incanto 0.44.0 → 0.45.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.
- package/dist/3d.d.ts +12 -0
- package/dist/3d.js +3 -3
- package/dist/{create-game-D90pyPMx.js → create-game-Gifrjhnz.js} +2 -2
- package/dist/debug.d.ts +15 -0
- package/dist/debug.js +144 -11
- package/dist/{environment-presets-Ds5kXLoF.js → environment-presets-DUsBqvtk.js} +179 -38
- package/dist/index.js +1 -1
- package/dist/{physics-3d-CLPFv99o.js → physics-3d-DFqMtBUD.js} +1 -1
- package/dist/react.js +1 -1
- package/dist/{src-B3n06SsL.js → src-DUxGnvq3.js} +1 -1
- package/dist/{test-BMgiiD5i.js → test-DD5scWfm.js} +3 -3
- package/dist/test.js +1 -1
- package/dist/vite.js +2 -2
- package/editor/assets/{agent8-MgX6kYWH.js → agent8-B25qJ5Wo.js} +1 -1
- package/editor/assets/debug-CUsz-pT8.js +3 -0
- package/editor/assets/{index-D9MX3UHF.js → index-3u3GVteP.js} +24 -24
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/skills/incanto-3d-character.md +2 -1
- package/skills/incanto-3d-models.md +22 -7
- package/skills/incanto-audio.md +1 -1
- package/skills/incanto-scene-json-authoring.md +1 -1
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/village-quest-3d/package.json +1 -1
- package/editor/assets/debug-Czri9cgX.js +0 -3
package/dist/3d.d.ts
CHANGED
|
@@ -1796,6 +1796,8 @@ declare class ModelInstance3D extends Node3D {
|
|
|
1796
1796
|
private entry;
|
|
1797
1797
|
private mountedRef;
|
|
1798
1798
|
private fittedHeight;
|
|
1799
|
+
/** A skinned model waiting for a posed skeleton it can be measured against. */
|
|
1800
|
+
private fitPending;
|
|
1799
1801
|
private fitGroup;
|
|
1800
1802
|
/**
|
|
1801
1803
|
* @internal The mounted model, or null while the asset is still loading.
|
|
@@ -1855,6 +1857,16 @@ declare class ModelInstance3D extends Node3D {
|
|
|
1855
1857
|
availableAnimations(): string[];
|
|
1856
1858
|
/** Called by the 3D sync pass with the renderer's asset store. */
|
|
1857
1859
|
_syncModel(assets: AssetStore3D): void;
|
|
1860
|
+
/**
|
|
1861
|
+
* Scale the model so it stands `targetHeight` tall, measured ONCE.
|
|
1862
|
+
*
|
|
1863
|
+
* Once, deliberately: the measurement reflects the pose the model happens to
|
|
1864
|
+
* be in, and re-running it every frame would let a walk cycle resize the
|
|
1865
|
+
* character mid-stride. In practice the pose barely matters — across a whole
|
|
1866
|
+
* idle clip this rig's height moves 0.5% — but "barely" is not "never", and
|
|
1867
|
+
* a size that breathes is worse than one that is half a percent off.
|
|
1868
|
+
*/
|
|
1869
|
+
private applyFit;
|
|
1858
1870
|
/** Apply per-instance material mods — `tint` (multiplied into colour) and the
|
|
1859
1871
|
* `metalness`/`roughness` overrides — by cloning the captured originals
|
|
1860
1872
|
* (never mutates the shared source), disposing prior clones on change. */
|
package/dist/3d.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { A as Water3D, F as PhysicsBody3D, I as RigidBody3D, L as StaticBody3D, M as WaterCutout3D, N as Area3D, P as CharacterBody3D, R as Node3D, V as WATER_MAX_RIPPLES, j as WATER_CUTOUT_MAX } from "./gameplay-BQOeAid6.js";
|
|
2
|
-
import { A as Terrain3D, B as keyboardIntensity, C as resolveFlowerDensity, D as BoneLookAt3D, E as Camera3D, F as InstancedMesh3D, G as acquireTexture, H as rigPose, I as MeshInstance3D, M as TERRAIN_THEMES, N as terrainThemeLayers, O as BoneAttachment3D, P as Joint3D, R as QUARTER_PITCH, S as Flowers3D, T as CharacterController3D, U as TextureCache3D, V as movementState, W as acquireOwnTexture, _ as LoftMesh3D, a as Tree3D, b as Foliage3D, c as buildRiverRings, d as riverCarveChannels, f as riverStepFor, g as ModelInstance3D, h as Particles3D, i as VoxelGrid3D, j as DEFAULT_TERRAIN_TEXTURE_BASE, k as Billboard3D, l as findRiverCoverageGaps, m as traceDownhillPath, n as registerNodes3D, o as Trail3D, p as smoothCourse, r as VOXEL_PALETTE, s as River3D, u as projectToRiver, v as DirectionalLight3D, w as FLOWER_VARIETIES, x as DENSITY_PRESETS, y as OmniLight3D, z as cameraRelative } from "./environment-presets-
|
|
3
|
-
import { a as Environment3D, c as parseEnvironment3D, d as AssetStore3D, i as syncTree, l as sunDirectionFromElevationAzimuth, o as setEnvironment3D, r as Renderer3D, s as horizonColorFromSky, t as createGame3D, u as sunDirectionFromSky } from "./create-game-
|
|
2
|
+
import { A as Terrain3D, B as keyboardIntensity, C as resolveFlowerDensity, D as BoneLookAt3D, E as Camera3D, F as InstancedMesh3D, G as acquireTexture, H as rigPose, I as MeshInstance3D, M as TERRAIN_THEMES, N as terrainThemeLayers, O as BoneAttachment3D, P as Joint3D, R as QUARTER_PITCH, S as Flowers3D, T as CharacterController3D, U as TextureCache3D, V as movementState, W as acquireOwnTexture, _ as LoftMesh3D, a as Tree3D, b as Foliage3D, c as buildRiverRings, d as riverCarveChannels, f as riverStepFor, g as ModelInstance3D, h as Particles3D, i as VoxelGrid3D, j as DEFAULT_TERRAIN_TEXTURE_BASE, k as Billboard3D, l as findRiverCoverageGaps, m as traceDownhillPath, n as registerNodes3D, o as Trail3D, p as smoothCourse, r as VOXEL_PALETTE, s as River3D, u as projectToRiver, v as DirectionalLight3D, w as FLOWER_VARIETIES, x as DENSITY_PRESETS, y as OmniLight3D, z as cameraRelative } from "./environment-presets-DUsBqvtk.js";
|
|
3
|
+
import { a as Environment3D, c as parseEnvironment3D, d as AssetStore3D, i as syncTree, l as sunDirectionFromElevationAzimuth, o as setEnvironment3D, r as Renderer3D, s as horizonColorFromSky, t as createGame3D, u as sunDirectionFromSky } from "./create-game-Gifrjhnz.js";
|
|
4
4
|
import { a as frameStats, i as frameSignature, n as diffSignatures, o as frameText, r as diffText, t as SIGNATURE_GRID } from "./frame-report-Lr3VO24R.js";
|
|
5
5
|
import { n as splatWeights, t as buildHeightmap } from "./heightmap-CRK0M4jT.js";
|
|
6
|
-
import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-
|
|
6
|
+
import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-DFqMtBUD.js";
|
|
7
7
|
//#region src/3d/terrain-nav.ts
|
|
8
8
|
function buildTerrainNav(terrain, opts) {
|
|
9
9
|
const cellSize = opts?.cellSize ?? 2;
|
|
@@ -6,9 +6,9 @@ import { i as resolveRendering, n as attachTouchControls } from "./touch-BoNg_Mn
|
|
|
6
6
|
import { a as openBundledEditor, i as devServerLibrary, n as pauseWhenHidden, o as poseFromRenderer, r as crossFade, t as teardown } from "./teardown-yePMOE1K.js";
|
|
7
7
|
import { B as createCausticsQuad, F as PhysicsBody3D, R as Node3D, n as registerGameplayBehaviors } from "./gameplay-BQOeAid6.js";
|
|
8
8
|
import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
|
|
9
|
-
import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-
|
|
9
|
+
import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-DUsBqvtk.js";
|
|
10
10
|
import { a as frameStats, i as frameSignature } from "./frame-report-Lr3VO24R.js";
|
|
11
|
-
import { n as enablePhysics3D } from "./physics-3d-
|
|
11
|
+
import { n as enablePhysics3D } from "./physics-3d-DFqMtBUD.js";
|
|
12
12
|
import { ACESFilmicToneMapping, AmbientLight, Box3, BufferAttribute, BufferGeometry, Color, DepthTexture, EquirectangularReflectionMapping, FloatType, Fog, HalfFloatType, LineBasicMaterial, LineSegments, Matrix4, Mesh, PCFShadowMap, PMREMGenerator, PerspectiveCamera, PlaneGeometry, Quaternion, Raycaster, Scene, ShaderMaterial, Vector2, Vector3, WebGLRenderTarget, WebGLRenderer } from "three";
|
|
13
13
|
import { VRMLoaderPlugin, VRMUtils } from "@pixiv/three-vrm";
|
|
14
14
|
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
|
package/dist/debug.d.ts
CHANGED
|
@@ -71,6 +71,9 @@ declare class DebugOverlay {
|
|
|
71
71
|
private readonly cleanups;
|
|
72
72
|
private readonly menuButton;
|
|
73
73
|
private dropdown;
|
|
74
|
+
private dismissDropdown;
|
|
75
|
+
/** Where the ☰ button sits, in container CSS px. Drag moves it; see bindMenuDrag. */
|
|
76
|
+
private menuPos;
|
|
74
77
|
private selected;
|
|
75
78
|
/** Explorer subtrees the user collapsed (nodes keep identity across frames). */
|
|
76
79
|
private readonly collapsedFlags;
|
|
@@ -121,6 +124,18 @@ declare class DebugOverlay {
|
|
|
121
124
|
dispose(): void;
|
|
122
125
|
/** `✓ Colliders · selected` — check for on, suffix for the collider mode. */
|
|
123
126
|
private menuLabel;
|
|
127
|
+
/**
|
|
128
|
+
* The ☰ button is draggable, because top-left is exactly where a game puts
|
|
129
|
+
* its own menu and a debug chip pinned on top of it is a debug chip you
|
|
130
|
+
* cannot use.
|
|
131
|
+
*
|
|
132
|
+
* Drag and click share one pointer, so they are told apart by distance: under
|
|
133
|
+
* the threshold the press was a click and the menu opens, over it the press
|
|
134
|
+
* was a grab and the menu must NOT open under the finger that just let go.
|
|
135
|
+
*/
|
|
136
|
+
private bindMenuDrag;
|
|
137
|
+
private moveMenuButton;
|
|
138
|
+
private closeDropdown;
|
|
124
139
|
private toggleDropdown;
|
|
125
140
|
private openStatsChip;
|
|
126
141
|
private renderStats;
|
package/dist/debug.js
CHANGED
|
@@ -193,6 +193,59 @@ function clampPanelRect(x, y, w, h, viewW, viewH, minW = 180, minH = 120) {
|
|
|
193
193
|
h: ch
|
|
194
194
|
};
|
|
195
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Where a dropdown goes relative to the thing that opened it.
|
|
198
|
+
*
|
|
199
|
+
* Left-aligned under the anchor, flipped above it when there is no room below,
|
|
200
|
+
* and never off the side — a menu that opens past the edge of the window is a
|
|
201
|
+
* menu with items nobody can reach. The anchor moves (the ☰ button is
|
|
202
|
+
* draggable), so this cannot be the constant it used to be.
|
|
203
|
+
*/
|
|
204
|
+
function anchorDropdown(anchor, menuW, menuH, viewW, viewH, gap = 4) {
|
|
205
|
+
const x = Math.min(Math.max(0, anchor.x), Math.max(0, viewW - menuW));
|
|
206
|
+
const below = anchor.y + anchor.h + gap;
|
|
207
|
+
const above = anchor.y - menuH - gap;
|
|
208
|
+
if (below + menuH <= viewH) return {
|
|
209
|
+
x,
|
|
210
|
+
y: below
|
|
211
|
+
};
|
|
212
|
+
if (above >= 0) return {
|
|
213
|
+
x,
|
|
214
|
+
y: above
|
|
215
|
+
};
|
|
216
|
+
return {
|
|
217
|
+
x,
|
|
218
|
+
y: Math.min(Math.max(0, below), Math.max(0, viewH - menuH))
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Make a transient thing dismissible: Esc, or a press anywhere outside it.
|
|
223
|
+
*
|
|
224
|
+
* Returns the disposer. Attaching this is how "you can always get out of it"
|
|
225
|
+
* stops being something each caller has to remember — the overlay had a
|
|
226
|
+
* dismissible capture layer and a dropdown you could only close by choosing
|
|
227
|
+
* something from it.
|
|
228
|
+
*/
|
|
229
|
+
function dismissOn(doc, inside, close) {
|
|
230
|
+
const onKey = (event) => {
|
|
231
|
+
if (event.key === "Escape") close();
|
|
232
|
+
};
|
|
233
|
+
const onDown = (event) => {
|
|
234
|
+
const target = event.target;
|
|
235
|
+
if (!target) return;
|
|
236
|
+
for (const el of inside) {
|
|
237
|
+
if (!el) continue;
|
|
238
|
+
if (el === target || el.contains?.(target)) return;
|
|
239
|
+
}
|
|
240
|
+
close();
|
|
241
|
+
};
|
|
242
|
+
doc.addEventListener?.("keydown", onKey);
|
|
243
|
+
doc.addEventListener?.("pointerdown", onDown);
|
|
244
|
+
return () => {
|
|
245
|
+
doc.removeEventListener?.("keydown", onKey);
|
|
246
|
+
doc.removeEventListener?.("pointerdown", onDown);
|
|
247
|
+
};
|
|
248
|
+
}
|
|
196
249
|
function applyStyle(el, rules) {
|
|
197
250
|
for (const [key, value] of Object.entries(rules)) el.style[key] = value;
|
|
198
251
|
}
|
|
@@ -658,6 +711,8 @@ function isPlainObject(value) {
|
|
|
658
711
|
/** The slider's ceiling. Beyond this the number box is the tool — a 0..8 slider
|
|
659
712
|
* makes the 0.1-to-1 range, where slow-motion debugging actually lives, unusable. */
|
|
660
713
|
const TIME_SLIDER_MAX = 2;
|
|
714
|
+
/** Under this much movement the press was a click, not a grab. */
|
|
715
|
+
const MENU_DRAG_THRESHOLD = 4;
|
|
661
716
|
/** Attach the overlay; null when no DOM is available (headless). */
|
|
662
717
|
function attachDebugOverlay(engine, opts = {}) {
|
|
663
718
|
const doc = opts.doc ?? (typeof document !== "undefined" ? document : null);
|
|
@@ -685,6 +740,12 @@ var DebugOverlay = class {
|
|
|
685
740
|
cleanups = [];
|
|
686
741
|
menuButton;
|
|
687
742
|
dropdown = null;
|
|
743
|
+
dismissDropdown = null;
|
|
744
|
+
/** Where the ☰ button sits, in container CSS px. Drag moves it; see bindMenuDrag. */
|
|
745
|
+
menuPos = {
|
|
746
|
+
x: 8,
|
|
747
|
+
y: 8
|
|
748
|
+
};
|
|
688
749
|
selected = null;
|
|
689
750
|
/** Explorer subtrees the user collapsed (nodes keep identity across frames). */
|
|
690
751
|
collapsedFlags = /* @__PURE__ */ new Map();
|
|
@@ -737,7 +798,7 @@ var DebugOverlay = class {
|
|
|
737
798
|
zIndex: "50",
|
|
738
799
|
pointerEvents: "auto"
|
|
739
800
|
});
|
|
740
|
-
this.
|
|
801
|
+
this.bindMenuDrag();
|
|
741
802
|
if (!container.style.position) container.style.position = "relative";
|
|
742
803
|
container.appendChild(this.menuButton);
|
|
743
804
|
this.cleanups.push(engine.log.added.connect((entry) => {
|
|
@@ -921,8 +982,7 @@ var DebugOverlay = class {
|
|
|
921
982
|
for (const cleanup of this.cleanups) cleanup();
|
|
922
983
|
for (const id of [...this.panels.keys()]) this.close(id);
|
|
923
984
|
this.close("stats");
|
|
924
|
-
this.
|
|
925
|
-
this.dropdown = null;
|
|
985
|
+
this.closeDropdown();
|
|
926
986
|
this.menuButton.remove();
|
|
927
987
|
}
|
|
928
988
|
/** `✓ Colliders · selected` — check for on, suffix for the collider mode. */
|
|
@@ -930,17 +990,79 @@ var DebugOverlay = class {
|
|
|
930
990
|
const suffix = id === "colliders" && this.colliderMode !== "off" ? ` · ${this.colliderMode}` : "";
|
|
931
991
|
return `${this.isOpen(id) ? "✓ " : ""}${label}${suffix}`;
|
|
932
992
|
}
|
|
993
|
+
/**
|
|
994
|
+
* The ☰ button is draggable, because top-left is exactly where a game puts
|
|
995
|
+
* its own menu and a debug chip pinned on top of it is a debug chip you
|
|
996
|
+
* cannot use.
|
|
997
|
+
*
|
|
998
|
+
* Drag and click share one pointer, so they are told apart by distance: under
|
|
999
|
+
* the threshold the press was a click and the menu opens, over it the press
|
|
1000
|
+
* was a grab and the menu must NOT open under the finger that just let go.
|
|
1001
|
+
*/
|
|
1002
|
+
bindMenuDrag() {
|
|
1003
|
+
let start = null;
|
|
1004
|
+
let dragged = false;
|
|
1005
|
+
this.menuButton.addEventListener("pointerdown", (event) => {
|
|
1006
|
+
const e = event;
|
|
1007
|
+
start = {
|
|
1008
|
+
x: e.clientX ?? 0,
|
|
1009
|
+
y: e.clientY ?? 0,
|
|
1010
|
+
bx: this.menuPos.x,
|
|
1011
|
+
by: this.menuPos.y
|
|
1012
|
+
};
|
|
1013
|
+
dragged = false;
|
|
1014
|
+
if (e.pointerId !== void 0) this.menuButton.setPointerCapture?.(e.pointerId);
|
|
1015
|
+
});
|
|
1016
|
+
this.menuButton.addEventListener("pointermove", (event) => {
|
|
1017
|
+
if (!start) return;
|
|
1018
|
+
const e = event;
|
|
1019
|
+
const dx = (e.clientX ?? 0) - start.x;
|
|
1020
|
+
const dy = (e.clientY ?? 0) - start.y;
|
|
1021
|
+
if (!dragged && Math.hypot(dx, dy) < MENU_DRAG_THRESHOLD) return;
|
|
1022
|
+
if (!dragged) {
|
|
1023
|
+
dragged = true;
|
|
1024
|
+
this.closeDropdown();
|
|
1025
|
+
applyStyle(this.menuButton, { cursor: "grabbing" });
|
|
1026
|
+
}
|
|
1027
|
+
this.moveMenuButton(start.bx + dx, start.by + dy);
|
|
1028
|
+
});
|
|
1029
|
+
const release = () => {
|
|
1030
|
+
if (!start) return;
|
|
1031
|
+
const wasDrag = dragged;
|
|
1032
|
+
start = null;
|
|
1033
|
+
dragged = false;
|
|
1034
|
+
applyStyle(this.menuButton, { cursor: "pointer" });
|
|
1035
|
+
if (!wasDrag) this.toggleDropdown();
|
|
1036
|
+
};
|
|
1037
|
+
this.menuButton.addEventListener("pointerup", release);
|
|
1038
|
+
this.menuButton.addEventListener("pointercancel", release);
|
|
1039
|
+
}
|
|
1040
|
+
moveMenuButton(x, y) {
|
|
1041
|
+
const el = this.menuButton;
|
|
1042
|
+
const box = clampPanelRect(x, y, el.offsetWidth ?? 0, el.offsetHeight ?? 0, this.container.clientWidth || 0, this.container.clientHeight || 0, 0, 0);
|
|
1043
|
+
this.menuPos = {
|
|
1044
|
+
x: box.x,
|
|
1045
|
+
y: box.y
|
|
1046
|
+
};
|
|
1047
|
+
applyStyle(this.menuButton, {
|
|
1048
|
+
left: `${box.x}px`,
|
|
1049
|
+
top: `${box.y}px`
|
|
1050
|
+
});
|
|
1051
|
+
}
|
|
1052
|
+
closeDropdown() {
|
|
1053
|
+
this.dismissDropdown?.();
|
|
1054
|
+
this.dismissDropdown = null;
|
|
1055
|
+
this.dropdown?.remove();
|
|
1056
|
+
this.dropdown = null;
|
|
1057
|
+
}
|
|
933
1058
|
toggleDropdown() {
|
|
934
1059
|
if (this.dropdown) {
|
|
935
|
-
this.
|
|
936
|
-
this.dropdown = null;
|
|
1060
|
+
this.closeDropdown();
|
|
937
1061
|
return;
|
|
938
1062
|
}
|
|
939
1063
|
const menu = this.doc.createElement("div");
|
|
940
1064
|
applyStyle(menu, {
|
|
941
1065
|
position: "absolute",
|
|
942
|
-
top: "34px",
|
|
943
|
-
left: "8px",
|
|
944
1066
|
background: "rgba(18,20,26,0.95)",
|
|
945
1067
|
border: "1px solid rgba(255,255,255,0.18)",
|
|
946
1068
|
borderRadius: "6px",
|
|
@@ -973,8 +1095,7 @@ var DebugOverlay = class {
|
|
|
973
1095
|
item.textContent = this.menuLabel(id, label);
|
|
974
1096
|
return;
|
|
975
1097
|
}
|
|
976
|
-
this.
|
|
977
|
-
this.dropdown = null;
|
|
1098
|
+
this.closeDropdown();
|
|
978
1099
|
});
|
|
979
1100
|
menu.appendChild(item);
|
|
980
1101
|
}
|
|
@@ -989,14 +1110,26 @@ var DebugOverlay = class {
|
|
|
989
1110
|
color: "rgba(158,232,220,0.95)"
|
|
990
1111
|
});
|
|
991
1112
|
item.addEventListener("click", () => {
|
|
992
|
-
this.
|
|
993
|
-
this.dropdown = null;
|
|
1113
|
+
this.closeDropdown();
|
|
994
1114
|
action.run();
|
|
995
1115
|
});
|
|
996
1116
|
menu.appendChild(item);
|
|
997
1117
|
}
|
|
998
1118
|
this.container.appendChild(menu);
|
|
999
1119
|
this.dropdown = menu;
|
|
1120
|
+
const el = menu;
|
|
1121
|
+
const btn = this.menuButton;
|
|
1122
|
+
const at = anchorDropdown({
|
|
1123
|
+
x: this.menuPos.x,
|
|
1124
|
+
y: this.menuPos.y,
|
|
1125
|
+
w: btn.offsetWidth ?? 0,
|
|
1126
|
+
h: btn.offsetHeight ?? 26
|
|
1127
|
+
}, el.offsetWidth ?? 0, el.offsetHeight ?? 0, this.container.clientWidth || 0, this.container.clientHeight || 0);
|
|
1128
|
+
applyStyle(menu, {
|
|
1129
|
+
left: `${at.x}px`,
|
|
1130
|
+
top: `${at.y}px`
|
|
1131
|
+
});
|
|
1132
|
+
this.dismissDropdown = dismissOn(this.doc, [menu, this.menuButton], () => this.closeDropdown());
|
|
1000
1133
|
}
|
|
1001
1134
|
openStatsChip() {
|
|
1002
1135
|
if (this.statsChip) return;
|
|
@@ -2797,8 +2797,12 @@ var CharacterController3D = class extends Node3D {
|
|
|
2797
2797
|
if (!input) return;
|
|
2798
2798
|
if (this.mouseLook) {
|
|
2799
2799
|
const d = input.pointerDelta();
|
|
2800
|
-
|
|
2801
|
-
|
|
2800
|
+
const settings = this.tree?.engine?.settings;
|
|
2801
|
+
const sensitivity = settings?.get("sensitivity") ?? 1;
|
|
2802
|
+
const invertY = settings?.get("invertY") ?? false;
|
|
2803
|
+
const speed = LOOK_SPEED * (typeof sensitivity === "number" && sensitivity > 0 ? sensitivity : 1);
|
|
2804
|
+
this.yaw -= d.x * speed;
|
|
2805
|
+
this.pitch = clamp(this.pitch + (invertY === true ? -d.y : d.y) * speed, -this.pitchMax, -this.pitchMin);
|
|
2802
2806
|
const wheel = input.wheelDelta();
|
|
2803
2807
|
if (wheel !== 0 && this.zoomMax > this.zoomMin) this.camDistance = clamp(this.camDistance + wheel * LOOK_SPEED, this.zoomMin, this.zoomMax);
|
|
2804
2808
|
}
|
|
@@ -5958,6 +5962,96 @@ function boneSubtree(root) {
|
|
|
5958
5962
|
return out;
|
|
5959
5963
|
}
|
|
5960
5964
|
//#endregion
|
|
5965
|
+
//#region src/3d/animation/retarget-rig.ts
|
|
5966
|
+
/**
|
|
5967
|
+
* Play someone else's animation without becoming someone else.
|
|
5968
|
+
*
|
|
5969
|
+
* A Mixamo clip is not a list of rotations. It carries a POSITION and a SCALE
|
|
5970
|
+
* track for every bone — 195 tracks for 65 bones on the stock character — and
|
|
5971
|
+
* three's mixer applies all of them. Bind a clip like that to a character by
|
|
5972
|
+
* node name and the clip does not animate the character: it REPLACES the
|
|
5973
|
+
* character's skeleton with the one the clip was authored on. A stocky
|
|
5974
|
+
* four-heads-tall model quietly becomes eight heads tall the moment it idles,
|
|
5975
|
+
* and there is nothing in the scene JSON that says so.
|
|
5976
|
+
*
|
|
5977
|
+
* That is backwards. The model owns its proportions; the animation is the thing
|
|
5978
|
+
* that has to adapt. So only the rotations cross over — they mean the same
|
|
5979
|
+
* thing on any skeleton — and of the translations only the hips survive, scaled
|
|
5980
|
+
* by the ratio of hip heights. That one exception matters: hip travel is in the
|
|
5981
|
+
* SOURCE rig's units, so handing a short character a tall rig's stride slides
|
|
5982
|
+
* its feet and overshoots its jumps.
|
|
5983
|
+
*
|
|
5984
|
+
* Same algorithm the VRM path has always used (`retarget-vrm.ts`), which until
|
|
5985
|
+
* now was the only path that had it.
|
|
5986
|
+
*/
|
|
5987
|
+
/** Mixamo exports this bone as `mixamorigHips` or `mixamorig:Hips`. */
|
|
5988
|
+
function findHips(root) {
|
|
5989
|
+
let found = null;
|
|
5990
|
+
root.traverse((o) => {
|
|
5991
|
+
if (found) return;
|
|
5992
|
+
if (/^mixamorig[:_]?hips$/i.test(o.name) || /^hips$/i.test(o.name)) found = o;
|
|
5993
|
+
});
|
|
5994
|
+
return found;
|
|
5995
|
+
}
|
|
5996
|
+
/** How high the hips sit above the rig's own root, in that rig's own units. */
|
|
5997
|
+
function hipHeight(root, hips) {
|
|
5998
|
+
root.updateMatrixWorld(true);
|
|
5999
|
+
const inRoot = hips.matrixWorld.clone().premultiply(root.matrixWorld.clone().invert());
|
|
6000
|
+
return Math.abs(inRoot.elements[13] ?? 0);
|
|
6001
|
+
}
|
|
6002
|
+
const boneOf = (trackName) => trackName.split(".")[0] ?? "";
|
|
6003
|
+
const propertyOf = (trackName) => trackName.split(".").pop() ?? "";
|
|
6004
|
+
/**
|
|
6005
|
+
* A copy of `clip` that animates `targetRoot` without re-proportioning it.
|
|
6006
|
+
*
|
|
6007
|
+
* Passes the clip through untouched when it cannot do better — a clip whose
|
|
6008
|
+
* bones the target does not have would be stripped to nothing, and a silent
|
|
6009
|
+
* empty animation is worse than a wrong-sized one.
|
|
6010
|
+
*/
|
|
6011
|
+
function retargetClipToRig(clip, sourceScene, targetRoot) {
|
|
6012
|
+
const targetBones = /* @__PURE__ */ new Set();
|
|
6013
|
+
targetRoot.traverse((o) => targetBones.add(o.name));
|
|
6014
|
+
if (clip.tracks.filter((t) => propertyOf(t.name) === "quaternion" && targetBones.has(boneOf(t.name))).length === 0) return {
|
|
6015
|
+
clip,
|
|
6016
|
+
droppedTracks: 0,
|
|
6017
|
+
hipsScale: 1,
|
|
6018
|
+
passthrough: true,
|
|
6019
|
+
reason: "no bone in this clip matches the model — played as authored"
|
|
6020
|
+
};
|
|
6021
|
+
const sourceHips = findHips(sourceScene);
|
|
6022
|
+
const targetHips = findHips(targetRoot);
|
|
6023
|
+
const sourceHeight = sourceHips ? hipHeight(sourceScene, sourceHips) : 0;
|
|
6024
|
+
const targetHeight = targetHips ? hipHeight(targetRoot, targetHips) : 0;
|
|
6025
|
+
const hipsScale = sourceHeight > 1e-6 && targetHeight > 1e-6 ? targetHeight / sourceHeight : 1;
|
|
6026
|
+
const hipsName = targetHips?.name ?? "";
|
|
6027
|
+
const tracks = [];
|
|
6028
|
+
let dropped = 0;
|
|
6029
|
+
for (const track of clip.tracks) {
|
|
6030
|
+
const bone = boneOf(track.name);
|
|
6031
|
+
const property = propertyOf(track.name);
|
|
6032
|
+
if (!targetBones.has(bone)) {
|
|
6033
|
+
dropped += 1;
|
|
6034
|
+
continue;
|
|
6035
|
+
}
|
|
6036
|
+
if (property === "quaternion") {
|
|
6037
|
+
tracks.push(track);
|
|
6038
|
+
continue;
|
|
6039
|
+
}
|
|
6040
|
+
if (property === "position" && bone === hipsName) {
|
|
6041
|
+
const values = Array.from(track.values, (v) => v * hipsScale);
|
|
6042
|
+
tracks.push(new VectorKeyframeTrack(track.name, Array.from(track.times), values));
|
|
6043
|
+
continue;
|
|
6044
|
+
}
|
|
6045
|
+
dropped += 1;
|
|
6046
|
+
}
|
|
6047
|
+
return {
|
|
6048
|
+
clip: new AnimationClip(`${clip.name} (retargeted)`, clip.duration, tracks),
|
|
6049
|
+
droppedTracks: dropped,
|
|
6050
|
+
hipsScale,
|
|
6051
|
+
passthrough: false
|
|
6052
|
+
};
|
|
6053
|
+
}
|
|
6054
|
+
//#endregion
|
|
5961
6055
|
//#region src/3d/animation/rigmap.ts
|
|
5962
6056
|
/**
|
|
5963
6057
|
* Mixamo rig name → VRM humanoid bone name (the vibe-starter-3d /
|
|
@@ -6190,6 +6284,8 @@ var ModelInstance3D = class extends Node3D {
|
|
|
6190
6284
|
entry = null;
|
|
6191
6285
|
mountedRef = "";
|
|
6192
6286
|
fittedHeight = -1;
|
|
6287
|
+
/** A skinned model waiting for a posed skeleton it can be measured against. */
|
|
6288
|
+
fitPending = false;
|
|
6193
6289
|
fitGroup = null;
|
|
6194
6290
|
/**
|
|
6195
6291
|
* @internal The mounted model, or null while the asset is still loading.
|
|
@@ -6340,18 +6436,15 @@ var ModelInstance3D = class extends Node3D {
|
|
|
6340
6436
|
});
|
|
6341
6437
|
});
|
|
6342
6438
|
}
|
|
6343
|
-
if (this.fitGroup
|
|
6344
|
-
this.fittedHeight
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
this.fitGroup.scale.setScalar(1);
|
|
6348
|
-
const size = skinnedAwareBox(this.fitGroup).getSize(new Vector3());
|
|
6349
|
-
const scale = size.y > 0 ? this.targetHeight / size.y : prev;
|
|
6350
|
-
if (scale < .05 || scale > 20) {
|
|
6439
|
+
if (this.fitGroup) {
|
|
6440
|
+
if (this.fittedHeight !== this.targetHeight) {
|
|
6441
|
+
this.fittedHeight = this.targetHeight;
|
|
6442
|
+
if (this.targetHeight <= 0) {
|
|
6351
6443
|
this.fitGroup.scale.setScalar(1);
|
|
6352
|
-
this.
|
|
6353
|
-
} else this.fitGroup.
|
|
6354
|
-
|
|
6444
|
+
this.fitPending = false;
|
|
6445
|
+
} else if (hasSkinning(this.fitGroup)) this.fitPending = true;
|
|
6446
|
+
else this.applyFit();
|
|
6447
|
+
}
|
|
6355
6448
|
}
|
|
6356
6449
|
if (this.fitGroup) this.fitGroup.traverse((obj) => {
|
|
6357
6450
|
const mesh = obj;
|
|
@@ -6365,6 +6458,30 @@ var ModelInstance3D = class extends Node3D {
|
|
|
6365
6458
|
this.syncAnimation(assets);
|
|
6366
6459
|
this.syncUpperAnimation(assets);
|
|
6367
6460
|
}
|
|
6461
|
+
/**
|
|
6462
|
+
* Scale the model so it stands `targetHeight` tall, measured ONCE.
|
|
6463
|
+
*
|
|
6464
|
+
* Once, deliberately: the measurement reflects the pose the model happens to
|
|
6465
|
+
* be in, and re-running it every frame would let a walk cycle resize the
|
|
6466
|
+
* character mid-stride. In practice the pose barely matters — across a whole
|
|
6467
|
+
* idle clip this rig's height moves 0.5% — but "barely" is not "never", and
|
|
6468
|
+
* a size that breathes is worse than one that is half a percent off.
|
|
6469
|
+
*/
|
|
6470
|
+
applyFit() {
|
|
6471
|
+
const fit = this.fitGroup;
|
|
6472
|
+
if (!fit) return;
|
|
6473
|
+
this.fitPending = false;
|
|
6474
|
+
const previous = fit.scale.x;
|
|
6475
|
+
fit.scale.setScalar(1);
|
|
6476
|
+
const height = renderedBox(fit).getSize(new Vector3()).y;
|
|
6477
|
+
const scale = height > 0 ? this.targetHeight / height : previous;
|
|
6478
|
+
if (scale < .05 || scale > 20) {
|
|
6479
|
+
fit.scale.setScalar(1);
|
|
6480
|
+
this.diagnose("warn", `[incanto] ModelInstance3D '${this.name}': targetHeight fit measured an implausible scale (${scale.toFixed(2)}x) — the model may have no geometry. Rendering at the model's authored scale instead.`);
|
|
6481
|
+
return;
|
|
6482
|
+
}
|
|
6483
|
+
fit.scale.setScalar(scale);
|
|
6484
|
+
}
|
|
6368
6485
|
/** Apply per-instance material mods — `tint` (multiplied into colour) and the
|
|
6369
6486
|
* `metalness`/`roughness` overrides — by cloning the captured originals
|
|
6370
6487
|
* (never mutates the shared source), disposing prior clones on change. */
|
|
@@ -6427,7 +6544,12 @@ var ModelInstance3D = class extends Node3D {
|
|
|
6427
6544
|
this.entry.retargeted.set(ref, result.clip);
|
|
6428
6545
|
return result.clip;
|
|
6429
6546
|
}
|
|
6430
|
-
|
|
6547
|
+
const cached = this.entry.retargeted.get(ref);
|
|
6548
|
+
if (cached) return cached;
|
|
6549
|
+
const rig = retargetClipToRig(source, anim.scene, this.fitGroup ?? this._ensureObject3D());
|
|
6550
|
+
if (rig.passthrough) this.diagnose("warn", `incanto: animation '${ref}' — ${rig.reason}`);
|
|
6551
|
+
this.entry.retargeted.set(ref, rig.clip);
|
|
6552
|
+
return rig.clip;
|
|
6431
6553
|
}
|
|
6432
6554
|
/** Masked upper/lower variants of a clip for two-layer playback (cached). */
|
|
6433
6555
|
layerVariants(clip) {
|
|
@@ -6536,6 +6658,7 @@ var ModelInstance3D = class extends Node3D {
|
|
|
6536
6658
|
}
|
|
6537
6659
|
this.mixer?.update(dt);
|
|
6538
6660
|
if (this.entry?.isVrm && this.entry.claimedBy === this) this.entry.vrm?.update(dt);
|
|
6661
|
+
if (this.fitPending) this.applyFit();
|
|
6539
6662
|
}
|
|
6540
6663
|
onExitTree() {
|
|
6541
6664
|
this.unmount(this._ensureObject3D());
|
|
@@ -6560,39 +6683,57 @@ var ModelInstance3D = class extends Node3D {
|
|
|
6560
6683
|
this.fittedHeight = -1;
|
|
6561
6684
|
}
|
|
6562
6685
|
};
|
|
6686
|
+
/** Does anything under here reach the screen through a skeleton? */
|
|
6687
|
+
function hasSkinning(root) {
|
|
6688
|
+
let found = false;
|
|
6689
|
+
root.traverse((o) => {
|
|
6690
|
+
if (o.isSkinnedMesh) found = true;
|
|
6691
|
+
});
|
|
6692
|
+
return found;
|
|
6693
|
+
}
|
|
6563
6694
|
/**
|
|
6564
|
-
*
|
|
6565
|
-
*
|
|
6566
|
-
*
|
|
6567
|
-
*
|
|
6568
|
-
*
|
|
6569
|
-
*
|
|
6695
|
+
* How big the model will actually BE on screen, in the fit group's own space.
|
|
6696
|
+
*
|
|
6697
|
+
* A skinned vertex does not reach the screen through `matrixWorld`. three puts
|
|
6698
|
+
* it through the whole skinning chain
|
|
6699
|
+
*
|
|
6700
|
+
* world = matrixWorld · bindMatrixInverse · boneMatrix · bindMatrix · v
|
|
6701
|
+
*
|
|
6702
|
+
* and on a mixamo rig those terms are not decoration: the armature carries a
|
|
6703
|
+
* 0.01 node scale that lives in one of them and the 100 cancelling it lives in
|
|
6704
|
+
* another. Measuring the geometry box through `matrixWorld` alone — the obvious
|
|
6705
|
+
* thing, and what this did for four releases — reported the character a HUNDRED
|
|
6706
|
+
* times too small, tripped the plausibility guard, and silently threw away
|
|
6707
|
+
* `targetHeight` on every skinned character in four shipped templates.
|
|
6708
|
+
*
|
|
6709
|
+
* Every cheaper proxy is wrong too, and by enough to see: on the same character
|
|
6710
|
+
* the joint positions measure 1.49 and the bind-pose geometry box 1.50 where
|
|
6711
|
+
* the renderer draws 1.66. So skinned meshes are measured the way three itself
|
|
6712
|
+
* measures them — `getVertexPosition`, which walks each vertex through its bone
|
|
6713
|
+
* transforms. Fitting to that gave 1.7000 for a `targetHeight` of 1.7 and
|
|
6714
|
+
* 2.5001 for 2.5.
|
|
6715
|
+
*
|
|
6716
|
+
* Rigid meshes keep their bounding box: it is exact for them and free.
|
|
6570
6717
|
*/
|
|
6571
|
-
function
|
|
6572
|
-
root.
|
|
6718
|
+
function renderedBox(root) {
|
|
6719
|
+
root.updateMatrixWorld(true);
|
|
6573
6720
|
const box = new Box3();
|
|
6574
6721
|
const tmp = new Box3();
|
|
6575
|
-
const invRoot = root.matrixWorld.clone().invert();
|
|
6576
|
-
const m4 = new Matrix4();
|
|
6577
6722
|
const v = new Vector3();
|
|
6723
|
+
const invRoot = root.matrixWorld.clone().invert();
|
|
6578
6724
|
root.traverse((o) => {
|
|
6579
|
-
const skinned = o;
|
|
6580
|
-
if (skinned.isSkinnedMesh && skinned.skeleton) {
|
|
6581
|
-
for (const inverse of skinned.skeleton.boneInverses) {
|
|
6582
|
-
m4.copy(inverse).invert().premultiply(skinned.matrixWorld).premultiply(invRoot);
|
|
6583
|
-
v.setFromMatrixPosition(m4);
|
|
6584
|
-
box.expandByPoint(v);
|
|
6585
|
-
}
|
|
6586
|
-
return;
|
|
6587
|
-
}
|
|
6588
6725
|
const mesh = o;
|
|
6589
|
-
if (mesh.isMesh
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6726
|
+
if (!mesh.isMesh || !mesh.geometry) return;
|
|
6727
|
+
const position = mesh.geometry.getAttribute("position");
|
|
6728
|
+
if (mesh.isSkinnedMesh && typeof mesh.getVertexPosition === "function" && position && mesh.geometry.getAttribute("skinIndex") && mesh.geometry.getAttribute("skinWeight") && position) {
|
|
6729
|
+
for (let i = 0; i < position.count; i++) {
|
|
6730
|
+
mesh.getVertexPosition?.(i, v);
|
|
6731
|
+
box.expandByPoint(v.applyMatrix4(mesh.matrixWorld).applyMatrix4(invRoot));
|
|
6594
6732
|
}
|
|
6733
|
+
return;
|
|
6595
6734
|
}
|
|
6735
|
+
mesh.geometry.computeBoundingBox();
|
|
6736
|
+
if (mesh.geometry.boundingBox) box.union(tmp.copy(mesh.geometry.boundingBox).applyMatrix4(mesh.matrixWorld).applyMatrix4(invRoot));
|
|
6596
6737
|
});
|
|
6597
6738
|
return box;
|
|
6598
6739
|
}
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { n as jsonEquals, r as jsonKind, t as jsonClone } from "./json-BLk7H2Qa.
|
|
|
7
7
|
import { a as getNodeSignals, c as mergeStaticSignals, i as getNodeSchema, l as registerNode, n as clearRegistry, o as getNodeType, r as createNode, u as registeredTypes } from "./registry-IyWCGe4q.js";
|
|
8
8
|
import { t as createNoise2D } from "./noise-CGUMx44x.js";
|
|
9
9
|
import { i as applyParticlePreset, n as PARTICLE_PRESETS, r as PARTICLE_PRESET_NAMES, t as ParticleSim } from "./particle-sim-Bw7hB93B.js";
|
|
10
|
-
import { a as findPath, i as preloadUrls, n as newUid, o as gridFromRows, r as assetUrls, t as VERSION } from "./src-
|
|
10
|
+
import { a as findPath, i as preloadUrls, n as newUid, o as gridFromRows, r as assetUrls, t as VERSION } from "./src-DUxGnvq3.js";
|
|
11
11
|
import { i as resolveRendering, n as attachTouchControls, r as joystickVector, t as TouchControls } from "./touch-BoNg_MnF.js";
|
|
12
12
|
import { t as duplicateNode } from "./duplicate-CRtihGmC.js";
|
|
13
13
|
export { AudioBuses, AudioPlayer, BASE_LOCALE, Behavior, CONST_REF_KEY, Engine, HudLayer, IncantoError, InputMap, Localization, LogManager, MusicManager, Node, ORDER_GROUP_BASE, PARTICLE_PRESETS, PARTICLE_PRESET_NAMES, ParticleSim, ROLLOFF_MODELS, Rng, SCENE_FORMAT, SFX_PRESETS, SFX_PRESET_NAMES, SaveSlots, Scene, SceneTree, Settings, SfxEngine, Signal, T_PREFIX, Timer, TouchControls, UiBanner, UiBar, UiButton, UiDialogue, UiImage, UiPanel, UiSelect, UiSlider, UiText, UiToggle, VERSION, WebAudioMusicBackend, applyParticlePreset, assetUrls, attachTouchControls, auditScene, behaviorSchema, behaviorSignals, behaviorsWithoutSave, captureBehaviors, clearBehaviors, clearRegistry, computeViewport, createNode, createNoise2D, createSaveStore, crossfadeGains, duplicateNode, effectiveOrder, fadeGain, findPath, getBehavior, getNodeSchema, getNodeSignals, getNodeType, gridFromRows, isAudioContextAvailable, isConstRef, joystickVector, jsonClone, jsonEquals, jsonKind, loadScene, mergeStaticSignals, newUid, parseNodePath, preloadUrls, qualityEnvironment, readDeviceHints, registerBehavior, registerCoreNodes, registerNode, registeredBehaviors, registeredTypes, replay, resolveConstants, resolveOrderGroups, resolveRendering, resolveViewport, restoreBehaviors, serializeNode, spatialGain, spatialPan, startRecording, suggestLocale, suggestQuality, synthSfx, translationKey };
|
|
@@ -3,7 +3,7 @@ import { v as diagnose } from "./loader-r49nDwB4.js";
|
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
4
|
import { F as PhysicsBody3D, I as RigidBody3D, N as Area3D, P as CharacterBody3D, R as Node3D, z as validateCollider3D } from "./gameplay-BQOeAid6.js";
|
|
5
5
|
import { n as registerDebugSource } from "./debug-draw-BM3DsvtT.js";
|
|
6
|
-
import { A as Terrain3D, F as InstancedMesh3D, L as buildMeshGeometry, P as Joint3D } from "./environment-presets-
|
|
6
|
+
import { A as Terrain3D, F as InstancedMesh3D, L as buildMeshGeometry, P as Joint3D } from "./environment-presets-DUsBqvtk.js";
|
|
7
7
|
import { Euler, Matrix4, Quaternion, Vector3 } from "three";
|
|
8
8
|
//#region src/3d/physics/collider-lines.ts
|
|
9
9
|
/**
|
package/dist/react.js
CHANGED
|
@@ -156,7 +156,7 @@ function IncantoCanvas(props) {
|
|
|
156
156
|
pointer: latest.pointer,
|
|
157
157
|
...keyboard !== void 0 ? { keyboard } : {}
|
|
158
158
|
};
|
|
159
|
-
const next = await (_gameFactory ?? (mode === "3d" ? async (o) => (await import("./create-game-
|
|
159
|
+
const next = await (_gameFactory ?? (mode === "3d" ? async (o) => (await import("./create-game-Gifrjhnz.js").then((n) => n.n)).createGame3D(o) : async (o) => (await import("./create-game-DFRbG0Bj.js").then((n) => n.n)).createGame2D(o)))(opts);
|
|
160
160
|
if (disposed) {
|
|
161
161
|
next.dispose();
|
|
162
162
|
return;
|
|
@@ -161,6 +161,6 @@ function newUid() {
|
|
|
161
161
|
//#endregion
|
|
162
162
|
//#region src/index.ts
|
|
163
163
|
/** Engine version. Kept in sync with package.json by the release pipeline. */
|
|
164
|
-
const VERSION = "0.
|
|
164
|
+
const VERSION = "0.45.1";
|
|
165
165
|
//#endregion
|
|
166
166
|
export { findPath as a, preloadUrls as i, newUid as n, gridFromRows as o, assetUrls as r, VERSION as t };
|
|
@@ -6,7 +6,7 @@ import { n as jsonEquals, t as jsonClone } from "./json-BLk7H2Qa.js";
|
|
|
6
6
|
import { i as getNodeSchema, s as mergeStaticProps } from "./registry-IyWCGe4q.js";
|
|
7
7
|
import { n as registerGameplayBehaviors } from "./gameplay-BQOeAid6.js";
|
|
8
8
|
import { t as registerNodes2D } from "./register-R2JTnIMw.js";
|
|
9
|
-
import { n as registerNodes3D, t as resolveEnvironmentHdri } from "./environment-presets-
|
|
9
|
+
import { n as registerNodes3D, t as resolveEnvironmentHdri } from "./environment-presets-DUsBqvtk.js";
|
|
10
10
|
import { t as registerNodesNet } from "./register-D651it1J.js";
|
|
11
11
|
import { Box3, Euler, Matrix4, PerspectiveCamera, Quaternion, Vector3 } from "three";
|
|
12
12
|
//#region src/test/framing.ts
|
|
@@ -1370,7 +1370,7 @@ async function runScript(json, opts) {
|
|
|
1370
1370
|
const { enablePhysics2D } = await import("./physics-2d-BmgXBNDB.js").then((n) => n.r);
|
|
1371
1371
|
await enablePhysics2D(engine);
|
|
1372
1372
|
} else if (physics === "3d" || physics === "auto" && scene.dimension === "3d") {
|
|
1373
|
-
const { enablePhysics3D } = await import("./physics-3d-
|
|
1373
|
+
const { enablePhysics3D } = await import("./physics-3d-DFqMtBUD.js").then((n) => n.r);
|
|
1374
1374
|
await enablePhysics3D(engine);
|
|
1375
1375
|
}
|
|
1376
1376
|
const failures = [];
|
|
@@ -1486,7 +1486,7 @@ async function createPlaySession(json, opts = {}) {
|
|
|
1486
1486
|
const { enablePhysics2D } = await import("./physics-2d-BmgXBNDB.js").then((n) => n.r);
|
|
1487
1487
|
await enablePhysics2D(engine);
|
|
1488
1488
|
} else if (physics === "3d" || physics === "auto" && scene.dimension === "3d") {
|
|
1489
|
-
const { enablePhysics3D } = await import("./physics-3d-
|
|
1489
|
+
const { enablePhysics3D } = await import("./physics-3d-DFqMtBUD.js").then((n) => n.r);
|
|
1490
1490
|
await enablePhysics3D(engine);
|
|
1491
1491
|
}
|
|
1492
1492
|
const stepMs = 1e3 / (opts.fixedHz ?? 60);
|