ldr 0.33.5 → 0.33.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -139,7 +139,7 @@ MPD-embedded parts, such as Studio/OMR unofficial parts or stickers, become part
139
139
  | `ldrawSpace` | `false` | `true` keeps native LDraw space (-Y up). |
140
140
  | `scale` | `1` | Uniform scale (1 = 1 LDU; 1 stud = 20 LDU). |
141
141
  | `step` | all | Initial build step (inclusive, 0-based). |
142
- | `lod` | `true` | Distance LOD, re-selected for each camera you render with. Batches are split into spatial clusters (off-screen ones are frustum-culled). Each cluster draws the coarsest simplified mesh (from `lod` packs) whose error stays under `lodPx`, swaps closed studs to a 10-triangle square stud then a flat disc, and drops them once their 12-LDU disc is under `lodPx`, and hides edges where a stud spans less than `lodEdgePx`. |
142
+ | `lod` | `true` | Distance LOD, re-selected for each camera you render with. Batches are split into spatial clusters (off-screen ones are frustum-culled). Each cluster draws the coarsest simplified mesh (from `lod` packs) whose error stays under `lodPx`, swaps closed studs to a 10-triangle square stud and open (hollow) studs to a 24-triangle square stud with a square hole (each with a square outline), then a flat disc, and drops them once their 12-LDU disc is under `lodPx`, and hides edges where a stud spans less than `lodEdgePx`. |
143
143
  | `lodPx` | `0.5` | LOD: maximum screen-space error in pixels. |
144
144
  | `lodEdgePx` | `0.5` | LOD: draw edge and conditional lines only where one stud (20 LDU) spans at least this many pixels. `0` = always. |
145
145
  | `lodEdgeMinPx` | `0.4` | LOD: draw only edge segments at least this many pixels long on screen. `0` = every segment. |
