@scenography/engine 0.1.0 → 0.2.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.
package/dist/index.d.cts CHANGED
@@ -1,21 +1,444 @@
1
- import { Object3D, PerspectiveCamera, Scene, Vector3, WebGLRenderer } from "three";
2
- import { Artwork, Scene as Scene$1, Wall } from "@scenography/core";
1
+ import { MeshStandardMaterial, Object3D, PerspectiveCamera, Scene, Vector3, WebGLRenderer } from "three";
2
+ import { DataPlugin, Scene as Scene$1, SurfaceTexture, Vec2 } from "@scenography/scene";
3
3
 
4
+ //#region src/camera/api.d.ts
5
+ /** Options for framing an artwork on screen. */
6
+ interface FocusOptions {
7
+ /** Horizontal screen position of the piece's center, `0`=left … `1`=right. Default `0.5`. */
8
+ centerX?: number;
9
+ /** Fraction of the viewport width available for the piece (e.g. `0.6`). Default `1`. */
10
+ widthFraction?: number;
11
+ /** Tween duration in ms. Default `900`. */
12
+ duration?: number;
13
+ }
14
+ /**
15
+ * Public camera-framing API exposed on the gallery context as `ctx.camera`.
16
+ * Implemented by a framing system plugin (`@scenography/plugin-focus`); when no
17
+ * such plugin is registered the kernel provides a no-op so callers are safe.
18
+ */
19
+ interface CameraApi {
20
+ /** Animate to frame an artwork (by `id`), e.g. offset into the free area beside a panel. */
21
+ focusArtwork(id: string, options?: FocusOptions): void;
22
+ /** Animate to center an artwork full-width (used when an info panel closes). */
23
+ centerArtwork(id: string, options?: FocusOptions): void;
24
+ /** Drop any active framing watch and hand control fully back to the user. */
25
+ release(): void;
26
+ /** Whether a framing tween is in progress (e.g. to suppress click-to-select). */
27
+ isAnimating(): boolean;
28
+ }
29
+ //#endregion
30
+ //#region src/api/index.d.ts
31
+ /**
32
+ * The public `ctx` API contracts implemented by plugins and surfaced on the
33
+ * gallery context. The interfaces live in the kernel (they are the supported
34
+ * surface); the implementations live in the plugins that own each concern.
35
+ */
36
+ interface LightSetOptions {
37
+ /** Fade duration in ms. `0`/omitted applies instantly. */
38
+ duration?: number;
39
+ }
40
+ interface LightSet {
41
+ intensity?: number;
42
+ /** CSS-style color. Applied instantly (not tweened). */
43
+ color?: string;
44
+ }
45
+ /** `ctx.lights` — high-level control over scene lights by id. */
46
+ interface LightsApi {
47
+ /** Set intensity (tweened) and/or color (instant) on a light by `id`. */
48
+ set(id: string, props: LightSet, opts?: LightSetOptions): void;
49
+ /** Dim every light toward `factor` of its current intensity (default `0`). */
50
+ dimAll(opts?: LightSetOptions & {
51
+ factor?: number;
52
+ }): void;
53
+ /** Fade every light back to the intensity captured before the last dim. */
54
+ restore(opts?: LightSetOptions): void;
55
+ }
56
+ /** `ctx.video` — high-level control over video screens by id. */
57
+ interface VideoApi {
58
+ /** Start (or resume) playback of the video with this `id`. */
59
+ play(id: string): void;
60
+ /** Pause the video with this `id`. */
61
+ pause(id: string): void;
62
+ /** Show or hide the screen with this `id`. */
63
+ setVisible(id: string, visible: boolean): void;
64
+ }
65
+ /** `ctx.media` — high-level control over background audio by id. */
66
+ interface MediaController {
67
+ /** Start (or resume) a source by `id`. */
68
+ play(id: string): void;
69
+ /** Pause a source, keeping its position. */
70
+ pause(id: string): void;
71
+ /** Stop a source and rewind it. */
72
+ stop(id: string): void;
73
+ /** Set a source's volume `0`..`1`, optionally fading over `duration` ms. */
74
+ setVolume(id: string, volume: number, opts?: {
75
+ duration?: number;
76
+ }): void;
77
+ /** Whether a source is currently playing. */
78
+ playing(id: string): boolean;
79
+ /** Mute or unmute everything at the master output (per-source volumes are kept). */
80
+ setMuted(muted: boolean): void;
81
+ /** Whether the master output is muted. */
82
+ muted(): boolean;
83
+ }
84
+ /** `ctx.sky` — drive the procedural sky's time of day at runtime. */
85
+ interface SkyApi {
86
+ /** Set the hour of day (`0`..`24`), updating sun, sky, fill and stars live. */
87
+ setTime(hour: number): void;
88
+ /** Current hour of day. */
89
+ getTime(): number;
90
+ /** Set the sun's compass offset (degrees). */
91
+ setAzimuth(degrees: number): void;
92
+ /** Current sun compass offset (degrees). */
93
+ getAzimuth(): number;
94
+ }
95
+ //#endregion
96
+ //#region src/plugin/CapabilityRegistry.d.ts
97
+ /**
98
+ * Shared runtime contracts between plugins, keyed by name. A plugin (or the
99
+ * kernel) *provides* a capability — e.g. the floor provides `terrain` — and
100
+ * other plugins *consume* it if present, without depending on the provider's
101
+ * package. Each name keeps a monotonic version counter so consumers can hash
102
+ * their dependencies cheaply and rebuild when a provider changes.
103
+ */
104
+ declare class CapabilityRegistry {
105
+ private readonly values;
106
+ private readonly versions;
107
+ /** Last change-token seen per name, to suppress redundant version bumps. */
108
+ private readonly tokens;
109
+ /**
110
+ * Publish (or replace) the capability under `name`. Pass a `token` (a cheap
111
+ * hash of the inputs) to dedupe: re-providing with an unchanged token is a
112
+ * no-op, so consumers that depend on this capability don't rebuild when the
113
+ * provider recomputes an identical value.
114
+ */
115
+ provide<T>(name: string, value: T, token?: string): void;
116
+ /** Remove the capability; consumers see `undefined` and a version bump. */
117
+ revoke(name: string): void;
118
+ get<T>(name: string): T | undefined;
119
+ /** Monotonic change counter for `name` (`0` if never provided). */
120
+ version(name: string): number;
121
+ private bump;
122
+ }
123
+ //#endregion
124
+ //#region src/plugin/enginePlugin.d.ts
125
+ /** What a plugin materializes for one element: an object plus lifecycle hooks. */
126
+ interface BuiltElement {
127
+ /** Mounted into (and removed from) the three.js scene by the kernel. */
128
+ object?: Object3D;
129
+ /** Advance time-based behavior; called once per frame with the delta in ms. */
130
+ update?: (deltaMs: number) => void;
131
+ /**
132
+ * Render an auxiliary pass before the main frame — e.g. a planar reflection
133
+ * or a portal view rendered into a texture the element's material samples.
134
+ * Called once per frame with the live renderer, scene and camera.
135
+ */
136
+ beforeRender?: (renderer: WebGLRenderer, scene: Scene, camera: PerspectiveCamera) => void;
137
+ /** Extra cleanup beyond the object's geometries/materials (which the kernel disposes). */
138
+ dispose?: () => void;
139
+ }
140
+ /** What the kernel hands a plugin while building. */
141
+ interface EngineContext {
142
+ capabilities: CapabilityRegistry;
143
+ }
144
+ /**
145
+ * An aggregate controller over all of an element plugin's live objects, exposing
146
+ * a public api (mapped onto `ctx` by the plugin's kind — e.g. the light plugin's
147
+ * `lights` api becomes `ctx.lights`). It reads the elements fresh each call, so
148
+ * it keeps working across hot-swaps.
149
+ */
150
+ interface ElementController<Api = unknown> {
151
+ /** The api surfaced on `ctx`. */
152
+ api?: Api;
153
+ /** Advance time-based control (e.g. light-intensity tweens). */
154
+ update?(deltaMs: number): void;
155
+ /** Tear down. */
156
+ dispose?(): void;
157
+ }
158
+ /**
159
+ * The runtime half of a plugin: embeds its data half (the scene key, its
160
+ * validation) and adds how each element materializes into three.js objects.
161
+ * The kernel reconciles by content: an element rebuilds when its definition
162
+ * changes, or when any capability named in `dependsOn` is re-provided.
163
+ */
164
+ interface EnginePlugin<T = unknown> {
165
+ data: DataPlugin<T>;
166
+ /** Capability names whose changes force a rebuild of this plugin's elements. */
167
+ dependsOn?: readonly string[];
168
+ /** Method syntax on purpose: keeps `EnginePlugin<Water>` assignable to `EnginePlugin[]`. */
169
+ build(value: T, ctx: EngineContext): BuiltElement;
170
+ /**
171
+ * Publish capabilities derived from *all* of this plugin's elements, once
172
+ * they have reconciled — the aggregate a single `build` can't see (e.g. the
173
+ * wall plugin indexing every edge into the `edges` capability). Pass a change
174
+ * token to `ctx.capabilities.provide` so consumers don't rebuild needlessly.
175
+ */
176
+ provide?(values: T[], ctx: EngineContext): void;
177
+ /**
178
+ * Build an aggregate controller over this plugin's live elements (e.g. the
179
+ * light plugin's `ctx.lights`). `elements` returns the current objects by id,
180
+ * queried fresh so it survives hot-swaps.
181
+ */
182
+ controller?(elements: () => ReadonlyMap<string, Object3D>): ElementController;
183
+ }
184
+ //#endregion
185
+ //#region src/input/InputBus.d.ts
186
+ /**
187
+ * The shared analog-input channel: the current movement and look intent, each
188
+ * axis in `-1..1` and held until a producer changes it. Producers (on-screen
189
+ * joysticks in the overlay, a gamepad…) write to it; whatever camera system is
190
+ * active reads it and interprets it its own way — free-roam walks with it, a
191
+ * fixed camera might only use the look axes to glance around. This is what makes
192
+ * the joysticks reusable across camera types. Pure state — no three.js.
193
+ */
194
+ declare class InputBus {
195
+ /** Forward (`+1`) / backward (`-1`). */
196
+ moveForward: number;
197
+ /** Strafe right (`+1`) / left (`-1`). */
198
+ moveStrafe: number;
199
+ /** Look right (`+1`) / left (`-1`). */
200
+ lookX: number;
201
+ /** Look up (`+1`) / down (`-1`). */
202
+ lookY: number;
203
+ /** Set the movement intent (forward, strafe). */
204
+ setMove(forward: number, strafe?: number): void;
205
+ /** Set the look intent (turn, pitch). */
206
+ setLook(x: number, y?: number): void;
207
+ }
208
+ //#endregion
209
+ //#region src/plugin/systemPlugin.d.ts
210
+ /**
211
+ * What the kernel hands a system on setup. A *system* plugin — unlike an element
212
+ * plugin — produces no scene object; it drives shared runtime state (the camera,
213
+ * input…) each frame. The camera is a kernel primitive (the renderer needs one),
214
+ * so systems receive it and drive it, publishing/consuming capabilities to
215
+ * cooperate (e.g. the camera plugin publishes `roamControl`).
216
+ */
217
+ interface SystemContext {
218
+ /** The current scene (its data keys, start pose, boundary…); also `setScene` on hot-swap. */
219
+ scene: Scene$1;
220
+ /** The render camera the system may drive. */
221
+ camera: PerspectiveCamera;
222
+ /** The canvas, for pointer/keyboard listeners. */
223
+ canvas: HTMLElement;
224
+ /** The three.js scene graph, for systems that manage their own objects (sky…). */
225
+ scene3d: Scene;
226
+ /** The renderer, for systems that need it (e.g. sky IBL generation). */
227
+ renderer: WebGLRenderer;
228
+ /** Shared analog input (joysticks feed it); systems interpret it. */
229
+ input: InputBus;
230
+ /** Capability registry for cross-plugin contracts (terrain, colliders…). */
231
+ capabilities: CapabilityRegistry;
232
+ /** Emit a gallery event. */
233
+ emit: (event: string, payload?: unknown) => void;
234
+ /** Resolve a live scene object by id (e.g. for a framing system). */
235
+ resolve: (id: string) => Object3D | undefined;
236
+ }
237
+ /** A running system: its per-frame update, hot-swap and teardown hooks. */
238
+ interface SystemInstance<Api = unknown> {
239
+ /** Advance the system by the frame delta (ms). */
240
+ update?(deltaMs: number): void;
241
+ /** React to a hot-swapped scene definition. */
242
+ setScene?(scene: Scene$1): void;
243
+ /** Tear down (detach listeners, revoke capabilities). */
244
+ dispose?(): void;
245
+ /**
246
+ * Public API the system exposes to userland/overlay. The kernel maps known
247
+ * system names onto `ctx` (e.g. a `focus` system's api → `ctx.camera`).
248
+ */
249
+ api?: Api;
250
+ }
251
+ /**
252
+ * A system plugin: sets up once against the kernel handles and returns its
253
+ * running instance. Registered alongside element plugins in `plugins`; the
254
+ * kernel tells them apart by shape (`setup` vs `build`).
255
+ */
256
+ interface SystemPlugin<Api = unknown> {
257
+ name: string;
258
+ setup(ctx: SystemContext): SystemInstance<Api>;
259
+ }
260
+ /** Narrow a mixed plugin to a system plugin (has `setup`, not `build`). */
261
+ declare const isSystemPlugin: (plugin: unknown) => plugin is SystemPlugin;
262
+ //#endregion
263
+ //#region src/plugin/roamControl.d.ts
264
+ /** Capability name under which a roaming camera system exposes pose control. */
265
+ declare const ROAM_CONTROL = "roamControl";
266
+ /**
267
+ * Handle a camera plugin publishes so other camera systems can cooperate with
268
+ * it — chiefly a framing/tour system that suspends free-roam while it animates
269
+ * the camera, then reads/writes the pose to hand control back cleanly.
270
+ */
271
+ interface RoamControl {
272
+ /** Enable/disable free-roam input (disabled while another system owns the camera). */
273
+ setEnabled(enabled: boolean): void;
274
+ /** Current pose: world position plus yaw (`phi`) and pitch (`theta`) in radians. */
275
+ getPose(): {
276
+ position: Vector3;
277
+ phi: number;
278
+ theta: number;
279
+ };
280
+ /** Force the pose so free-roam resumes from it. */
281
+ setPose(position: Vector3, phi: number, theta: number): void;
282
+ /** Current eye height above the ground (world units). */
283
+ getEyeHeight(): number;
284
+ }
285
+ //#endregion
286
+ //#region src/plugin/terrain.d.ts
287
+ /** Capability name under which the floor publishes its terrain. */
288
+ declare const TERRAIN = "terrain";
289
+ /**
290
+ * The geometry a terrain consumer relies on — the fields needed to sample the
291
+ * same ground a floor was displaced by (e.g. the water shader). A floor
292
+ * definition satisfies this structurally; the kernel stays floor-agnostic.
293
+ */
294
+ interface TerrainDefinition {
295
+ /** Extent on the ground plane, `[width (x), depth (z)]`. */
296
+ size: Vec2;
297
+ /** Center on the ground plane `[x, z]`. Defaults to `[0, 0]`. */
298
+ center?: Vec2;
299
+ /** Base vertical position (world Y). Defaults to `0`. */
300
+ y?: number;
301
+ /** Grayscale heightmap URL that displaces the ground. */
302
+ heightmap?: string;
303
+ /** Max displacement (world units) at white in the heightmap. */
304
+ heightScale?: number;
305
+ }
306
+ /**
307
+ * The walkable ground, published by the floor: its definition (for shaders that
308
+ * sample the same heightmap), the live height function (heightmap-aware once the
309
+ * image loads) and a promise that resolves once that sampling is in effect.
310
+ */
311
+ interface TerrainCapability {
312
+ definition: TerrainDefinition;
313
+ heightAt: (x: number, z: number) => number;
314
+ /** Resolves once `heightAt` reflects the heightmap (immediately when there is none). */
315
+ ready: Promise<void>;
316
+ }
317
+ //#endregion
318
+ //#region src/plugin/colliders.d.ts
319
+ /** Capability name under which walkable-space obstacles are published. */
320
+ declare const COLLIDERS = "colliders";
321
+ /**
322
+ * A collision obstacle as an oriented box on the XZ plane. The camera controls
323
+ * consume these to keep the visitor out of walls (and any other plugin that
324
+ * wants to block movement can provide more of them). Purely a movement contract
325
+ * — no geometry, no three.js.
326
+ */
327
+ interface Collider {
328
+ /** Box center `[x, z]`. */
329
+ cx: number;
330
+ cz: number;
331
+ /** Unit direction along the box's length. */
332
+ dx: number;
333
+ dz: number;
334
+ /** Half the box length. */
335
+ halfLength: number;
336
+ /** Half the box thickness. */
337
+ halfThickness: number;
338
+ }
339
+ //#endregion
340
+ //#region src/plugin/edges.d.ts
341
+ /** Capability name under which named wall edges are published for hanging. */
342
+ declare const EDGES = "edges";
343
+ /** A named anchor an artwork can hang on: a wall segment resolved to geometry. */
344
+ interface EdgeAnchor {
345
+ a: Vec2;
346
+ b: Vec2;
347
+ height: number;
348
+ thickness: number;
349
+ }
350
+ /** The `name -> anchor` index a provider (e.g. the wall plugin) publishes. */
351
+ type EdgeIndex = ReadonlyMap<string, EdgeAnchor>;
352
+ //#endregion
353
+ //#region src/plugin/eyeHeight.d.ts
354
+ /**
355
+ * Capability name under which the visitor's eye height (world units) is
356
+ * published — the default vertical placement for wall-hung artworks. The kernel
357
+ * provides it from the camera start; a camera plugin will own it later.
358
+ */
359
+ declare const EYE_HEIGHT = "eyeHeight";
360
+ //#endregion
4
361
  //#region src/createGallery.d.ts
