@roomle/web-sdk 5.0.0 → 5.1.0-alpha.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.
- package/lib/{BufferGeometry-DxRRBHpW.mjs → BufferGeometry-Cd2ewNVQ.mjs} +2 -2
- package/lib/{BufferGeometry-DxRRBHpW.mjs.map → BufferGeometry-Cd2ewNVQ.mjs.map} +1 -1
- package/lib/ConfiguratorKernel.wasm +0 -0
- package/lib/{GLTFExporter-BFaz434u.mjs → GLTFExporter-n80QLoDf.mjs} +1 -1
- package/lib/{GLTFExporter-BFaz434u.mjs.map → GLTFExporter-n80QLoDf.mjs.map} +1 -1
- package/lib/{GaussianBlurNode-BMH03PYf.mjs → GaussianBlurNode-Cwy3kx8H.mjs} +3 -3
- package/lib/{GaussianBlurNode-BMH03PYf.mjs.map → GaussianBlurNode-Cwy3kx8H.mjs.map} +1 -1
- package/lib/{Object3D-DxqUUhH8.mjs → Object3D-BHdngbxB.mjs} +1 -1
- package/lib/{Object3D-DxqUUhH8.mjs.map → Object3D-BHdngbxB.mjs.map} +1 -1
- package/lib/{PointLightHelper-dMNG9Rk5.mjs → PointLightHelper-DlPLsDNy.mjs} +4 -4
- package/lib/{PointLightHelper-dMNG9Rk5.mjs.map → PointLightHelper-DlPLsDNy.mjs.map} +1 -1
- package/lib/RoomleCore.wasm +0 -0
- package/lib/RoomleToolsCore.wasm +0 -0
- package/lib/{SpotLightHelper-DFIT6781.mjs → SpotLightHelper-YWHbVXAF.mjs} +3 -3
- package/lib/{SpotLightHelper-DFIT6781.mjs.map → SpotLightHelper-YWHbVXAF.mjs.map} +1 -1
- package/lib/{USDZExporter-DWwEB8-y.mjs → USDZExporter-Bm-c5e_n.mjs} +2 -2
- package/lib/{USDZExporter-DWwEB8-y.mjs.map → USDZExporter-Bm-c5e_n.mjs.map} +1 -1
- package/lib/{Vector4-DgGvlGnF.mjs → Vector4-C7TlIAyy.mjs} +2 -2
- package/lib/{Vector4-DgGvlGnF.mjs.map → Vector4-C7TlIAyy.mjs.map} +1 -1
- package/lib/{api-DrK8F76r.mjs → api-B5wIZIHt.mjs} +2 -2
- package/lib/{api-DrK8F76r.mjs.map → api-B5wIZIHt.mjs.map} +1 -1
- package/lib/{asset-loader.worker-eqHzNAwa.mjs → asset-loader.worker-CE4O0JU-.mjs} +1 -1
- package/lib/asset-loader.worker-CE4O0JU-.mjs.map +1 -0
- package/lib/{banana-for-scale-DGYmxeBG.mjs → banana-for-scale-D0bw51dn.mjs} +3 -3
- package/lib/{banana-for-scale-DGYmxeBG.mjs.map → banana-for-scale-D0bw51dn.mjs.map} +1 -1
- package/lib/{budgeteer.sw-BUMElkO1.mjs → budgeteer.sw-yR2xApHT.mjs} +1 -1
- package/lib/budgeteer.sw-yR2xApHT.mjs.map +1 -0
- package/lib/{common-utils-CyQUubmw.mjs → common-utils-DbL4tku0.mjs} +1 -1
- package/lib/{common-utils-CyQUubmw.mjs.map → common-utils-DbL4tku0.mjs.map} +1 -1
- package/lib/{component-dimensioning-Dao60YO2.mjs → component-dimensioning-VIUcXV7r.mjs} +40 -39
- package/lib/component-dimensioning-VIUcXV7r.mjs.map +1 -0
- package/lib/{component-raycast-helper-PVs7Vpbl.mjs → component-raycast-helper-CEAdBcdx.mjs} +4 -4
- package/lib/{component-raycast-helper-PVs7Vpbl.mjs.map → component-raycast-helper-CEAdBcdx.mjs.map} +1 -1
- package/lib/{configurator-herY75_C.mjs → configurator-CxlLvBCx.mjs} +4 -4
- package/lib/{configurator-herY75_C.mjs.map → configurator-CxlLvBCx.mjs.map} +1 -1
- package/lib/configurator-h8QoUnMz.mjs +2 -0
- package/lib/{continuous-drawing-helper-DIVY8E6B.mjs → continuous-drawing-helper-Dr1r-5N2.mjs} +2 -2
- package/lib/{continuous-drawing-helper-DIVY8E6B.mjs.map → continuous-drawing-helper-Dr1r-5N2.mjs.map} +1 -1
- package/lib/{dat.gui.module-B2PXSbre.mjs → dat.gui.module-CSOnFjd0.mjs} +1 -1
- package/lib/{dat.gui.module-B2PXSbre.mjs.map → dat.gui.module-CSOnFjd0.mjs.map} +1 -1
- package/lib/{decorate-CjaqqbUP.mjs → decorate-Bl-JF_YY.mjs} +1 -1
- package/lib/{decorate-CjaqqbUP.mjs.map → decorate-Bl-JF_YY.mjs.map} +1 -1
- package/lib/dimensioning-helper-BEGkpZFA.mjs +2 -0
- package/lib/{dimensioning-helper-Cgao7A18.mjs → dimensioning-helper-ChQDwSjn.mjs} +4 -4
- package/lib/{dimensioning-helper-Cgao7A18.mjs.map → dimensioning-helper-ChQDwSjn.mjs.map} +1 -1
- package/lib/{dist-Blgk0vU0.mjs → dist-BZTF7IJN.mjs} +1 -1
- package/lib/{dist-Blgk0vU0.mjs.map → dist-BZTF7IJN.mjs.map} +1 -1
- package/lib/{fflate.module-DTkA0kF8.mjs → fflate.module-Cx1QFI2-.mjs} +1 -1
- package/lib/{fflate.module-DTkA0kF8.mjs.map → fflate.module-Cx1QFI2-.mjs.map} +1 -1
- package/lib/{glb-viewer-DtyiyPiY.mjs → glb-viewer-27e6wfY4.mjs} +6 -6
- package/lib/{glb-viewer-DtyiyPiY.mjs.map → glb-viewer-27e6wfY4.mjs.map} +1 -1
- package/lib/glb-viewer-Dc2Tl8Ef.mjs +2 -0
- package/lib/{highlight-coordinator-DOO-54ml.mjs → highlight-coordinator-C05kDjj5.mjs} +12 -11
- package/lib/highlight-coordinator-C05kDjj5.mjs.map +1 -0
- package/lib/{homag-intelligence-BOqc8-8E.mjs → homag-intelligence-BRQ1WoQo.mjs} +6 -3
- package/lib/homag-intelligence-BRQ1WoQo.mjs.map +1 -0
- package/lib/{imos-ix-poc-export-helper-DRQK_p2h.mjs → imos-ix-poc-export-helper-DhxAAMc9.mjs} +3 -3
- package/lib/{imos-ix-poc-export-helper-DRQK_p2h.mjs.map → imos-ix-poc-export-helper-DhxAAMc9.mjs.map} +1 -1
- package/lib/{kernel-utils-voLUOj-0.mjs → kernel-utils-BvatnA7U.mjs} +2 -2
- package/lib/kernel-utils-BvatnA7U.mjs.map +1 -0
- package/lib/{layer-DvZF9ur3.mjs → layer-DaGoZ5YI.mjs} +1 -1
- package/lib/{layer-DvZF9ur3.mjs.map → layer-DaGoZ5YI.mjs.map} +1 -1
- package/lib/{material-viewer-Dk8D8-8C.mjs → material-viewer-Byi5t7-x.mjs} +6 -6
- package/lib/{material-viewer-Dk8D8-8C.mjs.map → material-viewer-Byi5t7-x.mjs.map} +1 -1
- package/lib/{packages-xgEJ9vvB.mjs → packages-3jOdcfbr.mjs} +5 -5
- package/lib/{packages-xgEJ9vvB.mjs.map → packages-3jOdcfbr.mjs.map} +1 -1
- package/lib/{planner-aBm7Ihtu.mjs → planner-BeINcWRR.mjs} +3 -3
- package/lib/{planner-aBm7Ihtu.mjs.map → planner-BeINcWRR.mjs.map} +1 -1
- package/lib/planner-Ler1UMAp.mjs +2 -0
- package/lib/{plugin-system-vlnG8j2T.mjs → plugin-system-DR5maiUo.mjs} +3 -3
- package/lib/{plugin-system-vlnG8j2T.mjs.map → plugin-system-DR5maiUo.mjs.map} +1 -1
- package/lib/render-cache-DCPIQbO1.mjs +150 -0
- package/lib/render-cache-DCPIQbO1.mjs.map +1 -0
- package/lib/render-order-BPF2wDMw.mjs +26 -0
- package/lib/render-order-BPF2wDMw.mjs.map +1 -0
- package/lib/{roomle-headless-setup-DbO_rLjK.mjs → roomle-headless-setup-ps3I0vOP.mjs} +1 -1
- package/lib/{roomle-headless-setup-DbO_rLjK.mjs.map → roomle-headless-setup-ps3I0vOP.mjs.map} +1 -1
- package/lib/roomle-headless.d.ts +27 -21
- package/lib/roomle-headless.js +15 -15
- package/lib/{roomle-renderer-FUqNfNIf.mjs → roomle-renderer-Ato6RMrd.mjs} +1 -1
- package/lib/{roomle-renderer-FUqNfNIf.mjs.map → roomle-renderer-Ato6RMrd.mjs.map} +1 -1
- package/lib/{roomle-sdk-k8Vvoclf.mjs → roomle-sdk-CsSQAqQG.mjs} +2777 -2626
- package/lib/roomle-sdk-CsSQAqQG.mjs.map +1 -0
- package/lib/roomle-sdk.d.ts +27 -21
- package/lib/roomle-sdk.js +7 -7
- package/lib/{roomle-webgpu-renderer-Dv_s6ZN-.mjs → roomle-webgpu-renderer-BBE14A8V.mjs} +7 -7
- package/lib/{roomle-webgpu-renderer-Dv_s6ZN-.mjs.map → roomle-webgpu-renderer-BBE14A8V.mjs.map} +1 -1
- package/lib/{scene-renderer-nIOJ3nuy.mjs → scene-renderer-B8SBMSQ7.mjs} +231 -372
- package/lib/scene-renderer-B8SBMSQ7.mjs.map +1 -0
- package/lib/{script-loader-BTeojHth.mjs → script-loader-Dx3gOiB3.mjs} +3 -3
- package/lib/{script-loader-BTeojHth.mjs.map → script-loader-Dx3gOiB3.mjs.map} +1 -1
- package/lib/{shading-settings-CRNmMpcn.mjs → shading-settings-BBhR7KcS.mjs} +2 -2
- package/lib/{shading-settings-CRNmMpcn.mjs.map → shading-settings-BBhR7KcS.mjs.map} +1 -1
- package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/package.json +1 -1
- package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/src/embind/plannerCoreCallback.d.ts +1 -1
- package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/src/embind/plannerCoreCallback.js +3 -3
- package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/src/embind/plannerCoreCallback.js.map +1 -1
- package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/src/embind/plannerCoreInterface.d.ts +1 -7
- package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/wasm_modern/ConfiguratorKernel.wasm +0 -0
- package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/wasm_modern/RoomleCore.wasm +0 -0
- package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/wasm_modern/RoomleToolsCore.wasm +0 -0
- package/lib/{stats-helper-iprJJmBn.mjs → stats-helper-W654V5ay.mjs} +3 -3
- package/lib/{stats-helper-iprJJmBn.mjs.map → stats-helper-W654V5ay.mjs.map} +1 -1
- package/lib/{svgo.browser-EB1zkPfG.mjs → svgo.browser-xZ3L7awG.mjs} +1 -1
- package/lib/{svgo.browser-EB1zkPfG.mjs.map → svgo.browser-xZ3L7awG.mjs.map} +1 -1
- package/lib/{three.tsl-DO_HZZuJ.mjs → three.tsl-B7hcNZE8.mjs} +2 -2
- package/lib/{three.tsl-DO_HZZuJ.mjs.map → three.tsl-B7hcNZE8.mjs.map} +1 -1
- package/lib/{three.tsl-BZfU6fFt.mjs → three.tsl-BBUCm-uB.mjs} +1 -1
- package/lib/{three.webgpu-bR4-ABJu.mjs → three.webgpu-ClICiWlK.mjs} +1 -1
- package/lib/{three.webgpu-ylONY593.mjs → three.webgpu-D3nSEIjD.mjs} +1 -1
- package/lib/{three.webgpu-ylONY593.mjs.map → three.webgpu-D3nSEIjD.mjs.map} +1 -1
- package/lib/{threejs-utils-D4TdXXAR.mjs → threejs-utils-WK7Uu2TS.mjs} +4 -4
- package/lib/threejs-utils-WK7Uu2TS.mjs.map +1 -0
- package/lib/{tools-core-La7SIpTQ.mjs → tools-core-CWrR_N9g.mjs} +3 -3
- package/lib/{tools-core-La7SIpTQ.mjs.map → tools-core-CWrR_N9g.mjs.map} +1 -1
- package/lib/{webgpu-C14yfIYy.mjs → webgpu-DSecxaB8.mjs} +3 -3
- package/lib/{webgpu-C14yfIYy.mjs.map → webgpu-DSecxaB8.mjs.map} +1 -1
- package/lib/workers-B-AqdQMe.mjs +6 -0
- package/lib/{workers-YGDNEfpU.mjs.map → workers-B-AqdQMe.mjs.map} +1 -1
- package/package.json +2 -2
- package/lib/asset-loader.worker-eqHzNAwa.mjs.map +0 -1
- package/lib/budgeteer.sw-BUMElkO1.mjs.map +0 -1
- package/lib/component-dimensioning-Dao60YO2.mjs.map +0 -1
- package/lib/configurator-Bj51dFg6.mjs +0 -2
- package/lib/dimensioning-helper-0s61LK9R.mjs +0 -2
- package/lib/glb-viewer-CUyHqGdt.mjs +0 -2
- package/lib/highlight-coordinator-DOO-54ml.mjs.map +0 -1
- package/lib/homag-intelligence-BOqc8-8E.mjs.map +0 -1
- package/lib/kernel-utils-voLUOj-0.mjs.map +0 -1
- package/lib/planner-DIz5mFvC.mjs +0 -2
- package/lib/roomle-sdk-k8Vvoclf.mjs.map +0 -1
- package/lib/scene-renderer-nIOJ3nuy.mjs.map +0 -1
- package/lib/threejs-utils-D4TdXXAR.mjs.map +0 -1
- package/lib/workers-YGDNEfpU.mjs +0 -6
package/lib/{roomle-headless-setup-DbO_rLjK.mjs.map → roomle-headless-setup-ps3I0vOP.mjs.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roomle-headless-setup-DbO_rLjK.mjs","names":["#registered"],"sources":["../../packages/headless-core/src/headless-webgpu-queue-polyfill.ts","../../packages/headless-core/src/setup-environment.ts"],"sourcesContent":["/// <reference types=\"@webgpu/types\" />\n// Headless polyfill for GPUQueue.copyExternalImageToTexture (bun-webgpu stubs it).\n// See .agents/headless-sdk.md § copyExternalImageToTexture polyfill.\n\nimport type { RawImagePixels } from '../../common-core/src/common-interfaces';\n\ninterface NativeContext2d {\n clearRect(x: number, y: number, width: number, height: number): void;\n drawImage(\n image: unknown,\n x: number,\n y: number,\n width: number,\n height: number,\n ): void;\n getImageData(\n x: number,\n y: number,\n width: number,\n height: number,\n ): { data: ArrayBufferView };\n}\n\ninterface NativeCanvas {\n width: number;\n height: number;\n getContext(contextId: '2d'): NativeContext2d | null;\n}\n\ninterface ImageDataSource {\n data: ArrayBufferView;\n width: number;\n height: number;\n}\n\ninterface CanvasSource {\n width?: number;\n height?: number;\n getContext(contextId: '2d'): NativeContext2d | null;\n}\n\ninterface DrawableSource {\n width?: number;\n height?: number;\n videoWidth?: number;\n videoHeight?: number;\n}\n\nexport interface QueuePolyfillHelpers {\n createNativeCanvas: (width: number, height: number) => NativeCanvas;\n // The headless <img> proxy stores the real napi Image under a symbol; unwrap\n // it so drawImage runs native-to-native.\n unwrapImage?: (source: unknown) => unknown;\n}\n\nconst asUint8Array = (view: ArrayBufferView): Uint8Array =>\n view instanceof Uint8Array\n ? view\n : new Uint8Array(view.buffer, view.byteOffset, view.byteLength);\n\nconst toExtentSize = (\n size: GPUExtent3DStrict,\n): { width: number; height: number } => {\n if (Array.isArray(size)) {\n return { width: size[0] ?? 0, height: size[1] ?? 0 };\n }\n const { width, height } = size as GPUExtent3DDictStrict;\n return { width: width ?? 0, height: height ?? 0 };\n};\n\nconst isImageDataSource = (source: object): source is ImageDataSource =>\n ArrayBuffer.isView((source as ImageDataSource).data) &&\n typeof (source as ImageDataSource).width === 'number' &&\n typeof (source as ImageDataSource).height === 'number';\n\nconst isCanvasSource = (source: object): source is CanvasSource =>\n typeof (source as CanvasSource).getContext === 'function';\n\nconst flipRowsRGBA = (\n data: Uint8Array,\n width: number,\n height: number,\n): Uint8Array => {\n const rowBytes = width * 4;\n const flipped = new Uint8Array(rowBytes * height);\n for (let row = 0; row < height; row++) {\n flipped.set(\n data.subarray((height - 1 - row) * rowBytes, (height - row) * rowBytes),\n row * rowBytes,\n );\n }\n return flipped;\n};\n\nconst premultiplyAlphaRGBA = (data: Uint8Array): void => {\n for (let i = 0; i < data.length; i += 4) {\n const alpha = data[i + 3]!;\n if (alpha === 255) {\n continue;\n }\n const factor = alpha / 255;\n data[i] = Math.round(data[i]! * factor);\n data[i + 1] = Math.round(data[i + 1]! * factor);\n data[i + 2] = Math.round(data[i + 2]! * factor);\n }\n};\n\nconst swizzleRedBlueRGBA = (data: Uint8Array): void => {\n for (let i = 0; i < data.length; i += 4) {\n const red = data[i]!;\n data[i] = data[i + 2]!;\n data[i + 2] = red;\n }\n};\n\n// Overrides unconditionally: upstream stubs the method with a fatal error, so\n// there is nothing to feature-detect.\nexport function installCopyExternalImageToTexturePolyfill(\n device: GPUDevice | null | undefined,\n helpers: QueuePolyfillHelpers,\n): void {\n const queue = device?.queue;\n if (!queue || typeof queue.writeTexture !== 'function') {\n return;\n }\n\n // Pooled scratch canvas, reused across uploads instead of one per call.\n let scratchCanvas: NativeCanvas | null = null;\n const getScratchContext = (\n width: number,\n height: number,\n ): NativeContext2d | null => {\n if (!scratchCanvas) {\n scratchCanvas = helpers.createNativeCanvas(width, height);\n } else {\n // Assigning width/height resets the backing store, so only on a change.\n if (scratchCanvas.width !== width) {\n scratchCanvas.width = width;\n }\n if (scratchCanvas.height !== height) {\n scratchCanvas.height = height;\n }\n }\n const context = scratchCanvas.getContext('2d');\n // Resizing resets the canvas; clear defensively for same-size reuse so a\n // smaller-than-canvas draw never leaks the previous upload's pixels.\n context?.clearRect(0, 0, width, height);\n return context;\n };\n\n const extractImagePixels = (\n source: unknown,\n fallbackWidth: number,\n fallbackHeight: number,\n ): RawImagePixels | null => {\n if (!source || typeof source !== 'object') {\n return null;\n }\n\n if (isImageDataSource(source)) {\n return {\n data: asUint8Array(source.data),\n width: source.width,\n height: source.height,\n };\n }\n\n const drawable = source as DrawableSource;\n const width =\n (drawable.width ?? drawable.videoWidth ?? fallbackWidth) | 0 || 0;\n const height =\n (drawable.height ?? drawable.videoHeight ?? fallbackHeight) | 0 || 0;\n if (width <= 0 || height <= 0) {\n return null;\n }\n\n if (isCanvasSource(source)) {\n const canvasContext = source.getContext('2d');\n if (canvasContext) {\n const imageData = canvasContext.getImageData(0, 0, width, height);\n return { data: asUint8Array(imageData.data), width, height };\n }\n }\n\n const scratchContext = getScratchContext(width, height);\n if (!scratchContext) {\n return null;\n }\n scratchContext.drawImage(\n helpers.unwrapImage ? helpers.unwrapImage(source) : source,\n 0,\n 0,\n width,\n height,\n );\n const imageData = scratchContext.getImageData(0, 0, width, height);\n return { data: asUint8Array(imageData.data), width, height };\n };\n\n queue.copyExternalImageToTexture = (\n source: GPUCopyExternalImageSourceInfo,\n destination: GPUCopyExternalImageDestInfo,\n copySize: GPUExtent3DStrict,\n ): undefined => {\n const size = toExtentSize(copySize);\n const extracted = extractImagePixels(\n source?.source,\n size.width,\n size.height,\n );\n if (!extracted) {\n throw new Error(\n '[headless] copyExternalImageToTexture: could not read pixels from ' +\n \"source. Expected ImageData, a canvas exposing getContext('2d'), \" +\n 'or a drawable image.',\n );\n }\n\n const { width, height } = extracted;\n // Fall back to the source dimensions when a copySize dimension is absent.\n const copyWidth = Math.min(width, size.width || width);\n const copyHeight = Math.min(height, size.height || height);\n\n let data = extracted.data;\n let isPrivateCopy = false;\n\n if (source?.flipY) {\n data = flipRowsRGBA(data, width, height);\n isPrivateCopy = true;\n }\n\n // getImageData is straight-alpha RGBA; premultiply / bgra-swizzle to match\n // the destination as requested (bgra is rare, headless prefers rgba8unorm).\n const needsPremultiply = destination?.premultipliedAlpha === true;\n const format = destination?.texture?.format;\n const needsSwizzle =\n typeof format === 'string' && format.startsWith('bgra');\n\n if (needsPremultiply || needsSwizzle) {\n if (!isPrivateCopy) {\n data = new Uint8Array(data);\n isPrivateCopy = true;\n }\n if (needsPremultiply) {\n premultiplyAlphaRGBA(data);\n }\n if (needsSwizzle) {\n swizzleRedBlueRGBA(data);\n }\n }\n\n queue.writeTexture(\n {\n texture: destination.texture,\n mipLevel: destination.mipLevel ?? 0,\n origin: destination.origin ?? { x: 0, y: 0, z: 0 },\n aspect: destination.aspect ?? 'all',\n },\n data,\n { offset: 0, bytesPerRow: width * 4, rowsPerImage: height },\n { width: copyWidth, height: copyHeight, depthOrArrayLayers: 1 },\n );\n return undefined;\n };\n}\n","/// <reference types=\"@webgpu/types\" />\nimport { createRequire } from 'module';\nimport type { IOptionalBrowserSettings } from 'happy-dom';\nimport type { createGPUInstance } from 'bun-webgpu';\nimport { installCopyExternalImageToTexturePolyfill } from './headless-webgpu-queue-polyfill';\n\ntype BunWebGpuInstance = ReturnType<typeof createGPUInstance>;\n\nconst napiCanvas = await import('@napi-rs/canvas').catch((): null => null);\nconst happyDom = await import('happy-dom').catch((): null => null);\n\nif (!napiCanvas) {\n throw new Error(\n '[headless] @napi-rs/canvas is required for headless setup. ' +\n 'Install it (it is an optionalDependency of @roomle/web-sdk)',\n );\n}\n\nif (!happyDom) {\n throw new Error(\n '[headless] happy-dom is required for headless setup. ' +\n 'Install it (it is an optionalDependency of @roomle/web-sdk)',\n );\n}\n\nconst {\n createCanvas: createNapiCanvas,\n Image: NapiImage,\n ImageData: NapiImageData,\n} = napiCanvas;\nconst { GlobalWindow, PropertySymbol } = happyDom;\n\n// Network APIs and built-ins that happy-dom must not override\n// We rely on Node/Bun native implementations for these.\nconst IGNORE_LIST = [\n 'fetch',\n 'Response',\n 'Request',\n 'Headers',\n 'AbortController',\n 'AbortSignal',\n 'ReadableStream',\n 'WritableStream',\n 'TransformStream',\n 'FormData',\n 'URL',\n 'URLSearchParams',\n 'Blob',\n 'File',\n 'constructor',\n 'undefined',\n 'NaN',\n 'global',\n 'globalThis',\n];\n\nclass GlobalRegistrator {\n static #registered: {\n [key: string | symbol]: PropertyDescriptor | null;\n } | null = null;\n\n public static get isRegistered(): boolean {\n return this.#registered !== null;\n }\n\n public static register(options?: {\n width?: number;\n height?: number;\n url?: string;\n settings?: IOptionalBrowserSettings;\n }): void {\n if (this.#registered !== null) {\n throw new Error(\n 'Failed to register. Happy DOM has already been globally registered.',\n );\n }\n\n const window = new GlobalWindow({\n ...options,\n console: globalThis.console,\n });\n\n this.#registered = {};\n\n const propertyDescriptors = Object.getOwnPropertyDescriptors(window);\n\n for (const key of Object.keys(propertyDescriptors)) {\n if (!IGNORE_LIST.includes(key)) {\n const windowPropertyDescriptor = propertyDescriptors[key];\n const globalPropertyDescriptor = Object.getOwnPropertyDescriptor(\n globalThis,\n key,\n );\n\n if (\n globalPropertyDescriptor?.value === undefined ||\n globalPropertyDescriptor?.value !== windowPropertyDescriptor?.value\n ) {\n this.#registered[key] = globalPropertyDescriptor || null;\n\n if (windowPropertyDescriptor?.value === window) {\n (window as any)[key] = globalThis;\n windowPropertyDescriptor.value = globalThis;\n }\n\n Object.defineProperty(globalThis, key, {\n ...windowPropertyDescriptor,\n configurable: true,\n });\n }\n }\n }\n\n const propertySymbols = Object.getOwnPropertySymbols(window);\n\n for (const key of propertySymbols) {\n const propertyDescriptor = Object.getOwnPropertyDescriptor(window, key);\n this.#registered[key] = null;\n\n if (propertyDescriptor!.value === window) {\n (window as any)[key] = globalThis;\n propertyDescriptor!.value = globalThis;\n }\n\n Object.defineProperty(globalThis, key, {\n ...propertyDescriptor,\n configurable: true,\n });\n }\n\n (globalThis as any).document[PropertySymbol.defaultView] = globalThis;\n }\n\n public static async unregister(): Promise<void> {\n if (this.#registered === null) {\n throw new Error(\n 'Failed to unregister. Happy DOM has not previously been globally registered.',\n );\n }\n\n const happyDOM = (globalThis as any).happyDOM;\n\n for (const key of Object.keys(this.#registered)) {\n if (this.#registered[key] !== null) {\n Object.defineProperty(globalThis, key, this.#registered[key]!);\n } else {\n delete (globalThis as any)[key];\n }\n }\n\n this.#registered = null;\n\n if (happyDOM) {\n await happyDOM.close();\n }\n }\n}\n\n// Resolves the bundle directory so root-relative Vite asset URLs like\n// \"/default_256.exr\" can be mapped to real files next to the bundle.\n// We use a bare `import.meta.url` (not wrapped in `new URL(…, import.meta.url)`)\n// because Rollup replaces the latter pattern with a data: URI at build time.\nconst _setupRequire = createRequire(import.meta.url);\nconst _fsSync = _setupRequire('fs');\nconst _pathSync = _setupRequire('path');\nconst _urlSync = _setupRequire('url');\nlet _bundleDir = '';\ntry {\n _bundleDir = _pathSync.dirname(_urlSync.fileURLToPath(import.meta.url));\n} catch {\n // Not a file URL\n}\n\n// Maps a root-relative path (e.g. \"/default_256.exr\") to a local file path\n// next to the bundle. Returns null when the file doesn't exist. */\nconst _resolveRootRelative = (urlPath: string): string | null => {\n if (!_bundleDir || !urlPath.startsWith('/') || urlPath.startsWith('//')) {\n return null;\n }\n const candidate = _pathSync.join(_bundleDir, urlPath);\n return _fsSync.existsSync(candidate) ? candidate : null;\n};\n\n// Patch globalThis.fetch to handle:\n// 1. file:// URLs, Node/undici rejects these natively; Bun accepts them.\n// 2. Root-relative URLs (e.g. \"/default_256.exr\") emitted by Vite's ?url\n// transform; no web server in Node means native fetch throws \"Invalid URL\".\nconst _nativeFetch = globalThis.fetch;\n// @ts-ignore -- this conflicts with DOM types.\nglobalThis.fetch = async (\n input: string | URL | Request,\n init?: RequestInit,\n): Promise<Response> => {\n const url =\n typeof input === 'string'\n ? input\n : input instanceof URL\n ? input.href\n : (input as any).url ?? String(input);\n\n if (url.startsWith('file://')) {\n const buffer = _fsSync.readFileSync(_urlSync.fileURLToPath(url));\n return new Response(buffer, {\n status: 200,\n headers: { 'Content-Type': 'application/octet-stream' },\n });\n }\n\n if (url.startsWith('/') && !url.startsWith('//')) {\n const localPath = _resolveRootRelative(url);\n if (localPath) {\n return new Response(_fsSync.readFileSync(localPath), {\n status: 200,\n headers: { 'Content-Type': 'application/octet-stream' },\n });\n }\n console.warn(\n `[headless] fetch: root-relative asset not found: ${url} (bundle dir: ${_bundleDir || 'unknown'})`,\n );\n return new Response(null, { status: 404, statusText: 'Not Found' });\n }\n\n return _nativeFetch.call(this, input, init);\n};\n\n// Proxy-wrap globalThis.Request so root-relative paths are converted to\n// file:// URLs before the constructor validates them. Three.js's FileLoader\n// calls `new Request(url)` before fetch(), so our fetch patch above is never\n// reached if the constructor throws first.\nconst _OrigRequest = (globalThis as any).Request;\nif (_OrigRequest) {\n (globalThis as any).Request = new Proxy(_OrigRequest, {\n construct(Target: any, [input, init]: [any, any]) {\n if (\n typeof input === 'string' &&\n input.startsWith('/') &&\n !input.startsWith('//')\n ) {\n const localPath =\n _resolveRootRelative(input) ??\n _pathSync.join(_bundleDir || '/tmp', input);\n input = _urlSync.pathToFileURL(localPath).href;\n }\n return Reflect.construct(\n Target,\n init !== undefined ? [input, init] : [input],\n Target,\n );\n },\n get(target: any, prop: string | symbol) {\n return target[prop];\n },\n });\n}\n\nGlobalRegistrator.register();\n\n// Throttle requestAnimationFrame to ~60fps (happy-dom's is unthrottled).\n// See .agents/headless-sdk.md § requestAnimationFrame is throttled to ~60 fps.\n{\n const RAF_INTERVAL_MS = 1000 / 60;\n (globalThis as any).requestAnimationFrame = (\n callback: FrameRequestCallback,\n ): number =>\n setTimeout(\n () => callback(performance.now()),\n RAF_INTERVAL_MS,\n ) as unknown as number;\n (globalThis as any).cancelAnimationFrame = (handle: number): void =>\n clearTimeout(handle as unknown as ReturnType<typeof setTimeout>);\n}\n\n// Provide napi-rs/canvas ImageData globally as GLTFExporter uses `new ImageData(…)`\nif (typeof (globalThis as any).ImageData === 'undefined') {\n (globalThis as any).ImageData = NapiImageData;\n}\n\n// FileReader shim because happy-dom's FileReader only accepts happy-dom Blobs\nclass NodeFileReader {\n public result: ArrayBuffer | string | null = null;\n public error: unknown = null;\n public readyState: number = 0;\n public onload: ((ev: any) => void) | null = null;\n public onloadend: ((ev: any) => void) | null = null;\n public onerror: ((ev: any) => void) | null = null;\n\n readAsArrayBuffer(blob: Blob): void {\n this.readyState = 1;\n blob.arrayBuffer().then(\n (buf) => {\n this.result = buf;\n this.readyState = 2;\n const ev = { target: this };\n this.onload?.(ev);\n this.onloadend?.(ev);\n },\n (err) => {\n this.error = err;\n this.readyState = 2;\n const ev = { target: this };\n this.onerror?.(ev);\n this.onloadend?.(ev);\n },\n );\n }\n\n readAsDataURL(blob: Blob): void {\n this.readyState = 1;\n blob.arrayBuffer().then(\n (buf) => {\n const b64 = Buffer.from(buf).toString('base64');\n const type = (blob as any).type || 'application/octet-stream';\n this.result = `data:${type};base64,${b64}`;\n this.readyState = 2;\n const ev = { target: this };\n this.onload?.(ev);\n this.onloadend?.(ev);\n },\n (err) => {\n this.error = err;\n this.readyState = 2;\n const ev = { target: this };\n this.onerror?.(ev);\n this.onloadend?.(ev);\n },\n );\n }\n\n readAsText(blob: Blob): void {\n this.readyState = 1;\n blob.text().then(\n (text) => {\n this.result = text;\n this.readyState = 2;\n const ev = { target: this };\n this.onload?.(ev);\n this.onloadend?.(ev);\n },\n (err) => {\n this.error = err;\n this.readyState = 2;\n const ev = { target: this };\n this.onerror?.(ev);\n this.onloadend?.(ev);\n },\n );\n }\n\n abort(): void {}\n}\n\n(globalThis as any).FileReader = NodeFileReader;\n\n// Symbol for storing the underlying NapiImage on wrapper elements so that\n// the patched 2d context can unwrap it before calling the native drawImage.\nconst NAPI_IMAGE = Symbol('napiImage');\n\ninterface NapiImageWrapper {\n [NAPI_IMAGE]?: CanvasImageSource;\n}\n\nconst origCreateElement = document.createElement.bind(document);\nconst origCreateElementNS = document.createElementNS.bind(document);\n\n// Patches a napi-rs/canvas 2d context so drawImage() unwraps NAPI_IMAGE wrappers.\n// Skia's native drawImage only accepts its own Image/Canvas types.\nconst patchContext2d = (\n ctx: CanvasRenderingContext2D,\n): CanvasRenderingContext2D => {\n const origDrawImage = ctx.drawImage.bind(ctx);\n ctx.drawImage = (image: CanvasImageSource, ...args: any[]) => {\n const real = (image as NapiImageWrapper | undefined)?.[NAPI_IMAGE] ?? image;\n return origDrawImage(real, ...args);\n };\n return ctx;\n};\n\nlet headlessWebGpuMaxTextureDimension: number | null = null;\n\n// The GPU's granted `maxTextureDimension2D`, or null before device creation\nexport const getHeadlessWebGpuMaxTextureDimension = (): number | null => {\n return headlessWebGpuMaxTextureDimension;\n};\n\nconst SPEC_DEFAULT_MAX_TEXTURE_DIMENSION = 8192;\nconst LIMIT_VALIDATION_HINT = 0x7fffffff;\n\n// Shadows the adapter's limits with mis-read-0 fields bumped high, for\n// bun-webgpu's requiredLimits validation ONLY (see .agents/headless-sdk.md\n// § Adaptive maxTextureDimension2D). Values sent to Dawn are unchanged; without\n// this the device request throws and three falls back to its null WebGL2 backend.\nconst shadowZeroLimits = (adapter: GPUAdapter): (() => void) => {\n const realLimits = adapter.limits;\n const validationHints: Record<string, number> = {};\n for (const limitName in realLimits) {\n const limit = (realLimits as unknown as Record<string, number>)[limitName]!;\n validationHints[limitName] = limit === 0 ? LIMIT_VALIDATION_HINT : limit;\n }\n Object.defineProperty(adapter, 'limits', {\n value: validationHints,\n configurable: true,\n });\n return () =>\n Object.defineProperty(adapter, 'limits', {\n value: realLimits,\n configurable: true,\n });\n};\n\n// Strips an empty requiredLimits ({} from three) so bun-webgpu doesn't\n// pack+validate the full limits struct.\nconst withoutEmptyRequiredLimits = (\n descriptor: GPUDeviceDescriptor | undefined,\n): GPUDeviceDescriptor => {\n const { requiredLimits, ...rest } = descriptor ?? {};\n return requiredLimits && Object.keys(requiredLimits).length > 0\n ? { ...descriptor }\n : (rest as GPUDeviceDescriptor);\n};\n\nconst getGPUExtent3D = (size: GPUExtent3DStrict): GPUExtent3DStrict => {\n if (Array.isArray(size)) {\n return size;\n }\n\n const { width, height, depthOrArrayLayers } = size as GPUExtent3DDictStrict;\n return {\n width: width ?? 1,\n height: height ?? 1,\n depthOrArrayLayers: depthOrArrayLayers ?? 1,\n };\n};\n\nconst patchCopyTextureToTexture = (device: GPUDevice) => {\n const createCommandEncoder = device.createCommandEncoder.bind(device);\n device.createCommandEncoder = (descriptor?: GPUCommandEncoderDescriptor) => {\n const encoder = createCommandEncoder(descriptor);\n const copyTextureToTexture = encoder.copyTextureToTexture.bind(encoder);\n encoder.copyTextureToTexture = (\n source: GPUTexelCopyTextureInfo,\n destination: GPUTexelCopyTextureInfo,\n copySize: GPUExtent3DStrict,\n ) => copyTextureToTexture(source, destination, getGPUExtent3D(copySize));\n return encoder;\n };\n};\n\nlet gpuAcquisitionQueue: Promise<void> = Promise.resolve();\n\nconst serializeGpuAcquisition = <T>(acquire: () => Promise<T>): Promise<T> => {\n const next = gpuAcquisitionQueue.then(acquire);\n gpuAcquisitionQueue = next.then(\n () => {},\n () => {},\n );\n return next;\n};\n\nconst rememberGrantedTextureDimension = (\n device: GPUDevice,\n adapterMaxTextureDimension: number | undefined,\n) => {\n const granted = device.limits?.maxTextureDimension2D;\n if (typeof granted === 'number' && granted > 0) {\n headlessWebGpuMaxTextureDimension = granted;\n } else if (typeof adapterMaxTextureDimension === 'number') {\n headlessWebGpuMaxTextureDimension = adapterMaxTextureDimension;\n }\n};\n\nconst patchRequestDevice = (adapter: GPUAdapter) => {\n const requestDevice = adapter.requestDevice.bind(adapter);\n const adapterMaxTextureDimension = adapter.limits?.maxTextureDimension2D;\n // Raise the texture limit only when the adapter beats the spec default;\n // otherwise keep the no-requiredLimits path.\n const canRaiseTextureLimit =\n typeof adapterMaxTextureDimension === 'number' &&\n adapterMaxTextureDimension > SPEC_DEFAULT_MAX_TEXTURE_DIMENSION;\n\n const requestDeviceWithShadowedLimits = (\n request: GPUDeviceDescriptor,\n ): Promise<GPUDevice | null> => {\n if (!canRaiseTextureLimit) {\n return requestDevice(request);\n }\n const restoreLimits = shadowZeroLimits(adapter);\n try {\n return requestDevice(request);\n } finally {\n restoreLimits();\n }\n };\n\n adapter.requestDevice = async (descriptor?: GPUDeviceDescriptor) => {\n // Only maxTextureDimension2D is set; every other limit stays unset so it\n // packs the spec default and reaches Dawn as before.\n const request = canRaiseTextureLimit\n ? {\n ...descriptor,\n requiredLimits: {\n ...(descriptor?.requiredLimits ?? {}),\n maxTextureDimension2D: adapterMaxTextureDimension,\n },\n }\n : withoutEmptyRequiredLimits(descriptor);\n\n const device = await serializeGpuAcquisition(() =>\n requestDeviceWithShadowedLimits(request as GPUDeviceDescriptor),\n );\n if (!device) {\n throw new Error(\n '[headless] WebGPU adapter returned no device (adapter already invalid)',\n );\n }\n\n rememberGrantedTextureDimension(device, adapterMaxTextureDimension);\n patchCopyTextureToTexture(device);\n installCopyExternalImageToTexturePolyfill(device, {\n createNativeCanvas: createNapiCanvas,\n unwrapImage: (source: unknown) =>\n (source as NapiImageWrapper | undefined)?.[NAPI_IMAGE] ?? source,\n });\n return device;\n };\n};\n\n// Default to the discrete GPU (Dawn may otherwise pick an iGPU/CPU adapter);\n// an explicit powerPreference still wins.\nconst patchRequestAdapter = (gpu: BunWebGpuInstance) => {\n const requestAdapter = gpu.requestAdapter.bind(gpu);\n gpu.requestAdapter = async (options?: GPURequestAdapterOptions) => {\n const adapterOptions: GPURequestAdapterOptions = { ...options };\n if (!adapterOptions.powerPreference) {\n adapterOptions.powerPreference = 'high-performance';\n }\n const adapter = await serializeGpuAcquisition<GPUAdapter | null>(() =>\n requestAdapter(adapterOptions),\n );\n if (adapter?.info) {\n console.log(\n `[headless] WebGPU adapter: ${adapter.info.vendor ?? '?'} ${adapter.info.device ?? ''} (${adapter.info.description ?? ''})`,\n );\n }\n if (adapter && typeof adapter.requestDevice === 'function') {\n patchRequestDevice(adapter);\n }\n return adapter;\n };\n};\n\nconst installNavigatorGpu = (gpu: BunWebGpuInstance) => {\n const currentNavigator = (globalThis as any).navigator;\n if (!currentNavigator || typeof currentNavigator !== 'object') {\n Object.defineProperty(globalThis, 'navigator', {\n value: { gpu },\n configurable: true,\n writable: true,\n });\n return;\n }\n try {\n currentNavigator.gpu = gpu;\n } catch {\n Object.defineProperty(currentNavigator, 'gpu', {\n value: gpu,\n configurable: true,\n writable: true,\n });\n }\n};\n\n// Device creation is lazy, so probe the adapter at setup time to have the\n// limit available before the first render.\nconst probeMaxTextureDimension = async (gpu: BunWebGpuInstance) => {\n try {\n const adapter = await gpu.requestAdapter({\n powerPreference: 'high-performance',\n });\n const maxTextureDimension = adapter?.limits?.maxTextureDimension2D;\n if (\n typeof maxTextureDimension === 'number' &&\n maxTextureDimension > 0 &&\n headlessWebGpuMaxTextureDimension == null\n ) {\n headlessWebGpuMaxTextureDimension = maxTextureDimension;\n }\n } catch (error) {\n console.log('[headless] adapter texture-limit probe failed', error);\n }\n};\n\nlet webgpuInstance: BunWebGpuInstance | null = null;\ntry {\n const bunWebgpu = await import('bun-webgpu');\n // Synchronous; loads the native Dawn wrapper from the platform companion\n // package (bun-webgpu-<platform>-<arch>) and returns the navigator.gpu object.\n webgpuInstance = bunWebgpu.createGPUInstance();\n // Install the WebGPU global constructors/enums three.js references.\n bunWebgpu.globals();\n // Prefer rgba8unorm for the offscreen canvas (avoids a full-frame B/R\n // swizzle per readback). See .agents/headless-sdk.md § Preferred canvas format.\n webgpuInstance.getPreferredCanvasFormat = () => 'rgba8unorm';\n // See .agents/headless-sdk.md § Device request workarounds.\n if (typeof webgpuInstance.requestAdapter === 'function') {\n patchRequestAdapter(webgpuInstance);\n }\n installNavigatorGpu(webgpuInstance);\n console.log(\n '[headless] Using bun-webgpu (Dawn FFI) for real WebGPU rendering',\n );\n await probeMaxTextureDimension(webgpuInstance);\n} catch (error) {\n console.log('[headless] bun-webgpu not available, WebGPU disabled', error);\n}\n\n// Spec-defined WebGPU flag constants. Used literally so we don't depend on\n// node-webgpu exposing them as module exports.\nconst GPU_TEXTURE_USAGE_COPY_SRC = 0x01;\nconst GPU_TEXTURE_USAGE_TEXTURE_BINDING = 0x04;\nconst GPU_TEXTURE_USAGE_RENDER_ATTACHMENT = 0x10;\nconst GPU_BUFFER_USAGE_COPY_DST = 0x08;\nconst GPU_BUFFER_USAGE_MAP_READ = 0x01;\nconst GPU_MAP_MODE_READ = 0x01;\n// WebGPU mandates copyTextureToBuffer bytesPerRow be a 256-byte multiple.\nconst READBACK_BYTES_PER_ROW_ALIGN = 256;\n// WebGPU spec-default maxBufferSize (256 MiB), enforced by Dawn\nconst MAX_READBACK_STAGING_BYTES = 256 * 1024 * 1024;\n\n// Fullscreen-triangle blit for readbackScaled() GPU downscale.\n// See .agents/headless-sdk.md § canvas WebGPU context shim.\nconst BLIT_WGSL = /* wgsl */ `\nstruct VSOut {\n @builtin(position) pos: vec4f,\n @location(0) uv: vec2f,\n};\n\n@vertex\nfn vs(@builtin(vertex_index) vertexIndex: u32) -> VSOut {\n var corners = array<vec2f, 3>(\n vec2f(0.0, 0.0),\n vec2f(2.0, 0.0),\n vec2f(0.0, 2.0)\n );\n let xy = corners[vertexIndex];\n var out: VSOut;\n out.pos = vec4f(xy * 2.0 - 1.0, 0.0, 1.0);\n // Clip-space y is up, texture v is down, flip v so the output keeps the\n // source orientation (row 0 = top), matching the direct readback path.\n out.uv = vec2f(xy.x, 1.0 - xy.y);\n return out;\n}\n\n@group(0) @binding(0) var srcTex: texture_2d<f32>;\n@group(0) @binding(1) var srcSampler: sampler;\n\n@fragment\nfn fs(in: VSOut) -> @location(0) vec4f {\n return textureSample(srcTex, srcSampler, in.uv);\n}\n`;\n\ninterface RawFramePixels {\n data: Uint8Array;\n width: number;\n height: number;\n}\n\n// Hand-rolled GPUCanvasContext shim (no swapchain surface, render to an\n// offscreen texture, read back). See .agents/headless-sdk.md § canvas WebGPU context shim.\nconst createHeadlessWebGPUContext = (canvas: HTMLCanvasElement) => {\n let device: GPUDevice | null = null;\n let format: GPUTextureFormat = 'bgra8unorm';\n let configuredUsage: GPUTextureUsageFlags = 0;\n let texture: GPUTexture | null = null;\n let textureWidth = 0;\n let textureHeight = 0;\n let lastFramePixels: Uint8Array | null = null;\n let blitPipeline: GPURenderPipeline | null = null;\n let blitSampler: GPUSampler | null = null;\n let blitTexture: GPUTexture | null = null;\n let blitWidth = 0;\n let blitHeight = 0;\n let stagingBuffer: GPUBuffer | null = null;\n let stagingSize = 0;\n let stagingBusy = false;\n\n // Every caller below runs behind a device check on the public methods.\n const requireDevice = (): GPUDevice => {\n if (!device) {\n throw new Error('[headless] WebGPU canvas context has no device');\n }\n return device;\n };\n\n const destroyTexture = (textureToDestroy: GPUTexture) => {\n try {\n textureToDestroy.destroy();\n } catch {\n console.error('[webgpu]: Failed to destroy texture image');\n }\n };\n\n const ensureTexture = (): GPUTexture | null => {\n if (!device) {\n return null;\n }\n const gpuDevice = device;\n const width = Math.max(1, canvas.width | 0);\n const height = Math.max(1, canvas.height | 0);\n if (texture && textureWidth === width && textureHeight === height) {\n return texture;\n }\n if (texture) {\n destroyTexture(texture);\n }\n textureWidth = width;\n textureHeight = height;\n // three's configured usage plus COPY_SRC (readback), RENDER_ATTACHMENT\n // (render target), and TEXTURE_BINDING (readbackScaled blit sampling).\n const usage =\n (configuredUsage || 0) |\n GPU_TEXTURE_USAGE_RENDER_ATTACHMENT |\n GPU_TEXTURE_USAGE_COPY_SRC |\n GPU_TEXTURE_USAGE_TEXTURE_BINDING;\n texture = gpuDevice.createTexture({\n size: { width, height, depthOrArrayLayers: 1 },\n format,\n usage,\n });\n return texture;\n };\n\n const destroyBuffer = (bufferToDestroy: GPUBuffer) => {\n try {\n bufferToDestroy.destroy();\n } catch {\n console.error('[webgpu]: Failed to destroy staging buffer');\n }\n };\n\n const createReadbackBuffer = (sizeInBytes: number): GPUBuffer =>\n requireDevice().createBuffer({\n size: sizeInBytes,\n usage: GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_MAP_READ,\n });\n\n // Reuse the pooled buffer when free and sized to the band; else a fresh\n // throwaway (pool lifetime owned by configure()/unconfigure()).\n const acquireReadbackBuffer = (\n bandBytes: number,\n ): { buffer: GPUBuffer; release: () => void } => {\n if (stagingBusy) {\n const throwawayBuffer = createReadbackBuffer(bandBytes);\n return {\n buffer: throwawayBuffer,\n release: () => destroyBuffer(throwawayBuffer),\n };\n }\n if (!stagingBuffer || stagingSize !== bandBytes) {\n if (stagingBuffer) {\n destroyBuffer(stagingBuffer);\n }\n stagingBuffer = createReadbackBuffer(bandBytes);\n stagingSize = bandBytes;\n }\n stagingBusy = true;\n return {\n buffer: stagingBuffer,\n release: () => {\n stagingBusy = false;\n },\n };\n };\n\n // Dawn returns the texture's native channel order; the wrapped 2d canvas\n // expects RGBA, so bgra8unorm needs a B/R swizzle.\n const swizzleBgraToRgbaInPlace = (pixels: Uint8Array) => {\n for (let i = 0; i < pixels.length; i += 4) {\n const blue = pixels[i]!;\n pixels[i] = pixels[i + 2]!;\n pixels[i + 2] = blue;\n }\n };\n\n const readPixelsFrom = async (\n sourceTexture: GPUTexture,\n width: number,\n height: number,\n ): Promise<Uint8Array | null> => {\n const gpuDevice = requireDevice();\n const tightRowBytes = width * 4;\n const bytesPerRow =\n Math.ceil(tightRowBytes / READBACK_BYTES_PER_ROW_ALIGN) *\n READBACK_BYTES_PER_ROW_ALIGN;\n // Row-band the copy so no single staging buffer exceeds maxBufferSize\n const rowsPerBand = Math.max(\n 1,\n Math.floor((MAX_READBACK_STAGING_BYTES * 0.95) / bytesPerRow),\n );\n const { buffer: readBuffer, release } = acquireReadbackBuffer(\n bytesPerRow * Math.min(rowsPerBand, height),\n );\n\n const pixels = new Uint8Array(tightRowBytes * height);\n try {\n for (\n let bandStartRow = 0;\n bandStartRow < height;\n bandStartRow += rowsPerBand\n ) {\n const bandHeight = Math.min(rowsPerBand, height - bandStartRow);\n const encoder = gpuDevice.createCommandEncoder();\n encoder.copyTextureToBuffer(\n { texture: sourceTexture, origin: { x: 0, y: bandStartRow, z: 0 } },\n { buffer: readBuffer, bytesPerRow, rowsPerImage: bandHeight },\n { width, height: bandHeight, depthOrArrayLayers: 1 },\n );\n gpuDevice.queue.submit([encoder.finish()]);\n await readBuffer.mapAsync(GPU_MAP_MODE_READ);\n const mappedBytes = new Uint8Array(readBuffer.getMappedRange());\n // Copy tight rows out before unmap invalidates the mapped range.\n for (let rowInBand = 0; rowInBand < bandHeight; rowInBand++) {\n pixels.set(\n mappedBytes.subarray(\n rowInBand * bytesPerRow,\n rowInBand * bytesPerRow + tightRowBytes,\n ),\n (bandStartRow + rowInBand) * tightRowBytes,\n );\n }\n readBuffer.unmap();\n }\n } catch (error: unknown) {\n console.warn('[headless] WebGPU readback failed', error);\n return null;\n } finally {\n release();\n }\n\n if (format === 'bgra8unorm') {\n swizzleBgraToRgbaInPlace(pixels);\n }\n return pixels;\n };\n\n // Reads the current canvas texture into lastFramePixels (sync toDataURL\n // consumes that cache).\n const queueReadback = async (): Promise<void> => {\n if (!device || !texture) {\n return;\n }\n const pixels = await readPixelsFrom(texture, textureWidth, textureHeight);\n if (pixels) {\n lastFramePixels = pixels;\n }\n };\n\n const ensureBlitPipeline = (): {\n pipeline: GPURenderPipeline;\n sampler: GPUSampler;\n } => {\n if (blitPipeline && blitSampler) {\n return { pipeline: blitPipeline, sampler: blitSampler };\n }\n const gpuDevice = requireDevice();\n const shaderModule = gpuDevice.createShaderModule({ code: BLIT_WGSL });\n const pipeline = gpuDevice.createRenderPipeline({\n layout: 'auto',\n vertex: { module: shaderModule, entryPoint: 'vs' },\n fragment: {\n module: shaderModule,\n entryPoint: 'fs',\n targets: [{ format }],\n },\n primitive: { topology: 'triangle-list' },\n });\n const sampler = gpuDevice.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n blitPipeline = pipeline;\n blitSampler = sampler;\n return { pipeline, sampler };\n };\n\n const ensureBlitTexture = (width: number, height: number): GPUTexture => {\n if (blitTexture && blitWidth === width && blitHeight === height) {\n return blitTexture;\n }\n if (blitTexture) {\n destroyTexture(blitTexture);\n }\n blitWidth = width;\n blitHeight = height;\n blitTexture = requireDevice().createTexture({\n size: { width, height, depthOrArrayLayers: 1 },\n format,\n usage: GPU_TEXTURE_USAGE_RENDER_ATTACHMENT | GPU_TEXTURE_USAGE_COPY_SRC,\n });\n return blitTexture;\n };\n\n const releaseCanvasTexture = () => {\n if (texture) {\n destroyTexture(texture);\n texture = null;\n }\n };\n\n const releaseBlitResources = () => {\n blitPipeline = null;\n blitSampler = null;\n if (blitTexture) {\n destroyTexture(blitTexture);\n blitTexture = null;\n }\n };\n\n const releaseStagingBuffer = () => {\n if (stagingBuffer && !stagingBusy) {\n destroyBuffer(stagingBuffer);\n }\n stagingBuffer = null;\n stagingSize = 0;\n stagingBusy = false;\n };\n\n const readCanvasPixels = async (\n sourceTexture: GPUTexture,\n ): Promise<RawFramePixels | null> => {\n const pixels = await readPixelsFrom(\n sourceTexture,\n textureWidth,\n textureHeight,\n );\n return pixels\n ? { data: pixels, width: textureWidth, height: textureHeight }\n : null;\n };\n\n const blitAndReadScaled = async (\n sourceTexture: GPUTexture,\n targetWidth: number,\n targetHeight: number,\n ): Promise<RawFramePixels | null> => {\n const gpuDevice = requireDevice();\n const { pipeline, sampler } = ensureBlitPipeline();\n const blitTarget = ensureBlitTexture(targetWidth, targetHeight);\n const bindGroup = gpuDevice.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n { binding: 0, resource: sourceTexture.createView() },\n { binding: 1, resource: sampler },\n ],\n });\n const encoder = gpuDevice.createCommandEncoder();\n const renderPass = encoder.beginRenderPass({\n colorAttachments: [\n {\n view: blitTarget.createView(),\n loadOp: 'clear',\n storeOp: 'store',\n clearValue: { r: 0, g: 0, b: 0, a: 0 },\n },\n ],\n });\n renderPass.setPipeline(pipeline);\n renderPass.setBindGroup(0, bindGroup);\n renderPass.draw(3);\n renderPass.end();\n gpuDevice.queue.submit([encoder.finish()]);\n const pixels = await readPixelsFrom(blitTarget, targetWidth, targetHeight);\n return pixels\n ? { data: pixels, width: targetWidth, height: targetHeight }\n : null;\n };\n\n return {\n canvas,\n __isHeadlessWebGPUContext: true,\n configure(configuration: GPUCanvasConfiguration) {\n device = configuration.device;\n format = configuration.format || format;\n configuredUsage = configuration.usage || 0;\n // Pipeline, textures and staging buffer are format and device bound\n releaseCanvasTexture();\n releaseBlitResources();\n releaseStagingBuffer();\n },\n unconfigure() {\n releaseCanvasTexture();\n releaseBlitResources();\n releaseStagingBuffer();\n device = null;\n },\n getCurrentTexture() {\n // No implicit per-frame readback, export paths read back explicitly\n // (see .agents/headless-sdk.md § canvas WebGPU context shim).\n return ensureTexture();\n },\n // Read the current frame back (single copy + mapAsync) and cache it for\n // the sync toDataURL path.\n async flushReadback(): Promise<Uint8Array | null> {\n if (texture) {\n await queueReadback();\n }\n return lastFramePixels;\n },\n // GPU-downscale the current frame to target size and read back only that\n // (full-size fallback when no scaling). Does not touch the toDataURL cache.\n async readbackScaled(\n targetWidth: number,\n targetHeight: number,\n ): Promise<RawFramePixels | null> {\n if (!device || !texture) {\n return null;\n }\n const canvasTexture = texture;\n if (targetWidth >= textureWidth && targetHeight >= textureHeight) {\n return readCanvasPixels(canvasTexture);\n }\n try {\n return await blitAndReadScaled(\n canvasTexture,\n targetWidth,\n targetHeight,\n );\n } catch (error) {\n console.warn(\n '[headless] WebGPU scaled readback failed, falling back to full-size readback',\n error,\n );\n return readCanvasPixels(canvasTexture);\n }\n },\n getCachedPixels(): Uint8Array | null {\n return lastFramePixels;\n },\n getPreferredFormat() {\n return webgpuInstance?.getPreferredCanvasFormat?.() ?? 'bgra8unorm';\n },\n };\n};\n\nexport type WebGPUMockContext = ReturnType<typeof createHeadlessWebGPUContext>;\n\n// Wraps a napi-rs/canvas Canvas so it behaves like an HTMLCanvasElement.\n// Fakes the prototype chain via Proxy getPrototypeOf (GLTFExporter checks instanceof).\n// The 2d context's drawImage is patched to unwrap NAPI_IMAGE symbols.\nconst createCanvasProxy = (\n width: number = 300,\n height: number = 150,\n): HTMLCanvasElement => {\n const napiCanvas = createNapiCanvas(width, height);\n let cachedCtx: CanvasRenderingContext2D | null = null;\n let cachedWebGpuContext: WebGPUMockContext | null = null;\n\n const proxy = new Proxy(napiCanvas as unknown as HTMLCanvasElement, {\n get(target: any, prop: string | symbol) {\n if (prop === NAPI_IMAGE) {\n return target;\n }\n if (prop === 'data') {\n return undefined;\n }\n if (prop === 'style') {\n return target._style ?? (target._style = {});\n }\n if (prop === 'classList') {\n return (\n target._classList ??\n (target._classList = {\n add() {},\n remove() {},\n contains() {\n return false;\n },\n toggle() {},\n })\n );\n }\n if (prop === Symbol.toStringTag) {\n return 'HTMLCanvasElement';\n }\n\n if (prop === 'getContext') {\n return (contextType: string, attrs?: any) => {\n if (contextType === '2d') {\n if (!cachedCtx) {\n cachedCtx = patchContext2d(target.getContext('2d', attrs));\n }\n return cachedCtx;\n }\n if (contextType === 'webgl2' || contextType === 'webgl') {\n // headless-sdk only runs on webGPU\n return null;\n }\n if (contextType === 'webgpu') {\n if (!webgpuInstance) {\n return null;\n }\n if (!cachedWebGpuContext) {\n cachedWebGpuContext = createHeadlessWebGPUContext(proxy);\n }\n return cachedWebGpuContext;\n }\n return target.getContext(contextType, attrs);\n };\n }\n\n if (prop === 'addEventListener' || prop === 'removeEventListener') {\n return () => {};\n }\n\n if (prop === 'getBoundingClientRect') {\n return () => ({\n x: 0,\n y: 0,\n width: target.width,\n height: target.height,\n top: 0,\n left: 0,\n bottom: target.height,\n right: target.width,\n });\n }\n\n // WebGPU: blit the last cached frame into the 2d canvas (lags one frame\n // unless the caller flushed the readback first, as the image renderer does).\n if (prop === 'toDataURL' && cachedWebGpuContext) {\n const webGpuContext = cachedWebGpuContext;\n return (mimeType?: string, quality?: number) => {\n const pixels = webGpuContext.getCachedPixels();\n if (pixels) {\n target\n .getContext('2d')\n .putImageData(\n new NapiImageData(\n new Uint8ClampedArray(pixels.buffer),\n target.width,\n target.height,\n ),\n 0,\n 0,\n );\n }\n return target.toDataURL(mimeType, quality);\n };\n }\n const value = target[prop];\n return typeof value === 'function' ? value.bind(target) : value;\n },\n\n set(target: any, prop: string | symbol, value: any) {\n target[prop] = value;\n return true;\n },\n\n getPrototypeOf() {\n return HTMLCanvasElement.prototype;\n },\n });\n\n return proxy;\n};\n\n// Keeps texture downloads cancellable; see .agents/headless-sdk/debugging.md,\n// item 14.\nconst IMAGE_FETCH_TIMEOUT_MS = 30_000;\nconst IMAGE_FETCH_ATTEMPTS = 3;\n\nconst fetchImageBytes = async (url: string): Promise<ArrayBuffer> => {\n let lastError: unknown;\n for (let attempt = 1; attempt <= IMAGE_FETCH_ATTEMPTS; attempt++) {\n try {\n const response = await fetch(url, {\n signal: AbortSignal.timeout(IMAGE_FETCH_TIMEOUT_MS),\n });\n if (!response.ok) {\n throw new Error(`HTTP ${response.status} for ${url}`);\n }\n return await response.arrayBuffer();\n } catch (error) {\n lastError = error;\n console.warn(\n `image request attempt ${attempt}/${IMAGE_FETCH_ATTEMPTS} failed for ${url}:`,\n error instanceof Error ? error.message : error,\n );\n }\n }\n throw lastError instanceof Error ? lastError : new Error(String(lastError));\n};\n\n// Creates a happy-dom HTMLImageElement backed by a napi-rs/canvas Image so that\n// images are actually decoded and canvas drawImage() works correctly.\nconst createNapiImageElement = (): HTMLImageElement => {\n const el = origCreateElementNS(\n 'http://www.w3.org/1999/xhtml',\n 'img',\n ) as HTMLImageElement;\n const napiImg = new NapiImage();\n\n (el as any)[NAPI_IMAGE] = napiImg;\n\n let currentSrc = '';\n Object.defineProperty(el, 'src', {\n get() {\n return currentSrc;\n },\n set(url: string) {\n currentSrc = url;\n // napi-rs/canvas Image cannot fetch blob: URLs (created by\n // URL.createObjectURL used heavily by GLTFLoader for embedded\n // textures). Resolve them ourselves via fetch (Node ≥18 understands\n // its own blob URL registry) and feed the bytes in as a Buffer.\n const isFetchable =\n typeof url === 'string' &&\n (url.startsWith('blob:') ||\n url.startsWith('http:') ||\n url.startsWith('https:'));\n if (isFetchable) {\n const load = url.startsWith('blob:')\n ? fetch(url).then((r) => r.arrayBuffer())\n : fetchImageBytes(url);\n load\n .then((ab) => {\n // Guard against a later src reassignment racing this resolution.\n if (currentSrc !== url) {\n return;\n }\n napiImg.src = Buffer.from(ab);\n })\n .catch((err) => {\n if (currentSrc !== url) {\n return;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n el.dispatchEvent(\n new ErrorEvent('error', { error, message: error.message }),\n );\n });\n return;\n }\n napiImg.src = url;\n },\n configurable: true,\n });\n\n napiImg.onload = () => {\n Object.defineProperty(el, 'width', {\n value: napiImg.width,\n writable: true,\n configurable: true,\n });\n Object.defineProperty(el, 'height', {\n value: napiImg.height,\n writable: true,\n configurable: true,\n });\n Object.defineProperty(el, 'naturalWidth', {\n value: napiImg.naturalWidth,\n configurable: true,\n });\n Object.defineProperty(el, 'naturalHeight', {\n value: napiImg.naturalHeight,\n configurable: true,\n });\n Object.defineProperty(el, 'complete', { value: true, configurable: true });\n el.dispatchEvent(new Event('load'));\n };\n\n napiImg.onerror = (err: Error) => {\n el.dispatchEvent(\n new ErrorEvent('error', { error: err, message: err?.message }),\n );\n };\n\n return el;\n};\n\ndocument.createElement = (\n tagName: string,\n options?: ElementCreationOptions,\n) => {\n if (tagName.toLowerCase() === 'canvas') {\n return createCanvasProxy();\n }\n return origCreateElement(tagName, options);\n};\n\ndocument.createElementNS = (\n namespaceURI: string | null,\n qualifiedName: string,\n options?: ElementCreationOptions,\n) => {\n const tag = qualifiedName.toLowerCase();\n if (tag === 'canvas') {\n return createCanvasProxy();\n }\n if (tag === 'img') {\n return createNapiImageElement();\n }\n return origCreateElementNS(namespaceURI, qualifiedName, options);\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"roomle-headless-setup-ps3I0vOP.mjs","names":["#registered"],"sources":["../../packages/headless-core/src/headless-webgpu-queue-polyfill.ts","../../packages/headless-core/src/setup-environment.ts"],"sourcesContent":["/// <reference types=\"@webgpu/types\" />\n// Headless polyfill for GPUQueue.copyExternalImageToTexture (bun-webgpu stubs it).\n// See .agents/headless-sdk.md § copyExternalImageToTexture polyfill.\n\nimport type { RawImagePixels } from '../../common-core/src/common-interfaces';\n\ninterface NativeContext2d {\n clearRect(x: number, y: number, width: number, height: number): void;\n drawImage(\n image: unknown,\n x: number,\n y: number,\n width: number,\n height: number,\n ): void;\n getImageData(\n x: number,\n y: number,\n width: number,\n height: number,\n ): { data: ArrayBufferView };\n}\n\ninterface NativeCanvas {\n width: number;\n height: number;\n getContext(contextId: '2d'): NativeContext2d | null;\n}\n\ninterface ImageDataSource {\n data: ArrayBufferView;\n width: number;\n height: number;\n}\n\ninterface CanvasSource {\n width?: number;\n height?: number;\n getContext(contextId: '2d'): NativeContext2d | null;\n}\n\ninterface DrawableSource {\n width?: number;\n height?: number;\n videoWidth?: number;\n videoHeight?: number;\n}\n\nexport interface QueuePolyfillHelpers {\n createNativeCanvas: (width: number, height: number) => NativeCanvas;\n // The headless <img> proxy stores the real napi Image under a symbol; unwrap\n // it so drawImage runs native-to-native.\n unwrapImage?: (source: unknown) => unknown;\n}\n\nconst asUint8Array = (view: ArrayBufferView): Uint8Array =>\n view instanceof Uint8Array\n ? view\n : new Uint8Array(view.buffer, view.byteOffset, view.byteLength);\n\nconst toExtentSize = (\n size: GPUExtent3DStrict,\n): { width: number; height: number } => {\n if (Array.isArray(size)) {\n return { width: size[0] ?? 0, height: size[1] ?? 0 };\n }\n const { width, height } = size as GPUExtent3DDictStrict;\n return { width: width ?? 0, height: height ?? 0 };\n};\n\nconst isImageDataSource = (source: object): source is ImageDataSource =>\n ArrayBuffer.isView((source as ImageDataSource).data) &&\n typeof (source as ImageDataSource).width === 'number' &&\n typeof (source as ImageDataSource).height === 'number';\n\nconst isCanvasSource = (source: object): source is CanvasSource =>\n typeof (source as CanvasSource).getContext === 'function';\n\nconst flipRowsRGBA = (\n data: Uint8Array,\n width: number,\n height: number,\n): Uint8Array => {\n const rowBytes = width * 4;\n const flipped = new Uint8Array(rowBytes * height);\n for (let row = 0; row < height; row++) {\n flipped.set(\n data.subarray((height - 1 - row) * rowBytes, (height - row) * rowBytes),\n row * rowBytes,\n );\n }\n return flipped;\n};\n\nconst premultiplyAlphaRGBA = (data: Uint8Array): void => {\n for (let i = 0; i < data.length; i += 4) {\n const alpha = data[i + 3]!;\n if (alpha === 255) {\n continue;\n }\n const factor = alpha / 255;\n data[i] = Math.round(data[i]! * factor);\n data[i + 1] = Math.round(data[i + 1]! * factor);\n data[i + 2] = Math.round(data[i + 2]! * factor);\n }\n};\n\nconst swizzleRedBlueRGBA = (data: Uint8Array): void => {\n for (let i = 0; i < data.length; i += 4) {\n const red = data[i]!;\n data[i] = data[i + 2]!;\n data[i + 2] = red;\n }\n};\n\n// Overrides unconditionally: upstream stubs the method with a fatal error, so\n// there is nothing to feature-detect.\nexport function installCopyExternalImageToTexturePolyfill(\n device: GPUDevice | null | undefined,\n helpers: QueuePolyfillHelpers,\n): void {\n const queue = device?.queue;\n if (!queue || typeof queue.writeTexture !== 'function') {\n return;\n }\n\n // Pooled scratch canvas, reused across uploads instead of one per call.\n let scratchCanvas: NativeCanvas | null = null;\n const getScratchContext = (\n width: number,\n height: number,\n ): NativeContext2d | null => {\n if (!scratchCanvas) {\n scratchCanvas = helpers.createNativeCanvas(width, height);\n } else {\n // Assigning width/height resets the backing store, so only on a change.\n if (scratchCanvas.width !== width) {\n scratchCanvas.width = width;\n }\n if (scratchCanvas.height !== height) {\n scratchCanvas.height = height;\n }\n }\n const context = scratchCanvas.getContext('2d');\n // Resizing resets the canvas; clear defensively for same-size reuse so a\n // smaller-than-canvas draw never leaks the previous upload's pixels.\n context?.clearRect(0, 0, width, height);\n return context;\n };\n\n const extractImagePixels = (\n source: unknown,\n fallbackWidth: number,\n fallbackHeight: number,\n ): RawImagePixels | null => {\n if (!source || typeof source !== 'object') {\n return null;\n }\n\n if (isImageDataSource(source)) {\n return {\n data: asUint8Array(source.data),\n width: source.width,\n height: source.height,\n };\n }\n\n const drawable = source as DrawableSource;\n const width =\n (drawable.width ?? drawable.videoWidth ?? fallbackWidth) | 0 || 0;\n const height =\n (drawable.height ?? drawable.videoHeight ?? fallbackHeight) | 0 || 0;\n if (width <= 0 || height <= 0) {\n return null;\n }\n\n if (isCanvasSource(source)) {\n const canvasContext = source.getContext('2d');\n if (canvasContext) {\n const imageData = canvasContext.getImageData(0, 0, width, height);\n return { data: asUint8Array(imageData.data), width, height };\n }\n }\n\n const scratchContext = getScratchContext(width, height);\n if (!scratchContext) {\n return null;\n }\n scratchContext.drawImage(\n helpers.unwrapImage ? helpers.unwrapImage(source) : source,\n 0,\n 0,\n width,\n height,\n );\n const imageData = scratchContext.getImageData(0, 0, width, height);\n return { data: asUint8Array(imageData.data), width, height };\n };\n\n queue.copyExternalImageToTexture = (\n source: GPUCopyExternalImageSourceInfo,\n destination: GPUCopyExternalImageDestInfo,\n copySize: GPUExtent3DStrict,\n ): undefined => {\n const size = toExtentSize(copySize);\n const extracted = extractImagePixels(\n source?.source,\n size.width,\n size.height,\n );\n if (!extracted) {\n throw new Error(\n '[headless] copyExternalImageToTexture: could not read pixels from ' +\n \"source. Expected ImageData, a canvas exposing getContext('2d'), \" +\n 'or a drawable image.',\n );\n }\n\n const { width, height } = extracted;\n // Fall back to the source dimensions when a copySize dimension is absent.\n const copyWidth = Math.min(width, size.width || width);\n const copyHeight = Math.min(height, size.height || height);\n\n let data = extracted.data;\n let isPrivateCopy = false;\n\n if (source?.flipY) {\n data = flipRowsRGBA(data, width, height);\n isPrivateCopy = true;\n }\n\n // getImageData is straight-alpha RGBA; premultiply / bgra-swizzle to match\n // the destination as requested (bgra is rare, headless prefers rgba8unorm).\n const needsPremultiply = destination?.premultipliedAlpha === true;\n const format = destination?.texture?.format;\n const needsSwizzle =\n typeof format === 'string' && format.startsWith('bgra');\n\n if (needsPremultiply || needsSwizzle) {\n if (!isPrivateCopy) {\n data = new Uint8Array(data);\n isPrivateCopy = true;\n }\n if (needsPremultiply) {\n premultiplyAlphaRGBA(data);\n }\n if (needsSwizzle) {\n swizzleRedBlueRGBA(data);\n }\n }\n\n queue.writeTexture(\n {\n texture: destination.texture,\n mipLevel: destination.mipLevel ?? 0,\n origin: destination.origin ?? { x: 0, y: 0, z: 0 },\n aspect: destination.aspect ?? 'all',\n },\n data,\n { offset: 0, bytesPerRow: width * 4, rowsPerImage: height },\n { width: copyWidth, height: copyHeight, depthOrArrayLayers: 1 },\n );\n return undefined;\n };\n}\n","/// <reference types=\"@webgpu/types\" />\nimport { createRequire } from 'module';\nimport type { IOptionalBrowserSettings } from 'happy-dom';\nimport type { createGPUInstance } from 'bun-webgpu';\nimport { installCopyExternalImageToTexturePolyfill } from './headless-webgpu-queue-polyfill';\n\ntype BunWebGpuInstance = ReturnType<typeof createGPUInstance>;\n\nconst napiCanvas = await import('@napi-rs/canvas').catch((): null => null);\nconst happyDom = await import('happy-dom').catch((): null => null);\n\nif (!napiCanvas) {\n throw new Error(\n '[headless] @napi-rs/canvas is required for headless setup. ' +\n 'Install it (it is an optionalDependency of @roomle/web-sdk)',\n );\n}\n\nif (!happyDom) {\n throw new Error(\n '[headless] happy-dom is required for headless setup. ' +\n 'Install it (it is an optionalDependency of @roomle/web-sdk)',\n );\n}\n\nconst {\n createCanvas: createNapiCanvas,\n Image: NapiImage,\n ImageData: NapiImageData,\n} = napiCanvas;\nconst { GlobalWindow, PropertySymbol } = happyDom;\n\n// Network APIs and built-ins that happy-dom must not override\n// We rely on Node/Bun native implementations for these.\nconst IGNORE_LIST = [\n 'fetch',\n 'Response',\n 'Request',\n 'Headers',\n 'AbortController',\n 'AbortSignal',\n 'ReadableStream',\n 'WritableStream',\n 'TransformStream',\n 'FormData',\n 'URL',\n 'URLSearchParams',\n 'Blob',\n 'File',\n 'constructor',\n 'undefined',\n 'NaN',\n 'global',\n 'globalThis',\n];\n\nclass GlobalRegistrator {\n static #registered: {\n [key: string | symbol]: PropertyDescriptor | null;\n } | null = null;\n\n public static get isRegistered(): boolean {\n return this.#registered !== null;\n }\n\n public static register(options?: {\n width?: number;\n height?: number;\n url?: string;\n settings?: IOptionalBrowserSettings;\n }): void {\n if (this.#registered !== null) {\n throw new Error(\n 'Failed to register. Happy DOM has already been globally registered.',\n );\n }\n\n const window = new GlobalWindow({\n ...options,\n console: globalThis.console,\n });\n\n this.#registered = {};\n\n const propertyDescriptors = Object.getOwnPropertyDescriptors(window);\n\n for (const key of Object.keys(propertyDescriptors)) {\n if (!IGNORE_LIST.includes(key)) {\n const windowPropertyDescriptor = propertyDescriptors[key];\n const globalPropertyDescriptor = Object.getOwnPropertyDescriptor(\n globalThis,\n key,\n );\n\n if (\n globalPropertyDescriptor?.value === undefined ||\n globalPropertyDescriptor?.value !== windowPropertyDescriptor?.value\n ) {\n this.#registered[key] = globalPropertyDescriptor || null;\n\n if (windowPropertyDescriptor?.value === window) {\n (window as any)[key] = globalThis;\n windowPropertyDescriptor.value = globalThis;\n }\n\n Object.defineProperty(globalThis, key, {\n ...windowPropertyDescriptor,\n configurable: true,\n });\n }\n }\n }\n\n const propertySymbols = Object.getOwnPropertySymbols(window);\n\n for (const key of propertySymbols) {\n const propertyDescriptor = Object.getOwnPropertyDescriptor(window, key);\n this.#registered[key] = null;\n\n if (propertyDescriptor!.value === window) {\n (window as any)[key] = globalThis;\n propertyDescriptor!.value = globalThis;\n }\n\n Object.defineProperty(globalThis, key, {\n ...propertyDescriptor,\n configurable: true,\n });\n }\n\n (globalThis as any).document[PropertySymbol.defaultView] = globalThis;\n }\n\n public static async unregister(): Promise<void> {\n if (this.#registered === null) {\n throw new Error(\n 'Failed to unregister. Happy DOM has not previously been globally registered.',\n );\n }\n\n const happyDOM = (globalThis as any).happyDOM;\n\n for (const key of Object.keys(this.#registered)) {\n if (this.#registered[key] !== null) {\n Object.defineProperty(globalThis, key, this.#registered[key]!);\n } else {\n delete (globalThis as any)[key];\n }\n }\n\n this.#registered = null;\n\n if (happyDOM) {\n await happyDOM.close();\n }\n }\n}\n\n// Resolves the bundle directory so root-relative Vite asset URLs like\n// \"/default_256.exr\" can be mapped to real files next to the bundle.\n// We use a bare `import.meta.url` (not wrapped in `new URL(…, import.meta.url)`)\n// because Rollup replaces the latter pattern with a data: URI at build time.\nconst _setupRequire = createRequire(import.meta.url);\nconst _fsSync = _setupRequire('fs');\nconst _pathSync = _setupRequire('path');\nconst _urlSync = _setupRequire('url');\nlet _bundleDir = '';\ntry {\n _bundleDir = _pathSync.dirname(_urlSync.fileURLToPath(import.meta.url));\n} catch {\n // Not a file URL\n}\n\n// Maps a root-relative path (e.g. \"/default_256.exr\") to a local file path\n// next to the bundle. Returns null when the file doesn't exist. */\nconst _resolveRootRelative = (urlPath: string): string | null => {\n if (!_bundleDir || !urlPath.startsWith('/') || urlPath.startsWith('//')) {\n return null;\n }\n const candidate = _pathSync.join(_bundleDir, urlPath);\n return _fsSync.existsSync(candidate) ? candidate : null;\n};\n\n// Patch globalThis.fetch to handle:\n// 1. file:// URLs, Node/undici rejects these natively; Bun accepts them.\n// 2. Root-relative URLs (e.g. \"/default_256.exr\") emitted by Vite's ?url\n// transform; no web server in Node means native fetch throws \"Invalid URL\".\nconst _nativeFetch = globalThis.fetch;\n// @ts-ignore -- this conflicts with DOM types.\nglobalThis.fetch = async (\n input: string | URL | Request,\n init?: RequestInit,\n): Promise<Response> => {\n const url =\n typeof input === 'string'\n ? input\n : input instanceof URL\n ? input.href\n : (input as any).url ?? String(input);\n\n if (url.startsWith('file://')) {\n const buffer = _fsSync.readFileSync(_urlSync.fileURLToPath(url));\n return new Response(buffer, {\n status: 200,\n headers: { 'Content-Type': 'application/octet-stream' },\n });\n }\n\n if (url.startsWith('/') && !url.startsWith('//')) {\n const localPath = _resolveRootRelative(url);\n if (localPath) {\n return new Response(_fsSync.readFileSync(localPath), {\n status: 200,\n headers: { 'Content-Type': 'application/octet-stream' },\n });\n }\n console.warn(\n `[headless] fetch: root-relative asset not found: ${url} (bundle dir: ${_bundleDir || 'unknown'})`,\n );\n return new Response(null, { status: 404, statusText: 'Not Found' });\n }\n\n return _nativeFetch.call(this, input, init);\n};\n\n// Proxy-wrap globalThis.Request so root-relative paths are converted to\n// file:// URLs before the constructor validates them. Three.js's FileLoader\n// calls `new Request(url)` before fetch(), so our fetch patch above is never\n// reached if the constructor throws first.\nconst _OrigRequest = (globalThis as any).Request;\nif (_OrigRequest) {\n (globalThis as any).Request = new Proxy(_OrigRequest, {\n construct(Target: any, [input, init]: [any, any]) {\n if (\n typeof input === 'string' &&\n input.startsWith('/') &&\n !input.startsWith('//')\n ) {\n const localPath =\n _resolveRootRelative(input) ??\n _pathSync.join(_bundleDir || '/tmp', input);\n input = _urlSync.pathToFileURL(localPath).href;\n }\n return Reflect.construct(\n Target,\n init !== undefined ? [input, init] : [input],\n Target,\n );\n },\n get(target: any, prop: string | symbol) {\n return target[prop];\n },\n });\n}\n\nGlobalRegistrator.register();\n\n// Throttle requestAnimationFrame to ~60fps (happy-dom's is unthrottled).\n// See .agents/headless-sdk.md § requestAnimationFrame is throttled to ~60 fps.\n{\n const RAF_INTERVAL_MS = 1000 / 60;\n (globalThis as any).requestAnimationFrame = (\n callback: FrameRequestCallback,\n ): number =>\n setTimeout(\n () => callback(performance.now()),\n RAF_INTERVAL_MS,\n ) as unknown as number;\n (globalThis as any).cancelAnimationFrame = (handle: number): void =>\n clearTimeout(handle as unknown as ReturnType<typeof setTimeout>);\n}\n\n// Provide napi-rs/canvas ImageData globally as GLTFExporter uses `new ImageData(…)`\nif (typeof (globalThis as any).ImageData === 'undefined') {\n (globalThis as any).ImageData = NapiImageData;\n}\n\n// FileReader shim because happy-dom's FileReader only accepts happy-dom Blobs\nclass NodeFileReader {\n public result: ArrayBuffer | string | null = null;\n public error: unknown = null;\n public readyState: number = 0;\n public onload: ((ev: any) => void) | null = null;\n public onloadend: ((ev: any) => void) | null = null;\n public onerror: ((ev: any) => void) | null = null;\n\n readAsArrayBuffer(blob: Blob): void {\n this.readyState = 1;\n blob.arrayBuffer().then(\n (buf) => {\n this.result = buf;\n this.readyState = 2;\n const ev = { target: this };\n this.onload?.(ev);\n this.onloadend?.(ev);\n },\n (err) => {\n this.error = err;\n this.readyState = 2;\n const ev = { target: this };\n this.onerror?.(ev);\n this.onloadend?.(ev);\n },\n );\n }\n\n readAsDataURL(blob: Blob): void {\n this.readyState = 1;\n blob.arrayBuffer().then(\n (buf) => {\n const b64 = Buffer.from(buf).toString('base64');\n const type = (blob as any).type || 'application/octet-stream';\n this.result = `data:${type};base64,${b64}`;\n this.readyState = 2;\n const ev = { target: this };\n this.onload?.(ev);\n this.onloadend?.(ev);\n },\n (err) => {\n this.error = err;\n this.readyState = 2;\n const ev = { target: this };\n this.onerror?.(ev);\n this.onloadend?.(ev);\n },\n );\n }\n\n readAsText(blob: Blob): void {\n this.readyState = 1;\n blob.text().then(\n (text) => {\n this.result = text;\n this.readyState = 2;\n const ev = { target: this };\n this.onload?.(ev);\n this.onloadend?.(ev);\n },\n (err) => {\n this.error = err;\n this.readyState = 2;\n const ev = { target: this };\n this.onerror?.(ev);\n this.onloadend?.(ev);\n },\n );\n }\n\n abort(): void {}\n}\n\n(globalThis as any).FileReader = NodeFileReader;\n\n// Symbol for storing the underlying NapiImage on wrapper elements so that\n// the patched 2d context can unwrap it before calling the native drawImage.\nconst NAPI_IMAGE = Symbol('napiImage');\n\ninterface NapiImageWrapper {\n [NAPI_IMAGE]?: CanvasImageSource;\n}\n\nconst origCreateElement = document.createElement.bind(document);\nconst origCreateElementNS = document.createElementNS.bind(document);\n\n// Patches a napi-rs/canvas 2d context so drawImage() unwraps NAPI_IMAGE wrappers.\n// Skia's native drawImage only accepts its own Image/Canvas types.\nconst patchContext2d = (\n ctx: CanvasRenderingContext2D,\n): CanvasRenderingContext2D => {\n const origDrawImage = ctx.drawImage.bind(ctx);\n ctx.drawImage = (image: CanvasImageSource, ...args: any[]) => {\n const real = (image as NapiImageWrapper | undefined)?.[NAPI_IMAGE] ?? image;\n return origDrawImage(real, ...args);\n };\n return ctx;\n};\n\nlet headlessWebGpuMaxTextureDimension: number | null = null;\n\n// The GPU's granted `maxTextureDimension2D`, or null before device creation\nexport const getHeadlessWebGpuMaxTextureDimension = (): number | null => {\n return headlessWebGpuMaxTextureDimension;\n};\n\nconst SPEC_DEFAULT_MAX_TEXTURE_DIMENSION = 8192;\nconst LIMIT_VALIDATION_HINT = 0x7fffffff;\n\n// Shadows the adapter's limits with mis-read-0 fields bumped high, for\n// bun-webgpu's requiredLimits validation ONLY (see .agents/headless-sdk.md\n// § Adaptive maxTextureDimension2D). Values sent to Dawn are unchanged; without\n// this the device request throws and three falls back to its null WebGL2 backend.\nconst shadowZeroLimits = (adapter: GPUAdapter): (() => void) => {\n const realLimits = adapter.limits;\n const validationHints: Record<string, number> = {};\n for (const limitName in realLimits) {\n const limit = (realLimits as unknown as Record<string, number>)[limitName]!;\n validationHints[limitName] = limit === 0 ? LIMIT_VALIDATION_HINT : limit;\n }\n Object.defineProperty(adapter, 'limits', {\n value: validationHints,\n configurable: true,\n });\n return () =>\n Object.defineProperty(adapter, 'limits', {\n value: realLimits,\n configurable: true,\n });\n};\n\n// Strips an empty requiredLimits ({} from three) so bun-webgpu doesn't\n// pack+validate the full limits struct.\nconst withoutEmptyRequiredLimits = (\n descriptor: GPUDeviceDescriptor | undefined,\n): GPUDeviceDescriptor => {\n const { requiredLimits, ...rest } = descriptor ?? {};\n return requiredLimits && Object.keys(requiredLimits).length > 0\n ? { ...descriptor }\n : (rest as GPUDeviceDescriptor);\n};\n\nconst getGPUExtent3D = (size: GPUExtent3DStrict): GPUExtent3DStrict => {\n if (Array.isArray(size)) {\n return size;\n }\n\n const { width, height, depthOrArrayLayers } = size as GPUExtent3DDictStrict;\n return {\n width: width ?? 1,\n height: height ?? 1,\n depthOrArrayLayers: depthOrArrayLayers ?? 1,\n };\n};\n\nconst patchCopyTextureToTexture = (device: GPUDevice) => {\n const createCommandEncoder = device.createCommandEncoder.bind(device);\n device.createCommandEncoder = (descriptor?: GPUCommandEncoderDescriptor) => {\n const encoder = createCommandEncoder(descriptor);\n const copyTextureToTexture = encoder.copyTextureToTexture.bind(encoder);\n encoder.copyTextureToTexture = (\n source: GPUTexelCopyTextureInfo,\n destination: GPUTexelCopyTextureInfo,\n copySize: GPUExtent3DStrict,\n ) => copyTextureToTexture(source, destination, getGPUExtent3D(copySize));\n return encoder;\n };\n};\n\nlet gpuAcquisitionQueue: Promise<void> = Promise.resolve();\n\nconst serializeGpuAcquisition = <T>(acquire: () => Promise<T>): Promise<T> => {\n const next = gpuAcquisitionQueue.then(acquire);\n gpuAcquisitionQueue = next.then(\n () => {},\n () => {},\n );\n return next;\n};\n\nconst rememberGrantedTextureDimension = (\n device: GPUDevice,\n adapterMaxTextureDimension: number | undefined,\n) => {\n const granted = device.limits?.maxTextureDimension2D;\n if (typeof granted === 'number' && granted > 0) {\n headlessWebGpuMaxTextureDimension = granted;\n } else if (typeof adapterMaxTextureDimension === 'number') {\n headlessWebGpuMaxTextureDimension = adapterMaxTextureDimension;\n }\n};\n\nconst patchRequestDevice = (adapter: GPUAdapter) => {\n const requestDevice = adapter.requestDevice.bind(adapter);\n const adapterMaxTextureDimension = adapter.limits?.maxTextureDimension2D;\n // Raise the texture limit only when the adapter beats the spec default;\n // otherwise keep the no-requiredLimits path.\n const canRaiseTextureLimit =\n typeof adapterMaxTextureDimension === 'number' &&\n adapterMaxTextureDimension > SPEC_DEFAULT_MAX_TEXTURE_DIMENSION;\n\n const requestDeviceWithShadowedLimits = (\n request: GPUDeviceDescriptor,\n ): Promise<GPUDevice | null> => {\n if (!canRaiseTextureLimit) {\n return requestDevice(request);\n }\n const restoreLimits = shadowZeroLimits(adapter);\n try {\n return requestDevice(request);\n } finally {\n restoreLimits();\n }\n };\n\n adapter.requestDevice = async (descriptor?: GPUDeviceDescriptor) => {\n // Only maxTextureDimension2D is set; every other limit stays unset so it\n // packs the spec default and reaches Dawn as before.\n const request = canRaiseTextureLimit\n ? {\n ...descriptor,\n requiredLimits: {\n ...(descriptor?.requiredLimits ?? {}),\n maxTextureDimension2D: adapterMaxTextureDimension,\n },\n }\n : withoutEmptyRequiredLimits(descriptor);\n\n const device = await serializeGpuAcquisition(() =>\n requestDeviceWithShadowedLimits(request as GPUDeviceDescriptor),\n );\n if (!device) {\n throw new Error(\n '[headless] WebGPU adapter returned no device (adapter already invalid)',\n );\n }\n\n rememberGrantedTextureDimension(device, adapterMaxTextureDimension);\n patchCopyTextureToTexture(device);\n installCopyExternalImageToTexturePolyfill(device, {\n createNativeCanvas: createNapiCanvas,\n unwrapImage: (source: unknown) =>\n (source as NapiImageWrapper | undefined)?.[NAPI_IMAGE] ?? source,\n });\n return device;\n };\n};\n\n// Default to the discrete GPU (Dawn may otherwise pick an iGPU/CPU adapter);\n// an explicit powerPreference still wins.\nconst patchRequestAdapter = (gpu: BunWebGpuInstance) => {\n const requestAdapter = gpu.requestAdapter.bind(gpu);\n gpu.requestAdapter = async (options?: GPURequestAdapterOptions) => {\n const adapterOptions: GPURequestAdapterOptions = { ...options };\n if (!adapterOptions.powerPreference) {\n adapterOptions.powerPreference = 'high-performance';\n }\n const adapter = await serializeGpuAcquisition<GPUAdapter | null>(() =>\n requestAdapter(adapterOptions),\n );\n if (adapter?.info) {\n console.log(\n `[headless] WebGPU adapter: ${adapter.info.vendor ?? '?'} ${adapter.info.device ?? ''} (${adapter.info.description ?? ''})`,\n );\n }\n if (adapter && typeof adapter.requestDevice === 'function') {\n patchRequestDevice(adapter);\n }\n return adapter;\n };\n};\n\nconst installNavigatorGpu = (gpu: BunWebGpuInstance) => {\n const currentNavigator = (globalThis as any).navigator;\n if (!currentNavigator || typeof currentNavigator !== 'object') {\n Object.defineProperty(globalThis, 'navigator', {\n value: { gpu },\n configurable: true,\n writable: true,\n });\n return;\n }\n try {\n currentNavigator.gpu = gpu;\n } catch {\n Object.defineProperty(currentNavigator, 'gpu', {\n value: gpu,\n configurable: true,\n writable: true,\n });\n }\n};\n\n// Device creation is lazy, so probe the adapter at setup time to have the\n// limit available before the first render.\nconst probeMaxTextureDimension = async (gpu: BunWebGpuInstance) => {\n try {\n const adapter = await gpu.requestAdapter({\n powerPreference: 'high-performance',\n });\n const maxTextureDimension = adapter?.limits?.maxTextureDimension2D;\n if (\n typeof maxTextureDimension === 'number' &&\n maxTextureDimension > 0 &&\n headlessWebGpuMaxTextureDimension == null\n ) {\n headlessWebGpuMaxTextureDimension = maxTextureDimension;\n }\n } catch (error) {\n console.log('[headless] adapter texture-limit probe failed', error);\n }\n};\n\nlet webgpuInstance: BunWebGpuInstance | null = null;\ntry {\n const bunWebgpu = await import('bun-webgpu');\n // Synchronous; loads the native Dawn wrapper from the platform companion\n // package (bun-webgpu-<platform>-<arch>) and returns the navigator.gpu object.\n webgpuInstance = bunWebgpu.createGPUInstance();\n // Install the WebGPU global constructors/enums three.js references.\n bunWebgpu.globals();\n // Prefer rgba8unorm for the offscreen canvas (avoids a full-frame B/R\n // swizzle per readback). See .agents/headless-sdk.md § Preferred canvas format.\n webgpuInstance.getPreferredCanvasFormat = () => 'rgba8unorm';\n // See .agents/headless-sdk.md § Device request workarounds.\n if (typeof webgpuInstance.requestAdapter === 'function') {\n patchRequestAdapter(webgpuInstance);\n }\n installNavigatorGpu(webgpuInstance);\n console.log(\n '[headless] Using bun-webgpu (Dawn FFI) for real WebGPU rendering',\n );\n await probeMaxTextureDimension(webgpuInstance);\n} catch (error) {\n console.log('[headless] bun-webgpu not available, WebGPU disabled', error);\n}\n\n// Spec-defined WebGPU flag constants. Used literally so we don't depend on\n// node-webgpu exposing them as module exports.\nconst GPU_TEXTURE_USAGE_COPY_SRC = 0x01;\nconst GPU_TEXTURE_USAGE_TEXTURE_BINDING = 0x04;\nconst GPU_TEXTURE_USAGE_RENDER_ATTACHMENT = 0x10;\nconst GPU_BUFFER_USAGE_COPY_DST = 0x08;\nconst GPU_BUFFER_USAGE_MAP_READ = 0x01;\nconst GPU_MAP_MODE_READ = 0x01;\n// WebGPU mandates copyTextureToBuffer bytesPerRow be a 256-byte multiple.\nconst READBACK_BYTES_PER_ROW_ALIGN = 256;\n// WebGPU spec-default maxBufferSize (256 MiB), enforced by Dawn\nconst MAX_READBACK_STAGING_BYTES = 256 * 1024 * 1024;\n\n// Fullscreen-triangle blit for readbackScaled() GPU downscale.\n// See .agents/headless-sdk.md § canvas WebGPU context shim.\nconst BLIT_WGSL = /* wgsl */ `\nstruct VSOut {\n @builtin(position) pos: vec4f,\n @location(0) uv: vec2f,\n};\n\n@vertex\nfn vs(@builtin(vertex_index) vertexIndex: u32) -> VSOut {\n var corners = array<vec2f, 3>(\n vec2f(0.0, 0.0),\n vec2f(2.0, 0.0),\n vec2f(0.0, 2.0)\n );\n let xy = corners[vertexIndex];\n var out: VSOut;\n out.pos = vec4f(xy * 2.0 - 1.0, 0.0, 1.0);\n // Clip-space y is up, texture v is down, flip v so the output keeps the\n // source orientation (row 0 = top), matching the direct readback path.\n out.uv = vec2f(xy.x, 1.0 - xy.y);\n return out;\n}\n\n@group(0) @binding(0) var srcTex: texture_2d<f32>;\n@group(0) @binding(1) var srcSampler: sampler;\n\n@fragment\nfn fs(in: VSOut) -> @location(0) vec4f {\n return textureSample(srcTex, srcSampler, in.uv);\n}\n`;\n\ninterface RawFramePixels {\n data: Uint8Array;\n width: number;\n height: number;\n}\n\n// Hand-rolled GPUCanvasContext shim (no swapchain surface, render to an\n// offscreen texture, read back). See .agents/headless-sdk.md § canvas WebGPU context shim.\nconst createHeadlessWebGPUContext = (canvas: HTMLCanvasElement) => {\n let device: GPUDevice | null = null;\n let format: GPUTextureFormat = 'bgra8unorm';\n let configuredUsage: GPUTextureUsageFlags = 0;\n let texture: GPUTexture | null = null;\n let textureWidth = 0;\n let textureHeight = 0;\n let lastFramePixels: Uint8Array | null = null;\n let blitPipeline: GPURenderPipeline | null = null;\n let blitSampler: GPUSampler | null = null;\n let blitTexture: GPUTexture | null = null;\n let blitWidth = 0;\n let blitHeight = 0;\n let stagingBuffer: GPUBuffer | null = null;\n let stagingSize = 0;\n let stagingBusy = false;\n\n // Every caller below runs behind a device check on the public methods.\n const requireDevice = (): GPUDevice => {\n if (!device) {\n throw new Error('[headless] WebGPU canvas context has no device');\n }\n return device;\n };\n\n const destroyTexture = (textureToDestroy: GPUTexture) => {\n try {\n textureToDestroy.destroy();\n } catch {\n console.error('[webgpu]: Failed to destroy texture image');\n }\n };\n\n const ensureTexture = (): GPUTexture | null => {\n if (!device) {\n return null;\n }\n const gpuDevice = device;\n const width = Math.max(1, canvas.width | 0);\n const height = Math.max(1, canvas.height | 0);\n if (texture && textureWidth === width && textureHeight === height) {\n return texture;\n }\n if (texture) {\n destroyTexture(texture);\n }\n textureWidth = width;\n textureHeight = height;\n // three's configured usage plus COPY_SRC (readback), RENDER_ATTACHMENT\n // (render target), and TEXTURE_BINDING (readbackScaled blit sampling).\n const usage =\n (configuredUsage || 0) |\n GPU_TEXTURE_USAGE_RENDER_ATTACHMENT |\n GPU_TEXTURE_USAGE_COPY_SRC |\n GPU_TEXTURE_USAGE_TEXTURE_BINDING;\n texture = gpuDevice.createTexture({\n size: { width, height, depthOrArrayLayers: 1 },\n format,\n usage,\n });\n return texture;\n };\n\n const destroyBuffer = (bufferToDestroy: GPUBuffer) => {\n try {\n bufferToDestroy.destroy();\n } catch {\n console.error('[webgpu]: Failed to destroy staging buffer');\n }\n };\n\n const createReadbackBuffer = (sizeInBytes: number): GPUBuffer =>\n requireDevice().createBuffer({\n size: sizeInBytes,\n usage: GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_MAP_READ,\n });\n\n // Reuse the pooled buffer when free and sized to the band; else a fresh\n // throwaway (pool lifetime owned by configure()/unconfigure()).\n const acquireReadbackBuffer = (\n bandBytes: number,\n ): { buffer: GPUBuffer; release: () => void } => {\n if (stagingBusy) {\n const throwawayBuffer = createReadbackBuffer(bandBytes);\n return {\n buffer: throwawayBuffer,\n release: () => destroyBuffer(throwawayBuffer),\n };\n }\n if (!stagingBuffer || stagingSize !== bandBytes) {\n if (stagingBuffer) {\n destroyBuffer(stagingBuffer);\n }\n stagingBuffer = createReadbackBuffer(bandBytes);\n stagingSize = bandBytes;\n }\n stagingBusy = true;\n return {\n buffer: stagingBuffer,\n release: () => {\n stagingBusy = false;\n },\n };\n };\n\n // Dawn returns the texture's native channel order; the wrapped 2d canvas\n // expects RGBA, so bgra8unorm needs a B/R swizzle.\n const swizzleBgraToRgbaInPlace = (pixels: Uint8Array) => {\n for (let i = 0; i < pixels.length; i += 4) {\n const blue = pixels[i]!;\n pixels[i] = pixels[i + 2]!;\n pixels[i + 2] = blue;\n }\n };\n\n const readPixelsFrom = async (\n sourceTexture: GPUTexture,\n width: number,\n height: number,\n ): Promise<Uint8Array | null> => {\n const gpuDevice = requireDevice();\n const tightRowBytes = width * 4;\n const bytesPerRow =\n Math.ceil(tightRowBytes / READBACK_BYTES_PER_ROW_ALIGN) *\n READBACK_BYTES_PER_ROW_ALIGN;\n // Row-band the copy so no single staging buffer exceeds maxBufferSize\n const rowsPerBand = Math.max(\n 1,\n Math.floor((MAX_READBACK_STAGING_BYTES * 0.95) / bytesPerRow),\n );\n const { buffer: readBuffer, release } = acquireReadbackBuffer(\n bytesPerRow * Math.min(rowsPerBand, height),\n );\n\n const pixels = new Uint8Array(tightRowBytes * height);\n try {\n for (\n let bandStartRow = 0;\n bandStartRow < height;\n bandStartRow += rowsPerBand\n ) {\n const bandHeight = Math.min(rowsPerBand, height - bandStartRow);\n const encoder = gpuDevice.createCommandEncoder();\n encoder.copyTextureToBuffer(\n { texture: sourceTexture, origin: { x: 0, y: bandStartRow, z: 0 } },\n { buffer: readBuffer, bytesPerRow, rowsPerImage: bandHeight },\n { width, height: bandHeight, depthOrArrayLayers: 1 },\n );\n gpuDevice.queue.submit([encoder.finish()]);\n await readBuffer.mapAsync(GPU_MAP_MODE_READ);\n const mappedBytes = new Uint8Array(readBuffer.getMappedRange());\n // Copy tight rows out before unmap invalidates the mapped range.\n for (let rowInBand = 0; rowInBand < bandHeight; rowInBand++) {\n pixels.set(\n mappedBytes.subarray(\n rowInBand * bytesPerRow,\n rowInBand * bytesPerRow + tightRowBytes,\n ),\n (bandStartRow + rowInBand) * tightRowBytes,\n );\n }\n readBuffer.unmap();\n }\n } catch (error: unknown) {\n console.warn('[headless] WebGPU readback failed', error);\n return null;\n } finally {\n release();\n }\n\n if (format === 'bgra8unorm') {\n swizzleBgraToRgbaInPlace(pixels);\n }\n return pixels;\n };\n\n // Reads the current canvas texture into lastFramePixels (sync toDataURL\n // consumes that cache).\n const queueReadback = async (): Promise<void> => {\n if (!device || !texture) {\n return;\n }\n const pixels = await readPixelsFrom(texture, textureWidth, textureHeight);\n if (pixels) {\n lastFramePixels = pixels;\n }\n };\n\n const ensureBlitPipeline = (): {\n pipeline: GPURenderPipeline;\n sampler: GPUSampler;\n } => {\n if (blitPipeline && blitSampler) {\n return { pipeline: blitPipeline, sampler: blitSampler };\n }\n const gpuDevice = requireDevice();\n const shaderModule = gpuDevice.createShaderModule({ code: BLIT_WGSL });\n const pipeline = gpuDevice.createRenderPipeline({\n layout: 'auto',\n vertex: { module: shaderModule, entryPoint: 'vs' },\n fragment: {\n module: shaderModule,\n entryPoint: 'fs',\n targets: [{ format }],\n },\n primitive: { topology: 'triangle-list' },\n });\n const sampler = gpuDevice.createSampler({\n magFilter: 'linear',\n minFilter: 'linear',\n });\n blitPipeline = pipeline;\n blitSampler = sampler;\n return { pipeline, sampler };\n };\n\n const ensureBlitTexture = (width: number, height: number): GPUTexture => {\n if (blitTexture && blitWidth === width && blitHeight === height) {\n return blitTexture;\n }\n if (blitTexture) {\n destroyTexture(blitTexture);\n }\n blitWidth = width;\n blitHeight = height;\n blitTexture = requireDevice().createTexture({\n size: { width, height, depthOrArrayLayers: 1 },\n format,\n usage: GPU_TEXTURE_USAGE_RENDER_ATTACHMENT | GPU_TEXTURE_USAGE_COPY_SRC,\n });\n return blitTexture;\n };\n\n const releaseCanvasTexture = () => {\n if (texture) {\n destroyTexture(texture);\n texture = null;\n }\n };\n\n const releaseBlitResources = () => {\n blitPipeline = null;\n blitSampler = null;\n if (blitTexture) {\n destroyTexture(blitTexture);\n blitTexture = null;\n }\n };\n\n const releaseStagingBuffer = () => {\n if (stagingBuffer && !stagingBusy) {\n destroyBuffer(stagingBuffer);\n }\n stagingBuffer = null;\n stagingSize = 0;\n stagingBusy = false;\n };\n\n const readCanvasPixels = async (\n sourceTexture: GPUTexture,\n ): Promise<RawFramePixels | null> => {\n const pixels = await readPixelsFrom(\n sourceTexture,\n textureWidth,\n textureHeight,\n );\n return pixels\n ? { data: pixels, width: textureWidth, height: textureHeight }\n : null;\n };\n\n const blitAndReadScaled = async (\n sourceTexture: GPUTexture,\n targetWidth: number,\n targetHeight: number,\n ): Promise<RawFramePixels | null> => {\n const gpuDevice = requireDevice();\n const { pipeline, sampler } = ensureBlitPipeline();\n const blitTarget = ensureBlitTexture(targetWidth, targetHeight);\n const bindGroup = gpuDevice.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n { binding: 0, resource: sourceTexture.createView() },\n { binding: 1, resource: sampler },\n ],\n });\n const encoder = gpuDevice.createCommandEncoder();\n const renderPass = encoder.beginRenderPass({\n colorAttachments: [\n {\n view: blitTarget.createView(),\n loadOp: 'clear',\n storeOp: 'store',\n clearValue: { r: 0, g: 0, b: 0, a: 0 },\n },\n ],\n });\n renderPass.setPipeline(pipeline);\n renderPass.setBindGroup(0, bindGroup);\n renderPass.draw(3);\n renderPass.end();\n gpuDevice.queue.submit([encoder.finish()]);\n const pixels = await readPixelsFrom(blitTarget, targetWidth, targetHeight);\n return pixels\n ? { data: pixels, width: targetWidth, height: targetHeight }\n : null;\n };\n\n return {\n canvas,\n __isHeadlessWebGPUContext: true,\n configure(configuration: GPUCanvasConfiguration) {\n device = configuration.device;\n format = configuration.format || format;\n configuredUsage = configuration.usage || 0;\n // Pipeline, textures and staging buffer are format and device bound\n releaseCanvasTexture();\n releaseBlitResources();\n releaseStagingBuffer();\n },\n unconfigure() {\n releaseCanvasTexture();\n releaseBlitResources();\n releaseStagingBuffer();\n device = null;\n },\n getCurrentTexture() {\n // No implicit per-frame readback, export paths read back explicitly\n // (see .agents/headless-sdk.md § canvas WebGPU context shim).\n return ensureTexture();\n },\n // Read the current frame back (single copy + mapAsync) and cache it for\n // the sync toDataURL path.\n async flushReadback(): Promise<Uint8Array | null> {\n if (texture) {\n await queueReadback();\n }\n return lastFramePixels;\n },\n // GPU-downscale the current frame to target size and read back only that\n // (full-size fallback when no scaling). Does not touch the toDataURL cache.\n async readbackScaled(\n targetWidth: number,\n targetHeight: number,\n ): Promise<RawFramePixels | null> {\n if (!device || !texture) {\n return null;\n }\n const canvasTexture = texture;\n if (targetWidth >= textureWidth && targetHeight >= textureHeight) {\n return readCanvasPixels(canvasTexture);\n }\n try {\n return await blitAndReadScaled(\n canvasTexture,\n targetWidth,\n targetHeight,\n );\n } catch (error) {\n console.warn(\n '[headless] WebGPU scaled readback failed, falling back to full-size readback',\n error,\n );\n return readCanvasPixels(canvasTexture);\n }\n },\n getCachedPixels(): Uint8Array | null {\n return lastFramePixels;\n },\n getPreferredFormat() {\n return webgpuInstance?.getPreferredCanvasFormat?.() ?? 'bgra8unorm';\n },\n };\n};\n\nexport type WebGPUMockContext = ReturnType<typeof createHeadlessWebGPUContext>;\n\n// Wraps a napi-rs/canvas Canvas so it behaves like an HTMLCanvasElement.\n// Fakes the prototype chain via Proxy getPrototypeOf (GLTFExporter checks instanceof).\n// The 2d context's drawImage is patched to unwrap NAPI_IMAGE symbols.\nconst createCanvasProxy = (\n width: number = 300,\n height: number = 150,\n): HTMLCanvasElement => {\n const napiCanvas = createNapiCanvas(width, height);\n let cachedCtx: CanvasRenderingContext2D | null = null;\n let cachedWebGpuContext: WebGPUMockContext | null = null;\n\n const proxy = new Proxy(napiCanvas as unknown as HTMLCanvasElement, {\n get(target: any, prop: string | symbol) {\n if (prop === NAPI_IMAGE) {\n return target;\n }\n if (prop === 'data') {\n return undefined;\n }\n if (prop === 'style') {\n return target._style ?? (target._style = {});\n }\n if (prop === 'classList') {\n return (\n target._classList ??\n (target._classList = {\n add() {},\n remove() {},\n contains() {\n return false;\n },\n toggle() {},\n })\n );\n }\n if (prop === Symbol.toStringTag) {\n return 'HTMLCanvasElement';\n }\n\n if (prop === 'getContext') {\n return (contextType: string, attrs?: any) => {\n if (contextType === '2d') {\n if (!cachedCtx) {\n cachedCtx = patchContext2d(target.getContext('2d', attrs));\n }\n return cachedCtx;\n }\n if (contextType === 'webgl2' || contextType === 'webgl') {\n // headless-sdk only runs on webGPU\n return null;\n }\n if (contextType === 'webgpu') {\n if (!webgpuInstance) {\n return null;\n }\n if (!cachedWebGpuContext) {\n cachedWebGpuContext = createHeadlessWebGPUContext(proxy);\n }\n return cachedWebGpuContext;\n }\n return target.getContext(contextType, attrs);\n };\n }\n\n if (prop === 'addEventListener' || prop === 'removeEventListener') {\n return () => {};\n }\n\n if (prop === 'getBoundingClientRect') {\n return () => ({\n x: 0,\n y: 0,\n width: target.width,\n height: target.height,\n top: 0,\n left: 0,\n bottom: target.height,\n right: target.width,\n });\n }\n\n // WebGPU: blit the last cached frame into the 2d canvas (lags one frame\n // unless the caller flushed the readback first, as the image renderer does).\n if (prop === 'toDataURL' && cachedWebGpuContext) {\n const webGpuContext = cachedWebGpuContext;\n return (mimeType?: string, quality?: number) => {\n const pixels = webGpuContext.getCachedPixels();\n if (pixels) {\n target\n .getContext('2d')\n .putImageData(\n new NapiImageData(\n new Uint8ClampedArray(pixels.buffer),\n target.width,\n target.height,\n ),\n 0,\n 0,\n );\n }\n return target.toDataURL(mimeType, quality);\n };\n }\n const value = target[prop];\n return typeof value === 'function' ? value.bind(target) : value;\n },\n\n set(target: any, prop: string | symbol, value: any) {\n target[prop] = value;\n return true;\n },\n\n getPrototypeOf() {\n return HTMLCanvasElement.prototype;\n },\n });\n\n return proxy;\n};\n\n// Keeps texture downloads cancellable; see .agents/headless-sdk/debugging.md,\n// item 14.\nconst IMAGE_FETCH_TIMEOUT_MS = 30_000;\nconst IMAGE_FETCH_ATTEMPTS = 3;\n\nconst fetchImageBytes = async (url: string): Promise<ArrayBuffer> => {\n let lastError: unknown;\n for (let attempt = 1; attempt <= IMAGE_FETCH_ATTEMPTS; attempt++) {\n try {\n const response = await fetch(url, {\n signal: AbortSignal.timeout(IMAGE_FETCH_TIMEOUT_MS),\n });\n if (!response.ok) {\n throw new Error(`HTTP ${response.status} for ${url}`);\n }\n return await response.arrayBuffer();\n } catch (error) {\n lastError = error;\n console.warn(\n `image request attempt ${attempt}/${IMAGE_FETCH_ATTEMPTS} failed for ${url}:`,\n error instanceof Error ? error.message : error,\n );\n }\n }\n throw lastError instanceof Error ? lastError : new Error(String(lastError));\n};\n\n// Creates a happy-dom HTMLImageElement backed by a napi-rs/canvas Image so that\n// images are actually decoded and canvas drawImage() works correctly.\nconst createNapiImageElement = (): HTMLImageElement => {\n const el = origCreateElementNS(\n 'http://www.w3.org/1999/xhtml',\n 'img',\n ) as HTMLImageElement;\n const napiImg = new NapiImage();\n\n (el as any)[NAPI_IMAGE] = napiImg;\n\n let currentSrc = '';\n Object.defineProperty(el, 'src', {\n get() {\n return currentSrc;\n },\n set(url: string) {\n currentSrc = url;\n // napi-rs/canvas Image cannot fetch blob: URLs (created by\n // URL.createObjectURL used heavily by GLTFLoader for embedded\n // textures). Resolve them ourselves via fetch (Node ≥18 understands\n // its own blob URL registry) and feed the bytes in as a Buffer.\n const isFetchable =\n typeof url === 'string' &&\n (url.startsWith('blob:') ||\n url.startsWith('http:') ||\n url.startsWith('https:'));\n if (isFetchable) {\n const load = url.startsWith('blob:')\n ? fetch(url).then((r) => r.arrayBuffer())\n : fetchImageBytes(url);\n load\n .then((ab) => {\n // Guard against a later src reassignment racing this resolution.\n if (currentSrc !== url) {\n return;\n }\n napiImg.src = Buffer.from(ab);\n })\n .catch((err) => {\n if (currentSrc !== url) {\n return;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n el.dispatchEvent(\n new ErrorEvent('error', { error, message: error.message }),\n );\n });\n return;\n }\n napiImg.src = url;\n },\n configurable: true,\n });\n\n napiImg.onload = () => {\n Object.defineProperty(el, 'width', {\n value: napiImg.width,\n writable: true,\n configurable: true,\n });\n Object.defineProperty(el, 'height', {\n value: napiImg.height,\n writable: true,\n configurable: true,\n });\n Object.defineProperty(el, 'naturalWidth', {\n value: napiImg.naturalWidth,\n configurable: true,\n });\n Object.defineProperty(el, 'naturalHeight', {\n value: napiImg.naturalHeight,\n configurable: true,\n });\n Object.defineProperty(el, 'complete', { value: true, configurable: true });\n el.dispatchEvent(new Event('load'));\n };\n\n napiImg.onerror = (err: Error) => {\n el.dispatchEvent(\n new ErrorEvent('error', { error: err, message: err?.message }),\n );\n };\n\n return el;\n};\n\ndocument.createElement = (\n tagName: string,\n options?: ElementCreationOptions,\n) => {\n if (tagName.toLowerCase() === 'canvas') {\n return createCanvasProxy();\n }\n return origCreateElement(tagName, options);\n};\n\ndocument.createElementNS = (\n namespaceURI: string | null,\n qualifiedName: string,\n options?: ElementCreationOptions,\n) => {\n const tag = qualifiedName.toLowerCase();\n if (tag === 'canvas') {\n return createCanvasProxy();\n }\n if (tag === 'img') {\n return createNapiImageElement();\n }\n return origCreateElementNS(namespaceURI, qualifiedName, options);\n};\n"],"mappings":"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"}
|
package/lib/roomle-headless.d.ts
CHANGED
|
@@ -134,6 +134,7 @@ export declare class AnimationValueMap {
|
|
|
134
134
|
static getKeyAndValue(animationName: string): AnimationKeyAndValue;
|
|
135
135
|
hasKeyAndValue(animationKeyAndValue: string): boolean;
|
|
136
136
|
getParameterValue(animationName: string): AnimationKeyAndValue | null;
|
|
137
|
+
getParameterLevel(animationName: string): number;
|
|
137
138
|
updateParameterValue(parameter: KernelParameter): void;
|
|
138
139
|
setValue(animationName: string, value: string, level: number): void;
|
|
139
140
|
setValueAndGetOldValue(animationName: string, value: string, level: number): string;
|
|
@@ -1525,6 +1526,7 @@ export declare class ConfiguratorSceneEventHandler extends SceneEventHandler<Sce
|
|
|
1525
1526
|
private _hoverOn;
|
|
1526
1527
|
private _hoverOff;
|
|
1527
1528
|
private _hoverOnPreview;
|
|
1529
|
+
private _hoverMovePreview;
|
|
1528
1530
|
private _hoverOffPreview;
|
|
1529
1531
|
private _hoverOnPreviewLine;
|
|
1530
1532
|
private _hoverMovePreviewLine;
|
|
@@ -1534,6 +1536,7 @@ export declare class ConfiguratorSceneEventHandler extends SceneEventHandler<Sce
|
|
|
1534
1536
|
private _setDragComponentShadow;
|
|
1535
1537
|
private _isDraggingPossible;
|
|
1536
1538
|
private _dragStart;
|
|
1539
|
+
private _applyPreviewRotation;
|
|
1537
1540
|
private _drag;
|
|
1538
1541
|
private _dragEnd;
|
|
1539
1542
|
protected _interaction(forceRender?: boolean): void;
|
|
@@ -2035,6 +2038,7 @@ export declare class ConfiguratorViewModel implements ConfiguratorKernelCallback
|
|
|
2035
2038
|
private _applyMeshUVTransform;
|
|
2036
2039
|
updateAnimationParameters(elementId: number | number[], parameters: KernelParameter[]): void;
|
|
2037
2040
|
changeAnimationValue(elementId: number, parameterKey: string, value: string, level: number, animationLevel: AnimationLevelType, animate: boolean): void;
|
|
2041
|
+
closeOpenGeometry(): () => void;
|
|
2038
2042
|
protected updatePlanElement(_elementId: number): void;
|
|
2039
2043
|
getComponentFromRuntimeId(elementId: number): RoomleComponent | null;
|
|
2040
2044
|
private _addMeshToSubPart;
|
|
@@ -3191,7 +3195,6 @@ export declare interface ExternalObjectGroupLayoutSide {
|
|
|
3191
3195
|
|
|
3192
3196
|
export declare interface ExternalObjectLoadConfiguration {
|
|
3193
3197
|
applyGlobalChildMode: boolean;
|
|
3194
|
-
correctArrangement: boolean;
|
|
3195
3198
|
applyGroupPosition: boolean;
|
|
3196
3199
|
findFreeSpaceInPlan: boolean;
|
|
3197
3200
|
isVisible: boolean;
|
|
@@ -3199,12 +3202,6 @@ export declare interface ExternalObjectLoadConfiguration {
|
|
|
3199
3202
|
lockCallbacks: boolean;
|
|
3200
3203
|
tryToMergeNewGroups: boolean;
|
|
3201
3204
|
calculationUpdate: boolean;
|
|
3202
|
-
moduleIdMap: ExternalObjectLoadingIdMap[];
|
|
3203
|
-
}
|
|
3204
|
-
|
|
3205
|
-
export declare interface ExternalObjectLoadingIdMap {
|
|
3206
|
-
originalModuleId: string;
|
|
3207
|
-
newModuleId: string;
|
|
3208
3205
|
}
|
|
3209
3206
|
|
|
3210
3207
|
export declare interface ExternalObjectMaterialConfiguration {
|
|
@@ -3679,6 +3676,7 @@ export declare interface GlueLogic {
|
|
|
3679
3676
|
findValidSubArticles(posGroupIds: string[] | string): PosArticle[];
|
|
3680
3677
|
getValidContainerModulesForSubArticle(posGroupIds: string[] | string, subArticleId: string): ValidContainerModules[];
|
|
3681
3678
|
addSubArticle(articleId: string, rootModuleId: string, parentModuleId: string, insertPosition?: number[]): void;
|
|
3679
|
+
moveSubArticle(articleId: string, subModuleId: string, rootModuleId: string, parentModuleId: string, insertPosition?: number[]): void;
|
|
3682
3680
|
deleteSubArticles(groupId: string, subModuleId: string[] | string): Promise<void>;
|
|
3683
3681
|
changedGroupPlanningSituation(changedGroup: ExternalObjectGroup, objectPositionChanged: boolean): Promise<void>;
|
|
3684
3682
|
changedGroupFromHistory(historyGroup: PosGroup, reloadGroup: boolean): void;
|
|
@@ -4011,6 +4009,7 @@ export declare const HI_CONTEXT_ACTION: {
|
|
|
4011
4009
|
|
|
4012
4010
|
export declare const HI_LOAD_OBJECT_REASON: {
|
|
4013
4011
|
readonly ADD_SUBARTICLE: "add_subarticle";
|
|
4012
|
+
readonly MOVE_SUBARTICLE: "move_subarticle";
|
|
4014
4013
|
readonly ADJUSTED: "adjusted";
|
|
4015
4014
|
readonly CHANGE_ATTRIBUTE: "change_attribute";
|
|
4016
4015
|
readonly CHANGE_META: "change_meta";
|
|
@@ -4251,7 +4250,7 @@ export declare class ImageRenderer implements Context {
|
|
|
4251
4250
|
protected _renderFrame(renderInstance: GenericRoomleRenderer | WebGLRenderer | WebGPURenderer, scene: Scene, camera: Camera, options: PrepareImageOptions): Promise<ImageFrame>;
|
|
4252
4251
|
protected _renderImageFrame(renderInstance: GenericRoomleRenderer | WebGLRenderer | WebGPURenderer, scene: Scene, camera: Camera, options?: PrepareImageOptions): Promise<ImageFrame>;
|
|
4253
4252
|
protected _getThreejsRenderer(renderInstance: GenericRoomleRenderer | WebGLRenderer | WebGPURenderer): WebGLRenderer | WebGPURenderer;
|
|
4254
|
-
protected _renderSingleFrame(renderInstance: GenericRoomleRenderer | WebGLRenderer | WebGPURenderer, scene: Scene, camera: Camera): void;
|
|
4253
|
+
protected _renderSingleFrame(renderInstance: GenericRoomleRenderer | WebGLRenderer | WebGPURenderer, scene: Scene, camera: Camera, options?: PrepareImageOptions): void;
|
|
4255
4254
|
protected _readFrameAndClear(renderer: WebGLRenderer | WebGPURenderer, _options?: PrepareImageOptions): Promise<ImageFrame>;
|
|
4256
4255
|
}
|
|
4257
4256
|
|
|
@@ -6152,9 +6151,9 @@ export declare class PlannerKernelAccess extends ConfiguratorKernelAccess {
|
|
|
6152
6151
|
externalObjectPlanChanged(plan: Plan_2, planObject: PlanObject, movedGroup: ExternalObjectGroup): void;
|
|
6153
6152
|
externalObjectConfigurationsMerged(plan: Plan_2, planObject: PlanObject, mergedGroup: ExternalObjectGroup, idsOfGroupsMerged: string | string[], targetRootModuleId: string, mergedWithDragging: boolean): void;
|
|
6154
6153
|
externalObjectComponentSplitOff(plan: Plan_2, planObject: PlanObject, splitGroups: ExternalObjectGroup[]): void;
|
|
6155
|
-
externalObjectArrangementChanged(): void;
|
|
6156
6154
|
externalObjectRequestAddOnContainers(plan: Plan_2, planObject: PlanObject, groupId: string, subArticleId: string): void;
|
|
6157
6155
|
externalObjectAddSubArticle(plan: Plan_2, planObject: PlanObject, subArticleId: string, rootModuleId: string, parentModuleId: string, insertPosition?: number[]): void;
|
|
6156
|
+
externalObjectMoveSubArticle(plan: Plan_2, planObject: PlanObject, subArticleId: string, subModuleId: string, rootModuleId: string, parentModuleId: string, insertPosition?: number[]): void;
|
|
6158
6157
|
externalObjectRemoveSubModule(plan: Plan_2, planObject: PlanObject, groupId: string, subModuleId: string): void;
|
|
6159
6158
|
planObjectConfigurationLoaded(plan: Plan_2, element: PlanElement_2, success: boolean): Promise<void>;
|
|
6160
6159
|
planObjectConfigurationChanged(plan: Plan_2, object: PlanObject): void;
|
|
@@ -6222,6 +6221,7 @@ export declare interface PlannerKernelCallbackI {
|
|
|
6222
6221
|
requestCatalogItem(catalogItemId: string): void;
|
|
6223
6222
|
externalObjectRequestAddOnContainers(groupId: string, subArticleId: string): void;
|
|
6224
6223
|
externalObjectAddSubArticle(subArticleId: string, rootModuleId: string, parentModuleId: string, insertPosition?: number[]): void;
|
|
6224
|
+
externalObjectMoveSubArticle(subArticleId: string, subModuleId: string, rootModuleId: string, parentModuleId: string, insertPosition?: number[]): void;
|
|
6225
6225
|
externalObjectRemoveSubModule(groupId: string, subModuleId: string): void;
|
|
6226
6226
|
}
|
|
6227
6227
|
|
|
@@ -6312,6 +6312,7 @@ export declare class PlannerSceneEventHandler extends SceneEventHandler<SceneEve
|
|
|
6312
6312
|
private _draggedObject;
|
|
6313
6313
|
private _lastDragPosition;
|
|
6314
6314
|
private _hoveredObject;
|
|
6315
|
+
private _lastResolvedFenceElement;
|
|
6315
6316
|
private _position;
|
|
6316
6317
|
private _isDrawingEnabled;
|
|
6317
6318
|
private _isCurrentlyDrawing;
|
|
@@ -6362,6 +6363,8 @@ export declare class PlannerSceneEventHandler extends SceneEventHandler<SceneEve
|
|
|
6362
6363
|
private _hoverOnMultiSelect;
|
|
6363
6364
|
private _hoverOnStandard;
|
|
6364
6365
|
private _hoverOff;
|
|
6366
|
+
private _resolveFenceElement;
|
|
6367
|
+
private _hoverMove;
|
|
6365
6368
|
private _isHiddenConstructionElement;
|
|
6366
6369
|
private _isHoveredObjectNonDraggable;
|
|
6367
6370
|
setLoadingCursor(isLoading: boolean): void;
|
|
@@ -6756,6 +6759,7 @@ export declare class PlannerSceneManager extends ConfiguratorSceneManager implem
|
|
|
6756
6759
|
private _saveConfiguration;
|
|
6757
6760
|
externalObjectRequestAddOnContainers(groupId: string, subArticleId: string): Promise<void>;
|
|
6758
6761
|
externalObjectAddSubArticle(subArticleId: string, rootModuleId: string, parentModuleId: string, insertPosition?: number[]): void;
|
|
6762
|
+
externalObjectMoveSubArticle(subArticleId: string, subModuleId: string, rootModuleId: string, parentModuleId: string, insertPosition?: number[]): void;
|
|
6759
6763
|
externalObjectRemoveSubModule(groupId: string, subModuleId: string): void;
|
|
6760
6764
|
getExternalSubArticles(id: number): PosArticle[];
|
|
6761
6765
|
}
|
|
@@ -7045,6 +7049,7 @@ export declare class PlanViewModel extends ConfiguratorViewModel implements Plan
|
|
|
7045
7049
|
requestCatalogItem(_catalogItemId: string): void;
|
|
7046
7050
|
externalObjectRequestAddOnContainers(_groupId: string, _subArticleId: string): void;
|
|
7047
7051
|
externalObjectAddSubArticle(_subArticleId: string, _rootModuleId: string, _parentModuleId: string, _insertPosition?: number[]): void;
|
|
7052
|
+
externalObjectMoveSubArticle(_subArticleId: string, _subModuleId: string, _rootModuleId: string, _parentModuleId: string, _insertPosition?: number[]): void;
|
|
7048
7053
|
externalObjectRemoveSubModule(_groupId: string, _subModuleId: string): void;
|
|
7049
7054
|
}
|
|
7050
7055
|
|
|
@@ -7376,6 +7381,7 @@ export declare interface PrepareImageOptions {
|
|
|
7376
7381
|
runtimeIds?: number[];
|
|
7377
7382
|
rotationY?: number;
|
|
7378
7383
|
preserveSceneBackground?: boolean;
|
|
7384
|
+
prepareScene?: () => () => void;
|
|
7379
7385
|
}
|
|
7380
7386
|
|
|
7381
7387
|
export declare interface PrepareImageOptionsPlanner extends PrepareImageOptions {
|
|
@@ -8377,7 +8383,7 @@ export declare class RoomleConfigurator<P extends readonly PluginName[] = readon
|
|
|
8377
8383
|
private _globalInitData;
|
|
8378
8384
|
private _globalCallback;
|
|
8379
8385
|
private _kernelIo;
|
|
8380
|
-
private
|
|
8386
|
+
private _elevationPlan2dGenerator;
|
|
8381
8387
|
private _sceneManager;
|
|
8382
8388
|
private _onInitDoneCollection;
|
|
8383
8389
|
private _isKernelReady;
|
|
@@ -8392,18 +8398,18 @@ export declare class RoomleConfigurator<P extends readonly PluginName[] = readon
|
|
|
8392
8398
|
private _onInitDone;
|
|
8393
8399
|
constructor(creator: string, activePlugins?: P);
|
|
8394
8400
|
/**
|
|
8395
|
-
* Creates
|
|
8396
|
-
*
|
|
8401
|
+
* Creates the 2D plans of the current configuration: the floor plan, the front
|
|
8402
|
+
* elevation and the side elevation seen from the left. Each plan is returned as
|
|
8403
|
+
* raw SVG markup (wireframe rendering with dimensionings).
|
|
8397
8404
|
*
|
|
8398
|
-
* @returns the
|
|
8405
|
+
* @returns the plans, each containing its SVG markup and its view type
|
|
8399
8406
|
*/
|
|
8400
|
-
|
|
8407
|
+
create2DPlanViews(): Promise<ElevationPlans>;
|
|
8401
8408
|
/**
|
|
8402
|
-
* Creates the 2D
|
|
8403
|
-
* {@link
|
|
8409
|
+
* Creates the 2D plans of the current configuration (see
|
|
8410
|
+
* {@link create2DPlanViews}) and downloads each plan as an SVG file.
|
|
8404
8411
|
*/
|
|
8405
|
-
|
|
8406
|
-
private createCameraForElevationPlan;
|
|
8412
|
+
download2DPlanViews(): Promise<void>;
|
|
8407
8413
|
exportCanvasScreenshot(quality?: number): Promise<string>;
|
|
8408
8414
|
initSceneManager(sceneManager?: ConfiguratorSceneManager): void;
|
|
8409
8415
|
getScene(): Scene;
|
|
@@ -9643,7 +9649,7 @@ export declare class RoomlePlanner<P extends readonly PluginName[] = readonly []
|
|
|
9643
9649
|
saveExternalObjectSnapshot(parentPlanId?: RapiId): Promise<ExternalObjectSnapshotSaveResult | null>;
|
|
9644
9650
|
private _getExternalObjectGroupsInPlan;
|
|
9645
9651
|
private _savePlanSnapshotExternalObjects;
|
|
9646
|
-
saveCurrentPlanSnapshot(parentPlanId?: RapiId, configurationHashOrGroupId?: string | string[]): Promise<RapiPlanSnapshotGetData>;
|
|
9652
|
+
saveCurrentPlanSnapshot(parentPlanId?: RapiId, configurationHashOrGroupId?: string | string[], imageOptions?: PrepareImageOptions): Promise<RapiPlanSnapshotGetData>;
|
|
9647
9653
|
getPlanXmlFrom(plan: RapiPlan | RapiPlanSnapshotGetData): any;
|
|
9648
9654
|
moveCamera(cameraParameter: CameraParameter): Promise<void>;
|
|
9649
9655
|
createNewSerializedConfiguration(configurationRuntimeId: number): Promise<ConfigurationString>;
|
|
@@ -10461,7 +10467,7 @@ export declare abstract class SceneManager implements Context, LifeCycleCallback
|
|
|
10461
10467
|
protected _getCameraControlFirstPerson(): CameraControlFirstPerson;
|
|
10462
10468
|
createUSDZExport(): Promise<Uint8Array<ArrayBuffer> | undefined>;
|
|
10463
10469
|
exportUSDZ(options?: ModelExportOptions): Promise<void>;
|
|
10464
|
-
createExportGLB(objectFilter?: (object: Object3D) => boolean): Promise<ArrayBuffer | null>;
|
|
10470
|
+
createExportGLB(objectFilter?: (object: Object3D) => boolean, prepareScene?: () => () => void): Promise<ArrayBuffer | null>;
|
|
10465
10471
|
exportGLB(options?: ModelExportOptions): Promise<void>;
|
|
10466
10472
|
}
|
|
10467
10473
|
|
|
@@ -11216,7 +11222,7 @@ export declare class WallPlanElementViewModel extends PlanElementViewModel {
|
|
|
11216
11222
|
private _visible;
|
|
11217
11223
|
private _cameraFacingHighlighted;
|
|
11218
11224
|
constructor(planObject: PlanObject);
|
|
11219
|
-
|
|
11225
|
+
isFenceContourWall(): boolean;
|
|
11220
11226
|
private _checkHasAttachedAttic;
|
|
11221
11227
|
getWallDimension(zoomFactor: number, clientWidth: number, clientHeight: number, preferredSideOverride?: LeftOrRightWallSide, isTerrainMeasurement?: boolean): WallDimension;
|
|
11222
11228
|
private calculateNormalVector;
|
package/lib/roomle-headless.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { a as e, i as t, n, r, t as i } from "./packages-
|
|
1
|
+
import { a as e, i as t, n, r, t as i } from "./packages-3jOdcfbr.mjs";
|
|
2
2
|
import { i as a, t as o } from "./kernel-BWfRHWkW.mjs";
|
|
3
|
-
import { bt as s, gt as c } from "./threejs-utils-
|
|
3
|
+
import { bt as s, gt as c } from "./threejs-utils-WK7Uu2TS.mjs";
|
|
4
4
|
import { Si as l, m as u, nt as d } from "./three.core-0KaTx8dm.mjs";
|
|
5
|
-
import { i as f } from "./decorate-
|
|
6
|
-
import { V as p } from "./common-utils-
|
|
7
|
-
import { A as m, F as h, G as ee, J as te, K as ne, M as re, N as ie, P as ae, S as oe, V as se, W as ce, a as g, at as le, b as ue, ct as de, dt as fe, i as pe, j as me, k as he, l as ge, lt as _e, m as ve, mt as ye, o as _, ot as v, q as y, r as b, s as x, st as S, t as C, u as w, ut as T, x as E, y as D, z as O } from "./roomle-sdk-
|
|
8
|
-
import { n as k } from "./roomle-renderer-
|
|
9
|
-
import { n as A } from "./script-loader-
|
|
10
|
-
import { t as j } from "./configurator-
|
|
11
|
-
import { t as M } from "./planner-
|
|
12
|
-
import { n as N, t as P } from "./glb-viewer-
|
|
13
|
-
import { t as be } from "./api-
|
|
14
|
-
import { t as xe } from "./roomle-headless-setup-
|
|
5
|
+
import { i as f } from "./decorate-Bl-JF_YY.mjs";
|
|
6
|
+
import { V as p } from "./common-utils-DbL4tku0.mjs";
|
|
7
|
+
import { A as m, F as h, G as ee, J as te, K as ne, M as re, N as ie, P as ae, S as oe, V as se, W as ce, a as g, at as le, b as ue, ct as de, dt as fe, i as pe, j as me, k as he, l as ge, lt as _e, m as ve, mt as ye, o as _, ot as v, q as y, r as b, s as x, st as S, t as C, u as w, ut as T, x as E, y as D, z as O } from "./roomle-sdk-CsSQAqQG.mjs";
|
|
8
|
+
import { n as k } from "./roomle-renderer-Ato6RMrd.mjs";
|
|
9
|
+
import { n as A } from "./script-loader-Dx3gOiB3.mjs";
|
|
10
|
+
import { t as j } from "./configurator-CxlLvBCx.mjs";
|
|
11
|
+
import { t as M } from "./planner-BeINcWRR.mjs";
|
|
12
|
+
import { n as N, t as P } from "./glb-viewer-27e6wfY4.mjs";
|
|
13
|
+
import { t as be } from "./api-B5wIZIHt.mjs";
|
|
14
|
+
import { t as xe } from "./roomle-headless-setup-ps3I0vOP.mjs";
|
|
15
15
|
import { createRequire as Se } from "module";
|
|
16
16
|
//#region packages/headless-core/src/headless-tween-stub.ts
|
|
17
17
|
var Ce = {
|
|
@@ -353,7 +353,7 @@ var Pe = (e) => {
|
|
|
353
353
|
async _getPathTracer(e) {
|
|
354
354
|
if (this._pathTracer && this._renderer === e) return this._pathTracer;
|
|
355
355
|
this._pathTracer?.dispose();
|
|
356
|
-
let { WebGPUPathTracer: t } = await import("./webgpu-
|
|
356
|
+
let { WebGPUPathTracer: t } = await import("./webgpu-DSecxaB8.mjs"), n = new t(e);
|
|
357
357
|
return n.useMegakernel(!0), n.dynamicLowRes = !1, n.renderDelay = 0, n.fadeDuration = 0, n.minSamples = 1, this._pathTracer = n, this._renderer = e, n;
|
|
358
358
|
}
|
|
359
359
|
}, Le = class e extends ve {
|
|
@@ -362,7 +362,7 @@ var Pe = (e) => {
|
|
|
362
362
|
}
|
|
363
363
|
async _createThreejsImageRenderer() {
|
|
364
364
|
if (!this._initData.webGpu) return super._createThreejsImageRenderer();
|
|
365
|
-
let { WebGPURenderer: e } = await import("./three.webgpu-
|
|
365
|
+
let { WebGPURenderer: e } = await import("./three.webgpu-ClICiWlK.mjs"), t = new e({
|
|
366
366
|
antialias: !1,
|
|
367
367
|
alpha: !0
|
|
368
368
|
});
|
|
@@ -370,7 +370,7 @@ var Pe = (e) => {
|
|
|
370
370
|
}
|
|
371
371
|
async _createRoomleRenderer(e) {
|
|
372
372
|
if (!e.isWebGPURenderer) return super._createRoomleRenderer(e);
|
|
373
|
-
let { RoomleWebGPURenderer: t } = await import("./roomle-webgpu-renderer-
|
|
373
|
+
let { RoomleWebGPURenderer: t } = await import("./roomle-webgpu-renderer-BBE14A8V.mjs");
|
|
374
374
|
return new t(this._creator_, e, !0, void 0, !1);
|
|
375
375
|
}
|
|
376
376
|
static hasExplicitCameraPlacement(e) {
|