Skip to content

Schema Reference

This is the complete field reference for goal set JSON files. For how these fields affect board generation, see Board Generation. For how to use the editors to build goal sets, see The Editors.

FieldTypeDescription
schema_version3Schema version. Must be 3 (current).
schema_modestringValidation mode: strict, capped, dedicated, or relaxed. See Schema Modes.
capped_schema_settingsobjectCapped mode only. Contains max_size (preset size ID, e.g. "square5").
dedicated_schema_settingsobjectDedicated mode only. Contains game_mode (e.g. "bingo") and game_size (e.g. "square5").
game_namestringName of the game. Max 50 characters.
set_namestringName of the objective set. Max 30 characters.
tag_namesstring[]List of valid exclusion tags. Max 150 tags, each max 20 characters, snake_case.
objectivesarrayArray of objective objects (see below).
limitsobjectCategory limit maps (see below).

FieldTypeConstraintsDescription
goalstringMax 60 chars. One {{X}} placeholder allowed.The task text shown on the board.
rangenumber[]Max 12 values, positive integers, ascending order.Target amounts for {{X}}. Required if goal uses {{X}}, and vice versa. See Using Ranges.
board_categoriesstring[]Max 4. Must exist in limits.board.Board-wide category labels for this objective.
line_categoriesstring[]Max 4. Must exist in limits.line.Per-line category labels for this objective.
iconsstring[]Max 12. Filenames must be .webp.Icon images for this objective. Cannot be used with emoji.
progressionstring[]1-4 values from e, m, l, n. Unique.Which progression zones this objective can appear in (Early, Mid, Late, Endgame).
FieldTypeDefaultConstraintsDescription
individual_limitinteger11-99. Must be ≤ number of range values.How many times this objective can appear on a single board.
weightinginteger1001-100Probability of being included in the generation pool.
tooltipstringMax 120 chars. Supports {{X}}.Help text shown on hover.
tagstringMax 20 chars, snake_case. Must exist in tag_names.Exclusion tag. Only one objective per tag can appear on a board.
forced_positionsinteger[]1-100, ascending, unique. Dedicated/Relaxed only.Board positions where this objective must be placed.
progressive_rangesbooleanfalseIf true, lower amounts appear in earlier board positions and higher amounts in later positions, instead of random selection.
overlay_iconbooleanfalseDisplay the goal text overlaid on the icon.
text_colorstring7-char hex, e.g. #ffffff.Text colour override for overlay mode.
emojistringMax 2 emoji, no whitespace.Displayed instead of icons. Cannot be used with icons.
shinybooleanfalsePermanently marks this objective as shiny.
disabledbooleanfalseExcludes this objective from generation without deleting it.

Category limits control how many objectives of a given type can appear on the board or in any single line. They’re defined as percentage values and converted to absolute counts during generation.

FieldTypeConstraintsDescription
limits.boardobjectMax 100 categories. Keys: snake_case, max 30 chars. Values: integer 0-9999.Board-wide category limits. 0 means “at most 1”, not zero.
limits.lineobjectMax 50 categories. Keys: snake_case, max 30 chars. Values: integer 0-9999.Per-line category limits. 0 means “at most 1 per line”.

Category keys used in objective board_categories must exist in limits.board, and keys used in line_categories must exist in limits.line.


Ranges represent a target amount to achieve. They’re for objectives where the goal is the same but the quantity scales the difficulty. The selected value is displayed on the board as x10, x100, etc.

Good uses of ranges:

  • “Collect {{X}} gold” with range [100, 500, 1000]
  • “Defeat {{X}} boss[[es]]” with range [1, 2, 3]
  • “Score {{X}} point[[s]]” with range [500, 1000, 5000]
  • “Reach level {{X}}” with range [10, 25, 50]

The common thread: the number is something you’re working toward, and a bigger number is harder. This is also why progressive_ranges works the way it does (lower values early, higher values endgame).


These rules are enforced by validation:

  • If goal contains {{X}}, range must have at least one value (and vice versa)
  • Only one {{X}} placeholder is allowed per goal
  • individual_limit must be ≤ the number of range values (each copy needs a distinct range)
  • emoji and icons are mutually exclusive
  • forced_positions is only available in dedicated and relaxed schema modes
  • All board_categories keys must exist in limits.board
  • All line_categories keys must exist in limits.line
  • All tag values must exist in tag_names
Wiki last updated for app version 0.27.X