The plan, and the tables that extend it. Every other directory reads from here and writes nothing back.
Files describing the example building are all rights reserved; see LICENSE. The formats below are MIT and are what transfers.
The single source of truth. All dimensions in inches.
walls: [[x1, y1, x2, y2, thickness], ...] // centrelines, mitred by the solver
doors: [[x1, y1, x2, y2], ...] // ON a wall centreline
windows: [[x1, y1, x2, y2], ...]
sliders: [[x1, y1, x2, y2], ...]
slabs: [[x1, y1, x2, y2, surface], ...] // or { poly: [[x,y], ...], surface }
rails: [[x1, y1, x2, y2], ...] // open edges: balconies, voids
rooms: [{ n, d, r: [x, y, w, d], wet, outdoor }, ...]
lights: [[x, y], ...] // ceiling fixture positionsA wall may carry a sixth element for a non-standard height, so a counter-height
partition is [229.5, 168.25, 229.5, 250, 4.5, 40].
An opening must sit on a wall centreline within half the wall thickness plus an
inch, or the solver will not match it to a wall and tools/walls.mjs will say
so. Moving a door means editing its two coordinates; the wall array is not
touched.
Slabs take three forms: a bare rectangle, { r, surface, overhang } where
overhang documents an intentional cantilever so tools/support.mjs stops
reporting it, or { poly, surface } for anything not rectangular.
Also exported: GRID_X / GRID_Y (the structural grid), LEVELS (floor level
per storey), DIMS (wall height, slab thickness, sill and head heights),
LIFT, STAIRS, and SITE for everything outside the building shell.
x runs along the plot's long axis from grid line 1. y runs across it from
row F. z is height above that storey's own level, so no first-floor
coordinate carries an offset. World space is (x - CX, z, y - CZ), converted
only in lib/prism.js and lib/geometry.js.
Maps plan inches to pixels in a scan, one calibration per sheet:
px = ax + s * x_inches
py = ay + s * y_inchesSheets drawn at the same scale can still sit differently on their pages, so each floor carries its own offsets. Align by eye with the nudge sliders in the panel; the "Bake alignment" button writes the result to disk so it can become the default. Automatic registration was tried and performs worse.
Latitude, longitude, timezone, and planXBearing, the compass bearing of the
plan's +x axis. Those four numbers make the sun correct for a site.
solarPosition(dayOfYear, hour) returns altitude and azimuth from a NOAA
routine; planFromBearing() maps a compass azimuth into plan space.
The coordinates here are a city reference point, not a plot. Solar altitude varies by well under a degree across a metro area.
Four files are data you add rows to rather than code you modify.
A scheme is a list of parts, each fixed to a named face of the building:
{ kind: 'jaali', lvl: 'F', axis: 'x', at: 846, from: 172, to: 458,
z0: 138, z1: 268, cell: 13, bar: 3.4, depth: 6, mat: 'terracotta' }axis: 'x' means the face plane is x = at and the run is measured in y.
dir is which way is outward. lvl is the storey, so a part hides with its
storey; 'S' means site, and follows the compound wall toggle.
Nine kinds ship: panel (punched by the openings behind it), band, fins,
slats, jaali, posts, frame, arch (a struck arc, not a staircase of
boxes) and lattice (diagonals, built in the plane of the face). A new kind is
one case in partGeometry() in components/Facade.jsx.
Schemes only add geometry. Selecting "As drawn" returns the elevation untouched.
Each is apply(model) operating on a deep clone, so the drawn plan is never
mutated and turning everything off returns exactly what the architect drew.
They compose, and each toggles independently.
Helpers are provided for the common operations: dropWalls, isWall, near.
A proposal can move walls, relocate openings, reroute railings and change what
the lift serves.
Wall colour and finish, joinery tone, upholstery, metal, and a floor finish schedule matched per room by regex.
Beats with a camera position, a caption, a state patch and a duration.
?tourAt=9000 freezes it at any millisecond, which is how frames are checked
and stills exported. Beats marked fade dip to black across the cut; beats
marked hold keep the camera still so a geometry change is visible.
Do not resolve the beat list at module scope. Hot reload swaps this file while a cached array goes stale.
getModel(enabledEnhancements) deep-clones the base plan, applies whichever
proposals are on, and caches by key. Everything downstream takes the result,
so a component never reads floors.js directly.