Skip to content
Agentmart
Submit a tool

game-balance-and-bots

Tunes game difficulty with seeded headless bots: sim reports, balance bands, tuning knobs, a fun-in-seconds test.

Skill by zakariaf

IndexedMIT★ 11
Write a review

Chalk Labs

Need help deploying game-balance-and-bots?

Chalk Labs sets up agents like this inside real teams: connected to your tools, tested on your data, with a human in the loop where it matters.

Book a call

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/zakariaf-game-balance-and-bots

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Tunes game difficulty with seeded headless bots: sim reports, balance bands, tuning knobs, a fun-in-seconds test. Use when balancing, tuning pacing or adding bots or sims. Not for solvers or par (level-generation-and-solvers).

Use cases: testing

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md and code. Checked Oct 26, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found
Runs as
Node.js package

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/game-balance-and-bots

What's inside

Skill name
game-balance-and-bots
Description
Tunes game difficulty with seeded headless bots: sim reports, balance bands, tuning knobs, a fun-in-seconds test. Use when balancing, tuning pacing or adding bots or sims. Not for solvers or par (level-generation-and-solvers).
License
MIT
Instructions
205 lines in SKILL.md · view on GitHub

Before installing

  • Ships executable scripts

Files (66)

  • SKILL.md
  • shared.json · assets/
  • template-placeholders.json · assets/
  • arena-chase.json · examples/arena-chase/reports/sim/
  • arena-chase-sim.test.ts · examples/arena-chase/src/games/arena-chase/sim/
  • arena-chase-sim.ts · examples/arena-chase/src/games/arena-chase/sim/
  • arena-chase-tuning.ts · examples/arena-chase/src/games/arena-chase/sim/
  • arena-chase-bot.test.ts · examples/arena-chase/src/games/arena-chase/testing/
  • arena-chase-bot.ts · examples/arena-chase/src/games/arena-chase/testing/
  • balance-bands.json · examples/arena-chase/test/sims/arena-chase/
  • balance.sim.test.ts · examples/arena-chase/test/sims/arena-chase/
  • pig.json · examples/pig/reports/sim/
  • pig-tuning.ts · examples/pig/src/games/pig/rules/
  • pig-bot.test.ts · examples/pig/src/games/pig/testing/
  • pig-bot.ts · examples/pig/src/games/pig/testing/
  • balance-bands.json · examples/pig/test/sims/pig/
  • balance.sim.test.ts · examples/pig/test/sims/pig/
  • balance-contract.md · references/
  • bots-and-sims.md · references/
  • checker.md · references/
  • fun-and-kill-test.md · references/
  • tuning-playbook.md · references/
  • check-balance.mjs · scripts/
  • check-lib.mjs · scripts/
  • balance.mjs · scripts/lib/
  • selftest.mjs · scripts/
  • jest.sim.config.js · templates/
  • balance-bands.test.ts · templates/src/core/game-balance/
  • balance-bands.ts · templates/src/core/game-balance/
  • bot-policies.test.ts · templates/src/core/game-balance/
  • bot-policies.ts · templates/src/core/game-balance/
  • parse-balance-bands.test.ts · templates/src/core/game-balance/
  • parse-balance-bands.ts · templates/src/core/game-balance/
  • run-sim-bot.test.ts · templates/src/core/game-balance/
  • run-sim-bot.ts · templates/src/core/game-balance/
  • sim-stats.test.ts · templates/src/core/game-balance/
  • sim-stats.ts · templates/src/core/game-balance/
  • trace-bot.test.ts · templates/src/core/game-balance/
  • trace-bot.ts · templates/src/core/game-balance/
  • difficulty.test.ts · templates/src/core/game/
  • difficulty.ts · templates/src/core/game/
  • game-engine.ts · templates/src/core/game/
  • play-bot.test.ts · templates/src/core/game/testing/
  • play-bot.ts · templates/src/core/game/testing/
  • __GAME_ID__-tuning.test.ts · templates/src/games/__GAME_ID__/rules/
  • __GAME_ID__-tuning.ts · templates/src/games/__GAME_ID__/rules/
  • __GAME_ID__-types.ts · templates/src/games/__GAME_ID__/rules/
  • apply-move.ts · templates/src/games/__GAME_ID__/rules/
  • create.ts · templates/src/games/__GAME_ID__/rules/
  • list-moves.ts · templates/src/games/__GAME_ID__/rules/
  • outcome.ts · templates/src/games/__GAME_ID__/rules/
  • toggle-cells.ts · templates/src/games/__GAME_ID__/rules/
  • __GAME_ID__-bot.test.ts · templates/src/games/__GAME_ID__/testing/
  • __GAME_ID__-bot.ts · templates/src/games/__GAME_ID__/testing/
  • balance-bands.json · templates/test/sims/__GAME_ID__/
  • balance.sim.test.ts · templates/test/sims/__GAME_ID__/
  • write-sim-report.test.ts · templates/test/sims/
  • write-sim-report.ts · templates/test/sims/
  • jest.config.js · tests/bases/app/
  • package.json · tests/bases/app/
  • …and 6 more

SKILL.md (first lines)

# Game balance and bots

Every game is played thousands of times headless by seeded bots before a person plays it. The sims
measure the difficulty curve, whether skill matters, how soon the first win moment comes and whether
the twist happens; a bands file says what "balanced" means; every balance number lives in one tuning
file. This skill builds the harness once (`src/core/game-balance/`, `test/sims/write-sim-report.ts`),
each game's bots, sims and bands, and the check that judges the numbers.

## Rules that must hold

1. **Bots play only through the pure engine contract** (`create`, `listMoves`, `applyMove`,
   `outcome`), headless in plain Node via `jest.sim.config.js`, never through the UI. Why: the same
   rules the app runs are measured, in seconds, with no React Native mock.
2. **Every run is deterministic:** seeds `1…seedsPerCell`, the bot's own seeded RNG, no
   `Math.random`, `Date`, `performance.now`, retries, skips or focus; the report has no timestamps.
   Why: a rerun gives identical bytes, so a diff of the report shows exactly what a change did, and
   chosen seeds could shop for numbers.
3. **Every run has a hard move cap, and no run may reach it** (`capHits` = 0). Why: a stuck or
   endless game is a rules bug that a bot finds long before a player does.
4. **Use the three standard players:** `random` (the baseline), a reasonable player (the testing
   spec's `bot`: `greedyPolicy` by default) and `lookahead` (the upper bound; it sees the seeded
   future). In a game that draws during play (dice, cards, spawns), the reasonable player is a rule a
   person could follow and never peeks at the next draw: `greedyPolicy` would. Skill must matter:
   random < reasonable < lookahead by a clear step. Why: if naive play does as well as sensible play,
   the choices are fake; a peeking player measures nothing a person meets.
5. **A sim asserts properties of at least 100 seeds per cell, never a single outcome,** and writes
   `reports/sim/<game-id>.json` before its assertions. Why: one game proves nothing about balance, and
   a failing run must still leave numbers to read.
6. **Every balance number lives in `src/games/<game-id>/rules/<game-id>-tuning.ts`** (real-time games:
   `sim/<game-id>-tuning.ts`, a `'worklet'` module): documented knobs plus a per-difficulty table read
   through `knobsFor`; the rules contain no other balance numbers. Why: one place to tune, and a diff
   shows every balance change.
7. **Difficulty is one scale, whole numbers 0..100, never a table index.** `knobsFor(d)` returns the
   endless row at 100 (`ENDLESS_DIFFICULTY`, no goal, never won) and otherwise the row
   `rowFor(d, rows)` picks, with a `reduce` over the table; the grid samples the lower bound of each
   row (`[0, 25, 50, 75]` for four rows), and an endless mode gets its own `endless` block at 100,
   never a step of the curve. Why: levels (0..99), a daily and saved runs all use this scale; a 0..3
   index makes every level above 3 play the hardest row.
8. **Balance is a contract in `test/sims/<game-id>/balance-bands.json`:** the bands hold, the curve
   moves monotonically by `minStep`, the skill gap holds, the first payoff comes early, the twist
   happens, and the endless run is never won and stays inside its own bands. Never widen a band, cut
   or change seeds, or tune the bot to go green. Why: bands are the design record; moving them hides
   the problem instead of fixing the game.
