Skip to main content

Building a 3D Table Configurator with Rete & Bitbybit Runner

What You Will Learn

In this tutorial, we will guide you through coding a very simple 3D table configurator using the Rete visual editor on the Bitbybit web CAD platform. After creating the visual script, we will export its logic and execute it on a separate, static website hosted on StackBlitz.

Matas Ubarevičius will demonstrate setting up the basic HTML, CSS, and JavaScript for this project without relying on any third-party UI frameworks. This approach will show you how you can leverage the pure web platform to create interactive 3D experiences powered by your Bitbybit visual scripts.

Final Result & Code

You can either check the demo StackBlitz project or use the code snippets below to recreate it on your own website.

Bitbybit Platform

StackBlitz - 3D Table Configurator Rete

Rete Script (The Visual Program)

The following Bitbybit Rete script is the visual program that defines the logic for our 3D table configurator. The JavaScript code used in the StackBlitz example is what gets generated when you use the "Export to Runner" feature from this Rete script.

Bitbybit Platform

Bitbybit Rete Editor - 3D Table Configurator

rete logoRete
Script Source (rete)
{
"id": "rete-v2-json",
"nodes": {
"5b1a91d40ba32ba6": {
"id": "5b1a91d40ba32ba6",
"name": "bitbybit.runner.getRunnerInputValue",
"customName": "get runner input value",
"data": {
"property": "width"
},
"inputs": {},
"position": [
357.7109375,
335.08203125
]
},
"efbf1e23c9b6bf7e": {
"id": "efbf1e23c9b6bf7e",
"name": "bitbybit.runner.getRunnerInputValue",
"customName": "get runner input value",
"data": {
"property": "length"
},
"inputs": {},
"position": [
359.78487455962875,
627.1862552286783
]
},
"203e7430dfe4dcfd": {
"id": "203e7430dfe4dcfd",
"name": "bitbybit.runner.getRunnerInputValue",
"customName": "get runner input value",
"data": {
"property": "height"
},
"inputs": {},
"position": [
374.3751202984906,
946.8246029187638
]
},
"f23a32492882d85a": {
"id": "f23a32492882d85a",
"name": "bitbybit.runner.getRunnerInputValue",
"customName": "get runner input value",
"data": {
"property": "thickness"
},
"inputs": {},
"position": [
373.2185918262571,
1281.7252055148786
]
},
"8b7917339eea18f8": {
"id": "8b7917339eea18f8",
"name": "bitbybit.math.numberSlider",
"customName": "number slider",
"data": {
"options": {
"min": 0.3,
"max": 2,
"step": 0.1,
"width": 350
},
"number": 0.7
},
"inputs": {},
"position": [
300.7520443498283,
458.40728587672555
]
},
"c9c45727382dea8d": {
"id": "c9c45727382dea8d",
"name": "bitbybit.math.numberSlider",
"customName": "number slider",
"data": {
"options": {
"min": 0.3,
"max": 2,
"step": 0.1,
"width": 350
},
"number": 1.4
},
"inputs": {},
"position": [
302.4189097049763,
756.1893030415021
]
},
"69f8da342f3d430d": {
"id": "69f8da342f3d430d",
"name": "bitbybit.math.numberSlider",
"customName": "number slider",
"data": {
"options": {
"min": 0.2,
"max": 1.5,
"step": 0.1,
"width": 350
},
"number": 0.6
},
"inputs": {},
"position": [
315.51345391086363,
1076.6204427638672
]
},
"0698b73576aa6d11": {
"id": "0698b73576aa6d11",
"name": "bitbybit.math.numberSlider",
"customName": "number slider",
"data": {
"options": {
"min": 0.01,
"max": 0.1,
"step": 0.01,
"width": 350
},
"number": 0.1
},
"inputs": {},
"position": [
315.5833705341361,
1412.793414041544
]
},
"e14f6ecc53f65aa9": {
"id": "e14f6ecc53f65aa9",
"name": "bitbybit.logic.firstDefinedValueGate",
"customName": "first defined value gate",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"value1": {
"connections": [
{
"node": "5b1a91d40ba32ba6",
"output": "result",
"data": {}
}
]
},
"value2": {
"connections": [
{
"node": "8b7917339eea18f8",
"output": "result",
"data": {}
}
]
}
},
"position": [
923.5117540498435,
336.9608762175
]
},
"37daef81676b5b92": {
"id": "37daef81676b5b92",
"name": "bitbybit.logic.firstDefinedValueGate",
"customName": "first defined value gate",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"value1": {
"connections": [
{
"node": "efbf1e23c9b6bf7e",
"output": "result",
"data": {}
}
]
},
"value2": {
"connections": [
{
"node": "c9c45727382dea8d",
"output": "result",
"data": {}
}
]
}
},
"position": [
924.1850990208965,
644.9389085098146
]
},
"a3fac1311dde6971": {
"id": "a3fac1311dde6971",
"name": "bitbybit.logic.firstDefinedValueGate",
"customName": "first defined value gate",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"value1": {
"connections": [
{
"node": "203e7430dfe4dcfd",
"output": "result",
"data": {}
}
]
},
"value2": {
"connections": [
{
"node": "69f8da342f3d430d",
"output": "result",
"data": {}
}
]
}
},
"position": [
918.2834458483889,
965.387924922689
]
},
"458ccc77b2143ccd": {
"id": "458ccc77b2143ccd",
"name": "bitbybit.logic.firstDefinedValueGate",
"customName": "first defined value gate",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"value1": {
"connections": [
{
"node": "f23a32492882d85a",
"output": "result",
"data": {}
}
]
},
"value2": {
"connections": [
{
"node": "0698b73576aa6d11",
"output": "result",
"data": {}
}
]
}
},
"position": [
913.3437112179006,
1295.7616773514583
]
},
"8e220872faa931d8": {
"id": "8e220872faa931d8",
"name": "bitbybit.math.twoNrOperation",
"customName": "two nr operation",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"first": 1,
"second": 1,
"operation": "subtract"
},
"inputs": {
"first": {
"connections": [
{
"node": "a3fac1311dde6971",
"output": "result",
"data": {}
}
]
},
"second": {
"connections": [
{
"node": "458ccc77b2143ccd",
"output": "result",
"data": {}
}
]
}
},
"position": [
1703.1678079506132,
1764.0526803957023
]
},
"e62483526c4f3a3f": {
"id": "e62483526c4f3a3f",
"name": "bitbybit.math.twoNrOperation",
"customName": "two nr operation",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"first": 1,
"second": 2,
"operation": "divide"
},
"inputs": {
"first": {
"connections": [
{
"node": "8e220872faa931d8",
"output": "result",
"data": {}
}
]
}
},
"position": [
2594.743809199683,
1621.068600494747
]
},
"6bbfdd464b38ccab": {
"id": "6bbfdd464b38ccab",
"name": "bitbybit.math.twoNrOperation",
"customName": "two nr operation",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"first": 1,
"second": 2,
"operation": "divide"
},
"inputs": {
"first": {
"connections": [
{
"node": "458ccc77b2143ccd",
"output": "result",
"data": {}
}
]
}
},
"position": [
1819.6554636662263,
1184.3187562960616
]
},
"e6622f51a6fe5320": {
"id": "e6622f51a6fe5320",
"name": "bitbybit.occt.shapes.solid.createBox",
"customName": "box",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"width": 1,
"length": 2,
"height": 3,
"center": [
0,
0,
0
],
"originOnCenter": true
},
"inputs": {
"width": {
"connections": [
{
"node": "458ccc77b2143ccd",
"output": "result",
"data": {}
}
]
},
"length": {
"connections": [
{
"node": "458ccc77b2143ccd",
"output": "result",
"data": {}
}
]
},
"height": {
"connections": [
{
"node": "8e220872faa931d8",
"output": "result",
"data": {}
}
]
},
"center": {
"connections": [
{
"node": "ca717ef467265caf",
"output": "result",
"data": {}
}
]
}
},
"position": [
3536.516115509764,
2077.563969793483
]
},
"94f79da53f3d8604": {
"id": "94f79da53f3d8604",
"name": "bitbybit.occt.shapes.solid.createBox",
"customName": "box",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"width": 1,
"length": 2,
"height": 3,
"center": [
0,
0,
0
],
"originOnCenter": true
},
"inputs": {
"width": {
"connections": [
{
"node": "e14f6ecc53f65aa9",
"output": "result",
"data": {}
}
]
},
"length": {
"connections": [
{
"node": "37daef81676b5b92",
"output": "result",
"data": {}
}
]
},
"height": {
"connections": [
{
"node": "458ccc77b2143ccd",
"output": "result",
"data": {}
}
]
},
"center": {
"connections": [
{
"node": "292db9705c9ee0e8",
"output": "result",
"data": {}
}
]
}
},
"position": [
3826.2485065772025,
-470.21314674259963
]
},
"292db9705c9ee0e8": {
"id": "292db9705c9ee0e8",
"name": "bitbybit.vector.vectorXYZ",
"customName": "vector xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 0,
"y": 0,
"z": 0
},
"inputs": {
"y": {
"connections": [
{
"node": "a288946269869252",
"output": "result",
"data": {}
}
]
}
},
"position": [
3348.080801452038,
45.64241378529691
]
},
"a288946269869252": {
"id": "a288946269869252",
"name": "bitbybit.math.twoNrOperation",
"customName": "two nr operation",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"first": 1,
"second": 1,
"operation": "subtract"
},
"inputs": {
"first": {
"connections": [
{
"node": "a3fac1311dde6971",
"output": "result",
"data": {}
}
]
},
"second": {
"connections": [
{
"node": "6bbfdd464b38ccab",
"output": "result",
"data": {}
}
]
}
},
"position": [
2881.0909166981914,
597.4113918442986
]
},
"ca717ef467265caf": {
"id": "ca717ef467265caf",
"name": "bitbybit.vector.vectorXYZ",
"customName": "vector xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 0,
"y": 0,
"z": 0
},
"inputs": {
"y": {
"connections": [
{
"node": "e62483526c4f3a3f",
"output": "result",
"data": {}
}
]
}
},
"position": [
3078.9762197702403,
1789.0664744488536
]
},
"686584193a41413e": {
"id": "686584193a41413e",
"name": "bitbybit.occt.transforms.translate",
"customName": "translate",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"translation": [
0,
0,
0
]
},
"inputs": {
"shape": {
"connections": [
{
"node": "e6622f51a6fe5320",
"output": "result",
"data": {}
}
]
},
"translation": {
"connections": [
{
"node": "8d9cc3862ae755be",
"output": "result",
"data": {}
}
]
}
},
"position": [
5395.541488918439,
1537.2740698805455
]
},
"e2f2414aec096e09": {
"id": "e2f2414aec096e09",
"name": "bitbybit.occt.shapes.compound.makeCompound",
"customName": "make compound",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"shapes": {
"connections": [
{
"node": "876407388eef06f6",
"output": "list",
"data": {}
}
]
}
},
"position": [
6246.846357460899,
677.7528590381784
]
},
"876407388eef06f6": {
"id": "876407388eef06f6",
"name": "bitbybit.lists.createList",
"customName": "create list",
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "94f79da53f3d8604",
"output": "result",
"data": {}
},
{
"node": "686584193a41413e",
"output": "result",
"data": {}
},
{
"node": "99ca6815384d7ac9",
"output": "result",
"data": {}
}
]
}
},
"position": [
5884.060808095813,
578.3725460085655
]
},
"0ec95026ea2dc179": {
"id": "0ec95026ea2dc179",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"options": {
"connections": [
{
"node": "6fefccf2e0134437",
"output": "result",
"data": {}
}
]
},
"entity": {
"connections": [
{
"node": "e2f2414aec096e09",
"output": "result",
"data": {}
}
]
}
},
"position": [
6891.147463655265,
797.4830145608578
]
},
"6fefccf2e0134437": {
"id": "6fefccf2e0134437",
"name": "bitbybit.draw.optionsOcctShapeSimple",
"customName": "options occt shape simple",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"precision": 0.01,
"drawFaces": true,
"faceColour": "#7984b9",
"drawEdges": true,
"edgeColour": "#ffffff",
"edgeWidth": 1
},
"inputs": {},
"position": [
6244.063597078312,
1017.4618136959568
]
},
"ea94f29e18e2905f": {
"id": "ea94f29e18e2905f",
"name": "bitbybit.babylon.scene.enableSkybox",
"customName": "enable skybox",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"skybox": "clearSky",
"size": 1000,
"blur": 0.1,
"environmentIntensity": 0.7
},
"inputs": {},
"position": [
478.7991629274379,
1961.5989104368246
]
},
"99ca6815384d7ac9": {
"id": "99ca6815384d7ac9",
"name": "bitbybit.occt.shapes.face.createCircleFace",
"customName": "circle face",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius": 2,
"center": [
0,
0,
0
],
"direction": [
0,
1,
0
]
},
"inputs": {},
"position": [
5342.421336308412,
52.78186428876929
]
},
"e7487a609439eb1a": {
"id": "e7487a609439eb1a",
"name": "bitbybit.babylon.scene.drawDirectionalLight",
"customName": "draw directional light",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"direction": [
-100,
-100,
-100
],
"intensity": 3,
"diffuse": "#ffffff",
"specular": "#ffffff",
"shadowGeneratorMapSize": 1024,
"enableShadows": true,
"shadowDarkness": 0,
"shadowUsePercentageCloserFiltering": true,
"shadowContactHardeningLightSizeUVRatio": 0.2,
"shadowBias": 0.0001,
"shadowNormalBias": 0.002,
"shadowMaxZ": 1000,
"shadowMinZ": 0
},
"inputs": {},
"position": [
440.6297419375685,
2400.4462009049967
]
},
"06bcca85b99c0a9a": {
"id": "06bcca85b99c0a9a",
"name": "bitbybit.runner.setRunnerResultValue",
"customName": "set runner result value",
"data": {
"property": "table"
},
"inputs": {
"value": {
"connections": [
{
"node": "0ec95026ea2dc179",
"output": "result",
"data": {}
}
]
}
},
"position": [
7499.164090083273,
881.7351372883692
]
},
"403744c0df41464b": {
"id": "403744c0df41464b",
"name": "bitbybit.occt.shapes.wire.createRectangleWire",
"customName": "rectangle wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"width": 1,
"length": 2,
"center": [
0,
0,
0
],
"direction": [
0,
1,
0
]
},
"inputs": {
"width": {
"connections": [
{
"node": "2c4a634ab383d9d2",
"output": "result",
"data": {}
}
]
},
"length": {
"connections": [
{
"node": "4bdf590f5ba6a111",
"output": "result",
"data": {}
}
]
}
},
"position": [
3424.8187103411997,
1370.7191878915464
]
},
"2c4a634ab383d9d2": {
"id": "2c4a634ab383d9d2",
"name": "bitbybit.math.twoNrOperation",
"customName": "two nr operation",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"first": 1,
"second": 2,
"operation": "subtract"
},
"inputs": {
"first": {
"connections": [
{
"node": "e14f6ecc53f65aa9",
"output": "result",
"data": {}
}
]
},
"second": {
"connections": [
{
"node": "458ccc77b2143ccd",
"output": "result",
"data": {}
}
]
}
},
"position": [
1843.7336654843714,
541.5799256987196
]
},
"4bdf590f5ba6a111": {
"id": "4bdf590f5ba6a111",
"name": "bitbybit.math.twoNrOperation",
"customName": "two nr operation",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"first": 1,
"second": 2,
"operation": "subtract"
},
"inputs": {
"second": {
"connections": [
{
"node": "458ccc77b2143ccd",
"output": "result",
"data": {}
}
]
},
"first": {
"connections": [
{
"node": "37daef81676b5b92",
"output": "result",
"data": {}
}
]
}
},
"position": [
1830.177622351865,
871.1643259022944
]
},
"8585b69a75a679a4": {
"id": "8585b69a75a679a4",
"name": "bitbybit.occt.shapes.edge.getCornerPointsOfEdgesForShape",
"customName": "get corner points of edges for shape",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"shape": {
"connections": [
{
"node": "403744c0df41464b",
"output": "result",
"data": {}
}
]
}
},
"position": [
3879.3839338658117,
1466.7755706923394
]
},
"8d9cc3862ae755be": {
"id": "8d9cc3862ae755be",
"name": "bitbybit.lists.flatten",
"customName": "flatten",
"data": {
"nrLevels": 1
},
"inputs": {
"list": {
"connections": [
{
"node": "8585b69a75a679a4",
"output": "result",
"data": {}
}
]
}
},
"position": [
4218.247570061954,
1499.0958273259153
]
}
}
}

