Tag Archives: ScriptCAD.org

CAD: ScriptCAD.org Prototype (2019/12)

Around February 2019 I bootstrapped a scripted CAD environment named “ScriptCAD”, and resembles closely to OpenSCAD.org and OpenJSCAD.org (which I co-developed for a couple of years) with a new take, developed from scratch:

ScriptCAD.org: ScriptCAD Logo 2019/11
  • Scripting capability using JavaScript
  • Separate internal representation from display representation
    • Triangulation or Implicit representation
    • only triangulate at late stage at display or export
ScriptCAD.org Internal Stages
  • Intuitive Graphical User Interface (GUI)
    • Simple export various formats
    • Select top-level solids
    • Source <-> TreeView <-> 3D Model selection
Select Source <-> TreeView Item <-> 3D Model

The transparent Source vs Object Tree vs 3D Space has been in the back of my mind for a long time as I keep the connection of each stage intact and transparent.

  • Ease of use
    • hiding JS module complexity and notions
    • Browser use (either use built-in editor or drag-n-drop source with autoreload)
    • Command Line Interface (CLI) use

Screenshots & Examples

SpiritCAD.org Online as Preview

As of November 2019, ScriptCAD.org is reachable as an early preview (alpha stage), most examples work, some do not yet or display wrong output.

Note: there is only limited documentation yet (2019/11), and the API is subject of changes.

I still tune it to my use-cases and therefore API and overall design of the API might change, even drastically; once the API becomes more stable I will release the source code as well.

Some of use-cases (as seen in the gallery above):

  • coding low-level Gcode and use ScriptCAD to preview (render) Gcode including colors, scriptcad (CLI) outputs .gcode to actually print
    • testing single layer color mixed 3D Printing: forms, color mixing
  • ScriptCAD uses ThreeCSG/csg.js at its core to perform CSG operations, which can be very slow – hence, designing complex pieces can be slow as every change recomputes all again (I like to avoid this in future developments) yet as of 0.3.2 basic caching is implemented so only deltas are recomputed.

Introduction Video

The on-going development I document also. That’s it.

ScriptCAD Reference

This reference covers ScriptCAD Core 0.3.3 (2019/12/29)

Note: ScriptCAD in its current implementation is highly experimental and subject of changes.


ScriptCAD is a library, CAD framework and web-site, depending on the context different aspects are meant. In general it allows you to create 2D and 3D geometries with JavaScript, in a very lightweight manner and export them with a particular format for further usage.

In order to reduce verbosity and complexity, you can call cube() and it actually creates an object on a stack or the scene already. You may assign a variable like let a = cube() and then operate on a later like scaling or translating, and even return it from a function. Additionally, you may declare a main() function, if it exists, it will be called.

let a = cube();

So, keep in mind, whenever you call primitives, they will be placed on a stack/scene in that very moment. You may walk through that stack/scene with children(function(c) { ... }) to post-process your scene.

2D Primitives


polygon({points: p, faces: f, ... })

where as

  • p an array of 2D points, and
  • f an array of indices of points defining faces (e.g. triangles).


  • closed: true (default) or false
  • fill: true (default) or false
  • thickness: (default 0 = minimal thickness)

polygon also can be used to draw a line or a polyline, in that case use option closed: false (default true) and fill: false (default true)

polygon([ [0,0], [10,10] ], { closed: false, fill: false }) is a simple line or
polygon([ [0,0], [10,0], [10,10], [0,10] ], { fill: true }) draws a rectangle (closed polyline or polygon)


square(w, h)
square(w, h, opts)
square({ w: 3, h: 2, ... })


  • fill: true (default) or false


circle(r, opts)


  • r: set radius (default 1.0)
  • d: set diameter
  • fill: true (default) or false
  • start: (default 0)
  • end: (default 360)
  • n: amount of segments (default 12)
  • angle: angle rotation (default 0)
  • midpoint: true or false (default)
  • thickness: 0 (default, minimal thickness)

3D Primitives


cube([2,1,3], { center: true })
cube({ size:[2,1,3], center: true })


  • center: true or false or and array of 3 true or false, e.g. [ true, false, false] for each axis x, y, and z
  • experimental:
    • chamfer: 0 (default)
    • fillet: 0 (default)


