# REPORT — 12-synthwave · NEON DRIVE · 霓虹疾驰

## Concept

A VHS tape boots, the "NEON DRIVE" program loads through a Y2K dialog, and the file it opens
is a midnight highway rendered as pure synthwave: a chrome sunset over an infinite neon grid,
the word **Midnight** writing itself in light, then slamming into chrome for the title card.

The film is one continuous one-point-perspective shot — the "camera" never cuts, it only
dollies, glitches and lets the CRT mask breathe, so the whole ten seconds read as a single
unbroken signal off an 1986 tape that has been left running too long.

## Beat sheet (cue sheet — identical at the top of parts/film.mjs and audio.py)

120 BPM · beat = 0.500 s · bar = 2.000 s

| time | picture | sound |
|---|---|---|
| 0.00 | VHS power-on: 4:3 mask boots in, static burst, colour bars settle | white-noise burst + tape thump + 1.85 kHz HV whine |
| 0.28 | tape clunk, tracking band settles | brown-noise clunk + tri blip |
| 0.50 | **beat 1** — grid starts rolling, sun rises, pads/arp enter (Am) | four-on-the-floor kick, saw arp, pad |
| 1.00 | gated snare enters; hats on the eighths; palms sway | snare every 1.0 s, hats on 8ths |
| 2.50 | chord → **F**; mountains intensify | chord change |
| 3.32 | neon tube ignites; **"Midnight"** writes on in script neon | chirp 180→1500 Hz, sparkle bell arp |
| 4.30 | **Y2K window pops in** (NEON_DRIVE.EXE) | pop (420→1200 Hz) + boing |
| 4.62 | progress bar ticks 0→100 %, rising pitch | pitched square ticks every 0.108 s |
| 4.50 | chord → **C** | chord change |
| 5.55 | cursor **CLICK** on ▶ 开始 | click blip + noise |
| 5.60 | riser + whoosh build into the hero | riser 300→6500 Hz, whoosh |
| 6.20 | **HERO** — chrome slam; magenta/cyan double glow; lens flare; anamorphic bar | chord stab + crash + impact + sub(41 Hz) + bell |
| 6.20 | chord → **Am** (hero) | |
| 7.36 | Chinese tagline **霓虹疾驰 / 一九八六 · 夏夜公路** writes | bell arp on each beat |
| 8.20 | chord → **F** (outro); scene calms to the composed hold | pad swells |
| 8.70 | outro crash, sustained ride, fade | crash + impact + bell |
| 9.5–10 | composed end hold — still alive (bokeh drift, kerning, grid crawl) | fade out |

## How each signature feature is realised

1. **Neon glow** — every luminous element is drawn twice: once blurred at ~30 px through a `lighter` pass and once crisp on top (title at 6.20 s, script at 3.32 s, grid at 0.50 s).
2. **Double glow, tight ~4 px + wide ~30 px** — `ctx.filter = 'blur(4px)'` for the core and a second `blur(30px)` pass additively, on the title (6.20 s) and the tagline (7.36 s).
3. **Perspective grid horizon** — rows plotted at `y = HORIZON + A/d` scrolling outward, converging verticals to the vanishing point at (960, 560); magenta horizon rule drawn crisp outside the blur so it never blows out (from 0.50 s, `gridSpeed(t)`).
4. **Multi-layer sunset gradient sun** — 460 px disc, 6-stop gradient `#fff6b0 → #ffd21f → #ff7a12 → #ff1f6e → #c4008f → #8a0096`, banded with `destination-out` slats, clipped at the horizon; rises from 0.50 s, peaks behind the title at 6.20 s.
5. **Scanlines + RGB chroma split** — a 2 px scanline multiply pattern at ~10 %; chroma split is 3 channel-isolated passes (multiply + `destination-in`) composited `lighter` at −dx/0/+dx, quantised to whole pixels (always on, strongest on impacts).
6. **Chrome metal type** — `buildWordmark` bakes a high-contrast chrome gradient with a top sheen and dark bottom bevel plus a dark halo; the title slams in at 6.20 s with a masked glint sweep and a lens flare.
7. **Acid palette** — magenta `#ff2f9e`, cyan `#25e8ff`, orange `#ff6a24`, acid green `#8bff3c` on a deep-violet field; no neutral grey anywhere except the Y2K chrome.
8. **Skeuomorphic window UI** — the NEON_DRIVE.EXE dialog (4.30–5.55 s) has a title bar, traffic-light buttons, an inset progress trough with a striped fill, a ▶ 开始 button and a live % read-out; it maximises with a white flash to drive the transition to the hero.
9. **VHS aging chain** — RGB split 1–2 px → 2 px scanlines at 10 % → wavy tracking band plus random glitch slices 1–2×/s → 4:3 rounded mask (boots in 0.00–0.70 s, retracts for the wide hero 0.70–1.14 s); whole chain always on.
10. **Y2K motion language** — pop-up window (4.30 s, anticipation→travel→rebound), cursor travels and clicks ▶ 开始 (5.55 s), window maximises / drags into the title (5.55–6.20 s).
11. **Deliberate frame-rate instability** — key passages hold a 15 fps stepping look via closed-form frame-hold quantisation, and short 2-frame reversals run at the glitch hits (0.28, 4.30, 5.55, 6.20 s), so the tape visibly stutters and slips.

