Interactive visualization for TypeScript, built for the browser.
Documentation · Examples · Hub
Status: pre-1.0 (
0.1.x). The API is stabilizing but may still change between minor versions.
Vizzy is for interactive visuals you can drop into a page. It's for people writing technical content (blog posts, docs, tutorials, explorable essays) who've hit the wall where static charts aren't enough but a whole JavaScript framework feels like overkill just to make a diagram move. Function graphs, geometric diagrams, algorithm walkthroughs: anywhere a moving, touchable picture beats prose.
It runs in TypeScript, renders in the browser, and is interactive by default, so you can drop a draggable derivative into a blog post, visualize a sorting algorithm in your docs, embed a classroom demo in a textbook, or prototype a visual proof directly in the page.
Vizzy isn't a charting library, a research notebook, or a Python-to-video pipeline. It's for interactive pictures that live inside your prose: ones the reader can drag, slide, and explore.
If you've used manim, you'll recognize a few ideas. Vizzy is its own project, shaped around the browser, async/await, and live interaction rather than offline video rendering.
npm install @vizzyjs/core @vizzyjs/renderer-canvasimport { circle, fadeIn, sky } from '@vizzyjs/core';
import { createScene } from '@vizzyjs/renderer-canvas';
const canvas = document.querySelector('canvas')!;
const { add, play, grid } = createScene(canvas);
grid();
const c = circle({ radius: 1, color: sky });
add(c);
await play(fadeIn(c));Using React? See @vizzyjs/react for a useScene hook that handles the canvas ref and lifecycle for you.
play() returns a Promise. await sequences animations without queues or schedulers.
import { circle, fadeIn, fadeOut, animateShift, animateRotate, animateColor, sky, violet } from '@vizzyjs/core';
import { createScene } from '@vizzyjs/renderer-canvas';
const canvas = document.querySelector('canvas')!;
const { add, play } = createScene(canvas);
const c = circle({ color: sky });
add(c);
await play(fadeIn(c));
await play(animateShift(c, [3, 0]));
await play(animateRotate(c, Math.PI * 2));
await play(animateColor(c, { stroke: violet }));
await play(fadeOut(c));Drag a point around and update its label in world coordinates.
import { circle, text, sky, white } from '@vizzyjs/core';
import { createScene } from '@vizzyjs/renderer-canvas';
const canvas = document.querySelector('canvas')!;
const { add, grid, interact } = createScene(canvas);
grid();
const dot = circle({ radius: 0.2, style: { fill: sky, stroke: null } });
const label = text({
content: '(0.0, 0.0)',
position: [0, 0.5],
style: { fill: white, fontSize: 0.25 },
});
add(dot, label);
interact.draggable(dot, {
onDrag(pos) {
dot.moveTo(pos);
label.position = [pos[0], pos[1] + 0.5];
label.content = '(' + pos[0].toFixed(1) + ', ' + pos[1].toFixed(1) + ')';
},
});| Package | Description |
|---|---|
@vizzyjs/core |
Render-agnostic core: shapes, scene graph, animations, math utilities |
@vizzyjs/renderer-canvas |
Canvas2D renderer with controls and interaction |
@vizzyjs/react |
React bindings: useScene hook |
- Shapes, not draw calls. 30+ factories (circles, axes, function graphs, TeX, arrows, braces, angles) with defaults that don't make you fight them.
- Animate with
await.await play(fadeIn(c))does the obvious thing. Sequence withawait, parallelize withplay(a, b, c). No animation scheduler to learn. - Interaction isn't an afterthought. Shapes can be dragged, hovered, and clicked. Sliders, checkboxes, and color pickers re-render the scene on change. No event wiring required.
- Think in math, not pixels. 14×8 world units, Y-up, origin at center.
radius: 1is a unit circle, not a 100-pixel blob. DPR and canvas resize handled for you. - Function graphs that don't lie. Discontinuities are handled without phantom vertical lines. One-call helpers for tangents, secants, KaTeX labels, braces, and annotations.
- Colors you won't have to google. The full Tailwind palette (22 scales × 11 shades) baked in. Reach for
sky[400]instead of memorizing#0ea5e9.
This is a pnpm workspace.
pnpm install
pnpm playground # local dev sandbox with Monaco editor + live preview
pnpm test
pnpm typecheckSee CONTRIBUTING.md for how to actually ship a contribution: workflow, code conventions, and tips on adding new shapes or animations.
Vizzy is pre-1.0. The API is stabilizing but will still move between minor versions.
Landing next:
- SVG renderer. The
Rendererinterface is already backend-agnostic; SVG is the next implementation, useful for print, export, and accessibility trees. - Richer interaction primitives. Constrained dragging, keyboard handlers, animated drag paths.
- Community shape registry. A shadcn-style catalog where contributors publish shapes (diagrams, domain-specific helpers, custom visuals) and you copy them into your project instead of adding a dep. Keeps the core small; keeps ownership with you.
- 1.0 API freeze. Once the surface settles, committing to a
1.0. - Scene export. Record a scene to GIF or MP4 from code, without the screen-capture dance.
Explicitly not on the roadmap (for 1.0):
- 3D rendering. Out of scope; browser-native 3D is a different product.
- A chart DSL.
@vizzyjs/coreis primitive-level by design. - Svelte / Vue bindings. Welcome as community packages once the core API freezes.
Ideas, bug reports, and use cases are welcome in Discussions and Issues.