@@ -201,7 +201,7 @@ How much each optimization contributed on Datsville 100k (Rounds 1–20, before
201
201
  - Full Datsville: **1.7 → 9.9 fps**.
202
202
  - Datsville 100k: **8 → 43.5 fps**.
203
203
  - **Conditional lines** (opt-in `cond` packs) cost **+12–14 %** frame time on Datsville 10k and 100k (M4 Pro, before Round 60), and add 7–14 % to the zstd pack size.
204
- - **Edges:** with LOD, edges take the Falcon fleet from 11.6 → 15.1 ms (19 ships) and 18.5 → 23.9 ms (75 ships) on the Mac Mini M6; before Round 62 they cost 12.8 → 33.3 and 19.3 → 45.1 ms there. Each cluster draws only edge segments at least 0.4 px long on screen (`lodEdgeMinPx`; 0.15 px until Round 62, when 85% of the segments drawn at the fleet overview were 0.15–0.5 px long and each darkened a whole pixel, so far ships looked charcoal) and none where bricks are sub-pixel (`lodEdgePx`). Far views drawn with edges get lighter: 2.6% of pixels differ from every-edge rendering on the 19-ship overview, 0.8% on the SF city, up to 4.7% on Datsville overviews. `lodEdgeMinPx: 0, lodEdgePx: 0` keeps every edge.
204
+ - **Edges:** with LOD, edges take the Falcon fleet from 9.8 → 12.9 ms (19 ships) and 18.3 → 22.9 ms (75 ships) on the Mac Mini M6 (Round 67); before Round 62 they cost 12.8 → 33.3 and 19.3 → 45.1 ms there. A simplified level draws its own outline: square studs a square per stud loop (8 segments instead of 16-32), bodies at their bounding-box level the box's 12 edges, and a line batch whose edge LOD leaves no segment issues no draw. Each cluster draws only edge segments at least 0.4 px long on screen (`lodEdgeMinPx`; 0.15 px until Round 62, when 85% of the segments drawn at the fleet overview were 0.15–0.5 px long and each darkened a whole pixel, so far ships looked charcoal) and none where bricks are sub-pixel (`lodEdgePx`). Far views drawn with edges get lighter: 2.6% of pixels differ from every-edge rendering on the 19-ship overview, 0.8% on the SF city, up to 4.7% on Datsville overviews. `lodEdgeMinPx: 0, lodEdgePx: 0` keeps every edge.
205
205
  - **Build steps:** `setStep` takes 39 ms on the 19-ship fleet (26,619 steps); on Datsville 100k it went from a full rebuild (752 ms) to 66 ms.
206
206
  - **Visual fidelity:** pixel diffs show culling and single-sided faces are lossless (≤ 0.009 % of pixels differ). Low-detail studs only change stud silhouettes.
207
207
 
package/dist/cli.js CHANGED
@@ -1,18 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/cli.ts
3
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/cli.ts
4
4
  import fs4 from "node:fs";
5
5
  import zlib from "node:zlib";
6
6
 
7
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/node/build-pack.ts
7
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/node/build-pack.ts
8
8
  import fs3 from "node:fs";
9
9
  import path3 from "node:path";
10
10
 
11
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/node/resolver.ts
11
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/node/resolver.ts
12
12
  import fs from "node:fs";
13
13
  import path from "node:path";
14
14
 
15
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/spec.ts
15
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/spec.ts
16
16
  var norm = (s) => s.trim().toLowerCase().replace(/\\/g, "/").replace(/\/+/g, "/");
17
17
  var COLOUR_ID_RE = /^[A-Za-z][A-Za-z0-9_]*$/;
18
18
  var namedCodes = new Map;
@@ -817,7 +817,7 @@ function fileStepViews(f) {
817
817
  return out;
818
818
  }
819
819
 
820
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/model.ts
820
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/model.ts
821
821
  class ModelLimitError extends Error {
822
822
  limit;
823
823
  code = "ldr-model-limit";
@@ -1259,7 +1259,7 @@ function blendedColourHex(code) {
1259
1259
  return "#" + [0, 1, 2].map((k) => (a[k] + b[k] >> 1).toString(16).padStart(2, "0")).join("").toUpperCase();
1260
1260
  }
1261
1261
 
1262
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/node/resolver.ts
1262
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/node/resolver.ts
1263
1263
  var TOP_STUD_RE = /^(stud|studa|stud2|stud2a|stud6|stud6a|stud10|stud15|stud2s|stud2s2|stud-logo\d*|stud2-logo\d*)\.dat$/i;
1264
1264
  var UNDER_STUD_RE = /^(stud3|stud3a|stud4.*|stud12|stud16.*|stud18a)\.dat$/i;
1265
1265
  var norm2 = (ref) => ref.trim().replace(/\\/g, "/").toLowerCase();
@@ -1586,11 +1586,11 @@ function collectDeps(lib, refs) {
1586
1586
  return out;
1587
1587
  }
1588
1588
 
1589
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/node/compile.ts
1589
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/node/compile.ts
1590
1590
  import fs2 from "node:fs";
1591
1591
  import path2 from "node:path";
1592
1592
 
1593
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/node/lod.ts
1593
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/node/lod.ts
1594
1594
  import { MeshoptSimplifier, MeshoptEncoder } from "meshoptimizer";
1595
1595
  await Promise.all([MeshoptSimplifier.ready, MeshoptEncoder.ready]);
1596
1596
  function reorderMesh(P, N, C, I) {
@@ -1796,7 +1796,7 @@ function lodChain(P, C, I, half = false) {
1796
1796
  return out;
1797
1797
  }
1798
1798
 
1799
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/node/compile.ts
1799
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/node/compile.ts
1800
1800
  class BfcState {
1801
1801
  accum;
1802
1802
  ccw = true;
@@ -2728,7 +2728,7 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
2728
2728
  return Buffer.concat([head, ...chunks.map((c) => new Uint8Array(c.buffer, c.byteOffset, c.byteLength))]);
2729
2729
  }
2730
2730
 
2731
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/node/build-pack.ts
2731
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/node/build-pack.ts
2732
2732
  function packCompilerOpts(o) {
2733
2733
  return { studs: o.studs ?? "low", prims: o.primitives ?? "full", weld: o.weld ?? true, separateStuds: true, cond: !!o.cond, tex: !!o.textures, ...o.partWorkLimit ? { workLimit: o.partWorkLimit } : {} };
2734
2734
  }
@@ -2801,7 +2801,7 @@ function buildPack(o) {
2801
2801
  return { data: encodePack(parts, kinds, comp.opts.weld, extra, { texture, lod: o.lod !== false, reorder: !!o.reorder }), parts: parts.size, studKinds: kinds.size, missing: [...missing], ...warnings.length ? { warnings } : {} };
2802
2802
  }
2803
2803
 
2804
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/cli.ts
2804
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/cli.ts
2805
2805
  var HELP = `ldr pack — build a parts pack for the ldr three.js renderer
2806
2806
 
2807
2807
  Usage:
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/spec.ts
1
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/spec.ts
2
2
  var norm = (s) => s.trim().toLowerCase().replace(/\\/g, "/").replace(/\/+/g, "/");
3
3
  var COLOUR_ID_RE = /^[A-Za-z][A-Za-z0-9_]*$/;
4
4
  var namedCodes = new Map;
@@ -778,7 +778,7 @@ function fileStepViews(f) {
778
778
  viewMemo.set(f, out);
779
779
  return out;
780
780
  }
781
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/model.ts
781
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/model.ts
782
782
  class ModelLimitError extends Error {
783
783
  limit;
784
784
  code = "ldr-model-limit";
@@ -1219,7 +1219,7 @@ function blendedColourHex(code) {
1219
1219
  const a = LDRAW_EXE_16[code - 256 >> 4], b = LDRAW_EXE_16[code - 256 & 15];
1220
1220
  return "#" + [0, 1, 2].map((k) => (a[k] + b[k] >> 1).toString(16).padStart(2, "0")).join("").toUpperCase();
1221
1221
  }
1222
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/instructions.ts
1222
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/instructions.ts
1223
1223
  var MIN_VIS = 0.5;
1224
1224
  var REORIENT = 0.35;
1225
1225
  var deg = Math.PI / 180;
@@ -1587,10 +1587,10 @@ function planStepViews(insts, parts, stepOf, nSteps, o = {}) {
1587
1587
  }
1588
1588
  };
1589
1589
  }
1590
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/render.ts
1590
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/render.ts
1591
1591
  import * as THREE from "three";
1592
1592
 
1593
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/pack-io.ts
1593
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/pack-io.ts
1594
1594
  import { decompress } from "fzstd";
1595
1595
  async function decompressPack(data) {
1596
1596
  const u = data instanceof Uint8Array ? data : new Uint8Array(data);
@@ -1613,7 +1613,7 @@ function decodePack(buf) {
1613
1613
  return { header, arr, bytes: buf.byteLength, buffer: buf };
1614
1614
  }
1615
1615
 
1616
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/cull.ts
1616
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/cull.ts
1617
1617
  var upright = (m, o = 0) => Math.abs(m[o + 7] - 1) < 0.001 && Math.abs(m[o + 4]) < 0.001 && Math.abs(m[o + 10]) < 0.001;
1618
1618
  var prepCache = new WeakMap;
1619
1619
  function prepPart(H, part) {
@@ -1996,7 +1996,7 @@ function precomputeCull(instances, H, useTex = true) {
1996
1996
  return cullCore(s.all, H, s.nSteps > 1 ? s.stepOf : undefined);
1997
1997
  }
1998
1998
 
1999
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/render.ts
1999
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/render.ts
2000
2000
  async function loadPack(url) {
2001
2001
  const res = await fetch(url);
2002
2002
  if (!res.ok)
@@ -2708,7 +2708,181 @@ function studBoxGeom(w) {
2708
2708
  _studBox.set(w, g);
2709
2709
  return g;
2710
2710
  }
2711
+ var _studTube = new Map;
2712
+ function studTubeGeom(w, wi) {
2713
+ const key = w + "," + wi;
2714
+ let g = _studTube.get(key);
2715
+ if (g)
2716
+ return g;
2717
+ const y = -4, s = Math.SQRT1_2;
2718
+ const sq = (h) => [[-h, -h], [h, -h], [h, h], [-h, h]];
2719
+ const C = sq(w), Ci = sq(wi);
2720
+ const pos = [], nrm = [], idx = [];
2721
+ for (const [x, z] of C) {
2722
+ pos.push(x, y, z);
2723
+ nrm.push(0, -1, 0);
2724
+ }
2725
+ for (const [x, z] of Ci) {
2726
+ pos.push(x, y, z);
2727
+ nrm.push(0, -1, 0);
2728
+ }
2729
+ for (const [x, z] of C) {
2730
+ pos.push(x, y, z, x, 0, z);
2731
+ nrm.push(Math.sign(x) * s, 0, Math.sign(z) * s, Math.sign(x) * s, 0, Math.sign(z) * s);
2732
+ }
2733
+ for (const [x, z] of Ci) {
2734
+ pos.push(x, y, z, x, 0, z);
2735
+ nrm.push(-Math.sign(x) * s, 0, -Math.sign(z) * s, -Math.sign(x) * s, 0, -Math.sign(z) * s);
2736
+ }
2737
+ const tri = (a, b, c, out) => {
2738
+ const P = (i) => pos.slice(i * 3, i * 3 + 3);
2739
+ const [A, B, Cc] = [P(a), P(b), P(c)];
2740
+ const u = [B[0] - A[0], B[1] - A[1], B[2] - A[2]], v = [Cc[0] - A[0], Cc[1] - A[1], Cc[2] - A[2]];
2741
+ const n = [u[1] * v[2] - u[2] * v[1], u[2] * v[0] - u[0] * v[2], u[0] * v[1] - u[1] * v[0]];
2742
+ if (n[0] * out[0] + n[1] * out[1] + n[2] * out[2] < 0)
2743
+ idx.push(a, c, b);
2744
+ else
2745
+ idx.push(a, b, c);
2746
+ };
2747
+ for (let i = 0;i < 4; i++) {
2748
+ const j = (i + 1) % 4;
2749
+ tri(i, j, 4 + j, [0, -1, 0]);
2750
+ tri(i, 4 + j, 4 + i, [0, -1, 0]);
2751
+ const mid = [(C[i][0] + C[j][0]) / 2, 0, (C[i][1] + C[j][1]) / 2];
2752
+ {
2753
+ const ti = 8 + i * 2, bi = ti + 1, tj = 8 + j * 2, bj = tj + 1;
2754
+ tri(ti, tj, bj, mid);
2755
+ tri(ti, bj, bi, mid);
2756
+ }
2757
+ {
2758
+ const ti = 16 + i * 2, bi = ti + 1, tj = 16 + j * 2, bj = tj + 1;
2759
+ const inn = [-mid[0], 0, -mid[2]];
2760
+ tri(ti, tj, bj, inn);
2761
+ tri(ti, bj, bi, inn);
2762
+ }
2763
+ }
2764
+ const nv = pos.length / 3;
2765
+ const col = new Uint8Array(nv * 4);
2766
+ for (let i = 0;i < nv; i++) {
2767
+ col[i * 4] = 255;
2768
+ col[i * 4 + 1] = 255;
2769
+ col[i * 4 + 2] = 255;
2770
+ col[i * 4 + 3] = 0;
2771
+ }
2772
+ g = new THREE.BufferGeometry;
2773
+ g.setAttribute("position", new THREE.Float16BufferAttribute(toF16(new Float32Array(pos)), 3));
2774
+ g.setAttribute("normal", new THREE.BufferAttribute(toI8(new Float32Array(nrm)), 3, true));
2775
+ g.setAttribute("ldrColor", new THREE.BufferAttribute(col, 4, true));
2776
+ g.setIndex(new THREE.BufferAttribute(new Uint16Array(idx), 1));
2777
+ g.computeBoundingSphere();
2778
+ g.computeBoundingBox();
2779
+ _studTube.set(key, g);
2780
+ return g;
2781
+ }
2782
+ var _hole = new WeakMap;
2783
+ function studHole(b, arr = (r) => r) {
2784
+ if (!b)
2785
+ return null;
2786
+ let v = _hole.get(b);
2787
+ if (v !== undefined)
2788
+ return v;
2789
+ v = null;
2790
+ const p = arr(b.pos);
2791
+ let rin = Infinity, out = Infinity, ok = p.length >= 9;
2792
+ for (let i = 0;i < p.length && ok; i += 3) {
2793
+ const y = p[i + 1], r = Math.hypot(p[i], p[i + 2]);
2794
+ if (y < -4.01 || y > 0.01 || r > 6.02)
2795
+ ok = false;
2796
+ else if (r < 5.8)
2797
+ rin = Math.min(rin, r);
2798
+ else
2799
+ out = Math.min(out, r);
2800
+ }
2801
+ if (ok && rin >= 3.5 && rin <= 4.5) {
2802
+ let top = false, foot = false;
2803
+ for (let i = 0;i < p.length && ok; i += 3) {
2804
+ const r = Math.hypot(p[i], p[i + 2]);
2805
+ if (r >= 5.8)
2806
+ continue;
2807
+ if (r - rin > 0.1)
2808
+ ok = false;
2809
+ else if (Math.abs(p[i + 1] + 4) < 0.01)
2810
+ top = true;
2811
+ else if (Math.abs(p[i + 1]) < 0.01)
2812
+ foot = true;
2813
+ }
2814
+ if (ok && top && foot)
2815
+ v = { r: rin, out };
2816
+ }
2817
+ _hole.set(b, v);
2818
+ return v;
2819
+ }
2711
2820
  var _topClosed = new WeakMap;
2821
+ function studSquareLines(E, w, hole) {
2822
+ const n = Math.floor(E.length / 6);
2823
+ if (!n)
2824
+ return null;
2825
+ const loops = new Map;
2826
+ const cls = (q) => {
2827
+ const r = Math.hypot(E[q], E[q + 2]);
2828
+ return Math.abs(r - 6) <= 0.02 ? "o" : hole && Math.abs(r - hole.r) <= 0.02 ? "i" : null;
2829
+ };
2830
+ for (let s = 0;s < n; s++) {
2831
+ const o = s * 6;
2832
+ const y0 = E[o + 1], y1 = E[o + 4];
2833
+ if (Math.abs(y0 - y1) > 0.001)
2834
+ return null;
2835
+ const c0 = cls(o);
2836
+ if (!c0 || cls(o + 3) !== c0)
2837
+ return null;
2838
+ const k = String(Math.round(y0 * 100) / 100 + 0) + c0;
2839
+ const L = loops.get(k) || loops.set(k, { segs: 0, len: 0, deg: new Map }).get(k);
2840
+ L.segs++;
2841
+ L.len = Math.max(L.len, Math.hypot(E[o + 3] - E[o], E[o + 5] - E[o + 2]));
2842
+ for (const q of [o, o + 3]) {
2843
+ const vk = Math.round(E[q] * 100) + 0 + "," + (Math.round(E[q + 2] * 100) + 0);
2844
+ L.deg.set(vk, (L.deg.get(vk) ?? 0) + 1);
2845
+ }
2846
+ }
2847
+ for (const L of loops.values())
2848
+ if (L.segs < 8 || L.deg.size !== L.segs || [...L.deg.values()].some((d) => d !== 2))
2849
+ return null;
2850
+ const ord = [...loops.entries()].sort((a, b) => b[1].len - a[1].len);
2851
+ const C = [[-w, -w], [w, -w], [w, w], [-w, w]];
2852
+ const pos = new Float32Array(ord.length * 24), lens = new Float32Array(ord.length * 4);
2853
+ ord.forEach(([yk, L], i) => {
2854
+ const y = parseFloat(yk), h = yk.endsWith("i") ? hole.w / w : 1;
2855
+ for (let c = 0;c < 4; c++) {
2856
+ const a = C[c], b = C[(c + 1) % 4];
2857
+ pos.set([a[0] * h, y, a[1] * h, b[0] * h, y, b[1] * h], (i * 4 + c) * 6);
2858
+ lens[i * 4 + c] = L.len;
2859
+ }
2860
+ });
2861
+ return { pos, lens };
2862
+ }
2863
+ function boxLevelLines(pos) {
2864
+ if (pos.length < 24)
2865
+ return null;
2866
+ const lo = [Infinity, Infinity, Infinity], hi = [-Infinity, -Infinity, -Infinity];
2867
+ for (let i = 0;i < pos.length; i += 3)
2868
+ for (let k = 0;k < 3; k++) {
2869
+ lo[k] = Math.min(lo[k], pos[i + k]);
2870
+ hi[k] = Math.max(hi[k], pos[i + k]);
2871
+ }
2872
+ for (let i = 0;i < pos.length; i += 3)
2873
+ for (let k = 0;k < 3; k++)
2874
+ if (pos[i + k] !== lo[k] && pos[i + k] !== hi[k])
2875
+ return null;
2876
+ if (!(hi[0] > lo[0] && hi[1] > lo[1] && hi[2] > lo[2]))
2877
+ return null;
2878
+ const c = (i) => [i & 1 ? hi[0] : lo[0], i & 2 ? hi[1] : lo[1], i & 4 ? hi[2] : lo[2]];
2879
+ const out = [];
2880
+ for (let i = 0;i < 8; i++)
2881
+ for (const b of [1, 2, 4])
2882
+ if (!(i & b))
2883
+ out.push(...c(i), ...c(i | b));
2884
+ return new Float32Array(out);
2885
+ }
2712
2886
  function studTopClosed(b, arr) {
2713
2887
  if (!b)
2714
2888
  return false;
@@ -2817,6 +2991,7 @@ class LdrLodRoot extends THREE.LOD {
2817
2991
  hi = mid;
2818
2992
  }
2819
2993
  l.geometry.drawRange.count = lo * 2;
2994
+ l.visible = lo > 0 && l.userData.ldrVis !== false;
2820
2995
  }
2821
2996
  }
2822
2997
  }
@@ -3174,11 +3349,12 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
3174
3349
  return l;
3175
3350
  };
3176
3351
  const lineCache = new Map;
3177
- const addLines = (ref, im, cl) => {
3352
+ const boxLineCache = new Map;
3353
+ const addLines = (ref, im, cl, src) => {
3178
3354
  let w = lineCache.get(ref);
3179
3355
  if (!w) {
3180
- const r = weldLines(arr(ref), LOD);
3181
- lineCache.set(ref, w = { P: new THREE.BufferAttribute(r.P, 3), I: new THREE.BufferAttribute(r.I, 1), lens: r.lens });
3356
+ const r = weldLines(src ? src.pos : arr(ref), LOD && !src?.lens);
3357
+ lineCache.set(ref, w = { P: new THREE.BufferAttribute(r.P, 3), I: new THREE.BufferAttribute(r.I, 1), lens: src?.lens ?? r.lens });
3182
3358
  }
3183
3359
  const g = new THREE.InstancedBufferGeometry;
3184
3360
  g.setAttribute("position", w.P);
@@ -3332,8 +3508,21 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
3332
3508
  const cl = newCluster(bodyIm.boundingSphere, bodyIm);
3333
3509
  lv0.forEach((o) => o.onBeforeRender = trackVp);
3334
3510
  cl.lv.push({ objs: lv0, err: 0 }, ...textured ? [] : lodLevels(p.body, bodyIm, mat));
3335
- if (EDGES && p.edges)
3336
- addLines(p.edges, bodyIm, cl);
3511
+ if (EDGES && p.edges) {
3512
+ const full = addLines(p.edges, bodyIm, cl);
3513
+ const bl = !textured && LOD ? p.body?.lod : null;
3514
+ const last = bl?.[bl.length - 1];
3515
+ if (last && last.tris === 12 && cl.lv.length === bl.length + 1) {
3516
+ let bx = boxLineCache.get(last);
3517
+ if (bx === undefined)
3518
+ boxLineCache.set(last, bx = boxLevelLines(arr(last.pos)));
3519
+ if (bx) {
3520
+ const l = addLines(last, bodyIm, cl, { pos: bx });
3521
+ full.userData.ldrLineLvs = [0, bl.length - 1];
3522
+ l.userData.ldrLineLvs = [bl.length, bl.length];
3523
+ }
3524
+ }
3525
+ }
3337
3526
  addCond(p, bodyIm, cl);
3338
3527
  if (steps)
3339
3528
  stepBatches.push({ im: bodyIm, objs: [...cl.lv.flatMap((l) => l.objs), ...cl.lines, ...cl.cond], own: Int32Array.from(ids, (id) => steps[id]), hide: null, flag: "body", inst: Int32Array.from(ids), stud: null, col: Uint16Array.from(ids, (id) => instCol[id]) });
@@ -3684,6 +3873,7 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
3684
3873
  const STUD_BOX_W_LOW = 5.317;
3685
3874
  const STUD_DISC_ERR = 8;
3686
3875
  let _coopS = 0;
3876
+ const sqLineKey = new Map;
3687
3877
  for (let ci = 0;ci < sMesh.length; ci++) {
3688
3878
  const sm = sMesh[ci];
3689
3879
  if (!sm)
@@ -3703,8 +3893,11 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
3703
3893
  cl.studLineLv = 0;
3704
3894
  cl.lv.push({ objs: [im], err: 0 });
3705
3895
  const discObjs = [];
3706
- if (LOD && studTopClosed(k.body, arr) && (im.geometry.getIndex()?.count ?? im.geometry.getAttribute("position").count) > 30) {
3707
- const box = new THREE.InstancedMesh(studBoxGeom(/(^|[\\/])8[\\/]/.test(kind) ? STUD_BOX_W_LOW : 6), im.material, 0);
3896
+ const sqW = /(^|[\\/])8[\\/]/.test(kind) ? STUD_BOX_W_LOW : 6;
3897
+ const h = studTopClosed(k.body, arr) ? null : studHole(k.body, arr);
3898
+ const hole = h ? { r: h.r, w: h.r * Math.sqrt(Math.PI) / 2 } : undefined;
3899
+ if (LOD && (hole || studTopClosed(k.body, arr)) && (im.geometry.getIndex()?.count ?? im.geometry.getAttribute("position").count) > 30) {
3900
+ const box = new THREE.InstancedMesh(hole ? studTubeGeom(sqW, hole.w) : studBoxGeom(sqW), im.material, 0);
3708
3901
  box.userData = { ldrStud: true, ldrLod: true };
3709
3902
  box.instanceMatrix = im.instanceMatrix;
3710
3903
  box.count = im.count;
@@ -3714,7 +3907,7 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
3714
3907
  box.onBeforeRender = trackVp;
3715
3908
  root.add(box);
3716
3909
  discObjs.push(box);
3717
- cl.lv.push({ objs: [box], err: STUD_BOX_ERR });
3910
+ cl.lv.push({ objs: [box], err: h ? Math.max(STUD_BOX_ERR, 6 * Math.SQRT2 - h.out) : STUD_BOX_ERR });
3718
3911
  cl.studLineLv = 1;
3719
3912
  }
3720
3913
  if (LOD) {
@@ -3731,8 +3924,19 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
3731
3924
  cl.lv.push({ objs: [disc], err: STUD_DISC_ERR });
3732
3925
  cl.lv.push({ objs: [], err: STUD_ERR });
3733
3926
  }
3734
- if (EDGES && k.edges)
3735
- addLines(k.edges, im, cl);
3927
+ if (EDGES && k.edges) {
3928
+ const round = addLines(k.edges, im, cl);
3929
+ let sq = cl.studLineLv === 1 && round ? sqLineKey.get(kind) : null;
3930
+ if (sq === undefined) {
3931
+ const r = studSquareLines(arr(k.edges), sqW, hole);
3932
+ sqLineKey.set(kind, sq = r && { sq: r });
3933
+ }
3934
+ if (sq && round) {
3935
+ const l = addLines(sq, im, cl, sq.sq);
3936
+ round.userData.ldrLineLvs = [0, 0];
3937
+ l.userData.ldrLineLvs = [1, 1];
3938
+ }
3939
+ }
3736
3940
  if (P.condStuds !== false)
3737
3941
  addCond(k, im, cl);
3738
3942
  const objs = [im, ...discObjs, ...cl.lines, ...cl.cond];
@@ -3760,8 +3964,12 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
3760
3964
  o.visible = i === c.cur;
3761
3965
  });
3762
3966
  const lineVis = edgesOn && c.edgeOk && c.cur >= 0 && (c.studLineLv !== undefined ? c.cur <= c.studLineLv : c.cur === 0 || !LOD || (c.setMergedLevel ? true : c.lv[c.cur].objs.length > 0));
3763
- for (const o of c.lines)
3764
- o.visible = lineVis;
3967
+ for (const o of c.lines) {
3968
+ const lv = o.userData.ldrLineLvs;
3969
+ const v = lineVis && (!lv || c.cur >= lv[0] && c.cur <= lv[1]);
3970
+ o.userData.ldrVis = v;
3971
+ o.visible = v && o.geometry.drawRange.count !== 0;
3972
+ }
3765
3973
  for (const o of c.cond)
3766
3974
  o.visible = lineVis && condOn;
3767
3975
  };
@@ -3990,7 +4198,7 @@ async function warmPackGeometry(pack, stop = () => false, sliceMs = 8) {
3990
4198
  await new Promise((r) => setTimeout(r, 0));
3991
4199
  }
3992
4200
  }
3993
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/scene.ts
4201
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/scene.ts
3994
4202
  import * as THREE2 from "three";
3995
4203
  var _box = new THREE2.Box3;
3996
4204
  var _m4 = new THREE2.Matrix4;
@@ -4345,10 +4553,10 @@ function createLdrObjectInner(instances, pack, options, progressive) {
4345
4553
  return finish();
4346
4554
  })();
4347
4555
  }
4348
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/parts-cdn.ts
4556
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/parts-cdn.ts
4349
4557
  import { decompress as decompress2 } from "fzstd";
4350
4558
 
4351
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/embedded.ts
4559
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/embedded.ts
4352
4560
  function splitFiles(text, fallback) {
4353
4561
  const files = new Map;
4354
4562
  let cur = null, saw = false, skip = false;
@@ -4423,7 +4631,7 @@ function embeddedKeys(text, names, fallback = "main.ldr") {
4423
4631
  return out;
4424
4632
  }
4425
4633
 
4426
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/parts-cdn.ts
4634
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/parts-cdn.ts
4427
4635
  var DEFAULT_PARTS_CDN = "https://ldr-demo.vercel.app/cdn/v1/";
4428
4636
  var indexCache = new Map;
4429
4637
  var shardCache = new Map;
@@ -4677,10 +4885,10 @@ async function prepareModel(source, o = {}) {
4677
4885
  return { insts, pack, tier, missing, requests, bytes, cull, timings: { fetchModel: t1 - t0, parse: t2 - t1, parts: t3 - t2, ...cull ? { cull: performance.now() - t3 } : {} } };
4678
4886
  }
4679
4887
 
4680
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/load-worker.gen.ts
4888
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/load-worker.gen.ts
4681
4889
  var load_worker_gen_default = 'var Ft=ArrayBuffer,ee=Uint8Array,we=Uint16Array,Rt=Int16Array;var Me=Int32Array,Ie=function(e,t,n){if(ee.prototype.slice)return ee.prototype.slice.call(e,t,n);if(t==null||t<0)t=0;if(n==null||n>e.length)n=e.length;var r=new ee(n-t);return r.set(e.subarray(t,n)),r},he=function(e,t,n,r){if(ee.prototype.fill)return ee.prototype.fill.call(e,t,n,r);if(n==null||n<0)n=0;if(r==null||r>e.length)r=e.length;for(;n<r;++n)e[n]=t;return e},Bt=function(e,t,n,r){if(ee.prototype.copyWithin)return ee.prototype.copyWithin.call(e,t,n,r);if(n==null||n<0)n=0;if(r==null||r>e.length)r=e.length;while(n<r)e[t++]=e[n++]};var Dt=["invalid zstd data","window size too large (>2046MB)","invalid block type","FSE accuracy too high","match distance too far back","unexpected EOF"],te=function(e,t,n){var r=Error(t||Dt[e]);if(r.code=e,Error.captureStackTrace)Error.captureStackTrace(r,te);if(!n)throw r;return r},Qe=function(e,t,n){var r=0,s=0;for(;r<n;++r)s|=e[t++]<<(r<<3);return s},Ut=function(e,t){return(e[t]|e[t+1]<<8|e[t+2]<<16|e[t+3]<<24)>>>0},Ot=function(e,t){var n=e[0]|e[1]<<8|e[2]<<16;if(n==3126568&&e[3]==253){var r=e[4],s=r>>5&1,o=r>>2&1,i=r&3,c=r>>6;if(r&8)te(0);var u=6-s,f=i==3?4:i,a=Qe(e,u,f);u+=f;var l=c?1<<c:s,m=Qe(e,u,l)+(c==1&&256),g=m;if(!s){var d=1<<10+(e[5]>>3);g=d+(d>>3)*(e[5]&7)}if(g>2145386496)te(1);var b=new ee((t==1?m||g:t?0:g)+12);return b[0]=1,b[4]=4,b[8]=8,{b:u+l,y:0,l:0,d:a,w:t&&t!=1?t:b.subarray(12),e:g,o:new Me(b.buffer,0,3),u:m,c:o,m:Math.min(131072,g)}}else if((n>>4|e[3]<<20)==25481893)return Ut(e,4)+8;te(0)},le=function(e){var t=0;for(;1<<t<=e;++t);return t-1},ge=function(e,t,n){var r=(t<<3)+4,s=(e[t]&15)+5;if(s>n)te(3);var o=1<<s,i=o,c=-1,u=-1,f=-1,a=o,l=new Ft(512+(o<<2)),m=new Rt(l,0,256),g=new we(l,0,256),d=new we(l,512,o),b=512+(o<<1),C=new ee(l,b,o),A=new ee(l,b+o);while(c<255&&i>0){var p=le(i+1),h=r>>3,M=(1<<p+1)-1,D=(e[h]|e[h+1]<<8|e[h+2]<<16)>>(r&7)&M,v=(1<<p)-1,L=M-i-1,R=D&v;if(R<L)r+=p,D=R;else if(r+=p+1,D>v)D-=L;if(m[++c]=--D,D==-1)i+=D,C[--a]=c;else i-=D;if(!D)do{var T=r>>3;u=(e[T]|e[T+1]<<8)>>(r&7)&3,r+=2,c+=u}while(u==3)}if(c>255||i)te(0);var x=0,w=(o>>1)+(o>>3)+3,E=o-1;for(var z=0;z<=c;++z){var k=m[z];if(k<1){g[z]=-k;continue}for(f=0;f<k;++f){C[x]=z;do x=x+w&E;while(x>=a)}}if(x)te(0);for(f=0;f<o;++f){var P=g[C[f]]++,Y=A[f]=s-le(P);d[f]=(P<<Y)-o}return[r+7>>3,{b:s,s:C,n:A,t:d}]},Nt=function(e,t){var n=0,r=-1,s=new ee(292),o=e[t],i=s.subarray(0,256),c=s.subarray(256,268),u=new we(s.buffer,268);if(o<128){var f=ge(e,t+1,6),a=f[0],l=f[1];t+=o;var m=a<<3,g=e[t];if(!g)te(0);var d=0,b=0,C=l.b,A=C,p=(++t<<3)-8+le(g);for(;;){if(p-=C,p<m)break;var h=p>>3;if(d+=(e[h]|e[h+1]<<8)>>(p&7)&(1<<C)-1,i[++r]=l.s[d],p-=A,p<m)break;h=p>>3,b+=(e[h]|e[h+1]<<8)>>(p&7)&(1<<A)-1,i[++r]=l.s[b],C=l.n[d],d=l.t[d],A=l.n[b],b=l.t[b]}if(++r>255)te(0)}else{r=o-127;for(;n<r;n+=2){var M=e[++t];i[n]=M>>4,i[n+1]=M&15}++t}var D=0;for(n=0;n<r;++n){var v=i[n];if(v>11)te(0);D+=v&&1<<v-1}var L=le(D)+1,R=1<<L,T=R-D;if(T&T-1)te(0);i[r++]=le(T)+1;for(n=0;n<r;++n){var v=i[n];++c[i[n]=v&&L+1-v]}var x=new ee(R<<1),w=x.subarray(0,R),E=x.subarray(R);u[L]=0;for(n=L;n>0;--n){var z=u[n];he(E,n,z,u[n-1]=z+c[n]*(1<<L-n))}if(u[0]!=R)te(0);for(n=0;n<r;++n){var k=i[n];if(k){var P=u[k];he(w,n,P,u[k]=P+(1<<L-k))}}return[t,{n:E,b:L,s:w}]},zt=ge(new ee([81,16,99,140,49,198,24,99,12,33,196,24,99,102,102,134,70,146,4]),0,6)[1],$t=ge(new ee([33,20,196,24,99,140,33,132,16,66,8,33,132,16,66,8,33,68,68,68,68,68,68,68,68,36,9]),0,6)[1],jt=ge(new ee([32,132,16,66,102,70,68,68,68,68,36,73,2]),0,5)[1],qe=function(e,t){var n=e.length,r=new Me(n);for(var s=0;s<n;++s)r[s]=t,t+=1<<e[s];return r},Fe=new ee(new Me([0,0,0,0,16843009,50528770,134678020,202050057,269422093]).buffer,0,36),Vt=qe(Fe,0),Re=new ee(new Me([0,0,0,0,0,0,0,0,16843009,50528770,117769220,185207048,252579084,16]).buffer,0,53),_t=qe(Re,3),me=function(e,t,n){var r=e.length,s=t.length,o=e[r-1],i=(1<<n.b)-1,c=-n.b;if(!o)te(0);var u=0,f=n.b,a=(r<<3)-8+le(o)-f,l=-1;for(;a>c&&l<s;){var m=a>>3,g=(e[m]|e[m+1]<<8|e[m+2]<<16)>>(a&7);u=(u<<f|g)&i,t[++l]=n.s[u],a-=f=n.n[u]}if(a!=c||l+1!=s)te(0)},Ht=function(e,t,n){var r=6,s=t.length,o=s+3>>2,i=o<<1,c=o+i;me(e.subarray(r,r+=e[0]|e[1]<<8),t.subarray(0,o),n),me(e.subarray(r,r+=e[2]|e[3]<<8),t.subarray(o,i),n),me(e.subarray(r,r+=e[4]|e[5]<<8),t.subarray(i,c),n),me(e.subarray(r),t.subarray(c),n)},Gt=function(e,t,n){var r,s=t.b,o=e[s],i=o>>1&3;t.l=o&1;var c=o>>3|e[s+1]<<5|e[s+2]<<13,u=(s+=3)+c;if(i==1){if(s>=e.length)return;if(t.b=s+1,n)return he(n,e[s],t.y,t.y+=c),n;return he(new ee(c),e[s])}if(u>e.length)return;if(i==0){if(t.b=u,n)return n.set(e.subarray(s,u),t.y),t.y+=c,n;return Ie(e,s,u)}if(i==2){var f=e[s],a=f&3,l=f>>2&3,m=f>>4,g=0,d=0;if(a<2)if(l&1)m|=e[++s]<<4|(l&2&&e[++s]<<12);else m=f>>3;else if(d=l,l<2)m|=(e[++s]&63)<<4,g=e[s]>>6|e[++s]<<2;else if(l==2)m|=e[++s]<<4|(e[++s]&3)<<12,g=e[s]>>2|e[++s]<<6;else m|=e[++s]<<4|(e[++s]&63)<<12,g=e[s]>>6|e[++s]<<2|e[++s]<<10;++s;var b=n?n.subarray(t.y,t.y+t.m):new ee(t.m),C=b.length-m;if(a==0)b.set(e.subarray(s,s+=m),C);else if(a==1)he(b,e[s++],C);else{var A=t.h;if(a==2){var p=Nt(e,s);g+=s-(s=p[0]),t.h=A=p[1]}else if(!A)te(0);(d?Ht:me)(e.subarray(s,s+=g),b.subarray(C),A)}var h=e[s++];if(h){if(h==255)h=(e[s++]|e[s++]<<8)+32512;else if(h>127)h=h-128<<8|e[s++];var M=e[s++];if(M&3)te(0);var D=[$t,jt,zt];for(var v=2;v>-1;--v){var L=M>>(v<<1)+2&3;if(L==1){var R=new ee([0,0,e[s++]]);D[v]={s:R.subarray(2,3),n:R.subarray(0,1),t:new we(R.buffer,0,1),b:0}}else if(L==2)r=ge(e,s,9-(v&1)),s=r[0],D[v]=r[1];else if(L==3){if(!t.t)te(0);D[v]=t.t[v]}}var T=t.t=D,x=T[0],w=T[1],E=T[2],z=e[u-1];if(!z)te(0);var k=(u<<3)-8+le(z)-E.b,P=k>>3,Y=0,I=(e[P]|e[P+1]<<8)>>(k&7)&(1<<E.b)-1;P=(k-=w.b)>>3;var j=(e[P]|e[P+1]<<8)>>(k&7)&(1<<w.b)-1;P=(k-=x.b)>>3;var H=(e[P]|e[P+1]<<8)>>(k&7)&(1<<x.b)-1;for(++h;--h;){var Z=E.s[I],O=E.n[I],G=x.s[H],K=x.n[H],J=w.s[j],Q=w.n[j];P=(k-=J)>>3;var S=1<<J,y=S+((e[P]|e[P+1]<<8|e[P+2]<<16|e[P+3]<<24)>>>(k&7)&S-1);P=(k-=Re[G])>>3;var B=_t[G]+((e[P]|e[P+1]<<8|e[P+2]<<16)>>(k&7)&(1<<Re[G])-1);P=(k-=Fe[Z])>>3;var _=Vt[Z]+((e[P]|e[P+1]<<8|e[P+2]<<16)>>(k&7)&(1<<Fe[Z])-1);if(P=(k-=O)>>3,I=E.t[I]+((e[P]|e[P+1]<<8)>>(k&7)&(1<<O)-1),P=(k-=K)>>3,H=x.t[H]+((e[P]|e[P+1]<<8)>>(k&7)&(1<<K)-1),P=(k-=Q)>>3,j=w.t[j]+((e[P]|e[P+1]<<8)>>(k&7)&(1<<Q)-1),y>3)t.o[2]=t.o[1],t.o[1]=t.o[0],t.o[0]=y-=3;else{var W=y-(_!=0);if(W){if(y=W==3?t.o[0]-1:t.o[W],W>1)t.o[2]=t.o[1];t.o[1]=t.o[0],t.o[0]=y}else y=t.o[0]}for(var v=0;v<_;++v)b[Y+v]=b[C+v];Y+=_,C+=_;var X=Y-y;if(X<0){var N=-X,q=t.e+X;if(N>B)N=B;for(var v=0;v<N;++v)b[Y+v]=t.w[q+v];Y+=N,B-=N,X=0}for(var v=0;v<B;++v)b[Y+v]=b[X+v];Y+=B}if(Y!=C)while(C<b.length)b[Y++]=b[C++];else Y=b.length;if(n)t.y+=Y;else b=Ie(b,0,Y)}else if(n){if(t.y+=m,C)for(var v=0;v<m;++v)b[v]=b[C+v]}else if(C)b=Ie(b,C);return t.b=u,b}te(2)},Wt=function(e,t){if(e.length==1)return e[0];var n=new ee(t);for(var r=0,s=0;r<e.length;++r){var o=e[r];n.set(o,s),s+=o.length}return n};function Ae(e,t){var n=[],r=+!t,s=0,o=0;for(;e.length;){var i=Ot(e,r||t);if(typeof i=="object"){if(r){if(t=null,i.w.length==i.u)n.push(t=i.w),o+=i.u}else n.push(t),i.e=0;for(;!i.l;){var c=Gt(e,i,t);if(!c)te(5);if(t)i.e=i.y;else n.push(c),o+=c.length,Bt(i.w,0,c.length),i.w.set(c,i.w.length-c.length)}s=i.b+i.c*4}else s=i;e=e.subarray(s)}return Wt(n,o)}async function Kt(e){let t=e instanceof Uint8Array?e:new Uint8Array(e),n=(r)=>r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);if(t[0]===40&&t[1]===181&&t[2]===47&&t[3]===253)return n(Ae(t));if(t[0]===31&&t[1]===139)return new Response(new Blob([t]).stream().pipeThrough(new DecompressionStream("gzip"))).arrayBuffer();return n(t)}async function et(e){return new TextDecoder().decode(await Kt(e))}var tt=(e)=>decodeURIComponent(e.split(/[?#]/)[0].split("/").pop()||"main.ldr").replace(/\\.(zst|gz)$/i,"")||"main.ldr";function ve(e){let t=new DataView(e).getUint32(0,!0),n=JSON.parse(new TextDecoder().decode(new Uint8Array(e,4,t))),r=4+t;return{header:n,arr:(o)=>o&&(o[2]==="f32"?new Float32Array(e,r+o[0],o[1]):o[2]==="u16"?new Uint16Array(e,r+o[0],o[1]):o[2]==="u8"?new Uint8Array(e,r+o[0],o[1]):new Uint32Array(e,r+o[0],o[1])),bytes:e.byteLength,buffer:e}}var ne=(e)=>e.trim().toLowerCase().replace(/\\\\/g,"/").replace(/\\/+/g,"/"),De=/^[A-Za-z][A-Za-z0-9_]*$/,Be=new Map;function Ue(e){let t=e.toLowerCase(),n=2166136261;for(let s=0;s<t.length;s++)n^=t.charCodeAt(s),n=Math.imul(n,16777619);let r=-1-(n>>>0&1073741823);if(!Be.has(r))Be.set(r,t);return r}function Oe(e){let t=e.charCodeAt(0)|32;if(t>=97&&t<=122&&De.test(e))return Ue(e);if(/^0x/i.test(e))return parseInt(e,16);return+e}var nt=/^~?\\s*moved\\s+to\\s+(.+)$/i,Xt=new Set(["FILE","NOFILE","!DATA","!:","STEP","BFC","ROTSTEP","BUFEXCHG","!TEXMAP"]),Zt=new Set(["FILE","NOFILE","!DATA"]),ut=1000000000000000,ft=new Set(["part","subpart","primitive","8_primitive","48_primitive","shortcut","helper"]),Yt=new Set(["model","submodel","configuration"]),Jt=/^(?:!?LDRAW_ORG|Unofficial|Official\\s+LCAD)\\s+(\\S+)/i;function rt(e){let t=Jt.exec(e);if(!t)return;let n=t[1].toLowerCase().replace(/^unofficial_/,"");return ft.has(n)||Yt.has(n)?n:void 0}function Qt(e){let t=[],n=0;while(n<e.length){while(e[n]===" "||e[n]==="\\t")n++;if(n>=e.length)break;if(e[n]===\'"\'){let r="";n++;while(n<e.length&&e[n]!==\'"\'){if(e[n]==="\\\\"&&n+1<e.length)n++;r+=e[n++]}n++,t.push(r)}else{let r=n;while(r<e.length&&e[r]!==" "&&e[r]!=="\\t")r++;t.push(e.slice(n,r)),n=r}}return t}function qt(e,t=!1){let n=/^\\s*(\\S+)\\s+(.*)$/.exec(e);if(!n)return null;let r=n[1].toUpperCase(),s=r==="PLANAR"?9:r==="CYLINDRICAL"?10:r==="SPHERICAL"?11:0;if(!s)return null;let o=n[2].trim().split(/\\s+/);if(o.length<s+1)return null;let i=o.slice(0,s).map(Number);if(!i.every((l)=>Number.isFinite(l)&&Math.abs(l)<=1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000))return null;if(s>=10&&!(Math.abs(i[9])>=0.000001)||s===11&&!(Math.abs(i[10])>=0.000001))return null;let c=n[2].trim();for(let l=0;l<s;l++)c=c.replace(/^\\S+\\s*/,"");let u=Qt(c);if(!u.length)return null;let f={method:r,p1:i.slice(0,3),p2:i.slice(3,6),p3:i.slice(6,9),texture:u[0]};if(s>=10)f.a=i[9];if(s===11)f.b=i[10];let a=u.findIndex((l,m)=>m>0&&l.toUpperCase()==="GLOSSMAP");if(a>0&&u[a+1])f.glossmap=u[a+1];if(t)f.next=!0;return f}var en=(e)=>{let t=e.replace(/[^A-Za-z0-9+/]/g,"");if(t.length%4===1)t=t.slice(0,-1);let n=t+"=".repeat((4-t.length%4)%4),r=atob(n),s=new Uint8Array(r.length);for(let o=0;o<r.length;o++)s[o]=r.charCodeAt(o);return s};function tn(e){let t=e.length,n=1,r=(a)=>a===32||a===9,s=()=>{while(n<t&&r(e.charCodeAt(n)))n++;let a=n;while(n<t&&!r(e.charCodeAt(n)))n++;return a<n?e.slice(a,n):null},o=s();if(o===null)return null;let i=Array(12);for(let a=0;a<12;a++){let l=s();if(l===null)return null;let m=+l;if(!Number.isFinite(m))return null;i[a]=m}while(n<t&&r(e.charCodeAt(n)))n++;if(n>=t)return null;let c=e.slice(n),u=/[ \\t]{2,}|\\t/.test(c)?c.split(/\\s+/).join(" "):c,f=Oe(o);if(!Number.isFinite(f))return null;return{t:1,color:f,m:i,file:ne(u)}}var nn=[0,12,6,9,12,12];function st(e){let t=+e[0];if(!(t>=1&&t<=5&&Number.isInteger(t))||e.length<2)return null;let n=Oe(e[1]),r=nn[t];if(!Number.isFinite(n)||e.length<2+r+(t===1?1:0))return null;let s=Array(r);for(let o=0;o<r;o++){let i=+e[2+o];if(!Number.isFinite(i))return null;s[o]=i}if(t===1){let o=ne(e.slice(14).join(" "));return o?{t:1,color:n,m:s,file:o}:null}if(t===2)return{t:2,color:n,p:s};if(t===3)return{t:3,color:n,p:s};if(t===4)return{t:4,color:n,p:s};return{t:5,color:n,p:s}}function pt(e,t="main.ldr",n={}){let r=!!n.geometryText,s=new Map,o=null,i="",c,u=null,f=[],a=null,l=()=>{if(!u)return;let p=en(u.chunks.join("")),h=p[0]===137&&p[1]===80&&p[2]===78&&p[3]===71;(c??=new Map).set(ne(u.name),{name:u.name,bytes:p,...h?{mime:"image/png"}:{}}),u=null},m=!0,g=(p)=>{if(l(),o={name:ne(p),cmds:[]},s.set(o.name,o),!i)i=o.name;f=[],a=null,m=!0},d=!1,b=!1,C=()=>{if(b)return;b=!0,s.clear(),o=null,i=""},A=(p,h)=>{if(a){p.tex=a,a=null;return}let M=f[f.length-1];if(!M)return;if(M.fallback){if(!h)p.fallback=!0}else p.tex=M.map};for(let p of e.split(`\n`)){let h=p.trim();if(!h)continue;if(r&&h.charCodeAt(0)>=50&&h.charCodeAt(0)<=53&&(h.charCodeAt(1)===32||h.charCodeAt(1)===9)){if(u||d)continue;if(!o)g(t);let L=h.slice(2).trimStart(),R=L.search(/\\s/),T={t:h.charCodeAt(0)-48,color:Oe(R<0?L:L.slice(0,R)),p:[],src:h};A(T,!1),o.cmds.push(T),m=!1;continue}if(h.charCodeAt(0)===48&&(h.charCodeAt(1)===32||h.charCodeAt(1)===9)){let L=2;while(h.charCodeAt(L)===32||h.charCodeAt(L)===9)L++;let R=L;while(R<h.length&&h.charCodeAt(R)!==32&&h.charCodeAt(R)!==9)R++;let T=h.slice(L,R),x=/[^\\x21-\\x7e]/.test(T)?h.slice(L).trim().split(/\\s+/)[0]:T;if(!Xt.has(x)&&!(x.length>=4&&x.length<=6&&Zt.has(x.toUpperCase()))){if(d||u)continue;if(!o)g(t);let w=h.slice(L),E={t:0,text:w};if(T.charCodeAt(0)===33)E.meta=T;if(a=null,m&&!o.org){let k=rt(w);if(k)o.org=k}let z=w.match(nt);if(z&&!o.movedTo){let k=z[1].trim().replace(/\\\\/g,"/");if(!/\\.(dat|ldr|mpd)$/i.test(k))k+=".dat";o.movedTo=ne(k)}o.cmds.push(E);continue}}if(h.charCodeAt(0)===49&&(h.charCodeAt(1)===32||h.charCodeAt(1)===9)&&!u&&!d){let L=tn(h);if(L){if(!o)g(t);A(L,!1),o.cmds.push(L),m=!1;continue}}let M=h.split(/\\s+/);if(+M[0]===0){let L=h.slice(1).trim(),R=M.length>1&&M[1].length>=4&&M[1].length<=6?M[1].toUpperCase():M[1];if(R==="FILE"){let w=L.slice(5).trimStart().split("\\r")[0].trim();if(w){C(),d=!1,g(w);continue}}if(R==="NOFILE"){l(),o=null,d=!0;continue}if(R==="!DATA"){C(),l(),o=null,d=!1,u={name:L.slice(5).trim(),chunks:[]};continue}if(d)continue;if(u){if(M[1]==="!:")u.chunks.push(M.slice(2).join(""));continue}if(!o)g(t);let T={t:0,text:L};if(M[1]==="STEP")T.step=!0,f=[],a=null;else if(M[1]==="BFC")T.bfc=M.slice(2).join(" ");else if(M[1]==="ROTSTEP")if(T.meta="ROTSTEP",T.step=!0,f=[],a=null,(M[2]??"").toUpperCase()==="END")T.rotstep={x:0,y:0,z:0,mode:"END"};else{let w=(M[5]??"REL").toUpperCase(),E=(z)=>{let k=Number(z);return Number.isFinite(k)?k:0};T.rotstep={x:E(M[2]),y:E(M[3]),z:E(M[4]),mode:["REL","ABS","ADD"].includes(w)?w:"REL"}}else if(M[1]==="BUFEXCHG"){T.meta="BUFEXCHG";let w=(M[2]??"").toUpperCase();T.bufexchg={op:w==="RETRIEVE"?"RETRIEVE":"STORE",buf:M[3]??"A"}}else if(M[1]?.startsWith("!"))T.meta=M[1];if(m&&!o.org){let w=rt(L);if(w)o.org=w}if(M[1]==="!TEXMAP"){let w=(M[2]??"").toUpperCase();if(a=null,w==="START"||w==="NEXT"){let E=qt(L.replace(/^!TEXMAP\\s+\\S+/i,""),w==="NEXT");if(T.texmap={op:w,...E?{map:E}:{}},E)if((o.texmaps??=[]).push(E),w==="START")f.push({map:E,fallback:!1});else a=E}else if(w==="FALLBACK"){T.texmap={op:w};let E=f[f.length-1];if(E)E.fallback=!0}else if(w==="END")T.texmap={op:w},f.pop()}else if(M[1]==="!:"){a=null;let w=st(M.slice(2));if(w)A(w,!0),T.geom=w}else a=null;let x=L.match(nt);if(x&&!o.movedTo){let w=x[1].trim().replace(/\\\\/g,"/");if(!/\\.(dat|ldr|mpd)$/i.test(w))w+=".dat";o.movedTo=ne(w)}o.cmds.push(T);continue}if(u||d)continue;if(!o)g(t);let v=st(M);if(!v){if(/^[2-5][ \\t]/.test(h))m=!1;continue}A(v,!1),o.cmds.push(v),m=!1}return l(),c?{main:i,files:s,data:c}:{main:i,files:s}}var Pn=Math.PI/180;function mt(e,t){let n=(r)=>[t[3]*r[0]+t[4]*r[1]+t[5]*r[2]+t[0],t[6]*r[0]+t[7]*r[1]+t[8]*r[2]+t[1],t[9]*r[0]+t[10]*r[1]+t[11]*r[2]+t[2]];return{...e,p1:n(e.p1),p2:n(e.p2),p3:n(e.p3)}}function ht(e,t){let[n,r,s,o,i,c,u,f,a,l,m,g]=e,[d,b,C,A,p,h,M,D,v,L,R,T]=t;return[o*d+i*b+c*C+n,u*d+f*b+a*C+r,l*d+m*b+g*C+s,o*A+i*M+c*L,o*p+i*D+c*R,o*h+i*v+c*T,u*A+f*M+a*L,u*p+f*D+a*R,u*h+f*v+a*T,l*A+m*M+g*L,l*p+m*D+g*R,l*h+m*v+g*T]}var Ne=[0,0,0,1,0,0,0,1,0,0,0,1];var ot=new WeakMap,rn=/^(s|8|48)\\//;function ze(e,t){let n=e.files.get(ne(t));if(!n)return"part";let r=ot.get(n);if(r)return r;if(n.org)r=ft.has(n.org)?"part":"model";else if(n.name===e.main)r="model";else r=n.cmds.some((s)=>s.t>=2||s.t===0&&!!s.geom||s.t===1&&rn.test(s.file))?"part":"model";return ot.set(n,r),r}var it=new WeakMap;function gt(e){let t=it.get(e);if(t)return t;t=[];let n=0;for(let r of e.cmds){if(r.t===0&&r.step){n++;continue}if((r.t>=2||r.t===0&&r.geom&&r.geom.t>=2)&&t[t.length-1]!==n)t.push(n)}return it.set(e,t),t}var at=(e)=>e>16777215?"0x"+e.toString(16).toUpperCase():e<0?Be.get(e)??String(e):String(e),sn=(e)=>e.t===0?"0 "+e.text:e.t===1?`1 ${at(e.color)} ${e.m.join(" ")} ${e.file}`:e.src?e.src:`${e.t} ${at(e.color)} ${e.p.join(" ")}`,$e=(e,t)=>`${ne(e)}#${t}`;function on(e,t){let n=[],r=0,s=(o)=>!!o&&o.t===0&&o.texmap?.op==="NEXT";for(let o of e.cmds){if(o.t===0){if(o.step){r++;continue}if(o.bfc!==void 0||o.meta==="!COLOUR"){n.push(o);continue}if(r!==t)continue;if(o.texmap)n.push(o);else if(o.geom){if(o.geom.t>=2)n.push(o);else if(s(n[n.length-1]))n.pop()}continue}if(r!==t)continue;if(o.t===1){if(s(n[n.length-1]))n.pop();continue}n.push(o)}return{name:$e(e.name,t),cmds:n}}function dt(e,t){return[`0 ldr: own geometry of ${e.name}, step ${t}`,...on(e,t).cmds.map(sn)].join(`\n`)+`\n`}function je(e){let t=2166136261;for(let n=0;n<e.length;n++)t^=e.charCodeAt(n),t=Math.imul(t,16777619);return(t>>>0).toString(16).padStart(8,"0")}function bt(e){let[t,n,r,s,o,i,c,u,f,a,l,m]=e,g=u*m-f*l,d=-(c*m-f*a),b=c*l-u*a,C=s*g+o*d+i*b;if(!Number.isFinite(C)||Math.abs(C)<0.000000000001)return null;let A=1/C,p=[g*A,-(o*m-i*l)*A,(o*f-i*u)*A,d*A,(s*m-i*a)*A,-(s*f-i*c)*A,b*A,-(s*l-o*a)*A,(s*u-o*c)*A];return[-(p[0]*t+p[1]*n+p[2]*r),-(p[3]*t+p[4]*n+p[5]*r),-(p[6]*t+p[7]*n+p[8]*r),...p]}var an=(e)=>String(+e.toFixed(6)||0),lt=(e)=>\'"\'+e.replace(/\\\\/g,"\\\\\\\\").replace(/"/g,"\\\\\\"")+\'"\';function yt(e,t){let n=[...t.p1,...t.p2,...t.p3,...t.method!=="PLANAR"?[t.a??360]:[],...t.method==="SPHERICAL"?[t.b??180]:[]].map(an).join(" "),r=`0 ldr: ${e} with a model-level !TEXMAP\n0 BFC CERTIFY CCW\n0 !TEXMAP START ${t.method} ${n} ${lt(t.texture)}${t.glossmap?" GLOSSMAP "+lt(t.glossmap):""}\n1 16 0 0 0 1 0 0 0 1 0 0 0 1 ${ne(e)}\n0 !TEXMAP END\n`;return{name:`${ne(e)}#tex-${je(r)}`,source:r}}var ln=(e,t)=>{let n=[,,,,,,,,,];for(let r=0;r<3;r++)for(let s=0;s<3;s++)n[r*3+s]=e[r*3]*t[s]+e[r*3+1]*t[3+s]+e[r*3+2]*t[6+s];return n};function cn(e,t,n){let r=Math.PI/180,s=Math.sin(e*r),o=Math.cos(e*r),i=Math.sin(t*r),c=Math.cos(t*r),u=Math.sin(n*r),f=Math.cos(n*r);return[c*f,-c*u,i,o*u+s*i*f,o*f-s*i*u,-s*c,s*u-o*i*f,s*f+o*i*u,o*c]}var ct=new WeakMap;function xt(e){let t=ct.get(e);if(t)return t;let n=[],r=null;for(let s of e.cmds){if(s.t!==0||!s.step)continue;let o=s.rotstep;if(o)if(o.mode==="END")r=null;else{let i=cn(o.x,o.y,o.z);r=o.mode==="ABS"?{abs:!0,m:i,rotstep:o}:o.mode==="ADD"&&r?{abs:r.abs,m:ln(r.m,i),rotstep:o}:{abs:!1,m:i,rotstep:o}}n.push(r)}return n.push(r),ct.set(e,n),n}class Ve extends Error{limit;code="ldr-model-limit";constructor(e,t){super(`ldr: ${e} expands past ${t.toLocaleString("en-US")} (see maxInstances)`);this.limit=t;this.name="ModelLimitError"}}var un=(e)=>{for(let t=0;t<12;t++)if(!(Math.abs(e[t])<=ut))return!1;return!0},wt=999999,vt=(e)=>e.map((t)=>String(t).padStart(6,"0")).join(".")+"~",Ct=new WeakMap,Mt=new WeakMap;function fn(e,t){let n=Mt.get(t);if(!n)n={head:[...t.values()].map((o)=>{let i=Ct.get(o)??"",c=i.indexOf("!COLOUR");return c<0?"":"0 "+i.slice(c).trim().replace(/\\s+/g," ")}).filter(Boolean).join(`\n`),parts:new Map},Mt.set(t,n);let r=n.parts.get(e);if(!r){let s=ne(e),o=`0 ldr: ${s} placed in a model\'s !COLOUR scope\n0 BFC CERTIFY CCW\n${n.head}\n1 16 0 0 0 1 0 0 0 1 0 0 0 1 ${s}\n`;r={name:`${s}#col-${je(o)}`,source:o},n.parts.set(e,r)}return r}function pn(e,t={}){let n=[],r=t.maxDepth??64,s=t.looseGeometry!==!1,o=!!t.textures,i=!!t.callouts,c=new Map,u=0,f=new Set,a=t.maxInstances??2000000,l=0,m=(d,b)=>{let C=d.name+"#"+b,A=c.get(C);if(!A){let p;A=Object.assign(()=>p??=dt(d,b),{file:d,step:b}),c.set(C,A)}return A},g=(d,b,C,A,p,h,M,D,v=null,L=[],R=[],T=void 0,x=null)=>{let w=d.files.get(b);if(!w||M>r||f.has(w))return;if(++l>a)throw new Ve("model",a);f.add(w);let E=x,z=0,k=M>0?++u:0,P=i&&k?[...L,k]:L,Y=i&&k?[...R,C]:R,I=i&&!v?new Map:null,j=-1,H=0,Z=(S,y,B,_,W,X,N)=>{if(j!==z)j=z,H=0;let q=I?.get(z+"|"+y);if(q)return q.n++,g(S,S===d?y:S.main,B,_,p+"/"+y,[...W,wt],M+1,X,[...W,wt],P,Y,N,E);let U=[...W,H++],F=n.length;g(S,S===d?y:S.main,B,_,p+"/"+y,U,M+1,X,v,P,Y,N,E),I?.set(z+"|"+y,{n:1,from:F,to:n.length})},O=xt(w),G=s?gt(w):[],K=0,J=(S,y,B,_,W,X,N,q,U)=>{if(v)_=v;if(++l>a)throw new Ve("model",a);let F={part:S,color:y,m:B,step:_[0],steps:_,localStep:W,path:p};if(q)F.colour=q;if(k){if(F.sub=k,i)F.subPath=P,F.subMats=Y}if(X)F.embedded=!0;if(N){let re=yt(S,N);F.texPart=re.name,F.texSource=re.source}else if(U){let re=fn(S,U);F.colPart=re.name,F.colSource=re.source}let V=O[W];if(V)F.view=V;return n.push(F),F},Q=(S)=>{while(K<G.length&&G[K]<=S){let y=G[K++];J($e(w.name,y),A,C,[...h,y],y,!1,null,T,x).source=m(w,y)}};for(let S of w.cmds){if(S.t===0&&S.step){z++;continue}let y=S;if(y.t>=2||y.t===0&&y.geom&&y.geom.t>=2){Q(z);continue}if(y.t===0){if(y.meta==="!COLOUR"){let V=hn(y.text);if(V&&V.code!==16&&V.code!==24)Ct.set(V,y.text),(E=new Map(E??[])).set(V.code,V);continue}if(o&&y.geom?.t===1)y=y.geom;else continue}if(y.t!==1)continue;if(o&&y.fallback)continue;let B=ht(C,y.m);if(!un(B))continue;let _=y.color===16?A:y.color,W=y.color===16?T:E?.get(y.color),X=[...h,z],N=o?y.tex??D:null,q=N?bt(y.m):null,U=N&&q?mt(N,q):null;if(d.files.has(y.file)){if(ze(d,y.file)==="model"){Z(d,y.file,B,_,X,U,W);continue}J(y.file,_,B,X,z,!0,U,W,E);continue}let F=t.resolveModel?.(y.file);if(F){Z(F,y.file,B,_,X,U,W);continue}J(y.file,_,B,X,z,!1,U,W,E)}if(Q(1/0),f.delete(w),I){for(let S of I.values())if(S.n>1)for(let y=S.from;y<S.to;y++)n[y].mult??=S.n}};if(ze(e,e.main)==="part"){if(e.files.get(e.main))n.push({part:e.main,color:16,m:[...Ne],step:0,steps:[0],localStep:0,path:e.main,embedded:!0});return n}return g(e,e.main,Ne,16,e.main,[],0,null),n}function Tt(e,t="main.ldr",n){return pn(pt(e,t,{geometryText:!0}),n)}var mn=new Set(["CHROME","PEARLESCENT","RUBBER","MATTE_METALLIC","METAL","MATERIAL"]);function _e(e){if(!e)return null;if(e.startsWith("#")&&/^#[0-9A-Fa-f]{6}$/.test(e))return e.toUpperCase();if(/^0x[0-9A-Fa-f]{6}$/i.test(e))return("#"+e.slice(2)).toUpperCase();return null}function At(e,t){let n={value:"#FFFFFF",fraction:0.5};while(t<e.length){let r=e[t].toUpperCase(),s=e[t+1];if(r==="VALUE"){let o=_e(s);if(o)n.value=o;t+=2}else if(r==="ALPHA")n.alpha=+s,t+=2;else if(r==="LUMINANCE")n.luminance=+s,t+=2;else if(r==="FRACTION")n.fraction=+s,t+=2;else if(r==="VFRACTION")n.vfraction=+s,t+=2;else if(r==="SIZE")n.size=+s,t+=2;else if(r==="MINSIZE")n.minsize=+s,t+=2;else if(r==="MAXSIZE")n.maxsize=+s,t+=2;else break}return{grain:n,next:t}}function hn(e){let t=e.indexOf("!COLOUR");if(t<0)return null;let n=e.slice(t+7).trim().split(/\\s+/).filter(Boolean);if(n.length<2)return null;let r=n[0],s=NaN,o="#FF00FF",i="#333333",c=255,u=0,f={type:"default"},a=1;while(a<n.length){let l=n[a].toUpperCase(),m=n[a+1];if(l==="CODE")s=m!==void 0&&De.test(m)?Ue(m):m!==void 0&&/^\\d+$/.test(m)?+m:NaN,a+=2;else if(l==="VALUE"){let g=_e(m);if(g)o=g;a+=2}else if(l==="EDGE")i=_e(m)??m,a+=2;else if(l==="ALPHA")c=+m,a+=2;else if(l==="LUMINANCE")u=+m,a+=2;else if(l==="CHROME")f={type:"chrome"},a+=1;else if(l==="PEARLESCENT")f={type:"pearlescent"},a+=1;else if(l==="RUBBER")f={type:"rubber"},a+=1;else if(l==="MATTE_METALLIC")f={type:"matte_metallic"},a+=1;else if(l==="METAL")f={type:"metal"},a+=1;else if(l==="MATERIAL"){let g=(n[a+1]||"").toUpperCase();if(g==="GLITTER"){let{grain:d,next:b}=At(n,a+2);f={type:"glitter",material:d},a=b}else if(g==="SPECKLE"){let{grain:d,next:b}=At(n,a+2);f={type:"speckle",material:d},a=b}else if(g==="FABRIC"){let d=(n[a+2]||"").toUpperCase(),b=["VELVET","CANVAS","STRING","FUR"].includes(d)?d.toLowerCase():void 0;f={type:"fabric",kind:b},a+=b?3:2}else a=n.length}else if(mn.has(l))a+=1;else a+=1}if(Number.isNaN(s)||!o)return null;return{code:s,name:r,hex:o,edge:i,alpha:Number.isFinite(c)?c:255,luminance:Number.isFinite(u)?u:0,finish:f}}function gn(e){let t=Math.max(0,Math.min(1,(e.alpha??255)/255)),n=t<1,r=Math.max(0,Math.min(1,(e.luminance??0)/255)),s={opacity:t,transparent:n,depthWrite:!n,emissive:r,clearcoat:0,clearcoatRoughness:0,sheen:0,sheenRoughness:0};switch(e.finish?.type??"default"){case"chrome":return{...s,metalness:1,roughness:0,finish:"chrome"};case"pearlescent":return{...s,metalness:0.25,roughness:0.3,clearcoat:0.5,clearcoatRoughness:0.25,sheen:0.4,sheenRoughness:0.35,finish:"pearlescent"};case"rubber":return{...s,metalness:0,roughness:0.9,finish:"rubber"};case"matte_metallic":return{...s,metalness:0.4,roughness:0.8,finish:"matte_metallic"};case"metal":return{...s,metalness:0.85,roughness:0.2,finish:"metal"};case"glitter":{let i=e.finish.material,c=i.size??(i.minsize!=null&&i.maxsize!=null?(i.minsize+i.maxsize)/2:1);return{...s,metalness:0.35,roughness:0.25,clearcoat:1,clearcoatRoughness:0.08,particleHex:i.value,particleFraction:i.fraction,particleSize:c,finish:"glitter"}}case"speckle":{let i=e.finish.material,c=i.size??(i.minsize!=null&&i.maxsize!=null?(i.minsize+i.maxsize)/2:1);return{...s,metalness:0.2,roughness:0.55,particleHex:i.value,particleFraction:i.fraction,particleSize:c,finish:"speckle"}}case"fabric":return{...s,metalness:0,roughness:0.85,sheen:0.65,sheenRoughness:0.75,finish:"fabric"};default:return{...s,metalness:0,roughness:0.45,finish:"default"}}}function He(e){let t=gn(e),n=!t.transparent?"op":t.opacity>=0.75?"a200":t.opacity>=0.4?"a128":`a${Math.round(t.opacity*255)}`,r=t.emissive>0?`L${Math.round(t.emissive*16)}`:"",s=`${t.finish}:${n}${r}`;if(t.particleHex)s+=`:${t.particleHex}:${(t.particleFraction??0).toFixed(2)}`;return s}function dn(e,t){let n=new Map,r=null,s=!1,o=!1;for(let i of e.split(/\\r?\\n/)){let c=/^\\s*0\\s+FILE\\s+(\\S[^\\r]*)/i.exec(i);if(c){if(!s)n.clear();s=!0,o=!1,r=[],n.set(ne(c[1]),r);continue}if(/^\\s*0\\s+(NOFILE|!DATA)(\\s|$)/i.test(i)){if(!s&&/!DATA/i.test(i))n.clear(),s=!0;r=null,o=!0;continue}if(!r){if(s||o)continue;r=[],n.set(ne(t),r)}let u=i.trim().replace(/\\s+/g," ");if(u)r.push(u)}return n}var bn=(e)=>{if(!e.startsWith("1 "))return null;let t=e.split(" ");return t.length>=15?ne(t.slice(14).join(" ")):null};function yn(e){let t=2166136261,n=1523705862;for(let r=0;r<e.length;r++){let s=e.charCodeAt(r);t=Math.imul(t^s,16777619),n=Math.imul(n^s,16777629)^n>>>15}return(t>>>0).toString(16).padStart(8,"0")+(n>>>0).toString(16).padStart(8,"0")}function Lt(e,t,n="main.ldr"){let r=dn(e,n),s=new Map;for(let o of t){let i=ne(o);if(!r.has(i)||s.has(i))continue;let c=new Set([i]),u=[i];while(u.length)for(let a of r.get(u.pop())){let l=bn(a);if(l&&r.has(l)&&!c.has(l))c.add(l),u.push(l)}let f=[i,...[...c].filter((a)=>a!==i).sort()].map((a)=>"0 FILE "+(a===i?"":a)+`\n`+r.get(a).join(`\n`)).join(`\n`);s.set(i,`emb/${yn(f)}.dat`)}return s}var St=(e,t=0)=>Math.abs(e[t+7]-1)<0.001&&Math.abs(e[t+4])<0.001&&Math.abs(e[t+10])<0.001,Et=new WeakMap;function Ge(e,t){let n=Et.get(e);if(!n)Et.set(e,n=new Map);let r=n.get(t);if(r!==void 0)return r;let s=e.parts[t];if(!s)return n.set(t,null),null;let o=s.studs.length,i=new Float64Array(o*12),c=[],u=[];s.studs.forEach((m,g)=>{c.push(m[0]),u.push(m[1]);for(let d=0;d<12;d++)i[g*12+d]=m[2+d]});let f=null,a=0,l=0;if(s.mask){a=s.mask[0],l=s.mask[1];let m=s.mask[2];f=new Uint8Array(m.length);for(let g=0;g<m.length;g++)f[g]=m.charCodeAt(g)===49?1:0}return n.set(t,r={nStuds:o,studM:i,kind:c,color:u,mask:f,nx:a,nz:l}),r}var fe=1073741824;class We{a;b;c;vals;used;mask;size=0;constructor(e=1024){let t=1024;while(t<e*2)t*=2;this.a=new Int32Array(t),this.b=new Int32Array(t),this.c=new Int32Array(t),this.vals=new Int32Array(t),this.used=new Uint8Array(t),this.mask=t-1}slot(e,t,n){let r=Math.imul(e,2654435761)^Math.imul(t,2246822507)^Math.imul(n,3266489909);return r^=r>>>15,r=Math.imul(r,739982445),r^=r>>>12,r&this.mask}get(e,t,n){let r=this.slot(e,t,n),s=this.used,o=this.a,i=this.b,c=this.c;for(;;){if(!s[r])return-1;if(o[r]===e&&i[r]===t&&c[r]===n)return this.vals[r];r=r+1&this.mask}}put(e,t,n,r){if((this.size+1)*2>this.used.length)this.grow();let s=this.slot(e,t,n),o=this.used,i=this.a,c=this.b,u=this.c;for(;;){if(!o[s])return o[s]=1,i[s]=e,c[s]=t,u[s]=n,this.vals[s]=r,this.size++,-1;if(i[s]===e&&c[s]===t&&u[s]===n){let f=this.vals[s];return this.vals[s]=r,f}s=s+1&this.mask}}grow(){let{a:e,b:t,c:n,vals:r,used:s}=this,o=s.length*2;this.a=new Int32Array(o),this.b=new Int32Array(o),this.c=new Int32Array(o),this.vals=new Int32Array(o),this.used=new Uint8Array(o),this.mask=o-1,this.size=0;for(let i=0;i<s.length;i++)if(s[i])this.put(e[i],t[i],n[i],r[i])}}var pe=(e,t,n)=>e>-fe&&e<fe&&t>-fe&&t<fe&&n>-fe&&n<fe,de=2147483647;function xn(e,t){let n=e.colorTable?.[t];if(n)return(n.alpha??255)<255;return t.charCodeAt(0)===35&&/\\/[^:/]*:a\\d/.test(t)}function wn(e,t,n){let s=new Map,o=(I)=>{let j=s.get(I);if(j===void 0)s.set(I,j=xn(t,I));return j},i=[],c=[],u=[],f=[],a=[],l=[],m=[],g=[],d=[],b=new We(e.length*2),C=[],A=[];for(let I=0;I<e.length;I++){let j=e[I],H=j.m,Z=t.parts[j.part];if(!Z||!Z.mask||!St(H)||o(j.color))continue;let O=Z.bbox,G=1/0,K=-1/0,J=1/0,Q=-1/0;for(let U=0;U<2;U++)for(let F=0;F<2;F++){let V=U?O[3]:O[0],re=F?O[5]:O[2],oe=H[0]+H[3]*V+H[5]*re,se=H[2]+H[9]*V+H[11]*re;if(oe<G)G=oe;if(oe>K)K=oe;if(se<J)J=se;if(se>Q)Q=se}let S=Math.round((H[1]+O[4])*2),y=Ge(t,j.part),B=Math.floor(G/40),_=Math.floor(K/40),W=Math.floor(J/40),X=Math.floor(Q/40);if(!((_-B+1)*(X-W+1)<=65536)||!pe(S,B,W)||!pe(S,_,X))continue;let N=-1;for(let U=b.get(S,B,W),F=0;U>=0&&F<8;U=C[U],F++){let V=A[U];if(i[V]!==G||c[V]!==K||u[V]!==J||f[V]!==Q||m[V]!==y)continue;let re=e[a[V]].m,oe=!0;for(let se=0;se<12;se++)if(re[se]!==H[se]){oe=!1;break}if(oe){N=V;break}}if(N>=0){let U=n?n[I]:0;if(n&&U<n[a[N]])l[N]=a[N],a[N]=I;else if(l[N]<0||n&&U<n[l[N]])l[N]=I;continue}let q=a.length;i.push(G),c.push(K),u.push(J),f.push(Q),a.push(I),l.push(-1),m.push(y),g.push(O[0]),d.push(O[2]);for(let U=B;U<=_;U++)for(let F=W;F<=X;F++){if(!pe(S,U,F))continue;let V=A.length;A.push(q),C.push(b.put(S,U,F,V))}}let p=[0,5,-5,5,-5],h=[0,5,5,-5,-5],M=NaN,D=NaN,v=NaN,L=-1,R=(I,j,H,Z)=>{let O=Math.round(j*2),G=Math.floor(I/40),K=Math.floor(H/40);if(!pe(O,G,K))return de;let J=de;if(O!==M||G!==D||K!==v)M=O,D=G,v=K,L=b.get(O,G,K);for(let Q=L;Q>=0;Q=C[Q]){let S=A[Q],y=a[S];if(y===Z&&(y=l[S])<0)continue;if(!(I-6>=i[S]-0.5&&I+6<=c[S]+0.5&&H-6>=u[S]-0.5&&H+6<=f[S]+0.5))continue;let B=e[a[S]].m,_=m[S],W=g[S],X=d[S],N=I-B[0],q=j-B[1],U=H-B[2],F=B[3]*N+B[6]*q+B[9]*U,V=B[5]*N+B[8]*q+B[11]*U,{nx:re,nz:oe,mask:se}=_,ce=!0;for(let ie=0;ie<5;ie++){let ae=Math.floor((F+p[ie]-W)/20),ue=Math.floor((V+h[ie]-X)/20);if(ae<0||ue<0||ae>=re||ue>=oe||se[ae*oe+ue]!==1){ce=!1;break}}if(ce){if(!n)return 0;let ie=n[y];if(ie<J)J=ie}}return J},T=0;for(let I of e){let j=Ge(t,I.part);if(j)T+=j.nStuds}let x=new Uint8Array(T),w=new Uint8Array(T),E=new We(T),z=0,k=n?new Int32Array(T).fill(de):void 0;for(let I=0,j=0;I<e.length;I++){let H=e[I],Z=Ge(t,H.part);if(!Z)continue;let O=H.m,G=Z.studM,K=O[0],J=O[1],Q=O[2],S=O[3],y=O[4],B=O[5],_=O[6],W=O[7],X=O[8],N=O[9],q=O[10],U=O[11];for(let F=0;F<Z.nStuds;F++,j++){let V=F*12,re=G[V+4],oe=G[V+7],se=G[V+10];if(!(Math.abs(_*re+W*oe+X*se-1)<0.001&&Math.abs(S*re+y*oe+B*se)<0.001&&Math.abs(N*re+q*oe+U*se)<0.001))continue;w[j]=1;let ce=G[V],ie=G[V+1],ae=G[V+2],ue=K+S*ce+y*ie+B*ae,Ke=J+_*ce+W*ie+X*ae,Xe=Q+N*ce+q*ie+U*ae,Ze=R(ue,Ke,Xe,I);if(Ze!==de){if(x[j]=1,z++,k)k[j]=Ze}let be=Math.round(ue),ye=Math.round(Ke),xe=Math.round(Xe);if(!pe(be,ye,xe))continue;if(!n){E.put(be,ye,xe,1);continue}let Ye=n[I],Je=E.get(be,ye,xe);if(Je<0||Ye<Je)E.put(be,ye,xe,Ye)}}let P=new Uint8Array(e.length),Y=n?new Int32Array(e.length).fill(de):void 0;for(let I=0;I<e.length;I++){let j=e[I],H=t.parts[j.part];if(!H||!H.under||!St(j.m)||o(j.color))continue;let Z=H.bbox,O=Math.round((Z[3]-Z[0])/20),G=Math.round((Z[5]-Z[2])/20);if(!O||!G||O*G>4096)continue;let K=j.m,J=!0,Q=0;for(let S=0;S<O&&J;S++)for(let y=0;y<G;y++){let B=Z[0]+10+20*S,_=Z[2]+10+20*y,W=K[0]+K[3]*B+K[5]*_,X=K[2]+K[9]*B+K[11]*_,N=Math.round(W),q=Math.round(K[1]+Z[4]),U=Math.round(X),F=pe(N,q,U)?E.get(N,q,U):-1;if(F<0){J=!1;break}if(F>Q)Q=F}if(J){if(P[I]=1,Y)Y[I]=Q}}return{nStuds:T,studHidden:x,studUp:w,underHidden:P,studsHidden:z,studHideStep:k,underHideStep:Y}}function Mn(e,t,n){let r=(l)=>l.colPart&&t.parts[l.colPart]?l.colPart:n&&l.texPart&&t.parts[l.texPart]?l.texPart:l.part,s=new Map,o=new Map,i=(l)=>{let m=l.colour;if(!m)return String(l.color);let g=o.get(m);if(g!==void 0)return g;let d=t.colorTable?.[l.color],b=d?.hex??t.colors?.[l.color],C=d?He({alpha:d.alpha??255,luminance:d.luminance??0,finish:d.finish??{type:"default"}}):"default:op",A=He(m);if(g=b&&b.toUpperCase()===m.hex.toUpperCase()&&C===A?String(l.color):m.hex.toUpperCase()+"/"+A,g!==String(l.color))s.set(g,m);return o.set(m,g),g},c=e.map((l)=>({part:r(l),color:i(l),m:l.m,steps:l.steps})),u=c.map((l)=>vt(l.steps)),f=[...new Set(u)].sort(),a=new Map(f.map((l,m)=>[l,m]));return{all:c,stepOf:u.map((l)=>a.get(l)),nSteps:f.length,localColours:s}}function Ce(e,t,n=!0){let r=Mn(e,t,n);return wn(r.all,t,r.nSteps>1?r.stepOf:void 0)}var ke="https://ldr-demo.vercel.app/cdn/v1/",Le=new Map,Te=new Map;function Se(e=ke,t=fetch){let n=Le.get(e);if(!n)n=t(e+"parts.json").then((r)=>{if(!r.ok)throw Error(`ldr: parts CDN index ${r.status} (${e}parts.json)`);return r.json()}),n.catch(()=>Le.delete(e)),Le.set(e,n);return n}var An=(e)=>Array.isArray(e)&&e.length===3&&typeof e[0]==="number"&&typeof e[1]==="number"&&(e[2]==="f32"||e[2]==="u16"||e[2]==="u8"||e[2]==="u32"),Ee=(e,t)=>An(e)?[e[0]+t,e[1],e[2]]:Array.isArray(e)?e.map((n)=>Ee(n,t)):e&&typeof e==="object"?Object.fromEntries(Object.entries(e).map(([n,r])=>[n,Ee(r,t)])):e;function vn(e,t={}){let n=[],r=0,s={},o={};for(let m of e){let g=m.buffer;if(!g)throw Error("ldr: mergePacks needs packs from decodePack/loadPack");let d=new DataView(g).getUint32(0,!0),b=new Uint8Array(g,4+d),C=r;n.push(b),r+=b.byteLength;let A=(4-r%4)%4;if(A)n.push(new Uint8Array(A)),r+=A;for(let[p,h]of Object.entries(m.header.parts??{}))if(!(p in s))s[p]=Ee(h,C);for(let[p,h]of Object.entries(m.header.studKinds??{}))if(!(p in o))o[p]=Ee(h,C)}let i=e[0]?.header??{version:1,weld:!0},c=new TextEncoder().encode(JSON.stringify({...i,parts:s,studKinds:o,...t})),u=(4-(4+c.length)%4)%4,f=4+c.length+u,a=new Uint8Array(f+r);new DataView(a.buffer).setUint32(0,c.length+u,!0),a.set(c,4),a.fill(32,4+c.length,f);let l=f;for(let m of n)a.set(m,l),l+=m.byteLength;return ve(a.buffer)}async function Cn(e,t={}){e=[...e];try{return await kt(e,t)}catch(n){let r=t.cdn??ke,s=t.fetch??fetch;Le.delete(r);let o=(i,c)=>s(i,{...c,cache:"reload"});try{return await kt(e,{...t,fetch:o})}catch{throw n}}}async function kt(e,t){let n=t.cdn??ke,r=t.fetch??fetch,s=t.gap??16384,o=await Se(n,r),i=[...new Set([...e].map(ne))],c=[],u=[];for(let p of i){if(Te.has(n+p))continue;let h=o.parts[p];if(h)u.push({name:p,off:h[0],len:h[1],file:h[2]??0});else c.push(p)}u.sort((p,h)=>p.file-h.file||p.off-h.off);let f=[];for(let p of u){let h=f[f.length-1];if(h&&h.file===p.file&&p.off-h.end<=s)h.end=Math.max(h.end,p.off+p.len),h.items.push(p);else f.push({file:p.file,start:p.off,end:p.off+p.len,items:[p]})}let a=0,l=0,m=0,g=new Map,d=async()=>{while(m<f.length){let p=f[m++],h=g.get(p.file);if(h)h=h.subarray(p.start,p.end);else{let M=await r(new URL(o.archives[p.file],n).href,{headers:{Range:`bytes=${p.start}-${p.end-1}`,"Accept-Encoding":"identity"}});if(!M.ok)throw Error(`ldr: parts CDN ${M.status}`);if(l++,h=new Uint8Array(await M.arrayBuffer()),a+=h.byteLength,M.status===200)g.set(p.file,h),h=h.subarray(p.start,p.end)}for(let M of p.items){let D=Ae(h.subarray(M.off-p.start,M.off-p.start+M.len)),v=D.buffer.slice(D.byteOffset,D.byteOffset+D.byteLength);Te.set(n+M.name,ve(v))}}};await Promise.all(Array.from({length:Math.min(t.concurrency??24,f.length)},d));let b=i.filter((p)=>Te.has(n+p)).map((p)=>Te.get(n+p)),C={colors:o.colors,...o.colorTable?{colorTable:o.colorTable}:{}};return{pack:b.length?vn(b,C):ve(Tn(C)),missing:c,requests:l,bytes:a}}function Tn(e){let t=new TextEncoder().encode(JSON.stringify({version:1,weld:!0,parts:{},studKinds:{},...e})),n=(4-(4+t.length)%4)%4,r=new Uint8Array(4+t.length+n).fill(32);return new DataView(r.buffer).setUint32(0,t.length+n,!0),r.set(t,4),r.buffer}function Ln(e,t){let n=t.header.parts;if(!n)return 0;let r=0;for(let s of e){let o=n[s.part]?.body?.tris;if(o)r+=o}return r}function Pt(e,t,n){let r=0,s=0,o=!1,i=new Set;for(let c of e){let u=c.embedded?t.get(c.part):ne(c.part),f=u?n.parts[u]:void 0;if(!f)continue;if(f[3]!=null)o=!0,r+=f[3];if(!i.has(u))i.add(u),s+=f[1]}return{bodyTris:r,packBytes:s,known:o}}class Pe extends Error{code="ldr-budget";bodyTris;packBytes;maxBodyTris;maxPackBytes;constructor(e){let t=[e.maxBodyTris!=null&&e.bodyTris>e.maxBodyTris?`${e.bodyTris} triangles (limit ${e.maxBodyTris})`:"",e.maxPackBytes!=null&&e.packBytes>e.maxPackBytes?`${(e.packBytes/1e6).toFixed(1)} MB parts pack (limit ${(e.maxPackBytes/1e6).toFixed(0)} MB)`:""].filter(Boolean).join(", ");super(`ldr: model exceeds device budget: ${t}`);this.name="BudgetError",this.bodyTris=e.bodyTris,this.packBytes=e.packBytes,this.maxBodyTris=e.maxBodyTris,this.maxPackBytes=e.maxPackBytes}}async function It(e,t={}){let n=performance.now(),r=t.fetch??fetch,s=Se(t.cdn??ke,r);s.catch(()=>{});let o=t.text?e:await r(e).then(async(x)=>{if(!x.ok)throw Error(`ldr: ${x.status} fetching ${e}`);return et(await x.arrayBuffer())}),i=performance.now(),c=t.name??(t.text?"main.ldr":tt(e)),u=Tt(o,c,{looseGeometry:!1,callouts:t.callouts}),f=performance.now();t.onParsed?.(u),await s;let a=Lt(o,new Set(u.filter((x)=>x.embedded).map((x)=>x.part)),c),l=(x,w)=>t.maxBodyTris!=null&&x>t.maxBodyTris||t.maxPackBytes!=null&&w>t.maxPackBytes,m=t.maxBodyTris!=null||t.maxPackBytes!=null,g=(x)=>new Pe({...x,maxBodyTris:t.maxBodyTris,maxPackBytes:t.maxPackBytes}),d="full";if(m){let x=Pt(u,a,await s);if(l(x.known?x.bodyTris:0,x.packBytes)){if(!t.lowCdn)throw g(x);let w=await Se(t.lowCdn,r).catch(()=>null);if(!w)throw g(x);let E=Pt(u,a,w);if(l(E.known?E.bodyTris:0,E.packBytes))throw g(E);d="low"}}let b=[...u.filter((x)=>!x.embedded).map((x)=>x.part),...a.values()],C=async()=>{let x=await Cn(b,d==="low"?{...t,cdn:t.lowCdn}:t);for(let[w,E]of a){let z=x.pack.header.parts[E];if(z)x.pack.header.parts[w]=z}return{...x,packBytes:x.pack.buffer?.byteLength??x.pack.bytes??0,bodyTris:Ln(u,x.pack)}},A=await C();if(m&&l(A.bodyTris,A.packBytes)&&d==="full"&&t.lowCdn&&await Se(t.lowCdn,r).then(()=>!0,()=>!1)){d="low";let x=A;A=await C(),A.requests+=x.requests,A.bytes+=x.bytes}if(m&&l(A.bodyTris,A.packBytes))throw g(A);let{pack:p,missing:h,requests:M,bytes:D}=A,v=new Map([...a].map(([x,w])=>[w,x])),L=h.map((x)=>v.get(x)??x),R=performance.now(),T=t.cull?Ce(u,p.header,t.textures!==!1):void 0;return{insts:u,pack:p,tier:d,missing:L,requests:M,bytes:D,cull:T,timings:{fetchModel:i-n,parse:f-i,parts:R-f,...T?{cull:performance.now()-R}:{}}}}self.onmessage=async(e)=>{let{id:t,source:n,opts:r}=e.data;try{let s=await It(n,{...r,cull:!1,onParsed:(a)=>self.postMessage({id:t,insts:a})}),o=s.pack.buffer;if(self.postMessage({id:t,buffer:o,tier:s.tier,missing:s.missing,requests:s.requests,bytes:s.bytes,timings:s.timings},[o]),!r.cull)return;let i=performance.now(),c=Ce(s.insts,s.pack.header,r.textures!==!1),u=performance.now()-i,f=[];for(let a of[c.studHidden,c.studUp,c.underHidden,c.studHideStep,c.underHideStep])if(a)f.push(a.buffer);self.postMessage({id:t,cull:c,ms:u},f)}catch(s){if(s instanceof Pe||s?.code==="ldr-budget")self.postMessage({id:t,phase:"error",error:String(s?.message??s),budget:{bodyTris:s.bodyTris,packBytes:s.packBytes,maxBodyTris:s.maxBodyTris,maxPackBytes:s.maxPackBytes}});else self.postMessage({id:t,phase:"error",error:String(s?.message??s)})}};\n';
4682
4890
 
4683
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/cdn.ts
4891
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/cdn.ts
4684
4892
  var worker;
4685
4893
  var seq = 0;
4686
4894
  var pending = new Map;
@@ -1,4 +1,4 @@
1
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/spec.ts
1
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/spec.ts
2
2
  var norm = (s) => s.trim().toLowerCase().replace(/\\/g, "/").replace(/\/+/g, "/");
3
3
  var COLOUR_ID_RE = /^[A-Za-z][A-Za-z0-9_]*$/;
4
4
  var namedCodes = new Map;
@@ -802,7 +802,7 @@ function fileStepViews(f) {
802
802
  viewMemo.set(f, out);
803
803
  return out;
804
804
  }
805
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/model.ts
805
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/model.ts
806
806
  class ModelLimitError extends Error {
807
807
  limit;
808
808
  code = "ldr-model-limit";
@@ -1243,7 +1243,7 @@ function blendedColourHex(code) {
1243
1243
  const a = LDRAW_EXE_16[code - 256 >> 4], b = LDRAW_EXE_16[code - 256 & 15];
1244
1244
  return "#" + [0, 1, 2].map((k) => (a[k] + b[k] >> 1).toString(16).padStart(2, "0")).join("").toUpperCase();
1245
1245
  }
1246
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/instructions.ts
1246
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/instructions.ts
1247
1247
  var MIN_VIS = 0.5;
1248
1248
  var REORIENT = 0.35;
1249
1249
  var deg = Math.PI / 180;
@@ -1611,10 +1611,10 @@ function planStepViews(insts, parts, stepOf, nSteps, o = {}) {
1611
1611
  }
1612
1612
  };
1613
1613
  }
1614
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/render.ts
1614
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/render.ts
1615
1615
  import * as THREE from "three";
1616
1616
 
1617
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/pack-io.ts
1617
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/pack-io.ts
1618
1618
  import { decompress } from "fzstd";
1619
1619
  async function decompressPack(data) {
1620
1620
  const u = data instanceof Uint8Array ? data : new Uint8Array(data);
@@ -1637,7 +1637,7 @@ function decodePack(buf) {
1637
1637
  return { header, arr, bytes: buf.byteLength, buffer: buf };
1638
1638
  }
1639
1639
 
1640
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/cull.ts
1640
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/cull.ts
1641
1641
  var upright = (m, o = 0) => Math.abs(m[o + 7] - 1) < 0.001 && Math.abs(m[o + 4]) < 0.001 && Math.abs(m[o + 10]) < 0.001;
1642
1642
  var prepCache = new WeakMap;
1643
1643
  function prepPart(H, part) {
@@ -2020,7 +2020,7 @@ function precomputeCull(instances, H, useTex = true) {
2020
2020
  return cullCore(s.all, H, s.nSteps > 1 ? s.stepOf : undefined);
2021
2021
  }
2022
2022
 
2023
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/render.ts
2023
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/render.ts
2024
2024
  async function loadPack(url) {
2025
2025
  const res = await fetch(url);
2026
2026
  if (!res.ok)
@@ -2732,7 +2732,181 @@ function studBoxGeom(w) {
2732
2732
  _studBox.set(w, g);
2733
2733
  return g;
2734
2734
  }
2735
+ var _studTube = new Map;
2736
+ function studTubeGeom(w, wi) {
2737
+ const key = w + "," + wi;
2738
+ let g = _studTube.get(key);
2739
+ if (g)
2740
+ return g;
2741
+ const y = -4, s = Math.SQRT1_2;
2742
+ const sq = (h) => [[-h, -h], [h, -h], [h, h], [-h, h]];
2743
+ const C = sq(w), Ci = sq(wi);
2744
+ const pos = [], nrm = [], idx = [];
2745
+ for (const [x, z] of C) {
2746
+ pos.push(x, y, z);
2747
+ nrm.push(0, -1, 0);
2748
+ }
2749
+ for (const [x, z] of Ci) {
2750
+ pos.push(x, y, z);
2751
+ nrm.push(0, -1, 0);
2752
+ }
2753
+ for (const [x, z] of C) {
2754
+ pos.push(x, y, z, x, 0, z);
2755
+ nrm.push(Math.sign(x) * s, 0, Math.sign(z) * s, Math.sign(x) * s, 0, Math.sign(z) * s);
2756
+ }
2757
+ for (const [x, z] of Ci) {
2758
+ pos.push(x, y, z, x, 0, z);
2759
+ nrm.push(-Math.sign(x) * s, 0, -Math.sign(z) * s, -Math.sign(x) * s, 0, -Math.sign(z) * s);
2760
+ }
2761
+ const tri = (a, b, c, out) => {
2762
+ const P = (i) => pos.slice(i * 3, i * 3 + 3);
2763
+ const [A, B, Cc] = [P(a), P(b), P(c)];
2764
+ const u = [B[0] - A[0], B[1] - A[1], B[2] - A[2]], v = [Cc[0] - A[0], Cc[1] - A[1], Cc[2] - A[2]];
2765
+ const n = [u[1] * v[2] - u[2] * v[1], u[2] * v[0] - u[0] * v[2], u[0] * v[1] - u[1] * v[0]];
2766
+ if (n[0] * out[0] + n[1] * out[1] + n[2] * out[2] < 0)
2767
+ idx.push(a, c, b);
2768
+ else
2769
+ idx.push(a, b, c);
2770
+ };
2771
+ for (let i = 0;i < 4; i++) {
2772
+ const j = (i + 1) % 4;
2773
+ tri(i, j, 4 + j, [0, -1, 0]);
2774
+ tri(i, 4 + j, 4 + i, [0, -1, 0]);
2775
+ const mid = [(C[i][0] + C[j][0]) / 2, 0, (C[i][1] + C[j][1]) / 2];
2776
+ {
2777
+ const ti = 8 + i * 2, bi = ti + 1, tj = 8 + j * 2, bj = tj + 1;
2778
+ tri(ti, tj, bj, mid);
2779
+ tri(ti, bj, bi, mid);
2780
+ }
2781
+ {
2782
+ const ti = 16 + i * 2, bi = ti + 1, tj = 16 + j * 2, bj = tj + 1;
2783
+ const inn = [-mid[0], 0, -mid[2]];
2784
+ tri(ti, tj, bj, inn);
2785
+ tri(ti, bj, bi, inn);
2786
+ }
2787
+ }
2788
+ const nv = pos.length / 3;
2789
+ const col = new Uint8Array(nv * 4);
2790
+ for (let i = 0;i < nv; i++) {
2791
+ col[i * 4] = 255;
2792
+ col[i * 4 + 1] = 255;
2793
+ col[i * 4 + 2] = 255;
2794
+ col[i * 4 + 3] = 0;
2795
+ }
2796
+ g = new THREE.BufferGeometry;
2797
+ g.setAttribute("position", new THREE.Float16BufferAttribute(toF16(new Float32Array(pos)), 3));
2798
+ g.setAttribute("normal", new THREE.BufferAttribute(toI8(new Float32Array(nrm)), 3, true));
2799
+ g.setAttribute("ldrColor", new THREE.BufferAttribute(col, 4, true));
2800
+ g.setIndex(new THREE.BufferAttribute(new Uint16Array(idx), 1));
2801
+ g.computeBoundingSphere();
2802
+ g.computeBoundingBox();
2803
+ _studTube.set(key, g);
2804
+ return g;
2805
+ }
2806
+ var _hole = new WeakMap;
2807
+ function studHole(b, arr = (r) => r) {
2808
+ if (!b)
2809
+ return null;
2810
+ let v = _hole.get(b);
2811
+ if (v !== undefined)
2812
+ return v;
2813
+ v = null;
2814
+ const p = arr(b.pos);
2815
+ let rin = Infinity, out = Infinity, ok = p.length >= 9;
2816
+ for (let i = 0;i < p.length && ok; i += 3) {
2817
+ const y = p[i + 1], r = Math.hypot(p[i], p[i + 2]);
2818
+ if (y < -4.01 || y > 0.01 || r > 6.02)
2819
+ ok = false;
2820
+ else if (r < 5.8)
2821
+ rin = Math.min(rin, r);
2822
+ else
2823
+ out = Math.min(out, r);
2824
+ }
2825
+ if (ok && rin >= 3.5 && rin <= 4.5) {
2826
+ let top = false, foot = false;
2827
+ for (let i = 0;i < p.length && ok; i += 3) {
2828
+ const r = Math.hypot(p[i], p[i + 2]);
2829
+ if (r >= 5.8)
2830
+ continue;
2831
+ if (r - rin > 0.1)
2832
+ ok = false;
2833
+ else if (Math.abs(p[i + 1] + 4) < 0.01)
2834
+ top = true;
2835
+ else if (Math.abs(p[i + 1]) < 0.01)
2836
+ foot = true;
2837
+ }
2838
+ if (ok && top && foot)
2839
+ v = { r: rin, out };
2840
+ }
2841
+ _hole.set(b, v);
2842
+ return v;
2843
+ }
2735
2844
  var _topClosed = new WeakMap;
2845
+ function studSquareLines(E, w, hole) {
2846
+ const n = Math.floor(E.length / 6);
2847
+ if (!n)
2848
+ return null;
2849
+ const loops = new Map;
2850
+ const cls = (q) => {
2851
+ const r = Math.hypot(E[q], E[q + 2]);
2852
+ return Math.abs(r - 6) <= 0.02 ? "o" : hole && Math.abs(r - hole.r) <= 0.02 ? "i" : null;
2853
+ };
2854
+ for (let s = 0;s < n; s++) {
2855
+ const o = s * 6;
2856
+ const y0 = E[o + 1], y1 = E[o + 4];
2857
+ if (Math.abs(y0 - y1) > 0.001)
2858
+ return null;
2859
+ const c0 = cls(o);
2860
+ if (!c0 || cls(o + 3) !== c0)
2861
+ return null;
2862
+ const k = String(Math.round(y0 * 100) / 100 + 0) + c0;
2863
+ const L = loops.get(k) || loops.set(k, { segs: 0, len: 0, deg: new Map }).get(k);
2864
+ L.segs++;
2865
+ L.len = Math.max(L.len, Math.hypot(E[o + 3] - E[o], E[o + 5] - E[o + 2]));
2866
+ for (const q of [o, o + 3]) {
2867
+ const vk = Math.round(E[q] * 100) + 0 + "," + (Math.round(E[q + 2] * 100) + 0);
2868
+ L.deg.set(vk, (L.deg.get(vk) ?? 0) + 1);
2869
+ }
2870
+ }
2871
+ for (const L of loops.values())
2872
+ if (L.segs < 8 || L.deg.size !== L.segs || [...L.deg.values()].some((d) => d !== 2))
2873
+ return null;
2874
+ const ord = [...loops.entries()].sort((a, b) => b[1].len - a[1].len);
2875
+ const C = [[-w, -w], [w, -w], [w, w], [-w, w]];
2876
+ const pos = new Float32Array(ord.length * 24), lens = new Float32Array(ord.length * 4);
2877
+ ord.forEach(([yk, L], i) => {
2878
+ const y = parseFloat(yk), h = yk.endsWith("i") ? hole.w / w : 1;
2879
+ for (let c = 0;c < 4; c++) {
2880
+ const a = C[c], b = C[(c + 1) % 4];
2881
+ pos.set([a[0] * h, y, a[1] * h, b[0] * h, y, b[1] * h], (i * 4 + c) * 6);
2882
+ lens[i * 4 + c] = L.len;
2883
+ }
2884
+ });
2885
+ return { pos, lens };
2886
+ }
2887
+ function boxLevelLines(pos) {
2888
+ if (pos.length < 24)
2889
+ return null;
2890
+ const lo = [Infinity, Infinity, Infinity], hi = [-Infinity, -Infinity, -Infinity];
2891
+ for (let i = 0;i < pos.length; i += 3)
2892
+ for (let k = 0;k < 3; k++) {
2893
+ lo[k] = Math.min(lo[k], pos[i + k]);
2894
+ hi[k] = Math.max(hi[k], pos[i + k]);
2895
+ }
2896
+ for (let i = 0;i < pos.length; i += 3)
2897
+ for (let k = 0;k < 3; k++)
2898
+ if (pos[i + k] !== lo[k] && pos[i + k] !== hi[k])
2899
+ return null;
2900
+ if (!(hi[0] > lo[0] && hi[1] > lo[1] && hi[2] > lo[2]))
2901
+ return null;
2902
+ const c = (i) => [i & 1 ? hi[0] : lo[0], i & 2 ? hi[1] : lo[1], i & 4 ? hi[2] : lo[2]];
2903
+ const out = [];
2904
+ for (let i = 0;i < 8; i++)
2905
+ for (const b of [1, 2, 4])
2906
+ if (!(i & b))
2907
+ out.push(...c(i), ...c(i | b));
2908
+ return new Float32Array(out);
2909
+ }
2736
2910
  function studTopClosed(b, arr) {
2737
2911
  if (!b)
2738
2912
  return false;
@@ -2841,6 +3015,7 @@ class LdrLodRoot extends THREE.LOD {
2841
3015
  hi = mid;
2842
3016
  }
2843
3017
  l.geometry.drawRange.count = lo * 2;
3018
+ l.visible = lo > 0 && l.userData.ldrVis !== false;
2844
3019
  }
2845
3020
  }
2846
3021
  }
@@ -3198,11 +3373,12 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
3198
3373
  return l;
3199
3374
  };
3200
3375
  const lineCache = new Map;
3201
- const addLines = (ref, im, cl) => {
3376
+ const boxLineCache = new Map;
3377
+ const addLines = (ref, im, cl, src) => {
3202
3378
  let w = lineCache.get(ref);
3203
3379
  if (!w) {
3204
- const r = weldLines(arr(ref), LOD);
3205
- lineCache.set(ref, w = { P: new THREE.BufferAttribute(r.P, 3), I: new THREE.BufferAttribute(r.I, 1), lens: r.lens });
3380
+ const r = weldLines(src ? src.pos : arr(ref), LOD && !src?.lens);
3381
+ lineCache.set(ref, w = { P: new THREE.BufferAttribute(r.P, 3), I: new THREE.BufferAttribute(r.I, 1), lens: src?.lens ?? r.lens });
3206
3382
  }
3207
3383
  const g = new THREE.InstancedBufferGeometry;
3208
3384
  g.setAttribute("position", w.P);
@@ -3356,8 +3532,21 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
3356
3532
  const cl = newCluster(bodyIm.boundingSphere, bodyIm);
3357
3533
  lv0.forEach((o) => o.onBeforeRender = trackVp);
3358
3534
  cl.lv.push({ objs: lv0, err: 0 }, ...textured ? [] : lodLevels(p.body, bodyIm, mat));
3359
- if (EDGES && p.edges)
3360
- addLines(p.edges, bodyIm, cl);
3535
+ if (EDGES && p.edges) {
3536
+ const full = addLines(p.edges, bodyIm, cl);
3537
+ const bl = !textured && LOD ? p.body?.lod : null;
3538
+ const last = bl?.[bl.length - 1];
3539
+ if (last && last.tris === 12 && cl.lv.length === bl.length + 1) {
3540
+ let bx = boxLineCache.get(last);
3541
+ if (bx === undefined)
3542
+ boxLineCache.set(last, bx = boxLevelLines(arr(last.pos)));
3543
+ if (bx) {
3544
+ const l = addLines(last, bodyIm, cl, { pos: bx });
3545
+ full.userData.ldrLineLvs = [0, bl.length - 1];
3546
+ l.userData.ldrLineLvs = [bl.length, bl.length];
3547
+ }
3548
+ }
3549
+ }
3361
3550
  addCond(p, bodyIm, cl);
3362
3551
  if (steps)
3363
3552
  stepBatches.push({ im: bodyIm, objs: [...cl.lv.flatMap((l) => l.objs), ...cl.lines, ...cl.cond], own: Int32Array.from(ids, (id) => steps[id]), hide: null, flag: "body", inst: Int32Array.from(ids), stud: null, col: Uint16Array.from(ids, (id) => instCol[id]) });
@@ -3708,6 +3897,7 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
3708
3897
  const STUD_BOX_W_LOW = 5.317;
3709
3898
  const STUD_DISC_ERR = 8;
3710
3899
  let _coopS = 0;
3900
+ const sqLineKey = new Map;
3711
3901
  for (let ci = 0;ci < sMesh.length; ci++) {
3712
3902
  const sm = sMesh[ci];
3713
3903
  if (!sm)
@@ -3727,8 +3917,11 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
3727
3917
  cl.studLineLv = 0;
3728
3918
  cl.lv.push({ objs: [im], err: 0 });
3729
3919
  const discObjs = [];
3730
- if (LOD && studTopClosed(k.body, arr) && (im.geometry.getIndex()?.count ?? im.geometry.getAttribute("position").count) > 30) {
3731
- const box = new THREE.InstancedMesh(studBoxGeom(/(^|[\\/])8[\\/]/.test(kind) ? STUD_BOX_W_LOW : 6), im.material, 0);
3920
+ const sqW = /(^|[\\/])8[\\/]/.test(kind) ? STUD_BOX_W_LOW : 6;
3921
+ const h = studTopClosed(k.body, arr) ? null : studHole(k.body, arr);
3922
+ const hole = h ? { r: h.r, w: h.r * Math.sqrt(Math.PI) / 2 } : undefined;
3923
+ if (LOD && (hole || studTopClosed(k.body, arr)) && (im.geometry.getIndex()?.count ?? im.geometry.getAttribute("position").count) > 30) {
3924
+ const box = new THREE.InstancedMesh(hole ? studTubeGeom(sqW, hole.w) : studBoxGeom(sqW), im.material, 0);
3732
3925
  box.userData = { ldrStud: true, ldrLod: true };
3733
3926
  box.instanceMatrix = im.instanceMatrix;
3734
3927
  box.count = im.count;
@@ -3738,7 +3931,7 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
3738
3931
  box.onBeforeRender = trackVp;
3739
3932
  root.add(box);
3740
3933
  discObjs.push(box);
3741
- cl.lv.push({ objs: [box], err: STUD_BOX_ERR });
3934
+ cl.lv.push({ objs: [box], err: h ? Math.max(STUD_BOX_ERR, 6 * Math.SQRT2 - h.out) : STUD_BOX_ERR });
3742
3935
  cl.studLineLv = 1;
3743
3936
  }
3744
3937
  if (LOD) {
@@ -3755,8 +3948,19 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
3755
3948
  cl.lv.push({ objs: [disc], err: STUD_DISC_ERR });
3756
3949
  cl.lv.push({ objs: [], err: STUD_ERR });
3757
3950
  }
3758
- if (EDGES && k.edges)
3759
- addLines(k.edges, im, cl);
3951
+ if (EDGES && k.edges) {
3952
+ const round = addLines(k.edges, im, cl);
3953
+ let sq = cl.studLineLv === 1 && round ? sqLineKey.get(kind) : null;
3954
+ if (sq === undefined) {
3955
+ const r = studSquareLines(arr(k.edges), sqW, hole);
3956
+ sqLineKey.set(kind, sq = r && { sq: r });
3957
+ }
3958
+ if (sq && round) {
3959
+ const l = addLines(sq, im, cl, sq.sq);
3960
+ round.userData.ldrLineLvs = [0, 0];
3961
+ l.userData.ldrLineLvs = [1, 1];
3962
+ }
3963
+ }
3760
3964
  if (P.condStuds !== false)
3761
3965
  addCond(k, im, cl);
3762
3966
  const objs = [im, ...discObjs, ...cl.lines, ...cl.cond];
@@ -3784,8 +3988,12 @@ function* buildLdrSceneGen(insts, pack, P, color, mark) {
3784
3988
  o.visible = i === c.cur;
3785
3989
  });
3786
3990
  const lineVis = edgesOn && c.edgeOk && c.cur >= 0 && (c.studLineLv !== undefined ? c.cur <= c.studLineLv : c.cur === 0 || !LOD || (c.setMergedLevel ? true : c.lv[c.cur].objs.length > 0));
3787
- for (const o of c.lines)
3788
- o.visible = lineVis;
3991
+ for (const o of c.lines) {
3992
+ const lv = o.userData.ldrLineLvs;
3993
+ const v = lineVis && (!lv || c.cur >= lv[0] && c.cur <= lv[1]);
3994
+ o.userData.ldrVis = v;
3995
+ o.visible = v && o.geometry.drawRange.count !== 0;
3996
+ }
3789
3997
  for (const o of c.cond)
3790
3998
  o.visible = lineVis && condOn;
3791
3999
  };
@@ -4014,7 +4222,7 @@ async function warmPackGeometry(pack, stop = () => false, sliceMs = 8) {
4014
4222
  await new Promise((r) => setTimeout(r, 0));
4015
4223
  }
4016
4224
  }
4017
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/scene.ts
4225
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/scene.ts
4018
4226
  import * as THREE2 from "three";
4019
4227
  var _box = new THREE2.Box3;
4020
4228
  var _m4 = new THREE2.Matrix4;
@@ -4369,10 +4577,10 @@ function createLdrObjectInner(instances, pack, options, progressive) {
4369
4577
  return finish();
4370
4578
  })();
4371
4579
  }
4372
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/parts-cdn.ts
4580
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/parts-cdn.ts
4373
4581
  import { decompress as decompress2 } from "fzstd";
4374
4582
 
4375
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/embedded.ts
4583
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/embedded.ts
4376
4584
  function splitFiles(text, fallback) {
4377
4585
  const files = new Map;
4378
4586
  let cur = null, saw = false, skip = false;
@@ -4447,7 +4655,7 @@ function embeddedKeys(text, names, fallback = "main.ldr") {
4447
4655
  return out;
4448
4656
  }
4449
4657
 
4450
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/parts-cdn.ts
4658
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/parts-cdn.ts
4451
4659
  var DEFAULT_PARTS_CDN = "https://ldr-demo.vercel.app/cdn/v1/";
4452
4660
  var indexCache = new Map;
4453
4661
  var shardCache = new Map;
@@ -4701,10 +4909,10 @@ async function prepareModel(source, o = {}) {
4701
4909
  return { insts, pack, tier, missing, requests, bytes, cull, timings: { fetchModel: t1 - t0, parse: t2 - t1, parts: t3 - t2, ...cull ? { cull: performance.now() - t3 } : {} } };
4702
4910
  }
4703
4911
 
4704
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/load-worker.gen.ts
4912
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/load-worker.gen.ts
4705
4913
  var load_worker_gen_default = 'var Ft=ArrayBuffer,ee=Uint8Array,we=Uint16Array,Rt=Int16Array;var Me=Int32Array,Ie=function(e,t,n){if(ee.prototype.slice)return ee.prototype.slice.call(e,t,n);if(t==null||t<0)t=0;if(n==null||n>e.length)n=e.length;var r=new ee(n-t);return r.set(e.subarray(t,n)),r},he=function(e,t,n,r){if(ee.prototype.fill)return ee.prototype.fill.call(e,t,n,r);if(n==null||n<0)n=0;if(r==null||r>e.length)r=e.length;for(;n<r;++n)e[n]=t;return e},Bt=function(e,t,n,r){if(ee.prototype.copyWithin)return ee.prototype.copyWithin.call(e,t,n,r);if(n==null||n<0)n=0;if(r==null||r>e.length)r=e.length;while(n<r)e[t++]=e[n++]};var Dt=["invalid zstd data","window size too large (>2046MB)","invalid block type","FSE accuracy too high","match distance too far back","unexpected EOF"],te=function(e,t,n){var r=Error(t||Dt[e]);if(r.code=e,Error.captureStackTrace)Error.captureStackTrace(r,te);if(!n)throw r;return r},Qe=function(e,t,n){var r=0,s=0;for(;r<n;++r)s|=e[t++]<<(r<<3);return s},Ut=function(e,t){return(e[t]|e[t+1]<<8|e[t+2]<<16|e[t+3]<<24)>>>0},Ot=function(e,t){var n=e[0]|e[1]<<8|e[2]<<16;if(n==3126568&&e[3]==253){var r=e[4],s=r>>5&1,o=r>>2&1,i=r&3,c=r>>6;if(r&8)te(0);var u=6-s,f=i==3?4:i,a=Qe(e,u,f);u+=f;var l=c?1<<c:s,m=Qe(e,u,l)+(c==1&&256),g=m;if(!s){var d=1<<10+(e[5]>>3);g=d+(d>>3)*(e[5]&7)}if(g>2145386496)te(1);var b=new ee((t==1?m||g:t?0:g)+12);return b[0]=1,b[4]=4,b[8]=8,{b:u+l,y:0,l:0,d:a,w:t&&t!=1?t:b.subarray(12),e:g,o:new Me(b.buffer,0,3),u:m,c:o,m:Math.min(131072,g)}}else if((n>>4|e[3]<<20)==25481893)return Ut(e,4)+8;te(0)},le=function(e){var t=0;for(;1<<t<=e;++t);return t-1},ge=function(e,t,n){var r=(t<<3)+4,s=(e[t]&15)+5;if(s>n)te(3);var o=1<<s,i=o,c=-1,u=-1,f=-1,a=o,l=new Ft(512+(o<<2)),m=new Rt(l,0,256),g=new we(l,0,256),d=new we(l,512,o),b=512+(o<<1),C=new ee(l,b,o),A=new ee(l,b+o);while(c<255&&i>0){var p=le(i+1),h=r>>3,M=(1<<p+1)-1,D=(e[h]|e[h+1]<<8|e[h+2]<<16)>>(r&7)&M,v=(1<<p)-1,L=M-i-1,R=D&v;if(R<L)r+=p,D=R;else if(r+=p+1,D>v)D-=L;if(m[++c]=--D,D==-1)i+=D,C[--a]=c;else i-=D;if(!D)do{var T=r>>3;u=(e[T]|e[T+1]<<8)>>(r&7)&3,r+=2,c+=u}while(u==3)}if(c>255||i)te(0);var x=0,w=(o>>1)+(o>>3)+3,E=o-1;for(var z=0;z<=c;++z){var k=m[z];if(k<1){g[z]=-k;continue}for(f=0;f<k;++f){C[x]=z;do x=x+w&E;while(x>=a)}}if(x)te(0);for(f=0;f<o;++f){var P=g[C[f]]++,Y=A[f]=s-le(P);d[f]=(P<<Y)-o}return[r+7>>3,{b:s,s:C,n:A,t:d}]},Nt=function(e,t){var n=0,r=-1,s=new ee(292),o=e[t],i=s.subarray(0,256),c=s.subarray(256,268),u=new we(s.buffer,268);if(o<128){var f=ge(e,t+1,6),a=f[0],l=f[1];t+=o;var m=a<<3,g=e[t];if(!g)te(0);var d=0,b=0,C=l.b,A=C,p=(++t<<3)-8+le(g);for(;;){if(p-=C,p<m)break;var h=p>>3;if(d+=(e[h]|e[h+1]<<8)>>(p&7)&(1<<C)-1,i[++r]=l.s[d],p-=A,p<m)break;h=p>>3,b+=(e[h]|e[h+1]<<8)>>(p&7)&(1<<A)-1,i[++r]=l.s[b],C=l.n[d],d=l.t[d],A=l.n[b],b=l.t[b]}if(++r>255)te(0)}else{r=o-127;for(;n<r;n+=2){var M=e[++t];i[n]=M>>4,i[n+1]=M&15}++t}var D=0;for(n=0;n<r;++n){var v=i[n];if(v>11)te(0);D+=v&&1<<v-1}var L=le(D)+1,R=1<<L,T=R-D;if(T&T-1)te(0);i[r++]=le(T)+1;for(n=0;n<r;++n){var v=i[n];++c[i[n]=v&&L+1-v]}var x=new ee(R<<1),w=x.subarray(0,R),E=x.subarray(R);u[L]=0;for(n=L;n>0;--n){var z=u[n];he(E,n,z,u[n-1]=z+c[n]*(1<<L-n))}if(u[0]!=R)te(0);for(n=0;n<r;++n){var k=i[n];if(k){var P=u[k];he(w,n,P,u[k]=P+(1<<L-k))}}return[t,{n:E,b:L,s:w}]},zt=ge(new ee([81,16,99,140,49,198,24,99,12,33,196,24,99,102,102,134,70,146,4]),0,6)[1],$t=ge(new ee([33,20,196,24,99,140,33,132,16,66,8,33,132,16,66,8,33,68,68,68,68,68,68,68,68,36,9]),0,6)[1],jt=ge(new ee([32,132,16,66,102,70,68,68,68,68,36,73,2]),0,5)[1],qe=function(e,t){var n=e.length,r=new Me(n);for(var s=0;s<n;++s)r[s]=t,t+=1<<e[s];return r},Fe=new ee(new Me([0,0,0,0,16843009,50528770,134678020,202050057,269422093]).buffer,0,36),Vt=qe(Fe,0),Re=new ee(new Me([0,0,0,0,0,0,0,0,16843009,50528770,117769220,185207048,252579084,16]).buffer,0,53),_t=qe(Re,3),me=function(e,t,n){var r=e.length,s=t.length,o=e[r-1],i=(1<<n.b)-1,c=-n.b;if(!o)te(0);var u=0,f=n.b,a=(r<<3)-8+le(o)-f,l=-1;for(;a>c&&l<s;){var m=a>>3,g=(e[m]|e[m+1]<<8|e[m+2]<<16)>>(a&7);u=(u<<f|g)&i,t[++l]=n.s[u],a-=f=n.n[u]}if(a!=c||l+1!=s)te(0)},Ht=function(e,t,n){var r=6,s=t.length,o=s+3>>2,i=o<<1,c=o+i;me(e.subarray(r,r+=e[0]|e[1]<<8),t.subarray(0,o),n),me(e.subarray(r,r+=e[2]|e[3]<<8),t.subarray(o,i),n),me(e.subarray(r,r+=e[4]|e[5]<<8),t.subarray(i,c),n),me(e.subarray(r),t.subarray(c),n)},Gt=function(e,t,n){var r,s=t.b,o=e[s],i=o>>1&3;t.l=o&1;var c=o>>3|e[s+1]<<5|e[s+2]<<13,u=(s+=3)+c;if(i==1){if(s>=e.length)return;if(t.b=s+1,n)return he(n,e[s],t.y,t.y+=c),n;return he(new ee(c),e[s])}if(u>e.length)return;if(i==0){if(t.b=u,n)return n.set(e.subarray(s,u),t.y),t.y+=c,n;return Ie(e,s,u)}if(i==2){var f=e[s],a=f&3,l=f>>2&3,m=f>>4,g=0,d=0;if(a<2)if(l&1)m|=e[++s]<<4|(l&2&&e[++s]<<12);else m=f>>3;else if(d=l,l<2)m|=(e[++s]&63)<<4,g=e[s]>>6|e[++s]<<2;else if(l==2)m|=e[++s]<<4|(e[++s]&3)<<12,g=e[s]>>2|e[++s]<<6;else m|=e[++s]<<4|(e[++s]&63)<<12,g=e[s]>>6|e[++s]<<2|e[++s]<<10;++s;var b=n?n.subarray(t.y,t.y+t.m):new ee(t.m),C=b.length-m;if(a==0)b.set(e.subarray(s,s+=m),C);else if(a==1)he(b,e[s++],C);else{var A=t.h;if(a==2){var p=Nt(e,s);g+=s-(s=p[0]),t.h=A=p[1]}else if(!A)te(0);(d?Ht:me)(e.subarray(s,s+=g),b.subarray(C),A)}var h=e[s++];if(h){if(h==255)h=(e[s++]|e[s++]<<8)+32512;else if(h>127)h=h-128<<8|e[s++];var M=e[s++];if(M&3)te(0);var D=[$t,jt,zt];for(var v=2;v>-1;--v){var L=M>>(v<<1)+2&3;if(L==1){var R=new ee([0,0,e[s++]]);D[v]={s:R.subarray(2,3),n:R.subarray(0,1),t:new we(R.buffer,0,1),b:0}}else if(L==2)r=ge(e,s,9-(v&1)),s=r[0],D[v]=r[1];else if(L==3){if(!t.t)te(0);D[v]=t.t[v]}}var T=t.t=D,x=T[0],w=T[1],E=T[2],z=e[u-1];if(!z)te(0);var k=(u<<3)-8+le(z)-E.b,P=k>>3,Y=0,I=(e[P]|e[P+1]<<8)>>(k&7)&(1<<E.b)-1;P=(k-=w.b)>>3;var j=(e[P]|e[P+1]<<8)>>(k&7)&(1<<w.b)-1;P=(k-=x.b)>>3;var H=(e[P]|e[P+1]<<8)>>(k&7)&(1<<x.b)-1;for(++h;--h;){var Z=E.s[I],O=E.n[I],G=x.s[H],K=x.n[H],J=w.s[j],Q=w.n[j];P=(k-=J)>>3;var S=1<<J,y=S+((e[P]|e[P+1]<<8|e[P+2]<<16|e[P+3]<<24)>>>(k&7)&S-1);P=(k-=Re[G])>>3;var B=_t[G]+((e[P]|e[P+1]<<8|e[P+2]<<16)>>(k&7)&(1<<Re[G])-1);P=(k-=Fe[Z])>>3;var _=Vt[Z]+((e[P]|e[P+1]<<8|e[P+2]<<16)>>(k&7)&(1<<Fe[Z])-1);if(P=(k-=O)>>3,I=E.t[I]+((e[P]|e[P+1]<<8)>>(k&7)&(1<<O)-1),P=(k-=K)>>3,H=x.t[H]+((e[P]|e[P+1]<<8)>>(k&7)&(1<<K)-1),P=(k-=Q)>>3,j=w.t[j]+((e[P]|e[P+1]<<8)>>(k&7)&(1<<Q)-1),y>3)t.o[2]=t.o[1],t.o[1]=t.o[0],t.o[0]=y-=3;else{var W=y-(_!=0);if(W){if(y=W==3?t.o[0]-1:t.o[W],W>1)t.o[2]=t.o[1];t.o[1]=t.o[0],t.o[0]=y}else y=t.o[0]}for(var v=0;v<_;++v)b[Y+v]=b[C+v];Y+=_,C+=_;var X=Y-y;if(X<0){var N=-X,q=t.e+X;if(N>B)N=B;for(var v=0;v<N;++v)b[Y+v]=t.w[q+v];Y+=N,B-=N,X=0}for(var v=0;v<B;++v)b[Y+v]=b[X+v];Y+=B}if(Y!=C)while(C<b.length)b[Y++]=b[C++];else Y=b.length;if(n)t.y+=Y;else b=Ie(b,0,Y)}else if(n){if(t.y+=m,C)for(var v=0;v<m;++v)b[v]=b[C+v]}else if(C)b=Ie(b,C);return t.b=u,b}te(2)},Wt=function(e,t){if(e.length==1)return e[0];var n=new ee(t);for(var r=0,s=0;r<e.length;++r){var o=e[r];n.set(o,s),s+=o.length}return n};function Ae(e,t){var n=[],r=+!t,s=0,o=0;for(;e.length;){var i=Ot(e,r||t);if(typeof i=="object"){if(r){if(t=null,i.w.length==i.u)n.push(t=i.w),o+=i.u}else n.push(t),i.e=0;for(;!i.l;){var c=Gt(e,i,t);if(!c)te(5);if(t)i.e=i.y;else n.push(c),o+=c.length,Bt(i.w,0,c.length),i.w.set(c,i.w.length-c.length)}s=i.b+i.c*4}else s=i;e=e.subarray(s)}return Wt(n,o)}async function Kt(e){let t=e instanceof Uint8Array?e:new Uint8Array(e),n=(r)=>r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);if(t[0]===40&&t[1]===181&&t[2]===47&&t[3]===253)return n(Ae(t));if(t[0]===31&&t[1]===139)return new Response(new Blob([t]).stream().pipeThrough(new DecompressionStream("gzip"))).arrayBuffer();return n(t)}async function et(e){return new TextDecoder().decode(await Kt(e))}var tt=(e)=>decodeURIComponent(e.split(/[?#]/)[0].split("/").pop()||"main.ldr").replace(/\\.(zst|gz)$/i,"")||"main.ldr";function ve(e){let t=new DataView(e).getUint32(0,!0),n=JSON.parse(new TextDecoder().decode(new Uint8Array(e,4,t))),r=4+t;return{header:n,arr:(o)=>o&&(o[2]==="f32"?new Float32Array(e,r+o[0],o[1]):o[2]==="u16"?new Uint16Array(e,r+o[0],o[1]):o[2]==="u8"?new Uint8Array(e,r+o[0],o[1]):new Uint32Array(e,r+o[0],o[1])),bytes:e.byteLength,buffer:e}}var ne=(e)=>e.trim().toLowerCase().replace(/\\\\/g,"/").replace(/\\/+/g,"/"),De=/^[A-Za-z][A-Za-z0-9_]*$/,Be=new Map;function Ue(e){let t=e.toLowerCase(),n=2166136261;for(let s=0;s<t.length;s++)n^=t.charCodeAt(s),n=Math.imul(n,16777619);let r=-1-(n>>>0&1073741823);if(!Be.has(r))Be.set(r,t);return r}function Oe(e){let t=e.charCodeAt(0)|32;if(t>=97&&t<=122&&De.test(e))return Ue(e);if(/^0x/i.test(e))return parseInt(e,16);return+e}var nt=/^~?\\s*moved\\s+to\\s+(.+)$/i,Xt=new Set(["FILE","NOFILE","!DATA","!:","STEP","BFC","ROTSTEP","BUFEXCHG","!TEXMAP"]),Zt=new Set(["FILE","NOFILE","!DATA"]),ut=1000000000000000,ft=new Set(["part","subpart","primitive","8_primitive","48_primitive","shortcut","helper"]),Yt=new Set(["model","submodel","configuration"]),Jt=/^(?:!?LDRAW_ORG|Unofficial|Official\\s+LCAD)\\s+(\\S+)/i;function rt(e){let t=Jt.exec(e);if(!t)return;let n=t[1].toLowerCase().replace(/^unofficial_/,"");return ft.has(n)||Yt.has(n)?n:void 0}function Qt(e){let t=[],n=0;while(n<e.length){while(e[n]===" "||e[n]==="\\t")n++;if(n>=e.length)break;if(e[n]===\'"\'){let r="";n++;while(n<e.length&&e[n]!==\'"\'){if(e[n]==="\\\\"&&n+1<e.length)n++;r+=e[n++]}n++,t.push(r)}else{let r=n;while(r<e.length&&e[r]!==" "&&e[r]!=="\\t")r++;t.push(e.slice(n,r)),n=r}}return t}function qt(e,t=!1){let n=/^\\s*(\\S+)\\s+(.*)$/.exec(e);if(!n)return null;let r=n[1].toUpperCase(),s=r==="PLANAR"?9:r==="CYLINDRICAL"?10:r==="SPHERICAL"?11:0;if(!s)return null;let o=n[2].trim().split(/\\s+/);if(o.length<s+1)return null;let i=o.slice(0,s).map(Number);if(!i.every((l)=>Number.isFinite(l)&&Math.abs(l)<=1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000))return null;if(s>=10&&!(Math.abs(i[9])>=0.000001)||s===11&&!(Math.abs(i[10])>=0.000001))return null;let c=n[2].trim();for(let l=0;l<s;l++)c=c.replace(/^\\S+\\s*/,"");let u=Qt(c);if(!u.length)return null;let f={method:r,p1:i.slice(0,3),p2:i.slice(3,6),p3:i.slice(6,9),texture:u[0]};if(s>=10)f.a=i[9];if(s===11)f.b=i[10];let a=u.findIndex((l,m)=>m>0&&l.toUpperCase()==="GLOSSMAP");if(a>0&&u[a+1])f.glossmap=u[a+1];if(t)f.next=!0;return f}var en=(e)=>{let t=e.replace(/[^A-Za-z0-9+/]/g,"");if(t.length%4===1)t=t.slice(0,-1);let n=t+"=".repeat((4-t.length%4)%4),r=atob(n),s=new Uint8Array(r.length);for(let o=0;o<r.length;o++)s[o]=r.charCodeAt(o);return s};function tn(e){let t=e.length,n=1,r=(a)=>a===32||a===9,s=()=>{while(n<t&&r(e.charCodeAt(n)))n++;let a=n;while(n<t&&!r(e.charCodeAt(n)))n++;return a<n?e.slice(a,n):null},o=s();if(o===null)return null;let i=Array(12);for(let a=0;a<12;a++){let l=s();if(l===null)return null;let m=+l;if(!Number.isFinite(m))return null;i[a]=m}while(n<t&&r(e.charCodeAt(n)))n++;if(n>=t)return null;let c=e.slice(n),u=/[ \\t]{2,}|\\t/.test(c)?c.split(/\\s+/).join(" "):c,f=Oe(o);if(!Number.isFinite(f))return null;return{t:1,color:f,m:i,file:ne(u)}}var nn=[0,12,6,9,12,12];function st(e){let t=+e[0];if(!(t>=1&&t<=5&&Number.isInteger(t))||e.length<2)return null;let n=Oe(e[1]),r=nn[t];if(!Number.isFinite(n)||e.length<2+r+(t===1?1:0))return null;let s=Array(r);for(let o=0;o<r;o++){let i=+e[2+o];if(!Number.isFinite(i))return null;s[o]=i}if(t===1){let o=ne(e.slice(14).join(" "));return o?{t:1,color:n,m:s,file:o}:null}if(t===2)return{t:2,color:n,p:s};if(t===3)return{t:3,color:n,p:s};if(t===4)return{t:4,color:n,p:s};return{t:5,color:n,p:s}}function pt(e,t="main.ldr",n={}){let r=!!n.geometryText,s=new Map,o=null,i="",c,u=null,f=[],a=null,l=()=>{if(!u)return;let p=en(u.chunks.join("")),h=p[0]===137&&p[1]===80&&p[2]===78&&p[3]===71;(c??=new Map).set(ne(u.name),{name:u.name,bytes:p,...h?{mime:"image/png"}:{}}),u=null},m=!0,g=(p)=>{if(l(),o={name:ne(p),cmds:[]},s.set(o.name,o),!i)i=o.name;f=[],a=null,m=!0},d=!1,b=!1,C=()=>{if(b)return;b=!0,s.clear(),o=null,i=""},A=(p,h)=>{if(a){p.tex=a,a=null;return}let M=f[f.length-1];if(!M)return;if(M.fallback){if(!h)p.fallback=!0}else p.tex=M.map};for(let p of e.split(`\n`)){let h=p.trim();if(!h)continue;if(r&&h.charCodeAt(0)>=50&&h.charCodeAt(0)<=53&&(h.charCodeAt(1)===32||h.charCodeAt(1)===9)){if(u||d)continue;if(!o)g(t);let L=h.slice(2).trimStart(),R=L.search(/\\s/),T={t:h.charCodeAt(0)-48,color:Oe(R<0?L:L.slice(0,R)),p:[],src:h};A(T,!1),o.cmds.push(T),m=!1;continue}if(h.charCodeAt(0)===48&&(h.charCodeAt(1)===32||h.charCodeAt(1)===9)){let L=2;while(h.charCodeAt(L)===32||h.charCodeAt(L)===9)L++;let R=L;while(R<h.length&&h.charCodeAt(R)!==32&&h.charCodeAt(R)!==9)R++;let T=h.slice(L,R),x=/[^\\x21-\\x7e]/.test(T)?h.slice(L).trim().split(/\\s+/)[0]:T;if(!Xt.has(x)&&!(x.length>=4&&x.length<=6&&Zt.has(x.toUpperCase()))){if(d||u)continue;if(!o)g(t);let w=h.slice(L),E={t:0,text:w};if(T.charCodeAt(0)===33)E.meta=T;if(a=null,m&&!o.org){let k=rt(w);if(k)o.org=k}let z=w.match(nt);if(z&&!o.movedTo){let k=z[1].trim().replace(/\\\\/g,"/");if(!/\\.(dat|ldr|mpd)$/i.test(k))k+=".dat";o.movedTo=ne(k)}o.cmds.push(E);continue}}if(h.charCodeAt(0)===49&&(h.charCodeAt(1)===32||h.charCodeAt(1)===9)&&!u&&!d){let L=tn(h);if(L){if(!o)g(t);A(L,!1),o.cmds.push(L),m=!1;continue}}let M=h.split(/\\s+/);if(+M[0]===0){let L=h.slice(1).trim(),R=M.length>1&&M[1].length>=4&&M[1].length<=6?M[1].toUpperCase():M[1];if(R==="FILE"){let w=L.slice(5).trimStart().split("\\r")[0].trim();if(w){C(),d=!1,g(w);continue}}if(R==="NOFILE"){l(),o=null,d=!0;continue}if(R==="!DATA"){C(),l(),o=null,d=!1,u={name:L.slice(5).trim(),chunks:[]};continue}if(d)continue;if(u){if(M[1]==="!:")u.chunks.push(M.slice(2).join(""));continue}if(!o)g(t);let T={t:0,text:L};if(M[1]==="STEP")T.step=!0,f=[],a=null;else if(M[1]==="BFC")T.bfc=M.slice(2).join(" ");else if(M[1]==="ROTSTEP")if(T.meta="ROTSTEP",T.step=!0,f=[],a=null,(M[2]??"").toUpperCase()==="END")T.rotstep={x:0,y:0,z:0,mode:"END"};else{let w=(M[5]??"REL").toUpperCase(),E=(z)=>{let k=Number(z);return Number.isFinite(k)?k:0};T.rotstep={x:E(M[2]),y:E(M[3]),z:E(M[4]),mode:["REL","ABS","ADD"].includes(w)?w:"REL"}}else if(M[1]==="BUFEXCHG"){T.meta="BUFEXCHG";let w=(M[2]??"").toUpperCase();T.bufexchg={op:w==="RETRIEVE"?"RETRIEVE":"STORE",buf:M[3]??"A"}}else if(M[1]?.startsWith("!"))T.meta=M[1];if(m&&!o.org){let w=rt(L);if(w)o.org=w}if(M[1]==="!TEXMAP"){let w=(M[2]??"").toUpperCase();if(a=null,w==="START"||w==="NEXT"){let E=qt(L.replace(/^!TEXMAP\\s+\\S+/i,""),w==="NEXT");if(T.texmap={op:w,...E?{map:E}:{}},E)if((o.texmaps??=[]).push(E),w==="START")f.push({map:E,fallback:!1});else a=E}else if(w==="FALLBACK"){T.texmap={op:w};let E=f[f.length-1];if(E)E.fallback=!0}else if(w==="END")T.texmap={op:w},f.pop()}else if(M[1]==="!:"){a=null;let w=st(M.slice(2));if(w)A(w,!0),T.geom=w}else a=null;let x=L.match(nt);if(x&&!o.movedTo){let w=x[1].trim().replace(/\\\\/g,"/");if(!/\\.(dat|ldr|mpd)$/i.test(w))w+=".dat";o.movedTo=ne(w)}o.cmds.push(T);continue}if(u||d)continue;if(!o)g(t);let v=st(M);if(!v){if(/^[2-5][ \\t]/.test(h))m=!1;continue}A(v,!1),o.cmds.push(v),m=!1}return l(),c?{main:i,files:s,data:c}:{main:i,files:s}}var Pn=Math.PI/180;function mt(e,t){let n=(r)=>[t[3]*r[0]+t[4]*r[1]+t[5]*r[2]+t[0],t[6]*r[0]+t[7]*r[1]+t[8]*r[2]+t[1],t[9]*r[0]+t[10]*r[1]+t[11]*r[2]+t[2]];return{...e,p1:n(e.p1),p2:n(e.p2),p3:n(e.p3)}}function ht(e,t){let[n,r,s,o,i,c,u,f,a,l,m,g]=e,[d,b,C,A,p,h,M,D,v,L,R,T]=t;return[o*d+i*b+c*C+n,u*d+f*b+a*C+r,l*d+m*b+g*C+s,o*A+i*M+c*L,o*p+i*D+c*R,o*h+i*v+c*T,u*A+f*M+a*L,u*p+f*D+a*R,u*h+f*v+a*T,l*A+m*M+g*L,l*p+m*D+g*R,l*h+m*v+g*T]}var Ne=[0,0,0,1,0,0,0,1,0,0,0,1];var ot=new WeakMap,rn=/^(s|8|48)\\//;function ze(e,t){let n=e.files.get(ne(t));if(!n)return"part";let r=ot.get(n);if(r)return r;if(n.org)r=ft.has(n.org)?"part":"model";else if(n.name===e.main)r="model";else r=n.cmds.some((s)=>s.t>=2||s.t===0&&!!s.geom||s.t===1&&rn.test(s.file))?"part":"model";return ot.set(n,r),r}var it=new WeakMap;function gt(e){let t=it.get(e);if(t)return t;t=[];let n=0;for(let r of e.cmds){if(r.t===0&&r.step){n++;continue}if((r.t>=2||r.t===0&&r.geom&&r.geom.t>=2)&&t[t.length-1]!==n)t.push(n)}return it.set(e,t),t}var at=(e)=>e>16777215?"0x"+e.toString(16).toUpperCase():e<0?Be.get(e)??String(e):String(e),sn=(e)=>e.t===0?"0 "+e.text:e.t===1?`1 ${at(e.color)} ${e.m.join(" ")} ${e.file}`:e.src?e.src:`${e.t} ${at(e.color)} ${e.p.join(" ")}`,$e=(e,t)=>`${ne(e)}#${t}`;function on(e,t){let n=[],r=0,s=(o)=>!!o&&o.t===0&&o.texmap?.op==="NEXT";for(let o of e.cmds){if(o.t===0){if(o.step){r++;continue}if(o.bfc!==void 0||o.meta==="!COLOUR"){n.push(o);continue}if(r!==t)continue;if(o.texmap)n.push(o);else if(o.geom){if(o.geom.t>=2)n.push(o);else if(s(n[n.length-1]))n.pop()}continue}if(r!==t)continue;if(o.t===1){if(s(n[n.length-1]))n.pop();continue}n.push(o)}return{name:$e(e.name,t),cmds:n}}function dt(e,t){return[`0 ldr: own geometry of ${e.name}, step ${t}`,...on(e,t).cmds.map(sn)].join(`\n`)+`\n`}function je(e){let t=2166136261;for(let n=0;n<e.length;n++)t^=e.charCodeAt(n),t=Math.imul(t,16777619);return(t>>>0).toString(16).padStart(8,"0")}function bt(e){let[t,n,r,s,o,i,c,u,f,a,l,m]=e,g=u*m-f*l,d=-(c*m-f*a),b=c*l-u*a,C=s*g+o*d+i*b;if(!Number.isFinite(C)||Math.abs(C)<0.000000000001)return null;let A=1/C,p=[g*A,-(o*m-i*l)*A,(o*f-i*u)*A,d*A,(s*m-i*a)*A,-(s*f-i*c)*A,b*A,-(s*l-o*a)*A,(s*u-o*c)*A];return[-(p[0]*t+p[1]*n+p[2]*r),-(p[3]*t+p[4]*n+p[5]*r),-(p[6]*t+p[7]*n+p[8]*r),...p]}var an=(e)=>String(+e.toFixed(6)||0),lt=(e)=>\'"\'+e.replace(/\\\\/g,"\\\\\\\\").replace(/"/g,"\\\\\\"")+\'"\';function yt(e,t){let n=[...t.p1,...t.p2,...t.p3,...t.method!=="PLANAR"?[t.a??360]:[],...t.method==="SPHERICAL"?[t.b??180]:[]].map(an).join(" "),r=`0 ldr: ${e} with a model-level !TEXMAP\n0 BFC CERTIFY CCW\n0 !TEXMAP START ${t.method} ${n} ${lt(t.texture)}${t.glossmap?" GLOSSMAP "+lt(t.glossmap):""}\n1 16 0 0 0 1 0 0 0 1 0 0 0 1 ${ne(e)}\n0 !TEXMAP END\n`;return{name:`${ne(e)}#tex-${je(r)}`,source:r}}var ln=(e,t)=>{let n=[,,,,,,,,,];for(let r=0;r<3;r++)for(let s=0;s<3;s++)n[r*3+s]=e[r*3]*t[s]+e[r*3+1]*t[3+s]+e[r*3+2]*t[6+s];return n};function cn(e,t,n){let r=Math.PI/180,s=Math.sin(e*r),o=Math.cos(e*r),i=Math.sin(t*r),c=Math.cos(t*r),u=Math.sin(n*r),f=Math.cos(n*r);return[c*f,-c*u,i,o*u+s*i*f,o*f-s*i*u,-s*c,s*u-o*i*f,s*f+o*i*u,o*c]}var ct=new WeakMap;function xt(e){let t=ct.get(e);if(t)return t;let n=[],r=null;for(let s of e.cmds){if(s.t!==0||!s.step)continue;let o=s.rotstep;if(o)if(o.mode==="END")r=null;else{let i=cn(o.x,o.y,o.z);r=o.mode==="ABS"?{abs:!0,m:i,rotstep:o}:o.mode==="ADD"&&r?{abs:r.abs,m:ln(r.m,i),rotstep:o}:{abs:!1,m:i,rotstep:o}}n.push(r)}return n.push(r),ct.set(e,n),n}class Ve extends Error{limit;code="ldr-model-limit";constructor(e,t){super(`ldr: ${e} expands past ${t.toLocaleString("en-US")} (see maxInstances)`);this.limit=t;this.name="ModelLimitError"}}var un=(e)=>{for(let t=0;t<12;t++)if(!(Math.abs(e[t])<=ut))return!1;return!0},wt=999999,vt=(e)=>e.map((t)=>String(t).padStart(6,"0")).join(".")+"~",Ct=new WeakMap,Mt=new WeakMap;function fn(e,t){let n=Mt.get(t);if(!n)n={head:[...t.values()].map((o)=>{let i=Ct.get(o)??"",c=i.indexOf("!COLOUR");return c<0?"":"0 "+i.slice(c).trim().replace(/\\s+/g," ")}).filter(Boolean).join(`\n`),parts:new Map},Mt.set(t,n);let r=n.parts.get(e);if(!r){let s=ne(e),o=`0 ldr: ${s} placed in a model\'s !COLOUR scope\n0 BFC CERTIFY CCW\n${n.head}\n1 16 0 0 0 1 0 0 0 1 0 0 0 1 ${s}\n`;r={name:`${s}#col-${je(o)}`,source:o},n.parts.set(e,r)}return r}function pn(e,t={}){let n=[],r=t.maxDepth??64,s=t.looseGeometry!==!1,o=!!t.textures,i=!!t.callouts,c=new Map,u=0,f=new Set,a=t.maxInstances??2000000,l=0,m=(d,b)=>{let C=d.name+"#"+b,A=c.get(C);if(!A){let p;A=Object.assign(()=>p??=dt(d,b),{file:d,step:b}),c.set(C,A)}return A},g=(d,b,C,A,p,h,M,D,v=null,L=[],R=[],T=void 0,x=null)=>{let w=d.files.get(b);if(!w||M>r||f.has(w))return;if(++l>a)throw new Ve("model",a);f.add(w);let E=x,z=0,k=M>0?++u:0,P=i&&k?[...L,k]:L,Y=i&&k?[...R,C]:R,I=i&&!v?new Map:null,j=-1,H=0,Z=(S,y,B,_,W,X,N)=>{if(j!==z)j=z,H=0;let q=I?.get(z+"|"+y);if(q)return q.n++,g(S,S===d?y:S.main,B,_,p+"/"+y,[...W,wt],M+1,X,[...W,wt],P,Y,N,E);let U=[...W,H++],F=n.length;g(S,S===d?y:S.main,B,_,p+"/"+y,U,M+1,X,v,P,Y,N,E),I?.set(z+"|"+y,{n:1,from:F,to:n.length})},O=xt(w),G=s?gt(w):[],K=0,J=(S,y,B,_,W,X,N,q,U)=>{if(v)_=v;if(++l>a)throw new Ve("model",a);let F={part:S,color:y,m:B,step:_[0],steps:_,localStep:W,path:p};if(q)F.colour=q;if(k){if(F.sub=k,i)F.subPath=P,F.subMats=Y}if(X)F.embedded=!0;if(N){let re=yt(S,N);F.texPart=re.name,F.texSource=re.source}else if(U){let re=fn(S,U);F.colPart=re.name,F.colSource=re.source}let V=O[W];if(V)F.view=V;return n.push(F),F},Q=(S)=>{while(K<G.length&&G[K]<=S){let y=G[K++];J($e(w.name,y),A,C,[...h,y],y,!1,null,T,x).source=m(w,y)}};for(let S of w.cmds){if(S.t===0&&S.step){z++;continue}let y=S;if(y.t>=2||y.t===0&&y.geom&&y.geom.t>=2){Q(z);continue}if(y.t===0){if(y.meta==="!COLOUR"){let V=hn(y.text);if(V&&V.code!==16&&V.code!==24)Ct.set(V,y.text),(E=new Map(E??[])).set(V.code,V);continue}if(o&&y.geom?.t===1)y=y.geom;else continue}if(y.t!==1)continue;if(o&&y.fallback)continue;let B=ht(C,y.m);if(!un(B))continue;let _=y.color===16?A:y.color,W=y.color===16?T:E?.get(y.color),X=[...h,z],N=o?y.tex??D:null,q=N?bt(y.m):null,U=N&&q?mt(N,q):null;if(d.files.has(y.file)){if(ze(d,y.file)==="model"){Z(d,y.file,B,_,X,U,W);continue}J(y.file,_,B,X,z,!0,U,W,E);continue}let F=t.resolveModel?.(y.file);if(F){Z(F,y.file,B,_,X,U,W);continue}J(y.file,_,B,X,z,!1,U,W,E)}if(Q(1/0),f.delete(w),I){for(let S of I.values())if(S.n>1)for(let y=S.from;y<S.to;y++)n[y].mult??=S.n}};if(ze(e,e.main)==="part"){if(e.files.get(e.main))n.push({part:e.main,color:16,m:[...Ne],step:0,steps:[0],localStep:0,path:e.main,embedded:!0});return n}return g(e,e.main,Ne,16,e.main,[],0,null),n}function Tt(e,t="main.ldr",n){return pn(pt(e,t,{geometryText:!0}),n)}var mn=new Set(["CHROME","PEARLESCENT","RUBBER","MATTE_METALLIC","METAL","MATERIAL"]);function _e(e){if(!e)return null;if(e.startsWith("#")&&/^#[0-9A-Fa-f]{6}$/.test(e))return e.toUpperCase();if(/^0x[0-9A-Fa-f]{6}$/i.test(e))return("#"+e.slice(2)).toUpperCase();return null}function At(e,t){let n={value:"#FFFFFF",fraction:0.5};while(t<e.length){let r=e[t].toUpperCase(),s=e[t+1];if(r==="VALUE"){let o=_e(s);if(o)n.value=o;t+=2}else if(r==="ALPHA")n.alpha=+s,t+=2;else if(r==="LUMINANCE")n.luminance=+s,t+=2;else if(r==="FRACTION")n.fraction=+s,t+=2;else if(r==="VFRACTION")n.vfraction=+s,t+=2;else if(r==="SIZE")n.size=+s,t+=2;else if(r==="MINSIZE")n.minsize=+s,t+=2;else if(r==="MAXSIZE")n.maxsize=+s,t+=2;else break}return{grain:n,next:t}}function hn(e){let t=e.indexOf("!COLOUR");if(t<0)return null;let n=e.slice(t+7).trim().split(/\\s+/).filter(Boolean);if(n.length<2)return null;let r=n[0],s=NaN,o="#FF00FF",i="#333333",c=255,u=0,f={type:"default"},a=1;while(a<n.length){let l=n[a].toUpperCase(),m=n[a+1];if(l==="CODE")s=m!==void 0&&De.test(m)?Ue(m):m!==void 0&&/^\\d+$/.test(m)?+m:NaN,a+=2;else if(l==="VALUE"){let g=_e(m);if(g)o=g;a+=2}else if(l==="EDGE")i=_e(m)??m,a+=2;else if(l==="ALPHA")c=+m,a+=2;else if(l==="LUMINANCE")u=+m,a+=2;else if(l==="CHROME")f={type:"chrome"},a+=1;else if(l==="PEARLESCENT")f={type:"pearlescent"},a+=1;else if(l==="RUBBER")f={type:"rubber"},a+=1;else if(l==="MATTE_METALLIC")f={type:"matte_metallic"},a+=1;else if(l==="METAL")f={type:"metal"},a+=1;else if(l==="MATERIAL"){let g=(n[a+1]||"").toUpperCase();if(g==="GLITTER"){let{grain:d,next:b}=At(n,a+2);f={type:"glitter",material:d},a=b}else if(g==="SPECKLE"){let{grain:d,next:b}=At(n,a+2);f={type:"speckle",material:d},a=b}else if(g==="FABRIC"){let d=(n[a+2]||"").toUpperCase(),b=["VELVET","CANVAS","STRING","FUR"].includes(d)?d.toLowerCase():void 0;f={type:"fabric",kind:b},a+=b?3:2}else a=n.length}else if(mn.has(l))a+=1;else a+=1}if(Number.isNaN(s)||!o)return null;return{code:s,name:r,hex:o,edge:i,alpha:Number.isFinite(c)?c:255,luminance:Number.isFinite(u)?u:0,finish:f}}function gn(e){let t=Math.max(0,Math.min(1,(e.alpha??255)/255)),n=t<1,r=Math.max(0,Math.min(1,(e.luminance??0)/255)),s={opacity:t,transparent:n,depthWrite:!n,emissive:r,clearcoat:0,clearcoatRoughness:0,sheen:0,sheenRoughness:0};switch(e.finish?.type??"default"){case"chrome":return{...s,metalness:1,roughness:0,finish:"chrome"};case"pearlescent":return{...s,metalness:0.25,roughness:0.3,clearcoat:0.5,clearcoatRoughness:0.25,sheen:0.4,sheenRoughness:0.35,finish:"pearlescent"};case"rubber":return{...s,metalness:0,roughness:0.9,finish:"rubber"};case"matte_metallic":return{...s,metalness:0.4,roughness:0.8,finish:"matte_metallic"};case"metal":return{...s,metalness:0.85,roughness:0.2,finish:"metal"};case"glitter":{let i=e.finish.material,c=i.size??(i.minsize!=null&&i.maxsize!=null?(i.minsize+i.maxsize)/2:1);return{...s,metalness:0.35,roughness:0.25,clearcoat:1,clearcoatRoughness:0.08,particleHex:i.value,particleFraction:i.fraction,particleSize:c,finish:"glitter"}}case"speckle":{let i=e.finish.material,c=i.size??(i.minsize!=null&&i.maxsize!=null?(i.minsize+i.maxsize)/2:1);return{...s,metalness:0.2,roughness:0.55,particleHex:i.value,particleFraction:i.fraction,particleSize:c,finish:"speckle"}}case"fabric":return{...s,metalness:0,roughness:0.85,sheen:0.65,sheenRoughness:0.75,finish:"fabric"};default:return{...s,metalness:0,roughness:0.45,finish:"default"}}}function He(e){let t=gn(e),n=!t.transparent?"op":t.opacity>=0.75?"a200":t.opacity>=0.4?"a128":`a${Math.round(t.opacity*255)}`,r=t.emissive>0?`L${Math.round(t.emissive*16)}`:"",s=`${t.finish}:${n}${r}`;if(t.particleHex)s+=`:${t.particleHex}:${(t.particleFraction??0).toFixed(2)}`;return s}function dn(e,t){let n=new Map,r=null,s=!1,o=!1;for(let i of e.split(/\\r?\\n/)){let c=/^\\s*0\\s+FILE\\s+(\\S[^\\r]*)/i.exec(i);if(c){if(!s)n.clear();s=!0,o=!1,r=[],n.set(ne(c[1]),r);continue}if(/^\\s*0\\s+(NOFILE|!DATA)(\\s|$)/i.test(i)){if(!s&&/!DATA/i.test(i))n.clear(),s=!0;r=null,o=!0;continue}if(!r){if(s||o)continue;r=[],n.set(ne(t),r)}let u=i.trim().replace(/\\s+/g," ");if(u)r.push(u)}return n}var bn=(e)=>{if(!e.startsWith("1 "))return null;let t=e.split(" ");return t.length>=15?ne(t.slice(14).join(" ")):null};function yn(e){let t=2166136261,n=1523705862;for(let r=0;r<e.length;r++){let s=e.charCodeAt(r);t=Math.imul(t^s,16777619),n=Math.imul(n^s,16777629)^n>>>15}return(t>>>0).toString(16).padStart(8,"0")+(n>>>0).toString(16).padStart(8,"0")}function Lt(e,t,n="main.ldr"){let r=dn(e,n),s=new Map;for(let o of t){let i=ne(o);if(!r.has(i)||s.has(i))continue;let c=new Set([i]),u=[i];while(u.length)for(let a of r.get(u.pop())){let l=bn(a);if(l&&r.has(l)&&!c.has(l))c.add(l),u.push(l)}let f=[i,...[...c].filter((a)=>a!==i).sort()].map((a)=>"0 FILE "+(a===i?"":a)+`\n`+r.get(a).join(`\n`)).join(`\n`);s.set(i,`emb/${yn(f)}.dat`)}return s}var St=(e,t=0)=>Math.abs(e[t+7]-1)<0.001&&Math.abs(e[t+4])<0.001&&Math.abs(e[t+10])<0.001,Et=new WeakMap;function Ge(e,t){let n=Et.get(e);if(!n)Et.set(e,n=new Map);let r=n.get(t);if(r!==void 0)return r;let s=e.parts[t];if(!s)return n.set(t,null),null;let o=s.studs.length,i=new Float64Array(o*12),c=[],u=[];s.studs.forEach((m,g)=>{c.push(m[0]),u.push(m[1]);for(let d=0;d<12;d++)i[g*12+d]=m[2+d]});let f=null,a=0,l=0;if(s.mask){a=s.mask[0],l=s.mask[1];let m=s.mask[2];f=new Uint8Array(m.length);for(let g=0;g<m.length;g++)f[g]=m.charCodeAt(g)===49?1:0}return n.set(t,r={nStuds:o,studM:i,kind:c,color:u,mask:f,nx:a,nz:l}),r}var fe=1073741824;class We{a;b;c;vals;used;mask;size=0;constructor(e=1024){let t=1024;while(t<e*2)t*=2;this.a=new Int32Array(t),this.b=new Int32Array(t),this.c=new Int32Array(t),this.vals=new Int32Array(t),this.used=new Uint8Array(t),this.mask=t-1}slot(e,t,n){let r=Math.imul(e,2654435761)^Math.imul(t,2246822507)^Math.imul(n,3266489909);return r^=r>>>15,r=Math.imul(r,739982445),r^=r>>>12,r&this.mask}get(e,t,n){let r=this.slot(e,t,n),s=this.used,o=this.a,i=this.b,c=this.c;for(;;){if(!s[r])return-1;if(o[r]===e&&i[r]===t&&c[r]===n)return this.vals[r];r=r+1&this.mask}}put(e,t,n,r){if((this.size+1)*2>this.used.length)this.grow();let s=this.slot(e,t,n),o=this.used,i=this.a,c=this.b,u=this.c;for(;;){if(!o[s])return o[s]=1,i[s]=e,c[s]=t,u[s]=n,this.vals[s]=r,this.size++,-1;if(i[s]===e&&c[s]===t&&u[s]===n){let f=this.vals[s];return this.vals[s]=r,f}s=s+1&this.mask}}grow(){let{a:e,b:t,c:n,vals:r,used:s}=this,o=s.length*2;this.a=new Int32Array(o),this.b=new Int32Array(o),this.c=new Int32Array(o),this.vals=new Int32Array(o),this.used=new Uint8Array(o),this.mask=o-1,this.size=0;for(let i=0;i<s.length;i++)if(s[i])this.put(e[i],t[i],n[i],r[i])}}var pe=(e,t,n)=>e>-fe&&e<fe&&t>-fe&&t<fe&&n>-fe&&n<fe,de=2147483647;function xn(e,t){let n=e.colorTable?.[t];if(n)return(n.alpha??255)<255;return t.charCodeAt(0)===35&&/\\/[^:/]*:a\\d/.test(t)}function wn(e,t,n){let s=new Map,o=(I)=>{let j=s.get(I);if(j===void 0)s.set(I,j=xn(t,I));return j},i=[],c=[],u=[],f=[],a=[],l=[],m=[],g=[],d=[],b=new We(e.length*2),C=[],A=[];for(let I=0;I<e.length;I++){let j=e[I],H=j.m,Z=t.parts[j.part];if(!Z||!Z.mask||!St(H)||o(j.color))continue;let O=Z.bbox,G=1/0,K=-1/0,J=1/0,Q=-1/0;for(let U=0;U<2;U++)for(let F=0;F<2;F++){let V=U?O[3]:O[0],re=F?O[5]:O[2],oe=H[0]+H[3]*V+H[5]*re,se=H[2]+H[9]*V+H[11]*re;if(oe<G)G=oe;if(oe>K)K=oe;if(se<J)J=se;if(se>Q)Q=se}let S=Math.round((H[1]+O[4])*2),y=Ge(t,j.part),B=Math.floor(G/40),_=Math.floor(K/40),W=Math.floor(J/40),X=Math.floor(Q/40);if(!((_-B+1)*(X-W+1)<=65536)||!pe(S,B,W)||!pe(S,_,X))continue;let N=-1;for(let U=b.get(S,B,W),F=0;U>=0&&F<8;U=C[U],F++){let V=A[U];if(i[V]!==G||c[V]!==K||u[V]!==J||f[V]!==Q||m[V]!==y)continue;let re=e[a[V]].m,oe=!0;for(let se=0;se<12;se++)if(re[se]!==H[se]){oe=!1;break}if(oe){N=V;break}}if(N>=0){let U=n?n[I]:0;if(n&&U<n[a[N]])l[N]=a[N],a[N]=I;else if(l[N]<0||n&&U<n[l[N]])l[N]=I;continue}let q=a.length;i.push(G),c.push(K),u.push(J),f.push(Q),a.push(I),l.push(-1),m.push(y),g.push(O[0]),d.push(O[2]);for(let U=B;U<=_;U++)for(let F=W;F<=X;F++){if(!pe(S,U,F))continue;let V=A.length;A.push(q),C.push(b.put(S,U,F,V))}}let p=[0,5,-5,5,-5],h=[0,5,5,-5,-5],M=NaN,D=NaN,v=NaN,L=-1,R=(I,j,H,Z)=>{let O=Math.round(j*2),G=Math.floor(I/40),K=Math.floor(H/40);if(!pe(O,G,K))return de;let J=de;if(O!==M||G!==D||K!==v)M=O,D=G,v=K,L=b.get(O,G,K);for(let Q=L;Q>=0;Q=C[Q]){let S=A[Q],y=a[S];if(y===Z&&(y=l[S])<0)continue;if(!(I-6>=i[S]-0.5&&I+6<=c[S]+0.5&&H-6>=u[S]-0.5&&H+6<=f[S]+0.5))continue;let B=e[a[S]].m,_=m[S],W=g[S],X=d[S],N=I-B[0],q=j-B[1],U=H-B[2],F=B[3]*N+B[6]*q+B[9]*U,V=B[5]*N+B[8]*q+B[11]*U,{nx:re,nz:oe,mask:se}=_,ce=!0;for(let ie=0;ie<5;ie++){let ae=Math.floor((F+p[ie]-W)/20),ue=Math.floor((V+h[ie]-X)/20);if(ae<0||ue<0||ae>=re||ue>=oe||se[ae*oe+ue]!==1){ce=!1;break}}if(ce){if(!n)return 0;let ie=n[y];if(ie<J)J=ie}}return J},T=0;for(let I of e){let j=Ge(t,I.part);if(j)T+=j.nStuds}let x=new Uint8Array(T),w=new Uint8Array(T),E=new We(T),z=0,k=n?new Int32Array(T).fill(de):void 0;for(let I=0,j=0;I<e.length;I++){let H=e[I],Z=Ge(t,H.part);if(!Z)continue;let O=H.m,G=Z.studM,K=O[0],J=O[1],Q=O[2],S=O[3],y=O[4],B=O[5],_=O[6],W=O[7],X=O[8],N=O[9],q=O[10],U=O[11];for(let F=0;F<Z.nStuds;F++,j++){let V=F*12,re=G[V+4],oe=G[V+7],se=G[V+10];if(!(Math.abs(_*re+W*oe+X*se-1)<0.001&&Math.abs(S*re+y*oe+B*se)<0.001&&Math.abs(N*re+q*oe+U*se)<0.001))continue;w[j]=1;let ce=G[V],ie=G[V+1],ae=G[V+2],ue=K+S*ce+y*ie+B*ae,Ke=J+_*ce+W*ie+X*ae,Xe=Q+N*ce+q*ie+U*ae,Ze=R(ue,Ke,Xe,I);if(Ze!==de){if(x[j]=1,z++,k)k[j]=Ze}let be=Math.round(ue),ye=Math.round(Ke),xe=Math.round(Xe);if(!pe(be,ye,xe))continue;if(!n){E.put(be,ye,xe,1);continue}let Ye=n[I],Je=E.get(be,ye,xe);if(Je<0||Ye<Je)E.put(be,ye,xe,Ye)}}let P=new Uint8Array(e.length),Y=n?new Int32Array(e.length).fill(de):void 0;for(let I=0;I<e.length;I++){let j=e[I],H=t.parts[j.part];if(!H||!H.under||!St(j.m)||o(j.color))continue;let Z=H.bbox,O=Math.round((Z[3]-Z[0])/20),G=Math.round((Z[5]-Z[2])/20);if(!O||!G||O*G>4096)continue;let K=j.m,J=!0,Q=0;for(let S=0;S<O&&J;S++)for(let y=0;y<G;y++){let B=Z[0]+10+20*S,_=Z[2]+10+20*y,W=K[0]+K[3]*B+K[5]*_,X=K[2]+K[9]*B+K[11]*_,N=Math.round(W),q=Math.round(K[1]+Z[4]),U=Math.round(X),F=pe(N,q,U)?E.get(N,q,U):-1;if(F<0){J=!1;break}if(F>Q)Q=F}if(J){if(P[I]=1,Y)Y[I]=Q}}return{nStuds:T,studHidden:x,studUp:w,underHidden:P,studsHidden:z,studHideStep:k,underHideStep:Y}}function Mn(e,t,n){let r=(l)=>l.colPart&&t.parts[l.colPart]?l.colPart:n&&l.texPart&&t.parts[l.texPart]?l.texPart:l.part,s=new Map,o=new Map,i=(l)=>{let m=l.colour;if(!m)return String(l.color);let g=o.get(m);if(g!==void 0)return g;let d=t.colorTable?.[l.color],b=d?.hex??t.colors?.[l.color],C=d?He({alpha:d.alpha??255,luminance:d.luminance??0,finish:d.finish??{type:"default"}}):"default:op",A=He(m);if(g=b&&b.toUpperCase()===m.hex.toUpperCase()&&C===A?String(l.color):m.hex.toUpperCase()+"/"+A,g!==String(l.color))s.set(g,m);return o.set(m,g),g},c=e.map((l)=>({part:r(l),color:i(l),m:l.m,steps:l.steps})),u=c.map((l)=>vt(l.steps)),f=[...new Set(u)].sort(),a=new Map(f.map((l,m)=>[l,m]));return{all:c,stepOf:u.map((l)=>a.get(l)),nSteps:f.length,localColours:s}}function Ce(e,t,n=!0){let r=Mn(e,t,n);return wn(r.all,t,r.nSteps>1?r.stepOf:void 0)}var ke="https://ldr-demo.vercel.app/cdn/v1/",Le=new Map,Te=new Map;function Se(e=ke,t=fetch){let n=Le.get(e);if(!n)n=t(e+"parts.json").then((r)=>{if(!r.ok)throw Error(`ldr: parts CDN index ${r.status} (${e}parts.json)`);return r.json()}),n.catch(()=>Le.delete(e)),Le.set(e,n);return n}var An=(e)=>Array.isArray(e)&&e.length===3&&typeof e[0]==="number"&&typeof e[1]==="number"&&(e[2]==="f32"||e[2]==="u16"||e[2]==="u8"||e[2]==="u32"),Ee=(e,t)=>An(e)?[e[0]+t,e[1],e[2]]:Array.isArray(e)?e.map((n)=>Ee(n,t)):e&&typeof e==="object"?Object.fromEntries(Object.entries(e).map(([n,r])=>[n,Ee(r,t)])):e;function vn(e,t={}){let n=[],r=0,s={},o={};for(let m of e){let g=m.buffer;if(!g)throw Error("ldr: mergePacks needs packs from decodePack/loadPack");let d=new DataView(g).getUint32(0,!0),b=new Uint8Array(g,4+d),C=r;n.push(b),r+=b.byteLength;let A=(4-r%4)%4;if(A)n.push(new Uint8Array(A)),r+=A;for(let[p,h]of Object.entries(m.header.parts??{}))if(!(p in s))s[p]=Ee(h,C);for(let[p,h]of Object.entries(m.header.studKinds??{}))if(!(p in o))o[p]=Ee(h,C)}let i=e[0]?.header??{version:1,weld:!0},c=new TextEncoder().encode(JSON.stringify({...i,parts:s,studKinds:o,...t})),u=(4-(4+c.length)%4)%4,f=4+c.length+u,a=new Uint8Array(f+r);new DataView(a.buffer).setUint32(0,c.length+u,!0),a.set(c,4),a.fill(32,4+c.length,f);let l=f;for(let m of n)a.set(m,l),l+=m.byteLength;return ve(a.buffer)}async function Cn(e,t={}){e=[...e];try{return await kt(e,t)}catch(n){let r=t.cdn??ke,s=t.fetch??fetch;Le.delete(r);let o=(i,c)=>s(i,{...c,cache:"reload"});try{return await kt(e,{...t,fetch:o})}catch{throw n}}}async function kt(e,t){let n=t.cdn??ke,r=t.fetch??fetch,s=t.gap??16384,o=await Se(n,r),i=[...new Set([...e].map(ne))],c=[],u=[];for(let p of i){if(Te.has(n+p))continue;let h=o.parts[p];if(h)u.push({name:p,off:h[0],len:h[1],file:h[2]??0});else c.push(p)}u.sort((p,h)=>p.file-h.file||p.off-h.off);let f=[];for(let p of u){let h=f[f.length-1];if(h&&h.file===p.file&&p.off-h.end<=s)h.end=Math.max(h.end,p.off+p.len),h.items.push(p);else f.push({file:p.file,start:p.off,end:p.off+p.len,items:[p]})}let a=0,l=0,m=0,g=new Map,d=async()=>{while(m<f.length){let p=f[m++],h=g.get(p.file);if(h)h=h.subarray(p.start,p.end);else{let M=await r(new URL(o.archives[p.file],n).href,{headers:{Range:`bytes=${p.start}-${p.end-1}`,"Accept-Encoding":"identity"}});if(!M.ok)throw Error(`ldr: parts CDN ${M.status}`);if(l++,h=new Uint8Array(await M.arrayBuffer()),a+=h.byteLength,M.status===200)g.set(p.file,h),h=h.subarray(p.start,p.end)}for(let M of p.items){let D=Ae(h.subarray(M.off-p.start,M.off-p.start+M.len)),v=D.buffer.slice(D.byteOffset,D.byteOffset+D.byteLength);Te.set(n+M.name,ve(v))}}};await Promise.all(Array.from({length:Math.min(t.concurrency??24,f.length)},d));let b=i.filter((p)=>Te.has(n+p)).map((p)=>Te.get(n+p)),C={colors:o.colors,...o.colorTable?{colorTable:o.colorTable}:{}};return{pack:b.length?vn(b,C):ve(Tn(C)),missing:c,requests:l,bytes:a}}function Tn(e){let t=new TextEncoder().encode(JSON.stringify({version:1,weld:!0,parts:{},studKinds:{},...e})),n=(4-(4+t.length)%4)%4,r=new Uint8Array(4+t.length+n).fill(32);return new DataView(r.buffer).setUint32(0,t.length+n,!0),r.set(t,4),r.buffer}function Ln(e,t){let n=t.header.parts;if(!n)return 0;let r=0;for(let s of e){let o=n[s.part]?.body?.tris;if(o)r+=o}return r}function Pt(e,t,n){let r=0,s=0,o=!1,i=new Set;for(let c of e){let u=c.embedded?t.get(c.part):ne(c.part),f=u?n.parts[u]:void 0;if(!f)continue;if(f[3]!=null)o=!0,r+=f[3];if(!i.has(u))i.add(u),s+=f[1]}return{bodyTris:r,packBytes:s,known:o}}class Pe extends Error{code="ldr-budget";bodyTris;packBytes;maxBodyTris;maxPackBytes;constructor(e){let t=[e.maxBodyTris!=null&&e.bodyTris>e.maxBodyTris?`${e.bodyTris} triangles (limit ${e.maxBodyTris})`:"",e.maxPackBytes!=null&&e.packBytes>e.maxPackBytes?`${(e.packBytes/1e6).toFixed(1)} MB parts pack (limit ${(e.maxPackBytes/1e6).toFixed(0)} MB)`:""].filter(Boolean).join(", ");super(`ldr: model exceeds device budget: ${t}`);this.name="BudgetError",this.bodyTris=e.bodyTris,this.packBytes=e.packBytes,this.maxBodyTris=e.maxBodyTris,this.maxPackBytes=e.maxPackBytes}}async function It(e,t={}){let n=performance.now(),r=t.fetch??fetch,s=Se(t.cdn??ke,r);s.catch(()=>{});let o=t.text?e:await r(e).then(async(x)=>{if(!x.ok)throw Error(`ldr: ${x.status} fetching ${e}`);return et(await x.arrayBuffer())}),i=performance.now(),c=t.name??(t.text?"main.ldr":tt(e)),u=Tt(o,c,{looseGeometry:!1,callouts:t.callouts}),f=performance.now();t.onParsed?.(u),await s;let a=Lt(o,new Set(u.filter((x)=>x.embedded).map((x)=>x.part)),c),l=(x,w)=>t.maxBodyTris!=null&&x>t.maxBodyTris||t.maxPackBytes!=null&&w>t.maxPackBytes,m=t.maxBodyTris!=null||t.maxPackBytes!=null,g=(x)=>new Pe({...x,maxBodyTris:t.maxBodyTris,maxPackBytes:t.maxPackBytes}),d="full";if(m){let x=Pt(u,a,await s);if(l(x.known?x.bodyTris:0,x.packBytes)){if(!t.lowCdn)throw g(x);let w=await Se(t.lowCdn,r).catch(()=>null);if(!w)throw g(x);let E=Pt(u,a,w);if(l(E.known?E.bodyTris:0,E.packBytes))throw g(E);d="low"}}let b=[...u.filter((x)=>!x.embedded).map((x)=>x.part),...a.values()],C=async()=>{let x=await Cn(b,d==="low"?{...t,cdn:t.lowCdn}:t);for(let[w,E]of a){let z=x.pack.header.parts[E];if(z)x.pack.header.parts[w]=z}return{...x,packBytes:x.pack.buffer?.byteLength??x.pack.bytes??0,bodyTris:Ln(u,x.pack)}},A=await C();if(m&&l(A.bodyTris,A.packBytes)&&d==="full"&&t.lowCdn&&await Se(t.lowCdn,r).then(()=>!0,()=>!1)){d="low";let x=A;A=await C(),A.requests+=x.requests,A.bytes+=x.bytes}if(m&&l(A.bodyTris,A.packBytes))throw g(A);let{pack:p,missing:h,requests:M,bytes:D}=A,v=new Map([...a].map(([x,w])=>[w,x])),L=h.map((x)=>v.get(x)??x),R=performance.now(),T=t.cull?Ce(u,p.header,t.textures!==!1):void 0;return{insts:u,pack:p,tier:d,missing:L,requests:M,bytes:D,cull:T,timings:{fetchModel:i-n,parse:f-i,parts:R-f,...T?{cull:performance.now()-R}:{}}}}self.onmessage=async(e)=>{let{id:t,source:n,opts:r}=e.data;try{let s=await It(n,{...r,cull:!1,onParsed:(a)=>self.postMessage({id:t,insts:a})}),o=s.pack.buffer;if(self.postMessage({id:t,buffer:o,tier:s.tier,missing:s.missing,requests:s.requests,bytes:s.bytes,timings:s.timings},[o]),!r.cull)return;let i=performance.now(),c=Ce(s.insts,s.pack.header,r.textures!==!1),u=performance.now()-i,f=[];for(let a of[c.studHidden,c.studUp,c.underHidden,c.studHideStep,c.underHideStep])if(a)f.push(a.buffer);self.postMessage({id:t,cull:c,ms:u},f)}catch(s){if(s instanceof Pe||s?.code==="ldr-budget")self.postMessage({id:t,phase:"error",error:String(s?.message??s),budget:{bodyTris:s.bodyTris,packBytes:s.packBytes,maxBodyTris:s.maxBodyTris,maxPackBytes:s.maxPackBytes}});else self.postMessage({id:t,phase:"error",error:String(s?.message??s)})}};\n';
4706
4914
 
4707
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/cdn.ts
4915
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/cdn.ts
4708
4916
  var worker;
4709
4917
  var seq = 0;
4710
4918
  var pending = new Map;
@@ -4818,7 +5026,7 @@ async function loadModel(source, o = {}) {
4818
5026
  timings: { ...prep.timings, parts: t3 - t0 - prep.timings.fetchModel - prep.timings.parse, build: t4 - t3, total: t4 - t0 }
4819
5027
  });
4820
5028
  }
