---
name: spoke-map
version: 1.0.0
description: Show one central idea and 3-6 related parts as a 1920x1080 hub-and-spoke film. The hub resolves first, then each route draws out and its node lands, in order. HyperFrames render with optional synthesised cue sounds.
---
# Spoke Map

A parameterized renderer (HTML/SVG + GSAP, rendered with HyperFrames), not a prompt-to-film tool. You write a short JSON brief; `scripts/create.mjs` turns it into an editable project and `scripts/render.mjs` renders it. Other diagram shapes need new authoring and new checks.

Read [direction](references/direction.md) for the beats, [input](references/input.md) for the brief contract and [sound](references/sound.md) for the cue map. [third-party](references/third-party.md) lists bundled libraries and licenses.

## Use it
Requirements: Node 22+, ffmpeg/ffprobe, a Chrome HyperFrames can drive. No API key; the only network use is fetching the pinned renderer through `npx`.

```sh
node scripts/create.mjs --brief brief.json --out ./project [--palette dunes|deep-teal|plum-paper] [--palette-file tokens.json] [--audio on|off]
node scripts/render.mjs ./project ./project/film.mp4 [--silent] [--workers N]
```

`render.mjs` writes `film.mp4` (H.264 + 48 kHz stereo AAC cue track) and `film.video-only.mp4` (same picture, no audio stream). With `--silent`, `--audio off` or `"sound": {"enabled": false}` only a picture-only file is written. The cue list is plain data in `project/cues.json`; edit it and render again to retime or drop cues.

Brief fields: `core` (hub text), `spokes` (3-6 labels or `{label, mark}`), optional `heading`, `routeStyle` (`plain` or `beaded`), `demoNote`, `lang`, `palette`, `sound`. Mark invented content with `demoNote` such as "Demo data".

## Keep
- Order: hub resolves and stays put; each spoke draws from the hub toward its node, the node lands as the route arrives; the last landing closes the hub frame; hold of at least 1.5 s. Motion starts after 0.16 s.
- Node positions come from a collision search (largest label size, widest ellipse that fits); too-long labels fail with a readable error instead of overlapping.
- Duration depends on the spoke count (about 6.9 s for 4 spokes, 8.3 s for 6).
- Sound is synthesised from the visible events in `cues.json` (hub swell, a glide per route, a pitched pop per node rising with the index, a closing chord, optional quiet bed). No samples or recordings. Say "synthesised cues", never "mixed soundtrack", and do not claim anyone listened unless a person did.

## Check before delivering
Run `render.mjs` (it runs `hyperframes check` first); confirm 1920x1080, 30 fps, expected duration and audio streams; look at frames at the hub, each route midpoint, each landing and the final hold. Check text against the brief and that nothing is clipped. Measure the audio (ffprobe, loudness, true peak) and compare cue times with the frame where each element first changes. Chinese briefs switch to Noto Sans SC automatically; check them separately.
