Atlas VTT

Statblock files

How Atlas statblocks are stored, the YAML of a statblock note, the JSON of a template, and how to write both by hand.

You never need to touch these files, since the card and the template editor write them for you. They are plain text in your vault, though, so you can write statblocks by hand, make them with a script, or keep them in git.

An Atlas statblock is two things:

  • A note, a normal Markdown file. Its YAML frontmatter holds the values: this creature's hit points and attacks.
  • A template, a JSON file. It holds the shape: which values exist, what kind each one is and where it stands on the card.

Many notes point at one template. The values never go into the template, and the layout never goes into the note, so you can change a template without touching your notes.

The note

This is a complete statblock. Put it in any note and it shows its card.

---
statblock: true
atlas-template: bog-creature-a1b2c3
name: Bog Lurker
level: 3
type: Swamp beast
hp: 27
guard: 13
speed: 20
mood: Hungry
attacks:
  - name: Bite
    desc: +5 to hit, 2d6 + 3 damage.
  - name: Drag under
    desc: The target must save or sink.
---
It waits under the reeds by the old causeway.
The same note in Source mode, with the card its properties make.

Two properties make it a statblock:

PropertyWhat it does
statblock: trueMarks the note as a statblock. Fantasy Statblocks, Dataview and Bases read this property too.
atlas-templateThe id of the template that draws it. Without it, Atlas reads the note as a Fantasy Statblocks statblock.

Every other property is a value. All of them stand at the top level of the frontmatter, so Obsidian's Properties, Dataview and Bases can read them. Everything under the frontmatter is your own text, and Atlas never changes it.

A few things Atlas does when it writes a note:

  • A new note holds only statblock, atlas-template, name and, for a token, image. Other values appear as you fill them in.
  • Clearing a value deletes its property.
  • Values it works out, like a modifier, are never stored.
  • It changes only the lines of the values you edit. Your comments and the order of other properties stay.
  • A note whose YAML has an error is never written. The card tells you the line.
  • Changing name never renames the file.

A value that does not fit its kind stays as you wrote it, with a small chip like "Not a number". Atlas never converts it.

A note can show its card inside its own text with an empty atlas-statblock code block.

What each kind of value looks like

Kindtype in the templateIn the note
Texttextspeed: 30 ft.
Paragraphsmarkdowndescription: "It hunts at dusk."
Numbernumberhp: 27
Ratingratingcr: 1/4 or cr: 3
Dicedicehit_dice: 7d10 + 14
One of a listchoicesize: Large, or languages: Common, Elvish with several
Wordslisttraits: [Beast, Swamp]
Labels and valuespairssaves: { dex: 5, wis: 2 }
Names and textentriesA list of - name: Bite with desc: …
TablescoresOne row: stats: [14, 12, 13]. Several: - [Sword, 1, 1d8] for each row.
Groups with itemsspellsA list of texts, or of - At will: light, mage hand
CounterscountersA list of - { name: Ki, max: 3, used: 1 }
Pictureimageimage: art/bog-lurker.webp, a path in the vault

A counter row can also have regain, a dice formula for the uses that come back, and reset, the recovery action that gives them back.

A table with columns of its own is written as { columns: [Item, Qty], rows: [[Rope, 1]] }.

Keys you cannot use

A property name starts with a letter and holds only letters, digits, _ and -. Keep hyphens out of names you use in formulas. Obsidian, Fantasy Statblocks and Atlas use these for themselves, so a template field cannot:

statblock, atlas-template, atlas-type, layout, tags, aliases, cssclasses, cssclass, token, token-image, statblock-link, path, extends, bestiary, note, columns, mtime, monster, creature, player, position.

name and image are fine: they are the header's name and token art. If Atlas refuses another name, Edit as JSON says why.

References with @

An @ in a value reads a number of the same statblock. The note keeps what you wrote, and the card shows the number. 2d6 + @level on a level 3 creature shows and rolls 2d6 + 3.

You writeIt reads
@levelA field by its key, or a key it had before you renamed it
@stats.0The first item of a list
@saves.dexAn entry of labels and values
@strA table's column by its name, in any table
@str.modA worked-out row under that column
@hpThe hit points, whatever the template calls that field

@con-1 is Con minus 1, and @leveld6 is the level before a d6. A reference that names no number stays as you wrote it, gets a chip on the card and does not roll.

