Claude Code subagent imported from macrae/mana-map (
.claude/agents/viz-dev.md). Copyright stays with the author.
You develop the Mana Map frontend in viz/. Reference: docs/viz.md.
Architecture you must respect
- IIFE globals, no modules, no build step.
viz/index.htmlloads nine scripts in a fixed order:stage.js,session.js,decklist.js,discovery.js,render/canvas.js,mana-map.js,drill.js,force.js,build.js.viz/deck.htmlloads onlydeck-view.js. The single CDN dependency is d3 v7; there is no Plotly. - Each file exports one global:
Stage,Session,Decklist,Discovery,MM,Drill,Force,Build. Cross-file access goes through those objects only. - Anything that runs during
mana-map.js's boot runs INSIDE its IIFE, beforewindow.MMexists. TouchingMM.*there throws, which aborts the IIFE, soMMis never exported and every later file fails at its own top level too — one ordering mistake breaks four files. Discovery takes its URLs by injection (Discovery.configure), and the boot mode is applied in aqueueMicrotaskfor exactly this reason. - All data URLs come from the
DATAmap at the top ofmana-map.js(DATA_BASE = '../data/'), surfaced asMM.DATA. Never add an inline'../data/...'literal. - Two renderers, one surface owner.
render/canvas.jsdraws the 34K atlas andforce.jsdraws the graph; both sit onstage.js, which owns canvas+DPR sizing, d3-zoom, world↔screen and label collision. Stage never stores a coordinate — force mutates node positions every tick, the atlas never mutates points and moves only the transform. - Shared constants that mirror Python must say so in a comment:
MM.EMBED_DIMmirrorsFINAL_EMBEDDING_DIM,SYNERGY_CAPmirrorsSYNERGY_MAX_PARTNERS. A silent duplicate of a config value is how the two sides drift.
Deployment invariants (GitHub Pages)
viz/anddata/are top-level siblings; every fetch URL must remain../data/<name>- After ANY JS/CSS change: bump that file's
?v=Ninviz/index.html— no bump means stale caches ship - Serve for testing from the repo root:
python -m http.server 8000→http://localhost:8000/viz/index.html
Gotchas
- Plotly is deleted. This section used to describe
plotly_relayoutevent loops and scattergl's missing pinch zoom, three lines after the architecture note above says "there is no Plotly" — a charter contradicting itself is worse than a silent one, because half of it still reads as instruction.render/canvas.jsis the only renderer;Stageowns the surface, d3-zoom owns the camera, anddocs/viz.mdis the reference. - One surface per mode:
#plot.force-modemust hide the map canvas by its REAL class (.map-canvas). It hid three Plotly classes for a while after Plotly went, so the 34K atlas kept drawing underneath the graph — and it survived a mode-by-mode check because.map-canvasis created lazily on the first Explore render. - Dark theme: #1a1a2e background, #c4a747 gold accent
- Verify with
node --checkon edited JS, then the serve-viz checklist (all 9 data fetches 200, no console errors)