The geometry
Inputs are the finished face (W × H), return depth R and ACM thickness t.
Everything else is derived:
- blank = (W + 2R) × (H + 2R)
- an R × R square is notched out of each corner — a through cut
- fold lines are one closed rectangle inset R, which is exactly the face footprint
- the groove is routed on the back, leaving 0.5 mm of front skin as the hinge
- returns fold 90° away from the face; the notched corners butt at the panel edge
Worked example: 600 × 450, R25, 3 mm → blank 650 × 500, 2100 mm of groove,
about 1.2 kg, six blanks per 2440 × 1220 sheet.
Files
| File | What it is |
panel.dxf | R2010, millimetres, 1:1. Layers: OUTLINE (cut),
VGROOVE (fold), REVEAL, LABEL, DATUM, NOTES. |
panel.svg | Dimensioned drawing for the shop wall. |
panel.obj | Folded solid, one group per member, two 0.5 mm
skins either side of the core. |
panel.json | Spec: blank, groove length, mass estimate, sheet yield. |
nests/sheet-NN.dxf | Sheet layout, cut + groove + part ID. |
labels.svg | Printable labels: ID, face, blank, qty, sheet. |
cutlist.csv | Production schedule with dims and groove length. |
What comes out, and who it is for
| Format | Goes to | What it holds |
| DXF R2010 | router / CAM | OUTLINE through cut, VGROOVE partial,
DRILL, WEEP, REVEAL — one layer per operation, millimetres, units set |
| SVG | the shop wall | dimensioned drawing at 1:1 |
| OBJ | CAD / visual | the folded solid, skins and core at true thickness |
| PDF pack | submittal, print | cover and numbers, drawing, one page per
nest, labels 1:1, cut list and hardware schedule — licence and date on every page |
| XLSX | estimator / office | panels, hardware, quote and notes in one workbook |
| CSV | saw / procurement | cutlist.csv,
extrusions.csv, and tigerstop.csv for a push-feed list |
| JSON | integrations | spec: blank, groove length, mass, yield,
mounting, finish |
No DWG and no STEP yet — both need a converter we do not ship. DXF R2010 is
what router CAM software reads, and it opens in AutoCAD, Fusion, Rhino and LibreCAD.
If a project demands DWG or STEP, say so and it goes on the list.
Schedule CSV
Header required. Only id,w,h are mandatory.
id,w,h,qty,return,thickness,reveal,material,note
P-101,1200,900,4,25,4,0,ACM,bay A north
P-102,1200,600,4,25,4,0,ACM,spandrel
P-107,450,450,8,20,3,0,ACM,closures
Defaults: qty 1, return 25, thickness 4, reveal 0. Duplicate IDs are refused —
two parts with the same ID is how a shop cuts the wrong thing twice.
Nesting
Shelf / guillotine nesting, tallest first, 12 mm margin, 10 mm between parts,
rotation allowed, best-fit into an existing row before opening a new one. It keeps rows
whole so the saw operator can follow it — a true-shape optimiser packs tighter but cuts
nothing like a straight line. Every nest is re-read after writing and its cut outlines
measured against the sheet border before you get the file.
Revision diff
Two schedules in, four answers out:
- new — cut it
- re-draw + re-cut — same ID, different size; the old file is scrap
- cut more, same file — quantity changed, geometry did not
- deleted — do not cut
Version B is rebuilt in full so the shop has one consistent set of files.
API
GET /api/preview.svg?w=900&h=600&return=25&thickness=4&reveal=0
GET /api/spec.json?w=900&h=600&return=25
GET /api/panel3d.json?w=900&h=600&return=25&thickness=4
GET /files/panel.dxf?w=..&sig=<signed> paid
GET /files/panel.obj?w=..&sig=<signed> paid
POST /batch csv, sheet_w, sheet_h paid
POST /diff csv_a, csv_b paid
# agent / API-key lane (metered per call)
GET /api/v1/ping X-API-Key
POST /api/v1/panel X-API-Key, JSON {"w":900,"h":600,"return":25,"thickness":4,"format":"dxf"}
The API returns one file per call and a X-Calls-Remaining
header. Keys are minted in web/api_keys.json with a call limit — the lane for
an agent or an ERP that needs geometry without a browser.
Everything is millimetres. There is no queue: a 30-panel schedule builds in
about a second.
Exports and protection
- Free is a look, not a file. The anonymous drawing is rounded to 5 mm, carries
no dimensions and is watermarked. It is not a fabrication drawing.
- Paid exports are signed. Each link carries an HMAC token bound to the panel
parameters and expires in an hour; editing the size in the URL breaks it.
- Every export is stamped: the DXF has a
LICENCE layer reading
"LICENSED TO <email> - date", the OBJ has the same in its header, the JSON has a
_licence block. Files that leak point at the account that made them.
- Caps: 400 exported files per licence per day, 240 requests per minute per IP.
Bulk conversion needs a bulk licence.
- Audit log: logins, exports, refusals and cap hits are appended to
audit.jsonl.
Be clear-eyed about it: a pan's geometry is not secret — anyone can compute
blank = face + 2 × return. What is protected is the finished, checked, layered file set,
and the traceability of who made it.
Standards the numbers follow
| ACM | Groove depth | Skin left | Min return | Weight |
| 3 mm | 2.4 mm | 0.6 mm | 12 mm | 3.8 kg/m² |
| 4 mm | 3.3 mm | 0.7 mm | 20 mm | 5.1 kg/m² |
| 6 mm | 4.9 mm | 1.1 mm | 25 mm | 7.6 kg/m² |
- Groove depth runs 60–70% of thickness; remaining material 0.2–0.5 mm is the industry
window for a clean 90° fold.
- Flat-tip V bit (~3 mm flat). A sharp point touches the front skin and cracks it.
- 90° bit for right-angle returns, 135° for obtuse folds; PCD tooling on FR/mineral cores.
- Joints: butt 0, sign reveal 6 mm, rainscreen 12 mm, exposed 15 mm.
- Tolerance we hold the geometry to: ±0.5 mm cut, ±1.0 mm fold, ±1 mm/m square.
Mounting
Fasteners go through the return, never the face. Mount holes are
placed in the middle of the return strip in the flat pattern, so they are drilled or
punched before folding and land on the flange afterwards. They are written to the
DRILL layer of both the panel DXF and the nest sheets.
| Pattern | Holes | Where | Use |
| perimeter | evenly at pitch (default 300 mm) | all four returns |
screw to a subframe or frame |
| zclip | 2 per return, 40 mm from each corner | all four returns |
Z-clips, panel removable |
| cleat | evenly at pitch | top and bottom only |
French cleat rails, clean sides |
Defaults: Ø6.5 mm (a #12 screw), first hole 40 mm from the corner, pitch
300 mm. Change the diameter for rivets (Ø4.8 or Ø6.4) or standoffs. Not modelled yet:
cleat heights, subframe layout, and clip spacing for wind load.
Extrusions, weep holes and the saw list
Pick an extrusion and the screw pattern changes with it: hole diameter,
pitch along the run and the inset from the corner all come from the profile, not from a
guess. Profiles are generic classes — edit the library and your own part numbers go in.
| Profile | Holes | Where | Note |
| Top-hat 400 | Ø6.5, 300 pitch, 40 from corner | top and bottom returns |
horizontal rails |
| Dry-seal 600 | Ø6.5, 300 pitch, 45 | top and bottom | gasketed rail |
| Wet-seal 600 | Ø8, 250 pitch, 50 | all four returns | sealed perimeter |
| Z-clip 20 | Ø6.5, 2 per return | all four | removable panel |
| Corner angle 25 | Ø5.5, 2 screws a leg | four corners | internal corner |
Weep holes go in the bottom return, mid-strip, Ø6 at 300 pitch,
60 mm in from each corner, on their own WEEP layer so the router knows they are
drainage, not fixing.
Batch writes two hardware files next to the panels:
extrusions.csv (profile, piece, length, quantity, metres) and
tigerstop.csv — a flat length/quantity/label list for a push-feed saw or
optimiser. Labels for cut pieces are in labels.svg.
Limits, stated plainly
- Square butt corners only; 45° mitre is not built.
- No adhesive, corner locks, cleats or paint in the model.
- No elevation DXF import or opening deduction yet — Facade does full bays only.
- Shelf nesting, not true-shape.
- Sessions live in memory: a restart signs you out.