CollapseLogic/CollapseLogic_LevelSpec.md

9.2 KiB
Raw Blame History

Collapse Logic — Level Format Specification

Version: 1.0
Last Updated: March 2026
Studio: Vulcara Games


Overview

Levels are defined as JSON files bundled in the app. Each world has a directory of level files. The format is designed to be human-readable for hand-crafting levels and machine-parseable for the game engine.

File Structure

CollapseLogic/
├── Levels/
│   ├── world1/
│   │   ├── level_01.json
│   │   ├── level_02.json
│   │   └── ...
│   ├── world2/
│   │   └── ...
│   └── metadata.json

Level JSON Schema

{
  "id": "w1_01",
  "world": 1,
  "level": 1,
  "title": "First Steps",
  "grid": {
    "width": 5,
    "height": 5
  },
  "blocks": [
    { "x": 1, "y": 1, "color": "red" },
    { "x": 3, "y": 1, "color": "red" },
    { "x": 2, "y": 3, "color": "blue" },
    { "x": 4, "y": 3, "color": "blue" }
  ],
  "walls": [
    { "x": 2, "y": 2 }
  ],
  "special_tiles": [],
  "objective": {
    "type": "clear_all"
  },
  "par": 4,
  "hints": [
    "Try pushing the top-left red block down first."
  ]
}

Field Definitions

Top-Level Fields

Field Type Required Description
id string Yes Unique identifier. Convention: w{world}_{level:02d} (e.g., w1_01, w3_15)
world integer Yes World number (1-6)
level integer Yes Level number within the world (1-20)
title string No Display name for the level (optional flavor text)
grid object Yes Grid dimensions
blocks array Yes Array of block objects placed on the grid
walls array No Array of wall positions. Default: []
special_tiles array No Array of special tile objects. Default: []
objective object Yes Win condition for the level
par integer Yes Target move count for 3-star rating
hints array No Array of hint strings (revealed progressively). Default: []

Grid Object

{
  "width": 5,
  "height": 5
}
Field Type Constraints Description
width integer 310 Number of columns
height integer 310 Number of rows

Coordinate system: (0, 0) is the top-left cell. x increases rightward, y increases downward.

Block Object

{ "x": 2, "y": 3, "color": "red" }
Field Type Values Description
x integer 0 to width-1 Column position
y integer 0 to height-1 Row position
color string See Color Values Block color

Color Values

Primary colors (can merge):

Value Display Hex
"red" Ruby #E63946
"blue" Sapphire #457B9D
"yellow" Topaz #F4D35E

Secondary colors (result of merges, cannot merge further):

Value Created From Hex
"purple" red + blue #7B2D8B
"orange" red + yellow #E76F51
"green" blue + yellow #2A9D8F

Secondary-color blocks can appear in level definitions as pre-placed blocks, allowing level designers to create puzzles that start with merged colors already on the board.

Wall Object

{ "x": 2, "y": 2 }

Simple position. Walls are impassable — blocks stop when they would move into a wall cell.

Special Tile Object

{ "x": 3, "y": 4, "type": "mirror", "direction": "horizontal" }
Field Type Values Description
x integer 0 to width-1 Column position
y integer 0 to height-1 Row position
type string See below Tile type
Additional fields vary by type

Tile types and their extra fields:

mirror

Reverses block direction on contact.

Field Values Description
direction "horizontal", "vertical", "both" Which axis the mirror reflects
  • "horizontal" — reverses left↔right movement; vertical movement passes through
  • "vertical" — reverses up↔down movement; horizontal movement passes through
  • "both" — reverses any direction (block bounces back the way it came)

splitter

Breaks a merged (secondary) block into its two primary components. The two resulting blocks are placed on either side of the splitter along the axis of movement.

No extra fields.

If a primary-color block hits a splitter, it passes through (no effect).

void

Absorbs any block that enters. Single use — the void tile is consumed along with the block.

Field Values Description
charges integer (default: 1) Number of blocks it can absorb before being consumed

ice

Block slides through without stopping. The block continues moving until it hits a non-ice cell's wall/block/boundary.

No extra fields.

lock

A block that can only be destroyed by a matching key block.