Complete Code for Your Website

Below are the index.html and script.js files you would use on StackBlitz or your own website to run the 3D table configurator.

<!DOCTYPE html>
<html lang="en">
<head>
<title>Home</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<link rel="stylesheet" href="styles.css" />
<script src="https://cdn.jsdelivr.net/gh/bitbybit-dev/bitbybit-assets@0.15.14.1/runner/bitbybit-runner.js"></script>
<script type="module" src="script.js"></script>
</head>
<body>
<h1>3D Table Configurator</h1>
<div class="myCanvasZone">
<canvas id="myCanvas"></canvas>
</div>
<div>
<input
id="width"
type="range"
value="1"
min="0.3"
max="3"
step="0.1"
onchange="changeModel(+event.target.value, 'width')"
/>
<label for="width">Width</label>
</div>
<div>
<input
id="length"
type="range"
value="1"
min="0.3"
max="3"
step="0.1"
onchange="changeModel(+event.target.value, 'length')"
/>
<label for="length">Length</label>
</div>
<div>
<input
id="height"
type="range"
value="0.5"
min="0.3"
max="1.5"
step="0.1"
onchange="changeModel(+event.target.value, 'height')"
/>
<label for="height">Height</label>
</div>
<div>
<input
id="thickness"
type="range"
value="0.05"
min="0.01"
max="0.25"
step="0.01"
onchange="changeModel(+event.target.value, 'thickness')"
/>
<label for="thickness">Thickness</label>
</div>
</body>
</html>


This tutorial illustrates how you can combine the visual programming power of Rete on Bitbybit with the Bitbybit Runner to create interactive 3D configurators that can be embedded into any website. By exporting your Rete logic, you can control complex 3D geometry and behavior through simple HTML UI elements.