---
name: milestone-track
description: Make a 1920x1080 motion clip with optional synthesized cues that draws a horizontal track and lands 2-6 dated stops on it one by one, each with a large date and a short note, then holds still.
version: 1.0.3
category: video
delivery: download-only
---

# Milestone Track

A parameterized renderer, not a free-form scene generator. A JSON brief goes through `scripts/create.mjs` into an editable HyperFrames project (HTML/CSS plus a deterministic GSAP timeline), and `scripts/render.mjs` renders it to MP4. The Agent writes the brief (short dates, short notes) and picks a palette. The layout, timing and validation are fixed by the scripts.

Read `references/direction.md` for the beat order and `references/input.md` for the brief format before editing anything.

## Use

```sh
node scripts/create.mjs --data /abs/brief.json --out /abs/project --style harbor
node scripts/render.mjs /abs/project /abs/video.mp4
```

Brief: optional `heading`, 2-6 `stops` of `{when, note}`, optional `footnote`, optional `sound`. Mark invented numbers or dates as demo data in the `footnote`. Palettes: `harbor`, `chalk` (light), `ember`, `slate` (dark). `--colors file.json` overrides single tokens with six-digit hex values.

The create step stops with a readable message when the brief is wrong (count, unknown fields, labels too long for the stop count). Fix the brief rather than lowering limits.

## Sound (optional)

`render.mjs` always writes a video-only MP4. To add sound, run the cue synthesizer on that file:

```sh
node scripts/sound.mjs --project /abs/project --video /abs/video-only.mp4 --out /abs/video-with-audio.mp4
```

The project's `sound.json` is the sound map: one cue per visible beat (rail wipe, accent-line glide, marker tick whose pitch climbs with each stop, date swish, note tap, final chime) plus an optional quiet pad. Cues are synthesized from math in `sound.mjs` (no samples, no models, no network), panned by the stop's horizontal position, written as 48 kHz stereo and muxed as AAC with the video stream copied. Set `"sound": {"enabled": false}` in the brief to opt out (the script then refuses to mux) or `"bed": false` to drop the pad. Keep the video-only file for posters and covers.

This is a set of cues, not a composed soundtrack. Loudness, true peak and cue timing can be measured; whether it sounds good needs a person to listen.

## Requirements

Node.js 22+, FFmpeg, a Chrome that HyperFrames can drive, and `hyperframes@0.8.30` (run through pinned `npx`; `HYPERFRAMES_CLI=/abs/path/to/hyperframes.mjs` can point at a preinstalled copy, it is a tool path and not a credential). The first run may need network access. No API keys, models or other Skills are used. Fonts and GSAP ship locally with their licenses.

## Review before delivering

The renderer's own output has no audio stream; sound exists only if you run `sound.mjs`. Run `npx --yes hyperframes@0.8.30 inspect /abs/project --json`, then check the first frame, the frames around each stop landing, and the last frame at native resolution. Look for crowded dates, wrapped notes colliding with the next stop, and low contrast on custom colors. A passing build is not visual approval.

See `references/third-party.md` for bundled runtime dependencies and their licenses.
