@fonsecabarreto/genesis-gl-core 0.1.0 → 0.1.2

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 (40) hide show
  1. package/README.md +19 -2
  2. package/dist/{Camera-DY_8gx3C.d.ts → Camera-CJVYy9fH.d.ts} +13 -2
  3. package/dist/Core/classes/Material.d.ts +1 -1
  4. package/dist/Core/classes/Material.js +1 -1
  5. package/dist/Core/classes/Model.d.ts +3 -3
  6. package/dist/Core/classes/Model.js +1 -1
  7. package/dist/Core/classes/Renderer.d.ts +11 -5
  8. package/dist/Core/classes/Renderer.js +4 -4
  9. package/dist/Core/classes/Scene.d.ts +2 -2
  10. package/dist/Core/classes/Viewport.d.ts +1 -1
  11. package/dist/Core/classes/Viewport.js +1 -1
  12. package/dist/Core/index.d.ts +4 -4
  13. package/dist/Core/index.js +4 -4
  14. package/dist/Core/utils/load-glb.d.ts +3 -3
  15. package/dist/Core/utils/load-glb.js +4 -4
  16. package/dist/Core/utils/parse-obj.d.ts +2 -2
  17. package/dist/Core/utils/parse-obj.js +4 -4
  18. package/dist/Editor/index.d.ts +126 -15
  19. package/dist/Editor/index.js +471 -74
  20. package/dist/Editor/index.js.map +1 -1
  21. package/dist/Game/controls/KeyboardInput.d.ts +4 -4
  22. package/dist/Game/index.d.ts +308 -7
  23. package/dist/Game/index.js +470 -24
  24. package/dist/Game/index.js.map +1 -1
  25. package/dist/{KeyboardInput-DTsfj3tE.d.ts → KeyboardInput-1xOAabI0.d.ts} +95 -14
  26. package/dist/{Material-BGLkldxv.d.ts → Material-DhwSRbP2.d.ts} +8 -0
  27. package/dist/{Model-CQvDXd-b.d.ts → Model-BBZHnUp1.d.ts} +24 -8
  28. package/dist/{chunk-6LS6AO5H.js → chunk-L66K4AZU.js} +36 -30
  29. package/dist/chunk-L66K4AZU.js.map +1 -0
  30. package/dist/{chunk-JK2HEZAT.js → chunk-QOAQVTAB.js} +26 -22
  31. package/dist/chunk-QOAQVTAB.js.map +1 -0
  32. package/dist/{chunk-5TAAXI6S.js → chunk-XMW2MS66.js} +39 -16
  33. package/dist/chunk-XMW2MS66.js.map +1 -0
  34. package/dist/{chunk-QCQVJCSR.js → chunk-ZCJ3MJZD.js} +103 -67
  35. package/dist/chunk-ZCJ3MJZD.js.map +1 -0
  36. package/package.json +1 -1
  37. package/dist/chunk-5TAAXI6S.js.map +0 -1
  38. package/dist/chunk-6LS6AO5H.js.map +0 -1
  39. package/dist/chunk-JK2HEZAT.js.map +0 -1
  40. package/dist/chunk-QCQVJCSR.js.map +0 -1
package/README.md CHANGED
@@ -8,7 +8,7 @@ GenesisGL is a lightweight browser-side WebGL 3D engine written in TypeScript.
8
8
  npm install @fonsecabarreto/genesis-gl-core
9
9
  ```
10
10
 
11
- ## Usage
11
+ ## Quick Start
12
12
 
13
13
  ```ts
14
14
  import { WebGLCore, Scene, Renderer, Viewport } from '@fonsecabarreto/genesis-gl-core';
