@volter/editor-game 0.5.65
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 +661 -0
- package/NOTICE +23 -0
- package/contributions/asset-budget-asset.menu.ts +26 -0
- package/contributions/asset-budget.action.ts +18 -0
- package/contributions/asset-budget.document.tsx +21 -0
- package/contributions/asset-budget.menu.ts +22 -0
- package/contributions/audio-unlock.service.ts +17 -0
- package/contributions/audio.utility.tsx +15 -0
- package/contributions/autoplay.service.ts +48 -0
- package/contributions/bridge.command.ts +172 -0
- package/contributions/build-profiles.document.tsx +21 -0
- package/contributions/build-progress.status.tsx +45 -0
- package/contributions/build.action.ts +26 -0
- package/contributions/build.command.ts +27 -0
- package/contributions/build.header.tsx +37 -0
- package/contributions/build.menu.ts +31 -0
- package/contributions/build.service.ts +31 -0
- package/contributions/connection.status.tsx +43 -0
- package/contributions/coverage.service.ts +118 -0
- package/contributions/edit-mode-audio.service.ts +23 -0
- package/contributions/edit-mode-networking.service.ts +30 -0
- package/contributions/game-document.service.ts +25 -0
- package/contributions/game-eval.command.ts +210 -0
- package/contributions/game.layout.ts +19 -0
- package/contributions/gameplay.command.ts +255 -0
- package/contributions/generation.service.ts +96 -0
- package/contributions/generations.status.tsx +53 -0
- package/contributions/ingest.service.ts +80 -0
- package/contributions/instances.command.ts +75 -0
- package/contributions/navmesh.menu.ts +39 -0
- package/contributions/navmesh.service.ts +19 -0
- package/contributions/network.utility.tsx +17 -0
- package/contributions/play.command.ts +355 -0
- package/contributions/profiler.action.ts +16 -0
- package/contributions/profiler.menu.ts +22 -0
- package/contributions/profiler.utility.tsx +17 -0
- package/contributions/react/component-board.service.ts +21 -0
- package/contributions/react/design-time-mount.service.ts +60 -0
- package/contributions/react/pasteboard.action.ts +41 -0
- package/contributions/react/react-inspector.service.ts +85 -0
- package/contributions/react/story-documents.service.ts +44 -0
- package/contributions/scene-document.service.ts +32 -0
- package/contributions/state-watch.action.ts +17 -0
- package/contributions/state-watch.menu.ts +23 -0
- package/contributions/state-watch.utility.tsx +20 -0
- package/contributions/team-playtest.service.ts +124 -0
- package/contributions/three/camera-runtime.inspector.tsx +34 -0
- package/contributions/three/component-board.service.ts +24 -0
- package/contributions/three/component-verbs.command.ts +110 -0
- package/contributions/three/component-verbs.service.ts +92 -0
- package/contributions/three/constraints.inspector.tsx +34 -0
- package/contributions/three/model-asset-sections.service.ts +26 -0
- package/contributions/three/reflection-probe-capture.inspector.tsx +32 -0
- package/contributions/three/story-documents.service.ts +31 -0
- package/contributions/three/three-authoring.service.ts +66 -0
- package/contributions/transport.header.tsx +19 -0
- package/contributions/xstate-behavior.action.ts +42 -0
- package/contributions/xstate-behavior.document.tsx +73 -0
- package/contributions/xstate-behavior.inspector.tsx +28 -0
- package/contributions/xstate-behavior.menu.ts +23 -0
- package/package.json +144 -0
- package/src/asset-budget/AssetBudgetPanel.tsx +1172 -0
- package/src/asset-budget/asset-budget-model.ts +799 -0
- package/src/asset-budget/basis-encoder.ts +165 -0
- package/src/asset-budget/gltf-io.ts +154 -0
- package/src/asset-budget/gltf-optimize.ts +384 -0
- package/src/asset-budget/image-dims.ts +78 -0
- package/src/asset-budget/optimize-apply.ts +221 -0
- package/src/audio/AudioDebuggerPanel.tsx +457 -0
- package/src/audio/audio-debugger-model.ts +87 -0
- package/src/bridge/call.ts +60 -0
- package/src/bridge/dispatch.ts +459 -0
- package/src/bridge/live-frames.ts +25 -0
- package/src/bridge/screenshot.ts +316 -0
- package/src/build/BuildProfilesPanel.tsx +476 -0
- package/src/build/build-session.ts +247 -0
- package/src/build/format-bytes.ts +14 -0
- package/src/command-results.ts +36 -0
- package/src/coverage/live-authoring-surface.ts +30 -0
- package/src/coverage/live-project-verbs.ts +162 -0
- package/src/coverage/native-system-coverage.ts +143 -0
- package/src/coverage/root-coverage.ts +79 -0
- package/src/coverage/session-coverage.ts +193 -0
- package/src/design-system-stories/ApplicationChrome.stories.tsx +100 -0
- package/src/design-system-stories/InspectorNarrowBodies.stories.tsx +406 -0
- package/src/edit-mode/edit-mode-audio.ts +56 -0
- package/src/edit-mode/edit-mode-networking.ts +112 -0
- package/src/game-document/DevicePresetPicker.tsx +84 -0
- package/src/game-document/GameCaptureFrameButton.tsx +45 -0
- package/src/game-document/GameDocument.tsx +215 -0
- package/src/game-document/GamePanel.tsx +662 -0
- package/src/game-document/InstanceInspectorPicker.tsx +183 -0
- package/src/game-document/crowd-debug.ts +183 -0
- package/src/game-document/device-preview.ts +336 -0
- package/src/game-document/game-view-store.ts +107 -0
- package/src/game-document/physics-debug.ts +187 -0
- package/src/generation/GenerationActivity.tsx +421 -0
- package/src/generation/GenerationGallery.css +231 -0
- package/src/generation/generation-documents.tsx +338 -0
- package/src/generation/generation-jobs.ts +128 -0
- package/src/generation/generation-presentation.ts +257 -0
- package/src/host/adapter-reach.ts +445 -0
- package/src/host/adapter-runtime-bindings.ts +303 -0
- package/src/host/after-paint.ts +112 -0
- package/src/host/api/configurations.ts +66 -0
- package/src/host/authoring/babylon-authoring-adapter.ts +703 -0
- package/src/host/authoring/canvas-runtime-recognition.ts +50 -0
- package/src/host/authoring/contract-hierarchy-authoring.ts +144 -0
- package/src/host/authoring/contract-scenes-stories.ts +204 -0
- package/src/host/authoring/creation-site-related.ts +55 -0
- package/src/host/authoring/ephemeral-persistence.ts +29 -0
- package/src/host/authoring/gesture-persist.ts +84 -0
- package/src/host/authoring/ingest-data-writer.ts +232 -0
- package/src/host/authoring/ingest-source-persistence.ts +826 -0
- package/src/host/authoring/mount-isolated-pixi-screen.ts +250 -0
- package/src/host/authoring/mounted-authoring.ts +41 -0
- package/src/host/authoring/owned-pixi-ticker-listeners.ts +96 -0
- package/src/host/authoring/phaser-live-authoring-adapter.ts +265 -0
- package/src/host/authoring/pixi-authoring-adapter.ts +1554 -0
- package/src/host/authoring/pixi-creation-site-write-target.ts +60 -0
- package/src/host/authoring/pixi-isolation-assets.ts +25 -0
- package/src/host/authoring/pixi-live-write-target.ts +979 -0
- package/src/host/authoring/pixi-source-identity.ts +141 -0
- package/src/host/authoring/pixi-still-presentation.ts +71 -0
- package/src/host/authoring/pixi-structure-history.ts +237 -0
- package/src/host/authoring/pixi-transform-channels.ts +205 -0
- package/src/host/authoring/selection-remount-handoff.ts +23 -0
- package/src/host/authoring/source-persistence-backend.ts +373 -0
- package/src/host/authoring/source-refresh-revisions.ts +81 -0
- package/src/host/authoring/struct-write-pipe.ts +143 -0
- package/src/host/auto-frame-window.ts +89 -0
- package/src/host/binding-resolver.ts +393 -0
- package/src/host/browser-transpile.ts +631 -0
- package/src/host/canvas-entry-runtime.ts +95 -0
- package/src/host/components/CameraAuthoringOverlay.tsx +216 -0
- package/src/host/components/HeaderTelemetry.tsx +341 -0
- package/src/host/components/PixiIsolationSceneContent.tsx +280 -0
- package/src/host/components/ResolutionPicker.tsx +89 -0
- package/src/host/components/ThreeIsolationSceneContent.tsx +180 -0
- package/src/host/components/frame-debugger-model.ts +579 -0
- package/src/host/components/header-telemetry-model.ts +74 -0
- package/src/host/components/scene-document.tsx +447 -0
- package/src/host/components/utility-view-state.ts +87 -0
- package/src/host/components/world-root-stage-binding.tsx +133 -0
- package/src/host/components/world-root-stage.ts +1046 -0
- package/src/host/coverage/authoring-read-probe.ts +583 -0
- package/src/host/coverage/capability-coverage.ts +1587 -0
- package/src/host/coverage/coverage-accounting.ts +261 -0
- package/src/host/coverage/game-contract-seam-evidence.ts +82 -0
- package/src/host/coverage/project-verb-coverage.ts +148 -0
- package/src/host/coverage/system-adapter-coverage.ts +373 -0
- package/src/host/design-system-stories/StoryLayout.tsx +104 -0
- package/src/host/design-system-stories/fixtures/authoring.ts +247 -0
- package/src/host/design-system-stories/fixtures/editor-runtime.tsx +115 -0
- package/src/host/document-preview-three.ts +110 -0
- package/src/host/entry-adjudication.ts +89 -0
- package/src/host/game-location-guard.ts +150 -0
- package/src/host/game-module-access.ts +196 -0
- package/src/host/game-realm-page.ts +358 -0
- package/src/host/game-realm-reclaim.ts +55 -0
- package/src/host/game-realm-storage.ts +104 -0
- package/src/host/gameplay-export.ts +288 -0
- package/src/host/gameplay-recording.ts +717 -0
- package/src/host/gated-globals.ts +1511 -0
- package/src/host/history/json-history-resource.ts +254 -0
- package/src/host/ingest/registry.ts +261 -0
- package/src/host/instance-extract-actions.ts +120 -0
- package/src/host/instance-fork-actions.ts +120 -0
- package/src/host/play-control-hook.ts +26 -0
- package/src/host/playwright-shim.ts +479 -0
- package/src/host/projection/dom.ts +295 -0
- package/src/host/projection/pixi.ts +288 -0
- package/src/host/r3f-entry-runtime.ts +77 -0
- package/src/host/react-mount-runtime.ts +162 -0
- package/src/host/realm-services.ts +148 -0
- package/src/host/recording-preview.ts +106 -0
- package/src/host/roots/module-root.ts +203 -0
- package/src/host/roots/react-root.ts +181 -0
- package/src/host/same-realm-loop-gate.ts +544 -0
- package/src/host/scene-view-drawability.ts +69 -0
- package/src/host/sdk/tools.ts +31 -0
- package/src/host/served-bundle-runtime-modules.ts +331 -0
- package/src/host/server-log-bridge.ts +60 -0
- package/src/host/staged-projects.ts +24 -0
- package/src/host/stories/mounted-story-viewport-source.ts +64 -0
- package/src/host/stories/story-arg-descriptors.ts +50 -0
- package/src/host/stories/story-media-presence.ts +152 -0
- package/src/host/surface-content.ts +87 -0
- package/src/host/take-named-export.ts +23 -0
- package/src/host/three-ingest-runtime.ts +76 -0
- package/src/host/types-fastnoise-lite.d.ts +7 -0
- package/src/host/types-mikktspace.d.ts +20 -0
- package/src/host/types-troika-three-text.d.ts +7 -0
- package/src/host/use-active-performance-source.ts +53 -0
- package/src/host/viewport-pose-memory.ts +48 -0
- package/src/host/viewport-root-presentation.ts +40 -0
- package/src/ingest/active-ingest.ts +251 -0
- package/src/ingest/active-scene-navigation.ts +43 -0
- package/src/ingest/authoring/ingest-dom-surface-authoring.ts +191 -0
- package/src/ingest/authoring/ingest-root-adapter.ts +897 -0
- package/src/ingest/capture-wait-report.ts +122 -0
- package/src/ingest/deferred-ingest-play.ts +216 -0
- package/src/ingest/deferred-ingest-session.ts +23 -0
- package/src/ingest/discovery-public-ingest.ts +242 -0
- package/src/ingest/dom-stub-mark.ts +7 -0
- package/src/ingest/entry-load.ts +56 -0
- package/src/ingest/game-contract-realm.ts +34 -0
- package/src/ingest/game-pointer-lock.ts +89 -0
- package/src/ingest/held-scene-repaint.ts +73 -0
- package/src/ingest/host-surface-box.ts +174 -0
- package/src/ingest/ingest-boot-viewport.ts +54 -0
- package/src/ingest/ingest-canvas-scene-document.tsx +177 -0
- package/src/ingest/ingest-canvas-scene.ts +50 -0
- package/src/ingest/ingest-evidence-hook.ts +131 -0
- package/src/ingest/ingest-frame-snapshot.ts +183 -0
- package/src/ingest/ingest-play-commands.ts +134 -0
- package/src/ingest/ingest-play-control.ts +299 -0
- package/src/ingest/ingest-render-debug.ts +320 -0
- package/src/ingest/ingest-siblings.ts +487 -0
- package/src/ingest/ingest-status.ts +62 -0
- package/src/ingest/live-ingest-facet.ts +46 -0
- package/src/ingest/module-mode.ts +229 -0
- package/src/ingest/mount-canvas-ingest-root.ts +899 -0
- package/src/ingest/mount-coverage.ts +296 -0
- package/src/ingest/mount-dom-ingest-root.ts +282 -0
- package/src/ingest/mount-ingest-root.ts +744 -0
- package/src/ingest/mount-three-ingest-root.ts +366 -0
- package/src/ingest/resolve-canvas.ts +47 -0
- package/src/ingest/resolve-three.ts +123 -0
- package/src/ingest/served-bundle.ts +109 -0
- package/src/ingest/served-html-boot.ts +292 -0
- package/src/ingest/surface-canvas.ts +84 -0
- package/src/ingest/surface-dom.ts +84 -0
- package/src/ingest/surface-three.ts +128 -0
- package/src/ingest/types.ts +76 -0
- package/src/ingest/unmount-ingest-root.ts +224 -0
- package/src/navmesh/navmesh-actions.ts +27 -0
- package/src/navmesh/navmesh-handler.ts +237 -0
- package/src/navmesh/navmesh-workflow-store.ts +78 -0
- package/src/network/NetworkInspectorPanel.tsx +644 -0
- package/src/network/network-inspector-model.ts +225 -0
- package/src/play/play-boot-stall.ts +118 -0
- package/src/play/play-log-events.ts +26 -0
- package/src/play/play-mode.ts +2553 -0
- package/src/play/play-recording.ts +335 -0
- package/src/play/react-play-live-authoring.ts +165 -0
- package/src/play-bar/PlayBar.tsx +488 -0
- package/src/play-bar/PlayerCountPicker.tsx +100 -0
- package/src/profiler/FrameDebuggerPanel.tsx +458 -0
- package/src/profiler/PerformancePanel.tsx +1068 -0
- package/src/profiler/ProfilerPanel.tsx +53 -0
- package/src/profiler/frame-debugger-store.ts +97 -0
- package/src/profiler/main-thread-busy.ts +90 -0
- package/src/react/design-time-react-mount.ts +782 -0
- package/src/react/dom-authoring-adapter.ts +764 -0
- package/src/react/pasteboard-materialize.ts +154 -0
- package/src/react/react-inspector-section.tsx +2496 -0
- package/src/react/react-world-authoring-adapter.ts +3795 -0
- package/src/react/story-documents/story-args-section.ts +19 -0
- package/src/react/story-documents/story-documents.tsx +1380 -0
- package/src/react/story-paint-bounds.ts +94 -0
- package/src/react/ui-board-document.tsx +101 -0
- package/src/react/ui-board-title.ts +9 -0
- package/src/react/ui-component-board.ts +72 -0
- package/src/services/audio-pose-guard.ts +81 -0
- package/src/services/game-audio-unlock.ts +48 -0
- package/src/state-watch/StateWatchPanel.tsx +535 -0
- package/src/three/authoring/camera-runtime-inspector-section.tsx +135 -0
- package/src/three/authoring/constraint-inspector-section.tsx +189 -0
- package/src/three/authoring/design-time-renderer.ts +189 -0
- package/src/three/authoring/model-asset-inspector-section.css +41 -0
- package/src/three/authoring/model-asset-inspector-section.tsx +869 -0
- package/src/three/authoring/oid-source-persistence.ts +557 -0
- package/src/three/authoring/r3f-design-session.ts +1174 -0
- package/src/three/authoring/r3f-source-authoring-adapter.ts +5949 -0
- package/src/three/authoring/reflection-probe-inspector-section.tsx +76 -0
- package/src/three/authoring/spatial-audio-handles.ts +215 -0
- package/src/three/authoring/spatial-collider-handles.ts +229 -0
- package/src/three/authoring/spatial-joint-handles.ts +114 -0
- package/src/three/authoring/spatial-light-handles.ts +178 -0
- package/src/three/authoring/spatial-lod-handles.ts +93 -0
- package/src/three/authoring/spatial-particle-handles.ts +368 -0
- package/src/three/authoring/three-authoring-adapter.ts +1953 -0
- package/src/three/authoring/three-scene-identity.ts +19 -0
- package/src/three/authoring/three-spatial-handles.ts +161 -0
- package/src/three/authoring/typed-three-inspector.ts +528 -0
- package/src/three/component-verbs/extract-menu.ts +71 -0
- package/src/three/component-verbs/fork-menu.ts +78 -0
- package/src/three/component-verbs/internals-menu.ts +91 -0
- package/src/three/story-documents/three-story-documents.tsx +607 -0
- package/src/three/three-board/ThreeBoardDocument.tsx +888 -0
- package/src/three/three-board/board-framing.ts +412 -0
- package/src/three/three-board/board-layout.ts +401 -0
- package/src/three/three-board/board-scene.ts +901 -0
- package/src/three/three-board/three-component-board.ts +62 -0
- package/src/xstate/XStateBehaviorSection.tsx +130 -0
- package/src/xstate/XStateMachineInspector.tsx +566 -0
- package/src/xstate/character-animation-machine.fixture.ts +74 -0
- package/src/xstate/live-behaviors.ts +106 -0
- package/src/xstate/use-live-actor-state.ts +44 -0
- package/src/xstate/xstate-graph.ts +235 -0
- package/src/xstate/xstate-layout.ts +76 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binomial's Basis Universal ENCODER, loaded from the vendored first-party
|
|
3
|
+
* artifact — the encode half of the Asset Budget's KTX2 texture compression.
|
|
4
|
+
*
|
|
5
|
+
* WHY THE ARTIFACT AND NOT A PACKAGE. `docs/ARCHITECTURE-CORE.md` §Surfacing:
|
|
6
|
+
* "Engine builds are exact-pinned deps … never their three-coupled wrapper
|
|
7
|
+
* packages; if a pin breaks, escalate to vendoring the wasm with an
|
|
8
|
+
* `UPSTREAM.lock`-shaped record, never to trusting a wrapper." Binomial
|
|
9
|
+
* publishes no npm package for the encoder at all (the two registry names that
|
|
10
|
+
* look like one — `basisu`, `basis_universal` — are third-party wrappers around
|
|
11
|
+
* the NATIVE `basisu` executable, which would make this op depend on a system
|
|
12
|
+
* binary), so the escalation is the only honest path: `basis_encoder.js` and
|
|
13
|
+
* `basis_encoder.wasm` are vendored byte-identical from the upstream repo at a
|
|
14
|
+
* pinned commit and recorded in `vendor/upstream-assets.lock.json`.
|
|
15
|
+
*
|
|
16
|
+
* WHAT THIS FILE OWNS. The coupling surface only. It resolves the two
|
|
17
|
+
* artifacts, hands the wasm to the emscripten factory as `wasmBinary` (so the
|
|
18
|
+
* module never fetches anything itself — hermetic in a browser and in vitest
|
|
19
|
+
* alike), and returns the encoder module as-is. Everything above it programs
|
|
20
|
+
* against Binomial's own `BasisEncoder` API; nothing here wraps it.
|
|
21
|
+
*
|
|
22
|
+
* WHY `new Function`. The vendored glue is upstream's UMD-flavoured build
|
|
23
|
+
* (`var BASIS = (() => …)()`), and it stays byte-identical — appending an
|
|
24
|
+
* `export` would break the pinned sha256 and the zero-diff guard that pins it.
|
|
25
|
+
* The three parameters are the Node branch's free variables: emscripten
|
|
26
|
+
* evaluates `require("fs")` and `__dirname` eagerly when `globalThis.process`
|
|
27
|
+
* looks like Node (so vitest takes that branch), but only ever USES them from
|
|
28
|
+
* `readBinary`/`readAsync` — the paths that fetch the wasm, which supplying
|
|
29
|
+
* `wasmBinary` retires. Hence {@link deadRequire}: it satisfies the eager
|
|
30
|
+
* call and throws by name if anything actually reaches through it, rather
|
|
31
|
+
* than pretending to be Node's module system. In a browser the parameters are
|
|
32
|
+
* `undefined` and the branch is not taken at all.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/** Where the vendored encoder is served from (repo-root `public/`). Editor
|
|
36
|
+
* only — a shipped game decodes KTX2 and never encodes it, which is why the
|
|
37
|
+
* template vendors the transcoder but not this. */
|
|
38
|
+
export const BASIS_ENCODER_PATH = '/jsm/libs/basis-encoder/';
|
|
39
|
+
|
|
40
|
+
/** The two vendored files, when the caller already has their bytes (headless
|
|
41
|
+
* tests read them straight off disk; the editor fetches them). */
|
|
42
|
+
export interface BasisEncoderArtifacts {
|
|
43
|
+
/** `basis_encoder.js` source text. */
|
|
44
|
+
readonly glue: string;
|
|
45
|
+
/** `basis_encoder.wasm` bytes. */
|
|
46
|
+
readonly wasmBinary: Uint8Array;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** The slice of Binomial's module this repo actually calls. Deliberately not a
|
|
50
|
+
* full re-declaration of the encoder's API — an unused declaration is a
|
|
51
|
+
* maintenance liability, and everything here has a caller. */
|
|
52
|
+
export interface BasisEncoderModule {
|
|
53
|
+
initializeBasis(): void;
|
|
54
|
+
readonly ldr_image_type: {
|
|
55
|
+
readonly cRGBA32: { value: number };
|
|
56
|
+
readonly cPNGImage: { value: number };
|
|
57
|
+
readonly cJPGImage: { value: number };
|
|
58
|
+
};
|
|
59
|
+
readonly BasisEncoder: new () => BasisEncoderInstance;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** The encoder methods this repo drives. Same rule as above: every one is
|
|
63
|
+
* called by `compressTexturesKtx2`. */
|
|
64
|
+
export interface BasisEncoderInstance {
|
|
65
|
+
setCreateKTX2File(value: boolean): void;
|
|
66
|
+
setKTX2UASTCSupercompression(value: boolean): void;
|
|
67
|
+
setKTX2AndBasisSRGBTransferFunc(value: boolean): void;
|
|
68
|
+
setDebug(value: boolean): void;
|
|
69
|
+
setStatusOutput(value: boolean): void;
|
|
70
|
+
setComputeStats(value: boolean): void;
|
|
71
|
+
setPerceptual(value: boolean): void;
|
|
72
|
+
setMipSRGB(value: boolean): void;
|
|
73
|
+
setMipGen(value: boolean): void;
|
|
74
|
+
setUASTC(value: boolean): void;
|
|
75
|
+
setQualityLevel(value: number): void;
|
|
76
|
+
setSliceSourceImage(
|
|
77
|
+
sliceIndex: number,
|
|
78
|
+
image: Uint8Array,
|
|
79
|
+
width: number,
|
|
80
|
+
height: number,
|
|
81
|
+
imageType: number,
|
|
82
|
+
): boolean;
|
|
83
|
+
encode(output: Uint8Array): number;
|
|
84
|
+
delete(): void;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
type BasisFactory = (options: { wasmBinary: Uint8Array }) => Promise<BasisEncoderModule>;
|
|
88
|
+
|
|
89
|
+
let _module: Promise<BasisEncoderModule> | null = null;
|
|
90
|
+
|
|
91
|
+
async function fetchArtifact(file: string): Promise<Response> {
|
|
92
|
+
const url = `${BASIS_ENCODER_PATH}${file}`;
|
|
93
|
+
const response = await fetch(url);
|
|
94
|
+
if (!response.ok) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`The Basis Universal encoder is not being served at ${url} (HTTP ${response.status}). ` +
|
|
97
|
+
`It is vendored under public${BASIS_ENCODER_PATH} and pinned in vendor/upstream-assets.lock.json.`,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
return response;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Stands in for Node's `require` inside the glue, where the module system is
|
|
105
|
+
* reached for eagerly but the results are only used by the wasm-FETCHING
|
|
106
|
+
* paths that `wasmBinary` retires. Every property access throws with the
|
|
107
|
+
* module name, so a genuine dependency shows up as itself rather than as a
|
|
108
|
+
* silent `undefined` deep inside emscripten.
|
|
109
|
+
*/
|
|
110
|
+
function deadRequire(specifier: string): unknown {
|
|
111
|
+
return new Proxy(
|
|
112
|
+
{},
|
|
113
|
+
{
|
|
114
|
+
get(_target, property) {
|
|
115
|
+
throw new Error(
|
|
116
|
+
`The vendored Basis encoder reached for require('${specifier}').${String(property)} — ` +
|
|
117
|
+
`it is loaded with an explicit wasmBinary and must never load anything itself.`,
|
|
118
|
+
);
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function instantiate(artifacts: BasisEncoderArtifacts): Promise<BasisEncoderModule> {
|
|
125
|
+
const factory = new Function(
|
|
126
|
+
'require',
|
|
127
|
+
'__dirname',
|
|
128
|
+
'__filename',
|
|
129
|
+
`${artifacts.glue}\n;return BASIS;`,
|
|
130
|
+
)(deadRequire, '', '') as BasisFactory;
|
|
131
|
+
const module = await factory({ wasmBinary: artifacts.wasmBinary });
|
|
132
|
+
module.initializeBasis();
|
|
133
|
+
return module;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* The initialized encoder module, created once per page/process.
|
|
138
|
+
*
|
|
139
|
+
* Pass `artifacts` when the bytes are already in hand (headless tests); with
|
|
140
|
+
* no argument the two vendored files are fetched from {@link
|
|
141
|
+
* BASIS_ENCODER_PATH}. Either way the wasm is handed over as `wasmBinary`, so
|
|
142
|
+
* no network request originates inside the emscripten module itself.
|
|
143
|
+
*/
|
|
144
|
+
export function getBasisEncoder(artifacts?: BasisEncoderArtifacts): Promise<BasisEncoderModule> {
|
|
145
|
+
if (!_module) {
|
|
146
|
+
_module = artifacts
|
|
147
|
+
? instantiate(artifacts)
|
|
148
|
+
: (async () => {
|
|
149
|
+
const [glueResponse, wasmResponse] = await Promise.all([
|
|
150
|
+
fetchArtifact('basis_encoder.js'),
|
|
151
|
+
fetchArtifact('basis_encoder.wasm'),
|
|
152
|
+
]);
|
|
153
|
+
return instantiate({
|
|
154
|
+
glue: await glueResponse.text(),
|
|
155
|
+
wasmBinary: new Uint8Array(await wasmResponse.arrayBuffer()),
|
|
156
|
+
});
|
|
157
|
+
})();
|
|
158
|
+
}
|
|
159
|
+
return _module;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** Test-only reset so a suite can re-instantiate against fresh artifacts. */
|
|
163
|
+
export function __resetBasisEncoderForTest(): void {
|
|
164
|
+
_module = null;
|
|
165
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared gltf-transform IO for the Asset Budget window (W4a).
|
|
3
|
+
*
|
|
4
|
+
* One lazily-created `WebIO` with ALL registered extensions plus whatever
|
|
5
|
+
* codec dependencies are actually loadable in this environment. Codec
|
|
6
|
+
* availability is PROBED, never assumed (anti-shim): a codec that fails to
|
|
7
|
+
* import/initialize is recorded with its reason, and callers surface that
|
|
8
|
+
* reason instead of fabricating success. `WebIO.readBinary`/`writeBinary`
|
|
9
|
+
* operate on in-memory GLB bytes, so the same module serves both the browser
|
|
10
|
+
* editor (bytes via the storage seam) and headless vitest (bytes from
|
|
11
|
+
* generated fixtures) — no NodeIO/fs dependency.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { WebIO } from '@gltf-transform/core';
|
|
15
|
+
import { ALL_EXTENSIONS } from '@gltf-transform/extensions';
|
|
16
|
+
import dracoDecoderWasmUrl from 'draco3d/draco_decoder.wasm?url';
|
|
17
|
+
import dracoEncoderWasmUrl from 'draco3d/draco_encoder.wasm?url';
|
|
18
|
+
import { BASIS_ENCODER_PATH } from './basis-encoder';
|
|
19
|
+
|
|
20
|
+
export interface GltfCodecAvailability {
|
|
21
|
+
readonly available: boolean;
|
|
22
|
+
/** Human-readable reason when unavailable — shown verbatim in the UI. */
|
|
23
|
+
readonly reason?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface GltfIOCapabilities {
|
|
27
|
+
readonly meshoptDecoder: GltfCodecAvailability;
|
|
28
|
+
readonly meshoptEncoder: GltfCodecAvailability;
|
|
29
|
+
readonly meshoptSimplifier: GltfCodecAvailability;
|
|
30
|
+
readonly dracoDecoder: GltfCodecAvailability;
|
|
31
|
+
readonly dracoEncoder: GltfCodecAvailability;
|
|
32
|
+
/** KTX2/Basis ENCODING: Binomial's vendored encoder wasm, served from
|
|
33
|
+
* `BASIS_ENCODER_PATH`. Probed by asking the server for it, because the
|
|
34
|
+
* question the UI needs answered is whether THIS deployment serves it. */
|
|
35
|
+
readonly ktx2Encoder: GltfCodecAvailability;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface GltfIOBundle {
|
|
39
|
+
readonly io: WebIO;
|
|
40
|
+
readonly capabilities: GltfIOCapabilities;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let _bundle: Promise<GltfIOBundle> | null = null;
|
|
44
|
+
|
|
45
|
+
function unavailable(error: unknown, what: string): GltfCodecAvailability {
|
|
46
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
47
|
+
return { available: false, reason: `${what} failed to load: ${message}` };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Create (once) the shared IO. Meshopt decode/encode/simplify come from the
|
|
52
|
+
* `meshoptimizer` package (inline-wasm — loads in both browser and node).
|
|
53
|
+
* Draco decode/encode come from `draco3d`, whose glue is its Node build:
|
|
54
|
+
* without a `locateFile` the emscripten runtime fetched `draco_*.wasm`
|
|
55
|
+
* relative to the page and got the dev server's HTML fallback (measured
|
|
56
|
+
* 2026-09-17, four emscripten warnings per Asset Budget open). The package
|
|
57
|
+
* ships both wasm files beside the glue; Vite serves them by URL and the
|
|
58
|
+
* glue is told where. Still probed — a host that cannot run the glue reports
|
|
59
|
+
* Draco unavailable. KTX2 encoding has no in-repo encoder and is reported
|
|
60
|
+
* unavailable with that exact reason.
|
|
61
|
+
*/
|
|
62
|
+
export function getGltfIO(): Promise<GltfIOBundle> {
|
|
63
|
+
if (!_bundle) _bundle = createBundle();
|
|
64
|
+
return _bundle;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function createBundle(): Promise<GltfIOBundle> {
|
|
68
|
+
const io = new WebIO().registerExtensions(ALL_EXTENSIONS);
|
|
69
|
+
const dependencies: Record<string, unknown> = {};
|
|
70
|
+
|
|
71
|
+
let meshoptDecoder: GltfCodecAvailability = { available: true };
|
|
72
|
+
let meshoptEncoder: GltfCodecAvailability = { available: true };
|
|
73
|
+
let meshoptSimplifier: GltfCodecAvailability = { available: true };
|
|
74
|
+
try {
|
|
75
|
+
const meshopt = await import('meshoptimizer');
|
|
76
|
+
await Promise.all([
|
|
77
|
+
meshopt.MeshoptDecoder.ready,
|
|
78
|
+
meshopt.MeshoptEncoder.ready,
|
|
79
|
+
meshopt.MeshoptSimplifier.ready,
|
|
80
|
+
]);
|
|
81
|
+
dependencies['meshopt.decoder'] = meshopt.MeshoptDecoder;
|
|
82
|
+
dependencies['meshopt.encoder'] = meshopt.MeshoptEncoder;
|
|
83
|
+
} catch (error) {
|
|
84
|
+
meshoptDecoder = unavailable(error, 'meshoptimizer decoder');
|
|
85
|
+
meshoptEncoder = unavailable(error, 'meshoptimizer encoder');
|
|
86
|
+
meshoptSimplifier = unavailable(error, 'meshoptimizer simplifier');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let dracoDecoder: GltfCodecAvailability = { available: true };
|
|
90
|
+
let dracoEncoder: GltfCodecAvailability = { available: true };
|
|
91
|
+
try {
|
|
92
|
+
const draco3d = (await import('draco3d')).default;
|
|
93
|
+
dependencies['draco3d.decoder'] = await draco3d.createDecoderModule({
|
|
94
|
+
locateFile: (file: string) => (file.endsWith('.wasm') ? dracoDecoderWasmUrl : file),
|
|
95
|
+
});
|
|
96
|
+
} catch (error) {
|
|
97
|
+
dracoDecoder = unavailable(error, 'draco3d decoder');
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
const draco3d = (await import('draco3d')).default;
|
|
101
|
+
dependencies['draco3d.encoder'] = await draco3d.createEncoderModule({
|
|
102
|
+
locateFile: (file: string) => (file.endsWith('.wasm') ? dracoEncoderWasmUrl : file),
|
|
103
|
+
});
|
|
104
|
+
} catch (error) {
|
|
105
|
+
dracoEncoder = unavailable(error, 'draco3d encoder');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
io.registerDependencies(dependencies);
|
|
109
|
+
return {
|
|
110
|
+
io,
|
|
111
|
+
capabilities: {
|
|
112
|
+
meshoptDecoder,
|
|
113
|
+
meshoptEncoder,
|
|
114
|
+
meshoptSimplifier,
|
|
115
|
+
dracoDecoder,
|
|
116
|
+
dracoEncoder,
|
|
117
|
+
ktx2Encoder: await probeKtx2Encoder(),
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Is the vendored Basis encoder reachable from this page?
|
|
124
|
+
*
|
|
125
|
+
* A HEAD request rather than an import: the encoder is a 3.3 MB wasm served
|
|
126
|
+
* as a static file (`basis-encoder.ts` explains why it is vendored rather
|
|
127
|
+
* than depended on), so probing it by LOADING it would cost the download at
|
|
128
|
+
* every Asset Budget open, for a button the user may never press. HEAD costs
|
|
129
|
+
* one round trip and answers exactly the question — does this deployment
|
|
130
|
+
* serve the artifact — while the op itself still fails loudly with the real
|
|
131
|
+
* reason if the body turns out to be unusable.
|
|
132
|
+
*/
|
|
133
|
+
async function probeKtx2Encoder(): Promise<GltfCodecAvailability> {
|
|
134
|
+
const url = `${BASIS_ENCODER_PATH}basis_encoder.wasm`;
|
|
135
|
+
try {
|
|
136
|
+
const response = await fetch(url, { method: 'HEAD' });
|
|
137
|
+
if (response.ok) return { available: true };
|
|
138
|
+
return {
|
|
139
|
+
available: false,
|
|
140
|
+
reason: `The Basis Universal encoder is not being served at ${url} (HTTP ${response.status}).`,
|
|
141
|
+
};
|
|
142
|
+
} catch (error) {
|
|
143
|
+
return unavailable(error, `the Basis Universal encoder at ${url}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** The meshoptimizer simplifier module, for simplify()/simplifyPrimitive(). */
|
|
148
|
+
export async function getMeshoptSimplifier(): Promise<
|
|
149
|
+
typeof import('meshoptimizer').MeshoptSimplifier
|
|
150
|
+
> {
|
|
151
|
+
const meshopt = await import('meshoptimizer');
|
|
152
|
+
await meshopt.MeshoptSimplifier.ready;
|
|
153
|
+
return meshopt.MeshoptSimplifier;
|
|
154
|
+
}
|