Skip to main content

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 in defineScene so 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

PackageWhat it is
@scenography/sceneThe scene language: serializable data + validation. Zero three.js.
@scenography/engineThe 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/overlayA framework-agnostic DOM overlay (HUD) layered over the canvas.
@scenography/overlay-presetsBatteries-included overlay widgets and a defaultPreset (daisyUI-styled).
@scenography/reactReact bindings: a declarative <Gallery> component.
@scenography/propsOptional, tree-shakeable catalog of set-dressing objects.

Continue with Installation and the Quick start.