Imported from ChrisMagee01/universe-visualiser (
AGENTS.md). Install upstream withnpx skills add ChrisMagee01/universe-visualiser. Copyright stays with the author.
AGENTS.md — Universe Visualiser
Project context for any agent (Claude Code or otherwise) working in this repo.
What this is
A personal watch/read/track dashboard where every movie, TV season/episode, book, or other work is a node in a directed graph, connected to the nodes it follows on. Two visual languages — the MCU's "Sacred Timeline" (glowing central line with variant branches) and a Stark HUD aesthetic (glass, cyan-lit chrome) — inform the UI, but the system itself is not hardcoded to Marvel or to film/TV. Content lives in data files, not code, so any franchise (the MCU, Fox's X-Men, Sony's Spider-Man Universe, Brandon Sanderson's Cosmere, etc.) can be added by dropping in a new folder.
The full design brief (concept, schema, build order) lives in the conversation history that started this project — see the "Suggested Build Order" section below for the phased plan. This file is the durable summary; if a fuller written brief exists elsewhere in the repo later, prefer that as the source of truth and update this pointer.
Architecture (four layers)
- Content layer (
/universes/*/nodes/*.json,/tags/**/*.json) — hand-edited, source of truth for all canon data. One JSON file per node, one per tag. Version-controlled. - Content store (
content.db, generated) —scripts/ingest-content.tsvalidates every JSON file against/schema/*.schema.json(ajv) and ingests it into SQLite (Node,Parent; tag/trivia tables not yet added). Disposable build artifact: delete it, rerunpnpm ingest-content, get the same result. Applied viaprisma db push(pnpm db:push:content), not migrations — there's no schema history to track for a DB that's rebuilt from files every time. - Backend — Next.js API routes serve
content.db(GET /api/nodes,GET /api/nodes/:id) and separately persist the user's consumed-state inprogress.db(GET /api/progress,POST /api/progress).progress.dbuses realprisma migrate dev(pnpm db:migrate:progress), because it's the one thing that can't be regenerated. The two databases are separate SQLite files with no DB-level foreign key between them —progress.db'sConsumedNode.nodeIdmatches acontent.dbNode.idby convention, checked at the API layer, not by SQLite. This holds as long as node ids (hand-assigned slugs from filenames) stay stable — never rename an existing node'sidonce progress has been recorded against it. - Frontend — single Next.js app (App Router), React Flow graph (dagre auto-layout,
swimlanes by
timelineTrack) at/, a sortable checklist/table view at/checklist, both backed by a shared Zustand progress store. Character/thread pages, trivia panels, filters, and the Sacred Timeline / Stark HUD theming pass are not built yet.
Prisma 7 specifics (postdates training data — don't assume Prisma 6 patterns)
- No
urlinschema.prisma'sdatasourceblock anymore — it lives in aprisma.<name>.config.tsfile (prisma.content.config.ts,prisma.progress.config.tshere), selected per-command with--config. - Generator provider is
"prisma-client"(not"prisma-client-js"), andoutputis mandatory — generated code lands under/generated/prisma/<name>/(gitignored, rerunpnpm db:generate:content/db:generate:progressafter a schema change). - The client now requires a driver adapter —
@prisma/adapter-better-sqlite3here, passed asnew PrismaClient({ adapter }). Seelib/content-db.ts/lib/progress-db.ts. - pnpm blocks native/postinstall build scripts by default (
ERR_PNPM_IGNORED_BUILDS) — new packages needing one (@prisma/engines,prisma,better-sqlite3,esbuildfortsx) need an entry inpnpm-workspace.yaml'sallowBuildsmap, thenpnpm installagain.
Season/episode progress modeling
Episodes are their own tv-episode nodes (not folded into one tv-season node) so partial
"3 episodes in" progress is just 3 consumed episode rows. A season's own progress is
derived by grouping nodes that share its arc field — not via an explicit parents[]
containment edge, since connectionType has no "part-of" semantic and overloading
side-story/direct-sequel for that would be misleading. See
app/components/NodeDetailPanel.tsx. Nodes not worth splitting into sub-nodes (a book, a
single long film) use ConsumedNode.progressValue instead (same unit as the node's length).
Working rules
- JSON files under
/universes/and/tags/are the only source of truth for canon data. Nothing programmatic ever writes back into them — hand-edit, then rerun the ingest script. content.dbis disposable. Never hand-edit it, never treat data that only exists there as durable — if it's not in the JSON, it doesn't really exist.progress.dbis the one real database. It holds Chris's actual watch/read history and can't be regenerated. Never delete or reset it without an explicit ask. It's the only file in this repo worth backing up (and per.gitignore, it's never committed).- Adding a franchise = adding a folder under
/universes/, not writing code. - Keep a
userIdfield inprogress.db's schema from day one even though v1 hardcodes a single local user — this keeps a future auth layer from requiring a migration. - No comics issue-level data or UI in v1 — schema should stay compatible with it
(
comic-arcas a coarse node type) without building it out.
Actual build order (Chris reordered from the original brief)
Front-loads a visible result instead of building the full tag/trivia/theming system before anything renders: graph viz → progress tracker → real data → tags/trivia → theming → polish. Full rationale and milestone-by-milestone detail lives in the plan file from that session (not preserved in-repo — this section is the durable summary).
- ✅ Milestone 1 — graph viz.
/schema/node.schema.json+/schema/manifest.schema.json,scripts/ingest-content.ts(full validate → referential-integrity → upsert pipeline, not a throwaway seed script),content.dbviaprisma db push,GET /api/nodes(/:id), React Flow graph at/with dagre layout +timelineTrackswimlanes. Proven against/universes/test-fixture-a/and/test-fixture-b/— throwaway fixtures, not real MCU data. Includes a cross-universe merge node (two parents from different universes) and a deliberately-broken reference to confirm the ingest fails loudly rather than silently dropping an edge. - ✅ Milestone 2 — progress tracker.
progress.dbvia realprisma migrate dev,GET/POST /api/progress, a node detail panel (click a node) with status cycle +progressValueinput,/checklistsortable table view, per-medium stats — see "Season/episode progress modeling" above. Test fixtures extended with atv-season+ 3tv-episodechildren and aprose/novelnode to exercise both partial-progress paths. - ⬜ Milestone 3 — real data. Swap
/universes/test-fixture-*/for real/universes/mcu/content through the same pipeline (no rework needed) — write/schema/tag.schema.json(the one schema piece not yet needed). Sourcing approach (draft-and-verify vs hand-authored) wasn't pinned down — confirm with Chris before populating. - ⬜ Tags/threads (brief Section 5) — after real data, since they're more meaningful
against real nodes. Character/thread browser, dynamic
fields[]rendering, expanding CK-style character panels, multiversalvariantGroupsiblings, tag highlight mode. - ⬜ Trivia (brief Section 6) — category badges,
relatedNodeIds"see also" links, graph-level trivia toggle. - ⬜ Visual theming (brief Section 9) — Sacred Timeline lanes, Stark HUD chrome,
per-universe/connection-type/medium styling. Deliberately after real data so theming
decisions are made against real content, not placeholders. Chris wants each milestone's UI
mirrored into Figma for tweaking (
figma-generate-designskill) — the Figma MCP connector wasn't authorized as of Milestone 1/2; check before this pass. - ⬜ Filters, search, "up next," personal rewatch queue, polish (brief Sections 8/10).
This is NOT the Next.js you know
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in node_modules/next/dist/docs/ (resolved from this file's directory; in monorepos the next package may not be visible from the repo root) before writing any code. Heed deprecation notices.
This block is written and re-added by next dev — verify at node_modules/next/dist/server/lib/generate-agent-files.js. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.