457 lines
19 KiB
HTML
457 lines
19 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8"/>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
<title>Intro Reveal Tests — In + Out</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com"/>
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/>
|
|
<link href="https://fonts.googleapis.com/css2?family=DM+Serif+Display&family=Barlow:wght@300;400;600;700&display=swap" rel="stylesheet"/>
|
|
<style>
|
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
:root {
|
|
--paint: #0a0a0a;
|
|
--bg: #FAFAFA;
|
|
--text: #1A1A18;
|
|
--muted: #5A5A54;
|
|
--green: #2a3010;
|
|
--cream: #f4ecd8;
|
|
--easeOut: cubic-bezier(0.22, 0.61, 0.36, 1);
|
|
--easeStrong: cubic-bezier(0.16, 1, 0.3, 1);
|
|
--easeIn: cubic-bezier(0.4, 0, 1, 1);
|
|
}
|
|
body {
|
|
background: var(--bg);
|
|
font-family: 'Barlow', sans-serif;
|
|
color: var(--text);
|
|
padding: 40px 20px 80px;
|
|
min-height: 100vh;
|
|
}
|
|
header {
|
|
max-width: 800px;
|
|
margin: 0 auto 32px;
|
|
text-align: center;
|
|
}
|
|
h1 {
|
|
font-family: 'DM Serif Display', serif;
|
|
font-weight: 400;
|
|
font-size: 40px;
|
|
margin-bottom: 8px;
|
|
letter-spacing: 0.01em;
|
|
}
|
|
.lede {
|
|
color: var(--muted);
|
|
font-size: 14px;
|
|
letter-spacing: 0.04em;
|
|
margin-bottom: 8px;
|
|
}
|
|
.lede small {
|
|
display: block;
|
|
margin-top: 6px;
|
|
color: var(--muted);
|
|
opacity: 0.85;
|
|
}
|
|
.controls {
|
|
text-align: center;
|
|
margin-bottom: 32px;
|
|
}
|
|
.btn-all {
|
|
font-family: 'Barlow', sans-serif;
|
|
font-weight: 600;
|
|
font-size: 12px;
|
|
letter-spacing: 0.18em;
|
|
text-transform: uppercase;
|
|
background: var(--green);
|
|
color: var(--cream);
|
|
border: none;
|
|
padding: 12px 22px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
box-shadow: 0 3px 6px rgba(0,0,0,0.12), inset 0 1px 0 rgba(255,236,200,0.15);
|
|
}
|
|
.btn-all:hover { background: #1a2008; }
|
|
|
|
.grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr;
|
|
gap: 18px;
|
|
max-width: 800px;
|
|
margin: 0 auto;
|
|
}
|
|
@media (min-width: 720px) {
|
|
.grid { grid-template-columns: 1fr 1fr; }
|
|
}
|
|
.card {
|
|
background: #FFFFFF;
|
|
border: 1px solid rgba(0,0,0,0.08);
|
|
border-radius: 14px;
|
|
overflow: hidden;
|
|
cursor: pointer;
|
|
transition: border-color 0.15s ease, transform 0.15s ease;
|
|
}
|
|
.card:hover { border-color: rgba(0,0,0,0.18); transform: translateY(-2px); }
|
|
.card-stage {
|
|
position: relative;
|
|
height: 240px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
text-align: center;
|
|
padding: 0 20px;
|
|
overflow: hidden;
|
|
background: var(--bg);
|
|
border-bottom: 1px solid rgba(0,0,0,0.06);
|
|
}
|
|
.card-stage .demo-text {
|
|
display: inline-block;
|
|
font-family: 'Barlow', sans-serif;
|
|
font-weight: 400;
|
|
font-size: clamp(18px, 3.4vw, 26px);
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.22em;
|
|
line-height: 1.3;
|
|
color: var(--paint);
|
|
opacity: 0; /* default hidden until .play-in or .play-out applied */
|
|
will-change: opacity, transform, filter, clip-path;
|
|
}
|
|
.card-stage.is-resting .demo-text {
|
|
opacity: 1; /* resting state for outro previews */
|
|
filter: none;
|
|
transform: none;
|
|
clip-path: inset(0 0 0 0);
|
|
}
|
|
.card-foot {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 12px;
|
|
padding: 14px 18px;
|
|
}
|
|
.card-name {
|
|
font-weight: 600;
|
|
font-size: 12px;
|
|
letter-spacing: 0.14em;
|
|
text-transform: uppercase;
|
|
color: var(--text);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
.card-name small {
|
|
display: block;
|
|
font-weight: 400;
|
|
font-size: 11px;
|
|
letter-spacing: 0.02em;
|
|
text-transform: none;
|
|
color: var(--muted);
|
|
margin-top: 2px;
|
|
}
|
|
.card-num {
|
|
display: inline-block;
|
|
width: 26px; height: 26px;
|
|
border-radius: 50%;
|
|
background: var(--green);
|
|
color: var(--cream);
|
|
font-size: 11px;
|
|
font-weight: 700;
|
|
line-height: 26px;
|
|
text-align: center;
|
|
flex-shrink: 0;
|
|
}
|
|
.card-actions { display: flex; gap: 6px; }
|
|
.btn {
|
|
font-family: 'Barlow', sans-serif;
|
|
font-weight: 600;
|
|
font-size: 11px;
|
|
letter-spacing: 0.14em;
|
|
text-transform: uppercase;
|
|
background: transparent;
|
|
color: var(--text);
|
|
border: 1px solid rgba(0,0,0,0.18);
|
|
padding: 8px 12px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
}
|
|
.btn:hover { background: rgba(0,0,0,0.04); }
|
|
.btn.btn-out { border-color: rgba(192,48,48,0.4); color: #C03030; }
|
|
.btn.btn-out:hover { background: rgba(192,48,48,0.06); }
|
|
|
|
.tip {
|
|
text-align: center;
|
|
margin-top: 32px;
|
|
color: var(--muted);
|
|
font-size: 12px;
|
|
font-family: 'Barlow', monospace;
|
|
letter-spacing: 0.06em;
|
|
}
|
|
|
|
/* ─────────────────────────────────────────────────────────────
|
|
IN + OUT animations — every style now has a paired exit so the
|
|
user can preview the full cycle. Click the card or "Cycle" to
|
|
run In → hold → Out; "In" / "Out" buttons fire one direction.
|
|
───────────────────────────────────────────────────────────── */
|
|
|
|
/* 1. SMOKE */
|
|
@keyframes a-smoke-in { 0% { opacity: 0; filter: blur(16px); transform: translateY(14px); } 35% { opacity: 0.6; } 100% { opacity: 1; filter: blur(0); transform: translateY(0); } }
|
|
@keyframes a-smoke-out { 0% { opacity: 1; filter: blur(0); transform: translateY(0); } 100% { opacity: 0; filter: blur(16px); transform: translateY(-14px); } }
|
|
.demo-1.play-in { animation: a-smoke-in 1.6s var(--easeOut) forwards; }
|
|
.demo-1.play-out { animation: a-smoke-out 1.0s var(--easeIn) forwards; }
|
|
|
|
/* 2. FOCUS PULL */
|
|
@keyframes a-focus-in { 0% { opacity: 0; filter: blur(28px); } 40% { opacity: 1; filter: blur(28px); } 100% { opacity: 1; filter: blur(0); } }
|
|
@keyframes a-focus-out { 0% { opacity: 1; filter: blur(0); } 60% { opacity: 1; filter: blur(28px); } 100% { opacity: 0; filter: blur(28px); } }
|
|
.demo-2.play-in { animation: a-focus-in 1.8s var(--easeStrong) forwards; }
|
|
.demo-2.play-out { animation: a-focus-out 1.4s var(--easeIn) forwards; }
|
|
|
|
/* 3. SLOW ZOOM (entry: 1.08 → 1.00 ; exit: 1.00 → 1.10 outward) */
|
|
@keyframes a-zoom-in { 0% { opacity: 0; transform: scale(1.08); filter: blur(2px); } 100% { opacity: 1; transform: scale(1); filter: blur(0); } }
|
|
@keyframes a-zoom-out { 0% { opacity: 1; transform: scale(1); filter: blur(0); } 100% { opacity: 0; transform: scale(1.10); filter: blur(2px); } }
|
|
.demo-3.play-in { animation: a-zoom-in 2.2s var(--easeStrong) forwards; }
|
|
.demo-3.play-out { animation: a-zoom-out 1.0s var(--easeIn) forwards; }
|
|
|
|
/* 4. PUSH-IN (entry: 0.92 → 1.00 ; exit: 1.00 → 0.92 reverse dolly) */
|
|
@keyframes a-push-in { 0% { opacity: 0; transform: scale(0.92); filter: blur(3px); } 100% { opacity: 1; transform: scale(1); filter: blur(0); } }
|
|
@keyframes a-push-out { 0% { opacity: 1; transform: scale(1); filter: blur(0); } 100% { opacity: 0; transform: scale(0.92); filter: blur(3px); } }
|
|
.demo-4.play-in { animation: a-push-in 1.6s var(--easeOut) forwards; }
|
|
.demo-4.play-out { animation: a-push-out 1.0s var(--easeIn) forwards; }
|
|
|
|
/* 5. MASK UP (entry: clip bottom → top ; exit: clip top → bottom) */
|
|
@keyframes a-mask-in { 0% { opacity: 1; clip-path: inset(100% 0 0 0); } 10% { opacity: 1; } 100% { opacity: 1; clip-path: inset(0 0 0 0); } }
|
|
@keyframes a-mask-out { 0% { opacity: 1; clip-path: inset(0 0 0 0); } 100% { opacity: 1; clip-path: inset(0 0 100% 0); } }
|
|
.demo-5.play-in { animation: a-mask-in 1.4s var(--easeStrong) forwards; }
|
|
.demo-5.play-out { animation: a-mask-out 1.0s var(--easeIn) forwards; }
|
|
|
|
/* 6. IRIS (entry: circle 0% → 75% ; exit: circle 75% → 0%) */
|
|
@keyframes a-iris-in { 0% { opacity: 1; clip-path: circle(0% at 50% 50%); } 100% { opacity: 1; clip-path: circle(75% at 50% 50%); } }
|
|
@keyframes a-iris-out { 0% { opacity: 1; clip-path: circle(75% at 50% 50%); } 100% { opacity: 1; clip-path: circle(0% at 50% 50%); } }
|
|
.demo-6.play-in { animation: a-iris-in 1.4s var(--easeStrong) forwards; }
|
|
.demo-6.play-out { animation: a-iris-out 1.0s var(--easeIn) forwards; }
|
|
|
|
/* 7. WORD CASCADE (each word in/out with stagger; JS sets per-word delay) */
|
|
@keyframes a-word-in { 0% { opacity: 0; transform: translateY(14px); filter: blur(8px); } 100% { opacity: 1; transform: translateY(0); filter: blur(0); } }
|
|
@keyframes a-word-out { 0% { opacity: 1; transform: translateY(0); filter: blur(0); } 100% { opacity: 0; transform: translateY(-12px); filter: blur(6px); } }
|
|
.card-stage.style-7 .demo-text { opacity: 1; }
|
|
.card-stage.style-7 .demo-text > .word {
|
|
display: inline-block;
|
|
margin-right: 0.25em;
|
|
opacity: 0;
|
|
}
|
|
.card-stage.style-7.is-resting .demo-text > .word { opacity: 1; }
|
|
.card-stage.style-7.play-in .demo-text > .word { animation: a-word-in 0.7s var(--easeOut) forwards; }
|
|
.card-stage.style-7.play-out .demo-text > .word { animation: a-word-out 0.55s var(--easeIn) forwards; }
|
|
|
|
/* 8. GLOW HALO */
|
|
@keyframes a-glow-in { 0% { opacity: 0; text-shadow: 0 0 0 rgba(90,154,120,0); filter: blur(2px); transform: scale(0.97); } 45% { opacity: 1; text-shadow: 0 0 28px rgba(90,154,120,0.65), 0 0 12px rgba(90,154,120,0.45); } 100% { opacity: 1; text-shadow: 0 0 0 rgba(90,154,120,0); filter: blur(0); transform: scale(1); } }
|
|
@keyframes a-glow-out { 0% { opacity: 1; text-shadow: 0 0 0 rgba(90,154,120,0); filter: blur(0); } 50% { opacity: 1; text-shadow: 0 0 32px rgba(90,154,120,0.55); } 100% { opacity: 0; text-shadow: 0 0 4px rgba(90,154,120,0); filter: blur(2px); transform: scale(1.04); } }
|
|
.demo-8.play-in { animation: a-glow-in 1.9s var(--easeOut) forwards; }
|
|
.demo-8.play-out { animation: a-glow-out 1.2s var(--easeIn) forwards; }
|
|
|
|
/* 9. CHROMATIC */
|
|
.card-stage.style-9 .demo-text { position: relative; }
|
|
.card-stage.style-9 .demo-text::before,
|
|
.card-stage.style-9 .demo-text::after {
|
|
content: attr(data-text);
|
|
position: absolute;
|
|
inset: 0;
|
|
pointer-events: none;
|
|
}
|
|
.card-stage.style-9 .demo-text::before { color: rgba(220,40,40,0.85); }
|
|
.card-stage.style-9 .demo-text::after { color: rgba(40,120,220,0.85); }
|
|
@keyframes a-chrom-base-in { 0% { opacity: 0; } 20% { opacity: 1; } 100% { opacity: 1; } }
|
|
@keyframes a-chrom-base-out { 0% { opacity: 1; } 100% { opacity: 0; } }
|
|
@keyframes a-chrom-r-in { 0% { opacity: 0; transform: translate3d(-22px,0,0); } 20% { opacity: 0.85; } 100% { opacity: 0; transform: translate3d(0,0,0); } }
|
|
@keyframes a-chrom-r-out { 0% { opacity: 0; transform: translate3d(0,0,0); } 30% { opacity: 0.85; transform: translate3d(-22px,0,0); } 100% { opacity: 0; transform: translate3d(-32px,0,0); } }
|
|
@keyframes a-chrom-b-in { 0% { opacity: 0; transform: translate3d(22px,0,0); } 20% { opacity: 0.85; } 100% { opacity: 0; transform: translate3d(0,0,0); } }
|
|
@keyframes a-chrom-b-out { 0% { opacity: 0; transform: translate3d(0,0,0); } 30% { opacity: 0.85; transform: translate3d(22px,0,0); } 100% { opacity: 0; transform: translate3d(32px,0,0); } }
|
|
.card-stage.style-9.play-in .demo-text { animation: a-chrom-base-in 1.4s var(--easeStrong) forwards; }
|
|
.card-stage.style-9.play-in .demo-text::before { animation: a-chrom-r-in 1.4s var(--easeStrong) forwards; }
|
|
.card-stage.style-9.play-in .demo-text::after { animation: a-chrom-b-in 1.4s var(--easeStrong) forwards; }
|
|
.card-stage.style-9.play-out .demo-text { animation: a-chrom-base-out 1.0s var(--easeIn) forwards; }
|
|
.card-stage.style-9.play-out .demo-text::before { animation: a-chrom-r-out 1.0s var(--easeIn) forwards; }
|
|
.card-stage.style-9.play-out .demo-text::after { animation: a-chrom-b-out 1.0s var(--easeIn) forwards; }
|
|
|
|
/* 10. VAPOR RISE (entry: rises into focus ; exit: continues rising into haze) */
|
|
@keyframes a-vapor-in { 0% { opacity: 0; filter: blur(0) brightness(1.3); transform: translateY(28px); } 20% { opacity: 0.45; filter: blur(8px) brightness(1.2); } 100% { opacity: 1; filter: blur(0) brightness(1); transform: translateY(0); } }
|
|
@keyframes a-vapor-out { 0% { opacity: 1; filter: blur(0) brightness(1); transform: translateY(0); } 100% { opacity: 0; filter: blur(8px) brightness(1.2); transform: translateY(-28px); } }
|
|
.demo-10.play-in { animation: a-vapor-in 2.0s var(--easeOut) forwards; }
|
|
.demo-10.play-out { animation: a-vapor-out 1.0s var(--easeIn) forwards; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<header>
|
|
<h1>Intro Reveal Tests — In + Out</h1>
|
|
<p class="lede">
|
|
Ten cinematic reveal styles, each with a matching exit.
|
|
<small>Tap the card for a full <em>In → hold → Out</em> cycle. "In" / "Out" preview each direction independently.</small>
|
|
</p>
|
|
</header>
|
|
|
|
<div class="controls">
|
|
<button class="btn-all" id="play-all">▶ Cycle All Together</button>
|
|
</div>
|
|
|
|
<div class="grid">
|
|
|
|
<div class="card" data-num="1">
|
|
<div class="card-stage style-1"><span class="demo-text demo-1">Wisdom is to prepare</span></div>
|
|
<div class="card-foot">
|
|
<div class="card-name"><span class="card-num">01</span><div>Smoke<small>blur 16px → focus → blur out</small></div></div>
|
|
<div class="card-actions"><button class="btn btn-in">In</button><button class="btn btn-out">Out</button></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card" data-num="2">
|
|
<div class="card-stage style-2"><span class="demo-text demo-2">Wisdom is to prepare</span></div>
|
|
<div class="card-foot">
|
|
<div class="card-name"><span class="card-num">02</span><div>Focus pull<small>blur snaps to focus, then defocuses</small></div></div>
|
|
<div class="card-actions"><button class="btn btn-in">In</button><button class="btn btn-out">Out</button></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card" data-num="3">
|
|
<div class="card-stage style-3"><span class="demo-text demo-3">Wisdom is to prepare</span></div>
|
|
<div class="card-foot">
|
|
<div class="card-name"><span class="card-num">03</span><div>Slow zoom<small>1.08 → 1.00 → 1.10 (camera pulls back)</small></div></div>
|
|
<div class="card-actions"><button class="btn btn-in">In</button><button class="btn btn-out">Out</button></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card" data-num="4">
|
|
<div class="card-stage style-4"><span class="demo-text demo-4">Wisdom is to prepare</span></div>
|
|
<div class="card-foot">
|
|
<div class="card-name"><span class="card-num">04</span><div>Push-in<small>0.92 → 1.00 → 0.92 (reverse dolly)</small></div></div>
|
|
<div class="card-actions"><button class="btn btn-in">In</button><button class="btn btn-out">Out</button></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card" data-num="5">
|
|
<div class="card-stage style-5"><span class="demo-text demo-5">Wisdom is to prepare</span></div>
|
|
<div class="card-foot">
|
|
<div class="card-name"><span class="card-num">05</span><div>Mask up<small>clip bottom → top; exits top → bottom</small></div></div>
|
|
<div class="card-actions"><button class="btn btn-in">In</button><button class="btn btn-out">Out</button></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card" data-num="6">
|
|
<div class="card-stage style-6"><span class="demo-text demo-6">Wisdom is to prepare</span></div>
|
|
<div class="card-foot">
|
|
<div class="card-name"><span class="card-num">06</span><div>Iris<small>circle opens, then closes</small></div></div>
|
|
<div class="card-actions"><button class="btn btn-in">In</button><button class="btn btn-out">Out</button></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card" data-num="7">
|
|
<div class="card-stage style-7"><span class="demo-text demo-7" data-text="Wisdom is to prepare">Wisdom is to prepare</span></div>
|
|
<div class="card-foot">
|
|
<div class="card-name"><span class="card-num">07</span><div>Word cascade<small>words in & out, staggered up/down</small></div></div>
|
|
<div class="card-actions"><button class="btn btn-in">In</button><button class="btn btn-out">Out</button></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card" data-num="8">
|
|
<div class="card-stage style-8"><span class="demo-text demo-8">Wisdom is to prepare</span></div>
|
|
<div class="card-foot">
|
|
<div class="card-name"><span class="card-num">08</span><div>Glow halo<small>halo in, halo flares & fades out</small></div></div>
|
|
<div class="card-actions"><button class="btn btn-in">In</button><button class="btn btn-out">Out</button></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card" data-num="9">
|
|
<div class="card-stage style-9"><span class="demo-text demo-9" data-text="Wisdom is to prepare">Wisdom is to prepare</span></div>
|
|
<div class="card-foot">
|
|
<div class="card-name"><span class="card-num">09</span><div>Chromatic<small>RGB split converges; splits apart on out</small></div></div>
|
|
<div class="card-actions"><button class="btn btn-in">In</button><button class="btn btn-out">Out</button></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card" data-num="10">
|
|
<div class="card-stage style-10"><span class="demo-text demo-10">Wisdom is to prepare</span></div>
|
|
<div class="card-foot">
|
|
<div class="card-name"><span class="card-num">10</span><div>Vapor rise<small>rises into focus; continues rising into haze</small></div></div>
|
|
<div class="card-actions"><button class="btn btn-in">In</button><button class="btn btn-out">Out</button></div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<p class="tip">Click a card for the full cycle, or use In / Out buttons to preview each direction.</p>
|
|
|
|
<script>
|
|
// Word cascade — split text into <span class="word"> chunks with stagger.
|
|
function buildWords() {
|
|
const t = document.querySelector('.demo-7')
|
|
if (!t) return
|
|
const text = t.dataset.text || t.textContent || ''
|
|
t.innerHTML = ''
|
|
text.split(' ').forEach((w, i) => {
|
|
const span = document.createElement('span')
|
|
span.className = 'word'
|
|
span.dataset.idx = i
|
|
span.dataset.total = text.split(' ').length
|
|
span.style.animationDelay = (i * 0.18) + 's'
|
|
span.textContent = w
|
|
t.appendChild(span)
|
|
})
|
|
}
|
|
buildWords()
|
|
|
|
// Stages 7 and 9 toggle classes on the .card-stage; the rest toggle on
|
|
// the .demo-N inner element.
|
|
function targetFor(num) {
|
|
const stageLevel = ['7', '9'].includes(String(num))
|
|
return stageLevel
|
|
? document.querySelector('.style-' + num)
|
|
: document.querySelector('.demo-' + num)
|
|
}
|
|
|
|
function setClass(num, cls) {
|
|
const t = targetFor(num)
|
|
if (!t) return
|
|
t.classList.remove('play-in', 'play-out')
|
|
void t.offsetWidth
|
|
t.classList.add(cls)
|
|
}
|
|
|
|
function reset(num) {
|
|
const t = targetFor(num)
|
|
if (!t) return
|
|
t.classList.remove('play-in', 'play-out')
|
|
// Park stage 7 (cascade) and 5/6 (clip) in resting state for outro previews.
|
|
const stage = (['7','9'].includes(String(num))) ? t : t.closest('.card-stage')
|
|
if (stage) stage.classList.add('is-resting')
|
|
}
|
|
|
|
function playIn(num) { document.querySelector('.style-' + num)?.classList.remove('is-resting'); setClass(num, 'play-in') }
|
|
function playOut(num) { document.querySelector('.style-' + num)?.classList.add('is-resting'); setClass(num, 'play-out') }
|
|
|
|
function cycle(num) {
|
|
playIn(num)
|
|
// Hold for a moment after in completes (~1.6s baseline + 0.7s read)
|
|
setTimeout(() => playOut(num), 2400)
|
|
}
|
|
|
|
document.querySelectorAll('.card').forEach(card => {
|
|
card.addEventListener('click', () => cycle(card.dataset.num))
|
|
})
|
|
document.querySelectorAll('.btn-in').forEach(btn => {
|
|
btn.addEventListener('click', e => { e.stopPropagation(); playIn(btn.closest('.card').dataset.num) })
|
|
})
|
|
document.querySelectorAll('.btn-out').forEach(btn => {
|
|
btn.addEventListener('click', e => { e.stopPropagation(); playOut(btn.closest('.card').dataset.num) })
|
|
})
|
|
document.getElementById('play-all').addEventListener('click', () => {
|
|
for (let n = 1; n <= 10; n++) cycle(n)
|
|
})
|
|
|
|
// Auto-cycle each card once on load with a stagger.
|
|
window.addEventListener('load', () => {
|
|
for (let n = 1; n <= 10; n++) {
|
|
setTimeout(() => cycle(n), 300 + n * 150)
|
|
}
|
|
})
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|