Takes a video file (e.g. a product deconstruction/assembly animation, before/after transformation) and builds a production-quality website with scroll-driven animation. The video plays forward and backward as the user scrolls, creating a mesmerizing Apple-style scroll-stopping effect. Uses frame extraction via FFmpeg, canvas-based rendering, and modern scroll-driven techniques. Includes: animated starscape background, annotation cards with snap-stop scroll, specs section with count-up animations, navbar with scroll-to-pill transform, loader, and full mobile responsiveness. Trigger when the user says "3D animation", "scroll-stop build", "scroll animation website", "scroll-driven video", "build the scroll-stop site", or provides a video file and asks to make it scroll-controlled. Also trigger for "Apple-style scroll animation" or "video on scroll".
You take a video file and build a production-quality website where the video playback is controlled by scroll position — creating a dramatic, Apple-style scroll-stopping effect.
The user gives you a video. You handle everything: frame extraction, website build, content population, and serving it locally for preview.
Before touching any code or extracting any frames, ask the user these questions. Do not skip this step — the whole site is built from these answers.
Ask these naturally, not as a numbered interrogation:
Ask how they want to provide the website content:
If they provide a URL, use WebFetch to retrieve the page and extract relevant copy, product details, features, specs, and any other usable content.
Ask whether they want these included:
Only include these if the user explicitly opts in.
brew install ffmpeg if not)Once the interview is complete, construct the design system:
backdrop-filter: blur(20px), border-radius: 20pxffprobe -v quiet -print_format json -show_streams -show_format "{VIDEO_PATH}"
Extract duration, fps, resolution, total frame count. Target 60-150 frames total.
mkdir -p "{OUTPUT_DIR}/frames"
ffmpeg -i "{VIDEO_PATH}" -vf "fps={TARGET_FPS},scale=1920:-2" -q:v 2 "{OUTPUT_DIR}/frames/frame_%04d.jpg"
Use -q:v 2 for high quality JPEG. Use JPEG not PNG for smaller files.
Create a single HTML file. The site has these sections (top to bottom):
For the exact CSS/JS implementation of every section, read references/sections-guide.md.
That file contains the complete code for each section — structure, styling, JavaScript, mobile
adaptations, and animation patterns.
Canvas rendering with Retina support:
canvas.width = window.innerWidth * window.devicePixelRatio;
canvas.height = window.innerHeight * window.devicePixelRatio;
canvas.style.width = window.innerWidth + 'px';
canvas.style.height = window.innerHeight + 'px';
Cover-fit drawing (desktop) — zoomed contain-fit (mobile): On desktop, use cover-fit so the frame fills edge-to-edge. On mobile, use a slightly zoomed contain-fit approach so the object stays centered and visible.
Annotation cards with snap-stop scroll: Annotation cards appear at specific scroll progress points (data-show/data-hide attributes). The scroll FREEZES briefly at each card position — creating a "boom, boom, boom" effect where each card pops up as you stop. Uses JS-based snap: detects when scroll progress enters a snap zone, scrolls to the exact position, locks the body overflow for ~600ms, then releases. The number of annotation cards is flexible — match it to the content the user provides.
Navbar scroll-to-pill transform: The navbar starts full-width, then on scroll shrinks to a centered pill shape (max-width ~820px) with rounded corners and glass-morphism background.
Count-up animation: Spec numbers animate from 0 to target with easeOutExpo easing, staggered 200ms apart. Numbers get an accent-color glow pulse while counting. Triggered by IntersectionObserver.
Animated starscape: A fixed canvas behind everything with ~180 stars that slowly drift and twinkle. Each star has random drift speed, twinkle speed/phase, and opacity. Creates a subtle living background.
All content comes from the interview (Step 0). Use the real brand name, real product details, and real copy — never use placeholder "Lorem ipsum" text. If content came from a website URL, use the actual text from that site. Populate:
cd "{OUTPUT_DIR}" && python3 -m http.server 8080
Open http://localhost:8080 and test. Then open the browser URL for the user.
Key mobile adaptations:
bottom: 1.5vh)350vh desktop, 300vh tablet, 250vh phonerequestAnimationFrame for drawing — Never draw directly in scroll handler{ passive: true } on scroll listener — Enables browser scroll optimizationsdevicePixelRatio — Crisp on Retina displaysdrawFrame when frame index actually changesscroll-behavior: smooth — Would interfere with frame-accurate scroll mappingposition: sticky keeps canvas viewport-fixed while scroll container moves| Issue | Solution |
|---|---|
| FFmpeg not installed | Tell user to run brew install ffmpeg |
| Frames don't load | Check file paths, ensure local server is running (can't load from file://) |
| Animation is choppy | Reduce frame count, ensure JPEG not PNG, check file sizes (<100KB each) |
| Canvas is blurry | Ensure devicePixelRatio scaling is applied |
| Scroll feels too fast/slow | Adjust .scroll-animation height (200vh=fast, 500vh=slow, 800vh=cinematic) |
| Mobile cards overlap content | Use compact single-line card design, position at bottom: 1.5vh |
| Snap-stop feels jarring | Reduce HOLD_DURATION to 400ms or increase SNAP_ZONE |
| Stars too bright/dim | Adjust starscape canvas opacity (default 0.6) |
| First frame isn't white | Ask user to re-export video with white opening frame |
| Video too long (>10s) | Recommend trimming to 3-6 seconds for optimal scroll feel |