## Tech route

- Canvas 2D, 1920×1080, `alpha:false` context. Everything is a **pure function of `t`**: no `Date.now()`, no `Math.random()` (build-time `mulberry32(19860712)` only), no CSS animation, no rAF-driven state, no per-call accumulation.
- Static content (sky, stars, mountains, palms, wordmark, script, static tiles, dust, scan pattern) is pre-rendered once into offscreen canvases in `init()`, then blitted per frame.
- The only 2D feature that needed a local helper: **`rrPath()`**, which appends a rounded rect to the current path without calling `beginPath()`, so the 4:3 side-bar mask and the CRT frame can be filled with the `evenodd` rule. (The shared `roundRect()` calls `beginPath()` internally and therefore cannot build an even-odd mask.)
- Post chain (in `draw()`): chroma split → glitch slices → tracking band → scanline multiply → boot static → vignette + tile grain → 4:3 rounded mask → CRT rounded frame.
- Camera: a dolly zoom about (CX, HORIZON) so the baked sky horizon stays locked to the grid (push-ins at 0.85–3.60 s and 4.20–6.15 s), plus a floating hand-held offset.
- Audio: `audio.py`, ~5.4 s runtime, 100 % synthesised from `shared/audio.py`; A-minor at 120 BPM; chord map Am/F/C/G driven by the same `CHORD_AT` table as the picture.

## Check numbers

| metric | value | spec |
|---|---|---|
| duration | **10.000 s** | 10.000 |
| resolution | **1920×1080** | 1920×1080 |
| fps | **30** (300 frames) | 30 |
| video | h264 yuv420p | h264 |
| audio | aac 48 000 Hz stereo | stereo AAC 48 kHz |
| integrated loudness | **−13.7 LUFS** | ≈ −14 |
| true peak | **−2.3 dBTP** | ≤ −1 |
| bitrate | **24.3 Mbps** | 8–25 |
| black frames | 0 | 0 |
| frozen frames | 0 | 0 |
| console errors | 0 | 0 |
| dead spans (rhythm.mjs) | **none** (min 2.41 % moved) | none |

`node harness/render.mjs demos/12-synthwave` prints no PROBLEMS line.

## Top-3 weaknesses (honest)

1. **Held-camera stretches are the calmest part of the film.** Between 1.0–2.0 s and 7.0–8.0 s the grid crawl + dust + palm sway carry it at ~2.4–3.6 % moved — above the dead threshold and deliberately calm, but a sharper eye would still call those bars the least eventful of the ten seconds.
2. **15 fps / frame-reversal instability is a closed-form approximation**, not true variable frame timing — it reads as a tape stutter in motion but a frame-by-frame inspection shows the hold pattern is regular rather than organically random.
3. **The Chinese tagline is typographically safe rather than brave.** PingFang SC at 46/24 px with letter-spacing is clean and tofu-free, but it does not push the acid/synthwave styling as hard as the Latin chrome does — the Latin and CJK halves of the identity are not yet at the same level of flourish.

## Self-scores (/10)

| dimension | score |
|---|---|
| style fidelity | 9 |
| concept | 8 |
| motion craft | 8 |
| design & type | 8 |
| finish | 9 |
| sound & sync | 8 |
| technical | 9 |
