Back to CSS Scroll Animations Kinetic Typography CSS + JS
Share
HTML
<!-- Block 1: Dark gold -->
<section class="block b1">
  <span class="counter-tag">01 / 05</span>
  <div class="ghost">DE</div>
  <div class="kl"><span class="w">DESIGN</span>&nbsp;<span class="w"><span class="em">that</span></span></div>
  <div class="kl"><span class="w">MOVES</span></div>
  <div class="kl"><span class="w">PEOPLE</span></div>
  <div class="rule"></div>
  <p class="sub">Scroll-driven motion. Cinematic reveals. Zero libraries.</p>
</section>

<!-- Block 2: Cream terracotta -->
<section class="block b2">
  <span class="counter-tag">02 / 05</span>
  <div class="ghost">GO</div>
  <div class="kl"><span class="w">EVERY</span></div>
  <div class="kl"><span class="w">WORD</span>&nbsp;<span class="w"><span class="em">earns</span></span></div>
  <div class="kl"><span class="w">ITS&nbsp;</span><span class="w">PLACE</span></div>
  <div class="rule"></div>
  <p class="sub">Typography as choreography. Each line its own entrance.</p>
</section>

<!-- Block 3: Dark purple -->
<section class="block b3">
  <span class="counter-tag">03 / 05</span>
  <div class="ghost">MO</div>
  <div class="kl"><span class="w">MOTION</span></div>
  <div class="solo"><span class="w"><span class="em">is the</span></span></div>
  <div class="kl" style="margin-top:0.1em"><span class="w">MESSAGE</span></div>
  <div class="rule"></div>
  <p class="sub">The way it arrives matters as much as what it says.</p>
</section>

<!-- Block 4: Warm cream -->
<section class="block b4">
  <span class="counter-tag">04 / 05</span>
  <div class="ghost">AR</div>
  <div class="kl"><span class="w">ARRIVE</span></div>
  <div class="kl"><span class="w">ON&nbsp;</span><span class="w"><span class="em">cue,</span></span></div>
  <div class="kl"><span class="w">ALWAYS</span></div>
  <div class="rule"></div>
  <p class="sub">Timing is everything. Precision in every millisecond.</p>
</section>

<!-- Block 5: Dark neon mono -->
<section class="block b5">
  <span class="counter-tag">05 / 05</span>
  <div class="ghost" style="-webkit-text-stroke:1px rgba(57,255,20,0.04)">SC</div>
  <div class="mono"><span class="w">SCROLL</span></div>
  <div class="mono"><span class="w">IS</span>&nbsp;<span class="w">THE</span></div>
  <div class="mono"><span class="w">INPUT</span></div>
  <div class="rule" style="background:#39FF14"></div>
  <p class="sub" style="color:rgba(57,255,20,0.35);font-family:'Courier New',monospace;font-style:normal;font-size:clamp(12px,1.2vw,16px);letter-spacing:0.08em">USER_SCROLL → ANIMATION_TRIGGER → REVEAL_STATE</p>
</section>
CSS
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
body{overflow-x:hidden}

.block{
  min-height:100vh;
  display:flex;flex-direction:column;justify-content:center;
  padding:8rem 7vw;position:relative;overflow:hidden;
}

/* Block themes */
.b1{background:#0E0C09}
.b2{background:#EDE8DF}
.b3{background:#100A08}
.b4{background:#F0EDE6}
.b5{background:#080C10}

/* Kinetic lines */
.kl{
  font-family:'Bebas Neue',sans-serif;
  font-size:clamp(62px,12vw,180px);
  line-height:0.91;
  overflow:hidden;display:block;
}
.kl .w{
  display:inline-block;
  transform:translateY(115%);opacity:0;
  transition:transform 0.95s cubic-bezier(0.16,1,0.3,1),opacity 0.38s ease;
}
.kl.in .w{transform:translateY(0);opacity:1}
.kl.in .w:nth-child(2){transition-delay:0.07s}
.kl.in .w:nth-child(3){transition-delay:0.14s}
.kl.in .w:nth-child(4){transition-delay:0.21s}
.kl.in .w:nth-child(5){transition-delay:0.28s}

/* per-block text colors */
.b1 .kl,.b3 .kl,.b5 .kl{color:#F0EBE0}
.b2 .kl,.b4 .kl{color:#16110C}

/* accent color per block */
.b1 .em{color:#C9A96E}
.b2 .em{color:#B34A38}
.b3 .em{color:#9B7FE8}
.b4 .em{color:#2E6B8A}
.b5 .em{color:#39FF14}
.em{font-family:'Fraunces',serif;font-style:italic}

/* rule */
.rule{
  height:2px;width:0;opacity:0;margin:2.5rem 0 2rem;
  transition:width 1s cubic-bezier(0.16,1,0.3,1) 0.45s,opacity 0.4s ease 0.45s;
}
.rule.in{width:80px;opacity:1}
.b1 .rule,.b3 .rule,.b5 .rule{background:#C9A96E}
.b2 .rule{background:#B34A38}
.b4 .rule{background:#2E6B8A}
.b5 .rule{background:#39FF14}

/* sub */
.sub{
  font-family:'Fraunces',serif;font-style:italic;
  font-size:clamp(14px,1.7vw,22px);
  opacity:0;transform:translateY(14px);
  transition:opacity 0.8s ease 0.7s,transform 0.8s cubic-bezier(0.16,1,0.3,1) 0.7s;
}
.sub.in{opacity:1;transform:translateY(0)}
.b1 .sub,.b3 .sub,.b5 .sub{color:rgba(240,235,224,0.35)}
.b2 .sub,.b4 .sub{color:rgba(22,17,12,0.38)}

/* ghost watermark */
.ghost{
  position:absolute;user-select:none;pointer-events:none;
  font-family:'Bebas Neue',sans-serif;font-size:28vw;line-height:1;
  color:transparent;
}
.b1 .ghost,.b3 .ghost,.b5 .ghost{-webkit-text-stroke:1px rgba(255,255,255,0.03);bottom:-8%;right:-4%}
.b2 .ghost,.b4 .ghost{-webkit-text-stroke:1px rgba(0,0,0,0.04);bottom:-8%;right:-4%}

/* counter tag */
.counter-tag{
  position:absolute;top:3rem;right:4rem;
  font-family:'Fraunces',serif;font-style:italic;
  font-size:13px;letter-spacing:0.05em;
}
.b1 .counter-tag,.b3 .counter-tag,.b5 .counter-tag{color:rgba(240,235,224,0.2)}
.b2 .counter-tag,.b4 .counter-tag{color:rgba(22,17,12,0.2)}

/* large italic solo line */
.solo{
  font-family:'Fraunces',serif;font-style:italic;
  font-size:clamp(40px,7vw,110px);
  line-height:1;overflow:hidden;display:block;
}
.solo .w{
  display:inline-block;
  transform:translateY(115%);opacity:0;
  transition:transform 1.1s cubic-bezier(0.16,1,0.3,1),opacity 0.5s ease;
}
.solo.in .w{transform:translateY(0);opacity:1}
.solo.in .w:nth-child(2){transition-delay:0.09s}
.solo.in .w:nth-child(3){transition-delay:0.18s}

.b5{font-family:monospace}
.mono{
  font-family:'Courier New',monospace;
  font-size:clamp(48px,9vw,140px);
  font-weight:700;line-height:0.9;
  color:#39FF14;overflow:hidden;display:block;
}
.mono .w{
  display:inline-block;
  transform:translateX(-40px);opacity:0;
  transition:transform 0.8s cubic-bezier(0.16,1,0.3,1),opacity 0.4s ease;
}
.mono.in .w{transform:translateX(0);opacity:1}
.mono.in .w:nth-child(2){transition-delay:0.06s}
.mono.in .w:nth-child(3){transition-delay:0.12s}
.mono.in .w:nth-child(4){transition-delay:0.18s}
.mono.in .w:nth-child(5){transition-delay:0.24s}
JS
const io = new IntersectionObserver(entries=>{
  entries.forEach(e=>{
    if(!e.isIntersecting)return;
    e.target.classList.add('in');
  });
},{threshold:0.25});
document.querySelectorAll('.kl,.solo,.mono,.rule,.sub').forEach(el=>io.observe(el));