An introduction to CAD in TypeScript with Replicad

Replicad is a JavaScript/TypeScript library for creating 3D CAD models programmatically. It allows us to create complex structures with code and more uniquely, allows for shared, zero-install, interactive parametric designs.

Getting started with 2D drawing

We will use the Replicad Workbench. You can type code and see the results quickly. The workbench provides a replicad object which has many functions we will use. To start with, let's draw something in 2D using draw().

const { draw } = replicad;

export default function main() {
  return draw().hLine(10).vLine(10).hLine(-5).close()
}

The fluent API (where we chain method calls) allows us to give low-level drawing commands, finishing with a call to close(). This looks like:

Basic Drawing

The full API for drawing is in the Drawing Pen docs where you will find many ways to draw curves, arcs, lines and so on. You can also draw common shapes like circles and rectangles with helper methods like drawCircle and drawRectangle.

Extrude it into 3D

Let's make something 3D. This requires two new steps:

  1. We sketch it on a particular plane, e.g., "XY"
  2. We extrude by a particular depth
export default function main() {
  return draw()
    .hLine(10)
    .vLine(10)
    .hLine(-5)
    .close()
    .sketchOnPlane("XY")
    .extrude(10)
}
Extruding

Merging (Fusing) Shapes

Let's make a Lego brick, like in our previous OpenSCAD tutorial. It will look like this:

Lego style brick

We only really need two new concepts:

  1. fuse to combine shapes
  2. translate to move shapes around

For now, we will pick some variables to control the number of studs, but you can easily make this into a function.

export default function main() {

  const N = 6
  const M = 2

Let's draw a basic cube:

  const r = drawRectangle(N * 20, M * 20).sketchOnPlane("XY").extrude(20)

We will then build up an array of cylinders for the studs on top. The tricky bit is positioning them correctly using translate:

  const cylinders = []

  for(let i=0; i<M; i++) {
    for(let j=0; j<N; j++) {
      let c = drawCircle(6)
          .sketchOnPlane("XY")
          .extrude(5)
          .translate(
                      -(N / 2) * 20 + 10 + j * 20,
                      -(M / 2) * 20 + 10 + i * 20,
                      20
                    )
      cylinders.push(c)
    }
  }

But how do we fuse them? We'll want to fuse them all in turn. It would be tedious to do this in the loop, so we can create a helper function (as suggested in the docs) to do this:

  return fuseAll([r, ...cylinders])
}

const fuseAll = (shapes) => {
  let result = shapes[0];
  shapes.slice(1).forEach((shape) => {
    result = result.fuse(shape);
  });
  return result;
};

That is already enough Replicad to create quite a lot of things. In a future post we will look at subtracting shapes, fancy ways of creating 3D shapes from more than one 2D sketch and modifications we can apply to shapes.