Example: bike_pack_mount
// Copyright © 2025 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::geo2d::*;
use std::ops::*;
use std::math::*;
sketch Base(
width = 130.0mm,
height = 23.5mm,
radius = 3mm,
) {
RoundedRect(width, height, radius);
}
part RackRails(
rack_rail_distance = 100mm,
rack_rail_diameter = 10.5mm,
) {
{
rd = (rack_rail_distance + rack_rail_diameter) / 2;
Circle(d = rack_rail_diameter, c = (x = [-0.5,0.5]mm, y = 0mm))
.hull()
.translate(x = [-rd, rd]);
}
.extrude(40mm)
.orient(Y)
.translate(y = -15mm);
}
part Mount(
height: Length,
screw_distance = 94mm,
screw_hole_diameter = 6mm,
rack_rail_distance = 100mm,
rack_rail_diameter = 10.5mm,
) {
d = screw_distance / 2;
screws = Circle(d = screw_hole_diameter, c = (x = [-d,d], y = 0.0mm));
Base().extrude(height) - screws.extrude(height + 10mm) - RackRails();
}
pub part Lower() {
Mount(height = 15mm);
}
pub part Upper() {
Mount(height = 55mm);
}
#[export = "lower.stl"]
Lower().translate(y = 50mm);
#[export = "upper.stl"]
Upper().translate(y = -50mm);
2D Output
:
3D Output
:
Example: bricks
Module: brick
// file: brick.µcad
// Copyright © 2025-2026 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::geo2d::*;
use std::ops::*;
use std::math::*;
pub const SPACING = 8mm;
pub const THICKNESS = 1.2mm;
pub const BASE_HEIGHT = 9.6mm;
pub const TOLERANCE = 0.2mm;
pub part Brick(rows = 2, columns = 4, base_height = BASE_HEIGHT) {
width = columns * SPACING - TOLERANCE;
height = rows * SPACING - TOLERANCE;
base = {
Frame(width, height, THICKNESS);
r = rows - 1;
c = columns - 1;
n_rings = r * c;
if n_rings > 0 {
Ring(outer_diameter = 6.51mm, inner_diameter = 4.8mm)
.multiply(n_rings)
.distribute_grid(
width = width - width / columns,
height = height - height / rows,
rows = r,
columns = c
);
}
}
.extrude(base_height - THICKNESS);
cap = Rect(width, height).extrude(THICKNESS);
knobs = Circle(d = 4.8mm)
.multiply(rows * columns)
.distribute_grid(width, height, rows, columns)
.extrude(1.7mm);
{ base; cap; knobs; }.align(Z).union();
}
n = 4;
Brick(
rows = [1..n],
columns = [1..n],
base_height = BASE_HEIGHT * [1 / 3, 100%, 200%, 300%]
)
.distribute_grid(cell_size = n * 10mm,
rows = 2*n,
columns = 2*n,
);
2D Output
:
3D Output
:
Module: tutorial
// file: tutorial.µcad
// Copyright © 2025-2026 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::geo2d::*;
use std::ops::*;
pub const SPACING = 8mm;
op grid(columns: Integer, rows: Integer) {
@input
.translate(x = [1..columns] * SPACING, y = [1..rows] * SPACING)
.center()
}
sketch Base(
columns: Integer,
rows: Integer,
width: Length,
height: Length
) {
thickness = 1.2mm;
frame = Frame(width, height, thickness);
struts = Ring(outer_diameter = 6.51mm, inner_diameter = 4.8mm)
.grid(columns = columns-1, rows = rows-1);
frame | struts;
}
use Rect as Cap;
sketch Knobs(columns: Integer, rows: Integer) {
Circle(d = 4.8mm)
.grid(columns, rows);
}
pub part LegoBrick(rows = 2, columns = 4, base_height = 9.6mm) {
width = columns * SPACING - 0.2mm;
height =rows * SPACING - 0.2mm;
cap_thickness = 1.0mm;
base = Base(rows, columns, width, height)
.extrude(base_height - cap_thickness);
cap = Cap(width, height)
.extrude(cap_thickness)
.translate(z = base_height - cap_thickness);
knobs = Knobs(rows, columns)
.extrude(1.7mm)
.translate(z = base_height);
base | cap | knobs;
}
// render a brick with default values
LegoBrick();
2D Output
:
3D Output
:
Module: use_bricks
// file: use_bricks.µcad
// Copyright © 2025 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
mod brick;
use brick::*;
// 2x2 double height
double_2x2 = Brick(rows = 2, columns = 2, base_height = 9.6mm * 2);
// 4x2 single height
single_4x2 = Brick(rows = 4, columns = 2);
// 3x2 one-third height
third_3x2 = Brick(rows = 3, columns = 2, base_height = 3.2mm);
// generate geometry placing all elements side by side
use std::ops::translate;
single_4x2;
double_2x2.translate(y = -40mm);
third_3x2.translate(y = 40mm);
2D Output
:
3D Output
:
Example: buffer_stand
// Copyright © 2025 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::ops::*;
use std::geo2d::*;
use std::math::*;
part BufferStand() {
size = 5.25in;
width = 5.875in;
base = (Circle(d = width) & Rect(width, height = size / 2))
.extrude(4.0in);
side = {
Line(height = size/2);
Circle(d = 1.5in).translate(x = -3.25in);
}
.hull()
.extrude(width)
.orient(X)
.translate(x = -width / 2);
front_cut_off = {
w = 4.25in;
d = w * 0.5 - 0.5in;
Circle(r = 0.5in, c = (x = [d,-d], y = 0in));
Line(width = w, p = (x = -w * 0.5, y = -4.0in));
}
.hull()
.extrude(width)
.orient(Y)
.translate(y = -width / 4, z = 0.75in);
bearing = (Rect(width = 1.25in, height = width - 1in) | Rect(height = width, width = 0.5in))
.revolve()
.orient(X)
.translate(z = 3.25in);
mount = Rect(height = 4.25in - 3.5in, width = 1.5in * 50%, x = 0mm, y = 0mm)
.revolve()
.orient(X)
.translate(x = [2.0, -2.0]in, z = 3.25in);
bottom_bar = {
Circle(d = 0.15in).translate(x = -1.35in);
Line(height = 0.5in);
}
.hull()
.extrude(width)
.orient(X)
.translate(x = -width / 2);
base & (side - front_cut_off) | (base & bottom_bar) | mount - bearing;
}
BufferStand();
2D Output
:
3D Output
:
Example: chess
// Copyright © 2025-2026 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::geo2d::*;
use std::geo3d::*;
use std::ops::*;
use std::math::*;
// https://de.wikipedia.org/wiki/Bauhaus-Schachspiel
pub TILE_SIZE = 5.8cm;
const BASE_SIZE = TILE_SIZE * 70%;
pub part Pawn() {
Cube(BASE_SIZE * 80%)
}
pub part King() {
{
Cube(BASE_SIZE);
Cube(BASE_SIZE / sqrt(2)).rotate(45°);
}.align(Z)
}
pub part Queen() {
{
Cube(BASE_SIZE);
Sphere(diameter = BASE_SIZE / sqrt(2));
}.align(Z)
}
pub part Bishop() {
size = BASE_SIZE / 3;
Rect(size * 90%)
.translate(size * 150%, [45,-135]°)
.hull()
.mirror(X)
.union()
.extrude(BASE_SIZE)
.rotate(x = 90°)
.center()
}
pub part Rook() {
Cube(BASE_SIZE)
}
pub part Knight() {
{
height = BASE_SIZE/2;
r = Rect(BASE_SIZE);
(r - r.translate(x = height, y = height)).extrude(height);
}.rotate([0,90]°).align(Z)
}
{
Rook();
Knight();
Bishop();
Queen();
King();
Bishop();
Knight().rotate(x = 180°).rotate(90°);
Rook();
8 * Pawn();
}
.distribute_grid(cell_size = TILE_SIZE, rows = 2, columns = 8)
.translate(y = TILE_SIZE * 3)
.rotate([0, 180]°);
board_height = 1mm;
Rect(TILE_SIZE * 8).extrude(board_height).translate(z = -board_height);
2D Output
:
3D Output
:
Example: csg_cube
// Copyright © 2025-2026 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::math::*;
use std::ops::*;
use std::geo3d::*;
part CsgCube(size: Length) {
s = size / sqrt(2.1);
body = Sphere(radius = s) & Cube(size);
holes = Cylinder(size, diameter = s).orient([X,Y,Z]);
body - holes;
}
CsgCube(50mm);
2D Output
:
3D Output
:
Example: cylinder_stack
// Copyright © 2025 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::geo3d::*;
use std::debug::*;
part CylinderStack(heights: [Length], radii: [Length], offset: Length = 0mm) {
assert(heights.count() == radii.count() - 1, "radii must be an array with one more elements that heights");
self = Cylinder(height = heights.head(), radius_bottom = radii.head(), radius_top = radii.tail().head(), offset);
if heights.count() > 1 {
self | CylinderStack(heights = heights.tail(), radii = radii.tail(), offset = offset + heights.head())
} else {
self
}
}
CylinderStack(heights = [5, 15, 5]mm, radii = [6, 4, 4, 6]mm);
2D Output
:
3D Output
:
Example: dome
// Copyright © 2025-2026 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
// file: dome.µcad
use std::geo2d::*;
use std::ops::*;
pub part Dome(size: Length, strut_width = 1mm) {
Rect(strut_width)
.translate(x = size)
.revolve(180°)
.rotate(x = -[0..6]*180°/6)
.rotate(z = [0..3]*180°/3);
}
Dome(10mm, strut_width = 0.25mm);
2D Output
:
3D Output
:
Example: drill_plate
// Copyright © 2025 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::geo2d::*;
use std::ops::*;
/// A drill plate with four holes.
#[color = "red"]
sketch DrillPlate(size = 100mm, hole_size = 10mm) {
l = size/2 - hole_size;
Rect(size) - Circle(diameter = hole_size).translate(x = [-l,l], y = [-l,l])
}
DrillPlate();
2D Output
:
3D Output
:
Example: footpad
// Copyright © 2025-2026 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::ops::*;
use std::geo2d::*;
use std::math::*;
part FootPad(
height = 45mm,
base = (x = 155mm, y = 101mm, z = 18mm),
slot = (x = 8mm, y = 13mm),
center_hole = (d_inner = 42mm, d_outer = 55mm),
corner_hole = (d_lower = 14mm, d_upper = 22mm),
corner_radius = 15mm,
) {
s = (x = base.x / 2 - corner_radius, y = base.y / 2 - corner_radius);
hole_pos = (x = [-1,1]*s.x, y = [-1,1]*s.y);
radius = corner_radius;
base_lower = Circle(radius, c = hole_pos)
.hull()
.extrude(12mm);
base_upper_height = slot.x;
base_lower_height = base.z - base_upper_height;
base_upper = {
top_left = (x = -s.x, y = s.y);
top_right = (x = s.x, y = s.y);
bottom_left = (x = -s.x, y = -s.y);
bottom_right = (x = s.x, y = -s.y);
(Circle(radius, c = (x = top_left.x, y = bottom_right.y)).hull()
| Circle(radius, c = (x = top_right.x, y = bottom_left.y)).hull());
}
.extrude(base_upper_height)
.translate(z = base_lower_height);
center = {
(Circle(d = center_hole.d_outer) - Circle(d = center_hole.d_inner))
.extrude(height);
Rect(height = slot.x, width = center_hole.d_outer)
.extrude(slot.y)
.translate(z = height - slot.y);
}.subtract();
holes = {
Circle(d = corner_hole.d_lower, c = hole_pos)
.extrude(height = base_lower_height);
Circle(d = corner_hole.d_upper, c = hole_pos)
.extrude(height = base.z * 2)
.translate(z = base_lower_height);
Circle(d = center_hole.d_inner)
.extrude(height);
}.union();
base_lower | base_upper | center - holes;
}
FootPad();
2D Output
:
3D Output
:
Example: gears
Module: gear_2d
// file: gear_2d.µcad
// Copyright © 2025 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::ops::*;
use std::geo2d::*;
InvoluteGearProfile(1.0mm, 100);
2D Output
:
3D Output
:
Module: gears_3d
// file: gears_3d.µcad
// Copyright © 2025-2026 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::ops::*;
use std::geo2d::*;
use std::math::*;
const TEETH = 20;
angle = 30° * TEETH;
part Gear(teeth: Integer) {
gear_profile = InvoluteGearProfile(module = 1.0mm, teeth);
prop pitch_radius = gear_profile.pitch_radius;
prop outer_radius = gear_profile.outer_radius;
n_holes = 5;
bearing_hole = Circle(radius = gear_profile.pitch_radius / 8);
hole_radius = pitch_radius / n_holes;
holes = Circle(radius = pitch_radius / n_holes)
.translate(x = outer_radius - hole_radius * 2)
.rotate([1..n_holes] * 360° / n_holes);
inner = Circle(radius = pitch_radius - 3mm);
bearing = (Circle(radius = pitch_radius / 4) - bearing_hole).extrude(8mm)
- Circle(radius = gear_profile.module)
.extrude(pitch_radius / 4)
.translate(z = -pitch_radius / 4)
.rotate(x = 90°)
.translate(z = 5mm);
bearing
| (inner - holes - Circle(radius = pitch_radius / 4)).extrude(2mm)
| (gear_profile - inner).extrude(4mm);
}
gear1 = Gear(80);
gear2 = Gear(40);
gear3 = Gear(20);
#[color = std::color::BLUE]
#[export = "gear1.stl"]
gear1.rotate(angle / gear1.teeth);
#[color = std::color::RED]
#[export = "gear2.stl"]
gear2
.rotate(-angle / gear2.teeth + 360°/gear2.teeth/2.0)
.translate(gear2.outer_radius + gear1.pitch_radius, 135°);
#[color = std::color::GREEN]
#[export = "gear3.stl"]
gear3
.rotate(-angle / gear3.teeth)
.translate(gear1.outer_radius + gear3.pitch_radius, 45°);
2D Output
:
3D Output
:
Module: herringbone_gears
// file: herringbone_gears.µcad
// Copyright © 2025-2026 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::ops::*;
use std::geo2d::*;
use std::math::*;
part Gear(teeth: Integer) {
gear_profile = InvoluteGearProfile(1.5mm, teeth);
prop outer_radius = gear_profile.outer_radius;
prop pitch_radius = gear_profile.pitch_radius;
prop tooth_angle = gear_profile.tooth_angle;
prop tooth_distance = gear_profile.tooth_distance;
prop module = gear_profile.module;
disc = Circle(radius = pitch_radius - module * 400%);
web = {
sector = Sector(disc.radius, 360° / 5)
.buffer(-disc.radius * 15%)
.buffer(disc.radius * 12%);
holes = (sector - Circle(radius = module * 1000%))
.rotate([0..4] * 360° / 5);
hub = InvoluteGearProfile(2.5mm, 7);
disc - holes - hub;
}.extrude(tooth_distance * 300%).center();
rim = (gear_profile - disc)
.extrude(tooth_distance * 200%, tooth_angle)
.mirror(-Z);
web | rim;
}
gear1 = Gear(90);
gear2 = Gear(60);
gear1.reflect(X);
gear2
.rotate(gear2.tooth_angle * 50%)
.translate(gear1.outer_radius + gear2.pitch_radius, [1..3] * 360° / 3);
2D Output
:
3D Output
:
Example: hole_test
// Copyright © 2025-2026 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::geo2d::*;
use std::geo3d::*;
use std::ops::*;
use std::math::*;
const THICKNESS = 2mm;
part Hole(diameter: Length) {
r = diameter * 50%;
Cylinder(radius_bottom = r, radius_top = r + THICKNESS * 50%, height = THICKNESS);
}
r = RoundedRect(60mm, radius = 10mm).extrude(THICKNESS);
holes = Hole([1..9] * 0.25mm)
.distribute_grid(size = 60mm, rows = 3, columns = 3);
r - holes;
2D Output
:
3D Output
:
Example: letter_cube
// Copyright © 2025 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::math::*;
use std::ops::*;
use std::geo3d::*;
use std::geo2d::*;
part Letter(letter: String, size: Length, axis: Vec3) {
Text(letter, height = size)
.center()
.contour(thickness = 0.25mm, distance = 0.5mm)
.extrude(1mm)
.translate(z = size / 2 - 0.5mm)
.orient(axis);
}
part LetterCube(size: Length) {
s = size / sqrt(2.1);
body = Cube(size) & Sphere(r = s);
p = Letter("P", size, [-Z, Z]).rotate(z = -90°);
t = Letter("T", size, [-X, X]).rotate(x = 90°);
f = Letter("F", size, [-Y, Y]);
body - (p | t | f);
}
LetterCube(20mm).translate(z = 10mm);
2D Output
:
3D Output
:
Example: lid
// Copyright © 2024-2025 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
/// A part called `Lid` with three parameters.
part Lid(
thickness = 1.6mm,
inner_diameter = 16.0cm,
height = 20.0mm,
) {
// Calculate the outer diameter
outer_diameter = 2.0 * thickness + inner_diameter;
// Create two cylinders, one for the outer and one for the inner
outer = std::geo3d::Cylinder(d = outer_diameter, h = height);
inner = std::geo3d::Cylinder(d = inner_diameter, h = height).std::ops::translate(z = thickness);
// Calculate the difference between two translated cylinders and output them
outer - inner;
}
// `l` is the instance of the lid model
l = Lid();
l; // Instantiate the lid.
2D Output
:
3D Output
:
Example: logo
// Copyright © 2025-2026 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
// file: logo.µcad
pub mod microcad {
use std::geo2d::*;
use std::ops::*;
sketch IconElement( radius: Length ) {
c = Sector(radius, start = 180°, end = 270°).translate(y = radius);
r = Rect(width = radius, height = radius * 2, x = -radius, y = -radius);
c | r
}
sketch Arc(radius: Length, thickness: Length, angle = 300°) {
Sector(radius, start = -angle / 2, end = angle / 2)
.rotate(180° - angle) - Circle(radius = radius - thickness)
}
pub sketch Icon(radius: Length) {
prop gap = radius / 5;
IconElement(radius)
.translate(x = -radius - gap)
.rotate([0..3] * 90°);
}
pub sketch Micro(radius: Length, thickness: Length) {
u = Sector(radius, 180°).rotate(90°) - Circle(radius = radius - thickness);
r_l = Rect(width = thickness, height = radius * 3, x = -radius, y = -2*radius);
r_r = Rect(width = thickness, height = radius * 2, x = radius - thickness, y = -radius);
u | r_l | r_r
}
pub sketch C(radius: Length, thickness: Length) {
Arc(radius, thickness, 260°)
}
pub sketch A(radius: Length, thickness: Length) {
Arc(radius, thickness)
| Rect(width = thickness, height = radius * 2, x = radius * 0.5, y = -radius);
}
pub sketch D(radius: Length, thickness: Length) {
Arc(radius, thickness)
| Rect(width = thickness, height = radius * 3, x = radius * 0.5, y = -radius);
}
pub sketch Logo(radius: Length, thickness: Length) {
use std::math::*;
init(size: Length) {
radius = size * 50%;
thickness = radius * 40%;
}
{
Icon(radius);
{
Micro(radius, thickness);
C(radius, thickness);
A(radius, thickness);
D(radius, thickness);
}.align(X);
}.align(X, 4mm).center();
}
}
use std::ops::*;
pub SIZE = 1cm;
microcad::Logo(size = SIZE).extrude(4mm);
2D Output
:
3D Output
:
Example: multi_export
// Copyright © 2025 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::ops::*;
#[export = "rect.svg"]
std::geo2d::Rect(42mm)
.rotate(45°);
#[export = "circle.svg"] // Will be exported to `circle.svg`
std::geo2d::Circle(r = 42mm)
.translate(x = 42mm);
2D Output
:
3D Output
:
Example: ngons
// Copyright © 2025 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::geo2d::*;
use std::ops::*;
(Hexagon(20mm) - Ngon(5, 10mm)).extrude(20mm);
2D Output
:
3D Output
:
Example: spirograph
// Copyright © 2025-2026 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::geo2d::*;
use std::ops::*;
mod logo;
use logo::microcad::Logo;
const TEETH_SIZE = 0.5mm;
const THICKNESS = 2mm;
const BORDER_WIDTH = 7mm;
sketch GearProfile(teeth: Integer) {
prop module = TEETH_SIZE;
prop radius = teeth * module;
SinusoidalGearProfile(module, teeth, stretch = 0.6, roundness = 0.6);
}
sketch RingProfile(outer_teeth: Integer, inner_teeth: Integer, border_width = BORDER_WIDTH) {
inner_gear = GearProfile(inner_teeth);
outer_gear = GearProfile(outer_teeth);
prop radius = outer_gear.radius;
prop shift = inner_gear.radius * 40%;
sector = {
disc = Circle(r = outer_gear.radius - border_width);
sector = Sector(r = outer_gear.radius, start = 30°, end = 90°).rotate(60°);
inner_disc = Circle(r = inner_gear.radius - border_width * 250%);
ring = Ring(o_r = inner_gear.radius + border_width - TEETH_SIZE * 2, thickness = border_width);
(disc - (sector - inner_disc) - ring.translate(x = shift))
.buffer(-TEETH_SIZE * 2)
.buffer(TEETH_SIZE * 2);
};
outer_gear - sector - inner_gear.translate(x = shift);
}
part PencilHole(pencil_hole_diameter = 0.5mm, offset = 0.0mm) {
Circle(d = pencil_hole_diameter)
.extrude(THICKNESS, scale = (x = 300%, y = 300%))
.translate(y = offset);
}
part PencilHoles(radius: Length, n = 4, start = 4, angle = 22.5°) {
{
PencilHole(offset = [start..n*2-1] * radius / n / 2);
PencilHole(offset = ([start..n*2-1] + 0.5) * radius / n / 2).rotate(-angle);
PencilHole(offset = ([start..n*2-1] + 1/3) * radius / n / 2).rotate(angle);
}.rotate(90°)
}
#[export = "spirograph_frame.stl"]
#[color = std::color::BLUE]
{
outer_gear = GearProfile(180);
size = outer_gear.radius * 200% + 3 * BORDER_WIDTH;
frame = {
border = RoundedRect(size, radius = BORDER_WIDTH * 200%);
border - outer_gear;
}.extrude(THICKNESS*2);
logo2 = Logo(size = BORDER_WIDTH*85%)
.extrude(THICKNESS)
.translate(x = size * 35%, y = size * 43%, z = THICKNESS * 150%);
url = Text("microcad.xyz", BORDER_WIDTH*150%)
.center()
.extrude(THICKNESS)
.translate(x = size * 32%, y = -size * 46%, z = THICKNESS * 150%);
frame - logo2 - url;
}.translate(x = 0mm);
ring_1 = RingProfile(outer_teeth = 180, inner_teeth = 120);
ring_2 = RingProfile(outer_teeth = 120, inner_teeth = 72);
ring_3 = RingProfile(outer_teeth = 72, inner_teeth = 36);
#[export = "spirograph_ring_1.stl"]
#[color = std::color::GREEN]
{
ring = ring_1.extrude(THICKNESS);
pencil_holes = PencilHoles(ring_1.radius, n = 6, start = 6);
ring - pencil_holes;
}.translate();
#[export = "spirograph_ring_2.stl"]
#[color = std::color::RED]
{
ring = ring_2.extrude(THICKNESS);
pencil_holes = PencilHoles(ring_2.radius, n = 5, start = 5);
ring - pencil_holes;
}.translate(x = ring_1.shift);
#[export = "spirograph_ring_3.stl"]
#[color = std::color::YELLOW]
{
ring = ring_3.extrude(THICKNESS);
pencil_holes = PencilHoles(ring_3.radius);
ring - pencil_holes;
}.translate(x = ring_2.shift + ring_1.shift);
gear = {
profile = GearProfile(36);
gear = profile.extrude(THICKNESS);
pencil_holes = PencilHoles(profile.radius, start = 1, n = 2, 120°);
gear - pencil_holes;
};
#[export = "spirograph_gear.stl"]
#[color = std::color::TEAL]
gear.translate(x = ring_1.shift + ring_2.shift + ring_3.shift);
2D Output
:
3D Output
:
Example: text
Module: love
// file: love.µcad
// Copyright © 2025 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::geo2d::*;
use std::ops::*;
sketch Heart(size: Length) {
r = size / 3;
Circle(d = size).translate(x = [r, -r], y = r) | Rect(size).rotate(45°);
}
#[color = std::color::GREEN]
Text("µcad", height = 80mm).center().translate(x = -110mm).extrude(4mm);
#[color = std::color::RED]
Heart(40mm).extrude(12mm);
#[color = std::color::BLUE]
Text("PTF", height = 80mm).center().translate(x = 90mm).extrude(4mm);
2D Output
:
3D Output
:
Module: text_plate
// file: text_plate.µcad
// Copyright © 2025 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::geo2d::*;
use std::ops::*;
use std::math::*;
sketch TextPlate(text: String, height: Length = 30mm) {
letters = Text(text, height).center();
plate = RoundedRect(60mm, radius = 20mm);
plate - letters
}
TextPlate("Hello µcad", 10mm)
.extrude(2mm, 0°);
2D Output
:
3D Output
:
Example: torus
// Copyright © 2025 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
std::geo3d::Torus([1..5] * 10mm, minor_radius = 3mm);
2D Output
:
3D Output
:
Example: use_dome
// Copyright © 2025 The µcad authors <info@ucad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later
mod dome;
dome::Dome(10mm, strut_width = 0.5mm).std::ops::mirror(std::math::Z);
2D Output
:
3D Output
: