UP | HOME

Support via Liberapay

OpenSCAD Code Blocks in Org mode

Org Mode support for OpenSCAD

Introduction

OpenSCAD is a solid 3D CAD modeler that uses a scripting language to create 3D models. Its programmatic nature makes it particularly well-suited for integration with Org mode through Babel source code blocks. This integration allows you to:

  • Embed 3D model definitions directly within your Org documents
  • Generate and preview models without leaving your editing environment
  • Capture OpenSCAD console output for debugging and documentation
  • Create parameterized designs using Org mode variables
  • Maintain complete design documentation alongside the CAD code
  • Export models in various formats (images or cad files) for visualization or use in other applications

Unlike interactive CAD tools, OpenSCAD focuses on precision and parametric design, making it ideal for technical parts, mathematical models, and 3D-printable objects. When combined with Org mode, it becomes a powerful tool for creating reproducible, well-documented CAD workflows.

Requirements and Setup

Installing OpenSCAD

To use OpenSCAD source blocks in Org mode, you must first have the OpenSCAD program itself installed on your system.

Official installers, packages, and detailed instructions are available for all major operating systems on the OpenSCAD downloads page.

  • Linux: Available in most distribution repositories (e.g., sudo apt install openscad).
  • macOS: Available via Homebrew (brew install openscad) or direct download.
  • Windows: Available via WinGet (winget install -e OpenSCAD.OpenSCAD) or direct download.

Installing scad-mode in Emacs

The scad-mode package, available on MELPA, provides syntax highlighting for .scad files and Org Babel support.

  1. Ensure MELPA is in your package archives.
  2. Install the package:
    • M-x package-install RET scad-mode RET.
    • Or within your configuration using for instance use-package.

Emacs Configuration

Add OpenSCAD support to your Babel languages:

