incanto 0.12.0 → 0.14.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 (83) hide show
  1. package/README.md +22 -0
  2. package/bin/incanto-new.mjs +87 -0
  3. package/dist/2d.d.ts +2 -2
  4. package/dist/2d.js +3 -3
  5. package/dist/3d.d.ts +219 -82
  6. package/dist/3d.js +74 -4
  7. package/dist/{behavior-Bod1AyJS.d.ts → behavior-CPibUfnH.d.ts} +4 -2
  8. package/dist/{create-game-C_xf4gm9.js → create-game-Ct86zczq.js} +5 -5
  9. package/dist/{create-game-B2fewJUy.js → create-game-OSntcIiM.js} +5 -5
  10. package/dist/debug.d.ts +1 -1
  11. package/dist/{duplicate-BEvGBtb_.js → duplicate-BINwP0WG.js} +1 -1
  12. package/dist/{gameplay-Dn3yidJw.js → gameplay-sSqrUcnz.js} +75 -3
  13. package/dist/gameplay.d.ts +37 -2
  14. package/dist/gameplay.js +2 -2
  15. package/dist/index.d.ts +3 -3
  16. package/dist/index.js +4 -4
  17. package/dist/{loader-B4OEXDZ8.js → loader-BZqOKfI2.js} +3 -1
  18. package/dist/{loader-BcUDfNHn.d.ts → loader-DILt9PGC.d.ts} +1 -1
  19. package/dist/net.d.ts +1 -1
  20. package/dist/net.js +3 -3
  21. package/dist/{pathfinding-BSiXjd6W.d.ts → pathfinding-RWYkNKx9.d.ts} +1 -1
  22. package/dist/{physics-2d-B6D864oZ.js → physics-2d-BiIdl51r.js} +2 -2
  23. package/dist/{physics-3d-RLNaxRyw.js → physics-3d-D_kUdOjr.js} +2 -2
  24. package/dist/react.d.ts +1 -1
  25. package/dist/react.js +1 -1
  26. package/dist/{register-Cwc-yCYx.js → register-BFFE1Mh1.js} +2 -2
  27. package/dist/{register-ysLR3WQS.js → register-C9-16x_t.js} +562 -157
  28. package/dist/{register-BD6zgrv_.js → register-Djwckzgx.js} +2 -2
  29. package/dist/{register-DJZXxwAn.js → register-nObreUQR.js} +1 -1
  30. package/dist/test.d.ts +2 -2
  31. package/dist/test.js +10 -10
  32. package/editor/assets/{agent8-D_4QY8Aq.js → agent8-BDC4LhjC.js} +1 -1
  33. package/editor/assets/{index-s0DZuroe.js → index-7qOYg7t8.js} +74 -74
  34. package/editor/index.html +1 -1
  35. package/package.json +4 -2
  36. package/schemas/scene.schema.json +266 -6
  37. package/skills/incanto-3d-character.md +35 -0
  38. package/skills/incanto-building-3d-games.md +48 -0
  39. package/skills/incanto-environment.md +15 -16
  40. package/skills/incanto-gameplay-behaviors.md +23 -1
  41. package/skills/incanto-node-reference.md +54 -3
  42. package/templates-app/beacon-isle-3d/PROJECT/Context.md +44 -0
  43. package/templates-app/beacon-isle-3d/PROJECT/Requirements.md +16 -0
  44. package/templates-app/beacon-isle-3d/PROJECT/Status.md +38 -0
  45. package/templates-app/beacon-isle-3d/PROJECT/Structure.md +24 -0
  46. package/templates-app/beacon-isle-3d/docs/project-3d-rules.md +38 -0
  47. package/templates-app/beacon-isle-3d/generate-world.ts +812 -0
  48. package/templates-app/beacon-isle-3d/index.html +68 -0
  49. package/templates-app/beacon-isle-3d/package.json +26 -0
  50. package/templates-app/beacon-isle-3d/src/behaviors.ts +570 -0
  51. package/templates-app/beacon-isle-3d/src/game.scene.json +2969 -0
  52. package/templates-app/beacon-isle-3d/src/main.ts +33 -0
  53. package/templates-app/beacon-isle-3d/tsconfig.json +13 -0
  54. package/templates-app/beacon-isle-3d/verify.ts +285 -0
  55. package/templates-app/beacon-isle-3d/vite.config.ts +5 -0
  56. package/templates-app/tps-3d/PROJECT/Context.md +49 -0
  57. package/templates-app/tps-3d/PROJECT/Requirements.md +38 -0
  58. package/templates-app/tps-3d/PROJECT/Status.md +41 -0
  59. package/templates-app/tps-3d/PROJECT/Structure.md +44 -0
  60. package/templates-app/tps-3d/docs/project-3d-rules.md +38 -0
  61. package/templates-app/tps-3d/index.html +244 -0
  62. package/templates-app/tps-3d/package.json +25 -0
  63. package/templates-app/tps-3d/src/behaviors.ts +405 -0
  64. package/templates-app/tps-3d/src/game.scene.json +677 -0
  65. package/templates-app/tps-3d/src/main.ts +64 -0
  66. package/templates-app/tps-3d/tsconfig.json +13 -0
  67. package/templates-app/tps-3d/verify.ts +167 -0
  68. package/templates-app/tps-3d/vite.config.ts +5 -0
  69. package/templates-app/village-quest-3d/PROJECT/Context.md +39 -0
  70. package/templates-app/village-quest-3d/PROJECT/Requirements.md +36 -0
  71. package/templates-app/village-quest-3d/PROJECT/Status.md +26 -0
  72. package/templates-app/village-quest-3d/PROJECT/Structure.md +30 -0
  73. package/templates-app/village-quest-3d/docs/project-3d-rules.md +38 -0
  74. package/templates-app/village-quest-3d/index.html +68 -0
  75. package/templates-app/village-quest-3d/package.json +25 -0
  76. package/templates-app/village-quest-3d/src/behaviors.ts +529 -0
  77. package/templates-app/village-quest-3d/src/grove.scene.json +826 -0
  78. package/templates-app/village-quest-3d/src/main.ts +35 -0
  79. package/templates-app/village-quest-3d/src/quest.ts +18 -0
  80. package/templates-app/village-quest-3d/src/village.scene.json +680 -0
  81. package/templates-app/village-quest-3d/tsconfig.json +13 -0
  82. package/templates-app/village-quest-3d/verify.ts +254 -0
  83. package/templates-app/village-quest-3d/vite.config.ts +5 -0
