incanto 0.51.0 → 0.52.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 (54) hide show
  1. package/dist/2d.d.ts +37 -2
  2. package/dist/2d.js +3 -3
  3. package/dist/3d.d.ts +3 -3
  4. package/dist/3d.js +4 -4
  5. package/dist/{behavior-rZNfzVbH.d.ts → behavior-uPEuZrUB.d.ts} +10 -0
  6. package/dist/{create-game-CkzKZ4v5.js → create-game-B_e9hJf7.js} +92 -10
  7. package/dist/{create-game-BNaOC3Px.js → create-game-CGnoypjL.js} +6 -6
  8. package/dist/debug.d.ts +1 -1
  9. package/dist/debug.js +1 -1
  10. package/dist/{duplicate-EybyYeyL.js → duplicate-B-OtSRFL.js} +1 -1
  11. package/dist/editor.js +1917 -1579
  12. package/dist/{environment-presets-C08pOC6H.js → environment-presets-DSZwsKPs.js} +3 -3
  13. package/dist/{gameplay-bStgtZBV.js → gameplay-B6jqvYeM.js} +6 -4
  14. package/dist/gameplay.d.ts +1 -1
  15. package/dist/gameplay.js +1 -1
  16. package/dist/index.d.ts +65 -5
  17. package/dist/index.js +7 -7
  18. package/dist/{loader-B2asghWa.js → loader-B-Gft32x.js} +32 -32
  19. package/dist/{loader-Dkbn56KC.d.ts → loader-B9iTqs27.d.ts} +1 -1
  20. package/dist/net.d.ts +15 -410
  21. package/dist/net.js +1 -822
  22. package/dist/{pathfinding-Bz34pvQD.d.ts → pathfinding-CAR9DjQQ.d.ts} +1 -1
  23. package/dist/{physics-2d-Ccq2L9R0.js → physics-2d-Dns-oZlE.js} +2 -2
  24. package/dist/{physics-3d-B2c5KNYh.js → physics-3d-BhI0ehpe.js} +3 -3
  25. package/dist/react.d.ts +1 -1
  26. package/dist/react.js +1 -1
  27. package/dist/{register-CGq-Hee8.js → register-DVwlnZAZ.js} +2 -2
  28. package/dist/{register-B_BaaGx-.js → register-Trx7WHnD.js} +3 -3
  29. package/dist/{registry-IyWCGe4q.js → registry-C7u42TID.js} +23 -1
  30. package/dist/{replay-DIP2_as4.d.ts → replay-BU1CCM15.d.ts} +1 -1
  31. package/dist/{replay-BgKxGcXH.js → replay-BicPOMX0.js} +195 -2
  32. package/dist/split-screen-CZ9ccBBQ.js +1267 -0
  33. package/dist/split-screen-paxkQs_q.d.ts +441 -0
  34. package/dist/{src-C3UwzYXl.js → src-5gbZO47I.js} +1 -1
  35. package/dist/{teardown-BKTCzLek.js → teardown-ks3d5W9n.js} +2 -1
  36. package/dist/{test-D2gRpk5V.js → test-DAojuFdb.js} +119 -22
  37. package/dist/test.d.ts +60 -5
  38. package/dist/test.js +3 -3
  39. package/dist/vite.js +2 -2
  40. package/editor/assets/{agent8-DbX_msaO.js → agent8-CCvckvbw.js} +1 -1
  41. package/editor/assets/{debug-C-kMxdl1.js → debug-CLNCOnbc.js} +1 -1
  42. package/editor/assets/{index-CUc1U7wm.js → index-Cb5Brupb.js} +99 -92
  43. package/editor/index.html +1 -1
  44. package/package.json +1 -1
  45. package/skills/incanto-assets.md +4 -1
  46. package/skills/incanto-editor.md +48 -11
  47. package/skills/incanto-gameplay-behaviors.md +14 -5
  48. package/skills/incanto-multiplayer.md +39 -3
  49. package/skills/incanto-verifying-your-game.md +56 -0
  50. package/templates/agent8-server.ts +79 -2
  51. package/templates-app/beacon-isle-3d/package.json +1 -1
  52. package/templates-app/tps-3d/package.json +1 -1
  53. package/templates-app/village-quest-3d/package.json +1 -1
  54. package/dist/register-CLVhzWcI.js +0 -374
