incanto 0.62.0 → 0.63.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.
Files changed (46) hide show
  1. package/dist/2d.js +3 -3
  2. package/dist/3d.d.ts +22 -0
  3. package/dist/3d.js +5 -5
  4. package/dist/{create-game-BpunnGPX.js → create-game-lLeITaZ5.js} +6 -6
  5. package/dist/{create-game-Caut3bqN.js → create-game-viBqXUoZ.js} +6 -6
  6. package/dist/{duplicate-E4FUs5Bn.js → duplicate-BOOKmkQ7.js} +1 -1
  7. package/dist/{environment-presets-BAWeOeqf.js → environment-presets-QR7_75KJ.js} +3 -3
  8. package/dist/{gameplay-CaHqDiQD.js → gameplay-CuqoHHUB.js} +29 -3
  9. package/dist/gameplay.js +1 -1
  10. package/dist/index.js +5 -5
  11. package/dist/{loader-DEe272nY.js → loader-zDynoew_.js} +57 -2
  12. package/dist/net.js +1 -1
  13. package/dist/{physics-2d-BXmu2i7W.js → physics-2d-CllJXlic.js} +2 -2
  14. package/dist/{physics-3d-ClxP6Uv7.js → physics-3d-BL_pFJ19.js} +5 -3
  15. package/dist/react.js +1 -1
  16. package/dist/{register-CNh4FlbD.js → register-1cKM8DEj.js} +3 -3
  17. package/dist/{register-D3yx8D4r.js → register-Btm7_Emq.js} +1 -1
  18. package/dist/{replay-DlgHItNv.js → replay-Bhdntkvq.js} +2 -2
  19. package/dist/{split-screen-CBM9wcMX.js → split-screen-Dx0LvzqS.js} +2 -2
  20. package/dist/{src-CH00_JsR.js → src-BlV9Sv4m.js} +1 -1
  21. package/dist/{teardown-C7qP-dcC.js → teardown-BwhkcNt8.js} +1 -1
  22. package/dist/{test-BMkg8zMV.js → test-Ct1_zf5S.js} +50 -18
  23. package/dist/test.d.ts +4 -0
  24. package/dist/test.js +2 -2
  25. package/dist/vite.js +2 -2
  26. package/editor/assets/{agent8-m5mtAO_A.js → agent8-CLZXBRoM.js} +1 -1
  27. package/editor/assets/{debug-CPhzCT8f.js → debug-eaSKFAKW.js} +1 -1
  28. package/editor/assets/{index-D422P4kW.js → index-D66AuRwG.js} +91 -91
  29. package/editor/index.html +1 -1
  30. package/package.json +1 -1
  31. package/schemas/scene.schema.json +4 -0
  32. package/skills/README.md +4 -0
  33. package/skills/incanto-game-feel.md +3 -2
  34. package/skills/incanto-gameplay-behaviors.md +30 -5
  35. package/skills/incanto-node-reference.md +1 -0
  36. package/skills/incanto-physics-and-input.md +30 -0
  37. package/skills/incanto-scene-json-authoring.md +15 -1
  38. package/skills/incanto-your-first-game.md +237 -0
  39. package/templates-app/beacon-isle-3d/package.json +1 -1
  40. package/templates-app/platformer-2d/package.json +1 -1
  41. package/templates-app/star-survivor/package.json +1 -1
  42. package/templates-app/star-survivor/src/game.scene.json +4 -2
  43. package/templates-app/tps-3d/package.json +1 -1
  44. package/templates-app/tps-3d/src/game.scene.json +3 -2
  45. package/templates-app/tps-3d/verify.ts +38 -0
  46. package/templates-app/village-quest-3d/package.json +1 -1
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-BpunnGPX.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-CNh4FlbD.js";
4
- import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-BXmu2i7W.js";
2
+ import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-lLeITaZ5.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-1cKM8DEj.js";
4
+ import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-CllJXlic.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
@@ -399,6 +399,28 @@ declare class CharacterBody3D extends PhysicsBody3D {
399
399
  /** Max climbable slope angle. */
400
400
  slopeLimitDeg: number;
401
401
  /**
402
+ * How high a step this body walks UP without jumping (0 = none).
403
+ *
404
+ * Rapier's character controller does not autostep unless asked, and nothing
405
+ * asked — so every `CharacterBody3D` was stopped dead by any ledge at all.
406
+ * The player never showed it, because `CharacterController3D` rides a hover
407
+ * spring rather than the KCC; enemies are the ones that walk.
408
+ *
409
+ * Measured on the shipped `tps-3d` template, whose arena has a 0.6 m `Ramp`
410
+ * between the spawn and the player. Standing still for 45 seconds:
411
+ *
412
+ * ```
413
+ * hits=0 hp=100 closest an enemy ever got = 33.91m
414
+ * ```
415
+ *
416
+ * They chase at the right speed the whole time and pile up against the near
417
+ * face of a knee-high box, because a chaser walks a straight line and cannot
418
+ * climb. The template's own playtest had been printing
419
+ * `danger: the player took damage 0 times in 4 runs — nothing here can hurt
420
+ * you` all along, and no rung failed on it.
421
+ */
422
+ stepHeight: number;
423
+ /**
402
424
  * `snapToGround` on a character body is ambiguous, so it is refused.
403
425
  *
404
426
  * A boolean here used to mean the ground-stick, and as placement it means
package/dist/3d.js CHANGED
@@ -1,10 +1,10 @@
1
- import { c as parseEnvironment3D, l as sunDirectionFromElevationAzimuth, s as horizonColorFromSky, u as sunDirectionFromSky } from "./loader-DEe272nY.js";
1
+ import { c as parseEnvironment3D, l as sunDirectionFromElevationAzimuth, s as horizonColorFromSky, u as sunDirectionFromSky } from "./loader-zDynoew_.js";
2
2
  import { a as frameSignature, n as diffSignatures, o as frameStats, r as diffText, s as frameText, t as SIGNATURE_GRID } from "./frame-report-BSMny7oe.js";
3
- import { B as CharacterBody3D, F as Water3D, H as RigidBody3D, I as WATER_CUTOUT_MAX, L as WaterCutout3D, U as StaticBody3D, V as PhysicsBody3D, W as Node3D, q as WATER_MAX_RIPPLES, z as Area3D } from "./gameplay-CaHqDiQD.js";
4
- import { A as Terrain3D, B as keyboardIntensity, C as resolveFlowerDensity, D as BoneLookAt3D, E as Camera3D, F as InstancedMesh3D, G as acquireTexture, H as rigPose, I as MeshInstance3D, M as TERRAIN_THEMES, N as terrainThemeLayers, O as BoneAttachment3D, P as Joint3D, R as QUARTER_PITCH, S as Flowers3D, T as CharacterController3D, U as TextureCache3D, V as movementState, W as acquireOwnTexture, _ as LoftMesh3D, a as Tree3D, b as Foliage3D, c as buildRiverRings, d as riverCarveChannels, f as riverStepFor, g as ModelInstance3D, h as Particles3D, i as VoxelGrid3D, j as DEFAULT_TERRAIN_TEXTURE_BASE, k as Billboard3D, l as findRiverCoverageGaps, m as traceDownhillPath, n as registerNodes3D, o as Trail3D, p as smoothCourse, r as VOXEL_PALETTE, s as River3D, u as projectToRiver, v as DirectionalLight3D, w as FLOWER_VARIETIES, x as DENSITY_PRESETS, y as OmniLight3D, z as cameraRelative } from "./environment-presets-BAWeOeqf.js";
5
- import { a as Environment3D, i as syncTree, o as setEnvironment3D, r as Renderer3D, s as AssetStore3D, t as createGame3D } from "./create-game-Caut3bqN.js";
3
+ import { B as CharacterBody3D, F as Water3D, H as RigidBody3D, I as WATER_CUTOUT_MAX, L as WaterCutout3D, U as StaticBody3D, V as PhysicsBody3D, W as Node3D, q as WATER_MAX_RIPPLES, z as Area3D } from "./gameplay-CuqoHHUB.js";
4
+ import { A as Terrain3D, B as keyboardIntensity, C as resolveFlowerDensity, D as BoneLookAt3D, E as Camera3D, F as InstancedMesh3D, G as acquireTexture, H as rigPose, I as MeshInstance3D, M as TERRAIN_THEMES, N as terrainThemeLayers, O as BoneAttachment3D, P as Joint3D, R as QUARTER_PITCH, S as Flowers3D, T as CharacterController3D, U as TextureCache3D, V as movementState, W as acquireOwnTexture, _ as LoftMesh3D, a as Tree3D, b as Foliage3D, c as buildRiverRings, d as riverCarveChannels, f as riverStepFor, g as ModelInstance3D, h as Particles3D, i as VoxelGrid3D, j as DEFAULT_TERRAIN_TEXTURE_BASE, k as Billboard3D, l as findRiverCoverageGaps, m as traceDownhillPath, n as registerNodes3D, o as Trail3D, p as smoothCourse, r as VOXEL_PALETTE, s as River3D, u as projectToRiver, v as DirectionalLight3D, w as FLOWER_VARIETIES, x as DENSITY_PRESETS, y as OmniLight3D, z as cameraRelative } from "./environment-presets-QR7_75KJ.js";
5
+ import { a as Environment3D, i as syncTree, o as setEnvironment3D, r as Renderer3D, s as AssetStore3D, t as createGame3D } from "./create-game-viBqXUoZ.js";
6
6
  import { n as splatWeights, t as buildHeightmap } from "./heightmap-CRK0M4jT.js";
7
- import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-ClxP6Uv7.js";
7
+ import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-BL_pFJ19.js";
8
8
  //#region src/3d/model-verdict.ts
9
9
  /** Mixamo exports every bone as `mixamorigX`; the retargeter binds by that name. */
10
10
  const MIXAMO = /^mixamorig[:_]?/i;
@@ -1,14 +1,14 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { d as computeViewport, f as resolveViewport, k as diagnose, n as loadScene, z as registerBehavior } from "./loader-DEe272nY.js";
3
- import { _ as AudioPlayer, v as Engine } from "./register-D3yx8D4r.js";
2
+ import { d as computeViewport, f as resolveViewport, k as diagnose, n as loadScene, z as registerBehavior } from "./loader-zDynoew_.js";
3
+ import { _ as AudioPlayer, v as Engine } from "./register-Btm7_Emq.js";
4
4
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
5
5
  import { i as resolveRendering, n as attachTouchControls } from "./touch-DESwnpOc.js";
6
- import { a as openBundledEditor, c as claimCanvasGestures, i as devServerLibrary, l as audioErrors, n as pauseWhenHidden, r as crossFade, s as wireDevChannel, t as teardown } from "./teardown-C7qP-dcC.js";
6
+ import { a as openBundledEditor, c as claimCanvasGestures, i as devServerLibrary, l as audioErrors, n as pauseWhenHidden, r as crossFade, s as wireDevChannel, t as teardown } from "./teardown-BwhkcNt8.js";
7
7
  import { o as frameStats } from "./frame-report-BSMny7oe.js";
8
- import { n as registerGameplayBehaviors } from "./gameplay-CaHqDiQD.js";
9
- import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-CNh4FlbD.js";
8
+ import { n as registerGameplayBehaviors } from "./gameplay-CuqoHHUB.js";
9
+ import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-1cKM8DEj.js";
10
10
  import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
11
- import { n as enablePhysics2D } from "./physics-2d-BXmu2i7W.js";
11
+ import { n as enablePhysics2D } from "./physics-2d-CllJXlic.js";
12
12
  import { Box3, BufferAttribute, BufferGeometry, Color, LineBasicMaterial, LineSegments, LinearFilter, NearestFilter, OrthographicCamera, Raycaster, SRGBColorSpace, Scene, TextureLoader, Vector2, Vector3, WebGLRenderer } from "three";
13
13
  //#region src/2d/assets.ts
14
14
  /**
@@ -1,14 +1,14 @@
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-DEe272nY.js";
3
- import { C as qualityRendering, _ as AudioPlayer, v as Engine, x as qualityCaps } from "./register-D3yx8D4r.js";
2
+ import { c as parseEnvironment3D, k as diagnose, n as loadScene, s as horizonColorFromSky, u as sunDirectionFromSky, z as registerBehavior } from "./loader-zDynoew_.js";
3
+ import { C as qualityRendering, _ as AudioPlayer, v as Engine, x as qualityCaps } from "./register-Btm7_Emq.js";
4
4
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
5
5
  import { i as resolveRendering, n as attachTouchControls } from "./touch-DESwnpOc.js";
6
- import { a as openBundledEditor, c as claimCanvasGestures, i as devServerLibrary, l as audioErrors, n as pauseWhenHidden, o as poseFromRenderer, r as crossFade, s as wireDevChannel, t as teardown } from "./teardown-C7qP-dcC.js";
6
+ import { a as openBundledEditor, c as claimCanvasGestures, i as devServerLibrary, l as audioErrors, n as pauseWhenHidden, o as poseFromRenderer, r as crossFade, s as wireDevChannel, t as teardown } from "./teardown-BwhkcNt8.js";
7
7
  import { o as frameStats } from "./frame-report-BSMny7oe.js";
8
- import { K as createCausticsQuad, V as PhysicsBody3D, W as Node3D, n as registerGameplayBehaviors } from "./gameplay-CaHqDiQD.js";
8
+ import { K as createCausticsQuad, V as PhysicsBody3D, W as Node3D, n as registerGameplayBehaviors } from "./gameplay-CuqoHHUB.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-BAWeOeqf.js";
11
- import { n as enablePhysics3D } from "./physics-3d-ClxP6Uv7.js";
10
+ import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-QR7_75KJ.js";
11
+ import { n as enablePhysics3D } from "./physics-3d-BL_pFJ19.js";
12
12
  import { ACESFilmicToneMapping, AmbientLight, Box3, BufferAttribute, BufferGeometry, Color, DepthTexture, EquirectangularReflectionMapping, FloatType, Fog, HalfFloatType, LineBasicMaterial, LineSegments, Matrix4, Mesh, PCFShadowMap, PMREMGenerator, PerspectiveCamera, PlaneGeometry, Quaternion, Raycaster, Scene, ShaderMaterial, Vector2, Vector3, WebGLRenderTarget, WebGLRenderer } from "three";
13
13
  import { VRMLoaderPlugin, VRMUtils } from "@pixiv/three-vrm";
14
14
  import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
@@ -1,4 +1,4 @@
1
- import { a as serializeNode, t as buildNodeJson } from "./loader-DEe272nY.js";
1
+ import { a as serializeNode, t as buildNodeJson } from "./loader-zDynoew_.js";
2
2
  //#region src/core/scene/duplicate.ts
3
3
  function stripUids(json) {
4
4
  const { uid: _uid, ...rest } = json;
@@ -1,11 +1,11 @@
1
- import { k as diagnose } from "./loader-DEe272nY.js";
2
- import { L as translateOn, t as registerCoreNodes } from "./register-D3yx8D4r.js";
1
+ import { k as diagnose } from "./loader-zDynoew_.js";
2
+ import { L as translateOn, t as registerCoreNodes } from "./register-Btm7_Emq.js";
3
3
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
4
4
  import { t as Rng } from "./rng-DP-SR7eg.js";
5
5
  import { i as getNodeSchema, l as registerNode } from "./registry-CF70EArN.js";
6
6
  import { t as createNoise2D } from "./noise-CGUMx44x.js";
7
7
  import { i as ParticleSim, n as resolveFrames, o as PARTICLE_PRESET_NAMES, r as validateAnimationAliases, s as applyParticlePreset, t as resolveAnimation } from "./sprite-animation-CY-mrr1L.js";
8
- import { B as CharacterBody3D, F as Water3D, H as RigidBody3D, J as colliderFootDrop, L as WaterCutout3D, R as rejectScale, U as StaticBody3D, V as PhysicsBody3D, W as Node3D, w as tolerateUnknownAction, z as Area3D } from "./gameplay-CaHqDiQD.js";
8
+ import { B as CharacterBody3D, F as Water3D, H as RigidBody3D, J as colliderFootDrop, L as WaterCutout3D, R as rejectScale, U as StaticBody3D, V as PhysicsBody3D, W as Node3D, w as tolerateUnknownAction, z as Area3D } from "./gameplay-CuqoHHUB.js";
9
9
  import { t as checkSheetGrid } from "./sheet-grid-BT6N_Bjs.js";
10
10
  import { n as splatWeights, t as buildHeightmap } from "./heightmap-CRK0M4jT.js";
11
11
  import { AdditiveBlending, AnimationClip, AnimationMixer, Box3, BoxGeometry, BufferAttribute, BufferGeometry, CanvasTexture, CapsuleGeometry, ClampToEdgeWrapping, Color, ConeGeometry, CylinderGeometry, DataTexture, DirectionalLight, DoubleSide, DynamicDrawUsage, Euler, Group, IcosahedronGeometry, ImageBitmapLoader, InstancedBufferAttribute, InstancedMesh, LinearFilter, LinearMipmapLinearFilter, LoopOnce, LoopRepeat, Matrix4, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshPhysicalMaterial, MeshStandardMaterial, NearestFilter, NoBlending, NoColorSpace, NormalBlending, PerspectiveCamera, PlaneGeometry, PointLight, Points, PointsMaterial, Quaternion, QuaternionKeyframeTrack, RGBADepthPacking, RGBAFormat, RepeatWrapping, SRGBColorSpace, ShaderChunk, ShaderMaterial, SphereGeometry, Texture, TextureLoader, UniformsLib, UniformsUtils, Vector3, Vector4, VectorKeyframeTrack } from "three";
@@ -1,7 +1,7 @@
1
- import { O as Node, P as Behavior, _ as SaveSlots, k as diagnose, n as loadScene, w as effectiveOrder, z as registerBehavior } from "./loader-DEe272nY.js";
1
+ import { O as Node, P as Behavior, _ as SaveSlots, k as diagnose, n as loadScene, w as effectiveOrder, z as registerBehavior } from "./loader-zDynoew_.js";
2
2
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
3
3
  import { t as jsonClone } from "./json-CwwhxQgb.js";
4
- import { t as duplicateNode } from "./duplicate-E4FUs5Bn.js";
4
+ import { t as duplicateNode } from "./duplicate-BOOKmkQ7.js";
5
5
  import { Color, CubeCamera, DepthTexture, DoubleSide, Euler, FloatType, Frustum, HalfFloatType, LinearMipmapLinearFilter, MathUtils, Matrix4, Mesh, MeshDepthMaterial, Object3D, PerspectiveCamera, Plane, PlaneGeometry, Quaternion, ShaderMaterial, Sphere, Vector2, Vector3, Vector4, WebGLCubeRenderTarget, WebGLRenderTarget } from "three";
6
6
  //#region src/3d/frustum.ts
7
7
  const scratchFrustum = new Frustum();
@@ -2582,7 +2582,11 @@ var CharacterBody3D = class extends PhysicsBody3D {
2582
2582
  0
2583
2583
  ] },
2584
2584
  stickToGround: { default: true },
2585
- slopeLimitDeg: { default: 45 }
2585
+ slopeLimitDeg: { default: 45 },
2586
+ stepHeight: {
2587
+ default: .35,
2588
+ range: { min: 0 }
2589
+ }
2586
2590
  };
2587
2591
  /** m/s, y-up (up = +y). */
2588
2592
  velocity = [
@@ -2604,6 +2608,28 @@ var CharacterBody3D = class extends PhysicsBody3D {
2604
2608
  /** Max climbable slope angle. */
2605
2609
  slopeLimitDeg = 45;
2606
2610
  /**
2611
+ * How high a step this body walks UP without jumping (0 = none).
2612
+ *
2613
+ * Rapier's character controller does not autostep unless asked, and nothing
2614
+ * asked — so every `CharacterBody3D` was stopped dead by any ledge at all.
2615
+ * The player never showed it, because `CharacterController3D` rides a hover
2616
+ * spring rather than the KCC; enemies are the ones that walk.
2617
+ *
2618
+ * Measured on the shipped `tps-3d` template, whose arena has a 0.6 m `Ramp`
2619
+ * between the spawn and the player. Standing still for 45 seconds:
2620
+ *
2621
+ * ```
2622
+ * hits=0 hp=100 closest an enemy ever got = 33.91m
2623
+ * ```
2624
+ *
2625
+ * They chase at the right speed the whole time and pile up against the near
2626
+ * face of a knee-high box, because a chaser walks a straight line and cannot
2627
+ * climb. The template's own playtest had been printing
2628
+ * `danger: the player took damage 0 times in 4 runs — nothing here can hurt
2629
+ * you` all along, and no rung failed on it.
2630
+ */
2631
+ stepHeight = .35;
2632
+ /**
2607
2633
  * `snapToGround` on a character body is ambiguous, so it is refused.
2608
2634
  *
2609
2635
  * A boolean here used to mean the ground-stick, and as placement it means
package/dist/gameplay.js CHANGED
@@ -1,2 +1,2 @@
1
- import { A as Health, C as restartScene, D as DayNight, E as FloatAway, M as Chase, O as phaseOf, S as goToScene, T as FollowCamera, _ as Cooldown, a as Wander, b as Interactable, c as SavePoint, d as Patrol, f as PathFollow, g as CameraShake, h as Lifetime, i as WaveSpawner, j as Collector, k as DamageOnContact, l as Projectile, m as MoveTo, n as registerGameplayBehaviors, o as Spawner, p as Oscillate, r as ZombieAI, s as ScoreKeeper, t as GAMEPLAY_BEHAVIORS, u as Pickup, v as hitStop, x as GameFlow, y as screenFlash } from "./gameplay-CaHqDiQD.js";
1
+ import { A as Health, C as restartScene, D as DayNight, E as FloatAway, M as Chase, O as phaseOf, S as goToScene, T as FollowCamera, _ as Cooldown, a as Wander, b as Interactable, c as SavePoint, d as Patrol, f as PathFollow, g as CameraShake, h as Lifetime, i as WaveSpawner, j as Collector, k as DamageOnContact, l as Projectile, m as MoveTo, n as registerGameplayBehaviors, o as Spawner, p as Oscillate, r as ZombieAI, s as ScoreKeeper, t as GAMEPLAY_BEHAVIORS, u as Pickup, v as hitStop, x as GameFlow, y as screenFlash } from "./gameplay-CuqoHHUB.js";
2
2
  export { CameraShake, Chase, Collector, Cooldown, DamageOnContact, DayNight, FloatAway, FollowCamera, GAMEPLAY_BEHAVIORS, GameFlow, Health, Interactable, Lifetime, MoveTo, Oscillate, PathFollow, Patrol, Pickup, Projectile, SavePoint, ScoreKeeper, Spawner, Wander, WaveSpawner, ZombieAI, goToScene, hitStop, phaseOf, registerGameplayBehaviors, restartScene, screenFlash };
package/dist/index.js CHANGED
@@ -1,13 +1,13 @@
1
- import { A as describeRefProblem, B as registeredBehaviors, C as ORDER_GROUP_BASE, E as InputMap, F as behaviorSchema, I as behaviorSignals, L as clearBehaviors, M as resolveRefInJson, N as parseNodePath, O as Node, P as Behavior, R as getBehavior, S as createSaveStore, T as resolveOrderGroups, V as Signal, _ as SaveSlots, a as serializeNode, b as restoreBehaviors, d as computeViewport, f as resolveViewport, g as resolveConstants, h as isConstRef, i as Scene, j as nodeRefWarnings, m as CONST_REF_KEY, n as loadScene, o as SCENE_FORMAT, p as SceneTree, v as behaviorsWithoutSave, w as effectiveOrder, x as savesWithoutUid, y as captureBehaviors, z as registerBehavior } from "./loader-DEe272nY.js";
2
- import { A as UiBanner, B as isAudioContextAvailable, D as EffectLog, E as LogManager, F as T_PREFIX, G as SFX_PRESET_NAMES, H as spatialGain, I as suggestLocale, J as MusicManager, K as sfxDuration, M as UiText, N as BASE_LOCALE, O as HudLayer, P as Localization, Q as AudioBuses, R as translationKey, S as qualityEnvironment, T as suggestQuality, U as spatialPan, V as ROLLOFF_MODELS, W as SFX_PRESETS, X as crossfadeGains, Y as WebAudioMusicBackend, Z as fadeGain, _ as AudioPlayer, a as UiMuteToggle, b as Settings, c as UiRenderScaleSelect, d as UiToggle, f as UiVolumeSlider, g as UiDialogue, h as UiButton, i as UiLanguageSelect, j as UiBar, l as UiSelect, m as Respawn, n as UiFrameCapSelect, o as UiPanel, p as Timer, q as synthSfx, r as UiImage, s as UiQualitySelect, t as registerCoreNodes, u as UiSlider, v as Engine, w as readDeviceHints, z as SfxEngine } from "./register-D3yx8D4r.js";
1
+ import { A as describeRefProblem, B as registeredBehaviors, C as ORDER_GROUP_BASE, E as InputMap, F as behaviorSchema, I as behaviorSignals, L as clearBehaviors, M as resolveRefInJson, N as parseNodePath, O as Node, P as Behavior, R as getBehavior, S as createSaveStore, T as resolveOrderGroups, V as Signal, _ as SaveSlots, a as serializeNode, b as restoreBehaviors, d as computeViewport, f as resolveViewport, g as resolveConstants, h as isConstRef, i as Scene, j as nodeRefWarnings, m as CONST_REF_KEY, n as loadScene, o as SCENE_FORMAT, p as SceneTree, v as behaviorsWithoutSave, w as effectiveOrder, x as savesWithoutUid, y as captureBehaviors, z as registerBehavior } from "./loader-zDynoew_.js";
2
+ import { A as UiBanner, B as isAudioContextAvailable, D as EffectLog, E as LogManager, F as T_PREFIX, G as SFX_PRESET_NAMES, H as spatialGain, I as suggestLocale, J as MusicManager, K as sfxDuration, M as UiText, N as BASE_LOCALE, O as HudLayer, P as Localization, Q as AudioBuses, R as translationKey, S as qualityEnvironment, T as suggestQuality, U as spatialPan, V as ROLLOFF_MODELS, W as SFX_PRESETS, X as crossfadeGains, Y as WebAudioMusicBackend, Z as fadeGain, _ as AudioPlayer, a as UiMuteToggle, b as Settings, c as UiRenderScaleSelect, d as UiToggle, f as UiVolumeSlider, g as UiDialogue, h as UiButton, i as UiLanguageSelect, j as UiBar, l as UiSelect, m as Respawn, n as UiFrameCapSelect, o as UiPanel, p as Timer, q as synthSfx, r as UiImage, s as UiQualitySelect, t as registerCoreNodes, u as UiSlider, v as Engine, w as readDeviceHints, z as SfxEngine } from "./register-Btm7_Emq.js";
3
3
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
4
4
  import { t as Rng } from "./rng-DP-SR7eg.js";
5
5
  import { n as jsonEquals, r as jsonKind, t as jsonClone } from "./json-CwwhxQgb.js";
6
6
  import { a as getNodeSignals, c as mergeStaticSignals, i as getNodeSchema, l as registerNode, n as clearRegistry, o as getNodeType, r as createNode, u as registeredTypes } from "./registry-CF70EArN.js";
7
- import { n as startRecording, r as auditScene, t as replay } from "./replay-DlgHItNv.js";
7
+ import { n as startRecording, r as auditScene, t as replay } from "./replay-Bhdntkvq.js";
8
8
  import { a as logReport, i as resolveRendering, n as attachTouchControls, o as logText, r as joystickVector, s as parseDrive, t as TouchControls } from "./touch-DESwnpOc.js";
9
9
  import { t as createNoise2D } from "./noise-CGUMx44x.js";
10
10
  import { a as PARTICLE_PRESETS, i as ParticleSim, n as resolveFrames, o as PARTICLE_PRESET_NAMES, s as applyParticlePreset, t as resolveAnimation } from "./sprite-animation-CY-mrr1L.js";
11
- import { a as preloadUrls, i as preloadSceneAssets, n as newUid, o as findPath, r as assetUrls, s as gridFromRows, t as VERSION } from "./src-CH00_JsR.js";
12
- import { t as duplicateNode } from "./duplicate-E4FUs5Bn.js";
11
+ import { a as preloadUrls, i as preloadSceneAssets, n as newUid, o as findPath, r as assetUrls, s as gridFromRows, t as VERSION } from "./src-BlV9Sv4m.js";
12
+ import { t as duplicateNode } from "./duplicate-BOOKmkQ7.js";
13
13
  export { AudioBuses, AudioPlayer, BASE_LOCALE, Behavior, CONST_REF_KEY, EffectLog, Engine, HudLayer, IncantoError, InputMap, Localization, LogManager, MusicManager, Node, ORDER_GROUP_BASE, PARTICLE_PRESETS, PARTICLE_PRESET_NAMES, ParticleSim, ROLLOFF_MODELS, Respawn, Rng, SCENE_FORMAT, SFX_PRESETS, SFX_PRESET_NAMES, SaveSlots, Scene, SceneTree, Settings, SfxEngine, Signal, T_PREFIX, Timer, TouchControls, UiBanner, UiBar, UiButton, UiDialogue, UiFrameCapSelect, UiImage, UiLanguageSelect, UiMuteToggle, UiPanel, UiQualitySelect, UiRenderScaleSelect, UiSelect, UiSlider, UiText, UiToggle, UiVolumeSlider, VERSION, WebAudioMusicBackend, applyParticlePreset, assetUrls, attachTouchControls, auditScene, behaviorSchema, behaviorSignals, behaviorsWithoutSave, captureBehaviors, clearBehaviors, clearRegistry, computeViewport, createNode, createNoise2D, createSaveStore, crossfadeGains, describeRefProblem, duplicateNode, effectiveOrder, fadeGain, findPath, getBehavior, getNodeSchema, getNodeSignals, getNodeType, gridFromRows, isAudioContextAvailable, isConstRef, joystickVector, jsonClone, jsonEquals, jsonKind, loadScene, logReport, logText, mergeStaticSignals, newUid, nodeRefWarnings, parseDrive, parseNodePath, preloadSceneAssets, preloadUrls, qualityEnvironment, readDeviceHints, registerBehavior, registerCoreNodes, registerNode, registeredBehaviors, registeredTypes, replay, resolveAnimation, resolveConstants, resolveFrames, resolveOrderGroups, resolveRefInJson, resolveRendering, resolveViewport, restoreBehaviors, savesWithoutUid, serializeNode, sfxDuration, spatialGain, spatialPan, startRecording, suggestLocale, suggestQuality, synthSfx, translationKey };
@@ -2815,6 +2815,53 @@ function validateStrings(strings) {
2815
2815
  }
2816
2816
  }
2817
2817
  //#endregion
2818
+ //#region src/core/scene/wire-arity.ts
2819
+ /**
2820
+ * A wire that hands a handler fewer arguments than it needs.
2821
+ *
2822
+ * The engine hard-validates node types, prop kinds, every prop enum, node
2823
+ * paths, handler existence and signal declaration — and never that the signal's
2824
+ * ARGUMENTS fit the handler it is wired to. `died` carries none and
2825
+ * `ScoreKeeper.addScore(n)` wants one, so the most natural way to score a kill:
2826
+ *
2827
+ * ```json
2828
+ * { "signal": "died", "from": "Enemy", "to": "Keeper", "handler": "addScore" }
2829
+ * ```
2830
+ *
2831
+ * sets the score to `NaN` on the first kill and the win condition becomes
2832
+ * permanently unreachable. Measured:
2833
+ *
2834
+ * ```
2835
+ * score = NaN | Number.isNaN: true
2836
+ * HUD text = "Kills 0"
2837
+ * won emitted = false
2838
+ * engine errors = 0
2839
+ * incanto-check → 1/1 scene(s) valid
2840
+ * ```
2841
+ *
2842
+ * Two agents building different games from the published package hit it
2843
+ * independently, which is what makes it worth a rule rather than a footnote.
2844
+ *
2845
+ * **Why this is not a load error.** Nothing declares how many arguments a signal
2846
+ * carries — `static signals` is a list of names — so at load the pair cannot be
2847
+ * compared. At the moment the wire FIRES both halves are known exactly, and
2848
+ * that is where this lives.
2849
+ *
2850
+ * **Why `fn.length` is the right measure.** It counts leading parameters
2851
+ * without defaults, so it makes precisely the distinction the engine needs:
2852
+ * `addScore(n)` is 1 and gets reported; `GameFlow.win(text = 'YOU WIN')` is 0
2853
+ * and is silent, because that wire genuinely works — the banner defaults. The
2854
+ * same arg-less signal into a same-arity method is right in one case and wrong
2855
+ * in the other, and only the defaults tell them apart.
2856
+ */
2857
+ function reportShortWire(from, conn, fn, args) {
2858
+ diagnose(from.tree?.engine ?? null, "error", `[incanto] '${conn.signal}' from '${conn.from}' carries ${args.length} argument(s) and '${conn.to}.${conn.handler}' needs ${fn.length}. The missing one(s) arrive as undefined — a number handler gets NaN and never recovers. Give the handler a default, or wire a signal that carries what it needs.`);
2859
+ }
2860
+ /** Does this wire under-feed its handler? */
2861
+ function isShortWire(fn, args) {
2862
+ return args.length < fn.length;
2863
+ }
2864
+ //#endregion
2818
2865
  //#region src/core/scene/loader.ts
2819
2866
  var loader_exports = /* @__PURE__ */ __exportAll({
2820
2867
  buildNodeJson: () => buildNodeJson,
@@ -3023,17 +3070,25 @@ function wireConnections(root, connections, declareSignals = false) {
3023
3070
  const behaviorFn = toNode.behavior ? toNode.behavior[conn.handler] : void 0;
3024
3071
  if (typeof nodeFn !== "function" && typeof behaviorFn !== "function" && !(toNode.behavior instanceof StubBehavior)) throw new IncantoError("UNKNOWN_HANDLER", `Connection '${conn.signal}' → '${conn.to}' names handler '${conn.handler}', but '${toNode.name}' has no such method` + (toNode.behavior ? ` (nor does its behavior '${toNode.script?.name}')` : "") + `.`);
3025
3072
  if (ambiguousHandler(toNode, conn.handler)) throw ambiguousHandlerError(toNode, conn.handler, toNode.script?.name, conn.to);
3073
+ let saidShort = false;
3074
+ const feed = (fn, self, args) => {
3075
+ if (!saidShort && isShortWire(fn, args)) {
3076
+ saidShort = true;
3077
+ reportShortWire(fromNode, conn, fn, args);
3078
+ }
3079
+ fn.apply(self, args);
3080
+ };
3026
3081
  const listener = (...args) => {
3027
3082
  if (conn.filter && !matchesFilter(args[0], conn.filter)) return;
3028
3083
  if (conn.once) fromNode.off(conn.signal, listener);
3029
3084
  try {
3030
3085
  const fn = toNode[conn.handler];
3031
3086
  if (typeof fn === "function") {
3032
- fn.apply(toNode, args);
3087
+ feed(fn, toNode, args);
3033
3088
  return;
3034
3089
  }
3035
3090
  const bfn = toNode.behavior ? toNode.behavior[conn.handler] : void 0;
3036
- if (typeof bfn === "function") bfn.apply(toNode.behavior, args);
3091
+ if (typeof bfn === "function") feed(bfn, toNode.behavior, args);
3037
3092
  } catch (error) {
3038
3093
  quarantineWire(fromNode, toNode, conn, listener, error);
3039
3094
  }
package/dist/net.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import { n as createAgent8Server } from "./agent8-CvsfVskX.js";
2
- import { a as NetworkManager, d as createLocalGameServer, f as LoopbackHub, l as LocalGameServer, n as registerNodesNet, o as applySyncPatch, p as LoopbackTransport, r as NetworkSpawner, t as createSplitScreen, u as LocalGameServerTransport } from "./split-screen-CBM9wcMX.js";
2
+ import { a as NetworkManager, d as createLocalGameServer, f as LoopbackHub, l as LocalGameServer, n as registerNodesNet, o as applySyncPatch, p as LoopbackTransport, r as NetworkSpawner, t as createSplitScreen, u as LocalGameServerTransport } from "./split-screen-Dx0LvzqS.js";
3
3
  export { LocalGameServer, LocalGameServerTransport, LoopbackHub, LoopbackTransport, NetworkManager, NetworkSpawner, applySyncPatch, createAgent8Server, createLocalGameServer, createSplitScreen, registerNodesNet };
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { k as diagnose } from "./loader-DEe272nY.js";
2
+ import { k as diagnose } from "./loader-zDynoew_.js";
3
3
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
4
- import { _ as RigidBody2D, b as validateCollider2D, g as PhysicsBody2D, h as CharacterBody2D, m as Area2D, p as Joint2D, y as Node2D } from "./register-CNh4FlbD.js";
4
+ import { _ as RigidBody2D, b as validateCollider2D, g as PhysicsBody2D, h as CharacterBody2D, m as Area2D, p as Joint2D, y as Node2D } from "./register-1cKM8DEj.js";
5
5
  import { n as registerDebugSource } from "./debug-draw-BM3DsvtT.js";
6
6
  import { t as withoutRapierInitNoise } from "./quiet-rapier-BAJ4K94N.js";
7
7
  //#region src/2d/physics/physics-2d.ts
@@ -1,10 +1,10 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { k as diagnose } from "./loader-DEe272nY.js";
2
+ import { k as diagnose } from "./loader-zDynoew_.js";
3
3
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
4
- import { B as CharacterBody3D, G as validateCollider3D, H as RigidBody3D, V as PhysicsBody3D, W as Node3D, z as Area3D } from "./gameplay-CaHqDiQD.js";
4
+ import { B as CharacterBody3D, G as validateCollider3D, H as RigidBody3D, V as PhysicsBody3D, W as Node3D, z as Area3D } from "./gameplay-CuqoHHUB.js";
5
5
  import { n as registerDebugSource } from "./debug-draw-BM3DsvtT.js";
6
6
  import { t as withoutRapierInitNoise } from "./quiet-rapier-BAJ4K94N.js";
7
- import { A as Terrain3D, F as InstancedMesh3D, L as buildMeshGeometry, P as Joint3D } from "./environment-presets-BAWeOeqf.js";
7
+ import { A as Terrain3D, F as InstancedMesh3D, L as buildMeshGeometry, P as Joint3D } from "./environment-presets-QR7_75KJ.js";
8
8
  import { Euler, Matrix4, Quaternion, Vector3 } from "three";
9
9
  //#region src/3d/physics/collider-lines.ts
10
10
  /**
@@ -384,6 +384,8 @@ var Physics3D = class {
384
384
  if (node.stickToGround && vy <= 0) this.kcc.enableSnapToGround(.1);
385
385
  else this.kcc.disableSnapToGround();
386
386
  this.kcc.setMaxSlopeClimbAngle(node.slopeLimitDeg * DEG);
387
+ if (node.stepHeight > 0) this.kcc.enableAutostep(node.stepHeight, node.stepHeight / 2, false);
388
+ else this.kcc.disableAutostep();
387
389
  let carryX = 0;
388
390
  let carryY = 0;
389
391
  let carryZ = 0;
package/dist/react.js CHANGED
@@ -156,7 +156,7 @@ function IncantoCanvas(props) {
156
156
  pointer: latest.pointer,
157
157
  ...keyboard !== void 0 ? { keyboard } : {}
158
158
  };
159
- const next = await (_gameFactory ?? (mode === "3d" ? async (o) => (await import("./create-game-Caut3bqN.js").then((n) => n.n)).createGame3D(o) : async (o) => (await import("./create-game-BpunnGPX.js").then((n) => n.n)).createGame2D(o)))(opts);
159
+ const next = await (_gameFactory ?? (mode === "3d" ? async (o) => (await import("./create-game-viBqXUoZ.js").then((n) => n.n)).createGame3D(o) : async (o) => (await import("./create-game-lLeITaZ5.js").then((n) => n.n)).createGame2D(o)))(opts);
160
160
  if (disposed) {
161
161
  next.dispose();
162
162
  return;
@@ -1,10 +1,10 @@
1
- import { O as Node, k as diagnose, w as effectiveOrder } from "./loader-DEe272nY.js";
2
- import { L as translateOn, t as registerCoreNodes } from "./register-D3yx8D4r.js";
1
+ import { O as Node, k as diagnose, w as effectiveOrder } from "./loader-zDynoew_.js";
2
+ import { L as translateOn, t as registerCoreNodes } from "./register-Btm7_Emq.js";
3
3
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
4
4
  import { t as Rng } from "./rng-DP-SR7eg.js";
5
5
  import { i as getNodeSchema, l as registerNode } from "./registry-CF70EArN.js";
6
6
  import { i as ParticleSim, n as resolveFrames, o as PARTICLE_PRESET_NAMES, r as validateAnimationAliases, s as applyParticlePreset, t as resolveAnimation } from "./sprite-animation-CY-mrr1L.js";
7
- import { N as localFromWorld, P as worldPosition } from "./gameplay-CaHqDiQD.js";
7
+ import { N as localFromWorld, P as worldPosition } from "./gameplay-CuqoHHUB.js";
8
8
  import { t as checkSheetGrid } from "./sheet-grid-BT6N_Bjs.js";
9
9
  import { AdditiveBlending, BufferAttribute, BufferGeometry, CanvasTexture, Color, DynamicDrawUsage, Group, InstancedMesh, MathUtils, Matrix4, Mesh, MeshBasicMaterial, NearestFilter, NormalBlending, Object3D, PlaneGeometry, SRGBColorSpace } from "three";
10
10
  //#region src/2d/physics/collider-validate.ts
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { C as ORDER_GROUP_BASE, E as InputMap, O as Node, S as createSaveStore, T as resolveOrderGroups, V as Signal, b as restoreBehaviors, k as diagnose, y as captureBehaviors } from "./loader-DEe272nY.js";
2
+ import { C as ORDER_GROUP_BASE, E as InputMap, O as Node, S as createSaveStore, T as resolveOrderGroups, V as Signal, b as restoreBehaviors, k as diagnose, y as captureBehaviors } from "./loader-zDynoew_.js";
3
3
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
4
4
  import { t as Rng } from "./rng-DP-SR7eg.js";
5
5
  import { l as registerNode } from "./registry-CF70EArN.js";
@@ -1,5 +1,5 @@
1
- import { D as handlerShadowWarnings, j as nodeRefWarnings } from "./loader-DEe272nY.js";
2
- import { R as translationKey, k as HudWidgetBase } from "./register-D3yx8D4r.js";
1
+ import { D as handlerShadowWarnings, j as nodeRefWarnings } from "./loader-zDynoew_.js";
2
+ import { R as translationKey, k as HudWidgetBase } from "./register-Btm7_Emq.js";
3
3
  import { o as getNodeType } from "./registry-CF70EArN.js";
4
4
  //#region src/core/audit.ts
5
5
  const ANIMATED_TYPES = new Set([
@@ -1,5 +1,5 @@
1
- import { O as Node, V as Signal, k as diagnose, n as loadScene, t as buildNodeJson } from "./loader-DEe272nY.js";
2
- import { t as registerCoreNodes, v as Engine } from "./register-D3yx8D4r.js";
1
+ import { O as Node, V as Signal, k as diagnose, n as loadScene, t as buildNodeJson } from "./loader-zDynoew_.js";
2
+ import { t as registerCoreNodes, v as Engine } from "./register-Btm7_Emq.js";
3
3
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
4
4
  import { n as jsonEquals, t as jsonClone } from "./json-CwwhxQgb.js";
5
5
  import { l as registerNode } from "./registry-CF70EArN.js";
@@ -214,6 +214,6 @@ function newUid() {
214
214
  //#endregion
215
215
  //#region src/index.ts
216
216
  /** Engine version. Kept in sync with package.json by the release pipeline. */
217
- const VERSION = "0.62.0";
217
+ const VERSION = "0.63.0";
218
218
  //#endregion
219
219
  export { preloadUrls as a, preloadSceneAssets as i, newUid as n, findPath as o, assetUrls as r, gridFromRows as s, VERSION as t };
@@ -1,4 +1,4 @@
1
- import { _ as AudioPlayer } from "./register-D3yx8D4r.js";
1
+ import { _ as AudioPlayer } from "./register-Btm7_Emq.js";
2
2
  import { a as logReport, s as parseDrive } from "./touch-DESwnpOc.js";
3
3
  import { a as frameSignature, i as frameImage, o as frameStats } from "./frame-report-BSMny7oe.js";
4
4
  //#region src/core/audio-errors.ts
@@ -1,13 +1,13 @@
1
- import { f as resolveViewport, n as loadScene, z as registerBehavior } from "./loader-DEe272nY.js";
2
- import { v as Engine } from "./register-D3yx8D4r.js";
1
+ import { f as resolveViewport, n as loadScene, z as registerBehavior } from "./loader-zDynoew_.js";
2
+ import { v as Engine } from "./register-Btm7_Emq.js";
3
3
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
4
4
  import { n as jsonEquals, t as jsonClone } from "./json-CwwhxQgb.js";
5
5
  import { i as getNodeSchema, s as mergeStaticProps } from "./registry-CF70EArN.js";
6
- import { n as startRecording } from "./replay-DlgHItNv.js";
7
- import { n as registerGameplayBehaviors } from "./gameplay-CaHqDiQD.js";
8
- import { t as registerNodes2D } from "./register-CNh4FlbD.js";
9
- import { n as registerNodes3D, t as resolveEnvironmentHdri } from "./environment-presets-BAWeOeqf.js";
10
- import { a as NetworkManager, c as readSyncKey, i as sanitizeName, n as registerNodesNet, r as NetworkSpawner, s as findOwnerNode, t as createSplitScreen } from "./split-screen-CBM9wcMX.js";
6
+ import { n as startRecording } from "./replay-Bhdntkvq.js";
7
+ import { n as registerGameplayBehaviors } from "./gameplay-CuqoHHUB.js";
8
+ import { t as registerNodes2D } from "./register-1cKM8DEj.js";
9
+ import { n as registerNodes3D, t as resolveEnvironmentHdri } from "./environment-presets-QR7_75KJ.js";
10
+ import { a as NetworkManager, c as readSyncKey, i as sanitizeName, n as registerNodesNet, r as NetworkSpawner, s as findOwnerNode, t as createSplitScreen } from "./split-screen-Dx0LvzqS.js";
11
11
  import { Box3, Euler, Matrix4, PerspectiveCamera, Quaternion, Vector3 } from "three";
12
12
  //#region src/test/framing.ts
13
13
  /**
@@ -1360,12 +1360,30 @@ function turnaround(probe, move, top) {
1360
1360
  probe.engine.input.setActionVector(move, 0, 0);
1361
1361
  return null;
1362
1362
  }
1363
- function jumpShape(probe, jump) {
1363
+ /**
1364
+ * How high one jump goes — TAPPED by default, HELD when asked.
1365
+ *
1366
+ * This pressed for exactly one frame and released, which is a tap. With
1367
+ * `jumpCutMultiplier` — the variable-height jump the 3D character skill
1368
+ * recommends at `0.45` — a tap is a fraction of the real jump, and this number
1369
+ * is what the skill tells you to size your level against. Measured on one
1370
+ * scene, changing only that prop:
1371
+ *
1372
+ * ```
1373
+ * jumpCutMultiplier 1 apex 1.831 u time to apex 433 ms airtime 717 ms
1374
+ * jumpCutMultiplier 0.45 apex 0.478 u time to apex 200 ms airtime 367 ms
1375
+ * ```
1376
+ *
1377
+ * Under-reporting the jump by ~4x is how a level ends up with gaps the player
1378
+ * clears effortlessly, or ledges they cannot understand missing. Both are
1379
+ * reported now, and the text names which is which.
1380
+ */
1381
+ function jumpShape(probe, jump, hold = false) {
1364
1382
  settle$1(probe);
1365
1383
  const floor = probe.pos()[1];
1366
1384
  probe.engine.input.pressAction(jump);
1367
1385
  probe.step();
1368
- probe.engine.input.releaseAction(jump);
1386
+ if (!hold) probe.engine.input.releaseAction(jump);
1369
1387
  let apex = 0;
1370
1388
  let toApex = 0;
1371
1389
  let airtime = null;
@@ -1381,6 +1399,7 @@ function jumpShape(probe, jump) {
1381
1399
  break;
1382
1400
  }
1383
1401
  }
1402
+ if (hold) probe.engine.input.releaseAction(jump);
1384
1403
  const noise = probe.up > 0 ? .02 : 2;
1385
1404
  if (apex <= noise) return {
1386
1405
  apex: null,
@@ -1502,6 +1521,8 @@ async function feelReport(json, opts = {}) {
1502
1521
  timeToStopMs: null,
1503
1522
  turnaroundMs: null,
1504
1523
  jumpApex: null,
1524
+ heldJumpApex: null,
1525
+ heldAirtimeMs: null,
1505
1526
  timeToApexMs: null,
1506
1527
  airtimeMs: null,
1507
1528
  coyoteMs: null,
@@ -1538,11 +1559,13 @@ async function feelReport(json, opts = {}) {
1538
1559
  c.session.dispose();
1539
1560
  }
1540
1561
  }
1541
- let shape = {
1562
+ const NO_SHAPE = {
1542
1563
  apex: null,
1543
1564
  toApexMs: null,
1544
1565
  airtimeMs: null
1545
1566
  };
1567
+ let shape = NO_SHAPE;
1568
+ let held = NO_SHAPE;
1546
1569
  let coyote = null;
1547
1570
  let buffer = null;
1548
1571
  if (jump) {
@@ -1551,6 +1574,11 @@ async function feelReport(json, opts = {}) {
1551
1574
  shape = jumpShape(d, jump);
1552
1575
  d.session.dispose();
1553
1576
  }
1577
+ const h = await fresh();
1578
+ if (h) {
1579
+ held = jumpShape(h, jump, true);
1580
+ h.session.dispose();
1581
+ }
1554
1582
  coyote = await measureCoyote(json, opts, jump);
1555
1583
  buffer = await measureBuffer(json, opts, jump);
1556
1584
  }
@@ -1563,6 +1591,8 @@ async function feelReport(json, opts = {}) {
1563
1591
  timeToStopMs: toStop,
1564
1592
  turnaroundMs: turn,
1565
1593
  jumpApex: shape.apex,
1594
+ heldJumpApex: held.apex,
1595
+ heldAirtimeMs: held.airtimeMs,
1566
1596
  timeToApexMs: shape.toApexMs,
1567
1597
  airtimeMs: shape.airtimeMs,
1568
1598
  coyoteMs: coyote,
@@ -1584,9 +1614,11 @@ function feelText(report) {
1584
1614
  lines.push(` input → motion ${report.inputToMotionFrames === null ? "—" : `${report.inputToMotionFrames} frame(s)`}`);
1585
1615
  if (report.jumpAction) {
1586
1616
  lines.push("");
1587
- lines.push(` jump apex ${report.jumpApex === null ? "— (nothing left the ground)" : `${report.jumpApex} u`}`);
1617
+ lines.push(` jump apex ${report.jumpApex === null ? "— (nothing left the ground)" : `${report.jumpApex} u (tapped)`}`);
1618
+ const cut = report.heldJumpApex !== null && report.jumpApex !== null && Math.abs(report.heldJumpApex - report.jumpApex) > .02;
1619
+ if (cut) lines.push(` held apex ${report.heldJumpApex} u ← size your level against THIS`);
1588
1620
  lines.push(` time to apex ${ms(report.timeToApexMs)}`);
1589
- lines.push(` airtime ${ms(report.airtimeMs)}`);
1621
+ lines.push(` airtime ${ms(report.airtimeMs)}${cut && report.heldAirtimeMs !== null ? ` (${ms(report.heldAirtimeMs)} held)` : ""}`);
1590
1622
  lines.push(` coyote window ${report.coyoteMs === null ? "always (no window)" : ms(report.coyoteMs)}`);
1591
1623
  lines.push(` jump buffer ${report.jumpBufferMs === null ? "always (no window)" : ms(report.jumpBufferMs)}`);
1592
1624
  if (report.coyoteMs === 0) {
@@ -1677,8 +1709,8 @@ async function playMultiplayer(opts) {
1677
1709
  */
1678
1710
  async function joinLate(server, first, opts) {
1679
1711
  try {
1680
- const { Engine } = await import("./register-D3yx8D4r.js").then((n) => n.y);
1681
- const { loadScene } = await import("./loader-DEe272nY.js").then((n) => n.r);
1712
+ const { Engine } = await import("./register-Btm7_Emq.js").then((n) => n.y);
1713
+ const { loadScene } = await import("./loader-zDynoew_.js").then((n) => n.r);
1682
1714
  const { jsonClone } = await import("./json-CwwhxQgb.js").then((n) => n.i);
1683
1715
  const engine = new Engine(opts.seed !== void 0 ? { seed: opts.seed + 999 } : {});
1684
1716
  engine.setScene(loadScene(jsonClone(opts.scene), opts.load));
@@ -2040,10 +2072,10 @@ async function runScript(json, opts) {
2040
2072
  if (opts.locale) engine.locale.locale = opts.locale;
2041
2073
  const physics = opts.physics ?? "auto";
2042
2074
  if (physics === "2d" || physics === "auto" && scene.dimension === "2d") {
2043
- const { enablePhysics2D } = await import("./physics-2d-BXmu2i7W.js").then((n) => n.r);
2075
+ const { enablePhysics2D } = await import("./physics-2d-CllJXlic.js").then((n) => n.r);
2044
2076
  await enablePhysics2D(engine);
2045
2077
  } else if (physics === "3d" || physics === "auto" && scene.dimension === "3d") {
2046
- const { enablePhysics3D } = await import("./physics-3d-ClxP6Uv7.js").then((n) => n.r);
2078
+ const { enablePhysics3D } = await import("./physics-3d-BL_pFJ19.js").then((n) => n.r);
2047
2079
  await enablePhysics3D(engine);
2048
2080
  }
2049
2081
  const failures = [];
@@ -2156,10 +2188,10 @@ async function createPlaySession(json, opts = {}) {
2156
2188
  engine.setScene(scene);
2157
2189
  const physics = opts.physics ?? "auto";
2158
2190
  if (physics === "2d" || physics === "auto" && scene.dimension === "2d") {
2159
- const { enablePhysics2D } = await import("./physics-2d-BXmu2i7W.js").then((n) => n.r);
2191
+ const { enablePhysics2D } = await import("./physics-2d-CllJXlic.js").then((n) => n.r);
2160
2192
  await enablePhysics2D(engine);
2161
2193
  } else if (physics === "3d" || physics === "auto" && scene.dimension === "3d") {
2162
- const { enablePhysics3D } = await import("./physics-3d-ClxP6Uv7.js").then((n) => n.r);
2194
+ const { enablePhysics3D } = await import("./physics-3d-BL_pFJ19.js").then((n) => n.r);
2163
2195
  await enablePhysics3D(engine);
2164
2196
  }
2165
2197
  const stepMs = 1e3 / (opts.fixedHz ?? 60);
package/dist/test.d.ts CHANGED
@@ -202,6 +202,10 @@ interface FeelReport {
202
202
  turnaroundMs: number | null;
203
203
  /** Height gained above the standing position. */
204
204
  jumpApex: number | null;
205
+ /** The apex with the button HELD — see `jumpShape`. Null when it matches. */
206
+ heldJumpApex: number | null;
207
+ /** Airtime with the button held. */
208
+ heldAirtimeMs: number | null;
205
209
  timeToApexMs: number | null;
206
210
  /** Launch → back on the ground. */
207
211
  airtimeMs: number | null;
package/dist/test.js CHANGED
@@ -1,3 +1,3 @@
1
- import { r as auditScene } from "./replay-DlgHItNv.js";
2
- import { C as describeFraming, S as playtestText, _ as facingReport, a as registerAllNodes, b as findPlayer, c as ladderText, d as multiplayText, f as playMultiplayer, g as agreementProblems, h as takeAgreementSnapshots, i as findFloatingProps, l as ladderVerdict, m as feelText, n as createPlaySession, o as runScript, p as feelReport, r as describeCapture, s as validateScene, t as captureScene, u as multiplayProblems, v as facingText, w as framingText, x as playtest, y as failingReplays } from "./test-BMkg8zMV.js";
1
+ import { r as auditScene } from "./replay-Bhdntkvq.js";
2
+ import { C as describeFraming, S as playtestText, _ as facingReport, a as registerAllNodes, b as findPlayer, c as ladderText, d as multiplayText, f as playMultiplayer, g as agreementProblems, h as takeAgreementSnapshots, i as findFloatingProps, l as ladderVerdict, m as feelText, n as createPlaySession, o as runScript, p as feelReport, r as describeCapture, s as validateScene, t as captureScene, u as multiplayProblems, v as facingText, w as framingText, x as playtest, y as failingReplays } from "./test-Ct1_zf5S.js";
3
3
  export { agreementProblems, auditScene, captureScene, createPlaySession, describeCapture, describeFraming, facingReport, facingText, failingReplays, feelReport, feelText, findFloatingProps, findPlayer, framingText, ladderText, ladderVerdict, multiplayProblems, multiplayText, playMultiplayer, playtest, playtestText, registerAllNodes, runScript, takeAgreementSnapshots, validateScene };
package/dist/vite.js CHANGED
@@ -1,6 +1,6 @@
1
- import { t as VERSION } from "./src-CH00_JsR.js";
1
+ import { t as VERSION } from "./src-BlV9Sv4m.js";
2
2
  import { n as diffSignatures } from "./frame-report-BSMny7oe.js";
3
- import { s as validateScene } from "./test-BMkg8zMV.js";
3
+ import { s as validateScene } from "./test-Ct1_zf5S.js";
4
4
  import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
5
5
  import { basename, dirname, join, normalize, relative, resolve, sep } from "node:path";
6
6
  //#region src/vite/frame-endpoint.ts