incanto 0.67.0 → 0.69.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/assets/catalog.json +9 -5
- package/bin/_pick-server.mjs +48 -0
- package/bin/incanto-assets.mjs +14 -1
- package/bin/incanto-check.mjs +69 -5
- package/bin/incanto-frame.mjs +10 -25
- package/bin/incanto-logs.mjs +8 -18
- package/bin/incanto-new.mjs +29 -1
- package/bin/incanto-serve.mjs +160 -0
- package/bin/incanto-verify.mjs +40 -0
- package/bin/incanto.mjs +1 -0
- package/dist/2d.d.ts +10 -8
- package/dist/2d.js +6 -4
- package/dist/3d.d.ts +31 -7
- package/dist/3d.js +9 -7
- package/dist/{audio-player-BNUHo0JF.d.ts → audio-player-C0j2k-yB.d.ts} +80 -3
- package/dist/{behavior-ZnfzKDo3.d.ts → behavior-rm8vVzu_.d.ts} +145 -1
- package/dist/boot-failure-CKYrEcGF.js +47 -0
- package/dist/{create-game-FAXdHta3.js → create-game-CvJ1wSRP.js} +27 -27
- package/dist/{create-game-DMetd3vR.js → create-game-CwxEDlCm.js} +15 -11
- package/dist/debug.d.ts +1 -1
- package/dist/{duplicate-B8QnX2-r.js → duplicate-Dj4L-5AA.js} +1 -1
- package/dist/{editor-switch-DAvWQeld.d.ts → editor-switch-CnIOiyNJ.d.ts} +1 -1
- package/dist/editor.js +12 -6
- package/dist/env.d.ts +1 -1
- package/dist/{environment-presets-C-5g2pMh.js → environment-presets-BO-7XoFV.js} +58 -9
- package/dist/{frame-report-DCnHFmto.d.ts → frame-report-DNxDAb1w.d.ts} +8 -0
- package/dist/{frame-report-BSMny7oe.js → frame-report-Dlq13Gyj.js} +1 -0
- package/dist/{gameplay-CGSv-9XR.js → gameplay-D1KixWK8.js} +175 -151
- package/dist/gameplay.d.ts +51 -3
- package/dist/gameplay.js +2 -2
- package/dist/index.d.ts +6 -6
- package/dist/index.js +8 -7
- package/dist/{loader-KZESOZmE.js → loader-DZE7B07H.js} +48 -7
- package/dist/{loader-DyT30ArB.d.ts → loader-DadV2QCT.d.ts} +2 -2
- package/dist/net.d.ts +2 -2
- package/dist/net.js +1 -1
- package/dist/{physics-2d-_B6zj3zU.js → physics-2d-CF5yyjbj.js} +2 -2
- package/dist/{physics-3d-i1IeAY0F.js → physics-3d-DbYaEcZy.js} +3 -3
- package/dist/react.d.ts +2 -2
- package/dist/react.js +1 -1
- package/dist/{register-vIxU3Xbv.js → register-DbVArsns.js} +19 -10
- package/dist/{register-Cs53CY7s.js → register-mmfugpaQ.js} +159 -6
- package/dist/{replay-BkpDV51O.js → replay-BEHLDcQV.js} +28 -5
- package/dist/{replay-D0GcEHYU.d.ts → replay-BQfkX4x7.d.ts} +38 -4
- package/dist/{schema-CFeioQRE.d.ts → schema-B6ugCV1Q.d.ts} +11 -0
- package/dist/{sheet-grid-BT6N_Bjs.js → sheet-grid-Cea343VO.js} +6 -2
- package/dist/{split-screen-DS8RaUV_.js → split-screen-CauMwu6y.js} +2 -2
- package/dist/{split-screen-DD5eYIgW.d.ts → split-screen-Cg76MCV5.d.ts} +3 -3
- package/dist/{src-BLlsGJW9.js → src-CYEu-_S9.js} +1 -1
- package/dist/{teardown-LB9cTnXJ.js → teardown-CMqFVxO9.js} +5 -4
- package/dist/{test-81uZ967a.js → test-D6ISmuFE.js} +73 -25
- package/dist/test.d.ts +17 -6
- package/dist/test.js +3 -3
- package/dist/vite.d.ts +70 -2
- package/dist/vite.js +176 -14
- package/dist/{rendering-options-ByAdi8PF.js → webgl-unavailable-Z5_g8x9H.js} +57 -2
- package/editor/assets/{agent8-C2jtNKbx.js → agent8-BDvaZMQJ.js} +1 -1
- package/editor/assets/{debug-DoU3KeqS.js → debug-CMULinBW.js} +1 -1
- package/editor/assets/{index-CNqHojcC.js → index-CZIRr5EL.js} +92 -92
- package/editor/index.html +1 -1
- package/package.json +4 -3
- package/schemas/scene.schema.json +4 -0
- package/skills/incanto-3d-character.md +1 -0
- package/skills/incanto-assets.md +16 -2
- package/skills/incanto-audio.md +65 -0
- package/skills/incanto-building-2d-games.md +66 -0
- package/skills/incanto-building-3d-games.md +97 -2
- package/skills/incanto-gameplay-behaviors.md +46 -2
- package/skills/incanto-node-reference.md +1 -0
- package/skills/incanto-physics-and-input.md +23 -0
- package/skills/incanto-save-slots.md +27 -0
- package/skills/incanto-scene-json-authoring.md +12 -1
- package/skills/incanto-verifying-your-game.md +96 -2
- package/skills/incanto-your-first-game.md +2 -1
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/beacon-isle-3d/src/main.ts +21 -4
- package/templates-app/platformer-2d/index.html +0 -23
- package/templates-app/platformer-2d/package.json +1 -1
- package/templates-app/platformer-2d/src/behaviors.ts +26 -16
- package/templates-app/platformer-2d/src/game.scene.json +17 -27
- package/templates-app/platformer-2d/src/main.ts +32 -13
- package/templates-app/star-survivor/package.json +1 -1
- package/templates-app/star-survivor/src/main.ts +25 -7
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/tps-3d/src/main.ts +34 -16
- package/templates-app/village-quest-3d/package.json +1 -1
- package/templates-app/village-quest-3d/src/main.ts +21 -4
package/dist/2d.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { c as showBootFailure, i as ParticleSim, o as ParticleView, r as SpatialPose, s as isWebGLAvailable } from "./audio-player-C0j2k-yB.js";
|
|
2
|
+
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, x as EngineOptions } from "./behavior-rm8vVzu_.js";
|
|
3
|
+
import { n as DiagnosticSink, t as EditorSwitchOptions } from "./editor-switch-CnIOiyNJ.js";
|
|
4
|
+
import { i as SceneJson, s as JsonObject } from "./schema-B6ugCV1Q.js";
|
|
5
|
+
import { r as FrameStats } from "./frame-report-DNxDAb1w.js";
|
|
6
|
+
import { t as LoadSceneOptions } from "./loader-DadV2QCT.js";
|
|
6
7
|
import { n as AnimationEntry } from "./sprite-animation-CMr6f1K2.js";
|
|
7
|
-
import { i as ParticleSim, o as ParticleView, r as SpatialPose } from "./audio-player-BNUHo0JF.js";
|
|
8
8
|
import { Group, Mesh, Object3D, Scene, Texture } from "three";
|
|
9
9
|
import * as RapierNs from "@dimforge/rapier2d-compat";
|
|
10
10
|
|
|
@@ -972,9 +972,11 @@ declare class TileMap2D extends Node2D {
|
|
|
972
972
|
private _solid;
|
|
973
973
|
/** Rebuild flags — raised when the map-shaping props are REPLACED. */
|
|
974
974
|
private geometryDirty;
|
|
975
|
-
/**
|
|
975
|
+
/** `texture|highestTile` already reported, so a bad grid says so once. */
|
|
976
976
|
private gridChecked;
|
|
977
977
|
private collidersDirty;
|
|
978
|
+
/** The `scale` the colliders were last built for — see `rebuildColliders`. */
|
|
979
|
+
private builtScale;
|
|
978
980
|
/** Replace the whole array to change the map (mutations are not watched). */
|
|
979
981
|
get cells(): (string | number[])[];
|
|
980
982
|
set cells(value: (string | number[])[]);
|
|
@@ -1247,4 +1249,4 @@ declare function parseCells(cells: readonly (string | readonly number[])[], lege
|
|
|
1247
1249
|
*/
|
|
1248
1250
|
declare function mergeSolidRects(grid: readonly (readonly number[])[], solid: Set<number>): TileRect[];
|
|
1249
1251
|
//#endregion
|
|
1250
|
-
export { AnimatedSprite2D, Area2D, type AssetStatus, AssetStore2D, Camera2D, CharacterBody2D, CharacterController2D, ColorRect2D, type CreateGame2DOptions, type Game2D, Joint2D, type JointType2D, Label, Node2D, Particles2D, Physics2D, type Physics2DOptions, PhysicsBody2D, Renderer2D, type Renderer2DOptions, type ResolvedSpriteTexture, RigidBody2D, type SheetInfo, Sprite2D, type SpriteFromLibraryResult, StaticBody2D, type Sync2DResult, type TextureLoadCallbacks, TileMap2D, type TileRect, type UIAnchor, UILayer, createGame2D, enablePhysics2D, mergeSolidRects, parseCells, registerNodes2D, spriteFromLibraryMeta, syncTree2D };
|
|
1252
|
+
export { AnimatedSprite2D, Area2D, type AssetStatus, AssetStore2D, Camera2D, CharacterBody2D, CharacterController2D, ColorRect2D, type CreateGame2DOptions, type Game2D, Joint2D, type JointType2D, Label, Node2D, Particles2D, Physics2D, type Physics2DOptions, PhysicsBody2D, Renderer2D, type Renderer2DOptions, type ResolvedSpriteTexture, RigidBody2D, type SheetInfo, Sprite2D, type SpriteFromLibraryResult, StaticBody2D, type Sync2DResult, type TextureLoadCallbacks, TileMap2D, type TileRect, type UIAnchor, UILayer, createGame2D, enablePhysics2D, isWebGLAvailable, mergeSolidRects, parseCells, registerNodes2D, showBootFailure, spriteFromLibraryMeta, syncTree2D };
|
package/dist/2d.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { t as showBootFailure } from "./boot-failure-CKYrEcGF.js";
|
|
3
|
+
import { t as isWebGLAvailable } from "./webgl-unavailable-Z5_g8x9H.js";
|
|
4
|
+
import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-CwxEDlCm.js";
|
|
5
|
+
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-DbVArsns.js";
|
|
6
|
+
import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-CF5yyjbj.js";
|
|
5
7
|
//#region src/2d/library-sprite.ts
|
|
6
8
|
/**
|
|
7
9
|
* What a `CharacterController2D`/`3D` will ask a skin to play, and the clip in
|
|
@@ -95,4 +97,4 @@ function spriteFromLibraryMeta(meta, opts) {
|
|
|
95
97
|
};
|
|
96
98
|
}
|
|
97
99
|
//#endregion
|
|
98
|
-
export { AnimatedSprite2D, Area2D, AssetStore2D, Camera2D, CharacterBody2D, CharacterController2D, ColorRect2D, Joint2D, Label, Node2D, Particles2D, Physics2D, PhysicsBody2D, Renderer2D, RigidBody2D, Sprite2D, StaticBody2D, TileMap2D, UILayer, createGame2D, enablePhysics2D, mergeSolidRects, parseCells, registerNodes2D, spriteFromLibraryMeta, syncTree2D };
|
|
100
|
+
export { AnimatedSprite2D, Area2D, AssetStore2D, Camera2D, CharacterBody2D, CharacterController2D, ColorRect2D, Joint2D, Label, Node2D, Particles2D, Physics2D, PhysicsBody2D, Renderer2D, RigidBody2D, Sprite2D, StaticBody2D, TileMap2D, UILayer, createGame2D, enablePhysics2D, isWebGLAvailable, mergeSolidRects, parseCells, registerNodes2D, showBootFailure, spriteFromLibraryMeta, syncTree2D };
|
package/dist/3d.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { t as
|
|
6
|
-
import {
|
|
1
|
+
import { c as showBootFailure, i as ParticleSim, o as ParticleView, r as SpatialPose, s as isWebGLAvailable } from "./audio-player-C0j2k-yB.js";
|
|
2
|
+
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, x as EngineOptions } from "./behavior-rm8vVzu_.js";
|
|
3
|
+
import { n as DiagnosticSink, t as EditorSwitchOptions } from "./editor-switch-CnIOiyNJ.js";
|
|
4
|
+
import { i as SceneJson$1, s as JsonObject } from "./schema-B6ugCV1Q.js";
|
|
5
|
+
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-DNxDAb1w.js";
|
|
6
|
+
import { t as LoadSceneOptions } from "./loader-DadV2QCT.js";
|
|
7
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";
|
|
@@ -1404,6 +1404,30 @@ declare class CharacterController3D extends Node3D {
|
|
|
1404
1404
|
pitchMax: number;
|
|
1405
1405
|
/** Spring-arm: pull the orbit camera in front of walls/ground instead of clipping. */
|
|
1406
1406
|
cameraCollision: boolean;
|
|
1407
|
+
/**
|
|
1408
|
+
* Ride whatever you are standing on.
|
|
1409
|
+
*
|
|
1410
|
+
* `false` restores the old behaviour: the controller steers toward a target
|
|
1411
|
+
* velocity in WORLD space, so standing still on a moving floor brakes you off
|
|
1412
|
+
* it. Turn it off for a conveyor you want to be scenery.
|
|
1413
|
+
*/
|
|
1414
|
+
platformCarry: boolean;
|
|
1415
|
+
/** The node the ground probe hit last step, and where it was. */
|
|
1416
|
+
private carriedBy;
|
|
1417
|
+
private carriedFrom;
|
|
1418
|
+
/**
|
|
1419
|
+
* How fast the floor is moving, in world units per second.
|
|
1420
|
+
*
|
|
1421
|
+
* From the POSITION DELTA, not `linearVelocity`, because the documented way
|
|
1422
|
+
* to author a platform is to move its `position` — a behavior, a `PathFollow`,
|
|
1423
|
+
* an `Oscillate` — and that path calls `body.setTranslation`, which teleports
|
|
1424
|
+
* and carries no momentum at all. The delta sees both kinds.
|
|
1425
|
+
*
|
|
1426
|
+
* Only while grounded on the SAME node two steps running: the first step on a
|
|
1427
|
+
* new platform has nothing to compare against, and inventing a velocity there
|
|
1428
|
+
* would fling the player on every step onto one.
|
|
1429
|
+
*/
|
|
1430
|
+
private groundCarry;
|
|
1407
1431
|
turnSpeed: number;
|
|
1408
1432
|
/** Camera smoothing rate (1-exp(-rate·dt)); side view uses 5. */
|
|
1409
1433
|
camLerp: number;
|
|
@@ -4106,4 +4130,4 @@ declare function createNavDebugNode(nav: TerrainNav, opts?: {
|
|
|
4106
4130
|
name?: string;
|
|
4107
4131
|
}): InstancedMesh3D;
|
|
4108
4132
|
//#endregion
|
|
4109
|
-
export { Area3D, AssetStore3D, type BedSampler, Billboard3D, type BillboardGroupMode, BoneAttachment3D, BoneLookAt3D, Camera3D, CharacterBody3D, CharacterController3D, type CreateGame3DOptions, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, type DownhillTraceOptions, Environment3D, type Environment3DConfig, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, type FlowerVariety, Flowers3D, type FogEnvironment, Foliage3D, type FoliageKind, type FoliageStyle, type FrameDiff, type FrameSignature, type FrameStats, type FrameStatsOptions, type Game3D, type GridCell, type HeightSampler, type Heightmap, type HeightmapOptions, InstancedMesh3D, Joint3D, type JointType3D, LoftMesh3D, type LoftSection, MeshInstance3D, type MeshKind, type MeshMaterialProps, type ModelEntry, type ModelFacts, ModelInstance3D, type ModelVerdict, Node3D, OmniLight3D, Particles3D, Physics3D, type Physics3DOptions, PhysicsBody3D, QUARTER_PITCH, type RenderContext3D, type RenderHook3D, Renderer3D, type Renderer3DOptions, type Rig, type RigView, RigidBody3D, type Ripple, River3D, type RiverCarveOptions, type RiverCoverageGap, type RiverHit, type RiverRing, type RiverRingOptions, SIGNATURE_GRID, type SceneJson, type ShadowsEnvironment, type SkyEnvironment, StaticBody3D, type SunConsumer3D, type SyncOptions, type SyncResult, TERRAIN_THEMES, Terrain3D, type TerrainLayer, type TerrainNav, type TerrainNavOptions, type TerrainTheme, TextureCache3D, type TextureSpec, Trail3D, Tree3D, type TreeTier, type TreeType, VOXEL_PALETTE, type VoxelBlock, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, acquireOwnTexture, acquireTexture, applyQualityTier3D, buildHeightmap, buildRiverRings, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, diffSignatures, diffText, enablePhysics3D, findRiverCoverageGaps, frameSignature, frameStats, frameText, horizonColorFromSky, keyboardIntensity, modelVerdict, movementState, parseEnvironment3D, projectToRiver, registerNodes3D, resolveFlowerDensity, rigPose, riverCarveChannels, riverStepFor, setEnvironment3D, smoothCourse, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath, verdictText };
|
|
4133
|
+
export { Area3D, AssetStore3D, type BedSampler, Billboard3D, type BillboardGroupMode, BoneAttachment3D, BoneLookAt3D, Camera3D, CharacterBody3D, CharacterController3D, type CreateGame3DOptions, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, type DownhillTraceOptions, Environment3D, type Environment3DConfig, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, type FlowerVariety, Flowers3D, type FogEnvironment, Foliage3D, type FoliageKind, type FoliageStyle, type FrameDiff, type FrameSignature, type FrameStats, type FrameStatsOptions, type Game3D, type GridCell, type HeightSampler, type Heightmap, type HeightmapOptions, InstancedMesh3D, Joint3D, type JointType3D, LoftMesh3D, type LoftSection, MeshInstance3D, type MeshKind, type MeshMaterialProps, type ModelEntry, type ModelFacts, ModelInstance3D, type ModelVerdict, Node3D, OmniLight3D, Particles3D, Physics3D, type Physics3DOptions, PhysicsBody3D, QUARTER_PITCH, type RenderContext3D, type RenderHook3D, Renderer3D, type Renderer3DOptions, type Rig, type RigView, RigidBody3D, type Ripple, River3D, type RiverCarveOptions, type RiverCoverageGap, type RiverHit, type RiverRing, type RiverRingOptions, SIGNATURE_GRID, type SceneJson, type ShadowsEnvironment, type SkyEnvironment, StaticBody3D, type SunConsumer3D, type SyncOptions, type SyncResult, TERRAIN_THEMES, Terrain3D, type TerrainLayer, type TerrainNav, type TerrainNavOptions, type TerrainTheme, TextureCache3D, type TextureSpec, Trail3D, Tree3D, type TreeTier, type TreeType, VOXEL_PALETTE, type VoxelBlock, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, acquireOwnTexture, acquireTexture, applyQualityTier3D, buildHeightmap, buildRiverRings, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, diffSignatures, diffText, enablePhysics3D, findRiverCoverageGaps, frameSignature, frameStats, frameText, horizonColorFromSky, isWebGLAvailable, keyboardIntensity, modelVerdict, movementState, parseEnvironment3D, projectToRiver, registerNodes3D, resolveFlowerDensity, rigPose, riverCarveChannels, riverStepFor, setEnvironment3D, showBootFailure, smoothCourse, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath, verdictText };
|
package/dist/3d.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { c as parseEnvironment3D, l as sunDirectionFromElevationAzimuth, s as horizonColorFromSky, u as sunDirectionFromSky } from "./loader-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { c as parseEnvironment3D, l as sunDirectionFromElevationAzimuth, s as horizonColorFromSky, u as sunDirectionFromSky } from "./loader-DZE7B07H.js";
|
|
2
|
+
import { t as showBootFailure } from "./boot-failure-CKYrEcGF.js";
|
|
3
|
+
import { t as isWebGLAvailable } from "./webgl-unavailable-Z5_g8x9H.js";
|
|
4
|
+
import { a as frameSignature, n as diffSignatures, o as frameStats, r as diffText, s as frameText, t as SIGNATURE_GRID } from "./frame-report-Dlq13Gyj.js";
|
|
5
|
+
import { G as StaticBody3D, H as CharacterBody3D, K as Node3D, L as Water3D, R as WATER_CUTOUT_MAX, U as PhysicsBody3D, V as Area3D, W as RigidBody3D, Y as WATER_MAX_RIPPLES, z as WaterCutout3D } from "./gameplay-D1KixWK8.js";
|
|
6
|
+
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-BO-7XoFV.js";
|
|
7
|
+
import { a as Environment3D, c as AssetStore3D, i as syncTree, o as applyQualityTier3D, r as Renderer3D, s as setEnvironment3D, t as createGame3D } from "./create-game-CvJ1wSRP.js";
|
|
6
8
|
import { n as splatWeights, t as buildHeightmap } from "./heightmap-CRK0M4jT.js";
|
|
7
|
-
import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-
|
|
9
|
+
import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-DbYaEcZy.js";
|
|
8
10
|
//#region src/3d/model-verdict.ts
|
|
9
11
|
/** Mixamo exports every bone as `mixamorigX`; the retargeter binds by that name. */
|
|
10
12
|
const MIXAMO = /^mixamorig[:_]?/i;
|
|
@@ -317,4 +319,4 @@ function createNavDebugNode(nav, opts) {
|
|
|
317
319
|
return node;
|
|
318
320
|
}
|
|
319
321
|
//#endregion
|
|
320
|
-
export { Area3D, AssetStore3D, Billboard3D, BoneAttachment3D, BoneLookAt3D, Camera3D, CharacterBody3D, CharacterController3D, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, Environment3D, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, Flowers3D, Foliage3D, InstancedMesh3D, Joint3D, LoftMesh3D, MeshInstance3D, ModelInstance3D, Node3D, OmniLight3D, Particles3D, Physics3D, PhysicsBody3D, QUARTER_PITCH, Renderer3D, RigidBody3D, River3D, SIGNATURE_GRID, StaticBody3D, TERRAIN_THEMES, Terrain3D, TextureCache3D, Trail3D, Tree3D, VOXEL_PALETTE, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, acquireOwnTexture, acquireTexture, applyQualityTier3D, buildHeightmap, buildRiverRings, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, diffSignatures, diffText, enablePhysics3D, findRiverCoverageGaps, frameSignature, frameStats, frameText, horizonColorFromSky, keyboardIntensity, modelVerdict, movementState, parseEnvironment3D, projectToRiver, registerNodes3D, resolveFlowerDensity, rigPose, riverCarveChannels, riverStepFor, setEnvironment3D, smoothCourse, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath, verdictText };
|
|
322
|
+
export { Area3D, AssetStore3D, Billboard3D, BoneAttachment3D, BoneLookAt3D, Camera3D, CharacterBody3D, CharacterController3D, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, Environment3D, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, Flowers3D, Foliage3D, InstancedMesh3D, Joint3D, LoftMesh3D, MeshInstance3D, ModelInstance3D, Node3D, OmniLight3D, Particles3D, Physics3D, PhysicsBody3D, QUARTER_PITCH, Renderer3D, RigidBody3D, River3D, SIGNATURE_GRID, StaticBody3D, TERRAIN_THEMES, Terrain3D, TextureCache3D, Trail3D, Tree3D, VOXEL_PALETTE, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, acquireOwnTexture, acquireTexture, applyQualityTier3D, buildHeightmap, buildRiverRings, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, diffSignatures, diffText, enablePhysics3D, findRiverCoverageGaps, frameSignature, frameStats, frameText, horizonColorFromSky, isWebGLAvailable, keyboardIntensity, modelVerdict, movementState, parseEnvironment3D, projectToRiver, registerNodes3D, resolveFlowerDensity, rigPose, riverCarveChannels, riverStepFor, setEnvironment3D, showBootFailure, smoothCourse, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath, verdictText };
|
|
@@ -1,6 +1,42 @@
|
|
|
1
|
-
import { d as PropSchema, dt as Listener, jt as Node } from "./behavior-
|
|
2
|
-
import { a as Rng } from "./schema-
|
|
1
|
+
import { d as PropSchema, dt as Listener, jt as Node } from "./behavior-rm8vVzu_.js";
|
|
2
|
+
import { a as Rng } from "./schema-B6ugCV1Q.js";
|
|
3
3
|
|
|
4
|
+
//#region src/core/boot-failure.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Put a boot failure on the SCREEN, where the player is looking.
|
|
7
|
+
*
|
|
8
|
+
* Every shipped starter preloads its assets behind a `#loading` overlay and
|
|
9
|
+
* removes that overlay on the line after `await createGame*`. So anything that
|
|
10
|
+
* rejects — no WebGL context, a scene that will not load, a 404 the preload
|
|
11
|
+
* insisted on — leaves the overlay standing at "100%" forever, with the reason
|
|
12
|
+
* in a console the player will never open. Measured on a pristine scaffold with
|
|
13
|
+
* WebGL denied:
|
|
14
|
+
*
|
|
15
|
+
* ```
|
|
16
|
+
* control #loading gone "Talk to the Elder [E] …"
|
|
17
|
+
* no webgl #loading present "Emberwood 100%" … and still there 8.6 s later
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* A bar that reaches 100% and stops reads as a hang, which is the one failure
|
|
21
|
+
* mode a player cannot report usefully. This turns it into a sentence.
|
|
22
|
+
*
|
|
23
|
+
* Headless it does nothing but rethrow-safe logging, so a test that boots a
|
|
24
|
+
* game without a document is unaffected.
|
|
25
|
+
*/
|
|
26
|
+
declare function showBootFailure(error: unknown, opts?: {
|
|
27
|
+
into?: string;
|
|
28
|
+
}): void;
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/core/webgl-unavailable.d.ts
|
|
31
|
+
/**
|
|
32
|
+
* Can this document make a WebGL context at all?
|
|
33
|
+
*
|
|
34
|
+
* The question a game wants BEFORE it boots, so the answer can be a screen
|
|
35
|
+
* instead of an exception. Uses a throwaway canvas and never touches yours;
|
|
36
|
+
* `false` outside a browser, where the question is not meaningful.
|
|
37
|
+
*/
|
|
38
|
+
declare function isWebGLAvailable(): boolean;
|
|
39
|
+
//#endregion
|
|
4
40
|
//#region src/core/particle-sim.d.ts
|
|
5
41
|
/**
|
|
6
42
|
* Deterministic particle pool — pure math, renderer-agnostic, headless-
|
|
@@ -197,6 +233,47 @@ declare class AudioPlayer extends Node {
|
|
|
197
233
|
private spatialElementGain;
|
|
198
234
|
/** The `spatial` option for the SFX path, or undefined when not spatial. */
|
|
199
235
|
private spatialPlay;
|
|
236
|
+
/**
|
|
237
|
+
* Start the sound, now.
|
|
238
|
+
*
|
|
239
|
+
* **Takes no arguments, on purpose.** This is the method scenes wire signals
|
|
240
|
+
* to — `incanto-audio.md` teaches
|
|
241
|
+
* `{"signal": "collected", "from": "Player/Collector", "to": "Coin",
|
|
242
|
+
* "handler": "play"}` — and a signal hands its handler whatever it carries.
|
|
243
|
+
* `collected` leads with a NUMBER. When this briefly took an optional
|
|
244
|
+
* scheduling time, that wiring became `play(10)`, which scheduled the pickup
|
|
245
|
+
* sound at ABSOLUTE audio-clock second 10: inaudible for the first ten
|
|
246
|
+
* seconds of the game and fine thereafter. The same optional parameter also
|
|
247
|
+
* made `Function.length` 1, so the engine's own arity checker cried wolf on
|
|
248
|
+
* the shipped `platformer-2d` template's own harness.
|
|
249
|
+
*
|
|
250
|
+
* Scheduling has its own name: {@link playAt}.
|
|
251
|
+
*/
|
|
252
|
+
/**
|
|
253
|
+
* Start the sound at `when` on the AUDIO clock (`engine.sfx.now` + a lead).
|
|
254
|
+
*
|
|
255
|
+
* A frame is a 16.67 ms grid at 60 Hz and 33.33 ms at 30, so a sound fired
|
|
256
|
+
* from `update()` cannot land closer than one frame to where a chart wants
|
|
257
|
+
* it — measured 0 of 64 notes given a scheduled start. Queue them a lead
|
|
258
|
+
* ahead and the same notes land at |mean| 0.000000 ms:
|
|
259
|
+
*
|
|
260
|
+
* ```ts
|
|
261
|
+
* const LEAD = 0.08;
|
|
262
|
+
* for (const note of dueSoon(engine.sfx.now + LEAD)) {
|
|
263
|
+
* hit.playAt(startedAt + note.atSec);
|
|
264
|
+
* }
|
|
265
|
+
* ```
|
|
266
|
+
*
|
|
267
|
+
* PRESETS only — a `src` clip goes through an `<audio>` element, which has no
|
|
268
|
+
* scheduling clock, so `playAt` on one plays immediately rather than being
|
|
269
|
+
* silently approximated. A time already past plays now (Web Audio's own
|
|
270
|
+
* rule), so a late scheduler is late, not silent. The bus gain, the
|
|
271
|
+
* `engine.audio.recent()` entry and `muted` all still apply.
|
|
272
|
+
*
|
|
273
|
+
* Separate from {@link play} because `play` is what scenes wire signals to,
|
|
274
|
+
* and a signal hands its handler whatever it carries.
|
|
275
|
+
*/
|
|
276
|
+
playAt(when: number): void;
|
|
200
277
|
play(): void;
|
|
201
278
|
/**
|
|
202
279
|
* Procedural-SFX path: synthesize the preset and fire it through WebAudio
|
|
@@ -222,4 +299,4 @@ declare class AudioPlayer extends Node {
|
|
|
222
299
|
override update(_dt: number): void;
|
|
223
300
|
}
|
|
224
301
|
//#endregion
|
|
225
|
-
export { ParticleSimConfig as a, ParticleSim as i, AudioPlayer as n, ParticleView as o, SpatialPose as r, AudioElementLike as t };
|
|
302
|
+
export { ParticleSimConfig as a, showBootFailure as c, ParticleSim as i, AudioPlayer as n, ParticleView as o, SpatialPose as r, isWebGLAvailable as s, AudioElementLike as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as Rng, c as JsonValue, i as SceneJson, s as JsonObject } from "./schema-
|
|
1
|
+
import { a as Rng, c as JsonValue, i as SceneJson, s as JsonObject } from "./schema-B6ugCV1Q.js";
|
|
2
2
|
|
|
3
3
|
//#region src/core/signal.d.ts
|
|
4
4
|
/**
|
|
@@ -353,6 +353,15 @@ interface AudioEvent {
|
|
|
353
353
|
bus: BusName;
|
|
354
354
|
/** `engine.time` when it fired, in seconds. */
|
|
355
355
|
at: number;
|
|
356
|
+
/**
|
|
357
|
+
* It repeats until stopped, rather than ending on its own.
|
|
358
|
+
*
|
|
359
|
+
* A looping sound is recorded ONCE — re-recording every pass would evict the
|
|
360
|
+
* rest of the log within seconds for a 0.2 s preset — so without this a
|
|
361
|
+
* headless check could not tell "the alarm loops" from "the alarm fired once
|
|
362
|
+
* and stopped". Both read `countOf('alarm') === 1`.
|
|
363
|
+
*/
|
|
364
|
+
loop?: boolean;
|
|
356
365
|
}
|
|
357
366
|
declare class AudioBuses {
|
|
358
367
|
/** Fires whenever any value changes (drives live re-gain of playing sounds). */
|
|
@@ -419,6 +428,12 @@ interface MusicTrack {
|
|
|
419
428
|
play(): void;
|
|
420
429
|
/** Stop and release the underlying element/source. */
|
|
421
430
|
stop(): void;
|
|
431
|
+
/**
|
|
432
|
+
* Seconds into the track, or `null` when the backend cannot say.
|
|
433
|
+
*
|
|
434
|
+
* Optional so an existing custom backend keeps compiling.
|
|
435
|
+
*/
|
|
436
|
+
playhead?(): number | null;
|
|
422
437
|
}
|
|
423
438
|
/** Backend that mints {@link MusicTrack}s — WebAudio-backed in the browser. */
|
|
424
439
|
interface MusicBackend {
|
|
@@ -470,6 +485,22 @@ declare class MusicManager {
|
|
|
470
485
|
constructor(buses: AudioBuses);
|
|
471
486
|
/** Source of the logically-current track, or null when nothing is playing. */
|
|
472
487
|
get current(): string | null;
|
|
488
|
+
/**
|
|
489
|
+
* Seconds into the current track — the playhead of the thing you can HEAR.
|
|
490
|
+
*
|
|
491
|
+
* `null` when nothing is playing, or when the backend has no clock (headless,
|
|
492
|
+
* or a custom backend that does not implement it).
|
|
493
|
+
*
|
|
494
|
+
* A game charted to a soundtrack needs this and there was no way to get it:
|
|
495
|
+
* `current` gave the src and the backend was private, so the only option was
|
|
496
|
+
* an `engine.time` counter started next to `music.play()` — a different clock
|
|
497
|
+
* from the one the audio is on, and one that keeps counting through a
|
|
498
|
+
* gesture-block, a stall or a seek. This is the audio's own answer.
|
|
499
|
+
*
|
|
500
|
+
* It is the RAW element time, so a looping track wraps to 0 at each pass:
|
|
501
|
+
* that is a loop boundary you can chart against, not a fault.
|
|
502
|
+
*/
|
|
503
|
+
get playhead(): number | null;
|
|
473
504
|
/** Per-manager volume (0..1), on top of the bus gain. */
|
|
474
505
|
get volume(): number;
|
|
475
506
|
/**
|
|
@@ -694,6 +725,23 @@ interface SfxPlayOptions {
|
|
|
694
725
|
seed?: number;
|
|
695
726
|
/** When set, the sound is spatialized through a PannerNode at this emitter. */
|
|
696
727
|
spatial?: SpatialPlay;
|
|
728
|
+
/**
|
|
729
|
+
* Start at this point on the AUDIO clock (`engine.sfx.now` + lead), instead
|
|
730
|
+
* of "as soon as this call returns".
|
|
731
|
+
*
|
|
732
|
+
* Nothing in the audio API took a time, so a sound could only be fired from a
|
|
733
|
+
* frame — and a frame is a 16.67 ms grid at 60 Hz, 33.33 ms at 30. Measured
|
|
734
|
+
* on a metronome: firing from `update()` gave 0 of 64 notes a scheduled
|
|
735
|
+
* start; the same notes queued one frame ahead with `when` land at
|
|
736
|
+
* |mean| 0.000000 ms. That difference is the whole of a rhythm game, and
|
|
737
|
+
* anything charted to a soundtrack.
|
|
738
|
+
*
|
|
739
|
+
* A time already past plays immediately (Web Audio's own rule), so a late
|
|
740
|
+
* scheduler degrades instead of going silent. The bus gain and the
|
|
741
|
+
* `engine.audio.recent()` record apply either way — which is what a
|
|
742
|
+
* hand-rolled `AudioContext` scheduler loses.
|
|
743
|
+
*/
|
|
744
|
+
when?: number;
|
|
697
745
|
}
|
|
698
746
|
/**
|
|
699
747
|
* One AudioContext + a PCM cache. Instance-scoped (held by the renderer's game
|
|
@@ -741,6 +789,14 @@ declare class SfxEngine {
|
|
|
741
789
|
/** Resume a gesture-suspended context (wired to the first user gesture). */
|
|
742
790
|
unlock(): void;
|
|
743
791
|
/**
|
|
792
|
+
* The AUDIO clock, in seconds — the one a sound is actually scheduled
|
|
793
|
+
* against, and the only clock that does not drift relative to what you hear.
|
|
794
|
+
*
|
|
795
|
+
* `0` headless and before the first sound, since there is no context yet.
|
|
796
|
+
* Schedule with a lead: `sfx.play(params, 1, { when: sfx.now + 0.08 })`.
|
|
797
|
+
*/
|
|
798
|
+
get now(): number;
|
|
799
|
+
/**
|
|
744
800
|
* Play a preset at `gain` (0..1, already bus-multiplied by the caller). Each
|
|
745
801
|
* call spawns its own source so rapid repeats overlap instead of cutting off.
|
|
746
802
|
* Headless → no-op.
|
|
@@ -839,6 +895,10 @@ declare class InputMap {
|
|
|
839
895
|
private readonly injectedDown;
|
|
840
896
|
private readonly injectedPressed;
|
|
841
897
|
private readonly injectedReleased;
|
|
898
|
+
private readonly injectedPressedNext;
|
|
899
|
+
private readonly injectedReleasedNext;
|
|
900
|
+
/** True between the start of a frame's update pass and `endFrame()`. */
|
|
901
|
+
private inFrame;
|
|
842
902
|
private readonly injectedVectors;
|
|
843
903
|
/**
|
|
844
904
|
* Press a button ACTION directly — no key codes involved. This is how
|
|
@@ -990,6 +1050,9 @@ declare class InputMap {
|
|
|
990
1050
|
};
|
|
991
1051
|
/** Consume one-frame edges. The Engine calls this at the end of every tick. */
|
|
992
1052
|
endFrame(): void;
|
|
1053
|
+
/** @internal The engine marks the update phase, so an edge injected inside
|
|
1054
|
+
* it can be held for the next frame. */
|
|
1055
|
+
beginFrame(): void;
|
|
993
1056
|
/**
|
|
994
1057
|
* Drop all action declarations and injected action state (physical key
|
|
995
1058
|
* state is kept). The Engine calls this on setScene so keybinds never
|
|
@@ -1182,6 +1245,25 @@ interface SaveStore {
|
|
|
1182
1245
|
remove(key: string): void;
|
|
1183
1246
|
/** Wipe THIS namespace only. */
|
|
1184
1247
|
clear(): void;
|
|
1248
|
+
/**
|
|
1249
|
+
* Does a write here survive the page closing?
|
|
1250
|
+
*
|
|
1251
|
+
* `false` means this store is a Map that lives as long as the tab does — a
|
|
1252
|
+
* private window, storage disabled, quota exhausted, or headless. Everything
|
|
1253
|
+
* still works IN the session, which is exactly what made it undetectable:
|
|
1254
|
+
* measured in Safari-private conditions, `set('highScore', 4200)` then
|
|
1255
|
+
* `get('highScore', 0)` returned 4200, zero warnings, and the interface had
|
|
1256
|
+
* no way to ask. On reload the score was 0, the slot list empty, and
|
|
1257
|
+
* `SavePoint` had emitted `saved(1)` for a write that went nowhere.
|
|
1258
|
+
*
|
|
1259
|
+
* Read it once and tell the player their progress will not be kept.
|
|
1260
|
+
*
|
|
1261
|
+
* Optional so a game that injects its OWN store (a cloud backend, a test
|
|
1262
|
+
* double) keeps compiling; absent counts as persistent, which is what a store
|
|
1263
|
+
* somebody wrote on purpose almost always is. Every store the engine makes
|
|
1264
|
+
* says so explicitly.
|
|
1265
|
+
*/
|
|
1266
|
+
readonly persistent?: boolean;
|
|
1185
1267
|
}
|
|
1186
1268
|
declare function createSaveStore(namespace: string): SaveStore;
|
|
1187
1269
|
//#endregion
|
|
@@ -1261,6 +1343,15 @@ declare function restoreBehaviors(root: Node, state: BehaviorState): RestoreRepo
|
|
|
1261
1343
|
declare class SaveSlots {
|
|
1262
1344
|
private readonly store;
|
|
1263
1345
|
constructor(namespace?: string, store?: SaveStore);
|
|
1346
|
+
/**
|
|
1347
|
+
* Will these slots survive the page closing?
|
|
1348
|
+
*
|
|
1349
|
+
* `false` in a private window, with storage disabled, or headless — every
|
|
1350
|
+
* write still succeeds and every read still answers, for as long as the tab
|
|
1351
|
+
* lives. A load menu should say so instead of offering a slot that will not
|
|
1352
|
+
* be there tomorrow.
|
|
1353
|
+
*/
|
|
1354
|
+
get persistent(): boolean;
|
|
1264
1355
|
/** Slot ids that have a save, newest first. */
|
|
1265
1356
|
list(): string[];
|
|
1266
1357
|
/** Every slot with its contents — what a load menu actually renders. */
|
|
@@ -1331,6 +1422,8 @@ declare class Scene {
|
|
|
1331
1422
|
readonly orderGroups: Record<string, number> | undefined;
|
|
1332
1423
|
/** Physics config (gravity etc. — interpreted by the physics modules). */
|
|
1333
1424
|
readonly physics: JsonObject | undefined;
|
|
1425
|
+
/** Declared piece of another scene — see `SceneJson.fragment`. */
|
|
1426
|
+
readonly fragment: boolean | undefined;
|
|
1334
1427
|
/** Multiplayer config (room etc. — interpreted by incanto/net). */
|
|
1335
1428
|
readonly multiplayer: JsonObject | undefined;
|
|
1336
1429
|
/** Design-resolution viewport (consumed by renderers via resolveViewport). */
|
|
@@ -1577,6 +1670,24 @@ interface EngineStats {
|
|
|
1577
1670
|
fps: number;
|
|
1578
1671
|
/** Mean frame delta in ms over the same window (headless runs: 0). */
|
|
1579
1672
|
frameMs: number;
|
|
1673
|
+
/**
|
|
1674
|
+
* How long ago the newest frame arrived, in ms. `null` when none has.
|
|
1675
|
+
*
|
|
1676
|
+
* `fps` is a rate over a WINDOW, so it keeps answering after the frames stop
|
|
1677
|
+
* — a hidden tab, a descheduled loop, a page the browser froze. Measured on
|
|
1678
|
+
* an engine that ticked 40 times and then stopped being ticked:
|
|
1679
|
+
*
|
|
1680
|
+
* ```
|
|
1681
|
+
* while ticking : fps 59.9
|
|
1682
|
+
* after 0 more ticks : fps 59.9 <- the last sample is 668 ms old
|
|
1683
|
+
* ```
|
|
1684
|
+
*
|
|
1685
|
+
* Both numbers are true about the window they describe; nothing said WHEN
|
|
1686
|
+
* that window was, so "60 fps" read the same whether it was measured 8 ms ago
|
|
1687
|
+
* or four seconds ago. A reader that cares should compare this against a
|
|
1688
|
+
* frame budget before trusting `fps`.
|
|
1689
|
+
*/
|
|
1690
|
+
lastFrameAgeMs: number | null;
|
|
1580
1691
|
/** Current node count of the active scene tree (no scene: 0). */
|
|
1581
1692
|
nodes: number;
|
|
1582
1693
|
/** Whether the loop is scheduled (start() without stop()/dispose()). */
|
|
@@ -1673,6 +1784,39 @@ declare class Engine {
|
|
|
1673
1784
|
* learns about Rapier or three. From a behavior, prefer `this.physics`.
|
|
1674
1785
|
*/
|
|
1675
1786
|
physics: PhysicsQuery | null;
|
|
1787
|
+
/**
|
|
1788
|
+
* How to build a physics world for a scene that needs one.
|
|
1789
|
+
*
|
|
1790
|
+
* `createGame2D`/`createGame3D` install this; core never learns what Rapier
|
|
1791
|
+
* is. It exists because `physics: 'auto'` can only look at the scene the game
|
|
1792
|
+
* BOOTED with, and the most universal act of finishing a game is putting a
|
|
1793
|
+
* title screen in front of it:
|
|
1794
|
+
*
|
|
1795
|
+
* ```
|
|
1796
|
+
* after boot on the title : engine.physics = null
|
|
1797
|
+
* after goToScene into game: engine.physics = null
|
|
1798
|
+
* player y after 2 s : 0 -> 0
|
|
1799
|
+
* ```
|
|
1800
|
+
*
|
|
1801
|
+
* The game rendered perfectly and was inert — nothing fell, nothing collided,
|
|
1802
|
+
* nothing could be collected or hurt. One scene swap turned a working game
|
|
1803
|
+
* into a diorama, and nothing was logged.
|
|
1804
|
+
*/
|
|
1805
|
+
physicsProvider: ((root: Node) => Promise<void>) | null;
|
|
1806
|
+
private ensuring;
|
|
1807
|
+
/**
|
|
1808
|
+
* Give the current scene a physics world if it needs one and has none.
|
|
1809
|
+
*
|
|
1810
|
+
* Idempotent and safe to call on every swap: the provider decides whether the
|
|
1811
|
+
* incoming tree actually wants physics, and an explicit `physics: false` at
|
|
1812
|
+
* boot installs no provider at all, so opting out stays opted out.
|
|
1813
|
+
*
|
|
1814
|
+
* Asynchronous because the Rapier WASM has to load. The first frames after a
|
|
1815
|
+
* swap therefore run unsimulated — which every AI behaviour already tolerates
|
|
1816
|
+
* (`moveBody` falls back to a direct write when `_physics` is null) and which
|
|
1817
|
+
* is a hitch, where the alternative was a game that never simulated at all.
|
|
1818
|
+
*/
|
|
1819
|
+
ensurePhysics(): Promise<void>;
|
|
1676
1820
|
/** Seeded randomness for game logic (deterministic when `seed` is set). */
|
|
1677
1821
|
readonly rng: Rng;
|
|
1678
1822
|
/** The engine log channel (debug overlay + headless harness tail this). */
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
2
|
+
//#region src/core/boot-failure.ts
|
|
3
|
+
/**
|
|
4
|
+
* Put a boot failure on the SCREEN, where the player is looking.
|
|
5
|
+
*
|
|
6
|
+
* Every shipped starter preloads its assets behind a `#loading` overlay and
|
|
7
|
+
* removes that overlay on the line after `await createGame*`. So anything that
|
|
8
|
+
* rejects — no WebGL context, a scene that will not load, a 404 the preload
|
|
9
|
+
* insisted on — leaves the overlay standing at "100%" forever, with the reason
|
|
10
|
+
* in a console the player will never open. Measured on a pristine scaffold with
|
|
11
|
+
* WebGL denied:
|
|
12
|
+
*
|
|
13
|
+
* ```
|
|
14
|
+
* control #loading gone "Talk to the Elder [E] …"
|
|
15
|
+
* no webgl #loading present "Emberwood 100%" … and still there 8.6 s later
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* A bar that reaches 100% and stops reads as a hang, which is the one failure
|
|
19
|
+
* mode a player cannot report usefully. This turns it into a sentence.
|
|
20
|
+
*
|
|
21
|
+
* Headless it does nothing but rethrow-safe logging, so a test that boots a
|
|
22
|
+
* game without a document is unaffected.
|
|
23
|
+
*/
|
|
24
|
+
function showBootFailure(error, opts = {}) {
|
|
25
|
+
const message = error instanceof IncantoError ? error.message : String(error?.message ?? error);
|
|
26
|
+
const code = error instanceof IncantoError ? error.code : null;
|
|
27
|
+
console.error(`[incanto] the game could not start${code ? ` (${code})` : ""}: ${message}`);
|
|
28
|
+
const doc = globalThis.document;
|
|
29
|
+
if (!doc?.body) return;
|
|
30
|
+
const host = opts.into ? doc.querySelector(opts.into) : doc.querySelector("#loading");
|
|
31
|
+
const panel = host ?? doc.createElement("div");
|
|
32
|
+
if (!host) {
|
|
33
|
+
panel.style.cssText = "position:fixed;inset:0;display:grid;place-content:center;gap:12px;padding:32px;background:#10131a;color:#e6e9ef;z-index:2147483647;font:14px/1.6 system-ui,sans-serif;text-align:center";
|
|
34
|
+
doc.body.appendChild(panel);
|
|
35
|
+
}
|
|
36
|
+
panel.textContent = "";
|
|
37
|
+
const title = doc.createElement("div");
|
|
38
|
+
title.textContent = "This game could not start";
|
|
39
|
+
title.style.cssText = "font-size:18px;font-weight:600;margin-bottom:8px";
|
|
40
|
+
const detail = doc.createElement("div");
|
|
41
|
+
detail.textContent = message;
|
|
42
|
+
detail.style.cssText = "opacity:.85;max-width:52ch;margin:0 auto";
|
|
43
|
+
panel.appendChild(title);
|
|
44
|
+
panel.appendChild(detail);
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
export { showBootFailure as t };
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import { c as parseEnvironment3D, k as diagnose, n as loadScene, s as horizonColorFromSky, u as sunDirectionFromSky, z as registerBehavior } from "./loader-
|
|
3
|
-
import { C as qualityRendering, _ as AudioPlayer, v as Engine, x as qualityCaps } from "./register-
|
|
2
|
+
import { c as parseEnvironment3D, k as diagnose, n as loadScene, s as horizonColorFromSky, u as sunDirectionFromSky, z as registerBehavior } from "./loader-DZE7B07H.js";
|
|
3
|
+
import { C as qualityRendering, _ as AudioPlayer, v as Engine, x as qualityCaps } from "./register-mmfugpaQ.js";
|
|
4
4
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
5
5
|
import { n as attachTouchControls } from "./touch-DEAmqGdf.js";
|
|
6
|
-
import {
|
|
7
|
-
import { a as openBundledEditor, c as claimCanvasGestures, i as devServerLibrary, l as audioErrors, n as pauseWhenHidden, o as poseFromRenderer, r as crossFade, s as wireDevChannel, t as teardown } from "./teardown-
|
|
8
|
-
import { o as frameStats } from "./frame-report-
|
|
9
|
-
import { J as createCausticsQuad, K as Node3D, U as PhysicsBody3D, n as registerGameplayBehaviors } from "./gameplay-
|
|
6
|
+
import { n as withWebGLContext, r as resolveRendering } from "./webgl-unavailable-Z5_g8x9H.js";
|
|
7
|
+
import { a as openBundledEditor, c as claimCanvasGestures, i as devServerLibrary, l as audioErrors, n as pauseWhenHidden, o as poseFromRenderer, r as crossFade, s as wireDevChannel, t as teardown } from "./teardown-CMqFVxO9.js";
|
|
8
|
+
import { o as frameStats } from "./frame-report-Dlq13Gyj.js";
|
|
9
|
+
import { J as createCausticsQuad, K as Node3D, U as PhysicsBody3D, n as registerGameplayBehaviors } from "./gameplay-D1KixWK8.js";
|
|
10
10
|
import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
|
|
11
|
-
import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-
|
|
12
|
-
import { n as enablePhysics3D } from "./physics-3d-
|
|
11
|
+
import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-BO-7XoFV.js";
|
|
12
|
+
import { n as enablePhysics3D } from "./physics-3d-DbYaEcZy.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";
|
|
@@ -87,22 +87,18 @@ var AssetStore3D = class {
|
|
|
87
87
|
url,
|
|
88
88
|
error
|
|
89
89
|
});
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
url: decl.url,
|
|
103
|
-
error: String(entry.error)
|
|
104
|
-
});
|
|
105
|
-
}
|
|
90
|
+
const modelRefs = new Map([...this.modelKeys].map(([ref, url]) => [url, ref]));
|
|
91
|
+
for (const [url, entry] of this.models) if (entry.error) out.push({
|
|
92
|
+
ref: modelRefs.get(url) ?? url,
|
|
93
|
+
url,
|
|
94
|
+
error: String(entry.error)
|
|
95
|
+
});
|
|
96
|
+
const clipRefs = new Map([...this.animationKeys].map(([ref, decl]) => [decl.url, ref]));
|
|
97
|
+
for (const [url, entry] of this.animations) if (entry.error) out.push({
|
|
98
|
+
ref: clipRefs.get(url) ?? url,
|
|
99
|
+
url,
|
|
100
|
+
error: String(entry.error)
|
|
101
|
+
});
|
|
106
102
|
return out;
|
|
107
103
|
}
|
|
108
104
|
/** Map a scene's `assets` header. */
|
|
@@ -1491,11 +1487,11 @@ var Renderer3D = class {
|
|
|
1491
1487
|
pixelRatio: opts.pixelRatio,
|
|
1492
1488
|
preserveDrawingBuffer: opts.preserveDrawingBuffer
|
|
1493
1489
|
});
|
|
1494
|
-
this.webgl = new WebGLRenderer({
|
|
1490
|
+
this.webgl = withWebGLContext(() => new WebGLRenderer({
|
|
1495
1491
|
canvas: opts.canvas,
|
|
1496
1492
|
antialias: rendering.antialias,
|
|
1497
1493
|
preserveDrawingBuffer: rendering.preserveDrawingBuffer
|
|
1498
|
-
});
|
|
1494
|
+
}));
|
|
1499
1495
|
this.webgl.info.autoReset = false;
|
|
1500
1496
|
this.engine.picker = (x, y) => this.pick(x, y);
|
|
1501
1497
|
this.basePixelRatio = rendering.pixelRatio;
|
|
@@ -2253,6 +2249,10 @@ async function createGame3D(opts) {
|
|
|
2253
2249
|
await report(.06, "scene");
|
|
2254
2250
|
let physics = null;
|
|
2255
2251
|
if (opts.physics === true || (opts.physics ?? "auto") === "auto" && hasBody(scene.root)) physics = await enablePhysics3D(engine);
|
|
2252
|
+
if (opts.physics !== false) engine.physicsProvider = async (root) => {
|
|
2253
|
+
if (engine.physics || !hasBody(root)) return;
|
|
2254
|
+
physics = await enablePhysics3D(engine);
|
|
2255
|
+
};
|
|
2256
2256
|
await report(.1, "physics");
|
|
2257
2257
|
const cleanups = [];
|
|
2258
2258
|
const keyboard = opts.keyboard ?? (typeof window !== "undefined" ? window : false);
|
|
@@ -2420,7 +2420,7 @@ async function createGame3D(opts) {
|
|
|
2420
2420
|
await report(1, "ready");
|
|
2421
2421
|
function disposeGame() {
|
|
2422
2422
|
teardown([
|
|
2423
|
-
|
|
2423
|
+
["physics", () => physics?.dispose()],
|
|
2424
2424
|
["app cleanups", () => {
|
|
2425
2425
|
for (const cleanup of cleanups) cleanup();
|
|
2426
2426
|
}],
|