@ioai/robot_viewer 0.0.0-stage → 1.1.2

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 (159) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +217 -2
  3. package/bin/cli.js +83 -0
  4. package/dist/assets/css/PlotPanel-3e7d7555.css +1 -0
  5. package/dist/assets/js/ColladaLoader-2a0c4638.js +1 -0
  6. package/dist/assets/js/GLTFLoader-7a7f40d7.js +1 -0
  7. package/dist/assets/js/MTLLoader-b6ce88b7.js +1 -0
  8. package/dist/assets/js/OBJLoader-7667aa01.js +1 -0
  9. package/dist/assets/js/PlotPanel-09f986c7.js +1 -0
  10. package/dist/assets/js/STLLoader-de0915d4.js +1 -0
  11. package/dist/assets/js/URDFLoader-a34b6917.js +1 -0
  12. package/dist/assets/js/USDZLoader-64197f74.js +7 -0
  13. package/dist/assets/js/__vite-browser-external-afb87ea8.js +1 -0
  14. package/dist/assets/js/codemirror-c3cec7b3.js +1 -0
  15. package/dist/assets/js/codemirror-themes-e6995a6a.js +1 -0
  16. package/dist/assets/js/d3-2e308866.js +1 -0
  17. package/dist/assets/js/index-56e94ce5.js +6 -0
  18. package/dist/assets/js/mujoco_wasm-345a2576.js +1 -0
  19. package/dist/assets/js/three-9c891de0.js +6 -0
  20. package/dist/camera-publish-worker.js +1 -0
  21. package/dist/favicon.svg +2 -0
  22. package/dist/heartbeat-worker.js +1 -0
  23. package/dist/index.html +4373 -0
  24. package/dist/models/mocap/blender_human.urdf +2319 -0
  25. package/dist/models/mocap/blender_human_skeleton_v4.urdf +1432 -0
  26. package/dist/models/mocap/blender_human_skeleton_v5.urdf +2717 -0
  27. package/dist/models/mocap/meshes/v4/L_base_link.STL +0 -0
  28. package/dist/models/mocap/meshes/v4/L_figer1_1.STL +0 -0
  29. package/dist/models/mocap/meshes/v4/L_figer1_2.STL +0 -0
  30. package/dist/models/mocap/meshes/v4/L_figer1_3.STL +0 -0
  31. package/dist/models/mocap/meshes/v4/L_figer1_4.STL +0 -0
  32. package/dist/models/mocap/meshes/v4/L_figer1_5.STL +0 -0
  33. package/dist/models/mocap/meshes/v4/L_figer1base.STL +0 -0
  34. package/dist/models/mocap/meshes/v4/L_figer2_1.STL +0 -0
  35. package/dist/models/mocap/meshes/v4/L_figer2_2.STL +0 -0
  36. package/dist/models/mocap/meshes/v4/L_figer2_3.STL +0 -0
  37. package/dist/models/mocap/meshes/v4/L_figer2_4.STL +0 -0
  38. package/dist/models/mocap/meshes/v4/L_figer2_5.STL +0 -0
  39. package/dist/models/mocap/meshes/v4/L_figer3_1.STL +0 -0
  40. package/dist/models/mocap/meshes/v4/L_figer3_2.STL +0 -0
  41. package/dist/models/mocap/meshes/v4/L_figer3_3.STL +0 -0
  42. package/dist/models/mocap/meshes/v4/L_figer3_4.STL +0 -0
  43. package/dist/models/mocap/meshes/v4/L_figer3_5.STL +0 -0
  44. package/dist/models/mocap/meshes/v4/L_figer4_1.STL +0 -0
  45. package/dist/models/mocap/meshes/v4/L_figer4_2.STL +0 -0
  46. package/dist/models/mocap/meshes/v4/L_figer4_3.STL +0 -0
  47. package/dist/models/mocap/meshes/v4/L_figer4_4.STL +0 -0
  48. package/dist/models/mocap/meshes/v4/L_figer4_5.STL +0 -0
  49. package/dist/models/mocap/meshes/v4/L_figer5_1.STL +0 -0
  50. package/dist/models/mocap/meshes/v4/L_figer5_2.STL +0 -0
  51. package/dist/models/mocap/meshes/v4/L_figer5_3.STL +0 -0
  52. package/dist/models/mocap/meshes/v4/L_figer5_4.STL +0 -0
  53. package/dist/models/mocap/meshes/v4/L_figer5_5.STL +0 -0
  54. package/dist/models/mocap/meshes/v4/L_handle.STL +0 -0
  55. package/dist/models/mocap/meshes/v4/L_handleseat.STL +0 -0
  56. package/dist/models/mocap/meshes/v4/L_mark.STL +0 -0
  57. package/dist/models/mocap/meshes/v4/L_markseat.STL +0 -0
  58. package/dist/models/mocap/meshes/v4/Lgamepadbase.STL +0 -0
  59. package/dist/models/mocap/meshes/v4/Link1.STL +0 -0
  60. package/dist/models/mocap/meshes/v4/Link2.STL +0 -0
  61. package/dist/models/mocap/meshes/v4/R_base_link.STL +0 -0
  62. package/dist/models/mocap/meshes/v4/R_figer1_1.STL +0 -0
  63. package/dist/models/mocap/meshes/v4/R_figer1_2.STL +0 -0
  64. package/dist/models/mocap/meshes/v4/R_figer1_3.STL +0 -0
  65. package/dist/models/mocap/meshes/v4/R_figer1_4.STL +0 -0
  66. package/dist/models/mocap/meshes/v4/R_figer1_5.STL +0 -0
  67. package/dist/models/mocap/meshes/v4/R_figer1base.STL +0 -0
  68. package/dist/models/mocap/meshes/v4/R_figer2_1.STL +0 -0
  69. package/dist/models/mocap/meshes/v4/R_figer2_2.STL +0 -0
  70. package/dist/models/mocap/meshes/v4/R_figer2_3.STL +0 -0
  71. package/dist/models/mocap/meshes/v4/R_figer2_4.STL +0 -0
  72. package/dist/models/mocap/meshes/v4/R_figer2_5.STL +0 -0
  73. package/dist/models/mocap/meshes/v4/R_figer3_1.STL +0 -0
  74. package/dist/models/mocap/meshes/v4/R_figer3_2.STL +0 -0
  75. package/dist/models/mocap/meshes/v4/R_figer3_3.STL +0 -0
  76. package/dist/models/mocap/meshes/v4/R_figer3_4.STL +0 -0
  77. package/dist/models/mocap/meshes/v4/R_figer3_5.STL +0 -0
  78. package/dist/models/mocap/meshes/v4/R_figer4_1.STL +0 -0
  79. package/dist/models/mocap/meshes/v4/R_figer4_2.STL +0 -0
  80. package/dist/models/mocap/meshes/v4/R_figer4_3.STL +0 -0
  81. package/dist/models/mocap/meshes/v4/R_figer4_4.STL +0 -0
  82. package/dist/models/mocap/meshes/v4/R_figer4_5.STL +0 -0
  83. package/dist/models/mocap/meshes/v4/R_figer5_1.STL +0 -0
  84. package/dist/models/mocap/meshes/v4/R_figer5_2.STL +0 -0
  85. package/dist/models/mocap/meshes/v4/R_figer5_3.STL +0 -0
  86. package/dist/models/mocap/meshes/v4/R_figer5_4.STL +0 -0
  87. package/dist/models/mocap/meshes/v4/R_figer5_5.STL +0 -0
  88. package/dist/models/mocap/meshes/v4/R_handle.STL +0 -0
  89. package/dist/models/mocap/meshes/v4/R_handleseat.STL +0 -0
  90. package/dist/models/mocap/meshes/v4/R_mark.STL +0 -0
  91. package/dist/models/mocap/meshes/v4/R_markseat.STL +0 -0
  92. package/dist/models/mocap/meshes/v4/Rgamepadbase.STL +0 -0
  93. package/dist/models/mocap/meshes/v4/base_link.STL +0 -0
  94. package/dist/models/mocap/meshes/v4/r_figer1_1.STL +0 -0
  95. package/dist/models/mocap/meshes/v5/L_handleseat.STL +0 -0
  96. package/dist/models/mocap/meshes/v5/R_handleseat.STL +0 -0
  97. package/dist/models/mocap/meshes/v5/link_LeftSkeletonBase.STL +0 -0
  98. package/dist/models/mocap/meshes/v5/link_LeftSkeletonIndex1.STL +0 -0
  99. package/dist/models/mocap/meshes/v5/link_LeftSkeletonIndex2.STL +0 -0
  100. package/dist/models/mocap/meshes/v5/link_LeftSkeletonIndex3.STL +0 -0
  101. package/dist/models/mocap/meshes/v5/link_LeftSkeletonIndex4.STL +0 -0
  102. package/dist/models/mocap/meshes/v5/link_LeftSkeletonMiddle1.STL +0 -0
  103. package/dist/models/mocap/meshes/v5/link_LeftSkeletonMiddle2.STL +0 -0
  104. package/dist/models/mocap/meshes/v5/link_LeftSkeletonMiddle3.STL +0 -0
  105. package/dist/models/mocap/meshes/v5/link_LeftSkeletonMiddle4.STL +0 -0
  106. package/dist/models/mocap/meshes/v5/link_LeftSkeletonPinky1.STL +0 -0
  107. package/dist/models/mocap/meshes/v5/link_LeftSkeletonPinky2.STL +0 -0
  108. package/dist/models/mocap/meshes/v5/link_LeftSkeletonPinky3.STL +0 -0
  109. package/dist/models/mocap/meshes/v5/link_LeftSkeletonPinky4.STL +0 -0
  110. package/dist/models/mocap/meshes/v5/link_LeftSkeletonRing1.STL +0 -0
  111. package/dist/models/mocap/meshes/v5/link_LeftSkeletonRing2.STL +0 -0
  112. package/dist/models/mocap/meshes/v5/link_LeftSkeletonRing3.STL +0 -0
  113. package/dist/models/mocap/meshes/v5/link_LeftSkeletonRing4.STL +0 -0
  114. package/dist/models/mocap/meshes/v5/link_LeftSkeletonThumb1.STL +0 -0
  115. package/dist/models/mocap/meshes/v5/link_LeftSkeletonThumb2.STL +0 -0
  116. package/dist/models/mocap/meshes/v5/link_LeftSkeletonThumb3.STL +0 -0
  117. package/dist/models/mocap/meshes/v5/link_LeftSkeletonThumb4.STL +0 -0
  118. package/dist/models/mocap/meshes/v5/link_LeftSkeletonThumbBase.STL +0 -0
  119. package/dist/models/mocap/meshes/v5/link_RightSkeletonBase.STL +0 -0
  120. package/dist/models/mocap/meshes/v5/link_RightSkeletonIndex1.STL +0 -0
  121. package/dist/models/mocap/meshes/v5/link_RightSkeletonIndex2.STL +0 -0
  122. package/dist/models/mocap/meshes/v5/link_RightSkeletonIndex3.STL +0 -0
  123. package/dist/models/mocap/meshes/v5/link_RightSkeletonIndex4.STL +0 -0
  124. package/dist/models/mocap/meshes/v5/link_RightSkeletonMiddle1.STL +0 -0
  125. package/dist/models/mocap/meshes/v5/link_RightSkeletonMiddle2.STL +0 -0
  126. package/dist/models/mocap/meshes/v5/link_RightSkeletonMiddle3.STL +0 -0
  127. package/dist/models/mocap/meshes/v5/link_RightSkeletonMiddle4.STL +0 -0
  128. package/dist/models/mocap/meshes/v5/link_RightSkeletonPinky1.STL +0 -0
  129. package/dist/models/mocap/meshes/v5/link_RightSkeletonPinky2.STL +0 -0
  130. package/dist/models/mocap/meshes/v5/link_RightSkeletonPinky3.STL +0 -0
  131. package/dist/models/mocap/meshes/v5/link_RightSkeletonPinky4.STL +0 -0
  132. package/dist/models/mocap/meshes/v5/link_RightSkeletonRing1.STL +0 -0
  133. package/dist/models/mocap/meshes/v5/link_RightSkeletonRing2.STL +0 -0
  134. package/dist/models/mocap/meshes/v5/link_RightSkeletonRing3.STL +0 -0
  135. package/dist/models/mocap/meshes/v5/link_RightSkeletonRing4.STL +0 -0
  136. package/dist/models/mocap/meshes/v5/link_RightSkeletonThumb1.STL +0 -0
  137. package/dist/models/mocap/meshes/v5/link_RightSkeletonThumb2.STL +0 -0
  138. package/dist/models/mocap/meshes/v5/link_RightSkeletonThumb3.STL +0 -0
  139. package/dist/models/mocap/meshes/v5/link_RightSkeletonThumb4.STL +0 -0
  140. package/dist/models/mocap/meshes/v5/link_RightSkeletonThumbBase.STL +0 -0
  141. package/dist/scripts/start-rosbridge.sh +77 -0
  142. package/dist/usd-iframe.html +41 -0
  143. package/dist/usd-viewer/bindings/.gitattributes +2 -0
  144. package/dist/usd-viewer/bindings/emHdBindings.data +19331 -0
  145. package/dist/usd-viewer/bindings/emHdBindings.js +12281 -0
  146. package/dist/usd-viewer/bindings/emHdBindings.wasm +0 -0
  147. package/dist/usd-viewer/bindings/emHdBindings.worker.js +124 -0
  148. package/dist/usd-viewer/environments/neutral.hdr +0 -0
  149. package/dist/usd-viewer/error-handler.js +57 -0
  150. package/dist/usd-viewer/hydra/HydraPrimitives.js +740 -0
  151. package/dist/usd-viewer/hydra/TextureRegistry.js +130 -0
  152. package/dist/usd-viewer/hydra/ThreeJsRenderDelegate.js +65 -0
  153. package/dist/usd-viewer/index.d.ts +1 -0
  154. package/dist/usd-viewer/main.js +1018 -0
  155. package/dist/usd-viewer/usd.html +36 -0
  156. package/dist/usd-viewer/usdUtils.js +67 -0
  157. package/package.json +70 -4
  158. package/server/package.json +14 -0
  159. package/server/static-server.js +106 -0
