Skip to content

Zones ​

In ATLAS, you shouldn't think of Zones strictly as visual UI elements. They are abstract, structured data containers. They define where entities exist and who has permission to view them.

Topologies ​

ATLAS supports several fundamental data structures to hold entities. Topologies are divided into Physical (Boards) and Abstract (Collections).

Physical Topologies ​

When building systems to programmatically define rulesets, physical layouts must be abstracted into mathematical models.

  1. Grid (Square Grid): The traditional layout (e.g., Chess). Handled as a 2D array (#X, Y$). Moving diagonally can create a geometry problem (faster movement).
  2. HexGrid (Hexagon Grid): Solves the diagonal movement problem. Every hex shares flat edges with exactly 6 neighbors, creating equidistant adjacency. Requires offset or cubic coordinate (#X, Y, Z$) systems.
  3. Network (Point-to-Point): Defines specific locations (nodes) and paths (edges), mapping perfectly to graph theory (e.g., Ticket to Ride). Eliminates "dead space."
  4. Region (Area Movement): Map is divided into irregular polygons (e.g., Risk). Simulates realistic maps while keeping movement adjacency simple.
  5. Track (Linear Path): A 1-dimensional array wrapped into a shape (e.g., Monopoly). Movement is usually unidirectional or bidirectional along a strict line.

Abstract Topologies ​

  1. Set: Unordered data arrays. Items stored here have no sequential index or distance relation (e.g., a player's Hand or a generic token pool).
  2. Stack: Ordered collections (FILO / FIFO). Used for draw-decks or discard piles where the order of entities heavily dictates state accessibility.

Visibility and Capacity ​

Zones limit visibility—preventing the underlying engine from transmitting hidden data (preventing client-side cheating).

  • Public: The contents are synchronized to all connected players.
  • Hidden: The contents are hidden from all non-privileged players or roles (e.g., face-down cards).
  • Private: The zone's contents are only synchronized to the owner role.

You can also restrict total capacity.

Subzones and Board Layouts ​

To handle complex spatial boundaries (like game boards), zones can define subzones and a layout. Subzones allow you to assign specific organizational patterns and designate explicit entrance_points for entities moving between spaces.

Layouts can be described concisely using dimension strings (like 8x8 or 3x3). For irregular or complex boards, you can use grid string arrays. In these arrays, a space () represents a void, X represents a standard playable space, and other alphabetical characters can be mapped to specific subzones using a mapping dictionary.

yaml
zones:
  - id: MainBoard
    topology: Grid
    layout: 8x8
    subzones:
      - id: Player1_Territory
        bounds: [0, 0, 8, 4]  # x, y, width, height
      - id: Player2_Territory
        bounds: [0, 4, 8, 4]
  - id: CustomBoard
    topology: Grid
    layout:
      - "  XXX  "
      - "  XAX  "
      - "XXBXBXX"
      - "XXXOXXX"
      - "XXBXBXX"
      - "  XAX  "
      - "  XXX  "
    mapping:
      X: Default
      A: Spawner
      B: ChokePoint
      O: ScoringArea
    subzones:
      - id: Spawner
      - id: ChokePoint
      - id: ScoringArea
        entrance_points:
          - [3, 3]
json
{
  "zones": [
    {
      "id": "MainBoard",
      "topology": "Grid",
      "layout": "8x8",
      "subzones": [
        {
          "id": "Player1_Territory",
          "bounds": [0, 0, 8, 4]
        },
        {
          "id": "Player2_Territory",
          "bounds": [0, 4, 8, 4]
        }
      ]
    },
    {
      "id": "CustomBoard",
      "topology": "Grid",
      "layout": [
        "  XXX  ",
        "  XAX  ",
        "XXBXBXX",
        "XXXOXXX",
        "XXBXBXX",
        "  XAX  ",
        "  XXX  "
      ],
      "mapping": {
        "X": "Default",
        "A": "Spawner",
        "B": "ChokePoint",
        "O": "ScoringArea"
      },
      "subzones": [
        { "id": "Spawner" },
        { "id": "ChokePoint" },
        {
          "id": "ScoringArea",
          "entrance_points": [[3, 3]]
        }
      ]
    }
  ]
}

The Setup Block ​

When an ATLAS game initializes, it populates zones using a setup object.

For abstract topologies like Stack or Set, you can simply pass a count:

yaml
zones:
  - id: Player1_Hand
    topology: Set
    visibility: Private
    capacity: 7
  - id: Player1_Deck
    topology: Stack
    visibility: Hidden
    capacity: -1
    setup:
      shuffle_on_init: true
      entities:
        - id: BasicInfantry
          count: 10
        - id: FireballSpell
          count: 2
json
{
  "zones": [
    {
      "id": "Player1_Hand",
      "topology": "Set",
      "visibility": "Private",
      "capacity": 7
    },
    {
      "id": "Player1_Deck",
      "topology": "Stack",
      "visibility": "Hidden",
      "capacity": -1,
      "setup": {
        "shuffle_on_init": true,
        "entities": [
          { "id": "BasicInfantry", "count": 10 },
          { "id": "FireballSpell", "count": 2 }
        ]
      }
    }
  ]
}

For physical topologies like Grid or HexGrid, you should define locations (an array of coordinate tuples) instead of a simple count:

Coordinates Are 1-Based

In ATLAS, grid coordinates are explicitly 1-based (i.e. starting from [1, 1]) rather than 0-based to better match standard tabletop conventions.

yaml
zones:
  - id: MainBoard
    topology: Grid
    layout: 8x8
    setup:
      entities:
        - id: WhiteKing
          locations:
            - [5, 1]
        - id: BlackKing
          locations:
            - [5, 8]
json
{
  "zones": [
    {
      "id": "MainBoard",
      "topology": "Grid",
      "layout": "8x8",
      "setup": {
        "entities": [
          { "id": "WhiteKing", "locations": [[5, 1]] },
          { "id": "BlackKing", "locations": [[5, 8]] }
        ]
      }
    }
  ]
}

Data vs Render

Never define CSS, positions, or 3D rotations in a Zone. Zones dictate data topology (Who can see this? Is it ordered? Is it full?). The Frontend renderer is responsible for drawing a Stack as a 3D deck of cards.

Single-Board Shorthand ​

Games with exactly one physical zone (Chess, Checkers, ...) don't need a whole zones array just to declare it — a single top-level board object is shorthand for one Grid/HexGrid zone:

yaml
board:
  topology: Grid
  layout: 8x8
  setup:
    fen: "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR"

board.setup.fen accepts a standard FEN piece-placement string as a compact alternative to the setup.entities[].locations form above. Each rank is read top-to-bottom the same way layout grid rows are. Every letter must match a pieces[].symbol declared beside that piece's canonical id (for example, id: Rook with symbol: R). Standard FEN letter case supplies the owner: uppercase places a White piece and lowercase places a Black piece, while both resolve through the same declared symbol. Reach for the full zones array (with per-zone setup) as soon as a game needs more than one physical or abstract zone, e.g. a graveyard, a hand, or a deck alongside the board.

Appendix: Zones Reference ​

Valid Topologies ​

When declaring your zone, the topology property must be set to one of the following:

Physical (Boards):

  • Grid: 2-Dimensional square matrix.
  • HexGrid: 6-axis adjacency geometry.
  • Network: Graph-theory style nodes and edges point-to-point.
  • Region: Irregular geometric areas.
  • Track: 1-Dimensional sequence path.

Abstract (Collections):

  • Set: Unordered data structure.
  • Stack: Ordered data structure typically treated by the engine as a FILO or FIFO array.

Valid Visibilities ​

When declaring a zone, you optionally constrain its data using the visibility enum:

  • Public: All connected clients receive data updates.
  • Private: Only the owning client receives the zone data.
  • Hidden: No clients receive the data (all queries are securely handled server-side).