Video → Scroll-Driven Landing Page
Build a cinematic landing page where the hero is a video playing on scroll instead of time — like Apple product pages or the GitHub Copilot landing. Frames are extracted from the source video and swapped as the user scrolls; below the sticky hero, normal-scroll sections carry copy and CTA.
When to invoke
- User drops a video and asks for a landing page, scrolling site, scroll-frame hero, or website from a video
- Mentions of "Apple-style scroll", "GitHub Copilot landing", "scrub-on-scroll", "frame on scroll"
- Hebrew equivalents: "דף נחיתה מסרטון", "אתר עם גלילה", "סרטון בגלילה"
Save location
Default: ~/Documents/yuv-projects/landings/<slug>/ — always save landing pages here so you can find them again. Create the parent directory if missing.
mkdir -p ~/Documents/yuv-projects/landings
cd ~/Documents/yuv-projects/landings
# Build <slug>/ here.
Final path: ~/Documents/yuv-projects/landings/<slug>/. Tell the user where the landing lives at the end of every build.
Workflow (8 steps)
- Probe the source —
ffprobefor duration, fps, dimensions, audio. - Pick frame count — default
80. Floor40(choppy if lower), ceiling160(heavy page). Choose by duration: ≤10s → 50, 10–30s → 80, 30–60s → 120, >60s → 160. - Decide output directory — default
~/Documents/yuv-projects/landings/<slug>/. The<slug>is short, derived from the video name or the topic. Override only on explicit request. - Extract frames — run
references/extract-frames.py <source-video> <output-dir> [count]. Outputsoutput-dir/frames/f_0001.jpg… with consistent JPG quality 82 and a max-width of 1920 (downscaled if source is larger). - Copy and customise
references/landing-template.htmlintooutput-dir/index.html:- Replace the
__FRAMES__placeholder with<img>tags for each frame (the build script does this for you when you pass--build-html). - Fill in
__HEADLINE__,__TAGLINE__,__CTA_TEXT__,__CTA_HREF__, sections. - For Hebrew content: set
<html lang="he" dir="rtl">and swap fonts to Rubik/Assistant (seereferences/design-notes.md).
- Replace the
- Optimise frames — the build script already scales to 1920px max-width. If the page total weight is > 12 MB, drop quality to 75 or reduce frame count.
- Preview —
python -m http.serverinside the output directory and openhttp://localhost:8000. Scroll feels buttery on a decent machine. - Deploy — drop the folder on Vercel/Netlify/Cloudflare Pages. No build step needed.
The scroll mechanic
- Outer scroller
.scroll-stageheight set in viewport units (default600vh= scroll 5 screens to traverse all frames). - Sticky hero
position: sticky; top: 0; height: 100vhcontaining all frames absolutely positioned and hidden except the active one. - Scroll listener computes
progress = scrolledIntoStage / scrollableHeightclamped 0–1. idx = floor(progress * (N - 1))— swap the.activeclass to that frame.- Wrap the listener in
requestAnimationFrameto keep 60fps.
Design rules
- If the project is YUV.AI-branded (Yuval personally, his portfolio, his brand): call
yuv-design-systemand lock it to a mode by medium —- Neon mode (DEFAULT for YUV.AI web): hot pink (
#FF1464) + neon cyan (#00E5FF) + white or rich black canvas. Anton + Inter (English) / Rubik + Assistant (Hebrew). 0px or 999px radii. - Warm Editorial mode: only for Hope, Marcus, bigcats.ai, practical.yuv.ai — pink + yellow + bone, off-white never pure
#fff. - Never use Decks mode (Fly High purple/yellow) for a landing page — that palette is reserved for slide decks only.
- Neon mode (DEFAULT for YUV.AI web): hot pink (
- If the project is not YUV.AI-branded: do not apply yuv-design-system. Pick a palette that fits the source video's mood. Anton + Inter remain reasonable defaults but aren't mandatory.
- Hero overlays should be subtle — a vignette and a single big headline; don't drown the frame.
- Below-hero sections: light canvas (white in Neon mode, off-white in Warm Editorial, bone if going generic-warm), large Anton heading, body copy in Inter at 18–22px, CTA as a sharp pill (
border-radius: 999px) — pink fill in Neon mode, brand-appropriate color otherwise. - For Hebrew: respect RTL, use Rubik 900 for headlines, Assistant 400/500 for body.
File references
| File | Purpose |
| --- | --- |
| references/extract-frames.py | ffmpeg-based frame extractor; optionally builds the full HTML in one go |
| references/landing-template.html | Self-contained landing-page skeleton with the scroll mechanic |
| references/design-notes.md | Typography, palette, and motion defaults |