blockymodel-web 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/LICENSE +21 -0
  2. package/dist/blockymodel-web.js +2717 -0
  3. package/dist/blockymodel-web.js.map +1 -0
  4. package/dist/blockymodel-web.umd.cjs +122 -0
  5. package/dist/blockymodel-web.umd.cjs.map +1 -0
  6. package/dist/editor/Editor.d.ts +94 -0
  7. package/dist/editor/Editor.d.ts.map +1 -0
  8. package/dist/editor/History.d.ts +52 -0
  9. package/dist/editor/History.d.ts.map +1 -0
  10. package/dist/editor/SelectionManager.d.ts +57 -0
  11. package/dist/editor/SelectionManager.d.ts.map +1 -0
  12. package/dist/editor/Serializer.d.ts +44 -0
  13. package/dist/editor/Serializer.d.ts.map +1 -0
  14. package/dist/editor/TransformManager.d.ts +73 -0
  15. package/dist/editor/TransformManager.d.ts.map +1 -0
  16. package/dist/editor/commands/AddNodeCommand.d.ts +24 -0
  17. package/dist/editor/commands/AddNodeCommand.d.ts.map +1 -0
  18. package/dist/editor/commands/Command.d.ts +50 -0
  19. package/dist/editor/commands/Command.d.ts.map +1 -0
  20. package/dist/editor/commands/RemoveNodeCommand.d.ts +28 -0
  21. package/dist/editor/commands/RemoveNodeCommand.d.ts.map +1 -0
  22. package/dist/editor/commands/SetPositionCommand.d.ts +24 -0
  23. package/dist/editor/commands/SetPositionCommand.d.ts.map +1 -0
  24. package/dist/editor/commands/SetPropertyCommand.d.ts +41 -0
  25. package/dist/editor/commands/SetPropertyCommand.d.ts.map +1 -0
  26. package/dist/editor/commands/SetRotationCommand.d.ts +24 -0
  27. package/dist/editor/commands/SetRotationCommand.d.ts.map +1 -0
  28. package/dist/editor/commands/SetScaleCommand.d.ts +24 -0
  29. package/dist/editor/commands/SetScaleCommand.d.ts.map +1 -0
  30. package/dist/editor/index.d.ts +15 -0
  31. package/dist/editor/index.d.ts.map +1 -0
  32. package/dist/index.d.ts +21 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/loaders/BlockyModelLoader.d.ts +48 -0
  35. package/dist/loaders/BlockyModelLoader.d.ts.map +1 -0
  36. package/dist/types/blockymodel.d.ts +72 -0
  37. package/dist/types/blockymodel.d.ts.map +1 -0
  38. package/dist/ui/HierarchyPanel.d.ts +73 -0
  39. package/dist/ui/HierarchyPanel.d.ts.map +1 -0
  40. package/dist/ui/PropertyPanel.d.ts +59 -0
  41. package/dist/ui/PropertyPanel.d.ts.map +1 -0
  42. package/dist/ui/UVEditor.d.ts +56 -0
  43. package/dist/ui/UVEditor.d.ts.map +1 -0
  44. package/dist/ui/index.d.ts +4 -0
  45. package/dist/ui/index.d.ts.map +1 -0
  46. package/dist/viewer/ViewerController.d.ts +71 -0
  47. package/dist/viewer/ViewerController.d.ts.map +1 -0
  48. package/package.json +63 -0
  49. package/src/editor/Editor.ts +196 -0
  50. package/src/editor/History.ts +123 -0
  51. package/src/editor/SelectionManager.ts +183 -0
  52. package/src/editor/Serializer.ts +212 -0
  53. package/src/editor/TransformManager.ts +270 -0
  54. package/src/editor/commands/AddNodeCommand.ts +53 -0
  55. package/src/editor/commands/Command.ts +63 -0
  56. package/src/editor/commands/RemoveNodeCommand.ts +59 -0
  57. package/src/editor/commands/SetPositionCommand.ts +51 -0
  58. package/src/editor/commands/SetPropertyCommand.ts +100 -0
  59. package/src/editor/commands/SetRotationCommand.ts +51 -0
  60. package/src/editor/commands/SetScaleCommand.ts +51 -0
  61. package/src/editor/index.ts +19 -0
  62. package/src/index.ts +49 -0
  63. package/src/loaders/BlockyModelLoader.ts +281 -0
  64. package/src/main.ts +290 -0
  65. package/src/styles.css +597 -0
  66. package/src/types/blockymodel.ts +82 -0
  67. package/src/ui/HierarchyPanel.ts +343 -0
  68. package/src/ui/PropertyPanel.ts +434 -0
  69. package/src/ui/UVEditor.ts +336 -0
  70. package/src/ui/index.ts +4 -0
  71. package/src/viewer/ViewerController.ts +295 -0
