Internal Tooling

Puzzle editor foundation

This is a local-only admin studio. Drafts and published puzzle edits are persisted to local JSON files, with no auth or database involved.

Authoring Studio

Build puzzles without hand-editing `data/puzzles.ts`

Create a board, validate it, then ask the solver for lines.

Import JSON

Paste board or puzzle state

Accepts a full puzzle export, or a state object with `player` and `opponent`. Card entries can use `cardCode`, `code`, or a resolved `card.code`.

Player State

You

Leader

OP01-001

Leader card

Hand

0 cards

Add hand card

No cards in this zone.

Life

0 cards

Add life card

No cards in this zone.

Board

0 cards

Add board card

No cards in this zone.

Opponent State

Opponent

Leader

OP08-001

Leader card

Hand

0 cards

Add hand card

No cards in this zone.

Life

0 cards

Add life card

No cards in this zone.

Board

0 cards

Add board card

No cards in this zone.

Preview

Live board scene

This uses the current draft state, so leader swaps, hand edits, board edits, and DON changes update here immediately.

Preview is waiting on card metadata for one or more selected card codes.

Scripted Actions

Custom move builder

No scripted actions yet. Use the solver for generic lines, and add scripted actions only when the generic engine cannot express the move.

Solution

Canonical line

No canonical solution yet. Promote a guaranteed line or build the solution manually.

Validation

Draft checks

Run validation to check ids, card codes, DON math, action references, and solution wiring.

Solver

Guaranteed wins

Run the fast search for quick candidate lines, or the exact proof search when you need a definitive yes-or-no answer.

Export

Live payload preview

Save drafts locally. Copy JSON or TypeScript when you want to publish or review the exact payload.

JSON

{
  "id": "new-puzzle",
  "title": "New Puzzle",
  "summary": "Describe the tactical spot this puzzle teaches.",
  "difficulty": "medium",
  "tags": [
    "draft"
  ],
  "failureHint": "Describe the common sequencing failure you want players to avoid.",
  "initialLog": [
    "Describe the board and the pressure point."
  ],
  "player": {
    "label": "You",
    "donTotal": 10,
    "donActive": 10,
    "trashCount": 0,
    "leader": {
      "instanceId": "p-leader",
      "cardCode": "OP01-001",
      "life": 1,
      "attachedDon": 0
    },
    "hand": [],
    "lifeCards": [],
    "board": [],
    "notes": []
  },
  "opponent": {
    "label": "Opponent",
    "donTotal": 10,
    "donActive": 0,
    "trashCount": 0,
    "leader": {
      "instanceId": "o-leader",
      "cardCode": "OP08-001",
      "life": 1,
      "attachedDon": 0
    },
    "hand": [],
    "lifeCards": [],
    "board": [],
    "notes": []
  },
  "actions": [],
  "solution": []
}

TypeScript

import type { Puzzle } from "@/types/domain";

export const draftPuzzle: Puzzle = {
  "id": "new-puzzle",
  "title": "New Puzzle",
  "summary": "Describe the tactical spot this puzzle teaches.",
  "difficulty": "medium",
  "tags": [
    "draft"
  ],
  "failureHint": "Describe the common sequencing failure you want players to avoid.",
  "initialLog": [
    "Describe the board and the pressure point."
  ],
  "player": {
    "label": "You",
    "donTotal": 10,
    "donActive": 10,
    "trashCount": 0,
    "leader": {
      "instanceId": "p-leader",
      "cardCode": "OP01-001",
      "life": 1,
      "attachedDon": 0
    },
    "hand": [],
    "lifeCards": [],
    "board": [],
    "notes": []
  },
  "opponent": {
    "label": "Opponent",
    "donTotal": 10,
    "donActive": 0,
    "trashCount": 0,
    "leader": {
      "instanceId": "o-leader",
      "cardCode": "OP08-001",
      "life": 1,
      "attachedDon": 0
    },
    "hand": [],
    "lifeCards": [],
    "board": [],
    "notes": []
  },
  "actions": [],
  "solution": []
};