@roomle/web-sdk 3.8.0 → 3.9.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/ConfiguratorKernel.wasm +0 -0
- package/lib/{GLTFExporter-BqjC9LhS.mjs → GLTFExporter-yfYOtLdk.mjs} +2 -2
- package/lib/{GLTFExporter-BqjC9LhS.mjs.map → GLTFExporter-yfYOtLdk.mjs.map} +1 -1
- package/lib/RoomleCore.js +3 -3
- package/lib/RoomleCore.wasm +0 -0
- package/lib/RoomleToolsCore.wasm +0 -0
- package/lib/{USDZExporter-qUD2VgwK.mjs → USDZExporter-DFJQYX8l.mjs} +2 -2
- package/lib/{USDZExporter-qUD2VgwK.mjs.map → USDZExporter-DFJQYX8l.mjs.map} +1 -1
- package/lib/{api-CbHAzwVm.mjs → api-s0Yey2rD.mjs} +12 -12
- package/lib/api-s0Yey2rD.mjs.map +1 -0
- package/lib/asset-loader.worker-A7nEeQB4.mjs.map +1 -1
- package/lib/{banana-for-scale-DiBCpVNM.mjs → banana-for-scale-CFY_5rk1.mjs} +4 -4
- package/lib/{banana-for-scale-DiBCpVNM.mjs.map → banana-for-scale-CFY_5rk1.mjs.map} +1 -1
- package/lib/budgeteer.sw-CQWYbQSc.mjs.map +1 -1
- package/lib/{common-utils-AB4Lnet3.mjs → common-utils-L3DF6Ey5.mjs} +2 -2
- package/lib/{common-utils-AB4Lnet3.mjs.map → common-utils-L3DF6Ey5.mjs.map} +1 -1
- package/lib/{component-dimensioning-LUnZnpqG.mjs → component-dimensioning-DmcHgmpq.mjs} +44 -38
- package/lib/component-dimensioning-DmcHgmpq.mjs.map +1 -0
- package/lib/{component-raycast-helper-Bl0mWPcj.mjs → component-raycast-helper-cJxdYLXm.mjs} +28 -28
- package/lib/{component-raycast-helper-Bl0mWPcj.mjs.map → component-raycast-helper-cJxdYLXm.mjs.map} +1 -1
- package/lib/configurator-CC0uDa2i.mjs +2 -0
- package/lib/configurator-CxsFgHxg.mjs +45 -0
- package/lib/{configurator-CP80d0HI.mjs.map → configurator-CxsFgHxg.mjs.map} +1 -1
- package/lib/{continuous-drawing-helper-BlRy7u2t.mjs → continuous-drawing-helper-DEmx54k_.mjs} +3 -3
- package/lib/{continuous-drawing-helper-BlRy7u2t.mjs.map → continuous-drawing-helper-DEmx54k_.mjs.map} +1 -1
- package/lib/{decorate-Bck1_lG8.mjs → decorate-C9r0zXzz.mjs} +1 -1
- package/lib/{decorate-Bck1_lG8.mjs.map → decorate-C9r0zXzz.mjs.map} +1 -1
- package/lib/{dimensioning-helper-vPhGfHd-.mjs → dimensioning-helper-BXD6AEqL.mjs} +28 -21
- package/lib/dimensioning-helper-BXD6AEqL.mjs.map +1 -0
- package/lib/dimensioning-helper-Do9jwg8T.mjs +2 -0
- package/lib/glb-viewer-DyHnMYi0.mjs +2 -0
- package/lib/{glb-viewer-B7pA8K_w.mjs → glb-viewer-I86nXb0A.mjs} +69 -69
- package/lib/{glb-viewer-B7pA8K_w.mjs.map → glb-viewer-I86nXb0A.mjs.map} +1 -1
- package/lib/{highlight-coordinator-DeB46jQq.mjs → highlight-coordinator-DvgAfvb2.mjs} +3 -3
- package/lib/{highlight-coordinator-DeB46jQq.mjs.map → highlight-coordinator-DvgAfvb2.mjs.map} +1 -1
- package/lib/{homag-intelligence-f1JD0An1.mjs → homag-intelligence-Bt--x6_f.mjs} +23 -9
- package/lib/homag-intelligence-Bt--x6_f.mjs.map +1 -0
- package/lib/{imos-ix-poc-export-helper-Vyv-uuNs.mjs → imos-ix-poc-export-helper-C9wPB6fl.mjs} +3 -3
- package/lib/{imos-ix-poc-export-helper-Vyv-uuNs.mjs.map → imos-ix-poc-export-helper-C9wPB6fl.mjs.map} +1 -1
- package/lib/kernel-C7YDLxq8.mjs.map +1 -1
- package/lib/{kernel-utils-BG1uqfT_.mjs → kernel-utils-B5QlsCwn.mjs} +15 -7
- package/lib/kernel-utils-B5QlsCwn.mjs.map +1 -0
- package/lib/{layer-BfckfWZz.mjs → layer-C_JtkhdO.mjs} +1 -1
- package/lib/{layer-BfckfWZz.mjs.map → layer-C_JtkhdO.mjs.map} +1 -1
- package/lib/{main-CuqGqemT.mjs → main-DeOPstVA.mjs} +37244 -3141
- package/lib/main-DeOPstVA.mjs.map +1 -0
- package/lib/{material-viewer-Cij9aWpI.mjs → material-viewer-D8Qdq6-m.mjs} +55 -55
- package/lib/material-viewer-D8Qdq6-m.mjs.map +1 -0
- package/lib/packages-eckwotTn.mjs +4 -0
- package/lib/{planner-DKbmQVSf.mjs → planner-BWZr-Th2.mjs} +14 -14
- package/lib/{planner-DKbmQVSf.mjs.map → planner-BWZr-Th2.mjs.map} +1 -1
- package/lib/planner-D3jvWraY.mjs +2 -0
- package/lib/{plugin-system-BEZnFUyT.mjs → plugin-system-BBgoIai2.mjs} +3 -3
- package/lib/{plugin-system-BEZnFUyT.mjs.map → plugin-system-BBgoIai2.mjs.map} +1 -1
- package/lib/roomle-headless-setup-CMK-quZI.mjs.map +1 -1
- package/lib/roomle-headless.d.ts +279 -38
- package/lib/roomle-headless.js +42 -41
- package/lib/roomle-headless.js.map +1 -1
- package/lib/{roomle-renderer-BgT28pfp.mjs → roomle-renderer-CkSFbpmg.mjs} +2 -2
- package/lib/{roomle-renderer-BgT28pfp.mjs.map → roomle-renderer-CkSFbpmg.mjs.map} +1 -1
- package/lib/roomle-sdk.d.ts +279 -38
- package/lib/roomle-sdk.js +8 -7
- package/lib/{roomle-webgpu-renderer-BdCItfH1.mjs → roomle-webgpu-renderer-Cs4eLEwf.mjs} +690 -280
- package/lib/roomle-webgpu-renderer-Cs4eLEwf.mjs.map +1 -0
- package/lib/{scene-renderer-Bdl7umAf.mjs → scene-renderer-4zk6BXsR.mjs} +228 -228
- package/lib/{scene-renderer-Bdl7umAf.mjs.map → scene-renderer-4zk6BXsR.mjs.map} +1 -1
- package/lib/{script-loader-BtWHegD-.mjs → script-loader-DSL6zJat.mjs} +9 -9
- package/lib/{script-loader-BtWHegD-.mjs.map → script-loader-DSL6zJat.mjs.map} +1 -1
- package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/package.json +1 -1
- package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/src/embind/configuratorCoreInterface.d.ts +7 -3
- package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/src/embind/configuratorCoreInterface.js +2 -1
- package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/src/embind/configuratorCoreInterface.js.map +1 -1
- package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/src/embind/plannerCoreInterface.d.ts +37 -3
- package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/src/embind/plannerCoreInterface.js +12 -1
- package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/src/embind/plannerCoreInterface.js.map +1 -1
- package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/wasm_modern/ConfiguratorKernel.wasm +0 -0
- package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/wasm_modern/RoomleCore.js +3 -3
- package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/wasm_modern/RoomleCore.wasm +0 -0
- package/lib/static/roomle-core-hsc/node_modules/roomle-core-hsc/wasm_modern/RoomleToolsCore.wasm +0 -0
- package/lib/{stats-helper-BvDfWWfq.mjs → stats-helper-DyRFKnMs.mjs} +3 -3
- package/lib/{stats-helper-BvDfWWfq.mjs.map → stats-helper-DyRFKnMs.mjs.map} +1 -1
- package/lib/{three.core-K1JzUaep.mjs → three.core-DNErG1F6.mjs} +1 -1
- package/lib/{three.core-K1JzUaep.mjs.map → three.core-DNErG1F6.mjs.map} +1 -1
- package/lib/{three.module-Q2K9uyhi.mjs → three.module-BZkESKo3.mjs} +2 -2
- package/lib/{three.module-Q2K9uyhi.mjs.map → three.module-BZkESKo3.mjs.map} +1 -1
- package/lib/{three.webgpu-7v7o6Pxs.mjs → three.webgpu-C8myBXe1.mjs} +2 -2
- package/lib/{three.webgpu-7v7o6Pxs.mjs.map → three.webgpu-C8myBXe1.mjs.map} +1 -1
- package/lib/three.webgpu-WIkDzwXU.mjs +3 -0
- package/lib/{threejs-utils-BzXU2M3w.mjs → threejs-utils-fEhH05zP.mjs} +103 -87
- package/lib/threejs-utils-fEhH05zP.mjs.map +1 -0
- package/lib/{tools-core-BoxckhTR.mjs → tools-core-Bf4_WCg8.mjs} +5 -5
- package/lib/{tools-core-BoxckhTR.mjs.map → tools-core-Bf4_WCg8.mjs.map} +1 -1
- package/package.json +5 -2
- package/lib/api-CbHAzwVm.mjs.map +0 -1
- package/lib/component-dimensioning-LUnZnpqG.mjs.map +0 -1
- package/lib/configurator-BmJX0gB5.mjs +0 -2
- package/lib/configurator-CP80d0HI.mjs +0 -45
- package/lib/dimensioning-helper-5xsc6I7Y.mjs +0 -2
- package/lib/dimensioning-helper-vPhGfHd-.mjs.map +0 -1
- package/lib/glb-viewer-XFEP993c.mjs +0 -2
- package/lib/homag-intelligence-f1JD0An1.mjs.map +0 -1
- package/lib/kernel-utils-BG1uqfT_.mjs.map +0 -1
- package/lib/main-CuqGqemT.mjs.map +0 -1
- package/lib/material-viewer-Cij9aWpI.mjs.map +0 -1
- package/lib/packages-DALvuVA_.mjs +0 -4
- package/lib/planner-CVn2Lls0.mjs +0 -2
- package/lib/roomle-webgpu-renderer-BdCItfH1.mjs.map +0 -1
- package/lib/three.webgpu-ChguPx4k.mjs +0 -3
- package/lib/threejs-utils-BzXU2M3w.mjs.map +0 -1
package/lib/roomle-headless.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { i as e, t } from "./kernel-C7YDLxq8.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { n as P } from "./
|
|
5
|
-
import {
|
|
6
|
-
import { t as F } from "./
|
|
7
|
-
import {
|
|
8
|
-
import { t as R } from "./
|
|
9
|
-
import "./
|
|
2
|
+
import { pt as n } from "./threejs-utils-fEhH05zP.mjs";
|
|
3
|
+
import { bi as r } from "./three.core-DNErG1F6.mjs";
|
|
4
|
+
import { F as i, G as a, H as o, M as s, N as c, O as l, P as u, U as d, V as f, W as p, a as m, at as h, b as g, c as _, ct as v, i as y, j as b, k as x, l as S, n as C, nt as w, q as T, rt as E, s as D, st as O, tt as k, ut as A, v as j, x as M, y as N, z as P } from "./main-DeOPstVA.mjs";
|
|
5
|
+
import { n as ee } from "./script-loader-DSL6zJat.mjs";
|
|
6
|
+
import { t as F } from "./configurator-CxsFgHxg.mjs";
|
|
7
|
+
import { t as I } from "./planner-BWZr-Th2.mjs";
|
|
8
|
+
import { n as L, t as R } from "./glb-viewer-I86nXb0A.mjs";
|
|
9
|
+
import { t as z } from "./api-s0Yey2rD.mjs";
|
|
10
|
+
import "./packages-eckwotTn.mjs";
|
|
10
11
|
import "./roomle-headless-setup-CMK-quZI.mjs";
|
|
11
|
-
import { createRequire as
|
|
12
|
+
import { createRequire as B } from "module";
|
|
12
13
|
//#region packages/headless-core/src/headless-script-loader.ts
|
|
13
|
-
var
|
|
14
|
+
var V = B(import.meta.url), H = {}, U = [
|
|
14
15
|
[
|
|
15
16
|
"ConfiguratorKernel.wasm",
|
|
16
17
|
"ConfiguratorKernel",
|
|
@@ -26,48 +27,48 @@ var B = z(import.meta.url), V = {}, H = [
|
|
|
26
27
|
"RoomleToolsCore",
|
|
27
28
|
"roomle-core-hsc/wasm_modern/RoomleToolsCore.js"
|
|
28
29
|
]
|
|
29
|
-
],
|
|
30
|
+
], W = class {
|
|
30
31
|
constructor(e) {
|
|
31
32
|
this._creator_ = e;
|
|
32
33
|
}
|
|
33
34
|
async fetch(e, t) {
|
|
34
|
-
if (
|
|
35
|
+
if (H[t.id]) return;
|
|
35
36
|
if (typeof e == "function") {
|
|
36
|
-
this._registerFactory(e),
|
|
37
|
+
this._registerFactory(e), H[t.id] = !0;
|
|
37
38
|
return;
|
|
38
39
|
}
|
|
39
40
|
let n = this._resolveEntry(e);
|
|
40
41
|
if (n) {
|
|
41
|
-
let [, r, i] = n, a =
|
|
42
|
-
globalThis[r] = a.default || a,
|
|
42
|
+
let [, r, i] = n, a = V(e.startsWith("/") ? e : i);
|
|
43
|
+
globalThis[r] = a.default || a, H[t.id] = !0;
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
_registerFactory(e) {
|
|
46
47
|
let t = e.toString();
|
|
47
|
-
for (let [n, r] of
|
|
48
|
+
for (let [n, r] of U) if (t.includes(n)) {
|
|
48
49
|
globalThis[r] = e;
|
|
49
50
|
return;
|
|
50
51
|
}
|
|
51
52
|
console.warn("HeadlessScriptLoader: Could not identify Emscripten factory function");
|
|
52
53
|
}
|
|
53
54
|
_resolveEntry(e) {
|
|
54
|
-
for (let t of
|
|
55
|
+
for (let t of U) {
|
|
55
56
|
let [n, r] = t, i = r;
|
|
56
57
|
if (e.includes(i) || e.includes(n)) return t;
|
|
57
58
|
}
|
|
58
|
-
return e.includes("configurator") ?
|
|
59
|
+
return e.includes("configurator") ? U[0] : e.includes("planner") ? U[1] : e.includes("tools") ? U[2] : (console.warn(`HeadlessScriptLoader: Could not resolve module for URL: ${e}`), null);
|
|
59
60
|
}
|
|
60
61
|
loadScripts(e) {
|
|
61
62
|
let t = e.map((e) => this.fetch(e.name, { id: e.id }));
|
|
62
63
|
return Promise.all(t);
|
|
63
64
|
}
|
|
64
65
|
resolveKernelPaths(e) {
|
|
65
|
-
return
|
|
66
|
+
return ee(e);
|
|
66
67
|
}
|
|
67
68
|
cleanUp() {
|
|
68
|
-
|
|
69
|
+
H = {};
|
|
69
70
|
}
|
|
70
|
-
},
|
|
71
|
+
}, G = class {
|
|
71
72
|
get _lifeCycleManager() {
|
|
72
73
|
return globalThis.__RML__DI__?.lookup("life-cycle-manager", this._creator_);
|
|
73
74
|
}
|
|
@@ -123,7 +124,7 @@ var B = z(import.meta.url), V = {}, H = [
|
|
|
123
124
|
}
|
|
124
125
|
setDomElement(e) {}
|
|
125
126
|
getClientDimensions() {
|
|
126
|
-
return new
|
|
127
|
+
return new r(this._width, this._height);
|
|
127
128
|
}
|
|
128
129
|
getAspectRatio() {
|
|
129
130
|
return this._width / this._height;
|
|
@@ -133,7 +134,7 @@ var B = z(import.meta.url), V = {}, H = [
|
|
|
133
134
|
pause() {}
|
|
134
135
|
resume() {}
|
|
135
136
|
destroy() {}
|
|
136
|
-
},
|
|
137
|
+
}, K = class {
|
|
137
138
|
constructor(e) {
|
|
138
139
|
this._creator_ = e;
|
|
139
140
|
}
|
|
@@ -161,11 +162,11 @@ var B = z(import.meta.url), V = {}, H = [
|
|
|
161
162
|
}
|
|
162
163
|
setAlwaysUseCache(e) {}
|
|
163
164
|
preFillAssetCache(e, t) {}
|
|
164
|
-
},
|
|
165
|
+
}, q = class extends D {
|
|
165
166
|
_getScriptLoaderKernelId(e) {
|
|
166
167
|
return e === x.PLANNER ? "kernel-planner" : "kernel";
|
|
167
168
|
}
|
|
168
|
-
},
|
|
169
|
+
}, J = class {
|
|
169
170
|
wrap(e) {
|
|
170
171
|
return new Proxy(e, { get(e, t) {
|
|
171
172
|
let n = e[t];
|
|
@@ -178,7 +179,7 @@ var B = z(import.meta.url), V = {}, H = [
|
|
|
178
179
|
} : n;
|
|
179
180
|
} });
|
|
180
181
|
}
|
|
181
|
-
},
|
|
182
|
+
}, Y = {
|
|
182
183
|
add(e) {
|
|
183
184
|
try {
|
|
184
185
|
e.end?.();
|
|
@@ -190,10 +191,10 @@ var B = z(import.meta.url), V = {}, H = [
|
|
|
190
191
|
return [];
|
|
191
192
|
},
|
|
192
193
|
update() {}
|
|
193
|
-
},
|
|
194
|
+
}, X = () => {
|
|
194
195
|
let e = window;
|
|
195
|
-
e.TWEEN =
|
|
196
|
-
},
|
|
196
|
+
e.TWEEN = Y;
|
|
197
|
+
}, Z = (e) => e.split(":").length - 1 == 1, Q = (e) => e.split(":").length - 1 <= 0, $ = (e) => e ? e.startsWith("component@") : !1, te = class e {
|
|
197
198
|
constructor() {
|
|
198
199
|
this._initialized = !1, this._configuratorReady = !1, this._plannerReady = !1, this._glbViewerReady = !1, this._loadedConfigurationId = null, this._loadedPlanId = null, this._loadedStaticItemId = null, this._width = 1024, this._height = 768, this._loaderQueue = Promise.resolve(), this._onReadyForRenderArmed = null;
|
|
199
200
|
}
|
|
@@ -202,7 +203,7 @@ var B = z(import.meta.url), V = {}, H = [
|
|
|
202
203
|
return await n._init(t), n;
|
|
203
204
|
}
|
|
204
205
|
async _init(e) {
|
|
205
|
-
this._width = e.width ?? 1024, this._height = e.height ?? 768,
|
|
206
|
+
this._width = e.width ?? 1024, this._height = e.height ?? 768, X(), this._registerHeadlessServices(this._width, this._height), await S.setGlobalInitData({
|
|
206
207
|
configuratorId: e.configuratorId,
|
|
207
208
|
locale: e.locale,
|
|
208
209
|
tenant: e.tenant,
|
|
@@ -211,21 +212,21 @@ var B = z(import.meta.url), V = {}, H = [
|
|
|
211
212
|
}), this._initialized = !0;
|
|
212
213
|
}
|
|
213
214
|
_registerHeadlessServices(e, t) {
|
|
214
|
-
let n = new
|
|
215
|
+
let n = new k();
|
|
215
216
|
globalThis.__RML__DI__ = n;
|
|
216
|
-
class r extends
|
|
217
|
+
class r extends G {
|
|
217
218
|
constructor(n) {
|
|
218
219
|
super(n, e, t);
|
|
219
220
|
}
|
|
220
221
|
}
|
|
221
222
|
let i = [
|
|
222
|
-
new
|
|
223
|
-
new
|
|
224
|
-
new
|
|
225
|
-
new
|
|
226
|
-
new
|
|
223
|
+
new E("script-loader", W, w.CONTEXT, !0),
|
|
224
|
+
new E("dom-helper", r, w.CONTEXT, !0),
|
|
225
|
+
new E("data-syncer", K, w.GLOBAL, !0),
|
|
226
|
+
new E("planner-kernel-access", q, w.GLOBAL, !0),
|
|
227
|
+
new E("kernel-callback-guard", J, w.GLOBAL, !0)
|
|
227
228
|
];
|
|
228
|
-
n.addDependencyInjectionAssignments(
|
|
229
|
+
n.addDependencyInjectionAssignments(y), n.addDependencyInjectionAssignments(i);
|
|
229
230
|
}
|
|
230
231
|
_makeStubElement() {
|
|
231
232
|
return {
|
|
@@ -286,8 +287,8 @@ var B = z(import.meta.url), V = {}, H = [
|
|
|
286
287
|
});
|
|
287
288
|
}
|
|
288
289
|
async loadObject(e, t) {
|
|
289
|
-
if (this._ensureInitialized(),
|
|
290
|
-
return
|
|
290
|
+
if (this._ensureInitialized(), $(e)) throw Error(`HeadlessRoomleSdk: component ids ("${e}") are not supported. Use loadConfigurableItemById, loadConfiguration, or loadPlan directly.`);
|
|
291
|
+
return Q(e) ? this.loadPlan(e, t) : Z(e) ? (await (await S.getRapiAccess()).getItem(e))?.configuration ? this.loadConfigurableItemById(e, t) : this.loadStaticItem(e, t) : this.loadConfiguration(e, t);
|
|
291
292
|
}
|
|
292
293
|
async loadPlan(e, t) {
|
|
293
294
|
return this._ensureInitialized(), this._withLoader(async () => {
|
|
@@ -435,6 +436,6 @@ var B = z(import.meta.url), V = {}, H = [
|
|
|
435
436
|
}
|
|
436
437
|
};
|
|
437
438
|
//#endregion
|
|
438
|
-
export { t as CONFIGURATION_TYPE, e as CORE_PERMISSION_TO_DELETE,
|
|
439
|
+
export { t as CONFIGURATION_TYPE, n as CORE_EDGE_TYPE, e as CORE_PERMISSION_TO_DELETE, F as Configurator, m as ConfiguratorUiCallbacks, b as FloorPlanElementViewModel, R as GlbViewer, T as GlobalCallback, P as HI_CONTEXT_ACTION, te as HeadlessRoomleSdk, O as IdbManager, C as Main, M as MeasurementLinePlanElementViewModel, j as PLAN_ELEMENT_CHANGE_TYPES, i as PlanElementViewModel, u as PlanObjectViewModel, I as Planner, h as RapiAccess, z as RoomDesignerApi, l as RoomleConfigurator, L as RoomleGLBViewer, A as RoomleLightSource, _ as RoomlePlanner, N as RoomlePlannerUiCallback, S as RoomleSdk, c as StaticPlanObjectViewModel, s as WallPlanElementViewModel, f as createExtObj, a as createExtObjId, v as getCatalogIdFromConfigurationHash, o as isExtObjId, d as isExternalObject, g as isSafari, p as removeExtObjIdPrefix };
|
|
439
440
|
|
|
440
441
|
//# sourceMappingURL=roomle-headless.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roomle-headless.js","names":[],"sources":["../../packages/headless-core/src/headless-script-loader.ts","../../packages/headless-core/src/stubs.ts","../../packages/headless-core/src/headless-dom-helper.ts","../../packages/headless-core/src/headless-data-syncer.ts","../../packages/headless-core/src/headless-planner-kernel-access.ts","../../packages/headless-core/src/headless-kernel-callback-guard.ts","../../packages/headless-core/src/headless-tween-stub.ts","../../../common/src/utils/id-inferrer.ts","../../packages/headless-core/src/headless-sdk.ts"],"sourcesContent":["/**\n * Replaces the browser ScriptLoader for headless mode.\n * Instead of injecting <script> tags, directly imports the Emscripten JS modules.\n */\nimport { createRequire } from 'module';\nimport type { Context } from '../../common-core/src/di/context';\nimport { getHeadlessWasmPath } from '../../common-core/src/static-files/roomle-core';\n\n// createRequire is needed because the Emscripten kernel files are CommonJS\n// and must be loaded synchronously\nconst _require = createRequire(import.meta.url);\n\nlet _idCache: { [key: string]: boolean } = {};\n\n// Maps a .wasm filename found in the Emscripten factory's source to its global name.\n// Each Emscripten factory references its own .wasm file (e.g. ConfiguratorKernel.wasm).\nconst WASM_TO_GLOBAL: Array<\n [wasmFile: string, globalName: string, modulePath: string]\n> = [\n [\n 'ConfiguratorKernel.wasm',\n 'ConfiguratorKernel',\n 'roomle-core-hsc/wasm_modern/ConfiguratorKernel.js',\n ],\n [\n 'RoomleCore.wasm',\n 'RoomleCore',\n 'roomle-core-hsc/wasm_modern/RoomleCore.js',\n ],\n [\n 'RoomleToolsCore.wasm',\n 'RoomleToolsCore',\n 'roomle-core-hsc/wasm_modern/RoomleToolsCore.js',\n ],\n];\n\nexport default class HeadlessScriptLoader implements Context {\n public _creator_: string;\n\n constructor(creator: string) {\n this._creator_ = creator;\n }\n\n public async fetch(url: string, options: { id: string }) {\n if (_idCache[options.id]) {\n return;\n }\n\n // In Bun, Vite's ?no-inline?url imports resolve to the module's default\n // export (a function) rather than a URL string. Handle both cases.\n if (typeof url === 'function') {\n this._registerFactory(url);\n _idCache[options.id] = true;\n return;\n }\n\n const entry = this._resolveEntry(url);\n if (entry) {\n const [, globalName, modulePath] = entry;\n // If url is an absolute filesystem path (from getHeadlessWasmPath),\n // require it directly. Otherwise fall back to the module specifier\n // (works from source where roomle-core-hsc is in node_modules).\n const pathToLoad = url.startsWith('/') ? url : modulePath;\n const mod = _require(pathToLoad);\n (globalThis as any)[globalName] = mod.default || mod;\n _idCache[options.id] = true;\n }\n }\n\n // Identify an Emscripten factory function by checking its source for the\n // unique .wasm filename it references, then register it on globalThis\n // under the name the kernel-access classes expect (e.g. window.ConfiguratorKernel).\n private _registerFactory(factory: () => void) {\n const source = factory.toString();\n for (const [wasmFile, globalName] of WASM_TO_GLOBAL) {\n if (source.includes(wasmFile)) {\n (globalThis as any)[globalName] = factory;\n return;\n }\n }\n console.warn(\n 'HeadlessScriptLoader: Could not identify Emscripten factory function',\n );\n }\n\n private _resolveEntry(url: string) {\n for (const entry of WASM_TO_GLOBAL) {\n const [wasmFile, globalName] = entry;\n const baseName = globalName; // e.g. \"ConfiguratorKernel\"\n if (url.includes(baseName) || url.includes(wasmFile)) {\n return entry;\n }\n }\n // Fallback: looser matching for generic URLs\n if (url.includes('configurator')) {\n return WASM_TO_GLOBAL[0];\n }\n if (url.includes('planner')) {\n return WASM_TO_GLOBAL[1];\n }\n if (url.includes('tools')) {\n return WASM_TO_GLOBAL[2];\n }\n console.warn(\n `HeadlessScriptLoader: Could not resolve module for URL: ${url}`,\n );\n return null;\n }\n\n public loadScripts(scripts: Array<{ id: string; name: string }>) {\n const promises = scripts.map((script) =>\n this.fetch(script.name, { id: script.id }),\n );\n return Promise.all(promises);\n }\n\n public resolveKernelPaths(type: 'configurator' | 'planner' | 'tools'): {\n wasm: string;\n loader: string;\n } {\n return getHeadlessWasmPath(type);\n }\n\n public cleanUp() {\n _idCache = {};\n }\n}\n","export const noop = () => {};\n","/**\n * Stub DomHelper for headless mode.\n * Returns fixed dimensions since we don't render to a real canvas.\n */\nimport { Vector2 } from 'three';\nimport { noop } from './stubs';\nimport type {\n LifeCycleCallbacks,\n LifeCycleManager,\n} from '../../common-core/src/life-cycle-manager';\nimport type { Context } from '../../common-core/src/di/context';\n\nexport default class HeadlessDomHelper implements LifeCycleCallbacks, Context {\n public _creator_: string;\n\n // Manual DI lookup instead of @inject decorator (avoids legacy/TC39 decorator mismatch)\n private get _lifeCycleManager(): LifeCycleManager | undefined {\n return (globalThis as any).__RML__DI__?.lookup(\n 'life-cycle-manager',\n this._creator_,\n );\n }\n\n private _width: number;\n private _height: number;\n private _stubElement: any;\n\n get element(): any {\n return this._stubElement;\n }\n\n constructor(creator: string, width = 1024, height = 768) {\n this._creator_ = creator;\n this._width = width;\n this._height = height;\n\n const w = this._width;\n const h = this._height;\n this._stubElement = {\n clientWidth: w,\n clientHeight: h,\n appendChild() {},\n removeChild() {},\n style: {},\n classList: {\n add() {},\n remove() {},\n contains() {\n return false;\n },\n },\n setAttribute() {},\n getAttribute(): string | null {\n return null;\n },\n children: [] as any[],\n getBoundingClientRect() {\n return {\n x: 0,\n y: 0,\n width: w,\n height: h,\n top: 0,\n left: 0,\n bottom: h,\n right: w,\n };\n },\n addEventListener() {},\n removeEventListener() {},\n dispatchEvent() {\n return true;\n },\n offsetWidth: w,\n offsetHeight: h,\n scrollWidth: w,\n scrollHeight: h,\n contains() {\n return false;\n },\n };\n }\n\n public setDomElement(_element: any) {\n noop();\n }\n\n public getClientDimensions() {\n return new Vector2(this._width, this._height);\n }\n\n public getAspectRatio() {\n return this._width / this._height;\n }\n\n public ensureCanvasFocus() {}\n public reset() {}\n public pause() {}\n public resume() {}\n public destroy() {}\n}\n","/**\n * Replaces the Worker-based DataSyncer with a no-op for headless mode.\n * In headless mode, assets are loaded on-demand via RapiAccess rather than\n * being pre-synced with a Web Worker.\n */\nimport type { RapiId } from '@roomle/web-sdk';\nimport { noop } from './stubs';\nimport type { Context } from '../../common-core/src/di/context';\n\nexport default class HeadlessDataSyncer implements Context {\n public _creator_: string;\n\n constructor(creator: string) {\n this._creator_ = creator;\n }\n\n public start(_catalogId: RapiId) {\n return Promise.resolve();\n }\n\n public syncCatalog(_catalogId: RapiId): Promise<void> {\n return Promise.resolve();\n }\n\n public syncFloorTag(_tagId: RapiId) {\n return Promise.resolve();\n }\n\n public syncTypeChangeTag(_tagId: RapiId) {\n return Promise.resolve();\n }\n\n public _syncTypeChangeTag(_tagId: RapiId): Promise<any> {\n return Promise.resolve();\n }\n\n public getIsCatalogSynced(_catalogId: RapiId) {\n return false;\n }\n\n public onCommand(_command: number, _conversationId: number, _data: any) {\n noop();\n }\n\n public requestAsset(url: string, _urlAsFallback: boolean = false): string {\n return url;\n }\n\n public setAlwaysUseCache(_alwaysUseCache: boolean): void {\n noop();\n }\n\n public preFillAssetCache(_key: string, _url: string) {\n noop();\n }\n}\n","/**\n * Headless override of `PlannerKernelAccess`.\n */\nimport { KERNEL_TYPE } from '../../common-core/src/services/common-kernel-access';\nimport PlannerKernelAccess from '../../planner-core/src/services/planner-kernel-access';\n\nexport default class HeadlessPlannerKernelAccess extends PlannerKernelAccess {\n protected _getScriptLoaderKernelId(kernelType: KERNEL_TYPE): string {\n return kernelType === KERNEL_TYPE.PLANNER ? 'kernel-planner' : 'kernel';\n }\n}\n","import type { KernelCallbackGuard } from '../../common-core/src/services/kernel-callback-guard';\n\n/**\n * Headless implementation: wraps the kernel callback target in a Proxy so that\n * any JS exception thrown inside a callback invoked from C++ (via Embind) is\n * caught and logged rather than propagating into C++, which would call\n * std::terminate and abort the process.\n */\nexport default class HeadlessKernelCallbackGuard\n implements KernelCallbackGuard\n{\n wrap<T extends object>(target: T): T {\n return new Proxy(target, {\n get(t: any, prop) {\n const val = t[prop];\n if (typeof val === 'function') {\n return function (...args: any[]) {\n try {\n return val.apply(t, args);\n } catch (e) {\n console.error(\n `[Headless] Kernel callback '${String(prop)}' threw:`,\n e,\n );\n }\n };\n }\n return val;\n },\n });\n }\n}\n","// Prevents tween effects from happening in headless mode, we don't ever want\n// things to fade in or out headlessly because it creates delays and causes\n// elements to show up white or half-visible as they tween in while taking a screenshot.\n\ninterface MinimalTween {\n end?: () => void;\n}\n\ninterface MinimalTweenGroup {\n add(tween: MinimalTween): void;\n remove(_tween: MinimalTween): void;\n removeAll(): void;\n getAll(): MinimalTween[];\n update(_time?: number): void;\n}\n\nconst noopGroup: MinimalTweenGroup = {\n add(tween) {\n // Synchronously fast-forward. Wrapped in try/catch so a single\n // misbehaving tween can't poison the whole queue — at worst that\n // tween silently doesn't apply, exactly as in browser mode if it\n // never advances.\n try {\n tween.end?.();\n } catch {\n // ignore\n }\n },\n remove() {},\n removeAll() {},\n getAll() {\n return [];\n },\n update() {},\n};\n\nexport const installHeadlessTweenStub = (): void => {\n const target = window as unknown as { TWEEN?: MinimalTweenGroup };\n // Always overwrite — if a previous SDK boot left the real Group here,\n // we want our noop in its place for the new instance.\n target.TWEEN = noopGroup;\n};\n","import type { RapiId, RapiPlanSnapshotId } from '@roomle/web-sdk';\n\nexport const isIdAnItem = (id: string) => id.split(':').length - 1 === 1;\n\nexport const isIdAPlan = (id: string) => id.split(':').length - 1 <= 0;\n\nexport const isIdAComponent = (id: string) =>\n id ? id.startsWith('component@') : false;\n\nexport const isIdAConfigurationString = (id: string) =>\n id.startsWith('{') && id.endsWith('}');\n\nexport const isPlanSnapshotId = (\n id: string | RapiId,\n): id is RapiPlanSnapshotId => id.startsWith('ps_');\n","/**\n * Main entry point for the headless Roomle SDK.\n * Provides the ability to run the Roomle web-sdk in Node.js/Bun\n * for loading configurations/plans and exporting them to GLB/USDZ.\n */\nimport HeadlessScriptLoader from './headless-script-loader';\nimport HeadlessDomHelper from './headless-dom-helper';\nimport HeadlessDataSyncer from './headless-data-syncer';\nimport HeadlessPlannerKernelAccess from './headless-planner-kernel-access';\nimport HeadlessKernelCallbackGuard from './headless-kernel-callback-guard';\nimport { installHeadlessTweenStub } from './headless-tween-stub';\nimport type {\n RoomlePlanner,\n Planner,\n RoomleConfigurator,\n Configurator,\n InitDataDefinition,\n GlobalInitDataDefinition,\n RapiId,\n GlbViewer,\n RoomleGLBViewer,\n} from '../../index';\nimport { RoomleSdk } from '../../index';\nimport {\n Container,\n DependencyInjectionAssignment,\n DI_TYPE,\n} from '../../common-core/src/di/container';\nimport { INJECTABLES } from '../../common-core/src/di/injectables';\nimport {\n isIdAComponent,\n isIdAPlan,\n isIdAnItem,\n} from '#/common/src/utils/id-inferrer';\nimport type { Mesh } from 'three';\n\nexport interface HeadlessInitData\n extends Partial<InitDataDefinition>,\n Partial<GlobalInitDataDefinition> {\n configuratorId: string;\n /** Canvas width in pixels. Defaults to 1024. */\n width?: number;\n /** Canvas height in pixels. Defaults to 768. */\n height?: number;\n}\n\nexport interface ExportResult {\n buffer: ArrayBuffer;\n}\n\nexport interface ImageExportOptions {\n /** Supersampling anti-aliasing factor. Defaults to 2. */\n ssaa?: number;\n /** Output image size in pixels. Defaults to 1024. */\n size?: number;\n}\n\n/** Mixin for image exports that frame the scene from a rotatable camera. */\nexport interface RotatableImageExportOptions {\n /** Camera rotation around the Y axis, in radians. */\n rotationY?: number;\n}\n\nexport interface ScreenshotExportOptions\n extends ImageExportOptions,\n RotatableImageExportOptions {\n /** JPEG quality (0–1). Defaults to 1. */\n quality?: number;\n}\n\nexport interface PerspectiveImageExportOptions\n extends ImageExportOptions,\n RotatableImageExportOptions {\n showDimensions?: boolean;\n}\n\nexport interface TopImageExportOptions extends ImageExportOptions {\n showDimensions?: boolean;\n}\n\nexport class HeadlessRoomleSdk {\n private _planner: RoomlePlanner;\n private _plannerMain: Planner;\n private _configurator: RoomleConfigurator;\n private _configuratorMain: Configurator;\n private _glbViewer: RoomleGLBViewer;\n private _glbViewerMain: GlbViewer;\n private _initialized = false;\n private _configuratorReady = false;\n private _plannerReady = false;\n private _glbViewerReady = false;\n private _loadedConfigurationId: RapiId | null = null;\n private _loadedPlanId: string | null = null;\n private _loadedStaticItemId: string | null = null;\n private _width = 1024;\n private _height = 768;\n private _loaderQueue: Promise<void> = Promise.resolve();\n\n /**\n * Create and initialize a headless SDK instance.\n * @param initData Configurator id plus optional canvas size and global init fields.\n * @returns Initialized SDK instance.\n */\n public static async create(\n initData: HeadlessInitData,\n ): Promise<HeadlessRoomleSdk> {\n const instance = new HeadlessRoomleSdk();\n await instance._init(initData);\n return instance;\n }\n\n private async _init(initData: HeadlessInitData) {\n this._width = initData.width ?? 1024;\n this._height = initData.height ?? 768;\n\n installHeadlessTweenStub();\n\n // Register headless service overrides BEFORE the DI container initializes.\n // This monkey-patches Container so that headless overrides always win,\n // even after boot() re-registers the default INJECTABLES.\n this._registerHeadlessServices(this._width, this._height);\n\n await RoomleSdk.setGlobalInitData({\n configuratorId: initData.configuratorId,\n locale: initData.locale,\n // @ts-ignore -- tenant is untyped, but we still need it.\n tenant: initData.tenant,\n overrideCountry: initData.overrideCountry,\n animateCamera: false,\n });\n\n this._initialized = true;\n }\n\n private _registerHeadlessServices(width: number, height: number) {\n // Create the DI container early. When roomle-dependency-injection.ts is\n // later loaded transitively, its _ensureContainer() checks if __RML__DI__\n // already exists and skips creating a new one — so we must register the\n // full INJECTABLES here ourselves.\n const container = new Container();\n (globalThis as any).__RML__DI__ = container;\n\n // Capture width/height in a subclass so the DI container instantiates\n // HeadlessDomHelper with the correct dimensions (DI only passes `creator`).\n class SizedHeadlessDomHelper extends HeadlessDomHelper {\n constructor(creator: string) {\n super(creator, width, height);\n }\n }\n\n // override: true marks each key so that subsequent boot() calls that\n // re-register the default INJECTABLES cannot overwrite these entries.\n const headlessOverrides = [\n new DependencyInjectionAssignment(\n 'script-loader',\n HeadlessScriptLoader,\n DI_TYPE.CONTEXT,\n true,\n ),\n new DependencyInjectionAssignment(\n 'dom-helper',\n SizedHeadlessDomHelper,\n DI_TYPE.CONTEXT,\n true,\n ),\n new DependencyInjectionAssignment(\n 'data-syncer',\n HeadlessDataSyncer,\n DI_TYPE.GLOBAL,\n true,\n ),\n new DependencyInjectionAssignment(\n 'planner-kernel-access',\n HeadlessPlannerKernelAccess,\n DI_TYPE.GLOBAL,\n true,\n ),\n new DependencyInjectionAssignment(\n 'kernel-callback-guard',\n HeadlessKernelCallbackGuard,\n DI_TYPE.GLOBAL,\n true,\n ),\n ];\n\n // Register defaults first, then overlay headless overrides.\n // The override: true flag on each headless entry prevents later boot() calls\n // from overwriting them when they re-register the default INJECTABLES.\n container.addDependencyInjectionAssignments(INJECTABLES);\n container.addDependencyInjectionAssignments(headlessOverrides);\n }\n\n private _makeStubElement() {\n return {\n clientWidth: this._width,\n clientHeight: this._height,\n appendChild() {},\n removeChild() {},\n style: {},\n classList: { add() {} },\n };\n }\n\n /**\n * Boot and initialize the configurator module ahead of first load.\n * @param initData Optional per-module init overrides.\n */\n public async prewarmConfigurator(\n initData?: Partial<InitDataDefinition>,\n ): Promise<void> {\n this._ensureInitialized();\n const configuratorModule = await RoomleSdk.getConfigurator(initData);\n await configuratorModule.boot();\n this._configuratorMain = configuratorModule;\n this._configurator = configuratorModule.getApi();\n await this._configurator.init(this._makeStubElement() as any);\n this._configuratorReady = true;\n }\n\n /**\n * Boot and initialize the planner module ahead of first load.\n * @param initData Optional per-module init overrides.\n */\n public async prewarmPlanner(\n initData?: Partial<InitDataDefinition>,\n ): Promise<void> {\n this._ensureInitialized();\n const plannerModule = await RoomleSdk.getPlanner({\n moc: true,\n ...initData,\n });\n if (initData?.moc === false) {\n throw new Error('HeadlessRoomleSdk: planner requires moc:true');\n }\n await plannerModule.boot();\n this._plannerMain = plannerModule;\n this._planner = plannerModule.getApi();\n await this._planner.init(this._makeStubElement() as any);\n this._plannerReady = true;\n }\n\n /**\n * Boot and initialize the GLB viewer module ahead of first load.\n * @param initData Optional per-module init overrides.\n */\n public async prewarmGlbViewer(\n initData?: Partial<InitDataDefinition>,\n ): Promise<void> {\n this._ensureInitialized();\n const glbModule = await RoomleSdk.getGlbViewer(initData);\n await glbModule.boot();\n this._glbViewerMain = glbModule;\n this._glbViewer = glbModule.getApi();\n await this._glbViewer.init(this._makeStubElement() as any);\n this._glbViewerReady = true;\n }\n\n /**\n * Load a saved configuration via the RAPI `/configurations/` endpoint.\n * @param configurationId Multi-segment id like `catalog:item:HASH`.\n * @param initData Optional per-module init overrides for prewarm.\n */\n public async loadConfiguration(\n configurationId: RapiId,\n initData?: Partial<InitDataDefinition>,\n ): Promise<void> {\n return this._loadIntoConfigurator(\n configurationId,\n (id) => this._configurator.loadConfigurationById(id),\n initData,\n );\n }\n\n /**\n * Load a configurable item via the RAPI `/items/` endpoint.\n * @param itemId Single-segment id like `catalog:item`.\n * @param initData Optional per-module init overrides for prewarm.\n */\n public async loadConfigurableItemById(\n itemId: RapiId,\n initData?: Partial<InitDataDefinition>,\n ): Promise<void> {\n return this._loadIntoConfigurator(\n itemId,\n (id) => this._configurator.loadConfigurableItemById(id),\n initData,\n );\n }\n\n private async _loadIntoConfigurator(\n id: RapiId,\n load: (id: RapiId) => Promise<unknown>,\n initData?: Partial<InitDataDefinition>,\n ): Promise<void> {\n this._ensureInitialized();\n return this._withLoader(async () => {\n if (!this._configuratorReady) {\n await this.prewarmConfigurator(initData);\n }\n if (this._loadedConfigurationId === id) {\n return;\n }\n // Temporarily remove the planner view model from PKA listeners so it\n // doesn't process configurator kernel callbacks (avoids listener\n // cross-contamination when both configurator and planner are pre-warmed).\n const { pka, plannerVM } = this._plannerReady\n ? this._getPlannerListenerInfo()\n : {};\n if (pka && plannerVM) {\n pka.removeConfiguratorListener(plannerVM);\n }\n try {\n await this._armOnReadyForRender();\n await load(id);\n this._loadedConfigurationId = id;\n this._loadedPlanId = null;\n this._loadedStaticItemId = null;\n await this._settleScene();\n } finally {\n if (pka && plannerVM) {\n pka.addConfiguratorListener(plannerVM);\n }\n }\n });\n }\n\n /**\n * Load a static (non-configurable) item via the GLB viewer.\n * @param staticItemId Catalog item id whose RAPI record has no `configuration`.\n * @param initData Optional per-module init overrides for prewarm.\n */\n public async loadStaticItem(\n staticItemId: string,\n initData?: Partial<InitDataDefinition>,\n ): Promise<void> {\n this._ensureInitialized();\n return this._withLoader(async () => {\n if (!this._glbViewerReady) {\n await this.prewarmGlbViewer(initData);\n }\n if (this._loadedStaticItemId === staticItemId) {\n return;\n }\n await this._armOnReadyForRender();\n await this._glbViewer.loadStaticItem(staticItemId);\n this._suppressGlbSelfShadowing();\n this._loadedStaticItemId = staticItemId;\n this._loadedConfigurationId = null;\n this._loadedPlanId = null;\n await this._settleScene();\n });\n }\n\n /**\n * Temporary workaround:\n * GLB-loaded scenes commonly contain hundreds of thousands of triangles\n * (high-poly furniture/cars). With the default 1024² shadow map those\n * triangles cast a self-shadow pattern back onto themselves that the\n * shadow comparison can't resolve cleanly — it appears as a dense\n * triangle/herringbone overlay covering every PBR-shaded surface\n * (visible on flat-coloured car bodies, wood slats, etc.). The\n * artifact is specific to headless's GL backend; in the browser the\n * same scene renders fine.\n *\n * Walking the freshly-loaded scene and clearing `castShadow` on every\n * mesh removes the cause of the acne while keeping `receiveShadow`,\n * so static items still pick up shadows from external casters and\n * full PBR direct-light shading is preserved.\n */\n private _suppressGlbSelfShadowing(): void {\n const sceneManager = this._glbViewer.getSceneManager();\n const root = sceneManager.getScene();\n\n if (!root) {\n return;\n }\n\n root.traverse((node) => {\n if ((node as Mesh).isMesh) {\n (node as Mesh).castShadow = false;\n }\n });\n }\n\n /**\n * Auto-dispatch by id shape using the shared id-inferrer utilities so\n * detection stays in lock-step with the UI's `SdkConnector.loadObject`:\n * - `component@…` → not supported in headless, throws\n * - 0 colons (plan id) → {@link loadPlan}\n * - 1 colon (item id) → {@link loadStaticItem} if RAPI says the\n * item has no `configuration`, otherwise\n * {@link loadConfigurableItemById}\n * - 2+ colons (config id) → {@link loadConfiguration}\n *\n * RAPI lookup failures during the item branch are propagated rather than\n * swallowed — a transient 5xx routing the call to the wrong loader would\n * surface as an unrelated downstream error.\n */\n async loadObject(\n id: string,\n initData?: Partial<InitDataDefinition>,\n ): Promise<void> {\n this._ensureInitialized();\n if (isIdAComponent(id)) {\n throw new Error(\n `HeadlessRoomleSdk: component ids (\"${id}\") are not supported. Use loadConfigurableItemById, loadConfiguration, or loadPlan directly.`,\n );\n }\n if (isIdAPlan(id)) {\n return this.loadPlan(id, initData);\n }\n if (isIdAnItem(id)) {\n const rapi = await RoomleSdk.getRapiAccess();\n const item = await rapi.getItem(id as RapiId);\n const isStatic = !item?.configuration;\n if (isStatic) {\n return this.loadStaticItem(id, initData);\n }\n return this.loadConfigurableItemById(id as RapiId, initData);\n }\n return this.loadConfiguration(id as RapiId, initData);\n }\n\n /**\n * Load a plan into the planner.\n * @param planId Plan id (no colons).\n * @param initData Optional per-module init overrides for prewarm.\n */\n async loadPlan(\n planId: string,\n initData?: Partial<InitDataDefinition>,\n ): Promise<void> {\n this._ensureInitialized();\n return this._withLoader(async () => {\n if (!this._plannerReady) {\n await this.prewarmPlanner(initData);\n }\n // Skip reload if the same plan is already loaded.\n if (this._loadedPlanId === planId) {\n return;\n }\n // Temporarily remove the configurator view model from PKA listeners so it\n // doesn't process planner kernel callbacks.\n const { pka, configuratorVM } = this._configuratorReady\n ? this._getConfiguratorListenerInfo()\n : {};\n if (pka && configuratorVM) {\n pka.removeConfiguratorListener(configuratorVM);\n }\n try {\n await this._armOnReadyForRender();\n await this._planner.loadPlan(planId);\n this._loadedPlanId = planId;\n // A freshly-loaded plan scene invalidates any previously-loaded configuration.\n this._loadedConfigurationId = null;\n this._loadedStaticItemId = null;\n await this._settleScene();\n } finally {\n if (pka && configuratorVM) {\n pka.addConfiguratorListener(configuratorVM);\n }\n }\n });\n }\n\n /**\n * Serialises concurrent load operations using a promise-chain queue.\n * Each call chains its task onto the previous queue tail so they run\n * one at a time — listener mutations never overlap across an await.\n * Errors in one task do not stall subsequent ones (the queue tail is\n * always advanced in a settled state).\n */\n private _withLoader<T>(task: () => Promise<T>): Promise<T> {\n const next = this._loaderQueue.then(task);\n // Advance the queue unconditionally so a failing task never blocks\n // future callers.\n this._loaderQueue = next.then(\n () => {},\n () => {},\n );\n return next;\n }\n\n /**\n * Wait for the active scene to fire its onReadyForRender callback —\n * fired by each scene manager once `_itemsLoaded` (planner) /\n * `loadConfiguration` (configurator) / `loadStaticItem` (GLB viewer)\n * has finished constructing the scene and queued its materials. The\n * callback is armed via {@link _armOnReadyForRender} *before* the load\n * begins so synchronous firings (the GLB viewer does this) are still\n * caught.\n */\n private async _settleScene(): Promise<void> {\n if (!this._onReadyForRenderArmed) {\n return;\n }\n await this._onReadyForRenderArmed;\n this._onReadyForRenderArmed = null;\n }\n\n /**\n * Pre-arms an onReadyForRender listener on the *global* callback (shared\n * across configurator/planner/GLB viewer) so that it captures even\n * synchronous firings during the upcoming load. Restores the previous\n * callback after firing. Using the global callback rather than each\n * module's api.callbacks is necessary because the GLB viewer only fires\n * the global one ([glb-viewer-scene-manager.ts:355](packages/web-sdk/packages/glb-viewer-core/src/webgl/glb-viewer-scene-manager.ts:355)).\n */\n private async _armOnReadyForRender(): Promise<void> {\n const globalCallback = (await RoomleSdk.callbacks) as unknown as {\n onReadyForRender?: () => void;\n };\n if (!globalCallback) {\n this._onReadyForRenderArmed = null;\n return;\n }\n const previous = globalCallback.onReadyForRender;\n this._onReadyForRenderArmed = new Promise<void>((resolve) => {\n globalCallback.onReadyForRender = () => {\n try {\n previous?.();\n } finally {\n globalCallback.onReadyForRender = previous;\n resolve();\n }\n };\n });\n }\n\n private _onReadyForRenderArmed: Promise<void> | null = null;\n\n private _getPlannerListenerInfo() {\n try {\n const pka = (globalThis as any).__RML__DI__?.lookup?.(\n 'planner-kernel-access',\n );\n const plannerVM = this._planner?.getSceneManager()?.viewModel;\n return { pka, plannerVM };\n } catch {\n return {};\n }\n }\n\n private _getConfiguratorListenerInfo() {\n try {\n const pka = (globalThis as any).__RML__DI__?.lookup?.(\n 'planner-kernel-access',\n );\n const configuratorVM = this._configurator?.getSceneManager()?.viewModel;\n return { pka, configuratorVM };\n } catch {\n return {};\n }\n }\n\n /**\n * Export the active scene as GLB.\n * @param outputPath Optional file path to write the buffer to.\n * @returns The GLB bytes as an ArrayBuffer.\n */\n async exportGLB(outputPath?: string): Promise<ExportResult> {\n return this._export(outputPath, 'glb');\n }\n\n /**\n * Export the active scene as USDZ.\n * @param outputPath Optional file path to write the buffer to.\n * @returns The USDZ bytes as an ArrayBuffer.\n */\n async exportUSDZ(outputPath?: string): Promise<ExportResult> {\n return this._export(outputPath, 'usdz');\n }\n\n /**\n * Returns the active top-level API (planner or configurator) based on what\n * was last loaded. `loadPlan()` and `loadConfiguration()` are mutually\n * exclusive — each one nulls the other's id — so this resolves cleanly.\n */\n private _getActiveApi():\n | RoomlePlanner\n | RoomleConfigurator\n | RoomleGLBViewer {\n if (this._loadedPlanId) {\n return this._planner;\n }\n if (this._loadedConfigurationId) {\n return this._configurator;\n }\n if (this._loadedStaticItemId) {\n return this._glbViewer;\n }\n throw new Error(\n 'HeadlessRoomleSdk: nothing loaded — call loadPlan(), loadConfiguration(), loadConfigurableItemById(), loadStaticItem() or loadObject() first',\n );\n }\n\n /**\n * Returns the scene manager of whichever module is active. All exporters\n * route through here so plan-mode and config-mode share a single code path.\n */\n private _getActiveSceneManager() {\n if (this._loadedStaticItemId) {\n // The GLB viewer doesn't expose a sceneManager getter; reach into the\n // private field. The methods we use here (createExportGLB,\n // createUSDZExport, exportCanvasScreenshot) are shared with the\n // configurator/planner scene managers.\n return this._glbViewer.getSceneManager();\n }\n return this._getActiveApi().getSceneManager();\n }\n\n private async _export(\n outputPath: string | undefined,\n type: 'glb' | 'usdz',\n ): Promise<ExportResult> {\n this._ensureInitialized();\n\n const activeSceneManager = this._getActiveSceneManager();\n const buffer =\n type === 'glb'\n ? await activeSceneManager.createExportGLB()\n : await activeSceneManager.createUSDZExport();\n\n if (!buffer) {\n throw new Error(`${type.toUpperCase()} export produced no data`);\n }\n\n // The buffer is either ArrayBuffer (GLB) or Uint8Array (USDZ).\n // Extract the underlying ArrayBuffer in both cases.\n const arrayBuffer =\n buffer instanceof ArrayBuffer\n ? buffer\n : ((buffer as Uint8Array).buffer as ArrayBuffer);\n\n if (outputPath) {\n const fs = await import('fs');\n fs.writeFileSync(outputPath, Buffer.from(arrayBuffer));\n }\n\n return { buffer: arrayBuffer };\n }\n\n /**\n * Render a perspective screenshot preserving the scene background.\n * @param outputPath Optional file path to write the PNG to.\n * @param options ssaa, size, quality, rotationY.\n * @returns Data URL of the rendered image.\n */\n public async exportScreenshot(\n outputPath?: string,\n options: ScreenshotExportOptions = {},\n ): Promise<{ dataUrl: string }> {\n this._ensureInitialized();\n\n // Reuse the deterministic preparePerspectiveImage pipeline — it clones\n // the live camera and frames it synchronously off the bounding box,\n // sidestepping the zoomToFitBounds tween race that the previous\n // exportCanvasScreenshot path suffered from. The only behavioural\n // difference vs. exportPerspectiveImage is preserveSceneBackground:true,\n // so the scene's sky/floor/skybox stays visible.\n const ssaa = options.ssaa ?? 2;\n const targetSize = options.size ?? 1024;\n const renderSize = targetSize * ssaa;\n\n const result = await this._getActiveApi().preparePerspectiveImage({\n rotationY: options.rotationY,\n size: renderSize,\n preserveSceneBackground: true,\n });\n\n let dataUrl = result.image;\n if (ssaa > 1) {\n dataUrl = await this._ssaaDownscale(dataUrl, targetSize, targetSize);\n }\n\n if (outputPath) {\n const fs = await import('fs');\n const base64 = dataUrl.replace(/^data:image\\/\\w+;base64,/, '');\n fs.writeFileSync(outputPath, Buffer.from(base64, 'base64'));\n }\n\n return { dataUrl };\n }\n\n /**\n * Render a framed perspective image of the scene.\n * @param outputPath Optional file path to write the PNG to.\n * @param options ssaa, size, showDimensions, rotationY.\n * @returns Data URL plus final image dimensions.\n */\n public async exportPerspectiveImage(\n outputPath?: string,\n options: PerspectiveImageExportOptions = {},\n ): Promise<{ dataUrl: string; width: number; height: number }> {\n this._ensureInitialized();\n\n const ssaa = options.ssaa ?? 2;\n const targetSize = options.size ?? 1024;\n const renderSize = targetSize * ssaa;\n\n const result = await this._getActiveApi().preparePerspectiveImage({\n ...options,\n size: renderSize,\n });\n\n let finalDataUrl = result.image;\n let finalWidth = result.width;\n let finalHeight = result.height;\n\n // Downscale with SSAA if rendering at higher resolution, achieves antialiasing effect.\n if (ssaa > 1) {\n finalDataUrl = await this._ssaaDownscale(\n finalDataUrl,\n targetSize,\n targetSize,\n );\n finalWidth = targetSize;\n finalHeight = targetSize;\n }\n\n if (outputPath) {\n const fs = await import('fs');\n const base64 = finalDataUrl.replace(/^data:image\\/\\w+;base64,/, '');\n fs.writeFileSync(outputPath, Buffer.from(base64, 'base64'));\n }\n\n return { dataUrl: finalDataUrl, width: finalWidth, height: finalHeight };\n }\n\n /**\n * Render a top-down image of the scene. Not supported for static items.\n * @param outputPath Optional file path to write the PNG to.\n * @param options ssaa, size, showDimensions.\n * @returns Data URL plus final image dimensions.\n */\n public async exportTopImage(\n outputPath?: string,\n options: TopImageExportOptions = {},\n ): Promise<{ dataUrl: string; width: number; height: number }> {\n this._ensureInitialized();\n\n if (this._loadedStaticItemId) {\n throw new Error(\n 'HeadlessRoomleSdk: exportTopImage is not supported for static items',\n );\n }\n const api = this._getActiveApi() as RoomlePlanner | RoomleConfigurator;\n\n const ssaa = options.ssaa ?? 2;\n const result = await api.prepareTopImage({\n ...options,\n size: (options.size ?? 1024) * ssaa,\n showDimensions: options.showDimensions ?? false,\n });\n\n let finalDataUrl = result.image;\n let finalWidth = result.width;\n let finalHeight = result.height;\n\n if (ssaa > 1) {\n const targetWidth = Math.round(finalWidth / ssaa);\n const targetHeight = Math.round(finalHeight / ssaa);\n finalDataUrl = await this._ssaaDownscale(\n finalDataUrl,\n targetWidth,\n targetHeight,\n );\n finalWidth = targetWidth;\n finalHeight = targetHeight;\n }\n\n if (outputPath) {\n const fs = await import('fs');\n const base64 = finalDataUrl.replace(/^data:image\\/\\w+;base64,/, '');\n fs.writeFileSync(outputPath, Buffer.from(base64, 'base64'));\n }\n\n return { dataUrl: finalDataUrl, width: finalWidth, height: finalHeight };\n }\n\n /** Downscale a data URL image to target dimensions using high-quality filtering. */\n private async _ssaaDownscale(\n dataUrl: string,\n targetWidth: number,\n targetHeight: number,\n ): Promise<string> {\n const { createCanvas, loadImage } = await import('@napi-rs/canvas');\n const imgBuffer = Buffer.from(\n dataUrl.replace(/^data:image\\/\\w+;base64,/, ''),\n 'base64',\n );\n const img = await loadImage(imgBuffer);\n const outCanvas = createCanvas(targetWidth, targetHeight);\n const ctx = outCanvas.getContext('2d');\n (ctx as any).imageSmoothingEnabled = true;\n (ctx as any).imageSmoothingQuality = 'high';\n ctx.drawImage(img, 0, 0, targetWidth, targetHeight);\n return outCanvas.toDataURL('image/png');\n }\n\n getConfiguratorApi() {\n return this._configurator;\n }\n\n getPlannerApi() {\n return this._planner;\n }\n\n /** Destroy any prewarmed configurator, planner, and GLB viewer modules. */\n public async destroy() {\n if (this._configuratorMain) {\n this._configuratorMain.destroy();\n }\n if (this._plannerMain) {\n this._plannerMain.destroy();\n }\n if (this._glbViewerMain) {\n this._glbViewerMain.destroy();\n }\n }\n\n private _ensureInitialized() {\n if (!this._initialized) {\n throw new Error(\n 'HeadlessRoomleSdk not initialized. Call HeadlessRoomleSdk.create() first.',\n );\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"roomle-headless.js","names":[],"sources":["../../packages/headless-core/src/headless-script-loader.ts","../../packages/headless-core/src/stubs.ts","../../packages/headless-core/src/headless-dom-helper.ts","../../packages/headless-core/src/headless-data-syncer.ts","../../packages/headless-core/src/headless-planner-kernel-access.ts","../../packages/headless-core/src/headless-kernel-callback-guard.ts","../../packages/headless-core/src/headless-tween-stub.ts","../../../common/src/utils/id-inferrer.ts","../../packages/headless-core/src/headless-sdk.ts"],"sourcesContent":["/**\n * Replaces the browser ScriptLoader for headless mode.\n * Instead of injecting <script> tags, directly imports the Emscripten JS modules.\n */\nimport { createRequire } from 'module';\nimport type { Context } from '../../common-core/src/di/context';\nimport { getHeadlessWasmPath } from '../../common-core/src/static-files/roomle-core';\n\n// createRequire is needed because the Emscripten kernel files are CommonJS\n// and must be loaded synchronously\nconst _require = createRequire(import.meta.url);\n\nlet _idCache: { [key: string]: boolean } = {};\n\n// Maps a .wasm filename found in the Emscripten factory's source to its global name.\n// Each Emscripten factory references its own .wasm file (e.g. ConfiguratorKernel.wasm).\nconst WASM_TO_GLOBAL: Array<\n [wasmFile: string, globalName: string, modulePath: string]\n> = [\n [\n 'ConfiguratorKernel.wasm',\n 'ConfiguratorKernel',\n 'roomle-core-hsc/wasm_modern/ConfiguratorKernel.js',\n ],\n [\n 'RoomleCore.wasm',\n 'RoomleCore',\n 'roomle-core-hsc/wasm_modern/RoomleCore.js',\n ],\n [\n 'RoomleToolsCore.wasm',\n 'RoomleToolsCore',\n 'roomle-core-hsc/wasm_modern/RoomleToolsCore.js',\n ],\n];\n\nexport default class HeadlessScriptLoader implements Context {\n public _creator_: string;\n\n constructor(creator: string) {\n this._creator_ = creator;\n }\n\n public async fetch(url: string, options: { id: string }) {\n if (_idCache[options.id]) {\n return;\n }\n\n // In Bun, Vite's ?no-inline?url imports resolve to the module's default\n // export (a function) rather than a URL string. Handle both cases.\n if (typeof url === 'function') {\n this._registerFactory(url);\n _idCache[options.id] = true;\n return;\n }\n\n const entry = this._resolveEntry(url);\n if (entry) {\n const [, globalName, modulePath] = entry;\n // If url is an absolute filesystem path (from getHeadlessWasmPath),\n // require it directly. Otherwise fall back to the module specifier\n // (works from source where roomle-core-hsc is in node_modules).\n const pathToLoad = url.startsWith('/') ? url : modulePath;\n const mod = _require(pathToLoad);\n (globalThis as any)[globalName] = mod.default || mod;\n _idCache[options.id] = true;\n }\n }\n\n // Identify an Emscripten factory function by checking its source for the\n // unique .wasm filename it references, then register it on globalThis\n // under the name the kernel-access classes expect (e.g. window.ConfiguratorKernel).\n private _registerFactory(factory: () => void) {\n const source = factory.toString();\n for (const [wasmFile, globalName] of WASM_TO_GLOBAL) {\n if (source.includes(wasmFile)) {\n (globalThis as any)[globalName] = factory;\n return;\n }\n }\n console.warn(\n 'HeadlessScriptLoader: Could not identify Emscripten factory function',\n );\n }\n\n private _resolveEntry(url: string) {\n for (const entry of WASM_TO_GLOBAL) {\n const [wasmFile, globalName] = entry;\n const baseName = globalName; // e.g. \"ConfiguratorKernel\"\n if (url.includes(baseName) || url.includes(wasmFile)) {\n return entry;\n }\n }\n // Fallback: looser matching for generic URLs\n if (url.includes('configurator')) {\n return WASM_TO_GLOBAL[0];\n }\n if (url.includes('planner')) {\n return WASM_TO_GLOBAL[1];\n }\n if (url.includes('tools')) {\n return WASM_TO_GLOBAL[2];\n }\n console.warn(\n `HeadlessScriptLoader: Could not resolve module for URL: ${url}`,\n );\n return null;\n }\n\n public loadScripts(scripts: Array<{ id: string; name: string }>) {\n const promises = scripts.map((script) =>\n this.fetch(script.name, { id: script.id }),\n );\n return Promise.all(promises);\n }\n\n public resolveKernelPaths(type: 'configurator' | 'planner' | 'tools'): {\n wasm: string;\n loader: string;\n } {\n return getHeadlessWasmPath(type);\n }\n\n public cleanUp() {\n _idCache = {};\n }\n}\n","export const noop = () => {};\n","/**\n * Stub DomHelper for headless mode.\n * Returns fixed dimensions since we don't render to a real canvas.\n */\nimport { Vector2 } from 'three';\nimport { noop } from './stubs';\nimport type {\n LifeCycleCallbacks,\n LifeCycleManager,\n} from '../../common-core/src/life-cycle-manager';\nimport type { Context } from '../../common-core/src/di/context';\n\nexport default class HeadlessDomHelper implements LifeCycleCallbacks, Context {\n public _creator_: string;\n\n // Manual DI lookup instead of @inject decorator (avoids legacy/TC39 decorator mismatch)\n private get _lifeCycleManager(): LifeCycleManager | undefined {\n return (globalThis as any).__RML__DI__?.lookup(\n 'life-cycle-manager',\n this._creator_,\n );\n }\n\n private _width: number;\n private _height: number;\n private _stubElement: any;\n\n get element(): any {\n return this._stubElement;\n }\n\n constructor(creator: string, width = 1024, height = 768) {\n this._creator_ = creator;\n this._width = width;\n this._height = height;\n\n const w = this._width;\n const h = this._height;\n this._stubElement = {\n clientWidth: w,\n clientHeight: h,\n appendChild() {},\n removeChild() {},\n style: {},\n classList: {\n add() {},\n remove() {},\n contains() {\n return false;\n },\n },\n setAttribute() {},\n getAttribute(): string | null {\n return null;\n },\n children: [] as any[],\n getBoundingClientRect() {\n return {\n x: 0,\n y: 0,\n width: w,\n height: h,\n top: 0,\n left: 0,\n bottom: h,\n right: w,\n };\n },\n addEventListener() {},\n removeEventListener() {},\n dispatchEvent() {\n return true;\n },\n offsetWidth: w,\n offsetHeight: h,\n scrollWidth: w,\n scrollHeight: h,\n contains() {\n return false;\n },\n };\n }\n\n public setDomElement(_element: any) {\n noop();\n }\n\n public getClientDimensions() {\n return new Vector2(this._width, this._height);\n }\n\n public getAspectRatio() {\n return this._width / this._height;\n }\n\n public ensureCanvasFocus() {}\n public reset() {}\n public pause() {}\n public resume() {}\n public destroy() {}\n}\n","/**\n * Replaces the Worker-based DataSyncer with a no-op for headless mode.\n * In headless mode, assets are loaded on-demand via RapiAccess rather than\n * being pre-synced with a Web Worker.\n */\nimport type { RapiId } from '@roomle/web-sdk';\nimport { noop } from './stubs';\nimport type { Context } from '../../common-core/src/di/context';\n\nexport default class HeadlessDataSyncer implements Context {\n public _creator_: string;\n\n constructor(creator: string) {\n this._creator_ = creator;\n }\n\n public start(_catalogId: RapiId) {\n return Promise.resolve();\n }\n\n public syncCatalog(_catalogId: RapiId): Promise<void> {\n return Promise.resolve();\n }\n\n public syncFloorTag(_tagId: RapiId) {\n return Promise.resolve();\n }\n\n public syncTypeChangeTag(_tagId: RapiId) {\n return Promise.resolve();\n }\n\n public _syncTypeChangeTag(_tagId: RapiId): Promise<any> {\n return Promise.resolve();\n }\n\n public getIsCatalogSynced(_catalogId: RapiId) {\n return false;\n }\n\n public onCommand(_command: number, _conversationId: number, _data: any) {\n noop();\n }\n\n public requestAsset(url: string, _urlAsFallback: boolean = false): string {\n return url;\n }\n\n public setAlwaysUseCache(_alwaysUseCache: boolean): void {\n noop();\n }\n\n public preFillAssetCache(_key: string, _url: string) {\n noop();\n }\n}\n","/**\n * Headless override of `PlannerKernelAccess`.\n */\nimport { KERNEL_TYPE } from '../../common-core/src/services/common-kernel-access';\nimport PlannerKernelAccess from '../../planner-core/src/services/planner-kernel-access';\n\nexport default class HeadlessPlannerKernelAccess extends PlannerKernelAccess {\n protected _getScriptLoaderKernelId(kernelType: KERNEL_TYPE): string {\n return kernelType === KERNEL_TYPE.PLANNER ? 'kernel-planner' : 'kernel';\n }\n}\n","import type { KernelCallbackGuard } from '../../common-core/src/services/kernel-callback-guard';\n\n/**\n * Headless implementation: wraps the kernel callback target in a Proxy so that\n * any JS exception thrown inside a callback invoked from C++ (via Embind) is\n * caught and logged rather than propagating into C++, which would call\n * std::terminate and abort the process.\n */\nexport default class HeadlessKernelCallbackGuard\n implements KernelCallbackGuard\n{\n wrap<T extends object>(target: T): T {\n return new Proxy(target, {\n get(t: any, prop) {\n const val = t[prop];\n if (typeof val === 'function') {\n return function (...args: any[]) {\n try {\n return val.apply(t, args);\n } catch (e) {\n console.error(\n `[Headless] Kernel callback '${String(prop)}' threw:`,\n e,\n );\n }\n };\n }\n return val;\n },\n });\n }\n}\n","// Prevents tween effects from happening in headless mode, we don't ever want\n// things to fade in or out headlessly because it creates delays and causes\n// elements to show up white or half-visible as they tween in while taking a screenshot.\n\ninterface MinimalTween {\n end?: () => void;\n}\n\ninterface MinimalTweenGroup {\n add(tween: MinimalTween): void;\n remove(_tween: MinimalTween): void;\n removeAll(): void;\n getAll(): MinimalTween[];\n update(_time?: number): void;\n}\n\nconst noopGroup: MinimalTweenGroup = {\n add(tween) {\n // Synchronously fast-forward. Wrapped in try/catch so a single\n // misbehaving tween can't poison the whole queue — at worst that\n // tween silently doesn't apply, exactly as in browser mode if it\n // never advances.\n try {\n tween.end?.();\n } catch {\n // ignore\n }\n },\n remove() {},\n removeAll() {},\n getAll() {\n return [];\n },\n update() {},\n};\n\nexport const installHeadlessTweenStub = (): void => {\n const target = window as unknown as { TWEEN?: MinimalTweenGroup };\n // Always overwrite — if a previous SDK boot left the real Group here,\n // we want our noop in its place for the new instance.\n target.TWEEN = noopGroup;\n};\n","import type { RapiId, RapiPlanSnapshotId } from '@roomle/web-sdk';\n\nexport const isIdAnItem = (id: string) => id.split(':').length - 1 === 1;\n\nexport const isIdAPlan = (id: string) => id.split(':').length - 1 <= 0;\n\nexport const isIdAComponent = (id: string) =>\n id ? id.startsWith('component@') : false;\n\nexport const isIdAConfigurationString = (id: string) =>\n id.startsWith('{') && id.endsWith('}');\n\nexport const isPlanSnapshotId = (\n id: string | RapiId,\n): id is RapiPlanSnapshotId => id.startsWith('ps_');\n","/**\n * Main entry point for the headless Roomle SDK.\n * Provides the ability to run the Roomle web-sdk in Node.js/Bun\n * for loading configurations/plans and exporting them to GLB/USDZ.\n */\nimport HeadlessScriptLoader from './headless-script-loader';\nimport HeadlessDomHelper from './headless-dom-helper';\nimport HeadlessDataSyncer from './headless-data-syncer';\nimport HeadlessPlannerKernelAccess from './headless-planner-kernel-access';\nimport HeadlessKernelCallbackGuard from './headless-kernel-callback-guard';\nimport { installHeadlessTweenStub } from './headless-tween-stub';\nimport type {\n RoomlePlanner,\n Planner,\n RoomleConfigurator,\n Configurator,\n InitDataDefinition,\n GlobalInitDataDefinition,\n RapiId,\n GlbViewer,\n RoomleGLBViewer,\n} from '../../index';\nimport { RoomleSdk } from '../../index';\nimport {\n Container,\n DependencyInjectionAssignment,\n DI_TYPE,\n} from '../../common-core/src/di/container';\nimport { INJECTABLES } from '../../common-core/src/di/injectables';\nimport {\n isIdAComponent,\n isIdAPlan,\n isIdAnItem,\n} from '#/common/src/utils/id-inferrer';\nimport type { Mesh } from 'three';\n\nexport interface HeadlessInitData\n extends Partial<InitDataDefinition>,\n Partial<GlobalInitDataDefinition> {\n configuratorId: string;\n /** Canvas width in pixels. Defaults to 1024. */\n width?: number;\n /** Canvas height in pixels. Defaults to 768. */\n height?: number;\n}\n\nexport interface ExportResult {\n buffer: ArrayBuffer;\n}\n\nexport interface ImageExportOptions {\n /** Supersampling anti-aliasing factor. Defaults to 2. */\n ssaa?: number;\n /** Output image size in pixels. Defaults to 1024. */\n size?: number;\n}\n\n/** Mixin for image exports that frame the scene from a rotatable camera. */\nexport interface RotatableImageExportOptions {\n /** Camera rotation around the Y axis, in radians. */\n rotationY?: number;\n}\n\nexport interface ScreenshotExportOptions\n extends ImageExportOptions,\n RotatableImageExportOptions {\n /** JPEG quality (0–1). Defaults to 1. */\n quality?: number;\n}\n\nexport interface PerspectiveImageExportOptions\n extends ImageExportOptions,\n RotatableImageExportOptions {\n showDimensions?: boolean;\n}\n\nexport interface TopImageExportOptions extends ImageExportOptions {\n showDimensions?: boolean;\n}\n\nexport class HeadlessRoomleSdk {\n private _planner: RoomlePlanner;\n private _plannerMain: Planner;\n private _configurator: RoomleConfigurator;\n private _configuratorMain: Configurator;\n private _glbViewer: RoomleGLBViewer;\n private _glbViewerMain: GlbViewer;\n private _initialized = false;\n private _configuratorReady = false;\n private _plannerReady = false;\n private _glbViewerReady = false;\n private _loadedConfigurationId: RapiId | null = null;\n private _loadedPlanId: string | null = null;\n private _loadedStaticItemId: string | null = null;\n private _width = 1024;\n private _height = 768;\n private _loaderQueue: Promise<void> = Promise.resolve();\n\n /**\n * Create and initialize a headless SDK instance.\n * @param initData Configurator id plus optional canvas size and global init fields.\n * @returns Initialized SDK instance.\n */\n public static async create(\n initData: HeadlessInitData,\n ): Promise<HeadlessRoomleSdk> {\n const instance = new HeadlessRoomleSdk();\n await instance._init(initData);\n return instance;\n }\n\n private async _init(initData: HeadlessInitData) {\n this._width = initData.width ?? 1024;\n this._height = initData.height ?? 768;\n\n installHeadlessTweenStub();\n\n // Register headless service overrides BEFORE the DI container initializes.\n // This monkey-patches Container so that headless overrides always win,\n // even after boot() re-registers the default INJECTABLES.\n this._registerHeadlessServices(this._width, this._height);\n\n await RoomleSdk.setGlobalInitData({\n configuratorId: initData.configuratorId,\n locale: initData.locale,\n // @ts-ignore -- tenant is untyped, but we still need it.\n tenant: initData.tenant,\n overrideCountry: initData.overrideCountry,\n animateCamera: false,\n });\n\n this._initialized = true;\n }\n\n private _registerHeadlessServices(width: number, height: number) {\n // Create the DI container early. When roomle-dependency-injection.ts is\n // later loaded transitively, its _ensureContainer() checks if __RML__DI__\n // already exists and skips creating a new one — so we must register the\n // full INJECTABLES here ourselves.\n const container = new Container();\n (globalThis as any).__RML__DI__ = container;\n\n // Capture width/height in a subclass so the DI container instantiates\n // HeadlessDomHelper with the correct dimensions (DI only passes `creator`).\n class SizedHeadlessDomHelper extends HeadlessDomHelper {\n constructor(creator: string) {\n super(creator, width, height);\n }\n }\n\n // override: true marks each key so that subsequent boot() calls that\n // re-register the default INJECTABLES cannot overwrite these entries.\n const headlessOverrides = [\n new DependencyInjectionAssignment(\n 'script-loader',\n HeadlessScriptLoader,\n DI_TYPE.CONTEXT,\n true,\n ),\n new DependencyInjectionAssignment(\n 'dom-helper',\n SizedHeadlessDomHelper,\n DI_TYPE.CONTEXT,\n true,\n ),\n new DependencyInjectionAssignment(\n 'data-syncer',\n HeadlessDataSyncer,\n DI_TYPE.GLOBAL,\n true,\n ),\n new DependencyInjectionAssignment(\n 'planner-kernel-access',\n HeadlessPlannerKernelAccess,\n DI_TYPE.GLOBAL,\n true,\n ),\n new DependencyInjectionAssignment(\n 'kernel-callback-guard',\n HeadlessKernelCallbackGuard,\n DI_TYPE.GLOBAL,\n true,\n ),\n ];\n\n // Register defaults first, then overlay headless overrides.\n // The override: true flag on each headless entry prevents later boot() calls\n // from overwriting them when they re-register the default INJECTABLES.\n container.addDependencyInjectionAssignments(INJECTABLES);\n container.addDependencyInjectionAssignments(headlessOverrides);\n }\n\n private _makeStubElement() {\n return {\n clientWidth: this._width,\n clientHeight: this._height,\n appendChild() {},\n removeChild() {},\n style: {},\n classList: { add() {} },\n };\n }\n\n /**\n * Boot and initialize the configurator module ahead of first load.\n * @param initData Optional per-module init overrides.\n */\n public async prewarmConfigurator(\n initData?: Partial<InitDataDefinition>,\n ): Promise<void> {\n this._ensureInitialized();\n const configuratorModule = await RoomleSdk.getConfigurator(initData);\n await configuratorModule.boot();\n this._configuratorMain = configuratorModule;\n this._configurator = configuratorModule.getApi();\n await this._configurator.init(this._makeStubElement() as any);\n this._configuratorReady = true;\n }\n\n /**\n * Boot and initialize the planner module ahead of first load.\n * @param initData Optional per-module init overrides.\n */\n public async prewarmPlanner(\n initData?: Partial<InitDataDefinition>,\n ): Promise<void> {\n this._ensureInitialized();\n const plannerModule = await RoomleSdk.getPlanner({\n moc: true,\n ...initData,\n });\n if (initData?.moc === false) {\n throw new Error('HeadlessRoomleSdk: planner requires moc:true');\n }\n await plannerModule.boot();\n this._plannerMain = plannerModule;\n this._planner = plannerModule.getApi();\n await this._planner.init(this._makeStubElement() as any);\n this._plannerReady = true;\n }\n\n /**\n * Boot and initialize the GLB viewer module ahead of first load.\n * @param initData Optional per-module init overrides.\n */\n public async prewarmGlbViewer(\n initData?: Partial<InitDataDefinition>,\n ): Promise<void> {\n this._ensureInitialized();\n const glbModule = await RoomleSdk.getGlbViewer(initData);\n await glbModule.boot();\n this._glbViewerMain = glbModule;\n this._glbViewer = glbModule.getApi();\n await this._glbViewer.init(this._makeStubElement() as any);\n this._glbViewerReady = true;\n }\n\n /**\n * Load a saved configuration via the RAPI `/configurations/` endpoint.\n * @param configurationId Multi-segment id like `catalog:item:HASH`.\n * @param initData Optional per-module init overrides for prewarm.\n */\n public async loadConfiguration(\n configurationId: RapiId,\n initData?: Partial<InitDataDefinition>,\n ): Promise<void> {\n return this._loadIntoConfigurator(\n configurationId,\n (id) => this._configurator.loadConfigurationById(id),\n initData,\n );\n }\n\n /**\n * Load a configurable item via the RAPI `/items/` endpoint.\n * @param itemId Single-segment id like `catalog:item`.\n * @param initData Optional per-module init overrides for prewarm.\n */\n public async loadConfigurableItemById(\n itemId: RapiId,\n initData?: Partial<InitDataDefinition>,\n ): Promise<void> {\n return this._loadIntoConfigurator(\n itemId,\n (id) => this._configurator.loadConfigurableItemById(id),\n initData,\n );\n }\n\n private async _loadIntoConfigurator(\n id: RapiId,\n load: (id: RapiId) => Promise<unknown>,\n initData?: Partial<InitDataDefinition>,\n ): Promise<void> {\n this._ensureInitialized();\n return this._withLoader(async () => {\n if (!this._configuratorReady) {\n await this.prewarmConfigurator(initData);\n }\n if (this._loadedConfigurationId === id) {\n return;\n }\n // Temporarily remove the planner view model from PKA listeners so it\n // doesn't process configurator kernel callbacks (avoids listener\n // cross-contamination when both configurator and planner are pre-warmed).\n const { pka, plannerVM } = this._plannerReady\n ? this._getPlannerListenerInfo()\n : {};\n if (pka && plannerVM) {\n pka.removeConfiguratorListener(plannerVM);\n }\n try {\n await this._armOnReadyForRender();\n await load(id);\n this._loadedConfigurationId = id;\n this._loadedPlanId = null;\n this._loadedStaticItemId = null;\n await this._settleScene();\n } finally {\n if (pka && plannerVM) {\n pka.addConfiguratorListener(plannerVM);\n }\n }\n });\n }\n\n /**\n * Load a static (non-configurable) item via the GLB viewer.\n * @param staticItemId Catalog item id whose RAPI record has no `configuration`.\n * @param initData Optional per-module init overrides for prewarm.\n */\n public async loadStaticItem(\n staticItemId: string,\n initData?: Partial<InitDataDefinition>,\n ): Promise<void> {\n this._ensureInitialized();\n return this._withLoader(async () => {\n if (!this._glbViewerReady) {\n await this.prewarmGlbViewer(initData);\n }\n if (this._loadedStaticItemId === staticItemId) {\n return;\n }\n await this._armOnReadyForRender();\n await this._glbViewer.loadStaticItem(staticItemId);\n this._suppressGlbSelfShadowing();\n this._loadedStaticItemId = staticItemId;\n this._loadedConfigurationId = null;\n this._loadedPlanId = null;\n await this._settleScene();\n });\n }\n\n /**\n * Temporary workaround:\n * GLB-loaded scenes commonly contain hundreds of thousands of triangles\n * (high-poly furniture/cars). With the default 1024² shadow map those\n * triangles cast a self-shadow pattern back onto themselves that the\n * shadow comparison can't resolve cleanly — it appears as a dense\n * triangle/herringbone overlay covering every PBR-shaded surface\n * (visible on flat-coloured car bodies, wood slats, etc.). The\n * artifact is specific to headless's GL backend; in the browser the\n * same scene renders fine.\n *\n * Walking the freshly-loaded scene and clearing `castShadow` on every\n * mesh removes the cause of the acne while keeping `receiveShadow`,\n * so static items still pick up shadows from external casters and\n * full PBR direct-light shading is preserved.\n */\n private _suppressGlbSelfShadowing(): void {\n const sceneManager = this._glbViewer.getSceneManager();\n const root = sceneManager.getScene();\n\n if (!root) {\n return;\n }\n\n root.traverse((node) => {\n if ((node as Mesh).isMesh) {\n (node as Mesh).castShadow = false;\n }\n });\n }\n\n /**\n * Auto-dispatch by id shape using the shared id-inferrer utilities so\n * detection stays in lock-step with the UI's `SdkConnector.loadObject`:\n * - `component@…` → not supported in headless, throws\n * - 0 colons (plan id) → {@link loadPlan}\n * - 1 colon (item id) → {@link loadStaticItem} if RAPI says the\n * item has no `configuration`, otherwise\n * {@link loadConfigurableItemById}\n * - 2+ colons (config id) → {@link loadConfiguration}\n *\n * RAPI lookup failures during the item branch are propagated rather than\n * swallowed — a transient 5xx routing the call to the wrong loader would\n * surface as an unrelated downstream error.\n */\n async loadObject(\n id: string,\n initData?: Partial<InitDataDefinition>,\n ): Promise<void> {\n this._ensureInitialized();\n if (isIdAComponent(id)) {\n throw new Error(\n `HeadlessRoomleSdk: component ids (\"${id}\") are not supported. Use loadConfigurableItemById, loadConfiguration, or loadPlan directly.`,\n );\n }\n if (isIdAPlan(id)) {\n return this.loadPlan(id, initData);\n }\n if (isIdAnItem(id)) {\n const rapi = await RoomleSdk.getRapiAccess();\n const item = await rapi.getItem(id as RapiId);\n const isStatic = !item?.configuration;\n if (isStatic) {\n return this.loadStaticItem(id, initData);\n }\n return this.loadConfigurableItemById(id as RapiId, initData);\n }\n return this.loadConfiguration(id as RapiId, initData);\n }\n\n /**\n * Load a plan into the planner.\n * @param planId Plan id (no colons).\n * @param initData Optional per-module init overrides for prewarm.\n */\n async loadPlan(\n planId: string,\n initData?: Partial<InitDataDefinition>,\n ): Promise<void> {\n this._ensureInitialized();\n return this._withLoader(async () => {\n if (!this._plannerReady) {\n await this.prewarmPlanner(initData);\n }\n // Skip reload if the same plan is already loaded.\n if (this._loadedPlanId === planId) {\n return;\n }\n // Temporarily remove the configurator view model from PKA listeners so it\n // doesn't process planner kernel callbacks.\n const { pka, configuratorVM } = this._configuratorReady\n ? this._getConfiguratorListenerInfo()\n : {};\n if (pka && configuratorVM) {\n pka.removeConfiguratorListener(configuratorVM);\n }\n try {\n await this._armOnReadyForRender();\n await this._planner.loadPlan(planId);\n this._loadedPlanId = planId;\n // A freshly-loaded plan scene invalidates any previously-loaded configuration.\n this._loadedConfigurationId = null;\n this._loadedStaticItemId = null;\n await this._settleScene();\n } finally {\n if (pka && configuratorVM) {\n pka.addConfiguratorListener(configuratorVM);\n }\n }\n });\n }\n\n /**\n * Serialises concurrent load operations using a promise-chain queue.\n * Each call chains its task onto the previous queue tail so they run\n * one at a time — listener mutations never overlap across an await.\n * Errors in one task do not stall subsequent ones (the queue tail is\n * always advanced in a settled state).\n */\n private _withLoader<T>(task: () => Promise<T>): Promise<T> {\n const next = this._loaderQueue.then(task);\n // Advance the queue unconditionally so a failing task never blocks\n // future callers.\n this._loaderQueue = next.then(\n () => {},\n () => {},\n );\n return next;\n }\n\n /**\n * Wait for the active scene to fire its onReadyForRender callback —\n * fired by each scene manager once `_itemsLoaded` (planner) /\n * `loadConfiguration` (configurator) / `loadStaticItem` (GLB viewer)\n * has finished constructing the scene and queued its materials. The\n * callback is armed via {@link _armOnReadyForRender} *before* the load\n * begins so synchronous firings (the GLB viewer does this) are still\n * caught.\n */\n private async _settleScene(): Promise<void> {\n if (!this._onReadyForRenderArmed) {\n return;\n }\n await this._onReadyForRenderArmed;\n this._onReadyForRenderArmed = null;\n }\n\n /**\n * Pre-arms an onReadyForRender listener on the *global* callback (shared\n * across configurator/planner/GLB viewer) so that it captures even\n * synchronous firings during the upcoming load. Restores the previous\n * callback after firing. Using the global callback rather than each\n * module's api.callbacks is necessary because the GLB viewer only fires\n * the global one ([glb-viewer-scene-manager.ts:355](packages/web-sdk/packages/glb-viewer-core/src/webgl/glb-viewer-scene-manager.ts:355)).\n */\n private async _armOnReadyForRender(): Promise<void> {\n const globalCallback = (await RoomleSdk.callbacks) as unknown as {\n onReadyForRender?: () => void;\n };\n if (!globalCallback) {\n this._onReadyForRenderArmed = null;\n return;\n }\n const previous = globalCallback.onReadyForRender;\n this._onReadyForRenderArmed = new Promise<void>((resolve) => {\n globalCallback.onReadyForRender = () => {\n try {\n previous?.();\n } finally {\n globalCallback.onReadyForRender = previous;\n resolve();\n }\n };\n });\n }\n\n private _onReadyForRenderArmed: Promise<void> | null = null;\n\n private _getPlannerListenerInfo() {\n try {\n const pka = (globalThis as any).__RML__DI__?.lookup?.(\n 'planner-kernel-access',\n );\n const plannerVM = this._planner?.getSceneManager()?.viewModel;\n return { pka, plannerVM };\n } catch {\n return {};\n }\n }\n\n private _getConfiguratorListenerInfo() {\n try {\n const pka = (globalThis as any).__RML__DI__?.lookup?.(\n 'planner-kernel-access',\n );\n const configuratorVM = this._configurator?.getSceneManager()?.viewModel;\n return { pka, configuratorVM };\n } catch {\n return {};\n }\n }\n\n /**\n * Export the active scene as GLB.\n * @param outputPath Optional file path to write the buffer to.\n * @returns The GLB bytes as an ArrayBuffer.\n */\n async exportGLB(outputPath?: string): Promise<ExportResult> {\n return this._export(outputPath, 'glb');\n }\n\n /**\n * Export the active scene as USDZ.\n * @param outputPath Optional file path to write the buffer to.\n * @returns The USDZ bytes as an ArrayBuffer.\n */\n async exportUSDZ(outputPath?: string): Promise<ExportResult> {\n return this._export(outputPath, 'usdz');\n }\n\n /**\n * Returns the active top-level API (planner or configurator) based on what\n * was last loaded. `loadPlan()` and `loadConfiguration()` are mutually\n * exclusive — each one nulls the other's id — so this resolves cleanly.\n */\n private _getActiveApi():\n | RoomlePlanner\n | RoomleConfigurator\n | RoomleGLBViewer {\n if (this._loadedPlanId) {\n return this._planner;\n }\n if (this._loadedConfigurationId) {\n return this._configurator;\n }\n if (this._loadedStaticItemId) {\n return this._glbViewer;\n }\n throw new Error(\n 'HeadlessRoomleSdk: nothing loaded — call loadPlan(), loadConfiguration(), loadConfigurableItemById(), loadStaticItem() or loadObject() first',\n );\n }\n\n /**\n * Returns the scene manager of whichever module is active. All exporters\n * route through here so plan-mode and config-mode share a single code path.\n */\n private _getActiveSceneManager() {\n if (this._loadedStaticItemId) {\n // The GLB viewer doesn't expose a sceneManager getter; reach into the\n // private field. The methods we use here (createExportGLB,\n // createUSDZExport, exportCanvasScreenshot) are shared with the\n // configurator/planner scene managers.\n return this._glbViewer.getSceneManager();\n }\n return this._getActiveApi().getSceneManager();\n }\n\n private async _export(\n outputPath: string | undefined,\n type: 'glb' | 'usdz',\n ): Promise<ExportResult> {\n this._ensureInitialized();\n\n const activeSceneManager = this._getActiveSceneManager();\n const buffer =\n type === 'glb'\n ? await activeSceneManager.createExportGLB()\n : await activeSceneManager.createUSDZExport();\n\n if (!buffer) {\n throw new Error(`${type.toUpperCase()} export produced no data`);\n }\n\n // The buffer is either ArrayBuffer (GLB) or Uint8Array (USDZ).\n // Extract the underlying ArrayBuffer in both cases.\n const arrayBuffer =\n buffer instanceof ArrayBuffer\n ? buffer\n : ((buffer as Uint8Array).buffer as ArrayBuffer);\n\n if (outputPath) {\n const fs = await import('fs');\n fs.writeFileSync(outputPath, Buffer.from(arrayBuffer));\n }\n\n return { buffer: arrayBuffer };\n }\n\n /**\n * Render a perspective screenshot preserving the scene background.\n * @param outputPath Optional file path to write the PNG to.\n * @param options ssaa, size, quality, rotationY.\n * @returns Data URL of the rendered image.\n */\n public async exportScreenshot(\n outputPath?: string,\n options: ScreenshotExportOptions = {},\n ): Promise<{ dataUrl: string }> {\n this._ensureInitialized();\n\n // Reuse the deterministic preparePerspectiveImage pipeline — it clones\n // the live camera and frames it synchronously off the bounding box,\n // sidestepping the zoomToFitBounds tween race that the previous\n // exportCanvasScreenshot path suffered from. The only behavioural\n // difference vs. exportPerspectiveImage is preserveSceneBackground:true,\n // so the scene's sky/floor/skybox stays visible.\n const ssaa = options.ssaa ?? 2;\n const targetSize = options.size ?? 1024;\n const renderSize = targetSize * ssaa;\n\n const result = await this._getActiveApi().preparePerspectiveImage({\n rotationY: options.rotationY,\n size: renderSize,\n preserveSceneBackground: true,\n });\n\n let dataUrl = result.image;\n if (ssaa > 1) {\n dataUrl = await this._ssaaDownscale(dataUrl, targetSize, targetSize);\n }\n\n if (outputPath) {\n const fs = await import('fs');\n const base64 = dataUrl.replace(/^data:image\\/\\w+;base64,/, '');\n fs.writeFileSync(outputPath, Buffer.from(base64, 'base64'));\n }\n\n return { dataUrl };\n }\n\n /**\n * Render a framed perspective image of the scene.\n * @param outputPath Optional file path to write the PNG to.\n * @param options ssaa, size, showDimensions, rotationY.\n * @returns Data URL plus final image dimensions.\n */\n public async exportPerspectiveImage(\n outputPath?: string,\n options: PerspectiveImageExportOptions = {},\n ): Promise<{ dataUrl: string; width: number; height: number }> {\n this._ensureInitialized();\n\n const ssaa = options.ssaa ?? 2;\n const targetSize = options.size ?? 1024;\n const renderSize = targetSize * ssaa;\n\n const result = await this._getActiveApi().preparePerspectiveImage({\n ...options,\n size: renderSize,\n });\n\n let finalDataUrl = result.image;\n let finalWidth = result.width;\n let finalHeight = result.height;\n\n // Downscale with SSAA if rendering at higher resolution, achieves antialiasing effect.\n if (ssaa > 1) {\n finalDataUrl = await this._ssaaDownscale(\n finalDataUrl,\n targetSize,\n targetSize,\n );\n finalWidth = targetSize;\n finalHeight = targetSize;\n }\n\n if (outputPath) {\n const fs = await import('fs');\n const base64 = finalDataUrl.replace(/^data:image\\/\\w+;base64,/, '');\n fs.writeFileSync(outputPath, Buffer.from(base64, 'base64'));\n }\n\n return { dataUrl: finalDataUrl, width: finalWidth, height: finalHeight };\n }\n\n /**\n * Render a top-down image of the scene. Not supported for static items.\n * @param outputPath Optional file path to write the PNG to.\n * @param options ssaa, size, showDimensions.\n * @returns Data URL plus final image dimensions.\n */\n public async exportTopImage(\n outputPath?: string,\n options: TopImageExportOptions = {},\n ): Promise<{ dataUrl: string; width: number; height: number }> {\n this._ensureInitialized();\n\n if (this._loadedStaticItemId) {\n throw new Error(\n 'HeadlessRoomleSdk: exportTopImage is not supported for static items',\n );\n }\n const api = this._getActiveApi() as RoomlePlanner | RoomleConfigurator;\n\n const ssaa = options.ssaa ?? 2;\n const result = await api.prepareTopImage({\n ...options,\n size: (options.size ?? 1024) * ssaa,\n showDimensions: options.showDimensions ?? false,\n });\n\n let finalDataUrl = result.image;\n let finalWidth = result.width;\n let finalHeight = result.height;\n\n if (ssaa > 1) {\n const targetWidth = Math.round(finalWidth / ssaa);\n const targetHeight = Math.round(finalHeight / ssaa);\n finalDataUrl = await this._ssaaDownscale(\n finalDataUrl,\n targetWidth,\n targetHeight,\n );\n finalWidth = targetWidth;\n finalHeight = targetHeight;\n }\n\n if (outputPath) {\n const fs = await import('fs');\n const base64 = finalDataUrl.replace(/^data:image\\/\\w+;base64,/, '');\n fs.writeFileSync(outputPath, Buffer.from(base64, 'base64'));\n }\n\n return { dataUrl: finalDataUrl, width: finalWidth, height: finalHeight };\n }\n\n /** Downscale a data URL image to target dimensions using high-quality filtering. */\n private async _ssaaDownscale(\n dataUrl: string,\n targetWidth: number,\n targetHeight: number,\n ): Promise<string> {\n const { createCanvas, loadImage } = await import('@napi-rs/canvas');\n const imgBuffer = Buffer.from(\n dataUrl.replace(/^data:image\\/\\w+;base64,/, ''),\n 'base64',\n );\n const img = await loadImage(imgBuffer);\n const outCanvas = createCanvas(targetWidth, targetHeight);\n const ctx = outCanvas.getContext('2d');\n (ctx as any).imageSmoothingEnabled = true;\n (ctx as any).imageSmoothingQuality = 'high';\n ctx.drawImage(img, 0, 0, targetWidth, targetHeight);\n return outCanvas.toDataURL('image/png');\n }\n\n getConfiguratorApi() {\n return this._configurator;\n }\n\n getPlannerApi() {\n return this._planner;\n }\n\n /** Destroy any prewarmed configurator, planner, and GLB viewer modules. */\n public async destroy() {\n if (this._configuratorMain) {\n this._configuratorMain.destroy();\n }\n if (this._plannerMain) {\n this._plannerMain.destroy();\n }\n if (this._glbViewerMain) {\n this._glbViewerMain.destroy();\n }\n }\n\n private _ensureInitialized() {\n if (!this._initialized) {\n throw new Error(\n 'HeadlessRoomleSdk not initialized. Call HeadlessRoomleSdk.create() first.',\n );\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as e } from "./three.core-
|
|
1
|
+
import { d as e } from "./three.core-DNErG1F6.mjs";
|
|
2
2
|
//#region packages/common-core/src/roomle-renderer.ts
|
|
3
3
|
var t = /* @__PURE__ */ function(e) {
|
|
4
4
|
return e[e.Mode3D = 0] = "Mode3D", e[e.Mode2D = 1] = "Mode2D", e;
|
|
@@ -46,4 +46,4 @@ var t = /* @__PURE__ */ function(e) {
|
|
|
46
46
|
//#endregion
|
|
47
47
|
export { n, t };
|
|
48
48
|
|
|
49
|
-
//# sourceMappingURL=roomle-renderer-
|
|
49
|
+
//# sourceMappingURL=roomle-renderer-CkSFbpmg.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roomle-renderer-
|
|
1
|
+
{"version":3,"file":"roomle-renderer-CkSFbpmg.mjs","names":[],"sources":["../../packages/common-core/src/roomle-renderer.ts"],"sourcesContent":["import type { Camera, Object3D, Scene, Vector2, WebGLRenderer } from 'three';\nimport { Box3 } from 'three';\nimport type { Enumify } from '#/common/src/utils/types';\nimport type { CAMERA_TYPE } from './cameracontrol/camera-type';\nimport type { WebGPURenderer } from 'three/webgpu';\nimport type {\n CustomShadingParameters,\n SceneShadingType,\n} from './webgl/renderer/shading-settings';\nimport type {\n LutImageDefinition,\n OutlineCustomParameters,\n QualityLevel,\n QualityMap,\n} from './webgl/renderer/scene-renderer';\n\nexport type GenericRoomleRenderer = RoomleRenderer<\n WebGLRenderer | WebGPURenderer\n>;\n\nexport enum PlannerRenderMode {\n Mode3D,\n Mode2D,\n}\n\nexport abstract class RoomleRenderer<\n RendererType extends WebGLRenderer | WebGPURenderer,\n> {\n public _creator_: string;\n public renderer: RendererType;\n protected isConfiguratorMode: boolean = true;\n protected isCameraMoving: boolean = false;\n protected cameraType: Enumify<typeof CAMERA_TYPE>;\n protected shadowNeedsUpdate: boolean = false;\n protected boundingBox: Box3 = new Box3();\n protected boundingBoxNeedsUpdate: boolean = false;\n\n protected constructor(creator: string, renderer: RendererType) {\n this._creator_ = creator;\n this.renderer = renderer;\n }\n\n public get isConfiguring(): boolean {\n return this.isConfiguratorMode;\n }\n\n public dispose(): void {\n this.renderer.dispose();\n }\n\n public setSize(width: number, height: number): void {\n this.renderer.setSize(width, height);\n }\n\n public getSize(target: Vector2): Vector2 {\n return this.renderer.getSize(target);\n }\n\n public setCameraType(cameraType: Enumify<typeof CAMERA_TYPE>) {\n this.cameraType = cameraType;\n }\n\n public movingCameraStarts(): void {\n this.isCameraMoving = true;\n }\n\n public movingCameraStops(): void {\n this.isCameraMoving = false;\n }\n\n public forceShadowUpdates(_updateBakedGroundShadow: boolean): void {\n this.shadowNeedsUpdate = true;\n }\n\n public clear() {\n this.renderer.clear();\n }\n\n public updateBounds(geometryBounds: Box3) {\n this.boundingBox.copy(geometryBounds);\n this.boundingBoxNeedsUpdate = true;\n }\n\n public switchToConfigurator(): void {\n this.isConfiguratorMode = true;\n }\n\n public switchToPlanner(_renderMode: PlannerRenderMode) {\n this.isConfiguratorMode = false;\n }\n\n public abstract setShadingType(shadingType: SceneShadingType): void;\n\n public abstract setAutoQuality(autoQuality: boolean): void;\n\n public abstract setQualityLevel(qualityLevel: QualityLevel): void;\n\n public abstract getQualityLevel(): QualityLevel;\n\n public abstract setQualityMap(qualityMap: QualityMap): void;\n\n public abstract setCustomShadingParameters(\n customShadingParameters?: CustomShadingParameters,\n customShadingParametersMoc?: CustomShadingParameters,\n ): void;\n\n public abstract setCustomOutlineParameters(\n outlineCustomParameters: OutlineCustomParameters,\n ): void;\n\n public abstract loadLutImages(luts: LutImageDefinition[]): void;\n\n public abstract render(scene: Scene, camera: Camera): void;\n\n public abstract showGUI(updateCallback: () => void): void;\n\n public abstract setOnQualityLevelChangeCallback(\n callback: (qualityLevel: QualityLevel) => void,\n ): void;\n\n public abstract clearCache(): void;\n\n public abstract highlightObjects(selectedMeshes: Object3D[]): void;\n\n public abstract setGroundShadow(enabled: boolean, scene: Scene): void;\n\n public abstract enableUiInteractionMode(): void;\n\n public abstract disableUiInteractionMode(): void;\n}\n"],"mappings":";;AAoBA,IAAY,IAAL,yBAAA,GAAA;QACL,EAAA,EAAA,SAAA,KAAA,UACA,EAAA,EAAA,SAAA,KAAA;KACD,EAEqB,IAAtB,MAEE;CAUA,YAAsB,GAAiB,GAAwB;AAE7D,4BATsC,0BACJ,6BAEG,uBACT,IAAI,GAAM,gCACI,IAG1C,KAAK,YAAY,GACjB,KAAK,WAAW;;CAGlB,IAAW,gBAAyB;AAClC,SAAO,KAAK;;CAGd,UAAuB;AACrB,OAAK,SAAS,SAAS;;CAGzB,QAAe,GAAe,GAAsB;AAClD,OAAK,SAAS,QAAQ,GAAO,EAAO;;CAGtC,QAAe,GAA0B;AACvC,SAAO,KAAK,SAAS,QAAQ,EAAO;;CAGtC,cAAqB,GAAyC;AAC5D,OAAK,aAAa;;CAGpB,qBAAkC;AAChC,OAAK,iBAAiB;;CAGxB,oBAAiC;AAC/B,OAAK,iBAAiB;;CAGxB,mBAA0B,GAAyC;AACjE,OAAK,oBAAoB;;CAG3B,QAAe;AACb,OAAK,SAAS,OAAO;;CAGvB,aAAoB,GAAsB;AAExC,EADA,KAAK,YAAY,KAAK,EAAe,EACrC,KAAK,yBAAyB;;CAGhC,uBAAoC;AAClC,OAAK,qBAAqB;;CAG5B,gBAAuB,GAAgC;AACrD,OAAK,qBAAqB"}
|