Navigate and Extract Assembly Parts
When you need to access individual parts from a STEP file, understanding the assembly structure is key. This tutorial shows you how to explore the hierarchy, find specific parts using their labels, and render them with custom colors.
How the Hierarchy Works
Assemblies organize parts in a tree structure. Each part has:
- A label (like an address):
0:1:1:3tells you exactly where the part lives in the structure - A name: Human-readable identifier like "Mounting Plate" or "Screw"
- Properties: Colors, materials, and other metadata
The hierarchy preview component shows this structure visually, making it easy to find the labels you need.
The Workflow
Here's what happens in the examples below:
- Fetch the STEP file - Download the compressed CAD model from a URL
- Load into a document - Parse the file into an OCCT document structure
- Get the hierarchy - Extract the tree structure showing all parts
- Preview the hierarchy - Display it so you can see labels and names
- Extract shapes by label - Use the labels to get specific parts
- Draw with custom styling - Render each part with your chosen colors
Labels like 0:1:1:1:6 work like folder paths on your computer. The numbers represent levels in the hierarchy:
0:1- Root level0:1:1- First sub-assembly0:1:1:1- Component within that sub-assembly0:1:1:1:6- Specific shape within that component
Click on items in the hierarchy preview to see their full labels!
Extract a Single Shape
This first example shows the basic workflow - loading a STEP file and extracting one specific shape using its label.
- Rete
- Blockly
- TypeScript
{
"id": "rete-v2-json",
"nodes": {
"e0e94797745b9499": {
"id": "e0e94797745b9499",
"name": "bitbybit.asset.fetchFile",
"customName": "fetch file",
"async": true,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"url": "https://learn.bitbybit.dev/files/3d/Soil-Sensor.stpZ"
},
"inputs": {},
"position": [
447.0390625,
364.58203125
]
},
"824be0f956f86e07": {
"id": "824be0f956f86e07",
"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,
"transparencyShadow": false,
"shadowContactHardeningLightSizeUVRatio": 0.2,
"shadowBias": 0.001,
"shadowNormalBias": 0.02,
"shadowMaxZ": 1000,
"shadowMinZ": 0,
"shadowRefreshRate": 6
},
"inputs": {
"direction": {
"connections": [
{
"node": "1cf530bc3b05cd75",
"output": "result",
"data": {}
}
]
}
},
"position": [
220.90978154060178,
1141.4474910149524
]
},
"a2753a0a68a97354": {
"id": "a2753a0a68a97354",
"name": "bitbybit.point.pointXYZ",
"customName": "point xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 0,
"y": -5,
"z": 0
},
"inputs": {},
"position": [
720.7524355897118,
1488.399577959778
]
},
"1cf530bc3b05cd75": {
"id": "1cf530bc3b05cd75",
"name": "bitbybit.point.pointXYZ",
"customName": "point xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 100,
"y": -100,
"z": -100
},
"inputs": {},
"position": [
-142.37939449872056,
1144.5669505658402
]
},
"09ff71828df19896": {
"id": "09ff71828df19896",
"name": "bitbybit.point.pointXYZ",
"customName": "point xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 70,
"y": 50,
"z": 70
},
"inputs": {},
"position": [
714.6847345665905,
1143.2908329012987
]
},
"d737b03aa186cfde": {
"id": "d737b03aa186cfde",
"name": "bitbybit.babylon.scene.adjustActiveArcRotateCamera",
"customName": "adjust active arc rotate camera",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"position": [
10,
10,
10
],
"lookAt": [
0,
0,
0
],
"lowerBetaLimit": 1,
"upperBetaLimit": 179,
"angularSensibilityX": 1000,
"angularSensibilityY": 1000,
"maxZ": 1000,
"panningSensibility": 1000,
"wheelPrecision": 3
},
"inputs": {
"lookAt": {
"connections": [
{
"node": "a2753a0a68a97354",
"output": "result",
"data": {}
}
]
},
"position": {
"connections": [
{
"node": "09ff71828df19896",
"output": "result",
"data": {}
}
]
}
},
"position": [
1140.4592129965072,
1279.8313039785085
]
},
"6e0425b3ab3715f4": {
"id": "6e0425b3ab3715f4",
"name": "bitbybit.occt.assembly.manager.loadStepToDoc",
"customName": "load step to doc",
"async": true,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"stepData": {
"connections": [
{
"node": "e0e94797745b9499",
"output": "result",
"data": {}
}
]
}
},
"position": [
815.8178400767682,
364.9872279487489
]
},
"ce31b6e5c2308c9c": {
"id": "ce31b6e5c2308c9c",
"name": "bitbybit.previewAssemblyHierarchy",
"customName": "preview occt assembly hierarchy",
"data": {},
"inputs": {
"data": {
"connections": [
{
"node": "a41ed949a48dd353",
"output": "result",
"data": {}
}
]
}
},
"position": [
1568.2992714974453,
402.6559493386362
]
},
"a41ed949a48dd353": {
"id": "a41ed949a48dd353",
"name": "bitbybit.occt.assembly.query.getAssemblyHierarchy",
"customName": "get assembly hierarchy",
"async": true,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"document": {
"connections": [
{
"node": "6e0425b3ab3715f4",
"output": "result",
"data": {}
}
]
}
},
"position": [
1188.4388314788046,
364.15039486583663
]
},
"4fe2985ce5a35e76": {
"id": "4fe2985ce5a35e76",
"name": "bitbybit.occt.assembly.query.getShapeFromLabel",
"customName": "get shape from label",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"label": "0:1:1:1:6"
},
"inputs": {
"document": {
"connections": [
{
"node": "6e0425b3ab3715f4",
"output": "result",
"data": {}
}
]
}
},
"position": [
1178.4270856228939,
8.999238142087234
]
},
"06851fe24453fd5c": {
"id": "06851fe24453fd5c",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"entity": {
"connections": [
{
"node": "4fe2985ce5a35e76",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "dfaed57ad37e99ee",
"output": "result",
"data": {}
}
]
}
},
"position": [
2673.7673191707004,
12.234165474468261
]
},
"dfaed57ad37e99ee": {
"id": "dfaed57ad37e99ee",
"name": "bitbybit.draw.optionsOcctShape",
"customName": "options occt shape",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"faceOpacity": 1,
"edgeOpacity": 1,
"edgeColour": "#ffffff",
"faceColour": "#ff0000",
"vertexColour": "#ff00ff",
"edgeWidth": 10,
"vertexSize": 0.03,
"drawEdges": true,
"drawFaces": true,
"drawVertices": false,
"precision": 0.1,
"drawEdgeIndexes": false,
"edgeIndexHeight": 0.06,
"edgeIndexColour": "#ff00ff",
"drawFaceIndexes": false,
"faceIndexHeight": 0.06,
"faceIndexColour": "#0000ff",
"drawTwoSided": false,
"backFaceColour": "#0000ff",
"backFaceOpacity": 1,
"edgeArrowSize": 0,
"edgeArrowAngle": 15
},
"inputs": {},
"position": [
2147.0747334465477,
409.56140922372725
]
},
"f0d4e9ea3cd24449": {
"id": "f0d4e9ea3cd24449",
"name": "bitbybit.babylon.scene.twoColorLinearGradientBackground",
"customName": "two color linear gradient background",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"colorFrom": "#1a1c1f",
"colorTo": "#93aacd",
"direction": "to top",
"stopFrom": 0,
"stopTo": 100
},
"inputs": {},
"position": [
326.1284717805745,
2031.466101347526
]
}
}
}
<xml xmlns="https://developers.google.com/blockly/xml"><variables><variable id="stepData">stepData</variable><variable id="document">document</variable><variable id="hierarchy">hierarchy</variable><variable id="shape">shape</variable><variable id="bg">bg</variable></variables><block type="variables_set" id="fetchStep" x="-562" y="-36"><field name="VAR" id="stepData">stepData</field><value name="VALUE"><block type="bitbybit.asset.fetchFile" id="fetchFile"><value name="Url"><block type="text" id="urlText"><field name="TEXT">https://learn.bitbybit.dev/files/3d/Soil-Sensor.stpZ</field></block></value></block></value><next><block type="variables_set" id="loadDoc"><field name="VAR" id="document">document</field><value name="VALUE"><block type="bitbybit.occt.assembly.manager.loadStepToDoc" id="loadStepToDoc"><value name="StepData"><block type="variables_get" id="getStepData"><field name="VAR" id="stepData">stepData</field></block></value></block></value><next><block type="variables_set" id="getHierarchy"><field name="VAR" id="hierarchy">hierarchy</field><value name="VALUE"><block type="base_time_await_return" id="0Q@C-Wu(^6@f2(GnaOvI"><value name="Promise"><block type="bitbybit.occt.assembly.query.getAssemblyHierarchy" id="assemblyHierarchy"><value name="Document"><block type="variables_get" id="getDoc1"><field name="VAR" id="document">document</field></block></value></block></value></block></value><next><block type="base_io_preview_assembly_hierarchy" id="previewHierarchy"><value name="Data"><block type="variables_get" id="mn[./puC2In#P`M5B]s("><field name="VAR" id="hierarchy">hierarchy</field></block></value><next><block type="variables_set" id="getShape"><field name="VAR" id="shape">shape</field><value name="VALUE"><block type="bitbybit.occt.assembly.query.getShapeFromLabel" id="shapeFromLabel"><value name="Document"><block type="variables_get" id="getDoc2"><field name="VAR" id="document">document</field></block></value><value name="Label"><block type="text" id="labelText"><field name="TEXT">0:1:1:1:6</field></block></value></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn" id="drawShape"><value name="Entity"><block type="variables_get" id="getShape2"><field name="VAR" id="shape">shape</field></block></value><value name="Options"><block type="bitbybit.draw.optionsOcctShape" id=",Wtm}Jtz`Ps{-.:tf:Gg"><value name="FaceOpacity"><block type="math_number" id="h_^SsT$!Jh|T-0{(jY78"><field name="NUM">1</field></block></value><value name="EdgeOpacity"><block type="math_number" id="|=WjbgUU,u}h:O]lE|RV"><field name="NUM">1</field></block></value><value name="EdgeColour"><block type="colour_picker" id="U?DFPhM7vNUFx:IH3x_%"><field name="COLOUR">#ffffff</field></block></value><value name="FaceColour"><block type="colour_picker" id="|_eti%|}6Fb0GMt@qkVC"><field name="COLOUR">#ff0000</field></block></value><value name="VertexColour"><block type="colour_picker" id="I~IC~[QMy~0naSgK}Qf2"><field name="COLOUR">#ff00ff</field></block></value><value name="EdgeWidth"><block type="math_number" id="bi=I?6uI:5f_Bcie@dtT"><field name="NUM">10</field></block></value><value name="VertexSize"><block type="math_number" id="s%1Bn?AdiS*9ywK`P+cF"><field name="NUM">0.03</field></block></value><value name="DrawEdges"><block type="logic_boolean" id=")|?W{pz$I[4buavF5j?g"><field name="BOOL">TRUE</field></block></value><value name="DrawFaces"><block type="logic_boolean" id="}!%Q6(9mnf@qN$|?cLo*"><field name="BOOL">TRUE</field></block></value><value name="DrawVertices"><block type="logic_boolean" id=";m,z%|^QssetR+uS4Gcu"><field name="BOOL">FALSE</field></block></value><value name="Precision"><block type="math_number" id="D]tTvOw7FLoOw,!-j*~x"><field name="NUM">0.03</field></block></value><value name="DrawEdgeIndexes"><block type="logic_boolean" id="lZFK1*tm7Yl3nXnKhN_C"><field name="BOOL">FALSE</field></block></value><value name="EdgeIndexHeight"><block type="math_number" id=".m~.h=hC{(l,dgt/ip76"><field name="NUM">0.06</field></block></value><value name="EdgeIndexColour"><block type="colour_picker" id="^t4weKq9C)jPiP:nJBi!"><field name="COLOUR">#ff00ff</field></block></value><value name="DrawFaceIndexes"><block type="logic_boolean" id="1)AIjk_yqZT33[1o2faF"><field name="BOOL">FALSE</field></block></value><value name="FaceIndexHeight"><block type="math_number" id="*vX2+kJZjnq%Ss)-_RrQ"><field name="NUM">0.06</field></block></value><value name="FaceIndexColour"><block type="colour_picker" id="A6YsR3y5KT@.L2O51^LK"><field name="COLOUR">#0000ff</field></block></value><value name="DrawTwoSided"><block type="logic_boolean" id="_k/)Oap]Y,HC]8[eTT42"><field name="BOOL">TRUE</field></block></value><value name="BackFaceColour"><block type="colour_picker" id="wIvss:pADfoLCar+Z0Ko"><field name="COLOUR">#0000ff</field></block></value><value name="BackFaceOpacity"><block type="math_number" id="WHTmvyjp#G%v~:q#h$Nt"><field name="NUM">1</field></block></value><value name="EdgeArrowSize"><block type="math_number" id="jgHH?VH^$SvU5uUy`[~G"><field name="NUM">0</field></block></value><value name="EdgeArrowAngle"><block type="math_number" id="S4B}}cn=9xR!,qZ:)v2N"><field name="NUM">15</field></block></value></block></value><next><block type="bitbybit.babylon.scene.drawDirectionalLightNoReturn" id="drawLight"><value name="Direction"><block type="bitbybit.vector.vectorXYZ" id="lightDir"><value name="X"><block type="math_number" id="lightX"><field name="NUM">100</field></block></value><value name="Y"><block type="math_number" id="lightY"><field name="NUM">-100</field></block></value><value name="Z"><block type="math_number" id="lightZ"><field name="NUM">-100</field></block></value></block></value><value name="Intensity"><block type="math_number" id="lightIntensity"><field name="NUM">3</field></block></value><value name="Diffuse"><block type="colour_picker" id="diffuse"><field name="COLOUR">#ffffff</field></block></value><value name="Specular"><block type="colour_picker" id="specular"><field name="COLOUR">#ffffff</field></block></value><value name="ShadowGeneratorMapSize"><block type="math_number" id="shadowMapSize"><field name="NUM">1024</field></block></value><value name="EnableShadows"><block type="logic_boolean" id="enableShadows"><field name="BOOL">TRUE</field></block></value><value name="ShadowDarkness"><block type="math_number" id="shadowDarkness"><field name="NUM">0</field></block></value><value name="ShadowUsePercentageCloserFiltering"><block type="logic_boolean" id="shadowPCF"><field name="BOOL">TRUE</field></block></value><value name="ShadowContactHardeningLightSizeUVRatio"><block type="math_number" id="shadowHardening"><field name="NUM">0.2</field></block></value><value name="ShadowBias"><block type="math_number" id="shadowBias"><field name="NUM">0.001</field></block></value><value name="ShadowNormalBias"><block type="math_number" id="shadowNormalBias"><field name="NUM">0.02</field></block></value><value name="ShadowMaxZ"><block type="math_number" id="shadowMaxZ"><field name="NUM">1000</field></block></value><value name="ShadowMinZ"><block type="math_number" id="shadowMinZ"><field name="NUM">0</field></block></value><next><block type="bitbybit.babylon.scene.adjustActiveArcRotateCamera" id="adjustCamera"><value name="Position"><block type="bitbybit.point.pointXYZ" id="camPos"><value name="X"><block type="math_number" id="camPosX"><field name="NUM">70</field></block></value><value name="Y"><block type="math_number" id="camPosY"><field name="NUM">50</field></block></value><value name="Z"><block type="math_number" id="camPosZ"><field name="NUM">70</field></block></value></block></value><value name="LookAt"><block type="bitbybit.point.pointXYZ" id="camLookAt"><value name="X"><block type="math_number" id="lookAtX"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="lookAtY"><field name="NUM">-5</field></block></value><value name="Z"><block type="math_number" id="lookAtZ"><field name="NUM">0</field></block></value></block></value><value name="LowerBetaLimit"><block type="math_number" id="lowerBeta"><field name="NUM">1</field></block></value><value name="UpperBetaLimit"><block type="math_number" id="upperBeta"><field name="NUM">179</field></block></value><value name="AngularSensibilityX"><block type="math_number" id="angSensX"><field name="NUM">1000</field></block></value><value name="AngularSensibilityY"><block type="math_number" id="angSensY"><field name="NUM">1000</field></block></value><value name="MaxZ"><block type="math_number" id="maxZ"><field name="NUM">1000</field></block></value><value name="PanningSensibility"><block type="math_number" id="panningSens"><field name="NUM">1000</field></block></value><value name="WheelPrecision"><block type="math_number" id="wheelPrec"><field name="NUM">3</field></block></value><next><block type="variables_set" id="setBg"><field name="VAR" id="bg">bg</field><value name="VALUE"><block type="bitbybit.babylon.scene.twoColorLinearGradientBackground" id="background"><value name="ColorFrom"><block type="colour_picker" id="colorFrom"><field name="COLOUR">#1a1c1f</field></block></value><value name="ColorTo"><block type="colour_picker" id="colorTo"><field name="COLOUR">#93aacd</field></block></value><value name="Direction"><block type="bitbybit.babylon.enums.gradientDirectionEnum" id="gradientDir"><field name="bitbybit.babylon.enums.gradientDirectionEnum">'to top'</field></block></value><value name="StopFrom"><block type="math_number" id="stopFrom"><field name="NUM">0</field></block></value><value name="StopTo"><block type="math_number" id="stopTo"><field name="NUM">100</field></block></value></block></value></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></xml>
// Import required DTOs for scene setup and assembly operations
const { SceneTwoColorLinearGradientDto, DirectionalLightDto, CameraConfigurationDto } = Bit.Inputs.BabylonScene;
const { LoadStepToDocDto, DocumentLabelQueryDto, DocumentQueryDto } = Bit.Inputs.OCCT;
const { gradientDirectionEnum } = Bit.Inputs.Base;
// Import type definitions for type safety
type Point3 = Bit.Inputs.Base.Point3;
type Vector3 = Bit.Inputs.Base.Vector3;
// Get access to modules
const { scene } = bitbybit.babylon;
const { asset } = bitbybit;
const { manager, query } = bitbybit.occt.assembly;
const start = async () => {
// Setup two-color gradient background
const backgroundOpt = new SceneTwoColorLinearGradientDto();
backgroundOpt.colorFrom = "#1a1c1f";
backgroundOpt.colorTo = "#93aacd";
backgroundOpt.direction = gradientDirectionEnum.toTop;
backgroundOpt.stopFrom = 0;
backgroundOpt.stopTo = 100;
scene.twoColorLinearGradientBackground(backgroundOpt);
// Setup directional light with shadows
const dirLightOpt = new DirectionalLightDto();
dirLightOpt.direction = [100, -100, -100] as Vector3;
dirLightOpt.intensity = 3;
dirLightOpt.diffuse = "#ffffff";
dirLightOpt.specular = "#ffffff";
dirLightOpt.shadowGeneratorMapSize = 1024;
dirLightOpt.enableShadows = true;
dirLightOpt.shadowDarkness = 0;
dirLightOpt.shadowUsePercentageCloserFiltering = true;
dirLightOpt.shadowContactHardeningLightSizeUVRatio = 0.2;
dirLightOpt.shadowBias = 0.001;
dirLightOpt.shadowNormalBias = 0.02;
dirLightOpt.shadowMaxZ = 1000;
dirLightOpt.shadowMinZ = 0;
scene.drawDirectionalLight(dirLightOpt);
// Adjust camera position and settings
const cameraOpt = new CameraConfigurationDto();
cameraOpt.position = [70, 50, 70] as Point3;
cameraOpt.lookAt = [0, -5, 0] as Point3;
cameraOpt.lowerBetaLimit = 1;
cameraOpt.upperBetaLimit = 179;
cameraOpt.angularSensibilityX = 1000;
cameraOpt.angularSensibilityY = 1000;
cameraOpt.maxZ = 1000;
cameraOpt.panningSensibility = 1000;
cameraOpt.wheelPrecision = 3;
scene.adjustActiveArcRotateCamera(cameraOpt);
// Fetch the STEP file from URL
const stepData = await asset.fetchFile({
url: "https://learn.bitbybit.dev/files/3d/Soil-Sensor.stpZ"
});
// Load STEP data into an OCCT document
const loadDocOpt = new LoadStepToDocDto();
loadDocOpt.stepData = stepData;
const document = await manager.loadStepToDoc(loadDocOpt);
// Get assembly hierarchy (useful for understanding structure)
const hierarchyOpt = new DocumentQueryDto<Bit.Inputs.OCCT.TDocStdDocumentPointer>();
hierarchyOpt.document = document;
const hierarchy = await query.getAssemblyHierarchy(hierarchyOpt);
console.log("Assembly Hierarchy:", hierarchy);
// Get a specific shape from the assembly using its label
const shapeOpt = new DocumentLabelQueryDto<Bit.Inputs.OCCT.TDocStdDocumentPointer>();
shapeOpt.document = document;
shapeOpt.label = "0:1:1:1:6";
const shape = await query.getShapeFromLabel(shapeOpt);
// Draw the extracted shape with custom styling
const drawOpt = new Bit.Inputs.Draw.DrawOcctShapeOptions();
drawOpt.precision = 0.1;
drawOpt.drawEdges = true;
drawOpt.edgeColour = "#ffffff";
drawOpt.edgeWidth = 10;
drawOpt.edgeOpacity = 1;
drawOpt.drawFaces = true;
drawOpt.faceColour = "#ff0000";
drawOpt.faceOpacity = 1;
drawOpt.drawVertices = false;
await bitbybit.draw.drawAnyAsync({
entity: shape,
options: drawOpt
});
}
// Execute the main function
start();
Parse more parts
Once you understand the basics, you can extract multiple parts and style them independently. This is where things get exciting - you can create custom visualizations that highlight different components, use original colors from the CAD model, or apply your own color schemes.
What's New in This Example?
This advanced example introduces several important concepts:
-
Right-handed coordinate system - Some CAD software exports models with a different orientation (Y-Up). We use
useRightHandedSystemto ensure the model displays correctly. -
Multiple shape extraction - Instead of one shape, we extract four different parts using their labels.
-
Original colors from CAD - The
getLabelColorfunction retrieves the color assigned to a part in the original CAD software, preserving the designer's intent. -
Color conversion - CAD colors are stored as RGB objects (with values 0-1). We convert them to hex format (
#ff0000) usingrgbObjToHexfor use in drawing options. -
Batch rendering - Multiple shapes can be drawn with the same styling by passing them as an array.
Why This Matters
Understanding assembly structure unlocks powerful capabilities:
- Selective visualization - Show only the parts that matter for your use case
- Interactive configurators - Let users click to select and customize individual components
- Assembly analysis - Check if all required parts are present
- Documentation - Generate exploded views or highlight specific components
- Performance optimization - Load and display only the parts you need
BabylonJS uses a left-handed coordinate system by default, which causes Y-Up models to appear mirrored. We use useRightHandedSystem to compensate for this. This will be improved in the next release.
- Rete
- Blockly
- TypeScript
{
"id": "rete-v2-json",
"nodes": {
"e0e94797745b9499": {
"id": "e0e94797745b9499",
"name": "bitbybit.asset.fetchFile",
"customName": "fetch file",
"async": true,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"url": "https://learn.bitbybit.dev/files/3d/Soil-Sensor-Y-Up.stpZ"
},
"inputs": {},
"position": [
447.0390625,
364.58203125
]
},
"824be0f956f86e07": {
"id": "824be0f956f86e07",
"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,
"transparencyShadow": false,
"shadowContactHardeningLightSizeUVRatio": 0.2,
"shadowBias": 0.001,
"shadowNormalBias": 0.02,
"shadowMaxZ": 1000,
"shadowMinZ": 0,
"shadowRefreshRate": 6
},
"inputs": {
"direction": {
"connections": [
{
"node": "1cf530bc3b05cd75",
"output": "result",
"data": {}
}
]
}
},
"position": [
220.90978154060178,
1141.4474910149524
]
},
"a2753a0a68a97354": {
"id": "a2753a0a68a97354",
"name": "bitbybit.point.pointXYZ",
"customName": "point xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 0,
"y": -5,
"z": 0
},
"inputs": {},
"position": [
720.7524355897118,
1488.399577959778
]
},
"1cf530bc3b05cd75": {
"id": "1cf530bc3b05cd75",
"name": "bitbybit.point.pointXYZ",
"customName": "point xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 100,
"y": -100,
"z": -100
},
"inputs": {},
"position": [
-142.37939449872056,
1144.5669505658402
]
},
"09ff71828df19896": {
"id": "09ff71828df19896",
"name": "bitbybit.point.pointXYZ",
"customName": "point xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 70,
"y": 50,
"z": 70
},
"inputs": {},
"position": [
714.6847345665905,
1143.2908329012987
]
},
"d737b03aa186cfde": {
"id": "d737b03aa186cfde",
"name": "bitbybit.babylon.scene.adjustActiveArcRotateCamera",
"customName": "adjust active arc rotate camera",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"position": [
10,
10,
10
],
"lookAt": [
0,
0,
0
],
"lowerBetaLimit": 1,
"upperBetaLimit": 179,
"angularSensibilityX": 1000,
"angularSensibilityY": 1000,
"maxZ": 1000,
"panningSensibility": 1000,
"wheelPrecision": 3
},
"inputs": {
"lookAt": {
"connections": [
{
"node": "a2753a0a68a97354",
"output": "result",
"data": {}
}
]
},
"position": {
"connections": [
{
"node": "09ff71828df19896",
"output": "result",
"data": {}
}
]
}
},
"position": [
1140.4592129965072,
1279.8313039785085
]
},
"6e0425b3ab3715f4": {
"id": "6e0425b3ab3715f4",
"name": "bitbybit.occt.assembly.manager.loadStepToDoc",
"customName": "load step to doc",
"async": true,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"stepData": {
"connections": [
{
"node": "e0e94797745b9499",
"output": "result",
"data": {}
}
]
}
},
"position": [
815.8178400767682,
364.9872279487489
]
},
"ce31b6e5c2308c9c": {
"id": "ce31b6e5c2308c9c",
"name": "bitbybit.previewAssemblyHierarchy",
"customName": "preview occt assembly hierarchy",
"data": {},
"inputs": {
"data": {
"connections": [
{
"node": "a41ed949a48dd353",
"output": "result",
"data": {}
}
]
}
},
"position": [
1784.887643979641,
649.6759881067767
]
},
"a41ed949a48dd353": {
"id": "a41ed949a48dd353",
"name": "bitbybit.occt.assembly.query.getAssemblyHierarchy",
"customName": "get assembly hierarchy",
"async": true,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"document": {
"connections": [
{
"node": "6e0425b3ab3715f4",
"output": "result",
"data": {}
}
]
}
},
"position": [
1394.8366083022465,
607.909443023177
]
},
"4fe2985ce5a35e76": {
"id": "4fe2985ce5a35e76",
"name": "bitbybit.occt.assembly.query.getShapeFromLabel",
"customName": "get shape from label",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"label": "0:1:1:3"
},
"inputs": {
"document": {
"connections": [
{
"node": "6e0425b3ab3715f4",
"output": "result",
"data": {}
}
]
}
},
"position": [
2156.547963359031,
-12.896263949365462
]
},
"06851fe24453fd5c": {
"id": "06851fe24453fd5c",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"entity": {
"connections": [
{
"node": "4fe2985ce5a35e76",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "dfaed57ad37e99ee",
"output": "result",
"data": {}
}
]
}
},
"position": [
3671.1763385204913,
29.207742738975483
]
},
"dfaed57ad37e99ee": {
"id": "dfaed57ad37e99ee",
"name": "bitbybit.draw.optionsOcctShape",
"customName": "options occt shape",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"faceOpacity": 1,
"edgeOpacity": 1,
"edgeColour": "#ffffff",
"faceColour": "#ff0000",
"vertexColour": "#ff00ff",
"edgeWidth": 10,
"vertexSize": 0.03,
"drawEdges": true,
"drawFaces": true,
"drawVertices": false,
"precision": 0.1,
"drawEdgeIndexes": false,
"edgeIndexHeight": 0.06,
"edgeIndexColour": "#ff00ff",
"drawFaceIndexes": false,
"faceIndexHeight": 0.06,
"faceIndexColour": "#0000ff",
"drawTwoSided": false,
"backFaceColour": "#0000ff",
"backFaceOpacity": 1,
"edgeArrowSize": 0,
"edgeArrowAngle": 15
},
"inputs": {
"faceColour": {
"connections": [
{
"node": "7dee1698453f567d",
"output": "result",
"data": {}
}
]
}
},
"position": [
2995.9608037824505,
256.0881469787753
]
},
"f0d4e9ea3cd24449": {
"id": "f0d4e9ea3cd24449",
"name": "bitbybit.babylon.scene.twoColorLinearGradientBackground",
"customName": "two color linear gradient background",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"colorFrom": "#1a1c1f",
"colorTo": "#93aacd",
"direction": "to top",
"stopFrom": 0,
"stopTo": 100
},
"inputs": {},
"position": [
326.1284717805745,
2031.466101347526
]
},
"d5a48cb27b820987": {
"id": "d5a48cb27b820987",
"name": "bitbybit.occt.assembly.query.getLabelColor",
"customName": "get label color",
"async": true,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"label": "0:1:1:3"
},
"inputs": {
"document": {
"connections": [
{
"node": "6e0425b3ab3715f4",
"output": "result",
"data": {}
}
]
}
},
"position": [
2159.6684784714134,
305.31442553740163
]
},
"7dee1698453f567d": {
"id": "7dee1698453f567d",
"name": "bitbybit.color.rgbObjToHex",
"customName": "rgb obj to hex",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"rgb": {
"r": 0,
"g": 0,
"b": 1
},
"min": 0,
"max": 1
},
"inputs": {
"rgb": {
"connections": [
{
"node": "d5a48cb27b820987",
"output": "result",
"data": {}
}
]
}
},
"position": [
2624.3920949660132,
368.8889633788438
]
},
"d7c85a30eb78221f": {
"id": "d7c85a30eb78221f",
"name": "bitbybit.babylon.scene.useRightHandedSystem",
"customName": "use right handed system",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"use": true
},
"inputs": {},
"position": [
21.7841448438097,
366.34065342780343
]
},
"5036c49105610d5e": {
"id": "5036c49105610d5e",
"name": "bitbybit.occt.assembly.query.getShapeFromLabel",
"customName": "get shape from label",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"label": "0:1:1:5"
},
"inputs": {
"document": {
"connections": [
{
"node": "6e0425b3ab3715f4",
"output": "result",
"data": {}
}
]
}
},
"position": [
2151.823468782882,
-655.1743062177443
]
},
"dd577d75ba3affc0": {
"id": "dd577d75ba3affc0",
"name": "bitbybit.occt.assembly.query.getShapeFromLabel",
"customName": "get shape from label",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"label": "0:1:1:1:6"
},
"inputs": {
"document": {
"connections": [
{
"node": "6e0425b3ab3715f4",
"output": "result",
"data": {}
}
]
}
},
"position": [
2146.3287113784004,
-1309.6547664008176
]
},
"2b66393cc9a664d7": {
"id": "2b66393cc9a664d7",
"name": "bitbybit.occt.assembly.query.getShapeFromLabel",
"customName": "get shape from label",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"label": "0:1:1:1:7"
},
"inputs": {
"document": {
"connections": [
{
"node": "6e0425b3ab3715f4",
"output": "result",
"data": {}
}
]
}
},
"position": [
2158.734535684166,
-338.45393687967106
]
},
"c44f71935e30d923": {
"id": "c44f71935e30d923",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"entity": {
"connections": [
{
"node": "dd577d75ba3affc0",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "1b8a0240f5caf9d2",
"output": "result",
"data": {}
}
]
}
},
"position": [
3528.1664634619065,
-1695.1896885314713
]
},
"1b8a0240f5caf9d2": {
"id": "1b8a0240f5caf9d2",
"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": "#0011ff",
"drawEdges": true,
"edgeColour": "#ffffff",
"edgeWidth": 10,
"drawTwoSided": true,
"backFaceColour": "#0000ff",
"backFaceOpacity": 1
},
"inputs": {},
"position": [
3093.6154269708823,
-1404.5733810085403
]
},
"370d7f17f2793bdd": {
"id": "370d7f17f2793bdd",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"entity": {
"connections": [
{
"node": "5036c49105610d5e",
"output": "result",
"data": {}
},
{
"node": "2b66393cc9a664d7",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "48a24c0fde98d856",
"output": "result",
"data": {}
}
]
}
},
"position": [
3617.4327673234375,
-851.2304624572846
]
},
"48a24c0fde98d856": {
"id": "48a24c0fde98d856",
"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": "#fb05ff",
"drawEdges": true,
"edgeColour": "#000000",
"edgeWidth": 10,
"drawTwoSided": true,
"backFaceColour": "#0000ff",
"backFaceOpacity": 1
},
"inputs": {},
"position": [
3130.5380527600073,
-490.49271645542683
]
}
}
}
<xml xmlns="https://developers.google.com/blockly/xml"><variables><variable id="stepData">stepData</variable><variable id="document">document</variable><variable id="hierarchy">hierarchy</variable><variable id="shape1">shape1</variable><variable id="shape2">shape2</variable><variable id="shape3">shape3</variable><variable id="shape4">shape4</variable><variable id="labelColor">labelColor</variable><variable id="hexColor">hexColor</variable><variable id="bg">bg</variable></variables><block type="bitbybit.babylon.scene.useRightHandedSystem" id="useRHS" x="-562" y="-136"><value name="Use"><block type="logic_boolean" id="useRHSTrue"><field name="BOOL">TRUE</field></block></value><next><block type="variables_set" id="fetchStep" x="-562" y="-36"><field name="VAR" id="stepData">stepData</field><value name="VALUE"><block type="bitbybit.asset.fetchFile" id="fetchFile"><value name="Url"><block type="text" id="urlText"><field name="TEXT">https://learn.bitbybit.dev/files/3d/Soil-Sensor-Y-Up.stpZ</field></block></value></block></value><next><block type="variables_set" id="loadDoc"><field name="VAR" id="document">document</field><value name="VALUE"><block type="bitbybit.occt.assembly.manager.loadStepToDoc" id="loadStepToDoc"><value name="StepData"><block type="variables_get" id="getStepData"><field name="VAR" id="stepData">stepData</field></block></value></block></value><next><block type="variables_set" id="getHierarchy"><field name="VAR" id="hierarchy">hierarchy</field><value name="VALUE"><block type="base_time_await_return" id="awaitHierarchy"><value name="Promise"><block type="bitbybit.occt.assembly.query.getAssemblyHierarchy" id="assemblyHierarchy"><value name="Document"><block type="variables_get" id="getDoc1"><field name="VAR" id="document">document</field></block></value></block></value></block></value><next><block type="base_io_preview_assembly_hierarchy" id="previewHierarchy"><value name="Data"><block type="variables_get" id="getHierarchyVar"><field name="VAR" id="hierarchy">hierarchy</field></block></value><next><block type="variables_set" id="getShape1"><field name="VAR" id="shape1">shape1</field><value name="VALUE"><block type="bitbybit.occt.assembly.query.getShapeFromLabel" id="shapeFromLabel1"><value name="Document"><block type="variables_get" id="getDoc2"><field name="VAR" id="document">document</field></block></value><value name="Label"><block type="text" id="label1"><field name="TEXT">0:1:1:3</field></block></value></block></value><next><block type="variables_set" id="getShape2"><field name="VAR" id="shape2">shape2</field><value name="VALUE"><block type="bitbybit.occt.assembly.query.getShapeFromLabel" id="shapeFromLabel2"><value name="Document"><block type="variables_get" id="getDoc3"><field name="VAR" id="document">document</field></block></value><value name="Label"><block type="text" id="label2"><field name="TEXT">0:1:1:5</field></block></value></block></value><next><block type="variables_set" id="getShape3"><field name="VAR" id="shape3">shape3</field><value name="VALUE"><block type="bitbybit.occt.assembly.query.getShapeFromLabel" id="shapeFromLabel3"><value name="Document"><block type="variables_get" id="getDoc4"><field name="VAR" id="document">document</field></block></value><value name="Label"><block type="text" id="label3"><field name="TEXT">0:1:1:1:6</field></block></value></block></value><next><block type="variables_set" id="getShape4"><field name="VAR" id="shape4">shape4</field><value name="VALUE"><block type="bitbybit.occt.assembly.query.getShapeFromLabel" id="shapeFromLabel4"><value name="Document"><block type="variables_get" id="getDoc5"><field name="VAR" id="document">document</field></block></value><value name="Label"><block type="text" id="label4"><field name="TEXT">0:1:1:1:7</field></block></value></block></value><next><block type="variables_set" id="getLabelColor"><field name="VAR" id="labelColor">labelColor</field><value name="VALUE"><block type="bitbybit.occt.assembly.query.getLabelColor" id="labelColorBlock"><value name="Document"><block type="variables_get" id="getDoc6"><field name="VAR" id="document">document</field></block></value><value name="Label"><block type="text" id="labelForColor"><field name="TEXT">0:1:1:3</field></block></value></block></value><next><block type="variables_set" id="getHexColor"><field name="VAR" id="hexColor">hexColor</field><value name="VALUE"><block type="bitbybit.color.rgbObjToHex" id="rgbToHex"><value name="Rgb"><block type="variables_get" id="getLabelColorVar"><field name="VAR" id="labelColor">labelColor</field></block></value><value name="Min"><block type="math_number" id="minVal"><field name="NUM">0</field></block></value><value name="Max"><block type="math_number" id="maxVal"><field name="NUM">1</field></block></value></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn" id="drawShape1"><value name="Entity"><block type="variables_get" id="getShape1Var"><field name="VAR" id="shape1">shape1</field></block></value><value name="Options"><block type="bitbybit.draw.optionsOcctShapeSimple" id="drawOpt1"><value name="Precision"><block type="math_number" id="prec1"><field name="NUM">0.1</field></block></value><value name="DrawFaces"><block type="logic_boolean" id="drawFaces1"><field name="BOOL">TRUE</field></block></value><value name="FaceColour"><block type="variables_get" id="getHexColorVar"><field name="VAR" id="hexColor">hexColor</field></block></value><value name="DrawEdges"><block type="logic_boolean" id="drawEdges1"><field name="BOOL">TRUE</field></block></value><value name="EdgeColour"><block type="colour_picker" id="edgeColor1"><field name="COLOUR">#ffffff</field></block></value><value name="EdgeWidth"><block type="math_number" id="edgeWidth1"><field name="NUM">10</field></block></value><value name="DrawTwoSided"><block type="logic_boolean" id="twoSided1"><field name="BOOL">TRUE</field></block></value><value name="BackFaceColour"><block type="colour_picker" id="backFace1"><field name="COLOUR">#0000ff</field></block></value><value name="BackFaceOpacity"><block type="math_number" id="backOpacity1"><field name="NUM">1</field></block></value></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn" id="drawShape2and4"><value name="Entity"><block type="lists_create_with" id="shapesList"><mutation items="2"></mutation><value name="ADD0"><block type="variables_get" id="getShape2Var"><field name="VAR" id="shape2">shape2</field></block></value><value name="ADD1"><block type="variables_get" id="getShape4Var"><field name="VAR" id="shape4">shape4</field></block></value></block></value><value name="Options"><block type="bitbybit.draw.optionsOcctShapeSimple" id="drawOpt2"><value name="Precision"><block type="math_number" id="prec2"><field name="NUM">0.01</field></block></value><value name="DrawFaces"><block type="logic_boolean" id="drawFaces2"><field name="BOOL">TRUE</field></block></value><value name="FaceColour"><block type="colour_picker" id="faceColor2"><field name="COLOUR">#fb05ff</field></block></value><value name="DrawEdges"><block type="logic_boolean" id="drawEdges2"><field name="BOOL">TRUE</field></block></value><value name="EdgeColour"><block type="colour_picker" id="edgeColor2"><field name="COLOUR">#000000</field></block></value><value name="EdgeWidth"><block type="math_number" id="edgeWidth2"><field name="NUM">10</field></block></value><value name="DrawTwoSided"><block type="logic_boolean" id="twoSided2"><field name="BOOL">TRUE</field></block></value><value name="BackFaceColour"><block type="colour_picker" id="backFace2"><field name="COLOUR">#0000ff</field></block></value><value name="BackFaceOpacity"><block type="math_number" id="backOpacity2"><field name="NUM">1</field></block></value></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn" id="drawShape3"><value name="Entity"><block type="variables_get" id="getShape3Var"><field name="VAR" id="shape3">shape3</field></block></value><value name="Options"><block type="bitbybit.draw.optionsOcctShapeSimple" id="drawOpt3"><value name="Precision"><block type="math_number" id="prec3"><field name="NUM">0.01</field></block></value><value name="DrawFaces"><block type="logic_boolean" id="drawFaces3"><field name="BOOL">TRUE</field></block></value><value name="FaceColour"><block type="colour_picker" id="faceColor3"><field name="COLOUR">#0011ff</field></block></value><value name="DrawEdges"><block type="logic_boolean" id="drawEdges3"><field name="BOOL">TRUE</field></block></value><value name="EdgeColour"><block type="colour_picker" id="edgeColor3"><field name="COLOUR">#ffffff</field></block></value><value name="EdgeWidth"><block type="math_number" id="edgeWidth3"><field name="NUM">10</field></block></value><value name="DrawTwoSided"><block type="logic_boolean" id="twoSided3"><field name="BOOL">TRUE</field></block></value><value name="BackFaceColour"><block type="colour_picker" id="backFace3"><field name="COLOUR">#0000ff</field></block></value><value name="BackFaceOpacity"><block type="math_number" id="backOpacity3"><field name="NUM">1</field></block></value></block></value><next><block type="bitbybit.babylon.scene.drawDirectionalLightNoReturn" id="drawLight"><value name="Direction"><block type="bitbybit.vector.vectorXYZ" id="lightDir"><value name="X"><block type="math_number" id="lightX"><field name="NUM">100</field></block></value><value name="Y"><block type="math_number" id="lightY"><field name="NUM">-100</field></block></value><value name="Z"><block type="math_number" id="lightZ"><field name="NUM">-100</field></block></value></block></value><value name="Intensity"><block type="math_number" id="lightIntensity"><field name="NUM">3</field></block></value><value name="Diffuse"><block type="colour_picker" id="diffuse"><field name="COLOUR">#ffffff</field></block></value><value name="Specular"><block type="colour_picker" id="specular"><field name="COLOUR">#ffffff</field></block></value><value name="ShadowGeneratorMapSize"><block type="math_number" id="shadowMapSize"><field name="NUM">1024</field></block></value><value name="EnableShadows"><block type="logic_boolean" id="enableShadows"><field name="BOOL">TRUE</field></block></value><value name="ShadowDarkness"><block type="math_number" id="shadowDarkness"><field name="NUM">0</field></block></value><value name="ShadowUsePercentageCloserFiltering"><block type="logic_boolean" id="shadowPCF"><field name="BOOL">TRUE</field></block></value><value name="ShadowContactHardeningLightSizeUVRatio"><block type="math_number" id="shadowHardening"><field name="NUM">0.2</field></block></value><value name="ShadowBias"><block type="math_number" id="shadowBias"><field name="NUM">0.001</field></block></value><value name="ShadowNormalBias"><block type="math_number" id="shadowNormalBias"><field name="NUM">0.02</field></block></value><value name="ShadowMaxZ"><block type="math_number" id="shadowMaxZ"><field name="NUM">1000</field></block></value><value name="ShadowMinZ"><block type="math_number" id="shadowMinZ"><field name="NUM">0</field></block></value><next><block type="bitbybit.babylon.scene.adjustActiveArcRotateCamera" id="adjustCamera"><value name="Position"><block type="bitbybit.point.pointXYZ" id="camPos"><value name="X"><block type="math_number" id="camPosX"><field name="NUM">70</field></block></value><value name="Y"><block type="math_number" id="camPosY"><field name="NUM">50</field></block></value><value name="Z"><block type="math_number" id="camPosZ"><field name="NUM">70</field></block></value></block></value><value name="LookAt"><block type="bitbybit.point.pointXYZ" id="camLookAt"><value name="X"><block type="math_number" id="lookAtX"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="lookAtY"><field name="NUM">-5</field></block></value><value name="Z"><block type="math_number" id="lookAtZ"><field name="NUM">0</field></block></value></block></value><value name="LowerBetaLimit"><block type="math_number" id="lowerBeta"><field name="NUM">1</field></block></value><value name="UpperBetaLimit"><block type="math_number" id="upperBeta"><field name="NUM">179</field></block></value><value name="AngularSensibilityX"><block type="math_number" id="angSensX"><field name="NUM">1000</field></block></value><value name="AngularSensibilityY"><block type="math_number" id="angSensY"><field name="NUM">1000</field></block></value><value name="MaxZ"><block type="math_number" id="maxZ"><field name="NUM">1000</field></block></value><value name="PanningSensibility"><block type="math_number" id="panningSens"><field name="NUM">1000</field></block></value><value name="WheelPrecision"><block type="math_number" id="wheelPrec"><field name="NUM">3</field></block></value><next><block type="variables_set" id="setBg"><field name="VAR" id="bg">bg</field><value name="VALUE"><block type="bitbybit.babylon.scene.twoColorLinearGradientBackground" id="background"><value name="ColorFrom"><block type="colour_picker" id="colorFrom"><field name="COLOUR">#1a1c1f</field></block></value><value name="ColorTo"><block type="colour_picker" id="colorTo"><field name="COLOUR">#93aacd</field></block></value><value name="Direction"><block type="bitbybit.babylon.enums.gradientDirectionEnum" id="gradientDir"><field name="bitbybit.babylon.enums.gradientDirectionEnum">'to top'</field></block></value><value name="StopFrom"><block type="math_number" id="stopFrom"><field name="NUM">0</field></block></value><value name="StopTo"><block type="math_number" id="stopTo"><field name="NUM">100</field></block></value></block></value></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></xml>
// Import required DTOs for scene setup and assembly operations
const { SceneTwoColorLinearGradientDto, DirectionalLightDto, CameraConfigurationDto, UseRightHandedSystemDto } = Bit.Inputs.BabylonScene;
const { LoadStepToDocDto, DocumentLabelQueryDto, DocumentQueryDto } = Bit.Inputs.OCCT;
const { gradientDirectionEnum } = Bit.Inputs.Base;
// Import type definitions for type safety
type Point3 = Bit.Inputs.Base.Point3;
type Vector3 = Bit.Inputs.Base.Vector3;
// Get access to modules
const { scene } = bitbybit.babylon;
const { asset, color } = bitbybit;
const { manager, query } = bitbybit.occt.assembly;
const start = async () => {
// Enable right-handed coordinate system
const rhsOpt = new UseRightHandedSystemDto();
rhsOpt.use = true;
scene.useRightHandedSystem(rhsOpt);
// Setup two-color gradient background
const backgroundOpt = new SceneTwoColorLinearGradientDto();
backgroundOpt.colorFrom = "#1a1c1f";
backgroundOpt.colorTo = "#93aacd";
backgroundOpt.direction = gradientDirectionEnum.toTop;
backgroundOpt.stopFrom = 0;
backgroundOpt.stopTo = 100;
scene.twoColorLinearGradientBackground(backgroundOpt);
// Setup directional light with shadows
const dirLightOpt = new DirectionalLightDto();
dirLightOpt.direction = [100, -100, -100] as Vector3;
dirLightOpt.intensity = 3;
dirLightOpt.diffuse = "#ffffff";
dirLightOpt.specular = "#ffffff";
dirLightOpt.shadowGeneratorMapSize = 1024;
dirLightOpt.enableShadows = true;
dirLightOpt.shadowDarkness = 0;
dirLightOpt.shadowUsePercentageCloserFiltering = true;
dirLightOpt.shadowContactHardeningLightSizeUVRatio = 0.2;
dirLightOpt.shadowBias = 0.001;
dirLightOpt.shadowNormalBias = 0.02;
dirLightOpt.shadowMaxZ = 1000;
dirLightOpt.shadowMinZ = 0;
scene.drawDirectionalLight(dirLightOpt);
// Adjust camera position and settings
const cameraOpt = new CameraConfigurationDto();
cameraOpt.position = [70, 50, 70] as Point3;
cameraOpt.lookAt = [0, -5, 0] as Point3;
cameraOpt.lowerBetaLimit = 1;
cameraOpt.upperBetaLimit = 179;
cameraOpt.angularSensibilityX = 1000;
cameraOpt.angularSensibilityY = 1000;
cameraOpt.maxZ = 1000;
cameraOpt.panningSensibility = 1000;
cameraOpt.wheelPrecision = 3;
scene.adjustActiveArcRotateCamera(cameraOpt);
// Fetch the STEP file from URL (Y-Up version for right-handed system)
const stepData = await asset.fetchFile({
url: "https://learn.bitbybit.dev/files/3d/Soil-Sensor-Y-Up.stpZ"
});
// Load STEP data into an OCCT document
const loadDocOpt = new LoadStepToDocDto();
loadDocOpt.stepData = stepData;
const document = await manager.loadStepToDoc(loadDocOpt);
// Get assembly hierarchy (useful for understanding structure)
const hierarchyOpt = new DocumentQueryDto<Bit.Inputs.OCCT.TDocStdDocumentPointer>();
hierarchyOpt.document = document;
const hierarchy = await query.getAssemblyHierarchy(hierarchyOpt);
console.log("Assembly Hierarchy:", hierarchy);
// Get multiple shapes from the assembly using their labels
const shapeOpt1 = new DocumentLabelQueryDto<Bit.Inputs.OCCT.TDocStdDocumentPointer>();
shapeOpt1.document = document;
shapeOpt1.label = "0:1:1:3";
const shape1 = await query.getShapeFromLabel(shapeOpt1);
const shapeOpt2 = new DocumentLabelQueryDto<Bit.Inputs.OCCT.TDocStdDocumentPointer>();
shapeOpt2.document = document;
shapeOpt2.label = "0:1:1:5";
const shape2 = await query.getShapeFromLabel(shapeOpt2);
const shapeOpt3 = new DocumentLabelQueryDto<Bit.Inputs.OCCT.TDocStdDocumentPointer>();
shapeOpt3.document = document;
shapeOpt3.label = "0:1:1:1:6";
const shape3 = await query.getShapeFromLabel(shapeOpt3);
const shapeOpt4 = new DocumentLabelQueryDto<Bit.Inputs.OCCT.TDocStdDocumentPointer>();
shapeOpt4.document = document;
shapeOpt4.label = "0:1:1:1:7";
const shape4 = await query.getShapeFromLabel(shapeOpt4);
// Get the color from a label in the assembly
const colorOpt = new DocumentLabelQueryDto<Bit.Inputs.OCCT.TDocStdDocumentPointer>();
colorOpt.document = document;
colorOpt.label = "0:1:1:3";
const labelColor = await query.getLabelColor(colorOpt);
// Convert RGB object to hex color
const hexColor = color.rgbObjToHex({
rgb: labelColor,
min: 0,
max: 1
});
// Draw shape1 with color from assembly
const drawOpt1 = new Bit.Inputs.Draw.DrawOcctShapeSimpleOptions();
drawOpt1.precision = 0.1;
drawOpt1.drawEdges = true;
drawOpt1.edgeColour = "#ffffff";
drawOpt1.edgeWidth = 10;
drawOpt1.drawFaces = true;
drawOpt1.faceColour = hexColor;
drawOpt1.drawTwoSided = true;
drawOpt1.backFaceColour = "#0000ff";
drawOpt1.backFaceOpacity = 1;
await bitbybit.draw.drawAnyAsync({
entity: shape1,
options: drawOpt1
});
// Draw shapes 2 and 4 with magenta color
const drawOpt2 = new Bit.Inputs.Draw.DrawOcctShapeSimpleOptions();
drawOpt2.precision = 0.01;
drawOpt2.drawEdges = true;
drawOpt2.edgeColour = "#000000";
drawOpt2.edgeWidth = 10;
drawOpt2.drawFaces = true;
drawOpt2.faceColour = "#fb05ff";
drawOpt2.drawTwoSided = true;
drawOpt2.backFaceColour = "#0000ff";
drawOpt2.backFaceOpacity = 1;
await bitbybit.draw.drawAnyAsync({
entity: [shape2, shape4],
options: drawOpt2
});
// Draw shape3 with blue color
const drawOpt3 = new Bit.Inputs.Draw.DrawOcctShapeSimpleOptions();
drawOpt3.precision = 0.01;
drawOpt3.drawEdges = true;
drawOpt3.edgeColour = "#ffffff";
drawOpt3.edgeWidth = 10;
drawOpt3.drawFaces = true;
drawOpt3.faceColour = "#0011ff";
drawOpt3.drawTwoSided = true;
drawOpt3.backFaceColour = "#0000ff";
drawOpt3.backFaceOpacity = 1;
await bitbybit.draw.drawAnyAsync({
entity: shape3,
options: drawOpt3
});
}
// Execute the main function
start();
Conclusion
You've learned the fundamentals of working with OCCT assembly structures! Here's a quick recap:
- Assemblies are hierarchical - Parts are organized in a tree structure with unique labels
- Labels are addresses - Use them to pinpoint and extract specific shapes
- Colors can be preserved - Extract original CAD colors using
getLabelColor - Coordinate systems matter - Use
useRightHandedSystemwhen models appear incorrectly oriented
With these skills, you can now build interactive 3D viewers, product configurators, and CAD visualization tools that work with professional engineering files. Try experimenting with your own STEP files to see how different assemblies are structured!



