Skip to content

Components

Lunchbox 2 contains:

  • Built-in components
  • Several automatically-registered ThreeJS components
  • The ability to add your own components via extend

Built-in components

<three-lunchbox> wrapper

The <three-lunchbox> wrapper handles several common use cases for ThreeJS scenes. It automatically creates a scene, WebGLRenderer, and camera, and adds a canvas to the DOM that stretches to fit its container.

Available attributes are:

NameDefault valueNotes
backgroundnullBackground color of the scene. Any ThreeJS color representation will work.

<three-lunchbox background="blue">
<three-lunchbox background="#0f0">
(etc)
cameranullOptions to pass to the default camera. Accepts an object that is parsed and whose values are sent to the camera.

Nested values can be set by replacing dot notation with a dash.

Set camera.position.z to 5:
<three-renderer camera='{"position-z": 5}'>

Set camera.position to 1, 2, 3:
<three-renderer camera='{"position": [1, 2, 3]}'>
camera-args[]Array of args to pass to the camera when it is instantiated.
dprInfinityDevice pixel ratio. Will automatically adjust to the screen's DPR if set to Infinity.
dispatch-after-renderfalseSet to true to dispatch an afterrender CustomEvent after every render. See <three-lunchbox> events.
dispatch-before-renderfalseSet to true to dispatch a beforerender CustomEvent before every render. See <three-lunchbox> events.
headlessfalseSet to true to prevent automatic WebGLRenderer initialization. Useful in unit tests, for example.
manual-renderfalseSet to true to prevent automatic rendering. Note you'll need to call renderThree() yourself if this is the case.
renderernullOptions to pass to the default renderer. Accepts an object that is parsed and whose values are sent to the renderer. See camera for formatting.
renderer-args[]Array of args to pass to the renderer when it is instantiated.
scenenullOptions to pass to the default scene. Accepts an object that is parsed and whose values are sent to the scene. See camera for formatting.

<three-lunchbox> Events

List of events:

NamePropertiesNotes
three-ready{ lunchbox: /** The three-lunchbox element */ }Emitted when the scene, renderer, and camera are created

Note that the events emitted by <three-lunchbox> are CustomEvents, so the properties listed below are contained in a detail property. For example:

ts
const lunchbox = document.createElement('three-lunchbox') as ThreeLunchbox;
lunchbox.addEventListener('three-ready', (evt: CustomEvent<{ lunchbox: ThreeLunchbox }>) => {
    console.log('lunchbox:', evt.detail.lunchbox);
});

The three property of <three-lunchbox>

A three-lunchbox component contains a property called three with ThreeJS details. For example:

js
const lunchbox = document.querySelector('three-lunchbox');
console.log(lunchbox.three);

Current methods/properties of three are:

PropertyNotes
cameraThe component's camera.
rendererThe component's renderer.
sceneThe component's scene.

In TypeScript, you can get type completion by querying the ThreeLunchbox type:

ts
import { type ThreeLunchbox } from 'lunchboxjs';
const lunchbox = document.querySelector<ThreeLunchbox>('three-lunchbox');
console.log(lunchbox?.three);

Customizing your lunchbox

See here for instructions on customizing Lunchbox's scene, camera, or renderer.

Other built-in <three-lunchbox> properties and methods

Other available properties and methods include:

PropertyNotes
renderThree(scene?, camera?)Manually render the default scene with the default camera. Optionally pass a custom override scene and camera.

TypeScript example:

ts
import { type ThreeLunchbox } from 'lunchboxjs';
const lunchbox = document.querySelector<ThreeLunchbox>('three-lunchbox');
// manually render
lunchbox?.renderThree();

<html-anchor>

<html-anchor> makes the .position of its parent available as CSS vars (--left and --top, from the top left of the canvas).

For example, you can create this:

with this:

