Skip to main content

Christmas Tree

OCCT category icon with a stylized logo representation

🎄 What better way to celebrate the festive season than by creating your very own 3D printable Christmas tree! In this tutorial, you'll learn how to create a charming tree ornament using wire operations and extrusion techniques.

This tutorial introduces important CAD concepts: creating specialized wire shapes, applying offsets to create hollow shapes, reversing wires for proper face creation, and extruding to create 3D solids. These techniques are essential for creating many types of decorative objects!

The Christmas Tree Shape

Our tree starts with the createChristmasTreeWire function, which generates a stylized tree silhouette with customizable height, number of skirts (layers), and trunk dimensions. We then create a hollow shape by offsetting the wire inward and combining both wires to form a face.

Bitbybit Platform

Christmas tree ornament

rete logoRete
Script Source (rete)
{
"id": "rete-v2-json",
"nodes": {
"a932fe6ce769acfa": {
"id": "a932fe6ce769acfa",
"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": "da2acd0d47017c24",
"output": "result",
"data": {}
}
]
},
"entity": {
"connections": [
{
"node": "1939360f8cfd0f2c",
"output": "result",
"data": {}
}
]
}
},
"position": [
3594.1578079633227,
290.78454059034675
]
},
"da2acd0d47017c24": {
"id": "da2acd0d47017c24",
"name": "bitbybit.draw.optionsOcctShapeMaterial",
"customName": "options occt shape material",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"precision": 0.001,
"drawEdges": true,
"edgeColour": "#000000",
"edgeWidth": 1
},
"inputs": {
"faceMaterial": {
"connections": [
{
"node": "afe922cb471989f2",
"output": "result",
"data": {}
}
]
}
},
"position": [
3110.2310988276963,
657.2956972942368
]
},
"afe922cb471989f2": {
"id": "afe922cb471989f2",
"name": "bitbybit.babylon.material.pbrMetallicRoughness.create",
"customName": "pbr metallic roughness",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"name": "Custom Material",
"baseColor": "#ffffff",
"emissiveColor": "#00ffcc",
"metallic": 0.8,
"roughness": 0.99,
"alpha": 1,
"backFaceCulling": false,
"zOffset": 2
},
"inputs": {},
"position": [
2716.9293228554334,
697.6514263073639
]
},
"79d52744100a3112": {
"id": "79d52744100a3112",
"name": "bitbybit.occt.shapes.wire.createChristmasTreeWire",
"customName": "christmas tree wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"height": 6,
"innerDist": 1.5,
"outerDist": 3,
"nrSkirts": 5,
"trunkHeight": 1,
"trunkWidth": 1,
"half": false,
"rotation": 0,
"origin": [
0,
0,
0
],
"direction": [
0,
1,
0
]
},
"inputs": {
"height": {
"connections": [
{
"node": "63e0af5f77dce775",
"output": "result",
"data": {}
}
]
},
"nrSkirts": {
"connections": [
{
"node": "d08945e62f24fbb3",
"output": "result",
"data": {}
}
]
}
},
"position": [
546.3762864386036,
-471.0596093720724
]
},
"a3d0e894bd5ebf71": {
"id": "a3d0e894bd5ebf71",
"name": "bitbybit.occt.operations.offset",
"customName": "offset",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"distance": -0.2,
"tolerance": 0.1
},
"inputs": {
"shape": {
"connections": [
{
"node": "79d52744100a3112",
"output": "result",
"data": {}
}
]
}
},
"position": [
954.3103175963458,
-273.67929088778646
]
},
"9238033b4014a6cc": {
"id": "9238033b4014a6cc",
"name": "bitbybit.occt.shapes.wire.reversedWire",
"customName": "reversed wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"shape": {
"connections": [
{
"node": "a3d0e894bd5ebf71",
"output": "result",
"data": {}
}
]
}
},
"position": [
1344.5982416146323,
-275.37459604091447
]
},
"34d31006f74ca955": {
"id": "34d31006f74ca955",
"name": "bitbybit.occt.shapes.face.createFaceFromWires",
"customName": "face from wires",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"planar": true
},
"inputs": {
"shapes": {
"connections": [
{
"node": "0b768057a17b3295",
"output": "list",
"data": {}
}
]
}
},
"position": [
2214.7243683018314,
-475.0663658026932
]
},
"0b768057a17b3295": {
"id": "0b768057a17b3295",
"name": "bitbybit.lists.createList",
"customName": "create list",
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "79d52744100a3112",
"output": "result",
"data": {}
},
{
"node": "9238033b4014a6cc",
"output": "result",
"data": {}
}
]
}
},
"position": [
1732.7863844808319,
-435.99928596405556
]
},
"4b3ad6c9c9d60d30": {
"id": "4b3ad6c9c9d60d30",
"name": "bitbybit.occt.operations.extrude",
"customName": "extrude",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"direction": [
0,
1,
0
]
},
"inputs": {
"shape": {
"connections": [
{
"node": "34d31006f74ca955",
"output": "result",
"data": {}
}
]
},
"direction": {
"connections": [
{
"node": "ce6014fe1483c928",
"output": "result",
"data": {}
}
]
}
},
"position": [
2683.7999039789725,
-155.97027806282958
]
},
"ce6014fe1483c928": {
"id": "ce6014fe1483c928",
"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": 1
},
"inputs": {
"z": {
"connections": [
{
"node": "76c568ee3e8321b1",
"output": "result",
"data": {}
}
]
}
},
"position": [
2220.2405238398114,
-36.486176362989994
]
},
"1939360f8cfd0f2c": {
"id": "1939360f8cfd0f2c",
"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": "4b3ad6c9c9d60d30",
"output": "result",
"data": {}
}
]
},
"translation": {
"connections": [
{
"node": "91164aa6213e17b7",
"output": "result",
"data": {}
}
]
}
},
"position": [
3124.664806252851,
19.75642048287014
]
},
"76c568ee3e8321b1": {
"id": "76c568ee3e8321b1",
"name": "bitbybit.math.numberSlider",
"customName": "thickness",
"data": {
"options": {
"min": 0.3,
"max": 10,
"step": 0.1,
"width": 350,
"updateOnDrag": false
},
"number": 1
},
"inputs": {},
"position": [
-58.97592277012882,
198.3307979031627
]
},
"8594dd1286c4cc80": {
"id": "8594dd1286c4cc80",
"name": "bitbybit.math.divide",
"customName": "divide",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"first": 1,
"second": -2
},
"inputs": {
"first": {
"connections": [
{
"node": "76c568ee3e8321b1",
"output": "result",
"data": {}
}
]
}
},
"position": [
2219.785919470777,
327.7500037345209
]
},
"91164aa6213e17b7": {
"id": "91164aa6213e17b7",
"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": 1
},
"inputs": {
"z": {
"connections": [
{
"node": "8594dd1286c4cc80",
"output": "result",
"data": {}
}
]
}
},
"position": [
2704.8361748389225,
272.80238269882733
]
},
"18a73e114a608f1a": {
"id": "18a73e114a608f1a",
"name": "bitbybit.advanced.navigation.zoomOn",
"customName": "zoom on",
"async": true,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"meshes": [],
"includeChildren": true,
"animationSpeed": 0.8,
"offset": 0,
"doNotUpdateMaxZ": true
},
"inputs": {
"meshes": {
"connections": [
{
"node": "f6dfebdd2cdc4d89",
"output": "list",
"data": {}
}
]
}
},
"position": [
4376.7854728627535,
301.8636179550458
]
},
"f6dfebdd2cdc4d89": {
"id": "f6dfebdd2cdc4d89",
"name": "bitbybit.lists.createList",
"customName": "create list",
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "a932fe6ce769acfa",
"output": "result",
"data": {}
}
]
}
},
"position": [
3965.021403582512,
330.8252706728621
]
},
"63e0af5f77dce775": {
"id": "63e0af5f77dce775",
"name": "bitbybit.math.numberSlider",
"customName": "height",
"data": {
"options": {
"min": 4,
"max": 12,
"step": 0.1,
"width": 350,
"updateOnDrag": false
},
"number": 6.5
},
"inputs": {},
"position": [
-81.84956634248212,
-477.96914891477024
]
},
"d08945e62f24fbb3": {
"id": "d08945e62f24fbb3",
"name": "bitbybit.math.numberSlider",
"customName": "skirts",
"data": {
"options": {
"min": 1,
"max": 7,
"step": 1,
"width": 350,
"updateOnDrag": false
},
"number": 3
},
"inputs": {},
"position": [
-83.43661827210975,
-285.8102741025945
]
}
}
}

