incanto 0.75.0 → 0.77.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 (39) hide show
  1. package/dist/2d.d.ts +1 -1
  2. package/dist/2d.js +4 -4
  3. package/dist/3d.d.ts +121 -3
  4. package/dist/3d.js +4 -4
  5. package/dist/{create-game-DnwhJ5nW.js → create-game-BMIPKrQW.js} +5 -5
  6. package/dist/{create-game-DVUhHs2B.js → create-game-Dai5vfVu.js} +5 -5
  7. package/dist/{editor-switch-O8mxpgRX.d.ts → editor-switch-Bzt0GzVp.d.ts} +12 -2
  8. package/dist/{environment-presets-BP77Dl0K.js → environment-presets-e_9YCnGu.js} +348 -36
  9. package/dist/{gameplay-D-JuGura.js → gameplay-Bfff_beb.js} +1468 -61
  10. package/dist/gameplay.js +1 -1
  11. package/dist/index.js +1 -1
  12. package/dist/{physics-2d-x3bCrQf0.js → physics-2d-Tuf5LAyq.js} +2 -2
  13. package/dist/{physics-3d-Bz2VPQ6D.js → physics-3d-C5MOujfQ.js} +2 -2
  14. package/dist/{picking-Buita5T9.js → picking-DIwE48sU.js} +8 -5
  15. package/dist/react.js +1 -1
  16. package/dist/{register-DxAbTO2T.js → register-7E3P1gz6.js} +1 -1
  17. package/dist/{src-DLKVc6Hj.js → src-DygJfhOb.js} +1 -1
  18. package/dist/{test-HlVUeCSn.js → test-CVbxnXlv.js} +7 -7
  19. package/dist/test.js +1 -1
  20. package/dist/vite.d.ts +47 -3
  21. package/dist/vite.js +81 -20
  22. package/editor/assets/{agent8-BXlYM9rv.js → agent8-DA-I5qhv.js} +1 -1
  23. package/editor/assets/{debug-S42XGP4Y.js → debug-99tEPoGm.js} +1 -1
  24. package/editor/assets/index-Db74LZY-.js +11579 -0
  25. package/editor/index.html +1 -1
  26. package/package.json +1 -1
  27. package/schemas/scene.schema.json +30 -2
  28. package/skills/incanto-3d-character.md +26 -1
  29. package/skills/incanto-editor.md +56 -2
  30. package/skills/incanto-environment.md +30 -12
  31. package/skills/incanto-node-reference.md +6 -1
  32. package/templates-app/beacon-isle-3d/package.json +1 -1
  33. package/templates-app/beacon-isle-3d/src/game.scene.json +6 -1
  34. package/templates-app/molehill-2d/package.json +1 -1
  35. package/templates-app/platformer-2d/package.json +1 -1
  36. package/templates-app/star-survivor/package.json +1 -1
  37. package/templates-app/tps-3d/package.json +1 -1
  38. package/templates-app/village-quest-3d/package.json +1 -1
  39. package/editor/assets/index-DgrgUKno.js +0 -11046
