The sheet layer is declarative on purpose: you describe what a character has and what a roll means,
and the system draws the sheet and wires the buttons. This is the shortest useful path through it,
which is a single stat, a single skill, and a button that rolls 2d6+3.
What a sheet definition is
A sheet is data, not code. It names fields, groups them, and says which of them are rollable. Nothing in it runs, which is what lets the same definition render on a phone, in a side panel, and in a printed export without three implementations.
- Fields are typed, and the type decides the control a player sees.
- Groups are layout, and layout is the only thing in the file that is about looks.
- A roll is a name and an expression, and the expression is the only place dice appear.
The smallest thing that works
Start with one attribute. Give it a key, a label, and a default, then stop and load the sheet. A field you can see and edit is worth more than a full character you cannot render yet, because from here every mistake is one line old.
Keys are permanent, labels are not
A field key is what saved characters point at, so renaming one after people have made characters means a migration. Labels are display text and can change whenever you like. Spend the extra minute on the key.
Wiring the roll
A skill check needs two things: the expression and what it is allowed to read. Write the expression
as 2d6+3 first, with the modifier hardcoded, and confirm the button rolls and reports. Only then
replace the 3 with a reference to the attribute you defined. Doing it in that order means when it
breaks, you know whether the dice or the reference is at fault.
Where people get stuck
Almost always the same place: trying to express a rule the system does not have a concept for yet, and reaching for something imperative to force it. That is the moment to stop and check whether the rule belongs in the sheet at all, or whether it is an automation that should watch the roll and react to it. The sheet describes a character. It is not the place to encode what happens next.



