Behind the build

How this site
was made.

BurgerLab is a fictional dark-luxury burger brand, and this page documents the real pipeline behind its site — a single-page landing where a full-screen background video scrubs frame-by-frame with your scroll. Every pixel of the burger you see was AI-generated; every line of copy lives in HTML/CSS. Here's the full recipe.

The four-phase workflow.

The build ran as four gated phases — each one stopped for review before the next, because phases 2 and 3 spend generation credits.

01

Brand & planning files

Before any media existed, the whole site was designed on paper: a brand kit (palette, Archivo Black + Inter type, "engineered flavor" tone), a website brief (section-by-section plan plus the scrub-system design), an asset plan, one written prompt per image, and a filled video prompt. These planning files were the source of truth for everything downstream.

02

Stills — GPT Image 2 via Higgsfield

Seven 16:9 stills generated in a strict order: the hero burger first, then the exploded view using the hero as its visual reference (so the product identity stays consistent), then a macro texture detail, then four catalog product shots — all in the same dark-luxury studio look.

03

Scroll video — Seedance 2.0

One continuous 16:9 720p shot (8–12s), generated with the hero still as the only product reference: camera orbits the assembled burger, then in the second half its existing layers separate into a clean vertical exploded stack. No cuts — a single seamless move, designed to be readable when scrubbed in either direction.

04

The build — Vite + React + GSAP + Lenis

The raw video was re-encoded to all-keyframe H.264 as public/bg.mp4, then wired into a Vite + React front end where GSAP ScrollTrigger and Lenis smooth scroll drive the video's currentTime from scroll progress.

The scroll-scrub system.

The signature mechanic: a fixed full-screen <video> sits behind all content — muted, playsInline, preload="auto", and permanently paused. It never plays on its own. Instead:

The all-keyframe trick (why scrubbing works)

Normally-encoded H.264 stores most frames as deltas from a previous frame; only occasional keyframes (I-frames) are complete pictures. Seeking a paused video to an arbitrary time forces the decoder to jump back to the nearest keyframe and decode forward — dozens of frames per seek. Do that on every scroll event and the video stutters, lags, or snaps between keyframes, especially scrolling backwards.

The fix is a one-time ffmpeg re-encode where every frame is a keyframe:

ffmpeg -i burgerlab-scroll-background-raw.mp4 -an \
  -c:v libx264 -crf 18 -pix_fmt yuv420p \
  -g 1 -keyint_min 1 -sc_threshold 0 \
  website/public/bg.mp4

The file gets larger (no inter-frame compression), but every currentTime assignment decodes exactly one frame — instant, frame-accurate seeking in both directions. That's what makes scroll feel like it is physically dragging the camera.

The mobile fallback

Below 768px the scrubbed video is swapped for a fixed static hero image (hero-burgerlab.png) with identical copy and layout. Mobile browsers throttle programmatic video seeking and touch scrolling has a different feel, so a crisp still is the more premium experience there. The swap is handled with gsap.matchMedia('(min-width: 768px)'), which creates and kills the scrub trigger as the viewport crosses the breakpoint — so a resize can never strand the page without its scrub.

The art direction.

All media came from Higgsfield — stills from GPT Image 2, the video from Seedance 2.0. Every image and the scroll video was generated from a carefully art-directed brief specifying the lighting, lens, palette, composition and mood — the same dark-luxury studio look pinned across the hero, the exploded view, the macro detail and all four catalog shots, with copy kept in HTML and never baked into media — then iterated until the product stayed identical from frame to frame and matched the brand.

Prompt library

The full shot-by-shot prompt library behind this site is proprietary — available to clients on request.

Why the constraints matter: a single continuous shot means every scroll position maps to a coherent frame; product-consistency rules stop the model inventing ingredients mid-orbit; and scrub-stable motion (no flicker, no teleporting camera) is what lets a paused, scroll-driven playhead still read as deliberate cinematography.

Deployment — Netlify static hosting.

There is no backend. Vite compiles the React app to plain static files — one HTML shell, hashed JS/CSS bundles, and the public/ assets (the all-keyframe bg.mp4, the images, and this guide) copied through verbatim:

cd website
npm install
npm run build        # emits website/dist/
Netlify settingValue
Base directorywebsite
Build commandnpm run build
Publish directorywebsite/dist

The site builds with Vite's default base / and is served as the site root. Because everything in public/ ships as-is, this guide is just a static page living at /guide/ — no routing config, no redirects, no functions. The single heaviest asset is the all-keyframe video, a deliberate trade: a few extra megabytes buys perfectly smooth frame-accurate scrubbing.

← Scroll the finished site