Building RS Universe: a portfolio as a scroll-driven scene
Most portfolios are a stack of <section> tags with a fade-in. I wanted mine to feel
like a place you move through, not a document you scroll past.
The stack
- Next.js App Router for routing and static generation
- react-three-fiber + three.js for the WebGL scene (see
src/components/scene/LiveField.tsx) - Motion (
motion/react) for scroll-linked transforms on the DOM layer - GSAP for the finer-grained timeline work the scroll library can't express cleanly
Layering DOM and WebGL
The trick that made this maintainable was keeping the DOM and the canvas as separate
layers that only communicate through scroll progress. Intro.tsx reads
useScroll/useTransform from Motion and feeds a spring-smoothed value into a
PixelCanvas component sitting behind the text, rather than trying to drive the
Three.js scene and the DOM from the same imperative code path.
That separation means the WebGL layer can be swapped, throttled, or disabled (for reduced-motion or low-end devices) without touching the layout code at all.
What's next
Next up is pulling apart the Story component into independently scroll-triggered
chapters, each with its own camera behavior in LiveField, so the "universe" actually
changes shape as you move through it instead of just fading art in and out.