feat(mockups): 09 schematic sea chart spike

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas Winther
2026-10-29 02:34:37 +01:00
co-authored by Claude Opus 5.5
parent e880a69177
commit a422234970
4 changed files with 1107 additions and 93 deletions
@@ -1,102 +1,97 @@
# 09 — Schematic sea chart (`09-chart-transit`): interrupted
# 09 — Schematic sea chart (`09-chart-transit`): report
Status: **stopped before any code was written** (the coordinator called a halt for the usage limit).
`src/mockups/09-chart-transit/` is still the untouched stub. No files were left half-edited.
Status: **done**. Built from the saved plan. `bun test` (42 pass) and `bun run typecheck` pass. The build
goes to the scratchpad outdir `r2-09-chart-transit`, served on port 4109. Nothing is committed.
## What's done
Files: `src/mockups/09-chart-transit/layout.ts` (new), `main.ts`, `style.css`. `index.html` is unchanged.
- I read the brief (`round2-brief.md`), `AGENTS.md`, `docs/design/002-direction-round-notes.md`, the shared contract (`src/data/*.ts`, `src/shared/*.ts`), the layout code for mockups 03 (`map.ts`) and 07 (`route.ts`), and the screenshots for 01, 03 and 07.
- I loaded the `frontend-design` skill and settled the design plan below. It is not built yet.
## The navigation idea
## Design plan (settled, ready to build)
The ship's course is straightened into a transit-map schematic, like mockup 03:
- x is story time: a hop of 92 between songs, +100 per year, +70 when the saga changes.
- Each saga is a horizontal row, and the rows are joined by single 45° diagonals in the gaps between
ports. Every port therefore sits on a horizontal, and every label is level and unrotated.
- Under the course is a faint Admiralty-style chart: pale water, rhumb lines from a compass rose, buff
"saga islands" with a shoal band and dashed depth contours, and a dashed storm cell at Storm.
**Look:** this is an Admiralty-chart palette, not cream parchment.
- Deep water `#f4f7f5` is the background.
- Shoal bands `#d3e5ea`.
- Buff land `#ecdca4`.
- Navy chart ink `#1f3346`.
- Chart magenta `#a8326e` marks the ship's course and "you are here". This is the one bold element.
- Fonts are Cormorant Garamond and Inter, both via `@fontsource`:
- Cormorant: upright for land and saga names, italic for sea areas and in-story time.
- Inter: port labels and UI.
Motifs run as coloured lanes parallel to the magenta course:
- Character themes run on the left of the course and musical motifs on the right, each in a fixed lane.
- A lane is solid where the motif plays in consecutive songs. A single song gets a ~30px stub.
- A dotted lane means the theme is silent there and returns later.
- Each port is a capsule across the course and every lane that calls there.
**Schematic layout** (to go in `layout.ts`):
- The x-axis is story time:
- hop 92 between songs;
- +110 per year;
- +50 when the saga changes;
- X0 = 110.
- The rows are octilinear:
- Troy row at y≈290;
- a 45° diagonal down to the Cyclops row at y≈410;
- a long diagonal down to Storm at y≈590.
- The diagonals sit only in the gaps between ports, so every port is on a horizontal.
- Labels are horizontal, centred above each port, and wrap to two lines (max ~88px).
- The `storyTime.label` goes in italic below the lanes, with a year tag wherever the year changes.
- Gaps of a year or more carry an italic note on the course, such as "a year passes".
A slider (with "Schematic" and "True geography" end buttons that animate) morphs every sample of the
course to a rough equirectangular Aegean–Ionian map. Land crossfades to coastlines, a graticule fades
in, lanes pull closer to the course, and names give way to track numbers.
**Motif lines:**
- Each motif gets a fixed lane parallel to the course: character themes on the left (north) side, musical motifs on the right (south) side, spaced 10 apart.
- A lane is drawn only over runs of consecutive songs that contain that motif. A single-song run gets a ±30 stub.
- Between runs, a faint dotted lane shows the motif returning.
- Lanes are built as offset polylines with miter joins, plus `roundedPath` (re-implement it locally; don't import from 03).
- Pale data colours are darkened toward a warm dark until they reach about 2.6:1 contrast on the paper. Each line has a paper-coloured casing.
- At each port, a capsule perpendicular to the course spans the lanes present. A port with 2 or more motifs is an interchange and gets a heavier border.
## What works
**Chart layer:**
- A compass rose in the empty top-right, around (1210, 190), with faint rhumb lines radiating across the chart.
- Schematic islands: soft blobs drawn as closed Catmull-Rom curves.
- A Troy blob under the Troy row.
- A Cyclops blob under the Cyclops row.
- A storm cell (dashed rings) at Storm.
- Dashed depth contours, drawn as scaled copies of each blob.
- **Readable at a glance (the round's question).** At the default 1440×900, all ten song titles,
three saga names, every in-story time label, the year tags (Year 0, 1, 3) and the gap notes ("a year
passes", "two years pass") are visible together with no hunting. Straightening the course is what
makes this possible.
- **Motif tracing is very clear.**
- Selecting a theme fades the other lanes to 13% and rings its ports in the theme colour.
- Ports that don't carry it are greyed.
- The key prints "plays in 5 songs: …".
- The dotted "returns later" stretches show when a theme goes silent and comes back. 03 couldn't
show that.
- **One chart serves both uses.** At `?overlay=1` the same SVG renders inside a ~1180×650 card over a
dimmed sea gradient:
- the viewBox is cropped to the course;
- time labels are hidden and the key becomes chips;
- a magenta ship marker reads "You are here: Survive";
- clicking a port opens a popover with **Sail here** (the ship animates along the course and the
pill reads "Sailing to Storm", then "You are here: Storm") and **Song details**.
- **The morph earns its place.** At `?morph=1` you see that the voyage really doubles back westward,
and the slider makes the cost of geography obvious: ports 06–09 cluster at Messina and their names
can't fit.
- **Detail drawer.**
- Contents: track and saga, title, story time with years after Troy, Odyssey link, theme chips (which
select the motif), parts with singers and motif dots, `createAudioSlot` and `createVideoCards`.
- The chart pans left when the open port would sit under the drawer, e.g. Storm.
- **Interactions and accessibility.**
- URL state: `?song=`, `?motif=`, `?overlay=1`, plus `?morph=0..1` and `?pop=<id>` for screenshots.
- Escape closes the popover, then the drawer, then the motif.
- Ports are keyboard-focusable.
- Reduced motion is respected.
- **Credits.** The credit is fixed at the bottom and fully visible in every state.
- **Verification.** Click flows were checked over Chrome DevTools: port → drawer, key → motif,
geography button → morph=1, overlay popover → Sail here → arrival, and popover → details. No console
errors.
**Morph slider (schematic ↔ true geography):**
- Sample the course densely by schematic parameter `u`.
- The geo course is a polyline through the songs' lon/lat in an equirectangular projection (lon 11–28.5, lat 35–42, x scaled by cos 38.5°).
- Point = lerp(schematic(u), geo(u), t). Recompute the lanes and ports for every `t`.
- Land crossfades between the schematic blobs and rough Mediterranean polygons: Italy, Sicily, Greece with the Peloponnese, Asia Minor, Crete and Ithaca. I drafted the coordinates in my head; re-derive them.
- Geo positions:
- songs 1–4 near Troy/Ismarus (26.2,40.0 → 24.6,40.3);
- Warrior of the Mind off Cape Malea (22.0,36.0), with via-points so the route avoids Attica;
- the Cyclops songs on Sicily (~15,37.7);
- Storm NW of Sicily (13.0,38.9).
- As `t` rises, the time labels fade out and port labels shrink to track numbers, which shows the trade-off.
- Support `?morph=0..1`.
## What doesn't work (or is weak)
**Page:**
- Title cartouche at top-left, morph control at top-centre, motif key at bottom-left.
- The detail drawer is about 400px on the right and pans the chart when the port would be hidden.
- Contents: title, story time, Odyssey link, parts with singers, motif chips, `createAudioSlot`, `createVideoCards`.
- Selecting a motif fades the other lanes and rings the ports where it plays.
- The footer is styled to be always visible.
- URL params: `?song=`, `?motif=`, `?overlay=1`.
- **Geo mode is a demo of the trade-off, not a usable view.**
- The four Troy ports and the four Cyclops ports bunch up.
- Capsules overlap at the turnarounds, and you only get track numbers.
- The midpoint of the morph (~0.5) is messy: big rotated capsules and two land layers crossfading.
- **The coastlines are hand-drafted and rough.** Hellas and Thrace are one blob, and the Peloponnese
is crude.
- **Song positions are illustrative.** Geo positions per song are rough guesses: Troy and Ismarus,
off Cape Malea, the cave on Sicily's east coast, and Storm north-west of Sicily. They are not
checked against the musical.
- **Interchanges were redefined.** In the sample data every song has 2 or more themes, so I made an
"interchange" mean **3 or more** themes meet. Otherwise every port would be one.
- **Horizontal space is tight.** The hop of 92 only works because titles wrap onto two balanced lines.
The full album (~40 songs) won't fit one screen at this density, so it would need horizontal
panning like 03, or rows that wrap per saga.
- **Many dotted lanes.** Seven lanes plus dotted returns along the whole course get busy. Without a
motif selected, the dotted returns compete a little.
- **Small chart details.**
- In overlay mode, the "N" of the compass is cropped and the ship marker covers the Survive capsule.
- The Odysseus colour was pushed to a brown (contrast 4.6) so it doesn't collide with Warrior gold.
It is no longer the data colour `#f2e3b3`.
- **The key covers some land.** The key panel covers the south-west corner of the Troy island, and the
western lon labels in geo mode.
**Overlay (`?overlay=1`):**
- A dimmed CSS-gradient sea backdrop.
- The chart as a compact card, about 1180×650: story-time labels hidden, key as compact chips, slider hidden.
- A magenta ship marker reading "You are here: Survive".
- Clicking a port opens a popover with "Sail here", which animates the ship along `u`.
## Screenshots
## What's left
- [ ] Write `layout.ts`: schematic trunk, port positions, geo coordinates and polygons, morph sampling, offset lanes, `roundedPath`, blobs.
- [ ] Write `main.ts`: SVG render (static chart layer plus a dynamic layer rebuilt on morph), key, motif select, detail drawer, URL params, overlay mode with Sail here, `mountCredits()`.
- [ ] Write `style.css`. It must stay unique, not byte-identical to any other mockup's.
- [ ] Update the `index.html` title if needed. Keep `<footer data-fan-credits>` and the `credits.css` link.
- [ ] Build to `/tmp/claude-1000/-home-user-epic-the-musical-timeline/fb650f6d-47a0-47e4-8f6b-197d02417f3b/scratchpad/r2-09-chart-transit` and serve on port 4109.
- [ ] Take screenshots: `screenshots/09-chart-transit-{default,motif,song,overlay}.png`, plus optionally `-geo.png`. Review them.
- [ ] Run `bun test` and `bun run typecheck`.
- [ ] Rewrite this file as the final report: the idea, what works, what doesn't, and the screenshot paths.
## Known broken bits
- None in the code, since nothing has been written. The stub still renders "Schematic sea chart (stub)".
- Expected risks:
- Port labels may be cramped at hop 92.
- Lanes may self-intersect in geo mode where ports cluster. That is acceptable and shows the trade-off.
- The pale Odysseus colour may sit close to Warrior gold once darkened.
## Next step to resume
Start with `src/mockups/09-chart-transit/layout.ts`, built from the plan above. Then write `main.ts` and `style.css`, then build, take the screenshots and run the checks.
- `screenshots/09-chart-transit-default.png`
- `screenshots/09-chart-transit-motif.png` (`?motif=warrior`)
- `screenshots/09-chart-transit-song.png` (`?song=storm`, chart panned clear of the drawer)
- `screenshots/09-chart-transit-overlay.png` (`?overlay=1`)
- Extras:
- `screenshots/09-chart-transit-overlay-pop.png` (Sail here popover)
- `screenshots/09-chart-transit-geo.png` (`?morph=1`)
- `screenshots/09-chart-transit-mid.png` (`?morph=0.5`)