Skip to content

Releases: hiroshiyui/rrcad

v0.3.0

15 May 03:24

Choose a tag to compare

[0.3.0] - 2026-05-15

Added

  • Hardware helpers — hole tools (src/ruby/prelude.rb,
    tests/phase8_tier2.rs): added clearance_hole(size, depth:),
    tap_drill(size, depth:), heat_set_insert(size, depth:),
    socket_head_cbore(size, depth:, head_depth:), and
    flat_head_csink(size, depth:, angle:) for :m2:m5 metric hardware,
    each producing a cylinder/counterbore/countersink suitable for subtractive
    modelling with .cut.
  • Hardware helpers — bearing bores (src/ruby/prelude.rb,
    tests/phase8_tier2.rs): bearing_bore(size, depth:, fit:) produces an
    outer-diameter bore for common deep-groove ball bearings (:b608, :b623,
    :b624, :b625, :b626, :b688, :b695, :b6000, :b6001, or a numeric
    OD), with :press (interference) or :slip (clearance) fit.
  • Hardware helpers — shaft fits (src/ruby/prelude.rb,
    tests/phase8_tier2.rs): shaft(diameter, length:, fit:) generates a solid
    mating shaft cylinder with :nominal, :press, :slip, or :running fit
    adjustments relative to the nominal diameter.
  • Hardware helpers — standard fasteners (src/ruby/prelude.rb,
    tests/phase8_tier2.rs): screw(size, length:, style:) generates solid
    fastener bodies for :m2:m5 in :socket (ISO 4762), :button
    (ISO 7380), and :flat (ISO 10642 90° conical head) styles.
  • Sketch — tangent constraint (src/ruby/prelude.rb,
    tests/phase10_sketch_constraints.rs): tangent(a, b, center, radius, side:) constrains a line segment tangent to a circle. With side:
    (:above/:below for horizontal lines, :left/:right for vertical
    lines) the solver propagates the unknown perpendicular coordinate on
    either the line or the center; for fully-resolved geometry it verifies the
    point-to-line distance and raises on conflict. Endpoint-driven orientation
    inference lets the constraint work inside open rectangle sketches.
  • Assembly — transform-based constraint helpers (src/ruby/prelude.rb,
    tests/assembly_constraints.rs): Shape#rotate_about(point, axis_dir, angle_deg) rotates around any pivot; Assembly#distance_mate(shape, from:, to:, distance:) is a named air-gap variant of mate;
    Assembly#axis_align(shape, from: [p1, p2], to: [q1, q2]) rotates and
    translates a shape so a source axis maps to a target axis (covers
    coaxial / concentric / axis-alignment cases); Assembly#angle_mate(..., angle:, pivot:, axis_dir:, offset:) mates a face flush and then rotates
    about a chosen pivot axis to lock the leftover rotational degree of
    freedom.
  • Sketch — solver diagnostics enriched (src/ruby/prelude.rb,
    tests/phase10_sketch_constraints.rs): conflict messages now name the
    involved sketch points and report the actual vs expected values
    (horizontal/vertical/coincident/dimension/equal_length/
    tangent and any assign_coord-driven constraint); the "did not
    converge" failure lists every unresolved point with its missing
    coordinates. The original "conflicting X constraint" substring is
    preserved at the start of each message for backward-compatible matching.
  • Sketch — polar_point construction helper (src/ruby/prelude.rb,
    tests/phase10_sketch_constraints.rs): polar_point([:name,] center, radius, angle_deg) registers a construction point at polar coordinates
    around center; once center resolves the solver derives (cx + r·cos θ, cy + r·sin θ). Useful for bolt circles and angular layouts.
    Closes the constraint-based-sketching MVP entry in doc/TODOs.md.
  • CAM / 3-D printing — mass and build-volume helpers
    (src/ruby/prelude.rb, tests/cam_checks.rs):
    mass_estimate(part, density: 1.24) computes a rough mass in grams from
    part.volume × density / 1000; print_volume_check(part, x:, y:, z:)
    reports {fits:, dx:, dy:, dz:, overflow_x/y/z:} against a rectangular
    build volume.
  • CAM / 3-D printing — face normals exposed + overhang_faces
    (src/occt/bridge.{h,cpp}, src/occt/mod.rs, src/ruby/native.rs,
    src/ruby/glue.c, src/ruby/prelude.rb, tests/cam_checks.rs): new
    shape_face_normal bridge call samples the outward unit normal at the
    face's parameter-space midpoint via BRepLProp_SLProps, flipping for
    TopAbs_REVERSED faces; surfaced to Ruby as Shape#normal returning
    [nx, ny, nz]. Built on top: overhang_faces(part, max_angle_deg: 45)
    lists faces whose outward normal tips below a horizontal threshold
    (assumes +Z-up build direction).
  • CAM / 3-D printing — draft analysis (src/ruby/prelude.rb,
    tests/cam_checks.rs): draft_faces(part, axis: [0, 0, 1], min_draft_deg: 1.0) lists faces with insufficient mould draft along the
    pull axis (asin(|n·axis|) < min_draft_deg). Top/bottom faces are
    naturally excluded; the pull direction is configurable so non-Z pull
    setups work without rotation tricks.
  • CAM / 3-D printing — hole orientation analysis
    (src/occt/bridge.{h,cpp}, src/occt/mod.rs, src/ruby/native.rs,
    src/ruby/glue.c, src/ruby/prelude.rb, tests/cam_checks.rs): new
    shape_cylinder_axis bridge call extracts the axis (origin + unit
    direction) and radius of cylindrical faces via
    BRepAdaptor_Surface::Cylinder(). Surfaced to Ruby as
    Shape#cylinder_axis returning {origin:, axis:, radius:}. Built on
    top: hole_axes(part, orientation: :vertical | :horizontal, tolerance_deg:) enumerates and filters cylindrical faces by axis
    direction.
  • OCCT diagnostics — call-site context + actionable hints
    (src/occt/mod.rs, tests/error_diagnostics.rs): errors from
    Boolean ops (fuse/cut/common), fillets and chamfers (including
    selector / variable-radius / asymmetric variants),
    extrude/revolve/shell/offset/offset_2d/simplify,
    sweep/sweep_guide/sweep_sections, loft, Part Design (pad,
    pocket), and import/export now lead with the operation name, its
    numeric parameters, the operand shape kind (via a summarize()
    helper), and any file path or view name. The most common failures
    (fillet/chamfer radius too large, extrude on a solid, shell
    thickness too thick, pad/pocket planar-face requirement,
    sweep/sweep_guide profile-and-path types,
    import_step/import_stl missing files) also carry an actionable
    one-line hint: … suffix. The original "X failed: …" substring is
    preserved so existing substring matchers keep working.

