Skip to content

This page is generated from docs/furniture.md — edit it there.

Furniture & Fixtures

furniture places a piece of furniture or a built-in fixture into a plan. Every catalogued kind draws a real plan symbol — a WC with a cistern and a seat, a bed with a headboard and pillows, a wardrobe with hanging scallops — in the same drawing vocabulary as the door arcs and window panes. Anything ArchLang doesn't know still renders as a labelled rectangle, which is the escape hatch for a piece the catalogue has no word for.

Where you put it matters to the soundness checks: the linter knows a WC should have its back to a wall, that a bath needs a wet fixture, and that a door leaf should not sweep across a basin.

This page covers the placement modes, the symbol catalogue, how a symbol is oriented and sized, the importable fixture library, and the lint rules that key off furniture. The one-line grammar lives in the language reference.

Three placement modes

A piece is positioned absolutely by its top-left corner, snapped against a wall so its back sits on the wall face, or anchored inside a room's box. The two non-absolute modes derive the piece's rotation for you.

ModeGrammarYou giveArchLang derives
Absolutefurniture <kind> at (x,y) size <w>x<h> [rotate 0|90|180|270] [in <room>]corner, footprint, optional quarter-turnnothing — what you write is what's drawn
Against wallfurniture <kind> against wall <ref> [segment <n>] [offset <mm>] [side left|right] [size <along>x<depth>] [in <room>]which wall, how far along, optionally a depththe position and the rotation, from the wall — plus the footprint, if the kind has one and you omit size
In a roomfurniture <kind> in <room> centered|anchor <a> [flush] [inset <mm>] size <w>x<h> [rotate …]which room, which corner/edge, footprintthe position from the room's box (or, with flush, from the backing wall's face), and — for a kind whose facing means something — the rotation from the wall the anchor names
arch
# Absolute: a bed in the top-left, turned a quarter turn so its head is on the left wall.
furniture bed at (4300,300) size 1500x2000 rotate 90 in r_bed

# Against a wall: a 600-mm-deep counter run 1800 mm long, snapped to the north wall,
# starting 300 mm in from the wall's start, sitting on the interior (room) side.
furniture counter against wall north offset 300 side left size 1800x600 in r_kitchen

# Against a wall with NO size: the catalogued footprint is used (a fridge is 600 along
# the wall by 650 deep), so the only numbers left are the ones this plan chooses.
furniture fridge against wall w_west offset 400 in r_kitchen

