START DOCUMENTATION

3D Table Configurator With Blockly

What you will learn

In this tutorial we will code a very simple 3D table configurator in Blockly 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.

Blockly script

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

Blockly

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.18.0/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\":\"blockly\",\"version\":\"0.15.13\",\"script\":\"async function(e,r,t,n,c){var o,a,s,l,k,i,d,y,u,p,b,H;o=(()=>{const r={property:\\"width\\"};e.HS.handleBlock(e.blocklyWorkspace,\\"#NbGE|3bv2C@.$SI-H{|\\",r);try{return c.getBitbybitRunnerInputs()[r.property]}catch(e){errorHandle(e,\\"#NbGE|3bv2C@.$SI-H{|\\")}})(),a=(()=>{const r={property:\\"length\\"};e.HS.handleBlock(e.blocklyWorkspace,\\"S{jMIIo:J`iK]^J!=?Gg\\",r);try{return c.getBitbybitRunnerInputs()[r.property]}catch(e){errorHandle(e,\\"S{jMIIo:J`iK]^J!=?Gg\\")}})(),l=(()=>{const r={property:\\"height\\"};e.HS.handleBlock(e.blocklyWorkspace,\\"*A+C4*x]q|dA(crX6;X-\\",r);try{return c.getBitbybitRunnerInputs()[r.property]}catch(e){errorHandle(e,\\"*A+C4*x]q|dA(crX6;X-\\")}})(),i=(()=>{const r={property:\\"thickness\\"};e.HS.handleBlock(e.blocklyWorkspace,\\"1-)l_`)G8HCySvY_-jQ)\\",r);try{return c.getBitbybitRunnerInputs()[r.property]}catch(e){errorHandle(e,\\"1-)l_`)G8HCySvY_-jQ)\\")}})(),o||(o=1),a||(a=1),l||(l=.5),i||(i=.05),(()=>{const t={skybox:(()=>{const r={enumType:\\"clearSky\\"};e.HS.handleBlock(e.blocklyWorkspace,\\"a/J0jndc!e~YjnxMKOBM\\",r);try{return r.enumType}catch(e){errorHandle(e,\\"a/J0jndc!e~YjnxMKOBM\\")}})(),size:1e3,blur:.1,environmentIntensity:.7};e.HS.handleBlock(e.blocklyWorkspace,\\"9;RhsqBwF[,!}jbY3s**\\",t);try{r.babylon.scene.enableSkybox(t)}catch(e){errorHandle(e,\\"9;RhsqBwF[,!}jbY3s**\\")}})(),(()=>{const t={direction:(()=>{const t={x:-100,y:-100,z:-100};e.HS.handleBlock(e.blocklyWorkspace,\\"!7ul03{)E|rxKvW:_t_|\\",t);try{return r.vector.vectorXYZ(t)}catch(e){errorHandle(e,\\"!7ul03{)E|rxKvW:_t_|\\")}})(),intensity:3,diffuse:\\"#ffffff\\",specular:\\"#ffffff\\",shadowGeneratorMapSize:1024,enableShadows:!0,shadowDarkness:0};e.HS.handleBlock(e.blocklyWorkspace,\\"{[b@-dl=AJIaLEcb60MQ\\",t);try{r.babylon.scene.drawDirectionalLightNoReturn(t)}catch(e){errorHandle(e,\\"{[b@-dl=AJIaLEcb60MQ\\")}})(),k=(s=l-i)/2,y=o/2-(d=i/2),u=a/2-d,p=(()=>{const t={width:i,length:i,height:s,center:(()=>{const t={x:0,y:0,z:0};e.HS.handleBlock(e.blocklyWorkspace,\\"dxg[toUrT*v:+AP]d/H?\\",t);try{return r.point.pointXYZ(t)}catch(e){errorHandle(e,\\"dxg[toUrT*v:+AP]d/H?\\")}})()};return async function(){return await e.HS.inputAwaiter(t,e.blocklyWorkspace,\\"8RNRy..emBU8_B3KFd0;\\"),e.HS.handleBlock(e.blocklyWorkspace,\\"8RNRy..emBU8_B3KFd0;\\",t),e.HS.startedAsyncTask(e.blocklyWorkspace,\\"8RNRy..emBU8_B3KFd0;\\",\\"#ddddff\\"),r.occt.shapes.solid.createBox(t).then((r=>(e.HS.finishedAsyncTask(e.blocklyWorkspace,\\"8RNRy..emBU8_B3KFd0;\\"),r)),(e=>{errorHandle(e.substring?e.substring(0,1e3):e,\\"8RNRy..emBU8_B3KFd0;\\")}))}()})(),b=(()=>{const t={shapes:[(()=>{const t={width:o,length:a,height:i,center:(()=>{const t={x:0,y:l-d,z:0};e.HS.handleBlock(e.blocklyWorkspace,\\"oh2fO|gul7:I}lpy;WT%\\",t);try{return r.point.pointXYZ(t)}catch(e){errorHandle(e,\\"oh2fO|gul7:I}lpy;WT%\\")}})()};return async function(){return await e.HS.inputAwaiter(t,e.blocklyWorkspace,\\"c:r6|OA^Gq1ei=d*N]RK\\"),e.HS.handleBlock(e.blocklyWorkspace,\\"c:r6|OA^Gq1ei=d*N]RK\\",t),e.HS.startedAsyncTask(e.blocklyWorkspace,\\"c:r6|OA^Gq1ei=d*N]RK\\",\\"#ddddff\\"),r.occt.shapes.solid.createBox(t).then((r=>(e.HS.finishedAsyncTask(e.blocklyWorkspace,\\"c:r6|OA^Gq1ei=d*N]RK\\"),r)),(e=>{errorHandle(e.substring?e.substring(0,1e3):e,\\"c:r6|OA^Gq1ei=d*N]RK\\")}))}()})(),(()=>{const t={shape:p,translation:(()=>{const t={x:y,y:k,z:u};e.HS.handleBlock(e.blocklyWorkspace,\\"9Q8@!v({?D%cmR_hWSt5\\",t);try{return r.point.pointXYZ(t)}catch(e){errorHandle(e,\\"9Q8@!v({?D%cmR_hWSt5\\")}})()};return async function(){return await e.HS.inputAwaiter(t,e.blocklyWorkspace,\\"w(0J6zA)Vk=@+b^7.%FD\\"),e.HS.handleBlock(e.blocklyWorkspace,\\"w(0J6zA)Vk=@+b^7.%FD\\",t),e.HS.startedAsyncTask(e.blocklyWorkspace,\\"w(0J6zA)Vk=@+b^7.%FD\\",\\"#ddddff\\"),r.occt.transforms.translate(t).then((r=>(e.HS.finishedAsyncTask(e.blocklyWorkspace,\\"w(0J6zA)Vk=@+b^7.%FD\\"),r)),(e=>{errorHandle(e.substring?e.substring(0,1e3):e,\\"w(0J6zA)Vk=@+b^7.%FD\\")}))}()})(),(()=>{const t={shape:p,translation:(()=>{const t={x:-y,y:k,z:u};e.HS.handleBlock(e.blocklyWorkspace,\\"Jq}lWz6M)zk*}:e`zG7P\\",t);try{return r.point.pointXYZ(t)}catch(e){errorHandle(e,\\"Jq}lWz6M)zk*}:e`zG7P\\")}})()};return async function(){return await e.HS.inputAwaiter(t,e.blocklyWorkspace,\\"B:BWiRk?snzLlG~$4mS!\\"),e.HS.handleBlock(e.blocklyWorkspace,\\"B:BWiRk?snzLlG~$4mS!\\",t),e.HS.startedAsyncTask(e.blocklyWorkspace,\\"B:BWiRk?snzLlG~$4mS!\\",\\"#ddddff\\"),r.occt.transforms.translate(t).then((r=>(e.HS.finishedAsyncTask(e.blocklyWorkspace,\\"B:BWiRk?snzLlG~$4mS!\\"),r)),(e=>{errorHandle(e.substring?e.substring(0,1e3):e,\\"B:BWiRk?snzLlG~$4mS!\\")}))}()})(),(()=>{const t={shape:p,translation:(()=>{const t={x:y,y:k,z:-u};e.HS.handleBlock(e.blocklyWorkspace,\\",]00E]4a|okH9[YJ,Hd*\\",t);try{return r.point.pointXYZ(t)}catch(e){errorHandle(e,\\",]00E]4a|okH9[YJ,Hd*\\")}})()};return async function(){return await e.HS.inputAwaiter(t,e.blocklyWorkspace,\\"u%iUbaefB{u{BupM_jPx\\"),e.HS.handleBlock(e.blocklyWorkspace,\\"u%iUbaefB{u{BupM_jPx\\",t),e.HS.startedAsyncTask(e.blocklyWorkspace,\\"u%iUbaefB{u{BupM_jPx\\",\\"#ddddff\\"),r.occt.transforms.translate(t).then((r=>(e.HS.finishedAsyncTask(e.blocklyWorkspace,\\"u%iUbaefB{u{BupM_jPx\\"),r)),(e=>{errorHandle(e.substring?e.substring(0,1e3):e,\\"u%iUbaefB{u{BupM_jPx\\")}))}()})(),(()=>{const t={shape:p,translation:(()=>{const t={x:-y,y:k,z:-u};e.HS.handleBlock(e.blocklyWorkspace,\\";SD;M*CzF]b{W9cvUrw.\\",t);try{return r.point.pointXYZ(t)}catch(e){errorHandle(e,\\";SD;M*CzF]b{W9cvUrw.\\")}})()};return async function(){return await e.HS.inputAwaiter(t,e.blocklyWorkspace,\\";6M~xu/B-t=+6pAMoHn!\\"),e.HS.handleBlock(e.blocklyWorkspace,\\";6M~xu/B-t=+6pAMoHn!\\",t),e.HS.startedAsyncTask(e.blocklyWorkspace,\\";6M~xu/B-t=+6pAMoHn!\\",\\"#ddddff\\"),r.occt.transforms.translate(t).then((r=>(e.HS.finishedAsyncTask(e.blocklyWorkspace,\\";6M~xu/B-t=+6pAMoHn!\\"),r)),(e=>{errorHandle(e.substring?e.substring(0,1e3):e,\\";6M~xu/B-t=+6pAMoHn!\\")}))}()})(),(()=>{const t={radius:2,center:(()=>{const t={x:0,y:0,z:0};e.HS.handleBlock(e.blocklyWorkspace,\\"_`usIB0$WWd`7F(eK`%j\\",t);try{return r.point.pointXYZ(t)}catch(e){errorHandle(e,\\"_`usIB0$WWd`7F(eK`%j\\")}})(),direction:(()=>{const t={x:0,y:1,z:0};e.HS.handleBlock(e.blocklyWorkspace,\\"Ba3CWT`|ju!%8j(atgeo\\",t);try{return r.vector.vectorXYZ(t)}catch(e){errorHandle(e,\\"Ba3CWT`|ju!%8j(atgeo\\")}})()};return async function(){return await e.HS.inputAwaiter(t,e.blocklyWorkspace,\\"~LYI=/U2NV(X{?7H@}dH\\"),e.HS.handleBlock(e.blocklyWorkspace,\\"~LYI=/U2NV(X{?7H@}dH\\",t),e.HS.startedAsyncTask(e.blocklyWorkspace,\\"~LYI=/U2NV(X{?7H@}dH\\",\\"#ddddff\\"),r.occt.shapes.face.createCircleFace(t).then((r=>(e.HS.finishedAsyncTask(e.blocklyWorkspace,\\"~LYI=/U2NV(X{?7H@}dH\\"),r)),(e=>{errorHandle(e.substring?e.substring(0,1e3):e,\\"~LYI=/U2NV(X{?7H@}dH\\")}))}()})()]};return async function(){return await e.HS.inputAwaiter(t,e.blocklyWorkspace,\\"m`h?x^VKesu,Fo_]wTKM\\"),e.HS.handleBlock(e.blocklyWorkspace,\\"m`h?x^VKesu,Fo_]wTKM\\",t),e.HS.startedAsyncTask(e.blocklyWorkspace,\\"m`h?x^VKesu,Fo_]wTKM\\",\\"#ddddff\\"),r.occt.shapes.compound.makeCompound(t).then((r=>(e.HS.finishedAsyncTask(e.blocklyWorkspace,\\"m`h?x^VKesu,Fo_]wTKM\\"),r)),(e=>{errorHandle(e.substring?e.substring(0,1e3):e,\\"m`h?x^VKesu,Fo_]wTKM\\")}))}()})(),H=await(()=>{let t={promise:(()=>{const t={entity:b,options:(()=>{const t={precision:.01,drawFaces:!0,faceColour:\\"#999999\\",drawEdges:!0,edgeColour:\\"#ffffff\\",edgeWidth:1};e.HS.handleBlock(e.blocklyWorkspace,\\"glRbb$9x]0z|mN%BL]t}\\",t);try{return r.draw.optionsOcctShapeSimple(t)}catch(e){errorHandle(e,\\"glRbb$9x]0z|mN%BL]t}\\")}})()};return async function(){return await e.HS.inputAwaiter(t,e.blocklyWorkspace,\\"!bPf323Us:qK~#J#nu_|\\"),e.HS.handleBlock(e.blocklyWorkspace,\\"!bPf323Us:qK~#J#nu_|\\",t),e.HS.startedAsyncTask(e.blocklyWorkspace,\\"!bPf323Us:qK~#J#nu_|\\",\\"#ddddff\\"),r.draw.drawAnyAsync(t).then((r=>(e.HS.finishedAsyncTask(e.blocklyWorkspace,\\"!bPf323Us:qK~#J#nu_|\\"),r)),(e=>{errorHandle(e.substring?e.substring(0,1e3):e,\\"!bPf323Us:qK~#J#nu_|\\")}))}()})()}.promise;return Array.isArray(t)&&(t=Promise.all(t)),t})(),(()=>{const r={property:\\"table\\",value:H};e.HS.handleBlock(e.blocklyWorkspace,\\"JEic2[BK%J3Vb_!QY~lF\\",r);try{c.setBitbybitRunnerResultValue(r.property,r.value)}catch(e){errorHandle(e,\\"JEic2[BK%J3Vb_!QY~lF\\")}})()}(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>