Dodecahedron
// ============================================================
// 3×3×3 hollow dodecahedron cube – solid fill at BOTH ends
// Bottom fill: Z = 0 to fill_height
// Top fill: Z = total_height - fill_height to total_height
// Plates: 0.4 mm thick, overlapping 0.4 mm
// ============================================================
phi = (1 + sqrt(5)) / 2;
vertices = [
[ 1, 1, 1], [ 1, 1, -1], [ 1, -1, 1], [ 1, -1, -1],
[-1, 1, 1], [-1, 1, -1], [-1, -1, 1], [-1, -1, -1],
[0, 1/phi, phi], [0, 1/phi, -phi], [0, -1/phi, phi], [0, -1/phi, -phi],
[ 1/phi, phi, 0], [ 1/phi, -phi, 0], [-1/phi, phi, 0], [-1/phi, -phi, 0],
[ phi, 0, 1/phi], [ phi, 0, -1/phi], [-phi, 0, 1/phi], [-phi, 0, -1/phi]
];
faces = [
[0, 8, 4, 14, 12], [0, 8, 10, 2, 16], [0, 16, 17, 1, 12],
[7, 11, 3, 13, 15], [7, 19, 5, 9, 11], [7, 15, 6, 18, 19],
[1, 9, 5, 14, 12], [6, 15, 13, 2, 10], [1, 17, 3, 11, 9],
[6, 10, 8, 4, 18], [2, 13, 3, 17, 16], [5, 19, 18, 4, 14]
];
function face_center(idx) =
let(p = [for (i = faces[idx]) vertices[i]])
(p[0] + p[1] + p[2] + p[3] + p[4]) / 5;
function inradius(radius) = radius * norm(face_center(0)) / sqrt(3);
function bbox_half(radius) = (radius / sqrt(3)) * max(abs(phi), abs(1/phi), 1);
module dodecahedron(radius = 1) {
scale(radius / sqrt(3))
polyhedron(points = vertices, faces = faces);
}
module hollow_dodecahedron(radius = 20, wall = 0.8) {
difference() {
dodecahedron(radius);
scale((radius - wall) / radius)
dodecahedron(radius);
}
}
module dodecahedron_cube_hollow_thin_filled_top_and_bottom(
radius = 20,
rows = 3,
cols = 3,
layers = 3,
wall = 0.8,
plate_thickness = 0.4,
plate_overlap = 0.4,
fill_height = 5 // height of the solid fill at each end
) {
s = 2 * inradius(radius);
h = bbox_half(radius);
dx = (cols - 1) * s + 2 * h;
dy = (rows - 1) * s + 2 * h;
total_height = (layers - 1) * s + 2 * h;
echo(str("Plate footprint: ", dx, " mm x ", dy, " mm"));
echo(str("Total height: ", total_height + plate_overlap * 2, " mm"));
echo(str("Fill height (bottom & top): ", fill_height, " mm"));
translate([-dx/2, -dy/2, -total_height/2])
union() {
// --- Bottom plate (thin) ---
translate([0, 0, -plate_overlap])
cube([dx, dy, plate_thickness]);
// --- Solid fill block at bottom (Z = 0 to fill_height) ---
translate([0, 0, 0])
cube([dx, dy, fill_height]);
// --- Top plate (thin) ---
translate([0, 0, total_height - plate_thickness + plate_overlap])
cube([dx, dy, plate_thickness]);
// --- Solid fill block at top (Z = total_height - fill_height to total_height) ---
translate([0, 0, total_height - fill_height])
cube([dx, dy, fill_height]);
// --- Hollow dodecahedra (embedded into the fill blocks) ---
for (layer = [0:layers-1])
for (row = [0:rows-1])
for (col = [0:cols-1])
translate([h + col * s, h + row * s, h + layer * s])
hollow_dodecahedron(radius, wall);
}
}
// Generate the model
dodecahedron_cube_hollow_thin_filled_top_and_bottom(radius = 10, fill_height = 3);
// ============================================================
// Generate the model - change radius 5 23.4 × 23.4 mm 27.9 mm
// 10 46.8 × 46.8 mm 55.7 mm
// 15 70.2 × 70.2 mm 83.5 mm
// 20 93.6 × 93.6 mm 111.3 mm
// ============================================================
Straight after Batman.
#deggers #rigger
#cyberpunkcoltoure
Green Batman has a place now. So...
// ============================================================
// 3×3×3 Kelvin lattice (truncated octahedra) – hollow, connected,
// solid fill at BOTH ends, optional skin plates.
// ============================================================
/* [Main Parameters] */
size = 25; // distance between opposite square faces of one cell
rows = 3; // number of cells along Y
cols = 3; // number of cells along X
layers = 3; // number of cells along Z
wall = 0.8; // shell thickness (≥ 0.8 mm for strength)
fill_height = 3.0; // height of solid fill blocks at top & bottom
plate_thickness = 0.4; // thickness of outer skin plates (0 = no plates)
plate_overlap = 0.4; // how much the plates extend beyond the lattice
// ---------- vertex & face data (one unit truncated octahedron) ----------
to_raw = [
[ 0, 1, 2], [ 0, 2, 1], [ 0, 2, -1], [ 0, 1, -2],
[ 0, -1, -2], [ 0, -2, -1], [ 0, -2, 1], [ 0, -1, 2],
[ 1, 0, 2], [ 2, 0, 1], [ 2, 0, -1], [ 1, 0, -2],
[-1, 0, -2], [-2, 0, -1], [-2, 0, 1], [-1, 0, 2],
[ 1, 2, 0], [ 2, 1, 0], [ 2, -1, 0], [ 1, -2, 0],
[-1, -2, 0], [-2, -1, 0], [-2, 1, 0], [-1, 2, 0]
];
// all 14 faces with correct outward orientation
to_faces = [
// hexagonal faces (8)
[0,8,9,17,16,1], // (+x,+y,+z)
[2,16,17,10,11,3], // (+x,+y,-z)
[8,7,6,19,18,9], // (+x,-y,+z)
[10,18,19,5,4,11], // (+x,-y,-z)
[0,1,23,22,14,15], // (-x,+y,+z)
[2,3,12,13,22,23], // (-x,+y,-z)
[7,15,14,21,20,6], // (-x,-y,+z)
[5,20,21,13,12,4], // (-x,-y,-z)
// square faces (6)
[9,18,10,17], // +x
[22,13,21,14], // -x
[1,16,2,23], // +y
[20,5,19,6], // -y
[15,7,8,0], // +z
[3,11,4,12] // -z
];
// ---------- module: one hollow truncated octahedron ----------
module hollow_kelvin_cell(size, wall) {
s_outer = size / 4; // raw coords span 4 → size
s_inner = (size - 2*wall) / 4; // inner shell offset by wall
outer_pts = [for (v = to_raw) v * s_outer];
inner_pts = [for (v = to_raw) v * s_inner];
difference() {
polyhedron(points = outer_pts, faces = to_faces);
polyhedron(points = inner_pts, faces = to_faces);
}
}
// ---------- overall lattice module ----------
module kelvin_lattice_sandwich(
size,
rows, cols, layers,
wall,
fill_height,
plate_thickness,
plate_overlap
) {
dx = cols * size;
dy = rows * size;
total_height = layers * size;
echo(str("Plate footprint: ", dx, " mm × ", dy, " mm"));
echo(str("Total lattice height: ", total_height, " mm"));
echo(str("Fill height (top & bottom): ", fill_height, " mm"));
union() {
// --- hollow cells array (centers at half‑cell intervals) ---
for (x = [0:cols-1], y = [0:rows-1], z = [0:layers-1])
translate([x*size + size/2, y*size + size/2, z*size + size/2])
hollow_kelvin_cell(size, wall);
// --- bottom solid fill block ---
translate([0, 0, 0])
cube([dx, dy, fill_height]);
// --- top solid fill block ---
translate([0, 0, total_height - fill_height])
cube([dx, dy, fill_height]);
// --- optional thin outer plates ---
if (plate_thickness > 0) {
// bottom plate
translate([0, 0, -plate_overlap])
cube([dx, dy, plate_thickness]);
// top plate
translate([0, 0, total_height - plate_thickness + plate_overlap])
cube([dx, dy, plate_thickness]);
}
}
}
// ---------- generate model ----------
kelvin_lattice_sandwich(
size = size,
rows = rows,
cols = cols,
layers = layers,
wall = wall,
fill_height = fill_height,
plate_thickness = plate_thickness,
plate_overlap = plate_overlap
);
For the same wall thickness and overall dimensions, the Kelvin lattice is about 30 % stiffer than a dodecahedron‑based foam (Gibson‑Ashby constant C1≈1.0C1≈1.0 vs. 0.70.7). This means you get more rigidity for the same amount of material.
In short, the truncated octahedron turns your isolated‑shell concept into a true interconnected cellular solid. It retains the lightweight, hollow‑core idea while giving you a continuous, load‑bearing structure that is as stiff as a solid block for the same weight, and it prints cleanly. If you need any clarification on how the faces connect or how to verify the fusion in your slicer, just let me know.
_How Cyberpunk is that??
// ============================================================
// 3×3×3 Kelvin lattice (truncated octahedra) – Klemmbrick variants
//
// This script builds on the hollow Kelvin lattice sandwich and
// adds compatible male/female connectors to turn it into a
// stackable building block.
//
// Two variants are provided:
// kelvin_lattice_tile() – flat top, female sockets on bottom
// kelvin_lattice_brick() – male studs on top, female sockets on bottom
//
// The stud grid automatically follows the cell arrangement:
// stud spacing = size, stud count = cols × rows
// ============================================================
/* [Main Parameters] */
size = 25; // distance between opposite square faces of one cell
rows = 3; // number of cells along Y
cols = 3; // number of cells along X
layers = 3; // number of cells along Z
wall = 0.8; // shell thickness (≥ 0.8 mm for strength)
fill_height = 3.0; // height of solid fill blocks at top & bottom
plate_thickness = 0.4; // thickness of outer skin plates (0 = no plates)
plate_overlap = 0.4; // how much the plates extend beyond the lattice
/* [Klemmbrick Connectors] */
stud_spacing = 25; // grid spacing of the connectors (default = size)
stud_diameter = 10; // diameter of male studs
stud_height = 3.75; // height of male studs (default = size*0.15)
female_clearance = 0.2; // extra diameter for female sockets
// ---------- vertex & face data (one unit truncated octahedron) ----------
to_raw = [
[ 0, 1, 2], [ 0, 2, 1], [ 0, 2, -1], [ 0, 1, -2],
[ 0, -1, -2], [ 0, -2, -1], [ 0, -2, 1], [ 0, -1, 2],
[ 1, 0, 2], [ 2, 0, 1], [ 2, 0, -1], [ 1, 0, -2],
[-1, 0, -2], [-2, 0, -1], [-2, 0, 1], [-1, 0, 2],
[ 1, 2, 0], [ 2, 1, 0], [ 2, -1, 0], [ 1, -2, 0],
[-1, -2, 0], [-2, -1, 0], [-2, 1, 0], [-1, 2, 0]
];
to_faces = [
// hexagonal faces (8)
[0,8,9,17,16,1], // (+x,+y,+z)
[2,16,17,10,11,3], // (+x,+y,-z)
[8,7,6,19,18,9], // (+x,-y,+z)
[10,18,19,5,4,11], // (+x,-y,-z)
[0,1,23,22,14,15], // (-x,+y,+z)
[2,3,12,13,22,23], // (-x,+y,-z)
[7,15,14,21,20,6], // (-x,-y,+z)
[5,20,21,13,12,4], // (-x,-y,-z)
// square faces (6)
[9,18,10,17], // +x
[22,13,21,14], // -x
[1,16,2,23], // +y
[20,5,19,6], // -y
[15,7,8,0], // +z
[3,11,4,12] // -z
];
// ---------- module: one hollow truncated octahedron ----------
module hollow_kelvin_cell(size, wall) {
s_outer = size / 4;
s_inner = (size - 2*wall) / 4;
outer_pts = [for (v = to_raw) v * s_outer];
inner_pts = [for (v = to_raw) v * s_inner];
difference() {
polyhedron(points = outer_pts, faces = to_faces);
polyhedron(points = inner_pts, faces = to_faces);
}
}
// ---------- core lattice sandwich (internal) ----------
module kelvin_lattice_sandwich(
size,
rows, cols, layers,
wall,
fill_height,
plate_thickness,
plate_overlap
) {
dx = cols * size;
dy = rows * size;
total_height = layers * size;
union() {
// hollow cell array
for (x = [0:cols-1], y = [0:rows-1], z = [0:layers-1])
translate([x*size + size/2, y*size + size/2, z*size + size/2])
hollow_kelvin_cell(size, wall);
// bottom solid fill
translate([0, 0, 0])
cube([dx, dy, fill_height]);
// top solid fill
translate([0, 0, total_height - fill_height])
cube([dx, dy, fill_height]);
// optional thin outer plates
if (plate_thickness > 0) {
// bottom plate
translate([0, 0, -plate_overlap])
cube([dx, dy, plate_thickness]);
// top plate
translate([0, 0, total_height - plate_thickness + plate_overlap])
cube([dx, dy, plate_thickness]);
}
}
}
// ---------- Klemmbrick helper: female sockets on the bottom ----------
module add_female_sockets(
dx, dy,
cols, rows,
size,
fill_height,
plate_thickness,
plate_overlap,
stud_diameter,
female_clearance,
stud_height
) {
// deepest point of the model underside
bottom_z = (plate_thickness > 0) ? -plate_overlap : 0;
// hole must go from bottom surface up through the solid fill
hole_height = fill_height - bottom_z;
// female hole radius
female_r = (stud_diameter + female_clearance) / 2;
// subtract a cylinder at each cell center
for (x = [0:cols-1], y = [0:rows-1]) {
cx = x * size + size/2;
cy = y * size + size/2;
translate([cx, cy, bottom_z])
cylinder(r = female_r, h = hole_height, $fn = 32);
}
}
// ---------- Klemmbrick helper: male studs on the top ----------
module add_male_studs(
dx, dy,
cols, rows,
size,
total_height,
plate_thickness,
plate_overlap,
stud_diameter,
stud_height
) {
// highest surface of the model
top_z = (plate_thickness > 0)
? total_height + plate_overlap
: total_height;
stud_r = stud_diameter / 2;
for (x = [0:cols-1], y = [0:rows-1]) {
cx = x * size + size/2;
cy = y * size + size/2;
translate([cx, cy, top_z])
cylinder(r = stud_r, h = stud_height, $fn = 32);
}
}
// ---------- public module: flat tile with female connectors on bottom ----------
module kelvin_lattice_tile() {
dx = cols * size;
dy = rows * size;
total_height = layers * size;
difference() {
kelvin_lattice_sandwich(
size, rows, cols, layers,
wall, fill_height, plate_thickness, plate_overlap
);
add_female_sockets(
dx, dy, cols, rows, size,
fill_height, plate_thickness, plate_overlap,
stud_diameter, female_clearance, stud_height
);
}
}
// ---------- public module: brick with male studs on top and female on bottom ----------
module kelvin_lattice_brick() {
dx = cols * size;
dy = rows * size;
total_height = layers * size;
difference() {
union() {
kelvin_lattice_sandwich(
size, rows, cols, layers,
wall, fill_height, plate_thickness, plate_overlap
);
add_male_studs(
dx, dy, cols, rows, size,
total_height, plate_thickness, plate_overlap,
stud_diameter, stud_height
);
}
add_female_sockets(
dx, dy, cols, rows, size,
fill_height, plate_thickness, plate_overlap,
stud_diameter, female_clearance, stud_height
);
}
}
// ============================================================
// Build one of the variants below (comment/uncomment)
// ============================================================
// Tile (flat top, female bottom)
// kelvin_lattice_tile();
// Brick (male top, female bottom)
kelvin_lattice_brick();
Do you see the opportunities??!!
PS: DIN LEGO
// ============================================================
// 3×3×3 Kelvin lattice – Klemmbrick with INDEPENDENT stud grid
//
// - Stud spacing FIXED at 8 mm (true Lego grid)
// - Stud diameter / height locked to original Lego values
// - Plate size (lattice) can be scaled independently
// ============================================================
/* [Main Parameters] */
size = 10; // cell size of the Kelvin lattice
rows = 30; // number of cells along Y
cols = 15; // number of cells along X
layers = 3; // number of cells along Z
wall = 0.8; // shell thickness
fill_height = 3.0; // solid fill height top & bottom
plate_thickness = 0.4; // outer skin thickness (0 = off)
plate_overlap = 0.4; // extra plate extension
/* [Lego Grid – DO NOT change for standard compatibility] */
stud_spacing = 8; // fixed 8 mm grid (original Lego pitch)
stud_diameter = 4.8; // standard stud diameter
stud_height = 1.8; // standard stud height
female_clearance = 0.2; // extra hole width for a snug fit
// ---------- vertex & face data (unchanged) ----------
to_raw = [
[ 0, 1, 2], [ 0, 2, 1], [ 0, 2, -1], [ 0, 1, -2],
[ 0, -1, -2], [ 0, -2, -1], [ 0, -2, 1], [ 0, -1, 2],
[ 1, 0, 2], [ 2, 0, 1], [ 2, 0, -1], [ 1, 0, -2],
[-1, 0, -2], [-2, 0, -1], [-2, 0, 1], [-1, 0, 2],
[ 1, 2, 0], [ 2, 1, 0], [ 2, -1, 0], [ 1, -2, 0],
[-1, -2, 0], [-2, -1, 0], [-2, 1, 0], [-1, 2, 0]
];
to_faces = [
[0,8,9,17,16,1], [2,16,17,10,11,3], [8,7,6,19,18,9],
[10,18,19,5,4,11], [0,1,23,22,14,15], [2,3,12,13,22,23],
[7,15,14,21,20,6], [5,20,21,13,12,4],
[9,18,10,17], [22,13,21,14], [1,16,2,23],
[20,5,19,6], [15,7,8,0], [3,11,4,12]
];
// ---------- one hollow cell ----------
module hollow_kelvin_cell(size, wall) {
s_outer = size / 4;
s_inner = (size - 2*wall) / 4;
outer_pts = [for (v = to_raw) v * s_outer];
inner_pts = [for (v = to_raw) v * s_inner];
difference() {
polyhedron(points = outer_pts, faces = to_faces);
polyhedron(points = inner_pts, faces = to_faces);
}
}
// ---------- core lattice sandwich ----------
module kelvin_lattice_sandwich(size, rows, cols, layers, wall, fill_height, plate_thickness, plate_overlap) {
dx = cols * size;
dy = rows * size;
total_height = layers * size;
union() {
for (x = [0:cols-1], y = [0:rows-1], z = [0:layers-1])
translate([x*size + size/2, y*size + size/2, z*size + size/2])
hollow_kelvin_cell(size, wall);
translate([0,0,0]) cube([dx, dy, fill_height]);
translate([0,0,total_height - fill_height]) cube([dx, dy, fill_height]);
if (plate_thickness > 0) {
translate([0,0,-plate_overlap]) cube([dx, dy, plate_thickness]);
translate([0,0,total_height - plate_thickness + plate_overlap]) cube([dx, dy, plate_thickness]);
}
}
}
// ---------- stud grid helper (uses fixed 8 mm spacing) ----------
module generate_stud_grid(dx, dy, total_height, plate_thickness, plate_overlap, female = false) {
// how many studs can we fit across each axis?
studs_x = floor(dx / stud_spacing);
studs_y = floor(dy / stud_spacing);
// center the grid on the plate
offset_x = (dx - studs_x * stud_spacing) / 2 + stud_spacing / 2;
offset_y = (dy - studs_y * stud_spacing) / 2 + stud_spacing / 2;
// height for male studs (top) or female holes (bottom)
top_z = (plate_thickness > 0) ? total_height + plate_overlap : total_height;
bottom_z = (plate_thickness > 0) ? -plate_overlap : 0;
hole_height = fill_height - bottom_z;
female_r = (stud_diameter + female_clearance) / 2;
stud_r = stud_diameter / 2;
for (ix = [0:studs_x-1], iy = [0:studs_y-1]) {
cx = offset_x + ix * stud_spacing;
cy = offset_y + iy * stud_spacing;
if (female) {
// subtract female socket
translate([cx, cy, bottom_z])
cylinder(r = female_r, h = hole_height, $fn = 32);
} else {
// add male stud
translate([cx, cy, top_z])
cylinder(r = stud_r, h = stud_height, $fn = 32);
}
}
}
// ---------- flat tile (top without studs, bottom with sockets) ----------
module kelvin_lattice_tile() {
dx = cols * size;
dy = rows * size;
total_height = layers * size;
difference() {
kelvin_lattice_sandwich(size, rows, cols, layers, wall, fill_height, plate_thickness, plate_overlap);
generate_stud_grid(dx, dy, total_height, plate_thickness, plate_overlap, female = true);
}
}
// ---------- brick (studs on top, sockets on bottom) ----------
module kelvin_lattice_brick() {
dx = cols * size;
dy = rows * size;
total_height = layers * size;
difference() {
union() {
kelvin_lattice_sandwich(size, rows, cols, layers, wall, fill_height, plate_thickness, plate_overlap);
generate_stud_grid(dx, dy, total_height, plate_thickness, plate_overlap, female = false);
}
generate_stud_grid(dx, dy, total_height, plate_thickness, plate_overlap, female = true);
}
}
// ============================================================
// Choose one:
// ============================================================
// kelvin_lattice_tile();
kelvin_lattice_brick();