@splinetool/viewer 2.0.8 → 2.0.10
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/build/hana-ui.js +122 -42
- package/build/hana-ui.wasm +0 -0
- package/build/snippets/hana-82e9eb82a79dead4/js-imports.js +204 -77
- package/build/spline-viewer.cjs +212 -212
- package/build/spline-viewer.js +212 -212
- package/build/spline-viewer.webgl.js +150 -150
- package/build/spline-viewer.webgpu.js +102 -102
- package/package.json +1 -1
package/build/hana-ui.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* @ts-self-types="./hana.d.ts" */
|
|
2
|
-
import { loadImageFromBytes, loadImageFromUrl, loadVideoFromBytes, loadVideoFromUrl } from './snippets/hana-82e9eb82a79dead4/js-imports.js';
|
|
2
|
+
import { disposeVideo, loadImageFromBytes, loadImageFromUrl, loadVideoFromBytes, loadVideoFromUrl, videoFrameToken } from './snippets/hana-82e9eb82a79dead4/js-imports.js';
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
export class DeviceLostPromise {
|
|
@@ -331,6 +331,22 @@ export class SceneController {
|
|
|
331
331
|
const ret = wasm.scenecontroller_centerVectorData(this.__wbg_ptr);
|
|
332
332
|
return takeObject(ret);
|
|
333
333
|
}
|
|
334
|
+
/**
|
|
335
|
+
* Drop the export-time frame override for one video asset (see
|
|
336
|
+
* `setVideoExportFrame`): the renderer resumes sampling its `<video>`
|
|
337
|
+
* element and `seekVideos` drives it again. The export loop's per-video
|
|
338
|
+
* fallback for a WebCodecs source that stopped delivering mid-export.
|
|
339
|
+
* @param {ID} id
|
|
340
|
+
*/
|
|
341
|
+
clearVideoExportFrame(id) {
|
|
342
|
+
wasm.scenecontroller_clearVideoExportFrame(this.__wbg_ptr, addHeapObject(id));
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Drop every export-time video frame override (see `setVideoExportFrame`).
|
|
346
|
+
*/
|
|
347
|
+
clearVideoExportFrames() {
|
|
348
|
+
wasm.scenecontroller_clearVideoExportFrames(this.__wbg_ptr);
|
|
349
|
+
}
|
|
334
350
|
/**
|
|
335
351
|
* @param {any} network
|
|
336
352
|
* @param {Float2} size
|
|
@@ -898,8 +914,11 @@ export class SceneController {
|
|
|
898
914
|
return takeObject(ret);
|
|
899
915
|
}
|
|
900
916
|
/**
|
|
917
|
+
* Resolves to whether any video seeked backward (wrapped across its
|
|
918
|
+
* loop point) — the export loop renders throwaway frames after a wrap
|
|
919
|
+
* to keep cold-path video→RGB conversion transients off captured frames.
|
|
901
920
|
* @param {number} dt
|
|
902
|
-
* @returns {Promise<
|
|
921
|
+
* @returns {Promise<boolean>}
|
|
903
922
|
*/
|
|
904
923
|
seekVideos(dt) {
|
|
905
924
|
const ret = wasm.scenecontroller_seekVideos(this.__wbg_ptr, dt);
|
|
@@ -983,6 +1002,20 @@ export class SceneController {
|
|
|
983
1002
|
setVectorTool(tool) {
|
|
984
1003
|
wasm.scenecontroller_setVectorTool(this.__wbg_ptr, addHeapObject(tool));
|
|
985
1004
|
}
|
|
1005
|
+
/**
|
|
1006
|
+
* Register an export-time frame override for a video asset: the renderer
|
|
1007
|
+
* uploads this WebCodecs frame instead of sampling the `<video>` element,
|
|
1008
|
+
* and `seekVideos` leaves the element alone. The caller keeps ownership
|
|
1009
|
+
* of the frame — it must stay unclosed until the override is replaced or
|
|
1010
|
+
* cleared, and `clearVideoExportFrames` must run before anything renders
|
|
1011
|
+
* outside the export loop. WebGPU backend only (`isWebgpu`); the WebGL
|
|
1012
|
+
* path still samples the element.
|
|
1013
|
+
* @param {ID} id
|
|
1014
|
+
* @param {VideoFrame} frame
|
|
1015
|
+
*/
|
|
1016
|
+
setVideoExportFrame(id, frame) {
|
|
1017
|
+
wasm.scenecontroller_setVideoExportFrame(this.__wbg_ptr, addHeapObject(id), addHeapObject(frame));
|
|
1018
|
+
}
|
|
986
1019
|
/**
|
|
987
1020
|
* Snap a world-space resize handle position against other (non-selected) vertices.
|
|
988
1021
|
* `snap_x`/`snap_y` indicate which axes may snap. Returns the snapped world position.
|
|
@@ -1191,6 +1224,27 @@ export class SceneController {
|
|
|
1191
1224
|
vectorStopContinueSubpath() {
|
|
1192
1225
|
wasm.scenecontroller_vectorStopContinueSubpath(this.__wbg_ptr);
|
|
1193
1226
|
}
|
|
1227
|
+
/**
|
|
1228
|
+
* The video fills the export loop should decode with WebCodecs, as
|
|
1229
|
+
* `{ id, src }` objects (`src` is the loaded `<video>` element's source:
|
|
1230
|
+
* the asset's own URL for streamed loads, a `blob:` URL for byte-loaded
|
|
1231
|
+
* ones — either way the same URL the element itself fetched). Enumerated from the start events' video actions — the exact set
|
|
1232
|
+
* `seekVideos` drives — so the WebCodecs path animates precisely the
|
|
1233
|
+
* fills the element path would: a fill without a play action stays a
|
|
1234
|
+
* static frame on both paths and both backends. Scoped to actions
|
|
1235
|
+
* targeting `frame_id`'s subtree on purpose: enumerating the whole
|
|
1236
|
+
* document put a live decoder behind every video in the file (74 in one
|
|
1237
|
+
* real doc), turning a 5s export into 74 decode streams. Videos still
|
|
1238
|
+
* loading are omitted, and videos outside the subtree stay on the
|
|
1239
|
+
* seek-driven element path — both remain correct, just less
|
|
1240
|
+
* stable/deterministic.
|
|
1241
|
+
* @param {ID} frame_id
|
|
1242
|
+
* @returns {Array<any>}
|
|
1243
|
+
*/
|
|
1244
|
+
videoFillSources(frame_id) {
|
|
1245
|
+
const ret = wasm.scenecontroller_videoFillSources(this.__wbg_ptr, addHeapObject(frame_id));
|
|
1246
|
+
return takeObject(ret);
|
|
1247
|
+
}
|
|
1194
1248
|
/**
|
|
1195
1249
|
* @param {Float2} pos
|
|
1196
1250
|
* @returns {Float2}
|
|
@@ -1764,6 +1818,17 @@ function __wbg_get_imports() {
|
|
|
1764
1818
|
__wbg_dispatchWorkgroups_afb2344298c62227: function(arg0, arg1, arg2, arg3) {
|
|
1765
1819
|
getObject(arg0).dispatchWorkgroups(arg1 >>> 0, arg2 >>> 0, arg3 >>> 0);
|
|
1766
1820
|
},
|
|
1821
|
+
__wbg_displayHeight_465673c1823a1db3: function(arg0) {
|
|
1822
|
+
const ret = getObject(arg0).displayHeight;
|
|
1823
|
+
return ret;
|
|
1824
|
+
},
|
|
1825
|
+
__wbg_displayWidth_73729fd8eb965076: function(arg0) {
|
|
1826
|
+
const ret = getObject(arg0).displayWidth;
|
|
1827
|
+
return ret;
|
|
1828
|
+
},
|
|
1829
|
+
__wbg_disposeVideo_c94c1ccd57a63f68: function(arg0) {
|
|
1830
|
+
disposeVideo(getObject(arg0));
|
|
1831
|
+
},
|
|
1767
1832
|
__wbg_document_aceb08cd6489baf5: function(arg0) {
|
|
1768
1833
|
const ret = getObject(arg0).document;
|
|
1769
1834
|
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
|
@@ -2410,7 +2475,7 @@ function __wbg_get_imports() {
|
|
|
2410
2475
|
const a = state0.a;
|
|
2411
2476
|
state0.a = 0;
|
|
2412
2477
|
try {
|
|
2413
|
-
return
|
|
2478
|
+
return __wasm_bindgen_func_elem_14186(a, state0.b, arg0, arg1);
|
|
2414
2479
|
} finally {
|
|
2415
2480
|
state0.a = a;
|
|
2416
2481
|
}
|
|
@@ -2456,7 +2521,7 @@ function __wbg_get_imports() {
|
|
|
2456
2521
|
const a = state0.a;
|
|
2457
2522
|
state0.a = 0;
|
|
2458
2523
|
try {
|
|
2459
|
-
return
|
|
2524
|
+
return __wasm_bindgen_func_elem_14186(a, state0.b, arg0, arg1);
|
|
2460
2525
|
} finally {
|
|
2461
2526
|
state0.a = a;
|
|
2462
2527
|
}
|
|
@@ -2583,6 +2648,10 @@ function __wbg_get_imports() {
|
|
|
2583
2648
|
__wbg_readPixels_d00c1cae608273d8: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) {
|
|
2584
2649
|
getObject(arg0).readPixels(arg1, arg2, arg3, arg4, arg5 >>> 0, arg6 >>> 0, arg7);
|
|
2585
2650
|
}, arguments); },
|
|
2651
|
+
__wbg_readyState_77b1b1db1b8c2a5f: function(arg0) {
|
|
2652
|
+
const ret = getObject(arg0).readyState;
|
|
2653
|
+
return ret;
|
|
2654
|
+
},
|
|
2586
2655
|
__wbg_reason_b02cd587d1a09948: function(arg0) {
|
|
2587
2656
|
const ret = getObject(arg0).reason;
|
|
2588
2657
|
return (__wbindgen_enum_GpuDeviceLostReason.indexOf(ret) + 1 || 3) - 1;
|
|
@@ -3313,6 +3382,13 @@ function __wbg_get_imports() {
|
|
|
3313
3382
|
const ret = getObject(arg0).size;
|
|
3314
3383
|
return ret;
|
|
3315
3384
|
},
|
|
3385
|
+
__wbg_src_f0e9281991fbd919: function(arg0, arg1) {
|
|
3386
|
+
const ret = getObject(arg1).src;
|
|
3387
|
+
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
3388
|
+
const len1 = WASM_VECTOR_LEN;
|
|
3389
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
|
3390
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
|
3391
|
+
},
|
|
3316
3392
|
__wbg_stack_3b0d974bbf31e44f: function(arg0, arg1) {
|
|
3317
3393
|
const ret = getObject(arg1).stack;
|
|
3318
3394
|
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
@@ -3531,6 +3607,10 @@ function __wbg_get_imports() {
|
|
|
3531
3607
|
__wbg_vertexAttribPointer_3bc50c0431082f73: function(arg0, arg1, arg2, arg3, arg4, arg5, arg6) {
|
|
3532
3608
|
getObject(arg0).vertexAttribPointer(arg1 >>> 0, arg2, arg3 >>> 0, arg4 !== 0, arg5, arg6);
|
|
3533
3609
|
},
|
|
3610
|
+
__wbg_videoFrameToken_6f05524e85fa2b75: function(arg0) {
|
|
3611
|
+
const ret = videoFrameToken(getObject(arg0));
|
|
3612
|
+
return ret;
|
|
3613
|
+
},
|
|
3534
3614
|
__wbg_videoHeight_e267fd1e74bb1b06: function(arg0) {
|
|
3535
3615
|
const ret = getObject(arg0).videoHeight;
|
|
3536
3616
|
return ret;
|
|
@@ -3556,48 +3636,48 @@ function __wbg_get_imports() {
|
|
|
3556
3636
|
getObject(arg0).writeTexture(getObject(arg1), getArrayU8FromWasm0(arg2, arg3), getObject(arg4), getObject(arg5));
|
|
3557
3637
|
}, arguments); },
|
|
3558
3638
|
__wbindgen_cast_0000000000000001: function(arg0, arg1) {
|
|
3559
|
-
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx:
|
|
3560
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
3639
|
+
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1054, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
|
3640
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_14184);
|
|
3561
3641
|
return addHeapObject(ret);
|
|
3562
3642
|
},
|
|
3563
3643
|
__wbindgen_cast_0000000000000002: function(arg0, arg1) {
|
|
3564
|
-
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx:
|
|
3565
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
3644
|
+
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 34, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
|
3645
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_5119);
|
|
3566
3646
|
return addHeapObject(ret);
|
|
3567
3647
|
},
|
|
3568
3648
|
__wbindgen_cast_0000000000000003: function(arg0, arg1) {
|
|
3569
|
-
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("GPUComputePipeline")], shim_idx:
|
|
3570
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
3649
|
+
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("GPUComputePipeline")], shim_idx: 929, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
|
3650
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_11140);
|
|
3571
3651
|
return addHeapObject(ret);
|
|
3572
3652
|
},
|
|
3573
3653
|
__wbindgen_cast_0000000000000004: function(arg0, arg1) {
|
|
3574
|
-
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("GPUDevice")], shim_idx:
|
|
3575
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
3654
|
+
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("GPUDevice")], shim_idx: 929, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
|
3655
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_11140_3);
|
|
3576
3656
|
return addHeapObject(ret);
|
|
3577
3657
|
},
|
|
3578
3658
|
__wbindgen_cast_0000000000000005: function(arg0, arg1) {
|
|
3579
|
-
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("GPUDeviceLostInfo")], shim_idx:
|
|
3580
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
3659
|
+
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("GPUDeviceLostInfo")], shim_idx: 930, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
|
3660
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_11141);
|
|
3581
3661
|
return addHeapObject(ret);
|
|
3582
3662
|
},
|
|
3583
3663
|
__wbindgen_cast_0000000000000006: function(arg0, arg1) {
|
|
3584
|
-
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("GPURenderPipeline")], shim_idx:
|
|
3585
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
3664
|
+
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("GPURenderPipeline")], shim_idx: 929, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
|
3665
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_11140_5);
|
|
3586
3666
|
return addHeapObject(ret);
|
|
3587
3667
|
},
|
|
3588
3668
|
__wbindgen_cast_0000000000000007: function(arg0, arg1) {
|
|
3589
|
-
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("any")], shim_idx:
|
|
3590
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
3669
|
+
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("any")], shim_idx: 929, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
|
3670
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_11140_6);
|
|
3591
3671
|
return addHeapObject(ret);
|
|
3592
3672
|
},
|
|
3593
3673
|
__wbindgen_cast_0000000000000008: function(arg0, arg1) {
|
|
3594
|
-
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("undefined")], shim_idx:
|
|
3595
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
3674
|
+
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("undefined")], shim_idx: 929, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
|
3675
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_11140_7);
|
|
3596
3676
|
return addHeapObject(ret);
|
|
3597
3677
|
},
|
|
3598
3678
|
__wbindgen_cast_0000000000000009: function(arg0, arg1) {
|
|
3599
|
-
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx:
|
|
3600
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
3679
|
+
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 1037, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
|
3680
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_12547);
|
|
3601
3681
|
return addHeapObject(ret);
|
|
3602
3682
|
},
|
|
3603
3683
|
__wbindgen_cast_000000000000000a: function(arg0) {
|
|
@@ -3671,22 +3751,22 @@ function __wbg_get_imports() {
|
|
|
3671
3751
|
};
|
|
3672
3752
|
}
|
|
3673
3753
|
|
|
3674
|
-
function
|
|
3675
|
-
wasm.
|
|
3754
|
+
function __wasm_bindgen_func_elem_12547(arg0, arg1) {
|
|
3755
|
+
wasm.__wasm_bindgen_func_elem_12547(arg0, arg1);
|
|
3676
3756
|
}
|
|
3677
3757
|
|
|
3678
|
-
function
|
|
3679
|
-
wasm.
|
|
3758
|
+
function __wasm_bindgen_func_elem_5119(arg0, arg1, arg2) {
|
|
3759
|
+
wasm.__wasm_bindgen_func_elem_5119(arg0, arg1, addHeapObject(arg2));
|
|
3680
3760
|
}
|
|
3681
3761
|
|
|
3682
|
-
function
|
|
3683
|
-
wasm.
|
|
3762
|
+
function __wasm_bindgen_func_elem_11141(arg0, arg1, arg2) {
|
|
3763
|
+
wasm.__wasm_bindgen_func_elem_11141(arg0, arg1, addHeapObject(arg2));
|
|
3684
3764
|
}
|
|
3685
3765
|
|
|
3686
|
-
function
|
|
3766
|
+
function __wasm_bindgen_func_elem_14184(arg0, arg1, arg2) {
|
|
3687
3767
|
try {
|
|
3688
3768
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
3689
|
-
wasm.
|
|
3769
|
+
wasm.__wasm_bindgen_func_elem_14184(retptr, arg0, arg1, addHeapObject(arg2));
|
|
3690
3770
|
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
3691
3771
|
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
3692
3772
|
if (r1) {
|
|
@@ -3697,10 +3777,10 @@ function __wasm_bindgen_func_elem_14110(arg0, arg1, arg2) {
|
|
|
3697
3777
|
}
|
|
3698
3778
|
}
|
|
3699
3779
|
|
|
3700
|
-
function
|
|
3780
|
+
function __wasm_bindgen_func_elem_11140(arg0, arg1, arg2) {
|
|
3701
3781
|
try {
|
|
3702
3782
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
3703
|
-
wasm.
|
|
3783
|
+
wasm.__wasm_bindgen_func_elem_11140(retptr, arg0, arg1, addHeapObject(arg2));
|
|
3704
3784
|
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
3705
3785
|
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
3706
3786
|
if (r1) {
|
|
@@ -3711,10 +3791,10 @@ function __wasm_bindgen_func_elem_11070(arg0, arg1, arg2) {
|
|
|
3711
3791
|
}
|
|
3712
3792
|
}
|
|
3713
3793
|
|
|
3714
|
-
function
|
|
3794
|
+
function __wasm_bindgen_func_elem_11140_3(arg0, arg1, arg2) {
|
|
3715
3795
|
try {
|
|
3716
3796
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
3717
|
-
wasm.
|
|
3797
|
+
wasm.__wasm_bindgen_func_elem_11140_3(retptr, arg0, arg1, addHeapObject(arg2));
|
|
3718
3798
|
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
3719
3799
|
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
3720
3800
|
if (r1) {
|
|
@@ -3725,10 +3805,10 @@ function __wasm_bindgen_func_elem_11070_3(arg0, arg1, arg2) {
|
|
|
3725
3805
|
}
|
|
3726
3806
|
}
|
|
3727
3807
|
|
|
3728
|
-
function
|
|
3808
|
+
function __wasm_bindgen_func_elem_11140_5(arg0, arg1, arg2) {
|
|
3729
3809
|
try {
|
|
3730
3810
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
3731
|
-
wasm.
|
|
3811
|
+
wasm.__wasm_bindgen_func_elem_11140_5(retptr, arg0, arg1, addHeapObject(arg2));
|
|
3732
3812
|
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
3733
3813
|
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
3734
3814
|
if (r1) {
|
|
@@ -3739,10 +3819,10 @@ function __wasm_bindgen_func_elem_11070_5(arg0, arg1, arg2) {
|
|
|
3739
3819
|
}
|
|
3740
3820
|
}
|
|
3741
3821
|
|
|
3742
|
-
function
|
|
3822
|
+
function __wasm_bindgen_func_elem_11140_6(arg0, arg1, arg2) {
|
|
3743
3823
|
try {
|
|
3744
3824
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
3745
|
-
wasm.
|
|
3825
|
+
wasm.__wasm_bindgen_func_elem_11140_6(retptr, arg0, arg1, addHeapObject(arg2));
|
|
3746
3826
|
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
3747
3827
|
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
3748
3828
|
if (r1) {
|
|
@@ -3753,10 +3833,10 @@ function __wasm_bindgen_func_elem_11070_6(arg0, arg1, arg2) {
|
|
|
3753
3833
|
}
|
|
3754
3834
|
}
|
|
3755
3835
|
|
|
3756
|
-
function
|
|
3836
|
+
function __wasm_bindgen_func_elem_11140_7(arg0, arg1, arg2) {
|
|
3757
3837
|
try {
|
|
3758
3838
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
3759
|
-
wasm.
|
|
3839
|
+
wasm.__wasm_bindgen_func_elem_11140_7(retptr, arg0, arg1, addHeapObject(arg2));
|
|
3760
3840
|
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
3761
3841
|
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
3762
3842
|
if (r1) {
|
|
@@ -3767,8 +3847,8 @@ function __wasm_bindgen_func_elem_11070_7(arg0, arg1, arg2) {
|
|
|
3767
3847
|
}
|
|
3768
3848
|
}
|
|
3769
3849
|
|
|
3770
|
-
function
|
|
3771
|
-
wasm.
|
|
3850
|
+
function __wasm_bindgen_func_elem_14186(arg0, arg1, arg2, arg3) {
|
|
3851
|
+
wasm.__wasm_bindgen_func_elem_14186(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
|
|
3772
3852
|
}
|
|
3773
3853
|
|
|
3774
3854
|
|
package/build/hana-ui.wasm
CHANGED
|
Binary file
|
|
@@ -1,93 +1,220 @@
|
|
|
1
|
-
|
|
2
1
|
export async function loadImageFromBytes(bytes) {
|
|
3
|
-
|
|
4
|
-
const url = URL.createObjectURL(blob)
|
|
5
|
-
return createImageBitmap(blob).finally(() => {
|
|
6
|
-
URL.revokeObjectURL(url)
|
|
7
|
-
})
|
|
2
|
+
return createImageBitmap(new Blob([bytes]))
|
|
8
3
|
}
|
|
9
4
|
|
|
10
5
|
export async function loadImageFromUrl(url) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
6
|
+
return fetch(url)
|
|
7
|
+
.then((response) => {
|
|
8
|
+
if (!response.ok) {
|
|
9
|
+
throw new Error(`Failed to fetch image: ${response.statusText}`)
|
|
10
|
+
}
|
|
11
|
+
return response.blob()
|
|
12
|
+
})
|
|
13
|
+
.then((blob) => createImageBitmap(blob))
|
|
19
14
|
}
|
|
20
15
|
|
|
21
16
|
// Video Imports
|
|
22
|
-
function setupVideo(video) {
|
|
23
|
-
video.preload = "auto";
|
|
24
|
-
video.autoplay = true; //iOs hack to show the first frame
|
|
25
|
-
video.loop = true;
|
|
26
|
-
video.muted = true;
|
|
27
|
-
video.playsInline = true;
|
|
28
|
-
video.currentTime = 0.01;
|
|
29
|
-
video.load();
|
|
30
|
-
|
|
31
|
-
video.onloadeddata = () => {
|
|
32
|
-
video.muted = true;
|
|
33
|
-
// DOMException: The play() request was interrupted by a new load request.
|
|
34
|
-
// https://developers.google.com/web/updates/2017/06/play-request-was-interrupted
|
|
35
|
-
const playPromise = video.play();
|
|
36
|
-
|
|
37
|
-
if (playPromise !== undefined) {
|
|
38
|
-
playPromise
|
|
39
|
-
.then((_) => {
|
|
40
|
-
// Automatic playback started! Do nothing all good!
|
|
41
|
-
})
|
|
42
|
-
.catch(() => {
|
|
43
|
-
// for some reason the video could not be played (The play() request was interrupted by a new load request.)
|
|
44
|
-
// so let's try to play it again
|
|
45
|
-
video.play();
|
|
46
|
-
}).finally(() => {
|
|
47
|
-
video.pause();
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
let copyVideo = false;
|
|
53
|
-
video.addEventListener("playing", function() {
|
|
54
|
-
copyVideo = true;
|
|
55
|
-
}, true);
|
|
56
|
-
|
|
57
|
-
return new Promise((resolve) => {
|
|
58
|
-
const checkVideo = () => {
|
|
59
|
-
if (copyVideo) {
|
|
60
|
-
resolve(video);
|
|
61
|
-
} else {
|
|
62
|
-
setTimeout(checkVideo, 10);
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
checkVideo();
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
17
|
|
|
18
|
+
let videoFrameSeq = 0
|
|
69
19
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
20
|
+
// Fallback tokens (see `videoFrameToken`) are the media clock offset per element
|
|
21
|
+
// by this stride, so two elements' ranges stay disjoint for any media under ~11.5 days.
|
|
22
|
+
const MEDIA_CLOCK_STRIDE = 1e6
|
|
23
|
+
|
|
24
|
+
// `HTMLMediaElement.HAVE_CURRENT_DATA` — a decoded frame the renderer can sample.
|
|
25
|
+
const HAVE_CURRENT_DATA = 2
|
|
26
|
+
|
|
27
|
+
// Generous, because a slow decode is not a failure — but bounded, because a source
|
|
28
|
+
// the browser silently declines must not wedge the load forever.
|
|
29
|
+
const VIDEO_READY_TIMEOUT_MS = 30000
|
|
30
|
+
|
|
31
|
+
// Maintains a token that changes exactly when the element presents a new frame,
|
|
32
|
+
// so the renderer can tell whether a GPU copy is needed at all.
|
|
33
|
+
//
|
|
34
|
+
// The callback chain re-arms itself and keeps `video` reachable until
|
|
35
|
+
// `disposeVideo` cancels it. It only fires on a presented frame, so a paused or
|
|
36
|
+
// stalled element costs nothing.
|
|
37
|
+
function trackPresentedFrames(video) {
|
|
38
|
+
if (typeof video.requestVideoFrameCallback !== 'function') {
|
|
39
|
+
// No presented-frame signal: `videoFrameToken` falls back to the media clock,
|
|
40
|
+
// offset per element to keep the guarantee below.
|
|
41
|
+
video.hanaClockBase = ++videoFrameSeq * MEDIA_CLOCK_STRIDE
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// One global sequence, so no two elements ever report the same token: when an
|
|
46
|
+
// asset is replaced, the token the renderer still holds for the displaced
|
|
47
|
+
// element cannot collide with the replacement's.
|
|
48
|
+
video.hanaPresentedFrames = ++videoFrameSeq
|
|
49
|
+
const bump = () => {
|
|
50
|
+
// Disposal detaches the source, which fires `seeked` on the way out.
|
|
51
|
+
if (video.hanaDisposed) return
|
|
52
|
+
video.hanaPresentedFrames = ++videoFrameSeq
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// A seek repaints a paused element without necessarily running the frame
|
|
56
|
+
// callback, and the video export seeks frame by frame with the element paused —
|
|
57
|
+
// it must never be handed the texture from the previous seek.
|
|
58
|
+
video.addEventListener('seeked', bump)
|
|
59
|
+
|
|
60
|
+
const onFrame = () => {
|
|
61
|
+
bump()
|
|
62
|
+
// Never re-arm a disposed element: that resurrects the cancelled chain.
|
|
63
|
+
if (video.hanaDisposed) return
|
|
64
|
+
video.hanaFrameCallback = video.requestVideoFrameCallback(onFrame)
|
|
65
|
+
}
|
|
66
|
+
video.hanaFrameCallback = video.requestVideoFrameCallback(onFrame)
|
|
75
67
|
}
|
|
76
68
|
|
|
69
|
+
// Read by the renderer once per frame per video. Where
|
|
70
|
+
// `requestVideoFrameCallback` is missing, falls back to the media clock: browsers
|
|
71
|
+
// advance `currentTime` at frame granularity, so it answers the same question. The
|
|
72
|
+
// per-element base keeps the cross-element guarantee across a reload, where
|
|
73
|
+
// `Assets::insert_video` replaces the element under the same id.
|
|
74
|
+
export function videoFrameToken(video) {
|
|
75
|
+
const presented = video.hanaPresentedFrames
|
|
76
|
+
return presented === undefined ? video.hanaClockBase + video.currentTime : presented
|
|
77
|
+
}
|
|
77
78
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
// Only for `Local(bytes)`, which has no URL to stream from. A blob: URL pins its
|
|
80
|
+
// Blob — the whole file — until revoked, so keep it on the element for
|
|
81
|
+
// `disposeVideo` to release.
|
|
82
|
+
function setVideoSourceFromBlob(video, blob) {
|
|
83
|
+
video.hanaObjectUrl = URL.createObjectURL(blob)
|
|
84
|
+
video.src = video.hanaObjectUrl
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Releases everything the element holds: the frame-callback chain, the blob: URL
|
|
88
|
+
// mapping, and the buffered media and decoder behind it. Runs from `OwnedVideo`'s
|
|
89
|
+
// `Drop` in `assets.rs`. Idempotent, and each step is independently conditional —
|
|
90
|
+
// an element loaded without a blob: URL still gets the rest of the teardown.
|
|
91
|
+
export function disposeVideo(video) {
|
|
92
|
+
if (video.hanaDisposed) return
|
|
93
|
+
// Set first: the steps below fire events that must not read as a live element.
|
|
94
|
+
video.hanaDisposed = true
|
|
95
|
+
|
|
96
|
+
const callback = video.hanaFrameCallback
|
|
97
|
+
if (callback !== undefined) {
|
|
98
|
+
video.hanaFrameCallback = undefined
|
|
99
|
+
// A throw here must not skip the rest of the teardown.
|
|
100
|
+
if (typeof video.cancelVideoFrameCallback === 'function') {
|
|
101
|
+
video.cancelVideoFrameCallback(callback)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const url = video.hanaObjectUrl
|
|
106
|
+
if (url !== undefined) {
|
|
107
|
+
video.hanaObjectUrl = undefined
|
|
108
|
+
URL.revokeObjectURL(url)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
video.pause()
|
|
112
|
+
// Revoking only drops the URL -> Blob mapping. Detaching the source is what
|
|
113
|
+
// actually releases the media the element has buffered and its decoder.
|
|
114
|
+
video.removeAttribute('src')
|
|
115
|
+
video.load()
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Resolves once the element holds a frame the renderer can sample, rejects if it
|
|
119
|
+
// never will. Every branch settles: an unsettled load holds its `PendingLoadGuard`,
|
|
120
|
+
// and headless hosts poll `Assets::pending_loads` to know a document is ready.
|
|
121
|
+
//
|
|
122
|
+
// Readiness is `loadeddata`, not `playing`: the video export drives the element
|
|
123
|
+
// paused, so `playing` never fires there, and a blocked autoplay is not a failure.
|
|
124
|
+
function whenSampleable(video) {
|
|
125
|
+
const mediaError = (prefix) => {
|
|
126
|
+
const err = video.error
|
|
127
|
+
return new Error(err === null ? prefix : `${prefix} (code ${err.code}: ${err.message})`)
|
|
128
|
+
}
|
|
129
|
+
// A rejected load never becomes an `OwnedVideo`, so nothing else releases the
|
|
130
|
+
// element: it would pin its blob: URL for the page lifetime and, if it buffers
|
|
131
|
+
// after a timeout, decode invisibly on loop (`autoplay` and `loop` stay set). The
|
|
132
|
+
// error is built first — `disposeVideo`'s `load()` clears `video.error`.
|
|
133
|
+
const failure = (prefix) => {
|
|
134
|
+
const err = mediaError(prefix)
|
|
135
|
+
disposeVideo(video)
|
|
136
|
+
return err
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (video.error !== null) return Promise.reject(failure('video failed to load'))
|
|
140
|
+
if (video.readyState >= HAVE_CURRENT_DATA) return Promise.resolve(video)
|
|
141
|
+
|
|
142
|
+
return new Promise((resolve, reject) => {
|
|
143
|
+
// Armed first so `settle` can clear it; nothing below runs this tick.
|
|
144
|
+
const timer = setTimeout(
|
|
145
|
+
() => settle(reject, failure('video timed out before presenting a frame')),
|
|
146
|
+
VIDEO_READY_TIMEOUT_MS,
|
|
147
|
+
)
|
|
148
|
+
const settle = (finish, value) => {
|
|
149
|
+
clearTimeout(timer)
|
|
150
|
+
video.removeEventListener('loadeddata', onReady)
|
|
151
|
+
video.removeEventListener('canplay', onReady)
|
|
152
|
+
video.removeEventListener('error', onError)
|
|
153
|
+
finish(value)
|
|
154
|
+
}
|
|
155
|
+
const onReady = () => settle(resolve, video)
|
|
156
|
+
const onError = () => settle(reject, failure('video failed to load'))
|
|
157
|
+
|
|
158
|
+
video.addEventListener('loadeddata', onReady)
|
|
159
|
+
// A partly-loaded source can become sampleable without a fresh `loadeddata`.
|
|
160
|
+
video.addEventListener('canplay', onReady)
|
|
161
|
+
video.addEventListener('error', onError)
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function setupVideo(video) {
|
|
166
|
+
video.preload = 'auto'
|
|
167
|
+
video.autoplay = true //iOs hack to show the first frame
|
|
168
|
+
video.loop = true
|
|
169
|
+
video.muted = true
|
|
170
|
+
video.playsInline = true
|
|
171
|
+
video.currentTime = 0.01
|
|
172
|
+
video.load()
|
|
173
|
+
|
|
174
|
+
video.onloadeddata = () => {
|
|
175
|
+
video.muted = true
|
|
176
|
+
// DOMException: The play() request was interrupted by a new load request.
|
|
177
|
+
// https://developers.google.com/web/updates/2017/06/play-request-was-interrupted
|
|
178
|
+
const playPromise = video.play()
|
|
179
|
+
|
|
180
|
+
if (playPromise !== undefined) {
|
|
181
|
+
playPromise
|
|
182
|
+
.then((_) => {
|
|
183
|
+
// Automatic playback started! Do nothing all good!
|
|
184
|
+
})
|
|
185
|
+
.catch(() => {
|
|
186
|
+
// for some reason the video could not be played (The play() request was interrupted by a new load request.)
|
|
187
|
+
// so let's try to play it again
|
|
188
|
+
video.play()
|
|
189
|
+
})
|
|
190
|
+
.finally(() => {
|
|
191
|
+
video.pause()
|
|
85
192
|
})
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
trackPresentedFrames(video)
|
|
197
|
+
|
|
198
|
+
return whenSampleable(video)
|
|
91
199
|
}
|
|
92
200
|
|
|
201
|
+
export async function loadVideoFromBytes(bytes) {
|
|
202
|
+
const video = document.createElement('video')
|
|
203
|
+
setVideoSourceFromBlob(video, new Blob([bytes]))
|
|
204
|
+
return setupVideo(video)
|
|
205
|
+
}
|
|
93
206
|
|
|
207
|
+
// Streams from `url` instead of fetching it into a Blob first, so the browser can
|
|
208
|
+
// range-request it, playback starts before the last byte lands, and the file never
|
|
209
|
+
// sits in memory whole.
|
|
210
|
+
//
|
|
211
|
+
// `crossOrigin` must be set before `src`: without it a cross-origin element is
|
|
212
|
+
// tainted and every texture upload throws a SecurityError. It costs no reach — the
|
|
213
|
+
// `fetch` this replaces was already a CORS request, so any URL that used to load
|
|
214
|
+
// still does.
|
|
215
|
+
export async function loadVideoFromUrl(url) {
|
|
216
|
+
const video = document.createElement('video')
|
|
217
|
+
video.crossOrigin = 'anonymous'
|
|
218
|
+
video.src = url
|
|
219
|
+
return setupVideo(video)
|
|
220
|
+
}
|