incanto 0.51.0 → 0.53.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/dist/2d.d.ts +86 -3
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +9 -3
- package/dist/3d.js +4 -4
- package/dist/{behavior-rZNfzVbH.d.ts → behavior-Do0Da56m.d.ts} +108 -0
- package/dist/{create-game-CkzKZ4v5.js → create-game-9D87XaiX.js} +112 -15
- package/dist/{create-game-BNaOC3Px.js → create-game-CDJ1lVqK.js} +21 -13
- package/dist/debug.d.ts +1 -1
- package/dist/debug.js +1 -1
- package/dist/{duplicate-EybyYeyL.js → duplicate-MNLMAcbz.js} +1 -1
- package/dist/editor.js +1931 -1579
- package/dist/{environment-presets-C08pOC6H.js → environment-presets-SkGanr2s.js} +3 -3
- package/dist/{gameplay-bStgtZBV.js → gameplay-CRYw_Q-T.js} +6 -4
- package/dist/gameplay.d.ts +1 -1
- package/dist/gameplay.js +1 -1
- package/dist/index.d.ts +237 -5
- package/dist/index.js +9 -9
- package/dist/{loader-B2asghWa.js → loader-BTkHYrQn.js} +86 -50
- package/dist/{loader-Dkbn56KC.d.ts → loader-Cu_7kJDy.d.ts} +1 -1
- package/dist/{log-report-lxrQY9cH.js → log-report-CPFm4OXf.js} +0 -0
- package/dist/net.d.ts +15 -410
- package/dist/net.js +1 -822
- package/dist/{pathfinding-Bz34pvQD.d.ts → pathfinding-HNGFqGUZ.d.ts} +24 -1
- package/dist/{physics-2d-Ccq2L9R0.js → physics-2d-BhZZ-HAp.js} +2 -2
- package/dist/{physics-3d-B2c5KNYh.js → physics-3d-DmyO2oaN.js} +3 -3
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-CGq-Hee8.js → register-BTomIiYG.js} +305 -25
- package/dist/{register-B_BaaGx-.js → register-DROK2l7J.js} +3 -3
- package/dist/{registry-IyWCGe4q.js → registry-C7u42TID.js} +23 -1
- package/dist/{replay-DIP2_as4.d.ts → replay-9Fy6C10F.d.ts} +1 -1
- package/dist/{replay-BgKxGcXH.js → replay-DYNUL4BU.js} +195 -2
- package/dist/split-screen-CaF9hO7g.js +1267 -0
- package/dist/split-screen-DNmcX1Pz.d.ts +441 -0
- package/dist/{src-C3UwzYXl.js → src-C9xyZW7M.js} +1 -1
- package/dist/{teardown-BKTCzLek.js → teardown-Bw2aeyGI.js} +32 -2
- package/dist/{test-D2gRpk5V.js → test-CJRsciFk.js} +119 -22
- package/dist/test.d.ts +60 -5
- package/dist/test.js +3 -3
- package/dist/{touch-BoNg_MnF.js → touch-BnMyy9tr.js} +4 -4
- package/dist/vite.js +2 -2
- package/editor/assets/{agent8-DbX_msaO.js → agent8-PlFHzJsh.js} +1 -1
- package/editor/assets/{debug-C-kMxdl1.js → debug-CebV7CDW.js} +1 -1
- package/editor/assets/index-CdbsY31G.js +10958 -0
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +213 -0
- package/skills/incanto-assets.md +4 -1
- package/skills/incanto-audio.md +97 -10
- package/skills/incanto-building-2d-games.md +20 -3
- package/skills/incanto-editor.md +48 -11
- package/skills/incanto-gameplay-behaviors.md +14 -5
- package/skills/incanto-hud.md +7 -0
- package/skills/incanto-multiplayer.md +39 -3
- package/skills/incanto-node-reference.md +34 -0
- package/skills/incanto-physics-and-input.md +38 -0
- package/skills/incanto-verifying-your-game.md +75 -1
- package/skills/incanto-web-integration.md +1 -0
- package/templates/agent8-server.ts +79 -2
- package/templates-app/beacon-isle-3d/index.html +3 -3
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/tps-3d/index.html +3 -3
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/village-quest-3d/index.html +3 -3
- package/templates-app/village-quest-3d/package.json +1 -1
- package/dist/register-CLVhzWcI.js +0 -374
- package/editor/assets/index-CUc1U7wm.js +0 -10951
package/dist/2d.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Dt 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 { Dt 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-Do0Da56m.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 { t as LoadSceneOptions } from "./loader-
|
|
4
|
+
import { t as LoadSceneOptions } from "./loader-Cu_7kJDy.js";
|
|
5
5
|
import { n as AnimationEntry } from "./sprite-animation-CMr6f1K2.js";
|
|
6
6
|
import { t as ParticleSim } from "./particle-sim-BzJ1yxoE.js";
|
|
7
7
|
import { Group, Mesh, Object3D, Scene, Texture } from "three";
|
|
@@ -36,6 +36,19 @@ declare class AssetStore2D {
|
|
|
36
36
|
constructor(loader?: (url: string, callbacks?: TextureLoadCallbacks) => Texture, engine?: DiagnosticSink | null);
|
|
37
37
|
/** Load (or extend with) a scene's `assets` declarations. Hard-validates each entry. */
|
|
38
38
|
load(assets: Record<string, JsonObject>): void;
|
|
39
|
+
/**
|
|
40
|
+
* Every declared asset that FAILED to load, `$ref` and url included.
|
|
41
|
+
*
|
|
42
|
+
* The 3D store has answered this since 0.32.0 — the 2D one only tracked a
|
|
43
|
+
* per-key status, which the console printed and nothing else could read. A
|
|
44
|
+
* 404'd texture is invisible, and "invisible" is the one symptom an author
|
|
45
|
+
* cannot tell apart from "I put it in the wrong place".
|
|
46
|
+
*/
|
|
47
|
+
errors(): Array<{
|
|
48
|
+
ref: string;
|
|
49
|
+
url: string;
|
|
50
|
+
error: string;
|
|
51
|
+
}>;
|
|
39
52
|
/** Load status of a declared asset KEY (no '$'), or undefined if unknown. */
|
|
40
53
|
status(key: string): AssetStatus | undefined;
|
|
41
54
|
getTexture(ref: string): Texture;
|
|
@@ -291,7 +304,21 @@ interface CreateGame2DOptions {
|
|
|
291
304
|
* false disables. They overlay `touchContainer` (default: the canvas's
|
|
292
305
|
* parent element — give it position: relative).
|
|
293
306
|
*/
|
|
307
|
+
/**
|
|
308
|
+
* Attach pointer input (mouse, finger or pen) to the canvas: positions for
|
|
309
|
+
* `input.pointerPosition()`, buttons for `input.mousePressed()`.
|
|
310
|
+
* `{ lockOnClick: true }` captures the cursor — rare in 2D, so it is off.
|
|
311
|
+
*/
|
|
312
|
+
pointer?: boolean | {
|
|
313
|
+
lockOnClick?: boolean;
|
|
314
|
+
};
|
|
294
315
|
touch?: "auto" | boolean;
|
|
316
|
+
/**
|
|
317
|
+
* Leave the browser's touch gestures (scroll/zoom/pull-to-refresh) on the
|
|
318
|
+
* canvas. Default false: the GAME owns them, or a drag on a phone scrolls
|
|
319
|
+
* the page instead of playing.
|
|
320
|
+
*/
|
|
321
|
+
pageGestures?: boolean;
|
|
295
322
|
touchContainer?: HTMLElement;
|
|
296
323
|
/** @internal Test seam — replaces `document` for the touch overlay. */
|
|
297
324
|
_touchDoc?: {
|
|
@@ -331,10 +358,32 @@ interface CreateGame2DOptions {
|
|
|
331
358
|
_scheduler?: Scheduler;
|
|
332
359
|
}
|
|
333
360
|
/** What createGame needs from a renderer (stats is optional for test stubs). */
|
|
361
|
+
/** What a renderer must do for the engine. The test seam supplies this much. */
|
|
334
362
|
interface GameRenderer {
|
|
335
363
|
dispose(): void;
|
|
336
364
|
stats?(): RendererStats;
|
|
337
365
|
}
|
|
366
|
+
/**
|
|
367
|
+
* What a GAME can ask its renderer for.
|
|
368
|
+
*
|
|
369
|
+
* The two coordinate conversions live here rather than only on `Renderer2D`,
|
|
370
|
+
* because `game.renderer` is what a consumer holds: a tap needs screen→world
|
|
371
|
+
* and a pinned DOM element needs world→screen, both are documented in the
|
|
372
|
+
* skills, and neither typechecked through the narrow interface. Found by
|
|
373
|
+
* following my own documentation in a fresh project.
|
|
374
|
+
*/
|
|
375
|
+
interface Game2DRenderer extends GameRenderer {
|
|
376
|
+
/** Canvas px → world px, through the design viewport and the camera. */
|
|
377
|
+
worldFromScreen(sx: number, sy: number): {
|
|
378
|
+
x: number;
|
|
379
|
+
y: number;
|
|
380
|
+
};
|
|
381
|
+
/** World px → canvas px (pin DOM to a node). */
|
|
382
|
+
screenFromWorld(wx: number, wy: number): {
|
|
383
|
+
x: number;
|
|
384
|
+
y: number;
|
|
385
|
+
};
|
|
386
|
+
}
|
|
338
387
|
interface Game2D {
|
|
339
388
|
engine: Engine;
|
|
340
389
|
scene: Scene$1;
|
|
@@ -343,13 +392,25 @@ interface Game2D {
|
|
|
343
392
|
* A running tree has moved; the editor gets what was written down.
|
|
344
393
|
*/
|
|
345
394
|
sourceJson: SceneJson;
|
|
346
|
-
renderer:
|
|
395
|
+
renderer: Game2DRenderer;
|
|
347
396
|
physics: Physics2D | null;
|
|
348
397
|
/**
|
|
349
398
|
* The node under a screen pixel, or null. The raycast the renderer already
|
|
350
399
|
* does — reachable now without holding the renderer.
|
|
351
400
|
*/
|
|
352
401
|
pick(x: number, y: number): Node | null;
|
|
402
|
+
/**
|
|
403
|
+
* Assets that did not arrive — a texture that 404'd, a sound that cannot be
|
|
404
|
+
* played — with the ref and the reason.
|
|
405
|
+
*
|
|
406
|
+
* The verify loop names this as one of its four signals, and 2D never had it:
|
|
407
|
+
* a 2D game could not ask the question at all.
|
|
408
|
+
*/
|
|
409
|
+
assetErrors(): Array<{
|
|
410
|
+
ref: string;
|
|
411
|
+
url: string;
|
|
412
|
+
error: string;
|
|
413
|
+
}>;
|
|
353
414
|
/** Engine + renderer perf counters in one read (fps/nodes/triangles/…). */
|
|
354
415
|
stats(): GameStats;
|
|
355
416
|
/**
|
|
@@ -841,6 +902,8 @@ declare class Renderer2D {
|
|
|
841
902
|
private syncSelectionOutline;
|
|
842
903
|
private syncDebugLines;
|
|
843
904
|
private render;
|
|
905
|
+
/** UI-pass extent from the last render — the space HUD nodes are posed in. */
|
|
906
|
+
private lastUi;
|
|
844
907
|
private lastViewport;
|
|
845
908
|
private lastView;
|
|
846
909
|
/** The world view used by the LAST render (center/zoom/canvas size). */
|
|
@@ -863,6 +926,26 @@ declare class Renderer2D {
|
|
|
863
926
|
* Hits resolve through `userData.incantoNode` and prefer higher renderOrder.
|
|
864
927
|
*/
|
|
865
928
|
pick(sx: number, sy: number): Node | null;
|
|
929
|
+
private hit;
|
|
930
|
+
/** Does the UI pass draw this node (i.e. is it under a UILayer)? */
|
|
931
|
+
isUiNode(node: Node): boolean;
|
|
932
|
+
/**
|
|
933
|
+
* UI-space px → canvas px.
|
|
934
|
+
*
|
|
935
|
+
* A UILayer's children are posed in the UI pass's own space (origin top-left,
|
|
936
|
+
* `uiW × uiH`), NOT in world space — so mapping them with `screenFromWorld`
|
|
937
|
+
* puts them wherever the game camera happens to be looking.
|
|
938
|
+
*/
|
|
939
|
+
screenFromUi(ux: number, uy: number): {
|
|
940
|
+
x: number;
|
|
941
|
+
y: number;
|
|
942
|
+
};
|
|
943
|
+
/** Canvas px → UI-space px (the inverse of `screenFromUi`). */
|
|
944
|
+
uiFromScreen(sx: number, sy: number): {
|
|
945
|
+
x: number;
|
|
946
|
+
y: number;
|
|
947
|
+
};
|
|
948
|
+
private uiView;
|
|
866
949
|
/**
|
|
867
950
|
* Canvas-pixel AABB of a node's rendered world-pass objects, or null when it
|
|
868
951
|
* has no renderable extent (plain Nodes, empty containers).
|
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-9D87XaiX.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-DROK2l7J.js";
|
|
4
|
+
import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-BhZZ-HAp.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 { D as QualityCaps, Dt 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 { D as QualityCaps, Dt 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-Do0Da56m.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 LoadSceneOptions } from "./loader-
|
|
4
|
+
import { t as LoadSceneOptions } from "./loader-Cu_7kJDy.js";
|
|
5
5
|
import { t as ParticleSim } from "./particle-sim-BzJ1yxoE.js";
|
|
6
6
|
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-DZ70IY26.js";
|
|
7
|
-
import { n as PathGrid, s as SpatialPose } from "./pathfinding-
|
|
7
|
+
import { n as PathGrid, s as SpatialPose } from "./pathfinding-HNGFqGUZ.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";
|
|
@@ -563,6 +563,12 @@ interface CreateGame3DOptions {
|
|
|
563
563
|
* parent element — give it position: relative).
|
|
564
564
|
*/
|
|
565
565
|
touch?: "auto" | boolean;
|
|
566
|
+
/**
|
|
567
|
+
* Leave the browser's touch gestures (scroll/zoom/pull-to-refresh) on the
|
|
568
|
+
* canvas. Default false: the GAME owns them, or a drag on a phone scrolls
|
|
569
|
+
* the page instead of playing.
|
|
570
|
+
*/
|
|
571
|
+
pageGestures?: boolean;
|
|
566
572
|
touchContainer?: HTMLElement;
|
|
567
573
|
/** @internal Test seam — replaces `document` for the touch overlay. */
|
|
568
574
|
_touchDoc?: {
|
package/dist/3d.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { F as CharacterBody3D, H as WATER_MAX_RIPPLES, I as PhysicsBody3D, L as RigidBody3D, M as WATER_CUTOUT_MAX, N as WaterCutout3D, P as Area3D, R as StaticBody3D, j as Water3D, z as Node3D } from "./gameplay-
|
|
2
|
-
import { A as Terrain3D, B as keyboardIntensity, C as resolveFlowerDensity, D as BoneLookAt3D, E as Camera3D, F as InstancedMesh3D, G as acquireTexture, H as rigPose, I as MeshInstance3D, M as TERRAIN_THEMES, N as terrainThemeLayers, O as BoneAttachment3D, P as Joint3D, R as QUARTER_PITCH, S as Flowers3D, T as CharacterController3D, U as TextureCache3D, V as movementState, W as acquireOwnTexture, _ as LoftMesh3D, a as Tree3D, b as Foliage3D, c as buildRiverRings, d as riverCarveChannels, f as riverStepFor, g as ModelInstance3D, h as Particles3D, i as VoxelGrid3D, j as DEFAULT_TERRAIN_TEXTURE_BASE, k as Billboard3D, l as findRiverCoverageGaps, m as traceDownhillPath, n as registerNodes3D, o as Trail3D, p as smoothCourse, r as VOXEL_PALETTE, s as River3D, u as projectToRiver, v as DirectionalLight3D, w as FLOWER_VARIETIES, x as DENSITY_PRESETS, y as OmniLight3D, z as cameraRelative } from "./environment-presets-
|
|
3
|
-
import { a as Environment3D, c as parseEnvironment3D, d as AssetStore3D, i as syncTree, l as sunDirectionFromElevationAzimuth, o as setEnvironment3D, r as Renderer3D, s as horizonColorFromSky, t as createGame3D, u as sunDirectionFromSky } from "./create-game-
|
|
1
|
+
import { F as CharacterBody3D, H as WATER_MAX_RIPPLES, I as PhysicsBody3D, L as RigidBody3D, M as WATER_CUTOUT_MAX, N as WaterCutout3D, P as Area3D, R as StaticBody3D, j as Water3D, z as Node3D } from "./gameplay-CRYw_Q-T.js";
|
|
2
|
+
import { A as Terrain3D, B as keyboardIntensity, C as resolveFlowerDensity, D as BoneLookAt3D, E as Camera3D, F as InstancedMesh3D, G as acquireTexture, H as rigPose, I as MeshInstance3D, M as TERRAIN_THEMES, N as terrainThemeLayers, O as BoneAttachment3D, P as Joint3D, R as QUARTER_PITCH, S as Flowers3D, T as CharacterController3D, U as TextureCache3D, V as movementState, W as acquireOwnTexture, _ as LoftMesh3D, a as Tree3D, b as Foliage3D, c as buildRiverRings, d as riverCarveChannels, f as riverStepFor, g as ModelInstance3D, h as Particles3D, i as VoxelGrid3D, j as DEFAULT_TERRAIN_TEXTURE_BASE, k as Billboard3D, l as findRiverCoverageGaps, m as traceDownhillPath, n as registerNodes3D, o as Trail3D, p as smoothCourse, r as VOXEL_PALETTE, s as River3D, u as projectToRiver, v as DirectionalLight3D, w as FLOWER_VARIETIES, x as DENSITY_PRESETS, y as OmniLight3D, z as cameraRelative } from "./environment-presets-SkGanr2s.js";
|
|
3
|
+
import { a as Environment3D, c as parseEnvironment3D, d as AssetStore3D, i as syncTree, l as sunDirectionFromElevationAzimuth, o as setEnvironment3D, r as Renderer3D, s as horizonColorFromSky, t as createGame3D, u as sunDirectionFromSky } from "./create-game-CDJ1lVqK.js";
|
|
4
4
|
import { a as frameSignature, n as diffSignatures, o as frameStats, r as diffText, s as frameText, t as SIGNATURE_GRID } from "./frame-report-njybhZon.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-DmyO2oaN.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;
|
|
@@ -325,9 +325,42 @@ type BusName = "sfx" | "music";
|
|
|
325
325
|
* engine.audio.muted = true; // mute toggle
|
|
326
326
|
* ```
|
|
327
327
|
*/
|
|
328
|
+
/** One thing that sounded (or would have, headless). */
|
|
329
|
+
interface AudioEvent {
|
|
330
|
+
/** `preset` (procedural one-shot), `src` (a clip), `music`, or `voice`. */
|
|
331
|
+
kind: "preset" | "src" | "music" | "voice";
|
|
332
|
+
/** The preset name, the clip url, or the voice preset. */
|
|
333
|
+
name: string;
|
|
334
|
+
/** Node path for a node-driven sound; `engine.music` / `engine.sfx` otherwise. */
|
|
335
|
+
from: string;
|
|
336
|
+
bus: BusName;
|
|
337
|
+
/** `engine.time` when it fired, in seconds. */
|
|
338
|
+
at: number;
|
|
339
|
+
}
|
|
328
340
|
declare class AudioBuses {
|
|
329
341
|
/** Fires whenever any value changes (drives live re-gain of playing sounds). */
|
|
330
342
|
readonly changed: Signal<[]>;
|
|
343
|
+
/**
|
|
344
|
+
* What has sounded, most recent last.
|
|
345
|
+
*
|
|
346
|
+
* Audio is a no-op headless, which left "did the coin sound actually fire
|
|
347
|
+
* when the coin was collected?" unanswerable — the audio skill's own advice
|
|
348
|
+
* was to *"assert `play()` doesn't throw and check your gameplay logic
|
|
349
|
+
* instead"*, which checks something else. The CALL still happens with no
|
|
350
|
+
* backend, so recording it answers the wiring question everywhere: in the
|
|
351
|
+
* verify VM, in a playtest, in a test.
|
|
352
|
+
*
|
|
353
|
+
* Bounded (200) — a game running for an hour must not grow a log.
|
|
354
|
+
*/
|
|
355
|
+
private readonly events;
|
|
356
|
+
/** @internal Called by the players; games read `recent()`. */
|
|
357
|
+
record(event: AudioEvent): void;
|
|
358
|
+
/** The last `limit` sounds, oldest first. */
|
|
359
|
+
recent(limit?: number): AudioEvent[];
|
|
360
|
+
/** How many times a preset/clip/track sounded — the assertion you want. */
|
|
361
|
+
countOf(name: string): number;
|
|
362
|
+
/** Forget what has sounded so far (between scenes, or between assertions). */
|
|
363
|
+
clearLog(): void;
|
|
331
364
|
private _master;
|
|
332
365
|
private _sfx;
|
|
333
366
|
private _music;
|
|
@@ -377,6 +410,8 @@ interface MusicBackend {
|
|
|
377
410
|
createTrack(src: string): MusicTrack;
|
|
378
411
|
/** Resume a gesture-suspended context (wired to the first user gesture). */
|
|
379
412
|
unlock(): void;
|
|
413
|
+
/** Release the context it owns (optional — teardown). */
|
|
414
|
+
dispose?(): void;
|
|
380
415
|
}
|
|
381
416
|
interface PlayMusicOptions {
|
|
382
417
|
/** Loop the track (default true — music usually loops). */
|
|
@@ -420,6 +455,15 @@ declare class MusicManager {
|
|
|
420
455
|
get current(): string | null;
|
|
421
456
|
/** Per-manager volume (0..1), on top of the bus gain. */
|
|
422
457
|
get volume(): number;
|
|
458
|
+
/**
|
|
459
|
+
* The backend, or an INERT one that mints silent tracks.
|
|
460
|
+
*
|
|
461
|
+
* Never null, on purpose: the manager used to return before touching its
|
|
462
|
+
* state when there was no backend, so `current` stayed null forever in every
|
|
463
|
+
* headless run — including the verify VM, which is the only place a game is
|
|
464
|
+
* checked automatically. "Did the boss music start?" had no answer anywhere.
|
|
465
|
+
* With an inert backend the state machine runs identically and nothing plays.
|
|
466
|
+
*/
|
|
423
467
|
private ensure;
|
|
424
468
|
/** Resume a gesture-suspended context + (re)start any pending track. */
|
|
425
469
|
unlock(): void;
|
|
@@ -432,6 +476,13 @@ declare class MusicManager {
|
|
|
432
476
|
crossfadeTo(src: string, seconds?: number): void;
|
|
433
477
|
/** Stop the current track, optionally fading out over `fadeOut` seconds. */
|
|
434
478
|
stop(fadeOut?: number): void;
|
|
479
|
+
/**
|
|
480
|
+
* Stop instantly and release the backend — music must not outlive the game.
|
|
481
|
+
*
|
|
482
|
+
* `dispose()` is the one call that tears an SPA-mounted game down, and it used
|
|
483
|
+
* to leave the track playing with the engine that owned it gone.
|
|
484
|
+
*/
|
|
485
|
+
dispose(): void;
|
|
435
486
|
/** Set the per-manager volume (re-applied to live tracks on the next tick). */
|
|
436
487
|
setVolume(v: number): void;
|
|
437
488
|
/** Advance fades by `dt` seconds and (re)apply bus×fade gains. Frame-driven. */
|
|
@@ -588,6 +639,14 @@ interface Voice {
|
|
|
588
639
|
//#endregion
|
|
589
640
|
//#region src/core/audio/webaudio-sfx.d.ts
|
|
590
641
|
/** A spatial emitter: where the sound is + where the listener is. */
|
|
642
|
+
/** The shape `AudioBuses.record` takes (structural — no import cycle). */
|
|
643
|
+
interface AudioRecord {
|
|
644
|
+
kind: "preset" | "src" | "music" | "voice";
|
|
645
|
+
name: string;
|
|
646
|
+
from: string;
|
|
647
|
+
bus: "sfx" | "music";
|
|
648
|
+
at: number;
|
|
649
|
+
}
|
|
591
650
|
interface SpatialPlay {
|
|
592
651
|
/** Emitter world position. */
|
|
593
652
|
position: Vec3;
|
|
@@ -615,6 +674,19 @@ declare class SfxEngine {
|
|
|
615
674
|
private ctx;
|
|
616
675
|
private resolved;
|
|
617
676
|
private readonly pcmCache;
|
|
677
|
+
/**
|
|
678
|
+
* The engine's buses, when this SfxEngine belongs to one — so a continuous
|
|
679
|
+
* voice lands in the same audio record as everything else. A record that
|
|
680
|
+
* covered only SOME sounds would answer "did the engine hum start?" with a
|
|
681
|
+
* confident no.
|
|
682
|
+
*/
|
|
683
|
+
private buses;
|
|
684
|
+
/** Live continuous voices, so teardown can silence the ones nobody stopped. */
|
|
685
|
+
private readonly voices;
|
|
686
|
+
/** @internal Engine wiring. */
|
|
687
|
+
_setBuses(buses: {
|
|
688
|
+
record(event: AudioRecord): void;
|
|
689
|
+
}): void;
|
|
618
690
|
/** True once a backend is present (lazily created on first use). */
|
|
619
691
|
get available(): boolean;
|
|
620
692
|
private ensure;
|
|
@@ -624,6 +696,18 @@ declare class SfxEngine {
|
|
|
624
696
|
* done. Headless returns an inert handle (same call sites, no ifs).
|
|
625
697
|
*/
|
|
626
698
|
startVoice(preset: VoicePreset, gain?: number): Voice;
|
|
699
|
+
/** How many continuous voices are still running (teardown/leak checks). */
|
|
700
|
+
get liveVoiceCount(): number;
|
|
701
|
+
/** Silence every continuous voice — the hum must not outlive the game. */
|
|
702
|
+
stopAll(seconds?: number): void;
|
|
703
|
+
/**
|
|
704
|
+
* Silence everything and release the AudioContext.
|
|
705
|
+
*
|
|
706
|
+
* A browser allows only a handful of contexts per page, so an SPA that mounts
|
|
707
|
+
* the game a few times must hand this one back — `dispose()` is documented as
|
|
708
|
+
* the call that tears everything down.
|
|
709
|
+
*/
|
|
710
|
+
dispose(): void;
|
|
627
711
|
/** Resume a gesture-suspended context (wired to the first user gesture). */
|
|
628
712
|
unlock(): void;
|
|
629
713
|
/**
|
|
@@ -760,6 +844,20 @@ declare class InputMap {
|
|
|
760
844
|
connect(fn: () => void): () => void;
|
|
761
845
|
};
|
|
762
846
|
}): () => void;
|
|
847
|
+
/**
|
|
848
|
+
* Pointer input from a mouse, a FINGER or a pen — one code path.
|
|
849
|
+
*
|
|
850
|
+
* This used to bind `mousedown`/`mousemove`/`mouseup`, which on a phone only
|
|
851
|
+
* arrive as COMPATIBILITY events: delayed until the browser has decided the
|
|
852
|
+
* touch is not a scroll, never fired for drags or multi-touch, and suppressed
|
|
853
|
+
* outright once the surface claims its gestures with `touch-action: none`.
|
|
854
|
+
* So every genre the comment below lists — match-3, tower defense, card,
|
|
855
|
+
* point-and-click, RTS — was mouse-only on the device most of them are played
|
|
856
|
+
* on. Pointer events cover all three input kinds and fire immediately.
|
|
857
|
+
*
|
|
858
|
+
* Only the PRIMARY pointer drives it: a second finger (the one on the virtual
|
|
859
|
+
* stick) must not also swing the camera.
|
|
860
|
+
*/
|
|
763
861
|
attachPointer(target: HTMLElement, opts?: {
|
|
764
862
|
lockOnClick?: boolean;
|
|
765
863
|
}): () => void;
|
|
@@ -1581,6 +1679,16 @@ interface PropDef {
|
|
|
1581
1679
|
*/
|
|
1582
1680
|
nodePath?: boolean;
|
|
1583
1681
|
/**
|
|
1682
|
+
* The prop must be given a value — an empty string is not a configuration.
|
|
1683
|
+
*
|
|
1684
|
+
* `Chase.target` and `FollowCamera.target` threw for this in `onReady`, which
|
|
1685
|
+
* is the browser, at the moment the level starts. Declared here it is a LOAD
|
|
1686
|
+
* error instead: `incanto-check` reports it while you are still writing the
|
|
1687
|
+
* scene, and the editor knows not to "unlink" a prop whose emptiness the
|
|
1688
|
+
* engine refuses.
|
|
1689
|
+
*/
|
|
1690
|
+
required?: boolean;
|
|
1691
|
+
/**
|
|
1584
1692
|
* For an OBJECT-valued prop shaped as a tagged union — `collider`, whose
|
|
1585
1693
|
* `shape` decides which other keys are required. One declaration gives an
|
|
1586
1694
|
* inspector both the dropdown AND something valid to write when the tag
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import { A as registerBehavior, n as loadScene, o as computeViewport, s as resolveViewport
|
|
3
|
-
import {
|
|
2
|
+
import { A as registerBehavior, C as diagnose, n as loadScene, o as computeViewport, s as resolveViewport } from "./loader-BTkHYrQn.js";
|
|
3
|
+
import { b as AudioPlayer, x as Engine } from "./register-BTomIiYG.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, i as devServerLibrary, n as pauseWhenHidden, r as crossFade, t as teardown } from "./teardown-
|
|
7
|
-
import { n as registerGameplayBehaviors } from "./gameplay-
|
|
8
|
-
import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-
|
|
5
|
+
import { i as resolveRendering, n as attachTouchControls } from "./touch-BnMyy9tr.js";
|
|
6
|
+
import { a as openBundledEditor, c as audioErrors, i as devServerLibrary, n as pauseWhenHidden, r as crossFade, s as claimCanvasGestures, t as teardown } from "./teardown-Bw2aeyGI.js";
|
|
7
|
+
import { n as registerGameplayBehaviors } from "./gameplay-CRYw_Q-T.js";
|
|
8
|
+
import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-DROK2l7J.js";
|
|
9
9
|
import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
|
|
10
|
-
import { n as enablePhysics2D } from "./physics-2d-
|
|
10
|
+
import { n as enablePhysics2D } from "./physics-2d-BhZZ-HAp.js";
|
|
11
11
|
import { Box3, BufferAttribute, BufferGeometry, Color, LineBasicMaterial, LineSegments, LinearFilter, NearestFilter, OrthographicCamera, Raycaster, SRGBColorSpace, Scene, TextureLoader, Vector2, Vector3, WebGLRenderer } from "three";
|
|
12
12
|
//#region src/2d/assets.ts
|
|
13
13
|
/**
|
|
@@ -50,6 +50,7 @@ var AssetStore2D = class {
|
|
|
50
50
|
},
|
|
51
51
|
onError: (err) => {
|
|
52
52
|
state.status = "error";
|
|
53
|
+
state.error = err instanceof Error ? err.message : `could not load ${decl.url}`;
|
|
53
54
|
diagnose(this.engine, "error", `[incanto] failed to load texture '${key}' (${decl.url}):`, err);
|
|
54
55
|
}
|
|
55
56
|
});
|
|
@@ -66,10 +67,31 @@ var AssetStore2D = class {
|
|
|
66
67
|
type,
|
|
67
68
|
frameWidth,
|
|
68
69
|
frameHeight,
|
|
70
|
+
url: decl.url,
|
|
69
71
|
state
|
|
70
72
|
});
|
|
71
73
|
}
|
|
72
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Every declared asset that FAILED to load, `$ref` and url included.
|
|
77
|
+
*
|
|
78
|
+
* The 3D store has answered this since 0.32.0 — the 2D one only tracked a
|
|
79
|
+
* per-key status, which the console printed and nothing else could read. A
|
|
80
|
+
* 404'd texture is invisible, and "invisible" is the one symptom an author
|
|
81
|
+
* cannot tell apart from "I put it in the wrong place".
|
|
82
|
+
*/
|
|
83
|
+
errors() {
|
|
84
|
+
const out = [];
|
|
85
|
+
for (const [key, entry] of this.entries) {
|
|
86
|
+
if (entry.state.status !== "error") continue;
|
|
87
|
+
out.push({
|
|
88
|
+
ref: `$${key}`,
|
|
89
|
+
url: entry.url,
|
|
90
|
+
error: entry.state.error ?? `could not load ${entry.url}`
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
73
95
|
/** Load status of a declared asset KEY (no '$'), or undefined if unknown. */
|
|
74
96
|
status(key) {
|
|
75
97
|
return this.entries.get(key)?.state.status;
|
|
@@ -107,6 +129,18 @@ function worldFromScreen(view, sx, sy) {
|
|
|
107
129
|
y: (sy - view.h / 2) / view.zoom + view.cy
|
|
108
130
|
};
|
|
109
131
|
}
|
|
132
|
+
function screenFromUi(v, ux, uy) {
|
|
133
|
+
return {
|
|
134
|
+
x: v.offsetX + ux / v.uiW * v.contentW,
|
|
135
|
+
y: v.offsetY + uy / v.uiH * v.contentH
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function uiFromScreen(v, sx, sy) {
|
|
139
|
+
return {
|
|
140
|
+
x: (sx - v.offsetX) / v.contentW * v.uiW,
|
|
141
|
+
y: (sy - v.offsetY) / v.contentH * v.uiH
|
|
142
|
+
};
|
|
143
|
+
}
|
|
110
144
|
//#endregion
|
|
111
145
|
//#region src/2d/selection-outline.ts
|
|
112
146
|
/** 2D twin of the 3D selection outline: a world-space (px, y-down) rectangle
|
|
@@ -355,6 +389,10 @@ var Renderer2D = class {
|
|
|
355
389
|
const view = vp ? computeViewport(w, h, vp) : null;
|
|
356
390
|
const uiW = view ? view.viewW : w;
|
|
357
391
|
const uiH = view ? view.viewH : h;
|
|
392
|
+
this.lastUi = {
|
|
393
|
+
w: uiW,
|
|
394
|
+
h: uiH
|
|
395
|
+
};
|
|
358
396
|
const { activeCamera } = syncTree2D(scene.root, this.worldScene, this.uiScene, this.assets, {
|
|
359
397
|
width: uiW,
|
|
360
398
|
height: uiH
|
|
@@ -406,6 +444,11 @@ var Renderer2D = class {
|
|
|
406
444
|
this.webgl.render(this.uiScene, this.uiCam);
|
|
407
445
|
this.webgl.autoClear = true;
|
|
408
446
|
}
|
|
447
|
+
/** UI-pass extent from the last render — the space HUD nodes are posed in. */
|
|
448
|
+
lastUi = {
|
|
449
|
+
w: 1,
|
|
450
|
+
h: 1
|
|
451
|
+
};
|
|
409
452
|
lastViewport = null;
|
|
410
453
|
lastView = {
|
|
411
454
|
cx: 0,
|
|
@@ -448,8 +491,13 @@ var Renderer2D = class {
|
|
|
448
491
|
const cw = this.lastViewport?.contentW ?? w;
|
|
449
492
|
const ch = this.lastViewport?.contentH ?? h;
|
|
450
493
|
pickNdc.set((sx - ox) / cw * 2 - 1, -((sy - oy) / ch * 2 - 1));
|
|
451
|
-
|
|
452
|
-
|
|
494
|
+
const ui = this.hit(this.uiScene, this.uiCam);
|
|
495
|
+
if (ui) return ui;
|
|
496
|
+
return this.hit(this.worldScene, this.worldCam);
|
|
497
|
+
}
|
|
498
|
+
hit(scene, cam) {
|
|
499
|
+
raycaster.setFromCamera(pickNdc, cam);
|
|
500
|
+
const hits = raycaster.intersectObjects(scene.children, true);
|
|
453
501
|
let best = null;
|
|
454
502
|
for (const hit of hits) {
|
|
455
503
|
let obj = hit.object;
|
|
@@ -464,6 +512,39 @@ var Renderer2D = class {
|
|
|
464
512
|
}
|
|
465
513
|
return best?.node ?? null;
|
|
466
514
|
}
|
|
515
|
+
/** Does the UI pass draw this node (i.e. is it under a UILayer)? */
|
|
516
|
+
isUiNode(node) {
|
|
517
|
+
let obj = node._object2D ?? node._group ?? null;
|
|
518
|
+
while (obj) {
|
|
519
|
+
if (obj === this.uiScene) return true;
|
|
520
|
+
obj = obj.parent;
|
|
521
|
+
}
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* UI-space px → canvas px.
|
|
526
|
+
*
|
|
527
|
+
* A UILayer's children are posed in the UI pass's own space (origin top-left,
|
|
528
|
+
* `uiW × uiH`), NOT in world space — so mapping them with `screenFromWorld`
|
|
529
|
+
* puts them wherever the game camera happens to be looking.
|
|
530
|
+
*/
|
|
531
|
+
screenFromUi(ux, uy) {
|
|
532
|
+
return screenFromUi(this.uiView(), ux, uy);
|
|
533
|
+
}
|
|
534
|
+
/** Canvas px → UI-space px (the inverse of `screenFromUi`). */
|
|
535
|
+
uiFromScreen(sx, sy) {
|
|
536
|
+
return uiFromScreen(this.uiView(), sx, sy);
|
|
537
|
+
}
|
|
538
|
+
uiView() {
|
|
539
|
+
return {
|
|
540
|
+
offsetX: this.lastViewport?.offsetX ?? 0,
|
|
541
|
+
offsetY: this.lastViewport?.offsetY ?? 0,
|
|
542
|
+
contentW: this.lastViewport?.contentW ?? this.lastView.w,
|
|
543
|
+
contentH: this.lastViewport?.contentH ?? this.lastView.h,
|
|
544
|
+
uiW: this.lastUi.w,
|
|
545
|
+
uiH: this.lastUi.h
|
|
546
|
+
};
|
|
547
|
+
}
|
|
467
548
|
/**
|
|
468
549
|
* Canvas-pixel AABB of a node's rendered world-pass objects, or null when it
|
|
469
550
|
* has no renderable extent (plain Nodes, empty containers).
|
|
@@ -476,8 +557,9 @@ var Renderer2D = class {
|
|
|
476
557
|
if (boundsScratch.isEmpty()) return null;
|
|
477
558
|
boundsScratch.getSize(sizeScratch3);
|
|
478
559
|
if (sizeScratch3.x === 0 && sizeScratch3.y === 0) return null;
|
|
479
|
-
const
|
|
480
|
-
const
|
|
560
|
+
const map = this.isUiNode(node) ? (x, y) => this.screenFromUi(x, y) : (x, y) => this.screenFromWorld(x, y);
|
|
561
|
+
const a = map(boundsScratch.min.x, -boundsScratch.max.y);
|
|
562
|
+
const b = map(boundsScratch.max.x, -boundsScratch.min.y);
|
|
481
563
|
return {
|
|
482
564
|
x: a.x,
|
|
483
565
|
y: a.y,
|
|
@@ -543,10 +625,15 @@ async function createGame2D(opts) {
|
|
|
543
625
|
const cleanups = [];
|
|
544
626
|
const keyboard = opts.keyboard ?? (typeof window !== "undefined" ? window : false);
|
|
545
627
|
if (keyboard) engine.input.attachKeyboard(keyboard);
|
|
628
|
+
if (opts.pointer) {
|
|
629
|
+
const lockOnClick = typeof opts.pointer === "object" ? opts.pointer.lockOnClick ?? false : false;
|
|
630
|
+
engine.input.attachPointer(opts.canvas, { lockOnClick });
|
|
631
|
+
}
|
|
546
632
|
cleanups.push(wireAudioUnlock(engine, scene.root, opts.canvas));
|
|
547
633
|
cleanups.push(engine.settings.bindAudio(engine.audio));
|
|
548
634
|
cleanups.push(pauseWhenHidden(engine));
|
|
549
635
|
cleanups.push(engine.settings.bindLocale(engine.locale));
|
|
636
|
+
if (!opts.pageGestures) claimCanvasGestures(opts.canvas);
|
|
550
637
|
const touchMode = opts.touch ?? "auto";
|
|
551
638
|
if (touchMode !== false) {
|
|
552
639
|
const host = opts.touchContainer ?? opts.canvas.parentElement ?? null;
|
|
@@ -636,6 +723,9 @@ async function createGame2D(opts) {
|
|
|
636
723
|
pick(x, y) {
|
|
637
724
|
return engine.picker?.(x, y) ?? null;
|
|
638
725
|
},
|
|
726
|
+
assetErrors() {
|
|
727
|
+
return [...renderer.assets?.errors() ?? [], ...audioErrors(engine.scene?.tree.root)];
|
|
728
|
+
},
|
|
639
729
|
stats() {
|
|
640
730
|
return {
|
|
641
731
|
triangles: 0,
|
|
@@ -673,10 +763,17 @@ function wireAudioUnlock(engine, root, canvas) {
|
|
|
673
763
|
target: canvasTarget,
|
|
674
764
|
type: "pointerdown"
|
|
675
765
|
});
|
|
676
|
-
if (typeof window !== "undefined")
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
766
|
+
if (typeof window !== "undefined") {
|
|
767
|
+
const win = window;
|
|
768
|
+
sources.push({
|
|
769
|
+
target: win,
|
|
770
|
+
type: "keydown"
|
|
771
|
+
});
|
|
772
|
+
sources.push({
|
|
773
|
+
target: win,
|
|
774
|
+
type: "pointerdown"
|
|
775
|
+
});
|
|
776
|
+
}
|
|
680
777
|
if (sources.length === 0) return () => {};
|
|
681
778
|
function detachAll() {
|
|
682
779
|
for (const s of sources) s.target.removeEventListener?.(s.type, unlock);
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import { A as registerBehavior,
|
|
3
|
-
import {
|
|
2
|
+
import { A as registerBehavior, C as diagnose, n as loadScene } from "./loader-BTkHYrQn.js";
|
|
3
|
+
import { C as qualityCaps, T as qualityRendering, b as AudioPlayer, x as Engine } from "./register-BTomIiYG.js";
|
|
4
4
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
5
|
-
import { r as parseDrive, t as logReport } from "./log-report-
|
|
6
|
-
import { i as resolveRendering, n as attachTouchControls } from "./touch-
|
|
7
|
-
import { a as openBundledEditor, i as devServerLibrary, n as pauseWhenHidden, o as poseFromRenderer, r as crossFade, t as teardown } from "./teardown-
|
|
8
|
-
import { I as PhysicsBody3D, V as createCausticsQuad, n as registerGameplayBehaviors, z as Node3D } from "./gameplay-
|
|
5
|
+
import { r as parseDrive, t as logReport } from "./log-report-CPFm4OXf.js";
|
|
6
|
+
import { i as resolveRendering, n as attachTouchControls } from "./touch-BnMyy9tr.js";
|
|
7
|
+
import { a as openBundledEditor, c as audioErrors, i as devServerLibrary, n as pauseWhenHidden, o as poseFromRenderer, r as crossFade, s as claimCanvasGestures, t as teardown } from "./teardown-Bw2aeyGI.js";
|
|
8
|
+
import { I as PhysicsBody3D, V as createCausticsQuad, n as registerGameplayBehaviors, z as Node3D } from "./gameplay-CRYw_Q-T.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-
|
|
10
|
+
import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-SkGanr2s.js";
|
|
11
11
|
import { a as frameSignature, i as frameImage, o as frameStats } from "./frame-report-njybhZon.js";
|
|
12
|
-
import { n as enablePhysics3D } from "./physics-3d-
|
|
12
|
+
import { n as enablePhysics3D } from "./physics-3d-DmyO2oaN.js";
|
|
13
13
|
import { ACESFilmicToneMapping, AmbientLight, Box3, BufferAttribute, BufferGeometry, Color, DepthTexture, EquirectangularReflectionMapping, FloatType, Fog, HalfFloatType, LineBasicMaterial, LineSegments, Matrix4, Mesh, PCFShadowMap, PMREMGenerator, PerspectiveCamera, PlaneGeometry, Quaternion, Raycaster, Scene, ShaderMaterial, Vector2, Vector3, WebGLRenderTarget, WebGLRenderer } from "three";
|
|
14
14
|
import { VRMLoaderPlugin, VRMUtils } from "@pixiv/three-vrm";
|
|
15
15
|
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
|
|
@@ -2349,6 +2349,7 @@ async function createGame3D(opts) {
|
|
|
2349
2349
|
engine.input.attachPointer(opts.canvas, { lockOnClick });
|
|
2350
2350
|
}
|
|
2351
2351
|
cleanups.push(wireAudioUnlock(engine, scene.root, opts.canvas));
|
|
2352
|
+
if (!opts.pageGestures) claimCanvasGestures(opts.canvas);
|
|
2352
2353
|
const touchMode = opts.touch ?? "auto";
|
|
2353
2354
|
if (touchMode !== false) {
|
|
2354
2355
|
const host = opts.touchContainer ?? opts.canvas.parentElement ?? null;
|
|
@@ -2575,7 +2576,7 @@ async function createGame3D(opts) {
|
|
|
2575
2576
|
renderer,
|
|
2576
2577
|
physics,
|
|
2577
2578
|
assetErrors() {
|
|
2578
|
-
return renderer.assets?.errors() ?? [];
|
|
2579
|
+
return [...renderer.assets?.errors() ?? [], ...audioErrors(engine.scene?.tree.root)];
|
|
2579
2580
|
},
|
|
2580
2581
|
async frame(frameOpts) {
|
|
2581
2582
|
const capture = renderer.captureFrame;
|
|
@@ -2623,10 +2624,17 @@ function wireAudioUnlock(engine, root, canvas) {
|
|
|
2623
2624
|
target: canvasTarget,
|
|
2624
2625
|
type: "pointerdown"
|
|
2625
2626
|
});
|
|
2626
|
-
if (typeof window !== "undefined")
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2627
|
+
if (typeof window !== "undefined") {
|
|
2628
|
+
const win = window;
|
|
2629
|
+
sources.push({
|
|
2630
|
+
target: win,
|
|
2631
|
+
type: "keydown"
|
|
2632
|
+
});
|
|
2633
|
+
sources.push({
|
|
2634
|
+
target: win,
|
|
2635
|
+
type: "pointerdown"
|
|
2636
|
+
});
|
|
2637
|
+
}
|
|
2630
2638
|
if (sources.length === 0) return () => {};
|
|
2631
2639
|
function detachAll() {
|
|
2632
2640
|
for (const s of sources) s.target.removeEventListener?.(s.type, unlock);
|
package/dist/debug.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { T as RendererStats, b as Engine, jt as LogLevel } from "./behavior-
|
|
1
|
+
import { T as RendererStats, b as Engine, jt as LogLevel } from "./behavior-Do0Da56m.js";
|
|
2
2
|
|
|
3
3
|
//#region src/debug/panel.d.ts
|
|
4
4
|
/** Minimal document surface the overlay needs (injectable for tests). */
|
package/dist/debug.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as jsonClone } from "./json-BLk7H2Qa.js";
|
|
2
|
-
import { s as mergeStaticProps } from "./registry-
|
|
2
|
+
import { s as mergeStaticProps } from "./registry-C7u42TID.js";
|
|
3
3
|
import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
|
|
4
4
|
//#region src/debug/capture.ts
|
|
5
5
|
/**
|