incanto 0.65.0 → 0.67.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/_behaviors-loader.mjs +87 -0
- package/bin/incanto-editor.mjs +39 -2
- package/bin/incanto-feel.mjs +4 -1
- package/bin/incanto-frame.mjs +52 -3
- package/bin/incanto-logs.mjs +33 -3
- package/bin/incanto-multiplay.mjs +50 -1
- package/bin/incanto-play.mjs +3 -1
- package/bin/incanto-playtest.mjs +3 -25
- package/bin/incanto-verify.mjs +15 -2
- package/dist/2d.d.ts +76 -4
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +213 -14
- package/dist/3d.js +6 -6
- package/dist/{audio-player-BrEHwbK1.d.ts → audio-player-BNUHo0JF.d.ts} +1 -1
- package/dist/{behavior-CmMuQ6CL.d.ts → behavior-ZnfzKDo3.d.ts} +58 -1
- package/dist/{create-game-DIyh5Zy9.js → create-game-DMetd3vR.js} +14 -8
- package/dist/{create-game-W2xzTJhs.js → create-game-FAXdHta3.js} +138 -11
- package/dist/debug.d.ts +1 -1
- package/dist/debug.js +3 -2
- package/dist/{duplicate-CqSAtdrh.js → duplicate-B8QnX2-r.js} +1 -1
- package/dist/editor.js +7 -2
- package/dist/{environment-presets-BvHs6HEk.js → environment-presets-C-5g2pMh.js} +113 -9
- package/dist/{gameplay-D-H986A4.js → gameplay-CGSv-9XR.js} +295 -12
- package/dist/gameplay.d.ts +102 -6
- package/dist/gameplay.js +2 -2
- package/dist/index.d.ts +50 -6
- package/dist/index.js +7 -6
- package/dist/{loader-CTB441z4.d.ts → loader-DyT30ArB.d.ts} +1 -1
- package/dist/{loader-lQDCwNag.js → loader-KZESOZmE.js} +148 -1
- package/dist/net.d.ts +2 -2
- package/dist/net.js +1 -1
- package/dist/{physics-2d-CmnunaR2.js → physics-2d-_B6zj3zU.js} +57 -4
- package/dist/{physics-3d-DULB1lD1.js → physics-3d-i1IeAY0F.js} +74 -5
- package/dist/{quiet-rapier-BAJ4K94N.js → quiet-rapier-C6fW4zcW.js} +14 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-CgeR4ckF.js → register-Cs53CY7s.js} +110 -16
- package/dist/{register-DO5_Qp0Q.js → register-vIxU3Xbv.js} +38 -4
- package/dist/rendering-options-ByAdi8PF.js +184 -0
- package/dist/{replay-CEw2xAhG.js → replay-BkpDV51O.js} +4 -3
- package/dist/{replay-CThvwkcQ.d.ts → replay-D0GcEHYU.d.ts} +1 -1
- package/dist/{split-screen-DxZzC1nm.d.ts → split-screen-DD5eYIgW.d.ts} +2 -2
- package/dist/{split-screen-gb0c3xdb.js → split-screen-DS8RaUV_.js} +2 -2
- package/dist/{src-DYffzHbd.js → src-BLlsGJW9.js} +1 -1
- package/dist/{teardown-BordHL9o.js → teardown-LB9cTnXJ.js} +2 -2
- package/dist/{test-CXZuXs8k.js → test-81uZ967a.js} +127 -24
- package/dist/test.d.ts +7 -5
- package/dist/test.js +2 -2
- package/dist/{touch-DESwnpOc.js → touch-DEAmqGdf.js} +30 -186
- package/dist/vite.d.ts +0 -7
- package/dist/vite.js +13 -3
- package/editor/assets/{agent8-DO5qzIOD.js → agent8-C2jtNKbx.js} +1 -1
- package/editor/assets/debug-DoU3KeqS.js +3 -0
- package/editor/assets/{index-CqEUVaPN.js → index-CNqHojcC.js} +92 -92
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +20 -1
- package/skills/incanto-building-3d-games.md +19 -0
- package/skills/incanto-editor.md +5 -1
- package/skills/incanto-environment.md +2 -2
- package/skills/incanto-gameplay-behaviors.md +86 -7
- package/skills/incanto-hud.md +14 -1
- package/skills/incanto-multiplayer.md +14 -0
- package/skills/incanto-node-reference.md +60 -2
- package/skills/incanto-performance.md +35 -0
- package/skills/incanto-physics-and-input.md +69 -0
- package/skills/incanto-playtesting.md +15 -1
- package/skills/incanto-save-slots.md +21 -1
- package/skills/incanto-verifying-your-game.md +19 -0
- package/skills/incanto-web-integration.md +24 -3
- package/skills/incanto-your-first-game.md +4 -4
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/beacon-isle-3d/src/game.scene.json +38 -19
- package/templates-app/platformer-2d/package.json +1 -1
- package/templates-app/platformer-2d/src/game.scene.json +99 -53
- package/templates-app/star-survivor/package.json +1 -1
- package/templates-app/star-survivor/src/game.scene.json +31 -17
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/tps-3d/src/game.scene.json +14 -8
- package/templates-app/village-quest-3d/package.json +1 -1
- package/templates-app/village-quest-3d/src/grove.scene.json +20 -11
- package/templates-app/village-quest-3d/src/village.scene.json +10 -7
- package/editor/assets/debug-DntG9CVD.js +0 -3
- package/templates-app/beacon-isle-3d/coverage.json +0 -9
- package/templates-app/platformer-2d/coverage.json +0 -5
- package/templates-app/star-survivor/coverage.json +0 -5
- package/templates-app/tps-3d/coverage.json +0 -5
- package/templates-app/village-quest-3d/coverage.json +0 -9
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import { c as parseEnvironment3D, k as diagnose, n as loadScene, s as horizonColorFromSky, u as sunDirectionFromSky, z as registerBehavior } from "./loader-
|
|
3
|
-
import { C as qualityRendering, _ as AudioPlayer, v as Engine, x as qualityCaps } from "./register-
|
|
2
|
+
import { c as parseEnvironment3D, k as diagnose, n as loadScene, s as horizonColorFromSky, u as sunDirectionFromSky, z as registerBehavior } from "./loader-KZESOZmE.js";
|
|
3
|
+
import { C as qualityRendering, _ as AudioPlayer, v as Engine, x as qualityCaps } from "./register-Cs53CY7s.js";
|
|
4
4
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { n as attachTouchControls } from "./touch-DEAmqGdf.js";
|
|
6
|
+
import { t as resolveRendering } from "./rendering-options-ByAdi8PF.js";
|
|
7
|
+
import { a as openBundledEditor, c as claimCanvasGestures, i as devServerLibrary, l as audioErrors, n as pauseWhenHidden, o as poseFromRenderer, r as crossFade, s as wireDevChannel, t as teardown } from "./teardown-LB9cTnXJ.js";
|
|
7
8
|
import { o as frameStats } from "./frame-report-BSMny7oe.js";
|
|
8
|
-
import {
|
|
9
|
+
import { J as createCausticsQuad, K as Node3D, U as PhysicsBody3D, n as registerGameplayBehaviors } from "./gameplay-CGSv-9XR.js";
|
|
9
10
|
import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
|
|
10
|
-
import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-
|
|
11
|
-
import { n as enablePhysics3D } from "./physics-3d-
|
|
11
|
+
import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-C-5g2pMh.js";
|
|
12
|
+
import { n as enablePhysics3D } from "./physics-3d-i1IeAY0F.js";
|
|
12
13
|
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
14
|
import { VRMLoaderPlugin, VRMUtils } from "@pixiv/three-vrm";
|
|
14
15
|
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
|
|
@@ -27,6 +28,31 @@ import { Sky } from "three/examples/jsm/objects/Sky.js";
|
|
|
27
28
|
*/
|
|
28
29
|
var AssetStore3D = class {
|
|
29
30
|
engine;
|
|
31
|
+
/**
|
|
32
|
+
* One geometry and one material per distinct SHAPE and per distinct look.
|
|
33
|
+
*
|
|
34
|
+
* `MeshInstance3D._createObject3D` used to `new BoxGeometry()` and
|
|
35
|
+
* `new MeshPhysicalMaterial()` for every node, even when byte-identical.
|
|
36
|
+
* Three identical nodes reported `geometry shared? false false / material
|
|
37
|
+
* shared? false false`, with distinct uuids. Measured at 3,200 units, all
|
|
38
|
+
* three runs at identical 3,209 draw calls / 1,741,932 triangles and an
|
|
39
|
+
* identical screenshot:
|
|
40
|
+
*
|
|
41
|
+
* ```
|
|
42
|
+
* per-node geometry + material 31.0 ms wall (renderMs 27.3)
|
|
43
|
+
* share one geometry 27.0 ms
|
|
44
|
+
* + share two materials 15.4 ms <- 2x the headroom
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* 13.1 ms of that 26.5 ms cliff was GPU state churn from per-node objects,
|
|
48
|
+
* and none of it was visible headlessly: with no renderer `_syncObject3D`
|
|
49
|
+
* never runs, so the bench measured 55 ns/node instead of ~2,000.
|
|
50
|
+
*
|
|
51
|
+
* Renderer-scoped, deliberately — module-level state is the predecessor's
|
|
52
|
+
* fatal flaw and two games in one page must not share a cache.
|
|
53
|
+
*/
|
|
54
|
+
meshGeometries = /* @__PURE__ */ new Map();
|
|
55
|
+
meshMaterials = /* @__PURE__ */ new Map();
|
|
30
56
|
models = /* @__PURE__ */ new Map();
|
|
31
57
|
animations = /* @__PURE__ */ new Map();
|
|
32
58
|
modelKeys = /* @__PURE__ */ new Map();
|
|
@@ -253,10 +279,27 @@ function yieldToFrame(maxWaitMs = DEFAULT_MAX_WAIT_MS, raf = typeof requestAnima
|
|
|
253
279
|
* - hard-validates the merged result NOW (in your call stack), so a bad patch
|
|
254
280
|
* throws where you wrote it — never inside the render loop
|
|
255
281
|
*/
|
|
256
|
-
|
|
282
|
+
/**
|
|
283
|
+
* The environment stages a quality tier is allowed to touch.
|
|
284
|
+
*
|
|
285
|
+
* These are the ones `qualityEnvironment` names, and the ones that must snap
|
|
286
|
+
* back to what the scene file says rather than accumulating.
|
|
287
|
+
*/
|
|
288
|
+
const TIER_KEYS = [
|
|
289
|
+
"shadows",
|
|
290
|
+
"bloom",
|
|
291
|
+
"post",
|
|
292
|
+
"clouds"
|
|
293
|
+
];
|
|
294
|
+
function setEnvironment3D(engine, patch, opts) {
|
|
257
295
|
const scene = engine.scene;
|
|
258
296
|
if (!scene) throw new IncantoError("BAD_FORMAT", "setEnvironment3D: the engine has no scene.");
|
|
259
297
|
const merged = { ...scene.environment ?? {} };
|
|
298
|
+
if (opts?.rebaseTierKeys) {
|
|
299
|
+
const authored = scene.source?.environment ?? {};
|
|
300
|
+
for (const key of TIER_KEYS) if (key in authored) merged[key] = authored[key];
|
|
301
|
+
else delete merged[key];
|
|
302
|
+
}
|
|
260
303
|
for (const [key, value] of Object.entries(patch)) if (value === null) delete merged[key];
|
|
261
304
|
else if (typeof value === "object" && !Array.isArray(value) && typeof merged[key] === "object" && merged[key] !== null && !Array.isArray(merged[key])) merged[key] = {
|
|
262
305
|
...merged[key],
|
|
@@ -266,6 +309,24 @@ function setEnvironment3D(engine, patch) {
|
|
|
266
309
|
parseEnvironment3D(merged);
|
|
267
310
|
scene.environment = merged;
|
|
268
311
|
}
|
|
312
|
+
/**
|
|
313
|
+
* Apply a quality tier — the only caller that may RESET as well as patch.
|
|
314
|
+
*
|
|
315
|
+
* A tier is re-applied every time the player moves the slider, so it cannot
|
|
316
|
+
* compose with what the last one left behind: `low` strips the author's bloom,
|
|
317
|
+
* and `high` then has nothing to put back. This re-derives the four tier-owned
|
|
318
|
+
* stages from the scene FILE first, so every tier is reversible, and so a stage
|
|
319
|
+
* the author never wrote can never appear — the contract `settings.ts` states
|
|
320
|
+
* and `incanto-performance.md` promises: *the tier can only take things away.*
|
|
321
|
+
*
|
|
322
|
+
* Measured before this, on a scene with no `bloom` and no `post` in its JSON:
|
|
323
|
+
* `high` and `medium` both rendered five GL passes at 3.3 ms where `low`
|
|
324
|
+
* rendered one at 1.24 ms — 62% of the frame on a chain the game never asked
|
|
325
|
+
* for, and `environment.bloom` read back `{strength: 0.8, threshold: 1}`.
|
|
326
|
+
*/
|
|
327
|
+
function applyQualityTier3D(engine, patch) {
|
|
328
|
+
setEnvironment3D(engine, patch, { rebaseTierKeys: true });
|
|
329
|
+
}
|
|
269
330
|
//#endregion
|
|
270
331
|
//#region src/3d/adaptive-resolution.ts
|
|
271
332
|
const DEFAULTS = {
|
|
@@ -1967,6 +2028,67 @@ var Renderer3D = class {
|
|
|
1967
2028
|
};
|
|
1968
2029
|
}
|
|
1969
2030
|
/**
|
|
2031
|
+
* The WORLD POINT under canvas pixel (sx, sy) — the other half of
|
|
2032
|
+
* `screenFromWorld`, and the call `incanto-web-integration.md` has always
|
|
2033
|
+
* offered "for taps and clicks".
|
|
2034
|
+
*
|
|
2035
|
+
* It did not exist in 3D. `Renderer2D` has had it since the beginning, the
|
|
2036
|
+
* doc covers both runtimes, and an agent building a tower defense went looking
|
|
2037
|
+
* for it and measured `typeof game.renderer.worldFromScreen === "undefined"`.
|
|
2038
|
+
* `pick()` gives you the NODE under a pixel but never the POINT, so "put the
|
|
2039
|
+
* thing where the player clicked on the ground" was not expressible and that
|
|
2040
|
+
* game discretised its whole map into clickable pads instead.
|
|
2041
|
+
*
|
|
2042
|
+
* A pixel in 3D is a RAY, not a point, so this needs a surface to land on and
|
|
2043
|
+
* takes the horizontal plane at `planeY` (default 0 — the ground). Returns
|
|
2044
|
+
* null when the ray runs parallel to that plane or would only meet it behind
|
|
2045
|
+
* the camera, which is what "the sky" looks like from here.
|
|
2046
|
+
*
|
|
2047
|
+
* For anything not flat — terrain, a hillside, a stack of crates — raycast
|
|
2048
|
+
* physics instead: `rayFromScreen` gives you the origin and direction to feed
|
|
2049
|
+
* `physics.castRay`.
|
|
2050
|
+
*/
|
|
2051
|
+
worldFromScreen(sx, sy, planeY = 0) {
|
|
2052
|
+
const ray = this.rayFromScreen(sx, sy);
|
|
2053
|
+
if (!ray) return null;
|
|
2054
|
+
const dy = ray.dir[1];
|
|
2055
|
+
if (Math.abs(dy) < 1e-6) return null;
|
|
2056
|
+
const t = (planeY - ray.origin[1]) / dy;
|
|
2057
|
+
if (t < 0) return null;
|
|
2058
|
+
return {
|
|
2059
|
+
x: ray.origin[0] + ray.dir[0] * t,
|
|
2060
|
+
y: planeY,
|
|
2061
|
+
z: ray.origin[2] + ray.dir[2] * t
|
|
2062
|
+
};
|
|
2063
|
+
}
|
|
2064
|
+
/**
|
|
2065
|
+
* The camera ray through canvas pixel (sx, sy) — origin and unit direction,
|
|
2066
|
+
* ready for `physics.castRay(origin, dir, maxLen)`.
|
|
2067
|
+
*
|
|
2068
|
+
* This is the honest 3D answer to "where did the player click": on uneven
|
|
2069
|
+
* ground the only thing that knows is the collision world.
|
|
2070
|
+
*/
|
|
2071
|
+
rayFromScreen(sx, sy) {
|
|
2072
|
+
const cam = this.lastCamera;
|
|
2073
|
+
if (!cam) return null;
|
|
2074
|
+
pickNdc.set(sx / this.lastSize.w * 2 - 1, -(sy / this.lastSize.h * 2 - 1));
|
|
2075
|
+
pickRaycaster.setFromCamera(pickNdc, cam);
|
|
2076
|
+
const o = pickRaycaster.ray.origin;
|
|
2077
|
+
const d = pickRaycaster.ray.direction;
|
|
2078
|
+
return {
|
|
2079
|
+
origin: [
|
|
2080
|
+
o.x,
|
|
2081
|
+
o.y,
|
|
2082
|
+
o.z
|
|
2083
|
+
],
|
|
2084
|
+
dir: [
|
|
2085
|
+
d.x,
|
|
2086
|
+
d.y,
|
|
2087
|
+
d.z
|
|
2088
|
+
]
|
|
2089
|
+
};
|
|
2090
|
+
}
|
|
2091
|
+
/**
|
|
1970
2092
|
* The node rendered under canvas pixel (sx, sy), or null — raycasts the last
|
|
1971
2093
|
* rendered camera into the scene and resolves the hit up to its `incantoNode`
|
|
1972
2094
|
* (every Node3D stamps that in `_ensureObject3D`). 3D depth-sorts, so the
|
|
@@ -2119,6 +2241,7 @@ async function createGame3D(opts) {
|
|
|
2119
2241
|
const engine = new Engine({
|
|
2120
2242
|
seed: opts.seed,
|
|
2121
2243
|
fixedHz: opts.fixedHz,
|
|
2244
|
+
...opts.settings ? { settings: opts.settings } : {},
|
|
2122
2245
|
...opts._scheduler ? { scheduler: opts._scheduler } : {}
|
|
2123
2246
|
});
|
|
2124
2247
|
const sourceJson = cloneSceneJson(opts.scene);
|
|
@@ -2233,7 +2356,7 @@ async function createGame3D(opts) {
|
|
|
2233
2356
|
cleanups.push(engine.settings.bindAudio(engine.audio));
|
|
2234
2357
|
cleanups.push(engine.settings.bindLocale(engine.locale));
|
|
2235
2358
|
cleanups.push(engine.settings.bindQuality((patch) => {
|
|
2236
|
-
|
|
2359
|
+
applyQualityTier3D(engine, patch);
|
|
2237
2360
|
}));
|
|
2238
2361
|
cleanups.push(engine.settings.bindFrameCap((fps) => {
|
|
2239
2362
|
engine.maxFps = fps;
|
|
@@ -2307,7 +2430,11 @@ async function createGame3D(opts) {
|
|
|
2307
2430
|
}
|
|
2308
2431
|
return {
|
|
2309
2432
|
engine,
|
|
2310
|
-
scene
|
|
2433
|
+
get scene() {
|
|
2434
|
+
const live = engine.scene;
|
|
2435
|
+
if (!live) throw new IncantoError("TREE_VIOLATION", "game.scene: the engine has no scene.");
|
|
2436
|
+
return live;
|
|
2437
|
+
},
|
|
2311
2438
|
sourceJson,
|
|
2312
2439
|
renderer,
|
|
2313
2440
|
physics,
|
|
@@ -2393,4 +2520,4 @@ function wireAudioUnlock(engine, root, canvas) {
|
|
|
2393
2520
|
return detachAll;
|
|
2394
2521
|
}
|
|
2395
2522
|
//#endregion
|
|
2396
|
-
export { Environment3D as a, syncTree as i, create_game_exports as n,
|
|
2523
|
+
export { Environment3D as a, AssetStore3D as c, syncTree as i, create_game_exports as n, applyQualityTier3D as o, Renderer3D as r, setEnvironment3D as s, createGame3D as t };
|
package/dist/debug.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ft as LogLevel, T as RendererStats, b as Engine } from "./behavior-
|
|
1
|
+
import { Ft as LogLevel, T as RendererStats, b as Engine } from "./behavior-ZnfzKDo3.js";
|
|
2
2
|
|
|
3
3
|
//#region src/debug/panel.d.ts
|
|
4
4
|
/** Minimal document surface the overlay needs (injectable for tests). */
|
package/dist/debug.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { t as jsonClone } from "./json-CwwhxQgb.js";
|
|
2
2
|
import { s as mergeStaticProps } from "./registry-CF70EArN.js";
|
|
3
|
+
import { r as capturePointer } from "./touch-DEAmqGdf.js";
|
|
3
4
|
import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
|
|
4
5
|
//#region src/debug/capture.ts
|
|
5
6
|
/**
|
|
@@ -369,7 +370,7 @@ var FloatingPanel = class {
|
|
|
369
370
|
active = e.pointerId;
|
|
370
371
|
lastX = e.clientX;
|
|
371
372
|
lastY = e.clientY;
|
|
372
|
-
grip
|
|
373
|
+
capturePointer(grip, e.pointerId);
|
|
373
374
|
});
|
|
374
375
|
grip.addEventListener("pointermove", (e) => {
|
|
375
376
|
if (e.pointerId !== active) return;
|
|
@@ -565,7 +566,7 @@ function openRegionSelect(opts) {
|
|
|
565
566
|
applyStyle(popup, { display: "none" });
|
|
566
567
|
applyStyle(box, { cursor: next === "move" ? "grabbing" : "crosshair" });
|
|
567
568
|
const id = event.pointerId;
|
|
568
|
-
if (id !== void 0) layer
|
|
569
|
+
if (id !== void 0) capturePointer(layer, id);
|
|
569
570
|
render();
|
|
570
571
|
}
|
|
571
572
|
function render() {
|
package/dist/editor.js
CHANGED
|
@@ -2380,7 +2380,8 @@ var Vn = [
|
|
|
2380
2380
|
"connections",
|
|
2381
2381
|
"input",
|
|
2382
2382
|
"multiplayer",
|
|
2383
|
-
"strings"
|
|
2383
|
+
"strings",
|
|
2384
|
+
"environment"
|
|
2384
2385
|
];
|
|
2385
2386
|
function Hn(e, t, n) {
|
|
2386
2387
|
e.appendChild(Tr("scene")), e.appendChild(Ar("name", String(t.working.name ?? ""), (e) => {
|
|
@@ -7842,6 +7843,10 @@ var ss = class {
|
|
|
7842
7843
|
return !0;
|
|
7843
7844
|
}) === !0;
|
|
7844
7845
|
}
|
|
7846
|
+
resume(e) {
|
|
7847
|
+
let t = this.original;
|
|
7848
|
+
this.reset(e), this.original = t;
|
|
7849
|
+
}
|
|
7845
7850
|
reset(e) {
|
|
7846
7851
|
this.working = e, this.working.root && cs(this.working.root), this.original = JSON.stringify(this.working), this.undoStack = [], this.selection = [], this.emit();
|
|
7847
7852
|
}
|
|
@@ -9794,7 +9799,7 @@ async function xc(e = {}) {
|
|
|
9794
9799
|
let t = e.target.matches("input, textarea, select");
|
|
9795
9800
|
(e.metaKey || e.ctrlKey) && e.key === "z" ? (e.preventDefault(), u.undo()) : (e.metaKey || e.ctrlKey) && e.key === "s" ? (e.preventDefault(), p.disabled || p.click()) : !t && e.code === "KeyF" ? P.zoomToFit() : !t && (e.code === "Digit0" || e.code === "Numpad0") ? P.gameView() : !t && e.code === "KeyW" ? P.setMode("move") : !t && e.code === "KeyE" ? P.setMode("rotate") : !t && e.code === "KeyR" && P.setMode("scale");
|
|
9796
9801
|
};
|
|
9797
|
-
return window.addEventListener("keydown", Me), n.push(() => window.removeEventListener("keydown", Me)), F(), e.camera && P.setEditCamera(e.camera.position, e.camera.target), kt.ready(C, w, o.version), {
|
|
9802
|
+
return window.addEventListener("keydown", Me), n.push(() => window.removeEventListener("keydown", Me)), F(), e.scene && u.resume(e.scene), e.camera && P.setEditCamera(e.camera.position, e.camera.target), kt.ready(C, w, o.version), {
|
|
9798
9803
|
working: () => u.working,
|
|
9799
9804
|
camera: () => P.editCamera(),
|
|
9800
9805
|
showError: O,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { k as diagnose } from "./loader-
|
|
2
|
-
import { L as translateOn, t as registerCoreNodes } from "./register-
|
|
1
|
+
import { k as diagnose } from "./loader-KZESOZmE.js";
|
|
2
|
+
import { L as translateOn, t as registerCoreNodes } from "./register-Cs53CY7s.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
4
|
import { t as Rng } from "./rng-DP-SR7eg.js";
|
|
5
5
|
import { i as getNodeSchema, l as registerNode } from "./registry-CF70EArN.js";
|
|
6
6
|
import { t as createNoise2D } from "./noise-CGUMx44x.js";
|
|
7
7
|
import { i as ParticleSim, n as resolveFrames, o as PARTICLE_PRESET_NAMES, r as validateAnimationAliases, s as applyParticlePreset, t as resolveAnimation } from "./sprite-animation-CY-mrr1L.js";
|
|
8
|
-
import { B as
|
|
8
|
+
import { B as rejectScale, G as StaticBody3D, H as CharacterBody3D, K as Node3D, L as Water3D, U as PhysicsBody3D, V as Area3D, W as RigidBody3D, X as colliderFootDrop, w as tolerateUnknownAction, z as WaterCutout3D } from "./gameplay-CGSv-9XR.js";
|
|
9
9
|
import { t as checkSheetGrid } from "./sheet-grid-BT6N_Bjs.js";
|
|
10
10
|
import { n as splatWeights, t as buildHeightmap } from "./heightmap-CRK0M4jT.js";
|
|
11
11
|
import { AdditiveBlending, AnimationClip, AnimationMixer, Box3, BoxGeometry, BufferAttribute, BufferGeometry, CanvasTexture, CapsuleGeometry, ClampToEdgeWrapping, Color, ConeGeometry, CylinderGeometry, DataTexture, DirectionalLight, DoubleSide, DynamicDrawUsage, Euler, Group, IcosahedronGeometry, ImageBitmapLoader, InstancedBufferAttribute, InstancedMesh, LinearFilter, LinearMipmapLinearFilter, LoopOnce, LoopRepeat, Matrix4, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshPhysicalMaterial, MeshStandardMaterial, NearestFilter, NoBlending, NoColorSpace, NormalBlending, PerspectiveCamera, PlaneGeometry, PointLight, Points, PointsMaterial, Quaternion, QuaternionKeyframeTrack, RGBADepthPacking, RGBAFormat, RepeatWrapping, SRGBColorSpace, ShaderChunk, ShaderMaterial, SphereGeometry, Texture, TextureLoader, UniformsLib, UniformsUtils, Vector3, Vector4, VectorKeyframeTrack } from "three";
|
|
@@ -387,6 +387,10 @@ var MeshInstance3D = class extends Node3D {
|
|
|
387
387
|
validateMeshMaterial(node.material, node.name);
|
|
388
388
|
}
|
|
389
389
|
geometryKey = "";
|
|
390
|
+
materialKey = "";
|
|
391
|
+
/** True while this node is using a cache entry it must not dispose. */
|
|
392
|
+
sharedGeometry = false;
|
|
393
|
+
sharedMaterial = false;
|
|
390
394
|
textureKey = "";
|
|
391
395
|
loadedTextures = [];
|
|
392
396
|
_createObject3D() {
|
|
@@ -395,12 +399,48 @@ var MeshInstance3D = class extends Node3D {
|
|
|
395
399
|
_syncObject3D(alpha = 1, assets = null) {
|
|
396
400
|
super._syncObject3D(alpha, assets);
|
|
397
401
|
const m = this._ensureObject3D();
|
|
398
|
-
const key = `${this.mesh}:${
|
|
402
|
+
const key = `${this.mesh}:${this.size.join(",")}`;
|
|
399
403
|
if (key !== this.geometryKey) {
|
|
400
|
-
m.geometry.dispose();
|
|
401
|
-
|
|
404
|
+
if (!this.sharedGeometry) m.geometry.dispose();
|
|
405
|
+
const cached = assets?.meshGeometries.get(key);
|
|
406
|
+
if (cached) {
|
|
407
|
+
m.geometry = cached;
|
|
408
|
+
this.sharedGeometry = true;
|
|
409
|
+
} else {
|
|
410
|
+
const built = buildMeshGeometry(this.mesh, this.size);
|
|
411
|
+
m.geometry = built;
|
|
412
|
+
this.sharedGeometry = Boolean(assets);
|
|
413
|
+
assets?.meshGeometries.set(key, built);
|
|
414
|
+
}
|
|
402
415
|
this.geometryKey = key;
|
|
403
416
|
}
|
|
417
|
+
const look = JSON.stringify(this.material);
|
|
418
|
+
if (assets && look !== this.materialKey) {
|
|
419
|
+
const shared = assets.meshMaterials.get(look);
|
|
420
|
+
if (shared) {
|
|
421
|
+
if (!this.sharedMaterial) m.material.dispose();
|
|
422
|
+
m.material = shared;
|
|
423
|
+
this.sharedMaterial = true;
|
|
424
|
+
this.materialKey = look;
|
|
425
|
+
this.textureKey = "shared";
|
|
426
|
+
m.castShadow = this.castShadow;
|
|
427
|
+
m.receiveShadow = this.receiveShadow;
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
if (this.sharedMaterial) {
|
|
431
|
+
m.material = new MeshPhysicalMaterial();
|
|
432
|
+
this.sharedMaterial = false;
|
|
433
|
+
this.textureKey = "";
|
|
434
|
+
}
|
|
435
|
+
this.materialKey = look;
|
|
436
|
+
const mine = m.material;
|
|
437
|
+
applyMeshMaterial(mine, this.material);
|
|
438
|
+
this.syncTextures(mine, assets);
|
|
439
|
+
assets.meshMaterials.set(look, mine);
|
|
440
|
+
m.castShadow = this.castShadow;
|
|
441
|
+
m.receiveShadow = this.receiveShadow;
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
404
444
|
const mat = m.material;
|
|
405
445
|
applyMeshMaterial(mat, this.material);
|
|
406
446
|
this.syncTextures(mat, assets);
|
|
@@ -742,7 +782,8 @@ var Joint3D = class extends Node3D {
|
|
|
742
782
|
] },
|
|
743
783
|
length: { default: 0 },
|
|
744
784
|
stiffness: { default: 50 },
|
|
745
|
-
damping: { default: 5 }
|
|
785
|
+
damping: { default: 5 },
|
|
786
|
+
collide: { default: null }
|
|
746
787
|
};
|
|
747
788
|
type = "spherical";
|
|
748
789
|
target = "";
|
|
@@ -760,6 +801,31 @@ var Joint3D = class extends Node3D {
|
|
|
760
801
|
length = 0;
|
|
761
802
|
stiffness = 50;
|
|
762
803
|
damping = 5;
|
|
804
|
+
/**
|
|
805
|
+
* Do the two linked bodies still collide with EACH OTHER?
|
|
806
|
+
*
|
|
807
|
+
* `null` (default) decides from the joint type, because the two families want
|
|
808
|
+
* opposite answers:
|
|
809
|
+
*
|
|
810
|
+
* - **pivots** (`fixed`, `spherical`, `revolute`) → **off**. A hinge's bodies
|
|
811
|
+
* overlap at the pivot by construction, so the contact solver fights the
|
|
812
|
+
* joint and flings them. A puzzle builder's first hinge produced a bar that
|
|
813
|
+
* spun chaotically forever and threw a 40 kg box thirty metres, and they
|
|
814
|
+
* nearly filed "spherical joints inject energy":
|
|
815
|
+
*
|
|
816
|
+
* ```
|
|
817
|
+
* t= 0 Plank r=[0,0,0] Box [ 0.00, 5.50, 2.40]
|
|
818
|
+
* t=3000 Plank r=[-66,24,64] Box [-29.70, 0.40, -4.91]
|
|
819
|
+
* ```
|
|
820
|
+
*
|
|
821
|
+
* - **tethers** (`rope`, `spring`) → **on**. These anchor a thing to the world,
|
|
822
|
+
* and the thing has to rest on what it is tethered to. Defaulting these off
|
|
823
|
+
* drops a barrel roped to the floor straight through it — measured, in this
|
|
824
|
+
* repo's own conformance room.
|
|
825
|
+
*
|
|
826
|
+
* Set `true`/`false` to say it outright.
|
|
827
|
+
*/
|
|
828
|
+
collide = null;
|
|
763
829
|
onEnterTree() {
|
|
764
830
|
if (!(this.parent instanceof PhysicsBody3D)) throw new IncantoError("TREE_VIOLATION", `Joint3D '${this.name}' must be a child of a physics body (its body A); parent is '${this.parent?.name ?? "none"}'.`);
|
|
765
831
|
if (this.target === "") throw new IncantoError("BAD_FORMAT", `Joint3D '${this.name}' needs a "target" node path to the body it links to.`);
|
|
@@ -2641,6 +2707,7 @@ var CharacterController3D = class extends Node3D {
|
|
|
2641
2707
|
/** Gravity multiplier while falling — >1 is the "snappy" arc. */
|
|
2642
2708
|
fallGravity: { default: 2.5 },
|
|
2643
2709
|
floatHeight: { default: .01 },
|
|
2710
|
+
stepHeight: { default: .35 },
|
|
2644
2711
|
mouseLook: { default: true },
|
|
2645
2712
|
zoomMin: { default: 0 },
|
|
2646
2713
|
zoomMax: { default: 0 },
|
|
@@ -2673,6 +2740,25 @@ var CharacterController3D = class extends Node3D {
|
|
|
2673
2740
|
airControl = .2;
|
|
2674
2741
|
fallGravity = 2.5;
|
|
2675
2742
|
floatHeight = .01;
|
|
2743
|
+
/**
|
|
2744
|
+
* How high a step the PLAYER walks up without jumping (0 = off).
|
|
2745
|
+
*
|
|
2746
|
+
* The hover spring holds the capsule a fixed distance above whatever is
|
|
2747
|
+
* DIRECTLY below it, so a vertical face stopped the player dead at about
|
|
2748
|
+
* 0.2 m — while `CharacterBody3D.stepHeight` let every enemy climb 0.35 m.
|
|
2749
|
+
* The docs said the player did not need this ("it floats over small ledges
|
|
2750
|
+
* already"); it floats over 18 cm ones.
|
|
2751
|
+
*
|
|
2752
|
+
* This probes just AHEAD of the capsule in the direction of travel: if the
|
|
2753
|
+
* ground there is higher, but by no more than `stepHeight`, the spring aims
|
|
2754
|
+
* at THAT surface and lifts the character onto it. A wall taller than the
|
|
2755
|
+
* step is not a step and still stops you.
|
|
2756
|
+
*
|
|
2757
|
+
* Do not reach for `floatHeight` instead. It does raise the character over
|
|
2758
|
+
* ledges, and it silently makes it WEIGHTLESS: at `floatHeight: 0.28` a
|
|
2759
|
+
* 200 kg character does not move a seesaw a 70 kg crate tips.
|
|
2760
|
+
*/
|
|
2761
|
+
stepHeight = .35;
|
|
2676
2762
|
mouseLook = true;
|
|
2677
2763
|
zoomMin = 0;
|
|
2678
2764
|
zoomMax = 0;
|
|
@@ -2803,8 +2889,26 @@ var CharacterController3D = class extends Node3D {
|
|
|
2803
2889
|
0,
|
|
2804
2890
|
-vel[2] * DRAG_DAMPING * mass
|
|
2805
2891
|
]);
|
|
2806
|
-
|
|
2807
|
-
|
|
2892
|
+
let springToi = toi;
|
|
2893
|
+
if (this.stepHeight > 0 && moving && toi !== null && !this.jumping && (vel[1] ?? 0) <= .5) {
|
|
2894
|
+
const ahead = radius + .12;
|
|
2895
|
+
const probeTop = originY + this.stepHeight + .05;
|
|
2896
|
+
const stepHit = physics.castRay([
|
|
2897
|
+
pos[0] + mx * ahead,
|
|
2898
|
+
probeTop,
|
|
2899
|
+
pos[2] + mz * ahead
|
|
2900
|
+
], [
|
|
2901
|
+
0,
|
|
2902
|
+
-1,
|
|
2903
|
+
0
|
|
2904
|
+
], this.stepHeight + .05 + rayLen, body);
|
|
2905
|
+
if (stepHit) {
|
|
2906
|
+
const rise = probeTop - stepHit.distance - (originY - toi);
|
|
2907
|
+
if (rise > .02 && rise <= this.stepHeight + .02) springToi = toi - rise;
|
|
2908
|
+
}
|
|
2909
|
+
}
|
|
2910
|
+
if (springToi !== null && springToi < floatingDis * 2 && !this.jumping) {
|
|
2911
|
+
const spring = SPRING_K * (floatingDis - springToi) - vel[1] * SPRING_DAMPING;
|
|
2808
2912
|
body.applyImpulse([
|
|
2809
2913
|
0,
|
|
2810
2914
|
spring * mass,
|