Canonical benchmark brief
16. City Scroll Journey
Back to all prompts# 16. City Scroll Journey
Build a landing page whose hero is a scroll-scrubbed, continuous camera flight through a stylized miniature city of your choice — 4 to 5 distinct scenes flown as one unbroken forward take, each with its own overlaid copy, ending on a call to action — followed by supporting content sections (destinations, food) and a footer. The reference genre is the cinematic scroll-journey site; your scene media is AI-generated during the build via the provided media-generation MCP. The point is the journey: one continuous, art-directed flight that makes a city feel like a miniature world — not a slideshow, not an autoplay video, not a stack of sections with fade-ins.
Plan first, then execute. Choose one city and one coherent miniature style (vinyl-toy diorama, tilt-shift model town, low-poly, paper-craft — your call) and keep it consistent across every scene and section.
**Tooling.** Two MCP servers are connected and available to you:
- **Higgsfield** (`mcp__higgsfield__*`) — AI image and video generation. Use it to generate the scene clips and stills for the journey and any visuals for the supporting sections. Generate short clips (a few seconds each) with a consistent style prompt across all scenes; they will be scrubbed frame-by-frame, so forward camera motion and visual continuity between neighboring scenes matter more than narrative action. Save all generated media into the target folder.
- **Mobbin** (`mcp__mobbin__*`) — real product UI/UX references. Use it during planning to ground the layout of the supporting sections (card grids, content bands, footer) in proven patterns instead of inventing from scratch.
Keep a record of every generation prompt you use. If an MCP call fails with an authentication error, stop and ask the operator to complete the OAuth login (e.g. `/mcp-config login <server>`) — do not treat it as unavailable. If a generation fails repeatedly, a service is down, or the operator declines to log in, fall back to free local means (code-built canvas/SVG scenes, locally rendered frames) and record the substitution in `manifest.json.warnings`. CDN libraries are allowed but must be listed in `manifest.json.externalAssets`.
## Required features
### 1. The journey
- One continuous forward camera flight through 4–5 distinct, recognizable city scenes (for example: skyline → street market → landmark → waterfront at night). Each scene reads as a different place in the same city at a glance.
- The camera is scrubbed by scroll, in both directions — scrolling down flies forward, scrolling up flies backward. Never autoplay. Roughly 1.2–1.8 viewport-heights of scroll distance per scene, so the flight feels deliberate, not twitchy.
- Scene transitions are seamless: crossfaded or genuinely continuous — no hard cuts, no black flashes, no visible loading between scenes.
- While the journey occupies the viewport it is pinned/fixed; normal page flow resumes after the final scene releases.
### 2. Scene copy
- Each scene overlays its own copy: a short eyebrow label, a title, and 1–2 sentences of body text, plus one accent color that ties title, eyebrow, and UI details together.
- Copy timing tracks the flight: it peaks (fully visible, camera settled or slowest) at a dwell point mid-scene and recedes as the camera moves on.
- The final scene carries the page's call to action: a primary CTA and a secondary CTA. Both are real links (anchors to the page's own sections are fine).
### 3. Stills and fallbacks
- Every scene has a static poster/still that is visible before its media paints, so first paint is never a blank or black hero. For video scenes, the poster is the clip's actual first frame, so the transition from poster to scrubbed video is invisible.
- Under `prefers-reduced-motion`: no scrubbing and no pinned flight. The journey degrades to a stacked sequence of static scenes (poster + copy) that reads as the same story.
- Mobile / coarse-pointer handling: lighter media or reduced effects on small screens, no scroll-jank, no layout jump when the mobile URL bar shows/hides.
### 4. Supporting sections
- Below the journey, a **destinations** section: a grid of at least 3 cards (visual, name, one-line blurb) for popular spots in the chosen city.
- A **food** section: at least 3 items (visual, name, blurb) for signature dishes or food places.
- Both sections animate in on scroll (reveal/stagger), and card visuals match the miniature art direction — generated with the media MCP, rendered, or drawn locally; no hotlinked images.
- A footer closes the page. Plain copy throughout; no fake testimonials, fake logos, or lorem ipsum.
### 5. Atmosphere and craft
- Unified art direction: one miniature style, one palette logic, per-scene accent colors that don't clash.
- Ambient life between scrolls: subtle drifting particles, haze, or light movement so the hero never looks frozen at rest.
- Type stays legible over media at every point of the flight (scrim, contrast, or placement — your choice).
- A site nav that overlays the journey transparently, then becomes a normal sticky bar once the journey releases.
## Output constraints
- Static artifact that opens from `index.html` with no build step (`file://` acceptable), containing only files inside the target directory. No `node_modules`, lockfiles, source maps, or temp tooling.
- No login, no analytics, no tracking. No runtime network requests for media or data; CDN libraries only, listed in `manifest.json.externalAssets`.
- Keyboard-accessible (journey scrolls natively; CTAs and nav are focusable). `lang="en"` on `<html>`. Honor `prefers-reduced-motion` and `prefers-color-scheme`.
- 30+ fps at 1280×800 on a 2020 laptop while scrubbing the journey.
Expose a small automated verification hook that calls the same code paths the UI uses:
```js
window.__journey = {
ready: true,
getState(), // phase (loading/journey/released), scrollProgress 0..1, activeScene index
getScenes(), // [{ id, eyebrow, title, accent, hasPoster, mediaType }] in flight order
setProgress(p), // scrub programmatically to progress p (0..1) without scrolling
getPerf(), // { fps, frames } measured during the last scrub
};
```
## Loop / validation rule
Do not stop until you have personally verified all of the following in a browser:
1. Opening `index.html` shows the first scene's poster immediately — no blank or black hero, no console errors; for video scenes the poster matches the clip's first frame.
2. Scrolling down scrubs the camera forward through every scene; scrolling back up flies it backward; nothing autoplays.
3. All 4–5 scenes are visually distinct places that clearly belong to one city and one miniature style.
4. Scene seams crossfade or continue without hard cuts, black flashes, or loading gaps.
5. Each scene's eyebrow, title, body, and accent color appear and peak at that scene's dwell point, then recede.
6. The final scene shows both CTAs, and both links work.
7. With `prefers-reduced-motion` emulated, the journey renders as stacked static scenes with all copy reachable, and no pinned scrub.
8. At a 390px-wide mobile viewport, the hero loads, scrubs without jank, and resizes (URL-bar simulation) don't jump the layout.
9. The destinations grid renders 3+ cards and the food section 3+ items, each with a local visual matching the miniature style; both sections reveal on scroll.
10. The nav overlays the journey and switches to a sticky bar after the journey releases; page flow below the hero is normal.
11. `window.__journey.getState()` and `getScenes()` agree with what is on screen; `setProgress(0.5)` lands on the expected mid-journey scene.
12. Scrubbing the full journey holds 30+ fps at 1280×800 (`getPerf()` or manual measurement).
13. The page opens over `file://` with zero media/data network requests; every runtime CDN in use is listed in `manifest.json.externalAssets`.
14. All journey media are local files generated during this build, and the record of generation prompts (and any fallback substitutions) is in the folder or in `manifest.json.warnings`.
If any check fails, fix the specific mechanism and re-run all fourteen checks.