Skip to content
Part of the ArchCanvas family

Designs that compile.A declarative language for floor plans.

ArchLang is an open-source (MIT) language for floor plans: write .arch source and compile it to SVG, DXF or PDF, with linting and geometric checks.

  • npx -y @chanmeng666/archlang compile plan.arch
  • claude mcp add archlang -- npx -y @chanmeng666/archlang-mcp
  • npx -y skills add ChanMeng666/archlang --yes
laneway-house.archcompiled
plan "Laneway House" {
  units mm
  grid 50            # partitions are 100 thick, so a `flush` fixture lands on a …50
  north up
  dims auto all
  site { street north }

  wall id=w_lane   exterior  thickness 200 { (0,0) (7500,0) }
  wall id=w_east   exterior  thickness 200 { (7500,0) (7500,6500) }
  wall id=w_garden exterior  thickness 200 { (0,6500) (7500,6500) }
  wall id=w_west   exterior  thickness 200 { (0,0) (0,6500) }
  wall id=w_hall   partition thickness 100 { (4200,0) (4200,6500) }
  wall id=w_bath   partition thickness 100 { (4200,2500) (7500,2500) }

  room id=r_live at (0,0) size 4200x6500 label "Living / Kitchen" uses living kitchen
  strip down at (4200,0) gap 0 width 3300 {
    room id=r_bath size 2500 label "Bath"    uses bath
    room id=r_bed  size 4000 label "Bedroom" uses bedroom
  }

  door id=d_front  on w_lane at 2100 width 900 hinge near start swing into r_live
  door id=d_garden sliding on w_garden at 2700 width 1800 slide left
  door id=d_bed    on w_hall at 5600 width 800 hinge left swing into r_bed
  # `w_hall` is walked lane→garden, so `slide right` sends the panel down the solid wall
  # below the jamb; `slide left` would aim it at 500 mm and trip `W_POCKET_RUN`.
  door id=d_bath   pocket on w_hall at 900 width 800 slide right

  window on w_west   at 2400 width 1200
  window on w_garden at 700  width 1000
  window on w_garden at 5850 width 1600
  window on w_east   at 1500 width 600

  furniture fridge       against wall w_west offset 400  in r_live
  furniture stove        against wall w_west offset 1200 in r_live
  furniture kitchen_sink against wall w_west offset 2000 in r_live
  # The rug is an UNDERLAY, drawn before the pieces that stand on it so the sofa and
  # table sit visibly on top rather than hiding it — anchored to the room, like
  # everything else here, never a coordinate.
  furniture rug   in r_live anchor bottom-left inset 400 size 2800x3400
  furniture table  in r_live centered size 1300x900 label "Table"
  furniture sofa   in r_live anchor bottom-left flush inset 250 size 900x2000  label "Sofa"
  furniture bed    in r_bed  anchor bottom-right flush inset 250 size 1500x2000 label "Bed"
  furniture robe   in r_bed  anchor top-left     flush inset 200 size 1800x600  label "Wardrobe"
  furniture shower in r_bath anchor top-right    flush size 900x900
  furniture wc     in r_bath anchor bottom-left  flush size 400x700
  furniture basin  in r_bath anchor bottom-right flush size 600x450

  title { project "Laneway House" drawn_by "ArchLang" date "2026-08-16" }
}
Laneway HouseSheet A-101
Living / Kitchen 27.3 m² Bath 8.3 m² Bedroom 13.2 m² 300 1000 600 1800 1450 1600 950 4200 3300 7700 1900 1200 3600 2500 4000 6700 1750 900 5050 4200 3300 7700 1300 600 4800 2500 4000 6700 100 200 N 02 m PROJECTLaneway HouseDRAWN BYArchLangDATE2026-08-16
The whole language on one sheet — a compiled ArchLang floor plan
A-101Showpiece

The whole language on one sheet

Two storeys, an attached garage, one A2 sheet at 1:50 — 11 rooms and 196.54 m² on the ground floor, nine rooms and 140.76 m² above. Nearly every sheet below appears here at once: site orientation, a polygon reading nook, an L-shaped master suite, an arc-bowed bay off the living room, all six door kinds — the five that have to be named, plus the hinged default on the rest — one stair shaft declared by a shared id on both level blocks, a void over the double-height living room, roof eaves, and a mirrored pair of ensuites placed from a single component. arch lint still raises three warnings, left in and named in the source — the honest cost of a real site, not a plan tuned to hide them.

hillside-villa.archOpen in Playground ↗
townhouse.arch storey 1 of 3 — a compiled ArchLang floor plantownhouse.arch storey 2 of 3 — a compiled ArchLang floor plantownhouse.arch storey 3 of 3 — a compiled ArchLang floor plan
A-102Levels

One storey is one drawing

A plan written as level blocks compiles to a complete sheet per storey — three here, 4 rooms and 55.64 m² each, on a 5.5 × 11 m terrace footprint. That is the outer face, which is what a footprint means; the plan's own let W and let D are the 5.2 × 10.7 m wall centrelines, and every plan here has both numbers. arch compile writes townhouse.L1.svg, .L2.svg and .L3.svg; the three drawings above are those files. The stair is one object written three times: ids are unique within a level, so the same id=st on all three storeys is not a clash but the declaration that these are one shaft — and it is why the upper floors lint clean with no front door of their own.