package/README.md CHANGED
@@ -3,6 +3,28 @@
3
3
  **Vibe-coding-first web game engine SDK.** Every scene, character, event, and multiplayer
4
4
  rule is JSON an AI agent can read, diff, and rewrite — rendered by three.js.
5
5
 
6
+ ## Start with a whole game
7
+
8
+ ```bash
9
+ bunx incanto-new my-game # Beacon Isle — the flagship 3D template
10
+ cd my-game && bun install && bun run dev
11
+ ```
12
+
13
+ One command scaffolds a complete island action-adventure: a **generated
14
+ golden-hour world** (terrain, sea, groves, grass — `bun run world` re-rolls the
15
+ whole island deterministically), a quest NPC with dialogue and choices, enemies
16
+ that **hunt you across the terrain** via grid navigation, melee with a sword
17
+ riding the character's hand bone, bloom + color-grade, touch controls on
18
+ phones, win fireworks and a death/respawn loop — in ~2 files of game code, the
19
+ rest declared in JSON. `bun run verify` plays the entire quest **headlessly**
20
+ and replays recorded input bit-identically: the agent loop is author → verify →
21
+ fix, no browser needed.
22
+
23
+ `bunx incanto-new --list` shows the other starters (third-person shooter,
24
+ quest vignette).
25
+
26
+ ## Or wire the engine yourself
27
+
6
28
  ```bash
7
29
  bun add incanto three
8
30
  ```
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * incanto-new — scaffold a ready-to-run incanto game from a shipped template:
4
+ *
5
+ * bunx incanto-new my-game # Beacon Isle (3D flagship)
6
+ * bunx incanto-new my-game --template tps-3d # third-person shooter
7
+ * bunx incanto-new --list
8
+ *
9
+ * Copies the template, names the package after the directory, prints the
10
+ * three commands that get you playing. Templates are real npm consumers —
11
+ * no monorepo, no aliases.
12
+ */
13
+ import { cpSync, existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
14
+ import { basename, dirname, join, resolve } from 'node:path';
15
+ import { fileURLToPath } from 'node:url';
16
+
17
+ const PKG = join(dirname(fileURLToPath(import.meta.url)), '..');
18
+ const TEMPLATES_DIR = join(PKG, 'templates-app');
19
+
20
+ const DESCRIPTIONS = {
21
+ 'beacon-isle-3d':
22
+ '3D island action-adventure (the flagship): generated world, quest NPC, terrain-nav enemies, melee',
23
+ 'village-quest-3d': '3D quest vignette: dialogue, scene transitions, patrol AI, sword combat',
24
+ 'tps-3d': 'third-person arena shooter: GLB soldier, hitscan rifle, enemy waves',
25
+ };
26
+
27
+ function listTemplates() {
28
+ if (!existsSync(TEMPLATES_DIR)) return [];
29
+ return readdirSync(TEMPLATES_DIR, { withFileTypes: true })
30
+ .filter((e) => e.isDirectory())
31
+ .map((e) => e.name)
32
+ .sort();
33
+ }
34
+
35
+ const argv = process.argv.slice(2);
36
+ if (argv.includes('--list') || argv.includes('-l')) {
37
+ for (const t of listTemplates()) {
38
+ console.log(` ${t.padEnd(20)} ${DESCRIPTIONS[t] ?? ''}`);
39
+ }
40
+ process.exit(0);
41
+ }
42
+
43
+ let target;
44
+ let template = 'beacon-isle-3d';
45
+ for (let i = 0; i < argv.length; i++) {
46
+ if (argv[i] === '--template' || argv[i] === '-t') template = argv[++i];
47
+ else if (!argv[i].startsWith('-') && !target) target = argv[i];
48
+ }
49
+
50
+ if (!target) {
51
+ console.error('usage: incanto-new <dir> [--template <name>] | --list');
52
+ process.exit(1);
53
+ }
54
+
55
+ const templates = listTemplates();
56
+ if (!templates.includes(template)) {
57
+ console.error(`unknown template '${template}'. Available: ${templates.join(', ')}`);
58
+ process.exit(1);
59
+ }
60
+
61
+ const dest = resolve(process.cwd(), target);
62
+ if (existsSync(dest)) {
63
+ console.error(`refusing to scaffold: '${dest}' already exists.`);
64
+ process.exit(1);
65
+ }
66
+
67
+ cpSync(join(TEMPLATES_DIR, template), dest, { recursive: true });
68
+
69
+ const pkgPath = join(dest, 'package.json');
70
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
71
+ pkg.name = basename(dest)
72
+ .toLowerCase()
73
+ .replace(/[^a-z0-9-]/g, '-');
74
+ writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
75
+
76
+ console.log(`
77
+ ${template} → ${target}
78
+
79
+ cd ${target}
80
+ bun install # or: npm install
81
+ bun run dev # play it
82
+ bun run verify # prove it plays, headlessly
83
+ bun run check # validate the scene JSON
84
+
85
+ Vibe-coding? Install the agent skills too:
86
+ bunx incanto-skills claude # or: opencode
87
+ `);
package/dist/2d.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { s as JsonObject } from "./schema-CcoWb32N.js";
2
- import { $ as Node, C as RendererStats, S as GameStats, b as Scheduler, l as PropSchema, n as BehaviorCtor, v as Engine, w as Scene$1 } from "./behavior-Bod1AyJS.js";
3
- import { t as LoadSceneOptions } from "./loader-BcUDfNHn.js";
2
+ import { $ as Node, C as RendererStats, S as GameStats, b as Scheduler, l as PropSchema, n as BehaviorCtor, v as Engine, w as Scene$1 } from "./behavior-CPibUfnH.js";
3
+ import { t as LoadSceneOptions } from "./loader-DILt9PGC.js";
4
4
  import { t as ParticleSim } from "./particle-sim-CwJ5rI_P.js";
5
5
  import { Group, Mesh, Object3D, Scene, Texture } from "three";
6
6
  import * as RapierNs from "@dimforge/rapier2d-compat";
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-C_xf4gm9.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-BD6zgrv_.js";
4
- import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-B6D864oZ.js";
2
+ import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-Ct86zczq.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-Djwckzgx.js";
4
+ import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-BiIdl51r.js";
5
5
  //#region src/2d/library-sprite.ts
6
6
  /**
7
7
  * Turn a library sprite-animation JSON into a scene-ready spritesheet asset
package/dist/3d.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { s as JsonObject } from "./schema-CcoWb32N.js";
2
- import { $ as Node, C as RendererStats, S as GameStats, b as Scheduler, l as PropSchema, n as BehaviorCtor, v as Engine, w as Scene$1 } from "./behavior-Bod1AyJS.js";
3
- import { t as LoadSceneOptions } from "./loader-BcUDfNHn.js";
2
+ import { $ as Node, C as RendererStats, S as GameStats, b as Scheduler, l as PropSchema, n as BehaviorCtor, v as Engine, w as Scene$1 } from "./behavior-CPibUfnH.js";
3
+ import { t as LoadSceneOptions } from "./loader-DILt9PGC.js";
4
4
  import { t as ParticleSim } from "./particle-sim-CwJ5rI_P.js";
5
- import { n as PathGrid, s as SpatialPose } from "./pathfinding-BSiXjd6W.js";
5
+ import { n as PathGrid, s as SpatialPose } from "./pathfinding-RWYkNKx9.js";
6
6
  import { AnimationClip, BufferGeometry, Color, DirectionalLight, InstancedMesh, MeshPhysicalMaterial, Object3D, PerspectiveCamera, Scene, Vector3, WebGLRenderer } from "three";
7
7
  import { VRM } from "@pixiv/three-vrm";
8
8
  import { Sky } from "three/examples/jsm/objects/Sky.js";
@@ -618,6 +618,21 @@ declare class Environment3D {
618
618
  dispose(): void;
619
619
  }
620
620
  //#endregion
621
+ //#region src/3d/environment-runtime.d.ts
622
+ /**
623
+ * Live environment editing — the renderer re-applies `scene.environment`
624
+ * every frame (cheap when unchanged), so changing the LOOK at runtime is
625
+ * just writing that object. This helper does it safely:
626
+ *
627
+ * setEnvironment3D(engine, { sky: { elevationDeg: 4 }, exposure: 0.8 });
628
+ * setEnvironment3D(engine, { fog: null }); // null DELETES a key
629
+ *
630
+ * - one-level deep merge (patching `sky.elevationDeg` keeps the other sky keys)
631
+ * - hard-validates the merged result NOW (in your call stack), so a bad patch
632
+ * throws where you wrote it — never inside the render loop
633
+ */
634
+ declare function setEnvironment3D(engine: Engine, patch: JsonObject): void;
635
+ //#endregion
621
636
  //#region src/3d/nodes/billboard-3d.d.ts
622
637
  /** Valid `Billboard3D.mode` values — drives the prop options AND validateJson. */
623
638
  declare const BILLBOARD_GROUP_MODES: readonly ["screen", "y", "none"];
@@ -692,6 +707,37 @@ declare class BoneAttachment3D extends Node3D {
692
707
  override free(): void;
693
708
  }
694
709
  //#endregion
710
+ //#region src/3d/nodes/bone-look-at-3d.d.ts
711
+ /**
712
+ * Look-at IK for one bone — the character's head (or chest, or turret) turns
713
+ * toward a target node ON TOP of whatever the animation is doing. Runs after
714
+ * the mixer each rendered frame, blends in/out smoothly, and DISENGAGES when
715
+ * the target leaves the comfort cone (no owl necks).
716
+ *
717
+ * { "name": "HeadTrack", "type": "BoneLookAt3D",
718
+ * "props": { "target": "../Skin", "bone": "Head", "lookAt": "%Player" } }
719
+ *
720
+ * `forwardAxis` names the bone's local facing axis (mixamo heads face +z,
721
+ * the default). Purely visual — headless it's a no-op.
722
+ */
723
+ declare class BoneLookAt3D extends Node3D {
724
+ static override readonly typeName: string;
725
+ static override readonly props: PropSchema;
726
+ target: string;
727
+ bone: string;
728
+ lookAt: string;
729
+ maxAngleDeg: number;
730
+ weight: number;
731
+ forwardAxis: string;
732
+ private boneObj;
733
+ private lookedUpFor;
734
+ /** 0..1 engage blend — eases in/out so tracking never snaps. */
735
+ private engage;
736
+ /** Test hook. */
737
+ get attachedBone(): Object3D | null;
738
+ _onRender3D(_ctx: RenderContext3D): void;
739
+ }
740
+ //#endregion
695
741
  //#region src/3d/nodes/camera-3d.d.ts
696
742
  /**
697
743
  * A perspective camera. Mark exactly one camera `current: true`; with none
@@ -842,9 +888,13 @@ declare class Flowers3D extends Node3D {
842
888
  clustering: number;
843
889
  /** Gentle head-bob wind strength — 0 holds still. */
844
890
  sway: number;
845
- /** Drape each plant onto a Terrain3D's surface so flowers root on the ground
846
- * instead of a flat plane (lets ONE bed cover rolling terrain). */
847
- drape: boolean;
891
+ /**
892
+ * null (the default) is AUTO: whenever the scene has a Terrain3D, instances
893
+ * root on it — flat ground behaves as before, rolling terrain just works.
894
+ * true forces it (keeps retrying until a terrain appears), false disables
895
+ * draping entirely.
896
+ */
897
+ drape: boolean | null;
848
898
  /** Drape target: a node path to the Terrain3D. Empty = auto-find the first
849
899
  * Terrain3D in the tree (the zero-config default when `drape` is on). */
850
900
  terrain: string;
@@ -979,9 +1029,14 @@ declare class Foliage3D extends Node3D implements SunConsumer3D {
979
1029
  flowers: number;
980
1030
  /** Placement seed — the field is identical across runs and machines. */
981
1031
  seed: number;
982
- /** Drape each instance onto a Terrain3D's surface so blades root on the
983
- * ground instead of a flat plane (lets ONE field cover rolling terrain). */
984
- drape: boolean;
1032
+ /**
1033
+ * Drape each instance onto a Terrain3D's surface so blades root on the
1034
+ * ground instead of a flat plane. null (the default) is AUTO: whenever the
1035
+ * scene has a Terrain3D, instances root on it — flat ground behaves as
1036
+ * before, rolling terrain just works. true forces it (keeps retrying until
1037
+ * a terrain appears), false disables draping entirely.
1038
+ */
1039
+ drape: boolean | null;
985
1040
  /** Drape target: a node path to the Terrain3D. Empty = auto-find the first
986
1041
  * Terrain3D in the tree (the zero-config default when `drape` is on). */
987
1042
  terrain: string;
@@ -1015,6 +1070,8 @@ declare class Foliage3D extends Node3D implements SunConsumer3D {
1015
1070
  /** @internal Every InstancedMesh of the field: [quads] or [quads, quads90°]. */
1016
1071
  _fields(): InstancedMesh[];
1017
1072
  override update(dt: number): void;
1073
+ /** Wind time/strength + the ≤4 character-bend slots (no-op before first build). */
1074
+ private writeAnimationUniforms;
1018
1075
  override _syncObject3D(): void;
1019
1076
  /**
1020
1077
  * @internal Environment-sky sun hand-off (see {@link SunConsumer3D}): the
@@ -1076,73 +1133,6 @@ declare class Foliage3D extends Node3D implements SunConsumer3D {
1076
1133
  override free(): void;
1077
1134
  }
1078
1135
  //#endregion
1079
- //#region src/3d/nodes/joint-3d.d.ts
1080
- type JointType3D = "fixed" | "spherical" | "rope" | "spring";
1081
- /**
1082
- * A physics joint linking its PARENT body to `target` (a node path to the
1083
- * other body). Godot-style placement: the joint lives as a child of body A.
1084
- *
1085
- * { "name": "Hinge", "type": "Joint3D",
1086
- * "props": { "type": "spherical", "target": "%Anchor", "anchor": [0, -20] } }
1087
- *
1088
- * Types: `fixed` welds the bodies rigidly · `spherical` is a ball joint at the
1089
- * anchors · `rope` caps the anchor distance at `length` (m; 0 = measured at
1090
- * creation) · `spring` pulls toward `length` with `stiffness`/`damping`.
1091
- * Anchors are LOCAL meter offsets on each body.
1092
- */
1093
- declare class Joint3D extends Node3D {
1094
- static override readonly typeName: string;
1095
- static override readonly props: PropSchema;
1096
- type: JointType3D;
1097
- target: string;
1098
- anchor: number[];
1099
- targetAnchor: number[];
1100
- /** rope/spring rest length in m; 0 = measure body distance at creation. */
1101
- length: number;
1102
- stiffness: number;
1103
- damping: number;
1104
- override onEnterTree(): void;
1105
- /** @internal The two bodies, resolved (throws on a bad target at step time). */
1106
- _resolveBodies(): {
1107
- a: PhysicsBody3D;
1108
- b: PhysicsBody3D;
1109
- };
1110
- }
1111
- //#endregion
1112
- //#region src/3d/nodes/lights-3d.d.ts
1113
- /** Sun-style light. Direction comes from the node's rotation. */
1114
- declare class DirectionalLight3D extends Node3D {
1115
- static override readonly typeName: string;
1116
- static override readonly props: PropSchema;
1117
- color: string;
1118
- intensity: number;
1119
- castShadow: boolean;
1120
- /** Half-extent of the directional shadow frustum (template default ±75). */
1121
- shadowArea: number;
1122
- shadowMapSize: number;
1123
- /**
1124
- * Re-center the shadow frustum on the camera every frame. A directional sun's
1125
- * shadow map covers a fixed ortho box; in a big roaming world that box must be
1126
- * huge (and so low-resolution that the player's own shadow nearly vanishes).
1127
- * With this on, a SMALL `shadowArea` tracks the camera, so contact shadows stay
1128
- * crisp wherever you go. The renderer supplies the camera position.
1129
- */
1130
- shadowFollowsCamera: boolean;
1131
- protected override _createObject3D(): Object3D;
1132
- override _syncObject3D(): void;
1133
- }
1134
- /** Point light with a range (Godot's OmniLight3D). */
1135
- declare class OmniLight3D extends Node3D {
1136
- static override readonly typeName: string;
1137
- static override readonly props: PropSchema;
1138
- color: string;
1139
- intensity: number;
1140
- /** 0 = unlimited (three `distance` semantics). */
1141
- range: number;
1142
- protected override _createObject3D(): Object3D;
1143
- override _syncObject3D(): void;
1144
- }
1145
- //#endregion
1146
1136
  //#region src/3d/nodes/mesh-instance-3d.d.ts
1147
1137
  type MeshKind = "box" | "sphere" | "capsule" | "plane" | "cylinder" | "gem";
1148
1138
  interface MeshMaterialProps {
@@ -1220,6 +1210,109 @@ declare class MeshInstance3D extends Node3D {
1220
1210
  override free(): void;
1221
1211
  }
1222
1212
  //#endregion
1213
+ //#region src/3d/nodes/instanced-mesh-3d.d.ts
1214
+ /**
1215
+ * Hundreds of copies of one mesh in ONE draw call — scattered rocks, fence
1216
+ * posts, pillars, crates, gravestones. Same `mesh`/`size`/`material` surface
1217
+ * as MeshInstance3D; `transforms` places the copies:
1218
+ *
1219
+ * { "name": "Rocks", "type": "InstancedMesh3D",
1220
+ * "props": { "mesh": "gem", "size": [0.7, 0.5, 0.7],
1221
+ * "material": { "color": "#8a8f98", "roughness": 0.9, "flatShading": true },
1222
+ * "transforms": [[12, 0.2, -8, 40, 1.3], [-6, 0.1, 14, 210, 0.8]] } }
1223
+ *
1224
+ * Each row is `[x, y, z, yawDeg?, scale?]` (yaw 0 and scale 1 when omitted) —
1225
+ * dense enough to generate hundreds inline. REPLACE the array to update
1226
+ * (mutations are not watched).
1227
+ */
1228
+ declare class InstancedMesh3D extends Node3D {
1229
+ static override readonly typeName: string;
1230
+ static override readonly props: PropSchema;
1231
+ mesh: string;
1232
+ size: number[];
1233
+ material: MeshMaterialProps;
1234
+ castShadow: boolean;
1235
+ receiveShadow: boolean;
1236
+ private _transforms;
1237
+ private transformsDirty;
1238
+ get transforms(): number[][];
1239
+ set transforms(value: number[][]);
1240
+ private instanced;
1241
+ private builtKey;
1242
+ static validateJson(node: Node): void;
1243
+ /** Test hook: the live instance count. */
1244
+ get instanceCount(): number;
1245
+ override _syncObject3D(alpha?: number): void;
1246
+ override free(): void;
1247
+ }
1248
+ //#endregion
1249
+ //#region src/3d/nodes/joint-3d.d.ts
1250
+ type JointType3D = "fixed" | "spherical" | "rope" | "spring";
1251
+ /**
1252
+ * A physics joint linking its PARENT body to `target` (a node path to the
1253
+ * other body). Godot-style placement: the joint lives as a child of body A.
1254
+ *
1255
+ * { "name": "Hinge", "type": "Joint3D",
1256
+ * "props": { "type": "spherical", "target": "%Anchor", "anchor": [0, -20] } }
1257
+ *
1258
+ * Types: `fixed` welds the bodies rigidly · `spherical` is a ball joint at the
1259
+ * anchors · `rope` caps the anchor distance at `length` (m; 0 = measured at
1260
+ * creation) · `spring` pulls toward `length` with `stiffness`/`damping`.
1261
+ * Anchors are LOCAL meter offsets on each body.
1262
+ */
1263
+ declare class Joint3D extends Node3D {
1264
+ static override readonly typeName: string;
1265
+ static override readonly props: PropSchema;
1266
+ type: JointType3D;
1267
+ target: string;
1268
+ anchor: number[];
1269
+ targetAnchor: number[];
1270
+ /** rope/spring rest length in m; 0 = measure body distance at creation. */
1271
+ length: number;
1272
+ stiffness: number;
1273
+ damping: number;
1274
+ override onEnterTree(): void;
1275
+ /** @internal The two bodies, resolved (throws on a bad target at step time). */
1276
+ _resolveBodies(): {
1277
+ a: PhysicsBody3D;
1278
+ b: PhysicsBody3D;
1279
+ };
1280
+ }
1281
+ //#endregion
1282
+ //#region src/3d/nodes/lights-3d.d.ts
1283
+ /** Sun-style light. Direction comes from the node's rotation. */
1284
+ declare class DirectionalLight3D extends Node3D {
1285
+ static override readonly typeName: string;
1286
+ static override readonly props: PropSchema;
1287
+ color: string;
1288
+ intensity: number;
1289
+ castShadow: boolean;
1290
+ /** Half-extent of the directional shadow frustum (template default ±75). */
1291
+ shadowArea: number;
1292
+ shadowMapSize: number;
1293
+ /**
1294
+ * Re-center the shadow frustum on the camera every frame. A directional sun's
1295
+ * shadow map covers a fixed ortho box; in a big roaming world that box must be
1296
+ * huge (and so low-resolution that the player's own shadow nearly vanishes).
1297
+ * With this on, a SMALL `shadowArea` tracks the camera, so contact shadows stay
1298
+ * crisp wherever you go. The renderer supplies the camera position.
1299
+ */
1300
+ shadowFollowsCamera: boolean;
1301
+ protected override _createObject3D(): Object3D;
1302
+ override _syncObject3D(): void;
1303
+ }
1304
+ /** Point light with a range (Godot's OmniLight3D). */
1305
+ declare class OmniLight3D extends Node3D {
1306
+ static override readonly typeName: string;
1307
+ static override readonly props: PropSchema;
1308
+ color: string;
1309
+ intensity: number;
1310
+ /** 0 = unlimited (three `distance` semantics). */
1311
+ range: number;
1312
+ protected override _createObject3D(): Object3D;
1313
+ override _syncObject3D(): void;
1314
+ }
1315
+ //#endregion
1223
1316
  //#region src/3d/nodes/loft-mesh-3d.d.ts
1224
1317
  /**
1225
1318
  * One station of a loft: the hull's cross-section at local `z`.
@@ -1293,6 +1386,16 @@ declare class ModelInstance3D extends Node3D {
1293
1386
  castShadow: boolean;
1294
1387
  /** false = play the clip once, then emit `animationFinished`. */
1295
1388
  animationLoop: boolean;
1389
+ /**
1390
+ * Two-layer animation: play this clip on the UPPER BODY ONLY (the
1391
+ * `upperBodyRoot` bone subtree) while `animation` keeps driving the rest —
1392
+ * attack while running, wave while walking. One-shot by default
1393
+ * (`animationUpperLoop: false`): finishes, emits `animationFinished` with
1394
+ * this key, and auto-clears back to ''.
1395
+ */
1396
+ animationUpper: string;
1397
+ animationUpperLoop: boolean;
1398
+ upperBodyRoot: string;
1296
1399
  receiveShadow: boolean;
1297
1400
  /** Hex colour multiplied into every material — RESKIN one shared GLB into many
1298
1401
  * variants (e.g. a sickly-green zombie from the base human). '' = untinted. */
@@ -1311,6 +1414,12 @@ declare class ModelInstance3D extends Node3D {
1311
1414
  private mixer;
1312
1415
  private playing;
1313
1416
  private currentAction;
1417
+ private playingUpper;
1418
+ private upperAction;
1419
+ /** Which variant the BASE action is playing ('lower' while a layer is on). */
1420
+ private baseMode;
1421
+ /** Masked-clip cache: source clip uuid + layer root → {upper, lower}. */
1422
+ private readonly maskCache;
1314
1423
  /** action → the `animation` key that played it, so `animationFinished` reports
1315
1424
  * the clip that ACTUALLY finished (a crossfaded-away one-shot can finish a few
1316
1425
  * frames after `this.animation` already moved on). */
@@ -1352,7 +1461,15 @@ declare class ModelInstance3D extends Node3D {
1352
1461
  private applyMaterialMods;
1353
1462
  /** Re-apply every queued named-node pose onto the mounted instance. */
1354
1463
  private applyPoses;
1464
+ /** Resolve a clip ref: embedded name → '$asset' / URL (VRM-retargeted when
1465
+ * needed). 'loading' = asset still fetching, try again next frame. */
1466
+ private resolveClip;
1467
+ /** Masked upper/lower variants of a clip for two-layer playback (cached). */
1468
+ private layerVariants;
1469
+ private upperLayerActive;
1355
1470
  private syncAnimation;
1471
+ /** The upper-body layer: masked clip on the `upperBodyRoot` subtree. */
1472
+ private syncUpperAnimation;
1356
1473
  override update(dt: number): void;
1357
1474
  override onExitTree(): void;
1358
1475
  private unmount;
@@ -1715,11 +1832,14 @@ declare class Tree3D extends Node3D {
1715
1832
  /** Let leaves cast shadows. false keeps trunk/branch shadows but drops the
1716
1833
  * expensive alpha-cutout leaf shadow pass (the dappled floor) for big FPS. */
1717
1834
  leafShadows: boolean;
1718
- /** Drape the grove over a Terrain3D: each scattered instance roots at the
1719
- * ground height under it (not the node's single Y), so a patch on rolling or
1720
- * carved terrain never floats/buries. No effect on a count:1 tree placed by
1721
- * hand unless it sits off the ground. */
1722
- drape: boolean;
1835
+ /**
1836
+ * Drape the grove over a Terrain3D: each scattered instance roots at the
1837
+ * ground height under it (not the node's single Y), so a patch on rolling
1838
+ * or carved terrain never floats/buries. null (the default) is AUTO:
1839
+ * whenever the scene has a Terrain3D the grove drapes onto it. true forces
1840
+ * it (keeps retrying until a terrain appears), false disables draping.
1841
+ */
1842
+ drape: boolean | null;
1723
1843
  /** Node path to the Terrain3D to drape onto ('' = auto-find the first one). */
1724
1844
  terrain: string;
1725
1845
  /** Resolved drape target + the grove's world position, set per rebuild. */
@@ -2259,4 +2379,21 @@ interface TerrainNavOptions {
2259
2379
  }
2260
2380
  declare function buildTerrainNav(terrain: HeightSampler, opts?: TerrainNavOptions): TerrainNav;
2261
2381
  //#endregion
2262
- export { Area3D, AssetStore3D, Billboard3D, type BillboardGroupMode, BoneAttachment3D, Camera3D, CharacterBody3D, CharacterController3D, type CreateGame3DOptions, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, Environment3D, type Environment3DConfig, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, type FlowerVariety, Flowers3D, type FogEnvironment, Foliage3D, type FoliageKind, type FoliageStyle, type Game3D, type HeightSampler, type Heightmap, type HeightmapOptions, Joint3D, type JointType3D, LoftMesh3D, type LoftSection, MeshInstance3D, type MeshKind, type MeshMaterialProps, type ModelEntry, ModelInstance3D, Node3D, OmniLight3D, Particles3D, Physics3D, type Physics3DOptions, PhysicsBody3D, QUARTER_PITCH, type RenderContext3D, type RenderHook3D, Renderer3D, type Renderer3DOptions, type RigView, RigidBody3D, type Ripple, type ShadowsEnvironment, type SkyEnvironment, StaticBody3D, type SunConsumer3D, type SyncOptions, type SyncResult, TERRAIN_THEMES, Terrain3D, type TerrainLayer, type TerrainNav, type TerrainNavOptions, type TerrainTheme, Trail3D, Tree3D, type TreeTier, type TreeType, VOXEL_PALETTE, type VoxelBlock, VoxelGrid3D, WATER_MAX_RIPPLES, Water3D, buildHeightmap, buildTerrainNav, cameraRelative, createGame3D, enablePhysics3D, horizonColorFromSky, keyboardIntensity, movementState, parseEnvironment3D, registerNodes3D, resolveFlowerDensity, rigPose, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers };
2382
+ //#region src/3d/terrain-nav-debug.d.ts
2383
+ /**
2384
+ * See what the enemies see: one node that paints every WALKABLE nav cell as a
2385
+ * translucent quad hugging the terrain surface. Add it while tuning
2386
+ * `cellSize`/`maxSlopeDeg`, drop it when the routes look right:
2387
+ *
2388
+ * if (DEBUG_NAV) this.node.addChild(createNavDebugNode(this.nav));
2389
+ *
2390
+ * One InstancedMesh — a few thousand cells render as a single draw call.
2391
+ */
2392
+ declare function createNavDebugNode(nav: TerrainNav, opts?: {
2393
+ color?: string;
2394
+ opacity?: number;
2395
+ lift?: number;
2396
+ name?: string;
2397
+ }): InstancedMesh3D;
2398
+ //#endregion
2399
+ export { Area3D, AssetStore3D, Billboard3D, type BillboardGroupMode, BoneAttachment3D, BoneLookAt3D, Camera3D, CharacterBody3D, CharacterController3D, type CreateGame3DOptions, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, Environment3D, type Environment3DConfig, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, type FlowerVariety, Flowers3D, type FogEnvironment, Foliage3D, type FoliageKind, type FoliageStyle, type Game3D, type HeightSampler, type Heightmap, type HeightmapOptions, InstancedMesh3D, Joint3D, type JointType3D, LoftMesh3D, type LoftSection, MeshInstance3D, type MeshKind, type MeshMaterialProps, type ModelEntry, ModelInstance3D, Node3D, OmniLight3D, Particles3D, Physics3D, type Physics3DOptions, PhysicsBody3D, QUARTER_PITCH, type RenderContext3D, type RenderHook3D, Renderer3D, type Renderer3DOptions, type RigView, RigidBody3D, type Ripple, type ShadowsEnvironment, type SkyEnvironment, StaticBody3D, type SunConsumer3D, type SyncOptions, type SyncResult, TERRAIN_THEMES, Terrain3D, type TerrainLayer, type TerrainNav, type TerrainNavOptions, type TerrainTheme, Trail3D, Tree3D, type TreeTier, type TreeType, VOXEL_PALETTE, type VoxelBlock, VoxelGrid3D, WATER_MAX_RIPPLES, Water3D, buildHeightmap, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, enablePhysics3D, horizonColorFromSky, keyboardIntensity, movementState, parseEnvironment3D, registerNodes3D, resolveFlowerDensity, rigPose, setEnvironment3D, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers };
package/dist/3d.js CHANGED
@@ -1,7 +1,35 @@
1
- import { a as Environment3D, c as sunDirectionFromElevationAzimuth, i as syncTree, l as sunDirectionFromSky, o as horizonColorFromSky, r as Renderer3D, s as parseEnvironment3D, t as createGame3D, u as AssetStore3D } from "./create-game-B2fewJUy.js";
2
- import { A as PhysicsBody3D, C as Terrain3D, D as Joint3D, E as terrainThemeLayers, F as QUARTER_PITCH, I as cameraRelative, L as keyboardIntensity, M as StaticBody3D, N as Node3D, O as Area3D, R as movementState, S as Billboard3D, T as TERRAIN_THEMES, _ as resolveFlowerDensity, a as VoxelGrid3D, b as Camera3D, c as Particles3D, d as MeshInstance3D, f as DirectionalLight3D, g as Flowers3D, h as DENSITY_PRESETS, i as VOXEL_PALETTE, j as RigidBody3D, k as CharacterBody3D, l as ModelInstance3D, m as Foliage3D, n as Water3D, o as Tree3D, p as OmniLight3D, r as WATER_MAX_RIPPLES, s as Trail3D, t as registerNodes3D, u as LoftMesh3D, v as FLOWER_VARIETIES, w as DEFAULT_TERRAIN_TEXTURE_BASE, x as BoneAttachment3D, y as CharacterController3D, z as rigPose } from "./register-ysLR3WQS.js";
1
+ import { t as IncantoError } from "./errors-BpWbnbb_.js";
2
+ import { a as Environment3D, c as sunDirectionFromElevationAzimuth, i as syncTree, l as sunDirectionFromSky, o as horizonColorFromSky, r as Renderer3D, s as parseEnvironment3D, t as createGame3D, u as AssetStore3D } from "./create-game-OSntcIiM.js";
3
+ import { A as Area3D, B as movementState, C as BoneAttachment3D, D as TERRAIN_THEMES, E as DEFAULT_TERRAIN_TEXTURE_BASE, F as Node3D, L as QUARTER_PITCH, M as PhysicsBody3D, N as RigidBody3D, O as terrainThemeLayers, P as StaticBody3D, R as cameraRelative, S as BoneLookAt3D, T as Terrain3D, V as rigPose, _ as Flowers3D, a as VoxelGrid3D, b as CharacterController3D, c as Particles3D, d as DirectionalLight3D, f as OmniLight3D, g as DENSITY_PRESETS, h as Foliage3D, i as VOXEL_PALETTE, j as CharacterBody3D, k as Joint3D, l as ModelInstance3D, m as MeshInstance3D, n as Water3D, o as Tree3D, p as InstancedMesh3D, r as WATER_MAX_RIPPLES, s as Trail3D, t as registerNodes3D, u as LoftMesh3D, v as resolveFlowerDensity, w as Billboard3D, x as Camera3D, y as FLOWER_VARIETIES, z as keyboardIntensity } from "./register-C9-16x_t.js";
3
4
  import { n as splatWeights, t as buildHeightmap } from "./heightmap-CroQPEER.js";
4
- import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-RLNaxRyw.js";
5
+ import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-D_kUdOjr.js";
6
+ //#region src/3d/environment-runtime.ts
7
+ /**
8
+ * Live environment editing — the renderer re-applies `scene.environment`
9
+ * every frame (cheap when unchanged), so changing the LOOK at runtime is
10
+ * just writing that object. This helper does it safely:
11
+ *
12
+ * setEnvironment3D(engine, { sky: { elevationDeg: 4 }, exposure: 0.8 });
13
+ * setEnvironment3D(engine, { fog: null }); // null DELETES a key
14
+ *
15
+ * - one-level deep merge (patching `sky.elevationDeg` keeps the other sky keys)
16
+ * - hard-validates the merged result NOW (in your call stack), so a bad patch
17
+ * throws where you wrote it — never inside the render loop
18
+ */
19
+ function setEnvironment3D(engine, patch) {
20
+ const scene = engine.scene;
21
+ if (!scene) throw new IncantoError("BAD_FORMAT", "setEnvironment3D: the engine has no scene.");
22
+ const merged = { ...scene.environment ?? {} };
23
+ for (const [key, value] of Object.entries(patch)) if (value === null) delete merged[key];
24
+ else if (typeof value === "object" && !Array.isArray(value) && typeof merged[key] === "object" && merged[key] !== null && !Array.isArray(merged[key])) merged[key] = {
25
+ ...merged[key],
26
+ ...value
27
+ };
28
+ else merged[key] = value;
29
+ parseEnvironment3D(merged);
30
+ scene.environment = merged;
31
+ }
32
+ //#endregion
5
33
  //#region src/3d/terrain-nav.ts
6
34
  function buildTerrainNav(terrain, opts) {
7
35
  const cellSize = opts?.cellSize ?? 2;
@@ -71,4 +99,46 @@ const CORNERS = [
71
99
  [-1, -1]
72
100
  ];
73
101
  //#endregion
74
- export { Area3D, AssetStore3D, Billboard3D, BoneAttachment3D, Camera3D, CharacterBody3D, CharacterController3D, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, Environment3D, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, Flowers3D, Foliage3D, Joint3D, LoftMesh3D, MeshInstance3D, ModelInstance3D, Node3D, OmniLight3D, Particles3D, Physics3D, PhysicsBody3D, QUARTER_PITCH, Renderer3D, RigidBody3D, StaticBody3D, TERRAIN_THEMES, Terrain3D, Trail3D, Tree3D, VOXEL_PALETTE, VoxelGrid3D, WATER_MAX_RIPPLES, Water3D, buildHeightmap, buildTerrainNav, cameraRelative, createGame3D, enablePhysics3D, horizonColorFromSky, keyboardIntensity, movementState, parseEnvironment3D, registerNodes3D, resolveFlowerDensity, rigPose, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers };
102
+ //#region src/3d/terrain-nav-debug.ts
103
+ /**
104
+ * See what the enemies see: one node that paints every WALKABLE nav cell as a
105
+ * translucent quad hugging the terrain surface. Add it while tuning
106
+ * `cellSize`/`maxSlopeDeg`, drop it when the routes look right:
107
+ *
108
+ * if (DEBUG_NAV) this.node.addChild(createNavDebugNode(this.nav));
109
+ *
110
+ * One InstancedMesh — a few thousand cells render as a single draw call.
111
+ */
112
+ function createNavDebugNode(nav, opts) {
113
+ const node = new InstancedMesh3D(opts?.name ?? "__navDebug");
114
+ node.mesh = "plane";
115
+ node.size = [
116
+ nav.cellSize * .9,
117
+ 1,
118
+ nav.cellSize * .9
119
+ ];
120
+ node.material = {
121
+ color: opts?.color ?? "#37ff8b",
122
+ emissive: opts?.color ?? "#37ff8b",
123
+ emissiveIntensity: .5,
124
+ opacity: opts?.opacity ?? .3,
125
+ roughness: 1,
126
+ depthWrite: false
127
+ };
128
+ node.renderOrder = 50;
129
+ const lift = opts?.lift ?? .08;
130
+ const rows = [];
131
+ for (let cy = 0; cy < nav.grid.height; cy++) for (let cx = 0; cx < nav.grid.width; cx++) {
132
+ if (nav.grid.solid(cx, cy)) continue;
133
+ const [x, y, z] = nav.toWorld(cx, cy);
134
+ rows.push([
135
+ x,
136
+ y + lift,
137
+ z
138
+ ]);
139
+ }
140
+ node.transforms = rows;
141
+ return node;
142
+ }
143
+ //#endregion
144
+ export { Area3D, AssetStore3D, Billboard3D, BoneAttachment3D, BoneLookAt3D, Camera3D, CharacterBody3D, CharacterController3D, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, Environment3D, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, Flowers3D, Foliage3D, InstancedMesh3D, Joint3D, LoftMesh3D, MeshInstance3D, ModelInstance3D, Node3D, OmniLight3D, Particles3D, Physics3D, PhysicsBody3D, QUARTER_PITCH, Renderer3D, RigidBody3D, StaticBody3D, TERRAIN_THEMES, Terrain3D, Trail3D, Tree3D, VOXEL_PALETTE, VoxelGrid3D, WATER_MAX_RIPPLES, Water3D, buildHeightmap, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, enablePhysics3D, horizonColorFromSky, keyboardIntensity, movementState, parseEnvironment3D, registerNodes3D, resolveFlowerDensity, rigPose, setEnvironment3D, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers };
@@ -693,8 +693,10 @@ declare class Scene {
693
693
  readonly dimension: "2d" | "3d" | undefined;
694
694
  readonly root: Node;
695
695
  readonly tree: SceneTree;
696
- /** Scene-level rendering environment (read by renderer adapters). */
697
- readonly environment: JsonObject | undefined;
696
+ /** Scene-level rendering environment (read by renderer adapters EVERY
697
+ * frame, cheap when unchanged) — mutable so runtime look changes
698
+ * (setEnvironment3D, DayNight) are just writes to this object. */
699
+ environment: JsonObject | undefined;
698
700
  /** Asset declarations (consumed by renderer/asset layers, `$key` references). */
699
701
  readonly assets: Record<string, JsonObject> | undefined;
700
702
  /** Named constant values (`{"@const": "NAME"}` prop references resolve to these). */
@@ -1,12 +1,12 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { _ as registerBehavior, n as loadScene, o as computeViewport, s as resolveViewport } from "./loader-B4OEXDZ8.js";
3
- import { l as AudioPlayer, u as Engine } from "./register-DJZXxwAn.js";
2
+ import { _ as registerBehavior, n as loadScene, o as computeViewport, s as resolveViewport } from "./loader-BZqOKfI2.js";
3
+ import { l as AudioPlayer, u as Engine } from "./register-nObreUQR.js";
4
4
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
5
5
  import { i as resolveRendering, n as attachTouchControls } from "./touch-031PxtCR.js";
6
- import { n as registerGameplayBehaviors } from "./gameplay-Dn3yidJw.js";
7
- import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-BD6zgrv_.js";
6
+ import { n as registerGameplayBehaviors } from "./gameplay-sSqrUcnz.js";
7
+ import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-Djwckzgx.js";
8
8
  import { t as debugSources } from "./debug-draw-CZmOYjL2.js";
9
- import { n as enablePhysics2D } from "./physics-2d-B6D864oZ.js";
9
+ import { n as enablePhysics2D } from "./physics-2d-BiIdl51r.js";
10
10
  import { Box3, BufferAttribute, BufferGeometry, Color, LineBasicMaterial, LineSegments, LinearFilter, NearestFilter, OrthographicCamera, Raycaster, SRGBColorSpace, Scene, TextureLoader, Vector2, Vector3, WebGLRenderer } from "three";
11
11
  //#region src/2d/assets.ts
12
12
  /**