jailedthreejs
v0.9.5
Published
Dedicated To Willson :D, A small, fast and lightweight Three.js framework.
Downloads
257
Maintainers
Readme
JailedThreeJS
A CSS-first layer on top of Three.js.
Define a scene with HTML inside a <cell>, style objects with CSS custom properties, and attach behavior with plain JS. JailedThreeJS creates the renderer, scene, cameras, resize handling, and object mapping for you.
What It Does
- Maps DOM tags to
THREE.Object3Dinstances (<mesh>,<group>,<perspectivecamera>, etc.) - Applies CSS custom properties to Three.js objects (
--position,--rotation,--scale,--material-*, ...) - Supports DOM-style interaction (
onclick,onmouseover,ondblclick,oncontextmenu, ...) - Supports CSS pseudo-classes on 3D objects (
:hover,:focus,:active) - Supports transitions and CSS
@keyframes-driven animation of custom props - Supports basic asset references (
cube,sphere,plane,torus) plus CSS-defined asset rules
Identity Mapping (Important)
Runtime object identity now maps like this:
DOM id->Object3D.nameDOM class list->Object3D.classList(compat alias) andobject.userData.classList
Examples:
<mesh id="box" class="hero selected"></mesh>convict.name === "box"convict.classListis['hero', 'selected']
Notes:
convict.classListis a JailedThreeJS compatibility alias (not native Three.js API).convict.userData.domIdandconvict.userData.classListare also maintained.
Install
Install with three:
npm install jailedthreejs threeThen import from the package:
import { JThree, Cell } from 'jailedthreejs';Package entrypoint notes:
- npm publishes the library build from
dist/lib/
Minimal Example
<cell id="demo" style="display:block;width:640px;height:360px">
<perspectivecamera id="cam" render></perspectivecamera>
<directionallight id="sun"></directionallight>
<mesh id="box" class="scene-object hero" onclick="spinBox()"></mesh>
</cell>
<style>
#cam {
--position: (0, 1.5, 5);
}
#sun {
--position: (3, 6, 4);
--intensity: 2;
}
.scene-object {
--geometry: cube;
--position: (0, 0, 0);
--material-color: (0.3, 0.7, 1.0);
--transition: 200ms ease-out;
}
.scene-object:hover {
--scale: (1.08, 1.08, 1.08);
}
.scene-object:active {
--scale: (0.96, 0.96, 0.96);
}
</style>
<script type="module">
import './module/main.js';
import Cell from './module/cell.js';
const cellEl = document.getElementById('demo');
const cell = Cell.getCell(cellEl);
const box = cell.getConvictById('box');
window.spinBox = () => {
box.rotation.y += Math.PI * 0.25;
};
console.log(box.name); // "box"
console.log(box.classList); // ["scene-object", "hero"]
</script>How It Works
1. DOM -> Three.js conversion
Every supported child element inside a <cell> is converted into a matching Three.js object.
- Parent/child DOM nesting becomes scene graph nesting.
- Cameras can be declared in HTML.
- The first camera (or one with
render) becomes the active render camera.
2. CSS painter
Custom properties (--...) are parsed and applied to object properties.
Examples:
--position: (x,y,z)--rotation: (rx,ry,rz)--scale: (sx,sy,sz)--material-color: (r,g,b)--geometry: cube--transition: 250ms ease--animation: bob 1.5s infinite ease-in-out
3. Interaction + pseudo-classes
JailedThreeJS raycasts the scene and updates pseudo-state flags so CSS selectors like these work:
.button:hover.button:active#hero:focus
Supported DOM event attributes on scene elements include:
onclickonmouseoveronmousedownonmouseupondblclickoncontextmenu
Handler functions receive a synthetic event object containing references to:
target3dtargetCelltargetElementpointerPositionoriginalEvt
Runtime API
JThree
Imported from src/module/main.js (or re-exported by src/module/index.js).
JThree.init_convert()- Scans the document for
<cell>elements and converts any not already initialized.
- Scans the document for
Cell
Cell.getCell(cellElement)- Returns the
Cellinstance attached to a<cell>DOM element.
- Returns the
Instance methods:
cell.getConvictById(id)- Returns the Three.js object for a DOM id inside that cell.
cell.getConvictByDom(domElement)- Returns the mapped Three.js object for a DOM element.
cell.getConvictsByClass(className)- Returns all mapped objects in that cell with the class.
cell.addUpdateFunction(fn)- Registers a per-frame callback.
cell.removeUpdateFunction(fn)- Removes a previously registered callback.
cell.removeConvict(object)- Removes an object (and descendants) from the scene and mapping.
cell.dispose()- Cleans up observers, handlers, and canvas.
CSS Value Parsing Rules
JailedThreeJS parses custom property values with a best-effort mapper:
"(1,2,3)"->[1,2,3]"1.25"->1.25"cube"-> built-in asset/object from the asset cache"#otherId-position-x"-> property lookup from another object in the same cell
Assets
Built-ins are available by default:
cubesphereplanetorus
Custom assets can be declared in CSS-like at-rules:
@Ship{
url: "/models/ship.glb";
}
.hero {
--geometry: Ship;
}Supported loader types include GLTF/GLB, FBX, textures, audio, MTL, and material JSON.
Build Outputs
npm run build:lib-> builds the npm library package output todist/lib
Performance Notes (Current)
Recent runtime improvements in this repo include:
- cell-local ID/class lookup indexes (faster
getConvictById/getConvictsByClass) - cached CSS selector lookups with style-change invalidation
- cached keyframe and asset-rule scans with style-change invalidation
- requestAnimationFrame-throttled pointer-move raycasting
- targeted repaints for pseudo-state changes instead of full-cell pseudo repaint on each move
Limitations / Gotchas
- The CSS painter is best-effort and will ignore unsupported custom props.
- Cross-origin stylesheets may not be readable (
cssRulesaccess restrictions); those rules are skipped. - Async assets resolve later; properties may update after the loader completes.
- If you mutate object transforms directly in JS, any later CSS repaint can overwrite those values.
Development Notes
This repo contains the runtime modules and a demo/test page.
- Source + demo live in
src/ - npm package build output lives in
dist/lib/ - demo build output lives in
dist/demo/
License
MIT