Field Values Description
lock_color color string The color of key required to destroy this lock

key

When colliding with a matching lock, both are destroyed.

Field Values Description
key_color color string Must match a lock's lock_color to destroy it

Objective Object

{ "type": "clear_all" }
Type Extra Fields Description
"clear_all" None Remove all blocks from the board
"clear_color" "color": "red" Remove all blocks of a specific color
"reduce_to" "count": 1 Reduce total blocks to the specified count
"clear_targets" "targets": [{"x":2,"y":3}, ...] Clear specific cells (blocks must be destroyed at those positions)

Metadata File

Levels/metadata.json provides an index of all worlds and levels:

{
  "version": "1.0",
  "worlds": [
    {
      "id": 1,
      "name": "Primary",
      "description": "Learn the basics of pushing and destroying.",
      "new_mechanic": null,
      "levels": [
        {
          "id": "w1_01",
          "title": "First Steps",
          "file": "world1/level_01.json",
          "is_challenge": false
        },
        {
          "id": "w1_16",
          "title": "Ruby Gauntlet",
          "file": "world1/level_16.json",
          "is_challenge": true,
          "stars_required": 30
        }
      ]
    }
  ]
}

Challenge levels have is_challenge: true and require a cumulative star count (stars_required) to unlock.

Example Levels

Tutorial Level (World 1, Level 1)

Two red blocks on a 4x4 grid. Push one into the other.

{
  "id": "w1_01",
  "world": 1,
  "level": 1,
  "title": "First Steps",
  "grid": { "width": 4, "height": 4 },
  "blocks": [
    { "x": 0, "y": 1, "color": "red" },
    { "x": 3, "y": 1, "color": "red" }
  ],
  "walls": [],
  "special_tiles": [],
  "objective": { "type": "clear_all" },
  "par": 1,
  "hints": ["Push the left block to the right."]
}

Intermediate Level (World 1, Level 8)

Walls force an indirect path.

{
  "id": "w1_08",
  "world": 1,
  "level": 8,
  "title": "Detour",
  "grid": { "width": 5, "height": 5 },
  "blocks": [
    { "x": 0, "y": 0, "color": "red" },
    { "x": 4, "y": 0, "color": "red" },
    { "x": 1, "y": 4, "color": "blue" },
    { "x": 3, "y": 4, "color": "blue" }
  ],
  "walls": [
    { "x": 2, "y": 0 },
    { "x": 2, "y": 1 },
    { "x": 2, "y": 3 },
    { "x": 2, "y": 4 }
  ],
  "special_tiles": [],
  "objective": { "type": "clear_all" },
  "par": 6,
  "hints": [
    "The wall column splits the board in two.",
    "Row 2 is the only crossing point."
  ]
}

Merge Level (World 2, Level 5)

Create purple to clear it.

{
  "id": "w2_05",
  "world": 2,
  "level": 5,
  "title": "Color Theory",
  "grid": { "width": 5, "height": 5 },
  "blocks": [
    { "x": 0, "y": 2, "color": "red" },
    { "x": 4, "y": 2, "color": "blue" },
    { "x": 2, "y": 0, "color": "purple" }
  ],
  "walls": [],
  "special_tiles": [],
  "objective": { "type": "clear_all" },
  "par": 3,
  "hints": [
    "You need to make a purple block to match the one already on the board.",
    "Merge red and blue first, then align the two purples."
  ]
}

Validation Rules

A level file is valid if:

  1. id is unique across all levels
  2. grid.width and grid.height are between 3 and 10
  3. All block, wall, and special tile positions are within grid bounds
  4. No two objects occupy the same cell
  5. par is a positive integer
  6. objective.type is one of the defined types
  7. If objective.type is "clear_color", the specified color exists in blocks
  8. At least 2 blocks are present (a puzzle requires at minimum something to collide)
  9. Block colors are valid primary or secondary color strings

Extending the Format

New special tile types can be added by defining a new type string and its associated extra fields. The game engine should gracefully ignore unrecognized tile types (forward compatibility for older app versions loading newer level packs).

New objective types follow the same pattern. The objective object is intentionally flexible — additional fields can be added per type without breaking existing levels.