Fixed

  • CI — install g++ explicitly (.github/workflows/rust.yml):
    Debian sid's gcc meta-package no longer pulls g++ as a transitive
    dependency, so the CI container was missing a C++ compiler and
    link-cplusplus / cxx bridge builds failed with failed to find tool "c++". Add g++ to the apt install line.

v0.2.2

13 May 00:24

Choose a tag to compare

Security

  • MCP timeouts are now process-enforced (src/mcp/mod.rs, src/main.rs): MCP tool evaluations run in one-shot worker processes that are killed when the 30 s timeout expires. A runaway Ruby loop or long OCCT operation can no longer keep running on a blocking thread after the client receives a timeout.
  • MCP prelude hardening extended (src/mcp/mod.rs): the production security prelude now removes additional metaprogramming entry points from BasicObject, Object, Kernel, and Module, including top-level define_method, closing a dev-build escape path caught by the expanded integration tests.

Changed

  • MCP tests use production hardening (tests/mcp_tools.rs, tests/mcp_stress.rs): integration and stress tests now construct MCP VMs through the real production helper instead of carrying a stale copied prelude, and cover blocked file-access and metaprogramming methods.
  • Dependency audit rationale documented (audit.toml): accepted the transitive rand advisory (RUSTSEC-2026-0097) with the project-specific rationale pending an upstream axum/tungstenite update.
  • Agent repository guidance added (AGENTS.md): documented project layout, build/test commands, coding style, testing expectations, and agent-specific instructions for future automation.

v0.2.1

12 May 12:57

Choose a tag to compare

[0.2.1] - 2026-05-12

Security

  • MCP prelude: undef metaprogramming methods (src/mcp/mod.rs): the runtime
    security prelude now also strips eval, instance_eval, class_eval,
    module_eval, send, __send__, public_send, method, define_method,
    define_singleton_method, and binding from Kernel. Production builds
    with mcp_safe.gembox were already safe, but a development build using the
    default gembox could previously reach undef'd methods via send or eval.
    The loop now runs inside Kernel.module_eval { … } so undef'ing :send
    mid-iteration cannot break the loop itself.
  • CLI preview tempfile uses CSPRNG (src/main.rs): the temporary GLB
    filename is now derived from uuid::Uuid::new_v4() (122 bits of OS-CSPRNG
    entropy) instead of DefaultHasher(time, pid). The previous path was
    predictable from PID plus approximate launch time, weakening the symlink-
    attack mitigation.

