Skip to main content

ThreeJS Lite Runner

The lite runner requires you to load Three.js separately before loading the runner. This results in a smaller Bitbybit bundle size and allows you to use your own version of Three.js.

Live Example

Bitbybit Platform

StackBlitz - Three.js Lite Runner Example

Complete Example

Below is a complete example that creates a parametric lofted surface with rectangle holes using OCCT:

<!doctype html>
<html lang="en">

<head>
<title>Bitbybit Runner ThreeJS Lite Example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<!-- Load ThreeJS separately first using import maps -->
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@v0.182.0/build/three.module.js",
"three/addons/controls/OrbitControls": "https://cdn.jsdelivr.net/npm/three@v0.182.0/examples/jsm/controls/OrbitControls.min.js"
}
}
</script>
<script type="module">
import * as THREEJS from 'three';
import * as OrbitControls from 'three/addons/controls/OrbitControls';
window.THREEJS = THREEJS;
window.OrbitControls = OrbitControls;
</script>

<!-- Load the lite runner (requires ThreeJS to be loaded) -->
<script defer
src="https://cdn.jsdelivr.net/gh/bitbybit-dev/bitbybit-assets@latest/runner/bitbybit-runner-lite-threejs.js"></script>
<script type="module">

const runnerOptions = {
canvasId: 'myCanvas',
canvasZoneClass: 'myCanvasZone',
enableOCCT: true,
enableJSCAD: false,
enableManifold: false,
cameraPosition: [20, 10, 20],
cameraTarget: [10, 5, 0],
backgroundColor: "#1a1c1f",
loadFonts: ['Roboto'],
};

const runner = window.bitbybitRunner.getRunnerInstance();
const { bitbybit, Bit, camera, scene, renderer } = await runner.run(
runnerOptions
);

// Create a directional light with shadows
const dirLight = new THREEJS.DirectionalLight(0xffffff, 50);
dirLight.position.set(60, 70, -30);
dirLight.castShadow = true;
scene.add(dirLight);

// Model parameters
const model = {
uRec: 16,
vRec: 16,
rounding: 0.5,
drawEdges: true,
drawFaces: true,
color: '#6600ff'
}

// Create curve points for lofting
const curvePts = [
[[-10, 0, -10], [0, 3, -10], [10, -1, -10], [20, 2, -10]],
[[-10, -5, 0], [0, -3, 0], [10, 1, 0], [20, -2, 0]],
[[-10, 0, 10], [0, 3, 10], [10, -1, 10], [20, 2, 10]]
];

// Create wires from interpolated points
const wirePromises = curvePts.map((pts) => {
return bitbybit.occt.shapes.wire.interpolatePoints({
points: pts, periodic: false, tolerance: 1e-7
});
});

const wires = await Promise.all(wirePromises);
const loft = await bitbybit.occt.operations.loft({ shapes: wires, makeSolid: false });
const translated = await bitbybit.occt.transforms.translate({ shape: loft, translation: [0, 10, 0] });
const faces = await bitbybit.occt.shapes.face.getFaces({ shape: translated });

// Subdivide face with rectangle holes
const subdivideOptions = new Bit.Inputs.OCCT.FaceSubdivideToRectangleHolesDto(faces[0]);
subdivideOptions.nrRectanglesU = model.vRec;
subdivideOptions.nrRectanglesV = model.uRec;
subdivideOptions.scalePatternU = [0.9, 0.5, 0.7];
subdivideOptions.scalePatternV = [0.9, 0.5, 0.7];
subdivideOptions.filletPattern = [model.rounding];
subdivideOptions.inclusionPattern = [false, true, true, true, true];
subdivideOptions.offsetFromBorderU = 0.01;
subdivideOptions.offsetFromBorderV = 0.01;

const withHoles = await bitbybit.occt.shapes.face.subdivideToRectangleHoles(subdivideOptions);
const finalShape = await bitbybit.occt.operations.makeThickSolidSimple({
shape: withHoles[0], offset: 0.5
});

// Draw options with custom material
const options = new Bit.Inputs.Draw.DrawOcctShapeOptions();
options.precision = 0.02;
options.drawEdges = model.drawEdges;
options.drawFaces = model.drawFaces;
options.drawVertices = false;
options.edgeWidth = 20;
options.edgeColour = "#000000";

// Create custom ThreeJS material
const mat = new THREEJS.MeshPhongMaterial({ color: new THREEJS.Color(model.color) });
mat.polygonOffset = true;
mat.polygonOffsetFactor = 1;
options.faceMaterial = mat;

const group = await bitbybit.draw.drawAnyAsync({ entity: finalShape, options });

// Enable shadows on mesh children
group.children[0].children.forEach((child) => {
child.castShadow = true;
child.receiveShadow = true;
});

</script>
<style>
body {
margin: 0;
background-color: #1a1c1f;
}
#myCanvas {
display: block;
width: 100%;
height: 100vh;
}
.myCanvasZone {
width: 100%;
height: 100vh;
}
</style>
</head>

<body>
<div class="myCanvasZone">
<canvas id="myCanvas"></canvas>
</div>
</body>

</html>

Key Points

Loading ThreeJS First with Import Maps

<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@v0.182.0/build/three.module.js",
"three/addons/controls/OrbitControls": "https://cdn.jsdelivr.net/npm/three@v0.182.0/examples/jsm/controls/OrbitControls.min.js"
}
}
</script>
<script type="module">
import * as THREEJS from 'three';
import * as OrbitControls from 'three/addons/controls/OrbitControls';
window.THREEJS = THREEJS;
window.OrbitControls = OrbitControls;
</script>

Important: You must expose ThreeJS and OrbitControls to the window object before loading the lite runner:

  • window.THREEJS - The ThreeJS library
  • window.OrbitControls - The OrbitControls for camera navigation

Lite Runner Script

<script defer src="https://cdn.jsdelivr.net/gh/bitbybit-dev/bitbybit-assets@latest/runner/bitbybit-runner-lite-threejs.js"></script>

Note the defer attribute - this ensures the script loads after ThreeJS is available.

Initialization

const runner = window.bitbybitRunner.getRunnerInstance();
const { bitbybit, Bit, camera, scene, renderer } = await runner.run(runnerOptions);

Note: The lite runner returns THREEJS from the window object, not from the runner itself (since you loaded it separately).

When to Use Lite vs Full

Use CaseRecommended
Quick prototypingFull Runner
Need specific ThreeJS versionLite Runner
Smallest possible bundleLite Runner
Using other ThreeJS addonsLite Runner
Simple single-page demosFull Runner

Runner Options

The options are the same as the full runner:

OptionTypeDescription
canvasIdstringThe ID of your canvas element
canvasZoneClassstringCSS class for the canvas container
enableOCCTbooleanEnable OpenCASCADE kernel
enableJSCADbooleanEnable JSCAD kernel
enableManifoldbooleanEnable Manifold kernel
cameraPositionnumber[]Initial camera position [x, y, z]
cameraTargetnumber[]Camera look-at target [x, y, z]
backgroundColorstringScene background color (hex)
loadFontsstring[]Fonts to load for text operations

GitHub Source

View the full source code on GitHub: ThreeJS Lite Runner Examples