scenography
scenography is a library for building declarative 3D art galleries on top of a three.js engine. You describe a space as plain data — walls, artworks, a camera — and the engine materializes it and runs it.
Core principle: data vs. runtime
The single most important rule. Two layers, never mixed:
- Definition = pure data. Fully serializable to JSON. No three.js, no
closures, no functions. This is what an editor produces, what a database
stores, what travels over the network. It lives in
@scenography/scene. - Behavior = code. Triggers, scripts, render logic. Registered by
reference and connected to the data by
id— never embedded inside the definition. It lives in@scenography/engine.
A scene definition must always survive a JSON.parse(JSON.stringify(scene))
round-trip unchanged.
Elements are plugins
Every scene element — walls, artworks, floors, water, sky, audio… — is a plugin, and each plugin comes in two halves that mirror the data/runtime split:
- a data half (e.g.
wallData), registered indefineSceneso its scene key is understood and validated; - a runtime half (e.g.
wall()), handed to the gallery so it materializes into three.js.
You only pull in the elements you use, and the kernel itself ships no elements.
import { defineScene } from '@scenography/scene';
import { wallData } from '@scenography/plugin-wall/data';
import { artworkData } from '@scenography/plugin-artwork/data';
// Layer 1 — DATA. Serializable. Data plugins validate the keys they own.
const scene = defineScene(
{
walls: [
{
id: 'room',
path: [
[300, -300],
[-300, -300],
[-300, 300],
],
edges: [{ segment: 0, name: 'north' }],
},
],
artworks: [
{
id: 'lucho',
location: { type: 'wall', edge: 'north', position: '50%' },
src: '/lucho.jpg',
size: [120, 160],
},
],
camera: { start: { position: [0, 170, 0] } },
},
[wallData, artworkData],
);
import { createGallery } from '@scenography/engine';
import { wall } from '@scenography/plugin-wall';
import { artwork } from '@scenography/plugin-artwork';
import { fpc } from '@scenography/plugin-fpc';
// Layer 2 — CODE. Runtime plugins materialize the scene; behavior wires by id.
const gallery = createGallery(scene, {
canvas,
plugins: [wall(), artwork(), fpc()],
});
gallery.start();
The packages
| Package | What it is |
|---|---|
@scenography/scene | The scene language: serializable data + validation. Zero three.js. |
@scenography/engine | The runtime: materializes a scene with three.js and runs it. |
@scenography/plugin-* | Scene elements, one package each: wall, artwork, floor, water, sky, audio, light, model, video, plus the system plugins fpc (roaming), focus (framing) and cardboard (stereo VR). Each exposes a runtime half and, for elements, a ./data half. |
@scenography/overlay | A framework-agnostic DOM overlay (HUD) layered over the canvas. |
@scenography/overlay-presets | Batteries-included overlay widgets and a defaultPreset (daisyUI-styled). |
@scenography/react | React bindings: a declarative <Gallery> component. |
@scenography/props | Optional, tree-shakeable catalog of set-dressing objects. |
Continue with Installation and the Quick start.