Sheet-metal MCP tools and manufacturing pipeline#226
Merged
Conversation
Adds `flat_pattern_to_dxf` in vcad-kernel-sheet: serialises a FlatPattern to DXF R12 with the manufacturing layer convention from the design spec — CUT (red) for panel outlines + holes, BEND_UP (blue) / BEND_DOWN (cyan) for creases, in millimetres. Threaded through the WASM binding and engine glue (rides along with the flat pattern in one boundary call) and surfaced as a "Download DXF" button in the sheet-metal panel. Closes the last foundation-tier gap. https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Adds check_manufacturability(model, shop) in vcad-kernel-sheet: a pure function over the panel/bend graph returning structured Violations (BendRadiusBelowMinimum, BendExceedsBrakeCapacity, FlangeBelowMinHeight, HoleTooCloseToBend, BendsTooClose), plus a ShopProfile type with a sensible generic() default. Threaded through the WASM binding and engine glue and surfaced as a Problems-style DFM inspector in the sheet-metal panel (errors/warnings chip, "Shop-ready" when clean). First leg of the spec's DFM-as-typed-query — same data will back the sheet_metal.check MCP tool. https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Makes manufacturability a tunable typed query rather than a generic-shop by-product: - ShopProfile is now Deserialize + #[serde(default)] (field-tolerant: omitted keys fall back to generic(), so older saved profiles still load). - New checkSheetMetal(chainJson, shopJson) WASM binding — runs check_manufacturability against a caller-supplied shop and echoes back the merged profile. Kept separate from evaluateSheetMetalChain on purpose: the spec treats manufacturability as a query against the model, not a mesh-eval side effect. - Engine: SheetMetalShopProfile / SheetMetalCheckResult types, DEFAULT_SHOP_PROFILE, checkSheetMetalManufacturability(), and an Engine.checkSheetMetal(doc, shop?) method that finds the sheet-metal root and runs the query. Kernel WASM rebuilt. Backend only; the Shop Profile editor UI lands next. https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
- Persisted shop-profile store (localStorage, field-tolerant merge onto generic defaults) + an editor in the sheet-metal panel: brake length, R/t, flange height, hole→bend, bend→bend, shop name, reset. - DFM inspector re-runs against the active profile via Engine.checkSheetMetal and shows which shop it checked against. Root-cause fix so the feature actually renders in-app: - KernelModule never carried the sheet-metal bindings, so this.kernel.checkSheetMetal / evaluateSheetMetalChain were undefined. Added them to the interface + Engine.init + worker kernelModule. - The eval worker (the default async path) post-processed embroidery but not sheet metal, so sheet-metal parts never got their part.sheetMetal bundle and the panel never appeared. Added postProcessSheetMetal mirroring postProcessEmbroidery. Engine + app typecheck clean; 65 engine tests pass. https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Adds the AI-native sheet-metal surface from the spec: - sheet_metal_create: base flange + edge-flange chain → session document_id (reusable with inspect_cad / export_cad / open_in_browser) + model summary + generic-shop DFM. - sheet_metal_unfold: flat pattern + layered DXF. - sheet_metal_check: manufacturability vs. a field-tolerant shop profile → structured violations to iterate on. Session-document based for consistency with the rest of the MCP surface; reuses Engine.evaluate / Engine.checkSheetMetal so there's one source of truth. Added registerSession() to session.ts so tools can hand back ids without duplicating the id scheme. New test drives create → unfold → check end-to-end through the real engine + WASM (also covers the step-4 kernel wiring). 17 MCP tests pass; mcp typechecks clean. cost / suggest_fix deferred (need the process-cost model + IR-edit primitives). https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Replaces the spec's "single global K-factor lie" / single shop R/t with
a real materials registry plumbed through the manufacturability query:
- New vcad-kernel-sheet::materials module: 6 curated materials
(al-soft/-hard, steel-mild, ss-304, brass, copper) with min R/t,
yield, modulus, density, and a coarse springback estimate. Lookup is
case + alias tolerant ("aluminum", "6061-T6", "stainless" all hit);
unknowns fall back to a conservative profile so checks don't silently
pass.
- check_manufacturability now uses max(material.min_r_over_t,
shop.min_bend_radius_ratio) and tags the radius violation with which
one was the stricter constraint, so the UI can explain.
- SheetMetalModel grows a `material` field, populated through the WASM
chain from the BaseFlangeRect op. Bend-table rows lowercased to one
canonical key; lookup is case-insensitive for forward-compat.
- New WASM bindings + engine helpers + MCP tools:
sheet_metal_materials and sheet_metal_bend_table — agents can inspect
what's available before authoring.
- App: material shown in the sheet-metal panel header.
52 sheet + 14 wasm + 20 mcp tests pass; clippy/fmt clean; app typecheck
clean. New MCP test proves al-hard at R/t=1 is flagged while al-soft is
shop-ready — the spec's "K-factor lie" is gone.
https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Live, line-itemed manufacturing cost — material / cut / pierce / bend / setup with shop markup — surfaced as a panel badge and as the sheet_metal_cost MCP tool. Spec strategic item #6, killing the send-to-shop-wait-three-days-for-a-quote loop. - New vcad-kernel-sheet::cost module: pure function of (model, flat, qty, rates). Mass from flat area × thickness × density (looked up via the materials registry, so changing alloy updates cost). Generic low-volume laser defaults work out of the box; rates are Deserialize + #[serde(default)] so a partial JSON merges onto generic. - WASM costSheetMetal binding + engine helper + Engine.costSheetMetal(doc, rates?, qty?) method (worker kernelModule carries it too). - App cost badge: per-unit total + expandable breakdown (material kg, cut length, pierces, bends, setup, markup) with an editable quantity for setup amortization. Recomputes live on edit. - sheet_metal_cost MCP tool: agents see which line dominates and which design changes lower the price. 57 sheet + 14 wasm + 22 mcp + 65 engine tests pass; clippy/fmt clean; app typecheck clean. https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Adds first-class hem support — 180° folds at the edge of a flange, the most common sheet-metal feature after edge flanges (~50% of real brackets have hems for stiffening / burr removal). Plumbed through every layer: - IR: new SheetMetalHem op (Rust + TS), SheetMetalHemKind (Closed | Open). All existing CsgOp matches updated. - Kernel: new vcad_kernel_sheet::hem module with add_hem(). Closed hems pack tight (R = t/2); open hems honour gap (R = gap/2). The bend's k_factor_source carries a ";hem:closed|open" tag for the UI/DXF/agent to label it. - Same lossless unfold, layered DXF, DFM check, and cost machinery pick hems up for free — they're regular bends with angle = π. - WASM chain gained a Hem variant; engine buildSheetMetalChain walks SheetMetalHem; worker post-processing already handles it. - MCP sheet_metal_create gained a `hems` array, applied in order after flanges. New end-to-end MCP test creates a hemmed bracket, unfolds it, and asserts a 180° crease in the DXF. 60 sheet + 14 wasm + 23 mcp + 65 engine tests pass; app typecheck clean. Workspace compiles green. https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Closes the AI self-heal loop. For each manufacturability violation, return the concrete parameter change that resolves it — typed fix.action plus the new numeric target: BendRadiusBelowMinimum → increase_radius (new_radius_mm) FlangeBelowMinHeight → increase_flange_length (new_length_mm) BendExceedsBrakeCapacity → shorten_or_split_bend (max_length_mm) HoleTooCloseToBend → move_hole_or_clearance (required_clearance_mm) BendsTooClose → separate_bends (required_distance_mm) With create → check → suggest_fix → re-create → re-check, an LLM agent can iterate to a manufacturable part with no human in the loop — the spec's headline AI bet. 24 MCP tests pass; mcp typechecks clean. https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Materials registry already carries springback_per_radian; now expose it on every bend so the brake operator sees the angle to actually form rather than guessing. - bend summary grows springback_rad + compensated_angle_rad = angle + springback_per_radian × angle (material-specific). - app: bend list shows "Form to 91.2° (+1.2° springback)" when non-trivial. Hems get a "Hem closed/open" label instead of "180°". - engine TS types updated; new MCP test asserts al-hard springback exceeds al-soft. Spec's springback item: data → user-visible. 25 MCP tests pass. https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Adds first-class jog support — Z-shaped offsets, the third common sheet-metal feature after flanges and hems. Plumbed end-to-end. - IR: SheetMetalJog op (Rust + TS). All existing CsgOp matches updated. - Kernel: vcad_kernel_sheet::jog::add_jog — two equal-and-opposite 90° bends; the tail panel ends up parallel to the parent and `offset` mm above. Bends tagged `;jog:a` and `;jog:b` for UI labels. - WASM chain gained a Jog variant; engine buildSheetMetalChain walks SheetMetalJog; worker post-processes hem and jog the same way. - MCP sheet_metal_create gained a `jogs` array. Flanges + hems + jogs compose in one call. 63 sheet + 14 wasm + 26 mcp tests pass; clippy/fmt clean; app typecheck clean. https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Removes the rectangle-only authoring constraint. Any CCW outline (with
optional CW hole loops) is now a first-class base flange.
- IR: SheetMetalBaseFlangePolygon op (Rust + TS) with outline, holes,
thickness, material. All CsgOp matches updated.
- Kernel: base_flange_polygon_with_holes exported from
vcad-kernel-sheet (base_flange_rect now a thin wrapper). Holes flow
through the existing Panel structure, so unfold + DXF pick them up
for free.
- WASM chain gained a BaseFlangePolygon variant; engine
buildSheetMetalChain walks the IR variant.
- MCP sheet_metal_create accepts `outline` (and `holes`), taking
precedence over width/depth. Outline points can be `{x,y}` objects
or `[x,y]` pairs for agent ergonomics.
L-bracket + holed-rectangle MCP tests pass end-to-end through unfold
and into the layered DXF (1 outline + 1 hole on the CUT layer for the
holed case). 65 sheet + 14 wasm + 28 mcp tests pass; app typecheck
clean.
https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Adds a feasible press-brake bend order with rationale. - vcad-kernel-sheet::sequence::bend_sequence: outside-in BFS over the bend tree, ties broken by id. Each step has angle / radius / compensated_angle (target + springback) / hinge length plus a one-line rationale (hem first, jog members together, root-adjacent last). - sheetMetalSequence WASM binding + engine helper + Engine.sheetMetalSequence(doc) method. - sheet_metal_sequence MCP tool — agents and shop UIs get the form order directly. End-to-end MCP test on a U-channel with a hem asserts deeper bends sort first. 69 sheet + 14 wasm + 29 mcp tests pass; app typecheck clean. https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Bottom-left-fill decreasing rectangular packer — the spec's Tier-7 "Nesting" capability arriving early. - vcad-kernel-sheet::nesting: configurable stock + spacing + edge margin + 0°/90° rotation. Sorts by max-dim descending, lowest-then- leftmost fit, new sheet on no-fit. Reports per-sheet utilization and flags oversize parts as unplaceable. - nestSheetMetalParts WASM binding + engine helper + Engine.nestSheetMetalParts method. - sheet_metal_nest MCP tool: each part is either an explicit footprint or a session document_id (footprint inferred from the flat bbox of the rendered part). 75 sheet + 14 wasm + 31 mcp tests pass; app typecheck clean. NFP true-shape nesting lands in a later tier — BLFD covers the bulk of laser-cut shop work today. https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
Emits one layered DXF per stock sheet with every nested part placed
and oriented — closes the loop from nesting to shop-ready file.
- vcad-kernel-sheet::dxf::nested_dxf: takes
&[NestedPlacement {flat, sheet, dx, dy, rotated}], returns one DXF
string per stock sheet. Same CUT / BEND_UP / BEND_DOWN layers as the
single-part exporter.
- nestedSheetMetalDxf WASM binding: accepts an array of
{chain, sheet, dx_mm, dy_mm, rotated} — each part is independently
evaluated then placed.
With sheet_metal_nest returning placements and this binding turning
them into per-sheet DXF, a multi-part nested job is one tool call away
from a quote-able artifact.
77 sheet + 14 wasm tests pass; clippy/fmt clean.
https://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q
cargo fmt --check (workspace-wide, both stable and nightly) wanted the sheet-metal arm body to be a single Err(...) expression rather than a block. My local fmt only ran on -p vcad-kernel-sheet/-wasm and missed it. No behavior change.
Three small duplications crept in across hem/jog/sequence/check/wasm.
Promoted them to methods on Bend and SheetMetalModel:
- Bend::append_source_tag(suffix): hem and jog were both inlining the
same "clone or 'manual' + push" boilerplate to tag bends as hems /
jog members.
- SheetMetalModel::material_properties() -> Option<MaterialProperties>:
manufacturability checks were doing the empty-material branching by
hand.
- SheetMetalModel::springback_per_radian() -> f64: sequence.rs and the
wasm summariser both repeated `if material.is_empty() { 0 } else {
lookup(...).springback }`.
Also dropped a dead `_point2_witness` placeholder + its now-unused
Point2 import in sequence.rs, and simplified a "let _ = w; let _ = h;"
in dxf::nested_dxf where only the height was actually used.
No behaviour change. 77 sheet + 14 wasm tests still pass; clippy clean;
workspace-wide cargo fmt --check clean (the same invocation CI uses).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the complete sheet-metal manufacturing pipeline as MCP tools and kernel operations, enabling AI agents to design, validate, cost, and nest sheet-metal parts. Adds manufacturability checking, cost estimation, bend sequencing, and multi-part nesting as queryable interfaces on the model.
Key Changes
MCP Tools (
packages/mcp/src/tools/sheet-metal.ts)sheet_metal_create— Build a sheet-metal part from base flange + edge flanges/hems/jogs; returns document ID + ambient DFM violationssheet_metal_unfold— Generate flat pattern and layered DXF (CUT/BEND_UP/BEND_DOWN) ready for laser bureaussheet_metal_check— Re-run manufacturability against caller-supplied shop profile; structured violation output for agent self-healingsheet_metal_materials— Registry of six shop-standard alloys with mechanical propertiessheet_metal_bend_table— K-factor lookup table (material × thickness × radius)sheet_metal_cost— Estimate manufacturing cost (material + cut + pierce + bend + setup)sheet_metal_sequence— Optimal bend order (outside-in heuristic for press-brake forming)sheet_metal_nest— Pack multiple parts onto stock sheets (BLFD algorithm)sheet_metal_suggest_fix— Deferred; structured violations already enable agent self-healingKernel Operations
crates/vcad-kernel-sheet/src/hem.rs) — 180° folds (closed/open variants) for edge stiffeningcrates/vcad-kernel-sheet/src/jog.rs) — Z-shaped offsets via two opposite 90° bendscrates/vcad-kernel-sheet/src/base_flange.rs) — Arbitrary CCW outline + CW holes instead of just rectanglescrates/vcad-kernel-sheet/src/manufacturability.rs) — Foundation-tier rules: bend radius, brake capacity, flange height, hole-to-bend distance, bend-to-bend spacingcrates/vcad-kernel-sheet/src/cost.rs) — Material + cut + pierce + bend + setup with configurable shop ratescrates/vcad-kernel-sheet/src/sequence.rs) — Outside-in ordering for collision-free formingcrates/vcad-kernel-sheet/src/nesting.rs) — Bottom-Left Fill Decreasing (BLFD) rectangular packingcrates/vcad-kernel-sheet/src/dxf.rs) — Layered R12 output (CUT/BEND_UP/BEND_DOWN) for laser bureauscrates/vcad-kernel-sheet/src/materials.rs) — Curated properties (Al-soft, Al-hard, Steel-mild, SS-304, Copper, Titanium)Engine & WASM Bindings
packages/engine/src/sheet-metal.ts— TypeScript wrappers for all kernel operationscrates/vcad-kernel-wasm/src/sheet_metal.rs— WASM bindings for evaluate, check, cost, sequence, nest, materials, bend tablepackages/kernel-wasm/vcad_kernel_wasm.d.ts— Type definitions for WASM exportsIR & Evaluation
packages/ir/src/index.ts— TypeScript types forSheetMetalBaseFlangePolygon,SheetMetalHem,SheetMetalJogoperationscrates/vcad-ir/src/lib.rs— IR enum variants for polygon base, hem, jogcrates/vcad-eval/src/evaluate.rsand other consumers (return `Nonehttps://claude.ai/code/session_01XR7wgpwQdW2GdQYH3Sk43q