townhouse.archOpen in Playground ↗
It issues a sheet, not a picture — a compiled ArchLang floor plan
A-103The sheet

It issues a sheet, not a picture

paper, scale, positioning axes, a room schedule, a legend and a title block — a 50 × 32 m public library on A2 landscape at 1:200, 14 rooms and 1545.06 m². Nothing in the margin is configured: the schedule's rows and total are the same numbers arch describe --json reports, and the legend lists one row per wall material actually used and one per placed fixture category that has a plan symbol. Add a seventh material and the table grows a row on its own.

library.archOpen in Playground ↗
Not only rectangles — a compiled ArchLang floor plan
A-104Geometry

Not only rectangles

Polygon rooms measured by exact shoelace area, circular rooms measured as πR², and true arc wall edges — SVG A commands and native DXF arcs, never faceted at any zoom. Six trapezoid galleries ring a drum here: 7 rooms, 122.79 m², and a rotunda of exactly 28.27 m² inside a wall of arc edges on a radius of 3000. Nothing in this plan is rectangular, and the hexagon is irregular on purpose — a 3-4-5 shell lands every vertex on the 50 mm grid, where a regular one would measure 7504 and have to be called 7500.

hexagon-pavilion.archOpen in Playground ↗
Everything outside the wall line — a compiled ArchLang floor plan
A-105Site

Everything outside the wall line

A lot line, ground materials, fences and a roof: 15 outdoor surfaces across all nine kinds — 14 on the ground and the balcony a storey up — two fence runs and a 484 m² lot around a house of 11 rooms and 240 m² over two storeys, 6 rooms and 136.5 m² of that on the ground floor the drawing shows. Read those totals off describe --json's levels[], not off its top level: the top-level facts are the LOWEST STOREY, so a page-1 read of this plan loses the balcony and with it the ninth ground kind. Floor, ground and lot are three different numbers and the language keeps them apart — a terrace is not floor area, so a ground surface appears in no rooms[] entry, no schedule row and no access graph. Every hatch is scale-aware: the same pattern size on the sheet at 1:100 as it would be at 1:50.

garden-house.archOpen in Playground ↗
Symbols, not labelled boxes — a compiled ArchLang floor plan
A-106Fixtures

Symbols, not labelled boxes

A WC with a cistern and a seat, a bed with a headboard and pillows, a washer told from a dryer by the chords across its drum — 39 pieces across 38 of the 83 catalogued families, in 7 rooms and 90.72 m². A drawn symbol ignores its label, so every word on this plan comes from a room; most pieces carry no size either, because against wall takes the catalogued footprint and derives the rotation from the wall. A fixture category is a catalogue row, never a keyword.

furnished-flat.archOpen in Playground ↗
Write the unit, place the row — a compiled ArchLang floor plan
A-107Composition

Write the unit, place the row

Four terrace dwellings from one component — 16 rooms, 199.8 m², 16 doors and 18 windows across 22.45 × 9.85 m over the outer faces, written as component unit(w, d, gable) in its own coordinates and then four place statements with mirror x on alternate units. The offsets are a running sum over an array rather than typed coordinates, and an if inside the component puts a side window on the two free gables only. A pinned label is a point like any other, so the mirrored units get their mirrored label positions for free.

terrace-row.archOpen in Playground ↗
Poché is the specification — a compiled ArchLang floor plan
A-108Materials

Poché is the specification

On a real drawing the hatch inside a cut wall is the specification, and ArchLang spells it as one clause on wall: material poche, concrete, brick, insulation, tile or none. All six are here, each on the element a builder would actually detail that way — 300 mm concrete facades, a 230 mm brick gable with its courses turned along the wall, a 200 mm insulation leaf drawn as its own wall, tile on the WC partitions, none on the glazed screen — over 4 rooms and 128 m². style wall and style room restyle the inks without touching a coordinate, and the legend beside them is derived: one swatch per material actually used.

materials.archOpen in Playground ↗

describe() & lint

Reads its own plans

A plan compiles to a drawing — and to facts. describe() returns rooms, areas, adjacency, a modelled access graph and circulation figures; lint() flags habitability and circulation problems. Both are image-free, so an agent can confirm what it drew without rendering a pixel.

GARDEN LOFT · A-201 · SCALE 1:50
Living / Kitchen 21.0 m² Bedroom 9.0 m² Bath 5.0 m² 2850 900 1050 600 1800 4200 2800 7200 3000 1400 800 3200 1800 5200 1600 1800 1700 1200 900 4200 2800 7200 100 200 N 02 m PROJECTGarden LoftDRAWN BYArchLangDATE2026-08-16SCALE1:50
garden-loft.archOpen in Playground ↗
Room schedule← describe()
RoomUseAreaAdj.
Living / Kitchenliving, kitchen21 m²2
Bedroombedroom8.96 m²2
Bathbath5.04 m²2
Total3 rooms35 m²7

3 doors · 4 windows · entrance verified · every room reachable

// built for agents

An interface, not just an image.

ArchLang answers on an agent's own terms. Every archlang command takes --json with deterministic exit codes; archlang context prints the whole language, workflow and error catalog as one system-prompt-ready bundle (llms-full.txt); and SKILL.md is the write → compile → describe → repair loop it follows. No pixels required to verify intent.