Site
The ground is checked, not just drawn. Every number on the site sheet is computed from the objects beside it.
A site plan is the one drawing somebody else grades. So the site entities are written to be measured, not just drawn: the coverage, FAR, stall count and accessible-stall count printed on the sheet are computed from the same objects the sheet shows, at build time. There is no second place to type them and therefore no way for the drawing and the schedule to disagree.
{"t":"parcel","id":"lot","x":0,"y":0,"w":40,"d":30,"frontage":"south"}
{"t":"setback","id":"yard","margin":{"north":3,"south":6,"east":4,"west":4}}
{"t":"parking","id":"front","x":5,"y":18,"along":"x","count":10,"accessible":2}Everything stays semantic. A street is a centreline plus a width and a class.
A parking row is a count plus an axis — ten stalls, two of them widened and
marked, and the ratio printed. A curb cut is the gap between two curb runs.
The ground is planes, not a number
One extentless grade is the base datum, and every signed level label on
every elevation is measured from it. Further grade entities may carry a
rectangle and override the base inside it; a fall slopes the plane linearly
along one axis:
{"t":"grade","id":"datum","elev":0}
{"t":"grade","id":"back-yard","x":0,"y":14,"w":24,"d":12,"elev":1.8}
{"t":"grade","id":"downhill","x":0,"y":-10,"w":24,"d":10,"elev":0,"fall":{"to":-2.7,"along":"y"}}Resolution is by containment, smallest rectangle first, so a terrace can sit inside a yard. Two rectangles that overlap without one containing the other are ambiguous ground and block the set — the compiler will not guess which plane you meant. Elevations and sections sample the profile only where it breaks, carry the below-ground mask along it, and site objects stand at their local grade rather than the datum.
This is what makes the walkout basement an authoring pattern instead of a
feature: a basement level below the datum, a falling grade rectangle on the
downhill side, and the door in the wall that surfaces. Uphill the house reads
one storey; downhill, two. A wall with type:"retaining" needs nothing new
— ground that differs on its two sides is just what the mask already draws.
Setbacks, in the words the ordinance uses
The compass form above works. So does the one every zoning code is actually written in, and it is much easier to check against the source document:
{"t":"setback","id":"yard","front":7.6,"rear":7.6,"side":1.5}front is the edge named by parcel.frontage, rear is the opposite, side
is both remaining edges. An explicit compass margin still beats a derived one,
and all fills any gap.
Leave frontage off and there is nothing to resolve against — so you get a
setback/no-frontage advisory, rather than a check that quietly does not run.
Silence is the failure this rule exists to remove.
Existing and proposed
Mark anything already on the ground with "existing": true, and it draws in the
convention a plan checker reads first: light, dashed, unmistakably not the
application.
An existing building has two forms, and the choice decides how good it looks:
| you write | you get |
|---|---|
{"t":"building","w":12,"d":14,"existing":true} | an extruded prism with a flat cap. No pitch, no eave, no opening |
{"t":"building","footprint":"house-fp","existing":true} | real walls and a real pitched roof — dashed to a simple outline on the site plan, whole in the elevations and the 3D |
The prism is right for a neighbour across the boundary that nobody is going to
measure. For the house the drawing is about — which on a permit set is the
biggest thing on the sheet — give it a footprint. site/proposed-massing nudges
you the same way.
A pool is geometry, not local policy
pool compiles to a basin floor and four retaining sides — the water volume
stays a genuine void that sections cut through, and earth, planting and paving
all open for it. The default validator checks that it has a parcel and clears
its authored setback.
Barrier layout and height depend on local code, so they are not default
validator rules. Author a fence with kind:"pool" when the model needs to
show one; apply jurisdiction-specific thresholds in an optional policy layer.
{"t":"pool","id":"pool","x":7,"y":17,"w":9,"d":4.5,"depth":1.6,"setback":1.5}
{"t":"fence","id":"barrier-n","kind":"pool","from":[4.8,16.3],"to":[18.2,16.3],"height":1.3}07-poolside builds the whole yard: pool, barrier,
timber deck, first-floor balcony, driveway and stalls.
What bites
paving.use is a closed list: driveway, walkway, patio, parking,
pond. There is no lawn in it — a lawn is a landscape. And when vehicle
access, width or a turning radius has to be checked, you want road, not
paving.
Every site finding is advisory, on purpose. A deck inside a setback draws perfectly; the building is nonconforming, not the drawing, and a variance application is a legitimate document. Surfacing these prominently is the job of whatever is consuming bimtex, not of the validator.
Overlapping plates fight in 3D. Two paved areas at the same level covering the same ground z-fight. Butt them; do not overlap them.