Skip to content

QuantumGlitch/casacob

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

87 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CasaCOB Designer

CasaCOB Designer is a parametric design engine for modular cob (monolithic earth-straw construction) roundhouses, enabling architects and builders to explore sustainable, customizable structural and aesthetic configurations through an integrated 3D design interface and geometric validation pipeline.

From a single JSON parameter file it derives every coordinate, angle, length, volume and quantity of a circular cob house — foundation, walls with openings, timber posts, ring beam and a reciprocal-frame roof — and produces 2D drawings, a 3D model, CAD/mesh exports (STL/OBJ/STEP/DXF/SVG), a bill of materials, a timber cut list and a bilingual (IT/EN) construction report (PDF). No empirical constants in the geometry — every dimension, angle, length and volume is derived analytically; material properties are cited, overridable parameters (see docs/formulas.md).

Screenshot

Install

Requires Python 3.13 and uv.

uv sync

Quickstart

CLI — build the full artifact pipeline from the bundled example project:

uv run casacob validate examples/roundhouse.json
uv run casacob check examples/roundhouse.json
uv run casacob build examples/roundhouse.json --out out/
uv run casacob report examples/roundhouse.json --out out/
  • validate loads and solves the project and prints key derived figures (net cob wall volume, ridge height, rafter axis length, contact shim/notch).
  • check runs the full design validator (collisions + geometric invariants) and prints its report; exits 3 on any error, writes nothing.
  • build runs the same validator first (nothing is written on a validation error, exit 3) and then writes every artifact under --out: mesh/CAD exports (STL/OBJ/STEP/DXF/SVG), dimensioned 2D drawings, a costed bill of materials (CSV+JSON), a 36-piece per-piece cut list (CSV), a coordinate dump, the collision census (collision_report.json) and validator report (validation.json), per-piece shop drawings (shop_drawings.pdf), and the bilingual PDF construction report (report.pdf, with a validation summary, tool/time estimates and an illustrated 15-step assembly sequence).
  • report writes only the PDF construction report under --out, gated by the same validator.
  • See CLI commands below for export-part, status and log.

Example project figures (examples/roundhouse.json, from casacob validate and casacob build):

Figure Value
Net cob wall volume 17.301 m³
Ridge height 4.928 m
Rafter axis length 3.834 m
Contact shim thickness 1.1 mm
Cut-list pieces 36
Assembly sequence 15 steps, 24.63 person-days
Estimated total material cost 1957.17 EUR

UI — open the interactive designer (loads examples/roundhouse.json by default, or the file passed as an argument):

uv run python -m casacob.main [file.json]

Construction engine (v2.0)

