OpenJsCad

Please note: OpenJsCad currently only runs reliably on Google Chrome!
Create an STL file for 3D printing using constructive solid modeling in Javascript.

Playground

Try it by entering some code below. Anything you enter will be lost as soon as this page is reloaded; to build your own models you should instead store them in a .jscad file on your computer and use the OpenJsCad parser.




About

This is intended to become a Javascript based alternative to OpenSCAD, for 3D solid modeling. CSG model is contructed using Javascript. For example:
var cube = CSG.cube(); return cube; creates a cube with a radius of 1 and centered at the origin. The code should always end in a return statement, returning a CSG solid.

To build your own modes, create a .jscad file with your javascript code and parse the file using the OpenJsCad parser. When finished you can generate an .stl file, ready to be printed on your 3d printer.

License

Copyright (c) 2012 Joost Nieuwenhuijse. Uses CSG.js, original copyright (c) 2011 Evan Wallace, extensively modified, copyright (c) 2012 Joost Nieuwenhuijse. Uses lightgl.js by Evan Wallace for WebGL rendering. All code released under MIT license.

Contributions are welcome! It's all written in Javascript, so if you know how to use it you know how to modify it as well.

To contribute go to CSG.js at GitHub, create your own fork and send me a pull request.

Viewer navigation

Click and drag to rotate the model around the origin.
Shift+Drag moves the model around.
Alt+drag zooms (by changing the distance between camera and model).

Primitive solids

Currently the following solids are supported. The parameters are passed in an object; most parameters are optional. 3D vectors can be passed in an array. If a scalar is passed for a parameter which expects a 3D vector, it is used for the x, y and z value. In other words: radius: 1 will give radius: [1,1,1].

All rounded solids have a 'resolution' parameter which controls tesselation. If resolution is set to 8, then 8 polygons per 360 degree of revolution are used. Beware that rendering time will increase dramatically when increasing the resolution. For a sphere the number of polygons increases quadratically with the resolution used.

// a cube:
var cube = CSG.cube({
  center: [0, 0, 0],
  radius: [1, 1, 1]
});

// a sphere:
var sphere = CSG.sphere({
  center: [0, 0, 0],
  radius: 2,            // must be scalar
  resolution: 32
});

// a cylinder:
var cylinder = CSG.cylinder({
  start: [0, -1, 0],
  end: [0, 1, 0],
  radius: 1,
  resolution: 16
});

// like a cylinder, but with spherical endpoints:
var roundedCylinder = CSG.roundedCylinder({
  start: [0, -1, 0],
  end: [0, 1, 0],
  radius: 1,
  resolution: 16
});

// a rounded cube:
var cube = CSG.roundedCube({
  center: [0, 0, 0],
  radius: 1,
  roundradius: 0.2,
  resolution: 8,
});

CSG operations

The 3 standard CSG operations are supported. All CSG operations return a new solid; the source solids are not modified:
var csg1 = cube.union(sphere);
var csg2 = cube.intersect(sphere);
var csg3 = cube.subtract(sphere);

Transformations

Solids can be translated, scaled and rotated. Multiple transforms can be combined into a single matrix transform:
var cube = CSG.cube();

// translation:
var cube2 = cube.translate([1, 2, 3]);

// scaling:
var largecube = cube.scale(2.0);
var stretchedcube = cube.scale([1.5, 1, 0.5]);

// rotation:
var rotated1 = cube.rotateX(-45); // rotate around the X axis
var rotated2 = cube.rotateY(90);  // rotate around the Y axis
var rotated3 = cube.rotateZ(20);  // rotate around the Z axis

// combine multiple transforms into a single matrix transform:
var m = new CSG.Matrix4x4();
m = m.multiply(CSG.Matrix4x4.rotationX(40));
m = m.multiply(CSG.Matrix4x4.rotationZ(40));
m = m.multiply(CSG.Matrix4x4.translation([-.5, 0, 0]));
m = m.multiply(CSG.Matrix4x4.scaling([1.1, 1.2, 1.3]));

