@adatechnology/game-vegetation-three 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -41,6 +41,1523 @@ var GameVegetationThree = (() => {
41
41
  scatterLot: () => scatterLot
42
42
  });
43
43
 
44
+ // ../game-shapes/dist/chunk-R4RY23RH.js
45
+ function canonicalJson(value) {
46
+ if (value === null) return "null";
47
+ if (typeof value === "number") return Object.is(value, -0) ? "-0" : Number.isFinite(value) ? String(value) : JSON.stringify(String(value));
48
+ if (typeof value === "string") return JSON.stringify(value);
49
+ if (typeof value === "boolean") return value ? "true" : "false";
50
+ if (typeof value === "function") throw new Error("game-shapes: a function cannot be part of a shape (register it as a generator)");
51
+ if (ArrayBuffer.isView(value)) return canonicalJson(Array.from(value));
52
+ if (Array.isArray(value)) return `[${value.map((item) => item === void 0 ? "null" : canonicalJson(item)).join(",")}]`;
53
+ if (typeof value === "object") {
54
+ const record = value;
55
+ const keys = Object.keys(record).filter((key) => record[key] !== void 0).sort();
56
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`).join(",")}}`;
57
+ }
58
+ return "null";
59
+ }
60
+ function needsUint32(array) {
61
+ for (let i = array.length - 1; i >= 0; --i) if (array[i] >= 65535) return true;
62
+ return false;
63
+ }
64
+ var indexArray = (indices) => needsUint32(indices) ? new Uint32Array(indices) : new Uint16Array(indices);
65
+ function pack(type, parameters, a) {
66
+ return {
67
+ type,
68
+ parameters,
69
+ positions: new Float32Array(a.vertices),
70
+ normals: new Float32Array(a.normals),
71
+ uvs: new Float32Array(a.uvs),
72
+ ...a.indices ? { indices: indexArray(a.indices) } : {},
73
+ groups: a.groups
74
+ };
75
+ }
76
+ var normalize3 = (x, y, z) => {
77
+ const length = Math.sqrt(x * x + y * y + z * z);
78
+ const s = 1 / (length || 1);
79
+ return [x * s, y * s, z * s];
80
+ };
81
+ function box(width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1) {
82
+ const parameters = { width, height, depth, widthSegments, heightSegments, depthSegments };
83
+ widthSegments = Math.floor(widthSegments);
84
+ heightSegments = Math.floor(heightSegments);
85
+ depthSegments = Math.floor(depthSegments);
86
+ const indices = [];
87
+ const vertices = [];
88
+ const normals = [];
89
+ const uvs = [];
90
+ const groups = [];
91
+ let numberOfVertices = 0;
92
+ let groupStart = 0;
93
+ const buildPlane = (u, v, w, udir, vdir, width2, height2, depth2, gridX, gridY, materialIndex) => {
94
+ const segmentWidth = width2 / gridX;
95
+ const segmentHeight = height2 / gridY;
96
+ const widthHalf = width2 / 2;
97
+ const heightHalf = height2 / 2;
98
+ const depthHalf = depth2 / 2;
99
+ const gridX1 = gridX + 1;
100
+ const gridY1 = gridY + 1;
101
+ let vertexCounter = 0;
102
+ let groupCount = 0;
103
+ const vector = { x: 0, y: 0, z: 0 };
104
+ for (let iy = 0; iy < gridY1; iy++) {
105
+ const y = iy * segmentHeight - heightHalf;
106
+ for (let ix = 0; ix < gridX1; ix++) {
107
+ const x = ix * segmentWidth - widthHalf;
108
+ vector[u] = x * udir;
109
+ vector[v] = y * vdir;
110
+ vector[w] = depthHalf;
111
+ vertices.push(vector.x, vector.y, vector.z);
112
+ vector[u] = 0;
113
+ vector[v] = 0;
114
+ vector[w] = depth2 > 0 ? 1 : -1;
115
+ normals.push(vector.x, vector.y, vector.z);
116
+ uvs.push(ix / gridX);
117
+ uvs.push(1 - iy / gridY);
118
+ vertexCounter += 1;
119
+ }
120
+ }
121
+ for (let iy = 0; iy < gridY; iy++) {
122
+ for (let ix = 0; ix < gridX; ix++) {
123
+ const a = numberOfVertices + ix + gridX1 * iy;
124
+ const b = numberOfVertices + ix + gridX1 * (iy + 1);
125
+ const c = numberOfVertices + (ix + 1) + gridX1 * (iy + 1);
126
+ const d = numberOfVertices + (ix + 1) + gridX1 * iy;
127
+ indices.push(a, b, d);
128
+ indices.push(b, c, d);
129
+ groupCount += 6;
130
+ }
131
+ }
132
+ groups.push({ start: groupStart, count: groupCount, materialIndex });
133
+ groupStart += groupCount;
134
+ numberOfVertices += vertexCounter;
135
+ };
136
+ buildPlane("z", "y", "x", -1, -1, depth, height, width, depthSegments, heightSegments, 0);
137
+ buildPlane("z", "y", "x", 1, -1, depth, height, -width, depthSegments, heightSegments, 1);
138
+ buildPlane("x", "z", "y", 1, 1, width, depth, height, widthSegments, depthSegments, 2);
139
+ buildPlane("x", "z", "y", 1, -1, width, depth, -height, widthSegments, depthSegments, 3);
140
+ buildPlane("x", "y", "z", 1, -1, width, height, depth, widthSegments, heightSegments, 4);
141
+ buildPlane("x", "y", "z", -1, -1, width, height, -depth, widthSegments, heightSegments, 5);
142
+ return pack("BoxGeometry", parameters, { vertices, normals, uvs, indices, groups });
143
+ }
144
+ function cylinderArrays(radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength) {
145
+ radialSegments = Math.floor(radialSegments);
146
+ heightSegments = Math.floor(heightSegments);
147
+ const indices = [];
148
+ const vertices = [];
149
+ const normals = [];
150
+ const uvs = [];
151
+ const groups = [];
152
+ let index = 0;
153
+ const indexArray2 = [];
154
+ const halfHeight = height / 2;
155
+ let groupStart = 0;
156
+ const generateTorso = () => {
157
+ let groupCount = 0;
158
+ const slope = (radiusBottom - radiusTop) / height;
159
+ for (let y = 0; y <= heightSegments; y++) {
160
+ const indexRow = [];
161
+ const v = y / heightSegments;
162
+ const radius = v * (radiusBottom - radiusTop) + radiusTop;
163
+ for (let x = 0; x <= radialSegments; x++) {
164
+ const u = x / radialSegments;
165
+ const theta = u * thetaLength + thetaStart;
166
+ const sinTheta = Math.sin(theta);
167
+ const cosTheta = Math.cos(theta);
168
+ vertices.push(radius * sinTheta, -v * height + halfHeight, radius * cosTheta);
169
+ const n = normalize3(sinTheta, slope, cosTheta);
170
+ normals.push(n[0], n[1], n[2]);
171
+ uvs.push(u, 1 - v);
172
+ indexRow.push(index++);
173
+ }
174
+ indexArray2.push(indexRow);
175
+ }
176
+ for (let x = 0; x < radialSegments; x++) {
177
+ for (let y = 0; y < heightSegments; y++) {
178
+ const a = indexArray2[y][x];
179
+ const b = indexArray2[y + 1][x];
180
+ const c = indexArray2[y + 1][x + 1];
181
+ const d = indexArray2[y][x + 1];
182
+ indices.push(a, b, d);
183
+ indices.push(b, c, d);
184
+ groupCount += 6;
185
+ }
186
+ }
187
+ groups.push({ start: groupStart, count: groupCount, materialIndex: 0 });
188
+ groupStart += groupCount;
189
+ };
190
+ const generateCap = (top) => {
191
+ const centerIndexStart = index;
192
+ let groupCount = 0;
193
+ const radius = top === true ? radiusTop : radiusBottom;
194
+ const sign2 = top === true ? 1 : -1;
195
+ for (let x = 1; x <= radialSegments; x++) {
196
+ vertices.push(0, halfHeight * sign2, 0);
197
+ normals.push(0, sign2, 0);
198
+ uvs.push(0.5, 0.5);
199
+ index++;
200
+ }
201
+ const centerIndexEnd = index;
202
+ for (let x = 0; x <= radialSegments; x++) {
203
+ const u = x / radialSegments;
204
+ const theta = u * thetaLength + thetaStart;
205
+ const cosTheta = Math.cos(theta);
206
+ const sinTheta = Math.sin(theta);
207
+ vertices.push(radius * sinTheta, halfHeight * sign2, radius * cosTheta);
208
+ normals.push(0, sign2, 0);
209
+ uvs.push(cosTheta * 0.5 + 0.5, sinTheta * 0.5 * sign2 + 0.5);
210
+ index++;
211
+ }
212
+ for (let x = 0; x < radialSegments; x++) {
213
+ const c = centerIndexStart + x;
214
+ const i = centerIndexEnd + x;
215
+ if (top === true) indices.push(i, i + 1, c);
216
+ else indices.push(i + 1, i, c);
217
+ groupCount += 3;
218
+ }
219
+ groups.push({ start: groupStart, count: groupCount, materialIndex: top === true ? 1 : 2 });
220
+ groupStart += groupCount;
221
+ };
222
+ generateTorso();
223
+ if (openEnded === false) {
224
+ if (radiusTop > 0) generateCap(true);
225
+ if (radiusBottom > 0) generateCap(false);
226
+ }
227
+ return { vertices, normals, uvs, indices, groups };
228
+ }
229
+ function cylinder(radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2) {
230
+ const parameters = { radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength };
231
+ return pack("CylinderGeometry", parameters, cylinderArrays(radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength));
232
+ }
233
+ function cone(radius = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2) {
234
+ const parameters = { radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength };
235
+ return pack("ConeGeometry", parameters, cylinderArrays(0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength));
236
+ }
237
+ function sphere(radius = 1, widthSegments = 32, heightSegments = 16, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI) {
238
+ const parameters = { radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength };
239
+ widthSegments = Math.max(3, Math.floor(widthSegments));
240
+ heightSegments = Math.max(2, Math.floor(heightSegments));
241
+ const thetaEnd = Math.min(thetaStart + thetaLength, Math.PI);
242
+ let index = 0;
243
+ const grid = [];
244
+ const indices = [];
245
+ const vertices = [];
246
+ const normals = [];
247
+ const uvs = [];
248
+ for (let iy = 0; iy <= heightSegments; iy++) {
249
+ const verticesRow = [];
250
+ const v = iy / heightSegments;
251
+ let uOffset = 0;
252
+ if (iy === 0 && thetaStart === 0) uOffset = 0.5 / widthSegments;
253
+ else if (iy === heightSegments && thetaEnd === Math.PI) uOffset = -0.5 / widthSegments;
254
+ for (let ix = 0; ix <= widthSegments; ix++) {
255
+ const u = ix / widthSegments;
256
+ const x = -radius * Math.cos(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength);
257
+ const y = radius * Math.cos(thetaStart + v * thetaLength);
258
+ const z = radius * Math.sin(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength);
259
+ vertices.push(x, y, z);
260
+ const n = normalize3(x, y, z);
261
+ normals.push(n[0], n[1], n[2]);
262
+ uvs.push(u + uOffset, 1 - v);
263
+ verticesRow.push(index++);
264
+ }
265
+ grid.push(verticesRow);
266
+ }
267
+ for (let iy = 0; iy < heightSegments; iy++) {
268
+ for (let ix = 0; ix < widthSegments; ix++) {
269
+ const a = grid[iy][ix + 1];
270
+ const b = grid[iy][ix];
271
+ const c = grid[iy + 1][ix];
272
+ const d = grid[iy + 1][ix + 1];
273
+ if (iy !== 0 || thetaStart > 0) indices.push(a, b, d);
274
+ if (iy !== heightSegments - 1 || thetaEnd < Math.PI) indices.push(b, c, d);
275
+ }
276
+ }
277
+ return pack("SphereGeometry", parameters, { vertices, normals, uvs, indices, groups: [] });
278
+ }
279
+ function plane(width = 1, height = 1, widthSegments = 1, heightSegments = 1) {
280
+ const parameters = { width, height, widthSegments, heightSegments };
281
+ const widthHalf = width / 2;
282
+ const heightHalf = height / 2;
283
+ const gridX = Math.floor(widthSegments);
284
+ const gridY = Math.floor(heightSegments);
285
+ const gridX1 = gridX + 1;
286
+ const gridY1 = gridY + 1;
287
+ const segmentWidth = width / gridX;
288
+ const segmentHeight = height / gridY;
289
+ const indices = [];
290
+ const vertices = [];
291
+ const normals = [];
292
+ const uvs = [];
293
+ for (let iy = 0; iy < gridY1; iy++) {
294
+ const y = iy * segmentHeight - heightHalf;
295
+ for (let ix = 0; ix < gridX1; ix++) {
296
+ const x = ix * segmentWidth - widthHalf;
297
+ vertices.push(x, -y, 0);
298
+ normals.push(0, 0, 1);
299
+ uvs.push(ix / gridX);
300
+ uvs.push(1 - iy / gridY);
301
+ }
302
+ }
303
+ for (let iy = 0; iy < gridY; iy++) {
304
+ for (let ix = 0; ix < gridX; ix++) {
305
+ const a = ix + gridX1 * iy;
306
+ const b = ix + gridX1 * (iy + 1);
307
+ const c = ix + 1 + gridX1 * (iy + 1);
308
+ const d = ix + 1 + gridX1 * iy;
309
+ indices.push(a, b, d);
310
+ indices.push(b, c, d);
311
+ }
312
+ }
313
+ return pack("PlaneGeometry", parameters, { vertices, normals, uvs, indices, groups: [] });
314
+ }
315
+ function circle(radius = 1, segments = 32, thetaStart = 0, thetaLength = Math.PI * 2) {
316
+ const parameters = { radius, segments, thetaStart, thetaLength };
317
+ segments = Math.max(3, segments);
318
+ const indices = [];
319
+ const vertices = [];
320
+ const normals = [];
321
+ const uvs = [];
322
+ vertices.push(0, 0, 0);
323
+ normals.push(0, 0, 1);
324
+ uvs.push(0.5, 0.5);
325
+ for (let s = 0, i = 3; s <= segments; s++, i += 3) {
326
+ const segment = thetaStart + s / segments * thetaLength;
327
+ vertices.push(radius * Math.cos(segment), radius * Math.sin(segment), 0);
328
+ normals.push(0, 0, 1);
329
+ uvs.push((vertices[i] / radius + 1) / 2, (vertices[i + 1] / radius + 1) / 2);
330
+ }
331
+ for (let i = 1; i <= segments; i++) indices.push(i, i + 1, 0);
332
+ return pack("CircleGeometry", parameters, { vertices, normals, uvs, indices, groups: [] });
333
+ }
334
+ function ring(innerRadius = 0.5, outerRadius = 1, thetaSegments = 32, phiSegments = 1, thetaStart = 0, thetaLength = Math.PI * 2) {
335
+ const parameters = { innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength };
336
+ thetaSegments = Math.max(3, thetaSegments);
337
+ phiSegments = Math.max(1, phiSegments);
338
+ const indices = [];
339
+ const vertices = [];
340
+ const normals = [];
341
+ const uvs = [];
342
+ let radius = innerRadius;
343
+ const radiusStep = (outerRadius - innerRadius) / phiSegments;
344
+ for (let j = 0; j <= phiSegments; j++) {
345
+ for (let i = 0; i <= thetaSegments; i++) {
346
+ const segment = thetaStart + i / thetaSegments * thetaLength;
347
+ const x = radius * Math.cos(segment);
348
+ const y = radius * Math.sin(segment);
349
+ vertices.push(x, y, 0);
350
+ normals.push(0, 0, 1);
351
+ uvs.push((x / outerRadius + 1) / 2, (y / outerRadius + 1) / 2);
352
+ }
353
+ radius += radiusStep;
354
+ }
355
+ for (let j = 0; j < phiSegments; j++) {
356
+ const thetaSegmentLevel = j * (thetaSegments + 1);
357
+ for (let i = 0; i < thetaSegments; i++) {
358
+ const segment = i + thetaSegmentLevel;
359
+ const a = segment;
360
+ const b = segment + thetaSegments + 1;
361
+ const c = segment + thetaSegments + 2;
362
+ const d = segment + 1;
363
+ indices.push(a, b, d);
364
+ indices.push(b, c, d);
365
+ }
366
+ }
367
+ return pack("RingGeometry", parameters, { vertices, normals, uvs, indices, groups: [] });
368
+ }
369
+ function lathe(points, segments = 12, phiStart = 0, phiLength = Math.PI * 2) {
370
+ const parameters = { points: points.map(([x, y]) => ({ x, y })), segments, phiStart, phiLength };
371
+ segments = Math.floor(segments);
372
+ phiLength = Math.max(0, Math.min(Math.PI * 2, phiLength));
373
+ const indices = [];
374
+ const vertices = [];
375
+ const uvs = [];
376
+ const initNormals = [];
377
+ const normals = [];
378
+ const inverseSegments = 1 / segments;
379
+ const normal = { x: 0, y: 0, z: 0 };
380
+ const curNormal = { x: 0, y: 0, z: 0 };
381
+ const prevNormal = { x: 0, y: 0, z: 0 };
382
+ let dx = 0;
383
+ let dy = 0;
384
+ const last = points.length - 1;
385
+ const px = (j) => points[j][0];
386
+ const py = (j) => points[j][1];
387
+ const setNormalized = () => {
388
+ const n = normalize3(normal.x, normal.y, normal.z);
389
+ normal.x = n[0];
390
+ normal.y = n[1];
391
+ normal.z = n[2];
392
+ };
393
+ for (let j = 0; j <= last; j++) {
394
+ if (j === 0) {
395
+ dx = px(j + 1) - px(j);
396
+ dy = py(j + 1) - py(j);
397
+ normal.x = dy * 1;
398
+ normal.y = -dx;
399
+ normal.z = dy * 0;
400
+ prevNormal.x = normal.x;
401
+ prevNormal.y = normal.y;
402
+ prevNormal.z = normal.z;
403
+ setNormalized();
404
+ initNormals.push(normal.x, normal.y, normal.z);
405
+ } else if (j === last) {
406
+ initNormals.push(prevNormal.x, prevNormal.y, prevNormal.z);
407
+ } else {
408
+ dx = px(j + 1) - px(j);
409
+ dy = py(j + 1) - py(j);
410
+ normal.x = dy * 1;
411
+ normal.y = -dx;
412
+ normal.z = dy * 0;
413
+ curNormal.x = normal.x;
414
+ curNormal.y = normal.y;
415
+ curNormal.z = normal.z;
416
+ normal.x += prevNormal.x;
417
+ normal.y += prevNormal.y;
418
+ normal.z += prevNormal.z;
419
+ setNormalized();
420
+ initNormals.push(normal.x, normal.y, normal.z);
421
+ prevNormal.x = curNormal.x;
422
+ prevNormal.y = curNormal.y;
423
+ prevNormal.z = curNormal.z;
424
+ }
425
+ }
426
+ for (let i = 0; i <= segments; i++) {
427
+ const phi = phiStart + i * inverseSegments * phiLength;
428
+ const sin = Math.sin(phi);
429
+ const cos = Math.cos(phi);
430
+ for (let j = 0; j <= last; j++) {
431
+ vertices.push(px(j) * sin, py(j), px(j) * cos);
432
+ uvs.push(i / segments, j / (points.length - 1));
433
+ const x = initNormals[3 * j + 0] * sin;
434
+ const y = initNormals[3 * j + 1];
435
+ const z = initNormals[3 * j + 0] * cos;
436
+ normals.push(x, y, z);
437
+ }
438
+ }
439
+ for (let i = 0; i < segments; i++) {
440
+ for (let j = 0; j < points.length - 1; j++) {
441
+ const base = j + i * points.length;
442
+ const a = base;
443
+ const b = base + points.length;
444
+ const c = base + points.length + 1;
445
+ const d = base + 1;
446
+ indices.push(a, b, d);
447
+ indices.push(c, d, b);
448
+ }
449
+ }
450
+ return pack("LatheGeometry", parameters, { vertices, normals, uvs, indices, groups: [] });
451
+ }
452
+ function torus(radius = 1, tube2 = 0.4, radialSegments = 12, tubularSegments = 48, arc = Math.PI * 2) {
453
+ const parameters = { radius, tube: tube2, radialSegments, tubularSegments, arc };
454
+ radialSegments = Math.floor(radialSegments);
455
+ tubularSegments = Math.floor(tubularSegments);
456
+ const indices = [];
457
+ const vertices = [];
458
+ const normals = [];
459
+ const uvs = [];
460
+ for (let j = 0; j <= radialSegments; j++) {
461
+ for (let i = 0; i <= tubularSegments; i++) {
462
+ const u = i / tubularSegments * arc;
463
+ const v = j / radialSegments * Math.PI * 2;
464
+ const x = (radius + tube2 * Math.cos(v)) * Math.cos(u);
465
+ const y = (radius + tube2 * Math.cos(v)) * Math.sin(u);
466
+ const z = tube2 * Math.sin(v);
467
+ vertices.push(x, y, z);
468
+ const cx = radius * Math.cos(u);
469
+ const cy = radius * Math.sin(u);
470
+ const n = normalize3(x - cx, y - cy, z - 0);
471
+ normals.push(n[0], n[1], n[2]);
472
+ uvs.push(i / tubularSegments);
473
+ uvs.push(j / radialSegments);
474
+ }
475
+ }
476
+ for (let j = 1; j <= radialSegments; j++) {
477
+ for (let i = 1; i <= tubularSegments; i++) {
478
+ const a = (tubularSegments + 1) * j + i - 1;
479
+ const b = (tubularSegments + 1) * (j - 1) + i - 1;
480
+ const c = (tubularSegments + 1) * (j - 1) + i;
481
+ const d = (tubularSegments + 1) * j + i;
482
+ indices.push(a, b, d);
483
+ indices.push(b, c, d);
484
+ }
485
+ }
486
+ return pack("TorusGeometry", parameters, { vertices, normals, uvs, indices, groups: [] });
487
+ }
488
+ function difference(size, subtract) {
489
+ const [w, h, d] = size;
490
+ const hw = w / 2;
491
+ const hh = h / 2;
492
+ const hd = d / 2;
493
+ const holes = subtract.map((hole) => ({ x0: Math.max(-hw, Math.min(hole.min[0], hole.max[0])), x1: Math.min(hw, Math.max(hole.min[0], hole.max[0])), y0: Math.max(-hh, Math.min(hole.min[1], hole.max[1])), y1: Math.min(hh, Math.max(hole.min[1], hole.max[1])) })).filter((hole) => hole.x1 > hole.x0 && hole.y1 > hole.y0);
494
+ const cuts = (lo, hi, values) => [.../* @__PURE__ */ new Set([lo, hi, ...values.filter((v) => v > lo && v < hi)])].sort((a, b) => a - b);
495
+ const xs = cuts(-hw, hw, holes.flatMap((hole) => [hole.x0, hole.x1]));
496
+ const ys = cuts(-hh, hh, holes.flatMap((hole) => [hole.y0, hole.y1]));
497
+ const nx = xs.length - 1;
498
+ const ny = ys.length - 1;
499
+ const solid = (i, j) => {
500
+ if (i < 0 || j < 0 || i >= nx || j >= ny) return false;
501
+ const cx = (xs[i] + xs[i + 1]) / 2;
502
+ const cy = (ys[j] + ys[j + 1]) / 2;
503
+ return !holes.some((hole) => cx > hole.x0 && cx < hole.x1 && cy > hole.y0 && cy < hole.y1);
504
+ };
505
+ const positions = [];
506
+ const normals = [];
507
+ const uvs = [];
508
+ const indices = [];
509
+ const quad = (corners, normal, uv) => {
510
+ const base = positions.length / 3;
511
+ for (let k = 0; k < 4; k++) {
512
+ positions.push(...corners[k]);
513
+ normals.push(...normal);
514
+ uvs.push(...uv[k]);
515
+ }
516
+ indices.push(base, base + 1, base + 2, base, base + 2, base + 3);
517
+ };
518
+ const fu = (x) => (x + hw) / w;
519
+ const fv = (y) => (y + hh) / h;
520
+ for (let j = 0; j < ny; j++) {
521
+ for (let i = 0; i < nx; i++) {
522
+ if (!solid(i, j)) continue;
523
+ const x0 = xs[i];
524
+ const x1 = xs[i + 1];
525
+ const y0 = ys[j];
526
+ const y1 = ys[j + 1];
527
+ quad([[x0, y0, hd], [x1, y0, hd], [x1, y1, hd], [x0, y1, hd]], [0, 0, 1], [[fu(x0), fv(y0)], [fu(x1), fv(y0)], [fu(x1), fv(y1)], [fu(x0), fv(y1)]]);
528
+ quad([[x1, y0, -hd], [x0, y0, -hd], [x0, y1, -hd], [x1, y1, -hd]], [0, 0, -1], [[1 - fu(x1), fv(y0)], [1 - fu(x0), fv(y0)], [1 - fu(x0), fv(y1)], [1 - fu(x1), fv(y1)]]);
529
+ const zu = (z) => (z + hd) / d;
530
+ if (!solid(i - 1, j)) quad([[x0, y0, -hd], [x0, y0, hd], [x0, y1, hd], [x0, y1, -hd]], [-1, 0, 0], [[zu(-hd), fv(y0)], [zu(hd), fv(y0)], [zu(hd), fv(y1)], [zu(-hd), fv(y1)]]);
531
+ if (!solid(i + 1, j)) quad([[x1, y0, hd], [x1, y0, -hd], [x1, y1, -hd], [x1, y1, hd]], [1, 0, 0], [[zu(hd), fv(y0)], [zu(-hd), fv(y0)], [zu(-hd), fv(y1)], [zu(hd), fv(y1)]]);
532
+ if (!solid(i, j - 1)) quad([[x0, y0, -hd], [x1, y0, -hd], [x1, y0, hd], [x0, y0, hd]], [0, -1, 0], [[fu(x0), zu(-hd)], [fu(x1), zu(-hd)], [fu(x1), zu(hd)], [fu(x0), zu(hd)]]);
533
+ if (!solid(i, j + 1)) quad([[x0, y1, hd], [x1, y1, hd], [x1, y1, -hd], [x0, y1, -hd]], [0, 1, 0], [[fu(x0), zu(hd)], [fu(x1), zu(hd)], [fu(x1), zu(-hd)], [fu(x0), zu(-hd)]]);
534
+ }
535
+ }
536
+ return {
537
+ type: "BufferGeometry",
538
+ parameters: { size: [w, h, d], subtract: holes.map((hole) => ({ min: [hole.x0, hole.y0], max: [hole.x1, hole.y1] })) },
539
+ positions: new Float32Array(positions),
540
+ normals: new Float32Array(normals),
541
+ uvs: new Float32Array(uvs),
542
+ indices: indexArray(indices),
543
+ groups: []
544
+ };
545
+ }
546
+ var Earcut = {
547
+ triangulate: function(data, holeIndices, dim = 2) {
548
+ const hasHoles = holeIndices && holeIndices.length;
549
+ const outerLen = hasHoles ? holeIndices[0] * dim : data.length;
550
+ let outerNode = linkedList(data, 0, outerLen, dim, true);
551
+ const triangles = [];
552
+ if (!outerNode || outerNode.next === outerNode.prev) return triangles;
553
+ let minX, minY, maxX, maxY, x, y, invSize;
554
+ if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
555
+ if (data.length > 80 * dim) {
556
+ minX = maxX = data[0];
557
+ minY = maxY = data[1];
558
+ for (let i = dim; i < outerLen; i += dim) {
559
+ x = data[i];
560
+ y = data[i + 1];
561
+ if (x < minX) minX = x;
562
+ if (y < minY) minY = y;
563
+ if (x > maxX) maxX = x;
564
+ if (y > maxY) maxY = y;
565
+ }
566
+ invSize = Math.max(maxX - minX, maxY - minY);
567
+ invSize = invSize !== 0 ? 32767 / invSize : 0;
568
+ }
569
+ earcutLinked(outerNode, triangles, dim, minX, minY, invSize, 0);
570
+ return triangles;
571
+ }
572
+ };
573
+ function linkedList(data, start, end, dim, clockwise) {
574
+ let i, last;
575
+ if (clockwise === signedArea(data, start, end, dim) > 0) {
576
+ for (i = start; i < end; i += dim) last = insertNode(i, data[i], data[i + 1], last);
577
+ } else {
578
+ for (i = end - dim; i >= start; i -= dim) last = insertNode(i, data[i], data[i + 1], last);
579
+ }
580
+ if (last && equals(last, last.next)) {
581
+ removeNode(last);
582
+ last = last.next;
583
+ }
584
+ return last;
585
+ }
586
+ function filterPoints(start, end) {
587
+ if (!start) return start;
588
+ if (!end) end = start;
589
+ let p = start, again;
590
+ do {
591
+ again = false;
592
+ if (!p.steiner && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) {
593
+ removeNode(p);
594
+ p = end = p.prev;
595
+ if (p === p.next) break;
596
+ again = true;
597
+ } else {
598
+ p = p.next;
599
+ }
600
+ } while (again || p !== end);
601
+ return end;
602
+ }
603
+ function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
604
+ if (!ear) return;
605
+ if (!pass && invSize) indexCurve(ear, minX, minY, invSize);
606
+ let stop = ear, prev, next;
607
+ while (ear.prev !== ear.next) {
608
+ prev = ear.prev;
609
+ next = ear.next;
610
+ if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) {
611
+ triangles.push(prev.i / dim | 0);
612
+ triangles.push(ear.i / dim | 0);
613
+ triangles.push(next.i / dim | 0);
614
+ removeNode(ear);
615
+ ear = next.next;
616
+ stop = next.next;
617
+ continue;
618
+ }
619
+ ear = next;
620
+ if (ear === stop) {
621
+ if (!pass) {
622
+ earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1);
623
+ } else if (pass === 1) {
624
+ ear = cureLocalIntersections(filterPoints(ear), triangles, dim);
625
+ earcutLinked(ear, triangles, dim, minX, minY, invSize, 2);
626
+ } else if (pass === 2) {
627
+ splitEarcut(ear, triangles, dim, minX, minY, invSize);
628
+ }
629
+ break;
630
+ }
631
+ }
632
+ }
633
+ function isEar(ear) {
634
+ const a = ear.prev, b = ear, c = ear.next;
635
+ if (area(a, b, c) >= 0) return false;
636
+ const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
637
+ const x0 = ax < bx ? ax < cx ? ax : cx : bx < cx ? bx : cx, y0 = ay < by ? ay < cy ? ay : cy : by < cy ? by : cy, x1 = ax > bx ? ax > cx ? ax : cx : bx > cx ? bx : cx, y1 = ay > by ? ay > cy ? ay : cy : by > cy ? by : cy;
638
+ let p = c.next;
639
+ while (p !== a) {
640
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
641
+ p = p.next;
642
+ }
643
+ return true;
644
+ }
645
+ function isEarHashed(ear, minX, minY, invSize) {
646
+ const a = ear.prev, b = ear, c = ear.next;
647
+ if (area(a, b, c) >= 0) return false;
648
+ const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
649
+ const x0 = ax < bx ? ax < cx ? ax : cx : bx < cx ? bx : cx, y0 = ay < by ? ay < cy ? ay : cy : by < cy ? by : cy, x1 = ax > bx ? ax > cx ? ax : cx : bx > cx ? bx : cx, y1 = ay > by ? ay > cy ? ay : cy : by > cy ? by : cy;
650
+ const minZ = zOrder(x0, y0, minX, minY, invSize), maxZ = zOrder(x1, y1, minX, minY, invSize);
651
+ let p = ear.prevZ, n = ear.nextZ;
652
+ while (p && p.z >= minZ && n && n.z <= maxZ) {
653
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
654
+ p = p.prevZ;
655
+ if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
656
+ n = n.nextZ;
657
+ }
658
+ while (p && p.z >= minZ) {
659
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
660
+ p = p.prevZ;
661
+ }
662
+ while (n && n.z <= maxZ) {
663
+ if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
664
+ n = n.nextZ;
665
+ }
666
+ return true;
667
+ }
668
+ function cureLocalIntersections(start, triangles, dim) {
669
+ let p = start;
670
+ do {
671
+ const a = p.prev, b = p.next.next;
672
+ if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {
673
+ triangles.push(a.i / dim | 0);
674
+ triangles.push(p.i / dim | 0);
675
+ triangles.push(b.i / dim | 0);
676
+ removeNode(p);
677
+ removeNode(p.next);
678
+ p = start = b;
679
+ }
680
+ p = p.next;
681
+ } while (p !== start);
682
+ return filterPoints(p);
683
+ }
684
+ function splitEarcut(start, triangles, dim, minX, minY, invSize) {
685
+ let a = start;
686
+ do {
687
+ let b = a.next.next;
688
+ while (b !== a.prev) {
689
+ if (a.i !== b.i && isValidDiagonal(a, b)) {
690
+ let c = splitPolygon(a, b);
691
+ a = filterPoints(a, a.next);
692
+ c = filterPoints(c, c.next);
693
+ earcutLinked(a, triangles, dim, minX, minY, invSize, 0);
694
+ earcutLinked(c, triangles, dim, minX, minY, invSize, 0);
695
+ return;
696
+ }
697
+ b = b.next;
698
+ }
699
+ a = a.next;
700
+ } while (a !== start);
701
+ }
702
+ function eliminateHoles(data, holeIndices, outerNode, dim) {
703
+ const queue = [];
704
+ let i, len2, start, end, list2;
705
+ for (i = 0, len2 = holeIndices.length; i < len2; i++) {
706
+ start = holeIndices[i] * dim;
707
+ end = i < len2 - 1 ? holeIndices[i + 1] * dim : data.length;
708
+ list2 = linkedList(data, start, end, dim, false);
709
+ if (list2 === list2.next) list2.steiner = true;
710
+ queue.push(getLeftmost(list2));
711
+ }
712
+ queue.sort(compareX);
713
+ for (i = 0; i < queue.length; i++) {
714
+ outerNode = eliminateHole(queue[i], outerNode);
715
+ }
716
+ return outerNode;
717
+ }
718
+ function compareX(a, b) {
719
+ return a.x - b.x;
720
+ }
721
+ function eliminateHole(hole, outerNode) {
722
+ const bridge = findHoleBridge(hole, outerNode);
723
+ if (!bridge) {
724
+ return outerNode;
725
+ }
726
+ const bridgeReverse = splitPolygon(bridge, hole);
727
+ filterPoints(bridgeReverse, bridgeReverse.next);
728
+ return filterPoints(bridge, bridge.next);
729
+ }
730
+ function findHoleBridge(hole, outerNode) {
731
+ let p = outerNode, qx = -Infinity, m;
732
+ const hx = hole.x, hy = hole.y;
733
+ do {
734
+ if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
735
+ const x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
736
+ if (x <= hx && x > qx) {
737
+ qx = x;
738
+ m = p.x < p.next.x ? p : p.next;
739
+ if (x === hx) return m;
740
+ }
741
+ }
742
+ p = p.next;
743
+ } while (p !== outerNode);
744
+ if (!m) return null;
745
+ const stop = m, mx = m.x, my = m.y;
746
+ let tanMin = Infinity, tan;
747
+ p = m;
748
+ do {
749
+ if (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)) {
750
+ tan = Math.abs(hy - p.y) / (hx - p.x);
751
+ if (locallyInside(p, hole) && (tan < tanMin || tan === tanMin && (p.x > m.x || p.x === m.x && sectorContainsSector(m, p)))) {
752
+ m = p;
753
+ tanMin = tan;
754
+ }
755
+ }
756
+ p = p.next;
757
+ } while (p !== stop);
758
+ return m;
759
+ }
760
+ function sectorContainsSector(m, p) {
761
+ return area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0;
762
+ }
763
+ function indexCurve(start, minX, minY, invSize) {
764
+ let p = start;
765
+ do {
766
+ if (p.z === 0) p.z = zOrder(p.x, p.y, minX, minY, invSize);
767
+ p.prevZ = p.prev;
768
+ p.nextZ = p.next;
769
+ p = p.next;
770
+ } while (p !== start);
771
+ p.prevZ.nextZ = null;
772
+ p.prevZ = null;
773
+ sortLinked(p);
774
+ }
775
+ function sortLinked(list2) {
776
+ let i, p, q, e, tail, numMerges, pSize, qSize, inSize = 1;
777
+ do {
778
+ p = list2;
779
+ list2 = null;
780
+ tail = null;
781
+ numMerges = 0;
782
+ while (p) {
783
+ numMerges++;
784
+ q = p;
785
+ pSize = 0;
786
+ for (i = 0; i < inSize; i++) {
787
+ pSize++;
788
+ q = q.nextZ;
789
+ if (!q) break;
790
+ }
791
+ qSize = inSize;
792
+ while (pSize > 0 || qSize > 0 && q) {
793
+ if (pSize !== 0 && (qSize === 0 || !q || p.z <= q.z)) {
794
+ e = p;
795
+ p = p.nextZ;
796
+ pSize--;
797
+ } else {
798
+ e = q;
799
+ q = q.nextZ;
800
+ qSize--;
801
+ }
802
+ if (tail) tail.nextZ = e;
803
+ else list2 = e;
804
+ e.prevZ = tail;
805
+ tail = e;
806
+ }
807
+ p = q;
808
+ }
809
+ tail.nextZ = null;
810
+ inSize *= 2;
811
+ } while (numMerges > 1);
812
+ return list2;
813
+ }
814
+ function zOrder(x, y, minX, minY, invSize) {
815
+ x = (x - minX) * invSize | 0;
816
+ y = (y - minY) * invSize | 0;
817
+ x = (x | x << 8) & 16711935;
818
+ x = (x | x << 4) & 252645135;
819
+ x = (x | x << 2) & 858993459;
820
+ x = (x | x << 1) & 1431655765;
821
+ y = (y | y << 8) & 16711935;
822
+ y = (y | y << 4) & 252645135;
823
+ y = (y | y << 2) & 858993459;
824
+ y = (y | y << 1) & 1431655765;
825
+ return x | y << 1;
826
+ }
827
+ function getLeftmost(start) {
828
+ let p = start, leftmost = start;
829
+ do {
830
+ if (p.x < leftmost.x || p.x === leftmost.x && p.y < leftmost.y) leftmost = p;
831
+ p = p.next;
832
+ } while (p !== start);
833
+ return leftmost;
834
+ }
835
+ function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
836
+ 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);
837
+ }
838
+ function isValidDiagonal(a, b) {
839
+ return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) && // dones't intersect other edges
840
+ (locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible
841
+ (area(a.prev, a, b.prev) || area(a, b.prev, b)) || // does not create opposite-facing sectors
842
+ equals(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0);
843
+ }
844
+ function area(p, q, r) {
845
+ return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
846
+ }
847
+ function equals(p1, p2) {
848
+ return p1.x === p2.x && p1.y === p2.y;
849
+ }
850
+ function intersects(p1, q1, p2, q2) {
851
+ const o1 = sign(area(p1, q1, p2));
852
+ const o2 = sign(area(p1, q1, q2));
853
+ const o3 = sign(area(p2, q2, p1));
854
+ const o4 = sign(area(p2, q2, q1));
855
+ if (o1 !== o2 && o3 !== o4) return true;
856
+ if (o1 === 0 && onSegment(p1, p2, q1)) return true;
857
+ if (o2 === 0 && onSegment(p1, q2, q1)) return true;
858
+ if (o3 === 0 && onSegment(p2, p1, q2)) return true;
859
+ if (o4 === 0 && onSegment(p2, q1, q2)) return true;
860
+ return false;
861
+ }
862
+ function onSegment(p, q, r) {
863
+ 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);
864
+ }
865
+ function sign(num2) {
866
+ return num2 > 0 ? 1 : num2 < 0 ? -1 : 0;
867
+ }
868
+ function intersectsPolygon(a, b) {
869
+ let p = a;
870
+ do {
871
+ if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && intersects(p, p.next, a, b)) return true;
872
+ p = p.next;
873
+ } while (p !== a);
874
+ return false;
875
+ }
876
+ function locallyInside(a, b) {
877
+ 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;
878
+ }
879
+ function middleInside(a, b) {
880
+ let p = a, inside = false;
881
+ const px = (a.x + b.x) / 2, py = (a.y + b.y) / 2;
882
+ do {
883
+ if (p.y > py !== p.next.y > py && p.next.y !== p.y && px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x)
884
+ inside = !inside;
885
+ p = p.next;
886
+ } while (p !== a);
887
+ return inside;
888
+ }
889
+ function splitPolygon(a, b) {
890
+ const a2 = new Node(a.i, a.x, a.y), b2 = new Node(b.i, b.x, b.y), an = a.next, bp = b.prev;
891
+ a.next = b;
892
+ b.prev = a;
893
+ a2.next = an;
894
+ an.prev = a2;
895
+ b2.next = a2;
896
+ a2.prev = b2;
897
+ bp.next = b2;
898
+ b2.prev = bp;
899
+ return b2;
900
+ }
901
+ function insertNode(i, x, y, last) {
902
+ const p = new Node(i, x, y);
903
+ if (!last) {
904
+ p.prev = p;
905
+ p.next = p;
906
+ } else {
907
+ p.next = last.next;
908
+ p.prev = last;
909
+ last.next.prev = p;
910
+ last.next = p;
911
+ }
912
+ return p;
913
+ }
914
+ function removeNode(p) {
915
+ p.next.prev = p.prev;
916
+ p.prev.next = p.next;
917
+ if (p.prevZ) p.prevZ.nextZ = p.nextZ;
918
+ if (p.nextZ) p.nextZ.prevZ = p.prevZ;
919
+ }
920
+ function Node(i, x, y) {
921
+ this.i = i;
922
+ this.x = x;
923
+ this.y = y;
924
+ this.prev = null;
925
+ this.next = null;
926
+ this.z = 0;
927
+ this.prevZ = null;
928
+ this.nextZ = null;
929
+ this.steiner = false;
930
+ }
931
+ function signedArea(data, start, end, dim) {
932
+ let sum = 0;
933
+ for (let i = start, j = end - dim; i < end; i += dim) {
934
+ sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
935
+ j = i;
936
+ }
937
+ return sum;
938
+ }
939
+ var equals2 = (a, b) => a.x === b.x && a.y === b.y;
940
+ var linePoint = (v1, v2, t) => t === 1 ? { x: v2.x, y: v2.y } : { x: (v2.x - v1.x) * t + v1.x, y: (v2.y - v1.y) * t + v1.y };
941
+ function pathPoints(points) {
942
+ const out = [];
943
+ let last;
944
+ for (let i = 1; i < points.length; i++) {
945
+ const v1 = { x: points[i - 1][0], y: points[i - 1][1] };
946
+ const v2 = { x: points[i][0], y: points[i][1] };
947
+ for (let d = 0; d <= 1; d++) {
948
+ const point = linePoint(v1, v2, d / 1);
949
+ if (last && equals2(last, point)) continue;
950
+ out.push(point);
951
+ last = point;
952
+ }
953
+ }
954
+ return out;
955
+ }
956
+ function area2(contour) {
957
+ const n = contour.length;
958
+ let a = 0;
959
+ for (let p = n - 1, q = 0; q < n; p = q++) a += contour[p].x * contour[q].y - contour[q].x * contour[p].y;
960
+ return a * 0.5;
961
+ }
962
+ var isClockWise = (pts) => area2(pts) < 0;
963
+ function removeDupEndPts(points) {
964
+ const l = points.length;
965
+ if (l > 2 && equals2(points[l - 1], points[0])) points.pop();
966
+ }
967
+ function triangulateShape(contour, holes) {
968
+ const vertices = [];
969
+ const holeIndices = [];
970
+ const faces = [];
971
+ removeDupEndPts(contour);
972
+ for (const p of contour) vertices.push(p.x, p.y);
973
+ let holeIndex = contour.length;
974
+ holes.forEach(removeDupEndPts);
975
+ for (let i = 0; i < holes.length; i++) {
976
+ holeIndices.push(holeIndex);
977
+ holeIndex += holes[i].length;
978
+ for (const p of holes[i]) vertices.push(p.x, p.y);
979
+ }
980
+ const triangles = Earcut.triangulate(vertices, holeIndices);
981
+ for (let i = 0; i < triangles.length; i += 3) faces.push(triangles.slice(i, i + 3));
982
+ return faces;
983
+ }
984
+ function computeVertexNormals(positions, indices) {
985
+ const normals = new Float32Array(positions.length);
986
+ const get = (array, i) => [array[i * 3], array[i * 3 + 1], array[i * 3 + 2]];
987
+ const face = (vA, vB, vC) => {
988
+ const pA = get(positions, vA);
989
+ const pB = get(positions, vB);
990
+ const pC = get(positions, vC);
991
+ const cb = [pC[0] - pB[0], pC[1] - pB[1], pC[2] - pB[2]];
992
+ const ab = [pA[0] - pB[0], pA[1] - pB[1], pA[2] - pB[2]];
993
+ return [cb[1] * ab[2] - cb[2] * ab[1], cb[2] * ab[0] - cb[0] * ab[2], cb[0] * ab[1] - cb[1] * ab[0]];
994
+ };
995
+ const set = (i, x, y, z) => {
996
+ normals[i * 3] = x;
997
+ normals[i * 3 + 1] = y;
998
+ normals[i * 3 + 2] = z;
999
+ };
1000
+ if (indices) {
1001
+ for (let i = 0; i < indices.length; i += 3) {
1002
+ const vA = indices[i];
1003
+ const vB = indices[i + 1];
1004
+ const vC = indices[i + 2];
1005
+ const cb = face(vA, vB, vC);
1006
+ for (const v of [vA, vB, vC]) {
1007
+ const n = get(normals, v);
1008
+ set(v, n[0] + cb[0], n[1] + cb[1], n[2] + cb[2]);
1009
+ }
1010
+ }
1011
+ } else {
1012
+ for (let i = 0; i < positions.length / 3; i += 3) {
1013
+ const cb = face(i, i + 1, i + 2);
1014
+ set(i, cb[0], cb[1], cb[2]);
1015
+ set(i + 1, cb[0], cb[1], cb[2]);
1016
+ set(i + 2, cb[0], cb[1], cb[2]);
1017
+ }
1018
+ }
1019
+ for (let i = 0; i < normals.length / 3; i++) {
1020
+ const [x, y, z] = get(normals, i);
1021
+ const s = 1 / (Math.sqrt(x * x + y * y + z * z) || 1);
1022
+ set(i, x * s, y * s, z * s);
1023
+ }
1024
+ return normals;
1025
+ }
1026
+ function extrude(outline, depth = 1, steps = 1, bevel = void 0) {
1027
+ const parameters = { shape: outline, depth, steps, bevel: bevel ?? {} };
1028
+ const verticesArray = [];
1029
+ const uvArray = [];
1030
+ const groups = [];
1031
+ const placeholder = [];
1032
+ const bevelEnabled = bevel !== false;
1033
+ const spec = bevel === false || bevel === void 0 ? {} : bevel;
1034
+ let bevelThickness = spec.thickness !== void 0 ? spec.thickness : 0.2;
1035
+ let bevelSize = spec.size !== void 0 ? spec.size : bevelThickness - 0.1;
1036
+ let bevelOffset = spec.offset !== void 0 ? spec.offset : 0;
1037
+ let bevelSegments = spec.segments !== void 0 ? spec.segments : 3;
1038
+ if (!bevelEnabled) {
1039
+ bevelSegments = 0;
1040
+ bevelThickness = 0;
1041
+ bevelSize = 0;
1042
+ bevelOffset = 0;
1043
+ }
1044
+ let vertices = pathPoints(outline.outer);
1045
+ const holes = (outline.holes ?? []).map(pathPoints);
1046
+ const reverse = !isClockWise(vertices);
1047
+ if (reverse) {
1048
+ vertices = vertices.reverse();
1049
+ for (let h = 0; h < holes.length; h++) {
1050
+ const ahole = holes[h];
1051
+ if (isClockWise(ahole)) holes[h] = ahole.reverse();
1052
+ }
1053
+ }
1054
+ const faces = triangulateShape(vertices, holes);
1055
+ const contour = vertices;
1056
+ for (const ahole of holes) vertices = vertices.concat(ahole);
1057
+ const scalePt2 = (pt, vec, size) => ({ x: pt.x + vec.x * size, y: pt.y + vec.y * size });
1058
+ const vlen = vertices.length;
1059
+ const flen = faces.length;
1060
+ const getBevelVec = (inPt, inPrev, inNext) => {
1061
+ let vTransX;
1062
+ let vTransY;
1063
+ let shrinkBy;
1064
+ const vPrevX = inPt.x - inPrev.x;
1065
+ const vPrevY = inPt.y - inPrev.y;
1066
+ const vNextX = inNext.x - inPt.x;
1067
+ const vNextY = inNext.y - inPt.y;
1068
+ const vPrevLensq = vPrevX * vPrevX + vPrevY * vPrevY;
1069
+ const collinear0 = vPrevX * vNextY - vPrevY * vNextX;
1070
+ if (Math.abs(collinear0) > Number.EPSILON) {
1071
+ const vPrevLen = Math.sqrt(vPrevLensq);
1072
+ const vNextLen = Math.sqrt(vNextX * vNextX + vNextY * vNextY);
1073
+ const ptPrevShiftX = inPrev.x - vPrevY / vPrevLen;
1074
+ const ptPrevShiftY = inPrev.y + vPrevX / vPrevLen;
1075
+ const ptNextShiftX = inNext.x - vNextY / vNextLen;
1076
+ const ptNextShiftY = inNext.y + vNextX / vNextLen;
1077
+ const sf = ((ptNextShiftX - ptPrevShiftX) * vNextY - (ptNextShiftY - ptPrevShiftY) * vNextX) / (vPrevX * vNextY - vPrevY * vNextX);
1078
+ vTransX = ptPrevShiftX + vPrevX * sf - inPt.x;
1079
+ vTransY = ptPrevShiftY + vPrevY * sf - inPt.y;
1080
+ const vTransLensq = vTransX * vTransX + vTransY * vTransY;
1081
+ if (vTransLensq <= 2) return { x: vTransX, y: vTransY };
1082
+ shrinkBy = Math.sqrt(vTransLensq / 2);
1083
+ } else {
1084
+ let directionEq = false;
1085
+ if (vPrevX > Number.EPSILON) {
1086
+ if (vNextX > Number.EPSILON) directionEq = true;
1087
+ } else if (vPrevX < -Number.EPSILON) {
1088
+ if (vNextX < -Number.EPSILON) directionEq = true;
1089
+ } else if (Math.sign(vPrevY) === Math.sign(vNextY)) {
1090
+ directionEq = true;
1091
+ }
1092
+ if (directionEq) {
1093
+ vTransX = -vPrevY;
1094
+ vTransY = vPrevX;
1095
+ shrinkBy = Math.sqrt(vPrevLensq);
1096
+ } else {
1097
+ vTransX = vPrevX;
1098
+ vTransY = vPrevY;
1099
+ shrinkBy = Math.sqrt(vPrevLensq / 2);
1100
+ }
1101
+ }
1102
+ return { x: vTransX / shrinkBy, y: vTransY / shrinkBy };
1103
+ };
1104
+ const movements = (ring2) => {
1105
+ const out = [];
1106
+ for (let i = 0, il = ring2.length, j = il - 1, k = i + 1; i < il; i++, j++, k++) {
1107
+ if (j === il) j = 0;
1108
+ if (k === il) k = 0;
1109
+ out[i] = getBevelVec(ring2[i], ring2[j], ring2[k]);
1110
+ }
1111
+ return out;
1112
+ };
1113
+ const contourMovements = movements(contour);
1114
+ const holesMovements = [];
1115
+ let verticesMovements = contourMovements.concat();
1116
+ for (const ahole of holes) {
1117
+ const oneHoleMovements = movements(ahole);
1118
+ holesMovements.push(oneHoleMovements);
1119
+ verticesMovements = verticesMovements.concat(oneHoleMovements);
1120
+ }
1121
+ const v = (x, y, z) => {
1122
+ placeholder.push(x);
1123
+ placeholder.push(y);
1124
+ placeholder.push(z);
1125
+ };
1126
+ const bevelLayer = (b, zOf) => {
1127
+ const t = b / bevelSegments;
1128
+ const z = bevelThickness * Math.cos(t * Math.PI / 2);
1129
+ const bs2 = bevelSize * Math.sin(t * Math.PI / 2) + bevelOffset;
1130
+ for (let i = 0; i < contour.length; i++) {
1131
+ const vert = scalePt2(contour[i], contourMovements[i], bs2);
1132
+ v(vert.x, vert.y, zOf(z));
1133
+ }
1134
+ for (let h = 0; h < holes.length; h++) {
1135
+ const ahole = holes[h];
1136
+ const oneHoleMovements = holesMovements[h];
1137
+ for (let i = 0; i < ahole.length; i++) {
1138
+ const vert = scalePt2(ahole[i], oneHoleMovements[i], bs2);
1139
+ v(vert.x, vert.y, zOf(z));
1140
+ }
1141
+ }
1142
+ };
1143
+ for (let b = 0; b < bevelSegments; b++) bevelLayer(b, (z) => -z);
1144
+ const bs = bevelSize + bevelOffset;
1145
+ for (let i = 0; i < vlen; i++) {
1146
+ const vert = bevelEnabled ? scalePt2(vertices[i], verticesMovements[i], bs) : vertices[i];
1147
+ v(vert.x, vert.y, 0);
1148
+ }
1149
+ for (let s = 1; s <= steps; s++) {
1150
+ for (let i = 0; i < vlen; i++) {
1151
+ const vert = bevelEnabled ? scalePt2(vertices[i], verticesMovements[i], bs) : vertices[i];
1152
+ v(vert.x, vert.y, depth / steps * s);
1153
+ }
1154
+ }
1155
+ for (let b = bevelSegments - 1; b >= 0; b--) bevelLayer(b, (z) => depth + z);
1156
+ const addVertex = (index) => {
1157
+ verticesArray.push(placeholder[index * 3 + 0]);
1158
+ verticesArray.push(placeholder[index * 3 + 1]);
1159
+ verticesArray.push(placeholder[index * 3 + 2]);
1160
+ };
1161
+ const addUV = (x, y) => {
1162
+ uvArray.push(x);
1163
+ uvArray.push(y);
1164
+ };
1165
+ const at = (index, axis) => verticesArray[index * 3 + axis];
1166
+ const f3 = (a, b, c) => {
1167
+ addVertex(a);
1168
+ addVertex(b);
1169
+ addVertex(c);
1170
+ const nextIndex = verticesArray.length / 3;
1171
+ for (const index of [nextIndex - 3, nextIndex - 2, nextIndex - 1]) addUV(at(index, 0), at(index, 1));
1172
+ };
1173
+ const f4 = (a, b, c, d) => {
1174
+ addVertex(a);
1175
+ addVertex(b);
1176
+ addVertex(d);
1177
+ addVertex(b);
1178
+ addVertex(c);
1179
+ addVertex(d);
1180
+ const nextIndex = verticesArray.length / 3;
1181
+ const iA = nextIndex - 6;
1182
+ const iB = nextIndex - 3;
1183
+ const iC = nextIndex - 2;
1184
+ const iD = nextIndex - 1;
1185
+ const byX = Math.abs(at(iA, 1) - at(iB, 1)) < Math.abs(at(iA, 0) - at(iB, 0));
1186
+ const uv = (index) => [byX ? at(index, 0) : at(index, 1), 1 - at(index, 2)];
1187
+ const uvs = [uv(iA), uv(iB), uv(iC), uv(iD)];
1188
+ for (const k of [0, 1, 3, 1, 2, 3]) addUV(...uvs[k]);
1189
+ };
1190
+ let start = verticesArray.length / 3;
1191
+ if (bevelEnabled) {
1192
+ let offset = 0;
1193
+ for (let i = 0; i < flen; i++) {
1194
+ const face = faces[i];
1195
+ f3(face[2] + offset, face[1] + offset, face[0] + offset);
1196
+ }
1197
+ const layer = steps + bevelSegments * 2;
1198
+ offset = vlen * layer;
1199
+ for (let i = 0; i < flen; i++) {
1200
+ const face = faces[i];
1201
+ f3(face[0] + offset, face[1] + offset, face[2] + offset);
1202
+ }
1203
+ } else {
1204
+ for (let i = 0; i < flen; i++) {
1205
+ const face = faces[i];
1206
+ f3(face[2], face[1], face[0]);
1207
+ }
1208
+ for (let i = 0; i < flen; i++) {
1209
+ const face = faces[i];
1210
+ f3(face[0] + vlen * steps, face[1] + vlen * steps, face[2] + vlen * steps);
1211
+ }
1212
+ }
1213
+ groups.push({ start, count: verticesArray.length / 3 - start, materialIndex: 0 });
1214
+ start = verticesArray.length / 3;
1215
+ const sidewalls = (ring2, layeroffset2) => {
1216
+ let i = ring2.length;
1217
+ while (--i >= 0) {
1218
+ const j = i;
1219
+ let k = i - 1;
1220
+ if (k < 0) k = ring2.length - 1;
1221
+ for (let s = 0, sl = steps + bevelSegments * 2; s < sl; s++) {
1222
+ const slen1 = vlen * s;
1223
+ const slen2 = vlen * (s + 1);
1224
+ f4(layeroffset2 + j + slen1, layeroffset2 + k + slen1, layeroffset2 + k + slen2, layeroffset2 + j + slen2);
1225
+ }
1226
+ }
1227
+ };
1228
+ let layeroffset = 0;
1229
+ sidewalls(contour, layeroffset);
1230
+ layeroffset += contour.length;
1231
+ for (const ahole of holes) {
1232
+ sidewalls(ahole, layeroffset);
1233
+ layeroffset += ahole.length;
1234
+ }
1235
+ groups.push({ start, count: verticesArray.length / 3 - start, materialIndex: 1 });
1236
+ const positions = new Float32Array(verticesArray);
1237
+ return { type: "ExtrudeGeometry", parameters, positions, normals: computeVertexNormals(positions), uvs: new Float32Array(uvArray), groups };
1238
+ }
1239
+ var PARAMETER_KEYS = {
1240
+ box: ["size", "segments"],
1241
+ cylinder: ["radiusTop", "radiusBottom", "height", "radialSegments", "heightSegments", "openEnded", "thetaStart", "thetaLength"],
1242
+ cone: ["radius", "height", "radialSegments", "heightSegments", "openEnded", "thetaStart", "thetaLength"],
1243
+ sphere: ["radius", "widthSegments", "heightSegments", "phiStart", "phiLength", "thetaStart", "thetaLength"],
1244
+ plane: ["width", "height", "widthSegments", "heightSegments"],
1245
+ circle: ["radius", "segments", "thetaStart", "thetaLength"],
1246
+ ring: ["innerRadius", "outerRadius", "thetaSegments", "phiSegments", "thetaStart", "thetaLength"],
1247
+ lathe: ["points", "segments", "phiStart", "phiLength"],
1248
+ torus: ["radius", "tube", "radialSegments", "tubularSegments", "arc"],
1249
+ extrude: ["shape", "depth", "steps", "bevel"],
1250
+ difference: ["size", "subtract"],
1251
+ mesh: ["positions", "normals", "uvs", "indices"]
1252
+ };
1253
+ var SEGMENT_KEYS = {
1254
+ cylinder: ["radialSegments"],
1255
+ cone: ["radialSegments"],
1256
+ sphere: ["widthSegments", "heightSegments"],
1257
+ circle: ["segments"],
1258
+ ring: ["thetaSegments"],
1259
+ lathe: ["segments"],
1260
+ torus: ["radialSegments", "tubularSegments"]
1261
+ };
1262
+ var SEGMENT_DEFAULTS = { radialSegments: 32, widthSegments: 32, heightSegments: 16, segments: 12, thetaSegments: 32, tubularSegments: 48 };
1263
+ var segmentDefault = (kind, key) => kind === "circle" && key === "segments" ? 32 : kind === "torus" && key === "radialSegments" ? 12 : SEGMENT_DEFAULTS[key];
1264
+ function primitiveParameters(node, options = {}) {
1265
+ const out = {};
1266
+ const source = node;
1267
+ for (const key of PARAMETER_KEYS[node.kind]) if (source[key] !== void 0) out[key] = source[key];
1268
+ const detail = options.detail ?? 1;
1269
+ if (detail !== 1) {
1270
+ const floor = options.minSegments ?? 3;
1271
+ for (const key of SEGMENT_KEYS[node.kind] ?? []) {
1272
+ const given = out[key] ?? segmentDefault(node.kind, key);
1273
+ out[key] = Math.max(floor, Math.round(given * detail));
1274
+ }
1275
+ }
1276
+ return out;
1277
+ }
1278
+ function mesh(p) {
1279
+ const positions = new Float32Array(p.positions);
1280
+ const indices = p.indices ? indexArray(p.indices) : void 0;
1281
+ return {
1282
+ type: "BufferGeometry",
1283
+ parameters: {},
1284
+ positions,
1285
+ normals: p.normals ? new Float32Array(p.normals) : computeVertexNormals(positions, indices),
1286
+ uvs: p.uvs ? new Float32Array(p.uvs) : new Float32Array(positions.length / 3 * 2),
1287
+ ...indices ? { indices } : {},
1288
+ groups: []
1289
+ };
1290
+ }
1291
+ function make(kind, p) {
1292
+ switch (kind) {
1293
+ case "box": {
1294
+ const size = p.size ?? [1, 1, 1];
1295
+ const segments = p.segments ?? [1, 1, 1];
1296
+ return box(size[0], size[1], size[2], segments[0], segments[1], segments[2]);
1297
+ }
1298
+ case "cylinder":
1299
+ return cylinder(p.radiusTop, p.radiusBottom, p.height, p.radialSegments, p.heightSegments, p.openEnded, p.thetaStart, p.thetaLength);
1300
+ case "cone":
1301
+ return cone(p.radius, p.height, p.radialSegments, p.heightSegments, p.openEnded, p.thetaStart, p.thetaLength);
1302
+ case "sphere":
1303
+ return sphere(p.radius, p.widthSegments, p.heightSegments, p.phiStart, p.phiLength, p.thetaStart, p.thetaLength);
1304
+ case "plane":
1305
+ return plane(p.width, p.height, p.widthSegments, p.heightSegments);
1306
+ case "circle":
1307
+ return circle(p.radius, p.segments, p.thetaStart, p.thetaLength);
1308
+ case "ring":
1309
+ return ring(p.innerRadius, p.outerRadius, p.thetaSegments, p.phiSegments, p.thetaStart, p.thetaLength);
1310
+ case "lathe":
1311
+ return lathe(p.points, p.segments, p.phiStart, p.phiLength);
1312
+ case "torus":
1313
+ return torus(p.radius, p.tube, p.radialSegments, p.tubularSegments, p.arc);
1314
+ case "extrude":
1315
+ return extrude(p.shape, p.depth, p.steps, p.bevel);
1316
+ case "difference":
1317
+ return difference(p.size, p.subtract ?? []);
1318
+ case "mesh":
1319
+ return mesh(p);
1320
+ default:
1321
+ throw new Error(`game-shapes: unknown primitive kind "${String(kind)}"`);
1322
+ }
1323
+ }
1324
+ var templates = /* @__PURE__ */ new Map();
1325
+ var templateLimit = 4096;
1326
+ var stats = { hits: 0, misses: 0 };
1327
+ function buildPrimitive(node, options = {}) {
1328
+ const parameters = primitiveParameters(node, options);
1329
+ if (node.kind === "mesh" || templateLimit === 0) return make(node.kind, parameters);
1330
+ const key = `${node.kind}:${canonicalJson(parameters)}`;
1331
+ const cached = templates.get(key);
1332
+ if (cached) {
1333
+ stats.hits++;
1334
+ templates.delete(key);
1335
+ templates.set(key, cached);
1336
+ return cached;
1337
+ }
1338
+ stats.misses++;
1339
+ const built = make(node.kind, parameters);
1340
+ templates.set(key, built);
1341
+ if (templates.size > templateLimit) templates.delete(templates.keys().next().value);
1342
+ return built;
1343
+ }
1344
+ var num = (v) => typeof v === "number" && Number.isFinite(v) ? null : "expected a finite number";
1345
+ var bool = (v) => typeof v === "boolean" ? null : "expected a boolean";
1346
+ var str = (v) => typeof v === "string" ? null : "expected a string";
1347
+ var int = (min) => (v) => typeof v === "number" && Number.isInteger(v) && v >= min ? null : `expected an integer >= ${min}`;
1348
+ var range = (lo, hi, loOpen = false) => (v) => typeof v === "number" && (loOpen ? v > lo : v >= lo) && v <= hi ? null : `expected a number in ${loOpen ? "(" : "["}${lo}, ${hi}]`;
1349
+ var tuple = (n, item = num) => (v) => {
1350
+ if (!Array.isArray(v) || v.length !== n) return `expected an array of ${n}`;
1351
+ for (const x of v) if (item(x)) return `expected an array of ${n} numbers`;
1352
+ return null;
1353
+ };
1354
+ var list = (item, min = 0) => (v) => {
1355
+ if (!Array.isArray(v)) return "expected an array";
1356
+ if (v.length < min) return `expected at least ${min} items`;
1357
+ for (let i = 0; i < v.length; i++) {
1358
+ const e = item(v[i]);
1359
+ if (e) return `[${i}]: ${e}`;
1360
+ }
1361
+ return null;
1362
+ };
1363
+ var color = (v) => typeof v === "number" && Number.isInteger(v) && v >= 0 && v <= 16777215 || typeof v === "string" && /^#[0-9a-fA-F]{6}$/.test(v) ? null : 'expected 0xRRGGBB or "#rrggbb"';
1364
+ var oneOf = (values) => (v) => values.includes(v) ? null : `expected one of ${values.map((x) => JSON.stringify(x)).join(", ")}`;
1365
+ var object = (fields, required = []) => (v) => {
1366
+ if (!v || typeof v !== "object" || Array.isArray(v)) return "expected an object";
1367
+ const record = v;
1368
+ for (const key of required) if (record[key] === void 0) return `${key}: required`;
1369
+ for (const key of Object.keys(record)) {
1370
+ if (record[key] === void 0) continue;
1371
+ const check = fields[key];
1372
+ if (!check) return `${key}: unknown field`;
1373
+ const e = check(record[key]);
1374
+ if (e) return `${key}: ${e}`;
1375
+ }
1376
+ return null;
1377
+ };
1378
+ var ORDERS = ["XYZ", "YXZ", "ZXY", "ZYX", "YZX", "XZY"];
1379
+ var TRANSFORM = {
1380
+ position: tuple(3),
1381
+ rotation: tuple(3),
1382
+ rotationOrder: oneOf(ORDERS),
1383
+ scale: (v) => typeof v === "number" ? num(v) : tuple(3)(v),
1384
+ heading: num,
1385
+ matrix: tuple(16)
1386
+ };
1387
+ var UV = object({ u0: num, v0: num, u1: num, v1: num }, ["u0", "v0", "u1", "v1"]);
1388
+ var INSTANCE = object({ ...TRANSFORM, color });
1389
+ var COMMON = {
1390
+ ...TRANSFORM,
1391
+ kind: str,
1392
+ name: str,
1393
+ part: str,
1394
+ material: str,
1395
+ color,
1396
+ uv: UV,
1397
+ instances: list(INSTANCE),
1398
+ minDetail: range(0, 1, true),
1399
+ tags: list(str)
1400
+ };
1401
+ var vec2 = tuple(2);
1402
+ var BEVEL = (v) => v === false ? null : object({ thickness: num, size: num, offset: num, segments: int(1) })(v);
1403
+ var KINDS = {
1404
+ group: { fields: {} },
1405
+ box: { fields: { size: tuple(3), segments: tuple(3, int(1)) } },
1406
+ cylinder: { fields: { radiusTop: num, radiusBottom: num, height: num, radialSegments: int(1), heightSegments: int(1), openEnded: bool, thetaStart: num, thetaLength: num } },
1407
+ cone: { fields: { radius: num, height: num, radialSegments: int(1), heightSegments: int(1), openEnded: bool, thetaStart: num, thetaLength: num } },
1408
+ sphere: { fields: { radius: num, widthSegments: int(3), heightSegments: int(2), phiStart: num, phiLength: num, thetaStart: num, thetaLength: num } },
1409
+ plane: { fields: { width: num, height: num, widthSegments: int(1), heightSegments: int(1) } },
1410
+ circle: { fields: { radius: num, segments: int(3), thetaStart: num, thetaLength: num } },
1411
+ ring: { fields: { innerRadius: num, outerRadius: num, thetaSegments: int(3), phiSegments: int(1), thetaStart: num, thetaLength: num } },
1412
+ lathe: { fields: { points: list(vec2, 2), segments: int(1), phiStart: num, phiLength: num }, required: ["points"] },
1413
+ torus: { fields: { radius: num, tube: num, radialSegments: int(1), tubularSegments: int(1), arc: num } },
1414
+ extrude: {
1415
+ fields: { shape: object({ outer: list(vec2, 3), holes: list(list(vec2, 3)) }, ["outer"]), depth: num, steps: int(1), bevel: BEVEL },
1416
+ required: ["shape"]
1417
+ },
1418
+ difference: { fields: { size: tuple(3), subtract: list(object({ min: vec2, max: vec2 }, ["min", "max"])) }, required: ["size", "subtract"] },
1419
+ mesh: {
1420
+ fields: {
1421
+ positions: (v) => list(num)(v) ?? (v.length % 3 === 0 ? null : "expected a multiple of 3 numbers"),
1422
+ normals: list(num),
1423
+ uvs: list(num),
1424
+ indices: list(int(0))
1425
+ },
1426
+ required: ["positions"]
1427
+ },
1428
+ point: { fields: { data: () => null } },
1429
+ custom: { fields: { generator: str, params: () => null }, required: ["generator"] }
1430
+ };
1431
+
1432
+ // ../game-shapes-three/dist/index.js
1433
+ var UV_BEFORE_NORMAL = /* @__PURE__ */ new Set(["LatheGeometry", "ExtrudeGeometry"]);
1434
+ var INDEX_FIRST = /* @__PURE__ */ new Set(["BoxGeometry", "CylinderGeometry", "ConeGeometry", "SphereGeometry", "PlaneGeometry", "CircleGeometry", "RingGeometry", "LatheGeometry", "TorusGeometry"]);
1435
+ var isPrimitive = (value) => typeof value.type === "string";
1436
+ function threeParameters(THREE, p) {
1437
+ if (p.type === "LatheGeometry") {
1438
+ const points = p.parameters.points.map(({ x, y }) => new THREE.Vector2(x, y));
1439
+ return { ...p.parameters, points };
1440
+ }
1441
+ return { ...p.parameters };
1442
+ }
1443
+ function toGeometry(THREE, source, options = {}) {
1444
+ const copy = options.copy !== false;
1445
+ const primitive = isPrimitive(source) ? source : null;
1446
+ const ThreeClass = primitive && primitive.type !== "BufferGeometry" ? THREE[primitive.type] : void 0;
1447
+ const geometry = ThreeClass ? Reflect.construct(THREE.BufferGeometry, [], ThreeClass) : new THREE.BufferGeometry();
1448
+ if (primitive && ThreeClass) {
1449
+ Object.assign(geometry, { type: primitive.type, parameters: threeParameters(THREE, primitive) });
1450
+ }
1451
+ const attribute = (array, size) => copy ? new THREE.Float32BufferAttribute(array, size) : new THREE.BufferAttribute(array, size);
1452
+ const index = source.indices;
1453
+ const setIndex = () => {
1454
+ if (!index) return;
1455
+ geometry.setIndex(copy ? index instanceof Uint32Array ? new THREE.Uint32BufferAttribute(index, 1) : new THREE.Uint16BufferAttribute(index, 1) : new THREE.BufferAttribute(index, 1));
1456
+ };
1457
+ const type = primitive?.type ?? "BufferGeometry";
1458
+ if (INDEX_FIRST.has(type)) setIndex();
1459
+ geometry.setAttribute("position", attribute(source.positions, 3));
1460
+ if (UV_BEFORE_NORMAL.has(type)) {
1461
+ geometry.setAttribute("uv", attribute(source.uvs, 2));
1462
+ geometry.setAttribute("normal", attribute(source.normals, 3));
1463
+ } else {
1464
+ geometry.setAttribute("normal", attribute(source.normals, 3));
1465
+ geometry.setAttribute("uv", attribute(source.uvs, 2));
1466
+ }
1467
+ if (!primitive && source.colors) geometry.setAttribute("color", attribute(source.colors, 3));
1468
+ if (!INDEX_FIRST.has(type)) setIndex();
1469
+ if (primitive) for (const group of primitive.groups) geometry.addGroup(group.start, group.count, group.materialIndex);
1470
+ return geometry;
1471
+ }
1472
+ var SHAPE_GEOMETRY_TYPES = ["BoxGeometry", "CylinderGeometry", "ConeGeometry", "SphereGeometry", "PlaneGeometry", "CircleGeometry", "RingGeometry", "LatheGeometry", "TorusGeometry", "ExtrudeGeometry"];
1473
+ function linePoints(path) {
1474
+ if (path.autoClose || path.curves.length === 0) return null;
1475
+ const points = [];
1476
+ for (const [index, curve] of path.curves.entries()) {
1477
+ if (!curve.isLineCurve || !curve.v1 || !curve.v2) return null;
1478
+ if (index === 0) points.push([curve.v1.x, curve.v1.y]);
1479
+ else {
1480
+ const last = points[points.length - 1];
1481
+ if (last[0] !== curve.v1.x || last[1] !== curve.v1.y) return null;
1482
+ }
1483
+ points.push([curve.v2.x, curve.v2.y]);
1484
+ }
1485
+ return points;
1486
+ }
1487
+ function extrudeOf(shapes, options = {}) {
1488
+ if (Array.isArray(shapes) || !shapes || options.extrudePath !== void 0 || options.UVGenerator !== void 0) return null;
1489
+ const shape = shapes;
1490
+ const outer = linePoints(shape);
1491
+ if (!outer) return null;
1492
+ const holes = [];
1493
+ for (const hole of shape.holes ?? []) {
1494
+ const points = linePoints(hole);
1495
+ if (!points) return null;
1496
+ holes.push(points);
1497
+ }
1498
+ const outline = holes.length ? { outer, holes } : { outer };
1499
+ const bevel = options.bevelEnabled === false ? false : {
1500
+ ...options.bevelThickness !== void 0 ? { thickness: options.bevelThickness } : {},
1501
+ ...options.bevelSize !== void 0 ? { size: options.bevelSize } : {},
1502
+ ...options.bevelOffset !== void 0 ? { offset: options.bevelOffset } : {},
1503
+ ...options.bevelSegments !== void 0 ? { segments: options.bevelSegments } : {}
1504
+ };
1505
+ return extrude(outline, options.depth, options.steps, bevel);
1506
+ }
1507
+ var namespaces = /* @__PURE__ */ new WeakMap();
1508
+ var shims = /* @__PURE__ */ new WeakSet();
1509
+ function shapeGeometries(THREE, options = {}) {
1510
+ if (shims.has(THREE)) return THREE;
1511
+ const cache2 = options.cache !== false;
1512
+ const key = cache2 ? "cache" : "nocache";
1513
+ let byKey = namespaces.get(THREE);
1514
+ if (!byKey) {
1515
+ byKey = /* @__PURE__ */ new Map();
1516
+ namespaces.set(THREE, byKey);
1517
+ }
1518
+ const existing = byKey.get(key);
1519
+ if (existing) return existing;
1520
+ const made = (p) => toGeometry(THREE, p);
1521
+ const viaCache = (node, direct) => cache2 ? buildPrimitive(node) : direct();
1522
+ const defined = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
1523
+ const constructors = {
1524
+ BoxGeometry: (width, height, depth, ws = 1, hs = 1, ds = 1) => made(viaCache({ kind: "box", size: [width ?? 1, height ?? 1, depth ?? 1], segments: [ws, hs, ds] }, () => box(width, height, depth, ws, hs, ds))),
1525
+ CylinderGeometry: (radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength) => made(viaCache({ kind: "cylinder", ...defined({ radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength }) }, () => cylinder(radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength))),
1526
+ ConeGeometry: (radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength) => made(viaCache({ kind: "cone", ...defined({ radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength }) }, () => cone(radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength))),
1527
+ SphereGeometry: (radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength) => made(viaCache({ kind: "sphere", ...defined({ radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength }) }, () => sphere(radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength))),
1528
+ PlaneGeometry: (width, height, widthSegments, heightSegments) => made(viaCache({ kind: "plane", ...defined({ width, height, widthSegments, heightSegments }) }, () => plane(width, height, widthSegments, heightSegments))),
1529
+ CircleGeometry: (radius, segments, thetaStart, thetaLength) => made(viaCache({ kind: "circle", ...defined({ radius, segments, thetaStart, thetaLength }) }, () => circle(radius, segments, thetaStart, thetaLength))),
1530
+ RingGeometry: (innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength) => made(viaCache({ kind: "ring", ...defined({ innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength }) }, () => ring(innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength))),
1531
+ LatheGeometry: (points, segments, phiStart, phiLength) => {
1532
+ if (!points) return new THREE.LatheGeometry(void 0, segments, phiStart, phiLength);
1533
+ const profile = points.map((p) => [p.x, p.y]);
1534
+ return made(viaCache({ kind: "lathe", points: profile, ...defined({ segments, phiStart, phiLength }) }, () => lathe(profile, segments, phiStart, phiLength)));
1535
+ },
1536
+ TorusGeometry: (radius, tube2, radialSegments, tubularSegments, arc) => made(viaCache({ kind: "torus", ...defined({ radius, tube: tube2, radialSegments, tubularSegments, arc }) }, () => torus(radius, tube2, radialSegments, tubularSegments, arc))),
1537
+ ExtrudeGeometry: (shapes, extrudeOptions) => {
1538
+ const buffers = shapes === void 0 ? null : extrudeOf(shapes, extrudeOptions);
1539
+ if (!buffers) return new THREE.ExtrudeGeometry(shapes, extrudeOptions);
1540
+ const geometry = toGeometry(THREE, buffers);
1541
+ geometry.parameters = { shapes, options: extrudeOptions ?? {} };
1542
+ return geometry;
1543
+ }
1544
+ };
1545
+ const namespace = { ...THREE };
1546
+ for (const type of SHAPE_GEOMETRY_TYPES) {
1547
+ const make2 = constructors[type];
1548
+ const Constructor = function(...args) {
1549
+ return make2(...args);
1550
+ };
1551
+ Constructor.prototype = THREE[type].prototype;
1552
+ Object.defineProperty(Constructor, "name", { value: type });
1553
+ namespace[type] = Constructor;
1554
+ }
1555
+ const result = namespace;
1556
+ byKey.set(key, result);
1557
+ shims.add(result);
1558
+ return result;
1559
+ }
1560
+
44
1561
  // ../game-vegetation/dist/index.js
