OpenJSCAD is a programmatic way of creating 3D objects with two advantages over my preferred method, Blender.
- It’s easier to create measured objects, so it’s ideal for 3D printing parts that require precision for things like screw holes and attachments.
- It has an API for taking in variables that can dynamically affect the final model. So users can create useful, custom models without needing to be able to code or be a modeler.

My C-Clamp visualization – JSFiddle: https://jsfiddle.net/fv41wqu9/3/
For my first project using OpenJSCAD I wanted to create something that would organize all the wires in my house. I often use zip ties but my biggest issue with that method is that it’s time consuming and wasteful to temporarily remove one of the cords. My solution was to create a script that asks for an array of wire diameters and then computes a radial clip that holds the wires neatly away from each other. I like this project because I think it’s a great example of the power of both openJSCAD and 3d printers to create something that wouldn’t be possible to mass manufacture because of the different sizes and combinations of wires, necessary. It was also an interesting math problem, getting the clips holders to organize around a circle, point towards the center and move in or out depending on the size and number of the wire holders required the code to be very dynamic. Using an html5 canvas on JSfiddle to quickly plot things out was a big help. For instance, to get the C shaped clamp that holds wires, I need to plot points along the out edge in the right order. I ended up with a string of dots that allowed me to quickly visualize what I was coming up with.
To use it, just download the radial-wire-clip OpenJSCAD file and drop it into the “Drop your .jscad file here” box on the OpenJSCAD parser. After that, the ‘clip sizes’ field takes a list of floating point numbers, separated by commas. They should be the diameters of each wire it will hold, in millimeters.
Clip Gallery
OpenJSCAD code
function getParameterDefinitions() {
return [
{ "name":"wire_diams_string", "caption":"Clips sizes (separated by commas)", "type":"text", "default":"2,4,5,6,8"},
{ "name":"clip_thickness", "caption":"Thickness of each clip", "type":"float", "default":"6"}
];
}
function main(params) {
var wire_diams = params.wire_diams_string.split(",").map(parseFloat); //turn the csv's into an array of floats
var numClips = wire_diams.length;
var clipSteps = 2 * Math.PI / numClips; // amount to add to theta each time (degrees)
var clipR = ((numClips * 1.5) + 2); //scale the root circle up linearly with the number of clips
var allClips = new CSG(); //a blank object to start adding clips to
var iter = 0; //This is for the main 'clip' loop, incremented once for each loop
for (k = 0.1; k < = 2 * Math.PI; k += clipSteps) {
//these set up the clip points that will be extruded
var theta = 1.5; // angle that will be increased each loop
var outertheta = 1.4; //s
var step = 2 * Math.PI / 40; // amount to add to theta each time (degrees)
var r = wire_diams[iter]/2;
var outerR = r + 2;
//////////ROOT RADIUS VARS (Where the clips are placed)
//Make the root radius variably bigger or smaller if the clip size is bigger or smaller
//how much to push out each clip as it gets bigger (2 is the smallest size)
xoffset = yoffset = r/2*1.4;
//Final x and y for placing each Clip
var rootX = (clipR + xoffset) * Math.cos(k);
var rootY = (clipR + yoffset) * Math.sin(k);
//Loop for points inside of clip shape
var points = [];
for (i = theta; i <= 2 * Math.PI; i += step) { x = r * Math.cos(i); y = r * Math.sin(i); points.push([x, y]); } //loop for outside points of clip shape, noticed it's reversed! This is because the points on the outside should start right next to the last inside loop point. for (i = 2 * Math.PI; i >= outertheta; i -= step) {
x = outerR * Math.cos(i);
y = outerR * Math.sin(i);
points.push([x, y]);
}
var shape = CAG.fromPoints(points);
var extruded = shape.extrude({
offset: [0, 0, params.clip_thickness], // direction for extrusion
});
//Figure out the angle for each clip to point towards then center, then move the clip to the outside radius
var angle = Math.atan2(0 - rootY, 0 - rootX);
angle = angle * (180 / Math.PI);
extruded = extruded.rotateZ(angle + 145);
extruded = extruded.translate([rootX, rootY, 0]);
allClips = allClips.union(extruded);
iter++;
}
// The inside cylinder that connects the clips:
var cylinder = CSG.cylinder({
start: [0, 0, 0],
end: [0, 0, 4],
radius: clipR - 1.15,
resolution: 30 // optional
});
//cylinder = cylinder.rotateZ(4);
finalform = allClips.union(cylinder);
return finalform;
}