v2.0 turns the parametric modeller into a construction engine: every element now knows its own identity, mass, connections, machining operations and site status — not just its geometry.

  • Digital twin. Every physical element (wall, foundation, post, ring beam segment, rafter, opening, joint) is a Component (core/component.py, core/registry.py) with a deterministic UUID (uuid5 of a fixed namespace and the element's graph node id — stable across regenerations and machines, see docs/formulas.md), mass, world bounding box, centroid, placement transform, connections to its neighbours and machining operations. Site build progress is tracked per component in a JSON sidecar (casacob status), and every parameter save is recorded in a changelog sidecar (casacob log) — the project JSON itself always stays the single source of geometric truth.
  • Carpentry. Rafters are defined by their three construction points — P1 (bearing on the ring beam), P2 (support on the previous rafter), P3 (free eaves end) — with the central roof opening a derived polygon, never an input (see docs/formulas.md). The rafter-to-ring-beam bearing is cut as a birdsmouth seat by default (IRC-cited depth cap), the ring beam is an autonomous per-segment component with its own bolt drill operations and optional steel gusset plates (hardware.steel_plates), and any single connection's joint kind can be overridden per project (joints_overrides).
  • Analysis. A two-stage collision detector (AABB broad phase in pure core, exact CAD boolean narrow phase) classifies every measured contact as expected (a joint's own cut accounts for the overlap) or interference (a real design conflict — e.g. an opening placed over a post). A blocking validator runs before every export (build, export-part, and every UI export/report action): on any error nothing is written, the CLI exits 3, and casacob check can be run standalone.
  • Workshop outputs. A per-piece cut list with every drill/notch/end-cut called out, illustrated single-part shop drawings collected into shop_drawings.pdf, a costed bill of materials decomposed into the cob recipe (earth/straw/sand), tool checklists and person-day estimates per phase (core/costing.py, core/labor.py, core/tools.py), and an illustrated assembly sequence with prop/closing notes for the reciprocal roof's closing cycle. Every physical part can be exported individually or all at once (casacob export-part, or the UI's component tree panel).

UI preview tabs (v2.1)

v2.1 adds an "Anteprime" toolbar to the interactive designer, alongside the existing Apri/Salva JSON/Rigenera/per-format-export toolbar. Seven buttons — one per registered preview — open closable tabs in the centre panel on demand; a second click on the same button focuses the tab already open rather than duplicating it, and each preview tab can be closed individually (unlike the always-open 3D/2D tabs). Every tab shows a live, read-only render of one build output plus its own Esporta button:

Toolbar button (preview id) Content shown Esporta writes
Bill of Materials (bom) Table: Categoria, Descrizione, Quantità, Unità, Costo € bom.csv
Cut List (cut_list) Table: ID, Tipo, Materiale, Sezione, Lungh. m, Massa kg, Taglio in., Taglio fin., Fori, Scassi cut_list.csv
Assembly Sequence (assembly) Table: N., Fase, Componenti, Utensili, Giorni-persona assembly.csv (preview-only export — not part of the full bundle below; the same sequence is already embedded in report.pdf)
Coordinates (coordinates) Pretty-printed JSON coordinate dump (read-only) coordinates.json
Collisions (collisions) Pretty-printed JSON collision census (read-only) collision_report.json
Validation (validation) Table: Gravità, Regola, Componente, Messaggio validation.json
Shop Drawings (shop_drawings) Part picker + canvas rendering one piece's dimensioned drawing at a time Esporta menu has two entries: "Tutte (PDF)" (every piece, shop_drawings.pdf) or "Pezzo mostrato" (only the shown piece, saved as SVG or PDF by extension)

Opening a preview is never blocked by validation — the Collisions/Validation tabs exist precisely so an author can see why a model fails — but every Esporta action is validation-gated exactly like the existing whole-house exports: on a validation error the red banner reports the error count ("Validazione fallita: N errori — export bloccato") and nothing is written. The per-tab Esporta buttons open the file save dialog first, then validate; the toolbar's Esporta tutto validates before opening any dialog.

Esporta tutto writes the full 20-file build bundle into a chosen folder, byte-identical to the CLI's build command: the three combined CAD exports (house.stl/.obj/.step), plan/section DXF+SVG, the costed BOM (CSV+JSON), the cut list, the coordinate dump, the collision and validation reports, report.pdf, shop_drawings.pdf, and the illustrated drawings/ set (plan/section/elevation SVG, axonometry/exploded PNG).

Language / Lingua (v2.2)

Every human-facing string produced by CasaCOB Designer — UI labels and menus, BOM/cut-list/assembly-sequence descriptions, validation messages, and the PDF construction report — is drawn from a single catalog (core/i18n/catalog.py, LABELS: {id: {it, en}}) through a Translator. Machine identifiers are never translated and stay identical across languages: JSON keys, the BOM category slug, cut-list piece_id/kind/material/section, graph node ids (e.g. rafter:3), JointKind values, validation rule slugs, and the full contents of coordinates.json/collision_report.json. Only descriptions, headings, messages and UI chrome change with the active language.

The active language is resolved with this precedence (first non-null value wins): **CLI --lang / UI "Lingua" menu selection > persisted UI settings

project report.language > default "it".**

  • UI "Lingua / Language" menu — a menubar menu with two checkable entries ("Italiano"/"English"). Selecting one switches every open widget's text live (form labels, tabs, table headers, previews) and persists the choice to ~/.casacob/settings.json ({"language": "it"} or {"language": "en"}), so the next UI launch reopens in the same language regardless of which project is loaded. A corrupt or unreadable settings file is reported in the error banner rather than crashing the window; that session falls back to the project's report.language (or the default).
  • CLI --lang {it,en} — accepted on every subcommand, either before or after it (casacob --lang en build ... and casacob build ... --lang en both work); overrides the language for that invocation only and is never persisted. The CLI does not consult ~/.casacob/settings.json (that file only backs the UI menu), so for CLI runs the effective order is --lang > project report.language > "it".
  • Project report.language — the optional "it"/"en" field in the project JSON's report object (see JSON schema below); the project's own default whenever no CLI flag, menu selection or settings-file value applies.

Example — build the same project in both languages:

uv run casacob build examples/roundhouse.json --lang en --out out/

produces the identical 20-artifact bundle as an it build — same category/piece_id/rule slugs, same JSON keys, same coordinates.json/collision_report.json content — with every description/message/heading (bom.csv, cut_list.csv, validation.json, report.pdf) rendered in English instead of Italian.

CLI commands

Every subcommand takes the project JSON path as its first argument; build/report/export-part additionally require --out. A ParameterError/GeometryError while loading or solving the project maps to a printed message and exit code 2; build/report/export-part additionally run the full validator FIRST and exit 3 (nothing written) on any validation error.

Command What it does
validate <json> Loads and solves the project, prints key derived figures.
check <json> Runs the full validator (collisions + geometric invariants) and prints its report (errors, then warnings, then "OK"); exit 0 clean, exit 3 on any error. Writes nothing.
build <json> --out DIR Writes every artifact (see Quickstart above).
report <json> --out DIR Writes only report.pdf.
export-part <json> --part <node_id>|all --format step|stl|dxf|svg --out DIR Exports one physical part (e.g. rafter:3) or every solid-bearing part (--part all) to its own file. STEP/STL export the built solid with its machining operations applied; DXF/SVG render a dimensioned single-part shop drawing (only available for posts/ring beam segments/rafters — a single wall/foundation DXF/SVG request exits 2; under --part all those two are silently skipped with a printed note).
status <json> [--set NODE_ID STATUS] Prints one row per component (node id, kind, short uuid, status); --set updates one component's status (planned/cut/installed/verified) and saves the <project>.site-status.json sidecar. Orphaned sidecar entries (from a component the project no longer builds) are reported, never silently dropped.
log <json> Prints the project's parameter changelog (<project>.log.json): one block per save, each changed leaf path with its before/after value.

Examples:

uv run casacob check examples/roundhouse.json
uv run casacob export-part examples/roundhouse.json --part rafter:3 --format step --out out/parts/
uv run casacob export-part examples/roundhouse.json --part all --format stl --out out/parts/
uv run casacob status examples/roundhouse.json
uv run casacob status examples/roundhouse.json --set rafter:3 installed
uv run casacob log examples/roundhouse.json

JSON schema

All lengths in metres, all masses in kilograms, angles in the JSON file are expressed in degrees (converted to radians at load time). Every constraint below is enforced by the loader (src/casacob/core/loader.py), which raises a ParameterError naming the JSON path and the violated rule.

room (required)

Field Unit Constraint
type informational only, currently ignored (v0.1 supports circular rooms only)
inner_diameter m > 0
wall_thickness m > 0
wall_height m > 0

openings (optional array, default [])

Each entry:

Field Unit Constraint
kind "door" or "window"
azimuth_deg deg any value (CCW from +X, not restricted to [0, 360))
width m > 0
height m > 0
sill_height m optional, default 0; ≥ 0

Cross-field: sill_height + height must be ≤ room.wall_height; the angular spans of all openings on the wall centerline circle must not overlap.

foundation (required)

Field Unit Constraint
depth m > 0
width m > 0
gravel_depth m > 0, and < foundation.depth
geotextile_overlap m > 0

posts (required)

Field Unit Constraint
count integer ≥ 3
diameter m > 0
length m > 0, and ≥ room.wall_height + posts.embedment
embedment m > 0

roof (required)

Field Unit Constraint
type only "reciprocal" is supported in v0.1
rafters integer ≥ 3
slope_deg deg > 0
eaves m > 0
timber_section [width, depth] (m) array of exactly 2 numbers, each > 0
central_opening_radius m > 0, and central_opening_radius + timber_width/2 < room.centerline_radius
max_shim m optional, default 0.02; ≥ 0. If the solved rafter-contact shim exceeds it, a GeometryError is raised with the maximum feasible slope
chamfer m optional, default 0; ≥ 0. When > 0, emits 4 chamfer machining operations per rafter (edge-break of this size); 0 emits none

hardware (optional)

Fastener choices shared by every generated joint (core/joints.py).

Field Unit Constraint
bolt_diameter m optional, default 0.012; > 0. Diameter of every bearing/steel-plate drill operation
steel_plates optional boolean, default false. When true, each ring beam vertex additionally gets a steel gusset plate (STEEL_PLATE joint) reinforcing the half-lap

materials (optional; overrides the literature-sourced defaults in core/materials/*.py)

Field Unit Default
cob.density kg/m³ 1700
cob.specific_heat J/(kg·K) 1000
timber.density kg/m³ 550
stone.density kg/m³ 1600
cob.recipe.earth fraction 0.5
cob.recipe.straw fraction 0.2
cob.recipe.sand fraction 0.3

cob.recipe (volumetric mix ratios of the wet cob batch, see docs/formulas.md) is all-or-nothing: when present, earth/straw/sand are all required, each > 0, and must sum to 1.0 within 1e-6.

costs (optional; overrides the cited defaults in core/costing.py)

An object of {category: unit_price}; every key must already be one of the categories below (an unknown key is a ParameterError), each value > 0 (the category's unit is fixed, never overridable). Defaults are indicative Italian market prices, 2026 — see docs/formulas.md for the full cited table (earth, sand, straw_bale, rubble_stone, gravel, geotextile, drain_pipe, timber, bolts, structural_screws, steel_plates).

labor (optional; overrides the cited defaults in core/labor.py)

An object of {phase: productivity} (units per person-day); every key must already be one of the phases below (an unknown key is a ParameterError), each value > 0. Defaults are indicative planning figures — see docs/formulas.md for the full cited table (excavation, stone_fill, cob_lift, timber_prep, assembly).

joints_overrides (optional array, default [])

Each entry swaps one connection's default joint kind:

Field Unit Constraint
connection array of exactly 2 node-id strings, e.g. ["rafter:3", "ringbeam_segment:2"] (order-insensitive; "ringbeam"/"ringbeam_segment" both denote a ring beam segment host)
joint one of the JointKind values (half_lap, saddle, mortise, tenon, birdsmouth, plus the hardware-only bolt/structural_screw/steel_plate, which are never meaningful override targets)

A connection naming a pair with no matching joint raises a GeometryError (at model-build time, listing how many connections are actually available) rather than a loader ParameterError, since matching requires the solved joint census.

report (optional)

Field Unit Constraint
language optional, default "it"; "it" or "en"

See examples/roundhouse.json for a complete, valid project file, docs/formulas.md for every formula derived from these parameters, and docs/superpowers/specs/2026-07-19-casacob-v2-design.md for the v2.0 design spec (docs/superpowers/specs/2026-07-18-casacob-designer-design.md for the original v0.1 spec).

Architecture

Clean Architecture, two layers plus composition roots. Dependencies point inward only: core never imports adapters, ui, cli.py or main.py; adapters depend on core but not on each other; ui/cli.py depend on both and wire everything together.

src/casacob/
  core/                 # PURE domain: numpy/scipy/shapely/networkx only, no I/O, no CAD, no Qt
    params.py           # frozen parameter dataclasses (validated ProjectParams)
    loader.py           # JSON -> ProjectParams (validation)
    model.py            # build_model(params) -> HouseModel (the one entry point)
    component.py        # digital-twin primitives: Operation, ConnectionRef, Component, UUIDs
    registry.py          # ComponentRegistry: builds one Component per physical element
    joints.py            # timber joint library + joint census (birdsmouth, half-lap, steel plate...)
    site_status.py       # per-component site-status sidecar (planned/cut/installed/verified)
    project_log.py       # project parameter changelog sidecar
    validation.py        # blocking pre-export validator (collisions + geometric invariants)
    analysis/            # two-stage AABB/CAD collision detection + classification
    costing.py           # cited unit-price defaults + override resolution
    labor.py             # cited labour-productivity defaults + override resolution
    tools.py             # hand/power tool checklists per machining operation / build phase
    geometry/           # circle, regular polygon, 3D frame/transform primitives
    walls/              # cob wall, openings, posts
    foundation/         # trench, rubble fill, drainage
    roof/               # reciprocal frame solver (P1/P2/P3 rafters), ring beam
    materials/          # literature-sourced material defaults + cob recipe
    reports/            # BOM, per-piece cut list, assembly sequence, coordinate dump (pure data)
  adapters/              # turn core data into artifacts
    cad/                # cadquery: solids, STEP/DXF/SVG export, interference measurement
    mesh/               # trimesh: STL/OBJ export, viewport meshes
    drawing2d/          # matplotlib: dimensioned plan/section/elevation/axonometry/exploded/parts
    pdf/                # reportlab: bilingual (IT/EN) construction report + shop drawings PDF
    export_part.py       # single-part STEP/STL/DXF/SVG export, shared by the CLI and the UI
  ui/                    # PySide6 main window (incl. component tree + per-item export),
                          # parameter form, 3D viewport, 2D tab
  cli.py                 # composition root (headless): validate|check|build|report|export-part|status|log
  main.py                # composition root (GUI)
   JSON  --loader.py-->  ProjectParams  --model.py-->  HouseModel  --adapters-->  artifacts
                              (core, pure)               (+ ComponentRegistry)        ^
                                                                              cli.py / main.py
                                                                            (composition roots)

Development

uv run ruff check .
uv run ruff format --check .
uv run mypy src
uv run pytest

All four must pass clean. Package-wide coverage is enforced at ≥ 90% (pytest-cov's --cov-fail-under=90, see pyproject.toml); src/casacob/core itself currently runs at ~98%.

Roadmap

Not in v2.0, but the architecture is designed not to block (unchanged since v0.1 — see docs/superpowers/specs/2026-07-19-casacob-v2-design.md's Non-goals):

  • Multi-room/corridor layouts (new nodes in the component graph)
  • Curved free walls
  • Domes and other roof types (new RoofBuilder strategies behind the same interface)
  • Load analysis and assembly simulation
  • MEP / PV / water systems (new component families + BOM sections)
  • Greenhouse/off-grid modules
  • BIM export (the v2.0 component registry — stable UUIDs, mass, connections, operations — is designed as its seed)
  • FreeCAD/OpenCascade adapter as an alternative SolidBackend

License

MIT — see LICENSE.


CasaCOB Designer (italiano)

CasaCOB Designer è un motore di progettazione parametrica per case circolari in terra cruda (COB) modulare, che consente ad architetti e costruttori di esplorare configurazioni strutturali e estetiche sostenibili e personalizzabili attraverso un'interfaccia di progettazione 3D integrata e una pipeline di validazione geometrica.

A partire da un unico file JSON di parametri, il motore deriva ogni coordinata, angolo, lunghezza, volume e quantità di una casa circolare in cob — fondazione, pareti con aperture, pali in legno, cordolo (ring beam) e tetto a struttura reciproca — e produce disegni 2D, un modello 3D, export CAD/mesh (STL/OBJ/STEP/DXF/SVG), un computo metrico dei materiali, una distinta di taglio del legname e una relazione di cantiere bilingue (IT/EN) in PDF. Nessuna costante empirica nella geometria — ogni dimensione, angolo, lunghezza e volume è derivato analiticamente; le proprietà dei materiali sono parametri sovrascrivibili con fonte citata (vedi docs/formulas.md).

Screenshot

Installazione

Richiede Python 3.13 e uv.

uv sync

Avvio rapido

CLI — genera l'intera pipeline di output a partire dal progetto di esempio incluso:

uv run casacob validate examples/roundhouse.json
uv run casacob check examples/roundhouse.json
uv run casacob build examples/roundhouse.json --out out/
uv run casacob report examples/roundhouse.json --out out/
  • validate carica e risolve il progetto stampando le grandezze derivate principali (volume netto della parete in cob, altezza di colmo, lunghezza asse della falda, spessore dello spessoramento/intaglio di contatto).
  • check esegue il validatore completo (collisioni + invarianti geometrici) e ne stampa il report; esce con codice 3 in presenza di errori, senza scrivere nulla.
  • build esegue prima lo stesso validatore (nulla viene scritto in caso di errore, uscita 3) e poi scrive tutti gli output in --out: export mesh/CAD (STL/OBJ/STEP/DXF/SVG), disegni 2D quotati, un computo metrico con costi (CSV+JSON), una distinta di taglio per singolo pezzo di 36 elementi (CSV), un dump delle coordinate, il censimento delle collisioni (collision_report.json) e il report di validazione (validation.json), i disegni di officina per singolo pezzo (shop_drawings.pdf) e la relazione PDF bilingue di cantiere (report.pdf, con sommario di validazione, stima di attrezzi/tempi e sequenza di montaggio illustrata in 15 fasi).
  • report scrive solo la relazione PDF di cantiere in --out, con lo stesso controllo del validatore.
  • Vedi Comandi CLI più sotto per export-part, status e log.

Grandezze del progetto di esempio (examples/roundhouse.json, da casacob validate e casacob build):

Grandezza Valore
Volume netto parete in cob 17,301 m³
Altezza di colmo 4,928 m
Lunghezza asse falda 3,834 m
Spessore spessoramento di contatto 1,1 mm
Pezzi nella distinta di taglio 36
Sequenza di montaggio 15 fasi, 24,63 persona-giorno
Costo totale stimato dei materiali 1957,17 EUR

UI — apre l'interfaccia grafica del designer (carica di default examples/roundhouse.json, oppure il file passato come argomento):

uv run python -m casacob.main [file.json]

Motore costruttivo (v2.0)

La v2.0 trasforma il modellatore parametrico in un motore costruttivo: ogni elemento conosce ora la propria identità, massa, connessioni, lavorazioni e stato di cantiere — non solo la propria geometria.

  • Gemello digitale. Ogni elemento fisico (parete, fondazione, palo, segmento di cordolo, trave, apertura, giunto) è un Component (core/component.py, core/registry.py) con un UUID deterministico (uuid5 di un namespace fisso e dell'id nodo del grafo dell'elemento — stabile tra rigenerazioni e macchine diverse, vedi docs/formulas.md), massa, bounding box mondiale, centroide, trasformazione di posizionamento, connessioni con gli elementi vicini e lavorazioni di officina. L'avanzamento di cantiere per componente è tracciato in un file sidecar JSON (casacob status), e ogni salvataggio dei parametri viene registrato in un changelog sidecar (casacob log) — il file JSON del progetto resta sempre l'unica fonte di verità geometrica.
  • Carpenteria. Le travi sono definite dai loro tre punti costruttivi — P1 (appoggio sul cordolo), P2 (appoggio sulla trave precedente), P3 (estremità libera di gronda) — con l'apertura centrale del tetto poligono derivato, mai un dato di ingresso (vedi docs/formulas.md). L'appoggio trave-cordolo è tagliato di default a incastro birdsmouth (profondità massima citata da normativa IRC), il cordolo è un componente autonomo per segmento con proprie forature per bulloni e piastre di acciaio opzionali (hardware.steel_plates), e il tipo di giunto di ogni singola connessione può essere sovrascritto per progetto (joints_overrides).
  • Analisi. Un rilevatore di collisioni a due stadi (AABB nel core puro, booleano CAD esatto per la fase stretta) classifica ogni contatto misurato come atteso (il taglio del giunto ne rende conto) o interferenza (un vero conflitto di progetto — es. un'apertura posta sopra un palo). Un validatore bloccante viene eseguito prima di ogni esportazione (build, export-part, e ogni azione di esportazione/relazione della UI): in presenza di errori non viene scritto nulla, la CLI esce con codice 3, e casacob check può essere eseguito da solo.
  • Output di officina. Una distinta di taglio per singolo pezzo con ogni foro/intaglio/taglio di testa esplicitato, disegni di officina per singolo pezzo raccolti in shop_drawings.pdf, un computo metrico con costi scomposto nella ricetta del cob (terra/paglia/sabbia), checklist degli attrezzi e stime in persona-giorno per fase (core/costing.py, core/labor.py, core/tools.py), e una sequenza di montaggio illustrata con note su puntellamento e chiusura del ciclo reciproco del tetto. Ogni pezzo fisico può essere esportato singolarmente o tutti insieme (casacob export-part, oppure il pannello ad albero dei componenti della UI).

Schede di anteprima nella UI (v2.1)

La v2.1 aggiunge alla UI interattiva una barra strumenti "Anteprime", accanto alla barra esistente Apri/Salva JSON/Rigenera/export per formato. Sette pulsanti — uno per ogni anteprima registrata — aprono su richiesta schede chiudibili nel pannello centrale; un secondo clic sullo stesso pulsante porta in primo piano la scheda già aperta invece di duplicarla, e ogni scheda di anteprima può essere chiusa singolarmente (a differenza delle schede sempre aperte 3D/2D). Ogni scheda mostra il rendering di sola lettura di un output di build, con un proprio pulsante Esporta:

Pulsante in barra (id anteprima) Contenuto mostrato Esporta scrive
Bill of Materials (bom) Tabella: Categoria, Descrizione, Quantità, Unità, Costo € bom.csv
Cut List (cut_list) Tabella: ID, Tipo, Materiale, Sezione, Lungh. m, Massa kg, Taglio in., Taglio fin., Fori, Scassi cut_list.csv
Assembly Sequence (assembly) Tabella: N., Fase, Componenti, Utensili, Giorni-persona assembly.csv (export solo-anteprima — non fa parte del pacchetto completo sotto; la stessa sequenza è già incorporata in report.pdf)
Coordinates (coordinates) Dump JSON di sola lettura delle coordinate coordinates.json
Collisions (collisions) Censimento collisioni in JSON di sola lettura collision_report.json
Validation (validation) Tabella: Gravità, Regola, Componente, Messaggio validation.json
Shop Drawings (shop_drawings) Selettore pezzo + canvas che disegna, quotato, un pezzo alla volta Il menu Esporta ha due voci: "Tutte (PDF)" (ogni pezzo, shop_drawings.pdf) oppure "Pezzo mostrato" (solo il pezzo visualizzato, salvato come SVG o PDF in base all'estensione)

L'apertura di un'anteprima non è mai bloccata dalla validazione — le schede Collisions/Validation esistono proprio perché l'autore possa vedere perché un modello fallisce — ma ogni azione Esporta è vincolata alla validazione esattamente come le esportazioni dell'intera casa già esistenti: in caso di errore di validazione il banner rosso riporta il numero di errori ("Validazione fallita: N errori — export bloccato") e non viene scritto nulla. I pulsanti Esporta per singola scheda aprono prima la finestra di salvataggio file, poi convalidano; il pulsante Esporta tutto della barra strumenti convalida prima di aprire qualsiasi finestra di dialogo.

Esporta tutto scrive l'intero pacchetto di 20 file di build in una cartella scelta, identico byte-per-byte a quello del comando CLI build: i tre export CAD combinati (house.stl/.obj/.step), DXF+SVG di pianta/sezione, il computo metrico con costi (CSV+JSON), la distinta di taglio, il dump delle coordinate, i report di collisioni e validazione, report.pdf, shop_drawings.pdf e la serie illustrata drawings/ (SVG di pianta/sezione/prospetto, PNG di assonometria/esploso).

Lingua / Language (v2.2)

Ogni stringa rivolta all'utente prodotta da CasaCOB Designer — etichette e menu della UI, descrizioni di computo metrico/distinta di taglio/sequenza di montaggio, messaggi di validazione e la relazione PDF di cantiere — proviene da un unico catalogo (core/i18n/catalog.py, LABELS: {id: {it, en}}) tramite un Translator. Gli identificatori macchina non vengono mai tradotti e restano identici in entrambe le lingue: chiavi JSON, lo slug category del computo metrico, piece_id/kind/material/section della distinta di taglio, gli id nodo del grafo (es. rafter:3), i valori JointKind, gli slug rule di validazione, e l'intero contenuto di coordinates.json/collision_report.json. Solo descrizioni, intestazioni, messaggi e testi dell'interfaccia cambiano con la lingua attiva.

La lingua attiva viene risolta con questa precedenza (vince il primo valore non nullo): selezione da --lang CLI / menu "Lingua" della UI > impostazioni UI persistite > report.language di progetto > default "it".

  • Menu UI "Lingua / Language" — un menu in barra dei menu con due voci selezionabili ("Italiano"/"English"). Selezionarne una cambia dal vivo il testo di ogni widget aperto (etichette del form, schede, intestazioni di tabella, anteprime) e salva la scelta in ~/.casacob/settings.json ({"language": "it"} oppure {"language": "en"}), cosicché il successivo avvio della UI riparta nella stessa lingua indipendentemente dal progetto caricato. Un file impostazioni corrotto o illeggibile viene segnalato nel banner di errore invece di far crashare la finestra; per quella sessione si ricade su report.language del progetto (o sul default).
  • CLI --lang {it,en} — accettato su ogni sottocomando, sia prima sia dopo (funzionano sia casacob --lang en build ... sia casacob build ... --lang en); sovrascrive la lingua solo per quella invocazione e non viene mai salvato. La CLI non consulta ~/.casacob/settings.json (quel file serve solo al menu della UI), quindi per le esecuzioni CLI l'ordine effettivo è --lang > report.language di progetto > "it".
  • report.language di progetto — il campo opzionale "it"/"en" nell'oggetto report del JSON di progetto (vedi Schema JSON più sotto); il default del progetto stesso quando non si applica alcun valore da flag CLI, selezione menu o file impostazioni.

Esempio — genera lo stesso progetto in entrambe le lingue:

uv run casacob build examples/roundhouse.json --lang en --out out/

produce lo stesso pacchetto di 20 file di una build it — identici slug category/piece_id/rule, identiche chiavi JSON, identico contenuto di coordinates.json/collision_report.json — con ogni description/message/intestazione (bom.csv, cut_list.csv, validation.json, report.pdf) resa in inglese invece che in italiano.

Comandi CLI

Ogni sottocomando accetta il percorso del JSON di progetto come primo argomento; build/report/export-part richiedono anche --out. Un ParameterError/GeometryError durante il caricamento o la risoluzione del progetto genera un messaggio stampato e il codice di uscita 2; build/report/export-part eseguono prima il validatore completo ed escono con codice 3 (nulla viene scritto) in presenza di errori di validazione.

Comando Cosa fa
validate <json> Carica e risolve il progetto, stampa le grandezze derivate principali.
check <json> Esegue il validatore completo (collisioni + invarianti geometrici) e ne stampa il report (errori, poi avvisi, poi "OK"); uscita 0 se pulito, uscita 3 in presenza di errori. Non scrive nulla.
build <json> --out DIR Scrive tutti gli output (vedi Avvio rapido sopra).
report <json> --out DIR Scrive solo report.pdf.
export-part <json> --part <node_id>|all --format step|stl|dxf|svg --out DIR Esporta un singolo pezzo fisico (es. rafter:3) o ogni pezzo dotato di solido (--part all) nel proprio file. STEP/STL esportano il solido costruito con le lavorazioni applicate; DXF/SVG generano un disegno di officina quotato per singolo pezzo (disponibile solo per pali/segmenti di cordolo/travi — una richiesta DXF/SVG singola su wall/foundation esce con codice 2; con --part all questi due vengono saltati silenziosamente con una nota stampata).
status <json> [--set NODE_ID STATUS] Stampa una riga per componente (id nodo, tipo, uuid breve, stato); --set aggiorna lo stato di un componente (planned/cut/installed/verified) e salva il sidecar <progetto>.site-status.json. Le voci orfane del sidecar (di un componente che il progetto non genera più) sono segnalate, mai eliminate silenziosamente.
log <json> Stampa il changelog dei parametri del progetto (<progetto>.log.json): un blocco per ogni salvataggio, con ogni percorso di parametro modificato e il suo valore prima/dopo.

Esempi:

uv run casacob check examples/roundhouse.json
uv run casacob export-part examples/roundhouse.json --part rafter:3 --format step --out out/parts/
uv run casacob export-part examples/roundhouse.json --part all --format stl --out out/parts/
uv run casacob status examples/roundhouse.json
uv run casacob status examples/roundhouse.json --set rafter:3 installed
uv run casacob log examples/roundhouse.json

Schema JSON

Tutte le lunghezze sono in metri, le masse in chilogrammi, gli angoli nel file JSON sono espressi in gradi (convertiti in radianti al momento del caricamento). Ogni vincolo elencato di seguito è verificato dal loader (src/casacob/core/loader.py), che solleva un ParameterError indicando il percorso JSON e la regola violata.

room (obbligatorio)

Campo Unità Vincolo
type solo informativo, attualmente ignorato (v0.1 supporta solo stanze circolari)
inner_diameter m > 0
wall_thickness m > 0
wall_height m > 0

openings (array opzionale, default [])

Ogni elemento:

Campo Unità Vincolo
kind "door" o "window"
azimuth_deg gradi qualsiasi valore (CCW da +X, non limitato a [0, 360))
width m > 0
height m > 0
sill_height m opzionale, default 0; ≥ 0

Vincolo incrociato: sill_height + height deve essere ≤ room.wall_height; gli intervalli angolari di tutte le aperture sulla circonferenza di asse parete non devono sovrapporsi.

foundation (obbligatorio)

Campo Unità Vincolo
depth m > 0
width m > 0
gravel_depth m > 0, e < foundation.depth
geotextile_overlap m > 0

posts (obbligatorio)

Campo Unità Vincolo
count intero ≥ 3
diameter m > 0
length m > 0, e ≥ room.wall_height + posts.embedment
embedment m > 0

roof (obbligatorio)

Campo Unità Vincolo
type in v0.1 è supportato solo "reciprocal"
rafters intero ≥ 3
slope_deg gradi > 0
eaves m > 0
timber_section [larghezza, altezza] (m) array di esattamente 2 numeri, ciascuno > 0
central_opening_radius m > 0, e central_opening_radius + timber_width/2 < room.centerline_radius
max_shim m opzionale, default 0.02; ≥ 0. Se lo spessoramento di contatto risolto lo supera, viene sollevato un GeometryError con la pendenza massima ammissibile
chamfer m opzionale, default 0; ≥ 0. Se > 0, genera 4 lavorazioni chamfer per trave (smusso di questa dimensione); 0 non ne genera nessuna

hardware (opzionale)

Scelte di ferramenta condivise da ogni giunto generato (core/joints.py).

Campo Unità Vincolo
bolt_diameter m opzionale, default 0.012; > 0. Diametro di ogni foratura di appoggio/piastra
steel_plates opzionale booleano, default false. Se true, ogni vertice del cordolo riceve in aggiunta una piastra di rinforzo in acciaio (giunto STEEL_PLATE) sul mezzo-legno

materials (opzionale; sovrascrive i valori di default di letteratura in core/materials/*.py)

Campo Unità Default
cob.density kg/m³ 1700
cob.specific_heat J/(kg·K) 1000
timber.density kg/m³ 550
stone.density kg/m³ 1600
cob.recipe.earth frazione 0,5
cob.recipe.straw frazione 0,2
cob.recipe.sand frazione 0,3

cob.recipe (rapporti volumetrici della miscela umida di cob, vedi docs/formulas.md) è tutto-o-niente: se presente, earth/straw/sand sono tutti obbligatori, ciascuno > 0, e la loro somma deve fare 1,0 con tolleranza 1e-6.

costs (opzionale; sovrascrive i valori di default citati in core/costing.py)

Un oggetto {categoria: prezzo_unitario}; ogni chiave deve già essere una delle categorie sottostanti (una chiave sconosciuta genera un ParameterError), ogni valore > 0 (l'unità della categoria è fissa, mai sovrascrivibile). I default sono prezzi indicativi del mercato italiano, 2026 — vedi docs/formulas.md per la tabella completa citata (earth, sand, straw_bale, rubble_stone, gravel, geotextile, drain_pipe, timber, bolts, structural_screws, steel_plates).

labor (opzionale; sovrascrive i valori di default citati in core/labor.py)

Un oggetto {fase: produttività} (unità per persona-giorno); ogni chiave deve già essere una delle fasi sottostanti (una chiave sconosciuta genera un ParameterError), ogni valore > 0. I default sono cifre di pianificazione indicative — vedi docs/formulas.md per la tabella completa citata (excavation, stone_fill, cob_lift, timber_prep, assembly).

joints_overrides (array opzionale, default [])

Ogni elemento sostituisce il tipo di giunto di default di una connessione:

Campo Unità Vincolo
connection array di esattamente 2 stringhe id-nodo, es. ["rafter:3", "ringbeam_segment:2"] (non ordinato; "ringbeam"/"ringbeam_segment" denotano entrambi un segmento di cordolo)
joint uno dei valori JointKind (half_lap, saddle, mortise, tenon, birdsmouth, più i soli di ferramenta bolt/structural_screw/steel_plate, mai bersagli significativi di sostituzione)

Una connection che nomina una coppia senza giunto corrispondente solleva un GeometryError (in fase di costruzione del modello, elencando quante connessioni sono effettivamente disponibili), non un ParameterError del loader, poiché la corrispondenza richiede il censimento dei giunti risolto.

report (opzionale)

Campo Unità Vincolo
language opzionale, default "it"; "it" o "en"

Vedi examples/roundhouse.json per un file di progetto completo e valido, docs/formulas.md per ogni formula derivata da questi parametri, e docs/superpowers/specs/2026-07-19-casacob-v2-design.md per il documento di design v2.0 (docs/superpowers/specs/2026-07-18-casacob-designer-design.md per lo spec v0.1 originale).

Architettura

Clean Architecture, due livelli più i composition root. Le dipendenze puntano solo verso l'interno: core non importa mai adapters, ui, cli.pymain.py; gli adapter dipendono da core ma non tra loro; ui/cli.py dipendono da entrambi e li collegano.

src/casacob/
  core/                 # dominio PURO: solo numpy/scipy/shapely/networkx, nessun I/O, CAD o Qt
    params.py           # dataclass dei parametri (ProjectParams validati e immutabili)
    loader.py           # JSON -> ProjectParams (validazione)
    model.py            # build_model(params) -> HouseModel (l'unico punto di ingresso)
    component.py         # primitive del gemello digitale: Operation, ConnectionRef, Component, UUID
    registry.py           # ComponentRegistry: costruisce un Component per ogni elemento fisico
    joints.py             # libreria giunti in legno + censimento (birdsmouth, mezzo-legno, piastra...)
    site_status.py        # sidecar stato di cantiere per componente (planned/cut/installed/verified)
    project_log.py        # sidecar changelog dei parametri di progetto
    validation.py         # validatore bloccante pre-esportazione (collisioni + invarianti geometrici)
    analysis/             # rilevamento collisioni a due stadi AABB/CAD + classificazione
    costing.py            # valori di default dei prezzi unitari citati + risoluzione override
    labor.py              # valori di default di produttività citati + risoluzione override
    tools.py              # checklist attrezzi manuali/elettrici per lavorazione/fase di cantiere
    geometry/           # cerchio, poligono regolare, primitive di trasformazione 3D
    walls/              # parete in cob, aperture, pali
    foundation/          # trincea, riempimento in pietrame, drenaggio
    roof/                # solutore della struttura reciproca (travi P1/P2/P3), cordolo
    materials/           # valori di default dei materiali (fonti di letteratura) + ricetta cob
    reports/             # computo metrico, distinta di taglio per pezzo, sequenza di montaggio, dump coordinate
  adapters/               # trasformano i dati del core in output
    cad/                 # cadquery: solidi, export STEP/DXF/SVG, misura interferenze
    mesh/                # trimesh: export STL/OBJ, mesh per il viewport
    drawing2d/            # matplotlib: pianta/sezione/prospetto/assonometria/esploso/pezzi quotati
    pdf/                  # reportlab: relazione di cantiere bilingue (IT/EN) + PDF disegni di officina
    export_part.py        # export STEP/STL/DXF/SVG di un singolo pezzo, condiviso da CLI e UI
  ui/                     # finestra principale PySide6 (incl. albero componenti + export per pezzo),
                           # form parametri, viewport 3D, scheda 2D
  cli.py                  # composition root (headless): validate|check|build|report|export-part|status|log
  main.py                 # composition root (GUI)
   JSON  --loader.py-->  ProjectParams  --model.py-->  HouseModel  --adapter-->  output
                              (core, puro)               (+ ComponentRegistry)        ^
                                                                              cli.py / main.py
                                                                            (composition root)

Sviluppo

uv run ruff check .
uv run ruff format --check .
uv run mypy src
uv run pytest

Tutti e quattro i comandi devono passare senza errori. La copertura dell'intero pacchetto è imposta a ≥ 90% (--cov-fail-under=90 di pytest-cov, vedi pyproject.toml); src/casacob/core da solo è attualmente al ~98%.

Roadmap

Non presenti in v2.0, ma l'architettura è pensata per non bloccarle (invariata rispetto alla v0.1 — vedi le "Non-goals" di docs/superpowers/specs/2026-07-19-casacob-v2-design.md):

  • Configurazioni multi-stanza/corridoio (nuovi nodi nel grafo dei componenti)
  • Pareti libere curve
  • Cupole e altre tipologie di tetto (nuove strategie RoofBuilder dietro la stessa interfaccia)
  • Analisi dei carichi e simulazione del montaggio
  • Impianti MEP / fotovoltaico / idrici (nuove famiglie di componenti + sezioni del computo metrico)
  • Moduli serra/off-grid
  • Export BIM (il registro componenti v2.0 — UUID stabili, massa, connessioni, lavorazioni — è pensato come suo seme)
  • Adapter FreeCAD/OpenCascade come SolidBackend alternativo

Licenza

MIT — vedi LICENSE.

About

CasaCOB Designer — open-source parametric design engine for COB (cob/earthen) roundhouses: JSON in, full geometry, drawings, BOM and construction report out

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages