Board game in progress · game kit

Game kit

Everything it takes to turn Paws in Peril into a video game: the rules, every character and card with its art, the numbers, a tested rules engine, and a concept to build from.

What the game is

Paws in Peril is a board game for 2 to 4 players that Christian Renfro is making. Each player is an animal on a board of hex tiles around a desert, with 10 HP, two lives and a hand of item cards. A turn is 5 action points: move, loot the tile you stand on, buy a card, raid a player next to you, or invade their home. Looting a home or a mansion means a dice fight with the monsters that live there; beat them and the building is yours, and the monster's card joins you with its one ability. Every home or mansion you own is a victory point, and the first to 4 wins (3 in a two-player Explorer game), or the last animal with lives left. Chests give item cards, forests give barricades, and 66 different item cards bend the rules on your turn, in a fight, or at any moment.

Rules

The V4 rulebook, a draft tuned over thousands of bot games. The engine below plays exactly this.

rulebook.md

Loading the rulebook…

Characters

The 44 monsters. Each one guards a home or a mansion; beat it and its card is yours, with its ability as a buff from your next turn. HP is the number on the card.

monsters.json

Items

66 item cards, 78 in the deck. Playing one is free. On your turn cards are played outside a fight while you have AP, In Combat cards during a fight you are in, Anytime cards at any moment.

items.json
Filter by when a card is played

Tiles

Flat-top hexes. The Beginner board is the desert with 18 tiles in two rings around it; on the Explorer board each player places their own tiles as the game goes.

tiles.json

Numbers

Decks

Monster HP

HPMonstersShare

Item timing

PlayedCardsCopies

Balance under V4

Smart bots, 3,000 seeded games per board, 2 to 4 players rotating (TUNING.md on the lab branch).

BoardRounds, averageEnds on VPLeader after round 3 winsFirst player winsRaids a gameStalls
Beginner11.486%62%39%1.32%
Explorer14.175%56%36%2.23%
  • Knockouts score nothing in V4, so the target dropped from 5 VP to 4; at 5, more than a third of Beginner games ended by elimination instead of points.
  • The early leader still wins too often with 2 players (79%); with 4 it is fair (44%). No edge for the leader's homes is the one catch-up rule that helped.
  • Reckless players stall on the Explorer board; a video game should end at round 20 with the most VP winning.
  • Six item cards have no rule yet (marked on their cards above); the engine plays them as no effect.

Downloads

Paths inside the zip match the site under /paws/: assets/art/<id>.webp is /paws/assets/art/<id>.webp. manifest.json lists every file with its size, pixel size and what it is.

FileWhat it isSize
paws-in-peril-assets.zipAll the art (161 pictures) with the data, the engine, the bots and the rulebook, in one folder
data/game.jsonThe V4 rule constants: AP per turn, HP, lives, VP targets, costs, dice, board
data/monsters.jsonThe 44 monsters: id, name, HP, ability, portrait and card paths
data/items.jsonThe 66 item cards: copies, timing, effect, notes, image path
data/tiles.jsonThe 5 tile types: count in print, what looting does, VP
engine.jsThe reference rules engine: every rule and card, plain JavaScript, no dependencies
bot.jsThe greedy bot and the fight odds it uses
smartbot.jsThe smart bot the balance numbers come from
rulebook.mdThe V4 rulebook (draft), Markdown
manifest.jsonEvery file above and every picture, with its size and what it is

The engine, in short

engine.js is a plain ES module that runs in any modern browser and in Node 18 or later. It is the tested implementation the playable game uses: state in, action in, new state out.

import { createGame, legalActions, apply, actor } from './engine.js';
const monsters = await (await fetch('/paws/kit/data/monsters.json')).json();
const items = await (await fetch('/paws/kit/data/items.json')).json();

let state = createGame({ monsters, items, players: 3, board: 'beginner', seed: 42 });
const moves = legalActions(state); // every action any player may take right now
state = apply(state, moves[0]);    // pure: returns a new state, throws on an illegal action
  • createGame(options): players 2 to 4 (or an array of { name, color }), board 'beginner' or 'explorer', mode 'ffa' or 'teams', seed. Rules default to V4.
  • legalActions(state): plain objects such as { type: 'move', player, q, r }, loot, buyItem, raid, invade, playItem, useAbility, the fight steps combatRoll, combatContinue, combatApply, and the choices discard, chooseDefender, takeCard, keepCard, placeTile. actor(state) is the player the game is waiting on.
  • apply(state, action): never mutates its input. state.lastEvents lists what just happened (each has a type and a readable msg): animate from those. state.over holds the winner.
  • State is plain JSON, so it saves, diffs and travels over a socket. Dice come from a seeded generator inside the state.
  • Bots: nextSmartStep(state, isBot) from smartbot.js returns the next { pid, action } for the seats isBot(pid) says are bots. Keep the three files in one folder.

