@plasius/gpu-shared 0.1.13 → 0.1.15

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 (41) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +70 -3
  3. package/dist/{chunk-NCPJWLX3.js → chunk-2GM64LB6.js} +1 -9
  4. package/dist/{chunk-NCPJWLX3.js.map → chunk-2GM64LB6.js.map} +1 -1
  5. package/dist/chunk-6SOHFUOE.js +403 -0
  6. package/dist/chunk-6SOHFUOE.js.map +1 -0
  7. package/dist/{chunk-DABW627O.js → chunk-CH3ZS5TQ.js} +7 -1
  8. package/dist/chunk-CH3ZS5TQ.js.map +1 -0
  9. package/dist/chunk-DGUM43GV.js +11 -0
  10. package/dist/{chunk-DQX4DXBR.js → chunk-QVNRTWHB.js} +82 -6
  11. package/dist/chunk-QVNRTWHB.js.map +1 -0
  12. package/dist/dist-B5R2GZQR.js +1433 -0
  13. package/dist/dist-B5R2GZQR.js.map +1 -0
  14. package/dist/gltf-loader-B6VOWGBV.js +9 -0
  15. package/dist/index.cjs +2408 -5913
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.js +55 -5
  18. package/dist/index.js.map +1 -1
  19. package/dist/product-studio-runtime-BYVBUWIN.js +12 -0
  20. package/dist/product-studio-runtime-BYVBUWIN.js.map +1 -0
  21. package/dist/showcase-inline-assets-QRQKXGVX.js +8 -0
  22. package/dist/showcase-inline-assets-QRQKXGVX.js.map +1 -0
  23. package/dist/showcase-runtime-M6TEUYOG.js +3786 -0
  24. package/dist/showcase-runtime-M6TEUYOG.js.map +1 -0
  25. package/package.json +7 -10
  26. package/src/feature-flags.js +1 -0
  27. package/src/gltf-loader.js +14 -2
  28. package/src/index.d.ts +73 -1
  29. package/src/index.js +67 -0
  30. package/src/product-studio-runtime.js +466 -0
  31. package/src/showcase-runtime.js +875 -72
  32. package/dist/chunk-2FIFSBB4.js +0 -74
  33. package/dist/chunk-2FIFSBB4.js.map +0 -1
  34. package/dist/chunk-DABW627O.js.map +0 -1
  35. package/dist/chunk-DQX4DXBR.js.map +0 -1
  36. package/dist/gltf-loader-WAM23F37.js +0 -9
  37. package/dist/showcase-inline-assets-B7U7VX5H.js +0 -7
  38. package/dist/showcase-runtime-PN7N3FZY.js +0 -9164
  39. package/dist/showcase-runtime-PN7N3FZY.js.map +0 -1
  40. /package/dist/{gltf-loader-WAM23F37.js.map → chunk-DGUM43GV.js.map} +0 -0
  41. /package/dist/{showcase-inline-assets-B7U7VX5H.js.map → gltf-loader-B6VOWGBV.js.map} +0 -0