@@ -19,7 +19,20 @@ const viewport = new Viewport(canvas, window.innerWidth, window.innerHeight, web
19
19
  const renderer = new Renderer(webglCore, viewport);
20
20
  const scene = Scene.withDefaultLights(webglCore);
21
21
 
22
- // Add models and render loop...
22
+ // Add models, implement render loop, etc.
23
+ ```
24
+
25
+ ## Sub-path Imports
26
+
27
+ ```ts
28
+ // Editor utilities (visual editor, scene/material stores)
29
+ import { MaterialStore, SceneStore } from '@fonsecabarreto/genesis-gl-core/Editor';
30
+
31
+ // Game utilities (characters, physics, animations)
32
+ import { Character, InteractiveActor } from '@fonsecabarreto/genesis-gl-core/Game';
33
+
34
+ // OBJ/GLB loaders
35
+ import { loadOBJWithMTL, GLBLoader } from '@fonsecabarreto/genesis-gl-core/Core/utils';
23
36
  ```
24
37
 
25
38
  ## Build
@@ -28,6 +41,10 @@ const scene = Scene.withDefaultLights(webglCore);
28
41
  yarn build
29
42
  ```
30
43
 
44
+ ## API Documentation
45
+
46
+ See [ARCHITECTURE.md](./ARCHITECTURE.md) for a detailed API overview.
47
+
31
48
  ## License
32
49
 
33
50
  MIT
@@ -19,11 +19,22 @@ declare class Camera {
19
19
  far: number;
20
20
  lastViewMatrix?: Float32Array;
21
21
  lastProjectionMatrix?: Float32Array;
22
+ private readonly _view;
23
+ private readonly _proj;
24
+ private readonly _mvp;
25
+ private _viewDirty;
26
+ private _projDirty;
22
27
  constructor(viewportWidth: number, viewportHeight: number);
23
28
  /** Translate the camera by a delta. */
24
29
  move(dx: number, dy: number, dz?: number): void;
25
30
  /** Clamp-set the zoom level. */
26
31
  setZoom(zoom: number): void;
32
+ /**
33
+ * Mark the view matrix as dirty so it is rebuilt on the next
34
+ * {@link getViewMatrix} call. Call this after directly mutating
35
+ * {@link target} or {@link position} (e.g. from a follow-camera update).
36
+ */
37
+ invalidate(): void;
27
38
  /** Zoom by a signed delta (positive = zoom in). */
28
39
  zoomBy(delta: number): void;
29
40
  worldToNDC(x: number, y: number): [number, number];
@@ -31,9 +42,9 @@ declare class Camera {
31
42
  setViewport(width: number, height: number): void;
32
43
  /** Compute the eye position from yaw/pitch/distance to target. */
33
44
  getComputedPosition(): vec3;
34
- /** Build the view matrix (lookAt). */
45
+ /** Build the view matrix (lookAt). Returns a cached matrix rebuilt only when the camera moves. */
35
46
  getViewMatrix(): mat4;
36
- /** Build the perspective projection matrix. */
47
+ /** Build the perspective projection matrix. Returns a cached matrix rebuilt only when viewport/zoom changes. */
37
48
  getProjectionMatrix(): mat4;
38
49
  worldToNDC3D(x: number, y: number, z?: number): [number, number, number];
39
50
  worldScale3D(scale: [number, number, number]): [number, number, number];
@@ -1,3 +1,3 @@
1
1
  import '../domain/interfaces/Vectors.js';
2
- export { M as MAX_LIGHTS, b as Material } from '../../Material-BGLkldxv.js';
2
+ export { M as MAX_LIGHTS, b as Material } from '../../Material-DhwSRbP2.js';
3
3
  import '../../WebGLCore-DR7ZHJB0.js';
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  MAX_LIGHTS,
3
3
  Material
4
- } from "../../chunk-6LS6AO5H.js";
4
+ } from "../../chunk-L66K4AZU.js";
5
5
  export {
6
6
  MAX_LIGHTS,
7
7
  Material
@@ -1,5 +1,5 @@
1
- export { i as Model } from '../../Model-CQvDXd-b.js';
1
+ import 'gl-matrix';
2
+ export { i as Model } from '../../Model-BBZHnUp1.js';
2
3
  import '../domain/interfaces/Vectors.js';
3
4
  import '../../WebGLCore-DR7ZHJB0.js';
4
- import '../../Material-BGLkldxv.js';
5
- import 'gl-matrix';
5
+ import '../../Material-DhwSRbP2.js';
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Model
3
- } from "../../chunk-JK2HEZAT.js";
3
+ } from "../../chunk-QOAQVTAB.js";
4
4
  export {
5
5
  Model
6
6
  };
@@ -1,11 +1,11 @@
1
- import { mat4 } from 'gl-matrix';
2
1
  import { W as WebGLCore } from '../../WebGLCore-DR7ZHJB0.js';
