M Hudson AI Studio · Production tech09 AUG 2026 · Phase IV

Drawing → CAD → Model
five pipelines, one deterministic path

Five drawing sets arrive in five different states — from a native CAD export to a scan of a hand drawing with no CAD underneath. Each needs a different way in. None of them needs an AI vision model, and that is the finding that shaped everything else.

The question that picks the route

entitiespixels onlyDrawing arrivesWhat does itactually carry?Read the dataPipelines A B C DRead colour + shapePipeline EStructured dataCAD file · Model · 3Dview · Fidelity exhibit
Every drawing is asked one question first: does it carry entities, or only pixels?

Four of these drawings were plotted from CAD. What looks like a picture is still stored underneath as lines, text and dimensions — so nothing has to be recognised by eye, and the reader takes the architect's own structure rather than guessing at it. The fifth is a scan of a hand drawing, and it is the only one where the pipeline must work from colour and shape.

The five pipelines

PipelineApplies toReaderSource carries
vector permit setBear's Club (wiener) — 34-page permit PDF plotted from CADreaders/wiener_pdf.pyvector paths, text layer, dimension strings, a door/window schedule
native cadCommodore (connors) — 5 DWG exported from Revitreaders/connors_dwg.pylayers, block names, the Revit family-type ElementId, level datums
landscape cadLandscape (davis) — 23 Land F/X filesreaders/davis_dwg.pysite polylines, planting blocks, species in an XML sidecar
revision seriesLandscape · revisions (davis-revisions) — 5 dated versionsreaders/davis_revisions.pythe same site at five points in design development
hand drawingRiverside Drive — a SCAN of a hand-drawn presentation planreaders/riverside_sketch.pypixels. No vector geometry, no text layer, no dimension strings.
Permit-set PDFplotted from CADRead pathstext · dimensionsFit scaleslope AND interceptWalls fromparallel pairsJoin schedulemarks to openingsBuild modelRe-open andre-measure376 of 376at 0.0 mm
Pipeline A — a vector permit set. The scale is fitted, not assumed.

The scale step is where this one earns its keep. Plotted dimension lines carry a constant overshoot; fitting a slope alone gives a ~10% scale error that nothing downstream detects, because the output still looks correct. Fitting slope and intercept removes it.

yesnoNative DWGRevit exportTake layersblocks · levelsDo sheets shareone datum?One offsetfor all sheetsPer-sheetand say soJoin sheets byfamily-type idStack floorsheights from drawingBuild model
Pipeline B — native CAD. The structure the architect authored is worth more than anything inferred.

Before choosing an origin the reader asks whether the sheets already share one. They did — and re-basing each sheet to its own extents would have placed one floor 32.57 ft east of another, silently, with every sheet still internally consistent.

Scanned hand drawingno CAD underneathFix the one scale0.640 in per pixelSeparate by colour5 material bandsFind the lotlargest connected groundLift drawn wallsopen ink at the kneeAdd unwashed interiorsaturation below 0.08Structures = wall+ interior it boundsMassing onlyheights DECLARED
Pipeline E — a hand drawing. Colour and shape only, and it stops at massing.

This is the hard case and it is deliberately scoped down. The printed ⅛" = 1'-0" note is the only measurement on the sheet, which puts a hard floor of 0.640 inches per pixel on anything derived from it. What comes out is where things are and how big they are — and explicitly not wall thicknesses, openings, rooms or heights.

What is deterministic, and what is not

NON-DETERMINISTIC - outside the pathDETERMINISTIC - the whole pipelinesets the targeta sweep is measuredagainstColour separationMorphologyGeometry + scaleModel authoringRound-trip checkOperator names groundtruthwhich walls · whichstructures
The pipeline is deterministic end to end. The only human judgement sits outside it.

There is no model in any path. The same drawing produces the same model, and a change in the output always means a change in the input — for four of five projects that holds at the byte level. The one non-deterministic input is a person naming what the drawing cannot say: which walls belong to which structure, and how many structures the sheet actually shows. Every threshold was then swept against that count. The sweep is deterministic; the target is not derivable from the sheet, and saying so is the point.

How the hand-drawing recipe was actually found

Measured and rejectedNegative of colourone 12,413 sf blobWall-bar density26% orthogonalEnclosure from heavy bars0.04% of sheetCluster the barsbars sit 20-30 ft apartWall PLUS the unwashedinterior it bounds5 structuresvalidated against namedwalls
Four approaches were built, measured and rejected before the fifth held.
ApproachWhy it failedMeasured
buildings = site minus every coloured materialevery unwashed pixel becomes 'building', so walkways, terraces and a dozen separate structures merged into ONE 12,413 sf mass. Paving had no class of its own.11 masses / 16,651 sf on a 34,853 sf lot — 48% site coverage
structures = regions where wall-bar density exceeds a thresholda single global scale either under-fills small rooms or merges whole wings. Produced organic blobs, not the rectangular shapes the linework describes.13 blobs; only 26% of traced edge length within 8 deg of orthogonal
fill the regions enclosed by the heavy poche barsthe bars are DISCRETE SEGMENTS, not closed outlines — rooms are implied, not enclosed.flood-filling enclosures returns 0.04% of the sheet; per-component hole-filling finds 2 structures
group wall bars by proximity into structuresthe bars of ONE structure sit far apart, because a garage is drawn as a few segments with a wide door opening between them. No distance bridges them without merging the site.separations within one structure: golf-cart garage 19.9 ft, bonus garage 26.6 ft, 2-car-everyday 29.2 ft. Cluster sweep: 6.0 ft -> 6 structures, 6.8 ft -> 4 (bonus garage merges into the house), 8.1 ft -> 2.
make the Riverside IFC byte-identical across rebuilds like the other fourIfcOpenShell interns simple entities through a set, so an identical graph is written with permuted entity numbering. Creating entities directly instead of through ifcopenshell.api did not fix it.publish a SEMANTIC fingerprint over the sorted (GlobalId, class, name) set — verified stable across three builds — and state the exception rather than quote a hash that moves.

Each of these is kept in the recipe registry with its root cause, so the next person does not spend a pass rediscovering it.

The recipe that held

A structure is drawn wall plus the unwashed interior it bounds. Interiors are bare paper; every outdoor surface carries a colour wash — measured at a garage interior 0.008–0.013 saturation against paving 0.101 and motorcourt 0.19–0.23. Saturation separates inside from outside outright, which is why the knob is a colour threshold and not a distance.

5structures

house + attached garage, two garages, casita, dock tackle — validated against operator-named walls

36wall bars

801 sf of drawn poché, the one thing measured rather than inferred

0.640 inper pixel

the accuracy floor no upsampling recovers

0vision models

in any of the five paths

Two figures are declared, not measured, and travel on every object as properties so a consumer sees it without reading documentation: massing height 12 ft, and canopy height at 1.2 × crown spread. The sheet is a plan and states no heights at all.