5
- interface GalleryOptions {
362
+ /** MSAA sample count for antialiasing. `0` disables it. */
363
+ type Antialias = 0 | 2 | 4 | 8;
364
+ /** Toggleable rendering features. All can be flipped live via `setRender`. */
365
+ interface RenderOptions {
366
+ /**
367
+ * Antialiasing as MSAA sample count (`0` off, `2`/`4`/`8`). Applied to the
368
+ * post-process render target so it survives SSAO/bloom and toggles live,
369
+ * unlike the canvas's native MSAA. Defaults to `4`.
370
+ */
371
+ antialias?: Antialias;
372
+ /** Screen-space ambient occlusion as a post-process. Defaults to `false`. */
373
+ ssao?: boolean;
374
+ /**
375
+ * Bloom strength: a soft glow bleeding out of the brightest areas. `0` off;
376
+ * gentle around `0.3`, strong around `1`. Defaults to `0`.
377
+ */
378
+ bloom?: number;
379
+ /** Real-time shadow mapping (PCF). Defaults to `true`. */
380
+ shadows?: boolean;
381
+ /**
382
+ * Cardboard / stereoscopic mode: split the view into a left/right eye pair for
383
+ * a phone-in-a-headset viewer. Skips post-processing while active. Defaults to
384
+ * `false`.
385
+ */
386
+ cardboard?: boolean;
387
+ /**
388
+ * Interocular distance for cardboard mode, in world units. The physical ≈6.4 cm
389
+ * is too much parallax to fuse comfortably through cardboard lenses, so this
390
+ * defaults to `3`; tune it live for the viewer. `0` flattens to mono.
391
+ */
392
+ eyeSeparation?: number;
393
+ }
394
+ interface GalleryOptions extends RenderOptions {
6
395
  /** Canvas the gallery renders into. */
7
396
  canvas: HTMLCanvasElement;
8
397
  /** Background color. Defaults to a soft gray. */
9
398
  background?: string;
10
- antialias?: boolean;
399
+ /**
400
+ * Runtime plugins: element plugins materialize a scene key; system plugins
401
+ * (e.g. a camera) drive shared runtime state. Mixed freely — the kernel tells
402
+ * them apart by shape.
403
+ */
404
+ plugins?: (EnginePlugin | SystemPlugin)[];
405
+ }
406
+ /**
407
+ * Drive the free-roam camera from outside the engine — e.g. on-screen touch
408
+ * controls in the overlay. Inputs are analog (`-1..1`) and held until changed.
409
+ */
410
+ interface ControlsApi {
411
+ /** Walk forward (`+1`) / back (`-1`); optional strafe right (`+1`) / left (`-1`). */
412
+ setMoveInput(forward: number, strafe?: number): void;
413
+ /** Turn right (`+1`) / left (`-1`); optional look up (`+1`) / down (`-1`). */
414
+ setLookInput(x: number, y?: number): void;
415
+ }
416
+ /** Control the HDRI sky / environment at runtime, for behavior code. */
417
+ interface EnvironmentApi {
418
+ /** Set the visible sky background brightness (`0` = black). */
419
+ setBackgroundIntensity(value: number): void;
11
420
  }
12
421
  /**
13
422
  * High-level API handed to behavior code. Deliberately NOT raw three.js: this is
14
423
  * the supported surface. Reach into `three` only as a documented escape hatch.
15
424
  */
16
425
  interface GalleryContext {
17
- /** Resolve the live object for a wall/artwork `id`. */
426
+ /** Resolve the live object for a wall/artwork/light `id`. */
18
427
  entity(id: string): Object3D | undefined;
428
+ /** Control scene lights (dim, set intensity/color) by `id`. */
429
+ readonly lights: LightsApi;
430
+ /** Control background audio (play, pause, fade) by `id`. */
431
+ readonly media: MediaController;
432
+ /** Drive the camera externally (on-screen touch controls, etc.). */
433
+ readonly controls: ControlsApi;
434
+ /** Control the HDRI sky / environment at runtime. */
435
+ readonly environment: EnvironmentApi;
436
+ /** Drive the procedural sky's time of day. */
437
+ readonly sky: SkyApi;
438
+ /** Animate the camera to frame artworks (e.g. when an info panel opens/closes). */
439
+ readonly camera: CameraApi;
440
+ /** Control video screens (play, pause, show/hide) by `id`. */
441
+ readonly video: VideoApi;
19
442
  /** Escape hatch to the underlying three.js objects for advanced use. */
20
443
  readonly three: {
21
444
  scene: Scene;
@@ -36,8 +459,12 @@ interface Gallery {
36
459
  on(event: string, handler: (payload?: unknown) => void): () => void;
37
460
  /** Emit a named event to subscribers. */
38
461
  emit(event: string, payload?: unknown): void;
462
+ /** Run a handler every frame with the frame delta in ms; returns unsubscribe. */
463
+ onFrame(handler: (deltaMs: number) => void): () => void;
39
464
  /** Resize the renderer/camera to the given pixel size. */
40
465
  resize(width: number, height: number): void;
466
+ /** Toggle rendering features (antialias, ssao, bloom, shadows) live. */
467
+ setRender(options: RenderOptions): void;
41
468
  readonly ctx: GalleryContext;
42
469
  }
43
470
  /**
@@ -57,64 +484,80 @@ declare function createGallery(scene: Scene$1, options: GalleryOptions): Gallery
57
484
  */
58
485
  declare class SceneManager {
59
486
  private readonly root;
60
- private readonly walls;
61
- private readonly artworks;
62
- constructor(root: Scene);
487
+ private readonly plugins;
488
+ private readonly capabilities;
489
+ /** Mounted plugin elements, per kind, keyed by element id ("" for singletons). */
490
+ private readonly pluginElements;
491
+ constructor(root: Scene, plugins?: EnginePlugin[], capabilities?: CapabilityRegistry);
63
492
  reconcile(scene: Scene$1): void;
64
- private reconcileWalls;
65
- private reconcileArtworks;
66
- /** Look up the live three.js object for a wall or artwork `id`. */
493
+ /**
494
+ * Reconcile every registered plugin's elements by content: an element
495
+ * rebuilds when its definition changes or when a capability it depends on
496
+ * was re-provided (the capability versions are part of the hash).
497
+ */
498
+ private reconcilePlugins;
499
+ private removePluginElement;
500
+ /** Advance time-based plugin elements (e.g. water ripple). Call once per frame. */
501
+ updateElements(deltaMs: number): void;
502
+ /** Run every element's auxiliary pre-render pass (e.g. water reflection). */
503
+ beforeRender(renderer: WebGLRenderer, scene: Scene, camera: PerspectiveCamera): void;
504
+ /** Look up the live three.js object for any plugin element `id`. */
67
505
  get(id: string): Object3D | undefined;
506
+ /** Live objects of one plugin kind, keyed by `id` — for that plugin's controller. */
507
+ elementsOf(kind: string): ReadonlyMap<string, Object3D>;
68
508
  dispose(): void;
69
509
  }
70
510
  //#endregion
71
- //#region src/controls/FreeRoamControls.d.ts
72
- interface FreeRoamOptions {
73
- /** Square half-extent that clamps XZ movement. */
74
- bounds?: number;
75
- /** Starting position. */
76
- position?: Vector3;
77
- /** Starting yaw in radians. */
78
- yaw?: number;
79
- }
80
- /**
81
- * First-person, free-roaming camera controls ported from the original Virtual
82
- * Gallery: drag-to-look with the mouse, WASD to walk, a subtle head-bob while
83
- * moving, and square boundary clamping. The cardboard / device-orientation path
84
- * was intentionally dropped.
85
- *
86
- * Framework-agnostic: construct it with a camera and the canvas element, call
87
- * `attach()`, then `update(delta)` once per frame.
88
- */
89
- declare class FreeRoamControls {
90
- bounds: number;
511
+ //#region src/builders/texture.d.ts
512
+ /**
513
+ * Apply a `SurfaceTexture` to a standard material. Returns whether a second UV
514
+ * set (`uv1`) is needed — three samples `aoMap` from it, so the geometry must
515
+ * provide one.
516
+ */
517
+ declare const applyTexture: (material: MeshStandardMaterial, texture: SurfaceTexture) => boolean;
518
+ //#endregion
519
+ //#region src/interaction/InteractionController.d.ts
520
+ /**
521
+ * Pointer picking for artworks: hovering a piece's click target (its label, or
522
+ * the piece itself when it has none) draws a pulsing red frame and shows a
523
+ * pointer cursor; clicking it emits `artwork:select { id }`. Targets are marked
524
+ * in the scene graph (`userData.pickTarget`/`pickInfo`) by the artwork builder,
525
+ * so this just raycasts and walks up to find them. An optional per-id radius
526
+ * gates interaction to when the camera is reasonably close.
527
+ */
528
+ declare class InteractionController {
91
529
  private readonly camera;
92
- private readonly domElement;
93
- private readonly mouse;
94
- private readonly keyboard;
95
- private readonly headBob;
96
- private readonly look;
97
- private rotation;
98
- private translation;
530
+ private readonly canvas;
531
+ private readonly scene;
532
+ private readonly emit;
533
+ private readonly canInteract;
534
+ private readonly raycaster;
535
+ private readonly pointer;
536
+ private over;
537
+ private downPos;
538
+ private radii;
539
+ private hovered;
540
+ private time;
541
+ private readonly highlight;
542
+ private highlightMat;
99
543
  private readonly handlers;
100
- constructor(camera: PerspectiveCamera, domElement: HTMLElement, options?: FreeRoamOptions);
544
+ constructor(camera: PerspectiveCamera, canvas: HTMLCanvasElement, scene: Scene, emit: (event: string, payload?: unknown) => void, canInteract: () => boolean);
545
+ /** Per-artwork max interaction distance (XZ). Absent id = no distance gate. */
546
+ setRadii(radii: Map<string, number>): void;
101
547
  attach(): void;
102
548
  detach(): void;
103
- /** Advance the camera by `delta` seconds of input. */
104
- update(delta: number): void;
549
+ private setPointer;
550
+ private onMove;
551
+ private onDown;
552
+ private onUp;
553
+ /** Resolve the nearest pickable artwork under the pointer, honoring the gate. */
554
+ private raycast;
555
+ /** Recompute hover state and animate the highlight. Call once per frame. */
556
+ update(deltaMs: number): void;
557
+ private clearHighlight;
558
+ /** Position a fresh pulsing red frame over the picked target's front face. */
559
+ private buildHighlight;
105
560
  }
106
561
  //#endregion
107
- //#region src/builders/wall.d.ts
108
- /** Build the three.js object that materializes a `Wall` definition. */
109
- declare function buildWall(wall: Wall): Object3D;
110
- //#endregion
111
- //#region src/builders/artwork.d.ts
112
- /**
113
- * Build the three.js object for an `Artwork`, placing it on its wall. The piece
114
- * is positioned in the wall's local plane via `offset` and nudged forward along
115
- * the wall normal so it sits in front of the surface.
116
- */
117
- declare function buildArtwork(artwork: Artwork, wall: Wall): Object3D;
118
- //#endregion
119
- export { FreeRoamControls, type FreeRoamOptions, type Gallery, type GalleryContext, type GalleryOptions, SceneManager, buildArtwork, buildWall, createGallery };
562
+ export { type Antialias, type BuiltElement, COLLIDERS, type CameraApi, CapabilityRegistry, type Collider, type ControlsApi, EDGES, EYE_HEIGHT, type EdgeAnchor, type EdgeIndex, type ElementController, type EngineContext, type EnginePlugin, type EnvironmentApi, type FocusOptions, type Gallery, type GalleryContext, type GalleryOptions, InputBus, InteractionController, type LightSet, type LightSetOptions, type LightsApi, type MediaController, ROAM_CONTROL, type RenderOptions, type RoamControl, SceneManager, type SkyApi, type SystemContext, type SystemInstance, type SystemPlugin, TERRAIN, type TerrainCapability, type TerrainDefinition, type VideoApi, applyTexture, createGallery, isSystemPlugin };
120
563
  //# sourceMappingURL=index.d.cts.map