incanto 0.71.0 → 0.72.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 (62) hide show
  1. package/bin/incanto-editor.mjs +15 -9
  2. package/bin/incanto-feel.mjs +11 -1
  3. package/bin/incanto-play.mjs +11 -1
  4. package/bin/incanto-playtest.mjs +11 -1
  5. package/dist/2d.d.ts +3 -3
  6. package/dist/2d.js +3 -3
  7. package/dist/3d.d.ts +3 -3
  8. package/dist/3d.js +5 -5
  9. package/dist/{agent8-Cfmd3ar_.js → agent8-BqZ0_O1u.js} +1 -1
  10. package/dist/{audio-player-L8yccdMP.d.ts → audio-player-ioZ7VKC6.d.ts} +1 -1
  11. package/dist/{behavior-Dcz0fr1S.d.ts → behavior-Bf9P9oB2.d.ts} +1 -1
  12. package/dist/{create-game-CH4kt78v.js → create-game-C9rWqqAC.js} +36 -12
  13. package/dist/{create-game-LCHBLfA4.js → create-game-CmFAtLZp.js} +7 -6
  14. package/dist/debug.d.ts +1 -1
  15. package/dist/editor.js +1069 -1035
  16. package/dist/{environment-presets-99BzP_L-.js → environment-presets-BeHoaGhy.js} +3 -3
  17. package/dist/{gameplay-CNULJvwh.js → gameplay-BlQe-M07.js} +1 -1
  18. package/dist/gameplay.d.ts +1 -1
  19. package/dist/gameplay.js +1 -1
  20. package/dist/index.d.ts +4 -4
  21. package/dist/index.js +4 -4
  22. package/dist/{loader-8-IHvbKD.d.ts → loader-CBfQzB6S.d.ts} +10 -3
  23. package/dist/net.d.ts +2 -2
  24. package/dist/net.js +2 -2
  25. package/dist/{physics-2d-FhrXUc6B.js → physics-2d-DrIgTlLk.js} +2 -2
  26. package/dist/{physics-3d-CFEGxBXZ.js → physics-3d-BzOCw1VS.js} +3 -3
  27. package/dist/{picking-DVo7fI13.js → picking-C9McVJrO.js} +2 -2
  28. package/dist/react.d.ts +1 -1
  29. package/dist/react.js +1 -1
  30. package/dist/{register-DuVdzxbq.js → register-5IYfooAN.js} +1 -1
  31. package/dist/{register-BYQCBySi.js → register-C8HuRkOf.js} +3 -3
  32. package/dist/{replay-F7IZHdFR.d.ts → replay-CBEChqXq.d.ts} +2 -2
  33. package/dist/{replay-DEvp3kyV.js → replay-datiAE-b.js} +15 -8
  34. package/dist/{save-slots-Bvuh2p_r.js → save-slots-CEuJPUle.js} +46 -1
  35. package/dist/{split-screen-eULetcg-.js → split-screen-Bm5DTElG.js} +3 -3
  36. package/dist/{split-screen-CIYf1zSf.d.ts → split-screen-DkqLng6q.d.ts} +2 -2
  37. package/dist/{src-_jk0qLsS.js → src-DRSsRleD.js} +1 -1
  38. package/dist/{test-CmN54kWv.js → test-Djuq3Vhq.js} +13 -13
  39. package/dist/test.d.ts +4 -4
  40. package/dist/test.js +2 -2
  41. package/dist/vite.d.ts +8 -1
  42. package/dist/vite.js +22 -5
  43. package/editor/assets/{agent8-yLIEYHbd.js → agent8-CMKz2cax.js} +1 -1
  44. package/editor/assets/{debug-u31w_yhq.js → debug-DLrQm-az.js} +1 -1
  45. package/editor/assets/{index-DK9xMGpW.js → index-BEKuxYcE.js} +92 -92
  46. package/editor/index.html +1 -1
  47. package/package.json +1 -1
  48. package/skills/incanto-building-2d-games.md +6 -0
  49. package/skills/incanto-editor.md +4 -0
  50. package/skills/incanto-scene-json-authoring.md +30 -0
  51. package/templates-app/beacon-isle-3d/package.json +1 -1
  52. package/templates-app/beacon-isle-3d/src/game.scene.json +377 -185
  53. package/templates-app/molehill-2d/package.json +1 -1
  54. package/templates-app/platformer-2d/package.json +1 -1
  55. package/templates-app/platformer-2d/src/game.scene.json +193 -93
  56. package/templates-app/star-survivor/package.json +1 -1
  57. package/templates-app/star-survivor/src/game.scene.json +18 -9
  58. package/templates-app/tps-3d/package.json +1 -1
  59. package/templates-app/tps-3d/src/game.scene.json +82 -39
  60. package/templates-app/village-quest-3d/package.json +1 -1
  61. package/templates-app/village-quest-3d/src/grove.scene.json +98 -46
  62. package/templates-app/village-quest-3d/src/village.scene.json +449 -223