The template file

A template is a JSON file ending in .atlastemplate. Atlas makes them in atlas-vtt/statblock-templates, and finds them anywhere in the vault. The file's name is the template's name, and a note beside it with the same name holds the text new statblocks start with.

This is the template of the Bog Lurker above:

{
  "format": "atlas-statblock-template",
  "version": 1,
  "id": "bog-creature-a1b2c3",
  "description": "A small creature card for a homebrew game.",
  "diceSetId": "builtin:power-roll",
  "fields": [
    { "key": "name", "label": "Name", "type": "text" },
    { "key": "image", "label": "Token art", "type": "image" },
    { "key": "level", "label": "Level", "type": "rating", "meaning": "rating" },
    { "key": "type", "label": "Type", "type": "text", "meaning": "creature-type" },
    { "key": "hp", "label": "Hit Points", "type": "number", "meaning": "hit-points" },
    { "key": "description", "label": "Description", "type": "markdown", "meaning": "description" },
    { "key": "guard", "label": "Guard", "type": "number", "meaning": "armor" },
    { "key": "speed", "label": "Speed", "type": "number", "unit": "ft." },
    { "key": "mood", "label": "Mood", "type": "choice", "options": ["Calm", "Hungry", "Furious"] },
    { "key": "attacks", "label": "Attacks", "type": "entries", "prompt": "Add an attack" }
  ],
  "layout": {
    "maxColumns": 1,
    "blocks": [
      {
        "id": "bogrow01",
        "type": "row",
        "blocks": [
          { "id": "bogguard", "type": "stat", "field": "guard", "look": "stacked" },
          { "id": "bogspeed", "type": "stat", "field": "speed", "look": "stacked" },
          { "id": "bogmood0", "type": "stat", "field": "mood", "look": "stacked" }
        ]
      },
      { "id": "bogline1", "type": "divider" },
      { "id": "bogatk01", "type": "entries", "field": "attacks", "heading": "Attacks", "addLabel": "Add attack" }
    ]
  },
  "sample": { "name": "Bog Lurker" }
}

The six fields at the top are the header, which Atlas draws by itself. Everything under layout is what comes below it.

Edit it in Atlas

Open the template, click the ⋯ next to Save and choose Edit as JSON. The text stands beside the card, and the card follows once you stop typing. If Atlas cannot use what you typed, it says why under the text, in plain sentences, and the card keeps the last text that worked. Click Done, then Save.

Edit as JSON, with the text beside the card.

To write a template from nothing, the safest start is Blank in the template gallery, then Edit as JSON. You can also make the file with any text editor.

Top-level keys

KeyWhat it holds
formatAlways atlas-statblock-template
versionAlways 1. A file with a higher number opens read-only.
idA slug, a hyphen and six letters or digits: bog-creature-a1b2c3
descriptionOne line for the gallery
suitsRole names it suits, as a hint for pickers
diceSetIdThe dice set of its bonuses. Left out, it rolls the collection's dice.
fieldsEverything a statblock of this template holds, in Tab order
headerhidden: header parts kept off the card, from level, type, hp, description
layoutmaxColumns (1 to 3, default 2), columnWidth in em (default 22) and blocks
lookupsTables for patterns, like { "xp": { "1": "200" } }
sampleValues the editor previews with. They never reach a statblock.
recoveryThe recovery actions. Set these in the editor.

The ids of built-in dice sets are builtin:d20, builtin:d20-roll-under, builtin:d100-roll-under, builtin:d10-exploding and builtin:power-roll. Your own sets are JSON files in atlas-vtt/dice-sets, each with its id inside.

Keys Atlas does not know stay in the file when it saves.

Fields

KeyForWhat it does
keyAllThe property name in the note. Never changes once notes use it.
labelAllThe name on the card
typeAllOne of the kinds above
meaningAllWhat Atlas uses the field for, under Meanings
formerKeysAllOld names, read while key is missing. Newest first.
promptAllThe text of an empty value, like "Add an attack"
unitnumber, numbered choiceWritten after the number, like ft.
optionschoiceThe values on offer
openchoicetrue takes other values too
severalchoicetrue picks several, written as one line
numberedchoicetrue gives each pick a number: darkvision 60 ft.
tracksnumber{ "counts": "down" } or "up", and max: the field that holds the maximum
entryentriesnameKey (default name), textKey (default desc) and extras: a list of { key, label, type, options, several }
slotsscoresThe column names
slotKeysscoresEach column's key, by default its name in lower case
headerscoresfalse draws no header row
rowsscoresThe rows every statblock starts with
alignscoresPer column: start, center, end
addRows, addColumnsscoresfalse keeps statblocks to the template's rows or columns
counterRowscountersStarting rows: { name, max, regain }

