three-html-elements
v0.1.0
Published
Place HTML elements in 3D space with Three.js - a lightweight library for integrating HTML content in WebGL scenes
Maintainers
Readme
Three HTML Elements
Place HTML elements in 3D space with Three.js - a lightweight library for integrating HTML content in WebGL scenes.
Features
- Place HTML elements in 3D space with Three.js
- Multiple positioning modes:
- Standard mode: Simple CSS positioning
- Transform mode: Full CSS 3D transforms using matrix3d
- Billboard mode: Always face the camera
- Occlusion: HTML elements can be hidden when behind 3D objects
- Distance-based scaling: Scale HTML elements based on distance from camera
- Full TypeScript support
- Three.js API design pattern
Installation
npm install three-html-elementsBasic Usage
import * as THREE from 'three'
import { HTMLElement3D, HTMLRenderer } from 'three-html-elements'
// Set up Three.js scene
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
camera.position.z = 5
const renderer = new THREE.WebGLRenderer()
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
// Create HTML renderer
const htmlRenderer = new HTMLRenderer(renderer)
// Create HTML element
const htmlElement = new HTMLElement3D({
html: '<div style="padding: 10px; background-color: rgba(0,0,0,0.7); color: white;">Hello Three.js!</div>',
position: [0, 1, 0],
center: true,
occlude: true,
distanceFactor: 10
})
// Add to scene
scene.add(htmlElement)
// Animation loop
function animate() {
requestAnimationFrame(animate)
// Render Three.js scene
renderer.render(scene, camera)
// Render HTML elements
htmlRenderer.render(scene, camera)
}
animate()API Reference
HTMLElement3D
new HTMLElement3D(parameters: HTMLElement3DParameters)Parameters
| Name | Type | Default | Description |
|------|------|---------|-------------|
| html | HTMLElement \| string | (required) | HTML element or HTML string to display |
| position | THREE.Vector3 \| [number, number, number] | [0, 0, 0] | Initial position |
| center | boolean | false | Center the element at its position |
| occlude | boolean \| Object3D[] | false | Hide when behind other objects, can specify which objects |
| transform | boolean | false | Use CSS matrix3d transforms |
| sprite | boolean | false | Always face the camera (billboard) |
| distanceFactor | number | undefined | Scale based on distance from camera |
| zIndexRange | [number, number] | undefined | Z-index range [max, min] based on distance |
| portal | HTMLElement | document.body | Parent element to append to |
| as | keyof HTMLElementTagNameMap | 'div' | Element type for the wrapper |
| wrapperClass | string | undefined | Class name for the wrapper element |
| prepend | boolean | false | Project content behind the canvas |
| fullscreen | boolean | false | Align to the upper-left corner and fill screen |
| calculatePosition | Function | undefined | Custom position calculation function |
| onOcclude | (hidden: boolean) => void | undefined | Callback when visibility changes |
Properties
All properties from THREE.Object3D, plus:
| Name | Type | Description |
|------|------|-------------|
| domElement | HTMLElement | The DOM element container |
| contentElement | HTMLElement | The actual HTML content |
| center | boolean | Whether element is centered |
| occlude | boolean \| Object3D[] | Whether element is occluded by objects |
| transform | boolean | Whether using CSS transform mode |
| sprite | boolean | Whether element acts as a billboard |
| distanceFactor | number \| undefined | Distance-based scaling factor |
| zIndexRange | [number, number] \| undefined | Z-index range |
| prepend | boolean | Whether content is behind the canvas |
| fullscreen | boolean | Whether element fills the screen |
| calculatePosition | Function \| undefined | Custom position calculation function |
| onOcclude | Function \| undefined | Visibility change callback |
Methods
All methods from THREE.Object3D, plus:
| Name | Returns | Description |
|------|---------|-------------|
| dispose() | void | Remove the element from DOM and clean up resources |
| updateOcclusionState(hidden: boolean) | void | Update occlusion state and trigger callback |
HTMLRenderer
new HTMLRenderer(renderer: THREE.WebGLRenderer, parameters?: HTMLRendererParameters)Parameters
| Name | Type | Default | Description |
|------|------|---------|-------------|
| renderer | THREE.WebGLRenderer | (required) | The WebGL renderer |
| domElement | HTMLElement | document.body | Container element for HTML |
| frustumCulling | boolean | true | Enable view frustum culling |
| positionThreshold | number | 1 | Minimum movement threshold to update position |
Methods
| Name | Parameters | Returns | Description |
|------|------------|---------|-------------|
| render | scene: THREE.Scene, camera: THREE.Camera | void | Render HTML elements in the scene |
| dispose | | void | Clean up resources |
Examples
See the examples directory for working examples:
- Basic: Simple HTML elements in 3D space
- Transform: Demonstrating different transform modes
- Occlusion: HTML elements that hide behind 3D objects
- Interactive: Interactive HTML elements that control 3D objects
Advanced Usage
Custom Element Types
You can use any HTML element as the wrapper instead of the default div:
const htmlElement = new HTMLElement3D({
html: '<p>Hello world</p>',
as: 'section',
wrapperClass: 'my-section-wrapper'
})Selective Occlusion
You can specify which objects should occlude the HTML element:
const htmlElement = new HTMLElement3D({
html: '<div>Behind the cube</div>',
occlude: [myCube, mySphere],
onOcclude: (hidden) => {
console.log(`Element is ${hidden ? 'hidden' : 'visible'}`)
}
})Fullscreen and Prepend
// Create a fullscreen overlay behind the canvas
const overlay = new HTMLElement3D({
html: '<div class="overlay">3D UI Overlay</div>',
fullscreen: true,
prepend: true
})Custom Positioning
const htmlElement = new HTMLElement3D({
html: '<div>Custom positioned</div>',
calculatePosition: (object, camera, size) => {
// Custom calculation logic
return [x, y, zIndex] // Return array of coordinates
}
})Comparison with CSS3DRenderer
While Three.js provides CSS3DRenderer for placing HTML in 3D space, Three HTML Elements offers several advantages:
Advanced Features
- Occlusion: HTML elements can be hidden when behind 3D objects
- Distance Scaling: Scale elements based on distance from camera
- Multiple Modes: Choose between simple positioning and full 3D transforms
- Billboard Mode: Make elements always face the camera
Simple API
Three HTML Elements follows the standard Three.js patterns:
// Three.js style API integration
const scene = new THREE.Scene()
const htmlElement = new HTMLElement3D({ html: '<div>Hello</div>' })
scene.add(htmlElement)
// Rendering pattern matches Three.js
renderer.render(scene, camera)
htmlRenderer.render(scene, camera)Performance Optimizations
- Position threshold to reduce DOM updates
- Frustum culling to skip elements outside the view
- Optimized update loop
Implementation Details
Three HTML Elements is inspired by @react-three/drei's HTML component, but designed for vanilla Three.js projects. It:
- Extends THREE.Object3D for seamless scene graph integration
- Uses CSS transforms for proper 3D positioning
- Implements raycasting for occlusion detection
- Handles DOM lifecycle and cleanup automatically
License
MIT