4821
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/node/library.ts
5029
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/node/library.ts
4822
5030
  import { existsSync, readFileSync, statSync } from "fs";
4823
5031
  import { join } from "path";
4824
5032
  var xf = (m, x, y, z) => [m[3] * x + m[4] * y + m[5] * z + m[0], m[6] * x + m[7] * y + m[8] * z + m[1], m[9] * x + m[10] * y + m[11] * z + m[2]];
@@ -5168,11 +5376,11 @@ class Library {
5168
5376
  return insts;
5169
5377
  }
5170
5378
  }
5171
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/node/build-pack.ts
5379
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/node/build-pack.ts
5172
5380
  import fs3 from "node:fs";
5173
5381
  import path3 from "node:path";
5174
5382
 
5175
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/node/resolver.ts
5383
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/node/resolver.ts
5176
5384
  import fs from "node:fs";
5177
5385
  import path from "node:path";
5178
5386
  var TOP_STUD_RE = /^(stud|studa|stud2|stud2a|stud6|stud6a|stud10|stud15|stud2s|stud2s2|stud-logo\d*|stud2-logo\d*)\.dat$/i;
@@ -5501,11 +5709,11 @@ function collectDeps(lib, refs) {
5501
5709
  return out;
5502
5710
  }
5503
5711
 
