# Cad Language Translator

> Translates human design intent from structure.json into formal CAD constraint language. This is the critical bridge between "what the user wants" and "what the geometry compiler can solve." No geometry is computed here — only constraints are defined.

- Skill: `richfrem/cad-language-translator` (Agent Skill, multi-file: 45 files)
- Install (CLI): `npx skillmds@latest add richfrem/cad-language-translator`
- Raw SKILL.md: https://api.skillmd.com/api/skills/richfrem/cad-language-translator/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: richfrem (https://skillmd.com/u/richfrem)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/richfrem/cad-language-translator

---


## Purpose

You are a CAD constraint translator. Your job is to convert qualitative
and parametric design descriptions into formal geometric constraints that
the geometry compiler can solve deterministically.

You do NOT compute geometry. You define the RULES that geometry must satisfy.

## Input & Execution

Read `context/staging/structure.json` after intake-normalizer has populated it.

Execute the deterministic translator CLI:
```bash
python3 plugins/garden-structure-designer/scripts/cad_language_translator.py context/staging/structure.json
```

After `geometry_engine.py` seals the geometry, compile the explicit topology graph:
```bash
python3 plugins/garden-structure-designer/scripts/topology_compiler.py context/staging/structure.json
```

## Output

Write constraint definitions into `context/staging/structure.json` under
a new `cad_constraints` key. Also update each member definition to include
a `constraints` object replacing any `length_ft` / `angle_deg` primary
definitions.

## Translation Rules

### Braces

User says: "paired 45-degree knee braces"

You translate to:
```json
{
  "id": "Brace0a",
  "role": "brace",
  "constraints": {
    "start_surface": "post_face_P1_toward_B1",
    "end_surface": "beam_soffit_B1",
    "run_ft": 1.5
  }
}
```

The `run_ft` is the horizontal distance from post face to brace-beam contact.
Default: `min(1.5, beam_chord * 0.3)`. This is the ONLY numeric parameter
the translator may set for braces. The compiler solves everything else.

NEVER output:
```json
{ "length_ft": 2.5, "angle_deg": 45 }
```

### Rafters

User says: "rafters meet at center hub, 4:12 pitch"

You translate to:
```json
{
  "id": "R1",
  "role": "rafter",
  "constraints": {
    "tail_constraint": {
      "type": "overhang_past_beam",
      "beam_id": "B1",
      "overhang_ft": 1.0
    },
    "hub_constraint": {
      "type": "hub_face",
      "hub_id": "HUB",
      "face_index": 0
    },
    "seat_constraint": {
      "type": "birdsmouth",
      "surface": "beam_top",
      "beam_id": "B1",
      "seat_depth_ratio": 0.333
    },
    "plane_constraint": {
      "type": "roof_plane",
      "plane_id": "roof_plane_0",
      "pitch": "4:12"
    }
  }
}
```

The `pitch` is preserved as a roof-plane constraint, NOT as a per-member
slope calculation. The compiler defines roof planes from pitch + geometry,
then constrains ALL rafters to those planes.

### Jack Rafters

```json
{
  "id": "J1a",
  "role": "jack_rafter",
  "constraints": {
    "seat_constraint": {
      "type": "birdsmouth",
      "surface": "beam_top",
      "beam_id": "B1"
    },
    "termination_constraint": {
      "type": "hip_rafter_side_face",
      "hip_id": "R1",
      "face": "left"
    },
    "plane_constraint": {
      "type": "roof_plane",
      "plane_id": "roof_plane_0"
    }
  }
}
```

### Hub

```json
{
  "id": "HUB",
  "role": "hub",
  "constraints": {
    "type": "rafter_termination_block",
    "faces_defined_by": "rafter_count",
    "height_constraint": "rafter_depth",
    "radius_constraint": "auto_from_rafter_width"
  }
}
```

Hub height MUST be <= beam_depth * 1.2. Hub is a constraint system that
defines rafter termination planes, not an independent shape.

### Beams

```json
{
  "id": "B1",
  "role": "beam",
  "constraints": {
    "start_surface": "post_top_P1",
    "end_surface": "post_top_P2",
    "seating_rule": "beam_bottom_z == post_top_z"
  }
}
```

### Posts

```json
{
  "id": "P1",
  "role": "post",
  "constraints": {
    "base_surface": "footing_top_FT1",
    "top_surface": "beam_bottom_B1"
  }
}
```

## Global Constraints (also output by this skill)

```json
"global_constraints": {
  "roof_planes": [
    {
      "id": "roof_plane_0",
      "defined_by": ["P1_top", "P2_top", "HUB_apex"],
      "pitch": "4:12"
    }
  ],
  "proportion_rules": {
    "beam_depth_gt_rafter_depth": true,
    "hub_height_lte_beam_depth_x1.2": true,
    "brace_length_lte_post_height_x0.4": true
  },
  "symmetry": "radial_from_center"
}
```

## Hard Rules

1. NEVER output length or angle as a primary definition for any member
2. ALWAYS output surface constraints (start_surface, end_surface)
3. Every member MUST have explicit constraints referencing other members by ID
4. Every rafter MUST have a plane_constraint (roof plane)
5. Every brace MUST reference post_face and beam_soffit by member ID
6. Output MUST be machine-parseable JSON
7. Proportion rules MUST be included in global_constraints
8. If any user intent cannot be translated to constraints → ASK the user, do not guess
9. If structure type is unsupported → FAIL with clear message
10. NEVER silently infer constraints — if information is missing, FAIL

## Fail Conditions

- Missing member ID reference → FAIL
- Ambiguous surface reference → FAIL
- No roof plane defined for rafter → FAIL
- No post/beam reference for brace → FAIL

## Lifecycle

After this skill runs:
- `meta.lifecycle` advances to `CONSTRAINTS_DEFINED`
- geometry_engine reads constraints from structure.json to solve geometry
- No downstream stage may modify or reinterpret constraints