3
2
  import { Scene } from './Scene.js';
4
- import { i as Model } from '../../Model-CQvDXd-b.js';
3
+ import { i as Model } from '../../Model-BBZHnUp1.js';
5
4
  import { Viewport } from './Viewport.js';
6
- import '../../Material-BGLkldxv.js';
5
+ import '../../Material-DhwSRbP2.js';
7
6
  import '../domain/interfaces/Vectors.js';
8
- import '../../Camera-DY_8gx3C.js';
7
+ import 'gl-matrix';
8
+ import '../../Camera-CJVYy9fH.js';
9
9
 
10
10
  declare class Renderer {
11
11
  private webglCore;
@@ -14,6 +14,12 @@ declare class Renderer {
14
14
  debug: boolean;
15
15
  private _modelHitboxMaterial;
16
16
  private _meshHitboxMaterial;
17
+ private readonly _modelWireBoxCache;
18
+ private readonly _meshWireBoxCache;
19
+ /** Pre-allocated identity matrix for world-space hitbox draws. */
20
+ private readonly _identity;
21
+ /** Cached `gl instanceof WebGL2RenderingContext` — computed once at construction. */
22
+ private readonly _isWebGL2;
17
23
  constructor(webglCore: WebGLCore, viewport: Viewport);
18
24
  /** Lazily-created material for model-level hitboxes (red). */
19
25
  private get modelHitboxMaterial();
@@ -23,7 +29,7 @@ declare class Renderer {
23
29
  render(scene: Scene): void;
24
30
  private drawModel;
25
31
  private drawMesh;
26
- drawHitBox(model: Model, modelMatrix: mat4, activeProgram: WebGLProgram | null): void;
32
+ drawHitBox(model: Model, activeProgram: WebGLProgram | null): void;
27
33
  private drawHitBoxForMesh;
28
34
  }
29
35
 
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  Renderer
3
- } from "../../chunk-QCQVJCSR.js";
4
- import "../../chunk-6LS6AO5H.js";
5
- import "../../chunk-JK2HEZAT.js";
3
+ } from "../../chunk-ZCJ3MJZD.js";
4
+ import "../../chunk-L66K4AZU.js";
5
+ import "../../chunk-QOAQVTAB.js";
6
6
  import "../../chunk-3ULETMWF.js";
7
- import "../../chunk-5TAAXI6S.js";
7
+ import "../../chunk-XMW2MS66.js";
8
8
  export {
9
9
  Renderer
10
10
  };
@@ -1,5 +1,5 @@
1
- import { L as Light } from '../../Material-BGLkldxv.js';
2
- import { i as Model } from '../../Model-CQvDXd-b.js';
1
+ import { L as Light } from '../../Material-DhwSRbP2.js';
2
+ import { i as Model } from '../../Model-BBZHnUp1.js';
3
3
  import { W as WebGLCore } from '../../WebGLCore-DR7ZHJB0.js';
4
4
  import '../domain/interfaces/Vectors.js';
5
5
  import 'gl-matrix';
@@ -1,4 +1,4 @@
1
- import { C as Camera } from '../../Camera-DY_8gx3C.js';
1
+ import { C as Camera } from '../../Camera-CJVYy9fH.js';
2
2
  import { W as WebGLCore } from '../../WebGLCore-DR7ZHJB0.js';
3
3
  import 'gl-matrix';
4
4
  import '../domain/interfaces/Vectors.js';
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Viewport
3
- } from "../../chunk-5TAAXI6S.js";
3
+ } from "../../chunk-XMW2MS66.js";
4
4
  export {
5
5
  Viewport
6
6
  };
@@ -1,10 +1,10 @@
1
- export { A as AnimationChannel, a as AnimationClip, b as AnimationPath, c as AnimationSampler, G as GL_LINES, d as GL_TRIANGLES, I as INITIAL_BOUNDING_BOX, e as InterpolationMode, J as Joint, f as JointPose, M as MAX_JOINTS, g as Mesh, h as MeshBuffers, i as Model, S as Skeleton } from '../Model-CQvDXd-b.js';
1
+ export { A as AnimationChannel, a as AnimationClip, b as AnimationPath, c as AnimationSampler, G as GL_LINES, d as GL_TRIANGLES, I as INITIAL_BOUNDING_BOX, e as InterpolationMode, J as Joint, f as JointPose, M as MAX_JOINTS, g as Mesh, h as MeshBuffers, i as Model, S as Skeleton } from '../Model-BBZHnUp1.js';
2
2
  export { R as RenderCallback, W as WebGLCore } from '../WebGLCore-DR7ZHJB0.js';