(org-babel-do-load-languages
 'org-babel-load-languages
 '((scad . t)))

;; Optional: Set OpenSCAD executable path if not in system PATH
(setq org-babel-openscad-command "openscad")

Org Mode Features for OpenSCAD Source Code Blocks

Header Arguments

OpenSCAD code blocks support several header arguments that map to OpenSCAD command-line options and rendering parameters:

Core Babel Headers

  • :results - Defaults to file when the :file header is specified
  • :exports - Control what gets exported (code, results, both, none)
  • :file - Required for generating any output (image or model file)
  • :cmdline - Additional command-line arguments for OpenSCAD
  • :var - Pass variables from other code blocks to parameterize designs

OpenSCAD-Specific Rendering Headers

  • :colorscheme - Color scheme for rendering (e.g., Cornfield, Sunset, Metallic, Starnight)
  • :projection - Projection type: ortho (orthographic) or perspective
  • :camera - Camera position and orientation as transx,transy,transz,rotx,roty,rotz,dist
  • :view - View mode: axes, scales, edges, or plain (no overlays)
  • :size - Render size as width,height in pixels (e.g., 300,300)
  • :imgsize - Alternative size parameter width,height

Sessions

OpenSCAD does not support persistent sessions in the traditional Babel sense, as each code block execution starts a new OpenSCAD process. However, you can use Org mode variables to maintain parameter consistency across blocks.

Result Types

OpenSCAD produces model files (STL, OFF, AMF, 3MF, CSG), 2D export files (DXF, SVG), and image files (PNG) via the :file header argument. Debug output formats (AST, TERM, NEF3, NEFDBG) are also supported.

Differences from Other Supported Languages

Console output from OpenSCAD's echo() function, warnings, and errors is not directly captured by Babel. To capture this output, use the shell wrapper method described in the console section.

Examples of Use

Basic 3D Model Generation

Create a simple cube and export it as a PNG image:

#+NAME: basic-sphere
#+CAPTION: A simple sphere generated with OpenSCAD
#+HEADER: :file ./images/basic-sphere.png
#+HEADER: :colorscheme Cornfield
#+HEADER: :size 300,300
#+begin_src scad :exports results
  diameter = 10;

  color("Cornfield", 0.5) sphere(s=diameter, $fn=36);
#+end_src
basic-sphere.png

Primitive 2D shapes

When working with 2D geometries in OpenSCAD, using orthographic projection with a top-down camera view provides an accurate, undistorted representation of dimensions. This is particularly important for 2D shapes where precise measurements matter.

#+NAME: square-circle
#+CAPTION: Some 2D primitives
#+HEADER: :file ./images/some-2d-primitives.png
#+HEADER: :colorscheme Cornfield
#+HEADER: :projection ortho
#+HEADER: :camera 0,0,0,0,0,0,0
#+HEADER: :size 300,300
#+begin_src scad :exports both
  side=20; radius=10; offset=12.5;
  module place_in_quadrant(quadrant) {
    x = (quadrant==1 || quadrant==4 ? 1 : -1) * offset;
    y = (quadrant==1 || quadrant==2 ? 1 : -1) * offset;
    translate([x, y]) children(0);
  }
  place_in_quadrant(1) square(side, center=true);
  place_in_quadrant(2) circle(radius, $fn=30);
  place_in_quadrant(3) circle(radius, $fn=5);
  place_in_quadrant(4) circle(radius, $fn=6);
#+end_src
some-2d-primitives.png

The :camera header supports two different camera modes in OpenSCAD, each with its own parameter format:

  • Gimbal Camera uses the format: transx,transy,transz,rotx,roty,rotz,distance, where:
    • transx,transy,transz - Translation (movement) of the object in X, Y, Z directions
    • rotx,roty,rotz - Rotation around X, Y, Z axes in degrees
    • distance - Distance between camera and object center
  • Vector Camera uses the format: eyex,eyey,eyez,centerx,centery,centerz, where:
    • eyex,eyey,eyez - Eye (camera) position coordinates
    • centerx,centery,centerz - Center (target) position coordinates

Organizing Code with Noweb References

Org mode's noweb syntax allows you to break complex designs into reusable components and share parameters across multiple code blocks.

Define a Reusable Module

Store the box geometry as a reusable module:

#+NAME: box-module
#+begin_src scad :exports code :results none
  module box(w, l, h, t) {
    difference() {
      cube([w, l, h], center=true);
      translate([0, 0, t])
        cube([w-2*t, l-2*t, h], center=true);
    }
  }
#+end_src

Define Shared Parameters

Store design parameters in a separate block for easy modification:

#+NAME: box-params
#+begin_src scad :exports code :results none
  width = 30;
  length = 20;
  height = 10;
  thickness = 2;
#+end_src

Combine Components with Noweb

Use <<block-name>> syntax to include code from other blocks:

#+NAME: parametric-box
#+CAPTION: Combining modules and parameters with noweb references
#+HEADER: :file ./images/parametric-box.png
#+HEADER: :colorscheme Cornfield
#+HEADER: :projection ortho
#+HEADER: :size 300,300
#+begin_src scad :exports both :noweb yes
  <<box-module>>
  <<box-params>>

  // Build the box
  box(width, length, height, thickness);
  // These echos will NOT appear in results
  echo("width, length, height, thickness: ", width, length, height, thickness);
  echo(version=version());
#+end_src
parametric-box.png

The echo() statements are processed by OpenSCAD but not captured by org-babel.

capturing OpenSCAD Console Output

Unlike some babel languages, OpenSCAD does not directly support console output capture through the :results output header argument. However, you can capture OpenSCAD's console output (including echo() statements) by wrapping the OpenSCAD execution in a shell code block.

Capturing All Console Output Types

#+NAME: parametric-box-full-output
#+CAPTION: Complete output including debug messages and render statistics
#+begin_src shell :results output :exports both :noweb yes :wrap results
  output=$(openscad -o /dev/null --export-format asciistl - <<'EOF' 2>&1
  <<parametric-box>>
  EOF
  )

  echo "=== Debug Information ==="
  echo "$output" | grep -i echo

  echo
  echo "=== Render Statistics ==="
  echo "$output" | grep -v -i echo
#+end_src
#+RESULTS: parametric-box-full-output
#+begin_results
=== Debug Information ===
ECHO: "width, length, height, thickness: ", 30, 20, 10, 2
ECHO: version = [2021, 1, 0]

=== Render Statistics ===
Geometries in cache: 3
Geometry cache size in bytes: 2184
CGAL Polyhedrons in cache: 1
CGAL cache size in bytes: 23888
Total rendering time: 0:00:00.018
   Top level object is a 3D object:
   Simple:        yes
   Vertices:       16
   Halfedges:      48
   Edges:          24
   Halffacets:     22
   Facets:         11
   Volumes:         2
#+end_results

Explanation

  • The shell code block uses openscad -o /dev/null to discard the .stl output
  • --export-format asciistl ensures OpenSCAD processes the file
  • 2>&1 redirects both stdout and stderr to capture all output
  • echo() statements in OpenSCAD are captured as "ECHO:" lines
  • The exit code shows whether the OpenSCAD code compiled successfully

OpenSCAD Title Logo

This example demonstrates how to generate an image using an OpenSCAD code block and place the resulting image anywhere in your Org document using the #+RESULTS: directive. In this case, the logo is generated and displayed at the top of the page as the title logo.

#+NAME: OpenSCAD logo
#+CAPTION: OpenSCAD logo
#+HEADER: :file  ./images/openscad-logo.png
#+HEADER: :colorscheme Cornfield
#+HEADER: :projection ortho
#+HEADER: :camera 0,0,0,60,0,45,0
#+HEADER: :view none
#+HEADER: :size 300,300
#+begin_src scad :export results :result output
  Logo();

  module Logo(size=50, $fn=100) {
      hole = size/2;
      cylinderHeight = size * 1.25;

      difference() {
          sphere(d=size);
          cylinder(d=hole, h=cylinderHeight, center=true);
          #rotate([90, 0, 0]) cylinder(d=hole, h=cylinderHeight, center=true);
          rotate([0, 90, 0]) cylinder(d=hole, h=cylinderHeight, center=true);
      }
  }
#+end_src
#+RESULTS: OpenSCAD logo
[[file:./images/openscad-logo.png]]

See the OpenSCAD banner at the top of the page, generated by the code block above. View the original source code.

Troubleshooting

OpenSCAD Not Found

If you encounter errors like openscad: command not found, ensure OpenSCAD is installed and the path is set correctly in your Emacs Configuration using the org-babel-openscad-command variable.

Syntax Errors

OpenSCAD is strict about syntax. Use the console output capture method to debug errors (see console section).

Performance Issues

Complex models may render slowly. Simplify designs, reduce $fn values, or use smaller :size values (e.g., :size 200,200) for faster previews.

Additional Resources

Documentation from the orgmode.org/worg/ website (either in its HTML format or in its Org format) is licensed under the GNU Free Documentation License version 1.3 or later. The code examples and css stylesheets are licensed under the GNU General Public License v3 or later.