Make it a video game

A concept a developer or an AI coding agent can build from, using only what is on this page.

The pitch

Paws in Peril is a turn-based tactics game for 2 to 4 players on a small hex map. Each player is an animal with 10 HP, two lives and a hand of item cards, racing to claim homes and mansions by beating the monsters inside them in quick dice fights. Every monster you beat joins your side with one ability, so each game builds a different little crew. A game is about 11 rounds, on one screen passed around the couch or online with friends, against bots that play like careful people. It looks like the cards: hot orange into purple, paint-splatter backgrounds, chunky round type.

Platform and engine

One turn, the core loop

  1. Start. The player gets 5 AP (plus monster buffs); starting on the desert heals 2 HP; poison ticks. The camera centres on their animal.
  2. Act. Tap a lit neighbouring tile to move (1 AP). Buttons for the current tile: Loot, Buy a card, Raid, Invade, Barricade. Item cards in the hand light up when they can be played (free).
  3. Fight. Looting a home or mansion, invading or raiding opens the fight: both sides roll 4 dice, the two highest count, the gap is damage. Between rolls, In Combat and Anytime cards can be played.
  4. Resolve. A beaten monster's card flies into the player's crew and their colour goes on the building; a knockout costs a life and sends the animal back to the desert.
  5. End. Unused AP is lost. The next player's turn begins, or the victory screen when someone reaches the VP target.

Screens

ScreenWhat is on it
TitleThe logo over the card-back art, Play, How to play (the rulebook), Settings (sound, motion, speed of bots).
Lobby2 to 4 seats, each human or bot with a colour; Beginner or Explorer board; free for all or teams; for online play, a room code to share.
BoardThe hex map in the middle; a panel per player (HP out of 12, lives, AP pips, VP, their monster cards); the action bar and the hand at the bottom; a short event feed.
FightAn overlay: the player on the left, the monster's portrait and card on the right, a tray of 4 dice each with the two that count lifted, HP bars, damage numbers, the playable cards, and a Roll or Continue button.
Card handA fan of item cards; tap to zoom to the full card art, play it if it is legal now; a discard picker when the hand goes over 5. Also the pickers for choosing a defender, taking a card after a knockout and keeping a monster.
EndThe winner, everyone's VP and crew, rounds played, fights won, and Rematch.

How the assets map to the game

