pre-bemis
This commit is contained in:
50
rpi-case/.claude/skills/openscad/tools/common.sh
Executable file
50
rpi-case/.claude/skills/openscad/tools/common.sh
Executable file
@@ -0,0 +1,50 @@
|
||||
#!/bin/bash
|
||||
# Common utilities for OpenSCAD tools
|
||||
|
||||
# Find OpenSCAD executable
|
||||
find_openscad() {
|
||||
# Check common locations
|
||||
if command -v openscad &> /dev/null; then
|
||||
echo "openscad"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# macOS Application bundle
|
||||
if [ -d "/Applications/OpenSCAD.app" ]; then
|
||||
echo "/Applications/OpenSCAD.app/Contents/MacOS/OpenSCAD"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Homebrew on Apple Silicon
|
||||
if [ -x "/opt/homebrew/bin/openscad" ]; then
|
||||
echo "/opt/homebrew/bin/openscad"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Homebrew on Intel
|
||||
if [ -x "/usr/local/bin/openscad" ]; then
|
||||
echo "/usr/local/bin/openscad"
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Check if OpenSCAD is available
|
||||
check_openscad() {
|
||||
OPENSCAD=$(find_openscad) || {
|
||||
echo "Error: OpenSCAD not found!"
|
||||
echo ""
|
||||
echo "Install OpenSCAD using one of:"
|
||||
echo " brew install openscad"
|
||||
echo " Download from https://openscad.org/downloads.html"
|
||||
exit 1
|
||||
}
|
||||
export OPENSCAD
|
||||
}
|
||||
|
||||
# Get version info
|
||||
openscad_version() {
|
||||
check_openscad
|
||||
$OPENSCAD --version 2>&1
|
||||
}
|
||||
56
rpi-case/.claude/skills/openscad/tools/export-stl.sh
Executable file
56
rpi-case/.claude/skills/openscad/tools/export-stl.sh
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/bin/bash
|
||||
# Export OpenSCAD file to STL
|
||||
# Usage: export-stl.sh input.scad output.stl [-D 'var=value' ...]
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
source "$SCRIPT_DIR/common.sh"
|
||||
|
||||
check_openscad
|
||||
|
||||
if [ $# -lt 2 ]; then
|
||||
echo "Usage: $0 input.scad output.stl [-D 'var=value' ...]"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 box.scad box.stl"
|
||||
echo " $0 box.scad box_large.stl -D 'width=80' -D 'height=60'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
INPUT="$1"
|
||||
OUTPUT="$2"
|
||||
shift 2
|
||||
|
||||
# Collect -D parameters
|
||||
DEFINES=()
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
-D)
|
||||
shift
|
||||
DEFINES+=("-D" "$1")
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# Ensure output directory exists
|
||||
mkdir -p "$(dirname "$OUTPUT")"
|
||||
|
||||
echo "Exporting STL: $INPUT -> $OUTPUT"
|
||||
if [ ${#DEFINES[@]} -gt 0 ]; then
|
||||
echo "Parameters: ${DEFINES[*]}"
|
||||
fi
|
||||
|
||||
$OPENSCAD \
|
||||
"${DEFINES[@]}" \
|
||||
-o "$OUTPUT" \
|
||||
"$INPUT"
|
||||
|
||||
# Show file info
|
||||
SIZE=$(ls -lh "$OUTPUT" | awk '{print $5}')
|
||||
echo "STL exported: $OUTPUT ($SIZE)"
|
||||
147
rpi-case/.claude/skills/openscad/tools/extract-params.sh
Executable file
147
rpi-case/.claude/skills/openscad/tools/extract-params.sh
Executable file
@@ -0,0 +1,147 @@
|
||||
#!/bin/bash
|
||||
# Extract customizable parameters from an OpenSCAD file
|
||||
# Usage: extract-params.sh input.scad [--json]
|
||||
#
|
||||
# Parses parameter declarations with special comments:
|
||||
# param = value; // [min:max] Description
|
||||
# param = value; // [min:step:max] Description
|
||||
# param = value; // [opt1, opt2] Description
|
||||
# param = value; // Description only
|
||||
|
||||
set -e
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "Usage: $0 input.scad [--json]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
INPUT="$1"
|
||||
JSON_OUTPUT=false
|
||||
|
||||
if [ "$2" = "--json" ]; then
|
||||
JSON_OUTPUT=true
|
||||
fi
|
||||
|
||||
if [ ! -f "$INPUT" ]; then
|
||||
echo "Error: File not found: $INPUT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract parameters using Python for better parsing
|
||||
extract_params() {
|
||||
python3 -c '
|
||||
import sys
|
||||
import re
|
||||
|
||||
filename = sys.argv[1]
|
||||
in_block = 0
|
||||
|
||||
with open(filename, "r") as f:
|
||||
for line in f:
|
||||
# Track block depth (skip params inside modules/functions)
|
||||
in_block += line.count("{") - line.count("}")
|
||||
if in_block > 0:
|
||||
continue
|
||||
|
||||
# Match: varname = value; // comment
|
||||
match = re.match(r"^\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*([^;]+);\s*(?://\s*(.*))?", line)
|
||||
if not match:
|
||||
continue
|
||||
|
||||
var_name = match.group(1)
|
||||
value = match.group(2).strip()
|
||||
comment = match.group(3) or ""
|
||||
|
||||
# Determine type
|
||||
if value in ("true", "false"):
|
||||
var_type = "boolean"
|
||||
elif re.match(r"^-?\d+$", value):
|
||||
var_type = "integer"
|
||||
elif re.match(r"^-?\d*\.?\d+$", value):
|
||||
var_type = "number"
|
||||
elif value.startswith("\"") and value.endswith("\""):
|
||||
var_type = "string"
|
||||
value = value[1:-1] # Remove quotes
|
||||
elif value.startswith("["):
|
||||
var_type = "array"
|
||||
else:
|
||||
var_type = "expression"
|
||||
|
||||
# Parse comment for range/options
|
||||
range_val = ""
|
||||
options_val = ""
|
||||
description = comment
|
||||
|
||||
range_match = re.match(r"\[([^\]]+)\]\s*(.*)", comment)
|
||||
if range_match:
|
||||
bracket_content = range_match.group(1)
|
||||
description = range_match.group(2)
|
||||
|
||||
# Check if numeric range (contains :) or options (contains ,)
|
||||
if ":" in bracket_content and not "," in bracket_content:
|
||||
range_val = bracket_content
|
||||
else:
|
||||
options_val = bracket_content
|
||||
|
||||
# Output pipe-delimited
|
||||
print(f"{var_name}|{value}|{var_type}|{range_val}|{options_val}|{description}")
|
||||
' "$INPUT"
|
||||
}
|
||||
|
||||
if [ "$JSON_OUTPUT" = true ]; then
|
||||
echo "["
|
||||
first=true
|
||||
while IFS='|' read -r name value type range options description; do
|
||||
if [ "$first" = true ]; then
|
||||
first=false
|
||||
else
|
||||
echo ","
|
||||
fi
|
||||
|
||||
# Escape quotes in values
|
||||
value=$(echo "$value" | sed 's/"/\\"/g')
|
||||
description=$(echo "$description" | sed 's/"/\\"/g')
|
||||
|
||||
# Build JSON object
|
||||
printf ' {\n'
|
||||
printf ' "name": "%s",\n' "$name"
|
||||
printf ' "value": "%s",\n' "$value"
|
||||
printf ' "type": "%s"' "$type"
|
||||
|
||||
if [ -n "$range" ]; then
|
||||
printf ',\n "range": "%s"' "$range"
|
||||
fi
|
||||
if [ -n "$options" ]; then
|
||||
printf ',\n "options": "%s"' "$options"
|
||||
fi
|
||||
if [ -n "$description" ]; then
|
||||
printf ',\n "description": "%s"' "$description"
|
||||
fi
|
||||
printf '\n }'
|
||||
done < <(extract_params)
|
||||
echo ""
|
||||
echo "]"
|
||||
else
|
||||
echo "Parameters in: $INPUT"
|
||||
echo "==============================================="
|
||||
printf "%-20s %-15s %-10s %s\n" "NAME" "VALUE" "TYPE" "CONSTRAINT/DESC"
|
||||
echo "-----------------------------------------------"
|
||||
|
||||
while IFS='|' read -r name value type range options description; do
|
||||
constraint=""
|
||||
if [ -n "$range" ]; then
|
||||
constraint="[$range]"
|
||||
elif [ -n "$options" ]; then
|
||||
constraint="[$options]"
|
||||
fi
|
||||
if [ -n "$description" ]; then
|
||||
if [ -n "$constraint" ]; then
|
||||
constraint="$constraint $description"
|
||||
else
|
||||
constraint="$description"
|
||||
fi
|
||||
fi
|
||||
|
||||
printf "%-20s %-15s %-10s %s\n" "$name" "$value" "$type" "$constraint"
|
||||
done < <(extract_params)
|
||||
fi
|
||||
68
rpi-case/.claude/skills/openscad/tools/multi-preview.sh
Executable file
68
rpi-case/.claude/skills/openscad/tools/multi-preview.sh
Executable file
@@ -0,0 +1,68 @@
|
||||
#!/bin/bash
|
||||
# Generate preview images from multiple angles
|
||||
# Usage: multi-preview.sh input.scad output_dir/ [-D 'var=value']
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
source "$SCRIPT_DIR/common.sh"
|
||||
|
||||
check_openscad
|
||||
|
||||
if [ $# -lt 2 ]; then
|
||||
echo "Usage: $0 input.scad output_dir/ [-D 'var=value' ...]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
INPUT="$1"
|
||||
OUTPUT_DIR="$2"
|
||||
shift 2
|
||||
|
||||
# Collect -D parameters
|
||||
DEFINES=()
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
-D)
|
||||
shift
|
||||
DEFINES+=("-D" "$1")
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
|
||||
# Get base name without extension
|
||||
BASENAME=$(basename "$INPUT" .scad)
|
||||
|
||||
echo "Generating multi-angle previews for: $INPUT"
|
||||
echo "Output directory: $OUTPUT_DIR"
|
||||
echo ""
|
||||
|
||||
# Define angles as name:camera pairs
|
||||
# Camera format: translate_x,translate_y,translate_z,rot_x,rot_y,rot_z,distance
|
||||
ANGLES="iso:0,0,0,55,0,25,0
|
||||
front:0,0,0,90,0,0,0
|
||||
back:0,0,0,90,0,180,0
|
||||
left:0,0,0,90,0,90,0
|
||||
right:0,0,0,90,0,-90,0
|
||||
top:0,0,0,0,0,0,0"
|
||||
|
||||
echo "$ANGLES" | while IFS=: read -r angle camera; do
|
||||
output="$OUTPUT_DIR/${BASENAME}_${angle}.png"
|
||||
|
||||
echo " Rendering $angle view..."
|
||||
$OPENSCAD \
|
||||
--camera="$camera" \
|
||||
--imgsize="800,600" \
|
||||
--colorscheme="Tomorrow Night" \
|
||||
--autocenter \
|
||||
--viewall \
|
||||
"${DEFINES[@]}" \
|
||||
-o "$output" \
|
||||
"$INPUT" 2>/dev/null
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Generated previews:"
|
||||
ls -la "$OUTPUT_DIR"/${BASENAME}_*.png
|
||||
74
rpi-case/.claude/skills/openscad/tools/preview.sh
Executable file
74
rpi-case/.claude/skills/openscad/tools/preview.sh
Executable file
@@ -0,0 +1,74 @@
|
||||
#!/bin/bash
|
||||
# Generate a preview PNG from an OpenSCAD file
|
||||
# Usage: preview.sh input.scad output.png [options]
|
||||
#
|
||||
# Options:
|
||||
# --camera=x,y,z,rx,ry,rz,dist Camera position
|
||||
# --size=WxH Image size (default: 800x600)
|
||||
# -D 'var=value' Set parameter value
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
source "$SCRIPT_DIR/common.sh"
|
||||
|
||||
check_openscad
|
||||
|
||||
if [ $# -lt 2 ]; then
|
||||
echo "Usage: $0 input.scad output.png [--camera=...] [--size=WxH] [-D 'var=val']"
|
||||
echo ""
|
||||
echo "Camera format: x,y,z,rotx,roty,rotz,distance"
|
||||
echo "Common cameras:"
|
||||
echo " Isometric: --camera=0,0,0,55,0,25,200"
|
||||
echo " Front: --camera=0,0,0,90,0,0,200"
|
||||
echo " Top: --camera=0,0,0,0,0,0,200"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
INPUT="$1"
|
||||
OUTPUT="$2"
|
||||
shift 2
|
||||
|
||||
# Defaults
|
||||
CAMERA="0,0,0,55,0,25,0"
|
||||
SIZE="800,600"
|
||||
DEFINES=()
|
||||
|
||||
# Parse options
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--camera=*)
|
||||
CAMERA="${1#--camera=}"
|
||||
;;
|
||||
--size=*)
|
||||
SIZE="${1#--size=}"
|
||||
SIZE="${SIZE/x/,}"
|
||||
;;
|
||||
-D)
|
||||
shift
|
||||
DEFINES+=("-D" "$1")
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# Ensure output directory exists
|
||||
mkdir -p "$(dirname "$OUTPUT")"
|
||||
|
||||
# Run OpenSCAD
|
||||
echo "Rendering preview: $INPUT -> $OUTPUT"
|
||||
$OPENSCAD \
|
||||
--camera="$CAMERA" \
|
||||
--imgsize="${SIZE}" \
|
||||
--colorscheme="Tomorrow Night" \
|
||||
--autocenter \
|
||||
--viewall \
|
||||
"${DEFINES[@]}" \
|
||||
-o "$OUTPUT" \
|
||||
"$INPUT"
|
||||
|
||||
echo "Preview saved to: $OUTPUT"
|
||||
91
rpi-case/.claude/skills/openscad/tools/render-with-params.sh
Executable file
91
rpi-case/.claude/skills/openscad/tools/render-with-params.sh
Executable file
@@ -0,0 +1,91 @@
|
||||
#!/bin/bash
|
||||
# Render OpenSCAD with parameters from a JSON file
|
||||
# Usage: render-with-params.sh input.scad params.json output.stl|output.png
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
source "$SCRIPT_DIR/common.sh"
|
||||
|
||||
check_openscad
|
||||
|
||||
if [ $# -lt 3 ]; then
|
||||
echo "Usage: $0 input.scad params.json output.[stl|png]"
|
||||
echo ""
|
||||
echo "params.json format:"
|
||||
echo ' {"width": 60, "height": 40, "include_lid": true}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
INPUT="$1"
|
||||
PARAMS_FILE="$2"
|
||||
OUTPUT="$3"
|
||||
|
||||
if [ ! -f "$INPUT" ]; then
|
||||
echo "Error: Input file not found: $INPUT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$PARAMS_FILE" ]; then
|
||||
echo "Error: Params file not found: $PARAMS_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Build -D arguments from JSON
|
||||
DEFINES=()
|
||||
while IFS= read -r line; do
|
||||
# Parse each key-value pair
|
||||
key=$(echo "$line" | cut -d'=' -f1)
|
||||
value=$(echo "$line" | cut -d'=' -f2-)
|
||||
|
||||
if [ -n "$key" ]; then
|
||||
DEFINES+=("-D" "$key=$value")
|
||||
fi
|
||||
done < <(
|
||||
# Use python or jq to parse JSON to key=value lines
|
||||
if command -v python3 &> /dev/null; then
|
||||
python3 -c "
|
||||
import json
|
||||
with open('$PARAMS_FILE') as f:
|
||||
params = json.load(f)
|
||||
for k, v in params.items():
|
||||
if isinstance(v, bool):
|
||||
print(f'{k}={str(v).lower()}')
|
||||
elif isinstance(v, str):
|
||||
print(f'{k}=\"{v}\"')
|
||||
else:
|
||||
print(f'{k}={v}')
|
||||
"
|
||||
elif command -v jq &> /dev/null; then
|
||||
jq -r 'to_entries | .[] | "\(.key)=\(.value)"' "$PARAMS_FILE"
|
||||
else
|
||||
echo "Error: Requires python3 or jq to parse JSON"
|
||||
exit 1
|
||||
fi
|
||||
)
|
||||
|
||||
echo "Rendering with parameters from: $PARAMS_FILE"
|
||||
echo "Parameters: ${DEFINES[*]}"
|
||||
|
||||
# Determine output type and set appropriate options
|
||||
EXT="${OUTPUT##*.}"
|
||||
case "$EXT" in
|
||||
stl|STL)
|
||||
$OPENSCAD "${DEFINES[@]}" -o "$OUTPUT" "$INPUT"
|
||||
;;
|
||||
png|PNG)
|
||||
$OPENSCAD "${DEFINES[@]}" \
|
||||
--camera="0,0,0,55,0,25,0" \
|
||||
--imgsize="800,600" \
|
||||
--colorscheme="Tomorrow Night" \
|
||||
--autocenter --viewall \
|
||||
-o "$OUTPUT" "$INPUT"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported output format: $EXT"
|
||||
echo "Supported: stl, png"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Output saved: $OUTPUT"
|
||||
46
rpi-case/.claude/skills/openscad/tools/validate.sh
Executable file
46
rpi-case/.claude/skills/openscad/tools/validate.sh
Executable file
@@ -0,0 +1,46 @@
|
||||
#!/bin/bash
|
||||
# Validate an OpenSCAD file for syntax errors
|
||||
# Usage: validate.sh input.scad
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
source "$SCRIPT_DIR/common.sh"
|
||||
|
||||
check_openscad
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "Usage: $0 input.scad"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
INPUT="$1"
|
||||
|
||||
if [ ! -f "$INPUT" ]; then
|
||||
echo "Error: File not found: $INPUT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Validating: $INPUT"
|
||||
|
||||
# Create temp file for output
|
||||
TEMP_OUTPUT=$(mktemp /tmp/openscad_validate.XXXXXX.echo)
|
||||
trap "rm -f $TEMP_OUTPUT" EXIT
|
||||
|
||||
# Run OpenSCAD with echo output (fastest way to check syntax)
|
||||
# Using --export-format=echo just parses and evaluates without rendering
|
||||
if $OPENSCAD -o "$TEMP_OUTPUT" --export-format=echo "$INPUT" 2>&1; then
|
||||
echo "✓ Syntax OK"
|
||||
|
||||
# Check for warnings in stderr
|
||||
if [ -s "$TEMP_OUTPUT" ]; then
|
||||
echo ""
|
||||
echo "Echo output:"
|
||||
cat "$TEMP_OUTPUT"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
else
|
||||
echo "✗ Validation failed"
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user