Skip to main content

space — spaces

For mode spatial, see spatial models: unwritten boundaries stay unresolved, heights and slabs may be omitted, and architectural assessment is not evaluated.

space /L5/A/ldk ldk X1+3200..X2+3200 Y1..Y1+4000 + X2+3200..X3 Y1..Y1+2400 name:LDK floor:オーク
space /out/road-s name:南側道路 road:12000 outside:1

space <path> <type> [regions...] [attributes...] declares a space. Space is the primary element — a wall is not a possession of a space but a relation between two of them (boundary), and plans, areas and circulation are all derived from how spaces are laid out.

Path — identity​

The first positional is a path beginning with /, and that is the space's identity in the model.

space /L5/A/ldk ldk X1..X2 Y1..Y2
  • A path is also the hierarchy of aggregation. Grouping by prefix is the job of a zone: the zone /L5/A has every space whose path begins /L5/A/ beneath it.
  • If the first segment is a declared level name, the space belongs to that level. /L5/A/ldk sits on L5. If it is not a level name (/site/bldg, say), the level is undetermined and must be stated with level:.
  • A duplicate path is an error. Under composition, the provenance of both is shown.
Duplicate space path: /L1/a (first seen in floors/L1.muro at line 12)

Paths change when things are renamed. To join against an external register across a rename, use uid:.

Type — an open vocabulary​

The second positional is the type, and it is optional. room, ldk, 厨房, tenant are all fine, and so is writing nothing at all.

space /L1/a room X1..X2 Y1..Y2
space /L1/b X1..X2 Y1..Y2

The type is the room's purpose — what the room is for, in whatever word you use for it. Every other division of the building (a tenancy, a fire compartment, a department) is a namespaced attribute, and a space may carry as many of those as it likes; the purpose is the one thing there is only ever one of.

core reads no meaning from the type position. The word appears in the aggregation axis (stats subtotals by type) and in the lettering on a plan, and no shape follows from it. Misspelling it produces no error: write bedrom for bedroom and you get one more row under a new type.

Judgement may read it. koyu.schematic.access.parking takes its population from the words parking and ramp, so parkign drops that room out of the rule quietly. Nothing guards a free word — which is why the facts of composition are not written here.

Write no type and the canonical form carries no type key. No default word is fabricated.

Facts of composition live in the declaration​

Being outside, and being a void, are written as attributes rather than as a type.

DeclarationMeaning
outside:1Outside the building. May have no region. Add road: and it takes part in street frontage
void:1A void through the floor. Not counted in floor area, not passable, and neither floor nor ceiling is generated
space /out name:南側道路 road:6000 outside:1
space /L2/hole X1..X2 Y1..Y2 name:吹抜け void:1

These two used to be written in the type position. That position is an open vocabulary, so the moment one extra character was typed — exteriorr — the space stopped being outside and the gross floor area went from 16.20 m2 to 32.40 m2 while check stayed green. The guard against that was a watch that refused words one edit away from either, which is a hunch standing in for a rule; it could not even be widened, because two edits from void reaches road and wood, words a person may legitimately write.

Moved into the attribute position, the spelling is guarded by the ledger instead (ATT03 refuses an unknown key, ATT02 refuses a value outside the domain). outsid:1 is an error; acme.outside:1 passes as carrier tier — because that is the author spelling out "this word is mine and the tool does not read it". Being open and being trustworthy hold together as long as the boundary is declared (scope).

Regions — a union of rectangles​

A region is two tokens, X?..X? Y?..Y?: one range on X and one on Y. A + written as its own token joins several rectangles into a union (an L shape, for instance).

space /L1/L ldk X1..X3 Y1..Y2 + X1..X2 Y2..Y3 name:L字
  • A descending spelling (X2..X1) is another way of writing the same rectangle and is normalized to ascending order.
  • A zero-width region is an error.
  • Rectangles overlapping within one space is GEO01; spaces on the same level overlapping is GEO02, both errors.
  • The region may be omitted. exterior spaces, and spaces that exist only to be aggregated, are written without one. A space with no region cannot carry a subdivision.

A space with a region needs a level and a ceiling height. Without either, not one solid can be produced, which is the error SUF02 or SUF01.

How grid references and offsets are spelled is in positions and regions.

Writing by dimension — band members​

To divide by dimension and order rather than position, use band. A space line indented under a band carries w: in place of a region.

band X X1..X3 Y1..Y2
  space /L1/ldk ldk w:3600 name:LDK
  space /L1/hall hall w:1800 name:玄関

w: may not be written on an unindented space. That refusal is what stops a member whose indentation was lost from passing silently as "a space with no region".