@@ -0,0 +1,403 @@
1
+ import {
2
+ loadGltfModel
3
+ } from "./chunk-QVNRTWHB.js";
4
+
5
+ // src/product-studio-runtime.js
6
+ var STYLE_ID = "plasius-product-studio-wavefront-style";
7
+ var DEFAULT_PRODUCT_ASSET_URL = "/data/models/eames-lounge-chair-ottoman/Eames_Lounge_Chair_Ottoman.gltf";
8
+ var DEFAULT_TARGET_CENTER = Object.freeze([0, 0.74, 0]);
9
+ var DEFAULT_TARGET_SIZE = 2.25;
10
+ function clamp(value, min, max) {
11
+ return Math.max(min, Math.min(max, value));
12
+ }
13
+ function isFiniteVector(value) {
14
+ return Array.isArray(value) && value.length >= 3 && Number.isFinite(value[0]) && Number.isFinite(value[1]) && Number.isFinite(value[2]);
15
+ }
16
+ function createEmptyBounds() {
17
+ return {
18
+ min: [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],
19
+ max: [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY]
20
+ };
21
+ }
22
+ function expandBounds(bounds, point) {
23
+ bounds.min[0] = Math.min(bounds.min[0], point[0]);
24
+ bounds.min[1] = Math.min(bounds.min[1], point[1]);
25
+ bounds.min[2] = Math.min(bounds.min[2], point[2]);
26
+ bounds.max[0] = Math.max(bounds.max[0], point[0]);
27
+ bounds.max[1] = Math.max(bounds.max[1], point[1]);
28
+ bounds.max[2] = Math.max(bounds.max[2], point[2]);
29
+ }
30
+ function getBoundsSize(bounds) {
31
+ return [
32
+ bounds.max[0] - bounds.min[0],
33
+ bounds.max[1] - bounds.min[1],
34
+ bounds.max[2] - bounds.min[2]
35
+ ];
36
+ }
37
+ function getBoundsCenter(bounds) {
38
+ return [
39
+ (bounds.min[0] + bounds.max[0]) * 0.5,
40
+ (bounds.min[1] + bounds.max[1]) * 0.5,
41
+ (bounds.min[2] + bounds.max[2]) * 0.5
42
+ ];
43
+ }
44
+ function getModelBounds(model) {
45
+ if (isFiniteVector(model?.bounds?.min) && isFiniteVector(model?.bounds?.max)) {
46
+ return {
47
+ min: [...model.bounds.min],
48
+ max: [...model.bounds.max]
49
+ };
50
+ }
51
+ const bounds = createEmptyBounds();
52
+ for (const primitive of model?.primitives ?? []) {
53
+ for (let index = 0; index < primitive.positions.length; index += 3) {
54
+ expandBounds(bounds, [
55
+ primitive.positions[index],
56
+ primitive.positions[index + 1],
57
+ primitive.positions[index + 2]
58
+ ]);
59
+ }
60
+ }
61
+ return bounds;
62
+ }
63
+ function transformPoint(point, modelCenter, scale, targetCenter) {
64
+ return [
65
+ (point[0] - modelCenter[0]) * scale + targetCenter[0],
66
+ (point[1] - modelCenter[1]) * scale + targetCenter[1],
67
+ (point[2] - modelCenter[2]) * scale + targetCenter[2]
68
+ ];
69
+ }
70
+ function readMaterialColor(material) {
71
+ const color = material?.color ?? {};
72
+ return [
73
+ Number.isFinite(color.r) ? color.r : 0.62,
74
+ Number.isFinite(color.g) ? color.g : 0.56,
75
+ Number.isFinite(color.b) ? color.b : 0.48,
76
+ Number.isFinite(color.a) ? color.a : 1
77
+ ];
78
+ }
79
+ function readMaterialKind(material) {
80
+ const emissive = material?.emissive ?? {};
81
+ if ((emissive.r ?? 0) + (emissive.g ?? 0) + (emissive.b ?? 0) > 1e-3) {
82
+ return "emissive";
83
+ }
84
+ if ((material?.metallic ?? 0) >= 0.5) {
85
+ return "metal";
86
+ }
87
+ const alpha = readMaterialColor(material)[3];
88
+ if (alpha < 0.9) {
89
+ return "transparent";
90
+ }
91
+ return "diffuse";
92
+ }
93
+ function readEmission(material) {
94
+ const emissive = material?.emissive ?? {};
95
+ return [
96
+ Number.isFinite(emissive.r) ? emissive.r : 0,
97
+ Number.isFinite(emissive.g) ? emissive.g : 0,
98
+ Number.isFinite(emissive.b) ? emissive.b : 0,
99
+ 1
100
+ ];
101
+ }
102
+ function createQuadMesh({
103
+ id,
104
+ corners,
105
+ color,
106
+ emission = [0, 0, 0, 1],
107
+ materialKind = "diffuse",
108
+ roughness = 0.72,
109
+ metallic = 0,
110
+ opacity = color[3] ?? 1
111
+ }) {
112
+ const [a, b, c] = corners;
113
+ const edge1 = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
114
+ const edge2 = [c[0] - a[0], c[1] - a[1], c[2] - a[2]];
115
+ const normal = [
116
+ edge1[1] * edge2[2] - edge1[2] * edge2[1],
117
+ edge1[2] * edge2[0] - edge1[0] * edge2[2],
118
+ edge1[0] * edge2[1] - edge1[1] * edge2[0]
119
+ ];
120
+ const length = Math.hypot(normal[0], normal[1], normal[2]) || 1;
121
+ const unitNormal = normal.map((value) => value / length);
122
+ return Object.freeze({
123
+ id,
124
+ positions: Object.freeze(corners.flat()),
125
+ indices: Object.freeze([0, 1, 2, 0, 2, 3]),
126
+ normals: Object.freeze([unitNormal, unitNormal, unitNormal, unitNormal].flat()),
127
+ color: Object.freeze([...color]),
128
+ emission: Object.freeze([...emission]),
129
+ materialKind,
130
+ roughness,
131
+ metallic,
132
+ opacity
133
+ });
134
+ }
135
+ function createProductStudioEnvironmentMeshes() {
136
+ return [
137
+ createQuadMesh({
138
+ id: 1,
139
+ corners: [
140
+ [-3.2, -0.08, 2.4],
141
+ [3.2, -0.08, 2.4],
142
+ [3.2, -0.08, -3.1],
143
+ [-3.2, -0.08, -3.1]
144
+ ],
145
+ color: [0.48, 0.55, 0.55, 1],
146
+ roughness: 0.82
147
+ }),
148
+ createQuadMesh({
149
+ id: 2,
150
+ corners: [
151
+ [-3.2, -0.08, -2.45],
152
+ [3.2, -0.08, -2.45],
153
+ [3.2, 2.65, -2.45],
154
+ [-3.2, 2.65, -2.45]
155
+ ],
156
+ color: [0.43, 0.42, 0.38, 1],
157
+ roughness: 0.86
158
+ }),
159
+ createQuadMesh({
160
+ id: 3,
161
+ corners: [
162
+ [-2.85, -0.08, -2.45],
163
+ [-2.85, 2.55, -2.45],
164
+ [-2.85, 2.55, 2.15],
165
+ [-2.85, -0.08, 2.15]
166
+ ],
167
+ color: [0.36, 0.42, 0.45, 1],
168
+ roughness: 0.8
169
+ }),
170
+ createQuadMesh({
171
+ id: 4,
172
+ corners: [
173
+ [0.78, 2.55, -0.82],
174
+ [-0.78, 2.55, -0.82],
175
+ [-0.78, 2.55, -1.78],
176
+ [0.78, 2.55, -1.78]
177
+ ],
178
+ color: [1, 0.94, 0.78, 1],
179
+ emission: [8.5, 7.2, 4.8, 1],
180
+ materialKind: "emissive",
181
+ roughness: 0
182
+ })
183
+ ];
184
+ }
185
+ function createProductStudioMeshFromPrimitive(primitive, primitiveIndex, transform) {
186
+ if (!Array.isArray(primitive?.positions) || primitive.positions.length < 9) {
187
+ return null;
188
+ }
189
+ const positions = [];
190
+ for (let index = 0; index < primitive.positions.length; index += 3) {
191
+ const point = transform([
192
+ primitive.positions[index],
193
+ primitive.positions[index + 1],
194
+ primitive.positions[index + 2]
195
+ ]);
196
+ positions.push(point[0], point[1], point[2]);
197
+ }
198
+ const indices = Array.isArray(primitive.indices) && primitive.indices.length >= 3 ? [...primitive.indices] : Array.from({ length: positions.length / 3 }, (_, index) => index);
199
+ const material = primitive.material ?? {};
200
+ const color = readMaterialColor(material);
201
+ return Object.freeze({
202
+ id: 1e3 + primitiveIndex,
203
+ positions: Object.freeze(positions),
204
+ indices: Object.freeze(indices),
205
+ normals: Array.isArray(primitive.normals) ? Object.freeze([...primitive.normals]) : null,
206
+ color: Object.freeze(color),
207
+ emission: Object.freeze(readEmission(material)),
208
+ materialKind: readMaterialKind(material),
209
+ materialRefId: 1e3 + primitiveIndex,
210
+ roughness: Number.isFinite(material.roughness) ? material.roughness : 0.72,
211
+ metallic: Number.isFinite(material.metallic) ? material.metallic : 0,
212
+ opacity: color[3]
213
+ });
214
+ }
215
+ function createProductStudioMeshes(model, options = {}) {
216
+ const primitives = Array.isArray(model?.primitives) ? model.primitives : [];
217
+ if (primitives.length === 0) {
218
+ throw new Error("Product Studio model must contain at least one renderable primitive.");
219
+ }
220
+ const targetCenter = isFiniteVector(options.targetCenter) ? [...options.targetCenter] : [...DEFAULT_TARGET_CENTER];
221
+ const targetSize = Number.isFinite(options.targetSize) ? Math.max(options.targetSize, 0.25) : DEFAULT_TARGET_SIZE;
222
+ const modelBounds = getModelBounds(model);
223
+ const modelSize = getBoundsSize(modelBounds);
224
+ const modelCenter = getBoundsCenter(modelBounds);
225
+ const scale = targetSize / Math.max(modelSize[0], modelSize[1], modelSize[2], 1e-6);
226
+ const transform = (point) => transformPoint(point, modelCenter, scale, targetCenter);
227
+ const modelMeshes = primitives.map((primitive, index) => createProductStudioMeshFromPrimitive(primitive, index, transform)).filter(Boolean);
228
+ return Object.freeze([...createProductStudioEnvironmentMeshes(), ...modelMeshes]);
229
+ }
230
+ function ensureStyles(documentRef) {
231
+ if (documentRef.getElementById?.(STYLE_ID)) {
232
+ return;
233
+ }
234
+ const style = documentRef.createElement("style");
235
+ style.id = STYLE_ID;
236
+ style.textContent = `
237
+ .plasius-product-studio-wavefront {
238
+ position: relative;
239
+ width: 100%;
240
+ min-height: 420px;
241
+ overflow: hidden;
242
+ background: #0f1418;
243
+ display: grid;
244
+ place-items: center;
245
+ }
246
+
247
+ .plasius-product-studio-wavefront canvas {
248
+ display: block;
249
+ width: 100%;
250
+ height: auto;
251
+ max-height: 100%;
252
+ aspect-ratio: 16 / 9;
253
+ min-height: 420px;
254
+ object-fit: contain;
255
+ }
256
+ `;
257
+ documentRef.head?.appendChild?.(style);
258
+ }
259
+ function resolveRoot(options) {
260
+ const documentRef = options.document ?? globalThis.document;
261
+ if (options.root) {
262
+ return options.root;
263
+ }
264
+ const root = documentRef?.querySelector?.("[data-plasius-gpu-product-studio]") ?? documentRef?.body;
265
+ if (!root) {
266
+ throw new Error("Product Studio requires a DOM root.");
267
+ }
268
+ return root;
269
+ }
270
+ function resolveRenderSize(root, options) {
271
+ const rect = root.getBoundingClientRect?.() ?? { width: 1280, height: 720 };
272
+ const devicePixelRatio = Number.isFinite(options.devicePixelRatio) ? options.devicePixelRatio : Number.isFinite(globalThis.window?.devicePixelRatio) ? globalThis.window.devicePixelRatio : 1;
273
+ const cssWidth = Number.isFinite(rect.width) && rect.width > 0 ? rect.width : 1280;
274
+ const cssHeight = Number.isFinite(rect.height) && rect.height > 0 ? rect.height : cssWidth * (9 / 16);
275
+ const width = Number.isFinite(options.width) ? Math.trunc(options.width) : clamp(Math.round(cssWidth * devicePixelRatio), 640, 1920);
276
+ const height = Number.isFinite(options.height) ? Math.trunc(options.height) : clamp(Math.round(cssHeight * devicePixelRatio), 360, 1080);
277
+ return {
278
+ width,
279
+ height
280
+ };
281
+ }
282
+ function installSnapshotHook(state) {
283
+ if (typeof globalThis.window === "undefined") {
284
+ return () => {
285
+ };
286
+ }
287
+ const previous = globalThis.window.render_game_to_text;
288
+ globalThis.window.render_game_to_text = () => JSON.stringify({
289
+ surface: "gpu-product-studio-wavefront",
290
+ model: state.modelName,
291
+ sourceTriangles: state.sourceTriangleCount,
292
+ meshCount: state.meshCount,
293
+ geometryMode: state.geometryMode,
294
+ requiresTriangleMeshRenderer: state.requiresTriangleMeshRenderer,
295
+ displayQuality: state.displayQuality,
296
+ requiresMeshBvhForDisplayQuality: state.requiresMeshBvhForDisplayQuality,
297
+ renderer: state.rendererStats
298
+ });
299
+ return () => {
300
+ if (previous === void 0) {
301
+ delete globalThis.window.render_game_to_text;
302
+ } else {
303
+ globalThis.window.render_game_to_text = previous;
304
+ }
305
+ };
306
+ }
307
+ function countSourceTriangles(model) {
308
+ return (model.primitives ?? []).reduce(
309
+ (total, primitive) => total + Math.floor((primitive.indices?.length ?? 0) / 3),
310
+ 0
311
+ );
312
+ }
313
+ async function resolveWavefrontLightingOptions(options) {
314
+ const fallback = {
315
+ environmentColor: [0.35, 0.43, 0.49, 1],
316
+ ambientColor: [0.02, 0.024, 0.028, 1]
317
+ };
318
+ const lightingLoader = typeof options.__lightingLoader === "function" ? options.__lightingLoader : () => import("./dist-B5R2GZQR.js").catch(() => null);
319
+ const lightingModule = await lightingLoader();
320
+ if (typeof lightingModule?.createWavefrontEnvironmentLightingOptions !== "function") {
321
+ return fallback;
322
+ }
323
+ return lightingModule.createWavefrontEnvironmentLightingOptions({
324
+ preset: options.lightingPreset ?? "product-studio",
325
+ intensity: options.lightingIntensity
326
+ });
327
+ }
328
+ async function mountGpuProductStudio(options = {}, featureFlags = null) {
329
+ const root = resolveRoot(options);
330
+ const documentRef = options.document ?? root.ownerDocument ?? globalThis.document;
331
+ ensureStyles(documentRef);
332
+ const previousMarkup = root.innerHTML;
333
+ root.innerHTML = "";
334
+ root.classList?.add?.("plasius-product-studio-wavefront");
335
+ const canvas = documentRef.createElement("canvas");
336
+ canvas.dataset.plasiusGpuProductStudio = "wavefront";
337
+ root.appendChild(canvas);
338
+ const modelLoader = typeof options.__modelLoader === "function" ? options.__modelLoader : loadGltfModel;
339
+ const rendererLoader = typeof options.__rendererLoader === "function" ? options.__rendererLoader : () => import("@plasius/gpu-renderer");
340
+ const assetUrl = options.productAssetUrl ?? options.assetUrl ?? DEFAULT_PRODUCT_ASSET_URL;
341
+ const model = await modelLoader(assetUrl);
342
+ const meshes = createProductStudioMeshes(model, {
343
+ targetCenter: options.targetCenter,
344
+ targetSize: options.targetSize
345
+ });
346
+ const rendererModule = await rendererLoader();
347
+ if (typeof rendererModule.createWavefrontPathTracingComputeRenderer !== "function") {
348
+ throw new Error("Product Studio renderer loader must provide createWavefrontPathTracingComputeRenderer.");
349
+ }
350
+ const size = resolveRenderSize(root, options);
351
+ const lightingOptions = await resolveWavefrontLightingOptions(options);
352
+ const renderer = await rendererModule.createWavefrontPathTracingComputeRenderer({
353
+ canvas,
354
+ width: size.width,
355
+ height: size.height,
356
+ maxDepth: Number.isFinite(options.maxDepth) ? options.maxDepth : 6,
357
+ tileSize: Number.isFinite(options.tileSize) ? options.tileSize : 128,
358
+ samplesPerPixel: Number.isFinite(options.samplesPerPixel) ? options.samplesPerPixel : 8,
359
+ denoise: options.denoise !== false,
360
+ displayQuality: true,
361
+ meshes,
362
+ camera: {
363
+ position: [0, 1.12, 5.05],
364
+ target: [0, 0.72, 0],
365
+ up: [0, 1, 0],
366
+ fovYDegrees: 43
367
+ },
368
+ ...lightingOptions
369
+ });
370
+ const rendererStats = renderer.renderOnce();
371
+ const state = Object.freeze({
372
+ featureFlags,
373
+ modelName: model.name,
374
+ sourceTriangleCount: countSourceTriangles(model),
375
+ meshCount: meshes.length,
376
+ geometryMode: "mesh-bvh-display-quality",
377
+ requiresTriangleMeshRenderer: true,
378
+ displayQuality: true,
379
+ requiresMeshBvhForDisplayQuality: true,
380
+ rendererStats
381
+ });
382
+ const restoreSnapshotHook = installSnapshotHook(state);
383
+ return Object.freeze({
384
+ state,
385
+ model,
386
+ productModel: model,
387
+ canvas,
388
+ renderer,
389
+ meshes,
390
+ destroy() {
391
+ restoreSnapshotHook();
392
+ renderer.destroy();
393
+ root.classList?.remove?.("plasius-product-studio-wavefront");
394
+ root.innerHTML = previousMarkup;
395
+ }
396
+ });
397
+ }
398
+
399
+ export {
400
+ createProductStudioMeshes,
401
+ mountGpuProductStudio
402
+ };
403
+ //# sourceMappingURL=chunk-6SOHFUOE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/product-studio-runtime.js"],"sourcesContent":["import { loadGltfModel } from \"./gltf-loader.js\";\n\nconst STYLE_ID = \"plasius-product-studio-wavefront-style\";\nconst DEFAULT_PRODUCT_ASSET_URL =\n \"/data/models/eames-lounge-chair-ottoman/Eames_Lounge_Chair_Ottoman.gltf\";\nconst DEFAULT_TARGET_CENTER = Object.freeze([0, 0.74, 0]);\nconst DEFAULT_TARGET_SIZE = 2.25;\n\nfunction clamp(value, min, max) {\n return Math.max(min, Math.min(max, value));\n}\n\nfunction isFiniteVector(value) {\n return (\n Array.isArray(value) &&\n value.length >= 3 &&\n Number.isFinite(value[0]) &&\n Number.isFinite(value[1]) &&\n Number.isFinite(value[2])\n );\n}\n\nfunction createEmptyBounds() {\n return {\n min: [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],\n max: [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY],\n };\n}\n\nfunction expandBounds(bounds, point) {\n bounds.min[0] = Math.min(bounds.min[0], point[0]);\n bounds.min[1] = Math.min(bounds.min[1], point[1]);\n bounds.min[2] = Math.min(bounds.min[2], point[2]);\n bounds.max[0] = Math.max(bounds.max[0], point[0]);\n bounds.max[1] = Math.max(bounds.max[1], point[1]);\n bounds.max[2] = Math.max(bounds.max[2], point[2]);\n}\n\nfunction getBoundsSize(bounds) {\n return [\n bounds.max[0] - bounds.min[0],\n bounds.max[1] - bounds.min[1],\n bounds.max[2] - bounds.min[2],\n ];\n}\n\nfunction getBoundsCenter(bounds) {\n return [\n (bounds.min[0] + bounds.max[0]) * 0.5,\n (bounds.min[1] + bounds.max[1]) * 0.5,\n (bounds.min[2] + bounds.max[2]) * 0.5,\n ];\n}\n\nfunction getModelBounds(model) {\n if (isFiniteVector(model?.bounds?.min) && isFiniteVector(model?.bounds?.max)) {\n return {\n min: [...model.bounds.min],\n max: [...model.bounds.max],\n };\n }\n\n const bounds = createEmptyBounds();\n for (const primitive of model?.primitives ?? []) {\n for (let index = 0; index < primitive.positions.length; index += 3) {\n expandBounds(bounds, [\n primitive.positions[index],\n primitive.positions[index + 1],\n primitive.positions[index + 2],\n ]);\n }\n }\n return bounds;\n}\n\nfunction transformPoint(point, modelCenter, scale, targetCenter) {\n return [\n (point[0] - modelCenter[0]) * scale + targetCenter[0],\n (point[1] - modelCenter[1]) * scale + targetCenter[1],\n (point[2] - modelCenter[2]) * scale + targetCenter[2],\n ];\n}\n\nfunction readMaterialColor(material) {\n const color = material?.color ?? {};\n return [\n Number.isFinite(color.r) ? color.r : 0.62,\n Number.isFinite(color.g) ? color.g : 0.56,\n Number.isFinite(color.b) ? color.b : 0.48,\n Number.isFinite(color.a) ? color.a : 1,\n ];\n}\n\nfunction readMaterialKind(material) {\n const emissive = material?.emissive ?? {};\n if ((emissive.r ?? 0) + (emissive.g ?? 0) + (emissive.b ?? 0) > 0.001) {\n return \"emissive\";\n }\n if ((material?.metallic ?? 0) >= 0.5) {\n return \"metal\";\n }\n const alpha = readMaterialColor(material)[3];\n if (alpha < 0.9) {\n return \"transparent\";\n }\n return \"diffuse\";\n}\n\nfunction readEmission(material) {\n const emissive = material?.emissive ?? {};\n return [\n Number.isFinite(emissive.r) ? emissive.r : 0,\n Number.isFinite(emissive.g) ? emissive.g : 0,\n Number.isFinite(emissive.b) ? emissive.b : 0,\n 1,\n ];\n}\n\nfunction createQuadMesh({\n id,\n corners,\n color,\n emission = [0, 0, 0, 1],\n materialKind = \"diffuse\",\n roughness = 0.72,\n metallic = 0,\n opacity = color[3] ?? 1,\n}) {\n const [a, b, c] = corners;\n const edge1 = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];\n const edge2 = [c[0] - a[0], c[1] - a[1], c[2] - a[2]];\n const normal = [\n edge1[1] * edge2[2] - edge1[2] * edge2[1],\n edge1[2] * edge2[0] - edge1[0] * edge2[2],\n edge1[0] * edge2[1] - edge1[1] * edge2[0],\n ];\n const length = Math.hypot(normal[0], normal[1], normal[2]) || 1;\n const unitNormal = normal.map((value) => value / length);\n\n return Object.freeze({\n id,\n positions: Object.freeze(corners.flat()),\n indices: Object.freeze([0, 1, 2, 0, 2, 3]),\n normals: Object.freeze([unitNormal, unitNormal, unitNormal, unitNormal].flat()),\n color: Object.freeze([...color]),\n emission: Object.freeze([...emission]),\n materialKind,\n roughness,\n metallic,\n opacity,\n });\n}\n\nfunction createProductStudioEnvironmentMeshes() {\n return [\n createQuadMesh({\n id: 1,\n corners: [\n [-3.2, -0.08, 2.4],\n [3.2, -0.08, 2.4],\n [3.2, -0.08, -3.1],\n [-3.2, -0.08, -3.1],\n ],\n color: [0.48, 0.55, 0.55, 1],\n roughness: 0.82,\n }),\n createQuadMesh({\n id: 2,\n corners: [\n [-3.2, -0.08, -2.45],\n [3.2, -0.08, -2.45],\n [3.2, 2.65, -2.45],\n [-3.2, 2.65, -2.45],\n ],\n color: [0.43, 0.42, 0.38, 1],\n roughness: 0.86,\n }),\n createQuadMesh({\n id: 3,\n corners: [\n [-2.85, -0.08, -2.45],\n [-2.85, 2.55, -2.45],\n [-2.85, 2.55, 2.15],\n [-2.85, -0.08, 2.15],\n ],\n color: [0.36, 0.42, 0.45, 1],\n roughness: 0.8,\n }),\n createQuadMesh({\n id: 4,\n corners: [\n [0.78, 2.55, -0.82],\n [-0.78, 2.55, -0.82],\n [-0.78, 2.55, -1.78],\n [0.78, 2.55, -1.78],\n ],\n color: [1, 0.94, 0.78, 1],\n emission: [8.5, 7.2, 4.8, 1],\n materialKind: \"emissive\",\n roughness: 0,\n }),\n ];\n}\n\nfunction createProductStudioMeshFromPrimitive(primitive, primitiveIndex, transform) {\n if (!Array.isArray(primitive?.positions) || primitive.positions.length < 9) {\n return null;\n }\n\n const positions = [];\n for (let index = 0; index < primitive.positions.length; index += 3) {\n const point = transform([\n primitive.positions[index],\n primitive.positions[index + 1],\n primitive.positions[index + 2],\n ]);\n positions.push(point[0], point[1], point[2]);\n }\n\n const indices =\n Array.isArray(primitive.indices) && primitive.indices.length >= 3\n ? [...primitive.indices]\n : Array.from({ length: positions.length / 3 }, (_, index) => index);\n const material = primitive.material ?? {};\n const color = readMaterialColor(material);\n\n return Object.freeze({\n id: 1000 + primitiveIndex,\n positions: Object.freeze(positions),\n indices: Object.freeze(indices),\n normals: Array.isArray(primitive.normals) ? Object.freeze([...primitive.normals]) : null,\n color: Object.freeze(color),\n emission: Object.freeze(readEmission(material)),\n materialKind: readMaterialKind(material),\n materialRefId: 1000 + primitiveIndex,\n roughness: Number.isFinite(material.roughness) ? material.roughness : 0.72,\n metallic: Number.isFinite(material.metallic) ? material.metallic : 0,\n opacity: color[3],\n });\n}\n\nexport function createProductStudioMeshes(model, options = {}) {\n const primitives = Array.isArray(model?.primitives) ? model.primitives : [];\n if (primitives.length === 0) {\n throw new Error(\"Product Studio model must contain at least one renderable primitive.\");\n }\n\n const targetCenter = isFiniteVector(options.targetCenter)\n ? [...options.targetCenter]\n : [...DEFAULT_TARGET_CENTER];\n const targetSize = Number.isFinite(options.targetSize)\n ? Math.max(options.targetSize, 0.25)\n : DEFAULT_TARGET_SIZE;\n const modelBounds = getModelBounds(model);\n const modelSize = getBoundsSize(modelBounds);\n const modelCenter = getBoundsCenter(modelBounds);\n const scale = targetSize / Math.max(modelSize[0], modelSize[1], modelSize[2], 0.000001);\n const transform = (point) => transformPoint(point, modelCenter, scale, targetCenter);\n const modelMeshes = primitives\n .map((primitive, index) => createProductStudioMeshFromPrimitive(primitive, index, transform))\n .filter(Boolean);\n\n return Object.freeze([...createProductStudioEnvironmentMeshes(), ...modelMeshes]);\n}\n\nfunction ensureStyles(documentRef) {\n if (documentRef.getElementById?.(STYLE_ID)) {\n return;\n }\n const style = documentRef.createElement(\"style\");\n style.id = STYLE_ID;\n style.textContent = `\n .plasius-product-studio-wavefront {\n position: relative;\n width: 100%;\n min-height: 420px;\n overflow: hidden;\n background: #0f1418;\n display: grid;\n place-items: center;\n }\n\n .plasius-product-studio-wavefront canvas {\n display: block;\n width: 100%;\n height: auto;\n max-height: 100%;\n aspect-ratio: 16 / 9;\n min-height: 420px;\n object-fit: contain;\n }\n `;\n documentRef.head?.appendChild?.(style);\n}\n\nfunction resolveRoot(options) {\n const documentRef = options.document ?? globalThis.document;\n if (options.root) {\n return options.root;\n }\n const root =\n documentRef?.querySelector?.(\"[data-plasius-gpu-product-studio]\") ?? documentRef?.body;\n if (!root) {\n throw new Error(\"Product Studio requires a DOM root.\");\n }\n return root;\n}\n\nfunction resolveRenderSize(root, options) {\n const rect = root.getBoundingClientRect?.() ?? { width: 1280, height: 720 };\n const devicePixelRatio =\n Number.isFinite(options.devicePixelRatio)\n ? options.devicePixelRatio\n : Number.isFinite(globalThis.window?.devicePixelRatio)\n ? globalThis.window.devicePixelRatio\n : 1;\n const cssWidth = Number.isFinite(rect.width) && rect.width > 0 ? rect.width : 1280;\n const cssHeight =\n Number.isFinite(rect.height) && rect.height > 0 ? rect.height : cssWidth * (9 / 16);\n const width = Number.isFinite(options.width)\n ? Math.trunc(options.width)\n : clamp(Math.round(cssWidth * devicePixelRatio), 640, 1920);\n const height = Number.isFinite(options.height)\n ? Math.trunc(options.height)\n : clamp(Math.round(cssHeight * devicePixelRatio), 360, 1080);\n\n return {\n width,\n height,\n };\n}\n\nfunction installSnapshotHook(state) {\n if (typeof globalThis.window === \"undefined\") {\n return () => {};\n }\n const previous = globalThis.window.render_game_to_text;\n globalThis.window.render_game_to_text = () =>\n JSON.stringify({\n surface: \"gpu-product-studio-wavefront\",\n model: state.modelName,\n sourceTriangles: state.sourceTriangleCount,\n meshCount: state.meshCount,\n geometryMode: state.geometryMode,\n requiresTriangleMeshRenderer: state.requiresTriangleMeshRenderer,\n displayQuality: state.displayQuality,\n requiresMeshBvhForDisplayQuality: state.requiresMeshBvhForDisplayQuality,\n renderer: state.rendererStats,\n });\n return () => {\n if (previous === undefined) {\n delete globalThis.window.render_game_to_text;\n } else {\n globalThis.window.render_game_to_text = previous;\n }\n };\n}\n\nfunction countSourceTriangles(model) {\n return (model.primitives ?? []).reduce(\n (total, primitive) => total + Math.floor((primitive.indices?.length ?? 0) / 3),\n 0\n );\n}\n\nasync function resolveWavefrontLightingOptions(options) {\n const fallback = {\n environmentColor: [0.35, 0.43, 0.49, 1],\n ambientColor: [0.02, 0.024, 0.028, 1],\n };\n const lightingLoader =\n typeof options.__lightingLoader === \"function\"\n ? options.__lightingLoader\n : () => import(\"@plasius/gpu-lighting\").catch(() => null);\n const lightingModule = await lightingLoader();\n\n if (\n typeof lightingModule?.createWavefrontEnvironmentLightingOptions !== \"function\"\n ) {\n return fallback;\n }\n\n return lightingModule.createWavefrontEnvironmentLightingOptions({\n preset: options.lightingPreset ?? \"product-studio\",\n intensity: options.lightingIntensity,\n });\n}\n\nexport async function mountGpuProductStudio(options = {}, featureFlags = null) {\n const root = resolveRoot(options);\n const documentRef = options.document ?? root.ownerDocument ?? globalThis.document;\n ensureStyles(documentRef);\n const previousMarkup = root.innerHTML;\n root.innerHTML = \"\";\n root.classList?.add?.(\"plasius-product-studio-wavefront\");\n\n const canvas = documentRef.createElement(\"canvas\");\n canvas.dataset.plasiusGpuProductStudio = \"wavefront\";\n root.appendChild(canvas);\n\n const modelLoader =\n typeof options.__modelLoader === \"function\" ? options.__modelLoader : loadGltfModel;\n const rendererLoader =\n typeof options.__rendererLoader === \"function\"\n ? options.__rendererLoader\n : () => import(\"@plasius/gpu-renderer\");\n const assetUrl = options.productAssetUrl ?? options.assetUrl ?? DEFAULT_PRODUCT_ASSET_URL;\n const model = await modelLoader(assetUrl);\n const meshes = createProductStudioMeshes(model, {\n targetCenter: options.targetCenter,\n targetSize: options.targetSize,\n });\n const rendererModule = await rendererLoader();\n if (typeof rendererModule.createWavefrontPathTracingComputeRenderer !== \"function\") {\n throw new Error(\"Product Studio renderer loader must provide createWavefrontPathTracingComputeRenderer.\");\n }\n\n const size = resolveRenderSize(root, options);\n const lightingOptions = await resolveWavefrontLightingOptions(options);\n const renderer = await rendererModule.createWavefrontPathTracingComputeRenderer({\n canvas,\n width: size.width,\n height: size.height,\n maxDepth: Number.isFinite(options.maxDepth) ? options.maxDepth : 6,\n tileSize: Number.isFinite(options.tileSize) ? options.tileSize : 128,\n samplesPerPixel: Number.isFinite(options.samplesPerPixel) ? options.samplesPerPixel : 8,\n denoise: options.denoise !== false,\n displayQuality: true,\n meshes,\n camera: {\n position: [0, 1.12, 5.05],\n target: [0, 0.72, 0],\n up: [0, 1, 0],\n fovYDegrees: 43,\n },\n ...lightingOptions,\n });\n const rendererStats = renderer.renderOnce();\n const state = Object.freeze({\n featureFlags,\n modelName: model.name,\n sourceTriangleCount: countSourceTriangles(model),\n meshCount: meshes.length,\n geometryMode: \"mesh-bvh-display-quality\",\n requiresTriangleMeshRenderer: true,\n displayQuality: true,\n requiresMeshBvhForDisplayQuality: true,\n rendererStats,\n });\n const restoreSnapshotHook = installSnapshotHook(state);\n\n return Object.freeze({\n state,\n model,\n productModel: model,\n canvas,\n renderer,\n meshes,\n destroy() {\n restoreSnapshotHook();\n renderer.destroy();\n root.classList?.remove?.(\"plasius-product-studio-wavefront\");\n root.innerHTML = previousMarkup;\n },\n });\n}\n"],"mappings":"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","names":[]}
@@ -1,3 +1,7 @@
1
+ // src/feature-flags.js
2
+ var GPU_SHOWCASE_REALISTIC_MODELS_FEATURE = "gpu_showcase_realistic_models_v1";
3
+ var GPU_SHOWCASE_PRODUCT_STUDIO_FEATURE = "gpu_showcase_product_studio_wavefront_v1";
4
+
1
5
  // src/translations/en-GB.js