Meanings

A meaning tells Atlas what a field is for when its key is unusual. Your "Guard" works as armour once it has the meaning armor. Each meaning goes on one field. Set meanings in JSON, since the editor has no control for them.

hit-points, armor, rating, size, creature-type, senses, initiative, traits, description, display-name.

rating is the level, and display-name is the name the card shows where the statblock has one, while name stays what identifies it.

Blocks

Every block has an id of eight lowercase letters or digits, unique in the template, and a type.

typeEditor nameKeys
statValuefield, label, look (run-in, stacked), pattern, display (plain, signed), rollFrom, rollable, addsToRolls
tagsValue of wordsfield, label, look (comma, chips, bullets, numbered)
pairsValue of labels and valuesfield, label, display, rollable, addsToRolls
metricMetricheading, fields, rollable, addsToRolls
entriesAbilitiesfield, heading, introField, nameStyle (run-in, heading), addLabel
scoresTablefield, orientation (row, table), perLine, display, columns, rollable
countersCountersfield, label
trackNumber shown as boxes or a gaugefield, label, resource, look (boxes, gauge), counts (down, up)
textTextfield or text, heading
dividerDivider
rowParts side by sidealign (start, center, spread), blocks

The editor shows these too, but you change them in JSON:

typeWhat it isKeys
sectionA group under a headingheading, headingField, collapsible (open, closed), blocks
tabsSections shown one at a time. It holds sections only and cannot stand in a row.heading, blocks
lineSeveral values in one linefields, pattern, separator
headingA heading you typetext, level (section, minor)
spellsGroups with itemsfield, heading, look (lines, tabs)
imageA picturefield, shape (token, portrait)

Atlas keeps a script block from a Fantasy Statblocks import as it was and never runs it in its own card. Do not write one yourself.

A rollFrom names a dice field a value rolls when it shows no dice of its own. rollable and addsToRolls are true or left out, as Roll as a bonus and Add to next roll in the editor.

A table's columns are its worked-out rows, each { label, field, formula, display }. A formula works on the column's score with the word value: floor((value - 10) / 2) is a 5E modifier. They show only while the table holds one row.

Keys every block can have:

KeyWhat it does
showWhenShows the block only if a field fits: { "field": "mood", "is": "equal", "value": "Furious" }. is can be present, absent, equal, not-equal, above or below.
whenEmptyWith nothing to show: hide (the default), fallback shows fallback, fold hides it on a card and folds it into a button under the card where you fill it in
fallbackA pattern for whenEmpty, so a value can come from other fields
sizeIn a row: fit or fill
classNameA word for themes and CSS snippets

Patterns

A pattern writes a block's values as text, without code.

PartExampleResult
A field{speed}20
Several fields{immunities, conditions|join:; }The ones with values, joined by "; "
A formula{=level * 100} XP300 XP
An optional part{size}[ ({subtype})]Leaves out the brackets' content while subtype is empty
An item of a list{stats.1}The second item

A filter follows |:

FilterWhat it does
signedNumbers with their sign: +3, -1
upper, lowerLetter case
countHow many items there are
avgThe average of dice, rounded down: 7d10 + 14 gives 52
lookup:xpThe row of the template's xp table: {cr|lookup:xp}
join:; Joins items with the text after the colon

A backslash writes { } [ ] \ , | as they are.

Formulas use + - * /, parentheses, field keys, and floor, ceil, round, abs, min and max. Text that holds a number counts as a number. A formula with an empty field shows nothing.

This is how the 5E templates show experience from the challenge rating, with a lookups table called xp:

{ "id": "b5cr0000", "type": "stat", "field": "cr", "label": "XP", "look": "run-in", "pattern": "{cr|lookup:xp}" }

Limits

Atlas reads a statblock within limits, far beyond what a real one holds: lists and maps six levels deep, 200 items per list, 10,000 characters per text and 5,000 values per statblock. What lies past a limit is left out of the card and stays in the note.