@adatechnology/game-characters-three 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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,
@@ -1231,9 +2774,9 @@ var GameCharactersThree = (() => {
1231
2774
  if (region === "torso") return bodyCount > 1 ? cost.bruteTorso : cost.torso;
1232
2775
  return cost.limb;
1233
2776
  };
1234
- var teamGameFalloff = (distance22, range) => {
2777
+ var teamGameFalloff = (distance22, range2) => {
1235
2778
  const floor = TEAM_GAME_RULES.falloff.atTwiceRange;
1236
- 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));
1237
2780
  };
1238
2781
  var NO_HEADSHOT = { headshot: false };
1239
2782
  var HEADSHOT = { headshot: true };
@@ -1286,8 +2829,8 @@ var GameCharactersThree = (() => {
1286
2829
  var DEFAULT_PROJECTILE_GRAMS = 8;
1287
2830
  var RIFLE_JOULES = 1e3;
1288
2831
  var penetrationForce = (energy, grams, diameterMm) => {
1289
- const area = Math.PI * diameterMm ** 2 / 4;
1290
- 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;
1291
2834
  };
1292
2835
  var projectileOf = (hit, caliber) => {
1293
2836
  const pellets = hit.pellets ?? caliber?.pellets ?? 1;
@@ -1375,7 +2918,15 @@ var GameCharactersThree = (() => {
1375
2918
  if (points >= rules.severity.stunAtPoints) ops.stun();
1376
2919
  return result;
1377
2920
  };
1378
- 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);
1379
2930
  var segmentBlast = (params) => {
1380
2931
  const { ops, rule, blow } = params;
1381
2932
  const { blast: blast2, segments } = ops.rules;
@@ -1615,7 +3166,7 @@ var GameCharactersThree = (() => {
1615
3166
  };
1616
3167
  var blast = ({ ops, hit, setup, localPoint, jointOf }) => {
1617
3168
  const points = hit.points ?? pointsFromEnergy(hit.energy ?? 0, setup.rules);
1618
- 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 };
1619
3170
  const common = { cut: hit.cut ?? setup.rules.defaultCut.explosive, damageType: hit.type, model: setup.model, headResistance: HEAD_RESISTANCE };
1620
3171
  const rule = SEGMENT_RULES[setup.rules.segmentRule] ?? kitRule;
1621
3172
  const result = ops.body.detail === "regions" ? regionBlast({ ...base, blow: { ...common, protection: NO_PROTECTION } }) : segmentBlast({ ...base, rule, blow: { ...common, limbFactor: ops.spec.limbFactor } });
@@ -1824,14 +3375,14 @@ var GameCharactersThree = (() => {
1824
3375
  var createCharacters = (options = {}) => {
1825
3376
  const body = createBodySpec(options.body);
1826
3377
  const packs = options.packs ?? [];
1827
- const presets = mergeById([PERSON_PRESET], packs.flatMap((pack) => pack.presets ?? []));
3378
+ const presets = mergeById([PERSON_PRESET], packs.flatMap((pack2) => pack2.presets ?? []));
1828
3379
  applyPatches(presets, options.patch);
1829
3380
  removeIds(presets, options.remove);
1830
3381
  const damage = resolveDamageRules(options.damage);
1831
3382
  const penetration = modelOf(options.penetration);
1832
- 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 ?? []]);
1833
3384
  const shippedCalibers = penetration.id === "team-game" ? TEAM_GAME_CALIBERS : [];
1834
- const calibers = mergeById(shippedCalibers, [...packs.flatMap((pack) => pack.calibers ?? []), ...options.calibers ?? []]);
3385
+ const calibers = mergeById(shippedCalibers, [...packs.flatMap((pack2) => pack2.calibers ?? []), ...options.calibers ?? []]);
1835
3386
  const setup = { rules: damage, model: penetration, protection, calibers };
1836
3387
  let counter = 0;
1837
3388
  return {
@@ -2271,6 +3822,486 @@ var GameCharactersThree = (() => {
2271
3822
  const apron = random() < APRON_SHARE;
2272
3823
  return { sleeve, hair, headWidth, headHeight, jaw, nose, beard, glasses, cap, capColor, bag, bagColor, torn, apron };
2273
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;
4304
+ };
2274
4305
 
2275
4306
  // src/instanced/body-geometry.ts
2276
4307
  var negativeFirst = (first, second) => first[0] <= second[0] ? [first, second] : [second, first];
@@ -2305,13 +4336,13 @@ var GameCharactersThree = (() => {
2305
4336
  return source;
2306
4337
  };
2307
4338
  var MERGED_ATTRIBUTES = [["position", 3], ["normal", 3], ["bone", 1], ["vcol", 4], ["pivot", 3], ["ppivot", 3]];
2308
- var mergeBody = (list, three) => {
2309
- 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);
2310
4341
  const merged = new three.BufferGeometry();
2311
4342
  for (const [name, size] of MERGED_ATTRIBUTES) {
2312
4343
  const array = new Float32Array(total * size);
2313
4344
  let offset = 0;
2314
- for (const geometry of list) {
4345
+ for (const geometry of list2) {
2315
4346
  const part = geometry.attributes[name].array;
2316
4347
  array.set(part, offset);
2317
4348
  offset += part.length;
@@ -2321,7 +4352,8 @@ var GameCharactersThree = (() => {
2321
4352
  merged.computeBoundingSphere();
2322
4353
  return merged;
2323
4354
  };
2324
- var buildInstancedBody = (three, { segments, body = TEAM_GAME }) => {
4355
+ var buildInstancedBody = (host, { segments, body = TEAM_GAME }) => {
4356
+ const three = shapeGeometries(host);
2325
4357
  const joints = jointsOf(body);
2326
4358
  const parts = [];
2327
4359
  const half = Math.max(4, segments >> 1);
@@ -2449,15 +4481,15 @@ var GameCharactersThree = (() => {
2449
4481
  copy.setAttribute(name, attribute);
2450
4482
  attributes[name] = attribute;
2451
4483
  }
2452
- const mesh = new three.InstancedMesh(copy, createBodyMaterial(three, { time }), max);
2453
- mesh.customDepthMaterial = createBodyMaterial(three, { depth: true, time });
2454
- mesh.frustumCulled = false;
2455
- mesh.castShadow = castShadow;
2456
- mesh.receiveShadow = true;
2457
- 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;
2458
4490
  let count = 0;
2459
4491
  return {
2460
- mesh,
4492
+ mesh: mesh2,
2461
4493
  max,
2462
4494
  get count() {
2463
4495
  return count;
@@ -2465,7 +4497,7 @@ var GameCharactersThree = (() => {
2465
4497
  begin() {
2466
4498
  count = 0;
2467
4499
  },
2468
- push({ a, b, c, color, eye, y = 0 }) {
4500
+ push({ a, b, c, color: color2, eye, y = 0 }) {
2469
4501
  if (count >= max) return;
2470
4502
  const index = count++;
2471
4503
  const fourOffset = index * 4;
@@ -2473,11 +4505,11 @@ var GameCharactersThree = (() => {
2473
4505
  attributes.iA.array.set(a, fourOffset);
2474
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);
2475
4507
  attributes.iC.array.set(c, fourOffset);
2476
- attributes.iCol.array.set([color.r, color.g, color.b], threeOffset);
4508
+ attributes.iCol.array.set([color2.r, color2.g, color2.b], threeOffset);
2477
4509
  attributes.iEye.array.set(eye ? [eye.r, eye.g, eye.b] : [0, 0, 0], threeOffset);
2478
4510
  },
2479
4511
  end() {
2480
- mesh.count = count;
4512
+ mesh2.count = count;
2481
4513
  for (const attribute of Object.values(attributes)) {
2482
4514
  attribute.clearUpdateRanges();
2483
4515
  attribute.addUpdateRange(0, count * attribute.itemSize);
@@ -2502,7 +4534,8 @@ var GameCharactersThree = (() => {
2502
4534
  var FAR_LOD = 0.6;
2503
4535
  var EYE_SCALE = 2.2;
2504
4536
  var EYE_DEPTH_SCALE = 1.4;
2505
- var bakeBody = (three, builders, spec, lod) => {
4537
+ var bakeBody = (host, builders, spec, lod) => {
4538
+ const three = shapeGeometries(host);
2506
4539
  const root = spec.retrato && builders.buildPortrait ? builders.buildPortrait(spec.retrato, lod) : builders.buildBest({ ...spec, pose: { ...BAKE_NEUTRAL_POSE, ...spec.pose ?? {} } }, lod);
2507
4540
  const rig = root.userData.rig;
2508
4541
  const P = rig.P;
@@ -2518,7 +4551,7 @@ var GameCharactersThree = (() => {
2518
4551
  leg.kn.rotation.set(0, 0, 0);
2519
4552
  }
2520
4553
  root.updateMatrixWorld(true);
2521
- const worldPosition2 = (object) => object.getWorldPosition(new three.Vector3()).toArray();
4554
+ const worldPosition2 = (object2) => object2.getWorldPosition(new three.Vector3()).toArray();
2522
4555
  const bones = /* @__PURE__ */ new Map();
2523
4556
  bones.set(rig.headG, [1, worldPosition2(rig.headG), [0, 0, 0]]);
2524
4557
  for (const arm of rig.arms) {
@@ -2534,13 +4567,13 @@ var GameCharactersThree = (() => {
2534
4567
  const trunk = [0, [0, 0.9 * P.s, 0], [0, 0, 0]];
2535
4568
  const parts = [];
2536
4569
  const topMaterial = spec.retrato ? null : builders.topMaterial();
2537
- root.traverse((object) => {
2538
- const mesh = object;
2539
- const material = mesh.material;
2540
- if (!mesh.isMesh || !mesh.geometry || material.transparent) return;
2541
- 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;
2542
4575
  let tag = trunk;
2543
- for (let ancestor = object.parent; ancestor; ancestor = ancestor.parent) {
4576
+ for (let ancestor = object2.parent; ancestor; ancestor = ancestor.parent) {
2544
4577
  const found = bones.get(ancestor);
2545
4578
  if (found) {
2546
4579
  tag = found;
@@ -2548,21 +4581,21 @@ var GameCharactersThree = (() => {
2548
4581
  }
2549
4582
  }
2550
4583
  let [bone, pivot, parentPivot] = tag;
2551
- if (object.userData.bone === 11) {
4584
+ if (object2.userData.bone === 11) {
2552
4585
  bone = 11;
2553
4586
  pivot = bones.get(rig.headG)[1];
2554
4587
  parentPivot = [0, 0, 0];
2555
4588
  }
2556
- const isEye2 = !!object.userData.eye;
2557
- const color = material.color;
4589
+ const isEye2 = !!object2.userData.eye;
4590
+ const color2 = material.color;
2558
4591
  const materialId = isEye2 ? 3 : material === topMaterial ? 1 : 6;
2559
4592
  if (isEye2 && bone === 1) bone = 6;
2560
- const geometry = mesh.geometry.clone();
2561
- geometry.applyMatrix4(mesh.matrixWorld);
4593
+ const geometry = mesh2.geometry.clone();
4594
+ geometry.applyMatrix4(mesh2.matrixWorld);
2562
4595
  const isBlood = material.polygonOffset && material.isMeshStandardMaterial;
2563
4596
  if (isBlood) liftAlongNormals(geometry, lod < FAR_LOD ? BLOOD_LIFT_FAR : BLOOD_LIFT_NEAR);
2564
4597
  if (isEye2) enlargeEye(three, geometry, lod < FAR_LOD ? 1 : 0.68);
2565
- 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];
2566
4599
  parts.push({ g: geometry, bone, pv: pivot, pp: parentPivot, col: colors });
2567
4600
  });
2568
4601
  return { geo: mergeBaked(three, parts), s: P.s, bulk: P.bulk, verts: parts.reduce((sum, part) => sum + part.g.attributes.position.count, 0) };
@@ -2588,7 +4621,7 @@ var GameCharactersThree = (() => {
2588
4621
  }
2589
4622
  const position = new Float32Array(vertexTotal * 3);
2590
4623
  const normal = new Float32Array(vertexTotal * 3);
2591
- const color = new Float32Array(vertexTotal * 4);
4624
+ const color2 = new Float32Array(vertexTotal * 4);
2592
4625
  const bone = new Float32Array(vertexTotal);
2593
4626
  const pivot = new Float32Array(vertexTotal * 3);
2594
4627
  const parentPivot = new Float32Array(vertexTotal * 3);
@@ -2600,7 +4633,7 @@ var GameCharactersThree = (() => {
2600
4633
  position.set(part.g.attributes.position.array, vertexOffset * 3);
2601
4634
  normal.set(part.g.attributes.normal.array, vertexOffset * 3);
2602
4635
  for (let vertex = 0; vertex < count; vertex++) {
2603
- color.set(part.col, (vertexOffset + vertex) * 4);
4636
+ color2.set(part.col, (vertexOffset + vertex) * 4);
2604
4637
  bone[vertexOffset + vertex] = part.bone;
2605
4638
  pivot.set(part.pv, (vertexOffset + vertex) * 3);
2606
4639
  parentPivot.set(part.pp, (vertexOffset + vertex) * 3);
@@ -2615,7 +4648,7 @@ var GameCharactersThree = (() => {
2615
4648
  const out = new three.BufferGeometry();
2616
4649
  out.setAttribute("position", new three.BufferAttribute(position, 3));
2617
4650
  out.setAttribute("normal", new three.BufferAttribute(normal, 3));
2618
- out.setAttribute("vcol", new three.BufferAttribute(color, 4));
4651
+ out.setAttribute("vcol", new three.BufferAttribute(color2, 4));
2619
4652
  out.setAttribute("bone", new three.BufferAttribute(bone, 1));
2620
4653
  out.setAttribute("pivot", new three.BufferAttribute(pivot, 3));
2621
4654
  out.setAttribute("ppivot", new three.BufferAttribute(parentPivot, 3));
@@ -2651,20 +4684,21 @@ var GameCharactersThree = (() => {
2651
4684
  var SPIN_DAMPING = 0.5;
2652
4685
  var REST_SPEED = 0.4;
2653
4686
  var LEG_COLOR = 2896704;
2654
- var createFlyingLimbs = (three, { max = 40, random, effects = {} }) => {
4687
+ var createFlyingLimbs = (host, { max = 40, random, effects = {} }) => {
4688
+ const three = shapeGeometries(host);
2655
4689
  const limbs = [];
2656
- const mesh = new three.InstancedMesh(new three.CapsuleGeometry(0.065, 0.32, 2, 6), new three.MeshLambertMaterial({ color: 16777215 }), max);
2657
- mesh.count = 0;
2658
- mesh.castShadow = true;
2659
- 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());
2660
4694
  const matrix = new three.Matrix4();
2661
4695
  const quaternion = new three.Quaternion();
2662
4696
  const scale = new three.Vector3();
2663
4697
  const position = new three.Vector3();
2664
4698
  const euler = new three.Euler();
2665
- const color = new three.Color();
4699
+ const color2 = new three.Color();
2666
4700
  return {
2667
- mesh,
4701
+ mesh: mesh2,
2668
4702
  limbs,
2669
4703
  launch({ x, z, kind, color: sleeve, blood }) {
2670
4704
  const isLeg2 = kind === "leg";
@@ -2717,12 +4751,12 @@ var GameCharactersThree = (() => {
2717
4751
  }
2718
4752
  }
2719
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));
2720
- mesh.setMatrixAt(index, matrix);
2721
- mesh.setColorAt(index, color.set(limb2.col));
4754
+ mesh2.setMatrixAt(index, matrix);
4755
+ mesh2.setColorAt(index, color2.set(limb2.col));
2722
4756
  });
2723
- mesh.count = limbs.length;
2724
- mesh.instanceMatrix.needsUpdate = true;
2725
- 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;
2726
4760
  }
2727
4761
  };
2728
4762
  };
@@ -2837,7 +4871,8 @@ var GameCharactersThree = (() => {
2837
4871
  };
2838
4872
 
2839
4873
  // src/rich/best-builder.ts
2840
- var createBestBuilder = (THREE, { types, random = Math.random }) => {
4874
+ var createBestBuilder = (host, { types, random = Math.random }) => {
4875
+ const THREE = shapeGeometries(host);
2841
4876
  const options = { types, random };
2842
4877
  let LK = 1, topM_ref = null;
2843
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);
@@ -2863,7 +4898,7 @@ var GameCharactersThree = (() => {
2863
4898
  const PANTS = 2896704, GRAY2 = 4868678, RED2 = 8000012;
2864
4899
  const col = (a, b, t) => new THREE.Color(a).lerp(new THREE.Color(b), t);
2865
4900
  const geoBox = (w, h, d) => new THREE.BoxGeometry(w, h, d);
2866
- 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);
2867
4902
  const limbGeo = (w, len) => {
2868
4903
  const g = geoBox(w, len, w);
2869
4904
  g.translate(0, -len / 2, 0);
@@ -3017,7 +5052,7 @@ var GameCharactersThree = (() => {
3017
5052
  st.scale.set(1, 0.35, 1);
3018
5053
  add(p2, CYL(r * 0.32, r * 0.36, 0.07, 10), M(15261900), 0, y + (up ? 0.04 : -0.04), 0);
3019
5054
  };
3020
- const ring = (p2, r, h, m, y, sx, sz) => {
5055
+ const ring2 = (p2, r, h, m, y, sx, sz) => {
3021
5056
  const o = add(p2, CYL(r, r, h, 24), m, 0, y, 0);
3022
5057
  o.scale.set(sx || 1.12, 1, sz || 0.7);
3023
5058
  return o;
@@ -3141,8 +5176,8 @@ var GameCharactersThree = (() => {
3141
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);
3142
5177
  }
3143
5178
  if (O.stripes) {
3144
- ring(U, 0.205, 0.05, M(O.stripes), 1.03, 1.13, 0.68);
3145
- 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);
3146
5181
  }
3147
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));
3148
5183
  if (!spec.human) {
@@ -3436,8 +5471,8 @@ var GameCharactersThree = (() => {
3436
5471
  },
3437
5472
  {
3438
5473
  ids: ["stubble"],
3439
- apply: ({ Hd, THREE, add, cmat, scaleHex, sp }) => {
3440
- 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);
3441
5476
  b.scale.set(1, 0.74, 1);
3442
5477
  }
3443
5478
  },
@@ -3755,8 +5790,8 @@ var GameCharactersThree = (() => {
3755
5790
  add(U, Bx(0.1, 0.12, 0.09), m, -0.17, 0.95, -0.15);
3756
5791
  return;
3757
5792
  },
3758
- belt: ({ U, m, ring }) => {
3759
- 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);
3760
5795
  return;
3761
5796
  },
3762
5797
  holster: ({ Bx, add, cmat, legs }) => {
@@ -3768,9 +5803,9 @@ var GameCharactersThree = (() => {
3768
5803
  add(U, Bx(0.012, 0.1, 0.012), cmat(1710618), 0.17, 1.52, 0.18);
3769
5804
  return;
3770
5805
  },
3771
- stripes: ({ THREE, U, add, arms, m, ring }) => {
3772
- ring(U, 0.205, 0.05, m, 1.03, 1.13, 0.68);
3773
- 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);
3774
5809
  arms.forEach((a) => {
3775
5810
  const r = add(a.el, new THREE.CylinderGeometry(0.058, 0.054, 0.05, 18), m, 0, -0.17, 0);
3776
5811
  });
@@ -3880,17 +5915,17 @@ var GameCharactersThree = (() => {
3880
5915
  add(arms[1].g, new THREE.CylinderGeometry(0.08, 0.078, 0.08, 18), m, 0, -0.12, 0);
3881
5916
  return;
3882
5917
  },
3883
- tiedsleeves: ({ Bx, U, add, legs, m, ring }) => {
3884
- 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);
3885
5920
  legs.forEach((l) => add(l.g, Bx(0.1, 0.26, 0.05), m, l.s * 0.02, -0.1, 0.105));
3886
5921
  return;
3887
5922
  },
3888
- 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 }) => {
3889
5924
  {
3890
5925
  const g = torsoGeo(fem);
3891
5926
  g.scale(1.06, 1, 1.12);
3892
5927
  add(U, g, m, 0, 0, 0);
3893
- 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);
3894
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));
3895
5930
  add(U, Bx(0.025, 0.62, 0.012), cmat(10132114), 0, 1.2, 0.19);
3896
5931
  arms.forEach((a) => {
@@ -3980,8 +6015,8 @@ var GameCharactersThree = (() => {
3980
6015
  add(U, Bx(0.05, 0.75, 0.02), cmat(4864546), 0, 1.22, 0.195, 0, 0, -0.75);
3981
6016
  return;
3982
6017
  },
3983
- scarf: ({ PI, THREE, U, add, m, ring }) => {
3984
- 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);
3985
6020
  add(U, new THREE.ConeGeometry(0.08, 0.14, 3), m, 0, 1.47, 0.15, PI, 0, 0);
3986
6021
  return;
3987
6022
  },
@@ -4024,12 +6059,12 @@ var GameCharactersThree = (() => {
4024
6059
  return;
4025
6060
  }
4026
6061
  },
4027
- refl: ({ Bx, THREE, U, add, cmat, m, ring }) => {
6062
+ refl: ({ Bx, THREE, U, add, cmat, m, ring: ring2 }) => {
4028
6063
  {
4029
6064
  const v = add(U, new THREE.CylinderGeometry(0.287, 0.252, 0.46, 20), m, 0, 1.3, 0);
4030
6065
  v.scale.set(1.13, 1, 0.72);
4031
- ring(U, 0.29, 0.035, cmat(13159632, { metalness: 0.3, roughness: 0.4 }), 1.2, 1.13, 0.73);
4032
- 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);
4033
6068
  add(U, Bx(0.17, 0.055, 0.02), cmat(1714794), 0, 1.47, 0.205);
4034
6069
  return;
4035
6070
  }
@@ -4129,9 +6164,10 @@ var GameCharactersThree = (() => {
4129
6164
  EXTRAS.dbl_front = EXTRAS.rifle_front;
4130
6165
 
4131
6166
  // src/rich/person-kit.ts
4132
- var createPersonKit = (THREE, { random: R, createCanvas = () => document.createElement("canvas") }) => {
6167
+ var createPersonKit = (host, { random: R, createCanvas = () => document.createElement("canvas") }) => {
6168
+ const THREE = shapeGeometries(host);
4133
6169
  const T = THREE;
4134
- const scaleHex = (hex2, factor) => {
6170
+ const scaleHex2 = (hex2, factor) => {
4135
6171
  const channel = (shift) => (hex2 >> shift & 255) / 255 * factor * 255;
4136
6172
  return channel(16) << 16 ^ channel(8) << 8 ^ channel(0) << 0;
4137
6173
  };
@@ -4188,7 +6224,7 @@ var GameCharactersThree = (() => {
4188
6224
  function ball(parent, r, m, x, y, z) {
4189
6225
  return add(parent, new THREE.SphereGeometry(r, SEG, 12), m, x || 0, y || 0, z || 0);
4190
6226
  }
4191
- function ring(parent, r, h, m, y, sx, sz) {
6227
+ function ring2(parent, r, h, m, y, sx, sz) {
4192
6228
  const o = add(parent, new THREE.CylinderGeometry(r, r, h, 20), m, 0, y, 0);
4193
6229
  o.scale.set(sx || 1.12, 1, sz || 0.7);
4194
6230
  return o;
@@ -4234,17 +6270,17 @@ var GameCharactersThree = (() => {
4234
6270
  const k = c + "|" + o;
4235
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 || {})));
4236
6272
  }
4237
- function splat(parent, x, y, z, r, color, n, out, kind) {
4238
- 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) => {
4239
6275
  o.castShadow = false;
4240
6276
  if (out) out.push(o);
4241
6277
  return o;
4242
6278
  };
4243
6279
  const sy = 0.8 + R() * 0.4, seed = R() * 10;
4244
- 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));
4245
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));
4246
6282
  if (!skin) {
4247
- 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));
4248
6284
  }
4249
6285
  for (let k = 0; k < (n || 0); k++) {
4250
6286
  const ang = R() * 6.28, d = r * (1.2 + R() * 0.9), rr = r * (0.16 + R() * 0.2);
@@ -4261,14 +6297,15 @@ var GameCharactersThree = (() => {
4261
6297
  }
4262
6298
  return a;
4263
6299
  }
4264
- 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 };
4265
6301
  };
4266
6302
 
4267
6303
  // src/rich/person-builder.ts
4268
6304
  var PAGE_EYES = { lento: 14926657, corredor: 15022379, brutamonte: 15698474 };
4269
- var createPersonBuilder = (THREE, options = {}) => {
6305
+ var createPersonBuilder = (host, options = {}) => {
6306
+ const THREE = shapeGeometries(host);
4270
6307
  const kit = createPersonKit(THREE, { random: options.random ?? createRng(77), createCanvas: options.createCanvas });
4271
- 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;
4272
6309
  const reduce = options.reducedMotion ?? false;
4273
6310
  const detailed = (options.detail ?? 0) === 0;
4274
6311
  const EYE = { ...PAGE_EYES, ...options.zombieEyes };
@@ -4369,7 +6406,7 @@ var GameCharactersThree = (() => {
4369
6406
  const ridge = ball(Hd, 0.1, skinM, 0, 1.842, 0.105);
4370
6407
  ridge.scale.set(1.3, 0.28, 0.55);
4371
6408
  add(Hd, new THREE.SphereGeometry(0.021, 10, 8), skinM, 0, 1.762, 0.182);
4372
- 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);
4373
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);
4374
6411
  bags.castShadow = false;
4375
6412
  const hc = cmat(sp.hair.c), hs = sp.hair.s;
@@ -4406,7 +6443,7 @@ var GameCharactersThree = (() => {
4406
6443
  t.rotation.x = 0.25;
4407
6444
  }
4408
6445
  const f = sp.face || [];
4409
- 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 });
4410
6447
  if (sp.hat) {
4411
6448
  const k = sp.hat.k, c = cmat(sp.hat.c);
4412
6449
  HATS.find((hat) => hat.kinds.includes(k))?.apply({ THREE, PI, Hd, add, Bx, cmat, cap, c, k, sp });
@@ -4445,7 +6482,7 @@ var GameCharactersThree = (() => {
4445
6482
  for (const e of sp.ex || []) {
4446
6483
  const [k, c] = e;
4447
6484
  const m = c !== void 0 ? cmat(c) : null;
4448
- 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 });
4449
6486
  }
4450
6487
  if (sp.back === "shotgun") {
4451
6488
  const g = new THREE.Group();
@@ -4625,9 +6662,9 @@ var GameCharactersThree = (() => {
4625
6662
  // src/eyes.ts
4626
6663
  var GLOW_SIZE = 64;
4627
6664
  var createGlowTexture = (three, createCanvas) => {
4628
- const make = createCanvas ?? (typeof document === "undefined" ? void 0 : () => document.createElement("canvas"));
4629
- if (!make) return null;
4630
- const canvas = make();
6665
+ const make2 = createCanvas ?? (typeof document === "undefined" ? void 0 : () => document.createElement("canvas"));
6666
+ if (!make2) return null;
6667
+ const canvas = make2();
4631
6668
  canvas.width = canvas.height = GLOW_SIZE;
4632
6669
  const context = canvas.getContext("2d");
4633
6670
  if (!context) return null;
@@ -4639,35 +6676,36 @@ var GameCharactersThree = (() => {
4639
6676
  context.fillRect(0, 0, GLOW_SIZE, GLOW_SIZE);
4640
6677
  return new three.CanvasTexture(canvas);
4641
6678
  };
4642
- 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);
4643
6681
  const eye = new three.Group();
4644
- 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 }));
4645
6683
  ball.userData.eye = 1;
4646
6684
  eye.add(ball);
4647
6685
  const size = glow ?? radius * 5;
4648
6686
  if (size > 0) {
4649
- 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 }));
4650
6688
  sprite.scale.setScalar(size);
4651
6689
  sprite.userData.eyeGlow = 1;
4652
6690
  eye.add(sprite);
4653
6691
  }
4654
6692
  return eye;
4655
6693
  };
4656
- var isEye = (object) => object.userData.eye === 1 || object.userData.eye === true;
6694
+ var isEye = (object2) => object2.userData.eye === 1 || object2.userData.eye === true;
4657
6695
  var findEyes = (three, root) => {
4658
6696
  const markable = [];
4659
6697
  const glows = [];
4660
6698
  const base = /* @__PURE__ */ new Map();
4661
- root.traverse((object) => {
4662
- const mesh = object;
4663
- if (mesh.isMesh && isEye(object)) markable.push(mesh);
4664
- const sprite = object;
6699
+ root.traverse((object2) => {
6700
+ const mesh2 = object2;
6701
+ if (mesh2.isMesh && isEye(object2)) markable.push(mesh2);
6702
+ const sprite = object2;
4665
6703
  if (sprite.isSprite && sprite.material.blending === three.AdditiveBlending) glows.push(sprite);
4666
6704
  });
4667
6705
  const remember = (material) => {
4668
6706
  if (material.color && !base.has(material)) base.set(material, { color: material.color.clone(), opacity: material.opacity });
4669
6707
  };
4670
- markable.forEach((mesh) => remember(mesh.material));
6708
+ markable.forEach((mesh2) => remember(mesh2.material));
4671
6709
  glows.forEach((sprite) => remember(sprite.material));
4672
6710
  const setBrightness = (level) => {
4673
6711
  const factor = Math.min(1, Math.max(0, level));
@@ -4687,14 +6725,14 @@ var GameCharactersThree = (() => {
4687
6725
  on: () => setBrightness(1),
4688
6726
  isolate(only) {
4689
6727
  if (!only) {
4690
- hidden.splice(0).forEach((object) => object.visible = true);
6728
+ hidden.splice(0).forEach((object2) => object2.visible = true);
4691
6729
  return;
4692
6730
  }
4693
- root.traverse((object) => {
4694
- const mesh = object;
4695
- if (mesh.isMesh && !isEye(object) && object.visible) {
4696
- object.visible = false;
4697
- 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);
4698
6736
  }
4699
6737
  });
4700
6738
  }
@@ -4814,9 +6852,9 @@ var GameCharactersThree = (() => {
4814
6852
  group.add(end);
4815
6853
  strands.push(end);
4816
6854
  }
4817
- group.traverse((object) => {
4818
- object.userData.stump = 1;
4819
- if (object.isMesh) object.castShadow = true;
6855
+ group.traverse((object2) => {
6856
+ object2.userData.stump = 1;
6857
+ if (object2.isMesh) object2.castShadow = true;
4820
6858
  });
4821
6859
  return strands;
4822
6860
  };
@@ -4831,15 +6869,15 @@ var GameCharactersThree = (() => {
4831
6869
  const group = new three.Group();
4832
6870
  group.position.y = y;
4833
6871
  parent.add(group);
4834
- const torus = new three.Mesh(new three.TorusGeometry(radius, 0.022, 8, 18), materials.wound);
4835
- torus.rotation.x = Math.PI / 2;
4836
- 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);
4837
6875
  for (let k = 0; k < 3; k++) {
4838
6876
  const strip = new three.Mesh(new three.CylinderGeometry(8e-3, 8e-3, 0.12, 6), materials.wound);
4839
6877
  strip.position.set((k - 1) * 0.03, 0.03, 0.02);
4840
6878
  group.add(strip);
4841
6879
  }
4842
- group.traverse((object) => object.userData.stump = 1);
6880
+ group.traverse((object2) => object2.userData.stump = 1);
4843
6881
  return group;
4844
6882
  };
4845
6883
 
@@ -4858,8 +6896,8 @@ var GameCharactersThree = (() => {
4858
6896
  const trim = () => {
4859
6897
  while (pieces.length > max) pieces.shift()?.object.removeFromParent();
4860
6898
  };
4861
- const add = (object, velocity, spin, tag) => {
4862
- 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 } : {} };
4863
6901
  pieces.push(piece);
4864
6902
  trim();
4865
6903
  return piece;
@@ -4936,8 +6974,8 @@ var GameCharactersThree = (() => {
4936
6974
  };
4937
6975
  var exitWound = (three, materials, random, segment, point, direction, damage) => {
4938
6976
  const meshes = [];
4939
- segment.traverse((object) => {
4940
- 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);
4941
6979
  });
4942
6980
  const raycaster = new three.Raycaster(point.clone().addScaledVector(direction, 0.6), direction.clone().negate(), 0, 0.6);
4943
6981
  const hit = raycaster.intersectObjects(meshes)[0];
@@ -4982,9 +7020,9 @@ var GameCharactersThree = (() => {
4982
7020
  crater.userData.wound = 1;
4983
7021
  return crater;
4984
7022
  };
4985
- var explodeChunks = (three, materials, random, box, direction, fling) => {
4986
- const centre = box.getCenter(new three.Vector3());
4987
- 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();
4988
7026
  const chunkMaterials = [materials.flesh, materials.bruise, materials.bone, materials.flesh, materials.meat];
4989
7027
  for (let i = 0; i < 14; i++) {
4990
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]);
@@ -5017,7 +7055,7 @@ var GameCharactersThree = (() => {
5017
7055
  };
5018
7056
 
5019
7057
  // src/wounds/wounds.ts
5020
- var worldPosition = (three, object) => object.getWorldPosition(new three.Vector3());
7058
+ var worldPosition = (three, object2) => object2.getWorldPosition(new three.Vector3());
5021
7059
  var createWounds = (three, options) => {
5022
7060
  const { random, scene: scene2, bridge, sound } = options;
5023
7061
  const materials = options.materials ?? createWoundMaterials(three);
@@ -5028,11 +7066,11 @@ var GameCharactersThree = (() => {
5028
7066
  if (!found) throw new Error("game-characters-three: this body is not tracked by the wounds (call `track` first)");
5029
7067
  return found;
5030
7068
  };
5031
- const burstBlood = (state, change, object, direction) => {
5032
- const point = worldPosition(three, object);
7069
+ const burstBlood = (state, change, object2, direction) => {
7070
+ const point = worldPosition(three, object2);
5033
7071
  bridge?.burst(change, [point.x, point.y, point.z], state.body.blood, direction ? [direction.x, direction.y, direction.z] : void 0);
5034
7072
  };
5035
- 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);
5036
7074
  const hideBelow = (state, id) => {
5037
7075
  for (const below2 of segmentsBelow(id)) state.gone.add(below2);
5038
7076
  };
@@ -5066,8 +7104,8 @@ var GameCharactersThree = (() => {
5066
7104
  const target = state.body.nodes[id];
5067
7105
  if (!target || state.gone.has(id)) return;
5068
7106
  const { node, radius, flip } = target;
5069
- const box = new three.Box3().setFromObject(node);
5070
- 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) => {
5071
7109
  scene2.add(chunk);
5072
7110
  flying.throwObject(chunk, velocity, spin, id);
5073
7111
  });
@@ -5726,7 +7764,7 @@ var GameCharactersThree = (() => {
5726
7764
  batches = variants.map((variant) => createVariantBatches(three, variant, time));
5727
7765
  for (const set of batches) for (const batch of set) group.add(batch.mesh);
5728
7766
  };
5729
- const color = (hex2) => new three.Color(hex2);
7767
+ const color2 = (hex2) => new three.Color(hex2);
5730
7768
  return {
5731
7769
  group,
5732
7770
  spawn(count) {
@@ -5757,7 +7795,7 @@ var GameCharactersThree = (() => {
5757
7795
  const variant = variants[member.variant];
5758
7796
  const distance3 = Math.hypot(member.x - camera.position.x, member.z - camera.position.z);
5759
7797
  const level = lodAt(distance3, LOD_DISTANCES);
5760
- const eye = color(eyes[variant.typeId] ?? 14926657);
7798
+ const eye = color2(eyes[variant.typeId] ?? 14926657);
5761
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 });
5762
7800
  }
5763
7801
  for (const set of batches) for (const batch of set) batch.end();
@@ -5822,6 +7860,58 @@ var GameCharactersThree = (() => {
5822
7860
  return spec;
5823
7861
  };
5824
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
+
5825
7915
  // src/test-area/scenarios.ts
5826
7916
  var LIMB_SEGMENTS = ["upperArmL", "forearmL", "handL", "upperArmR", "forearmR", "handR", "thighL", "shinL", "footL", "thighR", "shinR", "footR"];
5827
7917
  var BENCHMARK_BODIES = 1e3;
@@ -5899,8 +7989,8 @@ var GameCharactersThree = (() => {
5899
7989
  const colors = (decay) => {
5900
7990
  const root = deps.buildZombie(deps.typeNames()[0], decay);
5901
7991
  const seen = /* @__PURE__ */ new Set();
5902
- root.traverse((object) => {
5903
- const material = object.material;
7992
+ root.traverse((object2) => {
7993
+ const material = object2.material;
5904
7994
  if (material?.color) seen.add(material.color.getHexString());
5905
7995
  });
5906
7996
  return [...seen].sort().join(",");
@@ -6155,12 +8245,12 @@ var GameCharactersThree = (() => {
6155
8245
  return built.root;
6156
8246
  },
6157
8247
  impl: (root, id) => {
6158
- const object = root;
6159
- const made = builtOf.get(object);
8248
+ const object2 = root;
8249
+ const made = builtOf.get(object2);
6160
8250
  const character = createCharacter(made.kind, made.cardId, id);
6161
8251
  const scale = character.spec.height / kit.body.heightMetres;
6162
- if (Math.abs(scale - 1) > 0.01) object.scale.setScalar(scale);
6163
- 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 };
6164
8254
  entry.character = wrap(entry, character);
6165
8255
  const age = made.kind === "zombie" ? undead?.traitsOf(character)?.age : void 0;
6166
8256
  const blood = age !== void 0 ? options.bloodOf?.(age) : void 0;
@@ -6178,7 +8268,7 @@ var GameCharactersThree = (() => {
6178
8268
  return undead.speedFor(traits, { moment: MOMENTS_WITH_LIMP.has(moment) ? "chase" : moment, limp: moment === "limp", crawling: moment === "crawl" || entry.character.limping.length > 1 });
6179
8269
  };
6180
8270
  const clearOverlays = () => {
6181
- for (const object of overlays.values()) object.parent?.remove(object);
8271
+ for (const object2 of overlays.values()) object2.parent?.remove(object2);
6182
8272
  overlays.clear();
6183
8273
  };
6184
8274
  const overlayFor = (layer, entry) => {
@@ -6189,16 +8279,16 @@ var GameCharactersThree = (() => {
6189
8279
  for (const part of entry.character.describe().parts) {
6190
8280
  const shape = part.shape;
6191
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);
6192
- const mesh = new three.Mesh(geometry, material);
6193
- mesh.position.set(...part.position);
6194
- if (part.rotation) mesh.rotation.set(...part.rotation);
6195
- 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);
6196
8286
  }
6197
8287
  } else if (layer === "joints") {
6198
8288
  for (const joint of Object.values(entry.character.rig.joints)) {
6199
- const mesh = new three.Mesh(new three.SphereGeometry(0.025, 6, 4), material);
6200
- mesh.position.set(...joint);
6201
- 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);
6202
8292
  }
6203
8293
  } else if (layer === "speed") {
6204
8294
  const length = Math.max(0.1, speedOf(entry));
@@ -6225,6 +8315,17 @@ var GameCharactersThree = (() => {
6225
8315
  };
6226
8316
  const animate = (entry, dt) => {
6227
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
+ }
6228
8329
  if (!character.alive) {
6229
8330
  entry.tilt = Math.min(1, entry.tilt + dt * 2);
6230
8331
  const rig = root.userData.rig;
@@ -6430,6 +8531,15 @@ var GameCharactersThree = (() => {
6430
8531
  wounds = createWounds(lent.THREE, { random, scene: scene2, groundAt: (x, z) => lent.groundAt(x, z), ...bridge ? { bridge } : {}, ...sound ? { sound } : {} });
6431
8532
  for (const entry of entries.values()) trackEntry(entry);
6432
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
+ });
6433
8543
  const stopFrame = lent.onFrame((dt) => {
6434
8544
  time += dt;
6435
8545
  for (const [id, entry] of entries) {
@@ -6445,6 +8555,7 @@ var GameCharactersThree = (() => {
6445
8555
  });
6446
8556
  return () => {
6447
8557
  stopChange?.();
8558
+ stopEvents();
6448
8559
  stopFrame();
6449
8560
  clearOverlays();
6450
8561
  wounds?.dispose();
@@ -6480,6 +8591,1440 @@ var GameCharactersThree = (() => {
6480
8591
  var registerBodyMaterial = (world) => {
6481
8592
  if (!world.materials.has(BODY_MATERIAL_DEF.id)) world.materials.set(BODY_MATERIAL_DEF.id, BODY_MATERIAL_DEF);
6482
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
+ pose: {
8613
+ armL: 0,
8614
+ armR: 0,
8615
+ elbL: -0.12,
8616
+ elbR: -0.12,
8617
+ armOut: 0.11,
8618
+ lean: 0.04,
8619
+ headX: 0,
8620
+ headZ: 0
8621
+ }
8622
+ },
8623
+ shirtColor: "3d5a73"
8624
+ };
8625
+
8626
+ // src/player/avatar.ts
8627
+ var TWO_PI2 = Math.PI * 2;
8628
+ var MAX_GAIT = 1.4;
8629
+ var CLIP_BLEND = 0.12;
8630
+ var FALL_SECONDS2 = 0.3;
8631
+ var HIP_HEIGHT = 0.95;
8632
+ var WALK_ARM = 0.28;
8633
+ var WALK_BOB = 0.035;
8634
+ var WALK_LEAN = 0.04;
8635
+ var RUN_LEAN = 0.16;
8636
+ var RUN_BOB = 0.05;
8637
+ var REST_ARM_Z = 0.18;
8638
+ var CROUCH = { thigh: -0.95, thighWalk: 0.3, shin: 1.9, lean: 0.25, drop: -0.35 };
8639
+ var AIMED = { shoulder: -1.42, perAim: 0.85, swing: 0.02, zRight: -0.54, zLeft: 0.36, elbowRight: -0.04, elbowLeft: -0.12 };
8640
+ 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 };
8641
+ var HAND_OFFSET = { x: 0, y: -0.33, z: 0.04 };
8642
+ var hexOf = (value) => typeof value === "string" ? Number.parseInt(value, 16) : value;
8643
+ var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
8644
+ var fract = (value) => value - Math.floor(value);
8645
+ var createPlayerAvatar = (THREE, options = {}) => {
8646
+ const pose = {
8647
+ armL: 0,
8648
+ armR: 0,
8649
+ elbL: -0.08,
8650
+ elbR: -0.08,
8651
+ lean: 0.04,
8652
+ headX: 0,
8653
+ headZ: 0,
8654
+ ...player_avatar_default.spec.pose,
8655
+ ...options.spec?.pose
8656
+ };
8657
+ const spec = { ...player_avatar_default.spec, ...options.spec, pose };
8658
+ for (const key of ["skin", "hair"]) if (typeof spec[key] === "string") spec[key] = hexOf(spec[key]);
8659
+ const best = createBestBuilder(THREE, { types: [{ name: String(spec.type), eye: 0 }], random: createRng(Number(spec.seed ?? 1)) });
8660
+ const body = best.build(spec);
8661
+ best.topM().color.setHex(options.shirtColor ?? hexOf(player_avatar_default.shirtColor));
8662
+ const rig = body.userData.rig;
8663
+ const profile = { f: 1.1, a: 0.28, k: 0.35, arm: WALK_ARM, bob: WALK_BOB };
8664
+ const animator = createRigAnimator({ gaits: { [rig.type]: profile } });
8665
+ const clips = options.clips ?? createPoseClipRegistry(POSE_CLIPS);
8666
+ const blendDefault = options.blend ?? CLIP_BLEND;
8667
+ const fallSeconds = options.fallSeconds ?? FALL_SECONDS2;
8668
+ const smooth = options.cascade ?? true;
8669
+ const root = new THREE.Group();
8670
+ const tilt = new THREE.Group();
8671
+ tilt.add(body);
8672
+ root.add(tilt);
8673
+ const colorOf2 = (object2) => object2?.material?.color?.getHex();
8674
+ const meshesOf = (node) => node.children.filter((child) => child.isMesh);
8675
+ const shirt = options.shirtColor ?? hexOf(player_avatar_default.shirtColor);
8676
+ const shoe = meshesOf(rig.legs[0].kn).find((mesh2) => mesh2.scale.z > 1.5);
8677
+ const forearm = colorOf2(meshesOf(rig.arms[1].el)[0]);
8678
+ const colors = {
8679
+ skin: Number(spec.skin),
8680
+ shirt,
8681
+ trousers: colorOf2(meshesOf(rig.legs[0].g)[0]) ?? 2962496,
8682
+ shoes: colorOf2(shoe) ?? 1841690,
8683
+ longSleeves: forearm === shirt
8684
+ };
8685
+ const sockets = { R: new THREE.Object3D(), L: new THREE.Object3D() };
8686
+ const armOf = { R: rig.arms[1], L: rig.arms[0] };
8687
+ for (const side of ["R", "L"]) {
8688
+ sockets[side].name = `hand_${side}`;
8689
+ sockets[side].position.set(HAND_OFFSET.x, HAND_OFFSET.y, HAND_OFFSET.z);
8690
+ armOf[side].el.add(sockets[side]);
8691
+ }
8692
+ const addMesh = (parent, geometry, material, x = 0, y = 0, z = 0, rx = 0, ry = 0, rz = 0) => {
8693
+ const mesh2 = new THREE.Mesh(geometry, material);
8694
+ mesh2.position.set(x, y, z);
8695
+ if (rx || ry || rz) mesh2.rotation.set(rx, ry, rz);
8696
+ mesh2.castShadow = true;
8697
+ mesh2.receiveShadow = true;
8698
+ parent.add(mesh2);
8699
+ return mesh2;
8700
+ };
8701
+ const hands = [];
8702
+ rig.arms.forEach((arm, index) => {
8703
+ const el = arm.el;
8704
+ const side = index === 0 ? 1 : -1;
8705
+ const oldHand = meshesOf(el).find((mesh2) => Math.abs(mesh2.position.y + 0.33) < 0.025);
8706
+ const handMaterial = oldHand?.material ?? new THREE.MeshLambertMaterial({ color: colors.skin });
8707
+ if (oldHand) {
8708
+ oldHand.geometry?.dispose();
8709
+ el.remove(oldHand);
8710
+ }
8711
+ const hg = new THREE.Group();
8712
+ hg.name = side > 0 ? "hand_group_L" : "hand_group_R";
8713
+ hg.position.set(side * 0.02, -0.3, 0.01);
8714
+ el.add(hg);
8715
+ const palm = addMesh(hg, new THREE.SphereGeometry(0.048, 14, 10), handMaterial, 0, -0.035, 0);
8716
+ palm.scale.set(0.6, 1.05, 1);
8717
+ const built = buildHand({ THREE, add: addMesh, hg, handM: handMaterial, s: side, detailed: true });
8718
+ hands.push({ side, hg, fingers: built.fingers, th: built.th });
8719
+ });
8720
+ const setHandGrip = (hand, grip, wristX = 0) => {
8721
+ hand.fingers.forEach((finger, j) => {
8722
+ finger.rotation.z = -hand.side * grip * (j % 2 ? 1.1 : 0.9);
8723
+ });
8724
+ if (hand.th) hand.th.rotation.z = -hand.side * (0.32 + grip * 0.25);
8725
+ hand.hg.rotation.x = wristX;
8726
+ };
8727
+ const legRestX = rig.legs.map((leg) => leg.g.position.x);
8728
+ const legSide = (index) => index === 0 ? 1 : -1;
8729
+ let cycles = 0;
8730
+ let time = 0;
8731
+ let fall = 0;
8732
+ let run = null;
8733
+ const listeners = /* @__PURE__ */ new Set();
8734
+ const emit = (event, onEvent) => {
8735
+ onEvent?.(event);
8736
+ for (const listener of listeners) listener(event);
8737
+ };
8738
+ const readPose = () => ({
8739
+ lean: rig.upper.rotation.x,
8740
+ twist: rig.upper.rotation.y,
8741
+ side: rig.upper.rotation.z,
8742
+ drop: rig.fig.position.y - rig.dropBase,
8743
+ headX: rig.headG.rotation.x,
8744
+ headY: rig.headG.rotation.y,
8745
+ headZ: rig.headG.rotation.z,
8746
+ armR: rig.arms[0].g.rotation.x,
8747
+ armL: rig.arms[1].g.rotation.x,
8748
+ elbR: rig.arms[0].el.rotation.x,
8749
+ elbL: rig.arms[1].el.rotation.x,
8750
+ armRz: rig.arms[0].g.rotation.z,
8751
+ armLz: rig.arms[1].g.rotation.z,
8752
+ legL: rig.legs[0].g.rotation.x,
8753
+ legR: rig.legs[1].g.rotation.x,
8754
+ kneeL: rig.legs[0].kn.rotation.x,
8755
+ kneeR: rig.legs[1].kn.rotation.x
8756
+ });
8757
+ const armed = (pitch, gait, hip) => {
8758
+ const aim = clamp((pitch + 1) / 3, 0, 0.99) * 3 - 1;
8759
+ const shoulder = AIMED.shoulder + aim * AIMED.perAim + AIMED.swing * Math.sin(cycles * TWO_PI2) * gait;
8760
+ rig.legs.forEach((leg, index) => {
8761
+ const x = legRestX[index];
8762
+ leg.g.rotation.y = hip;
8763
+ leg.g.position.x = x * Math.cos(hip);
8764
+ leg.g.position.z = -x * Math.sin(hip);
8765
+ });
8766
+ return { armR: shoulder, armL: shoulder, armRz: AIMED.zRight, armLz: AIMED.zLeft, elbR: AIMED.elbowRight, elbL: AIMED.elbowLeft };
8767
+ };
8768
+ const holdingPose = (gait, itemUse) => {
8769
+ const bob = Math.sin(cycles * TWO_PI2) * 0.05 * gait;
8770
+ if (!itemUse) {
8771
+ return { armL: -0.45 + bob, armLz: 0.22, elbL: -1.05 };
8772
+ }
8773
+ const { id, position, rotation } = itemUse;
8774
+ if (id === "drink" || id === "sip" || id === "chug") {
8775
+ const raise2 = clamp((position[1] + 0.2) / 0.22, 0, 1);
8776
+ const tilt3 = clamp(Math.abs(rotation[0]) / 1.22, 0, 1.15);
8777
+ return {
8778
+ armL: -0.45 - 0.95 * raise2 - 0.22 * tilt3,
8779
+ armLz: 0.22 + 0.44 * raise2,
8780
+ elbL: -1.05 - 0.85 * raise2 + 0.12 * tilt3,
8781
+ headX: -0.26 * tilt3
8782
+ };
8783
+ }
8784
+ if (id === "open" || id === "close") {
8785
+ const reach = clamp((0.22 - position[0]) / 0.12, 0, 1);
8786
+ return {
8787
+ armL: -0.45 - 0.35 * reach,
8788
+ armLz: 0.22 + 0.28 * reach,
8789
+ elbL: -1.05 - 0.25 * reach,
8790
+ armR: -0.78 * reach,
8791
+ armRz: -0.48 * reach,
8792
+ elbR: -1.25 * reach
8793
+ };
8794
+ }
8795
+ const raise = clamp((position[1] + 0.2) / 0.25, 0, 1);
8796
+ const tilt2 = clamp(Math.abs(rotation[0]) / 1.75, 0, 1.2);
8797
+ const ext = Math.max(raise, tilt2 * 0.75);
8798
+ return {
8799
+ armL: -0.45 - 0.48 * ext,
8800
+ armLz: 0.22 + 0.08 * ext,
8801
+ elbL: -1.05 + 0.38 * ext
8802
+ };
8803
+ };
8804
+ const resetLegYaw = () => {
8805
+ rig.legs.forEach((leg, index) => {
8806
+ leg.g.rotation.y = 0;
8807
+ leg.g.position.x = legRestX[index];
8808
+ leg.g.position.z = 0;
8809
+ });
8810
+ };
8811
+ const runningPose = (gait, busyHands = false) => {
8812
+ const ph = cycles * TWO_PI2;
8813
+ const sine = Math.sin(ph);
8814
+ const cosine = Math.cos(ph);
8815
+ const legL = sine * 0.65 * gait;
8816
+ const legR = -sine * 0.65 * gait;
8817
+ const kneeL = Math.max(0, -cosine) * 1.15 * gait;
8818
+ const kneeR = Math.max(0, cosine) * 1.15 * gait;
8819
+ const targets = {
8820
+ lean: RUN_LEAN * Math.min(1, gait),
8821
+ drop: Math.abs(cosine) * RUN_BOB * gait,
8822
+ legL,
8823
+ legR,
8824
+ kneeL,
8825
+ kneeR
8826
+ };
8827
+ if (!busyHands) {
8828
+ targets.armR = -0.32 - sine * 0.65 * gait;
8829
+ targets.armL = -0.32 + sine * 0.65 * gait;
8830
+ targets.elbR = -1.25 + Math.max(0, sine) * 0.3 * gait;
8831
+ targets.elbL = -1.25 + Math.max(0, -sine) * 0.3 * gait;
8832
+ targets.armRz = 0.22;
8833
+ targets.armLz = -0.22;
8834
+ }
8835
+ return targets;
8836
+ };
8837
+ const crouchPose = (gait) => {
8838
+ const swing = (leg) => {
8839
+ const legS = legSide(leg);
8840
+ return CROUCH.thigh - Math.sin(cycles * TWO_PI2) * legS * CROUCH.thighWalk * gait;
8841
+ };
8842
+ return {
8843
+ legL: swing(0),
8844
+ legR: swing(1),
8845
+ kneeL: CROUCH.shin,
8846
+ kneeR: CROUCH.shin,
8847
+ lean: WALK_LEAN * gait + CROUCH.lean,
8848
+ drop: Math.abs(Math.sin(cycles * TWO_PI2)) * WALK_BOB * gait + CROUCH.drop
8849
+ };
8850
+ };
8851
+ const downPose = () => {
8852
+ const ph = cycles * TWO_PI2;
8853
+ const gait = 1;
8854
+ const leg = (index) => {
8855
+ const legS = legSide(index);
8856
+ const walkS = Math.sin(ph) * legS;
8857
+ 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;
8858
+ return { hip: -walkS * DOWN.thighWalk * gait, knee: bend };
8859
+ };
8860
+ const arm = (index) => {
8861
+ const side = index === 0 ? 1 : -1;
8862
+ const armS = Math.sin(ph) * (side > 0 ? 1 : -1);
8863
+ const shoulder = fract(cycles * 5) > 0.5 && side > 0 ? DOWN.armHigh : DOWN.armLow + DOWN.armWave * Math.sin(cycles * 5 + side);
8864
+ return { shoulder, z: side * (DOWN.armZ + DOWN.armZWave * Math.sin(cycles * 3)), elbow: -0.35 - Math.max(0, armS) * 0.4 * gait };
8865
+ };
8866
+ const [l, r] = [leg(0), leg(1)];
8867
+ const [a0, a1] = [arm(0), arm(1)];
8868
+ return {
8869
+ legL: l.hip,
8870
+ kneeL: l.knee,
8871
+ legR: r.hip,
8872
+ kneeR: r.knee,
8873
+ armR: a0.shoulder,
8874
+ armRz: a0.z,
8875
+ elbR: a0.elbow,
8876
+ armL: a1.shoulder,
8877
+ armLz: a1.z,
8878
+ elbL: a1.elbow,
8879
+ lean: WALK_LEAN * gait,
8880
+ drop: Math.abs(Math.sin(ph)) * WALK_BOB * gait
8881
+ };
8882
+ };
8883
+ const placeBody = (progress) => {
8884
+ const fk = progress * progress * (3 - 2 * progress);
8885
+ const flip = fract(cycles * 1.7) >= 0.5 ? 1 : 0;
8886
+ tilt.rotation.set((-DOWN.tilt + flip * 2 * DOWN.tilt) * fk, 0, Math.sin(cycles * 7) * DOWN.roll * fk, "XYZ");
8887
+ const hip = new THREE.Vector3(0, HIP_HEIGHT, 0);
8888
+ const target = new THREE.Vector3(0, DOWN.hipY, -DOWN.hipZ + flip * DOWN.hipZFlip);
8889
+ const place = new THREE.Vector3(0, HIP_HEIGHT * (1 - fk), 0).addScaledVector(target, fk);
8890
+ tilt.position.copy(place.sub(hip.applyEuler(tilt.rotation)));
8891
+ };
8892
+ const fireClipEvents = (r, from, to) => {
8893
+ for (const event of clipEventsBetween(r.clip, from, to)) emit({ ...event, clip: r.clip.id }, r.onEvent);
8894
+ };
8895
+ const stepClip = (dt, down) => {
8896
+ if (!run) return;
8897
+ const r = run;
8898
+ const from = r.time;
8899
+ r.time += dt;
8900
+ const { duration } = r.clip;
8901
+ if (r.clip.loop && r.time > duration) {
8902
+ fireClipEvents(r, from, duration);
8903
+ r.time -= duration * Math.floor(r.time / duration);
8904
+ fireClipEvents(r, -1e-9, r.time);
8905
+ } else {
8906
+ fireClipEvents(r, from, Math.min(r.time, duration));
8907
+ if (r.time >= duration && !r.clip.loop) r.target = 0;
8908
+ }
8909
+ r.weight = r.blend <= 0 ? r.target : clamp(r.weight + (r.target ? dt : -dt) / r.blend, 0, 1);
8910
+ if (r.target === 0 && r.weight <= 0) {
8911
+ run = null;
8912
+ return;
8913
+ }
8914
+ if (down) return;
8915
+ const sampled = filterPoseChannels(samplePoseClip(r.clip, Math.min(r.time, duration)), r.clip.channels ?? "full");
8916
+ const current = readPose();
8917
+ const blended = {};
8918
+ for (const [name, value] of Object.entries(sampled)) if (name in current) blended[name] = current[name] + (value - current[name]) * r.weight;
8919
+ animator.setPose(rig, blended);
8920
+ };
8921
+ return {
8922
+ root,
8923
+ rig,
8924
+ colors,
8925
+ three: THREE,
8926
+ get playing() {
8927
+ return run ? run.clip.id : null;
8928
+ },
8929
+ update(dt, state = {}) {
8930
+ const speed = state.speed ?? 0;
8931
+ const moving = speed >= 0.05;
8932
+ const down = !!state.down;
8933
+ const running = Boolean(state.running && moving && !down && !state.crouch);
8934
+ if (moving) cycles += dt * (running ? walkCadence(speed) * 1.3 : walkCadence(speed));
8935
+ const gait = Math.min(MAX_GAIT, walkGait(speed));
8936
+ profile.arm = (running ? 0.55 : WALK_ARM) * gait;
8937
+ profile.bob = (running ? RUN_BOB : WALK_BOB) * gait;
8938
+ time = cycles / (walkCadence(Math.max(speed, 0)) * (running ? 1.3 : 1));
8939
+ animator.animate(body, time, { speed });
8940
+ fall = fallSeconds <= 0 ? down ? 1 : 0 : clamp(fall + (down ? dt : -dt) / fallSeconds, 0, 1);
8941
+ resetLegYaw();
8942
+ if (down) animator.setPose(rig, downPose());
8943
+ else {
8944
+ if (running) animator.setPose(rig, runningPose(gait, Boolean(state.armed || state.holding || state.itemUse)));
8945
+ if (state.crouch) animator.setPose(rig, crouchPose(gait));
8946
+ if (state.armed) animator.setPose(rig, armed(state.pitch ?? 0, gait, state.hip ?? 0));
8947
+ else if (state.holding || state.itemUse) animator.setPose(rig, holdingPose(gait, state.itemUse));
8948
+ else if (!running) {
8949
+ animator.setPose(rig, {
8950
+ armRz: REST_ARM_Z,
8951
+ armLz: -REST_ARM_Z,
8952
+ elbR: -0.12,
8953
+ elbL: -0.12
8954
+ });
8955
+ }
8956
+ }
8957
+ placeBody(fall);
8958
+ stepClip(dt, down);
8959
+ if (smooth) animator.cascade(rig, dt);
8960
+ const clipId = run ? run.clip.id : null;
8961
+ const ph = cycles * TWO_PI2;
8962
+ hands.forEach((hand) => {
8963
+ const isRight = hand.side < 0;
8964
+ const holdRight = isRight && (!!state.holding || !!state.itemUse);
8965
+ const holdLeft = !isRight && (state.itemUse?.id === "open" || state.itemUse?.id === "close");
8966
+ const grip = clipId === "punch_right" ? 1.4 : clipId === "shove_two_hands" ? 0.15 : state.armed || holdRight || holdLeft ? 1.22 : running ? 0.85 : 0.12;
8967
+ const wristSwing = holdRight || state.armed || running ? 0 : -Math.min(1, gait) * Math.sin(ph - 0.6) * 0.12 * hand.side;
8968
+ setHandGrip(hand, grip, wristSwing);
8969
+ });
8970
+ },
8971
+ play(clip, playOptions = {}) {
8972
+ const found = typeof clip === "string" ? clips.get(clip) : clip;
8973
+ if (!found) throw new Error(`Unknown pose clip: ${String(clip)}`);
8974
+ run = { clip: found, time: 0, weight: run?.weight ?? 0, target: 1, blend: playOptions.blend ?? blendDefault, ...playOptions.onEvent ? { onEvent: playOptions.onEvent } : {} };
8975
+ fireClipEvents(run, -1e-9, 0);
8976
+ run.time = 0;
8977
+ },
8978
+ stop() {
8979
+ if (run) run.target = 0;
8980
+ },
8981
+ hand: (side) => sockets[side],
8982
+ on(_type, listener) {
8983
+ listeners.add(listener);
8984
+ return () => void listeners.delete(listener);
8985
+ },
8986
+ dispose() {
8987
+ run = null;
8988
+ listeners.clear();
8989
+ body.traverse((object2) => {
8990
+ const mesh2 = object2;
8991
+ mesh2.geometry?.dispose();
8992
+ const material = mesh2.material;
8993
+ if (Array.isArray(material)) material.forEach((m) => m.dispose());
8994
+ else material?.dispose();
8995
+ });
8996
+ root.removeFromParent();
8997
+ }
8998
+ };
8999
+ };
9000
+
9001
+ // ../game-characters-people/dist/index.js
9002
+ var attack_clips_default = {
9003
+ clips: [
9004
+ {
9005
+ id: "punch_right",
9006
+ source: { authored: "game-kit", note: "authored in the kit; replace with the Elenco team's clip when delivered" },
9007
+ duration: 0.35,
9008
+ loop: false,
9009
+ channels: "upper",
9010
+ keys: [
9011
+ { 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 } },
9012
+ { 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 } },
9013
+ { 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 } },
9014
+ { 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 } },
9015
+ { 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 } }
9016
+ ],
9017
+ events: [
9018
+ { t: 0, type: "phase", data: { label: "attack_clip.phase.windup" } },
9019
+ { t: 0.1, type: "phase", data: { label: "attack_clip.phase.strike" } },
9020
+ { t: 0.16, type: "impact", data: { kind: "punch" } },
9021
+ { t: 0.22, type: "phase", data: { label: "attack_clip.phase.recover" } }
9022
+ ]
9023
+ },
9024
+ {
9025
+ id: "shove_two_hands",
9026
+ source: { authored: "game-kit", note: "authored in the kit; replace with the Elenco team's clip when delivered" },
9027
+ duration: 0.5,
9028
+ loop: false,
9029
+ channels: "upper",
9030
+ keys: [
9031
+ { 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 } },
9032
+ { 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 } },
9033
+ { 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 } },
9034
+ { 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 } },
9035
+ { 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 } }
9036
+ ],
9037
+ events: [
9038
+ { t: 0, type: "phase", data: { label: "attack_clip.phase.windup" } },
9039
+ { t: 0.15, type: "phase", data: { label: "attack_clip.phase.strike" } },
9040
+ { t: 0.26, type: "impact", data: { kind: "shove" } },
9041
+ { t: 0.34, type: "phase", data: { label: "attack_clip.phase.recover" } }
9042
+ ]
9043
+ },
9044
+ {
9045
+ id: "front_kick",
9046
+ source: { authored: "game-kit", note: "authored in the kit; replace with the Elenco team's clip when delivered" },
9047
+ duration: 0.6,
9048
+ loop: false,
9049
+ channels: "full",
9050
+ keys: [
9051
+ { 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 } },
9052
+ { 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 } },
9053
+ { 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 } },
9054
+ { 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 } },
9055
+ { 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 } }
9056
+ ],
9057
+ events: [
9058
+ { t: 0, type: "phase", data: { label: "attack_clip.phase.windup" } },
9059
+ { t: 0.18, type: "phase", data: { label: "attack_clip.phase.strike" } },
9060
+ { t: 0.32, type: "impact", data: { kind: "kick" } },
9061
+ { t: 0.42, type: "phase", data: { label: "attack_clip.phase.recover" } }
9062
+ ]
9063
+ },
9064
+ {
9065
+ id: "recoil_rifle",
9066
+ 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" },
9067
+ duration: 0.22,
9068
+ loop: false,
9069
+ channels: "upper",
9070
+ keys: [
9071
+ { 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 } },
9072
+ { 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 } },
9073
+ { 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 } }
9074
+ ],
9075
+ events: [
9076
+ { t: 0, type: "impact", data: { kind: "shot" } },
9077
+ { t: 0, type: "phase", data: { label: "attack_clip.phase.strike" } },
9078
+ { t: 0.08, type: "phase", data: { label: "attack_clip.phase.recover" } }
9079
+ ]
9080
+ },
9081
+ {
9082
+ id: "recoil_pistol",
9083
+ 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" },
9084
+ duration: 0.18,
9085
+ loop: false,
9086
+ channels: "upper",
9087
+ keys: [
9088
+ { 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 } },
9089
+ { 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 } },
9090
+ { 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 } }
9091
+ ],
9092
+ events: [
9093
+ { t: 0, type: "impact", data: { kind: "shot" } },
9094
+ { t: 0, type: "phase", data: { label: "attack_clip.phase.strike" } },
9095
+ { t: 0.06, type: "phase", data: { label: "attack_clip.phase.recover" } }
9096
+ ]
9097
+ }
9098
+ ],
9099
+ locales: {
9100
+ "pt-BR": {
9101
+ "attack_clip.phase.windup": "Prepara\xE7\xE3o",
9102
+ "attack_clip.phase.strike": "Golpe",
9103
+ "attack_clip.phase.recover": "Recupera\xE7\xE3o"
9104
+ },
9105
+ en: {
9106
+ "attack_clip.phase.windup": "Wind-up",
9107
+ "attack_clip.phase.strike": "Strike",
9108
+ "attack_clip.phase.recover": "Recover"
9109
+ }
9110
+ }
9111
+ };
9112
+ var first_person_clips_default = {
9113
+ clips: [
9114
+ {
9115
+ id: "punch_right",
9116
+ 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" },
9117
+ duration: 0.35,
9118
+ keys: [
9119
+ { t: 0, R: { p: [0.15, -0.12, -0.4], r: [0, 1.5, 0.15], grip: 1, w: 0 } },
9120
+ { t: 0.1, R: { p: [0.21, -0.15, -0.29], r: [0.1, 1.45, 0.2], grip: 1 } },
9121
+ { t: 0.16, R: { p: [0.06, -0.09, -0.62], r: [0, 1.5708, -0.05], grip: 1 } },
9122
+ { t: 0.22, R: { p: [0.07, -0.1, -0.56], r: [0, 1.5708, -0.05], grip: 1 } },
9123
+ { t: 0.35, R: { p: [0.15, -0.12, -0.4], r: [0, 1.5, 0.15], grip: 1, w: 0 } }
9124
+ ],
9125
+ events: [
9126
+ { t: 0, type: "phase", data: { label: "attack_clip.phase.windup" } },
9127
+ { t: 0.1, type: "phase", data: { label: "attack_clip.phase.strike" } },
9128
+ { t: 0.16, type: "impact", data: { kind: "punch" } },
9129
+ { t: 0.22, type: "phase", data: { label: "attack_clip.phase.recover" } }
9130
+ ]
9131
+ },
9132
+ {
9133
+ id: "shove_two_hands",
9134
+ 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" },
9135
+ duration: 0.5,
9136
+ keys: [
9137
+ { t: 0, R: { p: [0.17, -0.14, -0.36], r: [0, 1.5708, 1.4], grip: 0.05, w: 0 }, L: "mirror" },
9138
+ { t: 0.15, R: { p: [0.15, -0.09, -0.27], r: [0, 1.5708, 1.5], grip: 0.05 }, L: "mirror" },
9139
+ { t: 0.26, R: { p: [0.11, -0.02, -0.58], r: [0, 1.5708, 1.75], grip: 0.05 }, L: "mirror" },
9140
+ { t: 0.34, R: { p: [0.12, -0.03, -0.54], r: [0, 1.5708, 1.65], grip: 0.05 }, L: "mirror" },
9141
+ { t: 0.5, R: { p: [0.17, -0.14, -0.36], r: [0, 1.5708, 1.4], grip: 0.05, w: 0 }, L: "mirror" }
9142
+ ],
9143
+ events: [
9144
+ { t: 0, type: "phase", data: { label: "attack_clip.phase.windup" } },
9145
+ { t: 0.15, type: "phase", data: { label: "attack_clip.phase.strike" } },
9146
+ { t: 0.26, type: "impact", data: { kind: "shove" } },
9147
+ { t: 0.34, type: "phase", data: { label: "attack_clip.phase.recover" } }
9148
+ ]
9149
+ },
9150
+ {
9151
+ id: "front_kick",
9152
+ 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" },
9153
+ duration: 0.6,
9154
+ keys: [
9155
+ { t: 0, F: { p: [0.13, -0.85, -0.05], r: [0, 1.5708, 0], w: 0 } },
9156
+ { t: 0.18, F: { p: [0.18, -0.58, -0.3], r: [0, 1.5708, 0.6] } },
9157
+ { t: 0.32, F: { p: [0.12, -0.24, -0.65], r: [0, 1.5708, 0.35] } },
9158
+ { t: 0.42, F: { p: [0.12, -0.3, -0.58], r: [0, 1.5708, 0.3] } },
9159
+ { t: 0.6, F: { p: [0.13, -0.85, -0.05], r: [0, 1.5708, 0], w: 0 } }
9160
+ ],
9161
+ events: [
9162
+ { t: 0, type: "phase", data: { label: "attack_clip.phase.windup" } },
9163
+ { t: 0.18, type: "phase", data: { label: "attack_clip.phase.strike" } },
9164
+ { t: 0.32, type: "impact", data: { kind: "kick" } },
9165
+ { t: 0.42, type: "phase", data: { label: "attack_clip.phase.recover" } }
9166
+ ]
9167
+ }
9168
+ ]
9169
+ };
9170
+ var names_default = {
9171
+ sources: {
9172
+ file: "specs/001-migracao-entregas-dos-times/sources/sobreviventes__os-vivos-do-vale.js (site/pages/sobreviventes/os-vivos-do-vale.html)",
9173
+ pools: "NM (lines 610-611): m, f, s, bm, bf",
9174
+ kinship: "RELW (line 612)"
9175
+ },
9176
+ "pt-BR": {
9177
+ male: [
9178
+ "Jo\xE3o",
9179
+ "Paulo",
9180
+ "Marcos",
9181
+ "Andr\xE9",
9182
+ "Rafael",
9183
+ "Thiago",
9184
+ "Bruno",
9185
+ "Luiz",
9186
+ "S\xE9rgio",
9187
+ "Wagner",
9188
+ "C\xEDcero",
9189
+ "Edson",
9190
+ "Igor",
9191
+ "Mateus",
9192
+ "Renan",
9193
+ "Hugo"
9194
+ ],
9195
+ female: [
9196
+ "Ana",
9197
+ "Patr\xEDcia",
9198
+ "Juliana",
9199
+ "Camila",
9200
+ "Sandra",
9201
+ "Luana",
9202
+ "M\xE1rcia",
9203
+ "Fernanda",
9204
+ "Aline",
9205
+ "Rita",
9206
+ "Jaqueline",
9207
+ "Simone",
9208
+ "Larissa",
9209
+ "Bruna",
9210
+ "Tereza",
9211
+ "Vanessa"
9212
+ ],
9213
+ surnames: [
9214
+ "Silva",
9215
+ "Santos",
9216
+ "Oliveira",
9217
+ "Souza",
9218
+ "Pereira",
9219
+ "Lima",
9220
+ "Carvalho",
9221
+ "Gomes",
9222
+ "Ribeiro",
9223
+ "Martins",
9224
+ "Rocha",
9225
+ "Almeida",
9226
+ "Barbosa",
9227
+ "Teixeira",
9228
+ "Moraes",
9229
+ "Cunha"
9230
+ ],
9231
+ babyMale: [
9232
+ "Davi",
9233
+ "Miguel",
9234
+ "Gael",
9235
+ "Bento",
9236
+ "Noah",
9237
+ "Theo"
9238
+ ],
9239
+ babyFemale: [
9240
+ "Esperan\xE7a",
9241
+ "Aurora",
9242
+ "Cec\xEDlia",
9243
+ "Luna",
9244
+ "Maria Luz",
9245
+ "Alice"
9246
+ ],
9247
+ kinship: {
9248
+ male: [
9249
+ "irm\xE3o",
9250
+ "primo",
9251
+ "ex-aluno",
9252
+ "vizinho",
9253
+ "colega de trabalho",
9254
+ "afilhado",
9255
+ "filho"
9256
+ ],
9257
+ female: [
9258
+ "irm\xE3",
9259
+ "prima",
9260
+ "ex-aluna",
9261
+ "vizinha",
9262
+ "colega de trabalho",
9263
+ "afilhada",
9264
+ "filha"
9265
+ ]
9266
+ }
9267
+ }
9268
+ };
9269
+ var ATTACK_CLIPS = attack_clips_default.clips;
9270
+ var ATTACK_CLIP_LOCALES = attack_clips_default.locales;
9271
+ var FIRST_PERSON_CLIPS = first_person_clips_default.clips;
9272
+ var NAME_POOLS = { "pt-BR": names_default["pt-BR"] };
9273
+
9274
+ // src/presets/first-person-arms.json
9275
+ var first_person_arms_default = {
9276
+ source: {
9277
+ 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)."
9278
+ },
9279
+ rig: {
9280
+ shoulder: [0.16, -0.36, 0.18],
9281
+ upper: 0.32,
9282
+ fore: 0.3,
9283
+ reachShift: 0.35,
9284
+ wrist: 0.07,
9285
+ elbowPole: [0.45, -1, 0.2],
9286
+ shoulderLeft: [-0.07, -0.46, 0.18],
9287
+ elbowPoleLeft: [-0.1, -1, 0.2],
9288
+ radius: { shoulder: 0.04, elbow: 0.034, wrist: 0.028, cuff: 0.031 },
9289
+ hip: [0.12, -0.82, 0.04],
9290
+ thigh: 0.46,
9291
+ shin: 0.46,
9292
+ kneePole: [0.1, 0.5, -1],
9293
+ foot: { p: [0.13, -0.85, -0.05], r: [0, 1.5708, 0] }
9294
+ },
9295
+ stances: {
9296
+ relaxed: {
9297
+ R: { p: [0.2, -0.22, -0.36], r: [0.05, 1.57, -0.05], grip: 0.2 },
9298
+ L: "mirror"
9299
+ },
9300
+ fists: {
9301
+ R: { p: [0.15, -0.12, -0.4], r: [0, 1.5, 0.15], grip: 1 },
9302
+ L: "mirror"
9303
+ },
9304
+ hold: { follow: true, fallback: "relaxed" }
9305
+ },
9306
+ bob: { frequency: 2.3, x: 6e-3, y: 8e-3, run: 1.5, fullSpeed: 4, crouch: 0.02 }
9307
+ };
9308
+
9309
+ // src/first-person/hand.ts
9310
+ var FINGERS = [
9311
+ { z: -0.03, lengths: [0.034, 0.024, 0.02], width: 0.016 },
9312
+ { z: -0.0105, lengths: [0.038, 0.027, 0.022], width: 0.0165 },
9313
+ { z: 9e-3, lengths: [0.035, 0.025, 0.02], width: 0.0155 },
9314
+ { z: 0.027, lengths: [0.029, 0.02, 0.018], width: 0.0135 }
9315
+ ];
9316
+ var PALM = { length: 0.09, thick: 0.026, width: 0.09, wristWidth: 0.066 };
9317
+ var FINGER_THICK = 0.0135;
9318
+ var CURL = { near: 1.05, mid: 1.25, far: 0.85, spread: 0.06 };
9319
+ var THUMB = { base: [5e-3, -6e-3, -0.044], near: 0.034, far: 0.028, width: 0.019 };
9320
+ var createHandMesh = (THREE, skin, wristSkin = skin) => {
9321
+ const root = new THREE.Group();
9322
+ root.name = "first-person-hand";
9323
+ const geometries = [];
9324
+ const box2 = (parent, sx, sy, sz, x, y, z, material = skin) => {
9325
+ const geometry = new THREE.BoxGeometry(sx, sy, sz);
9326
+ geometries.push(geometry);
9327
+ const mesh2 = new THREE.Mesh(geometry, material);
9328
+ mesh2.position.set(x, y, z);
9329
+ mesh2.frustumCulled = false;
9330
+ parent.add(mesh2);
9331
+ return mesh2;
9332
+ };
9333
+ const palmGeometry = new THREE.BoxGeometry(PALM.length, PALM.thick, PALM.width);
9334
+ const palmPosition = palmGeometry.getAttribute("position");
9335
+ for (let i = 0; i < palmPosition.count; i++) {
9336
+ if (palmPosition.getX(i) < 0) palmPosition.setZ(i, palmPosition.getZ(i) * PALM.wristWidth / PALM.width);
9337
+ }
9338
+ palmGeometry.computeVertexNormals();
9339
+ geometries.push(palmGeometry);
9340
+ const palm = new THREE.Mesh(palmGeometry, skin);
9341
+ palm.frustumCulled = false;
9342
+ root.add(palm);
9343
+ const wristGeometry = new THREE.CylinderGeometry(0.03, 0.033, 0.05, 8);
9344
+ wristGeometry.rotateZ(Math.PI / 2);
9345
+ geometries.push(wristGeometry);
9346
+ const wrist = new THREE.Mesh(wristGeometry, wristSkin);
9347
+ wrist.position.set(-PALM.length / 2 - 0.018, 0, 0);
9348
+ wrist.frustumCulled = false;
9349
+ root.add(wrist);
9350
+ const joints = [];
9351
+ FINGERS.forEach((finger, index) => {
9352
+ const segments = [];
9353
+ let parent = root;
9354
+ let at = PALM.length / 2;
9355
+ finger.lengths.forEach((length, k) => {
9356
+ const group = new THREE.Group();
9357
+ group.position.set(at, k === 0 ? 2e-3 : 0, k === 0 ? finger.z : 0);
9358
+ const taper = 1 - k * 0.07;
9359
+ box2(group, length, FINGER_THICK * taper, finger.width * taper, length / 2, 0, 0);
9360
+ parent.add(group);
9361
+ segments.push(group);
9362
+ parent = group;
9363
+ at = length;
9364
+ });
9365
+ joints.push({ segments, weight: 1 + index * (CURL.spread / CURL.near) });
9366
+ });
9367
+ const thumbNear = new THREE.Group();
9368
+ thumbNear.rotation.order = "YZX";
9369
+ thumbNear.position.set(...THUMB.base);
9370
+ box2(thumbNear, THUMB.near, FINGER_THICK * 1.1, THUMB.width, THUMB.near / 2, 0, 0);
9371
+ const thumbFar = new THREE.Group();
9372
+ thumbFar.position.set(THUMB.near, 0, 0);
9373
+ box2(thumbFar, THUMB.far, FINGER_THICK, THUMB.width * 0.9, THUMB.far / 2, 0, 0);
9374
+ thumbNear.add(thumbFar);
9375
+ root.add(thumbNear);
9376
+ let lastGrip = 0;
9377
+ let indexCurl;
9378
+ const curl = [CURL.near, CURL.mid, CURL.far];
9379
+ const applyIndex = () => {
9380
+ const finger = joints[0];
9381
+ if (!finger) return;
9382
+ const k = indexCurl === void 0 ? lastGrip : Math.min(1, Math.max(0, indexCurl));
9383
+ finger.segments.forEach((segment, i) => segment.rotation.z = -curl[i] * k * finger.weight);
9384
+ };
9385
+ const setGrip = (grip) => {
9386
+ const k = Math.min(1, Math.max(0, grip));
9387
+ lastGrip = k;
9388
+ for (const joint of joints) joint.segments.forEach((segment, i) => segment.rotation.z = -curl[i] * k * joint.weight);
9389
+ thumbNear.rotation.set(0, 0.55 - 1.45 * k, -0.1 - 0.75 * k);
9390
+ thumbFar.rotation.z = -0.1 - 0.7 * k;
9391
+ applyIndex();
9392
+ };
9393
+ const setIndex = (value) => {
9394
+ indexCurl = value;
9395
+ applyIndex();
9396
+ };
9397
+ setGrip(0);
9398
+ return {
9399
+ root,
9400
+ setGrip,
9401
+ setIndex,
9402
+ dispose() {
9403
+ for (const geometry of geometries) geometry.dispose();
9404
+ }
9405
+ };
9406
+ };
9407
+
9408
+ // src/first-person/ik.ts
9409
+ var solveTwoBone = (root, target, upper, lower, pole, out) => {
9410
+ const line = out.line.copy(target).sub(root);
9411
+ let distance3 = line.length();
9412
+ if (distance3 < 1e-6) line.set(0, 0, -1);
9413
+ else line.divideScalar(distance3);
9414
+ const min = Math.abs(upper - lower) + 1e-4;
9415
+ const max = upper + lower - 1e-4;
9416
+ out.clamped = distance3 > max || distance3 < min;
9417
+ distance3 = Math.min(max, Math.max(min, distance3));
9418
+ const along = (distance3 * distance3 + upper * upper - lower * lower) / (2 * distance3);
9419
+ const across = Math.sqrt(Math.max(0, upper * upper - along * along));
9420
+ const side = out.side.copy(pole);
9421
+ side.addScaledVector(line, -side.dot(line));
9422
+ if (side.lengthSq() < 1e-8) side.set(0, 1, 0).addScaledVector(line, -line.y);
9423
+ if (side.lengthSq() < 1e-8) side.set(1, 0, 0);
9424
+ side.normalize();
9425
+ out.joint.copy(root).addScaledVector(line, along).addScaledVector(side, across);
9426
+ out.end.copy(root).addScaledVector(line, distance3);
9427
+ return out;
9428
+ };
9429
+ var createTwoBone = (THREE) => ({ joint: new THREE.Vector3(), end: new THREE.Vector3(), clamped: false, line: new THREE.Vector3(), side: new THREE.Vector3() });
9430
+
9431
+ // src/first-person/arms.ts
9432
+ var DEFAULT_BLEND = 0.18;
9433
+ var ELBOW_SEGMENTS = 8;
9434
+ var REACH_SLACK = 0.97;
9435
+ var CONTACT_PROBE = 1.4;
9436
+ var CONTACT_MIN = 0.12;
9437
+ var CONTACT_MARGIN = 5e-3;
9438
+ var CONTACT_PALM = 0.03;
9439
+ var FOOT_LENGTH = 0.24;
9440
+ var FOOT_SHOWN = 1e-3;
9441
+ var AWAY_DROP = 0.55;
9442
+ var AWAY_OUT = 7;
9443
+ var AWAY_IN = 20;
9444
+ var AWAY_HIDDEN = 0.97;
9445
+ var FILL = 0.3;
9446
+ var FIRST_PERSON_STANCES = first_person_arms_default.stances;
9447
+ var FIRST_PERSON_RIG = first_person_arms_default.rig;
9448
+ var FIRST_PERSON_BOB = first_person_arms_default.bob;
9449
+ var hexOf2 = (value) => typeof value === "string" ? Number.parseInt(value, 16) : value;
9450
+ var scaleHex = (hex2, factor) => {
9451
+ const channel = (shift) => Math.round((hex2 >> shift & 255) * factor);
9452
+ return channel(16) << 16 | channel(8) << 8 | channel(0);
9453
+ };
9454
+ var mix2 = (a, b, k) => a + (b - a) * k;
9455
+ var ease2 = (k) => k * k * (3 - 2 * k);
9456
+ var FIRST_PERSON_COLORS = {
9457
+ skin: hexOf2(player_avatar_default.spec.skin),
9458
+ sleeve: hexOf2(player_avatar_default.shirtColor),
9459
+ cuff: scaleHex(hexOf2(player_avatar_default.shirtColor), 0.72),
9460
+ trouser: 2962496,
9461
+ shoe: 1841690
9462
+ };
9463
+ var newPose = (THREE) => ({ p: new THREE.Vector3(), q: new THREE.Quaternion(), grip: 0, scale: 1 });
9464
+ var copyPose = (to, from) => {
9465
+ to.p.copy(from.p);
9466
+ to.q.copy(from.q);
9467
+ to.grip = from.grip;
9468
+ to.scale = from.scale;
9469
+ return to;
9470
+ };
9471
+ var mixPose = (THREE, out, a, b, k) => {
9472
+ out.p.lerpVectors(a.p, b.p, k);
9473
+ out.q.copy(a.q).slerp(b.q, k);
9474
+ out.grip = mix2(a.grip, b.grip, k);
9475
+ out.scale = mix2(a.scale, b.scale, k);
9476
+ return out;
9477
+ };
9478
+ var mirrorRotation = (THREE, q) => {
9479
+ const m = new THREE.Matrix4().makeRotationFromQuaternion(q);
9480
+ const e = m.elements;
9481
+ for (const [i, j] of [[0, 1], [0, 2], [1, 0], [2, 0]]) e[j * 4 + i] = -e[j * 4 + i];
9482
+ return new THREE.Quaternion().setFromRotationMatrix(m);
9483
+ };
9484
+ var mirrorQuaternion = (THREE, q) => {
9485
+ const m = new THREE.Matrix4().makeRotationFromQuaternion(q);
9486
+ const e = m.elements;
9487
+ for (let column = 0; column < 3; column++) e[column * 4] = -e[column * 4];
9488
+ for (let row = 0; row < 3; row++) e[8 + row] = -e[8 + row];
9489
+ return new THREE.Quaternion().setFromRotationMatrix(m);
9490
+ };
9491
+ function createFirstPersonArms(THREE, options = {}) {
9492
+ const colors = { ...FIRST_PERSON_COLORS, ...options.colors };
9493
+ const rig = {
9494
+ ...FIRST_PERSON_RIG,
9495
+ ...options.rig,
9496
+ radius: { ...FIRST_PERSON_RIG.radius, ...options.rig?.radius },
9497
+ foot: options.rig?.foot ?? FIRST_PERSON_RIG.foot
9498
+ };
9499
+ const stances = { ...FIRST_PERSON_STANCES, ...options.stances };
9500
+ const bob = { ...FIRST_PERSON_BOB, ...options.bob };
9501
+ const blendSeconds = options.blend ?? DEFAULT_BLEND;
9502
+ const clips = new Map((options.clips ?? []).map((clip) => [clip.id, clip]));
9503
+ const root = new THREE.Group();
9504
+ root.name = "first-person-arms";
9505
+ root.userData.viewmodel = true;
9506
+ const lit = (color2) => new THREE.MeshLambertMaterial({ color: color2, emissive: scaleHex(color2, FILL) });
9507
+ const materials = {
9508
+ skin: lit(colors.skin),
9509
+ sleeve: lit(colors.sleeve),
9510
+ cuff: lit(colors.cuff),
9511
+ trouser: lit(colors.trouser),
9512
+ shoe: lit(colors.shoe),
9513
+ sole: lit(scaleHex(colors.shoe, 0.55))
9514
+ };
9515
+ const geometries = [];
9516
+ const Y = new THREE.Vector3(0, 1, 0);
9517
+ const limb2 = (parent, wide, narrow, length, material) => {
9518
+ const geometry = new THREE.CylinderGeometry(narrow, wide, length, 8, 1);
9519
+ geometry.translate(0, length / 2, 0);
9520
+ geometries.push(geometry);
9521
+ const mesh2 = new THREE.Mesh(geometry, material);
9522
+ mesh2.frustumCulled = false;
9523
+ mesh2.userData.length = length;
9524
+ parent.add(mesh2);
9525
+ return mesh2;
9526
+ };
9527
+ const ball = (parent, radius, material) => {
9528
+ const geometry = new THREE.SphereGeometry(radius, ELBOW_SEGMENTS, 6);
9529
+ geometries.push(geometry);
9530
+ const mesh2 = new THREE.Mesh(geometry, material);
9531
+ mesh2.frustumCulled = false;
9532
+ parent.add(mesh2);
9533
+ return mesh2;
9534
+ };
9535
+ const place = (segment, from, to) => {
9536
+ const direction = new THREE.Vector3().subVectors(to, from);
9537
+ const length = direction.length();
9538
+ segment.position.copy(from);
9539
+ if (length > 1e-6) segment.quaternion.setFromUnitVectors(Y, direction.divideScalar(length));
9540
+ segment.scale.y = length / segment.userData.length;
9541
+ };
9542
+ const arms = {};
9543
+ for (const side of ["R", "L"]) {
9544
+ const sign2 = side === "R" ? 1 : -1;
9545
+ const hand = createHandMesh(THREE, materials.skin);
9546
+ const anchor = new THREE.Group();
9547
+ anchor.name = `first-person-hand-${side}`;
9548
+ const mirror = new THREE.Group();
9549
+ mirror.scale.z = sign2;
9550
+ mirror.add(hand.root);
9551
+ anchor.add(mirror);
9552
+ root.add(anchor);
9553
+ const upper = limb2(root, rig.radius.shoulder, rig.radius.elbow, rig.upper, materials.sleeve);
9554
+ const fore = limb2(root, rig.radius.elbow, rig.radius.wrist, rig.fore, materials.sleeve);
9555
+ const cuff = limb2(root, rig.radius.cuff, rig.radius.cuff, 0.03, materials.cuff);
9556
+ const elbow = ball(root, rig.radius.elbow * 1.02, materials.sleeve);
9557
+ elbow.name = `first-person-elbow-${side}`;
9558
+ 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() }, away: options.hideWhenIdle ? 1 : 0 };
9559
+ }
9560
+ const leg = new THREE.Group();
9561
+ leg.name = "first-person-leg";
9562
+ leg.visible = false;
9563
+ root.add(leg);
9564
+ const thigh = limb2(leg, 0.088, 0.068, rig.thigh, materials.trouser);
9565
+ const shin = limb2(leg, 0.068, 0.05, rig.shin, materials.trouser);
9566
+ const knee = ball(leg, 0.07, materials.trouser);
9567
+ const shoe = new THREE.Group();
9568
+ const shoeBox = (sx, sy, sz, x, y, material) => {
9569
+ const geometry = new THREE.BoxGeometry(sx, sy, sz);
9570
+ geometries.push(geometry);
9571
+ const mesh2 = new THREE.Mesh(geometry, material);
9572
+ mesh2.position.set(x, y, 0);
9573
+ mesh2.frustumCulled = false;
9574
+ shoe.add(mesh2);
9575
+ };
9576
+ shoeBox(0.27, 0.07, 0.1, 0.065, -0.05, materials.shoe);
9577
+ shoeBox(0.27, 0.025, 0.104, 0.065, -0.095, materials.sole);
9578
+ shoeBox(0.1, 0.05, 0.088, 0.17, -5e-3, materials.shoe);
9579
+ leg.add(shoe);
9580
+ const shoulderOf = (sign2, out) => sign2 === -1 && rig.shoulderLeft ? out.set(...rig.shoulderLeft) : out.set(rig.shoulder[0] * sign2, rig.shoulder[1], rig.shoulder[2]);
9581
+ 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]);
9582
+ const kneePole = new THREE.Vector3(...rig.kneePole);
9583
+ const hip = new THREE.Vector3(...rig.hip);
9584
+ const euler = new THREE.Euler(0, 0, 0, "YZX");
9585
+ const quaternionOf = (r) => new THREE.Quaternion().setFromEuler(euler.set(r[0], r[1], r[2], "YZX"));
9586
+ const restPose = (rest, mirror, out) => {
9587
+ out.p.set(...rest.p);
9588
+ out.q.copy(quaternionOf(rest.r));
9589
+ if (mirror) {
9590
+ out.p.x = -out.p.x;
9591
+ out.q.copy(mirrorQuaternion(THREE, out.q));
9592
+ }
9593
+ out.grip = rest.grip ?? 0;
9594
+ out.scale = 1;
9595
+ return out;
9596
+ };
9597
+ const DEFAULT_REST = { p: [0.17, -0.3, -0.3], r: [0, 1.5, 0], grip: 0.3 };
9598
+ const stanceRest = (id, side, out) => {
9599
+ const stance = stances[id] ?? stances.relaxed;
9600
+ const right = stance?.R ?? DEFAULT_REST;
9601
+ const left = stance?.L;
9602
+ if (side === "R") return restPose(right, false, out);
9603
+ return left && left !== "mirror" ? restPose(left, false, out) : restPose(right, true, out);
9604
+ };
9605
+ const camPosition = new THREE.Vector3();
9606
+ const camQuaternion = new THREE.Quaternion();
9607
+ const camInverse = new THREE.Quaternion();
9608
+ const clamped = newPose(THREE);
9609
+ const probeAt = new THREE.Vector3();
9610
+ const probeForward = new THREE.Vector3();
9611
+ const probeFingers = new THREE.Vector3();
9612
+ let contact;
9613
+ const keepOutside = (pose, reach) => {
9614
+ if (!contact) return pose;
9615
+ probeAt.set(pose.p.x, pose.p.y, 0).applyQuaternion(camQuaternion).add(camPosition);
9616
+ probeForward.set(0, 0, -1).applyQuaternion(camQuaternion);
9617
+ const distance3 = contact([probeAt.x, probeAt.y, probeAt.z], [probeForward.x, probeForward.y, probeForward.z], CONTACT_PROBE);
9618
+ if (distance3 === null) return pose;
9619
+ const limit = Math.max(CONTACT_MIN, distance3 - reach - CONTACT_MARGIN);
9620
+ if (-pose.p.z <= limit) return pose;
9621
+ copyPose(clamped, pose);
9622
+ clamped.p.z = -limit;
9623
+ return clamped;
9624
+ };
9625
+ const forward = (pose, length) => Math.max(CONTACT_PALM, -probeFingers.set(1, 0, 0).applyQuaternion(pose.q).z * length * pose.scale);
9626
+ const handReach = (pose) => forward(pose, 0.085);
9627
+ const camScale = new THREE.Vector3();
9628
+ const toCamera = (target, grip, scale, out) => {
9629
+ out.p.set(...target.position).sub(camPosition).applyQuaternion(camInverse);
9630
+ out.q.set(...target.quaternion).premultiply(camInverse);
9631
+ out.grip = grip;
9632
+ out.scale = scale;
9633
+ return out;
9634
+ };
9635
+ const listeners = /* @__PURE__ */ new Set();
9636
+ let run = null;
9637
+ const emit = (event) => {
9638
+ for (const listener of listeners) listener(event);
9639
+ };
9640
+ const fire = (clip, from, to) => {
9641
+ for (const event of clipEventsBetween(clip, from, to)) emit({ ...event, clip: clip.id });
9642
+ };
9643
+ let stanceId = "relaxed";
9644
+ let phase = 0;
9645
+ let swing = 0;
9646
+ let sink = 0;
9647
+ let first = true;
9648
+ const bobOffset = new THREE.Vector3();
9649
+ const desired = newPose(THREE);
9650
+ const channelPose = newPose(THREE);
9651
+ const mixed = newPose(THREE);
9652
+ const dropped = newPose(THREE);
9653
+ let indexCurl;
9654
+ const bone = createTwoBone(THREE);
9655
+ const shoulder = new THREE.Vector3();
9656
+ const wristAt = new THREE.Vector3();
9657
+ const palmAt = new THREE.Vector3();
9658
+ const fingers = new THREE.Vector3();
9659
+ const towards = new THREE.Vector3();
9660
+ const fromChannel = (channel, side, base, out) => {
9661
+ out.p.set(...channel.p);
9662
+ out.q.copy(quaternionOf(channel.r));
9663
+ if (channel.mirror && side === "L") {
9664
+ out.p.x = -out.p.x;
9665
+ out.q.copy(mirrorQuaternion(THREE, out.q));
9666
+ }
9667
+ out.grip = channel.grip ?? base.grip;
9668
+ out.scale = base.scale;
9669
+ return out;
9670
+ };
9671
+ const drawArm = (arm, pose) => {
9672
+ copyPose(arm.drawn, pose);
9673
+ const scale = pose.scale;
9674
+ fingers.set(1, 0, 0).applyQuaternion(pose.q);
9675
+ wristAt.copy(pose.p).addScaledVector(fingers, -rig.wrist * scale);
9676
+ shoulderOf(arm.sign, shoulder).add(bobOffset);
9677
+ const excess = shoulder.distanceTo(wristAt) - (rig.upper + rig.fore) * REACH_SLACK;
9678
+ if (excess > 0 && rig.reachShift > 0) shoulder.addScaledVector(towards.subVectors(wristAt, shoulder).normalize(), Math.min(excess, rig.reachShift));
9679
+ solveTwoBone(shoulder, wristAt, rig.upper, rig.fore, poleOf(arm.sign), bone);
9680
+ palmAt.copy(bone.end).addScaledVector(fingers, rig.wrist * scale);
9681
+ arm.drawn.p.copy(palmAt);
9682
+ arm.anchor.position.copy(palmAt);
9683
+ arm.anchor.quaternion.copy(pose.q);
9684
+ arm.anchor.scale.setScalar(scale);
9685
+ arm.hand.setGrip(pose.grip);
9686
+ arm.hand.setIndex(arm.side === "R" ? indexCurl : void 0);
9687
+ arm.joints.shoulder.copy(shoulder);
9688
+ arm.joints.elbow.copy(bone.joint);
9689
+ arm.joints.wrist.copy(bone.end);
9690
+ place(arm.upper, shoulder, bone.joint);
9691
+ place(arm.fore, bone.joint, bone.end);
9692
+ arm.elbow.position.copy(bone.joint);
9693
+ const toWrist = new THREE.Vector3().subVectors(bone.end, bone.joint).normalize();
9694
+ place(arm.cuff, new THREE.Vector3().copy(bone.end).addScaledVector(toWrist, -0.02), new THREE.Vector3().copy(bone.end).addScaledVector(toWrist, 0.012));
9695
+ };
9696
+ const footPose = newPose(THREE);
9697
+ const footRest = newPose(THREE);
9698
+ const ankle = new THREE.Vector3();
9699
+ const hipMirrored = new THREE.Vector3(-hip.x, hip.y, hip.z);
9700
+ const kneePoleMirrored = new THREE.Vector3(-kneePole.x, kneePole.y, kneePole.z);
9701
+ const drawLeg = (pose, left) => {
9702
+ const origin = left ? hipMirrored : hip;
9703
+ solveTwoBone(origin, pose.p, rig.thigh, rig.shin, left ? kneePoleMirrored : kneePole, bone);
9704
+ ankle.copy(bone.end);
9705
+ place(thigh, origin, bone.joint);
9706
+ place(shin, bone.joint, ankle);
9707
+ knee.position.copy(bone.joint);
9708
+ shoe.position.copy(ankle);
9709
+ shoe.quaternion.copy(pose.q);
9710
+ };
9711
+ const modeOf = (key, arm) => {
9712
+ if (arm.mode === key) return;
9713
+ copyPose(arm.from, arm.shown);
9714
+ arm.mode = key;
9715
+ arm.blend = first ? 1 : 0;
9716
+ };
9717
+ return {
9718
+ root,
9719
+ get playing() {
9720
+ return run ? run.clip.id : null;
9721
+ },
9722
+ get stance() {
9723
+ return stanceId;
9724
+ },
9725
+ play(id, options2) {
9726
+ const clip = clips.get(id);
9727
+ if (!clip) return false;
9728
+ run = { clip, time: 0, left: options2?.leg === "left" };
9729
+ fire(clip, -1e-9, 0);
9730
+ return true;
9731
+ },
9732
+ stop() {
9733
+ run = null;
9734
+ },
9735
+ update(dt, state) {
9736
+ const { camera } = state;
9737
+ contact = state.contact;
9738
+ camera.updateWorldMatrix(true, false);
9739
+ camera.matrixWorld.decompose(camPosition, camQuaternion, camScale);
9740
+ camInverse.copy(camQuaternion).invert();
9741
+ root.position.copy(camPosition);
9742
+ root.quaternion.copy(camQuaternion);
9743
+ root.updateMatrixWorld(true);
9744
+ const speed = state.speed ?? 0;
9745
+ const target = Math.min(1, speed / bob.fullSpeed) * (state.running ? bob.run : 1);
9746
+ swing += (target - swing) * Math.min(1, dt * 8);
9747
+ phase += dt * speed * bob.frequency;
9748
+ sink += ((state.crouch ? 1 : 0) - sink) * Math.min(1, dt * 8);
9749
+ bobOffset.set(Math.sin(phase) * bob.x * swing, Math.sin(phase * 2) * bob.y * swing - bob.crouch * sink, 0);
9750
+ stanceId = state.stance ?? "relaxed";
9751
+ const stance = stances[stanceId] ?? stances.relaxed;
9752
+ const targets = state.targets ?? null;
9753
+ if (run) {
9754
+ const from = run.time;
9755
+ run.time += dt;
9756
+ fire(run.clip, from, Math.min(run.time, run.clip.duration));
9757
+ }
9758
+ const sample = run ? sampleFirstPersonClip(run.clip, Math.min(run.time, run.clip.duration)) : null;
9759
+ for (const side of ["R", "L"]) {
9760
+ const arm = arms[side];
9761
+ const target2 = targets?.[side];
9762
+ let mode;
9763
+ if (stance?.follow && target2) {
9764
+ mode = "target";
9765
+ toCamera(target2, (side === "L" ? targets?.gripL : void 0) ?? targets?.grip ?? 1, targets?.scale ?? 1, desired);
9766
+ } else {
9767
+ mode = `rest:${stance?.follow ? stance.fallback ?? "relaxed" : stanceId}`;
9768
+ stanceRest(stance?.follow ? stance.fallback ?? "relaxed" : stanceId, side, desired);
9769
+ desired.p.add(bobOffset);
9770
+ }
9771
+ modeOf(mode, arm);
9772
+ if (side === "R") indexCurl = mode === "target" ? targets?.fingers?.index : void 0;
9773
+ arm.blend = blendSeconds <= 0 ? 1 : Math.min(1, arm.blend + dt / blendSeconds);
9774
+ if (arm.blend >= 1) copyPose(arm.shown, desired);
9775
+ else mixPose(THREE, arm.shown, arm.from, desired, ease2(arm.blend));
9776
+ const channel = sample?.[side];
9777
+ let pose;
9778
+ if (channel && channel.w > 0) {
9779
+ fromChannel(channel, side, arm.shown, channelPose);
9780
+ mixPose(THREE, mixed, arm.shown, channelPose, channel.w);
9781
+ pose = mode === "target" ? mixed : keepOutside(mixed, handReach(mixed));
9782
+ } else pose = mode === "target" ? arm.shown : keepOutside(arm.shown, handReach(arm.shown));
9783
+ const idle = options.hideWhenIdle === true && mode === "rest:relaxed" && !(channel && channel.w > 0);
9784
+ arm.away = options.hideWhenIdle ? Math.min(1, Math.max(0, arm.away + ((idle ? 1 : 0) - arm.away) * Math.min(1, dt * (idle ? AWAY_OUT : AWAY_IN)))) : 0;
9785
+ if (arm.away > 0) {
9786
+ copyPose(dropped, pose);
9787
+ dropped.p.y -= AWAY_DROP * ease2(arm.away);
9788
+ pose = dropped;
9789
+ }
9790
+ drawArm(arm, pose);
9791
+ const shown = arm.away < AWAY_HIDDEN;
9792
+ for (const part of [arm.anchor, arm.upper, arm.fore, arm.cuff, arm.elbow]) part.visible = shown;
9793
+ }
9794
+ const foot = sample?.F;
9795
+ leg.visible = !!foot && foot.w > FOOT_SHOWN;
9796
+ if (foot && leg.visible) {
9797
+ restPose(rig.foot, false, footRest);
9798
+ fromChannel(foot, "R", footRest, footPose);
9799
+ mixPose(THREE, mixed, footRest, footPose, foot.w);
9800
+ copyPose(footPose, mixed);
9801
+ if (run?.left) {
9802
+ footPose.p.x = -footPose.p.x;
9803
+ footPose.q.copy(mirrorRotation(THREE, footPose.q));
9804
+ }
9805
+ drawLeg(contact ? keepOutside(footPose, forward(footPose, FOOT_LENGTH)) : footPose, run?.left ?? false);
9806
+ }
9807
+ if (run && run.time >= run.clip.duration) run = null;
9808
+ first = false;
9809
+ },
9810
+ on(_type, listener) {
9811
+ listeners.add(listener);
9812
+ return () => void listeners.delete(listener);
9813
+ },
9814
+ joints(side) {
9815
+ const { shoulder: shoulder2, elbow, wrist } = arms[side].joints;
9816
+ return { shoulder: shoulder2.clone(), elbow: elbow.clone(), wrist: wrist.clone() };
9817
+ },
9818
+ handPose(side) {
9819
+ const pose = arms[side].drawn;
9820
+ return { position: pose.p.clone(), quaternion: pose.q.clone(), grip: pose.grip };
9821
+ },
9822
+ dispose() {
9823
+ run = null;
9824
+ listeners.clear();
9825
+ for (const arm of Object.values(arms)) arm.hand.dispose();
9826
+ for (const geometry of geometries) geometry.dispose();
9827
+ for (const material of Object.values(materials)) material.dispose();
9828
+ root.removeFromParent();
9829
+ }
9830
+ };
9831
+ }
9832
+
9833
+ // src/player/room-avatar.ts
9834
+ var impactOf = (clip) => clip.events?.find((event) => event.type === "impact")?.t ?? null;
9835
+ var toRoomAvatar = (avatar, options = {}) => {
9836
+ const arms = options.firstPerson === false ? null : createFirstPersonArms(avatar.three, {
9837
+ 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 },
9838
+ clips: options.firstPersonClips ?? FIRST_PERSON_CLIPS,
9839
+ hideWhenIdle: true,
9840
+ ...options.firstPerson
9841
+ });
9842
+ const strikes = new Map((options.strikeClips ?? ATTACK_CLIPS).map((clip) => [clip.id, clip]));
9843
+ const mirrored = /* @__PURE__ */ new Map();
9844
+ const leftOf = (clip) => {
9845
+ let found = mirrored.get(clip.id);
9846
+ if (!found) mirrored.set(clip.id, found = mirrorPoseClip(clip, `${clip.id}_left`));
9847
+ return found;
9848
+ };
9849
+ return {
9850
+ root: avatar.root,
9851
+ avatar,
9852
+ arms,
9853
+ ...arms ? { firstPerson: { root: arms.root, update: (dt, state) => arms.update(dt, state) } } : {},
9854
+ update: (dt, state) => avatar.update(dt, {
9855
+ speed: state.speed,
9856
+ running: state.running,
9857
+ crouch: state.crouch,
9858
+ down: state.down,
9859
+ armed: state.armed,
9860
+ pitch: -state.pitch,
9861
+ ...state.holding !== void 0 ? { holding: state.holding } : {},
9862
+ ...state.itemUse !== void 0 ? { itemUse: state.itemUse } : {}
9863
+ }),
9864
+ hand: (side) => avatar.hand(side),
9865
+ strike: (clipId, strikeOptions) => {
9866
+ const clip = strikes.get(clipId);
9867
+ if (!clip) return null;
9868
+ const left = strikeOptions?.leg === "left";
9869
+ avatar.play(left ? leftOf(clip) : clip);
9870
+ arms?.play(clipId, left ? { leg: "left" } : void 0);
9871
+ return impactOf(clip);
9872
+ }
9873
+ };
9874
+ };
9875
+
9876
+ // src/player/test-text.ts
9877
+ var AVATAR_TEXT = {
9878
+ en: {
9879
+ group: "Avatar",
9880
+ name: "Player body",
9881
+ actions: {
9882
+ camera_first: "Camera: 1st person",
9883
+ camera_third: "Camera: 3rd person",
9884
+ crouch: "Crouch",
9885
+ stand: "Stand up",
9886
+ fall: "Fall down",
9887
+ get_up: "Get up",
9888
+ armed_on: "Armed: on",
9889
+ armed_off: "Armed: off",
9890
+ stop_clip: "Stop clip"
9891
+ },
9892
+ play: "Play",
9893
+ metrics: { camera: "Camera", clip: "Clip playing", last_event: "Last clip event", state: "State", joints: "Joints" },
9894
+ none: "none"
9895
+ },
9896
+ "pt-BR": {
9897
+ group: "Avatar",
9898
+ name: "Corpo do jogador",
9899
+ actions: {
9900
+ camera_first: "C\xE2mera: 1\xAA pessoa",
9901
+ camera_third: "C\xE2mera: 3\xAA pessoa",
9902
+ crouch: "Agachar",
9903
+ stand: "Levantar",
9904
+ fall: "Cair",
9905
+ get_up: "Levantar do ch\xE3o",
9906
+ armed_on: "Armado: ligado",
9907
+ armed_off: "Armado: desligado",
9908
+ stop_clip: "Parar clipe"
9909
+ },
9910
+ play: "Tocar",
9911
+ metrics: { camera: "C\xE2mera", clip: "Clipe tocando", last_event: "\xDAltimo evento do clipe", state: "Estado", joints: "Juntas" },
9912
+ none: "nenhum"
9913
+ }
9914
+ };
9915
+
9916
+ // src/player/test-module.ts
9917
+ var AVATAR_AREA_ID = "avatar_area";
9918
+ var round = (value) => (Math.round(value * 100) / 100).toString();
9919
+ function createAvatarTestModule(options) {
9920
+ const clips = options.clips ?? POSE_CLIPS;
9921
+ const textOf = (locale) => AVATAR_TEXT[locale ?? options.locale ?? "pt-BR"] ?? AVATAR_TEXT["pt-BR"];
9922
+ const phaseLabel = (label, locale) => {
9923
+ const id = locale ?? options.locale ?? "pt-BR";
9924
+ const table = { ...POSE_CLIP_LOCALES[id] ?? POSE_CLIP_LOCALES["pt-BR"], ...options.clipLocales?.[id] ?? options.clipLocales?.["pt-BR"] };
9925
+ return typeof label === "string" ? table[label] ?? label : "";
9926
+ };
9927
+ const state = { crouch: false, down: false, armed: null };
9928
+ let host = null;
9929
+ let lastEvent = "";
9930
+ const log = (action, extra = {}) => {
9931
+ const entry = { type: "avatar", action, ...extra };
9932
+ host?.log(JSON.stringify(entry), entry);
9933
+ };
9934
+ const push = (action, patch, extra = {}) => {
9935
+ Object.assign(state, patch);
9936
+ options.state?.set(patch);
9937
+ log(action, { crouch: state.crouch, down: state.down, armed: state.armed, ...extra });
9938
+ };
9939
+ const setCamera = (mode) => {
9940
+ options.camera?.set(mode);
9941
+ log(`camera_${mode}`, { mode: options.camera?.mode() ?? null });
9942
+ };
9943
+ const onChange = (change) => {
9944
+ if (change.kind !== "action") return;
9945
+ switch (change.id) {
9946
+ case "camera_first":
9947
+ return setCamera("first");
9948
+ case "camera_third":
9949
+ return setCamera("third");
9950
+ case "crouch":
9951
+ return push("crouch", { crouch: true });
9952
+ case "stand":
9953
+ return push("stand", { crouch: false });
9954
+ case "fall":
9955
+ return push("fall", { down: true });
9956
+ case "get_up":
9957
+ return push("get_up", { down: false });
9958
+ case "armed_on":
9959
+ return push("armed_on", { armed: true });
9960
+ case "armed_off":
9961
+ return push("armed_off", { armed: false });
9962
+ case "stop_clip":
9963
+ options.avatar.stop();
9964
+ return log("stop_clip", { playing: options.avatar.playing });
9965
+ default: {
9966
+ const clip = clips.find((item) => `play_${item.id}` === change.id);
9967
+ if (!clip) return;
9968
+ options.avatar.play(clip);
9969
+ log("play_clip", { clip: clip.id, duration: clip.duration, loop: clip.loop ?? false, channels: clip.channels ?? "full" });
9970
+ }
9971
+ }
9972
+ };
9973
+ const joints = () => {
9974
+ const rig = options.avatar.rig;
9975
+ const [armA, armB] = rig.arms;
9976
+ const [legA, legB] = rig.legs;
9977
+ 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)}`;
9978
+ };
9979
+ return {
9980
+ id: AVATAR_AREA_ID,
9981
+ name: textOf().name,
9982
+ group: textOf().group,
9983
+ state,
9984
+ items: () => [],
9985
+ area: () => ({ placements: [], view: { eye: [0, 1.7, 6], target: [0, 1.2, 0] } }),
9986
+ controls: (locale) => {
9987
+ const text = textOf(locale);
9988
+ const action = (id, name, hint) => ({ kind: "action", id, name, ...hint ? { hint } : {} });
9989
+ return [
9990
+ action("camera_first", text.actions.camera_first),
9991
+ action("camera_third", text.actions.camera_third),
9992
+ action("crouch", text.actions.crouch),
9993
+ action("stand", text.actions.stand),
9994
+ action("fall", text.actions.fall),
9995
+ action("get_up", text.actions.get_up),
9996
+ action("armed_on", text.actions.armed_on),
9997
+ action("armed_off", text.actions.armed_off),
9998
+ ...clips.map((clip) => action(`play_${clip.id}`, `${text.play}: ${clip.id}`)),
9999
+ action("stop_clip", text.actions.stop_clip)
10000
+ ];
10001
+ },
10002
+ metrics: (locale) => {
10003
+ const text = textOf(locale);
10004
+ return [
10005
+ { id: "camera", name: text.metrics.camera, read: () => options.camera?.mode() ?? text.none },
10006
+ { id: "clip", name: text.metrics.clip, read: () => options.avatar.playing ?? text.none },
10007
+ { id: "last_event", name: text.metrics.last_event, read: () => lastEvent || text.none },
10008
+ { id: "state", name: text.metrics.state, read: () => `${state.crouch ? "crouch " : ""}${state.down ? "down " : ""}${state.armed === null ? "" : state.armed ? "armed" : "unarmed"}`.trim() || text.none },
10009
+ { id: "joints", name: text.metrics.joints, read: joints }
10010
+ ];
10011
+ },
10012
+ attach(lent) {
10013
+ host = lent;
10014
+ const stopChange = lent.bench?.onChange(onChange);
10015
+ const stopEvents = options.avatar.on("event", (event) => {
10016
+ lastEvent = `${event.clip} ${event.type} ${round(event.t)}s${event.data && "label" in event.data ? ` ${phaseLabel(event.data.label)}` : ""}`;
10017
+ log("clip_event", { clip: event.clip, event: event.type, t: event.t, data: event.data ?? null });
10018
+ if (event.type === "impact") log("impact", { clip: event.clip, t: event.t, kind: event.data?.kind ?? null });
10019
+ });
10020
+ return () => {
10021
+ stopChange?.();
10022
+ stopEvents();
10023
+ host = null;
10024
+ };
10025
+ }
10026
+ };
10027
+ }
6483
10028
  return __toCommonJS(index_exports);
6484
10029
  })();
6485
10030
  //# sourceMappingURL=index.global.js.map