This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Arena3D is a web application for interactive 3D visualization of multilayered networks: FastAPI backend (Python, uv) + Vite / TypeScript / Three.js frontend (npm).
The app was migrated from R/Shiny to this stack. All R/Shiny source is gone; the migration history lives in:
SPEC.md— architecture decisions, chosen stack, design patterns, API contract, and rationale.PLAN.md— phased implementation checklist (essentially complete).MIGRATION.md— old R/Shiny file → new equivalent map (all rows done).
- Never push to remote. Commit only when explicitly asked, one commit per feature.
- Always use the
token-saviourskill — and the tools/skills it routes to across its layers — wherever it makes sense. - When a plan is active (e.g. a
PLAN*.mdfile): one feature per commit, tick the checkboxes as you go, and verify each feature at runtime before moving to the next. - Before every commit: run the build, lint, typecheck, and the relevant test suite (see commands below). Verify UI/UX changes at runtime with Playwright.
- Keep responses concise — summarize rather than dumping full files, to stay within output token limits.
Backend (package management via uv — no manual venv/pip):
cd backend
uv sync # installs deps + dev group into .venv
uv run uvicorn app.main:app --reload # http://localhost:8000Frontend:
cd frontend
npm install
npm run dev # http://localhost:5173 — /api proxied to localhost:8000Both together (Docker):
docker-compose upBackend tests:
cd backend && uv run pytestFrontend tests:
cd frontend && npm test # Vitest unit tests
cd frontend && npm run test:e2e # Playwright E2ELint / format / typecheck:
cd backend && uv run ruff check . && uv run ruff format . && uv run mypy app
cd frontend && npm run lint && npm run format && npx tsc --noEmitStateless FastAPI — the frontend holds all scene state; the server validates input and runs the graph algorithms.
main.py— app + router registration;config.py— constants (limits, palettes, scale targets) served atGET /api/config.models/— Pydantic request/response models (network,layout,topology,session,attributes).routers/— one per endpoint:config,network(TSV upload),layout,topology,session(import/export),external(token-shared sessions),attributes(node/edge attribute files).services/— logic:parser(TSV parse/validate),graph(igraph construction + scopes),layouts(11 layout algos),clustering(4 community algos, optional layout step),topology(Degree / Clustering Coefficient / Betweenness),session,attributes.- Algorithms use python-igraph — same C core as R's igraph, so layouts/clustering/topology port 1:1.
main.ts— entry point: fetch config → set up Three.js → mount canvas → wire panels + listeners →animate(). Exposeswindow.__arena = { ctx, history }as a Playwright test hook (the WebGL canvas is opaque to the a11y tree).three/—Scene,Layer,Node,Edgeclasses on npmthreer170;runtime.tsholds the shared mutablectx(replaces v2 ambient globals);constants.tsstatic geometry/palette constants.actions/— one module per domain (network,layout,layer,node,edge,labels,themes,screen,canvas_controls,nav_controls,drag_controls,right_click_menu,session). These mutate the object model +ctx.commands/—Commandinterface +CommandHistory(undo/redo);scene.tsholds the concrete commands. Every scene mutation that should be undoable routes through a command.ui/— one module per navbar panel (home,file,layouts,scene,layer,node,edge,data,fps,help), each filling its#panel-*pane with Bootstrap DOM and wiring controls toactions/commands.bus/— typedEventBussingleton (returns unsubscribe fns);store/— typedAppStatestore. Together they replace the old Shiny input/output sync.api/client.ts— hand-written typed client mirroring the Pydantic models.
- Frontend → backend:
api.*calls to/api/*(network parse, layout, topology, session, attributes). - Within frontend: components emit/subscribe on the
EventBusand read/write thestore; the render loop reacts toctxflags (renderInterLayerEdgesFlag, label flags, etc.).
- Networks upload as TSV with mandatory columns
SourceNode,SourceLayer,TargetNode,TargetLayer(optional:Weight,Channel, edge color columns). - Node/edge attribute files add per-node color/size/url/description and per-edge (optionally per-channel) color.
- Sessions export/import as JSON with full node/edge/layer/scene state.
POST /api/externalreturns a token URL so another app can hand off a session.