@adatechnology/game-characters-three 0.9.4 → 0.9.5

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.
@@ -1350,8 +1350,8 @@ var GameCharactersThree = (() => {
1350
1350
  const face = faces[i];
1351
1351
  f3(face[2] + offset, face[1] + offset, face[0] + offset);
1352
1352
  }
1353
- const layer = steps + bevelSegments * 2;
1354
- offset = vlen * layer;
1353
+ const layer2 = steps + bevelSegments * 2;
1354
+ offset = vlen * layer2;
1355
1355
  for (let i = 0; i < flen; i++) {
1356
1356
  const face = faces[i];
1357
1357
  f3(face[0] + offset, face[1] + offset, face[2] + offset);
@@ -1682,6 +1682,13 @@ var GameCharactersThree = (() => {
1682
1682
  } else if (knock2.lying > 0) knock2.lying = Math.max(0, knock2.lying - dt / RISE_SECONDS);
1683
1683
  return !moving && !knock2.down && knock2.lying === 0;
1684
1684
  }
1685
+ var LAUNCHED = "launched";
1686
+ function takeLaunch(root) {
1687
+ const velocity = root.userData[LAUNCHED];
1688
+ if (!velocity) return void 0;
1689
+ delete root.userData[LAUNCHED];
1690
+ return { velocity: [velocity[0], velocity[1], velocity[2]], airborne: true, lying: 0, lieLeft: 0, down: true };
1691
+ }
1685
1692
  var DEFAULT_COST_ALLOCATION_BYTES = 1024 * 1024;
1686
1693
  var MISSING_BITS = {
1687
1694
  head: 1,
@@ -3016,7 +3023,7 @@ var GameCharactersThree = (() => {
3016
3023
  var PHYSICAL_RULES = physical_default;
3017
3024
  var PHYSICAL_PENETRATION = {
3018
3025
  id: "physical",
3019
- stops: (layer, projectile) => projectile.force <= (layer.ballistic?.resistance ?? 0),
3026
+ stops: (layer2, projectile) => projectile.force <= (layer2.ballistic?.resistance ?? 0),
3020
3027
  piercesSkull: (projectile, headResistance) => projectile.force > headResistance
3021
3028
  };
3022
3029
  var TEAM_GAME_PENETRATION = {
@@ -3220,23 +3227,23 @@ var GameCharactersThree = (() => {
3220
3227
  };
3221
3228
  var LAYERED_PROTECTION_CAP = 0.9;
3222
3229
  var layeredProtection = ({ layers, attack, conditions }) => {
3223
- const through = layers.reduce((left, layer) => left * (1 - (layer[attack] ?? 0) * (conditions?.[layer.id] ?? 1)), 1);
3230
+ const through = layers.reduce((left, layer2) => left * (1 - (layer2[attack] ?? 0) * (conditions?.[layer2.id] ?? 1)), 1);
3224
3231
  return Math.min(LAYERED_PROTECTION_CAP, 1 - through);
3225
3232
  };
3226
- var layersOn = (worn, slots, consumed) => worn.filter((layer) => !consumed.has(layer.id) && layer.slots.some((slot) => slots.includes(slot)));
3233
+ var layersOn = (worn, slots, consumed) => worn.filter((layer2) => !consumed.has(layer2.id) && layer2.slots.some((slot) => slots.includes(slot)));
3227
3234
  var protect = ({ layers, projectile, model }) => {
3228
3235
  let ballistic = 1;
3229
3236
  let resistance = 0;
3230
- for (const layer of layers) {
3231
- const armour = layer.ballistic;
3237
+ for (const layer2 of layers) {
3238
+ const armour = layer2.ballistic;
3232
3239
  if (!armour || !projectile) continue;
3233
- const stops = model.stops(layer, projectile);
3234
- if (stops && armour.consumable) return { absorbedBy: layer.id, ballistic: 0, resistance: armour.resistance, limbs: 1, fire: 1 };
3240
+ const stops = model.stops(layer2, projectile);
3241
+ if (stops && armour.consumable) return { absorbedBy: layer2.id, ballistic: 0, resistance: armour.resistance, limbs: 1, fire: 1 };
3235
3242
  ballistic *= stops ? armour.blunt : armour.pass ?? armour.blunt;
3236
3243
  resistance += armour.resistance;
3237
3244
  }
3238
- const limbs = layers.reduce((factor, layer) => factor * (layer.limbs ?? 1), 1);
3239
- const fire = layers.reduce((factor, layer) => factor * (layer.fire ?? 1), 1);
3245
+ const limbs = layers.reduce((factor, layer2) => factor * (layer2.limbs ?? 1), 1);
3246
+ const fire = layers.reduce((factor, layer2) => factor * (layer2.fire ?? 1), 1);
3240
3247
  return { ballistic, resistance, limbs, fire };
3241
3248
  };
3242
3249
  var radiusOf = (part) => part.shape.kind === "box" ? Math.min(...part.shape.size) / 2 : part.shape.radius;
@@ -3490,7 +3497,7 @@ var GameCharactersThree = (() => {
3490
3497
  };
3491
3498
  var createDamageCharacter = (core, setup) => {
3492
3499
  const view = characterView(core);
3493
- const worn = core.spec.protection.map((id) => setup.protection.get(id)).filter((layer) => layer !== void 0);
3500
+ const worn = core.spec.protection.map((id) => setup.protection.get(id)).filter((layer2) => layer2 !== void 0);
3494
3501
  let bleeders = [];
3495
3502
  let hitCounter = 0;
3496
3503
  let clock = 0;
@@ -3542,7 +3549,7 @@ var GameCharactersThree = (() => {
3542
3549
  resistanceOf(part) {
3543
3550
  const id = resolveSegment(core.body, core.describe(), part, [0, 0, 0]);
3544
3551
  const layers = layersOn(worn, segmentNode(id).slots, core.body.consumed);
3545
- const protection = layers.reduce((sum, layer) => sum + (layer.ballistic?.resistance ?? 0), 0);
3552
+ const protection = layers.reduce((sum, layer2) => sum + (layer2.ballistic?.resistance ?? 0), 0);
3546
3553
  return segmentResistance({ kind: segmentNode(id).kind, bodyCount: core.spec.bodyCount, protection });
3547
3554
  },
3548
3555
  protectionAgainst: (attack, part) => layeredProtection({ layers: layersOn(worn, segmentNode(part).slots, core.body.consumed), attack }),
@@ -4869,7 +4876,7 @@ var GameCharactersThree = (() => {
4869
4876
  }
4870
4877
  }
4871
4878
  });
4872
- const layer = (bytes) => {
4879
+ const layer2 = (bytes) => {
4873
4880
  const texture2 = new three.DataTexture(bytes, stride, rows * cellHeight, three.RGBAFormat, three.UnsignedByteType);
4874
4881
  texture2.minFilter = three.NearestFilter;
4875
4882
  texture2.magFilter = three.NearestFilter;
@@ -4877,8 +4884,8 @@ var GameCharactersThree = (() => {
4877
4884
  texture2.needsUpdate = true;
4878
4885
  return texture2;
4879
4886
  };
4880
- const texture = layer(pixels);
4881
- const colorTexture = layer(colorPixels);
4887
+ const texture = layer2(pixels);
4888
+ const colorTexture = layer2(colorPixels);
4882
4889
  return { texture, colorTexture, silhouettes: bodies.length, cellWidth, cellHeight, columns, rows, boxes, pixels, colorPixels, dispose: () => (texture.dispose(), colorTexture.dispose()) };
4883
4890
  };
4884
4891
 
@@ -8568,7 +8575,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
8568
8575
  };
8569
8576
  };
8570
8577
 
8571
- // ../game-audio/dist/chunk-BXUGSOPY.js
8578
+ // ../game-audio/dist/chunk-C2K7XN2K.js
8572
8579
  var DISTANCE_CURVES = {
8573
8580
  /** The game's `sfx`: `vol / (1 + d² × 0.004)`, cutoff `/ (1 + d × 0.01)`, silent below 0.01 (jogo L62091–62092, L62101). */
8574
8581
  game_sfx: { model: "inverse_square", k: 4e-3, cutoffK: 0.01, minGain: 0.01 },
@@ -9003,6 +9010,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
9003
9010
  burst: 20,
9004
9011
  burstSpacing: 0.06
9005
9012
  };
9013
+ var CATALOG = new Map([...SFX_CATALOG, ...SFX_IMPACTS].map((entry) => [entry.id, entry]));
9006
9014
  var PT = {
9007
9015
  group: "Som",
9008
9016
  name: "Painel de som (arquivos e C1\u2013C10)",
@@ -9077,9 +9085,9 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
9077
9085
  strengths: { light: "leve", medium: "m\xE9dio", heavy: "forte" },
9078
9086
  states: { file: "A", synth: "S", missing: "F" },
9079
9087
  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" },
9080
- metrics: { source: "1 \xB7 Fonte do que tocou", 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" },
9088
+ metrics: { source: "1 \xB7 Fonte do que tocou", 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", unlicensed: "1 \xB7 Arquivo sem licen\xE7a" },
9081
9089
  run: { idle: "parada", measuring: "medindo\u2026", done: "pronta", failed: "falhou", recording: "gravando\u2026", recorded: "grava\xE7\xE3o baixada" },
9082
- words: { none: "\u2014", hidden: "? (revele)", prefers: "prefere", approved: "aprovado pelo dono" },
9090
+ words: { none: "\u2014", hidden: "? (revele)", prefers: "prefere", approved: "aprovado pelo dono", local_file: "arquivo do pacote local", sdk_file: "grava\xE7\xE3o do SDK", synth: "s\xEDntese do SDK" },
9083
9091
  sources: { sdk: "SDK", user: "seu som", synth: "sintetizado" },
9084
9092
  probe: "Fonte do som",
9085
9093
  wall: "Parede (oclus\xE3o)",
@@ -9150,9 +9158,9 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
9150
9158
  environments: { indoor: "indoor", outdoor: "outdoor" },
9151
9159
  strengths: { light: "light", medium: "medium", heavy: "heavy" },
9152
9160
  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" },
9153
- metrics: { source: "1 \xB7 Source of what played", 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" },
9161
+ metrics: { source: "1 \xB7 Source of what played", 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", unlicensed: "1 \xB7 File without licence" },
9154
9162
  run: { idle: "idle", measuring: "measuring\u2026", done: "done", failed: "failed", recording: "recording\u2026", recorded: "recording downloaded" },
9155
- words: { none: "\u2014", hidden: "? (reveal)", prefers: "prefers", approved: "approved by the owner" },
9163
+ words: { none: "\u2014", hidden: "? (reveal)", prefers: "prefers", approved: "approved by the owner", local_file: "local pack file", sdk_file: "SDK recording", synth: "SDK synthesis" },
9156
9164
  sources: { sdk: "SDK", user: "your sound", synth: "synthesized" },
9157
9165
  probe: "Sound source",
9158
9166
  wall: "Wall (occlusion)",
@@ -9235,6 +9243,66 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
9235
9243
  sources: [`cena:${line}`]
9236
9244
  };
9237
9245
  }
9246
+ var hz = (midi) => 440 * 2 ** ((midi - 69) / 12);
9247
+ var layer = (note, beat, wave, level) => {
9248
+ const [at, midi, beats] = note;
9249
+ const length = beats * beat;
9250
+ return {
9251
+ at: at * beat,
9252
+ duration: length,
9253
+ source: { kind: "osc", wave, frequency: { set: hz(midi) } },
9254
+ envelope: [[0, 1e-4, "set"], [0.01, level, "linear"], [Math.max(0.02, length * 0.9), level * 0.35, "linear"], [length, 1e-4, "exp", "fixed"]]
9255
+ };
9256
+ };
9257
+ function radioTrack(spec) {
9258
+ const beat = 60 / spec.bpm;
9259
+ const recipes = Array.from({ length: spec.bars }, (_, bar) => {
9260
+ const inBar = (notes) => notes.filter((n) => n[0] >= bar * 4 && n[0] < bar * 4 + 4).map((n) => [n[0] - bar * 4, n[1], n[2]]);
9261
+ const layers = [
9262
+ ...inBar(spec.bass).map((n) => layer(n, beat, "triangle", 0.16)),
9263
+ ...inBar(spec.chords).map((n) => layer(n, beat, "sine", 0.05)),
9264
+ ...inBar(spec.melody).map((n) => layer(n, beat, spec.wave, 0.07))
9265
+ ];
9266
+ return { id: `${spec.id}_${bar}`, bus: "world", duration: 4 * beat, layers, falloff: { model: "none" } };
9267
+ });
9268
+ return { song: { id: spec.id, barSeconds: 4 * beat, bars: recipes.map((r) => r.id) }, recipes };
9269
+ }
9270
+ var chord = (bar, root, minor = false) => [[bar * 4, root, 4], [bar * 4, root + (minor ? 3 : 4), 4], [bar * 4, root + 7, 4]];
9271
+ var bassLine = (roots, pattern) => roots.flatMap((root, bar) => pattern.map((b) => [bar * 4 + b, root - 12, 0.9]));
9272
+ var TRACKS = [
9273
+ // a bright pop loop: I–V–vi–IV in C
9274
+ radioTrack({
9275
+ id: "radio_track_pop",
9276
+ bpm: 112,
9277
+ bars: 4,
9278
+ wave: "square",
9279
+ bass: bassLine([48, 55, 57, 53], [0, 1.5, 2, 3]),
9280
+ chords: [...chord(0, 60), ...chord(1, 55), ...chord(2, 57, true), ...chord(3, 53)],
9281
+ melody: [[0, 76, 1], [1, 74, 0.5], [1.5, 72, 1.5], [4, 74, 1], [5, 76, 1], [6, 79, 2], [8, 76, 1], [9, 74, 1], [10, 72, 2], [12, 72, 1], [13, 74, 1], [14, 72, 2]]
9282
+ }),
9283
+ // a syncopated loop in A minor, the bass on the off-beats
9284
+ radioTrack({
9285
+ id: "radio_track_groove",
9286
+ bpm: 100,
9287
+ bars: 4,
9288
+ wave: "triangle",
9289
+ bass: bassLine([57, 62, 64, 57], [0, 0.75, 1.5, 2.5, 3.25]),
9290
+ chords: [...chord(0, 57, true), ...chord(1, 62, true), ...chord(2, 64), ...chord(3, 57, true)],
9291
+ melody: [[0.5, 72, 0.5], [1.25, 76, 0.75], [2.5, 74, 1], [4.5, 77, 0.5], [5.25, 74, 0.75], [6.5, 72, 1.5], [8.5, 71, 0.5], [9.25, 74, 0.75], [10.5, 76, 1.5], [12.5, 72, 0.5], [13.25, 69, 2]]
9292
+ }),
9293
+ // a slow blues-like loop in F with a swung melody
9294
+ radioTrack({
9295
+ id: "radio_track_slow",
9296
+ bpm: 76,
9297
+ bars: 4,
9298
+ wave: "sine",
9299
+ bass: bassLine([53, 58, 53, 60], [0, 2]),
9300
+ chords: [...chord(0, 65), ...chord(1, 58), ...chord(2, 65), ...chord(3, 60)],
9301
+ melody: [[0, 72, 1.5], [1.67, 75, 0.33], [2, 77, 2], [4, 74, 1], [5, 72, 1], [6, 70, 2], [8, 72, 1.5], [9.67, 69, 0.33], [10, 65, 2], [12, 67, 1], [13, 70, 1], [14, 72, 2]]
9302
+ })
9303
+ ];
9304
+ var RADIO_TRACKS = TRACKS.map((t) => t.song);
9305
+ var RADIO_BANK = { id: "vehicle_radio", sounds: TRACKS.flatMap((t) => t.recipes), loops: [] };
9238
9306
  var FOLEY_FALLOFF = {
9239
9307
  model: "inverse_square",
9240
9308
  k: 0.02,
@@ -9841,11 +9909,11 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
9841
9909
  ...s.splash ? [sceneNoise({ type: "bandpass", f: s.splash.f * take.f, f2: s.splash.f2 * take.f, q: 1.4, d: s.splash.d * take.t * weight ** 0.4, vol: s.splash.vol * gait.vol * take.v * weight ** 0.5 })] : []
9842
9910
  ];
9843
9911
  }
9844
- var quieter = (level, layers) => layers.map((layer) => {
9845
- const gain = layer.gain ?? 1;
9846
- if (typeof gain === "number") return { ...layer, gain: gain * level };
9847
- if (Array.isArray(gain)) return { ...layer, gain: [gain[0] * level, gain[1] * level] };
9848
- return layer;
9912
+ var quieter = (level, layers) => layers.map((layer2) => {
9913
+ const gain = layer2.gain ?? 1;
9914
+ if (typeof gain === "number") return { ...layer2, gain: gain * level };
9915
+ if (Array.isArray(gain)) return { ...layer2, gain: [gain[0] * level, gain[1] * level] };
9916
+ return layer2;
9849
9917
  });
9850
9918
  var recipe = (id, layers, falloff, bus = "world") => ({ id, bus, pan: true, layers, falloff, sources: ["sdk"] });
9851
9919
  var takeId = (id, index) => `${id}_${String(index + 1).padStart(2, "0")}`;
@@ -9861,7 +9929,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
9861
9929
  (take) => quieter(LANDING_LEVEL, [
9862
9930
  // both feet, a hair apart, then the knees taking the weight (a low body thump) and the clothes settling
9863
9931
  ...footLayers(surface, take, GAITS.run, LANDINGS[landing2].weight),
9864
- ...footLayers(surface, { ...take, v: take.v * 0.6 }, GAITS.run, LANDINGS[landing2].weight * 0.6).map((layer) => ({ ...layer, at: (typeof layer.at === "number" ? layer.at : 0) + 0.018 * take.t })),
9932
+ ...footLayers(surface, { ...take, v: take.v * 0.6 }, GAITS.run, LANDINGS[landing2].weight * 0.6).map((layer2) => ({ ...layer2, at: (typeof layer2.at === "number" ? layer2.at : 0) + 0.018 * take.t })),
9865
9933
  sceneTone({ f: 60 * take.f, f2: 38, d: 0.14 * LANDINGS[landing2].weight * take.t, vol: 0.22 * LANDINGS[landing2].weight ** 0.7 * take.v, delay: 0.02 }),
9866
9934
  sceneNoise({ type: "bandpass", f: [1800, 2600], q: 0.8, d: 0.18, vol: LANDINGS[landing2].cloth * take.v, delay: 0.04 })
9867
9935
  ]),
@@ -9907,7 +9975,7 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
9907
9975
  fall_damage: (take) => [
9908
9976
  ...BODY.body_fall(take),
9909
9977
  sceneNoise({ type: "highpass", f: 2800, d: 0.02, vol: 0.35 * take.v, delay: 0.01 }),
9910
- ...voice({ f0: 170, f1: 110, d: 0.32, fA: 650, fB: 1150, noise: 0.25, vol: 0.32 })(take).map((layer) => ({ ...layer, at: 0.08 }))
9978
+ ...voice({ f0: 170, f1: 110, d: 0.32, fA: 650, fB: 1150, noise: 0.25, vol: 0.32 })(take).map((layer2) => ({ ...layer2, at: 0.08 }))
9911
9979
  ],
9912
9980
  player_hurt: voice({ f0: 150, f1: 105, d: 0.26, fA: 620, fB: 1100, noise: 0.3, vol: 0.35 }),
9913
9981
  player_breath_run: (take) => [
@@ -10695,11 +10763,11 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
10695
10763
  for (const object2 of overlays.values()) object2.parent?.remove(object2);
10696
10764
  overlays.clear();
10697
10765
  };
10698
- const overlayFor = (layer, entry) => {
10766
+ const overlayFor = (layer2, entry) => {
10699
10767
  if (!three) return null;
10700
10768
  const group = new three.Group();
10701
- const material = new three.MeshBasicMaterial({ color: layer === "capsules" ? 4513279 : layer === "joints" ? 16772676 : 16729190, wireframe: layer === "capsules", depthTest: false, transparent: true, opacity: 0.8 });
10702
- if (layer === "capsules") {
10769
+ const material = new three.MeshBasicMaterial({ color: layer2 === "capsules" ? 4513279 : layer2 === "joints" ? 16772676 : 16729190, wireframe: layer2 === "capsules", depthTest: false, transparent: true, opacity: 0.8 });
10770
+ if (layer2 === "capsules") {
10703
10771
  for (const part of entry.character.describe().parts) {
10704
10772
  const shape = part.shape;
10705
10773
  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);
@@ -10708,13 +10776,13 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
10708
10776
  if (part.rotation) mesh2.rotation.set(...part.rotation);
10709
10777
  group.add(mesh2);
10710
10778
  }
10711
- } else if (layer === "joints") {
10779
+ } else if (layer2 === "joints") {
10712
10780
  for (const joint of Object.values(entry.character.rig.joints)) {
10713
10781
  const mesh2 = new three.Mesh(new three.SphereGeometry(0.025, 6, 4), material);
10714
10782
  mesh2.position.set(...joint);
10715
10783
  group.add(mesh2);
10716
10784
  }
10717
- } else if (layer === "speed") {
10785
+ } else if (layer2 === "speed") {
10718
10786
  const length = Math.max(0.1, speedOf(entry));
10719
10787
  const arrow = new three.ArrowHelper(new three.Vector3(0, 0, 1), new three.Vector3(0, 2.1, 0), length, 6750054);
10720
10788
  group.add(arrow);
@@ -10725,13 +10793,13 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
10725
10793
  const refreshLayers = () => {
10726
10794
  clearOverlays();
10727
10795
  if (!host?.bench) return;
10728
- for (const layer of ["capsules", "joints", "speed"]) {
10729
- if (!host.bench.layer(layer)) continue;
10796
+ for (const layer2 of ["capsules", "joints", "speed"]) {
10797
+ if (!host.bench.layer(layer2)) continue;
10730
10798
  for (const entry of entries2.values()) {
10731
- const overlay = overlayFor(layer, entry);
10799
+ const overlay = overlayFor(layer2, entry);
10732
10800
  if (!overlay) continue;
10733
10801
  entry.root.add(overlay);
10734
- overlays.set(`${layer}:${entry.id}`, overlay);
10802
+ overlays.set(`${layer2}:${entry.id}`, overlay);
10735
10803
  }
10736
10804
  }
10737
10805
  const eyesOnly = host.bench.layer("eyes_only");
@@ -10739,6 +10807,8 @@ ${accessoryHead}`).replace("{ vec3 _nn = objectNormal; bodyAnim(position, _nn);"
10739
10807
  };
10740
10808
  const animate = (entry, dt) => {
10741
10809
  const { root, character } = entry;
10810
+ const launched = takeLaunch(root);
10811
+ if (launched) entry.knock = launched;
10742
10812
  if (entry.knock) {
10743
10813
  const rig = root.userData.rig;
10744
10814
  const ground = (x, z) => host?.groundAt(x, z) ?? 0;