@tscircuit/cli 0.1.2410 → 0.1.2412

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.
@@ -6839,6 +6839,651 @@ var require_cjs = __commonJS(function(exports) {
6839
6839
  }
6840
6840
  });
6841
6841
 
6842
+ // node_modules/earcut/src/earcut.js
6843
+ function earcut(data, holeIndices, dim = 2) {
6844
+ const hasHoles = holeIndices && holeIndices.length;
6845
+ const outerLen = hasHoles ? holeIndices[0] * dim : data.length;
6846
+ if (steiners.size)
6847
+ steiners.clear();
6848
+ let outerNode = linkedList(data, 0, outerLen, dim, true);
6849
+ const triangles = [];
6850
+ if (!outerNode || outerNode.next === outerNode.prev)
6851
+ return triangles;
6852
+ let minX = 0, minY = 0, invSize = 0;
6853
+ if (hasHoles)
6854
+ outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
6855
+ if (data.length > 80 * dim) {
6856
+ minX = data[0];
6857
+ minY = data[1];
6858
+ let maxX = minX;
6859
+ let maxY = minY;
6860
+ for (let i = dim;i < outerLen; i += dim) {
6861
+ const x = data[i];
6862
+ const y = data[i + 1];
6863
+ if (x < minX)
6864
+ minX = x;
6865
+ if (y < minY)
6866
+ minY = y;
6867
+ if (x > maxX)
6868
+ maxX = x;
6869
+ if (y > maxY)
6870
+ maxY = y;
6871
+ }
6872
+ invSize = Math.max(maxX - minX, maxY - minY);
6873
+ invSize = invSize !== 0 ? 32767 / invSize : 0;
6874
+ }
6875
+ earcutLinked(outerNode, triangles, minX, minY, invSize);
6876
+ return triangles;
6877
+ }
6878
+ function linkedList(data, start, end, dim, clockwise) {
6879
+ let last = null;
6880
+ if (clockwise === signedArea(data, start, end, dim) > 0) {
6881
+ for (let i = start;i < end; i += dim)
6882
+ last = insertNode(i / dim | 0, data[i], data[i + 1], last);
6883
+ } else {
6884
+ for (let i = end - dim;i >= start; i -= dim)
6885
+ last = insertNode(i / dim | 0, data[i], data[i + 1], last);
6886
+ }
6887
+ if (last && equals(last, last.next)) {
6888
+ removeNode(last);
6889
+ last = last.next;
6890
+ }
6891
+ return last;
6892
+ }
6893
+ function filterPoints(start, end = start) {
6894
+ const full = end === start;
6895
+ let p = start, again;
6896
+ do {
6897
+ again = false;
6898
+ if (p !== p.next && (steiners.size === 0 || !steiners.has(p)) && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) {
6899
+ if (full || p === end)
6900
+ end = p.prev;
6901
+ filteredOut = true;
6902
+ removeNode(p);
6903
+ p = p.prev;
6904
+ again = true;
6905
+ } else if (full || p !== end) {
6906
+ p = p.next;
6907
+ again = !full;
6908
+ }
6909
+ } while (again || p !== end);
6910
+ return end;
6911
+ }
6912
+ function earcutLinked(ear, triangles, minX, minY, invSize) {
6913
+ if (invSize)
6914
+ indexCurve(ear, minX, minY, invSize);
6915
+ let stop = ear, cured = false;
6916
+ while (ear.prev !== ear.next) {
6917
+ const prev = ear.prev;
6918
+ const next = ear.next;
6919
+ if (area(prev, ear, next) < 0 && (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear))) {
6920
+ triangles.push(prev.i, ear.i, next.i);
6921
+ removeNode(ear);
6922
+ ear = next;
6923
+ stop = next;
6924
+ continue;
6925
+ }
6926
+ ear = next;
6927
+ if (ear === stop) {
6928
+ filteredOut = false;
6929
+ ear = filterPoints(ear);
6930
+ if (filteredOut) {
6931
+ stop = ear;
6932
+ continue;
6933
+ }
6934
+ if (!cured) {
6935
+ ear = cureLocalIntersections(ear, triangles);
6936
+ stop = ear;
6937
+ cured = true;
6938
+ continue;
6939
+ }
6940
+ splitEarcut(ear, triangles, minX, minY, invSize);
6941
+ break;
6942
+ }
6943
+ }
6944
+ }
6945
+ function isEar(ear) {
6946
+ const a = ear.prev, b = ear, c = ear.next, ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y, x0 = Math.min(ax, bx, cx), y0 = Math.min(ay, by, cy), x1 = Math.max(ax, bx, cx), y1 = Math.max(ay, by, cy);
6947
+ let p = c.next;
6948
+ while (p !== a) {
6949
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && !(ax === p.x && ay === p.y) && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0)
6950
+ return false;
6951
+ p = p.next;
6952
+ }
6953
+ return true;
6954
+ }
6955
+ function isEarHashed(ear, minX, minY, invSize) {
6956
+ const a = ear.prev, b = ear, c = ear.next, ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y, x0 = Math.min(ax, bx, cx), y0 = Math.min(ay, by, cy), x1 = Math.max(ax, bx, cx), y1 = Math.max(ay, by, cy), minZ = zOrder(x0, y0, minX, minY, invSize), maxZ = zOrder(x1, y1, minX, minY, invSize);
6957
+ let p = ear.prevZ;
6958
+ while (p && p.z >= minZ) {
6959
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== c && !(ax === p.x && ay === p.y) && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0)
6960
+ return false;
6961
+ p = p.prevZ;
6962
+ }
6963
+ let n = ear.nextZ;
6964
+ while (n && n.z <= maxZ) {
6965
+ if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== c && !(ax === n.x && ay === n.y) && pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0)
6966
+ return false;
6967
+ n = n.nextZ;
6968
+ }
6969
+ return true;
6970
+ }
6971
+ function cureLocalIntersections(start, triangles) {
6972
+ let p = start;
6973
+ let cured = false;
6974
+ do {
6975
+ const a = p.prev, b = p.next.next;
6976
+ if (intersects(a, p, p.next, b, false) && locallyInside(a, b) && locallyInside(b, a)) {
6977
+ triangles.push(a.i, p.i, b.i);
6978
+ removeNode(p);
6979
+ removeNode(p.next);
6980
+ p = start = b;
6981
+ cured = true;
6982
+ }
6983
+ p = p.next;
6984
+ } while (p !== start);
6985
+ return cured ? filterPoints(p) : p;
6986
+ }
6987
+ function splitEarcut(start, triangles, minX, minY, invSize) {
6988
+ let a = start;
6989
+ do {
6990
+ let b = a.next.next;
6991
+ while (b !== a.prev) {
6992
+ if (a.i !== b.i && isValidDiagonal(a, b)) {
6993
+ let c = splitPolygon(a, b);
6994
+ a = filterPoints(a, a.next);
6995
+ c = filterPoints(c, c.next);
6996
+ earcutLinked(a, triangles, minX, minY, invSize);
6997
+ earcutLinked(c, triangles, minX, minY, invSize);
6998
+ return;
6999
+ }
7000
+ b = b.next;
7001
+ }
7002
+ a = a.next;
7003
+ } while (a !== start);
7004
+ }
7005
+ function eliminateHoles(data, holeIndices, outerNode, dim) {
7006
+ const queue = [];
7007
+ for (let i = 0, len = holeIndices.length;i < len; i++) {
7008
+ const start = holeIndices[i] * dim;
7009
+ const end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
7010
+ const list = linkedList(data, start, end, dim, false);
7011
+ if (list === list.next)
7012
+ steiners.add(list);
7013
+ queue.push(getLeftmost(list));
7014
+ }
7015
+ queue.sort(compareXYSlope);
7016
+ buildBlockIndex(data.length / dim, holeIndices.length);
7017
+ indexSegment(outerNode, outerNode);
7018
+ indexActive = true;
7019
+ for (let i = 0;i < queue.length; i++) {
7020
+ outerNode = eliminateHole(queue[i], outerNode);
7021
+ }
7022
+ indexActive = false;
7023
+ return filterPoints(outerNode);
7024
+ }
7025
+ function compareXYSlope(a, b) {
7026
+ return a.x - b.x || a.y - b.y || (a.next.y - a.y) / (a.next.x - a.x) - (b.next.y - b.y) / (b.next.x - b.x);
7027
+ }
7028
+ function eliminateHole(hole, outerNode) {
7029
+ const bridge = findHoleBridge(hole, outerNode);
7030
+ if (!bridge) {
7031
+ return outerNode;
7032
+ }
7033
+ const bridgeReverse = splitPolygon(bridge, hole);
7034
+ const bridge2 = bridgeReverse.next;
7035
+ indexSegment(bridge, bridge2.next);
7036
+ filterPoints(bridgeReverse, bridgeReverse.next);
7037
+ return filterPoints(bridge, bridge.next);
7038
+ }
7039
+ function buildBlockIndex(maxNodes, numHoles) {
7040
+ const maxBlocks = Math.ceil((maxNodes + 2 * numHoles) / K) + numHoles + 2;
7041
+ if (blockBBox.length < maxBlocks * 4)
7042
+ blockBBox = new Float64Array(maxBlocks * 4);
7043
+ numBlocks = 0;
7044
+ }
7045
+ function indexSegment(head, stop) {
7046
+ let p = head;
7047
+ do {
7048
+ const b = numBlocks++;
7049
+ blockHead[b] = p;
7050
+ let minX = p.x, minY = p.y, maxX = p.x, maxY = p.y;
7051
+ let k = 0;
7052
+ do {
7053
+ const c = p.next;
7054
+ p.z = b;
7055
+ if (c.x < minX)
7056
+ minX = c.x;
7057
+ if (c.x > maxX)
7058
+ maxX = c.x;
7059
+ if (c.y < minY)
7060
+ minY = c.y;
7061
+ if (c.y > maxY)
7062
+ maxY = c.y;
7063
+ p = c;
7064
+ } while (++k < K && p !== stop);
7065
+ blockStop[b] = p;
7066
+ const g = b * 4;
7067
+ blockBBox[g] = minX;
7068
+ blockBBox[g + 1] = minY;
7069
+ blockBBox[g + 2] = maxX;
7070
+ blockBBox[g + 3] = maxY;
7071
+ } while (p !== stop);
7072
+ }
7073
+ function growBlock(head, tail) {
7074
+ const g = head.z * 4;
7075
+ if (tail.x < blockBBox[g])
7076
+ blockBBox[g] = tail.x;
7077
+ if (tail.y < blockBBox[g + 1])
7078
+ blockBBox[g + 1] = tail.y;
7079
+ if (tail.x > blockBBox[g + 2])
7080
+ blockBBox[g + 2] = tail.x;
7081
+ if (tail.y > blockBBox[g + 3])
7082
+ blockBBox[g + 3] = tail.y;
7083
+ }
7084
+ function liveBlockStop(b) {
7085
+ let stop = blockStop[b];
7086
+ while (stop.prev.next !== stop)
7087
+ stop = stop.next;
7088
+ blockStop[b] = stop;
7089
+ return stop;
7090
+ }
7091
+ function liveBlockHead(b) {
7092
+ let head = blockHead[b];
7093
+ while (head.prev.next !== head)
7094
+ head = head.next;
7095
+ blockHead[b] = head;
7096
+ return head;
7097
+ }
7098
+ function findHoleBridge(hole, outerNode) {
7099
+ let p = outerNode;
7100
+ const hx = hole.x;
7101
+ const hy = hole.y;
7102
+ let qx = -Infinity;
7103
+ let m;
7104
+ if (equals(hole, p))
7105
+ return p;
7106
+ for (let b = 0, g = 0;b < numBlocks; b++, g += 4) {
7107
+ if (hy < blockBBox[g + 1] || hy > blockBBox[g + 3] || blockBBox[g] > hx || blockBBox[g + 2] <= qx)
7108
+ continue;
7109
+ const stop = liveBlockStop(b);
7110
+ p = liveBlockHead(b);
7111
+ do {
7112
+ if (p.prev.next === p) {
7113
+ if (equals(hole, p.next))
7114
+ return p.next;
7115
+ else if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
7116
+ const x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
7117
+ if (x <= hx && x > qx) {
7118
+ qx = x;
7119
+ m = p.x < p.next.x ? p : p.next;
7120
+ if (x === hx)
7121
+ return m;
7122
+ }
7123
+ }
7124
+ }
7125
+ p = p.next;
7126
+ } while (p !== stop);
7127
+ }
7128
+ if (!m)
7129
+ return null;
7130
+ const mx = m.x;
7131
+ const my = m.y;
7132
+ const tminY = Math.min(hy, my);
7133
+ const tmaxY = Math.max(hy, my);
7134
+ let tanMin = Infinity;
7135
+ for (let b = 0, g = 0;b < numBlocks; b++, g += 4) {
7136
+ if (blockBBox[g + 2] < mx || blockBBox[g] > hx || blockBBox[g + 3] < tminY || blockBBox[g + 1] > tmaxY)
7137
+ continue;
7138
+ const stop = liveBlockStop(b);
7139
+ p = liveBlockHead(b);
7140
+ do {
7141
+ if (p.prev.next === p && hx >= p.x && p.x >= mx && hx !== p.x && pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
7142
+ const tan = Math.abs(hy - p.y) / (hx - p.x);
7143
+ if ((locallyInside(p, hole) || p.y === hy && p.next.y === hy && p.next.x > hx) && (tan < tanMin || tan === tanMin && (p.x > m.x || p.x === m.x && sectorContainsSector(m, p)))) {
7144
+ m = p;
7145
+ tanMin = tan;
7146
+ }
7147
+ }
7148
+ p = p.next;
7149
+ } while (p !== stop);
7150
+ }
7151
+ return m;
7152
+ }
7153
+ function sectorContainsSector(m, p) {
7154
+ return area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0;
7155
+ }
7156
+ function indexCurve(start, minX, minY, invSize) {
7157
+ let p = start;
7158
+ let n = 0;
7159
+ do {
7160
+ p.z = zOrder(p.x, p.y, minX, minY, invSize);
7161
+ sortArr[n++] = p;
7162
+ p = p.next;
7163
+ } while (p !== start);
7164
+ sortNodes(n);
7165
+ let prev = null;
7166
+ for (let i = 0;i < n; i++) {
7167
+ const node = sortArr[i];
7168
+ node.prevZ = prev;
7169
+ if (prev)
7170
+ prev.nextZ = node;
7171
+ prev = node;
7172
+ }
7173
+ prev.nextZ = null;
7174
+ sortArr.fill(null, 0, n);
7175
+ sortBuf.fill(null, 0, n);
7176
+ }
7177
+ function sortNodes(n) {
7178
+ if (n <= 32) {
7179
+ for (let i = 1;i < n; i++) {
7180
+ const node = sortArr[i], z = node.z;
7181
+ let j = i - 1;
7182
+ while (j >= 0 && sortArr[j].z > z) {
7183
+ sortArr[j + 1] = sortArr[j];
7184
+ j--;
7185
+ }
7186
+ sortArr[j + 1] = node;
7187
+ }
7188
+ return;
7189
+ }
7190
+ if (zArr.length < n) {
7191
+ zArr = new Uint32Array(n);
7192
+ zBuf = new Uint32Array(n);
7193
+ sortBuf = new Array(n);
7194
+ }
7195
+ for (let i = 0;i < n; i++)
7196
+ zArr[i] = sortArr[i].z;
7197
+ radixPass(n, sortArr, zArr, sortBuf, zBuf, 0);
7198
+ radixPass(n, sortBuf, zBuf, sortArr, zArr, 8);
7199
+ radixPass(n, sortArr, zArr, sortBuf, zBuf, 16);
7200
+ radixPass(n, sortBuf, zBuf, sortArr, zArr, 24);
7201
+ }
7202
+ function radixPass(n, src, srcZ, dst, dstZ, shift) {
7203
+ counts.fill(0);
7204
+ for (let i = 0;i < n; i++)
7205
+ counts[srcZ[i] >>> shift & 255]++;
7206
+ let sum = 0;
7207
+ for (let b = 0;b < 256; b++) {
7208
+ const c = counts[b];
7209
+ counts[b] = sum;
7210
+ sum += c;
7211
+ }
7212
+ for (let i = 0;i < n; i++) {
7213
+ const z = srcZ[i];
7214
+ const pos = counts[z >>> shift & 255]++;
7215
+ dst[pos] = src[i];
7216
+ dstZ[pos] = z;
7217
+ }
7218
+ }
7219
+ function zOrder(x, y, minX, minY, invSize) {
7220
+ x = (x - minX) * invSize | 0;
7221
+ y = (y - minY) * invSize | 0;
7222
+ x = (x | x << 8) & 16711935;
7223
+ x = (x | x << 4) & 252645135;
7224
+ x = (x | x << 2) & 858993459;
7225
+ x = (x | x << 1) & 1431655765;
7226
+ y = (y | y << 8) & 16711935;
7227
+ y = (y | y << 4) & 252645135;
7228
+ y = (y | y << 2) & 858993459;
7229
+ y = (y | y << 1) & 1431655765;
7230
+ return x | y << 1;
7231
+ }
7232
+ function getLeftmost(start) {
7233
+ let p = start, leftmost = start;
7234
+ do {
7235
+ if (p.x < leftmost.x || p.x === leftmost.x && p.y < leftmost.y)
7236
+ leftmost = p;
7237
+ p = p.next;
7238
+ } while (p !== start);
7239
+ return leftmost;
7240
+ }
7241
+ function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
7242
+ return (cx - px) * (ay - py) >= (ax - px) * (cy - py) && (ax - px) * (by - py) >= (bx - px) * (ay - py) && (bx - px) * (cy - py) >= (cx - px) * (by - py);
7243
+ }
7244
+ function isValidDiagonal(a, b) {
7245
+ const zeroLength = equals(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0;
7246
+ return a.next.i !== b.i && (zeroLength || locallyInside(a, b) && locallyInside(b, a) && (area(a.prev, a, b.prev) !== 0 || area(a, b.prev, b) !== 0)) && !intersectsPolygon(a, b) && (zeroLength || middleInside(a, b));
7247
+ }
7248
+ function area(p, q, r) {
7249
+ return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
7250
+ }
7251
+ function equals(p1, p2) {
7252
+ return p1.x === p2.x && p1.y === p2.y;
7253
+ }
7254
+ function intersects(p1, q1, p2, q2, includeBoundary = true) {
7255
+ const o1 = area(p1, q1, p2);
7256
+ const o2 = area(p1, q1, q2);
7257
+ const o3 = area(p2, q2, p1);
7258
+ const o4 = area(p2, q2, q1);
7259
+ if ((o1 > 0 && o2 < 0 || o1 < 0 && o2 > 0) && (o3 > 0 && o4 < 0 || o3 < 0 && o4 > 0))
7260
+ return true;
7261
+ if (!includeBoundary)
7262
+ return false;
7263
+ if (o1 === 0 && onSegment(p1, p2, q1))
7264
+ return true;
7265
+ if (o2 === 0 && onSegment(p1, q2, q1))
7266
+ return true;
7267
+ if (o3 === 0 && onSegment(p2, p1, q2))
7268
+ return true;
7269
+ if (o4 === 0 && onSegment(p2, q1, q2))
7270
+ return true;
7271
+ return false;
7272
+ }
7273
+ function onSegment(p, q, r) {
7274
+ return q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y);
7275
+ }
7276
+ function intersectsPolygon(a, b) {
7277
+ const minX = Math.min(a.x, b.x);
7278
+ const maxX = Math.max(a.x, b.x);
7279
+ const minY = Math.min(a.y, b.y);
7280
+ const maxY = Math.max(a.y, b.y);
7281
+ let p = a;
7282
+ do {
7283
+ const n = p.next;
7284
+ if (p.x > maxX && n.x > maxX || p.x < minX && n.x < minX || p.y > maxY && n.y > maxY || p.y < minY && n.y < minY) {
7285
+ p = n;
7286
+ continue;
7287
+ }
7288
+ if (p.i !== a.i && n.i !== a.i && p.i !== b.i && n.i !== b.i && intersects(p, n, a, b))
7289
+ return true;
7290
+ p = n;
7291
+ } while (p !== a);
7292
+ return false;
7293
+ }
7294
+ function locallyInside(a, b) {
7295
+ return area(a.prev, a, a.next) < 0 ? area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 : area(a, b, a.prev) < 0 || area(a, a.next, b) < 0;
7296
+ }
7297
+ function middleInside(a, b) {
7298
+ let p = a;
7299
+ let inside = false;
7300
+ const px = (a.x + b.x) / 2;
7301
+ const py = (a.y + b.y) / 2;
7302
+ do {
7303
+ const n = p.next;
7304
+ if (p.y > py !== n.y > py && px < (n.x - p.x) * (py - p.y) / (n.y - p.y) + p.x)
7305
+ inside = !inside;
7306
+ p = n;
7307
+ } while (p !== a);
7308
+ return inside;
7309
+ }
7310
+ function splitPolygon(a, b) {
7311
+ const a2 = createNode(a.i, a.x, a.y), b2 = createNode(b.i, b.x, b.y), an = a.next, bp = b.prev;
7312
+ a.next = b;
7313
+ b.prev = a;
7314
+ a2.next = an;
7315
+ an.prev = a2;
7316
+ b2.next = a2;
7317
+ a2.prev = b2;
7318
+ bp.next = b2;
7319
+ b2.prev = bp;
7320
+ return b2;
7321
+ }
7322
+ function insertNode(i, x, y, last) {
7323
+ const p = createNode(i, x, y);
7324
+ if (!last) {
7325
+ p.prev = p;
7326
+ p.next = p;
7327
+ } else {
7328
+ p.next = last.next;
7329
+ p.prev = last;
7330
+ last.next.prev = p;
7331
+ last.next = p;
7332
+ }
7333
+ return p;
7334
+ }
7335
+ function removeNode(p) {
7336
+ p.next.prev = p.prev;
7337
+ p.prev.next = p.next;
7338
+ if (p.prevZ)
7339
+ p.prevZ.nextZ = p.nextZ;
7340
+ if (p.nextZ)
7341
+ p.nextZ.prevZ = p.prevZ;
7342
+ if (indexActive)
7343
+ growBlock(p.prev, p.next);
7344
+ }
7345
+ function createNode(i, x, y) {
7346
+ return {
7347
+ i,
7348
+ x,
7349
+ y,
7350
+ prev: null,
7351
+ next: null,
7352
+ z: 0,
7353
+ prevZ: null,
7354
+ nextZ: null
7355
+ };
7356
+ }
7357
+ function signedArea(data, start, end, dim) {
7358
+ let sum = 0;
7359
+ for (let i = start, j = end - dim;i < end; i += dim) {
7360
+ sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
7361
+ j = i;
7362
+ }
7363
+ return sum;
7364
+ }
7365
+ function refine(triangles, coords, dim = 2) {
7366
+ const t = triangles;
7367
+ const n = t.length;
7368
+ if (n < 6)
7369
+ return;
7370
+ ensureScratch(n);
7371
+ gen++;
7372
+ he.fill(-1, 0, n);
7373
+ let i = 0;
7374
+ for (let e = 0;e < n; e++) {
7375
+ const a = t[e], b = t[nextHE(e)];
7376
+ const lo = a < b ? a : b, hi = a < b ? b : a;
7377
+ let h = (Math.imul(lo, 2654435761) ^ Math.imul(hi, 2246822507)) & hMask;
7378
+ while (hStamp[h] === gen) {
7379
+ const s = hTable[h];
7380
+ if (s !== -1) {
7381
+ const sa = t[s], sb = t[nextHE(s)];
7382
+ if (sa === lo && sb === hi || sa === hi && sb === lo) {
7383
+ he[e] = s;
7384
+ he[s] = e;
7385
+ hTable[h] = -1;
7386
+ edgeStamp[s] = 1;
7387
+ edgeStack[i++] = s;
7388
+ break;
7389
+ }
7390
+ }
7391
+ h = h + 1 & hMask;
7392
+ }
7393
+ if (hStamp[h] !== gen) {
7394
+ hTable[h] = e;
7395
+ hStamp[h] = gen;
7396
+ }
7397
+ }
7398
+ while (i > 0) {
7399
+ const a = edgeStack[--i];
7400
+ edgeStamp[a] = 0;
7401
+ const b = he[a];
7402
+ if (b === -1)
7403
+ continue;
7404
+ const a0 = a - a % 3;
7405
+ const b0 = b - b % 3;
7406
+ const ar = a0 + (a + 2) % 3;
7407
+ const al = a0 + (a + 1) % 3;
7408
+ const bl = b0 + (b + 2) % 3;
7409
+ const br = b0 + (b + 1) % 3;
7410
+ const p0 = t[ar], pr = t[a], pl = t[al], p1 = t[bl];
7411
+ const x0 = coords[p0 * dim], y0 = coords[p0 * dim + 1];
7412
+ const xr = coords[pr * dim], yr = coords[pr * dim + 1];
7413
+ const xl = coords[pl * dim], yl = coords[pl * dim + 1];
7414
+ const x1 = coords[p1 * dim], y1 = coords[p1 * dim + 1];
7415
+ if (!inCircle(x0, y0, xr, yr, xl, yl, x1, y1) && orient(x0, y0, xr, yr, x1, y1) > 0 && orient(x0, y0, x1, y1, xl, yl) > 0) {
7416
+ t[a] = p1;
7417
+ t[b] = p0;
7418
+ const hbl = he[bl], har = he[ar];
7419
+ he[a] = hbl;
7420
+ if (hbl !== -1)
7421
+ he[hbl] = a;
7422
+ he[b] = har;
7423
+ if (har !== -1)
7424
+ he[har] = b;
7425
+ he[ar] = bl;
7426
+ he[bl] = ar;
7427
+ if (hbl !== -1 && edgeStamp[a] === 0) {
7428
+ edgeStamp[a] = 1;
7429
+ edgeStack[i++] = a;
7430
+ }
7431
+ if (har !== -1 && edgeStamp[b] === 0) {
7432
+ edgeStamp[b] = 1;
7433
+ edgeStack[i++] = b;
7434
+ }
7435
+ if (he[al] !== -1 && edgeStamp[al] === 0) {
7436
+ edgeStamp[al] = 1;
7437
+ edgeStack[i++] = al;
7438
+ }
7439
+ if (he[br] !== -1 && edgeStamp[br] === 0) {
7440
+ edgeStamp[br] = 1;
7441
+ edgeStack[i++] = br;
7442
+ }
7443
+ }
7444
+ }
7445
+ }
7446
+ function orient(ax, ay, bx, by, cx, cy) {
7447
+ return (bx - ax) * (cy - ay) - (by - ay) * (cx - ax);
7448
+ }
7449
+ function inCircle(ax, ay, bx, by, cx, cy, px, py) {
7450
+ const dx = ax - px, dy = ay - py, ex = bx - px, ey = by - py, fx = cx - px, fy = cy - py;
7451
+ const ap = dx * dx + dy * dy, bp = ex * ex + ey * ey, cp = fx * fx + fy * fy;
7452
+ const s = ap + bp + cp;
7453
+ return dx * (ey * cp - bp * fy) - dy * (ex * cp - bp * fx) + ap * (ex * fy - ey * fx) <= 0.0000000000001 * s * s;
7454
+ }
7455
+ function nextHE(e) {
7456
+ return e - e % 3 + (e + 1) % 3;
7457
+ }
7458
+ function ensureScratch(n) {
7459
+ if (!edgeStack || edgeStack.length < n)
7460
+ edgeStack = new Int32Array(n);
7461
+ if (!he || he.length < n)
7462
+ he = new Int32Array(n);
7463
+ if (!edgeStamp || edgeStamp.length < n)
7464
+ edgeStamp = new Uint8Array(n);
7465
+ let size = 1;
7466
+ while (size < n * 4)
7467
+ size <<= 1;
7468
+ if (!hTable || hTable.length < size) {
7469
+ hTable = new Int32Array(size);
7470
+ hStamp = new Uint32Array(size);
7471
+ }
7472
+ hMask = size - 1;
7473
+ }
7474
+ var steiners, filteredOut = false, indexActive = false, K = 16, blockBBox, numBlocks = 0, blockHead, blockStop, sortArr, sortBuf, zArr, zBuf, counts, edgeStack, he, hTable, hStamp, edgeStamp, hMask = 0, gen = 0;
7475
+ var init_earcut = __esm(() => {
7476
+ steiners = new Set;
7477
+ blockBBox = new Float64Array(0);
7478
+ blockHead = [];
7479
+ blockStop = [];
7480
+ sortArr = [];
7481
+ sortBuf = [];
7482
+ zArr = new Uint32Array(0);
7483
+ zBuf = new Uint32Array(0);
7484
+ counts = new Uint32Array(256);
7485
+ });
7486
+
6842
7487
  // node_modules/fflate/esm/index.mjs