Understanding the Code

Christmas Tree Wire Creation

The createChristmasTreeWire function generates the tree silhouette with these key parameters:

  • height: Total height of the tree (default 6.5 units)
  • nrSkirts: Number of layered branches/skirts (default 3)
  • innerDist: Distance from center to inner edge of skirts
  • outerDist: Distance from center to outer edge of skirts
  • trunkHeight: Height of the tree trunk
  • trunkWidth: Width of the tree trunk
  • direction: The normal vector (facing up in Y direction)

Creating a Hollow Shape with Offset

To make our tree ornament hollow (perfect for 3D printing), we use these techniques:

  1. Offset: We apply a negative offset (-0.2) to shrink the wire inward, creating an inner boundary
  2. Reverse Wire: The inner wire must be reversed so that when combined with the outer wire, they form a proper hollow face
  3. Face from Wires: We combine both wires to create a face with a hole in the middle

Extrusion and Centering

The face is extruded along the Z-axis to create thickness. We then translate the shape by half the thickness in the negative Z direction to center it around the origin.

Making It Your Own 🎁

Try these festive variations:

  • Taller Tree: Increase the height parameter for a more majestic tree
  • More Layers: Increase nrSkirts for a bushier, more detailed tree
  • Thicker Ornament: Adjust the thickness slider for a more substantial piece
  • Different Offset: Change the offset distance for thicker or thinner walls

3D Printing Tips

Your Christmas tree ornament is print-ready! For best results:

  • Layer Height: 0.2mm works great
  • Infill: Not needed for hollow ornaments!
  • Material: Green PLA for a classic look, or try glow-in-the-dark filament
  • Support: Usually not needed when printed flat

Happy holidays and happy modeling! 🎄