Landing page hero loop — ambient product
A seamless loop ({{duration}}s) for a website hero: floating UI cards, soft gradient plate, and a slow camera drift.
Prompt
# Landing page hero loop — ambient product
## Format (read first)
- 1920×1080 (16:9), 30fps, 6.0s = 180 frames, seamless loop
- Target: Single HTML file
## Brief
A seamless hero loop (6s) for Ledgerly's website. Ambient, not attention-grabbing — it sits behind a headline. Must loop with no visible seam.
## Look
- Palette (background, accent, text): #0c0d12, #6ee7ff, #e8ecf3
- Type: UI sans 22–28px.
- Texture: Soft blurred gradient blobs, 60px blur, low contrast.
## Beats (exact timings)
1. 0.0–6.0s — Three glassy UI cards ("Inbox zero", "3 rules active", "Saved 4h this week") float on independent sine paths (amplitude 10–18px, periods that divide the loop exactly: 6s, half and a third of it). Background blobs drift on circular paths with a period of 6s. A 2% camera drift (scale 1→1.02→1) over the loop.
## Motion rules
- Every periodic motion's period divides the loop length exactly.
- Leave the left 45% calm for headline text.
## Known failure modes — avoid these
- Periods that don't divide the loop — causes a visible jump at the seam.
## Build
- Output ONE self-contained HTML file. No CDNs, web fonts, images or scripts from URLs.
- The stage is exactly 1920×1080 and scales to fit the window (letterbox) while keeping the aspect ratio.
- Expose window.__addmotion = { width: 1920, height: 1080, fps: 30, duration: 6, seek(t) } where seek(t) renders the exact frame for time t in seconds.
- Make every frame a pure function of t: compute positions from t (with easing functions you define) rather than accumulating state. Use requestAnimationFrame only to call seek(performance.now()/1000 % duration) for live preview.
- If you use CSS @keyframes, seek(t) must set animation-play-state: paused and a negative animation-delay of -t seconds on every animated element.
- To export MP4, step seek(t) frame by frame in a headless browser, screenshot each frame, and encode with ffmpeg.
## Done when
- [ ] Frame 0 and frame N are identical
- [ ] No element crosses the left 45% text area
- [ ] You scrubbed the start, middle and end of every beat and nothing overlaps, clips or jumps
Before writing code, restate the beat list with frame numbers. Then build it in one pass.