Prima delle quote, mi interessa il tipo di oggetto. Nel furniture design molti mobili si possono ricondurre all’archetipo del cabinet, o carcassa: una struttura che contiene un volume e ne mantiene la forma. I suoi elementi ricorrenti sono fianchi, piani, base, schienale e compartimenti o ripiani. Ante e cassetti sono opzionali; anche la base può assumere la forma di uno zoccolo, un telaio o semplici piedini.
La voce Cabinetry di Wikipedia è un buon promemoria: non esiste una distinta universale del mobile, esiste una famiglia di relazioni che ricompare con soluzioni costruttive diverse. La carcassa è il sistema strutturale; ripiani, ferramenta, ante e finiture si appoggiano a quel sistema.
Una Billy è un esempio quasi disarmante: niente ante da parametrizzare, ma abbastanza elementi da rendere visibili queste relazioni. Il modello che ho scritto non vuole essere un disegno costruttivo ufficiale IKEA. È un esercizio sul passaggio dal volume finito ai pannelli, e soprattutto sul modo di non perdere quel legame quando si cambia una scelta progettuale.
Il generatore parametrico segue questa sequenza: descrive il volume, lo scompone in pannelli con woodworkers-lib, costruisce la vista del mobile e prepara una BOM (bill of materials, distinta dei pannelli) per cutplanner. Il piano di taglio arriva dopo: aiuta a fabbricare, ma non prende decisioni di furniture design.
Descrivere il volume
La prima scelta è partire dalle dimensioni esterne e non dai pezzi. Nel codice width_l, depth_w e height_h descrivono rispettivamente larghezza, profondità e altezza; wood_thickness e back_thickness descrivono i materiali. Il punto importante non sono i valori iniziali, ma le dipendenze:
width_l = 800;
depth_w = 280;
height_h = 1900;
wood_thickness = 18;
back_thickness = 6;
has_back = true;
back_style = "nailed";
toekick_height = 70;
TH = wood_thickness;
carcass_h = height_h - toekick_height;
carcass_depth =
(has_back && back_style == "nailed") ? depth_w - back_thickness : depth_w;
carcass = [width_l, carcass_depth, carcass_h];
La profondità della carcassa cambia in base a come si monta lo schienale. Applicato dietro, lo schienale occupa parte della profondità finita; inserito in scanalatura, resta dentro il volume e modifica il modo in cui si incontrano fianchi, fondo e cappello. È una relazione progettuale generale, non un dettaglio della Billy.
Lo stesso vale per un pannello inserito tra due fianchi: la sua larghezza deriva dalla luce interna, quindi dalla larghezza esterna meno i due spessori. Se cambio wood_thickness, la relazione continua a valere. Non devo rincorrere la quota del ripiano con una correzione manuale.
Pensare per facce e pannelli
La libreria di fxdave propone una metafora che trovo utile: prima immagino una scatola, poi sostituisco le sue facce con pannelli. planeLeft() e planeRight() sono i fianchi; planeBottom() e planeTop() i piani; planeBack() lo schienale. I moduli generano la geometria e lasciano una traccia delle quote nella console.
Per esempio, il fondo deve sapere che si trova tra i fianchi:
include <woodworkers/std.scad>
box = [800, 280, 1900];
th = 18;
planeLeft(box, thick = th);
planeRight(box, thick = th);
planeBottom(box, l = -1, r = -1, thick = th);
Qui l = -1 e r = -1 esprimono la sottrazione di uno spessore per lato. Non è una quota da ricordare: è una relazione leggibile. Le correzioni assolute come ff e BB servono invece quando il pannello deve arretrare rispetto al fronte o al retro, per esempio per lasciare spazio allo schienale.
Nel sorgente del progetto i moduli sono incorporati, quindi quel file è autonomo. L’esempio ridotto qui sopra usa invece l’installazione separata descritta nel README; sono due modi diversi di provare la stessa idea.
Una scelta costruttiva attraversa tutto il modello
Nel generatore i pannelli sono riusati per costruire la carcassa:
module Sides() {
planeLeft(carcass, bb = toekick_height, thick = TH);
planeRight(carcass, bb = toekick_height, thick = TH);
}
module Shelves() {
for (z = shelf_positions)
translate([0, 0, z])
planeBottom(carcass, l = -1, r = -1,
ff = -shelf_recess_front, BB = shelf_bb, thick = TH);
}
Il for non descrive un nuovo tipo di pezzo: ripete lo stesso ripiano in posizioni diverse. Per questo una modifica a shelf_count deve riflettersi sia nella vista sia nella distinta.
Lo schienale rende evidente il vantaggio di questo approccio. Con back_style = "nailed" riduce la profondità della cassa; con back_style = "slot" resta nella cassa e introduce scanalature, arretramenti e giochi di montaggio. La geometria solida costruttiva (CSG) entra in gioco quando difference() sottrae le scanalature ai pannelli. La vista 3D, la distinta e le lavorazioni devono restare coerenti: un cambio di assemblaggio non è solo un cambio di colore nella preview.
Dalla geometria alla distinta
La console è un primo controllo, ma non è ancora una distinta affidabile. Per portare i pezzi fuori dalla preview il generatore costruisce una seconda rappresentazione: ogni voce di bom contiene nome, due lati della faccia e spessore.
bom = concat(
[["Fianco Sx", carcass_depth, side_h, TH],
["Fianco Dx", carcass_depth, side_h, TH],
["Fondo cassa", width_l - 2 * TH, carcass_depth, TH]],
[for (i = [0 : 1 : len(shelf_positions) - 1])
[str("Ripiano ", i + 1), width_l - 2 * TH,
carcass_depth - shelf_recess_front + shelf_bb, TH]]
);
for (p = bom)
echo(str("{\"name\":\"", p[0],
"\",\"length\":", max(p[1], p[2]),
",\"width\":", min(p[1], p[2]),
",\"thickness\":", p[3], "}"));
Questi record sono stringhe JSON, una per pannello, riconoscibili da cutplanner. La struttura JSON separa nome, lato maggiore, lato minore e spessore; cutplanner documenta questi campi. La ferramenta, le scanalature e i fori restano informazioni diverse: non diventano rettangoli aggiuntivi nel piano di taglio.
Il piano di taglio come controllo della pipeline
Una BOM dice cosa serve; un ottimizzatore prova a disporlo sui fogli disponibili. Il file inventory.yaml descrive i materiali disponibili e il loro spessore. Non è un dettaglio secondario: un pannello sottile non deve finire fra quelli strutturali.
La documentazione di cutplanner riporta i comandi necessari. La prova reale del progetto è stata:
uvx --from git+https://github.com/uberbruns/cutplanner cutplanner serve parametric-billy-bookcase.scad inventory.yaml --kerf 3
write-bom ha trovato 12 pannelli. Il layout prodotto con l’inventario del progetto e --kerf 3 ha collocato tutti i pannelli su fogli compatibili; non sono rimasti pannelli fuori. È una verifica della pipeline, non un certificato di progetto esecutivo: venatura, bordatura, rifili, lavorazioni e sicurezza del mobile richiedono ancora decisioni e controlli reali.
La regola che resta
Provare un altro valore di width_l, wood_thickness o shelf_count nel Customizer di OpenSCAD serve a osservare la qualità del modello: cambiano insieme carcassa, ripiani e BOM. La relazione più semplice è anche la più istruttiva: se i fianchi diventano più spessi, la luce interna si riduce del loro spessore complessivo.
È questa, per me, la parte interessante del CAD parametrico applicato al legno. Non disegnare una Billy una volta, ma descrivere le regole di una famiglia di mobili. woodworkers-lib rende quelle regole leggibili attraverso facce e pannelli; echo() le porta dalla preview alla distinta; cutplanner permette di controllare un passaggio ulteriore. Il modello non decide come costruire un mobile, ma evita che una scelta cambi in un punto soltanto e venga dimenticata negli altri.