45
1562
  var dist_exports = {};
46
1563
  __export(dist_exports, {
@@ -50,7 +1567,7 @@ var GameVegetationThree = (() => {
50
1567
  createRng: () => createRng,
51
1568
  distanceToBoundary: () => distanceToBoundary,
52
1569
  extractPlant: () => extractPlant,
53
- generate: () => generate,
1570
+ generate: () => generate2,
54
1571
  hashString: () => hashString,
55
1572
  hideLotPlant: () => hideLotPlant,
56
1573
  materialKeyForPart: () => materialKeyForPart,
@@ -285,7 +1802,7 @@ var GameVegetationThree = (() => {
285
1802
  const [h, s, v] = toHsv(c);
286
1803
  return fromHsv(h - amt * 0.03, clamp(s - amt * 0.12, 0, 1), clamp(v + amt * 0.35, 0, 1));
287
1804
  }
288
- function srgbToLinear(v) {
1805
+ function srgbToLinear2(v) {
289
1806
  return v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
290
1807
  }
291
1808
  function linearToSrgb(v) {
@@ -467,7 +1984,7 @@ var GameVegetationThree = (() => {
467
1984
  this.groupTriangles();
468
1985
  const n = this.pos.length / 3;
469
1986
  const colors = new Float32Array(n * 3);
470
- for (let i = 0; i < n * 3; i++) colors[i] = srgbToLinear(this.col[i]);
1987
+ for (let i = 0; i < n * 3; i++) colors[i] = srgbToLinear2(this.col[i]);
471
1988
  return {
472
1989
  positions: new Float32Array(this.pos),
473
1990
  normals: new Float32Array(this.nor),
@@ -668,16 +2185,16 @@ var GameVegetationThree = (() => {
668
2185
  const f = frames[k];
669
2186
  const r = o.radii[k];
670
2187
  const t = k / (n - 1);
671
- const ring = [];
2188
+ const ring2 = [];
672
2189
  for (let i = 0; i < S; i++) {
673
2190
  const a = i / S * TAU;
674
2191
  const ca = Math.cos(a);
675
2192
  const sa = Math.sin(a);
676
2193
  const dir = [f.n[0] * ca + f.b[0] * sa, f.n[1] * ca + f.b[1] * sa, f.n[2] * ca + f.b[2] * sa];
677
2194
  const rr = r * (1 + (o.rough ? o.rough(k, i) : 0));
678
- ring.push({ p: add(path[k], mul(dir, rr)), nr: dir, c: o.color(t, i / S) });
2195
+ ring2.push({ p: add(path[k], mul(dir, rr)), nr: dir, c: o.color(t, i / S) });
679
2196
  }
680
- rings.push(ring);
2197
+ rings.push(ring2);
681
2198
  }
682
2199
  const sw = (k) => o.sway(k / (n - 1));
683
2200
  if (smooth2) {
@@ -761,7 +2278,7 @@ var GameVegetationThree = (() => {
761
2278
  const swayAt = (k) => o.sway(k / (N - 1));
762
2279
  for (let k = 0; k < N; k++) {
763
2280
  const f = fr[k];
764
- const ring = [];
2281
+ const ring2 = [];
765
2282
  for (let i = 0; i < S; i++) {
766
2283
  const ridge = i % 2 === 0;
767
2284
  const rib = i >> 1;
@@ -771,10 +2288,10 @@ var GameVegetationThree = (() => {
771
2288
  const rr = radii[k] * (ridge ? 1 + wob : o.valley);
772
2289
  const p = add(pts[k], mul(dir, rr));
773
2290
  const c = o.color(Math.min(1, k / (path.length - 1)), ridge, rib);
774
- ring.push({ p, nr: dir, c });
2291
+ ring2.push({ p, nr: dir, c });
775
2292
  if (ridge && k < path.length) info.ridges.push({ p, n: dir, t: k / (path.length - 1), rib, ring: k });
776
2293
  }
777
- rings.push(ring);
2294
+ rings.push(ring2);
778
2295
  }
779
2296
  for (let k = 0; k < N - 1; k++) {
780
2297
  for (let i = 0; i < S; i++) {
@@ -1096,7 +2613,7 @@ var GameVegetationThree = (() => {
1096
2613
  return { p, r, members: g.members };
1097
2614
  });
1098
2615
  }
1099
- function octa(b, center, radii, color, sway) {
2616
+ function octa(b, center, radii, color2, sway) {
1100
2617
  const pts = [
1101
2618
  [radii[0], 0, 0],
1102
2619
  [0, 0, radii[2]],
@@ -1109,11 +2626,11 @@ var GameVegetationThree = (() => {
1109
2626
  const a = pts[i];
1110
2627
  const c = pts[(i + 1) % 4];
1111
2628
  const out = sub(add(a, c), mul(center, 2));
1112
- b.flatTri(a, c, top, color(0.5), color(0.5), color(1), sway, sway, sway, add(out, [0, 1, 0]));
1113
- b.flatTri(c, a, bot, color(0.5), color(0.5), color(0), sway, sway, sway, add(out, [0, -1, 0]));
2629
+ b.flatTri(a, c, top, color2(0.5), color2(0.5), color2(1), sway, sway, sway, add(out, [0, 1, 0]));
2630
+ b.flatTri(c, a, bot, color2(0.5), color2(0.5), color2(0), sway, sway, sway, add(out, [0, -1, 0]));
1114
2631
  }
1115
2632
  }
1116
- function blossom(b, center, normal, size, color, heart, sway, petals = 5, twist = 0) {
2633
+ function blossom(b, center, normal, size, color2, heart, sway, petals = 5, twist = 0) {
1117
2634
  const f = frameFromAxis(center, normal, twist);
1118
2635
  const peak = toWorld(f, [0, size * 0.3, 0]);
1119
2636
  for (let i = 0; i < petals; i++) {
@@ -1123,7 +2640,7 @@ var GameVegetationThree = (() => {
1123
2640
  const p0 = toWorld(f, [Math.cos(a0) * size * 0.75, 0, Math.sin(a0) * size * 0.75]);
1124
2641
  const p1 = toWorld(f, [Math.cos(a1) * size * 0.75, 0, Math.sin(a1) * size * 0.75]);
1125
2642
  const pm = toWorld(f, [Math.cos(am) * size * 1.1, size * 0.08, Math.sin(am) * size * 1.1]);
1126
- const c = i % 2 ? shade(color, 0.93) : color;
2643
+ const c = i % 2 ? shade(color2, 0.93) : color2;
1127
2644
  b.flatTri(peak, p0, pm, heart, c, lighten(c, 0.4), sway, sway, sway, normal);
1128
2645
  b.flatTri(peak, pm, p1, heart, lighten(c, 0.4), c, sway, sway, sway, normal);
1129
2646
  }
@@ -2013,8 +3530,8 @@ var GameVegetationThree = (() => {
2013
3530
  const nb = ctx.pick(6, 5, 4);
2014
3531
  for (let i = 0; i < nb; i++) {
2015
3532
  const a = i * 2.2 + 0.4;
2016
- const ring = i === 0 ? 0 : moundR * 0.5;
2017
- blobs.push({ c: [Math.cos(a) * ring, moundH * (i === 0 ? 0.55 : 0.28 + 0.07 * (i % 3)), Math.sin(a) * ring], r: moundR * (i === 0 ? 0.62 : 0.52), sq: 0.95 });
3533
+ const ring2 = i === 0 ? 0 : moundR * 0.5;
3534
+ blobs.push({ c: [Math.cos(a) * ring2, moundH * (i === 0 ? 0.55 : 0.28 + 0.07 * (i % 3)), Math.sin(a) * ring2], r: moundR * (i === 0 ? 0.62 : 0.52), sq: 0.95 });
2018
3535
  }
2019
3536
  }
2020
3537
  for (const bl of blobs) clump(ctx.foliage, { center: bl.c, radius: bl.r, squash: bl.sq, detail: ctx.pick(1, 1, 0), seed: rng.seed(), base: dead ? mix(leafBase, [0.42, 0.32, 0.2], 0.7) : dry ? mix(leafBase, [0.55, 0.48, 0.22], 0.45) : mix(leafBase, [0.25, 0.55, 0.22], 0.25), swayK: 0.3, noise: 0.16, flatBottom: 0.8, ao: 0.5 });
@@ -2381,7 +3898,7 @@ var GameVegetationThree = (() => {
2381
3898
  }
2382
3899
  }
2383
3900
  if (o.teeth && o.teeth.count > 0) {
2384
- const { count, color, size } = o.teeth;
3901
+ const { count, color: color2, size } = o.teeth;
2385
3902
  for (let k = 0; k < count; k++) {
2386
3903
  const t0 = 0.12 + 0.7 * k / count;
2387
3904
  const t1 = t0 + 0.05;
@@ -2392,7 +3909,7 @@ var GameVegetationThree = (() => {
2392
3909
  const e1 = sd < 0 ? rows[i1].L : rows[i1].R;
2393
3910
  const out = mul(right, sd * width * size);
2394
3911
  const tip = add(add(mul(add(e0, e1), 0.5), out), mul(d, length * 0.02));
2395
- b.flatTri(e0, tip, e1, color, shade(color, 1.3), color, rows[i0].s, rows[i0].s, rows[i1].s, add(out, n2));
3912
+ b.flatTri(e0, tip, e1, color2, shade(color2, 1.3), color2, rows[i0].s, rows[i0].s, rows[i1].s, add(out, n2));
2396
3913
  }
2397
3914
  }
2398
3915
  }
@@ -2421,8 +3938,8 @@ var GameVegetationThree = (() => {
2421
3938
  const az = i / n * TAU * 1 + rng.range(-0.3, 0.3);
2422
3939
  const el = rng.range(1.2, 1.5);
2423
3940
  const len2 = h * rng.range(0.55, 1) * (ctx.condition === "dead" ? 0.6 : 1);
2424
- const ring = rng.range(0, 0.08);
2425
- const base0 = [Math.cos(az) * ring, 0, Math.sin(az) * ring];
3941
+ const ring2 = rng.range(0, 0.08);
3942
+ const base0 = [Math.cos(az) * ring2, 0, Math.sin(az) * ring2];
2426
3943
  const band = rng.range(0, TAU);
2427
3944
  fleshyLeaf(ctx.foliage, base0, dirFromAngles(az, el), dirFromAngles(az + Math.PI, 0.2), len2, h * 0.16 * rng.range(0.85, 1.15), {
2428
3945
  rows: ctx.pick(7, 4, 2),
@@ -2444,10 +3961,10 @@ var GameVegetationThree = (() => {
2444
3961
  const base = tintFlesh(rgb(spec.color ?? 7315306), ctx.condition);
2445
3962
  const edge = rgb(spec.edgeColor ?? 15261896);
2446
3963
  for (let i = 0; i < n; i++) {
2447
- const ring = i < n * 0.4 ? 0 : i < n * 0.75 ? 1 : 2;
3964
+ const ring2 = i < n * 0.4 ? 0 : i < n * 0.75 ? 1 : 2;
2448
3965
  const az = i * 2.4 + rng.range(-0.2, 0.2);
2449
- const el = [1.15, 0.85, 0.55][ring] + rng.range(-0.1, 0.1);
2450
- const len2 = h * [0.75, 0.95, 0.85][ring] * rng.range(0.9, 1.1);
3966
+ const el = [1.15, 0.85, 0.55][ring2] + rng.range(-0.1, 0.1);
3967
+ const len2 = h * [0.75, 0.95, 0.85][ring2] * rng.range(0.9, 1.1);
2451
3968
  const c = jitter(base, rng, 0.01, 0.06, 0.04);
2452
3969
  fleshyLeaf(ctx.foliage, [0, 0.02, 0], dirFromAngles(az, el), [0, 1, 0], len2, h * 0.26, {
2453
3970
  rows: ctx.pick(3, 2, 2),
@@ -2534,7 +4051,7 @@ var GameVegetationThree = (() => {
2534
4051
  }
2535
4052
  return { collider: null, bendable: true };
2536
4053
  }
2537
- function spineTuft(b, p, n, count, length, color, rng, sway = 0) {
4054
+ function spineTuft(b, p, n, count, length, color2, rng, sway = 0) {
2538
4055
  const nn = norm(n);
2539
4056
  const t1 = perp(nn);
2540
4057
  const t2 = norm(cross(nn, t1));
@@ -2547,15 +4064,15 @@ var GameVegetationThree = (() => {
2547
4064
  const side = mul(norm(cross(dir, nn)), w);
2548
4065
  const left = add(p, side);
2549
4066
  const right = add(p, mul(side, -1));
2550
- b.flatTri(left, right, tip, shade(color, 0.8), shade(color, 0.8), color, sway, sway, sway, nn);
4067
+ b.flatTri(left, right, tip, shade(color2, 0.8), shade(color2, 0.8), color2, sway, sway, sway, nn);
2551
4068
  }
2552
4069
  }
2553
- function areole(b, p, n, size, color, sway = 0) {
4070
+ function areole(b, p, n, size, color2, sway = 0) {
2554
4071
  const nn = norm(n);
2555
4072
  const t1 = mul(perp(nn), size);
2556
4073
  const t2 = mul(norm(cross(nn, perp(nn))), size);
2557
4074
  const c = add(p, mul(nn, size * 0.1));
2558
- b.flatTri(add(c, t1), add(c, add(mul(t1, -0.5), t2)), add(c, add(mul(t1, -0.5), mul(t2, -1))), color, color, color, sway, sway, sway, nn);
4075
+ b.flatTri(add(c, t1), add(c, add(mul(t1, -0.5), t2)), add(c, add(mul(t1, -0.5), mul(t2, -1))), color2, color2, color2, sway, sway, sway, nn);
2559
4076
  }
2560
4077
  function generateColumnarCactus(spec, ctx) {
2561
4078
  const rng = ctx.rng;
@@ -2592,7 +4109,7 @@ var GameVegetationThree = (() => {
2592
4109
  dome: domeSteps,
2593
4110
  color: (t, ridge, rib) => bodyColor(t, ridge, rib + seedK),
2594
4111
  sway: () => 0,
2595
- rough: (ring, rib) => Math.sin(ring * 1.7 + rib * 2.3 + seedK) * 0.03
4112
+ rough: (ring2, rib) => Math.sin(ring2 * 1.7 + rib * 2.3 + seedK) * 0.03
2596
4113
  });
2597
4114
  const last = path[path.length - 1];
2598
4115
  const prev = path[path.length - 2];
@@ -2804,7 +4321,7 @@ var GameVegetationThree = (() => {
2804
4321
  return shade(base, k);
2805
4322
  },
2806
4323
  sway: () => 0,
2807
- rough: (ring, rib) => Math.sin(ring * 2.1 + rib * 1.3) * 0.02
4324
+ rough: (ring2, rib) => Math.sin(ring2 * 2.1 + rib * 1.3) * 0.02
2808
4325
  });
2809
4326
  if (ctx.lod === 0) {
2810
4327
  for (const rd of res.ridges) {
@@ -2959,9 +4476,9 @@ var GameVegetationThree = (() => {
2959
4476
  sides,
2960
4477
  radii,
2961
4478
  color: (t, a) => {
2962
- const ring = 0.84 + 0.16 * Math.cos(t * stemH * scars * TAU);
4479
+ const ring2 = 0.84 + 0.16 * Math.cos(t * stemH * scars * TAU);
2963
4480
  const stripe = 0.94 + 0.06 * Math.cos(a * TAU * 3 + t * 4);
2964
- let c = shade(trunkC, ring * stripe * (0.78 + 0.22 * Math.min(1, t * 6)));
4481
+ let c = shade(trunkC, ring2 * stripe * (0.78 + 0.22 * Math.min(1, t * 6)));
2965
4482
  if (variant === "royal") c = mix(c, [0.62, 0.62, 0.55], 0.25);
2966
4483
  if (dead) c = mix(c, [0.4, 0.37, 0.32], 0.5);
2967
4484
  return c;
@@ -2986,34 +4503,34 @@ var GameVegetationThree = (() => {
2986
4503
  for (let i = 0; i < n; i++) {
2987
4504
  if (ctx.lod === 2 && variant === "fan" && i % 2 === 1) continue;
2988
4505
  const f = srng.fork(i);
2989
- const ring = i % 3;
4506
+ const ring2 = i % 3;
2990
4507
  const az2 = i / n * TAU * 1 + f.range(-0.2, 0.2) + si;
2991
4508
  let elev;
2992
4509
  let droop;
2993
4510
  if (variant === "royal") {
2994
- elev = [1.1, 0.65, 0.2][ring] + f.range(-0.1, 0.1);
2995
- droop = [0.35, 0.65, 1][ring];
4511
+ elev = [1.1, 0.65, 0.2][ring2] + f.range(-0.1, 0.1);
4512
+ droop = [0.35, 0.65, 1][ring2];
2996
4513
  } else if (variant === "date") {
2997
- elev = [1.15, 0.8, 0.45][ring] + f.range(-0.08, 0.08);
2998
- droop = [0.3, 0.5, 0.75][ring];
4514
+ elev = [1.15, 0.8, 0.45][ring2] + f.range(-0.08, 0.08);
4515
+ droop = [0.3, 0.5, 0.75][ring2];
2999
4516
  } else if (variant === "areca") {
3000
- elev = [1.1, 0.8, 0.5][ring] + f.range(-0.1, 0.1);
3001
- droop = [0.45, 0.8, 1.1][ring];
4517
+ elev = [1.1, 0.8, 0.5][ring2] + f.range(-0.1, 0.1);
4518
+ droop = [0.45, 0.8, 1.1][ring2];
3002
4519
  } else if (variant === "fan") {
3003
- elev = [1.3, 0.95, 0.6][ring] + f.range(-0.1, 0.1);
3004
- droop = [0.25, 0.35, 0.5][ring];
4520
+ elev = [1.3, 0.95, 0.6][ring2] + f.range(-0.1, 0.1);
4521
+ droop = [0.25, 0.35, 0.5][ring2];
3005
4522
  } else {
3006
- elev = [1.15, 0.75, 0.38][ring] + f.range(-0.1, 0.1);
3007
- droop = [0.45, 0.78, 1.1][ring];
4523
+ elev = [1.15, 0.75, 0.38][ring2] + f.range(-0.1, 0.1);
4524
+ droop = [0.45, 0.78, 1.1][ring2];
3008
4525
  }
3009
4526
  if (dead) {
3010
4527
  elev = elev * 0.4 - 0.3;
3011
4528
  droop *= 1.4;
3012
4529
  }
3013
4530
  if (dry) droop *= 1.15;
3014
- const len2 = frondL * f.range(0.85, 1.1) * (ring === 2 ? 0.92 : 1);
4531
+ const len2 = frondL * f.range(0.85, 1.1) * (ring2 === 2 ? 0.92 : 1);
3015
4532
  const colA = dead ? mix(c0, deadC, 0.8) : c0;
3016
- const colB = dead ? mix(c1, deadC, 0.7) : ring === 2 && dry ? mix(c1, deadC, 0.4) : c1;
4533
+ const colB = dead ? mix(c1, deadC, 0.7) : ring2 === 2 && dry ? mix(c1, deadC, 0.4) : c1;
3017
4534
  if (variant === "fan") {
3018
4535
  fanFrond(ctx, f, crownTop, az2, elev, len2, droop, colA, colB);
3019
4536
  } else {
@@ -3124,10 +4641,10 @@ var GameVegetationThree = (() => {
3124
4641
  const rows = ctx.pick(9, 6, 3);
3125
4642
  for (let i = 0; i < nLeaves; i++) {
3126
4643
  const f = rng.fork(i);
3127
- const ring = i % 3;
4644
+ const ring2 = i % 3;
3128
4645
  const az = i / nLeaves * TAU * 1 + f.range(-0.25, 0.25);
3129
- const L = H * f.range(0.55, 0.72) * (ring === 2 ? 0.85 : 1);
3130
- const el = [1.15, 0.8, 0.45][ring] + f.range(-0.12, 0.12);
4646
+ const L = H * f.range(0.55, 0.72) * (ring2 === 2 ? 0.85 : 1);
4647
+ const el = [1.15, 0.8, 0.45][ring2] + f.range(-0.12, 0.12);
3131
4648
  const horiz = dirFromAngles(az, 0);
3132
4649
  const petL = L * 0.18;
3133
4650
  const pEnd = [top[0] + horiz[0] * petL * Math.cos(el), top[1] + petL * Math.sin(el), top[2] + horiz[2] * petL * Math.cos(el)];
@@ -3138,7 +4655,7 @@ var GameVegetationThree = (() => {
3138
4655
  const tearSeed = f.range(0, 10);
3139
4656
  leaf(ctx.foliage, pEnd, norm([horiz[0] * Math.cos(el), Math.sin(el), horiz[2] * Math.cos(el)]), [0, 1, 0], L, L * 0.34, c0, c1, {
3140
4657
  rows,
3141
- curl: [0.55, 0.7, 0.8][ring] * (dry ? 1.2 : 1),
4658
+ curl: [0.55, 0.7, 0.8][ring2] * (dry ? 1.2 : 1),
3142
4659
  fold: 0.35,
3143
4660
  swayBase: 0.25,
3144
4661
  swayTip: 1,
@@ -3238,8 +4755,8 @@ var GameVegetationThree = (() => {
3238
4755
  if (hit) return hit;
3239
4756
  const m = Math.max(Math.abs(c[0]), Math.abs(c[1]), Math.abs(c[2]));
3240
4757
  const s = norm(c);
3241
- const sphere = [s[0] * m, s[1] * m, s[2] * m];
3242
- const q = [lerp(c[0], sphere[0], o.round), lerp(c[1], sphere[1], o.round), lerp(c[2], sphere[2], o.round)];
4758
+ const sphere2 = [s[0] * m, s[1] * m, s[2] * m];
4759
+ const q = [lerp(c[0], sphere2[0], o.round), lerp(c[1], sphere2[1], o.round), lerp(c[2], sphere2[2], o.round)];
3243
4760
  const base = [o.center[0] + q[0] * hx, o.center[1] + q[1] * hy, o.center[2] + q[2] * hz];
3244
4761
  const nz = valueNoise3(base[0] * freq, base[1] * freq, base[2] * freq, seed) * 0.75 + valueNoise3(base[0] * freq * 2.3, base[1] * freq * 2.3, base[2] * freq * 2.3, seed + 7) * 0.25;
3245
4762
  const out = norm([q[0] / Math.max(hx, 1e-6), q[1] / Math.max(hy, 1e-6), q[2] / Math.max(hz, 1e-6)]);
@@ -3445,14 +4962,14 @@ var GameVegetationThree = (() => {
3445
4962
  const dark = shade(col, 0.62);
3446
4963
  const apex = [lean * (y / H) ** 2, y + tierH * 0.55, 0];
3447
4964
  const innerR = r * 0.32;
3448
- const ring = (rad, yy, k, ph) => [apex[0] + Math.cos(k / K * TAU + ph) * rad, yy, Math.sin(k / K * TAU + ph) * rad];
4965
+ const ring2 = (rad, yy, k, ph) => [apex[0] + Math.cos(k / K * TAU + ph) * rad, yy, Math.sin(k / K * TAU + ph) * rad];
3449
4966
  const tphase = i * 0.7;
3450
4967
  for (let k = 0; k < K; k++) {
3451
4968
  const jag = k % 2 === 0 ? 1 : 0.78;
3452
- const a0 = ring(innerR, y + tierH * 0.12, k, tphase);
3453
- const a1 = ring(innerR, y + tierH * 0.12, k + 1, tphase);
3454
- const o0 = ring(r * jag, y - tierH * 0.42, k, tphase);
3455
- const o1 = ring(r * (k % 2 === 0 ? 0.78 : 1), y - tierH * 0.42, k + 1, tphase);
4969
+ const a0 = ring2(innerR, y + tierH * 0.12, k, tphase);
4970
+ const a1 = ring2(innerR, y + tierH * 0.12, k + 1, tphase);
4971
+ const o0 = ring2(r * jag, y - tierH * 0.42, k, tphase);
4972
+ const o1 = ring2(r * (k % 2 === 0 ? 0.78 : 1), y - tierH * 0.42, k + 1, tphase);
3456
4973
  const sw = 0.25 + 0.35 * (1 - f);
3457
4974
  foliage.flat(apex, a1, a0, shade(lightTop, 0.85), 0.2, [0, 1, 0]);
3458
4975
  foliage.flatTri(a0, a1, o1, mix(col, lightTop, 0.2), mix(col, lightTop, 0.2), lightTop, 0.2, 0.2, sw, [0, 1, 0]);
@@ -3641,12 +5158,12 @@ var GameVegetationThree = (() => {
3641
5158
  const a1 = (i + 1) / sides * TAU;
3642
5159
  ctx.wood.flatTri([0, soilY, 0], [Math.cos(a1) * rim, soilY, Math.sin(a1) * rim], [Math.cos(a0) * rim, soilY, Math.sin(a0) * rim], shade(soil, 0.9), soil, soil, 0, 0, 0, [0, 1, 0]);
3643
5160
  }
3644
- const inner = generate(spec.plant, { seed: ctx.rng.fork("plant").seed(), lod: ctx.lod, condition: ctx.condition, season: ctx.season });
5161
+ const inner = generate2(spec.plant, { seed: ctx.rng.fork("plant").seed(), lod: ctx.lod, condition: ctx.condition, season: ctx.season });
3645
5162
  const yOff = soilY - 0.02;
3646
5163
  const tagsOf = (part) => {
3647
- const mesh = inner.parts[part];
3648
- if (!mesh) return void 0;
3649
- const tags = new Array(mesh.triangleCount).fill("");
5164
+ const mesh2 = inner.parts[part];
5165
+ if (!mesh2) return void 0;
5166
+ const tags = new Array(mesh2.triangleCount).fill("");
3650
5167
  for (const pc of inner.pieces) {
3651
5168
  if (pc.part !== part) continue;
3652
5169
  if (!ctx.pieceMeta.has(pc.id)) ctx.pieceMeta.set(pc.id, { kind: pc.kind, parent: pc.parent, pivot: [pc.pivot[0], pc.pivot[1] + yOff, pc.pivot[2]], ...pc.radius === void 0 || pc.length === void 0 || !pc.axis || !pc.base ? {} : { geom: { radius: pc.radius, length: pc.length, axis: pc.axis, base: [pc.base[0], pc.base[1] + yOff, pc.base[2]] } } });
@@ -3686,7 +5203,7 @@ var GameVegetationThree = (() => {
3686
5203
  function archetypes() {
3687
5204
  return Object.keys(GENERATORS);
3688
5205
  }
3689
- function generate(spec, opts = {}) {
5206
+ function generate2(spec, opts = {}) {
3690
5207
  const gen = GENERATORS[spec.archetype];
3691
5208
  if (!gen) throw new Error(`game-vegetation: unknown archetype "${spec.archetype}"`);
3692
5209
  const seed = toSeed(opts.seed);
@@ -3895,29 +5412,29 @@ var GameVegetationThree = (() => {
3895
5412
  }
3896
5413
  const tagBox = /* @__PURE__ */ new Map();
3897
5414
  for (const part of PART_ORDER) {
3898
- const mesh = parts[part];
3899
- if (!mesh) continue;
5415
+ const mesh2 = parts[part];
5416
+ if (!mesh2) continue;
3900
5417
  for (const r of builders[part].ranges) {
3901
5418
  const tag = r.tag || rootId;
3902
- let box = tagBox.get(tag);
3903
- if (!box) tagBox.set(tag, box = { min: [Infinity, Infinity, Infinity], max: [-Infinity, -Infinity, -Infinity] });
5419
+ let box2 = tagBox.get(tag);
5420
+ if (!box2) tagBox.set(tag, box2 = { min: [Infinity, Infinity, Infinity], max: [-Infinity, -Infinity, -Infinity] });
3904
5421
  for (let i = r.indexStart; i < r.indexStart + r.indexCount; i++) {
3905
- const v = mesh.indices[i] * 3;
5422
+ const v = mesh2.indices[i] * 3;
3906
5423
  for (let a = 0; a < 3; a++) {
3907
- const c = mesh.positions[v + a];
3908
- if (c < box.min[a]) box.min[a] = c;
3909
- if (c > box.max[a]) box.max[a] = c;
5424
+ const c = mesh2.positions[v + a];
5425
+ if (c < box2.min[a]) box2.min[a] = c;
5426
+ if (c > box2.max[a]) box2.max[a] = c;
3910
5427
  }
3911
5428
  }
3912
5429
  }
3913
5430
  }
3914
5431
  const fruitHang = /* @__PURE__ */ new Map();
3915
5432
  const PRIORITY = { branch: 0, pad: 0, arm: 0, stem: 1, trunk: 1, crown: 2 };
3916
- for (const [tag, box] of tagBox) {
5433
+ for (const [tag, box2] of tagBox) {
3917
5434
  if (meta.get(tag)?.kind !== "fruit") continue;
3918
- const cx = (box.min[0] + box.max[0]) / 2;
3919
- const cy = (box.min[1] + box.max[1]) / 2;
3920
- const cz = (box.min[2] + box.max[2]) / 2;
5435
+ const cx = (box2.min[0] + box2.max[0]) / 2;
5436
+ const cy = (box2.min[1] + box2.max[1]) / 2;
5437
+ const cz = (box2.min[2] + box2.max[2]) / 2;
3921
5438
  let parent;
3922
5439
  let pbox;
3923
5440
  let bd = Infinity;
@@ -3939,24 +5456,24 @@ var GameVegetationThree = (() => {
3939
5456
  pbox = pb;
3940
5457
  }
3941
5458
  }
3942
- const pc = pbox ? [(pbox.min[0] + pbox.max[0]) / 2, (pbox.min[1] + pbox.max[1]) / 2, (pbox.min[2] + pbox.max[2]) / 2] : [cx, box.max[1], cz];
3943
- const pivot = [Math.min(box.max[0], Math.max(box.min[0], pc[0])), Math.min(box.max[1], Math.max(box.min[1], pc[1])), Math.min(box.max[2], Math.max(box.min[2], pc[2]))];
5459
+ const pc = pbox ? [(pbox.min[0] + pbox.max[0]) / 2, (pbox.min[1] + pbox.max[1]) / 2, (pbox.min[2] + pbox.max[2]) / 2] : [cx, box2.max[1], cz];
5460
+ const pivot = [Math.min(box2.max[0], Math.max(box2.min[0], pc[0])), Math.min(box2.max[1], Math.max(box2.min[1], pc[1])), Math.min(box2.max[2], Math.max(box2.min[2], pc[2]))];
3944
5461
  fruitHang.set(tag, { parent, pivot });
3945
5462
  }
3946
5463
  const idOf = (tag, part) => primary.get(tag) === part ? tag : `${tag}:${part}`;
3947
5464
  const out = [];
3948
5465
  for (const part of PART_ORDER) {
3949
- const mesh = parts[part];
3950
- if (!mesh) continue;
5466
+ const mesh2 = parts[part];
5467
+ if (!mesh2) continue;
3951
5468
  for (const r of builders[part].ranges) {
3952
5469
  const tag = r.tag || rootId;
3953
5470
  const m = meta.get(tag) ?? { kind: "stem" };
3954
5471
  const min = [Infinity, Infinity, Infinity];
3955
5472
  const max = [-Infinity, -Infinity, -Infinity];
3956
5473
  for (let i = r.indexStart; i < r.indexStart + r.indexCount; i++) {
3957
- const v = mesh.indices[i] * 3;
5474
+ const v = mesh2.indices[i] * 3;
3958
5475
  for (let a = 0; a < 3; a++) {
3959
- const c = mesh.positions[v + a];
5476
+ const c = mesh2.positions[v + a];
3960
5477
  if (c < min[a]) min[a] = c;
3961
5478
  if (c > max[a]) max[a] = c;
3962
5479
  }
@@ -3968,7 +5485,7 @@ var GameVegetationThree = (() => {
3968
5485
  else if (m.kind === "crown" || m.kind === "fruit") pivot = [(min[0] + max[0]) / 2, (min[1] + max[1]) / 2, (min[2] + max[2]) / 2];
3969
5486
  else pivot = [(min[0] + max[0]) / 2, min[1], (min[2] + max[2]) / 2];
3970
5487
  if (m.kind === "trunk" || m.kind === "stem" || m.kind === "pot" || m.kind === "soil") pivot = [0, min[1], 0];
3971
- let material = materialKeyForPart(part, mesh.material, condition);
5488
+ let material = materialKeyForPart(part, mesh2.material, condition);
3972
5489
  if (m.kind === "pot") material = "pot";
3973
5490
  else if (m.kind === "soil") material = "soil";
3974
5491
  const parentTag = hang ? hang.parent : m.parent;
@@ -4012,10 +5529,10 @@ var GameVegetationThree = (() => {
4012
5529
  const go = { seed: hashMix(base, p.seed), lod, condition: opts.condition, season: opts.season };
4013
5530
  let plant;
4014
5531
  if (smallLod !== lod) {
4015
- const cheap = generate(spec, { ...go, lod: smallLod });
5532
+ const cheap = generate2(spec, { ...go, lod: smallLod });
4016
5533
  if (cheap.bounds.height * p.scale <= smallMax) plant = cheap;
4017
5534
  }
4018
- plant ?? (plant = generate(spec, go));
5535
+ plant ?? (plant = generate2(spec, go));
4019
5536
  total += plant.triangleCount;
4020
5537
  entries.push({ p, plant, go, spec });
4021
5538
  }
@@ -4039,7 +5556,7 @@ var GameVegetationThree = (() => {
4039
5556
  const group = entries.filter((e) => !e.dropped && kindOf(e) === kind && e.plant.lod < 2).sort((a, b) => a.plant.bounds.height * a.p.scale - b.plant.bounds.height * b.p.scale);
4040
5557
  for (const e of group) {
4041
5558
  if (total <= budget) break;
4042
- const cheap = generate(e.spec, { ...e.go, lod: 2 });
5559
+ const cheap = generate2(e.spec, { ...e.go, lod: 2 });
4043
5560
  total += cheap.triangleCount - e.plant.triangleCount;
4044
5561
  e.plant = cheap;
4045
5562
  }
@@ -4055,9 +5572,9 @@ var GameVegetationThree = (() => {
4055
5572
  lodCounts[plant.lod]++;
4056
5573
  const { parts } = plant;
4057
5574
  const tagsOf = (part) => {
4058
- const mesh = parts[part];
4059
- if (!mesh) return void 0;
4060
- const tags = new Array(mesh.triangleCount).fill("");
5575
+ const mesh2 = parts[part];
5576
+ if (!mesh2) return void 0;
5577
+ const tags = new Array(mesh2.triangleCount).fill("");
4061
5578
  for (const pc of plant.pieces) {
4062
5579
  if (pc.part !== part) continue;
4063
5580
  for (let t = pc.indexStart / 3; t < (pc.indexStart + pc.indexCount) / 3; t++) tags[t] = `${pi}|${pc.id}`;
@@ -4082,8 +5599,8 @@ var GameVegetationThree = (() => {
4082
5599
  };
4083
5600
  for (const k of Object.keys(meshes)) if (!meshes[k]) delete meshes[k];
4084
5601
  const rangeOf = /* @__PURE__ */ new Map();
4085
- for (const [mesh, b] of [["wood", wood], ["foliage", foliage], ["flowers", flowers]]) {
4086
- for (const r of b.ranges) if (r.tag) rangeOf.set(r.tag, { mesh, indexStart: r.indexStart, indexCount: r.indexCount });
5602
+ for (const [mesh2, b] of [["wood", wood], ["foliage", foliage], ["flowers", flowers]]) {
5603
+ for (const r of b.ranges) if (r.tag) rangeOf.set(r.tag, { mesh: mesh2, indexStart: r.indexStart, indexCount: r.indexCount });
4087
5604
  }
4088
5605
  const pieceTable = kept.map(({ plantIndex, e }) => ({
4089
5606
  plantIndex,
@@ -4111,7 +5628,7 @@ var GameVegetationThree = (() => {
4111
5628
  function extractPlant(lot, plantIndex) {
4112
5629
  const e = entryOf(lot, plantIndex);
4113
5630
  return {
4114
- plant: generate(e.spec, { ...e.generateOptions, species: e.species }),
5631
+ plant: generate2(e.spec, { ...e.generateOptions, species: e.species }),
4115
5632
  placement: { species: e.species, x: e.x, z: e.z, ry: e.ry, scale: e.scale },
4116
5633
  ranges: e.pieces
4117
5634
  };
@@ -4173,10 +5690,10 @@ var GameVegetationThree = (() => {
4173
5690
  }
4174
5691
  return w[w.length - 1].id;
4175
5692
  }
4176
- function scatter(area, rules, opts) {
4177
- const poly = regionPolygon(area);
5693
+ function scatter(area3, rules, opts) {
5694
+ const poly = regionPolygon(area3);
4178
5695
  const seed = toSeed(opts.seed);
4179
- const area2 = polygonArea(poly);
5696
+ const area22 = polygonArea(poly);
4180
5697
  let minX = Infinity;
4181
5698
  let minZ = Infinity;
4182
5699
  let maxX = -Infinity;
@@ -4192,11 +5709,11 @@ var GameVegetationThree = (() => {
4192
5709
  const grid = /* @__PURE__ */ new Map();
4193
5710
  const key = (cx, cz) => cx + "," + cz;
4194
5711
  const out = [];
4195
- const inradius = Math.max(0.5, Math.sqrt(area2) * 0.5);
5712
+ const inradius = Math.max(0.5, Math.sqrt(area22) * 0.5);
4196
5713
  rules.forEach((rule, ri) => {
4197
5714
  const rng = new Rng(hashMix(seed, ri + 1));
4198
5715
  const ex = [...globalEx, ...(rule.exclude ?? []).map(regionPolygon)];
4199
- let target = Math.round(area2 * rule.density);
5716
+ let target = Math.round(area22 * rule.density);
4200
5717
  if (rule.maxCount !== void 0) target = Math.min(target, rule.maxCount);
4201
5718
  const prefer = rule.prefer ?? "any";
4202
5719
  const edgeW = rule.edgeWidth ?? Math.max(0.4, rule.minDistance * 0.8);
@@ -4243,8 +5760,8 @@ var GameVegetationThree = (() => {
4243
5760
  }
4244
5761
  if (!ok) continue;
4245
5762
  const k = key(cx, cz);
4246
- const list = grid.get(k);
4247
- if (list) list.push({ x, z, md: rule.minDistance });
5763
+ const list2 = grid.get(k);
5764
+ if (list2) list2.push({ x, z, md: rule.minDistance });
4248
5765
  else grid.set(k, [{ x, z, md: rule.minDistance }]);
4249
5766
  out.push({ species: spec, x, z, ry, scale, seed: sd });
4250
5767
  placed++;
@@ -4348,7 +5865,7 @@ var GameVegetationThree = (() => {
4348
5865
  toBufferGeometry: () => toBufferGeometry
4349
5866
  });
4350
5867
  var MAX_ACTORS = 4;
4351
- var COMMON = (
5868
+ var COMMON2 = (
4352
5869
  /* glsl */
4353
5870
  `
4354
5871
  #include <common>
@@ -4409,13 +5926,13 @@ gl_Position = projectionMatrix * mvPosition;
4409
5926
  const patch = (m) => {
4410
5927
  m.onBeforeCompile = (shader) => {
4411
5928
  Object.assign(shader.uniforms, uniforms);
4412
- shader.vertexShader = shader.vertexShader.replace("#include <common>", COMMON).replace("#include <project_vertex>", PROJECT);
5929
+ shader.vertexShader = shader.vertexShader.replace("#include <common>", COMMON2).replace("#include <project_vertex>", PROJECT);
4413
5930
  };
4414
5931
  m.customProgramCacheKey = () => "vegetation-sway-v1";
4415
5932
  };
4416
5933
  const flat = opts.flatShading !== false;
4417
5934
  const rough = typeof opts.roughness === "number" ? opts.roughness : 0.85;
4418
- const make = (flatShading, double, roughness) => {
5935
+ const make2 = (flatShading, double, roughness) => {
4419
5936
  const m = new THREE.MeshStandardMaterial({
4420
5937
  vertexColors: true,
4421
5938
  flatShading,
@@ -4426,11 +5943,11 @@ gl_Position = projectionMatrix * mvPosition;
4426
5943
  patch(m);
4427
5944
  return m;
4428
5945
  };
4429
- const wood = make(false, false, 0.95);
4430
- const foliage = make(flat, true, rough);
4431
- const flowers = make(flat, true, 0.7);
4432
- const fruit = make(flat, false, 0.55);
4433
- const spines = make(true, true, 0.8);
5946
+ const wood = make2(false, false, 0.95);
5947
+ const foliage = make2(flat, true, rough);
5948
+ const flowers = make2(flat, true, 0.7);
5949
+ const fruit = make2(flat, false, 0.55);
5950
+ const spines = make2(true, true, 0.8);
4434
5951
  const dir = uniforms.uWindDir.value;
4435
5952
  return {
4436
5953
  materialIds: resolveMaterialIds(opts.materialIds),
@@ -4468,13 +5985,13 @@ gl_Position = projectionMatrix * mvPosition;
4468
5985
  };
4469
5986
  }
4470
5987
  var PART_ORDER2 = ["wood", "foliage", "flowers", "fruit", "spines"];
4471
- function toBufferGeometry(THREE, mesh) {
5988
+ function toBufferGeometry(THREE, mesh2) {
4472
5989
  const g = new THREE.BufferGeometry();
4473
- g.setAttribute("position", new THREE.BufferAttribute(mesh.positions, 3));
4474
- g.setAttribute("normal", new THREE.BufferAttribute(mesh.normals, 3));
4475
- g.setAttribute("color", new THREE.BufferAttribute(mesh.colors, 3));
4476
- g.setAttribute("sway", new THREE.BufferAttribute(mesh.sway, 1));
4477
- g.setIndex(new THREE.BufferAttribute(mesh.indices, 1));
5990
+ g.setAttribute("position", new THREE.BufferAttribute(mesh2.positions, 3));
5991
+ g.setAttribute("normal", new THREE.BufferAttribute(mesh2.normals, 3));
5992
+ g.setAttribute("color", new THREE.BufferAttribute(mesh2.colors, 3));
5993
+ g.setAttribute("sway", new THREE.BufferAttribute(mesh2.sway, 1));
5994
+ g.setIndex(new THREE.BufferAttribute(mesh2.indices, 1));
4478
5995
  g.computeBoundingSphere();
4479
5996
  g.computeBoundingBox();
4480
5997
  return g;
@@ -4488,18 +6005,18 @@ gl_Position = projectionMatrix * mvPosition;
4488
6005
  function meshFor(THREE, data, material, ids, condition) {
4489
6006
  const geo = toBufferGeometry(THREE, data);
4490
6007
  inflate(geo, 0.4);
4491
- const mesh = new THREE.Mesh(geo, material);
4492
- mesh.name = data.kind;
4493
- mesh.userData.damageable = { material: data.material };
4494
- if (ids) mesh.userData.destructionMaterial = ids[materialKeyForPart(data.kind, data.material, condition)];
4495
- return mesh;
6008
+ const mesh2 = new THREE.Mesh(geo, material);
6009
+ mesh2.name = data.kind;
6010
+ mesh2.userData.damageable = { material: data.material };
6011
+ if (ids) mesh2.userData.destructionMaterial = ids[materialKeyForPart(data.kind, data.material, condition)];
6012
+ return mesh2;
4496
6013
  }
4497
- function slicePiece(mesh, indexStart, indexCount, origin) {
6014
+ function slicePiece(mesh2, indexStart, indexCount, origin) {
4498
6015
  const remap = /* @__PURE__ */ new Map();
4499
6016
  const order = [];
4500
6017
  const indices = new Uint32Array(indexCount);
4501
6018
  for (let i = 0; i < indexCount; i++) {
4502
- const v = mesh.indices[indexStart + i];
6019
+ const v = mesh2.indices[indexStart + i];
4503
6020
  let n = remap.get(v);
4504
6021
  if (n === void 0) {
4505
6022
  n = order.length;
@@ -4514,14 +6031,14 @@ gl_Position = projectionMatrix * mvPosition;
4514
6031
  const sway = new Float32Array(order.length);
4515
6032
  for (let i = 0; i < order.length; i++) {
4516
6033
  const v = order[i];
4517
- positions[i * 3] = mesh.positions[v * 3] - origin[0];
4518
- positions[i * 3 + 1] = mesh.positions[v * 3 + 1] - origin[1];
4519
- positions[i * 3 + 2] = mesh.positions[v * 3 + 2] - origin[2];
4520
- normals.set(mesh.normals.subarray(v * 3, v * 3 + 3), i * 3);
4521
- colors.set(mesh.colors.subarray(v * 3, v * 3 + 3), i * 3);
4522
- sway[i] = mesh.sway[v];
6034
+ positions[i * 3] = mesh2.positions[v * 3] - origin[0];
6035
+ positions[i * 3 + 1] = mesh2.positions[v * 3 + 1] - origin[1];
6036
+ positions[i * 3 + 2] = mesh2.positions[v * 3 + 2] - origin[2];
6037
+ normals.set(mesh2.normals.subarray(v * 3, v * 3 + 3), i * 3);
6038
+ colors.set(mesh2.colors.subarray(v * 3, v * 3 + 3), i * 3);
6039
+ sway[i] = mesh2.sway[v];
4523
6040
  }
4524
- return { positions, normals, colors, sway, indices, triangleCount: indexCount / 3, kind: mesh.kind, material: mesh.material };
6041
+ return { positions, normals, colors, sway, indices, triangleCount: indexCount / 3, kind: mesh2.kind, material: mesh2.material };
4525
6042
  }
4526
6043
  function createPlantObject(THREE, plant, materials, options = {}) {
4527
6044
  const mats = materials ?? createVegetationMaterials(THREE);
@@ -4533,13 +6050,13 @@ gl_Position = projectionMatrix * mvPosition;
4533
6050
  const src = plant.parts[pc.part];
4534
6051
  if (!src) continue;
4535
6052
  const data = slicePiece(src, pc.indexStart, pc.indexCount, pc.pivot);
4536
- const mesh = meshFor(THREE, data, mats[pc.part]);
4537
- mesh.name = pc.id;
4538
- mesh.position.set(pc.pivot[0], pc.pivot[1], pc.pivot[2]);
6053
+ const mesh2 = meshFor(THREE, data, mats[pc.part]);
6054
+ mesh2.name = pc.id;
6055
+ mesh2.position.set(pc.pivot[0], pc.pivot[1], pc.pivot[2]);
4539
6056
  const id = ids[pc.material];
4540
- mesh.userData.destructionMaterial = id;
4541
- mesh.userData.destructionPart = { id: pc.id, kind: pc.kind, parent: pc.parent, material: id, materialKey: pc.material, ...pc.radius === void 0 ? {} : { radius: pc.radius, length: pc.length, axis: pc.axis, base: pc.base } };
4542
- g.add(mesh);
6057
+ mesh2.userData.destructionMaterial = id;
6058
+ mesh2.userData.destructionPart = { id: pc.id, kind: pc.kind, parent: pc.parent, material: id, materialKey: pc.material, ...pc.radius === void 0 ? {} : { radius: pc.radius, length: pc.length, axis: pc.axis, base: pc.base } };
6059
+ g.add(mesh2);
4543
6060
  }
4544
6061
  g.userData = { collider: plant.collider, bendable: plant.bendable, thorny: plant.thorny, species: plant.species, bounds: plant.bounds, pieces: plant.pieces, separable: true };
4545
6062
  return g;
@@ -4618,10 +6135,10 @@ gl_Position = projectionMatrix * mvPosition;
4618
6135
  const d = opts.distances ?? [0, 25, 60];
4619
6136
  const lod = new THREE.LOD();
4620
6137
  for (const l of [0, 1, 2]) {
4621
- const plant = generate(spec, { ...opts, lod: l });
6138
+ const plant = generate2(spec, { ...opts, lod: l });
4622
6139
  lod.addLevel(createPlantObject(THREE, plant, mats), d[l]);
4623
6140
  }
4624
- lod.userData = { collider: generate(spec, { ...opts, lod: 2 }).collider };
6141
+ lod.userData = { collider: generate2(spec, { ...opts, lod: 2 }).collider };
4625
6142
  return lod;
4626
6143
  }
4627
6144
 
@@ -7830,16 +9347,16 @@ gl_Position = projectionMatrix * mvPosition;
7830
9347
  };
7831
9348
  }
7832
9349
  function pickForContext(region, context, rng) {
7833
- const list = region.contexts[context];
7834
- if (!list || list.length === 0) throw new Error(`game-vegetation-species: region "${region.id}" has no context "${context}"`);
9350
+ const list2 = region.contexts[context];
9351
+ if (!list2 || list2.length === 0) throw new Error(`game-vegetation-species: region "${region.id}" has no context "${context}"`);
7835
9352
  const next = toNext(rng);
7836
- const total = list.reduce((a, b) => a + b.weight, 0);
9353
+ const total = list2.reduce((a, b) => a + b.weight, 0);
7837
9354
  let r = next() * total;
7838
- for (const it of list) {
9355
+ for (const it of list2) {
7839
9356
  r -= it.weight;
7840
9357
  if (r <= 0) return it.species;
7841
9358
  }
7842
- return list[list.length - 1].species;
9359
+ return list2[list2.length - 1].species;
7843
9360
  }
7844
9361
 
7845
9362
  // src/test-area/nursery.ts
@@ -7867,10 +9384,10 @@ gl_Position = projectionMatrix * mvPosition;
7867
9384
  for (const planting of plantings) {
7868
9385
  const { rules, picks } = species2.scatterRulesFor(species2.regions.br, planting.context, seed, planting.options);
7869
9386
  for (const p of picks) used.add(p.id);
7870
- planting.areas.forEach((area, i) => {
9387
+ planting.areas.forEach((area3, i) => {
7871
9388
  const exclude = [EX_HOUSE, EX_PATH];
7872
9389
  const perArea = rules.map((rule) => ({ ...rule, maxCount: Math.max(1, Math.ceil(rule.maxCount / planting.areas.length)) }));
7873
- placements.push(...sdk.scatter(area, perArea, { seed: `${seed}:${planting.tag}:${i}`, exclude }));
9390
+ placements.push(...sdk.scatter(area3, perArea, { seed: `${seed}:${planting.tag}:${i}`, exclude }));
7874
9391
  });
7875
9392
  }
7876
9393
  return { placements, used };
@@ -7878,45 +9395,46 @@ gl_Position = projectionMatrix * mvPosition;
7878
9395
  function buildScenery(THREE) {
7879
9396
  const g = new THREE.Group();
7880
9397
  g.name = "nursery-scenery";
7881
- const material = (color, roughness = 0.9) => new THREE.MeshStandardMaterial({ color, roughness, metalness: 0 });
9398
+ const material = (color2, roughness = 0.9) => new THREE.MeshStandardMaterial({ color: color2, roughness, metalness: 0 });
7882
9399
  const mats = { ground: material(6257989), asphalt: material(3816770), concrete: material(12039080), house: material(14931645), roof: material(10112312), door: material(7031343), glass: material(10471389, 0.2), wall: material(13222578) };
7883
- const box = (w, h, d, m, x, y, z) => {
7884
- const mesh = new THREE.Mesh(new THREE.BoxGeometry(w, h, d), m);
7885
- mesh.position.set(x, y, z);
7886
- mesh.castShadow = mesh.receiveShadow = true;
7887
- g.add(mesh);
7888
- return mesh;
9400
+ const box2 = (w, h, d, m, x, y, z) => {
9401
+ const mesh2 = new THREE.Mesh(new THREE.BoxGeometry(w, h, d), m);
9402
+ mesh2.position.set(x, y, z);
9403
+ mesh2.castShadow = mesh2.receiveShadow = true;
9404
+ g.add(mesh2);
9405
+ return mesh2;
7889
9406
  };
7890
9407
  const yard = new THREE.Mesh(new THREE.PlaneGeometry(LOT.W, LOT.D), mats.ground);
7891
9408
  yard.rotation.x = -Math.PI / 2;
7892
9409
  yard.position.set(6, 0.01, 10);
7893
9410
  yard.receiveShadow = true;
7894
9411
  g.add(yard);
7895
- box(30, 0.04, 4.6, mats.asphalt, 6, 0, -4.6);
7896
- box(30, 0.1, 2.2, mats.concrete, 6, 0.04, -1.1);
7897
- box(1.6, 0.03, 6.6, mats.concrete, 6, 0.02, 3.2);
9412
+ box2(30, 0.04, 4.6, mats.asphalt, 6, 0, -4.6);
9413
+ box2(30, 0.1, 2.2, mats.concrete, 6, 0.04, -1.1);
9414
+ box2(1.6, 0.03, 6.6, mats.concrete, 6, 0.02, 3.2);
7898
9415
  const hw = HOUSE.x1 - HOUSE.x0;
7899
9416
  const hd = HOUSE.z1 - HOUSE.z0;
7900
9417
  const hcx = (HOUSE.x0 + HOUSE.x1) / 2;
7901
9418
  const hcz = (HOUSE.z0 + HOUSE.z1) / 2;
7902
- box(hw, 2.8, hd, mats.house, hcx, 1.4, hcz);
9419
+ box2(hw, 2.8, hd, mats.house, hcx, 1.4, hcz);
7903
9420
  const roof = new THREE.Mesh(new THREE.ConeGeometry(1, 1.5, 4), mats.roof);
7904
9421
  roof.rotation.y = Math.PI / 4;
7905
9422
  roof.scale.set((hw + 1.2) / Math.SQRT2, 1, (hd + 1.2) / Math.SQRT2);
7906
9423
  roof.position.set(hcx, 2.8 + 0.75, hcz);
7907
9424
  roof.castShadow = roof.receiveShadow = true;
7908
9425
  g.add(roof);
7909
- box(1.1, 2.1, 0.08, mats.door, 6, 1.05, HOUSE.z0 - 0.04);
7910
- box(1.6, 1.1, 0.08, mats.glass, 3.8, 1.5, HOUSE.z0 - 0.04);
7911
- box(1.6, 1.1, 0.08, mats.glass, 8.2, 1.5, HOUSE.z0 - 0.04);
7912
- box(5, 1.4, 0.2, mats.wall, 2.5, 0.7, 0);
7913
- box(5, 1.4, 0.2, mats.wall, 9.5, 0.7, 0);
7914
- box(0.2, 1.8, LOT.D, mats.wall, 0, 0.9, 10);
7915
- box(0.2, 1.8, LOT.D, mats.wall, LOT.W, 0.9, 10);
7916
- box(LOT.W, 1.8, 0.2, mats.wall, 6, 0.9, LOT.D);
9426
+ box2(1.1, 2.1, 0.08, mats.door, 6, 1.05, HOUSE.z0 - 0.04);
9427
+ box2(1.6, 1.1, 0.08, mats.glass, 3.8, 1.5, HOUSE.z0 - 0.04);
9428
+ box2(1.6, 1.1, 0.08, mats.glass, 8.2, 1.5, HOUSE.z0 - 0.04);
9429
+ box2(5, 1.4, 0.2, mats.wall, 2.5, 0.7, 0);
9430
+ box2(5, 1.4, 0.2, mats.wall, 9.5, 0.7, 0);
9431
+ box2(0.2, 1.8, LOT.D, mats.wall, 0, 0.9, 10);
9432
+ box2(0.2, 1.8, LOT.D, mats.wall, LOT.W, 0.9, 10);
9433
+ box2(LOT.W, 1.8, 0.2, mats.wall, 6, 0.9, LOT.D);
7917
9434
  return g;
7918
9435
  }
7919
9436
  function createNursery(sdk, species2, THREE, materials, parent, origin) {
9437
+ const T = shapeGeometries(THREE);
7920
9438
  const group = new THREE.Group();
7921
9439
  group.name = "nursery";
7922
9440
  group.position.set(origin[0], 0, origin[1]);
@@ -7926,13 +9444,13 @@ gl_Position = projectionMatrix * mvPosition;
7926
9444
  let scenery = null;
7927
9445
  let lotObject = null;
7928
9446
  let data = null;
7929
- let stats = null;
9447
+ let stats2 = null;
7930
9448
  let actor = null;
7931
9449
  const walker = { x: WAY[0][0], z: WAY[0][1], waypoint: 0, on: false };
7932
9450
  const actors = [{ x: 0, y: 0.8, z: 0, radius: 1.5 }];
7933
9451
  let attached = false;
7934
- const disposeObject = (object) => {
7935
- object.traverse((child) => {
9452
+ const disposeObject = (object2) => {
9453
+ object2.traverse((child) => {
7936
9454
  child.geometry?.dispose?.();
7937
9455
  });
7938
9456
  };
@@ -7946,8 +9464,8 @@ gl_Position = projectionMatrix * mvPosition;
7946
9464
  const ensure = () => {
7947
9465
  if (attached) return;
7948
9466
  attached = true;
7949
- scenery = buildScenery(THREE);
7950
- const body = THREE.CapsuleGeometry ? new THREE.CapsuleGeometry(0.28, 1, 4, 10) : new THREE.CylinderGeometry(0.28, 0.28, 1.56, 10);
9467
+ scenery = buildScenery(T);
9468
+ const body = T.CapsuleGeometry ? new T.CapsuleGeometry(0.28, 1, 4, 10) : new T.CylinderGeometry(0.28, 0.28, 1.56, 10);
7951
9469
  actor = new THREE.Mesh(body, new THREE.MeshStandardMaterial({ color: 14254635, roughness: 0.7 }));
7952
9470
  actor.castShadow = true;
7953
9471
  actor.position.set(walker.x, 0.78, walker.z);
@@ -7971,7 +9489,7 @@ gl_Position = projectionMatrix * mvPosition;
7971
9489
  return {
7972
9490
  group,
7973
9491
  get stats() {
7974
- return stats;
9492
+ return stats2;
7975
9493
  },
7976
9494
  get planted() {
7977
9495
  return lotObject !== null;
@@ -8004,12 +9522,12 @@ gl_Position = projectionMatrix * mvPosition;
8004
9522
  });
8005
9523
  dynamic.add(lotObject);
8006
9524
  for (const c of data.colliders) {
8007
- const m = new THREE.Mesh(new THREE.CylinderGeometry(c.r, c.r, c.h, 14, 1, true), new THREE.MeshBasicMaterial({ color: c.damage ? 16742938 : 15017245, wireframe: true }));
9525
+ const m = new THREE.Mesh(new T.CylinderGeometry(c.r, c.r, c.h, 14, 1, true), new THREE.MeshBasicMaterial({ color: c.damage ? 16742938 : 15017245, wireframe: true }));
8008
9526
  m.position.set(c.x, c.h / 2, c.z);
8009
9527
  colliders.add(m);
8010
9528
  }
8011
- stats = { triangles: data.triangleCount, plants: data.plantCount, colliders: data.colliders.length, meshes: Object.keys(data.meshes).length, lod: data.lodCounts, buildMs, species: used.size };
8012
- return stats;
9529
+ stats2 = { triangles: data.triangleCount, plants: data.plantCount, colliders: data.colliders.length, meshes: Object.keys(data.meshes).length, lod: data.lodCounts, buildMs, species: used.size };
9530
+ return stats2;
8013
9531
  },
8014
9532
  /** The colliders of the lot as wire cylinders. */
8015
9533
  showColliders(on) {
@@ -8071,7 +9589,7 @@ gl_Position = projectionMatrix * mvPosition;
8071
9589
  actor = null;
8072
9590
  }
8073
9591
  data = null;
8074
- stats = null;
9592
+ stats2 = null;
8075
9593
  walker.x = WAY[0][0];
8076
9594
  walker.z = WAY[0][1];
8077
9595
  walker.waypoint = 0;
@@ -8079,6 +9597,15 @@ gl_Position = projectionMatrix * mvPosition;
8079
9597
  };
8080
9598
  }
8081
9599
 
9600
+ // ../game-contracts/dist/index.js
9601
+ var KIT_ORIGIN_KEY = "kitOrigin";
9602
+ function markKitOrigin(object2, origin) {
9603
+ const node = object2;
9604
+ node.userData = node.userData ?? {};
9605
+ node.userData[KIT_ORIGIN_KEY] = { ...origin };
9606
+ return object2;
9607
+ }
9608
+
8082
9609
  // src/test-area/plants.ts
8083
9610
  var PLANT_SEED = 3;
8084
9611
  var PLANT_DEFS = [
@@ -8122,25 +9649,25 @@ gl_Position = projectionMatrix * mvPosition;
8122
9649
  return plant;
8123
9650
  };
8124
9651
  function buildObject(THREE, def) {
8125
- const root = new THREE.Group();
9652
+ const root = markKitOrigin(new THREE.Group(), { owner: "game-vegetation-three", kind: "plant", id: def.base ?? def.id });
8126
9653
  root.name = def.id;
8127
9654
  const segments = def.segments ?? 1;
8128
9655
  let spacing = 0;
8129
9656
  for (let s = 0; s < segments; s++) {
8130
9657
  const plant = plantFor(def, s);
8131
- const object = sdk.createPlantObject(THREE, plant, materials(THREE), { separable: true });
9658
+ const object2 = sdk.createPlantObject(THREE, plant, materials(THREE), { separable: true });
8132
9659
  const prefix = segments > 1 ? `s${s}_` : "";
8133
- const children = object.children.slice();
9660
+ const children = object2.children.slice();
8134
9661
  if (s === 0 && segments > 1) {
8135
9662
  const g0 = children[0].geometry;
8136
9663
  g0.computeBoundingBox();
8137
9664
  spacing = (g0.boundingBox.max.x - g0.boundingBox.min.x) * 0.9;
8138
9665
  }
8139
- for (const mesh of children) {
8140
- const piece = mesh.userData.destructionPart;
9666
+ for (const mesh2 of children) {
9667
+ const piece = mesh2.userData.destructionPart;
8141
9668
  const bits = String(piece.id).split(":");
8142
9669
  const id = prefix + sanitize(piece.id);
8143
- mesh.name = id;
9670
+ mesh2.name = id;
8144
9671
  const dx = (s - (segments - 1) / 2) * spacing;
8145
9672
  const meta = {
8146
9673
  id,
@@ -8156,10 +9683,10 @@ gl_Position = projectionMatrix * mvPosition;
8156
9683
  axis: piece.axis,
8157
9684
  dx
8158
9685
  };
8159
- mesh.userData.veg = meta;
8160
- mesh.position.x += dx;
8161
- mesh.castShadow = true;
8162
- root.add(mesh);
9686
+ mesh2.userData.veg = meta;
9687
+ mesh2.position.x += dx;
9688
+ mesh2.castShadow = true;
9689
+ root.add(mesh2);
8163
9690
  }
8164
9691
  if (s === 0) {
8165
9692
  root.userData.collider = plant.collider || null;
@@ -8381,7 +9908,7 @@ gl_Position = projectionMatrix * mvPosition;
8381
9908
  const j = specOf(so).joints.filter((x) => x.id === jid)[0];
8382
9909
  const a = partSpec(so, j.a);
8383
9910
  const b = partSpec(so, j.b);
8384
- const box = (p) => {
9911
+ const box2 = (p) => {
8385
9912
  const h = p.shape.kind === "box" ? p.shape.size.map((s) => s / 2) : [p.shape.radius, p.shape.height / 2, p.shape.radius];
8386
9913
  const r = p.rotation || [0, 0, 0];
8387
9914
  const cx = Math.cos(r[0]), sx = Math.sin(r[0]), cz = Math.cos(r[2]), sz = Math.sin(r[2]);
@@ -8398,8 +9925,8 @@ gl_Position = projectionMatrix * mvPosition;
8398
9925
  }
8399
9926
  return { min: mn, max: mx };
8400
9927
  };
8401
- const A_ = box(a);
8402
- const B_ = box(b);
9928
+ const A_ = box2(a);
9929
+ const B_ = box2(b);
8403
9930
  return world(so, [0, 1, 2].map((k) => (Math.max(A_.min[k], B_.min[k]) + Math.min(A_.max[k], B_.max[k])) / 2));
8404
9931
  };
8405
9932
  const lost = (p) => !p || p.status === "broken" || p.status === "ashes" || p.status === "melted";
@@ -8828,17 +10355,17 @@ gl_Position = projectionMatrix * mvPosition;
8828
10355
  };
8829
10356
  if (host.bench.layer("colliders") && root.userData.collider && root.userData.collider.kind) {
8830
10357
  const c = root.userData.collider;
8831
- const wire = new three.Mesh(new three.CylinderGeometry(c.radius, c.radius, c.height, 14, 1, true), new three.MeshBasicMaterial({ color: root.userData.thorny ? 16742938 : 15017245, wireframe: true }));
10358
+ const wire = new three.Mesh(new (shapeGeometries(three)).CylinderGeometry(c.radius, c.radius, c.height, 14, 1, true), new three.MeshBasicMaterial({ color: root.userData.thorny ? 16742938 : 15017245, wireframe: true }));
8832
10359
  wire.position.set(0, c.height / 2, 0);
8833
10360
  mark(wire);
8834
10361
  }
8835
- for (const mesh of root.children) {
8836
- const v = mesh.userData?.veg;
8837
- if (!v || !mesh.geometry) continue;
10362
+ for (const mesh2 of root.children) {
10363
+ const v = mesh2.userData?.veg;
10364
+ if (!v || !mesh2.geometry) continue;
8838
10365
  if (host.bench.layer("piece_boxes")) {
8839
- mesh.geometry.computeBoundingBox();
8840
- const box = mesh.geometry.boundingBox.clone().translate(mesh.position);
8841
- mark(new three.Box3Helper(box, 6737151));
10366
+ mesh2.geometry.computeBoundingBox();
10367
+ const box2 = mesh2.geometry.boundingBox.clone().translate(mesh2.position);
10368
+ mark(new three.Box3Helper(box2, 6737151));
8842
10369
  }
8843
10370
  if (host.bench.layer("wood_axes") && v.radius !== void 0 && v.length !== void 0 && v.axis && !v.sub) {
8844
10371
  const base = pieceBase(root, v);
@@ -8854,8 +10381,8 @@ gl_Position = projectionMatrix * mvPosition;
8854
10381
  helpersShown = boxKey();
8855
10382
  };
8856
10383
  const pieceBase = (root, v) => {
8857
- const mesh = root.children.find((c) => c.userData?.veg?.id === v.id);
8858
- const base = mesh?.userData?.destructionPart?.base;
10384
+ const mesh2 = root.children.find((c) => c.userData?.veg?.id === v.id);
10385
+ const base = mesh2?.userData?.destructionPart?.base;
8859
10386
  return Array.isArray(base) ? base : null;
8860
10387
  };
8861
10388
  const nurseryOf = () => {
@@ -8866,9 +10393,9 @@ gl_Position = projectionMatrix * mvPosition;
8866
10393
  const plantLot = () => {
8867
10394
  const n = nurseryOf();
8868
10395
  if (!n || !host) return;
8869
- const stats = n.plant(settings);
10396
+ const stats2 = n.plant(settings);
8870
10397
  n.showColliders(Boolean(host.bench?.layer("colliders")));
8871
- host.log(fill(text.lot.planted, stats.plants, stats.triangles, stats.colliders), { plants: stats.plants, triangles: stats.triangles });
10398
+ host.log(fill(text.lot.planted, stats2.plants, stats2.triangles, stats2.colliders), { plants: stats2.plants, triangles: stats2.triangles });
8872
10399
  };
8873
10400
  const replant = () => {
8874
10401
  if (nursery?.planted) plantLot();
@@ -8937,12 +10464,12 @@ gl_Position = projectionMatrix * mvPosition;
8937
10464
  let triangles = 0;
8938
10465
  let pieces = 0;
8939
10466
  for (const entry of placed.values()) {
8940
- entry.root.traverse((mesh) => {
8941
- if (!mesh.isMesh || mesh.userData.helper) return;
8942
- for (let p = mesh; p; p = p.parent) if (p.visible === false) return;
10467
+ entry.root.traverse((mesh2) => {
10468
+ if (!mesh2.isMesh || mesh2.userData.helper) return;
10469
+ for (let p = mesh2; p; p = p.parent) if (p.visible === false) return;
8943
10470
  drawCalls += 1;
8944
- if (mesh.userData.veg) pieces += 1;
8945
- const g = mesh.geometry;
10471
+ if (mesh2.userData.veg) pieces += 1;
10472
+ const g = mesh2.geometry;
8946
10473
  triangles += (g.index ? g.index.count : g.attributes.position.count) / 3;
8947
10474
  });
8948
10475
  }
@@ -8997,9 +10524,9 @@ gl_Position = projectionMatrix * mvPosition;
8997
10524
  { kind: "choice", id: "season", name: text.controls.season, hint: text.hints.season, options: ["spring", "summer", "autumn", "winter"].map((id) => ({ id, name: text.options.season[id] })), default: "spring" },
8998
10525
  { kind: "number", id: "wind", name: text.controls.wind, hint: text.hints.wind, min: 0, max: 1, step: 0.05, default: 0.35 },
8999
10526
  { kind: "number", id: "gust", name: text.controls.gust, hint: text.hints.gust, min: 0, max: 1, step: 0.05, default: 0.15 },
9000
- { kind: "action", id: "plant_lot", name: text.actions.plant_lot },
10527
+ { kind: "action", id: "plant_lot", name: text.actions.plant_lot, slow: true },
9001
10528
  { kind: "action", id: "clear_lot", name: text.actions.clear_lot },
9002
- { kind: "action", id: "toggle_walker", name: text.actions.toggle_walker }
10529
+ { kind: "action", id: "toggle_walker", name: text.actions.toggle_walker, slow: true }
9003
10530
  ],
9004
10531
  layers: () => ["colliders", "piece_boxes", "wood_axes"].map((id) => ({ id, name: text.layers[id], default: false })),
9005
10532
  metrics: () => [