incanto 0.55.0 → 0.57.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/incanto-verify.mjs +9 -2
- package/dist/2d.d.ts +59 -7
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +34 -4
- package/dist/3d.js +5 -5
- package/dist/{behavior-CyQoSu4n.d.ts → behavior-l08AEbq9.d.ts} +5 -0
- package/dist/{create-game-CzK9_pzg.js → create-game-C5jQYPah.js} +28 -71
- package/dist/{create-game-BRt6XKmP.js → create-game-DpbUrMOQ.js} +146 -7
- package/dist/debug.d.ts +1 -1
- package/dist/{duplicate-MNLMAcbz.js → duplicate-BPLZDZpd.js} +1 -1
- package/dist/{environment-presets-DAbEdEwh.js → environment-presets-CvvQr_bJ.js} +118 -24
- package/dist/{frame-report-njybhZon.js → frame-report-BSMny7oe.js} +1 -1
- package/dist/{frame-report-DZ70IY26.d.ts → frame-report-DCnHFmto.d.ts} +1 -1
- package/dist/{gameplay-CZ2yq37J.js → gameplay-BVphcxmE.js} +163 -14
- package/dist/gameplay.d.ts +81 -2
- package/dist/gameplay.js +2 -2
- package/dist/index.d.ts +45 -5
- package/dist/index.js +8 -9
- package/dist/{loader-DhI1jFW_.d.ts → loader-BbEMTuWg.d.ts} +1 -1
- package/dist/{loader-BTkHYrQn.js → loader-BcrRSjxB.js} +682 -682
- package/dist/net.d.ts +2 -2
- package/dist/net.js +1 -1
- package/dist/{pathfinding-CXGCpRQe.d.ts → pathfinding-mEN4V1CU.d.ts} +1 -1
- package/dist/{physics-2d-CfWAggJ1.js → physics-2d-BLcvEFDR.js} +2 -2
- package/dist/{physics-3d-C_ZJ6f_d.js → physics-3d-QBrfIT2Y.js} +3 -3
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-en63AEZO.js → register-C6ZBFRjd.js} +63 -60
- package/dist/{register-p48lHE2o.js → register-Ch70uByv.js} +1615 -1502
- package/dist/{replay-ePMz26jw.d.ts → replay-Dw6gMlYA.d.ts} +1 -1
- package/dist/{replay-t1pP0gQg.js → replay-s7I2GstT.js} +31 -11
- package/dist/sheet-grid-BT6N_Bjs.js +59 -0
- package/dist/{split-screen-BsdOHbzP.d.ts → split-screen-B0baBwxI.d.ts} +5 -1
- package/dist/{split-screen-CSb_uZ6W.js → split-screen-DLsUrleX.js} +14 -3
- package/dist/{sprite-animation-7qvUxF6Z.js → sprite-animation-C0wXLBZJ.js} +8 -4
- package/dist/{src-BVOVHRL0.js → src-CGjmPw65.js} +55 -2
- package/dist/{teardown-C7uVSJvx.js → teardown-Cs113S9F.js} +74 -2
- package/dist/{test-Ca5eqELC.js → test-it1VekWs.js} +28 -19
- package/dist/test.d.ts +4 -4
- package/dist/test.js +2 -2
- package/dist/{touch-BnMyy9tr.js → touch-DESwnpOc.js} +173 -1
- package/dist/vite.d.ts +1 -1
- package/dist/vite.js +3 -3
- package/editor/assets/{agent8-Cz4oHPtm.js → agent8-CGT7r3Mb.js} +1 -1
- package/editor/assets/{debug-r-Fi9nZh.js → debug-BxWSIHG3.js} +1 -1
- package/editor/assets/{index-BfqmvXYD.js → index-CV1m-aX5.js} +62 -62
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/skills/incanto-assets.md +5 -1
- package/skills/incanto-audio.md +7 -1
- package/skills/incanto-building-3d-games.md +18 -5
- package/skills/incanto-gameplay-behaviors.md +21 -1
- package/skills/incanto-hud.md +6 -0
- package/skills/incanto-performance.md +5 -0
- package/skills/incanto-physics-and-input.md +14 -0
- package/skills/incanto-save-slots.md +2 -1
- package/skills/incanto-verifying-your-game.md +4 -0
- 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/dist/log-report-CPFm4OXf.js +0 -173
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { E as behaviorSchema, w as parseNodePath } from "./loader-
|
|
2
|
-
import {
|
|
3
|
-
import { i as getNodeSchema } from "./registry-C7u42TID.js";
|
|
1
|
+
import { E as behaviorSchema, w as parseNodePath } from "./loader-BcrRSjxB.js";
|
|
2
|
+
import { D as HudWidgetBase, F as translationKey } from "./register-Ch70uByv.js";
|
|
3
|
+
import { i as getNodeSchema, o as getNodeType } from "./registry-C7u42TID.js";
|
|
4
4
|
//#region src/core/node-refs.ts
|
|
5
5
|
/**
|
|
6
6
|
* Node-path PROPS, resolved against scene JSON.
|
|
@@ -211,13 +211,33 @@ const BODY_TYPES = new Set([
|
|
|
211
211
|
"Area3D",
|
|
212
212
|
"CharacterBody3D"
|
|
213
213
|
]);
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
214
|
+
/**
|
|
215
|
+
* Is this node type a HUD widget — one that renders NOTHING outside a HudLayer?
|
|
216
|
+
*
|
|
217
|
+
* This used to be a hand-written list of five, and the kit has sixteen. It went
|
|
218
|
+
* stale the moment UiPanel landed, so the settings menu in the performance
|
|
219
|
+
* skill and the volume menu in the audio skill — both bare `UiPanel`s of
|
|
220
|
+
* uncovered widgets — drew a blank screen while `incanto-check` printed `ok`.
|
|
221
|
+
* The runtime is silent by design (`hud.ts`: `if (!host) return;`), which is
|
|
222
|
+
* exactly why the lint has to be right.
|
|
223
|
+
*
|
|
224
|
+
* Derived from the class hierarchy instead: anything descending from
|
|
225
|
+
* `HudWidgetBase` is one, whatever it is called and whenever it was added.
|
|
226
|
+
*/
|
|
227
|
+
function isHudWidget(type) {
|
|
228
|
+
if (type.startsWith("Ui")) return true;
|
|
229
|
+
let ctor;
|
|
230
|
+
try {
|
|
231
|
+
ctor = getNodeType(type);
|
|
232
|
+
} catch {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
for (let c = ctor; c; c = Object.getPrototypeOf(c)) {
|
|
236
|
+
if (c.typeName === "HudWidgetBase") return true;
|
|
237
|
+
if (c === HudWidgetBase) return true;
|
|
238
|
+
}
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
221
241
|
const LIGHT_TYPES = new Set([
|
|
222
242
|
"DirectionalLight3D",
|
|
223
243
|
"OmniLight3D",
|
|
@@ -269,7 +289,7 @@ function auditScene(scene) {
|
|
|
269
289
|
const collider = props.collider;
|
|
270
290
|
if (!collider || collider.shape === void 0) warnings.push(`${path}: ${type} has no collider — physics will skip it (add "collider": { "shape": ... }).`);
|
|
271
291
|
}
|
|
272
|
-
if (
|
|
292
|
+
if (isHudWidget(type) && !insideHud) warnings.push(`${path}: ${type} works only as a descendant of a HudLayer — it will not render.`);
|
|
273
293
|
if (staticRoot && ANIMATED_TYPES.has(type)) warnings.push(`${path}: ${type} is frozen inside static subtree '${staticRoot}' — it will not animate/update on screen.`);
|
|
274
294
|
const nextStatic = staticRoot ?? (props.static === true ? node.name ?? path : null);
|
|
275
295
|
const nextHud = insideHud || type === "HudLayer";
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
//#region src/core/sheet-grid.ts
|
|
2
|
+
/**
|
|
3
|
+
* Does this spritesheet's grid actually fit the image?
|
|
4
|
+
*
|
|
5
|
+
* `frameWidth`/`frameHeight` are taken on trust, and the frame math floors the
|
|
6
|
+
* division — so a frame size that does not divide the sheet slices every row a
|
|
7
|
+
* little further off, and an animation naming a frame past the end of the grid
|
|
8
|
+
* reads whatever texels are there. Both draw WRONG ART with no error anywhere,
|
|
9
|
+
* which is the one symptom an author cannot tell apart from having picked the
|
|
10
|
+
* wrong sheet in the first place.
|
|
11
|
+
*
|
|
12
|
+
* Pure arithmetic on numbers that are known the moment the image loads, so it
|
|
13
|
+
* costs nothing and it is exact.
|
|
14
|
+
*
|
|
15
|
+
* It lives in core because THREE nodes do this division — AnimatedSprite2D,
|
|
16
|
+
* AnimatedSprite3D and TileMap2D — and for a while the checker sat in `2d/`
|
|
17
|
+
* where only one of them could see it. A checker one directory away from the
|
|
18
|
+
* bug it catches is the same as no checker.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Frame sizes that divide `total` cleanly, biggest first.
|
|
22
|
+
*
|
|
23
|
+
* Bounded to grids of 2–32 cells so the suggestion is a frame size someone
|
|
24
|
+
* might actually have meant, not every factor of the number.
|
|
25
|
+
*/
|
|
26
|
+
function divisors(total) {
|
|
27
|
+
const out = [];
|
|
28
|
+
for (let cells = 2; cells <= 32; cells++) if (total % cells === 0) out.push(total / cells);
|
|
29
|
+
return out.sort((a, b) => b - a).slice(0, 6);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The problem with this grid, or null when there is none.
|
|
33
|
+
*
|
|
34
|
+
* `highestFrame` is the largest frame index the scene asks for, when it is
|
|
35
|
+
* known — an animation range that runs off the end is the other half of the
|
|
36
|
+
* same mistake.
|
|
37
|
+
*/
|
|
38
|
+
function checkSheetGrid(key, frameWidth, frameHeight, imageWidth, imageHeight, highestFrame) {
|
|
39
|
+
if (!imageWidth || !imageHeight || !frameWidth || !frameHeight) return null;
|
|
40
|
+
if (imageWidth % frameWidth !== 0 || imageHeight % frameHeight !== 0) {
|
|
41
|
+
const parts = [];
|
|
42
|
+
if (imageWidth % frameWidth !== 0) {
|
|
43
|
+
const fits = divisors(imageWidth);
|
|
44
|
+
parts.push(`${imageWidth} px wide is not a whole number of ${frameWidth} px frames` + (fits.length > 0 ? ` (${fits.join(", ")} would divide it)` : ""));
|
|
45
|
+
}
|
|
46
|
+
if (imageHeight % frameHeight !== 0) {
|
|
47
|
+
const fits = divisors(imageHeight);
|
|
48
|
+
parts.push(`${imageHeight} px tall is not a whole number of ${frameHeight} px frames` + (fits.length > 0 ? ` (${fits.join(", ")} would divide it)` : ""));
|
|
49
|
+
}
|
|
50
|
+
return `[incanto] spritesheet '${key}' does not fit its frame size: ${parts.join("; ")}. Every row after the first is cut off centre.`;
|
|
51
|
+
}
|
|
52
|
+
if (highestFrame !== void 0) {
|
|
53
|
+
const frames = imageWidth / frameWidth * (imageHeight / frameHeight);
|
|
54
|
+
if (highestFrame >= frames) return `[incanto] spritesheet '${key}' has ${frames} frames (0–${frames - 1}), and an animation asks for frame ${highestFrame}. Those frames draw whatever is at the wrong end of the sheet.`;
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
export { checkSheetGrid as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { At as Node, It as Signal, b as Engine } from "./behavior-
|
|
1
|
+
import { At as Node, It as Signal, b as Engine } from "./behavior-l08AEbq9.js";
|
|
2
2
|
import { c as JsonValue, i as SceneJson, s as JsonObject } from "./schema-CFeioQRE.js";
|
|
3
3
|
|
|
4
4
|
//#region src/net/types.d.ts
|
|
@@ -317,6 +317,10 @@ declare class NetworkManager {
|
|
|
317
317
|
private readonly latestGlobalCollections;
|
|
318
318
|
private readonly scenes;
|
|
319
319
|
private readonly lastSent;
|
|
320
|
+
/** Sync keys already reported unreadable, so a per-frame send says it once. */
|
|
321
|
+
private readonly reportedDeadKeys;
|
|
322
|
+
/** Name a sync key the owner cannot read — a typo in the prop or the path. */
|
|
323
|
+
private reportDeadSyncKey;
|
|
320
324
|
private sendAccumulator;
|
|
321
325
|
private detachReplication;
|
|
322
326
|
private lastOwner;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as diagnose, M as Signal,
|
|
2
|
-
import {
|
|
1
|
+
import { C as diagnose, M as Signal, S as Node, n as loadScene, t as buildNodeJson } from "./loader-BcrRSjxB.js";
|
|
2
|
+
import { _ as Engine, t as registerCoreNodes } from "./register-Ch70uByv.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
4
|
import { n as jsonEquals, t as jsonClone } from "./json-BLk7H2Qa.js";
|
|
5
5
|
import { l as registerNode } from "./registry-C7u42TID.js";
|
|
@@ -811,6 +811,14 @@ var NetworkManager = class NetworkManager {
|
|
|
811
811
|
latestGlobalCollections = /* @__PURE__ */ new Map();
|
|
812
812
|
scenes = /* @__PURE__ */ new Map();
|
|
813
813
|
lastSent = /* @__PURE__ */ new Map();
|
|
814
|
+
/** Sync keys already reported unreadable, so a per-frame send says it once. */
|
|
815
|
+
reportedDeadKeys = /* @__PURE__ */ new Set();
|
|
816
|
+
/** Name a sync key the owner cannot read — a typo in the prop or the path. */
|
|
817
|
+
reportDeadSyncKey(owner, key) {
|
|
818
|
+
if (this.reportedDeadKeys.has(key)) return;
|
|
819
|
+
this.reportedDeadKeys.add(key);
|
|
820
|
+
diagnose(owner.tree?.engine ?? null, "error", `[incanto] ${owner.getPath()}: sync key '${key}' reads as undefined — it is never sent, so remote players never see it change. Check the prop name and the node path.`);
|
|
821
|
+
}
|
|
814
822
|
sendAccumulator = 0;
|
|
815
823
|
detachReplication = null;
|
|
816
824
|
lastOwner = null;
|
|
@@ -1000,7 +1008,10 @@ var NetworkManager = class NetworkManager {
|
|
|
1000
1008
|
const patch = {};
|
|
1001
1009
|
for (const key of syncKeys) {
|
|
1002
1010
|
const value = readSyncKey(owner, key);
|
|
1003
|
-
if (value === void 0)
|
|
1011
|
+
if (value === void 0) {
|
|
1012
|
+
this.reportDeadSyncKey(owner, key);
|
|
1013
|
+
continue;
|
|
1014
|
+
}
|
|
1004
1015
|
if (!jsonEquals(this.lastSent.get(key) ?? null, value)) patch[key] = jsonClone(value);
|
|
1005
1016
|
}
|
|
1006
1017
|
if (this.sendAccumulator < window) return;
|
|
@@ -306,10 +306,14 @@ function resolveAnimation(animations, name, owner) {
|
|
|
306
306
|
const via = seen.length > 0 ? ` (via ${seen.join(" → ")})` : "";
|
|
307
307
|
throw new IncantoError("UNKNOWN_ANIMATION", `No animation '${key}' on '${owner}'${via}. Available: [${Object.keys(animations).join(", ")}].`);
|
|
308
308
|
}
|
|
309
|
-
if (typeof entry !== "string")
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
309
|
+
if (typeof entry !== "string") {
|
|
310
|
+
const frames = resolveFrames(entry.frames, key);
|
|
311
|
+
if (frames.length > 1 && !(Number.isFinite(entry.fps) && entry.fps > 0)) throw new IncantoError("BAD_FORMAT", `Animation '${key}' on '${owner}' has ${frames.length} frames and no "fps" — it would sit on the first one forever. Add "fps" (the field is fps, not frameRate or speed).`);
|
|
312
|
+
return {
|
|
313
|
+
name: key,
|
|
314
|
+
def: entry
|
|
315
|
+
};
|
|
316
|
+
}
|
|
313
317
|
if (seen.includes(key)) throw new IncantoError("UNKNOWN_ANIMATION", `Animation aliases on '${owner}' point in a circle: ${[...seen, key].join(" → ")}.`);
|
|
314
318
|
seen.push(key);
|
|
315
319
|
key = entry;
|
|
@@ -143,6 +143,59 @@ async function preloadUrls(urls, onProgress) {
|
|
|
143
143
|
function assetUrls(assets) {
|
|
144
144
|
return Object.values(assets ?? {}).map((a) => a.url).filter((u) => typeof u === "string" && !u.startsWith("data:"));
|
|
145
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* The standard boot screen every template hand-rolled (~125 identical lines
|
|
148
|
+
* of HTML+CSS): black overlay, "Loading" title, progress track + percent.
|
|
149
|
+
* Headless it returns inert no-ops.
|
|
150
|
+
*/
|
|
151
|
+
function createLoadingOverlay(title = "Loading") {
|
|
152
|
+
if (typeof document === "undefined") return {
|
|
153
|
+
setProgress: () => {},
|
|
154
|
+
remove: () => {}
|
|
155
|
+
};
|
|
156
|
+
const wrap = document.createElement("div");
|
|
157
|
+
wrap.style.cssText = "position:fixed;inset:0;z-index:10000;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#000;color:#fff;font:600 15px system-ui, -apple-system, 'Segoe UI', sans-serif;transition:opacity .3s;";
|
|
158
|
+
const h = document.createElement("div");
|
|
159
|
+
h.textContent = title;
|
|
160
|
+
h.style.cssText = "font-size:1.5rem;font-weight:700;margin-bottom:1rem;";
|
|
161
|
+
const track = document.createElement("div");
|
|
162
|
+
track.style.cssText = "width:256px;height:8px;background:#374151;border-radius:9999px;overflow:hidden;";
|
|
163
|
+
const fill = document.createElement("div");
|
|
164
|
+
fill.style.cssText = "width:0%;height:100%;background:#3b82f6;transition:width .3s;";
|
|
165
|
+
track.appendChild(fill);
|
|
166
|
+
const pct = document.createElement("div");
|
|
167
|
+
pct.textContent = "0%";
|
|
168
|
+
pct.style.cssText = "margin-top:.5rem;font-size:.9rem;";
|
|
169
|
+
wrap.append(h, track, pct);
|
|
170
|
+
document.body.appendChild(wrap);
|
|
171
|
+
let removed = false;
|
|
172
|
+
return {
|
|
173
|
+
setProgress(done, total) {
|
|
174
|
+
const p = total > 0 ? Math.min(100, Math.round(done / total * 100)) : 100;
|
|
175
|
+
fill.style.width = `${p}%`;
|
|
176
|
+
pct.textContent = `${p}%`;
|
|
177
|
+
},
|
|
178
|
+
remove() {
|
|
179
|
+
if (removed) return;
|
|
180
|
+
removed = true;
|
|
181
|
+
wrap.style.opacity = "0";
|
|
182
|
+
setTimeout(() => wrap.remove(), 320);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Preload every scene-asset URL behind the standard overlay, then remove it:
|
|
188
|
+
*
|
|
189
|
+
* await preloadSceneAssets(sceneJson.assets);
|
|
190
|
+
*/
|
|
191
|
+
async function preloadSceneAssets(assets, title) {
|
|
192
|
+
const overlay = createLoadingOverlay(title);
|
|
193
|
+
try {
|
|
194
|
+
await preloadUrls(assetUrls(assets), (done, total) => overlay.setProgress(done, total));
|
|
195
|
+
} finally {
|
|
196
|
+
overlay.remove();
|
|
197
|
+
}
|
|
198
|
+
}
|
|
146
199
|
//#endregion
|
|
147
200
|
//#region src/core/uid-gen.ts
|
|
148
201
|
/**
|
|
@@ -161,6 +214,6 @@ function newUid() {
|
|
|
161
214
|
//#endregion
|
|
162
215
|
//#region src/index.ts
|
|
163
216
|
/** Engine version. Kept in sync with package.json by the release pipeline. */
|
|
164
|
-
const VERSION = "0.
|
|
217
|
+
const VERSION = "0.57.0";
|
|
165
218
|
//#endregion
|
|
166
|
-
export {
|
|
219
|
+
export { preloadUrls as a, preloadSceneAssets as i, newUid as n, findPath as o, assetUrls as r, gridFromRows as s, VERSION as t };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { g as AudioPlayer } from "./register-Ch70uByv.js";
|
|
2
|
+
import { a as logReport, s as parseDrive } from "./touch-DESwnpOc.js";
|
|
3
|
+
import { a as frameSignature, i as frameImage, o as frameStats } from "./frame-report-BSMny7oe.js";
|
|
2
4
|
//#region src/core/audio-errors.ts
|
|
3
5
|
/** Every AudioPlayer under `root` whose source could not be played. */
|
|
4
6
|
function audioErrors(root) {
|
|
@@ -27,6 +29,76 @@ function claimCanvasGestures(canvas) {
|
|
|
27
29
|
style.webkitTapHighlightColor = "transparent";
|
|
28
30
|
}
|
|
29
31
|
//#endregion
|
|
32
|
+
//#region src/core/dev-channel.ts
|
|
33
|
+
/**
|
|
34
|
+
* Answer the dev server's frame/log requests. Returns the unsubscribes, or an
|
|
35
|
+
* empty list outside a dev server.
|
|
36
|
+
*/
|
|
37
|
+
function wireDevChannel(opts) {
|
|
38
|
+
const hot = import.meta.hot;
|
|
39
|
+
const cleanups = [];
|
|
40
|
+
if (!hot) return cleanups;
|
|
41
|
+
const onFrameRequest = (data) => {
|
|
42
|
+
const request = data;
|
|
43
|
+
const id = request?.id;
|
|
44
|
+
hot.send("incanto:frame-ack", { id });
|
|
45
|
+
const drive = request?.drive ? parseDrive(request.drive) : null;
|
|
46
|
+
if (drive?.error) {
|
|
47
|
+
hot.send("incanto:frame-report", {
|
|
48
|
+
id,
|
|
49
|
+
report: { error: drive.error }
|
|
50
|
+
});
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
let droveFrames = null;
|
|
54
|
+
(drive ? opts.applyDrive(drive.steps) : Promise.resolve(null)).then((frames) => {
|
|
55
|
+
droveFrames = frames;
|
|
56
|
+
return opts.captureFramePixels();
|
|
57
|
+
}).then((shot) => hot.send("incanto:frame-report", {
|
|
58
|
+
id,
|
|
59
|
+
report: {
|
|
60
|
+
...frameStats(shot.pixels, shot.width, shot.height, { grid: request?.grid }),
|
|
61
|
+
signature: frameSignature(shot.pixels, shot.width, shot.height),
|
|
62
|
+
...droveFrames === null ? {} : { droveFrames },
|
|
63
|
+
...request?.image ? { image: frameImage(shot.pixels, shot.width, shot.height, (w, h) => Object.assign(document.createElement("canvas"), {
|
|
64
|
+
width: w,
|
|
65
|
+
height: h
|
|
66
|
+
}), request.image) } : {}
|
|
67
|
+
}
|
|
68
|
+
})).catch((error) => hot.send("incanto:frame-report", {
|
|
69
|
+
id,
|
|
70
|
+
report: { error: error instanceof Error ? error.message : String(error) }
|
|
71
|
+
}));
|
|
72
|
+
};
|
|
73
|
+
hot.on("incanto:frame-request", onFrameRequest);
|
|
74
|
+
cleanups.push(() => hot.off?.("incanto:frame-request", onFrameRequest));
|
|
75
|
+
const onLogsRequest = (data) => {
|
|
76
|
+
const id = data?.id;
|
|
77
|
+
try {
|
|
78
|
+
hot.send("incanto:logs-report", {
|
|
79
|
+
id,
|
|
80
|
+
report: logReport({
|
|
81
|
+
entries: opts.engine.log.entries(),
|
|
82
|
+
stats: {
|
|
83
|
+
...opts.engine.stats(),
|
|
84
|
+
...opts.rendererStats?.() ?? {}
|
|
85
|
+
},
|
|
86
|
+
assetErrors: opts.assetErrors?.() ?? [],
|
|
87
|
+
hidden: typeof document !== "undefined" && document.hidden
|
|
88
|
+
})
|
|
89
|
+
});
|
|
90
|
+
} catch (error) {
|
|
91
|
+
hot.send("incanto:logs-report", {
|
|
92
|
+
id,
|
|
93
|
+
report: { error: error instanceof Error ? error.message : String(error) }
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
hot.on("incanto:logs-request", onLogsRequest);
|
|
98
|
+
cleanups.push(() => hot.off?.("incanto:logs-request", onLogsRequest));
|
|
99
|
+
return cleanups;
|
|
100
|
+
}
|
|
101
|
+
//#endregion
|
|
30
102
|
//#region src/core/editor-switch.ts
|
|
31
103
|
/**
|
|
32
104
|
* Cover the page while it changes what it is.
|
|
@@ -324,4 +396,4 @@ function defaultReport(what, error) {
|
|
|
324
396
|
console.error(`[incanto] teardown: ${what} failed (continuing)`, error);
|
|
325
397
|
}
|
|
326
398
|
//#endregion
|
|
327
|
-
export { openBundledEditor as a,
|
|
399
|
+
export { openBundledEditor as a, claimCanvasGestures as c, devServerLibrary as i, audioErrors as l, pauseWhenHidden as n, poseFromRenderer as o, crossFade as r, wireDevChannel as s, teardown as t };
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { A as registerBehavior, n as loadScene, s as resolveViewport } from "./loader-
|
|
2
|
-
import {
|
|
1
|
+
import { A as registerBehavior, n as loadScene, s as resolveViewport } from "./loader-BcrRSjxB.js";
|
|
2
|
+
import { _ as Engine } from "./register-Ch70uByv.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
4
|
import { n as jsonEquals, t as jsonClone } from "./json-BLk7H2Qa.js";
|
|
5
5
|
import { i as getNodeSchema, s as mergeStaticProps } from "./registry-C7u42TID.js";
|
|
6
|
-
import { n as startRecording } from "./replay-
|
|
7
|
-
import { n as registerGameplayBehaviors } from "./gameplay-
|
|
8
|
-
import { t as registerNodes2D } from "./register-
|
|
9
|
-
import { n as registerNodes3D, t as resolveEnvironmentHdri } from "./environment-presets-
|
|
10
|
-
import { n as registerNodesNet, t as createSplitScreen } from "./split-screen-
|
|
6
|
+
import { n as startRecording } from "./replay-s7I2GstT.js";
|
|
7
|
+
import { n as registerGameplayBehaviors } from "./gameplay-BVphcxmE.js";
|
|
8
|
+
import { t as registerNodes2D } from "./register-C6ZBFRjd.js";
|
|
9
|
+
import { n as registerNodes3D, t as resolveEnvironmentHdri } from "./environment-presets-CvvQr_bJ.js";
|
|
10
|
+
import { n as registerNodesNet, t as createSplitScreen } from "./split-screen-DLsUrleX.js";
|
|
11
11
|
import { Box3, Euler, Matrix4, PerspectiveCamera, Quaternion, Vector3 } from "three";
|
|
12
12
|
//#region src/test/framing.ts
|
|
13
13
|
/**
|
|
@@ -1016,6 +1016,10 @@ function facingText(report) {
|
|
|
1016
1016
|
const STEP_MS = 1e3 / 60;
|
|
1017
1017
|
/** Drop height for the buffer probe — long enough to outlast a coyote window. */
|
|
1018
1018
|
const DROP = 12;
|
|
1019
|
+
/** Metres a 3D probe is lifted/dropped from. */
|
|
1020
|
+
const UNIT_LIFT = 40;
|
|
1021
|
+
/** Pixels a 2D probe is lifted/dropped from — a 2D world is ~30x the numbers. */
|
|
1022
|
+
const PX_LIFT = 1200;
|
|
1019
1023
|
function positionOf(node) {
|
|
1020
1024
|
const p = node.position;
|
|
1021
1025
|
return [
|
|
@@ -1062,11 +1066,14 @@ async function makeProbe(json, opts) {
|
|
|
1062
1066
|
jump
|
|
1063
1067
|
};
|
|
1064
1068
|
}
|
|
1069
|
+
const is2d = session.scene.dimension === "2d";
|
|
1065
1070
|
return {
|
|
1066
1071
|
probe: {
|
|
1067
1072
|
session,
|
|
1068
1073
|
engine: session.engine,
|
|
1069
1074
|
player,
|
|
1075
|
+
up: is2d ? -1 : 1,
|
|
1076
|
+
lift: is2d ? PX_LIFT : UNIT_LIFT,
|
|
1070
1077
|
step: (frames = 1) => session.step(frames * STEP_MS),
|
|
1071
1078
|
pos: () => positionOf(player),
|
|
1072
1079
|
vel: () => velocityOf(player),
|
|
@@ -1159,7 +1166,7 @@ function jumpShape(probe, jump) {
|
|
|
1159
1166
|
let airtime = null;
|
|
1160
1167
|
for (let f = 2; f <= 600; f++) {
|
|
1161
1168
|
probe.step();
|
|
1162
|
-
const h = probe.pos()[1] - floor;
|
|
1169
|
+
const h = (probe.pos()[1] - floor) * probe.up;
|
|
1163
1170
|
if (h > apex) {
|
|
1164
1171
|
apex = h;
|
|
1165
1172
|
toApex = f;
|
|
@@ -1169,7 +1176,8 @@ function jumpShape(probe, jump) {
|
|
|
1169
1176
|
break;
|
|
1170
1177
|
}
|
|
1171
1178
|
}
|
|
1172
|
-
|
|
1179
|
+
const noise = probe.up > 0 ? .02 : 2;
|
|
1180
|
+
if (apex <= noise) return {
|
|
1173
1181
|
apex: null,
|
|
1174
1182
|
toApexMs: null,
|
|
1175
1183
|
airtimeMs: null
|
|
@@ -1197,7 +1205,7 @@ async function measureCoyote(json, opts, jump) {
|
|
|
1197
1205
|
const p = probe.pos();
|
|
1198
1206
|
probe.player.position = [
|
|
1199
1207
|
p[0],
|
|
1200
|
-
p[1] +
|
|
1208
|
+
p[1] + probe.lift * probe.up,
|
|
1201
1209
|
p[2]
|
|
1202
1210
|
];
|
|
1203
1211
|
probe.step(delayFrames);
|
|
@@ -1206,7 +1214,7 @@ async function measureCoyote(json, opts, jump) {
|
|
|
1206
1214
|
probe.step();
|
|
1207
1215
|
const after = probe.vel()[1];
|
|
1208
1216
|
probe.session.dispose();
|
|
1209
|
-
return after - before > 1;
|
|
1217
|
+
return (after - before) * probe.up > 1;
|
|
1210
1218
|
};
|
|
1211
1219
|
if (!await fired(1)) return 0;
|
|
1212
1220
|
let lo = 1;
|
|
@@ -1231,13 +1239,14 @@ async function measureBuffer(json, opts, jump) {
|
|
|
1231
1239
|
if (!probe) return false;
|
|
1232
1240
|
settle$1(probe);
|
|
1233
1241
|
const floor = probe.pos()[1];
|
|
1242
|
+
const drop = (probe.up > 0 ? DROP : probe.lift / 3) * probe.up;
|
|
1234
1243
|
probe.player.position = [
|
|
1235
1244
|
probe.pos()[0],
|
|
1236
|
-
floor +
|
|
1245
|
+
floor + drop,
|
|
1237
1246
|
probe.pos()[2]
|
|
1238
1247
|
];
|
|
1239
1248
|
let frames = 0;
|
|
1240
|
-
while (probe.pos()[1]
|
|
1249
|
+
while ((probe.pos()[1] - floor) * probe.up > .05 && frames < 200) {
|
|
1241
1250
|
probe.step();
|
|
1242
1251
|
frames += 1;
|
|
1243
1252
|
}
|
|
@@ -1249,7 +1258,7 @@ async function measureBuffer(json, opts, jump) {
|
|
|
1249
1258
|
settle$1(p2);
|
|
1250
1259
|
p2.player.position = [
|
|
1251
1260
|
p2.pos()[0],
|
|
1252
|
-
floor +
|
|
1261
|
+
floor + drop,
|
|
1253
1262
|
p2.pos()[2]
|
|
1254
1263
|
];
|
|
1255
1264
|
p2.step(Math.max(0, fallFrames - earlyFrames));
|
|
@@ -1259,7 +1268,7 @@ async function measureBuffer(json, opts, jump) {
|
|
|
1259
1268
|
let rose = false;
|
|
1260
1269
|
for (let f = 0; f < 40; f++) {
|
|
1261
1270
|
p2.step();
|
|
1262
|
-
if (p2.vel()[1] > 1) rose = true;
|
|
1271
|
+
if (p2.vel()[1] * p2.up > 1) rose = true;
|
|
1263
1272
|
}
|
|
1264
1273
|
p2.session.dispose();
|
|
1265
1274
|
return rose;
|
|
@@ -1753,10 +1762,10 @@ async function runScript(json, opts) {
|
|
|
1753
1762
|
engine.setScene(scene);
|
|
1754
1763
|
const physics = opts.physics ?? "auto";
|
|
1755
1764
|
if (physics === "2d" || physics === "auto" && scene.dimension === "2d") {
|
|
1756
|
-
const { enablePhysics2D } = await import("./physics-2d-
|
|
1765
|
+
const { enablePhysics2D } = await import("./physics-2d-BLcvEFDR.js").then((n) => n.r);
|
|
1757
1766
|
await enablePhysics2D(engine);
|
|
1758
1767
|
} else if (physics === "3d" || physics === "auto" && scene.dimension === "3d") {
|
|
1759
|
-
const { enablePhysics3D } = await import("./physics-3d-
|
|
1768
|
+
const { enablePhysics3D } = await import("./physics-3d-QBrfIT2Y.js").then((n) => n.r);
|
|
1760
1769
|
await enablePhysics3D(engine);
|
|
1761
1770
|
}
|
|
1762
1771
|
const failures = [];
|
|
@@ -1869,10 +1878,10 @@ async function createPlaySession(json, opts = {}) {
|
|
|
1869
1878
|
engine.setScene(scene);
|
|
1870
1879
|
const physics = opts.physics ?? "auto";
|
|
1871
1880
|
if (physics === "2d" || physics === "auto" && scene.dimension === "2d") {
|
|
1872
|
-
const { enablePhysics2D } = await import("./physics-2d-
|
|
1881
|
+
const { enablePhysics2D } = await import("./physics-2d-BLcvEFDR.js").then((n) => n.r);
|
|
1873
1882
|
await enablePhysics2D(engine);
|
|
1874
1883
|
} else if (physics === "3d" || physics === "auto" && scene.dimension === "3d") {
|
|
1875
|
-
const { enablePhysics3D } = await import("./physics-3d-
|
|
1884
|
+
const { enablePhysics3D } = await import("./physics-3d-QBrfIT2Y.js").then((n) => n.r);
|
|
1876
1885
|
await enablePhysics3D(engine);
|
|
1877
1886
|
}
|
|
1878
1887
|
const stepMs = 1e3 / (opts.fixedHz ?? 60);
|
package/dist/test.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { At as Node, Nt as LogEntry, P as Scene, b as Engine, n as BehaviorCtor } from "./behavior-
|
|
1
|
+
import { At as Node, Nt as LogEntry, P as Scene, b as Engine, n as BehaviorCtor } from "./behavior-l08AEbq9.js";
|
|
2
2
|
import { c as JsonValue, i as SceneJson, s as JsonObject } from "./schema-CFeioQRE.js";
|
|
3
|
-
import { t as LoadSceneOptions } from "./loader-
|
|
4
|
-
import { l as auditScene, o as IncantoError, r as ReplayJson } from "./replay-
|
|
5
|
-
import { l as LocalGameServerOptions, n as SplitScreenPlayer } from "./split-screen-
|
|
3
|
+
import { t as LoadSceneOptions } from "./loader-BbEMTuWg.js";
|
|
4
|
+
import { l as auditScene, o as IncantoError, r as ReplayJson } from "./replay-Dw6gMlYA.js";
|
|
5
|
+
import { l as LocalGameServerOptions, n as SplitScreenPlayer } from "./split-screen-B0baBwxI.js";
|
|
6
6
|
|
|
7
7
|
//#region src/test/facing.d.ts
|
|
8
8
|
interface FacingOptions {
|
package/dist/test.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { r as auditScene } from "./replay-
|
|
2
|
-
import { S as framingText, _ as failingReplays, a as registerAllNodes, b as playtestText, c as ladderText, d as multiplayText, f as playMultiplayer, g as facingText, h as facingReport, i as findFloatingProps, l as ladderVerdict, m as feelText, n as createPlaySession, o as runScript, p as feelReport, r as describeCapture, s as validateScene, t as captureScene, u as multiplayProblems, v as findPlayer, x as describeFraming, y as playtest } from "./test-
|
|
1
|
+
import { r as auditScene } from "./replay-s7I2GstT.js";
|
|
2
|
+
import { S as framingText, _ as failingReplays, a as registerAllNodes, b as playtestText, c as ladderText, d as multiplayText, f as playMultiplayer, g as facingText, h as facingReport, i as findFloatingProps, l as ladderVerdict, m as feelText, n as createPlaySession, o as runScript, p as feelReport, r as describeCapture, s as validateScene, t as captureScene, u as multiplayProblems, v as findPlayer, x as describeFraming, y as playtest } from "./test-it1VekWs.js";
|
|
3
3
|
export { auditScene, captureScene, createPlaySession, describeCapture, describeFraming, facingReport, facingText, failingReplays, feelReport, feelText, findFloatingProps, findPlayer, framingText, ladderText, ladderVerdict, multiplayProblems, multiplayText, playMultiplayer, playtest, playtestText, registerAllNodes, runScript, validateScene };
|