feat(mockups): slot 14 voyage with side panel; record verdict on 13

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas Winther
2026-10-30 00:53:44 +01:00
co-authored by Claude Opus 5.5
parent e3fd97a78c
commit 3cda08c32e
12 changed files with 137 additions and 8 deletions
+2 -2
View File
@@ -1,7 +1,7 @@
# EPIC: The Musical Timeline
Unofficial fan site: an interactive timeline of *EPIC: The Musical* songs. Currently 7 design-direction
mockups. Bun 1.3.14 (server, bundler, test runner), TypeScript, three.js (mockups 06/07/13 only), Docker.
mockups. Bun 1.3.14 (server, bundler, test runner), TypeScript, three.js (mockups 06/07/13/14 only), Docker.
`AGENTS.md` is the single source of truth for agents here. `CLAUDE.md` and `GEMINI.md` only point here.
Deeper context on demand: `docs/ARCHITECTURE.md`, `docs/DECISIONS.md`, `docs/TODO.md`.
@@ -10,7 +10,7 @@ Deeper context on demand: `docs/ARCHITECTURE.md`, `docs/DECISIONS.md`, `docs/TOD
Install: `bun install --frozen-lockfile`
Dev: `bun run dev` (`PORT` env, default 3000)
Test: `bun test` | Single file: `bun test tests/data.test.ts` | Single case: `bun test -t "registry has 13"`
Test: `bun test` | Single file: `bun test tests/data.test.ts` | Single case: `bun test -t "registry has 14"`
Typecheck: `bun run typecheck`
Build: `bun run build` | Run the build: `bun run start`
Docker: `docker build -t epic-timeline .` then `docker run --rm -p 3000:3000 epic-timeline`
+5
View File
@@ -53,3 +53,8 @@ artefacts: kept after merge they go stale and contradict the code, so the spec i
**Decision:** mockup 13 (Curtain call) may use three.js, like 06 and 07. It mocks the frieze → 3D sea →
frieze → cave transition, which needs the 3D sea. three.js is already a dependency; nothing new is added.
## 2026-10-30 — three.js allowed in mockup 14
**Decision:** mockup 14 (Voyage with side panel) may use three.js; it converges 13's 3D flow with a
persistent side panel. No new dependency.
+1 -1
View File
@@ -22,7 +22,7 @@ or `AGENTS.md` Commands.
| `bun install --frozen-lockfile` | worked (no changes) |
| `bun test` | worked — 34 pass, 0 fail, 3 files |
| `bun test tests/data.test.ts` | worked — 10 pass |
| `bun test -t "registry has 13"` | worked — 1 pass |
| `bun test -t "registry has 14"` | worked — 1 pass |
| `bun run typecheck` | worked (`tsc --noEmit`, exit 0) |
| `bun run build` | worked — `dist/server.js` + hashed page assets |
| `bun run dev` (`PORT=3113`) | worked — `/` and all mockup routes 200, no-slash form 302 |
+26 -4
View File
@@ -202,14 +202,36 @@ mockup of the transition.
`docs/design/002-sea-chart-spikes/13-curtain-call-report.md`. Preview rebuilt with 01–13.
Known rough spots: a small sideways camera shuffle at landfall, sun glare in looks 1/2, a boxy giant.
### 14. Verdict on 13 Curtain call
> "Yes it looks pretty good! Small design issues here and there but these can be fixed. 1, 2 and 3 all
> look decent. The UI of 2 and 3 tend to look a bit better though. For the models/3d, its better to go
> stylistic than realistic. While going through the 3D experience, its still important to have the
> right side window open, to show information, paths, lyrics, and fan works."
- **Accepted:** the curtain-call flow (frieze → sea → landfall → frieze → landing) works; small design
issues are fixable later.
- **Look:** all three are "decent"; the UI of **2 (two worlds)** and **3 (frieze-led)** looks better.
Look 1 (vellum throughout) is effectively out; 2 vs 3 is not decided.
- **3D models: stylistic, not realistic.**
- **New requirement:** during the 3D experience a **right-side window stays open**, showing:
- information (about the current song/place);
- paths (motif threads / the route);
- lyrics;
- fan works.
- *(Claude's proposal)* Converge into **14 Voyage with side panel**: 13's flow with stylised models and
a persistent right panel (tabs: About · Paths · Lyrics · Fan works), with a 2/3 look toggle.
Fan works and lyrics are placeholders (no real lyrics, no real fan artists' names or links).
## Open questions (in priority order)
1. ~~Which sea-chart approach (08–11) reads best, or which mix?~~ 11's navigation + 10's style (§9).
Then A/B/C inside plates: **A threads** (§12).
2. What is the look of the whole: frieze-led (terracotta and black), chart-led (parchment), or
something in between? The user is "not sure" yet.
3. How do 2D and 3D relate as products? Is the 3D the main experience with the chart inside it, while
the chart also stands alone? This is unconfirmed.
2. What is the look of the whole? Narrowed to look 2 (two worlds) or 3 (frieze-led) (§14).
3. How do 2D and 3D relate as products? Partly answered: in 3D a right-side panel stays open with
info, paths, lyrics and fan works (§14). Whether the chart also stands alone is unconfirmed.
3b. Fan works: what are they (art, covers, animatics?), where do they come from, and how are they
credited? No data model for them yet.
4. Which landings are in scope for the first build? The user's examples are the Cyclops' cave, God
Games and Ithaca.
5. Earlier, still open from 001: lyrics copyright (deferred), branching policy, linter, and what
@@ -0,0 +1,76 @@
# 14 Voyage with side panel — converge brief
## Why
The user's verdict on 13 Curtain call (verbatim):
> "Yes it looks pretty good! Small design issues here and there but these can be fixed. 1, 2 and 3 all
> look decent. The UI of 2 and 3 tend to look a bit better though. For the models/3d, its better to go
> stylistic than realistic. While going through the 3D experience, its still important to have the
> right side window open, to show information, paths, lyrics, and fan works."
14 starts from a **copy of 13** (`src/mockups/13-curtain-call/`) and changes three things:
1. **Persistent right-side panel** (the main new thing).
2. **Stylised models**, not realistic.
3. **Look toggle 2 / 3 only** (`?look=2|3`, default 2). Drop look 1.
Keep 13's five beats, transitions, Play/step controls, `?beat=` `?t=` `?play=`, and the small vellum
chart. Fix 13's known rough spots while you're there: the sideways camera shuffle at landfall, the big
sun glare.
## 1. The side panel
- A right-hand panel, about 400–440px wide, **open throughout the 3D beats** (2 sea, 3 landfall,
5 cave). The 3D view fills the remaining width; frame the camera so the ship and island sit in the
visible area, not behind the panel. During the frieze beats (1, 4) the panel may stay open too
(preferred — it should feel like one persistent companion) — your call, but say what you chose.
- It can be collapsed to a slim tab, but starts open. `?panel=0` starts collapsed.
- It follows the voyage: each beat has a current song (beat 1 The Horse and the Infant, 2 Full Speed
Ahead, 3 Polyphemus, 4 Polyphemus, 5 Survive — check ids in `src/data/sample.ts`), and the panel
updates with a gentle transition when the beat changes.
- Tabs, `?tab=about|paths|lyrics|fan`:
- **About** — song title, track number, saga, story time, the Odyssey reference (book/lines from the
data), parts with singers, `createAudioSlot` and `createVideoCards` from `src/shared/`.
- **Paths** — the route and the motifs: a compact vertical **thread** strip (the user chose threads
in 12: soft coloured threads with knots where a motif plays) showing this song's motifs and where
each comes from / goes next ("Polyphemus — first heard here · returns in Survive"). Clicking a
motif highlights its thread; clicking a song in it is just a highlight (no navigation needed).
The small vellum chart may move into this tab or stay on the table — your call.
- **Lyrics** — the song's lyrics split by part with singer labels, using the **placeholder** lyrics
from the sample data (never real lyrics). Highlight motif lines with the motif colour. A current-part
marker is a nice touch, not required.
- **Fan works** — 3–4 placeholder cards per song: type (art / animatic / cover / cosplay), a
stylised placeholder thumbnail (CSS/SVG, no external images), a made-up clearly-placeholder title,
"by @fan-artist" placeholder handle, and a "credit + link to the original" line. Add a visible note
"Placeholder fan works — real ones will be credited and linked to their creators." Keep this data
local to your folder (e.g. `fanworks.ts`); do not change `src/data/`.
- The panel follows the look: look 2 parchment/vellum panel; look 3 dark/terracotta frieze panel.
Text must stay comfortably legible (≥15px body, good contrast) in both.
## 2. Stylised models
"Stylistic rather than realistic." Make the 3D read like illustration, consistent with the frieze:
flat or toon shading (e.g. `MeshToonMaterial` or flat `MeshLambertMaterial` with a stepped gradient
map), a limited palette per look, ink outlines (inverted-hull or `EdgesGeometry` lines), simple
graphic shapes. Stylised water (flat bands/patterned waves, not a realistic glare). The island a bold
graphic shape. **The giant** should become a strong stylised silhouette (black-figure inspired, one
eye) rather than boxes. Ship: graphic, silhouette-first.
## Rules
- Edit ONLY `src/mockups/14-voyage-panel/` (stub files exist; index.html links credits; main.ts calls
`mountCredits()`; replace the stub style.css with unique content). three.js is allowed. Copy from 13
(and 04/07/12 if useful) into your folder; don't import across mockup folders.
- Credits footer fully visible in every beat and with the panel open.
- Build to `/tmp/claude-1000/-home-user-epic-the-musical-timeline/fb650f6d-47a0-47e4-8f6b-197d02417f3b/scratchpad/r3-14`,
serve with `cd <outdir> && PORT=4114 bun server.js`. Kill only your own server.
- Screenshots 1440×900 with `--use-angle=swiftshader --use-gl=angle --enable-unsafe-swiftshader
--virtual-time-budget=6000` (plain `--use-gl=swiftshader` often captures a black stage):
`screenshots/14-voyage-panel-beat{1..5}.png` (look 2, tab about),
`-paths.png`, `-lyrics.png`, `-fan.png` (beat 3), `-beat2-look3.png`, `-beat5-look3.png`,
`-lyrics-look3.png`, `-collapsed.png`. Look at every one; fix what's off.
- `bun test` and `bun run typecheck` must pass. Don't commit. Don't spawn subagents.
- If you run low on budget, stop and write a pause report (done / checklist / next step) instead.
- Report to `docs/design/002-sea-chart-spikes/14-voyage-panel-report.md`: what you built, what works,
what doesn't, screenshots, and a short honest comparison of looks 2 and 3 with the panel.
+1
View File
@@ -26,6 +26,7 @@
<li class="card"><a href="/mockups/11-chart-atlas/"><span class="card__num">11</span><h2>Atlas with insets</h2><p>An overview chart of the whole sea; each saga island opens an inset chart with its songs as ports.</p><p class="card__try">Try this: Open an island's inset, then a song, then zoom back out.</p></a></li>
<li class="card"><a href="/mockups/12-vellum-atlas/"><span class="card__num">12</span><h2>Vellum atlas</h2><p>The atlas overview and island plates of 11, drawn in the vellum portolan style of 10.</p><p class="card__try">Try this: Open Cyclops' Island, pick a theme, and switch the plate's motif style (A/B/C).</p></a></li>
<li class="card"><a href="/mockups/13-curtain-call/"><span class="card__num">13</span><h2>Curtain call</h2><p>The frieze curtain that carries you from the 2D story into the 3D sea and down into a landing.</p><p class="card__try">Try this: Press Play, or step through: frieze, sea, Cyclops' Island, frieze, cave. Switch the look (1/2/3).</p></a></li>
<li class="card"><a href="/mockups/14-voyage-panel/"><span class="card__num">14</span><h2>Voyage with side panel</h2><p>The curtain-call voyage with stylised models and a side panel that stays open: about, paths, lyrics, fan works.</p><p class="card__try">Try this: Play the voyage and watch the panel follow; open Lyrics and Fan works; switch the look (2/3).</p></a></li>
</ul>
</main>
<footer data-fan-credits></footer>
+15
View File
@@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Voyage with side panel — EPIC Timeline mockup</title>
<link rel="stylesheet" href="../../shared/credits.css" />
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<main id="app"></main>
<footer data-fan-credits></footer>
<script type="module" src="./main.ts"></script>
</body>
</html>
+3
View File
@@ -0,0 +1,3 @@
import { mountCredits } from "../../shared/credits";
mountCredits();
+1
View File
@@ -0,0 +1 @@
body { margin: 0; --stub-14: 1; }
+3
View File
@@ -40,4 +40,7 @@ export const mockups: MockupInfo[] = [
{ slug: "13-curtain-call", number: 13, name: "Curtain call",
pitch: "The frieze curtain that carries you from the 2D story into the 3D sea and down into a landing.",
tryThis: "Press Play, or step through: frieze, sea, Cyclops' Island, frieze, cave. Switch the look (1/2/3)." },
{ slug: "14-voyage-panel", number: 14, name: "Voyage with side panel",
pitch: "The curtain-call voyage with stylised models and a side panel that stays open: about, paths, lyrics, fan works.",
tryThis: "Play the voyage and watch the panel follow; open Lyrics and Fan works; switch the look (2/3)." },
];
+3
View File
@@ -13,6 +13,7 @@ import m9 from "./mockups/10-chart-scroll/index.html";
import m10 from "./mockups/11-chart-atlas/index.html";
import m11 from "./mockups/12-vellum-atlas/index.html";
import m12 from "./mockups/13-curtain-call/index.html";
import m13 from "./mockups/14-voyage-panel/index.html";
export function startServer(port: number): Server<undefined> {
return Bun.serve({
@@ -45,6 +46,8 @@ export function startServer(port: number): Server<undefined> {
"/mockups/12-vellum-atlas": Response.redirect("/mockups/12-vellum-atlas/", 302),
"/mockups/13-curtain-call/": m12,
"/mockups/13-curtain-call": Response.redirect("/mockups/13-curtain-call/", 302),
"/mockups/14-voyage-panel/": m13,
"/mockups/14-voyage-panel": Response.redirect("/mockups/14-voyage-panel/", 302),
},
development: process.env.NODE_ENV !== "production",
fetch() {
+1 -1
View File
@@ -8,7 +8,7 @@ let base: string;
beforeAll(() => { server = startServer(0); base = `http://localhost:${server.port}`; });
afterAll(() => server.stop(true));
test("registry has 13 mockups", () => expect(mockups).toHaveLength(13));
test("registry has 14 mockups", () => expect(mockups).toHaveLength(14));
test("index links every mockup", async () => {
const res = await fetch(base + "/");