html
<three-lunchbox style="position: relative;">
  <three-mesh position-z="-5">
    <html-anchor>
        <!-- `--left` and `--top` are set automatically by <html-anchor> -->
        <div style="position: absolute; left: var(--left); top: var(--top);">
            HTML Label
        </div>
    </html-anchor>
    <torus-knot-geometry></torus-knot-geometry>
    <mesh-normal-material></mesh-normal-material>
  </three-mesh>
</three-lunchbox>

<html-anchor> will also have a class called in-frustum present if its 3D parent point is in the frustum.

Full list of CSS vars set on <html-anchor> (and therefore provided to children):

CSS var name/classNotes
--distance-from-cameraDistance from object to camera. Lower value = closer, which corresponds to a higher z-index in CSS.

When subtracted from a larger value and rounded, this can be used to correctly layer DOM elements based on their 3D parents.

Example using CSS round():

z-index: round(1000 - var(--distance-from-camera) * 100);
--in-frustumWhether the 3D parent's position is present in the main camera's frustum. 0 if not present or 1 if present.

DOM elements will still appear onscreen if they're directly behind the camera, so you can use this var to determine if they should be visible and interactive or not. (Note you can also use the presence or absence of the class in-frustum on the <html-anchor> element.)
in-frustumClass name added to <html-anchor> when the target position is in the camera's frustum
--leftPixels from the left of the main canvas
--topPixels from the top of the main canvas

Auto-registered components

All ThreeJS classes listed here can be used out of the box with Lunchbox 2. Elements must be separated by a dash if the class name is two or more words:

html
<!-- right -->
<box-geometry></box-geometry>

<!-- wrong -->
<boxGeometry></boxGeometry>

If the class name is one word, prepend three- to the element name:

html
<!-- right -->
<three-mesh></three-mesh>

<!-- wrong -->
<mesh></mesh>

See core concepts for attribute notes.

Universal component attributes

All components registered or extended through Lunchbox 2 have the following attributes:

NameDefault valueNotes
try-add-onceBy default, components poll for a suitable parent element (ie, one with an instance or three.scene property) every frame until they find a parent. Set this attribute to true to only try adding once on insertion into the DOM.

The instance property

All auto-registered components and components created by extend (see below) contain an instance property that holds the underlying ThreeJS object. For example:

html
<box-geometry></box-geometry>

<script>
const boxGeometry = document.querySelector('box-geometry');
console.log(boxGeometry.instance); // logs the BoxGeometry held by the component
</script>

In TypeScript, this you can get type completion with the Lunchbox generic type:

ts
import { type Lunchbox } from 'lunchboxjs';
import * as THREE from 'three';

const boxGeometry = document.querySelector<Lunchbox<THREE.BoxGeometry>>('box-geometry');
console.log(boxGeometry?.instance); // logs the BoxGeometry held by the component

You can do anything with an instance that you would do with a standard ThreeJS object - for example:

js
const mesh = document.querySelector('three-mesh');
// add a child to the selected mesh
mesh.instance.add(new THREE.Mesh(
    new THREE.BoxGeometry(),
    new THREE.MeshBasicMaterial(),
));

This is a contrived example, since it would usually be easier to add a child via another <three-mesh> element; doing so also handles disposal automatically when removing the element from the DOM, while in the example above you would need to handle disposal manually.

Accessing instance is most useful when handling animations or large quantities of components/updates that would otherwise be expensive to add in the DOM.

Custom components via extend

You can add your own components via the extend command. For example, a common use case is to add OrbitControls:

js
import { extend } from 'lunchboxjs';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

extend('orbit-controls', OrbitControls);

Now you can add an <orbit-controls> component:

html
<three-lunchbox camera="{ 'position-z': 5 }">
    <three-mesh>
        <torus-knot-geometry></torus-knot-geometry>
        <mesh-normal-material></mesh-normal-material>
    </three-mesh>

    <orbit-controls args='["$camera", "$domElement"]'></orbit-controls>
</three-lunchbox>

See here for notes on $camera and $renderer.