incanto 0.60.0 → 0.61.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-check.mjs +13 -0
- package/dist/2d.d.ts +22 -3
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +5 -5
- package/dist/3d.js +5 -4
- package/dist/{pathfinding-BqWBb0kh.d.ts → audio-player-D5GJgb_x.d.ts} +103 -38
- package/dist/{behavior-DWKTUzKI.d.ts → behavior-DsgayMsH.d.ts} +79 -1
- package/dist/{create-game-ClnIb_M5.js → create-game-DH7JI5xx.js} +76 -11
- package/dist/{create-game-BCm38FJV.js → create-game-IX5lEH0P.js} +21 -294
- package/dist/debug.d.ts +1 -1
- package/dist/debug.js +1 -1
- package/dist/{duplicate-DJQd44CD.js → duplicate-CGqAmK2h.js} +1 -1
- package/dist/editor.js +2 -1
- package/dist/{environment-presets-8cjF3t6w.js → environment-presets-CNxCuhZF.js} +48 -13
- package/dist/{gameplay-BBEjPFsR.js → gameplay-Dtzd2itW.js} +53 -11
- package/dist/gameplay.d.ts +1 -1
- package/dist/gameplay.js +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +7 -7
- package/dist/{loader-D8n7TU8W.js → loader-D7jTvDQv.js} +797 -2
- package/dist/{loader-TvkRFbyL.d.ts → loader-DolLJWJn.d.ts} +13 -1
- package/dist/net.d.ts +2 -2
- package/dist/net.js +1 -1
- package/dist/pathfinding-_fGrCFmH.d.ts +28 -0
- package/dist/{physics-2d-DqdVp1bt.js → physics-2d-CBnor8Zf.js} +2 -2
- package/dist/{physics-3d-BP0DZb_1.js → physics-3d-BTUfUSWO.js} +3 -3
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-BSu2dWGC.js → register-DL3izw8j.js} +46 -9
- package/dist/{register-Da3hXh2H.js → register-xuSRyD6b.js} +72 -16
- package/dist/{registry-WWcQcfMr.js → registry-CF70EArN.js} +55 -3
- package/dist/{replay-BCMK_VRP.d.ts → replay-C5x2vPF5.d.ts} +2 -2
- package/dist/{replay-BlNuIDdg.js → replay-D7-yle3s.js} +44 -197
- package/dist/{split-screen-CL5Yvxse.js → split-screen-5Ban4q4n.js} +3 -3
- package/dist/{split-screen-BQ3tAsf-.d.ts → split-screen-D7OopelJ.d.ts} +2 -2
- package/dist/{src-DFpXBMJN.js → src-DozXvyZS.js} +1 -1
- package/dist/{teardown-CTTwhWSe.js → teardown-B6rwJOyS.js} +1 -1
- package/dist/{test-BeZ95pqw.js → test-Dch_7VQD.js} +15 -14
- package/dist/test.d.ts +8 -4
- package/dist/test.js +2 -2
- package/dist/vite.js +2 -2
- package/editor/assets/{agent8-DSJries_.js → agent8-CF1JL2tR.js} +1 -1
- package/editor/assets/{debug-D15Wi5TO.js → debug-3QzYhOPA.js} +1 -1
- package/editor/assets/{index-BjC88k97.js → index-CAD2c5ug.js} +92 -92
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +4 -0
- package/skills/incanto-3d-models.md +1 -1
- package/skills/incanto-assets.md +10 -1
- package/skills/incanto-audio.md +21 -13
- package/skills/incanto-behaviors-and-scripts.md +7 -3
- package/skills/incanto-building-2d-games.md +12 -3
- package/skills/incanto-editor.md +1 -1
- package/skills/incanto-gameplay-behaviors.md +24 -1
- package/skills/incanto-hud.md +5 -3
- package/skills/incanto-localization.md +7 -0
- package/skills/incanto-node-reference.md +1 -0
- package/skills/incanto-scene-json-authoring.md +6 -1
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/platformer-2d/package.json +1 -1
- package/templates-app/star-survivor/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/particle-sim-C5OfBbmU.d.ts +0 -77
package/bin/incanto-check.mjs
CHANGED
|
@@ -167,6 +167,15 @@ const { auditScene, validateScene } = await import(pathToFileURL(join(DIST, 'tes
|
|
|
167
167
|
* knowing what the project declares.
|
|
168
168
|
*/
|
|
169
169
|
const declaredElsewhere = {};
|
|
170
|
+
/**
|
|
171
|
+
* Every asset the project declares.
|
|
172
|
+
*
|
|
173
|
+
* A scene a spawner instantiates resolves its `$ref`s against the HOST's
|
|
174
|
+
* `assets{}` — `remote-player.scene.json` names `$characters/base` and declares
|
|
175
|
+
* nothing itself, which is correct. Checked alone it cannot resolve; checked as
|
|
176
|
+
* part of its project it can.
|
|
177
|
+
*/
|
|
178
|
+
const declaredAssets = {};
|
|
170
179
|
for (const file of files) {
|
|
171
180
|
try {
|
|
172
181
|
const doc = JSON.parse(readFileSync(file, 'utf-8'));
|
|
@@ -174,6 +183,9 @@ for (const file of files) {
|
|
|
174
183
|
if (typeof entries !== 'object' || entries === null) continue;
|
|
175
184
|
declaredElsewhere[locale] = { ...(declaredElsewhere[locale] ?? {}), ...entries };
|
|
176
185
|
}
|
|
186
|
+
for (const [key, entry] of Object.entries(doc?.assets ?? {})) {
|
|
187
|
+
if (typeof entry === 'object' && entry !== null) declaredAssets[key] ??= entry;
|
|
188
|
+
}
|
|
177
189
|
} catch {
|
|
178
190
|
/* a file that will not parse is reported below, on its own line */
|
|
179
191
|
}
|
|
@@ -188,6 +200,7 @@ const results = files.map((file) => {
|
|
|
188
200
|
}
|
|
189
201
|
const res = validateScene(json, {
|
|
190
202
|
strictBehaviors: args.strict,
|
|
203
|
+
declaredAssets,
|
|
191
204
|
resolveScene: (p) => JSON.parse(readFileSync(resolve(dirname(file), p), 'utf-8')),
|
|
192
205
|
});
|
|
193
206
|
if (res.ok) {
|
package/dist/2d.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, jt as Node, n as BehaviorCtor, w as GameStats } from "./behavior-DsgayMsH.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
4
|
import { r as FrameStats } from "./frame-report-DCnHFmto.js";
|
|
5
|
-
import { t as LoadSceneOptions } from "./loader-
|
|
5
|
+
import { t as LoadSceneOptions } from "./loader-DolLJWJn.js";
|
|
6
6
|
import { n as AnimationEntry } from "./sprite-animation-CMr6f1K2.js";
|
|
7
|
-
import {
|
|
7
|
+
import { i as ParticleSim, o as ParticleView, r as SpatialPose } from "./audio-player-D5GJgb_x.js";
|
|
8
8
|
import { Group, Mesh, Object3D, Scene, Texture } from "three";
|
|
9
9
|
import * as RapierNs from "@dimforge/rapier2d-compat";
|
|
10
10
|
|
|
@@ -701,6 +701,16 @@ declare class Label extends Node2D {
|
|
|
701
701
|
font: string;
|
|
702
702
|
/** 'left' | 'center' | 'right' — anchor of the text block on the node origin. */
|
|
703
703
|
align: string;
|
|
704
|
+
/**
|
|
705
|
+
* 0..1, like `Sprite2D` and `ColorRect2D`.
|
|
706
|
+
*
|
|
707
|
+
* Label was the one 2D drawable without it, and the gap showed up through
|
|
708
|
+
* `FloatAway` — whose own doc names "a 2D `Label`" as a node it works on.
|
|
709
|
+
* `FloatAway` writes `opacity` when the node has one, so on a Label the
|
|
710
|
+
* number rose to full height at FULL opacity and then vanished in a single
|
|
711
|
+
* frame: the pop that behavior exists to avoid.
|
|
712
|
+
*/
|
|
713
|
+
opacity: number;
|
|
704
714
|
private quadMesh;
|
|
705
715
|
private canvas;
|
|
706
716
|
private lastKey;
|
|
@@ -1081,6 +1091,15 @@ interface UiSize {
|
|
|
1081
1091
|
interface Sync2DScratch {
|
|
1082
1092
|
visited: Set<Object3D>;
|
|
1083
1093
|
cameras: Camera2D[];
|
|
1094
|
+
emitters: Array<{
|
|
1095
|
+
node: Node & SpatialConsumer;
|
|
1096
|
+
parent: Object3D;
|
|
1097
|
+
}>;
|
|
1098
|
+
}
|
|
1099
|
+
/** A node that accepts a per-frame spatial pose (an AudioPlayer with spatial on). */
|
|
1100
|
+
interface SpatialConsumer {
|
|
1101
|
+
spatial: boolean;
|
|
1102
|
+
_setSpatialPose(pose: SpatialPose): void;
|
|
1084
1103
|
}
|
|
1085
1104
|
declare function syncTree2D(root: Node, world: Scene, ui: Scene, assets: AssetStore2D | null, uiSize?: UiSize, scratch?: Sync2DScratch, opts?: {
|
|
1086
1105
|
ignoreStatic?: boolean;
|
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-DH7JI5xx.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-DL3izw8j.js";
|
|
4
|
+
import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-CBnor8Zf.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 {
|
|
1
|
+
import { D as QualityCaps, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, jt as Node, n as BehaviorCtor, w as GameStats } from "./behavior-DsgayMsH.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
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-
|
|
6
|
-
import {
|
|
7
|
-
import { n as PathGrid
|
|
5
|
+
import { t as LoadSceneOptions } from "./loader-DolLJWJn.js";
|
|
6
|
+
import { i as ParticleSim, o as ParticleView, r as SpatialPose } from "./audio-player-D5GJgb_x.js";
|
|
7
|
+
import { n as PathGrid } from "./pathfinding-_fGrCFmH.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";
|
|
@@ -730,7 +730,7 @@ interface Game3D {
|
|
|
730
730
|
*/
|
|
731
731
|
declare function createGame3D(opts: CreateGame3DOptions): Promise<Game3D>;
|
|
732
732
|
//#endregion
|
|
733
|
-
//#region src/
|
|
733
|
+
//#region src/core/scene/environment.d.ts
|
|
734
734
|
/**
|
|
735
735
|
* The 3D `environment` header, parsed and validated — the renderer's
|
|
736
736
|
* "rendering stage". Pure data in, plain data out (NO three imports), so the
|
package/dist/3d.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { c as parseEnvironment3D, l as sunDirectionFromElevationAzimuth, s as horizonColorFromSky, u as sunDirectionFromSky } from "./loader-D7jTvDQv.js";
|
|
1
2
|
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-
|
|
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-
|
|
4
|
-
import { a as Environment3D,
|
|
3
|
+
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-Dtzd2itW.js";
|
|
4
|
+
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-CNxCuhZF.js";
|
|
5
|
+
import { a as Environment3D, i as syncTree, o as setEnvironment3D, r as Renderer3D, s as AssetStore3D, t as createGame3D } from "./create-game-IX5lEH0P.js";
|
|
5
6
|
import { n as splatWeights, t as buildHeightmap } from "./heightmap-CRK0M4jT.js";
|
|
6
|
-
import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-
|
|
7
|
+
import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-BTUfUSWO.js";
|
|
7
8
|
//#region src/3d/model-verdict.ts
|
|
8
9
|
/** Mixamo exports every bone as `mixamorigX`; the retargeter binds by that name. */
|
|
9
10
|
const MIXAMO = /^mixamorig[:_]?/i;
|
|
@@ -1,5 +1,80 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as PropSchema, dt as Listener, jt as Node } from "./behavior-DsgayMsH.js";
|
|
2
|
+
import { a as Rng } from "./schema-CFeioQRE.js";
|
|
2
3
|
|
|
4
|
+
//#region src/core/particle-sim.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Deterministic particle pool — pure math, renderer-agnostic, headless-
|
|
7
|
+
* testable. 2D uses the xy plane (y-down, directionDeg 0 = +x, -90 = up);
|
|
8
|
+
* 3D feeds the same sim with a z spread.
|
|
9
|
+
*/
|
|
10
|
+
interface ParticleSimConfig {
|
|
11
|
+
/** Particles per second (0 = burst-only). */
|
|
12
|
+
rate: number;
|
|
13
|
+
/** Seconds, [min, max]. */
|
|
14
|
+
lifetime: [number, number];
|
|
15
|
+
/** Initial speed, [min, max] (units/sec — px in 2D, meters in 3D). */
|
|
16
|
+
speed: [number, number];
|
|
17
|
+
/** Emission direction center, degrees (0 = +x, -90 = up in y-down 2D). */
|
|
18
|
+
directionDeg: number;
|
|
19
|
+
/** Cone width, degrees (360 = all directions). */
|
|
20
|
+
spreadDeg: number;
|
|
21
|
+
/** Constant acceleration (y-down in 2D). */
|
|
22
|
+
gravity: [number, number, number];
|
|
23
|
+
/** Exponential velocity damping per second (0 = none). */
|
|
24
|
+
drag: number;
|
|
25
|
+
maxParticles: number;
|
|
26
|
+
/** Spread emission into the z axis too (3D). */
|
|
27
|
+
spreadZ?: boolean;
|
|
28
|
+
}
|
|
29
|
+
interface ParticleView {
|
|
30
|
+
x: number;
|
|
31
|
+
y: number;
|
|
32
|
+
z: number;
|
|
33
|
+
vx: number;
|
|
34
|
+
vy: number;
|
|
35
|
+
vz: number;
|
|
36
|
+
/** Seconds alive. */
|
|
37
|
+
age: number;
|
|
38
|
+
/** Total lifetime in seconds. */
|
|
39
|
+
life: number;
|
|
40
|
+
/** age/life in [0, 1] — drives size/color/alpha ramps. */
|
|
41
|
+
t: number;
|
|
42
|
+
/** Per-particle random in [0, 1) — stable for the particle's lifetime. */
|
|
43
|
+
seed: number;
|
|
44
|
+
}
|
|
45
|
+
declare class ParticleSim {
|
|
46
|
+
private readonly config;
|
|
47
|
+
private readonly rng;
|
|
48
|
+
private readonly data;
|
|
49
|
+
private alive;
|
|
50
|
+
private spawnAccumulator;
|
|
51
|
+
private everSpawned;
|
|
52
|
+
constructor(config: ParticleSimConfig, rng: Rng);
|
|
53
|
+
/**
|
|
54
|
+
* Shift every live particle — how world-space emission is done.
|
|
55
|
+
*
|
|
56
|
+
* The pool is in the emitter's LOCAL space, so a moving emitter drags its
|
|
57
|
+
* whole plume with it: dust glued to a running player instead of left behind,
|
|
58
|
+
* and the documented "move the emitter and replay" recipe for a one-shot
|
|
59
|
+
* teleporting the previous explosion across the level. Counter-translating by
|
|
60
|
+
* the emitter's own motion each frame leaves the particles where they were
|
|
61
|
+
* born, exactly, and costs one pass over the live ones.
|
|
62
|
+
*/
|
|
63
|
+
translateAll(dx: number, dy: number, dz: number): void;
|
|
64
|
+
/** Change the emission rate LIVE (particles/sec; 0 pauses emission) — lets an
|
|
65
|
+
* emitter toggle on/off at runtime (drift smoke, throttle flames). */
|
|
66
|
+
setRate(rate: number): void;
|
|
67
|
+
get count(): number;
|
|
68
|
+
/** True when nothing is alive and at least one particle has ever spawned. */
|
|
69
|
+
get done(): boolean;
|
|
70
|
+
/** Spawn n particles immediately (fireworks, explosions, flashes). */
|
|
71
|
+
burst(n: number): void;
|
|
72
|
+
update(dt: number): void;
|
|
73
|
+
forEach(fn: (p: ParticleView) => void): void;
|
|
74
|
+
private spawn;
|
|
75
|
+
private kill;
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
3
78
|
//#region src/core/nodes/audio-player.d.ts
|
|
4
79
|
/**
|
|
5
80
|
* The per-frame spatial feed the 3D adapter pushes onto a spatial AudioPlayer:
|
|
@@ -23,7 +98,7 @@ interface AudioElementLike {
|
|
|
23
98
|
}
|
|
24
99
|
/**
|
|
25
100
|
* One sound. `play()` (or `autoplay: true`) starts it; `finished` fires when
|
|
26
|
-
* it ends. Browsers block audio before the first user gesture — a blocked
|
|
101
|
+
* it ends — for a procedural preset as well as a `src` clip. Browsers block audio before the first user gesture — a blocked
|
|
27
102
|
* play marks `pendingGesture`; `createGame` retries pending players on the
|
|
28
103
|
* first pointer/key gesture automatically.
|
|
29
104
|
*
|
|
@@ -58,10 +133,12 @@ declare class AudioPlayer extends Node {
|
|
|
58
133
|
/** Start on the first frame in the tree (subject to the gesture policy). */
|
|
59
134
|
autoplay: boolean;
|
|
60
135
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
136
|
+
* Positional audio: the sound pans + attenuates by the emitter's world
|
|
137
|
+
* position relative to the active camera (the listener). Default false →
|
|
138
|
+
* identical non-spatial behavior.
|
|
139
|
+
*
|
|
140
|
+
* Both dimensions. A 2D scene measures in PIXELS, so the distances below —
|
|
141
|
+
* metre-shaped defaults — need setting there; `auditScene` says so.
|
|
65
142
|
*/
|
|
66
143
|
spatial: boolean;
|
|
67
144
|
/** Distance at which spatial gain is full; closer never gets louder. */
|
|
@@ -81,6 +158,21 @@ declare class AudioPlayer extends Node {
|
|
|
81
158
|
loadError: string | null;
|
|
82
159
|
private element;
|
|
83
160
|
private _playing;
|
|
161
|
+
/**
|
|
162
|
+
* `engine.unscaledTime` at which the preset currently sounding ends.
|
|
163
|
+
*
|
|
164
|
+
* A preset used to be fire-and-forget: `playing` stayed false through a sound
|
|
165
|
+
* that was audibly playing, and `finished` — a signal this node DECLARES, so
|
|
166
|
+
* a connection to it loads clean — never fired at all. Wiring "when the coin
|
|
167
|
+
* chime ends, free the pickup" to a preset player produced a wire that is
|
|
168
|
+
* dead for the life of the game and says nothing.
|
|
169
|
+
*
|
|
170
|
+
* The end is known exactly: `attack + sustain + decay` is the length
|
|
171
|
+
* `synthSfx` sizes its buffer to. Measured on the UNSCALED clock because a
|
|
172
|
+
* sound does not slow down when the game does, and a paused game still hears
|
|
173
|
+
* the tail of the hit that paused it.
|
|
174
|
+
*/
|
|
175
|
+
private presetEndsAt;
|
|
84
176
|
private autoplayed;
|
|
85
177
|
/** Last spatial pose pushed by the 3D adapter (null until/unless spatial). */
|
|
86
178
|
private _spatialPose;
|
|
@@ -108,10 +200,10 @@ declare class AudioPlayer extends Node {
|
|
|
108
200
|
play(): void;
|
|
109
201
|
/**
|
|
110
202
|
* Procedural-SFX path: synthesize the preset and fire it through WebAudio
|
|
111
|
-
* (low-latency, overlap-friendly).
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
203
|
+
* (low-latency, overlap-friendly). Headless (no AudioContext) plays nothing —
|
|
204
|
+
* but still reports `playing` and still emits `finished` on schedule, because
|
|
205
|
+
* the length is arithmetic, not a device. WebAudio needs a gesture; a
|
|
206
|
+
* suspended context is resumed by the same unlock listener as `src` players.
|
|
115
207
|
*/
|
|
116
208
|
private playPreset;
|
|
117
209
|
/**
|
|
@@ -130,31 +222,4 @@ declare class AudioPlayer extends Node {
|
|
|
130
222
|
override update(_dt: number): void;
|
|
131
223
|
}
|
|
132
224
|
//#endregion
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Grid A* — the pathfinding every top-down/RPG/tower-defense asks for and
|
|
136
|
-
* agents keep re-inventing badly. Pure and dimension-free: cells in, cells
|
|
137
|
-
* out; the caller maps cells to world units (px, meters, tiles).
|
|
138
|
-
*/
|
|
139
|
-
interface PathGrid {
|
|
140
|
-
width: number;
|
|
141
|
-
height: number;
|
|
142
|
-
/** True = impassable. Out-of-bounds is always solid. */
|
|
143
|
-
solid(x: number, y: number): boolean;
|
|
144
|
-
}
|
|
145
|
-
interface FindPathOptions {
|
|
146
|
-
/** Allow diagonal steps (blocked from cutting corners). Default true. */
|
|
147
|
-
diagonal?: boolean;
|
|
148
|
-
/** Abort guard for huge/impossible searches. Default 20000 nodes. */
|
|
149
|
-
maxExpansions?: number;
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* A* from `from` to `to` (inclusive cell coords). Returns the cell path
|
|
153
|
-
* INCLUDING both endpoints, or null when unreachable. Straight steps cost
|
|
154
|
-
* 1, diagonals √2; the heuristic is octile (admissible for both modes).
|
|
155
|
-
*/
|
|
156
|
-
declare function findPath(grid: PathGrid, from: [number, number], to: [number, number], opts?: FindPathOptions): [number, number][] | null;
|
|
157
|
-
/** Build a PathGrid from row-strings ('#' = solid) — tests and tile games. */
|
|
158
|
-
declare function gridFromRows(rows: readonly string[]): PathGrid;
|
|
159
|
-
//#endregion
|
|
160
|
-
export { AudioElementLike as a, gridFromRows as i, PathGrid as n, AudioPlayer as o, findPath as r, SpatialPose as s, FindPathOptions as t };
|
|
225
|
+
export { ParticleSimConfig as a, ParticleSim as i, AudioPlayer as n, ParticleView as o, SpatialPose as r, AudioElementLike as t };
|
|
@@ -551,6 +551,14 @@ interface SynthOptions {
|
|
|
551
551
|
seed?: number;
|
|
552
552
|
}
|
|
553
553
|
/**
|
|
554
|
+
* How long a preset lasts, in seconds — the same `attack + sustain + decay`
|
|
555
|
+
* `synthSfx` uses to size its buffer.
|
|
556
|
+
*
|
|
557
|
+
* `pitch` deliberately does not enter into it: it is a frequency multiplier,
|
|
558
|
+
* not a playback rate, so a preset played an octave up is the same length.
|
|
559
|
+
*/
|
|
560
|
+
declare function sfxDuration(params: SfxParams): number;
|
|
561
|
+
/**
|
|
554
562
|
* Render a preset to mono PCM in [-1, 1]. PURE: identical inputs → identical
|
|
555
563
|
* output (the only randomness is the seeded noise generator), so determinism is
|
|
556
564
|
* unit-testable headlessly. Length = ceil((attack+sustain+decay) * sampleRate).
|
|
@@ -1780,6 +1788,44 @@ declare class Engine {
|
|
|
1780
1788
|
tick(nowMs: number): void;
|
|
1781
1789
|
}
|
|
1782
1790
|
//#endregion
|
|
1791
|
+
//#region src/core/prop-range.d.ts
|
|
1792
|
+
/**
|
|
1793
|
+
* The numeric range a prop documents, checked at LOAD.
|
|
1794
|
+
*
|
|
1795
|
+
* The docs give ranges constantly — `metalness`/`roughness` "0..1 … `-1` = keep
|
|
1796
|
+
* authored", `targetHeight` "> 0 uniformly scales the model", `opacity` 0..1 —
|
|
1797
|
+
* and the schema had no way to say so, so every one was a type check and
|
|
1798
|
+
* nothing more. Measured on `ModelInstance3D`:
|
|
1799
|
+
*
|
|
1800
|
+
* ```
|
|
1801
|
+
* targetHeight: -1.8 NO ERROR (kept -1.8)
|
|
1802
|
+
* metalness: 5 NO ERROR (kept 5)
|
|
1803
|
+
* roughness: -3 NO ERROR (kept -3)
|
|
1804
|
+
* ```
|
|
1805
|
+
*
|
|
1806
|
+
* The two failure modes differ, which is why neither is noticed. A negative
|
|
1807
|
+
* `targetHeight` folds into the same branch as "not set", so the model keeps
|
|
1808
|
+
* its authored size and looks like the prop did nothing; `metalness: 5` reaches
|
|
1809
|
+
* three and the surface goes wrong. An author who mistypes a decimal point gets
|
|
1810
|
+
* a different wrong answer depending on which prop they mistyped it in, and no
|
|
1811
|
+
* message in either case.
|
|
1812
|
+
*/
|
|
1813
|
+
interface PropRange {
|
|
1814
|
+
/** Lowest accepted value. */
|
|
1815
|
+
min?: number;
|
|
1816
|
+
/** Highest accepted value. */
|
|
1817
|
+
max?: number;
|
|
1818
|
+
/** `min` is a bound the value must EXCEED, not reach (`targetHeight > 0`). */
|
|
1819
|
+
exclusiveMin?: boolean;
|
|
1820
|
+
/**
|
|
1821
|
+
* Values outside the range that mean something anyway.
|
|
1822
|
+
*
|
|
1823
|
+
* `metalness: -1` is "keep whatever the GLB authored" — a real value with a
|
|
1824
|
+
* real meaning, and the reason a range cannot just be a clamp.
|
|
1825
|
+
*/
|
|
1826
|
+
allow?: readonly number[];
|
|
1827
|
+
}
|
|
1828
|
+
//#endregion
|
|
1783
1829
|
//#region src/core/registry.d.ts
|
|
1784
1830
|
/** A node prop definition. The default both documents and types the prop. */
|
|
1785
1831
|
interface PropDef {
|
|
@@ -1808,6 +1854,38 @@ interface PropDef {
|
|
|
1808
1854
|
*/
|
|
1809
1855
|
required?: boolean;
|
|
1810
1856
|
/**
|
|
1857
|
+
* This prop names an entry in the scene's `assets{}` block.
|
|
1858
|
+
*
|
|
1859
|
+
* Declaring it is what makes a typo a LOAD error. The check already existed —
|
|
1860
|
+
* `AssetStore2D.resolve` throws `UNKNOWN_ASSET` — and it runs inside the
|
|
1861
|
+
* renderer, in a browser, when the texture is first needed. Headless the
|
|
1862
|
+
* scene loaded clean, so `incanto-check` certified a sprite that will draw
|
|
1863
|
+
* nothing, and the docs' promise that "the engine hard-fails on a raw URL"
|
|
1864
|
+
* was not true anywhere an author could see it.
|
|
1865
|
+
*
|
|
1866
|
+
* The same story as `nodePath` and `required`: the rule existed, nothing
|
|
1867
|
+
* routed to it at author time.
|
|
1868
|
+
*/
|
|
1869
|
+
/**
|
|
1870
|
+
* The numeric range this prop documents.
|
|
1871
|
+
*
|
|
1872
|
+
* Without it a documented range is prose only: `metalness: 5` and
|
|
1873
|
+
* `targetHeight: -1.8` both passed the kind check and then failed in two
|
|
1874
|
+
* different silent ways. See prop-range.
|
|
1875
|
+
*/
|
|
1876
|
+
range?: PropRange;
|
|
1877
|
+
asset?: {
|
|
1878
|
+
/** The `assets{}` entry `type` a `$ref` here must point at. */kind: "texture" | "spritesheet" | "model" | "animation";
|
|
1879
|
+
/**
|
|
1880
|
+
* A value that is not a `$ref` is an error.
|
|
1881
|
+
*
|
|
1882
|
+
* False for props that legitimately take something else — a raw URL
|
|
1883
|
+
* (`UiImage.src`, `Sprite3D.texture`) or the name of a clip baked into a
|
|
1884
|
+
* GLB (`ModelInstance3D.animation`).
|
|
1885
|
+
*/
|
|
1886
|
+
refOnly?: boolean;
|
|
1887
|
+
};
|
|
1888
|
+
/**
|
|
1811
1889
|
* For an OBJECT-valued prop shaped as a tagged union — `collider`, whose
|
|
1812
1890
|
* `shape` decides which other keys are required. One declaration gives an
|
|
1813
1891
|
* inspector both the dropdown AND something valid to write when the tag
|
|
@@ -1943,4 +2021,4 @@ declare function registeredBehaviors(): string[];
|
|
|
1943
2021
|
/** Test isolation helper. */
|
|
1944
2022
|
declare function clearBehaviors(): void;
|
|
1945
2023
|
//#endregion
|
|
1946
|
-
export { T_PREFIX as $, SettingsValues as A,
|
|
2024
|
+
export { T_PREFIX as $, SettingsValues as A, BusName as At, captureBehaviors as B, EngineStats as C, sfxDuration as Ct, QualityCaps as D, MusicTrack as Dt, DeviceHints as E, MusicManager as Et, BehaviorState as F, LogLevel as Ft, ORDER_GROUP_BASE as G, savesWithoutUid as H, RestoreReport as I, LogManager as It, effectiveOrder as J, OrderGroup as K, SaveSlot as L, Signal as Lt, readDeviceHints as M, NodeLifecycle as Mt, suggestQuality as N, SceneTree as Nt, QualityTier as O, PlayMusicOptions as Ot, Scene as P, LogEntry as Pt, Localization as Q, SaveSlots as R, SignalListener as Rt, Scheduler as S, SynthOptions as St, RendererStats as T, MusicBackend as Tt, SaveStore as U, restoreBehaviors as V, createSaveStore as W, BASE_LOCALE as X, resolveOrderGroups as Y, LocaleTables as Z, mergeStaticSignals as _, spatialPan as _t, clearBehaviors as a, EffectLog as at, Engine as b, SfxParams as bt, registeredBehaviors as c, isAudioContextAvailable as ct, PropSchema as d, Listener as dt, suggestLocale as et, clearRegistry as f, ROLLOFF_MODELS as ft, getNodeType as g, spatialGain as gt, getNodeSignals as h, Vec3 as ht, behaviorSignals as i, EffectKind as it, qualityEnvironment as j, Node as jt, Settings as k, AudioBuses as kt, NodeCtor as l, Voice as lt, getNodeSchema as m, SpatialParams as mt, BehaviorCtor as n, InputMap as nt, getBehavior as o, SfxEngine as ot, createNode as p, RolloffModel as pt, OrderGroupTable as q, behaviorSchema as r, EffectEvent as rt, registerBehavior as s, SfxPlayOptions as st, Behavior as t, translationKey as tt, PropDef as u, VoicePreset as ut, registerNode as v, SFX_PRESETS as vt, GameStats as w, synthSfx as wt, EngineOptions as x, SfxWave as xt, registeredTypes as y, SFX_PRESET_NAMES as yt, behaviorsWithoutSave as z };
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import {
|
|
3
|
-
import { _ as Engine, g as AudioPlayer } from "./register-
|
|
2
|
+
import { d as computeViewport, f as resolveViewport, k as diagnose, n as loadScene, z as registerBehavior } from "./loader-D7jTvDQv.js";
|
|
3
|
+
import { _ as Engine, g as AudioPlayer } from "./register-xuSRyD6b.js";
|
|
4
4
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
5
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-
|
|
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-B6rwJOyS.js";
|
|
7
7
|
import { o as frameStats } from "./frame-report-BSMny7oe.js";
|
|
8
|
-
import { n as registerGameplayBehaviors } from "./gameplay-
|
|
9
|
-
import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-
|
|
8
|
+
import { n as registerGameplayBehaviors } from "./gameplay-Dtzd2itW.js";
|
|
9
|
+
import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-DL3izw8j.js";
|
|
10
10
|
import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
|
|
11
|
-
import { n as enablePhysics2D } from "./physics-2d-
|
|
11
|
+
import { n as enablePhysics2D } from "./physics-2d-CBnor8Zf.js";
|
|
12
12
|
import { Box3, BufferAttribute, BufferGeometry, Color, LineBasicMaterial, LineSegments, LinearFilter, NearestFilter, OrthographicCamera, Raycaster, SRGBColorSpace, Scene, TextureLoader, Vector2, Vector3, WebGLRenderer } from "three";
|
|
13
13
|
//#region src/2d/assets.ts
|
|
14
14
|
/**
|
|
@@ -199,14 +199,19 @@ function selectionOutline2D(node) {
|
|
|
199
199
|
function createSync2DScratch() {
|
|
200
200
|
return {
|
|
201
201
|
visited: /* @__PURE__ */ new Set(),
|
|
202
|
-
cameras: []
|
|
202
|
+
cameras: [],
|
|
203
|
+
emitters: []
|
|
203
204
|
};
|
|
204
205
|
}
|
|
206
|
+
function isSpatialConsumer(node) {
|
|
207
|
+
return node.spatial === true && typeof node._setSpatialPose === "function";
|
|
208
|
+
}
|
|
205
209
|
function syncTree2D(root, world, ui, assets, uiSize, scratch, opts) {
|
|
206
210
|
const s = scratch ?? createSync2DScratch();
|
|
207
211
|
s.visited.clear();
|
|
208
212
|
s.cameras.length = 0;
|
|
209
|
-
|
|
213
|
+
s.emitters.length = 0;
|
|
214
|
+
walk(root, world, ui, false, s.visited, s.cameras, s.emitters, assets, uiSize, opts?.ignoreStatic === true);
|
|
210
215
|
prune(world, s.visited);
|
|
211
216
|
prune(ui, s.visited);
|
|
212
217
|
let current = null;
|
|
@@ -218,9 +223,66 @@ function syncTree2D(root, world, ui, assets, uiSize, scratch, opts) {
|
|
|
218
223
|
}
|
|
219
224
|
}
|
|
220
225
|
if (!current) current = s.cameras[0] ?? null;
|
|
226
|
+
feedSpatialEmitters2D(s.emitters, current);
|
|
221
227
|
return { activeCamera: current };
|
|
222
228
|
}
|
|
223
|
-
|
|
229
|
+
const emitterScratch = new Vector3();
|
|
230
|
+
const listenerScratch = new Vector3();
|
|
231
|
+
const upScratch = new Vector3();
|
|
232
|
+
/**
|
|
233
|
+
* Give a 2D scene's spatial AudioPlayers the same per-frame pose the 3D sync
|
|
234
|
+
* gives its own.
|
|
235
|
+
*
|
|
236
|
+
* `spatial`, `refDistance`, `maxDistance` and `rolloff` have been props of
|
|
237
|
+
* `AudioPlayer` since positional audio landed, and in a 2D scene all four did
|
|
238
|
+
* NOTHING: the node only attenuates when an adapter pushes it a pose, and only
|
|
239
|
+
* the 3D one ever did. The scene loaded, `incanto check` said valid, and the
|
|
240
|
+
* sound played at full volume from the far side of the level.
|
|
241
|
+
*
|
|
242
|
+
* The listener is the active `Camera2D` — its world position is the view
|
|
243
|
+
* centre, its own rotation turns the stereo image with it, and the view looks
|
|
244
|
+
* down −Z like every other camera. Distances are therefore in the same units
|
|
245
|
+
* the rest of a 2D scene is in: PIXELS. `refDistance: 1` / `maxDistance: 50`
|
|
246
|
+
* are metre-shaped defaults and read as "silent one sprite away" here, so a 2D
|
|
247
|
+
* scene has to set them; `auditScene` says so when it sees the defaults.
|
|
248
|
+
*/
|
|
249
|
+
function feedSpatialEmitters2D(emitters, camera) {
|
|
250
|
+
if (emitters.length === 0 || !camera) return;
|
|
251
|
+
const view = camera._ensureObject2D();
|
|
252
|
+
view.updateWorldMatrix(true, false);
|
|
253
|
+
view.getWorldPosition(listenerScratch);
|
|
254
|
+
upScratch.set(0, 1, 0).applyQuaternion(view.quaternion);
|
|
255
|
+
const listener = {
|
|
256
|
+
position: [
|
|
257
|
+
listenerScratch.x,
|
|
258
|
+
listenerScratch.y,
|
|
259
|
+
0
|
|
260
|
+
],
|
|
261
|
+
forward: [
|
|
262
|
+
0,
|
|
263
|
+
0,
|
|
264
|
+
-1
|
|
265
|
+
],
|
|
266
|
+
up: [
|
|
267
|
+
upScratch.x,
|
|
268
|
+
upScratch.y,
|
|
269
|
+
upScratch.z
|
|
270
|
+
]
|
|
271
|
+
};
|
|
272
|
+
for (const { node, parent } of emitters) {
|
|
273
|
+
parent.updateWorldMatrix(true, false);
|
|
274
|
+
parent.getWorldPosition(emitterScratch);
|
|
275
|
+
node._setSpatialPose({
|
|
276
|
+
position: [
|
|
277
|
+
emitterScratch.x,
|
|
278
|
+
emitterScratch.y,
|
|
279
|
+
0
|
|
280
|
+
],
|
|
281
|
+
listener
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
function walk(node, parentObj, ui, inUi, visited, cameras, emitters, assets, uiSize, ignoreStatic) {
|
|
224
286
|
let nextParent = parentObj;
|
|
225
287
|
let nextInUi = inUi;
|
|
226
288
|
if (node instanceof Node2D && !(node instanceof UILayer)) {
|
|
@@ -249,8 +311,11 @@ function walk(node, parentObj, ui, inUi, visited, cameras, assets, uiSize, ignor
|
|
|
249
311
|
visited.add(obj);
|
|
250
312
|
if (node instanceof Camera2D && !inUi) cameras.push(node);
|
|
251
313
|
nextParent = obj;
|
|
252
|
-
}
|
|
253
|
-
|
|
314
|
+
} else if (isSpatialConsumer(node)) emitters.push({
|
|
315
|
+
node,
|
|
316
|
+
parent: nextParent
|
|
317
|
+
});
|
|
318
|
+
for (const child of node.children) walk(child, nextParent, ui, nextInUi, visited, cameras, emitters, assets, uiSize, ignoreStatic);
|
|
254
319
|
if (node instanceof Node2D && !(node instanceof UILayer)) {
|
|
255
320
|
const obj = node._ensureObject2D();
|
|
256
321
|
if (node.static && !ignoreStatic) {
|