✖ b5.muro:line 4: w: may not be written on space (a space written by width sits indented under band)

The indented subdivision — area​

An area indented under a space is an uncounted subdivision of the room: a change of floor finish, say, that appears in no area total, no room count and no graph. See area.

Level spans​

If the first segment of the path has the form L3..L10, the line expands over the declared levels in ascending z. This is how a typical floor is written once.

space /L2..L9/B unit X2..X3 Y1..Y2 name:Bタイプ lease.category:exclusive

Several paths on one line must name the same span. Indented area lines are attached to every expanded space.

The attributes​

The keys writable on a space are the ones listed here plus any namespaced key containing a dot (acme.sensor:23). A key that is in neither category is the error ATT03 — the point is to stop heigh:2400 from being read past in silence while check stays green.

✖ s1.muro:line 4: /L1/a carries heigh:, which is not in the ledger (check the spelling, or add a namespace if the value is only carried — e.g. acme.heigh:2400)

They fall into three tiers. Structure is lifted into typed fields by the parser, interpreted is read for its value by core, and carry is never looked at and only transported. The tiers are set out in the three tiers of attributes.

Structure​

KeyValueMeaning
level:a declared level nameStates the level. The default is the first path segment. Needed for a grouping that spans levels (a maisonette) and whenever the path does not start with a level name (/site/bldg). An undeclared level stops with Undeclared level: level:L9
w:positive integer mm / restThe dimension of a band member. Not writable on a space outside a band

Interpreted​

KeyValueMeaning
h:positive number, mmCeiling height. Defaults to the level's h:. Read by the height invariant and the section stack-up
road:positive number, mmThe width of an exterior space — the mark of a road. site derives frontage from it
daylight:0 / 1Declares that the daylight check applies. Only a space with 1 gets light's 1/7 test. Out of scope by default. Not inherited
ceiling:0 / 10 hangs no ceiling (an exposed soffit). One is hung by default
uid:opaque tokenPersistent identity across renames. Digits alone, or whitespace, is an error. Unique across the whole model, spanning space and zone
name:free wordDisplay name, shown in drawings and listings. Without it, the last path segment is used
stair: ramp: escalator:N / E / S / WA vertical-circulation declaration. The key names the device, the value the direction of ascent
lift:1A lift declaration (it has no direction)
form:straight / returnWhether the run turns back. Default straight
turn:R / LWhich way it turns back. Default R
entry:positive number, mmThe depth of the boarding floor. Default 1100
landing:positive number, mmThe depth of an intermediate landing. Derived by default (the remainder from the target going)
riser:positive number, mmThe maximum riser. Default 180
tread:positive number, mmThe target going. Default 300
lane:positive number, mmThe width of one unit or lane. 1200 by default for an escalator
slope:positive numberThe denominator of the permitted ramp gradient (slope:6 = up to 1/6). A limit for the check, not a gradient to build
use:free wordRetired after muro 1.2. A file declaring 1.3 or later that writes it is VER07. The room's purpose is the type position; any other division is a namespaced key

Values are checked too. A non-number is ATT01 and a word outside the ledger's set is ATT02 (daylight is guarded by DAY01, and form and the directions of ascent by the RUN family). What you wrote and the tool failed to interpret does not fall silently back to the default.

$ npx tsx src/cli.ts check s3.muro --json
  "code": "DAY01",
  "message": "daylight is either 1 (in scope for the daylight check) or 0 (out of scope): /L1/a carries daylight:yes",
  "code": "ATT02",
  "message": "ceiling on /L1/a is one of 0 / 1: ceiling:2",
  "code": "ATT02",
  "message": "turn on /L1/a is one of R / L: turn:X",

Carry​

KeyMeaning
floor:Floor finish. An area may override it over an interval
spec:The name of the thing. Carried, never interpreted
<namespace>.<key>:Anyone may write a dotted key, and core gives its content no meaning at all (acme.sensor:23, bems.temp:22.5)

Keys a space may not carry​

Three worth naming.

  • site: and area: belong to a zone. On a space they are ATT03.
  • underground: belongs to a level. On a space it is ATT03.
  • type: belongs to a boundary. A space's type is the second positional, not an attribute.

daylight — the scope is declared​

muro 1.6
grid X 0 4000
grid Y 0 5000
level L1 0 h:2400 slab:150
space /L1/living living X1..X2 Y1..Y2 daylight:1 name:居間
space /out name:外部 outside:1
boundary /L1/living /out edge:S t:120
  window w:2400 h:1800
