How the Character Sheet Thinks
The character schema has one design rule. Store decisions and derive everything else. A sheet stores the six base ability scores, level and experience, references to species, class, subclass, background, feats, and gear, and a few play-state fields. Everything else is computed.
The derivation chain
- Each final ability score is
min(20, base + feat increases)plus item increases and overrides. In this revision the background's increases arrive through its Origin feat and the ASI feats, sobasemeans the raw rolled score. A level 20 Barbarian's Primal Champion is applied automatically. - Modifiers, saves, and all 18 skills derive from there. Skills read two lists,
proficientSkillsandexpertSkills. Jack of All Trades fill in untrained skills on their own. - armorClass reads the equipped armor file's
acBase,addDexterity, anddexterityCap, then adds shield, magic, andmiscArmorBonus. Without armor it uses the best unarmored option you have, including class Unarmored Defense and the Draconic subclass. - Attack lines such as
mainHandAttackBonusandmainHandDamageDicekey off the weapon file's finesse and ranged flags and its magic bonus. - Spell slots come from
casterLevel, which counts full-caster levels plus half of each Paladin or Ranger level, rounded up per class. Warlock Pact Magic runs on its own track inpactMagic. - Features come from one computed list,
features. It readsfeaturesLevelNoff the class and subclass files for every level you have. A character levels up by changing one number.
Multiclassing
level is always the TOTAL character level. A multiclassed hero also sets secondClass, secondSubclass, and secondClassLevel, and the main class gets the rest. Proficiency Bonus and XP use the total. Hit points use the first class's full die at level 1 and averages after that. Saving throws come from the first class only. The spell pickers offer spells from both classes.
Resources and play state
Every limited pool lives in one stored map, resourceState, keyed by a stable slug. Spell slots use spell-slot-1 to spell-slot-9, then pact-slots, hit-dice, and each class or subclass pool (rage, wild-shape, focus-points, and so on). A missing key means the pool is full. The pool definitions live on the class and subclass files in their resources field, so a new pool is data, not a formula. The sheet shows them as tappable circles at the top. On/off states such as concentration, rage, and a held Bardic Inspiration die live in activeStates.
The creation flow
The character type also carries the guided creation flow. It walks a player from biography through class, subclass, fighting style, spells, background, and equipment to a finished level 5 hero. Its option screens hold references into the content folders, so copying this project's types into another project means remapping every option's referenceId. Edit the flow in the app or with care. It is data on the type and pushes with the type.
Class choices
Choices that used to live in notes now have their own fields on the Features tab. They are eldritchInvocations, metamagicOptions, weaponMasteries, draconicAncestry, and landType. Each offers only the SRD options, and each shows only for the classes, subclasses, or species that use it. The Resources card shows how many invocations, Metamagic options, and weapon masteries you may know at your level. The Mage Armor toggle sets unarmored AC to 13 plus your Dexterity modifier.
Aggregation by shared field names
The sheet never knows which feat or relic you took. It sums every instance of shared field names across the feats array, the three attunedItem slots, and every worn slot (head to feet) holding an item that needs no attunement. These are strengthIncrease to charismaIncrease, acBonus, initiativeBonus, speedBonus, hpBonus, hpBonusPerLevel, and saveBonusAll, plus initiativeProficiency for Alert, plus score-override fields for items like the Gauntlets of Ogre Power. Give any feat or magic item those fields and it wires itself into every derived number. @Missing file and @Missing file are the worked examples.
Platform limits that shaped this type
A type holds at most 200 top-level fields, and a single formula can be at most 5,000 characters. Long per-item families belong in one computed array, which is why skills, saves, spell slots, resources, and features are each one list. Reference-picker filters only work on top-level fields, which is why preparedSpellsLevel1 to preparedSpellsLevel9 and secondClass live at the top. Schema edits push with craft push --include-types after craft check. The server validates the new schema against every existing file and names each record a change would break.