Skip to content

Instantly share code, notes, and snippets.

@evenprimes
Last active April 9, 2026 17:13
Show Gist options
  • Select an option

  • Save evenprimes/f5b3cb9bbef3d5c8c03cc7a74c62b730 to your computer and use it in GitHub Desktop.

Select an option

Save evenprimes/f5b3cb9bbef3d5c8c03cc7a74c62b730 to your computer and use it in GitHub Desktop.
OpenSCAD rendering script
<#
.SYNOPSIS
Export STLs and PNGs of OpenSCAD scripts to the desktop.
.DESCRIPTION
Exports all defined parts from an OpenSCAD script.
Assumptions:
- The OpenSCAD script defines a RENDER_PART variable.
- When RENDER_PART = 0, it echo()s a list of parts with a number and name.
The name will be used as the STL and PNG filename.
RENDER_PART = 1;
if (RENDER_PART == 0)
{
echo("render 1 cube");
echo("render 2 cylinder");
}
if (RENDER_PART == 1) { cube(10); }
if (RENDER_PART == 2) { cylinder(d=10,l=10); }
When rendering all objects, only objects with a number < 1000 will be rendered.
Objects with an ID > 1000 are considered test objects. They can be rendered, but only manually.
.PARAMETER SCADScript
Path of the OpenSCAD script.
.PARAMETER PartNumber (Optional)
Part number to export, if only 1 part is desired.
#>
[CmdletBinding()]
param (
[Parameter(Position = 0, mandatory = $true)]
[ValidateScript({ Test-Path $_ -PathType Leaf })]
[System.IO.FileInfo]
$SCADScript,
# list of parts to print
[Parameter(Position = 1, mandatory = $false, ValueFromRemainingArguments = $true)]
[ValidateRange("Positive")]
[int[]]
$PartNumbers = -1,
# Just list the available parts?
[Parameter()]
[switch]
$List = $false,
# Include PNG outputs?
[Parameter()]
[switch]
$IncludePNG = $false
)
write-debug "Type of SCADScript: $($SCADScript.GetType())"
function Export-SinglePart {
[CmdletBinding()]
param (
[Parameter(Position = 0, mandatory = $true)]
[string]
$SCADScript,
# Which part to export
[Parameter(Position = 1, mandatory = $true)]
[ValidateRange("Positive")]
[int]
$PartNumber,
# Part Name
[Parameter(Position = 2, mandatory = $true)]
[string]
$PartName,
# Parameter help description
[Parameter(Position = 3, Mandatory = $true)]
[bool]
$IncludePNG
)
$dval = "RENDER_PART=$PartNumber"
if (Test-Path -Path $home\Desktop) {
$stl_dest = "$home\Desktop\$($PartName).stl"
}
else {
if (Test-Path -Path $env:OneDrive) {
$stl_dest = "$env:OneDrive\Desktop\$($PartName).stl"
}
else {
$stl_dest = "$($PartName).stl"
}
}
# $stl_dest = "$home\Desktop\$($PartName).stl"
Write-Host -ForegroundColor Cyan "`nRendering $PartName..."
if ($IncludePNG) {
$png_dest = "$home\Desktop\$($PartName).png"
& openscad -D $dval -o $stl_dest -o $png_dest $SCADScript
}
else {
& openscad -D $dval -o $stl_dest $SCADScript
}
}
function Get-PartList {
param (
# Path of the SCAD script we are interrogating
[Parameter()]
[string]
$SCADScript
)
$dval = "RENDER_PART=0"
$PartList = @{}
& openscad -D $dval -o "$temp\scriptlist.stl" $SCADScript |
ForEach-Object {
if ($_ -match '(\d+) (.*)\"') {
$PartList[[int]$Matches.1] = $Matches.2
}
}
return $PartList
}
$PartList = Get-PartList($SCADScript)
if ($List) {
$PartList.Keys | Sort-Object | ForEach-Object {
Write-Host $_, $PartList[$_]
}
Exit
}
if ($PartNumber -eq -1) {
foreach ($Key in $PartList.Keys) {
if ($Key -lt 1000) {
Export-SinglePart -SCADScript $SCADScript -PartNumber $Key -PartName $PartList[$Key] -IncludePNG $IncludePNG
}
}
}
else {
foreach ($PartNumber in $PartNumbers) {
Write-Debug "Working on part number $PartNumber"
if ($PartList.ContainsKey($PartNumber)) {
Export-SinglePart -SCADScript $SCADScript -PartNumber $PartNumber -PartName $PartList[$PartNumber] -IncludePNG $IncludePNG
}
else {
Write-Host "$SCADScript doesn't have part number '$PartNumber', will output based on part number" -ForegroundColor DarkCyan
$ofile = "$(Split-Path -Path $SCADScript -LeafBase)_part-$PartNumber"
Export-SinglePart -SCADScript $SCADScript -PartNumber $PartNumber -PartName $ofile -IncludePNG $IncludePNG
}
}
}
// MARK: Render Control
RENDER_PART = 2;
if (RENDER_PART == 0)
{
echo("render 1 first part");
echo("render 2 second part");
}
if (RENDER_PART == 1)
{
// Render an actual part.
cube([ 10, 10, 10 ]);
}
if (RENDER_PART == 2)
{
// Render another part.
complex_part();
}
if (RENDER_PART == -1)
{
// Render a test part, but only during development.
// -1 isn't in the list of renderable parts for the script.
subpart1();
}
// Start designs in modules here.
module complex_part()
{
union()
{
subpart1();
subpart2();
}
}
module subpart1() { cube([ 50, 50, 50 ], center = true); }
module subpart2() { translate([ 0, 0, 25 ]) cylinder(h = 50, r = 25); }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment