Christmas Tree
🎄 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.
- Rete
- Blockly
- TypeScript
{
"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
]
}
}
}
<xml xmlns="https://developers.google.com/blockly/xml"><variables><variable id="height">height</variable><variable id="nrSkirts">nrSkirts</variable><variable id="thickness">thickness</variable><variable id="treeWire">treeWire</variable><variable id="offsetWire">offsetWire</variable><variable id="reversedWire">reversedWire</variable><variable id="treeFace">treeFace</variable><variable id="treeSolid">treeSolid</variable><variable id="finalTree">finalTree</variable><variable id="[3JqnI1TH$EOUGt],kc!">drawnTreeMesh</variable></variables><block type="variables_set" id="set_height" x="-600" y="-200"><field name="VAR" id="height">height</field><value name="VALUE"><block type="math_number" id="height_val"><field name="NUM">8</field></block></value><next><block type="variables_set" id="set_skirts"><field name="VAR" id="nrSkirts">nrSkirts</field><value name="VALUE"><block type="math_number" id="skirts_val"><field name="NUM">4</field></block></value><next><block type="variables_set" id="set_thickness"><field name="VAR" id="thickness">thickness</field><value name="VALUE"><block type="math_number" id="thickness_val"><field name="NUM">2</field></block></value><next><block type="variables_set" id="set_tree_wire"><field name="VAR" id="treeWire">treeWire</field><value name="VALUE"><block type="bitbybit.occt.shapes.wire.createChristmasTreeWire" id="tree_wire"><value name="Height"><block type="variables_get" id="get_height"><field name="VAR" id="height">height</field></block></value><value name="InnerDist"><block type="math_number" id="inner_dist"><field name="NUM">1.5</field></block></value><value name="OuterDist"><block type="math_number" id="outer_dist"><field name="NUM">3</field></block></value><value name="NrSkirts"><block type="variables_get" id="get_skirts"><field name="VAR" id="nrSkirts">nrSkirts</field></block></value><value name="TrunkHeight"><block type="math_number" id="trunk_height"><field name="NUM">1</field></block></value><value name="TrunkWidth"><block type="math_number" id="trunk_width"><field name="NUM">1</field></block></value><value name="Half"><block type="logic_boolean" id="half"><field name="BOOL">FALSE</field></block></value><value name="Rotation"><block type="math_number" id="pUDJ8.xMeR$z$6J1;[r:"><field name="NUM">0</field></block></value><value name="Origin"><block type="bitbybit.point.pointXYZ" id="origin"><value name="X"><block type="math_number" id="ox"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="oy"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number" id="oz"><field name="NUM">0</field></block></value></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ" id="direction"><value name="X"><block type="math_number" id="dx"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="dy"><field name="NUM">1</field></block></value><value name="Z"><block type="math_number" id="dz"><field name="NUM">0</field></block></value></block></value></block></value><next><block type="variables_set" id="set_offset"><field name="VAR" id="offsetWire">offsetWire</field><value name="VALUE"><block type="bitbybit.occt.operations.offset" id="offset"><value name="Shape"><block type="variables_get" id="get_tree"><field name="VAR" id="treeWire">treeWire</field></block></value><value name="Distance"><block type="math_number" id="offset_dist"><field name="NUM">-0.2</field></block></value><value name="Tolerance"><block type="math_number" id="tolerance"><field name="NUM">0.1</field></block></value></block></value><next><block type="variables_set" id="set_reversed"><field name="VAR" id="reversedWire">reversedWire</field><value name="VALUE"><block type="bitbybit.occt.shapes.wire.reversedWire" id="reverse"><value name="Shape"><block type="variables_get" id="get_offset"><field name="VAR" id="offsetWire">offsetWire</field></block></value></block></value><next><block type="variables_set" id="set_face"><field name="VAR" id="treeFace">treeFace</field><value name="VALUE"><block type="bitbybit.occt.shapes.face.createFaceFromWires" id="face_from_wires"><value name="Shapes"><block type="lists_create_with" id="wires_list"><mutation items="2"></mutation><value name="ADD0"><block type="variables_get" id="get_tree2"><field name="VAR" id="treeWire">treeWire</field></block></value><value name="ADD1"><block type="variables_get" id="get_reversed"><field name="VAR" id="reversedWire">reversedWire</field></block></value></block></value><value name="Planar"><block type="logic_boolean" id="planar"><field name="BOOL">TRUE</field></block></value></block></value><next><block type="variables_set" id="set_solid"><field name="VAR" id="treeSolid">treeSolid</field><value name="VALUE"><block type="bitbybit.occt.operations.extrude" id="extrude"><value name="Shape"><block type="variables_get" id="get_face"><field name="VAR" id="treeFace">treeFace</field></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ" id="extrude_dir"><value name="X"><block type="math_number" id="ex"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="ey"><field name="NUM">0</field></block></value><value name="Z"><block type="variables_get" id="get_thick"><field name="VAR" id="thickness">thickness</field></block></value></block></value></block></value><next><block type="variables_set" id="set_final"><field name="VAR" id="finalTree">finalTree</field><value name="VALUE"><block type="bitbybit.occt.transforms.translate" id="translate"><value name="Shape"><block type="variables_get" id="get_solid"><field name="VAR" id="treeSolid">treeSolid</field></block></value><value name="Translation"><block type="bitbybit.vector.vectorXYZ" id="trans_vec"><value name="X"><block type="math_number" id="tx"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="ty"><field name="NUM">0</field></block></value><value name="Z"><block type="math_arithmetic" id="tz"><field name="OP">DIVIDE</field><value name="A"><block type="math_single" id="negate"><field name="OP">NEG</field><value name="NUM"><block type="variables_get" id="get_thick2"><field name="VAR" id="thickness">thickness</field></block></value></block></value><value name="B"><block type="math_number" id="div2"><field name="NUM">2</field></block></value></block></value></block></value></block></value><next><block type="base_time_async_context" id="*mIQ$/AFF%(abk3[o#58"><statement name="Then"><block type="variables_set" id="6q}kpfsh6,UeWMS:%_5a"><field name="VAR" id="[3JqnI1TH$EOUGt],kc!">drawnTreeMesh</field><value name="VALUE"><block type="bitbybit.draw.drawAnyAsync" id="]86t7Du2%b:OEO2[=`Yh"><value name="Entity"><block type="variables_get" id="get_final"><field name="VAR" id="finalTree">finalTree</field></block></value><value name="Options"><block type="bitbybit.draw.optionsOcctShapeMaterial" id="draw_options"><value name="Precision"><block type="math_number" id="precision"><field name="NUM">0.001</field></block></value><value name="FaceMaterial"><block type="bitbybit.babylon.material.pbrMetallicRoughness.create" id="pbr_material"><value name="Name"><block type="text" id="mat_name"><field name="TEXT">Tree Material</field></block></value><value name="BaseColor"><block type="colour_picker" id="base_color"><field name="COLOUR">#ffffff</field></block></value><value name="EmissiveColor"><block type="colour_picker" id="emissive_color"><field name="COLOUR">#00ffcc</field></block></value><value name="Metallic"><block type="math_number" id="metallic"><field name="NUM">0.8</field></block></value><value name="Roughness"><block type="math_number" id="roughness"><field name="NUM">0.99</field></block></value><value name="Alpha"><block type="math_number" id="alpha"><field name="NUM">1</field></block></value><value name="BackFaceCulling"><block type="logic_boolean" id="backface"><field name="BOOL">FALSE</field></block></value><value name="ZOffset"><block type="math_number" id="zoffset"><field name="NUM">2</field></block></value></block></value><value name="DrawEdges"><block type="logic_boolean" id="draw_edges"><field name="BOOL">TRUE</field></block></value><value name="EdgeColour"><block type="colour_picker" id="edge_colour"><field name="COLOUR">#000000</field></block></value><value name="EdgeWidth"><block type="math_number" id="edge_width"><field name="NUM">1</field></block></value></block></value></block></value><next><block type="bitbybit.advanced.navigation.zoomOn" id="17F|/S`W.B*I8fh^nf[F"><value name="Meshes"><block type="lists_create_with" id="kv;=Z`7Z.iGpEoyJI*hk"><mutation items="1"></mutation><value name="ADD0"><block type="variables_get" id=":`S[4n|KlG{*TLnkO$QC"><field name="VAR" id="[3JqnI1TH$EOUGt],kc!">drawnTreeMesh</field></block></value></block></value><value name="IncludeChildren"><block type="logic_boolean" id=")J_pE%R5SiypUO7^sznB"><field name="BOOL">TRUE</field></block></value><value name="AnimationSpeed"><block type="math_number" id="_HL3X,:lB{hoI{xnP]-["><field name="NUM">0.8</field></block></value><value name="Offset"><block type="math_number" id="$|fyj@i;_N!Bt,yaFNQ@"><field name="NUM">0</field></block></value><value name="DoNotUpdateMaxZ"><block type="logic_boolean" id="1*aGlJ7AVZ?Xii_=OFmU"><field name="BOOL">TRUE</field></block></value></block></next></block></statement></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></xml>
const { ChristmasTreeDto, OffsetDto, FaceFromWiresDto, ExtrudeDto, TranslateDto } = Bit.Inputs.OCCT;
const { PBRMetallicRoughnessDto } = Bit.Inputs.BabylonMaterial;
const { ZoomOnDto } = Bit.Advanced.Navigation;
type TopoDSWirePointer = Bit.Inputs.OCCT.TopoDSWirePointer;
type TopoDSFacePointer = Bit.Inputs.OCCT.TopoDSFacePointer;
type TopoDSShapePointer = Bit.Inputs.OCCT.TopoDSShapePointer;
const { wire, face } = bitbybit.occt.shapes;
const { operations, transforms } = bitbybit.occt;
const start = async () => {
// Define control variables
const height = 6.5;
const nrSkirts = 5;
const thickness = 0.5;
// Create PBR material with emissive glow
const materialOptions = new PBRMetallicRoughnessDto();
materialOptions.name = "Tree Material";
materialOptions.baseColor = "#ffffff";
materialOptions.emissiveColor = "#00ffcc";
materialOptions.metallic = 0.8;
materialOptions.roughness = 0.99;
materialOptions.alpha = 1;
materialOptions.backFaceCulling = false;
materialOptions.zOffset = 2;
const material = bitbybit.babylon.material.pbrMetallicRoughness.create(materialOptions);
// Create the Christmas tree wire
const treeOptions = new ChristmasTreeDto();
treeOptions.height = height;
treeOptions.nrSkirts = nrSkirts;
treeOptions.innerDist = 1.5;
treeOptions.outerDist = 3;
treeOptions.trunkHeight = 1;
treeOptions.trunkWidth = 1;
treeOptions.origin = [0, 0, 0];
treeOptions.direction = [0, 1, 0];
treeOptions.half = false;
const treeWire = await wire.createChristmasTreeWire(treeOptions);
// Create offset wire (inner boundary)
const offsetOptions = new OffsetDto<TopoDSShapePointer, TopoDSFacePointer>();
offsetOptions.shape = treeWire;
offsetOptions.distance = -0.2;
offsetOptions.tolerance = 0.1;
const offsetWire = await operations.offset(offsetOptions);
// Reverse the inner wire for proper face creation
const reversedWire = await wire.reversedWire({ shape: offsetWire });
// Create face from both wires (outer and reversed inner)
const faceOptions = new FaceFromWiresDto<TopoDSWirePointer>();
faceOptions.shapes = [treeWire, reversedWire];
faceOptions.planar = true;
const treeFace = await face.createFaceFromWires(faceOptions);
// Extrude the face to create thickness
const extrudeOptions = new ExtrudeDto<TopoDSFacePointer>();
extrudeOptions.shape = treeFace;
extrudeOptions.direction = [0, 0, thickness];
const treeSolid = await operations.extrude(extrudeOptions);
// Translate to center the shape
const translateOptions = new TranslateDto<TopoDSShapePointer>();
translateOptions.shape = treeSolid;
translateOptions.translation = [0, 0, -thickness / 2];
const finalTree = await transforms.translate(translateOptions);
// Draw with custom material and edge styling
const drawOptions = new Bit.Inputs.Draw.DrawOcctShapeOptions();
drawOptions.precision = 0.001;
drawOptions.drawEdges = true;
drawOptions.edgeColour = "#000000";
drawOptions.edgeWidth = 1;
drawOptions.faceMaterial = material;
const drawnTreeMesh = await bitbybit.draw.drawAnyAsync({
entity: finalTree,
options: drawOptions
});
const zoomOptions = new ZoomOnDto([drawnTreeMesh]);
bitbybit.advanced.navigation.zoomOn(zoomOptions);
}
start();
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:
- Offset: We apply a negative offset (-0.2) to shrink the wire inward, creating an inner boundary
- Reverse Wire: The inner wire must be reversed so that when combined with the outer wire, they form a proper hollow face
- 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
heightparameter for a more majestic tree - More Layers: Increase
nrSkirtsfor a bushier, more detailed tree - Thicker Ornament: Adjust the
thicknessslider 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! 🎄



