August 13, 2025
Description
Using AI with OpenSCAD 3D Modeling
Project Duration: Approx. 2 hours on August 12, 2025
Introduction: The Spark of an Idea
Use AI to create a basic human model with a customizer using Open-scad Scripting
All scripting was produced by Gemini. No coding by Myself. Just chatting to create script.
Phase 1: Laying the Foundation
To start, Gemini was provided with a set of essential resources to understand the project's context and the best practices for OpenSCAD:
These files established the "rules of the road," ensuring our final model would be robust, customizable, and ready for 3D printing.
Phase 2: First Iteration - Adding Joints and Poses
The first major task was to modify the static arm and leg modules to allow for rotation at the elbows and knees. This involved:
elbow_angle) to the module definitions.rotate() transformation inside the modules to bend the forearm and lower leg relative to the upper limbs.pose_selection).Our initial attempt at posing revealed a problem. In the "Sitting" pose, one of the arms was pointing in the wrong direction.
The first sign of trouble: a symmetrical error in the sitting pose.
This was a classic bug caused by removing the original script's mirror() function in favor of direct angle manipulation for both arms. The fix was to reintroduce mirror() for the right arm and negate the rotation values that are affected by the mirroring operation to ensure both symmetrical and asymmetrical poses rendered correctly.
Phase 3: Refining the Poses and Adding Visible Joints
Further testing revealed more subtle but significant issues. The T-Pose was actually an "I-Pose" with the arms pointing straight up, and in other poses, the arms would clip through the torso.
The "T-Pose" was more of an "I-Pose," indicating a flawed rotation logic.The "Walking" pose arms were described as "cattywampus." A clear sign for a rework.
This feedback prompted a major overhaul:
Phase 4: Finalization and Documentation
After several rounds of iteration and debugging, we arrived at the final version. The model was now fully posable, dimensionally parametric, and visually coherent with clear, functional joints.
.Conclusion
The creation of the Humanizer V2.3 was a testament to the power of iterative design and clear feedback. By starting with a solid foundation of best practices and working through each problem systematically, we transformed a simple static figure into a dynamic and highly customizable 3D model. This journey, from a simple request to a polished final product, showcases a successful collaboration between human creativity and artificial intelligence.
AI Guiding Principles for OpenSCAD & 3D PrintingThis document contains the core principles for collaborating with an AI on OpenSCAD projects intended for 3D printing. Providing this as a starting context for any new project will ensure a faster, more efficient workflow and lead to better, printable results.1. The Golden Rule: Thou Shalt Be ManifoldThis is the single most important concept. A 3D model must be "manifold" or "watertight" to be printable. This means it must be a single, solid object with no holes, no zero-thickness walls, and no internal overlapping faces.Core Problem: Errors like WARNING: Object may not be a valid 2-manifold or ERROR: The given mesh is not closed! mean the model is broken and will fail to print correctly.Our Goal: Every design decision must prioritize creating a single, solid object.2. CSG Best Practices: The epsilon TrickOpenSCAD uses Constructive Solid Geometry (CSG)—building complex shapes by adding (union) or subtracting (difference) simpler ones.The Pitfall: Placing two objects so their faces are perfectly touching often creates manifold errors. The software can't tell if they are one object or two.The Solution: Always ensure objects overlap slightly before joining them. We will use a helper variable, epsilon, for this.// Good: The cube slightly overlaps the sphere, creating a clean union.
epsilon = 0.01;
union() {
sphere(r=10);
translate([-5, -5, -epsilon]) {
cube(10);
}
}
3. Design for Reality: Clearance & TolerancesDigital models are perfect; 3D prints are not. Plastic expands, nozzles have width, and layers create rough surfaces. Parts that touch perfectly in the software will not fit in the real world.The Rule: Always design a gap (clearance) between parts that need to fit together.Best Practice: Define clearance as a variable at the top of your script. This allows you to easily adjust the fit for your specific printer.General Clearance Guidelines:Snug / Press Fit: clearance = 0.1; to 0.2; (mm)Loose / Slip Fit: clearance = 0.3; to 0.5; (mm)// Example: A peg in a hole with proper clearance
peg_diameter = 10;
clearance = 0.4; // A loose fit
difference() {
// The block with the hole
cube(20, center=true);
// The hole is LARGER than the peg
cylinder(h=22, r=(peg_diameter/2) + clearance, center=true);
}
// The peg is its exact size
cylinder(h=20, r=peg_diameter/2, center=true);
4. Parametric by DefaultEvery key dimension should be a variable defined at the top of the script. This is the core of smart, reusable design. It allows for easy tweaking and iteration without digging through the code.Good: length = 120; width = 8; thickness = 1.5;Bad: cube([120, 8, 1.5]);5. Build with ModulesBreak down complex designs into smaller, reusable parts using the module command. This keeps the code clean, organized, and much easier to debug. A project should consist of several small modules combined at the end, not one giant block of code.6. Custom Shapes: The Power and Peril of polyhedronFor complex, non-standard shapes, polyhedron is the most powerful tool. It lets you define an object by its vertices (points) and faces.The Catch: The points for each face must be listed in a clockwise order when viewed from the outside. Getting this wrong is the primary cause of mesh is not closed errors.Our Rule: When using polyhedron, we will double-check the face winding order to ensure the shape is solid.
// =============================================================================
// Parametric Primitives Library for Robust OpenSCAD Design (V3)
// =============================================================================
// This library contains "safe" versions of primitive shapes, designed to be
// fully parametric and less prone to common 3D printing errors.
//
// Guiding Principles Applied:
// 1. Manifold by Default: Shapes are constructed to be solid.
// 2. Parametric by Default: All key dimensions are variables.
// 3. Built with Modules: Each shape is a self-contained module.
// =============================================================================
// --- Helper variable ---
epsilon = 0.01; // A small value for overlaps to prevent manifold errors
// =============================================================================
// ENGINEERING MODULES
// =============================================================================
/*
* safe_cube()
* A robust cube module.
* - size: A vector [x, y, z] for the dimensions.
* - center: A boolean to center the cube on all axes.
*/
module safe_cube(size, center=false) {
if (center) {
translate([-size.x/2, -size.y/2, -size.z/2]) {
cube(size);
}
} else {
cube(size);
}
}
/*
* safe_sphere()
* A robust sphere module.
* - r: The radius of the sphere.
* - d: The diameter of the sphere (overrides radius).
* - res: The resolution ($fn), for controlling smoothness.
*/
module safe_sphere(r=1, d=-1, res=64) {
radius = (d > 0) ? d/2 : r;
sphere(r=radius, $fn=res);
}
/*
* safe_cylinder()
* A robust cylinder module. Can also create truncated cones.
* - h: The height of the cylinder.
* - r1: Bottom radius.
* - r2: Top radius.
* - d1: Bottom diameter (overrides r1).
* - d2: Top diameter (overrides r2).
* - center: A boolean to center the cylinder vertically.
* - res: The resolution ($fn), for controlling smoothness.
*/
module safe_cylinder(h, r1=1, r2=1, d1=-1, d2=-1, center=false, res=64) {
radius1 = (d1 > 0) ? d1/2 : r1;
radius2 = (d2 > 0) ? d2/2 : r2;
cylinder(h=h, r1=radius1, r2=radius2, center=center, $fn=res);
}
/*
* safe_cone()
* A convenient wrapper for creating a cone.
* - h: The height of the cone.
* - r: The bottom radius of the cone.
* - d: The bottom diameter of the cone (overrides radius).
* - center: A boolean to center the cone vertically.
* - res: The resolution ($fn), for controlling smoothness.
*/
module safe_cone(h, r=1, d=-1, center=false, res=64) {
radius = (d > 0) ? d/2 : r;
safe_cylinder(h=h, r1=radius, r2=0, center=center, res=res);
}
/*
* safe_pyramid()
* Creates a pyramid with a rectangular base.
* - base_size: A vector [x, y] for the base dimensions.
* - h: The height of the pyramid.
* - center: Centers the base on the XY plane.
*/
module safe_pyramid(base_size, h, center=false) {
x = base_size.x;
y = base_size.y;
points = [
[0, 0, 0], [x, 0, 0], [x, y, 0], [0, y, 0], // Base points
[x/2, y/2, h] // Apex point
];
faces = [
[0,1,2,3], [0,4,1], [1,4,2], [2,4,3], [3,4,0]
];
if (center) {
translate([-x/2, -y/2, 0]) polyhedron(points=points, faces=faces);
} else {
polyhedron(points=points, faces=faces);
}
}
// =============================================================================
// ARTISTIC & COMPLEX MODULES
// =============================================================================
/*
* safe_torus()
* Creates a torus (donut shape).
* - major_r: Radius from the center of the torus to the center of the tube.
* - minor_r: Radius of the tube itself.
* - res_major: The resolution ($fn) of the major circle.
* - res_minor: The resolution ($fn) of the minor circle.
*/
module safe_torus(major_r, minor_r, res_major=64, res_minor=32) {
rotate_extrude($fn = res_major) {
translate([major_r, 0, 0]) {
circle(r = minor_r, $fn = res_minor);
}
}
}
/*
* rounded_cube()
* Creates a cube with rounded edges and corners (filleted).
* NOTE: This uses minkowski() and can be slow to render.
* - size: A vector [x, y, z] for the overall dimensions.
* - radius: The fillet radius.
* - center: A boolean to center the cube on all axes.
* - res: The resolution ($fn) for the rounding sphere.
*/
module rounded_cube(size, radius, center=false, res=32) {
inner_size = [size.x - radius*2, size.y - radius*2, size.z - radius*2];
if (center) {
minkowski() {
safe_cube(inner_size, center=true);
safe_sphere(r=radius, res=res);
}
} else {
translate([radius, radius, radius]) {
minkowski() {
cube(inner_size);
sphere(r=radius, $fn=res);
}
}
}
}
/*
* safe_star()
* Creates a 2D star and extrudes it.
* - points: The number of points on the star.
* - outer_r: The radius to the outer tips.
* - inner_r: The radius to the inner corners.
* - h: The height to extrude the star.
* - center: Centers the star on the XY plane.
*/
module safe_star(points, outer_r, inner_r, h, center=true) {
angle = 360 / (points * 2);
star_points = [ for (i = [0 : points * 2 - 1])
let(r = i % 2 == 0 ? outer_r : inner_r)
[r * cos(i * angle), r * sin(i * angle)]
];
translate([0,0, center ? -h/2 : 0]) {
linear_extrude(height=h) {
polygon(points=star_points);
}
}
}
/*
* safe_heart()
* Creates a 2D heart and extrudes it.
* - size: An overall scaling factor for the heart.
* - h: The height to extrude the heart.
* - center: Centers the heart on the XY plane.
* - res: The resolution of the curves.
*/
module safe_heart(size, h, center=true, res=100) {
heart_points = [ for (t = [0 : 360/res : 360])
[
size * 16 * pow(sin(t), 3),
size * (13 * cos(t) - 5 * cos(2*t) - 2 * cos(3*t) - cos(4*t))
]
];
translate([0,0, center ? -h/2 : 0]) {
linear_extrude(height=h) {
polygon(points=heart_points);
}
}
}
/*
* safe_almond_eye()
* Creates an almond/eye shape (Vesica Piscis) and extrudes it.
* - width: The total width (x-axis) of the shape.
* - height: The total height (y-axis) of the shape.
* - h: The height to extrude the shape.
* - center: Centers the shape on the XY plane.
* - res: The resolution ($fn) of the curves.
*/
module safe_almond_eye(width, height, h, center=true, res=64) {
r = (pow(height, 2) + pow(width, 2)) / (4 * width);
d = r - width/2;
translate([0,0, center ? -h/2 : 0]) {
linear_extrude(height=h) {
intersection() {
translate([-d, 0, 0]) circle(r=r, $fn=res);
translate([d, 0, 0]) circle(r=r, $fn=res);
}
}
}
}
// =============================================================================
// VISUALIZATION
// =============================================================================
// This section calls the modules to render them for testing.
// --- Engineering Shapes ---
translate([-60, 0, 0]) safe_cube([15,20,10], center=true);
translate([-30, 0, 0]) safe_sphere(r=10);
translate([0, 0, 0]) safe_cylinder(h=20, r1=8, r2=5, center=true);
translate([30, 0, 0]) safe_cone(h=20, d=20, center=true);
translate([60, 0, 0]) safe_pyramid(base_size=[15,15], h=20, center=true);
// --- Artistic & Complex Shapes ---
translate([-60, 40, 0]) safe_torus(major_r=10, minor_r=4);
translate([-30, 40, 0]) rounded_cube(size=[15,15,15], radius=3, center=true);
translate([0, 40, 0]) safe_star(points=5, outer_r=12, inner_r=6, h=5);
translate([30, 40, 0]) safe_heart(size=0.8, h=5);
translate([60, 40, 0]) safe_almond_eye(width=25, height=15, h=5);
License:
Creative Commons — Public Domain
9