boundary /L1/living /out edge:E
boundary /L1/living /out edge:N
boundary /L1/living /out edge:W
$ npx tsx src/cli.ts light d1.muro
  /L1/living	居間	window 4.32 m2 / floor 20.00 m2 = 1/4.6
1 room in daylight scope — these are numbers, not a verdict (koyu validate applies the rule)

A room without daylight: is outside the test. The attribute names what the tool does, not a legal category — what the 1/7 applies to is the author's call.

ceiling — the ceiling is an approximation​

The ceiling surface is derived as the room's outline at the height h: fixes.

That outline does not necessarily match the real ceiling. A coffered ceiling, a bulkhead under a beam, a ceiling running continuously across several rooms, a shadow gap in front of a curtain wall — all of these are outside this resolution. The derivation is an approximation at the resolution of scheme design, not a drawn ceiling.

Only the absence of a ceiling — an exposed soffit — can be declared.

grid X 0 3600 7200
grid Y 0 4000
level L1 0 h:2400 slab:150
space /L1/a room X1..X2 Y1..Y2
space /L1/b room X2..X3 Y1..Y2 ceiling:0
space /out outside:1
boundary /L1/a /out
boundary /L1/b /out

The surfaces this model generates are these; /L1/b has no ceiling.

floor /L1/a -150 0
ceiling /L1/a 2370 2400
roof /L1/a 2400 2600
floor /L1/b -150 0
roof /L1/b 2400 2600

Voids, the outside, semi-outdoor spaces and vertical circulation never get a ceiling in the first place, so ceiling:0 is unnecessary there.

Vertical circulation​

Stairs, ramps, escalators and lifts are declared with the key that names the device and the direction of ascent. No riser count, going, landing or gradient is written — they are derived from the region and the storey height.

space /B2..B1/ramp ramp X3..X5 Y1..Y2 name:車路 ramp:E form:return slope:6
space /B2..B1/st stair X3..X3+2600 Y2..Y2+5400 name:避難階段 lease.category:common stair:N form:return
space /B2..B1/ev shaft X3+2600..X3+5200 Y2..Y2+5400 name:EV lease.category:common lift:1
$ npx tsx src/cli.ts runs examples/basement/main.muro
B2→B1	lift	EV	/B2/ev
B2→B1	ramp	車路	rise 3700mm	return	slope 1/7.2	going 26800mm	/B2/ramp
B2→B1	stair	避難階段	rise 3700mm	return	21 risers of 176mm, tread 300mm	going 6000mm	/B2/st
B1→L1	lift	EV	/B1/ev
B1→L1	ramp	車路	rise 3700mm	return	slope 1/7.2	going 26800mm	/B1/ramp
B1→L1	stair	避難階段	rise 3700mm	return	21 risers of 176mm, tread 300mm	going 6000mm	/B1/st
L1→R	lift	EV	/L1/ev

One space carries one device (two is RUN01), and its region must be a single rectangle. Which storeys it connects belongs to the vertical boundary, not to the space — the device declaration is a rule for generating form, not a topology. The whole set of rules is in vertical circulation.

What a space produces​

Writing a space produces things you did not write.

  • Area — measured to wall centerlines; void and exterior are outside the gross floor area.
  • Boundaries — spaces on the same level whose regions touch get a wall boundary derived for them unless one was declared.
  • Semi-outdoor — a space touching an exterior across an open or air:1 boundary is treated as semi-outdoor, and neither ceiling nor roof is laid over it.
  • Columns — they stand at grid intersections that fall inside a space with floor.
  • Floors, ceilings, roofs — generated from the level's slab: and h:.
$ npx tsx src/cli.ts stats v1.muro
L1
  /L1/hall	ホール	hall	14.40 m2
  /L1/r	r	room	14.40 m2
  Subtotal 28.80 m2
L2
  /L2/void	吹抜け	void (not counted as floor area)
  /L2/r	r	room	14.40 m2
  Subtotal 14.40 m2
Total 43.20 m2 (indoor floor area)
  hall: 14.40 m2
  room: 28.80 m2

To subdivide, make the parent a zone​

Putting a space with a region beneath a space with a region makes their regions overlap, which is GEO02.

grid X 0 3600 7200
grid Y 0 4000
level L1 0 h:2400 slab:150
space /L1/A unit X1..X3 Y1..Y2
space /L1/A/ldk ldk X1..X2 Y1..Y2
space /out outside:1
boundary /L1/A /out
boundary /L1/A/ldk /out
✖ z1.muro:line 4: Space regions overlap: /L1/A and /L1/A/ldk

To divide a dwelling into rooms, make the parent a zone. A zone has no geometry; it only groups by path prefix.