@@ -157,7 +157,10 @@ The engine owns:
157157- Edge index array (` Uint32Array ` of length ` 2M ` )
158158- Force simulation (CPU or GPU, same parameter object)
159159- Instanced node rendering (polygon or billboarded sprite)
160- - Edge rendering (straight or bezier, via line shader)
160+ - Edge rendering (straight or bezier, via line shader) with optional
161+ edge-type coloring (see Plugin surface)
162+ - Arrow-glyph rendering on directed edges, as an instanced-triangle mesh
163+ anchored to the target end of each edge (togglable per plugin)
161164- Camera (orthographic or perspective)
162165- Pointer picking via ` instanceId ` (uniform across node modes)
163166- Hidden mask (per-instance visibility, respected by both sim and renderer)
@@ -211,9 +214,24 @@ Plugins implement the existing `ExplorerPlugin` interface from ADR-034 and
211214embed the engine component as their scene. The engine exposes:
212215
213216``` ts
217+ interface EngineNode {
218+ id: string ; // stable key (e.g. kg concept_id)
219+ label: string ; // human-readable display text
220+ category: string ; // opaque string; resolved via palette
221+ degree: number ; // used for size scaling
222+ pinned? : boolean ;
223+ }
224+
225+ interface EngineEdge {
226+ from: string ;
227+ to: string ;
228+ type: string ; // relationship type; resolved via edgePalette
229+ weight? : number ;
230+ }
231+
214232interface UnifiedGraphEngineProps {
215- nodes: EngineNode []; // { id, category, degree, pinned? }
216- edges: EngineEdge []; // { from, to, type, weight? }
233+ nodes: EngineNode [];
234+ edges: EngineEdge [];
217235 projection: ' 2D' | ' 3D' ;
218236 nodeMode: ' sprite' | ' poly' ;
219237 physicsBackend? : ' auto' | ' cpu' | ' gpu' ;
@@ -223,7 +241,12 @@ interface UnifiedGraphEngineProps {
223241 highlightedEdges? : Set <string >;
224242 selectedId? : string | null ;
225243 hoveredId? : string | null ;
226- palette: (category : string ) => string ;
244+ palette: (category : string ) => string ; // node category → hex
245+ edgePalette? : (edgeType : string ) => string ; // edge type → hex (optional;
246+ // falls back to endpoint
247+ // gradient if absent)
248+ showArrows? : boolean ; // render target-end arrow
249+ // glyphs; default true
227250 onSelect? : (id : string | null ) => void ;
228251 onHover? : (id : string | null ) => void ;
229252 onHide? : (id : string ) => void ;
@@ -242,9 +265,11 @@ through the engine.
242265### Positive
243266
244267- ** One engine, one physics, one rendering path.** Maintenance surface
245- shrinks substantially — estimated ~ 2000-3000 LOC reduction across the
246- three current surfaces once migration completes, plus removal of
247- ` react-force-graph-3d ` as a dependency.
268+ shrinks substantially — the three current surfaces total ~ 4,400 lines
269+ (` ForceGraph2D ` 1840, ` ForceGraph3D ` 2052, ` EmbeddingScatter3D ` 529).
270+ Phase 1 alone takes ~ 2000 lines off the 3D surface (V2 replaces V1 and
271+ ` react-force-graph-3d ` is removed); phases 2 and 3 reduce the remaining
272+ two stacks. Expected total reduction ~ 2,000–3,000 lines by phase 3.
248273- ** 10k-node real-time interaction** becomes viable for the first time.
249274 Current 3D hits visible frame drops at a few hundred nodes.
250275- ** 2D and 3D share a camera and a sim** , so switching projection mode on
@@ -325,6 +350,11 @@ V1 stays registered. Users pick via the explorer dropdown. Once V2 reaches
325350full parity and soaks, V1 is removed and ` react-force-graph-3d ` dep is
326351dropped.
327352
353+ ** Phase-1 merge gate:** before the phase-1 PR merges, a follow-up spike at
354+ kg-scale (1,000+ concepts) must validate the performance target on
355+ kg-shaped data at volume (per spike finding #5 ). The current spike (52
356+ concepts) validated shape compatibility but not scaling.
357+
328358### Phase 2 — Add 2D projection
329359
330360Extend the engine with ` projection: '2D' ` :
@@ -447,10 +477,12 @@ The spike lives in `spike/unified-3d/` on this branch. It consists of:
447477- An export script (` export-kg-data.sh ` ) that pulls concepts and relationships
448478 from a live kg postgres and writes them to ` spike/unified-3d/data/kg-graph.json `
449479 in the shape the atlassian-graph UI expects (` {nodes, edges, meta} ` )
450- - A drop-in spike server (` spike/unified-3d/reference/spike-server.js ` ) that
451- replaces atlassian-graph's GraphQL-schema-backed ` /api/graph ` , ` /api/type/:name ` ,
452- ` /api/stats ` , ` /api/categories ` endpoints with static reads from the kg export,
453- leaving the rest of the reference implementation unchanged.
480+ - A drop-in spike server (` spike/unified-3d/spike-server.js ` ; copied into
481+ ` spike/unified-3d/reference/ ` at reproduction time so it resolves
482+ ` express ` from ` reference/node_modules ` ) that replaces atlassian-graph's
483+ GraphQL-schema-backed ` /api/graph ` , ` /api/type/:name ` , ` /api/stats ` ,
484+ ` /api/categories ` endpoints with static reads from the kg export, leaving
485+ the rest of the reference implementation unchanged.
454486
455487The reference UI's vite dev server and the spike server both run cleanly and
456488serve kg data through the atlassian-graph pipeline end-to-end. At the time of
0 commit comments