incanto 0.69.0 → 0.70.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/bin/_behaviors-loader.mjs +22 -0
  2. package/bin/_read-json.mjs +28 -0
  3. package/bin/incanto-assets.mjs +5 -4
  4. package/bin/incanto-check.mjs +58 -31
  5. package/bin/incanto-editor.mjs +128 -5
  6. package/bin/incanto-env.mjs +3 -2
  7. package/bin/incanto-feel.mjs +24 -13
  8. package/bin/incanto-frame.mjs +8 -1
  9. package/bin/incanto-multiplay.mjs +11 -9
  10. package/bin/incanto-new.mjs +105 -10
  11. package/bin/incanto-play.mjs +158 -16
  12. package/bin/incanto-playtest.mjs +66 -23
  13. package/bin/incanto-skills.mjs +14 -2
  14. package/bin/incanto-verify.mjs +125 -44
  15. package/bin/incanto.mjs +3 -2
  16. package/dist/2d.d.ts +281 -34
  17. package/dist/2d.js +4 -4
  18. package/dist/3d.d.ts +157 -9
  19. package/dist/3d.js +7 -7
  20. package/dist/{agent8-CvsfVskX.js → agent8-CmNF01gA.js} +61 -8
  21. package/dist/{audio-player-C0j2k-yB.d.ts → audio-player-DaMxqfNE.d.ts} +2 -2
  22. package/dist/{behavior-rm8vVzu_.d.ts → behavior-DZExDn9o.d.ts} +744 -46
  23. package/dist/{create-game-CwxEDlCm.js → create-game-Bwvh6q8A.js} +142 -59
  24. package/dist/{create-game-CvJ1wSRP.js → create-game-C7ffQWW7.js} +97 -47
  25. package/dist/debug.d.ts +1 -1
  26. package/dist/debug.js +2 -3
  27. package/dist/diagnostics-Cu85N3tL.d.ts +12 -0
  28. package/dist/{editor-switch-CnIOiyNJ.d.ts → editor-switch-CFU9mCec.d.ts} +22 -13
  29. package/dist/editor.js +1065 -863
  30. package/dist/env.d.ts +1 -1
  31. package/dist/env.js +5 -3
  32. package/dist/{environment-presets-BO-7XoFV.js → environment-presets-D6Q5BxeE.js} +298 -45
  33. package/dist/{gameplay-D1KixWK8.js → gameplay-BfHkuzVb.js} +809 -211
  34. package/dist/gameplay.d.ts +187 -7
  35. package/dist/gameplay.js +1 -1
  36. package/dist/{heightmap-CRK0M4jT.js → heightmap-BYgD5Edk.js} +1 -1
  37. package/dist/index.d.ts +156 -13
  38. package/dist/index.js +10 -12
  39. package/dist/json-CfTjpvW8.js +67 -0
  40. package/dist/{loader-DadV2QCT.d.ts → loader-Cff09LMm.d.ts} +2 -2
  41. package/dist/net.d.ts +27 -3
  42. package/dist/net.js +2 -2
  43. package/dist/{noise-CGUMx44x.js → noise-D3nPpmFg.js} +1 -1
  44. package/dist/{physics-2d-CF5yyjbj.js → physics-2d-CE0Qvy3V.js} +136 -11
  45. package/dist/{physics-3d-DbYaEcZy.js → physics-3d-CpH-2gn5.js} +104 -23
  46. package/dist/{teardown-CMqFVxO9.js → picking-CQJ_PJKh.js} +103 -12
  47. package/dist/react.d.ts +2 -2
  48. package/dist/react.js +2 -2
  49. package/dist/{register-mmfugpaQ.js → register-6DYnKZcy.js} +546 -817
  50. package/dist/{register-DbVArsns.js → register-Bkk0wSDB.js} +332 -23
  51. package/dist/{replay-BEHLDcQV.js → replay-DjAkAzMq.js} +224 -14
  52. package/dist/{replay-BQfkX4x7.d.ts → replay-Dmw-PKQu.d.ts} +20 -3
  53. package/dist/{schema-B6ugCV1Q.d.ts → rng-Bb-IutXB.d.ts} +38 -21
  54. package/dist/{rng-DP-SR7eg.js → rng-CDOMybym.js} +22 -0
  55. package/dist/{loader-DZE7B07H.js → save-slots-BXVg148r.js} +4570 -2322
  56. package/dist/{split-screen-Cg76MCV5.d.ts → split-screen--k-XpBjr.d.ts} +36 -4
  57. package/dist/{split-screen-CauMwu6y.js → split-screen-PL78oVXP.js} +159 -26
  58. package/dist/{sprite-animation-CY-mrr1L.js → sprite-animation-CqR2o3SA.js} +39 -8
  59. package/dist/{src-CYEu-_S9.js → src-Cxfiv1Hg.js} +2 -17
  60. package/dist/test-iHYVUcDK.js +4036 -0
  61. package/dist/test.d.ts +531 -30
  62. package/dist/test.js +3 -3
  63. package/dist/touch-BnCyPA0G.js +519 -0
  64. package/dist/vite.d.ts +20 -37
  65. package/dist/vite.js +176 -6
  66. package/dist/{webgl-unavailable-Z5_g8x9H.js → webgl-unavailable-C8aDbGmR.js} +44 -0
  67. package/editor/assets/agent8-D0MS174y.js +1 -0
  68. package/editor/assets/{debug-CMULinBW.js → debug-BnXkKuYu.js} +2 -2
  69. package/editor/assets/index-CIu3uc3l.js +11046 -0
  70. package/editor/index.html +1 -1
  71. package/package.json +4 -14
  72. package/schemas/scene.schema.json +30 -3
  73. package/skills/incanto-3d-character.md +14 -1
  74. package/skills/incanto-3d-models.md +12 -0
  75. package/skills/incanto-assets.md +9 -1
  76. package/skills/incanto-audio.md +8 -2
  77. package/skills/incanto-behaviors-and-scripts.md +83 -6
  78. package/skills/incanto-building-2d-games.md +77 -8
  79. package/skills/incanto-building-3d-games.md +58 -4
  80. package/skills/incanto-editor.md +46 -7
  81. package/skills/incanto-environment.md +19 -1
  82. package/skills/incanto-game-feel.md +70 -0
  83. package/skills/incanto-gameplay-behaviors.md +109 -19
  84. package/skills/incanto-hud.md +128 -7
  85. package/skills/incanto-localization.md +13 -5
  86. package/skills/incanto-multiplayer.md +83 -3
  87. package/skills/incanto-node-reference.md +222 -58
  88. package/skills/incanto-performance.md +52 -0
  89. package/skills/incanto-physics-and-input.md +123 -24
  90. package/skills/incanto-playtesting.md +78 -2
  91. package/skills/incanto-save-slots.md +161 -6
  92. package/skills/incanto-scene-json-authoring.md +69 -12
  93. package/skills/incanto-verifying-your-game.md +196 -10
  94. package/skills/incanto-web-integration.md +28 -0
  95. package/skills/incanto-your-first-game.md +3 -1
  96. package/templates-app/beacon-isle-3d/generate-world.ts +77 -9
  97. package/templates-app/beacon-isle-3d/package.json +2 -2
  98. package/templates-app/beacon-isle-3d/src/behaviors.ts +22 -0
  99. package/templates-app/beacon-isle-3d/src/game.scene.json +103 -378
  100. package/templates-app/beacon-isle-3d/src/main.ts +11 -1
  101. package/templates-app/beacon-isle-3d/tsconfig.json +1 -1
  102. package/templates-app/beacon-isle-3d/verify.ts +3 -1
  103. package/templates-app/molehill-2d/.incanto/playtest/lost-seed1.json +4277 -0
  104. package/templates-app/molehill-2d/PROJECT/Context.md +58 -0
  105. package/templates-app/molehill-2d/PROJECT/Requirements.md +39 -0
  106. package/templates-app/molehill-2d/PROJECT/Status.md +27 -0
  107. package/templates-app/molehill-2d/PROJECT/Structure.md +48 -0
  108. package/templates-app/molehill-2d/docs/project-2d-rules.md +44 -0
  109. package/templates-app/molehill-2d/index.html +73 -0
  110. package/templates-app/molehill-2d/package.json +23 -0
  111. package/templates-app/molehill-2d/src/behaviors.ts +198 -0
  112. package/templates-app/molehill-2d/src/game.scene.json +1255 -0
  113. package/templates-app/molehill-2d/src/main.ts +41 -0
  114. package/templates-app/molehill-2d/tsconfig.json +13 -0
  115. package/templates-app/molehill-2d/verify.ts +247 -0
  116. package/templates-app/molehill-2d/vite.config.ts +12 -0
  117. package/templates-app/platformer-2d/package.json +2 -2
  118. package/templates-app/platformer-2d/src/game.scene.json +128 -600
  119. package/templates-app/platformer-2d/src/main.ts +11 -1
  120. package/templates-app/platformer-2d/tsconfig.json +1 -1
  121. package/templates-app/star-survivor/package.json +2 -2
  122. package/templates-app/star-survivor/src/game.scene.json +41 -195
  123. package/templates-app/star-survivor/src/main.ts +11 -1
  124. package/templates-app/star-survivor/tsconfig.json +1 -1
  125. package/templates-app/tps-3d/PROJECT/Context.md +1 -1
  126. package/templates-app/tps-3d/package.json +2 -2
  127. package/templates-app/tps-3d/src/behaviors.ts +19 -1
  128. package/templates-app/tps-3d/src/game.scene.json +78 -217
  129. package/templates-app/tps-3d/src/main.ts +13 -2
  130. package/templates-app/tps-3d/tsconfig.json +1 -1
  131. package/templates-app/village-quest-3d/.incanto/playtest/swapped-seed1.json +1735 -0
  132. package/templates-app/village-quest-3d/package.json +2 -2
  133. package/templates-app/village-quest-3d/src/behaviors.ts +21 -0
  134. package/templates-app/village-quest-3d/src/grove.scene.json +54 -221
  135. package/templates-app/village-quest-3d/src/main.ts +11 -1
  136. package/templates-app/village-quest-3d/src/village.scene.json +199 -838
  137. package/templates-app/village-quest-3d/tsconfig.json +1 -1
  138. package/templates-app/village-quest-3d/verify.ts +14 -1
  139. package/dist/duplicate-Dj4L-5AA.js +0 -22
  140. package/dist/json-CwwhxQgb.js +0 -36
  141. package/dist/registry-CF70EArN.js +0 -212
  142. package/dist/rolldown-runtime-D7D4PA-g.js +0 -13
  143. package/dist/test-D6ISmuFE.js +0 -2383
  144. package/dist/touch-DEAmqGdf.js +0 -225
  145. package/editor/assets/agent8-BDvaZMQJ.js +0 -1
  146. package/editor/assets/index-CZIRr5EL.js +0 -10958
package/dist/editor.js CHANGED
@@ -5,33 +5,33 @@ import { registerGameplayBehaviors as A } from "incanto/gameplay";
5
5
  import { registerNodesNet as ee } from "incanto/net";
6
6
  import { GENERATORS as te, runGenerator as j } from "incanto/env";
7
7
  //#region src/format-json.ts
8
- var ne = 80, M = " ";
9
- function N(e) {
10
- return `${re(e, 0)}\n`;
8
+ var ne = 80, re = " ";
9
+ function M(e) {
10
+ return `${ie(e, 0)}\n`;
11
11
  }
12
- function re(e, t) {
12
+ function ie(e, t) {
13
13
  if (typeof e != "object" || !e) return JSON.stringify(e);
14
- let n = P(e);
14
+ let n = N(e);
15
15
  if (t * 2 + n.length <= ne) return n;
16
- let r = M.repeat(t + 1), i = M.repeat(t);
17
- if (Array.isArray(e)) return e.length === 0 ? "[]" : `[\n${e.map((e) => r + re(e, t + 1)).join(",\n")}\n${i}]`;
16
+ let r = re.repeat(t + 1), i = re.repeat(t);
17
+ if (Array.isArray(e)) return e.length === 0 ? "[]" : `[\n${e.map((e) => r + ie(e, t + 1)).join(",\n")}\n${i}]`;
18
18
  let a = Object.entries(e);
19
- return a.length === 0 ? "{}" : `{\n${a.map(([e, n]) => `${r}${JSON.stringify(e)}: ${re(n, t + 1)}`).join(",\n")}\n${i}}`;
19
+ return a.length === 0 ? "{}" : `{\n${a.map(([e, n]) => `${r}${JSON.stringify(e)}: ${ie(n, t + 1)}`).join(",\n")}\n${i}}`;
20
20
  }
21
- function P(e) {
21
+ function N(e) {
22
22
  if (typeof e != "object" || !e) return JSON.stringify(e);
23
- if (Array.isArray(e)) return e.length === 0 ? "[]" : `[${e.map(P).join(", ")}]`;
23
+ if (Array.isArray(e)) return e.length === 0 ? "[]" : `[${e.map(N).join(", ")}]`;
24
24
  let t = Object.entries(e);
25
- return t.length === 0 ? "{}" : `{ ${t.map(([e, t]) => `${JSON.stringify(e)}: ${P(t)}`).join(", ")} }`;
25
+ return t.length === 0 ? "{}" : `{ ${t.map(([e, t]) => `${JSON.stringify(e)}: ${N(t)}`).join(", ")} }`;
26
26
  }
27
27
  //#endregion
28
28
  //#region src/library-api.ts
29
- var ie = class extends Error {
29
+ var ae = class extends Error {
30
30
  needsToken = !0;
31
31
  constructor(e = "the asset library needs a Verse8 access token") {
32
32
  super(e), this.name = "LibraryAuthError";
33
33
  }
34
- }, ae = {
34
+ }, P = {
35
35
  "": ["3d", "2d"],
36
36
  "3d": [
37
37
  "characters",
@@ -46,11 +46,11 @@ var ie = class extends Error {
46
46
  "2d": ["sprite_characters", "projects"]
47
47
  };
48
48
  function oe(e) {
49
- return ae[e.join("/")] ?? [];
49
+ return P[e.join("/")] ?? [];
50
50
  }
51
51
  function se(e) {
52
52
  if (e.length === 0) return [];
53
- let t = ae[e.slice(0, -1).join("/")];
53
+ let t = P[e.slice(0, -1).join("/")];
54
54
  return t ? t.filter((t) => !e.includes(t)) : [];
55
55
  }
56
56
  var ce = 12;
@@ -223,7 +223,7 @@ async function Ie(e) {
223
223
  async function Le(e, t) {
224
224
  await je(await fetch(Fe(t), {
225
225
  method: "PUT",
226
- body: N(e)
226
+ body: M(e)
227
227
  }));
228
228
  }
229
229
  async function Re(e, t) {
@@ -234,7 +234,7 @@ async function Re(e, t) {
234
234
  });
235
235
  e.keyword?.trim() && n.set("keyword", e.keyword.trim());
236
236
  let r = await fetch(`/api/library?${n}`, { headers: t ? { "x-incanto-v8-token": t } : {} });
237
- if (r.status === 401) throw new ie((await r.json().catch(() => ({}))).error);
237
+ if (r.status === 401) throw new ae((await r.json().catch(() => ({}))).error);
238
238
  return await (await je(r)).json();
239
239
  }
240
240
  var ze = {
@@ -1876,11 +1876,22 @@ var en = {
1876
1876
  ko: "groups — 조회용 태그"
1877
1877
  },
1878
1878
  body: {
1879
- en: "Free-form tags. Game code finds nodes with tree-wide queries like getNodesInGroup(\"coins\"), and triggers can filter by group (e.g. only react to \"player\"). Type a name and press Enter.",
1879
+ en: "A LIST of names. Game code finds nodes with tree-wide queries like getNodesInGroup(\"coins\"), and triggers can filter by group (e.g. only react to \"player\"). Type a name and press Enter. For key-values a node carries (what KIND of thing it is, what it is worth) use `tags`, below.",
1880
1880
  ko: "자유 형식 태그입니다. 게임 코드가 getNodesInGroup(\"coins\")처럼 트리 전체에서 노드를 찾고, 트리거는 그룹으로 거릅니다(예: \"player\"에만 반응). 이름을 입력하고 Enter를 누르세요."
1881
1881
  },
1882
1882
  example: "triggerEnter → if (other.isInGroup(\"player\")) collect()"
1883
1883
  },
1884
+ tags: {
1885
+ title: {
1886
+ en: "tags — free-form identity JSON",
1887
+ ko: "tags — 자유 형식 식별 JSON"
1888
+ },
1889
+ body: {
1890
+ en: "Not groups. `groups` is a LIST of names you query the tree by; `tags` is an OBJECT of key-values the node carries for your game logic — what kind of thing it is and what it is worth. Connections filter on them (`filter: {tag: {kind: \"ITEM\"}}`), and a behavior reads `node.tags`. Anything JSON: numbers, strings, nested objects. A rhythm chart lives here — one note node per beat, `{\"beat\": 4, \"lane\": 0}`.",
1891
+ ko: "groups와 다릅니다. `groups`는 트리를 조회하는 이름 목록이고, `tags`는 노드가 지니는 키-값 객체입니다 — 무엇이며 얼마나 값어치가 있는지. 연결이 이것으로 거르고(`filter: {tag: {kind: \"ITEM\"}}`), 비헤이비어는 `node.tags`로 읽습니다. JSON이면 무엇이든 됩니다 — 숫자, 문자열, 중첩 객체."
1892
+ },
1893
+ example: "{\"kind\": \"ITEM\", \"value\": 10}"
1894
+ },
1884
1895
  script: {
1885
1896
  title: {
1886
1897
  en: "script — attach YOUR game logic",
@@ -2337,14 +2348,25 @@ function Pn(e, t) {
2337
2348
  }
2338
2349
  //#endregion
2339
2350
  //#region src/tilemap-paint.ts
2340
- function Fn(e, t, n, r) {
2351
+ function Fn(e, t, n, r, i = 1, a = 1) {
2341
2352
  return {
2342
- cx: Math.floor((n - e.x) / t),
2343
- cy: Math.floor((r - e.y) / t)
2353
+ cx: Math.floor((n - e.x) / (t * (i || 1))),
2354
+ cy: Math.floor((r - e.y) / (t * (a || 1)))
2344
2355
  };
2345
2356
  }
2346
2357
  function In(e, t, n, r) {
2347
2358
  if (t < 0 || n < 0 || r.length !== 1) return null;
2359
+ if (e.some((e) => Array.isArray(e))) {
2360
+ let i = Number(r);
2361
+ if (!Number.isInteger(i) || i < 0) return null;
2362
+ let a = e.map((e) => Array.isArray(e) ? [...e] : [...e].map((e) => Number(e) || 0)), o = Math.max(t + 1, ...a.map((e) => e.length)), s = Math.max(n + 1, a.length), c = [];
2363
+ for (let e = 0; e < s; e++) {
2364
+ let r = a[e] ?? [];
2365
+ for (; r.length < o;) r.push(-1);
2366
+ e === n && (r[t] = i), c.push(r);
2367
+ }
2368
+ return c;
2369
+ }
2348
2370
  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 = [];
2349
2371
  for (let e = 0; e < o; e++) {
2350
2372
  let o = i[e] ?? "";
@@ -2384,7 +2406,7 @@ var Vn = [
2384
2406
  "environment"
2385
2407
  ];
2386
2408
  function Hn(e, t, n) {
2387
- e.appendChild(Tr("scene")), e.appendChild(Ar("name", String(t.working.name ?? ""), (e) => {
2409
+ e.appendChild(Or("scene")), e.appendChild(Nr("name", String(t.working.name ?? ""), (e) => {
2388
2410
  t.mutate(() => {
2389
2411
  t.working.name = e;
2390
2412
  });
@@ -2398,13 +2420,13 @@ function Hn(e, t, n) {
2398
2420
  t.mutate(() => {
2399
2421
  t.working.dimension = r.value;
2400
2422
  });
2401
- }), e.appendChild(B("dimension", r));
2423
+ }), e.appendChild(V("dimension", r));
2402
2424
  let i = document.createElement("input");
2403
2425
  i.type = "checkbox", i.checked = t.working.fragment === !0, i.addEventListener("change", () => {
2404
2426
  t.mutate(() => {
2405
2427
  i.checked ? t.working.fragment = !0 : delete t.working.fragment;
2406
2428
  });
2407
- }), e.appendChild(B("fragment", i)), e.appendChild(Tr("physics", "physics"));
2429
+ }), e.appendChild(V("fragment", i)), e.appendChild(Or("physics", "physics"));
2408
2430
  let a = (t.working.physics ?? {}).gravity ?? (t.working.dimension === "3d" ? [
2409
2431
  0,
2410
2432
  -9.81,
@@ -2414,7 +2436,7 @@ function Hn(e, t, n) {
2414
2436
  -9.81,
2415
2437
  0
2416
2438
  ] : [0, 980];
2417
- e.appendChild(Mr("gravity", a, (e) => {
2439
+ e.appendChild(Fr("gravity", a, (e) => {
2418
2440
  t.mutate(() => {
2419
2441
  if (JSON.stringify(e) === JSON.stringify(o)) {
2420
2442
  let e = { ...t.working.physics };
@@ -2424,8 +2446,8 @@ function Hn(e, t, n) {
2424
2446
  gravity: e
2425
2447
  };
2426
2448
  });
2427
- })), e.appendChild(Tr("environment")), Un(e, t), e.appendChild(Tr("constants")), yr(e, t, n), e.appendChild(Tr("draw order bands")), vr(e, t), e.appendChild(Tr("advanced"));
2428
- for (let n of Vn) e.appendChild(Pr(n, t.working[n], (e) => {
2449
+ })), e.appendChild(Or("environment")), Un(e, t), e.appendChild(Or("constants")), yr(e, t, n), e.appendChild(Or("strings")), Sr(e, t, n), e.appendChild(Or("draw order bands")), vr(e, t), e.appendChild(Or("advanced"));
2450
+ for (let n of Vn) e.appendChild(Lr(n, t.working[n], (e) => {
2429
2451
  t.mutate(() => {
2430
2452
  e === void 0 ? delete t.working[n] : t.working[n] = e;
2431
2453
  });
@@ -2450,7 +2472,7 @@ function Un(e, t) {
2450
2472
  color: e === "" ? void 0 : e
2451
2473
  };
2452
2474
  t.color === void 0 && delete t.color, r({ ambient: Object.keys(t).length ? t : void 0 });
2453
- })), e.appendChild(jr("ambient power", n.ambient?.intensity ?? 0, (e) => {
2475
+ })), e.appendChild(Pr("ambient power", n.ambient?.intensity ?? 0, (e) => {
2454
2476
  r({ ambient: {
2455
2477
  ...n.ambient,
2456
2478
  intensity: e
@@ -2466,7 +2488,7 @@ function Un(e, t) {
2466
2488
  }, o = document.createElement("input");
2467
2489
  o.type = "checkbox", o.checked = i.antialias !== !1, o.addEventListener("change", () => {
2468
2490
  a({ antialias: o.checked ? void 0 : !1 });
2469
- }), e.appendChild(B("antialias", o));
2491
+ }), e.appendChild(V("antialias", o));
2470
2492
  let s = document.createElement("select");
2471
2493
  for (let [e, t] of [
2472
2494
  ["", "1 — soft hiDPI upscale (default)"],
@@ -2478,7 +2500,7 @@ function Un(e, t) {
2478
2500
  }
2479
2501
  s.addEventListener("change", () => {
2480
2502
  a({ pixelRatio: s.value === "" ? void 0 : s.value === "device" ? "device" : Number(s.value) });
2481
- }), e.appendChild(B("pixel ratio", s));
2503
+ }), e.appendChild(V("pixel ratio", s));
2482
2504
  }
2483
2505
  function Wn(e, t, n) {
2484
2506
  let r = document.createElement("div");
@@ -2488,7 +2510,7 @@ function Wn(e, t, n) {
2488
2510
  let a = document.createElement("input");
2489
2511
  return a.type = "text", a.className = "mono", a.placeholder = "unset", a.value = t, i.addEventListener("input", () => {
2490
2512
  a.value = i.value;
2491
- }), i.addEventListener("change", () => n(i.value)), a.addEventListener("change", () => n(a.value.trim())), r.append(i, a), B(e, r);
2513
+ }), i.addEventListener("change", () => n(i.value)), a.addEventListener("change", () => n(a.value.trim())), r.append(i, a), V(e, r);
2492
2514
  }
2493
2515
  function Gn(e, t) {
2494
2516
  let n = document.createElement("div");
@@ -2503,10 +2525,10 @@ function Gn(e, t) {
2503
2525
  let n = { ...o };
2504
2526
  t === void 0 || t === "" ? delete n[e] : n[e] = t, s(Object.keys(n).length === 0 ? !0 : n);
2505
2527
  }, l = document.createElement("input");
2506
- if (l.type = "checkbox", l.checked = a, l.addEventListener("change", () => s(l.checked)), n.appendChild(B("enabled", l)), a) {
2507
- n.appendChild(Wn("murk color", String(o.color ?? ""), (e) => c("color", e))), n.appendChild(jr("visibility (m)", Number(o.visibility ?? 22), (e) => c("visibility", e === 22 ? void 0 : e), () => c("visibility", void 0)));
2528
+ if (l.type = "checkbox", l.checked = a, l.addEventListener("change", () => s(l.checked)), n.appendChild(V("enabled", l)), a) {
2529
+ n.appendChild(Wn("murk color", String(o.color ?? ""), (e) => c("color", e))), n.appendChild(Pr("visibility (m)", Number(o.visibility ?? 22), (e) => c("visibility", e === 22 ? void 0 : e), () => c("visibility", void 0)));
2508
2530
  let e = document.createElement("input");
2509
- e.type = "checkbox", e.checked = (o.caustics ?? !0) !== !1, e.addEventListener("change", () => c("caustics", e.checked ? void 0 : !1)), n.appendChild(B("caustics", e));
2531
+ e.type = "checkbox", e.checked = (o.caustics ?? !0) !== !1, e.addEventListener("change", () => c("caustics", e.checked ? void 0 : !1)), n.appendChild(V("caustics", e));
2510
2532
  }
2511
2533
  return n;
2512
2534
  }
@@ -2529,13 +2551,13 @@ function Kn(e, t, n) {
2529
2551
  };
2530
2552
  r.appendChild(Wn("color", String(a.color ?? ""), (e) => o("color", e))), r.appendChild(Xn("roughness", Number(a.roughness ?? 1), (e) => o("roughness", e))), r.appendChild(Xn("metalness", Number(a.metalness ?? 0), (e) => o("metalness", e))), r.appendChild(Wn("emissive", String(a.emissive ?? ""), (e) => o("emissive", e))), r.appendChild(Xn("emissive power", Number(a.emissiveIntensity ?? 1), (e) => o("emissiveIntensity", e === 1 ? void 0 : e), 2)), r.appendChild(Xn("opacity", Number(a.opacity ?? 1), (e) => o("opacity", e === 1 ? void 0 : e))), r.appendChild(Xn("clearcoat", Number(a.clearcoat ?? 0), (e) => o("clearcoat", e === 0 ? void 0 : e))), r.appendChild(Xn("clearcoat rough", Number(a.clearcoatRoughness ?? 0), (e) => o("clearcoatRoughness", e === 0 ? void 0 : e))), r.appendChild(Xn("reflection", Number(a.envMapIntensity ?? 1), (e) => o("envMapIntensity", e === 1 ? void 0 : e), 3));
2531
2553
  let s = document.createElement("input");
2532
- s.type = "checkbox", s.checked = a.wireframe === !0, s.addEventListener("change", () => o("wireframe", s.checked || void 0)), r.appendChild(B("wireframe", s));
2554
+ s.type = "checkbox", s.checked = a.wireframe === !0, s.addEventListener("change", () => o("wireframe", s.checked || void 0)), r.appendChild(V("wireframe", s));
2533
2555
  let c = document.createElement("input");
2534
- c.type = "checkbox", c.checked = a.flatShading === !0, c.addEventListener("change", () => o("flatShading", c.checked || void 0)), r.appendChild(B("flatShading", c));
2556
+ c.type = "checkbox", c.checked = a.flatShading === !0, c.addEventListener("change", () => o("flatShading", c.checked || void 0)), r.appendChild(V("flatShading", c));
2535
2557
  let l = document.createElement("input");
2536
2558
  l.type = "checkbox", l.checked = a.depthTest === !1, l.addEventListener("change", () => {
2537
2559
  o("depthTest", l.checked ? !1 : void 0), o("depthWrite", l.checked ? !1 : void 0);
2538
- }), r.appendChild(B("draw on top (decal)", l)), r.appendChild(lr("map (texture)", String(a.map ?? ""), ur((e) => zn(e) && !e.name.includes("normal") && !e.name.includes("roughness")), (e) => o("map", e.trim()), {
2560
+ }), r.appendChild(V("draw on top (decal)", l)), r.appendChild(B("map (texture)", String(a.map ?? ""), ur((e) => zn(e) && !e.name.includes("normal") && !e.name.includes("roughness")), (e) => o("map", e.trim()), {
2539
2561
  placeholder: "built-in or custom URL",
2540
2562
  library: {
2541
2563
  kind: "image",
@@ -2543,7 +2565,7 @@ function Kn(e, t, n) {
2543
2565
  shelf: ["3d", "textures"]
2544
2566
  },
2545
2567
  ctx: n
2546
- })), r.appendChild(lr("normal map", String(a.normalMap ?? ""), ur((e) => zn(e) && e.name.includes("normal")), (e) => o("normalMap", e.trim()), {
2568
+ })), r.appendChild(B("normal map", String(a.normalMap ?? ""), ur((e) => zn(e) && e.name.includes("normal")), (e) => o("normalMap", e.trim()), {
2547
2569
  placeholder: "built-in or custom URL",
2548
2570
  library: {
2549
2571
  kind: "image",
@@ -2552,7 +2574,7 @@ function Kn(e, t, n) {
2552
2574
  },
2553
2575
  ctx: n
2554
2576
  }));
2555
- let u = !!(a.map || a.normalMap), d = Array.isArray(a.repeat) ? a.repeat : [1, 1], f = Mr("repeat [u,v]", [d[0] ?? 1, d[1] ?? 1], (e) => {
2577
+ let u = !!(a.map || a.normalMap), d = Array.isArray(a.repeat) ? a.repeat : [1, 1], f = Fr("repeat [u,v]", [d[0] ?? 1, d[1] ?? 1], (e) => {
2556
2578
  let [t, n] = e;
2557
2579
  !Number.isFinite(t) || !Number.isFinite(n) || t === 1 && n === 1 || !t && !n ? o("repeat", void 0) : o("repeat", [t, n]);
2558
2580
  });
@@ -2574,7 +2596,7 @@ function Jn(e, t, n, r) {
2574
2596
  let o = document.createElement("strong");
2575
2597
  o.textContent = "animation", a.appendChild(o), i.appendChild(a);
2576
2598
  let s = String(t.props?.animation ?? "");
2577
- if (i.appendChild(lr("clip", s, n.animationsForSelection().map((e) => ({
2599
+ if (i.appendChild(B("clip", s, n.animationsForSelection().map((e) => ({
2578
2600
  label: e,
2579
2601
  value: e,
2580
2602
  hint: e.startsWith("$") ? "scene asset" : "clip in this model"
@@ -2592,23 +2614,30 @@ function Jn(e, t, n, r) {
2592
2614
  let a = document.createElement("div");
2593
2615
  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(Yn(e, t, n, r)), i;
2594
2616
  }
2595
- i.appendChild(xr(e, t, "animationLoop", r.animationLoop?.default ?? !0, void 0, "loop"));
2617
+ i.appendChild(wr(e, t, "animationLoop", r.animationLoop?.default ?? !0, void 0, "loop"));
2596
2618
  let c = Xn("speed", Number(t.props?.animationSpeed ?? 1), (n) => z(e, t, "animationSpeed", n, 1), 3, -3);
2597
2619
  c.title = "1 = as authored · 0 freezes the pose · negative plays backwards (a closing door is an opening one reversed).", i.appendChild(c);
2598
- let l = xr(e, t, "animationOffset", r.animationOffset?.default ?? 0, void 0, "offset (s)");
2620
+ let l = wr(e, t, "animationOffset", r.animationOffset?.default ?? 0, void 0, "offset (s)");
2599
2621
  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(Yn(e, t, n, r)), i;
2600
2622
  }
2601
2623
  function Yn(e, t, n, r) {
2602
2624
  let i = document.createElement("details");
2603
2625
  i.className = "anim-upper", t.props?.animationUpper && (i.open = !0);
2604
2626
  let a = document.createElement("summary");
2605
- return a.textContent = "upper-body layer", a.title = "Play a second clip on the upper body only — attack while running, wave while walking.", i.appendChild(a), i.appendChild(lr("clip", String(t.props?.animationUpper ?? ""), n.animationsForSelection().map((e) => ({
2627
+ return a.textContent = "upper-body layer", a.title = "Play a second clip on the upper body only — attack while running, wave while walking.", i.appendChild(a), i.appendChild(B("clip", String(t.props?.animationUpper ?? ""), n.animationsForSelection().map((e) => ({
2606
2628
  label: e,
2607
2629
  value: e
2608
2630
  })), (n) => z(e, t, "animationUpper", n.trim(), ""), {
2609
2631
  placeholder: "empty = off",
2632
+ library: {
2633
+ kind: "model",
2634
+ target: "animationUpper",
2635
+ shelf: ["3d", "animations"],
2636
+ asAsset: !0,
2637
+ assetType: "animation"
2638
+ },
2610
2639
  ctx: n
2611
- })), i.appendChild(xr(e, t, "animationUpperLoop", r.animationUpperLoop?.default ?? !1, void 0, "loop")), i.appendChild(xr(e, t, "upperBodyRoot", r.upperBodyRoot?.default ?? "Spine", void 0, "root bone")), i;
2640
+ })), i.appendChild(wr(e, t, "animationUpperLoop", r.animationUpperLoop?.default ?? !1, void 0, "loop")), i.appendChild(wr(e, t, "upperBodyRoot", r.upperBodyRoot?.default ?? "Spine", void 0, "root bone")), i;
2612
2641
  }
2613
2642
  function Xn(e, t, n, r = 1, i = 0) {
2614
2643
  let a = document.createElement("div");
@@ -2620,21 +2649,21 @@ function Xn(e, t, n, r = 1, i = 0) {
2620
2649
  s.value = o.value;
2621
2650
  }), o.addEventListener("change", () => n(Number(o.value))), s.addEventListener("change", () => {
2622
2651
  o.value = s.value, n(Number(s.value));
2623
- }), a.append(o, s), B(e, a);
2652
+ }), a.append(o, s), V(e, a);
2624
2653
  }
2625
2654
  function Zn(e, t, n, r) {
2626
- if (e.appendChild(Tr(n.type ?? "instance")), e.appendChild(Qn(n)), e.appendChild(Ar("name", n.name ?? "", (e) => {
2655
+ if (e.appendChild(Or(n.type ?? "instance")), e.appendChild(Qn(n)), e.appendChild(Nr("name", n.name ?? "", (e) => {
2627
2656
  e.trim() === "" || t.selection === null || t.renameNode(t.selection, e.trim());
2628
- })), n.type === "TileMap2D" && r?.paint && e.appendChild(Nr(n, r.paint)), n.type) {
2657
+ })), n.type === "TileMap2D" && r?.paint && e.appendChild(Ir(n, r.paint)), n.type) {
2629
2658
  let i;
2630
2659
  try {
2631
2660
  i = s(n.type);
2632
2661
  } catch {
2633
2662
  i = {};
2634
2663
  }
2635
- for (let [a, o] of Object.entries(i)) if (a === "collider") e.appendChild(ar(t, n, o.default));
2664
+ for (let [a, o] of Object.entries(i)) if (a === "collider") e.appendChild(or(t, n, o.default));
2636
2665
  else if (a === "material") e.appendChild(Kn(t, n, r));
2637
- else if (n.type === "ModelInstance3D" && a === "model" && r) e.appendChild(lr("model", String(n.props?.model ?? ""), r.modelRefs().map((e) => ({
2666
+ else if (n.type === "ModelInstance3D" && a === "model" && r) e.appendChild(B("model", String(n.props?.model ?? ""), r.modelRefs().map((e) => ({
2638
2667
  label: e,
2639
2668
  value: e,
2640
2669
  hint: "scene asset"
@@ -2648,9 +2677,9 @@ function Zn(e, t, n, r) {
2648
2677
  },
2649
2678
  ctx: r
2650
2679
  }));
2651
- else if (n.type === "BoneAttachment3D" && a === "bone" && r?.bonesForSelection) e.appendChild(sr("bone", String(n.props?.bone ?? ""), r.bonesForSelection(String(n.props?.target ?? "")), (e) => z(t, n, "bone", e, "")));
2680
+ else if (n.type === "BoneAttachment3D" && a === "bone" && r?.bonesForSelection) e.appendChild(cr("bone", String(n.props?.bone ?? ""), r.bonesForSelection(String(n.props?.target ?? "")), (e) => z(t, n, "bone", e, "")));
2652
2681
  else if (n.type === "ModelInstance3D" && a === "animation" && r) e.appendChild(Jn(t, n, r, i));
2653
- else if (!(n.type === "ModelInstance3D" && qn.has(a))) if ((n.type === "Sprite3D" || n.type === "AnimatedSprite3D") && (a === "texture" || a === "sheet")) e.appendChild(lr(a === "sheet" ? "sheet (image URL)" : "texture (image URL)", String(n.props?.[a] ?? ""), ur((e) => e.kind === "character" || e.kind === "item"), (e) => z(t, n, a, e.trim(), ""), {
2682
+ else if (!(n.type === "ModelInstance3D" && qn.has(a))) if ((n.type === "Sprite3D" || n.type === "AnimatedSprite3D") && (a === "texture" || a === "sheet")) e.appendChild(B(a === "sheet" ? "sheet (image URL)" : "texture (image URL)", String(n.props?.[a] ?? ""), ur((e) => e.kind === "character" || e.kind === "item"), (e) => z(t, n, a, e.trim(), ""), {
2654
2683
  placeholder: "image URL — empty hides the sprite",
2655
2684
  library: {
2656
2685
  kind: "image",
@@ -2659,7 +2688,7 @@ function Zn(e, t, n, r) {
2659
2688
  },
2660
2689
  ctx: r
2661
2690
  }));
2662
- else if (n.type === "TileMap2D" && a === "texture") e.appendChild(lr("texture (atlas $ref)", String(n.props?.texture ?? ""), (r?.assetRefs?.(["texture", "spritesheet"]) ?? []).map((e) => ({
2691
+ else if (n.type === "TileMap2D" && a === "texture") e.appendChild(B("texture (atlas $ref)", String(n.props?.texture ?? ""), (r?.assetRefs?.(["texture", "spritesheet"]) ?? []).map((e) => ({
2663
2692
  label: e,
2664
2693
  value: e,
2665
2694
  hint: "scene asset"
@@ -2674,7 +2703,7 @@ function Zn(e, t, n, r) {
2674
2703
  },
2675
2704
  ctx: r
2676
2705
  }));
2677
- else if (n.type === "Tree3D" && a === "leafTexture") e.appendChild(lr("leaf texture", String(n.props?.leafTexture ?? ""), ur((e) => e.name.startsWith("leaves_")), (e) => z(t, n, "leafTexture", e.trim(), ""), {
2706
+ else if (n.type === "Tree3D" && a === "leafTexture") e.appendChild(B("leaf texture", String(n.props?.leafTexture ?? ""), ur((e) => e.name.startsWith("leaves_")), (e) => z(t, n, "leafTexture", e.trim(), ""), {
2678
2707
  placeholder: "default (per-type) or URL",
2679
2708
  library: {
2680
2709
  kind: "image",
@@ -2683,11 +2712,11 @@ function Zn(e, t, n, r) {
2683
2712
  },
2684
2713
  ctx: r
2685
2714
  }));
2686
- else if (n.type === "Terrain3D" && a === "textureBase") e.appendChild(lr("texture base", String(n.props?.textureBase ?? o.default ?? ""), fr, (e) => z(t, n, "textureBase", e.trim(), o.default), { placeholder: "splat texture base URL" }));
2715
+ else if (n.type === "Terrain3D" && a === "textureBase") e.appendChild(B("texture base", String(n.props?.textureBase ?? o.default ?? ""), fr, (e) => z(t, n, "textureBase", e.trim(), o.default), { placeholder: "splat texture base URL" }));
2687
2716
  else if (n.type === "AnimatedSprite2D" && a === "sheet" || n.type === "Sprite2D" && a === "texture") {
2688
2717
  let i = a === "sheet";
2689
2718
  e.appendChild(pr(t, n, a, r, i));
2690
- } else n.type === "AudioPlayer" && a === "src" ? e.appendChild(lr("src (audio file)", String(n.props?.src ?? ""), dr(), (e) => z(t, n, "src", e.trim(), ""), {
2719
+ } else n.type === "AudioPlayer" && a === "src" ? e.appendChild(B("src (audio file)", String(n.props?.src ?? ""), dr(), (e) => z(t, n, "src", e.trim(), ""), {
2691
2720
  placeholder: "built-in or custom URL — or use preset",
2692
2721
  note: "For zero-asset SFX, set the `preset` prop instead of src.",
2693
2722
  library: {
@@ -2695,11 +2724,11 @@ function Zn(e, t, n, r) {
2695
2724
  target: "audio src"
2696
2725
  },
2697
2726
  ctx: r
2698
- })) : n.type === "Flowers3D" && a === "varieties" ? e.appendChild(mr(t, n)) : n.type === "Water3D" && a === "underwater" ? e.appendChild(Gn(t, n)) : e.appendChild(xr(t, n, a, o.default, o.options, void 0, o.nodePath === !0));
2727
+ })) : n.type === "Flowers3D" && a === "varieties" ? e.appendChild(mr(t, n)) : n.type === "Water3D" && a === "underwater" ? e.appendChild(Gn(t, n)) : e.appendChild(wr(t, n, a, o.default, o.options, void 0, o.nodePath === !0, o.kinds));
2699
2728
  }
2700
- if (e.appendChild(Tr("structure")), e.appendChild($n(t, n)), e.appendChild(er(t, n)), e.appendChild(ir(t, n)), t.selection) {
2729
+ if (e.appendChild(Or("structure")), e.appendChild($n(t, n)), e.appendChild(er(t, n)), e.appendChild(tr(t, n)), e.appendChild(ar(t, n)), t.selection) {
2701
2730
  let n = Sn(t, t.selection);
2702
- n && (e.appendChild(Tr("connections", "connections")), e.appendChild(n));
2731
+ n && (e.appendChild(Or("connections", "connections")), e.appendChild(n));
2703
2732
  }
2704
2733
  }
2705
2734
  function Qn(e) {
@@ -2725,7 +2754,7 @@ function $n(e, t) {
2725
2754
  r.append("groups ", an("groups"));
2726
2755
  let i = document.createElement("div");
2727
2756
  i.className = "chips";
2728
- for (let n of t.groups ?? []) i.appendChild(Er(n, () => {
2757
+ for (let n of t.groups ?? []) i.appendChild(kr(n, () => {
2729
2758
  e.mutate(() => {
2730
2759
  t.groups = (t.groups ?? []).filter((e) => e !== n), t.groups.length === 0 && delete t.groups;
2731
2760
  });
@@ -2740,6 +2769,14 @@ function $n(e, t) {
2740
2769
  }), i.appendChild(a), i.addEventListener("click", () => a.focus()), n.append(r, i), n;
2741
2770
  }
2742
2771
  function er(e, t) {
2772
+ let n = Lr("tags", t.tags, (n) => {
2773
+ e.mutate(() => {
2774
+ n === void 0 ? delete t.tags : t.tags = n;
2775
+ });
2776
+ }, "{\"kind\": \"ITEM\", \"value\": 10}", (e) => typeof e == "object" && !!e && !Array.isArray(e)), r = n.querySelector("span");
2777
+ return r && r.append(" ", an("tags")), n;
2778
+ }
2779
+ function tr(e, t) {
2743
2780
  let n = document.createElement("div");
2744
2781
  n.className = "subcard";
2745
2782
  let i = document.createElement("div");
@@ -2761,19 +2798,19 @@ function er(e, t) {
2761
2798
  let i = document.createElement("button");
2762
2799
  return i.type = "button", i.className = "ghost", i.textContent = "+ attach behavior", i.addEventListener("click", () => {
2763
2800
  e.mutate(() => {
2764
- t.script = { name: tr()[0] ?? "MyBehavior" };
2801
+ t.script = { name: nr()[0] ?? "MyBehavior" };
2765
2802
  });
2766
2803
  }), n.append(r, i), n;
2767
2804
  }
2768
- let s = o.name ?? "", c = tr();
2769
- n.appendChild(Dr("name", s, c, (n) => {
2805
+ let s = o.name ?? "", c = nr();
2806
+ n.appendChild(Ar("name", s, c, (n) => {
2770
2807
  e.mutate(() => {
2771
2808
  t.script.name = n, delete t.script.props;
2772
2809
  });
2773
2810
  }));
2774
2811
  let l = c.includes(s) ? r(s) : null;
2775
- if (l && Object.keys(l).length > 0) for (let [r, i] of Object.entries(l)) n.appendChild(nr(e, t, r, i.default, i.options, i.nodePath === !0));
2776
- else n.appendChild(Pr("props", o.props, (n) => {
2812
+ if (l && Object.keys(l).length > 0) for (let [r, i] of Object.entries(l)) n.appendChild(rr(e, t, r, i.default, i.options, i.nodePath === !0));
2813
+ else n.appendChild(Lr("props", o.props, (n) => {
2777
2814
  e.mutate(() => {
2778
2815
  n === void 0 ? delete t.script.props : t.script.props = n;
2779
2816
  });
@@ -2781,10 +2818,10 @@ function er(e, t) {
2781
2818
  let u = document.createElement("div");
2782
2819
  return u.className = "muted-note", u.textContent = l ? "Shipped with the engine — these props are its own." : "Not a built-in: this is a TypeScript class in your game. ? has the boilerplate.", n.appendChild(u), n;
2783
2820
  }
2784
- function tr() {
2821
+ function nr() {
2785
2822
  return [...h()].sort();
2786
2823
  }
2787
- function nr(e, t, n, r, i, a = !1) {
2824
+ function rr(e, t, n, r, i, a = !1) {
2788
2825
  let o = (t.script?.props ?? {})[n] ?? r, s = (i) => {
2789
2826
  e.mutate(() => {
2790
2827
  let e = t.script;
@@ -2793,17 +2830,17 @@ function nr(e, t, n, r, i, a = !1) {
2793
2830
  JSON.stringify(i) === JSON.stringify(r) ? delete a[n] : a[n] = i, Object.keys(a).length === 0 && delete e.props;
2794
2831
  });
2795
2832
  };
2796
- if (i && i.length > 0) return Dr(n, String(o), [...i], (e) => s(e));
2833
+ if (i && i.length > 0) return Ar(n, String(o), [...i], (e) => s(e));
2797
2834
  if (typeof r == "boolean") {
2798
2835
  let e = document.createElement("input");
2799
- return e.type = "checkbox", e.checked = !!o, e.addEventListener("change", () => s(e.checked)), B(n, e);
2836
+ return e.type = "checkbox", e.checked = !!o, e.addEventListener("change", () => s(e.checked)), V(n, e);
2800
2837
  }
2801
- return typeof r == "number" ? jr(n, Number(o), (e) => s(e)) : typeof r == "string" ? a ? rr(e, n, String(o), (e) => s(e)) : Ar(n, String(o), (e) => s(e)) : Pr(n, o, (e) => s(e === void 0 ? r : e));
2838
+ return typeof r == "number" ? Pr(n, Number(o), (e) => s(e)) : typeof r == "string" ? a ? ir(e, n, String(o), (e) => s(e)) : Nr(n, String(o), (e) => s(e)) : Lr(n, o, (e) => s(e === void 0 ? r : e));
2802
2839
  }
2803
- function rr(e, t, n, r) {
2840
+ function ir(e, t, n, r) {
2804
2841
  let i = e.working.root, a = e.selection ?? [], o = document.createElement("input");
2805
2842
  o.type = "text", o.value = n, o.placeholder = "%Player, ../Skin, /root/Level/Goal";
2806
- let s = `nodepath-${or++}`;
2843
+ let s = `nodepath-${sr++}`;
2807
2844
  o.setAttribute("list", s);
2808
2845
  let c = document.createElement("datalist");
2809
2846
  c.id = s;
@@ -2812,7 +2849,7 @@ function rr(e, t, n, r) {
2812
2849
  t.value = e, c.appendChild(t);
2813
2850
  }
2814
2851
  o.addEventListener("change", () => r(o.value.trim()));
2815
- let l = B(t, o);
2852
+ let l = V(t, o);
2816
2853
  l.appendChild(c);
2817
2854
  let u = n === "" ? null : Dn(i, a, n);
2818
2855
  if (!u || u.ok) return l;
@@ -2825,7 +2862,7 @@ function rr(e, t, n, r) {
2825
2862
  let f = document.createElement("div");
2826
2863
  return f.append(l, d), f;
2827
2864
  }
2828
- function ir(e, t) {
2865
+ function ar(e, t) {
2829
2866
  let n = document.createElement("div");
2830
2867
  n.className = "subcard";
2831
2868
  let r = document.createElement("div");
@@ -2842,10 +2879,10 @@ function ir(e, t) {
2842
2879
  sync: i?.sync ?? ["position"]
2843
2880
  };
2844
2881
  });
2845
- }), n.appendChild(B("mode", a)), i?.mode === "owner") {
2882
+ }), n.appendChild(V("mode", a)), i?.mode === "owner") {
2846
2883
  let r = document.createElement("div");
2847
2884
  r.className = "chips";
2848
- for (let n of i.sync ?? []) r.appendChild(Er(n, () => {
2885
+ for (let n of i.sync ?? []) r.appendChild(kr(n, () => {
2849
2886
  e.mutate(() => {
2850
2887
  t.network.sync = (i.sync ?? []).filter((e) => e !== n);
2851
2888
  });
@@ -2861,7 +2898,7 @@ function ir(e, t) {
2861
2898
  let o = document.createElement("label");
2862
2899
  o.className = "field wide";
2863
2900
  let s = document.createElement("span");
2864
- s.textContent = "sync keys", o.append(s, r), n.appendChild(o), n.appendChild(jr("throttle ms", i.throttleMs ?? 50, (n) => {
2901
+ s.textContent = "sync keys", o.append(s, r), n.appendChild(o), n.appendChild(Pr("throttle ms", i.throttleMs ?? 50, (n) => {
2865
2902
  e.mutate(() => {
2866
2903
  t.network.throttleMs = n;
2867
2904
  });
@@ -2869,7 +2906,7 @@ function ir(e, t) {
2869
2906
  }
2870
2907
  return n;
2871
2908
  }
2872
- function ar(e, t, n) {
2909
+ function or(e, t, n) {
2873
2910
  let r = document.createElement("div");
2874
2911
  r.className = "subcard";
2875
2912
  let i = document.createElement("div");
@@ -2921,23 +2958,23 @@ function ar(e, t, n) {
2921
2958
  radius: a.radius ?? 12,
2922
2959
  height: a.height ?? 16
2923
2960
  });
2924
- }), r.appendChild(B("shape", l)), a.shape === "rect" || a.shape === "box" ? r.appendChild(Mr("size", a.size ?? (s ? [
2961
+ }), r.appendChild(V("shape", l)), a.shape === "rect" || a.shape === "box" ? r.appendChild(Fr("size", a.size ?? (s ? [
2925
2962
  1,
2926
2963
  1,
2927
2964
  1
2928
2965
  ] : [32, 32]), (e) => o({
2929
2966
  ...a,
2930
2967
  size: e
2931
- }))) : a.shape === "circle" || a.shape === "sphere" ? r.appendChild(jr("radius", a.radius ?? (s ? .5 : 16), (e) => o({
2968
+ }))) : a.shape === "circle" || a.shape === "sphere" ? r.appendChild(Pr("radius", a.radius ?? (s ? .5 : 16), (e) => o({
2932
2969
  ...a,
2933
2970
  radius: e
2934
- }))) : a.shape === "capsule" && (r.appendChild(jr("radius", a.radius ?? 12, (e) => o({
2971
+ }))) : a.shape === "capsule" && (r.appendChild(Pr("radius", a.radius ?? 12, (e) => o({
2935
2972
  ...a,
2936
2973
  radius: e
2937
- }))), r.appendChild(jr("height", a.height ?? 16, (e) => o({
2974
+ }))), r.appendChild(Pr("height", a.height ?? 16, (e) => o({
2938
2975
  ...a,
2939
2976
  height: e
2940
- })))), a.shape && r.appendChild(Mr("offset", a.offset ?? (s ? [
2977
+ })))), a.shape && r.appendChild(Fr("offset", a.offset ?? (s ? [
2941
2978
  0,
2942
2979
  0,
2943
2980
  0
@@ -2951,11 +2988,11 @@ function z(e, t, n, r, i) {
2951
2988
  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;
2952
2989
  });
2953
2990
  }
2954
- var or = 0;
2955
- function sr(e, t, n, r) {
2991
+ var sr = 0;
2992
+ function cr(e, t, n, r) {
2956
2993
  let i = document.createElement("input");
2957
2994
  i.type = "text", i.value = t;
2958
- let a = `suggest-${or++}`;
2995
+ let a = `suggest-${sr++}`;
2959
2996
  i.setAttribute("list", a);
2960
2997
  let o = document.createElement("datalist");
2961
2998
  o.id = a;
@@ -2964,11 +3001,11 @@ function sr(e, t, n, r) {
2964
3001
  t.value = e, o.appendChild(t);
2965
3002
  }
2966
3003
  i.addEventListener("change", () => r(i.value.trim()));
2967
- let s = B(e, i);
3004
+ let s = V(e, i);
2968
3005
  return s.appendChild(o), s;
2969
3006
  }
2970
- var cr = 0;
2971
- function lr(e, t, n, r, i = {}) {
3007
+ var lr = 0;
3008
+ function B(e, t, n, r, i = {}) {
2972
3009
  let a = document.createElement("label");
2973
3010
  a.className = "field wide asset-field";
2974
3011
  let o = document.createElement("span");
@@ -3035,7 +3072,7 @@ function lr(e, t, n, r, i = {}) {
3035
3072
  let e = document.createElement("div");
3036
3073
  e.className = "muted-note asset-note", e.textContent = i.note, a.appendChild(e);
3037
3074
  }
3038
- return s.id = `asset-input-${cr++}`, a.htmlFor = s.id, a;
3075
+ return s.id = `asset-input-${lr++}`, a.htmlFor = s.id, a;
3039
3076
  }
3040
3077
  function ur(e) {
3041
3078
  return Rn.filter(e).map((e) => ({
@@ -3069,7 +3106,7 @@ function pr(e, t, n, r, i) {
3069
3106
  value: `$${e.name}`,
3070
3107
  hint: `${e.kind} · creates a scene asset (${e.animation ? "spritesheet" : "texture"})`
3071
3108
  });
3072
- return lr(i ? "sheet" : "texture", a, s, (i) => {
3109
+ return B(i ? "sheet" : "texture", a, s, (i) => {
3073
3110
  let a = i.startsWith("$") && c.find((e) => `$${e.name}` === i);
3074
3111
  if (a && r?.addAsset) {
3075
3112
  let i = {
@@ -3175,7 +3212,7 @@ function vr(e, t) {
3175
3212
  }
3176
3213
  for (let t of i) {
3177
3214
  let n = document.createElement("div");
3178
- n.className = "const-row", n.appendChild(jr(t, r[t] ?? 0, (e) => a({
3215
+ n.className = "const-row", n.appendChild(Pr(t, r[t] ?? 0, (e) => a({
3179
3216
  ...r,
3180
3217
  [t]: e
3181
3218
  })));
@@ -3226,7 +3263,7 @@ function yr(e, t, n) {
3226
3263
  }
3227
3264
  for (let t of i) {
3228
3265
  let n = document.createElement("div");
3229
- n.className = "const-row", n.appendChild(br(t, r[t], (e) => a(t, e)));
3266
+ n.className = "const-row", n.appendChild(Cr(t, r[t], (e) => a(t, e)));
3230
3267
  let i = document.createElement("button");
3231
3268
  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);
3232
3269
  }
@@ -3245,54 +3282,161 @@ function yr(e, t, n) {
3245
3282
  e && (t.working.constants ?? {})[e] === void 0 && (a(e, (hr.find(([e]) => e === u.value)?.[1] ?? (() => 0))()), l.value = "");
3246
3283
  }), c.append(l, u, d), e.appendChild(c);
3247
3284
  }
3248
- function br(e, t, n) {
3285
+ var br = "en";
3286
+ function xr(e, t) {
3287
+ let n = `@t:${t}`, r = 0, i = (e) => {
3288
+ if (typeof e == "string") {
3289
+ for (let t of e.split(",")) t.trim() === n && (r += 1);
3290
+ return;
3291
+ }
3292
+ if (Array.isArray(e)) for (let t of e) i(t);
3293
+ else if (e && typeof e == "object") for (let t of Object.values(e)) i(t);
3294
+ };
3295
+ for (let [t, n] of Object.entries(e)) t !== "strings" && i(n);
3296
+ return r;
3297
+ }
3298
+ function Sr(e, t, n) {
3299
+ let r = t.working.strings ?? {}, i = Object.keys(r);
3300
+ i.includes(br) || i.unshift(br);
3301
+ let a = [...new Set(i.flatMap((e) => Object.keys(r[e] ?? {})))].sort(), o = (e) => {
3302
+ t.mutate(() => {
3303
+ let n = {};
3304
+ for (let [e, r] of Object.entries(t.working.strings ?? {})) n[e] = { ...r };
3305
+ e(n), Object.keys(n).length === 0 ? delete t.working.strings : t.working.strings = n;
3306
+ });
3307
+ }, s = document.createElement("div");
3308
+ s.className = "strings-langs";
3309
+ let c = document.createElement("span");
3310
+ c.className = "strings-langs-label", c.textContent = "languages", s.appendChild(c);
3311
+ for (let e of i) {
3312
+ let t = document.createElement("span");
3313
+ if (t.className = "strings-lang-chip", t.textContent = e, e === br) t.title = "the base language — everything falls back to this";
3314
+ else {
3315
+ let i = document.createElement("button");
3316
+ i.type = "button", i.className = "strings-locale-del", i.textContent = "✕", i.title = `remove the ${e} translation`, i.addEventListener("click", () => {
3317
+ let t = Object.keys(r[e] ?? {}).length, i = () => {
3318
+ o((t) => {
3319
+ delete t[e];
3320
+ });
3321
+ };
3322
+ t > 0 && n?.confirm ? n.confirm(`Delete the ${e} translation and its ${t} string${t === 1 ? "" : "s"}?`, "delete", i) : i();
3323
+ }), t.appendChild(i);
3324
+ }
3325
+ s.appendChild(t);
3326
+ }
3327
+ if (e.appendChild(s), a.length === 0) {
3328
+ let t = document.createElement("div");
3329
+ t.className = "hint", t.textContent = "No strings yet. A text prop can say \"@t:menu.start\" instead of a literal; add that key here and give it words.", e.appendChild(t);
3330
+ }
3331
+ for (let s of a) {
3332
+ let a = document.createElement("div");
3333
+ a.className = "strings-key-row";
3334
+ let c = document.createElement("span");
3335
+ c.className = "strings-key", c.textContent = s, c.title = `@t:${s}`, a.appendChild(c);
3336
+ let l = document.createElement("button");
3337
+ l.type = "button", l.className = "const-del", l.textContent = "✕", l.title = `delete the "${s}" string in every language`, l.addEventListener("click", () => {
3338
+ let e = () => {
3339
+ o((e) => {
3340
+ for (let t of Object.values(e)) delete t[s];
3341
+ });
3342
+ }, r = xr(t.working, s);
3343
+ if (r > 0 && n?.confirm) {
3344
+ n.confirm(`"@t:${s}" is used by ${r} prop${r === 1 ? "" : "s"}, which will paint the key itself. Delete it anyway?`, "delete", e);
3345
+ return;
3346
+ }
3347
+ e();
3348
+ }), a.appendChild(l), e.appendChild(a);
3349
+ let u = r[br]?.[s];
3350
+ for (let t of i) {
3351
+ let n = r[t]?.[s], i = document.createElement("div");
3352
+ i.className = "strings-row";
3353
+ let a = document.createElement("span");
3354
+ a.className = "strings-lang-tag", a.textContent = t, i.appendChild(a);
3355
+ let c = document.createElement("input");
3356
+ c.type = "text", c.className = "strings-cell", c.dataset.locale = t, c.dataset.key = s, c.value = n ?? "", n === void 0 && (t === br ? (c.classList.add("strings-missing-base"), c.placeholder = s, c.title = `no base text — "${s}" itself will be painted`) : (c.classList.add("strings-fallback"), c.placeholder = u === void 0 ? s : `\u2192 ${u}`, c.title = "not translated — falls back to English silently")), c.addEventListener("change", () => {
3357
+ let e = c.value;
3358
+ o((n) => {
3359
+ let r = n[t] ?? {};
3360
+ e === "" ? delete r[s] : r[s] = e, n[t] = r;
3361
+ });
3362
+ }), i.appendChild(c), e.appendChild(i);
3363
+ }
3364
+ }
3365
+ let l = document.createElement("div");
3366
+ l.className = "const-add";
3367
+ let u = document.createElement("input");
3368
+ u.type = "text", u.placeholder = "new key (e.g. menu.start)";
3369
+ let d = document.createElement("button");
3370
+ d.type = "button", d.textContent = "+ key", d.addEventListener("click", () => {
3371
+ let e = u.value.trim();
3372
+ e && r[br]?.[e] === void 0 && (o((t) => {
3373
+ let n = t[br] ?? {};
3374
+ n[e] = e, t[br] = n;
3375
+ }), u.value = "");
3376
+ }), l.append(u, d), e.appendChild(l);
3377
+ let f = document.createElement("div");
3378
+ f.className = "const-add";
3379
+ let p = document.createElement("input");
3380
+ p.type = "text", p.placeholder = "new language (e.g. ko)";
3381
+ let m = document.createElement("button");
3382
+ m.type = "button", m.textContent = "+ language", m.addEventListener("click", () => {
3383
+ let e = p.value.trim();
3384
+ !e || i.includes(e) || (o((t) => {
3385
+ t[e] = {}, t[br] ??= {};
3386
+ }), p.value = "");
3387
+ }), f.append(p, m), e.appendChild(f);
3388
+ }
3389
+ function Cr(e, t, n) {
3249
3390
  let r = d(t);
3250
- if (r === "number") return jr(e, t, (e) => n(e), () => n(0));
3391
+ if (r === "number") return Pr(e, t, (e) => n(e), () => n(0));
3251
3392
  if (r === "boolean") {
3252
3393
  let r = document.createElement("input");
3253
- return r.type = "checkbox", r.checked = t === !0, r.addEventListener("change", () => n(r.checked)), B(e, r);
3394
+ return r.type = "checkbox", r.checked = t === !0, r.addEventListener("change", () => n(r.checked)), V(e, r);
3254
3395
  }
3255
- return r === "array" && Array.isArray(t) && t.every((e) => typeof e == "number") ? Mr(e, t, (e) => n(e)) : r === "string" ? Ar(e, String(t), (e) => n(e)) : Pr(e, t, (e) => n(e ?? null), JSON.stringify(t));
3396
+ return r === "array" && Array.isArray(t) && t.every((e) => typeof e == "number") ? Fr(e, t, (e) => n(e)) : r === "string" ? Nr(e, String(t), (e) => n(e)) : Lr(e, t, (e) => n(e ?? null), JSON.stringify(t));
3256
3397
  }
3257
- function xr(e, t, n, r, i, a, o = !1) {
3258
- let s = t.props?.[n] ?? r, c = d(r), l = c === "number" || c === "boolean" || c === "string" || c === "array", f = (i) => {
3398
+ function wr(e, t, n, r, i, a, o = !1, s) {
3399
+ let c = t.props?.[n] ?? r, l = d(r), f = l === "number" || l === "boolean" || l === "string" || l === "array", p = (i) => {
3259
3400
  let a = u(i);
3260
3401
  e.mutate(() => {
3261
3402
  t.props ||= {};
3262
3403
  let e = t.props;
3263
3404
  JSON.stringify(i) === JSON.stringify(r) ? (delete e[n], Object.keys(e).length === 0 && delete t.props) : e[n] = i;
3264
- }, e.selection && l && !a ? {
3405
+ }, e.selection && f && !a ? {
3265
3406
  path: e.selection,
3266
3407
  key: n,
3267
3408
  value: i
3268
3409
  } : void 0);
3269
- }, p = Sr(e, c, r);
3270
- if (u(s)) return Cr(n, s["@const"], p, f, r);
3271
- let m = (e) => p.length > 0 ? wr(e, p, f) : e;
3272
- if (c === "number") return m(jr(a ?? n, s, (e) => f(e), () => f(r)));
3273
- if (c === "boolean") {
3410
+ }, m = Tr(e, l, r);
3411
+ if (u(c)) return Er(n, c["@const"], m, p, r);
3412
+ let h = (e) => m.length > 0 ? Dr(e, m, p) : e;
3413
+ if (s && s.length > 1 && d(c) !== l) return Lr(a ?? n, c, (e) => {
3414
+ p(e === void 0 ? r : e);
3415
+ }, JSON.stringify(r));
3416
+ if (l === "number") return h(Pr(a ?? n, c, (e) => p(e), () => p(r)));
3417
+ if (l === "boolean") {
3274
3418
  let e = document.createElement("input");
3275
- return e.type = "checkbox", e.checked = s === !0, e.addEventListener("change", () => f(e.checked)), m(B(a ?? n, e));
3419
+ return e.type = "checkbox", e.checked = c === !0, e.addEventListener("change", () => p(e.checked)), h(V(a ?? n, e));
3276
3420
  }
3277
- if (c === "string") {
3421
+ if (l === "string") {
3278
3422
  if (i && i.length > 0) {
3279
- let t = n === "orderGroup" ? kr(e) : [];
3280
- return m(Dr(a ?? n, String(s ?? ""), t.length > 0 ? [...i, ...t] : i, (e) => f(e), n === "orderGroup" ? (t) => Or(t, e) : void 0));
3423
+ let t = n === "orderGroup" ? Mr(e) : [];
3424
+ return h(Ar(a ?? n, String(c ?? ""), t.length > 0 ? [...i, ...t] : i, (e) => p(e), n === "orderGroup" ? (t) => jr(t, e) : void 0));
3281
3425
  }
3282
- return m(o ? rr(e, a ?? n, String(s ?? ""), (e) => f(e)) : Ar(a ?? n, String(s ?? ""), (e) => f(e)));
3426
+ return h(o ? ir(e, a ?? n, String(c ?? ""), (e) => p(e)) : Nr(a ?? n, String(c ?? ""), (e) => p(e)));
3283
3427
  }
3284
- return c === "array" && Array.isArray(r) && r.length > 0 && r.every((e) => typeof e == "number") ? m(Mr(n, s ?? r, (e) => f(e))) : Pr(n, s === r ? void 0 : s, (e) => {
3285
- f(e === void 0 ? r : e);
3428
+ return l === "array" && Array.isArray(r) && r.length > 0 && r.every((e) => typeof e == "number") ? h(Fr(n, c ?? r, (e) => p(e))) : Lr(n, c === r ? void 0 : c, (e) => {
3429
+ p(e === void 0 ? r : e);
3286
3430
  }, JSON.stringify(r));
3287
3431
  }
3288
- function Sr(e, t, n) {
3432
+ function Tr(e, t, n) {
3289
3433
  let r = e.working.constants ?? {};
3290
3434
  return Object.keys(r).filter((e) => {
3291
3435
  let i = r[e];
3292
3436
  return d(i) === t ? t === "array" && Array.isArray(n) && Array.isArray(i) ? i.length === n.length : !0 : !1;
3293
3437
  });
3294
3438
  }
3295
- function Cr(e, t, n, r, i) {
3439
+ function Er(e, t, n, r, i) {
3296
3440
  let a = document.createElement("select"), o = n.includes(t) ? n : [t, ...n];
3297
3441
  for (let e of o) {
3298
3442
  let n = document.createElement("option");
@@ -3302,10 +3446,10 @@ function Cr(e, t, n, r, i) {
3302
3446
  s.value = "", s.textContent = "↺ custom value", a.appendChild(s), a.addEventListener("change", () => {
3303
3447
  r(a.value ? { "@const": a.value } : i);
3304
3448
  });
3305
- let c = B(`🔗 ${e}`, a);
3449
+ let c = V(`🔗 ${e}`, a);
3306
3450
  return c.classList.add("const-bound"), c;
3307
3451
  }
3308
- function wr(e, t, n) {
3452
+ function Dr(e, t, n) {
3309
3453
  let r = document.createElement("select");
3310
3454
  r.className = "const-picker", r.title = "Bind to a named constant";
3311
3455
  let i = document.createElement("option");
@@ -3318,13 +3462,13 @@ function wr(e, t, n) {
3318
3462
  r.value && n({ "@const": r.value });
3319
3463
  }), e.classList.add("has-const-picker"), e.appendChild(r), e;
3320
3464
  }
3321
- function Tr(e, t) {
3465
+ function Or(e, t) {
3322
3466
  let n = document.createElement("div");
3323
3467
  n.className = "section-title", n.textContent = e, t && n.appendChild(an(t));
3324
3468
  let r = document.createElement("span");
3325
3469
  return r.className = "rule", n.appendChild(r), n;
3326
3470
  }
3327
- function Er(e, t) {
3471
+ function kr(e, t) {
3328
3472
  let n = document.createElement("span");
3329
3473
  n.className = "chip", n.textContent = e;
3330
3474
  let r = document.createElement("button");
@@ -3332,13 +3476,13 @@ function Er(e, t) {
3332
3476
  e.stopPropagation(), t();
3333
3477
  }), n.appendChild(r), n;
3334
3478
  }
3335
- function B(e, t) {
3479
+ function V(e, t) {
3336
3480
  let n = document.createElement("label");
3337
3481
  n.className = "field";
3338
3482
  let r = document.createElement("span");
3339
3483
  return r.textContent = e, n.append(r, t), n;
3340
3484
  }
3341
- function Dr(e, t, n, r, i) {
3485
+ function Ar(e, t, n, r, i) {
3342
3486
  let a = document.createElement("select");
3343
3487
  for (let e of n.includes(t) ? n : [t, ...n]) {
3344
3488
  let n = document.createElement("option");
@@ -3346,23 +3490,23 @@ function Dr(e, t, n, r, i) {
3346
3490
  let r = i?.(e);
3347
3491
  n.textContent = r ? `${e} (${r})` : e, e === t && (n.selected = !0), a.appendChild(n);
3348
3492
  }
3349
- return a.addEventListener("change", () => r(a.value)), B(e, a);
3493
+ return a.addEventListener("change", () => r(a.value)), V(e, a);
3350
3494
  }
3351
- function Or(e, t) {
3495
+ function jr(e, t) {
3352
3496
  let r = {
3353
3497
  ...n,
3354
3498
  ...t.working.orderGroups ?? {}
3355
3499
  }[e];
3356
3500
  return r === void 0 ? "unknown — sorts as default" : String(r);
3357
3501
  }
3358
- function kr(e) {
3502
+ function Mr(e) {
3359
3503
  return Object.keys(e.working.orderGroups ?? {});
3360
3504
  }
3361
- function Ar(e, t, n) {
3505
+ function Nr(e, t, n) {
3362
3506
  let r = document.createElement("input");
3363
- return r.type = "text", r.value = t, r.addEventListener("change", () => n(r.value)), B(e, r);
3507
+ return r.type = "text", r.value = t, r.addEventListener("change", () => n(r.value)), V(e, r);
3364
3508
  }
3365
- function jr(e, t, n, r) {
3509
+ function Pr(e, t, n, r) {
3366
3510
  let i = document.createElement("input");
3367
3511
  return i.type = "number", i.step = "any", i.value = String(t), i.addEventListener("change", () => {
3368
3512
  if (i.value.trim() === "") {
@@ -3371,9 +3515,9 @@ function jr(e, t, n, r) {
3371
3515
  }
3372
3516
  let e = Number(i.value);
3373
3517
  Number.isFinite(e) && n(e);
3374
- }), B(e, i);
3518
+ }), V(e, i);
3375
3519
  }
3376
- function Mr(e, t, n) {
3520
+ function Fr(e, t, n) {
3377
3521
  let r = document.createElement("div");
3378
3522
  r.className = "vector-row";
3379
3523
  let i = [...t];
@@ -3383,9 +3527,9 @@ function Mr(e, t, n) {
3383
3527
  let e = Number(a.value);
3384
3528
  Number.isFinite(e) && (i[t] = e, n([...i]));
3385
3529
  }), r.appendChild(a);
3386
- }), B(e, r);
3530
+ }), V(e, r);
3387
3531
  }
3388
- function Nr(e, t) {
3532
+ function Ir(e, t) {
3389
3533
  let n = document.createElement("div");
3390
3534
  n.className = "field wide tile-paint";
3391
3535
  let r = document.createElement("button");
@@ -3404,33 +3548,37 @@ function Nr(e, t) {
3404
3548
  let c = document.createElement("div");
3405
3549
  return c.className = "paint-hint", c.textContent = "grid grows right/down; digits map to atlas tiles, others need legend", n.appendChild(c), n;
3406
3550
  }
3407
- function Pr(e, t, n, r = "") {
3408
- let i = document.createElement("textarea");
3409
- i.rows = 3, i.placeholder = r, i.value = t === void 0 ? "" : JSON.stringify(t, null, 2), i.addEventListener("change", () => {
3410
- let e = i.value.trim();
3551
+ function Lr(e, t, n, r = "", i) {
3552
+ let a = document.createElement("textarea");
3553
+ a.rows = 3, a.placeholder = r, a.value = t === void 0 ? "" : JSON.stringify(t, null, 2), a.addEventListener("change", () => {
3554
+ let e = a.value.trim();
3411
3555
  if (e === "") {
3412
- i.classList.remove("invalid"), n(void 0);
3556
+ a.classList.remove("invalid"), n(void 0);
3413
3557
  return;
3414
3558
  }
3415
3559
  try {
3416
3560
  let t = JSON.parse(e);
3417
- i.classList.remove("invalid"), n(t);
3561
+ if (i && !i(t)) {
3562
+ a.classList.add("invalid");
3563
+ return;
3564
+ }
3565
+ a.classList.remove("invalid"), n(t);
3418
3566
  } catch {
3419
- i.classList.add("invalid");
3567
+ a.classList.add("invalid");
3420
3568
  }
3421
3569
  });
3422
- let a = B(e, i);
3423
- return a.className = "field wide", a;
3570
+ let o = V(e, a);
3571
+ return o.className = "field wide", o;
3424
3572
  }
3425
- var Fr = 1e3, Ir = 1001, Lr = 1002, Rr = 1006, zr = 1008, Br = 1009, Vr = 1023, Hr = 2300, Ur = 2301, Wr = 2302, Gr = 2303, Kr = 2400, qr = 2401, Jr = 2402, Yr = "srgb", Xr = "srgb-linear", Zr = "linear", Qr = "srgb", $r = 2e3;
3426
- function ei(e) {
3573
+ var Rr = 1e3, zr = 1001, Br = 1002, Vr = 1006, Hr = 1008, Ur = 1009, Wr = 1023, Gr = 2300, Kr = 2301, qr = 2302, Jr = 2303, Yr = 2400, Xr = 2401, Zr = 2402, Qr = "srgb", $r = "srgb-linear", ei = "linear", ti = "srgb", ni = 2e3;
3574
+ function ri(e) {
3427
3575
  return ArrayBuffer.isView(e) && !(e instanceof DataView);
3428
3576
  }
3429
- function ti(e) {
3577
+ function ii(e) {
3430
3578
  return document.createElementNS("http://www.w3.org/1999/xhtml", e);
3431
3579
  }
3432
- var ni = {}, ri = null;
3433
- function ii(e) {
3580
+ var ai = {}, oi = null;
3581
+ function si(e) {
3434
3582
  let t = e[0];
3435
3583
  if (typeof t == "string" && t.startsWith("TSL:")) {
3436
3584
  let t = e[1];
@@ -3438,29 +3586,29 @@ function ii(e) {
3438
3586
  }
3439
3587
  return e;
3440
3588
  }
3441
- function V(...e) {
3442
- e = ii(e);
3589
+ function H(...e) {
3590
+ e = si(e);
3443
3591
  let t = "THREE." + e.shift();
3444
- if (ri) ri("warn", t, ...e);
3592
+ if (oi) oi("warn", t, ...e);
3445
3593
  else {
3446
3594
  let n = e[0];
3447
3595
  n && n.isStackTrace ? console.warn(n.getError(t)) : console.warn(t, ...e);
3448
3596
  }
3449
3597
  }
3450
- function H(...e) {
3451
- e = ii(e);
3598
+ function U(...e) {
3599
+ e = si(e);
3452
3600
  let t = "THREE." + e.shift();
3453
- if (ri) ri("error", t, ...e);
3601
+ if (oi) oi("error", t, ...e);
3454
3602
  else {
3455
3603
  let n = e[0];
3456
3604
  n && n.isStackTrace ? console.error(n.getError(t)) : console.error(t, ...e);
3457
3605
  }
3458
3606
  }
3459
- function ai(...e) {
3607
+ function ci(...e) {
3460
3608
  let t = e.join(" ");
3461
- t in ni || (ni[t] = !0, V(...e));
3609
+ t in ai || (ai[t] = !0, H(...e));
3462
3610
  }
3463
- var oi = class {
3611
+ var li = class {
3464
3612
  addEventListener(e, t) {
3465
3613
  this._listeners === void 0 && (this._listeners = {});
3466
3614
  let n = this._listeners;
@@ -3490,22 +3638,22 @@ var oi = class {
3490
3638
  e.target = null;
3491
3639
  }
3492
3640
  }
3493
- }, U = /* @__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(".");
3641
+ }, 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(".");
3494
3642
  Math.PI / 180, 180 / Math.PI;
3495
- function si() {
3643
+ function ui() {
3496
3644
  let e = Math.random() * 4294967295 | 0, t = Math.random() * 4294967295 | 0, n = Math.random() * 4294967295 | 0, r = Math.random() * 4294967295 | 0;
3497
- return (U[e & 255] + U[e >> 8 & 255] + U[e >> 16 & 255] + U[e >> 24 & 255] + "-" + U[t & 255] + U[t >> 8 & 255] + "-" + U[t >> 16 & 15 | 64] + U[t >> 24 & 255] + "-" + U[n & 63 | 128] + U[n >> 8 & 255] + "-" + U[n >> 16 & 255] + U[n >> 24 & 255] + U[r & 255] + U[r >> 8 & 255] + U[r >> 16 & 255] + U[r >> 24 & 255]).toLowerCase();
3645
+ 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();
3498
3646
  }
3499
- function W(e, t, n) {
3647
+ function G(e, t, n) {
3500
3648
  return Math.max(t, Math.min(n, e));
3501
3649
  }
3502
- function ci(e, t) {
3650
+ function di(e, t) {
3503
3651
  return (e % t + t) % t;
3504
3652
  }
3505
- function li(e, t, n) {
3653
+ function fi(e, t, n) {
3506
3654
  return (1 - n) * e + n * t;
3507
3655
  }
3508
- var ui = class e {
3656
+ var pi = class e {
3509
3657
  static {
3510
3658
  e.prototype.isVector2 = !0;
3511
3659
  }
@@ -3605,14 +3753,14 @@ var ui = class e {
3605
3753
  return this.x = Math.max(this.x, e.x), this.y = Math.max(this.y, e.y), this;
3606
3754
  }
3607
3755
  clamp(e, t) {
3608
- return this.x = W(this.x, e.x, t.x), this.y = W(this.y, e.y, t.y), this;
3756
+ return this.x = G(this.x, e.x, t.x), this.y = G(this.y, e.y, t.y), this;
3609
3757
  }
3610
3758
  clampScalar(e, t) {
3611
- return this.x = W(this.x, e, t), this.y = W(this.y, e, t), this;
3759
+ return this.x = G(this.x, e, t), this.y = G(this.y, e, t), this;
3612
3760
  }
3613
3761
  clampLength(e, t) {
3614
3762
  let n = this.length();
3615
- return this.divideScalar(n || 1).multiplyScalar(W(n, e, t));
3763
+ return this.divideScalar(n || 1).multiplyScalar(G(n, e, t));
3616
3764
  }
3617
3765
  floor() {
3618
3766
  return this.x = Math.floor(this.x), this.y = Math.floor(this.y), this;
@@ -3654,7 +3802,7 @@ var ui = class e {
3654
3802
  let t = Math.sqrt(this.lengthSq() * e.lengthSq());
3655
3803
  if (t === 0) return Math.PI / 2;
3656
3804
  let n = this.dot(e) / t;
3657
- return Math.acos(W(n, -1, 1));
3805
+ return Math.acos(G(n, -1, 1));
3658
3806
  }
3659
3807
  distanceTo(e) {
3660
3808
  return Math.sqrt(this.distanceToSquared(e));
@@ -3697,7 +3845,7 @@ var ui = class e {
3697
3845
  *[Symbol.iterator]() {
3698
3846
  yield this.x, yield this.y;
3699
3847
  }
3700
- }, di = class {
3848
+ }, mi = class {
3701
3849
  constructor(e = 0, t = 0, n = 0, r = 1) {
3702
3850
  this.isQuaternion = !0, this._x = e, this._y = t, this._z = n, this._w = r;
3703
3851
  }
@@ -3776,7 +3924,7 @@ var ui = class e {
3776
3924
  case "XZY":
3777
3925
  this._x = d * l * u - c * f * p, this._y = c * f * u - d * l * p, this._z = c * l * p + d * f * u, this._w = c * l * u + d * f * p;
3778
3926
  break;
3779
- default: V("Quaternion: .setFromEuler() encountered an unknown order: " + a);
3927
+ default: H("Quaternion: .setFromEuler() encountered an unknown order: " + a);
3780
3928
  }
3781
3929
  return t === !0 && this._onChangeCallback(), this;
3782
3930
  }
@@ -3806,7 +3954,7 @@ var ui = class e {
3806
3954
  return n < 1e-8 ? (n = 0, Math.abs(e.x) > Math.abs(e.z) ? (this._x = -e.y, this._y = e.x, this._z = 0, this._w = n) : (this._x = 0, this._y = -e.z, this._z = e.y, this._w = n)) : (this._x = e.y * t.z - e.z * t.y, this._y = e.z * t.x - e.x * t.z, this._z = e.x * t.y - e.y * t.x, this._w = n), this.normalize();
3807
3955
  }
3808
3956
  angleTo(e) {
3809
- return 2 * Math.acos(Math.abs(W(this.dot(e), -1, 1)));
3957
+ return 2 * Math.acos(Math.abs(G(this.dot(e), -1, 1)));
3810
3958
  }
3811
3959
  rotateTowards(e, t) {
3812
3960
  let n = this.angleTo(e);
@@ -3885,7 +4033,7 @@ var ui = class e {
3885
4033
  *[Symbol.iterator]() {
3886
4034
  yield this._x, yield this._y, yield this._z, yield this._w;
3887
4035
  }
3888
- }, G = class e {
4036
+ }, K = class e {
3889
4037
  static {
3890
4038
  e.prototype.isVector3 = !0;
3891
4039
  }
@@ -3967,10 +4115,10 @@ var ui = class e {
3967
4115
  return this.x = e.x * t.x, this.y = e.y * t.y, this.z = e.z * t.z, this;
3968
4116
  }
3969
4117
  applyEuler(e) {
3970
- return this.applyQuaternion(pi.setFromEuler(e));
4118
+ return this.applyQuaternion(gi.setFromEuler(e));
3971
4119
  }
3972
4120
  applyAxisAngle(e, t) {
3973
- return this.applyQuaternion(pi.setFromAxisAngle(e, t));
4121
+ return this.applyQuaternion(gi.setFromAxisAngle(e, t));
3974
4122
  }
3975
4123
  applyMatrix3(e) {
3976
4124
  let t = this.x, n = this.y, r = this.z, i = e.elements;
@@ -4010,14 +4158,14 @@ var ui = class e {
4010
4158
  return this.x = Math.max(this.x, e.x), this.y = Math.max(this.y, e.y), this.z = Math.max(this.z, e.z), this;
4011
4159
  }
4012
4160
  clamp(e, t) {
4013
- return this.x = W(this.x, e.x, t.x), this.y = W(this.y, e.y, t.y), this.z = W(this.z, e.z, t.z), this;
4161
+ return this.x = G(this.x, e.x, t.x), this.y = G(this.y, e.y, t.y), this.z = G(this.z, e.z, t.z), this;
4014
4162
  }
4015
4163
  clampScalar(e, t) {
4016
- return this.x = W(this.x, e, t), this.y = W(this.y, e, t), this.z = W(this.z, e, t), this;
4164
+ return this.x = G(this.x, e, t), this.y = G(this.y, e, t), this.z = G(this.z, e, t), this;
4017
4165
  }
4018
4166
  clampLength(e, t) {
4019
4167
  let n = this.length();
4020
- return this.divideScalar(n || 1).multiplyScalar(W(n, e, t));
4168
+ return this.divideScalar(n || 1).multiplyScalar(G(n, e, t));
4021
4169
  }
4022
4170
  floor() {
4023
4171
  return this.x = Math.floor(this.x), this.y = Math.floor(this.y), this.z = Math.floor(this.z), this;
@@ -4072,16 +4220,16 @@ var ui = class e {
4072
4220
  return this.copy(e).multiplyScalar(n);
4073
4221
  }
4074
4222
  projectOnPlane(e) {
4075
- return fi.copy(this).projectOnVector(e), this.sub(fi);
4223
+ return hi.copy(this).projectOnVector(e), this.sub(hi);
4076
4224
  }
4077
4225
  reflect(e) {
4078
- return this.sub(fi.copy(e).multiplyScalar(2 * this.dot(e)));
4226
+ return this.sub(hi.copy(e).multiplyScalar(2 * this.dot(e)));
4079
4227
  }
4080
4228
  angleTo(e) {
4081
4229
  let t = Math.sqrt(this.lengthSq() * e.lengthSq());
4082
4230
  if (t === 0) return Math.PI / 2;
4083
4231
  let n = this.dot(e) / t;
4084
- return Math.acos(W(n, -1, 1));
4232
+ return Math.acos(G(n, -1, 1));
4085
4233
  }
4086
4234
  distanceTo(e) {
4087
4235
  return Math.sqrt(this.distanceToSquared(e));
@@ -4148,7 +4296,7 @@ var ui = class e {
4148
4296
  *[Symbol.iterator]() {
4149
4297
  yield this.x, yield this.y, yield this.z;
4150
4298
  }
4151
- }, fi = /*@__PURE__*/ new G(), pi = /*@__PURE__*/ new di(), mi = class e {
4299
+ }, hi = /*@__PURE__*/ new K(), gi = /*@__PURE__*/ new mi(), _i = class e {
4152
4300
  static {
4153
4301
  e.prototype.isMatrix3 = !0;
4154
4302
  }
@@ -4223,13 +4371,13 @@ var ui = class e {
4223
4371
  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;
4224
4372
  }
4225
4373
  scale(e, t) {
4226
- return this.premultiply(hi.makeScale(e, t)), this;
4374
+ return this.premultiply(vi.makeScale(e, t)), this;
4227
4375
  }
4228
4376
  rotate(e) {
4229
- return this.premultiply(hi.makeRotation(-e)), this;
4377
+ return this.premultiply(vi.makeRotation(-e)), this;
4230
4378
  }
4231
4379
  translate(e, t) {
4232
- return this.premultiply(hi.makeTranslation(e, t)), this;
4380
+ return this.premultiply(vi.makeTranslation(e, t)), this;
4233
4381
  }
4234
4382
  makeTranslation(e, t) {
4235
4383
  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;
@@ -4257,14 +4405,14 @@ var ui = class e {
4257
4405
  clone() {
4258
4406
  return new this.constructor().fromArray(this.elements);
4259
4407
  }
4260
- }, hi = /*@__PURE__*/ new mi(), gi = /*@__PURE__*/ new mi().set(.4123908, .3575843, .1804808, .212639, .7151687, .0721923, .0193308, .1191948, .9505322), _i = /*@__PURE__*/ new mi().set(3.2409699, -1.5373832, -.4986108, -.9692436, 1.8759675, .0415551, .0556301, -.203977, 1.0569715);
4261
- function vi() {
4408
+ }, vi = /*@__PURE__*/ new _i(), yi = /*@__PURE__*/ new _i().set(.4123908, .3575843, .1804808, .212639, .7151687, .0721923, .0193308, .1191948, .9505322), bi = /*@__PURE__*/ new _i().set(3.2409699, -1.5373832, -.4986108, -.9692436, 1.8759675, .0415551, .0556301, -.203977, 1.0569715);
4409
+ function xi() {
4262
4410
  let e = {
4263
4411
  enabled: !0,
4264
- workingColorSpace: Xr,
4412
+ workingColorSpace: $r,
4265
4413
  spaces: {},
4266
4414
  convert: function(e, t, n) {
4267
- return this.enabled === !1 || t === n || !t || !n ? e : (this.spaces[t].transfer === "srgb" && (e.r = yi(e.r), e.g = yi(e.g), e.b = yi(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 = bi(e.r), e.g = bi(e.g), e.b = bi(e.b)), e);
4415
+ return this.enabled === !1 || t === n || !t || !n ? e : (this.spaces[t].transfer === "srgb" && (e.r = Si(e.r), e.g = Si(e.g), e.b = Si(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 = Ci(e.r), e.g = Ci(e.g), e.b = Ci(e.b)), e);
4268
4416
  },
4269
4417
  workingToColorSpace: function(e, t) {
4270
4418
  return this.convert(e, this.workingColorSpace, t);
@@ -4276,7 +4424,7 @@ function vi() {
4276
4424
  return this.spaces[e].primaries;
4277
4425
  },
4278
4426
  getTransfer: function(e) {
4279
- return e === "" ? Zr : this.spaces[e].transfer;
4427
+ return e === "" ? ei : this.spaces[e].transfer;
4280
4428
  },
4281
4429
  getToneMappingMode: function(e) {
4282
4430
  return this.spaces[e].outputColorSpaceConfig.toneMappingMode || "standard";
@@ -4297,10 +4445,10 @@ function vi() {
4297
4445
  return this.spaces[e].workingColorSpaceConfig.unpackColorSpace;
4298
4446
  },
4299
4447
  fromWorkingColorSpace: function(t, n) {
4300
- return ai("ColorManagement: .fromWorkingColorSpace() has been renamed to .workingToColorSpace()."), e.workingToColorSpace(t, n);
4448
+ return ci("ColorManagement: .fromWorkingColorSpace() has been renamed to .workingToColorSpace()."), e.workingToColorSpace(t, n);
4301
4449
  },
4302
4450
  toWorkingColorSpace: function(t, n) {
4303
- return ai("ColorManagement: .toWorkingColorSpace() has been renamed to .colorSpaceToWorking()."), e.colorSpaceToWorking(t, n);
4451
+ return ci("ColorManagement: .toWorkingColorSpace() has been renamed to .colorSpaceToWorking()."), e.colorSpaceToWorking(t, n);
4304
4452
  }
4305
4453
  }, t = [
4306
4454
  .64,
@@ -4315,68 +4463,68 @@ function vi() {
4315
4463
  .0722
4316
4464
  ], r = [.3127, .329];
4317
4465
  return e.define({
4318
- [Xr]: {
4466
+ [$r]: {
4319
4467
  primaries: t,
4320
4468
  whitePoint: r,
4321
- transfer: Zr,
4322
- toXYZ: gi,
4323
- fromXYZ: _i,
4469
+ transfer: ei,
4470
+ toXYZ: yi,
4471
+ fromXYZ: bi,
4324
4472
  luminanceCoefficients: n,
4325
- workingColorSpaceConfig: { unpackColorSpace: Yr },
4326
- outputColorSpaceConfig: { drawingBufferColorSpace: Yr }
4473
+ workingColorSpaceConfig: { unpackColorSpace: Qr },
4474
+ outputColorSpaceConfig: { drawingBufferColorSpace: Qr }
4327
4475
  },
4328
- [Yr]: {
4476
+ [Qr]: {
4329
4477
  primaries: t,
4330
4478
  whitePoint: r,
4331
- transfer: Qr,
4332
- toXYZ: gi,
4333
- fromXYZ: _i,
4479
+ transfer: ti,
4480
+ toXYZ: yi,
4481
+ fromXYZ: bi,
4334
4482
  luminanceCoefficients: n,
4335
- outputColorSpaceConfig: { drawingBufferColorSpace: Yr }
4483
+ outputColorSpaceConfig: { drawingBufferColorSpace: Qr }
4336
4484
  }
4337
4485
  }), e;
4338
4486
  }
4339
- var K = /*@__PURE__*/ vi();
4340
- function yi(e) {
4487
+ var q = /*@__PURE__*/ xi();
4488
+ function Si(e) {
4341
4489
  return e < .04045 ? e * .0773993808 : (e * .9478672986 + .0521327014) ** 2.4;
4342
4490
  }
4343
- function bi(e) {
4491
+ function Ci(e) {
4344
4492
  return e < .0031308 ? e * 12.92 : 1.055 * e ** .41666 - .055;
4345
4493
  }
4346
- var xi, Si = class {
4494
+ var wi, Ti = class {
4347
4495
  static getDataURL(e, t = "image/png") {
4348
4496
  if (/^data:/i.test(e.src) || typeof HTMLCanvasElement > "u") return e.src;
4349
4497
  let n;
4350
4498
  if (e instanceof HTMLCanvasElement) n = e;
4351
4499
  else {
4352
- xi === void 0 && (xi = ti("canvas")), xi.width = e.width, xi.height = e.height;
4353
- let t = xi.getContext("2d");
4354
- e instanceof ImageData ? t.putImageData(e, 0, 0) : t.drawImage(e, 0, 0, e.width, e.height), n = xi;
4500
+ wi === void 0 && (wi = ii("canvas")), wi.width = e.width, wi.height = e.height;
4501
+ let t = wi.getContext("2d");
4502
+ e instanceof ImageData ? t.putImageData(e, 0, 0) : t.drawImage(e, 0, 0, e.width, e.height), n = wi;
4355
4503
  }
4356
4504
  return n.toDataURL(t);
4357
4505
  }
4358
4506
  static sRGBToLinear(e) {
4359
4507
  if (typeof HTMLImageElement < "u" && e instanceof HTMLImageElement || typeof HTMLCanvasElement < "u" && e instanceof HTMLCanvasElement || typeof ImageBitmap < "u" && e instanceof ImageBitmap) {
4360
- let t = ti("canvas");
4508
+ let t = ii("canvas");
4361
4509
  t.width = e.width, t.height = e.height;
4362
4510
  let n = t.getContext("2d");
4363
4511
  n.drawImage(e, 0, 0, e.width, e.height);
4364
4512
  let r = n.getImageData(0, 0, e.width, e.height), i = r.data;
4365
- for (let e = 0; e < i.length; e++) i[e] = yi(i[e] / 255) * 255;
4513
+ for (let e = 0; e < i.length; e++) i[e] = Si(i[e] / 255) * 255;
4366
4514
  return n.putImageData(r, 0, 0), t;
4367
4515
  } else if (e.data) {
4368
4516
  let t = e.data.slice(0);
4369
- for (let e = 0; e < t.length; e++) t instanceof Uint8Array || t instanceof Uint8ClampedArray ? t[e] = Math.floor(yi(t[e] / 255) * 255) : t[e] = yi(t[e]);
4517
+ for (let e = 0; e < t.length; e++) t instanceof Uint8Array || t instanceof Uint8ClampedArray ? t[e] = Math.floor(Si(t[e] / 255) * 255) : t[e] = Si(t[e]);
4370
4518
  return {
4371
4519
  data: t,
4372
4520
  width: e.width,
4373
4521
  height: e.height
4374
4522
  };
4375
- } else return V("ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied."), e;
4523
+ } else return H("ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied."), e;
4376
4524
  }
4377
- }, Ci = 0, wi = class {
4525
+ }, Ei = 0, Di = class {
4378
4526
  constructor(e = null) {
4379
- this.isSource = !0, Object.defineProperty(this, "id", { value: Ci++ }), this.uuid = si(), this.data = e, this.dataReady = !0, this.version = 0;
4527
+ this.isSource = !0, Object.defineProperty(this, "id", { value: Ei++ }), this.uuid = ui(), this.data = e, this.dataReady = !0, this.version = 0;
4380
4528
  }
4381
4529
  getSize(e) {
4382
4530
  let t = this.data;
@@ -4396,33 +4544,33 @@ var xi, Si = class {
4396
4544
  let e;
4397
4545
  if (Array.isArray(r)) {
4398
4546
  e = [];
4399
- for (let t = 0, n = r.length; t < n; t++) r[t].isDataTexture ? e.push(Ti(r[t].image)) : e.push(Ti(r[t]));
4400
- } else e = Ti(r);
4547
+ for (let t = 0, n = r.length; t < n; t++) r[t].isDataTexture ? e.push(Oi(r[t].image)) : e.push(Oi(r[t]));
4548
+ } else e = Oi(r);
4401
4549
  n.url = e;
4402
4550
  }
4403
4551
  return t || (e.images[this.uuid] = n), n;
4404
4552
  }
4405
4553
  };
4406
- function Ti(e) {
4407
- return typeof HTMLImageElement < "u" && e instanceof HTMLImageElement || typeof HTMLCanvasElement < "u" && e instanceof HTMLCanvasElement || typeof ImageBitmap < "u" && e instanceof ImageBitmap ? Si.getDataURL(e) : e.data ? {
4554
+ function Oi(e) {
4555
+ return typeof HTMLImageElement < "u" && e instanceof HTMLImageElement || typeof HTMLCanvasElement < "u" && e instanceof HTMLCanvasElement || typeof ImageBitmap < "u" && e instanceof ImageBitmap ? Ti.getDataURL(e) : e.data ? {
4408
4556
  data: Array.from(e.data),
4409
4557
  width: e.width,
4410
4558
  height: e.height,
4411
4559
  type: e.data.constructor.name
4412
- } : (V("Texture: Unable to serialize Texture."), {});
4560
+ } : (H("Texture: Unable to serialize Texture."), {});
4413
4561
  }
4414
- var Ei = 0, Di = /*@__PURE__*/ new G(), Oi = class e extends oi {
4415
- constructor(t = e.DEFAULT_IMAGE, n = e.DEFAULT_MAPPING, r = Ir, i = Ir, a = Rr, o = zr, s = Vr, c = Br, l = e.DEFAULT_ANISOTROPY, u = "") {
4416
- super(), this.isTexture = !0, Object.defineProperty(this, "id", { value: Ei++ }), this.uuid = si(), this.name = "", this.source = new wi(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 ui(0, 0), this.repeat = new ui(1, 1), this.center = new ui(0, 0), this.rotation = 0, this.matrixAutoUpdate = !0, this.matrix = new mi(), 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;
4562
+ var ki = 0, Ai = /*@__PURE__*/ new K(), ji = class e extends li {
4563
+ constructor(t = e.DEFAULT_IMAGE, n = e.DEFAULT_MAPPING, r = zr, i = zr, a = Vr, o = Hr, s = Wr, c = Ur, l = e.DEFAULT_ANISOTROPY, u = "") {
4564
+ super(), this.isTexture = !0, Object.defineProperty(this, "id", { value: ki++ }), this.uuid = ui(), this.name = "", this.source = new Di(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 pi(0, 0), this.repeat = new pi(1, 1), this.center = new pi(0, 0), this.rotation = 0, this.matrixAutoUpdate = !0, this.matrix = new _i(), 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;
4417
4565
  }
4418
4566
  get width() {
4419
- return this.source.getSize(Di).x;
4567
+ return this.source.getSize(Ai).x;
4420
4568
  }
4421
4569
  get height() {
4422
- return this.source.getSize(Di).y;
4570
+ return this.source.getSize(Ai).y;
4423
4571
  }
4424
4572
  get depth() {
4425
- return this.source.getSize(Di).z;
4573
+ return this.source.getSize(Ai).z;
4426
4574
  }
4427
4575
  get image() {
4428
4576
  return this.source.data;
@@ -4452,12 +4600,12 @@ var Ei = 0, Di = /*@__PURE__*/ new G(), Oi = class e extends oi {
4452
4600
  for (let t in e) {
4453
4601
  let n = e[t];
4454
4602
  if (n === void 0) {
4455
- V(`Texture.setValues(): parameter '${t}' has value of undefined.`);
4603
+ H(`Texture.setValues(): parameter '${t}' has value of undefined.`);
4456
4604
  continue;
4457
4605
  }
4458
4606
  let r = this[t];
4459
4607
  if (r === void 0) {
4460
- V(`Texture.setValues(): property '${t}' does not exist.`);
4608
+ H(`Texture.setValues(): property '${t}' does not exist.`);
4461
4609
  continue;
4462
4610
  }
4463
4611
  r && n && r.isVector2 && n.isVector2 || r && n && r.isVector3 && n.isVector3 || r && n && r.isMatrix3 && n.isMatrix3 ? r.copy(n) : this[t] = n;
@@ -4503,24 +4651,24 @@ var Ei = 0, Di = /*@__PURE__*/ new G(), Oi = class e extends oi {
4503
4651
  transformUv(e) {
4504
4652
  if (this.mapping !== 300) return e;
4505
4653
  if (e.applyMatrix3(this.matrix), e.x < 0 || e.x > 1) switch (this.wrapS) {
4506
- case Fr:
4654
+ case Rr:
4507
4655
  e.x -= Math.floor(e.x);
4508
4656
  break;
4509
- case Ir:
4657
+ case zr:
4510
4658
  e.x = e.x < 0 ? 0 : 1;
4511
4659
  break;
4512
- case Lr:
4660
+ case Br:
4513
4661
  Math.abs(Math.floor(e.x) % 2) === 1 ? e.x = Math.ceil(e.x) - e.x : e.x -= Math.floor(e.x);
4514
4662
  break;
4515
4663
  }
4516
4664
  if (e.y < 0 || e.y > 1) switch (this.wrapT) {
4517
- case Fr:
4665
+ case Rr:
4518
4666
  e.y -= Math.floor(e.y);
4519
4667
  break;
4520
- case Ir:
4668
+ case zr:
4521
4669
  e.y = e.y < 0 ? 0 : 1;
4522
4670
  break;
4523
- case Lr:
4671
+ case Br:
4524
4672
  Math.abs(Math.floor(e.y) % 2) === 1 ? e.y = Math.ceil(e.y) - e.y : e.y -= Math.floor(e.y);
4525
4673
  break;
4526
4674
  }
@@ -4533,7 +4681,7 @@ var Ei = 0, Di = /*@__PURE__*/ new G(), Oi = class e extends oi {
4533
4681
  e === !0 && this.pmremVersion++;
4534
4682
  }
4535
4683
  };
4536
- Oi.DEFAULT_IMAGE = null, Oi.DEFAULT_MAPPING = 300, Oi.DEFAULT_ANISOTROPY = 1, class e {
4684
+ ji.DEFAULT_IMAGE = null, ji.DEFAULT_MAPPING = 300, ji.DEFAULT_ANISOTROPY = 1, class e {
4537
4685
  static {
4538
4686
  e.prototype.isVector4 = !0;
4539
4687
  }
@@ -4667,14 +4815,14 @@ Oi.DEFAULT_IMAGE = null, Oi.DEFAULT_MAPPING = 300, Oi.DEFAULT_ANISOTROPY = 1, cl
4667
4815
  return this.x = Math.max(this.x, e.x), this.y = Math.max(this.y, e.y), this.z = Math.max(this.z, e.z), this.w = Math.max(this.w, e.w), this;
4668
4816
  }
4669
4817
  clamp(e, t) {
4670
- return this.x = W(this.x, e.x, t.x), this.y = W(this.y, e.y, t.y), this.z = W(this.z, e.z, t.z), this.w = W(this.w, e.w, t.w), this;
4818
+ return this.x = G(this.x, e.x, t.x), this.y = G(this.y, e.y, t.y), this.z = G(this.z, e.z, t.z), this.w = G(this.w, e.w, t.w), this;
4671
4819
  }
4672
4820
  clampScalar(e, t) {
4673
- return this.x = W(this.x, e, t), this.y = W(this.y, e, t), this.z = W(this.z, e, t), this.w = W(this.w, e, t), this;
4821
+ return this.x = G(this.x, e, t), this.y = G(this.y, e, t), this.z = G(this.z, e, t), this.w = G(this.w, e, t), this;
4674
4822
  }
4675
4823
  clampLength(e, t) {
4676
4824
  let n = this.length();
4677
- return this.divideScalar(n || 1).multiplyScalar(W(n, e, t));
4825
+ return this.divideScalar(n || 1).multiplyScalar(G(n, e, t));
4678
4826
  }
4679
4827
  floor() {
4680
4828
  return this.x = Math.floor(this.x), this.y = Math.floor(this.y), this.z = Math.floor(this.z), this.w = Math.floor(this.w), this;
@@ -4734,7 +4882,7 @@ Oi.DEFAULT_IMAGE = null, Oi.DEFAULT_MAPPING = 300, Oi.DEFAULT_ANISOTROPY = 1, cl
4734
4882
  yield this.x, yield this.y, yield this.z, yield this.w;
4735
4883
  }
4736
4884
  };
4737
- var ki = class e {
4885
+ var Mi = class e {
4738
4886
  static {
4739
4887
  e.prototype.isMatrix4 = !0;
4740
4888
  }
@@ -4788,7 +4936,7 @@ var ki = class e {
4788
4936
  }
4789
4937
  extractRotation(e) {
4790
4938
  if (e.determinant() === 0) return this.identity();
4791
- let t = this.elements, n = e.elements, r = 1 / Ai.setFromMatrixColumn(e, 0).length(), i = 1 / Ai.setFromMatrixColumn(e, 1).length(), a = 1 / Ai.setFromMatrixColumn(e, 2).length();
4939
+ let t = this.elements, n = e.elements, r = 1 / Ni.setFromMatrixColumn(e, 0).length(), i = 1 / Ni.setFromMatrixColumn(e, 1).length(), a = 1 / Ni.setFromMatrixColumn(e, 2).length();
4792
4940
  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;
4793
4941
  }
4794
4942
  makeRotationFromEuler(e) {
@@ -4815,11 +4963,11 @@ var ki = class e {
4815
4963
  return t[3] = 0, t[7] = 0, t[11] = 0, t[12] = 0, t[13] = 0, t[14] = 0, t[15] = 1, this;
4816
4964
  }
4817
4965
  makeRotationFromQuaternion(e) {
4818
- return this.compose(ji, e, Mi);
4966
+ return this.compose(Pi, e, Fi);
4819
4967
  }
4820
4968
  lookAt(e, t, n) {
4821
4969
  let r = this.elements;
4822
- return J.subVectors(e, t), J.lengthSq() === 0 && (J.z = 1), J.normalize(), Ni.crossVectors(n, J), Ni.lengthSq() === 0 && (Math.abs(n.z) === 1 ? J.x += 1e-4 : J.z += 1e-4, J.normalize(), Ni.crossVectors(n, J)), Ni.normalize(), Pi.crossVectors(J, Ni), r[0] = Ni.x, r[4] = Pi.x, r[8] = J.x, r[1] = Ni.y, r[5] = Pi.y, r[9] = J.y, r[2] = Ni.z, r[6] = Pi.z, r[10] = J.z, this;
4970
+ return Y.subVectors(e, t), Y.lengthSq() === 0 && (Y.z = 1), Y.normalize(), Ii.crossVectors(n, Y), Ii.lengthSq() === 0 && (Math.abs(n.z) === 1 ? Y.x += 1e-4 : Y.z += 1e-4, Y.normalize(), Ii.crossVectors(n, Y)), Ii.normalize(), Li.crossVectors(Y, Ii), r[0] = Ii.x, r[4] = Li.x, r[8] = Y.x, r[1] = Ii.y, r[5] = Li.y, r[9] = Y.y, r[2] = Ii.z, r[6] = Li.z, r[10] = Y.z, this;
4823
4971
  }
4824
4972
  multiply(e) {
4825
4973
  return this.multiplyMatrices(this, e);
@@ -4828,8 +4976,8 @@ var ki = class e {
4828
4976
  return this.multiplyMatrices(e, this);
4829
4977
  }
4830
4978
  multiplyMatrices(e, t) {
4831
- let n = e.elements, r = t.elements, i = this.elements, a = n[0], o = n[4], s = n[8], c = n[12], l = n[1], u = n[5], d = n[9], f = n[13], p = n[2], m = n[6], h = n[10], g = n[14], _ = n[3], v = n[7], y = n[11], b = n[15], x = r[0], S = r[4], C = r[8], w = r[12], T = r[1], E = r[5], D = r[9], O = r[13], k = r[2], A = r[6], ee = r[10], te = r[14], j = r[3], ne = r[7], M = r[11], N = r[15];
4832
- return i[0] = a * x + o * T + s * k + c * j, i[4] = a * S + o * E + s * A + c * ne, i[8] = a * C + o * D + s * ee + c * M, i[12] = a * w + o * O + s * te + c * N, i[1] = l * x + u * T + d * k + f * j, i[5] = l * S + u * E + d * A + f * ne, i[9] = l * C + u * D + d * ee + f * M, i[13] = l * w + u * O + d * te + f * N, i[2] = p * x + m * T + h * k + g * j, i[6] = p * S + m * E + h * A + g * ne, i[10] = p * C + m * D + h * ee + g * M, i[14] = p * w + m * O + h * te + g * N, i[3] = _ * x + v * T + y * k + b * j, i[7] = _ * S + v * E + y * A + b * ne, i[11] = _ * C + v * D + y * ee + b * M, i[15] = _ * w + v * O + y * te + b * N, this;
4979
+ let n = e.elements, r = t.elements, i = this.elements, a = n[0], o = n[4], s = n[8], c = n[12], l = n[1], u = n[5], d = n[9], f = n[13], p = n[2], m = n[6], h = n[10], g = n[14], _ = n[3], v = n[7], y = n[11], b = n[15], x = r[0], S = r[4], C = r[8], w = r[12], T = r[1], E = r[5], D = r[9], O = r[13], k = r[2], A = r[6], ee = r[10], te = r[14], j = r[3], ne = r[7], re = r[11], M = r[15];
4980
+ return i[0] = a * x + o * T + s * k + c * j, i[4] = a * S + o * E + s * A + c * ne, i[8] = a * C + o * D + s * ee + c * re, i[12] = a * w + o * O + s * te + c * M, i[1] = l * x + u * T + d * k + f * j, i[5] = l * S + u * E + d * A + f * ne, i[9] = l * C + u * D + d * ee + f * re, i[13] = l * w + u * O + d * te + f * M, i[2] = p * x + m * T + h * k + g * j, i[6] = p * S + m * E + h * A + g * ne, i[10] = p * C + m * D + h * ee + g * re, i[14] = p * w + m * O + h * te + g * M, i[3] = _ * x + v * T + y * k + b * j, i[7] = _ * S + v * E + y * A + b * ne, i[11] = _ * C + v * D + y * ee + b * re, i[15] = _ * w + v * O + y * te + b * M, this;
4833
4981
  }
4834
4982
  multiplyScalar(e) {
4835
4983
  let t = this.elements;
@@ -4895,12 +5043,12 @@ var ki = class e {
4895
5043
  e.x = r[12], e.y = r[13], e.z = r[14];
4896
5044
  let i = this.determinant();
4897
5045
  if (i === 0) return n.set(1, 1, 1), t.identity(), this;
4898
- let a = Ai.set(r[0], r[1], r[2]).length(), o = Ai.set(r[4], r[5], r[6]).length(), s = Ai.set(r[8], r[9], r[10]).length();
4899
- i < 0 && (a = -a), q.copy(this);
5046
+ let a = Ni.set(r[0], r[1], r[2]).length(), o = Ni.set(r[4], r[5], r[6]).length(), s = Ni.set(r[8], r[9], r[10]).length();
5047
+ i < 0 && (a = -a), J.copy(this);
4900
5048
  let c = 1 / a, l = 1 / o, u = 1 / s;
4901
- return q.elements[0] *= c, q.elements[1] *= c, q.elements[2] *= c, q.elements[4] *= l, q.elements[5] *= l, q.elements[6] *= l, q.elements[8] *= u, q.elements[9] *= u, q.elements[10] *= u, t.setFromRotationMatrix(q), n.x = a, n.y = o, n.z = s, this;
5049
+ 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;
4902
5050
  }
4903
- makePerspective(e, t, n, r, i, a, o = $r, s = !1) {
5051
+ makePerspective(e, t, n, r, i, a, o = ni, s = !1) {
4904
5052
  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;
4905
5053
  if (s) p = i / (a - i), m = a * i / (a - i);
4906
5054
  else if (o === 2e3) p = -(a + i) / (a - i), m = -2 * a * i / (a - i);
@@ -4908,7 +5056,7 @@ var ki = class e {
4908
5056
  else throw Error("THREE.Matrix4.makePerspective(): Invalid coordinate system: " + o);
4909
5057
  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;
4910
5058
  }
4911
- makeOrthographic(e, t, n, r, i, a, o = $r, s = !1) {
5059
+ makeOrthographic(e, t, n, r, i, a, o = ni, s = !1) {
4912
5060
  let c = this.elements, l = 2 / (t - e), u = 2 / (n - r), d = -(t + e) / (t - e), f = -(n + r) / (n - r), p, m;
4913
5061
  if (s) p = 1 / (a - i), m = a / (a - i);
4914
5062
  else if (o === 2e3) p = -2 / (a - i), m = -(a + i) / (a - i);
@@ -4929,7 +5077,7 @@ var ki = class e {
4929
5077
  let n = this.elements;
4930
5078
  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;
4931
5079
  }
4932
- }, Ai = /*@__PURE__*/ new G(), q = /*@__PURE__*/ new ki(), ji = /*@__PURE__*/ new G(0, 0, 0), Mi = /*@__PURE__*/ new G(1, 1, 1), Ni = /*@__PURE__*/ new G(), Pi = /*@__PURE__*/ new G(), J = /*@__PURE__*/ new G(), Fi = /*@__PURE__*/ new ki(), Ii = /*@__PURE__*/ new di(), Li = class e {
5080
+ }, Ni = /*@__PURE__*/ new K(), J = /*@__PURE__*/ new Mi(), Pi = /*@__PURE__*/ new K(0, 0, 0), Fi = /*@__PURE__*/ new K(1, 1, 1), Ii = /*@__PURE__*/ new K(), Li = /*@__PURE__*/ new K(), Y = /*@__PURE__*/ new K(), Ri = /*@__PURE__*/ new Mi(), zi = /*@__PURE__*/ new mi(), Bi = class e {
4933
5081
  constructor(t = 0, n = 0, r = 0, i = e.DEFAULT_ORDER) {
4934
5082
  this.isEuler = !0, this._x = t, this._y = n, this._z = r, this._order = i;
4935
5083
  }
@@ -4970,35 +5118,35 @@ var ki = class e {
4970
5118
  let r = e.elements, i = r[0], a = r[4], o = r[8], s = r[1], c = r[5], l = r[9], u = r[2], d = r[6], f = r[10];
4971
5119
  switch (t) {
4972
5120
  case "XYZ":
4973
- this._y = Math.asin(W(o, -1, 1)), Math.abs(o) < .9999999 ? (this._x = Math.atan2(-l, f), this._z = Math.atan2(-a, i)) : (this._x = Math.atan2(d, c), this._z = 0);
5121
+ this._y = Math.asin(G(o, -1, 1)), Math.abs(o) < .9999999 ? (this._x = Math.atan2(-l, f), this._z = Math.atan2(-a, i)) : (this._x = Math.atan2(d, c), this._z = 0);
4974
5122
  break;
4975
5123
  case "YXZ":
4976
- this._x = Math.asin(-W(l, -1, 1)), Math.abs(l) < .9999999 ? (this._y = Math.atan2(o, f), this._z = Math.atan2(s, c)) : (this._y = Math.atan2(-u, i), this._z = 0);
5124
+ this._x = Math.asin(-G(l, -1, 1)), Math.abs(l) < .9999999 ? (this._y = Math.atan2(o, f), this._z = Math.atan2(s, c)) : (this._y = Math.atan2(-u, i), this._z = 0);
4977
5125
  break;
4978
5126
  case "ZXY":
4979
- this._x = Math.asin(W(d, -1, 1)), Math.abs(d) < .9999999 ? (this._y = Math.atan2(-u, f), this._z = Math.atan2(-a, c)) : (this._y = 0, this._z = Math.atan2(s, i));
5127
+ this._x = Math.asin(G(d, -1, 1)), Math.abs(d) < .9999999 ? (this._y = Math.atan2(-u, f), this._z = Math.atan2(-a, c)) : (this._y = 0, this._z = Math.atan2(s, i));
4980
5128
  break;
4981
5129
  case "ZYX":
4982
- this._y = Math.asin(-W(u, -1, 1)), Math.abs(u) < .9999999 ? (this._x = Math.atan2(d, f), this._z = Math.atan2(s, i)) : (this._x = 0, this._z = Math.atan2(-a, c));
5130
+ this._y = Math.asin(-G(u, -1, 1)), Math.abs(u) < .9999999 ? (this._x = Math.atan2(d, f), this._z = Math.atan2(s, i)) : (this._x = 0, this._z = Math.atan2(-a, c));
4983
5131
  break;
4984
5132
  case "YZX":
4985
- this._z = Math.asin(W(s, -1, 1)), Math.abs(s) < .9999999 ? (this._x = Math.atan2(-l, c), this._y = Math.atan2(-u, i)) : (this._x = 0, this._y = Math.atan2(o, f));
5133
+ this._z = Math.asin(G(s, -1, 1)), Math.abs(s) < .9999999 ? (this._x = Math.atan2(-l, c), this._y = Math.atan2(-u, i)) : (this._x = 0, this._y = Math.atan2(o, f));
4986
5134
  break;
4987
5135
  case "XZY":
4988
- this._z = Math.asin(-W(a, -1, 1)), Math.abs(a) < .9999999 ? (this._x = Math.atan2(d, c), this._y = Math.atan2(o, i)) : (this._x = Math.atan2(-l, f), this._y = 0);
5136
+ this._z = Math.asin(-G(a, -1, 1)), Math.abs(a) < .9999999 ? (this._x = Math.atan2(d, c), this._y = Math.atan2(o, i)) : (this._x = Math.atan2(-l, f), this._y = 0);
4989
5137
  break;
4990
- default: V("Euler: .setFromRotationMatrix() encountered an unknown order: " + t);
5138
+ default: H("Euler: .setFromRotationMatrix() encountered an unknown order: " + t);
4991
5139
  }
4992
5140
  return this._order = t, n === !0 && this._onChangeCallback(), this;
4993
5141
  }
4994
5142
  setFromQuaternion(e, t, n) {
4995
- return Fi.makeRotationFromQuaternion(e), this.setFromRotationMatrix(Fi, t, n);
5143
+ return Ri.makeRotationFromQuaternion(e), this.setFromRotationMatrix(Ri, t, n);
4996
5144
  }
4997
5145
  setFromVector3(e, t = this._order) {
4998
5146
  return this.set(e.x, e.y, e.z, t);
4999
5147
  }
5000
5148
  reorder(e) {
5001
- return Ii.setFromEuler(this), this.setFromQuaternion(Ii, e);
5149
+ return zi.setFromEuler(this), this.setFromQuaternion(zi, e);
5002
5150
  }
5003
5151
  equals(e) {
5004
5152
  return e._x === this._x && e._y === this._y && e._z === this._z && e._order === this._order;
@@ -5017,8 +5165,8 @@ var ki = class e {
5017
5165
  yield this._x, yield this._y, yield this._z, yield this._order;
5018
5166
  }
5019
5167
  };
5020
- Li.DEFAULT_ORDER = "XYZ";
5021
- var Ri = class {
5168
+ Bi.DEFAULT_ORDER = "XYZ";
5169
+ var Vi = class {
5022
5170
  constructor() {
5023
5171
  this.mask = 1;
5024
5172
  }
@@ -5046,16 +5194,16 @@ var Ri = class {
5046
5194
  isEnabled(e) {
5047
5195
  return (this.mask & (1 << e | 0)) != 0;
5048
5196
  }
5049
- }, zi = 0, Bi = /*@__PURE__*/ new G(), Vi = /*@__PURE__*/ new di(), Hi = /*@__PURE__*/ new ki(), Ui = /*@__PURE__*/ new G(), Wi = /*@__PURE__*/ new G(), Gi = /*@__PURE__*/ new G(), Ki = /*@__PURE__*/ new di(), qi = /*@__PURE__*/ new G(1, 0, 0), Ji = /*@__PURE__*/ new G(0, 1, 0), Yi = /*@__PURE__*/ new G(0, 0, 1), Xi = { type: "added" }, Zi = { type: "removed" }, Qi = {
5197
+ }, Hi = 0, Ui = /*@__PURE__*/ new K(), Wi = /*@__PURE__*/ new mi(), Gi = /*@__PURE__*/ new Mi(), Ki = /*@__PURE__*/ new K(), qi = /*@__PURE__*/ new K(), Ji = /*@__PURE__*/ new K(), Yi = /*@__PURE__*/ new mi(), Xi = /*@__PURE__*/ new K(1, 0, 0), Zi = /*@__PURE__*/ new K(0, 1, 0), Qi = /*@__PURE__*/ new K(0, 0, 1), $i = { type: "added" }, ea = { type: "removed" }, ta = {
5050
5198
  type: "childadded",
5051
5199
  child: null
5052
- }, $i = {
5200
+ }, na = {
5053
5201
  type: "childremoved",
5054
5202
  child: null
5055
- }, ea = class e extends oi {
5203
+ }, ra = class e extends li {
5056
5204
  constructor() {
5057
- super(), this.isObject3D = !0, Object.defineProperty(this, "id", { value: zi++ }), this.uuid = si(), this.name = "", this.type = "Object3D", this.parent = null, this.children = [], this.up = e.DEFAULT_UP.clone();
5058
- let t = new G(), n = new Li(), r = new di(), i = new G(1, 1, 1);
5205
+ super(), this.isObject3D = !0, Object.defineProperty(this, "id", { value: Hi++ }), this.uuid = ui(), this.name = "", this.type = "Object3D", this.parent = null, this.children = [], this.up = e.DEFAULT_UP.clone();
5206
+ let t = new K(), n = new Bi(), r = new mi(), i = new K(1, 1, 1);
5059
5207
  function a() {
5060
5208
  r.setFromEuler(n, !1);
5061
5209
  }
@@ -5083,9 +5231,9 @@ var Ri = class {
5083
5231
  enumerable: !0,
5084
5232
  value: i
5085
5233
  },
5086
- modelViewMatrix: { value: new ki() },
5087
- normalMatrix: { value: new mi() }
5088
- }), this.matrix = new ki(), this.matrixWorld = new ki(), this.matrixAutoUpdate = e.DEFAULT_MATRIX_AUTO_UPDATE, this.matrixWorldAutoUpdate = e.DEFAULT_MATRIX_WORLD_AUTO_UPDATE, this.matrixWorldNeedsUpdate = !1, this.layers = new Ri(), 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;
5234
+ modelViewMatrix: { value: new Mi() },
5235
+ normalMatrix: { value: new _i() }
5236
+ }), this.matrix = new Mi(), this.matrixWorld = new Mi(), this.matrixAutoUpdate = e.DEFAULT_MATRIX_AUTO_UPDATE, this.matrixWorldAutoUpdate = e.DEFAULT_MATRIX_WORLD_AUTO_UPDATE, this.matrixWorldNeedsUpdate = !1, this.layers = new Vi(), 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;
5089
5237
  }
5090
5238
  onBeforeShadow() {}
5091
5239
  onAfterShadow() {}
@@ -5110,49 +5258,49 @@ var Ri = class {
5110
5258
  this.quaternion.copy(e);
5111
5259
  }
5112
5260
  rotateOnAxis(e, t) {
5113
- return Vi.setFromAxisAngle(e, t), this.quaternion.multiply(Vi), this;
5261
+ return Wi.setFromAxisAngle(e, t), this.quaternion.multiply(Wi), this;
5114
5262
  }
5115
5263
  rotateOnWorldAxis(e, t) {
5116
- return Vi.setFromAxisAngle(e, t), this.quaternion.premultiply(Vi), this;
5264
+ return Wi.setFromAxisAngle(e, t), this.quaternion.premultiply(Wi), this;
5117
5265
  }
5118
5266
  rotateX(e) {
5119
- return this.rotateOnAxis(qi, e);
5267
+ return this.rotateOnAxis(Xi, e);
5120
5268
  }
5121
5269
  rotateY(e) {
5122
- return this.rotateOnAxis(Ji, e);
5270
+ return this.rotateOnAxis(Zi, e);
5123
5271
  }
5124
5272
  rotateZ(e) {
5125
- return this.rotateOnAxis(Yi, e);
5273
+ return this.rotateOnAxis(Qi, e);
5126
5274
  }
5127
5275
  translateOnAxis(e, t) {
5128
- return Bi.copy(e).applyQuaternion(this.quaternion), this.position.add(Bi.multiplyScalar(t)), this;
5276
+ return Ui.copy(e).applyQuaternion(this.quaternion), this.position.add(Ui.multiplyScalar(t)), this;
5129
5277
  }
5130
5278
  translateX(e) {
5131
- return this.translateOnAxis(qi, e);
5279
+ return this.translateOnAxis(Xi, e);
5132
5280
  }
5133
5281
  translateY(e) {
5134
- return this.translateOnAxis(Ji, e);
5282
+ return this.translateOnAxis(Zi, e);
5135
5283
  }
5136
5284
  translateZ(e) {
5137
- return this.translateOnAxis(Yi, e);
5285
+ return this.translateOnAxis(Qi, e);
5138
5286
  }
5139
5287
  localToWorld(e) {
5140
5288
  return this.updateWorldMatrix(!0, !1), e.applyMatrix4(this.matrixWorld);
5141
5289
  }
5142
5290
  worldToLocal(e) {
5143
- return this.updateWorldMatrix(!0, !1), e.applyMatrix4(Hi.copy(this.matrixWorld).invert());
5291
+ return this.updateWorldMatrix(!0, !1), e.applyMatrix4(Gi.copy(this.matrixWorld).invert());
5144
5292
  }
5145
5293
  lookAt(e, t, n) {
5146
- e.isVector3 ? Ui.copy(e) : Ui.set(e, t, n);
5294
+ e.isVector3 ? Ki.copy(e) : Ki.set(e, t, n);
5147
5295
  let r = this.parent;
5148
- this.updateWorldMatrix(!0, !1), Wi.setFromMatrixPosition(this.matrixWorld), this.isCamera || this.isLight ? Hi.lookAt(Wi, Ui, this.up) : Hi.lookAt(Ui, Wi, this.up), this.quaternion.setFromRotationMatrix(Hi), r && (Hi.extractRotation(r.matrixWorld), Vi.setFromRotationMatrix(Hi), this.quaternion.premultiply(Vi.invert()));
5296
+ this.updateWorldMatrix(!0, !1), qi.setFromMatrixPosition(this.matrixWorld), this.isCamera || this.isLight ? Gi.lookAt(qi, Ki, this.up) : Gi.lookAt(Ki, qi, this.up), this.quaternion.setFromRotationMatrix(Gi), r && (Gi.extractRotation(r.matrixWorld), Wi.setFromRotationMatrix(Gi), this.quaternion.premultiply(Wi.invert()));
5149
5297
  }
5150
5298
  add(e) {
5151
5299
  if (arguments.length > 1) {
5152
5300
  for (let e = 0; e < arguments.length; e++) this.add(arguments[e]);
5153
5301
  return this;
5154
5302
  }
5155
- return e === this ? (H("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(Xi), Qi.child = e, this.dispatchEvent(Qi), Qi.child = null) : H("Object3D.add: object not an instance of THREE.Object3D.", e), this);
5303
+ 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($i), ta.child = e, this.dispatchEvent(ta), ta.child = null) : U("Object3D.add: object not an instance of THREE.Object3D.", e), this);
5156
5304
  }
5157
5305
  remove(e) {
5158
5306
  if (arguments.length > 1) {
@@ -5160,7 +5308,7 @@ var Ri = class {
5160
5308
  return this;
5161
5309
  }
5162
5310
  let t = this.children.indexOf(e);
5163
- return t !== -1 && (e.parent = null, this.children.splice(t, 1), e.dispatchEvent(Zi), $i.child = e, this.dispatchEvent($i), $i.child = null), this;
5311
+ return t !== -1 && (e.parent = null, this.children.splice(t, 1), e.dispatchEvent(ea), na.child = e, this.dispatchEvent(na), na.child = null), this;
5164
5312
  }
5165
5313
  removeFromParent() {
5166
5314
  let e = this.parent;
@@ -5170,7 +5318,7 @@ var Ri = class {
5170
5318
  return this.remove(...this.children);
5171
5319
  }
5172
5320
  attach(e) {
5173
- return this.updateWorldMatrix(!0, !1), Hi.copy(this.matrixWorld).invert(), e.parent !== null && (e.parent.updateWorldMatrix(!0, !1), Hi.multiply(e.parent.matrixWorld)), e.applyMatrix4(Hi), e.removeFromParent(), e.parent = this, this.children.push(e), e.updateWorldMatrix(!1, !0), e.dispatchEvent(Xi), Qi.child = e, this.dispatchEvent(Qi), Qi.child = null, this;
5321
+ return this.updateWorldMatrix(!0, !1), Gi.copy(this.matrixWorld).invert(), e.parent !== null && (e.parent.updateWorldMatrix(!0, !1), Gi.multiply(e.parent.matrixWorld)), e.applyMatrix4(Gi), e.removeFromParent(), e.parent = this, this.children.push(e), e.updateWorldMatrix(!1, !0), e.dispatchEvent($i), ta.child = e, this.dispatchEvent(ta), ta.child = null, this;
5174
5322
  }
5175
5323
  getObjectById(e) {
5176
5324
  return this.getObjectByProperty("id", e);
@@ -5195,10 +5343,10 @@ var Ri = class {
5195
5343
  return this.updateWorldMatrix(!0, !1), e.setFromMatrixPosition(this.matrixWorld);
5196
5344
  }
5197
5345
  getWorldQuaternion(e) {
5198
- return this.updateWorldMatrix(!0, !1), this.matrixWorld.decompose(Wi, e, Gi), e;
5346
+ return this.updateWorldMatrix(!0, !1), this.matrixWorld.decompose(qi, e, Ji), e;
5199
5347
  }
5200
5348
  getWorldScale(e) {
5201
- return this.updateWorldMatrix(!0, !1), this.matrixWorld.decompose(Wi, Ki, e), e;
5349
+ return this.updateWorldMatrix(!0, !1), this.matrixWorld.decompose(qi, Yi, e), e;
5202
5350
  }
5203
5351
  getWorldDirection(e) {
5204
5352
  this.updateWorldMatrix(!0, !1);
@@ -5321,8 +5469,8 @@ var Ri = class {
5321
5469
  return this;
5322
5470
  }
5323
5471
  };
5324
- ea.DEFAULT_UP = /*@__PURE__*/ new G(0, 1, 0), ea.DEFAULT_MATRIX_AUTO_UPDATE = !0, ea.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = !0;
5325
- var ta = {
5472
+ ra.DEFAULT_UP = /*@__PURE__*/ new K(0, 1, 0), ra.DEFAULT_MATRIX_AUTO_UPDATE = !0, ra.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = !0;
5473
+ var ia = {
5326
5474
  aliceblue: 15792383,
5327
5475
  antiquewhite: 16444375,
5328
5476
  aqua: 65535,
@@ -5471,19 +5619,19 @@ var ta = {
5471
5619
  whitesmoke: 16119285,
5472
5620
  yellow: 16776960,
5473
5621
  yellowgreen: 10145074
5474
- }, na = {
5622
+ }, aa = {
5475
5623
  h: 0,
5476
5624
  s: 0,
5477
5625
  l: 0
5478
- }, ra = {
5626
+ }, oa = {
5479
5627
  h: 0,
5480
5628
  s: 0,
5481
5629
  l: 0
5482
5630
  };
5483
- function ia(e, t, n) {
5631
+ function sa(e, t, n) {
5484
5632
  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;
5485
5633
  }
5486
- var aa = class {
5634
+ var ca = class {
5487
5635
  constructor(e, t, n) {
5488
5636
  return this.isColor = !0, this.r = 1, this.g = 1, this.b = 1, this.set(e, t, n);
5489
5637
  }
@@ -5497,23 +5645,23 @@ var aa = class {
5497
5645
  setScalar(e) {
5498
5646
  return this.r = e, this.g = e, this.b = e, this;
5499
5647
  }
5500
- setHex(e, t = Yr) {
5501
- return e = Math.floor(e), this.r = (e >> 16 & 255) / 255, this.g = (e >> 8 & 255) / 255, this.b = (e & 255) / 255, K.colorSpaceToWorking(this, t), this;
5648
+ setHex(e, t = Qr) {
5649
+ 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;
5502
5650
  }
5503
- setRGB(e, t, n, r = K.workingColorSpace) {
5504
- return this.r = e, this.g = t, this.b = n, K.colorSpaceToWorking(this, r), this;
5651
+ setRGB(e, t, n, r = q.workingColorSpace) {
5652
+ return this.r = e, this.g = t, this.b = n, q.colorSpaceToWorking(this, r), this;
5505
5653
  }
5506
- setHSL(e, t, n, r = K.workingColorSpace) {
5507
- if (e = ci(e, 1), t = W(t, 0, 1), n = W(n, 0, 1), t === 0) this.r = this.g = this.b = n;
5654
+ setHSL(e, t, n, r = q.workingColorSpace) {
5655
+ if (e = di(e, 1), t = G(t, 0, 1), n = G(n, 0, 1), t === 0) this.r = this.g = this.b = n;
5508
5656
  else {
5509
5657
  let r = n <= .5 ? n * (1 + t) : n + t - n * t, i = 2 * n - r;
5510
- this.r = ia(i, r, e + 1 / 3), this.g = ia(i, r, e), this.b = ia(i, r, e - 1 / 3);
5658
+ this.r = sa(i, r, e + 1 / 3), this.g = sa(i, r, e), this.b = sa(i, r, e - 1 / 3);
5511
5659
  }
5512
- return K.colorSpaceToWorking(this, r), this;
5660
+ return q.colorSpaceToWorking(this, r), this;
5513
5661
  }
5514
- setStyle(e, t = Yr) {
5662
+ setStyle(e, t = Qr) {
5515
5663
  function n(t) {
5516
- t !== void 0 && parseFloat(t) < 1 && V("Color: Alpha component of " + e + " will be ignored.");
5664
+ t !== void 0 && parseFloat(t) < 1 && H("Color: Alpha component of " + e + " will be ignored.");
5517
5665
  }
5518
5666
  let r;
5519
5667
  if (r = /^(\w+)\(([^\)]*)\)/.exec(e)) {
@@ -5528,19 +5676,19 @@ var aa = class {
5528
5676
  case "hsla":
5529
5677
  if (i = /^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o)) return n(i[4]), this.setHSL(parseFloat(i[1]) / 360, parseFloat(i[2]) / 100, parseFloat(i[3]) / 100, t);
5530
5678
  break;
5531
- default: V("Color: Unknown color model " + e);
5679
+ default: H("Color: Unknown color model " + e);
5532
5680
  }
5533
5681
  } else if (r = /^\#([A-Fa-f\d]+)$/.exec(e)) {
5534
5682
  let n = r[1], i = n.length;
5535
5683
  if (i === 3) return this.setRGB(parseInt(n.charAt(0), 16) / 15, parseInt(n.charAt(1), 16) / 15, parseInt(n.charAt(2), 16) / 15, t);
5536
5684
  if (i === 6) return this.setHex(parseInt(n, 16), t);
5537
- V("Color: Invalid hex color " + e);
5685
+ H("Color: Invalid hex color " + e);
5538
5686
  } else if (e && e.length > 0) return this.setColorName(e, t);
5539
5687
  return this;
5540
5688
  }
5541
- setColorName(e, t = Yr) {
5542
- let n = ta[e.toLowerCase()];
5543
- return n === void 0 ? V("Color: Unknown color " + e) : this.setHex(n, t), this;
5689
+ setColorName(e, t = Qr) {
5690
+ let n = ia[e.toLowerCase()];
5691
+ return n === void 0 ? H("Color: Unknown color " + e) : this.setHex(n, t), this;
5544
5692
  }
5545
5693
  clone() {
5546
5694
  return new this.constructor(this.r, this.g, this.b);
@@ -5549,10 +5697,10 @@ var aa = class {
5549
5697
  return this.r = e.r, this.g = e.g, this.b = e.b, this;
5550
5698
  }
5551
5699
  copySRGBToLinear(e) {
5552
- return this.r = yi(e.r), this.g = yi(e.g), this.b = yi(e.b), this;
5700
+ return this.r = Si(e.r), this.g = Si(e.g), this.b = Si(e.b), this;
5553
5701
  }
5554
5702
  copyLinearToSRGB(e) {
5555
- return this.r = bi(e.r), this.g = bi(e.g), this.b = bi(e.b), this;
5703
+ return this.r = Ci(e.r), this.g = Ci(e.g), this.b = Ci(e.b), this;
5556
5704
  }
5557
5705
  convertSRGBToLinear() {
5558
5706
  return this.copySRGBToLinear(this), this;
@@ -5560,15 +5708,15 @@ var aa = class {
5560
5708
  convertLinearToSRGB() {
5561
5709
  return this.copyLinearToSRGB(this), this;
5562
5710
  }
5563
- getHex(e = Yr) {
5564
- return K.workingToColorSpace(Y.copy(this), e), Math.round(W(Y.r * 255, 0, 255)) * 65536 + Math.round(W(Y.g * 255, 0, 255)) * 256 + Math.round(W(Y.b * 255, 0, 255));
5711
+ getHex(e = Qr) {
5712
+ 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));
5565
5713
  }
5566
- getHexString(e = Yr) {
5714
+ getHexString(e = Qr) {
5567
5715
  return ("000000" + this.getHex(e).toString(16)).slice(-6);
5568
5716
  }
5569
- getHSL(e, t = K.workingColorSpace) {
5570
- K.workingToColorSpace(Y.copy(this), t);
5571
- let n = Y.r, r = Y.g, i = Y.b, a = Math.max(n, r, i), o = Math.min(n, r, i), s, c, l = (o + a) / 2;
5717
+ getHSL(e, t = q.workingColorSpace) {
5718
+ q.workingToColorSpace(X.copy(this), t);
5719
+ let n = X.r, r = X.g, i = X.b, a = Math.max(n, r, i), o = Math.min(n, r, i), s, c, l = (o + a) / 2;
5572
5720
  if (o === a) s = 0, c = 0;
5573
5721
  else {
5574
5722
  let e = a - o;
@@ -5587,16 +5735,16 @@ var aa = class {
5587
5735
  }
5588
5736
  return e.h = s, e.s = c, e.l = l, e;
5589
5737
  }
5590
- getRGB(e, t = K.workingColorSpace) {
5591
- return K.workingToColorSpace(Y.copy(this), t), e.r = Y.r, e.g = Y.g, e.b = Y.b, e;
5738
+ getRGB(e, t = q.workingColorSpace) {
5739
+ return q.workingToColorSpace(X.copy(this), t), e.r = X.r, e.g = X.g, e.b = X.b, e;
5592
5740
  }
5593
- getStyle(e = Yr) {
5594
- K.workingToColorSpace(Y.copy(this), e);
5595
- let t = Y.r, n = Y.g, r = Y.b;
5741
+ getStyle(e = Qr) {
5742
+ q.workingToColorSpace(X.copy(this), e);
5743
+ let t = X.r, n = X.g, r = X.b;
5596
5744
  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)})`;
5597
5745
  }
5598
5746
  offsetHSL(e, t, n) {
5599
- return this.getHSL(na), this.setHSL(na.h + e, na.s + t, na.l + n);
5747
+ return this.getHSL(aa), this.setHSL(aa.h + e, aa.s + t, aa.l + n);
5600
5748
  }
5601
5749
  add(e) {
5602
5750
  return this.r += e.r, this.g += e.g, this.b += e.b, this;
@@ -5623,8 +5771,8 @@ var aa = class {
5623
5771
  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;
5624
5772
  }
5625
5773
  lerpHSL(e, t) {
5626
- this.getHSL(na), e.getHSL(ra);
5627
- let n = li(na.h, ra.h, t), r = li(na.s, ra.s, t), i = li(na.l, ra.l, t);
5774
+ this.getHSL(aa), e.getHSL(oa);
5775
+ let n = fi(aa.h, oa.h, t), r = fi(aa.s, oa.s, t), i = fi(aa.l, oa.l, t);
5628
5776
  return this.setHSL(n, r, i), this;
5629
5777
  }
5630
5778
  setFromVector3(e) {
@@ -5652,10 +5800,10 @@ var aa = class {
5652
5800
  *[Symbol.iterator]() {
5653
5801
  yield this.r, yield this.g, yield this.b;
5654
5802
  }
5655
- }, Y = /*@__PURE__*/ new aa();
5656
- aa.NAMES = ta;
5657
- var oa = class {
5658
- constructor(e = new G(Infinity, Infinity, Infinity), t = new G(-Infinity, -Infinity, -Infinity)) {
5803
+ }, X = /*@__PURE__*/ new ca();
5804
+ ca.NAMES = ia;
5805
+ var la = class {
5806
+ constructor(e = new K(Infinity, Infinity, Infinity), t = new K(-Infinity, -Infinity, -Infinity)) {
5659
5807
  this.isBox3 = !0, this.min = e, this.max = t;
5660
5808
  }
5661
5809
  set(e, t) {
@@ -5663,12 +5811,12 @@ var oa = class {
5663
5811
  }
5664
5812
  setFromArray(e) {
5665
5813
  this.makeEmpty();
5666
- for (let t = 0, n = e.length; t < n; t += 3) this.expandByPoint(X.fromArray(e, t));
5814
+ for (let t = 0, n = e.length; t < n; t += 3) this.expandByPoint(da.fromArray(e, t));
5667
5815
  return this;
5668
5816
  }
5669
5817
  setFromBufferAttribute(e) {
5670
5818
  this.makeEmpty();
5671
- for (let t = 0, n = e.count; t < n; t++) this.expandByPoint(X.fromBufferAttribute(e, t));
5819
+ for (let t = 0, n = e.count; t < n; t++) this.expandByPoint(da.fromBufferAttribute(e, t));
5672
5820
  return this;
5673
5821
  }
5674
5822
  setFromPoints(e) {
@@ -5677,7 +5825,7 @@ var oa = class {
5677
5825
  return this;
5678
5826
  }
5679
5827
  setFromCenterAndSize(e, t) {
5680
- let n = X.copy(t).multiplyScalar(.5);
5828
+ let n = da.copy(t).multiplyScalar(.5);
5681
5829
  return this.min.copy(e).sub(n), this.max.copy(e).add(n), this;
5682
5830
  }
5683
5831
  setFromObject(e, t = !1) {
@@ -5715,8 +5863,8 @@ var oa = class {
5715
5863
  let n = e.geometry;
5716
5864
  if (n !== void 0) {
5717
5865
  let r = n.getAttribute("position");
5718
- 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, X) : X.fromBufferAttribute(r, t), X.applyMatrix4(e.matrixWorld), this.expandByPoint(X);
5719
- else e.boundingBox === void 0 ? (n.boundingBox === null && n.computeBoundingBox(), ca.copy(n.boundingBox)) : (e.boundingBox === null && e.computeBoundingBox(), ca.copy(e.boundingBox)), ca.applyMatrix4(e.matrixWorld), this.union(ca);
5866
+ 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, da) : da.fromBufferAttribute(r, t), da.applyMatrix4(e.matrixWorld), this.expandByPoint(da);
5867
+ else e.boundingBox === void 0 ? (n.boundingBox === null && n.computeBoundingBox(), fa.copy(n.boundingBox)) : (e.boundingBox === null && e.computeBoundingBox(), fa.copy(e.boundingBox)), fa.applyMatrix4(e.matrixWorld), this.union(fa);
5720
5868
  }
5721
5869
  let r = e.children;
5722
5870
  for (let e = 0, n = r.length; e < n; e++) this.expandByObject(r[e], t);
@@ -5735,7 +5883,7 @@ var oa = class {
5735
5883
  return e.max.x >= this.min.x && e.min.x <= this.max.x && e.max.y >= this.min.y && e.min.y <= this.max.y && e.max.z >= this.min.z && e.min.z <= this.max.z;
5736
5884
  }
5737
5885
  intersectsSphere(e) {
5738
- return this.clampPoint(e.center, X), X.distanceToSquared(e.center) <= e.radius * e.radius;
5886
+ return this.clampPoint(e.center, da), da.distanceToSquared(e.center) <= e.radius * e.radius;
5739
5887
  }
5740
5888
  intersectsPlane(e) {
5741
5889
  let t, n;
@@ -5743,37 +5891,37 @@ var oa = class {
5743
5891
  }
5744
5892
  intersectsTriangle(e) {
5745
5893
  if (this.isEmpty()) return !1;
5746
- this.getCenter(ha), ga.subVectors(this.max, ha), la.subVectors(e.a, ha), ua.subVectors(e.b, ha), da.subVectors(e.c, ha), fa.subVectors(ua, la), pa.subVectors(da, ua), ma.subVectors(la, da);
5894
+ this.getCenter(ya), ba.subVectors(this.max, ya), pa.subVectors(e.a, ya), ma.subVectors(e.b, ya), ha.subVectors(e.c, ya), ga.subVectors(ma, pa), _a.subVectors(ha, ma), va.subVectors(pa, ha);
5747
5895
  let t = [
5748
5896
  0,
5749
- -fa.z,
5750
- fa.y,
5897
+ -ga.z,
5898
+ ga.y,
5751
5899
  0,
5752
- -pa.z,
5753
- pa.y,
5900
+ -_a.z,
5901
+ _a.y,
5754
5902
  0,
5755
- -ma.z,
5756
- ma.y,
5757
- fa.z,
5903
+ -va.z,
5904
+ va.y,
5905
+ ga.z,
5758
5906
  0,
5759
- -fa.x,
5760
- pa.z,
5907
+ -ga.x,
5908
+ _a.z,
5761
5909
  0,
5762
- -pa.x,
5763
- ma.z,
5910
+ -_a.x,
5911
+ va.z,
5764
5912
  0,
5765
- -ma.x,
5766
- -fa.y,
5767
- fa.x,
5913
+ -va.x,
5914
+ -ga.y,
5915
+ ga.x,
5768
5916
  0,
5769
- -pa.y,
5770
- pa.x,
5917
+ -_a.y,
5918
+ _a.x,
5771
5919
  0,
5772
- -ma.y,
5773
- ma.x,
5920
+ -va.y,
5921
+ va.x,
5774
5922
  0
5775
5923
  ];
5776
- return !ya(t, la, ua, da, ga) || (t = [
5924
+ return !Ca(t, pa, ma, ha, ba) || (t = [
5777
5925
  1,
5778
5926
  0,
5779
5927
  0,
@@ -5783,20 +5931,20 @@ var oa = class {
5783
5931
  0,
5784
5932
  0,
5785
5933
  1
5786
- ], !ya(t, la, ua, da, ga)) ? !1 : (_a.crossVectors(fa, pa), t = [
5787
- _a.x,
5788
- _a.y,
5789
- _a.z
5790
- ], ya(t, la, ua, da, ga));
5934
+ ], !Ca(t, pa, ma, ha, ba)) ? !1 : (xa.crossVectors(ga, _a), t = [
5935
+ xa.x,
5936
+ xa.y,
5937
+ xa.z
5938
+ ], Ca(t, pa, ma, ha, ba));
5791
5939
  }
5792
5940
  clampPoint(e, t) {
5793
5941
  return t.copy(e).clamp(this.min, this.max);
5794
5942
  }
5795
5943
  distanceToPoint(e) {
5796
- return this.clampPoint(e, X).distanceTo(e);
5944
+ return this.clampPoint(e, da).distanceTo(e);
5797
5945
  }
5798
5946
  getBoundingSphere(e) {
5799
- return this.isEmpty() ? e.makeEmpty() : (this.getCenter(e.center), e.radius = this.getSize(X).length() * .5), e;
5947
+ return this.isEmpty() ? e.makeEmpty() : (this.getCenter(e.center), e.radius = this.getSize(da).length() * .5), e;
5800
5948
  }
5801
5949
  intersect(e) {
5802
5950
  return this.min.max(e.min), this.max.min(e.max), this.isEmpty() && this.makeEmpty(), this;
@@ -5805,7 +5953,7 @@ var oa = class {
5805
5953
  return this.min.min(e.min), this.max.max(e.max), this;
5806
5954
  }
5807
5955
  applyMatrix4(e) {
5808
- return this.isEmpty() ? this : (sa[0].set(this.min.x, this.min.y, this.min.z).applyMatrix4(e), sa[1].set(this.min.x, this.min.y, this.max.z).applyMatrix4(e), sa[2].set(this.min.x, this.max.y, this.min.z).applyMatrix4(e), sa[3].set(this.min.x, this.max.y, this.max.z).applyMatrix4(e), sa[4].set(this.max.x, this.min.y, this.min.z).applyMatrix4(e), sa[5].set(this.max.x, this.min.y, this.max.z).applyMatrix4(e), sa[6].set(this.max.x, this.max.y, this.min.z).applyMatrix4(e), sa[7].set(this.max.x, this.max.y, this.max.z).applyMatrix4(e), this.setFromPoints(sa), this);
5956
+ return this.isEmpty() ? this : (ua[0].set(this.min.x, this.min.y, this.min.z).applyMatrix4(e), ua[1].set(this.min.x, this.min.y, this.max.z).applyMatrix4(e), ua[2].set(this.min.x, this.max.y, this.min.z).applyMatrix4(e), ua[3].set(this.min.x, this.max.y, this.max.z).applyMatrix4(e), ua[4].set(this.max.x, this.min.y, this.min.z).applyMatrix4(e), ua[5].set(this.max.x, this.min.y, this.max.z).applyMatrix4(e), ua[6].set(this.max.x, this.max.y, this.min.z).applyMatrix4(e), ua[7].set(this.max.x, this.max.y, this.max.z).applyMatrix4(e), this.setFromPoints(ua), this);
5809
5957
  }
5810
5958
  translate(e) {
5811
5959
  return this.min.add(e), this.max.add(e), this;
@@ -5822,28 +5970,28 @@ var oa = class {
5822
5970
  fromJSON(e) {
5823
5971
  return this.min.fromArray(e.min), this.max.fromArray(e.max), this;
5824
5972
  }
5825
- }, sa = [
5826
- /*@__PURE__*/ new G(),
5827
- /*@__PURE__*/ new G(),
5828
- /*@__PURE__*/ new G(),
5829
- /*@__PURE__*/ new G(),
5830
- /*@__PURE__*/ new G(),
5831
- /*@__PURE__*/ new G(),
5832
- /*@__PURE__*/ new G(),
5833
- /*@__PURE__*/ new G()
5834
- ], X = /*@__PURE__*/ new G(), ca = /*@__PURE__*/ new oa(), la = /*@__PURE__*/ new G(), ua = /*@__PURE__*/ new G(), da = /*@__PURE__*/ new G(), fa = /*@__PURE__*/ new G(), pa = /*@__PURE__*/ new G(), ma = /*@__PURE__*/ new G(), ha = /*@__PURE__*/ new G(), ga = /*@__PURE__*/ new G(), _a = /*@__PURE__*/ new G(), va = /*@__PURE__*/ new G();
5835
- function ya(e, t, n, r, i) {
5973
+ }, ua = [
5974
+ /*@__PURE__*/ new K(),
5975
+ /*@__PURE__*/ new K(),
5976
+ /*@__PURE__*/ new K(),
5977
+ /*@__PURE__*/ new K(),
5978
+ /*@__PURE__*/ new K(),
5979
+ /*@__PURE__*/ new K(),
5980
+ /*@__PURE__*/ new K(),
5981
+ /*@__PURE__*/ new K()
5982
+ ], da = /*@__PURE__*/ new K(), fa = /*@__PURE__*/ new la(), pa = /*@__PURE__*/ new K(), ma = /*@__PURE__*/ new K(), ha = /*@__PURE__*/ new K(), ga = /*@__PURE__*/ new K(), _a = /*@__PURE__*/ new K(), va = /*@__PURE__*/ new K(), ya = /*@__PURE__*/ new K(), ba = /*@__PURE__*/ new K(), xa = /*@__PURE__*/ new K(), Sa = /*@__PURE__*/ new K();
5983
+ function Ca(e, t, n, r, i) {
5836
5984
  for (let a = 0, o = e.length - 3; a <= o; a += 3) {
5837
- va.fromArray(e, a);
5838
- let o = i.x * Math.abs(va.x) + i.y * Math.abs(va.y) + i.z * Math.abs(va.z), s = t.dot(va), c = n.dot(va), l = r.dot(va);
5985
+ Sa.fromArray(e, a);
5986
+ let o = i.x * Math.abs(Sa.x) + i.y * Math.abs(Sa.y) + i.z * Math.abs(Sa.z), s = t.dot(Sa), c = n.dot(Sa), l = r.dot(Sa);
5839
5987
  if (Math.max(-Math.max(s, c, l), Math.min(s, c, l)) > o) return !1;
5840
5988
  }
5841
5989
  return !0;
5842
5990
  }
5843
- function ba(e, t) {
5991
+ function wa(e, t) {
5844
5992
  return !e || e.constructor === t ? e : typeof t.BYTES_PER_ELEMENT == "number" ? new t(e) : Array.prototype.slice.call(e);
5845
5993
  }
5846
- var xa = class {
5994
+ var Ta = class {
5847
5995
  constructor(e, t, n, r) {
5848
5996
  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_ = {};
5849
5997
  }
@@ -5901,29 +6049,29 @@ var xa = class {
5901
6049
  throw Error("call to abstract method");
5902
6050
  }
5903
6051
  intervalChanged_() {}
5904
- }, Sa = class extends xa {
6052
+ }, Ea = class extends Ta {
5905
6053
  constructor(e, t, n, r) {
5906
6054
  super(e, t, n, r), this._weightPrev = -0, this._offsetPrev = -0, this._weightNext = -0, this._offsetNext = -0, this.DefaultSettings_ = {
5907
- endingStart: Kr,
5908
- endingEnd: Kr
6055
+ endingStart: Yr,
6056
+ endingEnd: Yr
5909
6057
  };
5910
6058
  }
5911
6059
  intervalChanged_(e, t, n) {
5912
6060
  let r = this.parameterPositions, i = e - 2, a = e + 1, o = r[i], s = r[a];
5913
6061
  if (o === void 0) switch (this.getSettings_().endingStart) {
5914
- case qr:
6062
+ case Xr:
5915
6063
  i = e, o = 2 * t - n;
5916
6064
  break;
5917
- case Jr:
6065
+ case Zr:
5918
6066
  i = r.length - 2, o = t + r[i] - r[i + 1];
5919
6067
  break;
5920
6068
  default: i = e, o = n;
5921
6069
  }
5922
6070
  if (s === void 0) switch (this.getSettings_().endingEnd) {
5923
- case qr:
6071
+ case Xr:
5924
6072
  a = e, s = 2 * n - t;
5925
6073
  break;
5926
- case Jr:
6074
+ case Zr:
5927
6075
  a = 1, s = n + r[1] - r[0];
5928
6076
  break;
5929
6077
  default: a = e - 1, s = t;
@@ -5936,7 +6084,7 @@ var xa = class {
5936
6084
  for (let e = 0; e !== o; ++e) i[e] = g * a[l + e] + _ * a[c + e] + v * a[s + e] + y * a[u + e];
5937
6085
  return i;
5938
6086
  }
5939
- }, Ca = class extends xa {
6087
+ }, Da = class extends Ta {
5940
6088
  constructor(e, t, n, r) {
5941
6089
  super(e, t, n, r);
5942
6090
  }
@@ -5945,14 +6093,14 @@ var xa = class {
5945
6093
  for (let e = 0; e !== o; ++e) i[e] = a[c + e] * u + a[s + e] * l;
5946
6094
  return i;
5947
6095
  }
5948
- }, wa = class extends xa {
6096
+ }, Oa = class extends Ta {
5949
6097
  constructor(e, t, n, r) {
5950
6098
  super(e, t, n, r);
5951
6099
  }
5952
6100
  interpolate_(e) {
5953
6101
  return this.copySampleValue_(e - 1);
5954
6102
  }
5955
- }, Ta = class extends xa {
6103
+ }, ka = class extends Ta {
5956
6104
  interpolate_(e, t, n, r) {
5957
6105
  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;
5958
6106
  if (!u || !d) {
@@ -5975,11 +6123,11 @@ var xa = class {
5975
6123
  }
5976
6124
  return i;
5977
6125
  }
5978
- }, Ea = class {
6126
+ }, Aa = class {
5979
6127
  constructor(e, t, n, r) {
5980
6128
  if (e === void 0) throw Error("THREE.KeyframeTrack: track name is undefined");
5981
6129
  if (t === void 0 || t.length === 0) throw Error("THREE.KeyframeTrack: no keyframes in track named " + e);
5982
- this.name = e, this.times = ba(t, this.TimeBufferType), this.values = ba(n, this.ValueBufferType), this.setInterpolation(r || this.DefaultInterpolation);
6130
+ this.name = e, this.times = wa(t, this.TimeBufferType), this.values = wa(n, this.ValueBufferType), this.setInterpolation(r || this.DefaultInterpolation);
5983
6131
  }
5984
6132
  static toJSON(e) {
5985
6133
  let t = e.constructor, n;
@@ -5987,8 +6135,8 @@ var xa = class {
5987
6135
  else {
5988
6136
  n = {
5989
6137
  name: e.name,
5990
- times: ba(e.times, Array),
5991
- values: ba(e.values, Array)
6138
+ times: wa(e.times, Array),
6139
+ values: wa(e.values, Array)
5992
6140
  };
5993
6141
  let t = e.getInterpolation();
5994
6142
  t !== e.DefaultInterpolation && (n.interpolation = t);
@@ -5996,31 +6144,31 @@ var xa = class {
5996
6144
  return n.type = e.ValueTypeName, n;
5997
6145
  }
5998
6146
  InterpolantFactoryMethodDiscrete(e) {
5999
- return new wa(this.times, this.values, this.getValueSize(), e);
6147
+ return new Oa(this.times, this.values, this.getValueSize(), e);
6000
6148
  }
6001
6149
  InterpolantFactoryMethodLinear(e) {
6002
- return new Ca(this.times, this.values, this.getValueSize(), e);
6150
+ return new Da(this.times, this.values, this.getValueSize(), e);
6003
6151
  }
6004
6152
  InterpolantFactoryMethodSmooth(e) {
6005
- return new Sa(this.times, this.values, this.getValueSize(), e);
6153
+ return new Ea(this.times, this.values, this.getValueSize(), e);
6006
6154
  }
6007
6155
  InterpolantFactoryMethodBezier(e) {
6008
- let t = new Ta(this.times, this.values, this.getValueSize(), e);
6156
+ let t = new ka(this.times, this.values, this.getValueSize(), e);
6009
6157
  return this.settings && (t.settings = this.settings), t;
6010
6158
  }
6011
6159
  setInterpolation(e) {
6012
6160
  let t;
6013
6161
  switch (e) {
6014
- case Hr:
6162
+ case Gr:
6015
6163
  t = this.InterpolantFactoryMethodDiscrete;
6016
6164
  break;
6017
- case Ur:
6165
+ case Kr:
6018
6166
  t = this.InterpolantFactoryMethodLinear;
6019
6167
  break;
6020
- case Wr:
6168
+ case qr:
6021
6169
  t = this.InterpolantFactoryMethodSmooth;
6022
6170
  break;
6023
- case Gr:
6171
+ case Jr:
6024
6172
  t = this.InterpolantFactoryMethodBezier;
6025
6173
  break;
6026
6174
  }
@@ -6028,16 +6176,16 @@ var xa = class {
6028
6176
  let t = "unsupported interpolation for " + this.ValueTypeName + " keyframe track named " + this.name;
6029
6177
  if (this.createInterpolant === void 0) if (e !== this.DefaultInterpolation) this.setInterpolation(this.DefaultInterpolation);
6030
6178
  else throw Error(t);
6031
- return V("KeyframeTrack:", t), this;
6179
+ return H("KeyframeTrack:", t), this;
6032
6180
  }
6033
6181
  return this.createInterpolant = t, this;
6034
6182
  }
6035
6183
  getInterpolation() {
6036
6184
  switch (this.createInterpolant) {
6037
- case this.InterpolantFactoryMethodDiscrete: return Hr;
6038
- case this.InterpolantFactoryMethodLinear: return Ur;
6039
- case this.InterpolantFactoryMethodSmooth: return Wr;
6040
- case this.InterpolantFactoryMethodBezier: return Gr;
6185
+ case this.InterpolantFactoryMethodDiscrete: return Gr;
6186
+ case this.InterpolantFactoryMethodLinear: return Kr;
6187
+ case this.InterpolantFactoryMethodSmooth: return qr;
6188
+ case this.InterpolantFactoryMethodBezier: return Jr;
6041
6189
  }
6042
6190
  }
6043
6191
  getValueSize() {
@@ -6070,33 +6218,33 @@ var xa = class {
6070
6218
  }
6071
6219
  validate() {
6072
6220
  let e = !0, t = this.getValueSize();
6073
- t - Math.floor(t) !== 0 && (H("KeyframeTrack: Invalid value size in track.", this), e = !1);
6221
+ t - Math.floor(t) !== 0 && (U("KeyframeTrack: Invalid value size in track.", this), e = !1);
6074
6222
  let n = this.times, r = this.values, i = n.length;
6075
- i === 0 && (H("KeyframeTrack: Track is empty.", this), e = !1);
6223
+ i === 0 && (U("KeyframeTrack: Track is empty.", this), e = !1);
6076
6224
  let a = null;
6077
6225
  for (let t = 0; t !== i; t++) {
6078
6226
  let r = n[t];
6079
6227
  if (typeof r == "number" && isNaN(r)) {
6080
- H("KeyframeTrack: Time is not a valid number.", this, t, r), e = !1;
6228
+ U("KeyframeTrack: Time is not a valid number.", this, t, r), e = !1;
6081
6229
  break;
6082
6230
  }
6083
6231
  if (a !== null && a > r) {
6084
- H("KeyframeTrack: Out of order keys.", this, t, r, a), e = !1;
6232
+ U("KeyframeTrack: Out of order keys.", this, t, r, a), e = !1;
6085
6233
  break;
6086
6234
  }
6087
6235
  a = r;
6088
6236
  }
6089
- if (r !== void 0 && ei(r)) for (let t = 0, n = r.length; t !== n; ++t) {
6237
+ if (r !== void 0 && ri(r)) for (let t = 0, n = r.length; t !== n; ++t) {
6090
6238
  let n = r[t];
6091
6239
  if (isNaN(n)) {
6092
- H("KeyframeTrack: Value is not a valid number.", this, t, n), e = !1;
6240
+ U("KeyframeTrack: Value is not a valid number.", this, t, n), e = !1;
6093
6241
  break;
6094
6242
  }
6095
6243
  }
6096
6244
  return e;
6097
6245
  }
6098
6246
  optimize() {
6099
- let e = this.times.slice(), t = this.values.slice(), n = this.getValueSize(), r = this.getInterpolation() === Wr, i = e.length - 1, a = 1;
6247
+ let e = this.times.slice(), t = this.values.slice(), n = this.getValueSize(), r = this.getInterpolation() === qr, i = e.length - 1, a = 1;
6100
6248
  for (let o = 1; o < i; ++o) {
6101
6249
  let i = !1, s = e[o];
6102
6250
  if (s !== e[o + 1] && (o !== 1 || s !== e[0])) if (r) i = !0;
@@ -6131,56 +6279,56 @@ var xa = class {
6131
6279
  return r.createInterpolant = this.createInterpolant, r;
6132
6280
  }
6133
6281
  };
6134
- Ea.prototype.ValueTypeName = "", Ea.prototype.TimeBufferType = Float32Array, Ea.prototype.ValueBufferType = Float32Array, Ea.prototype.DefaultInterpolation = Ur;
6135
- var Da = class extends Ea {
6282
+ Aa.prototype.ValueTypeName = "", Aa.prototype.TimeBufferType = Float32Array, Aa.prototype.ValueBufferType = Float32Array, Aa.prototype.DefaultInterpolation = Kr;
6283
+ var ja = class extends Aa {
6136
6284
  constructor(e, t, n) {
6137
6285
  super(e, t, n);
6138
6286
  }
6139
6287
  };
6140
- Da.prototype.ValueTypeName = "bool", Da.prototype.ValueBufferType = Array, Da.prototype.DefaultInterpolation = Hr, Da.prototype.InterpolantFactoryMethodLinear = void 0, Da.prototype.InterpolantFactoryMethodSmooth = void 0;
6141
- var Oa = class extends Ea {
6288
+ ja.prototype.ValueTypeName = "bool", ja.prototype.ValueBufferType = Array, ja.prototype.DefaultInterpolation = Gr, ja.prototype.InterpolantFactoryMethodLinear = void 0, ja.prototype.InterpolantFactoryMethodSmooth = void 0;
6289
+ var Ma = class extends Aa {
6142
6290
  constructor(e, t, n, r) {
6143
6291
  super(e, t, n, r);
6144
6292
  }
6145
6293
  };
6146
- Oa.prototype.ValueTypeName = "color";
6147
- var ka = class extends Ea {
6294
+ Ma.prototype.ValueTypeName = "color";
6295
+ var Na = class extends Aa {
6148
6296
  constructor(e, t, n, r) {
6149
6297
  super(e, t, n, r);
6150
6298
  }
6151
6299
  };
6152
- ka.prototype.ValueTypeName = "number";
6153
- var Aa = class extends xa {
6300
+ Na.prototype.ValueTypeName = "number";
6301
+ var Pa = class extends Ta {
6154
6302
  constructor(e, t, n, r) {
6155
6303
  super(e, t, n, r);
6156
6304
  }
6157
6305
  interpolate_(e, t, n, r) {
6158
6306
  let i = this.resultBuffer, a = this.sampleValues, o = this.valueSize, s = (n - t) / (r - t), c = e * o;
6159
- for (let e = c + o; c !== e; c += 4) di.slerpFlat(i, 0, a, c - o, a, c, s);
6307
+ for (let e = c + o; c !== e; c += 4) mi.slerpFlat(i, 0, a, c - o, a, c, s);
6160
6308
  return i;
6161
6309
  }
6162
- }, ja = class extends Ea {
6310
+ }, Fa = class extends Aa {
6163
6311
  constructor(e, t, n, r) {
6164
6312
  super(e, t, n, r);
6165
6313
  }
6166
6314
  InterpolantFactoryMethodLinear(e) {
6167
- return new Aa(this.times, this.values, this.getValueSize(), e);
6315
+ return new Pa(this.times, this.values, this.getValueSize(), e);
6168
6316
  }
6169
6317
  };
6170
- ja.prototype.ValueTypeName = "quaternion", ja.prototype.InterpolantFactoryMethodSmooth = void 0;
6171
- var Ma = class extends Ea {
6318
+ Fa.prototype.ValueTypeName = "quaternion", Fa.prototype.InterpolantFactoryMethodSmooth = void 0;
6319
+ var Ia = class extends Aa {
6172
6320
  constructor(e, t, n) {
6173
6321
  super(e, t, n);
6174
6322
  }
6175
6323
  };
6176
- Ma.prototype.ValueTypeName = "string", Ma.prototype.ValueBufferType = Array, Ma.prototype.DefaultInterpolation = Hr, Ma.prototype.InterpolantFactoryMethodLinear = void 0, Ma.prototype.InterpolantFactoryMethodSmooth = void 0;
6177
- var Na = class extends Ea {
6324
+ Ia.prototype.ValueTypeName = "string", Ia.prototype.ValueBufferType = Array, Ia.prototype.DefaultInterpolation = Gr, Ia.prototype.InterpolantFactoryMethodLinear = void 0, Ia.prototype.InterpolantFactoryMethodSmooth = void 0;
6325
+ var La = class extends Aa {
6178
6326
  constructor(e, t, n, r) {
6179
6327
  super(e, t, n, r);
6180
6328
  }
6181
6329
  };
6182
- Na.prototype.ValueTypeName = "vector";
6183
- var Pa = /*@__PURE__*/ new class {
6330
+ La.prototype.ValueTypeName = "vector";
6331
+ var Ra = /*@__PURE__*/ new class {
6184
6332
  constructor(e, t, n) {
6185
6333
  let r = this, i = !1, a = 0, o = 0, s, c = [];
6186
6334
  this.onStart = void 0, this.onLoad = e, this.onProgress = t, this.onError = n, this._abortController = null, this.itemStart = function(e) {
@@ -6211,9 +6359,9 @@ var Pa = /*@__PURE__*/ new class {
6211
6359
  get abortController() {
6212
6360
  return this._abortController ||= new AbortController(), this._abortController;
6213
6361
  }
6214
- }(), Fa = class {
6362
+ }(), za = class {
6215
6363
  constructor(e) {
6216
- this.manager = e === void 0 ? Pa : 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 }));
6364
+ this.manager = e === void 0 ? Ra : 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 }));
6217
6365
  }
6218
6366
  load() {}
6219
6367
  loadAsync(e, t) {
@@ -6242,13 +6390,13 @@ var Pa = /*@__PURE__*/ new class {
6242
6390
  return this;
6243
6391
  }
6244
6392
  };
6245
- Fa.DEFAULT_MATERIAL_NAME = "__DEFAULT";
6246
- var Ia = "\\[\\]\\.:\\/", La = /* @__PURE__ */ RegExp("[\\[\\]\\.:\\/]", "g"), Ra = "[^\\[\\]\\.:\\/]", za = "[^" + Ia.replace("\\.", "") + "]", Ba = /*@__PURE__*/ "((?:WC+[\\/:])*)".replace("WC", Ra), Va = /*@__PURE__*/ "(WCOD+)?".replace("WCOD", za), Ha = /*@__PURE__*/ "(?:\\.(WC+)(?:\\[(.+)\\])?)?".replace("WC", Ra), Ua = /*@__PURE__*/ "\\.(WC+)(?:\\[(.+)\\])?".replace("WC", Ra), Wa = RegExp("^" + Ba + Va + Ha + Ua + "$"), Ga = [
6393
+ za.DEFAULT_MATERIAL_NAME = "__DEFAULT";
6394
+ var Ba = "\\[\\]\\.:\\/", Va = /* @__PURE__ */ RegExp("[\\[\\]\\.:\\/]", "g"), Ha = "[^\\[\\]\\.:\\/]", Ua = "[^" + Ba.replace("\\.", "") + "]", Wa = /*@__PURE__*/ "((?:WC+[\\/:])*)".replace("WC", Ha), Ga = /*@__PURE__*/ "(WCOD+)?".replace("WCOD", Ua), Ka = /*@__PURE__*/ "(?:\\.(WC+)(?:\\[(.+)\\])?)?".replace("WC", Ha), qa = /*@__PURE__*/ "\\.(WC+)(?:\\[(.+)\\])?".replace("WC", Ha), Ja = RegExp("^" + Wa + Ga + Ka + qa + "$"), Ya = [
6247
6395
  "material",
6248
6396
  "materials",
6249
6397
  "bones",
6250
6398
  "map"
6251
- ], Ka = class {
6399
+ ], Xa = class {
6252
6400
  constructor(e, t, n) {
6253
6401
  let r = n || Z.parseTrackName(t);
6254
6402
  this._targetGroup = e, this._bindings = e.subscribe_(t, r);
@@ -6278,10 +6426,10 @@ var Ia = "\\[\\]\\.:\\/", La = /* @__PURE__ */ RegExp("[\\[\\]\\.:\\/]", "g"), R
6278
6426
  return t && t.isAnimationObjectGroup ? new e.Composite(t, n, r) : new e(t, n, r);
6279
6427
  }
6280
6428
  static sanitizeNodeName(e) {
6281
- return e.replace(/\s/g, "_").replace(La, "");
6429
+ return e.replace(/\s/g, "_").replace(Va, "");
6282
6430
  }
6283
6431
  static parseTrackName(e) {
6284
- let t = Wa.exec(e);
6432
+ let t = Ja.exec(e);
6285
6433
  if (t === null) throw Error("PropertyBinding: Cannot parse trackName: " + e);
6286
6434
  let n = {
6287
6435
  nodeName: t[2],
@@ -6292,7 +6440,7 @@ var Ia = "\\[\\]\\.:\\/", La = /* @__PURE__ */ RegExp("[\\[\\]\\.:\\/]", "g"), R
6292
6440
  }, r = n.nodeName && n.nodeName.lastIndexOf(".");
6293
6441
  if (r !== void 0 && r !== -1) {
6294
6442
  let e = n.nodeName.substring(r + 1);
6295
- Ga.indexOf(e) !== -1 && (n.nodeName = n.nodeName.substring(0, r), n.objectName = e);
6443
+ Ya.indexOf(e) !== -1 && (n.nodeName = n.nodeName.substring(0, r), n.objectName = e);
6296
6444
  }
6297
6445
  if (n.propertyName === null || n.propertyName.length === 0) throw Error("PropertyBinding: can not parse propertyName from trackName: " + e);
6298
6446
  return n;
@@ -6382,7 +6530,7 @@ var Ia = "\\[\\]\\.:\\/", La = /* @__PURE__ */ RegExp("[\\[\\]\\.:\\/]", "g"), R
6382
6530
  bind() {
6383
6531
  let t = this.node, n = this.parsedPath, r = n.objectName, i = n.propertyName, a = n.propertyIndex;
6384
6532
  if (t || (t = e.findNode(this.rootNode, n.nodeName), this.node = t), this.getValue = this._getValue_unavailable, this.setValue = this._setValue_unavailable, !t) {
6385
- V("PropertyBinding: No target node found for track: " + this.path + ".");
6533
+ H("PropertyBinding: No target node found for track: " + this.path + ".");
6386
6534
  return;
6387
6535
  }
6388
6536
  if (r) {
@@ -6390,18 +6538,18 @@ var Ia = "\\[\\]\\.:\\/", La = /* @__PURE__ */ RegExp("[\\[\\]\\.:\\/]", "g"), R
6390
6538
  switch (r) {
6391
6539
  case "materials":
6392
6540
  if (!t.material) {
6393
- H("PropertyBinding: Can not bind to material as node does not have a material.", this);
6541
+ U("PropertyBinding: Can not bind to material as node does not have a material.", this);
6394
6542
  return;
6395
6543
  }
6396
6544
  if (!t.material.materials) {
6397
- H("PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.", this);
6545
+ U("PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.", this);
6398
6546
  return;
6399
6547
  }
6400
6548
  t = t.material.materials;
6401
6549
  break;
6402
6550
  case "bones":
6403
6551
  if (!t.skeleton) {
6404
- H("PropertyBinding: Can not bind to bones as node does not have a skeleton.", this);
6552
+ U("PropertyBinding: Can not bind to bones as node does not have a skeleton.", this);
6405
6553
  return;
6406
6554
  }
6407
6555
  t = t.skeleton.bones;
@@ -6416,25 +6564,25 @@ var Ia = "\\[\\]\\.:\\/", La = /* @__PURE__ */ RegExp("[\\[\\]\\.:\\/]", "g"), R
6416
6564
  break;
6417
6565
  }
6418
6566
  if (!t.material) {
6419
- H("PropertyBinding: Can not bind to material as node does not have a material.", this);
6567
+ U("PropertyBinding: Can not bind to material as node does not have a material.", this);
6420
6568
  return;
6421
6569
  }
6422
6570
  if (!t.material.map) {
6423
- H("PropertyBinding: Can not bind to material.map as node.material does not have a map.", this);
6571
+ U("PropertyBinding: Can not bind to material.map as node.material does not have a map.", this);
6424
6572
  return;
6425
6573
  }
6426
6574
  t = t.material.map;
6427
6575
  break;
6428
6576
  default:
6429
6577
  if (t[r] === void 0) {
6430
- H("PropertyBinding: Can not bind to objectName of node undefined.", this);
6578
+ U("PropertyBinding: Can not bind to objectName of node undefined.", this);
6431
6579
  return;
6432
6580
  }
6433
6581
  t = t[r];
6434
6582
  }
6435
6583
  if (e !== void 0) {
6436
6584
  if (t[e] === void 0) {
6437
- H("PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.", this, t);
6585
+ U("PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.", this, t);
6438
6586
  return;
6439
6587
  }
6440
6588
  t = t[e];
@@ -6443,7 +6591,7 @@ var Ia = "\\[\\]\\.:\\/", La = /* @__PURE__ */ RegExp("[\\[\\]\\.:\\/]", "g"), R
6443
6591
  let o = t[i];
6444
6592
  if (o === void 0) {
6445
6593
  let e = n.nodeName;
6446
- H("PropertyBinding: Trying to update property for track: " + e + "." + i + " but it wasn't found.", t);
6594
+ U("PropertyBinding: Trying to update property for track: " + e + "." + i + " but it wasn't found.", t);
6447
6595
  return;
6448
6596
  }
6449
6597
  let s = this.Versioning.None;
@@ -6452,11 +6600,11 @@ var Ia = "\\[\\]\\.:\\/", La = /* @__PURE__ */ RegExp("[\\[\\]\\.:\\/]", "g"), R
6452
6600
  if (a !== void 0) {
6453
6601
  if (i === "morphTargetInfluences") {
6454
6602
  if (!t.geometry) {
6455
- H("PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.", this);
6603
+ U("PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.", this);
6456
6604
  return;
6457
6605
  }
6458
6606
  if (!t.geometry.morphAttributes) {
6459
- H("PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.", this);
6607
+ U("PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.", this);
6460
6608
  return;
6461
6609
  }
6462
6610
  t.morphTargetDictionary[a] !== void 0 && (a = t.morphTargetDictionary[a]);
@@ -6469,7 +6617,7 @@ var Ia = "\\[\\]\\.:\\/", La = /* @__PURE__ */ RegExp("[\\[\\]\\.:\\/]", "g"), R
6469
6617
  this.node = null, this.getValue = this._getValue_unbound, this.setValue = this._setValue_unbound;
6470
6618
  }
6471
6619
  };
6472
- Z.Composite = Ka, Z.prototype.BindingType = {
6620
+ Z.Composite = Xa, Z.prototype.BindingType = {
6473
6621
  Direct: 0,
6474
6622
  EntireArray: 1,
6475
6623
  ArrayElement: 2,
@@ -6527,37 +6675,37 @@ Z.Composite = Ka, Z.prototype.BindingType = {
6527
6675
  let i = this.elements;
6528
6676
  return i[0] = e, i[2] = t, i[1] = n, i[3] = r, this;
6529
6677
  }
6530
- }, typeof __THREE_DEVTOOLS__ < "u" && __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("register", { detail: { revision: "184" } })), typeof window < "u" && (window.__THREE__ ? V("WARNING: Multiple instances of Three.js being imported.") : window.__THREE__ = "184");
6678
+ }, 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");
6531
6679
  //#endregion
6532
6680
  //#region src/model-preview.ts
6533
- var qa = 2.4, Ja = 1.35, Ya = [
6681
+ var Za = 2.4, Qa = 1.35, $a = [
6534
6682
  0,
6535
6683
  .5,
6536
6684
  0
6537
- ], Xa = 60 * Math.PI / 180, Za = 1;
6538
- function Qa(e) {
6539
- return Math.abs(e.height - Za) < Za * .25;
6685
+ ], eo = 60 * Math.PI / 180, to = 1;
6686
+ function no(e) {
6687
+ return Math.abs(e.height - to) < to * .25;
6540
6688
  }
6541
- function $a(e, t, n = 1.25) {
6689
+ function ro(e, t, n = 1.25) {
6542
6690
  let r = e.scene?.root.getNodesByName(t)[0];
6543
6691
  if (!r) return null;
6544
6692
  let i = r._ensureObject3D();
6545
6693
  i.updateWorldMatrix(!0, !0);
6546
- let a = new oa().setFromObject(i, !0);
6694
+ let a = new la().setFromObject(i, !0);
6547
6695
  if (a.isEmpty()) return null;
6548
- let o = a.getSize(new G()), s = a.getCenter(new G()), c = Math.max(o.x, o.y, o.z);
6696
+ let o = a.getSize(new K()), s = a.getCenter(new K()), c = Math.max(o.x, o.y, o.z);
6549
6697
  return !Number.isFinite(c) || c <= 0 ? null : {
6550
6698
  target: [
6551
6699
  s.x,
6552
6700
  s.y,
6553
6701
  s.z
6554
6702
  ],
6555
- distance: c / 2 / Math.tan(Xa / 2) * n,
6703
+ distance: c / 2 / Math.tan(eo / 2) * n,
6556
6704
  height: o.y
6557
6705
  };
6558
6706
  }
6559
- var eo = "https://agent8-games.verse8.io/assets/3d/characters/realistic style/base-model.glb";
6560
- function to(e) {
6707
+ var io = "https://agent8-games.verse8.io/assets/3d/characters/realistic style/base-model.glb";
6708
+ function ao(e) {
6561
6709
  let t = { model: {
6562
6710
  type: "model",
6563
6711
  url: e.model
@@ -6592,8 +6740,8 @@ function to(e) {
6592
6740
  current: !0,
6593
6741
  position: [
6594
6742
  0,
6595
- Ja,
6596
- qa
6743
+ Qa,
6744
+ Za
6597
6745
  ]
6598
6746
  }
6599
6747
  },
@@ -6622,7 +6770,7 @@ function to(e) {
6622
6770
  }
6623
6771
  };
6624
6772
  }
6625
- var no = (e, t) => e !== null && e.model === t.model && e.clip === t.clip, ro = class {
6773
+ var oo = (e, t) => e !== null && e.model === t.model && e.clip === t.clip, so = class {
6626
6774
  canvas = null;
6627
6775
  engine = null;
6628
6776
  renderer = null;
@@ -6639,7 +6787,7 @@ var no = (e, t) => e !== null && e.model === t.model && e.clip === t.clip, ro =
6639
6787
  let t = document.createElement("div");
6640
6788
  t.className = "lib-preview3d";
6641
6789
  let n = this.ensure();
6642
- return t.appendChild(n), no(this.subject, e) || (this.subject = e, this.aimed = e.clip !== void 0, this.framing = null, this.locked = !1, this.measureUntil = performance.now() + 4e3, this.load(e)), this.start(), t;
6790
+ return t.appendChild(n), oo(this.subject, e) || (this.subject = e, this.aimed = e.clip !== void 0, this.framing = null, this.locked = !1, this.measureUntil = performance.now() + 4e3, this.load(e)), this.start(), t;
6643
6791
  }
6644
6792
  detach() {
6645
6793
  this.stop(), this.canvas?.remove();
@@ -6665,7 +6813,7 @@ var no = (e, t) => e !== null && e.model === t.model && e.clip === t.clip, ro =
6665
6813
  }
6666
6814
  load(e) {
6667
6815
  if (this.engine) try {
6668
- this.engine.setScene(f(to(e)));
6816
+ this.engine.setScene(f(ao(e)));
6669
6817
  } catch (t) {
6670
6818
  console.warn("[incanto] library preview could not load", e, t);
6671
6819
  }
@@ -6679,17 +6827,17 @@ var no = (e, t) => e !== null && e.model === t.model && e.clip === t.clip, ro =
6679
6827
  let i = this.renderer;
6680
6828
  if (!i) return;
6681
6829
  if (this.engine && !this.locked) {
6682
- let e = $a(this.engine, "Model");
6683
- e && (this.framing = e, Qa(e) && (this.locked = !0)), this.framing && n > this.measureUntil && (this.locked = !0);
6830
+ let e = ro(this.engine, "Model");
6831
+ e && (this.framing = e, no(e) && (this.locked = !0)), this.framing && n > this.measureUntil && (this.locked = !0);
6684
6832
  }
6685
- let a = this.framing, o = a ? a.distance : qa, s = a ? a.target[1] + o * .25 : Ja;
6833
+ let a = this.framing, o = a ? a.distance : Za, s = a ? a.target[1] + o * .25 : Qa;
6686
6834
  i.viewOverride = {
6687
6835
  position: [
6688
6836
  (a?.target[0] ?? 0) + Math.sin(this.angle) * o,
6689
6837
  s,
6690
6838
  (a?.target[2] ?? 0) + Math.cos(this.angle) * o
6691
6839
  ],
6692
- target: a ? a.target : Ya
6840
+ target: a ? a.target : $a
6693
6841
  }, this.engine?.tick(n);
6694
6842
  };
6695
6843
  this.raf = requestAnimationFrame(t);
@@ -6697,11 +6845,11 @@ var no = (e, t) => e !== null && e.model === t.model && e.clip === t.clip, ro =
6697
6845
  stop() {
6698
6846
  this.raf && cancelAnimationFrame(this.raf), this.raf = 0;
6699
6847
  }
6700
- }, io = 192, ao = .9, oo = 1.05, so = .88, co = [
6848
+ }, co = 192, lo = .9, uo = 1.05, fo = .88, po = [
6701
6849
  0,
6702
6850
  .5,
6703
6851
  0
6704
- ], lo = 3, uo = 30, fo = 3e4, po = 12, mo = 20, ho = 60, go = (e) => `${e.model}|${e.clip ?? ""}`, _o = class {
6852
+ ], mo = 3, ho = 30, go = 3e4, _o = 12, vo = 20, yo = 60, bo = (e) => `${e.model}|${e.clip ?? ""}`, xo = class {
6705
6853
  jobs = /* @__PURE__ */ new Map();
6706
6854
  queue = [];
6707
6855
  running = !1;
@@ -6713,7 +6861,7 @@ var no = (e, t) => e !== null && e.model === t.model && e.clip === t.clip, ro =
6713
6861
  disposed = !1;
6714
6862
  pace = 0;
6715
6863
  get(e) {
6716
- let t = go(e), n = this.jobs.get(t);
6864
+ let t = bo(e), n = this.jobs.get(t);
6717
6865
  if (n) return n;
6718
6866
  let r = new Promise((n) => {
6719
6867
  this.queue.push({
@@ -6745,40 +6893,40 @@ var no = (e, t) => e !== null && e.model === t.model && e.clip === t.clip, ro =
6745
6893
  async draw(e) {
6746
6894
  if (this.disposed) return null;
6747
6895
  let { engine: t, renderer: n, canvas: r } = this.ensure();
6748
- (!this.held.has(e.model) && this.held.size >= po || this.clipsHeld >= ho) && (n.assets.dispose(), this.held.clear(), this.clipsHeld = 0), this.held.add(e.model), e.clip && (this.clipsHeld += 1);
6896
+ (!this.held.has(e.model) && this.held.size >= _o || this.clipsHeld >= yo) && (n.assets.dispose(), this.held.clear(), this.clipsHeld = 0), this.held.add(e.model), e.clip && (this.clipsHeld += 1);
6749
6897
  try {
6750
- t.setScene(f(to(e)));
6898
+ t.setScene(f(ao(e)));
6751
6899
  } catch {
6752
6900
  return null;
6753
6901
  }
6754
6902
  let i = !1, a = () => {
6755
- let e = $a(t, "Model", 1.15);
6756
- e && (i = Qa(e));
6757
- let r = e ? e.distance : oo;
6903
+ let e = ro(t, "Model", 1.15);
6904
+ e && (i = no(e));
6905
+ let r = e ? e.distance : uo;
6758
6906
  n.viewOverride = {
6759
6907
  position: [
6760
- (e?.target[0] ?? 0) + Math.sin(ao) * r,
6761
- e ? e.target[1] + r * .25 : so,
6762
- (e?.target[2] ?? 0) + Math.cos(ao) * r
6908
+ (e?.target[0] ?? 0) + Math.sin(lo) * r,
6909
+ e ? e.target[1] + r * .25 : fo,
6910
+ (e?.target[2] ?? 0) + Math.cos(lo) * r
6763
6911
  ],
6764
- target: e ? e.target : co
6912
+ target: e ? e.target : po
6765
6913
  };
6766
6914
  };
6767
6915
  a();
6768
- let o = Date.now() + fo;
6916
+ let o = Date.now() + go;
6769
6917
  for (; !this.disposed;) {
6770
- t.tick(await vo());
6918
+ t.tick(await So());
6771
6919
  let r = n.assets.getModel(e.model), i = e.clip ? n.assets.getAnimation(e.clip) : null;
6772
6920
  if (r.status === "error" || i?.status === "error") return null;
6773
6921
  if (r.status === "ready" && (!i || i.status === "ready")) break;
6774
6922
  if (Date.now() > o) return null;
6775
6923
  }
6776
- let s = e.clip ? uo : lo;
6777
- for (let e = 0; e < s && !this.disposed; e++) t.tick(await vo());
6924
+ let s = e.clip ? ho : mo;
6925
+ for (let e = 0; e < s && !this.disposed; e++) t.tick(await So());
6778
6926
  if (this.disposed) return null;
6779
6927
  a();
6780
- for (let e = 0; e < mo && !i && !this.disposed; e++) t.tick(await vo()), a();
6781
- return this.disposed || (t.tick(await vo()), this.disposed) ? null : r.toDataURL("image/webp", .85);
6928
+ for (let e = 0; e < vo && !i && !this.disposed; e++) t.tick(await So()), a();
6929
+ return this.disposed || (t.tick(await So()), this.disposed) ? null : r.toDataURL("image/webp", .85);
6782
6930
  }
6783
6931
  ensure() {
6784
6932
  if (this.canvas && this.engine && this.renderer) return {
@@ -6787,7 +6935,7 @@ var no = (e, t) => e !== null && e.model === t.model && e.clip === t.clip, ro =
6787
6935
  renderer: this.renderer
6788
6936
  };
6789
6937
  let e = document.createElement("canvas");
6790
- e.width = io, e.height = io;
6938
+ e.width = co, e.height = co;
6791
6939
  let n = new t({ scheduler: () => () => {} }), r = new D({
6792
6940
  canvas: e,
6793
6941
  engine: n,
@@ -6801,8 +6949,8 @@ var no = (e, t) => e !== null && e.model === t.model && e.clip === t.clip, ro =
6801
6949
  renderer: r
6802
6950
  };
6803
6951
  }
6804
- }, vo = () => new Promise((e) => requestAnimationFrame(e)), yo = "incanto-editor-v8-token", bo = 24;
6805
- async function xo(e, t, n) {
6952
+ }, So = () => new Promise((e) => requestAnimationFrame(e)), Co = "incanto-editor-v8-token", wo = 24;
6953
+ async function To(e, t, n) {
6806
6954
  if (!Oe(e.url) || n !== "spritesheet" && n !== "texture") return null;
6807
6955
  try {
6808
6956
  let n = x(await (await fetch(e.url)).json(), {
@@ -6817,7 +6965,7 @@ async function xo(e, t, n) {
6817
6965
  return console.warn("[incanto] not a usable sprite config:", e.url, t), null;
6818
6966
  }
6819
6967
  }
6820
- async function So(e, t) {
6968
+ async function Eo(e, t) {
6821
6969
  let n = async (t) => {
6822
6970
  let n = await fetch(t, {
6823
6971
  method: "POST",
@@ -6846,20 +6994,20 @@ async function So(e, t) {
6846
6994
  }
6847
6995
  throw Error("sign-in timed out — try again");
6848
6996
  }
6849
- function Co() {
6997
+ function Do() {
6850
6998
  try {
6851
- return localStorage.getItem(yo) ?? "";
6999
+ return localStorage.getItem(Co) ?? "";
6852
7000
  } catch {
6853
7001
  return "";
6854
7002
  }
6855
7003
  }
6856
- var wo = eo;
6857
- function To(e) {
7004
+ var Oo = io;
7005
+ function ko(e) {
6858
7006
  try {
6859
- e ? localStorage.setItem(yo, e) : localStorage.removeItem(yo);
7007
+ e ? localStorage.setItem(Co, e) : localStorage.removeItem(Co);
6860
7008
  } catch {}
6861
7009
  }
6862
- function Eo(e, t) {
7010
+ function Ao(e, t) {
6863
7011
  return new Promise((n) => {
6864
7012
  let r = [...t.shelf ?? []], i = "", a = 1, o = !1, s = [], c = [], l = null, u = !1, d = !1, f = document.createElement("div");
6865
7013
  f.className = "lib-backdrop";
@@ -6895,8 +7043,8 @@ function Eo(e, t) {
6895
7043
  E.className = "lib-sentinel", E.setAttribute("aria-hidden", "true"), S.append(w, C, T);
6896
7044
  let D = document.createElement("aside");
6897
7045
  D.className = "lib-detail", b.append(x, S, D);
6898
- let O = new ro(), k = (e) => {
6899
- d || (d = !0, O.dispose(), ie.dispose(), ce?.disconnect(), document.removeEventListener("keydown", A, !0), f.remove(), n(e));
7046
+ let O = new so(), k = (e) => {
7047
+ d || (d = !0, O.dispose(), ae.dispose(), ce?.disconnect(), document.removeEventListener("keydown", A, !0), f.remove(), n(e));
6900
7048
  }, A = (e) => {
6901
7049
  e.key === "Escape" && (e.stopPropagation(), k(null));
6902
7050
  };
@@ -6945,43 +7093,43 @@ function Eo(e, t) {
6945
7093
  tags: t,
6946
7094
  page: 1,
6947
7095
  limit: 1
6948
- }, Co() || void 0), i = r.total ?? r.items.length;
7096
+ }, Do() || void 0), i = r.total ?? r.items.length;
6949
7097
  if (j.set(n, i), d) return;
6950
7098
  te();
6951
7099
  } catch {
6952
7100
  j.delete(n);
6953
7101
  }
6954
7102
  }
6955
- }, M = (e) => ye(e) ? {
6956
- model: N,
7103
+ }, re = (e) => ye(e) ? {
7104
+ model: M,
6957
7105
  clip: e.url
6958
- } : { model: e.url }, N = wo, re = () => {
7106
+ } : { model: e.url }, M = Oo, ie = () => {
6959
7107
  let e = document.createElement("div");
6960
7108
  e.className = "lib-charpick";
6961
7109
  let t = document.createElement("label");
6962
7110
  t.className = "lib-charpick-label", t.textContent = "playing on";
6963
7111
  let n = document.createElement("input");
6964
- n.type = "text", n.value = N, n.spellcheck = !1, n.placeholder = "a character GLB url", n.title = N;
7112
+ n.type = "text", n.value = M, n.spellcheck = !1, n.placeholder = "a character GLB url", n.title = M;
6965
7113
  let r = document.createElement("button");
6966
7114
  r.type = "button", r.className = "ghost", r.textContent = "apply";
6967
7115
  let i = document.createElement("button");
6968
7116
  i.type = "button", i.className = "ghost", i.textContent = "base", i.title = "back to the base character";
6969
7117
  let a = (e) => {
6970
7118
  let t = e.trim();
6971
- if (!(!t || t === N)) {
6972
- N = t, wo = t, ie.cancelPending();
6973
- for (let e of s) ye(e) && ae.delete(e.url);
6974
- P(), F();
7119
+ if (!(!t || t === M)) {
7120
+ M = t, Oo = t, ae.cancelPending();
7121
+ for (let e of s) ye(e) && P.delete(e.url);
7122
+ N(), F();
6975
7123
  }
6976
7124
  };
6977
7125
  return r.addEventListener("click", () => a(n.value)), n.addEventListener("keydown", (e) => {
6978
7126
  e.key === "Enter" && (e.preventDefault(), a(n.value));
6979
7127
  }), i.addEventListener("click", () => {
6980
- n.value = eo, a(eo);
7128
+ n.value = io, a(io);
6981
7129
  }), e.append(t, n, r, i), e;
6982
- }, P = () => {
7130
+ }, N = () => {
6983
7131
  if (D.textContent = "", O.detach(), !l) {
6984
- ie.setPace(0);
7132
+ ae.setPace(0);
6985
7133
  let e = document.createElement("div");
6986
7134
  e.className = "lib-empty", e.textContent = "pick an asset to preview it", D.appendChild(e);
6987
7135
  return;
@@ -6995,12 +7143,12 @@ function Eo(e, t) {
6995
7143
  } else if (r === "audio") {
6996
7144
  let t = document.createElement("audio");
6997
7145
  t.controls = !0, t.src = e.url, n.appendChild(t);
6998
- } else if (r === "model") n.appendChild(O.mount(M(e))), ie.setPace(ye(e) ? 300 : 0);
7146
+ } else if (r === "model") n.appendChild(O.mount(re(e))), ae.setPace(ye(e) ? 300 : 0);
6999
7147
  else {
7000
7148
  let t = document.createElement("div");
7001
7149
  t.className = "lib-empty", t.textContent = `no preview for ${me(e.url) || "this file"}`, n.appendChild(t);
7002
7150
  }
7003
- if (D.appendChild(n), ye(e) && D.appendChild(re()), Oe(e.url)) {
7151
+ if (D.appendChild(n), ye(e) && D.appendChild(ie()), Oe(e.url)) {
7004
7152
  let e = document.createElement("p");
7005
7153
  e.className = "lib-desc lib-note", e.textContent = "Sprite config — picking it declares the sheet AND wires its named animations onto the node.", D.appendChild(e);
7006
7154
  }
@@ -7056,24 +7204,24 @@ function Eo(e, t) {
7056
7204
  return;
7057
7205
  }
7058
7206
  (async () => {
7059
- let n = Se(e), r = await xo(e, n, t.assetType), i = r?.asset ?? De(e, t.kind, t.assetType), a = t.onAsset?.(e, i, n) ?? e.url;
7207
+ let n = Se(e), r = await To(e, n, t.assetType), i = r?.asset ?? De(e, t.kind, t.assetType), a = t.onAsset?.(e, i, n) ?? e.url;
7060
7208
  r && t.onProps?.(r.props), k(a);
7061
7209
  })();
7062
7210
  }), d.appendChild(p), D.appendChild(d);
7063
- }, ie = new _o(), ae = /* @__PURE__ */ new Map(), oe = (e, t) => {
7211
+ }, ae = new xo(), P = /* @__PURE__ */ new Map(), oe = (e, t) => {
7064
7212
  e.textContent = "";
7065
7213
  let n = document.createElement("img");
7066
7214
  n.src = t, n.alt = "", e.appendChild(n);
7067
7215
  }, se = (e) => {
7068
7216
  let t = e.dataset.model;
7069
- if (!t || ae.has(t)) return;
7217
+ if (!t || P.has(t)) return;
7070
7218
  let n = s.find((e) => e.url === t);
7071
- ae.set(t, null), ie.get(n ? M(n) : { model: t }).then((e) => {
7219
+ P.set(t, null), ae.get(n ? re(n) : { model: t }).then((e) => {
7072
7220
  if (!e) {
7073
- ae.delete(t);
7221
+ P.delete(t);
7074
7222
  return;
7075
7223
  }
7076
- if (ae.set(t, e), !d) for (let n of C.querySelectorAll(`[data-model="${CSS.escape(t)}"]`)) oe(n, e);
7224
+ if (P.set(t, e), !d) for (let n of C.querySelectorAll(`[data-model="${CSS.escape(t)}"]`)) oe(n, e);
7077
7225
  });
7078
7226
  }, ce = typeof IntersectionObserver > "u" ? null : new IntersectionObserver((e) => {
7079
7227
  for (let t of e) t.isIntersecting && (ce?.unobserve(t.target), se(t.target));
@@ -7097,11 +7245,11 @@ function Eo(e, t) {
7097
7245
  let e = document.createElement("img");
7098
7246
  e.src = o ? ke(n.url) : n.url, e.alt = "", e.loading = "lazy", i.appendChild(e);
7099
7247
  } else if (a === "model") {
7100
- let t = ae.get(n.url);
7248
+ let t = P.get(n.url);
7101
7249
  if (t) oe(i, t);
7102
7250
  else {
7103
7251
  let t = Je("ModelInstance3D");
7104
- t.classList.add("lib-glyph"), i.appendChild(t), i.dataset.model = n.url, ae.has(n.url) || e.push(i);
7252
+ t.classList.add("lib-glyph"), i.appendChild(t), i.dataset.model = n.url, P.has(n.url) || e.push(i);
7105
7253
  }
7106
7254
  } else {
7107
7255
  let e = Je(a === "audio" ? "AudioPlayer" : "ModelInstance3D");
@@ -7113,11 +7261,11 @@ function Eo(e, t) {
7113
7261
  }
7114
7262
  let s = document.createElement("span");
7115
7263
  s.className = "lib-card-name", s.textContent = xe(n), r.append(i, s), r.title = be(n, t.kind, t.assetType) ?? n.description ?? n.url, r.addEventListener("click", () => {
7116
- l = n, F(), P();
7264
+ l = n, F(), N();
7117
7265
  }), C.appendChild(r);
7118
7266
  }
7119
7267
  if (o && !u && (C.appendChild(E), requestAnimationFrame(Te)), ce) for (let t of e) ce.observe(t);
7120
- else for (let t of e.slice(0, bo)) se(t);
7268
+ else for (let t of e.slice(0, wo)) se(t);
7121
7269
  T.hidden = !o || u;
7122
7270
  }, de = null, fe = !1, pe = (e) => {
7123
7271
  C.textContent = "", T.hidden = !0, de?.abort();
@@ -7134,24 +7282,24 @@ function Eo(e, t) {
7134
7282
  let s = document.createElement("div");
7135
7283
  s.className = "lib-token-row", s.append(o), t.append(n, r, s, i), C.appendChild(t), o.addEventListener("click", () => {
7136
7284
  let e = new AbortController();
7137
- de?.abort(), de = e, o.disabled = !0, i.textContent = "asking Verse8 for a code…", So(e.signal, (e) => {
7285
+ de?.abort(), de = e, o.disabled = !0, i.textContent = "asking Verse8 for a code…", Eo(e.signal, (e) => {
7138
7286
  i.textContent = e;
7139
7287
  }).then((t) => {
7140
- e.signal.aborted || (To(t), fe = !0, i.textContent = "signed in — loading the catalog…", a = 1, _e(!1));
7288
+ e.signal.aborted || (ko(t), fe = !0, i.textContent = "signed in — loading the catalog…", a = 1, _e(!1));
7141
7289
  }).catch((t) => {
7142
7290
  e.signal.aborted || (o.disabled = !1, i.textContent = t instanceof Error ? t.message : String(t));
7143
7291
  });
7144
7292
  });
7145
7293
  }, _e = async (n) => {
7146
7294
  if (!(!e.library || u)) {
7147
- u = !0, w.textContent = n ? "loading more…" : `loading ${ue(r)}…`, n || (s = [], l = null, ie.cancelPending(), F(), P()), te();
7295
+ u = !0, w.textContent = n ? "loading more…" : `loading ${ue(r)}…`, n || (s = [], l = null, ae.cancelPending(), F(), N()), te();
7148
7296
  try {
7149
7297
  let l = await e.library({
7150
7298
  tags: r,
7151
7299
  keyword: i.trim() || void 0,
7152
7300
  page: a,
7153
- limit: bo
7154
- }, Co() || void 0);
7301
+ limit: wo
7302
+ }, Do() || void 0);
7155
7303
  if (d) return;
7156
7304
  u = !1, s = n ? [...s, ...l.items] : l.items, c = s, o = l.hasNext;
7157
7305
  let f = l.total === void 0 ? "" : ` of ${l.total}`, p = s.filter((e) => ge(e.url, t.kind)).length, m = p === s.length ? "" : ` · ${p} fit this field`;
@@ -7182,21 +7330,21 @@ function Eo(e, t) {
7182
7330
  i = v.value, clearTimeout(Ee), Ee = window.setTimeout(() => {
7183
7331
  a = 1, _e(!1);
7184
7332
  }, 350);
7185
- }), te(), P(), document.body.appendChild(f), v.focus(), _e(!1);
7333
+ }), te(), N(), document.body.appendChild(f), v.focus(), _e(!1);
7186
7334
  });
7187
7335
  }
7188
7336
  //#endregion
7189
7337
  //#region src/scene-tree.ts
7190
- var Do = ".scene.json";
7191
- function Oo(e) {
7338
+ var jo = ".scene.json";
7339
+ function Mo(e) {
7192
7340
  let t = e.split("/").pop() ?? e;
7193
- return t.endsWith(Do) ? t.slice(0, -11) : t;
7341
+ return t.endsWith(jo) ? t.slice(0, -11) : t;
7194
7342
  }
7195
- function ko(e) {
7343
+ function No(e) {
7196
7344
  let t = e.lastIndexOf("/");
7197
7345
  return t === -1 ? "" : e.slice(0, t);
7198
7346
  }
7199
- function Ao(e, t) {
7347
+ function Po(e, t) {
7200
7348
  return {
7201
7349
  path: e,
7202
7350
  name: t,
@@ -7204,31 +7352,31 @@ function Ao(e, t) {
7204
7352
  files: []
7205
7353
  };
7206
7354
  }
7207
- function jo(e) {
7208
- let t = Ao("", "");
7355
+ function Fo(e) {
7356
+ let t = Po("", "");
7209
7357
  for (let n of e) {
7210
7358
  let e = n.rel.split("/");
7211
7359
  if (!e.pop()) continue;
7212
7360
  let r = t;
7213
7361
  for (let t of e) {
7214
7362
  let e = r.path ? `${r.path}/${t}` : t, n = r.dirs.get(t);
7215
- n || (n = Ao(e, t), r.dirs.set(t, n)), r = n;
7363
+ n || (n = Po(e, t), r.dirs.set(t, n)), r = n;
7216
7364
  }
7217
7365
  r.files.push(n);
7218
7366
  }
7219
7367
  return t;
7220
7368
  }
7221
- function Mo(e) {
7369
+ function Io(e) {
7222
7370
  let t = e.files.length;
7223
- for (let n of e.dirs.values()) t += Mo(n);
7371
+ for (let n of e.dirs.values()) t += Io(n);
7224
7372
  return t;
7225
7373
  }
7226
- function No(e) {
7374
+ function Lo(e) {
7227
7375
  let t = e.files.filter((e) => e.scene).length;
7228
- for (let n of e.dirs.values()) t += No(n);
7376
+ for (let n of e.dirs.values()) t += Lo(n);
7229
7377
  return t;
7230
7378
  }
7231
- function Po(e) {
7379
+ function Ro(e) {
7232
7380
  let t = e, n = e.name;
7233
7381
  for (; t.files.length === 0 && t.dirs.size === 1;) {
7234
7382
  let e = [...t.dirs.values()][0];
@@ -7240,16 +7388,16 @@ function Po(e) {
7240
7388
  label: n
7241
7389
  };
7242
7390
  }
7243
- function Fo(e) {
7244
- let t = ko(e ?? "").split("/").filter(Boolean), n = [], r = "";
7391
+ function zo(e) {
7392
+ let t = No(e ?? "").split("/").filter(Boolean), n = [], r = "";
7245
7393
  for (let e of t) r = r ? `${r}/${e}` : e, n.push(r);
7246
7394
  return n;
7247
7395
  }
7248
- function Io(e, t = {}) {
7396
+ function Bo(e, t = {}) {
7249
7397
  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) => {
7250
7398
  let s = [...e.dirs.values()].sort((e, t) => e.name.localeCompare(t.name));
7251
7399
  for (let e of s) {
7252
- let { dir: t, label: s } = Po(e), c = Mo(t);
7400
+ let { dir: t, label: s } = Ro(e), c = Io(t);
7253
7401
  if (c === 0) continue;
7254
7402
  let l = n !== "" || i.has(t.path);
7255
7403
  a.push({
@@ -7258,31 +7406,31 @@ function Io(e, t = {}) {
7258
7406
  label: s,
7259
7407
  depth: r,
7260
7408
  count: c,
7261
- scenes: No(t),
7409
+ scenes: Lo(t),
7262
7410
  open: l
7263
7411
  }), l && o(t, r + 1);
7264
7412
  }
7265
- let c = [...e.files].sort((e, t) => Oo(e.rel).localeCompare(Oo(t.rel)));
7413
+ let c = [...e.files].sort((e, t) => Mo(e.rel).localeCompare(Mo(t.rel)));
7266
7414
  for (let e of c) a.push({
7267
7415
  kind: "scene",
7268
7416
  entry: e,
7269
- label: Oo(e.rel),
7270
- folder: ko(e.rel),
7417
+ label: Mo(e.rel),
7418
+ folder: No(e.rel),
7271
7419
  depth: r,
7272
7420
  current: e.rel === t.current
7273
7421
  });
7274
7422
  };
7275
- return o(jo(r), 0), a;
7423
+ return o(Fo(r), 0), a;
7276
7424
  }
7277
- function Lo(e, t) {
7278
- let n = new Set(Fo(t));
7279
- if (e.length <= 24) for (let t of e) for (let e of Fo(t.rel)) n.add(e);
7425
+ function Vo(e, t) {
7426
+ let n = new Set(zo(t));
7427
+ if (e.length <= 24) for (let t of e) for (let e of zo(t.rel)) n.add(e);
7280
7428
  return n;
7281
7429
  }
7282
- function Ro(e) {
7430
+ function Ho(e) {
7283
7431
  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`;
7284
7432
  }
7285
- function zo(e, t) {
7433
+ function Uo(e, t) {
7286
7434
  if (typeof e != "number" || !Number.isFinite(e) || e <= 0) return "";
7287
7435
  let n = Math.round((t - e) / 1e3);
7288
7436
  if (n < 90) return "just now";
@@ -7291,49 +7439,53 @@ function zo(e, t) {
7291
7439
  let i = Math.round(r / 60);
7292
7440
  return i < 24 ? `${i}h ago` : i < 48 ? "yesterday" : new Date(e).toISOString().slice(0, 10);
7293
7441
  }
7294
- function Bo(e, t = "new-level") {
7442
+ function Wo(e, t = "new-level") {
7295
7443
  let n = e ? e.kind === "folder" ? e.path : e.folder : "";
7296
- return n ? `${n}/${t}${Do}` : `${t}${Do}`;
7444
+ return n ? `${n}/${t}${jo}` : `${t}${jo}`;
7297
7445
  }
7298
7446
  //#endregion
7299
7447
  //#region src/scene-browser.ts
7300
- function Vo(e, t) {
7448
+ function Go(e, t) {
7301
7449
  let n = document.createElement("span");
7302
7450
  return n.className = e, n.textContent = t, n;
7303
7451
  }
7304
- function Ho(e, t, n = () => Date.now()) {
7452
+ function Ko(e, t, n = () => Date.now()) {
7305
7453
  let r = [], i = /* @__PURE__ */ new Set(), a = [], o = 0, s = !0, c = !1, l = () => {
7306
7454
  let l = t.current();
7307
- if (a = Io(r, {
7455
+ a = Bo(r, {
7308
7456
  expanded: i,
7309
7457
  query: e.search.value,
7310
7458
  current: l
7311
- }), o >= a.length && (o = a.length - 1), o < 0 && (o = 0), s) {
7459
+ }), o >= a.length && (o = a.length - 1), o < 0 && (o = 0);
7460
+ let d = () => {
7461
+ let e = a.findIndex((e) => e.kind === "scene" && !e.entry.notScene);
7462
+ if (e >= 0) return e;
7463
+ let t = a.findIndex((e) => e.kind === "folder");
7464
+ return t >= 0 ? t : Math.max(0, a.findIndex((e) => e.kind === "scene"));
7465
+ };
7466
+ if (s) {
7312
7467
  let e = a.findIndex((e) => e.kind === "scene" && e.current);
7313
- o = e >= 0 ? e : Math.max(0, a.findIndex((e) => e.kind === "scene")), s = !1, c = !1;
7314
- } else if (c) {
7315
- let e = a.findIndex((e) => e.kind === "scene");
7316
- o = e >= 0 ? e : 0, c = !1;
7317
- }
7468
+ o = e >= 0 ? e : d(), s = !1, c = !1;
7469
+ } else c &&= (o = d(), !1);
7318
7470
  if (e.list.textContent = "", a.length === 0) {
7319
7471
  let t = document.createElement("div");
7320
7472
  t.className = "scene-empty", t.textContent = r.length ? `no scene matches “${e.search.value.trim()}”` : "no .json files in this project yet — create a scene below", e.list.appendChild(t);
7321
7473
  }
7322
- let d = n();
7474
+ let f = n();
7323
7475
  a.forEach((n, r) => {
7324
7476
  let i = document.createElement("div");
7325
7477
  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");
7326
- let a = Vo("scene-caret", "");
7327
- n.kind === "folder" ? (a.classList.add("chevron"), n.open || a.classList.add("collapsed"), a.appendChild(Ye())) : a.textContent = "◇", i.append(a, Vo("scene-name", n.label), Vo("scene-meta", n.kind === "folder" ? n.scenes > 0 ? `${n.scenes} scene${n.scenes === 1 ? "" : "s"}` : `${n.count} file${n.count === 1 ? "" : "s"}` : [
7478
+ let a = Go("scene-caret", "");
7479
+ n.kind === "folder" ? (a.classList.add("chevron"), n.open || a.classList.add("collapsed"), a.appendChild(Ye())) : a.textContent = "◇", i.append(a, Go("scene-name", n.label), Go("scene-meta", n.kind === "folder" ? n.scenes > 0 ? `${n.scenes} scene${n.scenes === 1 ? "" : "s"}` : `${n.count} file${n.count === 1 ? "" : "s"}` : [
7328
7480
  n.entry.scene ? [n.entry.scene.dimension, `${n.entry.scene.nodes} node${n.entry.scene.nodes === 1 ? "" : "s"}`].filter(Boolean).join(" · ") : "not a scene",
7329
- zo(n.entry.modified, d),
7330
- Ro(n.entry.size)
7481
+ Uo(n.entry.modified, f),
7482
+ Ho(n.entry.size)
7331
7483
  ].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", () => {
7332
7484
  o = r, n.kind === "folder" ? u(n.path) : t.open(n.entry);
7333
7485
  }), e.list.appendChild(i);
7334
7486
  });
7335
- let f = r.length, p = a.filter((e) => e.kind === "scene").length;
7336
- e.count.textContent = f === 0 ? "" : p === f ? `${f}` : `${p} / ${f}`, e.path.placeholder = Bo(a[o]), e.list.querySelector(".active")?.scrollIntoView({ block: "nearest" });
7487
+ let p = r.length, m = a.filter((e) => e.kind === "scene").length;
7488
+ e.count.textContent = p === 0 ? "" : m === p ? `${p}` : `${m} / ${p}`, e.path.placeholder = Wo(a[o]), e.list.querySelector(".active")?.scrollIntoView({ block: "nearest" });
7337
7489
  }, u = (e) => {
7338
7490
  i.has(e) ? i.delete(e) : i.add(e), l();
7339
7491
  }, d = (e) => {
@@ -7370,15 +7522,15 @@ function Ho(e, t, n = () => Date.now()) {
7370
7522
  n.className = "scene-empty", n.textContent = `could not list scenes: ${t instanceof Error ? t.message : String(t)}`, e.list.appendChild(n), e.count.textContent = "";
7371
7523
  return;
7372
7524
  }
7373
- if (i.size === 0) i = Lo(r, t.current());
7374
- else for (let e of Fo(t.current())) i.add(e);
7525
+ if (i.size === 0) i = Vo(r, t.current());
7526
+ else for (let e of zo(t.current())) i.add(e);
7375
7527
  s = !0, l(), e.search.focus(), e.search.select();
7376
7528
  } };
7377
7529
  }
7378
7530
  //#endregion
7379
7531
  //#region src/shell.ts
7380
- var Uo = "\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-alt\" class=\"ghost\" hidden>save &amp; open</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", Wo = Math.PI / 180, Go = 180 / Math.PI;
7381
- function Ko(e) {
7532
+ var qo = "\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-alt\" class=\"ghost\" hidden>save &amp; open</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", Jo = Math.PI / 180, Yo = 180 / Math.PI;
7533
+ function Xo(e) {
7382
7534
  let t = typeof e.type == "string" ? e.type : "";
7383
7535
  if (!t) return 0;
7384
7536
  let n;
@@ -7390,50 +7542,50 @@ function Ko(e) {
7390
7542
  let r = n.position?.default;
7391
7543
  return Array.isArray(r) ? r.length === 2 ? 2 : r.length === 3 ? 3 : 0 : 0;
7392
7544
  }
7393
- function qo(e, t) {
7545
+ function Zo(e, t) {
7394
7546
  return Array.isArray(e) ? t.map((t, n) => typeof e[n] == "number" ? e[n] : t) : [...t];
7395
7547
  }
7396
- function Jo(e, t) {
7397
- let [n, r, i] = qo(e, t);
7548
+ function Qo(e, t) {
7549
+ let [n, r, i] = Zo(e, t);
7398
7550
  return [
7399
7551
  n ?? t[0],
7400
7552
  r ?? t[1],
7401
7553
  i ?? t[2]
7402
7554
  ];
7403
7555
  }
7404
- function Yo(e, t) {
7405
- let [n, r] = qo(e, t);
7556
+ function $o(e, t) {
7557
+ let [n, r] = Zo(e, t);
7406
7558
  return [n ?? t[0], r ?? t[1]];
7407
7559
  }
7408
- function Xo(e) {
7409
- let t = Ko(e), n = new ki();
7560
+ function es(e) {
7561
+ let t = Xo(e), n = new Mi();
7410
7562
  if (t === 0) return n;
7411
7563
  let r = e.props ?? {};
7412
7564
  if (t === 2) {
7413
- let [e, t] = Yo(r.position, [0, 0]), [i, a] = Yo(r.scale, [1, 1]), o = typeof r.rotation == "number" ? r.rotation : 0;
7414
- return n.compose(new G(e, t, 0), new di().setFromEuler(new Li(0, 0, o * Wo, "XYZ")), new G(i || 1, a || 1, 1));
7565
+ let [e, t] = $o(r.position, [0, 0]), [i, a] = $o(r.scale, [1, 1]), o = typeof r.rotation == "number" ? r.rotation : 0;
7566
+ return n.compose(new K(e, t, 0), new mi().setFromEuler(new Bi(0, 0, o * Jo, "XYZ")), new K(i || 1, a || 1, 1));
7415
7567
  }
7416
- let [i, a, o] = Jo(r.position, [
7568
+ let [i, a, o] = Qo(r.position, [
7417
7569
  0,
7418
7570
  0,
7419
7571
  0
7420
- ]), [s, c, l] = Jo(r.rotation, [
7572
+ ]), [s, c, l] = Qo(r.rotation, [
7421
7573
  0,
7422
7574
  0,
7423
7575
  0
7424
- ]), [u, d, f] = Jo(r.scale, [
7576
+ ]), [u, d, f] = Qo(r.scale, [
7425
7577
  1,
7426
7578
  1,
7427
7579
  1
7428
7580
  ]);
7429
- return n.compose(new G(i, a, o), new di().setFromEuler(new Li(s * Wo, c * Wo, l * Wo, "XYZ")), new G(u || 1, d || 1, f || 1));
7581
+ return n.compose(new K(i, a, o), new mi().setFromEuler(new Bi(s * Jo, c * Jo, l * Jo, "XYZ")), new K(u || 1, d || 1, f || 1));
7430
7582
  }
7431
- function Zo(e, t) {
7432
- let n = Xo(e), r = e;
7583
+ function ts(e, t) {
7584
+ let n = es(e), r = e;
7433
7585
  for (let e of t) {
7434
7586
  let t = r.children?.[e];
7435
7587
  if (!t) break;
7436
- n.multiply(Xo(t)), r = t;
7588
+ n.multiply(es(t)), r = t;
7437
7589
  }
7438
7590
  return n;
7439
7591
  }
@@ -7441,15 +7593,15 @@ function Q(e) {
7441
7593
  let t = Math.round(e * 1e4) / 1e4;
7442
7594
  return Object.is(t, -0) ? 0 : t;
7443
7595
  }
7444
- function Qo(e, t, n) {
7445
- let r = Ko(e);
7596
+ function ns(e, t, n) {
7597
+ let r = Xo(e);
7446
7598
  if (r === 0) return;
7447
- let i = new ki().copy(t).invert().multiply(n), a = new G(), o = new di(), s = new G();
7599
+ let i = new Mi().copy(t).invert().multiply(n), a = new K(), o = new mi(), s = new K();
7448
7600
  i.decompose(a, o, s);
7449
- let c = new Li().setFromQuaternion(o, "XYZ"), l = e.props ?? {}, u = (e, t, n) => {
7601
+ let c = new Bi().setFromQuaternion(o, "XYZ"), l = e.props ?? {}, u = (e, t, n) => {
7450
7602
  JSON.stringify(t) === JSON.stringify(n) ? delete l[e] : l[e] = t;
7451
7603
  };
7452
- r === 2 ? (u("position", [Q(a.x), Q(a.y)], [0, 0]), u("rotation", Q(c.z * Go), 0), u("scale", [Q(s.x), Q(s.y)], [1, 1])) : (u("position", [
7604
+ r === 2 ? (u("position", [Q(a.x), Q(a.y)], [0, 0]), u("rotation", Q(c.z * Yo), 0), u("scale", [Q(s.x), Q(s.y)], [1, 1])) : (u("position", [
7453
7605
  Q(a.x),
7454
7606
  Q(a.y),
7455
7607
  Q(a.z)
@@ -7458,9 +7610,9 @@ function Qo(e, t, n) {
7458
7610
  0,
7459
7611
  0
7460
7612
  ]), u("rotation", [
7461
- Q(c.x * Go),
7462
- Q(c.y * Go),
7463
- Q(c.z * Go)
7613
+ Q(c.x * Yo),
7614
+ Q(c.y * Yo),
7615
+ Q(c.z * Yo)
7464
7616
  ], [
7465
7617
  0,
7466
7618
  0,
@@ -7477,7 +7629,7 @@ function Qo(e, t, n) {
7477
7629
  }
7478
7630
  //#endregion
7479
7631
  //#region src/rename-refs.ts
7480
- function $o(e, t) {
7632
+ function rs(e, t) {
7481
7633
  let n = [String(e.name ?? "")], r = e;
7482
7634
  for (let e of t) {
7483
7635
  let t = r.children?.[e];
@@ -7486,7 +7638,7 @@ function $o(e, t) {
7486
7638
  }
7487
7639
  return n;
7488
7640
  }
7489
- function es(e, t, n, r) {
7641
+ function is(e, t, n, r) {
7490
7642
  if (e === "" || e === ".") return null;
7491
7643
  let i = n[n.length - 1];
7492
7644
  if (i === void 0 || i === r) return null;
@@ -7509,7 +7661,7 @@ function es(e, t, n, r) {
7509
7661
  let p = [...o];
7510
7662
  return p[f] = r, (a ? "/" : "") + p.join("/");
7511
7663
  }
7512
- function ts(e) {
7664
+ function as(e) {
7513
7665
  let t = (e) => Object.entries(e).filter(([, e]) => e?.nodePath).map(([e]) => e), n = typeof e.type == "string" ? e.type : "", i = [];
7514
7666
  if (n) try {
7515
7667
  i = t(s(n));
@@ -7523,31 +7675,31 @@ function ts(e) {
7523
7675
  script: o
7524
7676
  };
7525
7677
  }
7526
- function ns(e, t, n) {
7678
+ function os(e, t, n) {
7527
7679
  let r = e.root;
7528
- if (!r || t.length === 0) return r && t.length === 0 ? rs(e, r, n) : [];
7529
- let i = $o(r, t), a = is(r, t);
7680
+ if (!r || t.length === 0) return r && t.length === 0 ? ss(e, r, n) : [];
7681
+ let i = rs(r, t), a = cs(r, t);
7530
7682
  if (!a) return [];
7531
- let o = as(e, r, i, n);
7683
+ let o = ls(e, r, i, n);
7532
7684
  return a.name = n, o;
7533
7685
  }
7534
- function rs(e, t, n) {
7535
- let r = as(e, t, [String(t.name ?? "")], n);
7686
+ function ss(e, t, n) {
7687
+ let r = ls(e, t, [String(t.name ?? "")], n);
7536
7688
  return t.name = n, r;
7537
7689
  }
7538
- function is(e, t) {
7690
+ function cs(e, t) {
7539
7691
  let n = e;
7540
7692
  for (let e of t) if (n = n?.children?.[e], !n) return null;
7541
7693
  return n ?? null;
7542
7694
  }
7543
- function as(e, t, n, r) {
7695
+ function ls(e, t, n, r) {
7544
7696
  let i = [], a = String(t.name ?? ""), o = e.connections;
7545
7697
  Array.isArray(o) && o.forEach((e, t) => {
7546
7698
  let o = e;
7547
7699
  for (let e of ["from", "to"]) {
7548
7700
  let s = o[e];
7549
7701
  if (typeof s != "string") continue;
7550
- let c = es(s, [a], n, r);
7702
+ let c = is(s, [a], n, r);
7551
7703
  c !== null && (o[e] = c, i.push({
7552
7704
  where: `connections[${t}].${e}`,
7553
7705
  from: s,
@@ -7556,7 +7708,7 @@ function as(e, t, n, r) {
7556
7708
  }
7557
7709
  });
7558
7710
  let s = (a, o) => {
7559
- let c = ts(a), l = a.script, d = [[
7711
+ let c = as(a), l = a.script, d = [[
7560
7712
  a.props,
7561
7713
  c.props,
7562
7714
  ""
@@ -7568,7 +7720,7 @@ function as(e, t, n, r) {
7568
7720
  for (let [a, s, c] of d) if (a) for (let l of s) {
7569
7721
  let s = a[l], d = `${o.join("/")}.${c}${l}`;
7570
7722
  if (typeof s == "string") {
7571
- let e = es(s, o, n, r);
7723
+ let e = is(s, o, n, r);
7572
7724
  e !== null && (a[l] = e, i.push({
7573
7725
  where: d,
7574
7726
  from: s,
@@ -7576,25 +7728,25 @@ function as(e, t, n, r) {
7576
7728
  }));
7577
7729
  } else Array.isArray(s) ? s.forEach((e, t) => {
7578
7730
  if (typeof e != "string") return;
7579
- let a = es(e, o, n, r);
7731
+ let a = is(e, o, n, r);
7580
7732
  a !== null && (s[t] = a, i.push({
7581
7733
  where: `${d}[${t}]`,
7582
7734
  from: e,
7583
7735
  to: a
7584
7736
  }));
7585
- }) : u(s) && os(e, t, s, n, r, d, i);
7737
+ }) : u(s) && us(e, t, s, n, r, d, i);
7586
7738
  }
7587
7739
  let f = a.children ?? [];
7588
7740
  for (let e of f) s(e, [...o, String(e.name ?? "")]);
7589
7741
  };
7590
7742
  return s(t, [a]), i;
7591
7743
  }
7592
- function os(e, t, n, r, i, a, o) {
7744
+ function us(e, t, n, r, i, a, o) {
7593
7745
  let s = n["@const"];
7594
7746
  if (typeof s != "string") return;
7595
7747
  let c = e.constants, l = c?.[s];
7596
7748
  if (typeof l != "string" || !l.startsWith("%") && !l.startsWith("/")) return;
7597
- let u = es(l, [String(t.name ?? "")], r, i);
7749
+ let u = is(l, [String(t.name ?? "")], r, i);
7598
7750
  u !== null && (c[s] = u, o.push({
7599
7751
  where: `constants.${s} (${a})`,
7600
7752
  from: l,
@@ -7603,7 +7755,7 @@ function os(e, t, n, r, i, a, o) {
7603
7755
  }
7604
7756
  //#endregion
7605
7757
  //#region src/state.ts
7606
- var ss = class {
7758
+ var ds = class {
7607
7759
  working;
7608
7760
  selection = [];
7609
7761
  extra = [];
@@ -7631,7 +7783,7 @@ var ss = class {
7631
7783
  undoStack = [];
7632
7784
  listeners = /* @__PURE__ */ new Set();
7633
7785
  constructor(e) {
7634
- this.working = e, this.working.root && cs(this.working.root), this.original = JSON.stringify(this.working);
7786
+ this.working = e, this.working.root && fs(this.working.root), this.original = JSON.stringify(this.working);
7635
7787
  }
7636
7788
  get dirty() {
7637
7789
  return JSON.stringify(this.working) !== this.original;
@@ -7664,8 +7816,8 @@ var ss = class {
7664
7816
  renameNode(e, t) {
7665
7817
  let n = this.nodeAt(e);
7666
7818
  if (!n) return null;
7667
- let r = this.parentOf(e), i = r ? _s(r, t, n) : t;
7668
- return i === n.name ? [] : this.transact(() => ns(this.working, e, i));
7819
+ let r = this.parentOf(e), i = r ? xs(r, t, n) : t;
7820
+ return i === n.name ? [] : this.transact(() => os(this.working, e, i));
7669
7821
  }
7670
7822
  priorError(e) {
7671
7823
  if (!this.validator) return null;
@@ -7679,35 +7831,35 @@ var ss = class {
7679
7831
  return this.moveNodes([e], t, n)?.[0] ?? null;
7680
7832
  }
7681
7833
  moveNodes(e, t, n) {
7682
- let r = ps(e).filter((e) => e.length > 0);
7834
+ let r = _s(e).filter((e) => e.length > 0);
7683
7835
  if (r.length === 0) return null;
7684
7836
  for (let e of r) if (e.length <= t.length && e.every((e, n) => e === t[n])) return null;
7685
7837
  let i = this.working.root, a = r.map((e) => this.nodeAt(e)).filter((e) => e !== null);
7686
7838
  if (a.length !== r.length) return null;
7687
7839
  let o = this.nodeAt(t);
7688
7840
  if (!o || a.includes(o)) return null;
7689
- let s = r.map((e) => Zo(i, e));
7841
+ let s = r.map((e) => ts(i, e));
7690
7842
  return this.transact(() => {
7691
- for (let e of a) hs(i, e);
7843
+ for (let e of a) ys(i, e);
7692
7844
  let e, t;
7693
7845
  if (n === "into") e = o, e.children ||= [], t = e.children.length;
7694
7846
  else {
7695
- let r = ms(i, o);
7847
+ let r = vs(i, o);
7696
7848
  if (!r) return null;
7697
7849
  e = r.parent, t = r.index + +(n === "after");
7698
7850
  }
7699
7851
  let r = [];
7700
7852
  a.forEach((n, r) => {
7701
- n.name = _s(e, n.name ?? "Node"), e.children?.splice(t + r, 0, n);
7853
+ n.name = xs(e, n.name ?? "Node"), e.children?.splice(t + r, 0, n);
7702
7854
  });
7703
7855
  for (let e of a) {
7704
- let t = gs(i, e);
7856
+ let t = bs(i, e);
7705
7857
  if (!t) return null;
7706
7858
  r.push(t);
7707
7859
  }
7708
7860
  return r.forEach((e, t) => {
7709
7861
  let n = s[t], r = a[t];
7710
- !n || !r || Qo(r, Zo(i, e.slice(0, -1)), n);
7862
+ !n || !r || ns(r, ts(i, e.slice(0, -1)), n);
7711
7863
  }), r;
7712
7864
  });
7713
7865
  }
@@ -7716,17 +7868,17 @@ var ss = class {
7716
7868
  let t = this.nodeAt(e), n = this.parentOf(e);
7717
7869
  return !t || !n?.children ? null : this.transact(() => {
7718
7870
  let r = JSON.parse(JSON.stringify(t));
7719
- r.name = _s(n, t.name ?? "Node"), ls(r);
7871
+ r.name = xs(n, t.name ?? "Node"), ps(r);
7720
7872
  let i = e[e.length - 1] + 1;
7721
7873
  return n.children?.splice(i, 0, r), [...e.slice(0, -1), i];
7722
7874
  });
7723
7875
  }
7724
7876
  removeNodes(e) {
7725
- let t = ps(e).filter((e) => e.length > 0);
7877
+ let t = _s(e).filter((e) => e.length > 0);
7726
7878
  if (t.length === 0) return !1;
7727
7879
  let n = this.working.root, r = t.map((e) => this.nodeAt(e)).filter((e) => e !== null);
7728
7880
  return this.transact(() => {
7729
- for (let e of r) hs(n, e);
7881
+ for (let e of r) ys(n, e);
7730
7882
  return !0;
7731
7883
  }) === !0;
7732
7884
  }
@@ -7736,16 +7888,16 @@ var ss = class {
7736
7888
  insertNode(e, t) {
7737
7889
  if (!this.working.root) {
7738
7890
  let t = JSON.parse(JSON.stringify(e));
7739
- return ls(t), this.transact(() => (this.working.root = t, []));
7891
+ return ps(t), this.transact(() => (this.working.root = t, []));
7740
7892
  }
7741
7893
  let n = this.nodeAt(t);
7742
7894
  return n ? this.transact(() => {
7743
7895
  let r = JSON.parse(JSON.stringify(e));
7744
- return r.name = _s(n, r.name ?? "Node"), ls(r), n.children ||= [], n.children.push(r), [...t, n.children.length - 1];
7896
+ return r.name = xs(n, r.name ?? "Node"), ps(r), n.children ||= [], n.children.push(r), [...t, n.children.length - 1];
7745
7897
  }) : null;
7746
7898
  }
7747
7899
  findRemovalReferences(e) {
7748
- let t = ps(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 = [];
7900
+ let t = _s(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 = [];
7749
7901
  for (let e of t) {
7750
7902
  let t = [], r = n;
7751
7903
  for (let n of e) {
@@ -7835,9 +7987,9 @@ var ss = class {
7835
7987
  return s;
7836
7988
  }
7837
7989
  removeNodesUnlinking(e) {
7838
- let t = this.findRemovalReferences(e), n = ps(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));
7990
+ let t = this.findRemovalReferences(e), n = _s(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));
7839
7991
  return this.transact(() => {
7840
- o.size > 0 && (this.working.connections = (this.working.connections ?? []).filter((e, t) => !o.has(t))), a.size > 0 && us(this.working, a, i);
7992
+ o.size > 0 && (this.working.connections = (this.working.connections ?? []).filter((e, t) => !o.has(t))), a.size > 0 && ms(this.working, a, i);
7841
7993
  for (let e of t) {
7842
7994
  if (e.kind !== "prop" || !e.prop || e.prop.required) continue;
7843
7995
  let t = this.nodeAt(e.prop.path);
@@ -7845,7 +7997,7 @@ var ss = class {
7845
7997
  let n = e.prop.bag === "props" ? t.props : t.script?.props;
7846
7998
  n && delete n[e.prop.key];
7847
7999
  }
7848
- for (let e of i) hs(r, e);
8000
+ for (let e of i) ys(r, e);
7849
8001
  return !0;
7850
8002
  }) === !0;
7851
8003
  }
@@ -7854,7 +8006,7 @@ var ss = class {
7854
8006
  this.reset(e), this.original = t;
7855
8007
  }
7856
8008
  reset(e) {
7857
- this.working = e, this.working.root && cs(this.working.root), this.original = JSON.stringify(this.working), this.undoStack = [], this.selection = [], this.emit();
8009
+ this.working = e, this.working.root && fs(this.working.root), this.original = JSON.stringify(this.working), this.undoStack = [], this.selection = [], this.emit();
7858
8010
  }
7859
8011
  markSaved() {
7860
8012
  this.original = JSON.stringify(this.working), this.emit();
@@ -7886,7 +8038,7 @@ var ss = class {
7886
8038
  return this.pendingGroups.delete(e) && this.pendingGroups.add(t), this.selectedGroup = t, this.mutate(() => {
7887
8039
  for (let i of r) {
7888
8040
  let r = `${t}/${i.slice(e.length + 1)}`;
7889
- n[r] = n[i], delete n[i], ds(this.working, `$${i}`, `$${r}`);
8041
+ n[r] = n[i], delete n[i], hs(this.working, `$${i}`, `$${r}`);
7890
8042
  }
7891
8043
  }), r.length === 0 && this.emit(), !0;
7892
8044
  }
@@ -7898,7 +8050,7 @@ var ss = class {
7898
8050
  renameAssetKey(e, t) {
7899
8051
  let n = this.assetMap();
7900
8052
  return !(e in n) || !t || t === e || t in n ? !1 : (this.selectedAsset = t, this.mutate(() => {
7901
- n[t] = n[e], delete n[e], ds(this.working, `$${e}`, `$${t}`);
8053
+ n[t] = n[e], delete n[e], hs(this.working, `$${e}`, `$${t}`);
7902
8054
  }), !0);
7903
8055
  }
7904
8056
  deleteGroup(e) {
@@ -7924,7 +8076,7 @@ var ss = class {
7924
8076
  this.emit();
7925
8077
  }
7926
8078
  allSelections() {
7927
- return [...this.selection === null ? [] : [this.selection, ...this.extra]].sort(fs);
8079
+ return [...this.selection === null ? [] : [this.selection, ...this.extra]].sort(gs);
7928
8080
  }
7929
8081
  isSelected(e) {
7930
8082
  let t = e.join(".");
@@ -7937,67 +8089,67 @@ var ss = class {
7937
8089
  for (let e of this.listeners) e();
7938
8090
  }
7939
8091
  };
7940
- function cs(e) {
8092
+ function fs(e) {
7941
8093
  (typeof e.uid != "string" || e.uid === "") && (e.uid = p());
7942
- for (let t of e.children ?? []) cs(t);
8094
+ for (let t of e.children ?? []) fs(t);
7943
8095
  }
7944
- function ls(e) {
8096
+ function ps(e) {
7945
8097
  e.uid = p();
7946
- for (let t of e.children ?? []) ls(t);
8098
+ for (let t of e.children ?? []) ps(t);
7947
8099
  }
7948
- function us(e, t, n) {
8100
+ function ms(e, t, n) {
7949
8101
  if (Array.isArray(e)) {
7950
- for (let r = e.length - 1; r >= 0; r--) typeof e[r] == "string" && t.has(e[r]) ? e.splice(r, 1) : us(e[r], t, n);
8102
+ for (let r = e.length - 1; r >= 0; r--) typeof e[r] == "string" && t.has(e[r]) ? e.splice(r, 1) : ms(e[r], t, n);
7951
8103
  return;
7952
8104
  }
7953
8105
  if (typeof e == "object" && e) {
7954
8106
  if (n.includes(e)) return;
7955
- for (let [r, i] of Object.entries(e)) r !== "uid" && (typeof i == "string" && t.has(i) ? delete e[r] : us(i, t, n));
8107
+ for (let [r, i] of Object.entries(e)) r !== "uid" && (typeof i == "string" && t.has(i) ? delete e[r] : ms(i, t, n));
7956
8108
  }
7957
8109
  }
7958
- function ds(e, t, n) {
8110
+ function hs(e, t, n) {
7959
8111
  if (Array.isArray(e)) {
7960
8112
  e.forEach((r, i) => {
7961
- r === t ? e[i] = n : ds(r, t, n);
8113
+ r === t ? e[i] = n : hs(r, t, n);
7962
8114
  });
7963
8115
  return;
7964
8116
  }
7965
- if (typeof e == "object" && e) for (let [r, i] of Object.entries(e)) i === t ? e[r] = n : ds(i, t, n);
8117
+ if (typeof e == "object" && e) for (let [r, i] of Object.entries(e)) i === t ? e[r] = n : hs(i, t, n);
7966
8118
  }
7967
- function fs(e, t) {
8119
+ function gs(e, t) {
7968
8120
  for (let n = 0; n < Math.min(e.length, t.length); n++) if (e[n] !== t[n]) return e[n] - t[n];
7969
8121
  return e.length - t.length;
7970
8122
  }
7971
- function ps(e) {
7972
- let t = [...e].sort(fs), n = [];
8123
+ function _s(e) {
8124
+ let t = [...e].sort(gs), n = [];
7973
8125
  for (let e of t) n.some((t) => t.length <= e.length && t.every((t, n) => t === e[n])) || n.push(e);
7974
8126
  return n;
7975
8127
  }
7976
- function ms(e, t) {
8128
+ function vs(e, t) {
7977
8129
  let n = e.children?.indexOf(t) ?? -1;
7978
8130
  if (n >= 0) return {
7979
8131
  parent: e,
7980
8132
  index: n
7981
8133
  };
7982
8134
  for (let n of e.children ?? []) {
7983
- let e = ms(n, t);
8135
+ let e = vs(n, t);
7984
8136
  if (e) return e;
7985
8137
  }
7986
8138
  return null;
7987
8139
  }
7988
- function hs(e, t) {
7989
- let n = ms(e, t);
8140
+ function ys(e, t) {
8141
+ let n = vs(e, t);
7990
8142
  n?.parent.children?.splice(n.index, 1);
7991
8143
  }
7992
- function gs(e, t) {
8144
+ function bs(e, t) {
7993
8145
  if (e === t) return [];
7994
8146
  for (let [n, r] of (e.children ?? []).entries()) {
7995
- let e = gs(r, t);
8147
+ let e = bs(r, t);
7996
8148
  if (e) return [n, ...e];
7997
8149
  }
7998
8150
  return null;
7999
8151
  }
8000
- function _s(e, t, n) {
8152
+ function xs(e, t, n) {
8001
8153
  let r = new Set((e.children ?? []).filter((e) => e !== n).map((e) => e.name));
8002
8154
  if (!r.has(t)) return t;
8003
8155
  let i = 2;
@@ -8006,21 +8158,51 @@ function _s(e, t, n) {
8006
8158
  }
8007
8159
  //#endregion
8008
8160
  //#region src/styles.ts
8009
- var vs = "\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/* A grid item's default min-width is auto: it refuses to shrink below its\n content's MIN-CONTENT width. One nowrap asset description was enough to push\n a whole field past the inspector — and no max-width: 100% further down can\n fix it, because 100% is then 100% of the already-grown track. The clamp has\n to come from here. */\n.field > * {\n min-width: 0;\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/* .field.wide is declared EARLIER and at equal specificity, so the rule above\n silently won inside a card: a full-width field (the asset picker) went back\n to two columns and its dropdown panel — a third grid child — was auto-placed\n into the 78px label column, four times too narrow to read. */\n.subcard .field.wide {\n grid-template-columns: 1fr;\n}\n.subcard .field.wide.has-const-picker {\n grid-template-columns: 1fr auto;\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: center;\n}\n.asset-control input {\n flex: 1;\n min-width: 0;\n}\n.asset-toggle {\n flex: none;\n /* square and matched to the input beside it. The base control rule's 9px of\n side padding does not fit a 26px box, which left the chevron off-centre in\n a button that looked taller than it was wide. */\n width: 30px;\n height: 30px;\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\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 min-width: 0;\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 min-width: 0;\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 /* A flex ITEM has the same auto-min-width default as a grid item, so this is\n what stops one long description widening the whole panel.\n overflow-x, NOT overflow: plain hidden also removes the automatic\n MINIMUM SIZE on the block axis, and this button is an item of a\n max-height scroll container — so every row shrank to fit 220px instead of\n scrolling, collapsing 46px rows to 16px with the text squashed to 1px.\n flex: none is the other half: items in a capped column must keep their\n height and let the container scroll. */\n min-width: 0;\n overflow-x: clip;\n flex: none;\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 /* asset keys are short today and a long one must still not widen the panel */\n max-width: 100%;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\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/* A row carrying the library button has THREE cells. Without this the button is\n a third child of a two-column grid: it wraps onto a second row INSIDE the\n label column, gets 52px to live in, and crushes \"📚 library\" against its own\n borders — which reads as a button with no padding, and no amount of padding\n fixes it. */\n.field.has-lib {\n grid-template-columns: 92px 1fr auto;\n}\n.asset-editor .field.has-lib {\n grid-template-columns: 52px 1fr auto;\n}\n.subcard .field.has-lib {\n grid-template-columns: 78px 1fr auto;\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/* an asset the renderer could not fetch: the node is fine, the art is not */\n.asset-row.asset-failed .asset-key {\n color: #f87171;\n text-decoration: underline dotted #f87171;\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/* The third grid column a bound-able prop row opens for its 🔗 picker. The\n .field grid is 92px 1fr; without this the picker is auto-placed into row 2\n column 1, tucked under the label where nobody finds it. */\n.field.has-const-picker {\n grid-template-columns: 92px 1fr auto;\n}\n.field.wide.has-const-picker {\n grid-template-columns: 1fr auto;\n}\n.const-picker {\n flex: none;\n width: 30px;\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: 12px;\n /* The base select rule reserves 9px + 30px of horizontal padding for its\n drawn chevron. In a 30px box that leaves the link glyph nowhere to be, so\n the control rendered as an empty rectangle. This one has no chevron. */\n padding: 0;\n background-image: none;\n text-align: center;\n text-align-last: center;\n height: 30px;\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 /* NOT stretch: .field carries a 7px bottom margin, so a stretched button\n grew to cover it and stood a third taller than the input beside it. */\n align-items: center;\n}\n.const-row .field {\n flex: 1;\n min-width: 0;\n}\n.const-del {\n flex: none;\n width: 30px;\n /* square, and matched to the input it sits beside, rather than to whatever\n the row's tallest margin box happens to be */\n height: 30px;\n /* the field's own bottom margin is the row's spacing; without this the button\n sits 3.5px low against the input */\n margin-bottom: 7px;\n /* the glyph sat right of centre: the base control rule gives every button\n 9px of side padding, which a 30px box has no room for */\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\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 height: 30px;\n /* room for the word: a bare icon next to a URL field reads as decoration,\n and nobody clicks decoration */\n padding: 0 16px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 7px;\n white-space: nowrap;\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n background: var(--bg-1);\n color: var(--fg-1);\n font-size: 12px;\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 min-height: 0;\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 /* Grid items size to their content unless told not to. Without this the\n results pane grows past the dialog and takes the scrollbar with it. */\n min-height: 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 /* A flex child will not shrink below its content without this, so flex:1\n plus overflow-y:auto grew the grid instead of scrolling it: the results ran\n off the bottom of the dialog with no way to reach them, and the\n infinite-scroll sentinel sat permanently in view. */\n min-height: 0;\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(112px, 1fr));\n /* Not \"auto\": once the grid has a definite height, an auto row sizes to its\n MIN-content, and a thumbnail sized by aspect-ratio contributes nothing to\n that — every row collapsed to the 14px of its filename. */\n grid-auto-rows: max-content;\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/* On the shelf, but not something this field can take. Shown — a library that\n hides most of itself is worse — just clearly second. */\n.lib-card.off-kind {\n opacity: 0.42;\n}\n.lib-card.off-kind:hover,\n.lib-card.off-kind.active {\n opacity: 1;\n}\n.lib-sentinel {\n grid-column: 1 / -1;\n height: 1px;\n}\n.lib-charpick {\n display: grid;\n grid-template-columns: auto 1fr auto auto;\n align-items: center;\n gap: 6px;\n padding: 7px 8px;\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n background: var(--bg-2);\n}\n.lib-charpick-label {\n color: var(--text-faint);\n font-size: 11px;\n white-space: nowrap;\n}\n.lib-charpick input {\n min-width: 0;\n padding: 4px 7px;\n font-size: 11px;\n font-family: ui-monospace, Menlo, monospace;\n text-overflow: ellipsis;\n}\n.lib-charpick button {\n padding: 4px 8px;\n font-size: 11px;\n}\n.lib-blocked {\n margin: 0;\n color: var(--warn, #e7c86e);\n font-size: 12px;\n line-height: 1.5;\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 min-height: 0;\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.field input.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", ys = new Map(Nt.flatMap((e) => e.nodes.map((e) => [e.type, e.summary]))), bs = /* @__PURE__ */ new Set(), xs = null, Ss = null, Cs = null;
8010
- function ws(e) {
8011
- Ss = e;
8012
- }
8013
- function Ts(e) {
8014
- xs = e;
8161
+ var Ss = "\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/* A grid item's default min-width is auto: it refuses to shrink below its\n content's MIN-CONTENT width. One nowrap asset description was enough to push\n a whole field past the inspector — and no max-width: 100% further down can\n fix it, because 100% is then 100% of the already-grown track. The clamp has\n to come from here. */\n.field > * {\n min-width: 0;\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/* .field.wide is declared EARLIER and at equal specificity, so the rule above\n silently won inside a card: a full-width field (the asset picker) went back\n to two columns and its dropdown panel — a third grid child — was auto-placed\n into the 78px label column, four times too narrow to read. */\n.subcard .field.wide {\n grid-template-columns: 1fr;\n}\n.subcard .field.wide.has-const-picker {\n grid-template-columns: 1fr auto;\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: center;\n}\n.asset-control input {\n flex: 1;\n min-width: 0;\n}\n.asset-toggle {\n flex: none;\n /* square and matched to the input beside it. The base control rule's 9px of\n side padding does not fit a 26px box, which left the chevron off-centre in\n a button that looked taller than it was wide. */\n width: 30px;\n height: 30px;\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\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 min-width: 0;\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 min-width: 0;\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 /* A flex ITEM has the same auto-min-width default as a grid item, so this is\n what stops one long description widening the whole panel.\n overflow-x, NOT overflow: plain hidden also removes the automatic\n MINIMUM SIZE on the block axis, and this button is an item of a\n max-height scroll container — so every row shrank to fit 220px instead of\n scrolling, collapsing 46px rows to 16px with the text squashed to 1px.\n flex: none is the other half: items in a capped column must keep their\n height and let the container scroll. */\n min-width: 0;\n overflow-x: clip;\n flex: none;\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 /* asset keys are short today and a long one must still not widen the panel */\n max-width: 100%;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\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/* A row carrying the library button has THREE cells. Without this the button is\n a third child of a two-column grid: it wraps onto a second row INSIDE the\n label column, gets 52px to live in, and crushes \"📚 library\" against its own\n borders — which reads as a button with no padding, and no amount of padding\n fixes it. */\n.field.has-lib {\n grid-template-columns: 92px 1fr auto;\n}\n.asset-editor .field.has-lib {\n grid-template-columns: 52px 1fr auto;\n}\n.subcard .field.has-lib {\n grid-template-columns: 78px 1fr auto;\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/* an asset the renderer could not fetch: the node is fine, the art is not */\n.asset-row.asset-failed .asset-key {\n color: #f87171;\n text-decoration: underline dotted #f87171;\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/* The third grid column a bound-able prop row opens for its 🔗 picker. The\n .field grid is 92px 1fr; without this the picker is auto-placed into row 2\n column 1, tucked under the label where nobody finds it. */\n.field.has-const-picker {\n grid-template-columns: 92px 1fr auto;\n}\n.field.wide.has-const-picker {\n grid-template-columns: 1fr auto;\n}\n.const-picker {\n flex: none;\n width: 30px;\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: 12px;\n /* The base select rule reserves 9px + 30px of horizontal padding for its\n drawn chevron. In a 30px box that leaves the link glyph nowhere to be, so\n the control rendered as an empty rectangle. This one has no chevron. */\n padding: 0;\n background-image: none;\n text-align: center;\n text-align-last: center;\n height: 30px;\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 /* NOT stretch: .field carries a 7px bottom margin, so a stretched button\n grew to cover it and stood a third taller than the input beside it. */\n align-items: center;\n}\n.const-row .field {\n flex: 1;\n min-width: 0;\n}\n.const-del {\n flex: none;\n width: 30px;\n /* square, and matched to the input it sits beside, rather than to whatever\n the row's tallest margin box happens to be */\n height: 30px;\n /* the field's own bottom margin is the row's spacing; without this the button\n sits 3.5px low against the input */\n margin-bottom: 7px;\n /* the glyph sat right of centre: the base control rule gives every button\n 9px of side padding, which a 30px box has no room for */\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\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/* ---- scene strings (localization) ---- */\n/* One block per key: the inspector is ~300px, and a column per language gave\n each cell 48px with three languages — measured in the real panel. */\n.strings-langs {\n display: flex;\n flex-wrap: wrap;\n gap: 5px;\n align-items: center;\n margin-bottom: 8px;\n}\n.strings-langs-label {\n font-size: 10px;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--text-faint);\n margin-right: 2px;\n}\n.strings-lang-chip {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n padding: 1px 5px;\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: 10px;\n}\n.strings-locale-del {\n padding: 0 1px;\n border: 0;\n background: none;\n color: var(--text-faint);\n font-size: 9px;\n line-height: 1;\n cursor: pointer;\n}\n.strings-locale-del:hover {\n color: var(--rose);\n}\n.strings-key-row {\n display: flex;\n gap: 6px;\n align-items: center;\n margin-top: 8px;\n}\n.strings-key {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 11px;\n color: var(--accent);\n}\n.strings-key-row .const-del {\n margin-bottom: 0;\n}\n.strings-row {\n display: flex;\n gap: 6px;\n align-items: center;\n margin: 3px 0 0 10px;\n}\n.strings-lang-tag {\n flex: 0 0 22px;\n font-size: 10px;\n color: var(--text-faint);\n text-align: right;\n}\n.strings-cell {\n flex: 1;\n min-width: 0;\n}\n/* Not translated: the English it will silently fall back to, greyed. That\n fallback is the documented design, not an error — so it is dimmed, not red. */\n.strings-cell.strings-fallback::placeholder {\n color: var(--text-faint);\n font-style: italic;\n}\n/* No BASE text: nothing to fall back to, so the raw key paints on screen. */\n.strings-cell.strings-missing-base {\n border-color: var(--rose);\n}\n.strings-cell.strings-missing-base::placeholder {\n color: var(--rose);\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 height: 30px;\n /* room for the word: a bare icon next to a URL field reads as decoration,\n and nobody clicks decoration */\n padding: 0 16px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 7px;\n white-space: nowrap;\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n background: var(--bg-1);\n color: var(--fg-1);\n font-size: 12px;\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 min-height: 0;\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 /* Grid items size to their content unless told not to. Without this the\n results pane grows past the dialog and takes the scrollbar with it. */\n min-height: 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 /* A flex child will not shrink below its content without this, so flex:1\n plus overflow-y:auto grew the grid instead of scrolling it: the results ran\n off the bottom of the dialog with no way to reach them, and the\n infinite-scroll sentinel sat permanently in view. */\n min-height: 0;\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(112px, 1fr));\n /* Not \"auto\": once the grid has a definite height, an auto row sizes to its\n MIN-content, and a thumbnail sized by aspect-ratio contributes nothing to\n that — every row collapsed to the 14px of its filename. */\n grid-auto-rows: max-content;\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/* On the shelf, but not something this field can take. Shown — a library that\n hides most of itself is worse — just clearly second. */\n.lib-card.off-kind {\n opacity: 0.42;\n}\n.lib-card.off-kind:hover,\n.lib-card.off-kind.active {\n opacity: 1;\n}\n.lib-sentinel {\n grid-column: 1 / -1;\n height: 1px;\n}\n.lib-charpick {\n display: grid;\n grid-template-columns: auto 1fr auto auto;\n align-items: center;\n gap: 6px;\n padding: 7px 8px;\n border: 1px solid var(--line);\n border-radius: var(--r-sm);\n background: var(--bg-2);\n}\n.lib-charpick-label {\n color: var(--text-faint);\n font-size: 11px;\n white-space: nowrap;\n}\n.lib-charpick input {\n min-width: 0;\n padding: 4px 7px;\n font-size: 11px;\n font-family: ui-monospace, Menlo, monospace;\n text-overflow: ellipsis;\n}\n.lib-charpick button {\n padding: 4px 8px;\n font-size: 11px;\n}\n.lib-blocked {\n margin: 0;\n color: var(--warn, #e7c86e);\n font-size: 12px;\n line-height: 1.5;\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 min-height: 0;\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.field input.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";
8162
+ //#endregion
8163
+ //#region src/sub-scenes.ts
8164
+ async function Cs(e, t, n = 8) {
8165
+ let r = /* @__PURE__ */ new Map(), i = [e];
8166
+ for (let e = 0; e < n && i.length > 0; e++) {
8167
+ let e = /* @__PURE__ */ new Set();
8168
+ for (let t of i) ws(t.root, e);
8169
+ let n = [...e].filter((e) => !r.has(e));
8170
+ if (n.length === 0) break;
8171
+ let a = await Promise.all(n.map(async (e) => {
8172
+ try {
8173
+ return [e, await t.loadScene(e)];
8174
+ } catch {
8175
+ return [e, null];
8176
+ }
8177
+ }));
8178
+ i = [];
8179
+ for (let [e, t] of a) t && (r.set(e, t), i.push(t));
8180
+ }
8181
+ return r;
8015
8182
  }
8016
- function Es(e) {
8017
- Cs = e;
8183
+ function ws(e, t) {
8184
+ if (!e || typeof e != "object") return;
8185
+ let n = e.instance;
8186
+ typeof n == "string" && n !== "" && t.add(n);
8187
+ for (let n of e.children ?? []) ws(n, t);
8018
8188
  }
8019
- var Ds = null, Os = null, ks = null;
8189
+ //#endregion
8190
+ //#region src/tree.ts
8191
+ var Ts = new Map(Nt.flatMap((e) => e.nodes.map((e) => [e.type, e.summary]))), Es = /* @__PURE__ */ new Set(), Ds = null, Os = null, ks = null;
8020
8192
  function As(e) {
8193
+ Os = e;
8194
+ }
8195
+ function js(e) {
8196
+ Ds = e;
8197
+ }
8198
+ function Ms(e) {
8199
+ ks = e;
8200
+ }
8201
+ var Ns = null, Ps = null, Fs = null;
8202
+ function Is(e) {
8021
8203
  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";
8022
8204
  }
8023
- function js(e, t) {
8205
+ function Ls(e, t) {
8024
8206
  e.textContent = "";
8025
8207
  let n = document.createElement("div");
8026
8208
  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);
@@ -8030,54 +8212,54 @@ function js(e, t) {
8030
8212
  t.className = "muted-note explorer-empty", t.textContent = "no root node — pick a type below and + to start the scene", e.appendChild(t);
8031
8213
  return;
8032
8214
  }
8033
- Fs(r, t.selection), e.appendChild(Is(r, [], t, "")), Ns(e, t.selection);
8215
+ Vs(r, t.selection), e.appendChild(Hs(r, [], t, "")), zs(e, t.selection);
8034
8216
  }
8035
- var Ms = null;
8036
- function Ns(e, t) {
8217
+ var Rs = null;
8218
+ function zs(e, t) {
8037
8219
  let n = JSON.stringify(t);
8038
- n !== Ms && (Ms = n, e.querySelector(".tree-row.selected")?.scrollIntoView?.({
8220
+ n !== Rs && (Rs = n, e.querySelector(".tree-row.selected")?.scrollIntoView?.({
8039
8221
  block: "nearest",
8040
8222
  inline: "nearest"
8041
8223
  }));
8042
8224
  }
8043
- function Ps() {
8044
- Ms = null;
8225
+ function Bs() {
8226
+ Rs = null;
8045
8227
  }
8046
- function Fs(e, t) {
8228
+ function Vs(e, t) {
8047
8229
  if (!t) return;
8048
8230
  let n = e, r = "";
8049
8231
  for (let e of t) {
8050
- r = r ? `${r}/${n.name}` : String(n.name), bs.delete(r);
8232
+ r = r ? `${r}/${n.name}` : String(n.name), Es.delete(r);
8051
8233
  let t = n.children?.[e];
8052
8234
  if (!t) return;
8053
8235
  n = t;
8054
8236
  }
8055
8237
  }
8056
- function Is(e, t, n, r) {
8057
- let i = r ? `${r}/${e.name}` : String(e.name), a = (e.children?.length ?? 0) > 0, o = bs.has(i), s = document.createElement("div");
8238
+ function Hs(e, t, n, r) {
8239
+ let i = r ? `${r}/${e.name}` : String(e.name), a = (e.children?.length ?? 0) > 0, o = Es.has(i), s = document.createElement("div");
8058
8240
  s.className = "tree-branch";
8059
8241
  let c = document.createElement("div");
8060
- c.className = `tree-row${n.isSelected(t) ? " selected" : ""}`, c.draggable = t.length > 0 && ks !== i;
8242
+ c.className = `tree-row${n.isSelected(t) ? " selected" : ""}`, c.draggable = t.length > 0 && Fs !== i;
8061
8243
  let l = document.createElement("span");
8062
8244
  l.className = `chevron${a ? "" : " leaf"}${o ? " collapsed" : ""}`, a ? l.appendChild(Ye()) : l.textContent = "·", a && l.addEventListener("click", (e) => {
8063
- e.stopPropagation(), o ? bs.delete(i) : bs.add(i), n.select(n.selection);
8245
+ e.stopPropagation(), o ? Es.delete(i) : Es.add(i), n.select(n.selection);
8064
8246
  });
8065
8247
  let u = document.createElement("span");
8066
- if (u.className = `tree-icon ${As(e.type)}`, u.appendChild(Je(e.type)), u.title = e.type ?? "instance", u.addEventListener("click", (t) => {
8067
- t.stopPropagation(), Ls(u, e.type ?? "instance");
8068
- }), c.append(l, u), ks === i) {
8248
+ if (u.className = `tree-icon ${Is(e.type)}`, u.appendChild(Je(e.type)), u.title = e.type ?? "instance", u.addEventListener("click", (t) => {
8249
+ t.stopPropagation(), Us(u, e.type ?? "instance");
8250
+ }), c.append(l, u), Fs === i) {
8069
8251
  let r = document.createElement("input");
8070
8252
  r.className = "rename-input", r.value = e.name ?? "";
8071
8253
  let i = () => {
8072
- ks = null;
8254
+ Fs = null;
8073
8255
  let i = r.value.trim();
8074
8256
  if (i && i !== e.name) {
8075
8257
  let e = n.renameNode(t, i) ?? [];
8076
- e.length > 0 && Cs?.(e);
8258
+ e.length > 0 && ks?.(e);
8077
8259
  } else n.select(n.selection);
8078
8260
  };
8079
8261
  r.addEventListener("keydown", (e) => {
8080
- e.stopPropagation(), e.key === "Enter" && i(), e.key === "Escape" && (ks = null, n.select(n.selection));
8262
+ e.stopPropagation(), e.key === "Enter" && i(), e.key === "Escape" && (Fs = null, n.select(n.selection));
8081
8263
  });
8082
8264
  for (let e of [
8083
8265
  "click",
@@ -8091,38 +8273,38 @@ function Is(e, t, n, r) {
8091
8273
  } else {
8092
8274
  let r = document.createElement("span");
8093
8275
  r.className = "tree-name", r.textContent = e.name ?? "(unnamed)", r.addEventListener("dblclick", (e) => {
8094
- e.stopPropagation(), ks = i, n.select(t);
8276
+ e.stopPropagation(), Fs = i, n.select(t);
8095
8277
  }), c.appendChild(r);
8096
8278
  }
8097
8279
  if (c.addEventListener("click", (e) => {
8098
- a && !e.metaKey && !e.ctrlKey && (o ? bs.delete(i) : bs.add(i)), n.select(t, { toggle: e.metaKey || e.ctrlKey });
8280
+ a && !e.metaKey && !e.ctrlKey && (o ? Es.delete(i) : Es.add(i)), n.select(t, { toggle: e.metaKey || e.ctrlKey });
8099
8281
  }), c.addEventListener("contextmenu", (e) => {
8100
- e.preventDefault(), n.isSelected(t) || n.select(t), Rs(e.clientX, e.clientY, n, t, i);
8101
- }), qs(c, t, n), s.appendChild(c), a && !o) {
8282
+ e.preventDefault(), n.isSelected(t) || n.select(t), Ws(e.clientX, e.clientY, n, t, i);
8283
+ }), $s(c, t, n), s.appendChild(c), a && !o) {
8102
8284
  let r = document.createElement("div");
8103
8285
  r.className = "tree-children", (e.children ?? []).forEach((e, a) => {
8104
- r.appendChild(Is(e, [...t, a], n, i));
8286
+ r.appendChild(Hs(e, [...t, a], n, i));
8105
8287
  }), s.appendChild(r);
8106
8288
  }
8107
8289
  return s;
8108
8290
  }
8109
- function Ls(e, t) {
8110
- Us();
8291
+ function Us(e, t) {
8292
+ Ys();
8111
8293
  let n = document.createElement("div");
8112
8294
  n.className = "balloon floating";
8113
8295
  let r = document.createElement("span");
8114
8296
  r.className = "balloon-title", r.textContent = t, n.appendChild(r);
8115
- let i = ys.get(t);
8297
+ let i = Ts.get(t);
8116
8298
  if (i) {
8117
8299
  let e = document.createElement("span");
8118
8300
  e.textContent = I(i), n.appendChild(e);
8119
8301
  }
8120
8302
  document.body.appendChild(n);
8121
8303
  let a = e.getBoundingClientRect();
8122
- n.style.left = `${Math.min(innerWidth - 240, a.right + 8)}px`, n.style.top = `${Math.max(8, a.top - 6)}px`, Ws(n);
8304
+ n.style.left = `${Math.min(innerWidth - 240, a.right + 8)}px`, n.style.top = `${Math.max(8, a.top - 6)}px`, Xs(n);
8123
8305
  }
8124
- function Rs(e, t, n, r, i) {
8125
- Us();
8306
+ function Ws(e, t, n, r, i) {
8307
+ Ys();
8126
8308
  let a = n.allSelections(), o = a.length === 1 && r.length > 0, s = document.createElement("div");
8127
8309
  s.className = "context-menu floating";
8128
8310
  let c = (e, t, n) => {
@@ -8134,52 +8316,52 @@ function Rs(e, t, n, r, i) {
8134
8316
  e.textContent = n.kbd, r.appendChild(e);
8135
8317
  }
8136
8318
  t && r.addEventListener("click", () => {
8137
- Us(), t();
8319
+ Ys(), t();
8138
8320
  }), s.appendChild(r);
8139
8321
  };
8140
8322
  c(`duplicate${a.length > 1 ? ` ×${a.length}` : ""}`, () => {
8141
8323
  for (let e of [...a].reverse()) n.duplicateNode(e);
8142
- }), c("frame in view", Ss && r.length > 0 ? () => {
8143
- n.select(r), Ss?.();
8324
+ }), c("frame in view", Os && r.length > 0 ? () => {
8325
+ n.select(r), Os?.();
8144
8326
  } : null, { kbd: "F" }), c("rename", o ? () => {
8145
- ks = i, n.select(r);
8146
- } : null, { kbd: "dbl-click" }), s.appendChild(zs()), c("cut", r.length > 0 ? () => Bs(n, !0) : null), c("copy", r.length > 0 ? () => Bs(n, !1) : null), c(`paste as child${Os ? ` (${Os.nodes.length})` : ""}`, Os ? () => Vs(n, r) : null), s.appendChild(zs()), c("delete", r.length > 0 ? () => (xs ?? ((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`, Ws(s);
8327
+ Fs = i, n.select(r);
8328
+ } : null, { kbd: "dbl-click" }), s.appendChild(Gs()), c("cut", r.length > 0 ? () => Ks(n, !0) : null), c("copy", r.length > 0 ? () => Ks(n, !1) : null), c(`paste as child${Ps ? ` (${Ps.nodes.length})` : ""}`, Ps ? () => qs(n, r) : null), s.appendChild(Gs()), c("delete", r.length > 0 ? () => (Ds ?? ((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`, Xs(s);
8147
8329
  }
8148
- function zs() {
8330
+ function Gs() {
8149
8331
  let e = document.createElement("div");
8150
8332
  return e.className = "menu-divider", e;
8151
8333
  }
8152
- function Bs(e, t) {
8334
+ function Ks(e, t) {
8153
8335
  let n = e.allSelections().filter((e) => e.length > 0).map((t) => e.nodeAt(t)).filter((e) => e !== null);
8154
- Os = {
8336
+ Ps = {
8155
8337
  nodes: n.map((e) => JSON.parse(JSON.stringify(e))),
8156
8338
  cut: t ? n : null
8157
8339
  };
8158
8340
  }
8159
- function Vs(e, t) {
8160
- if (Os) {
8161
- for (let n of Os.nodes) e.insertNode(n, t);
8162
- if (Os.cut) {
8163
- let t = e.working.root, n = Os.cut.map((e) => Hs(t, e)).filter((e) => e !== null);
8164
- n.length > 0 && e.removeNodes(n), Os = {
8165
- nodes: Os.nodes,
8341
+ function qs(e, t) {
8342
+ if (Ps) {
8343
+ for (let n of Ps.nodes) e.insertNode(n, t);
8344
+ if (Ps.cut) {
8345
+ let t = e.working.root, n = Ps.cut.map((e) => Js(t, e)).filter((e) => e !== null);
8346
+ n.length > 0 && e.removeNodes(n), Ps = {
8347
+ nodes: Ps.nodes,
8166
8348
  cut: null
8167
8349
  };
8168
8350
  }
8169
8351
  }
8170
8352
  }
8171
- function Hs(e, t) {
8353
+ function Js(e, t) {
8172
8354
  if (e === t) return [];
8173
8355
  for (let [n, r] of (e.children ?? []).entries()) {
8174
- let e = Hs(r, t);
8356
+ let e = Js(r, t);
8175
8357
  if (e) return [n, ...e];
8176
8358
  }
8177
8359
  return null;
8178
8360
  }
8179
- function Us() {
8361
+ function Ys() {
8180
8362
  for (let e of document.querySelectorAll(".floating")) e.remove();
8181
8363
  }
8182
- function Ws(e) {
8364
+ function Xs(e) {
8183
8365
  let t = (r) => {
8184
8366
  e.contains(r.target) || (e.remove(), document.removeEventListener("pointerdown", t, !0), document.removeEventListener("keydown", n, !0));
8185
8367
  }, n = (r) => {
@@ -8189,38 +8371,38 @@ function Ws(e) {
8189
8371
  document.addEventListener("pointerdown", t, !0), document.addEventListener("keydown", n, !0);
8190
8372
  }, 0);
8191
8373
  }
8192
- function Gs(e, t) {
8374
+ function Zs(e, t) {
8193
8375
  let n = t.getBoundingClientRect(), r = (e.clientY - n.top) / n.height;
8194
8376
  return r < .25 ? "before" : r > .75 ? "after" : "into";
8195
8377
  }
8196
- function Ks(e) {
8378
+ function Qs(e) {
8197
8379
  e.classList.remove("drop-into", "drop-before", "drop-after");
8198
8380
  }
8199
- function qs(e, t, n) {
8381
+ function $s(e, t, n) {
8200
8382
  e.addEventListener("dragstart", (r) => {
8201
- Ds = n.isSelected(t) ? n.allSelections() : [t], r.dataTransfer?.setData("text/plain", ""), r.dataTransfer && (r.dataTransfer.effectAllowed = "move"), e.classList.add("dragging");
8383
+ Ns = n.isSelected(t) ? n.allSelections() : [t], r.dataTransfer?.setData("text/plain", ""), r.dataTransfer && (r.dataTransfer.effectAllowed = "move"), e.classList.add("dragging");
8202
8384
  }), e.addEventListener("dragend", () => {
8203
- Ds = null, e.classList.remove("dragging");
8385
+ Ns = null, e.classList.remove("dragging");
8204
8386
  }), e.addEventListener("dragover", (n) => {
8205
- if (!Ds || Ds.some((e) => e.length <= t.length && e.every((e, n) => e === t[n]))) return;
8206
- n.preventDefault(), n.dataTransfer && (n.dataTransfer.dropEffect = "move"), Ks(e);
8207
- let r = t.length === 0 ? "into" : Gs(n, e);
8387
+ if (!Ns || Ns.some((e) => e.length <= t.length && e.every((e, n) => e === t[n]))) return;
8388
+ n.preventDefault(), n.dataTransfer && (n.dataTransfer.dropEffect = "move"), Qs(e);
8389
+ let r = t.length === 0 ? "into" : Zs(n, e);
8208
8390
  e.classList.add(`drop-${r}`);
8209
- }), e.addEventListener("dragleave", () => Ks(e)), e.addEventListener("drop", (r) => {
8210
- if (Ks(e), !Ds) return;
8391
+ }), e.addEventListener("dragleave", () => Qs(e)), e.addEventListener("drop", (r) => {
8392
+ if (Qs(e), !Ns) return;
8211
8393
  r.preventDefault();
8212
- let i = t.length === 0 ? "into" : Gs(r, e), a = n.moveNodes(Ds, t, i);
8213
- Ds = null, a?.[0] && n.select(a[0]);
8394
+ let i = t.length === 0 ? "into" : Zs(r, e), a = n.moveNodes(Ns, t, i);
8395
+ Ns = null, a?.[0] && n.select(a[0]);
8214
8396
  });
8215
8397
  }
8216
8398
  //#endregion
8217
8399
  //#region src/transform-gizmo.ts
8218
- var Js = {
8400
+ var ec = {
8219
8401
  x: "#fb7185",
8220
8402
  y: "#86efac",
8221
8403
  z: "#7aa2ff"
8222
8404
  };
8223
- function Ys(e, t, n) {
8405
+ function tc(e, t, n) {
8224
8406
  let r = t - e.origin.x, i = n - e.origin.y;
8225
8407
  if (Math.abs(r) <= e.centerSize && Math.abs(i) <= e.centerSize) return { kind: "center" };
8226
8408
  for (let t of e.axes) {
@@ -8234,11 +8416,11 @@ function Ys(e, t, n) {
8234
8416
  }
8235
8417
  return null;
8236
8418
  }
8237
- function Xs(e, t, n) {
8419
+ function nc(e, t, n) {
8238
8420
  let r = e.sx * e.sx + e.sy * e.sy;
8239
8421
  return r < 1 ? 0 : (t * e.sx + n * e.sy) / r * e.worldPerUnit;
8240
8422
  }
8241
- function Zs(e, t, n, r = !1) {
8423
+ function rc(e, t, n, r = !1) {
8242
8424
  let { origin: i, axes: a, centerSize: o } = t;
8243
8425
  for (let t of a) {
8244
8426
  let a = n?.kind === "axis" && n.axis === t.axis;
@@ -8249,16 +8431,16 @@ function Zs(e, t, n, r = !1) {
8249
8431
  let s = n?.kind === "center";
8250
8432
  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;
8251
8433
  }
8252
- function Qs(e, t, n) {
8434
+ function ic(e, t, n) {
8253
8435
  return Math.atan2(n - e.y, t - e.x) * 180 / Math.PI;
8254
8436
  }
8255
- function $s(e, t) {
8437
+ function ac(e, t) {
8256
8438
  let n = t - e;
8257
8439
  for (; n > 180;) n -= 360;
8258
8440
  for (; n <= -180;) n += 360;
8259
8441
  return n;
8260
8442
  }
8261
- function ec(e, t, n, r) {
8443
+ function oc(e, t, n, r) {
8262
8444
  let i = null, a = r;
8263
8445
  for (let r of e) for (let e of r.points) {
8264
8446
  let o = Math.hypot(t - e.x, n - e.y);
@@ -8266,11 +8448,11 @@ function ec(e, t, n, r) {
8266
8448
  }
8267
8449
  return i;
8268
8450
  }
8269
- function tc(e, t, n) {
8451
+ function sc(e, t, n) {
8270
8452
  for (let r of t) {
8271
8453
  if (r.points.length < 2) continue;
8272
8454
  let t = n === r.axis;
8273
- e.strokeStyle = Js[r.axis], e.globalAlpha = t ? 1 : .75, e.lineWidth = t ? 3 : 2, e.beginPath();
8455
+ e.strokeStyle = ec[r.axis], e.globalAlpha = t ? 1 : .75, e.lineWidth = t ? 3 : 2, e.beginPath();
8274
8456
  let i = r.points[0];
8275
8457
  e.moveTo(i.x, i.y);
8276
8458
  for (let t of r.points.slice(1)) e.lineTo(t.x, t.y);
@@ -8278,14 +8460,25 @@ function tc(e, t, n) {
8278
8460
  }
8279
8461
  e.globalAlpha = 1;
8280
8462
  }
8281
- function nc(e, t, n, r) {
8463
+ function cc(e, t, n, r) {
8282
8464
  e.font = "600 11px ui-monospace, Menlo, monospace";
8283
8465
  let i = e.measureText(r).width + 14;
8284
8466
  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);
8285
8467
  }
8286
8468
  //#endregion
8287
8469
  //#region src/viewport.ts
8288
- var rc = class {
8470
+ var lc = class {
8471
+ subScenes = /* @__PURE__ */ new Map();
8472
+ setSubScenes(e) {
8473
+ this.subScenes = e;
8474
+ }
8475
+ get resolver() {
8476
+ return this.subScenes.size === 0 ? {} : { resolveScene: (e) => {
8477
+ let t = this.subScenes.get(e);
8478
+ if (!t) throw Error(`no sub-scene fetched for '${e}'`);
8479
+ return t;
8480
+ } };
8481
+ }
8289
8482
  engine;
8290
8483
  editCanvas;
8291
8484
  overlay;
@@ -8393,7 +8586,10 @@ var rc = class {
8393
8586
  let n;
8394
8587
  try {
8395
8588
  let t = structuredClone(e);
8396
- yc(t), n = f(t, { stubAllBehaviors: !0 });
8589
+ Tc(t), n = f(t, {
8590
+ stubAllBehaviors: !0,
8591
+ ...this.resolver
8592
+ });
8397
8593
  } catch (e) {
8398
8594
  return e instanceof Error ? e.message : String(e);
8399
8595
  }
@@ -8409,7 +8605,7 @@ var rc = class {
8409
8605
  canvas: this.editCanvas,
8410
8606
  engine: this.engine
8411
8607
  }), this.renderer3d.ignoreStatic = !0;
8412
- let t = hc(e.root);
8608
+ let t = xc(e.root);
8413
8609
  if (t) {
8414
8610
  let [e, n, r] = t;
8415
8611
  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 = [
@@ -8431,13 +8627,16 @@ var rc = class {
8431
8627
  if (!e.root) return null;
8432
8628
  try {
8433
8629
  let t = structuredClone(e);
8434
- return yc(t), f(t, { stubAllBehaviors: !0 }), null;
8630
+ return Tc(t), f(t, {
8631
+ stubAllBehaviors: !0,
8632
+ ...this.resolver
8633
+ }), null;
8435
8634
  } catch (e) {
8436
8635
  return e instanceof Error ? e.message : String(e);
8437
8636
  }
8438
8637
  }
8439
8638
  defaultView(e) {
8440
- let t = gc(e.root);
8639
+ let t = Sc(e.root);
8441
8640
  if (t) return {
8442
8641
  cx: t[0],
8443
8642
  cy: t[1],
@@ -8514,7 +8713,7 @@ var rc = class {
8514
8713
  this.gizmoMode = e, this.cb.onModeChanged(e);
8515
8714
  }
8516
8715
  screen2D(e) {
8517
- let t = mc(e);
8716
+ let t = bc(e);
8518
8717
  return this.renderer2d ? this.renderer2d.isUiNode(e) ? this.renderer2d.screenFromUi(t.x, t.y) : this.renderer2d.screenFromWorld(t.x, t.y) : t;
8519
8718
  }
8520
8719
  point2D(e, t, n) {
@@ -8538,13 +8737,13 @@ var rc = class {
8538
8737
  sx: 64,
8539
8738
  sy: 0,
8540
8739
  worldPerUnit: 64 / r,
8541
- color: Js.x
8740
+ color: ec.x
8542
8741
  }, {
8543
8742
  axis: "y",
8544
8743
  sx: 0,
8545
8744
  sy: 64,
8546
8745
  worldPerUnit: 64 / r,
8547
- color: Js.y
8746
+ color: ec.y
8548
8747
  }]
8549
8748
  };
8550
8749
  }
@@ -8578,7 +8777,7 @@ var rc = class {
8578
8777
  sx: n.x - r.x,
8579
8778
  sy: n.y - r.y,
8580
8779
  worldPerUnit: o,
8581
- color: Js[e]
8780
+ color: ec[e]
8582
8781
  });
8583
8782
  }
8584
8783
  return {
@@ -8652,11 +8851,11 @@ var rc = class {
8652
8851
  return null;
8653
8852
  }
8654
8853
  orbitVectors() {
8655
- let { yaw: e, pitch: t, dist: n, target: r } = this.orbit, i = Math.cos(t), a = new G(r[0] + n * i * Math.sin(e), r[1] + n * Math.sin(t), r[2] + n * i * Math.cos(e)), o = new G(r[0], r[1], r[2]).sub(a).normalize(), s = new G().crossVectors(o, ac).normalize();
8854
+ 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, dc).normalize();
8656
8855
  return {
8657
8856
  pos: a,
8658
8857
  right: s,
8659
- up: new G().crossVectors(s, o).normalize(),
8858
+ up: new K().crossVectors(s, o).normalize(),
8660
8859
  forward: o
8661
8860
  };
8662
8861
  }
@@ -8678,13 +8877,13 @@ var rc = class {
8678
8877
  for (let [t] of this.pathOf) if (t instanceof S && (t.current || !e) && (e = t, t.current)) break;
8679
8878
  let t = e ? e._ensureObject3D() : null;
8680
8879
  if (t) {
8681
- t.getWorldPosition(oc), sc.set(0, 0, -1).applyQuaternion(t.getWorldQuaternion(cc));
8880
+ t.getWorldPosition(fc), pc.set(0, 0, -1).applyQuaternion(t.getWorldQuaternion(mc));
8682
8881
  let e = Math.min(40, Math.max(3, this.orbit.dist));
8683
8882
  this.orbit.target = [
8684
- oc.x + sc.x * e,
8685
- oc.y + sc.y * e,
8686
- oc.z + sc.z * e
8687
- ], this.orbit.dist = e, this.orbit.yaw = Math.atan2(-sc.x, -sc.z), this.orbit.pitch = Math.asin(Math.max(-.99, Math.min(.99, -sc.y)));
8883
+ fc.x + pc.x * e,
8884
+ fc.y + pc.y * e,
8885
+ fc.z + pc.z * e
8886
+ ], this.orbit.dist = e, this.orbit.yaw = Math.atan2(-pc.x, -pc.z), this.orbit.pitch = Math.asin(Math.max(-.99, Math.min(.99, -pc.y)));
8688
8887
  }
8689
8888
  this.renderer3d.viewOverride = null;
8690
8889
  return;
@@ -8704,9 +8903,9 @@ var rc = class {
8704
8903
  gizmoHandles() {
8705
8904
  let { right: e, up: t, forward: n } = this.orbitVectors(), r = this.gizmoCenter(), i = [];
8706
8905
  for (let [a, o] of [
8707
- ["x", new G(1, 0, 0)],
8708
- ["y", new G(0, 1, 0)],
8709
- ["z", new G(0, 0, 1)]
8906
+ ["x", new K(1, 0, 0)],
8907
+ ["y", new K(0, 1, 0)],
8908
+ ["z", new K(0, 0, 1)]
8710
8909
  ]) for (let s of [1, -1]) {
8711
8910
  let c = o.clone().multiplyScalar(s);
8712
8911
  i.push({
@@ -8780,7 +8979,7 @@ var rc = class {
8780
8979
  let t = this.overlay.clientWidth, n = this.overlay.clientHeight, r = Math.min(devicePixelRatio || 1, 2);
8781
8980
  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;
8782
8981
  if (this.rendererDim === "3d") {
8783
- this.drawGizmo(e), this.drawModeGizmo(e), this.readout && nc(e, this.readout.x, this.readout.y, this.readout.text);
8982
+ this.drawGizmo(e), this.drawModeGizmo(e), this.readout && cc(e, this.readout.x, this.readout.y, this.readout.text);
8784
8983
  return;
8785
8984
  }
8786
8985
  if (!this.renderer2d) return;
@@ -8805,16 +9004,16 @@ var rc = class {
8805
9004
  ]) e.fillRect(n - 3, r - 3, 6, 6);
8806
9005
  }
8807
9006
  }
8808
- this.drawModeGizmo(e), this.readout && nc(e, this.readout.x, this.readout.y, this.readout.text);
9007
+ this.drawModeGizmo(e), this.readout && cc(e, this.readout.x, this.readout.y, this.readout.text);
8809
9008
  }
8810
9009
  drawModeGizmo(e) {
8811
9010
  if (this.gizmoMode === "rotate") {
8812
9011
  let t = this.ringLayout();
8813
- t && tc(e, t.rings, this.activeRing);
9012
+ t && sc(e, t.rings, this.activeRing);
8814
9013
  return;
8815
9014
  }
8816
9015
  let t = this.gizmoLayout();
8817
- t && Zs(e, t, this.gizmoActive, this.gizmoMode === "scale");
9016
+ t && rc(e, t, this.gizmoActive, this.gizmoMode === "scale");
8818
9017
  }
8819
9018
  pointBounds(e) {
8820
9019
  if (!this.renderer2d) return null;
@@ -8867,7 +9066,7 @@ var rc = class {
8867
9066
  let e = this.overlay, t = null, n = null, r = !1, i = null, a = null, o = null, s = null, c = null, l = (t) => {
8868
9067
  let n = this.ringLayout();
8869
9068
  if (!n) return !1;
8870
- let r = ec(n.rings, t.offsetX, t.offsetY, 9);
9069
+ let r = oc(n.rings, t.offsetX, t.offsetY, 9);
8871
9070
  if (!r) return !1;
8872
9071
  let i = this.liveSelected();
8873
9072
  if (!i) return !1;
@@ -8881,13 +9080,13 @@ var rc = class {
8881
9080
  axis: r,
8882
9081
  node: i,
8883
9082
  origin: n.origin,
8884
- startAngle: Qs(n.origin, t.offsetX, t.offsetY),
9083
+ startAngle: ic(n.origin, t.offsetX, t.offsetY),
8885
9084
  startRotation: Array.isArray(a) ? [...a] : a ?? 0,
8886
9085
  sign: o
8887
9086
  }, this.activeRing = r, !0;
8888
9087
  }, u = (e) => {
8889
9088
  if (!c) return;
8890
- let { axis: t, node: n, origin: r, startAngle: i, startRotation: a, sign: o } = c, s = $s(i, Qs(r, e.offsetX, e.offsetY)) * o, l = e.shiftKey || this.shiftHeld ? 15 : null, u = (e) => {
9089
+ let { axis: t, node: n, origin: r, startAngle: i, startRotation: a, sign: o } = c, s = ac(i, ic(r, e.offsetX, e.offsetY)) * o, l = e.shiftKey || this.shiftHeld ? 15 : null, u = (e) => {
8891
9090
  let t = e + s;
8892
9091
  return l ? Math.round(t / l) * l : Math.round(t * 10) / 10;
8893
9092
  }, d;
@@ -8928,7 +9127,7 @@ var rc = class {
8928
9127
  if (this.gizmoMode === "rotate") return l(t);
8929
9128
  let n = this.gizmoLayout();
8930
9129
  if (!n) return !1;
8931
- let r = Ys(n, t.offsetX, t.offsetY);
9130
+ let r = tc(n, t.offsetX, t.offsetY);
8932
9131
  if (!r) return !1;
8933
9132
  let i = this.liveSelected();
8934
9133
  if (!i) return !1;
@@ -8953,12 +9152,12 @@ var rc = class {
8953
9152
  }, 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;
8954
9153
  if (n === "scale") {
8955
9154
  let n = Math.max(.05, 1 + (c - l) * .005), r = [...o];
8956
- if (t.kind === "axis") r[d[t.axis]] = ic(g((o[d[t.axis]] ?? 1) * n));
8957
- else for (let e = 0; e < r.length; e++) r[e] = ic(g((o[e] ?? 1) * n));
9155
+ if (t.kind === "axis") r[d[t.axis]] = uc(g((o[d[t.axis]] ?? 1) * n));
9156
+ else for (let e = 0; e < r.length; e++) r[e] = uc(g((o[e] ?? 1) * n));
8958
9157
  i.scale = r, this.readout = {
8959
9158
  x: e.offsetX,
8960
9159
  y: e.offsetY,
8961
- text: `×${r.map((e) => ic(e)).join(", ")}`
9160
+ text: `×${r.map((e) => uc(e)).join(", ")}`
8962
9161
  };
8963
9162
  return;
8964
9163
  }
@@ -8966,23 +9165,23 @@ var rc = class {
8966
9165
  if (t.kind === "axis") {
8967
9166
  let e = r.axes.find((e) => e.axis === t.axis);
8968
9167
  if (!e) return;
8969
- let n = Xs(e, c, l);
8970
- if (u) _[d[t.axis]] = ic(h((a[d[t.axis]] ?? 0) + n));
9168
+ let n = nc(e, c, l);
9169
+ if (u) _[d[t.axis]] = uc(h((a[d[t.axis]] ?? 0) + n));
8971
9170
  else {
8972
- let e = fc(i, t.axis === "x" ? n : 0, t.axis === "y" ? n : 0), r = t.axis === "x" ? e.x : e.y;
9171
+ let e = vc(i, t.axis === "x" ? n : 0, t.axis === "y" ? n : 0), r = t.axis === "x" ? e.x : e.y;
8973
9172
  _[d[t.axis]] = Math.round(h((a[d[t.axis]] ?? 0) + r));
8974
9173
  }
8975
9174
  } else if (u && this.renderer3d) {
8976
9175
  let { right: e, up: t } = this.renderer3d.cameraBasis(), n = this.orbit.dist * .0016;
8977
- _[0] = ic(h((a[0] ?? 0) + (e.x * c - t.x * l) * n)), _[1] = ic(h((a[1] ?? 0) + (e.y * c - t.y * l) * n)), _[2] = ic(h((a[2] ?? 0) + (e.z * c - t.z * l) * n));
9176
+ _[0] = uc(h((a[0] ?? 0) + (e.x * c - t.x * l) * n)), _[1] = uc(h((a[1] ?? 0) + (e.y * c - t.y * l) * n)), _[2] = uc(h((a[2] ?? 0) + (e.z * c - t.z * l) * n));
8978
9177
  } else if (this.renderer2d) {
8979
- let e = this.renderer2d.view(), t = fc(i, c / e.zoom, l / e.zoom);
9178
+ let e = this.renderer2d.view(), t = vc(i, c / e.zoom, l / e.zoom);
8980
9179
  _[0] = Math.round(h((a[0] ?? 0) + t.x)), _[1] = Math.round(h((a[1] ?? 0) + t.y));
8981
9180
  }
8982
9181
  i.position = _, this.readout = {
8983
9182
  x: e.offsetX,
8984
9183
  y: e.offsetY,
8985
- text: `[${_.map((e) => ic(e)).join(", ")}]`
9184
+ text: `[${_.map((e) => uc(e)).join(", ")}]`
8986
9185
  };
8987
9186
  }, m = () => {
8988
9187
  if (!s) return;
@@ -9091,7 +9290,7 @@ var rc = class {
9091
9290
  return;
9092
9291
  }
9093
9292
  if (t) {
9094
- let e = this.point2D(t.node, o.offsetX, o.offsetY), n = fc(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);
9293
+ let e = this.point2D(t.node, o.offsetX, o.offsetY), n = vc(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);
9095
9294
  t.node.position = [r, i];
9096
9295
  return;
9097
9296
  }
@@ -9142,9 +9341,9 @@ var rc = class {
9142
9341
  zoomToFit() {
9143
9342
  let e = this.liveSelected();
9144
9343
  if (this.rendererDim === "3d") {
9145
- let t = new oa();
9344
+ let t = new la();
9146
9345
  for (let [n] of this.pathOf) {
9147
- if (e && n !== e && !pc(n, e)) continue;
9346
+ if (e && n !== e && !yc(n, e)) continue;
9148
9347
  let r = n._object3D;
9149
9348
  r && (t.expandByObject(r), t.expandByPoint(r.getWorldPosition($)));
9150
9349
  }
@@ -9165,7 +9364,7 @@ var rc = class {
9165
9364
  0
9166
9365
  ], this.orbit.dist = 10;
9167
9366
  else {
9168
- let e = t.getCenter(new G()), n = t.getSize(new G());
9367
+ let e = t.getCenter(new K()), n = t.getSize(new K());
9169
9368
  this.orbit.target = [
9170
9369
  e.x,
9171
9370
  e.y,
@@ -9178,10 +9377,10 @@ var rc = class {
9178
9377
  if (!this.renderer2d) return;
9179
9378
  let t = this.editCanvas.clientWidth || 960, n = this.editCanvas.clientHeight || 540, r = Infinity, i = Infinity, a = -Infinity, o = -Infinity;
9180
9379
  for (let [t] of this.pathOf) {
9181
- if (e && t !== e && !pc(t, e)) continue;
9380
+ if (e && t !== e && !yc(t, e)) continue;
9182
9381
  let n = t.position;
9183
9382
  if (!Array.isArray(n)) continue;
9184
- let s = mc(t);
9383
+ let s = bc(t);
9185
9384
  r = Math.min(r, s.x), i = Math.min(i, s.y), a = Math.max(a, s.x), o = Math.max(o, s.y);
9186
9385
  }
9187
9386
  if (!Number.isFinite(r)) return;
@@ -9195,12 +9394,13 @@ var rc = class {
9195
9394
  async play(e) {
9196
9395
  if (this.playing) return null;
9197
9396
  let n = structuredClone(e);
9198
- yc(n);
9397
+ Tc(n);
9199
9398
  let r;
9200
9399
  try {
9201
9400
  r = f(n, {
9202
9401
  stubAllBehaviors: !0,
9203
- declareConnectionSignals: !0
9402
+ declareConnectionSignals: !0,
9403
+ ...this.resolver
9204
9404
  });
9205
9405
  } catch (e) {
9206
9406
  return e instanceof Error ? e.message : String(e);
@@ -9234,25 +9434,25 @@ var rc = class {
9234
9434
  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);
9235
9435
  }
9236
9436
  };
9237
- function ic(e) {
9437
+ function uc(e) {
9238
9438
  return Math.round(e * 100) / 100;
9239
9439
  }
9240
- var ac = new G(0, 1, 0), oc = new G(), sc = new G(), cc = new di(), $ = new G(), lc = new ki(), uc = new G(), dc = new G();
9241
- function fc(e, t, n) {
9440
+ var dc = new K(0, 1, 0), fc = new K(), pc = new K(), mc = new mi(), $ = new K(), hc = new Mi(), gc = new K(), _c = new K();
9441
+ function vc(e, t, n) {
9242
9442
  let r = e._object2D?.parent;
9243
- return r ? (lc.copy(r.matrixWorld).invert(), uc.set(t, -n, 0).applyMatrix4(lc), dc.set(0, 0, 0).applyMatrix4(lc), {
9244
- x: uc.x - dc.x,
9245
- y: -(uc.y - dc.y)
9443
+ return r ? (hc.copy(r.matrixWorld).invert(), gc.set(t, -n, 0).applyMatrix4(hc), _c.set(0, 0, 0).applyMatrix4(hc), {
9444
+ x: gc.x - _c.x,
9445
+ y: -(gc.y - _c.y)
9246
9446
  }) : {
9247
9447
  x: t,
9248
9448
  y: n
9249
9449
  };
9250
9450
  }
9251
- function pc(e, t) {
9451
+ function yc(e, t) {
9252
9452
  for (let n = e.parent; n; n = n.parent) if (n === t) return !0;
9253
9453
  return !1;
9254
9454
  }
9255
- function mc(e) {
9455
+ function bc(e) {
9256
9456
  let t = e._object2D;
9257
9457
  if (t) return t.getWorldPosition($), {
9258
9458
  x: $.x,
@@ -9265,7 +9465,7 @@ function mc(e) {
9265
9465
  y: r
9266
9466
  };
9267
9467
  }
9268
- function hc(e) {
9468
+ function xc(e) {
9269
9469
  if (!e) return null;
9270
9470
  if (e.type === "Camera3D") {
9271
9471
  let t = e.props?.position ?? [
@@ -9280,49 +9480,49 @@ function hc(e) {
9280
9480
  ];
9281
9481
  }
9282
9482
  for (let t of e.children ?? []) {
9283
- let e = hc(t);
9483
+ let e = xc(t);
9284
9484
  if (e) return e;
9285
9485
  }
9286
9486
  return null;
9287
9487
  }
9288
- function gc(e) {
9488
+ function Sc(e) {
9289
9489
  if (!e) return null;
9290
9490
  if (e.type === "Camera2D") {
9291
9491
  let t = e.props?.position ?? [0, 0];
9292
9492
  return [t[0] ?? 0, t[1] ?? 0];
9293
9493
  }
9294
9494
  for (let t of e.children ?? []) {
9295
- let e = gc(t);
9495
+ let e = Sc(t);
9296
9496
  if (e) return e;
9297
9497
  }
9298
9498
  return null;
9299
9499
  }
9300
- var _c = null;
9301
- function vc() {
9302
- if (_c) return _c;
9500
+ var Cc = null;
9501
+ function wc() {
9502
+ if (Cc) return Cc;
9303
9503
  let e = document.createElement("canvas");
9304
9504
  e.width = 16, e.height = 16;
9305
9505
  let t = e.getContext("2d");
9306
9506
  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);
9307
- return _c = e.toDataURL(), _c;
9507
+ return Cc = e.toDataURL(), Cc;
9308
9508
  }
9309
- function yc(e) {
9509
+ function Tc(e) {
9310
9510
  let t = e.assets;
9311
- if (t) for (let e of Object.values(t)) typeof e?.url == "string" && !e.url.includes("/") && !e.url.includes(".") && (e.url = vc());
9511
+ if (t) for (let e of Object.values(t)) typeof e?.url == "string" && !e.url.includes("/") && !e.url.includes(".") && (e.url = wc());
9312
9512
  }
9313
9513
  //#endregion
9314
9514
  //#region src/main.ts
9315
- var bc = new Set([
9515
+ var Ec = new Set([
9316
9516
  "Terrain3D",
9317
9517
  "Water3D",
9318
9518
  "River3D"
9319
9519
  ]);
9320
9520
  m(), b(), k(), ee(), A();
9321
- async function xc(e = {}) {
9521
+ async function Dc(e = {}) {
9322
9522
  let t = e.api ?? ze, n = [], r = document.createElement("style");
9323
- r.dataset.incantoEditor = "true", r.textContent = vs, document.head.appendChild(r), n.push(() => r.remove());
9523
+ r.dataset.incantoEditor = "true", r.textContent = Ss, document.head.appendChild(r), n.push(() => r.remove());
9324
9524
  let i = document.createElement("div");
9325
- i.className = "incanto-editor-root", i.innerHTML = Uo, (e.host ?? document.body).appendChild(i), n.push(() => i.remove());
9525
+ i.className = "incanto-editor-root", i.innerHTML = qo, (e.host ?? document.body).appendChild(i), n.push(() => i.remove());
9326
9526
  let a = (e) => {
9327
9527
  let t = i.querySelector(e);
9328
9528
  if (!t) throw Error(`missing ${e}`);
@@ -9362,7 +9562,7 @@ async function xc(e = {}) {
9362
9562
  }), Ge(() => {
9363
9563
  l(), zt(), u.select(u.selection);
9364
9564
  });
9365
- let u = new ss({
9565
+ let u = new ds({
9366
9566
  format: 1,
9367
9567
  type: "scene",
9368
9568
  name: "",
@@ -9391,22 +9591,22 @@ async function xc(e = {}) {
9391
9591
  x: t,
9392
9592
  y: n
9393
9593
  };
9394
- }, M = !1, N = (e, t, n = !0) => {
9395
- n && (M = !1);
9594
+ }, re = !1, M = (e, t, n = !0) => {
9595
+ n && (re = !1);
9396
9596
  let r = u.selection, i = u.nodeAt(r);
9397
9597
  if (!r || i?.type !== "TileMap2D") return;
9398
- let { cx: a, cy: o } = Fn(ne(r), Number(i.props?.tileSize ?? 32), e, t), s = i.props?.cells ?? [], c = In(s, a, o, j.brush);
9399
- !c || JSON.stringify(c) === JSON.stringify(s) || (u.mutate(() => {
9400
- i.props ||= {}, i.props.cells = c;
9598
+ let a = ne(r), o = Number(i.props?.scale?.[0] ?? 1) || 1, s = Number(i.props?.scale?.[1] ?? 1) || 1, { cx: c, cy: l } = Fn(a, Number(i.props?.tileSize ?? 32), e, t, o, s), d = i.props?.cells ?? [], f = In(d, c, l, j.brush);
9599
+ !f || JSON.stringify(f) === JSON.stringify(d) || (u.mutate(() => {
9600
+ i.props ||= {}, i.props.cells = f;
9401
9601
  }, {
9402
9602
  path: r,
9403
9603
  key: "cells",
9404
- value: c
9405
- }, { coalesce: M }), M = !0);
9406
- }, re = () => {
9604
+ value: f
9605
+ }, { coalesce: re }), re = !0);
9606
+ }, ie = () => {
9407
9607
  let e = u.nodeAt(u.selection);
9408
- j.on && e?.type !== "TileMap2D" && (j.on = !1), P.setPaintHandler(j.on ? N : null);
9409
- }, P = new rc(a("#viewport"), a("#overlay"), a("#play-canvas"), {
9608
+ j.on && e?.type !== "TileMap2D" && (j.on = !1), N.setPaintHandler(j.on ? M : null);
9609
+ }, N = new lc(a("#viewport"), a("#overlay"), a("#play-canvas"), {
9410
9610
  onPick: (e, t) => u.select(e ?? null, t),
9411
9611
  onNodeMoved: (e, t) => de(e, "position", t, [0, 0]),
9412
9612
  onNodeScaled: (e, t) => de(e, "scale", t, [1, 1]),
@@ -9417,7 +9617,7 @@ async function xc(e = {}) {
9417
9617
  ]),
9418
9618
  onNodeScaled3D: (e, t) => {
9419
9619
  let n = u.nodeAt(e);
9420
- if (n && bc.has(String(n.type))) {
9620
+ if (n && Ec.has(String(n.type))) {
9421
9621
  O(`${n.type} '${n.name}' cannot be scaled — scale would move only the mesh. Resize it with its "size" prop in the inspector.`);
9422
9622
  return;
9423
9623
  }
@@ -9449,9 +9649,9 @@ async function xc(e = {}) {
9449
9649
  document.body.classList.toggle("playing", e), n.push(() => document.body.classList.remove("playing")), h.classList.toggle("stop", e), h.innerHTML = e ? "<svg width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><rect x=\"6\" y=\"6\" width=\"12\" height=\"12\"/></svg> stop" : "<svg width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M8 5v14l11-7z\"/></svg> play", v.hidden = !e, e && (v.textContent = "▶ simulating — physics + input live; game scripts run only in your real game. Esc or stop to return.");
9450
9650
  },
9451
9651
  onError: O
9452
- }), ie = g().sort(), ae = "", oe = (e) => {
9453
- if (e === ae) return;
9454
- ae = e, y.textContent = "";
9652
+ }), ae = g().sort(), P = "", oe = (e) => {
9653
+ if (e === P) return;
9654
+ P = e, y.textContent = "";
9455
9655
  let t = e === "3d" ? [
9456
9656
  "3D",
9457
9657
  "3D Physics",
@@ -9473,7 +9673,7 @@ async function xc(e = {}) {
9473
9673
  if (!t) continue;
9474
9674
  let n = document.createElement("optgroup");
9475
9675
  n.label = e;
9476
- for (let e of ie.filter(t)) {
9676
+ for (let e of ae.filter(t)) {
9477
9677
  let t = document.createElement("option");
9478
9678
  t.value = e, t.textContent = e, n.appendChild(t);
9479
9679
  }
@@ -9484,7 +9684,7 @@ async function xc(e = {}) {
9484
9684
  oe("2d");
9485
9685
  let se = () => {
9486
9686
  let e = u.selection ?? [];
9487
- if (P.validate(u.working) !== null) {
9687
+ if (N.validate(u.working) !== null) {
9488
9688
  for (let e of y.querySelectorAll("option")) e.disabled = !1;
9489
9689
  return;
9490
9690
  }
@@ -9502,47 +9702,49 @@ async function xc(e = {}) {
9502
9702
  type: t.value
9503
9703
  });
9504
9704
  }
9505
- t.disabled = P.validate(n) !== null;
9705
+ t.disabled = N.validate(n) !== null;
9506
9706
  }
9507
9707
  };
9508
9708
  y.addEventListener("mousedown", se), y.addEventListener("focus", se);
9509
- let ce = t.library ? (e) => Eo(t, {
9709
+ let ce = t.library ? (e) => Ao(t, {
9510
9710
  kind: e.kind,
9511
9711
  ...e.target ? { target: e.target } : {},
9512
9712
  ...e.shelf ? { shelf: e.shelf } : {},
9513
9713
  ...e.assetType ? { assetType: e.assetType } : {},
9514
9714
  ...e.onProps ? { onProps: e.onProps } : {},
9515
- ...e.asAsset ? { onAsset: (e, t, n) => Tc(u, n, t) } : {}
9715
+ ...e.asAsset ? { onAsset: (e, t, n) => jc(u, n, t) } : {}
9516
9716
  }) : void 0, le = !1, F = () => {
9517
9717
  if (!E) return;
9518
- js(d, u), rt(a("#asset-tree"), u), f.textContent = "", it(f, u, Ce, ce) || Bn(f, u, {
9519
- modelRefs: () => Cc(u, "model"),
9520
- animationsForSelection: () => u.selection ? P.modelAnimationsAt(u.selection) : [],
9521
- bonesForSelection: (e) => u.selection ? P.boneNamesAt(u.selection, e) : [],
9522
- assetRefs: (e) => wc(u, e),
9523
- addAsset: (e, t) => Tc(u, e, t),
9718
+ Ls(d, u), rt(a("#asset-tree"), u), f.textContent = "", it(f, u, Ce, ce) || Bn(f, u, {
9719
+ modelRefs: () => kc(u, "model"),
9720
+ animationsForSelection: () => u.selection ? N.modelAnimationsAt(u.selection) : [],
9721
+ bonesForSelection: (e) => u.selection ? N.boneNamesAt(u.selection, e) : [],
9722
+ assetRefs: (e) => Ac(u, e),
9723
+ addAsset: (e, t) => jc(u, e, t),
9524
9724
  ...ce ? { openLibrary: ce } : {},
9525
9725
  confirm: Ce,
9526
9726
  paint: {
9527
9727
  active: () => j.on,
9528
9728
  brush: () => j.brush,
9529
9729
  toggle: () => {
9530
- j.on = !j.on, re(), F();
9730
+ j.on = !j.on, ie(), F();
9531
9731
  },
9532
9732
  setBrush: (e) => {
9533
9733
  j.brush = e, F();
9534
9734
  }
9535
9735
  }
9536
- }), oe(u.working.dimension ?? "2d"), a("#hints").hidden = (u.working.dimension ?? "2d") === "3d", a("#hints-3d").hidden = (u.working.dimension ?? "2d") !== "3d", P.setSelection(u.selection, u.extra), re();
9736
+ }), oe(u.working.dimension ?? "2d"), a("#hints").hidden = (u.working.dimension ?? "2d") === "3d", a("#hints-3d").hidden = (u.working.dimension ?? "2d") !== "3d", N.setSelection(u.selection, u.extra), ie();
9537
9737
  let e = u.pendingLivePatch;
9538
- if (u.pendingLivePatch = null, !P.playing) if (e && P.patchProp(u.working, e.path, e.key, e.value)) _.hidden = !0;
9539
- else {
9540
- let e = P.apply(u.working);
9738
+ if (u.pendingLivePatch = null, !N.playing) if (e && N.patchProp(u.working, e.path, e.key, e.value)) {
9739
+ let e = N.validate(u.working);
9740
+ _.hidden = e === null, e !== null && O(e);
9741
+ } else {
9742
+ let e = N.apply(u.working);
9541
9743
  _.hidden = e === null, e !== null && O(e);
9542
9744
  }
9543
9745
  p.disabled = !u.dirty || !u.working.root, p.title = u.working.root ? "" : "Add a root node before saving", m.disabled = !u.canUndo, u.dirty !== le && (le = u.dirty, kt.change(u.dirty));
9544
9746
  };
9545
- u.onChange(F), u.validator = (e) => P.validate(e), u.onError = O;
9747
+ u.onChange(F), u.validator = (e) => N.validate(e), u.onError = O;
9546
9748
  let ue = (e, t, n, r) => {
9547
9749
  let i = u.nodeAt(e);
9548
9750
  i && u.mutate(() => {
@@ -9562,12 +9764,12 @@ async function xc(e = {}) {
9562
9764
  value: n
9563
9765
  });
9564
9766
  }, fe = async (e, n, r) => {
9565
- P.playing && P.stop();
9767
+ N.playing && N.stop();
9566
9768
  let i = await t.loadScene(e);
9567
9769
  T = e, C = n, w = r, E = !0;
9568
9770
  let s = e ?? n;
9569
- a("#file-chip").hidden = !s, a("#file-path").textContent = s ?? "", a("#file-chip").title = `input: ${n}\noutput: ${r}`, b.hidden = !0, k(), Ps(), u.reset(i), o.mode === "project" && n && kt.open(n, r);
9570
- }, pe = Ho({
9771
+ a("#file-chip").hidden = !s, a("#file-path").textContent = s ?? "", a("#file-chip").title = `input: ${n}\noutput: ${r}`, N.setSubScenes(await Cs(i, t)), b.hidden = !0, k(), Bs(), u.reset(i), o.mode === "project" && n && kt.open(n, r);
9772
+ }, pe = Ko({
9571
9773
  list: x,
9572
9774
  search: a("#picker-search"),
9573
9775
  count: a("#picker-count"),
@@ -9632,7 +9834,7 @@ async function xc(e = {}) {
9632
9834
  if (e.length === 0) {
9633
9835
  let e = u.working.root;
9634
9836
  if (!e) return;
9635
- let t = Sc(e);
9837
+ let t = Oc(e);
9636
9838
  Ce(`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());
9637
9839
  return;
9638
9840
  }
@@ -9640,7 +9842,7 @@ async function xc(e = {}) {
9640
9842
  if (n.length === 0) {
9641
9843
  let n = e.reduce((e, t) => {
9642
9844
  let n = u.nodeAt(t);
9643
- return e + (n ? Sc(n) : 0);
9845
+ return e + (n ? Oc(n) : 0);
9644
9846
  }, 0);
9645
9847
  if (n > 0) {
9646
9848
  Ce(`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`, () => {
@@ -9689,7 +9891,7 @@ async function xc(e = {}) {
9689
9891
  return;
9690
9892
  }
9691
9893
  be && u.removeNodesUnlinking(be.selections) && u.select(be.parentOfFirst), Te();
9692
- }), Ts(ye), Es((e) => {
9894
+ }), js(ye), Ms((e) => {
9693
9895
  te(`${I({
9694
9896
  en: `Rename: repaired ${e.length} reference${e.length === 1 ? "" : "s"}`,
9695
9897
  ko: `이름 변경: 참조 ${e.length}건 수정`
@@ -9709,13 +9911,13 @@ async function xc(e = {}) {
9709
9911
  ye(u.allSelections().filter((e) => e.length > 0));
9710
9912
  });
9711
9913
  let Ee = () => {
9712
- _.hidden = !0, P.play(u.working).then((e) => {
9914
+ _.hidden = !0, N.play(u.working).then((e) => {
9713
9915
  e && O(e);
9714
9916
  });
9715
9917
  };
9716
9918
  if (h.addEventListener("click", () => {
9717
- if (P.playing) {
9718
- P.stop(), F();
9919
+ if (N.playing) {
9920
+ N.stop(), F();
9719
9921
  return;
9720
9922
  }
9721
9923
  if (!e.onPlay) {
@@ -9763,21 +9965,21 @@ async function xc(e = {}) {
9763
9965
  "move",
9764
9966
  "rotate",
9765
9967
  "scale"
9766
- ]) a(`#tool-${e}`).addEventListener("click", () => P.setMode(e));
9767
- P.setMode("move");
9968
+ ]) a(`#tool-${e}`).addEventListener("click", () => N.setMode(e));
9969
+ N.setMode("move");
9768
9970
  let De = a("#tool-colliders"), Oe = "incanto-editor-show-colliders", ke = (e) => {
9769
- P.showColliders = e, De.classList.toggle("active", e), localStorage.setItem(Oe, e ? "" : "0");
9971
+ N.showColliders = e, De.classList.toggle("active", e), localStorage.setItem(Oe, e ? "" : "0");
9770
9972
  };
9771
- ke(localStorage.getItem(Oe) !== "0"), De.addEventListener("click", () => ke(!P.showColliders));
9973
+ ke(localStorage.getItem(Oe) !== "0"), De.addEventListener("click", () => ke(!N.showColliders));
9772
9974
  let Ae = a("#hints-dock"), je = "incanto-editor-hints-open";
9773
9975
  Ae.classList.toggle("open", localStorage.getItem(je) === "1"), a("#hints-toggle").addEventListener("click", () => {
9774
9976
  let e = Ae.classList.toggle("open");
9775
9977
  localStorage.setItem(je, e ? "1" : "");
9776
- }), a("#fit-btn").addEventListener("click", () => P.zoomToFit()), ws(() => P.zoomToFit()), a("#gameview-btn").addEventListener("click", () => P.gameView()), t.saveScene || (p.hidden = !0), p.addEventListener("click", () => {
9978
+ }), a("#fit-btn").addEventListener("click", () => N.zoomToFit()), As(() => N.zoomToFit()), a("#gameview-btn").addEventListener("click", () => N.gameView()), t.saveScene || (p.hidden = !0), p.addEventListener("click", () => {
9777
9979
  we();
9778
9980
  }), m.addEventListener("click", () => u.undo());
9779
9981
  let Me = (e) => {
9780
- if (e.key === "Escape" && P.cancelActiveDrag(), e.key === "Escape" && !_.hidden && a("#docs").hidden && ve.hidden && _e.hidden && b.hidden && !P.playing) {
9982
+ if (e.key === "Escape" && N.cancelActiveDrag(), e.key === "Escape" && !_.hidden && a("#docs").hidden && ve.hidden && _e.hidden && b.hidden && !N.playing) {
9781
9983
  k();
9782
9984
  return;
9783
9985
  }
@@ -9797,39 +9999,39 @@ async function xc(e = {}) {
9797
9999
  ge();
9798
10000
  return;
9799
10001
  }
9800
- if (e.key === "Escape" && P.playing) {
9801
- P.stop(), F();
10002
+ if (e.key === "Escape" && N.playing) {
10003
+ N.stop(), F();
9802
10004
  return;
9803
10005
  }
9804
- if (P.playing) return;
10006
+ if (N.playing) return;
9805
10007
  let t = e.target.matches("input, textarea, select");
9806
- (e.metaKey || e.ctrlKey) && e.key === "z" ? (e.preventDefault(), u.undo()) : (e.metaKey || e.ctrlKey) && e.key === "s" ? (e.preventDefault(), p.disabled || p.click()) : !t && e.code === "KeyF" ? P.zoomToFit() : !t && (e.code === "Digit0" || e.code === "Numpad0") ? P.gameView() : !t && e.code === "KeyW" ? P.setMode("move") : !t && e.code === "KeyE" ? P.setMode("rotate") : !t && e.code === "KeyR" && P.setMode("scale");
10008
+ (e.metaKey || e.ctrlKey) && e.key === "z" ? (e.preventDefault(), u.undo()) : (e.metaKey || e.ctrlKey) && e.key === "s" ? (e.preventDefault(), p.disabled || p.click()) : !t && e.code === "KeyF" ? N.zoomToFit() : !t && (e.code === "Digit0" || e.code === "Numpad0") ? N.gameView() : !t && e.code === "KeyW" ? N.setMode("move") : !t && e.code === "KeyE" ? N.setMode("rotate") : !t && e.code === "KeyR" && N.setMode("scale");
9807
10009
  };
9808
- return window.addEventListener("keydown", Me), n.push(() => window.removeEventListener("keydown", Me)), F(), e.scene && u.resume(e.scene), e.camera && P.setEditCamera(e.camera.position, e.camera.target), kt.ready(C, w, o.version), {
10010
+ return window.addEventListener("keydown", Me), n.push(() => window.removeEventListener("keydown", Me)), F(), e.scene && u.resume(e.scene), e.camera && N.setEditCamera(e.camera.position, e.camera.target), kt.ready(C, w, o.version), {
9809
10011
  working: () => u.working,
9810
- camera: () => P.editCamera(),
10012
+ camera: () => N.editCamera(),
9811
10013
  showError: O,
9812
10014
  dispose() {
9813
- P.dispose();
10015
+ N.dispose();
9814
10016
  for (let e of document.querySelectorAll(".context-menu, .balloon")) e.remove();
9815
10017
  for (let e of n.splice(0).reverse()) e();
9816
10018
  }
9817
10019
  };
9818
10020
  }
9819
- function Sc(e) {
10021
+ function Oc(e) {
9820
10022
  let t = 0;
9821
- for (let n of e.children ?? []) t += 1 + Sc(n);
10023
+ for (let n of e.children ?? []) t += 1 + Oc(n);
9822
10024
  return t;
9823
10025
  }
9824
- function Cc(e, t) {
10026
+ function kc(e, t) {
9825
10027
  let n = e.working.assets;
9826
10028
  return n ? Object.entries(n).filter(([, e]) => e?.type === t).map(([e]) => `$${e}`) : [];
9827
10029
  }
9828
- function wc(e, t) {
10030
+ function Ac(e, t) {
9829
10031
  let n = e.working.assets;
9830
10032
  return n ? Object.entries(n).filter(([, e]) => !t || e?.type !== void 0 && t.includes(e.type)).map(([e]) => `$${e}`) : [];
9831
10033
  }
9832
- function Tc(e, t, n) {
10034
+ function jc(e, t, n) {
9833
10035
  let r = e.working.assets ?? {};
9834
10036
  for (let [e, t] of Object.entries(r)) if (t?.url === n.url) return `$${e}`;
9835
10037
  let i = t;
@@ -9839,4 +10041,4 @@ function Tc(e, t, n) {
9839
10041
  }), `$${i}`;
9840
10042
  }
9841
10043
  //#endregion
9842
- export { N as formatSceneJson, ze as httpEditorApi, xc as mountEditor };
10044
+ export { M as formatSceneJson, ze as httpEditorApi, Dc as mountEditor };