npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

canvas2d-geometry-ir

v0.1.2

Published

Deterministic Canvas-like recording and geometry IR engine

Downloads

31

Readme

Canvas2DGeometryIR

Canvas2DGeometryIR is a standalone Bun + TypeScript library for deterministic 2D vector composition, structured geometry inspection, and replay rendering.

It provides a Canvas-like recording API that does not draw pixels while composing. Instead, the context records paths and paint operations into a structured, JSON-safe intermediate representation (IR). Geometry operations and replay are derived from that IR.

v1 scope

  • Path recording (moveTo, lineTo, bezierCurveTo, quadraticCurveTo, arc, closePath)
  • Fills and strokes
  • Transform operations (translate, scale, rotate, setTransform, resetTransform)
  • State stack (save, restore)
  • Replay to an injected canvas-like target
  • Geometry queries
    • axis-aligned bounds
    • point hit testing
    • path intersections (flattened)
    • closest-point on boundaries
    • anchor/anchor-candidate extraction
    • path inspection (segment kinds, subpath count)
  • JSON-safe serialization/deserialization with Zod validation

Text rendering is intentionally out of scope for v1.

Installation

bun install

Published npm releases are generated by GitHub Actions on every push to main or trunk. The committed package.json keeps a stable base version such as 0.1.0, and CI rewrites it at publish time to 0.1.<github.run_number> without committing that change back.

Scripts

bun run typecheck
bun test
bun run build
bun run playground:build
bun run playground:serve

bun run playground:build emits a static site in playground/site, which is the artifact used for GitHub Pages deployment.

Quick usage

import {
  Canvas2DGeometryIRContext,
  GeometryEngine,
  replayDocument,
  serializeDocument,
  deserializeDocument,
} from "canvas2d-geometry-ir";

const ctx = new Canvas2DGeometryIRContext();
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(100, 0);
ctx.lineTo(100, 100);
ctx.closePath();
ctx.fillStyle = "#0ea5e9";
ctx.fill();

const doc = ctx.getDocument();
const engine = new GeometryEngine(doc);

console.log(engine.getBounds());
console.log(engine.hitTestPoint({ x: 20, y: 20 }));
console.log(engine.closestPoint({ x: 105, y: 30 }));
console.log(engine.getAnchorCandidates());

const json = serializeDocument(doc);
const roundtrip = deserializeDocument(json);

// replayDocument(roundtrip, yourCanvasLikeTarget)

Browser playground (manual verification + bug capture)

A lightweight browser playground now ships in playground/ for realistic manual verification of:

  • selecting visible paths or grouped shapes
  • dragging path bodies directly
  • editing anchors and control points directly
  • interactively adding line, arc, and Bezier segments
  • inspecting bounds and anchor overlays
  • exporting reproducible scenes (scene + tool state + concise click trace)

Run locally

bun run playground:serve

Then open the printed local URL (default http://localhost:4070).

GitHub Pages deployment

The repository now includes /.github/workflows/deploy-playground.yml, which builds the static playground and deploys it to GitHub Pages on pushes to main.

To enable it in GitHub:

  1. Open the repository settings.
  2. Go to Pages.
  3. Set Source to GitHub Actions.

After that, each push to main will publish the latest playground build.

npm publishing

The repository also includes /.github/workflows/publish-npm.yml for package publishing to npm.

To enable npm publishing in GitHub:

  1. Create an npm automation or granular access token that can publish this package and is allowed to bypass 2FA for publishing.
  2. Add it to the repository secrets as NPM_TOKEN.
  3. Push to main or trunk.

Important details:

  • package.json must keep the repository URL exactly as https://github.com/alexandr-panchenko/Canvas2DGeometryIR
  • the workflow publishes with NODE_AUTH_TOKEN from the NPM_TOKEN GitHub secret
  • use a token that can bypass your npm publish 2FA requirement, otherwise npm will reject the publish

Each eligible push to main or trunk will:

  • install dependencies with Bun
  • run tests
  • build the package and declaration files
  • replace the base version in package.json only inside CI
  • publish the resulting package to the public npm registry

The workflow publishes only on the first run attempt for a given push so a manual rerun does not collide with an already-published version.

Bug-capture workflow

  1. Load one of the built-in scenes.
  2. Reproduce the incorrect interaction (selection, drag, point editing, grouping, etc.).
  3. Click Export Scene.
  4. Paste the exported JSON artifact into your bug report.

The export includes:

  • current scene data
  • ordered scene commands
  • derived geometry document
  • current tool state
  • recent click-only interaction log

This makes failures reproducible without manually authoring numeric geometry expectations.

Replay target contract

Replay stays independent of browser/DOM APIs. A host can adapt any backend by implementing:

  • beginPath, moveTo, lineTo, bezierCurveTo, arc, closePath
  • fill, stroke
  • setFillStyle, setStrokeStyle, setLineWidth

Determinism

  • IR emission order is stable.
  • Draw operations receive stable generated IDs (op-0, op-1, ...).
  • Serialization output is JSON-safe and deterministic for equivalent command streams.

Geometry model

Each path is composed from ordered subpaths and segments. Segment kinds are:

  • line
  • bezier (cubic)
  • arc

Segment-level operations are implemented and composed upward for path/document-level queries.

Serialization

Use:

  • serializeDocument(document): string
  • deserializeDocument(json): GeometryDocument

Deserialization validates with Zod schemas to prevent untyped data from leaking into geometry code.

Examples

See examples/basic.ts.

Run it with:

bun run examples/basic.ts

Performance notes (v1)

Current implementation favors clarity and correctness.

Hotspots to optimize later if needed:

  1. Bézier/arc flattening used by hit tests and intersections.
  2. Repeated path flattening in repeated queries.
  3. Repeated bounds recomputation across immutable documents.

Safe future improvements:

  • Cache flattened polylines per segment/path with tolerance keying.
  • Cache per-op and full-document bounds.
  • Add broad-phase spatial bucketing for hit and intersection queries.

Non-goals for v1

  • Full browser Canvas API fidelity
  • Text layout/rendering
  • DOM-specific dependencies
  • Speculative plugin framework internals