npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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 SpriteScene renders to a THREE.CanvasTexture ready for book pages.
  • Per-frame syncscene.update(dt, book) handles animation ticks and three-book texture clone workaround.

Installation

npm install @objectifthunes/three-book-theatre three

or

pnpm add @objectifthunes/three-book-theatre three

Peer 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 elements

Scene-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 items

Scene-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