2
6
  var gpuSharedEnGbTranslations = Object.freeze({
3
7
  "gpuShared.showcase.title": "Flag by the Sea",
@@ -104,10 +108,12 @@ function createGpuSharedTranslator(translate) {
104
108
  }
105
109
 
106
110
  export {
111
+ GPU_SHOWCASE_REALISTIC_MODELS_FEATURE,
112
+ GPU_SHOWCASE_PRODUCT_STUDIO_FEATURE,
107
113
  gpuSharedEnGbTranslations,
108
114
  gpuSharedTranslationKeys,
109
115
  gpuSharedTranslations,
110
116
  translateGpuSharedText,
111
117
  createGpuSharedTranslator
112
118
  };
113
- //# sourceMappingURL=chunk-DABW627O.js.map
119
+ //# sourceMappingURL=chunk-CH3ZS5TQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/feature-flags.js","../src/translations/en-GB.js","../src/i18n.js"],"sourcesContent":["export const GPU_SHOWCASE_REALISTIC_MODELS_FEATURE = \"gpu_showcase_realistic_models_v1\";\nexport const GPU_SHOWCASE_PRODUCT_STUDIO_FEATURE = \"gpu_showcase_product_studio_wavefront_v1\";\n","export const gpuSharedEnGbTranslations = Object.freeze({\n \"gpuShared.showcase.title\": \"Flag by the Sea\",\n \"gpuShared.showcase.subtitle\":\n \"Shared 3D validation scene using GLTF ships, cloth, fluid continuity, adaptive performance, and telemetry.\",\n \"gpuShared.showcase.status.booting\": \"Booting 3D scene...\",\n \"gpuShared.showcase.status.live\": \"3D scene live - {fps} FPS\",\n \"gpuShared.showcase.details.booting\":\n \"Preparing a moonlit harbor scene, GLTF hull data, cloth and fluid continuity plans, and adaptive quality metadata.\",\n \"gpuShared.showcase.details.physics\":\n \"Stable world snapshots are emitted from {snapshotStageId} after the authoritative solver; the heavier hull now carries momentum through mass-aware collision impulses while cloth and fluid remain downstream.\",\n \"gpuShared.showcase.details.realistic\":\n \"Moonlit GLTF ships now mix a brigantine and a cutter against modeled harbor assets; cloth, fluid, and ship-local lighting stay continuous while the governor pressure is {pressureLevel}.\",\n \"gpuShared.showcase.details.legacy\":\n \"Moonlit GLTF ships use the legacy brigantine and placeholder harbor blocks while cloth, fluid, and ship-local lighting stay continuous while the governor pressure is {pressureLevel}.\",\n \"gpuShared.showcase.action.pause\": \"Pause\",\n \"gpuShared.showcase.action.resume\": \"Resume\",\n \"gpuShared.showcase.control.stressMode\": \"Stress mode\",\n \"gpuShared.showcase.control.focus\": \"Focus\",\n \"gpuShared.showcase.focus.integrated\": \"integrated\",\n \"gpuShared.showcase.focus.lighting\": \"lighting\",\n \"gpuShared.showcase.focus.cloth\": \"cloth\",\n \"gpuShared.showcase.focus.fluid\": \"fluid\",\n \"gpuShared.showcase.focus.physics\": \"physics\",\n \"gpuShared.showcase.focus.performance\": \"performance\",\n \"gpuShared.showcase.focus.debug\": \"debug\",\n \"gpuShared.showcase.legend.title\": \"Scene\",\n \"gpuShared.showcase.legend.shipMetadata\":\n \"GLTF ships carry hull mass and damping metadata.\",\n \"gpuShared.showcase.legend.lighting\":\n \"Lanterns and torches warm the moonlit harbor.\",\n \"gpuShared.showcase.legend.collisions\":\n \"Mass-aware collisions stay authoritative near the camera.\",\n \"gpuShared.showcase.section.sceneState\": \"Scene State\",\n \"gpuShared.showcase.section.qualityBudgets\": \"Quality + Budgets\",\n \"gpuShared.showcase.section.debugTelemetry\": \"Debug Telemetry\",\n \"gpuShared.showcase.section.notes\": \"Notes\",\n \"gpuShared.showcase.note.assetLoading\":\n \"Ships are loaded from a GLTF asset and carry mass, damping, restitution, and hull extents from node extras.\",\n \"gpuShared.showcase.note.moonlight\":\n \"Moonlight sets the cold ambient read while deck lanterns and harbor torches provide warm local contrast.\",\n \"gpuShared.showcase.note.continuity\":\n \"Cloth and fluid continuity stay coherent across near, mid, far, and horizon bands even in the darker night palette.\",\n \"gpuShared.showcase.note.performance\":\n \"Performance pressure reduces visual detail before mass-weighted authoritative collision motion is touched.\",\n \"gpuShared.showcase.note.physicsSnapshots\":\n \"Stable world snapshots are taken after the authoritative rigid-body commit and before visual follow-up work.\",\n \"gpuShared.showcase.note.physicsCollisions\":\n \"The ships collide with mass-weighted impulses and positional correction, so the heavier hull keeps more of its line.\",\n \"gpuShared.showcase.note.physicsLighting\":\n \"Moonlight keeps the overall read legible while lanterns and torches make collision moments easy to track against the water.\",\n \"gpuShared.debug.adapter.showcase\": \"3D showcase\",\n \"gpuShared.debug.allocation.mainColorBuffer\": \"Main color buffer\",\n \"gpuShared.debug.allocation.shadowImpressionAtlas\": \"Shadow impression atlas\",\n});\n\n","import { gpuSharedEnGbTranslations } from \"./translations/en-GB.js\";\n\nexport const gpuSharedTranslationKeys = Object.freeze({\n showcaseTitle: \"gpuShared.showcase.title\",\n showcaseSubtitle: \"gpuShared.showcase.subtitle\",\n statusBooting: \"gpuShared.showcase.status.booting\",\n statusLive: \"gpuShared.showcase.status.live\",\n detailsBooting: \"gpuShared.showcase.details.booting\",\n detailsPhysics: \"gpuShared.showcase.details.physics\",\n detailsRealistic: \"gpuShared.showcase.details.realistic\",\n detailsLegacy: \"gpuShared.showcase.details.legacy\",\n pause: \"gpuShared.showcase.action.pause\",\n resume: \"gpuShared.showcase.action.resume\",\n stressMode: \"gpuShared.showcase.control.stressMode\",\n focus: \"gpuShared.showcase.control.focus\",\n focusIntegrated: \"gpuShared.showcase.focus.integrated\",\n focusLighting: \"gpuShared.showcase.focus.lighting\",\n focusCloth: \"gpuShared.showcase.focus.cloth\",\n focusFluid: \"gpuShared.showcase.focus.fluid\",\n focusPhysics: \"gpuShared.showcase.focus.physics\",\n focusPerformance: \"gpuShared.showcase.focus.performance\",\n focusDebug: \"gpuShared.showcase.focus.debug\",\n legendTitle: \"gpuShared.showcase.legend.title\",\n legendShipMetadata: \"gpuShared.showcase.legend.shipMetadata\",\n legendLighting: \"gpuShared.showcase.legend.lighting\",\n legendCollisions: \"gpuShared.showcase.legend.collisions\",\n sceneState: \"gpuShared.showcase.section.sceneState\",\n qualityBudgets: \"gpuShared.showcase.section.qualityBudgets\",\n debugTelemetry: \"gpuShared.showcase.section.debugTelemetry\",\n notes: \"gpuShared.showcase.section.notes\",\n noteAssetLoading: \"gpuShared.showcase.note.assetLoading\",\n noteMoonlight: \"gpuShared.showcase.note.moonlight\",\n noteContinuity: \"gpuShared.showcase.note.continuity\",\n notePerformance: \"gpuShared.showcase.note.performance\",\n notePhysicsSnapshots: \"gpuShared.showcase.note.physicsSnapshots\",\n notePhysicsCollisions: \"gpuShared.showcase.note.physicsCollisions\",\n notePhysicsLighting: \"gpuShared.showcase.note.physicsLighting\",\n debugAdapterShowcase: \"gpuShared.debug.adapter.showcase\",\n debugMainColorBuffer: \"gpuShared.debug.allocation.mainColorBuffer\",\n debugShadowImpressionAtlas: \"gpuShared.debug.allocation.shadowImpressionAtlas\",\n});\n\nexport const gpuSharedTranslations = Object.freeze({\n \"en-GB\": gpuSharedEnGbTranslations,\n});\n\nfunction formatTranslation(template, args = {}) {\n return template.replace(/\\{([A-Za-z0-9_]+)\\}/g, (match, name) => {\n if (!Object.prototype.hasOwnProperty.call(args, name)) {\n return match;\n }\n\n const value = args[name];\n return value == null ? \"\" : String(value);\n });\n}\n\nexport function translateGpuSharedText(key, args, translate) {\n const translated = translate?.(key, args);\n if (translated && translated !== key) {\n return translated;\n }\n\n const fallback = gpuSharedEnGbTranslations[key];\n return fallback ? formatTranslation(fallback, args) : key;\n}\n\nexport function createGpuSharedTranslator(translate) {\n return (key, args) => translateGpuSharedText(key, args, translate);\n}\n\n"],"mappings":";AAAO,IAAM,wCAAwC;AAC9C,IAAM,sCAAsC;;;ACD5C,IAAM,4BAA4B,OAAO,OAAO;AAAA,EACrD,4BAA4B;AAAA,EAC5B,+BACE;AAAA,EACF,qCAAqC;AAAA,EACrC,kCAAkC;AAAA,EAClC,sCACE;AAAA,EACF,sCACE;AAAA,EACF,wCACE;AAAA,EACF,qCACE;AAAA,EACF,mCAAmC;AAAA,EACnC,oCAAoC;AAAA,EACpC,yCAAyC;AAAA,EACzC,oCAAoC;AAAA,EACpC,uCAAuC;AAAA,EACvC,qCAAqC;AAAA,EACrC,kCAAkC;AAAA,EAClC,kCAAkC;AAAA,EAClC,oCAAoC;AAAA,EACpC,wCAAwC;AAAA,EACxC,kCAAkC;AAAA,EAClC,mCAAmC;AAAA,EACnC,0CACE;AAAA,EACF,sCACE;AAAA,EACF,wCACE;AAAA,EACF,yCAAyC;AAAA,EACzC,6CAA6C;AAAA,EAC7C,6CAA6C;AAAA,EAC7C,oCAAoC;AAAA,EACpC,wCACE;AAAA,EACF,qCACE;AAAA,EACF,sCACE;AAAA,EACF,uCACE;AAAA,EACF,4CACE;AAAA,EACF,6CACE;AAAA,EACF,2CACE;AAAA,EACF,oCAAoC;AAAA,EACpC,8CAA8C;AAAA,EAC9C,oDAAoD;AACtD,CAAC;;;ACnDM,IAAM,2BAA2B,OAAO,OAAO;AAAA,EACpD,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,OAAO;AAAA,EACP,iBAAiB;AAAA,EACjB,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,OAAO;AAAA,EACP,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,sBAAsB;AAAA,EACtB,uBAAuB;AAAA,EACvB,qBAAqB;AAAA,EACrB,sBAAsB;AAAA,EACtB,sBAAsB;AAAA,EACtB,4BAA4B;AAC9B,CAAC;AAEM,IAAM,wBAAwB,OAAO,OAAO;AAAA,EACjD,SAAS;AACX,CAAC;AAED,SAAS,kBAAkB,UAAU,OAAO,CAAC,GAAG;AAC9C,SAAO,SAAS,QAAQ,wBAAwB,CAAC,OAAO,SAAS;AAC/D,QAAI,CAAC,OAAO,UAAU,eAAe,KAAK,MAAM,IAAI,GAAG;AACrD,aAAO;AAAA,IACT;AAEA,UAAM,QAAQ,KAAK,IAAI;AACvB,WAAO,SAAS,OAAO,KAAK,OAAO,KAAK;AAAA,EAC1C,CAAC;AACH;AAEO,SAAS,uBAAuB,KAAK,MAAM,WAAW;AAC3D,QAAM,aAAa,YAAY,KAAK,IAAI;AACxC,MAAI,cAAc,eAAe,KAAK;AACpC,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,0BAA0B,GAAG;AAC9C,SAAO,WAAW,kBAAkB,UAAU,IAAI,IAAI;AACxD;AAEO,SAAS,0BAA0B,WAAW;AACnD,SAAO,CAAC,KAAK,SAAS,uBAAuB,KAAK,MAAM,SAAS;AACnE;","names":[]}
@@ -0,0 +1,11 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ export {
9
+ __require
10
+ };
11
+ //# sourceMappingURL=chunk-DGUM43GV.js.map
@@ -1,6 +1,71 @@
1
1
  import {
2
- shouldUseInlineShowcaseFallback
3
- } from "./chunk-2FIFSBB4.js";
2
+ INLINE_SHOWCASE_ASSET_URLS
3
+ } from "./chunk-2GM64LB6.js";
4
+
5
+ // src/asset-url.js
6
+ var SHOWCASE_ASSET_FILES = Object.freeze({
7
+ brigantine: "brigantine.gltf",
8
+ cutter: "cutter.gltf",
9
+ lighthouse: "lighthouse.gltf",
10
+ "harbor-dock": "harbor-dock.gltf"
11
+ });
12
+ function createInlineShowcaseAssetUrl(assetName) {
13
+ const inlineUrl = INLINE_SHOWCASE_ASSET_URLS[assetName];
14
+ return inlineUrl ? new URL(inlineUrl) : null;
15
+ }
16
+ function getBrowserBaseUrl() {
17
+ if (typeof document !== "undefined" && typeof document.baseURI === "string" && document.baseURI.length > 0) {
18
+ return document.baseURI;
19
+ }
20
+ if (typeof window !== "undefined" && typeof window.location?.href === "string" && window.location.href.length > 0) {
21
+ return window.location.href;
22
+ }
23
+ return null;
24
+ }
25
+ function normalizeAssetName(assetName) {
26
+ return typeof assetName === "string" && assetName in SHOWCASE_ASSET_FILES ? assetName : "brigantine";
27
+ }
28
+ function parseResolveArgs(baseUrlOrAssetName, assetName) {
29
+ if (typeof baseUrlOrAssetName === "string" && baseUrlOrAssetName in SHOWCASE_ASSET_FILES && typeof assetName === "undefined") {
30
+ return {
31
+ baseUrl: import.meta.url,
32
+ assetName: baseUrlOrAssetName
33
+ };
34
+ }
35
+ return {
36
+ baseUrl: baseUrlOrAssetName ?? import.meta.url,
37
+ assetName: normalizeAssetName(assetName)
38
+ };
39
+ }
40
+ function resolveShowcaseAssetUrl(baseUrlOrAssetName, assetName) {
41
+ const resolved = parseResolveArgs(baseUrlOrAssetName, assetName);
42
+ const fileName = SHOWCASE_ASSET_FILES[resolved.assetName];
43
+ try {
44
+ return new URL(`../assets/${fileName}`, resolved.baseUrl);
45
+ } catch {
46
+ const browserBaseUrl = getBrowserBaseUrl();
47
+ if (browserBaseUrl) {
48
+ try {
49
+ const normalizedBaseUrl = new URL(resolved.baseUrl, browserBaseUrl);
50
+ return new URL(`../assets/${fileName}`, normalizedBaseUrl);
51
+ } catch {
52
+ const inlineAsset = createInlineShowcaseAssetUrl(resolved.assetName);
53
+ if (inlineAsset) {
54
+ return inlineAsset;
55
+ }
56
+ }
57
+ }
58
+ try {
59
+ return new URL(`../assets/${fileName}`, import.meta.url);
60
+ } catch {
61
+ return new URL(`assets/${fileName}`, "file:///");
62
+ }
63
+ }
64
+ }
65
+ function shouldUseInlineShowcaseFallback(url) {
66
+ const href = url instanceof URL ? url.href : String(url ?? "");
67
+ return href.includes("/assets/");
68
+ }
4
69
 
5
70
  // src/gltf-loader.js
6
71
  function decodeDataUri(uri) {
@@ -120,6 +185,16 @@ function computeBounds(positions) {
120
185
  max: Object.freeze([max[0], max[1], max[2]])
121
186
  });
122
187
  }
