Skip to content

vismayIO/graph-engine

Repository files navigation

graph-engine

A high-performance, canvas-first visualization engine for 1,000+ interactive elements, implemented on d3 (layout/math) with a bespoke Canvas 2D renderer. Framework- agnostic and WebGL-ready — the renderer is swappable behind an abstract DrawList boundary, proven by a dual-backend gate. First domain: radial dendrograms with expand/collapse, per-node drag, animation, and pan/zoom.

  • No SVG. d3 is used for layout/spatial/scale math + d3-shape drawn into canvas.
  • Scales with node count — auto-radius layout so nodes never overlap; constant-size crisp labels at any zoom.
  • Measured: 2,000 elements at ~2.6 ms/frame (p95) under 4× CPU throttle; 10k within the 16.6 ms budget (apps/bench).

Quick start (the public API)

Use @ge/graph — the framework-agnostic GraphController. It mounts a graph into a DOM element with collapse/expand, drag, animation, and pan/zoom built in.

import { GraphController } from '@ge/graph';

const graph = new GraphController(
  document.getElementById('app')!,
  { parentIndex: [-1, 0, 0, 0, 1, 1, 3] }, // flat hierarchy: parentIndex[i] = parent, -1 = root
  { nodeSpacing: 16 },
);
graph.on('collapse', ({ id }) => console.log('collapsed', id));
graph.toggle(0);
// … on unmount: graph.destroy()

Full API reference, events, and React/Vue/vanilla examples: packages/graph/README.md.


Packages

The engine is modular; each package is independently replaceable behind an interface. @ge/graph composes them — most users only need that one.

Package Role Public surface
@ge/graph Public APIGraphController facade + events, GraphModel, EventEmitter new GraphController(el, data, opts)
@ge/contracts Shared interfaces + flag bits (zero-dep DI surface) LayoutEngine, SpatialIndex, Renderer-adjacent types, FLAG_*
@ge/renderer The load-bearing boundary: abstract Renderer + declarative DrawList Renderer, DrawList, ShapeBatch/EdgeBatch/LabelBatch
@ge/renderer-canvas Canvas 2D backend (sole owner of CanvasRenderingContext2D) CanvasRenderer
@ge/renderer-webgl-stub POC backend proving the DrawList boundary is WebGL-ready WebGLRenderer (stub)
@ge/geometry-store Struct-of-Arrays typed-array node/edge store + object pools TypedGeometryStore, ObjectPool
@ge/layout-d3 d3-hierarchy radial cluster layout with auto-radius (no overlap) RadialClusterLayout, RadialLayoutOptions
@ge/layout-worker Off-thread layout via comlink (zero-copy transfer) LayoutSupervisor
@ge/spatial-index O(log n) hit-testing QuadtreeIndex (+ PolarIndex stub)
@ge/viewport Camera ({tx,ty,scale}) + culling + native pointer/wheel input Camera, CartesianCuller, InputController
@ge/interaction Hit-testing + behaviors PointerInteractionEngine, Hover/Select/CollapseExpand/DragNode behaviors
@ge/animation d3-interpolate position tweens TweenAnimationEngine
@ge/core Engine loop, DI EngineContext, extension registry, scene-graph, frame scheduler Engine, register/get, SceneGraph, FrameScheduler
@ge/domain-radial Radial dendrogram edge/label builders buildEdgeBatch, buildLabelBatch

Apps: apps/playground (Vite demo using @ge/graph) · apps/bench (CDP perf harness + the WebGL POC gate).


Architecture in one screen

data ──▶ @ge/layout-d3 (RadialClusterLayout, auto-radius) ──▶ @ge/geometry-store (SoA typed arrays)
      ──▶ @ge/spatial-index (hit-test) · @ge/viewport (cull/camera) · @ge/animation (tweens)
      ──▶ @ge/renderer DrawList ──▶ @ge/renderer-canvas (Canvas2D)  [swap-in: WebGL]
      ▲                                                              │
      └────────── @ge/graph GraphController (events + gestures) ─────┘
  • DrawList boundary (Rule 1): core/domain/interaction emit declarative typed-array batches; CanvasRenderingContext2D lives only in renderer-canvas. A WebGL backend drops in without touching core (gate-tested in apps/bench).
  • No per-frame allocation on the render path (object pools + reused typed arrays).
  • Labels render in device space at constant size → always crisp, never blurry on zoom.

Design records: .omc/specs/ · build status: BUILD-STATUS.md.


Develop

bun install
turbo run check-types     # strict TS across the workspace
turbo run build           # tsup ESM + .d.ts per package; Vite for apps
bun run test              # unit tests (bun test, scoped to our packages — vendor excluded)

bun run --filter @app/playground dev    # open the interactive demo
bun run apps/bench/src/run-cdp.mjs       # perf sweep (needs google-chrome) → results.json

Toolchain: TypeScript 5.9 (strict) · bun · turbo · Node ≥18.

About

No description, website, or topics provided.

Resources

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors