@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.
Files changed (134) hide show
  1. package/lib/{BufferGeometry-DxRRBHpW.mjs → BufferGeometry-Cd2ewNVQ.mjs} +2 -2
  2. package/lib/{BufferGeometry-DxRRBHpW.mjs.map → BufferGeometry-Cd2ewNVQ.mjs.map} +1 -1
  3. package/lib/ConfiguratorKernel.wasm +0 -0
  4. package/lib/{GLTFExporter-BFaz434u.mjs → GLTFExporter-n80QLoDf.mjs} +1 -1
  5. package/lib/{GLTFExporter-BFaz434u.mjs.map → GLTFExporter-n80QLoDf.mjs.map} +1 -1
  6. package/lib/{GaussianBlurNode-BMH03PYf.mjs → GaussianBlurNode-Cwy3kx8H.mjs} +3 -3
  7. package/lib/{GaussianBlurNode-BMH03PYf.mjs.map → GaussianBlurNode-Cwy3kx8H.mjs.map} +1 -1
  8. package/lib/{Object3D-DxqUUhH8.mjs → Object3D-BHdngbxB.mjs} +1 -1
  9. package/lib/{Object3D-DxqUUhH8.mjs.map → Object3D-BHdngbxB.mjs.map} +1 -1
  10. package/lib/{PointLightHelper-dMNG9Rk5.mjs → PointLightHelper-DlPLsDNy.mjs} +4 -4
  11. package/lib/{PointLightHelper-dMNG9Rk5.mjs.map → PointLightHelper-DlPLsDNy.mjs.map} +1 -1
  12. package/lib/RoomleCore.wasm +0 -0
  13. package/lib/RoomleToolsCore.wasm +0 -0
  14. package/lib/{SpotLightHelper-DFIT6781.mjs → SpotLightHelper-YWHbVXAF.mjs} +3 -3
  15. package/lib/{SpotLightHelper-DFIT6781.mjs.map → SpotLightHelper-YWHbVXAF.mjs.map} +1 -1
  16. package/lib/{USDZExporter-DWwEB8-y.mjs → USDZExporter-Bm-c5e_n.mjs} +2 -2
  17. package/lib/{USDZExporter-DWwEB8-y.mjs.map → USDZExporter-Bm-c5e_n.mjs.map} +1 -1
  18. package/lib/{Vector4-DgGvlGnF.mjs → Vector4-C7TlIAyy.mjs} +2 -2
  19. package/lib/{Vector4-DgGvlGnF.mjs.map → Vector4-C7TlIAyy.mjs.map} +1 -1
  20. package/lib/{api-DrK8F76r.mjs → api-B5wIZIHt.mjs} +2 -2
  21. package/lib/{api-DrK8F76r.mjs.map → api-B5wIZIHt.mjs.map} +1 -1
  22. package/lib/{asset-loader.worker-eqHzNAwa.mjs → asset-loader.worker-CE4O0JU-.mjs} +1 -1
  23. package/lib/asset-loader.worker-CE4O0JU-.mjs.map +1 -0
  24. package/lib/{banana-for-scale-DGYmxeBG.mjs → banana-for-scale-D0bw51dn.mjs} +3 -3
  25. package/lib/{banana-for-scale-DGYmxeBG.mjs.map → banana-for-scale-D0bw51dn.mjs.map} +1 -1
  26. package/lib/{budgeteer.sw-BUMElkO1.mjs → budgeteer.sw-yR2xApHT.mjs} +1 -1
  27. package/lib/budgeteer.sw-yR2xApHT.mjs.map +1 -0
  28. package/lib/{common-utils-CyQUubmw.mjs → common-utils-DbL4tku0.mjs} +1 -1
  29. package/lib/{common-utils-CyQUubmw.mjs.map → common-utils-DbL4tku0.mjs.map} +1 -1
  30. package/lib/{component-dimensioning-Dao60YO2.mjs → component-dimensioning-VIUcXV7r.mjs} +40 -39
  31. package/lib/component-dimensioning-VIUcXV7r.mjs.map +1 -0
  32. package/lib/{component-raycast-helper-PVs7Vpbl.mjs → component-raycast-helper-CEAdBcdx.mjs} +4 -4
  33. package/lib/{component-raycast-helper-PVs7Vpbl.mjs.map → component-raycast-helper-CEAdBcdx.mjs.map} +1 -1
  34. package/lib/{configurator-herY75_C.mjs → configurator-CxlLvBCx.mjs} +4 -4
  35. package/lib/{configurator-herY75_C.mjs.map → configurator-CxlLvBCx.mjs.map} +1 -1
  36. package/lib/configurator-h8QoUnMz.mjs +2 -0
  37. package/lib/{continuous-drawing-helper-DIVY8E6B.mjs → continuous-drawing-helper-Dr1r-5N2.mjs} +2 -2
  38. package/lib/{continuous-drawing-helper-DIVY8E6B.mjs.map → continuous-drawing-helper-Dr1r-5N2.mjs.map} +1 -1
  39. package/lib/{dat.gui.module-B2PXSbre.mjs → dat.gui.module-CSOnFjd0.mjs} +1 -1
  40. package/lib/{dat.gui.module-B2PXSbre.mjs.map → dat.gui.module-CSOnFjd0.mjs.map} +1 -1
  41. package/lib/{decorate-CjaqqbUP.mjs → decorate-Bl-JF_YY.mjs} +1 -1
  42. package/lib/{decorate-CjaqqbUP.mjs.map → decorate-Bl-JF_YY.mjs.map} +1 -1
  43. package/lib/dimensioning-helper-BEGkpZFA.mjs +2 -0
  44. package/lib/{dimensioning-helper-Cgao7A18.mjs → dimensioning-helper-ChQDwSjn.mjs} +4 -4
  45. package/lib/{dimensioning-helper-Cgao7A18.mjs.map → dimensioning-helper-ChQDwSjn.mjs.map} +1 -1
  46. package/lib/{dist-Blgk0vU0.mjs → dist-BZTF7IJN.mjs} +1 -1
  47. package/lib/{dist-Blgk0vU0.mjs.map → dist-BZTF7IJN.mjs.map} +1 -1
  48. package/lib/{fflate.module-DTkA0kF8.mjs → fflate.module-Cx1QFI2-.mjs} +1 -1
  49. package/lib/{fflate.module-DTkA0kF8.mjs.map → fflate.module-Cx1QFI2-.mjs.map} +1 -1
  50. package/lib/{glb-viewer-DtyiyPiY.mjs → glb-viewer-27e6wfY4.mjs} +6 -6
  51. package/lib/{glb-viewer-DtyiyPiY.mjs.map → glb-viewer-27e6wfY4.mjs.map} +1 -1
  52. package/lib/glb-viewer-Dc2Tl8Ef.mjs +2 -0
  53. package/lib/{highlight-coordinator-DOO-54ml.mjs → highlight-coordinator-C05kDjj5.mjs} +12 -11
  54. package/lib/highlight-coordinator-C05kDjj5.mjs.map +1 -0
  55. package/lib/{homag-intelligence-BOqc8-8E.mjs → homag-intelligence-BRQ1WoQo.mjs} +6 -3
  56. package/lib/homag-intelligence-BRQ1WoQo.mjs.map +1 -0
  57. package/lib/{imos-ix-poc-export-helper-DRQK_p2h.mjs → imos-ix-poc-export-helper-DhxAAMc9.mjs} +3 -3
  58. package/lib/{imos-ix-poc-export-helper-DRQK_p2h.mjs.map → imos-ix-poc-export-helper-DhxAAMc9.mjs.map} +1 -1
  59. package/lib/{kernel-utils-voLUOj-0.mjs → kernel-utils-BvatnA7U.mjs} +2 -2
  60. package/lib/kernel-utils-BvatnA7U.mjs.map +1 -0
  61. package/lib/{layer-DvZF9ur3.mjs → layer-DaGoZ5YI.mjs} +1 -1
  62. package/lib/{layer-DvZF9ur3.mjs.map → layer-DaGoZ5YI.mjs.map} +1 -1
  63. package/lib/{material-viewer-Dk8D8-8C.mjs → material-viewer-Byi5t7-x.mjs} +6 -6
  64. package/lib/{material-viewer-Dk8D8-8C.mjs.map → material-viewer-Byi5t7-x.mjs.map} +1 -1
  65. package/lib/{packages-xgEJ9vvB.mjs → packages-3jOdcfbr.mjs} +5 -5
  66. package/lib/{packages-xgEJ9vvB.mjs.map → packages-3jOdcfbr.mjs.map} +1 -1
  67. package/lib/{planner-aBm7Ihtu.mjs → planner-BeINcWRR.mjs} +3 -3
  68. package/lib/{planner-aBm7Ihtu.mjs.map → planner-BeINcWRR.mjs.map} +1 -1
  69. package/lib/planner-Ler1UMAp.mjs +2 -0
  70. package/lib/{plugin-system-vlnG8j2T.mjs → plugin-system-DR5maiUo.mjs} +3 -3
  71. package/lib/{plugin-system-vlnG8j2T.mjs.map → plugin-system-DR5maiUo.mjs.map} +1 -1
  72. package/lib/render-cache-DCPIQbO1.mjs +150 -0
  73. package/lib/render-cache-DCPIQbO1.mjs.map +1 -0
  74. package/lib/render-order-BPF2wDMw.mjs +26 -0
  75. package/lib/render-order-BPF2wDMw.mjs.map +1 -0
  76. package/lib/{roomle-headless-setup-DbO_rLjK.mjs → roomle-headless-setup-ps3I0vOP.mjs} +1 -1
  77. package/lib/{roomle-headless-setup-DbO_rLjK.mjs.map → roomle-headless-setup-ps3I0vOP.mjs.map} +1 -1
  78. package/lib/roomle-headless.d.ts +27 -21
  79. package/lib/roomle-headless.js +15 -15
  80. package/lib/{roomle-renderer-FUqNfNIf.mjs → roomle-renderer-Ato6RMrd.mjs} +1 -1
  81. package/lib/{roomle-renderer-FUqNfNIf.mjs.map → roomle-renderer-Ato6RMrd.mjs.map} +1 -1
  82. package/lib/{roomle-sdk-k8Vvoclf.mjs → roomle-sdk-CsSQAqQG.mjs} +2777 -2626
  83. package/lib/roomle-sdk-CsSQAqQG.mjs.map +1 -0
  84. package/lib/roomle-sdk.d.ts +27 -21
  85. package/lib/roomle-sdk.js +7 -7
  86. package/lib/{roomle-webgpu-renderer-Dv_s6ZN-.mjs → roomle-webgpu-renderer-BBE14A8V.mjs} +7 -7
  87. package/lib/{roomle-webgpu-renderer-Dv_s6ZN-.mjs.map → roomle-webgpu-renderer-BBE14A8V.mjs.map} +1 -1
  88. package/lib/{scene-renderer-nIOJ3nuy.mjs → scene-renderer-B8SBMSQ7.mjs} +231 -372
  89. package/lib/scene-renderer-B8SBMSQ7.mjs.map +1 -0
  90. package/lib/{script-loader-BTeojHth.mjs → script-loader-Dx3gOiB3.mjs} +3 -3
  91. package/lib/{script-loader-BTeojHth.mjs.map → script-loader-Dx3gOiB3.mjs.map} +1 -1
  92. package/lib/{shading-settings-CRNmMpcn.mjs → shading-settings-BBhR7KcS.mjs} +2 -2
  93. package/lib/{shading-settings-CRNmMpcn.mjs.map → shading-settings-BBhR7KcS.mjs.map} +1 -1
  94. package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/package.json +1 -1
  95. package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/src/embind/plannerCoreCallback.d.ts +1 -1
  96. package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/src/embind/plannerCoreCallback.js +3 -3
  97. package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/src/embind/plannerCoreCallback.js.map +1 -1
  98. package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/src/embind/plannerCoreInterface.d.ts +1 -7
  99. package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/wasm_modern/ConfiguratorKernel.wasm +0 -0
  100. package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/wasm_modern/RoomleCore.wasm +0 -0
  101. package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/wasm_modern/RoomleToolsCore.wasm +0 -0
  102. package/lib/{stats-helper-iprJJmBn.mjs → stats-helper-W654V5ay.mjs} +3 -3
  103. package/lib/{stats-helper-iprJJmBn.mjs.map → stats-helper-W654V5ay.mjs.map} +1 -1
  104. package/lib/{svgo.browser-EB1zkPfG.mjs → svgo.browser-xZ3L7awG.mjs} +1 -1
  105. package/lib/{svgo.browser-EB1zkPfG.mjs.map → svgo.browser-xZ3L7awG.mjs.map} +1 -1
  106. package/lib/{three.tsl-DO_HZZuJ.mjs → three.tsl-B7hcNZE8.mjs} +2 -2
  107. package/lib/{three.tsl-DO_HZZuJ.mjs.map → three.tsl-B7hcNZE8.mjs.map} +1 -1
  108. package/lib/{three.tsl-BZfU6fFt.mjs → three.tsl-BBUCm-uB.mjs} +1 -1
  109. package/lib/{three.webgpu-bR4-ABJu.mjs → three.webgpu-ClICiWlK.mjs} +1 -1
  110. package/lib/{three.webgpu-ylONY593.mjs → three.webgpu-D3nSEIjD.mjs} +1 -1
  111. package/lib/{three.webgpu-ylONY593.mjs.map → three.webgpu-D3nSEIjD.mjs.map} +1 -1
  112. package/lib/{threejs-utils-D4TdXXAR.mjs → threejs-utils-WK7Uu2TS.mjs} +4 -4
  113. package/lib/threejs-utils-WK7Uu2TS.mjs.map +1 -0
  114. package/lib/{tools-core-La7SIpTQ.mjs → tools-core-CWrR_N9g.mjs} +3 -3
  115. package/lib/{tools-core-La7SIpTQ.mjs.map → tools-core-CWrR_N9g.mjs.map} +1 -1
  116. package/lib/{webgpu-C14yfIYy.mjs → webgpu-DSecxaB8.mjs} +3 -3
  117. package/lib/{webgpu-C14yfIYy.mjs.map → webgpu-DSecxaB8.mjs.map} +1 -1
  118. package/lib/workers-B-AqdQMe.mjs +6 -0
  119. package/lib/{workers-YGDNEfpU.mjs.map → workers-B-AqdQMe.mjs.map} +1 -1
  120. package/package.json +2 -2
  121. package/lib/asset-loader.worker-eqHzNAwa.mjs.map +0 -1
  122. package/lib/budgeteer.sw-BUMElkO1.mjs.map +0 -1
  123. package/lib/component-dimensioning-Dao60YO2.mjs.map +0 -1
  124. package/lib/configurator-Bj51dFg6.mjs +0 -2
  125. package/lib/dimensioning-helper-0s61LK9R.mjs +0 -2
  126. package/lib/glb-viewer-CUyHqGdt.mjs +0 -2
  127. package/lib/highlight-coordinator-DOO-54ml.mjs.map +0 -1
  128. package/lib/homag-intelligence-BOqc8-8E.mjs.map +0 -1
  129. package/lib/kernel-utils-voLUOj-0.mjs.map +0 -1
  130. package/lib/planner-DIz5mFvC.mjs +0 -2
  131. package/lib/roomle-sdk-k8Vvoclf.mjs.map +0 -1
  132. package/lib/scene-renderer-nIOJ3nuy.mjs.map +0 -1
  133. package/lib/threejs-utils-D4TdXXAR.mjs.map +0 -1
  134. package/lib/workers-YGDNEfpU.mjs +0 -6
