Behind the build
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 build ran as four gated phases — each one stopped for review before the next, because phases 2 and 3 spend generation credits.
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.
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.
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.
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 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:
lenis.on('scroll', ScrollTrigger.update)).#scroll-track element defines the scrub range. A GSAP
ScrollTrigger with scrub: true maps scroll progress to the playhead:
video.currentTime = progress × video.duration.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
-g 1 — GOP size of 1: every single frame is an I-frame.-keyint_min 1 — allow keyframes that close together.-sc_threshold 0 — disable scene-cut detection so the encoder
can't insert its own GOP structure.-an — strip audio (a background video never needs it).
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.
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.
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.
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.
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 setting | Value |
|---|---|
| Base directory | website |
| Build command | npm run build |
| Publish directory | website/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.