Kit fileIn the game
assets/tiles/*.webpThe hex map. Each is 400 × 346, a flat-top hex, so a tile of radius R sits at x = 1.5 R q, y = √3 R (r + q/2) from the engine's axial q, r. Tint or stamp a tile in the owner's colour; show a barricade and a looted brick on top.
assets/art/*.webpMonster portraits, 480 square: the monster in a fight, the crew row on a player panel, the token on a building it defends.
assets/cards/*.webpThe printed monster cards, 600 × 840: the zoomed view and the "you won this card" moment. card-back.webp is the monster deck pile.
assets/items/*.webpThe item cards, 600 × 818: the hand, the card being played, the discard pile. _back.webp is the item deck and the other players' hands.
data/*.jsonAll names, numbers and card text; game.json sizes the HUD (AP pips, the HP bar out of 12, lives).
Not in the kitThe players' own animals. Use tokens in the engine's colours (red, blue, green, yellow) with a shape each, or draw four animals in the cards' style. The four V4 cards (Grenade, Snare, Poison Dart, Smoke Bomb) have stand-in art.

Multiplayer

AI opponents

smartbot.js is the opponent to ship. It prices every option in victory points: a home is worth 1 VP (more when it wins the game), a monster card is worth its buff and its value as a defender, and dying costs a life and the cards you drop. It takes a fight only when the chance of winning times the gain beats the chance of losing times the cost, with the chance from a few hundred simulated fights, and never takes a hopeless one. It raids when the cards it expects to grab outweigh the HP it risks, throws grenades at clusters or the leader, and keeps its best defender. It is deterministic, and at a table split between the two bots it wins about two games in three against the greedy one under the tuned rules.

Art and audio

First milestone

A playable slice: hot-seat on the Beginner board, one human against one smart bot, start to finish.

  1. A Vite + TypeScript + Phaser project that loads the kit's data and engine.js as they are.
  2. The board from state.board.tiles with the tile art and a token per player; the tiles you can move to lit from legalActions.
  3. Player panels (HP, lives, AP, VP, crew) and the action bar: move, loot, buy, end turn.
  4. The fight overlay for monster fights, stepping through combatRoll, combatContinue and combatApply.
  5. The hand: item cards that can be played when legalActions includes them; the discard picker.
  6. The end screen from state.over.

Done when a game plays from the lobby to a winner on a desktop and on a phone, with no rule logic outside engine.js. Next: raids, invasions and the other pickers; the Explorer board and teams; sound; then online play.

Prompt for an AI coding agent

Build a web video game of the board game Paws in Peril. Everything you need is at https://renfrovibes.com/paws/kit/.

Fetch and read these before writing any code:
- https://renfrovibes.com/paws/kit/rulebook.md (the rules, V4 draft)
- https://renfrovibes.com/paws/kit/data/game.json (the rule constants)
- https://renfrovibes.com/paws/kit/data/monsters.json, data/items.json, data/tiles.json (the content)
- https://renfrovibes.com/paws/kit/engine.js (the rules engine: a plain ES module, no dependencies, every rule and card)
- https://renfrovibes.com/paws/kit/bot.js and smartbot.js (the bots; they import ./engine.js and ./bot.js, keep all three in one folder)
- https://renfrovibes.com/paws/kit/manifest.json (every picture with its path, size in bytes and pixels, and what it is)
Then download https://renfrovibes.com/paws/kit/paws-in-peril-assets.zip, which holds all of the above and all the art, and unzip its paws-in-peril folder into the project's public folder.

Stack: TypeScript, Vite, Phaser 3. Keep engine.js, bot.js and smartbot.js byte for byte. The game never implements a rule itself.

How the engine works:
- createGame({ monsters, items, players: 2 to 4, board: 'beginner' or 'explorer', mode: 'ffa' or 'teams', seed }) returns the game state as plain JSON. Rules default to V4.
- legalActions(state) returns every action any player may take now, as plain objects ({ type: 'move', player, q, r }, loot, buyItem, raid, invade, placeBarricade, playItem, useAbility, endTurn, combatRoll, combatContinue, combatApply, discard, chooseDefender, takeCard, doneTaking, keepCard, placeTile). actor(state) is the player the game waits on.
- apply(state, action) returns a new state and throws on an illegal action. state.lastEvents lists what just happened, each with a type and a readable msg; animate from these. state.over is set when the game ends.
- The board uses axial hex coordinates (q, r) with the desert at 0,0. Tiles are flat-top hexes, assets/tiles/*.webp at 400 x 346.
- nextSmartStep(state, isBot) from smartbot.js returns { pid, action } for the next bot move.

Build this first (hot-seat on one screen):
1. A title screen and a setup screen: 2 to 4 seats, each human or bot, the Beginner board.
2. The board: every tile in state.board.tiles drawn with its tile art, a coloured token per player (red, blue, green, yellow), and the tiles the current player can move to highlighted from legalActions.
3. A panel per player: HP out of 12, lives, AP pips, VP, and the monster cards they own (assets/cards/<id>.webp).
4. The current player's actions: tap a tile to move; buttons for loot, buy, raid, invade, barricade and end turn, shown only when legalActions has them. The hand of item cards (assets/items/<id>.webp), playable when legalActions includes them.
5. A fight overlay: both sides (monster portraits from assets/art/<id>.webp), 4 dice each with the two highest marked, damage, HP bars; step through combatRoll, combatContinue and combatApply.
6. A picker for every choice the engine waits on: discard, chooseDefender, takeCard, keepCard, placeTile.
7. An end screen from state.over.
Bot seats act through nextSmartStep with half a second between moves; run it in a Web Worker if it stalls a frame.

Done when a game with one human and one smart bot plays from setup to a winner on a desktop and on a phone, with no rule logic outside engine.js. Next: the Explorer board, teams, sound, then online play with engine.js on a server that owns the state and hides other players' hands.

Look: hot orange (#FF9A2E, #EA6A1F) into deep purple (#1C0E24, #28143A), orange dots, Lilita One for headings and numbers, Figtree for text, rounded chunky buttons. No emoji.