// and apply the transform:
var cube3 = cube.transform(m);

Mirroring

Solids can be mirrored in any plane in 3D space:
var cube = CSG.cube().translate([1,0,0]);

var cube2 = cube.mirroredX(); // mirrored in the x=0 plane
var cube3 = cube.mirroredY(); // mirrored in the y=0 plane
var cube4 = cube.mirroredZ(); // mirrored in the z=0 plane

// create a plane by specifying 3 points:
var plane = CSG.Plane.fromPoints([5,0,0], [5, 1, 0], [3, 1, 7]);

// and mirror in that plane:
var cube5 = cube.mirrored(plane);

Cutting by a plane

A solid can be cut by a plane; only the part on the back side is kept:
var cube = CSG.cube({radius: 10});

// create a plane by specifying 3 points:
var plane1 = CSG.Plane.fromPoints([5,0,0], [7, 1, 0], [3, 1, 7]);

// or by specifying a normal and a point on the plane:
var plane2 = CSG.Plane.fromNormalAndPoint([3, 1, 2], [5, 0, 0]);

// and cut by the plane:
var part1 = cube.cutByPlane(plane2);

// or if we need the other half of the cube:
var part2 = cube.cutByPlane(plane2.flipped());

Expansion and contraction

Expansion can be seen as the 3D convolution of an object with a sphere. Contraction is the reverse: the area outside the solid is expanded, and this is then subtracted from the solid.

Expansion and contraction are very powerful ways to get an object with nice smooth corners. For example a rounded cube can be created by expanding a normal cube.

Note that these are expensive operations: spheroids are created around every corner and edge in the original object, so the number of polygons quickly increases. Expansion and contraction therefore are only practical for simple non-curved objects.

expand() and contract() take two parameters: the first is the radius of expansion or contraction; the second parameter is optional and specififies the resolution (number of polygons on spherical surfaces, per 360 degree revolution).
var cube1 = CSG.cube({radius: 1.0});
var cube2 = CSG.cube({radius: 1.0}).translate([-0.3, -0.3, -0.3]);
var csg = cube1.subtract(cube2);
var rounded = csg.expand(0.2, 8); 

Determining the bounds of an object

The getBounds() function can be used to retrieve the bounding box of an object. This can be useful if you want to align two objects to each other. getBounds() returns an array with two elements specifying the minimum x,y,z coordinate and the maximum x,y,z coordinate:
var cube1 = CSG.cube({radius: 10});
var cube2 = CSG.cube({radius: 5});

// get the right bound of cube1 and the left bound of cube2:
var deltax = cube1.getBounds()[1].x - cube2.getBounds()[0].x;

// align cube2 so it touches cube1:
cube2  = cube2.translate([deltax, 0, 0]);

return cube1.union(cube2);

2D shapes

Two dimensional shapes can be defined through the Polygon2D class. Currently this requires the polygon to be convex (i.e. all corners less than 180 degrees). Shapes can be transformed (rotation, translation, scaling). To actually use the shape it needs to be extruded into a 3D CSG object through the extrude() function. extrude() places the 2D solid onto the z=0 plane, and extrudes in the specified direction. Extrusion can be done with an optional twist. This rotates the solid around the z axis (and not necessariy around the extrusion axis) during extrusion. The total degrees of rotation is specified in the twistangle parameter, and twiststeps determine the number of steps between the bottom and top surface.
// Create a shape; argument is an array of 2D coordinates
// The shape must be convex, can be specified in clockwise or in counterclockwise direction 
var shape2d=new CSG.Polygon2D([[0,0], [5,0], [3,5], [0,5]]);

// Do some transformations:
shape2d=shape2d.translate([-2, -2]);
shape2d=shape2d.rotate(20);
shape2d=shape2d.scale([0.2, 0.2]);

// And extrude. This creates a CSG solid:
var extruded=shape2d.extrude({
  offset: [0.5, 0, 2],   // direction for extrusion
  twistangle: 180,       // top surface is rotated 180 degrees 
  twiststeps: 100        // create 100 slices
});