@mocanvas/wasm 1.0.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 +21 -0
- package/README.md +102 -0
- package/dist/index.d.ts +253 -0
- package/dist/index.js +370 -0
- package/dist/index.js.map +1 -0
- package/package.json +54 -0
- package/pkg/mocanvas-wasm-base64.d.ts +2 -0
- package/pkg/mocanvas-wasm-base64.js +3 -0
- package/pkg/mocanvas.d.ts +243 -0
- package/pkg/mocanvas.js +505 -0
- package/pkg/mocanvas_bg.wasm +0 -0
- package/pkg/mocanvas_bg.wasm.d.ts +42 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import init, { Engine, initSync, version } from '../pkg/mocanvas.js';
|
|
2
|
+
export { Engine } from '../pkg/mocanvas.js';
|
|
3
|
+
|
|
4
|
+
// src/index.ts
|
|
5
|
+
var OP = {
|
|
6
|
+
UPSERT_SHAPE: 1,
|
|
7
|
+
REMOVE_SHAPE: 2,
|
|
8
|
+
SET_GEOMETRY: 3,
|
|
9
|
+
SET_STYLE: 4,
|
|
10
|
+
CLEAR: 5,
|
|
11
|
+
SET_TEXTURE: 6
|
|
12
|
+
};
|
|
13
|
+
var PATH_OP = {
|
|
14
|
+
MOVE: 0,
|
|
15
|
+
LINE: 1,
|
|
16
|
+
QUAD: 2,
|
|
17
|
+
CUBIC: 3,
|
|
18
|
+
CLOSE: 4
|
|
19
|
+
};
|
|
20
|
+
var FLAG = {
|
|
21
|
+
HIDDEN: 1 << 0,
|
|
22
|
+
LOCKED: 1 << 1,
|
|
23
|
+
OVERLAY: 1 << 2,
|
|
24
|
+
NO_FILL: 1 << 3,
|
|
25
|
+
/** GPU-drawn and also reported to the DOM overlay (labels). */
|
|
26
|
+
LABEL: 1 << 4,
|
|
27
|
+
/** Descendants are clipped to this shape's page-space geometry AABB (frames). */
|
|
28
|
+
CLIP: 1 << 5
|
|
29
|
+
};
|
|
30
|
+
var HIT_FILTER = {
|
|
31
|
+
INCLUDE_LOCKED: 1,
|
|
32
|
+
INCLUDE_HIDDEN: 2,
|
|
33
|
+
HOLLOW_ONLY: 4
|
|
34
|
+
};
|
|
35
|
+
var VERTEX_FLOATS = 8;
|
|
36
|
+
var BATCH_WORDS = 7;
|
|
37
|
+
var OVERLAY_WORDS = 10;
|
|
38
|
+
var scratchF32 = new Float32Array(1);
|
|
39
|
+
var scratchU32 = new Uint32Array(scratchF32.buffer);
|
|
40
|
+
function f32bits(v) {
|
|
41
|
+
scratchF32[0] = v;
|
|
42
|
+
return scratchU32[0];
|
|
43
|
+
}
|
|
44
|
+
function bitsf32(v) {
|
|
45
|
+
scratchU32[0] = v;
|
|
46
|
+
return scratchF32[0];
|
|
47
|
+
}
|
|
48
|
+
function readClip(words, offset) {
|
|
49
|
+
const a = words[offset];
|
|
50
|
+
const b = words[offset + 1];
|
|
51
|
+
const c = words[offset + 2];
|
|
52
|
+
const d = words[offset + 3];
|
|
53
|
+
if ((a | b | c | d) === 0) return void 0;
|
|
54
|
+
return [bitsf32(a), bitsf32(b), bitsf32(c), bitsf32(d)];
|
|
55
|
+
}
|
|
56
|
+
var CommandWriter = class {
|
|
57
|
+
constructor(engine, memory, initialWords = 1 << 14) {
|
|
58
|
+
this.engine = engine;
|
|
59
|
+
this.memory = memory;
|
|
60
|
+
this.cap = initialWords;
|
|
61
|
+
const ptr = engine.cmd_ptr(this.cap);
|
|
62
|
+
this.view = new Uint32Array(memory.buffer, ptr, this.cap);
|
|
63
|
+
}
|
|
64
|
+
engine;
|
|
65
|
+
memory;
|
|
66
|
+
view;
|
|
67
|
+
cap;
|
|
68
|
+
len = 0;
|
|
69
|
+
/** Words queued but not yet applied. */
|
|
70
|
+
get pending() {
|
|
71
|
+
return this.len;
|
|
72
|
+
}
|
|
73
|
+
ensure(words) {
|
|
74
|
+
if (this.len + words <= this.cap && this.view.buffer === this.memory.buffer) return;
|
|
75
|
+
let cap = this.cap;
|
|
76
|
+
while (this.len + words > cap) cap *= 2;
|
|
77
|
+
this.cap = cap;
|
|
78
|
+
const ptr = this.engine.cmd_ptr(cap);
|
|
79
|
+
this.view = new Uint32Array(this.memory.buffer, ptr, cap);
|
|
80
|
+
}
|
|
81
|
+
upsert(handle, kind, parent, zlo, zhi, flags, x, y, rotation, w, h) {
|
|
82
|
+
this.ensure(12);
|
|
83
|
+
const v = this.view;
|
|
84
|
+
let i = this.len;
|
|
85
|
+
v[i++] = OP.UPSERT_SHAPE;
|
|
86
|
+
v[i++] = handle;
|
|
87
|
+
v[i++] = kind;
|
|
88
|
+
v[i++] = parent;
|
|
89
|
+
v[i++] = zlo;
|
|
90
|
+
v[i++] = zhi;
|
|
91
|
+
v[i++] = flags;
|
|
92
|
+
v[i++] = f32bits(x);
|
|
93
|
+
v[i++] = f32bits(y);
|
|
94
|
+
v[i++] = f32bits(rotation);
|
|
95
|
+
v[i++] = f32bits(w);
|
|
96
|
+
v[i++] = f32bits(h);
|
|
97
|
+
this.len = i;
|
|
98
|
+
}
|
|
99
|
+
remove(handle) {
|
|
100
|
+
this.ensure(2);
|
|
101
|
+
this.view[this.len++] = OP.REMOVE_SHAPE;
|
|
102
|
+
this.view[this.len++] = handle;
|
|
103
|
+
}
|
|
104
|
+
/** `pathWords` is the flat f32 path encoding (opcode, args...). */
|
|
105
|
+
setGeometry(handle, pathWords) {
|
|
106
|
+
const n = pathWords.length;
|
|
107
|
+
this.ensure(3 + n);
|
|
108
|
+
const v = this.view;
|
|
109
|
+
let i = this.len;
|
|
110
|
+
v[i++] = OP.SET_GEOMETRY;
|
|
111
|
+
v[i++] = handle;
|
|
112
|
+
v[i++] = n;
|
|
113
|
+
for (let k = 0; k < n; k++) v[i++] = f32bits(pathWords[k]);
|
|
114
|
+
this.len = i;
|
|
115
|
+
}
|
|
116
|
+
setStyle(handle, s) {
|
|
117
|
+
this.ensure(8);
|
|
118
|
+
const v = this.view;
|
|
119
|
+
let i = this.len;
|
|
120
|
+
v[i++] = OP.SET_STYLE;
|
|
121
|
+
v[i++] = handle;
|
|
122
|
+
v[i++] = s.fill >>> 0;
|
|
123
|
+
v[i++] = s.stroke >>> 0;
|
|
124
|
+
v[i++] = f32bits(s.strokeWidth);
|
|
125
|
+
v[i++] = s.dash >>> 0;
|
|
126
|
+
v[i++] = f32bits(s.opacity);
|
|
127
|
+
v[i++] = (s.seed ?? 0) >>> 0;
|
|
128
|
+
this.len = i;
|
|
129
|
+
}
|
|
130
|
+
/** Set the fill texture of a shape (0 = solid fill). Independent of `setStyle`. */
|
|
131
|
+
setTexture(handle, texture) {
|
|
132
|
+
this.ensure(3);
|
|
133
|
+
const v = this.view;
|
|
134
|
+
let i = this.len;
|
|
135
|
+
v[i++] = OP.SET_TEXTURE;
|
|
136
|
+
v[i++] = handle;
|
|
137
|
+
v[i++] = texture >>> 0;
|
|
138
|
+
this.len = i;
|
|
139
|
+
}
|
|
140
|
+
clear() {
|
|
141
|
+
this.ensure(1);
|
|
142
|
+
this.view[this.len++] = OP.CLEAR;
|
|
143
|
+
}
|
|
144
|
+
/** Apply queued commands. Returns the number of commands applied. Throws on a malformed stream. */
|
|
145
|
+
flush() {
|
|
146
|
+
if (this.len === 0) return 0;
|
|
147
|
+
const n = this.engine.apply(this.len);
|
|
148
|
+
this.len = 0;
|
|
149
|
+
const err = this.engine.take_error();
|
|
150
|
+
if (err) throw new Error(`mocanvas engine: ${err}`);
|
|
151
|
+
return n;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
var EngineBridge = class _EngineBridge {
|
|
155
|
+
constructor(engine, memory) {
|
|
156
|
+
this.engine = engine;
|
|
157
|
+
this.memory = memory;
|
|
158
|
+
this.cmd = new CommandWriter(engine, memory);
|
|
159
|
+
this.tessBudget = Engine.default_tess_budget();
|
|
160
|
+
}
|
|
161
|
+
engine;
|
|
162
|
+
memory;
|
|
163
|
+
cmd;
|
|
164
|
+
/**
|
|
165
|
+
* Shapes the engine may tessellate in one `frame()` call; the rest are drawn as
|
|
166
|
+
* level-of-detail quads and picked up by later frames, which keeps a viewport
|
|
167
|
+
* full of never-seen shapes from stalling on one frame. Read from the engine so
|
|
168
|
+
* `mocanvas_render::DEFAULT_TESS_BUDGET` stays the single source of truth.
|
|
169
|
+
*/
|
|
170
|
+
tessBudget;
|
|
171
|
+
lastFrame = null;
|
|
172
|
+
get shapeCount() {
|
|
173
|
+
return this.engine.shape_count();
|
|
174
|
+
}
|
|
175
|
+
get epoch() {
|
|
176
|
+
return this.engine.epoch();
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Build (or reuse) the frame for a camera. `tessBudget` overrides
|
|
180
|
+
* {@link EngineBridge.tessBudget} for this call; pass `0` for no cap, which is
|
|
181
|
+
* what tests want when they need one deterministic frame.
|
|
182
|
+
*
|
|
183
|
+
* When the engine reports the buffers unchanged the previous `FrameBuffers`
|
|
184
|
+
* object is returned as-is, views included, so `frame.version` is a stable
|
|
185
|
+
* identity a backend can compare against what it last uploaded.
|
|
186
|
+
*/
|
|
187
|
+
frame(cam, viewportW, viewportH, tessBudget = this.tessBudget) {
|
|
188
|
+
const e = this.engine;
|
|
189
|
+
e.frame(cam.x, cam.y, cam.z, viewportW, viewportH, tessBudget);
|
|
190
|
+
const buf = this.memory.buffer;
|
|
191
|
+
const version = e.frame_version();
|
|
192
|
+
const last = this.lastFrame;
|
|
193
|
+
if (last && !e.frame_dirty() && last.version === version && last.vertices.buffer === buf) {
|
|
194
|
+
last.dirty = false;
|
|
195
|
+
last.pending = e.frame_pending();
|
|
196
|
+
return last;
|
|
197
|
+
}
|
|
198
|
+
const frame = {
|
|
199
|
+
vertices: new Float32Array(buf, e.vertices_ptr(), e.vertices_len()),
|
|
200
|
+
indices: new Uint32Array(buf, e.indices_ptr(), e.indices_len()),
|
|
201
|
+
batches: new Uint32Array(buf, e.batches_ptr(), e.batches_len()),
|
|
202
|
+
overlay: new Uint32Array(buf, e.overlay_ptr(), e.overlay_len()),
|
|
203
|
+
drawn: e.drawn_count(),
|
|
204
|
+
culled: e.culled_count(),
|
|
205
|
+
version,
|
|
206
|
+
dirty: e.frame_dirty(),
|
|
207
|
+
pending: e.frame_pending()
|
|
208
|
+
};
|
|
209
|
+
this.lastFrame = frame;
|
|
210
|
+
return frame;
|
|
211
|
+
}
|
|
212
|
+
/** Decode the overlay buffer of a frame. */
|
|
213
|
+
static readOverlay(overlay) {
|
|
214
|
+
const out = [];
|
|
215
|
+
for (let i = 0; i + OVERLAY_WORDS <= overlay.length; i += OVERLAY_WORDS) {
|
|
216
|
+
const entry = {
|
|
217
|
+
handle: overlay[i],
|
|
218
|
+
x: bitsf32(overlay[i + 1]),
|
|
219
|
+
y: bitsf32(overlay[i + 2]),
|
|
220
|
+
w: bitsf32(overlay[i + 3]),
|
|
221
|
+
h: bitsf32(overlay[i + 4]),
|
|
222
|
+
rotation: bitsf32(overlay[i + 5])
|
|
223
|
+
};
|
|
224
|
+
const clip = readClip(overlay, i + 6);
|
|
225
|
+
if (clip) entry.clip = clip;
|
|
226
|
+
out.push(entry);
|
|
227
|
+
}
|
|
228
|
+
return out;
|
|
229
|
+
}
|
|
230
|
+
/** Decode one batch record starting at word `offset` (a multiple of `BATCH_WORDS`). */
|
|
231
|
+
static readBatch(batches, offset) {
|
|
232
|
+
const b = { firstIndex: batches[offset], indexCount: batches[offset + 1], texture: batches[offset + 2] };
|
|
233
|
+
const clip = readClip(batches, offset + 3);
|
|
234
|
+
if (clip) b.clip = clip;
|
|
235
|
+
return b;
|
|
236
|
+
}
|
|
237
|
+
/** Decode the batch buffer of a frame. */
|
|
238
|
+
static readBatches(batches) {
|
|
239
|
+
const out = [];
|
|
240
|
+
for (let i = 0; i + BATCH_WORDS <= batches.length; i += BATCH_WORDS) out.push(_EngineBridge.readBatch(batches, i));
|
|
241
|
+
return out;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Grow the box each frame is built for by `pad` (a fraction of the viewport size)
|
|
245
|
+
* on every side, so a camera panning inside that margin reuses the buffers instead
|
|
246
|
+
* of rebuilding and re-uploading them.
|
|
247
|
+
*
|
|
248
|
+
* Zero by default: the pad submits `(1 + 2 * pad)²` more geometry on every frame in
|
|
249
|
+
* exchange for skipping the upload on some of them, which only pays when the host's
|
|
250
|
+
* upload is expensive relative to its per-triangle cost. It is on a hardware GPU;
|
|
251
|
+
* it is emphatically not under software rasterisation.
|
|
252
|
+
*/
|
|
253
|
+
setViewportPad(pad) {
|
|
254
|
+
this.engine.set_viewport_pad(pad);
|
|
255
|
+
}
|
|
256
|
+
/** The current viewport pad. */
|
|
257
|
+
get viewportPad() {
|
|
258
|
+
return this.engine.viewport_pad();
|
|
259
|
+
}
|
|
260
|
+
hitTest(pageX, pageY, tolerance, filter = 0) {
|
|
261
|
+
return this.engine.hit_test(pageX, pageY, tolerance, filter);
|
|
262
|
+
}
|
|
263
|
+
/** Handles in draw order. `mode` 0 = intersects, 1 = contains. Returns a copy. */
|
|
264
|
+
queryBox(minX, minY, maxX, maxY, mode = 0, filter = 0) {
|
|
265
|
+
const n = this.engine.query_box(minX, minY, maxX, maxY, mode, filter);
|
|
266
|
+
return new Uint32Array(this.memory.buffer, this.engine.handles_ptr(), n).slice();
|
|
267
|
+
}
|
|
268
|
+
readBox() {
|
|
269
|
+
const f = new Float32Array(this.memory.buffer, this.engine.f32_ptr(), 4);
|
|
270
|
+
return [f[0], f[1], f[2], f[3]];
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Ink page bounds `[minX, minY, maxX, maxY]` or null: the shape's outline
|
|
274
|
+
* expanded by half its stroke width. This is what the spatial index, the
|
|
275
|
+
* viewport cull and clipping run on. For a user-facing measurement of where
|
|
276
|
+
* the shape *is*, use {@link geometryBounds}.
|
|
277
|
+
*/
|
|
278
|
+
bounds(handle) {
|
|
279
|
+
return this.engine.bounds(handle) ? this.readBox() : null;
|
|
280
|
+
}
|
|
281
|
+
/** Geometry page bounds `[minX, minY, maxX, maxY]` or null: `bounds` without the stroke pad. */
|
|
282
|
+
geometryBounds(handle) {
|
|
283
|
+
return this.engine.geometry_bounds(handle) ? this.readBox() : null;
|
|
284
|
+
}
|
|
285
|
+
unionBounds(handles) {
|
|
286
|
+
if (this.cmd.pending > 0) throw new Error("unionBounds called with unflushed commands");
|
|
287
|
+
const n = handles.length;
|
|
288
|
+
const ptr = this.engine.cmd_ptr(Math.max(n, 1));
|
|
289
|
+
new Uint32Array(this.memory.buffer, ptr, n).set(handles);
|
|
290
|
+
return this.engine.union_bounds(n) ? this.readBox() : null;
|
|
291
|
+
}
|
|
292
|
+
/** Union of every shape's ink bounds, or null when the scene is empty. */
|
|
293
|
+
allBounds() {
|
|
294
|
+
return this.engine.all_bounds() ? this.readBox() : null;
|
|
295
|
+
}
|
|
296
|
+
/** Union of every shape's geometry bounds, or null when the scene is empty. */
|
|
297
|
+
allGeometryBounds() {
|
|
298
|
+
return this.engine.all_geometry_bounds() ? this.readBox() : null;
|
|
299
|
+
}
|
|
300
|
+
/** Page transform `[a b c d e f]` or null. */
|
|
301
|
+
pageTransform(handle) {
|
|
302
|
+
if (!this.engine.page_transform(handle)) return null;
|
|
303
|
+
const f = new Float32Array(this.memory.buffer, this.engine.f32_ptr(), 6);
|
|
304
|
+
return [f[0], f[1], f[2], f[3], f[4], f[5]];
|
|
305
|
+
}
|
|
306
|
+
dispose() {
|
|
307
|
+
this.engine.free();
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
var initPromise = null;
|
|
311
|
+
var warnedEmbedded = false;
|
|
312
|
+
var WASM_MAGIC = [0, 97, 115, 109];
|
|
313
|
+
function isWasm(bytes) {
|
|
314
|
+
if (bytes.byteLength < WASM_MAGIC.length) return false;
|
|
315
|
+
const head = new Uint8Array(bytes, 0, WASM_MAGIC.length);
|
|
316
|
+
return WASM_MAGIC.every((b, i) => head[i] === b);
|
|
317
|
+
}
|
|
318
|
+
async function fetchWasm(url) {
|
|
319
|
+
try {
|
|
320
|
+
const res = await fetch(url);
|
|
321
|
+
if (!res.ok) return null;
|
|
322
|
+
const bytes = await res.arrayBuffer();
|
|
323
|
+
return isWasm(bytes) ? bytes : null;
|
|
324
|
+
} catch {
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
function base64ToBytes(b64) {
|
|
329
|
+
if (typeof atob === "function") {
|
|
330
|
+
const bin = atob(b64);
|
|
331
|
+
const out = new Uint8Array(bin.length);
|
|
332
|
+
for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
|
|
333
|
+
return out;
|
|
334
|
+
}
|
|
335
|
+
const buf = globalThis.Buffer;
|
|
336
|
+
if (!buf) throw new Error("mocanvas: no base64 decoder (`atob` or `Buffer`) in this runtime");
|
|
337
|
+
return new Uint8Array(buf.from(b64, "base64"));
|
|
338
|
+
}
|
|
339
|
+
async function loadDefault() {
|
|
340
|
+
const url = new URL("../pkg/mocanvas_bg.wasm", import.meta.url);
|
|
341
|
+
const fetched = await fetchWasm(url);
|
|
342
|
+
if (fetched) return (await init({ module_or_path: fetched })).memory;
|
|
343
|
+
if (!warnedEmbedded) {
|
|
344
|
+
warnedEmbedded = true;
|
|
345
|
+
console.warn(
|
|
346
|
+
`mocanvas: could not fetch the WebAssembly module from ${url.href} \u2014 it was not served as WebAssembly. Falling back to the copy embedded in the bundle; the canvas works, but that is a larger download than it needs to be. To take the URL instead, add optimizeDeps: { exclude: ["@mocanvas/wasm"] } to your Vite config.`
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
const { wasmBase64 } = await import('../pkg/mocanvas-wasm-base64.js');
|
|
350
|
+
return (await init({ module_or_path: base64ToBytes(wasmBase64) })).memory;
|
|
351
|
+
}
|
|
352
|
+
async function loadEngine(input) {
|
|
353
|
+
if (!initPromise) {
|
|
354
|
+
initPromise = input === void 0 ? loadDefault() : init({ module_or_path: input }).then((o) => o.memory);
|
|
355
|
+
}
|
|
356
|
+
const memory = await initPromise;
|
|
357
|
+
return new EngineBridge(new Engine(), memory);
|
|
358
|
+
}
|
|
359
|
+
function loadEngineSync(bytes) {
|
|
360
|
+
const out = initSync({ module: bytes });
|
|
361
|
+
initPromise = Promise.resolve(out.memory);
|
|
362
|
+
return new EngineBridge(new Engine(), out.memory);
|
|
363
|
+
}
|
|
364
|
+
function engineVersion() {
|
|
365
|
+
return version();
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export { BATCH_WORDS, CommandWriter, EngineBridge, FLAG, HIT_FILTER, OP, OVERLAY_WORDS, PATH_OP, VERTEX_FLOATS, bitsf32, engineVersion, f32bits, loadEngine, loadEngineSync, readClip };
|
|
369
|
+
//# sourceMappingURL=index.js.map
|
|
370
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["wasmVersion"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Typed loader and zero-copy bridge over the mocanvas WebAssembly engine.\n *\n * See docs/ARCHITECTURE.md → \"Bridge ABI\".\n */\nimport init, { Engine, initSync, version as wasmVersion, type InitInput, type SyncInitInput } from \"../pkg/mocanvas.js\"\n\nexport { Engine }\n\n/** Command opcodes; must match `crates/mocanvas-wasm/src/lib.rs::op`. */\nexport const OP = {\n UPSERT_SHAPE: 1,\n REMOVE_SHAPE: 2,\n SET_GEOMETRY: 3,\n SET_STYLE: 4,\n CLEAR: 5,\n SET_TEXTURE: 6,\n} as const\n\n/** Path opcodes; must match `mocanvas-geo::PathCmd`. */\nexport const PATH_OP = {\n MOVE: 0,\n LINE: 1,\n QUAD: 2,\n CUBIC: 3,\n CLOSE: 4,\n} as const\n\n/** Shape flags; must match `mocanvas-scene`. */\nexport const FLAG = {\n HIDDEN: 1 << 0,\n LOCKED: 1 << 1,\n OVERLAY: 1 << 2,\n NO_FILL: 1 << 3,\n /** GPU-drawn and also reported to the DOM overlay (labels). */\n LABEL: 1 << 4,\n /** Descendants are clipped to this shape's page-space geometry AABB (frames). */\n CLIP: 1 << 5,\n} as const\n\n/** Hit-test filter bits. */\nexport const HIT_FILTER = {\n INCLUDE_LOCKED: 1,\n INCLUDE_HIDDEN: 2,\n HOLLOW_ONLY: 4,\n} as const\n\nexport type Handle = number\n\nexport interface CameraState {\n /** Page-space offset. screen = (page + cam) * z */\n x: number\n y: number\n z: number\n}\n\n/** Floats per vertex in `FrameBuffers.vertices`: `x y u v r g b a`. */\nexport const VERTEX_FLOATS = 8\n/** `u32` words per record in `FrameBuffers.batches`. */\nexport const BATCH_WORDS = 7\n/** `u32` words per record in `FrameBuffers.overlay`. */\nexport const OVERLAY_WORDS = 10\n\n/** Page-space clip rectangle `[minX, minY, maxX, maxY]`. */\nexport type ClipRect = [number, number, number, number]\n\nexport interface FrameBuffers {\n /**\n * Interleaved `x y u v r g b a` (8 floats) in page space; solid geometry has\n * `u = v = 0`. View into WASM memory; valid until the next engine call.\n */\n vertices: Float32Array\n indices: Uint32Array\n /**\n * `BATCH_WORDS` (7) words per batch: `firstIndex indexCount texture clipMinX\n * clipMinY clipMaxX clipMaxY`. The clip words are f32 bits in page space; all\n * four zero means unclipped. Texture 0 = solid color. A new batch starts\n * whenever the texture or the clip rect changes — use `readBatch`.\n */\n batches: Uint32Array\n /**\n * `OVERLAY_WORDS` (10) words per entry: `handle x y w h rot clipMinX clipMinY\n * clipMaxX clipMaxY` with floats as bits — use `readOverlay`.\n */\n overlay: Uint32Array\n drawn: number\n culled: number\n /**\n * Build counter, bumped only when the buffers are rebuilt. The vertex data is\n * page-space and the camera is a shader uniform, so a moving camera alone does\n * not change it: a backend that has already uploaded version `v` can skip the\n * upload for as long as this reads `v`.\n */\n version: number\n /** Whether the call that produced this frame rebuilt the buffers. */\n dirty: boolean\n /**\n * Shapes were deferred by the per-frame tessellation budget and are drawn as\n * flat placeholder quads meanwhile. Keep scheduling frames until this is false.\n */\n pending: boolean\n}\n\nexport interface Batch {\n firstIndex: number\n indexCount: number\n /** Host texture id, 0 = solid color. */\n texture: number\n /** Page-space clip rect, or undefined when unclipped. */\n clip?: ClipRect\n}\n\nexport interface OverlayEntry {\n handle: Handle\n x: number\n y: number\n w: number\n h: number\n rotation: number\n /** Page-space clip rect inherited from the nearest clipping ancestor, if any. */\n clip?: ClipRect\n}\n\nexport interface StyleWords {\n /** 0xRRGGBBAA, alpha 0 = none */\n fill: number\n stroke: number\n strokeWidth: number\n dash: number\n opacity: number\n /**\n * Host texture id (0 or undefined = none). Not part of SET_STYLE; send it with\n * `CommandWriter.setTexture`. When set, the fill is drawn as one textured quad\n * over the shape's local bounds (uv 0..1), tinted white × opacity.\n */\n texture?: number\n /**\n * Per-shape random seed (0 or undefined = 0). Only `dash: 3` (hand-drawn) reads\n * it: it picks that shape's wobble, so the same seed always redraws the same\n * outline. Derive it from the shape's stable id, never from its handle or its\n * position in the scene, or a shape will change shape when it is re-added.\n */\n seed?: number\n}\n\nconst scratchF32 = new Float32Array(1)\nconst scratchU32 = new Uint32Array(scratchF32.buffer)\n\n/** Bit-cast a float to u32 without allocation. */\nexport function f32bits(v: number): number {\n scratchF32[0] = v\n return scratchU32[0]!\n}\n\n/** Bit-cast a u32 to float without allocation. */\nexport function bitsf32(v: number): number {\n scratchU32[0] = v\n return scratchF32[0]!\n}\n\n/** Four clip words (f32 bits) at `offset` → rect, or undefined when all zero (unclipped). */\nexport function readClip(words: Uint32Array, offset: number): ClipRect | undefined {\n const a = words[offset]!\n const b = words[offset + 1]!\n const c = words[offset + 2]!\n const d = words[offset + 3]!\n if ((a | b | c | d) === 0) return undefined\n return [bitsf32(a), bitsf32(b), bitsf32(c), bitsf32(d)]\n}\n\n/**\n * Writes commands straight into the engine's command buffer in WASM memory.\n * Call `flush()` once per store transaction.\n */\nexport class CommandWriter {\n private view: Uint32Array\n private cap: number\n private len = 0\n\n constructor(\n private readonly engine: Engine,\n private readonly memory: WebAssembly.Memory,\n initialWords = 1 << 14,\n ) {\n this.cap = initialWords\n const ptr = engine.cmd_ptr(this.cap)\n this.view = new Uint32Array(memory.buffer, ptr, this.cap)\n }\n\n /** Words queued but not yet applied. */\n get pending(): number {\n return this.len\n }\n\n private ensure(words: number): void {\n if (this.len + words <= this.cap && this.view.buffer === this.memory.buffer) return\n let cap = this.cap\n while (this.len + words > cap) cap *= 2\n this.cap = cap\n // The engine's Vec keeps existing content on resize; only the pointer may move.\n const ptr = this.engine.cmd_ptr(cap)\n this.view = new Uint32Array(this.memory.buffer, ptr, cap)\n }\n\n upsert(\n handle: Handle,\n kind: number,\n parent: Handle,\n zlo: number,\n zhi: number,\n flags: number,\n x: number,\n y: number,\n rotation: number,\n w: number,\n h: number,\n ): void {\n this.ensure(12)\n const v = this.view\n let i = this.len\n v[i++] = OP.UPSERT_SHAPE\n v[i++] = handle\n v[i++] = kind\n v[i++] = parent\n v[i++] = zlo\n v[i++] = zhi\n v[i++] = flags\n v[i++] = f32bits(x)\n v[i++] = f32bits(y)\n v[i++] = f32bits(rotation)\n v[i++] = f32bits(w)\n v[i++] = f32bits(h)\n this.len = i\n }\n\n remove(handle: Handle): void {\n this.ensure(2)\n this.view[this.len++] = OP.REMOVE_SHAPE\n this.view[this.len++] = handle\n }\n\n /** `pathWords` is the flat f32 path encoding (opcode, args...). */\n setGeometry(handle: Handle, pathWords: ArrayLike<number>): void {\n const n = pathWords.length\n this.ensure(3 + n)\n const v = this.view\n let i = this.len\n v[i++] = OP.SET_GEOMETRY\n v[i++] = handle\n v[i++] = n\n for (let k = 0; k < n; k++) v[i++] = f32bits(pathWords[k]!)\n this.len = i\n }\n\n setStyle(handle: Handle, s: StyleWords): void {\n this.ensure(8)\n const v = this.view\n let i = this.len\n v[i++] = OP.SET_STYLE\n v[i++] = handle\n v[i++] = s.fill >>> 0\n v[i++] = s.stroke >>> 0\n v[i++] = f32bits(s.strokeWidth)\n v[i++] = s.dash >>> 0\n v[i++] = f32bits(s.opacity)\n v[i++] = (s.seed ?? 0) >>> 0\n this.len = i\n }\n\n /** Set the fill texture of a shape (0 = solid fill). Independent of `setStyle`. */\n setTexture(handle: Handle, texture: number): void {\n this.ensure(3)\n const v = this.view\n let i = this.len\n v[i++] = OP.SET_TEXTURE\n v[i++] = handle\n v[i++] = texture >>> 0\n this.len = i\n }\n\n clear(): void {\n this.ensure(1)\n this.view[this.len++] = OP.CLEAR\n }\n\n /** Apply queued commands. Returns the number of commands applied. Throws on a malformed stream. */\n flush(): number {\n if (this.len === 0) return 0\n const n = this.engine.apply(this.len)\n this.len = 0\n const err = this.engine.take_error()\n if (err) throw new Error(`mocanvas engine: ${err}`)\n return n\n }\n}\n\n/** High-level wrapper: owns the engine, the command writer, and typed views. */\nexport class EngineBridge {\n readonly cmd: CommandWriter\n /**\n * Shapes the engine may tessellate in one `frame()` call; the rest are drawn as\n * level-of-detail quads and picked up by later frames, which keeps a viewport\n * full of never-seen shapes from stalling on one frame. Read from the engine so\n * `mocanvas_render::DEFAULT_TESS_BUDGET` stays the single source of truth.\n */\n tessBudget: number\n private lastFrame: FrameBuffers | null = null\n\n constructor(\n readonly engine: Engine,\n readonly memory: WebAssembly.Memory,\n ) {\n this.cmd = new CommandWriter(engine, memory)\n this.tessBudget = Engine.default_tess_budget()\n }\n\n get shapeCount(): number {\n return this.engine.shape_count()\n }\n\n get epoch(): number {\n return this.engine.epoch()\n }\n\n /**\n * Build (or reuse) the frame for a camera. `tessBudget` overrides\n * {@link EngineBridge.tessBudget} for this call; pass `0` for no cap, which is\n * what tests want when they need one deterministic frame.\n *\n * When the engine reports the buffers unchanged the previous `FrameBuffers`\n * object is returned as-is, views included, so `frame.version` is a stable\n * identity a backend can compare against what it last uploaded.\n */\n frame(cam: CameraState, viewportW: number, viewportH: number, tessBudget: number = this.tessBudget): FrameBuffers {\n const e = this.engine\n e.frame(cam.x, cam.y, cam.z, viewportW, viewportH, tessBudget)\n const buf = this.memory.buffer\n const version = e.frame_version()\n const last = this.lastFrame\n // Reuse the views when nothing was rebuilt — unless WASM memory grew, which\n // detaches every existing view over it.\n if (last && !e.frame_dirty() && last.version === version && last.vertices.buffer === buf) {\n last.dirty = false\n last.pending = e.frame_pending()\n return last\n }\n const frame: FrameBuffers = {\n vertices: new Float32Array(buf, e.vertices_ptr(), e.vertices_len()),\n indices: new Uint32Array(buf, e.indices_ptr(), e.indices_len()),\n batches: new Uint32Array(buf, e.batches_ptr(), e.batches_len()),\n overlay: new Uint32Array(buf, e.overlay_ptr(), e.overlay_len()),\n drawn: e.drawn_count(),\n culled: e.culled_count(),\n version,\n dirty: e.frame_dirty(),\n pending: e.frame_pending(),\n }\n this.lastFrame = frame\n return frame\n }\n\n /** Decode the overlay buffer of a frame. */\n static readOverlay(overlay: Uint32Array): OverlayEntry[] {\n const out: OverlayEntry[] = []\n for (let i = 0; i + OVERLAY_WORDS <= overlay.length; i += OVERLAY_WORDS) {\n const entry: OverlayEntry = {\n handle: overlay[i]!,\n x: bitsf32(overlay[i + 1]!),\n y: bitsf32(overlay[i + 2]!),\n w: bitsf32(overlay[i + 3]!),\n h: bitsf32(overlay[i + 4]!),\n rotation: bitsf32(overlay[i + 5]!),\n }\n const clip = readClip(overlay, i + 6)\n if (clip) entry.clip = clip\n out.push(entry)\n }\n return out\n }\n\n /** Decode one batch record starting at word `offset` (a multiple of `BATCH_WORDS`). */\n static readBatch(batches: Uint32Array, offset: number): Batch {\n const b: Batch = { firstIndex: batches[offset]!, indexCount: batches[offset + 1]!, texture: batches[offset + 2]! }\n const clip = readClip(batches, offset + 3)\n if (clip) b.clip = clip\n return b\n }\n\n /** Decode the batch buffer of a frame. */\n static readBatches(batches: Uint32Array): Batch[] {\n const out: Batch[] = []\n for (let i = 0; i + BATCH_WORDS <= batches.length; i += BATCH_WORDS) out.push(EngineBridge.readBatch(batches, i))\n return out\n }\n\n /**\n * Grow the box each frame is built for by `pad` (a fraction of the viewport size)\n * on every side, so a camera panning inside that margin reuses the buffers instead\n * of rebuilding and re-uploading them.\n *\n * Zero by default: the pad submits `(1 + 2 * pad)²` more geometry on every frame in\n * exchange for skipping the upload on some of them, which only pays when the host's\n * upload is expensive relative to its per-triangle cost. It is on a hardware GPU;\n * it is emphatically not under software rasterisation.\n */\n setViewportPad(pad: number): void {\n this.engine.set_viewport_pad(pad)\n }\n\n /** The current viewport pad. */\n get viewportPad(): number {\n return this.engine.viewport_pad()\n }\n\n hitTest(pageX: number, pageY: number, tolerance: number, filter = 0): Handle {\n return this.engine.hit_test(pageX, pageY, tolerance, filter)\n }\n\n /** Handles in draw order. `mode` 0 = intersects, 1 = contains. Returns a copy. */\n queryBox(minX: number, minY: number, maxX: number, maxY: number, mode: 0 | 1 = 0, filter = 0): Uint32Array {\n const n = this.engine.query_box(minX, minY, maxX, maxY, mode, filter)\n return new Uint32Array(this.memory.buffer, this.engine.handles_ptr(), n).slice()\n }\n\n private readBox(): [number, number, number, number] {\n const f = new Float32Array(this.memory.buffer, this.engine.f32_ptr(), 4)\n return [f[0]!, f[1]!, f[2]!, f[3]!]\n }\n\n /**\n * Ink page bounds `[minX, minY, maxX, maxY]` or null: the shape's outline\n * expanded by half its stroke width. This is what the spatial index, the\n * viewport cull and clipping run on. For a user-facing measurement of where\n * the shape *is*, use {@link geometryBounds}.\n */\n bounds(handle: Handle): [number, number, number, number] | null {\n return this.engine.bounds(handle) ? this.readBox() : null\n }\n\n /** Geometry page bounds `[minX, minY, maxX, maxY]` or null: `bounds` without the stroke pad. */\n geometryBounds(handle: Handle): [number, number, number, number] | null {\n return this.engine.geometry_bounds(handle) ? this.readBox() : null\n }\n\n unionBounds(handles: ArrayLike<number>): [number, number, number, number] | null {\n if (this.cmd.pending > 0) throw new Error(\"unionBounds called with unflushed commands\")\n const n = handles.length\n const ptr = this.engine.cmd_ptr(Math.max(n, 1))\n new Uint32Array(this.memory.buffer, ptr, n).set(handles)\n return this.engine.union_bounds(n) ? this.readBox() : null\n }\n\n /** Union of every shape's ink bounds, or null when the scene is empty. */\n allBounds(): [number, number, number, number] | null {\n return this.engine.all_bounds() ? this.readBox() : null\n }\n\n /** Union of every shape's geometry bounds, or null when the scene is empty. */\n allGeometryBounds(): [number, number, number, number] | null {\n return this.engine.all_geometry_bounds() ? this.readBox() : null\n }\n\n /** Page transform `[a b c d e f]` or null. */\n pageTransform(handle: Handle): [number, number, number, number, number, number] | null {\n if (!this.engine.page_transform(handle)) return null\n const f = new Float32Array(this.memory.buffer, this.engine.f32_ptr(), 6)\n return [f[0]!, f[1]!, f[2]!, f[3]!, f[4]!, f[5]!]\n }\n\n dispose(): void {\n this.engine.free()\n }\n}\n\nlet initPromise: Promise<WebAssembly.Memory> | null = null\nlet warnedEmbedded = false\n\n/** `\\0asm` — the four bytes every WebAssembly module starts with. */\nconst WASM_MAGIC = [0x00, 0x61, 0x73, 0x6d]\n\nfunction isWasm(bytes: ArrayBuffer): boolean {\n if (bytes.byteLength < WASM_MAGIC.length) return false\n const head = new Uint8Array(bytes, 0, WASM_MAGIC.length)\n return WASM_MAGIC.every((b, i) => head[i] === b)\n}\n\n/**\n * Fetch the module URL ourselves and check it really is WebAssembly.\n *\n * A dev server that rewrites unknown paths to `index.html` (Vite's SPA\n * fallback, hit whenever the optimizer has moved this module and the relative\n * URL no longer points anywhere) answers with a `200` full of HTML. Handing\n * that to the glue raises `CompileError: expected magic word 00 61 73 6d,\n * found 3c 21 64 6f` from deep inside a vendored file. Returning `null` here\n * instead lets the caller reach for the embedded copy.\n */\nasync function fetchWasm(url: URL): Promise<ArrayBuffer | null> {\n try {\n const res = await fetch(url)\n if (!res.ok) return null\n const bytes = await res.arrayBuffer()\n return isWasm(bytes) ? bytes : null\n } catch {\n // No `fetch`, a `file:` URL (Node), CORS, an offline network: all the same\n // answer — we could not get the bytes from the URL.\n return null\n }\n}\n\nfunction base64ToBytes(b64: string): Uint8Array {\n if (typeof atob === \"function\") {\n const bin = atob(b64)\n const out = new Uint8Array(bin.length)\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i)\n return out\n }\n // Node without `atob` (or a runtime that only has `Buffer`).\n const buf = (globalThis as { Buffer?: { from(s: string, enc: string): Uint8Array } }).Buffer\n if (!buf) throw new Error(\"mocanvas: no base64 decoder (`atob` or `Buffer`) in this runtime\")\n return new Uint8Array(buf.from(b64, \"base64\"))\n}\n\n/**\n * The default load path: the URL first, the embedded copy as a safety net.\n *\n * The base64 module is generated at build time (see `scripts/prepare-pkg.mjs`)\n * and pulled in with a *dynamic* import, so every bundler gives it its own\n * chunk and the happy path never downloads it.\n */\nasync function loadDefault(): Promise<WebAssembly.Memory> {\n const url = new URL(\"../pkg/mocanvas_bg.wasm\", import.meta.url)\n const fetched = await fetchWasm(url)\n if (fetched) return (await init({ module_or_path: fetched })).memory\n\n if (!warnedEmbedded) {\n warnedEmbedded = true\n console.warn(\n `mocanvas: could not fetch the WebAssembly module from ${url.href} — it was not served as WebAssembly. ` +\n \"Falling back to the copy embedded in the bundle; the canvas works, but that is a larger download than it needs to be. \" +\n 'To take the URL instead, add optimizeDeps: { exclude: [\"@mocanvas/wasm\"] } to your Vite config.',\n )\n }\n const { wasmBase64 } = await import(\"../pkg/mocanvas-wasm-base64.js\")\n return (await init({ module_or_path: base64ToBytes(wasmBase64) })).memory\n}\n\n/**\n * Load the WASM module (once) and create an engine.\n *\n * With no argument the module is resolved as\n * `new URL(\"../pkg/mocanvas_bg.wasm\", import.meta.url)` — which Vite, webpack 5\n * and Rollup all recognise: they emit the `.wasm` file as an asset and rewrite\n * the URL — then fetched and checked for the WebAssembly magic number. If those\n * bytes are not a module (a dev server's HTML fallback, a 404 page, a JSON\n * error), an embedded base64 copy is used instead and a one-time warning is\n * logged. No consumer configuration is required either way.\n *\n * Passing an input takes over completely: `loadEngine(\"/assets/mocanvas_bg.wasm\")`,\n * a `URL`, a `Response`, the compiled bytes or a `WebAssembly.Module` are handed\n * to the glue as-is, with no validation and no fallback, so a mistake in the\n * location you chose surfaces as its own error. See the package README.\n */\nexport async function loadEngine(input?: InitInput): Promise<EngineBridge> {\n if (!initPromise) {\n initPromise = input === undefined ? loadDefault() : init({ module_or_path: input }).then((o) => o.memory)\n }\n const memory = await initPromise\n return new EngineBridge(new Engine(), memory)\n}\n\n/** Synchronous variant for tests / Node: pass the compiled bytes. */\nexport function loadEngineSync(bytes: SyncInitInput): EngineBridge {\n const out = initSync({ module: bytes })\n initPromise = Promise.resolve(out.memory)\n return new EngineBridge(new Engine(), out.memory)\n}\n\nexport function engineVersion(): string {\n return wasmVersion()\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mocanvas/wasm",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Typed loader and zero-copy bridge over the mocanvas Rust/WebAssembly engine.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Symbio Digital",
|
|
7
|
+
"homepage": "https://github.com/SYMBIO/mocanvas/tree/main/packages/wasm#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/SYMBIO/mocanvas.git",
|
|
11
|
+
"directory": "packages/wasm"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/SYMBIO/mocanvas/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"webassembly",
|
|
18
|
+
"wasm",
|
|
19
|
+
"rust",
|
|
20
|
+
"tessellation",
|
|
21
|
+
"geometry",
|
|
22
|
+
"hit-testing",
|
|
23
|
+
"mocanvas"
|
|
24
|
+
],
|
|
25
|
+
"type": "module",
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=20"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"pkg",
|
|
32
|
+
"README.md",
|
|
33
|
+
"LICENSE"
|
|
34
|
+
],
|
|
35
|
+
"sideEffects": false,
|
|
36
|
+
"main": "./dist/index.js",
|
|
37
|
+
"types": "./dist/index.d.ts",
|
|
38
|
+
"exports": {
|
|
39
|
+
".": {
|
|
40
|
+
"types": "./dist/index.d.ts",
|
|
41
|
+
"import": "./dist/index.js"
|
|
42
|
+
},
|
|
43
|
+
"./package.json": "./package.json"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "pnpm run build:wasm && node scripts/prepare-pkg.mjs && tsup",
|
|
50
|
+
"build:wasm": "wasm-pack build ../../crates/mocanvas-wasm --release --target web --out-dir ../../packages/wasm/pkg --out-name mocanvas",
|
|
51
|
+
"build:dev": "wasm-pack build ../../crates/mocanvas-wasm --dev --target web --out-dir ../../packages/wasm/pkg --out-name mocanvas && node scripts/prepare-pkg.mjs",
|
|
52
|
+
"typecheck": "tsc --noEmit"
|
|
53
|
+
}
|
|
54
|
+
}
|