Skip to content

Global Metadata ​

The global metadata of an ATLAS configuration outlines the universal constants of your game. This acts as the ultimate lifecycle controller for the backend game engine and provides metadata.

Unique Identifiers (IDs) ​

When naming elements in your configuration (using id or name), the identifier must be globally unique across all types. For example, you cannot declare an entity named Setup and a zone named Setup, nor an action named MainBoard. Because ATLAS engine variables resolve explicitly through standard queries (e.g. @ActionName or @EntityName), colliding names will result in immediate schema validation rejection.

Global Block ​

The global block is strictly reserved for metadata like the game's title, author, and version.

yaml
global:
  title: "CyberHack 2088"
  author: "Alice Designer"
  version: "1.0.0"
json
{
  "global": {
    "title": "CyberHack 2088",
    "author": "Alice Designer",
    "version": "1.0.0"
  }
}

Players ​

Players are defined in their own distinct category. You can dictate a generic exact number of players or a supported range if they all share identical mechanics, or specify explicit asymmetric roles.

yaml
# For a generic 4-player game
players:
  count: 4

# Or a supported range of players
players:
  count: "2-6"

# Or for an asymmetric game with distinct roles
players:
  roles:
    - Corp
    - Runner
json
{
  "players": {
    "count": 4
  }
}

// Or a supported range of players
{
  "players": {
    "count": "2-6"
  }
}

// Or for an asymmetric game with distinct roles
{
  "players": {
    "roles": ["Corp", "Runner"]
  }
}

Player Context Selectors ​

ATLAS provides contextual player selectors that resolve dynamically during rule evaluation:

  • @player.current: The player whose action or turn context is currently being evaluated.
  • @player.opponent: The opposing player relative to @player.current.

Resolution behavior:

  • In turn-driven flow (for example, Alternating or Sequential), @player.current is the active priority holder.
  • In action evaluation, @player.current is the player who initiated the action being validated/resolved.
  • In two-player games, @player.opponent resolves to the other player.
yaml
global_restrictions:
  - name: KingSafety
    condition: @player.current.entities(tag: 'King').is_targeted == false

win_conditions:
  - name: Checkmate
    condition: @player.current.entities(tag: 'King').is_targeted == true and @player.current.valid_actions.count == 0
    winner: @player.opponent
json
{
  "global_restrictions": [
    {
      "name": "KingSafety",
      "condition": "@player.current.entities(tag: 'King').is_targeted == false"
    }
  ],
  "win_conditions": [
    {
      "name": "Checkmate",
      "condition": "@player.current.entities(tag: 'King').is_targeted == true and @player.current.valid_actions.count == 0",
      "winner": "@player.opponent"
    }
  ]
}

Global Restrictions ​

global_restrictions defines always-on legality constraints that every attempted action must satisfy. If any restriction evaluates to false, the engine rejects that action.

Use this for universal rule guards such as "you may not leave your king in check" or "you cannot exceed hand size at action resolution".

yaml
global_restrictions:
  - name: KingSafety
    description: A player cannot end their turn with their King targeted by an enemy.
    condition: @player.current.entities(tag: 'King').is_targeted == false
json
{
  "global_restrictions": [
    {
      "name": "KingSafety",
      "description": "A player cannot end their turn with their King targeted by an enemy.",
      "condition": "@player.current.entities(tag: 'King').is_targeted == false"
    }
  ]
}

Each restriction object supports:

  • name: Unique identifier for the restriction.
  • description: Human-readable explanation for debugging/UI surfaces.
  • condition: Boolean expression that must evaluate to true for an action to be accepted.

global_restrictions is distinct from win_conditions:

  • global_restrictions gate legality of a move.
  • win_conditions determine whether the game ends after a legal state transition.

The global_rules container

For games that only need a single turn order plus a handful of restrictions, you can consolidate both under one global_rules block instead of separate top-level keys — global_rules.turn_order is a shorthand for simple Alternating/Sequential games that don't need the full Stages/Turns/Phases timeline, and global_rules.move_constraints is exactly global_restrictions under a different name:

yaml
global_rules:
  turn_order: Alternating
  move_constraints:
    - id: PreventSelfCheck
      condition: $engine.state.is_in_check($player.active) == false

Win and Loss Conditions ​

Win and loss conditions are continuous, boolean logic evaluations. The game engine evaluates these states after every valid action. If any of these resolve to true, the game loop immediately halts.

When evaluating these conditions, you can reference the state of existing structures and entities using the ATLAS variable notation: @ideaName.subproperty.

The winner field can be a fixed role/value (for example Player1, White, or Draw) or a dynamic player selector (for example @player.opponent) when defining generic reusable rules. For non-partisan outcomes (stalemate, a drawn deck-out, ...), use result: Draw instead of winner — no side is declared victorious, but the game loop still halts.

yaml
win_conditions:
  - name: AvatarDestroyed
    condition: @entity.Avatar.count == 0
    winner: Player1
  - name: DeckOut
    condition: @zone.Player1Deck.count == 0
    winner: Player2
json
{
  "win_conditions": [
    {
      "name": "AvatarDestroyed",
      "condition": "@entity.Avatar.count == 0",
      "winner": "Player1"
    },
    {
      "name": "DeckOut",
      "condition": "@zone.Player1Deck.count == 0",
      "winner": "Player2"
    }
  ]
}

Halting the Engine

When a win_conditions block fires, the game terminates deterministic state progression, and the server communicates the final payload to the connected clients.