Holographic Boarding Pass ホログラフィック・ボーディングパス
An interactive airline boarding pass with dynamic iridescent shimmer, 3D tilt tracking, tear-off perforation styling, and inline SVG security watermark. ポインタ追従による虹色光沢シマーと3Dチルト効果、ミシン目切り離し風の搭乗券UIデモ。
ライブデモ Live Demo
概要・用途・特徴Overview, Usage & Features
何ができるかWhat it does
An interactive airline boarding pass with dynamic iridescent shimmer, 3D tilt tracking, tear-off perforation styling, and inline SVG security watermark.
ポインタ追従による虹色光沢シマーと3Dチルト効果、ミシン目切り離し風の搭乗券UIデモ。
どこで使うかWhere to use
Portfolio, product showcase, landing page.
ポートフォリオ、製品紹介、ランディングページ。
特徴Key features
An interactive airline boarding pass with dynamic iridescent shimmer, 3D tilt tracking, tear-off perforation styling, and inline SVG security watermark.
ポインタ追従による虹色光沢シマーと3Dチルト効果、ミシン目切り離し風の搭乗券UIデモ。
調整可能パラメータ Adjustable Parameters
| Parameter | Default | Description |
|---|---|---|
--hp-cyan | #38ef7d | Change this CSS custom property to match your brand color. |
実装コード Implementation Code
<div class="demo-stage hp-root"><div class="hp-card-wrap"><div class="hp-card"><div class="hp-sheen" aria-hidden="true"></div><div class="hp-main"><div class="hp-header"><span class="hp-badge">ORBITAL SKYWAY</span><span class="hp-flight">FLIGHT OS-409</span></div><div class="hp-route"><div class="hp-city"><span class="hp-code">TYO</span><span class="hp-name">Tokyo Haneda</span></div><div class="hp-path" aria-hidden="true"><svg class="hp-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M12 2L19 21L12 17L5 21L12 2Z"/></svg><span class="hp-duration">9h 45m</span></div><div class="hp-city hp-right"><span class="hp-code">SFO</span><span class="hp-name">San Francisco</span></div></div><div class="hp-meta"><div class="hp-col"><span class="hp-label">GATE</span><span class="hp-val">52B</span></div><div class="hp-col"><span class="hp-label">SEAT</span><span class="hp-val">04A</span></div><div class="hp-col"><span class="hp-label">CLASS</span><span class="hp-val">FIRST</span></div><div class="hp-col"><span class="hp-label">BOARDING</span><span class="hp-val">21:40</span></div></div></div><div class="hp-divider" aria-hidden="true"><span class="hp-notch hp-notch-top"></span><span class="hp-dashes"></span><span class="hp-notch hp-notch-bottom"></span></div><div class="hp-stub"><div class="hp-passenger"><span class="hp-label">PASSENGER</span><span class="hp-name-lg">VALENTINA K.</span></div><div class="hp-barcode-box"><svg class="hp-barcode" viewBox="0 0 140 40" aria-hidden="true"><rect x="0" y="0" width="3" height="40" fill="currentColor"/><rect x="6" y="0" width="2" height="40" fill="currentColor"/><rect x="11" y="0" width="5" height="40" fill="currentColor"/><rect x="19" y="0" width="2" height="40" fill="currentColor"/><rect x="24" y="0" width="4" height="40" fill="currentColor"/><rect x="31" y="0" width="2" height="40" fill="currentColor"/><rect x="36" y="0" width="6" height="40" fill="currentColor"/><rect x="45" y="0" width="2" height="40" fill="currentColor"/><rect x="50" y="0" width="3" height="40" fill="currentColor"/><rect x="56" y="0" width="5" height="40" fill="currentColor"/><rect x="64" y="0" width="2" height="40" fill="currentColor"/><rect x="69" y="0" width="4" height="40" fill="currentColor"/><rect x="76" y="0" width="3" height="40" fill="currentColor"/><rect x="82" y="0" width="6" height="40" fill="currentColor"/><rect x="91" y="0" width="2" height="40" fill="currentColor"/><rect x="96" y="0" width="4" height="40" fill="currentColor"/><rect x="103" y="0" width="2" height="40" fill="currentColor"/><rect x="108" y="0" width="5" height="40" fill="currentColor"/><rect x="116" y="0" width="3" height="40" fill="currentColor"/><rect x="122" y="0" width="4" height="40" fill="currentColor"/><rect x="129" y="0" width="2" height="40" fill="currentColor"/><rect x="134" y="0" width="5" height="40" fill="currentColor"/></svg><span class="hp-seq">ETKT #88204911</span></div><button type="button" class="hp-action-btn" aria-label="Toggle boarding pass hologram" aria-pressed="true">HOLOGRAM ON</button></div></div></div></div>
<script>
(() => { document.querySelectorAll('.hp-root').forEach((root) => { const card = root.querySelector('.hp-card'); if (!card) return; if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; const onMove = (e) => { const r = card.getBoundingClientRect(); const x = (e.clientX - r.left) / r.width; const y = (e.clientY - r.top) / r.height; const rx = ((0.5 - y) * 20).toFixed(2); const ry = ((x - 0.5) * 20).toFixed(2); card.style.setProperty('--hp-rx', rx + 'deg'); card.style.setProperty('--hp-ry', ry + 'deg'); card.style.setProperty('--hp-mx', (x * 100).toFixed(1) + '%'); card.style.setProperty('--hp-my', (y * 100).toFixed(1) + '%'); }; const onLeave = () => { card.style.setProperty('--hp-rx', '0deg'); card.style.setProperty('--hp-ry', '0deg'); card.style.setProperty('--hp-mx', '50%'); card.style.setProperty('--hp-my', '50%'); }; card.addEventListener('pointermove', onMove); card.addEventListener('pointerleave', onLeave); }); })();
document.querySelectorAll(".hp-root").forEach(root=>{const btn=root.querySelector(".hp-action-btn");btn?.addEventListener("click",()=>{const off=root.classList.toggle("hp-static");btn.setAttribute("aria-pressed",String(!off));btn.textContent=off?"HOLOGRAM OFF":"HOLOGRAM ON";});});
</script>
.hp-root{--hp-bg:#090d16;--hp-card:#121826;--hp-cyan:#38ef7d;--hp-pink:#ff007f;--hp-violet:#7928ca;--hp-rx:0deg;--hp-ry:0deg;--hp-mx:50%;--hp-my:50%;display:flex;align-items:center;justify-content:center;min-height:360px;padding:24px 16px;background:radial-gradient(circle at 50% 20%,#1a243a 0%,var(--hp-bg) 80%);color:#f8fafc;font-family:system-ui,-apple-system,sans-serif;box-sizing:border-box;width:100%}.hp-root *,.hp-root *::before,.hp-root *::after{box-sizing:border-box}.hp-root .hp-card-wrap{perspective:1100px;width:100%;max-width:680px}.hp-root .hp-card{position:relative;display:flex;flex-direction:row;background:linear-gradient(135deg,#161e31 0%,#0f172a 100%);border-radius:20px;border:1px solid rgba(255,255,255,0.12);box-shadow:0 30px 60px -15px rgba(0,0,0,0.7),0 0 35px rgba(56,239,125,0.08);transform:rotateX(var(--hp-rx)) rotateY(var(--hp-ry));transform-style:preserve-3d;transition:transform 0.15s ease-out;overflow:hidden}.hp-root .hp-sheen{position:absolute;inset:0;background:radial-gradient(circle at var(--hp-mx) var(--hp-my),rgba(255,255,255,0.4) 0%,rgba(255,0,128,0.2) 25%,rgba(0,255,230,0.25) 50%,rgba(121,40,202,0.15) 75%,transparent 100%);mix-blend-mode:color-dodge;pointer-events:none;z-index:4;opacity:0.8}.hp-root .hp-main{flex:1 1 65%;padding:28px 24px;display:flex;flex-direction:column;gap:20px;position:relative;z-index:2}.hp-root .hp-header{display:flex;justify-content:space-between;align-items:center}.hp-root .hp-badge{background:linear-gradient(90deg,#ff007f,#7928ca);padding:5px 12px;border-radius:999px;font-size:11px;font-weight:800;letter-spacing:1.5px}.hp-root .hp-flight{font-size:13px;letter-spacing:1px;color:#94a3b8;font-weight:600}.hp-root .hp-route{display:flex;align-items:center;justify-content:space-between;gap:12px}.hp-root .hp-code{display:block;font-size:38px;font-weight:900;letter-spacing:-1px;background:linear-gradient(180deg,#ffffff 0%,#94a3b8 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent}.hp-root .hp-name{display:block;font-size:11px;color:#94a3b8;margin-top:2px}.hp-root .hp-path{display:flex;flex-direction:column;align-items:center;gap:4px;flex:1}.hp-root .hp-icon{width:22px;height:22px;stroke:#38ef7d}.hp-root .hp-duration{font-size:11px;color:#64748b}.hp-root .hp-meta{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;border-top:1px dashed rgba(255,255,255,0.15);padding-top:16px}.hp-root .hp-label{display:block;font-size:10px;color:#64748b;letter-spacing:1px;margin-bottom:4px}.hp-root .hp-val{font-size:15px;font-weight:700;color:#f1f5f9}.hp-root .hp-divider{width:28px;position:relative;display:flex;align-items:center;justify-content:center;z-index:2}.hp-root .hp-dashes{width:1px;height:100%;border-left:2px dashed rgba(255,255,255,0.2)}.hp-root .hp-notch{position:absolute;width:24px;height:24px;background:#090d16;border-radius:50%;left:50%;transform:translateX(-50%)}.hp-root .hp-notch-top{top:-12px;box-shadow:inset 0 -3px 4px rgba(0,0,0,0.4)}.hp-root .hp-notch-bottom{bottom:-12px;box-shadow:inset 0 3px 4px rgba(0,0,0,0.4)}.hp-root .hp-stub{flex:0 0 35%;padding:28px 20px;background:rgba(255,255,255,0.02);display:flex;flex-direction:column;justify-content:space-between;z-index:2}.hp-root .hp-name-lg{font-size:14px;font-weight:700;letter-spacing:0.5px}.hp-root .hp-barcode-box{display:flex;flex-direction:column;gap:6px}.hp-root .hp-barcode{width:100%;height:34px;color:#cbd5e1}.hp-root .hp-seq{font-size:9px;color:#64748b;letter-spacing:1px;font-family:monospace}.hp-root .hp-action-btn{background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.2);color:#f8fafc;padding:9px 12px;border-radius:8px;font-size:11px;font-weight:700;letter-spacing:1px;cursor:pointer;transition:background 0.2s,border-color 0.2s}.hp-root .hp-action-btn:hover{background:rgba(255,255,255,0.15);border-color:#38ef7d}@media (max-width:580px){.hp-root .hp-card{flex-direction:column}.hp-root .hp-divider{width:100%;height:24px}.hp-root .hp-dashes{width:100%;height:1px;border-left:none;border-top:2px dashed rgba(255,255,255,0.2)}.hp-root .hp-notch{top:50%;left:auto;transform:translateY(-50%)}.hp-root .hp-notch-top{left:-12px}.hp-root .hp-notch-bottom{right:-12px}}@media (prefers-reduced-motion: no-preference){.hp-root .hp-badge{animation:hp-shimmer-glow 4s ease-in-out infinite alternate}}@keyframes hp-shimmer-glow{0%{filter:drop-shadow(0 0 4px rgba(255,0,128,0.4))}100%{filter:drop-shadow(0 0 10px rgba(56,239,125,0.6))}}
@media not all and (prefers-reduced-motion: no-preference){.hp-root *{transition:none!important;animation:none!important}}
.hp-root.hp-static .hp-sheen{opacity:0}.hp-root .hp-stub{min-width:0}.hp-root .hp-header{gap:8px;flex-wrap:wrap}.hp-root .hp-action-btn:focus-visible{outline:2px solid #38ef7d;outline-offset:3px}.hp-root .hp-right{text-align:right}
import { useState, useEffect } from "react";
import "./I-012.css";
function useReducedMotion() {
const [reduced, setReduced] = useState(true);
useEffect(() => {
const media = window.matchMedia("(prefers-reduced-motion: reduce)");
const sync = () => setReduced(media.matches);
sync();
media.addEventListener("change", sync);
return () => media.removeEventListener("change", sync);
}, []);
return reduced;
}
function HolographicBoardingPass() {
const [hologram, setHologram] = useState(true);
const [tilt, setTilt] = useState({});
const reduced = useReducedMotion();
return <div className={"demo-stage hp-root" + (hologram ? "" : " hp-static")}><div className="hp-card-wrap"><div className="hp-card" style={tilt} onPointerMove={(event) => {
if (reduced) return;
const rect = event.currentTarget.getBoundingClientRect();
const x = (event.clientX - rect.left) / rect.width;
const y = (event.clientY - rect.top) / rect.height;
setTilt({ "--hp-rx": `${(0.5 - y) * 20}deg`, "--hp-ry": `${(x - 0.5) * 20}deg`, "--hp-mx": `${x * 100}%`, "--hp-my": `${y * 100}%` });
}} onPointerLeave={() => setTilt({})}><div className="hp-sheen" aria-hidden="true" /><div className="hp-main"><div className="hp-header"><span className="hp-badge">{"ORBITAL SKYWAY"}</span><span className="hp-flight">{"FLIGHT OS-409"}</span></div><div className="hp-route"><div className="hp-city"><span className="hp-code">{"TYO"}</span><span className="hp-name">{"Tokyo Haneda"}</span></div><div className="hp-path" aria-hidden="true"><svg className="hp-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M12 2L19 21L12 17L5 21L12 2Z" /></svg><span className="hp-duration">{"9h 45m"}</span></div><div className="hp-city hp-right"><span className="hp-code">{"SFO"}</span><span className="hp-name">{"San Francisco"}</span></div></div><div className="hp-meta"><div className="hp-col"><span className="hp-label">{"GATE"}</span><span className="hp-val">{"52B"}</span></div><div className="hp-col"><span className="hp-label">{"SEAT"}</span><span className="hp-val">{"04A"}</span></div><div className="hp-col"><span className="hp-label">{"CLASS"}</span><span className="hp-val">{"FIRST"}</span></div><div className="hp-col"><span className="hp-label">{"BOARDING"}</span><span className="hp-val">{"21:40"}</span></div></div></div><div className="hp-divider" aria-hidden="true"><span className="hp-notch hp-notch-top" /><span className="hp-dashes" /><span className="hp-notch hp-notch-bottom" /></div><div className="hp-stub"><div className="hp-passenger"><span className="hp-label">{"PASSENGER"}</span><span className="hp-name-lg">{"VALENTINA K."}</span></div><div className="hp-barcode-box"><svg className="hp-barcode" viewBox="0 0 140 40" aria-hidden="true"><rect x="0" y="0" width="3" height="40" fill="currentColor" /><rect x="6" y="0" width="2" height="40" fill="currentColor" /><rect x="11" y="0" width="5" height="40" fill="currentColor" /><rect x="19" y="0" width="2" height="40" fill="currentColor" /><rect x="24" y="0" width="4" height="40" fill="currentColor" /><rect x="31" y="0" width="2" height="40" fill="currentColor" /><rect x="36" y="0" width="6" height="40" fill="currentColor" /><rect x="45" y="0" width="2" height="40" fill="currentColor" /><rect x="50" y="0" width="3" height="40" fill="currentColor" /><rect x="56" y="0" width="5" height="40" fill="currentColor" /><rect x="64" y="0" width="2" height="40" fill="currentColor" /><rect x="69" y="0" width="4" height="40" fill="currentColor" /><rect x="76" y="0" width="3" height="40" fill="currentColor" /><rect x="82" y="0" width="6" height="40" fill="currentColor" /><rect x="91" y="0" width="2" height="40" fill="currentColor" /><rect x="96" y="0" width="4" height="40" fill="currentColor" /><rect x="103" y="0" width="2" height="40" fill="currentColor" /><rect x="108" y="0" width="5" height="40" fill="currentColor" /><rect x="116" y="0" width="3" height="40" fill="currentColor" /><rect x="122" y="0" width="4" height="40" fill="currentColor" /><rect x="129" y="0" width="2" height="40" fill="currentColor" /><rect x="134" y="0" width="5" height="40" fill="currentColor" /></svg><span className="hp-seq">{"ETKT #88204911"}</span></div><button type="button" className="hp-action-btn" aria-label="Toggle boarding pass hologram" onClick={() => setHologram((value) => !value)} aria-pressed={hologram}>{hologram ? "HOLOGRAM ON" : "HOLOGRAM OFF"}</button></div></div></div></div>;
}
export {
HolographicBoardingPass as default
};
.hp-root{--hp-bg:#090d16;--hp-card:#121826;--hp-cyan:#38ef7d;--hp-pink:#ff007f;--hp-violet:#7928ca;--hp-rx:0deg;--hp-ry:0deg;--hp-mx:50%;--hp-my:50%;display:flex;align-items:center;justify-content:center;min-height:360px;padding:24px 16px;background:radial-gradient(circle at 50% 20%,#1a243a 0%,var(--hp-bg) 80%);color:#f8fafc;font-family:system-ui,-apple-system,sans-serif;box-sizing:border-box;width:100%}.hp-root *,.hp-root *::before,.hp-root *::after{box-sizing:border-box}.hp-root .hp-card-wrap{perspective:1100px;width:100%;max-width:680px}.hp-root .hp-card{position:relative;display:flex;flex-direction:row;background:linear-gradient(135deg,#161e31 0%,#0f172a 100%);border-radius:20px;border:1px solid rgba(255,255,255,0.12);box-shadow:0 30px 60px -15px rgba(0,0,0,0.7),0 0 35px rgba(56,239,125,0.08);transform:rotateX(var(--hp-rx)) rotateY(var(--hp-ry));transform-style:preserve-3d;transition:transform 0.15s ease-out;overflow:hidden}.hp-root .hp-sheen{position:absolute;inset:0;background:radial-gradient(circle at var(--hp-mx) var(--hp-my),rgba(255,255,255,0.4) 0%,rgba(255,0,128,0.2) 25%,rgba(0,255,230,0.25) 50%,rgba(121,40,202,0.15) 75%,transparent 100%);mix-blend-mode:color-dodge;pointer-events:none;z-index:4;opacity:0.8}.hp-root .hp-main{flex:1 1 65%;padding:28px 24px;display:flex;flex-direction:column;gap:20px;position:relative;z-index:2}.hp-root .hp-header{display:flex;justify-content:space-between;align-items:center}.hp-root .hp-badge{background:linear-gradient(90deg,#ff007f,#7928ca);padding:5px 12px;border-radius:999px;font-size:11px;font-weight:800;letter-spacing:1.5px}.hp-root .hp-flight{font-size:13px;letter-spacing:1px;color:#94a3b8;font-weight:600}.hp-root .hp-route{display:flex;align-items:center;justify-content:space-between;gap:12px}.hp-root .hp-code{display:block;font-size:38px;font-weight:900;letter-spacing:-1px;background:linear-gradient(180deg,#ffffff 0%,#94a3b8 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent}.hp-root .hp-name{display:block;font-size:11px;color:#94a3b8;margin-top:2px}.hp-root .hp-path{display:flex;flex-direction:column;align-items:center;gap:4px;flex:1}.hp-root .hp-icon{width:22px;height:22px;stroke:#38ef7d}.hp-root .hp-duration{font-size:11px;color:#64748b}.hp-root .hp-meta{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;border-top:1px dashed rgba(255,255,255,0.15);padding-top:16px}.hp-root .hp-label{display:block;font-size:10px;color:#64748b;letter-spacing:1px;margin-bottom:4px}.hp-root .hp-val{font-size:15px;font-weight:700;color:#f1f5f9}.hp-root .hp-divider{width:28px;position:relative;display:flex;align-items:center;justify-content:center;z-index:2}.hp-root .hp-dashes{width:1px;height:100%;border-left:2px dashed rgba(255,255,255,0.2)}.hp-root .hp-notch{position:absolute;width:24px;height:24px;background:#090d16;border-radius:50%;left:50%;transform:translateX(-50%)}.hp-root .hp-notch-top{top:-12px;box-shadow:inset 0 -3px 4px rgba(0,0,0,0.4)}.hp-root .hp-notch-bottom{bottom:-12px;box-shadow:inset 0 3px 4px rgba(0,0,0,0.4)}.hp-root .hp-stub{flex:0 0 35%;padding:28px 20px;background:rgba(255,255,255,0.02);display:flex;flex-direction:column;justify-content:space-between;z-index:2}.hp-root .hp-name-lg{font-size:14px;font-weight:700;letter-spacing:0.5px}.hp-root .hp-barcode-box{display:flex;flex-direction:column;gap:6px}.hp-root .hp-barcode{width:100%;height:34px;color:#cbd5e1}.hp-root .hp-seq{font-size:9px;color:#64748b;letter-spacing:1px;font-family:monospace}.hp-root .hp-action-btn{background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.2);color:#f8fafc;padding:9px 12px;border-radius:8px;font-size:11px;font-weight:700;letter-spacing:1px;cursor:pointer;transition:background 0.2s,border-color 0.2s}.hp-root .hp-action-btn:hover{background:rgba(255,255,255,0.15);border-color:#38ef7d}@media (max-width:580px){.hp-root .hp-card{flex-direction:column}.hp-root .hp-divider{width:100%;height:24px}.hp-root .hp-dashes{width:100%;height:1px;border-left:none;border-top:2px dashed rgba(255,255,255,0.2)}.hp-root .hp-notch{top:50%;left:auto;transform:translateY(-50%)}.hp-root .hp-notch-top{left:-12px}.hp-root .hp-notch-bottom{right:-12px}}@media (prefers-reduced-motion: no-preference){.hp-root .hp-badge{animation:hp-shimmer-glow 4s ease-in-out infinite alternate}}@keyframes hp-shimmer-glow{0%{filter:drop-shadow(0 0 4px rgba(255,0,128,0.4))}100%{filter:drop-shadow(0 0 10px rgba(56,239,125,0.6))}}
@media not all and (prefers-reduced-motion: no-preference){.hp-root *{transition:none!important;animation:none!important}}
.hp-root.hp-static .hp-sheen{opacity:0}.hp-root .hp-stub{min-width:0}.hp-root .hp-header{gap:8px;flex-wrap:wrap}.hp-root .hp-action-btn:focus-visible{outline:2px solid #38ef7d;outline-offset:3px}.hp-root .hp-right{text-align:right}
仕組みとカスタマイズHow It Works & Customization
仕組みHow it works
Scoped CSS creates the visual design; small vanilla JavaScript handlers update the local demo state.
スコープ化したCSSで描画し、Vanilla JavaScriptでデモ内の状態だけを更新します。
カスタマイズ方法Customization
Change this CSS custom property to match your brand color.
CSSカスタムプロパティでブランドカラーを変更できます。
注意点Caveats
The sample content is fictional. No external assets or libraries are required. Motion follows the operating system preference. Demo labels are English; surrounding documentation supports Japanese and English.
デモ内容は架空です。外部素材・ライブラリは不要。OSの動きを減らす設定に対応します。デモ内のラベルは英語、解説は日英対応です。
よくある質問 Frequently Asked Questions
Does this demo need external libraries? 外部ライブラリは必要ですか?
The sample content is fictional. No external assets or libraries are required. Motion follows the operating system preference. Demo labels are English; surrounding documentation supports Japanese and English.
デモ内容は架空です。外部素材・ライブラリは不要。OSの動きを減らす設定に対応します。デモ内のラベルは英語、解説は日英対応です。
AIへの指示テンプレート AI Prompt Template
以下をAIに貼り付けると実装を依頼できます。 Paste the following into your AI assistant to request implementation.