incanto 0.35.0 → 0.35.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/editor.js CHANGED
@@ -191,23 +191,33 @@ var Te = {
191
191
  scenes: ye,
192
192
  createScene: be,
193
193
  library: we
194
- }, Ee = localStorage.getItem("incanto-editor-lang") ?? "en", De = /* @__PURE__ */ new Set();
195
- function Oe() {
196
- return Ee;
194
+ };
195
+ //#endregion
196
+ //#region src/i18n.ts
197
+ function Ee() {
198
+ try {
199
+ return typeof localStorage > "u" ? null : localStorage;
200
+ } catch {
201
+ return null;
202
+ }
197
203
  }
198
- function ke(e) {
199
- Ee = e, localStorage.setItem("incanto-editor-lang", e);
200
- for (let e of De) e();
204
+ var De = Ee()?.getItem("incanto-editor-lang") ?? "en", Oe = /* @__PURE__ */ new Set();
205
+ function ke() {
206
+ return De;
201
207
  }
202
208
  function Ae(e) {
203
- De.add(e);
209
+ De = e, Ee()?.setItem("incanto-editor-lang", e);
210
+ for (let e of Oe) e();
211
+ }
212
+ function je(e) {
213
+ Oe.add(e);
204
214
  }
205
215
  function I(e) {
206
- return e[Ee];
216
+ return e[De];
207
217
  }
208
218
  //#endregion
209
219
  //#region src/icons.ts
210
- var je = {
220
+ var Me = {
211
221
  node: { paths: ["M5 5h14v14H5z"] },
212
222
  move: { paths: ["M12 3v18M3 12h18", "M8 7l4-4 4 4M8 17l4 4 4-4M7 8l-4 4 4 4M17 8l4 4-4 4"] },
213
223
  image: {
@@ -366,7 +376,7 @@ var je = {
366
376
  "M12 14h8v8h-8z",
367
377
  "M8 6h8v8H8z"
368
378
  ] }
369
- }, Me = {
379
+ }, Ne = {
370
380
  Node: "node",
371
381
  Timer: "clock",
372
382
  AudioPlayer: "speaker",
@@ -403,8 +413,8 @@ var je = {
403
413
  Area3D: "area",
404
414
  NetworkSpawner: "globe"
405
415
  };
406
- function Ne(e) {
407
- let t = je[Me[e ?? ""] ?? (e ? "node" : "link")], n = document.createElementNS("http://www.w3.org/2000/svg", "svg");
416
+ function Pe(e) {
417
+ let t = Me[Ne[e ?? ""] ?? (e ? "node" : "link")], n = document.createElementNS("http://www.w3.org/2000/svg", "svg");
408
418
  n.setAttribute("viewBox", "0 0 24 24"), n.setAttribute("width", "13"), n.setAttribute("height", "13"), n.setAttribute("fill", "none"), n.setAttribute("stroke", "currentColor"), n.setAttribute("stroke-width", "2"), n.setAttribute("stroke-linecap", "round"), n.setAttribute("stroke-linejoin", "round"), t.dashed && n.setAttribute("stroke-dasharray", "3 2.4");
409
419
  for (let e of t.paths) {
410
420
  let t = document.createElementNS("http://www.w3.org/2000/svg", "path");
@@ -416,7 +426,7 @@ function Ne(e) {
416
426
  }
417
427
  return n;
418
428
  }
419
- function Pe() {
429
+ function Fe() {
420
430
  let e = document.createElementNS("http://www.w3.org/2000/svg", "svg");
421
431
  e.setAttribute("viewBox", "0 0 24 24"), e.setAttribute("width", "12"), e.setAttribute("height", "12"), e.setAttribute("fill", "none"), e.setAttribute("stroke", "currentColor"), e.setAttribute("stroke-width", "2.4"), e.setAttribute("aria-hidden", "true");
422
432
  let t = document.createElementNS("http://www.w3.org/2000/svg", "path");
@@ -424,7 +434,7 @@ function Pe() {
424
434
  }
425
435
  //#endregion
426
436
  //#region src/asset-manager.ts
427
- var Fe = [
437
+ var Ie = [
428
438
  {
429
439
  type: "texture",
430
440
  label: "image (texture)",
@@ -449,8 +459,8 @@ var Fe = [
449
459
  label: "animation (GLB clips)",
450
460
  metaHints: ["clip"]
451
461
  }
452
- ], Ie = /* @__PURE__ */ new Set(), Le = null, Re = null;
453
- function ze(e, t, n) {
462
+ ], Le = /* @__PURE__ */ new Set(), Re = null, ze = null;
463
+ function Be(e, t, n) {
454
464
  let r = document.createElement("input");
455
465
  r.className = "rename-input", r.value = e;
456
466
  let i = () => {
@@ -470,7 +480,7 @@ function ze(e, t, n) {
470
480
  r.focus(), r.select();
471
481
  }), r;
472
482
  }
473
- function Be(e, t) {
483
+ function Ve(e, t) {
474
484
  let n = {
475
485
  path: "",
476
486
  name: "",
@@ -497,12 +507,12 @@ function Be(e, t) {
497
507
  for (let e of t) r(e);
498
508
  return n;
499
509
  }
500
- function Ve(e) {
510
+ function He(e) {
501
511
  let t = e.assets.length;
502
- for (let n of e.folders.values()) t += Ve(n);
512
+ for (let n of e.folders.values()) t += He(n);
503
513
  return t;
504
514
  }
505
- function He(e, t) {
515
+ function Ue(e, t) {
506
516
  e.textContent = "";
507
517
  let n = t.working.assets ?? {}, r = Object.keys(n);
508
518
  if (r.length === 0 && t.pendingGroups.size === 0 && !t.addingAsset && !t.addingGroup) {
@@ -528,37 +538,37 @@ function He(e, t) {
528
538
  t.dataTransfer?.setData("text/incanto-asset", e);
529
539
  });
530
540
  let s = document.createElement("span");
531
- if (s.className = "tree-icon", s.appendChild(it(i.type ?? "")), s.addEventListener("click", (e) => {
532
- e.stopPropagation(), at(s, i.type ?? "");
533
- }), Le === e) {
541
+ if (s.className = "tree-icon", s.appendChild(at(i.type ?? "")), s.addEventListener("click", (e) => {
542
+ e.stopPropagation(), ot(s, i.type ?? "");
543
+ }), Re === e) {
534
544
  let n = e.includes("/") ? e.slice(0, e.lastIndexOf("/") + 1) : "";
535
- o.appendChild(ze(a, (r) => {
536
- Le = null, t.renameAssetKey(e, n + r);
545
+ o.appendChild(Be(a, (r) => {
546
+ Re = null, t.renameAssetKey(e, n + r);
537
547
  }, () => {
538
- Le = null, t.selectAsset(t.selectedAsset);
548
+ Re = null, t.selectAsset(t.selectedAsset);
539
549
  })), o.draggable = !1, o.insertBefore(s, o.firstChild), r.appendChild(o);
540
550
  return;
541
551
  }
542
552
  let c = document.createElement("span");
543
553
  c.className = "tree-name asset-key", c.textContent = `$${a}`, c.title = `$${e}`, c.addEventListener("dblclick", (n) => {
544
- n.stopPropagation(), Le = e, t.selectAsset(e);
554
+ n.stopPropagation(), Re = e, t.selectAsset(e);
545
555
  }), o.append(s, c), o.addEventListener("click", () => t.selectAsset(e)), r.appendChild(o);
546
556
  }, o = (e, n) => {
547
- let r = Ie.has(e.path), s = document.createElement("div");
557
+ let r = Le.has(e.path), s = document.createElement("div");
548
558
  s.className = `asset-folder${r ? " collapsed" : ""}${t.selectedGroup === e.path ? " selected" : ""}`, s.draggable = !0, s.addEventListener("dragstart", (t) => {
549
559
  t.stopPropagation(), t.dataTransfer?.setData("text/incanto-group", e.path);
550
560
  });
551
561
  let c = document.createElement("span");
552
- c.className = "chev", c.appendChild(Pe());
562
+ c.className = "chev", c.appendChild(Fe());
553
563
  let l = document.createElementNS("http://www.w3.org/2000/svg", "svg");
554
564
  l.setAttribute("viewBox", "0 0 24 24"), l.setAttribute("width", "12"), l.setAttribute("height", "12"), l.setAttribute("fill", "none"), l.setAttribute("stroke", "currentColor"), l.setAttribute("stroke-width", "1.8"), l.setAttribute("aria-hidden", "true");
555
565
  let u = document.createElementNS("http://www.w3.org/2000/svg", "path");
556
- if (u.setAttribute("d", "M3 6a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"), l.appendChild(u), Re === e.path) {
566
+ if (u.setAttribute("d", "M3 6a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"), l.appendChild(u), ze === e.path) {
557
567
  let i = e.path.includes("/") ? e.path.slice(0, e.path.lastIndexOf("/") + 1) : "";
558
- if (s.append(c, l, ze(e.name, (n) => {
559
- Re = null, t.renameGroup(e.path, i + n);
568
+ if (s.append(c, l, Be(e.name, (n) => {
569
+ ze = null, t.renameGroup(e.path, i + n);
560
570
  }, () => {
561
- Re = null, t.selectGroup(t.selectedGroup);
571
+ ze = null, t.selectGroup(t.selectedGroup);
562
572
  })), s.draggable = !1, n.appendChild(s), !r) {
563
573
  let t = document.createElement("div");
564
574
  t.className = "tree-children";
@@ -570,11 +580,11 @@ function He(e, t) {
570
580
  }
571
581
  let d = document.createElement("span");
572
582
  d.textContent = e.name, d.addEventListener("dblclick", (n) => {
573
- n.stopPropagation(), Re = e.path, t.selectGroup(e.path);
583
+ n.stopPropagation(), ze = e.path, t.selectGroup(e.path);
574
584
  });
575
585
  let f = document.createElement("span");
576
- if (f.className = "count", f.textContent = `(${Ve(e)})`, s.append(c, l, d, f), s.addEventListener("click", () => {
577
- Ie.has(e.path) ? Ie.delete(e.path) : Ie.add(e.path), t.selectGroup(e.path);
586
+ if (f.className = "count", f.textContent = `(${He(e)})`, s.append(c, l, d, f), s.addEventListener("click", () => {
587
+ Le.has(e.path) ? Le.delete(e.path) : Le.add(e.path), t.selectGroup(e.path);
578
588
  }), i(s, e.path), n.appendChild(s), !r) {
579
589
  let t = document.createElement("div");
580
590
  t.className = "tree-children";
@@ -582,16 +592,16 @@ function He(e, t) {
582
592
  for (let n of e.assets) a(n, t);
583
593
  t.children.length > 0 && n.appendChild(t);
584
594
  }
585
- }, s = Be(r, t.pendingGroups);
595
+ }, s = Ve(r, t.pendingGroups);
586
596
  for (let t of s.assets) a(t, e);
587
597
  for (let t of s.folders.values()) o(t, e);
588
598
  }
589
- function Ue(e, t, n, r) {
599
+ function We(e, t, n, r) {
590
600
  if (t.selection !== null) return !1;
591
601
  if (t.addingGroup) {
592
- e.appendChild(lt(t.newGroupParent ? `NEW GROUP IN ${t.newGroupParent}/` : "NEW GROUP"));
602
+ e.appendChild(ut(t.newGroupParent ? `NEW GROUP IN ${t.newGroupParent}/` : "NEW GROUP"));
593
603
  let n = document.createElement("input");
594
- n.placeholder = t.newGroupParent ? "heroes" : "characters (or a/b to nest)", n.className = "mono", e.appendChild($e("name", n));
604
+ n.placeholder = t.newGroupParent ? "heroes" : "characters (or a/b to nest)", n.className = "mono", e.appendChild(et("name", n));
595
605
  let r = document.createElement("button");
596
606
  r.type = "button", r.className = "primary", r.textContent = "add";
597
607
  let i = () => {
@@ -604,12 +614,12 @@ function Ue(e, t, n, r) {
604
614
  let a = document.createElement("div");
605
615
  return a.className = "pop-actions", a.appendChild(r), e.appendChild(a), setTimeout(() => n.focus(), 0), !0;
606
616
  }
607
- if (t.addingAsset) return qe(e, t, r);
617
+ if (t.addingAsset) return Je(e, t, r);
608
618
  if (t.selectedGroup !== null) {
609
619
  let r = t.selectedGroup, i = t.groupCount(r);
610
- e.appendChild(lt(`GROUP (${i} asset${i === 1 ? "" : "s"})`));
620
+ e.appendChild(ut(`GROUP (${i} asset${i === 1 ? "" : "s"})`));
611
621
  let a = r.includes("/") ? r.slice(0, r.lastIndexOf("/") + 1) : "", o = r.includes("/") ? r.slice(r.lastIndexOf("/") + 1) : r;
612
- e.appendChild(et("name", o, (e) => {
622
+ e.appendChild(tt("name", o, (e) => {
613
623
  let n = e.trim().replace(/\/+/g, "");
614
624
  n && n !== o && t.renameGroup(r, a + n);
615
625
  }));
@@ -626,7 +636,7 @@ function Ue(e, t, n, r) {
626
636
  if (i === null) return !1;
627
637
  let a = t.working.assets ?? {};
628
638
  if (!(i in a)) return !1;
629
- e.appendChild(lt(`ASSET — ${String(a[i].type ?? "?")}`)), e.appendChild(ot(i)), e.appendChild(st(t, i)), e.appendChild(We(t, a, i, r));
639
+ e.appendChild(ut(`ASSET — ${String(a[i].type ?? "?")}`)), e.appendChild(st(i)), e.appendChild(ct(t, i)), e.appendChild(Ge(t, a, i, r));
630
640
  let o = document.createElement("button");
631
641
  return o.type = "button", o.className = "ghost danger", o.textContent = "delete asset", o.addEventListener("click", () => {
632
642
  t.selectAsset(null), t.mutate(() => {
@@ -634,34 +644,34 @@ function Ue(e, t, n, r) {
634
644
  });
635
645
  }), e.appendChild(o), !0;
636
646
  }
637
- function We(e, t, n, r) {
647
+ function Ge(e, t, n, r) {
638
648
  let i = t[n], a = document.createElement("div");
639
649
  a.className = "asset-editor";
640
- let o = n.includes("/") ? n.slice(n.lastIndexOf("/") + 1) : n, s = n.includes("/") ? n.slice(0, n.lastIndexOf("/") + 1) : "", c = et("name", o, (t) => {
650
+ let o = n.includes("/") ? n.slice(n.lastIndexOf("/") + 1) : n, s = n.includes("/") ? n.slice(0, n.lastIndexOf("/") + 1) : "", c = tt("name", o, (t) => {
641
651
  let r = t.trim().replace(/^\$/, "").replace(/\//g, "");
642
652
  r && r !== o && e.renameAssetKey(n, s + r);
643
653
  });
644
- ct(c.querySelector("input")), a.appendChild(c);
645
- let l = et("url", String(i.url ?? ""), (t) => {
654
+ lt(c.querySelector("input")), a.appendChild(c);
655
+ let l = tt("url", String(i.url ?? ""), (t) => {
646
656
  e.mutate(() => {
647
657
  i.url = t.trim();
648
658
  });
649
659
  }), u = l.querySelector("input");
650
660
  if (r && u) {
651
- let t = Ye(String(i.type ?? ""));
652
- l.appendChild(Qe(() => t, "asset url", r, (t) => {
661
+ let t = Xe(String(i.type ?? ""));
662
+ l.appendChild($e(() => t, "asset url", r, (t) => {
653
663
  u.value = t, e.mutate(() => {
654
664
  i.url = t;
655
665
  });
656
- }, () => Ze(t, e)));
666
+ }, () => Qe(t, e)));
657
667
  }
658
668
  a.appendChild(l);
659
669
  let d = document.createElement("div");
660
670
  d.className = "muted-note", d.textContent = "meta (key · value)", a.appendChild(d);
661
- for (let [t, n] of Object.entries(i)) t === "type" || t === "url" || a.appendChild(Ge(e, i, t, n));
662
- return a.appendChild(Ke(e, i)), a;
671
+ for (let [t, n] of Object.entries(i)) t === "type" || t === "url" || a.appendChild(Ke(e, i, t, n));
672
+ return a.appendChild(qe(e, i)), a;
663
673
  }
664
- function Ge(e, t, n, r) {
674
+ function Ke(e, t, n, r) {
665
675
  let i = document.createElement("div");
666
676
  i.className = "meta-row";
667
677
  let a = document.createElement("input");
@@ -671,7 +681,7 @@ function Ge(e, t, n, r) {
671
681
  let s = () => {
672
682
  let r = a.value.trim();
673
683
  e.mutate(() => {
674
- delete t[n], r && (t[r] = tt(o.value));
684
+ delete t[n], r && (t[r] = nt(o.value));
675
685
  });
676
686
  };
677
687
  a.addEventListener("change", s), o.addEventListener("change", s);
@@ -682,7 +692,7 @@ function Ge(e, t, n, r) {
682
692
  });
683
693
  }), i.append(a, o, c), i;
684
694
  }
685
- function Ke(e, t) {
695
+ function qe(e, t) {
686
696
  let n = document.createElement("div");
687
697
  n.className = "meta-row";
688
698
  let r = document.createElement("input");
@@ -692,23 +702,23 @@ function Ke(e, t) {
692
702
  let a = () => {
693
703
  let n = r.value.trim();
694
704
  !n || i.value.trim() === "" || e.mutate(() => {
695
- t[n] = tt(i.value);
705
+ t[n] = nt(i.value);
696
706
  });
697
707
  };
698
708
  return r.addEventListener("change", a), i.addEventListener("change", a), n.append(r, i, document.createElement("span")), n;
699
709
  }
700
- function qe(e, t, n) {
701
- return e.appendChild(lt("NEW ASSET")), e.appendChild(Je(t, n)), !0;
710
+ function Je(e, t, n) {
711
+ return e.appendChild(ut("NEW ASSET")), e.appendChild(Ye(t, n)), !0;
702
712
  }
703
- function Je(e, t) {
713
+ function Ye(e, t) {
704
714
  let n = document.createElement("div");
705
715
  n.className = "asset-editor";
706
716
  let r = document.createElement("select");
707
- for (let e of Fe) {
717
+ for (let e of Ie) {
708
718
  let t = document.createElement("option");
709
719
  t.value = e.type, t.textContent = e.label, r.appendChild(t);
710
720
  }
711
- n.appendChild($e("type", r));
721
+ n.appendChild(et("type", r));
712
722
  let i = document.createElement("input");
713
723
  i.placeholder = "(optional) characters", i.className = "mono", i.value = e.newAssetGroup;
714
724
  let a = "asset-groups-list";
@@ -725,15 +735,15 @@ function Je(e, t) {
725
735
  let t = document.createElement("option");
726
736
  t.value = e, o.appendChild(t);
727
737
  }
728
- n.appendChild($e("group", i)), n.appendChild(o);
738
+ n.appendChild(et("group", i)), n.appendChild(o);
729
739
  let c = document.createElement("input");
730
- c.placeholder = "coin", c.className = "mono", ct(c), n.appendChild($e("key", c));
740
+ c.placeholder = "coin", c.className = "mono", lt(c), n.appendChild(et("key", c));
731
741
  let l = document.createElement("input");
732
742
  l.placeholder = "/textures/coin.png · https://… · data:…", l.className = "mono";
733
- let u = $e("url", l);
734
- t && u.appendChild(Qe(() => Ye(r.value), "new asset", t, (e) => {
735
- l.value = e, c.value.trim() || (c.value = Xe(e));
736
- }, () => Ze(Ye(r.value), e))), n.appendChild(u);
743
+ let u = et("url", l);
744
+ t && u.appendChild($e(() => Xe(r.value), "new asset", t, (e) => {
745
+ l.value = e, c.value.trim() || (c.value = Ze(e));
746
+ }, () => Qe(Xe(r.value), e))), n.appendChild(u);
737
747
  let d = document.createElement("textarea");
738
748
  d.rows = 2, d.placeholder = "or paste a JSON object: { \"type\": \"model\", \"url\": \"/m.glb\" }", n.appendChild(d);
739
749
  let f = document.createElement("button");
@@ -760,18 +770,18 @@ function Je(e, t) {
760
770
  let p = document.createElement("div");
761
771
  return p.className = "pop-actions", p.appendChild(f), n.appendChild(p), n;
762
772
  }
763
- function Ye(e) {
773
+ function Xe(e) {
764
774
  return e === "model" || e === "animation" ? "model" : e === "audio" ? "audio" : e === "texture" || e === "spritesheet" ? "image" : "any";
765
775
  }
766
- function Xe(e) {
776
+ function Ze(e) {
767
777
  return ((e.split(/[?#]/)[0] ?? "").split("/").pop() ?? "").replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9_-]+/g, "_").replace(/_{2,}/g, "_").replace(/^_+|_+$/g, "").toLowerCase() || "asset";
768
778
  }
769
- function Ze(e, t) {
779
+ function Qe(e, t) {
770
780
  let n = (t.working.dimension ?? "2d") === "3d";
771
781
  if (e === "image") return n ? ["3d", "textures"] : ["2d", "sprite_characters"];
772
782
  if (e === "model") return ["3d", "characters"];
773
783
  }
774
- function Qe(e, t, n, r, i) {
784
+ function $e(e, t, n, r, i) {
775
785
  let a = document.createElement("button");
776
786
  return a.type = "button", a.className = "asset-lib", a.textContent = "📚", a.title = "Browse the agent8 library", a.addEventListener("click", (a) => {
777
787
  a.preventDefault();
@@ -785,17 +795,17 @@ function Qe(e, t, n, r, i) {
785
795
  });
786
796
  }), a;
787
797
  }
788
- function $e(e, t) {
798
+ function et(e, t) {
789
799
  let n = document.createElement("label");
790
800
  n.className = "field";
791
801
  let r = document.createElement("span");
792
802
  return r.textContent = e, n.append(r, t), n;
793
803
  }
794
- function et(e, t, n) {
804
+ function tt(e, t, n) {
795
805
  let r = document.createElement("input");
796
- return r.value = t, r.className = "mono", r.addEventListener("change", () => n(r.value)), $e(e, r);
806
+ return r.value = t, r.className = "mono", r.addEventListener("change", () => n(r.value)), et(e, r);
797
807
  }
798
- function tt(e) {
808
+ function nt(e) {
799
809
  let t = e.trim();
800
810
  if (t === "true") return !0;
801
811
  if (t === "false") return !1;
@@ -807,12 +817,12 @@ function tt(e) {
807
817
  }
808
818
  return e;
809
819
  }
810
- var nt = {
820
+ var rt = {
811
821
  texture: "M3 5h18v14H3z M3 15l5-5 4 4 3-3 6 6 M8.5 9.5h.01",
812
822
  spritesheet: "M3 4h18v16H3z M9 4v16 M15 4v16 M3 12h18",
813
823
  model: "M12 2l9 5v10l-9 5-9-5V7z M12 12l9-5 M12 12L3 7 M12 12v10",
814
824
  animation: "M12 2a10 10 0 1 0 10 10 M22 12l-3-3m3 3l3-3 M12 7v5l3 3"
815
- }, rt = {
825
+ }, it = {
816
826
  texture: {
817
827
  en: "image (texture) — Sprite2D.texture references it as \"$key\".",
818
828
  ko: "이미지(텍스처) — Sprite2D.texture에서 \"$키\"로 참조합니다."
@@ -830,15 +840,15 @@ var nt = {
830
840
  ko: "애니메이션 클립(GLB, 메모리 전용 — 그려지지 않음) — 어떤 모델이든 재생 가능, mixamo는 VRM에 자동 리타게팅."
831
841
  }
832
842
  };
833
- function it(e) {
843
+ function at(e) {
834
844
  let t = document.createElementNS("http://www.w3.org/2000/svg", "svg");
835
845
  t.setAttribute("viewBox", "0 0 24 24"), t.setAttribute("width", "13"), t.setAttribute("height", "13"), t.setAttribute("fill", "none"), t.setAttribute("stroke", "currentColor"), t.setAttribute("stroke-width", "1.8"), t.setAttribute("aria-hidden", "true");
836
846
  let n = document.createElementNS("http://www.w3.org/2000/svg", "path");
837
- return n.setAttribute("d", nt[e] ?? "M4 4h16v16H4z"), t.appendChild(n), t.classList.add(`asset-icon-${e}`), t;
847
+ return n.setAttribute("d", rt[e] ?? "M4 4h16v16H4z"), t.appendChild(n), t.classList.add(`asset-icon-${e}`), t;
838
848
  }
839
- function at(e, t) {
849
+ function ot(e, t) {
840
850
  document.querySelector(".balloon")?.remove();
841
- let n = rt[t];
851
+ let n = it[t];
842
852
  if (!n) return;
843
853
  let r = document.createElement("div");
844
854
  r.className = "balloon floating";
@@ -853,7 +863,7 @@ function at(e, t) {
853
863
  };
854
864
  setTimeout(() => document.addEventListener("pointerdown", s, !0), 0);
855
865
  }
856
- function ot(e) {
866
+ function st(e) {
857
867
  let t = document.createElement("div");
858
868
  t.className = "field uid-line";
859
869
  let n = document.createElement("span");
@@ -867,7 +877,7 @@ function ot(e) {
867
877
  navigator.clipboard?.writeText(`$${e}`), a.classList.add("copied"), setTimeout(() => a.classList.remove("copied"), 600);
868
878
  }), r.append(i, a), t.append(n, r), t;
869
879
  }
870
- function st(e, t) {
880
+ function ct(e, t) {
871
881
  let n = t.includes("/") ? t.slice(0, t.lastIndexOf("/")) : "", r = document.createElement("select"), i = new Set([""]);
872
882
  for (let t of Object.keys(e.working.assets ?? {})) {
873
883
  let e = t.split("/");
@@ -886,14 +896,14 @@ function st(e, t) {
886
896
  let o = document.createElement("span");
887
897
  return o.textContent = "group", a.append(o, r), a;
888
898
  }
889
- function ct(e) {
899
+ function lt(e) {
890
900
  e && (e.addEventListener("keydown", (e) => {
891
901
  e.key === "/" && e.preventDefault();
892
902
  }), e.addEventListener("input", () => {
893
903
  e.value.includes("/") && (e.value = e.value.replace(/\//g, ""));
894
904
  }));
895
905
  }
896
- function lt(e) {
906
+ function ut(e) {
897
907
  let t = document.createElement("div");
898
908
  t.className = "section-title", t.textContent = e;
899
909
  let n = document.createElement("span");
@@ -901,19 +911,19 @@ function lt(e) {
901
911
  }
902
912
  //#endregion
903
913
  //#region src/bridge.ts
904
- var ut = window.parent !== window, dt = new URLSearchParams(window.location.search).get("parentOrigin"), ft = !1;
905
- function pt(e) {
906
- if (ut) {
907
- if (!dt) {
908
- ft || (ft = !0, console.warn("incanto-editor: embedded without ?parentOrigin=<origin> — postMessage disabled"));
914
+ var dt = window.parent !== window, ft = new URLSearchParams(window.location.search).get("parentOrigin"), pt = !1;
915
+ function mt(e) {
916
+ if (dt) {
917
+ if (!ft) {
918
+ pt || (pt = !0, console.warn("incanto-editor: embedded without ?parentOrigin=<origin> — postMessage disabled"));
909
919
  return;
910
920
  }
911
- window.parent.postMessage(e, dt);
921
+ window.parent.postMessage(e, ft);
912
922
  }
913
923
  }
914
- var mt = {
924
+ var ht = {
915
925
  ready(e, t, n) {
916
- pt({
926
+ mt({
917
927
  type: "incanto-editor:ready",
918
928
  input: e,
919
929
  output: t,
@@ -921,20 +931,20 @@ var mt = {
921
931
  });
922
932
  },
923
933
  open(e, t) {
924
- pt({
934
+ mt({
925
935
  type: "incanto-editor:open",
926
936
  input: e,
927
937
  output: t
928
938
  });
929
939
  },
930
940
  change(e) {
931
- pt({
941
+ mt({
932
942
  type: "incanto-editor:change",
933
943
  dirty: e
934
944
  });
935
945
  },
936
946
  save(e, t, n) {
937
- pt({
947
+ mt({
938
948
  type: "incanto-editor:save",
939
949
  input: e,
940
950
  output: t,
@@ -942,19 +952,19 @@ var mt = {
942
952
  });
943
953
  },
944
954
  error(e) {
945
- pt({
955
+ mt({
946
956
  type: "incanto-editor:error",
947
957
  message: e
948
958
  });
949
959
  }
950
- }, ht = [
960
+ }, gt = [
951
961
  ["Core", (e) => !e.endsWith("2D") && !e.endsWith("3D") && e !== "Label" && e !== "UILayer" && e !== "NetworkSpawner"],
952
962
  ["2D", (e) => e.endsWith("2D") && !/Body|Area|Controller/.test(e) || e === "Label" || e === "UILayer"],
953
963
  ["2D Physics", (e) => e.endsWith("2D") && /Body|Area|Controller/.test(e)],
954
964
  ["3D", (e) => e.endsWith("3D") && !/Body|Area|Controller/.test(e)],
955
965
  ["3D Physics", (e) => e.endsWith("3D") && /Body|Area|Controller/.test(e)],
956
966
  ["Network", (e) => e === "NetworkSpawner"]
957
- ], gt = [...ht, ["Other", (e) => ht.every(([, t]) => !t(e))]], _t = {
967
+ ], _t = [...gt, ["Other", (e) => gt.every(([, t]) => !t(e))]], vt = {
958
968
  title: {
959
969
  en: "How Incanto scenes work",
960
970
  ko: "Incanto 씬은 어떻게 동작하나"
@@ -1015,7 +1025,7 @@ var mt = {
1015
1025
  type: e,
1016
1026
  summary: t,
1017
1027
  body: n
1018
- }), vt = [
1028
+ }), yt = [
1019
1029
  {
1020
1030
  id: "core",
1021
1031
  label: {
@@ -1396,8 +1406,8 @@ var mt = {
1396
1406
  ko: "진짜 프로시저럴 꽃 식물(휘어진 줄기, 잎 2-3장, 대비되는 중심 원반을 두른 꽃잎 5-8장 머리, 포기당 꽃 1-3송이)을 area [w,d]에 흩뿌립니다. density가 바이브 다이얼: 'lush'(풍성하게) / 'sparse'(듬성듬성, 기본) / 'none'(없게) 또는 m²당 개수. varieties는 daisy/cosmos/bellflower 부분집합([] = 셋 다), palette는 꽃 색([] = 흰/노랑/보라). clustering 0-1이 보로노이 패치로 모아 한 패치가 같은 종·같은 색으로 피고, sway가 바람에 머리를 끄덕이며, seed로 배치가 재현됩니다. 품종 ≤3 → 드로우 콜 ≤6. avoidWater(기본 켜짐)는 고인 물·흐르는 물 안에 꽃을 심지 않습니다 — 시내가 지나는 들판에는 물살 속 꽃이 아니라 꽃이 핀 둑이 생깁니다."
1397
1407
  }),
1398
1408
  L("Tree3D", {
1399
- en: "Procedural ez-tree groves — branchy trunks, textured leaves.",
1400
- ko: "프로시저럴 ez-tree 나무 — 가지 달린 줄기와 텍스처 잎까지."
1409
+ en: "Procedural tree groves — real branching trunks, textured leaves, one node per forest.",
1410
+ ko: "프로시저럴 나무 진짜 가지가 뻗은 줄기와 텍스처 잎, 숲 하나가 노드 하나."
1401
1411
  }, {
1402
1412
  en: "type conifer/broadleaf/dead picks the recipe family; tier is the cost dial: simple = primitive low-poly, medium = light forest presets (≤3k tris/tree), high = full ez-tree presets (8–20k, hero trees). count > 1 scatters a forest patch over area [w,d] — up to 3 seed variants, each branches + leaves InstancedMesh (≤6 draw calls); count × tris/tree is budget-checked at load. seed makes every branch and leaf reproducible; height jitters ±20% per instance; leaves sway in a simplex wind.",
1403
1413
  ko: "type conifer/broadleaf/dead가 수종을, tier가 비용을 정합니다: simple = 기존 로우폴리, medium = 가벼운 forest 프리셋(나무당 ≤3k tris), high = 풀 ez-tree 프리셋(8–20k, 주인공 나무). count > 1이면 area [w,d]에 숲 패치를 흩뿌립니다 — 시드 변형 최대 3종, 변형마다 가지+잎 InstancedMesh(드로우 콜 ≤6), count × tris는 로드 시 예산 검사. seed로 가지와 잎이 전부 재현되고 height는 인스턴스마다 ±20% 지터링, 잎은 심플렉스 바람에 흔들립니다."
@@ -1512,79 +1522,79 @@ var mt = {
1512
1522
  ko: "source \"users\"는 방의 다른 모든 계정을 미러링하고(자신 제외) \"collection:<id>\"는 방 컬렉션을 미러링합니다. 복제 sync 패치가 인스턴스에 적용되고 position은 보간됩니다. spawned/despawned를 발산합니다."
1513
1523
  })]
1514
1524
  }
1515
- ], yt = "overview", bt = null;
1516
- function xt() {
1517
- document.querySelector("#docs")?.removeAttribute("hidden"), wt();
1518
- }
1525
+ ], bt = "overview", xt = null;
1519
1526
  function St() {
1520
- document.querySelector("#docs")?.setAttribute("hidden", "");
1527
+ document.querySelector("#docs")?.removeAttribute("hidden"), Tt();
1521
1528
  }
1522
1529
  function Ct() {
1530
+ document.querySelector("#docs")?.setAttribute("hidden", "");
1531
+ }
1532
+ function wt() {
1523
1533
  let e = document.querySelector("#docs");
1524
1534
  e && (e.addEventListener("pointerdown", (t) => {
1525
- t.target === e && St();
1526
- }), document.querySelector("#docs-close")?.addEventListener("click", St));
1535
+ t.target === e && Ct();
1536
+ }), document.querySelector("#docs-close")?.addEventListener("click", Ct));
1527
1537
  }
1528
- function wt() {
1538
+ function Tt() {
1529
1539
  let e = document.querySelector("#docs-tabs"), t = document.querySelector("#docs-body");
1530
1540
  if (!e || !t) return;
1531
1541
  e.textContent = "";
1532
1542
  let n = (t, n) => {
1533
1543
  let r = document.createElement("button");
1534
- r.type = "button", r.className = `docs-tab${yt === t ? " active" : ""}`, r.textContent = n, r.addEventListener("click", () => {
1535
- yt = t, bt = null, wt();
1544
+ r.type = "button", r.className = `docs-tab${bt === t ? " active" : ""}`, r.textContent = n, r.addEventListener("click", () => {
1545
+ bt = t, xt = null, Tt();
1536
1546
  }), e.appendChild(r);
1537
1547
  };
1538
1548
  n("overview", I({
1539
1549
  en: "Overview",
1540
1550
  ko: "개요"
1541
1551
  }));
1542
- for (let e of vt) n(e.id, I(e.label));
1543
- if (t.textContent = "", yt === "overview") {
1544
- Tt(t);
1552
+ for (let e of yt) n(e.id, I(e.label));
1553
+ if (t.textContent = "", bt === "overview") {
1554
+ Et(t);
1545
1555
  return;
1546
1556
  }
1547
- let r = vt.find((e) => e.id === yt);
1548
- r && Et(t, r);
1557
+ let r = yt.find((e) => e.id === bt);
1558
+ r && Dt(t, r);
1549
1559
  }
1550
- function Tt(e) {
1560
+ function Et(e) {
1551
1561
  let t = document.createElement("h2");
1552
- t.textContent = I(_t.title), e.appendChild(t);
1553
- for (let t of _t.sections) {
1562
+ t.textContent = I(vt.title), e.appendChild(t);
1563
+ for (let t of vt.sections) {
1554
1564
  let n = document.createElement("h3");
1555
1565
  n.textContent = I(t.heading);
1556
1566
  let r = document.createElement("p");
1557
1567
  r.textContent = I(t.text), e.append(n, r);
1558
1568
  }
1559
1569
  }
1560
- function Et(e, t) {
1570
+ function Dt(e, t) {
1561
1571
  let n = document.createElement("p");
1562
1572
  n.className = "docs-intro", n.textContent = I(t.intro), e.appendChild(n);
1563
1573
  for (let n of t.nodes) {
1564
1574
  let t = document.createElement("div");
1565
- t.className = `docs-node${bt === n.type ? " open" : ""}`;
1575
+ t.className = `docs-node${xt === n.type ? " open" : ""}`;
1566
1576
  let r = document.createElement("button");
1567
1577
  r.type = "button", r.className = "docs-node-head";
1568
1578
  let i = document.createElement("span");
1569
- i.className = "tree-icon", i.appendChild(Ne(n.type));
1579
+ i.className = "tree-icon", i.appendChild(Pe(n.type));
1570
1580
  let a = document.createElement("strong");
1571
1581
  a.textContent = n.type;
1572
1582
  let o = document.createElement("span");
1573
1583
  if (o.className = "docs-summary", o.textContent = I(n.summary), r.append(i, a, o), r.addEventListener("click", () => {
1574
- bt = bt === n.type ? null : n.type, wt();
1575
- }), t.appendChild(r), bt === n.type) {
1584
+ xt = xt === n.type ? null : n.type, Tt();
1585
+ }), t.appendChild(r), xt === n.type) {
1576
1586
  let e = document.createElement("div");
1577
1587
  e.className = "docs-detail";
1578
1588
  for (let t of n.body) {
1579
1589
  let n = document.createElement("p");
1580
1590
  n.textContent = I(t), e.appendChild(n);
1581
1591
  }
1582
- e.appendChild(Dt(n.type)), t.appendChild(e);
1592
+ e.appendChild(Ot(n.type)), t.appendChild(e);
1583
1593
  }
1584
1594
  e.appendChild(t);
1585
1595
  }
1586
1596
  }
1587
- function Dt(e) {
1597
+ function Ot(e) {
1588
1598
  let t = document.createElement("table");
1589
1599
  t.className = "docs-props";
1590
1600
  let n = document.createElement("tr");
@@ -1612,13 +1622,13 @@ function Dt(e) {
1612
1622
  }
1613
1623
  //#endregion
1614
1624
  //#region src/generate.ts
1615
- function Ot(e) {
1625
+ function kt(e) {
1616
1626
  return Object.entries(E).filter(([, t]) => t.dimension === e).map(([e, t]) => ({
1617
1627
  name: e,
1618
1628
  meta: t
1619
1629
  }));
1620
1630
  }
1621
- function kt(e, t) {
1631
+ function At(e, t) {
1622
1632
  if (e.type === "boolean") return t === !0 || t === "true";
1623
1633
  if (e.type === "number") {
1624
1634
  let n = typeof t == "boolean" ? NaN : Number(t);
@@ -1627,42 +1637,42 @@ function kt(e, t) {
1627
1637
  let n = String(t);
1628
1638
  return e.options && !e.options.includes(n) ? e.default : n;
1629
1639
  }
1630
- function At() {
1640
+ function jt() {
1631
1641
  return Math.floor(Math.random() * 1e6);
1632
1642
  }
1633
1643
  //#endregion
1634
1644
  //#region src/generate-dialog.ts
1635
- var jt = [], Mt = /* @__PURE__ */ new Map(), R = null;
1636
- function Nt(e) {
1645
+ var Mt = [], Nt = /* @__PURE__ */ new Map(), R = null;
1646
+ function Pt(e) {
1637
1647
  let t = document.querySelector("#generate");
1638
- t && (It(e), t.removeAttribute("hidden"));
1648
+ t && (Lt(e), t.removeAttribute("hidden"));
1639
1649
  }
1640
- function Pt() {
1650
+ function Ft() {
1641
1651
  document.querySelector("#generate")?.setAttribute("hidden", "");
1642
1652
  }
1643
- function Ft(e) {
1653
+ function It(e) {
1644
1654
  let t = document.querySelector("#generate");
1645
1655
  t && (t.addEventListener("pointerdown", (e) => {
1646
- e.target === t && Pt();
1647
- }), document.querySelector("#generate-close")?.addEventListener("click", Pt), document.querySelector("#generate-cancel")?.addEventListener("click", Pt), document.querySelector("#generate-insert")?.addEventListener("click", () => Lt(e)));
1656
+ e.target === t && Ft();
1657
+ }), document.querySelector("#generate-close")?.addEventListener("click", Ft), document.querySelector("#generate-cancel")?.addEventListener("click", Ft), document.querySelector("#generate-insert")?.addEventListener("click", () => Rt(e)));
1648
1658
  }
1649
- function It(e) {
1659
+ function Lt(e) {
1650
1660
  let t = document.querySelector("#generate-body"), n = document.querySelector("#generate-status");
1651
1661
  if (!t) return;
1652
1662
  n && (n.textContent = ""), t.textContent = "";
1653
1663
  let r = e.working.dimension ?? "2d";
1654
- jt = Ot(r);
1664
+ Mt = kt(r);
1655
1665
  let i = document.createElement("p");
1656
1666
  i.className = "gen-hint", i.textContent = I({
1657
1667
  en: `Deterministic ${r.toUpperCase()} environment generators — the subtree inserts under the selected node (the root when nothing is selected). The same seed always generates the same level.`,
1658
1668
  ko: `결정적 ${r.toUpperCase()} 환경 생성기 — 생성된 서브트리는 선택한 노드 아래에(선택이 없으면 루트에) 들어갑니다. 같은 시드는 항상 같은 레벨을 만듭니다.`
1659
1669
  }), t.appendChild(i);
1660
- let a = Rt(I({
1670
+ let a = zt(I({
1661
1671
  en: "generator",
1662
1672
  ko: "생성기"
1663
1673
  })), o = document.createElement("select");
1664
1674
  o.id = "generate-name";
1665
- for (let { name: e } of jt) {
1675
+ for (let { name: e } of Mt) {
1666
1676
  let t = document.createElement("option");
1667
1677
  t.value = e, t.textContent = e, o.appendChild(t);
1668
1678
  }
@@ -1671,23 +1681,23 @@ function It(e) {
1671
1681
  s.className = "gen-desc", t.appendChild(s);
1672
1682
  let c = document.createElement("div");
1673
1683
  c.id = "generate-params", t.appendChild(c);
1674
- let l = Rt("seed");
1675
- R = document.createElement("input"), R.type = "number", R.step = "1", R.value = String(At());
1684
+ let l = zt("seed");
1685
+ R = document.createElement("input"), R.type = "number", R.step = "1", R.value = String(jt());
1676
1686
  let u = document.createElement("button");
1677
1687
  u.type = "button", u.className = "ghost", u.textContent = "↻", u.title = I({
1678
1688
  en: "New random seed",
1679
1689
  ko: "새 랜덤 시드"
1680
1690
  }), u.addEventListener("click", () => {
1681
- R && (R.value = String(At()));
1691
+ R && (R.value = String(jt()));
1682
1692
  });
1683
1693
  let d = document.createElement("div");
1684
1694
  d.className = "gen-seed-row", d.append(R, u), l.appendChild(d), t.appendChild(l);
1685
1695
  let f = () => {
1686
- let e = jt.find((e) => e.name === o.value) ?? jt[0];
1696
+ let e = Mt.find((e) => e.name === o.value) ?? Mt[0];
1687
1697
  if (e) {
1688
- s.textContent = e.meta.description, c.textContent = "", Mt = /* @__PURE__ */ new Map();
1698
+ s.textContent = e.meta.description, c.textContent = "", Nt = /* @__PURE__ */ new Map();
1689
1699
  for (let [t, n] of Object.entries(e.meta.params)) {
1690
- let e = Rt(t), r;
1700
+ let e = zt(t), r;
1691
1701
  if (n.type === "boolean") r = document.createElement("input"), r.type = "checkbox", r.checked = n.default === !0;
1692
1702
  else if (n.type === "string" && n.options) {
1693
1703
  r = document.createElement("select");
@@ -1697,23 +1707,23 @@ function It(e) {
1697
1707
  }
1698
1708
  r.value = String(n.default);
1699
1709
  } else r = document.createElement("input"), r.type = n.type === "number" ? "number" : "text", n.type === "number" && (r.step = "any", n.min !== void 0 && (r.min = String(n.min)), n.max !== void 0 && (r.max = String(n.max))), r.value = String(n.default), (n.min !== void 0 || n.max !== void 0) && (r.title = `${n.min ?? ""}–${n.max ?? ""}`);
1700
- Mt.set(t, r), e.appendChild(r), c.appendChild(e);
1710
+ Nt.set(t, r), e.appendChild(r), c.appendChild(e);
1701
1711
  }
1702
1712
  }
1703
1713
  };
1704
1714
  o.addEventListener("change", f), f();
1705
1715
  }
1706
- function Lt(e) {
1707
- let t = document.querySelector("#generate-status"), n = document.querySelector("#generate-name"), r = jt.find((e) => e.name === n?.value);
1716
+ function Rt(e) {
1717
+ let t = document.querySelector("#generate-status"), n = document.querySelector("#generate-name"), r = Mt.find((e) => e.name === n?.value);
1708
1718
  if (!r || !R) return;
1709
- let i = { seed: kt({
1719
+ let i = { seed: At({
1710
1720
  type: "number",
1711
- default: At(),
1721
+ default: jt(),
1712
1722
  min: 0
1713
1723
  }, R.value) };
1714
- for (let [e, t] of Mt) {
1724
+ for (let [e, t] of Nt) {
1715
1725
  let n = r.meta.params[e];
1716
- n && (i[e] = kt(n, t.type === "checkbox" ? t.checked : t.value));
1726
+ n && (i[e] = At(n, t.type === "checkbox" ? t.checked : t.value));
1717
1727
  }
1718
1728
  let a;
1719
1729
  try {
@@ -1730,9 +1740,9 @@ function Lt(e) {
1730
1740
  }));
1731
1741
  return;
1732
1742
  }
1733
- e.select(o), R && (R.value = String(At())), Pt();
1743
+ e.select(o), R && (R.value = String(jt())), Ft();
1734
1744
  }
1735
- function Rt(e) {
1745
+ function zt(e) {
1736
1746
  let t = document.createElement("label");
1737
1747
  t.className = "field";
1738
1748
  let n = document.createElement("span");
@@ -1740,7 +1750,7 @@ function Rt(e) {
1740
1750
  }
1741
1751
  //#endregion
1742
1752
  //#region src/help.ts
1743
- var zt = {
1753
+ var Bt = {
1744
1754
  connections: {
1745
1755
  title: {
1746
1756
  en: "connections — wire a signal to a handler",
@@ -1810,21 +1820,21 @@ var zt = {
1810
1820
  },
1811
1821
  example: "\"physics\": { \"gravity\": [0, 1400] }"
1812
1822
  }
1813
- }, Bt = null;
1814
- function Vt(e) {
1823
+ }, Vt = null;
1824
+ function Ht(e) {
1815
1825
  document.addEventListener("click", (t) => {
1816
1826
  let n = t.target, r = n.closest("[data-help]");
1817
1827
  if (!r) {
1818
1828
  e.contains(n) || (e.hidden = !0);
1819
1829
  return;
1820
1830
  }
1821
- let i = zt[r.dataset.help ?? ""];
1831
+ let i = Bt[r.dataset.help ?? ""];
1822
1832
  if (!i) return;
1823
- if (!e.hidden && Bt === r) {
1833
+ if (!e.hidden && Vt === r) {
1824
1834
  e.hidden = !0;
1825
1835
  return;
1826
1836
  }
1827
- Bt = r, e.textContent = "";
1837
+ Vt = r, e.textContent = "";
1828
1838
  let a = document.createElement("h4");
1829
1839
  a.textContent = I(i.title);
1830
1840
  let o = document.createElement("div");
@@ -1841,24 +1851,37 @@ function Vt(e) {
1841
1851
  }), t.appendChild(n), e.appendChild(t);
1842
1852
  }
1843
1853
  e.hidden = !1;
1844
- let s = r.getBoundingClientRect();
1845
- e.style.left = `${Math.max(8, Math.min(innerWidth - 300 - 8, s.left - 300 + 20))}px`, e.style.top = `${Math.min(innerHeight - 60, s.bottom + 8)}px`;
1854
+ let s = e.getBoundingClientRect(), { left: c, top: l } = Ut(r.getBoundingClientRect(), {
1855
+ width: s.width,
1856
+ height: s.height
1857
+ }, {
1858
+ width: innerWidth,
1859
+ height: innerHeight
1860
+ });
1861
+ e.style.left = `${c}px`, e.style.top = `${l}px`;
1846
1862
  });
1847
1863
  }
1848
- function Ht(e) {
1864
+ function Ut(e, t, n, r = 8) {
1865
+ let i = t.width || 300, a = e.left - i + 20, o = Math.max(r, Math.min(n.width - i - r, a)), s = e.bottom + r, c = e.top - t.height - r, l;
1866
+ return l = s + t.height + r <= n.height ? s : c >= r ? c : r, {
1867
+ left: o,
1868
+ top: l
1869
+ };
1870
+ }
1871
+ function Wt(e) {
1849
1872
  let t = document.createElement("button");
1850
1873
  return t.type = "button", t.className = "help-btn", t.dataset.help = e, t.textContent = "?", t.title = "What is this?", t;
1851
1874
  }
1852
1875
  //#endregion
1853
1876
  //#region ../engine/assets/catalog.json
1854
- var Ut = /*#__PURE__*/ JSON.parse("[{\"name\":\"2dbasic\",\"file\":\"characters/2dbasic.png\",\"url\":\"incanto/assets/characters/2dbasic.png\",\"kind\":\"character\",\"bytes\":30499,\"description\":\"2dbasic sprite sheet image.anything,base character. (frame size 192x192)\",\"animation\":\"characters/2dbasic.json\",\"frameWidth\":111,\"frameHeight\":83},{\"name\":\"attacked\",\"file\":\"audio/attacked.mp3\",\"url\":\"incanto/assets/audio/attacked.mp3\",\"kind\":\"audio\",\"bytes\":8757,\"description\":\"Short hurt / took-damage SFX for the player or an enemy.\"},{\"name\":\"bark_birch_color\",\"file\":\"vegetation/bark/birch_color_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/birch_color_1k.jpg\",\"kind\":\"foliage\",\"bytes\":194186,\"description\":\"Birch bark base color texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_birch_normal\",\"file\":\"vegetation/bark/birch_normal_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/birch_normal_1k.jpg\",\"kind\":\"foliage\",\"bytes\":378046,\"description\":\"Birch bark tangent-space normal texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_birch_roughness\",\"file\":\"vegetation/bark/birch_roughness_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/birch_roughness_1k.jpg\",\"kind\":\"foliage\",\"bytes\":127387,\"description\":\"Birch bark roughness texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_oak_color\",\"file\":\"vegetation/bark/oak_color_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/oak_color_1k.jpg\",\"kind\":\"foliage\",\"bytes\":297877,\"description\":\"Oak bark base color texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_oak_normal\",\"file\":\"vegetation/bark/oak_normal_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/oak_normal_1k.jpg\",\"kind\":\"foliage\",\"bytes\":67610,\"description\":\"Oak bark tangent-space normal texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_oak_roughness\",\"file\":\"vegetation/bark/oak_roughness_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/oak_roughness_1k.jpg\",\"kind\":\"foliage\",\"bytes\":16648,\"description\":\"Oak bark roughness texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_pine_color\",\"file\":\"vegetation/bark/pine_color_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/pine_color_1k.jpg\",\"kind\":\"foliage\",\"bytes\":196361,\"description\":\"Pine bark base color texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_pine_normal\",\"file\":\"vegetation/bark/pine_normal_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/pine_normal_1k.jpg\",\"kind\":\"foliage\",\"bytes\":58237,\"description\":\"Pine bark tangent-space normal texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_pine_roughness\",\"file\":\"vegetation/bark/pine_roughness_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/pine_roughness_1k.jpg\",\"kind\":\"foliage\",\"bytes\":36136,\"description\":\"Pine bark roughness texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"box\",\"file\":\"items/box.png\",\"url\":\"incanto/assets/items/box.png\",\"kind\":\"item\",\"bytes\":10861,\"description\":\"Item box sprite for Dungeons and Dungeoners. Container sprite that holds random items or rewards when opened by player.\"},{\"name\":\"buff_potion\",\"file\":\"items/buff_potion.png\",\"url\":\"incanto/assets/items/buff_potion.png\",\"kind\":\"item\",\"bytes\":3809,\"description\":\"Buff potion item sprite for Dungeons and Dungeoners. Consumable item that grants temporary stat boosts or positive effects to player character.\"},{\"name\":\"coin\",\"file\":\"items/coin.png\",\"url\":\"incanto/assets/items/coin.png\",\"kind\":\"item\",\"bytes\":1689,\"description\":\"Gold coin collectible sprite for Dungeons and Dungeoners. Currency item with metallic sheen, used as in-game money or collectible reward.\"},{\"name\":\"explosion\",\"file\":\"audio/explosion.mp3\",\"url\":\"incanto/assets/audio/explosion.mp3\",\"kind\":\"audio\",\"bytes\":40124,\"description\":\"Impactful explosion / large destructive hit SFX. Pair with the Particles2D \\\"explosion\\\" preset.\"},{\"name\":\"floor00\",\"file\":\"tiles/floor00.jpg\",\"url\":\"incanto/assets/tiles/floor00.jpg\",\"kind\":\"tile\",\"bytes\":28736,\"description\":\"Basic floor tile texture for Dungeons and Dungeoners project, suitable for dungeon ground surfaces.\"},{\"name\":\"gem\",\"file\":\"items/gem.png\",\"url\":\"incanto/assets/items/gem.png\",\"kind\":\"item\",\"bytes\":8762,\"description\":\"Gem collectible sprite for Dungeons and Dungeoners. Valuable gemstone item used as currency, crafting material, or quest objective.\"},{\"name\":\"ghost\",\"file\":\"characters/ghost.png\",\"url\":\"incanto/assets/characters/ghost.png\",\"kind\":\"character\",\"bytes\":22933,\"description\":\"Ghost character with translucent appearance sprite sheet image (frame size 112x128)\",\"animation\":\"characters/ghost.json\",\"frameWidth\":112,\"frameHeight\":128},{\"name\":\"goblin\",\"file\":\"characters/goblin.png\",\"url\":\"incanto/assets/characters/goblin.png\",\"kind\":\"character\",\"bytes\":57994,\"description\":\"Medieval goblin with torch sprite sheet image (frame size 192x192)\",\"animation\":\"characters/goblin.json\",\"frameWidth\":192,\"frameHeight\":192},{\"name\":\"gold\",\"file\":\"items/gold.png\",\"url\":\"incanto/assets/items/gold.png\",\"kind\":\"item\",\"bytes\":22313,\"description\":\"Gold item sprite for Dungeons and Dungeoners. Gold pile or gold bar sprite representing valuable currency or treasure reward.\"},{\"name\":\"gold-loot\",\"file\":\"audio/gold_loot.mp3\",\"url\":\"incanto/assets/audio/gold_loot.mp3\",\"kind\":\"audio\",\"bytes\":7506,\"description\":\"Metallic coin / gold pickup jingle — collecting currency.\"},{\"name\":\"ground_dirt\",\"file\":\"vegetation/ground/dirt_color.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/ground/dirt_color.jpg\",\"kind\":\"foliage\",\"bytes\":231383,\"description\":\"Dense dirt/gravel ground texture (1024px) from the ez-tree demo app (MIT) — the reference meadow ground. Terrain3D grassland themes tile it for slope + noise-patch dirt by default; also bundled in `incanto/assets` (see `file`) for offline use.\"},{\"name\":\"ground_dirt_normal\",\"file\":\"vegetation/ground/dirt_normal.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/ground/dirt_normal.jpg\",\"kind\":\"foliage\",\"bytes\":123478,\"description\":\"Dirt ground normal map (1024px) from the ez-tree demo app (MIT). Terrain3D grassland themes apply it across the whole ground band (demo parity); also bundled in `incanto/assets` (see `file`) for offline use.\"},{\"name\":\"ground_grass\",\"file\":\"vegetation/ground/grass.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/ground/grass.jpg\",\"kind\":\"foliage\",\"bytes\":322486,\"description\":\"Mossy meadow grass ground texture (1024px) from the ez-tree demo app (MIT). Terrain3D grassland themes (meadow/forest generators) tile it as the grass splat layer by default; also bundled in `incanto/assets` (see `file`) for offline use.\"},{\"name\":\"heal\",\"file\":\"audio/heal.mp3\",\"url\":\"incanto/assets/audio/heal.mp3\",\"kind\":\"audio\",\"bytes\":29764,\"description\":\"Soothing health-restore / heal spell SFX.\"},{\"name\":\"hit-metal-bang\",\"file\":\"audio/hit_metal_bang.mp3\",\"url\":\"incanto/assets/audio/hit_metal_bang.mp3\",\"kind\":\"audio\",\"bytes\":17972,\"description\":\"Metallic impact — hitting armor, metal, or a blocked attack.\"},{\"name\":\"hp_potion\",\"file\":\"items/hp_potion.png\",\"url\":\"incanto/assets/items/hp_potion.png\",\"kind\":\"item\",\"bytes\":3513,\"description\":\"Health potion item sprite for Dungeons and Dungeoners. Consumable healing item that restores player health points when used.\"},{\"name\":\"ice-spear\",\"file\":\"audio/ice_spear.mp3\",\"url\":\"incanto/assets/audio/ice_spear.mp3\",\"kind\":\"audio\",\"bytes\":21315,\"description\":\"Sharp piercing ice projectile fire SFX.\"},{\"name\":\"leaves_ash\",\"file\":\"vegetation/ash_color.png\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/ash_color.png\",\"kind\":\"foliage\",\"bytes\":181423,\"description\":\"Ash leaf-cluster alpha-cutout texture (1024px) from ez-tree by Dan Greenheck (MIT). Tree3D samples it for broadleaf/dead ash variants by default; copy it next to your game and set leafTexture to serve offline.\"},{\"name\":\"leaves_aspen\",\"file\":\"vegetation/aspen_color.png\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/aspen_color.png\",\"kind\":\"foliage\",\"bytes\":142116,\"description\":\"Aspen leaf-cluster alpha-cutout texture (1024px) from ez-tree by Dan Greenheck (MIT). Tree3D samples it for high-tier broadleaf aspen variants; copy + leafTexture for offline serving.\"},{\"name\":\"leaves_oak\",\"file\":\"vegetation/oak_color.png\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/oak_color.png\",\"kind\":\"foliage\",\"bytes\":238115,\"description\":\"Oak leaf-cluster alpha-cutout texture (1024px) from ez-tree by Dan Greenheck (MIT). Tree3D samples it for broadleaf oak variants by default; copy + leafTexture for offline serving.\"},{\"name\":\"leaves_pine\",\"file\":\"vegetation/pine_color.png\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/pine_color.png\",\"kind\":\"foliage\",\"bytes\":303684,\"description\":\"Pine needle-cluster alpha-cutout texture (1024px) from ez-tree by Dan Greenheck (MIT). Tree3D samples it for conifer variants by default; copy + leafTexture for offline serving.\"},{\"name\":\"locked_item_box\",\"file\":\"items/locked_item_box.png\",\"url\":\"incanto/assets/items/locked_item_box.png\",\"kind\":\"item\",\"bytes\":11074,\"description\":\"Locked item box sprite for Dungeons and Dungeoners. Container sprite requiring key or lockpick to open, containing valuable rewards.\"},{\"name\":\"map\",\"file\":\"items/map.png\",\"url\":\"incanto/assets/items/map.png\",\"kind\":\"item\",\"bytes\":3754,\"description\":\"Map item sprite for Dungeons and Dungeoners. Navigation item revealing dungeon layout or providing exploration assistance.\"},{\"name\":\"medieval-knight\",\"file\":\"characters/medieval-knight.png\",\"url\":\"incanto/assets/characters/medieval-knight.png\",\"kind\":\"character\",\"bytes\":84367,\"description\":\"(frame size 192x192) Using a medieval-themed SD(Super Deformed) knight sprite sheet image, you can apply idle, move, and attack animations, among others.\",\"animation\":\"characters/medieval-knight.json\",\"frameWidth\":192,\"frameHeight\":192},{\"name\":\"minecraft-tiles\",\"file\":\"tiles/minecraft-tiles.png\",\"url\":\"incanto/assets/tiles/minecraft-tiles.png\",\"kind\":\"tile\",\"bytes\":10511,\"description\":\"Minecraft-themed tiles sprite sheet image (frame size 16x16)\"},{\"name\":\"monster-died\",\"file\":\"audio/monster_died.mp3\",\"url\":\"incanto/assets/audio/monster_died.mp3\",\"kind\":\"audio\",\"bytes\":16836,\"description\":\"Enemy defeat / death SFX.\"},{\"name\":\"resurrection_potion\",\"file\":\"items/resurrection_potion.png\",\"url\":\"incanto/assets/items/resurrection_potion.png\",\"kind\":\"item\",\"bytes\":3471,\"description\":\"Resurrection potion item sprite for Dungeons and Dungeoners. Rare consumable that revives fallen party members or prevents death.\"},{\"name\":\"slash\",\"file\":\"audio/slash.mp3\",\"url\":\"incanto/assets/audio/slash.mp3\",\"kind\":\"audio\",\"bytes\":10425,\"description\":\"Quick sword swing / melee slash SFX.\"},{\"name\":\"smite\",\"file\":\"audio/smite.mp3\",\"url\":\"incanto/assets/audio/smite.mp3\",\"kind\":\"audio\",\"bytes\":12956,\"description\":\"Powerful holy downward-strike SFX.\"},{\"name\":\"spells-cast\",\"file\":\"audio/spells_cast.mp3\",\"url\":\"incanto/assets/audio/spells_cast.mp3\",\"kind\":\"audio\",\"bytes\":22151,\"description\":\"Generic magical spell-cast / chant SFX.\"},{\"name\":\"super_box\",\"file\":\"items/super_box.png\",\"url\":\"incanto/assets/items/super_box.png\",\"kind\":\"item\",\"bytes\":12184,\"description\":\"Super item box sprite for Dungeons and Dungeoners. Premium container sprite containing rare or powerful items and equipment.\"},{\"name\":\"swoosh\",\"file\":\"effects/swoosh.png\",\"url\":\"incanto/assets/effects/swoosh.png\",\"kind\":\"effect\",\"bytes\":2599,\"description\":\"Swoosh effect sprite for Dungeons and Dungeoners. Motion blur or attack trail effect used for melee attacks, sword slashes, or fast movement animations.\"},{\"name\":\"trap\",\"file\":\"items/trap.png\",\"url\":\"incanto/assets/items/trap.png\",\"kind\":\"item\",\"bytes\":3969,\"description\":\"Trap object sprite for Dungeons and Dungeoners. Hazard sprite that damages players when triggered in dungeon exploration.\"},{\"name\":\"ui-click\",\"file\":\"audio/ui_click.wav\",\"url\":\"incanto/assets/audio/ui_click.wav\",\"kind\":\"audio\",\"bytes\":17332,\"description\":\"Short tactile UI click for menus and buttons.\"},{\"name\":\"walk\",\"file\":\"audio/walk.mp3\",\"url\":\"incanto/assets/audio/walk.mp3\",\"kind\":\"audio\",\"bytes\":5642,\"description\":\"Single footstep SFX for character movement (loop or one-shot).\"},{\"name\":\"wall00\",\"file\":\"tiles/wall00.jpg\",\"url\":\"incanto/assets/tiles/wall00.jpg\",\"kind\":\"tile\",\"bytes\":44344,\"description\":\"Basic wall tile texture for Dungeons and Dungeoners project, suitable for dungeon vertical boundaries.\"}]");
1877
+ var Gt = /*#__PURE__*/ JSON.parse("[{\"name\":\"2dbasic\",\"file\":\"characters/2dbasic.png\",\"url\":\"incanto/assets/characters/2dbasic.png\",\"kind\":\"character\",\"bytes\":30499,\"description\":\"2dbasic sprite sheet image.anything,base character. (frame size 192x192)\",\"animation\":\"characters/2dbasic.json\",\"frameWidth\":111,\"frameHeight\":83},{\"name\":\"attacked\",\"file\":\"audio/attacked.mp3\",\"url\":\"incanto/assets/audio/attacked.mp3\",\"kind\":\"audio\",\"bytes\":8757,\"description\":\"Short hurt / took-damage SFX for the player or an enemy.\"},{\"name\":\"bark_birch_color\",\"file\":\"vegetation/bark/birch_color_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/birch_color_1k.jpg\",\"kind\":\"foliage\",\"bytes\":194186,\"description\":\"Birch bark base color texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_birch_normal\",\"file\":\"vegetation/bark/birch_normal_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/birch_normal_1k.jpg\",\"kind\":\"foliage\",\"bytes\":378046,\"description\":\"Birch bark tangent-space normal texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_birch_roughness\",\"file\":\"vegetation/bark/birch_roughness_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/birch_roughness_1k.jpg\",\"kind\":\"foliage\",\"bytes\":127387,\"description\":\"Birch bark roughness texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_oak_color\",\"file\":\"vegetation/bark/oak_color_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/oak_color_1k.jpg\",\"kind\":\"foliage\",\"bytes\":297877,\"description\":\"Oak bark base color texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_oak_normal\",\"file\":\"vegetation/bark/oak_normal_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/oak_normal_1k.jpg\",\"kind\":\"foliage\",\"bytes\":67610,\"description\":\"Oak bark tangent-space normal texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_oak_roughness\",\"file\":\"vegetation/bark/oak_roughness_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/oak_roughness_1k.jpg\",\"kind\":\"foliage\",\"bytes\":16648,\"description\":\"Oak bark roughness texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_pine_color\",\"file\":\"vegetation/bark/pine_color_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/pine_color_1k.jpg\",\"kind\":\"foliage\",\"bytes\":196361,\"description\":\"Pine bark base color texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_pine_normal\",\"file\":\"vegetation/bark/pine_normal_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/pine_normal_1k.jpg\",\"kind\":\"foliage\",\"bytes\":58237,\"description\":\"Pine bark tangent-space normal texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"bark_pine_roughness\",\"file\":\"vegetation/bark/pine_roughness_1k.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/bark/pine_roughness_1k.jpg\",\"kind\":\"foliage\",\"bytes\":36136,\"description\":\"Pine bark roughness texture (1k), ambientcg Bark (CC0) packaged by ez-tree (MIT). Tree3D trunks/branches sample it by default from the agent8 CDN (the only sanctioned external host); the bundled `incanto/assets` copy (see this entry’s `file`) serves it offline.\"},{\"name\":\"box\",\"file\":\"items/box.png\",\"url\":\"incanto/assets/items/box.png\",\"kind\":\"item\",\"bytes\":10861,\"description\":\"Item box sprite for Dungeons and Dungeoners. Container sprite that holds random items or rewards when opened by player.\"},{\"name\":\"buff_potion\",\"file\":\"items/buff_potion.png\",\"url\":\"incanto/assets/items/buff_potion.png\",\"kind\":\"item\",\"bytes\":3809,\"description\":\"Buff potion item sprite for Dungeons and Dungeoners. Consumable item that grants temporary stat boosts or positive effects to player character.\"},{\"name\":\"coin\",\"file\":\"items/coin.png\",\"url\":\"incanto/assets/items/coin.png\",\"kind\":\"item\",\"bytes\":1689,\"description\":\"Gold coin collectible sprite for Dungeons and Dungeoners. Currency item with metallic sheen, used as in-game money or collectible reward.\"},{\"name\":\"explosion\",\"file\":\"audio/explosion.mp3\",\"url\":\"incanto/assets/audio/explosion.mp3\",\"kind\":\"audio\",\"bytes\":40124,\"description\":\"Impactful explosion / large destructive hit SFX. Pair with the Particles2D \\\"explosion\\\" preset.\"},{\"name\":\"floor00\",\"file\":\"tiles/floor00.jpg\",\"url\":\"incanto/assets/tiles/floor00.jpg\",\"kind\":\"tile\",\"bytes\":28736,\"description\":\"Basic floor tile texture for Dungeons and Dungeoners project, suitable for dungeon ground surfaces.\"},{\"name\":\"gem\",\"file\":\"items/gem.png\",\"url\":\"incanto/assets/items/gem.png\",\"kind\":\"item\",\"bytes\":8762,\"description\":\"Gem collectible sprite for Dungeons and Dungeoners. Valuable gemstone item used as currency, crafting material, or quest objective.\"},{\"name\":\"ghost\",\"file\":\"characters/ghost.png\",\"url\":\"incanto/assets/characters/ghost.png\",\"kind\":\"character\",\"bytes\":22933,\"description\":\"Ghost character with translucent appearance sprite sheet image (frame size 112x128)\",\"animation\":\"characters/ghost.json\",\"frameWidth\":112,\"frameHeight\":128},{\"name\":\"goblin\",\"file\":\"characters/goblin.png\",\"url\":\"incanto/assets/characters/goblin.png\",\"kind\":\"character\",\"bytes\":57994,\"description\":\"Medieval goblin with torch sprite sheet image (frame size 192x192)\",\"animation\":\"characters/goblin.json\",\"frameWidth\":192,\"frameHeight\":192},{\"name\":\"gold\",\"file\":\"items/gold.png\",\"url\":\"incanto/assets/items/gold.png\",\"kind\":\"item\",\"bytes\":22313,\"description\":\"Gold item sprite for Dungeons and Dungeoners. Gold pile or gold bar sprite representing valuable currency or treasure reward.\"},{\"name\":\"gold-loot\",\"file\":\"audio/gold_loot.mp3\",\"url\":\"incanto/assets/audio/gold_loot.mp3\",\"kind\":\"audio\",\"bytes\":7506,\"description\":\"Metallic coin / gold pickup jingle — collecting currency.\"},{\"name\":\"ground_dirt\",\"file\":\"vegetation/ground/dirt_color.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/ground/dirt_color.jpg\",\"kind\":\"foliage\",\"bytes\":231383,\"description\":\"Dense dirt/gravel ground texture (1024px) from the ez-tree demo app (MIT) — the reference meadow ground. Terrain3D grassland themes tile it for slope + noise-patch dirt by default; also bundled in `incanto/assets` (see `file`) for offline use.\"},{\"name\":\"ground_dirt_normal\",\"file\":\"vegetation/ground/dirt_normal.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/ground/dirt_normal.jpg\",\"kind\":\"foliage\",\"bytes\":123478,\"description\":\"Dirt ground normal map (1024px) from the ez-tree demo app (MIT). Terrain3D grassland themes apply it across the whole ground band (demo parity); also bundled in `incanto/assets` (see `file`) for offline use.\"},{\"name\":\"ground_grass\",\"file\":\"vegetation/ground/grass.jpg\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/ground/grass.jpg\",\"kind\":\"foliage\",\"bytes\":322486,\"description\":\"Mossy meadow grass ground texture (1024px) from the ez-tree demo app (MIT). Terrain3D grassland themes (meadow/forest generators) tile it as the grass splat layer by default; also bundled in `incanto/assets` (see `file`) for offline use.\"},{\"name\":\"heal\",\"file\":\"audio/heal.mp3\",\"url\":\"incanto/assets/audio/heal.mp3\",\"kind\":\"audio\",\"bytes\":29764,\"description\":\"Soothing health-restore / heal spell SFX.\"},{\"name\":\"hit-metal-bang\",\"file\":\"audio/hit_metal_bang.mp3\",\"url\":\"incanto/assets/audio/hit_metal_bang.mp3\",\"kind\":\"audio\",\"bytes\":17972,\"description\":\"Metallic impact — hitting armor, metal, or a blocked attack.\"},{\"name\":\"hp_potion\",\"file\":\"items/hp_potion.png\",\"url\":\"incanto/assets/items/hp_potion.png\",\"kind\":\"item\",\"bytes\":3513,\"description\":\"Health potion item sprite for Dungeons and Dungeoners. Consumable healing item that restores player health points when used.\"},{\"name\":\"ice-spear\",\"file\":\"audio/ice_spear.mp3\",\"url\":\"incanto/assets/audio/ice_spear.mp3\",\"kind\":\"audio\",\"bytes\":21315,\"description\":\"Sharp piercing ice projectile fire SFX.\"},{\"name\":\"leaves_ash\",\"file\":\"vegetation/ash_color.png\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/ash_color.png\",\"kind\":\"foliage\",\"bytes\":181423,\"description\":\"Ash leaf-cluster alpha-cutout texture (1024px) from ez-tree by Dan Greenheck (MIT). Tree3D samples it for broadleaf/dead ash variants by default; copy it next to your game and set leafTexture to serve offline.\"},{\"name\":\"leaves_aspen\",\"file\":\"vegetation/aspen_color.png\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/aspen_color.png\",\"kind\":\"foliage\",\"bytes\":142116,\"description\":\"Aspen leaf-cluster alpha-cutout texture (1024px) from ez-tree by Dan Greenheck (MIT). Tree3D samples it for high-tier broadleaf aspen variants; copy + leafTexture for offline serving.\"},{\"name\":\"leaves_oak\",\"file\":\"vegetation/oak_color.png\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/oak_color.png\",\"kind\":\"foliage\",\"bytes\":238115,\"description\":\"Oak leaf-cluster alpha-cutout texture (1024px) from ez-tree by Dan Greenheck (MIT). Tree3D samples it for broadleaf oak variants by default; copy + leafTexture for offline serving.\"},{\"name\":\"leaves_pine\",\"file\":\"vegetation/pine_color.png\",\"url\":\"https://agent8-games.verse8.io/assets/3D/default/textures/vegetation/pine_color.png\",\"kind\":\"foliage\",\"bytes\":303684,\"description\":\"Pine needle-cluster alpha-cutout texture (1024px) from ez-tree by Dan Greenheck (MIT). Tree3D samples it for conifer variants by default; copy + leafTexture for offline serving.\"},{\"name\":\"locked_item_box\",\"file\":\"items/locked_item_box.png\",\"url\":\"incanto/assets/items/locked_item_box.png\",\"kind\":\"item\",\"bytes\":11074,\"description\":\"Locked item box sprite for Dungeons and Dungeoners. Container sprite requiring key or lockpick to open, containing valuable rewards.\"},{\"name\":\"map\",\"file\":\"items/map.png\",\"url\":\"incanto/assets/items/map.png\",\"kind\":\"item\",\"bytes\":3754,\"description\":\"Map item sprite for Dungeons and Dungeoners. Navigation item revealing dungeon layout or providing exploration assistance.\"},{\"name\":\"medieval-knight\",\"file\":\"characters/medieval-knight.png\",\"url\":\"incanto/assets/characters/medieval-knight.png\",\"kind\":\"character\",\"bytes\":84367,\"description\":\"(frame size 192x192) Using a medieval-themed SD(Super Deformed) knight sprite sheet image, you can apply idle, move, and attack animations, among others.\",\"animation\":\"characters/medieval-knight.json\",\"frameWidth\":192,\"frameHeight\":192},{\"name\":\"minecraft-tiles\",\"file\":\"tiles/minecraft-tiles.png\",\"url\":\"incanto/assets/tiles/minecraft-tiles.png\",\"kind\":\"tile\",\"bytes\":10511,\"description\":\"Minecraft-themed tiles sprite sheet image (frame size 16x16)\"},{\"name\":\"monster-died\",\"file\":\"audio/monster_died.mp3\",\"url\":\"incanto/assets/audio/monster_died.mp3\",\"kind\":\"audio\",\"bytes\":16836,\"description\":\"Enemy defeat / death SFX.\"},{\"name\":\"resurrection_potion\",\"file\":\"items/resurrection_potion.png\",\"url\":\"incanto/assets/items/resurrection_potion.png\",\"kind\":\"item\",\"bytes\":3471,\"description\":\"Resurrection potion item sprite for Dungeons and Dungeoners. Rare consumable that revives fallen party members or prevents death.\"},{\"name\":\"slash\",\"file\":\"audio/slash.mp3\",\"url\":\"incanto/assets/audio/slash.mp3\",\"kind\":\"audio\",\"bytes\":10425,\"description\":\"Quick sword swing / melee slash SFX.\"},{\"name\":\"smite\",\"file\":\"audio/smite.mp3\",\"url\":\"incanto/assets/audio/smite.mp3\",\"kind\":\"audio\",\"bytes\":12956,\"description\":\"Powerful holy downward-strike SFX.\"},{\"name\":\"spells-cast\",\"file\":\"audio/spells_cast.mp3\",\"url\":\"incanto/assets/audio/spells_cast.mp3\",\"kind\":\"audio\",\"bytes\":22151,\"description\":\"Generic magical spell-cast / chant SFX.\"},{\"name\":\"super_box\",\"file\":\"items/super_box.png\",\"url\":\"incanto/assets/items/super_box.png\",\"kind\":\"item\",\"bytes\":12184,\"description\":\"Super item box sprite for Dungeons and Dungeoners. Premium container sprite containing rare or powerful items and equipment.\"},{\"name\":\"swoosh\",\"file\":\"effects/swoosh.png\",\"url\":\"incanto/assets/effects/swoosh.png\",\"kind\":\"effect\",\"bytes\":2599,\"description\":\"Swoosh effect sprite for Dungeons and Dungeoners. Motion blur or attack trail effect used for melee attacks, sword slashes, or fast movement animations.\"},{\"name\":\"trap\",\"file\":\"items/trap.png\",\"url\":\"incanto/assets/items/trap.png\",\"kind\":\"item\",\"bytes\":3969,\"description\":\"Trap object sprite for Dungeons and Dungeoners. Hazard sprite that damages players when triggered in dungeon exploration.\"},{\"name\":\"ui-click\",\"file\":\"audio/ui_click.wav\",\"url\":\"incanto/assets/audio/ui_click.wav\",\"kind\":\"audio\",\"bytes\":17332,\"description\":\"Short tactile UI click for menus and buttons.\"},{\"name\":\"walk\",\"file\":\"audio/walk.mp3\",\"url\":\"incanto/assets/audio/walk.mp3\",\"kind\":\"audio\",\"bytes\":5642,\"description\":\"Single footstep SFX for character movement (loop or one-shot).\"},{\"name\":\"wall00\",\"file\":\"tiles/wall00.jpg\",\"url\":\"incanto/assets/tiles/wall00.jpg\",\"kind\":\"tile\",\"bytes\":44344,\"description\":\"Basic wall tile texture for Dungeons and Dungeoners project, suitable for dungeon vertical boundaries.\"}]");
1855
1878
  //#endregion
1856
1879
  //#region src/connections.ts
1857
- function Wt(e) {
1880
+ function Kt(e) {
1858
1881
  let t = e.connections;
1859
1882
  return Array.isArray(t) ? t : [];
1860
1883
  }
1861
- function Gt(e, t) {
1884
+ function qt(e, t) {
1862
1885
  if (!e || t === "") return null;
1863
1886
  if (t === ".") return [];
1864
1887
  if (t.startsWith("%")) {
@@ -1882,7 +1905,7 @@ function Gt(e, t) {
1882
1905
  for (let t of i) {
1883
1906
  if (t === "..") {
1884
1907
  if (a.length === 0) return null;
1885
- a.pop(), o = Kt(e, a);
1908
+ a.pop(), o = Jt(e, a);
1886
1909
  continue;
1887
1910
  }
1888
1911
  let n = (o.children ?? []).findIndex((e) => e.name === t);
@@ -1891,12 +1914,12 @@ function Gt(e, t) {
1891
1914
  }
1892
1915
  return a;
1893
1916
  }
1894
- function Kt(e, t) {
1917
+ function Jt(e, t) {
1895
1918
  let n = e;
1896
1919
  for (let e of t) n = n?.children?.[e];
1897
1920
  return n ?? null;
1898
1921
  }
1899
- function qt(e, t) {
1922
+ function Yt(e, t) {
1900
1923
  if (!e) return "";
1901
1924
  if (t.length === 0) return ".";
1902
1925
  let n = [], r = e;
@@ -1907,13 +1930,13 @@ function qt(e, t) {
1907
1930
  }
1908
1931
  return n.join("/");
1909
1932
  }
1910
- function Jt(e, t) {
1933
+ function Xt(e, t) {
1911
1934
  let n = e.root, r = (e) => {
1912
1935
  if (typeof e != "string") return !1;
1913
- let r = Gt(n, e);
1936
+ let r = qt(n, e);
1914
1937
  return r !== null && r.length === t.length && r.every((e, n) => e === t[n]);
1915
1938
  }, i = [], a = [];
1916
- return Wt(e).forEach((e, t) => {
1939
+ return Kt(e).forEach((e, t) => {
1917
1940
  r(e.from) && i.push({
1918
1941
  index: t,
1919
1942
  conn: e
@@ -1926,7 +1949,7 @@ function Jt(e, t) {
1926
1949
  incoming: a
1927
1950
  };
1928
1951
  }
1929
- function Yt(e) {
1952
+ function Zt(e) {
1930
1953
  if (!e) return [];
1931
1954
  let t = [];
1932
1955
  if (typeof e.type == "string" && e.type !== "") try {
@@ -1935,7 +1958,7 @@ function Yt(e) {
1935
1958
  let r = e.script;
1936
1959
  return typeof r?.name == "string" && t.push(...n(r.name)), [...new Set(t)];
1937
1960
  }
1938
- function Xt(e) {
1961
+ function Qt(e) {
1939
1962
  if (!e || e.script?.name) return [];
1940
1963
  let t = typeof e.type == "string" ? e.type : "";
1941
1964
  if (!t) return [];
@@ -1950,10 +1973,10 @@ function Xt(e) {
1950
1973
  for (let t of Object.getOwnPropertyNames(e)) t === "constructor" || t.startsWith("_") || typeof Object.getOwnPropertyDescriptor(e, t)?.value == "function" && r.add(t);
1951
1974
  e = Object.getPrototypeOf(e);
1952
1975
  }
1953
- for (let e of Zt) r.delete(e);
1976
+ for (let e of $t) r.delete(e);
1954
1977
  return [...r].sort();
1955
1978
  }
1956
- var Zt = new Set([
1979
+ var $t = new Set([
1957
1980
  "addChild",
1958
1981
  "removeChild",
1959
1982
  "addToGroup",
@@ -1975,7 +1998,7 @@ var Zt = new Set([
1975
1998
  "toJSON",
1976
1999
  "diagnose"
1977
2000
  ]);
1978
- function Qt(e) {
2001
+ function en(e) {
1979
2002
  if (!e) return [];
1980
2003
  let t = [{
1981
2004
  path: ".",
@@ -1984,59 +2007,59 @@ function Qt(e) {
1984
2007
  (r.children ?? []).forEach((r, a) => {
1985
2008
  let o = [...i, a];
1986
2009
  t.push({
1987
- path: qt(e, o),
1988
- label: qt(e, o)
2010
+ path: Yt(e, o),
2011
+ label: Yt(e, o)
1989
2012
  }), n(r, o);
1990
2013
  });
1991
2014
  };
1992
2015
  return n(e, []), t;
1993
2016
  }
1994
- function $t(e, t) {
2017
+ function tn(e, t) {
1995
2018
  Array.isArray(e.connections) || (e.connections = []);
1996
2019
  let n = e.connections;
1997
2020
  return n.push(t), n.length - 1;
1998
2021
  }
1999
- function en(e, t, n) {
2000
- let r = Wt(e)[t];
2022
+ function nn(e, t, n) {
2023
+ let r = Kt(e)[t];
2001
2024
  r && Object.assign(r, n);
2002
2025
  }
2003
- function tn(e, t) {
2004
- let n = Wt(e);
2026
+ function rn(e, t) {
2027
+ let n = Kt(e);
2005
2028
  t < 0 || t >= n.length || (n.splice(t, 1), n.length === 0 && delete e.connections);
2006
2029
  }
2007
2030
  //#endregion
2008
2031
  //#region src/connections-ui.ts
2009
- function nn(e, t) {
2032
+ function an(e, t) {
2010
2033
  let n = e.working.root;
2011
2034
  if (!n) return null;
2012
2035
  let r = e.nodeAt(t);
2013
2036
  if (!r) return null;
2014
2037
  let i = document.createElement("div");
2015
2038
  i.className = "connections";
2016
- let { outgoing: a, incoming: o } = Jt(e.working, t), s = qt(n, t);
2017
- i.appendChild(rn(I({
2039
+ let { outgoing: a, incoming: o } = Xt(e.working, t), s = Yt(n, t);
2040
+ i.appendChild(on(I({
2018
2041
  en: `emits (${a.length})`,
2019
2042
  ko: `보냄 (${a.length})`
2020
2043
  })));
2021
- for (let t of a) i.appendChild(an(e, t, "out"));
2022
- if (i.appendChild(on(e, r, s)), o.length > 0) {
2023
- i.appendChild(rn(I({
2044
+ for (let t of a) i.appendChild(sn(e, t, "out"));
2045
+ if (i.appendChild(cn(e, r, s)), o.length > 0) {
2046
+ i.appendChild(on(I({
2024
2047
  en: `receives (${o.length})`,
2025
2048
  ko: `받음 (${o.length})`
2026
2049
  })));
2027
- for (let t of o) i.appendChild(an(e, t, "in"));
2050
+ for (let t of o) i.appendChild(sn(e, t, "in"));
2028
2051
  }
2029
2052
  return i;
2030
2053
  }
2031
- function rn(e) {
2054
+ function on(e) {
2032
2055
  let t = document.createElement("div");
2033
2056
  return t.className = "conn-group", t.textContent = e, t;
2034
2057
  }
2035
- function an(e, { index: t, conn: n }, r) {
2058
+ function sn(e, { index: t, conn: n }, r) {
2036
2059
  let i = e.working.root, a = document.createElement("div");
2037
2060
  a.className = "conn-row";
2038
- let o = e.nodeAt(Gt(i, String(n.from ?? "")) ?? [-1]), s = r === "out" ? "to" : "from", c = String(n[s] ?? ""), l = Gt(i, c) === null, u = sn(Yt(o), String(n.signal ?? ""), (n) => {
2039
- e.mutate(() => en(e.working, t, { signal: n }));
2061
+ let o = e.nodeAt(qt(i, String(n.from ?? "")) ?? [-1]), s = r === "out" ? "to" : "from", c = String(n[s] ?? ""), l = qt(i, c) === null, u = ln(Zt(o), String(n.signal ?? ""), (n) => {
2062
+ e.mutate(() => nn(e.working, t, { signal: n }));
2040
2063
  });
2041
2064
  u.title = I({
2042
2065
  en: "signal",
@@ -2044,18 +2067,18 @@ function an(e, { index: t, conn: n }, r) {
2044
2067
  });
2045
2068
  let d = document.createElement("span");
2046
2069
  d.className = "conn-arrow", d.textContent = r === "out" ? "→" : "←";
2047
- let f = sn(Qt(i).map((e) => e.path), c, (n) => {
2048
- e.mutate(() => en(e.working, t, { [s]: n }));
2070
+ let f = ln(en(i).map((e) => e.path), c, (n) => {
2071
+ e.mutate(() => nn(e.working, t, { [s]: n }));
2049
2072
  });
2050
2073
  f.title = I({
2051
2074
  en: s,
2052
2075
  ko: s === "to" ? "대상" : "출처"
2053
2076
  }), l && f.classList.add("dangling");
2054
- let p = Xt(e.nodeAt(Gt(i, String(n.to ?? "")) ?? [-1])), m = (n) => {
2055
- e.mutate(() => en(e.working, t, { handler: n.trim() }));
2077
+ let p = Qt(e.nodeAt(qt(i, String(n.to ?? "")) ?? [-1])), m = (n) => {
2078
+ e.mutate(() => nn(e.working, t, { handler: n.trim() }));
2056
2079
  }, h;
2057
2080
  if (p.length > 0) {
2058
- let e = sn(p, String(n.handler ?? ""), m);
2081
+ let e = ln(p, String(n.handler ?? ""), m);
2059
2082
  e.title = I({
2060
2083
  en: "handler method",
2061
2084
  ko: "핸들러 메서드"
@@ -2072,7 +2095,7 @@ function an(e, { index: t, conn: n }, r) {
2072
2095
  en: "remove this connection",
2073
2096
  ko: "이 연결 삭제"
2074
2097
  }), g.addEventListener("click", () => {
2075
- e.mutate(() => tn(e.working, t));
2098
+ e.mutate(() => rn(e.working, t));
2076
2099
  }), a.append(u, d, f, h, g), l) {
2077
2100
  let e = document.createElement("div");
2078
2101
  e.className = "conn-warn", e.textContent = I({
@@ -2084,8 +2107,8 @@ function an(e, { index: t, conn: n }, r) {
2084
2107
  }
2085
2108
  return a;
2086
2109
  }
2087
- function on(e, t, n) {
2088
- let r = Yt(t), i = document.createElement("div");
2110
+ function cn(e, t, n) {
2111
+ let r = Zt(t), i = document.createElement("div");
2089
2112
  i.className = "conn-add";
2090
2113
  let a = document.createElement("button");
2091
2114
  return a.type = "button", a.textContent = I({
@@ -2099,14 +2122,14 @@ function on(e, t, n) {
2099
2122
  from: n,
2100
2123
  signal: i,
2101
2124
  to: n,
2102
- handler: Xt(t)[0] ?? `on${i.charAt(0).toUpperCase()}${i.slice(1)}`
2125
+ handler: Qt(t)[0] ?? `on${i.charAt(0).toUpperCase()}${i.slice(1)}`
2103
2126
  };
2104
2127
  e.mutate(() => {
2105
- $t(e.working, a);
2128
+ tn(e.working, a);
2106
2129
  });
2107
2130
  }), i.appendChild(a), i;
2108
2131
  }
2109
- function sn(e, t, n) {
2132
+ function ln(e, t, n) {
2110
2133
  let r = document.createElement("select");
2111
2134
  r.className = "conn-select";
2112
2135
  for (let n of e.includes(t) ? e : [t, ...e]) {
@@ -2117,13 +2140,13 @@ function sn(e, t, n) {
2117
2140
  }
2118
2141
  //#endregion
2119
2142
  //#region src/tilemap-paint.ts
2120
- function cn(e, t, n, r) {
2143
+ function un(e, t, n, r) {
2121
2144
  return {
2122
2145
  cx: Math.floor((n - e.x) / t),
2123
2146
  cy: Math.floor((r - e.y) / t)
2124
2147
  };
2125
2148
  }
2126
- function ln(e, t, n, r) {
2149
+ function dn(e, t, n, r) {
2127
2150
  if (t < 0 || n < 0 || r.length !== 1) return null;
2128
2151
  let i = e.map((e) => typeof e == "string" ? e : e.map((e) => e >= 0 && e <= 9 ? String(e) : ".").join("")), a = Math.max(t + 1, ...i.map((e) => e.length)), o = Math.max(n + 1, i.length), s = [];
2129
2152
  for (let e = 0; e < o; e++) {
@@ -2132,7 +2155,7 @@ function ln(e, t, n, r) {
2132
2155
  }
2133
2156
  return s;
2134
2157
  }
2135
- function un(e, t) {
2158
+ function fn(e, t) {
2136
2159
  let n = new Set([
2137
2160
  ".",
2138
2161
  "0",
@@ -2144,25 +2167,25 @@ function un(e, t) {
2144
2167
  }
2145
2168
  //#endregion
2146
2169
  //#region src/inspector.ts
2147
- var dn = Ut;
2148
- function fn(e) {
2170
+ var pn = Gt;
2171
+ function mn(e) {
2149
2172
  return (e.kind === "foliage" || e.kind === "tile") && !e.animation;
2150
2173
  }
2151
- function pn(e, t, n) {
2174
+ function hn(e, t, n) {
2152
2175
  if (e.textContent = "", t.selection === null) {
2153
- hn(e, t, n);
2176
+ _n(e, t, n);
2154
2177
  return;
2155
2178
  }
2156
2179
  let r = t.nodeAt(t.selection);
2157
- r && wn(e, t, r, n);
2180
+ r && En(e, t, r, n);
2158
2181
  }
2159
- var mn = [
2182
+ var gn = [
2160
2183
  "connections",
2161
2184
  "input",
2162
2185
  "multiplayer"
2163
2186
  ];
2164
- function hn(e, t, n) {
2165
- e.appendChild(qn("scene")), e.appendChild(Xn("name", String(t.working.name ?? ""), (e) => {
2187
+ function _n(e, t, n) {
2188
+ e.appendChild(Yn("scene")), e.appendChild(Qn("name", String(t.working.name ?? ""), (e) => {
2166
2189
  t.mutate(() => {
2167
2190
  t.working.name = e;
2168
2191
  });
@@ -2176,7 +2199,7 @@ function hn(e, t, n) {
2176
2199
  t.mutate(() => {
2177
2200
  t.working.dimension = r.value;
2178
2201
  });
2179
- }), e.appendChild(V("dimension", r)), e.appendChild(qn("physics", "physics"));
2202
+ }), e.appendChild(V("dimension", r)), e.appendChild(Yn("physics", "physics"));
2180
2203
  let i = (t.working.physics ?? {}).gravity ?? (t.working.dimension === "3d" ? [
2181
2204
  0,
2182
2205
  -9.81,
@@ -2186,7 +2209,7 @@ function hn(e, t, n) {
2186
2209
  -9.81,
2187
2210
  0
2188
2211
  ] : [0, 980];
2189
- e.appendChild(Qn("gravity", i, (e) => {
2212
+ e.appendChild(er("gravity", i, (e) => {
2190
2213
  t.mutate(() => {
2191
2214
  if (JSON.stringify(e) === JSON.stringify(a)) {
2192
2215
  let e = { ...t.working.physics };
@@ -2196,14 +2219,14 @@ function hn(e, t, n) {
2196
2219
  gravity: e
2197
2220
  };
2198
2221
  });
2199
- })), e.appendChild(qn("environment")), gn(e, t), e.appendChild(qn("constants")), Vn(e, t, n), e.appendChild(qn("advanced"));
2200
- for (let n of mn) e.appendChild(er(n, t.working[n], (e) => {
2222
+ })), e.appendChild(Yn("environment")), vn(e, t), e.appendChild(Yn("constants")), Un(e, t, n), e.appendChild(Yn("advanced"));
2223
+ for (let n of gn) e.appendChild(nr(n, t.working[n], (e) => {
2201
2224
  t.mutate(() => {
2202
2225
  e === void 0 ? delete t.working[n] : t.working[n] = e;
2203
2226
  });
2204
2227
  }));
2205
2228
  }
2206
- function gn(e, t) {
2229
+ function vn(e, t) {
2207
2230
  let n = t.working.environment ?? {}, r = (e) => {
2208
2231
  t.mutate(() => {
2209
2232
  let n = {
@@ -2214,15 +2237,15 @@ function gn(e, t) {
2214
2237
  Object.keys(n).length === 0 ? delete t.working.environment : t.working.environment = n;
2215
2238
  });
2216
2239
  };
2217
- e.appendChild(_n("background", n.background ?? "", (e) => {
2240
+ e.appendChild(yn("background", n.background ?? "", (e) => {
2218
2241
  r({ background: e === "" ? void 0 : e });
2219
- })), e.appendChild(_n("ambient color", n.ambient?.color ?? "", (e) => {
2242
+ })), e.appendChild(yn("ambient color", n.ambient?.color ?? "", (e) => {
2220
2243
  let t = {
2221
2244
  ...n.ambient,
2222
2245
  color: e === "" ? void 0 : e
2223
2246
  };
2224
2247
  t.color === void 0 && delete t.color, r({ ambient: Object.keys(t).length ? t : void 0 });
2225
- })), e.appendChild(Zn("ambient power", n.ambient?.intensity ?? 0, (e) => {
2248
+ })), e.appendChild($n("ambient power", n.ambient?.intensity ?? 0, (e) => {
2226
2249
  r({ ambient: {
2227
2250
  ...n.ambient,
2228
2251
  intensity: e
@@ -2252,7 +2275,7 @@ function gn(e, t) {
2252
2275
  a({ pixelRatio: s.value === "" ? void 0 : s.value === "device" ? "device" : Number(s.value) });
2253
2276
  }), e.appendChild(V("pixel ratio", s));
2254
2277
  }
2255
- function _n(e, t, n) {
2278
+ function yn(e, t, n) {
2256
2279
  let r = document.createElement("div");
2257
2280
  r.className = "color-row";
2258
2281
  let i = document.createElement("input");
@@ -2262,7 +2285,7 @@ function _n(e, t, n) {
2262
2285
  a.value = i.value;
2263
2286
  }), i.addEventListener("change", () => n(i.value)), a.addEventListener("change", () => n(a.value.trim())), r.append(i, a), V(e, r);
2264
2287
  }
2265
- function vn(e, t) {
2288
+ function bn(e, t) {
2266
2289
  let n = document.createElement("div");
2267
2290
  n.className = "subcard";
2268
2291
  let r = document.createElement("div");
@@ -2276,13 +2299,13 @@ function vn(e, t) {
2276
2299
  t === void 0 || t === "" ? delete n[e] : n[e] = t, s(Object.keys(n).length === 0 ? !0 : n);
2277
2300
  }, l = document.createElement("input");
2278
2301
  if (l.type = "checkbox", l.checked = a, l.addEventListener("change", () => s(l.checked)), n.appendChild(V("enabled", l)), a) {
2279
- n.appendChild(_n("murk color", String(o.color ?? ""), (e) => c("color", e))), n.appendChild(Zn("visibility (m)", Number(o.visibility ?? 22), (e) => c("visibility", e === 22 ? void 0 : e), () => c("visibility", void 0)));
2302
+ n.appendChild(yn("murk color", String(o.color ?? ""), (e) => c("color", e))), n.appendChild($n("visibility (m)", Number(o.visibility ?? 22), (e) => c("visibility", e === 22 ? void 0 : e), () => c("visibility", void 0)));
2280
2303
  let e = document.createElement("input");
2281
2304
  e.type = "checkbox", e.checked = (o.caustics ?? !0) !== !1, e.addEventListener("change", () => c("caustics", e.checked ? void 0 : !1)), n.appendChild(V("caustics", e));
2282
2305
  }
2283
2306
  return n;
2284
2307
  }
2285
- function yn(e, t, n) {
2308
+ function xn(e, t, n) {
2286
2309
  let r = document.createElement("div");
2287
2310
  r.className = "subcard";
2288
2311
  let i = document.createElement("div");
@@ -2299,7 +2322,7 @@ function yn(e, t, n) {
2299
2322
  value: a
2300
2323
  } : void 0);
2301
2324
  };
2302
- r.appendChild(_n("color", String(a.color ?? ""), (e) => o("color", e))), r.appendChild(Cn("roughness", Number(a.roughness ?? 1), (e) => o("roughness", e))), r.appendChild(Cn("metalness", Number(a.metalness ?? 0), (e) => o("metalness", e))), r.appendChild(_n("emissive", String(a.emissive ?? ""), (e) => o("emissive", e))), r.appendChild(Cn("emissive power", Number(a.emissiveIntensity ?? 1), (e) => o("emissiveIntensity", e === 1 ? void 0 : e), 2)), r.appendChild(Cn("opacity", Number(a.opacity ?? 1), (e) => o("opacity", e === 1 ? void 0 : e))), r.appendChild(Cn("clearcoat", Number(a.clearcoat ?? 0), (e) => o("clearcoat", e === 0 ? void 0 : e))), r.appendChild(Cn("clearcoat rough", Number(a.clearcoatRoughness ?? 0), (e) => o("clearcoatRoughness", e === 0 ? void 0 : e))), r.appendChild(Cn("reflection", Number(a.envMapIntensity ?? 1), (e) => o("envMapIntensity", e === 1 ? void 0 : e), 3));
2325
+ r.appendChild(yn("color", String(a.color ?? ""), (e) => o("color", e))), r.appendChild(Tn("roughness", Number(a.roughness ?? 1), (e) => o("roughness", e))), r.appendChild(Tn("metalness", Number(a.metalness ?? 0), (e) => o("metalness", e))), r.appendChild(yn("emissive", String(a.emissive ?? ""), (e) => o("emissive", e))), r.appendChild(Tn("emissive power", Number(a.emissiveIntensity ?? 1), (e) => o("emissiveIntensity", e === 1 ? void 0 : e), 2)), r.appendChild(Tn("opacity", Number(a.opacity ?? 1), (e) => o("opacity", e === 1 ? void 0 : e))), r.appendChild(Tn("clearcoat", Number(a.clearcoat ?? 0), (e) => o("clearcoat", e === 0 ? void 0 : e))), r.appendChild(Tn("clearcoat rough", Number(a.clearcoatRoughness ?? 0), (e) => o("clearcoatRoughness", e === 0 ? void 0 : e))), r.appendChild(Tn("reflection", Number(a.envMapIntensity ?? 1), (e) => o("envMapIntensity", e === 1 ? void 0 : e), 3));
2303
2326
  let s = document.createElement("input");
2304
2327
  s.type = "checkbox", s.checked = a.wireframe === !0, s.addEventListener("change", () => o("wireframe", s.checked || void 0)), r.appendChild(V("wireframe", s));
2305
2328
  let c = document.createElement("input");
@@ -2307,7 +2330,7 @@ function yn(e, t, n) {
2307
2330
  let l = document.createElement("input");
2308
2331
  l.type = "checkbox", l.checked = a.depthTest === !1, l.addEventListener("change", () => {
2309
2332
  o("depthTest", l.checked ? !1 : void 0), o("depthWrite", l.checked ? !1 : void 0);
2310
- }), r.appendChild(V("draw on top (decal)", l)), r.appendChild(B("map (texture)", String(a.map ?? ""), Nn((e) => fn(e) && !e.name.includes("normal") && !e.name.includes("roughness")), (e) => o("map", e.trim()), {
2333
+ }), r.appendChild(V("draw on top (decal)", l)), r.appendChild(B("map (texture)", String(a.map ?? ""), Fn((e) => mn(e) && !e.name.includes("normal") && !e.name.includes("roughness")), (e) => o("map", e.trim()), {
2311
2334
  placeholder: "built-in or custom URL",
2312
2335
  library: {
2313
2336
  kind: "image",
@@ -2315,7 +2338,7 @@ function yn(e, t, n) {
2315
2338
  shelf: ["3d", "textures"]
2316
2339
  },
2317
2340
  ctx: n
2318
- })), r.appendChild(B("normal map", String(a.normalMap ?? ""), Nn((e) => fn(e) && e.name.includes("normal")), (e) => o("normalMap", e.trim()), {
2341
+ })), r.appendChild(B("normal map", String(a.normalMap ?? ""), Fn((e) => mn(e) && e.name.includes("normal")), (e) => o("normalMap", e.trim()), {
2319
2342
  placeholder: "built-in or custom URL",
2320
2343
  library: {
2321
2344
  kind: "image",
@@ -2324,13 +2347,13 @@ function yn(e, t, n) {
2324
2347
  },
2325
2348
  ctx: n
2326
2349
  }));
2327
- let u = !!(a.map || a.normalMap), d = Array.isArray(a.repeat) ? a.repeat : [1, 1], f = Qn("repeat [u,v]", [d[0] ?? 1, d[1] ?? 1], (e) => {
2350
+ let u = !!(a.map || a.normalMap), d = Array.isArray(a.repeat) ? a.repeat : [1, 1], f = er("repeat [u,v]", [d[0] ?? 1, d[1] ?? 1], (e) => {
2328
2351
  let [t, n] = e;
2329
2352
  !Number.isFinite(t) || !Number.isFinite(n) || t === 1 && n === 1 || !t && !n ? o("repeat", void 0) : o("repeat", [t, n]);
2330
2353
  });
2331
2354
  return f.title = u ? "Texture tiling across the mesh UVs." : "Only takes effect with a map/normal map set (engine validates).", r.appendChild(f), r;
2332
2355
  }
2333
- var bn = new Set([
2356
+ var Sn = new Set([
2334
2357
  "animationLoop",
2335
2358
  "animationSpeed",
2336
2359
  "animationOffset",
@@ -2338,7 +2361,7 @@ var bn = new Set([
2338
2361
  "animationUpperLoop",
2339
2362
  "upperBodyRoot"
2340
2363
  ]);
2341
- function xn(e, t, n, r) {
2364
+ function Cn(e, t, n, r) {
2342
2365
  let i = document.createElement("div");
2343
2366
  i.className = "subcard anim-card";
2344
2367
  let a = document.createElement("div");
@@ -2362,15 +2385,15 @@ function xn(e, t, n, r) {
2362
2385
  ctx: n
2363
2386
  })), !s) {
2364
2387
  let a = document.createElement("div");
2365
- return a.className = "muted-note", a.textContent = "Pick a clip and it plays as soon as the scene loads — no script needed.", i.appendChild(a), i.appendChild(Sn(e, t, n, r)), i;
2388
+ return a.className = "muted-note", a.textContent = "Pick a clip and it plays as soon as the scene loads — no script needed.", i.appendChild(a), i.appendChild(wn(e, t, n, r)), i;
2366
2389
  }
2367
- i.appendChild(Un(e, t, "animationLoop", r.animationLoop?.default ?? !0, void 0, "loop"));
2368
- let c = Cn("speed", Number(t.props?.animationSpeed ?? 1), (n) => z(e, t, "animationSpeed", n, 1), 3, -3);
2390
+ i.appendChild(Gn(e, t, "animationLoop", r.animationLoop?.default ?? !0, void 0, "loop"));
2391
+ let c = Tn("speed", Number(t.props?.animationSpeed ?? 1), (n) => z(e, t, "animationSpeed", n, 1), 3, -3);
2369
2392
  c.title = "1 = as authored · 0 freezes the pose · negative plays backwards (a closing door is an opening one reversed).", i.appendChild(c);
2370
- let l = Un(e, t, "animationOffset", r.animationOffset?.default ?? 0, void 0, "offset (s)");
2371
- return l.title = "Seconds into the clip to start at. Give copies different offsets so a row of torches stops flickering in lockstep.", i.appendChild(l), i.appendChild(Sn(e, t, n, r)), i;
2393
+ let l = Gn(e, t, "animationOffset", r.animationOffset?.default ?? 0, void 0, "offset (s)");
2394
+ return l.title = "Seconds into the clip to start at. Give copies different offsets so a row of torches stops flickering in lockstep.", i.appendChild(l), i.appendChild(wn(e, t, n, r)), i;
2372
2395
  }
2373
- function Sn(e, t, n, r) {
2396
+ function wn(e, t, n, r) {
2374
2397
  let i = document.createElement("details");
2375
2398
  i.className = "anim-upper", t.props?.animationUpper && (i.open = !0);
2376
2399
  let a = document.createElement("summary");
@@ -2380,9 +2403,9 @@ function Sn(e, t, n, r) {
2380
2403
  })), (n) => z(e, t, "animationUpper", n.trim(), ""), {
2381
2404
  placeholder: "empty = off",
2382
2405
  ctx: n
2383
- })), i.appendChild(Un(e, t, "animationUpperLoop", r.animationUpperLoop?.default ?? !1, void 0, "loop")), i.appendChild(Un(e, t, "upperBodyRoot", r.upperBodyRoot?.default ?? "Spine", void 0, "root bone")), i;
2406
+ })), i.appendChild(Gn(e, t, "animationUpperLoop", r.animationUpperLoop?.default ?? !1, void 0, "loop")), i.appendChild(Gn(e, t, "upperBodyRoot", r.upperBodyRoot?.default ?? "Spine", void 0, "root bone")), i;
2384
2407
  }
2385
- function Cn(e, t, n, r = 1, i = 0) {
2408
+ function Tn(e, t, n, r = 1, i = 0) {
2386
2409
  let a = document.createElement("div");
2387
2410
  a.className = "slider-row";
2388
2411
  let o = document.createElement("input");
@@ -2394,18 +2417,18 @@ function Cn(e, t, n, r = 1, i = 0) {
2394
2417
  o.value = s.value, n(Number(s.value));
2395
2418
  }), a.append(o, s), V(e, a);
2396
2419
  }
2397
- function wn(e, t, n, i) {
2398
- if (e.appendChild(qn(n.type ?? "instance")), e.appendChild(Tn(n)), e.appendChild(Xn("name", n.name ?? "", (e) => {
2420
+ function En(e, t, n, i) {
2421
+ if (e.appendChild(Yn(n.type ?? "instance")), e.appendChild(Dn(n)), e.appendChild(Qn("name", n.name ?? "", (e) => {
2399
2422
  e.trim() === "" || t.selection === null || t.renameNode(t.selection, e.trim());
2400
- })), n.type === "TileMap2D" && i?.paint && e.appendChild($n(n, i.paint)), n.type) {
2423
+ })), n.type === "TileMap2D" && i?.paint && e.appendChild(tr(n, i.paint)), n.type) {
2401
2424
  let a;
2402
2425
  try {
2403
2426
  a = r(n.type);
2404
2427
  } catch {
2405
2428
  a = {};
2406
2429
  }
2407
- for (let [r, o] of Object.entries(a)) if (r === "collider") e.appendChild(kn(t, n, o.default));
2408
- else if (r === "material") e.appendChild(yn(t, n, i));
2430
+ for (let [r, o] of Object.entries(a)) if (r === "collider") e.appendChild(jn(t, n, o.default));
2431
+ else if (r === "material") e.appendChild(xn(t, n, i));
2409
2432
  else if (n.type === "ModelInstance3D" && r === "model" && i) e.appendChild(B("model", String(n.props?.model ?? ""), i.modelRefs().map((e) => ({
2410
2433
  label: e,
2411
2434
  value: e,
@@ -2420,9 +2443,9 @@ function wn(e, t, n, i) {
2420
2443
  },
2421
2444
  ctx: i
2422
2445
  }));
2423
- else if (n.type === "BoneAttachment3D" && r === "bone" && i?.bonesForSelection) e.appendChild(jn("bone", String(n.props?.bone ?? ""), i.bonesForSelection(String(n.props?.target ?? "")), (e) => z(t, n, "bone", e, "")));
2424
- else if (n.type === "ModelInstance3D" && r === "animation" && i) e.appendChild(xn(t, n, i, a));
2425
- else if (!(n.type === "ModelInstance3D" && bn.has(r))) if ((n.type === "Sprite3D" || n.type === "AnimatedSprite3D") && (r === "texture" || r === "sheet")) e.appendChild(B(r === "sheet" ? "sheet (image URL)" : "texture (image URL)", String(n.props?.[r] ?? ""), Nn((e) => e.kind === "character" || e.kind === "item"), (e) => z(t, n, r, e.trim(), ""), {
2446
+ else if (n.type === "BoneAttachment3D" && r === "bone" && i?.bonesForSelection) e.appendChild(Nn("bone", String(n.props?.bone ?? ""), i.bonesForSelection(String(n.props?.target ?? "")), (e) => z(t, n, "bone", e, "")));
2447
+ else if (n.type === "ModelInstance3D" && r === "animation" && i) e.appendChild(Cn(t, n, i, a));
2448
+ else if (!(n.type === "ModelInstance3D" && Sn.has(r))) if ((n.type === "Sprite3D" || n.type === "AnimatedSprite3D") && (r === "texture" || r === "sheet")) e.appendChild(B(r === "sheet" ? "sheet (image URL)" : "texture (image URL)", String(n.props?.[r] ?? ""), Fn((e) => e.kind === "character" || e.kind === "item"), (e) => z(t, n, r, e.trim(), ""), {
2426
2449
  placeholder: "image URL — empty hides the sprite",
2427
2450
  library: {
2428
2451
  kind: "image",
@@ -2446,7 +2469,7 @@ function wn(e, t, n, i) {
2446
2469
  },
2447
2470
  ctx: i
2448
2471
  }));
2449
- else if (n.type === "Tree3D" && r === "leafTexture") e.appendChild(B("leaf texture", String(n.props?.leafTexture ?? ""), Nn((e) => e.name.startsWith("leaves_")), (e) => z(t, n, "leafTexture", e.trim(), ""), {
2472
+ else if (n.type === "Tree3D" && r === "leafTexture") e.appendChild(B("leaf texture", String(n.props?.leafTexture ?? ""), Fn((e) => e.name.startsWith("leaves_")), (e) => z(t, n, "leafTexture", e.trim(), ""), {
2450
2473
  placeholder: "default (per-type) or URL",
2451
2474
  library: {
2452
2475
  kind: "image",
@@ -2455,11 +2478,11 @@ function wn(e, t, n, i) {
2455
2478
  },
2456
2479
  ctx: i
2457
2480
  }));
2458
- else if (n.type === "Terrain3D" && r === "textureBase") e.appendChild(B("texture base", String(n.props?.textureBase ?? o.default ?? ""), Fn, (e) => z(t, n, "textureBase", e.trim(), o.default), { placeholder: "splat texture base URL" }));
2481
+ else if (n.type === "Terrain3D" && r === "textureBase") e.appendChild(B("texture base", String(n.props?.textureBase ?? o.default ?? ""), Ln, (e) => z(t, n, "textureBase", e.trim(), o.default), { placeholder: "splat texture base URL" }));
2459
2482
  else if (n.type === "AnimatedSprite2D" && r === "sheet" || n.type === "Sprite2D" && r === "texture") {
2460
2483
  let a = r === "sheet";
2461
- e.appendChild(In(t, n, r, i, a));
2462
- } else n.type === "AudioPlayer" && r === "src" ? e.appendChild(B("src (audio file)", String(n.props?.src ?? ""), Pn(), (e) => z(t, n, "src", e.trim(), ""), {
2484
+ e.appendChild(Rn(t, n, r, i, a));
2485
+ } else n.type === "AudioPlayer" && r === "src" ? e.appendChild(B("src (audio file)", String(n.props?.src ?? ""), In(), (e) => z(t, n, "src", e.trim(), ""), {
2463
2486
  placeholder: "built-in or custom URL — or use preset",
2464
2487
  note: "For zero-asset SFX, set the `preset` prop instead of src.",
2465
2488
  library: {
@@ -2467,14 +2490,14 @@ function wn(e, t, n, i) {
2467
2490
  target: "audio src"
2468
2491
  },
2469
2492
  ctx: i
2470
- })) : n.type === "Flowers3D" && r === "varieties" ? e.appendChild(Ln(t, n)) : n.type === "Water3D" && r === "underwater" ? e.appendChild(vn(t, n)) : e.appendChild(Un(t, n, r, o.default, o.options));
2493
+ })) : n.type === "Flowers3D" && r === "varieties" ? e.appendChild(zn(t, n)) : n.type === "Water3D" && r === "underwater" ? e.appendChild(bn(t, n)) : e.appendChild(Gn(t, n, r, o.default, o.options));
2471
2494
  }
2472
- if (e.appendChild(qn("structure")), e.appendChild(En(t, n)), e.appendChild(Dn(t, n)), e.appendChild(On(t, n)), t.selection) {
2473
- let n = nn(t, t.selection);
2474
- n && (e.appendChild(qn("connections", "connections")), e.appendChild(n));
2495
+ if (e.appendChild(Yn("structure")), e.appendChild(On(t, n)), e.appendChild(kn(t, n)), e.appendChild(An(t, n)), t.selection) {
2496
+ let n = an(t, t.selection);
2497
+ n && (e.appendChild(Yn("connections", "connections")), e.appendChild(n));
2475
2498
  }
2476
2499
  }
2477
- function Tn(e) {
2500
+ function Dn(e) {
2478
2501
  let t = document.createElement("div");
2479
2502
  t.className = "field uid-line";
2480
2503
  let n = document.createElement("span");
@@ -2490,14 +2513,14 @@ function Tn(e) {
2490
2513
  }, 800);
2491
2514
  }), r.append(i, a), t.append(n, r), t;
2492
2515
  }
2493
- function En(e, t) {
2516
+ function On(e, t) {
2494
2517
  let n = document.createElement("label");
2495
2518
  n.className = "field wide";
2496
2519
  let r = document.createElement("span");
2497
- r.append("groups ", Ht("groups"));
2520
+ r.append("groups ", Wt("groups"));
2498
2521
  let i = document.createElement("div");
2499
2522
  i.className = "chips";
2500
- for (let n of t.groups ?? []) i.appendChild(Jn(n, () => {
2523
+ for (let n of t.groups ?? []) i.appendChild(Xn(n, () => {
2501
2524
  e.mutate(() => {
2502
2525
  t.groups = (t.groups ?? []).filter((e) => e !== n), t.groups.length === 0 && delete t.groups;
2503
2526
  });
@@ -2511,11 +2534,11 @@ function En(e, t) {
2511
2534
  });
2512
2535
  }), i.appendChild(a), i.addEventListener("click", () => a.focus()), n.append(r, i), n;
2513
2536
  }
2514
- function Dn(e, t) {
2537
+ function kn(e, t) {
2515
2538
  let n = document.createElement("div");
2516
2539
  n.className = "subcard";
2517
2540
  let r = document.createElement("div");
2518
- r.className = "subcard-head", r.append("script ", Ht("script"));
2541
+ r.className = "subcard-head", r.append("script ", Wt("script"));
2519
2542
  let i = document.createElement("span");
2520
2543
  i.className = "spacer", r.appendChild(i);
2521
2544
  let a = t.script;
@@ -2537,11 +2560,11 @@ function Dn(e, t) {
2537
2560
  });
2538
2561
  }), n.append(r, i), n;
2539
2562
  }
2540
- n.appendChild(Xn("name", a.name ?? "", (n) => {
2563
+ n.appendChild(Qn("name", a.name ?? "", (n) => {
2541
2564
  e.mutate(() => {
2542
2565
  t.script.name = n.trim();
2543
2566
  });
2544
- })), n.appendChild(er("props", a.props, (n) => {
2567
+ })), n.appendChild(nr("props", a.props, (n) => {
2545
2568
  e.mutate(() => {
2546
2569
  n === void 0 ? delete t.script.props : t.script.props = n;
2547
2570
  });
@@ -2549,11 +2572,11 @@ function Dn(e, t) {
2549
2572
  let o = document.createElement("div");
2550
2573
  return o.className = "muted-note", o.textContent = "? has copy-paste boilerplate for the game side.", n.appendChild(o), n;
2551
2574
  }
2552
- function On(e, t) {
2575
+ function An(e, t) {
2553
2576
  let n = document.createElement("div");
2554
2577
  n.className = "subcard";
2555
2578
  let r = document.createElement("div");
2556
- r.className = "subcard-head", r.append("network ", Ht("network")), n.appendChild(r);
2579
+ r.className = "subcard-head", r.append("network ", Wt("network")), n.appendChild(r);
2557
2580
  let i = t.network, a = document.createElement("select");
2558
2581
  for (let [e, t] of [["", "not replicated"], ["owner", "owner — this player broadcasts it"]]) {
2559
2582
  let n = document.createElement("option");
@@ -2569,7 +2592,7 @@ function On(e, t) {
2569
2592
  }), n.appendChild(V("mode", a)), i?.mode === "owner") {
2570
2593
  let r = document.createElement("div");
2571
2594
  r.className = "chips";
2572
- for (let n of i.sync ?? []) r.appendChild(Jn(n, () => {
2595
+ for (let n of i.sync ?? []) r.appendChild(Xn(n, () => {
2573
2596
  e.mutate(() => {
2574
2597
  t.network.sync = (i.sync ?? []).filter((e) => e !== n);
2575
2598
  });
@@ -2585,7 +2608,7 @@ function On(e, t) {
2585
2608
  let o = document.createElement("label");
2586
2609
  o.className = "field wide";
2587
2610
  let s = document.createElement("span");
2588
- s.textContent = "sync keys", o.append(s, r), n.appendChild(o), n.appendChild(Zn("throttle ms", i.throttleMs ?? 50, (n) => {
2611
+ s.textContent = "sync keys", o.append(s, r), n.appendChild(o), n.appendChild($n("throttle ms", i.throttleMs ?? 50, (n) => {
2589
2612
  e.mutate(() => {
2590
2613
  t.network.throttleMs = n;
2591
2614
  });
@@ -2593,11 +2616,11 @@ function On(e, t) {
2593
2616
  }
2594
2617
  return n;
2595
2618
  }
2596
- function kn(e, t, n) {
2619
+ function jn(e, t, n) {
2597
2620
  let r = document.createElement("div");
2598
2621
  r.className = "subcard";
2599
2622
  let i = document.createElement("div");
2600
- i.className = "subcard-head", i.append("collider ", Ht("collider")), r.appendChild(i);
2623
+ i.className = "subcard-head", i.append("collider ", Wt("collider")), r.appendChild(i);
2601
2624
  let a = t.props?.collider ?? {}, o = (n) => {
2602
2625
  e.mutate(() => {
2603
2626
  t.props ||= {};
@@ -2645,23 +2668,23 @@ function kn(e, t, n) {
2645
2668
  radius: a.radius ?? 12,
2646
2669
  height: a.height ?? 16
2647
2670
  });
2648
- }), r.appendChild(V("shape", l)), a.shape === "rect" || a.shape === "box" ? r.appendChild(Qn("size", a.size ?? (s ? [
2671
+ }), r.appendChild(V("shape", l)), a.shape === "rect" || a.shape === "box" ? r.appendChild(er("size", a.size ?? (s ? [
2649
2672
  1,
2650
2673
  1,
2651
2674
  1
2652
2675
  ] : [32, 32]), (e) => o({
2653
2676
  ...a,
2654
2677
  size: e
2655
- }))) : a.shape === "circle" || a.shape === "sphere" ? r.appendChild(Zn("radius", a.radius ?? (s ? .5 : 16), (e) => o({
2678
+ }))) : a.shape === "circle" || a.shape === "sphere" ? r.appendChild($n("radius", a.radius ?? (s ? .5 : 16), (e) => o({
2656
2679
  ...a,
2657
2680
  radius: e
2658
- }))) : a.shape === "capsule" && (r.appendChild(Zn("radius", a.radius ?? 12, (e) => o({
2681
+ }))) : a.shape === "capsule" && (r.appendChild($n("radius", a.radius ?? 12, (e) => o({
2659
2682
  ...a,
2660
2683
  radius: e
2661
- }))), r.appendChild(Zn("height", a.height ?? 16, (e) => o({
2684
+ }))), r.appendChild($n("height", a.height ?? 16, (e) => o({
2662
2685
  ...a,
2663
2686
  height: e
2664
- })))), a.shape && r.appendChild(Qn("offset", a.offset ?? (s ? [
2687
+ })))), a.shape && r.appendChild(er("offset", a.offset ?? (s ? [
2665
2688
  0,
2666
2689
  0,
2667
2690
  0
@@ -2675,11 +2698,11 @@ function z(e, t, n, r, i) {
2675
2698
  t.props ||= {}, JSON.stringify(r) === JSON.stringify(i) ? (delete t.props[n], Object.keys(t.props).length === 0 && delete t.props) : t.props[n] = r;
2676
2699
  });
2677
2700
  }
2678
- var An = 0;
2679
- function jn(e, t, n, r) {
2701
+ var Mn = 0;
2702
+ function Nn(e, t, n, r) {
2680
2703
  let i = document.createElement("input");
2681
2704
  i.type = "text", i.value = t;
2682
- let a = `suggest-${An++}`;
2705
+ let a = `suggest-${Mn++}`;
2683
2706
  i.setAttribute("list", a);
2684
2707
  let o = document.createElement("datalist");
2685
2708
  o.id = a;
@@ -2691,7 +2714,7 @@ function jn(e, t, n, r) {
2691
2714
  let s = V(e, i);
2692
2715
  return s.appendChild(o), s;
2693
2716
  }
2694
- var Mn = 0;
2717
+ var Pn = 0;
2695
2718
  function B(e, t, n, r, i = {}) {
2696
2719
  let a = document.createElement("label");
2697
2720
  a.className = "field wide asset-field";
@@ -2755,33 +2778,33 @@ function B(e, t, n, r, i = {}) {
2755
2778
  let e = document.createElement("div");
2756
2779
  e.className = "muted-note asset-note", e.textContent = i.note, a.appendChild(e);
2757
2780
  }
2758
- return s.id = `asset-input-${Mn++}`, a.htmlFor = s.id, a;
2781
+ return s.id = `asset-input-${Pn++}`, a.htmlFor = s.id, a;
2759
2782
  }
2760
- function Nn(e) {
2761
- return dn.filter(e).map((e) => ({
2783
+ function Fn(e) {
2784
+ return pn.filter(e).map((e) => ({
2762
2785
  label: e.name,
2763
2786
  value: e.url,
2764
2787
  hint: `${e.kind} · ${e.description.slice(0, 70)}`
2765
2788
  }));
2766
2789
  }
2767
- function Pn() {
2768
- return dn.filter((e) => e.kind === "audio").map((e) => ({
2790
+ function In() {
2791
+ return pn.filter((e) => e.kind === "audio").map((e) => ({
2769
2792
  label: e.name,
2770
2793
  value: e.url,
2771
2794
  hint: `audio · ${e.description.slice(0, 70)}`
2772
2795
  }));
2773
2796
  }
2774
- var Fn = [{
2797
+ var Ln = [{
2775
2798
  label: "agent8 default terrain",
2776
2799
  value: "https://agent8-games.verse8.io/assets/3D/default/textures/terrain",
2777
2800
  hint: "sand/grass/stone/snow splat set (Terrain3D default)"
2778
2801
  }];
2779
- function In(e, t, n, r, i) {
2802
+ function Rn(e, t, n, r, i) {
2780
2803
  let a = String(t.props?.[n] ?? ""), o = i ? ["spritesheet"] : ["texture", "spritesheet"], s = (r?.assetRefs?.(o) ?? []).map((e) => ({
2781
2804
  label: e,
2782
2805
  value: e,
2783
2806
  hint: "scene asset"
2784
- })), c = dn.filter((e) => i ? !!e.animation : e.kind === "character" || e.kind === "item" || e.kind === "tile");
2807
+ })), c = pn.filter((e) => i ? !!e.animation : e.kind === "character" || e.kind === "item" || e.kind === "tile");
2785
2808
  for (let e of c) s.push({
2786
2809
  label: `built-in: ${e.name}`,
2787
2810
  value: `$${e.name}`,
@@ -2818,7 +2841,7 @@ function In(e, t, n, r, i) {
2818
2841
  ctx: r
2819
2842
  });
2820
2843
  }
2821
- function Ln(e, t) {
2844
+ function zn(e, t) {
2822
2845
  let n = document.createElement("label");
2823
2846
  n.className = "field wide";
2824
2847
  let r = document.createElement("span");
@@ -2844,7 +2867,7 @@ function Ln(e, t) {
2844
2867
  let s = document.createElement("div");
2845
2868
  return s.className = "muted-note", s.textContent = "All (or none) = the default mix of all three.", n.appendChild(s), n;
2846
2869
  }
2847
- var Rn = [
2870
+ var Bn = [
2848
2871
  ["number", () => 0],
2849
2872
  ["text", () => ""],
2850
2873
  ["boolean", () => !1],
@@ -2856,7 +2879,7 @@ var Rn = [
2856
2879
  0
2857
2880
  ]]
2858
2881
  ];
2859
- function zn(e, t) {
2882
+ function Vn(e, t) {
2860
2883
  let n = 0, r = (e) => {
2861
2884
  if (o(e)) {
2862
2885
  e["@const"] === t && (n += 1);
@@ -2868,7 +2891,7 @@ function zn(e, t) {
2868
2891
  for (let [t, n] of Object.entries(e)) t !== "constants" && r(n);
2869
2892
  return n;
2870
2893
  }
2871
- function Bn(e, t, n) {
2894
+ function Hn(e, t, n) {
2872
2895
  let r = (e) => {
2873
2896
  if (o(e)) return e["@const"] === t ? JSON.parse(JSON.stringify(n ?? null)) : e;
2874
2897
  if (Array.isArray(e)) return e.map(r);
@@ -2881,7 +2904,7 @@ function Bn(e, t, n) {
2881
2904
  };
2882
2905
  for (let t of Object.keys(e)) t !== "constants" && (e[t] = r(e[t]));
2883
2906
  }
2884
- function Vn(e, t, n) {
2907
+ function Un(e, t, n) {
2885
2908
  let r = t.working.constants ?? {}, i = Object.keys(r), a = (e, n) => {
2886
2909
  t.mutate(() => {
2887
2910
  let r = { ...t.working.constants ?? {} };
@@ -2889,12 +2912,12 @@ function Vn(e, t, n) {
2889
2912
  });
2890
2913
  }, o = (e, n) => {
2891
2914
  t.mutate(() => {
2892
- n && Bn(t.working, e, r[e]);
2915
+ n && Hn(t.working, e, r[e]);
2893
2916
  let i = { ...t.working.constants ?? {} };
2894
2917
  delete i[e], Object.keys(i).length === 0 ? delete t.working.constants : t.working.constants = i;
2895
2918
  });
2896
2919
  }, s = (e) => {
2897
- let r = zn(t.working, e);
2920
+ let r = Vn(t.working, e);
2898
2921
  if (r > 0 && n?.confirm) {
2899
2922
  n.confirm(`"${e}" is used by ${r} prop${r === 1 ? "" : "s"}. Unlink them (inline its current value) and delete?`, "unlink & delete", () => o(e, !0));
2900
2923
  return;
@@ -2907,7 +2930,7 @@ function Vn(e, t, n) {
2907
2930
  }
2908
2931
  for (let t of i) {
2909
2932
  let n = document.createElement("div");
2910
- n.className = "const-row", n.appendChild(Hn(t, r[t], (e) => a(t, e)));
2933
+ n.className = "const-row", n.appendChild(Wn(t, r[t], (e) => a(t, e)));
2911
2934
  let i = document.createElement("button");
2912
2935
  i.type = "button", i.className = "const-del", i.textContent = "✕", i.title = `delete constant "${t}"`, i.addEventListener("click", () => s(t)), n.appendChild(i), e.appendChild(n);
2913
2936
  }
@@ -2916,26 +2939,26 @@ function Vn(e, t, n) {
2916
2939
  let l = document.createElement("input");
2917
2940
  l.type = "text", l.placeholder = "new constant name";
2918
2941
  let u = document.createElement("select");
2919
- for (let [e] of Rn) {
2942
+ for (let [e] of Bn) {
2920
2943
  let t = document.createElement("option");
2921
2944
  t.value = e, t.textContent = e, u.appendChild(t);
2922
2945
  }
2923
2946
  let d = document.createElement("button");
2924
2947
  d.type = "button", d.textContent = "+ add", d.addEventListener("click", () => {
2925
2948
  let e = l.value.trim();
2926
- e && (t.working.constants ?? {})[e] === void 0 && (a(e, (Rn.find(([e]) => e === u.value)?.[1] ?? (() => 0))()), l.value = "");
2949
+ e && (t.working.constants ?? {})[e] === void 0 && (a(e, (Bn.find(([e]) => e === u.value)?.[1] ?? (() => 0))()), l.value = "");
2927
2950
  }), c.append(l, u, d), e.appendChild(c);
2928
2951
  }
2929
- function Hn(e, t, n) {
2952
+ function Wn(e, t, n) {
2930
2953
  let r = s(t);
2931
- if (r === "number") return Zn(e, t, (e) => n(e), () => n(0));
2954
+ if (r === "number") return $n(e, t, (e) => n(e), () => n(0));
2932
2955
  if (r === "boolean") {
2933
2956
  let r = document.createElement("input");
2934
2957
  return r.type = "checkbox", r.checked = t === !0, r.addEventListener("change", () => n(r.checked)), V(e, r);
2935
2958
  }
2936
- return r === "array" && Array.isArray(t) && t.every((e) => typeof e == "number") ? Qn(e, t, (e) => n(e)) : r === "string" ? Xn(e, String(t), (e) => n(e)) : er(e, t, (e) => n(e ?? null), JSON.stringify(t));
2959
+ return r === "array" && Array.isArray(t) && t.every((e) => typeof e == "number") ? er(e, t, (e) => n(e)) : r === "string" ? Qn(e, String(t), (e) => n(e)) : nr(e, t, (e) => n(e ?? null), JSON.stringify(t));
2937
2960
  }
2938
- function Un(e, t, n, r, i, a) {
2961
+ function Gn(e, t, n, r, i, a) {
2939
2962
  let c = t.props?.[n] ?? r, l = s(r), u = l === "number" || l === "boolean" || l === "string" || l === "array", d = (i) => {
2940
2963
  let a = o(i);
2941
2964
  e.mutate(() => {
@@ -2947,26 +2970,26 @@ function Un(e, t, n, r, i, a) {
2947
2970
  key: n,
2948
2971
  value: i
2949
2972
  } : void 0);
2950
- }, f = Wn(e, l, r);
2951
- if (o(c)) return Gn(n, c["@const"], f, d, r);
2952
- let p = (e) => f.length > 0 ? Kn(e, f, d) : e;
2953
- if (l === "number") return p(Zn(a ?? n, c, (e) => d(e), () => d(r)));
2973
+ }, f = Kn(e, l, r);
2974
+ if (o(c)) return qn(n, c["@const"], f, d, r);
2975
+ let p = (e) => f.length > 0 ? Jn(e, f, d) : e;
2976
+ if (l === "number") return p($n(a ?? n, c, (e) => d(e), () => d(r)));
2954
2977
  if (l === "boolean") {
2955
2978
  let e = document.createElement("input");
2956
2979
  return e.type = "checkbox", e.checked = c === !0, e.addEventListener("change", () => d(e.checked)), p(V(a ?? n, e));
2957
2980
  }
2958
- return l === "string" ? i && i.length > 0 ? p(Yn(a ?? n, String(c ?? ""), i, (e) => d(e))) : p(Xn(a ?? n, String(c ?? ""), (e) => d(e))) : l === "array" && Array.isArray(r) && r.length > 0 && r.every((e) => typeof e == "number") ? p(Qn(n, c ?? r, (e) => d(e))) : er(n, c === r ? void 0 : c, (e) => {
2981
+ return l === "string" ? i && i.length > 0 ? p(Zn(a ?? n, String(c ?? ""), i, (e) => d(e))) : p(Qn(a ?? n, String(c ?? ""), (e) => d(e))) : l === "array" && Array.isArray(r) && r.length > 0 && r.every((e) => typeof e == "number") ? p(er(n, c ?? r, (e) => d(e))) : nr(n, c === r ? void 0 : c, (e) => {
2959
2982
  d(e === void 0 ? r : e);
2960
2983
  }, JSON.stringify(r));
2961
2984
  }
2962
- function Wn(e, t, n) {
2985
+ function Kn(e, t, n) {
2963
2986
  let r = e.working.constants ?? {};
2964
2987
  return Object.keys(r).filter((e) => {
2965
2988
  let i = r[e];
2966
2989
  return s(i) === t ? t === "array" && Array.isArray(n) && Array.isArray(i) ? i.length === n.length : !0 : !1;
2967
2990
  });
2968
2991
  }
2969
- function Gn(e, t, n, r, i) {
2992
+ function qn(e, t, n, r, i) {
2970
2993
  let a = document.createElement("select"), o = n.includes(t) ? n : [t, ...n];
2971
2994
  for (let e of o) {
2972
2995
  let n = document.createElement("option");
@@ -2979,7 +3002,7 @@ function Gn(e, t, n, r, i) {
2979
3002
  let c = V(`🔗 ${e}`, a);
2980
3003
  return c.classList.add("const-bound"), c;
2981
3004
  }
2982
- function Kn(e, t, n) {
3005
+ function Jn(e, t, n) {
2983
3006
  let r = document.createElement("select");
2984
3007
  r.className = "const-picker", r.title = "Bind to a named constant";
2985
3008
  let i = document.createElement("option");
@@ -2992,13 +3015,13 @@ function Kn(e, t, n) {
2992
3015
  r.value && n({ "@const": r.value });
2993
3016
  }), e.appendChild(r), e;
2994
3017
  }
2995
- function qn(e, t) {
3018
+ function Yn(e, t) {
2996
3019
  let n = document.createElement("div");
2997
- n.className = "section-title", n.textContent = e, t && n.appendChild(Ht(t));
3020
+ n.className = "section-title", n.textContent = e, t && n.appendChild(Wt(t));
2998
3021
  let r = document.createElement("span");
2999
3022
  return r.className = "rule", n.appendChild(r), n;
3000
3023
  }
3001
- function Jn(e, t) {
3024
+ function Xn(e, t) {
3002
3025
  let n = document.createElement("span");
3003
3026
  n.className = "chip", n.textContent = e;
3004
3027
  let r = document.createElement("button");
@@ -3012,7 +3035,7 @@ function V(e, t) {
3012
3035
  let r = document.createElement("span");
3013
3036
  return r.textContent = e, n.append(r, t), n;
3014
3037
  }
3015
- function Yn(e, t, n, r) {
3038
+ function Zn(e, t, n, r) {
3016
3039
  let i = document.createElement("select");
3017
3040
  for (let e of n.includes(t) ? n : [t, ...n]) {
3018
3041
  let n = document.createElement("option");
@@ -3020,11 +3043,11 @@ function Yn(e, t, n, r) {
3020
3043
  }
3021
3044
  return i.addEventListener("change", () => r(i.value)), V(e, i);
3022
3045
  }
3023
- function Xn(e, t, n) {
3046
+ function Qn(e, t, n) {
3024
3047
  let r = document.createElement("input");
3025
3048
  return r.type = "text", r.value = t, r.addEventListener("change", () => n(r.value)), V(e, r);
3026
3049
  }
3027
- function Zn(e, t, n, r) {
3050
+ function $n(e, t, n, r) {
3028
3051
  let i = document.createElement("input");
3029
3052
  return i.type = "number", i.step = "any", i.value = String(t), i.addEventListener("change", () => {
3030
3053
  if (i.value.trim() === "") {
@@ -3035,7 +3058,7 @@ function Zn(e, t, n, r) {
3035
3058
  Number.isFinite(e) && n(e);
3036
3059
  }), V(e, i);
3037
3060
  }
3038
- function Qn(e, t, n) {
3061
+ function er(e, t, n) {
3039
3062
  let r = document.createElement("div");
3040
3063
  r.className = "vector-row";
3041
3064
  let i = [...t];
@@ -3047,7 +3070,7 @@ function Qn(e, t, n) {
3047
3070
  }), r.appendChild(a);
3048
3071
  }), V(e, r);
3049
3072
  }
3050
- function $n(e, t) {
3073
+ function tr(e, t) {
3051
3074
  let n = document.createElement("div");
3052
3075
  n.className = "field wide tile-paint";
3053
3076
  let r = document.createElement("button");
@@ -3055,7 +3078,7 @@ function $n(e, t) {
3055
3078
  let i = document.createElement("div");
3056
3079
  i.className = "paint-palette";
3057
3080
  let a = e.props?.cells ?? [], o = e.props?.legend ?? {};
3058
- for (let e of un(a, o)) {
3081
+ for (let e of fn(a, o)) {
3059
3082
  let n = document.createElement("button");
3060
3083
  n.type = "button", n.className = t.brush() === e ? "paint-chip on" : "paint-chip", n.textContent = e === "." ? "␡" : e, n.title = e === "." ? "eraser (empty cell)" : `tile '${e}'`, n.addEventListener("click", () => t.setBrush(e)), i.appendChild(n);
3061
3084
  }
@@ -3066,7 +3089,7 @@ function $n(e, t) {
3066
3089
  let c = document.createElement("div");
3067
3090
  return c.className = "paint-hint", c.textContent = "grid grows right/down; digits map to atlas tiles, others need legend", n.appendChild(c), n;
3068
3091
  }
3069
- function er(e, t, n, r = "") {
3092
+ function nr(e, t, n, r = "") {
3070
3093
  let i = document.createElement("textarea");
3071
3094
  i.rows = 3, i.placeholder = r, i.value = t === void 0 ? "" : JSON.stringify(t, null, 2), i.addEventListener("change", () => {
3072
3095
  let e = i.value.trim();
@@ -3086,12 +3109,12 @@ function er(e, t, n, r = "") {
3086
3109
  }
3087
3110
  //#endregion
3088
3111
  //#region src/model-preview.ts
3089
- var tr = 2.4, nr = 1.35, rr = [
3112
+ var rr = 2.4, ir = 1.35, ar = [
3090
3113
  0,
3091
3114
  .5,
3092
3115
  0
3093
3116
  ];
3094
- function ir(e) {
3117
+ function or(e) {
3095
3118
  return {
3096
3119
  format: 1,
3097
3120
  type: "scene",
@@ -3122,8 +3145,8 @@ function ir(e) {
3122
3145
  current: !0,
3123
3146
  position: [
3124
3147
  0,
3125
- nr,
3126
- tr
3148
+ ir,
3149
+ rr
3127
3150
  ]
3128
3151
  }
3129
3152
  },
@@ -3151,7 +3174,7 @@ function ir(e) {
3151
3174
  }
3152
3175
  };
3153
3176
  }
3154
- var ar = class {
3177
+ var sr = class {
3155
3178
  canvas = null;
3156
3179
  engine = null;
3157
3180
  renderer = null;
@@ -3190,7 +3213,7 @@ var ar = class {
3190
3213
  }
3191
3214
  load(e) {
3192
3215
  if (this.engine) try {
3193
- this.engine.setScene(c(ir(e)));
3216
+ this.engine.setScene(c(or(e)));
3194
3217
  } catch (t) {
3195
3218
  console.warn("[incanto] library preview could not load", e, t);
3196
3219
  }
@@ -3204,11 +3227,11 @@ var ar = class {
3204
3227
  let i = this.renderer;
3205
3228
  i && (i.viewOverride = {
3206
3229
  position: [
3207
- Math.sin(this.angle) * tr,
3208
- nr,
3209
- Math.cos(this.angle) * tr
3230
+ Math.sin(this.angle) * rr,
3231
+ ir,
3232
+ Math.cos(this.angle) * rr
3210
3233
  ],
3211
- target: rr
3234
+ target: ar
3212
3235
  }, this.engine?.tick(n));
3213
3236
  };
3214
3237
  this.raf = requestAnimationFrame(t);
@@ -3216,8 +3239,8 @@ var ar = class {
3216
3239
  stop() {
3217
3240
  this.raf && cancelAnimationFrame(this.raf), this.raf = 0;
3218
3241
  }
3219
- }, or = "incanto-editor-v8-token", sr = 24;
3220
- async function cr(e, t, n) {
3242
+ }, cr = "incanto-editor-v8-token", lr = 24;
3243
+ async function ur(e, t, n) {
3221
3244
  if (!me(e.url) || n !== "spritesheet" && n !== "texture") return null;
3222
3245
  try {
3223
3246
  let n = h(await (await fetch(e.url)).json(), {
@@ -3232,19 +3255,19 @@ async function cr(e, t, n) {
3232
3255
  return console.warn("[incanto] not a usable sprite config:", e.url, t), null;
3233
3256
  }
3234
3257
  }
3235
- function lr() {
3258
+ function dr() {
3236
3259
  try {
3237
- return localStorage.getItem(or) ?? "";
3260
+ return localStorage.getItem(cr) ?? "";
3238
3261
  } catch {
3239
3262
  return "";
3240
3263
  }
3241
3264
  }
3242
- function ur(e) {
3265
+ function fr(e) {
3243
3266
  try {
3244
- e ? localStorage.setItem(or, e) : localStorage.removeItem(or);
3267
+ e ? localStorage.setItem(cr, e) : localStorage.removeItem(cr);
3245
3268
  } catch {}
3246
3269
  }
3247
- function dr(e, t) {
3270
+ function pr(e, t) {
3248
3271
  return new Promise((n) => {
3249
3272
  let r = [...t.shelf ?? []], i = "", a = 1, o = !1, s = [], c = [], l = null, u = !1, d = !1, f = document.createElement("div");
3250
3273
  f.className = "lib-backdrop";
@@ -3274,7 +3297,7 @@ function dr(e, t) {
3274
3297
  w.type = "button", w.className = "ghost lib-more", w.textContent = "load more", w.hidden = !0, x.append(C, S, w);
3275
3298
  let T = document.createElement("aside");
3276
3299
  T.className = "lib-detail", y.append(b, x, T);
3277
- let E = new ar(), D = (e) => {
3300
+ let E = new sr(), D = (e) => {
3278
3301
  d || (d = !0, E.dispose(), document.removeEventListener("keydown", O, !0), f.remove(), n(e));
3279
3302
  }, O = (e) => {
3280
3303
  e.key === "Escape" && (e.stopPropagation(), D(null));
@@ -3377,7 +3400,7 @@ function dr(e, t) {
3377
3400
  return;
3378
3401
  }
3379
3402
  (async () => {
3380
- let n = ce(e), r = await cr(e, n, t.assetType), i = r?.asset ?? pe(e, t.kind, t.assetType), a = t.onAsset?.(e, i, n) ?? e.url;
3403
+ let n = ce(e), r = await ur(e, n, t.assetType), i = r?.asset ?? pe(e, t.kind, t.assetType), a = t.onAsset?.(e, i, n) ?? e.url;
3381
3404
  r && t.onProps?.(r.props), D(a);
3382
3405
  })();
3383
3406
  }), d.appendChild(f), T.appendChild(d);
@@ -3398,7 +3421,7 @@ function dr(e, t) {
3398
3421
  let e = document.createElement("img");
3399
3422
  e.src = t.url, e.alt = "", e.loading = "lazy", n.appendChild(e);
3400
3423
  } else {
3401
- let e = Ne(r === "audio" ? "AudioPlayer" : "ModelInstance3D");
3424
+ let e = Pe(r === "audio" ? "AudioPlayer" : "ModelInstance3D");
3402
3425
  e.classList.add("lib-glyph"), n.appendChild(e);
3403
3426
  }
3404
3427
  if (me(t.url)) {
@@ -3420,10 +3443,10 @@ function dr(e, t) {
3420
3443
  let r = document.createElement("p");
3421
3444
  r.className = "lib-token-line lib-token-how", r.textContent = "The catalog is per-account. Paste a Verse8 access token to browse it here — it is kept in this browser and sent only to your own editor server. Starting the editor with --token (or INCANTO_V8_TOKEN) skips this.";
3422
3445
  let i = document.createElement("input");
3423
- i.type = "password", i.className = "mono", i.placeholder = "v8 access token", i.value = lr();
3446
+ i.type = "password", i.className = "mono", i.placeholder = "v8 access token", i.value = dr();
3424
3447
  let o = document.createElement("button");
3425
3448
  o.type = "button", o.className = "primary", o.textContent = "connect", o.addEventListener("click", () => {
3426
- ur(i.value.trim()), a = 1, P(!1);
3449
+ fr(i.value.trim()), a = 1, P(!1);
3427
3450
  }), i.addEventListener("keydown", (e) => {
3428
3451
  e.key === "Enter" && o.click();
3429
3452
  });
@@ -3437,8 +3460,8 @@ function dr(e, t) {
3437
3460
  tags: r,
3438
3461
  keyword: i.trim() || void 0,
3439
3462
  page: a,
3440
- limit: sr
3441
- }, lr() || void 0);
3463
+ limit: lr
3464
+ }, dr() || void 0);
3442
3465
  if (d) return;
3443
3466
  s = t ? [...s, ...n.items] : n.items, c = s, o = n.hasNext;
3444
3467
  let l = n.total === void 0 ? "" : ` of ${n.total}`;
@@ -3470,16 +3493,16 @@ function dr(e, t) {
3470
3493
  }
3471
3494
  //#endregion
3472
3495
  //#region src/scene-tree.ts
3473
- var fr = ".scene.json";
3474
- function pr(e) {
3496
+ var mr = ".scene.json";
3497
+ function hr(e) {
3475
3498
  let t = e.split("/").pop() ?? e;
3476
- return t.endsWith(fr) ? t.slice(0, -11) : t;
3499
+ return t.endsWith(mr) ? t.slice(0, -11) : t;
3477
3500
  }
3478
- function mr(e) {
3501
+ function gr(e) {
3479
3502
  let t = e.lastIndexOf("/");
3480
3503
  return t === -1 ? "" : e.slice(0, t);
3481
3504
  }
3482
- function hr(e, t) {
3505
+ function _r(e, t) {
3483
3506
  return {
3484
3507
  path: e,
3485
3508
  name: t,
@@ -3487,31 +3510,31 @@ function hr(e, t) {
3487
3510
  files: []
3488
3511
  };
3489
3512
  }
3490
- function gr(e) {
3491
- let t = hr("", "");
3513
+ function vr(e) {
3514
+ let t = _r("", "");
3492
3515
  for (let n of e) {
3493
3516
  let e = n.rel.split("/");
3494
3517
  if (!e.pop()) continue;
3495
3518
  let r = t;
3496
3519
  for (let t of e) {
3497
3520
  let e = r.path ? `${r.path}/${t}` : t, n = r.dirs.get(t);
3498
- n || (n = hr(e, t), r.dirs.set(t, n)), r = n;
3521
+ n || (n = _r(e, t), r.dirs.set(t, n)), r = n;
3499
3522
  }
3500
3523
  r.files.push(n);
3501
3524
  }
3502
3525
  return t;
3503
3526
  }
3504
- function _r(e) {
3527
+ function yr(e) {
3505
3528
  let t = e.files.length;
3506
- for (let n of e.dirs.values()) t += _r(n);
3529
+ for (let n of e.dirs.values()) t += yr(n);
3507
3530
  return t;
3508
3531
  }
3509
- function vr(e) {
3532
+ function br(e) {
3510
3533
  let t = e.files.filter((e) => e.scene).length;
3511
- for (let n of e.dirs.values()) t += vr(n);
3534
+ for (let n of e.dirs.values()) t += br(n);
3512
3535
  return t;
3513
3536
  }
3514
- function yr(e) {
3537
+ function xr(e) {
3515
3538
  let t = e, n = e.name;
3516
3539
  for (; t.files.length === 0 && t.dirs.size === 1;) {
3517
3540
  let e = [...t.dirs.values()][0];
@@ -3523,16 +3546,16 @@ function yr(e) {
3523
3546
  label: n
3524
3547
  };
3525
3548
  }
3526
- function br(e) {
3527
- let t = mr(e ?? "").split("/").filter(Boolean), n = [], r = "";
3549
+ function Sr(e) {
3550
+ let t = gr(e ?? "").split("/").filter(Boolean), n = [], r = "";
3528
3551
  for (let e of t) r = r ? `${r}/${e}` : e, n.push(r);
3529
3552
  return n;
3530
3553
  }
3531
- function xr(e, t = {}) {
3554
+ function Cr(e, t = {}) {
3532
3555
  let n = (t.query ?? "").trim().toLowerCase(), r = n ? e.filter((e) => e.rel.toLowerCase().includes(n)) : e, i = t.expanded ?? /* @__PURE__ */ new Set(), a = [], o = (e, r) => {
3533
3556
  let s = [...e.dirs.values()].sort((e, t) => e.name.localeCompare(t.name));
3534
3557
  for (let e of s) {
3535
- let { dir: t, label: s } = yr(e), c = _r(t);
3558
+ let { dir: t, label: s } = xr(e), c = yr(t);
3536
3559
  if (c === 0) continue;
3537
3560
  let l = n !== "" || i.has(t.path);
3538
3561
  a.push({
@@ -3541,31 +3564,31 @@ function xr(e, t = {}) {
3541
3564
  label: s,
3542
3565
  depth: r,
3543
3566
  count: c,
3544
- scenes: vr(t),
3567
+ scenes: br(t),
3545
3568
  open: l
3546
3569
  }), l && o(t, r + 1);
3547
3570
  }
3548
- let c = [...e.files].sort((e, t) => pr(e.rel).localeCompare(pr(t.rel)));
3571
+ let c = [...e.files].sort((e, t) => hr(e.rel).localeCompare(hr(t.rel)));
3549
3572
  for (let e of c) a.push({
3550
3573
  kind: "scene",
3551
3574
  entry: e,
3552
- label: pr(e.rel),
3553
- folder: mr(e.rel),
3575
+ label: hr(e.rel),
3576
+ folder: gr(e.rel),
3554
3577
  depth: r,
3555
3578
  current: e.rel === t.current
3556
3579
  });
3557
3580
  };
3558
- return o(gr(r), 0), a;
3581
+ return o(vr(r), 0), a;
3559
3582
  }
3560
- function Sr(e, t) {
3561
- let n = new Set(br(t));
3562
- if (e.length <= 24) for (let t of e) for (let e of br(t.rel)) n.add(e);
3583
+ function wr(e, t) {
3584
+ let n = new Set(Sr(t));
3585
+ if (e.length <= 24) for (let t of e) for (let e of Sr(t.rel)) n.add(e);
3563
3586
  return n;
3564
3587
  }
3565
- function Cr(e) {
3588
+ function Tr(e) {
3566
3589
  return typeof e != "number" || !Number.isFinite(e) || e < 0 ? "" : e < 1e3 ? `${e} B` : e < 1e3 * 1e3 ? `${(e / 1e3).toFixed(1)} kB` : `${(e / 1e3 / 1e3).toFixed(1)} MB`;
3567
3590
  }
3568
- function wr(e, t) {
3591
+ function Er(e, t) {
3569
3592
  if (typeof e != "number" || !Number.isFinite(e) || e <= 0) return "";
3570
3593
  let n = Math.round((t - e) / 1e3);
3571
3594
  if (n < 90) return "just now";
@@ -3574,20 +3597,20 @@ function wr(e, t) {
3574
3597
  let i = Math.round(r / 60);
3575
3598
  return i < 24 ? `${i}h ago` : i < 48 ? "yesterday" : new Date(e).toISOString().slice(0, 10);
3576
3599
  }
3577
- function Tr(e, t = "new-level") {
3600
+ function Dr(e, t = "new-level") {
3578
3601
  let n = e ? e.kind === "folder" ? e.path : e.folder : "";
3579
- return n ? `${n}/${t}${fr}` : `${t}${fr}`;
3602
+ return n ? `${n}/${t}${mr}` : `${t}${mr}`;
3580
3603
  }
3581
3604
  //#endregion
3582
3605
  //#region src/scene-browser.ts
3583
- function Er(e, t) {
3606
+ function Or(e, t) {
3584
3607
  let n = document.createElement("span");
3585
3608
  return n.className = e, n.textContent = t, n;
3586
3609
  }
3587
- function Dr(e, t, n = () => Date.now()) {
3610
+ function kr(e, t, n = () => Date.now()) {
3588
3611
  let r = [], i = /* @__PURE__ */ new Set(), a = [], o = 0, s = !0, c = () => {
3589
3612
  let c = t.current();
3590
- if (a = xr(r, {
3613
+ if (a = Cr(r, {
3591
3614
  expanded: i,
3592
3615
  query: e.search.value,
3593
3616
  current: c
@@ -3603,17 +3626,17 @@ function Dr(e, t, n = () => Date.now()) {
3603
3626
  a.forEach((n, r) => {
3604
3627
  let i = document.createElement("div");
3605
3628
  i.className = n.kind === "folder" ? "scene-row scene-folder" : "scene-row", i.style.paddingLeft = `${6 + n.depth * 14}px`, r === o && i.classList.add("active");
3606
- let a = Er("scene-caret", "");
3607
- n.kind === "folder" ? (a.classList.add("chevron"), n.open || a.classList.add("collapsed"), a.appendChild(Pe())) : a.textContent = "◇", i.append(a, Er("scene-name", n.label), Er("scene-meta", n.kind === "folder" ? n.scenes > 0 ? `${n.scenes} scene${n.scenes === 1 ? "" : "s"}` : `${n.count} file${n.count === 1 ? "" : "s"}` : [
3629
+ let a = Or("scene-caret", "");
3630
+ n.kind === "folder" ? (a.classList.add("chevron"), n.open || a.classList.add("collapsed"), a.appendChild(Fe())) : a.textContent = "◇", i.append(a, Or("scene-name", n.label), Or("scene-meta", n.kind === "folder" ? n.scenes > 0 ? `${n.scenes} scene${n.scenes === 1 ? "" : "s"}` : `${n.count} file${n.count === 1 ? "" : "s"}` : [
3608
3631
  n.entry.scene ? [n.entry.scene.dimension, `${n.entry.scene.nodes} node${n.entry.scene.nodes === 1 ? "" : "s"}`].filter(Boolean).join(" · ") : "not a scene",
3609
- wr(n.entry.modified, u),
3610
- Cr(n.entry.size)
3632
+ Er(n.entry.modified, u),
3633
+ Tr(n.entry.size)
3611
3634
  ].filter(Boolean).join(" · "))), n.kind === "scene" && (n.current && i.classList.add("current"), n.entry.notScene ? (i.classList.add("not-scene"), i.title = `${n.entry.rel}\n\nnot a scene: ${n.entry.notScene}`) : i.title = n.entry.rel), i.addEventListener("click", () => {
3612
3635
  o = r, n.kind === "folder" ? l(n.path) : t.open(n.entry);
3613
3636
  }), e.list.appendChild(i);
3614
3637
  });
3615
3638
  let d = r.length, f = a.filter((e) => e.kind === "scene").length;
3616
- e.count.textContent = d === 0 ? "" : f === d ? `${d}` : `${f} / ${d}`, e.path.placeholder = Tr(a[o]), e.list.querySelector(".active")?.scrollIntoView({ block: "nearest" });
3639
+ e.count.textContent = d === 0 ? "" : f === d ? `${d}` : `${f} / ${d}`, e.path.placeholder = Dr(a[o]), e.list.querySelector(".active")?.scrollIntoView({ block: "nearest" });
3617
3640
  }, l = (e) => {
3618
3641
  i.has(e) ? i.delete(e) : i.add(e), c();
3619
3642
  }, u = (e) => {
@@ -3650,17 +3673,17 @@ function Dr(e, t, n = () => Date.now()) {
3650
3673
  n.className = "scene-empty", n.textContent = `could not list scenes: ${t instanceof Error ? t.message : String(t)}`, e.list.appendChild(n), e.count.textContent = "";
3651
3674
  return;
3652
3675
  }
3653
- if (i.size === 0) i = Sr(r, t.current());
3654
- else for (let e of br(t.current())) i.add(e);
3676
+ if (i.size === 0) i = wr(r, t.current());
3677
+ else for (let e of Sr(t.current())) i.add(e);
3655
3678
  s = !0, c(), e.search.focus(), e.search.select();
3656
3679
  } };
3657
3680
  }
3658
3681
  //#endregion
3659
3682
  //#region src/shell.ts
3660
- var Or = "\n<header id=\"topbar\">\n <div class=\"brand\">\n <span class=\"brand-mark\">in</span>\n <strong>incanto</strong><span class=\"brand-sub\">editor</span>\n </div>\n <div id=\"file-chip\" title=\"\">\n <svg aria-hidden=\"true\" width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/><path d=\"M14 2v6h6\"/></svg>\n <span id=\"file-path\"></span>\n </div>\n <span id=\"engine-version\" class=\"pill\"></span>\n <span class=\"spacer\"></span>\n <button type=\"button\" id=\"lang-btn\" class=\"ghost\" title=\"Language / 언어\">\n <span id=\"lang-current\">EN</span>\n <svg aria-hidden=\"true\" width=\"9\" height=\"9\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><path d=\"m6 9 6 6 6-6\"/></svg>\n </button>\n <button type=\"button\" id=\"docs-btn\" class=\"ghost\" title=\"Node documentation\">\n <svg aria-hidden=\"true\" width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M4 19.5A2.5 2.5 0 0 1 6.5 17H20\"/><path d=\"M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z\"/></svg>\n docs\n </button>\n <button type=\"button\" id=\"scenes-btn\" class=\"ghost\" hidden>\n <svg aria-hidden=\"true\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M3 7V5a2 2 0 0 1 2-2h2M17 3h2a2 2 0 0 1 2 2v2M21 17v2a2 2 0 0 1-2 2h-2M7 21H5a2 2 0 0 1-2-2v-2\"/></svg>\n scenes\n </button>\n <button type=\"button\" id=\"fit-btn\" class=\"ghost\" title=\"Frame the selected node — or the whole scene when nothing is selected (F)\">⌖ frame</button>\n <button type=\"button\" id=\"undo-btn\" class=\"ghost\" title=\"Undo (Ctrl/Cmd+Z)\" disabled>↩ undo</button>\n <button type=\"button\" id=\"play-btn\" class=\"play\" title=\"Run the scene with physics + input\">\n <svg aria-hidden=\"true\" width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M8 5v14l11-7z\"/></svg>\n play\n </button>\n <button type=\"button\" id=\"save-btn\" class=\"primary\" disabled>save</button>\n</header>\n<div id=\"error-banner\" hidden>\n <span id=\"error-text\"></span>\n <button type=\"button\" id=\"error-close\" title=\"Dismiss (Esc)\">✕</button>\n</div>\n<div id=\"play-notice\" hidden></div>\n<div id=\"edit-notice\" hidden></div>\n<main>\n <aside id=\"tree-pane\">\n <button type=\"button\" class=\"pane-title explorer-section section-toggle\" data-section=\"assets\">\n <span class=\"chev\"><svg aria-hidden=\"true\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.4\"><path d=\"m6 9 6 6 6-6\"/></svg></span> assets\n <span class=\"spacer\"></span>\n <span id=\"group-add-btn\" class=\"ghost section-add\" title=\"Add a group (folder)\" role=\"button\">\n <svg aria-hidden=\"true\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M3 6a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z\"/><path d=\"M12 11v6M9 14h6\"/></svg>\n </span>\n <span id=\"asset-add-btn\" class=\"ghost section-add\" title=\"Add an asset\" role=\"button\">+</span>\n </button>\n <div id=\"asset-tree\" data-body=\"assets\"></div>\n <button type=\"button\" class=\"pane-title explorer-section section-toggle\" data-section=\"scene\">\n <span class=\"chev\"><svg aria-hidden=\"true\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.4\"><path d=\"m6 9 6 6 6-6\"/></svg></span> scene\n </button>\n <div id=\"scene-body\" data-body=\"scene\">\n <div id=\"tree\"></div>\n <div id=\"tree-actions\">\n <select id=\"add-type\" title=\"Node type to add\"></select>\n <button type=\"button\" id=\"add-btn\" class=\"ghost\" title=\"Add child to the selected node\">+</button>\n <button type=\"button\" id=\"generate-btn\" class=\"ghost\" title=\"Generate an environment under the selected node\">\n <svg aria-hidden=\"true\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M12 3v4M12 17v4M3 12h4M17 12h4M5.6 5.6l2.8 2.8M15.6 15.6l2.8 2.8M18.4 5.6l-2.8 2.8M8.4 15.6l-2.8 2.8\"/></svg>\n </button>\n <button type=\"button\" id=\"delete-btn\" class=\"ghost danger\" title=\"Delete the selected node\">✕</button>\n </div>\n </div>\n </aside>\n <section id=\"viewport-pane\">\n <div id=\"mode-toolbar\">\n <button type=\"button\" id=\"tool-move\" class=\"tool active\" title=\"Move (W)\">\n <svg aria-hidden=\"true\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M12 2v20M2 12h20M8 6l4-4 4 4M8 18l4 4 4-4M6 8l-4 4 4 4M18 8l4 4-4 4\"/></svg>\n </button>\n <button type=\"button\" id=\"tool-rotate\" class=\"tool\" title=\"Rotate (E)\">\n <svg aria-hidden=\"true\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 12a9 9 0 1 1-3-6.7\"/><path d=\"M21 3v5h-5\"/></svg>\n </button>\n <button type=\"button\" id=\"tool-scale\" class=\"tool\" title=\"Scale (R)\">\n <svg aria-hidden=\"true\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 3 9 15\"/><path d=\"M21 8V3h-5\"/><rect x=\"3\" y=\"13\" width=\"8\" height=\"8\" rx=\"1\"/></svg>\n </button>\n <span class=\"tool-divider\"></span>\n <button type=\"button\" id=\"tool-colliders\" class=\"tool active\" title=\"Show colliders\">\n <svg aria-hidden=\"true\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-dasharray=\"3 2\"><rect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"2\"/></svg>\n </button>\n </div>\n <canvas id=\"viewport\"></canvas>\n <canvas id=\"overlay\"></canvas>\n <canvas id=\"play-canvas\" hidden></canvas>\n <div id=\"hints-dock\">\n <div id=\"hints\" class=\"hints\">\n <span><b>click</b> select</span><span><b>drag</b> move</span><span><b>wheel</b> zoom</span><span><b>W/E/R</b> move/rotate/scale</span><span><b>⇧</b> snap</span><span><b>right-drag</b> pan</span><span><b>F</b> frame selected</span>\n </div>\n <div id=\"hints-3d\" class=\"hints\" hidden>\n <span><b>drag</b> orbit</span><span><b>right-drag</b> pan</span><span><b>wheel</b> zoom</span><span><b>W/E/R</b> mode</span><span><b>⇧</b> snap</span><span><b>F</b> frame selected</span><span><b>0</b> game cam</span>\n </div>\n <button type=\"button\" id=\"hints-toggle\" title=\"Controls\">\n <svg aria-hidden=\"true\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\"><rect x=\"2\" y=\"6\" width=\"20\" height=\"12\" rx=\"2\"/><path d=\"M6 10h.01M10 10h.01M14 10h.01M18 10h.01M6 14h.01M18 14h.01M9 14h6\"/></svg>\n </button>\n </div>\n <button type=\"button\" id=\"gameview-btn\" class=\"ghost\" title=\"View through the game camera — exactly what running the scene shows (0)\">\n <svg aria-hidden=\"true\" width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M3 7h12v10H3z\"/><path d=\"M15 10l6-3v10l-6-3\"/></svg>\n game cam\n </button>\n </section>\n <aside id=\"inspector-pane\">\n <div class=\"pane-title\">inspector</div>\n <div id=\"inspector\"></div>\n </aside>\n</main>\n<div id=\"picker\" hidden>\n <div id=\"picker-card\">\n <div class=\"pane-title picker-title\">\n open a scene\n <button type=\"button\" id=\"picker-close\" title=\"Close (Esc)\">✕</button>\n </div>\n <div id=\"picker-find\">\n <input id=\"picker-search\" type=\"search\" placeholder=\"filter — ↑↓ move · → open · ⏎ load\" />\n <span id=\"picker-count\"></span>\n </div>\n <div id=\"picker-list\"></div>\n <div id=\"picker-new\">\n <input id=\"picker-path\" type=\"text\" placeholder=\"src/new-level.scene.json\" />\n <button type=\"button\" id=\"picker-create\" class=\"primary\">create</button>\n </div>\n </div>\n</div>\n<div id=\"docs\" hidden>\n <div id=\"docs-card\">\n <div class=\"pane-title picker-title\">\n incanto nodes\n <button type=\"button\" id=\"docs-close\" title=\"Close (Esc)\">✕</button>\n </div>\n <div id=\"docs-layout\">\n <nav id=\"docs-tabs\"></nav>\n <div id=\"docs-body\"></div>\n </div>\n </div>\n</div>\n<div id=\"confirm\" hidden>\n <div id=\"confirm-card\">\n <div class=\"pane-title picker-title\">\n <span id=\"confirm-title\">still referenced</span>\n <button type=\"button\" id=\"confirm-close\" title=\"Close (Esc)\">✕</button>\n </div>\n <div id=\"confirm-body\">\n <div id=\"confirm-text\"></div>\n <div id=\"confirm-list\"></div>\n </div>\n <div id=\"confirm-actions\">\n <button type=\"button\" id=\"confirm-cancel\" class=\"ghost\">cancel</button>\n <button type=\"button\" id=\"confirm-delete\">unlink &amp; delete</button>\n </div>\n </div>\n</div>\n<div id=\"generate\" hidden>\n <div id=\"generate-card\">\n <div class=\"pane-title picker-title\">\n generate environment\n <button type=\"button\" id=\"generate-close\" title=\"Close (Esc)\">✕</button>\n </div>\n <div id=\"generate-body\"></div>\n <div id=\"generate-actions\">\n <span id=\"generate-status\"></span>\n <button type=\"button\" id=\"generate-cancel\" class=\"ghost\">cancel</button>\n <button type=\"button\" id=\"generate-insert\" class=\"primary\">insert</button>\n </div>\n </div>\n</div>\n<div id=\"popover\" hidden></div>\n";
3683
+ var Ar = "\n<header id=\"topbar\">\n <div class=\"brand\">\n <span class=\"brand-mark\">in</span>\n <strong>incanto</strong><span class=\"brand-sub\">editor</span>\n </div>\n <div id=\"file-chip\" title=\"\">\n <svg aria-hidden=\"true\" width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/><path d=\"M14 2v6h6\"/></svg>\n <span id=\"file-path\"></span>\n </div>\n <span id=\"engine-version\" class=\"pill\"></span>\n <span class=\"spacer\"></span>\n <button type=\"button\" id=\"lang-btn\" class=\"ghost\" title=\"Language / 언어\">\n <span id=\"lang-current\">EN</span>\n <svg aria-hidden=\"true\" width=\"9\" height=\"9\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><path d=\"m6 9 6 6 6-6\"/></svg>\n </button>\n <button type=\"button\" id=\"docs-btn\" class=\"ghost\" title=\"Node documentation\">\n <svg aria-hidden=\"true\" width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M4 19.5A2.5 2.5 0 0 1 6.5 17H20\"/><path d=\"M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z\"/></svg>\n docs\n </button>\n <button type=\"button\" id=\"scenes-btn\" class=\"ghost\" hidden>\n <svg aria-hidden=\"true\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M3 7V5a2 2 0 0 1 2-2h2M17 3h2a2 2 0 0 1 2 2v2M21 17v2a2 2 0 0 1-2 2h-2M7 21H5a2 2 0 0 1-2-2v-2\"/></svg>\n scenes\n </button>\n <button type=\"button\" id=\"fit-btn\" class=\"ghost\" title=\"Frame the selected node — or the whole scene when nothing is selected (F)\">⌖ frame</button>\n <button type=\"button\" id=\"undo-btn\" class=\"ghost\" title=\"Undo (Ctrl/Cmd+Z)\" disabled>↩ undo</button>\n <button type=\"button\" id=\"play-btn\" class=\"play\" title=\"Run the scene with physics + input\">\n <svg aria-hidden=\"true\" width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M8 5v14l11-7z\"/></svg>\n play\n </button>\n <button type=\"button\" id=\"save-btn\" class=\"primary\" disabled>save</button>\n</header>\n<div id=\"error-banner\" hidden>\n <span id=\"error-text\"></span>\n <button type=\"button\" id=\"error-close\" title=\"Dismiss (Esc)\">✕</button>\n</div>\n<div id=\"play-notice\" hidden></div>\n<div id=\"edit-notice\" hidden></div>\n<main>\n <aside id=\"tree-pane\">\n <button type=\"button\" class=\"pane-title explorer-section section-toggle\" data-section=\"assets\">\n <span class=\"chev\"><svg aria-hidden=\"true\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.4\"><path d=\"m6 9 6 6 6-6\"/></svg></span> assets\n <span class=\"spacer\"></span>\n <span id=\"group-add-btn\" class=\"ghost section-add\" title=\"Add a group (folder)\" role=\"button\">\n <svg aria-hidden=\"true\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M3 6a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z\"/><path d=\"M12 11v6M9 14h6\"/></svg>\n </span>\n <span id=\"asset-add-btn\" class=\"ghost section-add\" title=\"Add an asset\" role=\"button\">+</span>\n </button>\n <div id=\"asset-tree\" data-body=\"assets\"></div>\n <button type=\"button\" class=\"pane-title explorer-section section-toggle\" data-section=\"scene\">\n <span class=\"chev\"><svg aria-hidden=\"true\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.4\"><path d=\"m6 9 6 6 6-6\"/></svg></span> scene\n </button>\n <div id=\"scene-body\" data-body=\"scene\">\n <div id=\"tree\"></div>\n <div id=\"tree-actions\">\n <select id=\"add-type\" title=\"Node type to add\"></select>\n <button type=\"button\" id=\"add-btn\" class=\"ghost\" title=\"Add child to the selected node\">+</button>\n <button type=\"button\" id=\"generate-btn\" class=\"ghost\" title=\"Generate an environment under the selected node\">\n <svg aria-hidden=\"true\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M12 3v4M12 17v4M3 12h4M17 12h4M5.6 5.6l2.8 2.8M15.6 15.6l2.8 2.8M18.4 5.6l-2.8 2.8M8.4 15.6l-2.8 2.8\"/></svg>\n </button>\n <button type=\"button\" id=\"delete-btn\" class=\"ghost danger\" title=\"Delete the selected node\">✕</button>\n </div>\n </div>\n </aside>\n <section id=\"viewport-pane\">\n <div id=\"mode-toolbar\">\n <button type=\"button\" id=\"tool-move\" class=\"tool active\" title=\"Move (W)\">\n <svg aria-hidden=\"true\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M12 2v20M2 12h20M8 6l4-4 4 4M8 18l4 4 4-4M6 8l-4 4 4 4M18 8l4 4-4 4\"/></svg>\n </button>\n <button type=\"button\" id=\"tool-rotate\" class=\"tool\" title=\"Rotate (E)\">\n <svg aria-hidden=\"true\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 12a9 9 0 1 1-3-6.7\"/><path d=\"M21 3v5h-5\"/></svg>\n </button>\n <button type=\"button\" id=\"tool-scale\" class=\"tool\" title=\"Scale (R)\">\n <svg aria-hidden=\"true\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 3 9 15\"/><path d=\"M21 8V3h-5\"/><rect x=\"3\" y=\"13\" width=\"8\" height=\"8\" rx=\"1\"/></svg>\n </button>\n <span class=\"tool-divider\"></span>\n <button type=\"button\" id=\"tool-colliders\" class=\"tool active\" title=\"Show colliders\">\n <svg aria-hidden=\"true\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-dasharray=\"3 2\"><rect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"2\"/></svg>\n </button>\n </div>\n <canvas id=\"viewport\"></canvas>\n <canvas id=\"overlay\"></canvas>\n <canvas id=\"play-canvas\" hidden></canvas>\n <div id=\"hints-dock\">\n <div id=\"hints\" class=\"hints\">\n <span><b>click</b> select</span><span><b>drag</b> move</span><span><b>wheel</b> zoom</span><span><b>W/E/R</b> move/rotate/scale</span><span><b>⇧</b> snap</span><span><b>right-drag</b> pan</span><span><b>F</b> frame selected</span>\n </div>\n <div id=\"hints-3d\" class=\"hints\" hidden>\n <span><b>drag</b> orbit</span><span><b>right-drag</b> pan</span><span><b>wheel</b> zoom</span><span><b>W/E/R</b> mode</span><span><b>⇧</b> snap</span><span><b>F</b> frame selected</span><span><b>0</b> game cam</span>\n </div>\n <button type=\"button\" id=\"hints-toggle\" title=\"Controls\">\n <svg aria-hidden=\"true\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\"><rect x=\"2\" y=\"6\" width=\"20\" height=\"12\" rx=\"2\"/><path d=\"M6 10h.01M10 10h.01M14 10h.01M18 10h.01M6 14h.01M18 14h.01M9 14h6\"/></svg>\n </button>\n </div>\n <button type=\"button\" id=\"gameview-btn\" class=\"ghost\" title=\"View through the game camera — exactly what running the scene shows (0)\">\n <svg aria-hidden=\"true\" width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M3 7h12v10H3z\"/><path d=\"M15 10l6-3v10l-6-3\"/></svg>\n game cam\n </button>\n </section>\n <aside id=\"inspector-pane\">\n <div class=\"pane-title\">inspector</div>\n <div id=\"inspector\"></div>\n </aside>\n</main>\n<div id=\"picker\" hidden>\n <div id=\"picker-card\">\n <div class=\"pane-title picker-title\">\n open a scene\n <button type=\"button\" id=\"picker-close\" title=\"Close (Esc)\">✕</button>\n </div>\n <div id=\"picker-find\">\n <input id=\"picker-search\" type=\"search\" placeholder=\"filter — ↑↓ move · → open · ⏎ load\" />\n <span id=\"picker-count\"></span>\n </div>\n <div id=\"picker-list\"></div>\n <div id=\"picker-new\">\n <input id=\"picker-path\" type=\"text\" placeholder=\"src/new-level.scene.json\" />\n <button type=\"button\" id=\"picker-create\" class=\"primary\">create</button>\n </div>\n </div>\n</div>\n<div id=\"docs\" hidden>\n <div id=\"docs-card\">\n <div class=\"pane-title picker-title\">\n incanto nodes\n <button type=\"button\" id=\"docs-close\" title=\"Close (Esc)\">✕</button>\n </div>\n <div id=\"docs-layout\">\n <nav id=\"docs-tabs\"></nav>\n <div id=\"docs-body\"></div>\n </div>\n </div>\n</div>\n<div id=\"confirm\" hidden>\n <div id=\"confirm-card\">\n <div class=\"pane-title picker-title\">\n <span id=\"confirm-title\">still referenced</span>\n <button type=\"button\" id=\"confirm-close\" title=\"Close (Esc)\">✕</button>\n </div>\n <div id=\"confirm-body\">\n <div id=\"confirm-text\"></div>\n <div id=\"confirm-list\"></div>\n </div>\n <div id=\"confirm-actions\">\n <button type=\"button\" id=\"confirm-cancel\" class=\"ghost\">cancel</button>\n <button type=\"button\" id=\"confirm-delete\">unlink &amp; delete</button>\n </div>\n </div>\n</div>\n<div id=\"generate\" hidden>\n <div id=\"generate-card\">\n <div class=\"pane-title picker-title\">\n generate environment\n <button type=\"button\" id=\"generate-close\" title=\"Close (Esc)\">✕</button>\n </div>\n <div id=\"generate-body\"></div>\n <div id=\"generate-actions\">\n <span id=\"generate-status\"></span>\n <button type=\"button\" id=\"generate-cancel\" class=\"ghost\">cancel</button>\n <button type=\"button\" id=\"generate-insert\" class=\"primary\">insert</button>\n </div>\n </div>\n</div>\n<div id=\"popover\" hidden></div>\n";
3661
3684
  //#endregion
3662
3685
  //#region src/rename-refs.ts
3663
- function kr(e, t) {
3686
+ function jr(e, t) {
3664
3687
  let n = [String(e.name ?? "")], r = e;
3665
3688
  for (let e of t) {
3666
3689
  let t = r.children?.[e];
@@ -3669,7 +3692,7 @@ function kr(e, t) {
3669
3692
  }
3670
3693
  return n;
3671
3694
  }
3672
- function Ar(e, t, n, r) {
3695
+ function Mr(e, t, n, r) {
3673
3696
  if (e === "" || e === ".") return null;
3674
3697
  let i = n[n.length - 1];
3675
3698
  if (i === void 0 || i === r) return null;
@@ -3692,7 +3715,7 @@ function Ar(e, t, n, r) {
3692
3715
  let p = [...o];
3693
3716
  return p[f] = r, (a ? "/" : "") + p.join("/");
3694
3717
  }
3695
- function jr(e) {
3718
+ function Nr(e) {
3696
3719
  let n = [], i = (e) => {
3697
3720
  for (let [t, r] of Object.entries(e)) r?.nodePath && n.push(t);
3698
3721
  }, a = typeof e.type == "string" ? e.type : "";
@@ -3702,31 +3725,31 @@ function jr(e) {
3702
3725
  let o = e.script;
3703
3726
  return typeof o?.name == "string" && i(t(o.name)), n;
3704
3727
  }
3705
- function Mr(e, t, n) {
3728
+ function Pr(e, t, n) {
3706
3729
  let r = e.root;
3707
- if (!r || t.length === 0) return r && t.length === 0 ? Nr(e, r, n) : [];
3708
- let i = kr(r, t), a = Pr(r, t);
3730
+ if (!r || t.length === 0) return r && t.length === 0 ? Fr(e, r, n) : [];
3731
+ let i = jr(r, t), a = Ir(r, t);
3709
3732
  if (!a) return [];
3710
- let o = Fr(e, r, i, n);
3733
+ let o = Lr(e, r, i, n);
3711
3734
  return a.name = n, o;
3712
3735
  }
3713
- function Nr(e, t, n) {
3714
- let r = Fr(e, t, [String(t.name ?? "")], n);
3736
+ function Fr(e, t, n) {
3737
+ let r = Lr(e, t, [String(t.name ?? "")], n);
3715
3738
  return t.name = n, r;
3716
3739
  }
3717
- function Pr(e, t) {
3740
+ function Ir(e, t) {
3718
3741
  let n = e;
3719
3742
  for (let e of t) if (n = n?.children?.[e], !n) return null;
3720
3743
  return n ?? null;
3721
3744
  }
3722
- function Fr(e, t, n, r) {
3745
+ function Lr(e, t, n, r) {
3723
3746
  let i = [], a = String(t.name ?? ""), s = e.connections;
3724
3747
  Array.isArray(s) && s.forEach((e, t) => {
3725
3748
  let o = e;
3726
3749
  for (let e of ["from", "to"]) {
3727
3750
  let s = o[e];
3728
3751
  if (typeof s != "string") continue;
3729
- let c = Ar(s, [a], n, r);
3752
+ let c = Mr(s, [a], n, r);
3730
3753
  c !== null && (o[e] = c, i.push({
3731
3754
  where: `connections[${t}].${e}`,
3732
3755
  from: s,
@@ -3736,10 +3759,10 @@ function Fr(e, t, n, r) {
3736
3759
  });
3737
3760
  let c = (a, s) => {
3738
3761
  let l = a.props;
3739
- if (l) for (let c of jr(a)) {
3762
+ if (l) for (let c of Nr(a)) {
3740
3763
  let a = l[c], u = `${s.join("/")}.${c}`;
3741
3764
  if (typeof a == "string") {
3742
- let e = Ar(a, s, n, r);
3765
+ let e = Mr(a, s, n, r);
3743
3766
  e !== null && (l[c] = e, i.push({
3744
3767
  where: u,
3745
3768
  from: a,
@@ -3747,25 +3770,25 @@ function Fr(e, t, n, r) {
3747
3770
  }));
3748
3771
  } else Array.isArray(a) ? a.forEach((e, t) => {
3749
3772
  if (typeof e != "string") return;
3750
- let o = Ar(e, s, n, r);
3773
+ let o = Mr(e, s, n, r);
3751
3774
  o !== null && (a[t] = o, i.push({
3752
3775
  where: `${u}[${t}]`,
3753
3776
  from: e,
3754
3777
  to: o
3755
3778
  }));
3756
- }) : o(a) && Ir(e, t, a, n, r, u, i);
3779
+ }) : o(a) && Rr(e, t, a, n, r, u, i);
3757
3780
  }
3758
3781
  let u = a.children ?? [];
3759
3782
  for (let e of u) c(e, [...s, String(e.name ?? "")]);
3760
3783
  };
3761
3784
  return c(t, [a]), i;
3762
3785
  }
3763
- function Ir(e, t, n, r, i, a, o) {
3786
+ function Rr(e, t, n, r, i, a, o) {
3764
3787
  let s = n["@const"];
3765
3788
  if (typeof s != "string") return;
3766
3789
  let c = e.constants, l = c?.[s];
3767
3790
  if (typeof l != "string" || !l.startsWith("%") && !l.startsWith("/")) return;
3768
- let u = Ar(l, [String(t.name ?? "")], r, i);
3791
+ let u = Mr(l, [String(t.name ?? "")], r, i);
3769
3792
  u !== null && (c[s] = u, o.push({
3770
3793
  where: `constants.${s} (${a})`,
3771
3794
  from: l,
@@ -3774,7 +3797,7 @@ function Ir(e, t, n, r, i, a, o) {
3774
3797
  }
3775
3798
  //#endregion
3776
3799
  //#region src/state.ts
3777
- var Lr = class {
3800
+ var zr = class {
3778
3801
  working;
3779
3802
  selection = [];
3780
3803
  extra = [];
@@ -3801,7 +3824,7 @@ var Lr = class {
3801
3824
  undoStack = [];
3802
3825
  listeners = /* @__PURE__ */ new Set();
3803
3826
  constructor(e) {
3804
- this.working = e, this.original = JSON.stringify(e), this.working.root && Rr(this.working.root);
3827
+ this.working = e, this.original = JSON.stringify(e), this.working.root && Br(this.working.root);
3805
3828
  }
3806
3829
  get dirty() {
3807
3830
  return JSON.stringify(this.working) !== this.original;
@@ -3834,8 +3857,8 @@ var Lr = class {
3834
3857
  renameNode(e, t) {
3835
3858
  let n = this.nodeAt(e);
3836
3859
  if (!n) return null;
3837
- let r = this.parentOf(e), i = r ? qr(r, t, n) : t;
3838
- return i === n.name ? [] : this.transact(() => Mr(this.working, e, i));
3860
+ let r = this.parentOf(e), i = r ? Yr(r, t, n) : t;
3861
+ return i === n.name ? [] : this.transact(() => Pr(this.working, e, i));
3839
3862
  }
3840
3863
  priorError(e) {
3841
3864
  if (!this.validator) return null;
@@ -3849,27 +3872,27 @@ var Lr = class {
3849
3872
  return this.moveNodes([e], t, n)?.[0] ?? null;
3850
3873
  }
3851
3874
  moveNodes(e, t, n) {
3852
- let r = Ur(e).filter((e) => e.length > 0);
3875
+ let r = Gr(e).filter((e) => e.length > 0);
3853
3876
  if (r.length === 0) return null;
3854
3877
  for (let e of r) if (e.length <= t.length && e.every((e, n) => e === t[n])) return null;
3855
3878
  let i = this.working.root, a = r.map((e) => this.nodeAt(e)).filter((e) => e !== null);
3856
3879
  if (a.length !== r.length) return null;
3857
3880
  let o = this.nodeAt(t);
3858
3881
  return !o || a.includes(o) ? null : this.transact(() => {
3859
- for (let e of a) Gr(i, e);
3882
+ for (let e of a) qr(i, e);
3860
3883
  let e, t;
3861
3884
  if (n === "into") e = o, e.children ||= [], t = e.children.length;
3862
3885
  else {
3863
- let r = Wr(i, o);
3886
+ let r = Kr(i, o);
3864
3887
  if (!r) return null;
3865
3888
  e = r.parent, t = r.index + +(n === "after");
3866
3889
  }
3867
3890
  let r = [];
3868
3891
  a.forEach((n, r) => {
3869
- n.name = qr(e, n.name ?? "Node"), e.children?.splice(t + r, 0, n);
3892
+ n.name = Yr(e, n.name ?? "Node"), e.children?.splice(t + r, 0, n);
3870
3893
  });
3871
3894
  for (let e of a) {
3872
- let t = Kr(i, e);
3895
+ let t = Jr(i, e);
3873
3896
  if (!t) return null;
3874
3897
  r.push(t);
3875
3898
  }
@@ -3881,17 +3904,17 @@ var Lr = class {
3881
3904
  let t = this.nodeAt(e), n = this.parentOf(e);
3882
3905
  return !t || !n?.children ? null : this.transact(() => {
3883
3906
  let r = JSON.parse(JSON.stringify(t));
3884
- r.name = qr(n, t.name ?? "Node"), zr(r);
3907
+ r.name = Yr(n, t.name ?? "Node"), Vr(r);
3885
3908
  let i = e[e.length - 1] + 1;
3886
3909
  return n.children?.splice(i, 0, r), [...e.slice(0, -1), i];
3887
3910
  });
3888
3911
  }
3889
3912
  removeNodes(e) {
3890
- let t = Ur(e).filter((e) => e.length > 0);
3913
+ let t = Gr(e).filter((e) => e.length > 0);
3891
3914
  if (t.length === 0) return !1;
3892
3915
  let n = this.working.root, r = t.map((e) => this.nodeAt(e)).filter((e) => e !== null);
3893
3916
  return this.transact(() => {
3894
- for (let e of r) Gr(n, e);
3917
+ for (let e of r) qr(n, e);
3895
3918
  return !0;
3896
3919
  }) === !0;
3897
3920
  }
@@ -3901,16 +3924,16 @@ var Lr = class {
3901
3924
  insertNode(e, t) {
3902
3925
  if (!this.working.root) {
3903
3926
  let t = JSON.parse(JSON.stringify(e));
3904
- return zr(t), this.transact(() => (this.working.root = t, []));
3927
+ return Vr(t), this.transact(() => (this.working.root = t, []));
3905
3928
  }
3906
3929
  let n = this.nodeAt(t);
3907
3930
  return n ? this.transact(() => {
3908
3931
  let r = JSON.parse(JSON.stringify(e));
3909
- return r.name = qr(n, r.name ?? "Node"), zr(r), n.children ||= [], n.children.push(r), [...t, n.children.length - 1];
3932
+ return r.name = Yr(n, r.name ?? "Node"), Vr(r), n.children ||= [], n.children.push(r), [...t, n.children.length - 1];
3910
3933
  }) : null;
3911
3934
  }
3912
3935
  findRemovalReferences(e) {
3913
- let t = Ur(e).filter((e) => e.length > 0), n = this.working.root, r = t.map((e) => this.nodeAt(e)).filter((e) => e !== null), i = /* @__PURE__ */ new Set(), a = [];
3936
+ let t = Gr(e).filter((e) => e.length > 0), n = this.working.root, r = t.map((e) => this.nodeAt(e)).filter((e) => e !== null), i = /* @__PURE__ */ new Set(), a = [];
3914
3937
  for (let e of t) {
3915
3938
  let t = [], r = n;
3916
3939
  for (let n of e) {
@@ -3964,15 +3987,15 @@ var Lr = class {
3964
3987
  return s;
3965
3988
  }
3966
3989
  removeNodesUnlinking(e) {
3967
- let t = this.findRemovalReferences(e), n = Ur(e).filter((e) => e.length > 0), r = this.working.root, i = n.map((e) => this.nodeAt(e)).filter((e) => e !== null), a = new Set(t.filter((e) => e.kind === "uid").map((e) => e.value)), o = new Set(t.filter((e) => e.kind === "connection").map((e) => e.connectionIndex));
3990
+ let t = this.findRemovalReferences(e), n = Gr(e).filter((e) => e.length > 0), r = this.working.root, i = n.map((e) => this.nodeAt(e)).filter((e) => e !== null), a = new Set(t.filter((e) => e.kind === "uid").map((e) => e.value)), o = new Set(t.filter((e) => e.kind === "connection").map((e) => e.connectionIndex));
3968
3991
  return this.transact(() => {
3969
- o.size > 0 && (this.working.connections = (this.working.connections ?? []).filter((e, t) => !o.has(t))), a.size > 0 && Br(this.working, a, i);
3970
- for (let e of i) Gr(r, e);
3992
+ o.size > 0 && (this.working.connections = (this.working.connections ?? []).filter((e, t) => !o.has(t))), a.size > 0 && Hr(this.working, a, i);
3993
+ for (let e of i) qr(r, e);
3971
3994
  return !0;
3972
3995
  }) === !0;
3973
3996
  }
3974
3997
  reset(e) {
3975
- this.working = e, this.original = JSON.stringify(e), this.working.root && Rr(this.working.root), this.undoStack = [], this.selection = [], this.emit();
3998
+ this.working = e, this.original = JSON.stringify(e), this.working.root && Br(this.working.root), this.undoStack = [], this.selection = [], this.emit();
3976
3999
  }
3977
4000
  markSaved() {
3978
4001
  this.original = JSON.stringify(this.working), this.emit();
@@ -4004,7 +4027,7 @@ var Lr = class {
4004
4027
  return this.pendingGroups.delete(e) && this.pendingGroups.add(t), this.selectedGroup = t, this.mutate(() => {
4005
4028
  for (let i of r) {
4006
4029
  let r = `${t}/${i.slice(e.length + 1)}`;
4007
- n[r] = n[i], delete n[i], Vr(this.working, `$${i}`, `$${r}`);
4030
+ n[r] = n[i], delete n[i], Ur(this.working, `$${i}`, `$${r}`);
4008
4031
  }
4009
4032
  }), r.length === 0 && this.emit(), !0;
4010
4033
  }
@@ -4016,7 +4039,7 @@ var Lr = class {
4016
4039
  renameAssetKey(e, t) {
4017
4040
  let n = this.assetMap();
4018
4041
  return !(e in n) || !t || t === e || t in n ? !1 : (this.selectedAsset = t, this.mutate(() => {
4019
- n[t] = n[e], delete n[e], Vr(this.working, `$${e}`, `$${t}`);
4042
+ n[t] = n[e], delete n[e], Ur(this.working, `$${e}`, `$${t}`);
4020
4043
  }), !0);
4021
4044
  }
4022
4045
  deleteGroup(e) {
@@ -4042,7 +4065,7 @@ var Lr = class {
4042
4065
  this.emit();
4043
4066
  }
4044
4067
  allSelections() {
4045
- return [...this.selection === null ? [] : [this.selection, ...this.extra]].sort(Hr);
4068
+ return [...this.selection === null ? [] : [this.selection, ...this.extra]].sort(Wr);
4046
4069
  }
4047
4070
  isSelected(e) {
4048
4071
  let t = e.join(".");
@@ -4055,67 +4078,67 @@ var Lr = class {
4055
4078
  for (let e of this.listeners) e();
4056
4079
  }
4057
4080
  };
4058
- function Rr(e) {
4081
+ function Br(e) {
4059
4082
  (typeof e.uid != "string" || e.uid === "") && (e.uid = l());
4060
- for (let t of e.children ?? []) Rr(t);
4083
+ for (let t of e.children ?? []) Br(t);
4061
4084
  }
4062
- function zr(e) {
4085
+ function Vr(e) {
4063
4086
  e.uid = l();
4064
- for (let t of e.children ?? []) zr(t);
4087
+ for (let t of e.children ?? []) Vr(t);
4065
4088
  }
4066
- function Br(e, t, n) {
4089
+ function Hr(e, t, n) {
4067
4090
  if (Array.isArray(e)) {
4068
- for (let r = e.length - 1; r >= 0; r--) typeof e[r] == "string" && t.has(e[r]) ? e.splice(r, 1) : Br(e[r], t, n);
4091
+ for (let r = e.length - 1; r >= 0; r--) typeof e[r] == "string" && t.has(e[r]) ? e.splice(r, 1) : Hr(e[r], t, n);
4069
4092
  return;
4070
4093
  }
4071
4094
  if (typeof e == "object" && e) {
4072
4095
  if (n.includes(e)) return;
4073
- for (let [r, i] of Object.entries(e)) r !== "uid" && (typeof i == "string" && t.has(i) ? delete e[r] : Br(i, t, n));
4096
+ for (let [r, i] of Object.entries(e)) r !== "uid" && (typeof i == "string" && t.has(i) ? delete e[r] : Hr(i, t, n));
4074
4097
  }
4075
4098
  }
4076
- function Vr(e, t, n) {
4099
+ function Ur(e, t, n) {
4077
4100
  if (Array.isArray(e)) {
4078
4101
  e.forEach((r, i) => {
4079
- r === t ? e[i] = n : Vr(r, t, n);
4102
+ r === t ? e[i] = n : Ur(r, t, n);
4080
4103
  });
4081
4104
  return;
4082
4105
  }
4083
- if (typeof e == "object" && e) for (let [r, i] of Object.entries(e)) i === t ? e[r] = n : Vr(i, t, n);
4106
+ if (typeof e == "object" && e) for (let [r, i] of Object.entries(e)) i === t ? e[r] = n : Ur(i, t, n);
4084
4107
  }
4085
- function Hr(e, t) {
4108
+ function Wr(e, t) {
4086
4109
  for (let n = 0; n < Math.min(e.length, t.length); n++) if (e[n] !== t[n]) return e[n] - t[n];
4087
4110
  return e.length - t.length;
4088
4111
  }
4089
- function Ur(e) {
4090
- let t = [...e].sort(Hr), n = [];
4112
+ function Gr(e) {
4113
+ let t = [...e].sort(Wr), n = [];
4091
4114
  for (let e of t) n.some((t) => t.length <= e.length && t.every((t, n) => t === e[n])) || n.push(e);
4092
4115
  return n;
4093
4116
  }
4094
- function Wr(e, t) {
4117
+ function Kr(e, t) {
4095
4118
  let n = e.children?.indexOf(t) ?? -1;
4096
4119
  if (n >= 0) return {
4097
4120
  parent: e,
4098
4121
  index: n
4099
4122
  };
4100
4123
  for (let n of e.children ?? []) {
4101
- let e = Wr(n, t);
4124
+ let e = Kr(n, t);
4102
4125
  if (e) return e;
4103
4126
  }
4104
4127
  return null;
4105
4128
  }
4106
- function Gr(e, t) {
4107
- let n = Wr(e, t);
4129
+ function qr(e, t) {
4130
+ let n = Kr(e, t);
4108
4131
  n?.parent.children?.splice(n.index, 1);
4109
4132
  }
4110
- function Kr(e, t) {
4133
+ function Jr(e, t) {
4111
4134
  if (e === t) return [];
4112
4135
  for (let [n, r] of (e.children ?? []).entries()) {
4113
- let e = Kr(r, t);
4136
+ let e = Jr(r, t);
4114
4137
  if (e) return [n, ...e];
4115
4138
  }
4116
4139
  return null;
4117
4140
  }
4118
- function qr(e, t, n) {
4141
+ function Yr(e, t, n) {
4119
4142
  let r = new Set((e.children ?? []).filter((e) => e !== n).map((e) => e.name));
4120
4143
  if (!r.has(t)) return t;
4121
4144
  let i = 2;
@@ -4124,21 +4147,21 @@ function qr(e, t, n) {
4124
4147
  }
4125
4148
  //#endregion
4126
4149
  //#region src/styles.ts
4127
- var Jr = "\n/* ─── incanto editor · design system ──────────────────────────────────────── */\n:root {\n --bg-0: #0b0d14;\n --bg-1: #10131d;\n --bg-2: #161a27;\n --bg-3: #1d2231;\n --line: #262c3e;\n --line-strong: #343c54;\n --text: #e2e6f0;\n --text-dim: #9aa3bd;\n --text-faint: #5d6680;\n --accent: #6ee7dc;\n --accent-deep: #14b8a6;\n --violet: #a78bfa;\n --amber: #fbbf24;\n --rose: #fb7185;\n --green: #86efac;\n --shadow: 0 12px 40px rgba(0, 0, 0, 0.55);\n --r-sm: 6px;\n --r-md: 10px;\n color-scheme: dark;\n}\n* {\n box-sizing: border-box;\n}\n/* A button rule of \"display: inline-flex\" outranks the UA's [hidden] rule, so\n a button hidden from JS stays on screen. Say it once, loudly, here. */\n[hidden] {\n display: none !important;\n}\nhtml,\nbody {\n margin: 0;\n height: 100%;\n overflow: hidden;\n background: var(--bg-0);\n color: var(--text);\n font:\n 13px / 1.55 \"Inter\",\n -apple-system,\n \"Segoe UI\",\n system-ui,\n sans-serif;\n -webkit-font-smoothing: antialiased;\n}\ncode,\ntextarea,\n.mono {\n font-family: ui-monospace, \"SF Mono\", Menlo, monospace;\n}\n\n/* ─── top bar ─── */\n#topbar {\n display: flex;\n flex: none;\n align-items: center;\n gap: 10px;\n height: 46px;\n padding: 0 14px;\n background: linear-gradient(to bottom, var(--bg-2), var(--bg-1));\n border-bottom: 1px solid var(--line);\n}\n.brand {\n display: flex;\n align-items: baseline;\n gap: 7px;\n margin-right: 6px;\n}\n.brand-mark {\n display: inline-grid;\n place-items: center;\n width: 22px;\n height: 22px;\n border-radius: 6px;\n background: linear-gradient(135deg, var(--accent), var(--accent-deep));\n color: #07211d;\n font-weight: 800;\n font-size: 11px;\n align-self: center;\n}\n.brand strong {\n font-weight: 700;\n letter-spacing: 0.2px;\n}\n.brand-sub {\n color: var(--text-faint);\n font-size: 12px;\n}\n#file-chip {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n border: 1px solid var(--line);\n border-radius: 999px;\n background: var(--bg-1);\n color: var(--text-dim);\n font-size: 12px;\n max-width: 320px;\n}\n#file-path {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.pill {\n padding: 2px 9px;\n border-radius: 999px;\n background: var(--bg-3);\n color: var(--text-faint);\n font-size: 11px;\n font-family: ui-monospace, Menlo, monospace;\n}\n.spacer {\n flex: 1;\n}\n\n/* ─── buttons & controls ─── */\nbutton {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font: inherit;\n font-size: 12.5px;\n font-weight: 600;\n padding: 6px 12px;\n border-radius: var(--r-sm);\n border: 1px solid transparent;\n background: transparent;\n color: var(--text);\n cursor: pointer;\n transition:\n background 0.12s,\n border-color 0.12s,\n color 0.12s,\n opacity 0.12s;\n}\nbutton:disabled {\n opacity: 0.35;\n cursor: default;\n}\nbutton.ghost {\n border-color: var(--line);\n background: var(--bg-1);\n color: var(--text-dim);\n}\nbutton.ghost:not(:disabled):hover {\n border-color: var(--line-strong);\n color: var(--text);\n}\nbutton.ghost.danger:not(:disabled):hover {\n border-color: var(--rose);\n color: var(--rose);\n}\nbutton.primary {\n background: linear-gradient(135deg, var(--accent), var(--accent-deep));\n color: #06201c;\n}\nbutton.primary:not(:disabled):hover {\n filter: brightness(1.1);\n}\nbutton.play {\n border-color: var(--green);\n color: var(--green);\n background: rgba(134, 239, 172, 0.08);\n}\nbutton.play:not(:disabled):hover {\n background: rgba(134, 239, 172, 0.16);\n}\nbutton.play.stop {\n border-color: var(--rose);\n color: var(--rose);\n background: rgba(251, 113, 133, 0.1);\n}\ninput,\nselect,\ntextarea {\n font: inherit;\n font-size: 12.5px;\n color: var(--text);\n background: var(--bg-0);\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n padding: 6px 9px;\n transition: border-color 0.12s;\n min-width: 0;\n}\nselect {\n /*\n * padding cannot move the NATIVE dropdown arrow — the browser pins it to\n * the edge. Draw our own chevron, inset to mirror the left text padding.\n */\n appearance: none;\n padding-right: 30px;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239aa3bd' stroke-width='2.4'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 9px center;\n background-size: 12px;\n}\ninput:focus,\nselect:focus,\ntextarea:focus {\n outline: none;\n border-color: var(--accent-deep);\n}\ntextarea {\n resize: vertical;\n font-size: 12px;\n line-height: 1.5;\n}\ntextarea.invalid {\n border-color: var(--rose);\n background: rgba(251, 113, 133, 0.05);\n}\n\n/* ─── banners ─── */\n#error-banner {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n padding: 8px 10px 8px 14px;\n background: rgba(251, 113, 133, 0.1);\n color: var(--rose);\n border-bottom: 1px solid rgba(251, 113, 133, 0.35);\n max-height: 110px;\n overflow: auto;\n font-family: ui-monospace, Menlo, monospace;\n font-size: 12px;\n}\n#error-text {\n flex: 1;\n white-space: pre-wrap;\n}\n#error-close {\n flex: none;\n padding: 0 6px;\n color: var(--rose);\n opacity: 0.65;\n font-size: 13px;\n line-height: 1.4;\n}\n#error-close:hover {\n opacity: 1;\n}\n#edit-notice {\n padding: 7px 14px;\n background: rgba(147, 197, 253, 0.08);\n color: #93c5fd;\n border-bottom: 1px solid rgba(147, 197, 253, 0.25);\n font-size: 12px;\n}\n#play-notice {\n padding: 7px 14px;\n background: rgba(134, 239, 172, 0.08);\n color: var(--green);\n border-bottom: 1px solid rgba(134, 239, 172, 0.25);\n font-size: 12px;\n}\n\n/* ─── layout ─── */\n/* The editor's root owns the window — on its own page AND mounted over a\n running game, where the host's <body> is some game's and says nothing about\n how tall a percentage is. Fixing it to the viewport gives every pane below a\n definite height in both cases; without it main's percentage height has\n nothing to resolve against, main grows to its CONTENT, and the viewport\n canvas is sized to a scene tree three thousand pixels tall. */\n.incanto-editor-root {\n position: fixed;\n inset: 0;\n z-index: 30;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n background: var(--bg-0);\n color: var(--text);\n font:\n 13px / 1.55 \"Inter\",\n -apple-system,\n \"Segoe UI\",\n system-ui,\n sans-serif;\n -webkit-font-smoothing: antialiased;\n}\nmain {\n display: flex;\n flex: 1;\n min-height: 0;\n}\n#tree-pane {\n width: 256px;\n display: flex;\n flex-direction: column;\n background: var(--bg-1);\n border-right: 1px solid var(--line);\n}\n#inspector-pane {\n width: 336px;\n overflow-y: auto;\n background: var(--bg-1);\n border-left: 1px solid var(--line);\n}\n#viewport-pane {\n flex: 1;\n position: relative;\n background:\n radial-gradient(1200px 500px at 50% -10%, rgba(110, 231, 220, 0.05), transparent), var(--bg-0);\n overflow: hidden;\n}\n#viewport,\n#overlay,\n#play-canvas {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n}\n#overlay {\n cursor: crosshair;\n}\n#play-canvas {\n z-index: 3;\n}\n#hints-dock {\n position: absolute;\n bottom: 12px;\n right: 16px;\n z-index: 4;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n#hints-toggle {\n width: 40px;\n height: 40px;\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n border: 1px solid var(--line-strong);\n background: rgba(16, 19, 29, 0.88);\n color: var(--text-dim);\n backdrop-filter: blur(6px);\n}\n#hints-toggle:hover {\n color: var(--accent);\n border-color: var(--accent-deep);\n}\n#hints-dock.open #hints-toggle {\n color: var(--accent);\n}\n.hints {\n max-width: 0;\n opacity: 0;\n overflow: hidden;\n white-space: nowrap;\n transition:\n max-width 0.22s ease,\n opacity 0.18s ease,\n padding 0.22s ease;\n padding: 5px 0;\n display: flex;\n gap: 14px;\n border-radius: 999px;\n background: rgba(16, 19, 29, 0.85);\n border: 1px solid transparent;\n color: var(--text-faint);\n font-size: 11px;\n pointer-events: none;\n backdrop-filter: blur(6px);\n}\n.hints b {\n color: var(--text-dim);\n font-weight: 600;\n}\n.pane-title {\n padding: 9px 14px 7px;\n font-size: 10.5px;\n font-weight: 700;\n letter-spacing: 1.6px;\n text-transform: uppercase;\n color: var(--text-faint);\n border-bottom: 1px solid var(--line);\n}\n\n/* ─── tree ─── */\n#tree {\n flex: 1;\n overflow-y: auto;\n padding: 8px;\n}\n.tree-row {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 3px 8px 3px 4px;\n border-radius: var(--r-sm);\n cursor: pointer;\n white-space: nowrap;\n overflow: hidden;\n color: var(--text-dim);\n border: 1px solid transparent;\n position: relative;\n}\n.chevron {\n display: inline-flex;\n align-items: center;\n transition: transform 0.12s;\n}\n.chevron.collapsed {\n transform: rotate(-90deg);\n}\n.chevron-legacy {\n flex: none;\n width: 14px;\n text-align: center;\n color: var(--text-faint);\n font-size: 9px;\n cursor: pointer;\n user-select: none;\n}\n.chevron.leaf {\n cursor: default;\n opacity: 0.35;\n}\n.chevron:not(.leaf):hover {\n color: var(--accent);\n}\n.tree-children {\n margin-left: 11px;\n padding-left: 8px;\n border-left: 1px solid var(--line);\n}\n.tree-row.dragging {\n opacity: 0.4;\n}\n.tree-row.drop-into {\n background: rgba(110, 231, 220, 0.14);\n border-color: var(--accent);\n}\n.tree-row.drop-before::before,\n.tree-row.drop-after::after {\n content: \"\";\n position: absolute;\n left: 4px;\n right: 4px;\n height: 2px;\n border-radius: 2px;\n background: var(--accent);\n}\n.tree-row.drop-before::before {\n top: -1px;\n}\n.tree-row.drop-after::after {\n bottom: -1px;\n}\n.tree-row:hover {\n background: var(--bg-2);\n color: var(--text);\n}\n.tree-row.selected {\n background: rgba(110, 231, 220, 0.1);\n border-color: rgba(110, 231, 220, 0.3);\n color: var(--accent);\n}\n.tree-name {\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.tree-icon {\n flex: none;\n display: inline-grid;\n place-items: center;\n width: 17px;\n height: 17px;\n border-radius: 4px;\n cursor: help;\n}\n.tree-icon:hover {\n background: var(--bg-3);\n}\n.cat-core {\n background: rgba(167, 139, 250, 0.15);\n color: var(--violet);\n}\n.cat-2d {\n background: rgba(110, 231, 220, 0.12);\n color: var(--accent);\n}\n.cat-3d {\n background: rgba(251, 191, 36, 0.12);\n color: var(--amber);\n}\n.cat-body {\n background: rgba(134, 239, 172, 0.12);\n color: var(--green);\n}\n.cat-net {\n background: rgba(251, 113, 133, 0.12);\n color: var(--rose);\n}\n.scene-row {\n margin-bottom: 6px;\n color: var(--text-faint);\n}\n.scene-row.selected {\n color: var(--accent);\n}\n#tree-actions {\n display: flex;\n gap: 7px;\n padding: 10px;\n border-top: 1px solid var(--line);\n}\n#add-type {\n flex: 1;\n}\n\n/* ─── inspector ─── */\n#inspector {\n padding: 12px 14px 40px;\n}\n.section-title {\n display: flex;\n align-items: center;\n gap: 7px;\n margin: 16px 0 8px;\n font-size: 11px;\n font-weight: 700;\n letter-spacing: 1.4px;\n text-transform: uppercase;\n color: var(--accent);\n}\n.section-title:first-child {\n margin-top: 2px;\n}\n.section-title .rule {\n flex: 1;\n height: 1px;\n background: var(--line);\n}\n.field {\n display: grid;\n grid-template-columns: 92px 1fr;\n align-items: center;\n gap: 8px;\n margin-bottom: 7px;\n}\n.field > span {\n font-size: 11.5px;\n color: var(--text-dim);\n display: flex;\n align-items: center;\n gap: 5px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.field.wide {\n grid-template-columns: 1fr;\n}\n.field.wide > span {\n margin-bottom: 2px;\n}\n.vector-row {\n display: flex;\n gap: 6px;\n}\n.vector-row input {\n width: 100%;\n}\n.help-btn {\n flex: none;\n width: 15px;\n height: 15px;\n padding: 0;\n border-radius: 50%;\n border: 1px solid var(--line-strong);\n color: var(--text-faint);\n font-size: 10px;\n font-weight: 700;\n justify-content: center;\n}\n.help-btn:hover {\n border-color: var(--accent);\n color: var(--accent);\n}\n.chips {\n display: flex;\n flex-wrap: wrap;\n gap: 5px;\n padding: 5px 7px;\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n background: var(--bg-0);\n cursor: text;\n}\n.chip {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 1px 8px;\n border-radius: 999px;\n background: rgba(110, 231, 220, 0.12);\n color: var(--accent);\n font-size: 11.5px;\n}\n.chip button {\n padding: 0;\n font-size: 12px;\n color: inherit;\n opacity: 0.7;\n}\n.chips input {\n flex: 1;\n min-width: 70px;\n border: none;\n background: transparent;\n padding: 2px;\n}\n.chips input:focus {\n outline: none;\n}\n.subcard {\n border: 1px solid var(--line);\n border-radius: var(--r-md);\n background: var(--bg-2);\n padding: 10px;\n margin-bottom: 10px;\n}\n.subcard .field {\n grid-template-columns: 78px 1fr;\n}\n.subcard-head {\n display: flex;\n align-items: center;\n gap: 7px;\n margin-bottom: 8px;\n font-size: 11.5px;\n font-weight: 600;\n color: var(--text-dim);\n}\n.subcard-head .spacer {\n flex: 1;\n}\n.linklike {\n padding: 2px 6px;\n font-size: 11px;\n color: var(--accent);\n font-weight: 600;\n}\n.linklike:hover {\n text-decoration: underline;\n}\n.muted-note {\n font-size: 11px;\n color: var(--text-faint);\n margin: -2px 0 8px;\n}\n\n/* ─── asset picker ─── */\n.asset-control {\n display: flex;\n gap: 6px;\n align-items: stretch;\n}\n.asset-control input {\n flex: 1;\n min-width: 0;\n}\n.asset-toggle {\n flex: none;\n width: 26px;\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n background: var(--bg-1);\n color: var(--text-dim);\n font-size: 11px;\n}\n.asset-toggle:hover {\n border-color: var(--accent);\n color: var(--accent);\n}\n.asset-panel {\n margin-top: 6px;\n border: 1px solid var(--line-strong);\n border-radius: var(--r-sm);\n background: var(--bg-0);\n padding: 6px;\n}\n.asset-search {\n width: 100%;\n margin-bottom: 6px;\n}\n.asset-options {\n display: flex;\n flex-direction: column;\n gap: 3px;\n max-height: 220px;\n overflow-y: auto;\n}\nbutton.asset-option {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 1px;\n padding: 5px 8px;\n text-align: left;\n border: 1px solid transparent;\n border-radius: var(--r-sm);\n background: var(--bg-2);\n color: var(--text);\n width: 100%;\n}\nbutton.asset-option:hover {\n border-color: var(--accent);\n background: var(--bg-3);\n}\nbutton.asset-option strong {\n font-size: 11.5px;\n font-weight: 600;\n}\nbutton.asset-option small {\n font-size: 10px;\n color: var(--text-faint);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 100%;\n}\n.asset-empty {\n font-size: 11px;\n color: var(--text-faint);\n padding: 4px 8px;\n}\n.asset-note {\n margin-top: 5px;\n}\n.varieties {\n cursor: default;\n}\n.variety-opt {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n font-size: 11.5px;\n color: var(--text-dim);\n cursor: pointer;\n}\n.variety-opt input[type=\"checkbox\"] {\n width: auto;\n}\n\n/* ─── popover (help) ─── */\n#popover {\n position: fixed;\n z-index: 50;\n width: 300px;\n background: var(--bg-3);\n border: 1px solid var(--line-strong);\n border-radius: var(--r-md);\n box-shadow: var(--shadow);\n padding: 12px 14px;\n font-size: 12px;\n color: var(--text-dim);\n}\n#popover h4 {\n margin: 0 0 6px;\n font-size: 12.5px;\n color: var(--text);\n}\n#popover code {\n background: var(--bg-0);\n padding: 1px 5px;\n border-radius: 4px;\n font-size: 11px;\n color: var(--accent);\n}\n#popover pre {\n margin: 8px 0 0;\n padding: 8px 10px;\n background: var(--bg-0);\n border-radius: var(--r-sm);\n font-size: 11px;\n line-height: 1.5;\n overflow-x: auto;\n color: var(--text-dim);\n}\n#popover .pop-actions {\n margin-top: 8px;\n display: flex;\n justify-content: flex-end;\n}\n\n/* ─── picker ─── */\n#picker {\n position: fixed;\n inset: 0;\n background: rgba(7, 9, 14, 0.78);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 40;\n backdrop-filter: blur(4px);\n}\n#picker[hidden] {\n display: none;\n}\n#picker-card {\n width: 460px;\n max-height: 72vh;\n background: var(--bg-2);\n border: 1px solid var(--line-strong);\n border-radius: 14px;\n box-shadow: var(--shadow);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n#picker-list {\n flex: 1;\n overflow-y: auto;\n padding: 6px;\n min-height: 120px;\n}\n#picker-list .tree-row {\n padding: 9px 12px;\n font-family: ui-monospace, Menlo, monospace;\n font-size: 12.5px;\n}\n#picker-find {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n border-bottom: 1px solid var(--line);\n}\n#picker-search {\n flex: 1;\n}\n#picker-count {\n font-size: 11px;\n color: var(--text-faint);\n font-variant-numeric: tabular-nums;\n}\n/* one row of the project explorer: caret, name, and the facts, right-aligned */\n.scene-row {\n display: flex;\n align-items: center;\n gap: 7px;\n padding: 6px 10px 6px 6px;\n border-radius: 7px;\n cursor: pointer;\n font-size: 12.5px;\n user-select: none;\n}\n.scene-row:hover {\n background: var(--bg-3);\n}\n.scene-row.active {\n background: var(--bg-3);\n outline: 1px solid var(--line-strong);\n}\n.scene-name {\n font-family: ui-monospace, Menlo, monospace;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.scene-folder .scene-name {\n color: var(--text-dim);\n}\n.scene-row.current .scene-name {\n color: var(--accent);\n}\n.scene-caret {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 13px;\n flex: none;\n color: var(--text-faint);\n font-size: 9px;\n line-height: 1;\n}\n.scene-folder .scene-caret {\n color: var(--text-dim);\n}\n.scene-meta {\n margin-left: auto;\n padding-left: 10px;\n flex: none;\n font-size: 10.5px;\n color: var(--text-faint);\n font-variant-numeric: tabular-nums;\n}\n/* a JSON that is not a scene: still there, still clickable, visibly not one */\n.scene-row.not-scene .scene-name,\n.scene-row.not-scene .scene-meta {\n color: var(--text-faint);\n}\n.scene-row.not-scene .scene-caret {\n opacity: 0.4;\n}\n.scene-empty {\n padding: 22px 12px;\n text-align: center;\n color: var(--text-faint);\n font-size: 12px;\n}\n#picker-new {\n display: flex;\n gap: 8px;\n padding: 12px;\n border-top: 1px solid var(--line);\n}\n#picker-path {\n flex: 1;\n font-family: ui-monospace, Menlo, monospace;\n}\n\n/* ─── scrollbars ─── */\n::-webkit-scrollbar {\n width: 9px;\n height: 9px;\n}\n::-webkit-scrollbar-thumb {\n background: var(--line-strong);\n border-radius: 99px;\n border: 2px solid var(--bg-1);\n}\n::-webkit-scrollbar-track {\n background: transparent;\n}\n\nbody.playing #tree-pane,\nbody.playing #inspector-pane {\n pointer-events: none;\n opacity: 0.45;\n filter: saturate(0.6);\n transition: opacity 0.2s;\n}\n\n.rename-input {\n flex: 1;\n min-width: 0;\n padding: 1px 6px;\n font-size: 12.5px;\n}\n.balloon {\n position: fixed;\n z-index: 60;\n max-width: 230px;\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 8px 11px;\n background: var(--bg-3);\n border: 1px solid var(--line-strong);\n border-radius: var(--r-md);\n box-shadow: var(--shadow);\n font-size: 11.5px;\n color: var(--text-dim);\n}\n.balloon .balloon-title {\n color: var(--accent);\n font-size: 12px;\n font-weight: 700;\n}\n.context-menu {\n position: fixed;\n z-index: 60;\n min-width: 190px;\n padding: 5px;\n background: var(--bg-3);\n border: 1px solid var(--line-strong);\n border-radius: var(--r-md);\n box-shadow: var(--shadow);\n display: flex;\n flex-direction: column;\n}\n.menu-item {\n justify-content: space-between;\n padding: 6px 10px;\n border-radius: var(--r-sm);\n font-weight: 500;\n color: var(--text);\n}\n.menu-item:not(:disabled):hover {\n background: var(--bg-2);\n}\n.menu-item.danger:not(:disabled):hover {\n color: var(--rose);\n}\n.menu-item kbd {\n font-size: 10px;\n color: var(--text-faint);\n font-family: inherit;\n}\n.menu-divider {\n height: 1px;\n margin: 4px 6px;\n background: var(--line);\n}\n/* The play menu is a choice, not a command list: each row carries a label and\n the sentence that says what actually happens, stacked. */\n.play-menu {\n width: 290px;\n gap: 2px;\n}\n.play-menu-item {\n flex-direction: column;\n align-items: flex-start;\n gap: 2px;\n padding: 8px 10px;\n text-align: left;\n}\n.play-menu-hint {\n font-size: 11px;\n font-weight: 400;\n line-height: 1.35;\n color: var(--text-faint);\n}\n\n.hints[hidden] {\n display: none;\n}\n#hints-dock.open .hints:not([hidden]) {\n max-width: 1100px;\n opacity: 1;\n padding: 5px 14px;\n border-color: var(--line);\n}\nbody.playing #hints-dock {\n display: none;\n}\n\n#gameview-btn {\n position: absolute;\n top: 104px;\n right: 18px;\n z-index: 4;\n font-size: 11.5px;\n padding: 4px 10px;\n backdrop-filter: blur(6px);\n background: rgba(16, 19, 29, 0.8);\n}\n\n.field input[type=\"checkbox\"] {\n justify-self: start;\n width: 15px;\n height: 15px;\n accent-color: var(--accent-deep);\n cursor: pointer;\n}\n\n.picker-title {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n#picker-close {\n padding: 0 4px;\n font-size: 12px;\n color: var(--text-faint);\n border: none;\n background: none;\n}\n#picker-close:hover {\n color: var(--text);\n}\n\n.uid-row {\n display: flex;\n gap: 6px;\n}\n.uid-row input {\n flex: 1;\n min-width: 0;\n font-size: 11.5px;\n}\n.uid-row .ghost {\n padding: 4px 8px;\n}\n#confirm {\n position: fixed;\n inset: 0;\n background: rgba(7, 9, 14, 0.78);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 70;\n backdrop-filter: blur(4px);\n}\n#confirm[hidden] {\n display: none;\n}\n#confirm-card {\n width: 480px;\n max-height: 70vh;\n display: flex;\n flex-direction: column;\n background: var(--bg-2);\n border: 1px solid var(--line-strong);\n border-radius: 14px;\n box-shadow: var(--shadow);\n overflow: hidden;\n}\n#confirm-body {\n padding: 14px;\n color: var(--text-dim);\n font-size: 12.5px;\n overflow-y: auto;\n}\n#confirm-list:empty {\n display: none; /* the group-delete confirm has no reference list */\n}\n#confirm-list {\n margin: 10px 0 0;\n padding: 10px 12px;\n background: var(--bg-0);\n border-radius: var(--r-sm);\n font-family: ui-monospace, Menlo, monospace;\n font-size: 11.5px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n#confirm-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 14px;\n border-top: 1px solid var(--line);\n}\n#confirm-delete {\n border-color: var(--rose);\n color: var(--rose);\n background: rgba(251, 113, 133, 0.08);\n}\n#confirm-delete:hover {\n background: rgba(251, 113, 133, 0.16);\n}\n\n.color-row {\n display: flex;\n gap: 6px;\n align-items: center;\n}\n.color-row input[type=\"color\"] {\n width: 30px;\n height: 26px;\n padding: 2px;\n cursor: pointer;\n}\n.color-row input[type=\"text\"] {\n flex: 1;\n min-width: 0;\n font-size: 11.5px;\n}\n.slider-row {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n.slider-row input[type=\"range\"] {\n flex: 1;\n accent-color: var(--accent-deep);\n padding: 0;\n border: none;\n background: transparent;\n}\n.slider-row input[type=\"number\"] {\n width: 64px;\n}\n.asset-row {\n display: flex;\n align-items: center;\n gap: 7px;\n padding: 5px 8px;\n border-radius: var(--r-sm);\n cursor: pointer;\n}\n.asset-row:hover,\n.asset-row.open {\n background: var(--bg-3);\n}\n.asset-key {\n color: var(--accent);\n}\n.asset-url {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--text-faint);\n font-size: 11px;\n font-family: ui-monospace, Menlo, monospace;\n}\n.danger-link {\n color: var(--text-faint);\n}\n.danger-link:hover {\n color: var(--rose);\n}\n.asset-editor {\n margin: 2px 0 10px;\n padding: 10px;\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n background: var(--bg-0);\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.asset-editor .field {\n grid-template-columns: 52px 1fr;\n margin-bottom: 4px;\n}\n.meta-row {\n display: grid;\n grid-template-columns: 1fr 1fr 24px;\n gap: 6px;\n align-items: center;\n}\n.meta-row input {\n font-size: 11.5px;\n padding: 4px 7px;\n}\n\n#docs {\n position: fixed;\n inset: 0;\n background: rgba(7, 9, 14, 0.8);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 60;\n backdrop-filter: blur(5px);\n}\n#docs[hidden] {\n display: none;\n}\n#docs-card {\n width: min(920px, 92vw);\n height: min(680px, 88vh);\n background: var(--bg-2);\n border: 1px solid var(--line-strong);\n border-radius: 14px;\n box-shadow: var(--shadow);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n#docs-layout {\n display: flex;\n flex: 1;\n min-height: 0;\n}\n#docs-tabs {\n width: 168px;\n border-right: 1px solid var(--line);\n padding: 10px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.docs-tab {\n justify-content: flex-start;\n padding: 7px 12px;\n border-radius: var(--r-sm);\n color: var(--text-dim);\n font-weight: 500;\n}\n.docs-tab:hover {\n background: var(--bg-3);\n color: var(--text);\n}\n.docs-tab.active {\n background: rgba(110, 231, 220, 0.1);\n color: var(--accent);\n font-weight: 700;\n}\n#docs-body {\n flex: 1;\n overflow-y: auto;\n padding: 18px 24px 40px;\n}\n#docs-body h2 {\n margin: 0 0 6px;\n font-size: 18px;\n}\n#docs-body h3 {\n margin: 18px 0 4px;\n font-size: 13.5px;\n color: var(--accent);\n}\n#docs-body p {\n margin: 4px 0 10px;\n color: var(--text-dim);\n line-height: 1.7;\n font-size: 13px;\n}\n.docs-intro {\n padding: 10px 14px;\n background: var(--bg-1);\n border: 1px solid var(--line);\n border-radius: var(--r-md);\n}\n.docs-node {\n border: 1px solid var(--line);\n border-radius: var(--r-md);\n margin-bottom: 8px;\n overflow: hidden;\n}\n.docs-node.open {\n border-color: var(--line-strong);\n}\n.docs-node-head {\n width: 100%;\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 9px 12px;\n border-radius: 0;\n text-align: left;\n}\n.docs-node-head:hover {\n background: var(--bg-3);\n}\n.docs-node-head strong {\n font-size: 13px;\n}\n.docs-summary {\n color: var(--text-faint);\n font-size: 12px;\n font-weight: 400;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.docs-detail {\n padding: 4px 14px 12px;\n border-top: 1px solid var(--line);\n background: var(--bg-1);\n}\n.docs-props {\n width: 100%;\n border-collapse: collapse;\n margin-top: 8px;\n font-size: 11.5px;\n}\n.docs-props th {\n text-align: left;\n color: var(--text-faint);\n font-weight: 600;\n padding: 4px 8px;\n border-bottom: 1px solid var(--line);\n}\n.docs-props td {\n padding: 3px 8px;\n border-bottom: 1px solid var(--line);\n color: var(--text-dim);\n}\n\n#mode-toolbar {\n position: absolute;\n top: 12px;\n left: 12px;\n z-index: 4;\n display: flex;\n gap: 4px;\n padding: 4px;\n border-radius: var(--r-md);\n background: rgba(16, 19, 29, 0.85);\n border: 1px solid var(--line);\n backdrop-filter: blur(6px);\n}\n.tool {\n width: 30px;\n height: 28px;\n justify-content: center;\n padding: 0;\n border-radius: var(--r-sm);\n color: var(--text-faint);\n}\n.tool:hover {\n color: var(--text);\n background: var(--bg-3);\n}\n.tool.active {\n background: rgba(110, 231, 220, 0.14);\n color: var(--accent);\n}\n\n.lang-menu {\n min-width: 130px;\n}\n.lang-check {\n color: var(--accent);\n font-weight: 700;\n}\n\n.explorer-section {\n display: flex;\n align-items: center;\n justify-content: space-between;\n border-top: 1px solid var(--line);\n margin-top: 4px;\n}\n.explorer-section .ghost {\n padding: 1px 8px;\n}\n#asset-tree {\n padding: 2px 8px 10px;\n overflow-y: auto;\n max-height: 30%;\n}\n.explorer-empty {\n padding: 4px 10px;\n font-size: 11px;\n}\n.asset-row .asset-key {\n color: var(--accent);\n font-family: ui-monospace, Menlo, monospace;\n}\n.asset-icon-texture {\n color: #f0abfc;\n}\n.asset-icon-spritesheet {\n color: #fbbf24;\n}\n.asset-icon-model {\n color: #7aa2ff;\n}\n.asset-icon-animation {\n color: #86efac;\n}\n.uid-value {\n display: flex;\n align-items: center;\n gap: 7px;\n min-width: 0;\n}\n.uid-value code {\n font-family: ui-monospace, Menlo, monospace;\n font-size: 11px;\n color: var(--text-dim);\n letter-spacing: 0.3px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.uid-copy {\n padding: 3px 5px;\n border: none;\n background: none;\n border-radius: var(--r-sm);\n color: var(--text-faint);\n line-height: 0;\n}\n.uid-copy:hover {\n color: var(--text);\n background: var(--bg-3);\n}\n.uid-copy.copied {\n color: var(--accent);\n font-size: 10px;\n line-height: 1;\n}\n\n.section-toggle {\n width: 100%;\n height: 30px; /* IDENTICAL header height for ASSETS and SCENE */\n box-sizing: border-box;\n padding-top: 0;\n padding-bottom: 0;\n display: flex;\n align-items: center;\n justify-content: flex-start;\n gap: 6px;\n text-align: left;\n cursor: pointer;\n background: var(--bg-1);\n border: none;\n border-top: 1px solid var(--line-strong);\n border-bottom: 1px solid var(--line);\n border-radius: 0;\n}\n.section-toggle:hover {\n color: var(--text);\n}\n.section-toggle .chev {\n display: inline-flex;\n transition: transform 0.12s;\n color: var(--text-dim);\n}\n.section-toggle.collapsed .chev {\n transform: rotate(-90deg);\n}\n.section-add {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 24px;\n height: 20px;\n padding: 0 6px;\n font-size: 13px;\n color: var(--text-dim);\n border: 1px solid var(--line-strong);\n border-radius: var(--r-sm);\n background: var(--bg-2);\n}\n.section-add:hover {\n background: var(--bg-3);\n color: var(--accent);\n border-color: var(--accent-deep);\n}\n[data-body][hidden],\naside#tree-pane #scene-body[hidden] {\n /* outranks the #scene-body flex rule — [hidden] must always win */\n display: none;\n}\n#scene-body {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n}\n.asset-folder {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 8px;\n color: var(--text-dim);\n cursor: pointer;\n border-radius: var(--r-sm);\n}\n.asset-folder:hover {\n background: var(--bg-3);\n}\n.asset-folder .chev {\n display: inline-flex;\n color: var(--text-dim);\n transition: transform 0.12s;\n}\n.asset-folder.collapsed .chev {\n transform: rotate(-90deg);\n}\n.asset-folder svg {\n color: #e7c66a;\n}\n.asset-row.grouped {\n margin-left: 18px;\n}\n\n.asset-folder .count {\n margin-left: auto;\n color: var(--text-faint);\n font-size: 10.5px;\n}\n.asset-folder.selected {\n background: rgba(110, 231, 220, 0.08);\n color: var(--accent);\n}\n.asset-folder.drop-target,\n#asset-tree.drop-target {\n outline: 1.5px dashed var(--accent);\n outline-offset: -2px;\n border-radius: var(--r-sm);\n}\n.asset-row[draggable=\"true\"] {\n cursor: grab;\n}\n\nbody.playing #mode-toolbar,\nbody.playing #gameview-btn {\n display: none; /* gizmo tools and the free-cam escape make no sense mid-play */\n}\n\n.tool-divider {\n width: 1px;\n height: 18px;\n background: var(--line);\n margin: 0 2px;\n align-self: center;\n}\n\n/* ─── generate dialog ─── */\n#generate {\n position: fixed;\n inset: 0;\n background: rgba(7, 9, 14, 0.78);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 70;\n backdrop-filter: blur(4px);\n}\n#generate[hidden] {\n display: none;\n}\n#generate-card {\n width: 420px;\n max-height: 78vh;\n display: flex;\n flex-direction: column;\n background: var(--bg-2);\n border: 1px solid var(--line-strong);\n border-radius: 14px;\n box-shadow: var(--shadow);\n overflow: hidden;\n}\n#generate-body {\n padding: 14px;\n overflow-y: auto;\n}\n#generate-body .gen-hint {\n margin: 0 0 12px;\n font-size: 11.5px;\n color: var(--text-faint);\n}\n#generate-body .gen-desc {\n margin: 2px 0 12px;\n font-size: 11.5px;\n color: var(--text-dim);\n}\n#generate-params {\n padding-top: 2px;\n border-top: 1px solid var(--line);\n}\n#generate-params .field:first-child {\n margin-top: 10px;\n}\n.gen-seed-row {\n display: flex;\n gap: 6px;\n}\n.gen-seed-row input {\n flex: 1;\n min-width: 0;\n}\n.gen-seed-row .ghost {\n padding: 4px 9px;\n}\n#generate-actions {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 14px;\n border-top: 1px solid var(--line);\n}\n#generate-status {\n margin-right: auto;\n font-size: 11px;\n color: var(--rose);\n}\n\n/* ---- scene constants + the prop \"bind to a constant\" picker ---- */\n.const-picker {\n flex: none;\n width: 30px;\n margin-left: 6px;\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n background: var(--bg-1);\n color: var(--text-dim);\n font-size: 11px;\n}\n.const-picker:hover {\n border-color: var(--accent);\n color: var(--accent);\n}\n.field.const-bound > span {\n color: var(--accent);\n}\n.const-row {\n display: flex;\n gap: 6px;\n align-items: stretch;\n}\n.const-row .field {\n flex: 1;\n min-width: 0;\n}\n.const-del {\n flex: none;\n width: 26px;\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n background: var(--bg-1);\n color: var(--text-dim);\n font-size: 11px;\n}\n.const-del:hover {\n border-color: var(--rose);\n color: var(--rose);\n}\n.const-add {\n display: flex;\n gap: 6px;\n align-items: stretch;\n margin-top: 6px;\n}\n.const-add input {\n flex: 1;\n min-width: 0;\n}\n\n/* ---- TileMap2D paint brush ---- */\n.tile-paint {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.paint-toggle {\n cursor: pointer;\n border: 1px solid var(--border, #444);\n border-radius: 6px;\n background: transparent;\n color: inherit;\n padding: 6px 10px;\n font: inherit;\n}\n.paint-toggle.on {\n background: #2e6b2e;\n border-color: #4a9e4a;\n color: #fff;\n}\n.paint-palette {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n align-items: center;\n}\n.paint-chip {\n cursor: pointer;\n width: 26px;\n height: 26px;\n border-radius: 5px;\n border: 1px solid var(--border, #444);\n background: transparent;\n color: inherit;\n font: 600 13px / 1 monospace;\n}\n.paint-chip.on {\n background: #3a5a8c;\n border-color: #6a9ae0;\n color: #fff;\n}\n.paint-brush-input {\n width: 32px;\n text-align: center;\n font: 600 13px / 1 monospace;\n background: transparent;\n color: inherit;\n border: 1px solid var(--border, #444);\n border-radius: 5px;\n padding: 4px;\n}\n.paint-hint {\n font-size: 11px;\n opacity: 0.6;\n}\n\n/* ─── agent8 asset library ─── */\n.asset-lib {\n flex: none;\n width: 30px;\n padding: 0;\n justify-content: center;\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n background: var(--bg-1);\n font-size: 13px;\n line-height: 1;\n}\n.asset-lib:hover {\n border-color: var(--accent);\n}\n.lib-backdrop {\n position: fixed;\n inset: 0;\n z-index: 70;\n display: grid;\n place-items: center;\n background: rgba(4, 6, 12, 0.72);\n backdrop-filter: blur(3px);\n}\n.lib-dialog {\n display: flex;\n flex-direction: column;\n width: min(1180px, 94vw);\n height: min(760px, 88vh);\n background: var(--bg-1);\n border: 1px solid var(--line-strong);\n border-radius: var(--r-md);\n box-shadow: var(--shadow);\n overflow: hidden;\n}\n.lib-head {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n border-bottom: 1px solid var(--line);\n background: var(--bg-2);\n}\n.lib-head strong {\n font-size: 13px;\n}\n.lib-sub {\n color: var(--accent);\n font-size: 12px;\n font-family: ui-monospace, Menlo, monospace;\n}\n.lib-search {\n margin-left: auto;\n width: 260px;\n}\n.lib-body {\n flex: 1;\n display: grid;\n grid-template-columns: 190px 1fr 320px;\n min-height: 0;\n}\n.lib-shelves {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 8px 6px;\n overflow-y: auto;\n border-right: 1px solid var(--line);\n background: var(--bg-1);\n}\n.lib-shelf {\n justify-content: flex-start;\n padding: 6px 10px;\n border-radius: var(--r-sm);\n color: var(--text-dim);\n font-weight: 500;\n text-align: left;\n}\n.lib-shelf:hover {\n background: var(--bg-2);\n color: var(--text);\n}\n.lib-shelf.active {\n background: rgba(110, 231, 220, 0.12);\n color: var(--accent);\n}\n.lib-shelf.crumb {\n color: var(--text-faint);\n font-size: 11.5px;\n}\n.lib-shelf-count {\n margin-left: auto;\n color: var(--text-faint);\n font-size: 10px;\n font-family: ui-monospace, Menlo, monospace;\n}\n.lib-shelf-head {\n margin: 8px 0 2px;\n padding: 0 10px;\n color: var(--text-faint);\n font-size: 10px;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n}\n.lib-grid-pane {\n display: flex;\n flex-direction: column;\n min-width: 0;\n background: var(--bg-0);\n}\n.lib-status {\n padding: 7px 12px;\n color: var(--text-faint);\n font-size: 11.5px;\n border-bottom: 1px solid var(--line);\n}\n.lib-grid {\n flex: 1;\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(112px, 1fr));\n gap: 10px;\n align-content: start;\n padding: 12px;\n overflow-y: auto;\n}\n.lib-card {\n display: flex;\n flex-direction: column;\n gap: 5px;\n min-width: 0; /* grid item: without this the name pushes the card wider */\n padding: 6px;\n overflow: hidden;\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n background: var(--bg-1);\n font-weight: 500;\n}\n.lib-card:hover {\n border-color: var(--line-strong);\n}\n.lib-card.active {\n border-color: var(--accent);\n background: rgba(110, 231, 220, 0.08);\n}\n.lib-thumb {\n display: grid;\n place-items: center;\n aspect-ratio: 1;\n border-radius: 4px;\n background: repeating-conic-gradient(var(--bg-3) 0% 25%, var(--bg-2) 0% 50%) 50% / 16px 16px;\n overflow: hidden;\n}\n.lib-thumb img {\n width: 100%;\n height: 100%;\n object-fit: contain;\n}\n.lib-glyph {\n width: 30px;\n height: 30px;\n color: var(--text-faint);\n}\n.lib-badge {\n position: absolute;\n right: 4px;\n bottom: 4px;\n padding: 1px 5px;\n border-radius: 999px;\n background: rgba(110, 231, 220, 0.16);\n color: var(--accent);\n font-size: 9px;\n font-style: normal;\n letter-spacing: 0.03em;\n}\n.lib-thumb {\n position: relative;\n}\n.lib-card-name {\n max-width: 100%;\n overflow: hidden;\n color: var(--text-dim);\n font-size: 11px;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.lib-more {\n margin: 0 12px 12px;\n}\n.lib-detail {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 12px;\n overflow-y: auto;\n border-left: 1px solid var(--line);\n background: var(--bg-1);\n}\n.lib-stage {\n display: grid;\n place-items: center;\n aspect-ratio: 1;\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n background: repeating-conic-gradient(var(--bg-3) 0% 25%, var(--bg-2) 0% 50%) 50% / 18px 18px;\n overflow: hidden;\n}\n.lib-stage img {\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n}\n.lib-preview3d,\n.lib-preview-canvas {\n width: 100%;\n height: 100%;\n display: block;\n cursor: grab;\n}\n.lib-preview-canvas:active {\n cursor: grabbing;\n}\n.lib-name {\n margin: 0;\n font-size: 13px;\n word-break: break-word;\n}\n.lib-desc {\n margin: 0;\n color: var(--text-dim);\n font-size: 12px;\n line-height: 1.5;\n}\n.lib-note {\n color: var(--accent);\n font-size: 11.5px;\n}\n.lib-tags {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n.lib-tag {\n padding: 2px 7px;\n border-radius: 999px;\n background: var(--bg-3);\n color: var(--text-faint);\n font-size: 10.5px;\n}\n.lib-facts {\n display: grid;\n grid-template-columns: 74px 1fr;\n gap: 3px 8px;\n margin: 0;\n font-size: 11.5px;\n}\n.lib-facts dt {\n color: var(--text-faint);\n}\n.lib-facts dd {\n margin: 0;\n color: var(--text-dim);\n font-family: ui-monospace, Menlo, monospace;\n}\n.lib-url {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.lib-url code {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n padding: 5px 7px;\n border-radius: var(--r-sm);\n background: var(--bg-0);\n color: var(--text-faint);\n font-size: 10.5px;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.lib-actions {\n display: flex;\n gap: 6px;\n margin-top: auto;\n}\n.lib-actions button {\n flex: 1;\n justify-content: center;\n}\n.lib-empty,\n.lib-error {\n grid-column: 1 / -1;\n padding: 24px 12px;\n color: var(--text-faint);\n font-size: 12px;\n text-align: center;\n}\n.lib-error {\n color: var(--rose);\n}\n.lib-token {\n grid-column: 1 / -1;\n max-width: 520px;\n margin: 24px auto;\n padding: 16px;\n border: 1px solid var(--line-strong);\n border-radius: var(--r-md);\n background: var(--bg-1);\n}\n.lib-token-line {\n margin: 0 0 8px;\n font-size: 12.5px;\n}\n.lib-token-how {\n color: var(--text-faint);\n font-size: 11.5px;\n line-height: 1.6;\n}\n.lib-token-row {\n display: flex;\n gap: 6px;\n}\n.lib-token-row input {\n flex: 1;\n}\n\n/* ─── animation card ─── */\n.anim-card .slider-row {\n width: 100%;\n}\n.anim-upper {\n margin-top: 8px;\n padding-top: 8px;\n border-top: 1px solid var(--line);\n}\n.anim-upper > summary {\n color: var(--text-faint);\n font-size: 11.5px;\n cursor: pointer;\n list-style: none;\n}\n.anim-upper > summary::before {\n content: \"▸ \";\n}\n.anim-upper[open] > summary::before {\n content: \"▾ \";\n}\n.anim-upper > summary:hover {\n color: var(--text-dim);\n}\n\n/* ─── connections ─── */\n/* Signal wiring on the selected node. Dense on purpose: a row is four fields,\n and a node with a dozen connections still has to fit the inspector column. */\n.connections {\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding: 2px 0 6px;\n}\n.conn-group {\n font-size: 10px;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n opacity: 0.55;\n margin-top: 4px;\n}\n.conn-row {\n display: grid;\n grid-template-columns: 1fr 10px 1fr 1fr 18px;\n gap: 3px;\n align-items: center;\n}\n.conn-arrow {\n text-align: center;\n opacity: 0.5;\n font-size: 11px;\n}\n.conn-select,\n.conn-handler {\n min-width: 0;\n font-size: 11px;\n padding: 2px 4px;\n}\n.conn-select.dangling {\n border-color: #f87171;\n color: #f87171;\n}\n.conn-warn {\n font-size: 10px;\n color: #f87171;\n padding: 1px 0 3px;\n line-height: 1.35;\n}\n.conn-remove {\n border: 0;\n background: none;\n color: inherit;\n opacity: 0.4;\n cursor: pointer;\n font-size: 11px;\n padding: 0;\n}\n.conn-remove:hover {\n opacity: 1;\n color: #f87171;\n}\n.conn-add {\n padding-top: 2px;\n}\n.conn-add button {\n font-size: 11px;\n padding: 2px 8px;\n cursor: pointer;\n}\n.conn-add button:disabled {\n opacity: 0.4;\n cursor: default;\n}\n", Yr = new Map(vt.flatMap((e) => e.nodes.map((e) => [e.type, e.summary]))), Xr = /* @__PURE__ */ new Set(), Zr = null, Qr = null, $r = null;
4128
- function ei(e) {
4129
- Qr = e;
4130
- }
4131
- function ti(e) {
4132
- Zr = e;
4133
- }
4150
+ var Xr = "\n/* ─── incanto editor · design system ──────────────────────────────────────── */\n:root {\n --bg-0: #0b0d14;\n --bg-1: #10131d;\n --bg-2: #161a27;\n --bg-3: #1d2231;\n --line: #262c3e;\n --line-strong: #343c54;\n --text: #e2e6f0;\n --text-dim: #9aa3bd;\n --text-faint: #5d6680;\n --accent: #6ee7dc;\n --accent-deep: #14b8a6;\n --violet: #a78bfa;\n --amber: #fbbf24;\n --rose: #fb7185;\n --green: #86efac;\n --shadow: 0 12px 40px rgba(0, 0, 0, 0.55);\n --r-sm: 6px;\n --r-md: 10px;\n color-scheme: dark;\n}\n* {\n box-sizing: border-box;\n}\n/* A button rule of \"display: inline-flex\" outranks the UA's [hidden] rule, so\n a button hidden from JS stays on screen. Say it once, loudly, here. */\n[hidden] {\n display: none !important;\n}\nhtml,\nbody {\n margin: 0;\n height: 100%;\n overflow: hidden;\n background: var(--bg-0);\n color: var(--text);\n font:\n 13px / 1.55 \"Inter\",\n -apple-system,\n \"Segoe UI\",\n system-ui,\n sans-serif;\n -webkit-font-smoothing: antialiased;\n}\ncode,\ntextarea,\n.mono {\n font-family: ui-monospace, \"SF Mono\", Menlo, monospace;\n}\n\n/* ─── top bar ─── */\n#topbar {\n display: flex;\n flex: none;\n align-items: center;\n gap: 10px;\n height: 46px;\n padding: 0 14px;\n background: linear-gradient(to bottom, var(--bg-2), var(--bg-1));\n border-bottom: 1px solid var(--line);\n}\n.brand {\n display: flex;\n align-items: baseline;\n gap: 7px;\n margin-right: 6px;\n}\n.brand-mark {\n display: inline-grid;\n place-items: center;\n width: 22px;\n height: 22px;\n border-radius: 6px;\n background: linear-gradient(135deg, var(--accent), var(--accent-deep));\n color: #07211d;\n font-weight: 800;\n font-size: 11px;\n align-self: center;\n}\n.brand strong {\n font-weight: 700;\n letter-spacing: 0.2px;\n}\n.brand-sub {\n color: var(--text-faint);\n font-size: 12px;\n}\n#file-chip {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n border: 1px solid var(--line);\n border-radius: 999px;\n background: var(--bg-1);\n color: var(--text-dim);\n font-size: 12px;\n max-width: 320px;\n}\n#file-path {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.pill {\n padding: 2px 9px;\n border-radius: 999px;\n background: var(--bg-3);\n color: var(--text-faint);\n font-size: 11px;\n font-family: ui-monospace, Menlo, monospace;\n}\n.spacer {\n flex: 1;\n}\n\n/* ─── buttons & controls ─── */\nbutton {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font: inherit;\n font-size: 12.5px;\n font-weight: 600;\n padding: 6px 12px;\n border-radius: var(--r-sm);\n border: 1px solid transparent;\n background: transparent;\n color: var(--text);\n cursor: pointer;\n transition:\n background 0.12s,\n border-color 0.12s,\n color 0.12s,\n opacity 0.12s;\n}\nbutton:disabled {\n opacity: 0.35;\n cursor: default;\n}\nbutton.ghost {\n border-color: var(--line);\n background: var(--bg-1);\n color: var(--text-dim);\n}\nbutton.ghost:not(:disabled):hover {\n border-color: var(--line-strong);\n color: var(--text);\n}\nbutton.ghost.danger:not(:disabled):hover {\n border-color: var(--rose);\n color: var(--rose);\n}\nbutton.primary {\n background: linear-gradient(135deg, var(--accent), var(--accent-deep));\n color: #06201c;\n}\nbutton.primary:not(:disabled):hover {\n filter: brightness(1.1);\n}\nbutton.play {\n border-color: var(--green);\n color: var(--green);\n background: rgba(134, 239, 172, 0.08);\n}\nbutton.play:not(:disabled):hover {\n background: rgba(134, 239, 172, 0.16);\n}\nbutton.play.stop {\n border-color: var(--rose);\n color: var(--rose);\n background: rgba(251, 113, 133, 0.1);\n}\ninput,\nselect,\ntextarea {\n font: inherit;\n font-size: 12.5px;\n color: var(--text);\n background: var(--bg-0);\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n padding: 6px 9px;\n transition: border-color 0.12s;\n min-width: 0;\n}\nselect {\n /*\n * padding cannot move the NATIVE dropdown arrow — the browser pins it to\n * the edge. Draw our own chevron, inset to mirror the left text padding.\n */\n appearance: none;\n padding-right: 30px;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239aa3bd' stroke-width='2.4'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 9px center;\n background-size: 12px;\n}\ninput:focus,\nselect:focus,\ntextarea:focus {\n outline: none;\n border-color: var(--accent-deep);\n}\ntextarea {\n resize: vertical;\n font-size: 12px;\n line-height: 1.5;\n}\ntextarea.invalid {\n border-color: var(--rose);\n background: rgba(251, 113, 133, 0.05);\n}\n\n/* ─── banners ─── */\n#error-banner {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n padding: 8px 10px 8px 14px;\n background: rgba(251, 113, 133, 0.1);\n color: var(--rose);\n border-bottom: 1px solid rgba(251, 113, 133, 0.35);\n max-height: 110px;\n overflow: auto;\n font-family: ui-monospace, Menlo, monospace;\n font-size: 12px;\n}\n#error-text {\n flex: 1;\n white-space: pre-wrap;\n}\n#error-close {\n flex: none;\n padding: 0 6px;\n color: var(--rose);\n opacity: 0.65;\n font-size: 13px;\n line-height: 1.4;\n}\n#error-close:hover {\n opacity: 1;\n}\n#edit-notice {\n padding: 7px 14px;\n background: rgba(147, 197, 253, 0.08);\n color: #93c5fd;\n border-bottom: 1px solid rgba(147, 197, 253, 0.25);\n font-size: 12px;\n}\n#play-notice {\n padding: 7px 14px;\n background: rgba(134, 239, 172, 0.08);\n color: var(--green);\n border-bottom: 1px solid rgba(134, 239, 172, 0.25);\n font-size: 12px;\n}\n\n/* ─── layout ─── */\n/* The editor's root owns the window — on its own page AND mounted over a\n running game, where the host's <body> is some game's and says nothing about\n how tall a percentage is. Fixing it to the viewport gives every pane below a\n definite height in both cases; without it main's percentage height has\n nothing to resolve against, main grows to its CONTENT, and the viewport\n canvas is sized to a scene tree three thousand pixels tall. */\n.incanto-editor-root {\n position: fixed;\n inset: 0;\n z-index: 30;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n background: var(--bg-0);\n color: var(--text);\n font:\n 13px / 1.55 \"Inter\",\n -apple-system,\n \"Segoe UI\",\n system-ui,\n sans-serif;\n -webkit-font-smoothing: antialiased;\n}\nmain {\n display: flex;\n flex: 1;\n min-height: 0;\n}\n#tree-pane {\n width: 256px;\n display: flex;\n flex-direction: column;\n background: var(--bg-1);\n border-right: 1px solid var(--line);\n}\n#inspector-pane {\n width: 336px;\n overflow-y: auto;\n background: var(--bg-1);\n border-left: 1px solid var(--line);\n}\n#viewport-pane {\n flex: 1;\n position: relative;\n background:\n radial-gradient(1200px 500px at 50% -10%, rgba(110, 231, 220, 0.05), transparent), var(--bg-0);\n overflow: hidden;\n}\n#viewport,\n#overlay,\n#play-canvas {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n}\n#overlay {\n cursor: crosshair;\n}\n#play-canvas {\n z-index: 3;\n}\n#hints-dock {\n position: absolute;\n bottom: 12px;\n right: 16px;\n z-index: 4;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n#hints-toggle {\n width: 40px;\n height: 40px;\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n border: 1px solid var(--line-strong);\n background: rgba(16, 19, 29, 0.88);\n color: var(--text-dim);\n backdrop-filter: blur(6px);\n}\n#hints-toggle:hover {\n color: var(--accent);\n border-color: var(--accent-deep);\n}\n#hints-dock.open #hints-toggle {\n color: var(--accent);\n}\n.hints {\n max-width: 0;\n opacity: 0;\n overflow: hidden;\n white-space: nowrap;\n transition:\n max-width 0.22s ease,\n opacity 0.18s ease,\n padding 0.22s ease;\n padding: 5px 0;\n display: flex;\n gap: 14px;\n border-radius: 999px;\n background: rgba(16, 19, 29, 0.85);\n border: 1px solid transparent;\n color: var(--text-faint);\n font-size: 11px;\n pointer-events: none;\n backdrop-filter: blur(6px);\n}\n.hints b {\n color: var(--text-dim);\n font-weight: 600;\n}\n.pane-title {\n padding: 9px 14px 7px;\n font-size: 10.5px;\n font-weight: 700;\n letter-spacing: 1.6px;\n text-transform: uppercase;\n color: var(--text-faint);\n border-bottom: 1px solid var(--line);\n}\n\n/* ─── tree ─── */\n#tree {\n flex: 1;\n overflow-y: auto;\n padding: 8px;\n}\n.tree-row {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 3px 8px 3px 4px;\n border-radius: var(--r-sm);\n cursor: pointer;\n white-space: nowrap;\n overflow: hidden;\n color: var(--text-dim);\n border: 1px solid transparent;\n position: relative;\n}\n.chevron {\n display: inline-flex;\n align-items: center;\n transition: transform 0.12s;\n}\n.chevron.collapsed {\n transform: rotate(-90deg);\n}\n.chevron-legacy {\n flex: none;\n width: 14px;\n text-align: center;\n color: var(--text-faint);\n font-size: 9px;\n cursor: pointer;\n user-select: none;\n}\n.chevron.leaf {\n cursor: default;\n opacity: 0.35;\n}\n.chevron:not(.leaf):hover {\n color: var(--accent);\n}\n.tree-children {\n margin-left: 11px;\n padding-left: 8px;\n border-left: 1px solid var(--line);\n}\n.tree-row.dragging {\n opacity: 0.4;\n}\n.tree-row.drop-into {\n background: rgba(110, 231, 220, 0.14);\n border-color: var(--accent);\n}\n.tree-row.drop-before::before,\n.tree-row.drop-after::after {\n content: \"\";\n position: absolute;\n left: 4px;\n right: 4px;\n height: 2px;\n border-radius: 2px;\n background: var(--accent);\n}\n.tree-row.drop-before::before {\n top: -1px;\n}\n.tree-row.drop-after::after {\n bottom: -1px;\n}\n.tree-row:hover {\n background: var(--bg-2);\n color: var(--text);\n}\n.tree-row.selected {\n background: rgba(110, 231, 220, 0.1);\n border-color: rgba(110, 231, 220, 0.3);\n color: var(--accent);\n}\n.tree-name {\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.tree-icon {\n flex: none;\n display: inline-grid;\n place-items: center;\n width: 17px;\n height: 17px;\n border-radius: 4px;\n cursor: help;\n}\n.tree-icon:hover {\n background: var(--bg-3);\n}\n.cat-core {\n background: rgba(167, 139, 250, 0.15);\n color: var(--violet);\n}\n.cat-2d {\n background: rgba(110, 231, 220, 0.12);\n color: var(--accent);\n}\n.cat-3d {\n background: rgba(251, 191, 36, 0.12);\n color: var(--amber);\n}\n.cat-body {\n background: rgba(134, 239, 172, 0.12);\n color: var(--green);\n}\n.cat-net {\n background: rgba(251, 113, 133, 0.12);\n color: var(--rose);\n}\n.scene-row {\n margin-bottom: 6px;\n color: var(--text-faint);\n}\n.scene-row.selected {\n color: var(--accent);\n}\n#tree-actions {\n display: flex;\n gap: 7px;\n padding: 10px;\n border-top: 1px solid var(--line);\n}\n#add-type {\n flex: 1;\n}\n\n/* ─── inspector ─── */\n#inspector {\n padding: 12px 14px 40px;\n}\n.section-title {\n display: flex;\n align-items: center;\n gap: 7px;\n margin: 16px 0 8px;\n font-size: 11px;\n font-weight: 700;\n letter-spacing: 1.4px;\n text-transform: uppercase;\n color: var(--accent);\n}\n.section-title:first-child {\n margin-top: 2px;\n}\n.section-title .rule {\n flex: 1;\n height: 1px;\n background: var(--line);\n}\n.field {\n display: grid;\n grid-template-columns: 92px 1fr;\n align-items: center;\n gap: 8px;\n margin-bottom: 7px;\n}\n.field > span {\n font-size: 11.5px;\n color: var(--text-dim);\n display: flex;\n align-items: center;\n gap: 5px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.field.wide {\n grid-template-columns: 1fr;\n}\n.field.wide > span {\n margin-bottom: 2px;\n}\n.vector-row {\n display: flex;\n gap: 6px;\n}\n.vector-row input {\n width: 100%;\n}\n.help-btn {\n flex: none;\n width: 15px;\n height: 15px;\n padding: 0;\n border-radius: 50%;\n border: 1px solid var(--line-strong);\n color: var(--text-faint);\n font-size: 10px;\n font-weight: 700;\n justify-content: center;\n}\n.help-btn:hover {\n border-color: var(--accent);\n color: var(--accent);\n}\n.chips {\n display: flex;\n flex-wrap: wrap;\n gap: 5px;\n padding: 5px 7px;\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n background: var(--bg-0);\n cursor: text;\n}\n.chip {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 1px 8px;\n border-radius: 999px;\n background: rgba(110, 231, 220, 0.12);\n color: var(--accent);\n font-size: 11.5px;\n}\n.chip button {\n padding: 0;\n font-size: 12px;\n color: inherit;\n opacity: 0.7;\n}\n.chips input {\n flex: 1;\n min-width: 70px;\n border: none;\n background: transparent;\n padding: 2px;\n}\n.chips input:focus {\n outline: none;\n}\n.subcard {\n border: 1px solid var(--line);\n border-radius: var(--r-md);\n background: var(--bg-2);\n padding: 10px;\n margin-bottom: 10px;\n}\n.subcard .field {\n grid-template-columns: 78px 1fr;\n}\n.subcard-head {\n display: flex;\n align-items: center;\n gap: 7px;\n margin-bottom: 8px;\n font-size: 11.5px;\n font-weight: 600;\n color: var(--text-dim);\n}\n.subcard-head .spacer {\n flex: 1;\n}\n.linklike {\n padding: 2px 6px;\n font-size: 11px;\n color: var(--accent);\n font-weight: 600;\n}\n.linklike:hover {\n text-decoration: underline;\n}\n.muted-note {\n font-size: 11px;\n color: var(--text-faint);\n margin: -2px 0 8px;\n}\n\n/* ─── asset picker ─── */\n.asset-control {\n display: flex;\n gap: 6px;\n align-items: stretch;\n}\n.asset-control input {\n flex: 1;\n min-width: 0;\n}\n.asset-toggle {\n flex: none;\n width: 26px;\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n background: var(--bg-1);\n color: var(--text-dim);\n font-size: 11px;\n}\n.asset-toggle:hover {\n border-color: var(--accent);\n color: var(--accent);\n}\n.asset-panel {\n margin-top: 6px;\n border: 1px solid var(--line-strong);\n border-radius: var(--r-sm);\n background: var(--bg-0);\n padding: 6px;\n}\n.asset-search {\n width: 100%;\n margin-bottom: 6px;\n}\n.asset-options {\n display: flex;\n flex-direction: column;\n gap: 3px;\n max-height: 220px;\n overflow-y: auto;\n}\nbutton.asset-option {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 1px;\n padding: 5px 8px;\n text-align: left;\n border: 1px solid transparent;\n border-radius: var(--r-sm);\n background: var(--bg-2);\n color: var(--text);\n width: 100%;\n}\nbutton.asset-option:hover {\n border-color: var(--accent);\n background: var(--bg-3);\n}\nbutton.asset-option strong {\n font-size: 11.5px;\n font-weight: 600;\n}\nbutton.asset-option small {\n font-size: 10px;\n color: var(--text-faint);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 100%;\n}\n.asset-empty {\n font-size: 11px;\n color: var(--text-faint);\n padding: 4px 8px;\n}\n.asset-note {\n margin-top: 5px;\n}\n.varieties {\n cursor: default;\n}\n.variety-opt {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n font-size: 11.5px;\n color: var(--text-dim);\n cursor: pointer;\n}\n.variety-opt input[type=\"checkbox\"] {\n width: auto;\n}\n\n/* ─── popover (help) ─── */\n#popover {\n position: fixed;\n z-index: 50;\n width: 300px;\n /* A topic longer than the window still has to be readable to the end: the\n positioner pins it to the top and this lets the rest scroll. */\n max-height: calc(100vh - 16px);\n overflow-y: auto;\n overscroll-behavior: contain;\n background: var(--bg-3);\n border: 1px solid var(--line-strong);\n border-radius: var(--r-md);\n box-shadow: var(--shadow);\n padding: 12px 14px;\n font-size: 12px;\n color: var(--text-dim);\n}\n#popover h4 {\n margin: 0 0 6px;\n font-size: 12.5px;\n color: var(--text);\n}\n#popover code {\n background: var(--bg-0);\n padding: 1px 5px;\n border-radius: 4px;\n font-size: 11px;\n color: var(--accent);\n}\n#popover pre {\n margin: 8px 0 0;\n padding: 8px 10px;\n background: var(--bg-0);\n border-radius: var(--r-sm);\n font-size: 11px;\n line-height: 1.5;\n overflow-x: auto;\n color: var(--text-dim);\n}\n#popover .pop-actions {\n margin-top: 8px;\n display: flex;\n justify-content: flex-end;\n}\n\n/* ─── picker ─── */\n#picker {\n position: fixed;\n inset: 0;\n background: rgba(7, 9, 14, 0.78);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 40;\n backdrop-filter: blur(4px);\n}\n#picker[hidden] {\n display: none;\n}\n#picker-card {\n width: 460px;\n max-height: 72vh;\n background: var(--bg-2);\n border: 1px solid var(--line-strong);\n border-radius: 14px;\n box-shadow: var(--shadow);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n#picker-list {\n flex: 1;\n overflow-y: auto;\n padding: 6px;\n min-height: 120px;\n}\n#picker-list .tree-row {\n padding: 9px 12px;\n font-family: ui-monospace, Menlo, monospace;\n font-size: 12.5px;\n}\n#picker-find {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n border-bottom: 1px solid var(--line);\n}\n#picker-search {\n flex: 1;\n}\n#picker-count {\n font-size: 11px;\n color: var(--text-faint);\n font-variant-numeric: tabular-nums;\n}\n/* one row of the project explorer: caret, name, and the facts, right-aligned */\n.scene-row {\n display: flex;\n align-items: center;\n gap: 7px;\n padding: 6px 10px 6px 6px;\n border-radius: 7px;\n cursor: pointer;\n font-size: 12.5px;\n user-select: none;\n}\n.scene-row:hover {\n background: var(--bg-3);\n}\n.scene-row.active {\n background: var(--bg-3);\n outline: 1px solid var(--line-strong);\n}\n.scene-name {\n font-family: ui-monospace, Menlo, monospace;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.scene-folder .scene-name {\n color: var(--text-dim);\n}\n.scene-row.current .scene-name {\n color: var(--accent);\n}\n.scene-caret {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 13px;\n flex: none;\n color: var(--text-faint);\n font-size: 9px;\n line-height: 1;\n}\n.scene-folder .scene-caret {\n color: var(--text-dim);\n}\n.scene-meta {\n margin-left: auto;\n padding-left: 10px;\n flex: none;\n font-size: 10.5px;\n color: var(--text-faint);\n font-variant-numeric: tabular-nums;\n}\n/* a JSON that is not a scene: still there, still clickable, visibly not one */\n.scene-row.not-scene .scene-name,\n.scene-row.not-scene .scene-meta {\n color: var(--text-faint);\n}\n.scene-row.not-scene .scene-caret {\n opacity: 0.4;\n}\n.scene-empty {\n padding: 22px 12px;\n text-align: center;\n color: var(--text-faint);\n font-size: 12px;\n}\n#picker-new {\n display: flex;\n gap: 8px;\n padding: 12px;\n border-top: 1px solid var(--line);\n}\n#picker-path {\n flex: 1;\n font-family: ui-monospace, Menlo, monospace;\n}\n\n/* ─── scrollbars ─── */\n::-webkit-scrollbar {\n width: 9px;\n height: 9px;\n}\n::-webkit-scrollbar-thumb {\n background: var(--line-strong);\n border-radius: 99px;\n border: 2px solid var(--bg-1);\n}\n::-webkit-scrollbar-track {\n background: transparent;\n}\n\nbody.playing #tree-pane,\nbody.playing #inspector-pane {\n pointer-events: none;\n opacity: 0.45;\n filter: saturate(0.6);\n transition: opacity 0.2s;\n}\n\n.rename-input {\n flex: 1;\n min-width: 0;\n padding: 1px 6px;\n font-size: 12.5px;\n}\n.balloon {\n position: fixed;\n z-index: 60;\n max-width: 230px;\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 8px 11px;\n background: var(--bg-3);\n border: 1px solid var(--line-strong);\n border-radius: var(--r-md);\n box-shadow: var(--shadow);\n font-size: 11.5px;\n color: var(--text-dim);\n}\n.balloon .balloon-title {\n color: var(--accent);\n font-size: 12px;\n font-weight: 700;\n}\n.context-menu {\n position: fixed;\n z-index: 60;\n min-width: 190px;\n padding: 5px;\n background: var(--bg-3);\n border: 1px solid var(--line-strong);\n border-radius: var(--r-md);\n box-shadow: var(--shadow);\n display: flex;\n flex-direction: column;\n}\n.menu-item {\n justify-content: space-between;\n padding: 6px 10px;\n border-radius: var(--r-sm);\n font-weight: 500;\n color: var(--text);\n}\n.menu-item:not(:disabled):hover {\n background: var(--bg-2);\n}\n.menu-item.danger:not(:disabled):hover {\n color: var(--rose);\n}\n.menu-item kbd {\n font-size: 10px;\n color: var(--text-faint);\n font-family: inherit;\n}\n.menu-divider {\n height: 1px;\n margin: 4px 6px;\n background: var(--line);\n}\n/* The play menu is a choice, not a command list: each row carries a label and\n the sentence that says what actually happens, stacked. */\n.play-menu {\n width: 290px;\n gap: 2px;\n}\n.play-menu-item {\n flex-direction: column;\n align-items: flex-start;\n gap: 2px;\n padding: 8px 10px;\n text-align: left;\n}\n.play-menu-hint {\n font-size: 11px;\n font-weight: 400;\n line-height: 1.35;\n color: var(--text-faint);\n}\n\n.hints[hidden] {\n display: none;\n}\n#hints-dock.open .hints:not([hidden]) {\n max-width: 1100px;\n opacity: 1;\n padding: 5px 14px;\n border-color: var(--line);\n}\nbody.playing #hints-dock {\n display: none;\n}\n\n#gameview-btn {\n position: absolute;\n top: 104px;\n right: 18px;\n z-index: 4;\n font-size: 11.5px;\n padding: 4px 10px;\n backdrop-filter: blur(6px);\n background: rgba(16, 19, 29, 0.8);\n}\n\n.field input[type=\"checkbox\"] {\n justify-self: start;\n width: 15px;\n height: 15px;\n accent-color: var(--accent-deep);\n cursor: pointer;\n}\n\n.picker-title {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n#picker-close {\n padding: 0 4px;\n font-size: 12px;\n color: var(--text-faint);\n border: none;\n background: none;\n}\n#picker-close:hover {\n color: var(--text);\n}\n\n.uid-row {\n display: flex;\n gap: 6px;\n}\n.uid-row input {\n flex: 1;\n min-width: 0;\n font-size: 11.5px;\n}\n.uid-row .ghost {\n padding: 4px 8px;\n}\n#confirm {\n position: fixed;\n inset: 0;\n background: rgba(7, 9, 14, 0.78);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 70;\n backdrop-filter: blur(4px);\n}\n#confirm[hidden] {\n display: none;\n}\n#confirm-card {\n width: 480px;\n max-height: 70vh;\n display: flex;\n flex-direction: column;\n background: var(--bg-2);\n border: 1px solid var(--line-strong);\n border-radius: 14px;\n box-shadow: var(--shadow);\n overflow: hidden;\n}\n#confirm-body {\n padding: 14px;\n color: var(--text-dim);\n font-size: 12.5px;\n overflow-y: auto;\n}\n#confirm-list:empty {\n display: none; /* the group-delete confirm has no reference list */\n}\n#confirm-list {\n margin: 10px 0 0;\n padding: 10px 12px;\n background: var(--bg-0);\n border-radius: var(--r-sm);\n font-family: ui-monospace, Menlo, monospace;\n font-size: 11.5px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n#confirm-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 14px;\n border-top: 1px solid var(--line);\n}\n#confirm-delete {\n border-color: var(--rose);\n color: var(--rose);\n background: rgba(251, 113, 133, 0.08);\n}\n#confirm-delete:hover {\n background: rgba(251, 113, 133, 0.16);\n}\n\n.color-row {\n display: flex;\n gap: 6px;\n align-items: center;\n}\n.color-row input[type=\"color\"] {\n width: 30px;\n height: 26px;\n padding: 2px;\n cursor: pointer;\n}\n.color-row input[type=\"text\"] {\n flex: 1;\n min-width: 0;\n font-size: 11.5px;\n}\n.slider-row {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n.slider-row input[type=\"range\"] {\n flex: 1;\n accent-color: var(--accent-deep);\n padding: 0;\n border: none;\n background: transparent;\n}\n.slider-row input[type=\"number\"] {\n width: 64px;\n}\n.asset-row {\n display: flex;\n align-items: center;\n gap: 7px;\n padding: 5px 8px;\n border-radius: var(--r-sm);\n cursor: pointer;\n}\n.asset-row:hover,\n.asset-row.open {\n background: var(--bg-3);\n}\n.asset-key {\n color: var(--accent);\n}\n.asset-url {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--text-faint);\n font-size: 11px;\n font-family: ui-monospace, Menlo, monospace;\n}\n.danger-link {\n color: var(--text-faint);\n}\n.danger-link:hover {\n color: var(--rose);\n}\n.asset-editor {\n margin: 2px 0 10px;\n padding: 10px;\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n background: var(--bg-0);\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.asset-editor .field {\n grid-template-columns: 52px 1fr;\n margin-bottom: 4px;\n}\n.meta-row {\n display: grid;\n grid-template-columns: 1fr 1fr 24px;\n gap: 6px;\n align-items: center;\n}\n.meta-row input {\n font-size: 11.5px;\n padding: 4px 7px;\n}\n\n#docs {\n position: fixed;\n inset: 0;\n background: rgba(7, 9, 14, 0.8);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 60;\n backdrop-filter: blur(5px);\n}\n#docs[hidden] {\n display: none;\n}\n#docs-card {\n width: min(920px, 92vw);\n height: min(680px, 88vh);\n background: var(--bg-2);\n border: 1px solid var(--line-strong);\n border-radius: 14px;\n box-shadow: var(--shadow);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n#docs-layout {\n display: flex;\n flex: 1;\n min-height: 0;\n}\n#docs-tabs {\n width: 168px;\n border-right: 1px solid var(--line);\n padding: 10px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.docs-tab {\n justify-content: flex-start;\n padding: 7px 12px;\n border-radius: var(--r-sm);\n color: var(--text-dim);\n font-weight: 500;\n}\n.docs-tab:hover {\n background: var(--bg-3);\n color: var(--text);\n}\n.docs-tab.active {\n background: rgba(110, 231, 220, 0.1);\n color: var(--accent);\n font-weight: 700;\n}\n#docs-body {\n flex: 1;\n overflow-y: auto;\n padding: 18px 24px 40px;\n}\n#docs-body h2 {\n margin: 0 0 6px;\n font-size: 18px;\n}\n#docs-body h3 {\n margin: 18px 0 4px;\n font-size: 13.5px;\n color: var(--accent);\n}\n#docs-body p {\n margin: 4px 0 10px;\n color: var(--text-dim);\n line-height: 1.7;\n font-size: 13px;\n}\n.docs-intro {\n padding: 10px 14px;\n background: var(--bg-1);\n border: 1px solid var(--line);\n border-radius: var(--r-md);\n}\n.docs-node {\n border: 1px solid var(--line);\n border-radius: var(--r-md);\n margin-bottom: 8px;\n overflow: hidden;\n}\n.docs-node.open {\n border-color: var(--line-strong);\n}\n.docs-node-head {\n width: 100%;\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 9px 12px;\n border-radius: 0;\n text-align: left;\n}\n.docs-node-head:hover {\n background: var(--bg-3);\n}\n.docs-node-head strong {\n font-size: 13px;\n}\n.docs-summary {\n color: var(--text-faint);\n font-size: 12px;\n font-weight: 400;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.docs-detail {\n padding: 4px 14px 12px;\n border-top: 1px solid var(--line);\n background: var(--bg-1);\n}\n.docs-props {\n width: 100%;\n border-collapse: collapse;\n margin-top: 8px;\n font-size: 11.5px;\n}\n.docs-props th {\n text-align: left;\n color: var(--text-faint);\n font-weight: 600;\n padding: 4px 8px;\n border-bottom: 1px solid var(--line);\n}\n.docs-props td {\n padding: 3px 8px;\n border-bottom: 1px solid var(--line);\n color: var(--text-dim);\n}\n\n#mode-toolbar {\n position: absolute;\n top: 12px;\n left: 12px;\n z-index: 4;\n display: flex;\n gap: 4px;\n padding: 4px;\n border-radius: var(--r-md);\n background: rgba(16, 19, 29, 0.85);\n border: 1px solid var(--line);\n backdrop-filter: blur(6px);\n}\n.tool {\n width: 30px;\n height: 28px;\n justify-content: center;\n padding: 0;\n border-radius: var(--r-sm);\n color: var(--text-faint);\n}\n.tool:hover {\n color: var(--text);\n background: var(--bg-3);\n}\n.tool.active {\n background: rgba(110, 231, 220, 0.14);\n color: var(--accent);\n}\n\n.lang-menu {\n min-width: 130px;\n}\n.lang-check {\n color: var(--accent);\n font-weight: 700;\n}\n\n.explorer-section {\n display: flex;\n align-items: center;\n justify-content: space-between;\n border-top: 1px solid var(--line);\n margin-top: 4px;\n}\n.explorer-section .ghost {\n padding: 1px 8px;\n}\n#asset-tree {\n padding: 2px 8px 10px;\n overflow-y: auto;\n max-height: 30%;\n}\n.explorer-empty {\n padding: 4px 10px;\n font-size: 11px;\n}\n.asset-row .asset-key {\n color: var(--accent);\n font-family: ui-monospace, Menlo, monospace;\n}\n.asset-icon-texture {\n color: #f0abfc;\n}\n.asset-icon-spritesheet {\n color: #fbbf24;\n}\n.asset-icon-model {\n color: #7aa2ff;\n}\n.asset-icon-animation {\n color: #86efac;\n}\n.uid-value {\n display: flex;\n align-items: center;\n gap: 7px;\n min-width: 0;\n}\n.uid-value code {\n font-family: ui-monospace, Menlo, monospace;\n font-size: 11px;\n color: var(--text-dim);\n letter-spacing: 0.3px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.uid-copy {\n padding: 3px 5px;\n border: none;\n background: none;\n border-radius: var(--r-sm);\n color: var(--text-faint);\n line-height: 0;\n}\n.uid-copy:hover {\n color: var(--text);\n background: var(--bg-3);\n}\n.uid-copy.copied {\n color: var(--accent);\n font-size: 10px;\n line-height: 1;\n}\n\n.section-toggle {\n width: 100%;\n height: 30px; /* IDENTICAL header height for ASSETS and SCENE */\n box-sizing: border-box;\n padding-top: 0;\n padding-bottom: 0;\n display: flex;\n align-items: center;\n justify-content: flex-start;\n gap: 6px;\n text-align: left;\n cursor: pointer;\n background: var(--bg-1);\n border: none;\n border-top: 1px solid var(--line-strong);\n border-bottom: 1px solid var(--line);\n border-radius: 0;\n}\n.section-toggle:hover {\n color: var(--text);\n}\n.section-toggle .chev {\n display: inline-flex;\n transition: transform 0.12s;\n color: var(--text-dim);\n}\n.section-toggle.collapsed .chev {\n transform: rotate(-90deg);\n}\n.section-add {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 24px;\n height: 20px;\n padding: 0 6px;\n font-size: 13px;\n color: var(--text-dim);\n border: 1px solid var(--line-strong);\n border-radius: var(--r-sm);\n background: var(--bg-2);\n}\n.section-add:hover {\n background: var(--bg-3);\n color: var(--accent);\n border-color: var(--accent-deep);\n}\n[data-body][hidden],\naside#tree-pane #scene-body[hidden] {\n /* outranks the #scene-body flex rule — [hidden] must always win */\n display: none;\n}\n#scene-body {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n}\n.asset-folder {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 8px;\n color: var(--text-dim);\n cursor: pointer;\n border-radius: var(--r-sm);\n}\n.asset-folder:hover {\n background: var(--bg-3);\n}\n.asset-folder .chev {\n display: inline-flex;\n color: var(--text-dim);\n transition: transform 0.12s;\n}\n.asset-folder.collapsed .chev {\n transform: rotate(-90deg);\n}\n.asset-folder svg {\n color: #e7c66a;\n}\n.asset-row.grouped {\n margin-left: 18px;\n}\n\n.asset-folder .count {\n margin-left: auto;\n color: var(--text-faint);\n font-size: 10.5px;\n}\n.asset-folder.selected {\n background: rgba(110, 231, 220, 0.08);\n color: var(--accent);\n}\n.asset-folder.drop-target,\n#asset-tree.drop-target {\n outline: 1.5px dashed var(--accent);\n outline-offset: -2px;\n border-radius: var(--r-sm);\n}\n.asset-row[draggable=\"true\"] {\n cursor: grab;\n}\n\nbody.playing #mode-toolbar,\nbody.playing #gameview-btn {\n display: none; /* gizmo tools and the free-cam escape make no sense mid-play */\n}\n\n.tool-divider {\n width: 1px;\n height: 18px;\n background: var(--line);\n margin: 0 2px;\n align-self: center;\n}\n\n/* ─── generate dialog ─── */\n#generate {\n position: fixed;\n inset: 0;\n background: rgba(7, 9, 14, 0.78);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 70;\n backdrop-filter: blur(4px);\n}\n#generate[hidden] {\n display: none;\n}\n#generate-card {\n width: 420px;\n max-height: 78vh;\n display: flex;\n flex-direction: column;\n background: var(--bg-2);\n border: 1px solid var(--line-strong);\n border-radius: 14px;\n box-shadow: var(--shadow);\n overflow: hidden;\n}\n#generate-body {\n padding: 14px;\n overflow-y: auto;\n}\n#generate-body .gen-hint {\n margin: 0 0 12px;\n font-size: 11.5px;\n color: var(--text-faint);\n}\n#generate-body .gen-desc {\n margin: 2px 0 12px;\n font-size: 11.5px;\n color: var(--text-dim);\n}\n#generate-params {\n padding-top: 2px;\n border-top: 1px solid var(--line);\n}\n#generate-params .field:first-child {\n margin-top: 10px;\n}\n.gen-seed-row {\n display: flex;\n gap: 6px;\n}\n.gen-seed-row input {\n flex: 1;\n min-width: 0;\n}\n.gen-seed-row .ghost {\n padding: 4px 9px;\n}\n#generate-actions {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 14px;\n border-top: 1px solid var(--line);\n}\n#generate-status {\n margin-right: auto;\n font-size: 11px;\n color: var(--rose);\n}\n\n/* ---- scene constants + the prop \"bind to a constant\" picker ---- */\n.const-picker {\n flex: none;\n width: 30px;\n margin-left: 6px;\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n background: var(--bg-1);\n color: var(--text-dim);\n font-size: 11px;\n}\n.const-picker:hover {\n border-color: var(--accent);\n color: var(--accent);\n}\n.field.const-bound > span {\n color: var(--accent);\n}\n.const-row {\n display: flex;\n gap: 6px;\n align-items: stretch;\n}\n.const-row .field {\n flex: 1;\n min-width: 0;\n}\n.const-del {\n flex: none;\n width: 26px;\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n background: var(--bg-1);\n color: var(--text-dim);\n font-size: 11px;\n}\n.const-del:hover {\n border-color: var(--rose);\n color: var(--rose);\n}\n.const-add {\n display: flex;\n gap: 6px;\n align-items: stretch;\n margin-top: 6px;\n}\n.const-add input {\n flex: 1;\n min-width: 0;\n}\n\n/* ---- TileMap2D paint brush ---- */\n.tile-paint {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.paint-toggle {\n cursor: pointer;\n border: 1px solid var(--border, #444);\n border-radius: 6px;\n background: transparent;\n color: inherit;\n padding: 6px 10px;\n font: inherit;\n}\n.paint-toggle.on {\n background: #2e6b2e;\n border-color: #4a9e4a;\n color: #fff;\n}\n.paint-palette {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n align-items: center;\n}\n.paint-chip {\n cursor: pointer;\n width: 26px;\n height: 26px;\n border-radius: 5px;\n border: 1px solid var(--border, #444);\n background: transparent;\n color: inherit;\n font: 600 13px / 1 monospace;\n}\n.paint-chip.on {\n background: #3a5a8c;\n border-color: #6a9ae0;\n color: #fff;\n}\n.paint-brush-input {\n width: 32px;\n text-align: center;\n font: 600 13px / 1 monospace;\n background: transparent;\n color: inherit;\n border: 1px solid var(--border, #444);\n border-radius: 5px;\n padding: 4px;\n}\n.paint-hint {\n font-size: 11px;\n opacity: 0.6;\n}\n\n/* ─── agent8 asset library ─── */\n.asset-lib {\n flex: none;\n width: 30px;\n padding: 0;\n justify-content: center;\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n background: var(--bg-1);\n font-size: 13px;\n line-height: 1;\n}\n.asset-lib:hover {\n border-color: var(--accent);\n}\n.lib-backdrop {\n position: fixed;\n inset: 0;\n z-index: 70;\n display: grid;\n place-items: center;\n background: rgba(4, 6, 12, 0.72);\n backdrop-filter: blur(3px);\n}\n.lib-dialog {\n display: flex;\n flex-direction: column;\n width: min(1180px, 94vw);\n height: min(760px, 88vh);\n background: var(--bg-1);\n border: 1px solid var(--line-strong);\n border-radius: var(--r-md);\n box-shadow: var(--shadow);\n overflow: hidden;\n}\n.lib-head {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n border-bottom: 1px solid var(--line);\n background: var(--bg-2);\n}\n.lib-head strong {\n font-size: 13px;\n}\n.lib-sub {\n color: var(--accent);\n font-size: 12px;\n font-family: ui-monospace, Menlo, monospace;\n}\n.lib-search {\n margin-left: auto;\n width: 260px;\n}\n.lib-body {\n flex: 1;\n display: grid;\n grid-template-columns: 190px 1fr 320px;\n min-height: 0;\n}\n.lib-shelves {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 8px 6px;\n overflow-y: auto;\n border-right: 1px solid var(--line);\n background: var(--bg-1);\n}\n.lib-shelf {\n justify-content: flex-start;\n padding: 6px 10px;\n border-radius: var(--r-sm);\n color: var(--text-dim);\n font-weight: 500;\n text-align: left;\n}\n.lib-shelf:hover {\n background: var(--bg-2);\n color: var(--text);\n}\n.lib-shelf.active {\n background: rgba(110, 231, 220, 0.12);\n color: var(--accent);\n}\n.lib-shelf.crumb {\n color: var(--text-faint);\n font-size: 11.5px;\n}\n.lib-shelf-count {\n margin-left: auto;\n color: var(--text-faint);\n font-size: 10px;\n font-family: ui-monospace, Menlo, monospace;\n}\n.lib-shelf-head {\n margin: 8px 0 2px;\n padding: 0 10px;\n color: var(--text-faint);\n font-size: 10px;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n}\n.lib-grid-pane {\n display: flex;\n flex-direction: column;\n min-width: 0;\n background: var(--bg-0);\n}\n.lib-status {\n padding: 7px 12px;\n color: var(--text-faint);\n font-size: 11.5px;\n border-bottom: 1px solid var(--line);\n}\n.lib-grid {\n flex: 1;\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(112px, 1fr));\n gap: 10px;\n align-content: start;\n padding: 12px;\n overflow-y: auto;\n}\n.lib-card {\n display: flex;\n flex-direction: column;\n gap: 5px;\n min-width: 0; /* grid item: without this the name pushes the card wider */\n padding: 6px;\n overflow: hidden;\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n background: var(--bg-1);\n font-weight: 500;\n}\n.lib-card:hover {\n border-color: var(--line-strong);\n}\n.lib-card.active {\n border-color: var(--accent);\n background: rgba(110, 231, 220, 0.08);\n}\n.lib-thumb {\n display: grid;\n place-items: center;\n aspect-ratio: 1;\n border-radius: 4px;\n background: repeating-conic-gradient(var(--bg-3) 0% 25%, var(--bg-2) 0% 50%) 50% / 16px 16px;\n overflow: hidden;\n}\n.lib-thumb img {\n width: 100%;\n height: 100%;\n object-fit: contain;\n}\n.lib-glyph {\n width: 30px;\n height: 30px;\n color: var(--text-faint);\n}\n.lib-badge {\n position: absolute;\n right: 4px;\n bottom: 4px;\n padding: 1px 5px;\n border-radius: 999px;\n background: rgba(110, 231, 220, 0.16);\n color: var(--accent);\n font-size: 9px;\n font-style: normal;\n letter-spacing: 0.03em;\n}\n.lib-thumb {\n position: relative;\n}\n.lib-card-name {\n max-width: 100%;\n overflow: hidden;\n color: var(--text-dim);\n font-size: 11px;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.lib-more {\n margin: 0 12px 12px;\n}\n.lib-detail {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 12px;\n overflow-y: auto;\n border-left: 1px solid var(--line);\n background: var(--bg-1);\n}\n.lib-stage {\n display: grid;\n place-items: center;\n aspect-ratio: 1;\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n background: repeating-conic-gradient(var(--bg-3) 0% 25%, var(--bg-2) 0% 50%) 50% / 18px 18px;\n overflow: hidden;\n}\n.lib-stage img {\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n}\n.lib-preview3d,\n.lib-preview-canvas {\n width: 100%;\n height: 100%;\n display: block;\n cursor: grab;\n}\n.lib-preview-canvas:active {\n cursor: grabbing;\n}\n.lib-name {\n margin: 0;\n font-size: 13px;\n word-break: break-word;\n}\n.lib-desc {\n margin: 0;\n color: var(--text-dim);\n font-size: 12px;\n line-height: 1.5;\n}\n.lib-note {\n color: var(--accent);\n font-size: 11.5px;\n}\n.lib-tags {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n.lib-tag {\n padding: 2px 7px;\n border-radius: 999px;\n background: var(--bg-3);\n color: var(--text-faint);\n font-size: 10.5px;\n}\n.lib-facts {\n display: grid;\n grid-template-columns: 74px 1fr;\n gap: 3px 8px;\n margin: 0;\n font-size: 11.5px;\n}\n.lib-facts dt {\n color: var(--text-faint);\n}\n.lib-facts dd {\n margin: 0;\n color: var(--text-dim);\n font-family: ui-monospace, Menlo, monospace;\n}\n.lib-url {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.lib-url code {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n padding: 5px 7px;\n border-radius: var(--r-sm);\n background: var(--bg-0);\n color: var(--text-faint);\n font-size: 10.5px;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.lib-actions {\n display: flex;\n gap: 6px;\n margin-top: auto;\n}\n.lib-actions button {\n flex: 1;\n justify-content: center;\n}\n.lib-empty,\n.lib-error {\n grid-column: 1 / -1;\n padding: 24px 12px;\n color: var(--text-faint);\n font-size: 12px;\n text-align: center;\n}\n.lib-error {\n color: var(--rose);\n}\n.lib-token {\n grid-column: 1 / -1;\n max-width: 520px;\n margin: 24px auto;\n padding: 16px;\n border: 1px solid var(--line-strong);\n border-radius: var(--r-md);\n background: var(--bg-1);\n}\n.lib-token-line {\n margin: 0 0 8px;\n font-size: 12.5px;\n}\n.lib-token-how {\n color: var(--text-faint);\n font-size: 11.5px;\n line-height: 1.6;\n}\n.lib-token-row {\n display: flex;\n gap: 6px;\n}\n.lib-token-row input {\n flex: 1;\n}\n\n/* ─── animation card ─── */\n.anim-card .slider-row {\n width: 100%;\n}\n.anim-upper {\n margin-top: 8px;\n padding-top: 8px;\n border-top: 1px solid var(--line);\n}\n.anim-upper > summary {\n color: var(--text-faint);\n font-size: 11.5px;\n cursor: pointer;\n list-style: none;\n}\n.anim-upper > summary::before {\n content: \"▸ \";\n}\n.anim-upper[open] > summary::before {\n content: \"▾ \";\n}\n.anim-upper > summary:hover {\n color: var(--text-dim);\n}\n\n/* ─── connections ─── */\n/* Signal wiring on the selected node. Dense on purpose: a row is four fields,\n and a node with a dozen connections still has to fit the inspector column. */\n.connections {\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding: 2px 0 6px;\n}\n.conn-group {\n font-size: 10px;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n opacity: 0.55;\n margin-top: 4px;\n}\n.conn-row {\n display: grid;\n grid-template-columns: 1fr 10px 1fr 1fr 18px;\n gap: 3px;\n align-items: center;\n}\n.conn-arrow {\n text-align: center;\n opacity: 0.5;\n font-size: 11px;\n}\n.conn-select,\n.conn-handler {\n min-width: 0;\n font-size: 11px;\n padding: 2px 4px;\n}\n.conn-select.dangling {\n border-color: #f87171;\n color: #f87171;\n}\n.conn-warn {\n font-size: 10px;\n color: #f87171;\n padding: 1px 0 3px;\n line-height: 1.35;\n}\n.conn-remove {\n border: 0;\n background: none;\n color: inherit;\n opacity: 0.4;\n cursor: pointer;\n font-size: 11px;\n padding: 0;\n}\n.conn-remove:hover {\n opacity: 1;\n color: #f87171;\n}\n.conn-add {\n padding-top: 2px;\n}\n.conn-add button {\n font-size: 11px;\n padding: 2px 8px;\n cursor: pointer;\n}\n.conn-add button:disabled {\n opacity: 0.4;\n cursor: default;\n}\n", Zr = new Map(yt.flatMap((e) => e.nodes.map((e) => [e.type, e.summary]))), Qr = /* @__PURE__ */ new Set(), $r = null, ei = null, ti = null;
4134
4151
  function ni(e) {
4152
+ ei = e;
4153
+ }
4154
+ function ri(e) {
4135
4155
  $r = e;
4136
4156
  }
4137
- var ri = null, ii = null, ai = null;
4138
- function oi(e) {
4157
+ function ii(e) {
4158
+ ti = e;
4159
+ }
4160
+ var ai = null, oi = null, si = null;
4161
+ function ci(e) {
4139
4162
  return e ? e.includes("Body") || e.includes("Area") || e.includes("Controller") ? "cat-body" : e === "NetworkSpawner" ? "cat-net" : e.endsWith("3D") ? "cat-3d" : e.endsWith("2D") || e === "Label" || e === "UILayer" ? "cat-2d" : "cat-core" : "cat-core";
4140
4163
  }
4141
- function si(e, t) {
4164
+ function li(e, t) {
4142
4165
  e.textContent = "";
4143
4166
  let n = document.createElement("div");
4144
4167
  n.className = `tree-row scene-row${t.selection === null && t.selectedAsset === null && t.selectedGroup === null && !t.addingAsset && !t.addingGroup ? " selected" : ""}`, n.textContent = `⚙ ${String(t.working.name ?? "scene")}`, n.addEventListener("click", () => t.select(null)), e.appendChild(n);
@@ -4148,54 +4171,54 @@ function si(e, t) {
4148
4171
  t.className = "muted-note explorer-empty", t.textContent = "no root node — pick a type below and + to start the scene", e.appendChild(t);
4149
4172
  return;
4150
4173
  }
4151
- di(r, t.selection), e.appendChild(fi(r, [], t, "")), li(e, t.selection);
4174
+ pi(r, t.selection), e.appendChild(mi(r, [], t, "")), di(e, t.selection);
4152
4175
  }
4153
- var ci = null;
4154
- function li(e, t) {
4176
+ var ui = null;
4177
+ function di(e, t) {
4155
4178
  let n = JSON.stringify(t);
4156
- n !== ci && (ci = n, e.querySelector(".tree-row.selected")?.scrollIntoView?.({
4179
+ n !== ui && (ui = n, e.querySelector(".tree-row.selected")?.scrollIntoView?.({
4157
4180
  block: "nearest",
4158
4181
  inline: "nearest"
4159
4182
  }));
4160
4183
  }
4161
- function ui() {
4162
- ci = null;
4184
+ function fi() {
4185
+ ui = null;
4163
4186
  }
4164
- function di(e, t) {
4187
+ function pi(e, t) {
4165
4188
  if (!t) return;
4166
4189
  let n = e, r = "";
4167
4190
  for (let e of t) {
4168
- r = r ? `${r}/${n.name}` : String(n.name), Xr.delete(r);
4191
+ r = r ? `${r}/${n.name}` : String(n.name), Qr.delete(r);
4169
4192
  let t = n.children?.[e];
4170
4193
  if (!t) return;
4171
4194
  n = t;
4172
4195
  }
4173
4196
  }
4174
- function fi(e, t, n, r) {
4175
- let i = r ? `${r}/${e.name}` : String(e.name), a = (e.children?.length ?? 0) > 0, o = Xr.has(i), s = document.createElement("div");
4197
+ function mi(e, t, n, r) {
4198
+ let i = r ? `${r}/${e.name}` : String(e.name), a = (e.children?.length ?? 0) > 0, o = Qr.has(i), s = document.createElement("div");
4176
4199
  s.className = "tree-branch";
4177
4200
  let c = document.createElement("div");
4178
- c.className = `tree-row${n.isSelected(t) ? " selected" : ""}`, c.draggable = t.length > 0 && ai !== i;
4201
+ c.className = `tree-row${n.isSelected(t) ? " selected" : ""}`, c.draggable = t.length > 0 && si !== i;
4179
4202
  let l = document.createElement("span");
4180
- l.className = `chevron${a ? "" : " leaf"}${o ? " collapsed" : ""}`, a ? l.appendChild(Pe()) : l.textContent = "·", a && l.addEventListener("click", (e) => {
4181
- e.stopPropagation(), o ? Xr.delete(i) : Xr.add(i), n.select(n.selection);
4203
+ l.className = `chevron${a ? "" : " leaf"}${o ? " collapsed" : ""}`, a ? l.appendChild(Fe()) : l.textContent = "·", a && l.addEventListener("click", (e) => {
4204
+ e.stopPropagation(), o ? Qr.delete(i) : Qr.add(i), n.select(n.selection);
4182
4205
  });
4183
4206
  let u = document.createElement("span");
4184
- if (u.className = `tree-icon ${oi(e.type)}`, u.appendChild(Ne(e.type)), u.title = e.type ?? "instance", u.addEventListener("click", (t) => {
4185
- t.stopPropagation(), pi(u, e.type ?? "instance");
4186
- }), c.append(l, u), ai === i) {
4207
+ if (u.className = `tree-icon ${ci(e.type)}`, u.appendChild(Pe(e.type)), u.title = e.type ?? "instance", u.addEventListener("click", (t) => {
4208
+ t.stopPropagation(), hi(u, e.type ?? "instance");
4209
+ }), c.append(l, u), si === i) {
4187
4210
  let r = document.createElement("input");
4188
4211
  r.className = "rename-input", r.value = e.name ?? "";
4189
4212
  let i = () => {
4190
- ai = null;
4213
+ si = null;
4191
4214
  let i = r.value.trim();
4192
4215
  if (i && i !== e.name) {
4193
4216
  let e = n.renameNode(t, i) ?? [];
4194
- e.length > 0 && $r?.(e);
4217
+ e.length > 0 && ti?.(e);
4195
4218
  } else n.select(n.selection);
4196
4219
  };
4197
4220
  r.addEventListener("keydown", (e) => {
4198
- e.stopPropagation(), e.key === "Enter" && i(), e.key === "Escape" && (ai = null, n.select(n.selection));
4221
+ e.stopPropagation(), e.key === "Enter" && i(), e.key === "Escape" && (si = null, n.select(n.selection));
4199
4222
  });
4200
4223
  for (let e of [
4201
4224
  "click",
@@ -4209,38 +4232,38 @@ function fi(e, t, n, r) {
4209
4232
  } else {
4210
4233
  let r = document.createElement("span");
4211
4234
  r.className = "tree-name", r.textContent = e.name ?? "(unnamed)", r.addEventListener("dblclick", (e) => {
4212
- e.stopPropagation(), ai = i, n.select(t);
4235
+ e.stopPropagation(), si = i, n.select(t);
4213
4236
  }), c.appendChild(r);
4214
4237
  }
4215
4238
  if (c.addEventListener("click", (e) => {
4216
- a && !e.metaKey && !e.ctrlKey && (o ? Xr.delete(i) : Xr.add(i)), n.select(t, { toggle: e.metaKey || e.ctrlKey });
4239
+ a && !e.metaKey && !e.ctrlKey && (o ? Qr.delete(i) : Qr.add(i)), n.select(t, { toggle: e.metaKey || e.ctrlKey });
4217
4240
  }), c.addEventListener("contextmenu", (e) => {
4218
- e.preventDefault(), n.isSelected(t) || n.select(t), mi(e.clientX, e.clientY, n, t, i);
4219
- }), Ci(c, t, n), s.appendChild(c), a && !o) {
4241
+ e.preventDefault(), n.isSelected(t) || n.select(t), gi(e.clientX, e.clientY, n, t, i);
4242
+ }), Ti(c, t, n), s.appendChild(c), a && !o) {
4220
4243
  let r = document.createElement("div");
4221
4244
  r.className = "tree-children", (e.children ?? []).forEach((e, a) => {
4222
- r.appendChild(fi(e, [...t, a], n, i));
4245
+ r.appendChild(mi(e, [...t, a], n, i));
4223
4246
  }), s.appendChild(r);
4224
4247
  }
4225
4248
  return s;
4226
4249
  }
4227
- function pi(e, t) {
4228
- yi();
4250
+ function hi(e, t) {
4251
+ xi();
4229
4252
  let n = document.createElement("div");
4230
4253
  n.className = "balloon floating";
4231
4254
  let r = document.createElement("span");
4232
4255
  r.className = "balloon-title", r.textContent = t, n.appendChild(r);
4233
- let i = Yr.get(t);
4256
+ let i = Zr.get(t);
4234
4257
  if (i) {
4235
4258
  let e = document.createElement("span");
4236
4259
  e.textContent = I(i), n.appendChild(e);
4237
4260
  }
4238
4261
  document.body.appendChild(n);
4239
4262
  let a = e.getBoundingClientRect();
4240
- n.style.left = `${Math.min(innerWidth - 240, a.right + 8)}px`, n.style.top = `${Math.max(8, a.top - 6)}px`, bi(n);
4263
+ n.style.left = `${Math.min(innerWidth - 240, a.right + 8)}px`, n.style.top = `${Math.max(8, a.top - 6)}px`, Si(n);
4241
4264
  }
4242
- function mi(e, t, n, r, i) {
4243
- yi();
4265
+ function gi(e, t, n, r, i) {
4266
+ xi();
4244
4267
  let a = n.allSelections(), o = a.length === 1 && r.length > 0, s = document.createElement("div");
4245
4268
  s.className = "context-menu floating";
4246
4269
  let c = (e, t, n) => {
@@ -4252,52 +4275,52 @@ function mi(e, t, n, r, i) {
4252
4275
  e.textContent = n.kbd, r.appendChild(e);
4253
4276
  }
4254
4277
  t && r.addEventListener("click", () => {
4255
- yi(), t();
4278
+ xi(), t();
4256
4279
  }), s.appendChild(r);
4257
4280
  };
4258
4281
  c(`duplicate${a.length > 1 ? ` ×${a.length}` : ""}`, () => {
4259
4282
  for (let e of [...a].reverse()) n.duplicateNode(e);
4260
- }), c("frame in view", Qr && r.length > 0 ? () => {
4261
- n.select(r), Qr?.();
4283
+ }), c("frame in view", ei && r.length > 0 ? () => {
4284
+ n.select(r), ei?.();
4262
4285
  } : null, { kbd: "F" }), c("rename", o ? () => {
4263
- ai = i, n.select(r);
4264
- } : null, { kbd: "dbl-click" }), s.appendChild(hi()), c("cut", r.length > 0 ? () => gi(n, !0) : null), c("copy", r.length > 0 ? () => gi(n, !1) : null), c(`paste as child${ii ? ` (${ii.nodes.length})` : ""}`, ii ? () => _i(n, r) : null), s.appendChild(hi()), c("delete", r.length > 0 ? () => (Zr ?? ((e) => n.removeNodes(e)))(a) : null, { danger: !0 }), document.body.appendChild(s), s.style.left = `${Math.min(innerWidth - 200 - 8, e)}px`, s.style.top = `${Math.min(innerHeight - s.offsetHeight - 8, t)}px`, bi(s);
4286
+ si = i, n.select(r);
4287
+ } : null, { kbd: "dbl-click" }), s.appendChild(_i()), c("cut", r.length > 0 ? () => vi(n, !0) : null), c("copy", r.length > 0 ? () => vi(n, !1) : null), c(`paste as child${oi ? ` (${oi.nodes.length})` : ""}`, oi ? () => yi(n, r) : null), s.appendChild(_i()), c("delete", r.length > 0 ? () => ($r ?? ((e) => n.removeNodes(e)))(a) : null, { danger: !0 }), document.body.appendChild(s), s.style.left = `${Math.min(innerWidth - 200 - 8, e)}px`, s.style.top = `${Math.min(innerHeight - s.offsetHeight - 8, t)}px`, Si(s);
4265
4288
  }
4266
- function hi() {
4289
+ function _i() {
4267
4290
  let e = document.createElement("div");
4268
4291
  return e.className = "menu-divider", e;
4269
4292
  }
4270
- function gi(e, t) {
4293
+ function vi(e, t) {
4271
4294
  let n = e.allSelections().filter((e) => e.length > 0).map((t) => e.nodeAt(t)).filter((e) => e !== null);
4272
- ii = {
4295
+ oi = {
4273
4296
  nodes: n.map((e) => JSON.parse(JSON.stringify(e))),
4274
4297
  cut: t ? n : null
4275
4298
  };
4276
4299
  }
4277
- function _i(e, t) {
4278
- if (ii) {
4279
- for (let n of ii.nodes) e.insertNode(n, t);
4280
- if (ii.cut) {
4281
- let t = e.working.root, n = ii.cut.map((e) => vi(t, e)).filter((e) => e !== null);
4282
- n.length > 0 && e.removeNodes(n), ii = {
4283
- nodes: ii.nodes,
4300
+ function yi(e, t) {
4301
+ if (oi) {
4302
+ for (let n of oi.nodes) e.insertNode(n, t);
4303
+ if (oi.cut) {
4304
+ let t = e.working.root, n = oi.cut.map((e) => bi(t, e)).filter((e) => e !== null);
4305
+ n.length > 0 && e.removeNodes(n), oi = {
4306
+ nodes: oi.nodes,
4284
4307
  cut: null
4285
4308
  };
4286
4309
  }
4287
4310
  }
4288
4311
  }
4289
- function vi(e, t) {
4312
+ function bi(e, t) {
4290
4313
  if (e === t) return [];
4291
4314
  for (let [n, r] of (e.children ?? []).entries()) {
4292
- let e = vi(r, t);
4315
+ let e = bi(r, t);
4293
4316
  if (e) return [n, ...e];
4294
4317
  }
4295
4318
  return null;
4296
4319
  }
4297
- function yi() {
4320
+ function xi() {
4298
4321
  for (let e of document.querySelectorAll(".floating")) e.remove();
4299
4322
  }
4300
- function bi(e) {
4323
+ function Si(e) {
4301
4324
  let t = (r) => {
4302
4325
  e.contains(r.target) || (e.remove(), document.removeEventListener("pointerdown", t, !0), document.removeEventListener("keydown", n, !0));
4303
4326
  }, n = (r) => {
@@ -4307,39 +4330,39 @@ function bi(e) {
4307
4330
  document.addEventListener("pointerdown", t, !0), document.addEventListener("keydown", n, !0);
4308
4331
  }, 0);
4309
4332
  }
4310
- function xi(e, t) {
4333
+ function Ci(e, t) {
4311
4334
  let n = t.getBoundingClientRect(), r = (e.clientY - n.top) / n.height;
4312
4335
  return r < .25 ? "before" : r > .75 ? "after" : "into";
4313
4336
  }
4314
- function Si(e) {
4337
+ function wi(e) {
4315
4338
  e.classList.remove("drop-into", "drop-before", "drop-after");
4316
4339
  }
4317
- function Ci(e, t, n) {
4340
+ function Ti(e, t, n) {
4318
4341
  e.addEventListener("dragstart", (r) => {
4319
- ri = n.isSelected(t) ? n.allSelections() : [t], r.dataTransfer?.setData("text/plain", ""), r.dataTransfer && (r.dataTransfer.effectAllowed = "move"), e.classList.add("dragging");
4342
+ ai = n.isSelected(t) ? n.allSelections() : [t], r.dataTransfer?.setData("text/plain", ""), r.dataTransfer && (r.dataTransfer.effectAllowed = "move"), e.classList.add("dragging");
4320
4343
  }), e.addEventListener("dragend", () => {
4321
- ri = null, e.classList.remove("dragging");
4344
+ ai = null, e.classList.remove("dragging");
4322
4345
  }), e.addEventListener("dragover", (n) => {
4323
- if (!ri || ri.some((e) => e.length <= t.length && e.every((e, n) => e === t[n]))) return;
4324
- n.preventDefault(), n.dataTransfer && (n.dataTransfer.dropEffect = "move"), Si(e);
4325
- let r = t.length === 0 ? "into" : xi(n, e);
4346
+ if (!ai || ai.some((e) => e.length <= t.length && e.every((e, n) => e === t[n]))) return;
4347
+ n.preventDefault(), n.dataTransfer && (n.dataTransfer.dropEffect = "move"), wi(e);
4348
+ let r = t.length === 0 ? "into" : Ci(n, e);
4326
4349
  e.classList.add(`drop-${r}`);
4327
- }), e.addEventListener("dragleave", () => Si(e)), e.addEventListener("drop", (r) => {
4328
- if (Si(e), !ri) return;
4350
+ }), e.addEventListener("dragleave", () => wi(e)), e.addEventListener("drop", (r) => {
4351
+ if (wi(e), !ai) return;
4329
4352
  r.preventDefault();
4330
- let i = t.length === 0 ? "into" : xi(r, e), a = n.moveNodes(ri, t, i);
4331
- ri = null, a?.[0] && n.select(a[0]);
4353
+ let i = t.length === 0 ? "into" : Ci(r, e), a = n.moveNodes(ai, t, i);
4354
+ ai = null, a?.[0] && n.select(a[0]);
4332
4355
  });
4333
4356
  }
4334
- var wi = 1e3, Ti = 1001, Ei = 1002, Di = 1006, Oi = 1008, ki = 1009, Ai = 1023, ji = 2300, Mi = 2301, Ni = 2302, Pi = 2303, Fi = 2400, Ii = 2401, Li = 2402, Ri = "srgb", zi = "srgb-linear", Bi = "linear", Vi = "srgb", Hi = 2e3;
4335
- function Ui(e) {
4357
+ var Ei = 1e3, Di = 1001, Oi = 1002, ki = 1006, Ai = 1008, ji = 1009, Mi = 1023, Ni = 2300, Pi = 2301, Fi = 2302, Ii = 2303, Li = 2400, Ri = 2401, zi = 2402, Bi = "srgb", Vi = "srgb-linear", Hi = "linear", Ui = "srgb", Wi = 2e3;
4358
+ function Gi(e) {
4336
4359
  return ArrayBuffer.isView(e) && !(e instanceof DataView);
4337
4360
  }
4338
- function Wi(e) {
4361
+ function Ki(e) {
4339
4362
  return document.createElementNS("http://www.w3.org/1999/xhtml", e);
4340
4363
  }
4341
- var Gi = {}, Ki = null;
4342
- function qi(e) {
4364
+ var qi = {}, Ji = null;
4365
+ function Yi(e) {
4343
4366
  let t = e[0];
4344
4367
  if (typeof t == "string" && t.startsWith("TSL:")) {
4345
4368
  let t = e[1];
@@ -4348,28 +4371,28 @@ function qi(e) {
4348
4371
  return e;
4349
4372
  }
4350
4373
  function H(...e) {
4351
- e = qi(e);
4374
+ e = Yi(e);
4352
4375
  let t = "THREE." + e.shift();
4353
- if (Ki) Ki("warn", t, ...e);
4376
+ if (Ji) Ji("warn", t, ...e);
4354
4377
  else {
4355
4378
  let n = e[0];
4356
4379
  n && n.isStackTrace ? console.warn(n.getError(t)) : console.warn(t, ...e);
4357
4380
  }
4358
4381
  }
4359
4382
  function U(...e) {
4360
- e = qi(e);
4383
+ e = Yi(e);
4361
4384
  let t = "THREE." + e.shift();
4362
- if (Ki) Ki("error", t, ...e);
4385
+ if (Ji) Ji("error", t, ...e);
4363
4386
  else {
4364
4387
  let n = e[0];
4365
4388
  n && n.isStackTrace ? console.error(n.getError(t)) : console.error(t, ...e);
4366
4389
  }
4367
4390
  }
4368
- function Ji(...e) {
4391
+ function Xi(...e) {
4369
4392
  let t = e.join(" ");
4370
- t in Gi || (Gi[t] = !0, H(...e));
4393
+ t in qi || (qi[t] = !0, H(...e));
4371
4394
  }
4372
- var Yi = class {
4395
+ var Zi = class {
4373
4396
  addEventListener(e, t) {
4374
4397
  this._listeners === void 0 && (this._listeners = {});
4375
4398
  let n = this._listeners;
@@ -4401,20 +4424,20 @@ var Yi = class {
4401
4424
  }
4402
4425
  }, W = /* @__PURE__ */ "00.01.02.03.04.05.06.07.08.09.0a.0b.0c.0d.0e.0f.10.11.12.13.14.15.16.17.18.19.1a.1b.1c.1d.1e.1f.20.21.22.23.24.25.26.27.28.29.2a.2b.2c.2d.2e.2f.30.31.32.33.34.35.36.37.38.39.3a.3b.3c.3d.3e.3f.40.41.42.43.44.45.46.47.48.49.4a.4b.4c.4d.4e.4f.50.51.52.53.54.55.56.57.58.59.5a.5b.5c.5d.5e.5f.60.61.62.63.64.65.66.67.68.69.6a.6b.6c.6d.6e.6f.70.71.72.73.74.75.76.77.78.79.7a.7b.7c.7d.7e.7f.80.81.82.83.84.85.86.87.88.89.8a.8b.8c.8d.8e.8f.90.91.92.93.94.95.96.97.98.99.9a.9b.9c.9d.9e.9f.a0.a1.a2.a3.a4.a5.a6.a7.a8.a9.aa.ab.ac.ad.ae.af.b0.b1.b2.b3.b4.b5.b6.b7.b8.b9.ba.bb.bc.bd.be.bf.c0.c1.c2.c3.c4.c5.c6.c7.c8.c9.ca.cb.cc.cd.ce.cf.d0.d1.d2.d3.d4.d5.d6.d7.d8.d9.da.db.dc.dd.de.df.e0.e1.e2.e3.e4.e5.e6.e7.e8.e9.ea.eb.ec.ed.ee.ef.f0.f1.f2.f3.f4.f5.f6.f7.f8.f9.fa.fb.fc.fd.fe.ff".split(".");
4403
4426
  Math.PI / 180, 180 / Math.PI;
4404
- function Xi() {
4427
+ function Qi() {
4405
4428
  let e = Math.random() * 4294967295 | 0, t = Math.random() * 4294967295 | 0, n = Math.random() * 4294967295 | 0, r = Math.random() * 4294967295 | 0;
4406
4429
  return (W[e & 255] + W[e >> 8 & 255] + W[e >> 16 & 255] + W[e >> 24 & 255] + "-" + W[t & 255] + W[t >> 8 & 255] + "-" + W[t >> 16 & 15 | 64] + W[t >> 24 & 255] + "-" + W[n & 63 | 128] + W[n >> 8 & 255] + "-" + W[n >> 16 & 255] + W[n >> 24 & 255] + W[r & 255] + W[r >> 8 & 255] + W[r >> 16 & 255] + W[r >> 24 & 255]).toLowerCase();
4407
4430
  }
4408
4431
  function G(e, t, n) {
4409
4432
  return Math.max(t, Math.min(n, e));
4410
4433
  }
4411
- function Zi(e, t) {
4434
+ function $i(e, t) {
4412
4435
  return (e % t + t) % t;
4413
4436
  }
4414
- function Qi(e, t, n) {
4437
+ function ea(e, t, n) {
4415
4438
  return (1 - n) * e + n * t;
4416
4439
  }
4417
- var $i = class e {
4440
+ var ta = class e {
4418
4441
  static {
4419
4442
  e.prototype.isVector2 = !0;
4420
4443
  }
@@ -4606,7 +4629,7 @@ var $i = class e {
4606
4629
  *[Symbol.iterator]() {
4607
4630
  yield this.x, yield this.y;
4608
4631
  }
4609
- }, ea = class {
4632
+ }, na = class {
4610
4633
  constructor(e = 0, t = 0, n = 0, r = 1) {
4611
4634
  this.isQuaternion = !0, this._x = e, this._y = t, this._z = n, this._w = r;
4612
4635
  }
@@ -4876,10 +4899,10 @@ var $i = class e {
4876
4899
  return this.x = e.x * t.x, this.y = e.y * t.y, this.z = e.z * t.z, this;
4877
4900
  }
4878
4901
  applyEuler(e) {
4879
- return this.applyQuaternion(na.setFromEuler(e));
4902
+ return this.applyQuaternion(ia.setFromEuler(e));
4880
4903
  }
4881
4904
  applyAxisAngle(e, t) {
4882
- return this.applyQuaternion(na.setFromAxisAngle(e, t));
4905
+ return this.applyQuaternion(ia.setFromAxisAngle(e, t));
4883
4906
  }
4884
4907
  applyMatrix3(e) {
4885
4908
  let t = this.x, n = this.y, r = this.z, i = e.elements;
@@ -4981,10 +5004,10 @@ var $i = class e {
4981
5004
  return this.copy(e).multiplyScalar(n);
4982
5005
  }
4983
5006
  projectOnPlane(e) {
4984
- return ta.copy(this).projectOnVector(e), this.sub(ta);
5007
+ return ra.copy(this).projectOnVector(e), this.sub(ra);
4985
5008
  }
4986
5009
  reflect(e) {
4987
- return this.sub(ta.copy(e).multiplyScalar(2 * this.dot(e)));
5010
+ return this.sub(ra.copy(e).multiplyScalar(2 * this.dot(e)));
4988
5011
  }
4989
5012
  angleTo(e) {
4990
5013
  let t = Math.sqrt(this.lengthSq() * e.lengthSq());
@@ -5057,7 +5080,7 @@ var $i = class e {
5057
5080
  *[Symbol.iterator]() {
5058
5081
  yield this.x, yield this.y, yield this.z;
5059
5082
  }
5060
- }, ta = /*@__PURE__*/ new K(), na = /*@__PURE__*/ new ea(), ra = class e {
5083
+ }, ra = /*@__PURE__*/ new K(), ia = /*@__PURE__*/ new na(), aa = class e {
5061
5084
  static {
5062
5085
  e.prototype.isMatrix3 = !0;
5063
5086
  }
@@ -5132,13 +5155,13 @@ var $i = class e {
5132
5155
  return this.set(n * s, n * c, -n * (s * a + c * o) + a + e, -r * c, r * s, -r * (-c * a + s * o) + o + t, 0, 0, 1), this;
5133
5156
  }
5134
5157
  scale(e, t) {
5135
- return this.premultiply(ia.makeScale(e, t)), this;
5158
+ return this.premultiply(oa.makeScale(e, t)), this;
5136
5159
  }
5137
5160
  rotate(e) {
5138
- return this.premultiply(ia.makeRotation(-e)), this;
5161
+ return this.premultiply(oa.makeRotation(-e)), this;
5139
5162
  }
5140
5163
  translate(e, t) {
5141
- return this.premultiply(ia.makeTranslation(e, t)), this;
5164
+ return this.premultiply(oa.makeTranslation(e, t)), this;
5142
5165
  }
5143
5166
  makeTranslation(e, t) {
5144
5167
  return e.isVector2 ? this.set(1, 0, e.x, 0, 1, e.y, 0, 0, 1) : this.set(1, 0, e, 0, 1, t, 0, 0, 1), this;
@@ -5166,14 +5189,14 @@ var $i = class e {
5166
5189
  clone() {
5167
5190
  return new this.constructor().fromArray(this.elements);
5168
5191
  }
5169
- }, ia = /*@__PURE__*/ new ra(), aa = /*@__PURE__*/ new ra().set(.4123908, .3575843, .1804808, .212639, .7151687, .0721923, .0193308, .1191948, .9505322), oa = /*@__PURE__*/ new ra().set(3.2409699, -1.5373832, -.4986108, -.9692436, 1.8759675, .0415551, .0556301, -.203977, 1.0569715);
5170
- function sa() {
5192
+ }, oa = /*@__PURE__*/ new aa(), sa = /*@__PURE__*/ new aa().set(.4123908, .3575843, .1804808, .212639, .7151687, .0721923, .0193308, .1191948, .9505322), ca = /*@__PURE__*/ new aa().set(3.2409699, -1.5373832, -.4986108, -.9692436, 1.8759675, .0415551, .0556301, -.203977, 1.0569715);
5193
+ function la() {
5171
5194
  let e = {
5172
5195
  enabled: !0,
5173
- workingColorSpace: zi,
5196
+ workingColorSpace: Vi,
5174
5197
  spaces: {},
5175
5198
  convert: function(e, t, n) {
5176
- return this.enabled === !1 || t === n || !t || !n ? e : (this.spaces[t].transfer === "srgb" && (e.r = ca(e.r), e.g = ca(e.g), e.b = ca(e.b)), this.spaces[t].primaries !== this.spaces[n].primaries && (e.applyMatrix3(this.spaces[t].toXYZ), e.applyMatrix3(this.spaces[n].fromXYZ)), this.spaces[n].transfer === "srgb" && (e.r = la(e.r), e.g = la(e.g), e.b = la(e.b)), e);
5199
+ return this.enabled === !1 || t === n || !t || !n ? e : (this.spaces[t].transfer === "srgb" && (e.r = ua(e.r), e.g = ua(e.g), e.b = ua(e.b)), this.spaces[t].primaries !== this.spaces[n].primaries && (e.applyMatrix3(this.spaces[t].toXYZ), e.applyMatrix3(this.spaces[n].fromXYZ)), this.spaces[n].transfer === "srgb" && (e.r = da(e.r), e.g = da(e.g), e.b = da(e.b)), e);
5177
5200
  },
5178
5201
  workingToColorSpace: function(e, t) {
5179
5202
  return this.convert(e, this.workingColorSpace, t);
@@ -5185,7 +5208,7 @@ function sa() {
5185
5208
  return this.spaces[e].primaries;
5186
5209
  },
5187
5210
  getTransfer: function(e) {
5188
- return e === "" ? Bi : this.spaces[e].transfer;
5211
+ return e === "" ? Hi : this.spaces[e].transfer;
5189
5212
  },
5190
5213
  getToneMappingMode: function(e) {
5191
5214
  return this.spaces[e].outputColorSpaceConfig.toneMappingMode || "standard";
@@ -5206,10 +5229,10 @@ function sa() {
5206
5229
  return this.spaces[e].workingColorSpaceConfig.unpackColorSpace;
5207
5230
  },
5208
5231
  fromWorkingColorSpace: function(t, n) {
5209
- return Ji("ColorManagement: .fromWorkingColorSpace() has been renamed to .workingToColorSpace()."), e.workingToColorSpace(t, n);
5232
+ return Xi("ColorManagement: .fromWorkingColorSpace() has been renamed to .workingToColorSpace()."), e.workingToColorSpace(t, n);
5210
5233
  },
5211
5234
  toWorkingColorSpace: function(t, n) {
5212
- return Ji("ColorManagement: .toWorkingColorSpace() has been renamed to .colorSpaceToWorking()."), e.colorSpaceToWorking(t, n);
5235
+ return Xi("ColorManagement: .toWorkingColorSpace() has been renamed to .colorSpaceToWorking()."), e.colorSpaceToWorking(t, n);
5213
5236
  }
5214
5237
  }, t = [
5215
5238
  .64,
@@ -5224,58 +5247,58 @@ function sa() {
5224
5247
  .0722
5225
5248
  ], r = [.3127, .329];
5226
5249
  return e.define({
5227
- [zi]: {
5250
+ [Vi]: {
5228
5251
  primaries: t,
5229
5252
  whitePoint: r,
5230
- transfer: Bi,
5231
- toXYZ: aa,
5232
- fromXYZ: oa,
5253
+ transfer: Hi,
5254
+ toXYZ: sa,
5255
+ fromXYZ: ca,
5233
5256
  luminanceCoefficients: n,
5234
- workingColorSpaceConfig: { unpackColorSpace: Ri },
5235
- outputColorSpaceConfig: { drawingBufferColorSpace: Ri }
5257
+ workingColorSpaceConfig: { unpackColorSpace: Bi },
5258
+ outputColorSpaceConfig: { drawingBufferColorSpace: Bi }
5236
5259
  },
5237
- [Ri]: {
5260
+ [Bi]: {
5238
5261
  primaries: t,
5239
5262
  whitePoint: r,
5240
- transfer: Vi,
5241
- toXYZ: aa,
5242
- fromXYZ: oa,
5263
+ transfer: Ui,
5264
+ toXYZ: sa,
5265
+ fromXYZ: ca,
5243
5266
  luminanceCoefficients: n,
5244
- outputColorSpaceConfig: { drawingBufferColorSpace: Ri }
5267
+ outputColorSpaceConfig: { drawingBufferColorSpace: Bi }
5245
5268
  }
5246
5269
  }), e;
5247
5270
  }
5248
- var q = /*@__PURE__*/ sa();
5249
- function ca(e) {
5271
+ var q = /*@__PURE__*/ la();
5272
+ function ua(e) {
5250
5273
  return e < .04045 ? e * .0773993808 : (e * .9478672986 + .0521327014) ** 2.4;
5251
5274
  }
5252
- function la(e) {
5275
+ function da(e) {
5253
5276
  return e < .0031308 ? e * 12.92 : 1.055 * e ** .41666 - .055;
5254
5277
  }
5255
- var ua, da = class {
5278
+ var fa, pa = class {
5256
5279
  static getDataURL(e, t = "image/png") {
5257
5280
  if (/^data:/i.test(e.src) || typeof HTMLCanvasElement > "u") return e.src;
5258
5281
  let n;
5259
5282
  if (e instanceof HTMLCanvasElement) n = e;
5260
5283
  else {
5261
- ua === void 0 && (ua = Wi("canvas")), ua.width = e.width, ua.height = e.height;
5262
- let t = ua.getContext("2d");
5263
- e instanceof ImageData ? t.putImageData(e, 0, 0) : t.drawImage(e, 0, 0, e.width, e.height), n = ua;
5284
+ fa === void 0 && (fa = Ki("canvas")), fa.width = e.width, fa.height = e.height;
5285
+ let t = fa.getContext("2d");
5286
+ e instanceof ImageData ? t.putImageData(e, 0, 0) : t.drawImage(e, 0, 0, e.width, e.height), n = fa;
5264
5287
  }
5265
5288
  return n.toDataURL(t);
5266
5289
  }
5267
5290
  static sRGBToLinear(e) {
5268
5291
  if (typeof HTMLImageElement < "u" && e instanceof HTMLImageElement || typeof HTMLCanvasElement < "u" && e instanceof HTMLCanvasElement || typeof ImageBitmap < "u" && e instanceof ImageBitmap) {
5269
- let t = Wi("canvas");
5292
+ let t = Ki("canvas");
5270
5293
  t.width = e.width, t.height = e.height;
5271
5294
  let n = t.getContext("2d");
5272
5295
  n.drawImage(e, 0, 0, e.width, e.height);
5273
5296
  let r = n.getImageData(0, 0, e.width, e.height), i = r.data;
5274
- for (let e = 0; e < i.length; e++) i[e] = ca(i[e] / 255) * 255;
5297
+ for (let e = 0; e < i.length; e++) i[e] = ua(i[e] / 255) * 255;
5275
5298
  return n.putImageData(r, 0, 0), t;
5276
5299
  } else if (e.data) {
5277
5300
  let t = e.data.slice(0);
5278
- for (let e = 0; e < t.length; e++) t instanceof Uint8Array || t instanceof Uint8ClampedArray ? t[e] = Math.floor(ca(t[e] / 255) * 255) : t[e] = ca(t[e]);
5301
+ for (let e = 0; e < t.length; e++) t instanceof Uint8Array || t instanceof Uint8ClampedArray ? t[e] = Math.floor(ua(t[e] / 255) * 255) : t[e] = ua(t[e]);
5279
5302
  return {
5280
5303
  data: t,
5281
5304
  width: e.width,
@@ -5283,9 +5306,9 @@ var ua, da = class {
5283
5306
  };
5284
5307
  } else return H("ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied."), e;
5285
5308
  }
5286
- }, fa = 0, pa = class {
5309
+ }, ma = 0, ha = class {
5287
5310
  constructor(e = null) {
5288
- this.isSource = !0, Object.defineProperty(this, "id", { value: fa++ }), this.uuid = Xi(), this.data = e, this.dataReady = !0, this.version = 0;
5311
+ this.isSource = !0, Object.defineProperty(this, "id", { value: ma++ }), this.uuid = Qi(), this.data = e, this.dataReady = !0, this.version = 0;
5289
5312
  }
5290
5313
  getSize(e) {
5291
5314
  let t = this.data;
@@ -5305,33 +5328,33 @@ var ua, da = class {
5305
5328
  let e;
5306
5329
  if (Array.isArray(r)) {
5307
5330
  e = [];
5308
- for (let t = 0, n = r.length; t < n; t++) r[t].isDataTexture ? e.push(ma(r[t].image)) : e.push(ma(r[t]));
5309
- } else e = ma(r);
5331
+ for (let t = 0, n = r.length; t < n; t++) r[t].isDataTexture ? e.push(ga(r[t].image)) : e.push(ga(r[t]));
5332
+ } else e = ga(r);
5310
5333
  n.url = e;
5311
5334
  }
5312
5335
  return t || (e.images[this.uuid] = n), n;
5313
5336
  }
5314
5337
  };
5315
- function ma(e) {
5316
- return typeof HTMLImageElement < "u" && e instanceof HTMLImageElement || typeof HTMLCanvasElement < "u" && e instanceof HTMLCanvasElement || typeof ImageBitmap < "u" && e instanceof ImageBitmap ? da.getDataURL(e) : e.data ? {
5338
+ function ga(e) {
5339
+ return typeof HTMLImageElement < "u" && e instanceof HTMLImageElement || typeof HTMLCanvasElement < "u" && e instanceof HTMLCanvasElement || typeof ImageBitmap < "u" && e instanceof ImageBitmap ? pa.getDataURL(e) : e.data ? {
5317
5340
  data: Array.from(e.data),
5318
5341
  width: e.width,
5319
5342
  height: e.height,
5320
5343
  type: e.data.constructor.name
5321
5344
  } : (H("Texture: Unable to serialize Texture."), {});
5322
5345
  }
5323
- var ha = 0, ga = /*@__PURE__*/ new K(), _a = class e extends Yi {
5324
- constructor(t = e.DEFAULT_IMAGE, n = e.DEFAULT_MAPPING, r = Ti, i = Ti, a = Di, o = Oi, s = Ai, c = ki, l = e.DEFAULT_ANISOTROPY, u = "") {
5325
- super(), this.isTexture = !0, Object.defineProperty(this, "id", { value: ha++ }), this.uuid = Xi(), this.name = "", this.source = new pa(t), this.mipmaps = [], this.mapping = n, this.channel = 0, this.wrapS = r, this.wrapT = i, this.magFilter = a, this.minFilter = o, this.anisotropy = l, this.format = s, this.internalFormat = null, this.type = c, this.offset = new $i(0, 0), this.repeat = new $i(1, 1), this.center = new $i(0, 0), this.rotation = 0, this.matrixAutoUpdate = !0, this.matrix = new ra(), this.generateMipmaps = !0, this.premultiplyAlpha = !1, this.flipY = !0, this.unpackAlignment = 4, this.colorSpace = u, this.userData = {}, this.updateRanges = [], this.version = 0, this.onUpdate = null, this.renderTarget = null, this.isRenderTargetTexture = !1, this.isArrayTexture = !!(t && t.depth && t.depth > 1), this.pmremVersion = 0, this.normalized = !1;
5346
+ var _a = 0, va = /*@__PURE__*/ new K(), ya = class e extends Zi {
5347
+ constructor(t = e.DEFAULT_IMAGE, n = e.DEFAULT_MAPPING, r = Di, i = Di, a = ki, o = Ai, s = Mi, c = ji, l = e.DEFAULT_ANISOTROPY, u = "") {
5348
+ super(), this.isTexture = !0, Object.defineProperty(this, "id", { value: _a++ }), this.uuid = Qi(), this.name = "", this.source = new ha(t), this.mipmaps = [], this.mapping = n, this.channel = 0, this.wrapS = r, this.wrapT = i, this.magFilter = a, this.minFilter = o, this.anisotropy = l, this.format = s, this.internalFormat = null, this.type = c, this.offset = new ta(0, 0), this.repeat = new ta(1, 1), this.center = new ta(0, 0), this.rotation = 0, this.matrixAutoUpdate = !0, this.matrix = new aa(), this.generateMipmaps = !0, this.premultiplyAlpha = !1, this.flipY = !0, this.unpackAlignment = 4, this.colorSpace = u, this.userData = {}, this.updateRanges = [], this.version = 0, this.onUpdate = null, this.renderTarget = null, this.isRenderTargetTexture = !1, this.isArrayTexture = !!(t && t.depth && t.depth > 1), this.pmremVersion = 0, this.normalized = !1;
5326
5349
  }
5327
5350
  get width() {
5328
- return this.source.getSize(ga).x;
5351
+ return this.source.getSize(va).x;
5329
5352
  }
5330
5353
  get height() {
5331
- return this.source.getSize(ga).y;
5354
+ return this.source.getSize(va).y;
5332
5355
  }
5333
5356
  get depth() {
5334
- return this.source.getSize(ga).z;
5357
+ return this.source.getSize(va).z;
5335
5358
  }
5336
5359
  get image() {
5337
5360
  return this.source.data;
@@ -5412,24 +5435,24 @@ var ha = 0, ga = /*@__PURE__*/ new K(), _a = class e extends Yi {
5412
5435
  transformUv(e) {
5413
5436
  if (this.mapping !== 300) return e;
5414
5437
  if (e.applyMatrix3(this.matrix), e.x < 0 || e.x > 1) switch (this.wrapS) {
5415
- case wi:
5438
+ case Ei:
5416
5439
  e.x -= Math.floor(e.x);
5417
5440
  break;
5418
- case Ti:
5441
+ case Di:
5419
5442
  e.x = e.x < 0 ? 0 : 1;
5420
5443
  break;
5421
- case Ei:
5444
+ case Oi:
5422
5445
  Math.abs(Math.floor(e.x) % 2) === 1 ? e.x = Math.ceil(e.x) - e.x : e.x -= Math.floor(e.x);
5423
5446
  break;
5424
5447
  }
5425
5448
  if (e.y < 0 || e.y > 1) switch (this.wrapT) {
5426
- case wi:
5449
+ case Ei:
5427
5450
  e.y -= Math.floor(e.y);
5428
5451
  break;
5429
- case Ti:
5452
+ case Di:
5430
5453
  e.y = e.y < 0 ? 0 : 1;
5431
5454
  break;
5432
- case Ei:
5455
+ case Oi:
5433
5456
  Math.abs(Math.floor(e.y) % 2) === 1 ? e.y = Math.ceil(e.y) - e.y : e.y -= Math.floor(e.y);
5434
5457
  break;
5435
5458
  }
@@ -5442,7 +5465,7 @@ var ha = 0, ga = /*@__PURE__*/ new K(), _a = class e extends Yi {
5442
5465
  e === !0 && this.pmremVersion++;
5443
5466
  }
5444
5467
  };
5445
- _a.DEFAULT_IMAGE = null, _a.DEFAULT_MAPPING = 300, _a.DEFAULT_ANISOTROPY = 1, class e {
5468
+ ya.DEFAULT_IMAGE = null, ya.DEFAULT_MAPPING = 300, ya.DEFAULT_ANISOTROPY = 1, class e {
5446
5469
  static {
5447
5470
  e.prototype.isVector4 = !0;
5448
5471
  }
@@ -5643,7 +5666,7 @@ _a.DEFAULT_IMAGE = null, _a.DEFAULT_MAPPING = 300, _a.DEFAULT_ANISOTROPY = 1, cl
5643
5666
  yield this.x, yield this.y, yield this.z, yield this.w;
5644
5667
  }
5645
5668
  };
5646
- var va = class e {
5669
+ var ba = class e {
5647
5670
  static {
5648
5671
  e.prototype.isMatrix4 = !0;
5649
5672
  }
@@ -5697,7 +5720,7 @@ var va = class e {
5697
5720
  }
5698
5721
  extractRotation(e) {
5699
5722
  if (e.determinant() === 0) return this.identity();
5700
- let t = this.elements, n = e.elements, r = 1 / ya.setFromMatrixColumn(e, 0).length(), i = 1 / ya.setFromMatrixColumn(e, 1).length(), a = 1 / ya.setFromMatrixColumn(e, 2).length();
5723
+ let t = this.elements, n = e.elements, r = 1 / xa.setFromMatrixColumn(e, 0).length(), i = 1 / xa.setFromMatrixColumn(e, 1).length(), a = 1 / xa.setFromMatrixColumn(e, 2).length();
5701
5724
  return t[0] = n[0] * r, t[1] = n[1] * r, t[2] = n[2] * r, t[3] = 0, t[4] = n[4] * i, t[5] = n[5] * i, t[6] = n[6] * i, t[7] = 0, t[8] = n[8] * a, t[9] = n[9] * a, t[10] = n[10] * a, t[11] = 0, t[12] = 0, t[13] = 0, t[14] = 0, t[15] = 1, this;
5702
5725
  }
5703
5726
  makeRotationFromEuler(e) {
@@ -5724,11 +5747,11 @@ var va = class e {
5724
5747
  return t[3] = 0, t[7] = 0, t[11] = 0, t[12] = 0, t[13] = 0, t[14] = 0, t[15] = 1, this;
5725
5748
  }
5726
5749
  makeRotationFromQuaternion(e) {
5727
- return this.compose(ba, e, xa);
5750
+ return this.compose(Sa, e, Ca);
5728
5751
  }
5729
5752
  lookAt(e, t, n) {
5730
5753
  let r = this.elements;
5731
- return Y.subVectors(e, t), Y.lengthSq() === 0 && (Y.z = 1), Y.normalize(), Sa.crossVectors(n, Y), Sa.lengthSq() === 0 && (Math.abs(n.z) === 1 ? Y.x += 1e-4 : Y.z += 1e-4, Y.normalize(), Sa.crossVectors(n, Y)), Sa.normalize(), Ca.crossVectors(Y, Sa), r[0] = Sa.x, r[4] = Ca.x, r[8] = Y.x, r[1] = Sa.y, r[5] = Ca.y, r[9] = Y.y, r[2] = Sa.z, r[6] = Ca.z, r[10] = Y.z, this;
5754
+ return Y.subVectors(e, t), Y.lengthSq() === 0 && (Y.z = 1), Y.normalize(), wa.crossVectors(n, Y), wa.lengthSq() === 0 && (Math.abs(n.z) === 1 ? Y.x += 1e-4 : Y.z += 1e-4, Y.normalize(), wa.crossVectors(n, Y)), wa.normalize(), Ta.crossVectors(Y, wa), r[0] = wa.x, r[4] = Ta.x, r[8] = Y.x, r[1] = wa.y, r[5] = Ta.y, r[9] = Y.y, r[2] = wa.z, r[6] = Ta.z, r[10] = Y.z, this;
5732
5755
  }
5733
5756
  multiply(e) {
5734
5757
  return this.multiplyMatrices(this, e);
@@ -5804,12 +5827,12 @@ var va = class e {
5804
5827
  e.x = r[12], e.y = r[13], e.z = r[14];
5805
5828
  let i = this.determinant();
5806
5829
  if (i === 0) return n.set(1, 1, 1), t.identity(), this;
5807
- let a = ya.set(r[0], r[1], r[2]).length(), o = ya.set(r[4], r[5], r[6]).length(), s = ya.set(r[8], r[9], r[10]).length();
5830
+ let a = xa.set(r[0], r[1], r[2]).length(), o = xa.set(r[4], r[5], r[6]).length(), s = xa.set(r[8], r[9], r[10]).length();
5808
5831
  i < 0 && (a = -a), J.copy(this);
5809
5832
  let c = 1 / a, l = 1 / o, u = 1 / s;
5810
5833
  return J.elements[0] *= c, J.elements[1] *= c, J.elements[2] *= c, J.elements[4] *= l, J.elements[5] *= l, J.elements[6] *= l, J.elements[8] *= u, J.elements[9] *= u, J.elements[10] *= u, t.setFromRotationMatrix(J), n.x = a, n.y = o, n.z = s, this;
5811
5834
  }
5812
- makePerspective(e, t, n, r, i, a, o = Hi, s = !1) {
5835
+ makePerspective(e, t, n, r, i, a, o = Wi, s = !1) {
5813
5836
  let c = this.elements, l = 2 * i / (t - e), u = 2 * i / (n - r), d = (t + e) / (t - e), f = (n + r) / (n - r), p, m;
5814
5837
  if (s) p = i / (a - i), m = a * i / (a - i);
5815
5838
  else if (o === 2e3) p = -(a + i) / (a - i), m = -2 * a * i / (a - i);
@@ -5817,7 +5840,7 @@ var va = class e {
5817
5840
  else throw Error("THREE.Matrix4.makePerspective(): Invalid coordinate system: " + o);
5818
5841
  return c[0] = l, c[4] = 0, c[8] = d, c[12] = 0, c[1] = 0, c[5] = u, c[9] = f, c[13] = 0, c[2] = 0, c[6] = 0, c[10] = p, c[14] = m, c[3] = 0, c[7] = 0, c[11] = -1, c[15] = 0, this;
5819
5842
  }
5820
- makeOrthographic(e, t, n, r, i, a, o = Hi, s = !1) {
5843
+ makeOrthographic(e, t, n, r, i, a, o = Wi, s = !1) {
5821
5844
  let c = this.elements, l = 2 / (t - e), u = 2 / (n - r), d = -(t + e) / (t - e), f = -(n + r) / (n - r), p, m;
5822
5845
  if (s) p = 1 / (a - i), m = a / (a - i);
5823
5846
  else if (o === 2e3) p = -2 / (a - i), m = -(a + i) / (a - i);
@@ -5838,7 +5861,7 @@ var va = class e {
5838
5861
  let n = this.elements;
5839
5862
  return e[t] = n[0], e[t + 1] = n[1], e[t + 2] = n[2], e[t + 3] = n[3], e[t + 4] = n[4], e[t + 5] = n[5], e[t + 6] = n[6], e[t + 7] = n[7], e[t + 8] = n[8], e[t + 9] = n[9], e[t + 10] = n[10], e[t + 11] = n[11], e[t + 12] = n[12], e[t + 13] = n[13], e[t + 14] = n[14], e[t + 15] = n[15], e;
5840
5863
  }
5841
- }, ya = /*@__PURE__*/ new K(), J = /*@__PURE__*/ new va(), ba = /*@__PURE__*/ new K(0, 0, 0), xa = /*@__PURE__*/ new K(1, 1, 1), Sa = /*@__PURE__*/ new K(), Ca = /*@__PURE__*/ new K(), Y = /*@__PURE__*/ new K(), wa = /*@__PURE__*/ new va(), Ta = /*@__PURE__*/ new ea(), Ea = class e {
5864
+ }, xa = /*@__PURE__*/ new K(), J = /*@__PURE__*/ new ba(), Sa = /*@__PURE__*/ new K(0, 0, 0), Ca = /*@__PURE__*/ new K(1, 1, 1), wa = /*@__PURE__*/ new K(), Ta = /*@__PURE__*/ new K(), Y = /*@__PURE__*/ new K(), Ea = /*@__PURE__*/ new ba(), Da = /*@__PURE__*/ new na(), Oa = class e {
5842
5865
  constructor(t = 0, n = 0, r = 0, i = e.DEFAULT_ORDER) {
5843
5866
  this.isEuler = !0, this._x = t, this._y = n, this._z = r, this._order = i;
5844
5867
  }
@@ -5901,13 +5924,13 @@ var va = class e {
5901
5924
  return this._order = t, n === !0 && this._onChangeCallback(), this;
5902
5925
  }
5903
5926
  setFromQuaternion(e, t, n) {
5904
- return wa.makeRotationFromQuaternion(e), this.setFromRotationMatrix(wa, t, n);
5927
+ return Ea.makeRotationFromQuaternion(e), this.setFromRotationMatrix(Ea, t, n);
5905
5928
  }
5906
5929
  setFromVector3(e, t = this._order) {
5907
5930
  return this.set(e.x, e.y, e.z, t);
5908
5931
  }
5909
5932
  reorder(e) {
5910
- return Ta.setFromEuler(this), this.setFromQuaternion(Ta, e);
5933
+ return Da.setFromEuler(this), this.setFromQuaternion(Da, e);
5911
5934
  }
5912
5935
  equals(e) {
5913
5936
  return e._x === this._x && e._y === this._y && e._z === this._z && e._order === this._order;
@@ -5926,8 +5949,8 @@ var va = class e {
5926
5949
  yield this._x, yield this._y, yield this._z, yield this._order;
5927
5950
  }
5928
5951
  };
5929
- Ea.DEFAULT_ORDER = "XYZ";
5930
- var Da = class {
5952
+ Oa.DEFAULT_ORDER = "XYZ";
5953
+ var ka = class {
5931
5954
  constructor() {
5932
5955
  this.mask = 1;
5933
5956
  }
@@ -5955,16 +5978,16 @@ var Da = class {
5955
5978
  isEnabled(e) {
5956
5979
  return (this.mask & (1 << e | 0)) != 0;
5957
5980
  }
5958
- }, Oa = 0, ka = /*@__PURE__*/ new K(), Aa = /*@__PURE__*/ new ea(), ja = /*@__PURE__*/ new va(), Ma = /*@__PURE__*/ new K(), Na = /*@__PURE__*/ new K(), Pa = /*@__PURE__*/ new K(), Fa = /*@__PURE__*/ new ea(), Ia = /*@__PURE__*/ new K(1, 0, 0), La = /*@__PURE__*/ new K(0, 1, 0), Ra = /*@__PURE__*/ new K(0, 0, 1), za = { type: "added" }, Ba = { type: "removed" }, Va = {
5981
+ }, Aa = 0, ja = /*@__PURE__*/ new K(), Ma = /*@__PURE__*/ new na(), Na = /*@__PURE__*/ new ba(), Pa = /*@__PURE__*/ new K(), Fa = /*@__PURE__*/ new K(), Ia = /*@__PURE__*/ new K(), La = /*@__PURE__*/ new na(), Ra = /*@__PURE__*/ new K(1, 0, 0), za = /*@__PURE__*/ new K(0, 1, 0), Ba = /*@__PURE__*/ new K(0, 0, 1), Va = { type: "added" }, Ha = { type: "removed" }, Ua = {
5959
5982
  type: "childadded",
5960
5983
  child: null
5961
- }, Ha = {
5984
+ }, Wa = {
5962
5985
  type: "childremoved",
5963
5986
  child: null
5964
- }, Ua = class e extends Yi {
5987
+ }, Ga = class e extends Zi {
5965
5988
  constructor() {
5966
- super(), this.isObject3D = !0, Object.defineProperty(this, "id", { value: Oa++ }), this.uuid = Xi(), this.name = "", this.type = "Object3D", this.parent = null, this.children = [], this.up = e.DEFAULT_UP.clone();
5967
- let t = new K(), n = new Ea(), r = new ea(), i = new K(1, 1, 1);
5989
+ super(), this.isObject3D = !0, Object.defineProperty(this, "id", { value: Aa++ }), this.uuid = Qi(), this.name = "", this.type = "Object3D", this.parent = null, this.children = [], this.up = e.DEFAULT_UP.clone();
5990
+ let t = new K(), n = new Oa(), r = new na(), i = new K(1, 1, 1);
5968
5991
  function a() {
5969
5992
  r.setFromEuler(n, !1);
5970
5993
  }
@@ -5992,9 +6015,9 @@ var Da = class {
5992
6015
  enumerable: !0,
5993
6016
  value: i
5994
6017
  },
5995
- modelViewMatrix: { value: new va() },
5996
- normalMatrix: { value: new ra() }
5997
- }), this.matrix = new va(), this.matrixWorld = new va(), this.matrixAutoUpdate = e.DEFAULT_MATRIX_AUTO_UPDATE, this.matrixWorldAutoUpdate = e.DEFAULT_MATRIX_WORLD_AUTO_UPDATE, this.matrixWorldNeedsUpdate = !1, this.layers = new Da(), this.visible = !0, this.castShadow = !1, this.receiveShadow = !1, this.frustumCulled = !0, this.renderOrder = 0, this.animations = [], this.customDepthMaterial = void 0, this.customDistanceMaterial = void 0, this.static = !1, this.userData = {}, this.pivot = null;
6018
+ modelViewMatrix: { value: new ba() },
6019
+ normalMatrix: { value: new aa() }
6020
+ }), this.matrix = new ba(), this.matrixWorld = new ba(), this.matrixAutoUpdate = e.DEFAULT_MATRIX_AUTO_UPDATE, this.matrixWorldAutoUpdate = e.DEFAULT_MATRIX_WORLD_AUTO_UPDATE, this.matrixWorldNeedsUpdate = !1, this.layers = new ka(), this.visible = !0, this.castShadow = !1, this.receiveShadow = !1, this.frustumCulled = !0, this.renderOrder = 0, this.animations = [], this.customDepthMaterial = void 0, this.customDistanceMaterial = void 0, this.static = !1, this.userData = {}, this.pivot = null;
5998
6021
  }
5999
6022
  onBeforeShadow() {}
6000
6023
  onAfterShadow() {}
@@ -6019,49 +6042,49 @@ var Da = class {
6019
6042
  this.quaternion.copy(e);
6020
6043
  }
6021
6044
  rotateOnAxis(e, t) {
6022
- return Aa.setFromAxisAngle(e, t), this.quaternion.multiply(Aa), this;
6045
+ return Ma.setFromAxisAngle(e, t), this.quaternion.multiply(Ma), this;
6023
6046
  }
6024
6047
  rotateOnWorldAxis(e, t) {
6025
- return Aa.setFromAxisAngle(e, t), this.quaternion.premultiply(Aa), this;
6048
+ return Ma.setFromAxisAngle(e, t), this.quaternion.premultiply(Ma), this;
6026
6049
  }
6027
6050
  rotateX(e) {
6028
- return this.rotateOnAxis(Ia, e);
6051
+ return this.rotateOnAxis(Ra, e);
6029
6052
  }
6030
6053
  rotateY(e) {
6031
- return this.rotateOnAxis(La, e);
6054
+ return this.rotateOnAxis(za, e);
6032
6055
  }
6033
6056
  rotateZ(e) {
6034
- return this.rotateOnAxis(Ra, e);
6057
+ return this.rotateOnAxis(Ba, e);
6035
6058
  }
6036
6059
  translateOnAxis(e, t) {
6037
- return ka.copy(e).applyQuaternion(this.quaternion), this.position.add(ka.multiplyScalar(t)), this;
6060
+ return ja.copy(e).applyQuaternion(this.quaternion), this.position.add(ja.multiplyScalar(t)), this;
6038
6061
  }
6039
6062
  translateX(e) {
6040
- return this.translateOnAxis(Ia, e);
6063
+ return this.translateOnAxis(Ra, e);
6041
6064
  }
6042
6065
  translateY(e) {
6043
- return this.translateOnAxis(La, e);
6066
+ return this.translateOnAxis(za, e);
6044
6067
  }
6045
6068
  translateZ(e) {
6046
- return this.translateOnAxis(Ra, e);
6069
+ return this.translateOnAxis(Ba, e);
6047
6070
  }
6048
6071
  localToWorld(e) {
6049
6072
  return this.updateWorldMatrix(!0, !1), e.applyMatrix4(this.matrixWorld);
6050
6073
  }
6051
6074
  worldToLocal(e) {
6052
- return this.updateWorldMatrix(!0, !1), e.applyMatrix4(ja.copy(this.matrixWorld).invert());
6075
+ return this.updateWorldMatrix(!0, !1), e.applyMatrix4(Na.copy(this.matrixWorld).invert());
6053
6076
  }
6054
6077
  lookAt(e, t, n) {
6055
- e.isVector3 ? Ma.copy(e) : Ma.set(e, t, n);
6078
+ e.isVector3 ? Pa.copy(e) : Pa.set(e, t, n);
6056
6079
  let r = this.parent;
6057
- this.updateWorldMatrix(!0, !1), Na.setFromMatrixPosition(this.matrixWorld), this.isCamera || this.isLight ? ja.lookAt(Na, Ma, this.up) : ja.lookAt(Ma, Na, this.up), this.quaternion.setFromRotationMatrix(ja), r && (ja.extractRotation(r.matrixWorld), Aa.setFromRotationMatrix(ja), this.quaternion.premultiply(Aa.invert()));
6080
+ this.updateWorldMatrix(!0, !1), Fa.setFromMatrixPosition(this.matrixWorld), this.isCamera || this.isLight ? Na.lookAt(Fa, Pa, this.up) : Na.lookAt(Pa, Fa, this.up), this.quaternion.setFromRotationMatrix(Na), r && (Na.extractRotation(r.matrixWorld), Ma.setFromRotationMatrix(Na), this.quaternion.premultiply(Ma.invert()));
6058
6081
  }
6059
6082
  add(e) {
6060
6083
  if (arguments.length > 1) {
6061
6084
  for (let e = 0; e < arguments.length; e++) this.add(arguments[e]);
6062
6085
  return this;
6063
6086
  }
6064
- return e === this ? (U("Object3D.add: object can't be added as a child of itself.", e), this) : (e && e.isObject3D ? (e.removeFromParent(), e.parent = this, this.children.push(e), e.dispatchEvent(za), Va.child = e, this.dispatchEvent(Va), Va.child = null) : U("Object3D.add: object not an instance of THREE.Object3D.", e), this);
6087
+ return e === this ? (U("Object3D.add: object can't be added as a child of itself.", e), this) : (e && e.isObject3D ? (e.removeFromParent(), e.parent = this, this.children.push(e), e.dispatchEvent(Va), Ua.child = e, this.dispatchEvent(Ua), Ua.child = null) : U("Object3D.add: object not an instance of THREE.Object3D.", e), this);
6065
6088
  }
6066
6089
  remove(e) {
6067
6090
  if (arguments.length > 1) {
@@ -6069,7 +6092,7 @@ var Da = class {
6069
6092
  return this;
6070
6093
  }
6071
6094
  let t = this.children.indexOf(e);
6072
- return t !== -1 && (e.parent = null, this.children.splice(t, 1), e.dispatchEvent(Ba), Ha.child = e, this.dispatchEvent(Ha), Ha.child = null), this;
6095
+ return t !== -1 && (e.parent = null, this.children.splice(t, 1), e.dispatchEvent(Ha), Wa.child = e, this.dispatchEvent(Wa), Wa.child = null), this;
6073
6096
  }
6074
6097
  removeFromParent() {
6075
6098
  let e = this.parent;
@@ -6079,7 +6102,7 @@ var Da = class {
6079
6102
  return this.remove(...this.children);
6080
6103
  }
6081
6104
  attach(e) {
6082
- return this.updateWorldMatrix(!0, !1), ja.copy(this.matrixWorld).invert(), e.parent !== null && (e.parent.updateWorldMatrix(!0, !1), ja.multiply(e.parent.matrixWorld)), e.applyMatrix4(ja), e.removeFromParent(), e.parent = this, this.children.push(e), e.updateWorldMatrix(!1, !0), e.dispatchEvent(za), Va.child = e, this.dispatchEvent(Va), Va.child = null, this;
6105
+ return this.updateWorldMatrix(!0, !1), Na.copy(this.matrixWorld).invert(), e.parent !== null && (e.parent.updateWorldMatrix(!0, !1), Na.multiply(e.parent.matrixWorld)), e.applyMatrix4(Na), e.removeFromParent(), e.parent = this, this.children.push(e), e.updateWorldMatrix(!1, !0), e.dispatchEvent(Va), Ua.child = e, this.dispatchEvent(Ua), Ua.child = null, this;
6083
6106
  }
6084
6107
  getObjectById(e) {
6085
6108
  return this.getObjectByProperty("id", e);
@@ -6104,10 +6127,10 @@ var Da = class {
6104
6127
  return this.updateWorldMatrix(!0, !1), e.setFromMatrixPosition(this.matrixWorld);
6105
6128
  }
6106
6129
  getWorldQuaternion(e) {
6107
- return this.updateWorldMatrix(!0, !1), this.matrixWorld.decompose(Na, e, Pa), e;
6130
+ return this.updateWorldMatrix(!0, !1), this.matrixWorld.decompose(Fa, e, Ia), e;
6108
6131
  }
6109
6132
  getWorldScale(e) {
6110
- return this.updateWorldMatrix(!0, !1), this.matrixWorld.decompose(Na, Fa, e), e;
6133
+ return this.updateWorldMatrix(!0, !1), this.matrixWorld.decompose(Fa, La, e), e;
6111
6134
  }
6112
6135
  getWorldDirection(e) {
6113
6136
  this.updateWorldMatrix(!0, !1);
@@ -6230,8 +6253,8 @@ var Da = class {
6230
6253
  return this;
6231
6254
  }
6232
6255
  };
6233
- Ua.DEFAULT_UP = /*@__PURE__*/ new K(0, 1, 0), Ua.DEFAULT_MATRIX_AUTO_UPDATE = !0, Ua.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = !0;
6234
- var Wa = {
6256
+ Ga.DEFAULT_UP = /*@__PURE__*/ new K(0, 1, 0), Ga.DEFAULT_MATRIX_AUTO_UPDATE = !0, Ga.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = !0;
6257
+ var Ka = {
6235
6258
  aliceblue: 15792383,
6236
6259
  antiquewhite: 16444375,
6237
6260
  aqua: 65535,
@@ -6380,19 +6403,19 @@ var Wa = {
6380
6403
  whitesmoke: 16119285,
6381
6404
  yellow: 16776960,
6382
6405
  yellowgreen: 10145074
6383
- }, Ga = {
6406
+ }, qa = {
6384
6407
  h: 0,
6385
6408
  s: 0,
6386
6409
  l: 0
6387
- }, Ka = {
6410
+ }, Ja = {
6388
6411
  h: 0,
6389
6412
  s: 0,
6390
6413
  l: 0
6391
6414
  };
6392
- function qa(e, t, n) {
6415
+ function Ya(e, t, n) {
6393
6416
  return n < 0 && (n += 1), n > 1 && --n, n < 1 / 6 ? e + (t - e) * 6 * n : n < 1 / 2 ? t : n < 2 / 3 ? e + (t - e) * 6 * (2 / 3 - n) : e;
6394
6417
  }
6395
- var Ja = class {
6418
+ var Xa = class {
6396
6419
  constructor(e, t, n) {
6397
6420
  return this.isColor = !0, this.r = 1, this.g = 1, this.b = 1, this.set(e, t, n);
6398
6421
  }
@@ -6406,21 +6429,21 @@ var Ja = class {
6406
6429
  setScalar(e) {
6407
6430
  return this.r = e, this.g = e, this.b = e, this;
6408
6431
  }
6409
- setHex(e, t = Ri) {
6432
+ setHex(e, t = Bi) {
6410
6433
  return e = Math.floor(e), this.r = (e >> 16 & 255) / 255, this.g = (e >> 8 & 255) / 255, this.b = (e & 255) / 255, q.colorSpaceToWorking(this, t), this;
6411
6434
  }
6412
6435
  setRGB(e, t, n, r = q.workingColorSpace) {
6413
6436
  return this.r = e, this.g = t, this.b = n, q.colorSpaceToWorking(this, r), this;
6414
6437
  }
6415
6438
  setHSL(e, t, n, r = q.workingColorSpace) {
6416
- if (e = Zi(e, 1), t = G(t, 0, 1), n = G(n, 0, 1), t === 0) this.r = this.g = this.b = n;
6439
+ if (e = $i(e, 1), t = G(t, 0, 1), n = G(n, 0, 1), t === 0) this.r = this.g = this.b = n;
6417
6440
  else {
6418
6441
  let r = n <= .5 ? n * (1 + t) : n + t - n * t, i = 2 * n - r;
6419
- this.r = qa(i, r, e + 1 / 3), this.g = qa(i, r, e), this.b = qa(i, r, e - 1 / 3);
6442
+ this.r = Ya(i, r, e + 1 / 3), this.g = Ya(i, r, e), this.b = Ya(i, r, e - 1 / 3);
6420
6443
  }
6421
6444
  return q.colorSpaceToWorking(this, r), this;
6422
6445
  }
6423
- setStyle(e, t = Ri) {
6446
+ setStyle(e, t = Bi) {
6424
6447
  function n(t) {
6425
6448
  t !== void 0 && parseFloat(t) < 1 && H("Color: Alpha component of " + e + " will be ignored.");
6426
6449
  }
@@ -6447,8 +6470,8 @@ var Ja = class {
6447
6470
  } else if (e && e.length > 0) return this.setColorName(e, t);
6448
6471
  return this;
6449
6472
  }
6450
- setColorName(e, t = Ri) {
6451
- let n = Wa[e.toLowerCase()];
6473
+ setColorName(e, t = Bi) {
6474
+ let n = Ka[e.toLowerCase()];
6452
6475
  return n === void 0 ? H("Color: Unknown color " + e) : this.setHex(n, t), this;
6453
6476
  }
6454
6477
  clone() {
@@ -6458,10 +6481,10 @@ var Ja = class {
6458
6481
  return this.r = e.r, this.g = e.g, this.b = e.b, this;
6459
6482
  }
6460
6483
  copySRGBToLinear(e) {
6461
- return this.r = ca(e.r), this.g = ca(e.g), this.b = ca(e.b), this;
6484
+ return this.r = ua(e.r), this.g = ua(e.g), this.b = ua(e.b), this;
6462
6485
  }
6463
6486
  copyLinearToSRGB(e) {
6464
- return this.r = la(e.r), this.g = la(e.g), this.b = la(e.b), this;
6487
+ return this.r = da(e.r), this.g = da(e.g), this.b = da(e.b), this;
6465
6488
  }
6466
6489
  convertSRGBToLinear() {
6467
6490
  return this.copySRGBToLinear(this), this;
@@ -6469,10 +6492,10 @@ var Ja = class {
6469
6492
  convertLinearToSRGB() {
6470
6493
  return this.copyLinearToSRGB(this), this;
6471
6494
  }
6472
- getHex(e = Ri) {
6495
+ getHex(e = Bi) {
6473
6496
  return q.workingToColorSpace(X.copy(this), e), Math.round(G(X.r * 255, 0, 255)) * 65536 + Math.round(G(X.g * 255, 0, 255)) * 256 + Math.round(G(X.b * 255, 0, 255));
6474
6497
  }
6475
- getHexString(e = Ri) {
6498
+ getHexString(e = Bi) {
6476
6499
  return ("000000" + this.getHex(e).toString(16)).slice(-6);
6477
6500
  }
6478
6501
  getHSL(e, t = q.workingColorSpace) {
@@ -6499,13 +6522,13 @@ var Ja = class {
6499
6522
  getRGB(e, t = q.workingColorSpace) {
6500
6523
  return q.workingToColorSpace(X.copy(this), t), e.r = X.r, e.g = X.g, e.b = X.b, e;
6501
6524
  }
6502
- getStyle(e = Ri) {
6525
+ getStyle(e = Bi) {
6503
6526
  q.workingToColorSpace(X.copy(this), e);
6504
6527
  let t = X.r, n = X.g, r = X.b;
6505
6528
  return e === "srgb" ? `rgb(${Math.round(t * 255)},${Math.round(n * 255)},${Math.round(r * 255)})` : `color(${e} ${t.toFixed(3)} ${n.toFixed(3)} ${r.toFixed(3)})`;
6506
6529
  }
6507
6530
  offsetHSL(e, t, n) {
6508
- return this.getHSL(Ga), this.setHSL(Ga.h + e, Ga.s + t, Ga.l + n);
6531
+ return this.getHSL(qa), this.setHSL(qa.h + e, qa.s + t, qa.l + n);
6509
6532
  }
6510
6533
  add(e) {
6511
6534
  return this.r += e.r, this.g += e.g, this.b += e.b, this;
@@ -6532,8 +6555,8 @@ var Ja = class {
6532
6555
  return this.r = e.r + (t.r - e.r) * n, this.g = e.g + (t.g - e.g) * n, this.b = e.b + (t.b - e.b) * n, this;
6533
6556
  }
6534
6557
  lerpHSL(e, t) {
6535
- this.getHSL(Ga), e.getHSL(Ka);
6536
- let n = Qi(Ga.h, Ka.h, t), r = Qi(Ga.s, Ka.s, t), i = Qi(Ga.l, Ka.l, t);
6558
+ this.getHSL(qa), e.getHSL(Ja);
6559
+ let n = ea(qa.h, Ja.h, t), r = ea(qa.s, Ja.s, t), i = ea(qa.l, Ja.l, t);
6537
6560
  return this.setHSL(n, r, i), this;
6538
6561
  }
6539
6562
  setFromVector3(e) {
@@ -6561,9 +6584,9 @@ var Ja = class {
6561
6584
  *[Symbol.iterator]() {
6562
6585
  yield this.r, yield this.g, yield this.b;
6563
6586
  }
6564
- }, X = /*@__PURE__*/ new Ja();
6565
- Ja.NAMES = Wa;
6566
- var Ya = class {
6587
+ }, X = /*@__PURE__*/ new Xa();
6588
+ Xa.NAMES = Ka;
6589
+ var Za = class {
6567
6590
  constructor(e = new K(Infinity, Infinity, Infinity), t = new K(-Infinity, -Infinity, -Infinity)) {
6568
6591
  this.isBox3 = !0, this.min = e, this.max = t;
6569
6592
  }
@@ -6625,7 +6648,7 @@ var Ya = class {
6625
6648
  if (n !== void 0) {
6626
6649
  let r = n.getAttribute("position");
6627
6650
  if (t === !0 && r !== void 0 && e.isInstancedMesh !== !0) for (let t = 0, n = r.count; t < n; t++) e.isMesh === !0 ? e.getVertexPosition(t, Z) : Z.fromBufferAttribute(r, t), Z.applyMatrix4(e.matrixWorld), this.expandByPoint(Z);
6628
- else e.boundingBox === void 0 ? (n.boundingBox === null && n.computeBoundingBox(), Za.copy(n.boundingBox)) : (e.boundingBox === null && e.computeBoundingBox(), Za.copy(e.boundingBox)), Za.applyMatrix4(e.matrixWorld), this.union(Za);
6651
+ else e.boundingBox === void 0 ? (n.boundingBox === null && n.computeBoundingBox(), $a.copy(n.boundingBox)) : (e.boundingBox === null && e.computeBoundingBox(), $a.copy(e.boundingBox)), $a.applyMatrix4(e.matrixWorld), this.union($a);
6629
6652
  }
6630
6653
  let r = e.children;
6631
6654
  for (let e = 0, n = r.length; e < n; e++) this.expandByObject(r[e], t);
@@ -6652,37 +6675,37 @@ var Ya = class {
6652
6675
  }
6653
6676
  intersectsTriangle(e) {
6654
6677
  if (this.isEmpty()) return !1;
6655
- this.getCenter(io), ao.subVectors(this.max, io), Qa.subVectors(e.a, io), $a.subVectors(e.b, io), eo.subVectors(e.c, io), to.subVectors($a, Qa), no.subVectors(eo, $a), ro.subVectors(Qa, eo);
6678
+ this.getCenter(oo), so.subVectors(this.max, oo), eo.subVectors(e.a, oo), to.subVectors(e.b, oo), no.subVectors(e.c, oo), ro.subVectors(to, eo), io.subVectors(no, to), ao.subVectors(eo, no);
6656
6679
  let t = [
6657
- 0,
6658
- -to.z,
6659
- to.y,
6660
- 0,
6661
- -no.z,
6662
- no.y,
6663
6680
  0,
6664
6681
  -ro.z,
6665
6682
  ro.y,
6666
- to.z,
6667
6683
  0,
6668
- -to.x,
6669
- no.z,
6684
+ -io.z,
6685
+ io.y,
6670
6686
  0,
6671
- -no.x,
6687
+ -ao.z,
6688
+ ao.y,
6672
6689
  ro.z,
6673
6690
  0,
6674
6691
  -ro.x,
6675
- -to.y,
6676
- to.x,
6692
+ io.z,
6677
6693
  0,
6678
- -no.y,
6679
- no.x,
6694
+ -io.x,
6695
+ ao.z,
6680
6696
  0,
6697
+ -ao.x,
6681
6698
  -ro.y,
6682
6699
  ro.x,
6700
+ 0,
6701
+ -io.y,
6702
+ io.x,
6703
+ 0,
6704
+ -ao.y,
6705
+ ao.x,
6683
6706
  0
6684
6707
  ];
6685
- return !co(t, Qa, $a, eo, ao) || (t = [
6708
+ return !uo(t, eo, to, no, so) || (t = [
6686
6709
  1,
6687
6710
  0,
6688
6711
  0,
@@ -6692,11 +6715,11 @@ var Ya = class {
6692
6715
  0,
6693
6716
  0,
6694
6717
  1
6695
- ], !co(t, Qa, $a, eo, ao)) ? !1 : (oo.crossVectors(to, no), t = [
6696
- oo.x,
6697
- oo.y,
6698
- oo.z
6699
- ], co(t, Qa, $a, eo, ao));
6718
+ ], !uo(t, eo, to, no, so)) ? !1 : (co.crossVectors(ro, io), t = [
6719
+ co.x,
6720
+ co.y,
6721
+ co.z
6722
+ ], uo(t, eo, to, no, so));
6700
6723
  }
6701
6724
  clampPoint(e, t) {
6702
6725
  return t.copy(e).clamp(this.min, this.max);
@@ -6714,7 +6737,7 @@ var Ya = class {
6714
6737
  return this.min.min(e.min), this.max.max(e.max), this;
6715
6738
  }
6716
6739
  applyMatrix4(e) {
6717
- return this.isEmpty() ? this : (Xa[0].set(this.min.x, this.min.y, this.min.z).applyMatrix4(e), Xa[1].set(this.min.x, this.min.y, this.max.z).applyMatrix4(e), Xa[2].set(this.min.x, this.max.y, this.min.z).applyMatrix4(e), Xa[3].set(this.min.x, this.max.y, this.max.z).applyMatrix4(e), Xa[4].set(this.max.x, this.min.y, this.min.z).applyMatrix4(e), Xa[5].set(this.max.x, this.min.y, this.max.z).applyMatrix4(e), Xa[6].set(this.max.x, this.max.y, this.min.z).applyMatrix4(e), Xa[7].set(this.max.x, this.max.y, this.max.z).applyMatrix4(e), this.setFromPoints(Xa), this);
6740
+ return this.isEmpty() ? this : (Qa[0].set(this.min.x, this.min.y, this.min.z).applyMatrix4(e), Qa[1].set(this.min.x, this.min.y, this.max.z).applyMatrix4(e), Qa[2].set(this.min.x, this.max.y, this.min.z).applyMatrix4(e), Qa[3].set(this.min.x, this.max.y, this.max.z).applyMatrix4(e), Qa[4].set(this.max.x, this.min.y, this.min.z).applyMatrix4(e), Qa[5].set(this.max.x, this.min.y, this.max.z).applyMatrix4(e), Qa[6].set(this.max.x, this.max.y, this.min.z).applyMatrix4(e), Qa[7].set(this.max.x, this.max.y, this.max.z).applyMatrix4(e), this.setFromPoints(Qa), this);
6718
6741
  }
6719
6742
  translate(e) {
6720
6743
  return this.min.add(e), this.max.add(e), this;
@@ -6731,7 +6754,7 @@ var Ya = class {
6731
6754
  fromJSON(e) {
6732
6755
  return this.min.fromArray(e.min), this.max.fromArray(e.max), this;
6733
6756
  }
6734
- }, Xa = [
6757
+ }, Qa = [
6735
6758
  /*@__PURE__*/ new K(),
6736
6759
  /*@__PURE__*/ new K(),
6737
6760
  /*@__PURE__*/ new K(),
@@ -6740,19 +6763,19 @@ var Ya = class {
6740
6763
  /*@__PURE__*/ new K(),
6741
6764
  /*@__PURE__*/ new K(),
6742
6765
  /*@__PURE__*/ new K()
6743
- ], Z = /*@__PURE__*/ new K(), Za = /*@__PURE__*/ new Ya(), Qa = /*@__PURE__*/ new K(), $a = /*@__PURE__*/ new K(), eo = /*@__PURE__*/ new K(), to = /*@__PURE__*/ new K(), no = /*@__PURE__*/ new K(), ro = /*@__PURE__*/ new K(), io = /*@__PURE__*/ new K(), ao = /*@__PURE__*/ new K(), oo = /*@__PURE__*/ new K(), so = /*@__PURE__*/ new K();
6744
- function co(e, t, n, r, i) {
6766
+ ], Z = /*@__PURE__*/ new K(), $a = /*@__PURE__*/ new Za(), eo = /*@__PURE__*/ new K(), to = /*@__PURE__*/ new K(), no = /*@__PURE__*/ new K(), ro = /*@__PURE__*/ new K(), io = /*@__PURE__*/ new K(), ao = /*@__PURE__*/ new K(), oo = /*@__PURE__*/ new K(), so = /*@__PURE__*/ new K(), co = /*@__PURE__*/ new K(), lo = /*@__PURE__*/ new K();
6767
+ function uo(e, t, n, r, i) {
6745
6768
  for (let a = 0, o = e.length - 3; a <= o; a += 3) {
6746
- so.fromArray(e, a);
6747
- let o = i.x * Math.abs(so.x) + i.y * Math.abs(so.y) + i.z * Math.abs(so.z), s = t.dot(so), c = n.dot(so), l = r.dot(so);
6769
+ lo.fromArray(e, a);
6770
+ let o = i.x * Math.abs(lo.x) + i.y * Math.abs(lo.y) + i.z * Math.abs(lo.z), s = t.dot(lo), c = n.dot(lo), l = r.dot(lo);
6748
6771
  if (Math.max(-Math.max(s, c, l), Math.min(s, c, l)) > o) return !1;
6749
6772
  }
6750
6773
  return !0;
6751
6774
  }
6752
- function lo(e, t) {
6775
+ function fo(e, t) {
6753
6776
  return !e || e.constructor === t ? e : typeof t.BYTES_PER_ELEMENT == "number" ? new t(e) : Array.prototype.slice.call(e);
6754
6777
  }
6755
- var uo = class {
6778
+ var po = class {
6756
6779
  constructor(e, t, n, r) {
6757
6780
  this.parameterPositions = e, this._cachedIndex = 0, this.resultBuffer = r === void 0 ? new t.constructor(n) : r, this.sampleValues = t, this.valueSize = n, this.settings = null, this.DefaultSettings_ = {};
6758
6781
  }
@@ -6810,29 +6833,29 @@ var uo = class {
6810
6833
  throw Error("call to abstract method");
6811
6834
  }
6812
6835
  intervalChanged_() {}
6813
- }, fo = class extends uo {
6836
+ }, mo = class extends po {
6814
6837
  constructor(e, t, n, r) {
6815
6838
  super(e, t, n, r), this._weightPrev = -0, this._offsetPrev = -0, this._weightNext = -0, this._offsetNext = -0, this.DefaultSettings_ = {
6816
- endingStart: Fi,
6817
- endingEnd: Fi
6839
+ endingStart: Li,
6840
+ endingEnd: Li
6818
6841
  };
6819
6842
  }
6820
6843
  intervalChanged_(e, t, n) {
6821
6844
  let r = this.parameterPositions, i = e - 2, a = e + 1, o = r[i], s = r[a];
6822
6845
  if (o === void 0) switch (this.getSettings_().endingStart) {
6823
- case Ii:
6846
+ case Ri:
6824
6847
  i = e, o = 2 * t - n;
6825
6848
  break;
6826
- case Li:
6849
+ case zi:
6827
6850
  i = r.length - 2, o = t + r[i] - r[i + 1];
6828
6851
  break;
6829
6852
  default: i = e, o = n;
6830
6853
  }
6831
6854
  if (s === void 0) switch (this.getSettings_().endingEnd) {
6832
- case Ii:
6855
+ case Ri:
6833
6856
  a = e, s = 2 * n - t;
6834
6857
  break;
6835
- case Li:
6858
+ case zi:
6836
6859
  a = 1, s = n + r[1] - r[0];
6837
6860
  break;
6838
6861
  default: a = e - 1, s = t;
@@ -6845,7 +6868,7 @@ var uo = class {
6845
6868
  for (let e = 0; e !== o; ++e) i[e] = g * a[l + e] + _ * a[c + e] + v * a[s + e] + y * a[u + e];
6846
6869
  return i;
6847
6870
  }
6848
- }, po = class extends uo {
6871
+ }, ho = class extends po {
6849
6872
  constructor(e, t, n, r) {
6850
6873
  super(e, t, n, r);
6851
6874
  }
@@ -6854,14 +6877,14 @@ var uo = class {
6854
6877
  for (let e = 0; e !== o; ++e) i[e] = a[c + e] * u + a[s + e] * l;
6855
6878
  return i;
6856
6879
  }
6857
- }, mo = class extends uo {
6880
+ }, go = class extends po {
6858
6881
  constructor(e, t, n, r) {
6859
6882
  super(e, t, n, r);
6860
6883
  }
6861
6884
  interpolate_(e) {
6862
6885
  return this.copySampleValue_(e - 1);
6863
6886
  }
6864
- }, ho = class extends uo {
6887
+ }, _o = class extends po {
6865
6888
  interpolate_(e, t, n, r) {
6866
6889
  let i = this.resultBuffer, a = this.sampleValues, o = this.valueSize, s = e * o, c = s - o, l = this.settings || this.DefaultSettings_, u = l.inTangents, d = l.outTangents;
6867
6890
  if (!u || !d) {
@@ -6884,11 +6907,11 @@ var uo = class {
6884
6907
  }
6885
6908
  return i;
6886
6909
  }
6887
- }, go = class {
6910
+ }, vo = class {
6888
6911
  constructor(e, t, n, r) {
6889
6912
  if (e === void 0) throw Error("THREE.KeyframeTrack: track name is undefined");
6890
6913
  if (t === void 0 || t.length === 0) throw Error("THREE.KeyframeTrack: no keyframes in track named " + e);
6891
- this.name = e, this.times = lo(t, this.TimeBufferType), this.values = lo(n, this.ValueBufferType), this.setInterpolation(r || this.DefaultInterpolation);
6914
+ this.name = e, this.times = fo(t, this.TimeBufferType), this.values = fo(n, this.ValueBufferType), this.setInterpolation(r || this.DefaultInterpolation);
6892
6915
  }
6893
6916
  static toJSON(e) {
6894
6917
  let t = e.constructor, n;
@@ -6896,8 +6919,8 @@ var uo = class {
6896
6919
  else {
6897
6920
  n = {
6898
6921
  name: e.name,
6899
- times: lo(e.times, Array),
6900
- values: lo(e.values, Array)
6922
+ times: fo(e.times, Array),
6923
+ values: fo(e.values, Array)
6901
6924
  };
6902
6925
  let t = e.getInterpolation();
6903
6926
  t !== e.DefaultInterpolation && (n.interpolation = t);
@@ -6905,31 +6928,31 @@ var uo = class {
6905
6928
  return n.type = e.ValueTypeName, n;
6906
6929
  }
6907
6930
  InterpolantFactoryMethodDiscrete(e) {
6908
- return new mo(this.times, this.values, this.getValueSize(), e);
6931
+ return new go(this.times, this.values, this.getValueSize(), e);
6909
6932
  }
6910
6933
  InterpolantFactoryMethodLinear(e) {
6911
- return new po(this.times, this.values, this.getValueSize(), e);
6934
+ return new ho(this.times, this.values, this.getValueSize(), e);
6912
6935
  }
6913
6936
  InterpolantFactoryMethodSmooth(e) {
6914
- return new fo(this.times, this.values, this.getValueSize(), e);
6937
+ return new mo(this.times, this.values, this.getValueSize(), e);
6915
6938
  }
6916
6939
  InterpolantFactoryMethodBezier(e) {
6917
- let t = new ho(this.times, this.values, this.getValueSize(), e);
6940
+ let t = new _o(this.times, this.values, this.getValueSize(), e);
6918
6941
  return this.settings && (t.settings = this.settings), t;
6919
6942
  }
6920
6943
  setInterpolation(e) {
6921
6944
  let t;
6922
6945
  switch (e) {
6923
- case ji:
6946
+ case Ni:
6924
6947
  t = this.InterpolantFactoryMethodDiscrete;
6925
6948
  break;
6926
- case Mi:
6949
+ case Pi:
6927
6950
  t = this.InterpolantFactoryMethodLinear;
6928
6951
  break;
6929
- case Ni:
6952
+ case Fi:
6930
6953
  t = this.InterpolantFactoryMethodSmooth;
6931
6954
  break;
6932
- case Pi:
6955
+ case Ii:
6933
6956
  t = this.InterpolantFactoryMethodBezier;
6934
6957
  break;
6935
6958
  }
@@ -6943,10 +6966,10 @@ var uo = class {
6943
6966
  }
6944
6967
  getInterpolation() {
6945
6968
  switch (this.createInterpolant) {
6946
- case this.InterpolantFactoryMethodDiscrete: return ji;
6947
- case this.InterpolantFactoryMethodLinear: return Mi;
6948
- case this.InterpolantFactoryMethodSmooth: return Ni;
6949
- case this.InterpolantFactoryMethodBezier: return Pi;
6969
+ case this.InterpolantFactoryMethodDiscrete: return Ni;
6970
+ case this.InterpolantFactoryMethodLinear: return Pi;
6971
+ case this.InterpolantFactoryMethodSmooth: return Fi;
6972
+ case this.InterpolantFactoryMethodBezier: return Ii;
6950
6973
  }
6951
6974
  }
6952
6975
  getValueSize() {
@@ -6995,7 +7018,7 @@ var uo = class {
6995
7018
  }
6996
7019
  a = r;
6997
7020
  }
6998
- if (r !== void 0 && Ui(r)) for (let t = 0, n = r.length; t !== n; ++t) {
7021
+ if (r !== void 0 && Gi(r)) for (let t = 0, n = r.length; t !== n; ++t) {
6999
7022
  let n = r[t];
7000
7023
  if (isNaN(n)) {
7001
7024
  U("KeyframeTrack: Value is not a valid number.", this, t, n), e = !1;
@@ -7005,7 +7028,7 @@ var uo = class {
7005
7028
  return e;
7006
7029
  }
7007
7030
  optimize() {
7008
- let e = this.times.slice(), t = this.values.slice(), n = this.getValueSize(), r = this.getInterpolation() === Ni, i = e.length - 1, a = 1;
7031
+ let e = this.times.slice(), t = this.values.slice(), n = this.getValueSize(), r = this.getInterpolation() === Fi, i = e.length - 1, a = 1;
7009
7032
  for (let o = 1; o < i; ++o) {
7010
7033
  let i = !1, s = e[o];
7011
7034
  if (s !== e[o + 1] && (o !== 1 || s !== e[0])) if (r) i = !0;
@@ -7040,56 +7063,56 @@ var uo = class {
7040
7063
  return r.createInterpolant = this.createInterpolant, r;
7041
7064
  }
7042
7065
  };
7043
- go.prototype.ValueTypeName = "", go.prototype.TimeBufferType = Float32Array, go.prototype.ValueBufferType = Float32Array, go.prototype.DefaultInterpolation = Mi;
7044
- var _o = class extends go {
7066
+ vo.prototype.ValueTypeName = "", vo.prototype.TimeBufferType = Float32Array, vo.prototype.ValueBufferType = Float32Array, vo.prototype.DefaultInterpolation = Pi;
7067
+ var yo = class extends vo {
7045
7068
  constructor(e, t, n) {
7046
7069
  super(e, t, n);
7047
7070
  }
7048
7071
  };
7049
- _o.prototype.ValueTypeName = "bool", _o.prototype.ValueBufferType = Array, _o.prototype.DefaultInterpolation = ji, _o.prototype.InterpolantFactoryMethodLinear = void 0, _o.prototype.InterpolantFactoryMethodSmooth = void 0;
7050
- var vo = class extends go {
7072
+ yo.prototype.ValueTypeName = "bool", yo.prototype.ValueBufferType = Array, yo.prototype.DefaultInterpolation = Ni, yo.prototype.InterpolantFactoryMethodLinear = void 0, yo.prototype.InterpolantFactoryMethodSmooth = void 0;
7073
+ var bo = class extends vo {
7051
7074
  constructor(e, t, n, r) {
7052
7075
  super(e, t, n, r);
7053
7076
  }
7054
7077
  };
7055
- vo.prototype.ValueTypeName = "color";
7056
- var yo = class extends go {
7078
+ bo.prototype.ValueTypeName = "color";
7079
+ var xo = class extends vo {
7057
7080
  constructor(e, t, n, r) {
7058
7081
  super(e, t, n, r);
7059
7082
  }
7060
7083
  };
7061
- yo.prototype.ValueTypeName = "number";
7062
- var bo = class extends uo {
7084
+ xo.prototype.ValueTypeName = "number";
7085
+ var So = class extends po {
7063
7086
  constructor(e, t, n, r) {
7064
7087
  super(e, t, n, r);
7065
7088
  }
7066
7089
  interpolate_(e, t, n, r) {
7067
7090
  let i = this.resultBuffer, a = this.sampleValues, o = this.valueSize, s = (n - t) / (r - t), c = e * o;
7068
- for (let e = c + o; c !== e; c += 4) ea.slerpFlat(i, 0, a, c - o, a, c, s);
7091
+ for (let e = c + o; c !== e; c += 4) na.slerpFlat(i, 0, a, c - o, a, c, s);
7069
7092
  return i;
7070
7093
  }
7071
- }, xo = class extends go {
7094
+ }, Co = class extends vo {
7072
7095
  constructor(e, t, n, r) {
7073
7096
  super(e, t, n, r);
7074
7097
  }
7075
7098
  InterpolantFactoryMethodLinear(e) {
7076
- return new bo(this.times, this.values, this.getValueSize(), e);
7099
+ return new So(this.times, this.values, this.getValueSize(), e);
7077
7100
  }
7078
7101
  };
7079
- xo.prototype.ValueTypeName = "quaternion", xo.prototype.InterpolantFactoryMethodSmooth = void 0;
7080
- var So = class extends go {
7102
+ Co.prototype.ValueTypeName = "quaternion", Co.prototype.InterpolantFactoryMethodSmooth = void 0;
7103
+ var wo = class extends vo {
7081
7104
  constructor(e, t, n) {
7082
7105
  super(e, t, n);
7083
7106
  }
7084
7107
  };
7085
- So.prototype.ValueTypeName = "string", So.prototype.ValueBufferType = Array, So.prototype.DefaultInterpolation = ji, So.prototype.InterpolantFactoryMethodLinear = void 0, So.prototype.InterpolantFactoryMethodSmooth = void 0;
7086
- var Co = class extends go {
7108
+ wo.prototype.ValueTypeName = "string", wo.prototype.ValueBufferType = Array, wo.prototype.DefaultInterpolation = Ni, wo.prototype.InterpolantFactoryMethodLinear = void 0, wo.prototype.InterpolantFactoryMethodSmooth = void 0;
7109
+ var To = class extends vo {
7087
7110
  constructor(e, t, n, r) {
7088
7111
  super(e, t, n, r);
7089
7112
  }
7090
7113
  };
7091
- Co.prototype.ValueTypeName = "vector";
7092
- var wo = /*@__PURE__*/ new class {
7114
+ To.prototype.ValueTypeName = "vector";
7115
+ var Eo = /*@__PURE__*/ new class {
7093
7116
  constructor(e, t, n) {
7094
7117
  let r = this, i = !1, a = 0, o = 0, s, c = [];
7095
7118
  this.onStart = void 0, this.onLoad = e, this.onProgress = t, this.onError = n, this._abortController = null, this.itemStart = function(e) {
@@ -7120,9 +7143,9 @@ var wo = /*@__PURE__*/ new class {
7120
7143
  get abortController() {
7121
7144
  return this._abortController ||= new AbortController(), this._abortController;
7122
7145
  }
7123
- }(), To = class {
7146
+ }(), Do = class {
7124
7147
  constructor(e) {
7125
- this.manager = e === void 0 ? wo : e, this.crossOrigin = "anonymous", this.withCredentials = !1, this.path = "", this.resourcePath = "", this.requestHeader = {}, typeof __THREE_DEVTOOLS__ < "u" && __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe", { detail: this }));
7148
+ this.manager = e === void 0 ? Eo : e, this.crossOrigin = "anonymous", this.withCredentials = !1, this.path = "", this.resourcePath = "", this.requestHeader = {}, typeof __THREE_DEVTOOLS__ < "u" && __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe", { detail: this }));
7126
7149
  }
7127
7150
  load() {}
7128
7151
  loadAsync(e, t) {
@@ -7151,13 +7174,13 @@ var wo = /*@__PURE__*/ new class {
7151
7174
  return this;
7152
7175
  }
7153
7176
  };
7154
- To.DEFAULT_MATERIAL_NAME = "__DEFAULT";
7155
- var Eo = "\\[\\]\\.:\\/", Do = /* @__PURE__ */ RegExp("[\\[\\]\\.:\\/]", "g"), Oo = "[^\\[\\]\\.:\\/]", ko = "[^" + Eo.replace("\\.", "") + "]", Ao = /*@__PURE__*/ "((?:WC+[\\/:])*)".replace("WC", Oo), jo = /*@__PURE__*/ "(WCOD+)?".replace("WCOD", ko), Mo = /*@__PURE__*/ "(?:\\.(WC+)(?:\\[(.+)\\])?)?".replace("WC", Oo), No = /*@__PURE__*/ "\\.(WC+)(?:\\[(.+)\\])?".replace("WC", Oo), Po = RegExp("^" + Ao + jo + Mo + No + "$"), Fo = [
7177
+ Do.DEFAULT_MATERIAL_NAME = "__DEFAULT";
7178
+ var Oo = "\\[\\]\\.:\\/", ko = /* @__PURE__ */ RegExp("[\\[\\]\\.:\\/]", "g"), Ao = "[^\\[\\]\\.:\\/]", jo = "[^" + Oo.replace("\\.", "") + "]", Mo = /*@__PURE__*/ "((?:WC+[\\/:])*)".replace("WC", Ao), No = /*@__PURE__*/ "(WCOD+)?".replace("WCOD", jo), Po = /*@__PURE__*/ "(?:\\.(WC+)(?:\\[(.+)\\])?)?".replace("WC", Ao), Fo = /*@__PURE__*/ "\\.(WC+)(?:\\[(.+)\\])?".replace("WC", Ao), Io = RegExp("^" + Mo + No + Po + Fo + "$"), Lo = [
7156
7179
  "material",
7157
7180
  "materials",
7158
7181
  "bones",
7159
7182
  "map"
7160
- ], Io = class {
7183
+ ], Ro = class {
7161
7184
  constructor(e, t, n) {
7162
7185
  let r = n || Q.parseTrackName(t);
7163
7186
  this._targetGroup = e, this._bindings = e.subscribe_(t, r);
@@ -7187,10 +7210,10 @@ var Eo = "\\[\\]\\.:\\/", Do = /* @__PURE__ */ RegExp("[\\[\\]\\.:\\/]", "g"), O
7187
7210
  return t && t.isAnimationObjectGroup ? new e.Composite(t, n, r) : new e(t, n, r);
7188
7211
  }
7189
7212
  static sanitizeNodeName(e) {
7190
- return e.replace(/\s/g, "_").replace(Do, "");
7213
+ return e.replace(/\s/g, "_").replace(ko, "");
7191
7214
  }
7192
7215
  static parseTrackName(e) {
7193
- let t = Po.exec(e);
7216
+ let t = Io.exec(e);
7194
7217
  if (t === null) throw Error("PropertyBinding: Cannot parse trackName: " + e);
7195
7218
  let n = {
7196
7219
  nodeName: t[2],
@@ -7201,7 +7224,7 @@ var Eo = "\\[\\]\\.:\\/", Do = /* @__PURE__ */ RegExp("[\\[\\]\\.:\\/]", "g"), O
7201
7224
  }, r = n.nodeName && n.nodeName.lastIndexOf(".");
7202
7225
  if (r !== void 0 && r !== -1) {
7203
7226
  let e = n.nodeName.substring(r + 1);
7204
- Fo.indexOf(e) !== -1 && (n.nodeName = n.nodeName.substring(0, r), n.objectName = e);
7227
+ Lo.indexOf(e) !== -1 && (n.nodeName = n.nodeName.substring(0, r), n.objectName = e);
7205
7228
  }
7206
7229
  if (n.propertyName === null || n.propertyName.length === 0) throw Error("PropertyBinding: can not parse propertyName from trackName: " + e);
7207
7230
  return n;
@@ -7378,7 +7401,7 @@ var Eo = "\\[\\]\\.:\\/", Do = /* @__PURE__ */ RegExp("[\\[\\]\\.:\\/]", "g"), O
7378
7401
  this.node = null, this.getValue = this._getValue_unbound, this.setValue = this._setValue_unbound;
7379
7402
  }
7380
7403
  };
7381
- Q.Composite = Io, Q.prototype.BindingType = {
7404
+ Q.Composite = Ro, Q.prototype.BindingType = {
7382
7405
  Direct: 0,
7383
7406
  EntireArray: 1,
7384
7407
  ArrayElement: 2,
@@ -7439,12 +7462,12 @@ Q.Composite = Io, Q.prototype.BindingType = {
7439
7462
  }, typeof __THREE_DEVTOOLS__ < "u" && __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("register", { detail: { revision: "184" } })), typeof window < "u" && (window.__THREE__ ? H("WARNING: Multiple instances of Three.js being imported.") : window.__THREE__ = "184");
7440
7463
  //#endregion
7441
7464
  //#region src/transform-gizmo.ts
7442
- var Lo = {
7465
+ var zo = {
7443
7466
  x: "#fb7185",
7444
7467
  y: "#86efac",
7445
7468
  z: "#7aa2ff"
7446
7469
  };
7447
- function Ro(e, t, n) {
7470
+ function Bo(e, t, n) {
7448
7471
  let r = t - e.origin.x, i = n - e.origin.y;
7449
7472
  if (Math.abs(r) <= e.centerSize && Math.abs(i) <= e.centerSize) return { kind: "center" };
7450
7473
  for (let t of e.axes) {
@@ -7458,11 +7481,11 @@ function Ro(e, t, n) {
7458
7481
  }
7459
7482
  return null;
7460
7483
  }
7461
- function zo(e, t, n) {
7484
+ function Vo(e, t, n) {
7462
7485
  let r = e.sx * e.sx + e.sy * e.sy;
7463
7486
  return r < 1 ? 0 : (t * e.sx + n * e.sy) / r * e.worldPerUnit;
7464
7487
  }
7465
- function Bo(e, t, n, r = !1) {
7488
+ function Ho(e, t, n, r = !1) {
7466
7489
  let { origin: i, axes: a, centerSize: o } = t;
7467
7490
  for (let t of a) {
7468
7491
  let a = n?.kind === "axis" && n.axis === t.axis;
@@ -7473,16 +7496,16 @@ function Bo(e, t, n, r = !1) {
7473
7496
  let s = n?.kind === "center";
7474
7497
  e.globalAlpha = s ? 1 : .95, e.fillStyle = s ? "#ffffff" : "#e2e6f0", e.strokeStyle = "#0b0d14", e.lineWidth = 1.5, e.beginPath(), e.rect(i.x - o, i.y - o, o * 2, o * 2), e.fill(), e.stroke(), e.globalAlpha = 1;
7475
7498
  }
7476
- function Vo(e, t, n) {
7499
+ function Uo(e, t, n) {
7477
7500
  return Math.atan2(n - e.y, t - e.x) * 180 / Math.PI;
7478
7501
  }
7479
- function Ho(e, t) {
7502
+ function Wo(e, t) {
7480
7503
  let n = t - e;
7481
7504
  for (; n > 180;) n -= 360;
7482
7505
  for (; n <= -180;) n += 360;
7483
7506
  return n;
7484
7507
  }
7485
- function Uo(e, t, n, r) {
7508
+ function Go(e, t, n, r) {
7486
7509
  let i = null, a = r;
7487
7510
  for (let r of e) for (let e of r.points) {
7488
7511
  let o = Math.hypot(t - e.x, n - e.y);
@@ -7490,11 +7513,11 @@ function Uo(e, t, n, r) {
7490
7513
  }
7491
7514
  return i;
7492
7515
  }
7493
- function Wo(e, t, n) {
7516
+ function Ko(e, t, n) {
7494
7517
  for (let r of t) {
7495
7518
  if (r.points.length < 2) continue;
7496
7519
  let t = n === r.axis;
7497
- e.strokeStyle = Lo[r.axis], e.globalAlpha = t ? 1 : .75, e.lineWidth = t ? 3 : 2, e.beginPath();
7520
+ e.strokeStyle = zo[r.axis], e.globalAlpha = t ? 1 : .75, e.lineWidth = t ? 3 : 2, e.beginPath();
7498
7521
  let i = r.points[0];
7499
7522
  e.moveTo(i.x, i.y);
7500
7523
  for (let t of r.points.slice(1)) e.lineTo(t.x, t.y);
@@ -7502,14 +7525,14 @@ function Wo(e, t, n) {
7502
7525
  }
7503
7526
  e.globalAlpha = 1;
7504
7527
  }
7505
- function Go(e, t, n, r) {
7528
+ function qo(e, t, n, r) {
7506
7529
  e.font = "600 11px ui-monospace, Menlo, monospace";
7507
7530
  let i = e.measureText(r).width + 14;
7508
7531
  e.fillStyle = "rgba(16, 19, 29, 0.92)", e.strokeStyle = "rgba(110, 231, 220, 0.5)", e.lineWidth = 1, e.beginPath(), e.roundRect(t + 14, n - 26, i, 20, 5), e.fill(), e.stroke(), e.fillStyle = "#6ee7dc", e.textAlign = "left", e.textBaseline = "middle", e.fillText(r, t + 21, n - 16);
7509
7532
  }
7510
7533
  //#endregion
7511
7534
  //#region src/viewport.ts
7512
- var Ko = class {
7535
+ var Jo = class {
7513
7536
  engine;
7514
7537
  editCanvas;
7515
7538
  overlay;
@@ -7617,7 +7640,7 @@ var Ko = class {
7617
7640
  let n;
7618
7641
  try {
7619
7642
  let t = structuredClone(e);
7620
- cs(t), n = c(t, { stubAllBehaviors: !0 });
7643
+ us(t), n = c(t, { stubAllBehaviors: !0 });
7621
7644
  } catch (e) {
7622
7645
  return e instanceof Error ? e.message : String(e);
7623
7646
  }
@@ -7633,7 +7656,7 @@ var Ko = class {
7633
7656
  canvas: this.editCanvas,
7634
7657
  engine: this.engine
7635
7658
  }), this.renderer3d.ignoreStatic = !0;
7636
- let t = is(e.root);
7659
+ let t = os(e.root);
7637
7660
  if (t) {
7638
7661
  let [e, n, r] = t;
7639
7662
  this.orbit.dist = Math.max(2, Math.hypot(e, n, r)), this.orbit.yaw = Math.atan2(e, r), this.orbit.pitch = Math.asin(Math.max(-.99, Math.min(.99, n / this.orbit.dist))), this.orbit.target = [
@@ -7655,13 +7678,13 @@ var Ko = class {
7655
7678
  if (!e.root) return null;
7656
7679
  try {
7657
7680
  let t = structuredClone(e);
7658
- return cs(t), c(t, { stubAllBehaviors: !0 }), null;
7681
+ return us(t), c(t, { stubAllBehaviors: !0 }), null;
7659
7682
  } catch (e) {
7660
7683
  return e instanceof Error ? e.message : String(e);
7661
7684
  }
7662
7685
  }
7663
7686
  defaultView(e) {
7664
- let t = as(e.root);
7687
+ let t = ss(e.root);
7665
7688
  if (t) return {
7666
7689
  cx: t[0],
7667
7690
  cy: t[1],
@@ -7743,7 +7766,7 @@ var Ko = class {
7743
7766
  if (this.rendererDim === "2d" && this.renderer2d) {
7744
7767
  let t = e.position;
7745
7768
  if (!Array.isArray(t)) return null;
7746
- let n = rs(e), r = this.renderer2d.screenFromWorld(n.x, n.y), i = this.renderer2d.view().zoom;
7769
+ let n = as(e), r = this.renderer2d.screenFromWorld(n.x, n.y), i = this.renderer2d.view().zoom;
7747
7770
  return {
7748
7771
  origin: r,
7749
7772
  centerSize: 7,
@@ -7752,13 +7775,13 @@ var Ko = class {
7752
7775
  sx: 64,
7753
7776
  sy: 0,
7754
7777
  worldPerUnit: 64 / i,
7755
- color: Lo.x
7778
+ color: zo.x
7756
7779
  }, {
7757
7780
  axis: "y",
7758
7781
  sx: 0,
7759
7782
  sy: 64,
7760
7783
  worldPerUnit: 64 / i,
7761
- color: Lo.y
7784
+ color: zo.y
7762
7785
  }]
7763
7786
  };
7764
7787
  }
@@ -7792,7 +7815,7 @@ var Ko = class {
7792
7815
  sx: n.x - r.x,
7793
7816
  sy: n.y - r.y,
7794
7817
  worldPerUnit: o,
7795
- color: Lo[e]
7818
+ color: zo[e]
7796
7819
  });
7797
7820
  }
7798
7821
  return {
@@ -7810,7 +7833,7 @@ var Ko = class {
7810
7833
  let e = this.liveSelected();
7811
7834
  if (!e) return null;
7812
7835
  if (this.rendererDim === "2d" && this.renderer2d) {
7813
- let t = rs(e), n = this.renderer2d.screenFromWorld(t.x, t.y), r = [];
7836
+ let t = as(e), n = this.renderer2d.screenFromWorld(t.x, t.y), r = [];
7814
7837
  for (let e = 0; e < 48; e++) {
7815
7838
  let t = e / 48 * Math.PI * 2;
7816
7839
  r.push({
@@ -7866,7 +7889,7 @@ var Ko = class {
7866
7889
  return null;
7867
7890
  }
7868
7891
  orbitVectors() {
7869
- let { yaw: e, pitch: t, dist: n, target: r } = this.orbit, i = Math.cos(t), a = new K(r[0] + n * i * Math.sin(e), r[1] + n * Math.sin(t), r[2] + n * i * Math.cos(e)), o = new K(r[0], r[1], r[2]).sub(a).normalize(), s = new K().crossVectors(o, Jo).normalize();
7892
+ let { yaw: e, pitch: t, dist: n, target: r } = this.orbit, i = Math.cos(t), a = new K(r[0] + n * i * Math.sin(e), r[1] + n * Math.sin(t), r[2] + n * i * Math.cos(e)), o = new K(r[0], r[1], r[2]).sub(a).normalize(), s = new K().crossVectors(o, Xo).normalize();
7870
7893
  return {
7871
7894
  pos: a,
7872
7895
  right: s,
@@ -7892,13 +7915,13 @@ var Ko = class {
7892
7915
  for (let [t] of this.pathOf) if (t instanceof g && (t.current || !e) && (e = t, t.current)) break;
7893
7916
  let t = e ? e._ensureObject3D() : null;
7894
7917
  if (t) {
7895
- t.getWorldPosition(Yo), Xo.set(0, 0, -1).applyQuaternion(t.getWorldQuaternion(Zo));
7918
+ t.getWorldPosition(Zo), Qo.set(0, 0, -1).applyQuaternion(t.getWorldQuaternion($o));
7896
7919
  let e = Math.min(40, Math.max(3, this.orbit.dist));
7897
7920
  this.orbit.target = [
7898
- Yo.x + Xo.x * e,
7899
- Yo.y + Xo.y * e,
7900
- Yo.z + Xo.z * e
7901
- ], this.orbit.dist = e, this.orbit.yaw = Math.atan2(-Xo.x, -Xo.z), this.orbit.pitch = Math.asin(Math.max(-.99, Math.min(.99, -Xo.y)));
7921
+ Zo.x + Qo.x * e,
7922
+ Zo.y + Qo.y * e,
7923
+ Zo.z + Qo.z * e
7924
+ ], this.orbit.dist = e, this.orbit.yaw = Math.atan2(-Qo.x, -Qo.z), this.orbit.pitch = Math.asin(Math.max(-.99, Math.min(.99, -Qo.y)));
7902
7925
  }
7903
7926
  this.renderer3d.viewOverride = null;
7904
7927
  return;
@@ -7986,7 +8009,7 @@ var Ko = class {
7986
8009
  let t = this.overlay.clientWidth, n = this.overlay.clientHeight, r = Math.min(devicePixelRatio || 1, 2);
7987
8010
  if ((this.overlay.width !== t * r || this.overlay.height !== n * r) && (this.overlay.width = t * r, this.overlay.height = n * r), e.setTransform(r, 0, 0, r, 0, 0), e.clearRect(0, 0, t, n), this.playing) return;
7988
8011
  if (this.rendererDim === "3d") {
7989
- this.drawGizmo(e), this.drawModeGizmo(e), this.readout && Go(e, this.readout.x, this.readout.y, this.readout.text);
8012
+ this.drawGizmo(e), this.drawModeGizmo(e), this.readout && qo(e, this.readout.x, this.readout.y, this.readout.text);
7990
8013
  return;
7991
8014
  }
7992
8015
  if (!this.renderer2d) return;
@@ -8011,22 +8034,22 @@ var Ko = class {
8011
8034
  ]) e.fillRect(n - 3, r - 3, 6, 6);
8012
8035
  }
8013
8036
  }
8014
- this.drawModeGizmo(e), this.readout && Go(e, this.readout.x, this.readout.y, this.readout.text);
8037
+ this.drawModeGizmo(e), this.readout && qo(e, this.readout.x, this.readout.y, this.readout.text);
8015
8038
  }
8016
8039
  drawModeGizmo(e) {
8017
8040
  if (this.gizmoMode === "rotate") {
8018
8041
  let t = this.ringLayout();
8019
- t && Wo(e, t.rings, this.activeRing);
8042
+ t && Ko(e, t.rings, this.activeRing);
8020
8043
  return;
8021
8044
  }
8022
8045
  let t = this.gizmoLayout();
8023
- t && Bo(e, t, this.gizmoActive, this.gizmoMode === "scale");
8046
+ t && Ho(e, t, this.gizmoActive, this.gizmoMode === "scale");
8024
8047
  }
8025
8048
  pointBounds(e) {
8026
8049
  if (!this.renderer2d) return null;
8027
8050
  let t = e.position;
8028
8051
  if (!Array.isArray(t)) return null;
8029
- let n = rs(e), r = this.renderer2d.screenFromWorld(n.x, n.y);
8052
+ let n = as(e), r = this.renderer2d.screenFromWorld(n.x, n.y);
8030
8053
  return {
8031
8054
  x: r.x - 12,
8032
8055
  y: r.y - 12,
@@ -8073,7 +8096,7 @@ var Ko = class {
8073
8096
  let e = this.overlay, t = null, n = null, r = !1, i = null, a = null, o = null, s = null, c = null, l = (t) => {
8074
8097
  let n = this.ringLayout();
8075
8098
  if (!n) return !1;
8076
- let r = Uo(n.rings, t.offsetX, t.offsetY, 9);
8099
+ let r = Go(n.rings, t.offsetX, t.offsetY, 9);
8077
8100
  if (!r) return !1;
8078
8101
  let i = this.liveSelected();
8079
8102
  if (!i) return !1;
@@ -8087,13 +8110,13 @@ var Ko = class {
8087
8110
  axis: r,
8088
8111
  node: i,
8089
8112
  origin: n.origin,
8090
- startAngle: Vo(n.origin, t.offsetX, t.offsetY),
8113
+ startAngle: Uo(n.origin, t.offsetX, t.offsetY),
8091
8114
  startRotation: Array.isArray(a) ? [...a] : a ?? 0,
8092
8115
  sign: o
8093
8116
  }, this.activeRing = r, !0;
8094
8117
  }, u = (e) => {
8095
8118
  if (!c) return;
8096
- let { axis: t, node: n, origin: r, startAngle: i, startRotation: a, sign: o } = c, s = Ho(i, Vo(r, e.offsetX, e.offsetY)) * o, l = e.shiftKey || this.shiftHeld ? 15 : null, u = (e) => {
8119
+ let { axis: t, node: n, origin: r, startAngle: i, startRotation: a, sign: o } = c, s = Wo(i, Uo(r, e.offsetX, e.offsetY)) * o, l = e.shiftKey || this.shiftHeld ? 15 : null, u = (e) => {
8097
8120
  let t = e + s;
8098
8121
  return l ? Math.round(t / l) * l : Math.round(t * 10) / 10;
8099
8122
  }, d;
@@ -8134,7 +8157,7 @@ var Ko = class {
8134
8157
  if (this.gizmoMode === "rotate") return l(t);
8135
8158
  let n = this.gizmoLayout();
8136
8159
  if (!n) return !1;
8137
- let r = Ro(n, t.offsetX, t.offsetY);
8160
+ let r = Bo(n, t.offsetX, t.offsetY);
8138
8161
  if (!r) return !1;
8139
8162
  let i = this.liveSelected();
8140
8163
  if (!i) return !1;
@@ -8159,12 +8182,12 @@ var Ko = class {
8159
8182
  }, f = e.shiftKey || this.shiftHeld, p = f ? u ? .5 : 10 : null, m = f ? .25 : null, h = (e) => p ? Math.round(e / p) * p : e, g = (e) => m ? Math.max(m, Math.round(e / m) * m) : e;
8160
8183
  if (n === "scale") {
8161
8184
  let n = Math.max(.05, 1 + (c - l) * .005), r = [...o];
8162
- if (t.kind === "axis") r[d[t.axis]] = qo(g((o[d[t.axis]] ?? 1) * n));
8163
- else for (let e = 0; e < r.length; e++) r[e] = qo(g((o[e] ?? 1) * n));
8185
+ if (t.kind === "axis") r[d[t.axis]] = Yo(g((o[d[t.axis]] ?? 1) * n));
8186
+ else for (let e = 0; e < r.length; e++) r[e] = Yo(g((o[e] ?? 1) * n));
8164
8187
  i.scale = r, this.readout = {
8165
8188
  x: e.offsetX,
8166
8189
  y: e.offsetY,
8167
- text: `×${r.map((e) => qo(e)).join(", ")}`
8190
+ text: `×${r.map((e) => Yo(e)).join(", ")}`
8168
8191
  };
8169
8192
  return;
8170
8193
  }
@@ -8172,23 +8195,23 @@ var Ko = class {
8172
8195
  if (t.kind === "axis") {
8173
8196
  let e = r.axes.find((e) => e.axis === t.axis);
8174
8197
  if (!e) return;
8175
- let n = zo(e, c, l);
8176
- if (u) _[d[t.axis]] = qo(h((a[d[t.axis]] ?? 0) + n));
8198
+ let n = Vo(e, c, l);
8199
+ if (u) _[d[t.axis]] = Yo(h((a[d[t.axis]] ?? 0) + n));
8177
8200
  else {
8178
- let e = ts(i, t.axis === "x" ? n : 0, t.axis === "y" ? n : 0), r = t.axis === "x" ? e.x : e.y;
8201
+ let e = rs(i, t.axis === "x" ? n : 0, t.axis === "y" ? n : 0), r = t.axis === "x" ? e.x : e.y;
8179
8202
  _[d[t.axis]] = Math.round(h((a[d[t.axis]] ?? 0) + r));
8180
8203
  }
8181
8204
  } else if (u && this.renderer3d) {
8182
8205
  let { right: e, up: t } = this.renderer3d.cameraBasis(), n = this.orbit.dist * .0016;
8183
- _[0] = qo(h((a[0] ?? 0) + (e.x * c - t.x * l) * n)), _[1] = qo(h((a[1] ?? 0) + (e.y * c - t.y * l) * n)), _[2] = qo(h((a[2] ?? 0) + (e.z * c - t.z * l) * n));
8206
+ _[0] = Yo(h((a[0] ?? 0) + (e.x * c - t.x * l) * n)), _[1] = Yo(h((a[1] ?? 0) + (e.y * c - t.y * l) * n)), _[2] = Yo(h((a[2] ?? 0) + (e.z * c - t.z * l) * n));
8184
8207
  } else if (this.renderer2d) {
8185
- let e = this.renderer2d.view(), t = ts(i, c / e.zoom, l / e.zoom);
8208
+ let e = this.renderer2d.view(), t = rs(i, c / e.zoom, l / e.zoom);
8186
8209
  _[0] = Math.round(h((a[0] ?? 0) + t.x)), _[1] = Math.round(h((a[1] ?? 0) + t.y));
8187
8210
  }
8188
8211
  i.position = _, this.readout = {
8189
8212
  x: e.offsetX,
8190
8213
  y: e.offsetY,
8191
- text: `[${_.map((e) => qo(e)).join(", ")}]`
8214
+ text: `[${_.map((e) => Yo(e)).join(", ")}]`
8192
8215
  };
8193
8216
  }, m = () => {
8194
8217
  if (!s) return;
@@ -8297,7 +8320,7 @@ var Ko = class {
8297
8320
  return;
8298
8321
  }
8299
8322
  if (t) {
8300
- let e = this.renderer2d.worldFromScreen(o.offsetX, o.offsetY), n = ts(t.node, e.x - t.startWorld.x, e.y - t.startWorld.y), r = Math.round(t.startPos[0] + n.x), i = Math.round(t.startPos[1] + n.y);
8323
+ let e = this.renderer2d.worldFromScreen(o.offsetX, o.offsetY), n = rs(t.node, e.x - t.startWorld.x, e.y - t.startWorld.y), r = Math.round(t.startPos[0] + n.x), i = Math.round(t.startPos[1] + n.y);
8301
8324
  t.node.position = [r, i];
8302
8325
  return;
8303
8326
  }
@@ -8348,9 +8371,9 @@ var Ko = class {
8348
8371
  zoomToFit() {
8349
8372
  let e = this.liveSelected();
8350
8373
  if (this.rendererDim === "3d") {
8351
- let t = new Ya();
8374
+ let t = new Za();
8352
8375
  for (let [n] of this.pathOf) {
8353
- if (e && n !== e && !ns(n, e)) continue;
8376
+ if (e && n !== e && !is(n, e)) continue;
8354
8377
  let r = n._object3D;
8355
8378
  r && (t.expandByObject(r), t.expandByPoint(r.getWorldPosition($)));
8356
8379
  }
@@ -8384,10 +8407,10 @@ var Ko = class {
8384
8407
  if (!this.renderer2d) return;
8385
8408
  let t = this.editCanvas.clientWidth || 960, n = this.editCanvas.clientHeight || 540, r = Infinity, i = Infinity, a = -Infinity, o = -Infinity;
8386
8409
  for (let [t] of this.pathOf) {
8387
- if (e && t !== e && !ns(t, e)) continue;
8410
+ if (e && t !== e && !is(t, e)) continue;
8388
8411
  let n = t.position;
8389
8412
  if (!Array.isArray(n)) continue;
8390
- let s = rs(t);
8413
+ let s = as(t);
8391
8414
  r = Math.min(r, s.x), i = Math.min(i, s.y), a = Math.max(a, s.x), o = Math.max(o, s.y);
8392
8415
  }
8393
8416
  if (!Number.isFinite(r)) return;
@@ -8401,7 +8424,7 @@ var Ko = class {
8401
8424
  async play(t) {
8402
8425
  if (this.playing) return null;
8403
8426
  let n = structuredClone(t);
8404
- cs(n);
8427
+ us(n);
8405
8428
  let r;
8406
8429
  try {
8407
8430
  r = c(n, {
@@ -8440,25 +8463,25 @@ var Ko = class {
8440
8463
  this.playEngine?.input.dispose(), this.playEngine?.stop(), this.playEngine?.dispose(), this.playEngine = null, this.playPhysics?.dispose(), this.playPhysics = null, this.editUiHost && (this.editUiHost.style.display = ""), this.playRenderer?.dispose(), this.playRenderer = null, this.playCanvas.hidden = !0, this.cb.onPlayStateChanged(!1), this.lastAppliedKey = null, this.lastGood && this.apply(this.lastGood);
8441
8464
  }
8442
8465
  };
8443
- function qo(e) {
8466
+ function Yo(e) {
8444
8467
  return Math.round(e * 100) / 100;
8445
8468
  }
8446
- var Jo = new K(0, 1, 0), Yo = new K(), Xo = new K(), Zo = new ea(), $ = new K(), Qo = new va(), $o = new K(), es = new K();
8447
- function ts(e, t, n) {
8469
+ var Xo = new K(0, 1, 0), Zo = new K(), Qo = new K(), $o = new na(), $ = new K(), es = new ba(), ts = new K(), ns = new K();
8470
+ function rs(e, t, n) {
8448
8471
  let r = e._object2D?.parent;
8449
- return r ? (Qo.copy(r.matrixWorld).invert(), $o.set(t, -n, 0).applyMatrix4(Qo), es.set(0, 0, 0).applyMatrix4(Qo), {
8450
- x: $o.x - es.x,
8451
- y: -($o.y - es.y)
8472
+ return r ? (es.copy(r.matrixWorld).invert(), ts.set(t, -n, 0).applyMatrix4(es), ns.set(0, 0, 0).applyMatrix4(es), {
8473
+ x: ts.x - ns.x,
8474
+ y: -(ts.y - ns.y)
8452
8475
  }) : {
8453
8476
  x: t,
8454
8477
  y: n
8455
8478
  };
8456
8479
  }
8457
- function ns(e, t) {
8480
+ function is(e, t) {
8458
8481
  for (let n = e.parent; n; n = n.parent) if (n === t) return !0;
8459
8482
  return !1;
8460
8483
  }
8461
- function rs(e) {
8484
+ function as(e) {
8462
8485
  let t = e._object2D;
8463
8486
  if (t) return t.getWorldPosition($), {
8464
8487
  x: $.x,
@@ -8471,7 +8494,7 @@ function rs(e) {
8471
8494
  y: r
8472
8495
  };
8473
8496
  }
8474
- function is(e) {
8497
+ function os(e) {
8475
8498
  if (!e) return null;
8476
8499
  if (e.type === "Camera3D") {
8477
8500
  let t = e.props?.position ?? [
@@ -8486,48 +8509,48 @@ function is(e) {
8486
8509
  ];
8487
8510
  }
8488
8511
  for (let t of e.children ?? []) {
8489
- let e = is(t);
8512
+ let e = os(t);
8490
8513
  if (e) return e;
8491
8514
  }
8492
8515
  return null;
8493
8516
  }
8494
- function as(e) {
8517
+ function ss(e) {
8495
8518
  if (!e) return null;
8496
8519
  if (e.type === "Camera2D") {
8497
8520
  let t = e.props?.position ?? [0, 0];
8498
8521
  return [t[0] ?? 0, t[1] ?? 0];
8499
8522
  }
8500
8523
  for (let t of e.children ?? []) {
8501
- let e = as(t);
8524
+ let e = ss(t);
8502
8525
  if (e) return e;
8503
8526
  }
8504
8527
  return null;
8505
8528
  }
8506
- var os = null;
8507
- function ss() {
8508
- if (os) return os;
8529
+ var cs = null;
8530
+ function ls() {
8531
+ if (cs) return cs;
8509
8532
  let e = document.createElement("canvas");
8510
8533
  e.width = 16, e.height = 16;
8511
8534
  let t = e.getContext("2d");
8512
8535
  for (let e = 0; e < 2; e++) for (let n = 0; n < 2; n++) t.fillStyle = (n + e) % 2 == 0 ? "#c252c2" : "#2b2b3b", t.fillRect(n * 8, e * 8, 8, 8);
8513
- return os = e.toDataURL(), os;
8536
+ return cs = e.toDataURL(), cs;
8514
8537
  }
8515
- function cs(e) {
8538
+ function us(e) {
8516
8539
  let t = e.assets;
8517
- if (t) for (let e of Object.values(t)) typeof e?.url == "string" && !e.url.includes("/") && !e.url.includes(".") && (e.url = ss());
8540
+ if (t) for (let e of Object.values(t)) typeof e?.url == "string" && !e.url.includes("/") && !e.url.includes(".") && (e.url = ls());
8518
8541
  }
8519
8542
  u(), m(), C(), T(), w();
8520
- async function ls(e = {}) {
8543
+ async function ds(e = {}) {
8521
8544
  let t = e.api ?? Te, n = [], r = document.createElement("style");
8522
- r.dataset.incantoEditor = "true", r.textContent = Jr, document.head.appendChild(r), n.push(() => r.remove());
8545
+ r.dataset.incantoEditor = "true", r.textContent = Xr, document.head.appendChild(r), n.push(() => r.remove());
8523
8546
  let i = document.createElement("div");
8524
- i.className = "incanto-editor-root", i.innerHTML = Or, (e.host ?? document.body).appendChild(i), n.push(() => i.remove());
8547
+ i.className = "incanto-editor-root", i.innerHTML = Ar, (e.host ?? document.body).appendChild(i), n.push(() => i.remove());
8525
8548
  let a = (e) => {
8526
8549
  let t = i.querySelector(e);
8527
8550
  if (!t) throw Error(`missing ${e}`);
8528
8551
  return t;
8529
8552
  }, o = await t.meta();
8530
- a("#engine-version").textContent = `incanto@${o.version}`, Vt(a("#popover")), Ct(), a("#docs-btn").addEventListener("click", () => xt());
8553
+ a("#engine-version").textContent = `incanto@${o.version}`, Ht(a("#popover")), wt(), a("#docs-btn").addEventListener("click", () => St());
8531
8554
  let s = a("#lang-btn"), c = [{
8532
8555
  code: "en",
8533
8556
  label: "English"
@@ -8535,7 +8558,7 @@ async function ls(e = {}) {
8535
8558
  code: "ko",
8536
8559
  label: "한국어"
8537
8560
  }], l = () => {
8538
- a("#lang-current").textContent = Oe() === "ko" ? "한국어" : "EN";
8561
+ a("#lang-current").textContent = ke() === "ko" ? "한국어" : "EN";
8539
8562
  };
8540
8563
  l(), s.addEventListener("click", () => {
8541
8564
  document.querySelector(".lang-menu")?.remove();
@@ -8547,8 +8570,8 @@ async function ls(e = {}) {
8547
8570
  let i = document.createElement("span");
8548
8571
  i.textContent = n;
8549
8572
  let a = document.createElement("span");
8550
- a.textContent = Oe() === t ? "✓" : "", a.className = "lang-check", r.append(i, a), r.addEventListener("click", () => {
8551
- e.remove(), ke(t);
8573
+ a.textContent = ke() === t ? "✓" : "", a.className = "lang-check", r.append(i, a), r.addEventListener("click", () => {
8574
+ e.remove(), Ae(t);
8552
8575
  }), e.appendChild(r);
8553
8576
  }
8554
8577
  document.body.appendChild(e);
@@ -8558,16 +8581,16 @@ async function ls(e = {}) {
8558
8581
  e.contains(t.target) || t.target === s || (e.remove(), document.removeEventListener("pointerdown", n, !0));
8559
8582
  };
8560
8583
  setTimeout(() => document.addEventListener("pointerdown", n, !0), 0);
8561
- }), Ae(() => {
8562
- l(), wt(), u.select(u.selection);
8584
+ }), je(() => {
8585
+ l(), Tt(), u.select(u.selection);
8563
8586
  });
8564
- let u = new Lr({
8587
+ let u = new zr({
8565
8588
  format: 1,
8566
8589
  type: "scene",
8567
8590
  name: "",
8568
8591
  root: null
8569
8592
  }), f = a("#tree"), p = a("#inspector"), m = a("#save-btn"), h = a("#undo-btn"), g = a("#play-btn"), _ = a("#error-banner"), v = a("#play-notice"), y = a("#add-type"), b = a("#picker"), x = a("#picker-list"), S = a("#scenes-btn"), C = o.input, w = o.output, T, E = !1, D = a("#error-text"), O = (e) => {
8570
- _.hidden = !1, D.textContent = e, mt.error(e);
8593
+ _.hidden = !1, D.textContent = e, ht.error(e);
8571
8594
  }, k = () => {
8572
8595
  _.hidden = !0, D.textContent = "";
8573
8596
  };
@@ -8594,7 +8617,7 @@ async function ls(e = {}) {
8594
8617
  n && (P = !1);
8595
8618
  let r = u.selection, i = u.nodeAt(r);
8596
8619
  if (!r || i?.type !== "TileMap2D") return;
8597
- let { cx: a, cy: o } = cn(ee(r), Number(i.props?.tileSize ?? 32), e, t), s = i.props?.cells ?? [], c = ln(s, a, o, N.brush);
8620
+ let { cx: a, cy: o } = un(ee(r), Number(i.props?.tileSize ?? 32), e, t), s = i.props?.cells ?? [], c = dn(s, a, o, N.brush);
8598
8621
  !c || JSON.stringify(c) === JSON.stringify(s) || (u.mutate(() => {
8599
8622
  i.props ||= {}, i.props.cells = c;
8600
8623
  }, {
@@ -8605,7 +8628,7 @@ async function ls(e = {}) {
8605
8628
  }, ne = () => {
8606
8629
  let e = u.nodeAt(u.selection);
8607
8630
  N.on && e?.type !== "TileMap2D" && (N.on = !1), F.setPaintHandler(N.on ? te : null);
8608
- }, F = new Ko(a("#viewport"), a("#overlay"), a("#play-canvas"), {
8631
+ }, F = new Jo(a("#viewport"), a("#overlay"), a("#play-canvas"), {
8609
8632
  onPick: (e, t) => u.select(e ?? null, t),
8610
8633
  onNodeMoved: (e, t) => de(e, "position", t, [0, 0]),
8611
8634
  onNodeScaled: (e, t) => de(e, "scale", t, [1, 1]),
@@ -8654,9 +8677,9 @@ async function ls(e = {}) {
8654
8677
  "3D",
8655
8678
  "3D Physics"
8656
8679
  ];
8657
- for (let [e] of gt) t.includes(e) || t.push(e);
8680
+ for (let [e] of _t) t.includes(e) || t.push(e);
8658
8681
  for (let e of t) {
8659
- let t = gt.find(([t]) => t === e)?.[1];
8682
+ let t = _t.find(([t]) => t === e)?.[1];
8660
8683
  if (!t) continue;
8661
8684
  let n = document.createElement("optgroup");
8662
8685
  n.label = e;
@@ -8693,21 +8716,21 @@ async function ls(e = {}) {
8693
8716
  }
8694
8717
  };
8695
8718
  y.addEventListener("mousedown", oe), y.addEventListener("focus", oe);
8696
- let se = t.library ? (e) => dr(t, {
8719
+ let se = t.library ? (e) => pr(t, {
8697
8720
  kind: e.kind,
8698
8721
  ...e.target ? { target: e.target } : {},
8699
8722
  ...e.shelf ? { shelf: e.shelf } : {},
8700
8723
  ...e.assetType ? { assetType: e.assetType } : {},
8701
8724
  ...e.onProps ? { onProps: e.onProps } : {},
8702
- ...e.asAsset ? { onAsset: (e, t, n) => ps(u, n, t) } : {}
8725
+ ...e.asAsset ? { onAsset: (e, t, n) => hs(u, n, t) } : {}
8703
8726
  }) : void 0, ce = !1, le = () => {
8704
8727
  if (!E) return;
8705
- si(f, u), He(a("#asset-tree"), u), p.textContent = "", Ue(p, u, Se, se) || pn(p, u, {
8706
- modelRefs: () => ds(u, "model"),
8728
+ li(f, u), Ue(a("#asset-tree"), u), p.textContent = "", We(p, u, Se, se) || hn(p, u, {
8729
+ modelRefs: () => ps(u, "model"),
8707
8730
  animationsForSelection: () => u.selection ? F.modelAnimationsAt(u.selection) : [],
8708
8731
  bonesForSelection: (e) => u.selection ? F.boneNamesAt(u.selection, e) : [],
8709
- assetRefs: (e) => fs(u, e),
8710
- addAsset: (e, t) => ps(u, e, t),
8732
+ assetRefs: (e) => ms(u, e),
8733
+ addAsset: (e, t) => hs(u, e, t),
8711
8734
  ...se ? { openLibrary: se } : {},
8712
8735
  confirm: Se,
8713
8736
  paint: {
@@ -8727,7 +8750,7 @@ async function ls(e = {}) {
8727
8750
  let e = F.apply(u.working);
8728
8751
  _.hidden = e === null, e !== null && O(e);
8729
8752
  }
8730
- m.disabled = !u.dirty || !u.working.root, m.title = u.working.root ? "" : "Add a root node before saving", h.disabled = !u.canUndo, u.dirty !== ce && (ce = u.dirty, mt.change(u.dirty));
8753
+ m.disabled = !u.dirty || !u.working.root, m.title = u.working.root ? "" : "Add a root node before saving", h.disabled = !u.canUndo, u.dirty !== ce && (ce = u.dirty, ht.change(u.dirty));
8731
8754
  };
8732
8755
  u.onChange(le), u.validator = (e) => F.validate(e), u.onError = O;
8733
8756
  let ue = (e, t, n, r) => {
@@ -8753,8 +8776,8 @@ async function ls(e = {}) {
8753
8776
  let i = await t.loadScene(e);
8754
8777
  T = e, C = n, w = r, E = !0;
8755
8778
  let s = e ?? n;
8756
- a("#file-chip").hidden = !s, a("#file-path").textContent = s ?? "", a("#file-chip").title = `input: ${n}\noutput: ${r}`, b.hidden = !0, k(), ui(), u.reset(i), o.mode === "project" && n && mt.open(n, r);
8757
- }, pe = Dr({
8779
+ a("#file-chip").hidden = !s, a("#file-path").textContent = s ?? "", a("#file-chip").title = `input: ${n}\noutput: ${r}`, b.hidden = !0, k(), fi(), u.reset(i), o.mode === "project" && n && ht.open(n, r);
8780
+ }, pe = kr({
8758
8781
  list: x,
8759
8782
  search: a("#picker-search"),
8760
8783
  count: a("#picker-count"),
@@ -8803,7 +8826,7 @@ async function ls(e = {}) {
8803
8826
  n && u.select(n);
8804
8827
  });
8805
8828
  let _e = a("#generate");
8806
- Ft(u), a("#generate-btn").addEventListener("click", () => Nt(u));
8829
+ It(u), a("#generate-btn").addEventListener("click", () => Pt(u));
8807
8830
  let ve = a("#confirm"), ye = (e) => {
8808
8831
  if (u.selection === null && e.length === 0) {
8809
8832
  O("The scene itself cannot be deleted — it IS the file.");
@@ -8812,7 +8835,7 @@ async function ls(e = {}) {
8812
8835
  if (e.length === 0) {
8813
8836
  let e = u.working.root;
8814
8837
  if (!e) return;
8815
- let t = us(e);
8838
+ let t = fs(e);
8816
8839
  Se(`This deletes the ROOT '${String(e.name ?? "")}'${t > 0 ? ` AND its ${t} descendant node${t === 1 ? "" : "s"}` : ""} — the scene goes empty, and the next node you add becomes the new root.`, "delete root", () => u.deleteRoot());
8817
8840
  return;
8818
8841
  }
@@ -8820,7 +8843,7 @@ async function ls(e = {}) {
8820
8843
  if (n.length === 0) {
8821
8844
  let n = e.reduce((e, t) => {
8822
8845
  let n = u.nodeAt(t);
8823
- return e + (n ? us(n) : 0);
8846
+ return e + (n ? fs(n) : 0);
8824
8847
  }, 0);
8825
8848
  if (n > 0) {
8826
8849
  Se(`This deletes ${e.length > 1 ? `${e.length} nodes` : `'${String(u.nodeAt(e[0] ?? [])?.name ?? "")}'`} AND ${n} descendant node${n === 1 ? "" : "s"}.`, `delete ${e.length + n} nodes`, () => {
@@ -8857,7 +8880,7 @@ async function ls(e = {}) {
8857
8880
  return;
8858
8881
  }
8859
8882
  be && u.removeNodesUnlinking(be.selections) && u.select(be.parentOfFirst), Ce();
8860
- }), ti(ye), ni((e) => {
8883
+ }), ri(ye), ii((e) => {
8861
8884
  M(`${I({
8862
8885
  en: `Rename: repaired ${e.length} reference${e.length === 1 ? "" : "s"}`,
8863
8886
  ko: `이름 변경: 참조 ${e.length}건 수정`
@@ -8933,18 +8956,18 @@ async function ls(e = {}) {
8933
8956
  "scale"
8934
8957
  ]) a(`#tool-${e}`).addEventListener("click", () => F.setMode(e));
8935
8958
  F.setMode("move");
8936
- let Ee = a("#tool-colliders"), De = "incanto-editor-show-colliders", je = (e) => {
8959
+ let Ee = a("#tool-colliders"), De = "incanto-editor-show-colliders", Oe = (e) => {
8937
8960
  F.showColliders = e, Ee.classList.toggle("active", e), localStorage.setItem(De, e ? "" : "0");
8938
8961
  };
8939
- je(localStorage.getItem(De) !== "0"), Ee.addEventListener("click", () => je(!F.showColliders));
8962
+ Oe(localStorage.getItem(De) !== "0"), Ee.addEventListener("click", () => Oe(!F.showColliders));
8940
8963
  let Me = a("#hints-dock"), Ne = "incanto-editor-hints-open";
8941
8964
  Me.classList.toggle("open", localStorage.getItem(Ne) === "1"), a("#hints-toggle").addEventListener("click", () => {
8942
8965
  let e = Me.classList.toggle("open");
8943
8966
  localStorage.setItem(Ne, e ? "1" : "");
8944
- }), a("#fit-btn").addEventListener("click", () => F.zoomToFit()), ei(() => F.zoomToFit()), a("#gameview-btn").addEventListener("click", () => F.gameView()), t.saveScene || (m.hidden = !0), m.addEventListener("click", () => {
8967
+ }), a("#fit-btn").addEventListener("click", () => F.zoomToFit()), ni(() => F.zoomToFit()), a("#gameview-btn").addEventListener("click", () => F.gameView()), t.saveScene || (m.hidden = !0), m.addEventListener("click", () => {
8945
8968
  (async () => {
8946
8969
  try {
8947
- await t.saveScene?.(u.working, T), u.markSaved(), mt.save(C, w, u.working);
8970
+ await t.saveScene?.(u.working, T), u.markSaved(), ht.save(C, w, u.working);
8948
8971
  } catch (e) {
8949
8972
  O(e instanceof Error ? e.message : String(e));
8950
8973
  }
@@ -8956,7 +8979,7 @@ async function ls(e = {}) {
8956
8979
  return;
8957
8980
  }
8958
8981
  if (e.key === "Escape" && !a("#docs").hidden) {
8959
- St();
8982
+ Ct();
8960
8983
  return;
8961
8984
  }
8962
8985
  if (e.key === "Escape" && !ve.hidden) {
@@ -8964,7 +8987,7 @@ async function ls(e = {}) {
8964
8987
  return;
8965
8988
  }
8966
8989
  if (e.key === "Escape" && !_e.hidden) {
8967
- Pt();
8990
+ Ft();
8968
8991
  return;
8969
8992
  }
8970
8993
  if (e.key === "Escape" && !b.hidden) {
@@ -8979,7 +9002,7 @@ async function ls(e = {}) {
8979
9002
  let t = e.target.matches("input, textarea, select");
8980
9003
  (e.metaKey || e.ctrlKey) && e.key === "z" ? (e.preventDefault(), u.undo()) : (e.metaKey || e.ctrlKey) && e.key === "s" ? (e.preventDefault(), m.disabled || m.click()) : !t && e.code === "KeyF" ? F.zoomToFit() : !t && (e.code === "Digit0" || e.code === "Numpad0") ? F.gameView() : !t && e.code === "KeyW" ? F.setMode("move") : !t && e.code === "KeyE" ? F.setMode("rotate") : !t && e.code === "KeyR" && F.setMode("scale");
8981
9004
  };
8982
- return window.addEventListener("keydown", Pe), n.push(() => window.removeEventListener("keydown", Pe)), le(), e.camera && F.setEditCamera(e.camera.position, e.camera.target), mt.ready(C, w, o.version), {
9005
+ return window.addEventListener("keydown", Pe), n.push(() => window.removeEventListener("keydown", Pe)), le(), e.camera && F.setEditCamera(e.camera.position, e.camera.target), ht.ready(C, w, o.version), {
8983
9006
  working: () => u.working,
8984
9007
  camera: () => F.editCamera(),
8985
9008
  showError: O,
@@ -8990,20 +9013,20 @@ async function ls(e = {}) {
8990
9013
  }
8991
9014
  };
8992
9015
  }
8993
- function us(e) {
9016
+ function fs(e) {
8994
9017
  let t = 0;
8995
- for (let n of e.children ?? []) t += 1 + us(n);
9018
+ for (let n of e.children ?? []) t += 1 + fs(n);
8996
9019
  return t;
8997
9020
  }
8998
- function ds(e, t) {
9021
+ function ps(e, t) {
8999
9022
  let n = e.working.assets;
9000
9023
  return n ? Object.entries(n).filter(([, e]) => e?.type === t).map(([e]) => `$${e}`) : [];
9001
9024
  }
9002
- function fs(e, t) {
9025
+ function ms(e, t) {
9003
9026
  let n = e.working.assets;
9004
9027
  return n ? Object.entries(n).filter(([, e]) => !t || e?.type !== void 0 && t.includes(e.type)).map(([e]) => `$${e}`) : [];
9005
9028
  }
9006
- function ps(e, t, n) {
9029
+ function hs(e, t, n) {
9007
9030
  let r = e.working.assets ?? {};
9008
9031
  for (let [e, t] of Object.entries(r)) if (t?.url === n.url) return `$${e}`;
9009
9032
  let i = t;
@@ -9013,4 +9036,4 @@ function ps(e, t, n) {
9013
9036
  }), `$${i}`;
9014
9037
  }
9015
9038
  //#endregion
9016
- export { A as formatSceneJson, Te as httpEditorApi, ls as mountEditor };
9039
+ export { A as formatSceneJson, Te as httpEditorApi, ds as mountEditor };