· 2 min read

How the 3D stack on this site works

A scroll-driven Three.js scene in a Next.js site — five layers, real 3D models drawn as outlines, and how it stays light enough to load fast.

By Kushal Sapkota

How the 3D stack on this site works — Kushal Sapkota

The first thing you see on this site is a stack of five floating plates — interface, infrastructure, telecom, radio, airspace — and as you scroll, the camera dives down through them. Here's how it's put together, and how it stays fast.

One canvas, pinned while you scroll

The section is six screens tall. Inside it, a position: sticky container holds a single WebGL canvas that stays on screen while the text cards scroll past on top. Scroll progress is just:

const progress = -section.getBoundingClientRect().top / window.innerHeight;

A value from 0 (the intro) to 5 (the last layer). Each frame the camera eases toward the matching layer instead of jumping, so even fast scrolling feels smooth.

Plates, grids and a signal column

Each layer is a thin box outline, a faint grid and a translucent plane — all line geometry, which is cheap to draw. A vertical red line with small moving points runs through every layer: packets falling from the web app all the way down to the drone.

The layer in focus is drawn at full strength; the others fade by distance from the current scroll position. That one trick does most of the "depth" work.

Real models, drawn as outlines

The server rack, cell tower, walkie-talkie and drone are free CC-licensed models from Poly Pizza. They'd clash with the line-drawing style if rendered normally, so each one is converted on load:

  1. Every mesh gets a matte, clay-coloured material taken from the page background.
  2. EdgesGeometry with a fairly high angle threshold pulls out only the sharp edges, drawn as thin lines on top.
  3. The model is scaled to fit its plate and centred.

If a model file is missing, the layer falls back to a hand-built wireframe, so the scene never breaks.

Keeping it light

  • The models are small (15 KB to 1.8 MB) and cached by the browser.
  • Light and dark mode change the CSS colours; the scene listens for the change and rebuilds itself in the new palette.
  • With "reduce motion" turned on, nothing animates on its own — the scene only redraws when you scroll.
  • All the actual content (text, projects, skills) is plain server-rendered HTML, so search engines read everything without running any 3D code.

The whole site, 3D included, is built with Next.js and Three.js and self-hosted on my own server.