@adatechnology/game-characters-three 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,6 +21,7 @@ var GameCharactersThree = (() => {
21
21
  // src/index.ts
22
22
  var index_exports = {};
23
23
  __export(index_exports, {
24
+ AVATAR_AREA_ID: () => AVATAR_AREA_ID,
24
25
  BAKE_NEUTRAL_POSE: () => BAKE_NEUTRAL_POSE,
25
26
  BODY_CHUNK: () => BODY_CHUNK,
26
27
  BODY_MATERIAL_DEF: () => BODY_MATERIAL_DEF,
@@ -30,6 +31,10 @@ var GameCharactersThree = (() => {
30
31
  CHARACTER_SOUND_BANK: () => CHARACTER_SOUND_BANK,
31
32
  EXTRAS: () => EXTRAS,
32
33
  FACE_FEATURES: () => FACE_FEATURES,
34
+ FIRST_PERSON_BOB: () => FIRST_PERSON_BOB,
35
+ FIRST_PERSON_COLORS: () => FIRST_PERSON_COLORS,
36
+ FIRST_PERSON_RIG: () => FIRST_PERSON_RIG,
37
+ FIRST_PERSON_STANCES: () => FIRST_PERSON_STANCES,
33
38
  HAND_ITEMS: () => HAND_ITEMS,
34
39
  HATS: () => HATS,
35
40
  HIT_PRESETS: () => HIT_PRESETS,
@@ -51,6 +56,7 @@ var GameCharactersThree = (() => {
51
56
  blobRadii: () => blobRadii,
52
57
  bloodLookOfAge: () => bloodLookOfAge,
53
58
  buildInstancedBody: () => buildInstancedBody,
59
+ createAvatarTestModule: () => createAvatarTestModule,
54
60
  createBestBuilder: () => createBestBuilder,
55
61
  createBodyBatch: () => createBodyBatch,
56
62
  createBodyChunk: () => createBodyChunk,
@@ -58,12 +64,14 @@ var GameCharactersThree = (() => {
58
64
  createCharacterSound: () => createCharacterSound,
59
65
  createCharactersTestModule: () => createCharactersTestModule,
60
66
  createEye: () => createEye,
67
+ createFirstPersonArms: () => createFirstPersonArms,
61
68
  createFluidsBridge: () => createFluidsBridge,
62
69
  createFlyingLimbs: () => createFlyingLimbs,
63
70
  createFlyingPieces: () => createFlyingPieces,
64
71
  createGlowTexture: () => createGlowTexture,
65
72
  createPendulum: () => createPendulum,
66
73
  createPersonBuilder: () => createPersonBuilder,
74
+ createPlayerAvatar: () => createPlayerAvatar,
67
75
  createRigAnimator: () => createRigAnimator,
68
76
  createVariantBatches: () => createVariantBatches,
69
77
  createWoundMaterials: () => createWoundMaterials,
@@ -78,8 +86,10 @@ var GameCharactersThree = (() => {
78
86
  makeStump: () => makeStump,
79
87
  registerBodyMaterial: () => registerBodyMaterial,
80
88
  ringWound: () => ringWound,
89
+ solveTwoBone: () => solveTwoBone,
81
90
  starGeometry: () => starGeometry,
82
91
  stepPendulum: () => stepPendulum,
92
+ toRoomAvatar: () => toRoomAvatar,
83
93
  woundBodyOf: () => woundBodyOf,
84
94
  woundDecal: () => woundDecal
85
95
  });
@@ -160,7 +170,1540 @@ var GameCharactersThree = (() => {
160
170
  var HIP_PIVOT = "vec3(0.,0.95,0.)";
161
171
  var createBodyChunk = ({ hipHeight = 0.95 } = {}) => hipHeight === 0.95 ? BODY_CHUNK : BODY_CHUNK.replaceAll(HIP_PIVOT, `vec3(0.,${hipHeight},0.)`);
162
172
 
173
+ // ../game-shapes/dist/chunk-R4RY23RH.js
174
+ function canonicalJson(value) {
175
+ if (value === null) return "null";
176
+ if (typeof value === "number") return Object.is(value, -0) ? "-0" : Number.isFinite(value) ? String(value) : JSON.stringify(String(value));
177
+ if (typeof value === "string") return JSON.stringify(value);
178
+ if (typeof value === "boolean") return value ? "true" : "false";
179
+ if (typeof value === "function") throw new Error("game-shapes: a function cannot be part of a shape (register it as a generator)");
180
+ if (ArrayBuffer.isView(value)) return canonicalJson(Array.from(value));
181
+ if (Array.isArray(value)) return `[${value.map((item) => item === void 0 ? "null" : canonicalJson(item)).join(",")}]`;
182
+ if (typeof value === "object") {
183
+ const record = value;
184
+ const keys = Object.keys(record).filter((key) => record[key] !== void 0).sort();
185
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`).join(",")}}`;
186
+ }
187
+ return "null";
188
+ }
189
+ function needsUint32(array) {
190
+ for (let i = array.length - 1; i >= 0; --i) if (array[i] >= 65535) return true;
191
+ return false;
192
+ }
193
+ var indexArray = (indices) => needsUint32(indices) ? new Uint32Array(indices) : new Uint16Array(indices);
194
+ function pack(type, parameters, a) {
195
+ return {
196
+ type,
197
+ parameters,
198
+ positions: new Float32Array(a.vertices),
199
+ normals: new Float32Array(a.normals),
200
+ uvs: new Float32Array(a.uvs),
201
+ ...a.indices ? { indices: indexArray(a.indices) } : {},
202
+ groups: a.groups
203
+ };
204
+ }
205
+ var normalize3 = (x, y, z) => {
206
+ const length = Math.sqrt(x * x + y * y + z * z);
207
+ const s = 1 / (length || 1);
208
+ return [x * s, y * s, z * s];
209
+ };
210
+ function box(width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1) {
211
+ const parameters = { width, height, depth, widthSegments, heightSegments, depthSegments };
212
+ widthSegments = Math.floor(widthSegments);
213
+ heightSegments = Math.floor(heightSegments);
214
+ depthSegments = Math.floor(depthSegments);
215
+ const indices = [];
216
+ const vertices = [];
217
+ const normals = [];
218
+ const uvs = [];
219
+ const groups = [];
220
+ let numberOfVertices = 0;
221
+ let groupStart = 0;
222
+ const buildPlane = (u, v, w, udir, vdir, width2, height2, depth2, gridX, gridY, materialIndex) => {
223
+ const segmentWidth = width2 / gridX;
224
+ const segmentHeight = height2 / gridY;
225
+ const widthHalf = width2 / 2;
226
+ const heightHalf = height2 / 2;
227
+ const depthHalf = depth2 / 2;
228
+ const gridX1 = gridX + 1;
229
+ const gridY1 = gridY + 1;
230
+ let vertexCounter = 0;
231
+ let groupCount = 0;
232
+ const vector = { x: 0, y: 0, z: 0 };
233
+ for (let iy = 0; iy < gridY1; iy++) {
234
+ const y = iy * segmentHeight - heightHalf;
235
+ for (let ix = 0; ix < gridX1; ix++) {
236
+ const x = ix * segmentWidth - widthHalf;
237
+ vector[u] = x * udir;
238
+ vector[v] = y * vdir;
239
+ vector[w] = depthHalf;
240
+ vertices.push(vector.x, vector.y, vector.z);
241
+ vector[u] = 0;
242
+ vector[v] = 0;
243
+ vector[w] = depth2 > 0 ? 1 : -1;
244
+ normals.push(vector.x, vector.y, vector.z);
245
+ uvs.push(ix / gridX);
246
+ uvs.push(1 - iy / gridY);
247
+ vertexCounter += 1;
248
+ }
249
+ }
250
+ for (let iy = 0; iy < gridY; iy++) {
251
+ for (let ix = 0; ix < gridX; ix++) {
252
+ const a = numberOfVertices + ix + gridX1 * iy;
253
+ const b = numberOfVertices + ix + gridX1 * (iy + 1);
254
+ const c = numberOfVertices + (ix + 1) + gridX1 * (iy + 1);
255
+ const d = numberOfVertices + (ix + 1) + gridX1 * iy;
256
+ indices.push(a, b, d);
257
+ indices.push(b, c, d);
258
+ groupCount += 6;
259
+ }
260
+ }
261
+ groups.push({ start: groupStart, count: groupCount, materialIndex });
262
+ groupStart += groupCount;
263
+ numberOfVertices += vertexCounter;
264
+ };
265
+ buildPlane("z", "y", "x", -1, -1, depth, height, width, depthSegments, heightSegments, 0);
266
+ buildPlane("z", "y", "x", 1, -1, depth, height, -width, depthSegments, heightSegments, 1);
267
+ buildPlane("x", "z", "y", 1, 1, width, depth, height, widthSegments, depthSegments, 2);
268
+ buildPlane("x", "z", "y", 1, -1, width, depth, -height, widthSegments, depthSegments, 3);
269
+ buildPlane("x", "y", "z", 1, -1, width, height, depth, widthSegments, heightSegments, 4);
270
+ buildPlane("x", "y", "z", -1, -1, width, height, -depth, widthSegments, heightSegments, 5);
271
+ return pack("BoxGeometry", parameters, { vertices, normals, uvs, indices, groups });
272
+ }
273
+ function cylinderArrays(radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength) {
274
+ radialSegments = Math.floor(radialSegments);
275
+ heightSegments = Math.floor(heightSegments);
276
+ const indices = [];
277
+ const vertices = [];
278
+ const normals = [];
279
+ const uvs = [];
280
+ const groups = [];
281
+ let index = 0;
282
+ const indexArray2 = [];
283
+ const halfHeight = height / 2;
284
+ let groupStart = 0;
285
+ const generateTorso = () => {
286
+ let groupCount = 0;
287
+ const slope = (radiusBottom - radiusTop) / height;
288
+ for (let y = 0; y <= heightSegments; y++) {
289
+ const indexRow = [];
290
+ const v = y / heightSegments;
291
+ const radius = v * (radiusBottom - radiusTop) + radiusTop;
292
+ for (let x = 0; x <= radialSegments; x++) {
293
+ const u = x / radialSegments;
294
+ const theta = u * thetaLength + thetaStart;
295
+ const sinTheta = Math.sin(theta);
296
+ const cosTheta = Math.cos(theta);
297
+ vertices.push(radius * sinTheta, -v * height + halfHeight, radius * cosTheta);
298
+ const n = normalize3(sinTheta, slope, cosTheta);
299
+ normals.push(n[0], n[1], n[2]);
300
+ uvs.push(u, 1 - v);
301
+ indexRow.push(index++);
302
+ }
303
+ indexArray2.push(indexRow);
304
+ }
305
+ for (let x = 0; x < radialSegments; x++) {
306
+ for (let y = 0; y < heightSegments; y++) {
307
+ const a = indexArray2[y][x];
308
+ const b = indexArray2[y + 1][x];
309
+ const c = indexArray2[y + 1][x + 1];
310
+ const d = indexArray2[y][x + 1];
311
+ indices.push(a, b, d);
312
+ indices.push(b, c, d);
313
+ groupCount += 6;
314
+ }
315
+ }
316
+ groups.push({ start: groupStart, count: groupCount, materialIndex: 0 });
317
+ groupStart += groupCount;
318
+ };
319
+ const generateCap = (top) => {
320
+ const centerIndexStart = index;
321
+ let groupCount = 0;
322
+ const radius = top === true ? radiusTop : radiusBottom;
323
+ const sign2 = top === true ? 1 : -1;
324
+ for (let x = 1; x <= radialSegments; x++) {
325
+ vertices.push(0, halfHeight * sign2, 0);
326
+ normals.push(0, sign2, 0);
327
+ uvs.push(0.5, 0.5);
328
+ index++;
329
+ }
330
+ const centerIndexEnd = index;
331
+ for (let x = 0; x <= radialSegments; x++) {
332
+ const u = x / radialSegments;
333
+ const theta = u * thetaLength + thetaStart;
334
+ const cosTheta = Math.cos(theta);
335
+ const sinTheta = Math.sin(theta);
336
+ vertices.push(radius * sinTheta, halfHeight * sign2, radius * cosTheta);
337
+ normals.push(0, sign2, 0);
338
+ uvs.push(cosTheta * 0.5 + 0.5, sinTheta * 0.5 * sign2 + 0.5);
339
+ index++;
340
+ }
341
+ for (let x = 0; x < radialSegments; x++) {
342
+ const c = centerIndexStart + x;
343
+ const i = centerIndexEnd + x;
344
+ if (top === true) indices.push(i, i + 1, c);
345
+ else indices.push(i + 1, i, c);
346
+ groupCount += 3;
347
+ }
348
+ groups.push({ start: groupStart, count: groupCount, materialIndex: top === true ? 1 : 2 });
349
+ groupStart += groupCount;
350
+ };
351
+ generateTorso();
352
+ if (openEnded === false) {
353
+ if (radiusTop > 0) generateCap(true);
354
+ if (radiusBottom > 0) generateCap(false);
355
+ }
356
+ return { vertices, normals, uvs, indices, groups };
357
+ }
358
+ function cylinder(radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2) {
359
+ const parameters = { radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength };
360
+ return pack("CylinderGeometry", parameters, cylinderArrays(radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength));
361
+ }
362
+ function cone(radius = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2) {
363
+ const parameters = { radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength };
364
+ return pack("ConeGeometry", parameters, cylinderArrays(0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength));
365
+ }
366
+ function sphere(radius = 1, widthSegments = 32, heightSegments = 16, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI) {
367
+ const parameters = { radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength };
368
+ widthSegments = Math.max(3, Math.floor(widthSegments));
369
+ heightSegments = Math.max(2, Math.floor(heightSegments));
370
+ const thetaEnd = Math.min(thetaStart + thetaLength, Math.PI);
371
+ let index = 0;
372
+ const grid = [];
373
+ const indices = [];
374
+ const vertices = [];
375
+ const normals = [];
376
+ const uvs = [];
377
+ for (let iy = 0; iy <= heightSegments; iy++) {
378
+ const verticesRow = [];
379
+ const v = iy / heightSegments;
380
+ let uOffset = 0;
381
+ if (iy === 0 && thetaStart === 0) uOffset = 0.5 / widthSegments;
382
+ else if (iy === heightSegments && thetaEnd === Math.PI) uOffset = -0.5 / widthSegments;
383
+ for (let ix = 0; ix <= widthSegments; ix++) {
384
+ const u = ix / widthSegments;
385
+ const x = -radius * Math.cos(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength);
386
+ const y = radius * Math.cos(thetaStart + v * thetaLength);
387
+ const z = radius * Math.sin(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength);
388
+ vertices.push(x, y, z);
389
+ const n = normalize3(x, y, z);
390
+ normals.push(n[0], n[1], n[2]);
391
+ uvs.push(u + uOffset, 1 - v);
392
+ verticesRow.push(index++);
393
+ }
394
+ grid.push(verticesRow);
395
+ }
396
+ for (let iy = 0; iy < heightSegments; iy++) {
397
+ for (let ix = 0; ix < widthSegments; ix++) {
398
+ const a = grid[iy][ix + 1];
399
+ const b = grid[iy][ix];
400
+ const c = grid[iy + 1][ix];
401
+ const d = grid[iy + 1][ix + 1];
402
+ if (iy !== 0 || thetaStart > 0) indices.push(a, b, d);
403
+ if (iy !== heightSegments - 1 || thetaEnd < Math.PI) indices.push(b, c, d);
404
+ }
405
+ }
406
+ return pack("SphereGeometry", parameters, { vertices, normals, uvs, indices, groups: [] });
407
+ }
408
+ function plane(width = 1, height = 1, widthSegments = 1, heightSegments = 1) {
409
+ const parameters = { width, height, widthSegments, heightSegments };
410
+ const widthHalf = width / 2;
411
+ const heightHalf = height / 2;
412
+ const gridX = Math.floor(widthSegments);
413
+ const gridY = Math.floor(heightSegments);
414
+ const gridX1 = gridX + 1;
415
+ const gridY1 = gridY + 1;
416
+ const segmentWidth = width / gridX;
417
+ const segmentHeight = height / gridY;
418
+ const indices = [];
419
+ const vertices = [];
420
+ const normals = [];
421
+ const uvs = [];
422
+ for (let iy = 0; iy < gridY1; iy++) {
423
+ const y = iy * segmentHeight - heightHalf;
424
+ for (let ix = 0; ix < gridX1; ix++) {
425
+ const x = ix * segmentWidth - widthHalf;
426
+ vertices.push(x, -y, 0);
427
+ normals.push(0, 0, 1);
428
+ uvs.push(ix / gridX);
429
+ uvs.push(1 - iy / gridY);
430
+ }
431
+ }
432
+ for (let iy = 0; iy < gridY; iy++) {
433
+ for (let ix = 0; ix < gridX; ix++) {
434
+ const a = ix + gridX1 * iy;
435
+ const b = ix + gridX1 * (iy + 1);
436
+ const c = ix + 1 + gridX1 * (iy + 1);
437
+ const d = ix + 1 + gridX1 * iy;
438
+ indices.push(a, b, d);
439
+ indices.push(b, c, d);
440
+ }
441
+ }
442
+ return pack("PlaneGeometry", parameters, { vertices, normals, uvs, indices, groups: [] });
443
+ }
444
+ function circle(radius = 1, segments = 32, thetaStart = 0, thetaLength = Math.PI * 2) {
445
+ const parameters = { radius, segments, thetaStart, thetaLength };
446
+ segments = Math.max(3, segments);
447
+ const indices = [];
448
+ const vertices = [];
449
+ const normals = [];
450
+ const uvs = [];
451
+ vertices.push(0, 0, 0);
452
+ normals.push(0, 0, 1);
453
+ uvs.push(0.5, 0.5);
454
+ for (let s = 0, i = 3; s <= segments; s++, i += 3) {
455
+ const segment = thetaStart + s / segments * thetaLength;
456
+ vertices.push(radius * Math.cos(segment), radius * Math.sin(segment), 0);
457
+ normals.push(0, 0, 1);
458
+ uvs.push((vertices[i] / radius + 1) / 2, (vertices[i + 1] / radius + 1) / 2);
459
+ }
460
+ for (let i = 1; i <= segments; i++) indices.push(i, i + 1, 0);
461
+ return pack("CircleGeometry", parameters, { vertices, normals, uvs, indices, groups: [] });
462
+ }
463
+ function ring(innerRadius = 0.5, outerRadius = 1, thetaSegments = 32, phiSegments = 1, thetaStart = 0, thetaLength = Math.PI * 2) {
464
+ const parameters = { innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength };
465
+ thetaSegments = Math.max(3, thetaSegments);
466
+ phiSegments = Math.max(1, phiSegments);
467
+ const indices = [];
468
+ const vertices = [];
469
+ const normals = [];
470
+ const uvs = [];
471
+ let radius = innerRadius;
472
+ const radiusStep = (outerRadius - innerRadius) / phiSegments;
473
+ for (let j = 0; j <= phiSegments; j++) {
474
+ for (let i = 0; i <= thetaSegments; i++) {
475
+ const segment = thetaStart + i / thetaSegments * thetaLength;
476
+ const x = radius * Math.cos(segment);
477
+ const y = radius * Math.sin(segment);
478
+ vertices.push(x, y, 0);
479
+ normals.push(0, 0, 1);
480
+ uvs.push((x / outerRadius + 1) / 2, (y / outerRadius + 1) / 2);
481
+ }
482
+ radius += radiusStep;
483
+ }
484
+ for (let j = 0; j < phiSegments; j++) {
485
+ const thetaSegmentLevel = j * (thetaSegments + 1);
486
+ for (let i = 0; i < thetaSegments; i++) {
487
+ const segment = i + thetaSegmentLevel;
488
+ const a = segment;
489
+ const b = segment + thetaSegments + 1;
490
+ const c = segment + thetaSegments + 2;
491
+ const d = segment + 1;
492
+ indices.push(a, b, d);
493
+ indices.push(b, c, d);
494
+ }
495
+ }
496
+ return pack("RingGeometry", parameters, { vertices, normals, uvs, indices, groups: [] });
497
+ }
498
+ function lathe(points, segments = 12, phiStart = 0, phiLength = Math.PI * 2) {
499
+ const parameters = { points: points.map(([x, y]) => ({ x, y })), segments, phiStart, phiLength };
500
+ segments = Math.floor(segments);
501
+ phiLength = Math.max(0, Math.min(Math.PI * 2, phiLength));
502
+ const indices = [];
503
+ const vertices = [];
504
+ const uvs = [];
505
+ const initNormals = [];
506
+ const normals = [];
507
+ const inverseSegments = 1 / segments;
508
+ const normal = { x: 0, y: 0, z: 0 };
509
+ const curNormal = { x: 0, y: 0, z: 0 };
510
+ const prevNormal = { x: 0, y: 0, z: 0 };
511
+ let dx = 0;
512
+ let dy = 0;
513
+ const last = points.length - 1;
514
+ const px = (j) => points[j][0];
515
+ const py = (j) => points[j][1];
516
+ const setNormalized = () => {
517
+ const n = normalize3(normal.x, normal.y, normal.z);
518
+ normal.x = n[0];
519
+ normal.y = n[1];
520
+ normal.z = n[2];
521
+ };
522
+ for (let j = 0; j <= last; j++) {
523
+ if (j === 0) {
524
+ dx = px(j + 1) - px(j);
525
+ dy = py(j + 1) - py(j);
526
+ normal.x = dy * 1;
527
+ normal.y = -dx;
528
+ normal.z = dy * 0;
529
+ prevNormal.x = normal.x;
530
+ prevNormal.y = normal.y;
531
+ prevNormal.z = normal.z;
532
+ setNormalized();
533
+ initNormals.push(normal.x, normal.y, normal.z);
534
+ } else if (j === last) {
535
+ initNormals.push(prevNormal.x, prevNormal.y, prevNormal.z);
536
+ } else {
537
+ dx = px(j + 1) - px(j);
538
+ dy = py(j + 1) - py(j);
539
+ normal.x = dy * 1;
540
+ normal.y = -dx;
541
+ normal.z = dy * 0;
542
+ curNormal.x = normal.x;
543
+ curNormal.y = normal.y;
544
+ curNormal.z = normal.z;
545
+ normal.x += prevNormal.x;
546
+ normal.y += prevNormal.y;
547
+ normal.z += prevNormal.z;
548
+ setNormalized();
549
+ initNormals.push(normal.x, normal.y, normal.z);
550
+ prevNormal.x = curNormal.x;
551
+ prevNormal.y = curNormal.y;
552
+ prevNormal.z = curNormal.z;
553
+ }
554
+ }
555
+ for (let i = 0; i <= segments; i++) {
556
+ const phi = phiStart + i * inverseSegments * phiLength;
557
+ const sin = Math.sin(phi);
558
+ const cos = Math.cos(phi);
559
+ for (let j = 0; j <= last; j++) {
560
+ vertices.push(px(j) * sin, py(j), px(j) * cos);
561
+ uvs.push(i / segments, j / (points.length - 1));
562
+ const x = initNormals[3 * j + 0] * sin;
563
+ const y = initNormals[3 * j + 1];
564
+ const z = initNormals[3 * j + 0] * cos;
565
+ normals.push(x, y, z);
566
+ }
567
+ }
568
+ for (let i = 0; i < segments; i++) {
569
+ for (let j = 0; j < points.length - 1; j++) {
570
+ const base = j + i * points.length;
571
+ const a = base;
572
+ const b = base + points.length;
573
+ const c = base + points.length + 1;
574
+ const d = base + 1;
575
+ indices.push(a, b, d);
576
+ indices.push(c, d, b);
577
+ }
578
+ }
579
+ return pack("LatheGeometry", parameters, { vertices, normals, uvs, indices, groups: [] });
580
+ }
581
+ function torus(radius = 1, tube = 0.4, radialSegments = 12, tubularSegments = 48, arc = Math.PI * 2) {
582
+ const parameters = { radius, tube, radialSegments, tubularSegments, arc };
583
+ radialSegments = Math.floor(radialSegments);
584
+ tubularSegments = Math.floor(tubularSegments);
585
+ const indices = [];
586
+ const vertices = [];
587
+ const normals = [];
588
+ const uvs = [];
589
+ for (let j = 0; j <= radialSegments; j++) {
590
+ for (let i = 0; i <= tubularSegments; i++) {
591
+ const u = i / tubularSegments * arc;
592
+ const v = j / radialSegments * Math.PI * 2;
593
+ const x = (radius + tube * Math.cos(v)) * Math.cos(u);
594
+ const y = (radius + tube * Math.cos(v)) * Math.sin(u);
595
+ const z = tube * Math.sin(v);
596
+ vertices.push(x, y, z);
597
+ const cx = radius * Math.cos(u);
598
+ const cy = radius * Math.sin(u);
599
+ const n = normalize3(x - cx, y - cy, z - 0);
600
+ normals.push(n[0], n[1], n[2]);
601
+ uvs.push(i / tubularSegments);
602
+ uvs.push(j / radialSegments);
603
+ }
604
+ }
605
+ for (let j = 1; j <= radialSegments; j++) {
606
+ for (let i = 1; i <= tubularSegments; i++) {
607
+ const a = (tubularSegments + 1) * j + i - 1;
608
+ const b = (tubularSegments + 1) * (j - 1) + i - 1;
609
+ const c = (tubularSegments + 1) * (j - 1) + i;
610
+ const d = (tubularSegments + 1) * j + i;
611
+ indices.push(a, b, d);
612
+ indices.push(b, c, d);
613
+ }
614
+ }
615
+ return pack("TorusGeometry", parameters, { vertices, normals, uvs, indices, groups: [] });
616
+ }
617
+ function difference(size, subtract) {
618
+ const [w, h, d] = size;
619
+ const hw = w / 2;
620
+ const hh = h / 2;
621
+ const hd = d / 2;
622
+ 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);
623
+ const cuts = (lo, hi, values) => [.../* @__PURE__ */ new Set([lo, hi, ...values.filter((v) => v > lo && v < hi)])].sort((a, b) => a - b);
624
+ const xs = cuts(-hw, hw, holes.flatMap((hole) => [hole.x0, hole.x1]));
625
+ const ys = cuts(-hh, hh, holes.flatMap((hole) => [hole.y0, hole.y1]));
626
+ const nx = xs.length - 1;
627
+ const ny = ys.length - 1;
628
+ const solid = (i, j) => {
629
+ if (i < 0 || j < 0 || i >= nx || j >= ny) return false;
630
+ const cx = (xs[i] + xs[i + 1]) / 2;
631
+ const cy = (ys[j] + ys[j + 1]) / 2;
632
+ return !holes.some((hole) => cx > hole.x0 && cx < hole.x1 && cy > hole.y0 && cy < hole.y1);
633
+ };
634
+ const positions = [];
635
+ const normals = [];
636
+ const uvs = [];
637
+ const indices = [];
638
+ const quad = (corners, normal, uv) => {
639
+ const base = positions.length / 3;
640
+ for (let k = 0; k < 4; k++) {
641
+ positions.push(...corners[k]);
642
+ normals.push(...normal);
643
+ uvs.push(...uv[k]);
644
+ }
645
+ indices.push(base, base + 1, base + 2, base, base + 2, base + 3);
646
+ };
647
+ const fu = (x) => (x + hw) / w;
648
+ const fv = (y) => (y + hh) / h;
649
+ for (let j = 0; j < ny; j++) {
650
+ for (let i = 0; i < nx; i++) {
651
+ if (!solid(i, j)) continue;
652
+ const x0 = xs[i];
653
+ const x1 = xs[i + 1];
654
+ const y0 = ys[j];
655
+ const y1 = ys[j + 1];
656
+ 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)]]);
657
+ 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)]]);
658
+ const zu = (z) => (z + hd) / d;
659
+ 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)]]);
660
+ 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)]]);
661
+ 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)]]);
662
+ 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)]]);
663
+ }
664
+ }
665
+ return {
666
+ type: "BufferGeometry",
667
+ parameters: { size: [w, h, d], subtract: holes.map((hole) => ({ min: [hole.x0, hole.y0], max: [hole.x1, hole.y1] })) },
668
+ positions: new Float32Array(positions),
669
+ normals: new Float32Array(normals),
670
+ uvs: new Float32Array(uvs),
671
+ indices: indexArray(indices),
672
+ groups: []
673
+ };
674
+ }
675
+ var Earcut = {
676
+ triangulate: function(data, holeIndices, dim = 2) {
677
+ const hasHoles = holeIndices && holeIndices.length;
678
+ const outerLen = hasHoles ? holeIndices[0] * dim : data.length;
679
+ let outerNode = linkedList(data, 0, outerLen, dim, true);
680
+ const triangles = [];
681
+ if (!outerNode || outerNode.next === outerNode.prev) return triangles;
682
+ let minX, minY, maxX, maxY, x, y, invSize;
683
+ if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
684
+ if (data.length > 80 * dim) {
685
+ minX = maxX = data[0];
686
+ minY = maxY = data[1];
687
+ for (let i = dim; i < outerLen; i += dim) {
688
+ x = data[i];
689
+ y = data[i + 1];
690
+ if (x < minX) minX = x;
691
+ if (y < minY) minY = y;
692
+ if (x > maxX) maxX = x;
693
+ if (y > maxY) maxY = y;
694
+ }
695
+ invSize = Math.max(maxX - minX, maxY - minY);
696
+ invSize = invSize !== 0 ? 32767 / invSize : 0;
697
+ }
698
+ earcutLinked(outerNode, triangles, dim, minX, minY, invSize, 0);
699
+ return triangles;
700
+ }
701
+ };
702
+ function linkedList(data, start, end, dim, clockwise) {
703
+ let i, last;
704
+ if (clockwise === signedArea(data, start, end, dim) > 0) {
705
+ for (i = start; i < end; i += dim) last = insertNode(i, data[i], data[i + 1], last);
706
+ } else {
707
+ for (i = end - dim; i >= start; i -= dim) last = insertNode(i, data[i], data[i + 1], last);
708
+ }
709
+ if (last && equals(last, last.next)) {
710
+ removeNode(last);
711
+ last = last.next;
712
+ }
713
+ return last;
714
+ }
715
+ function filterPoints(start, end) {
716
+ if (!start) return start;
717
+ if (!end) end = start;
718
+ let p2 = start, again;
719
+ do {
720
+ again = false;
721
+ if (!p2.steiner && (equals(p2, p2.next) || area(p2.prev, p2, p2.next) === 0)) {
722
+ removeNode(p2);
723
+ p2 = end = p2.prev;
724
+ if (p2 === p2.next) break;
725
+ again = true;
726
+ } else {
727
+ p2 = p2.next;
728
+ }
729
+ } while (again || p2 !== end);
730
+ return end;
731
+ }
732
+ function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
733
+ if (!ear) return;
734
+ if (!pass && invSize) indexCurve(ear, minX, minY, invSize);
735
+ let stop = ear, prev, next;
736
+ while (ear.prev !== ear.next) {
737
+ prev = ear.prev;
738
+ next = ear.next;
739
+ if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) {
740
+ triangles.push(prev.i / dim | 0);
741
+ triangles.push(ear.i / dim | 0);
742
+ triangles.push(next.i / dim | 0);
743
+ removeNode(ear);
744
+ ear = next.next;
745
+ stop = next.next;
746
+ continue;
747
+ }
748
+ ear = next;
749
+ if (ear === stop) {
750
+ if (!pass) {
751
+ earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1);
752
+ } else if (pass === 1) {
753
+ ear = cureLocalIntersections(filterPoints(ear), triangles, dim);
754
+ earcutLinked(ear, triangles, dim, minX, minY, invSize, 2);
755
+ } else if (pass === 2) {
756
+ splitEarcut(ear, triangles, dim, minX, minY, invSize);
757
+ }
758
+ break;
759
+ }
760
+ }
761
+ }
762
+ function isEar(ear) {
763
+ const a = ear.prev, b = ear, c = ear.next;
764
+ if (area(a, b, c) >= 0) return false;
765
+ const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
766
+ 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;
767
+ let p2 = c.next;
768
+ while (p2 !== a) {
769
+ if (p2.x >= x0 && p2.x <= x1 && p2.y >= y0 && p2.y <= y1 && pointInTriangle(ax, ay, bx, by, cx, cy, p2.x, p2.y) && area(p2.prev, p2, p2.next) >= 0) return false;
770
+ p2 = p2.next;
771
+ }
772
+ return true;
773
+ }
774
+ function isEarHashed(ear, minX, minY, invSize) {
775
+ const a = ear.prev, b = ear, c = ear.next;
776
+ if (area(a, b, c) >= 0) return false;
777
+ const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
778
+ 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;
779
+ const minZ = zOrder(x0, y0, minX, minY, invSize), maxZ = zOrder(x1, y1, minX, minY, invSize);
780
+ let p2 = ear.prevZ, n = ear.nextZ;
781
+ while (p2 && p2.z >= minZ && n && n.z <= maxZ) {
782
+ if (p2.x >= x0 && p2.x <= x1 && p2.y >= y0 && p2.y <= y1 && p2 !== a && p2 !== c && pointInTriangle(ax, ay, bx, by, cx, cy, p2.x, p2.y) && area(p2.prev, p2, p2.next) >= 0) return false;
783
+ p2 = p2.prevZ;
784
+ 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;
785
+ n = n.nextZ;
786
+ }
787
+ while (p2 && p2.z >= minZ) {
788
+ if (p2.x >= x0 && p2.x <= x1 && p2.y >= y0 && p2.y <= y1 && p2 !== a && p2 !== c && pointInTriangle(ax, ay, bx, by, cx, cy, p2.x, p2.y) && area(p2.prev, p2, p2.next) >= 0) return false;
789
+ p2 = p2.prevZ;
790
+ }
791
+ while (n && n.z <= maxZ) {
792
+ 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;
793
+ n = n.nextZ;
794
+ }
795
+ return true;
796
+ }
797
+ function cureLocalIntersections(start, triangles, dim) {
798
+ let p2 = start;
799
+ do {
800
+ const a = p2.prev, b = p2.next.next;
801
+ if (!equals(a, b) && intersects(a, p2, p2.next, b) && locallyInside(a, b) && locallyInside(b, a)) {
802
+ triangles.push(a.i / dim | 0);
803
+ triangles.push(p2.i / dim | 0);
804
+ triangles.push(b.i / dim | 0);
805
+ removeNode(p2);
806
+ removeNode(p2.next);
807
+ p2 = start = b;
808
+ }
809
+ p2 = p2.next;
810
+ } while (p2 !== start);
811
+ return filterPoints(p2);
812
+ }
813
+ function splitEarcut(start, triangles, dim, minX, minY, invSize) {
814
+ let a = start;
815
+ do {
816
+ let b = a.next.next;
817
+ while (b !== a.prev) {
818
+ if (a.i !== b.i && isValidDiagonal(a, b)) {
819
+ let c = splitPolygon(a, b);
820
+ a = filterPoints(a, a.next);
821
+ c = filterPoints(c, c.next);
822
+ earcutLinked(a, triangles, dim, minX, minY, invSize, 0);
823
+ earcutLinked(c, triangles, dim, minX, minY, invSize, 0);
824
+ return;
825
+ }
826
+ b = b.next;
827
+ }
828
+ a = a.next;
829
+ } while (a !== start);
830
+ }
831
+ function eliminateHoles(data, holeIndices, outerNode, dim) {
832
+ const queue = [];
833
+ let i, len, start, end, list2;
834
+ for (i = 0, len = holeIndices.length; i < len; i++) {
835
+ start = holeIndices[i] * dim;
836
+ end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
837
+ list2 = linkedList(data, start, end, dim, false);
838
+ if (list2 === list2.next) list2.steiner = true;
839
+ queue.push(getLeftmost(list2));
840
+ }
841
+ queue.sort(compareX);
842
+ for (i = 0; i < queue.length; i++) {
843
+ outerNode = eliminateHole(queue[i], outerNode);
844
+ }
845
+ return outerNode;
846
+ }
847
+ function compareX(a, b) {
848
+ return a.x - b.x;
849
+ }
850
+ function eliminateHole(hole, outerNode) {
851
+ const bridge = findHoleBridge(hole, outerNode);
852
+ if (!bridge) {
853
+ return outerNode;
854
+ }
855
+ const bridgeReverse = splitPolygon(bridge, hole);
856
+ filterPoints(bridgeReverse, bridgeReverse.next);
857
+ return filterPoints(bridge, bridge.next);
858
+ }
859
+ function findHoleBridge(hole, outerNode) {
860
+ let p2 = outerNode, qx = -Infinity, m;
861
+ const hx = hole.x, hy = hole.y;
862
+ do {
863
+ if (hy <= p2.y && hy >= p2.next.y && p2.next.y !== p2.y) {
864
+ const x = p2.x + (hy - p2.y) * (p2.next.x - p2.x) / (p2.next.y - p2.y);
865
+ if (x <= hx && x > qx) {
866
+ qx = x;
867
+ m = p2.x < p2.next.x ? p2 : p2.next;
868
+ if (x === hx) return m;
869
+ }
870
+ }
871
+ p2 = p2.next;
872
+ } while (p2 !== outerNode);
873
+ if (!m) return null;
874
+ const stop = m, mx = m.x, my = m.y;
875
+ let tanMin = Infinity, tan;
876
+ p2 = m;
877
+ do {
878
+ if (hx >= p2.x && p2.x >= mx && hx !== p2.x && pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p2.x, p2.y)) {
879
+ tan = Math.abs(hy - p2.y) / (hx - p2.x);
880
+ if (locallyInside(p2, hole) && (tan < tanMin || tan === tanMin && (p2.x > m.x || p2.x === m.x && sectorContainsSector(m, p2)))) {
881
+ m = p2;
882
+ tanMin = tan;
883
+ }
884
+ }
885
+ p2 = p2.next;
886
+ } while (p2 !== stop);
887
+ return m;
888
+ }
889
+ function sectorContainsSector(m, p2) {
890
+ return area(m.prev, m, p2.prev) < 0 && area(p2.next, m, m.next) < 0;
891
+ }
892
+ function indexCurve(start, minX, minY, invSize) {
893
+ let p2 = start;
894
+ do {
895
+ if (p2.z === 0) p2.z = zOrder(p2.x, p2.y, minX, minY, invSize);
896
+ p2.prevZ = p2.prev;
897
+ p2.nextZ = p2.next;
898
+ p2 = p2.next;
899
+ } while (p2 !== start);
900
+ p2.prevZ.nextZ = null;
901
+ p2.prevZ = null;
902
+ sortLinked(p2);
903
+ }
904
+ function sortLinked(list2) {
905
+ let i, p2, q, e, tail, numMerges, pSize, qSize, inSize = 1;
906
+ do {
907
+ p2 = list2;
908
+ list2 = null;
909
+ tail = null;
910
+ numMerges = 0;
911
+ while (p2) {
912
+ numMerges++;
913
+ q = p2;
914
+ pSize = 0;
915
+ for (i = 0; i < inSize; i++) {
916
+ pSize++;
917
+ q = q.nextZ;
918
+ if (!q) break;
919
+ }
920
+ qSize = inSize;
921
+ while (pSize > 0 || qSize > 0 && q) {
922
+ if (pSize !== 0 && (qSize === 0 || !q || p2.z <= q.z)) {
923
+ e = p2;
924
+ p2 = p2.nextZ;
925
+ pSize--;
926
+ } else {
927
+ e = q;
928
+ q = q.nextZ;
929
+ qSize--;
930
+ }
931
+ if (tail) tail.nextZ = e;
932
+ else list2 = e;
933
+ e.prevZ = tail;
934
+ tail = e;
935
+ }
936
+ p2 = q;
937
+ }
938
+ tail.nextZ = null;
939
+ inSize *= 2;
940
+ } while (numMerges > 1);
941
+ return list2;
942
+ }
943
+ function zOrder(x, y, minX, minY, invSize) {
944
+ x = (x - minX) * invSize | 0;
945
+ y = (y - minY) * invSize | 0;
946
+ x = (x | x << 8) & 16711935;
947
+ x = (x | x << 4) & 252645135;
948
+ x = (x | x << 2) & 858993459;
949
+ x = (x | x << 1) & 1431655765;
950
+ y = (y | y << 8) & 16711935;
951
+ y = (y | y << 4) & 252645135;
952
+ y = (y | y << 2) & 858993459;
953
+ y = (y | y << 1) & 1431655765;
954
+ return x | y << 1;
955
+ }
956
+ function getLeftmost(start) {
957
+ let p2 = start, leftmost = start;
958
+ do {
959
+ if (p2.x < leftmost.x || p2.x === leftmost.x && p2.y < leftmost.y) leftmost = p2;
960
+ p2 = p2.next;
961
+ } while (p2 !== start);
962
+ return leftmost;
963
+ }
964
+ function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
965
+ 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);
966
+ }
967
+ function isValidDiagonal(a, b) {
968
+ return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) && // dones't intersect other edges
969
+ (locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible
970
+ (area(a.prev, a, b.prev) || area(a, b.prev, b)) || // does not create opposite-facing sectors
971
+ equals(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0);
972
+ }
973
+ function area(p2, q, r) {
974
+ return (q.y - p2.y) * (r.x - q.x) - (q.x - p2.x) * (r.y - q.y);
975
+ }
976
+ function equals(p1, p2) {
977
+ return p1.x === p2.x && p1.y === p2.y;
978
+ }
979
+ function intersects(p1, q1, p2, q2) {
980
+ const o1 = sign(area(p1, q1, p2));
981
+ const o2 = sign(area(p1, q1, q2));
982
+ const o3 = sign(area(p2, q2, p1));
983
+ const o4 = sign(area(p2, q2, q1));
984
+ if (o1 !== o2 && o3 !== o4) return true;
985
+ if (o1 === 0 && onSegment(p1, p2, q1)) return true;
986
+ if (o2 === 0 && onSegment(p1, q2, q1)) return true;
987
+ if (o3 === 0 && onSegment(p2, p1, q2)) return true;
988
+ if (o4 === 0 && onSegment(p2, q1, q2)) return true;
989
+ return false;
990
+ }
991
+ function onSegment(p2, q, r) {
992
+ return q.x <= Math.max(p2.x, r.x) && q.x >= Math.min(p2.x, r.x) && q.y <= Math.max(p2.y, r.y) && q.y >= Math.min(p2.y, r.y);
993
+ }
994
+ function sign(num2) {
995
+ return num2 > 0 ? 1 : num2 < 0 ? -1 : 0;
996
+ }
997
+ function intersectsPolygon(a, b) {
998
+ let p2 = a;
999
+ do {
1000
+ if (p2.i !== a.i && p2.next.i !== a.i && p2.i !== b.i && p2.next.i !== b.i && intersects(p2, p2.next, a, b)) return true;
1001
+ p2 = p2.next;
1002
+ } while (p2 !== a);
1003
+ return false;
1004
+ }
1005
+ function locallyInside(a, b) {
1006
+ 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;
1007
+ }
1008
+ function middleInside(a, b) {
1009
+ let p2 = a, inside = false;
1010
+ const px = (a.x + b.x) / 2, py = (a.y + b.y) / 2;
1011
+ do {
1012
+ if (p2.y > py !== p2.next.y > py && p2.next.y !== p2.y && px < (p2.next.x - p2.x) * (py - p2.y) / (p2.next.y - p2.y) + p2.x)
1013
+ inside = !inside;
1014
+ p2 = p2.next;
1015
+ } while (p2 !== a);
1016
+ return inside;
1017
+ }
1018
+ function splitPolygon(a, b) {
1019
+ 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;
1020
+ a.next = b;
1021
+ b.prev = a;
1022
+ a2.next = an;
1023
+ an.prev = a2;
1024
+ b2.next = a2;
1025
+ a2.prev = b2;
1026
+ bp.next = b2;
1027
+ b2.prev = bp;
1028
+ return b2;
1029
+ }
1030
+ function insertNode(i, x, y, last) {
1031
+ const p2 = new Node(i, x, y);
1032
+ if (!last) {
1033
+ p2.prev = p2;
1034
+ p2.next = p2;
1035
+ } else {
1036
+ p2.next = last.next;
1037
+ p2.prev = last;
1038
+ last.next.prev = p2;
1039
+ last.next = p2;
1040
+ }
1041
+ return p2;
1042
+ }
1043
+ function removeNode(p2) {
1044
+ p2.next.prev = p2.prev;
1045
+ p2.prev.next = p2.next;
1046
+ if (p2.prevZ) p2.prevZ.nextZ = p2.nextZ;
1047
+ if (p2.nextZ) p2.nextZ.prevZ = p2.prevZ;
1048
+ }
1049
+ function Node(i, x, y) {
1050
+ this.i = i;
1051
+ this.x = x;
1052
+ this.y = y;
1053
+ this.prev = null;
1054
+ this.next = null;
1055
+ this.z = 0;
1056
+ this.prevZ = null;
1057
+ this.nextZ = null;
1058
+ this.steiner = false;
1059
+ }
1060
+ function signedArea(data, start, end, dim) {
1061
+ let sum = 0;
1062
+ for (let i = start, j = end - dim; i < end; i += dim) {
1063
+ sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
1064
+ j = i;
1065
+ }
1066
+ return sum;
1067
+ }
1068
+ var equals2 = (a, b) => a.x === b.x && a.y === b.y;
1069
+ 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 };
1070
+ function pathPoints(points) {
1071
+ const out = [];
1072
+ let last;
1073
+ for (let i = 1; i < points.length; i++) {
1074
+ const v1 = { x: points[i - 1][0], y: points[i - 1][1] };
1075
+ const v2 = { x: points[i][0], y: points[i][1] };
1076
+ for (let d = 0; d <= 1; d++) {
1077
+ const point = linePoint(v1, v2, d / 1);
1078
+ if (last && equals2(last, point)) continue;
1079
+ out.push(point);
1080
+ last = point;
1081
+ }
1082
+ }
1083
+ return out;
1084
+ }
1085
+ function area2(contour) {
1086
+ const n = contour.length;
1087
+ let a = 0;
1088
+ for (let p2 = n - 1, q = 0; q < n; p2 = q++) a += contour[p2].x * contour[q].y - contour[q].x * contour[p2].y;
1089
+ return a * 0.5;
1090
+ }
1091
+ var isClockWise = (pts) => area2(pts) < 0;
1092
+ function removeDupEndPts(points) {
1093
+ const l = points.length;
1094
+ if (l > 2 && equals2(points[l - 1], points[0])) points.pop();
1095
+ }
1096
+ function triangulateShape(contour, holes) {
1097
+ const vertices = [];
1098
+ const holeIndices = [];
1099
+ const faces = [];
1100
+ removeDupEndPts(contour);
1101
+ for (const p2 of contour) vertices.push(p2.x, p2.y);
1102
+ let holeIndex = contour.length;
1103
+ holes.forEach(removeDupEndPts);
1104
+ for (let i = 0; i < holes.length; i++) {
1105
+ holeIndices.push(holeIndex);
1106
+ holeIndex += holes[i].length;
1107
+ for (const p2 of holes[i]) vertices.push(p2.x, p2.y);
1108
+ }
1109
+ const triangles = Earcut.triangulate(vertices, holeIndices);
1110
+ for (let i = 0; i < triangles.length; i += 3) faces.push(triangles.slice(i, i + 3));
1111
+ return faces;
1112
+ }
1113
+ function computeVertexNormals(positions, indices) {
1114
+ const normals = new Float32Array(positions.length);
1115
+ const get = (array, i) => [array[i * 3], array[i * 3 + 1], array[i * 3 + 2]];
1116
+ const face = (vA, vB, vC) => {
1117
+ const pA = get(positions, vA);
1118
+ const pB = get(positions, vB);
1119
+ const pC = get(positions, vC);
1120
+ const cb = [pC[0] - pB[0], pC[1] - pB[1], pC[2] - pB[2]];
1121
+ const ab = [pA[0] - pB[0], pA[1] - pB[1], pA[2] - pB[2]];
1122
+ 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]];
1123
+ };
1124
+ const set = (i, x, y, z) => {
1125
+ normals[i * 3] = x;
1126
+ normals[i * 3 + 1] = y;
1127
+ normals[i * 3 + 2] = z;
1128
+ };
1129
+ if (indices) {
1130
+ for (let i = 0; i < indices.length; i += 3) {
1131
+ const vA = indices[i];
1132
+ const vB = indices[i + 1];
1133
+ const vC = indices[i + 2];
1134
+ const cb = face(vA, vB, vC);
1135
+ for (const v of [vA, vB, vC]) {
1136
+ const n = get(normals, v);
1137
+ set(v, n[0] + cb[0], n[1] + cb[1], n[2] + cb[2]);
1138
+ }
1139
+ }
1140
+ } else {
1141
+ for (let i = 0; i < positions.length / 3; i += 3) {
1142
+ const cb = face(i, i + 1, i + 2);
1143
+ set(i, cb[0], cb[1], cb[2]);
1144
+ set(i + 1, cb[0], cb[1], cb[2]);
1145
+ set(i + 2, cb[0], cb[1], cb[2]);
1146
+ }
1147
+ }
1148
+ for (let i = 0; i < normals.length / 3; i++) {
1149
+ const [x, y, z] = get(normals, i);
1150
+ const s = 1 / (Math.sqrt(x * x + y * y + z * z) || 1);
1151
+ set(i, x * s, y * s, z * s);
1152
+ }
1153
+ return normals;
1154
+ }
1155
+ function extrude(outline, depth = 1, steps = 1, bevel = void 0) {
1156
+ const parameters = { shape: outline, depth, steps, bevel: bevel ?? {} };
1157
+ const verticesArray = [];
1158
+ const uvArray = [];
1159
+ const groups = [];
1160
+ const placeholder = [];
1161
+ const bevelEnabled = bevel !== false;
1162
+ const spec = bevel === false || bevel === void 0 ? {} : bevel;
1163
+ let bevelThickness = spec.thickness !== void 0 ? spec.thickness : 0.2;
1164
+ let bevelSize = spec.size !== void 0 ? spec.size : bevelThickness - 0.1;
1165
+ let bevelOffset = spec.offset !== void 0 ? spec.offset : 0;
1166
+ let bevelSegments = spec.segments !== void 0 ? spec.segments : 3;
1167
+ if (!bevelEnabled) {
1168
+ bevelSegments = 0;
1169
+ bevelThickness = 0;
1170
+ bevelSize = 0;
1171
+ bevelOffset = 0;
1172
+ }
1173
+ let vertices = pathPoints(outline.outer);
1174
+ const holes = (outline.holes ?? []).map(pathPoints);
1175
+ const reverse = !isClockWise(vertices);
1176
+ if (reverse) {
1177
+ vertices = vertices.reverse();
1178
+ for (let h = 0; h < holes.length; h++) {
1179
+ const ahole = holes[h];
1180
+ if (isClockWise(ahole)) holes[h] = ahole.reverse();
1181
+ }
1182
+ }
1183
+ const faces = triangulateShape(vertices, holes);
1184
+ const contour = vertices;
1185
+ for (const ahole of holes) vertices = vertices.concat(ahole);
1186
+ const scalePt2 = (pt, vec, size) => ({ x: pt.x + vec.x * size, y: pt.y + vec.y * size });
1187
+ const vlen = vertices.length;
1188
+ const flen = faces.length;
1189
+ const getBevelVec = (inPt, inPrev, inNext) => {
1190
+ let vTransX;
1191
+ let vTransY;
1192
+ let shrinkBy;
1193
+ const vPrevX = inPt.x - inPrev.x;
1194
+ const vPrevY = inPt.y - inPrev.y;
1195
+ const vNextX = inNext.x - inPt.x;
1196
+ const vNextY = inNext.y - inPt.y;
1197
+ const vPrevLensq = vPrevX * vPrevX + vPrevY * vPrevY;
1198
+ const collinear0 = vPrevX * vNextY - vPrevY * vNextX;
1199
+ if (Math.abs(collinear0) > Number.EPSILON) {
1200
+ const vPrevLen = Math.sqrt(vPrevLensq);
1201
+ const vNextLen = Math.sqrt(vNextX * vNextX + vNextY * vNextY);
1202
+ const ptPrevShiftX = inPrev.x - vPrevY / vPrevLen;
1203
+ const ptPrevShiftY = inPrev.y + vPrevX / vPrevLen;
1204
+ const ptNextShiftX = inNext.x - vNextY / vNextLen;
1205
+ const ptNextShiftY = inNext.y + vNextX / vNextLen;
1206
+ const sf = ((ptNextShiftX - ptPrevShiftX) * vNextY - (ptNextShiftY - ptPrevShiftY) * vNextX) / (vPrevX * vNextY - vPrevY * vNextX);
1207
+ vTransX = ptPrevShiftX + vPrevX * sf - inPt.x;
1208
+ vTransY = ptPrevShiftY + vPrevY * sf - inPt.y;
1209
+ const vTransLensq = vTransX * vTransX + vTransY * vTransY;
1210
+ if (vTransLensq <= 2) return { x: vTransX, y: vTransY };
1211
+ shrinkBy = Math.sqrt(vTransLensq / 2);
1212
+ } else {
1213
+ let directionEq = false;
1214
+ if (vPrevX > Number.EPSILON) {
1215
+ if (vNextX > Number.EPSILON) directionEq = true;
1216
+ } else if (vPrevX < -Number.EPSILON) {
1217
+ if (vNextX < -Number.EPSILON) directionEq = true;
1218
+ } else if (Math.sign(vPrevY) === Math.sign(vNextY)) {
1219
+ directionEq = true;
1220
+ }
1221
+ if (directionEq) {
1222
+ vTransX = -vPrevY;
1223
+ vTransY = vPrevX;
1224
+ shrinkBy = Math.sqrt(vPrevLensq);
1225
+ } else {
1226
+ vTransX = vPrevX;
1227
+ vTransY = vPrevY;
1228
+ shrinkBy = Math.sqrt(vPrevLensq / 2);
1229
+ }
1230
+ }
1231
+ return { x: vTransX / shrinkBy, y: vTransY / shrinkBy };
1232
+ };
1233
+ const movements = (ring2) => {
1234
+ const out = [];
1235
+ for (let i = 0, il = ring2.length, j = il - 1, k = i + 1; i < il; i++, j++, k++) {
1236
+ if (j === il) j = 0;
1237
+ if (k === il) k = 0;
1238
+ out[i] = getBevelVec(ring2[i], ring2[j], ring2[k]);
1239
+ }
1240
+ return out;
1241
+ };
1242
+ const contourMovements = movements(contour);
1243
+ const holesMovements = [];
1244
+ let verticesMovements = contourMovements.concat();
1245
+ for (const ahole of holes) {
1246
+ const oneHoleMovements = movements(ahole);
1247
+ holesMovements.push(oneHoleMovements);
1248
+ verticesMovements = verticesMovements.concat(oneHoleMovements);
1249
+ }
1250
+ const v = (x, y, z) => {
1251
+ placeholder.push(x);
1252
+ placeholder.push(y);
1253
+ placeholder.push(z);
1254
+ };
1255
+ const bevelLayer = (b, zOf) => {
1256
+ const t = b / bevelSegments;
1257
+ const z = bevelThickness * Math.cos(t * Math.PI / 2);
1258
+ const bs2 = bevelSize * Math.sin(t * Math.PI / 2) + bevelOffset;
1259
+ for (let i = 0; i < contour.length; i++) {
1260
+ const vert = scalePt2(contour[i], contourMovements[i], bs2);
1261
+ v(vert.x, vert.y, zOf(z));
1262
+ }
1263
+ for (let h = 0; h < holes.length; h++) {
1264
+ const ahole = holes[h];
1265
+ const oneHoleMovements = holesMovements[h];
1266
+ for (let i = 0; i < ahole.length; i++) {
1267
+ const vert = scalePt2(ahole[i], oneHoleMovements[i], bs2);
1268
+ v(vert.x, vert.y, zOf(z));
1269
+ }
1270
+ }
1271
+ };
1272
+ for (let b = 0; b < bevelSegments; b++) bevelLayer(b, (z) => -z);
1273
+ const bs = bevelSize + bevelOffset;
1274
+ for (let i = 0; i < vlen; i++) {
1275
+ const vert = bevelEnabled ? scalePt2(vertices[i], verticesMovements[i], bs) : vertices[i];
1276
+ v(vert.x, vert.y, 0);
1277
+ }
1278
+ for (let s = 1; s <= steps; s++) {
1279
+ for (let i = 0; i < vlen; i++) {
1280
+ const vert = bevelEnabled ? scalePt2(vertices[i], verticesMovements[i], bs) : vertices[i];
1281
+ v(vert.x, vert.y, depth / steps * s);
1282
+ }
1283
+ }
1284
+ for (let b = bevelSegments - 1; b >= 0; b--) bevelLayer(b, (z) => depth + z);
1285
+ const addVertex = (index) => {
1286
+ verticesArray.push(placeholder[index * 3 + 0]);
1287
+ verticesArray.push(placeholder[index * 3 + 1]);
1288
+ verticesArray.push(placeholder[index * 3 + 2]);
1289
+ };
1290
+ const addUV = (x, y) => {
1291
+ uvArray.push(x);
1292
+ uvArray.push(y);
1293
+ };
1294
+ const at = (index, axis) => verticesArray[index * 3 + axis];
1295
+ const f3 = (a, b, c) => {
1296
+ addVertex(a);
1297
+ addVertex(b);
1298
+ addVertex(c);
1299
+ const nextIndex = verticesArray.length / 3;
1300
+ for (const index of [nextIndex - 3, nextIndex - 2, nextIndex - 1]) addUV(at(index, 0), at(index, 1));
1301
+ };
1302
+ const f4 = (a, b, c, d) => {
1303
+ addVertex(a);
1304
+ addVertex(b);
1305
+ addVertex(d);
1306
+ addVertex(b);
1307
+ addVertex(c);
1308
+ addVertex(d);
1309
+ const nextIndex = verticesArray.length / 3;
1310
+ const iA = nextIndex - 6;
1311
+ const iB = nextIndex - 3;
1312
+ const iC = nextIndex - 2;
1313
+ const iD = nextIndex - 1;
1314
+ const byX = Math.abs(at(iA, 1) - at(iB, 1)) < Math.abs(at(iA, 0) - at(iB, 0));
1315
+ const uv = (index) => [byX ? at(index, 0) : at(index, 1), 1 - at(index, 2)];
1316
+ const uvs = [uv(iA), uv(iB), uv(iC), uv(iD)];
1317
+ for (const k of [0, 1, 3, 1, 2, 3]) addUV(...uvs[k]);
1318
+ };
1319
+ let start = verticesArray.length / 3;
1320
+ if (bevelEnabled) {
1321
+ let offset = 0;
1322
+ for (let i = 0; i < flen; i++) {
1323
+ const face = faces[i];
1324
+ f3(face[2] + offset, face[1] + offset, face[0] + offset);
1325
+ }
1326
+ const layer = steps + bevelSegments * 2;
1327
+ offset = vlen * layer;
1328
+ for (let i = 0; i < flen; i++) {
1329
+ const face = faces[i];
1330
+ f3(face[0] + offset, face[1] + offset, face[2] + offset);
1331
+ }
1332
+ } else {
1333
+ for (let i = 0; i < flen; i++) {
1334
+ const face = faces[i];
1335
+ f3(face[2], face[1], face[0]);
1336
+ }
1337
+ for (let i = 0; i < flen; i++) {
1338
+ const face = faces[i];
1339
+ f3(face[0] + vlen * steps, face[1] + vlen * steps, face[2] + vlen * steps);
1340
+ }
1341
+ }
1342
+ groups.push({ start, count: verticesArray.length / 3 - start, materialIndex: 0 });
1343
+ start = verticesArray.length / 3;
1344
+ const sidewalls = (ring2, layeroffset2) => {
1345
+ let i = ring2.length;
1346
+ while (--i >= 0) {
1347
+ const j = i;
1348
+ let k = i - 1;
1349
+ if (k < 0) k = ring2.length - 1;
1350
+ for (let s = 0, sl = steps + bevelSegments * 2; s < sl; s++) {
1351
+ const slen1 = vlen * s;
1352
+ const slen2 = vlen * (s + 1);
1353
+ f4(layeroffset2 + j + slen1, layeroffset2 + k + slen1, layeroffset2 + k + slen2, layeroffset2 + j + slen2);
1354
+ }
1355
+ }
1356
+ };
1357
+ let layeroffset = 0;
1358
+ sidewalls(contour, layeroffset);
1359
+ layeroffset += contour.length;
1360
+ for (const ahole of holes) {
1361
+ sidewalls(ahole, layeroffset);
1362
+ layeroffset += ahole.length;
1363
+ }
1364
+ groups.push({ start, count: verticesArray.length / 3 - start, materialIndex: 1 });
1365
+ const positions = new Float32Array(verticesArray);
1366
+ return { type: "ExtrudeGeometry", parameters, positions, normals: computeVertexNormals(positions), uvs: new Float32Array(uvArray), groups };
1367
+ }
1368
+ var PARAMETER_KEYS = {
1369
+ box: ["size", "segments"],
1370
+ cylinder: ["radiusTop", "radiusBottom", "height", "radialSegments", "heightSegments", "openEnded", "thetaStart", "thetaLength"],
1371
+ cone: ["radius", "height", "radialSegments", "heightSegments", "openEnded", "thetaStart", "thetaLength"],
1372
+ sphere: ["radius", "widthSegments", "heightSegments", "phiStart", "phiLength", "thetaStart", "thetaLength"],
1373
+ plane: ["width", "height", "widthSegments", "heightSegments"],
1374
+ circle: ["radius", "segments", "thetaStart", "thetaLength"],
1375
+ ring: ["innerRadius", "outerRadius", "thetaSegments", "phiSegments", "thetaStart", "thetaLength"],
1376
+ lathe: ["points", "segments", "phiStart", "phiLength"],
1377
+ torus: ["radius", "tube", "radialSegments", "tubularSegments", "arc"],
1378
+ extrude: ["shape", "depth", "steps", "bevel"],
1379
+ difference: ["size", "subtract"],
1380
+ mesh: ["positions", "normals", "uvs", "indices"]
1381
+ };
1382
+ var SEGMENT_KEYS = {
1383
+ cylinder: ["radialSegments"],
1384
+ cone: ["radialSegments"],
1385
+ sphere: ["widthSegments", "heightSegments"],
1386
+ circle: ["segments"],
1387
+ ring: ["thetaSegments"],
1388
+ lathe: ["segments"],
1389
+ torus: ["radialSegments", "tubularSegments"]
1390
+ };
1391
+ var SEGMENT_DEFAULTS = { radialSegments: 32, widthSegments: 32, heightSegments: 16, segments: 12, thetaSegments: 32, tubularSegments: 48 };
1392
+ var segmentDefault = (kind, key) => kind === "circle" && key === "segments" ? 32 : kind === "torus" && key === "radialSegments" ? 12 : SEGMENT_DEFAULTS[key];
1393
+ function primitiveParameters(node, options = {}) {
1394
+ const out = {};
1395
+ const source = node;
1396
+ for (const key of PARAMETER_KEYS[node.kind]) if (source[key] !== void 0) out[key] = source[key];
1397
+ const detail = options.detail ?? 1;
1398
+ if (detail !== 1) {
1399
+ const floor = options.minSegments ?? 3;
1400
+ for (const key of SEGMENT_KEYS[node.kind] ?? []) {
1401
+ const given = out[key] ?? segmentDefault(node.kind, key);
1402
+ out[key] = Math.max(floor, Math.round(given * detail));
1403
+ }
1404
+ }
1405
+ return out;
1406
+ }
1407
+ function mesh(p2) {
1408
+ const positions = new Float32Array(p2.positions);
1409
+ const indices = p2.indices ? indexArray(p2.indices) : void 0;
1410
+ return {
1411
+ type: "BufferGeometry",
1412
+ parameters: {},
1413
+ positions,
1414
+ normals: p2.normals ? new Float32Array(p2.normals) : computeVertexNormals(positions, indices),
1415
+ uvs: p2.uvs ? new Float32Array(p2.uvs) : new Float32Array(positions.length / 3 * 2),
1416
+ ...indices ? { indices } : {},
1417
+ groups: []
1418
+ };
1419
+ }
1420
+ function make(kind, p2) {
1421
+ switch (kind) {
1422
+ case "box": {
1423
+ const size = p2.size ?? [1, 1, 1];
1424
+ const segments = p2.segments ?? [1, 1, 1];
1425
+ return box(size[0], size[1], size[2], segments[0], segments[1], segments[2]);
1426
+ }
1427
+ case "cylinder":
1428
+ return cylinder(p2.radiusTop, p2.radiusBottom, p2.height, p2.radialSegments, p2.heightSegments, p2.openEnded, p2.thetaStart, p2.thetaLength);
1429
+ case "cone":
1430
+ return cone(p2.radius, p2.height, p2.radialSegments, p2.heightSegments, p2.openEnded, p2.thetaStart, p2.thetaLength);
1431
+ case "sphere":
1432
+ return sphere(p2.radius, p2.widthSegments, p2.heightSegments, p2.phiStart, p2.phiLength, p2.thetaStart, p2.thetaLength);
1433
+ case "plane":
1434
+ return plane(p2.width, p2.height, p2.widthSegments, p2.heightSegments);
1435
+ case "circle":
1436
+ return circle(p2.radius, p2.segments, p2.thetaStart, p2.thetaLength);
1437
+ case "ring":
1438
+ return ring(p2.innerRadius, p2.outerRadius, p2.thetaSegments, p2.phiSegments, p2.thetaStart, p2.thetaLength);
1439
+ case "lathe":
1440
+ return lathe(p2.points, p2.segments, p2.phiStart, p2.phiLength);
1441
+ case "torus":
1442
+ return torus(p2.radius, p2.tube, p2.radialSegments, p2.tubularSegments, p2.arc);
1443
+ case "extrude":
1444
+ return extrude(p2.shape, p2.depth, p2.steps, p2.bevel);
1445
+ case "difference":
1446
+ return difference(p2.size, p2.subtract ?? []);
1447
+ case "mesh":
1448
+ return mesh(p2);
1449
+ default:
1450
+ throw new Error(`game-shapes: unknown primitive kind "${String(kind)}"`);
1451
+ }
1452
+ }
1453
+ var templates = /* @__PURE__ */ new Map();
1454
+ var templateLimit = 4096;
1455
+ var stats = { hits: 0, misses: 0 };
1456
+ function buildPrimitive(node, options = {}) {
1457
+ const parameters = primitiveParameters(node, options);
1458
+ if (node.kind === "mesh" || templateLimit === 0) return make(node.kind, parameters);
1459
+ const key = `${node.kind}:${canonicalJson(parameters)}`;
1460
+ const cached = templates.get(key);
1461
+ if (cached) {
1462
+ stats.hits++;
1463
+ templates.delete(key);
1464
+ templates.set(key, cached);
1465
+ return cached;
1466
+ }
1467
+ stats.misses++;
1468
+ const built = make(node.kind, parameters);
1469
+ templates.set(key, built);
1470
+ if (templates.size > templateLimit) templates.delete(templates.keys().next().value);
1471
+ return built;
1472
+ }
1473
+ var num = (v) => typeof v === "number" && Number.isFinite(v) ? null : "expected a finite number";
1474
+ var bool = (v) => typeof v === "boolean" ? null : "expected a boolean";
1475
+ var str = (v) => typeof v === "string" ? null : "expected a string";
1476
+ var int = (min) => (v) => typeof v === "number" && Number.isInteger(v) && v >= min ? null : `expected an integer >= ${min}`;
1477
+ 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}]`;
1478
+ var tuple = (n, item = num) => (v) => {
1479
+ if (!Array.isArray(v) || v.length !== n) return `expected an array of ${n}`;
1480
+ for (const x of v) if (item(x)) return `expected an array of ${n} numbers`;
1481
+ return null;
1482
+ };
1483
+ var list = (item, min = 0) => (v) => {
1484
+ if (!Array.isArray(v)) return "expected an array";
1485
+ if (v.length < min) return `expected at least ${min} items`;
1486
+ for (let i = 0; i < v.length; i++) {
1487
+ const e = item(v[i]);
1488
+ if (e) return `[${i}]: ${e}`;
1489
+ }
1490
+ return null;
1491
+ };
1492
+ 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"';
1493
+ var oneOf = (values) => (v) => values.includes(v) ? null : `expected one of ${values.map((x) => JSON.stringify(x)).join(", ")}`;
1494
+ var object = (fields, required = []) => (v) => {
1495
+ if (!v || typeof v !== "object" || Array.isArray(v)) return "expected an object";
1496
+ const record = v;
1497
+ for (const key of required) if (record[key] === void 0) return `${key}: required`;
1498
+ for (const key of Object.keys(record)) {
1499
+ if (record[key] === void 0) continue;
1500
+ const check = fields[key];
1501
+ if (!check) return `${key}: unknown field`;
1502
+ const e = check(record[key]);
1503
+ if (e) return `${key}: ${e}`;
1504
+ }
1505
+ return null;
1506
+ };
1507
+ var ORDERS = ["XYZ", "YXZ", "ZXY", "ZYX", "YZX", "XZY"];
1508
+ var TRANSFORM = {
1509
+ position: tuple(3),
1510
+ rotation: tuple(3),
1511
+ rotationOrder: oneOf(ORDERS),
1512
+ scale: (v) => typeof v === "number" ? num(v) : tuple(3)(v),
1513
+ heading: num,
1514
+ matrix: tuple(16)
1515
+ };
1516
+ var UV = object({ u0: num, v0: num, u1: num, v1: num }, ["u0", "v0", "u1", "v1"]);
1517
+ var INSTANCE = object({ ...TRANSFORM, color });
1518
+ var COMMON = {
1519
+ ...TRANSFORM,
1520
+ kind: str,
1521
+ name: str,
1522
+ part: str,
1523
+ material: str,
1524
+ color,
1525
+ uv: UV,
1526
+ instances: list(INSTANCE),
1527
+ minDetail: range(0, 1, true),
1528
+ tags: list(str)
1529
+ };
1530
+ var vec2 = tuple(2);
1531
+ var BEVEL = (v) => v === false ? null : object({ thickness: num, size: num, offset: num, segments: int(1) })(v);
1532
+ var KINDS = {
1533
+ group: { fields: {} },
1534
+ box: { fields: { size: tuple(3), segments: tuple(3, int(1)) } },
1535
+ cylinder: { fields: { radiusTop: num, radiusBottom: num, height: num, radialSegments: int(1), heightSegments: int(1), openEnded: bool, thetaStart: num, thetaLength: num } },
1536
+ cone: { fields: { radius: num, height: num, radialSegments: int(1), heightSegments: int(1), openEnded: bool, thetaStart: num, thetaLength: num } },
1537
+ sphere: { fields: { radius: num, widthSegments: int(3), heightSegments: int(2), phiStart: num, phiLength: num, thetaStart: num, thetaLength: num } },
1538
+ plane: { fields: { width: num, height: num, widthSegments: int(1), heightSegments: int(1) } },
1539
+ circle: { fields: { radius: num, segments: int(3), thetaStart: num, thetaLength: num } },
1540
+ ring: { fields: { innerRadius: num, outerRadius: num, thetaSegments: int(3), phiSegments: int(1), thetaStart: num, thetaLength: num } },
1541
+ lathe: { fields: { points: list(vec2, 2), segments: int(1), phiStart: num, phiLength: num }, required: ["points"] },
1542
+ torus: { fields: { radius: num, tube: num, radialSegments: int(1), tubularSegments: int(1), arc: num } },
1543
+ extrude: {
1544
+ fields: { shape: object({ outer: list(vec2, 3), holes: list(list(vec2, 3)) }, ["outer"]), depth: num, steps: int(1), bevel: BEVEL },
1545
+ required: ["shape"]
1546
+ },
1547
+ difference: { fields: { size: tuple(3), subtract: list(object({ min: vec2, max: vec2 }, ["min", "max"])) }, required: ["size", "subtract"] },
1548
+ mesh: {
1549
+ fields: {
1550
+ positions: (v) => list(num)(v) ?? (v.length % 3 === 0 ? null : "expected a multiple of 3 numbers"),
1551
+ normals: list(num),
1552
+ uvs: list(num),
1553
+ indices: list(int(0))
1554
+ },
1555
+ required: ["positions"]
1556
+ },
1557
+ point: { fields: { data: () => null } },
1558
+ custom: { fields: { generator: str, params: () => null }, required: ["generator"] }
1559
+ };
1560
+
1561
+ // ../game-shapes-three/dist/index.js
1562
+ var UV_BEFORE_NORMAL = /* @__PURE__ */ new Set(["LatheGeometry", "ExtrudeGeometry"]);
1563
+ var INDEX_FIRST = /* @__PURE__ */ new Set(["BoxGeometry", "CylinderGeometry", "ConeGeometry", "SphereGeometry", "PlaneGeometry", "CircleGeometry", "RingGeometry", "LatheGeometry", "TorusGeometry"]);
1564
+ var isPrimitive = (value) => typeof value.type === "string";
1565
+ function threeParameters(THREE, p2) {
1566
+ if (p2.type === "LatheGeometry") {
1567
+ const points = p2.parameters.points.map(({ x, y }) => new THREE.Vector2(x, y));
1568
+ return { ...p2.parameters, points };
1569
+ }
1570
+ return { ...p2.parameters };
1571
+ }
1572
+ function toGeometry(THREE, source, options = {}) {
1573
+ const copy = options.copy !== false;
1574
+ const primitive = isPrimitive(source) ? source : null;
1575
+ const ThreeClass = primitive && primitive.type !== "BufferGeometry" ? THREE[primitive.type] : void 0;
1576
+ const geometry = ThreeClass ? Reflect.construct(THREE.BufferGeometry, [], ThreeClass) : new THREE.BufferGeometry();
1577
+ if (primitive && ThreeClass) {
1578
+ Object.assign(geometry, { type: primitive.type, parameters: threeParameters(THREE, primitive) });
1579
+ }
1580
+ const attribute = (array, size) => copy ? new THREE.Float32BufferAttribute(array, size) : new THREE.BufferAttribute(array, size);
1581
+ const index = source.indices;
1582
+ const setIndex = () => {
1583
+ if (!index) return;
1584
+ geometry.setIndex(copy ? index instanceof Uint32Array ? new THREE.Uint32BufferAttribute(index, 1) : new THREE.Uint16BufferAttribute(index, 1) : new THREE.BufferAttribute(index, 1));
1585
+ };
1586
+ const type = primitive?.type ?? "BufferGeometry";
1587
+ if (INDEX_FIRST.has(type)) setIndex();
1588
+ geometry.setAttribute("position", attribute(source.positions, 3));
1589
+ if (UV_BEFORE_NORMAL.has(type)) {
1590
+ geometry.setAttribute("uv", attribute(source.uvs, 2));
1591
+ geometry.setAttribute("normal", attribute(source.normals, 3));
1592
+ } else {
1593
+ geometry.setAttribute("normal", attribute(source.normals, 3));
1594
+ geometry.setAttribute("uv", attribute(source.uvs, 2));
1595
+ }
1596
+ if (!primitive && source.colors) geometry.setAttribute("color", attribute(source.colors, 3));
1597
+ if (!INDEX_FIRST.has(type)) setIndex();
1598
+ if (primitive) for (const group of primitive.groups) geometry.addGroup(group.start, group.count, group.materialIndex);
1599
+ return geometry;
1600
+ }
1601
+ var SHAPE_GEOMETRY_TYPES = ["BoxGeometry", "CylinderGeometry", "ConeGeometry", "SphereGeometry", "PlaneGeometry", "CircleGeometry", "RingGeometry", "LatheGeometry", "TorusGeometry", "ExtrudeGeometry"];
1602
+ function linePoints(path) {
1603
+ if (path.autoClose || path.curves.length === 0) return null;
1604
+ const points = [];
1605
+ for (const [index, curve] of path.curves.entries()) {
1606
+ if (!curve.isLineCurve || !curve.v1 || !curve.v2) return null;
1607
+ if (index === 0) points.push([curve.v1.x, curve.v1.y]);
1608
+ else {
1609
+ const last = points[points.length - 1];
1610
+ if (last[0] !== curve.v1.x || last[1] !== curve.v1.y) return null;
1611
+ }
1612
+ points.push([curve.v2.x, curve.v2.y]);
1613
+ }
1614
+ return points;
1615
+ }
1616
+ function extrudeOf(shapes, options = {}) {
1617
+ if (Array.isArray(shapes) || !shapes || options.extrudePath !== void 0 || options.UVGenerator !== void 0) return null;
1618
+ const shape = shapes;
1619
+ const outer = linePoints(shape);
1620
+ if (!outer) return null;
1621
+ const holes = [];
1622
+ for (const hole of shape.holes ?? []) {
1623
+ const points = linePoints(hole);
1624
+ if (!points) return null;
1625
+ holes.push(points);
1626
+ }
1627
+ const outline = holes.length ? { outer, holes } : { outer };
1628
+ const bevel = options.bevelEnabled === false ? false : {
1629
+ ...options.bevelThickness !== void 0 ? { thickness: options.bevelThickness } : {},
1630
+ ...options.bevelSize !== void 0 ? { size: options.bevelSize } : {},
1631
+ ...options.bevelOffset !== void 0 ? { offset: options.bevelOffset } : {},
1632
+ ...options.bevelSegments !== void 0 ? { segments: options.bevelSegments } : {}
1633
+ };
1634
+ return extrude(outline, options.depth, options.steps, bevel);
1635
+ }
1636
+ var namespaces = /* @__PURE__ */ new WeakMap();
1637
+ var shims = /* @__PURE__ */ new WeakSet();
1638
+ function shapeGeometries(THREE, options = {}) {
1639
+ if (shims.has(THREE)) return THREE;
1640
+ const cache = options.cache !== false;
1641
+ const key = cache ? "cache" : "nocache";
1642
+ let byKey = namespaces.get(THREE);
1643
+ if (!byKey) {
1644
+ byKey = /* @__PURE__ */ new Map();
1645
+ namespaces.set(THREE, byKey);
1646
+ }
1647
+ const existing = byKey.get(key);
1648
+ if (existing) return existing;
1649
+ const made = (p2) => toGeometry(THREE, p2);
1650
+ const viaCache = (node, direct2) => cache ? buildPrimitive(node) : direct2();
1651
+ const defined = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
1652
+ const constructors = {
1653
+ 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))),
1654
+ 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))),
1655
+ 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))),
1656
+ 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))),
1657
+ PlaneGeometry: (width, height, widthSegments, heightSegments) => made(viaCache({ kind: "plane", ...defined({ width, height, widthSegments, heightSegments }) }, () => plane(width, height, widthSegments, heightSegments))),
1658
+ CircleGeometry: (radius, segments, thetaStart, thetaLength) => made(viaCache({ kind: "circle", ...defined({ radius, segments, thetaStart, thetaLength }) }, () => circle(radius, segments, thetaStart, thetaLength))),
1659
+ 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))),
1660
+ LatheGeometry: (points, segments, phiStart, phiLength) => {
1661
+ if (!points) return new THREE.LatheGeometry(void 0, segments, phiStart, phiLength);
1662
+ const profile = points.map((p2) => [p2.x, p2.y]);
1663
+ return made(viaCache({ kind: "lathe", points: profile, ...defined({ segments, phiStart, phiLength }) }, () => lathe(profile, segments, phiStart, phiLength)));
1664
+ },
1665
+ TorusGeometry: (radius, tube, radialSegments, tubularSegments, arc) => made(viaCache({ kind: "torus", ...defined({ radius, tube, radialSegments, tubularSegments, arc }) }, () => torus(radius, tube, radialSegments, tubularSegments, arc))),
1666
+ ExtrudeGeometry: (shapes, extrudeOptions) => {
1667
+ const buffers = shapes === void 0 ? null : extrudeOf(shapes, extrudeOptions);
1668
+ if (!buffers) return new THREE.ExtrudeGeometry(shapes, extrudeOptions);
1669
+ const geometry = toGeometry(THREE, buffers);
1670
+ geometry.parameters = { shapes, options: extrudeOptions ?? {} };
1671
+ return geometry;
1672
+ }
1673
+ };
1674
+ const namespace = { ...THREE };
1675
+ for (const type of SHAPE_GEOMETRY_TYPES) {
1676
+ const make2 = constructors[type];
1677
+ const Constructor = function(...args) {
1678
+ return make2(...args);
1679
+ };
1680
+ Constructor.prototype = THREE[type].prototype;
1681
+ Object.defineProperty(Constructor, "name", { value: type });
1682
+ namespace[type] = Constructor;
1683
+ }
1684
+ const result = namespace;
1685
+ byKey.set(key, result);
1686
+ shims.add(result);
1687
+ return result;
1688
+ }
1689
+
163
1690
  // ../game-contracts/dist/index.js
1691
+ var DEFAULT_BLAST_SHOVE = { coupling: 0.02, maxSpeed: 20, lift: 0.3, minSpeed: 0.3, falloffPower: 2 };
1692
+ function blastShove(blast2, target, options = {}) {
1693
+ const o = { ...DEFAULT_BLAST_SHOVE, ...options };
1694
+ const dx = target.position[0] - blast2.point[0];
1695
+ const dy = target.position[1] - blast2.point[1];
1696
+ const dz = target.position[2] - blast2.point[2];
1697
+ const distance3 = Math.hypot(dx, dy, dz);
1698
+ if (!(blast2.radius > 0) || distance3 > blast2.radius) return void 0;
1699
+ const falloff = (1 - distance3 / blast2.radius) ** o.falloffPower;
1700
+ const mass = Math.max(target.mass, 0.05);
1701
+ const speed = Math.min(o.maxSpeed, Math.sqrt(2 * blast2.energy * (blast2.reach ?? 1) * o.coupling / mass)) * falloff;
1702
+ if (!(speed >= o.minSpeed)) return void 0;
1703
+ const direction = distance3 > 1e-4 ? [dx / distance3, dy / distance3 + o.lift, dz / distance3] : [0, 1, 0];
1704
+ const length = Math.hypot(direction[0], direction[1], direction[2]);
1705
+ return { speed, direction: [direction[0] / length, direction[1] / length, direction[2] / length], distance: distance3, falloff };
1706
+ }
164
1707
  var MISSING_BITS = {
165
1708
  head: 1,
166
1709
  armL: 2,
@@ -358,6 +1901,13 @@ var GameCharactersThree = (() => {
358
1901
  }
359
1902
  return removed;
360
1903
  },
1904
+ remove(index) {
1905
+ const entry = entries[index];
1906
+ if (!entry) return void 0;
1907
+ entries[index] = entries[entries.length - 1];
1908
+ entries.pop();
1909
+ return entry.data;
1910
+ },
361
1911
  clear() {
362
1912
  entries.length = 0;
363
1913
  }
@@ -1224,9 +2774,9 @@ var GameCharactersThree = (() => {
1224
2774
  if (region === "torso") return bodyCount > 1 ? cost.bruteTorso : cost.torso;
1225
2775
  return cost.limb;
1226
2776
  };
1227
- var teamGameFalloff = (distance22, range) => {
2777
+ var teamGameFalloff = (distance22, range2) => {
1228
2778
  const floor = TEAM_GAME_RULES.falloff.atTwiceRange;
1229
- return distance22 <= range * TEAM_GAME_RULES.falloff.fullAtRange ? 1 : Math.max(floor, 1 - (distance22 - range) / range * (1 - floor));
2779
+ return distance22 <= range2 * TEAM_GAME_RULES.falloff.fullAtRange ? 1 : Math.max(floor, 1 - (distance22 - range2) / range2 * (1 - floor));
1230
2780
  };
1231
2781
  var NO_HEADSHOT = { headshot: false };
1232
2782
  var HEADSHOT = { headshot: true };
@@ -1279,8 +2829,8 @@ var GameCharactersThree = (() => {
1279
2829
  var DEFAULT_PROJECTILE_GRAMS = 8;
1280
2830
  var RIFLE_JOULES = 1e3;
1281
2831
  var penetrationForce = (energy, grams, diameterMm) => {
1282
- const area = Math.PI * diameterMm ** 2 / 4;
1283
- return area > 0 && energy > 0 ? Math.sqrt(energy * grams / area) : 0;
2832
+ const area3 = Math.PI * diameterMm ** 2 / 4;
2833
+ return area3 > 0 && energy > 0 ? Math.sqrt(energy * grams / area3) : 0;
1284
2834
  };
1285
2835
  var projectileOf = (hit, caliber) => {
1286
2836
  const pellets = hit.pellets ?? caliber?.pellets ?? 1;
@@ -1368,7 +2918,15 @@ var GameCharactersThree = (() => {
1368
2918
  if (points >= rules.severity.stunAtPoints) ops.stun();
1369
2919
  return result;
1370
2920
  };
1371
- var shares = (params, targets, pivot) => targets.map((target) => ({ target, points: params.points * Math.max(0, 1 - distance(params.jointOf(pivot(target)), params.center) / params.radius) })).filter((share) => share.points > params.ops.rules.blast.minimumPoints).sort((a, b) => b.points - a.points);
2921
+ var INJURY_POINTS = 15;
2922
+ var pointsAt = (params, metres) => {
2923
+ const { points, radius, lethalRadius, ops } = params;
2924
+ if (lethalRadius === void 0 || lethalRadius >= radius) return points * Math.max(0, 1 - metres / radius);
2925
+ if (metres <= lethalRadius) return points;
2926
+ const injury = Math.min(points, ops.rules.blast.injuryPoints ?? INJURY_POINTS);
2927
+ return injury * Math.max(0, 1 - (metres - lethalRadius) / (radius - lethalRadius));
2928
+ };
2929
+ var shares = (params, targets, pivot) => targets.map((target) => ({ target, points: pointsAt(params, distance(params.jointOf(pivot(target)), params.center)) })).filter((share) => share.points > params.ops.rules.blast.minimumPoints).sort((a, b) => b.points - a.points);
1372
2930
  var segmentBlast = (params) => {
1373
2931
  const { ops, rule, blow } = params;
1374
2932
  const { blast: blast2, segments } = ops.rules;
@@ -1608,7 +3166,7 @@ var GameCharactersThree = (() => {
1608
3166
  };
1609
3167
  var blast = ({ ops, hit, setup, localPoint, jointOf }) => {
1610
3168
  const points = hit.points ?? pointsFromEnergy(hit.energy ?? 0, setup.rules);
1611
- const base = { ops, center: localPoint, points, radius: hit.radius ?? 1, jointOf };
3169
+ const base = { ops, center: localPoint, points, radius: hit.radius ?? 1, ...hit.lethalRadius !== void 0 ? { lethalRadius: hit.lethalRadius } : {}, jointOf };
1612
3170
  const common = { cut: hit.cut ?? setup.rules.defaultCut.explosive, damageType: hit.type, model: setup.model, headResistance: HEAD_RESISTANCE };
1613
3171
  const rule = SEGMENT_RULES[setup.rules.segmentRule] ?? kitRule;
1614
3172
  const result = ops.body.detail === "regions" ? regionBlast({ ...base, blow: { ...common, protection: NO_PROTECTION } }) : segmentBlast({ ...base, rule, blow: { ...common, limbFactor: ops.spec.limbFactor } });
@@ -1817,14 +3375,14 @@ var GameCharactersThree = (() => {
1817
3375
  var createCharacters = (options = {}) => {
1818
3376
  const body = createBodySpec(options.body);
1819
3377
  const packs = options.packs ?? [];
1820
- const presets = mergeById([PERSON_PRESET], packs.flatMap((pack) => pack.presets ?? []));
3378
+ const presets = mergeById([PERSON_PRESET], packs.flatMap((pack2) => pack2.presets ?? []));
1821
3379
  applyPatches(presets, options.patch);
1822
3380
  removeIds(presets, options.remove);
1823
3381
  const damage = resolveDamageRules(options.damage);
1824
3382
  const penetration = modelOf(options.penetration);
1825
- const protection = mergeById(PROTECTION_PRESETS, [...packs.flatMap((pack) => pack.protection ?? []), ...options.protection ?? []]);
3383
+ const protection = mergeById(PROTECTION_PRESETS, [...packs.flatMap((pack2) => pack2.protection ?? []), ...options.protection ?? []]);
1826
3384
  const shippedCalibers = penetration.id === "team-game" ? TEAM_GAME_CALIBERS : [];
1827
- const calibers = mergeById(shippedCalibers, [...packs.flatMap((pack) => pack.calibers ?? []), ...options.calibers ?? []]);
3385
+ const calibers = mergeById(shippedCalibers, [...packs.flatMap((pack2) => pack2.calibers ?? []), ...options.calibers ?? []]);
1828
3386
  const setup = { rules: damage, model: penetration, protection, calibers };
1829
3387
  let counter = 0;
1830
3388
  return {
@@ -2231,38 +3789,518 @@ var GameCharactersThree = (() => {
2231
3789
  const shoeColor = uniform ? UNIFORM_SHOES : pick(SHOE_COLORS);
2232
3790
  return { traits: { female, tone, topColor, pantsColor, ...look, hairColor, shoeColor }, random };
2233
3791
  };
2234
- var uniformLook = () => ({
2235
- sleeve: "short",
2236
- hair: "short",
2237
- headWidth: 1,
2238
- headHeight: 1,
2239
- jaw: 1,
2240
- nose: 1,
2241
- beard: false,
2242
- glasses: false,
2243
- cap: false,
2244
- capColor: 0,
2245
- bag: false,
2246
- bagColor: 0,
2247
- torn: false,
2248
- apron: false
2249
- });
2250
- var drawLook = ({ random, pick, female, outfit, human, params }) => {
2251
- const sleeve = outfit.cloth ? "long" : pick(SLEEVES);
2252
- const hair = params.hairStyle ?? (params.wet ? "long" : params.charred ? "bald" : pick(female ? HAIR_STYLES_FEMALE : HAIR_STYLES_MALE));
2253
- const headWidth = 1 + (random() - 0.5) * 0.16;
2254
- const headHeight = 1 + (random() - 0.5) * 0.14;
2255
- const jaw = 1 + (random() - 0.5) * 0.3;
2256
- const nose = 1 + (random() - 0.5) * 0.5;
2257
- const beard = !female && random() < BEARD_SHARE;
2258
- const glasses = random() < GLASSES_SHARE;
2259
- const cap = !outfit.hat && random() < CAP_SHARE;
2260
- const capColor = pick(CAP_COLORS);
2261
- const bag = random() < BAG_SHARE && !human;
2262
- const bagColor = pick(BAG_COLORS);
2263
- const torn = random() < TORN_SHARE && !human;
2264
- const apron = random() < APRON_SHARE;
2265
- return { sleeve, hair, headWidth, headHeight, jaw, nose, beard, glasses, cap, capColor, bag, bagColor, torn, apron };
3792
+ var uniformLook = () => ({
3793
+ sleeve: "short",
3794
+ hair: "short",
3795
+ headWidth: 1,
3796
+ headHeight: 1,
3797
+ jaw: 1,
3798
+ nose: 1,
3799
+ beard: false,
3800
+ glasses: false,
3801
+ cap: false,
3802
+ capColor: 0,
3803
+ bag: false,
3804
+ bagColor: 0,
3805
+ torn: false,
3806
+ apron: false
3807
+ });
3808
+ var drawLook = ({ random, pick, female, outfit, human, params }) => {
3809
+ const sleeve = outfit.cloth ? "long" : pick(SLEEVES);
3810
+ const hair = params.hairStyle ?? (params.wet ? "long" : params.charred ? "bald" : pick(female ? HAIR_STYLES_FEMALE : HAIR_STYLES_MALE));
3811
+ const headWidth = 1 + (random() - 0.5) * 0.16;
3812
+ const headHeight = 1 + (random() - 0.5) * 0.14;
3813
+ const jaw = 1 + (random() - 0.5) * 0.3;
3814
+ const nose = 1 + (random() - 0.5) * 0.5;
3815
+ const beard = !female && random() < BEARD_SHARE;
3816
+ const glasses = random() < GLASSES_SHARE;
3817
+ const cap = !outfit.hat && random() < CAP_SHARE;
3818
+ const capColor = pick(CAP_COLORS);
3819
+ const bag = random() < BAG_SHARE && !human;
3820
+ const bagColor = pick(BAG_COLORS);
3821
+ const torn = random() < TORN_SHARE && !human;
3822
+ const apron = random() < APRON_SHARE;
3823
+ return { sleeve, hair, headWidth, headHeight, jaw, nose, beard, glasses, cap, capColor, bag, bagColor, torn, apron };
3824
+ };
3825
+ var samplePoseClip = (clip, time) => {
3826
+ const keys = clip.keys;
3827
+ if (keys.length === 0) return {};
3828
+ if (keys.length === 1) return { ...keys[0].pose };
3829
+ let index = 0;
3830
+ while (index < keys.length - 2 && time > keys[index + 1].t) index++;
3831
+ const a = keys[index];
3832
+ const b = keys[index + 1];
3833
+ const k = Math.min(1, Math.max(0, (time - a.t) / (b.t - a.t)));
3834
+ const eased = k * k * (3 - 2 * k);
3835
+ return lerpPose(a.pose, b.pose, eased);
3836
+ };
3837
+ var clipEventsBetween = (clip, from, to) => (clip.events ?? []).filter((event) => event.t > from && event.t <= to).sort((x, y) => x.t - y.t);
3838
+ var POSE_CHANNEL_JOINTS = {
3839
+ full: void 0,
3840
+ upper: ["lean", "twist", "side", "headX", "headY", "headZ", "armR", "armL", "elbR", "elbL", "armRz", "armLz"],
3841
+ lower: ["drop", "legL", "legR", "kneeL", "kneeR"]
3842
+ };
3843
+ var filterPoseChannels = (pose, channels = "full") => {
3844
+ const allowed = POSE_CHANNEL_JOINTS[channels];
3845
+ if (!allowed) return pose;
3846
+ const out = {};
3847
+ for (const name of allowed) if (pose[name] !== void 0) out[name] = pose[name];
3848
+ return out;
3849
+ };
3850
+ var MIRROR_PAIRS = [["armR", "armL"], ["elbR", "elbL"], ["armRz", "armLz"], ["legR", "legL"], ["kneeR", "kneeL"]];
3851
+ var MIRROR_NEGATED = /* @__PURE__ */ new Set(["side", "twist", "headY", "headZ"]);
3852
+ var mirrorPoseClip = (clip, id) => ({
3853
+ ...clip,
3854
+ id,
3855
+ keys: clip.keys.map((key) => {
3856
+ const pose = {};
3857
+ for (const [name, value] of Object.entries(key.pose)) pose[name] = MIRROR_NEGATED.has(name) ? -value : value;
3858
+ for (const [a, b] of MIRROR_PAIRS) {
3859
+ const va = key.pose[a];
3860
+ const vb = key.pose[b];
3861
+ const sign2 = a === "armRz" ? -1 : 1;
3862
+ if (vb !== void 0) pose[a] = sign2 * vb;
3863
+ else delete pose[a];
3864
+ if (va !== void 0) pose[b] = sign2 * va;
3865
+ else delete pose[b];
3866
+ }
3867
+ return { t: key.t, pose };
3868
+ }),
3869
+ ...clip.events ? { events: clip.events.map((event) => ({ ...event })) } : {}
3870
+ });
3871
+ var pose_clips_default = {
3872
+ clips: [
3873
+ {
3874
+ id: "grabbed_bitten_human",
3875
+ source: {
3876
+ file: "site/pages/zumbis-personagens/bestiario.html",
3877
+ scene: "ataque (Agarr\xE3o e mordida)",
3878
+ variable: "HK"
3879
+ },
3880
+ duration: 8,
3881
+ loop: false,
3882
+ channels: "full",
3883
+ keys: [
3884
+ {
3885
+ t: 0,
3886
+ pose: {
3887
+ lean: 0,
3888
+ headY: 0,
3889
+ armL: -0.1,
3890
+ armR: 0.05,
3891
+ elbL: -0.2,
3892
+ elbR: -0.2,
3893
+ drop: 0,
3894
+ kneeL: 0.05,
3895
+ kneeR: 0.05,
3896
+ legL: -0.05,
3897
+ legR: 0.05,
3898
+ headX: 0
3899
+ }
3900
+ },
3901
+ {
3902
+ t: 1.5,
3903
+ pose: {
3904
+ lean: -0.1,
3905
+ headY: -0.6,
3906
+ armL: -0.1,
3907
+ armR: 0.05,
3908
+ elbL: -0.2,
3909
+ elbR: -0.2,
3910
+ drop: 0,
3911
+ kneeL: 0.05,
3912
+ kneeR: 0.05,
3913
+ legL: -0.05,
3914
+ legR: 0.05,
3915
+ headX: -0.1
3916
+ }
3917
+ },
3918
+ {
3919
+ t: 2.1,
3920
+ pose: {
3921
+ lean: -0.3,
3922
+ headY: -0.2,
3923
+ armL: -1.3,
3924
+ armR: -1.2,
3925
+ elbL: -1.4,
3926
+ elbR: -1.5,
3927
+ drop: -0.04,
3928
+ kneeL: 0.25,
3929
+ kneeR: 0.2,
3930
+ legL: -0.3,
3931
+ legR: 0.25,
3932
+ headX: -0.25
3933
+ }
3934
+ },
3935
+ {
3936
+ t: 3.6,
3937
+ pose: {
3938
+ lean: -0.35,
3939
+ headY: 0.3,
3940
+ armL: -1.5,
3941
+ armR: -1,
3942
+ elbL: -0.6,
3943
+ elbR: -1.8,
3944
+ drop: -0.05,
3945
+ kneeL: 0.3,
3946
+ kneeR: 0.2,
3947
+ legL: -0.4,
3948
+ legR: 0.35,
3949
+ headX: -0.2
3950
+ }
3951
+ },
3952
+ {
3953
+ t: 4.3,
3954
+ pose: {
3955
+ lean: -0.2,
3956
+ headY: 0.7,
3957
+ headZ: -0.5,
3958
+ armL: -0.6,
3959
+ armR: -1.9,
3960
+ elbL: -0.4,
3961
+ elbR: -1.2,
3962
+ drop: -0.06,
3963
+ kneeL: 0.3,
3964
+ kneeR: 0.3,
3965
+ legL: -0.3,
3966
+ legR: 0.3,
3967
+ headX: -0.3
3968
+ }
3969
+ },
3970
+ {
3971
+ t: 5.6,
3972
+ pose: {
3973
+ lean: 0.55,
3974
+ headY: 0.4,
3975
+ headZ: -0.3,
3976
+ armL: -0.3,
3977
+ armR: -0.5,
3978
+ elbL: -0.6,
3979
+ elbR: -0.8,
3980
+ drop: -0.5,
3981
+ kneeL: 1.9,
3982
+ kneeR: 1.7,
3983
+ legL: -1.1,
3984
+ legR: -0.9,
3985
+ headX: 0.3
3986
+ }
3987
+ },
3988
+ {
3989
+ t: 8,
3990
+ pose: {
3991
+ lean: 0.6,
3992
+ headY: 0.4,
3993
+ headZ: -0.3,
3994
+ armL: -0.25,
3995
+ armR: -0.45,
3996
+ elbL: -0.6,
3997
+ elbR: -0.8,
3998
+ drop: -0.52,
3999
+ kneeL: 1.95,
4000
+ kneeR: 1.75,
4001
+ legL: -1.1,
4002
+ legR: -0.95,
4003
+ headX: 0.4
4004
+ }
4005
+ }
4006
+ ],
4007
+ events: [
4008
+ {
4009
+ t: 0,
4010
+ type: "phase",
4011
+ data: {
4012
+ label: "pose_clip.grab_bite.phase.approach"
4013
+ }
4014
+ },
4015
+ {
4016
+ t: 1.7,
4017
+ type: "phase",
4018
+ data: {
4019
+ label: "pose_clip.grab_bite.phase.pounce"
4020
+ }
4021
+ },
4022
+ {
4023
+ t: 2.1,
4024
+ type: "phase",
4025
+ data: {
4026
+ label: "pose_clip.grab_bite.phase.grab"
4027
+ }
4028
+ },
4029
+ {
4030
+ t: 4.3,
4031
+ type: "phase",
4032
+ data: {
4033
+ label: "pose_clip.grab_bite.phase.bite"
4034
+ }
4035
+ },
4036
+ {
4037
+ t: 5.6,
4038
+ type: "phase",
4039
+ data: {
4040
+ label: "pose_clip.grab_bite.phase.fall"
4041
+ }
4042
+ },
4043
+ {
4044
+ t: 4.4,
4045
+ type: "impact",
4046
+ data: {
4047
+ kind: "bite",
4048
+ source: "bite.visible=T>4.4 in the scene's step()"
4049
+ }
4050
+ }
4051
+ ]
4052
+ },
4053
+ {
4054
+ id: "grab_bite_zombie",
4055
+ source: {
4056
+ file: "site/pages/zumbis-personagens/bestiario.html",
4057
+ scene: "ataque (Agarr\xE3o e mordida)",
4058
+ variable: "ZK"
4059
+ },
4060
+ duration: 8,
4061
+ loop: false,
4062
+ channels: "full",
4063
+ keys: [
4064
+ {
4065
+ t: 0,
4066
+ pose: {
4067
+ x: -6,
4068
+ lean: 0.75,
4069
+ armL: -1.35,
4070
+ armR: -1.05,
4071
+ elbL: -0.08,
4072
+ elbR: -0.12,
4073
+ headX: -0.55,
4074
+ drop: -0.1,
4075
+ run: 1
4076
+ }
4077
+ },
4078
+ {
4079
+ t: 1.7,
4080
+ pose: {
4081
+ x: -0.9,
4082
+ lean: 0.75,
4083
+ armL: -1.35,
4084
+ armR: -1.05,
4085
+ elbL: -0.08,
4086
+ elbR: -0.12,
4087
+ headX: -0.55,
4088
+ drop: -0.1,
4089
+ run: 1
4090
+ }
4091
+ },
4092
+ {
4093
+ t: 2.1,
4094
+ pose: {
4095
+ x: -0.32,
4096
+ lean: 0.45,
4097
+ armL: -1.65,
4098
+ armR: -1.6,
4099
+ elbL: -0.25,
4100
+ elbR: -0.3,
4101
+ headX: -0.3,
4102
+ drop: -0.08,
4103
+ legL: -0.6,
4104
+ legR: 0.4,
4105
+ kneeL: 0.5,
4106
+ kneeR: 0.6,
4107
+ run: 0
4108
+ }
4109
+ },
4110
+ {
4111
+ t: 3.6,
4112
+ pose: {
4113
+ x: -0.2,
4114
+ lean: 0.35,
4115
+ armL: -1.5,
4116
+ armR: -1.45,
4117
+ elbL: -1.1,
4118
+ elbR: -1.2,
4119
+ headX: -0.2,
4120
+ drop: -0.06,
4121
+ legL: -0.4,
4122
+ legR: 0.3,
4123
+ kneeL: 0.4,
4124
+ kneeR: 0.4,
4125
+ run: 0
4126
+ }
4127
+ },
4128
+ {
4129
+ t: 4.3,
4130
+ pose: {
4131
+ x: -0.1,
4132
+ lean: 0.5,
4133
+ armL: -1.4,
4134
+ armR: -1.3,
4135
+ elbL: -1.5,
4136
+ elbR: -1.5,
4137
+ headX: 0.35,
4138
+ headY: 0.35,
4139
+ drop: -0.08,
4140
+ legL: -0.35,
4141
+ legR: 0.3,
4142
+ kneeL: 0.4,
4143
+ kneeR: 0.4,
4144
+ run: 0
4145
+ }
4146
+ },
4147
+ {
4148
+ t: 5.6,
4149
+ pose: {
4150
+ x: 0,
4151
+ lean: 0.95,
4152
+ armL: -1.2,
4153
+ armR: -1,
4154
+ elbL: -1.4,
4155
+ elbR: -1.3,
4156
+ headX: 0.5,
4157
+ headY: 0.3,
4158
+ drop: -0.45,
4159
+ legL: -1.2,
4160
+ legR: -0.8,
4161
+ kneeL: 1.8,
4162
+ kneeR: 1.5,
4163
+ run: 0
4164
+ }
4165
+ },
4166
+ {
4167
+ t: 8,
4168
+ pose: {
4169
+ x: 0,
4170
+ lean: 1,
4171
+ armL: -1.15,
4172
+ armR: -0.95,
4173
+ elbL: -1.4,
4174
+ elbR: -1.3,
4175
+ headX: 0.55,
4176
+ headY: 0.3,
4177
+ drop: -0.47,
4178
+ legL: -1.2,
4179
+ legR: -0.8,
4180
+ kneeL: 1.85,
4181
+ kneeR: 1.5,
4182
+ run: 0
4183
+ }
4184
+ }
4185
+ ],
4186
+ events: [
4187
+ {
4188
+ t: 0,
4189
+ type: "phase",
4190
+ data: {
4191
+ label: "pose_clip.grab_bite.phase.approach"
4192
+ }
4193
+ },
4194
+ {
4195
+ t: 1.7,
4196
+ type: "phase",
4197
+ data: {
4198
+ label: "pose_clip.grab_bite.phase.pounce"
4199
+ }
4200
+ },
4201
+ {
4202
+ t: 2.1,
4203
+ type: "phase",
4204
+ data: {
4205
+ label: "pose_clip.grab_bite.phase.grab"
4206
+ }
4207
+ },
4208
+ {
4209
+ t: 4.3,
4210
+ type: "phase",
4211
+ data: {
4212
+ label: "pose_clip.grab_bite.phase.bite"
4213
+ }
4214
+ },
4215
+ {
4216
+ t: 5.6,
4217
+ type: "phase",
4218
+ data: {
4219
+ label: "pose_clip.grab_bite.phase.fall"
4220
+ }
4221
+ }
4222
+ ]
4223
+ }
4224
+ ],
4225
+ locales: {
4226
+ "pt-BR": {
4227
+ "pose_clip.grab_bite.phase.approach": "1. Aproxima\xE7\xE3o",
4228
+ "pose_clip.grab_bite.phase.pounce": "2. O bote",
4229
+ "pose_clip.grab_bite.phase.grab": "3. Agarr\xE3o: 3 s para se soltar",
4230
+ "pose_clip.grab_bite.phase.bite": "4. Mordida: infec\xE7\xE3o 100%",
4231
+ "pose_clip.grab_bite.phase.fall": "5. Queda"
4232
+ },
4233
+ en: {
4234
+ "pose_clip.grab_bite.phase.approach": "1. Approach",
4235
+ "pose_clip.grab_bite.phase.pounce": "2. The pounce",
4236
+ "pose_clip.grab_bite.phase.grab": "3. Grab: 3 s to break free",
4237
+ "pose_clip.grab_bite.phase.bite": "4. Bite: 100% infection",
4238
+ "pose_clip.grab_bite.phase.fall": "5. The fall"
4239
+ }
4240
+ }
4241
+ };
4242
+ var createPoseClipRegistry = (initial = []) => {
4243
+ const clips = /* @__PURE__ */ new Map();
4244
+ const registry = {
4245
+ register(clip) {
4246
+ clips.set(clip.id, clip);
4247
+ return registry;
4248
+ },
4249
+ get: (id) => clips.get(id),
4250
+ list: () => [...clips.values()],
4251
+ remove: (id) => clips.delete(id)
4252
+ };
4253
+ for (const clip of initial) registry.register(clip);
4254
+ return registry;
4255
+ };
4256
+ var POSE_CLIPS = pose_clips_default.clips;
4257
+ var POSE_CLIP_LOCALES = pose_clips_default.locales;
4258
+ var ease = (k) => k * k * (3 - 2 * k);
4259
+ var mix = (a, b, k) => a + (b - a) * k;
4260
+ var mixTriple = (a, b, k) => [mix(a[0], b[0], k), mix(a[1], b[1], k), mix(a[2], b[2], k)];
4261
+ var trackOf = (clip, side) => {
4262
+ const out = [];
4263
+ for (const key of clip.keys) {
4264
+ if (side === "L") {
4265
+ if (key.L === "mirror") {
4266
+ if (key.R) out.push({ t: key.t, key: key.R, mirror: true });
4267
+ } else if (key.L) out.push({ t: key.t, key: key.L, mirror: false });
4268
+ } else {
4269
+ const entry = key[side];
4270
+ if (entry) out.push({ t: key.t, key: entry, mirror: false });
4271
+ }
4272
+ }
4273
+ return out.sort((a, b) => a.t - b.t);
4274
+ };
4275
+ var sampleTrack = (track, time) => {
4276
+ if (track.length === 0) return void 0;
4277
+ const first = track[0];
4278
+ const last = track[track.length - 1];
4279
+ const of = (entry) => ({ p: [...entry.key.p], r: [...entry.key.r], grip: entry.key.grip, w: entry.key.w ?? 1, mirror: entry.mirror });
4280
+ if (time <= first.t) return of(first);
4281
+ if (time >= last.t) return of(last);
4282
+ let index = 0;
4283
+ while (index < track.length - 2 && time > track[index + 1].t) index++;
4284
+ const a = track[index];
4285
+ const b = track[index + 1];
4286
+ const k = ease(Math.min(1, Math.max(0, (time - a.t) / (b.t - a.t))));
4287
+ const ga = a.key.grip;
4288
+ const gb = b.key.grip;
4289
+ return {
4290
+ p: mixTriple(a.key.p, b.key.p, k),
4291
+ r: mixTriple(a.key.r, b.key.r, k),
4292
+ grip: ga === void 0 ? gb : gb === void 0 ? ga : mix(ga, gb, k),
4293
+ w: mix(a.key.w ?? 1, b.key.w ?? 1, k),
4294
+ mirror: a.mirror
4295
+ };
4296
+ };
4297
+ var sampleFirstPersonClip = (clip, time) => {
4298
+ const out = {};
4299
+ for (const side of ["R", "L", "F"]) {
4300
+ const sample = sampleTrack(trackOf(clip, side), time);
4301
+ if (sample) out[side] = sample;
4302
+ }
4303
+ return out;
2266
4304
  };
2267
4305
 
2268
4306
  // src/instanced/body-geometry.ts
@@ -2298,13 +4336,13 @@ var GameCharactersThree = (() => {
2298
4336
  return source;
2299
4337
  };
2300
4338
  var MERGED_ATTRIBUTES = [["position", 3], ["normal", 3], ["bone", 1], ["vcol", 4], ["pivot", 3], ["ppivot", 3]];
2301
- var mergeBody = (list, three) => {
2302
- const total = list.reduce((sum, geometry) => sum + geometry.attributes.position.count, 0);
4339
+ var mergeBody = (list2, three) => {
4340
+ const total = list2.reduce((sum, geometry) => sum + geometry.attributes.position.count, 0);
2303
4341
  const merged = new three.BufferGeometry();
2304
4342
  for (const [name, size] of MERGED_ATTRIBUTES) {
2305
4343
  const array = new Float32Array(total * size);
2306
4344
  let offset = 0;
2307
- for (const geometry of list) {
4345
+ for (const geometry of list2) {
2308
4346
  const part = geometry.attributes[name].array;
2309
4347
  array.set(part, offset);
2310
4348
  offset += part.length;
@@ -2314,7 +4352,8 @@ var GameCharactersThree = (() => {
2314
4352
  merged.computeBoundingSphere();
2315
4353
  return merged;
2316
4354
  };
2317
- var buildInstancedBody = (three, { segments, body = TEAM_GAME }) => {
4355
+ var buildInstancedBody = (host, { segments, body = TEAM_GAME }) => {
4356
+ const three = shapeGeometries(host);
2318
4357
  const joints = jointsOf(body);
2319
4358
  const parts = [];
2320
4359
  const half = Math.max(4, segments >> 1);
@@ -2442,15 +4481,15 @@ var GameCharactersThree = (() => {
2442
4481
  copy.setAttribute(name, attribute);
2443
4482
  attributes[name] = attribute;
2444
4483
  }
2445
- const mesh = new three.InstancedMesh(copy, createBodyMaterial(three, { time }), max);
2446
- mesh.customDepthMaterial = createBodyMaterial(three, { depth: true, time });
2447
- mesh.frustumCulled = false;
2448
- mesh.castShadow = castShadow;
2449
- mesh.receiveShadow = true;
2450
- mesh.count = 0;
4484
+ const mesh2 = new three.InstancedMesh(copy, createBodyMaterial(three, { time }), max);
4485
+ mesh2.customDepthMaterial = createBodyMaterial(three, { depth: true, time });
4486
+ mesh2.frustumCulled = false;
4487
+ mesh2.castShadow = castShadow;
4488
+ mesh2.receiveShadow = true;
4489
+ mesh2.count = 0;
2451
4490
  let count = 0;
2452
4491
  return {
2453
- mesh,
4492
+ mesh: mesh2,
2454
4493
  max,
2455
4494
  get count() {
2456
4495
  return count;
@@ -2458,7 +4497,7 @@ var GameCharactersThree = (() => {
2458
4497
  begin() {
2459
4498
  count = 0;
2460
4499
  },
2461
- push({ a, b, c, color, eye, y = 0 }) {
4500
+ push({ a, b, c, color: color2, eye, y = 0 }) {
2462
4501
  if (count >= max) return;
2463
4502
  const index = count++;
2464
4503
  const fourOffset = index * 4;
@@ -2466,11 +4505,11 @@ var GameCharactersThree = (() => {
2466
4505
  attributes.iA.array.set(a, fourOffset);
2467
4506
  attributes.iB.array.set([b[0], b[1], b[2], b[3] + POSE_SLOTS2 * Math.round((Math.min(MAX_HEIGHT2, Math.max(MIN_HEIGHT2, y)) - MIN_HEIGHT2) * HEIGHT_STEPS2)], fourOffset);
2468
4507
  attributes.iC.array.set(c, fourOffset);
2469
- attributes.iCol.array.set([color.r, color.g, color.b], threeOffset);
4508
+ attributes.iCol.array.set([color2.r, color2.g, color2.b], threeOffset);
2470
4509
  attributes.iEye.array.set(eye ? [eye.r, eye.g, eye.b] : [0, 0, 0], threeOffset);
2471
4510
  },
2472
4511
  end() {
2473
- mesh.count = count;
4512
+ mesh2.count = count;
2474
4513
  for (const attribute of Object.values(attributes)) {
2475
4514
  attribute.clearUpdateRanges();
2476
4515
  attribute.addUpdateRange(0, count * attribute.itemSize);
@@ -2495,7 +4534,8 @@ var GameCharactersThree = (() => {
2495
4534
  var FAR_LOD = 0.6;
2496
4535
  var EYE_SCALE = 2.2;
2497
4536
  var EYE_DEPTH_SCALE = 1.4;
2498
- var bakeBody = (three, builders, spec, lod) => {
4537
+ var bakeBody = (host, builders, spec, lod) => {
4538
+ const three = shapeGeometries(host);
2499
4539
  const root = spec.retrato && builders.buildPortrait ? builders.buildPortrait(spec.retrato, lod) : builders.buildBest({ ...spec, pose: { ...BAKE_NEUTRAL_POSE, ...spec.pose ?? {} } }, lod);
2500
4540
  const rig = root.userData.rig;
2501
4541
  const P = rig.P;
@@ -2511,7 +4551,7 @@ var GameCharactersThree = (() => {
2511
4551
  leg.kn.rotation.set(0, 0, 0);
2512
4552
  }
2513
4553
  root.updateMatrixWorld(true);
2514
- const worldPosition2 = (object) => object.getWorldPosition(new three.Vector3()).toArray();
4554
+ const worldPosition2 = (object2) => object2.getWorldPosition(new three.Vector3()).toArray();
2515
4555
  const bones = /* @__PURE__ */ new Map();
2516
4556
  bones.set(rig.headG, [1, worldPosition2(rig.headG), [0, 0, 0]]);
2517
4557
  for (const arm of rig.arms) {
@@ -2527,13 +4567,13 @@ var GameCharactersThree = (() => {
2527
4567
  const trunk = [0, [0, 0.9 * P.s, 0], [0, 0, 0]];
2528
4568
  const parts = [];
2529
4569
  const topMaterial = spec.retrato ? null : builders.topMaterial();
2530
- root.traverse((object) => {
2531
- const mesh = object;
2532
- const material = mesh.material;
2533
- if (!mesh.isMesh || !mesh.geometry || material.transparent) return;
2534
- for (let ancestor = object; ancestor; ancestor = ancestor.parent) if (!ancestor.visible) return;
4570
+ root.traverse((object2) => {
4571
+ const mesh2 = object2;
4572
+ const material = mesh2.material;
4573
+ if (!mesh2.isMesh || !mesh2.geometry || material.transparent) return;
4574
+ for (let ancestor = object2; ancestor; ancestor = ancestor.parent) if (!ancestor.visible) return;
2535
4575
  let tag = trunk;
2536
- for (let ancestor = object.parent; ancestor; ancestor = ancestor.parent) {
4576
+ for (let ancestor = object2.parent; ancestor; ancestor = ancestor.parent) {
2537
4577
  const found = bones.get(ancestor);
2538
4578
  if (found) {
2539
4579
  tag = found;
@@ -2541,21 +4581,21 @@ var GameCharactersThree = (() => {
2541
4581
  }
2542
4582
  }
2543
4583
  let [bone, pivot, parentPivot] = tag;
2544
- if (object.userData.bone === 11) {
4584
+ if (object2.userData.bone === 11) {
2545
4585
  bone = 11;
2546
4586
  pivot = bones.get(rig.headG)[1];
2547
4587
  parentPivot = [0, 0, 0];
2548
4588
  }
2549
- const isEye2 = !!object.userData.eye;
2550
- const color = material.color;
4589
+ const isEye2 = !!object2.userData.eye;
4590
+ const color2 = material.color;
2551
4591
  const materialId = isEye2 ? 3 : material === topMaterial ? 1 : 6;
2552
4592
  if (isEye2 && bone === 1) bone = 6;
2553
- const geometry = mesh.geometry.clone();
2554
- geometry.applyMatrix4(mesh.matrixWorld);
4593
+ const geometry = mesh2.geometry.clone();
4594
+ geometry.applyMatrix4(mesh2.matrixWorld);
2555
4595
  const isBlood = material.polygonOffset && material.isMeshStandardMaterial;
2556
4596
  if (isBlood) liftAlongNormals(geometry, lod < FAR_LOD ? BLOOD_LIFT_FAR : BLOOD_LIFT_NEAR);
2557
4597
  if (isEye2) enlargeEye(three, geometry, lod < FAR_LOD ? 1 : 0.68);
2558
- const colors = isBlood ? [Math.max(color.r * 1.7, 0.3), Math.min(color.g * 1.7, 0.04), Math.min(color.b * 1.7, 0.04), materialId] : [color.r, color.g, color.b, materialId];
4598
+ const colors = isBlood ? [Math.max(color2.r * 1.7, 0.3), Math.min(color2.g * 1.7, 0.04), Math.min(color2.b * 1.7, 0.04), materialId] : [color2.r, color2.g, color2.b, materialId];
2559
4599
  parts.push({ g: geometry, bone, pv: pivot, pp: parentPivot, col: colors });
2560
4600
  });
2561
4601
  return { geo: mergeBaked(three, parts), s: P.s, bulk: P.bulk, verts: parts.reduce((sum, part) => sum + part.g.attributes.position.count, 0) };
@@ -2581,7 +4621,7 @@ var GameCharactersThree = (() => {
2581
4621
  }
2582
4622
  const position = new Float32Array(vertexTotal * 3);
2583
4623
  const normal = new Float32Array(vertexTotal * 3);
2584
- const color = new Float32Array(vertexTotal * 4);
4624
+ const color2 = new Float32Array(vertexTotal * 4);
2585
4625
  const bone = new Float32Array(vertexTotal);
2586
4626
  const pivot = new Float32Array(vertexTotal * 3);
2587
4627
  const parentPivot = new Float32Array(vertexTotal * 3);
@@ -2593,7 +4633,7 @@ var GameCharactersThree = (() => {
2593
4633
  position.set(part.g.attributes.position.array, vertexOffset * 3);
2594
4634
  normal.set(part.g.attributes.normal.array, vertexOffset * 3);
2595
4635
  for (let vertex = 0; vertex < count; vertex++) {
2596
- color.set(part.col, (vertexOffset + vertex) * 4);
4636
+ color2.set(part.col, (vertexOffset + vertex) * 4);
2597
4637
  bone[vertexOffset + vertex] = part.bone;
2598
4638
  pivot.set(part.pv, (vertexOffset + vertex) * 3);
2599
4639
  parentPivot.set(part.pp, (vertexOffset + vertex) * 3);
@@ -2608,7 +4648,7 @@ var GameCharactersThree = (() => {
2608
4648
  const out = new three.BufferGeometry();
2609
4649
  out.setAttribute("position", new three.BufferAttribute(position, 3));
2610
4650
  out.setAttribute("normal", new three.BufferAttribute(normal, 3));
2611
- out.setAttribute("vcol", new three.BufferAttribute(color, 4));
4651
+ out.setAttribute("vcol", new three.BufferAttribute(color2, 4));
2612
4652
  out.setAttribute("bone", new three.BufferAttribute(bone, 1));
2613
4653
  out.setAttribute("pivot", new three.BufferAttribute(pivot, 3));
2614
4654
  out.setAttribute("ppivot", new three.BufferAttribute(parentPivot, 3));
@@ -2644,20 +4684,21 @@ var GameCharactersThree = (() => {
2644
4684
  var SPIN_DAMPING = 0.5;
2645
4685
  var REST_SPEED = 0.4;
2646
4686
  var LEG_COLOR = 2896704;
2647
- var createFlyingLimbs = (three, { max = 40, random, effects = {} }) => {
4687
+ var createFlyingLimbs = (host, { max = 40, random, effects = {} }) => {
4688
+ const three = shapeGeometries(host);
2648
4689
  const limbs = [];
2649
- const mesh = new three.InstancedMesh(new three.CapsuleGeometry(0.065, 0.32, 2, 6), new three.MeshLambertMaterial({ color: 16777215 }), max);
2650
- mesh.count = 0;
2651
- mesh.castShadow = true;
2652
- mesh.setColorAt(0, new three.Color());
4690
+ const mesh2 = new three.InstancedMesh(new three.CapsuleGeometry(0.065, 0.32, 2, 6), new three.MeshLambertMaterial({ color: 16777215 }), max);
4691
+ mesh2.count = 0;
4692
+ mesh2.castShadow = true;
4693
+ mesh2.setColorAt(0, new three.Color());
2653
4694
  const matrix = new three.Matrix4();
2654
4695
  const quaternion = new three.Quaternion();
2655
4696
  const scale = new three.Vector3();
2656
4697
  const position = new three.Vector3();
2657
4698
  const euler = new three.Euler();
2658
- const color = new three.Color();
4699
+ const color2 = new three.Color();
2659
4700
  return {
2660
- mesh,
4701
+ mesh: mesh2,
2661
4702
  limbs,
2662
4703
  launch({ x, z, kind, color: sleeve, blood }) {
2663
4704
  const isLeg2 = kind === "leg";
@@ -2710,12 +4751,12 @@ var GameCharactersThree = (() => {
2710
4751
  }
2711
4752
  }
2712
4753
  matrix.compose(position.set(limb2.x, limb2.y, limb2.z), quaternion.setFromEuler(euler.set(limb2.rx, limb2.rz, 0)), scale.set(1, limb2.len, 1));
2713
- mesh.setMatrixAt(index, matrix);
2714
- mesh.setColorAt(index, color.set(limb2.col));
4754
+ mesh2.setMatrixAt(index, matrix);
4755
+ mesh2.setColorAt(index, color2.set(limb2.col));
2715
4756
  });
2716
- mesh.count = limbs.length;
2717
- mesh.instanceMatrix.needsUpdate = true;
2718
- if (mesh.instanceColor) mesh.instanceColor.needsUpdate = true;
4757
+ mesh2.count = limbs.length;
4758
+ mesh2.instanceMatrix.needsUpdate = true;
4759
+ if (mesh2.instanceColor) mesh2.instanceColor.needsUpdate = true;
2719
4760
  }
2720
4761
  };
2721
4762
  };
@@ -2830,7 +4871,8 @@ var GameCharactersThree = (() => {
2830
4871
  };
2831
4872
 
2832
4873
  // src/rich/best-builder.ts
2833
- var createBestBuilder = (THREE, { types, random = Math.random }) => {
4874
+ var createBestBuilder = (host, { types, random = Math.random }) => {
4875
+ const THREE = shapeGeometries(host);
2834
4876
  const options = { types, random };
2835
4877
  let LK = 1, topM_ref = null;
2836
4878
  const SPH = (r, w = 8, h = 6, ...a) => new THREE.SphereGeometry(r, Math.max(4, Math.round(w * LK)), Math.max(3, Math.round(h * LK)), ...a);
@@ -2856,7 +4898,7 @@ var GameCharactersThree = (() => {
2856
4898
  const PANTS = 2896704, GRAY2 = 4868678, RED2 = 8000012;
2857
4899
  const col = (a, b, t) => new THREE.Color(a).lerp(new THREE.Color(b), t);
2858
4900
  const geoBox = (w, h, d) => new THREE.BoxGeometry(w, h, d);
2859
- const box = (w, h, d, m) => new THREE.Mesh(geoBox(w, h, d), m);
4901
+ const box2 = (w, h, d, m) => new THREE.Mesh(geoBox(w, h, d), m);
2860
4902
  const limbGeo = (w, len) => {
2861
4903
  const g = geoBox(w, len, w);
2862
4904
  g.translate(0, -len / 2, 0);
@@ -3010,7 +5052,7 @@ var GameCharactersThree = (() => {
3010
5052
  st.scale.set(1, 0.35, 1);
3011
5053
  add(p2, CYL(r * 0.32, r * 0.36, 0.07, 10), M(15261900), 0, y + (up ? 0.04 : -0.04), 0);
3012
5054
  };
3013
- const ring = (p2, r, h, m, y, sx, sz) => {
5055
+ const ring2 = (p2, r, h, m, y, sx, sz) => {
3014
5056
  const o = add(p2, CYL(r, r, h, 24), m, 0, y, 0);
3015
5057
  o.scale.set(sx || 1.12, 1, sz || 0.7);
3016
5058
  return o;
@@ -3134,8 +5176,8 @@ var GameCharactersThree = (() => {
3134
5176
  for (let i = 0; i < 3; i++) add(U, geoBox(0.11, 0.13, 0.05), M(O.vest), -0.15 + i * 0.15, 1.17, 0.17);
3135
5177
  }
3136
5178
  if (O.stripes) {
3137
- ring(U, 0.205, 0.05, M(O.stripes), 1.03, 1.13, 0.68);
3138
- ring(U, 0.268, 0.05, M(O.stripes), 1.42, 1.13, 0.67);
5179
+ ring2(U, 0.205, 0.05, M(O.stripes), 1.03, 1.13, 0.68);
5180
+ ring2(U, 0.268, 0.05, M(O.stripes), 1.42, 1.13, 0.67);
3139
5181
  }
3140
5182
  if (d === 3 && !P.bloat) [0, 1, 2].forEach((k) => add(U, geoBox(0.2, 0.022, 0.02), M(14208952), 0, 1.3 + k * 0.065, 0.168));
3141
5183
  if (!spec.human) {
@@ -3429,8 +5471,8 @@ var GameCharactersThree = (() => {
3429
5471
  },
3430
5472
  {
3431
5473
  ids: ["stubble"],
3432
- apply: ({ Hd, THREE, add, cmat, scaleHex, sp }) => {
3433
- const b = add(Hd, new THREE.SphereGeometry(0.123, 16, 12), cmat(scaleHex(sp.skin, 0.62)), 0, 1.705, 0.032);
5474
+ apply: ({ Hd, THREE, add, cmat, scaleHex: scaleHex2, sp }) => {
5475
+ const b = add(Hd, new THREE.SphereGeometry(0.123, 16, 12), cmat(scaleHex2(sp.skin, 0.62)), 0, 1.705, 0.032);
3434
5476
  b.scale.set(1, 0.74, 1);
3435
5477
  }
3436
5478
  },
@@ -3748,8 +5790,8 @@ var GameCharactersThree = (() => {
3748
5790
  add(U, Bx(0.1, 0.12, 0.09), m, -0.17, 0.95, -0.15);
3749
5791
  return;
3750
5792
  },
3751
- belt: ({ U, m, ring }) => {
3752
- ring(U, 0.212, 0.07, m, 0.95, 1.12, 0.72);
5793
+ belt: ({ U, m, ring: ring2 }) => {
5794
+ ring2(U, 0.212, 0.07, m, 0.95, 1.12, 0.72);
3753
5795
  return;
3754
5796
  },
3755
5797
  holster: ({ Bx, add, cmat, legs }) => {
@@ -3761,9 +5803,9 @@ var GameCharactersThree = (() => {
3761
5803
  add(U, Bx(0.012, 0.1, 0.012), cmat(1710618), 0.17, 1.52, 0.18);
3762
5804
  return;
3763
5805
  },
3764
- stripes: ({ THREE, U, add, arms, m, ring }) => {
3765
- ring(U, 0.205, 0.05, m, 1.03, 1.13, 0.68);
3766
- ring(U, 0.268, 0.05, m, 1.42, 1.13, 0.67);
5806
+ stripes: ({ THREE, U, add, arms, m, ring: ring2 }) => {
5807
+ ring2(U, 0.205, 0.05, m, 1.03, 1.13, 0.68);
5808
+ ring2(U, 0.268, 0.05, m, 1.42, 1.13, 0.67);
3767
5809
  arms.forEach((a) => {
3768
5810
  const r = add(a.el, new THREE.CylinderGeometry(0.058, 0.054, 0.05, 18), m, 0, -0.17, 0);
3769
5811
  });
@@ -3873,17 +5915,17 @@ var GameCharactersThree = (() => {
3873
5915
  add(arms[1].g, new THREE.CylinderGeometry(0.08, 0.078, 0.08, 18), m, 0, -0.12, 0);
3874
5916
  return;
3875
5917
  },
3876
- tiedsleeves: ({ Bx, U, add, legs, m, ring }) => {
3877
- ring(U, 0.215, 0.1, m, 0.95, 1.12, 0.74);
5918
+ tiedsleeves: ({ Bx, U, add, legs, m, ring: ring2 }) => {
5919
+ ring2(U, 0.215, 0.1, m, 0.95, 1.12, 0.74);
3878
5920
  legs.forEach((l) => add(l.g, Bx(0.1, 0.26, 0.05), m, l.s * 0.02, -0.1, 0.105));
3879
5921
  return;
3880
5922
  },
3881
- labcoat: ({ Bx, THREE, U, add, arms, cmat, fem, legs, m, ring, torsoGeo }) => {
5923
+ labcoat: ({ Bx, THREE, U, add, arms, cmat, fem, legs, m, ring: ring2, torsoGeo }) => {
3882
5924
  {
3883
5925
  const g = torsoGeo(fem);
3884
5926
  g.scale(1.06, 1, 1.12);
3885
5927
  add(U, g, m, 0, 0, 0);
3886
- ring(U, 0.22, 0.14, m, 0.9, 1.12, 0.76);
5928
+ ring2(U, 0.22, 0.14, m, 0.9, 1.12, 0.76);
3887
5929
  legs.forEach((l) => add(l.g, new THREE.CylinderGeometry(0.145, 0.165, 0.46, 20, 1, true).translate(0, -0.21, 0), m, 0, 0, 0));
3888
5930
  add(U, Bx(0.025, 0.62, 0.012), cmat(10132114), 0, 1.2, 0.19);
3889
5931
  arms.forEach((a) => {
@@ -3973,8 +6015,8 @@ var GameCharactersThree = (() => {
3973
6015
  add(U, Bx(0.05, 0.75, 0.02), cmat(4864546), 0, 1.22, 0.195, 0, 0, -0.75);
3974
6016
  return;
3975
6017
  },
3976
- scarf: ({ PI, THREE, U, add, m, ring }) => {
3977
- ring(U, 0.1, 0.08, m, 1.57, 1.3, 1.2);
6018
+ scarf: ({ PI, THREE, U, add, m, ring: ring2 }) => {
6019
+ ring2(U, 0.1, 0.08, m, 1.57, 1.3, 1.2);
3978
6020
  add(U, new THREE.ConeGeometry(0.08, 0.14, 3), m, 0, 1.47, 0.15, PI, 0, 0);
3979
6021
  return;
3980
6022
  },
@@ -4017,12 +6059,12 @@ var GameCharactersThree = (() => {
4017
6059
  return;
4018
6060
  }
4019
6061
  },
4020
- refl: ({ Bx, THREE, U, add, cmat, m, ring }) => {
6062
+ refl: ({ Bx, THREE, U, add, cmat, m, ring: ring2 }) => {
4021
6063
  {
4022
6064
  const v = add(U, new THREE.CylinderGeometry(0.287, 0.252, 0.46, 20), m, 0, 1.3, 0);
4023
6065
  v.scale.set(1.13, 1, 0.72);
4024
- ring(U, 0.29, 0.035, cmat(13159632, { metalness: 0.3, roughness: 0.4 }), 1.2, 1.13, 0.73);
4025
- ring(U, 0.3, 0.035, cmat(13159632, { metalness: 0.3, roughness: 0.4 }), 1.37, 1.13, 0.73);
6066
+ ring2(U, 0.29, 0.035, cmat(13159632, { metalness: 0.3, roughness: 0.4 }), 1.2, 1.13, 0.73);
6067
+ ring2(U, 0.3, 0.035, cmat(13159632, { metalness: 0.3, roughness: 0.4 }), 1.37, 1.13, 0.73);
4026
6068
  add(U, Bx(0.17, 0.055, 0.02), cmat(1714794), 0, 1.47, 0.205);
4027
6069
  return;
4028
6070
  }
@@ -4122,9 +6164,10 @@ var GameCharactersThree = (() => {
4122
6164
  EXTRAS.dbl_front = EXTRAS.rifle_front;
4123
6165
 
4124
6166
  // src/rich/person-kit.ts
4125
- var createPersonKit = (THREE, { random: R, createCanvas = () => document.createElement("canvas") }) => {
6167
+ var createPersonKit = (host, { random: R, createCanvas = () => document.createElement("canvas") }) => {
6168
+ const THREE = shapeGeometries(host);
4126
6169
  const T = THREE;
4127
- const scaleHex = (hex2, factor) => {
6170
+ const scaleHex2 = (hex2, factor) => {
4128
6171
  const channel = (shift) => (hex2 >> shift & 255) / 255 * factor * 255;
4129
6172
  return channel(16) << 16 ^ channel(8) << 8 ^ channel(0) << 0;
4130
6173
  };
@@ -4181,7 +6224,7 @@ var GameCharactersThree = (() => {
4181
6224
  function ball(parent, r, m, x, y, z) {
4182
6225
  return add(parent, new THREE.SphereGeometry(r, SEG, 12), m, x || 0, y || 0, z || 0);
4183
6226
  }
4184
- function ring(parent, r, h, m, y, sx, sz) {
6227
+ function ring2(parent, r, h, m, y, sx, sz) {
4185
6228
  const o = add(parent, new THREE.CylinderGeometry(r, r, h, 20), m, 0, y, 0);
4186
6229
  o.scale.set(sx || 1.12, 1, sz || 0.7);
4187
6230
  return o;
@@ -4227,17 +6270,17 @@ var GameCharactersThree = (() => {
4227
6270
  const k = c + "|" + o;
4228
6271
  return stainMs[k] || (stainMs[k] = new THREE.MeshStandardMaterial(Object.assign({ color: c, roughness: 0.95, metalness: 0, polygonOffset: true, polygonOffsetFactor: -2, polygonOffsetUnits: -2, side: THREE.DoubleSide }, o || {})));
4229
6272
  }
4230
- function splat(parent, x, y, z, r, color, n, out, kind) {
4231
- const skin = kind === "skin", fresh = color === 9046538, push = (o) => {
6273
+ function splat(parent, x, y, z, r, color2, n, out, kind) {
6274
+ const skin = kind === "skin", fresh = color2 === 9046538, push = (o) => {
4232
6275
  o.castShadow = false;
4233
6276
  if (out) out.push(o);
4234
6277
  return o;
4235
6278
  };
4236
6279
  const sy = 0.8 + R() * 0.4, seed = R() * 10;
4237
- const core = skin ? stainM(color, { roughness: 0.12, metalness: 0.1 }) : stainM(scaleHex(color, 0.72));
6280
+ const core = skin ? stainM(color2, { roughness: 0.12, metalness: 0.1 }) : stainM(scaleHex2(color2, 0.72));
4238
6281
  const a = push(add(parent, blobGeo(blobR(40, skin ? 0.4 : 0.9, seed), r * 0.82, r * 0.82 * sy), core, x, y, z + 4e-3));
4239
6282
  if (!skin) {
4240
- push(add(parent, blobGeo(blobR(48, 1.6, seed + 0.3), r * 1.3, r * 1.3 * sy), stainM(color, { transparent: true, opacity: 0.5, depthWrite: false }), x, y, z + 2e-3));
6283
+ push(add(parent, blobGeo(blobR(48, 1.6, seed + 0.3), r * 1.3, r * 1.3 * sy), stainM(color2, { transparent: true, opacity: 0.5, depthWrite: false }), x, y, z + 2e-3));
4241
6284
  }
4242
6285
  for (let k = 0; k < (n || 0); k++) {
4243
6286
  const ang = R() * 6.28, d = r * (1.2 + R() * 0.9), rr = r * (0.16 + R() * 0.2);
@@ -4254,14 +6297,15 @@ var GameCharactersThree = (() => {
4254
6297
  }
4255
6298
  return a;
4256
6299
  }
4257
- return { THREE, PI, SEG, R, scaleHex, Bx, add, cmat, ball, ring, cap, limb: limb2, mlimb, torsoGeo, splat, stainM, chessTex };
6300
+ return { THREE, PI, SEG, R, scaleHex: scaleHex2, Bx, add, cmat, ball, ring: ring2, cap, limb: limb2, mlimb, torsoGeo, splat, stainM, chessTex };
4258
6301
  };
4259
6302
 
4260
6303
  // src/rich/person-builder.ts
4261
6304
  var PAGE_EYES = { lento: 14926657, corredor: 15022379, brutamonte: 15698474 };
4262
- var createPersonBuilder = (THREE, options = {}) => {
6305
+ var createPersonBuilder = (host, options = {}) => {
6306
+ const THREE = shapeGeometries(host);
4263
6307
  const kit = createPersonKit(THREE, { random: options.random ?? createRng(77), createCanvas: options.createCanvas });
4264
- const { PI, R, scaleHex, Bx, add, cmat, ball, ring, cap, limb: limb2, mlimb, torsoGeo, splat, stainM, chessTex } = kit;
6308
+ const { PI, R, scaleHex: scaleHex2, Bx, add, cmat, ball, ring: ring2, cap, limb: limb2, mlimb, torsoGeo, splat, stainM, chessTex } = kit;
4265
6309
  const reduce = options.reducedMotion ?? false;
4266
6310
  const detailed = (options.detail ?? 0) === 0;
4267
6311
  const EYE = { ...PAGE_EYES, ...options.zombieEyes };
@@ -4362,7 +6406,7 @@ var GameCharactersThree = (() => {
4362
6406
  const ridge = ball(Hd, 0.1, skinM, 0, 1.842, 0.105);
4363
6407
  ridge.scale.set(1.3, 0.28, 0.55);
4364
6408
  add(Hd, new THREE.SphereGeometry(0.021, 10, 8), skinM, 0, 1.762, 0.182);
4365
- add(Hd, Bx(0.064, 0.013, 0.02), cmat(scaleHex(sp.skin, 0.68)), 0, 1.703, 0.156);
6409
+ add(Hd, Bx(0.064, 0.013, 0.02), cmat(scaleHex2(sp.skin, 0.68)), 0, 1.703, 0.156);
4366
6410
  const bags = add(Hd, Bx(0.2, 0.022, 0.012), new THREE.MeshBasicMaterial({ color: 3811882, transparent: true, opacity: 0 }), 0, 1.79, 0.166);
4367
6411
  bags.castShadow = false;
4368
6412
  const hc = cmat(sp.hair.c), hs = sp.hair.s;
@@ -4399,7 +6443,7 @@ var GameCharactersThree = (() => {
4399
6443
  t.rotation.x = 0.25;
4400
6444
  }
4401
6445
  const f = sp.face || [];
4402
- for (const feature of FACE_FEATURES) if (feature.ids.some((id) => f.includes(id))) feature.apply({ THREE, PI, Hd, add, Bx, cmat, hc, sp, f, scaleHex });
6446
+ for (const feature of FACE_FEATURES) if (feature.ids.some((id) => f.includes(id))) feature.apply({ THREE, PI, Hd, add, Bx, cmat, hc, sp, f, scaleHex: scaleHex2 });
4403
6447
  if (sp.hat) {
4404
6448
  const k = sp.hat.k, c = cmat(sp.hat.c);
4405
6449
  HATS.find((hat) => hat.kinds.includes(k))?.apply({ THREE, PI, Hd, add, Bx, cmat, cap, c, k, sp });
@@ -4438,7 +6482,7 @@ var GameCharactersThree = (() => {
4438
6482
  for (const e of sp.ex || []) {
4439
6483
  const [k, c] = e;
4440
6484
  const m = c !== void 0 ? cmat(c) : null;
4441
- EXTRAS[k]?.({ THREE, PI, U, Hd, root, add, Bx, cmat, ring, torsoGeo, legs, arms, fem, topM, m, e, k, headG, fig, upper, skinM, sp, splat, R, ball, cap, hc });
6485
+ EXTRAS[k]?.({ THREE, PI, U, Hd, root, add, Bx, cmat, ring: ring2, torsoGeo, legs, arms, fem, topM, m, e, k, headG, fig, upper, skinM, sp, splat, R, ball, cap, hc });
4442
6486
  }
4443
6487
  if (sp.back === "shotgun") {
4444
6488
  const g = new THREE.Group();
@@ -4618,9 +6662,9 @@ var GameCharactersThree = (() => {
4618
6662
  // src/eyes.ts
4619
6663
  var GLOW_SIZE = 64;
4620
6664
  var createGlowTexture = (three, createCanvas) => {
4621
- const make = createCanvas ?? (typeof document === "undefined" ? void 0 : () => document.createElement("canvas"));
4622
- if (!make) return null;
4623
- const canvas = make();
6665
+ const make2 = createCanvas ?? (typeof document === "undefined" ? void 0 : () => document.createElement("canvas"));
6666
+ if (!make2) return null;
6667
+ const canvas = make2();
4624
6668
  canvas.width = canvas.height = GLOW_SIZE;
4625
6669
  const context = canvas.getContext("2d");
4626
6670
  if (!context) return null;
@@ -4632,35 +6676,36 @@ var GameCharactersThree = (() => {
4632
6676
  context.fillRect(0, 0, GLOW_SIZE, GLOW_SIZE);
4633
6677
  return new three.CanvasTexture(canvas);
4634
6678
  };
4635
- var createEye = (three, { color, radius = 0.02, glow, glowOpacity = 0.55, texture = null }) => {
6679
+ var createEye = (host, { color: color2, radius = 0.02, glow, glowOpacity = 0.55, texture = null }) => {
6680
+ const three = shapeGeometries(host);
4636
6681
  const eye = new three.Group();
4637
- const ball = new three.Mesh(new three.SphereGeometry(radius, 10, 8), new three.MeshBasicMaterial({ color }));
6682
+ const ball = new three.Mesh(new three.SphereGeometry(radius, 10, 8), new three.MeshBasicMaterial({ color: color2 }));
4638
6683
  ball.userData.eye = 1;
4639
6684
  eye.add(ball);
4640
6685
  const size = glow ?? radius * 5;
4641
6686
  if (size > 0) {
4642
- const sprite = new three.Sprite(new three.SpriteMaterial({ map: texture, color, transparent: true, blending: three.AdditiveBlending, depthWrite: false, opacity: glowOpacity }));
6687
+ const sprite = new three.Sprite(new three.SpriteMaterial({ map: texture, color: color2, transparent: true, blending: three.AdditiveBlending, depthWrite: false, opacity: glowOpacity }));
4643
6688
  sprite.scale.setScalar(size);
4644
6689
  sprite.userData.eyeGlow = 1;
4645
6690
  eye.add(sprite);
4646
6691
  }
4647
6692
  return eye;
4648
6693
  };
4649
- var isEye = (object) => object.userData.eye === 1 || object.userData.eye === true;
6694
+ var isEye = (object2) => object2.userData.eye === 1 || object2.userData.eye === true;
4650
6695
  var findEyes = (three, root) => {
4651
6696
  const markable = [];
4652
6697
  const glows = [];
4653
6698
  const base = /* @__PURE__ */ new Map();
4654
- root.traverse((object) => {
4655
- const mesh = object;
4656
- if (mesh.isMesh && isEye(object)) markable.push(mesh);
4657
- const sprite = object;
6699
+ root.traverse((object2) => {
6700
+ const mesh2 = object2;
6701
+ if (mesh2.isMesh && isEye(object2)) markable.push(mesh2);
6702
+ const sprite = object2;
4658
6703
  if (sprite.isSprite && sprite.material.blending === three.AdditiveBlending) glows.push(sprite);
4659
6704
  });
4660
6705
  const remember = (material) => {
4661
6706
  if (material.color && !base.has(material)) base.set(material, { color: material.color.clone(), opacity: material.opacity });
4662
6707
  };
4663
- markable.forEach((mesh) => remember(mesh.material));
6708
+ markable.forEach((mesh2) => remember(mesh2.material));
4664
6709
  glows.forEach((sprite) => remember(sprite.material));
4665
6710
  const setBrightness = (level) => {
4666
6711
  const factor = Math.min(1, Math.max(0, level));
@@ -4680,14 +6725,14 @@ var GameCharactersThree = (() => {
4680
6725
  on: () => setBrightness(1),
4681
6726
  isolate(only) {
4682
6727
  if (!only) {
4683
- hidden.splice(0).forEach((object) => object.visible = true);
6728
+ hidden.splice(0).forEach((object2) => object2.visible = true);
4684
6729
  return;
4685
6730
  }
4686
- root.traverse((object) => {
4687
- const mesh = object;
4688
- if (mesh.isMesh && !isEye(object) && object.visible) {
4689
- object.visible = false;
4690
- hidden.push(object);
6731
+ root.traverse((object2) => {
6732
+ const mesh2 = object2;
6733
+ if (mesh2.isMesh && !isEye(object2) && object2.visible) {
6734
+ object2.visible = false;
6735
+ hidden.push(object2);
4691
6736
  }
4692
6737
  });
4693
6738
  }
@@ -4807,9 +6852,9 @@ var GameCharactersThree = (() => {
4807
6852
  group.add(end);
4808
6853
  strands.push(end);
4809
6854
  }
4810
- group.traverse((object) => {
4811
- object.userData.stump = 1;
4812
- if (object.isMesh) object.castShadow = true;
6855
+ group.traverse((object2) => {
6856
+ object2.userData.stump = 1;
6857
+ if (object2.isMesh) object2.castShadow = true;
4813
6858
  });
4814
6859
  return strands;
4815
6860
  };
@@ -4824,15 +6869,15 @@ var GameCharactersThree = (() => {
4824
6869
  const group = new three.Group();
4825
6870
  group.position.y = y;
4826
6871
  parent.add(group);
4827
- const torus = new three.Mesh(new three.TorusGeometry(radius, 0.022, 8, 18), materials.wound);
4828
- torus.rotation.x = Math.PI / 2;
4829
- group.add(torus);
6872
+ const torus2 = new three.Mesh(new three.TorusGeometry(radius, 0.022, 8, 18), materials.wound);
6873
+ torus2.rotation.x = Math.PI / 2;
6874
+ group.add(torus2);
4830
6875
  for (let k = 0; k < 3; k++) {
4831
6876
  const strip = new three.Mesh(new three.CylinderGeometry(8e-3, 8e-3, 0.12, 6), materials.wound);
4832
6877
  strip.position.set((k - 1) * 0.03, 0.03, 0.02);
4833
6878
  group.add(strip);
4834
6879
  }
4835
- group.traverse((object) => object.userData.stump = 1);
6880
+ group.traverse((object2) => object2.userData.stump = 1);
4836
6881
  return group;
4837
6882
  };
4838
6883
 
@@ -4851,8 +6896,8 @@ var GameCharactersThree = (() => {
4851
6896
  const trim = () => {
4852
6897
  while (pieces.length > max) pieces.shift()?.object.removeFromParent();
4853
6898
  };
4854
- const add = (object, velocity, spin, tag) => {
4855
- const piece = { object, velocity, spin, rest: false, ...tag ? { tag } : {} };
6899
+ const add = (object2, velocity, spin, tag) => {
6900
+ const piece = { object: object2, velocity, spin, rest: false, ...tag ? { tag } : {} };
4856
6901
  pieces.push(piece);
4857
6902
  trim();
4858
6903
  return piece;
@@ -4929,8 +6974,8 @@ var GameCharactersThree = (() => {
4929
6974
  };
4930
6975
  var exitWound = (three, materials, random, segment, point, direction, damage) => {
4931
6976
  const meshes = [];
4932
- segment.traverse((object) => {
4933
- if (object.isMesh && !object.userData.wound && !object.userData.stump) meshes.push(object);
6977
+ segment.traverse((object2) => {
6978
+ if (object2.isMesh && !object2.userData.wound && !object2.userData.stump) meshes.push(object2);
4934
6979
  });
4935
6980
  const raycaster = new three.Raycaster(point.clone().addScaledVector(direction, 0.6), direction.clone().negate(), 0, 0.6);
4936
6981
  const hit = raycaster.intersectObjects(meshes)[0];
@@ -4975,9 +7020,9 @@ var GameCharactersThree = (() => {
4975
7020
  crater.userData.wound = 1;
4976
7021
  return crater;
4977
7022
  };
4978
- var explodeChunks = (three, materials, random, box, direction, fling) => {
4979
- const centre = box.getCenter(new three.Vector3());
4980
- const size = box.getSize(new three.Vector3()).length();
7023
+ var explodeChunks = (three, materials, random, box2, direction, fling) => {
7024
+ const centre = box2.getCenter(new three.Vector3());
7025
+ const size = box2.getSize(new three.Vector3()).length();
4981
7026
  const chunkMaterials = [materials.flesh, materials.bruise, materials.bone, materials.flesh, materials.meat];
4982
7027
  for (let i = 0; i < 14; i++) {
4983
7028
  const chunk = new three.Mesh(new three.BoxGeometry(0.015 + random() * size * 0.18, 0.015 + random() * size * 0.14, 0.015 + random() * size * 0.14), chunkMaterials[i % 5]);
@@ -5010,7 +7055,7 @@ var GameCharactersThree = (() => {
5010
7055
  };
5011
7056
 
5012
7057
  // src/wounds/wounds.ts
5013
- var worldPosition = (three, object) => object.getWorldPosition(new three.Vector3());
7058
+ var worldPosition = (three, object2) => object2.getWorldPosition(new three.Vector3());
5014
7059
  var createWounds = (three, options) => {
5015
7060
  const { random, scene: scene2, bridge, sound } = options;
5016
7061
  const materials = options.materials ?? createWoundMaterials(three);
@@ -5021,11 +7066,11 @@ var GameCharactersThree = (() => {
5021
7066
  if (!found) throw new Error("game-characters-three: this body is not tracked by the wounds (call `track` first)");
5022
7067
  return found;
5023
7068
  };
5024
- const burstBlood = (state, change, object, direction) => {
5025
- const point = worldPosition(three, object);
7069
+ const burstBlood = (state, change, object2, direction) => {
7070
+ const point = worldPosition(three, object2);
5026
7071
  bridge?.burst(change, [point.x, point.y, point.z], state.body.blood, direction ? [direction.x, direction.y, direction.z] : void 0);
5027
7072
  };
5028
- const sideOf2 = (object, body) => new three.Vector3(object.position.x >= 0 ? 1 : -1, 0, 0).applyQuaternion(body.root.quaternion);
7073
+ const sideOf2 = (object2, body) => new three.Vector3(object2.position.x >= 0 ? 1 : -1, 0, 0).applyQuaternion(body.root.quaternion);
5029
7074
  const hideBelow = (state, id) => {
5030
7075
  for (const below2 of segmentsBelow(id)) state.gone.add(below2);
5031
7076
  };
@@ -5059,8 +7104,8 @@ var GameCharactersThree = (() => {
5059
7104
  const target = state.body.nodes[id];
5060
7105
  if (!target || state.gone.has(id)) return;
5061
7106
  const { node, radius, flip } = target;
5062
- const box = new three.Box3().setFromObject(node);
5063
- explodeChunks(three, materials, random, box, direction, (chunk, velocity, spin) => {
7107
+ const box2 = new three.Box3().setFromObject(node);
7108
+ explodeChunks(three, materials, random, box2, direction, (chunk, velocity, spin) => {
5064
7109
  scene2.add(chunk);
5065
7110
  flying.throwObject(chunk, velocity, spin, id);
5066
7111
  });
@@ -5719,7 +7764,7 @@ var GameCharactersThree = (() => {
5719
7764
  batches = variants.map((variant) => createVariantBatches(three, variant, time));
5720
7765
  for (const set of batches) for (const batch of set) group.add(batch.mesh);
5721
7766
  };
5722
- const color = (hex2) => new three.Color(hex2);
7767
+ const color2 = (hex2) => new three.Color(hex2);
5723
7768
  return {
5724
7769
  group,
5725
7770
  spawn(count) {
@@ -5750,7 +7795,7 @@ var GameCharactersThree = (() => {
5750
7795
  const variant = variants[member.variant];
5751
7796
  const distance3 = Math.hypot(member.x - camera.position.x, member.z - camera.position.z);
5752
7797
  const level = lodAt(distance3, LOD_DISTANCES);
5753
- const eye = color(eyes[variant.typeId] ?? 14926657);
7798
+ const eye = color2(eyes[variant.typeId] ?? 14926657);
5754
7799
  batches[member.variant][level]?.push({ a: [member.x, member.z, member.yaw, member.phase], b: [variant.s, variant.bulk, STRIDE, pose], c: [0, 0.4, 1, member.phase], color: { r: 0.4, g: 0.45, b: 0.5 }, eye });
5755
7800
  }
5756
7801
  for (const set of batches) for (const batch of set) batch.end();
@@ -5815,6 +7860,58 @@ var GameCharactersThree = (() => {
5815
7860
  return spec;
5816
7861
  };
5817
7862
 
7863
+ // src/test-area/knock.ts
7864
+ var KNOCK_DOWN_SPEED = 2.5;
7865
+ var KNOCKED_DOWN_ANGLE = 1.35;
7866
+ var LIE_SECONDS = 1.6;
7867
+ var STAND_UP_PER_SPEED = 0.25;
7868
+ var FALL_SECONDS = 0.25;
7869
+ var RISE_SECONDS = 0.6;
7870
+ var GROUND_FRICTION = 7;
7871
+ var GRAVITY3 = 9.81;
7872
+ var CHEST = 1.1;
7873
+ var bodyMass = (height, build = 1) => 70 * (height / 1.75) ** 2 * build;
7874
+ function knockOf(blast2, feet, mass, options) {
7875
+ const hit = blastShove(blast2, { position: [feet[0], feet[1] + CHEST, feet[2]], mass }, options);
7876
+ if (!hit) return void 0;
7877
+ const [dx, dy, dz] = hit.direction;
7878
+ return { velocity: [dx * hit.speed, Math.max(0, dy * hit.speed), dz * hit.speed], airborne: dy > 0, lying: 0, lieLeft: 0, down: hit.speed >= KNOCK_DOWN_SPEED };
7879
+ }
7880
+ function stepKnock(knock, position, dt, groundAt, alive) {
7881
+ const v = knock.velocity;
7882
+ position.x += v[0] * dt;
7883
+ position.z += v[2] * dt;
7884
+ const ground = groundAt(position.x, position.z);
7885
+ if (knock.airborne || position.y > ground + 1e-4) {
7886
+ v[1] -= GRAVITY3 * dt;
7887
+ position.y += v[1] * dt;
7888
+ if (position.y <= ground) {
7889
+ position.y = ground;
7890
+ v[1] = 0;
7891
+ knock.airborne = false;
7892
+ }
7893
+ } else position.y = ground;
7894
+ const horizontal = Math.hypot(v[0], v[2]);
7895
+ if (!knock.airborne && horizontal > 0) {
7896
+ const slowed = Math.max(0, horizontal - GROUND_FRICTION * dt);
7897
+ v[0] *= slowed / horizontal;
7898
+ v[2] *= slowed / horizontal;
7899
+ }
7900
+ const moving = horizontal > 0.05 || knock.airborne;
7901
+ if (knock.down) {
7902
+ if (moving) knock.lying = Math.min(1, knock.lying + dt / FALL_SECONDS);
7903
+ else {
7904
+ knock.lying = 1;
7905
+ if (alive) {
7906
+ knock.lieLeft = knock.lieLeft > 0 ? knock.lieLeft : LIE_SECONDS + Math.hypot(v[0], v[2]) * STAND_UP_PER_SPEED;
7907
+ knock.lieLeft -= dt;
7908
+ if (knock.lieLeft <= 0) knock.down = false;
7909
+ }
7910
+ }
7911
+ } else if (knock.lying > 0) knock.lying = Math.max(0, knock.lying - dt / RISE_SECONDS);
7912
+ return !moving && !knock.down && knock.lying === 0;
7913
+ }
7914
+
5818
7915
  // src/test-area/scenarios.ts
5819
7916
  var LIMB_SEGMENTS = ["upperArmL", "forearmL", "handL", "upperArmR", "forearmR", "handR", "thighL", "shinL", "footL", "thighR", "shinR", "footR"];
5820
7917
  var BENCHMARK_BODIES = 1e3;
@@ -5892,8 +7989,8 @@ var GameCharactersThree = (() => {
5892
7989
  const colors = (decay) => {
5893
7990
  const root = deps.buildZombie(deps.typeNames()[0], decay);
5894
7991
  const seen = /* @__PURE__ */ new Set();
5895
- root.traverse((object) => {
5896
- const material = object.material;
7992
+ root.traverse((object2) => {
7993
+ const material = object2.material;
5897
7994
  if (material?.color) seen.add(material.color.getHexString());
5898
7995
  });
5899
7996
  return [...seen].sort().join(",");
@@ -6148,12 +8245,12 @@ var GameCharactersThree = (() => {
6148
8245
  return built.root;
6149
8246
  },
6150
8247
  impl: (root, id) => {
6151
- const object = root;
6152
- const made = builtOf.get(object);
8248
+ const object2 = root;
8249
+ const made = builtOf.get(object2);
6153
8250
  const character = createCharacter(made.kind, made.cardId, id);
6154
8251
  const scale = character.spec.height / kit.body.heightMetres;
6155
- if (Math.abs(scale - 1) > 0.01) object.scale.setScalar(scale);
6156
- const entry = { id, kind: made.kind, cardId: made.cardId, root: object, body: woundBodyOf(object), eyes: three ? findEyes(three, object) : null, built: made.built, character, walk: 0, tilt: 0 };
8252
+ if (Math.abs(scale - 1) > 0.01) object2.scale.setScalar(scale);
8253
+ const entry = { id, kind: made.kind, cardId: made.cardId, root: object2, body: woundBodyOf(object2), eyes: three ? findEyes(three, object2) : null, built: made.built, character, walk: 0, tilt: 0 };
6157
8254
  entry.character = wrap(entry, character);
6158
8255
  const age = made.kind === "zombie" ? undead?.traitsOf(character)?.age : void 0;
6159
8256
  const blood = age !== void 0 ? options.bloodOf?.(age) : void 0;
@@ -6171,7 +8268,7 @@ var GameCharactersThree = (() => {
6171
8268
  return undead.speedFor(traits, { moment: MOMENTS_WITH_LIMP.has(moment) ? "chase" : moment, limp: moment === "limp", crawling: moment === "crawl" || entry.character.limping.length > 1 });
6172
8269
  };
6173
8270
  const clearOverlays = () => {
6174
- for (const object of overlays.values()) object.parent?.remove(object);
8271
+ for (const object2 of overlays.values()) object2.parent?.remove(object2);
6175
8272
  overlays.clear();
6176
8273
  };
6177
8274
  const overlayFor = (layer, entry) => {
@@ -6182,16 +8279,16 @@ var GameCharactersThree = (() => {
6182
8279
  for (const part of entry.character.describe().parts) {
6183
8280
  const shape = part.shape;
6184
8281
  const geometry = shape.kind === "sphere" ? new three.SphereGeometry(shape.radius, 8, 6) : shape.kind === "cylinder" ? new three.CylinderGeometry(shape.radius, shape.radius, shape.height, 8, 1) : new three.BoxGeometry(...shape.size);
6185
- const mesh = new three.Mesh(geometry, material);
6186
- mesh.position.set(...part.position);
6187
- if (part.rotation) mesh.rotation.set(...part.rotation);
6188
- group.add(mesh);
8282
+ const mesh2 = new three.Mesh(geometry, material);
8283
+ mesh2.position.set(...part.position);
8284
+ if (part.rotation) mesh2.rotation.set(...part.rotation);
8285
+ group.add(mesh2);
6189
8286
  }
6190
8287
  } else if (layer === "joints") {
6191
8288
  for (const joint of Object.values(entry.character.rig.joints)) {
6192
- const mesh = new three.Mesh(new three.SphereGeometry(0.025, 6, 4), material);
6193
- mesh.position.set(...joint);
6194
- group.add(mesh);
8289
+ const mesh2 = new three.Mesh(new three.SphereGeometry(0.025, 6, 4), material);
8290
+ mesh2.position.set(...joint);
8291
+ group.add(mesh2);
6195
8292
  }
6196
8293
  } else if (layer === "speed") {
6197
8294
  const length = Math.max(0.1, speedOf(entry));
@@ -6218,6 +8315,17 @@ var GameCharactersThree = (() => {
6218
8315
  };
6219
8316
  const animate = (entry, dt) => {
6220
8317
  const { root, character } = entry;
8318
+ if (entry.knock) {
8319
+ const rig = root.userData.rig;
8320
+ const ground = (x, z) => host?.groundAt(x, z) ?? 0;
8321
+ const done = stepKnock(entry.knock, root.position, dt, ground, character.alive);
8322
+ if (done) entry.knock = void 0;
8323
+ if (character.alive && rig) rig.fig.rotation.x = -(entry.knock?.lying ?? 0) * KNOCKED_DOWN_ANGLE;
8324
+ if (entry.knock && entry.knock.lying > 0 && character.alive) {
8325
+ entry.eyes?.off();
8326
+ return;
8327
+ }
8328
+ }
6221
8329
  if (!character.alive) {
6222
8330
  entry.tilt = Math.min(1, entry.tilt + dt * 2);
6223
8331
  const rig = root.userData.rig;
@@ -6423,6 +8531,15 @@ var GameCharactersThree = (() => {
6423
8531
  wounds = createWounds(lent.THREE, { random, scene: scene2, groundAt: (x, z) => lent.groundAt(x, z), ...bridge ? { bridge } : {}, ...sound ? { sound } : {} });
6424
8532
  for (const entry of entries.values()) trackEntry(entry);
6425
8533
  const stopChange = lent.bench?.onChange(onChange);
8534
+ const stopEvents = lent.on((event) => {
8535
+ if (event.type !== "explosion") return;
8536
+ for (const entry of entries.values()) {
8537
+ if (!entry.root.parent) continue;
8538
+ const p2 = entry.root.position;
8539
+ const knock = knockOf(event, [p2.x, p2.y, p2.z], bodyMass(entry.character.spec.height, entry.character.spec.build), lent.blastShove);
8540
+ if (knock) entry.knock = entry.knock ? { ...knock, lying: entry.knock.lying } : knock;
8541
+ }
8542
+ });
6426
8543
  const stopFrame = lent.onFrame((dt) => {
6427
8544
  time += dt;
6428
8545
  for (const [id, entry] of entries) {
@@ -6438,6 +8555,7 @@ var GameCharactersThree = (() => {
6438
8555
  });
6439
8556
  return () => {
6440
8557
  stopChange?.();
8558
+ stopEvents();
6441
8559
  stopFrame();
6442
8560
  clearOverlays();
6443
8561
  wounds?.dispose();
@@ -6473,6 +8591,1272 @@ var GameCharactersThree = (() => {
6473
8591
  var registerBodyMaterial = (world) => {
6474
8592
  if (!world.materials.has(BODY_MATERIAL_DEF.id)) world.materials.set(BODY_MATERIAL_DEF.id, BODY_MATERIAL_DEF);
6475
8593
  };
8594
+
8595
+ // src/presets/player-avatar.json
8596
+ var player_avatar_default = {
8597
+ source: {
8598
+ file: "site/pages/jogo/zombiada-modo-livre.html",
8599
+ variable: "PB specs[0] ('voc\xEA') and PLAYER_COR",
8600
+ note: "The team game's player body: the Besti\xE1rio/Elenco human body. Overridable by `createPlayerAvatar(THREE, { spec, shirtColor })`."
8601
+ },
8602
+ spec: {
8603
+ type: "Lento",
8604
+ human: true,
8605
+ decay: 0,
8606
+ seed: 4242,
8607
+ skin: "b07a52",
8608
+ fem: false,
8609
+ life: 1,
8610
+ hs: "short",
8611
+ hair: "2a1e16"
8612
+ },
8613
+ shirtColor: "3d5a73"
8614
+ };
8615
+
8616
+ // src/player/avatar.ts
8617
+ var TWO_PI2 = Math.PI * 2;
8618
+ var MAX_GAIT = 1.4;
8619
+ var CLIP_BLEND = 0.12;
8620
+ var FALL_SECONDS2 = 0.3;
8621
+ var HIP_HEIGHT = 0.95;
8622
+ var WALK_ARM = 0.45;
8623
+ var WALK_BOB = 0.035;
8624
+ var WALK_LEAN = 0.04;
8625
+ var CROUCH = { thigh: -0.95, thighWalk: 0.3, shin: 1.9, lean: 0.25, drop: -0.35 };
8626
+ var AIMED = { shoulder: -1.42, perAim: 0.85, swing: 0.02, zRight: -0.54, zLeft: 0.36, elbowRight: -0.04, elbowLeft: -0.12 };
8627
+ var DOWN = { thighWalk: 0.5, shinSwing: 0.85, shinBend: 1.3, armHigh: -2.8, armLow: -0.35, armWave: 0.3, armZ: 0.5, armZWave: 0.3, tilt: 1.5, roll: 0.3, hipY: 0.16, hipZ: 0.6, hipZFlip: 1.2 };
8628
+ var HAND_OFFSET = { x: 0, y: -0.33, z: 0.04 };
8629
+ var hexOf = (value) => typeof value === "string" ? Number.parseInt(value, 16) : value;
8630
+ var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
8631
+ var fract = (value) => value - Math.floor(value);
8632
+ var createPlayerAvatar = (THREE, options = {}) => {
8633
+ const spec = { ...player_avatar_default.spec, ...options.spec };
8634
+ for (const key of ["skin", "hair"]) if (typeof spec[key] === "string") spec[key] = hexOf(spec[key]);
8635
+ const best = createBestBuilder(THREE, { types: [{ name: String(spec.type), eye: 0 }], random: createRng(Number(spec.seed ?? 1)) });
8636
+ const body = best.build(spec);
8637
+ best.topM().color.setHex(options.shirtColor ?? hexOf(player_avatar_default.shirtColor));
8638
+ const rig = body.userData.rig;
8639
+ const profile = { f: 1.1, a: 0.28, k: 0.35, arm: WALK_ARM, bob: WALK_BOB };
8640
+ const animator = createRigAnimator({ gaits: { [rig.type]: profile } });
8641
+ const clips = options.clips ?? createPoseClipRegistry(POSE_CLIPS);
8642
+ const blendDefault = options.blend ?? CLIP_BLEND;
8643
+ const fallSeconds = options.fallSeconds ?? FALL_SECONDS2;
8644
+ const smooth = options.cascade ?? true;
8645
+ const root = new THREE.Group();
8646
+ const tilt = new THREE.Group();
8647
+ tilt.add(body);
8648
+ root.add(tilt);
8649
+ const colorOf2 = (object2) => object2?.material?.color?.getHex();
8650
+ const meshesOf = (node) => node.children.filter((child) => child.isMesh);
8651
+ const shirt = options.shirtColor ?? hexOf(player_avatar_default.shirtColor);
8652
+ const shoe = meshesOf(rig.legs[0].kn).find((mesh2) => mesh2.scale.z > 1.5);
8653
+ const forearm = colorOf2(meshesOf(rig.arms[1].el)[0]);
8654
+ const colors = {
8655
+ skin: Number(spec.skin),
8656
+ shirt,
8657
+ trousers: colorOf2(meshesOf(rig.legs[0].g)[0]) ?? 2962496,
8658
+ shoes: colorOf2(shoe) ?? 1841690,
8659
+ longSleeves: forearm === shirt
8660
+ };
8661
+ const sockets = { R: new THREE.Object3D(), L: new THREE.Object3D() };
8662
+ const armOf = { R: rig.arms[1], L: rig.arms[0] };
8663
+ for (const side of ["R", "L"]) {
8664
+ sockets[side].name = `hand_${side}`;
8665
+ sockets[side].position.set(HAND_OFFSET.x, HAND_OFFSET.y, HAND_OFFSET.z);
8666
+ armOf[side].el.add(sockets[side]);
8667
+ }
8668
+ const legRestX = rig.legs.map((leg) => leg.g.position.x);
8669
+ const legSide = (index) => index === 0 ? 1 : -1;
8670
+ let cycles = 0;
8671
+ let time = 0;
8672
+ let fall = 0;
8673
+ let run = null;
8674
+ const listeners = /* @__PURE__ */ new Set();
8675
+ const emit = (event, onEvent) => {
8676
+ onEvent?.(event);
8677
+ for (const listener of listeners) listener(event);
8678
+ };
8679
+ const readPose = () => ({
8680
+ lean: rig.upper.rotation.x,
8681
+ twist: rig.upper.rotation.y,
8682
+ side: rig.upper.rotation.z,
8683
+ drop: rig.fig.position.y - rig.dropBase,
8684
+ headX: rig.headG.rotation.x,
8685
+ headY: rig.headG.rotation.y,
8686
+ headZ: rig.headG.rotation.z,
8687
+ armR: rig.arms[0].g.rotation.x,
8688
+ armL: rig.arms[1].g.rotation.x,
8689
+ elbR: rig.arms[0].el.rotation.x,
8690
+ elbL: rig.arms[1].el.rotation.x,
8691
+ armRz: rig.arms[0].g.rotation.z,
8692
+ armLz: rig.arms[1].g.rotation.z,
8693
+ legL: rig.legs[0].g.rotation.x,
8694
+ legR: rig.legs[1].g.rotation.x,
8695
+ kneeL: rig.legs[0].kn.rotation.x,
8696
+ kneeR: rig.legs[1].kn.rotation.x
8697
+ });
8698
+ const armed = (pitch, gait, hip) => {
8699
+ const aim = clamp((pitch + 1) / 3, 0, 0.99) * 3 - 1;
8700
+ const shoulder = AIMED.shoulder + aim * AIMED.perAim + AIMED.swing * Math.sin(cycles * TWO_PI2) * gait;
8701
+ rig.legs.forEach((leg, index) => {
8702
+ const x = legRestX[index];
8703
+ leg.g.rotation.y = hip;
8704
+ leg.g.position.x = x * Math.cos(hip);
8705
+ leg.g.position.z = -x * Math.sin(hip);
8706
+ });
8707
+ return { armR: shoulder, armL: shoulder, armRz: AIMED.zRight, armLz: AIMED.zLeft, elbR: AIMED.elbowRight, elbL: AIMED.elbowLeft };
8708
+ };
8709
+ const resetLegYaw = () => {
8710
+ rig.legs.forEach((leg, index) => {
8711
+ leg.g.rotation.y = 0;
8712
+ leg.g.position.x = legRestX[index];
8713
+ leg.g.position.z = 0;
8714
+ });
8715
+ };
8716
+ const crouchPose = (gait) => {
8717
+ const swing = (leg) => {
8718
+ const legS = legSide(leg);
8719
+ return CROUCH.thigh - Math.sin(cycles * TWO_PI2) * legS * CROUCH.thighWalk * gait;
8720
+ };
8721
+ return {
8722
+ legL: swing(0),
8723
+ legR: swing(1),
8724
+ kneeL: CROUCH.shin,
8725
+ kneeR: CROUCH.shin,
8726
+ lean: WALK_LEAN * gait + CROUCH.lean,
8727
+ drop: Math.abs(Math.sin(cycles * TWO_PI2)) * WALK_BOB * gait + CROUCH.drop
8728
+ };
8729
+ };
8730
+ const downPose = () => {
8731
+ const ph = cycles * TWO_PI2;
8732
+ const gait = 1;
8733
+ const leg = (index) => {
8734
+ const legS = legSide(index);
8735
+ const walkS = Math.sin(ph) * legS;
8736
+ const bend = fract(cycles * 3) * legS > 0.3 ? fract(cycles * 3) * DOWN.shinBend : Math.max(0, Math.cos(ph + (legS > 0 ? 0 : Math.PI))) * DOWN.shinSwing * gait;
8737
+ return { hip: -walkS * DOWN.thighWalk * gait, knee: bend };
8738
+ };
8739
+ const arm = (index) => {
8740
+ const side = index === 0 ? 1 : -1;
8741
+ const armS = Math.sin(ph) * (side > 0 ? 1 : -1);
8742
+ const shoulder = fract(cycles * 5) > 0.5 && side > 0 ? DOWN.armHigh : DOWN.armLow + DOWN.armWave * Math.sin(cycles * 5 + side);
8743
+ return { shoulder, z: side * (DOWN.armZ + DOWN.armZWave * Math.sin(cycles * 3)), elbow: -0.35 - Math.max(0, armS) * 0.4 * gait };
8744
+ };
8745
+ const [l, r] = [leg(0), leg(1)];
8746
+ const [a0, a1] = [arm(0), arm(1)];
8747
+ return {
8748
+ legL: l.hip,
8749
+ kneeL: l.knee,
8750
+ legR: r.hip,
8751
+ kneeR: r.knee,
8752
+ armR: a0.shoulder,
8753
+ armRz: a0.z,
8754
+ elbR: a0.elbow,
8755
+ armL: a1.shoulder,
8756
+ armLz: a1.z,
8757
+ elbL: a1.elbow,
8758
+ lean: WALK_LEAN * gait,
8759
+ drop: Math.abs(Math.sin(ph)) * WALK_BOB * gait
8760
+ };
8761
+ };
8762
+ const placeBody = (progress) => {
8763
+ const fk = progress * progress * (3 - 2 * progress);
8764
+ const flip = fract(cycles * 1.7) >= 0.5 ? 1 : 0;
8765
+ tilt.rotation.set((-DOWN.tilt + flip * 2 * DOWN.tilt) * fk, 0, Math.sin(cycles * 7) * DOWN.roll * fk, "XYZ");
8766
+ const hip = new THREE.Vector3(0, HIP_HEIGHT, 0);
8767
+ const target = new THREE.Vector3(0, DOWN.hipY, -DOWN.hipZ + flip * DOWN.hipZFlip);
8768
+ const place = new THREE.Vector3(0, HIP_HEIGHT * (1 - fk), 0).addScaledVector(target, fk);
8769
+ tilt.position.copy(place.sub(hip.applyEuler(tilt.rotation)));
8770
+ };
8771
+ const fireClipEvents = (r, from, to) => {
8772
+ for (const event of clipEventsBetween(r.clip, from, to)) emit({ ...event, clip: r.clip.id }, r.onEvent);
8773
+ };
8774
+ const stepClip = (dt, down) => {
8775
+ if (!run) return;
8776
+ const r = run;
8777
+ const from = r.time;
8778
+ r.time += dt;
8779
+ const { duration } = r.clip;
8780
+ if (r.clip.loop && r.time > duration) {
8781
+ fireClipEvents(r, from, duration);
8782
+ r.time -= duration * Math.floor(r.time / duration);
8783
+ fireClipEvents(r, -1e-9, r.time);
8784
+ } else {
8785
+ fireClipEvents(r, from, Math.min(r.time, duration));
8786
+ if (r.time >= duration && !r.clip.loop) r.target = 0;
8787
+ }
8788
+ r.weight = r.blend <= 0 ? r.target : clamp(r.weight + (r.target ? dt : -dt) / r.blend, 0, 1);
8789
+ if (r.target === 0 && r.weight <= 0) {
8790
+ run = null;
8791
+ return;
8792
+ }
8793
+ if (down) return;
8794
+ const sampled = filterPoseChannels(samplePoseClip(r.clip, Math.min(r.time, duration)), r.clip.channels ?? "full");
8795
+ const current = readPose();
8796
+ const blended = {};
8797
+ for (const [name, value] of Object.entries(sampled)) if (name in current) blended[name] = current[name] + (value - current[name]) * r.weight;
8798
+ animator.setPose(rig, blended);
8799
+ };
8800
+ return {
8801
+ root,
8802
+ rig,
8803
+ colors,
8804
+ three: THREE,
8805
+ get playing() {
8806
+ return run ? run.clip.id : null;
8807
+ },
8808
+ update(dt, state = {}) {
8809
+ const speed = state.speed ?? 0;
8810
+ const moving = speed >= 0.05;
8811
+ if (moving) cycles += dt * walkCadence(speed);
8812
+ const gait = Math.min(MAX_GAIT, walkGait(speed));
8813
+ profile.arm = WALK_ARM * gait;
8814
+ profile.bob = WALK_BOB * gait;
8815
+ time = cycles / walkCadence(Math.max(speed, 0));
8816
+ animator.animate(body, time, { speed });
8817
+ const down = !!state.down;
8818
+ fall = fallSeconds <= 0 ? down ? 1 : 0 : clamp(fall + (down ? dt : -dt) / fallSeconds, 0, 1);
8819
+ resetLegYaw();
8820
+ if (down) animator.setPose(rig, downPose());
8821
+ else {
8822
+ if (state.crouch) animator.setPose(rig, crouchPose(gait));
8823
+ if (state.armed) animator.setPose(rig, armed(state.pitch ?? 0, gait, state.hip ?? 0));
8824
+ }
8825
+ placeBody(fall);
8826
+ stepClip(dt, down);
8827
+ if (smooth) animator.cascade(rig, dt);
8828
+ },
8829
+ play(clip, playOptions = {}) {
8830
+ const found = typeof clip === "string" ? clips.get(clip) : clip;
8831
+ if (!found) throw new Error(`Unknown pose clip: ${String(clip)}`);
8832
+ run = { clip: found, time: 0, weight: run?.weight ?? 0, target: 1, blend: playOptions.blend ?? blendDefault, ...playOptions.onEvent ? { onEvent: playOptions.onEvent } : {} };
8833
+ fireClipEvents(run, -1e-9, 0);
8834
+ run.time = 0;
8835
+ },
8836
+ stop() {
8837
+ if (run) run.target = 0;
8838
+ },
8839
+ hand: (side) => sockets[side],
8840
+ on(_type, listener) {
8841
+ listeners.add(listener);
8842
+ return () => void listeners.delete(listener);
8843
+ },
8844
+ dispose() {
8845
+ run = null;
8846
+ listeners.clear();
8847
+ body.traverse((object2) => {
8848
+ const mesh2 = object2;
8849
+ mesh2.geometry?.dispose();
8850
+ const material = mesh2.material;
8851
+ if (Array.isArray(material)) material.forEach((m) => m.dispose());
8852
+ else material?.dispose();
8853
+ });
8854
+ root.removeFromParent();
8855
+ }
8856
+ };
8857
+ };
8858
+
8859
+ // ../game-characters-people/dist/index.js
8860
+ var attack_clips_default = {
8861
+ clips: [
8862
+ {
8863
+ id: "punch_right",
8864
+ source: { authored: "game-kit", note: "authored in the kit; replace with the Elenco team's clip when delivered" },
8865
+ duration: 0.35,
8866
+ loop: false,
8867
+ channels: "upper",
8868
+ keys: [
8869
+ { t: 0, pose: { lean: 0, twist: 0, side: 0, headX: 0, headY: 0, headZ: 0, armR: 0.05, armL: -0.1, elbR: -0.2, elbL: -0.2, armRz: 0, armLz: 0 } },
8870
+ { t: 0.1, pose: { lean: 0.04, twist: -0.35, side: 0, headX: 0, headY: 0.28, headZ: 0, armR: 0.45, armL: -0.7, elbR: -1.9, elbL: -1.6, armRz: 0, armLz: 0.1 } },
8871
+ { t: 0.16, pose: { lean: 0.2, twist: 0.5, side: 0, headX: 0, headY: -0.38, headZ: 0, armR: -1.5, armL: -0.6, elbR: -0.1, elbL: -1.7, armRz: -0.1, armLz: 0.1 } },
8872
+ { t: 0.22, pose: { lean: 0.16, twist: 0.4, side: 0, headX: 0, headY: -0.3, headZ: 0, armR: -1.35, armL: -0.6, elbR: -0.25, elbL: -1.6, armRz: -0.08, armLz: 0.08 } },
8873
+ { t: 0.35, pose: { lean: 0, twist: 0, side: 0, headX: 0, headY: 0, headZ: 0, armR: 0.05, armL: -0.1, elbR: -0.2, elbL: -0.2, armRz: 0, armLz: 0 } }
8874
+ ],
8875
+ events: [
8876
+ { t: 0, type: "phase", data: { label: "attack_clip.phase.windup" } },
8877
+ { t: 0.1, type: "phase", data: { label: "attack_clip.phase.strike" } },
8878
+ { t: 0.16, type: "impact", data: { kind: "punch" } },
8879
+ { t: 0.22, type: "phase", data: { label: "attack_clip.phase.recover" } }
8880
+ ]
8881
+ },
8882
+ {
8883
+ id: "shove_two_hands",
8884
+ source: { authored: "game-kit", note: "authored in the kit; replace with the Elenco team's clip when delivered" },
8885
+ duration: 0.5,
8886
+ loop: false,
8887
+ channels: "upper",
8888
+ keys: [
8889
+ { t: 0, pose: { lean: 0, twist: 0, side: 0, headX: 0, headY: 0, headZ: 0, armR: 0.05, armL: -0.1, elbR: -0.2, elbL: -0.2, armRz: 0, armLz: 0 } },
8890
+ { t: 0.15, pose: { lean: -0.08, twist: 0, side: 0, headX: -0.05, headY: 0, headZ: 0, armR: -0.9, armL: -0.9, elbR: -1.9, elbL: -1.9, armRz: -0.12, armLz: 0.12 } },
8891
+ { t: 0.26, pose: { lean: 0.3, twist: 0, side: 0, headX: 0.06, headY: 0, headZ: 0, armR: -1.5, armL: -1.5, elbR: -0.12, elbL: -0.12, armRz: -0.08, armLz: 0.08 } },
8892
+ { t: 0.34, pose: { lean: 0.26, twist: 0, side: 0, headX: 0.05, headY: 0, headZ: 0, armR: -1.4, armL: -1.4, elbR: -0.2, elbL: -0.2, armRz: -0.06, armLz: 0.06 } },
8893
+ { t: 0.5, pose: { lean: 0, twist: 0, side: 0, headX: 0, headY: 0, headZ: 0, armR: 0.05, armL: -0.1, elbR: -0.2, elbL: -0.2, armRz: 0, armLz: 0 } }
8894
+ ],
8895
+ events: [
8896
+ { t: 0, type: "phase", data: { label: "attack_clip.phase.windup" } },
8897
+ { t: 0.15, type: "phase", data: { label: "attack_clip.phase.strike" } },
8898
+ { t: 0.26, type: "impact", data: { kind: "shove" } },
8899
+ { t: 0.34, type: "phase", data: { label: "attack_clip.phase.recover" } }
8900
+ ]
8901
+ },
8902
+ {
8903
+ id: "front_kick",
8904
+ source: { authored: "game-kit", note: "authored in the kit; replace with the Elenco team's clip when delivered" },
8905
+ duration: 0.6,
8906
+ loop: false,
8907
+ channels: "full",
8908
+ keys: [
8909
+ { t: 0, pose: { lean: 0, twist: 0, side: 0, drop: 0, headX: 0, headY: 0, headZ: 0, armR: 0.05, armL: -0.1, elbR: -0.2, elbL: -0.2, armRz: 0, armLz: 0, legL: -0.05, legR: 0.05, kneeL: 0.05, kneeR: 0.05 } },
8910
+ { t: 0.18, pose: { lean: -0.1, twist: 0, side: 0.04, drop: -0.05, headX: 0.05, headY: 0, headZ: 0, armR: -0.5, armL: 0.4, elbR: -0.5, elbL: -0.4, armRz: -0.1, armLz: 0.1, legL: 0.1, legR: -1.1, kneeL: 0.35, kneeR: 1.8 } },
8911
+ { t: 0.32, pose: { lean: -0.22, twist: 0, side: 0.04, drop: -0.06, headX: 0.1, headY: 0, headZ: 0, armR: -0.7, armL: 0.7, elbR: -0.6, elbL: -0.3, armRz: -0.15, armLz: 0.15, legL: 0.12, legR: -1.45, kneeL: 0.2, kneeR: 0.1 } },
8912
+ { t: 0.42, pose: { lean: -0.18, twist: 0, side: 0.03, drop: -0.05, headX: 0.08, headY: 0, headZ: 0, armR: -0.5, armL: 0.5, elbR: -0.5, elbL: -0.3, armRz: -0.1, armLz: 0.1, legL: 0.1, legR: -1.2, kneeL: 0.3, kneeR: 1.2 } },
8913
+ { t: 0.6, pose: { lean: 0, twist: 0, side: 0, drop: 0, headX: 0, headY: 0, headZ: 0, armR: 0.05, armL: -0.1, elbR: -0.2, elbL: -0.2, armRz: 0, armLz: 0, legL: -0.05, legR: 0.05, kneeL: 0.05, kneeR: 0.05 } }
8914
+ ],
8915
+ events: [
8916
+ { t: 0, type: "phase", data: { label: "attack_clip.phase.windup" } },
8917
+ { t: 0.18, type: "phase", data: { label: "attack_clip.phase.strike" } },
8918
+ { t: 0.32, type: "impact", data: { kind: "kick" } },
8919
+ { t: 0.42, type: "phase", data: { label: "attack_clip.phase.recover" } }
8920
+ ]
8921
+ },
8922
+ {
8923
+ id: "recoil_rifle",
8924
+ source: { authored: "game-kit", note: "authored in the kit; replace with the Elenco team's clip when delivered. Starts and ends at the armed pose of createPlayerAvatar at pitch 0" },
8925
+ duration: 0.22,
8926
+ loop: false,
8927
+ channels: "upper",
8928
+ keys: [
8929
+ { t: 0, pose: { lean: 0, twist: 0, headX: 0, armR: -1.42, armL: -1.42, elbR: -0.04, elbL: -0.12, armRz: -0.54, armLz: 0.36 } },
8930
+ { t: 0.04, pose: { lean: -0.1, twist: 0.03, headX: -0.06, armR: -1.62, armL: -1.62, elbR: -0.35, elbL: -0.45, armRz: -0.5, armLz: 0.34 } },
8931
+ { t: 0.22, pose: { lean: 0, twist: 0, headX: 0, armR: -1.42, armL: -1.42, elbR: -0.04, elbL: -0.12, armRz: -0.54, armLz: 0.36 } }
8932
+ ],
8933
+ events: [
8934
+ { t: 0, type: "impact", data: { kind: "shot" } },
8935
+ { t: 0, type: "phase", data: { label: "attack_clip.phase.strike" } },
8936
+ { t: 0.08, type: "phase", data: { label: "attack_clip.phase.recover" } }
8937
+ ]
8938
+ },
8939
+ {
8940
+ id: "recoil_pistol",
8941
+ source: { authored: "game-kit", note: "authored in the kit; replace with the Elenco team's clip when delivered. Starts and ends at the armed pose of createPlayerAvatar at pitch 0" },
8942
+ duration: 0.18,
8943
+ loop: false,
8944
+ channels: "upper",
8945
+ keys: [
8946
+ { t: 0, pose: { lean: 0, twist: 0, headX: 0, armR: -1.42, armL: -1.42, elbR: -0.04, elbL: -0.12, armRz: -0.54, armLz: 0.36 } },
8947
+ { t: 0.03, pose: { lean: -0.05, twist: 0.02, headX: -0.03, armR: -1.58, armL: -1.52, elbR: -0.22, elbL: -0.25, armRz: -0.52, armLz: 0.35 } },
8948
+ { t: 0.18, pose: { lean: 0, twist: 0, headX: 0, armR: -1.42, armL: -1.42, elbR: -0.04, elbL: -0.12, armRz: -0.54, armLz: 0.36 } }
8949
+ ],
8950
+ events: [
8951
+ { t: 0, type: "impact", data: { kind: "shot" } },
8952
+ { t: 0, type: "phase", data: { label: "attack_clip.phase.strike" } },
8953
+ { t: 0.06, type: "phase", data: { label: "attack_clip.phase.recover" } }
8954
+ ]
8955
+ }
8956
+ ],
8957
+ locales: {
8958
+ "pt-BR": {
8959
+ "attack_clip.phase.windup": "Prepara\xE7\xE3o",
8960
+ "attack_clip.phase.strike": "Golpe",
8961
+ "attack_clip.phase.recover": "Recupera\xE7\xE3o"
8962
+ },
8963
+ en: {
8964
+ "attack_clip.phase.windup": "Wind-up",
8965
+ "attack_clip.phase.strike": "Strike",
8966
+ "attack_clip.phase.recover": "Recover"
8967
+ }
8968
+ }
8969
+ };
8970
+ var first_person_clips_default = {
8971
+ clips: [
8972
+ {
8973
+ id: "punch_right",
8974
+ source: { authored: "game-kit", note: "first-person counterpart of attack-clips.json (same duration, same events); authored in the kit, replace with the Elenco team's clips when delivered" },
8975
+ duration: 0.35,
8976
+ keys: [
8977
+ { t: 0, R: { p: [0.15, -0.12, -0.4], r: [0, 1.5, 0.15], grip: 1, w: 0 } },
8978
+ { t: 0.1, R: { p: [0.21, -0.15, -0.29], r: [0.1, 1.45, 0.2], grip: 1 } },
8979
+ { t: 0.16, R: { p: [0.06, -0.09, -0.62], r: [0, 1.5708, -0.05], grip: 1 } },
8980
+ { t: 0.22, R: { p: [0.07, -0.1, -0.56], r: [0, 1.5708, -0.05], grip: 1 } },
8981
+ { t: 0.35, R: { p: [0.15, -0.12, -0.4], r: [0, 1.5, 0.15], grip: 1, w: 0 } }
8982
+ ],
8983
+ events: [
8984
+ { t: 0, type: "phase", data: { label: "attack_clip.phase.windup" } },
8985
+ { t: 0.1, type: "phase", data: { label: "attack_clip.phase.strike" } },
8986
+ { t: 0.16, type: "impact", data: { kind: "punch" } },
8987
+ { t: 0.22, type: "phase", data: { label: "attack_clip.phase.recover" } }
8988
+ ]
8989
+ },
8990
+ {
8991
+ id: "shove_two_hands",
8992
+ source: { authored: "game-kit", note: "first-person counterpart of attack-clips.json (same duration, same events); authored in the kit, replace with the Elenco team's clips when delivered" },
8993
+ duration: 0.5,
8994
+ keys: [
8995
+ { t: 0, R: { p: [0.17, -0.14, -0.36], r: [0, 1.5708, 1.4], grip: 0.05, w: 0 }, L: "mirror" },
8996
+ { t: 0.15, R: { p: [0.15, -0.09, -0.27], r: [0, 1.5708, 1.5], grip: 0.05 }, L: "mirror" },
8997
+ { t: 0.26, R: { p: [0.11, -0.02, -0.58], r: [0, 1.5708, 1.75], grip: 0.05 }, L: "mirror" },
8998
+ { t: 0.34, R: { p: [0.12, -0.03, -0.54], r: [0, 1.5708, 1.65], grip: 0.05 }, L: "mirror" },
8999
+ { t: 0.5, R: { p: [0.17, -0.14, -0.36], r: [0, 1.5708, 1.4], grip: 0.05, w: 0 }, L: "mirror" }
9000
+ ],
9001
+ events: [
9002
+ { t: 0, type: "phase", data: { label: "attack_clip.phase.windup" } },
9003
+ { t: 0.15, type: "phase", data: { label: "attack_clip.phase.strike" } },
9004
+ { t: 0.26, type: "impact", data: { kind: "shove" } },
9005
+ { t: 0.34, type: "phase", data: { label: "attack_clip.phase.recover" } }
9006
+ ]
9007
+ },
9008
+ {
9009
+ id: "front_kick",
9010
+ source: { authored: "game-kit", note: "first-person counterpart of attack-clips.json (same duration, same events); authored in the kit, replace with the Elenco team's clips when delivered" },
9011
+ duration: 0.6,
9012
+ keys: [
9013
+ { t: 0, F: { p: [0.13, -0.85, -0.05], r: [0, 1.5708, 0], w: 0 } },
9014
+ { t: 0.18, F: { p: [0.18, -0.58, -0.3], r: [0, 1.5708, 0.6] } },
9015
+ { t: 0.32, F: { p: [0.12, -0.24, -0.65], r: [0, 1.5708, 0.35] } },
9016
+ { t: 0.42, F: { p: [0.12, -0.3, -0.58], r: [0, 1.5708, 0.3] } },
9017
+ { t: 0.6, F: { p: [0.13, -0.85, -0.05], r: [0, 1.5708, 0], w: 0 } }
9018
+ ],
9019
+ events: [
9020
+ { t: 0, type: "phase", data: { label: "attack_clip.phase.windup" } },
9021
+ { t: 0.18, type: "phase", data: { label: "attack_clip.phase.strike" } },
9022
+ { t: 0.32, type: "impact", data: { kind: "kick" } },
9023
+ { t: 0.42, type: "phase", data: { label: "attack_clip.phase.recover" } }
9024
+ ]
9025
+ }
9026
+ ]
9027
+ };
9028
+ var names_default = {
9029
+ sources: {
9030
+ file: "specs/001-migracao-entregas-dos-times/sources/sobreviventes__os-vivos-do-vale.js (site/pages/sobreviventes/os-vivos-do-vale.html)",
9031
+ pools: "NM (lines 610-611): m, f, s, bm, bf",
9032
+ kinship: "RELW (line 612)"
9033
+ },
9034
+ "pt-BR": {
9035
+ male: [
9036
+ "Jo\xE3o",
9037
+ "Paulo",
9038
+ "Marcos",
9039
+ "Andr\xE9",
9040
+ "Rafael",
9041
+ "Thiago",
9042
+ "Bruno",
9043
+ "Luiz",
9044
+ "S\xE9rgio",
9045
+ "Wagner",
9046
+ "C\xEDcero",
9047
+ "Edson",
9048
+ "Igor",
9049
+ "Mateus",
9050
+ "Renan",
9051
+ "Hugo"
9052
+ ],
9053
+ female: [
9054
+ "Ana",
9055
+ "Patr\xEDcia",
9056
+ "Juliana",
9057
+ "Camila",
9058
+ "Sandra",
9059
+ "Luana",
9060
+ "M\xE1rcia",
9061
+ "Fernanda",
9062
+ "Aline",
9063
+ "Rita",
9064
+ "Jaqueline",
9065
+ "Simone",
9066
+ "Larissa",
9067
+ "Bruna",
9068
+ "Tereza",
9069
+ "Vanessa"
9070
+ ],
9071
+ surnames: [
9072
+ "Silva",
9073
+ "Santos",
9074
+ "Oliveira",
9075
+ "Souza",
9076
+ "Pereira",
9077
+ "Lima",
9078
+ "Carvalho",
9079
+ "Gomes",
9080
+ "Ribeiro",
9081
+ "Martins",
9082
+ "Rocha",
9083
+ "Almeida",
9084
+ "Barbosa",
9085
+ "Teixeira",
9086
+ "Moraes",
9087
+ "Cunha"
9088
+ ],
9089
+ babyMale: [
9090
+ "Davi",
9091
+ "Miguel",
9092
+ "Gael",
9093
+ "Bento",
9094
+ "Noah",
9095
+ "Theo"
9096
+ ],
9097
+ babyFemale: [
9098
+ "Esperan\xE7a",
9099
+ "Aurora",
9100
+ "Cec\xEDlia",
9101
+ "Luna",
9102
+ "Maria Luz",
9103
+ "Alice"
9104
+ ],
9105
+ kinship: {
9106
+ male: [
9107
+ "irm\xE3o",
9108
+ "primo",
9109
+ "ex-aluno",
9110
+ "vizinho",
9111
+ "colega de trabalho",
9112
+ "afilhado",
9113
+ "filho"
9114
+ ],
9115
+ female: [
9116
+ "irm\xE3",
9117
+ "prima",
9118
+ "ex-aluna",
9119
+ "vizinha",
9120
+ "colega de trabalho",
9121
+ "afilhada",
9122
+ "filha"
9123
+ ]
9124
+ }
9125
+ }
9126
+ };
9127
+ var ATTACK_CLIPS = attack_clips_default.clips;
9128
+ var ATTACK_CLIP_LOCALES = attack_clips_default.locales;
9129
+ var FIRST_PERSON_CLIPS = first_person_clips_default.clips;
9130
+ var NAME_POOLS = { "pt-BR": names_default["pt-BR"] };
9131
+
9132
+ // src/presets/first-person-arms.json
9133
+ var first_person_arms_default = {
9134
+ source: {
9135
+ note: "Authored in the kit: no team delivered first-person arms. The rig is in metres in the camera's space (x right, y up, the view looks down -z); rest poses use the hand frame of HandPose in game-contracts, Euler [roll, yaw, pitch] in the order YZX (yaw pi/2 points the fingers forward)."
9136
+ },
9137
+ rig: {
9138
+ shoulder: [0.16, -0.36, 0.18],
9139
+ upper: 0.32,
9140
+ fore: 0.3,
9141
+ reachShift: 0.35,
9142
+ wrist: 0.07,
9143
+ elbowPole: [0.45, -1, 0.2],
9144
+ shoulderLeft: [-0.07, -0.46, 0.18],
9145
+ elbowPoleLeft: [-0.1, -1, 0.2],
9146
+ radius: { shoulder: 0.04, elbow: 0.034, wrist: 0.028, cuff: 0.031 },
9147
+ hip: [0.12, -0.82, 0.04],
9148
+ thigh: 0.46,
9149
+ shin: 0.46,
9150
+ kneePole: [0.1, 0.5, -1],
9151
+ foot: { p: [0.13, -0.85, -0.05], r: [0, 1.5708, 0] }
9152
+ },
9153
+ stances: {
9154
+ relaxed: {
9155
+ R: { p: [0.2, -0.2, -0.36], r: [0.2, 1.45, -0.4], grip: 0.35 },
9156
+ L: "mirror"
9157
+ },
9158
+ fists: {
9159
+ R: { p: [0.15, -0.12, -0.4], r: [0, 1.5, 0.15], grip: 1 },
9160
+ L: "mirror"
9161
+ },
9162
+ hold: { follow: true, fallback: "relaxed" }
9163
+ },
9164
+ bob: { frequency: 2.3, x: 6e-3, y: 8e-3, run: 1.5, fullSpeed: 4, crouch: 0.02 }
9165
+ };
9166
+
9167
+ // src/first-person/hand.ts
9168
+ var FINGERS = [
9169
+ { z: -0.03, lengths: [0.034, 0.024, 0.02], width: 0.016 },
9170
+ { z: -0.0105, lengths: [0.038, 0.027, 0.022], width: 0.0165 },
9171
+ { z: 9e-3, lengths: [0.035, 0.025, 0.02], width: 0.0155 },
9172
+ { z: 0.027, lengths: [0.029, 0.02, 0.018], width: 0.0135 }
9173
+ ];
9174
+ var PALM = { length: 0.09, thick: 0.026, width: 0.09, wristWidth: 0.066 };
9175
+ var FINGER_THICK = 0.0135;
9176
+ var CURL = { near: 1.05, mid: 1.25, far: 0.85, spread: 0.06 };
9177
+ var THUMB = { base: [5e-3, -6e-3, -0.044], near: 0.034, far: 0.028, width: 0.019 };
9178
+ var createHandMesh = (THREE, skin, wristSkin = skin) => {
9179
+ const root = new THREE.Group();
9180
+ root.name = "first-person-hand";
9181
+ const geometries = [];
9182
+ const box2 = (parent, sx, sy, sz, x, y, z, material = skin) => {
9183
+ const geometry = new THREE.BoxGeometry(sx, sy, sz);
9184
+ geometries.push(geometry);
9185
+ const mesh2 = new THREE.Mesh(geometry, material);
9186
+ mesh2.position.set(x, y, z);
9187
+ mesh2.frustumCulled = false;
9188
+ parent.add(mesh2);
9189
+ return mesh2;
9190
+ };
9191
+ const palmGeometry = new THREE.BoxGeometry(PALM.length, PALM.thick, PALM.width);
9192
+ const palmPosition = palmGeometry.getAttribute("position");
9193
+ for (let i = 0; i < palmPosition.count; i++) {
9194
+ if (palmPosition.getX(i) < 0) palmPosition.setZ(i, palmPosition.getZ(i) * PALM.wristWidth / PALM.width);
9195
+ }
9196
+ palmGeometry.computeVertexNormals();
9197
+ geometries.push(palmGeometry);
9198
+ const palm = new THREE.Mesh(palmGeometry, skin);
9199
+ palm.frustumCulled = false;
9200
+ root.add(palm);
9201
+ const wristGeometry = new THREE.CylinderGeometry(0.03, 0.033, 0.05, 8);
9202
+ wristGeometry.rotateZ(Math.PI / 2);
9203
+ geometries.push(wristGeometry);
9204
+ const wrist = new THREE.Mesh(wristGeometry, wristSkin);
9205
+ wrist.position.set(-PALM.length / 2 - 0.018, 0, 0);
9206
+ wrist.frustumCulled = false;
9207
+ root.add(wrist);
9208
+ const joints = [];
9209
+ FINGERS.forEach((finger, index) => {
9210
+ const segments = [];
9211
+ let parent = root;
9212
+ let at = PALM.length / 2;
9213
+ finger.lengths.forEach((length, k) => {
9214
+ const group = new THREE.Group();
9215
+ group.position.set(at, k === 0 ? 2e-3 : 0, k === 0 ? finger.z : 0);
9216
+ const taper = 1 - k * 0.07;
9217
+ box2(group, length, FINGER_THICK * taper, finger.width * taper, length / 2, 0, 0);
9218
+ parent.add(group);
9219
+ segments.push(group);
9220
+ parent = group;
9221
+ at = length;
9222
+ });
9223
+ joints.push({ segments, weight: 1 + index * (CURL.spread / CURL.near) });
9224
+ });
9225
+ const thumbNear = new THREE.Group();
9226
+ thumbNear.rotation.order = "YZX";
9227
+ thumbNear.position.set(...THUMB.base);
9228
+ box2(thumbNear, THUMB.near, FINGER_THICK * 1.1, THUMB.width, THUMB.near / 2, 0, 0);
9229
+ const thumbFar = new THREE.Group();
9230
+ thumbFar.position.set(THUMB.near, 0, 0);
9231
+ box2(thumbFar, THUMB.far, FINGER_THICK, THUMB.width * 0.9, THUMB.far / 2, 0, 0);
9232
+ thumbNear.add(thumbFar);
9233
+ root.add(thumbNear);
9234
+ let lastGrip = 0;
9235
+ let indexCurl;
9236
+ const curl = [CURL.near, CURL.mid, CURL.far];
9237
+ const applyIndex = () => {
9238
+ const finger = joints[0];
9239
+ if (!finger) return;
9240
+ const k = indexCurl === void 0 ? lastGrip : Math.min(1, Math.max(0, indexCurl));
9241
+ finger.segments.forEach((segment, i) => segment.rotation.z = -curl[i] * k * finger.weight);
9242
+ };
9243
+ const setGrip = (grip) => {
9244
+ const k = Math.min(1, Math.max(0, grip));
9245
+ lastGrip = k;
9246
+ for (const joint of joints) joint.segments.forEach((segment, i) => segment.rotation.z = -curl[i] * k * joint.weight);
9247
+ thumbNear.rotation.set(0, 0.55 - 1.45 * k, -0.1 - 0.75 * k);
9248
+ thumbFar.rotation.z = -0.1 - 0.7 * k;
9249
+ applyIndex();
9250
+ };
9251
+ const setIndex = (value) => {
9252
+ indexCurl = value;
9253
+ applyIndex();
9254
+ };
9255
+ setGrip(0);
9256
+ return {
9257
+ root,
9258
+ setGrip,
9259
+ setIndex,
9260
+ dispose() {
9261
+ for (const geometry of geometries) geometry.dispose();
9262
+ }
9263
+ };
9264
+ };
9265
+
9266
+ // src/first-person/ik.ts
9267
+ var solveTwoBone = (root, target, upper, lower, pole, out) => {
9268
+ const line = out.line.copy(target).sub(root);
9269
+ let distance3 = line.length();
9270
+ if (distance3 < 1e-6) line.set(0, 0, -1);
9271
+ else line.divideScalar(distance3);
9272
+ const min = Math.abs(upper - lower) + 1e-4;
9273
+ const max = upper + lower - 1e-4;
9274
+ out.clamped = distance3 > max || distance3 < min;
9275
+ distance3 = Math.min(max, Math.max(min, distance3));
9276
+ const along = (distance3 * distance3 + upper * upper - lower * lower) / (2 * distance3);
9277
+ const across = Math.sqrt(Math.max(0, upper * upper - along * along));
9278
+ const side = out.side.copy(pole);
9279
+ side.addScaledVector(line, -side.dot(line));
9280
+ if (side.lengthSq() < 1e-8) side.set(0, 1, 0).addScaledVector(line, -line.y);
9281
+ if (side.lengthSq() < 1e-8) side.set(1, 0, 0);
9282
+ side.normalize();
9283
+ out.joint.copy(root).addScaledVector(line, along).addScaledVector(side, across);
9284
+ out.end.copy(root).addScaledVector(line, distance3);
9285
+ return out;
9286
+ };
9287
+ var createTwoBone = (THREE) => ({ joint: new THREE.Vector3(), end: new THREE.Vector3(), clamped: false, line: new THREE.Vector3(), side: new THREE.Vector3() });
9288
+
9289
+ // src/first-person/arms.ts
9290
+ var DEFAULT_BLEND = 0.18;
9291
+ var ELBOW_SEGMENTS = 8;
9292
+ var REACH_SLACK = 0.97;
9293
+ var CONTACT_PROBE = 1.4;
9294
+ var CONTACT_MIN = 0.12;
9295
+ var CONTACT_MARGIN = 5e-3;
9296
+ var CONTACT_PALM = 0.03;
9297
+ var FOOT_LENGTH = 0.24;
9298
+ var FOOT_SHOWN = 1e-3;
9299
+ var FILL = 0.3;
9300
+ var FIRST_PERSON_STANCES = first_person_arms_default.stances;
9301
+ var FIRST_PERSON_RIG = first_person_arms_default.rig;
9302
+ var FIRST_PERSON_BOB = first_person_arms_default.bob;
9303
+ var hexOf2 = (value) => typeof value === "string" ? Number.parseInt(value, 16) : value;
9304
+ var scaleHex = (hex2, factor) => {
9305
+ const channel = (shift) => Math.round((hex2 >> shift & 255) * factor);
9306
+ return channel(16) << 16 | channel(8) << 8 | channel(0);
9307
+ };
9308
+ var mix2 = (a, b, k) => a + (b - a) * k;
9309
+ var ease2 = (k) => k * k * (3 - 2 * k);
9310
+ var FIRST_PERSON_COLORS = {
9311
+ skin: hexOf2(player_avatar_default.spec.skin),
9312
+ sleeve: hexOf2(player_avatar_default.shirtColor),
9313
+ cuff: scaleHex(hexOf2(player_avatar_default.shirtColor), 0.72),
9314
+ trouser: 2962496,
9315
+ shoe: 1841690
9316
+ };
9317
+ var newPose = (THREE) => ({ p: new THREE.Vector3(), q: new THREE.Quaternion(), grip: 0, scale: 1 });
9318
+ var copyPose = (to, from) => {
9319
+ to.p.copy(from.p);
9320
+ to.q.copy(from.q);
9321
+ to.grip = from.grip;
9322
+ to.scale = from.scale;
9323
+ return to;
9324
+ };
9325
+ var mixPose = (THREE, out, a, b, k) => {
9326
+ out.p.lerpVectors(a.p, b.p, k);
9327
+ out.q.copy(a.q).slerp(b.q, k);
9328
+ out.grip = mix2(a.grip, b.grip, k);
9329
+ out.scale = mix2(a.scale, b.scale, k);
9330
+ return out;
9331
+ };
9332
+ var mirrorRotation = (THREE, q) => {
9333
+ const m = new THREE.Matrix4().makeRotationFromQuaternion(q);
9334
+ const e = m.elements;
9335
+ for (const [i, j] of [[0, 1], [0, 2], [1, 0], [2, 0]]) e[j * 4 + i] = -e[j * 4 + i];
9336
+ return new THREE.Quaternion().setFromRotationMatrix(m);
9337
+ };
9338
+ var mirrorQuaternion = (THREE, q) => {
9339
+ const m = new THREE.Matrix4().makeRotationFromQuaternion(q);
9340
+ const e = m.elements;
9341
+ for (let column = 0; column < 3; column++) e[column * 4] = -e[column * 4];
9342
+ for (let row = 0; row < 3; row++) e[8 + row] = -e[8 + row];
9343
+ return new THREE.Quaternion().setFromRotationMatrix(m);
9344
+ };
9345
+ function createFirstPersonArms(THREE, options = {}) {
9346
+ const colors = { ...FIRST_PERSON_COLORS, ...options.colors };
9347
+ const rig = {
9348
+ ...FIRST_PERSON_RIG,
9349
+ ...options.rig,
9350
+ radius: { ...FIRST_PERSON_RIG.radius, ...options.rig?.radius },
9351
+ foot: options.rig?.foot ?? FIRST_PERSON_RIG.foot
9352
+ };
9353
+ const stances = { ...FIRST_PERSON_STANCES, ...options.stances };
9354
+ const bob = { ...FIRST_PERSON_BOB, ...options.bob };
9355
+ const blendSeconds = options.blend ?? DEFAULT_BLEND;
9356
+ const clips = new Map((options.clips ?? []).map((clip) => [clip.id, clip]));
9357
+ const root = new THREE.Group();
9358
+ root.name = "first-person-arms";
9359
+ root.userData.viewmodel = true;
9360
+ const lit = (color2) => new THREE.MeshLambertMaterial({ color: color2, emissive: scaleHex(color2, FILL) });
9361
+ const materials = {
9362
+ skin: lit(colors.skin),
9363
+ sleeve: lit(colors.sleeve),
9364
+ cuff: lit(colors.cuff),
9365
+ trouser: lit(colors.trouser),
9366
+ shoe: lit(colors.shoe),
9367
+ sole: lit(scaleHex(colors.shoe, 0.55))
9368
+ };
9369
+ const geometries = [];
9370
+ const Y = new THREE.Vector3(0, 1, 0);
9371
+ const limb2 = (parent, wide, narrow, length, material) => {
9372
+ const geometry = new THREE.CylinderGeometry(narrow, wide, length, 8, 1);
9373
+ geometry.translate(0, length / 2, 0);
9374
+ geometries.push(geometry);
9375
+ const mesh2 = new THREE.Mesh(geometry, material);
9376
+ mesh2.frustumCulled = false;
9377
+ mesh2.userData.length = length;
9378
+ parent.add(mesh2);
9379
+ return mesh2;
9380
+ };
9381
+ const ball = (parent, radius, material) => {
9382
+ const geometry = new THREE.SphereGeometry(radius, ELBOW_SEGMENTS, 6);
9383
+ geometries.push(geometry);
9384
+ const mesh2 = new THREE.Mesh(geometry, material);
9385
+ mesh2.frustumCulled = false;
9386
+ parent.add(mesh2);
9387
+ return mesh2;
9388
+ };
9389
+ const place = (segment, from, to) => {
9390
+ const direction = new THREE.Vector3().subVectors(to, from);
9391
+ const length = direction.length();
9392
+ segment.position.copy(from);
9393
+ if (length > 1e-6) segment.quaternion.setFromUnitVectors(Y, direction.divideScalar(length));
9394
+ segment.scale.y = length / segment.userData.length;
9395
+ };
9396
+ const arms = {};
9397
+ for (const side of ["R", "L"]) {
9398
+ const sign2 = side === "R" ? 1 : -1;
9399
+ const hand = createHandMesh(THREE, materials.skin);
9400
+ const anchor = new THREE.Group();
9401
+ anchor.name = `first-person-hand-${side}`;
9402
+ const mirror = new THREE.Group();
9403
+ mirror.scale.z = sign2;
9404
+ mirror.add(hand.root);
9405
+ anchor.add(mirror);
9406
+ root.add(anchor);
9407
+ const upper = limb2(root, rig.radius.shoulder, rig.radius.elbow, rig.upper, materials.sleeve);
9408
+ const fore = limb2(root, rig.radius.elbow, rig.radius.wrist, rig.fore, materials.sleeve);
9409
+ const cuff = limb2(root, rig.radius.cuff, rig.radius.cuff, 0.03, materials.cuff);
9410
+ const elbow = ball(root, rig.radius.elbow * 1.02, materials.sleeve);
9411
+ elbow.name = `first-person-elbow-${side}`;
9412
+ arms[side] = { side, sign: sign2, hand, anchor, upper, fore, cuff, elbow, shown: newPose(THREE), from: newPose(THREE), mode: null, blend: 1, drawn: newPose(THREE), joints: { shoulder: new THREE.Vector3(), elbow: new THREE.Vector3(), wrist: new THREE.Vector3() } };
9413
+ }
9414
+ const leg = new THREE.Group();
9415
+ leg.name = "first-person-leg";
9416
+ leg.visible = false;
9417
+ root.add(leg);
9418
+ const thigh = limb2(leg, 0.088, 0.068, rig.thigh, materials.trouser);
9419
+ const shin = limb2(leg, 0.068, 0.05, rig.shin, materials.trouser);
9420
+ const knee = ball(leg, 0.07, materials.trouser);
9421
+ const shoe = new THREE.Group();
9422
+ const shoeBox = (sx, sy, sz, x, y, material) => {
9423
+ const geometry = new THREE.BoxGeometry(sx, sy, sz);
9424
+ geometries.push(geometry);
9425
+ const mesh2 = new THREE.Mesh(geometry, material);
9426
+ mesh2.position.set(x, y, 0);
9427
+ mesh2.frustumCulled = false;
9428
+ shoe.add(mesh2);
9429
+ };
9430
+ shoeBox(0.27, 0.07, 0.1, 0.065, -0.05, materials.shoe);
9431
+ shoeBox(0.27, 0.025, 0.104, 0.065, -0.095, materials.sole);
9432
+ shoeBox(0.1, 0.05, 0.088, 0.17, -5e-3, materials.shoe);
9433
+ leg.add(shoe);
9434
+ const shoulderOf = (sign2, out) => sign2 === -1 && rig.shoulderLeft ? out.set(...rig.shoulderLeft) : out.set(rig.shoulder[0] * sign2, rig.shoulder[1], rig.shoulder[2]);
9435
+ const poleOf = (sign2) => sign2 === -1 && rig.elbowPoleLeft ? new THREE.Vector3(...rig.elbowPoleLeft) : new THREE.Vector3(rig.elbowPole[0] * sign2, rig.elbowPole[1], rig.elbowPole[2]);
9436
+ const kneePole = new THREE.Vector3(...rig.kneePole);
9437
+ const hip = new THREE.Vector3(...rig.hip);
9438
+ const euler = new THREE.Euler(0, 0, 0, "YZX");
9439
+ const quaternionOf = (r) => new THREE.Quaternion().setFromEuler(euler.set(r[0], r[1], r[2], "YZX"));
9440
+ const restPose = (rest, mirror, out) => {
9441
+ out.p.set(...rest.p);
9442
+ out.q.copy(quaternionOf(rest.r));
9443
+ if (mirror) {
9444
+ out.p.x = -out.p.x;
9445
+ out.q.copy(mirrorQuaternion(THREE, out.q));
9446
+ }
9447
+ out.grip = rest.grip ?? 0;
9448
+ out.scale = 1;
9449
+ return out;
9450
+ };
9451
+ const DEFAULT_REST = { p: [0.17, -0.3, -0.3], r: [0, 1.5, 0], grip: 0.3 };
9452
+ const stanceRest = (id, side, out) => {
9453
+ const stance = stances[id] ?? stances.relaxed;
9454
+ const right = stance?.R ?? DEFAULT_REST;
9455
+ const left = stance?.L;
9456
+ if (side === "R") return restPose(right, false, out);
9457
+ return left && left !== "mirror" ? restPose(left, false, out) : restPose(right, true, out);
9458
+ };
9459
+ const camPosition = new THREE.Vector3();
9460
+ const camQuaternion = new THREE.Quaternion();
9461
+ const camInverse = new THREE.Quaternion();
9462
+ const clamped = newPose(THREE);
9463
+ const probeAt = new THREE.Vector3();
9464
+ const probeForward = new THREE.Vector3();
9465
+ const probeFingers = new THREE.Vector3();
9466
+ let contact;
9467
+ const keepOutside = (pose, reach) => {
9468
+ if (!contact) return pose;
9469
+ probeAt.set(pose.p.x, pose.p.y, 0).applyQuaternion(camQuaternion).add(camPosition);
9470
+ probeForward.set(0, 0, -1).applyQuaternion(camQuaternion);
9471
+ const distance3 = contact([probeAt.x, probeAt.y, probeAt.z], [probeForward.x, probeForward.y, probeForward.z], CONTACT_PROBE);
9472
+ if (distance3 === null) return pose;
9473
+ const limit = Math.max(CONTACT_MIN, distance3 - reach - CONTACT_MARGIN);
9474
+ if (-pose.p.z <= limit) return pose;
9475
+ copyPose(clamped, pose);
9476
+ clamped.p.z = -limit;
9477
+ return clamped;
9478
+ };
9479
+ const forward = (pose, length) => Math.max(CONTACT_PALM, -probeFingers.set(1, 0, 0).applyQuaternion(pose.q).z * length * pose.scale);
9480
+ const handReach = (pose) => forward(pose, 0.085);
9481
+ const camScale = new THREE.Vector3();
9482
+ const toCamera = (target, grip, scale, out) => {
9483
+ out.p.set(...target.position).sub(camPosition).applyQuaternion(camInverse);
9484
+ out.q.set(...target.quaternion).premultiply(camInverse);
9485
+ out.grip = grip;
9486
+ out.scale = scale;
9487
+ return out;
9488
+ };
9489
+ const listeners = /* @__PURE__ */ new Set();
9490
+ let run = null;
9491
+ const emit = (event) => {
9492
+ for (const listener of listeners) listener(event);
9493
+ };
9494
+ const fire = (clip, from, to) => {
9495
+ for (const event of clipEventsBetween(clip, from, to)) emit({ ...event, clip: clip.id });
9496
+ };
9497
+ let stanceId = "relaxed";
9498
+ let phase = 0;
9499
+ let swing = 0;
9500
+ let sink = 0;
9501
+ let first = true;
9502
+ const bobOffset = new THREE.Vector3();
9503
+ const desired = newPose(THREE);
9504
+ const channelPose = newPose(THREE);
9505
+ const mixed = newPose(THREE);
9506
+ let indexCurl;
9507
+ const bone = createTwoBone(THREE);
9508
+ const shoulder = new THREE.Vector3();
9509
+ const wristAt = new THREE.Vector3();
9510
+ const palmAt = new THREE.Vector3();
9511
+ const fingers = new THREE.Vector3();
9512
+ const towards = new THREE.Vector3();
9513
+ const fromChannel = (channel, side, base, out) => {
9514
+ out.p.set(...channel.p);
9515
+ out.q.copy(quaternionOf(channel.r));
9516
+ if (channel.mirror && side === "L") {
9517
+ out.p.x = -out.p.x;
9518
+ out.q.copy(mirrorQuaternion(THREE, out.q));
9519
+ }
9520
+ out.grip = channel.grip ?? base.grip;
9521
+ out.scale = base.scale;
9522
+ return out;
9523
+ };
9524
+ const drawArm = (arm, pose) => {
9525
+ copyPose(arm.drawn, pose);
9526
+ const scale = pose.scale;
9527
+ fingers.set(1, 0, 0).applyQuaternion(pose.q);
9528
+ wristAt.copy(pose.p).addScaledVector(fingers, -rig.wrist * scale);
9529
+ shoulderOf(arm.sign, shoulder).add(bobOffset);
9530
+ const excess = shoulder.distanceTo(wristAt) - (rig.upper + rig.fore) * REACH_SLACK;
9531
+ if (excess > 0 && rig.reachShift > 0) shoulder.addScaledVector(towards.subVectors(wristAt, shoulder).normalize(), Math.min(excess, rig.reachShift));
9532
+ solveTwoBone(shoulder, wristAt, rig.upper, rig.fore, poleOf(arm.sign), bone);
9533
+ palmAt.copy(bone.end).addScaledVector(fingers, rig.wrist * scale);
9534
+ arm.drawn.p.copy(palmAt);
9535
+ arm.anchor.position.copy(palmAt);
9536
+ arm.anchor.quaternion.copy(pose.q);
9537
+ arm.anchor.scale.setScalar(scale);
9538
+ arm.hand.setGrip(pose.grip);
9539
+ arm.hand.setIndex(arm.side === "R" ? indexCurl : void 0);
9540
+ arm.joints.shoulder.copy(shoulder);
9541
+ arm.joints.elbow.copy(bone.joint);
9542
+ arm.joints.wrist.copy(bone.end);
9543
+ place(arm.upper, shoulder, bone.joint);
9544
+ place(arm.fore, bone.joint, bone.end);
9545
+ arm.elbow.position.copy(bone.joint);
9546
+ const toWrist = new THREE.Vector3().subVectors(bone.end, bone.joint).normalize();
9547
+ place(arm.cuff, new THREE.Vector3().copy(bone.end).addScaledVector(toWrist, -0.02), new THREE.Vector3().copy(bone.end).addScaledVector(toWrist, 0.012));
9548
+ };
9549
+ const footPose = newPose(THREE);
9550
+ const footRest = newPose(THREE);
9551
+ const ankle = new THREE.Vector3();
9552
+ const hipMirrored = new THREE.Vector3(-hip.x, hip.y, hip.z);
9553
+ const kneePoleMirrored = new THREE.Vector3(-kneePole.x, kneePole.y, kneePole.z);
9554
+ const drawLeg = (pose, left) => {
9555
+ const origin = left ? hipMirrored : hip;
9556
+ solveTwoBone(origin, pose.p, rig.thigh, rig.shin, left ? kneePoleMirrored : kneePole, bone);
9557
+ ankle.copy(bone.end);
9558
+ place(thigh, origin, bone.joint);
9559
+ place(shin, bone.joint, ankle);
9560
+ knee.position.copy(bone.joint);
9561
+ shoe.position.copy(ankle);
9562
+ shoe.quaternion.copy(pose.q);
9563
+ };
9564
+ const modeOf = (key, arm) => {
9565
+ if (arm.mode === key) return;
9566
+ copyPose(arm.from, arm.shown);
9567
+ arm.mode = key;
9568
+ arm.blend = first ? 1 : 0;
9569
+ };
9570
+ return {
9571
+ root,
9572
+ get playing() {
9573
+ return run ? run.clip.id : null;
9574
+ },
9575
+ get stance() {
9576
+ return stanceId;
9577
+ },
9578
+ play(id, options2) {
9579
+ const clip = clips.get(id);
9580
+ if (!clip) return false;
9581
+ run = { clip, time: 0, left: options2?.leg === "left" };
9582
+ fire(clip, -1e-9, 0);
9583
+ return true;
9584
+ },
9585
+ stop() {
9586
+ run = null;
9587
+ },
9588
+ update(dt, state) {
9589
+ const { camera } = state;
9590
+ contact = state.contact;
9591
+ camera.updateWorldMatrix(true, false);
9592
+ camera.matrixWorld.decompose(camPosition, camQuaternion, camScale);
9593
+ camInverse.copy(camQuaternion).invert();
9594
+ root.position.copy(camPosition);
9595
+ root.quaternion.copy(camQuaternion);
9596
+ root.updateMatrixWorld(true);
9597
+ const speed = state.speed ?? 0;
9598
+ const target = Math.min(1, speed / bob.fullSpeed) * (state.running ? bob.run : 1);
9599
+ swing += (target - swing) * Math.min(1, dt * 8);
9600
+ phase += dt * speed * bob.frequency;
9601
+ sink += ((state.crouch ? 1 : 0) - sink) * Math.min(1, dt * 8);
9602
+ bobOffset.set(Math.sin(phase) * bob.x * swing, Math.sin(phase * 2) * bob.y * swing - bob.crouch * sink, 0);
9603
+ stanceId = state.stance ?? "relaxed";
9604
+ const stance = stances[stanceId] ?? stances.relaxed;
9605
+ const targets = state.targets ?? null;
9606
+ if (run) {
9607
+ const from = run.time;
9608
+ run.time += dt;
9609
+ fire(run.clip, from, Math.min(run.time, run.clip.duration));
9610
+ }
9611
+ const sample = run ? sampleFirstPersonClip(run.clip, Math.min(run.time, run.clip.duration)) : null;
9612
+ for (const side of ["R", "L"]) {
9613
+ const arm = arms[side];
9614
+ const target2 = targets?.[side];
9615
+ let mode;
9616
+ if (stance?.follow && target2) {
9617
+ mode = "target";
9618
+ toCamera(target2, (side === "L" ? targets?.gripL : void 0) ?? targets?.grip ?? 1, targets?.scale ?? 1, desired);
9619
+ } else {
9620
+ mode = `rest:${stance?.follow ? stance.fallback ?? "relaxed" : stanceId}`;
9621
+ stanceRest(stance?.follow ? stance.fallback ?? "relaxed" : stanceId, side, desired);
9622
+ desired.p.add(bobOffset);
9623
+ }
9624
+ modeOf(mode, arm);
9625
+ if (side === "R") indexCurl = mode === "target" ? targets?.fingers?.index : void 0;
9626
+ arm.blend = blendSeconds <= 0 ? 1 : Math.min(1, arm.blend + dt / blendSeconds);
9627
+ if (arm.blend >= 1) copyPose(arm.shown, desired);
9628
+ else mixPose(THREE, arm.shown, arm.from, desired, ease2(arm.blend));
9629
+ const channel = sample?.[side];
9630
+ if (channel && channel.w > 0) {
9631
+ fromChannel(channel, side, arm.shown, channelPose);
9632
+ mixPose(THREE, mixed, arm.shown, channelPose, channel.w);
9633
+ drawArm(arm, mode === "target" ? mixed : keepOutside(mixed, handReach(mixed)));
9634
+ } else drawArm(arm, mode === "target" ? arm.shown : keepOutside(arm.shown, handReach(arm.shown)));
9635
+ }
9636
+ const foot = sample?.F;
9637
+ leg.visible = !!foot && foot.w > FOOT_SHOWN;
9638
+ if (foot && leg.visible) {
9639
+ restPose(rig.foot, false, footRest);
9640
+ fromChannel(foot, "R", footRest, footPose);
9641
+ mixPose(THREE, mixed, footRest, footPose, foot.w);
9642
+ copyPose(footPose, mixed);
9643
+ if (run?.left) {
9644
+ footPose.p.x = -footPose.p.x;
9645
+ footPose.q.copy(mirrorRotation(THREE, footPose.q));
9646
+ }
9647
+ drawLeg(contact ? keepOutside(footPose, forward(footPose, FOOT_LENGTH)) : footPose, run?.left ?? false);
9648
+ }
9649
+ if (run && run.time >= run.clip.duration) run = null;
9650
+ first = false;
9651
+ },
9652
+ on(_type, listener) {
9653
+ listeners.add(listener);
9654
+ return () => void listeners.delete(listener);
9655
+ },
9656
+ joints(side) {
9657
+ const { shoulder: shoulder2, elbow, wrist } = arms[side].joints;
9658
+ return { shoulder: shoulder2.clone(), elbow: elbow.clone(), wrist: wrist.clone() };
9659
+ },
9660
+ handPose(side) {
9661
+ const pose = arms[side].drawn;
9662
+ return { position: pose.p.clone(), quaternion: pose.q.clone(), grip: pose.grip };
9663
+ },
9664
+ dispose() {
9665
+ run = null;
9666
+ listeners.clear();
9667
+ for (const arm of Object.values(arms)) arm.hand.dispose();
9668
+ for (const geometry of geometries) geometry.dispose();
9669
+ for (const material of Object.values(materials)) material.dispose();
9670
+ root.removeFromParent();
9671
+ }
9672
+ };
9673
+ }
9674
+
9675
+ // src/player/room-avatar.ts
9676
+ var impactOf = (clip) => clip.events?.find((event) => event.type === "impact")?.t ?? null;
9677
+ var toRoomAvatar = (avatar, options = {}) => {
9678
+ const arms = options.firstPerson === false ? null : createFirstPersonArms(avatar.three, {
9679
+ colors: { skin: avatar.colors.skin, sleeve: avatar.colors.longSleeves ? avatar.colors.shirt : avatar.colors.skin, trouser: avatar.colors.trousers, shoe: avatar.colors.shoes, ...options.firstPerson?.colors },
9680
+ clips: options.firstPersonClips ?? FIRST_PERSON_CLIPS,
9681
+ ...options.firstPerson
9682
+ });
9683
+ const strikes = new Map((options.strikeClips ?? ATTACK_CLIPS).map((clip) => [clip.id, clip]));
9684
+ const mirrored = /* @__PURE__ */ new Map();
9685
+ const leftOf = (clip) => {
9686
+ let found = mirrored.get(clip.id);
9687
+ if (!found) mirrored.set(clip.id, found = mirrorPoseClip(clip, `${clip.id}_left`));
9688
+ return found;
9689
+ };
9690
+ return {
9691
+ root: avatar.root,
9692
+ avatar,
9693
+ arms,
9694
+ ...arms ? { firstPerson: { root: arms.root, update: (dt, state) => arms.update(dt, state) } } : {},
9695
+ update: (dt, state) => avatar.update(dt, { speed: state.speed, running: state.running, crouch: state.crouch, down: state.down, armed: state.armed, pitch: -state.pitch }),
9696
+ hand: (side) => avatar.hand(side),
9697
+ strike: (clipId, strikeOptions) => {
9698
+ const clip = strikes.get(clipId);
9699
+ if (!clip) return null;
9700
+ const left = strikeOptions?.leg === "left";
9701
+ avatar.play(left ? leftOf(clip) : clip);
9702
+ arms?.play(clipId, left ? { leg: "left" } : void 0);
9703
+ return impactOf(clip);
9704
+ }
9705
+ };
9706
+ };
9707
+
9708
+ // src/player/test-text.ts
9709
+ var AVATAR_TEXT = {
9710
+ en: {
9711
+ group: "Avatar",
9712
+ name: "Player body",
9713
+ actions: {
9714
+ camera_first: "Camera: 1st person",
9715
+ camera_third: "Camera: 3rd person",
9716
+ crouch: "Crouch",
9717
+ stand: "Stand up",
9718
+ fall: "Fall down",
9719
+ get_up: "Get up",
9720
+ armed_on: "Armed: on",
9721
+ armed_off: "Armed: off",
9722
+ stop_clip: "Stop clip"
9723
+ },
9724
+ play: "Play",
9725
+ metrics: { camera: "Camera", clip: "Clip playing", last_event: "Last clip event", state: "State", joints: "Joints" },
9726
+ none: "none"
9727
+ },
9728
+ "pt-BR": {
9729
+ group: "Avatar",
9730
+ name: "Corpo do jogador",
9731
+ actions: {
9732
+ camera_first: "C\xE2mera: 1\xAA pessoa",
9733
+ camera_third: "C\xE2mera: 3\xAA pessoa",
9734
+ crouch: "Agachar",
9735
+ stand: "Levantar",
9736
+ fall: "Cair",
9737
+ get_up: "Levantar do ch\xE3o",
9738
+ armed_on: "Armado: ligado",
9739
+ armed_off: "Armado: desligado",
9740
+ stop_clip: "Parar clipe"
9741
+ },
9742
+ play: "Tocar",
9743
+ metrics: { camera: "C\xE2mera", clip: "Clipe tocando", last_event: "\xDAltimo evento do clipe", state: "Estado", joints: "Juntas" },
9744
+ none: "nenhum"
9745
+ }
9746
+ };
9747
+
9748
+ // src/player/test-module.ts
9749
+ var AVATAR_AREA_ID = "avatar_area";
9750
+ var round = (value) => (Math.round(value * 100) / 100).toString();
9751
+ function createAvatarTestModule(options) {
9752
+ const clips = options.clips ?? POSE_CLIPS;
9753
+ const textOf = (locale) => AVATAR_TEXT[locale ?? options.locale ?? "pt-BR"] ?? AVATAR_TEXT["pt-BR"];
9754
+ const phaseLabel = (label, locale) => {
9755
+ const id = locale ?? options.locale ?? "pt-BR";
9756
+ const table = { ...POSE_CLIP_LOCALES[id] ?? POSE_CLIP_LOCALES["pt-BR"], ...options.clipLocales?.[id] ?? options.clipLocales?.["pt-BR"] };
9757
+ return typeof label === "string" ? table[label] ?? label : "";
9758
+ };
9759
+ const state = { crouch: false, down: false, armed: null };
9760
+ let host = null;
9761
+ let lastEvent = "";
9762
+ const log = (action, extra = {}) => {
9763
+ const entry = { type: "avatar", action, ...extra };
9764
+ host?.log(JSON.stringify(entry), entry);
9765
+ };
9766
+ const push = (action, patch, extra = {}) => {
9767
+ Object.assign(state, patch);
9768
+ options.state?.set(patch);
9769
+ log(action, { crouch: state.crouch, down: state.down, armed: state.armed, ...extra });
9770
+ };
9771
+ const setCamera = (mode) => {
9772
+ options.camera?.set(mode);
9773
+ log(`camera_${mode}`, { mode: options.camera?.mode() ?? null });
9774
+ };
9775
+ const onChange = (change) => {
9776
+ if (change.kind !== "action") return;
9777
+ switch (change.id) {
9778
+ case "camera_first":
9779
+ return setCamera("first");
9780
+ case "camera_third":
9781
+ return setCamera("third");
9782
+ case "crouch":
9783
+ return push("crouch", { crouch: true });
9784
+ case "stand":
9785
+ return push("stand", { crouch: false });
9786
+ case "fall":
9787
+ return push("fall", { down: true });
9788
+ case "get_up":
9789
+ return push("get_up", { down: false });
9790
+ case "armed_on":
9791
+ return push("armed_on", { armed: true });
9792
+ case "armed_off":
9793
+ return push("armed_off", { armed: false });
9794
+ case "stop_clip":
9795
+ options.avatar.stop();
9796
+ return log("stop_clip", { playing: options.avatar.playing });
9797
+ default: {
9798
+ const clip = clips.find((item) => `play_${item.id}` === change.id);
9799
+ if (!clip) return;
9800
+ options.avatar.play(clip);
9801
+ log("play_clip", { clip: clip.id, duration: clip.duration, loop: clip.loop ?? false, channels: clip.channels ?? "full" });
9802
+ }
9803
+ }
9804
+ };
9805
+ const joints = () => {
9806
+ const rig = options.avatar.rig;
9807
+ const [armA, armB] = rig.arms;
9808
+ const [legA, legB] = rig.legs;
9809
+ return `arms ${round(armA.g.rotation.x)}/${round(armB.g.rotation.x)} elbows ${round(armA.el.rotation.x)}/${round(armB.el.rotation.x)} legs ${round(legA.g.rotation.x)}/${round(legB.g.rotation.x)} knees ${round(legA.kn.rotation.x)}/${round(legB.kn.rotation.x)} lean ${round(rig.upper.rotation.x)}`;
9810
+ };
9811
+ return {
9812
+ id: AVATAR_AREA_ID,
9813
+ name: textOf().name,
9814
+ group: textOf().group,
9815
+ state,
9816
+ items: () => [],
9817
+ area: () => ({ placements: [], view: { eye: [0, 1.7, 6], target: [0, 1.2, 0] } }),
9818
+ controls: (locale) => {
9819
+ const text = textOf(locale);
9820
+ const action = (id, name, hint) => ({ kind: "action", id, name, ...hint ? { hint } : {} });
9821
+ return [
9822
+ action("camera_first", text.actions.camera_first),
9823
+ action("camera_third", text.actions.camera_third),
9824
+ action("crouch", text.actions.crouch),
9825
+ action("stand", text.actions.stand),
9826
+ action("fall", text.actions.fall),
9827
+ action("get_up", text.actions.get_up),
9828
+ action("armed_on", text.actions.armed_on),
9829
+ action("armed_off", text.actions.armed_off),
9830
+ ...clips.map((clip) => action(`play_${clip.id}`, `${text.play}: ${clip.id}`)),
9831
+ action("stop_clip", text.actions.stop_clip)
9832
+ ];
9833
+ },
9834
+ metrics: (locale) => {
9835
+ const text = textOf(locale);
9836
+ return [
9837
+ { id: "camera", name: text.metrics.camera, read: () => options.camera?.mode() ?? text.none },
9838
+ { id: "clip", name: text.metrics.clip, read: () => options.avatar.playing ?? text.none },
9839
+ { id: "last_event", name: text.metrics.last_event, read: () => lastEvent || text.none },
9840
+ { id: "state", name: text.metrics.state, read: () => `${state.crouch ? "crouch " : ""}${state.down ? "down " : ""}${state.armed === null ? "" : state.armed ? "armed" : "unarmed"}`.trim() || text.none },
9841
+ { id: "joints", name: text.metrics.joints, read: joints }
9842
+ ];
9843
+ },
9844
+ attach(lent) {
9845
+ host = lent;
9846
+ const stopChange = lent.bench?.onChange(onChange);
9847
+ const stopEvents = options.avatar.on("event", (event) => {
9848
+ lastEvent = `${event.clip} ${event.type} ${round(event.t)}s${event.data && "label" in event.data ? ` ${phaseLabel(event.data.label)}` : ""}`;
9849
+ log("clip_event", { clip: event.clip, event: event.type, t: event.t, data: event.data ?? null });
9850
+ if (event.type === "impact") log("impact", { clip: event.clip, t: event.t, kind: event.data?.kind ?? null });
9851
+ });
9852
+ return () => {
9853
+ stopChange?.();
9854
+ stopEvents();
9855
+ host = null;
9856
+ };
9857
+ }
9858
+ };
9859
+ }
6476
9860
  return __toCommonJS(index_exports);
6477
9861
  })();
6478
9862
  //# sourceMappingURL=index.global.js.map