@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.
Files changed (302) hide show
  1. package/LICENSE +661 -0
  2. package/NOTICE +23 -0
  3. package/contributions/asset-budget-asset.menu.ts +26 -0
  4. package/contributions/asset-budget.action.ts +18 -0
  5. package/contributions/asset-budget.document.tsx +21 -0
  6. package/contributions/asset-budget.menu.ts +22 -0
  7. package/contributions/audio-unlock.service.ts +17 -0
  8. package/contributions/audio.utility.tsx +15 -0
  9. package/contributions/autoplay.service.ts +48 -0
  10. package/contributions/bridge.command.ts +172 -0
  11. package/contributions/build-profiles.document.tsx +21 -0
  12. package/contributions/build-progress.status.tsx +45 -0
  13. package/contributions/build.action.ts +26 -0
  14. package/contributions/build.command.ts +27 -0
  15. package/contributions/build.header.tsx +37 -0
  16. package/contributions/build.menu.ts +31 -0
  17. package/contributions/build.service.ts +31 -0
  18. package/contributions/connection.status.tsx +43 -0
  19. package/contributions/coverage.service.ts +118 -0
  20. package/contributions/edit-mode-audio.service.ts +23 -0
  21. package/contributions/edit-mode-networking.service.ts +30 -0
  22. package/contributions/game-document.service.ts +25 -0
  23. package/contributions/game-eval.command.ts +210 -0
  24. package/contributions/game.layout.ts +19 -0
  25. package/contributions/gameplay.command.ts +255 -0
  26. package/contributions/generation.service.ts +96 -0
  27. package/contributions/generations.status.tsx +53 -0
  28. package/contributions/ingest.service.ts +80 -0
  29. package/contributions/instances.command.ts +75 -0
  30. package/contributions/navmesh.menu.ts +39 -0
  31. package/contributions/navmesh.service.ts +19 -0
  32. package/contributions/network.utility.tsx +17 -0
  33. package/contributions/play.command.ts +355 -0
  34. package/contributions/profiler.action.ts +16 -0
  35. package/contributions/profiler.menu.ts +22 -0
  36. package/contributions/profiler.utility.tsx +17 -0
  37. package/contributions/react/component-board.service.ts +21 -0
  38. package/contributions/react/design-time-mount.service.ts +60 -0
  39. package/contributions/react/pasteboard.action.ts +41 -0
  40. package/contributions/react/react-inspector.service.ts +85 -0
  41. package/contributions/react/story-documents.service.ts +44 -0
  42. package/contributions/scene-document.service.ts +32 -0
  43. package/contributions/state-watch.action.ts +17 -0
  44. package/contributions/state-watch.menu.ts +23 -0
  45. package/contributions/state-watch.utility.tsx +20 -0
  46. package/contributions/team-playtest.service.ts +124 -0
  47. package/contributions/three/camera-runtime.inspector.tsx +34 -0
  48. package/contributions/three/component-board.service.ts +24 -0
  49. package/contributions/three/component-verbs.command.ts +110 -0
  50. package/contributions/three/component-verbs.service.ts +92 -0
  51. package/contributions/three/constraints.inspector.tsx +34 -0
  52. package/contributions/three/model-asset-sections.service.ts +26 -0
  53. package/contributions/three/reflection-probe-capture.inspector.tsx +32 -0
  54. package/contributions/three/story-documents.service.ts +31 -0
  55. package/contributions/three/three-authoring.service.ts +66 -0
  56. package/contributions/transport.header.tsx +19 -0
  57. package/contributions/xstate-behavior.action.ts +42 -0
  58. package/contributions/xstate-behavior.document.tsx +73 -0
  59. package/contributions/xstate-behavior.inspector.tsx +28 -0
  60. package/contributions/xstate-behavior.menu.ts +23 -0
  61. package/package.json +144 -0
  62. package/src/asset-budget/AssetBudgetPanel.tsx +1172 -0
  63. package/src/asset-budget/asset-budget-model.ts +799 -0
  64. package/src/asset-budget/basis-encoder.ts +165 -0
  65. package/src/asset-budget/gltf-io.ts +154 -0
  66. package/src/asset-budget/gltf-optimize.ts +384 -0
  67. package/src/asset-budget/image-dims.ts +78 -0
  68. package/src/asset-budget/optimize-apply.ts +221 -0
  69. package/src/audio/AudioDebuggerPanel.tsx +457 -0
  70. package/src/audio/audio-debugger-model.ts +87 -0
  71. package/src/bridge/call.ts +60 -0
  72. package/src/bridge/dispatch.ts +459 -0
  73. package/src/bridge/live-frames.ts +25 -0
  74. package/src/bridge/screenshot.ts +316 -0
  75. package/src/build/BuildProfilesPanel.tsx +476 -0
  76. package/src/build/build-session.ts +247 -0
  77. package/src/build/format-bytes.ts +14 -0
  78. package/src/command-results.ts +36 -0
  79. package/src/coverage/live-authoring-surface.ts +30 -0
  80. package/src/coverage/live-project-verbs.ts +162 -0
  81. package/src/coverage/native-system-coverage.ts +143 -0
  82. package/src/coverage/root-coverage.ts +79 -0
  83. package/src/coverage/session-coverage.ts +193 -0
  84. package/src/design-system-stories/ApplicationChrome.stories.tsx +100 -0
  85. package/src/design-system-stories/InspectorNarrowBodies.stories.tsx +406 -0
  86. package/src/edit-mode/edit-mode-audio.ts +56 -0
  87. package/src/edit-mode/edit-mode-networking.ts +112 -0
  88. package/src/game-document/DevicePresetPicker.tsx +84 -0
  89. package/src/game-document/GameCaptureFrameButton.tsx +45 -0
  90. package/src/game-document/GameDocument.tsx +215 -0
  91. package/src/game-document/GamePanel.tsx +662 -0
  92. package/src/game-document/InstanceInspectorPicker.tsx +183 -0
  93. package/src/game-document/crowd-debug.ts +183 -0
  94. package/src/game-document/device-preview.ts +336 -0
  95. package/src/game-document/game-view-store.ts +107 -0
  96. package/src/game-document/physics-debug.ts +187 -0
  97. package/src/generation/GenerationActivity.tsx +421 -0
  98. package/src/generation/GenerationGallery.css +231 -0
  99. package/src/generation/generation-documents.tsx +338 -0
  100. package/src/generation/generation-jobs.ts +128 -0
  101. package/src/generation/generation-presentation.ts +257 -0
  102. package/src/host/adapter-reach.ts +445 -0
  103. package/src/host/adapter-runtime-bindings.ts +303 -0
  104. package/src/host/after-paint.ts +112 -0
  105. package/src/host/api/configurations.ts +66 -0
  106. package/src/host/authoring/babylon-authoring-adapter.ts +703 -0
  107. package/src/host/authoring/canvas-runtime-recognition.ts +50 -0
  108. package/src/host/authoring/contract-hierarchy-authoring.ts +144 -0
  109. package/src/host/authoring/contract-scenes-stories.ts +204 -0
  110. package/src/host/authoring/creation-site-related.ts +55 -0
  111. package/src/host/authoring/ephemeral-persistence.ts +29 -0
  112. package/src/host/authoring/gesture-persist.ts +84 -0
  113. package/src/host/authoring/ingest-data-writer.ts +232 -0
  114. package/src/host/authoring/ingest-source-persistence.ts +826 -0
  115. package/src/host/authoring/mount-isolated-pixi-screen.ts +250 -0
  116. package/src/host/authoring/mounted-authoring.ts +41 -0
  117. package/src/host/authoring/owned-pixi-ticker-listeners.ts +96 -0
  118. package/src/host/authoring/phaser-live-authoring-adapter.ts +265 -0
  119. package/src/host/authoring/pixi-authoring-adapter.ts +1554 -0
  120. package/src/host/authoring/pixi-creation-site-write-target.ts +60 -0
  121. package/src/host/authoring/pixi-isolation-assets.ts +25 -0
  122. package/src/host/authoring/pixi-live-write-target.ts +979 -0
  123. package/src/host/authoring/pixi-source-identity.ts +141 -0
  124. package/src/host/authoring/pixi-still-presentation.ts +71 -0
  125. package/src/host/authoring/pixi-structure-history.ts +237 -0
  126. package/src/host/authoring/pixi-transform-channels.ts +205 -0
  127. package/src/host/authoring/selection-remount-handoff.ts +23 -0
  128. package/src/host/authoring/source-persistence-backend.ts +373 -0
  129. package/src/host/authoring/source-refresh-revisions.ts +81 -0
  130. package/src/host/authoring/struct-write-pipe.ts +143 -0
  131. package/src/host/auto-frame-window.ts +89 -0
  132. package/src/host/binding-resolver.ts +393 -0
  133. package/src/host/browser-transpile.ts +631 -0
  134. package/src/host/canvas-entry-runtime.ts +95 -0
  135. package/src/host/components/CameraAuthoringOverlay.tsx +216 -0
  136. package/src/host/components/HeaderTelemetry.tsx +341 -0
  137. package/src/host/components/PixiIsolationSceneContent.tsx +280 -0
  138. package/src/host/components/ResolutionPicker.tsx +89 -0
  139. package/src/host/components/ThreeIsolationSceneContent.tsx +180 -0
  140. package/src/host/components/frame-debugger-model.ts +579 -0
  141. package/src/host/components/header-telemetry-model.ts +74 -0
  142. package/src/host/components/scene-document.tsx +447 -0
  143. package/src/host/components/utility-view-state.ts +87 -0
  144. package/src/host/components/world-root-stage-binding.tsx +133 -0
  145. package/src/host/components/world-root-stage.ts +1046 -0
  146. package/src/host/coverage/authoring-read-probe.ts +583 -0
  147. package/src/host/coverage/capability-coverage.ts +1587 -0
  148. package/src/host/coverage/coverage-accounting.ts +261 -0
  149. package/src/host/coverage/game-contract-seam-evidence.ts +82 -0
  150. package/src/host/coverage/project-verb-coverage.ts +148 -0
  151. package/src/host/coverage/system-adapter-coverage.ts +373 -0
  152. package/src/host/design-system-stories/StoryLayout.tsx +104 -0
  153. package/src/host/design-system-stories/fixtures/authoring.ts +247 -0
  154. package/src/host/design-system-stories/fixtures/editor-runtime.tsx +115 -0
  155. package/src/host/document-preview-three.ts +110 -0
  156. package/src/host/entry-adjudication.ts +89 -0
  157. package/src/host/game-location-guard.ts +150 -0
  158. package/src/host/game-module-access.ts +196 -0
  159. package/src/host/game-realm-page.ts +358 -0
  160. package/src/host/game-realm-reclaim.ts +55 -0
  161. package/src/host/game-realm-storage.ts +104 -0
  162. package/src/host/gameplay-export.ts +288 -0
  163. package/src/host/gameplay-recording.ts +717 -0
  164. package/src/host/gated-globals.ts +1511 -0
  165. package/src/host/history/json-history-resource.ts +254 -0
  166. package/src/host/ingest/registry.ts +261 -0
  167. package/src/host/instance-extract-actions.ts +120 -0
  168. package/src/host/instance-fork-actions.ts +120 -0
  169. package/src/host/play-control-hook.ts +26 -0
  170. package/src/host/playwright-shim.ts +479 -0
  171. package/src/host/projection/dom.ts +295 -0
  172. package/src/host/projection/pixi.ts +288 -0
  173. package/src/host/r3f-entry-runtime.ts +77 -0
  174. package/src/host/react-mount-runtime.ts +162 -0
  175. package/src/host/realm-services.ts +148 -0
  176. package/src/host/recording-preview.ts +106 -0
  177. package/src/host/roots/module-root.ts +203 -0
  178. package/src/host/roots/react-root.ts +181 -0
  179. package/src/host/same-realm-loop-gate.ts +544 -0
  180. package/src/host/scene-view-drawability.ts +69 -0
  181. package/src/host/sdk/tools.ts +31 -0
  182. package/src/host/served-bundle-runtime-modules.ts +331 -0
  183. package/src/host/server-log-bridge.ts +60 -0
  184. package/src/host/staged-projects.ts +24 -0
  185. package/src/host/stories/mounted-story-viewport-source.ts +64 -0
  186. package/src/host/stories/story-arg-descriptors.ts +50 -0
  187. package/src/host/stories/story-media-presence.ts +152 -0
  188. package/src/host/surface-content.ts +87 -0
  189. package/src/host/take-named-export.ts +23 -0
  190. package/src/host/three-ingest-runtime.ts +76 -0
  191. package/src/host/types-fastnoise-lite.d.ts +7 -0
  192. package/src/host/types-mikktspace.d.ts +20 -0
  193. package/src/host/types-troika-three-text.d.ts +7 -0
  194. package/src/host/use-active-performance-source.ts +53 -0
  195. package/src/host/viewport-pose-memory.ts +48 -0
  196. package/src/host/viewport-root-presentation.ts +40 -0
  197. package/src/ingest/active-ingest.ts +251 -0
  198. package/src/ingest/active-scene-navigation.ts +43 -0
  199. package/src/ingest/authoring/ingest-dom-surface-authoring.ts +191 -0
  200. package/src/ingest/authoring/ingest-root-adapter.ts +897 -0
  201. package/src/ingest/capture-wait-report.ts +122 -0
  202. package/src/ingest/deferred-ingest-play.ts +216 -0
  203. package/src/ingest/deferred-ingest-session.ts +23 -0
  204. package/src/ingest/discovery-public-ingest.ts +242 -0
  205. package/src/ingest/dom-stub-mark.ts +7 -0
  206. package/src/ingest/entry-load.ts +56 -0
  207. package/src/ingest/game-contract-realm.ts +34 -0
  208. package/src/ingest/game-pointer-lock.ts +89 -0
  209. package/src/ingest/held-scene-repaint.ts +73 -0
  210. package/src/ingest/host-surface-box.ts +174 -0
  211. package/src/ingest/ingest-boot-viewport.ts +54 -0
  212. package/src/ingest/ingest-canvas-scene-document.tsx +177 -0
  213. package/src/ingest/ingest-canvas-scene.ts +50 -0
  214. package/src/ingest/ingest-evidence-hook.ts +131 -0
  215. package/src/ingest/ingest-frame-snapshot.ts +183 -0
  216. package/src/ingest/ingest-play-commands.ts +134 -0
  217. package/src/ingest/ingest-play-control.ts +299 -0
  218. package/src/ingest/ingest-render-debug.ts +320 -0
  219. package/src/ingest/ingest-siblings.ts +487 -0
  220. package/src/ingest/ingest-status.ts +62 -0
  221. package/src/ingest/live-ingest-facet.ts +46 -0
  222. package/src/ingest/module-mode.ts +229 -0
  223. package/src/ingest/mount-canvas-ingest-root.ts +899 -0
  224. package/src/ingest/mount-coverage.ts +296 -0
  225. package/src/ingest/mount-dom-ingest-root.ts +282 -0
  226. package/src/ingest/mount-ingest-root.ts +744 -0
  227. package/src/ingest/mount-three-ingest-root.ts +366 -0
  228. package/src/ingest/resolve-canvas.ts +47 -0
  229. package/src/ingest/resolve-three.ts +123 -0
  230. package/src/ingest/served-bundle.ts +109 -0
  231. package/src/ingest/served-html-boot.ts +292 -0
  232. package/src/ingest/surface-canvas.ts +84 -0
  233. package/src/ingest/surface-dom.ts +84 -0
  234. package/src/ingest/surface-three.ts +128 -0
  235. package/src/ingest/types.ts +76 -0
  236. package/src/ingest/unmount-ingest-root.ts +224 -0
  237. package/src/navmesh/navmesh-actions.ts +27 -0
  238. package/src/navmesh/navmesh-handler.ts +237 -0
  239. package/src/navmesh/navmesh-workflow-store.ts +78 -0
  240. package/src/network/NetworkInspectorPanel.tsx +644 -0
  241. package/src/network/network-inspector-model.ts +225 -0
  242. package/src/play/play-boot-stall.ts +118 -0
  243. package/src/play/play-log-events.ts +26 -0
  244. package/src/play/play-mode.ts +2553 -0
  245. package/src/play/play-recording.ts +335 -0
  246. package/src/play/react-play-live-authoring.ts +165 -0
  247. package/src/play-bar/PlayBar.tsx +488 -0
  248. package/src/play-bar/PlayerCountPicker.tsx +100 -0
  249. package/src/profiler/FrameDebuggerPanel.tsx +458 -0
  250. package/src/profiler/PerformancePanel.tsx +1068 -0
  251. package/src/profiler/ProfilerPanel.tsx +53 -0
  252. package/src/profiler/frame-debugger-store.ts +97 -0
  253. package/src/profiler/main-thread-busy.ts +90 -0
  254. package/src/react/design-time-react-mount.ts +782 -0
  255. package/src/react/dom-authoring-adapter.ts +764 -0
  256. package/src/react/pasteboard-materialize.ts +154 -0
  257. package/src/react/react-inspector-section.tsx +2496 -0
  258. package/src/react/react-world-authoring-adapter.ts +3795 -0
  259. package/src/react/story-documents/story-args-section.ts +19 -0
  260. package/src/react/story-documents/story-documents.tsx +1380 -0
  261. package/src/react/story-paint-bounds.ts +94 -0
  262. package/src/react/ui-board-document.tsx +101 -0
  263. package/src/react/ui-board-title.ts +9 -0
  264. package/src/react/ui-component-board.ts +72 -0
  265. package/src/services/audio-pose-guard.ts +81 -0
  266. package/src/services/game-audio-unlock.ts +48 -0
  267. package/src/state-watch/StateWatchPanel.tsx +535 -0
  268. package/src/three/authoring/camera-runtime-inspector-section.tsx +135 -0
  269. package/src/three/authoring/constraint-inspector-section.tsx +189 -0
  270. package/src/three/authoring/design-time-renderer.ts +189 -0
  271. package/src/three/authoring/model-asset-inspector-section.css +41 -0
  272. package/src/three/authoring/model-asset-inspector-section.tsx +869 -0
  273. package/src/three/authoring/oid-source-persistence.ts +557 -0
  274. package/src/three/authoring/r3f-design-session.ts +1174 -0
  275. package/src/three/authoring/r3f-source-authoring-adapter.ts +5949 -0
  276. package/src/three/authoring/reflection-probe-inspector-section.tsx +76 -0
  277. package/src/three/authoring/spatial-audio-handles.ts +215 -0
  278. package/src/three/authoring/spatial-collider-handles.ts +229 -0
  279. package/src/three/authoring/spatial-joint-handles.ts +114 -0
  280. package/src/three/authoring/spatial-light-handles.ts +178 -0
  281. package/src/three/authoring/spatial-lod-handles.ts +93 -0
  282. package/src/three/authoring/spatial-particle-handles.ts +368 -0
  283. package/src/three/authoring/three-authoring-adapter.ts +1953 -0
  284. package/src/three/authoring/three-scene-identity.ts +19 -0
  285. package/src/three/authoring/three-spatial-handles.ts +161 -0
  286. package/src/three/authoring/typed-three-inspector.ts +528 -0
  287. package/src/three/component-verbs/extract-menu.ts +71 -0
  288. package/src/three/component-verbs/fork-menu.ts +78 -0
  289. package/src/three/component-verbs/internals-menu.ts +91 -0
  290. package/src/three/story-documents/three-story-documents.tsx +607 -0
  291. package/src/three/three-board/ThreeBoardDocument.tsx +888 -0
  292. package/src/three/three-board/board-framing.ts +412 -0
  293. package/src/three/three-board/board-layout.ts +401 -0
  294. package/src/three/three-board/board-scene.ts +901 -0
  295. package/src/three/three-board/three-component-board.ts +62 -0
  296. package/src/xstate/XStateBehaviorSection.tsx +130 -0
  297. package/src/xstate/XStateMachineInspector.tsx +566 -0
  298. package/src/xstate/character-animation-machine.fixture.ts +74 -0
  299. package/src/xstate/live-behaviors.ts +106 -0
  300. package/src/xstate/use-live-actor-state.ts +44 -0
  301. package/src/xstate/xstate-graph.ts +235 -0
  302. 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
+ }