Core renderer overview
insomni is an opinionated 2D WebGPU renderer built on
TypeGPU. It is tuned for data-heavy
scenes: every primitive is packed into one flat typed array, uploaded in a
single batch per frame, and drawn with SDF-style pipelines. The public surface
is one barrel import:
import { initGPU, createRenderer, createLayer, rgba } from "insomni";The pack, upload, draw model
Section titled “The pack, upload, draw model”A frame moves through three stages.
- Pack (CPU). You author shapes into a
Layer. EachpushRect/pushCircle/pushSegmentcall appends one instance — a fixed 16-float (64-byte) record — into the layer’sUberPack. All shape kinds share oneArrayBuffer; adjacent instances of the same kind, opacity, and group merge into a singleDrawCommand. - Upload (GPU).
Renderer2D.render(layers)concatenates every layer’s pack into one storage buffer and uploads it once. The buffer grows power-of-2 / 1.25× and is reused frame to frame. - Draw (GPU). The renderer issues the merged draw commands in a single
render pass: opaque geometry first (depth write on), then transparent
geometry. Depth is the per-instance
orderfield, stamped in global submission order, so painter stacking is explicit — later-submitted draws land on top.
const gpu = await initGPU();const renderer = createRenderer(gpu, canvas);
const layer = createLayer();layer.pushRect({ x: 16, y: 16, width: 180, height: 72, fill: rgba(0.06, 0.09, 0.13, 1) });layer.pushCircle({ cx: 240, cy: 52, radius: 18, fill: rgba(0.2, 0.7, 1, 0.9) });
function frame() { renderer.render([layer]); requestAnimationFrame(frame);}frame();Layers hold scene content
Section titled “Layers hold scene content”Ordinary painter-ordered scene content lives in a Layer. It wraps one
UberPack, a coordinate space, an optional default
Group, and metadata such as zIndex, cache,
visible, and label. Text and sprites ride on the same layer through dedicated
sibling pipelines. Specialized values such as CustomDrawable are phase hooks,
not layers.
Source-order draw semantics
Section titled “Source-order draw semantics”This ordering applies to ordinary Layers. Specialized BufferLayer and
CustomDrawable values use documented renderer phases; custom drawables choose
placement: "underlay" | "overlay".
render([a, b]) draws a first, then b. Layers are flat z-bands: layer b
is entirely above layer a (painter’s order), with no per-shape interleave
across layers. To interleave shapes, put them in the same layer (intra-
layer overlap resolves via transparency and depth). To
override insertion order without reordering the array, set
Layer.zIndex.
Static vs dynamic layers
Section titled “Static vs dynamic layers”By default a layer is dynamic: its pack is re-concatenated and re-uploaded every frame. For content that rarely changes, two retention tiers skip that work:
- Retained buffers —
renderer.retainLayer(layer, key)hands the layer’s pack a stable GPU buffer. Whilekey(andpack.version) are unchanged the layer draws with zero re-upload. See Packing and Renderer. - Cached RTT bakes —
renderer.cacheLayer(layer)(or thecache: "always"/"auto"hint) rasterizes the layer once into a texture and composites the snapshot instead of redrawing it.
Combined with damage-tracked partial redraw, this lets a busy scene re-rasterize only what actually moved.
Map of this section
Section titled “Map of this section”- Renderer & frame loop —
Renderer2D,createRenderer,render(layers), retention, config & timing. - Layers & groups — ordinary scene content and shareable transform containers.
- Packing & buffers —
UberPack, the instance schema, strides, dynamic growth, repack helpers. - Spaces & cameras — world/ui/device spaces, camera slots,
project, camera-view helpers. - Drawing primitives — rects, circles, segments, curves, arcs, sprites.
- Text — raster (system-font) and MSDF/TTF text.
- Specialized layers — Buffer, Mirror, Navigator, Lod, LabelCuller, CustomDrawable.
- Cameras & viewport — viewports, pan/zoom/pinch.
- Interactions — hit-testing, hover, selection, tooltips, brush, menus.
- Transparency (OIT) — the default-on A-buffer.
- Damage & partial redraw — persistent backbuffer + scissored regions.
- SVG export — CPU backend over the same
Layer[]. - Math, color & animation — vectors, matrices, color spaces, RNG, easings.
- Debugging & profiling — the render-debug probe and the profiler.