package/dist/2d.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { Dt as Node, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, n as BehaviorCtor, w as GameStats } from "./behavior-rZNfzVbH.js";
1
+ import { Dt as Node, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, n as BehaviorCtor, w as GameStats } from "./behavior-uPEuZrUB.js";
2
2
  import { n as DiagnosticSink, t as EditorSwitchOptions } from "./editor-switch-DAvWQeld.js";
3
3
  import { i as SceneJson, s as JsonObject } from "./schema-CFeioQRE.js";
4
- import { t as LoadSceneOptions } from "./loader-Dkbn56KC.js";
4
+ import { t as LoadSceneOptions } from "./loader-B9iTqs27.js";
5
5
  import { n as AnimationEntry } from "./sprite-animation-CMr6f1K2.js";
6
6
  import { t as ParticleSim } from "./particle-sim-BzJ1yxoE.js";
7
7
  import { Group, Mesh, Object3D, Scene, Texture } from "three";
@@ -36,6 +36,19 @@ declare class AssetStore2D {
36
36
  constructor(loader?: (url: string, callbacks?: TextureLoadCallbacks) => Texture, engine?: DiagnosticSink | null);
37
37
  /** Load (or extend with) a scene's `assets` declarations. Hard-validates each entry. */
38
38
  load(assets: Record<string, JsonObject>): void;
39
+ /**
40
+ * Every declared asset that FAILED to load, `$ref` and url included.
41
+ *
42
+ * The 3D store has answered this since 0.32.0 — the 2D one only tracked a
43
+ * per-key status, which the console printed and nothing else could read. A
44
+ * 404'd texture is invisible, and "invisible" is the one symptom an author
45
+ * cannot tell apart from "I put it in the wrong place".
46
+ */
47
+ errors(): Array<{
48
+ ref: string;
49
+ url: string;
50
+ error: string;
51
+ }>;
39
52
  /** Load status of a declared asset KEY (no '$'), or undefined if unknown. */
40
53
  status(key: string): AssetStatus | undefined;
41
54
  getTexture(ref: string): Texture;
@@ -841,6 +854,8 @@ declare class Renderer2D {
841
854
  private syncSelectionOutline;
842
855
  private syncDebugLines;
843
856
  private render;
857
+ /** UI-pass extent from the last render — the space HUD nodes are posed in. */
858
+ private lastUi;
844
859
  private lastViewport;
845
860
  private lastView;
846
861
  /** The world view used by the LAST render (center/zoom/canvas size). */
@@ -863,6 +878,26 @@ declare class Renderer2D {
863
878
  * Hits resolve through `userData.incantoNode` and prefer higher renderOrder.
864
879
  */
865
880
  pick(sx: number, sy: number): Node | null;
881
+ private hit;
882
+ /** Does the UI pass draw this node (i.e. is it under a UILayer)? */
883
+ isUiNode(node: Node): boolean;
884
+ /**
885
+ * UI-space px → canvas px.
886
+ *
887
+ * A UILayer's children are posed in the UI pass's own space (origin top-left,
888
+ * `uiW × uiH`), NOT in world space — so mapping them with `screenFromWorld`
889
+ * puts them wherever the game camera happens to be looking.
890
+ */
891
+ screenFromUi(ux: number, uy: number): {
892
+ x: number;
893
+ y: number;
894
+ };
895
+ /** Canvas px → UI-space px (the inverse of `screenFromUi`). */
896
+ uiFromScreen(sx: number, sy: number): {
897
+ x: number;
898
+ y: number;
899
+ };
900
+ private uiView;
866
901
  /**
867
902
  * Canvas-pixel AABB of a node's rendered world-pass objects, or null when it
868
903
  * has no renderable extent (plain Nodes, empty containers).
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-CkzKZ4v5.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-B_BaaGx-.js";
4
- import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-Ccq2L9R0.js";
2
+ import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-B_e9hJf7.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-Trx7WHnD.js";
4
+ import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-Dns-oZlE.js";
5
5
  //#region src/2d/library-sprite.ts
6
6
  /**
7
7
  * What a `CharacterController2D`/`3D` will ask a skin to play, and the clip in
package/dist/3d.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- import { D as QualityCaps, Dt as Node, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, n as BehaviorCtor, w as GameStats } from "./behavior-rZNfzVbH.js";
1
+ import { D as QualityCaps, Dt as Node, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, n as BehaviorCtor, w as GameStats } from "./behavior-uPEuZrUB.js";
2
2
  import { n as DiagnosticSink, t as EditorSwitchOptions } from "./editor-switch-DAvWQeld.js";
3
3
  import { i as SceneJson$1, s as JsonObject } from "./schema-CFeioQRE.js";
4
- import { t as LoadSceneOptions } from "./loader-Dkbn56KC.js";
4
+ import { t as LoadSceneOptions } from "./loader-B9iTqs27.js";
5
5
  import { t as ParticleSim } from "./particle-sim-BzJ1yxoE.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-DZ70IY26.js";
7
- import { n as PathGrid, s as SpatialPose } from "./pathfinding-Bz34pvQD.js";
7
+ import { n as PathGrid, s as SpatialPose } from "./pathfinding-CAR9DjQQ.js";
8
8
  import { AnimationClip, AnimationMixer, BufferGeometry, Color, DirectionalLight, Group, InstancedMesh, Mesh, MeshPhysicalMaterial, Object3D, PerspectiveCamera, Scene, ShaderMaterial, Texture, Vector3, WebGLRenderer } from "three";
9
9
  import { VRM } from "@pixiv/three-vrm";
10
10
  import { Sky } from "three/examples/jsm/objects/Sky.js";
package/dist/3d.js CHANGED
@@ -1,9 +1,9 @@
1
- import { F as CharacterBody3D, H as WATER_MAX_RIPPLES, I as PhysicsBody3D, L as RigidBody3D, M as WATER_CUTOUT_MAX, N as WaterCutout3D, P as Area3D, R as StaticBody3D, j as Water3D, z as Node3D } from "./gameplay-bStgtZBV.js";
2
- 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-C08pOC6H.js";
3
- import { a as Environment3D, c as parseEnvironment3D, d as AssetStore3D, i as syncTree, l as sunDirectionFromElevationAzimuth, o as setEnvironment3D, r as Renderer3D, s as horizonColorFromSky, t as createGame3D, u as sunDirectionFromSky } from "./create-game-BNaOC3Px.js";
1
+ import { F as CharacterBody3D, H as WATER_MAX_RIPPLES, I as PhysicsBody3D, L as RigidBody3D, M as WATER_CUTOUT_MAX, N as WaterCutout3D, P as Area3D, R as StaticBody3D, j as Water3D, z as Node3D } from "./gameplay-B6jqvYeM.js";
2
+ 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-DSZwsKPs.js";
3
+ import { a as Environment3D, c as parseEnvironment3D, d as AssetStore3D, i as syncTree, l as sunDirectionFromElevationAzimuth, o as setEnvironment3D, r as Renderer3D, s as horizonColorFromSky, t as createGame3D, u as sunDirectionFromSky } from "./create-game-CGnoypjL.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-njybhZon.js";
5
5
  import { n as splatWeights, t as buildHeightmap } from "./heightmap-CRK0M4jT.js";
6
- import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-B2c5KNYh.js";
6
+ import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-BhI0ehpe.js";
7
7
  //#region src/3d/model-verdict.ts
8
8
  /** Mixamo exports every bone as `mixamorigX`; the retargeter binds by that name. */
9
9
  const MIXAMO = /^mixamorig[:_]?/i;
@@ -1581,6 +1581,16 @@ interface PropDef {
1581
1581
  */
1582
1582
  nodePath?: boolean;
1583
1583
  /**
1584
+ * The prop must be given a value — an empty string is not a configuration.
1585
+ *
1586
+ * `Chase.target` and `FollowCamera.target` threw for this in `onReady`, which
1587
+ * is the browser, at the moment the level starts. Declared here it is a LOAD
1588
+ * error instead: `incanto-check` reports it while you are still writing the
1589
+ * scene, and the editor knows not to "unlink" a prop whose emptiness the
1590
+ * engine refuses.
1591
+ */
1592
+ required?: boolean;
1593
+ /**
1584
1594
  * For an OBJECT-valued prop shaped as a tagged union — `collider`, whose
1585
1595
  * `shape` decides which other keys are required. One declaration gives an
1586
1596
  * inspector both the dropdown AND something valid to write when the tag
@@ -1,13 +1,13 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { A as registerBehavior, n as loadScene, o as computeViewport, s as resolveViewport, w as diagnose } from "./loader-B2asghWa.js";
3
- import { h as Engine, m as AudioPlayer } from "./register-CGq-Hee8.js";
2
+ import { A as registerBehavior, C as diagnose, n as loadScene, o as computeViewport, s as resolveViewport } from "./loader-B-Gft32x.js";
3
+ import { h as Engine, m as AudioPlayer } from "./register-DVwlnZAZ.js";
4
4
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
5
5
  import { i as resolveRendering, n as attachTouchControls } from "./touch-BoNg_MnF.js";
6
- import { a as openBundledEditor, i as devServerLibrary, n as pauseWhenHidden, r as crossFade, t as teardown } from "./teardown-BKTCzLek.js";
7
- import { n as registerGameplayBehaviors } from "./gameplay-bStgtZBV.js";
8
- import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-B_BaaGx-.js";
6
+ import { a as openBundledEditor, i as devServerLibrary, n as pauseWhenHidden, r as crossFade, t as teardown } from "./teardown-ks3d5W9n.js";
7
+ import { n as registerGameplayBehaviors } from "./gameplay-B6jqvYeM.js";
8
+ import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-Trx7WHnD.js";
9
9
  import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
10
- import { n as enablePhysics2D } from "./physics-2d-Ccq2L9R0.js";
10
+ import { n as enablePhysics2D } from "./physics-2d-Dns-oZlE.js";
11
11
  import { Box3, BufferAttribute, BufferGeometry, Color, LineBasicMaterial, LineSegments, LinearFilter, NearestFilter, OrthographicCamera, Raycaster, SRGBColorSpace, Scene, TextureLoader, Vector2, Vector3, WebGLRenderer } from "three";
12
12
  //#region src/2d/assets.ts
13
13
  /**
@@ -50,6 +50,7 @@ var AssetStore2D = class {
50
50
  },
51
51
  onError: (err) => {
52
52
  state.status = "error";
53
+ state.error = err instanceof Error ? err.message : `could not load ${decl.url}`;
53
54
  diagnose(this.engine, "error", `[incanto] failed to load texture '${key}' (${decl.url}):`, err);
54
55
  }
55
56
  });
@@ -66,10 +67,31 @@ var AssetStore2D = class {
66
67
  type,
67
68
  frameWidth,
68
69
  frameHeight,
70
+ url: decl.url,
69
71
  state
70
72
  });
71
73
  }
72
74
  }
75
+ /**
76
+ * Every declared asset that FAILED to load, `$ref` and url included.
77
+ *
78
+ * The 3D store has answered this since 0.32.0 — the 2D one only tracked a
79
+ * per-key status, which the console printed and nothing else could read. A
80
+ * 404'd texture is invisible, and "invisible" is the one symptom an author
81
+ * cannot tell apart from "I put it in the wrong place".
82
+ */
83
+ errors() {
84
+ const out = [];
85
+ for (const [key, entry] of this.entries) {
86
+ if (entry.state.status !== "error") continue;
87
+ out.push({
88
+ ref: `$${key}`,
89
+ url: entry.url,
90
+ error: entry.state.error ?? `could not load ${entry.url}`
91
+ });
92
+ }
93
+ return out;
94
+ }
73
95
  /** Load status of a declared asset KEY (no '$'), or undefined if unknown. */
74
96
  status(key) {
75
97
  return this.entries.get(key)?.state.status;
@@ -107,6 +129,18 @@ function worldFromScreen(view, sx, sy) {
107
129
  y: (sy - view.h / 2) / view.zoom + view.cy
108
130
  };
109
131
  }
132
+ function screenFromUi(v, ux, uy) {
133
+ return {
134
+ x: v.offsetX + ux / v.uiW * v.contentW,
135
+ y: v.offsetY + uy / v.uiH * v.contentH
136
+ };
137
+ }
138
+ function uiFromScreen(v, sx, sy) {
139
+ return {
140
+ x: (sx - v.offsetX) / v.contentW * v.uiW,
141
+ y: (sy - v.offsetY) / v.contentH * v.uiH
142
+ };
143
+ }
110
144
  //#endregion
111
145
  //#region src/2d/selection-outline.ts
112
146
  /** 2D twin of the 3D selection outline: a world-space (px, y-down) rectangle
@@ -355,6 +389,10 @@ var Renderer2D = class {
355
389
  const view = vp ? computeViewport(w, h, vp) : null;
356
390
  const uiW = view ? view.viewW : w;
357
391
  const uiH = view ? view.viewH : h;
392
+ this.lastUi = {
393
+ w: uiW,
394
+ h: uiH
395
+ };
358
396
  const { activeCamera } = syncTree2D(scene.root, this.worldScene, this.uiScene, this.assets, {
359
397
  width: uiW,
360
398
  height: uiH
@@ -406,6 +444,11 @@ var Renderer2D = class {
406
444
  this.webgl.render(this.uiScene, this.uiCam);
407
445
  this.webgl.autoClear = true;
408
446
  }
447
+ /** UI-pass extent from the last render — the space HUD nodes are posed in. */
448
+ lastUi = {
449
+ w: 1,
450
+ h: 1
451
+ };
409
452
  lastViewport = null;
410
453
  lastView = {
411
454
  cx: 0,
@@ -448,8 +491,13 @@ var Renderer2D = class {
448
491
  const cw = this.lastViewport?.contentW ?? w;
449
492
  const ch = this.lastViewport?.contentH ?? h;
450
493
  pickNdc.set((sx - ox) / cw * 2 - 1, -((sy - oy) / ch * 2 - 1));
451
- raycaster.setFromCamera(pickNdc, this.worldCam);
452
- const hits = raycaster.intersectObjects(this.worldScene.children, true);
494
+ const ui = this.hit(this.uiScene, this.uiCam);
495
+ if (ui) return ui;
496
+ return this.hit(this.worldScene, this.worldCam);
497
+ }
498
+ hit(scene, cam) {
499
+ raycaster.setFromCamera(pickNdc, cam);
500
+ const hits = raycaster.intersectObjects(scene.children, true);
453
501
  let best = null;
454
502
  for (const hit of hits) {
455
503
  let obj = hit.object;
@@ -464,6 +512,39 @@ var Renderer2D = class {
464
512
  }
465
513
  return best?.node ?? null;
466
514
  }
515
+ /** Does the UI pass draw this node (i.e. is it under a UILayer)? */
516
+ isUiNode(node) {
517
+ let obj = node._object2D ?? node._group ?? null;
518
+ while (obj) {
519
+ if (obj === this.uiScene) return true;
520
+ obj = obj.parent;
521
+ }
522
+ return false;
523
+ }
524
+ /**
525
+ * UI-space px → canvas px.
526
+ *
527
+ * A UILayer's children are posed in the UI pass's own space (origin top-left,
528
+ * `uiW × uiH`), NOT in world space — so mapping them with `screenFromWorld`
529
+ * puts them wherever the game camera happens to be looking.
530
+ */
531
+ screenFromUi(ux, uy) {
532
+ return screenFromUi(this.uiView(), ux, uy);
533
+ }
534
+ /** Canvas px → UI-space px (the inverse of `screenFromUi`). */
535
+ uiFromScreen(sx, sy) {
536
+ return uiFromScreen(this.uiView(), sx, sy);
537
+ }
538
+ uiView() {
539
+ return {
540
+ offsetX: this.lastViewport?.offsetX ?? 0,
541
+ offsetY: this.lastViewport?.offsetY ?? 0,
542
+ contentW: this.lastViewport?.contentW ?? this.lastView.w,
543
+ contentH: this.lastViewport?.contentH ?? this.lastView.h,
544
+ uiW: this.lastUi.w,
545
+ uiH: this.lastUi.h
546
+ };
547
+ }
467
548
  /**
468
549
  * Canvas-pixel AABB of a node's rendered world-pass objects, or null when it
469
550
  * has no renderable extent (plain Nodes, empty containers).
@@ -476,8 +557,9 @@ var Renderer2D = class {
476
557
  if (boundsScratch.isEmpty()) return null;
477
558
  boundsScratch.getSize(sizeScratch3);
478
559
  if (sizeScratch3.x === 0 && sizeScratch3.y === 0) return null;
479
- const a = this.screenFromWorld(boundsScratch.min.x, -boundsScratch.max.y);
480
- const b = this.screenFromWorld(boundsScratch.max.x, -boundsScratch.min.y);
560
+ const map = this.isUiNode(node) ? (x, y) => this.screenFromUi(x, y) : (x, y) => this.screenFromWorld(x, y);
561
+ const a = map(boundsScratch.min.x, -boundsScratch.max.y);
562
+ const b = map(boundsScratch.max.x, -boundsScratch.min.y);
481
563
  return {
482
564
  x: a.x,
483
565
  y: a.y,
@@ -1,15 +1,15 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { A as registerBehavior, n as loadScene, w as diagnose } from "./loader-B2asghWa.js";
3
- import { _ as qualityCaps, h as Engine, m as AudioPlayer, y as qualityRendering } from "./register-CGq-Hee8.js";
2
+ import { A as registerBehavior, C as diagnose, n as loadScene } from "./loader-B-Gft32x.js";
3
+ import { _ as qualityCaps, h as Engine, m as AudioPlayer, y as qualityRendering } from "./register-DVwlnZAZ.js";
4
4
  import { t as IncantoError } from "./errors-BpWbnbb_.js";
5
5
  import { r as parseDrive, t as logReport } from "./log-report-lxrQY9cH.js";
6
6
  import { i as resolveRendering, n as attachTouchControls } from "./touch-BoNg_MnF.js";
7
- import { a as openBundledEditor, i as devServerLibrary, n as pauseWhenHidden, o as poseFromRenderer, r as crossFade, t as teardown } from "./teardown-BKTCzLek.js";
8
- import { I as PhysicsBody3D, V as createCausticsQuad, n as registerGameplayBehaviors, z as Node3D } from "./gameplay-bStgtZBV.js";
7
+ import { a as openBundledEditor, i as devServerLibrary, n as pauseWhenHidden, o as poseFromRenderer, r as crossFade, t as teardown } from "./teardown-ks3d5W9n.js";
8
+ import { I as PhysicsBody3D, V as createCausticsQuad, n as registerGameplayBehaviors, z as Node3D } from "./gameplay-B6jqvYeM.js";
9
9
  import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
10
- import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-C08pOC6H.js";
10
+ import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-DSZwsKPs.js";
11
11
  import { a as frameSignature, i as frameImage, o as frameStats } from "./frame-report-njybhZon.js";
12
- import { n as enablePhysics3D } from "./physics-3d-B2c5KNYh.js";
12
+ import { n as enablePhysics3D } from "./physics-3d-BhI0ehpe.js";
13
13
  import { ACESFilmicToneMapping, AmbientLight, Box3, BufferAttribute, BufferGeometry, Color, DepthTexture, EquirectangularReflectionMapping, FloatType, Fog, HalfFloatType, LineBasicMaterial, LineSegments, Matrix4, Mesh, PCFShadowMap, PMREMGenerator, PerspectiveCamera, PlaneGeometry, Quaternion, Raycaster, Scene, ShaderMaterial, Vector2, Vector3, WebGLRenderTarget, WebGLRenderer } from "three";
14
14
  import { VRMLoaderPlugin, VRMUtils } from "@pixiv/three-vrm";
15
15
  import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
package/dist/debug.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { T as RendererStats, b as Engine, jt as LogLevel } from "./behavior-rZNfzVbH.js";
1
+ import { T as RendererStats, b as Engine, jt as LogLevel } from "./behavior-uPEuZrUB.js";
2
2
 
3
3
  //#region src/debug/panel.d.ts
4
4
  /** Minimal document surface the overlay needs (injectable for tests). */
package/dist/debug.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as jsonClone } from "./json-BLk7H2Qa.js";
2
- import { s as mergeStaticProps } from "./registry-IyWCGe4q.js";
2
+ import { s as mergeStaticProps } from "./registry-C7u42TID.js";
3
3
  import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
4
4
  //#region src/debug/capture.ts
5
5
  /**
@@ -1,4 +1,4 @@
1
- import { i as serializeNode, t as buildNodeJson } from "./loader-B2asghWa.js";
1
+ import { i as serializeNode, t as buildNodeJson } from "./loader-B-Gft32x.js";
2
2
  //#region src/core/scene/duplicate.ts
3
3
  function stripUids(json) {
4
4
  const { uid: _uid, ...rest } = json;