blog/building-rs-universe.md

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.