3
- export { C as Camera } from '../Camera-DY_8gx3C.js';
4
- export { L as Light, a as LightType, M as MAX_LIGHTS, b as Material } from '../Material-BGLkldxv.js';
3
+ export { C as Camera } from '../Camera-CJVYy9fH.js';
4
+ export { L as Light, a as LightType, M as MAX_LIGHTS, b as Material } from '../Material-DhwSRbP2.js';
5
5
  export { Renderer } from './classes/Renderer.js';
6
6
  export { Scene } from './classes/Scene.js';
7
7
  export { Viewport } from './classes/Viewport.js';
8
8
  export { K as KeyboardControl } from '../KeyboardControl-5w7Vm0J0.js';
9
- import './domain/interfaces/Vectors.js';
10
9
  import 'gl-matrix';
10
+ import './domain/interfaces/Vectors.js';
@@ -12,14 +12,14 @@ import {
12
12
  Renderer,
13
13
  Skeleton,
14
14
  WebGLCore
15
- } from "../chunk-QCQVJCSR.js";
15
+ } from "../chunk-ZCJ3MJZD.js";
16
16
  import {
17
17
  MAX_LIGHTS,
18
18
  Material
19
- } from "../chunk-6LS6AO5H.js";
19
+ } from "../chunk-L66K4AZU.js";
20
20
  import {
21
21
  Model
22
- } from "../chunk-JK2HEZAT.js";
22
+ } from "../chunk-QOAQVTAB.js";
23
23
  import {
24
24
  Light,
25
25
  Scene
@@ -27,7 +27,7 @@ import {
27
27
  import {
28
28
  Camera,
29
29
  Viewport
30
- } from "../chunk-5TAAXI6S.js";
30
+ } from "../chunk-XMW2MS66.js";
31
31
  export {
32
32
  AnimationClip,
33
33
  Camera,
@@ -1,8 +1,8 @@
1
1
  import { W as WebGLCore } from '../../WebGLCore-DR7ZHJB0.js';
2
- import { i as Model, S as Skeleton, a as AnimationClip } from '../../Model-CQvDXd-b.js';
3
- import '../domain/interfaces/Vectors.js';
4
- import '../../Material-BGLkldxv.js';
2
+ import { i as Model, S as Skeleton, a as AnimationClip } from '../../Model-BBZHnUp1.js';
5
3
  import 'gl-matrix';
4
+ import '../domain/interfaces/Vectors.js';
5
+ import '../../Material-DhwSRbP2.js';
6
6
 
7
7
  /** Everything parsed from a GLB file. */
8
8
  interface GLBLoadResult {
@@ -3,15 +3,15 @@ import {
3
3
  GL_TRIANGLES,
4
4
  Mesh,
5
5
  Skeleton
6
- } from "../../chunk-QCQVJCSR.js";
6
+ } from "../../chunk-ZCJ3MJZD.js";
7
7
  import {
8
8
  Material
9
- } from "../../chunk-6LS6AO5H.js";
9
+ } from "../../chunk-L66K4AZU.js";
10
10
  import {
11
11
  Model
12
- } from "../../chunk-JK2HEZAT.js";
12
+ } from "../../chunk-QOAQVTAB.js";
13
13
  import "../../chunk-3ULETMWF.js";
14
- import "../../chunk-5TAAXI6S.js";
14
+ import "../../chunk-XMW2MS66.js";
15
15
 
16
16
  // src/Core/utils/load-glb.ts
17
17
  import { mat4, quat, vec3 } from "gl-matrix";
@@ -1,7 +1,7 @@
1
1
  import { W as WebGLCore } from '../../WebGLCore-DR7ZHJB0.js';
2
- import { b as Material } from '../../Material-BGLkldxv.js';
2
+ import { b as Material } from '../../Material-DhwSRbP2.js';
3
3
  import { Vector3 } from '../domain/interfaces/Vectors.js';