@@ -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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"}
@@ -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 _roomleSvgRenderer;
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 a 2D elevation plan of the current configuration, returned as raw
8396
- * SVG markup (wireframe rendering with measurements).
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 elevation plans, containing one plan with its SVG markup
8405
+ * @returns the plans, each containing its SVG markup and its view type
8399
8406
  */
8400
- create2DElevationPlan(): Promise<ElevationPlans>;
8407
+ create2DPlanViews(): Promise<ElevationPlans>;
8401
8408
  /**
8402
- * Creates the 2D elevation plan of the current configuration (see
8403
- * {@link create2DElevationPlan}) and downloads it as an SVG file.
8409
+ * Creates the 2D plans of the current configuration (see
8410
+ * {@link create2DPlanViews}) and downloads each plan as an SVG file.
8404
8411
  */
8405
- download2DElevationPlan(): Promise<void>;
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
- private _isFenceContourWall;
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;
@@ -1,17 +1,17 @@
1
- import { a as e, i as t, n, r, t as i } from "./packages-xgEJ9vvB.mjs";
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-D4TdXXAR.mjs";
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-CjaqqbUP.mjs";
6
- import { V as p } from "./common-utils-CyQUubmw.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-k8Vvoclf.mjs";
8
- import { n as k } from "./roomle-renderer-FUqNfNIf.mjs";
9
- import { n as A } from "./script-loader-BTeojHth.mjs";
10
- import { t as j } from "./configurator-herY75_C.mjs";
11
- import { t as M } from "./planner-aBm7Ihtu.mjs";
12
- import { n as N, t as P } from "./glb-viewer-DtyiyPiY.mjs";
13
- import { t as be } from "./api-DrK8F76r.mjs";
14
- import { t as xe } from "./roomle-headless-setup-DbO_rLjK.mjs";
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-C14yfIYy.mjs"), n = new t(e);
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-bR4-ABJu.mjs"), t = new e({
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-Dv_s6ZN-.mjs");
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) {
@@ -77,4 +77,4 @@ var t = /* @__PURE__ */ function(e) {
77
77
  //#endregion
78
78
  export { r as a, n as i, c as n, t as o, o as r, s as t };
79
79
 
80
- //# sourceMappingURL=roomle-renderer-FUqNfNIf.mjs.map
80
+ //# sourceMappingURL=roomle-renderer-Ato6RMrd.mjs.map