Fixed

  • Preview server start now returns Result (src/preview/mod.rs,
    src/main.rs): preview::start no longer panics on double-init or tokio
    runtime creation failure — the CLI prints a clear error and exits cleanly.
  • MCP preview port-init race (src/mcp/mod.rs): MCP_PREVIEW_PORT
    switched from std::sync::OnceLock to tokio::sync::OnceCell with
    get_or_try_init. Two concurrent first-time cad_preview calls could
    previously each bind a listener and spawn an axum task — only one won the
    OnceLock::set, leaking the loser's listener and task. The async OnceCell
    serialises initialisation so only one initialiser runs.
  • Preview WebSocket reconnect storm (src/preview/viewer.html): the
    browser previously retried every 1 s forever after rrcad exited, pounding a
    dead port. Reconnect now uses exponential backoff (1 → 2 → 4 → 8 s, capped
    at 8 attempts) and ends with a clear "server gone (reload page to retry)"
    status.
  • Preview GLB-load error detail (src/preview/viewer.html): the load-
    error status line now includes the underlying error message instead of the
    bare "load error" text, making failures self-diagnosable from the browser.
  • Clippy lints: items_after_test_module in src/main.rs (helpers moved
    above the test module), useless_vec in tests/phase5_params.rs, and
    len_zero in tests/e2e_dsl.rs.

Changed

  • REPL tab-completion: SHAPE_METHODS in src/main.rs extended with
    fillet_var, bounding_box, volume, surface_area, distance_to,
    inertia, and min_thickness so autocomplete matches the documented and
    available native methods.
  • Documentation: CLAUDE.md updated to reflect the per-process randomised
    CLI preview tempfile and the MCP /tmp/rrcad_mcp/preview.glb path, and to
    list the /logo.png axum route. src/preview/server.rs module doc lists
    /logo.png.

v0.2.0

31 Mar 01:33

Choose a tag to compare

Added

  • Preview: flat-line view: press F to toggle flat-line rendering — white flat-shaded surfaces with heavy-gray edge lines drawn at ≥15° creases. View mode persists across live-reloads.
  • Preview: hamburger menu: top-right menu button with three sections — View (Normal / Flat-line), Scene (Showroom / White), and Show (Axes). Keyboard shortcuts (F, A) stay in sync. Press Escape to close.
  • Preview: white scene: pure-white inspection scene preset — white background, white floor, flat neutral lighting, no vignette. The dark Showroom scene remains the default.

Fixed

  • Preview: GPU memory leaks: outgoing model geometries disposed on each live-reload, preventing unbounded GPU memory growth.
  • Preview: GLB load-error message: error callback now shows "rrcad preview — load error" and logs to console (previously showed "waiting for model").
  • Preview: F shortcut ambiguity: F shortcut shown only on the inactive view menu item.
  • MCP server: sandbox directory permissions: sandbox created with 0o700 (user-only), eliminating a TOCTOU window.
  • MCP server: prelude blocks additional methods: open, require, require_relative, and load are now removed from Kernel in the security prelude.
  • glue.c: malloc leak on mRuby raise: multi-shape operations now use mrb_data_check_get_ptr with free-before-raise to avoid leaking pointer arrays.
  • bridge.cpp: std::exception escape: added catch clause so non-OCCT C++ exceptions cannot silently cross the cxx boundary.

