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

@desert-ant-labs/shapes

v0.2.5

Published

On-device single-stroke shape recognition.

Readme

@desert-ant-labs/shapes

On-device single-stroke shape recognition for Node and the browser. Pure JS, no ONNX or WASM runtime.

On-device single-stroke shape recognition. Takes a hand-drawn stroke (a list of [x, y] points) and returns a clean geometric shape, fully in-process, no inference runtime. It does sketch recognition on raw digital ink: one stroke in, one snapped vector shape out.

import { recognize } from "@desert-ant-labs/shapes";

const shape = await recognize(points); // points: [number, number][]
// { type: "ellipse", center: [120, 90], semiMajor: 64, semiMinor: 40, rotation: 0.2 }
// or null if the stroke isn't a recognizable shape

Features

  • Pure-JS inference (no ONNX/WASM runtime); recognition is a few ms
  • Recognizes line, rectangle, triangle, ellipse, and star (rejects scribbles)
  • Fits clean vector geometry and snaps it to axes, circles, squares, and 15° rotations
  • Model (~0.2 MB, 4-bit palettized) is fetched from the Hugging Face Hub at a pinned revision, then cached, to the filesystem on Node and to Cache Storage in the browser, so it loads once and runs offline after

Install

npm install @desert-ant-labs/shapes

Importing

Pure ESM and fully tree-shakeable. The same import works everywhere (Node, bundlers, browsers, and edge/worker runtimes); the right build is selected automatically:

import { recognize } from "@desert-ant-labs/shapes";

CommonJS consumers use dynamic import (const { recognize } = await import("@desert-ant-labs/shapes")); native require() works on Node ≥ 22.12.

Bring-your-own-bytes. If you load the model files yourself, import the hub-free core from @desert-ant-labs/shapes/core, only the inference engine, with zero network/filesystem code:

import { createShapes } from "@desert-ant-labs/shapes/core";

// weights is a Uint8Array (shapes.safetensors); meta is the parsed shapes_meta.json
const shapes = createShapes({ weights, meta });
shapes.recognize(points)?.type; // "triangle"

Loading model

Model files (shapes.safetensors, shapes_meta.json) are fetched from the Hugging Face Hub (desert-ant-labs/shapes) at a pinned revision and cached.

  • Node: recognize() works zero-config; files cache under ~/.cache/shapes. To run fully offline, ship the files yourself and point at a folder with env.localModelPath (or SHAPES_LOCAL_PATH).
  • Browser: same API; files cache in Cache Storage.
import { env, load, recognize } from "@desert-ant-labs/shapes";

env.revision = "main";                 // or a commit SHA / tag
env.localModelPath = "./shapes-model"; // Node: use local files, skip the Hub

// or load an explicit instance (synchronous inference after it resolves)
const shapes = await load();
shapes.recognize(points)?.type;

API

export function recognize(points: Point[]): Promise<Shape | null>;
export function load(options?: Partial<ShapesEnv>): Promise<ShapesModel>;
export function createShapes(buffers: { weights; meta }): ShapesModel; // raw buffers
export function outline(shape: Shape, samples?: number): Point[];       // renderable polyline
export const env: ShapesEnv;
export function reset(): void; // clear the memoized model so the next recognize() re-reads env

export type Point = [number, number];

export type Shape =
  | { type: "line"; from: Point; to: Point }
  | { type: "rectangle"; corners: Point[] }
  | { type: "triangle"; vertices: Point[] }
  | { type: "ellipse"; center: Point; semiMajor: number; semiMinor: number; rotation: number }
  | { type: "star"; center: Point; outerRadius: number; innerRadius: number; rotation: number; pointCount: number };

recognize(points) returns the snapped shape, or null when the stroke is rejected (not a shape) or degenerate. ShapesModel.recognize is synchronous once loaded.

Example

Examples/ShapesExample is a tldraw canvas demo: draw a shape, pause for the preview, then lift to snap on-device.

cd Examples/ShapesExample
npm install
npm run dev

Model

Published at desert-ant-labs/shapes on Hugging Face.

Other platforms

Same model, native on each platform:

License

Desert Ant Labs Source-Available License. Free for most apps; a commercial license is required at scale. Full terms are at the link. Licensing: [email protected].