Skip to content

Parameters and expressions

This page as Markdown/docs/schema/parameters-and-expressions.mdView .md

parameters are the numbers a person would want to change: the mattress size, the timber, the deck height. Everything else in the document should be derived from them, so that changing one moves the whole piece rather than leaving half of it behind.

parameters:
- id: deck_height
label: Height of the slat top above the floor
type: length
value: 300
min: 180
max: 500
- id: deck_width
label: Clear width between the rails
type: length
derived: mattress.width + 2 * mattress_clearance

Every parameter has an id and a type, and optionally a label and a description. The label is what a person sees; write it as a sentence, not a variable name.

value is entered. derived is computed, and is always an expression string. A parameter with neither is SCH-002.

The distinction is the difference between a piece that can be resized and one that cannot. If you find yourself typing the same arithmetic into two blank: entries, that number wanted to be a derived parameter.

Millimetres. min and max bound it, and are themselves expressions.

- id: headboard_height
type: length
value: 900
min: 600
max: 1400

The same shape as lengthvalue or derived, with optional min and max. count is a whole number of things; angle is degrees.

A closed list, and a chosen value. Referencing it yields the string, so it is normally fed into a material’s species rather than into arithmetic.

- id: species
type: enum
values: [walnut, white_oak, ash, maple, cherry]
value: walnut
- id: add_centre_rail
type: boolean
value: true

Names a catalogue family and one entry in it. This is the useful one: the parameter then behaves like the entry, so its fields read as sub-references.

- id: mattress
type: catalog_ref
catalog: standards.mattress
value: us-queen

mattress.width is then 1524 and mattress.length is 2032, and changing value to uk-double moves every part derived from them. A value that is not in the family is RES-005, and the report lists the ones that are.

Expressions are the only computation in the format, and the evaluator is a hand-written recursive-descent parser. It never calls eval, never builds a function and never reaches a global. The only names it can see are the ones listed below.

Operators, in the usual precedence: ^ · * / % · + - · < <= > >= · == != · && · || · ? :, with unary - and !, and parentheses.

Functions: min, max (both variadic), round, ceil, floor, abs, sqrt, clamp(value, low, high).

count: ceil((slat_cleat.blank.length - slat.blank.width) / (slat.blank.width + max_slat_gap)) + 1

There are no user-defined functions, no loops and no conditionals beyond the ternary. If a computation does not fit, the answer is another derived parameter, not a longer expression.

Reference Yields
deck_height A parameter’s value
mattress.width A field of a catalog_ref parameter’s entry
rail_stock.thickness, .width A resolved material’s actual milled dimension
rail_stock.density, .modulus_of_elasticity That material’s species properties
side_rail.blank.length, .width, .thickness Another part’s resolved blank
standards.bed.slat_gap_max A catalogue standard

That table is the whole reach of the language. A bare part or material name is not a value — side_rail on its own resolves to nothing. Local names win over catalogue names, and nothing local may be called standards.

Resolution is lazy and memoised, so these may depend on each other in any order. A real loop is RES-003, and the finding names the cycle.

Anywhere the reference says Expr: blank dimensions, feature sizes and positions, offsets, pattern counts and spacings, min/max bounds, and array counts.

In a number-typed field, a string is always an expression — no marker needed:

blank:
length: deck_length # expression
width: rail_stock.width # expression
thickness: 38 # number

In a text-typed field, an expression needs a leading =, because the literal text is usually what you meant:

species: walnut # the literal string "walnut"
species: "=species" # the value of the `species` parameter

Catalogue keys contain hyphens — standards.mattress.us-queen.width — and so does subtraction. The rule the tokeniser applies:

A hyphen continues an identifier only when it sits directly between an identifier character and a letter or underscore, with no whitespace.

Written Read as
us-queen one name
deck_height - rail_stock.width subtraction
width-10 subtraction — a digit follows the hyphen
a-b one name

So if you mean subtraction between two single-word names, put spaces around the minus. Getting it wrong is a clear RES-002 — an unknown name — not a wrong number quietly compiled.

parameters:
- { id: mattress, type: catalog_ref, catalog: standards.mattress, value: us-queen }
- { id: mattress_clearance, type: length, value: 6, min: 3, max: 15 }
- { id: deck_height, type: length, value: 300 }
- id: deck_width
type: length
derived: mattress.width + 2 * mattress_clearance
- id: max_slat_gap
type: length
derived: standards.bed.slat_gap_max
- id: post_centre_offset
type: length
derived: deck_width / 2 + rail_stock.thickness / 2

Nothing in that block is a measurement of this particular bed. Change us-queen to uk-double and the rails, the cleats, the slat count and the gap between slats all follow.