@superb-ai/image-kit
v0.4.0
Published
Paint — Rust/wgpu 2D annotation editor for the web (wasm). Generic, framework-agnostic web runtime over the `editor` domain + `paint_engine` renderer.
Readme
@superb-ai/image-kit
Rust/wgpu 2D annotation editor for the web (wasm). Generic, framework-agnostic
web runtime over the editor domain + paint_engine renderer (this repo).
Use
import { init, create_web_editor, PaintEditor, Tool } from '@superb-ai/image-kit';
// Ergonomic:
const ed = await PaintEditor.mount(canvas);
ed.setTool(Tool.Box);
ed.start();
// Or drive the raw WebEditor yourself (build your own framework binding):
await init();
const web = await create_web_editor(canvas, devicePixelRatio);
web.set_tool('draw_box');
web.tick();The raw WebEditor surface is in pkg/paint_image_kit_wasm.d.ts.
Building an editor with an AI agent? Point it at
AGENT.md— the grimoire scroll: tool catalog, keymap, gestures, custom-tool (SAM) and read-back patterns, React lifecycle gotchas, all verified bye2e/.
Custom tools (e.g. SAM) — without forking the editor
A host builds an annotation via a draft: the editor owns the preview, snap, commit, and undo; your async work (e.g. a SAM inference call) stays in your code.
// 1. your tool's click → start a draft (class assigned upfront).
ed.beginDraft('polygon', 'car');
// 2. (your async SAM call — entirely in your code.)
const mask = await sam.segment(prompt); // → flat xy image-space coords
// 3. inject the result. ringLens = vertices per ring (ring 0 = outer, 1.. = holes).
ed.draftSetPolygon(mask.coords, mask.ringLens); // shows a live preview
// 4. accept → committed, undoable annotation; or ed.cancelDraft().
const id = ed.commitDraft();The editor renders the draft preview in the wgpu canvas; SAM masks keep their holes / disjoint regions. The interaction (which click is a prompt, refine loops) is yours; the result polygon's editing is the editor's.
Reading back geometry — anchor HTML chrome over shapes
tick() renders shapes to the canvas (opaque). To put DOM UI (labels, tooltips,
accept/reject buttons) over a shape, read its screen box — no need to re-render:
const box = ed.annotationScreenBounds(id); // [x, y, w, h] logical px, or null
const hit = ed.hitTest(localX, localY, 5); // topmost annotation uuid, or nullBuild
npm run build # wasm-pack --release → ./pkg (what publish ships)
npm run build:dev # faster, unoptimizedRequires the Rust toolchain + wasm-pack. pkg/ is a build artifact
(git-ignored); prepublishOnly rebuilds it (--release) before every publish.
Publish
Versioned, like @superb-ai/prism:
npm version patch # bump
npm publish # builds --release via prepublishOnly, then publishesSee repo services/image-kit notes for the dev-account / token flow.