package/dist/2d.d.ts CHANGED
@@ -2,7 +2,7 @@ import { c as showBootFailure, i as ParticleSim, o as ParticleView, r as Spatial
2
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-B_245qRy.js";
3
3
  import { t as DiagnosticSink } from "./diagnostics-Cu85N3tL.js";
4
4
  import { a as SceneJson, s as JsonObject } from "./rng-BsXZg3D6.js";
5
- import { t as EditorSwitchOptions } from "./editor-switch-O8mxpgRX.js";
5
+ import { t as EditorSwitchOptions } from "./editor-switch-Bzt0GzVp.js";
6
6
  import { r as FrameStats } from "./frame-report-DNxDAb1w.js";
7
7
  import { t as LoadSceneOptions } from "./loader-CbkVdXL8.js";
8
8
  import { n as AnimationEntry } from "./sprite-animation-CMr6f1K2.js";
package/dist/2d.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
2
2
  import { t as showBootFailure } from "./boot-failure-CKYrEcGF.js";
3
3
  import { t as isWebGLAvailable } from "./webgl-unavailable-C8aDbGmR.js";
4
- import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-DnwhJ5nW.js";
5
- import { _ as Node2D, f as Area2D, g as StaticBody2D, h as RigidBody2D, m as PhysicsBody2D, p as CharacterBody2D } from "./gameplay-D-JuGura.js";
6
- import { a as parseCells, c as ColorRect2D, d as AnimatedSprite2D, f as Sprite2D, i as mergeSolidRects, l as CharacterController2D, n as UILayer, o as Particles2D, p as Joint2D, r as TileMap2D, s as Label, t as registerNodes2D, u as Camera2D } from "./register-DxAbTO2T.js";
7
- import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-x3bCrQf0.js";
4
+ import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-BMIPKrQW.js";
5
+ import { _ as Node2D, f as Area2D, g as StaticBody2D, h as RigidBody2D, m as PhysicsBody2D, p as CharacterBody2D } from "./gameplay-Bfff_beb.js";
6
+ import { a as parseCells, c as ColorRect2D, d as AnimatedSprite2D, f as Sprite2D, i as mergeSolidRects, l as CharacterController2D, n as UILayer, o as Particles2D, p as Joint2D, r as TileMap2D, s as Label, t as registerNodes2D, u as Camera2D } from "./register-7E3P1gz6.js";
7
+ import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-Tuf5LAyq.js";
8
8
  //#region src/2d/library-sprite.ts
9
9
  /**
10
10
  * What a `CharacterController2D`/`3D` will ask a skin to play, and the clip in
package/dist/3d.d.ts CHANGED
@@ -2,7 +2,7 @@ import { c as showBootFailure, i as ParticleSim, o as ParticleView, r as Spatial
2
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-B_245qRy.js";
3
3
  import { t as DiagnosticSink } from "./diagnostics-Cu85N3tL.js";
4
4
  import { a as SceneJson$1, s as JsonObject } from "./rng-BsXZg3D6.js";
5
- import { t as EditorSwitchOptions } from "./editor-switch-O8mxpgRX.js";
5
+ import { t as EditorSwitchOptions } from "./editor-switch-Bzt0GzVp.js";
6
6
  import { a as GridCell, c as diffText, d as frameText, i as FrameStatsOptions, l as frameSignature, n as FrameSignature, o as SIGNATURE_GRID, r as FrameStats, s as diffSignatures, t as FrameDiff, u as frameStats } from "./frame-report-DNxDAb1w.js";
7
7
  import { t as LoadSceneOptions } from "./loader-CbkVdXL8.js";
8
8
  import { n as PathGrid } from "./pathfinding-_fGrCFmH.js";
@@ -1763,8 +1763,18 @@ declare class CharacterController3D extends Node3D {
1763
1763
  * is what a drowning pit wants and what every scene got before this.
1764
1764
  */
1765
1765
  swimSpeed: number;
1766
- /** Where the body's origin rides below the surface while swimming (m). */
1767
- swimDepth: number;
1766
+ /**
1767
+ * How far the body's ORIGIN rides below the surface while swimming (m), or
1768
+ * `null` (the default) to take it from the body: deep enough that the head
1769
+ * rides 15 cm clear and the rest is in the water, which is what treading
1770
+ * water looks like.
1771
+ *
1772
+ * The origin is the middle of the capsule, so a fixed number is only ever
1773
+ * right for one character size. The 0.35 m this used to default to left the
1774
+ * head of a standard 1.68 m rig 0.46 m clear of the surface — a person
1775
+ * floating like a boat, chest and shoulders in the air.
1776
+ */
1777
+ swimDepth: number | null;
1768
1778
  /** Held: swim down at `swimSpeed`. Missing from the input map is fine. */
1769
1779
  diveAction: string;
1770
1780
  /**
@@ -1820,6 +1830,20 @@ declare class CharacterController3D extends Node3D {
1820
1830
  * 200 kg character does not move a seesaw a 70 kg crate tips.
1821
1831
  */
1822
1832
  stepHeight: number;
1833
+ /**
1834
+ * The steepest ground this character STANDS on, in degrees (0-90).
1835
+ *
1836
+ * At or under it the ground is ground: the character holds its place with no
1837
+ * slide at all, however long you leave it there. Over it the ground stops
1838
+ * counting as ground — no hover spring, no `grounded`, no jump reset — and
1839
+ * the body slips off the face, which is what a slope limit means in every
1840
+ * engine that has one.
1841
+ *
1842
+ * 55° is a person. A mountain goat is 80; something on wheels is 25. `90`
1843
+ * turns the limit off — which is what this controller did before it had one,
1844
+ * and why it slid down a 7° hillside.
1845
+ */
1846
+ slopeLimitDeg: number;
1823
1847
  mouseLook: boolean;
1824
1848
  zoomMin: number;
1825
1849
  zoomMax: number;
@@ -1907,6 +1931,10 @@ declare class CharacterController3D extends Node3D {
1907
1931
  /** idle | walk | run | fastRun | airborne | swim — drive animations from this. */
1908
1932
  state: MovementState;
1909
1933
  grounded: boolean;
1934
+ /** Slope of the ground under the character, degrees — 0 when there is none. */
1935
+ groundSlopeDeg: number;
1936
+ /** Its outward normal, or null. `[0, 1, 0]` is flat ground. */
1937
+ groundNormal: [number, number, number] | null;
1910
1938
  /** In water too deep to stand in — held at the surface by the swim spring. */
1911
1939
  swimming: boolean;
1912
1940
  /** The head is under the surface (diving, or a wave over it). */
@@ -1936,6 +1964,12 @@ declare class CharacterController3D extends Node3D {
1936
1964
  private jumping;
1937
1965
  /** Seconds of air control still suppressed after a wall kick. */
1938
1966
  private wallLockout;
1967
+ /** What the anti-slide has learned it must keep paying to hold a slope. */
1968
+ private slideHold;
1969
+ /** Where the body stood last step, for the anti-slide's position error. */
1970
+ private slideFrom;
1971
+ /** Seconds since the player last asked this character to move. */
1972
+ private stillFor;
1939
1973
  /** The outward normal of the wall being pressed into this step, if any. */
1940
1974
  private wallNormal;
1941
1975
  private get body();
@@ -1959,6 +1993,8 @@ declare class CharacterController3D extends Node3D {
1959
1993
  */
1960
1994
  private setHeight;
1961
1995
  private sceneGravity;
1996
+ /** `swimDepth`, or what it is derived to be for this body (see the prop). */
1997
+ private effectiveSwimDepth;
1962
1998
  private surfaceAt;
1963
1999
  /**
1964
2000
  * Read an input action this controller is allowed to be missing.
@@ -3500,6 +3536,12 @@ declare class River3D extends Node3D implements SunConsumer3D {
3500
3536
  private rockScanAt;
3501
3537
  private world;
3502
3538
  private readonly _bodies;
3539
+ private cubeTarget;
3540
+ private cubeCamera;
3541
+ private lastSkyAt;
3542
+ private rippleFft;
3543
+ private rippleSpectrum;
3544
+ private fftUnsupported;
3503
3545
  /** Loader hook: a malformed river fails at LOAD, not as an invisible ribbon. */
3504
3546
  static validateJson(node: Node): void;
3505
3547
  protected override _createObject3D(): Object3D;
@@ -3511,6 +3553,10 @@ declare class River3D extends Node3D implements SunConsumer3D {
3511
3553
  override _syncObject3D(): void;
3512
3554
  /** Rocks are picked per FRAME (nearest to the eye), scanned on a timer. */
3513
3555
  _onRender3D(ctx: RenderContext3D): void;
3556
+ /** The sky cube: the world beyond the banks, from above the channel's middle. */
3557
+ private syncSky;
3558
+ /** The ripple FFT, advected by the fragment in the ribbon's own frame. */
3559
+ private syncRipple;
3514
3560
  /**
3515
3561
  * @internal Water surface height over a world point, or null where this
3516
3562
  * river does not run — the question scattered vegetation asks before it
@@ -4143,6 +4189,16 @@ declare class Water3D extends Node3D implements RenderHook3D, SunConsumer3D {
4143
4189
  */
4144
4190
  mirror: boolean;
4145
4191
  /**
4192
+ * Screen-space reflections (fancy only, default on): the scene ABOVE the
4193
+ * waterline is rendered once at half resolution and every water pixel
4194
+ * marches its reflected ray through that image — so a rock, a pier, a
4195
+ * wader or a boat is mirrored on the water WITHOUT the planar `mirror`
4196
+ * pass. What the screen cannot see (behind the camera, off its edges)
4197
+ * falls back to the sky cube, which is why a mirror-calm lake still wants
4198
+ * `mirror: true`; with `mirror` on this is skipped as redundant.
4199
+ */
4200
+ ssr: boolean;
4201
+ /**
4146
4202
  * Milliseconds between planar-mirror re-renders. A reflection seen through a
4147
4203
  * rippling surface does not need 60 Hz — 33 ms halves the pass's cost and
4148
4204
  * nobody can tell. 0 re-renders every frame.
@@ -4203,6 +4259,30 @@ declare class Water3D extends Node3D implements RenderHook3D, SunConsumer3D {
4203
4259
  /** Primary swell wavelength in meters (the two crossing trains derive). */
4204
4260
  swellWavelength: number;
4205
4261
  /**
4262
+ * The bottom under this water: a node path to a Terrain3D (fancy only). With
4263
+ * it the swell KNOWS the beach — waves slow and rise as the bottom comes up
4264
+ * (Green's law), their crests peak, and at 0.78× the depth they BREAK into
4265
+ * foam, with spray sprites bursting where the foam fronts pass. Sampled
4266
+ * once into a 256² depth grid over the terrain's footprint; beyond it the
4267
+ * water is assumed deep. Pair with `swell` (the waves that shoal) and
4268
+ * `shoreWaves` (the foam fronts the spray rides).
4269
+ */
4270
+ bed: string;
4271
+ /**
4272
+ * Wind speed in m/s — THE realistic-sea dial (fancy only; 0 = off). Above 0
4273
+ * the surface stops being a noise field and becomes a JONSWAP spectrum:
4274
+ * thousands of waves at every wavelength and heading, each moving at the
4275
+ * speed deep water gives it, inverse-FFT'd on the GPU every frame into a
4276
+ * tiling patch with real crest shapes, choppy horizontal drag and whitecaps
4277
+ * born where the surface folds. The wind blows toward `swellDirectionDeg`.
4278
+ * 4 = a light breeze (ripples, 20 cm), 7 = a fresh breeze (1 m waves),
4279
+ * 12 = rough. The CPU twin (buoyancy, waders) sums the same spectrum.
4280
+ */
4281
+ wind: number;
4282
+ /** Horizontal drag of the FFT sea toward its crests, 0..~1.5 — narrow
4283
+ * crests, broad troughs; past ~1.2 the surface folds and foams everywhere. */
4284
+ choppiness: number;
4285
+ /**
4206
4286
  * GERSTNER pinch on the swell: 0 keeps the legacy height-only trains, 1 is
4207
4287
  * maximum trochoid (crests narrow to a peak, troughs go broad). It also
4208
4288
  * decides where whitecaps break — the surface's Jacobian collapses on a
@@ -4265,6 +4345,26 @@ declare class Water3D extends Node3D implements RenderHook3D, SunConsumer3D {
4265
4345
  /** Per-frame scene pre-pass: depth (absorption/foam) + color grab (refraction). */
4266
4346
  private scenePassTarget;
4267
4347
  private mirrorTarget;
4348
+ /** Half-res render of the scene ABOVE the waterline — what SSR reflects. */
4349
+ private aboveTarget;
4350
+ private readonly ssrViewProj;
4351
+ /** The FFT sea (wind > 0): the GPU passes, and the CPU spectrum they share. */
4352
+ private seaFft;
4353
+ private seaFftUnsupported;
4354
+ private spectrum;
4355
+ private spectrumKey;
4356
+ private uploadedSpectrumKey;
4357
+ private rippleFft;
4358
+ private rippleSpectrum;
4359
+ private rippleKey;
4360
+ private uploadedRippleKey;
4361
+ /** The bed depth grid (see `bed`), its footprint, and the spray that rides it. */
4362
+ private bedTexture;
4363
+ private bedRect;
4364
+ private bedKey;
4365
+ private spray;
4366
+ /** Vertex spacing of the fancy grid — the mip the vertex shader reads at. */
4367
+ private fancySegments;
4268
4368
  private readonly mirrorCamera;
4269
4369
  private readonly mirrorMatrix;
4270
4370
  private lastMirrorAt;
@@ -4379,6 +4479,11 @@ declare class Water3D extends Node3D implements RenderHook3D, SunConsumer3D {
4379
4479
  private renderCutoutMasks;
4380
4480
  private syncFancy;
4381
4481
  /**
4482
+ * The bed depth grid and the spray that rides it. Built once per `bed`
4483
+ * (terrain heights are static); torn down when the path is cleared.
4484
+ */
4485
+ private syncBed;
4486
+ /**
4382
4487
  * @internal Environment-sky sun hand-off (see {@link SunConsumer3D}): the
4383
4488
  * sky's sun drives the glint ONLY while the `sunDirection` prop sits at its
4384
4489
  * schema default — an explicitly authored prop always wins. Runs right
@@ -4423,6 +4528,19 @@ declare class Water3D extends Node3D implements RenderHook3D, SunConsumer3D {
4423
4528
  _waterYAt(x: number, z: number): number | null;
4424
4529
  /** Base wave height at world (x, z) — the CPU twin of the active shader.
4425
4530
  * Ripples are excluded on purpose: a splash must not re-trigger itself. */
4531
+ /**
4532
+ * The sea's spectrum, or null when there is no wind (or the tier collapsed
4533
+ * the surface to the simple shader, whose CPU waves are its own). Built on
4534
+ * the CPU once per (wind, heading, choppiness) and shared by the GPU upload
4535
+ * and the headless twin — one sea, two evaluators.
4536
+ */
4537
+ private seaSpectrum;
4538
+ /**
4539
+ * The ripple layer's spectrum: the sea's own wind when it blows, else the
4540
+ * breeze that puts wind ripple on a pool — its ENERGY is irrelevant (the
4541
+ * layer is normalized to `detailStrength` by rms slope), only its shape.
4542
+ */
4543
+ private rippleSpectrumFor;
4426
4544
  private waveOffsetAt;
4427
4545
  }
4428
4546
  //#endregion
package/dist/3d.js CHANGED
@@ -2,11 +2,11 @@ import { D as sunDirectionFromElevationAzimuth, E as parseEnvironment3D, O as su
2
2
  import { t as showBootFailure } from "./boot-failure-CKYrEcGF.js";
3
3
  import { t as isWebGLAvailable } from "./webgl-unavailable-C8aDbGmR.js";
4
4
  import { a as frameSignature, n as diffSignatures, o as frameStats, r as diffText, s as frameText, t as SIGNATURE_GRID } from "./frame-report-D-_7YF2G.js";
5
- import { $ as Water3D, at as PhysicsBody3D, ct as Node3D, dt as WATER_MAX_RIPPLES, et as WATER_CUTOUT_MAX, it as CharacterBody3D, ot as RigidBody3D, rt as Area3D, st as StaticBody3D, tt as WaterCutout3D } from "./gameplay-D-JuGura.js";
6
- import { A as CharacterController3D, B as InstancedMesh3D, C as SpotLight3D, D as resolveFlowerDensity, E as Flowers3D, F as Terrain3D, G as keyboardIntensity, I as DEFAULT_TERRAIN_TEXTURE_BASE, J as TextureCache3D, K as movementState, L as TERRAIN_THEMES, M as BoneLookAt3D, N as BoneAttachment3D, O as FLOWER_VARIETIES, P as Billboard3D, R as terrainThemeLayers, S as OmniLight3D, T as DENSITY_PRESETS, U as QUARTER_PITCH, V as MeshInstance3D, W as cameraRelative, X as acquireTexture, Y as acquireOwnTexture, _ as Ragdoll3D, a as VoxelGrid3D, b as LoftMesh3D, c as Trail3D, d as findRiverCoverageGaps, f as projectToRiver, g as traceDownhillPath, h as smoothCourse, i as VOXEL_PALETTE, j as Camera3D, k as Flock3D, l as River3D, m as riverStepFor, n as registerNodes3D, o as Vehicle3D, p as riverCarveChannels, q as rigPose, r as Weather3D, s as Tree3D, u as buildRiverRings, v as Particles3D, w as Foliage3D, x as DirectionalLight3D, y as ModelInstance3D, z as Joint3D } from "./environment-presets-BP77Dl0K.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-DVUhHs2B.js";
5
+ import { $ as Water3D, at as PhysicsBody3D, ct as Node3D, dt as WATER_MAX_RIPPLES, et as WATER_CUTOUT_MAX, it as CharacterBody3D, ot as RigidBody3D, rt as Area3D, st as StaticBody3D, tt as WaterCutout3D } from "./gameplay-Bfff_beb.js";
6
+ import { A as CharacterController3D, B as InstancedMesh3D, C as SpotLight3D, D as resolveFlowerDensity, E as Flowers3D, F as Terrain3D, G as keyboardIntensity, I as DEFAULT_TERRAIN_TEXTURE_BASE, J as TextureCache3D, K as movementState, L as TERRAIN_THEMES, M as BoneLookAt3D, N as BoneAttachment3D, O as FLOWER_VARIETIES, P as Billboard3D, R as terrainThemeLayers, S as OmniLight3D, T as DENSITY_PRESETS, U as QUARTER_PITCH, V as MeshInstance3D, W as cameraRelative, X as acquireTexture, Y as acquireOwnTexture, _ as Ragdoll3D, a as VoxelGrid3D, b as LoftMesh3D, c as Trail3D, d as findRiverCoverageGaps, f as projectToRiver, g as traceDownhillPath, h as smoothCourse, i as VOXEL_PALETTE, j as Camera3D, k as Flock3D, l as River3D, m as riverStepFor, n as registerNodes3D, o as Vehicle3D, p as riverCarveChannels, q as rigPose, r as Weather3D, s as Tree3D, u as buildRiverRings, v as Particles3D, w as Foliage3D, x as DirectionalLight3D, y as ModelInstance3D, z as Joint3D } from "./environment-presets-e_9YCnGu.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-Dai5vfVu.js";
8
8
  import { n as splatWeights, t as buildHeightmap } from "./heightmap-BYgD5Edk.js";
9
- import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-Bz2VPQ6D.js";
9
+ import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-C5MOujfQ.js";
10
10
  //#region src/3d/model-verdict.ts
11
11
  /** Mixamo exports every bone as `mixamorigX`; the retargeter binds by that name. */
12
12
  const MIXAMO = /^mixamorig[:_]?/i;
@@ -4,12 +4,12 @@ import { T as qualityRendering, b as Engine, y as AudioPlayer } from "./register
4
4
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
5
5
  import { n as attachTouchControls } from "./touch-CioTZB-y.js";
6
6
  import { n as withWebGLContext, r as resolveRendering } from "./webgl-unavailable-C8aDbGmR.js";
7
- import { a as devServerLibrary, c as applyDriveStep, d as audioErrors, i as crossFade, l as wireDevChannel, n as teardown, o as openBundledEditor, r as pauseWhenHidden, t as nodeFromHits, u as claimCanvasGestures } from "./picking-Buita5T9.js";
7
+ import { a as devServerLibrary, c as applyDriveStep, d as audioErrors, i as crossFade, l as wireDevChannel, n as teardown, o as openBundledEditor, r as pauseWhenHidden, t as nodeFromHits, u as claimCanvasGestures } from "./picking-DIwE48sU.js";
8
8
  import { o as frameStats } from "./frame-report-D-_7YF2G.js";
9
- import { _ as Node2D, m as PhysicsBody2D, n as registerGameplayBehaviors } from "./gameplay-D-JuGura.js";
9
+ import { _ as Node2D, m as PhysicsBody2D, n as registerGameplayBehaviors } from "./gameplay-Bfff_beb.js";
10
10
  import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
11
- import { n as UILayer, t as registerNodes2D, u as Camera2D } from "./register-DxAbTO2T.js";
12
- import { n as enablePhysics2D } from "./physics-2d-x3bCrQf0.js";
11
+ import { n as UILayer, t as registerNodes2D, u as Camera2D } from "./register-7E3P1gz6.js";
12
+ import { n as enablePhysics2D } from "./physics-2d-Tuf5LAyq.js";
13
13
  import { Box3, BufferAttribute, BufferGeometry, Color, LineBasicMaterial, LineSegments, LinearFilter, NearestFilter, OrthographicCamera, Raycaster, SRGBColorSpace, Scene, TextureLoader, Vector2, Vector3, WebGLRenderer } from "three";
14
14
  //#region src/2d/assets.ts
15
15
  /**
@@ -1034,7 +1034,7 @@ async function createGame2D(opts) {
1034
1034
  await open({
1035
1035
  scene: sourceJson,
1036
1036
  play: reboot,
1037
- exit: () => reboot(sourceJson),
1037
+ exit: (working) => reboot(working ?? sourceJson),
1038
1038
  ...editorSwitch.save ? { save: editorSwitch.save } : {},
1039
1039
  ...editorSwitch.library ? { library: editorSwitch.library === true ? devServerLibrary() : editorSwitch.library } : {}
1040
1040
  });
@@ -4,12 +4,12 @@ import { C as qualityCaps, T as qualityRendering, b as Engine, w as qualityEnvir
4
4
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
5
5
  import { n as attachTouchControls } from "./touch-CioTZB-y.js";
6
6
  import { n as withWebGLContext, r as resolveRendering } from "./webgl-unavailable-C8aDbGmR.js";
7
- import { a as devServerLibrary, c as applyDriveStep, d as audioErrors, i as crossFade, l as wireDevChannel, n as teardown, o as openBundledEditor, r as pauseWhenHidden, s as poseFromRenderer, t as nodeFromHits, u as claimCanvasGestures } from "./picking-Buita5T9.js";
7
+ import { a as devServerLibrary, c as applyDriveStep, d as audioErrors, i as crossFade, l as wireDevChannel, n as teardown, o as openBundledEditor, r as pauseWhenHidden, s as poseFromRenderer, t as nodeFromHits, u as claimCanvasGestures } from "./picking-DIwE48sU.js";
8
8
  import { o as frameStats } from "./frame-report-D-_7YF2G.js";
9
- import { at as PhysicsBody3D, ct as Node3D, n as registerGameplayBehaviors, ut as createCausticsQuad } from "./gameplay-D-JuGura.js";
9
+ import { at as PhysicsBody3D, ct as Node3D, n as registerGameplayBehaviors, ut as createCausticsQuad } from "./gameplay-Bfff_beb.js";
10
10
  import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
11
- import { J as TextureCache3D, j as Camera3D, n as registerNodes3D, t as resolveEnvironmentHdri, x as DirectionalLight3D, y as ModelInstance3D } from "./environment-presets-BP77Dl0K.js";
12
- import { n as enablePhysics3D } from "./physics-3d-Bz2VPQ6D.js";
11
+ import { J as TextureCache3D, j as Camera3D, n as registerNodes3D, t as resolveEnvironmentHdri, x as DirectionalLight3D, y as ModelInstance3D } from "./environment-presets-e_9YCnGu.js";
12
+ import { n as enablePhysics3D } from "./physics-3d-C5MOujfQ.js";
13
13
  import { ACESFilmicToneMapping, AmbientLight, Box3, BufferAttribute, BufferGeometry, Color, DepthTexture, EquirectangularReflectionMapping, FloatType, Fog, HalfFloatType, LineBasicMaterial, LineSegments, LoadingManager, 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";
@@ -2405,7 +2405,7 @@ async function createGame3D(opts) {
2405
2405
  scene: sourceJson,
2406
2406
  ...camera ? { camera } : {},
2407
2407
  play: reboot,
2408
- exit: () => reboot(sourceJson),
2408
+ exit: (working) => reboot(working ?? sourceJson),
2409
2409
  ...editorSwitch.save ? { save: editorSwitch.save } : {},
2410
2410
  ...editorSwitch.library ? { library: editorSwitch.library === true ? devServerLibrary() : editorSwitch.library } : {}
2411
2411
  });
@@ -14,8 +14,18 @@ interface EditorOpenOptions {
14
14
  camera?: CameraPose;
15
15
  /** Called when the editor hands the page back — boot the game from `working`. */
16
16
  play(working: JsonObject, camera?: CameraPose): void | Promise<void>;
17
- /** Called when the user leaves the editor without playing. */
18
- exit?(): void | Promise<void>;
17
+ /**
18
+ * Called when the user leaves the editor by the ✕ — with the scene as the
19
+ * editor has it.
20
+ *
21
+ * It carries the working scene for the same reason ▶ does: you have been
22
+ * editing it, and half the time you have SAVED it. Handing back the scene the
23
+ * page booted with instead would show you your own edit disappearing, which
24
+ * is what it did until saving stopped reloading the page and made the
25
+ * difference visible. `undefined` (an editor that does not offer one) leaves
26
+ * the caller to fall back to whatever it opened with.
27
+ */
28
+ exit?(working?: JsonObject): void | Promise<void>;
19
29
  /** Persist edits (from `editor.save`). Omitted: no save button. */
20
30
  save?(working: JsonObject): void | Promise<void>;
21
31
  /** Asset-library search (from `editor.library`). Omitted: no 📚 buttons. */