-- BOSL2 (Belfry OpenSCAD Library v2) functions demo
-- All BOSL2 functions are available under the `bosl` namespace.
-- When exported to .scad, the necessary include directives are
-- added automatically.
-- A cuboid with rounded edges. BOSL2 shapes are centred unless an anchor
-- says otherwise, so `anchor = bosl.BOTTOM` would stand this on the XY plane.
local body = bosl.cuboid { {30, 20, 10}, rounding = 2 }
-- A threaded rod (from threading.scad, auto-included)
local rod = bosl.threaded_rod { d = 10, l = 25, pitch = 2 }
-- A spur gear (from gears.scad, auto-included)
local my_gear = bosl.spur_gear {
circ_pitch = 5,
teeth = 20,
thickness = 5,
shaft_diam = 5,
}
-- A NEMA 17 stepper motor model (from nema_steppers.scad, auto-included)
local _motor = bosl.nema17_stepper { h = 34, shaft = 5 }
-- BOSL2 constants are also available
local _up = bosl.UP -- {0, 0, 1}
local _phi = bosl.PHI -- golden ratio
-- Combine objects (BOSL2 objects support all normal CSG operations)
render(body:translate(0, 0, 0))
render(rod:translate(40, 0, 0))
render(my_gear:translate(0, 40, 0))
// Generated by LuaCAD
include <BOSL2/std.scad>
include <BOSL2/gears.scad>
include <BOSL2/threading.scad>
union() {
translate([0, 0, 0]) {
cuboid([30, 20, 10], rounding = 2);
}
translate([40, 0, 0]) {
threaded_rod();
}
translate([0, 40, 0]) {
spur_gear();
}
}
-- BOSL2 3D shapes preview demo
-- Each shape is placed on a grid so they're all visible at once.
local sp = 80 -- grid spacing
render(
bosl.tube { h = 30, ["or"] = 20, wall = 4 }
+ bosl.torus { r_maj = 18, r_min = 5 }:translate(sp, 0, 0)
+ bosl.prismoid { size1 = { 40, 40 }, size2 = { 20, 20 }, h = 30 }:translate(2 * sp, 0, 0)
+ bosl.rect_tube { size = { 40, 40 }, wall = 5, h = 30 }:translate(0, sp, 0)
+ bosl.wedge { { 30, 30, 20 } }:translate(sp, sp, 0)
+ bosl.octahedron { size = 35 }:translate(2 * sp, sp, 0)
+ bosl.pie_slice { r = 25, h = 20, ang = 120 }:translate(0, 2 * sp, 0)
+ bosl.regular_prism { n = 6, r = 20, h = 30 }:translate(sp, 2 * sp, 0)
+ bosl.teardrop { r = 15, h = 20 }:translate(2 * sp, 2 * sp, 0)
+ bosl.onion { r = 15 }:translate(0, 3 * sp, 0)
+ bosl.tube { h = 30, or1 = 25, or2 = 15, wall = 4 }:translate(sp, 3 * sp, 0)
+ bosl.pie_slice { r = 25, h = 15, ang = 270 }:translate(2 * sp, 3 * sp, 0)
)
// Generated by LuaCAD
include <BOSL2/std.scad>
union() {
union() {
union() {
union() {
union() {
union() {
union() {
union() {
union() {
union() {
union() {
tube(h = 30, or = 20, wall = 4);
translate([80, 0, 0]) {
torus(r_maj = 18, r_min = 5);
}
}
translate([160, 0, 0]) {
prismoid(h = 30, size1 = [40, 40], size2 = [20, 20]);
}
}
translate([0, 80, 0]) {
rect_tube(h = 30, size = [40, 40], wall = 5);
}
}
translate([80, 80, 0]) {
wedge([30, 30, 20]);
}
}
translate([160, 80, 0]) {
octahedron(size = 35);
}
}
translate([0, 160, 0]) {
pie_slice(ang = 120, h = 20, r = 25);
}
}
translate([80, 160, 0]) {
regular_prism(h = 30, n = 6, r = 20);
}
}
translate([160, 160, 0]) {
teardrop(h = 20, r = 15);
}
}
translate([0, 240, 0]) {
onion(r = 15);
}
}
translate([80, 240, 0]) {
tube(h = 30, or1 = 25, or2 = 15, wall = 4);
}
}
translate([160, 240, 0]) {
pie_slice(ang = 270, h = 15, r = 25);
}
}
function create_box(width, depth, height, thickness)
local outer_shell = cube(width, depth, height)
local inner_cavity = cube(
width - thickness * 2,
depth - thickness * 2,
height -- `thickness` higher than top surface to avoid z-fighting
):translate(thickness, thickness, thickness)
return outer_shell - inner_cavity
end
render(create_box(30, 20, 15, 2))
// Generated by LuaCAD
difference() {
cube([30, 20, 15]);
translate([2, 2, 2]) {
cube([26, 16, 15]);
}
}
// A chess game in progress, set up from a FEN string.
//
// The position is the Immortal Game — Anderssen vs Kieseritzky, London 1851 —
// after Black's 22...Nxf6. White has given up a bishop, both rooks and the
// queen, and mates next move with 23.Be7#. Black's queen sits on a1 and his
// bishop on g1, on the squares the rooks came from.
//
// luacad render --raytrace chess.scad chess_raytraced.png
// luacad render chess.scad chess.png
// luacad convert chess.scad chess.3mf
//
// Drop any other FEN in POSITION below to set up a different game. Only the
// piece-placement field is read; the side to move and the castling, en
// passant and clock fields are ignored, so either form works.
use <parts/pieces.scad>
include <parts/board.scad>
POSITION = "r1bk3r/p2p1pNp/n2B1n2/1p1NP2P/6P1/3P4/P1P1K3/q5b1 w - - 0 23";
SEGMENTS = 64; // facets around each lathed piece
CUTOUTS = 6; // crenellations on a rook
WHITE = "#f2e8d5"; // bone
BLACK = "#2b2724"; // ebony
// ---------------------------------------------------------------------------
// Reading FEN
//
// The placement field lists ranks 8 down to 1, separated by "/". A letter is
// a piece — uppercase White, lowercase Black — and a digit is that many empty
// squares. Everything after the first space is the game state, not the board.
// ---------------------------------------------------------------------------
function is_digit(c) = len(search(c, "12345678")) > 0;
function digit(c) = search(c, "0123456789")[0];
function is_white(c) = len(search(c, "PNBRQK")) > 0;
// Fold the two cases together: index 6-11 wraps back onto 0-5.
function kind(c) =
["p", "n", "b", "r", "q", "k"][search(c, "pnbrqkPNBRQK")[0] % 6];
// Walk the placement field one character at a time, emitting
// [file, rank, letter] for each piece. `f` counts files a-h left to right,
// `r` counts ranks down from 7 (rank 8) as each "/" is crossed.
function placement(fen, i = 0, f = 0, r = 7) =
i >= len(fen) || fen[i] == " " ? []
: fen[i] == "/" ? placement(fen, i + 1, 0, r - 1)
: is_digit(fen[i]) ? placement(fen, i + 1, f + digit(fen[i]), r)
: concat([[f, r, fen[i]]], placement(fen, i + 1, f + 1, r));
// Algebraic name of a square — echoed on load, so the parse can be read back
// against the diagram in README.md.
function square_name(f, r) = str("abcdefgh"[f], r + 1);
for (p = placement(POSITION))
echo(str(p[2], square_name(p[0], p[1])));
// ---------------------------------------------------------------------------
// Building the position
// ---------------------------------------------------------------------------
module piece(letter) {
k = kind(letter);
if (k == "p") pawn(1, SEGMENTS);
else if (k == "r") rook(1, SEGMENTS, CUTOUTS);
else if (k == "n") knight(1, SEGMENTS);
else if (k == "b") bishop(1, SEGMENTS);
else if (k == "q") queen(1, SEGMENTS);
else if (k == "k") king(1, SEGMENTS);
}
module position(fen) {
for (p = placement(fen)) {
f = p[0];
r = p[1];
letter = p[2];
white = is_white(letter);
color(white ? WHITE : BLACK)
translate([square_x(f), square_y(r), 0])
// Black's men turn to face down the board, so the two knights and
// the two bishops look at each other rather than the same way.
rotate([0, 0, white ? 0 : 180])
piece(letter);
}
}
board();
position(POSITION);
// Generated by LuaCAD
union() {
union() {
union() {
color([0.427451, 0.290196, 0.2]) {
translate([-128, -128, -4]) {
cube([32, 32, 4]);
}
}
color([0.890196, 0.811765, 0.643137]) {
translate([-128, -96, -4]) {
cube([32, 32, 4]);
}
}
color([0.427451, 0.290196, 0.2]) {
translate([-128, -64, -4]) {
cube([32, 32, 4]);
}
}
color([0.890196, 0.811765, 0.643137]) {
translate([-128, -32, -4]) {
cube([32, 32, 4]);
}
}
color([0.427451, 0.290196, 0.2]) {
translate([-128, 0, -4]) {
cube([32, 32, 4]);
}
}
color([0.890196, 0.811765, 0.643137]) {
translate([-128, 32, -4]) {
cube([32, 32, 4]);
}
}
color([0.427451, 0.290196, 0.2]) {
translate([-128, 64, -4]) {
cube([32, 32, 4]);
}
}
color([0.890196, 0.811765, 0.643137]) {
translate([-128, 96, -4]) {
cube([32, 32, 4]);
}
}
color([0.890196, 0.811765, 0.643137]) {
translate([-96, -128, -4]) {
cube([32, 32, 4]);
}
}
color([0.427451, 0.290196, 0.2]) {
translate([-96, -96, -4]) {
cube([32, 32, 4]);
}
}
color([0.890196, 0.811765, 0.643137]) {
translate([-96, -64, -4]) {
cube([32, 32, 4]);
}
}
color([0.427451, 0.290196, 0.2]) {
translate([-96, -32, -4]) {
cube([32, 32, 4]);
}
}
color([0.890196, 0.811765, 0.643137]) {
translate([-96, 0, -4]) {
cube([32, 32, 4]);
}
}
color([0.427451, 0.290196, 0.2]) {
translate([-96, 32, -4]) {
cube([32, 32, 4]);
}
}
color([0.890196, 0.811765, 0.643137]) {
translate([-96, 64, -4]) {
cube([32, 32, 4]);
}
}
color([0.427451, 0.290196, 0.2]) {
translate([-96, 96, -4]) {
cube([32, 32, 4]);
}
}
color([0.427451, 0.290196, 0.2]) {
translate([-64, -128, -4]) {
cube([32, 32, 4]);
}
}
color([0.890196, 0.811765, 0.643137]) {
translate([-64, -96, -4]) {
cube([32, 32, 4]);
}
}
color([0.427451, 0.290196, 0.2]) {
translate([-64, -64, -4]) {
cube([32, 32, 4]);
}
}
color([0.890196, 0.811765, 0.643137]) {
translate([-64, -32, -4]) {
cube([32, 32, 4]);
}
}
color([0.427451, 0.290196, 0.2]) {
translate([-64, 0, -4]) {
cube([32, 32, 4]);
}
}
color([0.890196, 0.811765, 0.643137]) {
translate([-64, 32, -4]) {
cube([32, 32, 4]);
}
}
color([0.427451, 0.290196, 0.2]) {
translate([-64, 64, -4]) {
cube([32, 32, 4]);
}
}
// … 91850 more lines. Run `luacad convert examples/chess/chess.scad chess.scad` for all of it.
-- Basic example of CSG usage
local union_model =
(cube { 15, 15, 15, center = true }
+ sphere({ r = 10 })
)
:translate(-24, 0, 0)
local intersection_model =
cube({ 15, 15, 15, center = true })
:intersect(sphere({ r = 10 }))
local difference_model =
(cube { 15, 15, 15, center = true }
- sphere({ r = 10 })
)
:translate(24, 0, 0)
render(union_model + intersection_model + difference_model)
// Generated by LuaCAD
union() {
union() {
translate([-24, 0, 0]) {
union() {
cube([15, 15, 15], center = true);
sphere(r = 10, $fn = 32);
}
}
intersection() {
cube([15, 15, 15], center = true);
sphere(r = 10, $fn = 32);
}
}
translate([24, 0, 0]) {
difference() {
cube([15, 15, 15], center = true);
sphere(r = 10, $fn = 32);
}
}
}
-- Basic usage of modules, color, and resolution.
-- Ported from CSG-modules.scad by Marius Kintel.
local debug = true -- Show helper geometry
local fn = 72 -- High segment count for smooth surfaces
-- Core geometric primitives
local body = sphere{r = 10, fn = fn}:color("#26A69A")
local intersector =
cube{15, 15, 15, center = true}
:color("#ffa726")
local hole_object =
cylinder{h = 20, r = 5, center = true, fn = fn}
:color("#3177be")
-- Various modules for visualizing intermediate components
local intersected = body * intersector
local hole_a = hole_object:rotate(0, 90, 0)
local hole_b = hole_object:rotate(90, 0, 0)
local hole_c = hole_object
local holes = hole_a + hole_b + hole_c
-- Main geometry
render(((body * intersector) - holes):translate(0, 0, 25))
-- Helpers
if debug then
local line =
cylinder{r = 1, h = 10, center = true, fn = fn}
:color("black")
-- Intersection breakdown
local left_group = (intersected
+ body:translate(-15, 0, -35)
+ intersector:translate(15, 0, -35)
+ line:rotate(0, 30, 0):translate(-7.5, 0, -17.5)
+ line:rotate(0, -30, 0):translate(7.5, 0, -17.5)
):translate(-30, 0, -40)
-- Holes breakdown
local right_group = (holes
+ hole_a:translate(-10, 0, -35)
+ hole_b:translate(10, 0, -35)
+ hole_c:translate(30, 0, -35)
+ line:rotate(0, -20, 0):translate(5, 0, -17.5)
+ line:rotate(0, 30, 0):translate(-5, 0, -17.5)
+ line:rotate(0, -45, 0):translate(15, 0, -17.5)
):translate(30, 0, -40)
local connecting_lines =
line:rotate(0, 45, 0):translate(-20, 0, -22.5)
+ line:rotate(0, -45, 0):translate(20, 0, -22.5)
local helpers =
(left_group + right_group + connecting_lines)
:scale(0.5, 0.5, 0.5)
render(helpers:translate(0, 0, 25))
end
// Generated by LuaCAD
union() {
translate([0, 0, 25]) {
difference() {
intersection() {
color([0.14902, 0.65098, 0.603922]) {
sphere(r = 10, $fn = 72);
}
color([1, 0.654902, 0.14902]) {
cube([15, 15, 15], center = true);
}
}
union() {
union() {
rotate([0, 90, 0]) {
color([0.192157, 0.466667, 0.745098]) {
cylinder(h = 20, r1 = 5, r2 = 5, $fn = 72, center = true);
}
}
rotate([90, 0, 0]) {
color([0.192157, 0.466667, 0.745098]) {
cylinder(h = 20, r1 = 5, r2 = 5, $fn = 72, center = true);
}
}
}
color([0.192157, 0.466667, 0.745098]) {
cylinder(h = 20, r1 = 5, r2 = 5, $fn = 72, center = true);
}
}
}
}
translate([0, 0, 25]) {
scale([0.5, 0.5, 0.5]) {
union() {
union() {
translate([-30, 0, -40]) {
union() {
union() {
union() {
union() {
intersection() {
color([0.14902, 0.65098, 0.603922]) {
sphere(r = 10, $fn = 72);
}
color([1, 0.654902, 0.14902]) {
cube([15, 15, 15], center = true);
}
}
translate([-15, 0, -35]) {
color([0.14902, 0.65098, 0.603922]) {
sphere(r = 10, $fn = 72);
}
}
}
translate([15, 0, -35]) {
color([1, 0.654902, 0.14902]) {
cube([15, 15, 15], center = true);
}
}
}
translate([-7.5, 0, -17.5]) {
rotate([0, 30, 0]) {
color([0, 0, 0]) {
cylinder(h = 10, r1 = 1, r2 = 1, $fn = 72, center = true);
}
}
}
}
translate([7.5, 0, -17.5]) {
rotate([0, -30, 0]) {
color([0, 0, 0]) {
cylinder(h = 10, r1 = 1, r2 = 1, $fn = 72, center = true);
}
}
}
}
}
translate([30, 0, -40]) {
union() {
union() {
union() {
union() {
union() {
union() {
union() {
union() {
rotate([0, 90, 0]) {
color([0.192157, 0.466667, 0.745098]) {
cylinder(h = 20, r1 = 5, r2 = 5, $fn = 72, center = true);
}
}
rotate([90, 0, 0]) {
color([0.192157, 0.466667, 0.745098]) {
cylinder(h = 20, r1 = 5, r2 = 5, $fn = 72, center = true);
}
}
}
color([0.192157, 0.466667, 0.745098]) {
cylinder(h = 20, r1 = 5, r2 = 5, $fn = 72, center = true);
}
}
translate([-10, 0, -35]) {
rotate([0, 90, 0]) {
color([0.192157, 0.466667, 0.745098]) {
cylinder(h = 20, r1 = 5, r2 = 5, $fn = 72, center = true);
}
}
}
}
translate([10, 0, -35]) {
rotate([90, 0, 0]) {
color([0.192157, 0.466667, 0.745098]) {
cylinder(h = 20, r1 = 5, r2 = 5, $fn = 72, center = true);
}
}
}
}
translate([30, 0, -35]) {
color([0.192157, 0.466667, 0.745098]) {
// … 50 more lines. Run `luacad convert examples/csg_modules/csg_modules.lua csg_modules.scad` for all of it.
local r = var("Radius of sphere", 9)
local t = var("Translation of sphere", 3)
local h = var("Height of cube", 4)
local rNew = r + 5 + h - 2
local model = cube { size = { 3, 3, 5 } }
+ cube { size = { 1, 2, 3 }, center = true }
+ sphere({ r = r }):translate(t, t, t)
+ sphere { r = rNew }
render(model)
// Generated by LuaCAD
union() {
union() {
union() {
cube([3, 3, 5]);
cube([1, 2, 3], center = true);
}
translate([3, 3, 3]) {
sphere(r = 9, $fn = 32);
}
}
sphere(r = 16, $fn = 32);
}
local model =
cube { { 10, 10, 10 }, center = true }
- cylinder { h = 20, r = 3, center = true }
render(model)
// Generated by LuaCAD
difference() {
cube([10, 10, 10], center = true);
cylinder(h = 20, r1 = 3, r2 = 3, $fn = 32, center = true);
}
function gear(num_teeth, height, radius)
local model = cylinder { h = height, r = radius * 0.7 }
local tooth_length = radius * 0.3;
local tooth_width = radius * 0.2;
-- Create teeth
for i = 1, num_teeth do
local angle = i * (360 / num_teeth)
model = model
+ cube(tooth_length * 1.2, tooth_width, height)
:translate(radius - (tooth_length * 1.2), -tooth_width/2, 0)
:rotate(0, 0, angle)
end
return model
end
render(gear(8, 5, 10))
// Generated by LuaCAD
union() {
union() {
union() {
union() {
union() {
union() {
union() {
union() {
cylinder(h = 5, r1 = 7, r2 = 7, $fn = 32);
rotate([0, 0, 45]) {
translate([6.4, -1, 0]) {
cube([3.6, 2, 5]);
}
}
}
rotate([0, 0, 90]) {
translate([6.4, -1, 0]) {
cube([3.6, 2, 5]);
}
}
}
rotate([0, 0, 135]) {
translate([6.4, -1, 0]) {
cube([3.6, 2, 5]);
}
}
}
rotate([0, 0, 180]) {
translate([6.4, -1, 0]) {
cube([3.6, 2, 5]);
}
}
}
rotate([0, 0, 225]) {
translate([6.4, -1, 0]) {
cube([3.6, 2, 5]);
}
}
}
rotate([0, 0, 270]) {
translate([6.4, -1, 0]) {
cube([3.6, 2, 5]);
}
}
}
rotate([0, 0, 315]) {
translate([6.4, -1, 0]) {
cube([3.6, 2, 5]);
}
}
}
rotate([0, 0, 360]) {
translate([6.4, -1, 0]) {
cube([3.6, 2, 5]);
}
}
}
-- Creating some objects using LuaCAD
local my_cube = cube { size = { 1, 2, 3 } }
local my_sphere = sphere({ r = 2 }):translate(5, 0, 0)
-- Using scad() to insert custom OpenSCAD code directly
local custom_scad = scad([[
module fancy_cylinder() {
cylinder(h=10, r1=3, r2=1, center=true, $fn=50);
}
fancy_cylinder();
]])
-- Using scad() for simple single-line commands
local another_scad = scad("cylinder(h=5, r=2, center=true);"):translate(0, 10, 0)
-- Combining all objects
local model = my_cube + my_sphere + custom_scad + another_scad
render(model)
// Generated by LuaCAD
union() {
union() {
union() {
cube([1, 2, 3]);
translate([5, 0, 0]) {
sphere(r = 2, $fn = 32);
}
}
module fancy_cylinder() {
cylinder(h=10, r1=3, r2=1, center=true, $fn=50);
}
fancy_cylinder();
}
translate([0, 10, 0]) {
cylinder(h=5, r=2, center=true);
}
}
-- Surface materials: how each kind scatters light.
-- Best viewed with `luacad render --raytrace`, where metals reflect,
-- glass refracts, and emissive shapes cast light of their own.
local fn = 72 -- High segment count for smooth surfaces
local function ball(x, y)
return sphere{r = 5, fn = fn}:translate(x, y, 5)
end
local floor = cube{70, 50, 2}
:translate(-35, -25, -2)
:color("#d9d9e0")
:material("matte")
-- A 3 x 4 grid of spheres, one per material
-- Base kinds, front row (with the default color)
local matte = ball(-21, -14):material("matte")
local plastic = ball(-7, -14):material("plastic")
local metal = ball(7, -14):material("metal")
local glass = ball(21, -14):material("glass", {ior = 1.5})
-- Middle row: the light source and the first colored presets
local glow = ball(-21, 0)
:color("#ffd66b")
:material("emissive", {strength = 4})
local gold = ball(-7, 0):material("gold")
local copper = ball(7, 0):material("copper")
local steel = ball(21, 0):material("steel")
-- Back row: the remaining presets with built-in colors
local chrome = ball(-21, 14):material("chrome")
local rubber = ball(-7, 14):material("rubber")
local wood = ball(7, 14):material("wood")
local ivory = ball(21, 14):material("ivory")
-- The floor goes last: a union inherits its base color from the first
-- operand, and the uncolored balls should keep the default blue.
render(
matte + plastic + metal + glass + glow
+ gold + copper + steel + chrome + rubber + wood + ivory
+ floor
)
// Generated by LuaCAD
union() {
union() {
union() {
union() {
union() {
union() {
union() {
union() {
union() {
union() {
union() {
union() {
translate([-21, -14, 5]) {
sphere(r = 5, $fn = 72);
}
translate([-7, -14, 5]) {
sphere(r = 5, $fn = 72);
}
}
translate([7, -14, 5]) {
sphere(r = 5, $fn = 72);
}
}
translate([21, -14, 5]) {
sphere(r = 5, $fn = 72);
}
}
color([1, 0.839216, 0.419608]) {
translate([-21, 0, 5]) {
sphere(r = 5, $fn = 72);
}
}
}
translate([-7, 0, 5]) {
sphere(r = 5, $fn = 72);
}
}
translate([7, 0, 5]) {
sphere(r = 5, $fn = 72);
}
}
translate([21, 0, 5]) {
sphere(r = 5, $fn = 72);
}
}
translate([-21, 14, 5]) {
sphere(r = 5, $fn = 72);
}
}
translate([-7, 14, 5]) {
sphere(r = 5, $fn = 72);
}
}
translate([7, 14, 5]) {
sphere(r = 5, $fn = 72);
}
}
translate([21, 14, 5]) {
sphere(r = 5, $fn = 72);
}
}
color([0.85098, 0.85098, 0.878431]) {
translate([-35, -25, -2]) {
cube([70, 50, 2]);
}
}
}
-- OpenSCAD modifier characters in LuaCAD:
-- * disable s(obj) / obj:skip()
-- ! show only o(obj) / obj:only()
-- # debug d(obj) / obj:debug()
-- % background t(obj) / obj:transparent()
-- `#` debug: the subtracted cylinder still cuts the hole,
-- and is additionally shown as a translucent red highlight.
local block = cube({ 20, 20, 10 })
local hole = cylinder({ h = 12, r = 4 }):translate(10, 10, -1)
render(block - d(hole))
-- `%` background: excluded from CSG, drawn as a translucent gray ghost.
local ghost = sphere({ r = 6 }):translate(-12, 10, 5)
render(t(ghost))
-- `*` skip: this cube is not rendered at all.
local hidden = cube({ 10, 10, 10 }):translate(25, 0, 0)
render(s(hidden))
-- Regular object for comparison.
render(sphere({ r = 5 }):translate(10, 30, 5))
-- `!` show only: uncomment to render ONLY this cylinder
-- and hide everything else.
-- render(o(cylinder({ h = 15, r = 3 }):translate(10, -12, 0)))
// Generated by LuaCAD
union() {
difference() {
cube([20, 20, 10]);
#translate([10, 10, -1]) {
cylinder(h = 12, r1 = 4, r2 = 4, $fn = 32);
}
}
%translate([-12, 10, 5]) {
sphere(r = 6, $fn = 32);
}
*translate([25, 0, 0]) {
cube([10, 10, 10]);
}
translate([10, 30, 5]) {
sphere(r = 5, $fn = 32);
}
}
-- MuSHR racecar -- the open-source robotic car from the UW Personal
-- Robotics Lab, ported to LuaCAD from the OpenSCAD original at
-- https://github.com/prl-mushr/mushr_cad (BSD-3-Clause).
--
-- luacad convert racecar.lua racecar.3mf --via-manifold
-- luacad render racecar.lua racecar.png
--
-- Every part is its own coloured object, so the 3MF opens as an assembly
-- rather than one welded lump. See parts/palette.lua for the colours and
-- the surface materials (rubber tires, metal linkage -- best seen with
-- `luacad render --raytrace`).
package.path = "./?.lua;" .. package.path
local body = require("parts.body")
local chassis = require("parts.chassis")
local function finish(part)
local solid = part.solid:color(part.color):name(part.name)
return part.material and solid:material(part.material) or solid
end
-- The body is modelled around the crossbar; the chassis hangs below it.
for _, part in ipairs(body.parts()) do
render(finish(part))
end
for _, part in ipairs(chassis.parts()) do
render(
finish(part):translate(body.chassis_x, body.chassis_y, body.chassis_z)
)
end
// Generated by LuaCAD
union() {
color([0.180392, 0.203922, 0.25098]) {
union() {
union() {
difference() {
difference() {
union() {
union() {
translate([93.125, 0, 0]) {
difference() {
difference() {
difference() {
union() {
union() {
translate([-0.05, 0, -1.25]) {
rotate([90, 0, 0]) {
polyhedron(
points = [
[0, 0, 12.5],
[0, 0, 0],
[4.75, 0, 0],
[0, 2.5, 12.5],
[0, 2.5, 0],
[4.75, 2.5, 0]
],
faces = [
[0, 2, 1],
[3, 4, 5],
[0, 1, 4, 3],
[1, 2, 5, 4],
[0, 3, 5, 2]
]
);
}
}
translate([-0.05, 0, 1.25]) {
rotate([-90, 0, 0]) {
polyhedron(
points = [
[0, 0, 12.5],
[0, 0, 0],
[4.75, 0, 0],
[0, 2.5, 12.5],
[0, 2.5, 0],
[4.75, 2.5, 0]
],
faces = [
[0, 2, 1],
[3, 4, 5],
[0, 1, 4, 3],
[1, 2, 5, 4],
[0, 3, 5, 2]
]
);
}
}
}
translate([-2.375, 0, 0]) {
cube([4.65, 25, 2.5], center = true);
}
}
translate([0.2, 0, 0.5]) {
cylinder(h = 3.5, r1 = 1.75, r2 = 1.75, $fn = 100, center = true);
}
}
translate([-1.97, 8, 0]) {
cylinder(h = 2.5, r1 = 2, r2 = 2, $fn = 100, center = true);
}
}
translate([-1.97, -8, 0]) {
cylinder(h = 2.5, r1 = 2, r2 = 2, $fn = 100, center = true);
}
}
}
translate([-1.075, 0, 0]) {
cube([179, 25, 2.5], center = true);
}
}
translate([-94.199997, 0, 0]) {
difference() {
difference() {
cube([7.25, 25, 2.5], center = true);
translate([0, 8.5, 0]) {
cylinder(h = 2.5, r1 = 2, r2 = 2, $fn = 100, center = true);
}
}
translate([0, -8.5, 0]) {
cylinder(h = 2.5, r1 = 2, r2 = 2, $fn = 100, center = true);
}
}
}
}
translate([4.175, -8.5, 0]) {
cylinder(h = 2.5, r1 = 2, r2 = 2, $fn = 100, center = true);
}
}
translate([-10.825, -8.5, 0]) {
cylinder(h = 2.5, r1 = 2, r2 = 2, $fn = 100, center = true);
}
}
translate([93.125, 0, -13.5]) {
difference() {
difference() {
difference() {
union() {
union() {
union() {
translate([-0.05, 0, -12.25]) {
rotate([90, 0, 0]) {
polyhedron(
points = [
[0, 0, 12.5],
[0, 0, 0],
[4.75, 0, 0],
[0, 24.5, 12.5],
[0, 24.5, 0],
[4.75, 24.5, 0]
],
// … 19576 more lines. Run `luacad convert examples/mushr_racecar/racecar.lua mushr_racecar.scad` for all of it.
function rounded_rect(width, height, radius)
local model =
circle({ r = radius }):translate(radius, radius, 0)
+ circle({ r = radius }):translate(width - radius, radius, 0)
+ circle({ r = radius }):translate(radius, height - radius, 0)
+ circle({ r = radius }):translate(width - radius, height - radius, 0)
return model:hull()
end
render(
rounded_rect(20, 10, 2)
:linear_extrude(5)
)
// Generated by LuaCAD
linear_extrude(height = 5) {
hull() {
union() {
union() {
union() {
translate([2, 2, 0]) {
circle(r = 2, $fn = 32);
}
translate([18, 2, 0]) {
circle(r = 2, $fn = 32);
}
}
translate([2, 8, 0]) {
circle(r = 2, $fn = 32);
}
}
translate([18, 8, 0]) {
circle(r = 2, $fn = 32);
}
}
}
}
local my_cube = cube { size = { 1, 2, 3 } }
local function my_sphere(_radius)
return sphere({ r = 2 }):translate(5, 0, 0)
end
local model = my_cube + my_sphere(2)
render(model)
// Generated by LuaCAD
union() {
cube([1, 2, 3]);
translate([5, 0, 0]) {
sphere(r = 2, $fn = 32);
}
}
local model = cube { { 60, 20, 10 }, center = true }
+ cube({ { 30, 20, 10 }, center = true }):translate(5, 0, 10 - 0.001)
+ cylinder({ h = 3, r = 8, center = true })
:rotate(90, 0, 0)
:translate(-20, -15, 0)
+ cylinder({ h = 3, r = 8, center = true })
:rotate(90, 0, 0)
:translate(-20, 15, 0)
+ cylinder({ h = 3, r = 8, center = true })
:rotate(90, 0, 0)
:translate(20, -15, 0)
+ cylinder({ h = 3, r = 8, center = true })
:rotate(90, 0, 0)
:translate(20, 15, 0)
+ cylinder({ h = 30, r = 2, center = true })
:rotate(90, 0, 0)
:translate(-20, 0, 0)
+ cylinder({ h = 30, r = 2, center = true })
:rotate(90, 0, 0)
:translate(20, 0, 0)
render(model)
// Generated by LuaCAD
union() {
union() {
union() {
union() {
union() {
union() {
union() {
cube([60, 20, 10], center = true);
translate([5, 0, 9.999]) {
cube([30, 20, 10], center = true);
}
}
translate([-20, -15, 0]) {
rotate([90, 0, 0]) {
cylinder(h = 3, r1 = 8, r2 = 8, $fn = 32, center = true);
}
}
}
translate([-20, 15, 0]) {
rotate([90, 0, 0]) {
cylinder(h = 3, r1 = 8, r2 = 8, $fn = 32, center = true);
}
}
}
translate([20, -15, 0]) {
rotate([90, 0, 0]) {
cylinder(h = 3, r1 = 8, r2 = 8, $fn = 32, center = true);
}
}
}
translate([20, 15, 0]) {
rotate([90, 0, 0]) {
cylinder(h = 3, r1 = 8, r2 = 8, $fn = 32, center = true);
}
}
}
translate([-20, 0, 0]) {
rotate([90, 0, 0]) {
cylinder(h = 30, r1 = 2, r2 = 2, $fn = 32, center = true);
}
}
}
translate([20, 0, 0]) {
rotate([90, 0, 0]) {
cylinder(h = 30, r1 = 2, r2 = 2, $fn = 32, center = true);
}
}
}
-- Text is outlined from a system font into a sketch, so it extrudes and
-- combines like any other 2D shape.
-- text3d() outlines and extrudes in one step.
render(text3d("LuaCAD", { size = 12, depth = 2 }))
-- text() returns the sketch, which leaves the extrusion up to you.
local label = text("v1.0", {
size = 8,
halign = "center",
valign = "top",
})
render(label:linear_extrude(1.5):translate(30, -6, 0))
-- Fonts are chosen by family, optionally with a style. An unknown family
-- falls back to the default sans-serif face rather than failing.
render(
text3d("Bold", {
size = 10,
depth = 2,
font = "DejaVu Sans:style=Bold",
}):translate(0, -30, 0)
)
-- Engraving is a difference like any other.
local plate = cube(70, 20, 4)
local engraving = text3d("ENGRAVED", { size = 7, depth = 5 })
:translate(6, 7, 1)
render((plate - engraving):translate(0, -60, 0))
// Generated by LuaCAD
union() {
linear_extrude(height = 2) {
text("LuaCAD", size = 12, font = "Arial", halign = "left", valign = "baseline");
}
translate([30, -6, 0]) {
linear_extrude(height = 1.5) {
text("v1.0", size = 8, font = "Arial", halign = "center", valign = "top");
}
}
translate([0, -30, 0]) {
linear_extrude(height = 2) {
text("Bold", size = 10, font = "DejaVu Sans:style=Bold", halign = "left", valign = "baseline");
}
}
translate([0, -60, 0]) {
difference() {
cube([70, 20, 4]);
translate([6, 7, 1]) {
linear_extrude(height = 5) {
text("ENGRAVED", size = 7, font = "Arial", halign = "left", valign = "baseline");
}
}
}
}
}
-- Create and print some basic shapes
print("Basic shapes:")
print("- Cube: " .. tostring(cube(10, 10, 10)))
print("- Sphere: " .. tostring(sphere { r = 5 }))
print("- Cylinder: " .. tostring(cylinder { h = 10, r = 5 }))
-- Cylinders with different parameters
print("\nCylinder variations:")
print("- Standard cylinder: " .. tostring(cylinder { h = 10, r = 5 }))
print("- Cylinder with diameter: " .. tostring(cylinder { h = 10, d = 10 }))
print("- Cone (r1, r2): " .. tostring(cylinder { h = 10, r1 = 5, r2 = 2 }))
print("- Cone (d1, d2): " .. tostring(cylinder { h = 10, d1 = 10, d2 = 4 }))
print(
"- Centered cylinder: " .. tostring(cylinder { h = 10, r = 5, center = true })
)
-- Colors
print("\nColored objects:")
local my_cube = cube(10, 10, 10)
local my_sphere = sphere { r = 7 }
print("- Red cube: " .. tostring(my_cube:setcolor("red")))
print("- Blue sphere: " .. tostring(my_sphere:setcolor("blue")))
print(
"- Green cylinder: "
.. tostring(cylinder({ h = 10, r = 5 }):setcolor("green"))
)
-- Render the colored objects
render(my_cube:setcolor("red") + my_sphere:setcolor("blue"))
// Generated by LuaCAD
union() {
color([1, 0, 0]) {
cube([10, 10, 10]);
}
color([0, 0, 1]) {
sphere(r = 7, $fn = 32);
}
}