Shapes: On-device Single-Stroke Shape Recognition
On-device single-stroke shape recognition that turns one hand-drawn stroke into a clean rectangle, ellipse, triangle, star, or line.
Shapes takes one hand-drawn stroke, a list of [x, y] points, and returns clean geometry: rectangle, ellipse, triangle, star, or line. The model fits precise vector shapes, snaps to axes, circles, squares, and 15-degree rotations, and rejects scribbles that are not shapes.
On Apple it adds Notes-style smart-shape snapping to PencilKit with a single call, live preview intact. Apple's own "Snap to Shape" is private API third-party apps cannot call, so Shapes fills that gap. The model is small enough to ship inside the app with no model download, and the web build runs a local WebAssembly pipeline with LiteRT.js inference.
Demo
Performance
Under 10 ms per stroke, from a 0.2 MB model with no inference runtime on the web.
Internal measurements. Pure-JS inference on the web, Core ML on Apple.
Use cases
Notes-style smart shapes
Add snap-to-shape to a PencilKit canvas with canvasView.enableShapeSnapping(). Live preview, undo and redo preserved, filling the gap left by Apple's private Snap to Shape API.
Diagram and whiteboard tools
Clean freehand strokes into precise geometry. Works with tldraw and Excalidraw stroke data.
Cross-platform drawing
The same recognizer runs on iOS, Android, and the web, so a drawing feature behaves identically everywhere.
No model download
At about 0.2 MB it ships inside the app. Unlike Google ML Kit Digital Ink there is no ~20 MB model to fetch at runtime.
What it does
- Recognizes rectangle, ellipse, triangle, star, and line, and rejects non-shapes.
- Snaps to axes, circles, squares, and 15-degree rotations.
- PencilKit live snapping via one call:
canvasView.enableShapeSnapping(). - Web inference via a local WebAssembly pipeline with LiteRT.js.
Platforms and install
// Swift Package Manager
.package(url: "https://github.com/Desert-Ant-Labs/shapes", from: "0.5.0")
import Shapes
let shapes = Shapes()
let shape = try await shapes.recognize(points: stroke)
// Shape? -> rectangle, ellipse, triangle, star, line
import PencilKit
import Shapes
// Live smart-shape snapping on a PencilKit canvas, in one line.
// Pause after a stroke to preview the fit, lift to snap. Undo-safe,
// and it uses the same recognizer, bundled by default.
canvasView.enableShapeSnapping()
// build.gradle.kts (Maven Central)
implementation("ai.desertant:shapes:0.5.0")
import ai.desertant.shapes.Shapes
val shapes = Shapes(context)
val shape = shapes.recognize(points)
// Shape? -> rectangle, ellipse, triangle, star, line
npm i @desert-ant-labs/shapes @litertjs/core
import { Shapes } from "@desert-ant-labs/shapes";
const shapes = await Shapes.load();
const shape = await shapes.recognize(points);
// { kind: "ellipse", center: {...}, ... } or null
Add Shapes from Desert Ant Labs to this project.
On-device single-stroke shape recognition that turns one hand-drawn stroke into a clean rectangle, ellipse, triangle, star, or line.
SDKs (use the one that matches this project's platform):
Swift (iOS, macOS)
Repo: https://github.com/Desert-Ant-Labs/shapes
// Swift Package Manager
.package(url: "https://github.com/Desert-Ant-Labs/shapes", from: "0.5.0")
Kotlin (Android)
Repo: https://github.com/Desert-Ant-Labs/shapes
// build.gradle.kts (Maven Central)
implementation("ai.desertant:shapes:0.5.0")
JavaScript / TypeScript (Web, Node.js)
Repo: https://github.com/Desert-Ant-Labs/shapes
npm i @desert-ant-labs/shapes @litertjs/core
Reference:
- Model page: https://desertant.com/models/shapes/
- Full catalog and other models: https://desertant.com/llms.txt
Add the SDK that matches this project's platform, then follow its README for the exact API and current version. Do not invent API names or method signatures; confirm them against the README.
Specs
- Shapes
- Rectangle, ellipse, triangle, star, line
- On-device size
- 0.2 MB (4-bit Core ML on Apple)
- Latency
- <10 ms
- Web runtime
- WebAssembly + LiteRT.js
FAQ
What is Shapes?
On-device single-stroke shape recognition that turns one hand-drawn stroke into a clean rectangle, ellipse, triangle, star, or line.
Does Shapes run on device?
Yes. Shapes runs entirely on device: inference happens locally with no server call, so data never leaves the device.
Which platforms does Shapes support?
Shapes ships as native on-device SDKs for Swift, Kotlin, JavaScript / TypeScript.
How much does Shapes cost?
Every model is free up to 100k monthly active devices per SDK. Unlimited inference per user. Contact us for custom licenses.
How accurate or fast is Shapes?
Under 10 ms per stroke, from a 0.2 MB model with no inference runtime on the web.