@@ -30,7 +30,7 @@
30
30
  import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
31
31
  import { createServer } from 'node:http';
32
32
  import { basename, dirname, extname, join, normalize, relative, resolve, sep } from 'node:path';
33
- import { fileURLToPath } from 'node:url';
33
+ import { fileURLToPath, pathToFileURL } from 'node:url';
34
34
  import { readJson } from './_read-json.mjs';
35
35
 
36
36
  const PKG_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
@@ -463,7 +463,7 @@ const server = createServer((req, res) => {
463
463
  if (!originAllowed(req)) {
464
464
  return send(res, 403, JSON.stringify({ error: 'cross-origin write rejected' }));
465
465
  }
466
- readBody(req, res, (body) => {
466
+ readBody(req, res, async (body) => {
467
467
  // a path with no extension means the usual thing, so `levels/arena` works
468
468
  const wanted =
469
469
  typeof body?.path === 'string' && body.path && !body.path.endsWith('.json')
@@ -495,14 +495,20 @@ const server = createServer((req, res) => {
495
495
  */
496
496
  const asked = body?.dimension === '3d' || body?.dimension === '2d' ? body.dimension : null;
497
497
  const dimension = asked ?? projectDimension() ?? '2d';
498
- const scene = {
499
- format: 1,
500
- type: 'scene',
501
- dimension,
502
- name,
503
- root: { name, type: dimension === '3d' ? 'Node3D' : 'Node2D' },
504
- };
505
498
  try {
499
+ // uid at CREATION, like every node the editor makes: without it the
500
+ // first save backfills one and the diff carries a line nobody wrote.
501
+ // Imported here rather than at the top so starting the editor never
502
+ // pays for `dist` it may not otherwise need — inside the try, so a
503
+ // missing build is a 400 and not a dead server.
504
+ const { newUid } = await import(pathToFileURL(join(PKG_ROOT, 'dist', 'index.js')).href);
505
+ const scene = {
506
+ format: 1,
507
+ type: 'scene',
508
+ dimension,
509
+ name,
510
+ root: { name, type: dimension === '3d' ? 'Node3D' : 'Node2D', uid: newUid() },
511
+ };
506
512
  mkdirSync(dirname(abs), { recursive: true });
507
513
  writeFileSync(abs, formatSceneJson(scene));
508
514
  return send(res, 201, JSON.stringify({ rel: relative(ROOT, abs), abs }));
@@ -60,7 +60,17 @@ if (args.help || !args.scene) {
60
60
  pushed +x/-y/+y/-x until the player moves)
61
61
  --jump ACTION the button to jump with (default: "jump")
62
62
  --json the report as JSON instead of prose`);
63
- process.exit(!args.invalid && args.help && args.scene !== undefined ? 0 : 1);
63
+ /*
64
+ * `--help` is a REQUEST, and the answer is the text above.
65
+ *
66
+ * The rule used to be "0 only if a scene was also named", so the exact thing
67
+ * an agent types first — `incanto-playtest --help` — printed the usage and
68
+ * exited 1, while thirteen sibling bins exited 0 for the same input. A
69
+ * non-zero exit says "you did it wrong" to someone who did the documented
70
+ * thing, and under `set -e` it stops the script. A typo still exits 1
71
+ * (`invalid`), and so does a missing scene when help was not asked for.
72
+ */
73
+ process.exit(args.help && !args.invalid ? 0 : 1);
64
74
  }
65
75
 
66
76
  const { facingReport, facingText, feelReport, feelText } = await import(
@@ -69,7 +69,17 @@ if (args.help || !args.scene) {
69
69
 
70
70
  Headless play: stdin commands (step/press/release/vector/key/mouse/pointer/
71
71
  wheel/capture/describe/framing/logs/quit), JSON-line responses on stdout.`);
72
- process.exit(!args.invalid && args.help && args.scene !== undefined ? 0 : 1);
72
+ /*
73
+ * `--help` is a REQUEST, and the answer is the text above.
74
+ *
75
+ * The rule used to be "0 only if a scene was also named", so the exact thing
76
+ * an agent types first — `incanto-playtest --help` — printed the usage and
77
+ * exited 1, while thirteen sibling bins exited 0 for the same input. A
78
+ * non-zero exit says "you did it wrong" to someone who did the documented
79
+ * thing, and under `set -e` it stops the script. A typo still exits 1
80
+ * (`invalid`), and so does a missing scene when help was not asked for.
81
+ */
82
+ process.exit(args.help && !args.invalid ? 0 : 1);
73
83
  }
74
84
 
75
85
  const out = (obj) => process.stdout.write(`${JSON.stringify(obj)}\n`);
@@ -92,7 +92,17 @@ if (args.help || !args.scene) {
92
92
  Exits 1 when a run THREW or left the world, or when a win is declared and no
93
93
  run reached it. A scene that declares no win, or has nobody to drive, exits 0 —
94
94
  the report marks those · rather than ✗, and the exit code says the same.`);
95
- process.exit(!args.invalid && args.help && args.scene !== undefined ? 0 : 1);
95
+ /*
96
+ * `--help` is a REQUEST, and the answer is the text above.
97
+ *
98
+ * The rule used to be "0 only if a scene was also named", so the exact thing
99
+ * an agent types first — `incanto-playtest --help` — printed the usage and
100
+ * exited 1, while thirteen sibling bins exited 0 for the same input. A
101
+ * non-zero exit says "you did it wrong" to someone who did the documented
102
+ * thing, and under `set -e` it stops the script. A typo still exits 1
103
+ * (`invalid`), and so does a missing scene when help was not asked for.
104
+ */
105
+ process.exit(args.help && !args.invalid ? 0 : 1);
96
106
  }
97
107
 
98
108
  const { playtest, playtestText, playtestFailed, failingReplays } = await import(
package/dist/2d.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- import { c as showBootFailure, i as ParticleSim, o as ParticleView, r as SpatialPose, s as isWebGLAvailable } from "./audio-player-L8yccdMP.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-Dcz0fr1S.js";
1
+ import { c as showBootFailure, i as ParticleSim, o as ParticleView, r as SpatialPose, s as isWebGLAvailable } from "./audio-player-ioZ7VKC6.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-Bf9P9oB2.js";
3
3
  import { t as DiagnosticSink } from "./diagnostics-Cu85N3tL.js";
4
4
  import { a as SceneJson, s as JsonObject } from "./rng-Bb-IutXB.js";
5
5
  import { t as EditorSwitchOptions } from "./editor-switch-CFU9mCec.js";
6
6
  import { r as FrameStats } from "./frame-report-DNxDAb1w.js";
7
- import { t as LoadSceneOptions } from "./loader-8-IHvbKD.js";
7
+ import { t as LoadSceneOptions } from "./loader-CBfQzB6S.js";
8
8
  import { n as AnimationEntry } from "./sprite-animation-CMr6f1K2.js";
9
9
  import { Group, Mesh, Object3D, Scene, Texture } from "three";
10
10
  import * as RapierNs from "@dimforge/rapier2d-compat";
package/dist/2d.js CHANGED
@@ -1,9 +1,9 @@
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-CH4kt78v.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-BYQCBySi.js";
6
- import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-FhrXUc6B.js";
4
+ import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-C9rWqqAC.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-C8HuRkOf.js";
6
+ import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-DrIgTlLk.js";
7
7
  //#region src/2d/library-sprite.ts
8
8
  /**
9
9
  * What a `CharacterController2D`/`3D` will ask a skin to play, and the clip in
package/dist/3d.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- import { c as showBootFailure, i as ParticleSim, o as ParticleView, r as SpatialPose, s as isWebGLAvailable } from "./audio-player-L8yccdMP.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-Dcz0fr1S.js";
1
+ import { c as showBootFailure, i as ParticleSim, o as ParticleView, r as SpatialPose, s as isWebGLAvailable } from "./audio-player-ioZ7VKC6.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-Bf9P9oB2.js";
3
3
  import { t as DiagnosticSink } from "./diagnostics-Cu85N3tL.js";
4
4
  import { a as SceneJson$1, s as JsonObject } from "./rng-Bb-IutXB.js";
5
5
  import { t as EditorSwitchOptions } from "./editor-switch-CFU9mCec.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
- import { t as LoadSceneOptions } from "./loader-8-IHvbKD.js";
7
+ import { t as LoadSceneOptions } from "./loader-CBfQzB6S.js";
8
8
  import { n as PathGrid } from "./pathfinding-_fGrCFmH.js";
9
9
  import { AnimationClip, AnimationMixer, BufferGeometry, Color, DirectionalLight, Group, InstancedMesh, Mesh, MeshPhysicalMaterial, Object3D, PerspectiveCamera, Scene, ShaderMaterial, Texture, Vector3, WebGLRenderer } from "three";
10
10
  import { VRM } from "@pixiv/three-vrm";
package/dist/3d.js CHANGED
@@ -1,12 +1,12 @@
1
- import { C as sunDirectionFromSky, S as sunDirectionFromElevationAzimuth, b as horizonColorFromSky, x as parseEnvironment3D } from "./save-slots-Bvuh2p_r.js";
1
+ import { C as sunDirectionFromSky, S as sunDirectionFromElevationAzimuth, b as horizonColorFromSky, x as parseEnvironment3D } from "./save-slots-CEuJPUle.js";
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 { 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-CNULJvwh.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-99BzP_L-.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-LCHBLfA4.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-BlQe-M07.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-BeHoaGhy.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-CmFAtLZp.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-CFEGxBXZ.js";
9
+ import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-BzOCw1VS.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;
@@ -1,5 +1,5 @@
1
1
  import { o as __exportAll } from "./json-CfTjpvW8.js";
2
- import { Y as diagnose } from "./save-slots-Bvuh2p_r.js";
2
+ import { Y as diagnose } from "./save-slots-CEuJPUle.js";
3
3
  //#region src/net/agent8.ts
4
4
  var agent8_exports = /* @__PURE__ */ __exportAll({
5
5
  Agent8TransportForTest: () => Agent8Transport,
@@ -1,4 +1,4 @@
1
- import { d as PropSchema, dt as Listener, jt as Node } from "./behavior-Dcz0fr1S.js";
1
+ import { d as PropSchema, dt as Listener, jt as Node } from "./behavior-Bf9P9oB2.js";
2
2
  import { t as Rng } from "./rng-Bb-IutXB.js";
3
3
 
4
4
  //#region src/core/boot-failure.d.ts
@@ -2297,7 +2297,7 @@ declare class Engine {
2297
2297
  * pass it back. Without that a game using the documented sub-scenes booted
2298
2298
  * fine and threw `UNRESOLVED_INSTANCE` on its first restart.
2299
2299
  */
2300
- resolveScene?: (path: string) => SceneJson;
2300
+ resolveScene?: (path: string) => SceneJson | null | undefined;
2301
2301
  /**
2302
2302
  * How the current scene was LOADED, for the rebuilds that happen later.
2303
2303
  *
@@ -1,15 +1,15 @@
1
1
  import { o as __exportAll } from "./json-CfTjpvW8.js";
2
- import { D as computeViewport, O as resolveViewport, Y as diagnose, h as loadScene, ot as registerBehavior } from "./save-slots-Bvuh2p_r.js";
3
- import { C as qualityRendering, _ as AudioPlayer, v as Engine } from "./register-DuVdzxbq.js";
2
+ import { D as computeViewport, O as resolveViewport, R as sceneDimension, Y as diagnose, h as loadScene, ot as registerBehavior } from "./save-slots-CEuJPUle.js";
3
+ import { C as qualityRendering, _ as AudioPlayer, v as Engine } from "./register-5IYfooAN.js";
4
4
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
5
5
  import { n as attachTouchControls } from "./touch-BnCyPA0G.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-DVo7fI13.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-C9McVJrO.js";
8
8
  import { o as frameStats } from "./frame-report-D-_7YF2G.js";
9
- import { n as registerGameplayBehaviors } from "./gameplay-CNULJvwh.js";
10
- import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-BYQCBySi.js";
9
+ import { n as registerGameplayBehaviors } from "./gameplay-BlQe-M07.js";
10
+ import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-C8HuRkOf.js";
11
11
  import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
12
- import { n as enablePhysics2D } from "./physics-2d-FhrXUc6B.js";
12
+ import { n as enablePhysics2D } from "./physics-2d-DrIgTlLk.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
  /**
@@ -132,6 +132,34 @@ var AssetStore2D = class {
132
132
  }
133
133
  };
134
134
  //#endregion
135
+ //#region src/2d/debug-lines.ts
136
+ /**
137
+ * Physics debug segments, moved into the space the 2D renderer draws in.
138
+ *
139
+ * Two coordinate systems meet here and they disagree about Y. Engine 2D is
140
+ * y-DOWN (screen pixels, gravity `+980`, and Rapier's world is built the same
141
+ * way — `kcc.setUp({x: 0, y: -1})`). The three.js scene the renderer paints
142
+ * into is y-UP, which is why every node's own sync writes
143
+ * `o.position.set(x, -y, 0)`.
144
+ *
145
+ * `syncDebugLines` copied Rapier's vertices straight across without that
146
+ * negation, so every collider outline was MIRRORED about the world's y=0 line:
147
+ * a crate at y=120 drew its box at −120, the further from the axis the further
148
+ * off, and a tilemap's merged floor at y=384 drew itself off the top of the
149
+ * canvas entirely. The overlay whose whole promise is "the colliders the
150
+ * ENGINE builds… wherever physics actually puts them" was the one thing in the
151
+ * 2D view that was not where physics put it.
152
+ */
153
+ function debugLinesToScene(px) {
154
+ const xyz = new Float32Array(px.length / 2 * 3);
155
+ for (let i = 0, j = 0; i < px.length; i += 2, j += 3) {
156
+ xyz[j] = px[i];
157
+ xyz[j + 1] = -px[i + 1];
158
+ xyz[j + 2] = 0;
159
+ }
160
+ return xyz;
161
+ }
162
+ //#endregion
135
163
  //#region src/2d/picking.ts
136
164
  function screenFromWorld(view, wx, wy) {
137
165
  return {
@@ -547,12 +575,7 @@ var Renderer2D = class {
547
575
  }
548
576
  this.debugLines.visible = vertices !== null;
549
577
  if (!vertices) return;
550
- const xyz = new Float32Array(vertices.length / 2 * 3);
551
- for (let i = 0, j = 0; i < vertices.length; i += 2, j += 3) {
552
- xyz[j] = vertices[i];
553
- xyz[j + 1] = vertices[i + 1];
554
- xyz[j + 2] = 0;
555
- }
578
+ const xyz = debugLinesToScene(vertices);
556
579
  this.debugLines.geometry.setAttribute("position", new BufferAttribute(xyz, 3));
557
580
  }
558
581
  render() {
@@ -809,6 +832,7 @@ async function createGame2D(opts) {
809
832
  ...opts._scheduler ? { scheduler: opts._scheduler } : {}
810
833
  });
811
834
  const sourceJson = cloneSceneJson(opts.scene);
835
+ if (sceneDimension(sourceJson) === "3d") throw new IncantoError("WRONG_DIMENSION", `createGame2D was given a 3D scene ('${String(sourceJson.name ?? "scene")}'). Its nodes are never drawn by the 2D renderer and never simulated by 2D physics — you get a blank canvas. Boot it with createGame3D instead.`);
812
836
  const scene = loadScene(cloneSceneJson(sourceJson), {
813
837
  resolveScene: opts.resolveScene,
814
838
  engine
@@ -1,15 +1,15 @@
1
1
  import { o as __exportAll } from "./json-CfTjpvW8.js";
2
- import { C as sunDirectionFromSky, Y as diagnose, b as horizonColorFromSky, h as loadScene, ot as registerBehavior, x as parseEnvironment3D } from "./save-slots-Bvuh2p_r.js";
3
- import { C as qualityRendering, S as qualityEnvironment, _ as AudioPlayer, v as Engine, x as qualityCaps } from "./register-DuVdzxbq.js";
2
+ import { C as sunDirectionFromSky, R as sceneDimension, Y as diagnose, b as horizonColorFromSky, h as loadScene, ot as registerBehavior, x as parseEnvironment3D } from "./save-slots-CEuJPUle.js";
3
+ import { C as qualityRendering, S as qualityEnvironment, _ as AudioPlayer, v as Engine, x as qualityCaps } from "./register-5IYfooAN.js";
4
4
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
5
5
  import { n as attachTouchControls } from "./touch-BnCyPA0G.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-DVo7fI13.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-C9McVJrO.js";
8
8
  import { o as frameStats } from "./frame-report-D-_7YF2G.js";
9
- import { J as createCausticsQuad, K as Node3D, U as PhysicsBody3D, n as registerGameplayBehaviors } from "./gameplay-CNULJvwh.js";
9
+ import { J as createCausticsQuad, K as Node3D, U as PhysicsBody3D, n as registerGameplayBehaviors } from "./gameplay-BlQe-M07.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-99BzP_L-.js";
12
- import { n as enablePhysics3D } from "./physics-3d-CFEGxBXZ.js";
11
+ import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-BeHoaGhy.js";
12
+ import { n as enablePhysics3D } from "./physics-3d-BzOCw1VS.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";
@@ -2253,6 +2253,7 @@ async function createGame3D(opts) {
2253
2253
  ...opts._scheduler ? { scheduler: opts._scheduler } : {}
2254
2254
  });
2255
2255
  const sourceJson = cloneSceneJson(opts.scene);
2256
+ if (sceneDimension(sourceJson) === "2d") throw new IncantoError("WRONG_DIMENSION", `createGame3D was given a 2D scene ('${String(sourceJson.name ?? "scene")}'). Its nodes are never drawn by the 3D renderer and never simulated by 3D physics — you get a blank canvas. Boot it with createGame2D instead.`);
2256
2257
  const scene = loadScene(cloneSceneJson(sourceJson), {
2257
2258
  resolveScene: opts.resolveScene,
2258
2259
  engine
package/dist/debug.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Ft as LogLevel, T as RendererStats, b as Engine } from "./behavior-Dcz0fr1S.js";
1
+ import { Ft as LogLevel, T as RendererStats, b as Engine } from "./behavior-Bf9P9oB2.js";
2
2
 
3
3
  //#region src/debug/panel.d.ts
4
4
  /** Minimal document surface the overlay needs (injectable for tests). */