@myzonerocks/gosslens 0.10.1 → 0.11.1
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/README.md +31 -7
- package/dist/src/audio-output.d.ts +1 -1
- package/dist/src/audio-output.d.ts.map +1 -1
- package/dist/src/index.d.ts +30 -5
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +169 -48
- package/dist/src/index.js.map +1 -1
- package/dist/src/mic-input.d.ts +1 -1
- package/dist/src/mic-input.d.ts.map +1 -1
- package/dist/src/video-texture.d.ts +1 -1
- package/dist/src/video-texture.d.ts.map +1 -1
- package/dist/src/world.d.ts +1 -1
- package/dist/src/world.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/audio-output.ts +1 -1
- package/src/index.ts +177 -48
- package/src/mic-input.ts +1 -1
- package/src/video-texture.ts +1 -1
- package/src/world.ts +1 -1
package/dist/src/mic-input.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mic-input.d.ts","sourceRoot":"","sources":["../../src/mic-input.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"mic-input.d.ts","sourceRoot":"","sources":["../../src/mic-input.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAiB9C,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,IAAI,CAAiC;IAC7C,OAAO,CAAC,MAAM,CAA2C;IAEzD,YAAY,OAAO,EAAE,WAAW,EAE/B;IAKK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAuB3B;IAGK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAU1B;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"video-texture.d.ts","sourceRoot":"","sources":["../../src/video-texture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"video-texture.d.ts","sourceRoot":"","sources":["../../src/video-texture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAM9C,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,GAAG,CAAkC;IAC7C,OAAO,CAAC,OAAO,CAAS;IAExB,YAAY,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAU1D;IAIK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAK3B;IAKD,IAAI,IAAI,IAAI,CAYX;IAGD,IAAI,IAAI,IAAI,CAKX;CACF"}
|
package/dist/src/world.d.ts
CHANGED
package/dist/src/world.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"world.d.ts","sourceRoot":"","sources":["../../src/world.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAwC,MAAM,
|
|
1
|
+
{"version":3,"file":"world.d.ts","sourceRoot":"","sources":["../../src/world.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAwC,MAAM,YAAY,CAAC;AAIpF,UAAU,oBAAoB;IAC5B,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,UAAU,UAAU;IAClB,gBAAgB,EAAE,YAAY,CAAC;CAChC;AAED,UAAU,gBAAgB;IACxB,SAAS,EAAE,oBAAoB,CAAC;IAChC,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,UAAU,WAAW;IACnB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,UAAU,YAAY;IACpB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,UAAU,UAAU;IAClB,SAAS,EAAE,oBAAoB,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,aAAa,CAAC,cAAc,EAAE,OAAO,GAAG,gBAAgB,GAAG,IAAI,CAAC;IAChE,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,GAAG,UAAU,GAAG,IAAI,CAAC;IACpE,cAAc,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;IAClC,cAAc,CAAC,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC;CACpC;AAED,qBAAa,oBAAoB;IAKnB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJpC,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,SAAS,CAAmC;IACpD,OAAO,CAAC,MAAM,CAAK;IAEnB,YAA6B,OAAO,EAAE,WAAW,EAAI;IAIrD,OAAO,CAAC,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CA6ClF;IAED,OAAO,CAAC,KAAK;CAQd"}
|
package/package.json
CHANGED
package/src/audio-output.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -163,6 +163,28 @@ export interface GossPoseOut {
|
|
|
163
163
|
|
|
164
164
|
export const GOSS_HAND_LANDMARK_COUNT = 21;
|
|
165
165
|
export const GOSS_HAND_MAX = 2;
|
|
166
|
+
|
|
167
|
+
export const GOSS_CAP_TRACKING = 1 << 0;
|
|
168
|
+
export const GOSS_CAP_SEGMENTATION = 1 << 1;
|
|
169
|
+
export const GOSS_CAP_ML_INFER = 1 << 2;
|
|
170
|
+
export const GOSS_CAP_DIFFUSION = 1 << 3;
|
|
171
|
+
export const GOSS_CAP_BEAUTY = 1 << 4;
|
|
172
|
+
export const GOSS_CAP_PHYSICS = 1 << 5;
|
|
173
|
+
export const GOSS_CAP_VIDEO_TEXTURES = 1 << 6;
|
|
174
|
+
export const GOSS_CAP_PHOTO_CAPTURE = 1 << 7;
|
|
175
|
+
export const GOSS_CAP_RECORDING = 1 << 8;
|
|
176
|
+
export const GOSS_CAP_FILE_IO = 1 << 9;
|
|
177
|
+
|
|
178
|
+
/// A hand handed to submitHands: the tracker's presence, handedness, gesture,
|
|
179
|
+
/// and GOSS_HAND_LANDMARK_COUNT * 3 frame-pixel landmark floats. The shape
|
|
180
|
+
/// GossHandTracker.process returns plugs in directly.
|
|
181
|
+
export interface GossHandInput {
|
|
182
|
+
presence?: number;
|
|
183
|
+
handedness?: number;
|
|
184
|
+
gesture?: number;
|
|
185
|
+
gestureScore?: number;
|
|
186
|
+
landmarks: Float32Array | number[];
|
|
187
|
+
}
|
|
166
188
|
const HAND_RESULT_BYTES = 560;
|
|
167
189
|
const HAND_ONE_BYTES = 268;
|
|
168
190
|
|
|
@@ -371,6 +393,13 @@ export class Gosslens {
|
|
|
371
393
|
return this.version;
|
|
372
394
|
}
|
|
373
395
|
|
|
396
|
+
/// Which capabilities this build compiled real, as GOSS_CAP_* bits. A stub
|
|
397
|
+
/// build shares the full one's filename and abi version, so check the rail
|
|
398
|
+
/// you need here before feeding real bytes to an enable call.
|
|
399
|
+
capabilities(): number {
|
|
400
|
+
return this.mod.ccall("goss_capabilities", "number", [], []) as number;
|
|
401
|
+
}
|
|
402
|
+
|
|
374
403
|
/// Loads gosslens_web.js and checks its ABI major version. A
|
|
375
404
|
/// dynamic import, not static: bun's bundler would otherwise inline
|
|
376
405
|
/// this file, breaking Emscripten's own import.meta.url-relative
|
|
@@ -498,8 +527,12 @@ export class GossEngine {
|
|
|
498
527
|
// itself, via emscripten_webgl_create_context - passing
|
|
499
528
|
// webGLContextAttributes here has no effect regardless,
|
|
500
529
|
// preserveDrawingBuffer stays false. Worked around in capturePixels.
|
|
501
|
-
|
|
502
|
-
|
|
530
|
+
let rendererStatus: number;
|
|
531
|
+
try {
|
|
532
|
+
rendererStatus = await mod.ccall("goss_engine_init_renderer", "number", ["number", "number"], [this.handle, rendererDescPtr], { async: true });
|
|
533
|
+
} finally {
|
|
534
|
+
mod.ccall("goss_free", null, ["number", "number"], [rendererDescPtr, 12]);
|
|
535
|
+
}
|
|
503
536
|
if (rendererStatus !== GOSS_OK) throw new Error(`renderer init failed: ${rendererStatus}`);
|
|
504
537
|
|
|
505
538
|
// Emscripten's C++ side just created this canvas's own rendering
|
|
@@ -1103,7 +1136,8 @@ export class GossSession {
|
|
|
1103
1136
|
if (bytes > this.scratchCapacity) {
|
|
1104
1137
|
if (this.scratchPtr !== 0) this.mod.ccall("goss_free", null, ["number", "number"], [this.scratchPtr, this.scratchCapacity]);
|
|
1105
1138
|
this.scratchPtr = this.mod.ccall("goss_alloc", "number", ["number"], [bytes]) as number;
|
|
1106
|
-
this.scratchCapacity = bytes;
|
|
1139
|
+
this.scratchCapacity = this.scratchPtr === 0 ? 0 : bytes;
|
|
1140
|
+
if (this.scratchPtr === 0) throw new Error("wasm allocation failed");
|
|
1107
1141
|
}
|
|
1108
1142
|
return this.scratchPtr;
|
|
1109
1143
|
}
|
|
@@ -1264,7 +1298,7 @@ export class GossSession {
|
|
|
1264
1298
|
/// muxed recording track, unused by the web preview path.
|
|
1265
1299
|
submitAudio(samples: Float32Array, frameCount: number, sampleRate: number, channels: number, timestampUs: bigint = 0n): void {
|
|
1266
1300
|
const bytes = samples.length * 4;
|
|
1267
|
-
const ptr = this.
|
|
1301
|
+
const ptr = this.scratch(bytes);
|
|
1268
1302
|
this.mod.HEAPF32.set(samples, ptr >> 2);
|
|
1269
1303
|
this.mod.ccall(
|
|
1270
1304
|
"goss_session_submit_audio",
|
|
@@ -1272,18 +1306,15 @@ export class GossSession {
|
|
|
1272
1306
|
["number", "number", "number", "number", "number", "number"],
|
|
1273
1307
|
[this.handle, ptr, frameCount, sampleRate, channels, timestampUs],
|
|
1274
1308
|
);
|
|
1275
|
-
this.mod.ccall("goss_free", null, ["number", "number"], [ptr, bytes]);
|
|
1276
1309
|
}
|
|
1277
1310
|
|
|
1278
1311
|
/// Pulls the next block of mixed lens audio (frames interleaved s16) that
|
|
1279
1312
|
/// play_sound triggers produced, for the page to feed into WebAudio.
|
|
1280
1313
|
pullAudio(frames: number): Int16Array {
|
|
1281
1314
|
const byteLen = frames * 2;
|
|
1282
|
-
const ptr = this.
|
|
1315
|
+
const ptr = this.scratch(byteLen);
|
|
1283
1316
|
this.mod.ccall("goss_session_pull_audio", "number", ["number", "number", "number"], [this.handle, ptr, frames]);
|
|
1284
|
-
|
|
1285
|
-
this.mod.ccall("goss_free", null, ["number", "number"], [ptr, byteLen]);
|
|
1286
|
-
return out;
|
|
1317
|
+
return new Int16Array(this.mod.HEAP16.buffer, ptr, frames).slice();
|
|
1287
1318
|
}
|
|
1288
1319
|
|
|
1289
1320
|
/// Folds the active lens sound into the caller's outgoing call/live track:
|
|
@@ -1292,12 +1323,12 @@ export class GossSession {
|
|
|
1292
1323
|
/// mixed interleaved s16. Advances the mixer once, replacing `pullAudio`.
|
|
1293
1324
|
mixOutputAudio(mic: Float32Array | null, frameCount: number, sampleRate: number, channels: number): Int16Array {
|
|
1294
1325
|
const outLen = frameCount * channels;
|
|
1295
|
-
const outBytes = outLen * 2;
|
|
1296
|
-
const outPtr = this.mod.ccall("goss_alloc", "number", ["number"], [outBytes]);
|
|
1297
|
-
let micPtr = 0;
|
|
1326
|
+
const outBytes = (outLen * 2 + 3) & ~3;
|
|
1298
1327
|
const micBytes = mic ? mic.length * 4 : 0;
|
|
1328
|
+
const outPtr = this.scratch(outBytes + micBytes);
|
|
1329
|
+
let micPtr = 0;
|
|
1299
1330
|
if (mic) {
|
|
1300
|
-
micPtr =
|
|
1331
|
+
micPtr = outPtr + outBytes;
|
|
1301
1332
|
this.mod.HEAPF32.set(mic, micPtr >> 2);
|
|
1302
1333
|
}
|
|
1303
1334
|
this.mod.ccall(
|
|
@@ -1306,10 +1337,7 @@ export class GossSession {
|
|
|
1306
1337
|
["number", "number", "number", "number", "number", "number"],
|
|
1307
1338
|
[this.handle, micPtr, outPtr, frameCount, sampleRate, channels],
|
|
1308
1339
|
);
|
|
1309
|
-
|
|
1310
|
-
this.mod.ccall("goss_free", null, ["number", "number"], [outPtr, outBytes]);
|
|
1311
|
-
if (mic) this.mod.ccall("goss_free", null, ["number", "number"], [micPtr, micBytes]);
|
|
1312
|
-
return out;
|
|
1340
|
+
return new Int16Array(this.mod.HEAP16.buffer, outPtr, outLen).slice();
|
|
1313
1341
|
}
|
|
1314
1342
|
|
|
1315
1343
|
/// Stores validated camera-hardware intent; the engine normalizes it. Read it
|
|
@@ -1454,7 +1482,7 @@ export class GossSession {
|
|
|
1454
1482
|
/// Uploads one RGBA/BGRA frame into a named source (pixelFormat 3 BGRA, 4 RGBA).
|
|
1455
1483
|
submitSourceFrameRgba(name: string, rgba: Uint8Array, width: number, height: number, stride: number, pixelFormat: GossPixelFormat = GossPixelFormat.Rgba8): void {
|
|
1456
1484
|
const byteLen = stride * height;
|
|
1457
|
-
const rgbaPtr = this.
|
|
1485
|
+
const rgbaPtr = this.scratch(byteLen);
|
|
1458
1486
|
this.mod.HEAPU8.set(rgba.subarray(0, byteLen), rgbaPtr);
|
|
1459
1487
|
this.mod.setValue(this.frameDescPtr, width, "i32");
|
|
1460
1488
|
this.mod.setValue(this.frameDescPtr + 4, height, "i32");
|
|
@@ -1466,7 +1494,6 @@ export class GossSession {
|
|
|
1466
1494
|
this.mod.setValue(this.frameDescPtr + 28, 0, "i32");
|
|
1467
1495
|
this.withName(name, (ptr, len) =>
|
|
1468
1496
|
this.mod.ccall("goss_session_submit_source_frame_rgba_copy", "number", ["number", "number", "number", "number", "number", "number"], [this.handle, ptr, len, this.frameDescPtr, rgbaPtr, stride]));
|
|
1469
|
-
this.mod.ccall("goss_free", null, ["number", "number"], [rgbaPtr, byteLen]);
|
|
1470
1497
|
}
|
|
1471
1498
|
|
|
1472
1499
|
/// Arranges the camera and named sources: 0 custom, 1 side-by-side, 2 top-bottom, 3 pip, 4 grid.
|
|
@@ -1635,7 +1662,7 @@ export class GossSession {
|
|
|
1635
1662
|
this.mod.ccall("goss_session_brush_clear", "number", ["number"], [this.handle]);
|
|
1636
1663
|
}
|
|
1637
1664
|
|
|
1638
|
-
/// The brush preset the next stroke opens with: 0 pen, 1 highlighter, 2 marker, 3 neon.
|
|
1665
|
+
/// The brush preset the next stroke opens with: 0 pen, 1 highlighter, 2 marker, 3 neon, 4 stamp.
|
|
1639
1666
|
setBrushMode(mode: number): void {
|
|
1640
1667
|
this.mod.ccall("goss_session_brush_set_mode", "number", ["number", "number"], [this.handle, mode]);
|
|
1641
1668
|
}
|
|
@@ -1769,7 +1796,7 @@ export class GossSession {
|
|
|
1769
1796
|
}
|
|
1770
1797
|
const scaleX = this.frameWidth / sourceWidth;
|
|
1771
1798
|
const scaleY = this.frameHeight / sourceHeight;
|
|
1772
|
-
const pointCount = landmarks.length / 3;
|
|
1799
|
+
const pointCount = Math.min(landmarks.length / 3, GOSS_FACE_LANDMARK_COUNT);
|
|
1773
1800
|
const base = this.landmarksPtr >> 2;
|
|
1774
1801
|
for (let at = 0; at < pointCount; at += 1) {
|
|
1775
1802
|
this.mod.HEAPF32[base + at * 3] = landmarks[at * 3]! * scaleX;
|
|
@@ -1800,15 +1827,15 @@ export class GossSession {
|
|
|
1800
1827
|
const off = i * FACE_RESULT_BYTES;
|
|
1801
1828
|
const base = ptr + off;
|
|
1802
1829
|
const f = faces[i]!;
|
|
1803
|
-
const count = f.landmarks.length / 3;
|
|
1830
|
+
const count = Math.min(f.landmarks.length / 3, GOSS_FACE_LANDMARK_COUNT);
|
|
1804
1831
|
dv.setBigUint64(off, BigInt(f.frameSerial ?? 0), true);
|
|
1805
1832
|
dv.setBigInt64(off + 8, BigInt(f.timestampUs ?? 0), true);
|
|
1806
1833
|
dv.setFloat32(off + 16, f.presence ?? 1, true);
|
|
1807
1834
|
dv.setUint32(off + 20, count, true);
|
|
1808
|
-
this.mod.HEAPF32.set(f.landmarks, (base + 24) >> 2);
|
|
1835
|
+
this.mod.HEAPF32.set(f.landmarks.subarray(0, count * 3), (base + 24) >> 2);
|
|
1809
1836
|
const bsStart = (base + 24 + GOSS_FACE_LANDMARK_COUNT * 3 * 4) >> 2;
|
|
1810
1837
|
this.mod.HEAPF32.fill(0, bsStart, bsStart + GOSS_FACE_BLENDSHAPE_COUNT);
|
|
1811
|
-
if (f.blendshapes) this.mod.HEAPF32.set(f.blendshapes, bsStart);
|
|
1838
|
+
if (f.blendshapes) this.mod.HEAPF32.set(f.blendshapes.subarray(0, GOSS_FACE_BLENDSHAPE_COUNT), bsStart);
|
|
1812
1839
|
}
|
|
1813
1840
|
this.mod.ccall("goss_session_submit_faces", "number", ["number", "number", "number"], [this.handle, ptr, faces.length]);
|
|
1814
1841
|
}
|
|
@@ -1865,20 +1892,48 @@ export class GossSession {
|
|
|
1865
1892
|
const off = i * POSE_RESULT_BYTES;
|
|
1866
1893
|
const base = ptr + off;
|
|
1867
1894
|
const b = bodies[i]!;
|
|
1868
|
-
const count = b.landmarks.length / 3;
|
|
1895
|
+
const count = Math.min(b.landmarks.length / 3, GOSS_POSE_LANDMARK_COUNT);
|
|
1869
1896
|
dv.setBigUint64(off, BigInt(b.frameSerial ?? 0), true);
|
|
1870
1897
|
dv.setBigInt64(off + 8, BigInt(b.timestampUs ?? 0), true);
|
|
1871
1898
|
dv.setFloat32(off + 16, b.presence ?? 1, true);
|
|
1872
1899
|
dv.setUint32(off + 20, count, true);
|
|
1873
|
-
this.mod.HEAPF32.set(b.landmarks, (base + 24) >> 2);
|
|
1900
|
+
this.mod.HEAPF32.set(b.landmarks.subarray(0, count * 3), (base + 24) >> 2);
|
|
1874
1901
|
const visStart = (base + 24 + GOSS_POSE_LANDMARK_COUNT * 3 * 4) >> 2;
|
|
1875
1902
|
this.mod.HEAPF32.fill(0, visStart, visStart + GOSS_POSE_LANDMARK_COUNT * 2);
|
|
1876
|
-
if (b.visibilities) this.mod.HEAPF32.set(b.visibilities, visStart);
|
|
1877
|
-
if (b.presences) this.mod.HEAPF32.set(b.presences, visStart + GOSS_POSE_LANDMARK_COUNT);
|
|
1903
|
+
if (b.visibilities) this.mod.HEAPF32.set(b.visibilities.subarray(0, GOSS_POSE_LANDMARK_COUNT), visStart);
|
|
1904
|
+
if (b.presences) this.mod.HEAPF32.set(b.presences.subarray(0, GOSS_POSE_LANDMARK_COUNT), visStart + GOSS_POSE_LANDMARK_COUNT);
|
|
1878
1905
|
}
|
|
1879
1906
|
this.mod.ccall("goss_session_submit_bodies", "number", ["number", "number", "number"], [this.handle, ptr, bodies.length]);
|
|
1880
1907
|
}
|
|
1881
1908
|
|
|
1909
|
+
/// Submits the hands tracked this frame from the page's own tracker (the
|
|
1910
|
+
/// GossHandTracker's result plugs in directly), so hands.gesture and
|
|
1911
|
+
/// hands.pinch lenses and handJoint work with no in-engine worker; the
|
|
1912
|
+
/// submitted hands win over the worker while set. Null clears the path.
|
|
1913
|
+
submitHands(hands: { hands: GossHandInput[]; timestampUs?: bigint } | null): void {
|
|
1914
|
+
if (hands === null) {
|
|
1915
|
+
this.mod.ccall("goss_session_submit_hands", "number", ["number", "number"], [this.handle, 0]);
|
|
1916
|
+
return;
|
|
1917
|
+
}
|
|
1918
|
+
const ptr = this.scratch(HAND_RESULT_BYTES);
|
|
1919
|
+
this.mod.HEAPU8.fill(0, ptr, ptr + HAND_RESULT_BYTES);
|
|
1920
|
+
const dv = new DataView(this.mod.HEAPU8.buffer, ptr, HAND_RESULT_BYTES);
|
|
1921
|
+
dv.setBigInt64(8, hands.timestampUs ?? 0n, true);
|
|
1922
|
+
const list = hands.hands.slice(0, GOSS_HAND_MAX);
|
|
1923
|
+
dv.setUint32(16, list.length, true);
|
|
1924
|
+
for (let i = 0; i < list.length; i += 1) {
|
|
1925
|
+
const off = 24 + i * HAND_ONE_BYTES;
|
|
1926
|
+
const h = list[i]!;
|
|
1927
|
+
dv.setFloat32(off, h.presence ?? 1, true);
|
|
1928
|
+
dv.setFloat32(off + 4, h.handedness ?? 0.5, true);
|
|
1929
|
+
dv.setUint32(off + 8, h.gesture ?? 0, true);
|
|
1930
|
+
dv.setFloat32(off + 12, h.gestureScore ?? 0, true);
|
|
1931
|
+
const floats = Math.min(h.landmarks.length, GOSS_HAND_LANDMARK_COUNT * 3);
|
|
1932
|
+
for (let k = 0; k < floats; k += 1) dv.setFloat32(off + 16 + k * 4, h.landmarks[k]!, true);
|
|
1933
|
+
}
|
|
1934
|
+
this.mod.ccall("goss_session_submit_hands", "number", ["number", "number"], [this.handle, ptr]);
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1882
1937
|
/// Submits one frame's depth map from the host AR backend (WebXR depth-
|
|
1883
1938
|
/// sensing): width by height metres per pixel, row major, with the near and
|
|
1884
1939
|
/// far metres that bound it. An empty array clears it. Kept for depth
|
|
@@ -2039,6 +2094,75 @@ export class GossSession {
|
|
|
2039
2094
|
return result;
|
|
2040
2095
|
}
|
|
2041
2096
|
|
|
2097
|
+
/// Hands the engine one bundle asset's bytes under its manifest name ahead
|
|
2098
|
+
/// of activateLens, so a lens's models, references, and label files load
|
|
2099
|
+
/// from memory - the door the web's inference nodes activate through. An
|
|
2100
|
+
/// empty array removes a staged name; the engine keeps its own copy.
|
|
2101
|
+
provideLensAsset(name: string, bytes: Uint8Array): void {
|
|
2102
|
+
const id = new TextEncoder().encode(name);
|
|
2103
|
+
const idPtr = this.mod.ccall("goss_alloc", "number", ["number"], [id.length || 1]) as number;
|
|
2104
|
+
this.mod.HEAPU8.set(id, idPtr);
|
|
2105
|
+
let bytesPtr = 0;
|
|
2106
|
+
if (bytes.length > 0) {
|
|
2107
|
+
bytesPtr = this.mod.ccall("goss_alloc", "number", ["number"], [bytes.length]) as number;
|
|
2108
|
+
this.mod.HEAPU8.set(bytes, bytesPtr);
|
|
2109
|
+
}
|
|
2110
|
+
const args = ["number", "number", "number", "number", "number"];
|
|
2111
|
+
const status = this.mod.ccall("goss_session_provide_lens_asset", "number", args, [this.handle, idPtr, id.length, bytesPtr, bytes.length]) as number;
|
|
2112
|
+
if (bytesPtr !== 0) this.mod.ccall("goss_free", null, ["number", "number"], [bytesPtr, bytes.length]);
|
|
2113
|
+
this.mod.ccall("goss_free", null, ["number", "number"], [idPtr, id.length || 1]);
|
|
2114
|
+
if (status !== 0) throw new Error(`provideLensAsset failed (${status})`);
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
/// One ml.infer node's whole published output tensor, by the node's id and
|
|
2118
|
+
/// tensor index, or null before the model's first publish or when the node
|
|
2119
|
+
/// or tensor does not exist. A length probe sizes the read, so detections,
|
|
2120
|
+
/// embeddings, and logits come back at their own length.
|
|
2121
|
+
mlOutput(nodeId: string, tensor = 0): Float32Array | null {
|
|
2122
|
+
const id = new TextEncoder().encode(nodeId);
|
|
2123
|
+
const idPtr = this.mod.ccall("goss_alloc", "number", ["number"], [id.length || 1]) as number;
|
|
2124
|
+
this.mod.HEAPU8.set(id, idPtr);
|
|
2125
|
+
const lenPtr = this.mod.ccall("goss_alloc", "number", ["number"], [4]) as number;
|
|
2126
|
+
const readLen = () => new DataView(this.mod.HEAPU8.buffer, lenPtr, 4).getUint32(0, true);
|
|
2127
|
+
const args = ["number", "number", "number", "number", "number", "number", "number"];
|
|
2128
|
+
this.mod.ccall("goss_session_ml_output", "number", args, [this.handle, idPtr, id.length, tensor, 0, 0, lenPtr]);
|
|
2129
|
+
const needed = readLen();
|
|
2130
|
+
let result: Float32Array | null = null;
|
|
2131
|
+
if (needed > 0) {
|
|
2132
|
+
const outPtr = this.mod.ccall("goss_alloc", "number", ["number"], [needed * 4]) as number;
|
|
2133
|
+
const status = this.mod.ccall("goss_session_ml_output", "number", args, [this.handle, idPtr, id.length, tensor, outPtr, needed, lenPtr]) as number;
|
|
2134
|
+
if (status === 0) result = this.mod.HEAPF32.slice(outPtr >> 2, (outPtr >> 2) + needed);
|
|
2135
|
+
this.mod.ccall("goss_free", null, ["number", "number"], [outPtr, needed * 4]);
|
|
2136
|
+
}
|
|
2137
|
+
this.mod.ccall("goss_free", null, ["number", "number"], [lenPtr, 4]);
|
|
2138
|
+
this.mod.ccall("goss_free", null, ["number", "number"], [idPtr, id.length || 1]);
|
|
2139
|
+
return result;
|
|
2140
|
+
}
|
|
2141
|
+
|
|
2142
|
+
/// One ml.infer node's mask-bound output resampled to the fixed
|
|
2143
|
+
/// segmentation plane, or null when the node has no mask binding or the
|
|
2144
|
+
/// model has not published yet.
|
|
2145
|
+
mlMask(nodeId: string): Float32Array | null {
|
|
2146
|
+
const id = new TextEncoder().encode(nodeId);
|
|
2147
|
+
const idPtr = this.mod.ccall("goss_alloc", "number", ["number"], [id.length || 1]) as number;
|
|
2148
|
+
this.mod.HEAPU8.set(id, idPtr);
|
|
2149
|
+
const lenPtr = this.mod.ccall("goss_alloc", "number", ["number"], [4]) as number;
|
|
2150
|
+
const readLen = () => new DataView(this.mod.HEAPU8.buffer, lenPtr, 4).getUint32(0, true);
|
|
2151
|
+
const args = ["number", "number", "number", "number", "number", "number"];
|
|
2152
|
+
this.mod.ccall("goss_session_ml_mask", "number", args, [this.handle, idPtr, id.length, 0, 0, lenPtr]);
|
|
2153
|
+
const needed = readLen();
|
|
2154
|
+
let result: Float32Array | null = null;
|
|
2155
|
+
if (needed > 0) {
|
|
2156
|
+
const outPtr = this.mod.ccall("goss_alloc", "number", ["number"], [needed * 4]) as number;
|
|
2157
|
+
const status = this.mod.ccall("goss_session_ml_mask", "number", args, [this.handle, idPtr, id.length, outPtr, needed, lenPtr]) as number;
|
|
2158
|
+
if (status === 0) result = this.mod.HEAPF32.slice(outPtr >> 2, (outPtr >> 2) + needed);
|
|
2159
|
+
this.mod.ccall("goss_free", null, ["number", "number"], [outPtr, needed * 4]);
|
|
2160
|
+
}
|
|
2161
|
+
this.mod.ccall("goss_free", null, ["number", "number"], [lenPtr, 4]);
|
|
2162
|
+
this.mod.ccall("goss_free", null, ["number", "number"], [idPtr, id.length || 1]);
|
|
2163
|
+
return result;
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2042
2166
|
/// The recent diarized caption segment at index (0 the newest), or null when
|
|
2043
2167
|
/// the index is past the segments held: the times it spanned, the speaker who
|
|
2044
2168
|
/// spoke it, and its text, a speaker-tagged transcript for diarized subtitles.
|
|
@@ -2089,9 +2213,9 @@ export class GossSession {
|
|
|
2089
2213
|
/// Submits one NV12 exposure of an HDR bracket, fed to bracket-source
|
|
2090
2214
|
/// temporal.fuse nodes. y and uv are the plane bytes as submitFrameCopy takes.
|
|
2091
2215
|
submitFrameBracket(y: Uint8Array, yStride: number, uv: Uint8Array, uvStride: number, width: number, height: number, colorStandard = 1, colorRange = 0): void {
|
|
2092
|
-
const yPtr = this.
|
|
2216
|
+
const yPtr = this.scratch(y.length + uv.length);
|
|
2093
2217
|
this.mod.HEAPU8.set(y, yPtr);
|
|
2094
|
-
const uvPtr =
|
|
2218
|
+
const uvPtr = yPtr + y.length;
|
|
2095
2219
|
this.mod.HEAPU8.set(uv, uvPtr);
|
|
2096
2220
|
this.mod.setValue(this.frameDescPtr, width, "i32");
|
|
2097
2221
|
this.mod.setValue(this.frameDescPtr + 4, height, "i32");
|
|
@@ -2102,14 +2226,12 @@ export class GossSession {
|
|
|
2102
2226
|
this.mod.setValue(this.frameDescPtr + 24, 0, "i32");
|
|
2103
2227
|
this.mod.setValue(this.frameDescPtr + 28, 0, "i32");
|
|
2104
2228
|
this.mod.ccall("goss_session_submit_frame_bracket", "number", ["number", "number", "number", "number", "number", "number"], [this.handle, this.frameDescPtr, yPtr, yStride, uvPtr, uvStride]);
|
|
2105
|
-
this.mod.ccall("goss_free", null, ["number", "number"], [yPtr, y.length]);
|
|
2106
|
-
this.mod.ccall("goss_free", null, ["number", "number"], [uvPtr, uv.length]);
|
|
2107
2229
|
}
|
|
2108
2230
|
|
|
2109
2231
|
private submitPlanes(sym: string, y: Uint8Array, yStride: number, uv: Uint8Array, uvStride: number, width: number, height: number, colorStandard: number, colorRange: number): void {
|
|
2110
|
-
const yPtr = this.
|
|
2232
|
+
const yPtr = this.scratch(y.length + uv.length);
|
|
2111
2233
|
this.mod.HEAPU8.set(y, yPtr);
|
|
2112
|
-
const uvPtr =
|
|
2234
|
+
const uvPtr = yPtr + y.length;
|
|
2113
2235
|
this.mod.HEAPU8.set(uv, uvPtr);
|
|
2114
2236
|
this.mod.setValue(this.frameDescPtr, width, "i32");
|
|
2115
2237
|
this.mod.setValue(this.frameDescPtr + 4, height, "i32");
|
|
@@ -2120,8 +2242,6 @@ export class GossSession {
|
|
|
2120
2242
|
this.mod.setValue(this.frameDescPtr + 24, 0, "i32");
|
|
2121
2243
|
this.mod.setValue(this.frameDescPtr + 28, 0, "i32");
|
|
2122
2244
|
this.mod.ccall(sym, "number", ["number", "number", "number", "number", "number", "number"], [this.handle, this.frameDescPtr, yPtr, yStride, uvPtr, uvStride]);
|
|
2123
|
-
this.mod.ccall("goss_free", null, ["number", "number"], [yPtr, y.length]);
|
|
2124
|
-
this.mod.ccall("goss_free", null, ["number", "number"], [uvPtr, uv.length]);
|
|
2125
2245
|
}
|
|
2126
2246
|
|
|
2127
2247
|
/// Feeds one NV12 frame to the in-engine trackers only (no render), for a host
|
|
@@ -2500,7 +2620,8 @@ export class GossSession {
|
|
|
2500
2620
|
if (this.framePixelsCapacity >= byteLength) return;
|
|
2501
2621
|
if (this.framePixelsPtr !== 0) this.mod.ccall("goss_free", null, ["number", "number"], [this.framePixelsPtr, this.framePixelsCapacity]);
|
|
2502
2622
|
this.framePixelsPtr = this.mod.ccall("goss_alloc", "number", ["number"], [byteLength]);
|
|
2503
|
-
this.framePixelsCapacity = byteLength;
|
|
2623
|
+
this.framePixelsCapacity = this.framePixelsPtr === 0 ? 0 : byteLength;
|
|
2624
|
+
if (this.framePixelsPtr === 0) throw new Error("wasm allocation failed");
|
|
2504
2625
|
}
|
|
2505
2626
|
|
|
2506
2627
|
/// rotationDegrees omitted means the setVideoFlip state decides (a
|
|
@@ -2603,7 +2724,8 @@ export class GossSession {
|
|
|
2603
2724
|
if (this.worldScratchLen >= byteLength) return;
|
|
2604
2725
|
if (this.worldScratchPtr !== 0) this.mod.ccall("goss_free", null, ["number", "number"], [this.worldScratchPtr, this.worldScratchLen]);
|
|
2605
2726
|
this.worldScratchPtr = this.mod.ccall("goss_alloc", "number", ["number"], [byteLength]);
|
|
2606
|
-
this.worldScratchLen = byteLength;
|
|
2727
|
+
this.worldScratchLen = this.worldScratchPtr === 0 ? 0 : byteLength;
|
|
2728
|
+
if (this.worldScratchPtr === 0) throw new Error("wasm allocation failed");
|
|
2607
2729
|
}
|
|
2608
2730
|
|
|
2609
2731
|
/// Reports one finished frame: measured whole-pipeline time plus
|
|
@@ -2679,9 +2801,14 @@ export class GossPreviewSession {
|
|
|
2679
2801
|
static async create(canvas: HTMLCanvasElement, wasmJsUrl: string | URL, events: GossSessionEvents = {}): Promise<GossPreviewSession> {
|
|
2680
2802
|
const gosslens = await Gosslens.load(canvas, wasmJsUrl);
|
|
2681
2803
|
const engine = GossEngine.create(gosslens);
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2804
|
+
try {
|
|
2805
|
+
await engine.initRenderer(canvas);
|
|
2806
|
+
const session = GossSession.create(engine);
|
|
2807
|
+
return new GossPreviewSession(gosslens, engine, session, events);
|
|
2808
|
+
} catch (err) {
|
|
2809
|
+
engine.destroy();
|
|
2810
|
+
throw err;
|
|
2811
|
+
}
|
|
2685
2812
|
}
|
|
2686
2813
|
|
|
2687
2814
|
abiVersion(): number {
|
|
@@ -2810,8 +2937,10 @@ export class GossPreviewSession {
|
|
|
2810
2937
|
this.cameraFrames += 1;
|
|
2811
2938
|
const width = this.video.videoWidth;
|
|
2812
2939
|
const height = this.video.videoHeight;
|
|
2813
|
-
this.scratchCanvas.width
|
|
2814
|
-
|
|
2940
|
+
if (this.scratchCanvas.width !== width || this.scratchCanvas.height !== height) {
|
|
2941
|
+
this.scratchCanvas.width = width;
|
|
2942
|
+
this.scratchCanvas.height = height;
|
|
2943
|
+
}
|
|
2815
2944
|
this.scratchCtx.drawImage(this.video, 0, 0, width, height);
|
|
2816
2945
|
const pixels = this.scratchCtx.getImageData(0, 0, width, height);
|
|
2817
2946
|
// Not mirrored here - the demo page's own CSS mirrors the canvas
|
|
@@ -2852,8 +2981,8 @@ export class GossPreviewSession {
|
|
|
2852
2981
|
}
|
|
2853
2982
|
}
|
|
2854
2983
|
|
|
2855
|
-
export { GossWebXRWorldSource } from "./world";
|
|
2856
|
-
export type { GossXRFrameLike } from "./world";
|
|
2857
|
-
export { GossAudioOutput } from "./audio-output";
|
|
2858
|
-
export { GossMicInput } from "./mic-input";
|
|
2859
|
-
export { GossVideoTexture } from "./video-texture";
|
|
2984
|
+
export { GossWebXRWorldSource } from "./world.js";
|
|
2985
|
+
export type { GossXRFrameLike } from "./world.js";
|
|
2986
|
+
export { GossAudioOutput } from "./audio-output.js";
|
|
2987
|
+
export { GossMicInput } from "./mic-input.js";
|
|
2988
|
+
export { GossVideoTexture } from "./video-texture.js";
|
package/src/mic-input.ts
CHANGED
package/src/video-texture.ts
CHANGED
package/src/world.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// planes, and tracked anchors off each XR frame and feeds them into
|
|
3
3
|
/// the session. The page owns the XR session; this source only reads.
|
|
4
4
|
|
|
5
|
-
import type { GossSession, GossWorldPlane, GossWorldAnchorInput } from "./index";
|
|
5
|
+
import type { GossSession, GossWorldPlane, GossWorldAnchorInput } from "./index.js";
|
|
6
6
|
|
|
7
7
|
// WebXR's types live outside the DOM lib; the narrow slice this source
|
|
8
8
|
// reads is declared here so no type package enters the build.
|