← Blurr Motion content-scrub-tied-statement-minimal
Categorie content Tier 1 Techniek #8 Deps gsap
01 / Statement Scrub-tied · Pinned

We build interfaces that do less, slower, and say more.

Scroll binnen het kader om de zin op te bouwen
1. Mechanisme — kopieer 1-op-1, geen styling-keuzes
// Mechanisme: scrub-tied statement (laag A)
// Pin + scrub: scroll-positie === animatie-progress.
// Minimal variant: lange zin fade-in word-by-word, geen vertical-shift.
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.12 });
  gsap.to(words, {
    autoAlpha: 1,
    ease: 'power2.out',
    duration: 0.8,
    stagger: { each: 0.05 },
    scrollTrigger: {
      trigger: '.scrub-pin',
      scroller: '.scrub-scroller',
      start: 'top top',
      end: '+=180%',
      pin: true,
      scrub: 1.2,
    },
  });
}
2. Skeleton — DOM + class-namen, mag herschikken
<!-- Skeleton: minimal statement (laag B) -->
<section class="minimal-frame">
  <div class="minimal-meta">
    <span>01 / Statement</span>
    <span class="minimal-rule"></span>
    <span>Scrub-tied · Pinned</span>
  </div>
  <div class="scrub-scroller">
    <div class="scrub-pin">
      <p class="scrub-statement">
        <span class="scrub-word">We</span>
        <span class="scrub-word">build</span>
        <span class="scrub-word">interfaces</span>
        <span class="scrub-word">that</span>
        <span class="scrub-word">do</span>
        <span class="scrub-word">less,</span>
        <span class="scrub-word">slower,</span>
        <span class="scrub-word">and</span>
        <span class="scrub-word">say</span>
        <span class="scrub-word">more.</span>
      </p>
    </div>
    <div class="scrub-spacer"></div>
  </div>
</section>
3. Styling-template — verplicht eigen invulling per merk
/* Styling: minimal (laag C — brand-tokens) */
.minimal-frame {
  --bg: #F4F1EB; --ink: #0A0A0A; --rule: rgba(10,10,10,0.18);
  background: var(--bg); color: var(--ink);
  font-family: 'Inter', system-ui, sans-serif;
}
.scrub-statement {
  font-size: clamp(1.4rem, 3vw, 2.4rem);
  font-weight: 300; line-height: 1.45; letter-spacing: -0.005em;
  max-width: 36ch;
}
.scrub-word { display: inline-block; margin-right: 0.28em; }
.minimal-rule { flex: 1; height: 1px; background: var(--rule); }
.scrub-scroller { height: 70vh; overflow-y: scroll; }
.scrub-pin { min-height: 100%; display: flex; align-items: center; padding: 0 clamp(2rem, 8vw, 8rem); }
.scrub-spacer { height: 180%; }