TypeScript + WebGPU

Graphs with depth.

BubbleGraph is a framework-agnostic library for expressive, interactive force-directed bubble graphs in the browser.

One focused library.

Bring your own data and interface. BubbleGraph owns the difficult graphical layer: rendering, layout, animation, labels, interaction, and cleanup.

01

GPU-native rendering

WebGPU-batched soap-bubble nodes and instanced edges keep drawing work compact.

02

Force-directed layout

Repulsion, collision constraints, edge springs, annealed shuffle, and animated entrances.

03

Readable at scale

Perspective-aware, raster-cached multiline labels use level of detail and a bounded budget.

04

Complete interaction

Pan, zoom, selection, activation, hit testing, fitting, dragging, and contextual removal.

05

Framework neutral

Use it from plain TypeScript or wrap it in React, Vue, Svelte, or your own application shell.

06

Host-controlled data

Your application remains responsible for fetching data, auxiliary UI, and cascade semantics.

Small API.
Full graph UI.

Create a graph in a positioned container, add typed data, connect related nodes, and let BubbleGraph manage the visual system.

01

Build the library

Run npm install and npm run build. JavaScript and declarations are written to dist-lib/.

02

Create the graph

Supply a container and optional callbacks for selection, activation, and removal.

03

Add your data

Each datum needs a stable ID, label, numeric value, and any host-specific payload.

04

Clean up

Call destroy() when the host view unmounts.

import { BubbleGraph } from "bubblegraph";

const graph = await BubbleGraph.create({
  container: document.querySelector<HTMLElement>("#graph")!,
  onSelect: (index, node) => console.log(node),
});

const root = graph.add({
  id: "root", label: "Root item",
  value: 120, data: { url: "/root" },
});

const child = graph.add({
  id: "child", label: "Related item",
  value: 20, data: { url: "/child" },
}, root);

graph.connect(root, child);
graph.fit();

Requires a browser with WebGPU · HTTPS or localhost