1 min readNext.jsCanvasPerformance

Why I rebuilt my portfolio as a scroll-driven film

Written by Nethma DissanayakeOnline Store Builder1 min read

Eighty-nine WebP frames, one canvas, zero video tags. Notes on building a scrollytelling hero that stays smooth on a phone.

Most portfolio heroes are a looping video. Mine is an image sequence scrubbed by scroll — the same technique Apple uses on product pages — because it gives deterministic frames, no autoplay restrictions, and a direct link between the visitor's hand and what they see.

The moving parts

  • A 500vh scroll zone with a sticky, full-viewport <canvas>
  • 89 frames pre-decoded into memory (frame 0 first, then six-wide concurrency)
  • Scroll progress → integer frame index → one drawImage per changed frame, coalesced through requestAnimationFrame

What I'd tell past me

  1. Reset your rAF handle in the effect cleanup, or StrictMode will silently stop every repaint.
  2. A portrait frame on an ultra-wide monitor needs a contain-over-blur fallback, not object-fit: cover.
  3. Version your frame URLs — browsers are happy to keep serving last week's sequence.

More on the Lenis + Framer Motion setup in a follow-up.

Keep reading