1. Mechanisme — kopieer 1-op-1, geen styling-keuzes
// Mechanisme: scrub-tied statement (laag A — kopieer 1-op-1)
// Lange statement, woord-voor-woord aangedreven door scroll-progress.
// Pin de container, scrub:true zodat tijd === scroll-positie.
import gsap from 'https://esm.sh/[email protected]';
import { ScrollTrigger } from 'https://esm.sh/[email protected]/ScrollTrigger';
gsap.registerPlugin(ScrollTrigger);
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
gsap.set('.scrub-word', { autoAlpha: 1 });
} else {
const words = gsap.utils.toArray('.scrub-word');
gsap.set(words, { autoAlpha: 0.08, yPercent: 30 });
gsap.to(words, {
autoAlpha: 1,
yPercent: 0,
ease: 'power4.out',
duration: 0.7,
stagger: { each: 0.04 },
scrollTrigger: {
trigger: '.scrub-pin',
scroller: '.scrub-scroller',
start: 'top top',
end: '+=200%',
pin: true,
scrub: 0.6,
},
});
} 2. Skeleton — DOM + class-namen, mag herschikken
<!-- Skeleton: kinetic statement (laag B) -->
<section class="kinetic-frame">
<div class="kinetic-eyebrow">
<span class="kinetic-mark"></span>
<span>Manifest / 01</span>
</div>
<div class="scrub-scroller">
<div class="scrub-pin">
<h2 class="scrub-statement">
<span class="scrub-word">Speed</span>
<span class="scrub-word">is</span>
<span class="scrub-word">a</span>
<span class="scrub-word">design</span>
<span class="scrub-word">decision.</span>
<span class="scrub-word">Hesitation</span>
<span class="scrub-word">is</span>
<span class="scrub-word">noise.</span>
<span class="scrub-word">Make</span>
<span class="scrub-word">it</span>
<span class="scrub-word">loud.</span>
</h2>
</div>
<div class="scrub-spacer"></div>
</div>
</section> 3. Styling-template — verplicht eigen invulling per merk
/* Styling: kinetic (laag C — brand-tokens) */
.kinetic-frame {
--bg: #0A0A0A; --ink: #FAFAFA; --hot: #FFE600;
background: var(--bg); color: var(--ink);
font-family: 'Archivo Black', 'Anton', system-ui, sans-serif;
text-transform: uppercase;
}
.scrub-statement { font-size: clamp(2.4rem, 9vw, 8rem); line-height: 0.92; letter-spacing: -0.02em; }
.scrub-word { display: inline-block; margin: 0 0.18em 0.05em 0; }
.scrub-word:nth-child(3n) { color: var(--hot); }
.scrub-scroller { height: 70vh; overflow-y: scroll; overflow-x: hidden; }
.scrub-pin { min-height: 100%; display: flex; align-items: center; padding: 0 6vw; }
.scrub-spacer { height: 200%; }