9. **The fun-within-seconds kill test:** on the easiest level the reasonable player reaches the first
   payoff within 1-3 moves (2 for single-tap moves; seconds for real-time games: `runSimBot` with
   `payoffStepTicks: 120`) in at least 90 % of runs, and the twist fires at least once per run. If
   even the lookahead bot cannot, stop and report to the developer. Why: prototype bots showed ideas
   fail here structurally (a loop-closing snake caught nothing in 13 foreseen moves; a crash puzzle's
   twist came 0.25 times per game).
10. **A report counts only for the code it measured:** its fingerprint covers the game's `rules/`,
    `levels/` (without the generated `pack-*.json`), `sim/`, `geom/` and `testing/` folders, the sim
    file and the `src/core` files they import (the sim's import closure), and game logic imports
    nothing outside them; rerun `npm run test:sim` after any change there. Why: stale numbers approve
    code that no longer exists.
11. **Change the game, not the player:** improve a bot's evaluation only to match reasonable human
    play, never to reach a band; decide the payoff and twist tags before the first run. Why: a bot or
    a tag tuned to the bands measures nothing.
12. **A person's play-test is the final judge, and it never blocks:** bands stay `"proposed"` until a
    person has played on an iPhone and an Android phone and agreed, then become `"approved"` with a
    date. Until then every report lists it under "Human checks (not blocking)", and
    `check-balance.mjs --release` prints a `HUMAN CHECK (not blocking)` line, not a problem. Why: bots
    measure pace, not joy; the person's feel wins whenever it comes, and nothing waits for it.
13. **Bot numbers hold on both platforms only through pure, seeded rules and fixed ticks.** Sims run in
    Node (V8), the app on Hermes on iOS and Android; a real-time sim counts fixed ticks, never display
    frames (60 Hz Android phones, 120 Hz iPhones). Why: a balance claim that depends on the engine,
    the frame rate or the device is not a claim about the game.

## Workflow

1. **Pick the job.** First harness setup: step 2. A game's bots and sims: steps 3-8. Retuning: steps
   6-8. Judging a new idea early: read [references/fun-and-kill-test.md](references/fun-and-kill-test.md),
   then steps 3-5 at the easiest difficulty only. Always finish with steps 9-10.
2. **Harness (once per app).** Read [references/bots-and-sims.md](references/bots-and-sims.md). The
   game kit (`src/core/game/`, `src/core/rng/sfc32.ts`) comes from game-rules-engine. Run
   `node ${CLAUDE_SKILL_DIR}/scripts/check-balance.mjs .`; for every `harness-missing`,
   `harness-outdated` or `sim-config` line copy the file from `templates/` verbatim
   (`src/core/game-balance/*` with tests, `test/sims/write-sim-report.ts` with its test,
   `jest.sim.config.js`), keep `"test:sim": "jest --ci --config jest.sim.config.js"` in
   `package.json`, and make the unit project of `jest.config.js` ignore `\\.sim\\.test\\.` (both are
   in the canonical configs). Run `npx jest src/core/game-balance test/sims/write-sim-report.test.ts --ci --selectProjects unit`
   (paths first: `--selectProjects` swallows every following word).
3. **Tuning file.** Read [references/tuning-playbook.md](references/tuning-playbook.md) first. The
   game already has `rules/<game-id>-tuning.ts` from game-rules-engine's template. Name the knobs for
   the game (document each per-difficulty knob once, on the knobs type), move every balance number of
   the rules into it and read them through `TUNING` and `knobsFor(difficulty)`, keeping the `rowFor` +
   `reduce` lookup. A game with an endless mode adds the endless row and returns it first for
   `isEndlessDifficulty(difficulty)`: [examples/pig/src/games/pig/rules/pig-tuning.ts](examples/pig/src/games/pig/rules/pig-tuning.ts).
4. **Bot hooks, test-first.** Copy `templates/src/games/__GAME_ID__/testing/__GAME_ID__-bot.ts` and
   its test (Lights Out's hooks; replace `__GAME_ID__`, `__GAME_PASCAL__` and `__GAME_CAMEL__`) and
   rewrite them for the game: `evaluate<Game>`, `scoreOf<Game>` (the number the HUD shows),
   `tag<Game>Event` (payoff and twist, decided now) and the reasonable player; then set it as `bot` in
   `testing/<game-id>-testing.ts`. A game that draws during play writes the reasonable player as a rule
   ([examples/pig/src/games/pig/testing/pig-bot.ts](examples/pig/src/games/pig/testing/pig-bot.ts)).
   When the levels are proven by the reasonable player (a witness), put the evaluation in
   `rules/<game-id>-evaluate.ts` and re-export it: `levels/` may not import `testing/`. A real-time
   game exports its `SimBotGame` hooks and the `idle`, `wander` and `dodge` command policies
   ([examples/arena-chase/src/games/arena-chase/testing/arena-chase-bot.ts](examples/arena-chase/src/games/arena-chase/testing/arena-chase-bot.ts)).
5. **Sim and bands.** Copy `templates/test/sims/__GAME_ID__/` to `test/sims/<game-id>/`, replace the
   placeholders, set the grid to the lower bound of each tuning row (the template's `[0, 34, 67]` are
   Lights Out's three), name the policies, and for an endless mode replace `"endless": null` with its
   block ([references/balance-contract.md](references/balance-contract.md), "Endless mode"). Run
   `npx eslint --fix` and `npx prettier --write` on it, then
   `npx jest test/sims/<game-id> --ci --config jest.sim.config.js`. The first run writes the report
   even if the bands fail. Real-time games play through `runSimBot` instead of `traceBot`
   ([examples/arena-chase/test/sims/arena-chase/balance.sim.test.ts](examples/arena-chase/test/sims/arena-chase/balance.sim.test.ts)).
6. **Read and tune.** Fix what is broken first (cap hits, replay differences, no early payoff, no
   twist), then tune one knob at a time with the tuning loop and the symptom table, rerunning the sim
   after each change and reading `lossReasons`.
7. **Write the bands** around the tuned numbers with a margin and a `why` per band, and the story in
   `notes` in plain words; keep `"status": "proposed"`.
8. **Kill test verdict.** If the first payoff or the twist cannot be reached after reasonable tuning,
   stop and tell the developer (fun-and-kill-test.md, "When a game fails"). Do not polish a game that
   fails it.
9. **Run the check** (run, fix, rerun until `RESULT: PASS`): `npm run test:sim`, then
   `node ${CLAUDE_SKILL_DIR}/scripts/check-balance.mjs .` (add `--game <game-id>` for one game).
   Options, config keys and troubleshooting: [references/checker.md](references/checker.md).
10. **Report and hand over.** Put the plain-language "Bots" line per difficulty (numbers from the
    report) in the evidence report and "Play-test <game> on an iPhone and an Android phone" under
    "Human checks (not blocking)" until a person has done it; when they agree, set

From zakariaf/ReactNative-Skills, MIT.

More from zakariaf/ReactNative-Skills

Signals

Stars
11
Forks
2
Open issues
0
Last commit (this folder)
Oct 17, 2026 (14 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from zakariaf

Done for you

Rather not set it up yourself?

Chalk Labs scopes, builds and runs agents for your team: the task audit, the eval harness, the integrations and the weekly ops report. Fixed scope, priced before we start.

See how we build AI agents →Read the case studies

Chalk Labs is a two-founder AI and growth studio. We build AI agents, CRMs and MVPs for Web3 and AI companies, and have shipped 50+ product and token launches.

launches shipped
50+
launches shipped
media placements
500+
media placements
founders on every account
2
founders on every account

Press we've placed: Forbes · CoinDesk · Decrypt · Cointelegraph · The Block

Rahil Jain, Co-founder, Chalk Labs. Ex-Goldman Sachs engineer. You talk to the person who builds it.

Get game-balance-and-bots running in your business

Tell us what you want to automate. A founder replies within one working day with a plan, not a pitch deck.

Goes to the Chalk Labs founders, not the newsletter. Privacy

Need help deploying game-balance-and-bots?

CallGet help
Cite this page

game-balance-and-bots skill. Agent Mart. https://agentmart.dev/skills/zakariaf-game-balance-and-bots (last updated 2026-10-24)