ArchLang Playground

Two-storey (2 levels) — an ArchLang floor plan example

A compact two-storey house whose stair carries the same id on both floors, which is what declares one shaft.

Level 1 (Ground floor) compiles to 3 rooms, 56 m² of floor area and 2 windows; every room is reachable from the entrance.

UP Hall 15.4 m² Living 20.9 m² Kitchen 19.7 m² 700 1000 6500 2200 5800 8200 3600 3400 7200 4200 1800 2200 2200 5800 8200 4800 1200 1200 3600 3400 7200 100 200 N 01 m PROJECTTwo-storey houseDRAWN BYArchLangDATE2026-07-26SCALE1:50LEVEL1 — Ground floor
"Two-storey house" — a 3-room floor plan, 56 m² total: Hall (15.4 m²), Living (20.88 m²), Kitchen (19.72 m²); 3 doors, 2 windows, entrance via front.

This is a 2-level plan: a storey is a drawing, so the compiler produces one sheet per level and the drawing above is level 1. The command line writes one file per level, and the playground's preview has a storey switcher. Each storey measures:

Open in the editor

The source

This is the whole plan. The drawing above is what the compiler produced from it — nothing was drawn by hand.

# A compact two-storey house — one drawing per storey, from `level` blocks.
#
# Settings and the plan-global `let`s live OUTSIDE the levels and apply to every one of
# them: one building is issued on one sheet at one scale. Each level's body is an ordinary
# plan body, and ids are unique WITHIN a level — so the `stair` below exists on both floors
# at the same coordinates, and that shared id is what declares one shaft: `describe --json`
# reports it under `vertical.connections`, and it is why the first floor needs no front
# door of its own to lint clean.
#
# THE HEIGHTS DRAW NOTHING, AND THAT IS THE POINT. A plan is a horizontal cut, so the
# `height` below moves no byte of either drawing — `examples/two-storey.svg` is the same
# file it was before these clauses existed. What the datum feeds is `describe --json
# --select heights` and `arch compile --view axon`. It is written in three tiers, narrowing:
# the plan's `height 2700` is every storey's floor-to-floor, the upper `level … height 3000`
# overrides it for that storey alone, and a `sill`/`head` on a window bounds that one piece
# of glazing. `heights.elevation` ACCUMULATES the storeys below rather than multiplying, so
# the first floor sits at 2700 — the ground floor's height — not at 2 x 3000. Most windows
# here write nothing and take the 900/2100 defaults; the two that do write are the two a
# drawing cannot tell you about.
plan "Two-storey house" {
  units mm
  grid 50
  height 2700         # floor-to-floor for every storey that does not override it
  paper A3 landscape
  north up
  dims auto all

  let W = 8000        # outer width (wall centerlines)
  let D = 7000        # outer depth
  let T = 200         # exterior wall thickness
  let HALL = 2200     # the stair hall / landing runs the full depth on the left

  level 1 "Ground floor" {
    wall id=shell exterior thickness T { (0,0) (W,0) (W,D) (0,D) close }
    wall id=hall_w partition thickness 100 { (HALL,0) (HALL,D) }
    wall id=kitchen_w partition thickness 100 { (HALL,3600) (W,3600) }

    room id=hall at (0,0) size 2200x7000 label "Hall" uses hall
    room id=living at (2200,0) size 5800x3600 label "Living" uses living
    room id=kitchen at (2200,3600) size 5800x3400 label "Kitchen" uses kitchen

    door id=front on shell at 21900 width 1000 swing into hall
    door id=d_living on hall_w at 1800 width 900 swing into living
    door id=d_kitchen on hall_w at 5300 width 900 swing into kitchen

    # A tall window onto the garden: 300 off the floor and up to 2400, inside this
    # storey's 2700. The kitchen window beside it writes neither and takes 900/2100.
    window id=w_living on shell at 5000 width 1800 sill 300 head 2400
    window id=w_kitchen on shell at 13300 width 1200

    furniture sofa in living anchor top flush inset 300 size 2000x850 label "Sofa"
    furniture kitchen_sink against wall kitchen_w offset 1200 in kitchen
    stair id=stair at (100,1500) size 900x2600 dir up
  }

  # A taller first floor than the ground: `height` in the level HEADER overrides the plan's
  # 2700 for this storey only (a `height` in the body would be E_LEVEL_MIX).
  level 2 "First floor" height 3000 {
    wall id=shell exterior thickness T { (0,0) (W,0) (W,D) (0,D) close }
    wall id=hall_w partition thickness 100 { (HALL,0) (HALL,D) }
    wall id=bath_w partition thickness 100 { (0,4600) (HALL,4600) }
    wall id=bed_w partition thickness 100 { (HALL,3600) (W,3600) }

    room id=landing at (0,0) size 2200x4600 label "Landing" uses circulation
    room id=bath at (0,4600) size 2200x2400 label "Bath" uses bath
    room id=bed1 at (2200,0) size 5800x3600 label "Bedroom 1" uses bedroom
    room id=bed2 at (2200,3600) size 5800x3400 label "Bedroom 2" uses bedroom

    # No exterior door up here: the `stair` below carries the same id as the ground
    # floor's, so the access graph reads the landing as reached from outside via the
    # storey below. (Before vertical circulation was modelled this floor needed a
    # made-up balcony door to lint clean.)
    door id=d_bed1 on hall_w at 1800 width 900 swing into bed1
    door id=d_bed2 on hall_w at 4100 width 900 swing into bed2
    door id=d_bath on bath_w at 1100 width 800 swing into bath

    window id=w_bed1 on shell at 5000 width 1500
    window id=w_bed2 on shell at 13300 width 1200
    # A bathroom window set high for privacy: `sill` alone, so the head still defaults to
    # 2100 — an authored bound and a defaulted one on the same opening.
    window id=w_bath on shell at 24200 width 600 sill 1500

    furniture bed in bed1 anchor top-right flush inset 300 size 1500x2000 label "Double"
    furniture bed in bed2 anchor bottom flush inset 300 size 1000x2000 label "Single"
    furniture wc in bath anchor bottom-left flush size 400x700
    furniture basin in bath anchor bottom-right flush size 600x450
    stair id=stair at (100,1500) size 900x2600 dir down

    # The landing looks down into the hall below over a balustrade: there is no floor
    # here, so the plan says so. A `void` is drawn (dashed rectangle + both diagonals)
    # and it OBSTRUCTS circulation — you cannot walk across a hole — with the walkable
    # halo suppressed on every edge, because you can stand at the railing. It does NOT
    # come off the landing's area: that number is the room's floor area and it is what
    # the schedule and `describe --json` both report, so subtracting the well here would
    # leave the drawing and the table disagreeing. `describe --json` lists it under
    # `voids[]` with the room it falls in, which is where a net figure comes from.
    void id=gallery at (100,200) size 900x1100

    # The eaves, on the top storey only — this level's `shell` is the plan's one
    # closed exterior ring on THIS page, so no `wall` clause is needed.
    roof overhang 400
  }

  title {
    project "Two-storey house"
    drawn_by "ArchLang"
    date "2026-07-26"
  }
}

Read more