@adatechnology/game-characters-three 0.8.0 → 0.8.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.
@@ -197,7 +197,7 @@ var GameCharactersThree = (() => {
197
197
  var HIP_PIVOT = "vec3(0.,0.95,0.)";
198
198
  var createBodyChunk = ({ hipHeight = 0.95 } = {}) => hipHeight === 0.95 ? BODY_CHUNK : BODY_CHUNK.replaceAll(HIP_PIVOT, `vec3(0.,${hipHeight},0.)`);
199
199
 
200
- // ../game-shapes/dist/chunk-IFXQIDSA.js
200
+ // ../game-shapes/dist/chunk-M5N2SHNL.js
201
201
  function canonicalJson(value) {
202
202
  if (value === null) return "null";
203
203
  if (typeof value === "number") return Object.is(value, -0) ? "-0" : Number.isFinite(value) ? String(value) : JSON.stringify(String(value));
@@ -1444,8 +1444,8 @@ var GameCharactersThree = (() => {
1444
1444
  groups: []
1445
1445
  };
1446
1446
  }
1447
- function make(kind, p2) {
1448
- switch (kind) {
1447
+ function make(p2) {
1448
+ switch (p2.kind) {
1449
1449
  case "box": {
1450
1450
  const size = p2.size ?? [1, 1, 1];
1451
1451
  const segments = p2.segments ?? [1, 1, 1];
@@ -1474,7 +1474,7 @@ var GameCharactersThree = (() => {
1474
1474
  case "mesh":
1475
1475
  return mesh(p2);
1476
1476
  default:
1477
- throw new Error(`game-shapes: unknown primitive kind "${String(kind)}"`);
1477
+ throw new Error(`game-shapes: unknown primitive kind "${String(p2.kind)}"`);
1478
1478
  }
1479
1479
  }
1480
1480
  var templates = /* @__PURE__ */ new Map();
@@ -1482,7 +1482,7 @@ var GameCharactersThree = (() => {
1482
1482
  var stats = { hits: 0, misses: 0 };
1483
1483
  function buildPrimitive(node, options = {}) {
1484
1484
  const parameters = primitiveParameters(node, options);
1485
- if (node.kind === "mesh" || templateLimit === 0) return make(node.kind, parameters);
1485
+ if (node.kind === "mesh" || templateLimit === 0) return make({ ...node, ...parameters });
1486
1486
  const key = `${node.kind}:${canonicalJson(parameters)}`;
1487
1487
  const cached = templates.get(key);
1488
1488
  if (cached) {
@@ -1492,7 +1492,7 @@ var GameCharactersThree = (() => {
1492
1492
  return cached;
1493
1493
  }
1494
1494
  stats.misses++;
1495
- const built2 = make(node.kind, parameters);
1495
+ const built2 = make({ ...node, ...parameters });
1496
1496
  templates.set(key, built2);
1497
1497
  if (templates.size > templateLimit) templates.delete(templates.keys().next().value);
1498
1498
  return built2;
@@ -1602,6 +1602,57 @@ var GameCharactersThree = (() => {
1602
1602
  const length = Math.hypot(direction[0], direction[1], direction[2]);
1603
1603
  return { speed, direction: [direction[0] / length, direction[1] / length, direction[2] / length], distance: distance3, falloff };
1604
1604
  }
1605
+ var KNOCK_DOWN_SPEED = 2.5;
1606
+ var KNOCKED_DOWN_ANGLE = 1.35;
1607
+ var LIE_SECONDS = 1.6;
1608
+ var STAND_UP_PER_SPEED = 0.25;
1609
+ var FALL_SECONDS = 0.25;
1610
+ var RISE_SECONDS = 0.6;
1611
+ var GROUND_FRICTION = 7;
1612
+ var GRAVITY = 9.81;
1613
+ var KNOCK_CHEST = 1.1;
1614
+ var CHEST = KNOCK_CHEST;
1615
+ var bodyMass = (height, build = 1) => 70 * (height / 1.75) ** 2 * build;
1616
+ function knockOf(blast2, feet, mass, options) {
1617
+ const hit = blastShove(blast2, { position: [feet[0], feet[1] + CHEST, feet[2]], mass }, options);
1618
+ if (!hit) return void 0;
1619
+ const [dx, dy, dz] = hit.direction;
1620
+ 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 };
1621
+ }
1622
+ function stepKnock(knock2, position, dt, groundAt, alive) {
1623
+ const v = knock2.velocity;
1624
+ position.x += v[0] * dt;
1625
+ position.z += v[2] * dt;
1626
+ const ground = groundAt(position.x, position.z);
1627
+ if (knock2.airborne || position.y > ground + 1e-4) {
1628
+ v[1] -= GRAVITY * dt;
1629
+ position.y += v[1] * dt;
1630
+ if (position.y <= ground) {
1631
+ position.y = ground;
1632
+ v[1] = 0;
1633
+ knock2.airborne = false;
1634
+ }
1635
+ } else position.y = ground;
1636
+ const horizontal = Math.hypot(v[0], v[2]);
1637
+ if (!knock2.airborne && horizontal > 0) {
1638
+ const slowed = Math.max(0, horizontal - GROUND_FRICTION * dt);
1639
+ v[0] *= slowed / horizontal;
1640
+ v[2] *= slowed / horizontal;
1641
+ }
1642
+ const moving = horizontal > 0.05 || knock2.airborne;
1643
+ if (knock2.down) {
1644
+ if (moving) knock2.lying = Math.min(1, knock2.lying + dt / FALL_SECONDS);
1645
+ else {
1646
+ knock2.lying = 1;
1647
+ if (alive) {
1648
+ knock2.lieLeft = knock2.lieLeft > 0 ? knock2.lieLeft : LIE_SECONDS + Math.hypot(v[0], v[2]) * STAND_UP_PER_SPEED;
1649
+ knock2.lieLeft -= dt;
1650
+ if (knock2.lieLeft <= 0) knock2.down = false;
1651
+ }
1652
+ }
1653
+ } else if (knock2.lying > 0) knock2.lying = Math.max(0, knock2.lying - dt / RISE_SECONDS);
1654
+ return !moving && !knock2.down && knock2.lying === 0;
1655
+ }
1605
1656
  var DEFAULT_COST_ALLOCATION_BYTES = 1024 * 1024;
1606
1657
  var MISSING_BITS = {
1607
1658
  head: 1,
@@ -2039,45 +2090,45 @@ var GameCharactersThree = (() => {
2039
2090
  segmentRadius: { ...base.segmentRadius, ...patch.segmentRadius }
2040
2091
  });
2041
2092
  var createCorpseLedger = (options) => {
2042
- const entries = [];
2093
+ const entries2 = [];
2043
2094
  return {
2044
- entries,
2095
+ entries: entries2,
2045
2096
  get count() {
2046
- return entries.length;
2097
+ return entries2.length;
2047
2098
  },
2048
2099
  add(data) {
2049
- if (entries.length < options.max) {
2050
- entries.push({ age: 0, data });
2100
+ if (entries2.length < options.max) {
2101
+ entries2.push({ age: 0, data });
2051
2102
  return void 0;
2052
2103
  }
2053
2104
  let oldest = 0;
2054
- for (let index = 1; index < entries.length; index++) if (entries[index].age > entries[oldest].age) oldest = index;
2055
- const replaced = entries[oldest].data;
2056
- entries[oldest] = { age: 0, data };
2105
+ for (let index = 1; index < entries2.length; index++) if (entries2[index].age > entries2[oldest].age) oldest = index;
2106
+ const replaced = entries2[oldest].data;
2107
+ entries2[oldest] = { age: 0, data };
2057
2108
  return replaced;
2058
2109
  },
2059
2110
  update(dt) {
2060
2111
  const removed = [];
2061
- for (let index = 0; index < entries.length; index++) {
2062
- const entry = entries[index];
2112
+ for (let index = 0; index < entries2.length; index++) {
2113
+ const entry = entries2[index];
2063
2114
  entry.age += dt;
2064
2115
  if (entry.age <= options.seconds) continue;
2065
2116
  removed.push(entry.data);
2066
- entries[index] = entries[entries.length - 1];
2067
- entries.pop();
2117
+ entries2[index] = entries2[entries2.length - 1];
2118
+ entries2.pop();
2068
2119
  index--;
2069
2120
  }
2070
2121
  return removed;
2071
2122
  },
2072
2123
  remove(index) {
2073
- const entry = entries[index];
2124
+ const entry = entries2[index];
2074
2125
  if (!entry) return void 0;
2075
- entries[index] = entries[entries.length - 1];
2076
- entries.pop();
2126
+ entries2[index] = entries2[entries2.length - 1];
2127
+ entries2.pop();
2077
2128
  return entry.data;
2078
2129
  },
2079
2130
  clear() {
2080
- entries.length = 0;
2131
+ entries2.length = 0;
2081
2132
  }
2082
2133
  };
2083
2134
  };
@@ -3534,18 +3585,18 @@ var GameCharactersThree = (() => {
3534
3585
  };
3535
3586
  var penetrateLine = (params) => params.model === "team-game" ? teamGameLine(params) : physicalLine(params);
3536
3587
  var mergeById = (shipped, extra) => {
3537
- const entries = /* @__PURE__ */ new Map();
3538
- for (const entry of [...shipped, ...extra ?? []]) entries.set(entry.id, entry);
3539
- return entries;
3588
+ const entries2 = /* @__PURE__ */ new Map();
3589
+ for (const entry of [...shipped, ...extra ?? []]) entries2.set(entry.id, entry);
3590
+ return entries2;
3540
3591
  };
3541
- var applyPatches = (entries, patches) => {
3592
+ var applyPatches = (entries2, patches) => {
3542
3593
  for (const [id, patch] of Object.entries(patches ?? {})) {
3543
- const entry = entries.get(id);
3544
- if (entry) entries.set(id, { ...entry, ...patch, id });
3594
+ const entry = entries2.get(id);
3595
+ if (entry) entries2.set(id, { ...entry, ...patch, id });
3545
3596
  }
3546
3597
  };
3547
- var removeIds = (entries, ids) => {
3548
- for (const id of ids ?? []) entries.delete(id);
3598
+ var removeIds = (entries2, ids) => {
3599
+ for (const id of ids ?? []) entries2.delete(id);
3549
3600
  };
3550
3601
  var DEFAULT_CORPSES = { max: 400, seconds: 900 };
3551
3602
  var PERSON_PRESET = { id: "person", kind: "person", age: "adult" };
@@ -5678,12 +5729,12 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
5678
5729
  const o = add(Hd, cap(0.205, PI / 2), c, 0, 1.835, -5e-3);
5679
5730
  o.scale.set(1, 0.98, 1.08);
5680
5731
  add(Hd, new THREE.CylinderGeometry(0.208, 0.212, 0.04, 20), c, 0, 1.84, -5e-3);
5681
- if (sp.hat.tape) add(Hd, new THREE.CylinderGeometry(0.205, 0.207, 0.035, 20), cmat(sp.hat.tape), 0, 1.9, -5e-3);
5682
- if (sp.hat.photo) {
5732
+ if (sp.hat?.tape) add(Hd, new THREE.CylinderGeometry(0.205, 0.207, 0.035, 20), cmat(sp.hat.tape), 0, 1.9, -5e-3);
5733
+ if (sp.hat?.photo) {
5683
5734
  add(Hd, Bx(0.07, 0.08, 0.012), cmat(16052448), 0.13, 1.9, 0.14, 0, 0.75, 0);
5684
5735
  add(Hd, Bx(0.05, 0.055, 0.014), cmat(9071184), 0.13, 1.9, 0.141, 0, 0.75, 0);
5685
5736
  }
5686
- if (sp.hat.nvg) {
5737
+ if (sp.hat?.nvg) {
5687
5738
  add(Hd, Bx(0.07, 0.05, 0.06), cmat(1710618), 0, 2, 0.175);
5688
5739
  for (const s of [-1, 1]) add(Hd, new THREE.CylinderGeometry(0.024, 0.024, 0.09, 10).rotateX(PI / 2), cmat(2767402), s * 0.032, 1.965, 0.235);
5689
5740
  }
@@ -6246,7 +6297,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
6246
6297
  };
6247
6298
 
6248
6299
  // src/instanced/flying-limbs.ts
6249
- var GRAVITY = 9.8;
6300
+ var GRAVITY2 = 9.8;
6250
6301
  var FLOOR_Y = 0.07;
6251
6302
  var BOUNCE = -0.3;
6252
6303
  var FRICTION = 0.6;
@@ -6298,7 +6349,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
6298
6349
  limbs.forEach((limb2, index) => {
6299
6350
  if (!limb2.rest) {
6300
6351
  limb2.t += dt;
6301
- limb2.vy -= GRAVITY * dt;
6352
+ limb2.vy -= GRAVITY2 * dt;
6302
6353
  limb2.x += limb2.vx * dt;
6303
6354
  limb2.y += limb2.vy * dt;
6304
6355
  limb2.z += limb2.vz * dt;
@@ -6517,7 +6568,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
6517
6568
  };
6518
6569
  function build(spec) {
6519
6570
  const ti = Math.max(0, BCARDS.findIndex((x) => x.n === spec.type)), z = BCARDS[ti];
6520
- const P = Object.assign({}, BASE, TYPES[spec.type] || {}, spec.pose || {}), d = spec.decay ?? 0, life = spec.life ?? 1, cut = spec.cut || {};
6571
+ const P = Object.assign({}, BASE, TYPES[spec.type ?? ""] || {}, spec.pose || {}), d = spec.decay ?? 0, life = spec.life ?? 1, cut = spec.cut || {};
6521
6572
  P.s *= spec.h ?? 1;
6522
6573
  P.bulk *= spec.bulk ?? 1;
6523
6574
  if (life === 0) {
@@ -6581,7 +6632,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
6581
6632
  };
6582
6633
  const ball = (p2, r, m, x, y, z2) => add(p2, SPH(r, SEG, 12), m, x, y, z2);
6583
6634
  topM_ref = topM;
6584
- const SKM = {}, skM = (c) => SKM[c] || (SKM[c] = new THREE.MeshStandardMaterial({ color: c, roughness: 0.3, metalness: 0, polygonOffset: true, polygonOffsetFactor: -4, polygonOffsetUnits: -4 }));
6635
+ const SKM = {}, skM = (c) => SKM[String(c)] || (SKM[String(c)] = new THREE.MeshStandardMaterial({ color: c, roughness: 0.3, metalness: 0, polygonOffset: true, polygonOffsetFactor: -4, polygonOffsetUnits: -4 }));
6585
6636
  const flat = (p2, x, y, zz, sx, sy, c) => {
6586
6637
  const m = new THREE.Mesh(BLOB, skM(c));
6587
6638
  m.rotation.set(PI / 2, 0, BR() * 6.28);
@@ -7000,7 +7051,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
7000
7051
  root.userData.rig = rig;
7001
7052
  return root;
7002
7053
  }
7003
- const marked2 = (...args) => markKitOrigin(build(...args), { owner: "game-characters-three", kind: "person" });
7054
+ const marked2 = (spec) => markKitOrigin(build(spec), { owner: "game-characters-three", kind: "person" });
7004
7055
  return { build: marked2, TYPES, setLOD(k) {
7005
7056
  LK = k;
7006
7057
  SEG = Math.max(5, Math.round(16 * k));
@@ -7652,7 +7703,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
7652
7703
  const hg = new THREE.Group();
7653
7704
  hg.position.y = -0.3;
7654
7705
  el.add(hg);
7655
- const handM = glove ? cmat(glove[1]) : skinM;
7706
+ const handM = glove ? cmat(glove[1] ?? 16777215) : skinM;
7656
7707
  const palm = ball(hg, 0.048, handM, 0, -0.035, 0);
7657
7708
  palm.scale.set(0.6, 1.05, 1);
7658
7709
  const { fingers, th } = buildHand({ THREE, add, hg, handM, s, detailed });
@@ -7664,7 +7715,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
7664
7715
  }
7665
7716
  for (const e of sp.ex || []) {
7666
7717
  const [k, c] = e;
7667
- const m = c !== void 0 ? cmat(c) : null;
7718
+ const m = c !== void 0 ? cmat(c) : topM;
7668
7719
  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 });
7669
7720
  }
7670
7721
  if (sp.back === "shotgun") {
@@ -7685,10 +7736,11 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
7685
7736
  const metal = cmat(9080982, { metalness: 0.7, roughness: 0.35 }), dark = cmat(1842463, { metalness: 0.6, roughness: 0.45 }), woodM = cmat(6961692);
7686
7737
  HAND_ITEMS[kind]?.({ THREE, PI, add, Bx, cmat, g, metal, dark, woodM, lights: options.lights, sources: lightSources });
7687
7738
  }
7688
- item(sp.hand, arms[0].mount);
7689
- item(sp.lhand, arms[1].mount);
7690
- if (sp.hand) arms[0].hold = true;
7691
- if (sp.lhand) arms[1].hold = true;
7739
+ const [rightArm, leftArm] = arms;
7740
+ item(sp.hand, rightArm.mount);
7741
+ item(sp.lhand, leftArm.mount);
7742
+ if (sp.hand) rightArm.hold = true;
7743
+ if (sp.lhand) leftArm.hold = true;
7692
7744
  const zb = [];
7693
7745
  for (let i = 0; i < 4; i++) splat(U, -0.15 + R() * 0.3, 1.2 + R() * 0.25, 0.17, 0.035 + R() * 0.025, 3874068, 3, zb);
7694
7746
  {
@@ -7732,8 +7784,9 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
7732
7784
  segs["shin" + k] = { node: l.kn, label: "Canela e p\xE9 " + LSIDE[k], hp: 55, r: 0.08, leg: k };
7733
7785
  });
7734
7786
  for (const k in segs) {
7735
- segs[k].max = segs[k].hp;
7736
- segs[k].state = "ok";
7787
+ const seg = segs[k];
7788
+ seg.max = seg.hp;
7789
+ seg.state = "ok";
7737
7790
  }
7738
7791
  const mouth = add(Hd, Bx(0.1, 0.04, 0.02), cmat(3803656), 0, 1.69, 0.145);
7739
7792
  mouth.visible = false;
@@ -7801,7 +7854,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
7801
7854
  if (a.fingers) {
7802
7855
  const gr = (a.hold || a.grip ? 1.25 : 0.4) * (z ? 0.5 : 1);
7803
7856
  a.fingers.forEach((f, j) => f.rotation.z = -a.s * gr * (j % 2 ? 1.1 : 0.9));
7804
- a.th.rotation.z = -a.s * (0.45 + gr * 0.25);
7857
+ if (a.th) a.th.rotation.z = -a.s * (0.45 + gr * 0.25);
7805
7858
  a.hg.rotation.x = reduce ? 0 : -W * Math.sin(ph - 0.6) * 0.15 * a.s;
7806
7859
  }
7807
7860
  });
@@ -7815,7 +7868,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
7815
7868
  }
7816
7869
  function zombify(c, cat) {
7817
7870
  c.skinM.color.copy(c.base).lerp(ZSKIN2, 1);
7818
- c.eyeM.color.set(EYE[cat || "lento"]);
7871
+ c.eyeM.color.set(EYE[cat || "lento"] ?? EYE.lento);
7819
7872
  c.zb.forEach((b) => b.visible = true);
7820
7873
  c.mouth.visible = true;
7821
7874
  c.bags.material.opacity = 0.9;
@@ -7827,7 +7880,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
7827
7880
  chars.push(c);
7828
7881
  root.add(c.root);
7829
7882
  if (zed && !p2.kid) zombify(c, p2.zcat);
7830
- c.z = zed && !p2.kid;
7883
+ c.z = !!(zed && !p2.kid);
7831
7884
  }
7832
7885
  (p2.kids || []).forEach((k) => {
7833
7886
  const c = build(k, 0);
@@ -7837,7 +7890,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
7837
7890
  chars.push(c);
7838
7891
  root.add(c.root);
7839
7892
  });
7840
- chars.forEach((c) => pose(c, c.z, 0, 0));
7893
+ chars.forEach((c) => pose(c, !!c.z, 0, 0));
7841
7894
  return { root, chars };
7842
7895
  }
7843
7896
  const mark = (c) => {
@@ -8070,7 +8123,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
8070
8123
  };
8071
8124
 
8072
8125
  // src/wounds/flying.ts
8073
- var GRAVITY2 = 9.8;
8126
+ var GRAVITY3 = 9.8;
8074
8127
  var FLOOR_OFFSET = 0.08;
8075
8128
  var BOUNCE_LIMIT = 1.2;
8076
8129
  var BOUNCE_VERTICAL = -0.25;
@@ -8112,7 +8165,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
8112
8165
  update(dt) {
8113
8166
  for (const piece of pieces) {
8114
8167
  if (piece.rest) continue;
8115
- piece.velocity.y -= GRAVITY2 * dt;
8168
+ piece.velocity.y -= GRAVITY3 * dt;
8116
8169
  piece.object.position.addScaledVector(piece.velocity, dt);
8117
8170
  quaternion.setFromEuler(euler.set(piece.spin.x * dt, piece.spin.y * dt, piece.spin.z * dt));
8118
8171
  piece.object.quaternion.multiply(quaternion);
@@ -8486,7 +8539,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
8486
8539
  };
8487
8540
  };
8488
8541
 
8489
- // ../game-audio/dist/chunk-DZITVFMJ.js
8542
+ // ../game-audio/dist/chunk-7TLFY7VO.js
8490
8543
  var DISTANCE_CURVES = {
8491
8544
  /** The game's `sfx`: `vol / (1 + d² × 0.004)`, cutoff `/ (1 + d × 0.01)`, silent below 0.01 (jogo L62091–62092, L62101). */
8492
8545
  game_sfx: { model: "inverse_square", k: 4e-3, cutoffK: 0.01, minGain: 0.01 },
@@ -8549,15 +8602,31 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
8549
8602
  {
8550
8603
  id: "game",
8551
8604
  master: 0.5,
8552
- noise: { seconds: 1.5, create: "lazy" },
8553
- sources: ["jogo:L62077-62081 master 0.5 to the output", "jogo:L62082-62088 noise 1.5 s made by the first sound that needs it"]
8605
+ noise: {
8606
+ seconds: 1.5,
8607
+ create: "lazy"
8608
+ },
8609
+ sources: [
8610
+ "jogo:L62077-62081 master 0.5 to the output",
8611
+ "jogo:L62082-62088 noise 1.5 s made by the first sound that needs it"
8612
+ ]
8554
8613
  },
8555
8614
  {
8556
8615
  id: "art_scene",
8557
8616
  master: 0.85,
8558
- compressor: { threshold: -12, ratio: 5 },
8559
- reverb: { seconds: 2.2, decay: 3.4, wet: 0.4 },
8560
- noise: { seconds: 2, create: "eager" },
8617
+ compressor: {
8618
+ threshold: -12,
8619
+ ratio: 5
8620
+ },
8621
+ reverb: {
8622
+ seconds: 2.2,
8623
+ decay: 3.4,
8624
+ wet: 0.4
8625
+ },
8626
+ noise: {
8627
+ seconds: 2,
8628
+ create: "eager"
8629
+ },
8561
8630
  sources: [
8562
8631
  "cena:L1308 compressor -12 dB, ratio 5",
8563
8632
  "cena:L1309 master 0.85",
@@ -8565,6 +8634,30 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
8565
8634
  "cena:L1311 wet 0.4",
8566
8635
  "cena:L1312 noise 2 s made with the chain"
8567
8636
  ]
8637
+ },
8638
+ {
8639
+ id: "kit",
8640
+ master: 0.85,
8641
+ compressor: {
8642
+ threshold: -12,
8643
+ ratio: 5
8644
+ },
8645
+ reverb: {
8646
+ seconds: 2.2,
8647
+ decay: 3.4,
8648
+ wet: 0.4
8649
+ },
8650
+ noise: {
8651
+ seconds: 2,
8652
+ create: "eager"
8653
+ },
8654
+ sources: [
8655
+ "sdk: the art scene chain (cena L1308-L1312) with a limiter after the compressor: the page has none, and a blast with its debris and a fire catching reached +7 dBFS"
8656
+ ],
8657
+ limiter: {
8658
+ ceiling: -1,
8659
+ knee: -6
8660
+ }
8568
8661
  }
8569
8662
  ];
8570
8663
  var MIX_PROFILES = Object.fromEntries(
@@ -8615,6 +8708,339 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
8615
8708
  }
8616
8709
  ]
8617
8710
  };
8711
+ var entries = (category, list2) => list2.map(([id, priority, current]) => ({ id, category, priority, ...current ? { current } : {} }));
8712
+ var SFX_CATALOG = [
8713
+ ...entries("armas", [
8714
+ ["pistol_22lr", 2, "sfx_pistol"],
8715
+ ["pistol_9mm", 1, "sfx_pistol"],
8716
+ ["pistol_45", 1, "sfx_pistol"],
8717
+ ["revolver_38_357", 2, "sfx_pistol"],
8718
+ ["revolver_44_50ae", 3, "sfx_pistol"],
8719
+ ["smg_9mm_auto", 1, "sfx_pistol"],
8720
+ ["shotgun_12", 1, "sfx_shotgun"],
8721
+ ["rifle_5_56", 1, "sfx_rifle"],
8722
+ ["rifle_7_62x39", 1, "sfx_rifle"],
8723
+ ["rifle_auto_burst", 1, "sfx_rifle"],
8724
+ ["rifle_308_3006", 2, "sfx_rifle"],
8725
+ ["sniper_338_300wm", 2, "sfx_rifle"],
8726
+ ["antimateriel_50bmg", 3, "sfx_rifle"],
8727
+ ["suppressed_pistol", 2],
8728
+ ["suppressed_rifle", 2],
8729
+ ["gunshot_far_pistol", 1],
8730
+ ["gunshot_far_rifle", 1],
8731
+ ["gunshot_far_shotgun", 1],
8732
+ ["gunshot_far_heavy", 2],
8733
+ ["gunshot_tail_indoor", 1],
8734
+ ["gunshot_tail_outdoor", 1],
8735
+ ["bullet_crack_by", 2],
8736
+ ["bullet_whiz", 2],
8737
+ ["ricochet_metal", 2, "ping"],
8738
+ ["dry_fire", 1],
8739
+ ["mag_out", 1],
8740
+ ["mag_in", 1],
8741
+ ["slide_pull_release", 1],
8742
+ ["pump_cycle", 1],
8743
+ ["casing_drop_concreto_pistol", 1],
8744
+ ["casing_drop_concreto_rifle", 1],
8745
+ ["casing_drop_concreto_shell", 1],
8746
+ ["casing_drop_madeira_pistol", 1],
8747
+ ["casing_drop_madeira_rifle", 1],
8748
+ ["casing_drop_madeira_shell", 1],
8749
+ ["casing_drop_metal_pistol", 1],
8750
+ ["casing_drop_metal_rifle", 1],
8751
+ ["casing_drop_metal_shell", 1],
8752
+ ["casing_drop_terra_pistol", 1],
8753
+ ["casing_drop_terra_rifle", 1],
8754
+ ["casing_drop_terra_shell", 1],
8755
+ ["rocket_fire", 2]
8756
+ ]),
8757
+ ...entries("explosoes-fogo", [
8758
+ ["explosion_grenade", 1, "boom"],
8759
+ ["explosion_big", 1, "boom_big"],
8760
+ ["explosion_car", 2, "boom_big"],
8761
+ ["explosion_far", 1],
8762
+ ["debris_rain_stone", 1],
8763
+ ["molotov_break_ignite", 1, "glass_shatter"],
8764
+ ["fire_ignite", 1, "hiss"],
8765
+ ["fire_loop_small", 1],
8766
+ ["fire_loop_large", 1],
8767
+ ["fire_extinguish", 2, "hiss"],
8768
+ ["gas_leak_hiss", 2],
8769
+ ["structure_collapse", 2, "crumble"]
8770
+ ]),
8771
+ ...entries("personagem", [
8772
+ ["footstep_concrete_walk", 1, "sfx_step"],
8773
+ ["footstep_wood_walk", 1, "sfx_step"],
8774
+ ["footstep_dirt_walk", 1, "sfx_step"],
8775
+ ["footstep_grass_walk", 1, "sfx_step"],
8776
+ ["footstep_gravel_walk", 1, "sfx_step"],
8777
+ ["land_concrete", 1, "sfx_step"],
8778
+ ["punch_swing", 1],
8779
+ ["punch_hit_body", 1, "sfx_flesh"],
8780
+ ["kick_hit", 1, "sfx_flesh"],
8781
+ ["knife_stab", 1],
8782
+ ["blunt_hit", 1],
8783
+ ["bite", 1, "sfx_flesh"],
8784
+ ["body_fall", 1],
8785
+ ["player_hurt", 2]
8786
+ ]),
8787
+ ...entries("veiculos", [
8788
+ ["engine_loop_car", 1],
8789
+ ["engine_start", 1],
8790
+ ["crash_light", 1, "crash"],
8791
+ ["crash_heavy", 1, "crash"],
8792
+ ["car_door_open", 1, "latch"],
8793
+ ["car_door_close", 1, "shut_metal"],
8794
+ ["horn_car", 2, "horn"],
8795
+ ["tire_skid_asphalt", 2]
8796
+ ]),
8797
+ ...entries("itens-portas", [
8798
+ ["item_pickup_metal", 1],
8799
+ ["can_open", 1],
8800
+ ["can_crush", 1],
8801
+ ["door_wood_open", 1, "latch"],
8802
+ ["door_wood_close", 1, "shut_wood"],
8803
+ ["door_creak", 1, "creak_wood"],
8804
+ ["door_locked_rattle", 1, "rattle"],
8805
+ ["drawer_open", 2, "slide"],
8806
+ ["fridge_close", 2, "shut_metal"]
8807
+ ]),
8808
+ ...entries("ambiente", [
8809
+ ["rain_loop", 2],
8810
+ ["wind_loop", 2],
8811
+ ["thunder_near", 2],
8812
+ ["thunder_far", 2],
8813
+ ["water_splash", 2]
8814
+ ])
8815
+ ];
8816
+ var SFX_MATERIALS = [
8817
+ ["steel", "metal"],
8818
+ ["aluminium", "metal"],
8819
+ ["wood", "wood"],
8820
+ ["plywood", "wood"],
8821
+ ["mdf", "wood"],
8822
+ ["glass", "glass"],
8823
+ ["tempered_glass", "glass"],
8824
+ ["ceramic", "glass"],
8825
+ ["concrete", "masonry"],
8826
+ ["brick", "masonry"],
8827
+ ["plaster", "masonry"],
8828
+ ["plastic", "soft"],
8829
+ ["fabric", "soft"],
8830
+ ["paper", "soft"],
8831
+ ["foliage", "soft"],
8832
+ ["soil", "soft"],
8833
+ ["flesh", "soft"]
8834
+ ];
8835
+ var SFX_BLOWS = ["bullet", "blunt", "blade", "break", "drag"];
8836
+ var CURRENT_BY_GROUP = {
8837
+ metal: { bullet: "clang", blunt: "clang", blade: "clang", break: "clang", drag: "drag_metal" },
8838
+ wood: { bullet: "wood_hit", blunt: "wood_hit", blade: "wood_hit", break: "crack", drag: "drag_wood" },
8839
+ glass: { bullet: "ping", blunt: "ping", break: "glass_shatter", drag: "drag_glass" },
8840
+ masonry: { bullet: "chip", blunt: "chip", blade: "chip", break: "crumble", drag: "drag_masonry" },
8841
+ soft: { bullet: "thud", blunt: "thud", blade: "thud", break: "thud", drag: "drag_soft" }
8842
+ };
8843
+ var impactSoundId = (material, blow) => `impact_${material}_${blow}`;
8844
+ var SFX_IMPACTS = SFX_MATERIALS.flatMap(
8845
+ ([material, group]) => SFX_BLOWS.map((blow) => {
8846
+ const current = CURRENT_BY_GROUP[group]?.[blow];
8847
+ return { id: impactSoundId(material, blow), category: "impactos", priority: ["steel", "wood", "glass", "concrete", "brick", "soil", "flesh"].includes(material) && blow === "bullet" ? 1 : 2, ...current ? { current } : {} };
8848
+ })
8849
+ );
8850
+ var CALIBRATION_ID = "calibration_shot";
8851
+ var PREFIX = "calibration/";
8852
+ var url = (name) => `${PREFIX}${name}`;
8853
+ var CALIBRATION_SOUND = {
8854
+ id: CALIBRATION_ID,
8855
+ bus: "weapons",
8856
+ close: ["close_1.wav", "close_2.wav", "close_3.wav", "close_4.wav"].map((name) => ({ url: url(name) })),
8857
+ far: ["far_1.wav", "far_2.wav"].map((name) => ({ url: url(name) })),
8858
+ tiers: [
8859
+ { name: "light", from: 0, close: ["light_1.wav", "light_2.wav"].map((name) => ({ url: url(name) })) },
8860
+ { name: "medium", from: 0.34, close: ["close_1.wav", "close_2.wav", "close_3.wav", "close_4.wav"].map((name) => ({ url: url(name) })) },
8861
+ { name: "heavy", from: 0.67, close: ["heavy_1.wav", "heavy_2.wav"].map((name) => ({ url: url(name) })) }
8862
+ ],
8863
+ tail: { indoor: [{ url: url("tail_in.wav") }], outdoor: [{ url: url("tail_out.wav") }] },
8864
+ pitch: 0.04,
8865
+ choke: { voices: 2 },
8866
+ fallback: "sfx_pistol",
8867
+ sources: ["sdk: calibration takes synthesized by the harness (measure/calibration.ts), no file, no licence"]
8868
+ };
8869
+ var CALIBRATION_LOOP_ID = "calibration_loop";
8870
+ var CALIBRATION_LOOP_SOUND = {
8871
+ id: CALIBRATION_LOOP_ID,
8872
+ bus: "ambience",
8873
+ close: ["loop_1.wav", "loop_2.wav", "loop_3.wav"].map((name) => ({ url: url(name) })),
8874
+ loop: { crossfade: 0.15 },
8875
+ sources: ["sdk: calibration takes synthesized by the harness (measure/calibration.ts), no file, no licence"]
8876
+ };
8877
+ var CRITERIA_TARGETS = {
8878
+ /** C1: event to the first sample, and onset to the peak (one 60 fps frame). */
8879
+ syncMs: 20,
8880
+ peakAfterOnsetMs: 1e3 / 60,
8881
+ /** C3: distances measured, metres. */
8882
+ distances: [1, 10, 50, 200],
8883
+ /** C5: plays, distinct takes and the pitch range (fraction). */
8884
+ plays: 10,
8885
+ minTakes: 4,
8886
+ pitch: [0.03, 0.05],
8887
+ /** C6: the highest peak, dBFS. */
8888
+ peakDb: -1,
8889
+ /** C8: the end of each file against its peak, dB. */
8890
+ endDropDb: -40,
8891
+ /** C9: a burst of rapid fire. */
8892
+ burst: 20,
8893
+ burstSpacing: 0.06
8894
+ };
8895
+ var PT = {
8896
+ group: "Som",
8897
+ name: "Painel de som (arquivos e C1\u2013C10)",
8898
+ controls: {
8899
+ category: "1 \xB7 Categoria",
8900
+ sound: "1 \xB7 Som",
8901
+ play: "1 \xB7 \u25B6 Tocar",
8902
+ material: "2 \xB7 Material",
8903
+ blow: "2 \xB7 Golpe",
8904
+ strike: "2 \xB7 \u25B6 Tocar golpe",
8905
+ distance: "3 \xB7 Dist\xE2ncia",
8906
+ bearing: "3 \xB7 Dire\xE7\xE3o",
8907
+ environment: "3 \xB7 Lugar",
8908
+ strength: "3 \xB7 For\xE7a",
8909
+ wall: "3 \xB7 Atr\xE1s da parede",
8910
+ burst: "3 \xB7 Rajada 20\xD7",
8911
+ play_a: "4 \xB7 \u25B6 A (atual)",
8912
+ play_b: "4 \xB7 \u25B6 B (novo)",
8913
+ ab_cycle: "4 \xB7 Alternar A/B",
8914
+ blind: "4 \xB7 \xC0s cegas (X)",
8915
+ reveal: "4 \xB7 Revelar X",
8916
+ prefer_a: "4 \xB7 Prefiro A",
8917
+ prefer_b: "4 \xB7 Prefiro B",
8918
+ measure: "5 \xB7 Medir C1\u2013C10",
8919
+ record: "5 \xB7 Gravar 3 s",
8920
+ approve: "5 \xB7 Aprovo (C10)"
8921
+ },
8922
+ hints: {
8923
+ sound: "A = arquivo, S = sintetizado, F = faltando. O que tem arquivo toca o arquivo; o resto toca o som atual.",
8924
+ strike: "Toca impact_<material>_<golpe>: o arquivo se existir, sen\xE3o o som atual daquele material.",
8925
+ wall: "P\xF5e a parede de casa entre voc\xEA e a fonte: o som fica abafado (C4).",
8926
+ burst: "Vinte vezes a cada 60 ms, como uma rajada (C9).",
8927
+ ab_cycle: "A, B, A, B, um por segundo.",
8928
+ blind: "Toca A ou B sem dizer qual; depois revele.",
8929
+ measure: "Mede o som escolhido no motor real (contexto offline): sincronia, som certo, dist\xE2ncia, lado, varia\xE7\xE3o, volume, for\xE7a, cauda e rajada.",
8930
+ record: "Grava 3 s da sa\xEDda com o som tocando e baixa o arquivo (C10).",
8931
+ approve: "Marca o C10 do som escolhido como aprovado pelo seu ouvido."
8932
+ },
8933
+ categories: {
8934
+ armas: "Armas",
8935
+ impactos: "Impactos",
8936
+ "explosoes-fogo": "Explos\xF5es e fogo",
8937
+ personagem: "Personagem",
8938
+ veiculos: "Ve\xEDculos",
8939
+ "itens-portas": "Itens e portas",
8940
+ ambiente: "Ambiente",
8941
+ calibracao: "Calibra\xE7\xE3o (SDK)"
8942
+ },
8943
+ blows: { bullet: "tiro", blunt: "soco/chute", blade: "faca", break: "quebra", drag: "arrasto/queda" },
8944
+ materials: {
8945
+ steel: "a\xE7o",
8946
+ aluminium: "alum\xEDnio",
8947
+ wood: "madeira",
8948
+ plywood: "compensado",
8949
+ mdf: "MDF",
8950
+ glass: "vidro",
8951
+ tempered_glass: "vidro temperado",
8952
+ ceramic: "cer\xE2mica",
8953
+ concrete: "concreto",
8954
+ brick: "tijolo",
8955
+ plaster: "gesso",
8956
+ plastic: "pl\xE1stico",
8957
+ fabric: "tecido",
8958
+ paper: "papel\xE3o",
8959
+ foliage: "folhagem",
8960
+ soil: "terra",
8961
+ flesh: "carne"
8962
+ },
8963
+ environments: { indoor: "interior", outdoor: "exterior" },
8964
+ strengths: { light: "leve", medium: "m\xE9dio", heavy: "forte" },
8965
+ states: { file: "A", synth: "S", missing: "F" },
8966
+ criteria: { C1: "C1 Sincronia", C2: "C2 Certo p/ a\xE7\xE3o", C3: "C3 Dist\xE2ncia", C4: "C4 Posi\xE7\xE3o", C5: "C5 Varia\xE7\xE3o", C6: "C6 Volume", C7: "C7 Intensidade", C8: "C8 Cauda", C9: "C9 Rajada", C10: "C10 Escuta" },
8967
+ metrics: { chosen: "1 \xB7 Escolhido", matrix: "2 \xB7 Matriz", last: "\xDAltimo tocado", ab: "4 \xB7 A \xD7 B", blind: "4 \xB7 X", verdicts: "4 \xB7 Prefer\xEAncias", state: "5 \xB7 Medi\xE7\xE3o", count: "1 \xB7 Cat\xE1logo" },
8968
+ run: { idle: "parada", measuring: "medindo\u2026", done: "pronta", failed: "falhou", recording: "gravando\u2026", recorded: "grava\xE7\xE3o baixada" },
8969
+ words: { none: "\u2014", hidden: "? (revele)", prefers: "prefere", approved: "aprovado pelo dono" },
8970
+ probe: "Fonte do som",
8971
+ wall: "Parede (oclus\xE3o)",
8972
+ scenarios: { pipeline: "Arquivo \u2192 decodifica \u2192 toca (round-robin, cauda)", criteria: "Crit\xE9rios C1\u2013C9 no som de calibra\xE7\xE3o", loop: "Loop de arquivo: emenda sem buraco (crossfade)", panel: "Painel: categorias, matriz, A/B e parede" }
8973
+ };
8974
+ var EN2 = {
8975
+ ...PT,
8976
+ group: "Sound",
8977
+ name: "Sound panel (files and C1\u2013C10)",
8978
+ controls: {
8979
+ category: "1 \xB7 Category",
8980
+ sound: "1 \xB7 Sound",
8981
+ play: "1 \xB7 \u25B6 Play",
8982
+ material: "2 \xB7 Material",
8983
+ blow: "2 \xB7 Blow",
8984
+ strike: "2 \xB7 \u25B6 Play blow",
8985
+ distance: "3 \xB7 Distance",
8986
+ bearing: "3 \xB7 Bearing",
8987
+ environment: "3 \xB7 Place",
8988
+ strength: "3 \xB7 Strength",
8989
+ wall: "3 \xB7 Behind the wall",
8990
+ burst: "3 \xB7 Burst 20\xD7",
8991
+ play_a: "4 \xB7 \u25B6 A (current)",
8992
+ play_b: "4 \xB7 \u25B6 B (new)",
8993
+ ab_cycle: "4 \xB7 Alternate A/B",
8994
+ blind: "4 \xB7 Blind (X)",
8995
+ reveal: "4 \xB7 Reveal X",
8996
+ prefer_a: "4 \xB7 Prefer A",
8997
+ prefer_b: "4 \xB7 Prefer B",
8998
+ measure: "5 \xB7 Measure C1\u2013C10",
8999
+ record: "5 \xB7 Record 3 s",
9000
+ approve: "5 \xB7 Approve (C10)"
9001
+ },
9002
+ hints: {
9003
+ sound: "A = file, S = synthesized, F = missing. A file plays the file; the rest plays the current sound.",
9004
+ strike: "Plays impact_<material>_<blow>: the file if there is one, else the current sound of that material.",
9005
+ wall: "Puts the house wall between you and the source: the sound is muffled (C4).",
9006
+ burst: "Twenty times every 60 ms, like a burst (C9).",
9007
+ ab_cycle: "A, B, A, B, one a second.",
9008
+ blind: "Plays A or B without saying which; reveal it after.",
9009
+ measure: "Measures the chosen sound through the real engine (offline context): sync, right sound, distance, side, variation, level, strength, tail and burst.",
9010
+ record: "Records 3 s of the output with the sound playing and downloads it (C10).",
9011
+ approve: "Marks C10 of the chosen sound as approved by your ear."
9012
+ },
9013
+ categories: { armas: "Weapons", impactos: "Impacts", "explosoes-fogo": "Explosions and fire", personagem: "Character", veiculos: "Vehicles", "itens-portas": "Items and doors", ambiente: "Ambience", calibracao: "Calibration (SDK)" },
9014
+ blows: { bullet: "bullet", blunt: "punch/kick", blade: "knife", break: "break", drag: "drag/fall" },
9015
+ materials: {
9016
+ steel: "steel",
9017
+ aluminium: "aluminium",
9018
+ wood: "wood",
9019
+ plywood: "plywood",
9020
+ mdf: "MDF",
9021
+ glass: "glass",
9022
+ tempered_glass: "tempered glass",
9023
+ ceramic: "ceramic",
9024
+ concrete: "concrete",
9025
+ brick: "brick",
9026
+ plaster: "plaster",
9027
+ plastic: "plastic",
9028
+ fabric: "fabric",
9029
+ paper: "cardboard",
9030
+ foliage: "foliage",
9031
+ soil: "soil",
9032
+ flesh: "flesh"
9033
+ },
9034
+ environments: { indoor: "indoor", outdoor: "outdoor" },
9035
+ strengths: { light: "light", medium: "medium", heavy: "heavy" },
9036
+ criteria: { C1: "C1 Sync", C2: "C2 Right sound", C3: "C3 Distance", C4: "C4 Position", C5: "C5 Variation", C6: "C6 Level", C7: "C7 Strength", C8: "C8 Tail", C9: "C9 Burst", C10: "C10 Listening" },
9037
+ metrics: { chosen: "1 \xB7 Chosen", matrix: "2 \xB7 Matrix", last: "Last played", ab: "4 \xB7 A \xD7 B", blind: "4 \xB7 X", verdicts: "4 \xB7 Preferences", state: "5 \xB7 Measurement", count: "1 \xB7 Catalogue" },
9038
+ run: { idle: "idle", measuring: "measuring\u2026", done: "done", failed: "failed", recording: "recording\u2026", recorded: "recording downloaded" },
9039
+ words: { none: "\u2014", hidden: "? (reveal)", prefers: "prefers", approved: "approved by the owner" },
9040
+ probe: "Sound source",
9041
+ wall: "Wall (occlusion)",
9042
+ scenarios: { pipeline: "File \u2192 decode \u2192 play (round-robin, tail)", criteria: "Criteria C1\u2013C9 on the calibration sound", loop: "File loop: seamless joins (crossfade)", panel: "Panel: categories, matrix, A/B and wall" }
9043
+ };
8618
9044
 
8619
9045
  // ../game-audio/dist/index.js
8620
9046
  var ATTACK = 2e-3;
@@ -8679,6 +9105,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
8679
9105
  ]
8680
9106
  };
8681
9107
  }
9108
+ var sceneMany = (count, make2) => Array.from({ length: count }, make2);
8682
9109
  function sceneRecipe(id, layers, line, options = {}) {
8683
9110
  return {
8684
9111
  id,
@@ -8691,6 +9118,569 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
8691
9118
  sources: [`cena:${line}`]
8692
9119
  };
8693
9120
  }
9121
+ var FOLEY_FALLOFF = {
9122
+ model: "inverse_square",
9123
+ k: 0.02,
9124
+ cutoffK: 0.04,
9125
+ minGain: 4e-3
9126
+ };
9127
+ var vary = (f, pct = 0.04) => [Math.round(f * (1 - pct)), Math.round(f * (1 + pct))];
9128
+ var foley = (id, layers, note) => ({
9129
+ id,
9130
+ bus: "world",
9131
+ pan: true,
9132
+ layers,
9133
+ falloff: FOLEY_FALLOFF,
9134
+ sources: [`sdk: ${note}`]
9135
+ });
9136
+ var click = (f, vol, delay = 0) => [
9137
+ sceneNoise({
9138
+ type: "bandpass",
9139
+ f: vary(f, 0.08),
9140
+ q: 4,
9141
+ d: [0.018, 0.03],
9142
+ vol: [vol * 0.85, vol * 1.1],
9143
+ delay
9144
+ }),
9145
+ sceneTone({
9146
+ f: vary(f * 0.8, 0.06),
9147
+ f2: Math.round(f * 0.62),
9148
+ d: [0.015, 0.025],
9149
+ vol: vol * 0.18,
9150
+ delay
9151
+ })
9152
+ ];
9153
+ var meet = (body, panel, vol, latch) => [
9154
+ sceneTone({
9155
+ f: vary(body),
9156
+ f2: Math.round(body * 0.5),
9157
+ d: [0.12, 0.16],
9158
+ vol: [vol * 0.9, vol * 1.1]
9159
+ }),
9160
+ sceneNoise({
9161
+ type: "bandpass",
9162
+ f: vary(panel, 0.06),
9163
+ q: 1.2,
9164
+ d: [0.08, 0.12],
9165
+ vol: [vol * 0.9, vol * 1.1],
9166
+ wet: 0.25
9167
+ }),
9168
+ ...click(latch, vol * 0.45, [0.012, 0.028])
9169
+ ];
9170
+ var LEAF_FOLEY = [
9171
+ // a wooden house door or wardrobe door: latch, a short creak, the leaf on the frame (the hard slam adds the frame rattling)
9172
+ foley("door_wood_open", click(2400, 0.4), "the latch of a wooden door giving"),
9173
+ foley(
9174
+ "door_creak",
9175
+ [
9176
+ sceneTone({ f: [190, 240], f2: 310, d: [0.4, 0.55], vol: [0.04, 0.06] }),
9177
+ sceneNoise({
9178
+ type: "bandpass",
9179
+ f: [480, 560],
9180
+ q: 6,
9181
+ a: 0.05,
9182
+ d: [0.35, 0.5],
9183
+ vol: [0.1, 0.14]
9184
+ })
9185
+ ],
9186
+ "a wooden hinge turning"
9187
+ ),
9188
+ foley("door_wood_close", meet(120, 600, 0.55, 2400), "a wooden leaf meeting its frame"),
9189
+ foley(
9190
+ "door_wood_slam",
9191
+ [
9192
+ ...meet(110, 560, 0.85, 2300),
9193
+ ...sceneMany(
9194
+ 3,
9195
+ () => sceneNoise({
9196
+ type: "bandpass",
9197
+ f: [900, 1500],
9198
+ q: 3,
9199
+ d: 0.03,
9200
+ vol: [0.08, 0.14],
9201
+ delay: [0.05, 0.18]
9202
+ })
9203
+ )
9204
+ ],
9205
+ "a wooden door slammed: the frame and the hinges rattle after the hit"
9206
+ ),
9207
+ // a metal door or gate: a hollow panel that rings a little
9208
+ foley("door_metal_open_close", [...meet(160, 900, 0.55, 2e3), sceneTone({ f: vary(1250), f2: 1150, d: [0.1, 0.16], vol: 0.06, wet: 0.3 })], "a metal door or gate meeting its frame"),
9209
+ foley(
9210
+ "door_creak_metal",
9211
+ [
9212
+ sceneTone({ f: [620, 760], f2: 900, d: [0.3, 0.4], vol: [0.03, 0.045] }),
9213
+ sceneNoise({
9214
+ type: "bandpass",
9215
+ f: [1300, 1500],
9216
+ q: 8,
9217
+ a: 0.04,
9218
+ d: [0.25, 0.35],
9219
+ vol: [0.07, 0.09]
9220
+ })
9221
+ ],
9222
+ "a metal hinge turning"
9223
+ ),
9224
+ // the handle of a locked door shaken: the latch knocking in its keeper, five to seven times in half a second
9225
+ foley(
9226
+ "door_locked_rattle",
9227
+ [
9228
+ ...sceneMany(
9229
+ 6,
9230
+ () => sceneNoise({
9231
+ type: "bandpass",
9232
+ f: [1600, 2600],
9233
+ q: 3,
9234
+ d: [0.025, 0.04],
9235
+ vol: [0.22, 0.34],
9236
+ delay: [0, 0.45]
9237
+ })
9238
+ ),
9239
+ ...sceneMany(
9240
+ 3,
9241
+ () => sceneTone({
9242
+ f: [170, 210],
9243
+ f2: 120,
9244
+ d: 0.05,
9245
+ vol: [0.12, 0.18],
9246
+ delay: [0.02, 0.4]
9247
+ })
9248
+ )
9249
+ ],
9250
+ "the handle of a locked door shaken: latch knocks and the leaf thumping in its frame"
9251
+ ),
9252
+ // a fridge: the rubber seal lets go with a soft suck, the bottles in the door clink; closing it is a soft thump and the seal pulling shut
9253
+ foley(
9254
+ "fridge_open",
9255
+ [
9256
+ sceneNoise({
9257
+ type: "lowpass",
9258
+ f: [320, 380],
9259
+ a: 0.03,
9260
+ d: [0.14, 0.2],
9261
+ vol: [0.32, 0.4]
9262
+ }),
9263
+ sceneNoise({
9264
+ type: "bandpass",
9265
+ f: [800, 950],
9266
+ f2: 1400,
9267
+ q: 2,
9268
+ a: 0.02,
9269
+ d: 0.12,
9270
+ vol: [0.08, 0.12]
9271
+ }),
9272
+ ...sceneMany(
9273
+ 2,
9274
+ () => sceneTone({
9275
+ f: [2600, 4200],
9276
+ d: [0.04, 0.08],
9277
+ vol: [0.015, 0.03],
9278
+ delay: [0.08, 0.22]
9279
+ })
9280
+ )
9281
+ ],
9282
+ "a fridge door: the seal letting go and the bottles in the door"
9283
+ ),
9284
+ foley(
9285
+ "fridge_close",
9286
+ [
9287
+ sceneTone({ f: vary(85), f2: 45, d: [0.1, 0.13], vol: [0.38, 0.46] }),
9288
+ sceneNoise({
9289
+ type: "lowpass",
9290
+ f: [520, 620],
9291
+ d: [0.08, 0.12],
9292
+ vol: [0.3, 0.36]
9293
+ }),
9294
+ sceneNoise({
9295
+ type: "lowpass",
9296
+ f: [260, 320],
9297
+ a: 0.02,
9298
+ d: 0.1,
9299
+ vol: [0.12, 0.18],
9300
+ delay: [0.04, 0.07]
9301
+ }),
9302
+ ...sceneMany(
9303
+ 2,
9304
+ () => sceneTone({
9305
+ f: [2600, 4200],
9306
+ d: [0.04, 0.07],
9307
+ vol: [0.015, 0.03],
9308
+ delay: [0.03, 0.12]
9309
+ })
9310
+ )
9311
+ ],
9312
+ "a fridge door shut: a soft thump, the seal pulling and the bottles"
9313
+ ),
9314
+ // a microwave: the spring catch of the door, plastic on plastic
9315
+ foley(
9316
+ "microwave_open",
9317
+ [
9318
+ ...click(1800, 0.34),
9319
+ sceneTone({
9320
+ f: [3e3, 3400],
9321
+ f2: 2800,
9322
+ d: 0.05,
9323
+ vol: 0.025,
9324
+ delay: [0.01, 0.02]
9325
+ })
9326
+ ],
9327
+ "the spring catch of a microwave door"
9328
+ ),
9329
+ foley(
9330
+ "microwave_close",
9331
+ [
9332
+ sceneNoise({
9333
+ type: "bandpass",
9334
+ f: [1200, 1450],
9335
+ q: 2.5,
9336
+ d: [0.04, 0.06],
9337
+ vol: [0.36, 0.44]
9338
+ }),
9339
+ sceneTone({ f: vary(180), f2: 120, d: 0.05, vol: [0.16, 0.22] }),
9340
+ ...click(2200, 0.2, [8e-3, 0.016])
9341
+ ],
9342
+ "a microwave door clacking shut"
9343
+ ),
9344
+ foley("microwave_beep", [sceneTone({ wave: "square", f: 2e3, d: 0.12, vol: 0.05 })], "the beep of a microwave"),
9345
+ // drawers and sliding leaves: the runners, then the stop
9346
+ foley(
9347
+ "drawer_open",
9348
+ [
9349
+ sceneNoise({
9350
+ type: "bandpass",
9351
+ f: [620, 780],
9352
+ q: 2,
9353
+ a: 0.04,
9354
+ d: [0.28, 0.36],
9355
+ vol: [0.18, 0.24]
9356
+ }),
9357
+ sceneNoise({ type: "bandpass", f: [2e3, 2400], q: 5, d: 0.28, vol: 0.04 }),
9358
+ ...click(1400, 0.16, [0.28, 0.34])
9359
+ ],
9360
+ "a drawer on its runners and its stop"
9361
+ ),
9362
+ foley(
9363
+ "drawer_close",
9364
+ [
9365
+ sceneNoise({
9366
+ type: "bandpass",
9367
+ f: [620, 780],
9368
+ q: 2,
9369
+ a: 0.03,
9370
+ d: [0.2, 0.28],
9371
+ vol: [0.18, 0.24]
9372
+ }),
9373
+ sceneTone({
9374
+ f: vary(150),
9375
+ f2: 90,
9376
+ d: 0.08,
9377
+ vol: [0.22, 0.3],
9378
+ delay: [0.2, 0.26]
9379
+ })
9380
+ ],
9381
+ "a drawer pushed home"
9382
+ )
9383
+ ];
9384
+ var ITEM_FOLEY = [
9385
+ // the hand closing on the item: a touch of skin and cloth, then the item's own small sound
9386
+ foley(
9387
+ "item_pickup_metal",
9388
+ [
9389
+ sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.18 }),
9390
+ sceneTone({
9391
+ f: [1900, 2600],
9392
+ f2: 1700,
9393
+ d: [0.05, 0.08],
9394
+ vol: [0.06, 0.09],
9395
+ delay: [0.01, 0.03]
9396
+ })
9397
+ ],
9398
+ "picking up a metal thing"
9399
+ ),
9400
+ foley(
9401
+ "item_pickup_plastic",
9402
+ [
9403
+ sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.18 }),
9404
+ sceneNoise({
9405
+ type: "bandpass",
9406
+ f: [1500, 1900],
9407
+ q: 3,
9408
+ d: 0.03,
9409
+ vol: [0.15, 0.21],
9410
+ delay: [0.01, 0.03]
9411
+ })
9412
+ ],
9413
+ "picking up a plastic thing"
9414
+ ),
9415
+ foley(
9416
+ "item_pickup_glass",
9417
+ [
9418
+ sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.15 }),
9419
+ sceneTone({
9420
+ f: [3200, 4200],
9421
+ d: [0.05, 0.08],
9422
+ vol: [0.038, 0.06],
9423
+ delay: [0.01, 0.03]
9424
+ })
9425
+ ],
9426
+ "picking up a glass thing"
9427
+ ),
9428
+ foley(
9429
+ "item_pickup_paper",
9430
+ [
9431
+ sceneNoise({
9432
+ type: "highpass",
9433
+ f: [2600, 3400],
9434
+ a: 0.01,
9435
+ d: [0.1, 0.14],
9436
+ vol: [0.12, 0.18]
9437
+ }),
9438
+ sceneNoise({ type: "bandpass", f: [800, 1e3], q: 1, d: 0.05, vol: 0.12 })
9439
+ ],
9440
+ "picking up paper or cardboard"
9441
+ ),
9442
+ foley(
9443
+ "item_pickup_fabric",
9444
+ [
9445
+ sceneNoise({
9446
+ type: "bandpass",
9447
+ f: [900, 1300],
9448
+ q: 0.8,
9449
+ a: 0.02,
9450
+ d: [0.12, 0.16],
9451
+ vol: [0.15, 0.21]
9452
+ })
9453
+ ],
9454
+ "picking up cloth"
9455
+ ),
9456
+ foley(
9457
+ "item_pickup_wood",
9458
+ [
9459
+ sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.18 }),
9460
+ sceneNoise({
9461
+ type: "bandpass",
9462
+ f: [900, 1100],
9463
+ q: 2,
9464
+ d: 0.04,
9465
+ vol: [0.15, 0.21],
9466
+ delay: [0.01, 0.03]
9467
+ })
9468
+ ],
9469
+ "picking up a wooden thing"
9470
+ ),
9471
+ foley(
9472
+ "item_pickup_food",
9473
+ [
9474
+ sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.18 }),
9475
+ sceneNoise({
9476
+ type: "lowpass",
9477
+ f: [500, 650],
9478
+ d: 0.05,
9479
+ vol: 0.12,
9480
+ delay: [0.01, 0.03]
9481
+ })
9482
+ ],
9483
+ "picking up food"
9484
+ ),
9485
+ foley(
9486
+ "item_throw",
9487
+ [
9488
+ sceneNoise({
9489
+ type: "bandpass",
9490
+ f: [450, 650],
9491
+ f2: 1400,
9492
+ q: 1.5,
9493
+ a: 0.05,
9494
+ d: 0.18,
9495
+ vol: [0.1, 0.14]
9496
+ })
9497
+ ],
9498
+ "the arm throwing something: air"
9499
+ ),
9500
+ // a can: the tab cracks, the gas hisses out; drinking is gulps; crushing it crumples the sheet
9501
+ foley(
9502
+ "can_open",
9503
+ [
9504
+ ...click(3200, 0.36),
9505
+ sceneNoise({
9506
+ type: "highpass",
9507
+ f: [3600, 4400],
9508
+ a: 5e-3,
9509
+ d: [0.22, 0.3],
9510
+ vol: [0.16, 0.22],
9511
+ delay: [0.012, 0.02]
9512
+ }),
9513
+ ...sceneMany(5, () => sceneTone({ f: [4e3, 7e3], d: 0.02, vol: 0.01, delay: [0.05, 0.4] }))
9514
+ ],
9515
+ "the tab of a can and the gas hissing out"
9516
+ ),
9517
+ foley(
9518
+ "can_crush",
9519
+ [
9520
+ sceneNoise({
9521
+ type: "bandpass",
9522
+ f: [1600, 2200],
9523
+ q: 1.2,
9524
+ d: [0.18, 0.25],
9525
+ vol: [0.3, 0.38]
9526
+ }),
9527
+ ...sceneMany(
9528
+ 6,
9529
+ () => sceneTone({
9530
+ f: [1200, 3400],
9531
+ f2: 900,
9532
+ d: 0.03,
9533
+ vol: [0.03, 0.06],
9534
+ delay: [0, 0.2]
9535
+ })
9536
+ )
9537
+ ],
9538
+ "a can crushed in the hand"
9539
+ ),
9540
+ foley(
9541
+ "can_puncture_spray",
9542
+ [
9543
+ sceneNoise({
9544
+ type: "highpass",
9545
+ f: [2400, 3e3],
9546
+ a: 5e-3,
9547
+ d: [0.5, 0.7],
9548
+ vol: [0.2, 0.26]
9549
+ }),
9550
+ sceneNoise({ type: "bandpass", f: [600, 800], q: 2, d: 0.4, vol: 0.06 })
9551
+ ],
9552
+ "a can holed: the jet hissing out"
9553
+ ),
9554
+ foley(
9555
+ "bottle_open",
9556
+ [
9557
+ ...sceneMany(
9558
+ 5,
9559
+ () => sceneNoise({
9560
+ type: "bandpass",
9561
+ f: [2200, 3e3],
9562
+ q: 4,
9563
+ d: 8e-3,
9564
+ vol: [0.1, 0.16],
9565
+ delay: [0, 0.18]
9566
+ })
9567
+ ),
9568
+ sceneNoise({
9569
+ type: "highpass",
9570
+ f: 3800,
9571
+ a: 5e-3,
9572
+ d: 0.12,
9573
+ vol: [0.06, 0.1],
9574
+ delay: [0.18, 0.22]
9575
+ })
9576
+ ],
9577
+ "the screw cap of a bottle turning off"
9578
+ ),
9579
+ foley(
9580
+ "drink_gulp",
9581
+ [
9582
+ sceneNoise({
9583
+ type: "lowpass",
9584
+ f: [280, 360],
9585
+ a: 0.02,
9586
+ d: [0.1, 0.14],
9587
+ vol: [0.24, 0.3]
9588
+ }),
9589
+ sceneTone({ f: [140, 170], f2: 85, d: [0.08, 0.11], vol: [0.12, 0.16] })
9590
+ ],
9591
+ "a gulp"
9592
+ ),
9593
+ foley(
9594
+ "eat_crunch",
9595
+ [
9596
+ ...sceneMany(
9597
+ 4,
9598
+ () => sceneNoise({
9599
+ type: "bandpass",
9600
+ f: [1800, 3200],
9601
+ q: 1.5,
9602
+ d: [0.02, 0.04],
9603
+ vol: [0.12, 0.2],
9604
+ delay: [0, 0.12]
9605
+ })
9606
+ )
9607
+ ],
9608
+ "a bite of something crunchy"
9609
+ ),
9610
+ foley(
9611
+ "eat_chew",
9612
+ [
9613
+ sceneNoise({
9614
+ type: "lowpass",
9615
+ f: [450, 600],
9616
+ a: 0.03,
9617
+ d: [0.1, 0.14],
9618
+ vol: [0.12, 0.16]
9619
+ }),
9620
+ sceneNoise({
9621
+ type: "bandpass",
9622
+ f: [1100, 1400],
9623
+ q: 2,
9624
+ d: 0.04,
9625
+ vol: 0.04,
9626
+ delay: [0.03, 0.06]
9627
+ })
9628
+ ],
9629
+ "chewing"
9630
+ ),
9631
+ foley(
9632
+ "bandage_wrap",
9633
+ [
9634
+ sceneNoise({
9635
+ type: "bandpass",
9636
+ f: [1400, 1800],
9637
+ f2: 2400,
9638
+ q: 1,
9639
+ a: 0.04,
9640
+ d: [0.3, 0.4],
9641
+ vol: [0.12, 0.16]
9642
+ })
9643
+ ],
9644
+ "a bandage unrolled round a limb"
9645
+ ),
9646
+ foley(
9647
+ "pills_shake",
9648
+ [
9649
+ ...sceneMany(
9650
+ 8,
9651
+ () => sceneTone({
9652
+ f: [2400, 3600],
9653
+ d: 0.015,
9654
+ vol: [0.03, 0.05],
9655
+ delay: [0, 0.25]
9656
+ })
9657
+ ),
9658
+ sceneNoise({ type: "bandpass", f: [1500, 1900], q: 2, d: 0.25, vol: 0.05 })
9659
+ ],
9660
+ "pills shaken in their bottle"
9661
+ ),
9662
+ foley(
9663
+ "medkit_use",
9664
+ [
9665
+ ...click(1700, 0.24),
9666
+ sceneNoise({
9667
+ type: "bandpass",
9668
+ f: [1e3, 1400],
9669
+ q: 1,
9670
+ a: 0.03,
9671
+ d: [0.25, 0.32],
9672
+ vol: [0.08, 0.12],
9673
+ delay: [0.05, 0.08]
9674
+ })
9675
+ ],
9676
+ "a first aid kit opened and rummaged"
9677
+ ),
9678
+ foley("flashlight_click", click(2600, 0.3), "the switch of a flashlight")
9679
+ ];
9680
+ var FOLEY_BANK = {
9681
+ id: "foley",
9682
+ sounds: [...LEAF_FOLEY, ...ITEM_FOLEY]
9683
+ };
8694
9684
  var TAKES = [
8695
9685
  { f: 1, t: 1, v: 1 },
8696
9686
  { f: 1.08, t: 0.9, v: 0.92 },
@@ -9203,74 +10193,22 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
9203
10193
  var hex = (value) => parseInt(value, 16);
9204
10194
  var personSpecOf = (profession) => {
9205
10195
  const { look } = profession;
9206
- const spec = {
10196
+ const ex = profession.accessories.map((accessory) => accessory.color ? [accessory.id, hex(accessory.color)] : [accessory.id]);
10197
+ return {
9207
10198
  skin: hex(look.skin),
9208
10199
  hair: { s: look.hair.style, c: hex(look.hair.color) },
9209
10200
  top: { c: hex(look.top.color), sl: look.top.sleeve, ...look.top.plaid ? { plaid: hex(look.top.plaid) } : {} },
9210
10201
  pants: { c: hex(look.pants.color) },
9211
10202
  shoes: hex(look.shoes),
9212
- ex: profession.accessories.map((accessory) => accessory.color ? [accessory.id, hex(accessory.color)] : [accessory.id])
10203
+ ex,
10204
+ ...profession.female ? { fem: 1 } : {},
10205
+ ...look.hat ? { hat: { k: look.hat.kind, c: hex(look.hat.color) } } : {},
10206
+ ...look.face && look.face.length > 0 ? { face: [...look.face] } : {},
10207
+ ...profession.hand ? { hand: profession.hand } : {},
10208
+ ...profession.leftHand ? { lhand: profession.leftHand } : {}
9213
10209
  };
9214
- if (profession.female) spec.fem = 1;
9215
- if (look.hat) spec.hat = { k: look.hat.kind, c: hex(look.hat.color) };
9216
- if (look.face && look.face.length > 0) spec.face = [...look.face];
9217
- if (profession.hand) spec.hand = profession.hand;
9218
- if (profession.leftHand) spec.lhand = profession.leftHand;
9219
- return spec;
9220
10210
  };
9221
10211
 
9222
- // src/test-area/knock.ts
9223
- var KNOCK_DOWN_SPEED = 2.5;
9224
- var KNOCKED_DOWN_ANGLE = 1.35;
9225
- var LIE_SECONDS = 1.6;
9226
- var STAND_UP_PER_SPEED = 0.25;
9227
- var FALL_SECONDS = 0.25;
9228
- var RISE_SECONDS = 0.6;
9229
- var GROUND_FRICTION = 7;
9230
- var GRAVITY3 = 9.81;
9231
- var CHEST = 1.1;
9232
- var bodyMass = (height, build = 1) => 70 * (height / 1.75) ** 2 * build;
9233
- function knockOf(blast2, feet, mass, options) {
9234
- const hit = blastShove(blast2, { position: [feet[0], feet[1] + CHEST, feet[2]], mass }, options);
9235
- if (!hit) return void 0;
9236
- const [dx, dy, dz] = hit.direction;
9237
- 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 };
9238
- }
9239
- function stepKnock(knock2, position, dt, groundAt, alive) {
9240
- const v = knock2.velocity;
9241
- position.x += v[0] * dt;
9242
- position.z += v[2] * dt;
9243
- const ground = groundAt(position.x, position.z);
9244
- if (knock2.airborne || position.y > ground + 1e-4) {
9245
- v[1] -= GRAVITY3 * dt;
9246
- position.y += v[1] * dt;
9247
- if (position.y <= ground) {
9248
- position.y = ground;
9249
- v[1] = 0;
9250
- knock2.airborne = false;
9251
- }
9252
- } else position.y = ground;
9253
- const horizontal = Math.hypot(v[0], v[2]);
9254
- if (!knock2.airborne && horizontal > 0) {
9255
- const slowed = Math.max(0, horizontal - GROUND_FRICTION * dt);
9256
- v[0] *= slowed / horizontal;
9257
- v[2] *= slowed / horizontal;
9258
- }
9259
- const moving = horizontal > 0.05 || knock2.airborne;
9260
- if (knock2.down) {
9261
- if (moving) knock2.lying = Math.min(1, knock2.lying + dt / FALL_SECONDS);
9262
- else {
9263
- knock2.lying = 1;
9264
- if (alive) {
9265
- knock2.lieLeft = knock2.lieLeft > 0 ? knock2.lieLeft : LIE_SECONDS + Math.hypot(v[0], v[2]) * STAND_UP_PER_SPEED;
9266
- knock2.lieLeft -= dt;
9267
- if (knock2.lieLeft <= 0) knock2.down = false;
9268
- }
9269
- }
9270
- } else if (knock2.lying > 0) knock2.lying = Math.max(0, knock2.lying - dt / RISE_SECONDS);
9271
- return !moving && !knock2.down && knock2.lying === 0;
9272
- }
9273
-
9274
10212
  // src/test-area/scenarios.ts
9275
10213
  var LIMB_SEGMENTS = ["upperArmL", "forearmL", "handL", "upperArmR", "forearmR", "handR", "thighL", "shinL", "footL", "thighR", "shinR", "footR"];
9276
10214
  var BENCHMARK_BODIES = 1e3;
@@ -9526,7 +10464,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
9526
10464
  let time = 0;
9527
10465
  let lastCrossed = 0;
9528
10466
  let lastEnergy = 1;
9529
- const entries = /* @__PURE__ */ new Map();
10467
+ const entries2 = /* @__PURE__ */ new Map();
9530
10468
  const builtOf = /* @__PURE__ */ new WeakMap();
9531
10469
  const overlays = /* @__PURE__ */ new Map();
9532
10470
  const gaits = Object.fromEntries(undeadTypes.map((card) => [card.name["pt-BR"] ?? card.id, card.gait]));
@@ -9624,7 +10562,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
9624
10562
  const blood = age !== void 0 ? options.bloodOf?.(age) : void 0;
9625
10563
  if (entry.body && blood) entry.body.blood = blood;
9626
10564
  if (three) entry.batcher = createStaticBatcher(three, object2, { followMeshes: true, budgetMs: BATCH_BUDGET_MS });
9627
- entries.set(id, entry);
10565
+ entries2.set(id, entry);
9628
10566
  selected ?? (selected = entry);
9629
10567
  trackEntry(entry);
9630
10568
  return entry.character;
@@ -9672,7 +10610,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
9672
10610
  if (!host?.bench) return;
9673
10611
  for (const layer of ["capsules", "joints", "speed"]) {
9674
10612
  if (!host.bench.layer(layer)) continue;
9675
- for (const entry of entries.values()) {
10613
+ for (const entry of entries2.values()) {
9676
10614
  const overlay = overlayFor(layer, entry);
9677
10615
  if (!overlay) continue;
9678
10616
  entry.root.add(overlay);
@@ -9680,7 +10618,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
9680
10618
  }
9681
10619
  }
9682
10620
  const eyesOnly = host.bench.layer("eyes_only");
9683
- for (const entry of entries.values()) entry.eyes?.isolate(eyesOnly);
10621
+ for (const entry of entries2.values()) entry.eyes?.isolate(eyesOnly);
9684
10622
  };
9685
10623
  const animate = (entry, dt) => {
9686
10624
  const { root, character } = entry;
@@ -9714,7 +10652,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
9714
10652
  wounds?.applyLimp(entry.body);
9715
10653
  }
9716
10654
  };
9717
- const selectedOrFirst = () => selected ?? entries.values().next().value ?? null;
10655
+ const selectedOrFirst = () => selected ?? entries2.values().next().value ?? null;
9718
10656
  const fireOn = (entry) => {
9719
10657
  const preset2 = hitPresetOf(settings.hit);
9720
10658
  const p2 = entry.root.position;
@@ -9754,7 +10692,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
9754
10692
  }
9755
10693
  } else if (change.id === "fire_preset" && target) fireOn(target);
9756
10694
  else if ((change.id === "voice" || change.id === "special_call") && sound) {
9757
- const speaker = target?.kind === "zombie" ? target : [...entries.values()].find((entry) => entry.kind === "zombie");
10695
+ const speaker = target?.kind === "zombie" ? target : [...entries2.values()].find((entry) => entry.kind === "zombie");
9758
10696
  if (speaker) {
9759
10697
  const at = speaker.root.getWorldPosition(new host.THREE.Vector3());
9760
10698
  const hurried = settings.moment === "alert" || settings.moment === "chase" || settings.moment === "sprint";
@@ -9838,7 +10776,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
9838
10776
  ground: { surface: "concrete_slab" },
9839
10777
  group: text.group,
9840
10778
  get entries() {
9841
- return entries;
10779
+ return entries2;
9842
10780
  },
9843
10781
  get crowd() {
9844
10782
  return crowd;
@@ -9876,7 +10814,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
9876
10814
  ],
9877
10815
  layers: () => ["capsules", "joints", "bleed", "eyes_only", "speed"].map((id) => ({ id, name: text.layers[id], default: false })),
9878
10816
  metrics: () => [
9879
- { id: "bodies", name: text.metrics.bodies, read: () => entries.size },
10817
+ { id: "bodies", name: text.metrics.bodies, read: () => entries2.size },
9880
10818
  { id: "instances", name: text.metrics.instances, read: () => crowd?.count ?? 0 },
9881
10819
  { id: "triangles", name: text.metrics.triangles, max: 25e4, read: () => Math.round(crowd?.triangles ?? 0) },
9882
10820
  { id: "draw_calls", name: text.metrics.draw_calls, read: () => crowd?.drawCalls ?? 0 },
@@ -9899,7 +10837,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
9899
10837
  const bridge = options.fluids ? createFluidsBridge({ sink: options.fluids, ...options.film ? { film: options.film } : {} }) : void 0;
9900
10838
  sound = lent.audio && options.sound !== false ? createCharacterSound(lent.audio, options.sound ?? {}) : null;
9901
10839
  wounds = createWounds(lent.THREE, { random, scene: scene2, groundAt: (x, z) => lent.groundAt(x, z), ...bridge ? { bridge } : {}, ...sound ? { sound } : {} });
9902
- for (const entry of entries.values()) trackEntry(entry);
10840
+ for (const entry of entries2.values()) trackEntry(entry);
9903
10841
  const stopChange = lent.bench?.onChange(onChange);
9904
10842
  const stopReset = lent.onReset?.(() => {
9905
10843
  stream = createRng(options.seed ?? 1);
@@ -9911,21 +10849,22 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
9911
10849
  });
9912
10850
  const stopEvents = lent.on((event) => {
9913
10851
  if (event.type !== "explosion") return;
9914
- for (const entry of entries.values()) {
10852
+ for (const entry of entries2.values()) {
9915
10853
  if (!entry.root.parent) continue;
9916
10854
  const p2 = entry.root.position;
9917
- const knock2 = knockOf(event, [p2.x, p2.y, p2.z], bodyMass(entry.character.spec.height, entry.character.spec.build), lent.blastShove);
10855
+ const reach = lent.blastReach?.(event.point, [p2.x, p2.y + KNOCK_CHEST, p2.z], [event.source, entry.id]) ?? 1;
10856
+ const knock2 = knockOf({ ...event, reach }, [p2.x, p2.y, p2.z], bodyMass(entry.character.spec.height, entry.character.spec.build), lent.blastShove);
9918
10857
  if (knock2) entry.knock = entry.knock ? { ...knock2, lying: entry.knock.lying } : knock2;
9919
10858
  }
9920
10859
  });
9921
10860
  const stopFrame = lent.onFrame((dt) => {
9922
10861
  time += dt;
9923
- for (const [id, entry] of entries) {
10862
+ for (const [id, entry] of entries2) {
9924
10863
  if (!entry.root.parent) {
9925
10864
  entry.batcher?.dispose();
9926
10865
  if (entry.body) wounds?.untrack(entry.body);
9927
10866
  if (selected === entry) selected = null;
9928
- entries.delete(id);
10867
+ entries2.delete(id);
9929
10868
  continue;
9930
10869
  }
9931
10870
  animate(entry, dt);
@@ -10460,7 +11399,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
10460
11399
  for (const key of ["skin", "hair"]) if (typeof spec[key] === "string") spec[key] = hexOf(spec[key]);
10461
11400
  const best = createBestBuilder(THREE, { types: [{ name: String(spec.type), eye: 0 }], random: createRng(Number(spec.seed ?? 1)) });
10462
11401
  const body = best.build(spec);
10463
- best.topM().color.setHex(options.shirtColor ?? hexOf(player_avatar_default.shirtColor));
11402
+ best.topM()?.color.setHex(options.shirtColor ?? hexOf(player_avatar_default.shirtColor));
10464
11403
  const rig = body.userData.rig;
10465
11404
  const profile = { f: 1.1, a: 0.28, k: 0.35, arm: WALK_ARM, bob: WALK_BOB };
10466
11405
  const animator = createRigAnimator({ gaits: { [rig.type]: profile } });