6843
7488
  import { createRequire as createRequire3 } from "module";
6844
7489
  function deflateSync(data, opts) {
@@ -19977,6 +20622,7 @@ __export(exports_dist, {
19977
20622
  createEdgeDrawCall: () => createEdgeDrawCall,
19978
20623
  createGrid: () => createGrid,
19979
20624
  createInfiniteGrid: () => createInfiniteGrid,
20625
+ createOutlineSection: () => createOutlineSection,
19980
20626
  createSceneFromGLTF: () => createSceneFromGLTF,
19981
20627
  createUint8Bitmap: () => createUint8Bitmap,
19982
20628
  decodeImageFromBuffer: () => decodeImageFromBuffer,
@@ -19998,15 +20644,273 @@ import {
19998
20644
  glyphLineAlphabet,
19999
20645
  textMetrics
20000
20646
  } from "@tscircuit/alphabet";
20647
+ function findSectionLoops(input) {
20648
+ const { positions, axis, offset, epsilon = 0.00001 } = input;
20649
+ const k = axis === "x" ? 0 : axis === "y" ? 1 : 2;
20650
+ let minimum = Infinity, maximum = -Infinity;
20651
+ for (let i = k;i < positions.length; i += 3) {
20652
+ minimum = Math.min(minimum, positions[i]);
20653
+ maximum = Math.max(maximum, positions[i]);
20654
+ }
20655
+ if (offset <= minimum + epsilon || offset >= maximum - epsilon)
20656
+ return { loops: [], openChains: 0 };
20657
+ const u = (k + 1) % 3;
20658
+ const v = (k + 2) % 3;
20659
+ const points = /* @__PURE__ */ new Map;
20660
+ const adjacency = /* @__PURE__ */ new Map;
20661
+ const edges = /* @__PURE__ */ new Set;
20662
+ const key = (p) => `${Math.round(p[0] / epsilon)},${Math.round(p[1] / epsilon)}`;
20663
+ for (let i = 0;i < positions.length; i += 9) {
20664
+ const hits = [];
20665
+ const distances = [0, 1, 2].map((j) => positions[i + j * 3 + k] - offset);
20666
+ const onPlane = distances.filter((d) => Math.abs(d) <= epsilon).length;
20667
+ if (onPlane === 3)
20668
+ continue;
20669
+ if (!(distances.some((d) => d > epsilon) && distances.some((d) => d < -epsilon)) && !(onPlane === 2 && distances.some((d) => d < -epsilon)))
20670
+ continue;
20671
+ for (let j = 0;j < 3; j++) {
20672
+ const a2 = i + j * 3;
20673
+ const b2 = i + (j + 1) % 3 * 3;
20674
+ const da = distances[j];
20675
+ const db = distances[(j + 1) % 3];
20676
+ if (Math.abs(da) <= epsilon)
20677
+ hits.push([positions[a2 + u], positions[a2 + v]]);
20678
+ else if (da > 0 !== db > 0 && Math.abs(db) > epsilon) {
20679
+ const t = da / (da - db);
20680
+ hits.push([
20681
+ positions[a2 + u] + t * (positions[b2 + u] - positions[a2 + u]),
20682
+ positions[a2 + v] + t * (positions[b2 + v] - positions[a2 + v])
20683
+ ]);
20684
+ }
20685
+ }
20686
+ const unique = [...new Map(hits.map((p) => [key(p), p])).values()];
20687
+ if (unique.length !== 2)
20688
+ continue;
20689
+ const [a, b] = unique.map(key);
20690
+ if (a === b)
20691
+ continue;
20692
+ const edge2 = a < b ? `${a}|${b}` : `${b}|${a}`;
20693
+ if (edges.has(edge2))
20694
+ continue;
20695
+ edges.add(edge2);
20696
+ points.set(a, unique[0]);
20697
+ points.set(b, unique[1]);
20698
+ if (!adjacency.has(a))
20699
+ adjacency.set(a, /* @__PURE__ */ new Set);
20700
+ if (!adjacency.has(b))
20701
+ adjacency.set(b, /* @__PURE__ */ new Set);
20702
+ adjacency.get(a).add(b);
20703
+ adjacency.get(b).add(a);
20704
+ }
20705
+ const loops = [];
20706
+ let openChains = 0;
20707
+ while (edges.size) {
20708
+ const first = edges.values().next().value;
20709
+ const [start, next] = first.split("|");
20710
+ const path = [start];
20711
+ let previous = start;
20712
+ let current = next;
20713
+ const remove = (a, b) => {
20714
+ edges.delete(a < b ? `${a}|${b}` : `${b}|${a}`);
20715
+ adjacency.get(a)?.delete(b);
20716
+ adjacency.get(b)?.delete(a);
20717
+ };
20718
+ remove(start, next);
20719
+ while (current !== start) {
20720
+ path.push(current);
20721
+ const candidates = [...adjacency.get(current) ?? []];
20722
+ if (!candidates.length)
20723
+ break;
20724
+ const p = points.get(previous);
20725
+ const c = points.get(current);
20726
+ candidates.sort((a, b) => {
20727
+ const score = (s) => {
20728
+ const n = points.get(s);
20729
+ return ((c[0] - p[0]) * (n[0] - c[0]) + (c[1] - p[1]) * (n[1] - c[1])) / (Math.hypot(n[0] - c[0], n[1] - c[1]) || 1);
20730
+ };
20731
+ return score(b) - score(a);
20732
+ });
20733
+ const chosen = candidates[0];
20734
+ remove(current, chosen);
20735
+ previous = current;
20736
+ current = chosen;
20737
+ }
20738
+ if (current === start && path.length >= 3)
20739
+ loops.push(path.map((p) => points.get(p)));
20740
+ else
20741
+ openChains++;
20742
+ }
20743
+ return { loops, openChains };
20744
+ }
20745
+ function contains(p, polygon) {
20746
+ let inside = false;
20747
+ for (let i = 0, j = polygon.length - 1;i < polygon.length; j = i++) {
20748
+ const a = polygon[i], b = polygon[j];
20749
+ if (a[1] > p[1] !== b[1] > p[1] && p[0] < (b[0] - a[0]) * (p[1] - a[1]) / (b[1] - a[1]) + a[0])
20750
+ inside = !inside;
20751
+ }
20752
+ return inside;
20753
+ }
20754
+ function createOutlineSection(drawCalls, spec) {
20755
+ const k = spec.axis === "x" ? 0 : spec.axis === "y" ? 1 : 2;
20756
+ const u = (k + 1) % 3, v = (k + 2) % 3;
20757
+ const spacing = spec.hatchSpacing ?? 1;
20758
+ if (!["x", "y", "z"].includes(spec.axis) || !Number.isFinite(spec.offset) || !["less", "greater"].includes(spec.keepSide) || !Number.isFinite(spacing) || spacing <= 0)
20759
+ throw new Error("Invalid outline section plane or hatch spacing");
20760
+ const output = [];
20761
+ let openChains = 0;
20762
+ const texture = createUint8Bitmap(128, 128);
20763
+ for (let y = 0;y < 128; y++)
20764
+ for (let x = 0;x < 128; x++) {
20765
+ const c = (x + 127 - y) % 16 < 2 ? 0 : 255;
20766
+ texture.data.set([c, c, c, 255], (y * 128 + x) * 4);
20767
+ }
20768
+ const sign = spec.keepSide === "less" ? 1 : -1;
20769
+ for (const dc of drawCalls) {
20770
+ const points = [];
20771
+ for (let i = 0;i < dc.positions.length; i += 3)
20772
+ points.push(Array.from(import_gl_matrix.vec3.transformMat4(import_gl_matrix.vec3.create(), dc.positions.subarray(i, i + 3), dc.model)));
20773
+ const indices = dc.indices ?? Uint32Array.from(points, (_, i) => i);
20774
+ const clipped = [], triangles = [];
20775
+ const distance = (p) => sign * (p[k] - spec.offset);
20776
+ const intersection = (a, b) => {
20777
+ const t = distance(a) / (distance(a) - distance(b));
20778
+ return a.map((n, j) => n + t * (b[j] - n));
20779
+ };
20780
+ if (dc.mode === 1) {
20781
+ for (let i = 0;i + 1 < indices.length; i += 2) {
20782
+ let a = points[indices[i]], b = points[indices[i + 1]];
20783
+ if (distance(a) > 0 && distance(b) > 0)
20784
+ continue;
20785
+ if (distance(a) > 0)
20786
+ a = intersection(a, b);
20787
+ else if (distance(b) > 0)
20788
+ b = intersection(a, b);
20789
+ clipped.push(...a, ...b);
20790
+ }
20791
+ output.push({
20792
+ ...dc,
20793
+ positions: new Float32Array(clipped),
20794
+ indices: null,
20795
+ model: import_gl_matrix.mat4.create()
20796
+ });
20797
+ continue;
20798
+ }
20799
+ if (dc.mode != null && dc.mode !== 4)
20800
+ continue;
20801
+ for (let i = 0;i + 2 < indices.length; i += 3) {
20802
+ const triangle = [
20803
+ points[indices[i]],
20804
+ points[indices[i + 1]],
20805
+ points[indices[i + 2]]
20806
+ ];
20807
+ triangles.push(...triangle.flat());
20808
+ const polygon = [];
20809
+ for (let j = 0;j < 3; j++) {
20810
+ const a = triangle[j], b = triangle[(j + 1) % 3];
20811
+ if (distance(a) <= 0)
20812
+ polygon.push(a);
20813
+ if (distance(a) < 0 && distance(b) > 0 || distance(a) > 0 && distance(b) < 0)
20814
+ polygon.push(intersection(a, b));
20815
+ }
20816
+ for (let j = 1;j + 1 < polygon.length; j++)
20817
+ clipped.push(...polygon[0], ...polygon[j], ...polygon[j + 1]);
20818
+ }
20819
+ const white = {
20820
+ baseColorFactor: [1, 1, 1, 1],
20821
+ baseColorTexture: null
20822
+ };
20823
+ const mesh = {
20824
+ ...dc,
20825
+ positions: new Float32Array(clipped),
20826
+ indices: null,
20827
+ model: import_gl_matrix.mat4.create(),
20828
+ normals: null,
20829
+ colors: null,
20830
+ uvs: null,
20831
+ material: white
20832
+ };
20833
+ output.push(mesh);
20834
+ const extent = Math.max(...[0, 1, 2].map((axis) => {
20835
+ let min = Infinity, max = -Infinity;
20836
+ for (const p of points) {
20837
+ min = Math.min(min, p[axis]);
20838
+ max = Math.max(max, p[axis]);
20839
+ }
20840
+ return max - min;
20841
+ }));
20842
+ const result = findSectionLoops({
20843
+ positions: new Float32Array(triangles),
20844
+ axis: spec.axis,
20845
+ offset: spec.offset,
20846
+ epsilon: Math.max(extent * 0.0000001, 0.000000001)
20847
+ });
20848
+ openChains += result.openChains;
20849
+ const rings = result.loops.map((points2) => ({
20850
+ points: points2,
20851
+ area: Math.abs(points2.reduce((a, p, i) => {
20852
+ const q = points2[(i + 1) % points2.length];
20853
+ return a + p[0] * q[1] - q[0] * p[1];
20854
+ }, 0)),
20855
+ parent: -1,
20856
+ depth: 0
20857
+ })).sort((a, b) => b.area - a.area);
20858
+ rings.forEach((ring, i) => {
20859
+ for (let j = 0;j < i; j++)
20860
+ if (contains(ring.points[0], rings[j].points))
20861
+ ring.parent = j;
20862
+ ring.depth = ring.parent < 0 ? 0 : rings[ring.parent].depth + 1;
20863
+ });
20864
+ const cap = [], uv = [];
20865
+ rings.forEach((ring, i) => {
20866
+ if (ring.depth % 2)
20867
+ return;
20868
+ const holes = rings.filter((r) => r.parent === i && r.depth % 2);
20869
+ const flat = [...ring.points], starts = [];
20870
+ for (const hole of holes) {
20871
+ starts.push(flat.length);
20872
+ flat.push(...hole.points);
20873
+ }
20874
+ const faces = earcut(flat.flat(), starts, 2);
20875
+ for (let j = 0;j < faces.length; j += 3) {
20876
+ const ids = faces.slice(j, j + 3);
20877
+ const a = flat[ids[0]], b = flat[ids[1]], c = flat[ids[2]];
20878
+ if (((b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0])) * sign < 0)
20879
+ ids.reverse();
20880
+ for (const id of ids) {
20881
+ const p = flat[id], xyz = [0, 0, 0];
20882
+ xyz[k] = spec.offset;
20883
+ xyz[u] = p[0];
20884
+ xyz[v] = p[1];
20885
+ cap.push(...xyz);
20886
+ uv.push(p[0] / (spacing * 8 * Math.SQRT2), p[1] / (spacing * 8 * Math.SQRT2));
20887
+ }
20888
+ }
20889
+ });
20890
+ if (cap.length)
20891
+ output.push({
20892
+ ...mesh,
20893
+ outlineSectionCap: true,
20894
+ positions: new Float32Array(cap),
20895
+ uvs: new Float32Array(uv),
20896
+ material: {
20897
+ ...white,
20898
+ baseColorTexture: texture,
20899
+ baseColorTextureWrap: "repeat"
20900
+ }
20901
+ });
20902
+ }
20903
+ return { drawCalls: output, openChains };
20904
+ }
20001
20905
  function computeWorldAABB(drawCalls) {
20002
20906
  const min = [Infinity, Infinity, Infinity];
20003
20907
  const max = [-Infinity, -Infinity, -Infinity];
20004
- const tmp = import_gl_matrix2.vec4.create();
20908
+ const tmp = import_gl_matrix3.vec4.create();
20005
20909
  for (const dc of drawCalls) {
20006
20910
  const { positions, model } = dc;
20007
20911
  for (let i = 0;i < positions.length; i += 3) {
20008
- import_gl_matrix2.vec4.set(tmp, positions[i], positions[i + 1], positions[i + 2], 1);
20009
- import_gl_matrix2.vec4.transformMat4(tmp, tmp, model);
20912
+ import_gl_matrix3.vec4.set(tmp, positions[i], positions[i + 1], positions[i + 2], 1);
20913
+ import_gl_matrix3.vec4.transformMat4(tmp, tmp, model);
20010
20914
  const x = tmp[0];
20011
20915
  const y = tmp[1];
20012
20916
  const z = tmp[2];
@@ -20029,75 +20933,75 @@ function computeWorldAABB(drawCalls) {
20029
20933
  function getWorldUpVector(up) {
20030
20934
  switch (up) {
20031
20935
  case "y-":
20032
- return import_gl_matrix.vec3.fromValues(0, -1, 0);
20936
+ return import_gl_matrix2.vec3.fromValues(0, -1, 0);
20033
20937
  case "x+":
20034
- return import_gl_matrix.vec3.fromValues(1, 0, 0);
20938
+ return import_gl_matrix2.vec3.fromValues(1, 0, 0);
20035
20939
  case "x-":
20036
- return import_gl_matrix.vec3.fromValues(-1, 0, 0);
20940
+ return import_gl_matrix2.vec3.fromValues(-1, 0, 0);
20037
20941
  case "z+":
20038
- return import_gl_matrix.vec3.fromValues(0, 0, 1);
20942
+ return import_gl_matrix2.vec3.fromValues(0, 0, 1);
20039
20943
  case "z-":
20040
- return import_gl_matrix.vec3.fromValues(0, 0, -1);
20944
+ return import_gl_matrix2.vec3.fromValues(0, 0, -1);
20041
20945
  case "y+":
20042
20946
  default:
20043
- return import_gl_matrix.vec3.fromValues(0, 1, 0);
20947
+ return import_gl_matrix2.vec3.fromValues(0, 1, 0);
20044
20948
  }
20045
20949
  }
20046
20950
  function buildCameraWorldMatrix(eye, forward, up) {
20047
- const normalizedForward = import_gl_matrix.vec3.normalize(import_gl_matrix.vec3.create(), forward);
20048
- const right = import_gl_matrix.vec3.cross(import_gl_matrix.vec3.create(), normalizedForward, up);
20049
- if (import_gl_matrix.vec3.squaredLength(right) === 0) {
20951
+ const normalizedForward = import_gl_matrix2.vec3.normalize(import_gl_matrix2.vec3.create(), forward);
20952
+ const right = import_gl_matrix2.vec3.cross(import_gl_matrix2.vec3.create(), normalizedForward, up);
20953
+ if (import_gl_matrix2.vec3.squaredLength(right) === 0) {
20050
20954
  return null;
20051
20955
  }
20052
- import_gl_matrix.vec3.normalize(right, right);
20053
- const correctedUp = import_gl_matrix.vec3.cross(import_gl_matrix.vec3.create(), right, normalizedForward);
20054
- if (import_gl_matrix.vec3.squaredLength(correctedUp) === 0) {
20956
+ import_gl_matrix2.vec3.normalize(right, right);
20957
+ const correctedUp = import_gl_matrix2.vec3.cross(import_gl_matrix2.vec3.create(), right, normalizedForward);
20958
+ if (import_gl_matrix2.vec3.squaredLength(correctedUp) === 0) {
20055
20959
  return null;
20056
20960
  }
20057
- import_gl_matrix.vec3.normalize(correctedUp, correctedUp);
20058
- return import_gl_matrix.mat4.fromValues(right[0], right[1], right[2], 0, correctedUp[0], correctedUp[1], correctedUp[2], 0, -normalizedForward[0], -normalizedForward[1], -normalizedForward[2], 0, eye[0], eye[1], eye[2], 1);
20961
+ import_gl_matrix2.vec3.normalize(correctedUp, correctedUp);
20962
+ return import_gl_matrix2.mat4.fromValues(right[0], right[1], right[2], 0, correctedUp[0], correctedUp[1], correctedUp[2], 0, -normalizedForward[0], -normalizedForward[1], -normalizedForward[2], 0, eye[0], eye[1], eye[2], 1);
20059
20963
  }
20060
20964
  function getDefaultForwardForUp(up) {
20061
- const zForward = import_gl_matrix.vec3.fromValues(0, 0, -1);
20062
- if (Math.abs(import_gl_matrix.vec3.dot(up, zForward)) < 0.999) {
20965
+ const zForward = import_gl_matrix2.vec3.fromValues(0, 0, -1);
20966
+ if (Math.abs(import_gl_matrix2.vec3.dot(up, zForward)) < 0.999) {
20063
20967
  return zForward;
20064
20968
  }
20065
- return import_gl_matrix.vec3.fromValues(1, 0, 0);
20969
+ return import_gl_matrix2.vec3.fromValues(1, 0, 0);
20066
20970
  }
20067
20971
  function buildViewFromRotation(eye, up, rotation) {
20068
20972
  const cameraWorld = buildCameraWorldMatrix(eye, getDefaultForwardForUp(up), up);
20069
20973
  if (!cameraWorld) {
20070
- return import_gl_matrix.mat4.create();
20974
+ return import_gl_matrix2.mat4.create();
20071
20975
  }
20072
20976
  if (rotation.x !== 0) {
20073
- import_gl_matrix.mat4.rotateX(cameraWorld, cameraWorld, toRad(rotation.x));
20977
+ import_gl_matrix2.mat4.rotateX(cameraWorld, cameraWorld, toRad(rotation.x));
20074
20978
  }
20075
20979
  if (rotation.y !== 0) {
20076
- import_gl_matrix.mat4.rotateY(cameraWorld, cameraWorld, toRad(rotation.y));
20980
+ import_gl_matrix2.mat4.rotateY(cameraWorld, cameraWorld, toRad(rotation.y));
20077
20981
  }
20078
20982
  if (rotation.z !== 0) {
20079
- import_gl_matrix.mat4.rotateZ(cameraWorld, cameraWorld, toRad(rotation.z));
20983
+ import_gl_matrix2.mat4.rotateZ(cameraWorld, cameraWorld, toRad(rotation.z));
20080
20984
  }
20081
- const view = import_gl_matrix.mat4.create();
20082
- import_gl_matrix.mat4.invert(view, cameraWorld);
20985
+ const view = import_gl_matrix2.mat4.create();
20986
+ import_gl_matrix2.mat4.invert(view, cameraWorld);
20083
20987
  return view;
20084
20988
  }
20085
20989
  function buildViewFromLookAt(eye, center, up) {
20086
- const forward = import_gl_matrix.vec3.subtract(import_gl_matrix.vec3.create(), center, eye);
20087
- if (import_gl_matrix.vec3.squaredLength(forward) === 0) {
20088
- return import_gl_matrix.mat4.create();
20990
+ const forward = import_gl_matrix2.vec3.subtract(import_gl_matrix2.vec3.create(), center, eye);
20991
+ if (import_gl_matrix2.vec3.squaredLength(forward) === 0) {
20992
+ return import_gl_matrix2.mat4.create();
20089
20993
  }
20090
20994
  const cameraWorld = buildCameraWorldMatrix(eye, forward, up);
20091
20995
  if (!cameraWorld) {
20092
- return import_gl_matrix.mat4.create();
20996
+ return import_gl_matrix2.mat4.create();
20093
20997
  }
20094
- const view = import_gl_matrix.mat4.create();
20095
- import_gl_matrix.mat4.invert(view, cameraWorld);
20998
+ const view = import_gl_matrix2.mat4.create();
20999
+ import_gl_matrix2.mat4.invert(view, cameraWorld);
20096
21000
  return view;
20097
21001
  }
20098
21002
  function getAutoDistance(drawCalls, fovDeg) {
20099
21003
  const aabb = computeWorldAABB(drawCalls);
20100
- const diag = import_gl_matrix.vec3.distance(import_gl_matrix.vec3.fromValues(aabb.min[0], aabb.min[1], aabb.min[2]), import_gl_matrix.vec3.fromValues(aabb.max[0], aabb.max[1], aabb.max[2]));
21004
+ const diag = import_gl_matrix2.vec3.distance(import_gl_matrix2.vec3.fromValues(aabb.min[0], aabb.min[1], aabb.min[2]), import_gl_matrix2.vec3.fromValues(aabb.max[0], aabb.max[1], aabb.max[2]));
20101
21005
  const radius = diag * 0.5;
20102
21006
  const fov = toRad(fovDeg);
20103
21007
  return radius / Math.tan(fov * 0.5) + radius * 0.5;
@@ -20111,7 +21015,7 @@ function getAABBCornerDistances(aabb, eye) {
20111
21015
  for (const x of xs) {
20112
21016
  for (const y of ys) {
20113
21017
  for (const z of zs) {
20114
- const distance = import_gl_matrix.vec3.distance(eye, import_gl_matrix.vec3.fromValues(x, y, z));
21018
+ const distance = import_gl_matrix2.vec3.distance(eye, import_gl_matrix2.vec3.fromValues(x, y, z));
20115
21019
  farthest = Math.max(farthest, distance);
20116
21020
  }
20117
21021
  }
@@ -20119,40 +21023,56 @@ function getAABBCornerDistances(aabb, eye) {
20119
21023
  return { nearest, farthest };
20120
21024
  }
20121
21025
  function getCameraForwardFromView(view) {
20122
- const cameraWorld = import_gl_matrix.mat4.create();
20123
- import_gl_matrix.mat4.invert(cameraWorld, view);
20124
- return import_gl_matrix.vec3.fromValues(-cameraWorld[8], -cameraWorld[9], -cameraWorld[10]);
21026
+ const cameraWorld = import_gl_matrix2.mat4.create();
21027
+ import_gl_matrix2.mat4.invert(cameraWorld, view);
21028
+ return import_gl_matrix2.vec3.fromValues(-cameraWorld[8], -cameraWorld[9], -cameraWorld[10]);
20125
21029
  }
20126
- function buildCamera(drawCalls, width, height, fovDeg, camPos, lookAt, up = "y+", cameraRotation = null) {
21030
+ function buildCamera(drawCalls, width, height, fovDeg, camPos, lookAt, up = "y+", cameraRotation = null, projection = "perspective", orthographicHeight = null) {
20127
21031
  const aspect = width / height;
20128
21032
  const worldUp = getWorldUpVector(up);
20129
21033
  const aabb = computeWorldAABB(drawCalls);
20130
- const center = import_gl_matrix.vec3.fromValues(0.5 * (aabb.min[0] + aabb.max[0]), 0.5 * (aabb.min[1] + aabb.max[1]), 0.5 * (aabb.min[2] + aabb.max[2]));
21034
+ const center = import_gl_matrix2.vec3.fromValues(0.5 * (aabb.min[0] + aabb.max[0]), 0.5 * (aabb.min[1] + aabb.max[1]), 0.5 * (aabb.min[2] + aabb.max[2]));
20131
21035
  const autoDistance = getAutoDistance(drawCalls, fovDeg);
20132
21036
  if (cameraRotation) {
20133
- const provisionalEye = camPos ? import_gl_matrix.vec3.fromValues(camPos[0], camPos[1], camPos[2]) : import_gl_matrix.vec3.clone(center);
21037
+ const provisionalEye = camPos ? import_gl_matrix2.vec3.fromValues(camPos[0], camPos[1], camPos[2]) : import_gl_matrix2.vec3.clone(center);
20134
21038
  const provisionalView = buildViewFromRotation(provisionalEye, worldUp, cameraRotation);
20135
- const eye2 = camPos ? provisionalEye : import_gl_matrix.vec3.scaleAndAdd(import_gl_matrix.vec3.create(), center, getCameraForwardFromView(provisionalView), -autoDistance);
21039
+ const eye2 = camPos ? provisionalEye : import_gl_matrix2.vec3.scaleAndAdd(import_gl_matrix2.vec3.create(), center, getCameraForwardFromView(provisionalView), -autoDistance);
20136
21040
  const { nearest: nearest2, farthest: farthest2 } = getAABBCornerDistances(aabb, eye2);
20137
21041
  const near2 = Math.max(0.01, nearest2 * 0.5);
20138
21042
  const far2 = Math.max(1000, farthest2 * 1.1);
20139
- const proj2 = import_gl_matrix.mat4.create();
20140
- import_gl_matrix.mat4.perspective(proj2, toRad(fovDeg), aspect, near2, far2);
21043
+ const proj2 = import_gl_matrix2.mat4.create();
21044
+ const view2 = buildViewFromRotation(eye2, worldUp, cameraRotation);
21045
+ setProjection(proj2, view2, aabb, projection, orthographicHeight, fovDeg, aspect, near2, far2);
20141
21046
  return {
20142
- view: buildViewFromRotation(eye2, worldUp, cameraRotation),
21047
+ view: view2,
20143
21048
  proj: proj2
20144
21049
  };
20145
21050
  }
20146
- const eye = camPos ? import_gl_matrix.vec3.fromValues(camPos[0], camPos[1], camPos[2]) : import_gl_matrix.vec3.fromValues(center[0] + autoDistance, center[1] + autoDistance * 0.3, center[2] + autoDistance);
20147
- const target = lookAt ? import_gl_matrix.vec3.fromValues(lookAt[0], lookAt[1], lookAt[2]) : center;
21051
+ const eye = camPos ? import_gl_matrix2.vec3.fromValues(camPos[0], camPos[1], camPos[2]) : import_gl_matrix2.vec3.fromValues(center[0] + autoDistance, center[1] + autoDistance * 0.3, center[2] + autoDistance);
21052
+ const target = lookAt ? import_gl_matrix2.vec3.fromValues(lookAt[0], lookAt[1], lookAt[2]) : center;
20148
21053
  const { nearest, farthest } = getAABBCornerDistances(aabb, eye);
20149
21054
  const near = Math.max(0.01, nearest * 0.5);
20150
21055
  const far = Math.max(1000, farthest * 1.1);
20151
- const proj = import_gl_matrix.mat4.create();
20152
- import_gl_matrix.mat4.perspective(proj, toRad(fovDeg), aspect, near, far);
21056
+ const proj = import_gl_matrix2.mat4.create();
20153
21057
  const view = buildViewFromLookAt(eye, target, worldUp);
21058
+ setProjection(proj, view, aabb, projection, orthographicHeight, fovDeg, aspect, near, far);
20154
21059
  return { view, proj };
20155
21060
  }
21061
+ function setProjection(proj, view, aabb, projection, height, fov, aspect, near, far) {
21062
+ if (projection === "perspective") {
21063
+ import_gl_matrix2.mat4.perspective(proj, toRad(fov), aspect, near, far);
21064
+ return;
21065
+ }
21066
+ let halfHeight = 0;
21067
+ for (const x of [aabb.min[0], aabb.max[0]])
21068
+ for (const y of [aabb.min[1], aabb.max[1]])
21069
+ for (const z of [aabb.min[2], aabb.max[2]]) {
21070
+ const p = import_gl_matrix2.vec3.transformMat4(import_gl_matrix2.vec3.create(), [x, y, z], view);
21071
+ halfHeight = Math.max(halfHeight, Math.abs(p[1]), Math.abs(p[0]) / aspect);
21072
+ }
21073
+ halfHeight = height != null && Number.isFinite(height) && height > 0 ? height / 2 : Math.max(halfHeight * 1.1, 0.001);
21074
+ import_gl_matrix2.mat4.ortho(proj, -halfHeight * aspect, halfHeight * aspect, -halfHeight, halfHeight, near, far);
21075
+ }
20156
21076
  function createGrid(options = {}) {
20157
21077
  const size = options.size ?? 10;
20158
21078
  const sizeX = typeof size === "number" ? size : size[0];
@@ -20177,8 +21097,8 @@ function createGrid(options = {}) {
20177
21097
  positions.push(halfSizeX, 0, pZ);
20178
21098
  indices.push(vertexIndex++, vertexIndex++);
20179
21099
  }
20180
- const model = import_gl_matrix3.mat4.create();
20181
- import_gl_matrix3.mat4.fromTranslation(model, [offset.x, offset.y, offset.z]);
21100
+ const model = import_gl_matrix4.mat4.create();
21101
+ import_gl_matrix4.mat4.fromTranslation(model, [offset.x, offset.y, offset.z]);
20182
21102
  return {
20183
21103
  positions: new Float32Array(positions),
20184
21104
  indices: new Uint32Array(indices),
@@ -20210,7 +21130,7 @@ function triangleNormal(positions, i0, i1, i2) {
20210
21130
  return null;
20211
21131
  return [nx / length, ny / length, nz / length];
20212
21132
  }
20213
- function addEdge(edges, positions, i0, i1, normal) {
21133
+ function addEdge(edges, positions, i0, i1, thirdVertex, normal, facing) {
20214
21134
  const key0 = positionKey(positions, i0);
20215
21135
  const key1 = positionKey(positions, i1);
20216
21136
  const isForward = key0 < key1;
@@ -20220,8 +21140,15 @@ function addEdge(edges, positions, i0, i1, normal) {
20220
21140
  if (existing) {
20221
21141
  if (normal)
20222
21142
  existing.normals.push(normal);
21143
+ existing.adjacentVertices.push(thirdVertex);
21144
+ existing.facings.push(facing);
20223
21145
  } else {
20224
- edges.set(key, { indices, normals: normal ? [normal] : [] });
21146
+ edges.set(key, {
21147
+ indices,
21148
+ normals: normal ? [normal] : [],
21149
+ adjacentVertices: [thirdVertex],
21150
+ facings: [facing]
21151
+ });
20225
21152
  }
20226
21153
  }
20227
21154
  function hasCrease(normals, minimumDot) {
@@ -20238,29 +21165,42 @@ function hasCrease(normals, minimumDot) {
20238
21165
  }
20239
21166
  return false;
20240
21167
  }
20241
- function createEdgeDrawCall(mesh, creaseAngleDegrees = DEFAULT_CREASE_ANGLE_DEGREES) {
21168
+ function createEdgeDrawCall(mesh, creaseAngleDegrees = DEFAULT_CREASE_ANGLE_DEGREES, camera) {
20242
21169
  if (mesh.mode != null && mesh.mode !== 4)
20243
21170
  return null;
20244
21171
  const vertexCount = Math.floor(mesh.positions.length / 3);
20245
21172
  const triangleIndices = mesh.indices ?? Uint32Array.from({ length: vertexCount }, (_, i) => i);
20246
21173
  if (triangleIndices.length < 3)
20247
21174
  return null;
21175
+ let normalPositions = mesh.positions;
21176
+ if (camera) {
21177
+ const modelView = import_gl_matrix5.mat4.multiply(import_gl_matrix5.mat4.create(), camera.view, mesh.model);
21178
+ normalPositions = new Float32Array(mesh.positions.length);
21179
+ for (let i = 0;i < vertexCount; i++) {
21180
+ const point = import_gl_matrix5.vec3.transformMat4(import_gl_matrix5.vec3.create(), mesh.positions.subarray(i * 3, i * 3 + 3), modelView);
21181
+ normalPositions.set(point, i * 3);
21182
+ }
21183
+ }
20248
21184
  const edges = /* @__PURE__ */ new Map;
20249
21185
  for (let i = 0;i + 2 < triangleIndices.length; i += 3) {
20250
21186
  const i0 = triangleIndices[i];
20251
21187
  const i1 = triangleIndices[i + 1];
20252
21188
  const i2 = triangleIndices[i + 2];
20253
- const normal = triangleNormal(mesh.positions, i0, i1, i2);
20254
- addEdge(edges, mesh.positions, i0, i1, normal);
20255
- addEdge(edges, mesh.positions, i1, i2, normal);
20256
- addEdge(edges, mesh.positions, i2, i0, normal);
21189
+ const normal = triangleNormal(normalPositions, i0, i1, i2);
21190
+ const facing = !normal ? 0 : camera?.projection === "perspective" ? -(normal[0] * normalPositions[i0 * 3] + normal[1] * normalPositions[i0 * 3 + 1] + normal[2] * normalPositions[i0 * 3 + 2]) : normal[2];
21191
+ addEdge(edges, mesh.positions, i0, i1, i2, normal, facing);
21192
+ addEdge(edges, mesh.positions, i1, i2, i0, normal, facing);
21193
+ addEdge(edges, mesh.positions, i2, i0, i1, normal, facing);
20257
21194
  }
20258
21195
  const minimumDot = Math.cos(creaseAngleDegrees * Math.PI / 180);
20259
21196
  const edgeIndices = [];
21197
+ const edgeAdjacentVertices = [];
20260
21198
  for (const edge2 of edges.values()) {
20261
- if (!hasCrease(edge2.normals, minimumDot))
21199
+ const silhouette = camera && edge2.facings.some((n) => n > 0.0000001) && edge2.facings.some((n) => n <= 0.0000001);
21200
+ if (!hasCrease(edge2.normals, minimumDot) && !silhouette)
20262
21201
  continue;
20263
21202
  edgeIndices.push(edge2.indices[0], edge2.indices[1]);
21203
+ edgeAdjacentVertices.push(edge2.adjacentVertices);
20264
21204
  }
20265
21205
  if (edgeIndices.length === 0)
20266
21206
  return null;
@@ -20275,7 +21215,8 @@ function createEdgeDrawCall(mesh, creaseAngleDegrees = DEFAULT_CREASE_ANGLE_DEGR
20275
21215
  baseColorTexture: null,
20276
21216
  alphaMode: "BLEND"
20277
21217
  },
20278
- mode: 1
21218
+ mode: 1,
21219
+ edgeAdjacentVertices
20279
21220
  };
20280
21221
  }
20281
21222
  function downsampleBitmap(source, targetWidth, targetHeight, imageFactory) {
@@ -20482,14 +21423,102 @@ function clipMeshToNearPlane(mesh, mvp) {
20482
21423
  indices: new Uint32Array(indices)
20483
21424
  };
20484
21425
  }
21426
+ function clipLine(start, end, marginX, marginY) {
21427
+ if (![...start, ...end].every(Number.isFinite))
21428
+ return null;
21429
+ const distances = (p) => [
21430
+ p[3] * (1 + marginX) + p[0],
21431
+ p[3] * (1 + marginX) - p[0],
21432
+ p[3] * (1 + marginY) + p[1],
21433
+ p[3] * (1 + marginY) - p[1],
21434
+ p[3] + p[2],
21435
+ p[3] - p[2]
21436
+ ];
21437
+ const a = distances(start);
21438
+ const b = distances(end);
21439
+ let from = 0;
21440
+ let to = 1;
21441
+ for (let plane = 0;plane < 6; plane++) {
21442
+ if (a[plane] < 0 && b[plane] < 0)
21443
+ return null;
21444
+ if (a[plane] < 0 !== b[plane] < 0) {
21445
+ const t = a[plane] / (a[plane] - b[plane]);
21446
+ if (a[plane] < 0)
21447
+ from = Math.max(from, t);
21448
+ else
21449
+ to = Math.min(to, t);
21450
+ }
21451
+ }
21452
+ if (from > to)
21453
+ return null;
21454
+ return [from, to].map((t) => Array.from(start, (value, axis) => value + t * (end[axis] - value)));
21455
+ }
21456
+ function rasterizeWideLine(start, end, width, height, strokeWidth, dashed, dashLength, fragment) {
21457
+ const radius = strokeWidth / 2;
21458
+ const padding = radius + 0.5;
21459
+ const clipped = clipLine(start, end, 2 * padding / Math.max(1, width - 1), 2 * padding / Math.max(1, height - 1));
21460
+ if (!clipped)
21461
+ return;
21462
+ const project = (p) => [
21463
+ (p[0] / p[3] * 0.5 + 0.5) * (width - 1),
21464
+ (0.5 - p[1] / p[3] * 0.5) * (height - 1),
21465
+ Math.max(0, Math.min(1, p[2] / p[3] * 0.5 + 0.5))
21466
+ ];
21467
+ const a = project(clipped[0]);
21468
+ const b = project(clipped[1]);
21469
+ if (![...a, ...b].every(Number.isFinite))
21470
+ return;
21471
+ const [x0, y0, z0] = a;
21472
+ const [x1, y1, z1] = b;
21473
+ const dx = x1 - x0;
21474
+ const dy = y1 - y0;
21475
+ const lengthSquared = dx * dx + dy * dy;
21476
+ const length = Math.sqrt(lengthSquared);
21477
+ const original = start[3] > 0 ? project(start) : a;
21478
+ const phase = Math.hypot(x0 - original[0], y0 - original[1]);
21479
+ const drawPixel = (x, y) => {
21480
+ const t = lengthSquared === 0 ? 0 : Math.max(0, Math.min(1, ((x - x0) * dx + (y - y0) * dy) / lengthSquared));
21481
+ if (dashed && Math.floor((phase + t * length) / dashLength) % 2 === 1)
21482
+ return;
21483
+ const distance = Math.hypot(x - (x0 + t * dx), y - (y0 + t * dy));
21484
+ const coverage = Math.min(1, padding - distance);
21485
+ if (coverage > 0)
21486
+ fragment(x, y, z0 + t * (z1 - z0), coverage);
21487
+ };
21488
+ if (Math.abs(dx) >= Math.abs(dy)) {
21489
+ const band = length === 0 ? padding : padding * length / Math.abs(dx);
21490
+ const first = Math.max(0, Math.ceil(Math.min(x0, x1) - padding));
21491
+ const last = Math.min(width - 1, Math.floor(Math.max(x0, x1) + padding));
21492
+ for (let x = first;x <= last; x++) {
21493
+ const t = dx === 0 ? 0 : Math.max(0, Math.min(1, (x - x0) / dx));
21494
+ const centerY = y0 + t * dy;
21495
+ const top = Math.max(0, Math.ceil(centerY - band));
21496
+ const bottom = Math.min(height - 1, Math.floor(centerY + band));
21497
+ for (let y = top;y <= bottom; y++)
21498
+ drawPixel(x, y);
21499
+ }
21500
+ } else {
21501
+ const band = padding * length / Math.abs(dy);
21502
+ const first = Math.max(0, Math.ceil(Math.min(y0, y1) - padding));
21503
+ const last = Math.min(height - 1, Math.floor(Math.max(y0, y1) + padding));
21504
+ for (let y = first;y <= last; y++) {
21505
+ const t = Math.max(0, Math.min(1, (y - y0) / dy));
21506
+ const centerX = x0 + t * dx;
21507
+ const left = Math.max(0, Math.ceil(centerX - band));
21508
+ const right = Math.min(width - 1, Math.floor(centerX + band));
21509
+ for (let x = left;x <= right; x++)
21510
+ drawPixel(x, y);
21511
+ }
21512
+ }
21513
+ }
20485
21514
  function edge(a, b, p) {
20486
21515
  return (p[0] - a[0]) * (b[1] - a[1]) - (p[1] - a[1]) * (b[0] - a[0]);
20487
21516
  }
20488
21517
  function drawDebugPoints(renderer, camera, debugPoints, debugFontSize, debugPointColor, debugLabelColor) {
20489
21518
  if (debugPoints.length === 0)
20490
21519
  return;
20491
- const viewProj = import_gl_matrix4.mat4.create();
20492
- import_gl_matrix4.mat4.multiply(viewProj, camera.proj, camera.view);
21520
+ const viewProj = import_gl_matrix6.mat4.create();
21521
+ import_gl_matrix6.mat4.multiply(viewProj, camera.proj, camera.view);
20493
21522
  const markerColor = toColorRGBA(debugPointColor, DEFAULT_MARKER_COLOR);
20494
21523
  const textColor = toColorRGBA(debugLabelColor, DEFAULT_TEXT_COLOR);
20495
21524
  const labelScale = typeof debugFontSize === "number" && Number.isFinite(debugFontSize) ? Math.max(1, Math.round(debugFontSize)) : Math.max(12, Math.round(Math.min(renderer.width, renderer.height) * 0.028));
@@ -20503,8 +21532,8 @@ function drawDebugPoints(renderer, camera, debugPoints, debugFontSize, debugPoin
20503
21532
  }
20504
21533
  }
20505
21534
  function projectWorldToScreen(position, viewProj, renderer) {
20506
- const clip = import_gl_matrix4.vec4.fromValues(position.x, position.y, position.z, 1);
20507
- import_gl_matrix4.vec4.transformMat4(clip, clip, viewProj);
21535
+ const clip = import_gl_matrix6.vec4.fromValues(position.x, position.y, position.z, 1);
21536
+ import_gl_matrix6.vec4.transformMat4(clip, clip, viewProj);
20508
21537
  if (!Number.isFinite(clip[3]) || clip[3] <= 0)
20509
21538
  return null;
20510
21539
  const invW = 1 / clip[3];
@@ -20632,23 +21661,23 @@ function drawInfiniteGrid(software_renderer, params) {
20632
21661
  const camera = params.camera;
20633
21662
  const view = camera.view;
20634
21663
  const proj = camera.proj;
20635
- const inv_view = import_gl_matrix6.mat4.create();
20636
- import_gl_matrix6.mat4.invert(inv_view, view);
21664
+ const inv_view = import_gl_matrix8.mat4.create();
21665
+ import_gl_matrix8.mat4.invert(inv_view, view);
20637
21666
  const cam_pos_x = inv_view[12];
20638
21667
  const cam_pos_y = inv_view[13];
20639
21668
  const cam_pos_z = inv_view[14];
20640
- const vp = import_gl_matrix6.mat4.create();
20641
- import_gl_matrix6.mat4.multiply(vp, proj, view);
20642
- const inv_vp = import_gl_matrix6.mat4.create();
20643
- import_gl_matrix6.mat4.invert(inv_vp, vp);
21669
+ const vp = import_gl_matrix8.mat4.create();
21670
+ import_gl_matrix8.mat4.multiply(vp, proj, view);
21671
+ const inv_vp = import_gl_matrix8.mat4.create();
21672
+ import_gl_matrix8.mat4.invert(inv_vp, vp);
20644
21673
  for (let y = 0;y < software_renderer.height; y++) {
20645
21674
  for (let x = 0;x < software_renderer.width; x++) {
20646
21675
  const ndc_x = x / (software_renderer.width - 1) * 2 - 1;
20647
21676
  const ndc_y = 1 - y / (software_renderer.height - 1) * 2;
20648
- const near_point = import_gl_matrix6.vec4.fromValues(ndc_x, ndc_y, -1, 1);
20649
- const far_point = import_gl_matrix6.vec4.fromValues(ndc_x, ndc_y, 1, 1);
20650
- import_gl_matrix6.vec4.transformMat4(near_point, near_point, inv_vp);
20651
- import_gl_matrix6.vec4.transformMat4(far_point, far_point, inv_vp);
21677
+ const near_point = import_gl_matrix8.vec4.fromValues(ndc_x, ndc_y, -1, 1);
21678
+ const far_point = import_gl_matrix8.vec4.fromValues(ndc_x, ndc_y, 1, 1);
21679
+ import_gl_matrix8.vec4.transformMat4(near_point, near_point, inv_vp);
21680
+ import_gl_matrix8.vec4.transformMat4(far_point, far_point, inv_vp);
20652
21681
  near_point[0] /= near_point[3];
20653
21682
  near_point[1] /= near_point[3];
20654
21683
  near_point[2] /= near_point[3];
@@ -20665,9 +21694,9 @@ function drawInfiniteGrid(software_renderer, params) {
20665
21694
  continue;
20666
21695
  const world_x = near_point[0] + t * ray_dir_x;
20667
21696
  const world_z = near_point[2] + t * ray_dir_z;
20668
- const world_pt = import_gl_matrix6.vec4.fromValues(world_x, grid_y, world_z, 1);
20669
- const clip_pt = import_gl_matrix6.vec4.create();
20670
- import_gl_matrix6.vec4.transformMat4(clip_pt, world_pt, vp);
21697
+ const world_pt = import_gl_matrix8.vec4.fromValues(world_x, grid_y, world_z, 1);
21698
+ const clip_pt = import_gl_matrix8.vec4.create();
21699
+ import_gl_matrix8.vec4.transformMat4(clip_pt, world_pt, vp);
20671
21700
  const ndc_z = clip_pt[2] / clip_pt[3];
20672
21701
  const depth_01 = ndc_z * 0.5 + 0.5;
20673
21702
  const di = y * software_renderer.width + x;
@@ -20753,17 +21782,36 @@ function resolveCameraRotation(cameraRotation) {
20753
21782
  }
20754
21783
  function resolveRenderOptions(options = {}) {
20755
21784
  const supersampling = typeof options.supersampling === "number" && Number.isFinite(options.supersampling) ? Math.max(1, Math.floor(options.supersampling)) : DEFAULT_RENDER_OPTIONS.supersampling;
21785
+ const outline = options.renderStyle === "outline";
20756
21786
  return {
20757
21787
  ...DEFAULT_RENDER_OPTIONS,
20758
21788
  ...options,
21789
+ renderStyle: outline ? "outline" : "shaded",
21790
+ projection: options.projection === "orthographic" || outline && options.projection !== "perspective" ? "orthographic" : "perspective",
21791
+ orthographicHeight: typeof options.orthographicHeight === "number" && Number.isFinite(options.orthographicHeight) && options.orthographicHeight > 0 ? options.orthographicHeight : null,
21792
+ ...outline ? {
21793
+ realistic: false,
21794
+ ambient: 1,
21795
+ gamma: false,
21796
+ cull: false,
21797
+ backgroundColor: options.backgroundColor ?? "#ffffff"
21798
+ } : {},
20759
21799
  supersampling,
20760
21800
  lightDir: options.lightDir != null ? options.lightDir : DEFAULT_RENDER_OPTIONS.lightDir,
20761
21801
  camPos: options.camPos !== undefined ? options.camPos : DEFAULT_RENDER_OPTIONS.camPos,
20762
21802
  lookAt: options.lookAt !== undefined ? options.lookAt : DEFAULT_RENDER_OPTIONS.lookAt,
20763
21803
  up: resolveCameraUp(options.up),
20764
- cameraRotation: resolveCameraRotation(options.cameraRotation)
21804
+ cameraRotation: resolveCameraRotation(options.cameraRotation),
21805
+ showEdges: options.showEdges ?? outline,
21806
+ showHiddenEdges: typeof options.showHiddenEdges === "boolean" ? options.showHiddenEdges : outline ? false : null,
21807
+ edgeWidth: resolveWidth(options.edgeWidth),
21808
+ lineWidth: resolveWidth(options.lineWidth),
21809
+ hiddenEdgeOpacity: typeof options.hiddenEdgeOpacity === "number" && Number.isFinite(options.hiddenEdgeOpacity) ? Math.max(0, Math.min(1, options.hiddenEdgeOpacity)) : DEFAULT_RENDER_OPTIONS.hiddenEdgeOpacity
20765
21810
  };
20766
21811
  }
21812
+ function resolveWidth(width) {
21813
+ return typeof width === "number" && Number.isFinite(width) && width > 0 ? width : 1;
21814
+ }
20767
21815
  function dotNormal(normal, direction) {
20768
21816
  return normal[0] * direction[0] + normal[1] * direction[1] + normal[2] * direction[2];
20769
21817
  }
@@ -20787,7 +21835,7 @@ function basis(n) {
20787
21835
  ]
20788
21836
  ];
20789
21837
  }
20790
- function orient(x, y, z, n, t, b) {
21838
+ function orient2(x, y, z, n, t, b) {
20791
21839
  return [
20792
21840
  t[0] * x + b[0] * y + n[0] * z,
20793
21841
  t[1] * x + b[1] * y + n[1] * z,
@@ -20829,14 +21877,14 @@ function getTables() {
20829
21877
  ];
20830
21878
  const [t, b] = basis(n), index = y * W + x;
20831
21879
  for (const s of diffuseSamples) {
20832
- const l = orient(...s, n, t, b);
21880
+ const l = orient2(...s, n, t, b);
20833
21881
  for (let j = 0;j < lobes.length; j++)
20834
21882
  diffuse[j][index] += Math.exp(lobes[j].sharpness * (dot(l, lobes[j].direction) - 1)) / SAMPLES;
20835
21883
  }
20836
21884
  for (let r = 0;r < ROUGHNESSES.length; r++) {
20837
21885
  let weight = 0;
20838
21886
  for (const s of halfSamples[r]) {
20839
- const h = orient(...s, n, t, b), nh = dot(n, h);
21887
+ const h = orient2(...s, n, t, b), nh = dot(n, h);
20840
21888
  const l = [
20841
21889
  2 * nh * h[0] - n[0],
20842
21890
  2 * nh * h[1] - n[1],
@@ -20877,11 +21925,150 @@ function getTables() {
20877
21925
  cachedTables = { diffuse, specular, brdf };
20878
21926
  return cachedTables;
20879
21927
  }
21928
+ function createExplosionLineDrawCall(line) {
21929
+ if (line.points.length < 2 || line.points.some((point) => point.length !== 3 || !point.every(Number.isFinite))) {
21930
+ throw new Error("Explosion lines need at least two finite XYZ points");
21931
+ }
21932
+ const color = line.color ?? [0.08, 0.2, 0.35];
21933
+ if (color.length !== 3 || color.some((channel) => !Number.isFinite(channel) || channel < 0 || channel > 1)) {
21934
+ throw new Error("Explosion line colors must be linear RGB values from 0 to 1");
21935
+ }
21936
+ const indices = [];
21937
+ for (let vertex = 1;vertex < line.points.length; vertex++) {
21938
+ indices.push(vertex - 1, vertex);
21939
+ }
21940
+ return {
21941
+ positions: new Float32Array(line.points.flatMap((point) => [...point])),
21942
+ indices: new Uint32Array(indices),
21943
+ normals: null,
21944
+ uvs: null,
21945
+ model: import_gl_matrix11.mat4.create(),
21946
+ material: { baseColorFactor: [...color, 1], baseColorTexture: null },
21947
+ mode: 1
21948
+ };
21949
+ }
21950
+ function clipExplosionLineDrawCall(drawCall, camera) {
21951
+ const viewProjection = import_gl_matrix11.mat4.multiply(import_gl_matrix11.mat4.create(), camera.proj, camera.view);
21952
+ const positions = [];
21953
+ const indices = [];
21954
+ const distances = (point) => [
21955
+ point[3] + point[0],
21956
+ point[3] - point[0],
21957
+ point[3] + point[1],
21958
+ point[3] - point[1],
21959
+ point[3] + point[2],
21960
+ point[3] - point[2]
21961
+ ];
21962
+ for (let segment = 0;segment < drawCall.indices.length; segment += 2) {
21963
+ const startIndex = drawCall.indices[segment] * 3;
21964
+ const endIndex = drawCall.indices[segment + 1] * 3;
21965
+ const start = import_gl_matrix11.vec4.fromValues(drawCall.positions[startIndex], drawCall.positions[startIndex + 1], drawCall.positions[startIndex + 2], 1);
21966
+ const end = import_gl_matrix11.vec4.fromValues(drawCall.positions[endIndex], drawCall.positions[endIndex + 1], drawCall.positions[endIndex + 2], 1);
21967
+ const startDistances = distances(import_gl_matrix11.vec4.transformMat4(import_gl_matrix11.vec4.create(), start, viewProjection));
21968
+ const endDistances = distances(import_gl_matrix11.vec4.transformMat4(import_gl_matrix11.vec4.create(), end, viewProjection));
21969
+ let from = 0;
21970
+ let to = 1;
21971
+ for (let plane = 0;plane < 6; plane++) {
21972
+ const a = startDistances[plane];
21973
+ const b = endDistances[plane];
21974
+ if (a < 0 && b < 0) {
21975
+ to = -1;
21976
+ break;
21977
+ }
21978
+ if (a < 0 !== b < 0) {
21979
+ const intersection = a / (a - b);
21980
+ if (a < 0)
21981
+ from = Math.max(from, intersection);
21982
+ else
21983
+ to = Math.min(to, intersection);
21984
+ }
21985
+ }
21986
+ if (from > to)
21987
+ continue;
21988
+ const vertex = positions.length / 3;
21989
+ for (const progress of [from, to]) {
21990
+ for (let axis = 0;axis < 3; axis++) {
21991
+ positions.push(start[axis] + progress * (end[axis] - start[axis]));
21992
+ }
21993
+ }
21994
+ indices.push(vertex, vertex + 1);
21995
+ }
21996
+ return {
21997
+ ...drawCall,
21998
+ positions: new Float32Array(positions),
21999
+ indices: new Uint32Array(indices)
22000
+ };
22001
+ }
22002
+ function createExplosionArrowDrawCall(drawCall, camera, width, height, supersampling) {
22003
+ if (width <= 1 || height <= 1)
22004
+ return null;
22005
+ const points = drawCall.positions;
22006
+ const end = points.length - 3;
22007
+ let start = end - 3;
22008
+ while (start >= 0 && points[start] === points[end] && points[start + 1] === points[end + 1] && points[start + 2] === points[end + 2]) {
22009
+ start -= 3;
22010
+ }
22011
+ if (start < 0)
22012
+ return null;
22013
+ const viewProjection = import_gl_matrix12.mat4.multiply(import_gl_matrix12.mat4.create(), camera.proj, camera.view);
22014
+ const tip = import_gl_matrix12.vec4.transformMat4(import_gl_matrix12.vec4.create(), import_gl_matrix12.vec4.fromValues(points[end], points[end + 1], points[end + 2], 1), viewProjection);
22015
+ if (!Array.from(tip).every(Number.isFinite) || tip[3] <= 0 || Math.abs(tip[0]) > tip[3] || Math.abs(tip[1]) > tip[3] || Math.abs(tip[2]) > tip[3]) {
22016
+ return null;
22017
+ }
22018
+ const clipped = clipExplosionLineDrawCall({
22019
+ ...drawCall,
22020
+ positions: new Float32Array([
22021
+ points[start],
22022
+ points[start + 1],
22023
+ points[start + 2],
22024
+ points[end],
22025
+ points[end + 1],
22026
+ points[end + 2]
22027
+ ]),
22028
+ indices: new Uint32Array([0, 1])
22029
+ }, camera);
22030
+ if (!clipped.indices?.length)
22031
+ return null;
22032
+ const tail = import_gl_matrix12.vec4.transformMat4(import_gl_matrix12.vec4.create(), import_gl_matrix12.vec4.fromValues(clipped.positions[0], clipped.positions[1], clipped.positions[2], 1), viewProjection);
22033
+ if (tail[3] <= 0)
22034
+ return null;
22035
+ const dx = (tip[0] / tip[3] - tail[0] / tail[3]) * (width - 1) / 2;
22036
+ const dy = (tip[1] / tip[3] - tail[1] / tail[3]) * (height - 1) / 2;
22037
+ const length = Math.hypot(dx, dy);
22038
+ if (!Number.isFinite(length) || length < 0.001)
22039
+ return null;
22040
+ const arrowLength = Math.min(10 * supersampling, length / 2);
22041
+ const ux = dx / length;
22042
+ const uy = dy / length;
22043
+ const inverse = import_gl_matrix12.mat4.invert(import_gl_matrix12.mat4.create(), viewProjection);
22044
+ if (!inverse)
22045
+ return null;
22046
+ const positions = [points[end], points[end + 1], points[end + 2]];
22047
+ for (const side of [-1, 1]) {
22048
+ const offsetX = -ux * arrowLength - side * uy * arrowLength * 0.45;
22049
+ const offsetY = -uy * arrowLength + side * ux * arrowLength * 0.45;
22050
+ const wing = import_gl_matrix12.vec4.transformMat4(import_gl_matrix12.vec4.create(), import_gl_matrix12.vec4.fromValues(tip[0] / tip[3] + 2 * offsetX / (width - 1), tip[1] / tip[3] + 2 * offsetY / (height - 1), tip[2] / tip[3], 1), inverse);
22051
+ if (!Array.from(wing).every(Number.isFinite) || wing[3] === 0)
22052
+ return null;
22053
+ positions.push(wing[0] / wing[3], wing[1] / wing[3], wing[2] / wing[3]);
22054
+ }
22055
+ return {
22056
+ ...drawCall,
22057
+ positions: new Float32Array(positions),
22058
+ indices: new Uint32Array([0, 1, 0, 2])
22059
+ };
22060
+ }
20880
22061
  function renderDrawCalls(drawCalls, optionsInput = {}, imageFactory = createUint8Bitmap) {
20881
22062
  const options = resolveRenderOptions(optionsInput);
22063
+ if (options.section) {
22064
+ if (options.renderStyle !== "outline")
22065
+ throw new Error("section requires renderStyle: outline");
22066
+ drawCalls = createOutlineSection(drawCalls, options.section).drawCalls;
22067
+ }
20882
22068
  const renderWidth = options.width * options.supersampling;
20883
22069
  const renderHeight = options.height * options.supersampling;
20884
- const camera = buildCamera(drawCalls, renderWidth, renderHeight, options.fov, options.camPos ?? null, options.lookAt ?? null, options.up, options.cameraRotation ?? null);
22070
+ const explosionDrawCalls = (options.explosionLines ?? []).map(createExplosionLineDrawCall);
22071
+ const camera = buildCamera([...drawCalls, ...explosionDrawCalls], renderWidth, renderHeight, options.fov, options.camPos ?? null, options.lookAt ?? null, options.up, options.cameraRotation ?? null, options.projection, options.orthographicHeight);
20885
22072
  const renderer = new SoftwareRenderer(renderWidth, renderHeight, imageFactory, options.realistic);
20886
22073
  let rgb = null;
20887
22074
  if (options.backgroundColor) {
@@ -20902,7 +22089,17 @@ function renderDrawCalls(drawCalls, optionsInput = {}, imageFactory = createUint
20902
22089
  } else {
20903
22090
  renderer.clear([0, 0, 0, 0]);
20904
22091
  }
20905
- const allDrawCalls = [...drawCalls];
22092
+ const allDrawCalls = options.renderStyle === "outline" ? drawCalls.map((dc) => dc.mode === 1 || dc.outlineSectionCap ? dc : {
22093
+ ...dc,
22094
+ normals: null,
22095
+ colors: null,
22096
+ uvs: null,
22097
+ material: {
22098
+ baseColorFactor: [1, 1, 1, 1],
22099
+ baseColorTexture: null,
22100
+ alphaMode: "OPAQUE"
22101
+ }
22102
+ }) : [...drawCalls];
20906
22103
  let infiniteGridOptions = null;
20907
22104
  if (options.grid) {
20908
22105
  const userGridOptions = typeof options.grid === "boolean" ? {} : options.grid;
@@ -20953,7 +22150,9 @@ function renderDrawCalls(drawCalls, optionsInput = {}, imageFactory = createUint
20953
22150
  for (let i = 0;i < dcs.length; i++) {
20954
22151
  const dc = dcs[i];
20955
22152
  if (dc.mode === 1) {
20956
- renderer.drawLines(dc, camera, options.gamma);
22153
+ renderer.drawLines(dc, camera, options.gamma, {
22154
+ width: options.lineWidth * options.supersampling
22155
+ });
20957
22156
  } else {
20958
22157
  renderer.drawMesh(dc, camera, { dir: options.lightDir, ambient: options.ambient }, dc.material, options.cull, options.gamma, studio, opaque && winners ? { winners, triangleOffset: triangleOffsets[i], depthOnly: false } : undefined);
20959
22158
  }
@@ -20980,24 +22179,50 @@ function renderDrawCalls(drawCalls, optionsInput = {}, imageFactory = createUint
20980
22179
  renderGroup(blendDraws);
20981
22180
  renderer.denoise(options.gamma);
20982
22181
  for (const dc of drawCalls) {
20983
- if (!dc.showHiddenEdges)
22182
+ const showHiddenEdges = options.showHiddenEdges ?? dc.showHiddenEdges;
22183
+ if (!options.showEdges && !showHiddenEdges)
20984
22184
  continue;
20985
- const edgeDrawCall = createEdgeDrawCall(dc);
22185
+ const edgeDrawCall = createEdgeDrawCall(dc, 30, options.renderStyle === "outline" ? { view: camera.view, projection: options.projection } : undefined);
20986
22186
  if (!edgeDrawCall)
20987
22187
  continue;
20988
22188
  renderer.drawLines(edgeDrawCall, camera, options.gamma, {
20989
22189
  depthCompare: "less-equal",
20990
22190
  depthWrite: false,
20991
- depthBias: 0.0001
22191
+ depthBias: 0.0001,
22192
+ width: options.edgeWidth * options.supersampling
20992
22193
  });
22194
+ if (!showHiddenEdges)
22195
+ continue;
20993
22196
  renderer.drawLines(edgeDrawCall, camera, options.gamma, {
20994
22197
  depthCompare: "greater",
20995
22198
  depthWrite: false,
20996
22199
  depthBias: 0.0001,
20997
22200
  dashed: true,
20998
22201
  dashLength: 4 * options.supersampling,
20999
- opacity: 0.35
22202
+ opacity: options.hiddenEdgeOpacity,
22203
+ width: options.edgeWidth * options.supersampling
22204
+ });
22205
+ }
22206
+ for (const [index, drawCall] of explosionDrawCalls.entries()) {
22207
+ renderer.drawLines(clipExplosionLineDrawCall(drawCall, camera), camera, options.gamma, {
22208
+ depthCompare: "less-equal",
22209
+ depthWrite: false,
22210
+ depthBias: 0.0001,
22211
+ dashed: options.explosionLines[index].dashed ?? true,
22212
+ dashLength: 4 * options.supersampling,
22213
+ width: options.lineWidth * options.supersampling
21000
22214
  });
22215
+ if (options.explosionLines[index].arrow) {
22216
+ const arrow = createExplosionArrowDrawCall(drawCall, camera, renderWidth, renderHeight, options.supersampling);
22217
+ if (arrow) {
22218
+ renderer.drawLines(clipExplosionLineDrawCall(arrow, camera), camera, options.gamma, {
22219
+ depthCompare: "less-equal",
22220
+ depthWrite: false,
22221
+ depthBias: 0.0001,
22222
+ width: options.lineWidth * options.supersampling
22223
+ });
22224
+ }
22225
+ }
21001
22226
  }
21002
22227
  if (options.debugPoints?.length) {
21003
22228
  drawDebugPoints(renderer, camera, options.debugPoints, options.debugFontSize, options.debugPointColor, options.debugLabelColor);
@@ -21028,9 +22253,9 @@ function createInfiniteGrid(options = {}) {
21028
22253
  size
21029
22254
  ]);
21030
22255
  const indices = new Uint32Array([0, 1, 2, 0, 2, 3]);
21031
- const model = import_gl_matrix9.mat4.create();
22256
+ const model = import_gl_matrix13.mat4.create();
21032
22257
  const offset = options.offset ?? {};
21033
- import_gl_matrix9.mat4.fromTranslation(model, [offset.x ?? 0, offset.y ?? 0, offset.z ?? 0]);
22258
+ import_gl_matrix13.mat4.fromTranslation(model, [offset.x ?? 0, offset.y ?? 0, offset.z ?? 0]);
21034
22259
  return {
21035
22260
  positions,
21036
22261
  indices,
@@ -21204,7 +22429,7 @@ function readIndices(ctx, accessorIndex) {
21204
22429
  }
21205
22430
  function nodeLocalMatrix(node) {
21206
22431
  if (node.matrix) {
21207
- const m2 = import_gl_matrix10.mat4.create();
22432
+ const m2 = import_gl_matrix14.mat4.create();
21208
22433
  for (let i = 0;i < 16; i++)
21209
22434
  m2[i] = node.matrix[i];
21210
22435
  return m2;
@@ -21212,10 +22437,10 @@ function nodeLocalMatrix(node) {
21212
22437
  const translation = node.translation || [0, 0, 0];
21213
22438
  const rotation = node.rotation || [0, 0, 0, 1];
21214
22439
  const scale = node.scale || [1, 1, 1];
21215
- const m = import_gl_matrix10.mat4.create();
21216
- const tmp = import_gl_matrix10.mat4.create();
21217
- import_gl_matrix10.mat4.fromRotationTranslationScale(tmp, rotation, translation, scale);
21218
- import_gl_matrix10.mat4.copy(m, tmp);
22440
+ const m = import_gl_matrix14.mat4.create();
22441
+ const tmp = import_gl_matrix14.mat4.create();
22442
+ import_gl_matrix14.mat4.fromRotationTranslationScale(tmp, rotation, translation, scale);
22443
+ import_gl_matrix14.mat4.copy(m, tmp);
21219
22444
  return m;
21220
22445
  }
21221
22446
  function getMaterial(gltf, textures, images, materialIndex) {
@@ -21259,8 +22484,8 @@ function createSceneFromGLTF(gltf, resources) {
21259
22484
  if (!node)
21260
22485
  return;
21261
22486
  const local = nodeLocalMatrix(node);
21262
- const world = import_gl_matrix10.mat4.create();
21263
- import_gl_matrix10.mat4.multiply(world, parentMatrix, local);
22487
+ const world = import_gl_matrix14.mat4.create();
22488
+ import_gl_matrix14.mat4.multiply(world, parentMatrix, local);
21264
22489
  if (Number.isInteger(node.mesh)) {
21265
22490
  const mesh = meshes[node.mesh];
21266
22491
  if (mesh) {
@@ -21296,7 +22521,7 @@ function createSceneFromGLTF(gltf, resources) {
21296
22521
  traverse(childIndex, world);
21297
22522
  }
21298
22523
  }
21299
- const identity = import_gl_matrix10.mat4.create();
22524
+ const identity = import_gl_matrix14.mat4.create();
21300
22525
  for (const rootIndex of scene.nodes || []) {
21301
22526
  traverse(rootIndex, identity);
21302
22527
  }
@@ -21582,11 +22807,11 @@ async function renderGLTFToPNGFromGLB(glb, options = {}) {
21582
22807
  function renderSceneFromGLTF(scene, options, imageFactory) {
21583
22808
  return renderDrawCalls(scene.drawCalls, options, imageFactory);
21584
22809
  }
21585
- var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, import_gl_matrix5, import_gl_matrix6, import_gl_matrix7, import_gl_matrix8, import_gl_matrix9, import_gl_matrix10, toRad = (degrees) => degrees * Math.PI / 180, DEFAULT_CREASE_ANGLE_DEGREES = 30, createUint8Bitmap = (width, height) => ({
22810
+ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, import_gl_matrix5, import_gl_matrix6, import_gl_matrix7, import_gl_matrix8, import_gl_matrix9, import_gl_matrix10, import_gl_matrix11, import_gl_matrix12, import_gl_matrix13, import_gl_matrix14, createUint8Bitmap = (width, height) => ({
21586
22811
  width,
21587
22812
  height,
21588
22813
  data: new Uint8ClampedArray(width * height * 4)
21589
- }), DEFAULT_LIGHT_DIR, DEFAULT_RENDER_OPTIONS, clamp = (value, min, max) => Math.max(min, Math.min(max, value)), GeometryDenoiser = class {
22814
+ }), toRad = (degrees) => degrees * Math.PI / 180, DEFAULT_CREASE_ANGLE_DEGREES = 30, DEFAULT_LIGHT_DIR, DEFAULT_RENDER_OPTIONS, clamp = (value, min, max) => Math.max(min, Math.min(max, value)), GeometryDenoiser = class {
21590
22815
  constructor(width, height) {
21591
22816
  this.width = width;
21592
22817
  this.height = height;
@@ -21724,16 +22949,18 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
21724
22949
  return;
21725
22950
  const view = camera.view;
21726
22951
  const proj = camera.proj;
21727
- const mvp = import_gl_matrix5.mat4.create();
21728
- import_gl_matrix5.mat4.multiply(mvp, proj, import_gl_matrix5.mat4.multiply(import_gl_matrix5.mat4.create(), view, model));
22952
+ const mvp = import_gl_matrix7.mat4.create();
22953
+ import_gl_matrix7.mat4.multiply(mvp, proj, import_gl_matrix7.mat4.multiply(import_gl_matrix7.mat4.create(), view, model));
21729
22954
  const vertexCount = positions.length / 3 | 0;
21730
22955
  const vScreen = new Array(vertexCount);
21731
22956
  const vInvW = new Float32Array(vertexCount);
21732
22957
  const vNDCz = new Float32Array(vertexCount);
22958
+ const clipVertices = [];
21733
22959
  for (let i = 0;i < vertexCount; i++) {
21734
- const p = import_gl_matrix5.vec4.fromValues(positions[i * 3 + 0], positions[i * 3 + 1], positions[i * 3 + 2], 1);
21735
- const c = import_gl_matrix5.vec4.create();
21736
- import_gl_matrix5.vec4.transformMat4(c, p, mvp);
22960
+ const p = import_gl_matrix7.vec4.fromValues(positions[i * 3 + 0], positions[i * 3 + 1], positions[i * 3 + 2], 1);
22961
+ const c = import_gl_matrix7.vec4.create();
22962
+ import_gl_matrix7.vec4.transformMat4(c, p, mvp);
22963
+ clipVertices.push(c);
21737
22964
  const invW = 1 / c[3];
21738
22965
  vInvW[i] = invW;
21739
22966
  if (!isFinite(invW)) {
@@ -21768,9 +22995,58 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
21768
22995
  const depthWrite = options.depthWrite ?? true;
21769
22996
  const depthBias = options.depthBias ?? 0;
21770
22997
  const dashLength = Math.max(1, options.dashLength ?? 4);
22998
+ const strokeWidth = typeof options.width === "number" && Number.isFinite(options.width) && options.width > 0 ? options.width : 1;
22999
+ const drawFragment = (xi, yi, z, coverage = 1) => {
23000
+ if (z < 0 || z > 1)
23001
+ return;
23002
+ const di = yi * this.width + xi;
23003
+ const currentDepth = this.depth[di];
23004
+ const passesDepth = depthCompare === "greater" ? z > currentDepth + depthBias : depthCompare === "less-equal" ? z <= currentDepth + depthBias : z < currentDepth - depthBias;
23005
+ if (!passesDepth)
23006
+ return;
23007
+ if (depthWrite)
23008
+ this.depth[di] = z;
23009
+ const pixelIndex = di * 4;
23010
+ const destinationAlpha = this.buffer[pixelIndex + 3] / 255;
23011
+ const alpha = sourceAlpha * coverage;
23012
+ const oneMinusSourceAlpha = 1 - alpha;
23013
+ const outAlpha = alpha + destinationAlpha * oneMinusSourceAlpha;
23014
+ const blend = (channel, offset) => outAlpha === 0 ? 0 : (channel * alpha + this.buffer[pixelIndex + offset] * destinationAlpha * oneMinusSourceAlpha) / outAlpha;
23015
+ this.setPixel(xi, yi, blend(r255, 0), blend(g255, 1), blend(b255, 2), outAlpha * 255);
23016
+ };
21771
23017
  for (let i = 0;i < indices.length; i += 2) {
21772
23018
  const i0 = indices[i + 0];
21773
23019
  const i1 = indices[i + 1];
23020
+ if (strokeWidth !== 1) {
23021
+ const sourceFaces = (mesh.edgeAdjacentVertices?.[i / 2] ?? []).flatMap((third) => {
23022
+ if (clipVertices[i0][3] <= 0 || clipVertices[i1][3] <= 0 || clipVertices[third][3] <= 0)
23023
+ return [];
23024
+ const a2 = vScreen[i0];
23025
+ const b2 = vScreen[i1];
23026
+ const c = vScreen[third];
23027
+ const area = edge(a2, b2, c);
23028
+ if (!Number.isFinite(area) || area === 0)
23029
+ return [];
23030
+ return [{ a: a2, b: b2, c, inverseArea: 1 / area, third }];
23031
+ });
23032
+ rasterizeWideLine(clipVertices[i0], clipVertices[i1], this.width, this.height, strokeWidth, options.dashed ?? false, dashLength, sourceFaces.length === 0 ? drawFragment : (x2, y2, z2, coverage) => {
23033
+ let surfaceDepth = Infinity;
23034
+ const sample = [x2 + 0.5, y2 + 0.5];
23035
+ for (const face of sourceFaces) {
23036
+ const l0 = edge(face.b, face.c, sample) * face.inverseArea;
23037
+ const l1 = edge(face.c, face.a, sample) * face.inverseArea;
23038
+ const l2 = 1 - l0 - l1;
23039
+ if (l0 < -0.000001 || l1 < -0.000001 || l2 < -0.000001)
23040
+ continue;
23041
+ const depth = (l0 * vNDCz[i0] + l1 * vNDCz[i1] + l2 * vNDCz[face.third]) * 0.5 + 0.5;
23042
+ if (depth >= 0 && depth <= 1) {
23043
+ surfaceDepth = Math.min(surfaceDepth, depth);
23044
+ }
23045
+ }
23046
+ drawFragment(x2, y2, surfaceDepth === Infinity ? z2 : surfaceDepth, coverage);
23047
+ });
23048
+ continue;
23049
+ }
21774
23050
  const v0s = vScreen[i0];
21775
23051
  const v1s = vScreen[i1];
21776
23052
  const z0_ndc = vNDCz[i0];
@@ -21806,21 +23082,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
21806
23082
  const xi = Math.round(x);
21807
23083
  const yi = Math.round(y);
21808
23084
  if (xi >= 0 && xi < this.width && yi >= 0 && yi < this.height && z >= 0 && z <= 1) {
21809
- const di = yi * this.width + xi;
21810
- const currentDepth = this.depth[di];
21811
- const passesDepth = depthCompare === "greater" ? z > currentDepth + depthBias : depthCompare === "less-equal" ? z <= currentDepth + depthBias : z < currentDepth - depthBias;
21812
- if (passesDepth) {
21813
- if (depthWrite)
21814
- this.depth[di] = z;
21815
- const pixelIndex = di * 4;
21816
- const destinationAlpha = this.buffer[pixelIndex + 3] / 255;
21817
- const oneMinusSourceAlpha = 1 - sourceAlpha;
21818
- const outAlpha = sourceAlpha + destinationAlpha * oneMinusSourceAlpha;
21819
- const outR = outAlpha === 0 ? 0 : (r255 * sourceAlpha + this.buffer[pixelIndex + 0] * destinationAlpha * oneMinusSourceAlpha) / outAlpha;
21820
- const outG = outAlpha === 0 ? 0 : (g255 * sourceAlpha + this.buffer[pixelIndex + 1] * destinationAlpha * oneMinusSourceAlpha) / outAlpha;
21821
- const outB = outAlpha === 0 ? 0 : (b255 * sourceAlpha + this.buffer[pixelIndex + 2] * destinationAlpha * oneMinusSourceAlpha) / outAlpha;
21822
- this.setPixel(xi, yi, outR, outG, outB, outAlpha * 255);
21823
- }
23085
+ drawFragment(xi, yi, z);
21824
23086
  }
21825
23087
  x += xinc;
21826
23088
  y += yinc;
@@ -21859,13 +23121,13 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
21859
23121
  const materialId = this.denoiser?.materialId(material) ?? 0;
21860
23122
  const lightDir = light.dir ?? DEFAULT_LIGHT_DIR;
21861
23123
  const ambient = clamp(light.ambient ?? DEFAULT_RENDER_OPTIONS.ambient, 0, 1);
21862
- const L = studio ? null : import_gl_matrix5.vec3.normalize(import_gl_matrix5.vec3.create(), import_gl_matrix5.vec3.fromValues(lightDir[0], lightDir[1], lightDir[2]));
23124
+ const L = studio ? null : import_gl_matrix7.vec3.normalize(import_gl_matrix7.vec3.create(), import_gl_matrix7.vec3.fromValues(lightDir[0], lightDir[1], lightDir[2]));
21863
23125
  const view = camera.view;
21864
23126
  const proj = camera.proj;
21865
- const mvp = import_gl_matrix5.mat4.create();
21866
- import_gl_matrix5.mat4.multiply(mvp, proj, import_gl_matrix5.mat4.multiply(import_gl_matrix5.mat4.create(), view, model));
21867
- const normalMat = import_gl_matrix5.mat3.create();
21868
- import_gl_matrix5.mat3.normalFromMat4(normalMat, model);
23127
+ const mvp = import_gl_matrix7.mat4.create();
23128
+ import_gl_matrix7.mat4.multiply(mvp, proj, import_gl_matrix7.mat4.multiply(import_gl_matrix7.mat4.create(), view, model));
23129
+ const normalMat = import_gl_matrix7.mat3.create();
23130
+ import_gl_matrix7.mat3.normalFromMat4(normalMat, model);
21869
23131
  let vertexCount = positions.length / 3 | 0;
21870
23132
  let idx = indices ?? (() => {
21871
23133
  const a = new Uint32Array(vertexCount);
@@ -21892,11 +23154,11 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
21892
23154
  const vWorldP = studio && !depthOnly ? new Array(vertexCount) : null;
21893
23155
  const vColor = new Array(depthOnly ? 0 : vertexCount);
21894
23156
  for (let i = 0;i < vertexCount; i++) {
21895
- const p = import_gl_matrix5.vec4.fromValues(positions[i * 3 + 0], positions[i * 3 + 1], positions[i * 3 + 2], 1);
21896
- const c = import_gl_matrix5.vec4.create();
21897
- import_gl_matrix5.vec4.transformMat4(c, p, mvp);
23157
+ const p = import_gl_matrix7.vec4.fromValues(positions[i * 3 + 0], positions[i * 3 + 1], positions[i * 3 + 2], 1);
23158
+ const c = import_gl_matrix7.vec4.create();
23159
+ import_gl_matrix7.vec4.transformMat4(c, p, mvp);
21898
23160
  if (vWorldP) {
21899
- const world = import_gl_matrix5.vec4.transformMat4(import_gl_matrix5.vec4.create(), p, model);
23161
+ const world = import_gl_matrix7.vec4.transformMat4(import_gl_matrix7.vec4.create(), p, model);
21900
23162
  vWorldP[i] = [world[0], world[1], world[2]];
21901
23163
  }
21902
23164
  const invW = 1 / c[3];
@@ -21910,9 +23172,9 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
21910
23172
  vNDCz[i] = ndcZ;
21911
23173
  if (depthOnly)
21912
23174
  continue;
21913
- const n = import_gl_matrix5.vec3.fromValues(useNormals[i * 3 + 0], useNormals[i * 3 + 1], useNormals[i * 3 + 2]);
21914
- const nw = import_gl_matrix5.vec3.create();
21915
- import_gl_matrix5.vec3.transformMat3(nw, n, normalMat);
23175
+ const n = import_gl_matrix7.vec3.fromValues(useNormals[i * 3 + 0], useNormals[i * 3 + 1], useNormals[i * 3 + 2]);
23176
+ const nw = import_gl_matrix7.vec3.create();
23177
+ import_gl_matrix7.vec3.transformMat3(nw, n, normalMat);
21916
23178
  vWorldN[i] = [nw[0], nw[1], nw[2]];
21917
23179
  if (colors && colors.length >= (i + 1) * 3) {
21918
23180
  vColor[i] = [colors[i * 3 + 0], colors[i * 3 + 1], colors[i * 3 + 2]];
@@ -21999,7 +23261,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
21999
23261
  ];
22000
23262
  if (uv && material.baseColorTexture) {
22001
23263
  const uvp = this.perspInterp(uv, invW, [l0, l1, l2]);
22002
- const texel = this.sampleTextureNearest(material.baseColorTexture, uvp[0], uvp[1]);
23264
+ const texel = this.sampleTextureNearest(material.baseColorTexture, material.baseColorTextureWrap === "repeat" ? uvp[0] - Math.floor(uvp[0]) : uvp[0], material.baseColorTextureWrap === "repeat" ? uvp[1] - Math.floor(uvp[1]) : uvp[1]);
22003
23265
  baseColor = mulColor(baseColor, [
22004
23266
  srgbDecodeToLinear01(texel[0]),
22005
23267
  srgbDecodeToLinear01(texel[1]),
@@ -22124,7 +23386,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
22124
23386
  const count = dc.indices?.length ?? dc.positions.length / 3;
22125
23387
  const worldVertices = [];
22126
23388
  for (let i = 0;i < dc.positions.length; i += 3) {
22127
- const p = import_gl_matrix8.vec3.transformMat4(import_gl_matrix8.vec3.create(), [dc.positions[i], dc.positions[i + 1], dc.positions[i + 2]], dc.model);
23389
+ const p = import_gl_matrix10.vec3.transformMat4(import_gl_matrix10.vec3.create(), [dc.positions[i], dc.positions[i + 1], dc.positions[i + 2]], dc.model);
22128
23390
  worldVertices.push([p[0], p[1], p[2]]);
22129
23391
  }
22130
23392
  const vertex = (index) => worldVertices[dc.indices?.[index] ?? index];
@@ -22446,7 +23708,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
22446
23708
  }
22447
23709
  constructor(drawCalls, camera) {
22448
23710
  this.occlusion = new RayOcclusion(drawCalls);
22449
- const world = import_gl_matrix7.mat4.invert(import_gl_matrix7.mat4.create(), camera.view);
23711
+ const world = import_gl_matrix9.mat4.invert(import_gl_matrix9.mat4.create(), camera.view);
22450
23712
  if (!world)
22451
23713
  throw new Error("Realistic rendering requires an invertible camera view.");
22452
23714
  this.eye = [world[12], world[13], world[14]];
@@ -22454,7 +23716,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
22454
23716
  const [t, b] = basis(l.direction);
22455
23717
  return Array.from({ length: SHADOW_SAMPLES }, (_, i) => {
22456
23718
  const u = (i + 0.5) / SHADOW_SAMPLES, cos = 1 + Math.log(1 - u) / l.sharpness, sin = Math.sqrt(Math.max(0, 1 - cos * cos)), phi = 2 * Math.PI * radicalInverse(i);
22457
- const direction = orient(sin * Math.cos(phi), sin * Math.sin(phi), cos, l.direction, t, b);
23719
+ const direction = orient2(sin * Math.cos(phi), sin * Math.sin(phi), cos, l.direction, t, b);
22458
23720
  const parallel = dot(direction, l.direction);
22459
23721
  return {
22460
23722
  parallel: l.direction.map((v) => v * parallel),
@@ -22577,7 +23839,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
22577
23839
  const [t, b] = basis(n);
22578
23840
  let blocked = 0;
22579
23841
  for (let i = 0;metal < 1 && i < DIFFUSE_SAMPLES; i++) {
22580
- const phi = i * 2 * Math.PI / DIFFUSE_SAMPLES + phase, l = orient(0.7 * Math.cos(phi), 0.7 * Math.sin(phi), Math.sqrt(0.51), n, t, b);
23842
+ const phi = i * 2 * Math.PI / DIFFUSE_SAMPLES + phase, l = orient2(0.7 * Math.cos(phi), 0.7 * Math.sin(phi), Math.sqrt(0.51), n, t, b);
22581
23843
  const hit = this.occlusion.trace(origin, l);
22582
23844
  if (hit) {
22583
23845
  blocked++;
@@ -22600,7 +23862,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
22600
23862
  this.reflectionSamples.set(rough, samples);
22601
23863
  }
22602
23864
  for (const [sx, sy, nh] of samples) {
22603
- const h = orient(sx * cosPhase - sy * sinPhase, sx * sinPhase + sy * cosPhase, nh, reflected, rt, rb);
23865
+ const h = orient2(sx * cosPhase - sy * sinPhase, sx * sinPhase + sy * cosPhase, nh, reflected, rt, rb);
22604
23866
  const l = [
22605
23867
  2 * nh * h[0] - reflected[0],
22606
23868
  2 * nh * h[1] - reflected[1],
@@ -22624,6 +23886,7 @@ var import_gl_matrix, import_gl_matrix2, import_gl_matrix3, import_gl_matrix4, i
22624
23886
  }
22625
23887
  }, COMPONENT_INFO, NUM_COMPONENTS, MAGIC = 1179937895, JSON_CHUNK_TYPE = 1313821514, BIN_CHUNK_TYPE = 5130562;
22626
23888
  var init_dist = __esm(() => {
23889
+ init_earcut();
22627
23890
  init_lib();
22628
23891
  init_lib();
22629
23892
  import_gl_matrix = __toESM(require_cjs(), 1);
@@ -22636,8 +23899,16 @@ var init_dist = __esm(() => {
22636
23899
  import_gl_matrix8 = __toESM(require_cjs(), 1);
22637
23900
  import_gl_matrix9 = __toESM(require_cjs(), 1);
22638
23901
  import_gl_matrix10 = __toESM(require_cjs(), 1);
23902
+ import_gl_matrix11 = __toESM(require_cjs(), 1);
23903
+ import_gl_matrix12 = __toESM(require_cjs(), 1);
23904
+ import_gl_matrix13 = __toESM(require_cjs(), 1);
23905
+ import_gl_matrix14 = __toESM(require_cjs(), 1);
22639
23906
  DEFAULT_LIGHT_DIR = [-0.4, -0.9, -0.2];
22640
23907
  DEFAULT_RENDER_OPTIONS = {
23908
+ renderStyle: "shaded",
23909
+ section: null,
23910
+ projection: "perspective",
23911
+ orthographicHeight: null,
22641
23912
  realistic: false,
22642
23913
  width: 800,
22643
23914
  height: 600,
@@ -22656,7 +23927,13 @@ var init_dist = __esm(() => {
22656
23927
  debugPoints: null,
22657
23928
  debugFontSize: null,
22658
23929
  debugPointColor: null,
22659
- debugLabelColor: null
23930
+ debugLabelColor: null,
23931
+ explosionLines: null,
23932
+ showEdges: false,
23933
+ showHiddenEdges: null,
23934
+ edgeWidth: 1,
23935
+ lineWidth: 1,
23936
+ hiddenEdgeOpacity: 0.35
22660
23937
  };
22661
23938
  DEFAULT_MARKER_COLOR = [
22662
23939
  255,
@@ -31961,6 +33238,8 @@ var projectConfigSchema = z.object({
31961
33238
  kicadLibrary: z.boolean().optional(),
31962
33239
  kicadPcm: z.boolean().optional(),
31963
33240
  previewImages: z.boolean().optional(),
33241
+ drawings: z.boolean().optional(),
33242
+ drawing: z.string().optional(),
31964
33243
  glbs: z.boolean().optional(),
31965
33244
  step: z.boolean().optional(),
31966
33245
  workerTimeoutMs: z.number().int().positive().optional(),