@desert-ant-labs/shapes 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +136 -0
- package/README.md +115 -0
- package/dist/cache-node.d.ts +5 -0
- package/dist/cache-node.js +32 -0
- package/dist/cache-web.d.ts +3 -0
- package/dist/cache-web.js +24 -0
- package/dist/fit.d.ts +6 -0
- package/dist/fit.js +393 -0
- package/dist/hub.d.ts +31 -0
- package/dist/hub.js +42 -0
- package/dist/index.browser.d.ts +18 -0
- package/dist/index.browser.js +36 -0
- package/dist/index.node.d.ts +18 -0
- package/dist/index.node.js +43 -0
- package/dist/model.d.ts +48 -0
- package/dist/model.js +342 -0
- package/dist/preprocess.d.ts +14 -0
- package/dist/preprocess.js +111 -0
- package/dist/shape.d.ts +34 -0
- package/dist/shape.js +38 -0
- package/package.json +80 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Desert Ant Labs Source-Available License
|
|
2
|
+
|
|
3
|
+
Version 1.0 · 2026-06-15
|
|
4
|
+
|
|
5
|
+
Copyright © 2026 Studio Company B.V., trading as Desert Ant Labs (`desertant.ai`).
|
|
6
|
+
|
|
7
|
+
This license governs Your use of the software, model weights, datasets, documentation, and associated assets in this repository (collectively, the **"Licensed Materials"**). It is a **source-available license intended for professional and business use**; it is not an OSI-approved open-source license. The rights granted here are subject to a per-Model usage cap and the other terms set out below.
|
|
8
|
+
|
|
9
|
+
## Definitions
|
|
10
|
+
|
|
11
|
+
- **"Desert Ant Labs"** (also "We", "Us", "Our") — Studio Company B.V., a private limited liability company (*besloten vennootschap*) incorporated under the laws of the Netherlands, with statutory seat in Amsterdam, registered with the Dutch Chamber of Commerce (KvK) under number **81228112**, trading as Desert Ant Labs.
|
|
12
|
+
- **"Model"** — a set of trained weights published by Desert Ant Labs under a single HuggingFace repository (for example, `huggingface.co/desert-ant-labs/eye`). Each Model is a distinct work under this license.
|
|
13
|
+
- **"Monthly Active User"** or **"MAU"** — a unique end user who interacts with a feature powered by a Model during a calendar month. Internal use by Your own employees and contractors does not count.
|
|
14
|
+
- **"You"** — the individual or legal entity exercising rights under this license.
|
|
15
|
+
|
|
16
|
+
## 0. Acceptance
|
|
17
|
+
|
|
18
|
+
By downloading, accessing, using, copying, modifying, or distributing the Licensed Materials, You agree to be bound by this license. If You do not agree, You may not use the Licensed Materials.
|
|
19
|
+
|
|
20
|
+
## 1. Grant
|
|
21
|
+
|
|
22
|
+
Subject to Your continued compliance with this license, Desert Ant Labs grants You a worldwide, royalty-free, non-exclusive, non-transferable, non-sublicensable license to use, reproduce, modify, and distribute the Licensed Materials.
|
|
23
|
+
|
|
24
|
+
## 2. Free-tier use
|
|
25
|
+
|
|
26
|
+
You may use the Licensed Materials free of charge, including for commercial purposes, subject to the following per-Model threshold:
|
|
27
|
+
|
|
28
|
+
> **For each Desert Ant Labs Model that Your products incorporate, the aggregate Monthly Active Users across all Your products must not exceed 100,000 in any calendar month.**
|
|
29
|
+
|
|
30
|
+
The threshold applies independently to each Model. Two Models at 50,000 MAU each do not combine into 100,000 MAU; each is independently within its own free-tier limit.
|
|
31
|
+
|
|
32
|
+
If a repository contains only software (no trained Model weights), no MAU threshold applies to that software on its own. The threshold attaches to the Models the software is used with.
|
|
33
|
+
|
|
34
|
+
## 3. Research and academic use
|
|
35
|
+
|
|
36
|
+
Use of the Licensed Materials for non-commercial scientific research and academic publications is exempt from the MAU threshold in Section 2, provided that any resulting publication credits "Desert Ant Labs" and links to the relevant Model repository.
|
|
37
|
+
|
|
38
|
+
## 4. Commercial license
|
|
39
|
+
|
|
40
|
+
If Your aggregate MAU for any Model exceeds 100,000 (or You expect it to within the next calendar month), You must obtain a commercial license from Desert Ant Labs before continuing to distribute or operate any product that incorporates that Model. A commercial license covers only the Models named in it; other Models remain under the free tier subject to their own thresholds.
|
|
41
|
+
|
|
42
|
+
Contact: <licensing@desertant.ai>.
|
|
43
|
+
|
|
44
|
+
## 5. Patent grant
|
|
45
|
+
|
|
46
|
+
Each contributor to the Licensed Materials grants You a perpetual, worldwide, non-exclusive, royalty-free, irrevocable (except as stated in this Section) patent license to make, use, sell, offer to sell, and import the Licensed Materials, where such license applies only to those patent claims licensable by that contributor that are necessarily infringed by the Licensed Materials.
|
|
47
|
+
|
|
48
|
+
**If You institute patent litigation against any entity** (including a cross-claim or counterclaim in a lawsuit) alleging that the Licensed Materials infringe a patent, **all patent licenses granted to You under this license terminate as of the date such litigation is filed.**
|
|
49
|
+
|
|
50
|
+
## 6. Restrictions
|
|
51
|
+
|
|
52
|
+
You may not:
|
|
53
|
+
|
|
54
|
+
1. Sell, sublicense, or otherwise distribute the Licensed Materials themselves, or any substantially unmodified derivative of them, as a standalone product or hosted service.
|
|
55
|
+
2. Use the Licensed Materials to train, distill, fine-tune, or otherwise derive a model that You release or distribute under any license more permissive than this license, including any OSI-approved open-source license. Internal research, personal fine-tuning, and use of derivative models that remain under this license are not restricted.
|
|
56
|
+
3. Remove or alter the copyright, license, attribution, or third-party notices in the Licensed Materials.
|
|
57
|
+
|
|
58
|
+
You may freely embed the Licensed Materials in Your own product, subject to Section 2 and the rest of this license.
|
|
59
|
+
|
|
60
|
+
## 7. Attribution
|
|
61
|
+
|
|
62
|
+
You must retain this LICENSE file and the copyright notice in all copies and substantial portions of the Licensed Materials. Where Your product surfaces acknowledgements, third-party notices, or "About" / "Credits" screens, please credit **"Desert Ant Labs (`desertant.ai`)"**.
|
|
63
|
+
|
|
64
|
+
## 8. Modifications
|
|
65
|
+
|
|
66
|
+
You may modify the Licensed Materials. If You distribute modified Licensed Materials, You must:
|
|
67
|
+
|
|
68
|
+
(a) include a prominent notice stating that You have modified them, with the date of modification; and
|
|
69
|
+
(b) ensure that Your distributed modifications are licensed under this license.
|
|
70
|
+
|
|
71
|
+
This license governs the Licensed Materials and modifications to them. Applications and products that merely incorporate, link to, or call the Licensed Materials are Your own work; their structure, source, and license are not constrained by this license, subject only to Sections 2, 6, and 7.
|
|
72
|
+
|
|
73
|
+
## 9. Reporting
|
|
74
|
+
|
|
75
|
+
To enable Desert Ant Labs to administer the free tier, You agree:
|
|
76
|
+
|
|
77
|
+
(a) to maintain reasonable records of Your aggregate MAU per Model; and
|
|
78
|
+
(b) upon written request from Desert Ant Labs, to provide a reasonable summary of those records sufficient to confirm compliance with Section 2. Such requests will be made no more than once per calendar year per licensee, except in the case of a reasonable, specific suspicion of breach.
|
|
79
|
+
|
|
80
|
+
You are encouraged — but not required — to notify Desert Ant Labs at <licensing@desertant.ai> when Your aggregate MAU for any Model first exceeds 80,000.
|
|
81
|
+
|
|
82
|
+
## 10. Trademarks
|
|
83
|
+
|
|
84
|
+
This license does not grant You any right to use the trade names, trademarks, service marks, or product names of Desert Ant Labs, except for the limited attribution use specified in Section 7. All goodwill arising from such attribution use inures to the benefit of Desert Ant Labs.
|
|
85
|
+
|
|
86
|
+
## 11. Third-party components
|
|
87
|
+
|
|
88
|
+
The Licensed Materials may include or derive from components licensed by third parties. Those components remain subject to their own licenses; nothing in this license overrides those terms. Notices for such components are provided in the model card or in a `THIRD_PARTY_NOTICES.md` file alongside the Licensed Materials.
|
|
89
|
+
|
|
90
|
+
## 12. Termination
|
|
91
|
+
|
|
92
|
+
This license terminates automatically and immediately upon any of the following:
|
|
93
|
+
|
|
94
|
+
(a) Your aggregate MAU for any Model exceeds 100,000 and You do not obtain a commercial license within thirty (30) days;
|
|
95
|
+
(b) Your breach of Section 6 (Restrictions); or
|
|
96
|
+
(c) Your institution of patent litigation as described in Section 5.
|
|
97
|
+
|
|
98
|
+
For any other curable breach, Desert Ant Labs will provide written notice; if the breach is not cured within thirty (30) days of receipt of that notice, this license terminates as of the date the notice was sent.
|
|
99
|
+
|
|
100
|
+
Upon termination, You must cease using and distributing the Licensed Materials. Sections 7 (Attribution, with respect to copies already in the field), 10 (Trademarks), 11 (Third-Party Components), 13 (No Warranty), 14 (Limitation of Liability), and 15 (Governing Law) survive termination.
|
|
101
|
+
|
|
102
|
+
## 13. No warranty
|
|
103
|
+
|
|
104
|
+
THE LICENSED MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. Desert Ant Labs makes no representation that the Licensed Materials are error-free, secure, or suitable for any particular use.
|
|
105
|
+
|
|
106
|
+
## 14. Limitation of liability
|
|
107
|
+
|
|
108
|
+
IN NO EVENT SHALL DESERT ANT LABS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, CONSEQUENTIAL, SPECIAL, OR EXEMPLARY DAMAGES (INCLUDING LOST PROFITS, LOSS OF DATA, OR BUSINESS INTERRUPTION) ARISING FROM OR IN CONNECTION WITH THE LICENSED MATERIALS, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
|
109
|
+
|
|
110
|
+
DESERT ANT LABS' TOTAL CUMULATIVE LIABILITY UNDER OR IN CONNECTION WITH THIS LICENSE SHALL NOT EXCEED THE GREATER OF (A) ONE HUNDRED EUROS (€100) OR (B) THE TOTAL FEES PAID BY YOU TO DESERT ANT LABS UNDER A SEPARATE COMMERCIAL LICENSE IN THE TWELVE (12) MONTHS PRECEDING THE CLAIM.
|
|
111
|
+
|
|
112
|
+
Nothing in this license limits or excludes liability to the extent such limitation or exclusion is not permitted by applicable mandatory law, including liability for willful misconduct (*opzet*) or gross negligence (*bewuste roekeloosheid*) and any mandatory provision of Dutch consumer-protection law.
|
|
113
|
+
|
|
114
|
+
## 15. Governing law and jurisdiction
|
|
115
|
+
|
|
116
|
+
This license is governed by the laws of the Netherlands, without regard to its conflict-of-laws provisions. The competent courts of Amsterdam, the Netherlands, have exclusive jurisdiction over any dispute arising under or in connection with this license, subject to mandatory provisions of applicable consumer-protection law.
|
|
117
|
+
|
|
118
|
+
The United Nations Convention on Contracts for the International Sale of Goods (CISG, 1980) does not apply to this license.
|
|
119
|
+
|
|
120
|
+
## 16. Miscellaneous
|
|
121
|
+
|
|
122
|
+
(a) **Severability.** If any provision of this license is held unenforceable by a court of competent jurisdiction, the remaining provisions remain in full force and effect, and the unenforceable provision shall be interpreted to give effect to its intent to the greatest extent permitted by law.
|
|
123
|
+
|
|
124
|
+
(b) **No waiver.** Failure or delay by Desert Ant Labs to enforce any right under this license is not a waiver of that right.
|
|
125
|
+
|
|
126
|
+
(c) **Assignment.** You may not assign this license without Desert Ant Labs' prior written consent. Desert Ant Labs may freely assign this license to a successor in interest. This license binds and benefits each party's successors and permitted assigns.
|
|
127
|
+
|
|
128
|
+
(d) **Entire agreement.** This license, together with any separate commercial license referenced in Section 4, is the entire agreement between You and Desert Ant Labs regarding the Licensed Materials and supersedes all prior agreements on the same subject matter.
|
|
129
|
+
|
|
130
|
+
(e) **Language.** The authoritative version of this license is in English. Any translation is for convenience only; in the event of any conflict, the English version controls.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
Commercial licensing inquiries: <licensing@desertant.ai>.
|
|
135
|
+
|
|
136
|
+
© 2026 Studio Company B.V., trading as Desert Ant Labs. Statutory seat: Amsterdam, the Netherlands. KvK: **81228112**.
|
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# @desert-ant-labs/shapes
|
|
2
|
+
|
|
3
|
+
On-device single-stroke shape recognition. Takes a hand-drawn stroke (a list of
|
|
4
|
+
`[x, y]` points) and returns a clean geometric shape — fully in-process, no
|
|
5
|
+
inference runtime.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { recognize } from "@desert-ant-labs/shapes";
|
|
9
|
+
|
|
10
|
+
const shape = await recognize(points); // points: [number, number][]
|
|
11
|
+
// { type: "ellipse", center: [120, 90], semiMajor: 64, semiMinor: 40, rotation: 0.2 }
|
|
12
|
+
// or null if the stroke isn't a recognizable shape
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- Pure-JS inference (no ONNX/WASM runtime) — recognition is a few ms
|
|
18
|
+
- Recognizes `line`, `rectangle`, `triangle`, `ellipse`, and `star` (rejects scribbles)
|
|
19
|
+
- Fits clean vector geometry and snaps it to axes, circles, squares, and 15° rotations
|
|
20
|
+
- Model (~0.2 MB, 4-bit palettized) is fetched from the Hugging Face Hub at a **pinned revision**, then
|
|
21
|
+
cached — to the **filesystem** on Node and to **Cache Storage** in the browser, so
|
|
22
|
+
it loads once and runs offline after
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install @desert-ant-labs/shapes
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Importing
|
|
31
|
+
|
|
32
|
+
Pure ESM and fully tree-shakeable. The **same import works everywhere** — Node, bundlers,
|
|
33
|
+
browsers, and edge/worker runtimes — the right build is selected automatically:
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import { recognize } from "@desert-ant-labs/shapes";
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
CommonJS consumers use dynamic import (`const { recognize } = await import("@desert-ant-labs/shapes")`);
|
|
40
|
+
native `require()` works on Node ≥ 22.12.
|
|
41
|
+
|
|
42
|
+
**Bring-your-own-bytes.** If you load the model files yourself, import the hub-free core
|
|
43
|
+
from `@desert-ant-labs/shapes/core` — only the inference engine, with zero network/filesystem code:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { createShapes } from "@desert-ant-labs/shapes/core";
|
|
47
|
+
|
|
48
|
+
// weights is a Uint8Array (shapes.safetensors); meta is the parsed shapes_meta.json
|
|
49
|
+
const shapes = createShapes({ weights, meta });
|
|
50
|
+
shapes.recognize(points)?.type; // "triangle"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Loading model
|
|
54
|
+
|
|
55
|
+
Model files (`shapes.safetensors`, `shapes_meta.json`) are fetched from the Hugging Face Hub
|
|
56
|
+
([`desert-ant-labs/shapes`](https://huggingface.co/desert-ant-labs/shapes)) at a pinned
|
|
57
|
+
revision and cached.
|
|
58
|
+
|
|
59
|
+
- **Node**: `recognize()` works zero-config; files cache under `~/.cache/shapes`. To run
|
|
60
|
+
fully offline, ship the files yourself and point at a folder with `env.localModelPath`
|
|
61
|
+
(or `SHAPES_LOCAL_PATH`).
|
|
62
|
+
- **Browser**: same API; files cache in Cache Storage.
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { env, load, recognize } from "@desert-ant-labs/shapes";
|
|
66
|
+
|
|
67
|
+
env.revision = "main"; // or a commit SHA / tag
|
|
68
|
+
env.localModelPath = "./shapes-model"; // Node: use local files, skip the Hub
|
|
69
|
+
|
|
70
|
+
// or load an explicit instance (synchronous inference after it resolves)
|
|
71
|
+
const shapes = await load();
|
|
72
|
+
shapes.recognize(points)?.type;
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## API
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
export function recognize(points: Point[]): Promise<Shape | null>;
|
|
79
|
+
export function load(options?: Partial<ShapesEnv>): Promise<ShapesModel>;
|
|
80
|
+
export function createShapes(buffers: { weights; meta }): ShapesModel; // raw buffers
|
|
81
|
+
export function outline(shape: Shape, samples?: number): Point[]; // renderable polyline
|
|
82
|
+
export const env: ShapesEnv;
|
|
83
|
+
export function reset(): void; // clear the memoized model so the next recognize() re-reads env
|
|
84
|
+
|
|
85
|
+
export type Point = [number, number];
|
|
86
|
+
|
|
87
|
+
export type Shape =
|
|
88
|
+
| { type: "line"; from: Point; to: Point }
|
|
89
|
+
| { type: "rectangle"; corners: Point[] }
|
|
90
|
+
| { type: "triangle"; vertices: Point[] }
|
|
91
|
+
| { type: "ellipse"; center: Point; semiMajor: number; semiMinor: number; rotation: number }
|
|
92
|
+
| { type: "star"; center: Point; outerRadius: number; innerRadius: number; rotation: number; pointCount: number };
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`recognize(points)` returns the snapped shape, or `null` when the stroke is rejected
|
|
96
|
+
(not a shape) or degenerate. `ShapesModel.recognize` is synchronous once loaded.
|
|
97
|
+
|
|
98
|
+
## Example
|
|
99
|
+
|
|
100
|
+
[`Examples/ShapesExample`](Examples/ShapesExample) is a tldraw canvas demo: draw a shape,
|
|
101
|
+
pause for the preview, then lift to snap on-device.
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
cd Examples/ShapesExample
|
|
105
|
+
npm install
|
|
106
|
+
npm run dev
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Model
|
|
110
|
+
|
|
111
|
+
Published at [`desert-ant-labs/shapes`](https://huggingface.co/desert-ant-labs/shapes) on Hugging Face.
|
|
112
|
+
|
|
113
|
+
## License
|
|
114
|
+
|
|
115
|
+
See [`LICENSE.md`](LICENSE.md) — Desert Ant Labs Source-Available License v1.0. Free for commercial use up to 100,000 MAU per Model; <licensing@desertant.ai> above that.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { FileCache } from "./hub.js";
|
|
2
|
+
/** Filesystem-backed cache (Node): downloaded files persist across runs. */
|
|
3
|
+
export declare function fsCache(cacheDir: string): FileCache;
|
|
4
|
+
/** Reads model files from a local directory (for `localModelPath`). */
|
|
5
|
+
export declare function localReader(dir: string): (name: string) => Promise<Uint8Array | null>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
const keyToPath = (cacheDir, key) => join(cacheDir, key.replace(/^https?:\/\//, "").replace(/[^a-zA-Z0-9._/-]/g, "_"));
|
|
4
|
+
/** Filesystem-backed cache (Node): downloaded files persist across runs. */
|
|
5
|
+
export function fsCache(cacheDir) {
|
|
6
|
+
return {
|
|
7
|
+
async get(key) {
|
|
8
|
+
try {
|
|
9
|
+
return new Uint8Array(await readFile(keyToPath(cacheDir, key)));
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
async put(key, data) {
|
|
16
|
+
const path = keyToPath(cacheDir, key);
|
|
17
|
+
await mkdir(dirname(path), { recursive: true });
|
|
18
|
+
await writeFile(path, data);
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/** Reads model files from a local directory (for `localModelPath`). */
|
|
23
|
+
export function localReader(dir) {
|
|
24
|
+
return async (name) => {
|
|
25
|
+
try {
|
|
26
|
+
return new Uint8Array(await readFile(join(dir, name)));
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Cache Storage-backed cache (browser): downloaded files persist across visits. */
|
|
2
|
+
export function webCache(name = "shapes-model") {
|
|
3
|
+
return {
|
|
4
|
+
async get(key) {
|
|
5
|
+
try {
|
|
6
|
+
const cache = await caches.open(name);
|
|
7
|
+
const res = await cache.match(key);
|
|
8
|
+
return res ? new Uint8Array(await res.arrayBuffer()) : null;
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
async put(key, data) {
|
|
15
|
+
try {
|
|
16
|
+
const cache = await caches.open(name);
|
|
17
|
+
await cache.put(key, new Response(data));
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
/* caching is best-effort */
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
package/dist/fit.d.ts
ADDED