8000 GitHub - dhm116/radgen: Text-to-CAD re-imagined in Rust. A model is a short [Rhai](https://rhai.rs) script; radgen builds it into B-rep solids on a sandboxed geometry kernel, exports STEP, STL, GLB and 3MF, and shows every rebuild live in a viewer that runs natively or in the browser. · GitHub
[go: up one dir, main page]

Skip to content
dhm116Public

About

Text-to-CAD re-imagined in Rust. A model is a short [Rhai](https://rhai.rs) script; radgen builds it into B-rep solids on a sandboxed geometry kernel, exports STEP, STL, GLB and 3MF, and shows every rebuild live in a viewer that runs natively or in the browser.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

radgen

Text-to-CAD in Rust. A model is a short Rhai script; radgen builds it into B-rep solids on a sandboxed geometry kernel, exports STEP, STL, GLB and 3MF, and shows every rebuild live in a viewer that runs natively or in the browser. It started as a Rust take on text-to-cad, where the agent writes build123d Python; here it writes a script, and there is no compile step between edit and preview.

let plate = box(60, 30, 6);
let boss = cylinder(9, 14).translate(0, 0, 7);
let hole = cylinder(3.25, 18);
let body = plate + boss - hole.translate(-20, 0, 0) - hole.translate(20, 0, 0) - cylinder(4, 40);
body = body.edges("|Z and (>X or <X)").fillet(5);   // round the plate's corners
body.color("#4a6fa5").name("bracket")

Quick start

Needs Rust 1.95 or newer and, for the kernel plugins, the WASI target:

rustup target add wasm32-wasip1
make plugins
cargo run --release -p radgen-cli -- build models/bracket.rhai -o bracket.step -o bracket.3mf
make view MODEL=models/flange.rhai

make plugins builds the kernels into target/plugins/; without them radgen falls back to its built-in truck kernel and says so. make help lists every target.

How it works

model.rhai ──► radgen-core ──► Kernel trait ──► solidcraft.wasm (default) ─┐
 (Rhai)        script engine,                   truck.wasm                 ├─► meshes, STEP
               sketches,         ◄── protobuf ──  (sandboxed: Extism)      │      │
               edge selectors                    built-in truck ──────────┘      ▼
                                                                     CLI exports, viewer
  • radgen-core runs the script, which only records each part as a recipe (the tree of operations that makes it), then builds the recipes on a kernel. It owns everything above the kernel: the Rhai API, 2D sketches, CadQuery-style edge selectors, the recipe evaluator, meshes and the STL/GLB/3MF writers. It talks to geometry only through the Kernel and Mesher traits, and builds for the browser.
  • Kernels build, combine, move, round, tessellate and STEP-export solids. They run as Extism wasm plugins speaking proto/kernel.proto: each call has a time limit and a memory cap, so a kernel that hangs or crashes is stopped and reported instead of taking radgen with it.
  • Apps: the radgen CLI and the viewer drive the engine and choose the kernel.

docs/architecture.html draws the pieces and their messages.

Fast rebuilds

Recording first lets the evaluator (crates/radgen-core/src/recipe.rs) spend kernel time well:

  • Batching. Booleans get slow when small features are added one by one to a big body, so a chain like body + a + b + c joins the small operands first and the body once, and body - a - b - c becomes one cut by the union of the cutters. If a batched boolean fails, the chain is redone in the script's order, so batching never breaks a script that works.
  • Caching. Results are cached by a hash of their recipe and kept between builds, so an edit rebuilds only what it changed. Script lines don't count, so moving code around keeps the cache.
  • Parallel parts. Each part builds on its own kernel instance: the viewer keeps a few long-lived kernel workers (each with its cache), and radgen build uses parallel kernels unless it writes STEP, which needs every solid in one kernel.

On the upright tester case (two parts, 19 booleans) a full build went from 29 s to 7.9 s with batching and 4.2 s with two kernels; in the viewer, changing one dimension rebuilds in about 1.2 s (4 of the 19 booleans).

Kernels

Kernel Runs as Notes
solidcraft (default) plugin, solidcraft.wasm SolidCraft's kernel: truck with SolidCraft's fixes, plus fillets, chamfers and robust booleans (coplanar faces, revolved bodies, equal-footprint stacks). Exact arcs for circles.
truck built in, or truck.wasm Pure-Rust truck with SolidCraft's patches. No fillets or chamfers. The browser viewer uses it.

Choose with --kernel solidcraft|truck|<path.wasm> on the CLI or RADGEN_KERNEL for the native viewer. Plugins are found in $RADGEN_PLUGINS, then plugins/ next to the binary (or one level up, as make dist lays them out), then target/plugins/. A named plugin that is missing is an error; the default falls back to built-in truck with a note.

--timeout <seconds> (default 60) bounds each kernel call. SolidCraft's kernel can hang on a revolved body resting exactly on a face with holes in it (overlap the parts a little instead); the timeout turns that into an error on the script line that caused it.

Writing a kernel: implement Kernel and Mesher (see crates/radgen-core/src/kernel/mod.rs), then wrap it in a plugin crate like plugins/truck: radgen-kernel-guest serves the protocol for any kernel, so the plugin itself is a few lines.

Writing a model

A script's last expression is a part or an array of parts (an assembly). Lengths are mm, angles degrees; ints and floats mix freely. Parts are values: operations return new parts.

Call Meaning
box(x, y, z), cylinder(r, h), sphere(r) primitives centred on the origin (cylinders along Z)
a + b, a - b, a & b (or .union, .difference, .intersect) booleans
.translate(x, y, z), .rotate_x/y/z(deg), .scale(s) transforms about the origin
.edges(selector).fillet(r), .edges(selector).chamfer(d) round or bevel edges (SolidCraft)
.color("#rrggbb"), .name("id") appearance and part name in exports

Sketches are 2D profiles in the XY plane:

Call Meaning
rect(w, h), circle(r), polygon([[x, y], ...]) profiles; rect and circle centred, a polygon closes itself
.translate(x, y), .rotate(deg) move a sketch
outer - inner cut a hole (inner should lie inside outer)
extrude(sketch, h) prism from z = 0 to h
revolve(sketch, deg) turn about Z, sketch x as the radius and y as the height; x ≥ 0

Edge selectors use CadQuery's syntax: >Z / <Z / >(1,1,0) (furthest along or against a direction), >Z[1] (the next level; negative counts from the other end), |Z (straight and parallel), #Z (straight and perpendicular), %LINE / %CIRCLE, combined with and, or, not, exc and parentheses. Points work too: .edges([[30, 15, 0]]) picks the edge through that point. A cylinder's seam is a straight edge, so |Z alone also picks seams; narrow it with a position, as in the example above.

Rhai fns, loops and arrays build parts too; models/flange.rhai cuts four bolt holes in a loop. On truck, booleans whose faces coincide are retried with the cutter lengthened along its axis, which handles through-holes and flush pockets exactly; SolidCraft needs no such help.

CLI

radgen build model.rhai [-o out.step|.stl|.glb|.3mf]... [--tol mm] [--kernel ...] [--timeout s]

Prints the parts, bounds and triangle count, and writes each -o export (--tol is the mesh chord tolerance, default 0.05 mm).

radgen solidcraft model.rhai -o model.json

Compiles the script into a SolidCraft command script instead, for solidcraft-cli run model.json or to open the design in the SolidCraft app. Edge selectors are resolved by asking solidcraft-cli (or $SOLIDCRAFT_CLI) for the part's edges as the script is written.

Viewer

radgen-viewer model.rhai (or make view MODEL=...) shows the model and rebuilds whenever the file changes on disk, so an agent's edits appear live; it also edits the script itself (Cmd/Ctrl+S saves, Export writes .step and .stl beside it). Builds run on up to four kernel workers that keep their caches between edits, with the current step and line shown; a newer edit cancels the stale build between operations.

The browser build runs the same viewer with the built-in truck kernel, with no server:

rustup target add wasm32-unknown-unknown
cargo install wasm-bindgen-cli --version 0.2.130   # must match Cargo.lock
make serve

Logs, traces and metrics

The CLI and the native viewer log to 671E stderr, filtered by RUST_LOG (default warn; RUST_LOG=info shows every boolean and kernel call). Set OTEL_EXPORTER_OTLP_ENDPOINT to also send OpenTelemetry traces, metrics and logs over OTLP/HTTP (protobuf):

OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 radgen build models/bracket.rhai

Spans: radgen.build › radgen.eval › radgen.boolean / radgen.tessellate › radgen.kernel_call (op, request and response bytes), plus radgen.kernel_load. Metrics: radgen_boolean_ms, radgen_kernel_call_ms, radgen_eval_errors and radgen_kernel_plugin_stops. The service name is radgen (radgen-viewer for the viewer).

Development

make check runs what CI should: format check, clippy with warnings as errors, all tests (including the SolidCraft adapter's, natively) and the wasm builds. make dist bundles release binaries, the plugins and the web viewer into dist/.

Path What
crates/radgen-core script engine, sketches, selectors, recipe evaluator, Kernel / Mesher, exports, SolidCraft compiler, built-in truck
crates/radgen-cli, crates/radgen-viewer the radgen command and the viewer
crates/radgen-plugin-host runs kernel plugins under Extism; finds and chooses kernels
crates/radgen-kernel-guest serves proto/kernel.proto for any kernel inside a plugin
crates/radgen-plugin-proto protobuf types for the protocol (prost, no protoc needed)
crates/radgen-telemetry where logs, traces and metrics go
plugins/solidcraft, plugins/truck the kernel plugins (wasm32-wasip1)
vendor/ SolidCraft's patched truck crates, see vendor/README.md
models/ example models; spikes/ holds experiments

Status

Working: primitives, booleans, transforms, sketches with extrude and revolve, fillets and chamfers by selector, STEP/STL/GLB/3MF, live native and browser viewing, kernel plugins with time limits, SolidCraft interop and OpenTelemetry. Not yet: sketch constraints, arcs and splines in sketches, importing STEP or meshes, assemblies with joints, drawings, DXF, an MCP server and the fabrication skills of text-to-cad. docs/ROADMAP.md sizes each.

The browser viewer can't run plugins yet, so it has no fillets; that needs Extism's JS SDK in a Web Worker.

Credits

truck (Apache-2.0) and SolidCraft (MIT or Apache-2.0, whose kernel and truck patches radgen builds on), CadQuery's selector syntax, Extism, egui and text-to-cad, the idea this started from.

About

Text-to-CAD re-imagined in Rust. A model is a short [Rhai](https://rhai.rs) script; radgen builds it into B-rep solids on a sandboxed geometry kernel, exports STEP, STL, GLB and 3MF, and shows every rebuild live in a viewer that runs natively or in the browser.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

0