6.3 KiB
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 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.
Commands
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 12"
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
Run the production bundle from inside dist/. Bun resolves bundled assets relative to the cwd:
bun run start # right: cd dist && bun server.js
bun dist/server.js # wrong: crashes with 'Bundled file "./index-….js" not found'
Rules
- Every page shows the fan notice and the Jorge Rivera-Herrans credit: keep
<footer data-fan-credits>and the../../shared/credits.csslink in the page's HTML, and callmountCredits()fromsrc/shared/credits.ts. Never write your own notice text. - Mockup agents edit only their own
src/mockups/NN-slug/folder.src/data/,src/shared/,src/server.ts,src/index.htmlandsrc/mockups/registry.tsare the shared contract; change them only when the plan says so. - No two mockups may have byte-identical
style.css— the build fails with "Multiple files share the same output path". Give each one its own styles from the start. - Sample data (
src/data/sample.ts): lyrics are placeholders, never real lyrics. Any fact, story time or Odyssey reference you can't confirm gets// TODO(verify). - Assets are bundled, never loaded from a CDN: fonts from
@fontsource/*, three.js from npm. YouTube videos are link cards (createVideoCards), not embeds. - Adding a mockup route means editing
src/server.ts,src/mockups/registry.tsand the cards insrc/index.htmltogether;tests/server.test.tschecks every registry slug is served and that the index shows each entry's name, pitch and tryThis.
Workflow
Required skills: superpowers, impeccable. Check at session start; install if missing.
Specs → docs/specs/NNN-slug.md (permanent). Plans → docs/plans/NNN-slug.md while in progress;
git rm them before opening a merge request — the spec is the record.
(Overrides the superpowers default paths.)
Anything beyond a trivial fix: brainstorm → spec (sign-off) → plan (sign-off) → TDD → review. Tick plan checkboxes as you go so an interrupted session is resumable. Trivial changes (typo, version bump, one-line config): say "trivial, skipping spec" and proceed.
Use impeccable for user-facing UI — craft for new, audit/polish on existing, harden before
shipping. Design context: PRODUCT.md, DESIGN.md. No visual direction is chosen yet (see DESIGN.md).
Mockup rounds — any UI change beyond a trivial tweak, while brainstorming and before the spec:
- Round 1: about three genuinely different alternatives, each a clickable mockup with realistic content, plus an index page giving each a one-line pitch and what to try.
- Then diverge (about three options on one open question) or converge (one combined mockup); small choices can be toggles inside one mockup. Repeat until the user approves one mockup.
- Once
DESIGN.mdhas a chosen direction, options vary structure, flow and behaviour within it — never a new palette or font family. - This repo deviates from the usual throwaway setup: mockups live in
src/mockups/NN-slug/, are committed, served by the app and smoke-tested. - On approval, write
docs/design/NNN-slug.md(the spec's number): each chosen idea, buildable without the mockup, and what was deselected and why. The spec links it.
Architecture
src/server.ts -> Bun.serve with HTML-import routes: / and /mockups/NN-slug/
src/data/ -> types.ts (shapes), sample.ts (shared sample data), query.ts (helpers)
src/shared/ -> credits, audio slot (direct MP3, empty state), YouTube link cards
src/mockups/NN-slug/ -> one design direction each: index.html, main.ts, style.css, plus optional helper modules (e.g. scene.ts, layout.ts)
tests/ -> data invariants, shared DOM modules (happy-dom), route smoke tests
Full picture: docs/ARCHITECTURE.md — read it before your first change in a session.
Boundaries
Never touch: dist/, node_modules/.
Never commit .env, secrets, or credentials.
Never force-push or rewrite pushed history.
Ask first: new runtime dependencies · changes to src/data/types.ts or the shared modules ·
the Dockerfile · work the approved plan does not cover.
If the task turns out much larger than the plan assumed: stop, report, re-plan.
Docs duties
Same commit as the code, not "later":
docs/ARCHITECTURE.md— when a module, boundary, or data flow changes.docs/DECISIONS.md— append-only; any choice a future maintainer would reverse-engineer.docs/TODO.md— anything noticed and deliberately not fixed. NoTODOcomments in source (// TODO(verify)in sample data is the exception).docs/PERMISSIONS.md— together with every tool permission file (.claude/settings.json,.codex/,.gemini/settings.json), in one commit.
Git
Remote origin is Gitea, not GitHub: gh does not apply. Commits: Conventional Commits (feat:,
docs:, chore:, feat(mockups):).
Branches: TODO(maintainer): confirm whether work goes on branches (suggest feat|fix|chore/<slug>) or straight to main as so far.
Done means verified
Do not report success on work you have not run. Before saying done:
bun test and bun run typecheck run in this session and seen passing · bun run build succeeds ·
matches the approved spec · docs duties complete · git status clean and the diff is only what you intended.
UI work, in the app or a mockup: with bun run start running, take headless screenshots at 1440×900
(google-chrome --headless --window-size=1440,900 --screenshot=screenshots/x.png <url>, or Playwright)
of each screen you changed into screenshots/ (gitignored) and look at them before saying done.
"It should work" is not verification.