Parameters & coordinates
This is the one idea that makes Molding click. When you select an element on the Generators tab, every position / size / depth / radius / angle field shows two small buttons — V and P. That toggle is the whole coordinate concept:
Each field is V or P
V(value) — a fixed number you type, in millimetres for lengths or radians for angles:45,0,1.5708.P(parameter) — the field follows a parameter you pick from the dropdown, so it changes whenever that parameter does. The−button next to it negates the parameter (mirror across the origin), e.g.HalfWidth→-HalfWidth.
That is the whole grammar: a field is either a fixed number or one parameter (optionally negated). There is one thing you will look for and not find:
There is no place to type a formula into a geometry field. A field is only ever V (a number) or P (one parameter). Any arithmetic goes into a parameter instead.
Where the math lives: parameter formulas
To centre a rectangle at half its height, you do not compute Height / 2 on the field. You add a parameter that computes it, then point the field's P at it:
Parameter HalfHeight formula: Height / 2 (Parameters tab)
Rectangle center Y: P -> HalfHeight (Generators tab)Why split it this way? Because it keeps every field trivial and identical in the browser preview and the Revit runner — both only ever ask "is this a number, or a parameter to look up?". The arithmetic lives in exactly one place (the parameter's formula), and Revit's own solver owns it.
The door panel, as parameters and fields
This is the family you built in Getting started, written out:
Parameters tab
Width length
Height length
Thickness length
HalfHeight length formula Height / 2
Types tab
"0900 x 2100mm" Width 900 Height 2100 Thickness 45
Generators tab
Rectangle
width = P -> Width
height = P -> Height
center = [ V 0 , P -> HalfHeight ]
Extrusion
profile = [x] Rectangle (ticked in the checkbox list)
depth = P -> ThicknessChange Width and the rectangle widens; HalfHeight updates through its formula so the panel stays centred — all from one edit. The extrusion's depth just points at Thickness because no math is needed there.
A parameter has no value — family types do
This is Revit's own rule and Molding follows it exactly: a parameter declares what it is (name, type, group, instance-or-type, and maybe a formula), and a family type holds what it is set to. A family with no type has nowhere to put a number, so every family has at least one type.
"parameters": [
{ "key": "Width", "type": "length", "group": "dimensions" },
{ "key": "Height", "type": "length", "group": "dimensions" },
{ "key": "Thickness", "type": "length", "group": "dimensions" },
{ "key": "HalfHeight", "type": "length", "group": "constraints", "formula": "Height / 2" }
],
"types": [
{ "name": "0800 x 2100mm", "values": { "Width": 800, "Height": 2100, "Thickness": 45 } },
{ "name": "0900 x 2100mm", "values": { "Width": 900, "Height": 2100, "Thickness": 45 } }
]Two rules follow from that:
- A parameter is driven either by a formula or by per-type values, never both.
HalfHeighthas a formula, so it never appears invalues— Revit computes it for every type. - Every parameter without a formula has a value in each type. The exception is the string-storage types (
text,material,url,multilineText): leaving the key out means "no value", which is what Revit shows as an empty parameter. - A type parameter's formula cannot read an instance parameter. A type parameter holds one value per family type, so it has no way to follow a value that varies per placed copy, and Revit answers
SetFormulawith "Formula setting failed." (measured 2026-09-24, Revit 2023). Either mark the dependent parameterinstancetoo —HalfHeightmay read an instanceHeightas long asHalfHeightis itself an instance parameter — or keep the one it reads a type parameter. Molding refuses the combination before generation rather than letting Revit drop the formula.
Adding a second type is how you ship a size catalog (0800 × 2100, 0900 × 2100, …). The user picks a type when placing the family; instance parameters stay tunable per placement on top of that.
Formula operators
A formula is written in Revit's family-formula language, not JavaScript — the string is handed verbatim to Revit's FamilyManager.SetFormula, so Molding accepts exactly what Revit accepts. Formulas (not coordinates) carry the arithmetic and may reference other parameter keys.
| Kind | Operators |
|---|---|
| Arithmetic | + - * / ^ (^ is power) |
| Compare | < > = (equality is a single =) |
| Sign | unary + and - |
There is no
%, no**, no==/!=/<=/>=, no ternarya ? b : c, and no&&/||/!. The validator rejects them and tells you the Revit spelling:<=→not(a > b),!=→not(a = b),&&→and(a, b),||→or(a, b),!→not(a),**→^.
Formula functions
The complete set — any other name is refused as an unknown function, and a call with the wrong number of arguments is refused too:
| Function | Meaning |
|---|---|
abs(x) | absolute value |
sqrt(x) | square root |
exp(x) | e raised to x |
log(x) | base-10 logarithm |
sin(x), cos(x), tan(x) | sine, cosine, tangent of an angle in radians |
asin(x), acos(x), atan(x) | inverse sine, cosine, tangent; the result is an angle in radians |
round(x) | nearest whole number; a half rounds up toward +∞ (round(2.5) = 3, round(-2.5) = −2) |
roundup(x) | smallest whole number ≥ x (ceiling) |
rounddown(x) | largest whole number ≤ x (floor) |
pi() | π ≈ 3.14159 — takes no argument |
if(test, whenTrue, whenFalse) | whenTrue when test holds, else whenFalse — exactly three arguments |
and(a, b, …) | Yes when every argument is Yes — two or more arguments |
or(a, b, …) | Yes when any argument is Yes — two or more arguments |
not(a) | the opposite of a |
There are no objects or namespaces — Math.PI is rejected as "unsupported member access"; write pi().
Width / 2 // halve a length
Height * 0.5 // scale
if(hasGlass, GlassThickness, 0) // optional part
Radius ^ 2 * pi() // area of a circle
sin(Angle) * Reach // trig — Angle must be an angle parameter
if(Width < 600, 1, 2) // a choice based on a size
and(Width > 600, Height > 600, IsBig) // and/or take more than two conditions — Yes/No only
"Standard" // a text parameter's formula is a quoted stringA text, URL, multi-line or material parameter takes a formula too, but its value is a string: quote it ("Standard"). Its per-type value, by contrast, is a plain literal — no quotes, never parsed ("PanelMaterial": "Wood - Walnut").
Formulas carry units
Revit refuses a formula whose result is a different kind of quantity than the parameter it feeds ("inconsistent units"), so Molding refuses it too, before generation rather than during it:
| Formula | On a… | |
|---|---|---|
Width * Height | length | rejected — that is an area |
Width * Height | area | fine |
sqrt(Width * Height) | length | fine — the root of an area is a length |
Width | number | rejected — a length is not a plain number |
Width + 100 | length | fine — a bare number takes the unit around it |
Width + Angle | anything | rejected — not a quantity at all |
asin(Ratio) | angle | fine — the arc functions return an angle |
sin(Count) | anything | rejected — sin/cos/tan need an angle |
round(Width) | anything | rejected — round/roundup/rounddown take a plain number |
100 / Width | number | fine — the literal takes mm, so the ratio is unit-free |
Height / Width | slope | fine — a slope is a ratio |
if(c, Width, 100 / Zero) | length | fine — only the whenTrue branch sets the unit |
Width > 500 | Yes/No | fine — a comparison answers yes or no |
Width > 500 | number | rejected — Yes/No is its own kind, not 1 and 0 |
and(IsWide, IsTall) | number | rejected — and / or / not answer Yes/No too |
A comparison (<, >, =) and and / or / not all produce a Yes/No result, and Revit lets that drive a Yes/No parameter and nothing else — it is not a number you can add to or multiply. Put the test inside if(...) when you need a number: if(Width > 500, 2, 1) on a number parameter is fine.
Powers follow the same algebra: Width ^ 2 is an area, Width ^ 3 a volume, and a dimensioned value can only be raised to a literal whole power.
Parameter types
| Type | Unit / meaning |
|---|---|
| length | millimetres |
| number | dimensionless real |
| integer | whole number (e.g. a count) |
| angle | radians |
| boolean | yes / no (a type value is true/false; a formula such as Width > 500 is allowed) |
| text | a string label |
| multilineText | multi-line string |
| material | a Revit material name |
| url | a URL string |
| area | mm² |
| volume | mm³ |
| force | N |
| mass | kg |
| slope | rise/run |
| speed | m/s |
| currency | currency value |
The fields of a parameter
The record is flat — one field per thing Revit's FamilyParameter knows about:
| Field | Means |
|---|---|
key | the parameter's name in Revit; what coordinates, formulas and properties reference |
type | its data type — length, angle, boolean, material… (see the table above) |
group | which section of Revit's Properties palette it appears under — one of dimensions, constraints, construction, graphics, materials, identity (Identity Data), text, data, general, structural, electrical, mechanical, plumbing, analysis (Analytical Properties). Absent → the runner picks one from the type: Dimensions for length / number / angle / area / volume, Construction for Yes/No, Identity Data for text / url / multi-line text, Materials for material, General otherwise. |
instance | true makes it editable on each placed copy in the model (e.g. a door's Width). Default false: a type parameter, set per family type and shared by every instance of that type. |
description | tooltip text in the Properties palette |
shared | { "guid": "…" } makes it a Revit shared parameter, so it can appear in multi-category schedules, drive tags and be reused across families. The GUID is its identity, so it is stored in the file and stays the same every time the family is regenerated. Most parameters do not need this. |
formula | a Revit formula that computes the value (see above). A parameter with one takes no per-type value. |
label | display name in the editor only; never reaches Revit. Absent → the key is shown. |
slider | { "min": …, "max": …, "step": … } — the editor's slider domain. Editor-only, never sent to Revit. |
{ "key": "Width", "label": "Door Width", "type": "length",
"group": "dimensions", "instance": true,
"slider": { "min": "600", "max": "3000", "step": "1" } }There is no args and no properties on a parameter, and no default value — the value for each family type lives in types[].values.
Editing parameters in the app
The Parameters tab header carries a family type dropdown (tooltip Active family type) next to the + button. It says which type's values the rows below are editing — a value belongs to a type, so the list would be ambiguous without it. The same switch is the radio button on each card of the Types tab, which also tints the active card.
Each parameter row is: its key (editable in place — renaming it updates every field that points at it), then the value in the active type, then ⚙ and ×. For a formula parameter the value cell shows the formula instead, greyed and read-only: Revit computes it, so no type holds a value to edit.
The ⚙ (Parameter settings) popover holds everything else about the parameter:
- Type and Group — two dropdowns.
- Instance and Shared checkboxes. Ticking Shared mints a GUID once and shows it in a read-only Shared GUID field — that GUID is the parameter's identity in Revit, so it is stored and never regenerated.
- Label — display name in the editor (defaults to the key if left blank). The
keyis what Revit names the parameter;labelis editor chrome only. - Description — the tooltip Revit shows in the Properties palette.
- Formula — a Revit formula. Filling it in makes the parameter computed; clearing it hands the parameter back to the per-type values.
- Range (min / max / step) — three inputs, shown only for numeric parameter types. min / max clamp the value in the editor's slider; step is the amount the increment arrow adds or subtracts. They are editor-only and never sent to Revit.
There is no Default value field: a parameter has no default, only a value per family type.
Gotchas
- Lengths are millimetres; angles are radians. To use degrees, make a parameter with a formula like
Angle * pi() / 180and point the field at it — aVfield takes the raw radian number. - A
Pfield left on(select parameter)has no value — pick one, or switch it toV. - To mirror, use the
−button on thePfield, not a formula likeHalfWidth * -1. - Parameter keys must be unique within a family; renaming a key updates every field that points at it.
- The Revit function names —
abs,sqrt,exp,log,sin,cos,tan,asin,acos,atan,round,roundup,rounddown,pi,if,and,or,not— are reserved and cannot be used as a key in any lane: not as a parameter key, a node key, a material key or a subcategory key. So are__proto__,constructor, andprototype. All four lanes share one key space, so a reserved name would be just as unresolvable in amaterialorsubcategoryfield as in a formula.
Next: see every element you can add in the Node reference.