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.

Field Type Description
schema_version 3 Schema version. Must be 3 (current).
schema_mode string Validation mode: strict, capped, dedicated, or relaxed. See Schema Modes.
capped_schema_settings object Capped mode only. Contains max_size (preset size ID, e.g. "square5").
dedicated_schema_settings object Dedicated mode only. Contains game_mode (e.g. "bingo") and game_size (e.g. "square5").
game_name string Name of the game. Max 50 characters.
set_name string Name of the objective set. Max 30 characters.
tag_names string[] List of valid exclusion tags. Max 150 tags, each max 20 characters, snake_case.
objectives array Array of objective objects (see below).
limits object Category limit maps (see below).

Field Type Constraints Description
goal string Max 60 chars. One {{X}} placeholder allowed. The task text shown on the board.
range number[] Max 12 values, positive integers, ascending order. Target amounts for {{X}}. Required if goal uses {{X}}, and vice versa. See Using Ranges.
board_categories string[] Max 4. Must exist in limits.board. Board-wide category labels for this objective.
line_categories string[] Max 4. Must exist in limits.line. Per-line category labels for this objective.
icons string[] Max 12. Filenames must be .webp. Icon images for this objective. Cannot be used with emoji.
progression string[] 1-4 values from e, m, l, n. Unique. Which progression zones this objective can appear in (Early, Mid, Late, Endgame).
Field Type Default Constraints Description
individual_limit integer 1 1-99. Must be ≤ number of range values. How many times this objective can appear on a single board.
weighting integer 100 1-100 Probability of being included in the generation pool.
tooltip string Max 120 chars. Supports {{X}}. Help text shown on hover.
tag string Max 20 chars, snake_case. Must exist in tag_names. Exclusion tag. Only one objective per tag can appear on a board.
forced_positions integer[] 1-100, ascending, unique. Dedicated/Relaxed only. Board positions where this objective can be placed. It will never appear outside these positions.
progressive_ranges boolean false If true, lower amounts appear in earlier board positions and higher amounts in later positions, instead of random selection.
overlay_icon boolean false Display the goal text overlaid on the icon.
text_color string 7-char hex, e.g. #ffffff. Text colour override for overlay mode.
emoji string Max 2 emoji, no whitespace. Displayed instead of icons. Cannot be used with icons.
shiny boolean false Permanently marks this objective as shiny.
disabled boolean false Excludes 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.

Field Type Constraints Description
limits.board object Max 100 categories. Keys: snake_case, max 30 chars. Values: integer 0-9999. Board-wide category limits. 0 means “at most 1”, not zero.
limits.line object Max 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