START DOCUMENTATION

3D Table Configurator With Rete

What you will learn

In this tutorial we will code a very simple 3D table configurator in Rete editor on bitbybit.dev web cad platform. Then we will export this code and execute it on separate static website on StackBlitz. Matas will set up some basic HTML, CSS and JavaScript for this tutorial without using any 3rd party UI frameworks so that you would see how you can use pure web platform for your sites.

Final result

You can either visit StackBlitz project page or copy these code snippets into your website to make the result from this tutorial appear on your website.

Rete script

In the following visual script you will find the final code that was exported to JavaScript via "Export to Runner" popover.

Rete

3D Table

Complete Code

You can also download this static index.html file and open it in your browser to see the result. It contains all of the styling, html and script inside it.

<!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.16.2/runner/bitbybit-runner.js"></script> <script> const runner = window.bitbybitRunner.getRunnerInstance(); const model = { width: 1, length: 1, height: 0.5, thickness: 0.05, }; setTimeout(async () => { const runnerOptions = { canvasId: 'myCanvas', canvasZoneClass: 'myCanvasZone', enablePhysics: false, enableOCCT: true, enableJSCAD: false, enableKeyEventListeners: false, backgroundColor: '#0000ff', cameraPosition: [3,3,3], cameraTarget: [0,0,0], loadFonts: [], }; await runner.run(runnerOptions); changeModel(); }, 0); let previousMesh; async function changeModel(value, name) { if (value === undefined || model[name] !== value) { if (value !== undefined) { model[name] = value; } const res = await runner.executeScript(getInlineScript(), model); if (previousMesh) { previousMesh.dispose(); } previousMesh = res.table; } } window.changeModel = changeModel; function getInlineScript() { return '{\"type\":\"rete\",\"version\":\"0.15.13\",\"script\":\"async function(e,t,s,r,n){let a={};a={property:[\\"width\\"],...a};const o=[{result:[r[a.property[0]]]}];let i={};i={property:[\\"length\\"],...i};const u=[{result:[r[i.property[0]]]}];let l={};l={property:[\\"height\\"],...l};const c=[{result:[r[l.property[0]]]}];let p={};p={property:[\\"thickness\\"],...p};const d=[{result:[r[p.property[0]]]}];let f={};f={precision:[.01],drawFaces:[!0],faceColour:[\\"#7984b9\\"],drawEdges:[!0],edgeColour:[\\"#ffffff\\"],edgeWidth:[1],...f};const y=[{result:e.HS.executeBasedOnType(f,!1,(e=>t.draw.optionsOcctShapeSimple(e))),transformers:[]}];let h={};h={skybox:[\\"clearSky\\"],size:[1e3],blur:[.1],environmentIntensity:[.7],...h};e.HS.executeBasedOnType(h,!1,(e=>t.babylon.scene.enableSkybox(e)));let S={};S={radius:[2],center:[[0,0,0]],direction:[[0,1,0]],...S};const H=[{result:await e.HS.executeBasedOnTypeAsync(S,!1,(e=>t.occt.shapes.face.createCircleFace(e))),transformers:[]}];let m={};m={direction:[[-100,-100,-100]],intensity:[3],diffuse:[\\"#ffffff\\"],specular:[\\"#ffffff\\"],shadowGeneratorMapSize:[1024],enableShadows:[!0],shadowDarkness:[0],...m};e.HS.executeBasedOnType(m,!1,(e=>t.babylon.scene.drawDirectionalLight(e)));const v={value1:[void 0],value2:[void 0]};let w={};w.value1=o,w.value2=[{result:[.7],transformers:[]}],e.HS.updateListInputs(w),w={...v,...w};const O=[{result:e.HS.executeBasedOnType(w,!1,(e=>t.logic.firstDefinedValueGate(e))),transformers:[]}],B={value1:[void 0],value2:[void 0]};let x={};x.value1=u,x.value2=[{result:[1.4],transformers:[]}],e.HS.updateListInputs(x),x={...B,...x};const b=[{result:e.HS.executeBasedOnType(x,!1,(e=>t.logic.firstDefinedValueGate(e))),transformers:[]}],L={value1:[void 0],value2:[void 0]};let g={};g.value1=c,g.value2=[{result:[.6],transformers:[]}],e.HS.updateListInputs(g),g={...L,...g};const I=[{result:e.HS.executeBasedOnType(g,!1,(e=>t.logic.firstDefinedValueGate(e))),transformers:[]}],T={value1:[void 0],value2:[void 0]};let A={};A.value1=d,A.value2=[{result:[.1],transformers:[]}],e.HS.updateListInputs(A),A={...T,...A};const k=[{result:e.HS.executeBasedOnType(A,!1,(e=>t.logic.firstDefinedValueGate(e))),transformers:[]}];let D={};D.first=I,D.second=k,e.HS.updateListInputs(D),D={first:[1],second:[1],operation:[\\"subtract\\"],...D};const N=[{result:e.HS.executeBasedOnType(D,!1,(e=>t.math.twoNrOperation(e))),transformers:[]}];let R={};R.first=k,e.HS.updateListInputs(R),R={first:[1],second:[2],operation:[\\"divide\\"],...R};const C=[{result:e.HS.executeBasedOnType(R,!1,(e=>t.math.twoNrOperation(e))),transformers:[]}];let E={};E.first=O,E.second=k,e.HS.updateListInputs(E),E={first:[1],second:[2],operation:[\\"subtract\\"],...E};const G=[{result:e.HS.executeBasedOnType(E,!1,(e=>t.math.twoNrOperation(e))),transformers:[]}];let V={};V.second=k,V.first=b,e.HS.updateListInputs(V),V={first:[1],second:[2],operation:[\\"subtract\\"],...V};const z=[{result:e.HS.executeBasedOnType(V,!1,(e=>t.math.twoNrOperation(e))),transformers:[]}];let F={};F.first=N,e.HS.updateListInputs(F),F={first:[1],second:[2],operation:[\\"divide\\"],...F};const M=[{result:e.HS.executeBasedOnType(F,!1,(e=>t.math.twoNrOperation(e))),transformers:[]}];let W={};W.first=I,W.second=C,e.HS.updateListInputs(W),W={first:[1],second:[1],operation:[\\"subtract\\"],...W};const X=[{result:e.HS.executeBasedOnType(W,!1,(e=>t.math.twoNrOperation(e))),transformers:[]}];let Y={};Y.width=G,Y.length=z,e.HS.updateListInputs(Y),Y={width:[1],length:[2],center:[[0,0,0]],direction:[[0,1,0]],...Y};const Z=[{result:await e.HS.executeBasedOnTypeAsync(Y,!1,(e=>t.occt.shapes.wire.createRectangleWire(e))),transformers:[]}];let P={};P.y=X,e.HS.updateListInputs(P),P={x:[0],y:[0],z:[0],...P};const j=[{result:e.HS.executeBasedOnType(P,!1,(e=>t.vector.vectorXYZ(e))),transformers:[]}];let q={};q.y=M,e.HS.updateListInputs(q),q={x:[0],y:[0],z:[0],...q};const J=[{result:e.HS.executeBasedOnType(q,!1,(e=>t.vector.vectorXYZ(e))),transformers:[]}],K={shape:[void 0]};let Q={};Q.shape=Z,e.HS.updateListInputs(Q),Q={...K,...Q};const U=[{result:await e.HS.executeBasedOnTypeAsync(Q,!1,(e=>t.occt.shapes.edge.getCornerPointsOfEdgesForShape(e))),transformers:[]}];let $={};$.width=k,$.length=k,$.height=N,$.center=J,e.HS.updateListInputs($),$={width:[1],length:[2],height:[3],center:[[0,0,0]],...$};const _=[{result:await e.HS.executeBasedOnTypeAsync($,!1,(e=>t.occt.shapes.solid.createBox(e))),transformers:[]}];let ee={};ee.width=O,ee.length=b,ee.height=k,ee.center=j,e.HS.updateListInputs(ee),ee={width:[1],length:[2],height:[3],center:[[0,0,0]],...ee};const te=[{result:await e.HS.executeBasedOnTypeAsync(ee,!1,(e=>t.occt.shapes.solid.createBox(e))),transformers:[]}];let se={};se.list=U,e.HS.updateListInputs(se),se={nrLevels:[1],...se};const re=[];for(let e=0;e<se.nrLevels;e++)re.push({type:\\"flat\\"});const ne=[{result:se.list,transformers:re}],ae={shape:[void 0],translation:[[0,0,0]]};let oe={};oe.shape=_,oe.translation=ne,e.HS.updateListInputs(oe),oe={...ae,...oe};const ie=[{result:await e.HS.executeBasedOnTypeAsync(oe,!1,(e=>t.occt.transforms.translate(e))),transformers:[]}];let ue={};ue.listElements=[te[0],ie[0],H[0]],e.HS.updateListInputs(ue),ue={...ue};const le=[{result:[ue.listElements?ue.listElements:[]]}],ce={shapes:[void 0]};let pe={};pe.shapes=le,e.HS.updateListInputs(pe),pe={...ce,...pe};const de=[{result:await e.HS.executeBasedOnTypeAsync(pe,!1,(e=>t.occt.shapes.compound.makeCompound(e))),transformers:[]}],fe={entity:[void 0],options:[void 0],babylonMesh:[void 0]};let ye={};ye.options=y,ye.entity=de,e.HS.updateListInputs(ye),ye={...fe,...ye};const he=[{result:await e.HS.executeBasedOnTypeAsync(ye,!1,(e=>t.draw.drawAnyAsync(e))),transformers:[]}];let Se={};Se.value=he,e.HS.updateListInputs(Se),Se={property:[\\"table\\"],...Se},setBitbybitRunnerResultValue(Se.property[0],Se.value[0])}(BitByBit,bitbybit,bitbybitRunnerResult,bitbybitRunnerInputs,Bit);\"}'; } </script> <style> body { background-color: #1a1c1f; color: white; font-weight: 400; font-family: 'IBM Plex Sans', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; padding: 50px; } #myCanvas { outline: none; border: 1px solid white; border-radius: 5px; width: 100%; } </style> </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>