188
+ function appendValues(target, values) {
189
+ for (let index = 0; index < values.length; index += 1) {
190
+ target.push(values[index]);
191
+ }
192
+ }
193
+ function appendIndicesWithOffset(target, values, vertexOffset) {
194
+ for (let index = 0; index < values.length; index += 1) {
195
+ target.push(values[index] + vertexOffset);
196
+ }
197
+ }
123
198
  function resolveBrowserRequestBaseUrl() {
124
199
  if (typeof document !== "undefined" && typeof document.baseURI === "string" && document.baseURI.length > 0) {
125
200
  return document.baseURI;
@@ -306,7 +381,7 @@ async function loadGltfDocument(url) {
306
381
  };
307
382
  }
308
383
  async function loadInlineShowcaseDocument() {
309
- const module = await import("./showcase-inline-assets-B7U7VX5H.js");
384
+ const module = await import("./showcase-inline-assets-QRQKXGVX.js");
310
385
  return loadGltfDocument(new URL(module.INLINE_SHOWCASE_ASSET_URLS.brigantine));
311
386
  }
312
387
  async function buildGltfModel(document2, baseUrl) {
@@ -330,8 +405,8 @@ async function buildGltfModel(document2, baseUrl) {
330
405
  const aggregateIndices = [];
331
406
  for (const primitive of scene.primitives) {
332
407
  const vertexOffset = aggregatePositions.length / 3;
333
- aggregatePositions.push(...primitive.positions);
334
- aggregateIndices.push(...primitive.indices.map((index) => index + vertexOffset));
408
+ appendValues(aggregatePositions, primitive.positions);
409
+ appendIndicesWithOffset(aggregateIndices, primitive.indices, vertexOffset);
335
410
  }
336
411
  const color = scene.primitives[0]?.material?.color ?? { r: 0.56, g: 0.33, b: 0.22, a: 1 };
337
412
  return Object.freeze({
@@ -364,6 +439,7 @@ async function loadGltfModel(url) {
364
439
  }
365
440
 
366
441
  export {
442
+ resolveShowcaseAssetUrl,
367
443
  loadGltfModel
368
444
  };
369
- //# sourceMappingURL=chunk-DQX4DXBR.js.map
445
+ //# sourceMappingURL=chunk-QVNRTWHB.js.map