Behavior & the runtime
@scenography/engine is the how: it materializes a scene with three.js, runs
the render loop, and drives a free-roaming first-person camera (drag to look,
WASD or the arrow keys to move, a subtle head-bob while walking).
createGallery
import { createGallery } from '@scenography/engine';
const gallery = createGallery(scene, { canvas });
gallery.start();
The returned Gallery exposes:
| Method | Purpose |
|---|---|
setScene(next) | Apply a new definition, reconciling only what changed. |
start() / stop() | Control the render loop. |
resize(w, h) | Resize renderer and camera. |
on(event, handler) | Subscribe to a named event; returns an unsubscribe fn. |
emit(event, data) | Emit a named event. |
dispose() | Tear down and release GPU resources. |
ctx | The high-level API handed to behavior code. |
The ctx — a high-level API, not raw three.js
Behavior code talks to ctx, not to three.js directly. This keeps three.js
an implementation detail that can be upgraded or swapped without breaking your
code.
const wall = gallery.ctx.entity('north'); // the live object for an id
When you genuinely need it, there is a documented escape hatch to the underlying three.js objects:
const { scene, camera, renderer } = gallery.ctx.three;
Wiring behavior by id
Behavior is connected to data by id, never embedded inside the definition.
That separation is what keeps the definition pure data.
gallery.on('entrance:enter', () => {
// ... react to a zone, play media, move the camera, etc.
});
Zones and triggers are part of the roadmap; the event surface above is the seam they plug into.