Components
A set is a component with variants. set names it; variants lists each variant property and its values; template is the node every variant starts from.
{
"set": "Raga/Card",
"props": {
"Name": "राग भैरव",
"Hour": "MORNING",
"Last": "Last riyaz 2 days ago · 25 min"
},
"variants": {
"State": {
"Learning": {},
"New": {},
"Locked": {
"fill": "#F3EFF7",
"props": {"Last": "Opens after 21 days of Yaman"}
}
}
},
"template": {
"width": 300,
"padding": 18,
"gap": 8,
"fill": "#FFFFFF",
"cornerRadius": 20,
"column": [
{"eyebrow": "{Hour}", "color": "@mute"},
{"deva-xl": "{Name}", "font": "Tiro Devanagari Hindi 24/30"},
{
"row": [{"swara": "रे॒"}, {"swara": "ध॒"}],
"gap": 6,
"only": "Learning"
},
{"small": "{Last}", "color": "@mute", "only": ["Learning", "Locked"]},
{
"name": "Progress",
"only": "Learning",
"stack": [
{
"type": "rectangle",
"width": 264,
"height": 6,
"cornerRadius": 3,
"fill": "@ink/8%"
},
{
"type": "rectangle",
"width": 180,
"height": 6,
"cornerRadius": 3,
"fill": "@saffron",
"at": "left"
}
]
},
{
"row": [
{
"text": "Start learning",
"font": "Inter 14/20 700",
"color": "#FFFFFF"
}
],
"padding": [8, 14],
"cornerRadius": 16,
"fill": "@ink",
"only": "New"
}
]
},
"behavior": {
"axes": {
"history": ["fresh", "practised"],
"streak": {
"values": ["short", "long"],
"when": {"history": ["practised"]}
}
},
"start": "Loading",
"states": {
"Loading": {"LOADED": "route"},
"route": [
"history == 'fresh' -> New", "streak == 'long' -> Learning", "Locked"
],
"New": {"START": "Learning"},
"Learning": {"PAUSE": "Locked"},
"Locked": {"UNLOCK": "Learning"}
},
"plays": {"Begin a new raga": ["LOADED", "START"]},
"targets": {"START": "Start learning"}
}
}

Three variants of a card. {Name}, {Hour} and {Last} bind texts to the set's properties; only keeps a layer to the variants that use it; the Locked variant sets its own Last.
Variants
"variants": {"State": ["Learning", "New", "Locked"]}
"variants": {"State": {"Learning": {}, "Locked": {"fill": "#F3EFF7"}}}
The first value of each property is the default. A value's map changes that variant: keys for the root, $nodes for named layers, and props for its own property values.
A text that names a variant property shows each variant's own value: {"text": "{Tier} plan"} reads "Free plan" in Tier=Free and "Pro plan" in Tier=Pro. No property needs declaring for it.
The set is drawn with a dashed purple outline around its variants in the app and in previews; each variant is a component of its own inside it.
Properties
props declares the set's properties once, with their defaults. A text written "{Name}" follows Name; a layer with "visible": "{Show retry}" shows or hides with a boolean. Instances set them by name.
A variant that sets its own value ("props": {"Last": "Opens after 21 days of Yaman"}) keeps that text; the property's value applies in the other variants. When every value of a variant property sets its own, no instance can change it, and the build warns INPUT_IGNORED: write the text in each variant instead, or leave one variant to follow the property.
A part's argument can be a property: {"chip": "{Hour}"} inside a template binds the chip's text to Hour.
Layers in some variants: only
"only": "Learning", "only": ["Learning", "Locked"], or "only": {"State": ["Learning"]} when a set has several properties. Other variants leave the layer out instead of hiding it, so a set with many views stays small. A layer only some variants hold can make those variants larger; the set lays its variants out side by side, so that is fine.
Instances
Use a component by its name. Keys that name a variant property choose the variant; the rest set properties, or override a layer's text by name. name beside the component names the instance, which matters when a screen holds several: {"Plan": {"Tier": "Pro"}, "name": "Pro card"}.
{
"name": "Library",
"gap": 20,
"align": "start",
"row": [
{"Raga/Card": {"State": "Learning"}},
{
"Raga/Card": {
"State": "New",
"Name": "राग भीमपलासी",
"Hour": "AFTERNOON"
}
},
{
"Raga/Card": {
"State": "Locked",
"Name": "राग मालकौंस",
"Hour": "LATE NIGHT"
}
}
]
}

Three instances; each chooses its State and sets the raga's name and hour.
A bare value sets a component's only text property: {"Button": "Pay now"}.
Changing a set
Build it again with --replace: the new set takes the old one's place, its instances move to the variants with the same names, and they keep what they set. Or change it in place with [--sync](update.md).