Skip to content

Commit f693cc8

Browse files
committed
docs: add Cortex Brain Map implementation plan (8 phases)
P1 geometry foundation, P2 render pipeline, P3 edge shader, P4 ripple engine, P5 click polish, P6 HUD overlay, P7 tests, P8 cleanup. ≤5 files per phase, verify gate after each, commit per phase. Includes risk reserves and out-of-scope carry-forward.
1 parent 48e3af9 commit f693cc8

1 file changed

Lines changed: 231 additions & 0 deletions

File tree

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
# Cortex Brain Map — Implementation Plan
2+
3+
**Spec:** `specs/2026-05-09-cortex-brain-map-redesign.md`
4+
**Date:** 2026-05-09
5+
**Status:** Ready for execution
6+
**Approach:** Phased delivery, ≤ 5 files per phase, verify after each, commit per phase.
7+
8+
## Phase ordering
9+
10+
```
11+
P1 Geometry foundation → P2 Render pipeline & layers
12+
P2 → P3 Edge shader + merged geometry
13+
P3 → P4 Ripple engine (BFS + DataTexture)
14+
P4 → P5 Click flow + camera ease + dim/restore
15+
P5 → P6 HUD overlay + SPLIT toggle + ripple path
16+
P6 → P7 Tests (unit + perf + snapshot)
17+
P7 → P8 Cleanup + flag wiring + removals
18+
```
19+
20+
Each phase is independently buildable and visually verifiable in the running desktop app. Verify gate: type-check, lint, run tests, manually open Brain tab, smoke-test the phase's added behavior. Commit on green.
21+
22+
---
23+
24+
## Phase 1 — Geometry foundation
25+
26+
**Goal:** Replace anatomical hemisphere layout with shell-based positions. App renders nodes on outer/inner geodesic shells with orbital rings, no anatomy, no ripple yet.
27+
28+
**Files (≤ 5):**
29+
1. `desktop/cortex-control-center/src/brain/ShellGeometry.js` — NEW. Builds outer icosphere (R=140, subdivision 2), inner icosphere (R=80), 3 ellipse rings (reuse current `ellipseRing` math), reticle ring, center crosshair. Exports `createConstellationShells()` returning a single `THREE.Group` named `cortex-constellation-shell`.
30+
2. `desktop/cortex-control-center/src/brain/ShellLayout.js` — NEW. Exports `applyShellLayout(nodes, { useShellSplit })` projecting each node to its shell surface using a deterministic seeded hash. Memory → outer if `useShellSplit`, else outer for both. Decisions → inner if `useShellSplit`, else outer. Returns nodes with `{ x, y, z, shellRadius, brainRegion: 'outer'|'inner' }`.
31+
3. `desktop/cortex-control-center/src/BrainVisualizer.jsx` — EDIT. Replace `applyBrainLayout` import with `applyShellLayout`. Replace shell injection useEffect to use `createConstellationShells` instead of `createJarvisBrainShell`. Drop the `createBrainShapeForce` registration; add `createShellProjectionForce` that pulls each node's `(x,y,z)` toward `shellRadius * normalize(node.pos)`. Keep `useShellSplit` as `useState(true)`.
32+
4. *(unused this phase)*
33+
5. *(unused this phase)*
34+
35+
**Anatomical removal scope (this phase):** delete `BRAIN_REGIONS`, `brainRegionForNode`, hemisphere math in `brainLayoutPoint`, `cortexPath`, `hemisphereOutline`, `createJarvisBrainShell`. Keep `seededUnit`, `hashString` (reused by ShellLayout).
36+
37+
**Verify:**
38+
- `pnpm tsc --noEmit` clean.
39+
- `pnpm lint` clean.
40+
- Open desktop app → Brain tab → see two faceted wireframe shells + 3 rings + reticle. Nodes scattered on shell surfaces. No two-blob brain shape at any zoom.
41+
- HUD copy and stats unchanged.
42+
43+
**Commit:** `refactor(brain): replace anatomical layout with shell-based constellation geometry`
44+
45+
---
46+
47+
## Phase 2 — Render pipeline & layers
48+
49+
**Goal:** Selective bloom on emissive elements only, layer assignment, tonemapping, draw call ceiling enforced.
50+
51+
**Files:**
52+
1. `desktop/cortex-control-center/src/brain/RenderLayers.js` — NEW. Exports `BRAIN_LAYERS = { BASE: 0, BLOOM: 1 }` and helper `assignLayer(object3d, layer)` walking children.
53+
2. `desktop/cortex-control-center/src/brain/PostFx.jsx` — NEW. React component wrapping `<EffectComposer>` + selective `<Bloom>` from `@react-three/postprocessing`. Props: `enabled`, `intensity`, `threshold`, `smoothing`. Manages a 1-second rolling frame-time window via `useFrame`; calls `onAutoDegrade(disabled: boolean)` when median crosses thresholds (≥33.3 ms disable, ≤22 ms re-enable sustained 3 s).
54+
3. `desktop/cortex-control-center/src/BrainVisualizer.jsx` — EDIT. Add `bloomEnabled` state (default `true`). Mount `<PostFx>` inside the graph wrapper. Set `gl.toneMapping = ACESFilmicToneMapping` and `gl.toneMappingExposure = 1.0` via `ForceGraph3D` ref. Assign shells/rings/reticle to layer 0; nodes (instanced material) to layer 1.
55+
4. `desktop/cortex-control-center/package.json` — EDIT. Add `@react-three/postprocessing` and `@react-three/fiber` (peer) if missing. Run `pnpm install`.
56+
5. *(unused this phase)*
57+
58+
**Verify:**
59+
- Bloom visible: nodes glow softly, shell wireframes stay crisp (no halo bleed).
60+
- Open Chrome devtools perf → record 5 s of orbiting → median frame time < 22 ms on reference machine.
61+
- Inject artificial 50 ms `setTimeout` stall in a scratch hook for 1.5 s → bloom disables; remove → bloom re-enables ≤ 4 s. (Manual smoke; perf test added later in P7.)
62+
- `renderer.info.render.calls < 50` logged once after first paint (temporary `console.debug`, removed in P8).
63+
64+
**Commit:** `feat(brain): add selective bloom + auto-degrade + layer assignment`
65+
66+
---
67+
68+
## Phase 3 — Edge shader + merged geometry
69+
70+
**Goal:** Replace `react-force-graph-3d` per-link rendering with a single merged `BufferGeometry` driven by a custom `ShaderMaterial`. Static look only — no activation animation yet.
71+
72+
**Files:**
73+
1. `desktop/cortex-control-center/src/brain/PulseShader.js` — NEW. Exports `createPulseMaterial({ baseColor, pulseColor })` returning a `THREE.ShaderMaterial` with uniforms `uTime`, `uActivation` (`DataTexture`, placeholder this phase), `uHeadPos`. Vertex shader passes `aEdgeId`, `aProgress` (0..1 along edge), `aActivation` from texture sample. Fragment shader: `gl_FragColor = mix(base, pulse, smoothstep(uHeadPos-0.05, uHeadPos, vProgress) * (1.0 - smoothstep(uHeadPos, uHeadPos+0.15, vProgress))) * (vActivation + 0.05)`.
74+
2. `desktop/cortex-control-center/src/brain/EdgeMesh.js` — NEW. Builds a single merged `BufferGeometry` from `graphData.links`. Each link contributes 16 quad segments along its straight or arched path; attributes: `aPosition`, `aProgress`, `aEdgeId`. Exports `buildEdgeMesh(links, nodesById)` and `disposeEdgeMesh(mesh)`.
75+
3. `desktop/cortex-control-center/src/BrainVisualizer.jsx` — EDIT. Disable `react-force-graph-3d`'s built-in link rendering (`linkVisibility={() => false}`). Add the merged edge mesh to the scene as a sibling of the InstancedMesh. Rebuild only when `graphData.links` reference changes.
76+
4. *(unused this phase)*
77+
5. *(unused this phase)*
78+
79+
**Verify:**
80+
- Edges still render, indistinguishable from prior look at static rest (just constant color).
81+
- Draw call count drops measurably (shells 2 + rings 3 + nodes 1 + edges 1 + reticle 1 + crosshair 1 + HUD ≤ 6 = ≤ 14 < 50).
82+
- No regression in hover/click selection (edges aren't clickable yet — not a regression; was already low-priority).
83+
- Type-check, lint, existing tests pass.
84+
85+
**Commit:** `feat(brain): replace per-link rendering with merged geometry + pulse shader scaffold`
86+
87+
---
88+
89+
## Phase 4 — Ripple engine (BFS + DataTexture)
90+
91+
**Goal:** When a node is clicked, BFS runs and writes activation values to the edge `DataTexture`. Shader reads them and animates the traveling pulse along activated edges.
92+
93+
**Files:**
94+
1. `desktop/cortex-control-center/src/brain/RippleEngine.js` — NEW. Class `RippleEngine` with:
95+
- `buildAdjacency(links)` — Map<nodeId, Array<{ neighborId, edgeIndex }>>.
96+
- `fire(nodeId, now)` — runs BFS depth ≤ 2, schedules activations into a Float32Array indexed by edge index, with `firstSeen[edgeIndex] = clickTime + depth × 110ms`.
97+
- `tick(now, gl)` — single rAF entry point: for each edge, computes `t = now - firstSeen[i]`; if `t >= 0`, writes `min(activation + risePart, 1.0) × exp(-(t-riseMs)/280)` into the DataTexture. Multiple ripples accumulate in `Float32Array activations` then clamp to 1.0 on flush.
98+
- Owns `THREE.DataTexture(activations, edgeCount, 1, RedFormat, FloatType)`; `texture.needsUpdate = true` on flush.
99+
2. `desktop/cortex-control-center/src/brain/easing.js` — NEW. Exports `easeOutCubic(t)`, `expDecay(t, tau)`, `clamp01(x)`.
100+
3. `desktop/cortex-control-center/src/BrainVisualizer.jsx` — EDIT. Instantiate `RippleEngine` once on `graphData` change. Wire its `DataTexture` into `PulseShader`'s `uActivation`. Run `engine.tick(performance.now(), gl)` inside an `useFrame` hook (added via `<RippleTicker>` child component because `ForceGraph3D` doesn't expose `useFrame`).
101+
4. `desktop/cortex-control-center/src/brain/RippleTicker.jsx` — NEW. Tiny component using `useFrame` to call `engine.tick()` each frame. Wired into the post-fx tree from P2.
102+
5. *(unused this phase)*
103+
104+
**Hook into click:** keep this phase shader-only. Click already exists (`selectGraphNode`); add `engineRef.current.fire(node.id, performance.now())` inside it. Visible result: clicked node's outgoing edges glow with a traveling head.
105+
106+
**Verify:**
107+
- Click a node → its outgoing edges show a pulse traveling outward, decaying within ~500 ms.
108+
- Two rapid clicks on adjacent nodes → both ripples visible, edges shared by both glow brighter (additive, clamped at 1.0).
109+
- No memory leak after 100 clicks (`renderer.info.memory.geometries` and `.textures` stable).
110+
- Type-check, lint, existing tests pass.
111+
112+
**Commit:** `feat(brain): ripple engine — BFS-timed activation drives pulse shader`
113+
114+
---
115+
116+
## Phase 5 — Click flow polish: source pulse, secondary pop-in, camera ease, dim/restore
117+
118+
**Goal:** Round out the click-fire experience to match §5 of the spec.
119+
120+
**Files:**
121+
1. `desktop/cortex-control-center/src/brain/NodeFx.jsx` — NEW. React component rendering source-node halo (additive sprite, scale pulse 1.0→1.4→1.0, 600 ms) and secondary ripple rings (additive sprites at depth-1/depth-2 nodes, 400 ms expand+fade). Driven by `RippleEngine` callbacks.
122+
2. `desktop/cortex-control-center/src/brain/RippleEngine.js` — EDIT. Add observer pattern: `onSourceFire(cb)`, `onNodeReached(cb)`. `NodeFx` subscribes.
123+
3. `desktop/cortex-control-center/src/BrainVisualizer.jsx` — EDIT.
124+
- Replace `focusGraphNode` (full dolly) with `easeCameraToward(camera, target, 0.15)`.
125+
- Add dim/restore: when ripple active, drive `nodeOpacity` per-instance to 0.25 for non-affected nodes, 1.0 for affected, ease 200 ms in / 400 ms out.
126+
- Mount `<NodeFx />` inside the graph tree.
127+
4. `desktop/cortex-control-center/src/brain/cameraEase.js` — NEW. Exports `easeCameraToward(camera, target, fraction)`.
128+
5. *(unused this phase)*
129+
130+
**Verify:**
131+
- Click node with several neighbors:
132+
- Source pulses 1.0→1.4→1.0 over 600 ms.
133+
- Edges show traveling glow.
134+
- Depth-1 nodes pop ripple ring on packet arrival; depth-2 nodes do too.
135+
- Non-affected nodes fade to ~25 % opacity, restore within 400 ms after ripple completes.
136+
- Camera eases ~15 % toward node, no re-center, user can still orbit.
137+
- Total ripple visibly complete within ~900 ms.
138+
139+
**Commit:** `feat(brain): source pulse, secondary ripple, camera ease, dim/restore`
140+
141+
---
142+
143+
## Phase 6 — HUD overlay + SPLIT toggle + ripple path trace
144+
145+
**Goal:** Add Jarvis HUD chrome (corner glyph clusters, radar reticle), wire `useShellSplit` toggle, populate "RIPPLE PATH" mini-trace in the selection panel.
146+
147+
**Files:**
148+
1. `desktop/cortex-control-center/src/brain/HudOverlay.jsx` — NEW. Four corner glyph clusters (DOM, absolutely positioned over canvas) with tick dials + status readouts: TL = nodes/links, TR = mem/dec/agents/last-fire timestamp, BL = bearing/zoom/depth, BR = small radar reticle (SVG arc + bearing needle reading from camera azimuth).
149+
2. `desktop/cortex-control-center/src/styles.css` — EDIT. Add `.brain-hud-corner`, `.brain-hud-radar`, `.brain-hud-tick`, `.brain-split-toggle`. Keep existing brain HUD classes intact.
150+
3. `desktop/cortex-control-center/src/BrainVisualizer.jsx` — EDIT.
151+
- Mount `<HudOverlay>` inside `.brain-container`.
152+
- Add SPLIT pill button next to AUTO/MANUAL toggle; flips `useShellSplit`. Passes through to `applyShellLayout` on next layout pass.
153+
- Extend selection panel: render `selectedFlow.flowLinks` (already computed) as a labeled "RIPPLE PATH" tree showing depth-1 hop names + depth-2 hop counts.
154+
4. *(unused this phase)*
155+
5. *(unused this phase)*
156+
157+
**Verify:**
158+
- Four corners populated, radar needle rotates with camera bearing.
159+
- SPLIT pill toggles outer/inner-shell vs single-shell-color-only modes; layout re-applies cleanly without losing the camera.
160+
- Selection panel shows RIPPLE PATH listing actual neighbors when a node is selected.
161+
- Existing top-left card and top-right stats unchanged.
162+
163+
**Commit:** `feat(brain): jarvis HUD overlay, SPLIT toggle, ripple path trace`
164+
165+
---
166+
167+
## Phase 7 — Tests
168+
169+
**Goal:** Cover every §14 acceptance bullet with automated tests where possible.
170+
171+
**Files:**
172+
1. `desktop/cortex-control-center/src/brain/__tests__/ShellLayout.test.js` — NEW. Deterministic positions across runs and across `graphData` reference changes that don't touch node ids.
173+
2. `desktop/cortex-control-center/src/brain/__tests__/RippleEngine.test.js` — NEW. BFS depth cap = 2, additivity (clamp at 1.0), camera ease (15 %, no re-center), dim/restore (0.25 ± 0.01, 400 ms restore).
174+
3. `desktop/cortex-control-center/src/brain/__tests__/easing.test.js` — NEW. `easeOutCubic` boundaries + monotonic, `expDecay(τ × ln(6)) ≈ 0.16`.
175+
4. `desktop/cortex-control-center/src/brain/__tests__/perf.test.js` — NEW. Headless WebGL via `gl` npm package: render 1000 nodes / 300 links, assert `renderer.info.render.calls < 50`. Bloom auto-degrade trigger: inject 50 ms stalls for 1.5 s, assert disable; remove, assert re-enable within 4 s.
176+
5. `desktop/cortex-control-center/src/brain/__tests__/snapshot.test.js` — NEW. Puppeteer launches the desktop app dev build, navigates to Brain tab, seeds fixed data, **disables bloom** in the harness, captures PNG, compares via `pixelmatch` 0.1 against `__snapshots__/constellation.png`. First run writes the baseline (manual approval gate in PR).
177+
178+
**Verify:**
179+
- `pnpm test --run` green.
180+
- `pnpm test perf.test.js` green on reference machine.
181+
- Snapshot baseline reviewed visually before being checked in.
182+
183+
**Commit:** `test(brain): unit + perf + snapshot coverage for constellation lattice`
184+
185+
---
186+
187+
## Phase 8 — Cleanup + flag wiring + removals
188+
189+
**Goal:** Wire build-time flag, delete dead code, remove temporary debug logs.
190+
191+
**Files:**
192+
1. `desktop/cortex-control-center/vite.config.js` — EDIT. Wire `CORTEX_BRAIN_LATTICE` env var; default `1`.
193+
2. `desktop/cortex-control-center/src/BrainVisualizer.jsx` — EDIT.
194+
- At entry: if `import.meta.env.VITE_CORTEX_BRAIN_LATTICE === '0'`, render the legacy renderer for the QA overlap window. (Else: lattice path.) Note: legacy renderer is already retained on disk only if Phase 1 deletion was deferred — given the spec says "delete in same PR", we delete now and ship lattice unconditionally; this Phase 8 file edit then becomes a no-op flag plumb that we keep for one release before removing.
195+
- Decision based on user signal at PR time: keep flag plumb or drop it. Default plan: drop, since spec says no shim.
196+
- Remove temporary `console.debug` for draw call count from P2.
197+
3. `desktop/cortex-control-center/src/BrainVisualizer.jsx` — EDIT. Final removals if any anatomy code still lingered (audit pass).
198+
4. `CHANGELOG.md` — EDIT. Add `## v0.6.x — Brain Map: Constellation Lattice` entry summarizing the redesign.
199+
5. *(unused this phase)*
200+
201+
**Verify:**
202+
- `rg -n "BRAIN_REGIONS|brainRegionForNode|createJarvisBrainShell|cortexPath|hemisphereOutline|applyBrainLayout" desktop/cortex-control-center/src/` returns zero hits.
203+
- Build passes: `pnpm build`.
204+
- Final manual smoke pass on reference machine: 1000-node load < 2 s, click-to-fire latency < 100 ms, ripple within 900 ms, 60 fps median, RIPPLE PATH HUD populated, SPLIT toggle works, 2D fallback still triggers when WebGL is forced off.
205+
- All P1–P7 commits land cleanly on top of master.
206+
207+
**Commit:** `chore(brain): remove anatomy code, wire flag, changelog`
208+
209+
---
210+
211+
## Cross-cutting rules
212+
213+
- **No `git add .`** — only stage files listed per phase.
214+
- **Re-read before editing.** Max 3 edits per file between verification reads.
215+
- **Verify gate after each phase** — type-check, lint, tests, manual smoke. No "deferred fixes" between phases.
216+
- **Commit per phase.** New commits, never amend.
217+
- **Run on reference machine** for any fps claim.
218+
- **Failures escalate after 3 attempts** — stop, report, do not loop silently.
219+
220+
## Risk reserves
221+
222+
- If P3 merged-geometry path causes hover flicker (the existing `nodeLabel` hover relies on per-link raycast that no longer exists): build a minimal raycaster against the InstancedMesh nodes only — links don't need hover. Spec doesn't require link hover. Budget: 2 hours.
223+
- If P4 shader compile fails on a target driver: fall back to 2D grid (already specified in §13). Budget: 30 min decision.
224+
- If P7 perf test in headless `gl` is too flaky: gate the draw-call assertion only; manual fps measurement on reference machine remains canonical.
225+
226+
## Out of scope (carry forward)
227+
228+
- Audio cues (Tone.js sub-pluck per hop).
229+
- Mobile/touch ripple gestures.
230+
- Saving/replaying ripple sequences.
231+
- Any change to `/dump` endpoint or downstream Cortex APIs.

0 commit comments

Comments
 (0)