@objectifthunes/three-book-theatre
v0.6.3
Published
Animated 2D sprite theatre for [@objectifthunes/three-book](https://www.npmjs.com/package/@objectifthunes/three-book) — place characters, elements, and parallax depth scenes on book pages via offscreen canvas textures.
Readme
@objectifthunes/three-book-theatre
Animated 2D sprite theatre for @objectifthunes/three-book — place characters, elements, and parallax depth scenes on book pages via offscreen canvas textures.
Features
- Animated sprites — autonomous 2D characters with idle/walk/action state machine.
- Static elements — place images (trees, props, furniture) at any depth.
- Parallax depth — band-fraction depth model with configurable horizon, ground/sky perspective.
- Optional animations & depth scaling — disable per-sprite/element or book-wide via
SpriteScene.animated/SpriteScene.depthScaling. - Background images — full-page backgrounds with contain/cover/fill fitting.
- Offscreen canvas textures — each
SpriteScenerenders to aTHREE.CanvasTextureready for book pages. - Per-frame sync —
scene.update(dt, book)handles animation ticks and three-book texture clone workaround.
Installation
npm install @objectifthunes/three-book-theatre threeor
pnpm add @objectifthunes/three-book-theatre threePeer dependency: three >= 0.150.0 (ESM).
Quick Start
import * as THREE from 'three';
import { Book, BookContent, StapleBookBinding } from '@objectifthunes/three-book';
import { SpriteScene } from '@objectifthunes/three-book-theatre';
// 1. Create a sprite scene for a page
const spriteScene = new SpriteScene({
width: 512,
height: 512,
background: '#e8d5b5',
horizonFraction: 0.4,
pageDistance: 10,
});
// 2. Add characters and elements
spriteScene.addSprite({
placement: 'ground',
distance: 5,
intrinsicSize: 100,
animated: true, // optional, default true
depthScaling: true, // optional, default true
idleImage: myIdleImg,
walkImage: myWalkImg,
actionImage: myActionImg,
});
spriteScene.addElement({
placement: 'ground',
distance: 8,
intrinsicSize: 60,
depthScaling: true, // optional, default true
image: myTreeImg,
});
// 3. Use the texture on a book page
const content = new BookContent();
content.pages.push(spriteScene.texture);
const book = new Book({ content, binding: new StapleBookBinding(), /* ... */ });
book.init();
// 4. Update every frame
const clock = new THREE.Clock();
function animate() {
requestAnimationFrame(animate);
const dt = clock.getDelta();
spriteScene.update(dt, book); // animate sprites + sync textures
book.update(dt);
renderer.render(scene, camera);
}
animate();Sprite State Machine
Each Sprite cycles autonomously through three states:
| State | Behaviour |
|-------|-----------|
| idle | Stand still, display idleImage |
| walk | Move to a random position, display walkImage |
| action | Play an action at current position, display actionImage |
Transitions happen automatically based on internal timers. Provide whichever images you have — missing states are skipped.
Depth Model
Objects are positioned using a band-fraction model:
placement: 'ground'— items sit on the ground plane, scaled by distance from the viewer.placement: 'sky'— items float in the sky region above the horizon.distance— depth value (larger = farther away = smaller).horizonFraction— where the horizon line sits (0 = top, 1 = bottom).
Animations & Depth Scaling
Both features are enabled by default and can be toggled at two levels:
Per-sprite / per-element — set animated or depthScaling on individual items:
sprite.animated = false; // freeze this sprite (stops state machine)
sprite.depthScaling = false; // render at intrinsicSize regardless of depth
element.depthScaling = false; // same for elementsScene-wide — use SpriteScene.animated / SpriteScene.depthScaling to override all items at once:
spriteScene.animated = false; // freeze ALL sprites in this scene
spriteScene.depthScaling = false; // disable depth scaling for ALL itemsScene-level defaults can also be set at construction time:
const scene = new SpriteScene({
animated: false, // all sprites start frozen
depthScaling: false, // all items render at intrinsicSize
});Newly added sprites/elements inherit the current scene-level defaults.
Texture Sync
three-book's renderer clones textures on first assignment and never calls needsUpdate on the clones. SpriteScene.update(dt, book) handles this by traversing the book's Object3D tree and marking matching materials dirty. Call it every frame.
API Surface
| Category | Exports |
|----------|---------|
| Core | SpriteScene, SpriteSceneOptions, SpriteUpdateOptions, ElementUpdateOptions |
| Sprites | Sprite, SpriteState, SpriteOptions |
| Elements | Element, ElementOptions |
| Base | Positionable, SpritePlacement |
| Perspective | groundR, skyR, depthScale, renderedSize |
| Utilities | drawImageFit, ImageFit |
Development
From the workspace root:
pnpm install
pnpm build # build the library
pnpm dev # build library + start demo app