tau-all-agent 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +45 -0
- package/extensions/answer.ts +601 -0
- package/extensions/branch-term.ts +405 -0
- package/extensions/btw.ts +444 -0
- package/extensions/ghostty.ts +301 -0
- package/extensions/git-diff-stats.ts +277 -0
- package/extensions/git-pr-status.ts +286 -0
- package/extensions/insights.ts +2367 -0
- package/extensions/interlude.ts +144 -0
- package/extensions/loop.ts +529 -0
- package/extensions/memory.ts +1889 -0
- package/extensions/notify.ts +161 -0
- package/extensions/openai-fast.ts +227 -0
- package/extensions/openai-verbosity.ts +223 -0
- package/extensions/review.ts +4347 -0
- package/extensions/sandbox/index.ts +2578 -0
- package/extensions/telegram/README.md +81 -0
- package/extensions/telegram/daemon.mjs +1942 -0
- package/extensions/telegram/index.ts +1073 -0
- package/extensions/telegram/message-text.d.mts +1 -0
- package/extensions/telegram/message-text.mjs +16 -0
- package/extensions/usage/anthropic.ts +198 -0
- package/extensions/usage/github-copilot.ts +204 -0
- package/extensions/usage/google-gemini-cli.ts +232 -0
- package/extensions/usage/index.ts +2310 -0
- package/extensions/usage/minimax.ts +208 -0
- package/extensions/usage/openai-codex.ts +180 -0
- package/extensions/usage/openrouter.ts +168 -0
- package/extensions/usage/providers.ts +26 -0
- package/extensions/usage/shared.ts +156 -0
- package/extensions/usage/types.ts +53 -0
- package/extensions/usage/zai.ts +186 -0
- package/extensions/websearch/README.md +68 -0
- package/extensions/websearch/browser/chromium.ts +330 -0
- package/extensions/websearch/browser/discovery.ts +75 -0
- package/extensions/websearch/browser/firefox.ts +150 -0
- package/extensions/websearch/browser/sqlite.ts +38 -0
- package/extensions/websearch/config.ts +76 -0
- package/extensions/websearch/index.ts +312 -0
- package/extensions/websearch/normalize.ts +155 -0
- package/extensions/websearch/providers/anthropic.pi.ts +139 -0
- package/extensions/websearch/providers/gemini.browser.ts +185 -0
- package/extensions/websearch/providers/gemini.pi.ts +108 -0
- package/extensions/websearch/providers/openai-codex.browser.ts +77 -0
- package/extensions/websearch/providers/openai-codex.pi.ts +49 -0
- package/extensions/websearch/providers/openai-codex.shared.ts +123 -0
- package/extensions/websearch/providers/pi-model.shared.ts +86 -0
- package/extensions/websearch/providers/search-prompt.shared.ts +17 -0
- package/extensions/websearch/providers/shared.ts +76 -0
- package/extensions/websearch/types.ts +52 -0
- package/extensions/worktree.ts +2223 -0
- package/package.json +76 -0
- package/skills/browser-tools/SKILL.md +253 -0
- package/skills/browser-tools/scripts/browser-content.js +100 -0
- package/skills/browser-tools/scripts/browser-cookies.js +33 -0
- package/skills/browser-tools/scripts/browser-dismiss-cookies.js +455 -0
- package/skills/browser-tools/scripts/browser-eval.js +75 -0
- package/skills/browser-tools/scripts/browser-logs-tail.js +89 -0
- package/skills/browser-tools/scripts/browser-nav.js +28 -0
- package/skills/browser-tools/scripts/browser-net-summary.js +115 -0
- package/skills/browser-tools/scripts/browser-pick.js +133 -0
- package/skills/browser-tools/scripts/browser-screenshot.js +18 -0
- package/skills/browser-tools/scripts/browser-start.js +281 -0
- package/skills/browser-tools/scripts/browser-watch.js +321 -0
- package/skills/browser-tools/scripts/utils.js +60 -0
- package/skills/git-clean-history/SKILL.md +45 -0
- package/skills/git-commit/SKILL.md +55 -0
- package/skills/homeassistant-ops/SKILL.md +184 -0
- package/skills/homeassistant-ops/references/api.md +64 -0
- package/skills/homeassistant-ops/references/id_conventions.md +71 -0
- package/skills/homeassistant-ops/references/playbook.md +150 -0
- package/skills/homeassistant-ops/scripts/ha_ops.js +2942 -0
- package/skills/openscad/SKILL.md +149 -0
- package/skills/openscad/examples/parametric_box.scad +92 -0
- package/skills/openscad/examples/phone_stand.scad +95 -0
- package/skills/openscad/scripts/common.sh +49 -0
- package/skills/openscad/scripts/export-stl.sh +56 -0
- package/skills/openscad/scripts/extract-params.sh +147 -0
- package/skills/openscad/scripts/multi-preview.sh +68 -0
- package/skills/openscad/scripts/preview.sh +74 -0
- package/skills/openscad/scripts/render-with-params.sh +91 -0
- package/skills/openscad/scripts/validate.sh +46 -0
- package/skills/oracle/SKILL.md +64 -0
- package/skills/oracle/scripts/oracle +249 -0
- package/skills/oracle/scripts/oracle-bundle +227 -0
- package/skills/sentry/SKILL.md +198 -0
- package/skills/sentry/lib/auth.js +99 -0
- package/skills/sentry/scripts/fetch-event.js +325 -0
- package/skills/sentry/scripts/fetch-issue.js +368 -0
- package/skills/sentry/scripts/list-issues.js +245 -0
- package/skills/sentry/scripts/search-events.js +291 -0
- package/skills/sentry/scripts/search-logs.js +234 -0
- package/skills/update-changelog/SKILL.md +135 -0
- package/skills/web-design/SKILL.md +117 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: openscad
|
|
3
|
+
description: "Create and render OpenSCAD 3D models. Generate preview images from multiple angles, extract customizable parameters, validate syntax, and export STL files for 3D printing platforms like Printables."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# OpenSCAD
|
|
7
|
+
|
|
8
|
+
Create, validate, visually verify, and export OpenSCAD 3D models.
|
|
9
|
+
|
|
10
|
+
## Requirements
|
|
11
|
+
|
|
12
|
+
The `openscad` executable is available on `PATH` (or discoverable in common locations like `/Applications/OpenSCAD.app` on macOS).
|
|
13
|
+
|
|
14
|
+
## Scripts
|
|
15
|
+
|
|
16
|
+
This skill ships helper scripts under `scripts/`. Run the commands below from this skill directory.
|
|
17
|
+
|
|
18
|
+
### Preview generation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Generate a single preview image
|
|
22
|
+
"./scripts/preview.sh" model.scad output.png \
|
|
23
|
+
[--camera=x,y,z,rotx,roty,rotz,distance] [--size=800x600]
|
|
24
|
+
|
|
25
|
+
# Generate multi-angle previews (front, back, left, right, top, iso)
|
|
26
|
+
"./scripts/multi-preview.sh" model.scad output_dir/
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### STL export
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
"./scripts/export-stl.sh" model.scad output.stl [-D 'param=value']
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Parameter extraction
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
"./scripts/extract-params.sh" model.scad
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Validation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
"./scripts/validate.sh" model.scad
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Render with params from JSON
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
"./scripts/render-with-params.sh" model.scad params.json output.stl
|
|
51
|
+
"./scripts/render-with-params.sh" model.scad params.json output.png
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Visual validation
|
|
55
|
+
|
|
56
|
+
Always validate models visually after creating or modifying them:
|
|
57
|
+
|
|
58
|
+
1. Generate multi-angle previews.
|
|
59
|
+
2. View _each_ generated image with the agent's image viewer (in this environment: the `read` tool).
|
|
60
|
+
3. Check geometry from multiple perspectives (front/back/left/right/top/iso).
|
|
61
|
+
4. Iterate until the renders match the intent.
|
|
62
|
+
|
|
63
|
+
Syntax validation alone will not catch common geometry problems (misaligned booleans, missing/floating geometry, inverted geometry, z-fighting, wrong proportions).
|
|
64
|
+
|
|
65
|
+
## Workflow
|
|
66
|
+
|
|
67
|
+
### 1) Create a parametric model
|
|
68
|
+
|
|
69
|
+
Put customizable parameters at the top and keep the model code below.
|
|
70
|
+
|
|
71
|
+
```openscad
|
|
72
|
+
// Customizable parameters
|
|
73
|
+
wall_thickness = 2; // [1:0.5:5] Wall thickness in mm
|
|
74
|
+
width = 50; // [20:100] Width in mm
|
|
75
|
+
height = 30; // [10:80] Height in mm
|
|
76
|
+
rounded = true; // Add rounded corners
|
|
77
|
+
|
|
78
|
+
module main_shape() {
|
|
79
|
+
if (rounded) {
|
|
80
|
+
minkowski() {
|
|
81
|
+
cube([width - 4, width - 4, height - 2]);
|
|
82
|
+
sphere(r = 2);
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
cube([width, width, height]);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
difference() {
|
|
90
|
+
main_shape();
|
|
91
|
+
translate([wall_thickness, wall_thickness, wall_thickness])
|
|
92
|
+
scale([1 - 2*wall_thickness/width, 1 - 2*wall_thickness/width, 1])
|
|
93
|
+
main_shape();
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Parameter comment formats:
|
|
98
|
+
|
|
99
|
+
- `// [min:max]` numeric range
|
|
100
|
+
- `// [min:step:max]` numeric range with step
|
|
101
|
+
- `// [opt1, opt2, opt3]` dropdown options
|
|
102
|
+
- `// Description` free-form description
|
|
103
|
+
|
|
104
|
+
### 2) Validate
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
"./scripts/validate.sh" model.scad
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 3) Render previews (then inspect them)
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
"./scripts/multi-preview.sh" model.scad ./previews/
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Use `read` to open each PNG in `./previews/` and confirm the model is correct.
|
|
117
|
+
|
|
118
|
+
### 4) Export STL
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
"./scripts/export-stl.sh" model.scad output.stl
|
|
122
|
+
|
|
123
|
+
# With parameter overrides:
|
|
124
|
+
"./scripts/export-stl.sh" model.scad output.stl -D 'width=60' -D 'height=40'
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Camera positions
|
|
128
|
+
|
|
129
|
+
Common camera angles:
|
|
130
|
+
|
|
131
|
+
- Isometric: `--camera=0,0,0,45,0,45,200`
|
|
132
|
+
- Front: `--camera=0,0,0,90,0,0,200`
|
|
133
|
+
- Top: `--camera=0,0,0,0,0,0,200`
|
|
134
|
+
- Right: `--camera=0,0,0,90,0,90,200`
|
|
135
|
+
|
|
136
|
+
Format: `x,y,z,rotx,roty,rotz,distance`
|
|
137
|
+
|
|
138
|
+
## Printables publishing checklist
|
|
139
|
+
|
|
140
|
+
Typically you need:
|
|
141
|
+
|
|
142
|
+
1. STL file(s) exported via `export-stl.sh`
|
|
143
|
+
2. Preview images (at least one strong hero/isometric view plus extra angles)
|
|
144
|
+
3. A model description covering customizable parameters, print settings, and assembly/use notes
|
|
145
|
+
4. License/category/tags filled in for discoverability
|
|
146
|
+
|
|
147
|
+
## Examples
|
|
148
|
+
|
|
149
|
+
Sample models live under `examples/`.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// Parametric Box with Lid
|
|
2
|
+
// A customizable storage box for 3D printing
|
|
3
|
+
|
|
4
|
+
// === Box Parameters ===
|
|
5
|
+
width = 60; // [20:200] Width in mm
|
|
6
|
+
depth = 40; // [20:200] Depth in mm
|
|
7
|
+
height = 30; // [10:150] Height in mm
|
|
8
|
+
wall_thickness = 2; // [1:0.5:5] Wall thickness in mm
|
|
9
|
+
|
|
10
|
+
// === Lid Parameters ===
|
|
11
|
+
include_lid = true; // Include a separate lid
|
|
12
|
+
lid_height = 8; // [5:30] Lid height in mm
|
|
13
|
+
lid_tolerance = 0.3; // [0.1:0.1:0.8] Gap for lid fit
|
|
14
|
+
|
|
15
|
+
// === Style Options ===
|
|
16
|
+
corner_radius = 3; // [0:10] Corner rounding radius
|
|
17
|
+
add_grip = true; // Add grip indents to lid
|
|
18
|
+
|
|
19
|
+
// === Internal ===
|
|
20
|
+
$fn = 32; // Smoothness
|
|
21
|
+
|
|
22
|
+
// Rounded box module
|
|
23
|
+
module rounded_box(w, d, h, r) {
|
|
24
|
+
if (r > 0) {
|
|
25
|
+
hull() {
|
|
26
|
+
for (x = [r, w-r]) {
|
|
27
|
+
for (y = [r, d-r]) {
|
|
28
|
+
translate([x, y, 0])
|
|
29
|
+
cylinder(h = h, r = r);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
cube([w, d, h]);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Main box body
|
|
39
|
+
module box_body() {
|
|
40
|
+
difference() {
|
|
41
|
+
rounded_box(width, depth, height, corner_radius);
|
|
42
|
+
|
|
43
|
+
// Hollow inside
|
|
44
|
+
translate([wall_thickness, wall_thickness, wall_thickness])
|
|
45
|
+
rounded_box(
|
|
46
|
+
width - 2*wall_thickness,
|
|
47
|
+
depth - 2*wall_thickness,
|
|
48
|
+
height, // Open top
|
|
49
|
+
max(0, corner_radius - wall_thickness)
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Lid
|
|
55
|
+
module lid() {
|
|
56
|
+
inner_w = width - 2*wall_thickness - 2*lid_tolerance;
|
|
57
|
+
inner_d = depth - 2*wall_thickness - 2*lid_tolerance;
|
|
58
|
+
lip_height = lid_height * 0.6;
|
|
59
|
+
|
|
60
|
+
difference() {
|
|
61
|
+
union() {
|
|
62
|
+
// Top cap
|
|
63
|
+
rounded_box(width, depth, wall_thickness, corner_radius);
|
|
64
|
+
|
|
65
|
+
// Inner lip
|
|
66
|
+
translate([wall_thickness + lid_tolerance, wall_thickness + lid_tolerance, -lip_height + wall_thickness])
|
|
67
|
+
rounded_box(inner_w, inner_d, lip_height, max(0, corner_radius - wall_thickness));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Grip indents
|
|
71
|
+
if (add_grip) {
|
|
72
|
+
for (x = [width * 0.3, width * 0.7]) {
|
|
73
|
+
translate([x, -1, wall_thickness/2])
|
|
74
|
+
rotate([-90, 0, 0])
|
|
75
|
+
cylinder(h = 5, r = 3, $fn = 16);
|
|
76
|
+
translate([x, depth - 4, wall_thickness/2])
|
|
77
|
+
rotate([-90, 0, 0])
|
|
78
|
+
cylinder(h = 5, r = 3, $fn = 16);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Render
|
|
85
|
+
box_body();
|
|
86
|
+
|
|
87
|
+
if (include_lid) {
|
|
88
|
+
// Position lid next to box for printing
|
|
89
|
+
translate([width + 10, 0, lid_height - wall_thickness])
|
|
90
|
+
rotate([180, 0, 0])
|
|
91
|
+
lid();
|
|
92
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// Adjustable Phone/Tablet Stand
|
|
2
|
+
// Parametric stand with customizable angle and size
|
|
3
|
+
|
|
4
|
+
// === Device Parameters ===
|
|
5
|
+
device_width = 80; // [50:200] Device width in mm
|
|
6
|
+
device_thickness = 12; // [6:20] Device thickness (with case)
|
|
7
|
+
|
|
8
|
+
// === Stand Parameters ===
|
|
9
|
+
stand_angle = 65; // [45:85] Viewing angle in degrees
|
|
10
|
+
stand_depth = 80; // [50:150] Base depth in mm
|
|
11
|
+
stand_height = 100; // [60:200] Back support height in mm
|
|
12
|
+
|
|
13
|
+
// === Construction ===
|
|
14
|
+
material_thickness = 4; // [2:0.5:8] Material thickness
|
|
15
|
+
slot_depth = 15; // [10:30] How deep device sits in slot
|
|
16
|
+
|
|
17
|
+
// === Features ===
|
|
18
|
+
cable_hole = true; // Add cable pass-through hole
|
|
19
|
+
cable_diameter = 15; // [8:25] Cable hole diameter
|
|
20
|
+
add_feet = true; // Add anti-slip feet
|
|
21
|
+
|
|
22
|
+
// === Quality ===
|
|
23
|
+
$fn = 48;
|
|
24
|
+
|
|
25
|
+
module stand_profile() {
|
|
26
|
+
// 2D profile of the stand side
|
|
27
|
+
polygon([
|
|
28
|
+
[0, 0], // Front bottom
|
|
29
|
+
[stand_depth, 0], // Back bottom
|
|
30
|
+
[stand_depth, material_thickness], // Back bottom inner
|
|
31
|
+
[stand_depth - material_thickness, material_thickness], // Base top back
|
|
32
|
+
[slot_depth + material_thickness, material_thickness], // Base top front (behind slot)
|
|
33
|
+
[slot_depth + material_thickness, slot_depth * tan(90 - stand_angle) + material_thickness], // Slot back
|
|
34
|
+
[material_thickness, slot_depth * tan(90 - stand_angle) + material_thickness + device_thickness / sin(stand_angle)], // Slot front top
|
|
35
|
+
[0, slot_depth * tan(90 - stand_angle) + material_thickness], // Front face bottom of slot
|
|
36
|
+
[0, 0] // Close
|
|
37
|
+
]);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module back_support() {
|
|
41
|
+
// Back angled support
|
|
42
|
+
translate([stand_depth - material_thickness, 0, material_thickness]) {
|
|
43
|
+
rotate([0, -90 + stand_angle, 0]) {
|
|
44
|
+
cube([stand_height, device_width, material_thickness]);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module cable_cutout() {
|
|
50
|
+
if (cable_hole) {
|
|
51
|
+
translate([stand_depth/2, device_width/2, -1])
|
|
52
|
+
cylinder(h = material_thickness + 2, d = cable_diameter);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module foot() {
|
|
57
|
+
cylinder(h = 2, d1 = 10, d2 = 8);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module stand() {
|
|
61
|
+
difference() {
|
|
62
|
+
union() {
|
|
63
|
+
// Left side
|
|
64
|
+
linear_extrude(material_thickness)
|
|
65
|
+
stand_profile();
|
|
66
|
+
|
|
67
|
+
// Right side
|
|
68
|
+
translate([0, device_width - material_thickness, 0])
|
|
69
|
+
linear_extrude(material_thickness)
|
|
70
|
+
stand_profile();
|
|
71
|
+
|
|
72
|
+
// Base plate
|
|
73
|
+
cube([stand_depth, device_width, material_thickness]);
|
|
74
|
+
|
|
75
|
+
// Front lip
|
|
76
|
+
cube([material_thickness, device_width, slot_depth * tan(90 - stand_angle) + material_thickness]);
|
|
77
|
+
|
|
78
|
+
// Back support
|
|
79
|
+
back_support();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Cable hole
|
|
83
|
+
cable_cutout();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Feet
|
|
87
|
+
if (add_feet) {
|
|
88
|
+
translate([10, 10, 0]) foot();
|
|
89
|
+
translate([10, device_width - 10, 0]) foot();
|
|
90
|
+
translate([stand_depth - 10, 10, 0]) foot();
|
|
91
|
+
translate([stand_depth - 10, device_width - 10, 0]) foot();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
stand();
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Common utilities for OpenSCAD tools
|
|
3
|
+
|
|
4
|
+
# Find OpenSCAD executable
|
|
5
|
+
find_openscad() {
|
|
6
|
+
# Check common locations
|
|
7
|
+
if command -v openscad &> /dev/null; then
|
|
8
|
+
echo "openscad"
|
|
9
|
+
return 0
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
# macOS Application bundle
|
|
13
|
+
if [ -d "/Applications/OpenSCAD.app" ]; then
|
|
14
|
+
echo "/Applications/OpenSCAD.app/Contents/MacOS/OpenSCAD"
|
|
15
|
+
return 0
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
# Homebrew on Apple Silicon
|
|
19
|
+
if [ -x "/opt/homebrew/bin/openscad" ]; then
|
|
20
|
+
echo "/opt/homebrew/bin/openscad"
|
|
21
|
+
return 0
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
# Homebrew on Intel
|
|
25
|
+
if [ -x "/usr/local/bin/openscad" ]; then
|
|
26
|
+
echo "/usr/local/bin/openscad"
|
|
27
|
+
return 0
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
return 1
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# Check if OpenSCAD is available
|
|
34
|
+
check_openscad() {
|
|
35
|
+
OPENSCAD=$(find_openscad) || {
|
|
36
|
+
echo "Error: OpenSCAD executable not found."
|
|
37
|
+
echo ""
|
|
38
|
+
echo "Please ensure OpenSCAD is already installed and available as 'openscad' in your PATH,"
|
|
39
|
+
echo "or located in a common location (e.g. /Applications/OpenSCAD.app on macOS)."
|
|
40
|
+
exit 1
|
|
41
|
+
}
|
|
42
|
+
export OPENSCAD
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
# Get version info
|
|
46
|
+
openscad_version() {
|
|
47
|
+
check_openscad
|
|
48
|
+
$OPENSCAD --version 2>&1
|
|
49
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Export OpenSCAD file to STL
|
|
3
|
+
# Usage: export-stl.sh input.scad output.stl [-D 'var=value' ...]
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
8
|
+
source "$SCRIPT_DIR/common.sh"
|
|
9
|
+
|
|
10
|
+
check_openscad
|
|
11
|
+
|
|
12
|
+
if [ $# -lt 2 ]; then
|
|
13
|
+
echo "Usage: $0 input.scad output.stl [-D 'var=value' ...]"
|
|
14
|
+
echo ""
|
|
15
|
+
echo "Examples:"
|
|
16
|
+
echo " $0 box.scad box.stl"
|
|
17
|
+
echo " $0 box.scad box_large.stl -D 'width=80' -D 'height=60'"
|
|
18
|
+
exit 1
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
INPUT="$1"
|
|
22
|
+
OUTPUT="$2"
|
|
23
|
+
shift 2
|
|
24
|
+
|
|
25
|
+
# Collect -D parameters
|
|
26
|
+
DEFINES=()
|
|
27
|
+
while [ $# -gt 0 ]; do
|
|
28
|
+
case "$1" in
|
|
29
|
+
-D)
|
|
30
|
+
shift
|
|
31
|
+
DEFINES+=("-D" "$1")
|
|
32
|
+
;;
|
|
33
|
+
*)
|
|
34
|
+
echo "Unknown option: $1"
|
|
35
|
+
exit 1
|
|
36
|
+
;;
|
|
37
|
+
esac
|
|
38
|
+
shift
|
|
39
|
+
done
|
|
40
|
+
|
|
41
|
+
# Ensure output directory exists
|
|
42
|
+
mkdir -p "$(dirname "$OUTPUT")"
|
|
43
|
+
|
|
44
|
+
echo "Exporting STL: $INPUT -> $OUTPUT"
|
|
45
|
+
if [ ${#DEFINES[@]} -gt 0 ]; then
|
|
46
|
+
echo "Parameters: ${DEFINES[*]}"
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
$OPENSCAD \
|
|
50
|
+
"${DEFINES[@]}" \
|
|
51
|
+
-o "$OUTPUT" \
|
|
52
|
+
"$INPUT"
|
|
53
|
+
|
|
54
|
+
# Show file info
|
|
55
|
+
SIZE=$(ls -lh "$OUTPUT" | awk '{print $5}')
|
|
56
|
+
echo "STL exported: $OUTPUT ($SIZE)"
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Extract customizable parameters from an OpenSCAD file
|
|
3
|
+
# Usage: extract-params.sh input.scad [--json]
|
|
4
|
+
#
|
|
5
|
+
# Parses parameter declarations with special comments:
|
|
6
|
+
# param = value; // [min:max] Description
|
|
7
|
+
# param = value; // [min:step:max] Description
|
|
8
|
+
# param = value; // [opt1, opt2] Description
|
|
9
|
+
# param = value; // Description only
|
|
10
|
+
|
|
11
|
+
set -e
|
|
12
|
+
|
|
13
|
+
if [ $# -lt 1 ]; then
|
|
14
|
+
echo "Usage: $0 input.scad [--json]"
|
|
15
|
+
exit 1
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
INPUT="$1"
|
|
19
|
+
JSON_OUTPUT=false
|
|
20
|
+
|
|
21
|
+
if [ "$2" = "--json" ]; then
|
|
22
|
+
JSON_OUTPUT=true
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
if [ ! -f "$INPUT" ]; then
|
|
26
|
+
echo "Error: File not found: $INPUT"
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# Extract parameters using Python for better parsing
|
|
31
|
+
extract_params() {
|
|
32
|
+
python3 -c '
|
|
33
|
+
import sys
|
|
34
|
+
import re
|
|
35
|
+
|
|
36
|
+
filename = sys.argv[1]
|
|
37
|
+
in_block = 0
|
|
38
|
+
|
|
39
|
+
with open(filename, "r") as f:
|
|
40
|
+
for line in f:
|
|
41
|
+
# Track block depth (skip params inside modules/functions)
|
|
42
|
+
in_block += line.count("{") - line.count("}")
|
|
43
|
+
if in_block > 0:
|
|
44
|
+
continue
|
|
45
|
+
|
|
46
|
+
# Match: varname = value; // comment
|
|
47
|
+
match = re.match(r"^\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*([^;]+);\s*(?://\s*(.*))?", line)
|
|
48
|
+
if not match:
|
|
49
|
+
continue
|
|
50
|
+
|
|
51
|
+
var_name = match.group(1)
|
|
52
|
+
value = match.group(2).strip()
|
|
53
|
+
comment = match.group(3) or ""
|
|
54
|
+
|
|
55
|
+
# Determine type
|
|
56
|
+
if value in ("true", "false"):
|
|
57
|
+
var_type = "boolean"
|
|
58
|
+
elif re.match(r"^-?\d+$", value):
|
|
59
|
+
var_type = "integer"
|
|
60
|
+
elif re.match(r"^-?\d*\.?\d+$", value):
|
|
61
|
+
var_type = "number"
|
|
62
|
+
elif value.startswith("\"") and value.endswith("\""):
|
|
63
|
+
var_type = "string"
|
|
64
|
+
value = value[1:-1] # Remove quotes
|
|
65
|
+
elif value.startswith("["):
|
|
66
|
+
var_type = "array"
|
|
67
|
+
else:
|
|
68
|
+
var_type = "expression"
|
|
69
|
+
|
|
70
|
+
# Parse comment for range/options
|
|
71
|
+
range_val = ""
|
|
72
|
+
options_val = ""
|
|
73
|
+
description = comment
|
|
74
|
+
|
|
75
|
+
range_match = re.match(r"\[([^\]]+)\]\s*(.*)", comment)
|
|
76
|
+
if range_match:
|
|
77
|
+
bracket_content = range_match.group(1)
|
|
78
|
+
description = range_match.group(2)
|
|
79
|
+
|
|
80
|
+
# Check if numeric range (contains :) or options (contains ,)
|
|
81
|
+
if ":" in bracket_content and not "," in bracket_content:
|
|
82
|
+
range_val = bracket_content
|
|
83
|
+
else:
|
|
84
|
+
options_val = bracket_content
|
|
85
|
+
|
|
86
|
+
# Output pipe-delimited
|
|
87
|
+
print(f"{var_name}|{value}|{var_type}|{range_val}|{options_val}|{description}")
|
|
88
|
+
' "$INPUT"
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if [ "$JSON_OUTPUT" = true ]; then
|
|
92
|
+
echo "["
|
|
93
|
+
first=true
|
|
94
|
+
while IFS='|' read -r name value type range options description; do
|
|
95
|
+
if [ "$first" = true ]; then
|
|
96
|
+
first=false
|
|
97
|
+
else
|
|
98
|
+
echo ","
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# Escape quotes in values
|
|
102
|
+
value=$(echo "$value" | sed 's/"/\\"/g')
|
|
103
|
+
description=$(echo "$description" | sed 's/"/\\"/g')
|
|
104
|
+
|
|
105
|
+
# Build JSON object
|
|
106
|
+
printf ' {\n'
|
|
107
|
+
printf ' "name": "%s",\n' "$name"
|
|
108
|
+
printf ' "value": "%s",\n' "$value"
|
|
109
|
+
printf ' "type": "%s"' "$type"
|
|
110
|
+
|
|
111
|
+
if [ -n "$range" ]; then
|
|
112
|
+
printf ',\n "range": "%s"' "$range"
|
|
113
|
+
fi
|
|
114
|
+
if [ -n "$options" ]; then
|
|
115
|
+
printf ',\n "options": "%s"' "$options"
|
|
116
|
+
fi
|
|
117
|
+
if [ -n "$description" ]; then
|
|
118
|
+
printf ',\n "description": "%s"' "$description"
|
|
119
|
+
fi
|
|
120
|
+
printf '\n }'
|
|
121
|
+
done < <(extract_params)
|
|
122
|
+
echo ""
|
|
123
|
+
echo "]"
|
|
124
|
+
else
|
|
125
|
+
echo "Parameters in: $INPUT"
|
|
126
|
+
echo "==============================================="
|
|
127
|
+
printf "%-20s %-15s %-10s %s\n" "NAME" "VALUE" "TYPE" "CONSTRAINT/DESC"
|
|
128
|
+
echo "-----------------------------------------------"
|
|
129
|
+
|
|
130
|
+
while IFS='|' read -r name value type range options description; do
|
|
131
|
+
constraint=""
|
|
132
|
+
if [ -n "$range" ]; then
|
|
133
|
+
constraint="[$range]"
|
|
134
|
+
elif [ -n "$options" ]; then
|
|
135
|
+
constraint="[$options]"
|
|
136
|
+
fi
|
|
137
|
+
if [ -n "$description" ]; then
|
|
138
|
+
if [ -n "$constraint" ]; then
|
|
139
|
+
constraint="$constraint $description"
|
|
140
|
+
else
|
|
141
|
+
constraint="$description"
|
|
142
|
+
fi
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
printf "%-20s %-15s %-10s %s\n" "$name" "$value" "$type" "$constraint"
|
|
146
|
+
done < <(extract_params)
|
|
147
|
+
fi
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Generate preview images from multiple angles
|
|
3
|
+
# Usage: multi-preview.sh input.scad output_dir/ [-D 'var=value']
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
8
|
+
source "$SCRIPT_DIR/common.sh"
|
|
9
|
+
|
|
10
|
+
check_openscad
|
|
11
|
+
|
|
12
|
+
if [ $# -lt 2 ]; then
|
|
13
|
+
echo "Usage: $0 input.scad output_dir/ [-D 'var=value' ...]"
|
|
14
|
+
exit 1
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
INPUT="$1"
|
|
18
|
+
OUTPUT_DIR="$2"
|
|
19
|
+
shift 2
|
|
20
|
+
|
|
21
|
+
# Collect -D parameters
|
|
22
|
+
DEFINES=()
|
|
23
|
+
while [ $# -gt 0 ]; do
|
|
24
|
+
case "$1" in
|
|
25
|
+
-D)
|
|
26
|
+
shift
|
|
27
|
+
DEFINES+=("-D" "$1")
|
|
28
|
+
;;
|
|
29
|
+
esac
|
|
30
|
+
shift
|
|
31
|
+
done
|
|
32
|
+
|
|
33
|
+
mkdir -p "$OUTPUT_DIR"
|
|
34
|
+
|
|
35
|
+
# Get base name without extension
|
|
36
|
+
BASENAME=$(basename "$INPUT" .scad)
|
|
37
|
+
|
|
38
|
+
echo "Generating multi-angle previews for: $INPUT"
|
|
39
|
+
echo "Output directory: $OUTPUT_DIR"
|
|
40
|
+
echo ""
|
|
41
|
+
|
|
42
|
+
# Define angles as name:camera pairs
|
|
43
|
+
# Camera format: translate_x,translate_y,translate_z,rot_x,rot_y,rot_z,distance
|
|
44
|
+
ANGLES="iso:0,0,0,55,0,25,0
|
|
45
|
+
front:0,0,0,90,0,0,0
|
|
46
|
+
back:0,0,0,90,0,180,0
|
|
47
|
+
left:0,0,0,90,0,90,0
|
|
48
|
+
right:0,0,0,90,0,-90,0
|
|
49
|
+
top:0,0,0,0,0,0,0"
|
|
50
|
+
|
|
51
|
+
echo "$ANGLES" | while IFS=: read -r angle camera; do
|
|
52
|
+
output="$OUTPUT_DIR/${BASENAME}_${angle}.png"
|
|
53
|
+
|
|
54
|
+
echo " Rendering $angle view..."
|
|
55
|
+
$OPENSCAD \
|
|
56
|
+
--camera="$camera" \
|
|
57
|
+
--imgsize="800,600" \
|
|
58
|
+
--colorscheme="Tomorrow Night" \
|
|
59
|
+
--autocenter \
|
|
60
|
+
--viewall \
|
|
61
|
+
"${DEFINES[@]}" \
|
|
62
|
+
-o "$output" \
|
|
63
|
+
"$INPUT" 2>/dev/null
|
|
64
|
+
done
|
|
65
|
+
|
|
66
|
+
echo ""
|
|
67
|
+
echo "Generated previews:"
|
|
68
|
+
ls -la "$OUTPUT_DIR"/${BASENAME}_*.png
|