Security

  • MCP prelude now blocks open, require, require_relative, and load in addition to system, exec, `, and eval.
  • Sandbox directory created with 0o700 permissions (was world-readable until chmod).

v0.1.6

28 Mar 02:41

Choose a tag to compare

Changed

  • Preview: studio photography look (src/preview/viewer.html): transformed the live viewer into a dark product-photography studio — vertical gradient background (cool dark top → faintly warm bottom), a large polished studio floor plane that catches shadows and shows faint model reflection, multi-light rig (key/fill/rim/bounce), 40° telephoto FOV (less distortion than 45°), CSS vignette overlay for cinematic corners, per-model shadow frustum fitted to bounding box for crisp shadows, orbit floor clamp so the camera cannot go below the studio floor, axes helper (press A to toggle), and ACES filmic tone mapping at 1.2× exposure.
  • Preview: tighter camera fit (src/preview/viewer.html): fitCamera multipliers reduced from 2.5 × 1.4 to 1.15 × 1.0, so the model fills the frame closely on every load rather than sitting in a wide empty viewport.
  • Split TKL keyboard — flat-bottom case (samples/split_tkl_keyboard.rb): removed the solid_tent wedge base entirely. The case now has a flat bottom; users glue on custom-printed tenting feet at whatever angle they prefer.
  • Split TKL keyboard — right bottom-row modifiers widened (samples/split_tkl_keyboard.rb): RAlt, Fn, and RCtrl widened from 1 U to 1.25 U each; Space repositioned to 1 U at the left edge of the row (flush with the case wall) so all three modifiers pack tightly against the spacebar. Leaves a natural 1.25 U gap before the arrow cluster.

Fixed

  • Split TKL keyboard — RShift position corrected (samples/split_tkl_keyboard.rb): RShift switch centre moved from 5.5 U to 6.0 U so the 2 U keycap sits flush against / on the left (both edges at 5.0 U) and flush against Up ↑ on the right (both edges at 7.0 U). The previous 5.5 U position caused the RShift keycap to overlap / by 0.5 U.
  • Preview: zoom limits removed (src/preview/viewer.html): minDistance and maxDistance constraints on OrbitControls were removed so the camera can orbit right up to the model surface for close-up detail inspection.
  • CLI: script paths outside working directory (src/main.rs): the safe_path CWD restriction on the input script argument was overly strict for CLI use — users should be able to run rrcad --preview ../mykb/script.rb or any absolute path. Removed the guard from run_script, run_preview, and run_table; export paths produced inside scripts remain confined by safe_path in native.rs.
  • Split TKL keyboard sample (samples/split_tkl_keyboard.rb): replaced fraction-based pillar positions with diagonal midpoints between 4 adjacent key centres, giving ~13.5 mm clearance from every switch body edge (previously the positions fell directly under Cherry MX switch bodies and inside the Raspberry Pi Pico board footprints). Both halves now have 4 pillars each.

v0.1.5

26 Mar 00:12

Choose a tag to compare

Fixed

  • MCP server: SIGSEGV from concurrent mRuby VMsspawn_blocking runs closures on a thread pool, so a timed-out tool call could leave a mRuby VM alive on one thread while a second call spawned a new VM on another. mRuby is not thread-safe; concurrent VMs caused SIGSEGV crashes. A new MRUBY_EVAL_LOCK (std::sync::Mutex<()>) is now acquired at the top of every spawn_blocking closure, serialising all mRuby/OCCT work regardless of how many concurrent calls arrive or how many timed-out threads are still running.
  • MCP server: TOCTOU port-binding race in cad_preview — the old code bound a listener to discover a free port, dropped it, then had axum try to rebind the same port. Another process could steal the port in that window, causing a panic! inside the spawned task. The tokio::net::TcpListener is now kept alive and passed directly to a new serve_with_listener() on the axum server, eliminating both the race and a 200 ms sleep.
  • Split TKL keyboard sample (samples/split_tkl_keyboard.rb): added M2.5 button-head counterbores (Ø4.8 mm, 1.5 mm deep) to all plate screw vias so screw heads sit flush with the plate top face.

Changed

  • Split TKL keyboard — connectors, bosses, and manufacturing details (samples/split_tkl_keyboard.rb):
    • Replaced RJ-45 inter-half connector with USB-C (safer for hot-plug; no VCC on interconnect cable). Left half: USB Micro host port at back wall ¼-width + USB-C interconnect at ¾-width. Right half: USB-C interconnect at ¼-width + USB-C host port at ¾-width.
    • Added wall slots for USB-C adapter boards (12×4.2 mm PCB, open-top insertion pocket, 9×3.5 mm USB-C port opening in back wall).
    • Upgraded corner and mid-edge screw bosses to M2.5 heat-set copper insert compatibility (POST_R 2.5 → 3.2 mm, M2_R 1.2 → 1.6 mm; 3D print FIT_TOL 0.2 mm per side).
    • Added bottom-face lead-in step (0.5 mm box-cut method) on all switch cutouts to ease Cherry MX switch clip insertion from below.
    • Added CHAMFER_CASE chamfer to the solid tent wedge base (applied before fusing with the tilted case half to avoid BRepFilletAPI_MakeChamfer failures on complex fused geometry).
    • Preview changed from 2×2 parts layout to a fully assembled side-by-side view (plates seated in cases, left and right halves with a 20 mm gap).

Added

  • MCP stress tests (tests/mcp_stress.rs): 10 new tests covering sequential VM churn, error recovery, boundary inputs, deep boolean chains, geometry validation after operations, security prelude persistence, and a two-thread lock-serialisation proof.

v0.1.4

24 Mar 13:51

Choose a tag to compare

Changed

  • Split TKL keyboard layout refinements (samples/split_tkl_keyboard.rb):
    • Left Fn row (F1–F6) aligned with number row (` 1–6) while maintaining proper Tab/Home/Shift row key widths (1.5U, 1.75U, 2.25U respectively)
    • RJ-45 Ethernet ports repositioned to symmetrical 1/4-width positions on both left and right cases (mirrors USB positioning)