@@ -0,0 +1,1018 @@
1
+ import {
2
+ Vector3,
3
+ Box3,
4
+ PerspectiveCamera,
5
+ Scene,
6
+ Group,
7
+ WebGLRenderer,
8
+ SRGBColorSpace,
9
+ NeutralToneMapping,
10
+ VSMShadowMap,
11
+ PMREMGenerator,
12
+ EquirectangularReflectionMapping,
13
+ } from "three";
14
+ import { ThreeRenderDelegateInterface } from "./hydra/ThreeJsRenderDelegate.js";
15
+ import {
16
+ shouldInclude,
17
+ isUsdFile,
18
+ getFileFromHandle,
19
+ parseFilePath,
20
+ safeCall,
21
+ getEntryFile,
22
+ } from "./usdUtils.js";
23
+ import { RGBELoader } from "three/addons/loaders/RGBELoader.js";
24
+ import { OrbitControls } from "three/addons/controls/OrbitControls.js";
25
+ import { GLTFExporter } from "three/addons/exporters/GLTFExporter.js";
26
+ import "./bindings/emHdBindings.js";
27
+
28
+ const getUsdModule = globalThis["NEEDLE:USD:GET"];
29
+
30
+ const SKIP_DIRS = [
31
+ ".git",
32
+ "node_modules",
33
+ "__pycache__",
34
+ ".vscode",
35
+ ".idea",
36
+ "build",
37
+ "dist",
38
+ ".next",
39
+ ];
40
+ const SKIP_FILES = [
41
+ ".gitignore",
42
+ "README.md",
43
+ "LICENSE",
44
+ "package.json",
45
+ ".DS_Store",
46
+ ".env",
47
+ ];
48
+ const SYS_DIRS = ["/dev/", "/proc/", "/home/", "/tmp/", "/usd/"];
49
+
50
+ export function init(options = { container: null, hdrPath: null }) {
51
+ return new Promise((resolveInit) => {
52
+ if (!options?.container) {
53
+ throw new Error("init: options.container is required");
54
+ }
55
+ options.hdrPath ||= "/usd-viewer/environments/neutral.hdr";
56
+
57
+ let handle = null;
58
+
59
+ const run = () => {
60
+ let USD;
61
+ let resolveUsdReady;
62
+ const usdReady = new Promise((resolve) => {
63
+ resolveUsdReady = resolve;
64
+ });
65
+
66
+ // Install a lightweight fetch rewrite so requests to "/host/..." are
67
+ // mapped to the current asset base directory of the last loaded URL
68
+ function installFetchRewrite() {
69
+ if (window.__usdFetchRewritten) return;
70
+ const origFetch = window.fetch.bind(window);
71
+ window.fetch = (input, init) => {
72
+ try {
73
+ const url = typeof input === "string" ? input : input?.url;
74
+ if (url?.startsWith("/host/") && window.__usdAssetBase) {
75
+ const mapped = window.__usdAssetBase + url.substring(6);
76
+ return origFetch(mapped, init);
77
+ }
78
+ } catch {}
79
+ return origFetch(input, init);
80
+ };
81
+ window.__usdFetchRewritten = true;
82
+ }
83
+
84
+ let currentDisplayFilename = "";
85
+ const initPromise = setup();
86
+
87
+ console.log("Loading USD Module...");
88
+ try {
89
+ Promise.all([
90
+ getUsdModule({
91
+ mainScriptUrlOrBlob: "/usd-viewer/bindings/emHdBindings.js",
92
+ locateFile: (file) => {
93
+ return "/usd-viewer/bindings/" + file;
94
+ },
95
+ // Suppress noisy OpenUSD discovery warnings that don't affect functionality
96
+ printErr: (text) => {
97
+ try {
98
+ const s = String(text || "");
99
+ if (
100
+ s.includes("_FindAndInstantiateDiscoveryPlugins") ||
101
+ s.includes("/ndr/registry.cpp") ||
102
+ s.includes("Failed verification: ' pluginFactory '") ||
103
+ // Harmless when loading packaged USDZ read-only; USD attempts to save are blocked
104
+ s.includes("_WriteToFile") ||
105
+ s.includes("/sdf/layer.cpp") ||
106
+ s.includes(
107
+ "writing package usdz layer is not allowed through this API"
108
+ )
109
+ ) {
110
+ return;
111
+ }
112
+ } catch {}
113
+ // Fallback to standard error output for everything else
114
+ try {
115
+ console.error(text);
116
+ } catch {}
117
+ },
118
+ }),
119
+ initPromise,
120
+ ]).then(async ([Usd]) => {
121
+ USD = Usd;
122
+ if (resolveUsdReady) resolveUsdReady(USD);
123
+ animate();
124
+ });
125
+ } catch (error) {
126
+ if (error.toString().indexOf("SharedArrayBuffer") >= 0) {
127
+ console.log(
128
+ error,
129
+ "Your current browser doesn't support SharedArrayBuffer which is required for USD."
130
+ );
131
+ } else {
132
+ console.log(
133
+ "Your current browser doesn't support USD-for-web. Error during initialization: " +
134
+ error
135
+ );
136
+ }
137
+ }
138
+
139
+ let timeout = 40;
140
+ let endTimeCode = 1;
141
+ let ready = false;
142
+
143
+ const usdzExportBtn = document.getElementById("export-usdz");
144
+ if (usdzExportBtn)
145
+ usdzExportBtn.addEventListener("click", () => {
146
+ alert("usdz");
147
+ });
148
+
149
+ const gltfExportBtn = document.getElementById("export-gltf");
150
+ if (gltfExportBtn)
151
+ gltfExportBtn.addEventListener("click", (evt) => {
152
+ const exporter = new GLTFExporter();
153
+ console.log("EXPORTING GLTF", window.usdRoot);
154
+ exporter.parse(
155
+ window.usdRoot,
156
+ function (gltf) {
157
+ const blob = new Blob([gltf], {
158
+ type: "application/octet-stream",
159
+ });
160
+ const url = URL.createObjectURL(blob);
161
+ const a = document.createElement("a");
162
+ a.href = url;
163
+ let filename = currentDisplayFilename;
164
+ // strip extension, strip path
165
+ filename =
166
+ filename.split("/").pop()?.split(".")[0].split("?")[0] ||
167
+ "export";
168
+ a.download = filename + ".glb";
169
+ a.click();
170
+ URL.revokeObjectURL(url);
171
+ },
172
+ function (error) {
173
+ console.error(error);
174
+ },
175
+ {
176
+ binary: true,
177
+ // not possible right now since USD controls animation bindings,
178
+ // it's not a three.js clip
179
+ animations: [
180
+ // window.usdRoot.animations[0]
181
+ ],
182
+ }
183
+ );
184
+ evt.preventDefault();
185
+ });
186
+
187
+ function getAllLoadedFiles() {
188
+ const filePaths = [];
189
+
190
+ getAllLoadedFilePaths("/", filePaths);
191
+
192
+ return filePaths;
193
+ }
194
+
195
+ function getAllLoadedFilePaths(currentPath, paths) {
196
+ const files = USD.FS_readdir(currentPath);
197
+ for (const file of files) {
198
+ if (file === "." || file === "..") continue;
199
+ const newPath = currentPath + file + "/";
200
+ const data = USD.FS_analyzePath(currentPath + file + "/");
201
+ if (data.object.node_ops.readdir) {
202
+ if (!SYS_DIRS.includes(newPath))
203
+ getAllLoadedFilePaths(newPath, paths);
204
+ } else {
205
+ paths.push(data.path);
206
+ }
207
+ }
208
+ }
209
+
210
+ // safeCall imported
211
+
212
+ function clearStage() {
213
+ if (!USD) {
214
+ console.warn("USD not ready; skipping clearStage.");
215
+ return;
216
+ }
217
+ // Try to dispose the driver/stage first to avoid any layer save attempts
218
+ if (!safeCall(window.driver, "Dispose")) {
219
+ safeCall(window.driver, "Destroy");
220
+ }
221
+ // Clear the rendered scene graph before touching the virtual FS
222
+ safeCall(window.usdRoot, "clear");
223
+
224
+ // Then unlink files from the in-memory FS, but keep .usdz packages to
225
+ // avoid triggering writes to packaged layers
226
+ const allFilePaths = getAllLoadedFiles();
227
+ for (const file of allFilePaths) {
228
+ if (String(file).toLowerCase().endsWith(".usdz")) {
229
+ continue;
230
+ }
231
+ USD.FS_unlink(file, true);
232
+ }
233
+ }
234
+
235
+ function addPath(root, path) {
236
+ const files = USD.FS_readdir(path);
237
+ for (const file of files) {
238
+ if (file === "." || file === "..") continue;
239
+ const newPath = path + file + "/";
240
+ const data = USD.FS_analyzePath(path + file + "/");
241
+ if (data.object.node_ops.readdir) {
242
+ if (!SYS_DIRS.includes(newPath)) {
243
+ root[file] = {};
244
+ addPath(root[file], newPath);
245
+ }
246
+ } else {
247
+ root[file] = data;
248
+ }
249
+ }
250
+ }
251
+
252
+ async function loadUsdFile(directory, filename, path, isRootFile = true) {
253
+ currentDisplayFilename = filename;
254
+ ready = false;
255
+
256
+ // should be loaded last
257
+ if (!isRootFile) return;
258
+
259
+ let driver = null;
260
+ const delegateConfig = {
261
+ usdRoot: window.usdRoot,
262
+ paths: [],
263
+ driver: () => driver,
264
+ };
265
+
266
+ const renderInterface = (window.renderInterface =
267
+ new ThreeRenderDelegateInterface(delegateConfig));
268
+ driver = new USD.HdWebSyncDriver(renderInterface, path);
269
+ if (driver instanceof Promise) {
270
+ driver = await driver;
271
+ }
272
+ window.driver = driver;
273
+ window.driver.Draw();
274
+
275
+ let stage = window.driver.GetStage();
276
+ if (stage instanceof Promise) {
277
+ stage = await stage;
278
+ stage = window.driver.GetStage();
279
+ }
280
+ window.usdStage = stage;
281
+ if (stage.GetEndTimeCode) {
282
+ endTimeCode = stage.GetEndTimeCode();
283
+ timeout = 1000 / stage.GetTimeCodesPerSecond();
284
+ }
285
+
286
+ // if up axis is z, rotate, otherwise make sure rotation is 0, in case we rotated in the past and need to undo it
287
+ window.usdRoot.rotation.x =
288
+ String.fromCharCode(stage.GetUpAxis()) === "z" ? -Math.PI / 2 : 0;
289
+
290
+ fitCameraToSelection(window.camera, window._controls, [window.usdRoot]);
291
+ ready = true;
292
+
293
+ console.log('[USD Viewer] Loading complete! Scene state:');
294
+ console.log(' - usdRoot.children:', window.usdRoot.children.length);
295
+ console.log(' - camera.position:', window.camera.position);
296
+ console.log(' - renderer.domElement size:', {
297
+ width: window.renderer.domElement.width,
298
+ height: window.renderer.domElement.height,
299
+ clientWidth: window.renderer.domElement.clientWidth,
300
+ clientHeight: window.renderer.domElement.clientHeight
301
+ });
302
+
303
+ const root = {};
304
+ addPath(root, "/");
305
+ }
306
+
307
+ // from https://discourse.threejs.org/t/camera-zoom-to-fit-object/936/24
308
+ function fitCameraToSelection(
309
+ camera,
310
+ controls,
311
+ selection,
312
+ fitOffset = 1.5
313
+ ) {
314
+ const size = new Vector3();
315
+ const center = new Vector3();
316
+ const box = new Box3();
317
+
318
+ box.makeEmpty();
319
+ for (const object of selection) {
320
+ box.expandByObject(object);
321
+ }
322
+
323
+ box.getSize(size);
324
+ box.getCenter(center);
325
+
326
+ if (
327
+ Number.isNaN(size.x) ||
328
+ Number.isNaN(size.y) ||
329
+ Number.isNaN(size.z) ||
330
+ Number.isNaN(center.x) ||
331
+ Number.isNaN(center.y) ||
332
+ Number.isNaN(center.z)
333
+ ) {
334
+ console.warn(
335
+ "Fit Camera failed: NaN values found, some objects may not have any mesh data.",
336
+ selection,
337
+ size
338
+ );
339
+ if (controls) controls.update();
340
+ return;
341
+ }
342
+
343
+ if (!controls) {
344
+ console.warn(
345
+ "No camera controls object found, something went wrong."
346
+ );
347
+ return;
348
+ }
349
+
350
+ const maxSize = Math.max(size.x, size.y, size.z);
351
+ const fitHeightDistance =
352
+ maxSize / (2 * Math.atan((Math.PI * camera.fov) / 360));
353
+ const fitWidthDistance = fitHeightDistance / camera.aspect;
354
+ const distance =
355
+ fitOffset * Math.max(fitHeightDistance, fitWidthDistance);
356
+
357
+ if (distance == 0) {
358
+ console.warn(
359
+ "Fit Camera failed: distance is 0, some objects may not have any mesh data."
360
+ );
361
+ return;
362
+ }
363
+
364
+ camera.position.z = 7;
365
+ camera.position.y = 7;
366
+ camera.position.x = 0;
367
+
368
+ const direction = controls.target
369
+ .clone()
370
+ .sub(camera.position)
371
+ .normalize()
372
+ .multiplyScalar(distance);
373
+
374
+ controls.maxDistance = distance * 10;
375
+ controls.target.copy(center);
376
+
377
+ camera.near = distance / 100;
378
+ camera.far = distance * 100;
379
+
380
+ camera.updateProjectionMatrix();
381
+
382
+ camera.position.copy(controls.target).sub(direction);
383
+ controls.update();
384
+ }
385
+
386
+ async function setup() {
387
+ // Use container size instead of window size
388
+ const width = options.container.clientWidth || window.innerWidth || 800;
389
+ const height = options.container.clientHeight || window.innerHeight || 600;
390
+ const aspect = width / height;
391
+ console.log('[USD Viewer] Setup - container size:', { width, height, aspect });
392
+
393
+ const camera = (window.camera = new PerspectiveCamera(
394
+ 27,
395
+ aspect,
396
+ 1,
397
+ 3500
398
+ ));
399
+ camera.position.z = 7;
400
+ camera.position.y = 7;
401
+ camera.position.x = 0;
402
+
403
+ const scene = (window.scene = new Scene());
404
+
405
+ const usdRoot = (window.usdRoot = new Group());
406
+ usdRoot.name = "USD Root";
407
+ scene.add(usdRoot);
408
+
409
+ const renderer = (window.renderer = new WebGLRenderer({
410
+ antialias: true,
411
+ alpha: true,
412
+ }));
413
+ renderer.setPixelRatio(window.devicePixelRatio);
414
+
415
+ // Use previously declared width and height
416
+ console.log('[USD Viewer] Set renderer size:', { width, height });
417
+ renderer.setSize(width, height);
418
+ renderer.outputColorSpace = SRGBColorSpace;
419
+ renderer.toneMapping = NeutralToneMapping;
420
+ renderer.shadowMap.enabled = false;
421
+ renderer.shadowMap.type = VSMShadowMap;
422
+ // Use transparent background, inherit parent page style
423
+ renderer.setClearColor(0x000000, 0);
424
+
425
+ console.log('[USD Viewer] Renderer created:', {
426
+ domElement: renderer.domElement,
427
+ width: renderer.domElement.width,
428
+ height: renderer.domElement.height,
429
+ parent: renderer.domElement.parentElement
430
+ });
431
+
432
+ const envMapPromise = new Promise((resolve) => {
433
+ const pmremGenerator = new PMREMGenerator(renderer);
434
+ pmremGenerator.compileCubemapShader();
435
+
436
+ new RGBELoader().load(
437
+ options.hdrPath,
438
+ (texture) => {
439
+ const hdrRenderTarget =
440
+ pmremGenerator.fromEquirectangular(texture);
441
+
442
+ texture.mapping = EquirectangularReflectionMapping;
443
+ texture.needsUpdate = true;
444
+ scene.environment = hdrRenderTarget.texture;
445
+ resolve();
446
+ },
447
+ undefined,
448
+ (err) => {
449
+ console.error(
450
+ "An error occurred loading the HDR environment map.",
451
+ err
452
+ );
453
+ resolve();
454
+ }
455
+ );
456
+ });
457
+
458
+ console.log('[USD Viewer] Add renderer canvas to container:', options.container);
459
+ options.container.appendChild(renderer.domElement);
460
+ console.log('[USD Viewer] Canvas added, canvas element:', renderer.domElement);
461
+ const controls = (window._controls = new OrbitControls(
462
+ camera,
463
+ renderer.domElement
464
+ ));
465
+ controls.enableDamping = true;
466
+ controls.dampingFactor = 0.2;
467
+ controls.update();
468
+
469
+ window.addEventListener("resize", onWindowResize);
470
+
471
+ render();
472
+ return envMapPromise;
473
+ }
474
+
475
+ // Optional: pause helper removed to avoid global DOM coupling
476
+
477
+ async function animate() {
478
+ window._controls.update();
479
+ let secs = new Date().getTime() / 1000;
480
+ await new Promise((resolve) => setTimeout(resolve, 10));
481
+ const time = (secs * (1000 / timeout)) % endTimeCode;
482
+ if (
483
+ window.driver &&
484
+ window.driver.SetTime &&
485
+ window.driver.Draw &&
486
+ ready
487
+ ) {
488
+ window.driver.SetTime(time);
489
+ window.driver.Draw();
490
+ render();
491
+ }
492
+ requestAnimationFrame(animate.bind(null, timeout, endTimeCode));
493
+ }
494
+
495
+ function onWindowResize() {
496
+ const width = options.container?.clientWidth || window.innerWidth;
497
+ const height = options.container?.clientHeight || window.innerHeight;
498
+ camera.aspect = width / height;
499
+ camera.updateProjectionMatrix();
500
+ renderer.setSize(width, height);
501
+ console.log('[USD Viewer] Resize:', { width, height });
502
+ }
503
+
504
+ function render() {
505
+ // const time = Date.now() * 0.001;
506
+ if (window.renderer.render && window.scene) {
507
+ window.renderer.render(window.scene, window.camera);
508
+ }
509
+ }
510
+
511
+ // getFileFromHandle imported
512
+
513
+ // parseFilePath imported
514
+
515
+ async function loadFile(
516
+ fileOrHandle,
517
+ isRootFile = true,
518
+ fullPath = undefined
519
+ ) {
520
+ try {
521
+ const file = await getFileFromHandle(fileOrHandle);
522
+ const { fileName, directory } = parseFilePath(fullPath, file.name);
523
+
524
+ const reader = new FileReader();
525
+ const loadingPromise = new Promise((resolve, reject) => {
526
+ reader.onloadend = resolve;
527
+ reader.onerror = reject;
528
+ });
529
+
530
+ reader.onload = async function (event) {
531
+ // Ensure USD module is initialized before filesystem operations
532
+ if (!USD) await usdReady;
533
+
534
+ USD.FS_createPath("", directory, true, true);
535
+ // Mount file as read-only to prevent USD from attempting write-backs to packages
536
+ USD.FS_createDataFile(
537
+ directory,
538
+ fileName,
539
+ new Uint8Array(event.target.result),
540
+ true /* canRead */,
541
+ false /* canWrite */,
542
+ true /* canOwn */
543
+ );
544
+
545
+ loadUsdFile(directory, fileName, fullPath, isRootFile);
546
+ };
547
+
548
+ reader.readAsArrayBuffer(file);
549
+ await loadingPromise;
550
+ } catch (ex) {
551
+ console.warn("Error loading file", fileOrHandle, ex);
552
+ }
553
+ }
554
+
555
+ // isUsdFile imported
556
+
557
+ function testAndLoadFile(file) {
558
+ if (isUsdFile(file.name)) {
559
+ clearStage();
560
+ loadFile(file);
561
+ }
562
+ }
563
+
564
+ /**
565
+ * @param {FileSystemDirectoryEntry} directory
566
+ */
567
+ async function readDirectory(directory) {
568
+ let entries = [];
569
+
570
+ let getAllDirectoryEntries = async (dirReader) => {
571
+ let entries = [];
572
+ let readEntries = async () => {
573
+ let result = await new Promise((resolve, reject) =>
574
+ dirReader.readEntries(resolve, reject)
575
+ );
576
+ if (result.length === 0) return entries;
577
+ else return entries.concat(result, await readEntries());
578
+ };
579
+ return await readEntries();
580
+ };
581
+
582
+ /**
583
+ * @param {FileSystemDirectoryReader} dirReader
584
+ * @param {FileSystemDirectoryEntry} directory
585
+ * @returns {Promise<number>}
586
+ */
587
+ let getEntries = async (directory) => {
588
+ let dirReader = directory.createReader();
589
+ await new Promise(async (resolve) => {
590
+ // Call the reader.readEntries() until no more results are returned.
591
+
592
+ const results = await getAllDirectoryEntries(dirReader);
593
+
594
+ if (results.length) {
595
+ // entries = entries.concat(results);
596
+ for (let entry of results) {
597
+ if (entry.isDirectory) {
598
+ const foundFiles = await getEntries(entry);
599
+ if (foundFiles === 100)
600
+ console.warn(
601
+ "Found more than 100 files in directory",
602
+ entry
603
+ );
604
+ } else {
605
+ entries.push(entry);
606
+ }
607
+ }
608
+ }
609
+ resolve(results.length);
610
+ });
611
+ };
612
+
613
+ await getEntries(directory);
614
+ return entries;
615
+ }
616
+
617
+ /**
618
+ * @param {FileSystemEntry[]} entries
619
+ */
620
+ async function handleFilesystemEntries(entries) {
621
+ const allFiles = [];
622
+
623
+ for (let entry of entries) {
624
+ if (entry.isFile) {
625
+ if (shouldInclude(entry.name)) allFiles.push(entry);
626
+ } else if (entry.isDirectory) {
627
+ if (SKIP_DIRS.includes(entry.name)) continue;
628
+ const files = await readDirectory(entry);
629
+ allFiles.push(...files.filter((file) => shouldInclude(file.name)));
630
+ }
631
+ }
632
+
633
+ // clear current set of files
634
+ clearStage();
635
+
636
+ // Find root file candidates
637
+ const usdFiles = allFiles.filter((file) => isUsdFile(file.name));
638
+ const usdaFiles = usdFiles.filter((file) =>
639
+ file.name.endsWith(".usda")
640
+ );
641
+
642
+ // Prefer .usda files, otherwise use first USD file
643
+ let rootFile = usdaFiles[0] || usdFiles[0];
644
+
645
+ if (rootFile) {
646
+ allFiles.splice(allFiles.indexOf(rootFile), 1);
647
+ } else {
648
+ console.warn("No USD file found");
649
+ return;
650
+ }
651
+
652
+ const getFile = getEntryFile;
653
+
654
+ // Mount all non-root files concurrently; order doesn't matter as we load the root last
655
+
656
+ // Load all non-root files into memory
657
+ const loadPromises = allFiles.map(async (file) => {
658
+ const fileObj = await getFile(file);
659
+ if (fileObj) await loadFile(fileObj, false, file.fullPath);
660
+ });
661
+ await Promise.all(loadPromises);
662
+
663
+ // Load the root file last
664
+ if (rootFile) {
665
+ if (!isUsdFile(rootFile.name)) {
666
+ console.error("Not a supported file format:", rootFile.name);
667
+ } else {
668
+ const rootFileObj = await getFile(rootFile);
669
+ if (rootFileObj) loadFile(rootFileObj, true, rootFile.fullPath);
670
+ }
671
+ }
672
+ }
673
+
674
+ /**
675
+ * @param {DataTransfer} dataTransfer
676
+ */
677
+ function processDataTransfer(dataTransfer) {
678
+ if (dataTransfer.items) {
679
+ /** @type {FileSystemEntry[]} */
680
+ const allEntries = [];
681
+
682
+ let haveGetAsEntry = false;
683
+ if (dataTransfer.items.length > 0)
684
+ haveGetAsEntry =
685
+ "getAsEntry" in dataTransfer.items[0] ||
686
+ "webkitGetAsEntry" in dataTransfer.items[0];
687
+
688
+ if (haveGetAsEntry) {
689
+ for (const item of dataTransfer.items) {
690
+ /** @type {FileSystemEntry} */
691
+ const entry =
692
+ "getAsEntry" in item
693
+ ? item.getAsEntry()
694
+ : item.webkitGetAsEntry();
695
+ allEntries.push(entry);
696
+ }
697
+ handleFilesystemEntries(allEntries);
698
+ return;
699
+ }
700
+
701
+ for (const item of dataTransfer.items) {
702
+ // API when there's no "getAsEntry" support
703
+ console.log(item.kind, item);
704
+ if (item.kind === "file") {
705
+ var file = item.getAsFile();
706
+ testAndLoadFile(file);
707
+ }
708
+ // could also be a directory
709
+ else if (item.kind === "directory") {
710
+ var dirReader = item.createReader();
711
+ dirReader.readEntries(function (entries) {
712
+ for (var i = 0; i < entries.length; i++) {
713
+ console.log(entries[i].name);
714
+ var entry = entries[i];
715
+ if (entry.isFile) {
716
+ entry.file(function (file) {
717
+ testAndLoadFile(file);
718
+ });
719
+ }
720
+ }
721
+ });
722
+ }
723
+ }
724
+ } else {
725
+ for (const file of dataTransfer.files) {
726
+ testAndLoadFile(file);
727
+ }
728
+ }
729
+ }
730
+
731
+ // Provide a minimal imperative API to the host (capturing the local scope)
732
+ handle = {
733
+ // Load a USD file from a URL
734
+ loadFromURL: async (url) => {
735
+ try {
736
+ if (!USD) await usdReady;
737
+ clearStage();
738
+ const parts = url.split("/");
739
+ const fileNameOnly = parts[parts.length - 1];
740
+ // For packaged usdz, mount read-only to avoid write attempts
741
+ if (fileNameOnly.toLowerCase().endsWith(".usdz")) {
742
+ const res = await fetch(url, { cache: "no-store" });
743
+ if (!res.ok) throw new Error("Failed to fetch " + url);
744
+ const buffer = await res.arrayBuffer();
745
+ const mountDir = "/host/";
746
+ USD.FS_createPath("", mountDir, true, true);
747
+ // If a previous package exists at the same path, remove it now that the stage is cleared
748
+ try {
749
+ const existing = USD.FS_analyzePath(mountDir + fileNameOnly);
750
+ if (existing?.exists) {
751
+ USD.FS_unlink(mountDir + fileNameOnly);
752
+ }
753
+ } catch {}
754
+ USD.FS_createDataFile(
755
+ mountDir,
756
+ fileNameOnly,
757
+ new Uint8Array(buffer),
758
+ true /* canRead */,
759
+ false /* canWrite */,
760
+ true /* canOwn */
761
+ );
762
+ await loadUsdFile(
763
+ mountDir,
764
+ fileNameOnly,
765
+ mountDir + fileNameOnly,
766
+ true
767
+ );
768
+ } else {
769
+ // For usd/usda/usdc, keep URL so relative asset paths resolve via HTTP
770
+ try {
771
+ const base = new URL(url, window.location.origin);
772
+ // ensure base URL ends with '/'
773
+ const baseDir = base.href.substring(
774
+ 0,
775
+ base.href.lastIndexOf("/") + 1
776
+ );
777
+ window.__usdAssetBase = baseDir;
778
+ installFetchRewrite();
779
+ } catch {}
780
+ await loadUsdFile(undefined, fileNameOnly, url, true);
781
+ }
782
+ } catch (e) {
783
+ console.warn("loadFromURL error", e);
784
+ }
785
+ },
786
+ // Load from array buffer entries mounted into the in-memory FS
787
+ loadFromEntries: async (entries, primaryPath) => {
788
+ try {
789
+ if (!USD) await usdReady;
790
+ clearStage();
791
+ // Mount all entries first (order doesn't matter since we load the root explicitly last)
792
+ const list = (entries || []).slice();
793
+ for (const { path, buffer } of list) {
794
+ const fileName = path.split("/").pop();
795
+ let dir = path.slice(0, path.length - (fileName?.length || 0));
796
+ // Ensure dir is at least "/", cannot be empty string
797
+ if (!dir || dir === "") {
798
+ dir = "/";
799
+ }
800
+ // Remove trailing slash (if present)
801
+ if (dir.length > 1 && dir.endsWith("/")) {
802
+ dir = dir.slice(0, -1);
803
+ }
804
+ console.log('[USD] Mount file:', { path, fileName, dir });
805
+ USD.FS_createPath("", dir, true, true);
806
+ USD.FS_createDataFile(
807
+ dir,
808
+ fileName,
809
+ new Uint8Array(buffer),
810
+ true /* canRead */,
811
+ false /* canWrite */,
812
+ true /* canOwn */
813
+ );
814
+ }
815
+ // Determine root
816
+ let root = primaryPath;
817
+ if (root) {
818
+ // primaryPath may only be filename, need to find full path in list
819
+ const foundEntry = list.find((e) => e.path.endsWith(root) || e.path === root);
820
+ if (foundEntry) {
821
+ root = foundEntry.path;
822
+ console.log('[USD] primaryPath matched to full path:', root);
823
+ } else {
824
+ console.warn('[USD] primaryPath not found:', primaryPath);
825
+ }
826
+ }
827
+ if (!root) {
828
+ // Prefer .usda, else any USD
829
+ root =
830
+ list.find((e) => e.path.endsWith(".usda"))?.path ||
831
+ list.find((e) => isUsdFile(e.path))?.path;
832
+ console.log('[USD] Auto-detected root file:', root);
833
+ }
834
+ if (root) {
835
+ const fileNameOnly = root.split("/").pop();
836
+ let dir = root.slice(0, root.length - (fileNameOnly?.length || 0));
837
+ if (!dir || dir === "") {
838
+ dir = "/";
839
+ }
840
+ if (dir.length > 1 && dir.endsWith("/")) {
841
+ dir = dir.slice(0, -1);
842
+ }
843
+ console.log('[USD] Load root file:', { root, dir, fileNameOnly });
844
+ await loadUsdFile(dir, fileNameOnly, root, true);
845
+ }
846
+ } catch (e) {
847
+ console.warn("loadFromEntries error", e);
848
+ }
849
+ },
850
+ // Load from a DataTransfer (e.g., from a drag/drop event)
851
+ loadFromDataTransfer: async (dataTransfer) => {
852
+ try {
853
+ if (!USD) await usdReady;
854
+ processDataTransfer(dataTransfer);
855
+ } catch (e) {
856
+ console.warn("loadFromDataTransfer error", e);
857
+ }
858
+ },
859
+ // Load directly from a FileList or array of File
860
+ loadFromFiles: async (files) => {
861
+ try {
862
+ if (!USD) await usdReady;
863
+ clearStage();
864
+ const fileArray = Array.from(files);
865
+ for (const file of fileArray) testAndLoadFile(file);
866
+ } catch (e) {
867
+ console.warn("loadFromFiles error", e);
868
+ }
869
+ },
870
+ // Load from a map of virtual paths -> File, with an optional primary root file path
871
+ loadFromFilesMap: async (filesMap, primaryPath) => {
872
+ try {
873
+ if (!USD) await usdReady;
874
+ clearStage();
875
+ const entries = Object.entries(filesMap).filter(([p]) => {
876
+ const name = p.split("/").pop() || p;
877
+ return (
878
+ !SKIP_FILES.includes(name) &&
879
+ !name.startsWith("._") &&
880
+ shouldInclude(name)
881
+ );
882
+ });
883
+ // Load all non-root files first
884
+ for (const [fullPath, file] of entries) {
885
+ if (primaryPath && fullPath === primaryPath) continue;
886
+ await loadFile(file, false, fullPath);
887
+ }
888
+ // Then load the primary/root if provided, else try to detect
889
+ if (primaryPath && filesMap[primaryPath]) {
890
+ await loadFile(filesMap[primaryPath], true, primaryPath);
891
+ return;
892
+ }
893
+ // Detect a reasonable root (prefer .usda)
894
+ const usdaRoot = entries.find(([p]) => p.endsWith(".usda"));
895
+ const anyUsdRoot = entries.find(([p]) => isUsdFile(p));
896
+ const root = usdaRoot || anyUsdRoot;
897
+ if (root) {
898
+ await loadFile(root[1], true, root[0]);
899
+ }
900
+ } catch (e) {
901
+ console.warn("loadFromFilesMap error", e);
902
+ }
903
+ },
904
+ // Clear the current stage
905
+ clear: () => {
906
+ try {
907
+ clearStage();
908
+ } catch (e) {
909
+ console.warn("clear error", e);
910
+ }
911
+ },
912
+ // Dispose the viewer and remove listeners/canvas
913
+ dispose: () => {
914
+ try {
915
+ window.removeEventListener("resize", onWindowResize);
916
+ if (window.renderer && window.renderer.domElement) {
917
+ if (options.container.contains(window.renderer.domElement)) {
918
+ options.container.removeChild(window.renderer.domElement);
919
+ }
920
+ if (window.renderer.dispose) window.renderer.dispose();
921
+ }
922
+ } catch (e) {
923
+ console.warn("dispose error", e);
924
+ }
925
+ },
926
+ };
927
+ };
928
+
929
+ if (document.readyState === "loading") {
930
+ document.addEventListener(
931
+ "DOMContentLoaded",
932
+ () => {
933
+ run();
934
+ try {
935
+ if (resolveInit) resolveInit(handle);
936
+ } catch {}
937
+ },
938
+ { once: true }
939
+ );
940
+ } else {
941
+ run();
942
+ try {
943
+ if (resolveInit) resolveInit(handle);
944
+ } catch {}
945
+ }
946
+ });
947
+ }
948
+
949
+ // Auto-initialize when loaded as a module
950
+ let handle = null;
951
+
952
+ // Create container dynamically with proper size
953
+ const container = document.createElement("div");
954
+ container.style.cssText = `
955
+ width: 100%;
956
+ height: 100vh;
957
+ position: absolute;
958
+ top: 0;
959
+ left: 0;
960
+ `;
961
+ document.body.appendChild(container);
962
+
963
+ function post(type, payload = {}) {
964
+ try {
965
+ parent.postMessage({ type, ...payload }, "*");
966
+ } catch {}
967
+ }
968
+
969
+ async function bootstrap() {
970
+ try {
971
+ handle = await init({
972
+ container,
973
+ hdrPath: "/usd-viewer/environments/neutral.hdr",
974
+ });
975
+ } catch (e) {
976
+ console.warn("[USD Iframe] init error", e);
977
+ } finally {
978
+ post("IFRAME_READY");
979
+ }
980
+ }
981
+
982
+ // helper to load entries [{ path, buffer(ArrayBuffer) }, ...]
983
+ async function loadFromEntries(entries, primaryPath) {
984
+ try {
985
+ if (!handle?.loadFromEntries) return;
986
+ await handle.loadFromEntries(entries, primaryPath);
987
+ } catch (e) {
988
+ console.warn("[USD Iframe] loadFromEntries error", e);
989
+ }
990
+ }
991
+
992
+ window.addEventListener("message", async (evt) => {
993
+ const data = evt.data;
994
+ if (!data || typeof data !== "object") return;
995
+ try {
996
+ switch (data.type) {
997
+ case "USD_LOAD_URL":
998
+ post("USD_LOADING_START");
999
+ await handle?.loadFromURL?.(data.url);
1000
+ post("USD_LOADED");
1001
+ break;
1002
+ case "USD_CLEAR":
1003
+ await handle?.clear?.();
1004
+ break;
1005
+ case "USD_LOAD_ENTRIES":
1006
+ post("USD_LOADING_START");
1007
+ await loadFromEntries(data.entries || [], data.primaryPath);
1008
+ post("USD_LOADED");
1009
+ break;
1010
+ default:
1011
+ break;
1012
+ }
1013
+ } catch (e) {
1014
+ console.warn("[USD Iframe] message error", e);
1015
+ }
1016
+ });
1017
+
1018
+ bootstrap();