5504
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/node/compile.ts
5712
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/node/compile.ts
5505
5713
  import fs2 from "node:fs";
5506
5714
  import path2 from "node:path";
5507
5715
 
5508
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/node/lod.ts
5716
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/node/lod.ts
5509
5717
  import { MeshoptSimplifier, MeshoptEncoder } from "meshoptimizer";
5510
5718
  await Promise.all([MeshoptSimplifier.ready, MeshoptEncoder.ready]);
5511
5719
  function reorderMesh(P, N, C, I) {
@@ -5711,7 +5919,7 @@ function lodChain(P, C, I, half = false) {
5711
5919
  return out;
5712
5920
  }
5713
5921
 
5714
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/node/compile.ts
5922
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/node/compile.ts
5715
5923
  class BfcState {
5716
5924
  accum;
5717
5925
  ccw = true;
@@ -6643,7 +6851,7 @@ function encodePack(parts, studKinds, weld, extra, options = {}) {
6643
6851
  return Buffer.concat([head, ...chunks.map((c) => new Uint8Array(c.buffer, c.byteOffset, c.byteLength))]);
6644
6852
  }
6645
6853
 
6646
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/node/build-pack.ts
6854
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/node/build-pack.ts
6647
6855
  function packCompilerOpts(o) {
6648
6856
  return { studs: o.studs ?? "low", prims: o.primitives ?? "full", weld: o.weld ?? true, separateStuds: true, cond: !!o.cond, tex: !!o.textures, ...o.partWorkLimit ? { workLimit: o.partWorkLimit } : {} };
6649
6857
  }
@@ -6715,7 +6923,7 @@ function buildPack(o) {
6715
6923
  const warnings = [...lib.conflicts].map((n) => `${n}: defined differently by two models; the first definition is used`);
6716
6924
  return { data: encodePack(parts, kinds, comp.opts.weld, extra, { texture, lod: o.lod !== false, reorder: !!o.reorder }), parts: parts.size, studKinds: kinds.size, missing: [...missing], ...warnings.length ? { warnings } : {} };
6717
6925
  }
6718
- // ../../../../../../../tmp/ldr-build-LeHH0q/src/node/promote.ts
6926
+ // ../../../../../../../tmp/ldr-build-wz5be9/src/node/promote.ts
6719
6927
  var GEOM = /^\s*[2-5]\s/;
6720
6928
  var REF = /^\s*1\s/;
6721
6929
  var FILE = /^\s*0\s+FILE\s+(\S.*?)\s*$/i;
package/dist/render.d.ts CHANGED
@@ -84,6 +84,25 @@ export declare function computeCulling(insts: Inst[], H: any): {
84
84
  }[];
85
85
  underHidden: boolean[];
86
86
  };
87
+ export declare function studHole(b: any, arr?: (r: any) => any): {
88
+ r: number;
89
+ out: number;
90
+ } | null;
91
+ /** Square-stud outline (Round 67): a stud kind whose edge lines are only horizontal round loops of radius 6 about its axis (the
92
+ * plain stud: top and foot circle) gets, per loop, the 4-segment square of the square-stud level (half-width `w`) at that height,
93
+ * in place of its 8- / 16-segment circle. Its corners are as far out as the square stud's (2.49 LDU at w = 6), so it is drawn where
94
+ * the square stud is. Each segment keeps its round loop's segment length for edge LOD, so a loop is drawn at exactly the distances
95
+ * its circle was. Null for anything else (partial loops, other radii, slanted lines): those keep their round lines. */
96
+ export declare function studSquareLines(E: ArrayLike<number>, w: number, hole?: {
97
+ r: number;
98
+ w: number;
99
+ }): {
100
+ pos: Float32Array;
101
+ lens: Float32Array;
102
+ } | null;
103
+ /** Box-level outline (Round 67): the 12 edges of a body's bounding-box LOD level (`lod.ts` boxMesh: an axis-aligned box in part
104
+ * space), drawn with that level in place of the part's own edge lines. Null unless `pos` is exactly such a box's corners. */
105
+ export declare function boxLevelLines(pos: ArrayLike<number>): Float32Array | null;
87
106
  /**
88
107
  * Builds (and caches on the pack) the shared BufferGeometries `buildLdrScene` will use, in time slices of about `sliceMs` that yield
89
108
  * to the event loop, until done or `stop()` returns true. Lets the main thread do this useful work while the load worker culls.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ldr",
3
- "version": "0.33.5",
3
+ "version": "0.33.7",
4
4
  "description": "High-performance LEGO (LDraw) rendering for three.js: instanced parts packs, hidden stud/tube culling, low-detail studs, indexed edges, build steps.",
5
5
  "license": "MIT",
6
6
  "author": "Evan Bacon",