v0.1.3

24 Mar 13:02

Choose a tag to compare

Added

  • Split TKL keyboard sample (samples/split_tkl_keyboard.rb): complete 86-key split TKL mechanical keyboard (Cherry MX, 19.05 mm pitch) with a compact right half (≈20.7 cm) that fits a 22 cm print bed. Layout features: single nav column, inverted-T arrow cluster on the bottom row, PrtSc/ScrLk/Pause on the Fn row alongside F7–F12.
  • M2.5 heat-set insert standoffs for Raspberry Pi Pico mounting (4 bosses per side, 4 mm tall, 3.2 mm Ø press-fit holes). Left Pico rotated 90° so the micro-USB port faces the back wall; USB cutout Z-offset raised to align with the Pico PCB level.
  • Mid-edge M2 screw bosses (2 per side) at verified switch-cutout-clear edge positions to improve plate–case rigidity beyond the four corner screws.
  • Central screw-less support pillar (1 per side) at the plate midpoint — a solid post rising to 0.2 mm below the plate underside to resist flex under typing load without requiring a via hole through the plate.
  • doc/split_tkl_keyboard.stl — 2×2 preview layout (cases + plates) for interactive 3D viewing on GitHub.

v0.1.2

24 Mar 04:24

Choose a tag to compare

Added

  • Schmidt ball pen sample (samples/pen_schmidt.rb): four-part pen body (barrel, tip, front cap, tail cap) demonstrating cone, rotate, boolean ops, and multi-part layout. Tip-to-barrel joint uses an L-shaped tenon & mortise (quarter-turn bayonet) with spring-relief cantilever tabs for tactile snap-fit installation. Exports STEP and STL.

Changed

  • Preview render quality (src/preview/viewer.html): replaced the ad-hoc three-directional-light rig (including a blue fill that caused unnatural colour casts) with ACES filmic tone mapping, a RoomEnvironment PBR ambient map, a HemisphereLight (cool sky / warm ground), and a single clean key light. Shadows upgraded to PCFSoftShadowMap at 2048 × 2048 with bias to eliminate shadow acne.

Fixed

  • set_params() backslash injection (src/ruby/vm.rs): only double-quotes were escaped when building the $_rrcad_params Ruby hash literal from --param CLI values. A backslash in a value (e.g. --param path=C:\dir) produced an unterminated string literal. Backslashes are now escaped before double-quotes.
  • Memory-limit doc discrepancy (src/mcp/mod.rs): module-level table said 512 MB but the constant is 2 GB. Updated to match actual value and clarified that the limit is applied once in start(), not per-call.

v0.1.1

23 Mar 13:01

Choose a tag to compare

What's Changed

Fixed

  • MRUBY_CONFIG path doubling: mruby's Rakefile already prepends
    build_config/ when resolving MRUBY_CONFIG, so passing
    build_config/rrcad produced build_config/build_config/rrcad.rb and
    broke every CI build from scratch. Fixed by passing the bare name rrcad.
    The bug was masked locally by the cached libmruby.a.
  • Missing mruby-compiler in mcp_safe gembox: mrb_load_string()
    used by glue.c to evaluate DSL strings — is implemented in the
    mruby-compiler core gem, not in mruby's base C library. Omitting it
    caused a linker error on all clean builds. mruby-compiler (C-level
    parser) is distinct from mruby-eval (Ruby-level Kernel#eval), which
    remains excluded.

Changed

  • Added scripts/clean-build.sh and a pre-push git hook that
    automatically runs a clean mruby build when build.rs or
    mruby_configs/ are in the outgoing commits, catching build-plumbing
    bugs before they reach CI.

Full changelog: https://github.com/hiroshiyui/rrcad/blob/main/CHANGELOG.md