--- license: other license_name: desert-ant-labs-source-available-1.0 license_link: https://license.desertant.ai/1.0 tags: - strokes - shapes - sketches - pen-input - on-device - core-ml - pencilkit pipeline_tag: image-classification --- # Shapes: on-device shape recognition from a single stroke Takes a single hand-drawn stroke (an ordered list of points) and recognizes it as a clean geometric shape, returning fitted vector geometry ready to snap to. Built for PencilKit-style "smart shapes": draw, pause, and the rough stroke becomes a crisp shape. The Core ML model is **about 0.2 MB** and runs in a few milliseconds on device. > ✏️ ➜ ▭ · ✏️ ➜ △ · ✏️ ➜ ◯ · ✏️ ➜ ★ ## Try it - **Live demo:** [desert-ant-labs/shapes-demo](https://huggingface.co/spaces/desert-ant-labs/shapes-demo): draw one stroke, get a fitted shape, fully in your browser. - **iOS / macOS / visionOS:** [`shapes-swift`](https://github.com/Desert-Ant-Labs/shapes-swift): Swift package with a one-line `PKCanvasView.enableShapeSnapping()` and a demo app. - **Android / Kotlin / JVM:** [`shapes-kotlin`](https://github.com/Desert-Ant-Labs/shapes-kotlin): the Kotlin SDK. - **JavaScript / TypeScript:** [`shapes-js`](https://github.com/Desert-Ant-Labs/shapes-js): the npm package (Node + browser). ## Files | File | Format | Size | Contents | |---|---|---:|---| | `shapes.mlmodelc` | Compiled Core ML | ~0.2 MB | 4-bit-palettized classifier, ready to load on Apple platforms | | `shapes.safetensors` | safetensors | ~0.2 MB | packed 4-bit palettized portable weights for JS/Kotlin | | `shapes_meta.json` | JSON | tiny | classes, preprocessing constants, model dims, and snap gates for JS/Kotlin | | `model.pt` | PyTorch checkpoint | ~1.5 MB | trained weights (for export / fine-tuning) | | `config.json` | JSON | tiny | class list, preprocessing constants, and per-class snap gates | ## How it works Two stages, *the network proposes, geometry verifies*: 1. **Classify**: the stroke is resampled and fed to a compact sequence classifier (Conv1d stem → small Transformer encoder → masked mean-pool → MLP), which predicts the shape type (or `none` to reject scribbles). 2. **Fit + snap**: a classical geometric fitter produces clean vector parameters (min-area box, moment/PCA ellipse, max-area triangle, …), then regularizes them (snap to axes, circles, squares, and 15° rotation increments). A fit-residual gate vetoes poor fits so non-shapes stay rejected. ## Inputs and outputs - **Input:** an ordered list of stroke points in canvas coordinates. Single stroke. - **Output:** a shape class plus fitted geometry, or nothing if the stroke is rejected. ## Classes `line`, `rectangle`, `triangle`, `ellipse`, `star`, plus `none` (the reject class: scribbles, partial shapes, and other non-shape strokes). Squares and circles are covered by `rectangle` and `ellipse` (snapped when near-regular). ## Limitations - Single stroke only; multi-stroke shapes aren't recognized. - Tuned for deliberate shapes; very rough or ambiguous strokes are rejected by design. ## License [Desert Ant Labs Source-Available License](https://license.desertant.ai/1.0). Free for most apps; a commercial license is required at scale. Full terms are at the link. Licensing: . ## Citation ```bibtex @software{shapes_2026, title = {Shapes: on-device shape recognition from a single stroke}, author = {Desert Ant Labs}, year = {2026}, url = {https://huggingface.co/desert-ant-labs/shapes}, } ``` --- © 2026 Desert Ant Labs ·