@@ -0,0 +1,2717 @@
1
+ var Wt = Object.defineProperty;
2
+ var Kt = (a, t, e) => t in a ? Wt(a, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : a[t] = e;
3
+ var r = (a, t, e) => Kt(a, typeof t != "symbol" ? t + "" : t, e);
4
+ import * as l from "three";
5
+ import { Controls as Ht, Vector3 as p, Quaternion as L, Raycaster as $t, Object3D as Mt, MeshBasicMaterial as Nt, LineBasicMaterial as Jt, CylinderGeometry as P, BoxGeometry as S, BufferGeometry as Pt, Float32BufferAttribute as It, Mesh as c, OctahedronGeometry as rt, Line as F, TorusGeometry as W, SphereGeometry as te, Euler as ee, Matrix4 as Ft, PlaneGeometry as ie, DoubleSide as se, MOUSE as G, TOUCH as V, Spherical as Tt, Vector2 as R, Ray as ne, Plane as oe, MathUtils as ae } from "three";
6
+ const re = 4491519, he = 0.3;
7
+ class le {
8
+ constructor(t) {
9
+ r(this, "editor");
10
+ r(this, "raycaster");
11
+ r(this, "mouse");
12
+ r(this, "selected", null);
13
+ r(this, "highlightedMaterials", /* @__PURE__ */ new Map());
14
+ r(this, "eventListeners", /* @__PURE__ */ new Map());
15
+ this.editor = t, this.raycaster = new l.Raycaster(), this.mouse = new l.Vector2(), this.handleClick = this.handleClick.bind(this), this.editor.domElement.addEventListener("click", this.handleClick);
16
+ }
17
+ /**
18
+ * Handle click events for selection
19
+ */
20
+ handleClick(t) {
21
+ if (t.target !== this.editor.renderer.domElement)
22
+ return;
23
+ const e = this.editor.domElement.getBoundingClientRect();
24
+ this.mouse.x = (t.clientX - e.left) / e.width * 2 - 1, this.mouse.y = -((t.clientY - e.top) / e.height) * 2 + 1, this.raycaster.setFromCamera(this.mouse, this.editor.camera);
25
+ const i = this.editor.getModel();
26
+ if (!i) {
27
+ this.deselect();
28
+ return;
29
+ }
30
+ const s = [];
31
+ i.traverse((n) => {
32
+ n instanceof l.Mesh && n.visible && (this.isTransformControlPart(n) || s.push(n));
33
+ });
34
+ const o = this.raycaster.intersectObjects(s, !1);
35
+ if (o.length > 0) {
36
+ let n = o[0].object;
37
+ for (; n.parent && !n.userData.id && n.parent !== i; )
38
+ n = n.parent;
39
+ this.select(n);
40
+ } else
41
+ this.deselect();
42
+ }
43
+ /**
44
+ * Check if object is part of TransformControls
45
+ */
46
+ isTransformControlPart(t) {
47
+ let e = t;
48
+ for (; e; ) {
49
+ if (e.type === "TransformControlsGizmo" || e.type === "TransformControlsPlane")
50
+ return !0;
51
+ e = e.parent;
52
+ }
53
+ return !1;
54
+ }
55
+ /**
56
+ * Select an object
57
+ */
58
+ select(t) {
59
+ t !== this.selected && (this.removeHighlight(), this.selected = t, t && this.applyHighlight(t), this.emit("selectionChanged", t));
60
+ }
61
+ /**
62
+ * Deselect current object
63
+ */
64
+ deselect() {
65
+ this.select(null);
66
+ }
67
+ /**
68
+ * Get currently selected object
69
+ */
70
+ getSelected() {
71
+ return this.selected;
72
+ }
73
+ /**
74
+ * Apply highlight effect to object
75
+ */
76
+ applyHighlight(t) {
77
+ t.traverse((e) => {
78
+ if (e instanceof l.Mesh) {
79
+ const i = e.material;
80
+ i.emissive && (this.highlightedMaterials.set(e, {
81
+ emissive: i.emissive.clone(),
82
+ emissiveIntensity: i.emissiveIntensity
83
+ }), i.emissive.setHex(re), i.emissiveIntensity = he);
84
+ }
85
+ });
86
+ }
87
+ /**
88
+ * Remove highlight effect
89
+ */
90
+ removeHighlight() {
91
+ this.highlightedMaterials.forEach((t, e) => {
92
+ const i = e.material;
93
+ i.emissive && (i.emissive.copy(t.emissive), i.emissiveIntensity = t.emissiveIntensity);
94
+ }), this.highlightedMaterials.clear();
95
+ }
96
+ /**
97
+ * Add event listener
98
+ */
99
+ on(t, e) {
100
+ this.eventListeners.has(t) || this.eventListeners.set(t, /* @__PURE__ */ new Set()), this.eventListeners.get(t).add(e);
101
+ }
102
+ /**
103
+ * Emit event
104
+ */
105
+ emit(t, ...e) {
106
+ var i;
107
+ (i = this.eventListeners.get(t)) == null || i.forEach((s) => s(e[0]));
108
+ }
109
+ /**
110
+ * Clean up
111
+ */
112
+ dispose() {
113
+ this.editor.domElement.removeEventListener("click", this.handleClick), this.removeHighlight(), this.eventListeners.clear();
114
+ }
115
+ }
116
+ const U = new $t(), x = new p(), X = new p(), g = new L(), Dt = {
117
+ X: new p(1, 0, 0),
118
+ Y: new p(0, 1, 0),
119
+ Z: new p(0, 0, 1)
120
+ }, gt = { type: "change" }, Ct = { type: "mouseDown", mode: null }, Lt = { type: "mouseUp", mode: null }, zt = { type: "objectChange" };
121
+ class ce extends Ht {
122
+ constructor(t, e = null) {
123
+ super(void 0, e);
124
+ const i = new ye(this);
125
+ this._root = i;
126
+ const s = new ge();
127
+ this._gizmo = s, i.add(s);
128
+ const o = new be();
129
+ this._plane = o, i.add(o);
130
+ const n = this;
131
+ function h(b, T) {
132
+ let k = T;
133
+ Object.defineProperty(n, b, {
134
+ get: function() {
135
+ return k !== void 0 ? k : T;
136
+ },
137
+ set: function(A) {
138
+ k !== A && (k = A, o[b] = A, s[b] = A, n.dispatchEvent({ type: b + "-changed", value: A }), n.dispatchEvent(gt));
139
+ }
140
+ }), n[b] = T, o[b] = T, s[b] = T;
141
+ }
142
+ h("camera", t), h("object", void 0), h("enabled", !0), h("axis", null), h("mode", "translate"), h("translationSnap", null), h("rotationSnap", null), h("scaleSnap", null), h("space", "world"), h("size", 1), h("dragging", !1), h("showX", !0), h("showY", !0), h("showZ", !0), h("minX", -1 / 0), h("maxX", 1 / 0), h("minY", -1 / 0), h("maxY", 1 / 0), h("minZ", -1 / 0), h("maxZ", 1 / 0);
143
+ const d = new p(), u = new p(), y = new L(), _ = new L(), D = new p(), yt = new L(), B = new p(), z = new p(), O = new p(), M = 0, E = new p();
144
+ h("worldPosition", d), h("worldPositionStart", u), h("worldQuaternion", y), h("worldQuaternionStart", _), h("cameraPosition", D), h("cameraQuaternion", yt), h("pointStart", B), h("pointEnd", z), h("rotationAxis", O), h("rotationAngle", M), h("eye", E), this._offset = new p(), this._startNorm = new p(), this._endNorm = new p(), this._cameraScale = new p(), this._parentPosition = new p(), this._parentQuaternion = new L(), this._parentQuaternionInv = new L(), this._parentScale = new p(), this._worldScaleStart = new p(), this._worldQuaternionInv = new L(), this._worldScale = new p(), this._positionStart = new p(), this._quaternionStart = new L(), this._scaleStart = new p(), this._getPointer = de.bind(this), this._onPointerDown = ue.bind(this), this._onPointerHover = pe.bind(this), this._onPointerMove = me.bind(this), this._onPointerUp = fe.bind(this), e !== null && this.connect();
145
+ }
146
+ connect() {
147
+ this.domElement.addEventListener("pointerdown", this._onPointerDown), this.domElement.addEventListener("pointermove", this._onPointerHover), this.domElement.addEventListener("pointerup", this._onPointerUp), this.domElement.style.touchAction = "none";
148
+ }
149
+ disconnect() {
150
+ this.domElement.removeEventListener("pointerdown", this._onPointerDown), this.domElement.removeEventListener("pointermove", this._onPointerHover), this.domElement.removeEventListener("pointermove", this._onPointerMove), this.domElement.removeEventListener("pointerup", this._onPointerUp), this.domElement.style.touchAction = "auto";
151
+ }
152
+ getHelper() {
153
+ return this._root;
154
+ }
155
+ pointerHover(t) {
156
+ if (this.object === void 0 || this.dragging === !0) return;
157
+ t !== null && U.setFromCamera(t, this.camera);
158
+ const e = bt(this._gizmo.picker[this.mode], U);
159
+ e ? this.axis = e.object.name : this.axis = null;
160
+ }
161
+ pointerDown(t) {
162
+ if (!(this.object === void 0 || this.dragging === !0 || t != null && t.button !== 0) && this.axis !== null) {
163
+ t !== null && U.setFromCamera(t, this.camera);
164
+ const e = bt(this._plane, U, !0);
165
+ e && (this.object.updateMatrixWorld(), this.object.parent.updateMatrixWorld(), this._positionStart.copy(this.object.position), this._quaternionStart.copy(this.object.quaternion), this._scaleStart.copy(this.object.scale), this.object.matrixWorld.decompose(this.worldPositionStart, this.worldQuaternionStart, this._worldScaleStart), this.pointStart.copy(e.point).sub(this.worldPositionStart)), this.dragging = !0, Ct.mode = this.mode, this.dispatchEvent(Ct);
166
+ }
167
+ }
168
+ pointerMove(t) {
169
+ const e = this.axis, i = this.mode, s = this.object;
170
+ let o = this.space;
171
+ if (i === "scale" ? o = "local" : (e === "E" || e === "XYZE" || e === "XYZ") && (o = "world"), s === void 0 || e === null || this.dragging === !1 || t !== null && t.button !== -1) return;
172
+ t !== null && U.setFromCamera(t, this.camera);
173
+ const n = bt(this._plane, U, !0);
174
+ if (n) {
175
+ if (this.pointEnd.copy(n.point).sub(this.worldPositionStart), i === "translate")
176
+ this._offset.copy(this.pointEnd).sub(this.pointStart), o === "local" && e !== "XYZ" && this._offset.applyQuaternion(this._worldQuaternionInv), e.indexOf("X") === -1 && (this._offset.x = 0), e.indexOf("Y") === -1 && (this._offset.y = 0), e.indexOf("Z") === -1 && (this._offset.z = 0), o === "local" && e !== "XYZ" ? this._offset.applyQuaternion(this._quaternionStart).divide(this._parentScale) : this._offset.applyQuaternion(this._parentQuaternionInv).divide(this._parentScale), s.position.copy(this._offset).add(this._positionStart), this.translationSnap && (o === "local" && (s.position.applyQuaternion(g.copy(this._quaternionStart).invert()), e.search("X") !== -1 && (s.position.x = Math.round(s.position.x / this.translationSnap) * this.translationSnap), e.search("Y") !== -1 && (s.position.y = Math.round(s.position.y / this.translationSnap) * this.translationSnap), e.search("Z") !== -1 && (s.position.z = Math.round(s.position.z / this.translationSnap) * this.translationSnap), s.position.applyQuaternion(this._quaternionStart)), o === "world" && (s.parent && s.position.add(x.setFromMatrixPosition(s.parent.matrixWorld)), e.search("X") !== -1 && (s.position.x = Math.round(s.position.x / this.translationSnap) * this.translationSnap), e.search("Y") !== -1 && (s.position.y = Math.round(s.position.y / this.translationSnap) * this.translationSnap), e.search("Z") !== -1 && (s.position.z = Math.round(s.position.z / this.translationSnap) * this.translationSnap), s.parent && s.position.sub(x.setFromMatrixPosition(s.parent.matrixWorld)))), s.position.x = Math.max(this.minX, Math.min(this.maxX, s.position.x)), s.position.y = Math.max(this.minY, Math.min(this.maxY, s.position.y)), s.position.z = Math.max(this.minZ, Math.min(this.maxZ, s.position.z));
177
+ else if (i === "scale") {
178
+ if (e.search("XYZ") !== -1) {
179
+ let h = this.pointEnd.length() / this.pointStart.length();
180
+ this.pointEnd.dot(this.pointStart) < 0 && (h *= -1), X.set(h, h, h);
181
+ } else
182
+ x.copy(this.pointStart), X.copy(this.pointEnd), x.applyQuaternion(this._worldQuaternionInv), X.applyQuaternion(this._worldQuaternionInv), X.divide(x), e.search("X") === -1 && (X.x = 1), e.search("Y") === -1 && (X.y = 1), e.search("Z") === -1 && (X.z = 1);
183
+ s.scale.copy(this._scaleStart).multiply(X), this.scaleSnap && (e.search("X") !== -1 && (s.scale.x = Math.round(s.scale.x / this.scaleSnap) * this.scaleSnap || this.scaleSnap), e.search("Y") !== -1 && (s.scale.y = Math.round(s.scale.y / this.scaleSnap) * this.scaleSnap || this.scaleSnap), e.search("Z") !== -1 && (s.scale.z = Math.round(s.scale.z / this.scaleSnap) * this.scaleSnap || this.scaleSnap));
184
+ } else if (i === "rotate") {
185
+ this._offset.copy(this.pointEnd).sub(this.pointStart);
186
+ const h = 20 / this.worldPosition.distanceTo(x.setFromMatrixPosition(this.camera.matrixWorld));
187
+ let d = !1;
188
+ e === "XYZE" ? (this.rotationAxis.copy(this._offset).cross(this.eye).normalize(), this.rotationAngle = this._offset.dot(x.copy(this.rotationAxis).cross(this.eye)) * h) : (e === "X" || e === "Y" || e === "Z") && (this.rotationAxis.copy(Dt[e]), x.copy(Dt[e]), o === "local" && x.applyQuaternion(this.worldQuaternion), x.cross(this.eye), x.length() === 0 ? d = !0 : this.rotationAngle = this._offset.dot(x.normalize()) * h), (e === "E" || d) && (this.rotationAxis.copy(this.eye), this.rotationAngle = this.pointEnd.angleTo(this.pointStart), this._startNorm.copy(this.pointStart).normalize(), this._endNorm.copy(this.pointEnd).normalize(), this.rotationAngle *= this._endNorm.cross(this._startNorm).dot(this.eye) < 0 ? 1 : -1), this.rotationSnap && (this.rotationAngle = Math.round(this.rotationAngle / this.rotationSnap) * this.rotationSnap), o === "local" && e !== "E" && e !== "XYZE" ? (s.quaternion.copy(this._quaternionStart), s.quaternion.multiply(g.setFromAxisAngle(this.rotationAxis, this.rotationAngle)).normalize()) : (this.rotationAxis.applyQuaternion(this._parentQuaternionInv), s.quaternion.copy(g.setFromAxisAngle(this.rotationAxis, this.rotationAngle)), s.quaternion.multiply(this._quaternionStart).normalize());
189
+ }
190
+ this.dispatchEvent(gt), this.dispatchEvent(zt);
191
+ }
192
+ }
193
+ pointerUp(t) {
194
+ t !== null && t.button !== 0 || (this.dragging && this.axis !== null && (Lt.mode = this.mode, this.dispatchEvent(Lt)), this.dragging = !1, this.axis = null);
195
+ }
196
+ dispose() {
197
+ this.disconnect(), this._root.dispose();
198
+ }
199
+ // Set current object
200
+ attach(t) {
201
+ return this.object = t, this._root.visible = !0, this;
202
+ }
203
+ // Detach from object
204
+ detach() {
205
+ return this.object = void 0, this.axis = null, this._root.visible = !1, this;
206
+ }
207
+ reset() {
208
+ this.enabled && this.dragging && (this.object.position.copy(this._positionStart), this.object.quaternion.copy(this._quaternionStart), this.object.scale.copy(this._scaleStart), this.dispatchEvent(gt), this.dispatchEvent(zt), this.pointStart.copy(this.pointEnd));
209
+ }
210
+ getRaycaster() {
211
+ return U;
212
+ }
213
+ // TODO: deprecate
214
+ getMode() {
215
+ return this.mode;
216
+ }
217
+ setMode(t) {
218
+ this.mode = t;
219
+ }
220
+ setTranslationSnap(t) {
221
+ this.translationSnap = t;
222
+ }
223
+ setRotationSnap(t) {
224
+ this.rotationSnap = t;
225
+ }
226
+ setScaleSnap(t) {
227
+ this.scaleSnap = t;
228
+ }
229
+ setSize(t) {
230
+ this.size = t;
231
+ }
232
+ setSpace(t) {
233
+ this.space = t;
234
+ }
235
+ }
236
+ function de(a) {
237
+ if (this.domElement.ownerDocument.pointerLockElement)
238
+ return {
239
+ x: 0,
240
+ y: 0,
241
+ button: a.button
242
+ };
243
+ {
244
+ const t = this.domElement.getBoundingClientRect();
245
+ return {
246
+ x: (a.clientX - t.left) / t.width * 2 - 1,
247
+ y: -(a.clientY - t.top) / t.height * 2 + 1,
248
+ button: a.button
249
+ };
250
+ }
251
+ }
252
+ function pe(a) {
253
+ if (this.enabled)
254
+ switch (a.pointerType) {
255
+ case "mouse":
256
+ case "pen":
257
+ this.pointerHover(this._getPointer(a));
258
+ break;
259
+ }
260
+ }
261
+ function ue(a) {
262
+ this.enabled && (document.pointerLockElement || this.domElement.setPointerCapture(a.pointerId), this.domElement.addEventListener("pointermove", this._onPointerMove), this.pointerHover(this._getPointer(a)), this.pointerDown(this._getPointer(a)));
263
+ }
264
+ function me(a) {
265
+ this.enabled && this.pointerMove(this._getPointer(a));
266
+ }
267
+ function fe(a) {
268
+ this.enabled && (this.domElement.releasePointerCapture(a.pointerId), this.domElement.removeEventListener("pointermove", this._onPointerMove), this.pointerUp(this._getPointer(a)));
269
+ }
270
+ function bt(a, t, e) {
271
+ const i = t.intersectObject(a, !0);
272
+ for (let s = 0; s < i.length; s++)
273
+ if (i[s].object.visible || e)
274
+ return i[s];
275
+ return !1;
276
+ }
277
+ const ht = new ee(), f = new p(0, 1, 0), Ot = new p(0, 0, 0), kt = new Ft(), lt = new L(), pt = new L(), Y = new p(), jt = new Ft(), tt = new p(1, 0, 0), Z = new p(0, 1, 0), et = new p(0, 0, 1), ct = new p(), K = new p(), $ = new p();
278
+ class ye extends Mt {
279
+ constructor(t) {
280
+ super(), this.isTransformControlsRoot = !0, this.controls = t, this.visible = !1;
281
+ }
282
+ // updateMatrixWorld updates key transformation variables
283
+ updateMatrixWorld(t) {
284
+ const e = this.controls;
285
+ e.object !== void 0 && (e.object.updateMatrixWorld(), e.object.parent === null ? console.error("TransformControls: The attached 3D object must be a part of the scene graph.") : e.object.parent.matrixWorld.decompose(e._parentPosition, e._parentQuaternion, e._parentScale), e.object.matrixWorld.decompose(e.worldPosition, e.worldQuaternion, e._worldScale), e._parentQuaternionInv.copy(e._parentQuaternion).invert(), e._worldQuaternionInv.copy(e.worldQuaternion).invert()), e.camera.updateMatrixWorld(), e.camera.matrixWorld.decompose(e.cameraPosition, e.cameraQuaternion, e._cameraScale), e.camera.isOrthographicCamera ? e.camera.getWorldDirection(e.eye).negate() : e.eye.copy(e.cameraPosition).sub(e.worldPosition).normalize(), super.updateMatrixWorld(t);
286
+ }
287
+ dispose() {
288
+ this.traverse(function(t) {
289
+ t.geometry && t.geometry.dispose(), t.material && t.material.dispose();
290
+ });
291
+ }
292
+ }
293
+ class ge extends Mt {
294
+ constructor() {
295
+ super(), this.isTransformControlsGizmo = !0, this.type = "TransformControlsGizmo";
296
+ const t = new Nt({
297
+ depthTest: !1,
298
+ depthWrite: !1,
299
+ fog: !1,
300
+ toneMapped: !1,
301
+ transparent: !0
302
+ }), e = new Jt({
303
+ depthTest: !1,
304
+ depthWrite: !1,
305
+ fog: !1,
306
+ toneMapped: !1,
307
+ transparent: !0
308
+ }), i = t.clone();
309
+ i.opacity = 0.15;
310
+ const s = e.clone();
311
+ s.opacity = 0.5;
312
+ const o = t.clone();
313
+ o.color.setHex(16711680);
314
+ const n = t.clone();
315
+ n.color.setHex(65280);
316
+ const h = t.clone();
317
+ h.color.setHex(255);
318
+ const d = t.clone();
319
+ d.color.setHex(16711680), d.opacity = 0.5;
320
+ const u = t.clone();
321
+ u.color.setHex(65280), u.opacity = 0.5;
322
+ const y = t.clone();
323
+ y.color.setHex(255), y.opacity = 0.5;
324
+ const _ = t.clone();
325
+ _.opacity = 0.25;
326
+ const D = t.clone();
327
+ D.color.setHex(16776960), D.opacity = 0.25, t.clone().color.setHex(16776960);
328
+ const B = t.clone();
329
+ B.color.setHex(7895160);
330
+ const z = new P(0, 0.04, 0.1, 12);
331
+ z.translate(0, 0.05, 0);
332
+ const O = new S(0.08, 0.08, 0.08);
333
+ O.translate(0, 0.04, 0);
334
+ const M = new Pt();
335
+ M.setAttribute("position", new It([0, 0, 0, 1, 0, 0], 3));
336
+ const E = new P(75e-4, 75e-4, 0.5, 3);
337
+ E.translate(0, 0.25, 0);
338
+ function b(C, st) {
339
+ const j = new W(C, 75e-4, 3, 64, st * Math.PI * 2);
340
+ return j.rotateY(Math.PI / 2), j.rotateX(Math.PI / 2), j;
341
+ }
342
+ function T() {
343
+ const C = new Pt();
344
+ return C.setAttribute("position", new It([0, 0, 0, 1, 1, 1], 3)), C;
345
+ }
346
+ const k = {
347
+ X: [
348
+ [new c(z, o), [0.5, 0, 0], [0, 0, -Math.PI / 2]],
349
+ [new c(z, o), [-0.5, 0, 0], [0, 0, Math.PI / 2]],
350
+ [new c(E, o), [0, 0, 0], [0, 0, -Math.PI / 2]]
351
+ ],
352
+ Y: [
353
+ [new c(z, n), [0, 0.5, 0]],
354
+ [new c(z, n), [0, -0.5, 0], [Math.PI, 0, 0]],
355
+ [new c(E, n)]
356
+ ],
357
+ Z: [
358
+ [new c(z, h), [0, 0, 0.5], [Math.PI / 2, 0, 0]],
359
+ [new c(z, h), [0, 0, -0.5], [-Math.PI / 2, 0, 0]],
360
+ [new c(E, h), null, [Math.PI / 2, 0, 0]]
361
+ ],
362
+ XYZ: [
363
+ [new c(new rt(0.1, 0), _.clone()), [0, 0, 0]]
364
+ ],
365
+ XY: [
366
+ [new c(new S(0.15, 0.15, 0.01), y.clone()), [0.15, 0.15, 0]]
367
+ ],
368
+ YZ: [
369
+ [new c(new S(0.15, 0.15, 0.01), d.clone()), [0, 0.15, 0.15], [0, Math.PI / 2, 0]]
370
+ ],
371
+ XZ: [
372
+ [new c(new S(0.15, 0.15, 0.01), u.clone()), [0.15, 0, 0.15], [-Math.PI / 2, 0, 0]]
373
+ ]
374
+ }, A = {
375
+ X: [
376
+ [new c(new P(0.2, 0, 0.6, 4), i), [0.3, 0, 0], [0, 0, -Math.PI / 2]],
377
+ [new c(new P(0.2, 0, 0.6, 4), i), [-0.3, 0, 0], [0, 0, Math.PI / 2]]
378
+ ],
379
+ Y: [
380
+ [new c(new P(0.2, 0, 0.6, 4), i), [0, 0.3, 0]],
381
+ [new c(new P(0.2, 0, 0.6, 4), i), [0, -0.3, 0], [0, 0, Math.PI]]
382
+ ],
383
+ Z: [
384
+ [new c(new P(0.2, 0, 0.6, 4), i), [0, 0, 0.3], [Math.PI / 2, 0, 0]],
385
+ [new c(new P(0.2, 0, 0.6, 4), i), [0, 0, -0.3], [-Math.PI / 2, 0, 0]]
386
+ ],
387
+ XYZ: [
388
+ [new c(new rt(0.2, 0), i)]
389
+ ],
390
+ XY: [
391
+ [new c(new S(0.2, 0.2, 0.01), i), [0.15, 0.15, 0]]
392
+ ],
393
+ YZ: [
394
+ [new c(new S(0.2, 0.2, 0.01), i), [0, 0.15, 0.15], [0, Math.PI / 2, 0]]
395
+ ],
396
+ XZ: [
397
+ [new c(new S(0.2, 0.2, 0.01), i), [0.15, 0, 0.15], [-Math.PI / 2, 0, 0]]
398
+ ]
399
+ }, it = {
400
+ START: [
401
+ [new c(new rt(0.01, 2), s), null, null, null, "helper"]
402
+ ],
403
+ END: [
404
+ [new c(new rt(0.01, 2), s), null, null, null, "helper"]
405
+ ],
406
+ DELTA: [
407
+ [new F(T(), s), null, null, null, "helper"]
408
+ ],
409
+ X: [
410
+ [new F(M, s.clone()), [-1e3, 0, 0], null, [1e6, 1, 1], "helper"]
411
+ ],
412
+ Y: [
413
+ [new F(M, s.clone()), [0, -1e3, 0], [0, 0, Math.PI / 2], [1e6, 1, 1], "helper"]
414
+ ],
415
+ Z: [
416
+ [new F(M, s.clone()), [0, 0, -1e3], [0, -Math.PI / 2, 0], [1e6, 1, 1], "helper"]
417
+ ]
418
+ }, Ut = {
419
+ XYZE: [
420
+ [new c(b(0.5, 1), B), null, [0, Math.PI / 2, 0]]
421
+ ],
422
+ X: [
423
+ [new c(b(0.5, 0.5), o)]
424
+ ],
425
+ Y: [
426
+ [new c(b(0.5, 0.5), n), null, [0, 0, -Math.PI / 2]]
427
+ ],
428
+ Z: [
429
+ [new c(b(0.5, 0.5), h), null, [0, Math.PI / 2, 0]]
430
+ ],
431
+ E: [
432
+ [new c(b(0.75, 1), D), null, [0, Math.PI / 2, 0]]
433
+ ]
434
+ }, Zt = {
435
+ AXIS: [
436
+ [new F(M, s.clone()), [-1e3, 0, 0], null, [1e6, 1, 1], "helper"]
437
+ ]
438
+ }, Bt = {
439
+ XYZE: [
440
+ [new c(new te(0.25, 10, 8), i)]
441
+ ],
442
+ X: [
443
+ [new c(new W(0.5, 0.1, 4, 24), i), [0, 0, 0], [0, -Math.PI / 2, -Math.PI / 2]]
444
+ ],
445
+ Y: [
446
+ [new c(new W(0.5, 0.1, 4, 24), i), [0, 0, 0], [Math.PI / 2, 0, 0]]
447
+ ],
448
+ Z: [
449
+ [new c(new W(0.5, 0.1, 4, 24), i), [0, 0, 0], [0, 0, -Math.PI / 2]]
450
+ ],
451
+ E: [
452
+ [new c(new W(0.75, 0.1, 2, 24), i)]
453
+ ]
454
+ }, Qt = {
455
+ X: [
456
+ [new c(O, o), [0.5, 0, 0], [0, 0, -Math.PI / 2]],
457
+ [new c(E, o), [0, 0, 0], [0, 0, -Math.PI / 2]],
458
+ [new c(O, o), [-0.5, 0, 0], [0, 0, Math.PI / 2]]
459
+ ],
460
+ Y: [
461
+ [new c(O, n), [0, 0.5, 0]],
462
+ [new c(E, n)],
463
+ [new c(O, n), [0, -0.5, 0], [0, 0, Math.PI]]
464
+ ],
465
+ Z: [
466
+ [new c(O, h), [0, 0, 0.5], [Math.PI / 2, 0, 0]],
467
+ [new c(E, h), [0, 0, 0], [Math.PI / 2, 0, 0]],
468
+ [new c(O, h), [0, 0, -0.5], [-Math.PI / 2, 0, 0]]
469
+ ],
470
+ XY: [
471
+ [new c(new S(0.15, 0.15, 0.01), y), [0.15, 0.15, 0]]
472
+ ],
473
+ YZ: [
474
+ [new c(new S(0.15, 0.15, 0.01), d), [0, 0.15, 0.15], [0, Math.PI / 2, 0]]
475
+ ],
476
+ XZ: [
477
+ [new c(new S(0.15, 0.15, 0.01), u), [0.15, 0, 0.15], [-Math.PI / 2, 0, 0]]
478
+ ],
479
+ XYZ: [
480
+ [new c(new S(0.1, 0.1, 0.1), _.clone())]
481
+ ]
482
+ }, Vt = {
483
+ X: [
484
+ [new c(new P(0.2, 0, 0.6, 4), i), [0.3, 0, 0], [0, 0, -Math.PI / 2]],
485
+ [new c(new P(0.2, 0, 0.6, 4), i), [-0.3, 0, 0], [0, 0, Math.PI / 2]]
486
+ ],
487
+ Y: [
488
+ [new c(new P(0.2, 0, 0.6, 4), i), [0, 0.3, 0]],
489
+ [new c(new P(0.2, 0, 0.6, 4), i), [0, -0.3, 0], [0, 0, Math.PI]]
490
+ ],
491
+ Z: [
492
+ [new c(new P(0.2, 0, 0.6, 4), i), [0, 0, 0.3], [Math.PI / 2, 0, 0]],
493
+ [new c(new P(0.2, 0, 0.6, 4), i), [0, 0, -0.3], [-Math.PI / 2, 0, 0]]
494
+ ],
495
+ XY: [
496
+ [new c(new S(0.2, 0.2, 0.01), i), [0.15, 0.15, 0]]
497
+ ],
498
+ YZ: [
499
+ [new c(new S(0.2, 0.2, 0.01), i), [0, 0.15, 0.15], [0, Math.PI / 2, 0]]
500
+ ],
501
+ XZ: [
502
+ [new c(new S(0.2, 0.2, 0.01), i), [0.15, 0, 0.15], [-Math.PI / 2, 0, 0]]
503
+ ],
504
+ XYZ: [
505
+ [new c(new S(0.2, 0.2, 0.2), i), [0, 0, 0]]
506
+ ]
507
+ }, Gt = {
508
+ X: [
509
+ [new F(M, s.clone()), [-1e3, 0, 0], null, [1e6, 1, 1], "helper"]
510
+ ],
511
+ Y: [
512
+ [new F(M, s.clone()), [0, -1e3, 0], [0, 0, Math.PI / 2], [1e6, 1, 1], "helper"]
513
+ ],
514
+ Z: [
515
+ [new F(M, s.clone()), [0, 0, -1e3], [0, -Math.PI / 2, 0], [1e6, 1, 1], "helper"]
516
+ ]
517
+ };
518
+ function H(C) {
519
+ const st = new Mt();
520
+ for (const j in C)
521
+ for (let Q = C[j].length; Q--; ) {
522
+ const v = C[j][Q][0].clone(), nt = C[j][Q][1], ot = C[j][Q][2], at = C[j][Q][3], qt = C[j][Q][4];
523
+ v.name = j, v.tag = qt, nt && v.position.set(nt[0], nt[1], nt[2]), ot && v.rotation.set(ot[0], ot[1], ot[2]), at && v.scale.set(at[0], at[1], at[2]), v.updateMatrix();
524
+ const vt = v.geometry.clone();
525
+ vt.applyMatrix4(v.matrix), v.geometry = vt, v.renderOrder = 1 / 0, v.position.set(0, 0, 0), v.rotation.set(0, 0, 0), v.scale.set(1, 1, 1), st.add(v);
526
+ }
527
+ return st;
528
+ }
529
+ this.gizmo = {}, this.picker = {}, this.helper = {}, this.add(this.gizmo.translate = H(k)), this.add(this.gizmo.rotate = H(Ut)), this.add(this.gizmo.scale = H(Qt)), this.add(this.picker.translate = H(A)), this.add(this.picker.rotate = H(Bt)), this.add(this.picker.scale = H(Vt)), this.add(this.helper.translate = H(it)), this.add(this.helper.rotate = H(Zt)), this.add(this.helper.scale = H(Gt)), this.picker.translate.visible = !1, this.picker.rotate.visible = !1, this.picker.scale.visible = !1;
530
+ }
531
+ // updateMatrixWorld will update transformations and appearance of individual handles
532
+ updateMatrixWorld(t) {
533
+ const i = (this.mode === "scale" ? "local" : this.space) === "local" ? this.worldQuaternion : pt;
534
+ this.gizmo.translate.visible = this.mode === "translate", this.gizmo.rotate.visible = this.mode === "rotate", this.gizmo.scale.visible = this.mode === "scale", this.helper.translate.visible = this.mode === "translate", this.helper.rotate.visible = this.mode === "rotate", this.helper.scale.visible = this.mode === "scale";
535
+ let s = [];
536
+ s = s.concat(this.picker[this.mode].children), s = s.concat(this.gizmo[this.mode].children), s = s.concat(this.helper[this.mode].children);
537
+ for (let o = 0; o < s.length; o++) {
538
+ const n = s[o];
539
+ n.visible = !0, n.rotation.set(0, 0, 0), n.position.copy(this.worldPosition);
540
+ let h;
541
+ if (this.camera.isOrthographicCamera ? h = (this.camera.top - this.camera.bottom) / this.camera.zoom : h = this.worldPosition.distanceTo(this.cameraPosition) * Math.min(1.9 * Math.tan(Math.PI * this.camera.fov / 360) / this.camera.zoom, 7), n.scale.set(1, 1, 1).multiplyScalar(h * this.size / 4), n.tag === "helper") {
542
+ n.visible = !1, n.name === "AXIS" ? (n.visible = !!this.axis, this.axis === "X" && (g.setFromEuler(ht.set(0, 0, 0)), n.quaternion.copy(i).multiply(g), Math.abs(f.copy(tt).applyQuaternion(i).dot(this.eye)) > 0.9 && (n.visible = !1)), this.axis === "Y" && (g.setFromEuler(ht.set(0, 0, Math.PI / 2)), n.quaternion.copy(i).multiply(g), Math.abs(f.copy(Z).applyQuaternion(i).dot(this.eye)) > 0.9 && (n.visible = !1)), this.axis === "Z" && (g.setFromEuler(ht.set(0, Math.PI / 2, 0)), n.quaternion.copy(i).multiply(g), Math.abs(f.copy(et).applyQuaternion(i).dot(this.eye)) > 0.9 && (n.visible = !1)), this.axis === "XYZE" && (g.setFromEuler(ht.set(0, Math.PI / 2, 0)), f.copy(this.rotationAxis), n.quaternion.setFromRotationMatrix(kt.lookAt(Ot, f, Z)), n.quaternion.multiply(g), n.visible = this.dragging), this.axis === "E" && (n.visible = !1)) : n.name === "START" ? (n.position.copy(this.worldPositionStart), n.visible = this.dragging) : n.name === "END" ? (n.position.copy(this.worldPosition), n.visible = this.dragging) : n.name === "DELTA" ? (n.position.copy(this.worldPositionStart), n.quaternion.copy(this.worldQuaternionStart), x.set(1e-10, 1e-10, 1e-10).add(this.worldPositionStart).sub(this.worldPosition).multiplyScalar(-1), x.applyQuaternion(this.worldQuaternionStart.clone().invert()), n.scale.copy(x), n.visible = this.dragging) : (n.quaternion.copy(i), this.dragging ? n.position.copy(this.worldPositionStart) : n.position.copy(this.worldPosition), this.axis && (n.visible = this.axis.search(n.name) !== -1));
543
+ continue;
544
+ }
545
+ n.quaternion.copy(i), this.mode === "translate" || this.mode === "scale" ? (n.name === "X" && Math.abs(f.copy(tt).applyQuaternion(i).dot(this.eye)) > 0.99 && (n.scale.set(1e-10, 1e-10, 1e-10), n.visible = !1), n.name === "Y" && Math.abs(f.copy(Z).applyQuaternion(i).dot(this.eye)) > 0.99 && (n.scale.set(1e-10, 1e-10, 1e-10), n.visible = !1), n.name === "Z" && Math.abs(f.copy(et).applyQuaternion(i).dot(this.eye)) > 0.99 && (n.scale.set(1e-10, 1e-10, 1e-10), n.visible = !1), n.name === "XY" && Math.abs(f.copy(et).applyQuaternion(i).dot(this.eye)) < 0.2 && (n.scale.set(1e-10, 1e-10, 1e-10), n.visible = !1), n.name === "YZ" && Math.abs(f.copy(tt).applyQuaternion(i).dot(this.eye)) < 0.2 && (n.scale.set(1e-10, 1e-10, 1e-10), n.visible = !1), n.name === "XZ" && Math.abs(f.copy(Z).applyQuaternion(i).dot(this.eye)) < 0.2 && (n.scale.set(1e-10, 1e-10, 1e-10), n.visible = !1)) : this.mode === "rotate" && (lt.copy(i), f.copy(this.eye).applyQuaternion(g.copy(i).invert()), n.name.search("E") !== -1 && n.quaternion.setFromRotationMatrix(kt.lookAt(this.eye, Ot, Z)), n.name === "X" && (g.setFromAxisAngle(tt, Math.atan2(-f.y, f.z)), g.multiplyQuaternions(lt, g), n.quaternion.copy(g)), n.name === "Y" && (g.setFromAxisAngle(Z, Math.atan2(f.x, f.z)), g.multiplyQuaternions(lt, g), n.quaternion.copy(g)), n.name === "Z" && (g.setFromAxisAngle(et, Math.atan2(f.y, f.x)), g.multiplyQuaternions(lt, g), n.quaternion.copy(g))), n.visible = n.visible && (n.name.indexOf("X") === -1 || this.showX), n.visible = n.visible && (n.name.indexOf("Y") === -1 || this.showY), n.visible = n.visible && (n.name.indexOf("Z") === -1 || this.showZ), n.visible = n.visible && (n.name.indexOf("E") === -1 || this.showX && this.showY && this.showZ), n.material._color = n.material._color || n.material.color.clone(), n.material._opacity = n.material._opacity || n.material.opacity, n.material.color.copy(n.material._color), n.material.opacity = n.material._opacity, this.enabled && this.axis && (n.name === this.axis || this.axis.split("").some(function(d) {
546
+ return n.name === d;
547
+ })) && (n.material.color.setHex(16776960), n.material.opacity = 1);
548
+ }
549
+ super.updateMatrixWorld(t);
550
+ }
551
+ }
552
+ class be extends c {
553
+ constructor() {
554
+ super(
555
+ new ie(1e5, 1e5, 2, 2),
556
+ new Nt({ visible: !1, wireframe: !0, side: se, transparent: !0, opacity: 0.1, toneMapped: !1 })
557
+ ), this.isTransformControlsPlane = !0, this.type = "TransformControlsPlane";
558
+ }
559
+ updateMatrixWorld(t) {
560
+ let e = this.space;
561
+ switch (this.position.copy(this.worldPosition), this.mode === "scale" && (e = "local"), ct.copy(tt).applyQuaternion(e === "local" ? this.worldQuaternion : pt), K.copy(Z).applyQuaternion(e === "local" ? this.worldQuaternion : pt), $.copy(et).applyQuaternion(e === "local" ? this.worldQuaternion : pt), f.copy(K), this.mode) {
562
+ case "translate":
563
+ case "scale":
564
+ switch (this.axis) {
565
+ case "X":
566
+ f.copy(this.eye).cross(ct), Y.copy(ct).cross(f);
567
+ break;
568
+ case "Y":
569
+ f.copy(this.eye).cross(K), Y.copy(K).cross(f);
570
+ break;
571
+ case "Z":
572
+ f.copy(this.eye).cross($), Y.copy($).cross(f);
573
+ break;
574
+ case "XY":
575
+ Y.copy($);
576
+ break;
577
+ case "YZ":
578
+ Y.copy(ct);
579
+ break;
580
+ case "XZ":
581
+ f.copy($), Y.copy(K);
582
+ break;
583
+ case "XYZ":
584
+ case "E":
585
+ Y.set(0, 0, 0);
586
+ break;
587
+ }
588
+ break;
589
+ case "rotate":
590
+ default:
591
+ Y.set(0, 0, 0);
592
+ }
593
+ Y.length() === 0 ? this.quaternion.copy(this.cameraQuaternion) : (jt.lookAt(x.set(0, 0, 0), Y, f), this.quaternion.setFromRotationMatrix(jt)), super.updateMatrixWorld(t);
594
+ }
595
+ }
596
+ class q {
597
+ constructor(t, e = !1) {
598
+ r(this, "object");
599
+ r(this, "updatable");
600
+ r(this, "timestamp");
601
+ this.object = t, this.updatable = e, this.timestamp = Date.now();
602
+ }
603
+ }
604
+ class ut extends q {
605
+ constructor(e, i, s) {
606
+ super(e, !0);
607
+ r(this, "type", "SetPosition");
608
+ r(this, "updatable", !0);
609
+ r(this, "newPosition");
610
+ r(this, "oldPosition");
611
+ this.newPosition = i.clone(), this.oldPosition = s.clone();
612
+ }
613
+ execute() {
614
+ this.object.position.copy(this.newPosition);
615
+ }
616
+ undo() {
617
+ this.object.position.copy(this.oldPosition);
618
+ }
619
+ update(e) {
620
+ e instanceof ut && this.newPosition.copy(e.newPosition);
621
+ }
622
+ /**
623
+ * Get the new position
624
+ */
625
+ getNewPosition() {
626
+ return this.newPosition.clone();
627
+ }
628
+ /**
629
+ * Get the old position
630
+ */
631
+ getOldPosition() {
632
+ return this.oldPosition.clone();
633
+ }
634
+ }
635
+ class mt extends q {
636
+ constructor(e, i, s) {
637
+ super(e, !0);
638
+ r(this, "type", "SetRotation");
639
+ r(this, "updatable", !0);
640
+ r(this, "newRotation");
641
+ r(this, "oldRotation");
642
+ this.newRotation = i.clone(), this.oldRotation = s.clone();
643
+ }
644
+ execute() {
645
+ this.object.rotation.copy(this.newRotation);
646
+ }
647
+ undo() {
648
+ this.object.rotation.copy(this.oldRotation);
649
+ }
650
+ update(e) {
651
+ e instanceof mt && this.newRotation.copy(e.newRotation);
652
+ }
653
+ /**
654
+ * Get the new rotation
655
+ */
656
+ getNewRotation() {
657
+ return this.newRotation.clone();
658
+ }
659
+ /**
660
+ * Get the old rotation
661
+ */
662
+ getOldRotation() {
663
+ return this.oldRotation.clone();
664
+ }
665
+ }
666
+ class ft extends q {
667
+ constructor(e, i, s) {
668
+ super(e, !0);
669
+ r(this, "type", "SetScale");
670
+ r(this, "updatable", !0);
671
+ r(this, "newScale");
672
+ r(this, "oldScale");
673
+ this.newScale = i.clone(), this.oldScale = s.clone();
674
+ }
675
+ execute() {
676
+ this.object.scale.copy(this.newScale);
677
+ }
678
+ undo() {
679
+ this.object.scale.copy(this.oldScale);
680
+ }
681
+ update(e) {
682
+ e instanceof ft && this.newScale.copy(e.newScale);
683
+ }
684
+ /**
685
+ * Get the new scale
686
+ */
687
+ getNewScale() {
688
+ return this.newScale.clone();
689
+ }
690
+ /**
691
+ * Get the old scale
692
+ */
693
+ getOldScale() {
694
+ return this.oldScale.clone();
695
+ }
696
+ }
697
+ class we {
698
+ constructor(t) {
699
+ r(this, "editor");
700
+ r(this, "controls");
701
+ r(this, "mode", "translate");
702
+ r(this, "eventListeners", /* @__PURE__ */ new Map());
703
+ // Track transform start state for undo
704
+ r(this, "transformStartPosition", null);
705
+ r(this, "transformStartRotation", null);
706
+ r(this, "transformStartScale", null);
707
+ r(this, "isTransforming", !1);
708
+ this.editor = t, this.controls = new ce(
709
+ this.editor.camera,
710
+ this.editor.renderer.domElement
711
+ ), this.controls.setSize(0.75), this.editor.scene.add(this.controls.getHelper()), this.handleDraggingChanged = this.handleDraggingChanged.bind(this), this.handleObjectChange = this.handleObjectChange.bind(this), this.controls.addEventListener("dragging-changed", this.handleDraggingChanged), this.controls.addEventListener("objectChange", this.handleObjectChange), this.handleKeyDown = this.handleKeyDown.bind(this), document.addEventListener("keydown", this.handleKeyDown);
712
+ }
713
+ /**
714
+ * Handle dragging state changes
715
+ */
716
+ handleDraggingChanged(t) {
717
+ const e = t.value;
718
+ this.editor.controls.enabled = !e, e ? (this.captureStartState(), this.isTransforming = !0) : this.isTransforming && (this.createCommand(), this.isTransforming = !1);
719
+ }
720
+ /**
721
+ * Capture the start state before transform
722
+ */
723
+ captureStartState() {
724
+ const t = this.controls.object;
725
+ t && (this.transformStartPosition = t.position.clone(), this.transformStartRotation = t.rotation.clone(), this.transformStartScale = t.scale.clone());
726
+ }
727
+ /**
728
+ * Create a command after transform completes
729
+ */
730
+ createCommand() {
731
+ const t = this.controls.object;
732
+ if (!t) return;
733
+ let e = null;
734
+ switch (this.mode) {
735
+ case "translate":
736
+ this.transformStartPosition && !t.position.equals(this.transformStartPosition) && (e = new ut(
737
+ t,
738
+ t.position.clone(),
739
+ this.transformStartPosition.clone()
740
+ ));
741
+ break;
742
+ case "rotate":
743
+ this.transformStartRotation && (t.rotation.x !== this.transformStartRotation.x || t.rotation.y !== this.transformStartRotation.y || t.rotation.z !== this.transformStartRotation.z) && (e = new mt(
744
+ t,
745
+ t.rotation.clone(),
746
+ this.transformStartRotation.clone()
747
+ ));
748
+ break;
749
+ case "scale":
750
+ this.transformStartScale && !t.scale.equals(this.transformStartScale) && (e = new ft(
751
+ t,
752
+ t.scale.clone(),
753
+ this.transformStartScale.clone()
754
+ ));
755
+ break;
756
+ }
757
+ e && this.emit("objectChanged", t, e), this.transformStartPosition = null, this.transformStartRotation = null, this.transformStartScale = null;
758
+ }
759
+ /**
760
+ * Handle object change during transform (live updates)
761
+ */
762
+ handleObjectChange() {
763
+ const t = this.controls.object;
764
+ t && this.emit("objectChanging", t);
765
+ }
766
+ /**
767
+ * Handle keyboard shortcuts
768
+ */
769
+ handleKeyDown(t) {
770
+ if (!(t.target instanceof HTMLInputElement || t.target instanceof HTMLTextAreaElement))
771
+ switch (t.key.toLowerCase()) {
772
+ case "g":
773
+ this.setMode("translate");
774
+ break;
775
+ case "r":
776
+ !t.ctrlKey && !t.metaKey && this.setMode("rotate");
777
+ break;
778
+ case "s":
779
+ !t.ctrlKey && !t.metaKey && this.setMode("scale");
780
+ break;
781
+ case "escape":
782
+ this.isTransforming && this.cancelTransform();
783
+ break;
784
+ }
785
+ }
786
+ /**
787
+ * Cancel current transform and restore original state
788
+ */
789
+ cancelTransform() {
790
+ const t = this.controls.object;
791
+ t && (this.transformStartPosition && t.position.copy(this.transformStartPosition), this.transformStartRotation && t.rotation.copy(this.transformStartRotation), this.transformStartScale && t.scale.copy(this.transformStartScale), this.isTransforming = !1, this.transformStartPosition = null, this.transformStartRotation = null, this.transformStartScale = null);
792
+ }
793
+ /**
794
+ * Attach controls to an object
795
+ */
796
+ attach(t) {
797
+ const e = this.controls.getHelper();
798
+ t ? (this.controls.attach(t), e.visible = !0) : (this.controls.detach(), e.visible = !1);
799
+ }
800
+ /**
801
+ * Set transform mode
802
+ */
803
+ setMode(t) {
804
+ this.mode = t, this.controls.setMode(t), this.emit("modeChanged", t);
805
+ }
806
+ /**
807
+ * Get current transform mode
808
+ */
809
+ getMode() {
810
+ return this.mode;
811
+ }
812
+ /**
813
+ * Get TransformControls instance
814
+ */
815
+ getControls() {
816
+ return this.controls;
817
+ }
818
+ /**
819
+ * Add event listener
820
+ */
821
+ on(t, e) {
822
+ this.eventListeners.has(t) || this.eventListeners.set(t, /* @__PURE__ */ new Set()), this.eventListeners.get(t).add(e);
823
+ }
824
+ /**
825
+ * Emit event
826
+ */
827
+ emit(t, ...e) {
828
+ var i;
829
+ (i = this.eventListeners.get(t)) == null || i.forEach((s) => s(...e));
830
+ }
831
+ /**
832
+ * Clean up
833
+ */
834
+ dispose() {
835
+ document.removeEventListener("keydown", this.handleKeyDown), this.controls.removeEventListener("dragging-changed", this.handleDraggingChanged), this.controls.removeEventListener("objectChange", this.handleObjectChange), this.controls.dispose(), this.editor.scene.remove(this.controls.getHelper()), this.eventListeners.clear();
836
+ }
837
+ }
838
+ const _e = 500;
839
+ class xe {
840
+ constructor() {
841
+ r(this, "undoStack", []);
842
+ r(this, "redoStack", []);
843
+ r(this, "eventListeners", /* @__PURE__ */ new Map());
844
+ }
845
+ /**
846
+ * Execute a command and add it to history
847
+ */
848
+ execute(t) {
849
+ t.execute();
850
+ const e = this.undoStack[this.undoStack.length - 1];
851
+ e && e.updatable && t.updatable && e.type === t.type && e.object === t.object && t.timestamp - e.timestamp < _e ? e.update && e.update(t) : this.undoStack.push(t), this.redoStack = [], this.emit("historyChanged");
852
+ }
853
+ /**
854
+ * Undo the last command
855
+ */
856
+ undo() {
857
+ const t = this.undoStack.pop();
858
+ t && (t.undo(), this.redoStack.push(t), this.emit("historyChanged"));
859
+ }
860
+ /**
861
+ * Redo the last undone command
862
+ */
863
+ redo() {
864
+ const t = this.redoStack.pop();
865
+ t && (t.execute(), this.undoStack.push(t), this.emit("historyChanged"));
866
+ }
867
+ /**
868
+ * Check if undo is available
869
+ */
870
+ canUndo() {
871
+ return this.undoStack.length > 0;
872
+ }
873
+ /**
874
+ * Check if redo is available
875
+ */
876
+ canRedo() {
877
+ return this.redoStack.length > 0;
878
+ }
879
+ /**
880
+ * Clear all history
881
+ */
882
+ clear() {
883
+ this.undoStack = [], this.redoStack = [], this.emit("historyChanged");
884
+ }
885
+ /**
886
+ * Get the number of items in undo stack
887
+ */
888
+ getUndoCount() {
889
+ return this.undoStack.length;
890
+ }
891
+ /**
892
+ * Get the number of items in redo stack
893
+ */
894
+ getRedoCount() {
895
+ return this.redoStack.length;
896
+ }
897
+ /**
898
+ * Add event listener
899
+ */
900
+ on(t, e) {
901
+ this.eventListeners.has(t) || this.eventListeners.set(t, /* @__PURE__ */ new Set()), this.eventListeners.get(t).add(e);
902
+ }
903
+ /**
904
+ * Emit event
905
+ */
906
+ emit(t) {
907
+ var e;
908
+ (e = this.eventListeners.get(t)) == null || e.forEach((i) => i());
909
+ }
910
+ }
911
+ class Ze {
912
+ constructor(t) {
913
+ r(this, "scene");
914
+ r(this, "camera");
915
+ r(this, "renderer");
916
+ r(this, "controls");
917
+ r(this, "domElement");
918
+ r(this, "selection");
919
+ r(this, "transform");
920
+ r(this, "history");
921
+ r(this, "currentModel", null);
922
+ r(this, "eventListeners", /* @__PURE__ */ new Map());
923
+ this.scene = t.scene, this.camera = t.camera, this.renderer = t.renderer, this.controls = t.controls, this.domElement = t.domElement, this.history = new xe(), this.selection = new le(this), this.transform = new we(this), this.selection.on("selectionChanged", (e) => {
924
+ this.emit("selectionChanged", e), this.transform.attach(e);
925
+ }), this.transform.on("objectChanged", (...e) => {
926
+ const i = e[0], s = e[1];
927
+ this.history.execute(s), this.emit("objectChanged", i);
928
+ }), this.history.on("historyChanged", () => {
929
+ this.emit("historyChanged");
930
+ }), this.transform.on("modeChanged", (...e) => {
931
+ const i = e[0];
932
+ this.emit("modeChanged", i);
933
+ });
934
+ }
935
+ /**
936
+ * Set the current model being edited
937
+ */
938
+ setModel(t) {
939
+ this.currentModel = t, this.selection.deselect(), this.history.clear(), this.emit("modelLoaded", t);
940
+ }
941
+ /**
942
+ * Get the current model
943
+ */
944
+ getModel() {
945
+ return this.currentModel;
946
+ }
947
+ /**
948
+ * Get the currently selected object
949
+ */
950
+ getSelected() {
951
+ return this.selection.getSelected();
952
+ }
953
+ /**
954
+ * Select an object
955
+ */
956
+ select(t) {
957
+ this.selection.select(t);
958
+ }
959
+ /**
960
+ * Execute a command (adds to history)
961
+ */
962
+ execute(t) {
963
+ this.history.execute(t), this.emit("objectChanged", this.getSelected());
964
+ }
965
+ /**
966
+ * Undo the last command
967
+ */
968
+ undo() {
969
+ this.history.undo(), this.emit("objectChanged", this.getSelected());
970
+ }
971
+ /**
972
+ * Redo the last undone command
973
+ */
974
+ redo() {
975
+ this.history.redo(), this.emit("objectChanged", this.getSelected());
976
+ }
977
+ /**
978
+ * Check if undo is available
979
+ */
980
+ canUndo() {
981
+ return this.history.canUndo();
982
+ }
983
+ /**
984
+ * Check if redo is available
985
+ */
986
+ canRedo() {
987
+ return this.history.canRedo();
988
+ }
989
+ /**
990
+ * Set transform mode
991
+ */
992
+ setTransformMode(t) {
993
+ this.transform.setMode(t);
994
+ }
995
+ /**
996
+ * Get current transform mode
997
+ */
998
+ getTransformMode() {
999
+ return this.transform.getMode();
1000
+ }
1001
+ /**
1002
+ * Add event listener
1003
+ */
1004
+ on(t, e) {
1005
+ this.eventListeners.has(t) || this.eventListeners.set(t, /* @__PURE__ */ new Set()), this.eventListeners.get(t).add(e);
1006
+ }
1007
+ /**
1008
+ * Remove event listener
1009
+ */
1010
+ off(t, e) {
1011
+ var i;
1012
+ (i = this.eventListeners.get(t)) == null || i.delete(e);
1013
+ }
1014
+ /**
1015
+ * Emit an event
1016
+ */
1017
+ emit(t, ...e) {
1018
+ var i;
1019
+ (i = this.eventListeners.get(t)) == null || i.forEach((s) => s(...e));
1020
+ }
1021
+ /**
1022
+ * Clean up resources
1023
+ */
1024
+ dispose() {
1025
+ this.selection.dispose(), this.transform.dispose(), this.eventListeners.clear();
1026
+ }
1027
+ }
1028
+ function Se() {
1029
+ return `node_${Date.now().toString(36)}_${Math.random().toString(36).substring(2, 8)}`;
1030
+ }
1031
+ class Be {
1032
+ /**
1033
+ * Serialize a Three.js model group to BlockyModel JSON
1034
+ */
1035
+ serialize(t) {
1036
+ const e = {
1037
+ format: t.userData.format || "prop",
1038
+ lod: t.userData.lod || "auto",
1039
+ nodes: []
1040
+ };
1041
+ for (const i of t.children)
1042
+ this.shouldSerialize(i) && e.nodes.push(this.serializeNode(i));
1043
+ return e;
1044
+ }
1045
+ /**
1046
+ * Check if an object should be serialized
1047
+ */
1048
+ shouldSerialize(t) {
1049
+ return !(t.type === "TransformControlsGizmo" || t.type === "TransformControlsPlane" || t.type === "GridHelper" || t.type === "AxesHelper");
1050
+ }
1051
+ /**
1052
+ * Serialize a single node
1053
+ */
1054
+ serializeNode(t) {
1055
+ const e = {
1056
+ id: t.userData.id || t.name || Se(),
1057
+ name: t.name || "Unnamed",
1058
+ position: this.serializePosition(t.position),
1059
+ orientation: this.serializeQuaternion(t.quaternion),
1060
+ shape: this.serializeShape(t),
1061
+ children: []
1062
+ };
1063
+ for (const i of t.children)
1064
+ this.shouldSerialize(i) && e.children.push(this.serializeNode(i));
1065
+ return e;
1066
+ }
1067
+ /**
1068
+ * Serialize position
1069
+ */
1070
+ serializePosition(t) {
1071
+ return {
1072
+ x: parseFloat(t.x.toFixed(4)),
1073
+ y: parseFloat(t.y.toFixed(4)),
1074
+ z: parseFloat(t.z.toFixed(4))
1075
+ };
1076
+ }
1077
+ /**
1078
+ * Serialize quaternion
1079
+ */
1080
+ serializeQuaternion(t) {
1081
+ return {
1082
+ w: parseFloat(t.w.toFixed(6)),
1083
+ x: parseFloat(t.x.toFixed(6)),
1084
+ y: parseFloat(t.y.toFixed(6)),
1085
+ z: parseFloat(t.z.toFixed(6))
1086
+ };
1087
+ }
1088
+ /**
1089
+ * Serialize shape
1090
+ */
1091
+ serializeShape(t) {
1092
+ const e = t.userData.shapeType || "none", i = {
1093
+ type: e,
1094
+ offset: t.userData.offset || { x: 0, y: 0, z: 0 },
1095
+ stretch: t.userData.stretch || { x: 1, y: 1, z: 1 },
1096
+ settings: {
1097
+ size: t.userData.originalSize || { x: 1, y: 1, z: 1 },
1098
+ isPiece: t.userData.isPiece || !1,
1099
+ isStaticBox: t.userData.isStaticBox || !1
1100
+ },
1101
+ textureLayout: t.userData.textureLayout || this.getDefaultTextureLayout(),
1102
+ unwrapMode: t.userData.unwrapMode || "custom",
1103
+ visible: t.visible !== !1,
1104
+ doubleSided: t.userData.doubleSided || !1,
1105
+ shadingMode: t.userData.shadingMode || "standard"
1106
+ };
1107
+ if (t instanceof l.Mesh) {
1108
+ const s = t.geometry;
1109
+ if (s instanceof l.BoxGeometry) {
1110
+ const n = s.parameters;
1111
+ t.userData.originalSize || (i.settings.size = {
1112
+ x: n.width,
1113
+ y: n.height,
1114
+ z: n.depth
1115
+ });
1116
+ }
1117
+ const o = t.material;
1118
+ o && (i.doubleSided = o.side === l.DoubleSide, o.emissiveIntensity > 0.5 ? i.shadingMode = "fullbright" : o.flatShading ? i.shadingMode = "flat" : o.metalness > 0.5 && (i.shadingMode = "reflective"));
1119
+ }
1120
+ return e === "quad" && t.userData.normal && (i.settings.normal = t.userData.normal), i;
1121
+ }
1122
+ /**
1123
+ * Get default texture layout
1124
+ */
1125
+ getDefaultTextureLayout() {
1126
+ const t = {
1127
+ offset: { x: 0, y: 0 },
1128
+ mirror: { x: !1, y: !1 },
1129
+ angle: 0
1130
+ };
1131
+ return {
1132
+ front: { ...t },
1133
+ back: { ...t },
1134
+ left: { ...t },
1135
+ right: { ...t },
1136
+ top: { ...t },
1137
+ bottom: { ...t }
1138
+ };
1139
+ }
1140
+ /**
1141
+ * Export model to JSON string
1142
+ */
1143
+ toJSON(t) {
1144
+ const e = this.serialize(t);
1145
+ return JSON.stringify(e, null, 2);
1146
+ }
1147
+ /**
1148
+ * Download model as .blockymodel file
1149
+ */
1150
+ download(t, e = "model.blockymodel") {
1151
+ const i = this.toJSON(t), s = new Blob([i], { type: "application/json" }), o = URL.createObjectURL(s), n = document.createElement("a");
1152
+ n.href = o, n.download = e.endsWith(".blockymodel") ? e : `${e}.blockymodel`, n.click(), URL.revokeObjectURL(o);
1153
+ }
1154
+ }
1155
+ class N extends q {
1156
+ constructor(e, i, s, o) {
1157
+ super(e, !0);
1158
+ r(this, "type", "SetProperty");
1159
+ r(this, "updatable", !0);
1160
+ r(this, "propertyPath");
1161
+ r(this, "newValue");
1162
+ r(this, "oldValue");
1163
+ this.propertyPath = i, this.newValue = this.cloneValue(s), this.oldValue = this.cloneValue(o);
1164
+ }
1165
+ /**
1166
+ * Clone a value if it's an object/array
1167
+ */
1168
+ cloneValue(e) {
1169
+ return e == null ? e : typeof e == "object" ? JSON.parse(JSON.stringify(e)) : e;
1170
+ }
1171
+ /**
1172
+ * Get a nested property by path (e.g., "userData.size.x")
1173
+ */
1174
+ getProperty(e, i) {
1175
+ const s = i.split(".");
1176
+ let o = e;
1177
+ for (const n of s) {
1178
+ if (o == null) return;
1179
+ o = o[n];
1180
+ }
1181
+ return o;
1182
+ }
1183
+ /**
1184
+ * Set a nested property by path
1185
+ */
1186
+ setProperty(e, i, s) {
1187
+ const o = i.split(".");
1188
+ let n = e;
1189
+ for (let h = 0; h < o.length - 1; h++)
1190
+ n[o[h]] === void 0 && (n[o[h]] = {}), n = n[o[h]];
1191
+ n[o[o.length - 1]] = s;
1192
+ }
1193
+ execute() {
1194
+ this.setProperty(this.object, this.propertyPath, this.cloneValue(this.newValue));
1195
+ }
1196
+ undo() {
1197
+ this.setProperty(this.object, this.propertyPath, this.cloneValue(this.oldValue));
1198
+ }
1199
+ update(e) {
1200
+ e instanceof N && e.propertyPath === this.propertyPath && (this.newValue = e.newValue);
1201
+ }
1202
+ /**
1203
+ * Get the property path
1204
+ */
1205
+ getPropertyPath() {
1206
+ return this.propertyPath;
1207
+ }
1208
+ /**
1209
+ * Get the new value
1210
+ */
1211
+ getNewValue() {
1212
+ return this.cloneValue(this.newValue);
1213
+ }
1214
+ /**
1215
+ * Get the old value
1216
+ */
1217
+ getOldValue() {
1218
+ return this.cloneValue(this.oldValue);
1219
+ }
1220
+ }
1221
+ class wt extends q {
1222
+ constructor(e, i, s) {
1223
+ super(e, !1);
1224
+ r(this, "type", "AddNode");
1225
+ r(this, "updatable", !1);
1226
+ r(this, "parent");
1227
+ r(this, "child");
1228
+ r(this, "index");
1229
+ this.parent = e, this.child = i, this.index = s ?? e.children.length;
1230
+ }
1231
+ execute() {
1232
+ if (this.parent.add(this.child), this.index < this.parent.children.length - 1) {
1233
+ const e = this.parent.children;
1234
+ e.splice(e.indexOf(this.child), 1), e.splice(this.index, 0, this.child);
1235
+ }
1236
+ }
1237
+ undo() {
1238
+ this.parent.remove(this.child);
1239
+ }
1240
+ /**
1241
+ * Get the added child
1242
+ */
1243
+ getChild() {
1244
+ return this.child;
1245
+ }
1246
+ /**
1247
+ * Get the parent
1248
+ */
1249
+ getParent() {
1250
+ return this.parent;
1251
+ }
1252
+ }
1253
+ class Me extends q {
1254
+ constructor(e) {
1255
+ super(e, !1);
1256
+ r(this, "type", "RemoveNode");
1257
+ r(this, "updatable", !1);
1258
+ r(this, "parent");
1259
+ r(this, "child");
1260
+ r(this, "index");
1261
+ if (!e.parent)
1262
+ throw new Error("Cannot remove node without parent");
1263
+ this.parent = e.parent, this.child = e, this.index = this.parent.children.indexOf(e);
1264
+ }
1265
+ execute() {
1266
+ this.parent.remove(this.child);
1267
+ }
1268
+ undo() {
1269
+ if (this.parent.add(this.child), this.index < this.parent.children.length) {
1270
+ const e = this.parent.children;
1271
+ e.splice(e.indexOf(this.child), 1), e.splice(this.index, 0, this.child);
1272
+ }
1273
+ }
1274
+ /**
1275
+ * Get the removed child
1276
+ */
1277
+ getChild() {
1278
+ return this.child;
1279
+ }
1280
+ /**
1281
+ * Get the parent
1282
+ */
1283
+ getParent() {
1284
+ return this.parent;
1285
+ }
1286
+ /**
1287
+ * Get the original index
1288
+ */
1289
+ getIndex() {
1290
+ return this.index;
1291
+ }
1292
+ }
1293
+ class Qe {
1294
+ constructor(t, e) {
1295
+ r(this, "editor");
1296
+ r(this, "container");
1297
+ r(this, "currentObject", null);
1298
+ r(this, "isUpdating", !1);
1299
+ // Input elements
1300
+ r(this, "nameInput");
1301
+ r(this, "posInputs");
1302
+ r(this, "rotInputs");
1303
+ r(this, "scaleInputs");
1304
+ r(this, "sizeInputs");
1305
+ r(this, "offsetInputs");
1306
+ r(this, "visibleCheckbox");
1307
+ r(this, "doubleSidedCheckbox");
1308
+ r(this, "shadingModeSelect");
1309
+ r(this, "shapeTypeSpan");
1310
+ this.editor = t;
1311
+ const i = document.getElementById(e);
1312
+ if (!i)
1313
+ throw new Error(`Property panel container not found: ${e}`);
1314
+ this.container = i, this.buildUI(), this.setupEventListeners();
1315
+ }
1316
+ /**
1317
+ * Build the property panel UI
1318
+ */
1319
+ buildUI() {
1320
+ this.container.innerHTML = `
1321
+ <div class="property-section" id="properties-transform">
1322
+ <div class="section-header">Transform</div>
1323
+ <div class="property-row">
1324
+ <label>Name</label>
1325
+ <input type="text" id="prop-name" class="prop-input prop-text" />
1326
+ </div>
1327
+ <div class="property-row">
1328
+ <label>Position</label>
1329
+ <div class="vec3-inputs">
1330
+ <input type="number" id="prop-pos-x" class="prop-input" step="0.1" />
1331
+ <input type="number" id="prop-pos-y" class="prop-input" step="0.1" />
1332
+ <input type="number" id="prop-pos-z" class="prop-input" step="0.1" />
1333
+ </div>
1334
+ </div>
1335
+ <div class="property-row">
1336
+ <label>Rotation</label>
1337
+ <div class="vec3-inputs">
1338
+ <input type="number" id="prop-rot-x" class="prop-input" step="1" />
1339
+ <input type="number" id="prop-rot-y" class="prop-input" step="1" />
1340
+ <input type="number" id="prop-rot-z" class="prop-input" step="1" />
1341
+ </div>
1342
+ </div>
1343
+ <div class="property-row">
1344
+ <label>Scale</label>
1345
+ <div class="vec3-inputs">
1346
+ <input type="number" id="prop-scale-x" class="prop-input" step="0.1" min="0.01" />
1347
+ <input type="number" id="prop-scale-y" class="prop-input" step="0.1" min="0.01" />
1348
+ <input type="number" id="prop-scale-z" class="prop-input" step="0.1" min="0.01" />
1349
+ </div>
1350
+ </div>
1351
+ </div>
1352
+
1353
+ <div class="property-section" id="properties-shape">
1354
+ <div class="section-header">Shape</div>
1355
+ <div class="property-row">
1356
+ <label>Type</label>
1357
+ <span id="prop-shape-type" class="prop-readonly">-</span>
1358
+ </div>
1359
+ <div class="property-row">
1360
+ <label>Size</label>
1361
+ <div class="vec3-inputs">
1362
+ <input type="number" id="prop-size-x" class="prop-input" step="1" min="0" />
1363
+ <input type="number" id="prop-size-y" class="prop-input" step="1" min="0" />
1364
+ <input type="number" id="prop-size-z" class="prop-input" step="1" min="0" />
1365
+ </div>
1366
+ </div>
1367
+ <div class="property-row">
1368
+ <label>Offset</label>
1369
+ <div class="vec3-inputs">
1370
+ <input type="number" id="prop-offset-x" class="prop-input" step="0.5" />
1371
+ <input type="number" id="prop-offset-y" class="prop-input" step="0.5" />
1372
+ <input type="number" id="prop-offset-z" class="prop-input" step="0.5" />
1373
+ </div>
1374
+ </div>
1375
+ <div class="property-row">
1376
+ <label>Visible</label>
1377
+ <input type="checkbox" id="prop-visible" class="prop-checkbox" />
1378
+ </div>
1379
+ <div class="property-row">
1380
+ <label>Double Sided</label>
1381
+ <input type="checkbox" id="prop-doublesided" class="prop-checkbox" />
1382
+ </div>
1383
+ <div class="property-row">
1384
+ <label>Shading</label>
1385
+ <select id="prop-shading" class="prop-select">
1386
+ <option value="standard">Standard</option>
1387
+ <option value="flat">Flat</option>
1388
+ <option value="fullbright">Fullbright</option>
1389
+ <option value="reflective">Reflective</option>
1390
+ </select>
1391
+ </div>
1392
+ </div>
1393
+
1394
+ <div class="property-empty" id="properties-empty">
1395
+ <p>Select an object to view properties</p>
1396
+ </div>
1397
+ `, this.nameInput = document.getElementById("prop-name"), this.posInputs = {
1398
+ x: document.getElementById("prop-pos-x"),
1399
+ y: document.getElementById("prop-pos-y"),
1400
+ z: document.getElementById("prop-pos-z")
1401
+ }, this.rotInputs = {
1402
+ x: document.getElementById("prop-rot-x"),
1403
+ y: document.getElementById("prop-rot-y"),
1404
+ z: document.getElementById("prop-rot-z")
1405
+ }, this.scaleInputs = {
1406
+ x: document.getElementById("prop-scale-x"),
1407
+ y: document.getElementById("prop-scale-y"),
1408
+ z: document.getElementById("prop-scale-z")
1409
+ }, this.sizeInputs = {
1410
+ x: document.getElementById("prop-size-x"),
1411
+ y: document.getElementById("prop-size-y"),
1412
+ z: document.getElementById("prop-size-z")
1413
+ }, this.offsetInputs = {
1414
+ x: document.getElementById("prop-offset-x"),
1415
+ y: document.getElementById("prop-offset-y"),
1416
+ z: document.getElementById("prop-offset-z")
1417
+ }, this.visibleCheckbox = document.getElementById("prop-visible"), this.doubleSidedCheckbox = document.getElementById("prop-doublesided"), this.shadingModeSelect = document.getElementById("prop-shading"), this.shapeTypeSpan = document.getElementById("prop-shape-type"), this.showEmpty();
1418
+ }
1419
+ /**
1420
+ * Setup event listeners
1421
+ */
1422
+ setupEventListeners() {
1423
+ this.editor.on("selectionChanged", (t) => {
1424
+ this.setObject(t);
1425
+ }), this.editor.on("objectChanged", () => {
1426
+ this.currentObject && this.updateFromObject();
1427
+ }), this.editor.transform.on("objectChanging", () => {
1428
+ this.currentObject && this.updateFromObject();
1429
+ }), this.nameInput.addEventListener("change", () => {
1430
+ if (this.currentObject && !this.isUpdating) {
1431
+ const t = this.currentObject.name, e = this.nameInput.value;
1432
+ this.editor.execute(new N(this.currentObject, "name", e, t));
1433
+ }
1434
+ }), this.setupVec3Input(this.posInputs, (t) => {
1435
+ if (this.currentObject && !this.isUpdating) {
1436
+ const e = this.currentObject.position.clone();
1437
+ this.editor.execute(new ut(this.currentObject, t, e));
1438
+ }
1439
+ }), this.setupVec3Input(this.rotInputs, (t) => {
1440
+ if (this.currentObject && !this.isUpdating) {
1441
+ const e = this.currentObject.rotation.clone(), i = new l.Euler(
1442
+ l.MathUtils.degToRad(t.x),
1443
+ l.MathUtils.degToRad(t.y),
1444
+ l.MathUtils.degToRad(t.z)
1445
+ );
1446
+ this.editor.execute(new mt(this.currentObject, i, e));
1447
+ }
1448
+ }), this.setupVec3Input(this.scaleInputs, (t) => {
1449
+ if (this.currentObject && !this.isUpdating) {
1450
+ const e = this.currentObject.scale.clone();
1451
+ this.editor.execute(new ft(this.currentObject, t, e));
1452
+ }
1453
+ }), this.setupVec3Input(this.sizeInputs, (t) => {
1454
+ if (this.currentObject && !this.isUpdating) {
1455
+ const e = this.currentObject.userData.originalSize || { x: 1, y: 1, z: 1 };
1456
+ this.editor.execute(
1457
+ new N(this.currentObject, "userData.originalSize", { x: t.x, y: t.y, z: t.z }, e)
1458
+ ), this.rebuildGeometry();
1459
+ }
1460
+ }), this.setupVec3Input(this.offsetInputs, (t) => {
1461
+ if (this.currentObject && !this.isUpdating) {
1462
+ const e = this.currentObject.userData.offset || { x: 0, y: 0, z: 0 };
1463
+ this.editor.execute(
1464
+ new N(this.currentObject, "userData.offset", { x: t.x, y: t.y, z: t.z }, e)
1465
+ ), this.rebuildGeometry();
1466
+ }
1467
+ }), this.visibleCheckbox.addEventListener("change", () => {
1468
+ if (this.currentObject && !this.isUpdating) {
1469
+ const t = this.currentObject.visible, e = this.visibleCheckbox.checked;
1470
+ this.editor.execute(new N(this.currentObject, "visible", e, t));
1471
+ }
1472
+ }), this.doubleSidedCheckbox.addEventListener("change", () => {
1473
+ if (this.currentObject && !this.isUpdating && this.currentObject instanceof l.Mesh) {
1474
+ const t = this.currentObject.material, e = t.side === l.DoubleSide, i = this.doubleSidedCheckbox.checked;
1475
+ t.side = i ? l.DoubleSide : l.FrontSide, this.currentObject.userData.doubleSided = i, this.editor.execute(
1476
+ new N(this.currentObject, "userData.doubleSided", i, e)
1477
+ );
1478
+ }
1479
+ }), this.shadingModeSelect.addEventListener("change", () => {
1480
+ if (this.currentObject && !this.isUpdating) {
1481
+ const t = this.currentObject.userData.shadingMode || "standard", e = this.shadingModeSelect.value;
1482
+ this.currentObject.userData.shadingMode = e, this.editor.execute(
1483
+ new N(this.currentObject, "userData.shadingMode", e, t)
1484
+ );
1485
+ }
1486
+ });
1487
+ }
1488
+ /**
1489
+ * Setup Vec3 input handlers
1490
+ */
1491
+ setupVec3Input(t, e) {
1492
+ const i = () => {
1493
+ const s = new l.Vector3(
1494
+ parseFloat(t.x.value) || 0,
1495
+ parseFloat(t.y.value) || 0,
1496
+ parseFloat(t.z.value) || 0
1497
+ );
1498
+ e(s);
1499
+ };
1500
+ t.x.addEventListener("change", i), t.y.addEventListener("change", i), t.z.addEventListener("change", i);
1501
+ }
1502
+ /**
1503
+ * Set the object to display properties for
1504
+ */
1505
+ setObject(t) {
1506
+ this.currentObject = t, t ? (this.showProperties(), this.updateFromObject()) : this.showEmpty();
1507
+ }
1508
+ /**
1509
+ * Update UI from current object
1510
+ */
1511
+ updateFromObject() {
1512
+ var o, n, h, d, u, y;
1513
+ if (!this.currentObject) return;
1514
+ this.isUpdating = !0;
1515
+ const t = this.currentObject;
1516
+ this.nameInput.value = t.name || "", this.posInputs.x.value = t.position.x.toFixed(2), this.posInputs.y.value = t.position.y.toFixed(2), this.posInputs.z.value = t.position.z.toFixed(2), this.rotInputs.x.value = l.MathUtils.radToDeg(t.rotation.x).toFixed(1), this.rotInputs.y.value = l.MathUtils.radToDeg(t.rotation.y).toFixed(1), this.rotInputs.z.value = l.MathUtils.radToDeg(t.rotation.z).toFixed(1), this.scaleInputs.x.value = t.scale.x.toFixed(2), this.scaleInputs.y.value = t.scale.y.toFixed(2), this.scaleInputs.z.value = t.scale.z.toFixed(2);
1517
+ const e = t.userData.shapeType || "none";
1518
+ this.shapeTypeSpan.textContent = e;
1519
+ const i = t.userData.originalSize || { x: 1, y: 1, z: 1 };
1520
+ this.sizeInputs.x.value = ((o = i.x) == null ? void 0 : o.toString()) || "1", this.sizeInputs.y.value = ((n = i.y) == null ? void 0 : n.toString()) || "1", this.sizeInputs.z.value = ((h = i.z) == null ? void 0 : h.toString()) || "1";
1521
+ const s = t.userData.offset || { x: 0, y: 0, z: 0 };
1522
+ if (this.offsetInputs.x.value = ((d = s.x) == null ? void 0 : d.toString()) || "0", this.offsetInputs.y.value = ((u = s.y) == null ? void 0 : u.toString()) || "0", this.offsetInputs.z.value = ((y = s.z) == null ? void 0 : y.toString()) || "0", this.visibleCheckbox.checked = t.visible, t instanceof l.Mesh) {
1523
+ const _ = t.material;
1524
+ this.doubleSidedCheckbox.checked = _.side === l.DoubleSide;
1525
+ } else
1526
+ this.doubleSidedCheckbox.checked = !1;
1527
+ this.shadingModeSelect.value = t.userData.shadingMode || "standard", this.isUpdating = !1;
1528
+ }
1529
+ /**
1530
+ * Rebuild geometry after size/offset changes
1531
+ */
1532
+ rebuildGeometry() {
1533
+ if (!this.currentObject || !(this.currentObject instanceof l.Mesh)) return;
1534
+ const t = this.currentObject, e = t.userData.originalSize || { x: 1, y: 1, z: 1 }, i = t.userData.offset || { x: 0, y: 0, z: 0 }, s = t.userData.stretch || { x: 1, y: 1, z: 1 }, o = {
1535
+ x: e.x * s.x,
1536
+ y: e.y * s.y,
1537
+ z: e.z * s.z
1538
+ };
1539
+ t.geometry.dispose(), t.userData.shapeType === "box" && (t.geometry = new l.BoxGeometry(o.x, o.y, o.z), t.geometry.translate(i.x, i.y, i.z));
1540
+ }
1541
+ /**
1542
+ * Show property sections
1543
+ */
1544
+ showProperties() {
1545
+ const t = document.getElementById("properties-transform"), e = document.getElementById("properties-shape"), i = document.getElementById("properties-empty");
1546
+ t && (t.style.display = "block"), e && (e.style.display = "block"), i && (i.style.display = "none");
1547
+ }
1548
+ /**
1549
+ * Show empty state
1550
+ */
1551
+ showEmpty() {
1552
+ const t = document.getElementById("properties-transform"), e = document.getElementById("properties-shape"), i = document.getElementById("properties-empty");
1553
+ t && (t.style.display = "none"), e && (e.style.display = "none"), i && (i.style.display = "block");
1554
+ }
1555
+ /**
1556
+ * Cleanup
1557
+ */
1558
+ dispose() {
1559
+ this.container.innerHTML = "";
1560
+ }
1561
+ }
1562
+ class Ve {
1563
+ constructor(t, e) {
1564
+ r(this, "editor");
1565
+ r(this, "container");
1566
+ r(this, "treeContainer");
1567
+ r(this, "contextMenu", null);
1568
+ r(this, "contextTarget", null);
1569
+ this.editor = t;
1570
+ const i = document.getElementById(e);
1571
+ if (!i)
1572
+ throw new Error(`Hierarchy panel container not found: ${e}`);
1573
+ this.container = i, this.buildUI(), this.setupEventListeners();
1574
+ }
1575
+ /**
1576
+ * Build the hierarchy panel UI
1577
+ */
1578
+ buildUI() {
1579
+ this.container.innerHTML = `
1580
+ <div class="hierarchy-tree" id="hierarchy-tree"></div>
1581
+ `, this.treeContainer = document.getElementById("hierarchy-tree"), this.contextMenu = document.createElement("div"), this.contextMenu.className = "context-menu", this.contextMenu.innerHTML = `
1582
+ <div class="context-menu-item" data-action="add-box">Add Child Box</div>
1583
+ <div class="context-menu-item" data-action="add-group">Add Child Group</div>
1584
+ <div class="context-menu-separator"></div>
1585
+ <div class="context-menu-item" data-action="duplicate">Duplicate</div>
1586
+ <div class="context-menu-separator"></div>
1587
+ <div class="context-menu-item context-menu-danger" data-action="delete">Delete</div>
1588
+ `, this.contextMenu.style.display = "none", document.body.appendChild(this.contextMenu);
1589
+ }
1590
+ /**
1591
+ * Setup event listeners
1592
+ */
1593
+ setupEventListeners() {
1594
+ var t;
1595
+ this.editor.on("modelLoaded", () => {
1596
+ this.refresh();
1597
+ }), this.editor.on("selectionChanged", () => {
1598
+ this.updateSelection();
1599
+ }), this.editor.on("objectChanged", () => {
1600
+ this.refresh();
1601
+ }), (t = this.contextMenu) == null || t.addEventListener("click", (e) => {
1602
+ const s = e.target.dataset.action;
1603
+ s && this.contextTarget && this.handleContextAction(s, this.contextTarget), this.hideContextMenu();
1604
+ }), document.addEventListener("click", (e) => {
1605
+ this.contextMenu && !this.contextMenu.contains(e.target) && this.hideContextMenu();
1606
+ }), document.addEventListener("keydown", (e) => {
1607
+ if (e.key === "Delete" || e.key === "Backspace") {
1608
+ const i = this.editor.getSelected();
1609
+ i && i.parent && !(e.target instanceof HTMLInputElement) && this.deleteNode(i);
1610
+ }
1611
+ });
1612
+ }
1613
+ /**
1614
+ * Refresh the hierarchy tree
1615
+ */
1616
+ refresh() {
1617
+ const t = this.editor.getModel();
1618
+ if (!t) {
1619
+ this.treeContainer.innerHTML = '<p class="hierarchy-empty">No model loaded</p>';
1620
+ return;
1621
+ }
1622
+ this.treeContainer.innerHTML = "", this.buildTree(t, this.treeContainer, 0);
1623
+ }
1624
+ /**
1625
+ * Build tree recursively
1626
+ */
1627
+ buildTree(t, e, i) {
1628
+ const s = document.createElement("div");
1629
+ s.className = "hierarchy-item", s.dataset.objectId = t.uuid;
1630
+ const o = document.createElement("span");
1631
+ o.className = "hierarchy-indent", o.style.width = `${i * 16}px`;
1632
+ const n = document.createElement("span");
1633
+ n.className = "hierarchy-expander", t.children.length > 0 && (n.textContent = "▼", n.addEventListener("click", (u) => {
1634
+ u.stopPropagation(), this.toggleExpand(s);
1635
+ }));
1636
+ const h = document.createElement("span");
1637
+ h.className = "hierarchy-icon", h.textContent = this.getIcon(t);
1638
+ const d = document.createElement("span");
1639
+ if (d.className = "hierarchy-label", d.textContent = t.name || `(${t.type})`, s.appendChild(o), s.appendChild(n), s.appendChild(h), s.appendChild(d), s.addEventListener("click", () => {
1640
+ this.editor.select(t);
1641
+ }), s.addEventListener("contextmenu", (u) => {
1642
+ u.preventDefault(), this.showContextMenu(u, t);
1643
+ }), e.appendChild(s), t.children.length > 0) {
1644
+ const u = document.createElement("div");
1645
+ u.className = "hierarchy-children";
1646
+ for (const y of t.children)
1647
+ y.type === "TransformControlsGizmo" || y.type === "TransformControlsPlane" || this.buildTree(y, u, i + 1);
1648
+ e.appendChild(u);
1649
+ }
1650
+ }
1651
+ /**
1652
+ * Get icon for object type
1653
+ */
1654
+ getIcon(t) {
1655
+ if (t instanceof l.Mesh) {
1656
+ const e = t.userData.shapeType;
1657
+ return e === "box" ? "📦" : e === "quad" ? "▫️" : "🔷";
1658
+ }
1659
+ return t instanceof l.Group ? "📁" : "◯";
1660
+ }
1661
+ /**
1662
+ * Toggle expand/collapse
1663
+ */
1664
+ toggleExpand(t) {
1665
+ const e = t.nextElementSibling;
1666
+ if (e != null && e.classList.contains("hierarchy-children")) {
1667
+ const i = e.classList.toggle("collapsed"), s = t.querySelector(".hierarchy-expander");
1668
+ s && (s.textContent = i ? "▶" : "▼");
1669
+ }
1670
+ }
1671
+ /**
1672
+ * Update selection highlight
1673
+ */
1674
+ updateSelection() {
1675
+ this.treeContainer.querySelectorAll(".hierarchy-item.selected").forEach((e) => {
1676
+ e.classList.remove("selected");
1677
+ });
1678
+ const t = this.editor.getSelected();
1679
+ if (t) {
1680
+ const e = this.treeContainer.querySelector(`[data-object-id="${t.uuid}"]`);
1681
+ e && (e.classList.add("selected"), e.scrollIntoView({ behavior: "smooth", block: "nearest" }));
1682
+ }
1683
+ }
1684
+ /**
1685
+ * Show context menu
1686
+ */
1687
+ showContextMenu(t, e) {
1688
+ if (!this.contextMenu) return;
1689
+ this.contextTarget = e, this.contextMenu.style.display = "block", this.contextMenu.style.left = `${t.clientX}px`, this.contextMenu.style.top = `${t.clientY}px`;
1690
+ const i = this.contextMenu.getBoundingClientRect();
1691
+ i.right > window.innerWidth && (this.contextMenu.style.left = `${window.innerWidth - i.width - 10}px`), i.bottom > window.innerHeight && (this.contextMenu.style.top = `${window.innerHeight - i.height - 10}px`);
1692
+ }
1693
+ /**
1694
+ * Hide context menu
1695
+ */
1696
+ hideContextMenu() {
1697
+ this.contextMenu && (this.contextMenu.style.display = "none"), this.contextTarget = null;
1698
+ }
1699
+ /**
1700
+ * Handle context menu action
1701
+ */
1702
+ handleContextAction(t, e) {
1703
+ switch (t) {
1704
+ case "add-box":
1705
+ this.addChildBox(e);
1706
+ break;
1707
+ case "add-group":
1708
+ this.addChildGroup(e);
1709
+ break;
1710
+ case "duplicate":
1711
+ this.duplicateNode(e);
1712
+ break;
1713
+ case "delete":
1714
+ this.deleteNode(e);
1715
+ break;
1716
+ }
1717
+ }
1718
+ /**
1719
+ * Add a child box
1720
+ */
1721
+ addChildBox(t) {
1722
+ const e = new l.BoxGeometry(10, 10, 10), i = new l.MeshStandardMaterial({ color: 8947848, roughness: 0.7 }), s = new l.Mesh(e, i);
1723
+ s.name = `Box_${Date.now().toString(36)}`, s.userData.id = s.name, s.userData.shapeType = "box", s.userData.originalSize = { x: 10, y: 10, z: 10 }, this.editor.execute(new wt(t, s)), this.editor.select(s);
1724
+ }
1725
+ /**
1726
+ * Add a child group
1727
+ */
1728
+ addChildGroup(t) {
1729
+ const e = new l.Group();
1730
+ e.name = `Group_${Date.now().toString(36)}`, e.userData.id = e.name, e.userData.shapeType = "none", this.editor.execute(new wt(t, e)), this.editor.select(e);
1731
+ }
1732
+ /**
1733
+ * Duplicate a node
1734
+ */
1735
+ duplicateNode(t) {
1736
+ if (!t.parent) return;
1737
+ const e = t.clone(!0);
1738
+ e.name = `${t.name}_copy`, e.userData.id = e.name, e.position.x += 10, this.editor.execute(new wt(t.parent, e)), this.editor.select(e);
1739
+ }
1740
+ /**
1741
+ * Delete a node
1742
+ */
1743
+ deleteNode(t) {
1744
+ if (!t.parent) return;
1745
+ const e = this.editor.getModel();
1746
+ t !== e && (this.editor.execute(new Me(t)), this.editor.select(null));
1747
+ }
1748
+ /**
1749
+ * Cleanup
1750
+ */
1751
+ dispose() {
1752
+ this.contextMenu && document.body.removeChild(this.contextMenu), this.container.innerHTML = "";
1753
+ }
1754
+ }
1755
+ const J = ["front", "back", "left", "right", "top", "bottom"], Ee = {
1756
+ front: "Front (+Z)",
1757
+ back: "Back (-Z)",
1758
+ left: "Left (-X)",
1759
+ right: "Right (+X)",
1760
+ top: "Top (+Y)",
1761
+ bottom: "Bottom (-Y)"
1762
+ }, _t = {
1763
+ offset: { x: 0, y: 0 },
1764
+ mirror: { x: !1, y: !1 },
1765
+ angle: 0
1766
+ };
1767
+ class Ge {
1768
+ constructor(t, e) {
1769
+ r(this, "editor");
1770
+ r(this, "container");
1771
+ r(this, "currentObject", null);
1772
+ r(this, "isUpdating", !1);
1773
+ r(this, "faceInputs", /* @__PURE__ */ new Map());
1774
+ this.editor = t;
1775
+ const i = document.getElementById(e);
1776
+ if (!i)
1777
+ throw new Error(`UV Editor container not found: ${e}`);
1778
+ this.container = i, this.buildUI(), this.setupEventListeners();
1779
+ }
1780
+ /**
1781
+ * Build the UV editor UI
1782
+ */
1783
+ buildUI() {
1784
+ let t = "";
1785
+ for (const e of J)
1786
+ t += `
1787
+ <div class="uv-face">
1788
+ <div class="uv-face-header">${Ee[e]}</div>
1789
+ <div class="uv-face-row">
1790
+ <label>Offset</label>
1791
+ <input type="number" id="uv-${e}-offset-x" class="uv-input" step="1" placeholder="X" />
1792
+ <input type="number" id="uv-${e}-offset-y" class="uv-input" step="1" placeholder="Y" />
1793
+ </div>
1794
+ <div class="uv-face-row">
1795
+ <label>Mirror</label>
1796
+ <label class="uv-checkbox-label">
1797
+ <input type="checkbox" id="uv-${e}-mirror-x" class="uv-checkbox" /> X
1798
+ </label>
1799
+ <label class="uv-checkbox-label">
1800
+ <input type="checkbox" id="uv-${e}-mirror-y" class="uv-checkbox" /> Y
1801
+ </label>
1802
+ </div>
1803
+ <div class="uv-face-row">
1804
+ <label>Rotation</label>
1805
+ <select id="uv-${e}-angle" class="uv-select">
1806
+ <option value="0">0°</option>
1807
+ <option value="90">90°</option>
1808
+ <option value="180">180°</option>
1809
+ <option value="270">270°</option>
1810
+ </select>
1811
+ </div>
1812
+ </div>
1813
+ `;
1814
+ this.container.innerHTML = `
1815
+ <div class="uv-editor-content" id="uv-editor-content">
1816
+ ${t}
1817
+ </div>
1818
+ <div class="uv-editor-empty" id="uv-editor-empty">
1819
+ <p>Select a box to edit UVs</p>
1820
+ </div>
1821
+ `;
1822
+ for (const e of J)
1823
+ this.faceInputs.set(e, {
1824
+ offsetX: document.getElementById(`uv-${e}-offset-x`),
1825
+ offsetY: document.getElementById(`uv-${e}-offset-y`),
1826
+ mirrorX: document.getElementById(`uv-${e}-mirror-x`),
1827
+ mirrorY: document.getElementById(`uv-${e}-mirror-y`),
1828
+ angle: document.getElementById(`uv-${e}-angle`)
1829
+ });
1830
+ this.showEmpty();
1831
+ }
1832
+ /**
1833
+ * Setup event listeners
1834
+ */
1835
+ setupEventListeners() {
1836
+ this.editor.on("selectionChanged", (t) => {
1837
+ this.setObject(t);
1838
+ }), this.editor.on("objectChanged", () => {
1839
+ this.currentObject && this.updateFromObject();
1840
+ });
1841
+ for (const t of J) {
1842
+ const e = this.faceInputs.get(t);
1843
+ e.offsetX.addEventListener("change", () => {
1844
+ this.handleFaceChange(t);
1845
+ }), e.offsetY.addEventListener("change", () => {
1846
+ this.handleFaceChange(t);
1847
+ }), e.mirrorX.addEventListener("change", () => {
1848
+ this.handleFaceChange(t);
1849
+ }), e.mirrorY.addEventListener("change", () => {
1850
+ this.handleFaceChange(t);
1851
+ }), e.angle.addEventListener("change", () => {
1852
+ this.handleFaceChange(t);
1853
+ });
1854
+ }
1855
+ }
1856
+ /**
1857
+ * Handle face UV change
1858
+ */
1859
+ handleFaceChange(t) {
1860
+ if (!this.currentObject || this.isUpdating) return;
1861
+ const e = this.faceInputs.get(t), i = this.getTextureLayout();
1862
+ i[t] || { ..._t };
1863
+ const s = {
1864
+ offset: {
1865
+ x: parseInt(e.offsetX.value) || 0,
1866
+ y: parseInt(e.offsetY.value) || 0
1867
+ },
1868
+ mirror: {
1869
+ x: e.mirrorX.checked,
1870
+ y: e.mirrorY.checked
1871
+ },
1872
+ angle: parseInt(e.angle.value)
1873
+ }, o = { ...i, [t]: s };
1874
+ this.editor.execute(
1875
+ new N(
1876
+ this.currentObject,
1877
+ "userData.textureLayout",
1878
+ o,
1879
+ i
1880
+ )
1881
+ ), this.applyTextureLayout(o);
1882
+ }
1883
+ /**
1884
+ * Get texture layout from current object
1885
+ */
1886
+ getTextureLayout() {
1887
+ var t;
1888
+ return ((t = this.currentObject) == null ? void 0 : t.userData.textureLayout) || {};
1889
+ }
1890
+ /**
1891
+ * Set the object to edit UVs for
1892
+ */
1893
+ setObject(t) {
1894
+ t && t instanceof l.Mesh && t.userData.shapeType === "box" ? (this.currentObject = t, this.showContent(), this.updateFromObject()) : (this.currentObject = null, this.showEmpty());
1895
+ }
1896
+ /**
1897
+ * Update UI from current object
1898
+ */
1899
+ updateFromObject() {
1900
+ var e, i, s, o, n, h, d;
1901
+ if (!this.currentObject) return;
1902
+ this.isUpdating = !0;
1903
+ const t = this.getTextureLayout();
1904
+ for (const u of J) {
1905
+ const y = this.faceInputs.get(u), _ = t[u] || _t;
1906
+ y.offsetX.value = ((i = (e = _.offset) == null ? void 0 : e.x) == null ? void 0 : i.toString()) || "0", y.offsetY.value = ((o = (s = _.offset) == null ? void 0 : s.y) == null ? void 0 : o.toString()) || "0", y.mirrorX.checked = ((n = _.mirror) == null ? void 0 : n.x) || !1, y.mirrorY.checked = ((h = _.mirror) == null ? void 0 : h.y) || !1, y.angle.value = ((d = _.angle) == null ? void 0 : d.toString()) || "0";
1907
+ }
1908
+ this.isUpdating = !1;
1909
+ }
1910
+ /**
1911
+ * Apply texture layout to geometry UVs
1912
+ * Note: This is a simplified implementation - full UV mapping would require
1913
+ * knowing the texture atlas dimensions
1914
+ */
1915
+ applyTextureLayout(t) {
1916
+ var h, d, u, y;
1917
+ if (!this.currentObject || !(this.currentObject instanceof l.Mesh)) return;
1918
+ const s = this.currentObject.geometry.getAttribute("uv");
1919
+ if (!s) return;
1920
+ const o = {
1921
+ right: 0,
1922
+ left: 1,
1923
+ top: 2,
1924
+ bottom: 3,
1925
+ front: 4,
1926
+ back: 5
1927
+ }, n = s.array;
1928
+ for (const _ of J) {
1929
+ const D = t[_] || _t, B = o[_] * 6, z = (((h = D.offset) == null ? void 0 : h.x) || 0) / 64, O = (((d = D.offset) == null ? void 0 : d.y) || 0) / 64;
1930
+ for (let M = 0; M < 6; M++) {
1931
+ const E = (B + M) * 2;
1932
+ let b = n[E], T = n[E + 1];
1933
+ if ((u = D.mirror) != null && u.x && (b = 1 - b), (y = D.mirror) != null && y.y && (T = 1 - T), D.angle) {
1934
+ const k = D.angle * Math.PI / 180, A = b - 0.5, it = T - 0.5;
1935
+ b = A * Math.cos(k) - it * Math.sin(k) + 0.5, T = A * Math.sin(k) + it * Math.cos(k) + 0.5;
1936
+ }
1937
+ n[E] = b + z, n[E + 1] = T + O;
1938
+ }
1939
+ }
1940
+ s.needsUpdate = !0;
1941
+ }
1942
+ /**
1943
+ * Show content
1944
+ */
1945
+ showContent() {
1946
+ const t = document.getElementById("uv-editor-content"), e = document.getElementById("uv-editor-empty");
1947
+ t && (t.style.display = "block"), e && (e.style.display = "none");
1948
+ }
1949
+ /**
1950
+ * Show empty state
1951
+ */
1952
+ showEmpty() {
1953
+ const t = document.getElementById("uv-editor-content"), e = document.getElementById("uv-editor-empty");
1954
+ t && (t.style.display = "none"), e && (e.style.display = "block");
1955
+ }
1956
+ /**
1957
+ * Cleanup
1958
+ */
1959
+ dispose() {
1960
+ this.container.innerHTML = "", this.faceInputs.clear();
1961
+ }
1962
+ }
1963
+ const xt = { x: 0, y: 0, z: 0 }, ve = { w: 1, x: 0, y: 0, z: 0 }, Rt = { x: 1, y: 1, z: 1 };
1964
+ class Pe extends l.Loader {
1965
+ constructor(t) {
1966
+ super(t);
1967
+ }
1968
+ /**
1969
+ * Load a .blockymodel file from URL
1970
+ */
1971
+ async load(t) {
1972
+ const e = await fetch(t);
1973
+ if (!e.ok)
1974
+ throw new Error(`Failed to load model: ${e.statusText}`);
1975
+ const i = await e.json();
1976
+ return this.parse(i);
1977
+ }
1978
+ /**
1979
+ * Load from File object (for drag-drop / file input)
1980
+ */
1981
+ async loadFromFile(t) {
1982
+ const e = await t.text(), i = JSON.parse(e);
1983
+ return this.parse(i);
1984
+ }
1985
+ /**
1986
+ * Parse BlockyModel JSON into Three.js scene graph
1987
+ */
1988
+ parse(t) {
1989
+ const e = new l.Group();
1990
+ e.name = "BlockyModel", e.userData.format = t.format, e.userData.lod = t.lod;
1991
+ for (const i of t.nodes) {
1992
+ const s = this.parseNode(i);
1993
+ e.add(s);
1994
+ }
1995
+ return e;
1996
+ }
1997
+ /**
1998
+ * Recursively parse a BlockyNode into Three.js Object3D
1999
+ */
2000
+ parseNode(t) {
2001
+ var o, n;
2002
+ const e = this.createNodeObject(t);
2003
+ e.name = t.name, e.userData.id = t.id, e.userData.isPiece = ((n = (o = t.shape) == null ? void 0 : o.settings) == null ? void 0 : n.isPiece) ?? !1;
2004
+ const i = t.position ?? xt;
2005
+ e.position.set(i.x, i.y, i.z);
2006
+ const s = t.orientation ?? ve;
2007
+ e.quaternion.set(s.x, s.y, s.z, s.w);
2008
+ for (const h of t.children ?? []) {
2009
+ const d = this.parseNode(h);
2010
+ e.add(d);
2011
+ }
2012
+ return e;
2013
+ }
2014
+ /**
2015
+ * Create the appropriate Object3D based on shape type
2016
+ */
2017
+ createNodeObject(t) {
2018
+ const e = t.shape;
2019
+ if (!e || e.type === "none" || !e.visible) {
2020
+ const i = new l.Group();
2021
+ return i.userData.shapeType = (e == null ? void 0 : e.type) ?? "none", i;
2022
+ }
2023
+ return e.type === "box" ? this.createBox(e) : e.type === "quad" ? this.createQuad(e) : new l.Group();
2024
+ }
2025
+ /**
2026
+ * Create a box mesh from shape data
2027
+ */
2028
+ createBox(t) {
2029
+ const e = t.settings.size ?? { x: 1, y: 1, z: 1 }, i = t.stretch ?? Rt, s = t.offset ?? xt, o = {
2030
+ x: e.x * i.x,
2031
+ y: e.y * i.y,
2032
+ z: e.z * i.z
2033
+ }, n = new l.BoxGeometry(o.x, o.y, o.z);
2034
+ n.translate(s.x, s.y, s.z);
2035
+ const h = this.createMaterial(t), d = new l.Mesh(n, h);
2036
+ return d.userData.shapeType = "box", d.userData.originalSize = e, d.userData.shadingMode = t.shadingMode, t.doubleSided && (h.side = l.DoubleSide), d;
2037
+ }
2038
+ /**
2039
+ * Create a quad (plane) mesh from shape data
2040
+ */
2041
+ createQuad(t) {
2042
+ const e = t.settings.size ?? { x: 1, y: 1, z: 0 }, i = t.stretch ?? Rt, s = t.offset ?? xt, o = t.settings.normal ?? "+Z";
2043
+ let n, h;
2044
+ switch (o) {
2045
+ case "+X":
2046
+ case "-X":
2047
+ n = e.z * i.z, h = e.y * i.y;
2048
+ break;
2049
+ case "+Y":
2050
+ case "-Y":
2051
+ n = e.x * i.x, h = e.z * i.z;
2052
+ break;
2053
+ case "+Z":
2054
+ case "-Z":
2055
+ default:
2056
+ n = e.x * i.x, h = e.y * i.y;
2057
+ break;
2058
+ }
2059
+ const d = new l.PlaneGeometry(n, h);
2060
+ switch (o) {
2061
+ case "+X":
2062
+ d.rotateY(Math.PI / 2);
2063
+ break;
2064
+ case "-X":
2065
+ d.rotateY(-Math.PI / 2);
2066
+ break;
2067
+ case "+Y":
2068
+ d.rotateX(-Math.PI / 2);
2069
+ break;
2070
+ case "-Y":
2071
+ d.rotateX(Math.PI / 2);
2072
+ break;
2073
+ case "-Z":
2074
+ d.rotateY(Math.PI);
2075
+ break;
2076
+ }
2077
+ d.translate(s.x, s.y, s.z);
2078
+ const u = this.createMaterial(t);
2079
+ u.side = t.doubleSided ? l.DoubleSide : l.FrontSide;
2080
+ const y = new l.Mesh(d, u);
2081
+ return y.userData.shapeType = "quad", y.userData.shadingMode = t.shadingMode, y;
2082
+ }
2083
+ /**
2084
+ * Create material based on shading mode
2085
+ * Phase 1: Basic color material, texture mapping in Phase 2
2086
+ */
2087
+ createMaterial(t) {
2088
+ switch (t.shadingMode) {
2089
+ case "fullbright":
2090
+ return new l.MeshStandardMaterial({
2091
+ color: 8947848,
2092
+ emissive: 8947848,
2093
+ emissiveIntensity: 1,
2094
+ roughness: 1,
2095
+ metalness: 0
2096
+ });
2097
+ case "flat":
2098
+ return new l.MeshStandardMaterial({
2099
+ color: 8947848,
2100
+ flatShading: !0,
2101
+ roughness: 0.9,
2102
+ metalness: 0
2103
+ });
2104
+ case "reflective":
2105
+ return new l.MeshStandardMaterial({
2106
+ color: 8947848,
2107
+ roughness: 0.1,
2108
+ metalness: 0.8
2109
+ });
2110
+ case "standard":
2111
+ default:
2112
+ return new l.MeshStandardMaterial({
2113
+ color: 8947848,
2114
+ roughness: 0.7,
2115
+ metalness: 0
2116
+ });
2117
+ }
2118
+ }
2119
+ }
2120
+ function Ie(a, t) {
2121
+ t.magFilter = l.NearestFilter, t.minFilter = l.NearestFilter, t.colorSpace = l.SRGBColorSpace, a.traverse((e) => {
2122
+ if (e instanceof l.Mesh) {
2123
+ const i = e.material;
2124
+ i.isMeshStandardMaterial && (i.map = t, i.color.setHex(16777215), i.needsUpdate = !0);
2125
+ }
2126
+ });
2127
+ }
2128
+ const At = { type: "change" }, Et = { type: "start" }, Xt = { type: "end" }, dt = new ne(), Yt = new oe(), Te = Math.cos(70 * ae.DEG2RAD), w = new p(), I = 2 * Math.PI, m = {
2129
+ NONE: -1,
2130
+ ROTATE: 0,
2131
+ DOLLY: 1,
2132
+ PAN: 2,
2133
+ TOUCH_ROTATE: 3,
2134
+ TOUCH_PAN: 4,
2135
+ TOUCH_DOLLY_PAN: 5,
2136
+ TOUCH_DOLLY_ROTATE: 6
2137
+ }, St = 1e-6;
2138
+ class De extends Ht {
2139
+ constructor(t, e = null) {
2140
+ super(t, e), this.state = m.NONE, this.enabled = !0, this.target = new p(), this.cursor = new p(), this.minDistance = 0, this.maxDistance = 1 / 0, this.minZoom = 0, this.maxZoom = 1 / 0, this.minTargetRadius = 0, this.maxTargetRadius = 1 / 0, this.minPolarAngle = 0, this.maxPolarAngle = Math.PI, this.minAzimuthAngle = -1 / 0, this.maxAzimuthAngle = 1 / 0, this.enableDamping = !1, this.dampingFactor = 0.05, this.enableZoom = !0, this.zoomSpeed = 1, this.enableRotate = !0, this.rotateSpeed = 1, this.enablePan = !0, this.panSpeed = 1, this.screenSpacePanning = !0, this.keyPanSpeed = 7, this.zoomToCursor = !1, this.autoRotate = !1, this.autoRotateSpeed = 2, this.keys = { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" }, this.mouseButtons = { LEFT: G.ROTATE, MIDDLE: G.DOLLY, RIGHT: G.PAN }, this.touches = { ONE: V.ROTATE, TWO: V.DOLLY_PAN }, this.target0 = this.target.clone(), this.position0 = this.object.position.clone(), this.zoom0 = this.object.zoom, this._domElementKeyEvents = null, this._lastPosition = new p(), this._lastQuaternion = new L(), this._lastTargetPosition = new p(), this._quat = new L().setFromUnitVectors(t.up, new p(0, 1, 0)), this._quatInverse = this._quat.clone().invert(), this._spherical = new Tt(), this._sphericalDelta = new Tt(), this._scale = 1, this._panOffset = new p(), this._rotateStart = new R(), this._rotateEnd = new R(), this._rotateDelta = new R(), this._panStart = new R(), this._panEnd = new R(), this._panDelta = new R(), this._dollyStart = new R(), this._dollyEnd = new R(), this._dollyDelta = new R(), this._dollyDirection = new p(), this._mouse = new R(), this._performCursorZoom = !1, this._pointers = [], this._pointerPositions = {}, this._controlActive = !1, this._onPointerMove = Le.bind(this), this._onPointerDown = Ce.bind(this), this._onPointerUp = ze.bind(this), this._onContextMenu = He.bind(this), this._onMouseWheel = je.bind(this), this._onKeyDown = Re.bind(this), this._onTouchStart = Ae.bind(this), this._onTouchMove = Ye.bind(this), this._onMouseDown = Oe.bind(this), this._onMouseMove = ke.bind(this), this._interceptControlDown = Ne.bind(this), this._interceptControlUp = Fe.bind(this), this.domElement !== null && this.connect(), this.update();
2141
+ }
2142
+ connect() {
2143
+ this.domElement.addEventListener("pointerdown", this._onPointerDown), this.domElement.addEventListener("pointercancel", this._onPointerUp), this.domElement.addEventListener("contextmenu", this._onContextMenu), this.domElement.addEventListener("wheel", this._onMouseWheel, { passive: !1 }), this.domElement.getRootNode().addEventListener("keydown", this._interceptControlDown, { passive: !0, capture: !0 }), this.domElement.style.touchAction = "none";
2144
+ }
2145
+ disconnect() {
2146
+ this.domElement.removeEventListener("pointerdown", this._onPointerDown), this.domElement.removeEventListener("pointermove", this._onPointerMove), this.domElement.removeEventListener("pointerup", this._onPointerUp), this.domElement.removeEventListener("pointercancel", this._onPointerUp), this.domElement.removeEventListener("wheel", this._onMouseWheel), this.domElement.removeEventListener("contextmenu", this._onContextMenu), this.stopListenToKeyEvents(), this.domElement.getRootNode().removeEventListener("keydown", this._interceptControlDown, { capture: !0 }), this.domElement.style.touchAction = "auto";
2147
+ }
2148
+ dispose() {
2149
+ this.disconnect();
2150
+ }
2151
+ getPolarAngle() {
2152
+ return this._spherical.phi;
2153
+ }
2154
+ getAzimuthalAngle() {
2155
+ return this._spherical.theta;
2156
+ }
2157
+ getDistance() {
2158
+ return this.object.position.distanceTo(this.target);
2159
+ }
2160
+ listenToKeyEvents(t) {
2161
+ t.addEventListener("keydown", this._onKeyDown), this._domElementKeyEvents = t;
2162
+ }
2163
+ stopListenToKeyEvents() {
2164
+ this._domElementKeyEvents !== null && (this._domElementKeyEvents.removeEventListener("keydown", this._onKeyDown), this._domElementKeyEvents = null);
2165
+ }
2166
+ saveState() {
2167
+ this.target0.copy(this.target), this.position0.copy(this.object.position), this.zoom0 = this.object.zoom;
2168
+ }
2169
+ reset() {
2170
+ this.target.copy(this.target0), this.object.position.copy(this.position0), this.object.zoom = this.zoom0, this.object.updateProjectionMatrix(), this.dispatchEvent(At), this.update(), this.state = m.NONE;
2171
+ }
2172
+ update(t = null) {
2173
+ const e = this.object.position;
2174
+ w.copy(e).sub(this.target), w.applyQuaternion(this._quat), this._spherical.setFromVector3(w), this.autoRotate && this.state === m.NONE && this._rotateLeft(this._getAutoRotationAngle(t)), this.enableDamping ? (this._spherical.theta += this._sphericalDelta.theta * this.dampingFactor, this._spherical.phi += this._sphericalDelta.phi * this.dampingFactor) : (this._spherical.theta += this._sphericalDelta.theta, this._spherical.phi += this._sphericalDelta.phi);
2175
+ let i = this.minAzimuthAngle, s = this.maxAzimuthAngle;
2176
+ isFinite(i) && isFinite(s) && (i < -Math.PI ? i += I : i > Math.PI && (i -= I), s < -Math.PI ? s += I : s > Math.PI && (s -= I), i <= s ? this._spherical.theta = Math.max(i, Math.min(s, this._spherical.theta)) : this._spherical.theta = this._spherical.theta > (i + s) / 2 ? Math.max(i, this._spherical.theta) : Math.min(s, this._spherical.theta)), this._spherical.phi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, this._spherical.phi)), this._spherical.makeSafe(), this.enableDamping === !0 ? this.target.addScaledVector(this._panOffset, this.dampingFactor) : this.target.add(this._panOffset), this.target.sub(this.cursor), this.target.clampLength(this.minTargetRadius, this.maxTargetRadius), this.target.add(this.cursor);
2177
+ let o = !1;
2178
+ if (this.zoomToCursor && this._performCursorZoom || this.object.isOrthographicCamera)
2179
+ this._spherical.radius = this._clampDistance(this._spherical.radius);
2180
+ else {
2181
+ const n = this._spherical.radius;
2182
+ this._spherical.radius = this._clampDistance(this._spherical.radius * this._scale), o = n != this._spherical.radius;
2183
+ }
2184
+ if (w.setFromSpherical(this._spherical), w.applyQuaternion(this._quatInverse), e.copy(this.target).add(w), this.object.lookAt(this.target), this.enableDamping === !0 ? (this._sphericalDelta.theta *= 1 - this.dampingFactor, this._sphericalDelta.phi *= 1 - this.dampingFactor, this._panOffset.multiplyScalar(1 - this.dampingFactor)) : (this._sphericalDelta.set(0, 0, 0), this._panOffset.set(0, 0, 0)), this.zoomToCursor && this._performCursorZoom) {
2185
+ let n = null;
2186
+ if (this.object.isPerspectiveCamera) {
2187
+ const h = w.length();
2188
+ n = this._clampDistance(h * this._scale);
2189
+ const d = h - n;
2190
+ this.object.position.addScaledVector(this._dollyDirection, d), this.object.updateMatrixWorld(), o = !!d;
2191
+ } else if (this.object.isOrthographicCamera) {
2192
+ const h = new p(this._mouse.x, this._mouse.y, 0);
2193
+ h.unproject(this.object);
2194
+ const d = this.object.zoom;
2195
+ this.object.zoom = Math.max(this.minZoom, Math.min(this.maxZoom, this.object.zoom / this._scale)), this.object.updateProjectionMatrix(), o = d !== this.object.zoom;
2196
+ const u = new p(this._mouse.x, this._mouse.y, 0);
2197
+ u.unproject(this.object), this.object.position.sub(u).add(h), this.object.updateMatrixWorld(), n = w.length();
2198
+ } else
2199
+ console.warn("WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled."), this.zoomToCursor = !1;
2200
+ n !== null && (this.screenSpacePanning ? this.target.set(0, 0, -1).transformDirection(this.object.matrix).multiplyScalar(n).add(this.object.position) : (dt.origin.copy(this.object.position), dt.direction.set(0, 0, -1).transformDirection(this.object.matrix), Math.abs(this.object.up.dot(dt.direction)) < Te ? this.object.lookAt(this.target) : (Yt.setFromNormalAndCoplanarPoint(this.object.up, this.target), dt.intersectPlane(Yt, this.target))));
2201
+ } else if (this.object.isOrthographicCamera) {
2202
+ const n = this.object.zoom;
2203
+ this.object.zoom = Math.max(this.minZoom, Math.min(this.maxZoom, this.object.zoom / this._scale)), n !== this.object.zoom && (this.object.updateProjectionMatrix(), o = !0);
2204
+ }
2205
+ return this._scale = 1, this._performCursorZoom = !1, o || this._lastPosition.distanceToSquared(this.object.position) > St || 8 * (1 - this._lastQuaternion.dot(this.object.quaternion)) > St || this._lastTargetPosition.distanceToSquared(this.target) > St ? (this.dispatchEvent(At), this._lastPosition.copy(this.object.position), this._lastQuaternion.copy(this.object.quaternion), this._lastTargetPosition.copy(this.target), !0) : !1;
2206
+ }
2207
+ _getAutoRotationAngle(t) {
2208
+ return t !== null ? I / 60 * this.autoRotateSpeed * t : I / 60 / 60 * this.autoRotateSpeed;
2209
+ }
2210
+ _getZoomScale(t) {
2211
+ const e = Math.abs(t * 0.01);
2212
+ return Math.pow(0.95, this.zoomSpeed * e);
2213
+ }
2214
+ _rotateLeft(t) {
2215
+ this._sphericalDelta.theta -= t;
2216
+ }
2217
+ _rotateUp(t) {
2218
+ this._sphericalDelta.phi -= t;
2219
+ }
2220
+ _panLeft(t, e) {
2221
+ w.setFromMatrixColumn(e, 0), w.multiplyScalar(-t), this._panOffset.add(w);
2222
+ }
2223
+ _panUp(t, e) {
2224
+ this.screenSpacePanning === !0 ? w.setFromMatrixColumn(e, 1) : (w.setFromMatrixColumn(e, 0), w.crossVectors(this.object.up, w)), w.multiplyScalar(t), this._panOffset.add(w);
2225
+ }
2226
+ // deltaX and deltaY are in pixels; right and down are positive
2227
+ _pan(t, e) {
2228
+ const i = this.domElement;
2229
+ if (this.object.isPerspectiveCamera) {
2230
+ const s = this.object.position;
2231
+ w.copy(s).sub(this.target);
2232
+ let o = w.length();
2233
+ o *= Math.tan(this.object.fov / 2 * Math.PI / 180), this._panLeft(2 * t * o / i.clientHeight, this.object.matrix), this._panUp(2 * e * o / i.clientHeight, this.object.matrix);
2234
+ } else this.object.isOrthographicCamera ? (this._panLeft(t * (this.object.right - this.object.left) / this.object.zoom / i.clientWidth, this.object.matrix), this._panUp(e * (this.object.top - this.object.bottom) / this.object.zoom / i.clientHeight, this.object.matrix)) : (console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled."), this.enablePan = !1);
2235
+ }
2236
+ _dollyOut(t) {
2237
+ this.object.isPerspectiveCamera || this.object.isOrthographicCamera ? this._scale /= t : (console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."), this.enableZoom = !1);
2238
+ }
2239
+ _dollyIn(t) {
2240
+ this.object.isPerspectiveCamera || this.object.isOrthographicCamera ? this._scale *= t : (console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."), this.enableZoom = !1);
2241
+ }
2242
+ _updateZoomParameters(t, e) {
2243
+ if (!this.zoomToCursor)
2244
+ return;
2245
+ this._performCursorZoom = !0;
2246
+ const i = this.domElement.getBoundingClientRect(), s = t - i.left, o = e - i.top, n = i.width, h = i.height;
2247
+ this._mouse.x = s / n * 2 - 1, this._mouse.y = -(o / h) * 2 + 1, this._dollyDirection.set(this._mouse.x, this._mouse.y, 1).unproject(this.object).sub(this.object.position).normalize();
2248
+ }
2249
+ _clampDistance(t) {
2250
+ return Math.max(this.minDistance, Math.min(this.maxDistance, t));
2251
+ }
2252
+ //
2253
+ // event callbacks - update the object state
2254
+ //
2255
+ _handleMouseDownRotate(t) {
2256
+ this._rotateStart.set(t.clientX, t.clientY);
2257
+ }
2258
+ _handleMouseDownDolly(t) {
2259
+ this._updateZoomParameters(t.clientX, t.clientX), this._dollyStart.set(t.clientX, t.clientY);
2260
+ }
2261
+ _handleMouseDownPan(t) {
2262
+ this._panStart.set(t.clientX, t.clientY);
2263
+ }
2264
+ _handleMouseMoveRotate(t) {
2265
+ this._rotateEnd.set(t.clientX, t.clientY), this._rotateDelta.subVectors(this._rotateEnd, this._rotateStart).multiplyScalar(this.rotateSpeed);
2266
+ const e = this.domElement;
2267
+ this._rotateLeft(I * this._rotateDelta.x / e.clientHeight), this._rotateUp(I * this._rotateDelta.y / e.clientHeight), this._rotateStart.copy(this._rotateEnd), this.update();
2268
+ }
2269
+ _handleMouseMoveDolly(t) {
2270
+ this._dollyEnd.set(t.clientX, t.clientY), this._dollyDelta.subVectors(this._dollyEnd, this._dollyStart), this._dollyDelta.y > 0 ? this._dollyOut(this._getZoomScale(this._dollyDelta.y)) : this._dollyDelta.y < 0 && this._dollyIn(this._getZoomScale(this._dollyDelta.y)), this._dollyStart.copy(this._dollyEnd), this.update();
2271
+ }
2272
+ _handleMouseMovePan(t) {
2273
+ this._panEnd.set(t.clientX, t.clientY), this._panDelta.subVectors(this._panEnd, this._panStart).multiplyScalar(this.panSpeed), this._pan(this._panDelta.x, this._panDelta.y), this._panStart.copy(this._panEnd), this.update();
2274
+ }
2275
+ _handleMouseWheel(t) {
2276
+ this._updateZoomParameters(t.clientX, t.clientY), t.deltaY < 0 ? this._dollyIn(this._getZoomScale(t.deltaY)) : t.deltaY > 0 && this._dollyOut(this._getZoomScale(t.deltaY)), this.update();
2277
+ }
2278
+ _handleKeyDown(t) {
2279
+ let e = !1;
2280
+ switch (t.code) {
2281
+ case this.keys.UP:
2282
+ t.ctrlKey || t.metaKey || t.shiftKey ? this._rotateUp(I * this.rotateSpeed / this.domElement.clientHeight) : this._pan(0, this.keyPanSpeed), e = !0;
2283
+ break;
2284
+ case this.keys.BOTTOM:
2285
+ t.ctrlKey || t.metaKey || t.shiftKey ? this._rotateUp(-I * this.rotateSpeed / this.domElement.clientHeight) : this._pan(0, -this.keyPanSpeed), e = !0;
2286
+ break;
2287
+ case this.keys.LEFT:
2288
+ t.ctrlKey || t.metaKey || t.shiftKey ? this._rotateLeft(I * this.rotateSpeed / this.domElement.clientHeight) : this._pan(this.keyPanSpeed, 0), e = !0;
2289
+ break;
2290
+ case this.keys.RIGHT:
2291
+ t.ctrlKey || t.metaKey || t.shiftKey ? this._rotateLeft(-I * this.rotateSpeed / this.domElement.clientHeight) : this._pan(-this.keyPanSpeed, 0), e = !0;
2292
+ break;
2293
+ }
2294
+ e && (t.preventDefault(), this.update());
2295
+ }
2296
+ _handleTouchStartRotate(t) {
2297
+ if (this._pointers.length === 1)
2298
+ this._rotateStart.set(t.pageX, t.pageY);
2299
+ else {
2300
+ const e = this._getSecondPointerPosition(t), i = 0.5 * (t.pageX + e.x), s = 0.5 * (t.pageY + e.y);
2301
+ this._rotateStart.set(i, s);
2302
+ }
2303
+ }
2304
+ _handleTouchStartPan(t) {
2305
+ if (this._pointers.length === 1)
2306
+ this._panStart.set(t.pageX, t.pageY);
2307
+ else {
2308
+ const e = this._getSecondPointerPosition(t), i = 0.5 * (t.pageX + e.x), s = 0.5 * (t.pageY + e.y);
2309
+ this._panStart.set(i, s);
2310
+ }
2311
+ }
2312
+ _handleTouchStartDolly(t) {
2313
+ const e = this._getSecondPointerPosition(t), i = t.pageX - e.x, s = t.pageY - e.y, o = Math.sqrt(i * i + s * s);
2314
+ this._dollyStart.set(0, o);
2315
+ }
2316
+ _handleTouchStartDollyPan(t) {
2317
+ this.enableZoom && this._handleTouchStartDolly(t), this.enablePan && this._handleTouchStartPan(t);
2318
+ }
2319
+ _handleTouchStartDollyRotate(t) {
2320
+ this.enableZoom && this._handleTouchStartDolly(t), this.enableRotate && this._handleTouchStartRotate(t);
2321
+ }
2322
+ _handleTouchMoveRotate(t) {
2323
+ if (this._pointers.length == 1)
2324
+ this._rotateEnd.set(t.pageX, t.pageY);
2325
+ else {
2326
+ const i = this._getSecondPointerPosition(t), s = 0.5 * (t.pageX + i.x), o = 0.5 * (t.pageY + i.y);
2327
+ this._rotateEnd.set(s, o);
2328
+ }
2329
+ this._rotateDelta.subVectors(this._rotateEnd, this._rotateStart).multiplyScalar(this.rotateSpeed);
2330
+ const e = this.domElement;
2331
+ this._rotateLeft(I * this._rotateDelta.x / e.clientHeight), this._rotateUp(I * this._rotateDelta.y / e.clientHeight), this._rotateStart.copy(this._rotateEnd);
2332
+ }
2333
+ _handleTouchMovePan(t) {
2334
+ if (this._pointers.length === 1)
2335
+ this._panEnd.set(t.pageX, t.pageY);
2336
+ else {
2337
+ const e = this._getSecondPointerPosition(t), i = 0.5 * (t.pageX + e.x), s = 0.5 * (t.pageY + e.y);
2338
+ this._panEnd.set(i, s);
2339
+ }
2340
+ this._panDelta.subVectors(this._panEnd, this._panStart).multiplyScalar(this.panSpeed), this._pan(this._panDelta.x, this._panDelta.y), this._panStart.copy(this._panEnd);
2341
+ }
2342
+ _handleTouchMoveDolly(t) {
2343
+ const e = this._getSecondPointerPosition(t), i = t.pageX - e.x, s = t.pageY - e.y, o = Math.sqrt(i * i + s * s);
2344
+ this._dollyEnd.set(0, o), this._dollyDelta.set(0, Math.pow(this._dollyEnd.y / this._dollyStart.y, this.zoomSpeed)), this._dollyOut(this._dollyDelta.y), this._dollyStart.copy(this._dollyEnd);
2345
+ const n = (t.pageX + e.x) * 0.5, h = (t.pageY + e.y) * 0.5;
2346
+ this._updateZoomParameters(n, h);
2347
+ }
2348
+ _handleTouchMoveDollyPan(t) {
2349
+ this.enableZoom && this._handleTouchMoveDolly(t), this.enablePan && this._handleTouchMovePan(t);
2350
+ }
2351
+ _handleTouchMoveDollyRotate(t) {
2352
+ this.enableZoom && this._handleTouchMoveDolly(t), this.enableRotate && this._handleTouchMoveRotate(t);
2353
+ }
2354
+ // pointers
2355
+ _addPointer(t) {
2356
+ this._pointers.push(t.pointerId);
2357
+ }
2358
+ _removePointer(t) {
2359
+ delete this._pointerPositions[t.pointerId];
2360
+ for (let e = 0; e < this._pointers.length; e++)
2361
+ if (this._pointers[e] == t.pointerId) {
2362
+ this._pointers.splice(e, 1);
2363
+ return;
2364
+ }
2365
+ }
2366
+ _isTrackingPointer(t) {
2367
+ for (let e = 0; e < this._pointers.length; e++)
2368
+ if (this._pointers[e] == t.pointerId) return !0;
2369
+ return !1;
2370
+ }
2371
+ _trackPointer(t) {
2372
+ let e = this._pointerPositions[t.pointerId];
2373
+ e === void 0 && (e = new R(), this._pointerPositions[t.pointerId] = e), e.set(t.pageX, t.pageY);
2374
+ }
2375
+ _getSecondPointerPosition(t) {
2376
+ const e = t.pointerId === this._pointers[0] ? this._pointers[1] : this._pointers[0];
2377
+ return this._pointerPositions[e];
2378
+ }
2379
+ //
2380
+ _customWheelEvent(t) {
2381
+ const e = t.deltaMode, i = {
2382
+ clientX: t.clientX,
2383
+ clientY: t.clientY,
2384
+ deltaY: t.deltaY
2385
+ };
2386
+ switch (e) {
2387
+ case 1:
2388
+ i.deltaY *= 16;
2389
+ break;
2390
+ case 2:
2391
+ i.deltaY *= 100;
2392
+ break;
2393
+ }
2394
+ return t.ctrlKey && !this._controlActive && (i.deltaY *= 10), i;
2395
+ }
2396
+ }
2397
+ function Ce(a) {
2398
+ this.enabled !== !1 && (this._pointers.length === 0 && (this.domElement.setPointerCapture(a.pointerId), this.domElement.addEventListener("pointermove", this._onPointerMove), this.domElement.addEventListener("pointerup", this._onPointerUp)), !this._isTrackingPointer(a) && (this._addPointer(a), a.pointerType === "touch" ? this._onTouchStart(a) : this._onMouseDown(a)));
2399
+ }
2400
+ function Le(a) {
2401
+ this.enabled !== !1 && (a.pointerType === "touch" ? this._onTouchMove(a) : this._onMouseMove(a));
2402
+ }
2403
+ function ze(a) {
2404
+ switch (this._removePointer(a), this._pointers.length) {
2405
+ case 0:
2406
+ this.domElement.releasePointerCapture(a.pointerId), this.domElement.removeEventListener("pointermove", this._onPointerMove), this.domElement.removeEventListener("pointerup", this._onPointerUp), this.dispatchEvent(Xt), this.state = m.NONE;
2407
+ break;
2408
+ case 1:
2409
+ const t = this._pointers[0], e = this._pointerPositions[t];
2410
+ this._onTouchStart({ pointerId: t, pageX: e.x, pageY: e.y });
2411
+ break;
2412
+ }
2413
+ }
2414
+ function Oe(a) {
2415
+ let t;
2416
+ switch (a.button) {
2417
+ case 0:
2418
+ t = this.mouseButtons.LEFT;
2419
+ break;
2420
+ case 1:
2421
+ t = this.mouseButtons.MIDDLE;
2422
+ break;
2423
+ case 2:
2424
+ t = this.mouseButtons.RIGHT;
2425
+ break;
2426
+ default:
2427
+ t = -1;
2428
+ }
2429
+ switch (t) {
2430
+ case G.DOLLY:
2431
+ if (this.enableZoom === !1) return;
2432
+ this._handleMouseDownDolly(a), this.state = m.DOLLY;
2433
+ break;
2434
+ case G.ROTATE:
2435
+ if (a.ctrlKey || a.metaKey || a.shiftKey) {
2436
+ if (this.enablePan === !1) return;
2437
+ this._handleMouseDownPan(a), this.state = m.PAN;
2438
+ } else {
2439
+ if (this.enableRotate === !1) return;
2440
+ this._handleMouseDownRotate(a), this.state = m.ROTATE;
2441
+ }
2442
+ break;
2443
+ case G.PAN:
2444
+ if (a.ctrlKey || a.metaKey || a.shiftKey) {
2445
+ if (this.enableRotate === !1) return;
2446
+ this._handleMouseDownRotate(a), this.state = m.ROTATE;
2447
+ } else {
2448
+ if (this.enablePan === !1) return;
2449
+ this._handleMouseDownPan(a), this.state = m.PAN;
2450
+ }
2451
+ break;
2452
+ default:
2453
+ this.state = m.NONE;
2454
+ }
2455
+ this.state !== m.NONE && this.dispatchEvent(Et);
2456
+ }
2457
+ function ke(a) {
2458
+ switch (this.state) {
2459
+ case m.ROTATE:
2460
+ if (this.enableRotate === !1) return;
2461
+ this._handleMouseMoveRotate(a);
2462
+ break;
2463
+ case m.DOLLY:
2464
+ if (this.enableZoom === !1) return;
2465
+ this._handleMouseMoveDolly(a);
2466
+ break;
2467
+ case m.PAN:
2468
+ if (this.enablePan === !1) return;
2469
+ this._handleMouseMovePan(a);
2470
+ break;
2471
+ }
2472
+ }
2473
+ function je(a) {
2474
+ this.enabled === !1 || this.enableZoom === !1 || this.state !== m.NONE || (a.preventDefault(), this.dispatchEvent(Et), this._handleMouseWheel(this._customWheelEvent(a)), this.dispatchEvent(Xt));
2475
+ }
2476
+ function Re(a) {
2477
+ this.enabled === !1 || this.enablePan === !1 || this._handleKeyDown(a);
2478
+ }
2479
+ function Ae(a) {
2480
+ switch (this._trackPointer(a), this._pointers.length) {
2481
+ case 1:
2482
+ switch (this.touches.ONE) {
2483
+ case V.ROTATE:
2484
+ if (this.enableRotate === !1) return;
2485
+ this._handleTouchStartRotate(a), this.state = m.TOUCH_ROTATE;
2486
+ break;
2487
+ case V.PAN:
2488
+ if (this.enablePan === !1) return;
2489
+ this._handleTouchStartPan(a), this.state = m.TOUCH_PAN;
2490
+ break;
2491
+ default:
2492
+ this.state = m.NONE;
2493
+ }
2494
+ break;
2495
+ case 2:
2496
+ switch (this.touches.TWO) {
2497
+ case V.DOLLY_PAN:
2498
+ if (this.enableZoom === !1 && this.enablePan === !1) return;
2499
+ this._handleTouchStartDollyPan(a), this.state = m.TOUCH_DOLLY_PAN;
2500
+ break;
2501
+ case V.DOLLY_ROTATE:
2502
+ if (this.enableZoom === !1 && this.enableRotate === !1) return;
2503
+ this._handleTouchStartDollyRotate(a), this.state = m.TOUCH_DOLLY_ROTATE;
2504
+ break;
2505
+ default:
2506
+ this.state = m.NONE;
2507
+ }
2508
+ break;
2509
+ default:
2510
+ this.state = m.NONE;
2511
+ }
2512
+ this.state !== m.NONE && this.dispatchEvent(Et);
2513
+ }
2514
+ function Ye(a) {
2515
+ switch (this._trackPointer(a), this.state) {
2516
+ case m.TOUCH_ROTATE:
2517
+ if (this.enableRotate === !1) return;
2518
+ this._handleTouchMoveRotate(a), this.update();
2519
+ break;
2520
+ case m.TOUCH_PAN:
2521
+ if (this.enablePan === !1) return;
2522
+ this._handleTouchMovePan(a), this.update();
2523
+ break;
2524
+ case m.TOUCH_DOLLY_PAN:
2525
+ if (this.enableZoom === !1 && this.enablePan === !1) return;
2526
+ this._handleTouchMoveDollyPan(a), this.update();
2527
+ break;
2528
+ case m.TOUCH_DOLLY_ROTATE:
2529
+ if (this.enableZoom === !1 && this.enableRotate === !1) return;
2530
+ this._handleTouchMoveDollyRotate(a), this.update();
2531
+ break;
2532
+ default:
2533
+ this.state = m.NONE;
2534
+ }
2535
+ }
2536
+ function He(a) {
2537
+ this.enabled !== !1 && a.preventDefault();
2538
+ }
2539
+ function Ne(a) {
2540
+ a.key === "Control" && (this._controlActive = !0, this.domElement.getRootNode().addEventListener("keyup", this._interceptControlUp, { passive: !0, capture: !0 }));
2541
+ }
2542
+ function Fe(a) {
2543
+ a.key === "Control" && (this._controlActive = !1, this.domElement.getRootNode().removeEventListener("keyup", this._interceptControlUp, { passive: !0, capture: !0 }));
2544
+ }
2545
+ class qe {
2546
+ constructor(t) {
2547
+ r(this, "scene");
2548
+ r(this, "camera");
2549
+ r(this, "renderer");
2550
+ r(this, "controls");
2551
+ r(this, "domElement");
2552
+ r(this, "loader");
2553
+ r(this, "textureLoader");
2554
+ r(this, "currentModel", null);
2555
+ r(this, "animationId", null);
2556
+ r(this, "animate", () => {
2557
+ this.animationId = requestAnimationFrame(this.animate), this.controls.update(), this.renderer.render(this.scene, this.camera);
2558
+ });
2559
+ const { container: e, backgroundColor: i = 1710638 } = t;
2560
+ this.domElement = e, this.scene = new l.Scene(), this.scene.background = new l.Color(i);
2561
+ const s = e.clientWidth / e.clientHeight;
2562
+ this.camera = new l.PerspectiveCamera(50, s, 0.1, 1e3), this.camera.position.set(50, 50, 100), this.renderer = new l.WebGLRenderer({
2563
+ antialias: !0,
2564
+ alpha: !0
2565
+ }), this.renderer.setSize(e.clientWidth, e.clientHeight), this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)), this.renderer.shadowMap.enabled = !0, this.renderer.shadowMap.type = l.PCFSoftShadowMap, e.appendChild(this.renderer.domElement), this.controls = new De(this.camera, this.renderer.domElement), this.controls.enableDamping = !0, this.controls.dampingFactor = 0.1, this.controls.minDistance = 10, this.controls.maxDistance = 500, this.loader = new Pe(), this.textureLoader = new l.TextureLoader(), this.setupLighting(), this.setupHelpers(), window.addEventListener("resize", () => this.handleResize(e)), this.animate();
2566
+ }
2567
+ setupLighting() {
2568
+ const t = new l.AmbientLight(16777215, 0.4);
2569
+ this.scene.add(t);
2570
+ const e = new l.DirectionalLight(16777215, 0.8);
2571
+ e.position.set(50, 100, 50), e.castShadow = !0, e.shadow.mapSize.width = 2048, e.shadow.mapSize.height = 2048, this.scene.add(e);
2572
+ const i = new l.DirectionalLight(16777215, 0.3);
2573
+ i.position.set(-50, 50, -50), this.scene.add(i);
2574
+ const s = new l.DirectionalLight(8965375, 0.2);
2575
+ s.position.set(0, -50, -100), this.scene.add(s);
2576
+ }
2577
+ setupHelpers() {
2578
+ const t = new l.GridHelper(200, 20, 4473924, 3355443);
2579
+ t.position.y = -0.1, this.scene.add(t);
2580
+ const e = new l.AxesHelper(20);
2581
+ this.scene.add(e);
2582
+ }
2583
+ handleResize(t) {
2584
+ const e = t.clientWidth, i = t.clientHeight;
2585
+ this.camera.aspect = e / i, this.camera.updateProjectionMatrix(), this.renderer.setSize(e, i);
2586
+ }
2587
+ /**
2588
+ * Load a .blockymodel file
2589
+ */
2590
+ async loadModel(t) {
2591
+ this.currentModel && (this.scene.remove(this.currentModel), this.disposeModel(this.currentModel), this.currentModel = null);
2592
+ try {
2593
+ return this.currentModel = await this.loader.loadFromFile(t), this.scene.add(this.currentModel), this.fitCameraToModel(), console.log(`Loaded model with ${this.countMeshes(this.currentModel)} meshes`), this.currentModel;
2594
+ } catch (e) {
2595
+ throw console.error("Failed to load model:", e), e;
2596
+ }
2597
+ }
2598
+ /**
2599
+ * Get the currently loaded model
2600
+ */
2601
+ getModel() {
2602
+ return this.currentModel;
2603
+ }
2604
+ /**
2605
+ * Load a texture and apply to current model
2606
+ */
2607
+ async loadTexture(t) {
2608
+ if (!this.currentModel) {
2609
+ console.warn("No model loaded to apply texture to");
2610
+ return;
2611
+ }
2612
+ const e = URL.createObjectURL(t);
2613
+ try {
2614
+ const i = await new Promise((s, o) => {
2615
+ this.textureLoader.load(e, s, void 0, o);
2616
+ });
2617
+ Ie(this.currentModel, i), console.log("Texture applied");
2618
+ } finally {
2619
+ URL.revokeObjectURL(e);
2620
+ }
2621
+ }
2622
+ /**
2623
+ * Fit camera to view the entire model
2624
+ */
2625
+ fitCameraToModel() {
2626
+ if (!this.currentModel) return;
2627
+ const t = new l.Box3().setFromObject(this.currentModel), e = t.getCenter(new l.Vector3()), i = t.getSize(new l.Vector3()), s = Math.max(i.x, i.y, i.z), o = this.camera.fov * (Math.PI / 180), n = s / (2 * Math.tan(o / 2)) * 1.5;
2628
+ this.camera.position.set(
2629
+ e.x + n * 0.5,
2630
+ e.y + n * 0.5,
2631
+ e.z + n
2632
+ ), this.controls.target.copy(e), this.controls.update();
2633
+ }
2634
+ /**
2635
+ * Reset camera to default position
2636
+ */
2637
+ resetCamera() {
2638
+ this.currentModel ? this.fitCameraToModel() : (this.camera.position.set(50, 50, 100), this.controls.target.set(0, 0, 0), this.controls.update());
2639
+ }
2640
+ /**
2641
+ * Set background color
2642
+ */
2643
+ setBackgroundColor(t) {
2644
+ this.scene.background = new l.Color(t);
2645
+ }
2646
+ /**
2647
+ * Toggle wireframe mode on all meshes
2648
+ */
2649
+ toggleWireframe(t) {
2650
+ var e;
2651
+ (e = this.currentModel) == null || e.traverse((i) => {
2652
+ if (i instanceof l.Mesh) {
2653
+ const s = i.material;
2654
+ s.wireframe = t;
2655
+ }
2656
+ });
2657
+ }
2658
+ /**
2659
+ * Get model hierarchy for debugging
2660
+ */
2661
+ getModelHierarchy() {
2662
+ if (!this.currentModel) return null;
2663
+ const t = (e) => ({
2664
+ name: e.name,
2665
+ type: e.type,
2666
+ userData: e.userData,
2667
+ children: e.children.map(t)
2668
+ });
2669
+ return t(this.currentModel);
2670
+ }
2671
+ /**
2672
+ * Count meshes in model
2673
+ */
2674
+ countMeshes(t) {
2675
+ let e = 0;
2676
+ return t.traverse((i) => {
2677
+ i instanceof l.Mesh && e++;
2678
+ }), e;
2679
+ }
2680
+ /**
2681
+ * Dispose of model resources
2682
+ */
2683
+ disposeModel(t) {
2684
+ t.traverse((e) => {
2685
+ e instanceof l.Mesh && (e.geometry.dispose(), Array.isArray(e.material) ? e.material.forEach((i) => i.dispose()) : e.material.dispose());
2686
+ });
2687
+ }
2688
+ /**
2689
+ * Clean up all resources
2690
+ */
2691
+ dispose() {
2692
+ this.animationId !== null && cancelAnimationFrame(this.animationId), this.currentModel && this.disposeModel(this.currentModel), this.controls.dispose(), this.renderer.dispose();
2693
+ }
2694
+ }
2695
+ export {
2696
+ wt as AddNodeCommand,
2697
+ q as BaseCommand,
2698
+ Pe as BlockyModelLoader,
2699
+ ve as DEFAULT_ORIENTATION,
2700
+ xt as DEFAULT_POSITION,
2701
+ Rt as DEFAULT_STRETCH,
2702
+ Ze as Editor,
2703
+ Ve as HierarchyPanel,
2704
+ xe as History,
2705
+ Qe as PropertyPanel,
2706
+ Me as RemoveNodeCommand,
2707
+ le as SelectionManager,
2708
+ Be as Serializer,
2709
+ ut as SetPositionCommand,
2710
+ N as SetPropertyCommand,
2711
+ mt as SetRotationCommand,
2712
+ ft as SetScaleCommand,
2713
+ we as TransformManager,
2714
+ Ge as UVEditor,
2715
+ qe as ViewerController
2716
+ };
2717
+ //# sourceMappingURL=blockymodel-web.js.map