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
package/bin/incanto-verify.mjs
CHANGED
|
@@ -109,14 +109,21 @@ const rungs = [];
|
|
|
109
109
|
{
|
|
110
110
|
const r = run('check', [scene, '--json']);
|
|
111
111
|
const out = safeJson(r.stdout);
|
|
112
|
-
|
|
112
|
+
// `incanto-check --json` emits { ok, results: [{ file, ok, code, message }] }.
|
|
113
|
+
// This read `out.files[].problems[].why` — three keys that have never existed —
|
|
114
|
+
// so the summary always fell through to the first line of the pretty-printed
|
|
115
|
+
// JSON, which is `{`. Every scene-validation failure, the top rung of the
|
|
116
|
+
// ladder, rendered as `✗ loads — {` with the sentence naming the node path and
|
|
117
|
+
// the legal values sitting one key away in the same object.
|
|
118
|
+
const broke = out?.results?.find((entry) => entry && entry.ok === false);
|
|
119
|
+
const detail = broke && (broke.message || broke.code) ? `[${broke.code}] ${broke.message}` : null;
|
|
113
120
|
rungs.push(
|
|
114
121
|
r.status === 0
|
|
115
122
|
? { name: 'loads', status: 'pass', summary: 'the scene is legal and its assets resolve' }
|
|
116
123
|
: {
|
|
117
124
|
name: 'loads',
|
|
118
125
|
status: 'fail',
|
|
119
|
-
summary:
|
|
126
|
+
summary: detail ?? firstLine(r.stderr) ?? 'incanto-check failed',
|
|
120
127
|
fix: `fix that, then run again — nothing above this rung means anything until it is green (\`incanto-check ${scene}\` for the detail)`,
|
|
121
128
|
},
|
|
122
129
|
);
|
package/dist/2d.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { At as Node, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, n as BehaviorCtor, w as GameStats } from "./behavior-
|
|
1
|
+
import { At as Node, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, n as BehaviorCtor, w as GameStats } from "./behavior-l08AEbq9.js";
|
|
2
2
|
import { n as DiagnosticSink, t as EditorSwitchOptions } from "./editor-switch-DAvWQeld.js";
|
|
3
3
|
import { i as SceneJson, s as JsonObject } from "./schema-CFeioQRE.js";
|
|
4
|
-
import {
|
|
4
|
+
import { r as FrameStats } from "./frame-report-DCnHFmto.js";
|
|
5
|
+
import { t as LoadSceneOptions } from "./loader-BbEMTuWg.js";
|
|
5
6
|
import { n as AnimationEntry } from "./sprite-animation-CMr6f1K2.js";
|
|
6
7
|
import { r as ParticleView, t as ParticleSim } from "./particle-sim-C5OfBbmU.js";
|
|
7
8
|
import { Group, Mesh, Object3D, Scene, Texture } from "three";
|
|
@@ -388,6 +389,16 @@ interface Game2D {
|
|
|
388
389
|
engine: Engine;
|
|
389
390
|
scene: Scene$1;
|
|
390
391
|
/**
|
|
392
|
+
* What the last drawn frame actually looks like, as numbers.
|
|
393
|
+
*
|
|
394
|
+
* The 3D game has answered this since 0.47 and a 2D game could not, so
|
|
395
|
+
* `incanto-frame` and `incanto-verify`'s `draws` rung were permanently
|
|
396
|
+
* unmeasured for half the engine's games.
|
|
397
|
+
*/
|
|
398
|
+
frame(opts?: {
|
|
399
|
+
grid?: [number, number];
|
|
400
|
+
}): Promise<FrameStats>;
|
|
401
|
+
/**
|
|
391
402
|
* The AUTHORED scene this game booted from — the JSON, not the live tree.
|
|
392
403
|
* A running tree has moved; the editor gets what was written down.
|
|
393
404
|
*/
|
|
@@ -691,6 +702,14 @@ declare class Label extends Node2D {
|
|
|
691
702
|
_quad(): Mesh;
|
|
692
703
|
override _syncObject2D(assets: AssetStore2D | null): void;
|
|
693
704
|
private rasterize;
|
|
705
|
+
/**
|
|
706
|
+
* Hand the canvas and its texture back.
|
|
707
|
+
*
|
|
708
|
+
* LABEL_PLANE is shared by every Label in the process and stays; the material
|
|
709
|
+
* and the CanvasTexture are this node's, and a scene that spawns floating
|
|
710
|
+
* text left one of each behind per freed node.
|
|
711
|
+
*/
|
|
712
|
+
override free(): void;
|
|
694
713
|
}
|
|
695
714
|
//#endregion
|
|
696
715
|
//#region src/2d/nodes/particles-2d.d.ts
|
|
@@ -768,6 +787,15 @@ declare class Particles2D extends Node2D {
|
|
|
768
787
|
* (dust under a player) as well as the node's own position.
|
|
769
788
|
*/
|
|
770
789
|
private holdWorldSpace;
|
|
790
|
+
/** What the current mesh was built FOR — capacity and blend, the two things
|
|
791
|
+
* baked into it. Not the draw count, which changes every frame. */
|
|
792
|
+
private meshKey;
|
|
793
|
+
/**
|
|
794
|
+
* Hand the GPU back. UNIT_PLANE is shared by every 2D particle system in the
|
|
795
|
+
* process, so the geometry stays; the per-node material and the instance
|
|
796
|
+
* buffers inside the InstancedMesh do not.
|
|
797
|
+
*/
|
|
798
|
+
override free(): void;
|
|
771
799
|
/** Tell the engine an effect fired — the visual half of the audio record. */
|
|
772
800
|
private report;
|
|
773
801
|
/** Restart a one-shot (re-burst + allow finished to fire again). */
|
|
@@ -815,6 +843,8 @@ declare class TileMap2D extends Node2D {
|
|
|
815
843
|
private _solid;
|
|
816
844
|
/** Rebuild flags — raised when the map-shaping props are REPLACED. */
|
|
817
845
|
private geometryDirty;
|
|
846
|
+
/** Reported once per atlas, so a bad grid says so on the first build only. */
|
|
847
|
+
private gridChecked;
|
|
818
848
|
private collidersDirty;
|
|
819
849
|
/** Replace the whole array to change the map (mutations are not watched). */
|
|
820
850
|
get cells(): (string | number[])[];
|
|
@@ -909,11 +939,6 @@ interface Renderer2DOptions {
|
|
|
909
939
|
/** MSAA on the canvas. Defaults to TRUE (Phaser parity). */
|
|
910
940
|
antialias?: boolean;
|
|
911
941
|
}
|
|
912
|
-
/**
|
|
913
|
-
* 2D presentation layer: world pass through the active Camera2D
|
|
914
|
-
* (center/zoom/limits), then a screen-space UI pass for UILayer subtrees.
|
|
915
|
-
* 1 unit = 1 px, (0,0) top-left, +y down.
|
|
916
|
-
*/
|
|
917
942
|
declare class Renderer2D {
|
|
918
943
|
/**
|
|
919
944
|
* When set, the world pass frames THIS view instead of the scene's active
|
|
@@ -926,6 +951,33 @@ declare class Renderer2D {
|
|
|
926
951
|
zoom: number;
|
|
927
952
|
} | null;
|
|
928
953
|
private readonly webgl;
|
|
954
|
+
/**
|
|
955
|
+
* The pixels of the next drawn frame — how `incanto-frame` sees a 2D game.
|
|
956
|
+
*
|
|
957
|
+
* Mirrors Renderer3D exactly: read inside the render, so
|
|
958
|
+
* `preserveDrawingBuffer` can stay off, and nudge a frame ourselves after a
|
|
959
|
+
* moment because a browser stops handing rAF to a tab it thinks is hidden —
|
|
960
|
+
* including a window merely covered by another one. Without the nudge the
|
|
961
|
+
* promise never settles and the CLI reports "no page connected" about a page
|
|
962
|
+
* that is right there.
|
|
963
|
+
*/
|
|
964
|
+
captureFrame(): Promise<{
|
|
965
|
+
pixels: Uint8Array;
|
|
966
|
+
width: number;
|
|
967
|
+
height: number;
|
|
968
|
+
}>;
|
|
969
|
+
private pendingCaptures;
|
|
970
|
+
/** Hand the waiting captures this frame's pixels. Called at the end of render. */
|
|
971
|
+
private drainFrameCapture;
|
|
972
|
+
/** The pixel ratio the scene asked for, before any render-scale setting. */
|
|
973
|
+
private basePixelRatio;
|
|
974
|
+
/**
|
|
975
|
+
* Fewer pixels for the same world — the cheapest frames on a weak device.
|
|
976
|
+
*
|
|
977
|
+
* `settings.renderScale` persisted and was applied by the 3D boot only, so a
|
|
978
|
+
* 2D game's resolution slider saved a number and changed nothing, forever.
|
|
979
|
+
*/
|
|
980
|
+
setRenderScale(scale: number): void;
|
|
929
981
|
private readonly worldScene;
|
|
930
982
|
private readonly syncScratch;
|
|
931
983
|
/** Editors set this: keep syncing `static: true` subtrees every frame. */
|
package/dist/2d.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
2
|
-
import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-
|
|
3
|
-
import { _ as RigidBody2D, a as parseCells, c as ColorRect2D, d as AnimatedSprite2D, f as Sprite2D, g as PhysicsBody2D, h as CharacterBody2D, i as mergeSolidRects, l as CharacterController2D, m as Area2D, n as UILayer, o as Particles2D, p as Joint2D, r as TileMap2D, s as Label, t as registerNodes2D, u as Camera2D, v as StaticBody2D, y as Node2D } from "./register-
|
|
4
|
-
import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-
|
|
2
|
+
import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-DpbUrMOQ.js";
|
|
3
|
+
import { _ as RigidBody2D, a as parseCells, c as ColorRect2D, d as AnimatedSprite2D, f as Sprite2D, g as PhysicsBody2D, h as CharacterBody2D, i as mergeSolidRects, l as CharacterController2D, m as Area2D, n as UILayer, o as Particles2D, p as Joint2D, r as TileMap2D, s as Label, t as registerNodes2D, u as Camera2D, v as StaticBody2D, y as Node2D } from "./register-C6ZBFRjd.js";
|
|
4
|
+
import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-BLcvEFDR.js";
|
|
5
5
|
//#region src/2d/library-sprite.ts
|
|
6
6
|
/**
|
|
7
7
|
* What a `CharacterController2D`/`3D` will ask a skin to play, and the clip in
|
package/dist/3d.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { At as Node, D as QualityCaps, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, n as BehaviorCtor, w as GameStats } from "./behavior-
|
|
1
|
+
import { At as Node, D as QualityCaps, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, n as BehaviorCtor, w as GameStats } from "./behavior-l08AEbq9.js";
|
|
2
2
|
import { n as DiagnosticSink, t as EditorSwitchOptions } from "./editor-switch-DAvWQeld.js";
|
|
3
3
|
import { i as SceneJson$1, s as JsonObject } from "./schema-CFeioQRE.js";
|
|
4
|
-
import { t as
|
|
4
|
+
import { a as GridCell, c as diffText, d as frameText, i as FrameStatsOptions, l as frameSignature, n as FrameSignature, o as SIGNATURE_GRID, r as FrameStats, s as diffSignatures, t as FrameDiff, u as frameStats } from "./frame-report-DCnHFmto.js";
|
|
5
|
+
import { t as LoadSceneOptions } from "./loader-BbEMTuWg.js";
|
|
5
6
|
import { r as ParticleView, t as ParticleSim } from "./particle-sim-C5OfBbmU.js";
|
|
6
|
-
import {
|
|
7
|
-
import { n as PathGrid, s as SpatialPose } from "./pathfinding-CXGCpRQe.js";
|
|
7
|
+
import { n as PathGrid, s as SpatialPose } from "./pathfinding-mEN4V1CU.js";
|
|
8
8
|
import { AnimationClip, AnimationMixer, BufferGeometry, Color, DirectionalLight, Group, InstancedMesh, Mesh, MeshPhysicalMaterial, Object3D, PerspectiveCamera, Scene, ShaderMaterial, Texture, Vector3, WebGLRenderer } from "three";
|
|
9
9
|
import { VRM } from "@pixiv/three-vrm";
|
|
10
10
|
import { Sky } from "three/examples/jsm/objects/Sky.js";
|
|
@@ -902,6 +902,9 @@ declare class Environment3D {
|
|
|
902
902
|
/** Underwater fog/tint, created lazily the first time the camera submerges. */
|
|
903
903
|
private underwaterFog;
|
|
904
904
|
private readonly underwaterBg;
|
|
905
|
+
/** Told when the scene's HDRI/preset lighting fails to arrive. Set by the
|
|
906
|
+
* renderer, which is the piece that knows the engine and the asset store. */
|
|
907
|
+
onHdriError: ((url: string, error: unknown) => void) | null;
|
|
905
908
|
constructor(scene: Scene);
|
|
906
909
|
/** The sky's unit sun direction, or null when no sky is declared. */
|
|
907
910
|
get sunDirection(): [number, number, number] | null;
|
|
@@ -1141,6 +1144,21 @@ declare class BoneAttachment3D extends Node3D {
|
|
|
1141
1144
|
get attachedBone(): Object3D | null;
|
|
1142
1145
|
_onRender3D(_ctx: RenderContext3D): void;
|
|
1143
1146
|
override free(): void;
|
|
1147
|
+
/** The model this attachment last looked in. */
|
|
1148
|
+
private source;
|
|
1149
|
+
private reportedBone;
|
|
1150
|
+
/**
|
|
1151
|
+
* Say when the bone NAME is wrong, without accusing a model that is still
|
|
1152
|
+
* loading.
|
|
1153
|
+
*
|
|
1154
|
+
* The lookup retries every frame on purpose — a GLB mounts async — so the
|
|
1155
|
+
* node can never conclude on its own that the name is bad. But once the model
|
|
1156
|
+
* HAS bones and this one is not among them, it is a typo, and the list that
|
|
1157
|
+
* would fix it is sitting in `boneNames()` right next to `findBone`. Until
|
|
1158
|
+
* now a misspelled bone left the sword at the mount node's authored position
|
|
1159
|
+
* while the character animated away from it, forever, in silence.
|
|
1160
|
+
*/
|
|
1161
|
+
private reportMissingBone;
|
|
1144
1162
|
}
|
|
1145
1163
|
//#endregion
|
|
1146
1164
|
//#region src/3d/nodes/bone-look-at-3d.d.ts
|
|
@@ -1262,6 +1280,18 @@ declare class CharacterController3D extends Node3D {
|
|
|
1262
1280
|
private get body();
|
|
1263
1281
|
override onEnterTree(): void;
|
|
1264
1282
|
override fixedUpdate(dt: number): void;
|
|
1283
|
+
/** Actions already reported missing, so a per-frame read says it once. */
|
|
1284
|
+
private readonly reportedActions;
|
|
1285
|
+
/**
|
|
1286
|
+
* Read an input action this controller is allowed to be missing.
|
|
1287
|
+
*
|
|
1288
|
+
* Tolerated because a game may declare no sprint key and no jump; reported
|
|
1289
|
+
* because otherwise a TYPO looks exactly like a deliberate omission, and the
|
|
1290
|
+
* engine has already thrown the sentence that fixes it.
|
|
1291
|
+
*/
|
|
1292
|
+
private readAction;
|
|
1293
|
+
/** Report a throw the caller already caught (the move read has its own try). */
|
|
1294
|
+
private reportMissingAction;
|
|
1265
1295
|
override update(dt: number): void;
|
|
1266
1296
|
private pivot;
|
|
1267
1297
|
private cameraCache;
|
package/dist/3d.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { a as
|
|
4
|
-
import { a as
|
|
1
|
+
import { a as frameSignature, n as diffSignatures, o as frameStats, r as diffText, s as frameText, t as SIGNATURE_GRID } from "./frame-report-BSMny7oe.js";
|
|
2
|
+
import { B as StaticBody3D, F as WaterCutout3D, I as Area3D, L as CharacterBody3D, N as Water3D, P as WATER_CUTOUT_MAX, R as PhysicsBody3D, V as Node3D, W as WATER_MAX_RIPPLES, z as RigidBody3D } from "./gameplay-BVphcxmE.js";
|
|
3
|
+
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-CvvQr_bJ.js";
|
|
4
|
+
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-C5jQYPah.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-QBrfIT2Y.js";
|
|
7
7
|
//#region src/3d/model-verdict.ts
|
|
8
8
|
/** Mixamo exports every bone as `mixamorigX`; the retargeter binds by that name. */
|
|
9
9
|
const MIXAMO = /^mixamorig[:_]?/i;
|
|
@@ -465,6 +465,11 @@ declare class MusicManager {
|
|
|
465
465
|
* With an inert backend the state machine runs identically and nothing plays.
|
|
466
466
|
*/
|
|
467
467
|
private ensure;
|
|
468
|
+
/**
|
|
469
|
+
* Where a track that will never play gets reported. The engine sets this; a
|
|
470
|
+
* bare MusicManager (tests) stays quiet.
|
|
471
|
+
*/
|
|
472
|
+
onTrackError: ((src: string, reason: string) => void) | null;
|
|
468
473
|
/** Resume a gesture-suspended context + (re)start any pending track. */
|
|
469
474
|
unlock(): void;
|
|
470
475
|
/** Play a single track (replacing any current one immediately, no fade). */
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import { A as registerBehavior, C as diagnose, n as loadScene } from "./loader-
|
|
3
|
-
import {
|
|
2
|
+
import { A as registerBehavior, C as diagnose, n as loadScene } from "./loader-BcrRSjxB.js";
|
|
3
|
+
import { _ as Engine, g as AudioPlayer, x as qualityRendering, y as qualityCaps } from "./register-Ch70uByv.js";
|
|
4
4
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
5
|
-
import {
|
|
6
|
-
import { i as
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
5
|
+
import { i as resolveRendering, n as attachTouchControls } from "./touch-DESwnpOc.js";
|
|
6
|
+
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-Cs113S9F.js";
|
|
7
|
+
import { o as frameStats } from "./frame-report-BSMny7oe.js";
|
|
8
|
+
import { R as PhysicsBody3D, U as createCausticsQuad, V as Node3D, n as registerGameplayBehaviors } from "./gameplay-BVphcxmE.js";
|
|
9
9
|
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 {
|
|
12
|
-
import { n as enablePhysics3D } from "./physics-3d-C_ZJ6f_d.js";
|
|
10
|
+
import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-CvvQr_bJ.js";
|
|
11
|
+
import { n as enablePhysics3D } from "./physics-3d-QBrfIT2Y.js";
|
|
13
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";
|
|
14
13
|
import { VRMLoaderPlugin, VRMUtils } from "@pixiv/three-vrm";
|
|
15
14
|
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
|
|
@@ -1014,6 +1013,9 @@ var Environment3D = class {
|
|
|
1014
1013
|
/** Underwater fog/tint, created lazily the first time the camera submerges. */
|
|
1015
1014
|
underwaterFog = null;
|
|
1016
1015
|
underwaterBg = new Color();
|
|
1016
|
+
/** Told when the scene's HDRI/preset lighting fails to arrive. Set by the
|
|
1017
|
+
* renderer, which is the piece that knows the engine and the asset store. */
|
|
1018
|
+
onHdriError = null;
|
|
1017
1019
|
constructor(scene) {
|
|
1018
1020
|
this.scene = scene;
|
|
1019
1021
|
this.scene.add(this.ambient);
|
|
@@ -1161,6 +1163,8 @@ var Environment3D = class {
|
|
|
1161
1163
|
}
|
|
1162
1164
|
texture.mapping = EquirectangularReflectionMapping;
|
|
1163
1165
|
this.hdriTexture = texture;
|
|
1166
|
+
}, void 0, (error) => {
|
|
1167
|
+
this.onHdriError?.(url, error);
|
|
1164
1168
|
});
|
|
1165
1169
|
}
|
|
1166
1170
|
applySky(sky, gl) {
|
|
@@ -1575,7 +1579,14 @@ var Renderer3D = class {
|
|
|
1575
1579
|
};
|
|
1576
1580
|
webgl;
|
|
1577
1581
|
threeScene = new Scene();
|
|
1578
|
-
environment =
|
|
1582
|
+
environment = (() => {
|
|
1583
|
+
const env = new Environment3D(this.threeScene);
|
|
1584
|
+
env.onHdriError = (url, error) => {
|
|
1585
|
+
this.assets.textures.noteError(url, error);
|
|
1586
|
+
diagnose(this.engine, "error", `[incanto] the scene's lighting (${url}) could not be loaded — nothing else lights it.`);
|
|
1587
|
+
};
|
|
1588
|
+
return env;
|
|
1589
|
+
})();
|
|
1579
1590
|
engine;
|
|
1580
1591
|
disconnect;
|
|
1581
1592
|
canvas;
|
|
@@ -2500,67 +2511,13 @@ async function createGame3D(opts) {
|
|
|
2500
2511
|
watching = false;
|
|
2501
2512
|
return frames;
|
|
2502
2513
|
};
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
if (drive?.error) {
|
|
2511
|
-
hot.send("incanto:frame-report", {
|
|
2512
|
-
id,
|
|
2513
|
-
report: { error: drive.error }
|
|
2514
|
-
});
|
|
2515
|
-
return;
|
|
2516
|
-
}
|
|
2517
|
-
let droveFrames = null;
|
|
2518
|
-
(drive ? applyDrive(drive.steps) : Promise.resolve(null)).then((frames) => {
|
|
2519
|
-
droveFrames = frames;
|
|
2520
|
-
return captureFramePixels();
|
|
2521
|
-
}).then((shot) => hot.send("incanto:frame-report", {
|
|
2522
|
-
id,
|
|
2523
|
-
report: {
|
|
2524
|
-
...frameStats(shot.pixels, shot.width, shot.height, { grid: request?.grid }),
|
|
2525
|
-
signature: frameSignature(shot.pixels, shot.width, shot.height),
|
|
2526
|
-
...droveFrames === null ? {} : { droveFrames },
|
|
2527
|
-
...request?.image ? { image: frameImage(shot.pixels, shot.width, shot.height, (w, h) => Object.assign(document.createElement("canvas"), {
|
|
2528
|
-
width: w,
|
|
2529
|
-
height: h
|
|
2530
|
-
}), request.image) } : {}
|
|
2531
|
-
}
|
|
2532
|
-
})).catch((error) => hot.send("incanto:frame-report", {
|
|
2533
|
-
id,
|
|
2534
|
-
report: { error: error instanceof Error ? error.message : String(error) }
|
|
2535
|
-
}));
|
|
2536
|
-
};
|
|
2537
|
-
hot.on("incanto:frame-request", onFrameRequest);
|
|
2538
|
-
cleanups.push(() => hot.off?.("incanto:frame-request", onFrameRequest));
|
|
2539
|
-
const onLogsRequest = (data) => {
|
|
2540
|
-
const id = data?.id;
|
|
2541
|
-
try {
|
|
2542
|
-
hot.send("incanto:logs-report", {
|
|
2543
|
-
id,
|
|
2544
|
-
report: logReport({
|
|
2545
|
-
entries: engine.log.entries(),
|
|
2546
|
-
stats: {
|
|
2547
|
-
...engine.stats(),
|
|
2548
|
-
...renderer.stats?.() ?? {}
|
|
2549
|
-
},
|
|
2550
|
-
assetErrors: renderer.assets?.errors() ?? [],
|
|
2551
|
-
hidden: typeof document !== "undefined" && document.hidden
|
|
2552
|
-
})
|
|
2553
|
-
});
|
|
2554
|
-
} catch (error) {
|
|
2555
|
-
hot.send("incanto:logs-report", {
|
|
2556
|
-
id,
|
|
2557
|
-
report: { error: error instanceof Error ? error.message : String(error) }
|
|
2558
|
-
});
|
|
2559
|
-
}
|
|
2560
|
-
};
|
|
2561
|
-
hot.on("incanto:logs-request", onLogsRequest);
|
|
2562
|
-
cleanups.push(() => hot.off?.("incanto:logs-request", onLogsRequest));
|
|
2563
|
-
}
|
|
2514
|
+
cleanups.push(...wireDevChannel({
|
|
2515
|
+
engine,
|
|
2516
|
+
applyDrive,
|
|
2517
|
+
captureFramePixels,
|
|
2518
|
+
rendererStats: () => renderer.stats?.(),
|
|
2519
|
+
assetErrors: () => renderer.assets?.errors() ?? []
|
|
2520
|
+
}));
|
|
2564
2521
|
cleanups.push(pauseWhenHidden(engine));
|
|
2565
2522
|
await report(1, "ready");
|
|
2566
2523
|
function disposeGame() {
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import { A as registerBehavior, C as diagnose, n as loadScene, o as computeViewport, s as resolveViewport } from "./loader-
|
|
3
|
-
import {
|
|
2
|
+
import { A as registerBehavior, C as diagnose, n as loadScene, o as computeViewport, s as resolveViewport } from "./loader-BcrRSjxB.js";
|
|
3
|
+
import { _ as Engine, g as AudioPlayer } from "./register-Ch70uByv.js";
|
|
4
4
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
5
|
-
import { i as resolveRendering, n as attachTouchControls } from "./touch-
|
|
6
|
-
import { a as openBundledEditor, c as
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
5
|
+
import { i as resolveRendering, n as attachTouchControls } from "./touch-DESwnpOc.js";
|
|
6
|
+
import { a as openBundledEditor, c as claimCanvasGestures, i as devServerLibrary, l as audioErrors, n as pauseWhenHidden, r as crossFade, s as wireDevChannel, t as teardown } from "./teardown-Cs113S9F.js";
|
|
7
|
+
import { o as frameStats } from "./frame-report-BSMny7oe.js";
|
|
8
|
+
import { n as registerGameplayBehaviors } from "./gameplay-BVphcxmE.js";
|
|
9
|
+
import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-C6ZBFRjd.js";
|
|
9
10
|
import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
|
|
10
|
-
import { n as enablePhysics2D } from "./physics-2d-
|
|
11
|
+
import { n as enablePhysics2D } from "./physics-2d-BLcvEFDR.js";
|
|
11
12
|
import { Box3, BufferAttribute, BufferGeometry, Color, LineBasicMaterial, LineSegments, LinearFilter, NearestFilter, OrthographicCamera, Raycaster, SRGBColorSpace, Scene, TextureLoader, Vector2, Vector3, WebGLRenderer } from "three";
|
|
12
13
|
//#region src/2d/assets.ts
|
|
13
14
|
/**
|
|
@@ -276,6 +277,8 @@ function prune(obj, visited) {
|
|
|
276
277
|
* (center/zoom/limits), then a screen-space UI pass for UILayer subtrees.
|
|
277
278
|
* 1 unit = 1 px, (0,0) top-left, +y down.
|
|
278
279
|
*/
|
|
280
|
+
/** How long to wait for the game's own loop before drawing a frame ourselves. */
|
|
281
|
+
const CAPTURE_NUDGE_MS = 120;
|
|
279
282
|
var Renderer2D = class {
|
|
280
283
|
/**
|
|
281
284
|
* When set, the world pass frames THIS view instead of the scene's active
|
|
@@ -284,6 +287,76 @@ var Renderer2D = class {
|
|
|
284
287
|
*/
|
|
285
288
|
viewOverride = null;
|
|
286
289
|
webgl;
|
|
290
|
+
/**
|
|
291
|
+
* The pixels of the next drawn frame — how `incanto-frame` sees a 2D game.
|
|
292
|
+
*
|
|
293
|
+
* Mirrors Renderer3D exactly: read inside the render, so
|
|
294
|
+
* `preserveDrawingBuffer` can stay off, and nudge a frame ourselves after a
|
|
295
|
+
* moment because a browser stops handing rAF to a tab it thinks is hidden —
|
|
296
|
+
* including a window merely covered by another one. Without the nudge the
|
|
297
|
+
* promise never settles and the CLI reports "no page connected" about a page
|
|
298
|
+
* that is right there.
|
|
299
|
+
*/
|
|
300
|
+
captureFrame() {
|
|
301
|
+
return new Promise((resolve, reject) => {
|
|
302
|
+
this.pendingCaptures.push({
|
|
303
|
+
resolve,
|
|
304
|
+
reject
|
|
305
|
+
});
|
|
306
|
+
setTimeout(() => {
|
|
307
|
+
if (this.pendingCaptures.length > 0) try {
|
|
308
|
+
this.render();
|
|
309
|
+
} catch (error) {
|
|
310
|
+
const e = error instanceof Error ? error : new Error(String(error));
|
|
311
|
+
for (const w of this.pendingCaptures.splice(0)) w.reject(e);
|
|
312
|
+
}
|
|
313
|
+
}, CAPTURE_NUDGE_MS);
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
pendingCaptures = [];
|
|
317
|
+
/** Hand the waiting captures this frame's pixels. Called at the end of render. */
|
|
318
|
+
drainFrameCapture() {
|
|
319
|
+
if (this.pendingCaptures.length === 0) return;
|
|
320
|
+
const waiting = this.pendingCaptures;
|
|
321
|
+
this.pendingCaptures = [];
|
|
322
|
+
try {
|
|
323
|
+
const gl = this.webgl.getContext();
|
|
324
|
+
const width = this.webgl.domElement.width;
|
|
325
|
+
const height = this.webgl.domElement.height;
|
|
326
|
+
const pixels = new Uint8Array(width * height * 4);
|
|
327
|
+
this.webgl.setRenderTarget(null);
|
|
328
|
+
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
|
329
|
+
for (let y = 0; y < Math.floor(height / 2); y++) {
|
|
330
|
+
const top = y * width * 4;
|
|
331
|
+
const bottom = (height - 1 - y) * width * 4;
|
|
332
|
+
for (let i = 0; i < width * 4; i++) {
|
|
333
|
+
const t = pixels[top + i];
|
|
334
|
+
pixels[top + i] = pixels[bottom + i];
|
|
335
|
+
pixels[bottom + i] = t;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
for (const w of waiting) w.resolve({
|
|
339
|
+
pixels,
|
|
340
|
+
width,
|
|
341
|
+
height
|
|
342
|
+
});
|
|
343
|
+
} catch (error) {
|
|
344
|
+
const e = error instanceof Error ? error : new Error(String(error));
|
|
345
|
+
for (const w of waiting) w.reject(e);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
/** The pixel ratio the scene asked for, before any render-scale setting. */
|
|
349
|
+
basePixelRatio = 1;
|
|
350
|
+
/**
|
|
351
|
+
* Fewer pixels for the same world — the cheapest frames on a weak device.
|
|
352
|
+
*
|
|
353
|
+
* `settings.renderScale` persisted and was applied by the 3D boot only, so a
|
|
354
|
+
* 2D game's resolution slider saved a number and changed nothing, forever.
|
|
355
|
+
*/
|
|
356
|
+
setRenderScale(scale) {
|
|
357
|
+
const clamped = Number.isFinite(scale) && scale > 0 ? Math.min(2, Math.max(.25, scale)) : 1;
|
|
358
|
+
this.webgl.setPixelRatio(this.basePixelRatio * clamped);
|
|
359
|
+
}
|
|
287
360
|
worldScene = new Scene();
|
|
288
361
|
syncScratch = createSync2DScratch();
|
|
289
362
|
/** Editors set this: keep syncing `static: true` subtrees every frame. */
|
|
@@ -313,6 +386,7 @@ var Renderer2D = class {
|
|
|
313
386
|
});
|
|
314
387
|
this.webgl.info.autoReset = false;
|
|
315
388
|
this.engine.picker = (x, y) => this.pick(x, y);
|
|
389
|
+
this.basePixelRatio = rendering.pixelRatio;
|
|
316
390
|
this.webgl.setPixelRatio(rendering.pixelRatio);
|
|
317
391
|
this.webgl.info.autoReset = false;
|
|
318
392
|
this.debugLines = new LineSegments(new BufferGeometry(), new LineBasicMaterial({
|
|
@@ -447,6 +521,7 @@ var Renderer2D = class {
|
|
|
447
521
|
this.webgl.autoClear = false;
|
|
448
522
|
this.webgl.render(this.uiScene, this.uiCam);
|
|
449
523
|
this.webgl.autoClear = true;
|
|
524
|
+
this.drainFrameCapture();
|
|
450
525
|
}
|
|
451
526
|
/** UI-pass extent from the last render — the space HUD nodes are posed in. */
|
|
452
527
|
lastUi = {
|
|
@@ -663,6 +738,64 @@ async function createGame2D(opts) {
|
|
|
663
738
|
...opts.pixelRatio !== void 0 ? { pixelRatio: opts.pixelRatio } : {},
|
|
664
739
|
...opts.antialias !== void 0 ? { antialias: opts.antialias } : {}
|
|
665
740
|
});
|
|
741
|
+
cleanups.push(engine.settings.bindFrameCap((fps) => {
|
|
742
|
+
engine.maxFps = fps;
|
|
743
|
+
}));
|
|
744
|
+
cleanups.push(engine.settings.bindRenderScale((scale) => {
|
|
745
|
+
renderer.setRenderScale?.(scale);
|
|
746
|
+
}));
|
|
747
|
+
/**
|
|
748
|
+
* Feed the running game a drive script and count the frames it drew.
|
|
749
|
+
*
|
|
750
|
+
* Same as the 3D boot: the count travels with the report because a browser
|
|
751
|
+
* stops handing rAF to a hidden tab, and inputs landing on a game that never
|
|
752
|
+
* advances produce an UNCHANGED capture that says nothing about why.
|
|
753
|
+
*/
|
|
754
|
+
const applyDrive = async (steps) => {
|
|
755
|
+
let frames = 0;
|
|
756
|
+
let watching = true;
|
|
757
|
+
const tick = () => {
|
|
758
|
+
if (!watching) return;
|
|
759
|
+
frames += 1;
|
|
760
|
+
requestAnimationFrame(tick);
|
|
761
|
+
};
|
|
762
|
+
if (typeof requestAnimationFrame === "function") requestAnimationFrame(tick);
|
|
763
|
+
for (const step of steps) switch (step.kind) {
|
|
764
|
+
case "press":
|
|
765
|
+
engine.input.pressAction(step.action);
|
|
766
|
+
break;
|
|
767
|
+
case "release":
|
|
768
|
+
engine.input.releaseAction(step.action);
|
|
769
|
+
break;
|
|
770
|
+
case "vector":
|
|
771
|
+
engine.input.setActionVector(step.action, step.x, step.y);
|
|
772
|
+
break;
|
|
773
|
+
case "key":
|
|
774
|
+
engine.input.handleKey(step.code, step.down);
|
|
775
|
+
break;
|
|
776
|
+
case "pointer":
|
|
777
|
+
engine.input.handlePointerMove(step.dx, step.dy);
|
|
778
|
+
break;
|
|
779
|
+
case "step":
|
|
780
|
+
await new Promise((r) => setTimeout(r, step.ms));
|
|
781
|
+
break;
|
|
782
|
+
}
|
|
783
|
+
watching = false;
|
|
784
|
+
return frames;
|
|
785
|
+
};
|
|
786
|
+
cleanups.push(...wireDevChannel({
|
|
787
|
+
engine,
|
|
788
|
+
applyDrive,
|
|
789
|
+
captureFramePixels: () => {
|
|
790
|
+
const capture = renderer.captureFrame;
|
|
791
|
+
if (!capture) return Promise.reject(new IncantoError("TREE_VIOLATION", "this renderer cannot capture frames"));
|
|
792
|
+
return capture.call(renderer);
|
|
793
|
+
},
|
|
794
|
+
rendererStats: () => renderer.stats?.(),
|
|
795
|
+
assetErrors: () => {
|
|
796
|
+
return [...renderer.assets?.errors() ?? [], ...audioErrors(engine.scene?.tree.root)];
|
|
797
|
+
}
|
|
798
|
+
}));
|
|
666
799
|
const wantDebug = opts.debug ?? false;
|
|
667
800
|
const wantEditor = opts.editor ?? wantDebug;
|
|
668
801
|
const editorSwitch = wantEditor === true ? {} : wantEditor ? wantEditor : null;
|
|
@@ -727,6 +860,12 @@ async function createGame2D(opts) {
|
|
|
727
860
|
pick(x, y) {
|
|
728
861
|
return engine.picker?.(x, y) ?? null;
|
|
729
862
|
},
|
|
863
|
+
async frame(frameOpts) {
|
|
864
|
+
const capture = renderer.captureFrame;
|
|
865
|
+
if (!capture) throw new IncantoError("TREE_VIOLATION", "this renderer cannot capture frames");
|
|
866
|
+
const shot = await capture.call(renderer);
|
|
867
|
+
return frameStats(shot.pixels, shot.width, shot.height, frameOpts);
|
|
868
|
+
},
|
|
730
869
|
assetErrors() {
|
|
731
870
|
return [...renderer.assets?.errors() ?? [], ...audioErrors(engine.scene?.tree.root)];
|
|
732
871
|
},
|
package/dist/debug.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Pt as LogLevel, T as RendererStats, b as Engine } from "./behavior-
|
|
1
|
+
import { Pt as LogLevel, T as RendererStats, b as Engine } from "./behavior-l08AEbq9.js";
|
|
2
2
|
|
|
3
3
|
//#region src/debug/panel.d.ts
|
|
4
4
|
/** Minimal document surface the overlay needs (injectable for tests). */
|