sphere({r: 1, ...})


  • center: true or false or and array of 3 true or false, e.g. [ true, false, false] for each axis x, y, and z
  • type: angular (default) or icosa
  • n: segments (default 12)

Note: the higher the frequency (n) is, the more computational intensive CSG opertions will be.


cylinder({h:1, r:2, ...})
cylinder({h:1, d:2, ...})
cylinder({h:1, r1: 1, r2: 0, ... })


  • center: true or false or and array of 3 true or false, e.g. [ true, false, false] for each axis x, y, and z
  • n: segments
  • experimental:
    • chamfer: 0 (default)
    • fillet: 0 (default)


polyhedron({points: p, faces: f, ...})

    [              // set of points
    [              // set of faces
       [0,1,2,3],     // square bottom
       [1,0,4],       // side
       [2,1,4],       //  "
       [3,2,4],       //  "
       [0,3,4]        //  "

where as:

  • p: array of [x,y,z] coordinates, e.g. [0, 0, 0]
  • f: array of vertice indexes e.g. [0, 1, 2]

Usually one does not manually compose polyhedron() but create such procedurally.

Note: polyhedron() isn’t compatible OpenSCAD polyhedron() as face orientation is reversed in OpenSCAD compared to common standard.








where as x, y, and z are angles in 0..360 degrees.


.transform([ t0, t1, t2, ... t15 ])
transform(obj,[t0, t1, t2, ... t15])

4×4 transformation matrix applied.


obj1.hull(obj2, ...)
hull(obj1, obj2, ... )

hull() is quite powerful, and one may reduce complex structures back to hulled 2D or 3D primitives.

linear extrude



  • h: height
  • n: segments
  • twist: twist in degrees (0..360)

rotate extrude



  • start: start angle 0..360 (default 0)
  • end: end angle 0..360 (default 360)
  • caps: true (false) or false in case start != end

CSG Operations


obj1.union(obj2, ...)
union(obj1, obj2, ...)

You may consider union() the additive manufacturing principle.

Note: union() operation can be costly in regards of computational overhead.


obj1.difference(obj2, ...)
difference(obj1, obj2, ...)

You may consider the difference() as substractive manufacturing, e.g. drilling a hole (with a cylinder()) into an existing object.

Note: difference() operation can be costly in regards of computational overhead.


obj1.intersection(obj2, ...)
intersection(obj1, obj2, ...)

Note: intersection() operation can be costly in regards of computational overhead.


exclusive(obj1, obj2, ...)
exclusive(obj1, obj2, ..., opts)


  • order: asc (default) or desc

You may consider exclusive() a new CSG operation where all the objects displace each other in ascending or descending order, hence, occupy exclusive space to each other – implementing “there can be no object occupy the same space at the same time”.

  • ascending order (default): each new object dominates and displaces previous ones.
  • descending order: each new object can only occupy the remaining free space left over.

Following illustrations show ascending and descending order, and are post-processed to show the parts aside of each other.

Note: unlike other CSG operations, this returns the same amount of objects as output as it accepted as input, but all objects are altered (this behavior might change in the future, e.g. return a group instead).

Misc Operations


group(obj1, obj2, ...)

You may group parts into a group and translate, scale etc again, a kind of lightweight union() while maintaining their properties.

Note: group() functionality is very experimental and behavior with children() and export of AMF, 3MF and 3MJ formats might change in the future.



where as r, g, and b is float 0..1

HSL color model is closer to human concept of colors:

  • h: hue 0..360 degrees (rainbow)
  • s: saturation 0..1
  • l: lightness 0..1 (0=black, 1= white, 0.5 = average)
for(h=0; h<=1; h+=1/12) { 
   for(s=0; s<=1; s+=1/12) {    



Note: the name of an object is considered when exporting from ScriptCAD, e.g. as STL or 3MJ format, the filename is taken from the name of the object.

% scriptcad -of stl --code "cube().name('my sample')"
scriptcad: writing my_sample.stl [stl]


obj.properties({k1: v1, k2: v2, ... })
properties(obj, { .... })


  • .name(s) is the same as .properties({name: s})
  • .color([r,g,b]) is the same as .properties({color:[r,g,b]})
  • you are free to add any kind of metadata, some export format will carry those on, e.g. 3MF, AMF and 3MJ format will carry them over

Simple Functions

A few simple functions help to port OpenSCAD source code, e.g. OpenSCAD for() statement resembles the forrange() as provided:


forrange([start,end],function(i) { })
forrange([start,step,end], function(i) { })


foreach([a1,a2,a3,...],function(i) { })


ifelse(b, function() { })
ifelse(b, function() { }, function() { })


children(function(c) { })

whenever you have a scene, you may process all objects again using children()


ScriptCAD computes in two stages:

  1. computes scene
    • run the code, and create all 2D and 3D forms
    • object tree is formed
  2. render scene
    • all objects are rendered
      • with triangles to display on WebGL or export to polyhedral forms (STL, OBJ, AMF, 3MF, 3MJ etc)


computeScene() computes the entire scene with all objects, and summarizes all transformations – at this point no vertices or actual geometries exist, only the representations.


renderScene() takes the scene and renders it, in case WebGL or exporting a certain format, then it triangulates all objects in order to display or export.

Important: current implementation of computeScene() calls renderScene().



  • STL ASCII / Binary: most common format, lasting support for slicers
  • OBJ Wavefront: common format, ASCII-based, compact
  • SCCAD ScriptCAD: native intermittent format describing the scene
  • AMF: multi-material/color format, XML-based, fading support for slicers
  • 3MJ: multi-material/color format, JSON-based, optionally compressed with gzip
  • Gcode: visualize 3D printing process with multitool (color) support

Any format which can be imported can also be Drag & Drop into the browser from a file browser.



  • STL ASCII / Binary: most common format, lasting support for slicers
  • OBJ Wavefront: common format, ASCII-based, compact
  • SCCAD ScriptCAD: describing scene as intermittent format
  • SCAD OpenSCAD: to exchange with OpenSCAD, all objects are exported as polyhedron() or polygon() in triangulated form
  • AMF: multi-material/color format, XML-based, fading support for slicers
  • 3MF: multi-material/color format, XML-based, compressed with zip, multiple files, cumbersome specification
  • 3MJ: multi-material/color format, JSON-based, optionally compressed with gzip

Drag & Drop

Any Import Formats can be dragged and dropped from file browser into the inline-editor or 3D platform of your browser, and you edit the source with you preferred editor outside of the browser, and ScriptCAD automatically reloads the source and computes & renders the scene.

Command Line Usage

On the command line you can use scriptcad and it will perform:

  • computeScene() and renderScene()
  • and export to the format you desire

best call scriptcad --help for some basic usage information (those change with new version):

ScriptCAD CLI 0.1.5 USAGE: scriptcad {<options>} [<input-file>]
       -h or --help            print this
       -v or --verbose         increase verbosity
       --version               print version and exit
       -q or --quiet           be quiet (no output)
       -o <fileout>            set output filename
       --output=<fileout>          "             "
       -of <fmt>               fmt: stl, stla, stlb, obj, amf, 3mf, 3mj, sccad, png, gcode (default: stl)
       --unname                unname all solids (enumerate multiple solids)
       --subname               add name to existing export name
       --merge                 merge all top-level solids to one
       --imgsize={w}x{h}       set image size (default: 512x512)
       --lib=<libs>            set libraries (e.g. --lib=./js/extra.js,/lib/sccad/lib.js)
       --function=<name>       set function called (default: main), may include arguments too
       --select=<name>,…       select various solids by name
       --view=<name>           select particular view
       --code                  consider arguments as code

       scriptcad -o test.stl example/sample.sccad
       scriptcad -o test.stl --output-format=stla example/sample.sccad
       scriptcad -o test.png --imgsize=800x600 example/sample.sccad
       scriptcad -o fan_adapter-50-40.stl "--function=fan_adapter({aoff:15})" examples/fan_adapter.sscad
       scriptcad -of stl --code 'cube()'
          writes code.stl
       scriptcad -of stl --code 'cube().name("test")'
          writes test.stl
       scriptcad -of stl --subname --code 'cube().name("test")'
          writes code.test.stl


% scriptcad -o cube.stl cube.sccad
% scriptcad -of stl cube.sscad
% scriptcad -of png --code 'cube(20)'

End of ScriptCAD Reference



Faces + Edges

Back in 2003 I adapted OpenJsCad framework and extended it and documented it properly so it can be used in an easy way and then handed OpenJSCAD.org over to JS devs, who transformed it into the several NPM packages so it becomes usable for 3rd party packages easier.

I realized I wanted to have CAD with strong script capability with the focus on easy use and leave all the NPM package and JavaScript module conformity aside but refocus on easy and powerful 3D scene language, and so I started 2019/01 again, this time from scratch:

  1. Modeling in JavaScript
  2. Hierarchical Scene (computeScene())
  3. Compute Form
    • computeSolid()
      • computeSolidPolygon(): creates polyhedral approximation of solids
      • computeSolidImplicit(): create code for implicit rendering
  4. Rendering (renderScene())
    • polygon: throw triangles into WebGL space (e.g. with threejs)
    • implicit: render using GL shader
  5. Export
    • polygonal:
      • Browser: .stl, .amf, .obj, .3mf, .3mj
      • CLI: .stl, .amf, .obj, .3mf, .3mj, .png


  • true scripting capability like JavaScript (OpenSCAD’s .scad is a reduced language)
  • keep it simple (no NPM module export or alike complexity)
  • CSG capability (union, intersection, difference)
  • name parts and enumerate parts/id
  • parametrical designs (expose certain variables)
  • extrude 2D polygons to another (not just hull)
  • morph from one solid to another
  • simple fillets and chamfers (reduce sharp edges for real world parts)
  • extensive and detailed documentation
  • 100% API backward compatibility (no depreciation)

Few notes how to achieve those:

  • using three.js and ThreeCSG: reliable and well maintained package somewhat, ThreeCSG seems outdated/abandoned; alternatively using csg.js and/or OpenJSCAD packages as fallback, but hiding all the module handling
  • separate creating scene and rendering scene altogether:
    • polygons or rendering triangles are a stage, but not the core of the CAD, but true solids like a (perfect) sphere
    • use WebGL as one backend among others
    • use implict representations alternatives
  • fillets and chamfers: even those look simple, those are hard(er) to do in polygonal/triangulated stage, but simple to do with implicit representation
    • referencing individual edges (using consistent notion)


Visit ScriptCAD.org

  • Chrome/Chromium provides full functionality
  • Firefox lacks marked source code from 3D space or Tree view


  • 3D Forms: cube(), sphere(), cylinder(), polyhedron()
  • 2D Forms: square(), circle(), polygon(): line, lines, closed/open polygon
  • Operations: linear_extrude(), rotate_extrude(), transform(), scale(), rotate(), hull(), mesh()
  • CSG Operations: union(), difference(), intersection(), exclusive()
  • Import: STL (ASCII/Binary), AMF, OBJ, DXF, SCCAD (ScriptCAD), 3MJ
  • Export: STL (ASCII/Binary), AMF, OBJ, 3MF, SCAD (OpenSCAD), SCCAD (ScriptCAD), 3MJ, Gcode, PNG (CLI only)
  • Browser Support: Chrome (fully functional), Firefox (source select missing)


  • 2019/12/27: 0.3.3: experimental export of SCAD (OpenSCAD), 3MF, and SVG (only 2D) added:
  • 2019/12/05: 0.3.0: ScriptCAD.org Reference online, for now hosted on this site
  • 2019/11/25: 0.2.5: ScriptCAD.org launched as preview and a limited ScriptCAD Reference
  • 2019/11/05: 0.2.3: various features implemented, e.g. exclusive(), 3MJ import and export support added.
  • 2019/03/04: 0.1.5: more drawing models, selectable windows, more examples:

Brief overview of features of 0.1.5:

  • 2019/01/18: select Source -> TreeView -> 3D Scene or any stage and respective part is highlighted


I used ScriptCAD to generate paths with certain colors, and visualize it within ScriptCAD Web-GUI, and on the command-line the same code generated actual Gcode for one of my 3D printers, Ashtar K#2 equipped with Diamond Hotend 3-in-1 (mixing colors) – it allowed me to control every detail, something an ordinate slicer would not have provided:

Related Projects