4
- import { i as Model } from '../../Model-CQvDXd-b.js';
4
+ import { i as Model } from '../../Model-BBZHnUp1.js';
5
5
  import 'gl-matrix';
6
6
 
7
7
  declare function loadMTL(url: string, webglCore: WebGLCore): Promise<Record<string, Material>>;
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  Mesh
3
- } from "../../chunk-QCQVJCSR.js";
3
+ } from "../../chunk-ZCJ3MJZD.js";
4
4
  import {
5
5
  Material
6
- } from "../../chunk-6LS6AO5H.js";
6
+ } from "../../chunk-L66K4AZU.js";
7
7
  import {
8
8
  Model
9
- } from "../../chunk-JK2HEZAT.js";
9
+ } from "../../chunk-QOAQVTAB.js";
10
10
  import "../../chunk-3ULETMWF.js";
11
- import "../../chunk-5TAAXI6S.js";
11
+ import "../../chunk-XMW2MS66.js";
12
12
 
13
13
  // src/Core/utils/parse-obj.ts
14
14
  function computeNormal(p1, p2, p3) {
@@ -100,6 +100,7 @@ interface SceneItemSpec {
100
100
  /**
101
101
  * Key used to look up the base model in the DI / resource container.
102
102
  * The model must have been loaded during resource initialisation.
103
+ * Leave empty for procedurally generated interactive actors (e.g. spheres).
103
104
  */
104
105
  resourceKey: string;
105
106
  translation: Vector3;
@@ -118,41 +119,121 @@ interface SceneItemSpec {
118
119
  * default material. Applied to all meshes in the model at placement time.
119
120
  */
120
121
  materialKey?: string | null;
122
+ /**
123
+ * When `true` this item is a physics-simulated {@link InteractiveActor}.
124
+ * Leave `resourceKey` empty to use a procedurally generated sphere shape.
125
+ */
126
+ interactive?: boolean;
127
+ /** Sphere radius (world units). Only used when `interactive: true` and no `resourceKey`. Default `0.5`. */
128
+ radius?: number;
129
+ /** Mass in kg — affects impulse distribution in body-pair collisions. Default `1.0`. */
130
+ mass?: number;
131
+ /** Bounce coefficient 0–1. Higher = bouncier. Default `0.6` for sphere actors. */
132
+ restitution?: number;
121
133
  }
122
- /** Top-level scene definition stored in `scene.json`. */
134
+ /** Top-level scene definition stored in `scenes.json`. */
123
135
  interface SceneSpec {
124
136
  /** World position where the player spawns. */
125
137
  playerSpawn: Vector3;
126
- /** All placed models in the scene. */
138
+ /** All items in the scene — static actors and interactive physics bodies. */
127
139
  items: SceneItemSpec[];
128
140
  }
129
141
  /** Create a new scene item with sensible defaults. */
130
142
  declare function createDefaultSceneItem(name?: string, resourceKey?: string): SceneItemSpec;
131
143
  /** Create an empty scene. */
132
144
  declare function createDefaultScene(): SceneSpec;
145
+ /**
146
+ * A named, addressable scene that can live inside a multi-scene project file.
147
+ * Extends {@link SceneSpec} with a stable `id` and a human-readable `name`.
148
+ */
149
+ interface NamedScene extends SceneSpec {
150
+ /** Stable unique identifier (crypto.randomUUID). */
151
+ id: string;
152
+ /** Human-readable label shown in the scene picker. */
153
+ name: string;
154
+ /**
155
+ * When `true`, this is the scene the game loads at startup.
156
+ * Exactly one scene in a {@link MultiSceneFile} should be active at a time.
157
+ */
158
+ isActive?: boolean;
159
+ }
160
+ /**
161
+ * Top-level structure stored in a multi-scene JSON file (e.g. `scenes.json`).
162
+ * Each entry in `scenes` is a fully self-contained {@link NamedScene}.
163
+ */
164
+ interface MultiSceneFile {
165
+ scenes: NamedScene[];
166
+ }
167
+ /** Create a new named scene with sensible defaults. */
168
+ declare function createDefaultNamedScene(name?: string, isActive?: boolean): NamedScene;
169
+ /** Create an empty multi-scene file containing a single default scene (marked active). */
170
+ declare function createDefaultMultiSceneFile(): MultiSceneFile;
133
171
 
172
+ /** Called whenever the *active* scene's data changes. */
134
173
  type StoreListener = (spec: SceneSpec) => void;
174
+ /** Called whenever the scene list or the active-scene selection changes. */
175
+ type ScenesListener = (scenes: NamedScene[], activeId: string) => void;
176
+ /** Called when the game-startup scene is toggled via {@link SceneStore.setActiveGameScene}. */
177
+ type GameSceneListener = (spec: SceneSpec) => void;
135
178
  interface SceneStoreOptions {
136
179
  /**
137
- * URL / public-folder path to a JSON file that seeds the store on {@link SceneStore.init}.
138
- * Example: `'data/scene.json'`
180
+ * URL / public-folder path to a multi-scene JSON (`MultiSceneFile`)
181
+ * that seeds the store on {@link SceneStore.init}.
182
+ * @example `'data/scenes.json'`
139
183
  */
140
- filePath?: string;
184
+ scenesFilePath: string;
141
185
  }
142
186
  /**
143
- * Manages the current scene definition ({@link SceneSpec}).
187
+ * Manages a collection of named scenes ({@link MultiSceneFile}).
188
+ *
189
+ * Back-compat: all single-scene mutators & readers still work — they
190
+ * transparently delegate to whichever scene is currently active.
144
191
  *
145
- * Follows the same patterns as `MaterialStore`:
146
- * - Persists to `localStorage` on every change.
147
- * - Call {@link init} once at startup to load from a JSON file.
148
- * - Syncs back to the server via a PUT endpoint (Vite dev plugin).
192
+ * Multi-scene extras:
193
+ * - {@link getScenes} – list all scenes
194
+ * - {@link getActiveSceneId} which scene the editor is editing
195
+ * - {@link setActiveScene} – switch which scene the editor is editing
196
+ * - {@link getActiveGameSceneId} – which scene the game will load
197
+ * - {@link setActiveGameScene} – toggle which scene the game will load
198
+ * - {@link addScene} – create & activate a new scene
199
+ * - {@link removeScene} – delete a scene (min 1 kept)
200
+ * - {@link renameScene}
201
+ * - {@link subscribeScenes} – react to scene-list / selection changes
149
202
  */
150
203
  declare class SceneStore {
151
- private scene;
204
+ private multiScene;
205
+ private activeSceneId;
152
206
  private listeners;
153
- private readonly filePath;
154
- constructor(options?: SceneStoreOptions);
207
+ private scenesListeners;
208
+ private gameSceneListeners;
209
+ private readonly scenesFilePath;
210
+ constructor(options: SceneStoreOptions);
155
211
  init(): Promise<void>;
212
+ /** All scenes in the project. */
213
+ getScenes(): NamedScene[];
214
+ /** Id of the currently active scene. */
215
+ getActiveSceneId(): string;
216
+ /** Switch which scene is being edited. */
217
+ setActiveScene(id: string): void;
218
+ /** Create a new scene and make it active. Returns the new scene. */
219
+ addScene(name?: string): NamedScene;
220
+ /**
221
+ * Delete a scene by id.
222
+ * The last remaining scene is never deleted.
223
+ */
224
+ removeScene(id: string): void;
225
+ /** Rename a scene. */
226
+ renameScene(id: string, name: string): void;
227
+ /**
228
+ * Returns the id of the scene flagged as the **game's** active scene
229
+ * (the one that loads at runtime), or the first scene if none is flagged.
230
+ */
231
+ getActiveGameSceneId(): string;
232
+ /**
233
+ * Set exactly one scene as the game's active scene.
234
+ * All other scenes have their `isActive` flag removed.
235
+ */
236
+ setActiveGameScene(id: string): void;
156
237
  get(): SceneSpec;
157
238
  getItems(): SceneItemSpec[];
158
239
  getItem(id: string): SceneItemSpec | undefined;
@@ -161,15 +242,33 @@ declare class SceneStore {
161
242
  addItem(item: SceneItemSpec): void;
162
243
  updateItem(item: SceneItemSpec): void;
163
244
  deleteItem(id: string): void;
164
- /** Replace the entire scene definition. */
245
+ /** Replace the entire active scene definition. */
165
246
  setScene(spec: SceneSpec): void;
166
247
  syncToServer(): Promise<boolean>;
167
248
  private persist;
168
249
  private loadFromStorage;
250
+ private loadData;
251
+ /** Export the full multi-scene file. */
169
252
  exportToFile(filename?: string): Promise<void>;
253
+ /** Import a multi-scene JSON file, replacing current data. */
170
254
  importFromFile(): Promise<void>;
255
+ /** Subscribe to active-scene data changes. */
171
256
  subscribe(fn: StoreListener): () => void;
257
+ /**
258
+ * Subscribe to scene-list or active-scene-selection changes.
259
+ * Fired when scenes are added/removed/renamed or the active scene switches.
260
+ */
261
+ subscribeScenes(fn: ScenesListener): () => void;
262
+ /**
263
+ * Subscribe to game-scene changes.
264
+ * Fired only when {@link setActiveGameScene} is called — use this to reload
265
+ * the running game world with the newly flagged scene's data.
266
+ */
267
+ subscribeGameScene(fn: GameSceneListener): () => void;
268
+ private get activeScene();
172
269
  private emit;
270
+ private emitScenes;
271
+ private emitGameScene;
173
272
  }
174
273
 
175
274
  interface EditorTab {
@@ -267,6 +366,8 @@ declare class SceneSection {
267
366
  private selectedId;
268
367
  private formEl;
269
368
  private unsub?;
369
+ private unsubScenes?;
370
+ private scenesBar;
270
371
  private modelRegistry;
271
372
  private readonly getMaterialNames;
272
373
  private readonly modelsFile;
@@ -278,6 +379,7 @@ declare class SceneSection {
278
379
  private onActivate;
279
380
  private onDeactivate;
280
381
  private buildContent;
382
+ private refreshScenesBar;
281
383
  private refreshList;
282
384
  private refreshForm;
283
385
  private buildSpawnForm;
@@ -285,6 +387,8 @@ declare class SceneSection {
285
387
  private onAdd;
286
388
  private onDuplicate;
287
389
  private onDelete;
390
+ private sectionHeader;
391
+ private numberRow;
288
392
  private vec3Row;
289
393
  private textRow;
290
394
  private selectRow;
@@ -299,6 +403,11 @@ interface ISidebar {
299
403
  activateTab(id: string): void;
300
404
  readonly isVisible: boolean;
301
405
  }
406
+ /** Minimal room panel interface used by TopBar. */
407
+ interface IRoomPanel {
408
+ toggle(): void;
409
+ readonly isVisible: boolean;
410
+ }
302
411
  /**
303
412
  * Slim top bar pinned at the top of the viewport.
304
413
  * Houses engine tool buttons (e.g. Material Editor toggle).
@@ -313,6 +422,8 @@ declare class TopBar {
313
422
  addModelsButton(sidebar: ISidebar): void;
314
423
  /** Add the Scene tab button after the game has started. */
315
424
  addSceneButton(sidebar: ISidebar): void;
425
+ /** Add the Room manager button. */
426
+ addRoomButton(panel: IRoomPanel): void;
316
427
  private mkToggleBtn;
317
428
  private mkPanelToggleBtn;
318
429
  }
@@ -361,4 +472,4 @@ declare class ModelsSection {
361
472
  private refresh;
362
473
  }
363
474
 
364
- export { EditorSidebar, type EditorTab, type MaterialSpec, MaterialStore, type MaterialStoreOptions, type ModelRegistryEntry, ModelsSection, type SceneItemSpec, SceneSection, type SceneSectionOptions, type SceneSpec, SceneStore, type SceneStoreOptions, TopBar, createDefaultScene, createDefaultSceneItem, createDefaultSpec };
475
+ export { EditorSidebar, type EditorTab, type MaterialSpec, MaterialStore, type MaterialStoreOptions, type ModelRegistryEntry, ModelsSection, type MultiSceneFile, type NamedScene, type SceneItemSpec, SceneSection, type SceneSectionOptions, type SceneSpec, SceneStore, type SceneStoreOptions, TopBar, createDefaultMultiSceneFile, createDefaultNamedScene, createDefaultScene, createDefaultSceneItem, createDefaultSpec };