# WoodShop **Voice-driven conversational 3D woodworking & furniture modeler.** Talk to it like the Star Trek holodeck and watch furniture build itself: > *"Place a 6 foot 2x4, sand it, then attach a 2 foot 2x4 at 90 degrees, 10 inches from the end."* > *"Build a coffee table: a four foot by two foot frame from 2x4s, with four legs 18 inches tall standing at the corners."* You can also **attach reference(s)** (📎, drag-drop, paste, or a URL) and say *"build something like this"*: one or **several photos** (front/side/detail), a **PDF plan**, a **3D model** (STL/STEP/OBJ — rendered to an image, with its bounding box measured), or a **web-page guide** (its text is pulled). WoodShop builds a simplified, buildable interpretation in dimensional lumber. Then click **🔄 Match photo** and it renders the build from several angles, compares them to your reference, and **self-corrects** — repeat until it looks right. (Still an interpretation, not a measured replica.) Each board is real dimensional lumber (a 2x4 is modeled at its true 1.5″ × 3.5″), so the result is buildable — export to **STEP** (CAD/CNC) or **STL** (3D print), and get a **cut list with board-feet and a shopping estimate**. ## How it works WoodShop reuses the existing [CmdForge](https://gitea.brrd.tech/rob/cmdforge) tool ecosystem for everything that isn't woodworking-specific, so no wheels are reinvented: ``` woodshop-talk ── the conversational loop │ dictate ............. speech → text (CmdForge tool) │ pa-load-tools ....... wood-* → Claude schemas (CmdForge tool) │ claude -p ........... interpret → tool calls (provider) │ pa-execute-tool ..... dispatch each wood-* (CmdForge tool) │ read-aloud .......... speak confirmation (CmdForge tool) ▼ scene.json ← single source of truth (parts, joints, selection, undo) ▲ │ writes │ reads/mutates ▼ wood-* CmdForge tools woodshop-view (place/join/stand/move/...) live pyvista 3D, watches scene.json ``` The `wood-*` tools are thin wrappers over the `woodshop` CLI, so the modeling logic lives in one place and the tools double as the LLM's documented command vocabulary. ## Installation ```bash python -m venv .venv && source .venv/bin/activate pip install -e ".[gui,dev]" # 'gui' pulls build123d + pyvista + PySide6 + pyvistaqt python scripts/gen_wood_tools.py # register the wood-* CmdForge tools ``` ## Usage ### The studio (recommended) ```bash woodshop # launches the unified desktop app ``` One window with the **3D viewport** (click a board to select it; Ctrl+click to select several), a **parts panel** (list + selected-part inspector + quick-action buttons), a **numberpad control panel** (move/rotate the selection by clicking or with your keyboard's numpad — 2/4/6/8 move, 1/3/7/9 rotate, +/− raise/lower, 0/. front/iso, 5 fit), and a **command bar** where you type or push-to-talk (🎤). Mouse, keyboard, and voice all drive the same scene and the same visible selection — so "move these 4 inches", the numpad 8 key, and the move button are interchangeable, and act on every selected board at once (one undo). Menus cover New/Open/Save projects, Export STL/STEP, Save Image, Undo/Redo, camera views, and Build templates. ### Standalone tools (headless / scripting) ```bash woodshop-view & # just the live 3D window (watches the scene) woodshop-talk # just the voice/text loop; --voice to speak woodshop-talk --once "build a workbench top from five 2x6 boards 6 feet long" ``` Or drive it directly from the CLI: ```bash woodshop place 2x4 "6 ft" # place a board woodshop stand # stand it up (a leg) woodshop join p2 --to p1 --angle 90 --offset "10 in" woodshop rename "front-left leg" woodshop cutlist # bill of materials woodshop export table.step # STEP / STL export woodshop save "coffee table" # named projects woodshop open "coffee table" ``` Run `woodshop --help` for the full command list (place, join, stand, lay, rotate, move, trim, copy, rename, sand, delete, undo, clear, status, cutlist, export, save, open, projects). The active scene lives at `$WOODSHOP_SCENE` or `~/.local/share/woodshop/scene.json`; named projects in `~/.local/share/woodshop/projects/`. ## Development ```bash pytest # 200+ tests ``` Key modules: | Module | Role | |--------|------| | `scene.py` | Part/Joint/Connection/Feature/Scene model, ops, undo, persistence | | `lumber.py` | nominal → actual dimensions, material colors/defaults | | `colors.py` | color name → hex + lightness blends for the viewer | | `units.py` | parse "6 ft" / "3 ft 6 in" / "-2 ft" → inches | | `cli.py` | the `woodshop` command | | `geometry.py` | build123d solids (incl. joinery booleans) + STL/STEP export | | `cutlist.py` | quick cut list / board-feet / shopping summary | | `cutplan.py` | the deterministic keystone: kerf-aware nesting, rough/final, batch, offcut reuse | | `prices.py` | editable price book (Kent NB) + material-aware cost estimate | | `estimate.py` | project quote: consumables + labor + suggested selling price | | `inventory.py` | shop-wide event-sourced stock / offcut / build ledger | | `instructions.py` / `jigs.py` | deterministic build steps & jig suggestions | | `viewer.py` | live pyvista 3D viewport (`woodshop-view`) | | `driver.py` | conversational loop (`woodshop-talk`) | | `gui/` | the unified PySide6 studio (`woodshop-gui`), incl. the Cut List & BOM window | | `scripts/gen_wood_tools.py` | (re)generate the `wood-*` CmdForge tools | ### Known limitations - **Joinery** is parametric (tenon/mortise/dado/rabbet/hole/slot/chamfer as build123d boolean ops, with connections/assemblies); what's *not* modeled is joinery-fit compensation for material lost to sanding, and lap/pocket-hole presets. Boards still attach as flush butt joints unless you add features. - Render is flat colors per material/finish — no image textures (wood grain) yet. - Command interpretation latency is ~7–13s per utterance (one `claude -p` call). ## License MIT