A library for attaching dynamic HTML overlays to Three.js Object3D instances with distance-based scaling, rotation, auto-centering, and DOM culling.
npm install sorcherer tag and have them automatically update (with culling, distance‑based scaling, rotation via CSS, auto‑centering, dynamic variables, and more) based on your 3D scene’s state.
Tag
Tag: Easily declare overlay elements with custom attributes.
rotate property. [!Currently Broken : D!]
$dogCount=20$) that become accessible as properties on the overlay instance.
Sorcherer.instancesById and clone overlays easily using the attachClone method.
bash
npm install sorcherer
`
Or clone the repository directly from GitHub.
Usage
$3
Use Sorcherer as an ES module:
`js
import { Sorcherer } from 'sorcherer';
`
Sorcherer expects three to be available as an ES module as well.
$3
Define overlays in your HTML with a custom tag. Each child element with an idm attribute is bound to a Three.js Object3D whose .name matches that idm.
Supported attributes on each child:
- idm="cube" – Name of the target Object3D (must match object.name).
- simulate3D="true" – Enable distance-based scaling of the overlay.
- simulateRotation="true" – Rotate the overlay with the object (around Z) via CSS transform.
- offset="x,y,z" – Optional world-space offset as a comma-separated vector, e.g. "0,0.5,0".
- autoCenter="true" – Auto-center the overlay around the computed screen position.
- scaleMultiplier="1.5" – Multiplies the distance-based scale factor.
Inside the element you can use dynamic variable placeholders:
- $varName$
- $varName=defaultValue$
At runtime these become properties on the corresponding Sorcherer instance. For example, $dogCount=0$ creates instance.dogCount which you can update from your render loop.
Example block:
`html
simulate3D="true"
simulateRotation="true"
autoCenter="true"
offset="0,0.8,0">
$label=Magic Cube$
$3
Below is a minimal example using Sorcherer.bootstrap, which replaces the older pattern of manually calling:
`js
Sorcherer.registerObject3D(cube);
Sorcherer.attachFromRealm();
Sorcherer.autoSetup(camera, renderer);
`
HTML:
`html
Sorcherer Example
simulate3D="true"
simulateRotation="true"
autoCenter="true"
offset="0,0.8,0">
$label=Magic Cube$
API Reference
$3
- Sorcherer.bootstrap(scene, camera, renderer, options?)
High-level convenience that wires everything up in one call. It:
1. Registers all named objects in scene (via registerScene) if autoRegister is true.
2. Scans the DOM for tags and attaches overlays if autoAttach is true.
3. Starts the auto-update loop (via autoSetup).
`ts
Sorcherer.bootstrap(
scene: THREE.Scene,
camera: THREE.Camera,
renderer: THREE.Renderer,
options?: {
interval?: number; // minimum ms between overlay updates (default: 16)
autoAttach?: boolean; // default: true
autoRegister?: boolean // default: true
}
)
`
- Sorcherer.registerScene(scene)
Traverses a Three.js scene (or any Object3D subtree) and registers every object that has a non-empty .name:
`js
Sorcherer.registerScene(scene);
`
This is what bootstrap uses internally when autoRegister: true.
- Sorcherer.registerObject3D(object)
Registers a single Object3D using its name property as the key:
`js
cube.name = 'cube';
Sorcherer.registerObject3D(cube);
`
- Sorcherer.attachFromRealm(root?)
Scans the DOM for tags (optionally under a specific root element) and, for each child element with an idm attribute, creates and attaches a Sorcherer overlay instance bound to the registered Object3D with the same name.
`ts
Sorcherer.attachFromRealm(root?: Document | Element);
`
You rarely need to call this manually if you use bootstrap.
- Sorcherer.autoSetup(camera, renderer, interval?)
Starts the auto-update loop that calls bufferAll(camera, renderer) on a throttled requestAnimationFrame loop.
`ts
Sorcherer.autoSetup(
camera: THREE.Camera,
renderer: THREE.Renderer,
interval?: number // minimum ms between updates, default 16
);
`
Normally invoked for you by bootstrap.
- Sorcherer.stopAutoSetup()
Stops the auto-update loop started by autoSetup or bootstrap.
`js
Sorcherer.stopAutoSetup();
`
- Sorcherer.bufferAll(camera, renderer)
Updates all active overlays:
- Computes the camera frustum.
- Performs frustum culling per target object.
- Calls bufferInstance(camera, renderer) on visible overlays.
- Hides overlays whose objects are outside the camera frustum.
You usually don’t call this directly; it’s driven by autoSetup.
- Sorcherer.defaultScaleMultiplier
Global default for distance-based scaling (used when an instance does not specify its own scaleMultiplier).
`js
Sorcherer.defaultScaleMultiplier = 1.5;
`
- Sorcherer.instancesById
A plain object mapping Object3D.name → overlay instance:
`js
const cubeOverlay = Sorcherer.instancesById['cube'];
cubeOverlay.dogCount = '42';
`
- Sorcherer.elements
Alias for Sorcherer.instancesById (handy shorter name):
`js
const overlays = Sorcherer.elements;
overlays.cube.label = 'Magic Cube';
`
$3
A Sorcherer instance is created either:
- Internally by attachFromRealm when it processes a child, or
- Manually via new Sorcherer(object, ...).
Constructor:
`ts
new Sorcherer(
object: THREE.Object3D,
offset?: THREE.Vector3, // default: (0,0,0)
simulate3D?: boolean, // default: false
simulateRotation?: boolean, // default: false
autoCenter?: boolean, // default: false
scaleMultiplier?: number // default: Sorcherer.defaultScaleMultiplier
);
`
- attach(innerHTML)
Binds an HTML template to the overlay. Parses dynamic variable placeholders of the form $var$ and $var=default$, stores them, and immediately renders the overlay.
`js
const overlay = new Sorcherer(cube, new THREE.Vector3(0, 0.8, 0), true, true, true);
overlay.attach(
);
`
- renderDynamicVars()
Rebuilds the current HTML from this.template by substituting the latest dynamicVars values into all $var$ placeholders. Normally you don’t need to call this manually because setDynamicVar and direct property setters call it for you.
- setDynamicVar(varName, value) / getDynamicVar(varName)
Low-level accessors for dynamic variables:
`js
overlay.setDynamicVar('health', '75');
console.log(overlay.getDynamicVar('health'));
`
- Dynamic variable property access
For each $varName$ placeholder in the template, attach() defines a property on the instance:
`html
Health: $health=100$
`
`js
const cubeOverlay = Sorcherer.instancesById['cube'];
cubeOverlay.health = '80'; // updates the DOM
console.log(cubeOverlay.health); // "80"
`
- bufferInstance(camera, renderer)
Repositions and transforms the overlay for its target object:
- Computes world position (plus offset).
- Projects to screen space and converts to pixel coordinates.
- Applies optional autoCenter, distance-based scaling (simulate3D), and Z-rotation (simulateRotation).
- Adjusts z-index based on distance.
- Shows or hides the overlay as needed.
This is called automatically from bufferAll.
- dispose()
Removes the overlay DOM element, unregisters it from allLoadedElements, and clears its entry from instancesById (if any). Use this when an overlay is no longer needed.
`js
const overlay = Sorcherer.instancesById['cube'];
overlay.dispose();
`
- attachClone(targetObject, newName?)
Clones an existing overlay (including its template and current dynamicVars) and attaches the clone to another Object3D.
`js
const srcOverlay = Sorcherer.instancesById['cube'];
const clone = srcOverlay.attachClone(otherMesh, 'otherMeshName');
clone.label = 'Clone HUD';
`
If newName is provided, targetObject.name is set to that value and the clone is stored in Sorcherer.instancesById[newName]`.