Skip to main content

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';
import { wall } from '@scenography/plugin-wall';
import { artwork } from '@scenography/plugin-artwork';
import { fpc } from '@scenography/plugin-fpc';

const gallery = createGallery(scene, {
canvas,
plugins: [wall(), artwork(), fpc()],
});
gallery.start();

Runtime plugins​

The kernel renders nothing on its own — a camera, a canvas and a render loop. Everything else is a plugin you pass in options.plugins:

  • Element plugins (wall(), artwork(), floor(), water(), sky(), audio(), …) materialize the scene key they own into three.js objects and keep them reconciled as the definition changes.
  • System plugins drive shared, per-frame runtime state: fpc() (the free-roaming first-person camera), focus() (frame a clicked artwork) and cardboard() (stereoscopic VR).

Order matters: a plugin that publishes a capability (the floor's terrain, a wall's colliders) must come before the plugins that consume it.

The returned Gallery exposes:

MethodPurpose
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.
ctxThe 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.