# In a room: a WC on the bathroom's south edge — `rotate 180` (cistern to that wall) is
# derived, and `flush` puts its back on that wall's inner face (no thickness to work out).
furniture wc in r_bath anchor bottom flush size 400x700
  • rotate turns the footprint a whole quarter-turn about its centre (0, 90, 180, or 270 — any other value is E_FURN_ROTATE). It is exact integer geometry, so the output stays byte-stable.
  • against wall <ref> snaps the piece's back onto a wall named by id or kind.
    • segment <n> selects which leg of a multi-point wall (0-based) to sit against.
    • offset <mm> slides the piece along that segment from its start.
    • side left|right picks which face of the wall to sit on (relative to the segment's direction); when you also give in <room>, the interior side is inferred for you.
    • size may be omitted for any kind with a catalogued footprint (the "Footprint" column below) — it is read as along × depth, along the wall and into the room. A kind with no footprint and no size is E_FURN_SIZE.
    • The rotation is derived from the wall, so combining against with an explicit rotate is an error (E_FURN_AGAINST).
  • in <room> records the owning room (by id). A trailing in <room> doesn't move the piece — it lets the linter check the piece is actually inside that room and lets against infer the interior side. A non-existent id is E_FURN_ROOM. The leading form (in <room> centered\|anchor …) both positions and owns the piece.
  • flush measures the inset from the wall FACE. A room's rectangle runs along wall centerlines, so anchor bottom alone leaves the piece's back half a wall thickness inside the solid — which is why you would otherwise write inset 100 for a 200-mm wall you never named (W_FURNITURE_WALL_COLLISION if you forget). flush re-bases inset (default still 0) onto the inner face of the wall behind each anchored edge — centerline + thickness / 2, toward the room — so anchor bottom flush lands on the plaster and anchor bottom flush inset 50 sits 50 mm off it. It applies per edge and independently (a corner anchor can be flush on one edge only), an anchored edge with no wall behind it keeps the room-rectangle reference, and it needs an anchored edge at all: centered / anchor center is E_FURN_FLUSH. Write it before inset, whose reference it changes.
  • anchor <edge> also aims a piece. An anchor names the wall(s) the piece is pushed against, so for a kind whose facing means something the quarter-turn is derived — no rotate to work out by hand. It is derived only when the answer is unique (ADR 0005): the anchored edge must have a wall behind it, and the footprint's aspect must allow that edge to be the back (a 400 × 700 WC is 400 along the wall and 700 deep, so it can only back onto a horizontal edge). anchor bottom-left in a walled corner therefore still has one answer for that WC, while a square 600 × 600 counter in the same corner has two — so nothing is derived and W_FIXTURE_BACK_TO_ROOM asks you to pick. An explicit rotate always wins.

The symbol catalogue

Eighty-three families, a hundred and twenty-nine names with the aliases, and every one of them draws. The tables below are grouped by the room the pieces belong to.

Three columns need a word of explanation:

  • Footprint is the catalogued along × depth in millimetres — the size against wall uses when you omit size. A dash means the kind has none, so size is required there.
  • Facing says what ArchLang will do about which way the piece points. Derived means the symbol has an unmistakable back — a cistern, a tap, a nosing, a headboard, a wardrobe's door line — so an anchor can derive the quarter-turn and W_FIXTURE_BACK_TO_ROOM flags a piece against a wall that faces the wrong way. Symmetric means the symbol is drawn so that a quarter-turn changes nothing, so its facing carries no meaning and is neither derived nor checked. Free means the piece is drawn with a front but is arranged rather than installed — a sofa's back to the room is a room-divider layout, not a defect — so nothing is derived and nothing is warned about.
  • Wall marks the kinds that carry requiresWall, which means services and nothing else: supply, waste, venting, or hanging off the wall by definition. Those are the kinds W_FIXTURE_FLOATING applies to. A bookcase is not one of them — a library's stacks are free-standing runs mid-floor, which is what stacks are.

Bath

Kind (and aliases)SymbolFootprintFacingWall
wc · toiletcistern across the back with its lid lip and flush button, bowl and seat ring in front400 × 700derived
basin · lavatoryvanity slab with an inset oval bowl, tap block, spout and drain — two bowls on a long enough slab600 × 450derived
showertray with an inset rim, both diagonals across the inner tray, and a centre drain900 × 900symmetric
bathtub · tub · batheased rim, an inset well, the tap at the head end and the waste on the centreline1700 × 700derived
bidetbowl with its rim, a small tap block at the back, the spout and the waste — a wc with no cistern400 × 700derived
urinalthe back plate on the wall and a half bowl hanging off it, with its rim and waste400 × 350derived
mirrorthe glass, with five 45° reflection ticks across it900 × 50derived

The tub's rim is deliberately uneven — thicker at the tap end than at the foot — so the drawing says which end you get in at. lavatory is the one alias that differs from its head: it does not count as a wet fixture for W_ROOM_NO_FIXTURE, which has always been true of it, while basin does.

urinal is the only symbol in the catalogue drawn as half a shape, and that is the honest plan of it: a wall-hung urinal has no back — the wall is its back — so the chord across the top of the bowl is the wall face, and the symbol runs to the very edge of its footprint where every other bath fixture leaves a margin.

mirror and bidet are both requiresWall, for the two different reasons that flag covers. A bidet is plumbed. A mirror hangs off the wall by definition — the upper_cabinet case, not the plumbing one. Neither carries a zone that would let it stand in for a WC or a basin: bidet counts as a wet fixture, mirror deliberately does not, because a mirror over a console table does not make a room a bathroom.

Kitchen & utility

Kind (and aliases)SymbolFootprintFacingWall
kitchen_sink · sinkcounter slab, two eased bowls each with a drain, and a tap with its spout at the back800 × 600derived
counter · worktopslab with a nosing line inside the front edge and one division tick per 600 mm base-cabinet module600 × 600derived
stove · hob · cooktopslab with four burners as concentric rings and the control rail across the front600 × 600derived
fridge · refrigeratorcarcass, the door face, the compartment split — across the width or the depth, by aspect — and the handle bar600 × 650derived
ovencarcass, three control knobs on the back edge, and the door with its window and handle bar — plus four burners when the footprint is wide enough to be a rangefree
dishwashercarcass, two basket lines across the tub, and the door leaf on the front with its control strip and handle600 × 600derived
islandeased worktop, the seating overhang along the front with cabinet ticks under it, and — by aspect — a hob or a sink at one endfree
upper_cabinet · wall_cabinetcarcass, one door split per 600 mm module and a hinge tick at each end, drawn entirely dashed600 × 350derived
washer · washing_machinecarcass, the control panel across the back with two knobs, and the drum with a white porthole600 × 600derived
dryerthe same carcass, with three chords across the drum where the washer has its porthole600 × 600derived
laundry_sink · laundry_tubslab with one deep double-rimmed bowl, its waste, and the tap block600 × 500derived
water_heater · boilerthe cylinder in plan, its inner shell, and two pipe ticks running back to the wall600 × 600derived
range_hoodthe hood outline with a fan ring, four blade radials and a hub, drawn entirely dashed900 × 500derived
microwavecarcass, the door window over the left three-quarters, and three buttons down the panel on the right500 × 400derived
bar_counterthe worktop over the back of the footprint, the overhang line, and one stool per ~1.2 counter-depths of run, capped at eight1800 × 600derived

washer and dryer are the same box at the same size and stand side by side in most utility rooms, so they are drawn to differ by shape: a glyph carries no text, so a letter is not available to tell them apart even if it were good drafting.

island is free-standing by definition — that is what makes it an island — so it needs no wall and has no single frontal clearance. It is no longer symmetric: the symbol gained a seating overhang along one side, which is a distinguishable front, so the catalog flag came off to keep the data true. Nothing observable changed with it — an island still derives no rotation and still never trips W_FIXTURE_BACK_TO_ROOM, because that needs requiresWall or directional and an island is neither. Seating round it is a stool, a separate kind with its own symbol; the stools drawn inside a bar_counter are a different piece with a different footprint.

Three symbols read their own footprint and draw a different appliance either side of a threshold, because the fixture word alone cannot tell them apart and inventing one answer would be wrong for half the plans that use it. A fridge at aspect 1.4 or over splits down its width (a side-by-side) and below it across its depth (a freezer drawer); an oven at aspect 1.6 or over is a range and gains a hob; an island at aspect 1.8 or over takes a hob at one end rather than a sink. Give the piece an explicit size to choose.

range_hood is the second symbol here drawn entirely dashed, and it makes the convention the drawing's rather than one glyph's: a dashed outline means a thing above the cut planeupper_cabinet, roof, void, the outdoor pergola and a garage door's projection all say the same. The two kitchen ones are told apart by what is inside: a cabinet's door splits run edge to edge, a hood's fan is a ring about the centre.

Bedroom

Kind (and aliases)SymbolFootprintFacingWall
bedmattress, headboard band at the head, one or two pillows, and the turned-down sheet with its fold diagonal1500 × 2000derived
double_bedthe same drawing — its wider footprint is what earns it the second pillow1800 × 2000derived
nightstand · bedside_tablecarcass and top, the lamp standing in the back third, and the drawer front with its handle on the room side450 × 400derived
wardrobe · robe · closetcarcass, the hanging rail at mid-depth with its clothes-hanger scallops, and the centre door split1800 × 600derived
bunk_bedlower mattress with its pillow at the head, the upper bunk dashed over it, and the ladder rungs at the foot1000 × 2000derived
crib · cotcarcass, the mattress inside it, and the rail bars down both long faces700 × 1300derived
dresser · chest_of_drawerscarcass with the drawer band, its two splits and a handle in each of the three drawers, all on the room side1200 × 500derived
vanity · dressing_tabletop, the mirror band dashed across the wall side, and the stool in front of it1200 × 500derived

None of these carries requiresWall — a bed needs no pipe — but all four are directional, because the symbol has a back worth turning toward a wall. That is what lets anchor top derive rotate 0 for a bed and put its headboard where you meant it.

The wardrobe's scallops tile the rail: their count comes from the carcass aspect and the radius is then half a cell, so consecutive semicircles meet exactly, end to end, with no gap and no overlap at any size.

Living & dining

Kind (and aliases)SymbolFootprintFacingWall
sofa · coucheased body, a back band along the rear edge, an arm at each end, and the cushion divisions between themfree
armchaireased body, a true arc for the curved back, and the seat cushionfree
coffee_tablerounded top and inner edge, four legs, and a tray line across it once it is longer than 1.6 : 1symmetric
tv_unitcarcass, the screen against the back edge, the shelf line, and the drawer bank with its handle on the room side1500 × 450derived
tablesquare top and inset edge, four legs, and a board line along its length once it is longer than 1.6 : 1symmetric
dining_tablethe table inside a chair-zone band, with the chairs drawn in itsymmetric
chairseat, back band along the rear edge, the cushion, and an armrest each side once the seat is wide enoughfree
stool · barstoola round seat with no back — three concentric true circles about the footprint centresymmetric
benchslab with its slats running lengthwise along whichever axis is longer, and a support across each endfree
fireplacethe chimney breast with the firebox opening cut into its room face and three flame ticks inside it1200 × 400derived
radiatora shallow slab with its fins ticked across the depth, at a clamped pitch1000 × 100derived
sideboard · buffetcarcass and top, the door splits along the run, and one handle per door on the room edge1600 × 450derived
loveseat · sofa_2the sofa construction with its cushion count pinned at two seats, whatever the footprint1500 × 850free
chaisean eased body with a back down one long side and a raised head across the top1600 × 800free
tvthe wall bracket with the screen panel hanging off it — not the tv_unit, which is a carcass1200 × 80derived
coat_rackthe post as two concentric circles with four hooks at a 90° pitch round it400 × 400symmetric
shoe_cabinetslim carcass, the door splits, and a tilt line in each door leaning toward the room800 × 300derived
sofa_l · corner_sofaan L: the back run along the rear edge, the return down the left, cushions along both, and the fourth quadrant left as open floor2600 × 1600free
rug · carpetouter and inner borders with a fringe at each short end — the only unfilled symbolsymmetric
piano · grand_pianothe keyboard across the back, the straight spine down the left, and the bent side sweeping round to the tailfree

sofa, armchair, chair, bench, sofa_l, loveseat and chaise are deliberately free: seating is arranged, not installed, so ArchLang neither derives a rotation for them nor warns when one faces the room. tv_unit is the exception in this group — it is directional (a media wall has a front) but still carries no services, so floating one as a room divider raises nothing.

A loveseat is a sofa with its cushion count pinned. Both draw from one construction, so the pair cannot drift apart; what separates them is the number of seats, which is the fact the two words actually carry. A sofa reads its aspect and draws three cushions on a 1500 mm footprint; a loveseat draws two on any footprint.

A tv and a tv_unit are different kinds, not synonyms. A media console is 450 mm deep and a wall-mounted panel is 80, so a plan that draws the first where the second belongs has taken 370 mm of walkway away. Both are directional, and the symbols differ: the console has a carcass, drawer splits and a screen band at the back; the panel has a bracket and nothing else.

fireplace and radiator are not requiresWall, and both are genuinely serviced. That flag means the piece cannot work without a wall behind it, and neither of these can be flagged without warning on a normal drawing: a radiator is as often fed from the floor as from the wall and lives under a window, and a free-standing stove in the middle of a room is a plan someone drew on purpose. Both are directional instead, which is the claim the drawing can back: a fireplace's opening faces the room, and a radiator's fins run from its back face to its front.

sofa_l's return is always on the LEFT, and there is no right-handed twin. Turn it with rotate where that reads right. place … mirror will not do it: a reflection transforms a resolved element's position, not the symbol drawn inside it, so a mirrored instance still draws a left-hand sofa. A sofa_l_r category was rejected rather than forgotten — it would put the fix in the vocabulary, where every future handed symbol would need its own twin; the real fix is glyph-aware mirroring in the place transform.

Its footprint is the whole bounding rectangle, empty quadrant included, which is what every furniture rule measures — so a coffee table tucked inside the L raises W_FURNITURE_OVERLAP even though nothing touches. That is a known cost of having one shape seam rather than five: teaching the overlap rule about the L and leaving the clearance rule, the wall-collision rule and the two walkability grids on the box would make the drawing and the lint disagree in a way nothing tests.

A piano carries no footprint on purpose, so furniture piano against wall <id> is E_FURN_SIZE. That form derives the rotation from the wall under the back-on-top rule, and a piano's back-on-top is its keyboard — so the one thing it could derive is the one orientation a piano is never in. Place it with at (x,y) and a rotate, which is how it goes on a drawing anyway.

Office & misc

Kind (and aliases)SymbolFootprintFacingWall
deskslab with the modesty panel across its back, the working edge stepped in, a drawer pedestal on the right and the cable grommetfree
office_chairround seat, a true arc back over it, and an armrest each sidefree
bookshelf · bookcase · shelfcarcass with its shelf bays ticked off along the run, read from the footprint's own long axis900 × 300derived
plant · planterpot as a true circle, foliage as a ring of eight radials at a 45° pitchsymmetric
carbody, cabin, the two screens, and a wing mirror each sidefree
sun_lounger · loungereased body, the raised backrest at the head end, and four to six transverse slatsfree
meeting_tablea long eased top inside a chair band, with the chairs drawn as rings — the dining_table rule, in swivel chairs2400 × 1200symmetric
reception_deskan L counter — a run along the back with a return down the left — its two nosings, and the chair inside the L2400 × 900derived
filing_cabinetnarrow carcass and top, three drawer lines across it, and the pull on the front edge450 × 600derived
lockera run of narrow doors at a clamped count, each with a vent tick on the room face1200 × 450derived
pool_tableeased frame, the cloth inside it, and six pockets — four at the corners, two on the long rails2500 × 1400symmetric
treadmillframe, the console band at the wall end, the belt, and the two side rails800 × 1800derived

A sun_lounger is aimed at the sun, and ArchLang has no sun model — the site layer names an aspect, not a daylight measurement — so nothing here derives which way it points and nothing warns about it. Say so with rotate.

The six commercial kinds take the drawing out of a house. Two things about them are decided rather than obvious. meeting_table follows dining_table's rule that the footprint includes its chairs — the dimension a plan needs to check is the one you cannot pull a chair out of — so a 2400 mm table is authored as roughly 3000 mm of footprint; it is drawn with an eased top and ring seats, which is what tells it from the square-topped dining table at a glance. And treadmill carries the largest clearanceMm in the catalogue, 900 mm, because the run-off space behind a user is the one thing a gym plan can be wrong about in a way that matters; dresser, vanity and filing_cabinet carry 600, for a drawer or a chair.

car earns its place for the same reason bench does: it is drawn on real plans (a carport, a driveway, a garage) and a model asked for one will write the word whether or not the catalogue knows it. Its long axis is the driving direction, drawn top-to-bottom like every other symbol's depth, so rotate 90 parks it across a garage.

Outdoor

Twenty-one families for what a site plan draws once the drawing leaves the building. They live in their own module (src/elements/glyphs-outdoor.ts) and follow one rule the indoor tables do not: planting is drawn unfilled, because a canopy overhangs ground — a path, a terrace, a parking bay — that has to keep reading through it.

Kind (and aliases)SymbolFootprintFacingWall
tree · deciduous_treesoftly scalloped canopy over the crown ring and the trunk, unfilledsymmetric
conifer · pinethe same canopy with the notches cut deeper, so it reads as needledsymmetric
shrub · busha lumpy cloud of eight overlapping lobes, unfilled, with three short interior arcs for foliagesymmetric
hedgea scalloped band — a chain of overlapping arcs down both faces, a half-scallop closing each end, one dashed centreline, and no box2000 × 600free
bbq · grill · barbecuethe body with a cross grid of grill bars, the side shelf down the right, and two wheels on the front edge1200 × 600derived
outdoor_table · patio_tableround or eased-rectangular top with four chairs hugging the footprint edgessymmetric
outdoor_chair · patio_chairthe chair construction — seat, back band, inset cushion — with slats across the back and an armrest each sidefree
umbrella · parasolan eight-segment canopy with the pole at the centresymmetric
bicycle · biketwo wheels at a quarter and three quarters of the run, the four-tube diamond frame between them, the saddle and the barsfree
motorcyclethe two wheels with the body slung between themfree
hot_tub · spathe shell, the water inside it, and the four seats round the rimsymmetric
swing · swing_setthe beam down the long axis, a leg at each end, and two seatsfree
trampolinethe frame, the mat, and twelve springs across the narrow band between themsymmetric
bin · wheelie_binthe body, the lid line at the hinged edge, and the two wheels under it600 × 700derived
mailbox · letterboxthe box with its flap, and the flag beside it400 × 300derived
ev_chargerthe pedestal against the back edge with the cable — a true arc — hanging off it400 × 300derived
pergolathe overhead frame on four posts, drawn entirely dashed and unfilledsymmetric
sandpit · sandboxthe eased kerb with five stipple dots for sandsymmetric
fire_pitthe rim, the bowl, and a four-lobed flame inside itsymmetric
shed · garden_shedthe carcass, a dashed roof ridge, and the door tick on the front2400 × 1800derived
clothesline · washing_linea post at each end of the run with three lines strung betweenfree

Nothing out here carries requiresWall, and that is a decision. The flag means services — supply, waste, venting, or hanging off a wall by definition — and W_FIXTURE_FLOATING's own remedy line says "supply/waste/venting runs in the wall". Two kinds tempt you to set it anyway and both are wrong: a hot_tub is genuinely plumbed and is still set down on a deck and fed from below, so a tub in the middle of a terrace is the normal arrangement; an ev_charger is genuinely wired and is as often on a free-standing bollard as on a wall. Outdoors the wall is the exception.

bbq is the only outdoor kind with a frontal clearance (900 mm — the standing room a cook needs at an open grill). The hot tub deliberately has none: it is symmetric, so it has no front to measure one from. The barbecue's back is the top edge, this module's convention — the shelf is on the right and the wheels are on the bottom, so the top is the edge clear of both and the one that goes against a wall or fence.

Three of the outdoor symbols are drawn from arcs alone, with no closed shape to fill: shrub and hedge (planting reads through, and a box around a hedge makes it read as a tray), and the outer half of every lobe only — a face scallop draws 120° of its circle, not the whole thing, or the run reads as a chain of overlapping rings.

Three of them are drawn dashed, and it is the same convention every time — above the cut plane, the rule upper_cabinet follows indoors and the one roof and void ship: the whole pergola outline, and the shed's roof ridge.

The five directional kinds (bbq, bin, mailbox, ev_charger, shed) are the ones you would write against wall or anchor about, and they are also the five that carry a footprint — so furniture shed against wall fence needs no size. outdoor_chair is deliberately free, for the reason every other seat in the catalogue is: seating is arranged, not installed.

What changed in v1.32

Twenty-six families were added — eight in Bath and Kitchen & utility, eighteen across Bedroom, Living & dining and Office & misc — and fourteen symbols that already existed were redrawn. Each of the fourteen still read as a rectangle with a line in it, which at plan scale is not a drawing of anything; several were not even distinguishable from each other (coffee_table and table differed only by a corner radius of 0.12 against 0.08 on the same two primitives, and washer and dryer were the same box at the same size).

The primitive counts below are measured, not estimated, at three footprints — 900 × 900, 2400 × 700 and 1800 × 600 — because several symbols read their own aspect and draw a different piece of equipment either side of a threshold rather than inventing one answer that is wrong for half the plans.

KindPrimitives (main → v1.32)What it gained
island2 → 7 / 9an eased worktop, a seating overhang with cabinet ticks under it, and by aspect either a hob or a sink bowl
upper_cabinet2 → 3 / 5 / 6a door split per 600 mm module and a hinge tick at each end of the back edge — a dashed empty rectangle is a void, this is cabinetry
dishwasher3 → 7two basket lines across the tub, and a door leaf with its control strip and handle
oven4 → 8 / 12three knobs, a door seam, a window and a handle bar; at aspect 1.6 or over it is a range and gains four burners
fridge4 → 5a door face line, a handle bar, and a compartment split placed by aspect — down the width of a side-by-side, across the depth of an upright
washer4 → 7a control panel with two knobs and a white porthole at the drum's centre, so it is no longer dryer's box
coffee_table2 → 6 / 7legs and a lower shelf
table2 → 6 / 7legs and supports, and a leaf seam on a long enough top
stool2 → 3a concentric third circle — a ring of foot dots would map onto itself under a quarter-turn and move the bytes for a drawing nobody can tell apart
bench3 → 7 / 8slats and legs
chair3 → 5a seat, a back and armrests
tv_unit3 → 6drawer splits and a plinth
nightstand3 → 6a drawer split and a pull
desk3 → 7a pedestal with drawer splits, and a modesty panel

Every one of them is structural detail rather than decoration — what the piece is made of and how it is used, not a texture — which is the only kind of line that survives being printed at 1:50. The redraw moves bytes on eighteen of the shipped example drawings and moves nothing else: describe() and lint() are SHA-256 identical on all thirty, and the changed lines all sit on A-FURN or on the A-ANNO legend swatches that are drawn from the same symbols.

How a symbol is drawn

Back on top. Every symbol is drawn with the side that goes against a wall along the top edge of its footprint, then quarter-turned about the footprint centre. So rotate 0 faces the back north, 90 east, 180 south, 270 west. Orient by the wall the piece sits against, or let against wall / in <room> anchor <edge> do it for you.

A drawn symbol ignores its label. A label reaches the drawing only through the labelled-rectangle fallback — that is, only for a kind the catalogue does not know. Writing furniture bed … label "Bed" is harmless but inert: the word stays in the source and in arch describe --json, and no text appears in the SVG. The fallback is the escape hatch, and it is deliberate: an uncatalogued word (furniture hammock at … label "Hammock") still draws a rectangle with its name in it, which is how you annotate something ArchLang has no symbol for.

A rug is an UNDERLAY, and it is the only kind that is. An underlay lies flat on the floor: furniture stands on it and people walk over it. Four rules read that one fact, and every one of them declines a check rather than adding one.

  • It is drawn with no fill at all — the only symbol in the catalogue that is. That is not a style choice: if it filled, a rug written after the sofa standing on it would paint over the sofa, and the same plan with the two lines swapped would look right. With nothing to paint over, there is no source order to get wrong.
  • A piece standing on it is not an overlap. W_FURNITURE_OVERLAP skips an underlay-and-not-an-underlay pair. Two rugs overlapping each other still warn — one rug half over another is a drawing mistake, and nothing about walking on them says otherwise.
  • It never blocks a fixture's use-space. A rug reaching under the basin is not what W_FURN_CLEARANCE is about; you stand on it.
  • It never blocks a route. Both walkability models — the whole-plan circulation grid behind arch describe --json's circulation block and the per-room flood fill behind W_ROOM_NO_CLEAR_PATH — drop it before they inflate anything by a body radius, so a rug across the only way into a room does not seal that room off.

W_FURNITURE_WALL_COLLISION deliberately still applies: what you can walk on has no bearing on whether it is drawn inside the plaster. The door rules (W_SWING_OBSTRUCTED, W_DOORWAY_BLOCKED) do not yet know about underlays either, so a rug in a doorway is still reported today.

Two symbols read their own footprint and change what they draw. Neither branch looks at the category word, because the shape is the honest datum:

  • basin draws two bowls, at the quarter points, once the slab is at least 2.2 times as wide as it is deep — the vanity convention. Below that it draws one, centred.
  • bed / double_bed draw two pillows once the mattress aspect (w / h) reaches 0.6, and one below it. On a 2000-long bed that falls at exactly the conventional 1200 mm single/double split, so furniture bed … size 1500x2000 draws the double it plainly is and a double_bed squeezed to 900 draws the single it has become.

A dashed outline means ABOVE THE CUT PLANE, and three fixture symbols use it. A floor plan is a horizontal section, so anything that sits above the cut is drawn dashed — present, but not cut — and unfilled, so whatever it overhangs still reads through it. upper_cabinet is dashed in its entirety because a wall cabinet hangs above the counter; a bunk_bed's upper deck is dashed for the same reason, and drawing it solid would claim the room has two mattresses of floor area; a vanity's mirror band is dashed because the mirror stands on the table. It is the same convention roof, void and the outdoor pergola and shed ridge follow, through one shared dashedPattern() helper. There is no syntax for saying "draw this piece above the cut plane" — a kind is dashed because of what it is.

dining_table's footprint includes its chairs. furniture dining_table … size WxH declares the whole eating zone: the table is the inner rectangle inside a chair-zone band, and the seats are drawn in that band. That is the dimension a plan needs to check — a table you cannot pull a chair out of is not a table that fits — so a 1200 mm table is authored as roughly 2400 mm of footprint. The seat count comes from the aspect, plus one at each short end when the table is under 2:1 (a square table seats its ends; a refectory bench does not).

The ASCII plan shows none of this. arch compile -f txt (and arch preview --ascii) reduces each piece to a single uppercase letter at its centre — the first letter of its category — because a character grid has no room for a symbol. The CLI turns on the annotate metadata the text backend needs to recover a category, so this works out of the box; a library caller passing a Scene built without compile(src, { annotate: true }) gets no marker at all for a drawn piece.

Sizes: catalogued footprints and the fixture library

The Footprint column above is what against wall uses when you omit size, so the common case has no numbers in it at all:

arch
furniture fridge       against wall w_west offset 400  in r_kitchen
furniture stove        against wall w_west offset 1200 in r_kitchen
furniture kitchen_sink against wall w_west offset 2000 in r_kitchen

The other placement modes always need an explicit size — an at (x,y) or in <room> piece has no wall to tell along from depth, so there is no unique answer to derive (E_FURN_SIZE).

Two importable libraries package the standard pieces at typical residential sizes, for when you would rather call a component than write a footprint:

arch
import "lib/fixtures.arch": wc, basin, shower, bathtub, kitchen_sink, counter, fridge
import "lib/furniture.arch": bed, double_bed, sofa, desk, wardrobe

wc(6200, 4600)
basin(5200, 4450)
shower(6000, 5000)
LibraryComponents
lib/fixtures.archwc 400 × 700 · basin 600 × 450 · shower 900 × 900 · bathtub 1700 × 700 · kitchen_sink 800 × 600 · counter 600 × 600 · fridge 600 × 650
lib/furniture.archbed 1500 × 2000 · double_bed 1800 × 2000 · nightstand 450 × 400 · wardrobe 1800 × 600 · sofa 2000 × 900 · sofa_l 2600 × 1600 · rug 2000 × 1400 · armchair 900 × 850 · coffee_table 1100 × 600 · tv_unit 1500 × 450 · dining_table 2400 × 2000 · desk 1400 × 700 · bookshelf 900 × 300 · piano 1500 × 1500 · sun_lounger 700 × 1900 · stove 600 × 600 · washer 600 × 600

Imports need a filesystem, so they work from the CLI and the library but not in the browser playground — the flagship examples/studio.arch uses inline furniture for exactly this reason. examples/furnished-flat.arch is the worked example: a two-bedroom flat furnished with twenty-nine of the thirty-six kinds across all five domains, arch validate --strict clean.

Furniture-aware lint rules

Placing fixtures meaningfully lets arch lint reason about habitability. The furniture and fixture rules (each documented in the error catalog):

CodeFlags
W_FIXTURE_FLOATINGa services fixture — plumbed, vented, or hung off the wall (WC, basin, shower, bath, sink, counter, stove, fridge, dishwasher, washer, dryer, upper cabinet) — placed away from any wall
W_FIXTURE_BACK_TO_ROOMa piece that is against a wall but faces the wrong way — its back (cistern, tap, nosing, headboard, wardrobe door line, bookshelf's open face) turned to the room. Carries a rotate fix when one edge is unambiguously the back. Arranged seating never trips it
W_FIXTURE_WRONG_ROOMa piece declared in <room> whose footprint does not sit on that room's floor (100 mm of overhang is allowed — a room edge is a wall centreline)
W_FURNITURE_OVERLAPtwo pieces overlapping by more than 1 mm on both axes — except an underlay and a piece standing on it (a sofa on a rug), which is the arrangement
W_FURN_CLEARANCEa fixture's frontal use-space blocked by free-standing furniture (an underlay never counts as the blocker)
W_ROOM_NO_FIXTUREa bath / WC / kitchen room with none of the relevant fixtures
W_SWING_OBSTRUCTEDa door leaf or swing arc sweeping onto a fixture

These are advisory — facts and warnings, never an auto-arranger (see ADR 0005). See Analysis: describe & lint for the full rule set and profiles.