# PLAN — Hermes Graph Explorer

## Goal
Build a Vite + TypeScript single-page graph explorer for 5,000 nodes and about 10,000 edges with a smooth force-directed layout, canvas rendering, pan/zoom, search, group filtering, neighbor highlighting, tests, and the required `src/lib/graph-core.ts` acceptance exports.

## Architecture
- `src/lib/graph-core.ts`
  - Pure acceptance contract: `GraphNode`, `GraphEdge`, `Graph`, `neighbors`, `searchNodes`, `filterByGroup`, `QuadTree`.
  - No DOM imports. Deterministic and tested under Vitest.
- `src/lib/generator.ts`
  - Deterministic clustered graph generator. Produces community labels and local/inter-community edges.
- `src/lib/simulation.ts`
  - Force simulation separated from UI/rendering.
  - Typed-array state (`Float32Array` for positions/velocities/forces, `Uint16Array` for groups, `Uint32Array` for links) to reduce object churn.
  - Barnes-Hut quadtree over typed arrays for repulsion; spring attraction over edge arrays; center force and damping.
  - Incremental `tick()` method usable by animation loop and by the buildoff perf hook.
- `src/lib/viewport.ts`
  - World/screen transforms for pan, zoom, and hit testing.
- `src/lib/renderer.ts`
  - Canvas 2D renderer. Draws edges, nodes, group colors, search/filter/hover/click highlights, and a minimap.
- `src/main.ts`
  - DOM wiring: controls, animation loop, pointer events, search, filter, simulation sliders, stats, `window.__buildoff`.
- `src/styles.css`
  - Lightweight app shell and overlay styling.
- `tests/`
  - Core acceptance API tests.
  - Generator/simulation smoke tests to verify the spatial path advances frames without DOM.

## Libraries and dependency choices
Use only Vite, TypeScript, Vitest, ESLint, Prettier, and the shared TypeScript ESLint packages required by `eslint.config.js`. No graph or rendering libraries: direct Canvas and typed arrays keep the bundle small and make algorithmic choices visible for A3/A5.

## Performance approach
- Render with a single `<canvas>`, never thousands of DOM elements.
- Typed arrays for hot simulation data and links.
- Barnes-Hut repulsion with a compact array-backed tree rebuilt per tick. This avoids O(n²) all-pairs repulsion for 5,000 nodes.
- Process all links each tick for springs (~10,000), which is linear and acceptable.
- Cap device pixel ratio and skip labels except at high zoom / highlighted nodes.
- The animation loop runs a small number of simulation ticks per frame while alpha is high, then coasts.
- Expose `window.__buildoff.warmup()` and `window.__buildoff.workload()` so the harness can measure the real workload.

## UX feature plan
- Generate 5,000 nodes and 10,000 edges on load.
- Community colors and group filter dropdown.
- Search by label/id with match highlighting; first match is focused.
- Drag to pan, wheel to zoom around cursor.
- Hover/click nearest node; highlight selected node and neighbors.
- Live sliders for repulsion, link distance, and damping.
- Stats readout for FPS, alpha, nodes, edges, and frame timing.
- Minimap as stretch feature.

## Risks and mitigations
- Barnes-Hut correctness/perf: keep the optimized simulation tree internal and test the public `QuadTree` independently.
- Canvas hit-testing at 5k nodes: use a bounded linear nearest-node scan on pointer move, acceptable compared with simulation; throttle naturally via pointer events.
- Hidden tests importing exact acceptance exports: keep `graph-core.ts` pure and signatures exact.
- Strict TypeScript/lint: avoid `any`, non-null assertions, and unused locals; run build/lint before final.
- Bundle size: avoid React/D3 and large dependencies.

## Verification
Run in order from the project directory:
1. `npm ci`
2. `npm test`
3. `npm run build` and confirm `dist/` exists
4. `npm run lint`

Document implementation decisions and pivots in `REASONING.md`, then finish with `SELF.md`.
