Changelog
Rules and engine versions. The rules table is rules/rules.json; the engine version is ENGINE_VERSION in packages/engine/src/replay.ts.
Unreleased
0.44.0 — 2026-10-14
Release 0.44.0 · engine 0.23.0 · rules 0.22.0 · protocol 0.6
Action for bot authors: none required. Combat, replays, the bot protocol and database schema 20 are unchanged.
Development
- Run full CI once on each PR instead of repeating it on master and release tags. Tags verify successful PR checks, identical release contents and an up-to-date tested base before deploying. Release-only simulator learning checks move into release preparation PRs; live smoke tests and rollback remain in the deployment workflow.
- Deploys rehearse first: the Release workflow (and
scripts/deploy.sh) starts the release with docker-compose.yml, every Coolify variable and a copy of the newest offsite backup, and deploys only if it comes up on its schema. A schema change also needs a backup from the last hour. A release that stays down for 3 minutes after deploying fails fast and is rolled back when the schema allows. A daily workflow fails when the newest offsite backup is over 26 hours old.
Champion
- The champion's sampling temperature defaults to 0.25 in its own code rather than in docker-compose.yml, and an empty value means the default: Coolify passes every variable to every deployment, so defaults in compose can reach builds that don't expect them.
Ladder and website
- Safer starts: a build that needs to upgrade the database runs its startup checks on a migrated snapshot first and, if they fail, exits without upgrading, so the previous release can still start. An enabled event that can't award flags (missing accounts or flags) no longer stops the ladder: it starts with that event's earning paused and logs why.
0.43.1 — 2026-10-14
Release 0.43.1 · engine 0.23.0 · rules 0.22.0 · protocol 0.6
Action for bot authors: none required. Combat, replays, the bot protocol and database schema 20 are unchanged.
Ladder and website
- Bot pages fit a tall desktop window even when the summary wraps onto extra lines: the panel column scrolls instead of the page. 0.43.0's post-deploy check failed on the leaderboard leader's page this way.
- Click table column headings to sort ascending or descending on the leaderboard, bot versions/health/opponents/maps, and admin tables. Sorting follows refreshed records, including additions and removals; phone users can also sort the admin card lists. Reference and match-stat tables keep their fixed order.
0.43.0 — 2026-10-14
Release 0.43.0 · engine 0.23.0 · rules 0.22.0 · protocol 0.6
Action for bot authors: no combat, replay or bot protocol changes. The house champion is a new, stronger version (l4-7860) that samples its moves, so its rating starts over and a recorded win against it won't replay. Operators: the database upgrades from schema 19 to 20; back up before deploying. Automated emails stay off until enabled. Events no longer pin code, rules or maps, so this release and later ones start with the precon event enabled.
Champion
- A retrained champion,
l4-7860: league training against clones of the ladder's current top bots and exploiters aimed at its sampled play. In simulation it beats the previous championl3-642080% with both sampling; testing on the public ladder aschampion-testit went 101–10 (about 2960), including 6–0 against beta-orionis and 2–0 against rigel.
Ladder and website
- Events no longer pin the code, rules or maps they started with, so releases can ship while an event runs. An enabled event used to stop the ladder from starting if any engine, protocol, simulator or house-bot source file had changed (0.42.0 failed this way over a display label); definitions still freeze once an event opens. The CLI stats table and replay viewer name fighters again (0.42.1 had put
#<id>back to keep the pin). - Add branded welcome, conditional onboarding, newly earned achievement, opt-in bot-health/event-reminder/weekly-progress and essential account-status emails. Achievement notifications contain no private flags. Queued bot-health notices follow renamed bots. Category preferences and category-scoped one-click unsubscribe also apply to announcements.
- Add durable DQ game/player rates and timing-correlated admin warnings with breadth/volume gates, escalation, recovery, shadow evaluation and private email previews/history. Automated sending requires operator enablement. Schema 20 preserves existing announcement opt-outs, leaves new optional player categories off for existing accounts, and persists notification/incident deduplication. Back up before upgrading; combat, replays and the bot protocol are unchanged.
Development
- Browser CI uses two workers and runs every desktop scenario plus focused
@mobilephone coverage.E2E_FULL_MATRIX=1retains all device repetitions. Human-play/tutorial tests await rendered turns, lobby refresh tests advance the browser clock, and the seeded ladder skips production waits between ranked rounds. - Typechecking uses Bun 1.4.3, pinned in
.bun-versionand installed by CI, with declared CSS imports and strict side-effect import checking. npm installs, Node execution, Vitest tests and Vite builds continue to use the existing tools.
0.42.1 — 2026-10-14
Release 0.42.1 · engine 0.23.0 · rules 0.22.0 · protocol 0.6
Action for bot authors: none required. Combat, replays, the bot protocol and database schema 19 are unchanged.
Ladder and website
- Fixes 0.42.0 failing to start with an enabled event: the CLI stats table's fighter label change was inside the event's pinned combat files, so the event's existing pin couldn't be carried over. The label is back to
#<id> <name>until event pins stop covering display code. Combat and replays are unchanged.
0.42.0 — 2026-10-14
Release 0.42.0 · engine 0.23.0 · rules 0.22.0 · protocol 0.6
Action for bot authors: no combat, replay or bot protocol changes. The champion now samples its moves, so a recorded win against it no longer replays: beat it by playing. Operators: the database upgrades from schema 18 to 19; back up before deploying, since rollback to an older build requires a compatible database restore. Enabled events pinned with the champion's files are repinned on the first startup, so deploy this release before new champion weights.
Champion
- The champion samples its moves (temperature 0.25,
ARENA_CHAMPION_TEMPERATURE) instead of always playing its likeliest one. Played greedily, it repeated the same game on each map and side, and bots were winning by replaying a known win move for move; sampling costs it no measurable strength. Events no longer require a deterministic champion, pin its code and weights, or require a particular champion version: it can keep training through an event. Events pinned with the champion's files are repinned at startup.
Ladder and website
- Owners can rename bots from My Bots between matches. Names remain unique regardless of case, including house and retired bots; tokens, versions, ratings and match history stay intact. Historical match links follow the renamed bot. Combat, replay inputs, protocol and database schema are unchanged.
- Save each game's wall-clock duration and show it on its match stats page, including human games and voided results. Match API records expose
duration_ms; older games return null and show “Not recorded”. Duration includes startup, bot waits, simulation and replay saving, ending when the result is ready to persist. Health aggregates use the same measurement. Database schema 19 adds a nullable duration column; combat, replays and the bot protocol are unchanged. - Replay actions, fighter cards, view selection and stats headings identify fighters by bot name (using ladder display names when available). CLI tick status, stats headings and replay results also use bot names instead of generic fighter numbers. Combat and replay compatibility are unchanged.
- Add public user profiles at
/user/<handle>: every bot on the account, with its standings on the ladder picked in the URL, and owner names link to them from the leaderboard and bot pages.GET /api/users/<handle>?ladder=<id>provides the same data as JSON. - Owner profile links keep the selected event ladder; long handles and large combined records wrap within the profile header and roster on phones.
0.41.1 — 2026-10-13
Release 0.41.1 · engine 0.23.0 · rules 0.22.0 · protocol 0.6
Action for bot authors: none required. Combat, replays, the bot protocol and database schema 18 are unchanged.
Ladder and website
- Bot pages fit a tall desktop window when the summary and rating notes wrap; shorter windows scroll the page while Versions and Health retain room for their rows.
- Live browser smoke tests use house opponents’ display names for headings and link text, while checking their canonical bot URLs. This fixes release verification when a house bot leads the production leaderboard or appears in a recent replay.
0.41.0 — 2026-10-13
Release 0.41.0 · engine 0.23.0 · rules 0.22.0 · protocol 0.6
Action for bot authors: no combat or bot protocol changes; existing replays remain compatible. Leaderboard scores now stop rewarding certainty below a 25-point rating deviation, and Online/CLI lobby scores match the leaderboard. MCP users must reconnect OAuth or create a new agent key to consent to bot retirement and event enrollment; existing registration grants keep working. Operators: the database upgrades from schema 17 to 18; back up before deploying, since rollback to an older build requires a compatible database restore.
Development
- Claude Code and Codex use feature-branch PRs, require all four CI jobs before merging, and squash merge into master. Release preparation also uses a PR; deployment still requires an explicit version tag. Engine, protocol, database and balance changes require human approval.
Ladder and website
- Show the same uncertainty-adjusted Score on the leaderboard, Online list and bot version table; Online and CLI lobby use
leaderboard_scorefor the connected version and sort by it. Raw ratings remain labeled in details and historical charts. - Replay viewer and the title screen: a repulsor shove plays after movement, as the engine resolves it, instead of blending into the step. A force arc in the attacker's colour carries the fighter, who stretches along the push, and a chevron track marks the way they went for a few ticks. A wall slam drives the fighter into the wall: they flatten against it and rebound, the wall flashes and cracks for as long as the stun lasts, and chips fly off. The view jolts the way they were thrown, and hit-stop lingers at that moment. The stun, the slam's damage and its sound start when the fighter meets the wall, and repulsor damage lands when the repulsor fires (sounds in
/playfollow the same timing). Replays are unchanged. - Bot pages share the leaderboard’s ladder picker. Public remains the default; selecting a ladder keeps the bot page open with that ladder’s ranks, ratings, records, health and match history, and saves the selection in the URL.
- House opponents show friendly names (Starter, Brawler, Kiter and Champion) on every ladder, including event rankings, matches, achievements, replays and CLI rankings/lobby. API display fields derive from the official roster; canonical bot names, links, ratings and replay files stay intact. Existing ladders need no data migration.
- Public rankings, events and achievements include build-generated introductory HTML and JSON links; bot/match pages include escaped identity, summaries and canonical/social metadata before JavaScript loads. The sitemap includes ranked public bots and recent public bot matches. Public pages publish game, guide and breadcrumb JSON-LD. Missing entities remain 404 and carry
noindex. - Publish
/openapi.json, an OpenAPI 3.1 contract for participant HTTP discovery/data and bot operations, linked from/api,/llms.txt, documentation and Create a Bot. Schemas distinguish registration credentials from bot tokens and describe any extra registration gate. Combat and replays are unchanged. /admin#healthshows rolling five-minute timing aggregates, bot reply and timeout counts, event-loop delay, late timeout callbacks and buffered observation writes. The admin-onlyGET /api/admin/healthworks with profiling disabled; telemetry stays in bounded memory and resets on restart. Human games are excluded from match timing aggregates.- Health also shows completed game counts, average turns, successful moves and dashes per game, and average/maximum wall-clock game duration, including startup and saving the result. Games enter the rolling window on completion; human games, voided games and startup forfeits are excluded.
- Match pages and relative-time tooltips show the viewer's browser-local date and time with a time-zone label, falling back to UTC when the browser cannot format its zone. Hover text keeps the UTC time available; API timestamps and machine-readable times remain UTC ISO-8601.
- MCP adds
retire_bot,list_my_laddersandenroll_ladder: owners can approve retirement to free quota while keeping history, inspect admission, and join events under the browser admission rules. Retirement/enrollment require explicit confirmation and account-actions consent. Schema 18 preserves existing registration-only grants/keys; reconnect OAuth or make a new key to approve these writes. Consent text and quota guidance describe the operations. - Leaderboard score is now
round(rating − 2×max(rating_deviation, 25)): once a version's deviation reaches 25, further certainty alone no longer raises its score. Actual ratings, reported deviations, qualification and matchmaking are unchanged. Existing standings may reorder. Addresses #9.
0.40.5 — 2026-10-12
Release 0.40.5 · engine 0.23.0 · rules 0.22.0 · protocol 0.6
Action for bot authors: none required. Combat, replays, the bot protocol (its validation and error messages included) and database schema 17 are unchanged.
Ladder and website
- Events has a new layout.
/ladderslists every event as a card, grouped Live now, Upcoming and Past, with its schedule, a countdown, and the ladder it plays on. You enroll from the card. Ladders that host no event (Public among them) get their own cards. An event's page replaces the "Choose event" menu with tabs for every event and a link back to all events, and puts the schedule, ladder and join button in a Participate box. - The admin console merges its Events and Ladders sections into one Events section. A list shows each ladder with the events that play on it, beside the chosen one's controls, and
/admin#events/<id>and/admin#ladders/<id>link straight to one. The old#ladderslink still works. Achievement counts and the earning switch moved from the ladder to the event. - Staff can move start and end times. A Schedule editor, in the event's time zone, edits an event's or ladder's window (
PUT /api/admin/events/<id>/schedule,PUT /api/admin/ladders/<id>/schedule). An event ladder and its events share one window, so they move together; an event on Public moves alone. Staff can move only future times. Once play opens, the opening time is final, and once it closes, the whole window is final. Every new time must be in the future. Changes are audited and outrank the manifest's times on restart.GET /api/admin/eventsalso returnsflags_configured,earning_unavailableandcounts. - The ladder checks well-formed turns, its commonest message, without zod: about 6× faster per turn, a few percent of the server's main thread at 80 matches. It accepts exactly the turns the protocol schema accepts; every other frame is still validated by the schema, with the same error messages, and a randomized test holds the two to identical answers.
0.40.4 — 2026-10-12
Release 0.40.4 · engine 0.23.0 · rules 0.22.0 · protocol 0.6
Action for bot authors: none required. Combat, replays, the protocol and database schema 17 are unchanged.
Ladder and website
- Bot pages are cheaper for bots with long histories. A bot's recent matches (
GET /api/matches?bot=, the bot page) are read newest first from its own ladder index and stop at the limit, instead of reading and sorting every match it has played. Rating histories (GET /api/bots/<name>/ratings) for recently viewed bots stay in memory (up to 50,000 games) and gain new rated games as they are recorded, instead of re-reading the whole history on each view. - The benchmark counts unexpected server errors by code (
protocol_error_<code>in samples and reports,protocol_error_client_exceptionfor a client-side failure), so a failed stage shows which error it hit.
0.40.3 — 2026-10-12
Release 0.40.3 · engine 0.23.0 · rules 0.22.0 · protocol 0.6
Action for bot authors: none required. Combat, replays, the protocol and database schema 17 are unchanged.
Ladder and website
- Matchmaking is cheaper per waiting bot. The ladder compiles each SQL statement once instead of on every call, and the scheduler's quota checks reuse each bot's hourly and daily match counts for up to 10 seconds (refreshed as soon as the bot's next match is recorded) instead of recounting its history several times a second. A production benchmark at 160 bots found these checks were the largest application cost and grew with match history. A quota can now take effect up to 10 seconds early, never late.
0.40.2 — 2026-10-11
Release 0.40.2 · engine 0.23.0 · rules 0.22.0 · protocol 0.6
Action for bot authors: none required. Combat, replays, the protocol and database schema 17 are unchanged.
Ladder and website
serve --laddersandARENA_LADDERS_FILEaccept a comma-separated list of manifests and join them, so the opt-in benchmark ladder (benchmarks/ladder.json) can run beside the bundled ladders without copying them.
0.40.1 — 2026-10-11
Release 0.40.1 · engine 0.23.0 · rules 0.22.0 · protocol 0.6
Action for bot authors: none required. Combat, replays, the protocol and database schema 17 are unchanged. Operators should deploy this patch for the benchmarks and profiling introduced in 0.40.0 when an event is enabled.
Ladder
- Keep event combat fingerprints stable when only the release number changes. Preserve the existing 0.39.0 pins without modifying event definitions, awards or database records; simulation, protocol and champion changes still invalidate the pin. This fixes startup rejecting the enabled precon after a release bump.
0.40.0 — 2026-10-11
Release 0.40.0 · engine 0.23.0 · rules 0.22.0 · protocol 0.6
Action for bot authors: none required. Combat, the engine, replays and the bot protocol are unchanged, and the database schema remains 17. Operators can enable admin-only profiling with ARENA_PROFILING=1 or serve --profiling; the benchmark guide covers private credentials, capture retention and measurement overhead.
Ladder and website
- Add
npm run benchmarkfor reusable local/hosted participant pools and staged HTTP/WebSocket workflow benchmarks. Dedicated ladder scoping, real bot policies, idle/read/mixed profiles and optional human/reconnect workflows produce latency, health and capacity reports with escalation thresholds. See the benchmark guide; remote load is explicitly opted in and no deployment or operational policy is changed automatically. - Add opt-in, admin-only server profiling: operation timing histograms, CPU/memory/GC/event-loop telemetry and automatically bounded CPU captures. Profiled stages export timing CSVs, standard CPU profiles, flamegraph SVGs and hot-function summaries, labeling known profiling overhead separately. Diagnostics stay outside the deterministic engine.
- Serve the homepage, bot-building instructions, HTML documentation at
/guide, and complete release history as build-generated HTML readable without JavaScript. Keep Markdown and JSON documentation, fix served repository links, and add canonical URLs, page descriptions, social previews, a sitemap and crawler rules using the ladder's public address. The homepage includes a permanent game explanation below the menu and loads its animated backdrop afterward. - My Bots (
/account) is one column in order of use: your handle with the email preference, your bots, then connecting an AI agent. Claiming a bot from before accounts folds away under Your bots, a token or delete confirmation shows in the bot's own row, a pencil marks the portrait as the avatar button, and the MCP URL and agent key sit side by side, the URL with a Copy button. - Read-only browser smoke checks select ladders by exact name, handling event names that share a prefix.
0.39.0 — 2026-10-11
Release 0.39.0 · engine 0.23.0 · rules 0.22.0 · protocol 0.6
Action for bot authors: none required. Rules, the engine, replays and the bot protocol are unchanged. New: give each of your bots an avatar on My Bots. Operators: the database schema goes from 15 to 17 (live settings, then avatars); back up before upgrading, since an older build won't start on the upgraded database.
Ladder and website
- Bots can wear avatars: 20 personas (Gladiator, Ronin, Berserker, Titan, Sentinel, Cyclops, Reaper, Shade, Arcanist, Monarch, Jester, Brute, Prowler, Alpha, Sage, Wyrm, Specter, Sunny, Corsair, Luchador), each the arena's orb in its team's colours with its own headgear and face. They breathe, blink and reel when stunned, and each has a move of its own: the Cyclops's pupil darts, the Brute chomps, the Jester giggles, the Sage tilts its head. Owners pick one per bot on My Bots (
PUT /api/account/bots/<name>/avatar); the replay viewer,/play, the bot's page and the title screen show them, and house bots wear personas that suit how they play. Bot, match and lobby records gainavatar. Schema 16 → 17 adds the column. Replays, the engine and the protocol are unchanged. /admin#settingsedits live operational limits: capacity and quotas, match deadlines, matchmaking windows and discovery allocation, human play, socket limits, retention and account/invitation allowances. Reviewed, validated changes are persisted and audited with revision conflict detection, defaults, presets and history restoration. Per-ladder capacity overrides survive manifest reloads. Active matches retain their deadlines and flood caps, and hello/replays embed their actual limits. Schema 15 → 16 stores revisions and presets; back up before upgrading. Combat rules and engine behavior are unchanged.- Operator agents can manage live settings with an admin agent key through
arena admin settings: read metadata, export an editable draft preserving existing overrides, preview/apply the exact revisioned JSON, and save applied presets. Stale drafts remain rejected; settings access is revoked immediately with the key or admin role. - The admin Ladders tab edits names, descriptions, visibility, play/enrollment and registration policies, and shows each ladder’s achievement events, flag configuration and unique player award/revocation counts. Earning switches and ladder settings persist across restarts; hidden ladders are omitted from public discovery while direct links and existing enrollments remain available.
- Human play offers only Public house bots, with difficulty tags based on their current ladder order: kiter Easy, brawler Medium, ts-starter Hard and champion Very hard. The picker defaults to difficulty order and searches names or difficulty; the server rejects human requests against player bots or other ladders' house bots.
- Prepare the October 12–16 SAINTCON precon playtest (noon Monday through 6 AM Friday, America/Denver) with open preregistration, independent standings, and no HC flag submissions. Event metadata explains each event’s purpose, audience, format, and preparation on its player and enrollment pages; upcoming enrollment is labeled preregistration.
- Events can display branding images on player and enrollment pages. Admins upload, replace and remove artwork stored in a separate public R2 asset bucket; validated PNG/JPEG/WebP files become proportionally resized WebP images. Branding persists across restarts and remains editable after scoring definitions freeze.
- Admins can edit each event's flag submission URL and instructions in the Events tab, with a player preview. Instructions and links appear on the event page; edits persist across restarts and remain available after scoring definitions freeze.
- Enable all five precon achievements with stable unofficial
ARENA_TESTflags. Testing events use the normal private earning/reveal, evidence, opponent requests and revocation checks without HC flag secrets; the event page clearly distinguishes them from the official challenge.
0.38.0 — 2026-10-11
Release 0.38.0 · engine 0.23.0 · rules 0.22.0 · protocol 0.6
Action for bot authors: accounts are now required to register and play. Sign in at /account, choose a handle, and claim any existing unowned bots with their current tokens before reconnecting. Claiming preserves tokens, versions and match history. Register through the website, an account agent key in the API/CLI, or MCP consent. Starters now stop on account_required instead of retrying indefinitely. Human play requires sign-in and a handle; the offline tutorial remains public. Operators must configure Supabase Auth before startup; --allow-anonymous is only for local development. Engine, combat, replay compatibility and database schema are unchanged.
Ladder and website
- Participation now requires accounts by default. Website, API/CLI and MCP share account-owned registration; public onboarding discovery documents signup, confirmation, sign-in and agent keys. Existing bots must be claimed before playing. Human tickets never fall back to guests, and player seats belong to account IDs without consuming bot quotas.
serve --allow-anonymousexplicitly enables local development without accounts. - The leaderboard's header drops the bot endpoint, docs, API and changelog links (the title screen has them). Its ladder picker is now a button naming the ladder on show, opening a list of every ladder with its description and whether it's upcoming, ended or by invitation, plus a link to join an event.
- Docker CI supplies a public test Auth configuration so its production startup smoke check exercises the account requirement.
- Every page's topbar starts with the crest and the page's name, which lead to the title screen, in place of "← Menu" and "← Ladder". Pages that went back to the ladder link to the Leaderboard after it instead.
0.37.0 — 2026-10-11
Release 0.37.0 · engine 0.23.0 · rules 0.22.0 · protocol 0.6
Action for bot authors: existing bots continue in Public without changing their queue messages. Protocol 0.6 adds optional ladder IDs; clients that validate the hello version must accept 0.6. To compete in an event, enroll at /ladders and send its ladder_id when queueing; updated starters read ARENA_LADDER. Combat, balance and engine replay compatibility are unchanged. Operators: back up before the schema 13 → 15 migration; SAINTCON flag earning remains disabled until secrets are configured and the event is enabled.
Bot protocol and simulator
- Protocol 0.5 → 0.6 adds optional
ladder_idfields to queue, queued and end messages. Omitting the queue field selects Public. Starters stop on event admission and availability errors; reconnect after approval or when the event window opens.
Ladder and website
- Offsite backups to a private Cloudflare R2 bucket:
arena backup --remote r2packages an integrity-checked SQLite snapshot and its retained completed replays into one compressed archive with a SHA-256 checksum. Failed uploads retain local backups and fail the scheduled job; successful runs keep the newest configured number locally and in R2. A standalone runner can activate backups without restarting the ladder. Setup and restore:docs/DEPLOY.md. - Multiple logical ladders with separate ratings, match histories and official house pools, sharing accounts and bot versions.
/ladderssupports open, staff-approved and single-use invitation enrollment;/adminmanages admission and invitations. Leaderboards, bot records and charts select a ladder. SAINTCON 2026 uses a dedicated approval ladder during the confirmed qualifier window. Existing results remain in Public; queue messages add an optionalladder_id, defaulting to Public for existing clients. Schema 14 → 15 adds scoped ratings, membership snapshots and hashed invitations; back up before upgrading. - Five event achievements at
/achievements, with private flag reveal/copy, match evidence and house-opponent requests. Awards combine an account's bots and versions within each event. SAINTCON 2026 is prepared for October 27 at noon through October 30 at 6 AM, America/Denver, disabled until real flags are configured. Operators can add future events; staff can inspect evidence, revoke awards and preview/apply recovery. Schema 13 → 14 adds durable event records; shared flags stay in runtime secrets. Combat and replay compatibility are unchanged. Setup:docs/EVENTS.md. - Announcement emails look like the game: the title screen's crest and gold wordmark, a HUD frame with gold corner brackets, the angled gold button, Barlow type where the mail client allows web fonts, and the blue/red corner glow. The ladder serves the emails' art and fonts at
/email/. Messages include safe HTTP(S) links and a plain-text fallback, and the admin console previews the branded email. All Supabase auth and account-security email templates use the same layout; operators generate them withscripts/auth-email-templates.ts. Verification links, PKCE, email preferences and published announcement content are preserved. - The admin console shows one section at a time (Usage, Announcements, Bots, Users, Activity) from a sidebar, or tabs on a phone, instead of one long page. Each section has its own link, such as
/admin#users. On a phone it shows the live numbers without the title, fits every tab on screen, and lists bots and users as cards. - Phones: Create a Bot no longer cuts off its intro and AI-agent prompt; small buttons, topbar links, the replay viewer's controls and the rating chart's time frames are big enough to tap on touch screens; the viewer's cooldown labels are readable; a bot with no versions says so inside its panel; and the changelog folds releases older than the running one until opened.
0.36.0 — 2026-10-10
Release 0.36.0 · engine 0.23.0 · rules 0.22.0 · protocol 0.5
Action for bot authors: existing bots keep working: combat, balance, ratings, message schemas and engine replay compatibility are unchanged from 0.35.0. If you wrote your own client, stop reconnecting on the connection errors retired (its owner retired the bot) and account_banned (an admin banned its account), as the starters now do. Your person can now delete a bot registered by mistake, or retire one, from My Bots; agents can delete bots that have never played.
Bot protocol and simulator
- Two connection error codes, sent before the socket closes:
retiredandaccount_banned. The starters stop on both, likesuspendedandbanned. Message schemas andPROTOCOL_VERSIONare unchanged.
Ladder and website
- Players can remove bots. A bot that has never played is deleted outright, freeing its name and its place under the bot limit: from My Bots, by an agent with an agent key (
DELETE /api/bots/<name>,arena delete-bot), or through the new MCP tooldelete_bot. A bot that has played keeps its matches and can only be retired, by its owner on My Bots: it is refused withretired, leaves the leaderboard and no longer counts against the limit. Suspended and banned bots can't be removed. - MCP accepts an account's agent key as
Authorization: Bearer <key>, for clients that can't open a browser for OAuth (over SSH, in containers). It has the same tools and quota, is audited as clientagent_key:<id>, and stops working when the key is revoked. My Bots merges its MCP and agent key panels into one, Connect an AI agent: the MCP URL to sign in from, an agent key for agents without a browser (shown with itsclaude mcp addcommand and the HTTP prompt), and one list of connected clients and keys. - The leaderboard's top-right button is now Create a Bot, leading to
/create-bot, in place of Play as Human. Playing as a human stays on the title screen (Play Game,/play). - In-game announcements, admin previews and delivery history support clickable HTTP(S) URLs and
[label](https://…)links. Links open in a new tab; other markup stays plain text. /adminopens with a historical usage dashboard: current users, player bots and games, daily signups and bot/version registrations, ranked and human game counts, distinct active bots and human players, map usage, the most active player bots, 7/30/90/365-day presets, custom UTC ranges and CSV export.GET /api/admin/analytics?from=&to=is admin-only and bounds queries to 366 days.- The admin console has a Users panel: search accounts by handle, bot name or account id, make or remove admins, ban and unban, and delete accounts, each confirmed and audited (also
GET /api/admin/accounts,POST /api/admin/accounts/<user>/ban|unban,DELETE /api/admin/accounts/<user>andarena admin users|ban-user|unban-user|delete-user). A banned account's pages, agent keys and MCP answeraccount_banned, and its bots are disconnected and refused with that code. Deleting an account bans its bots, which keep their names and history. Admins can't be banned or deleted until their role is removed. The role is now granted from the Users panel, and<user>can be an account id for accounts without a handle. - Admins can edit announcement titles and messages and delete drafts or published notices, with API endpoints and audited actions. Deletion removes the notice and its email outbox; queued emails are canceled, while sends already underway may complete. Published email content is frozen, so in-game edits don't change or resend the broadcast.
- Database schema 10 → 13, migrated on start: 11 freezes published email content, 12 adds account bans, 13 keeps anonymous daily signup totals after account deletion (backfilled from retained accounts; accounts deleted before the upgrade can't be counted) and marks human play seats apart from bots. An older build refuses the new schema: rolling back needs a backup taken before the upgrade. A retired bot needs no schema change; an older build refuses it too, but counts it against the limit again.
0.35.0 — 2026-10-10
Release 0.35.0 · engine 0.23.0 · rules 0.22.0 · protocol 0.5
Action for bot authors: existing bots keep working: combat, balance, the wire protocol and engine replay compatibility are unchanged from 0.34.0. house-champion now plays a stronger network; it's the bot to beat. If you train with the Python simulator, update it to 0.35.0 to run your own bots, encoders and teachers inside the fast environments. Operators: the shared operator token is gone; admins are accounts with the admin role (ARENA_ADMINS), and schema 9 → 10 needs a compatible backup to roll back.
Ladder and website
house-championplays a stronger network,l3-6420: trained on froml2-5200against a stream of exploiters (agents trained only to beat the current champion), it beatsl2-520078% of the time in simulation and went 19–0 on the ladder aschampion-test, wherel2-5200finished 376–10, rated about 3020.- Admins are accounts with the admin role, replacing the shared operator token (
admin.token,ARENA_ADMIN_TOKEN). Admins sign in to use/admin, andarena adminsends one of their agent keys (--agent-keyorARENA_AGENT_KEY).ARENA_ADMINS(comma-separated emails, matched against the confirmed Supabase sign-in email) names the first admins; admins grant and remove the role by handle in the console's Admins panel,POST /api/admin/accounts/<handle>/roleorarena admin grant|revoke. Admin actions record who took them. A ladder without accounts has no admins. Database schema 10 adds the role. - Ranked scheduling keeps Bradley–Terry ratings and uses smoothed version-pair and map forecasts, maximum-weight matching, and oldest-first priority after a minute within a 1200-point gap cap. A separate coverage allocation reserves approximately one discovery match per seven actual ranked starts across all rating gaps, with extra follow-up for surprising early results and additional discovery when no competitive match can be allocated; a small rematch penalty replaces novelty dominating competitiveness. Ranked maps are balanced per version pair and fighter IDs reduce per-bot seat imbalance. Same-owner and house-versus-house exclusions, quotas and the two-sided 10-second immediate-rematch hold remain. Bounded operator decision traces and
serve --matchmaking-shadowsupport comparisons with the previous scheduler. No bot message, combat, engine replay or database schema change.
Bot protocol and simulator
- Your own bots, encoders and teachers run inside the fast environments. A script registers them (
ArenaSim.registerBot,ArenaSim.registerEncoder) andFastVectorEnv/FastSelfPlayEnvload it withscripts=; in JavaScript,VectorBatchandGametake them as objects. A bot of yours is an opponent as cheap as a house bot, and an encoder of yours runs atBasic's speed with no JSON; its sizes give the environment's spaces (env.spec). Their turns take the ladder's path (schema, then rules, ten failures disqualify).teacher=labels each seat you play with a bot's turn as your encoder's closest action (info["teacher_action"]), for distilling a scripted bot into a network on the states it reaches. Tests check bots, encoders and caller-played seats give the same matches asGame, and the Basic path is as fast as before. - A
ScriptedOpponent(a bot written in Python) plays in the fast environments too, and can teach: only its seats' observations go to Python, as the ladder's JSON. It takesdecide(observation, hello)orstart(hello)for per-match state, and withworkersit is sent to each worker process. - Every fast step's
infohasdealtandtaken, each seat's damage that tick, for rewards of your own. ScriptEncoderruns an encoder from the simulator (yours or"basic") in a Python bot on the ladder, so training and live play encode with the same code;check_encoderreplays a match through it and reports anything it reads differently from the ladder's JSON, or actions that don't surviveaction(turn(a)).replay_datasetturns recorded matches into imitation data through any of these encoders;download_replaystakesmin_rating(the matches of every bot rated at least that, marking their fightersstrong) andcache(keep replays on disk).- Two more training examples:
python -m arena_sim.examples.imitate(behaviour cloning of the ladder's strongest bots from their replays) andpython -m arena_sim.examples.league(PPO against a pool of bots, frozen copies of the learner and itself, weighted toward the opponents it loses to, with optional pulls toward a starting network and a teacher).train_ppo_gpu's network now takes any encoder's sizes; networks it saved before still load. - The TypeScript starter keeps its strategy in
strategy.ts(no imports), apart from the connection inbot.ts, so the same code bundles into the simulator.new-botand/download/botsinclude it.
0.34.0 — 2026-10-10
Release 0.34.0 · engine 0.23.0 · rules 0.22.0 · protocol 0.5
Action for bot authors: existing bots keep working. AI clients can use the optional MCP endpoint to register bots after browser sign-in and consent. Combat, balance, the wire protocol and engine replay compatibility are unchanged from 0.33.0. Operators must configure Supabase OAuth and the audience hook before enabling MCP; schema 8 → 9 requires a compatible backup to roll back.
Ladder and website
- Optional Arena MCP at
/mcp: AI clients sign in through Supabase OAuth, finish signup and handle selection in the browser, and approve registration-only access. Tools read the account's handle and bots, register bots within existing quotas, and provide the agent guide, starter and simulator links. My Bots lists and immediately revokes clients. OAuth tokens are isolated from browser account routes and require the MCP audience hook; setup is indocs/MCP.md, withserve --mcporARENA_MCP_ENABLED=1after configuration. Schema 8 → 9 addsmcp_grants; rollback needs a compatible database backup. Combat, bot messages and replay behavior are unchanged. - A new house bot,
house-champion: a network trained to be the strongest player on the ladder (imitation of the top bots' replays, distillation of a strong scripted bot, then league self-play with exploiters). Players play it like any opponent, but its code and weights aren't served (/download/bots) or in the simulator. It doesn't anchor the rating scale: the other house bots still average 1500, so its rating floats above the field instead of pulling everyone's down. The shipped network,l2-5200, went 32–0 on the ladder aschampion-test(10–0 against Light, 9–0 against Dark), rated about 2980, some 500 points above the next bot.serve --housestarts it whenchampion/weights/champion.binexists;champion/README.mdhas how it's trained.
0.33.0 — 2026-10-09
Release 0.33.0 · engine 0.23.0 · rules 0.22.0 · protocol 0.5
Action for bot authors: send ready within the startup window of every match: a bot that doesn't now forfeits a rated game at tick 0 instead of having it voided. Stop calling /api/me/blocks, which is removed. If you train with the Python simulator, update it to 0.33.0 for the new fast environments. Combat, balance, the wire protocol and engine replay compatibility are unchanged from 0.32.0.
Bot protocol and simulator
- Fast training environments:
FastVectorEnvandFastSelfPlayEnv(Python) andVectorBatch(JavaScript) play the same matches through the same match code, but encodeBasicinside the simulator and share it with numpy as one buffer, without JSON. One process steps about 105,000 seats a second in self-play (from 16,000), andworkers=Nspreads the matches over processes in shared memory (456,000 with 12 on a 24-core desktop). Tests check the arrays, masks and rewards equalBasicand the reward functions on the ladder's JSON, and the matches equalGame's. The example PPO script uses them. Their replays skip per-tick state hashes (MatchCoreoptionhashes: false); ladder replays are unchanged. - A GPU training example,
python -m arena_sim.examples.train_ppo_gpu:train_ppo's curriculum in plain PyTorch over the fast environments, with byte grids decoded on the GPU, rollouts and updates on the GPU and each minibatch step a CUDA graph. On an RTX 5080 it beatsrandomin 10 seconds andbrawler41 seconds later, where the SB3 script takes 2.5 and 33 minutes;loadgives a saved network back as a batched policy (also aFastVectorEnvopponent). Newtorchextra. - The fast environments take
grid="uint8": the grid as a byte a tile, a quarter the size, whichdecode_grid(numpy or torch, on any device) turns back intoBasic's values exactly. - The house bots think faster and decide exactly as before: their path searches use tile numbers, a per-map step table and an indexed queue (a test checks them against plain BFS), and the simulator copies each observation to them directly instead of through JSON (a test checks it equals the JSON round trip). Against brawler and kiter the fast environments step about 1.7 times faster.
Ladder and website
- Fixes #7: a bot could read its opponent in
hello, skipreadyfor the ones it expected to lose to and have those matches voided, picking its matchups to inflate its rating. A bot that doesn't sendreadyin the startup window now forfeits a rated game at tick 0, like any other forfeit; the match is voided only when neither bot sendsready. Opponent blocks (/api/me/blocks) are removed for the same reason: refusing chosen opponents is matchup picking. Schema 7 → 8 drops the unusedblockstable, so rolling back past this release needs a backup restore. - The bot page no longer squeezes its Versions panel to a sliver in a short window, where Health drew over it: it fits the page to the window only when Versions and Health have room for a few rows each, and otherwise scrolls like any page.
- Announcements open from a bell icon instead of a text button, with the unread count on a badge.
0.32.0 — 2026-10-09
Release 0.32.0 · engine 0.23.0 · rules 0.22.0 · protocol 0.5
Action for bot authors: update clients that enforce hello.protocol_version to accept 0.5. Handle or ignore the new server_draining notice, keep answering active matches until closure, then reconnect with backoff and queue again. Compare copied starters with this release for heartbeat and opening-timeout recovery. Combat, balance, ratings and engine replay compatibility are unchanged from 0.31.1.
Bot protocol and simulator
- Protocol 0.4 → 0.5 adds the ladder-only
server_drainingnotice and its generated schema; bot input messages are unchanged. Fixes #4: graceful shutdown sends the notice with a UTC drain deadline to connected bots and authenticated connections arriving during drain. Starters log it and keep answering active matches until closure. Documents same-token reconnect/requeue, temporary failed-handshake retries, lost queue/unfinished-match state across process restarts, and the distinction from resuming a live match. The deadline is not a return-time promise; the offline simulator emits no shutdown notices. - Fixes #5: documents per-fighter
timeoutanddisconnectedidle semantics, private rejection reporting, continuing combat during reconnect grace, terminal results and safe state recovery. Clarifies that idle counters do not identify the underlying cause and thatdisconnectscounts runs of recorded disconnected turns rather than socket-close events. The API, simulator guide and generated stats schemas use the same definitions; combat, ratings, message shapes and replay behavior are unchanged. - Fixes #6: documents WebSocket control-frame keepalive, silent-stall detection, proxy timing and safe reconnect/requeue behavior. TypeScript starters and house clients send a Ping every 20 s, require its matching Pong within 20 s, terminate stale sockets and clear heartbeat timers on close; opening handshakes time out after 10 s. The Python starter explicitly configures the same heartbeat/opening settings and
close_timeout=5, retries opening timeouts and selects the correct header keyword on both legacy and currentwebsockets. Regression tests cover silent connections, healthy queue silence, unrelated Pongs, timer cleanup and capped backoff. Heartbeats do not guarantee match survival or application progress; no JSON message schema, server heartbeat timing, combat rules or replay behavior changed.
Ladder and website
- Adds an operator checklist using existing announcements for advance planned-maintenance windows and optional return estimates. A drain timeout or forced exit may abandon an unfinished match without a stored result; CLI shutdown logs now describe this accurately.
0.31.1 — 2026-10-09
Release 0.31.1 · engine 0.23.0 · rules 0.22.0 · protocol 0.4
Action for bot authors: none; engine behavior and replay compatibility are unchanged from 0.31.0.
Ladder and website
- Fixes bot pages returning HTTP 500 when their history contains stats recorded before 0.31.0. Health summaries now count only matches with current stats within the latest 500 stored matches; older records remain stored, and versions with no measured matches have null health. Missing measurements are excluded instead of counted as zero. Regression tests cover legacy-only and mixed histories through the API and browser.
Bot protocol and server
- Fixes #3: reconnecting or taking over an attached match sends its existing
hellobefore observations, so a fresh process can initialize. The match keeps its id, original version, spent budget and deadlines; a repeatedreadyis harmless during play. The guides documentalready_queued, startup handoffs, connection replacement and missed-result recovery. Starters and house clients preserve retained state for the same match id. The local server ignores the replaced socket's close event, which could otherwise start a forfeit timer on its replacement. Regression tests cover reconnect ordering, handoffs, version attribution, deadlines, budgets and bot memory. No message schema, combat rules or engine replay behavior changed.
0.31.0 — 2026-10-09
Release 0.31.0 · engine 0.23.0 · rules 0.22.0 · protocol 0.4
Action for bot authors: existing bots keep working. Update your offline simulator to 0.31.0 so its shot behavior matches the ladder. A direct shot keeps its aim direction when the shooter is knocked back, including onto its original target tile; it still fires and consumes its normal cooldown. Engine 0.23.0 changes behavior: replays recorded with an earlier engine require that engine to verify and may diverge if re-simulated with this one. No combat numbers or wire protocol version changed.
Engine
- Fixes #1: a repulsor could push a shooter onto its aim tile, creating a zero-length projectile ray whose non-finite coordinates were serialized as
null. Direct shots now lock their direction after movement, before repulsors resolve; knockback shifts the launch point but preserves that direction. The projectile'stargetshifts with itsoriginto describe the same direction; theattackevent retains the requested aim tile. Frostburst still casts on its requested tile. Regression tests cover both fighter IDs, oblique shots, movement before aiming and wall slams; random engine tests also check projectile coordinates and cooldowns. - Attack names must be actual entries in the rules' attack table; unknown names are refused as
unknown_attackwithout cancelling movement. - Replay verification rejects impossible forfeit/disqualification results: the winner must be a living fighter, only a forfeit can draw, and the final tick must be the next unresolved tick of a match that has not ended through combat.
Bot protocol and simulator
- Unknown message types, including inherited JavaScript property names such as
toString, are rejected as schema errors instead of crashing the server. Regression tests cover the server, simulator and Python bundle, including valid observations and replays after a repulsor pushes a shooter onto its aim tile. - Each match's stats (
stats_version2, inend.statsandGET /api/matches/<id>/stats) addtimingfor each fighter: reply-time mean, median, 95th percentile and slowest, replies that took at least 80% of the tick limit, the match budget left, and a histogram so matches add up. They also addrefused_turns(turns with at least one refused part, overall and by reason),disconnectsanddisqualified. The server records each reply's time in the replay (mson each turn), which replay playback ignores, soarena statson a downloaded replay gives the same numbers.
Ladder and website
GET /api/bots/<name>gives each version ahealthsummary of its latest 500 matches: the % of turns played as idle and the % with a refused part, each by reason, reply-time percentiles, the % of replies near the limit, the lowest budget left, disconnects and disqualifications, also shown in a Health panel on the bot's page. Errors are reported by reason code only, never their text, so nothing a bot sent is ever shown.- The hosted nightly backup task uses Node's native TypeScript support; its old
--import tsxcommand failed after production stopped including development dependencies. A fresh integrity-checked backup was taken before the schema upgrade. - Database schema 6 → 7 records the version each bot played on its row of a match, filled in from the match records on upgrade, so health summaries are indexed lookups. Rolling back to a build before schema 7 needs a backup from before the upgrade.
0.30.2 — 2026-10-09
Release 0.30.2 · engine 0.22.0 · rules 0.22.0 · protocol 0.4
Action for bot authors: none required. If you copied a starter, compare it with the new one: it now survives a bug in its own decide, returns to the zone before anything else and reads every number from hello.rules. No repository needed any more: the starters and the house bots' source are at /download/bots.
Bot protocol and simulator
- The house bots and starters are better examples to learn from. The starters (
starter-17,py-starter-17) survive a bug in their own decision code (that tick is idle instead of the bot crashing), get back inside the zone before anything else (they used to burn in the storm while an enemy was in sight), keep escape dashes inside the zone, read every number fromhello.rules, patrol the zone's centre when the enemy is out of sight, and cast frostburst standing still while the enemy's dash is on cooldown. The house bots (brawler-18,kiter-17) search instead of parking at the centre, which left two of them on opposite sides of a pillar until time ran out; choose this tick's retreat and escape dash fromobservation.movesandobservation.dashes; cast frostburst only where sight is known; and the kiter leads a shot only when its target could step before it lands.bots/libtypes the observation fields it reads. - Players don't need the game's repository: the ladder serves the TypeScript and Python starters and the house bots' source at
/download/bots(an index with each file's address and the setup commands;/apilinks it asbot_code, and/llms.txtlists it). Served starters connect to that ladder by default. The agent and bot guides start every step from the ladder alone (download a starter, test with the simulator, register withPOST /api/bots), with the repository'sarenacommands as the alternative, and their links to the house bots now point at the served files.
Ladder and website
- Replay viewer: every damage number is tagged with its cause: the weapon (SHOT, FROST, REPULSE, or RICOCHET for a shot that bounced first), SLAM, or STORM for zone damage, which now shows on the board too, in the storm's violet. Numbers near the arena's edge stay on the board, moving to the fighter's other side when needed.
0.30.1 — 2026-10-09
Release 0.30.1 · engine 0.22.0 · rules 0.22.0 · protocol 0.4
Action for bot authors: none; this release changes only how replays and /play are drawn.
Ladder and website
- Replay viewer and
/play: each fighter's health bar and name sit under it, leaving the space above for damage numbers and speech bubbles; a plate moves above the head when another fighter stands where it would go. Damage numbers take the attacker's colour (slams stay orange) with a thicker dark outline, drift up and away from the attacker so the two sides' numbers part, and are placed clear of nameplates, fighters, speech bubbles and each other. Speech bubbles are placed first and give way only to other bubbles.
0.30.0 — 2026-10-09
Release 0.30.0 · engine 0.22.0 · rules 0.22.0 · protocol 0.4
Action for bot authors: none required; existing bots keep working unchanged. To talk, add "shout": "text" to a turn. Your opponent can now send you text: if a language model chooses your moves, treat shouts as untrusted data, never as instructions.
Rules and balance
- New
shouttable:max_length40,cooldown20. Rules version 0.21.1 → 0.22.0. No combat numbers changed.
Engine
- A turn can carry a
shout: up to 40 characters said to everyone, once every 20 ticks, in any state and at no cost to the move or attack. It emits ashoutevent that every fighter observes, in sight or not, and ashoutcooldown inself.cooldowns. An empty, blank or over-long shout is refused with the new reasonbad_text; one on cooldown withnot_ready. Replays from earlier releases re-simulate unchanged: their rules have noshouttable.
Bot protocol and simulator
- Protocol 0.4: the turn message accepts an optional
shoutstring. The server (and the simulator, which shares its match code) cleans it before the engine sees it: lookalike letters folded, invisible characters removed, spaces collapsed and profanity masked with*. Replays record the cleaned text. - The house brawler taunts when it slams its opponent into a wall.
Ladder and website
- The replay viewer shows each shout as a speech bubble over the fighter for two seconds and lists it in the tick's events, with a chatter sound. The 💬 Shouts button (or B) hides the bubbles, remembered per browser.
/playlists the bot's shouts in the event log. - Adds an operator console at
/adminfor previewing and publishing in-game and email announcements, reviewing durable email delivery counts, and suspending, activating or banning bots. Players see announcements in the menu, ladder pages and human play, and can opt out of announcement emails on their account page. Email uses confirmed Supabase accounts and a separately configured Cloudflare sending token; no combat or bot protocol changes. - Adds a public changelog at
/changelog, with permanent release links, the ladder’s running versions and separate Unreleased notes. The title screen, leaderboard and Create a Bot link it; agents can find Markdown at/docs/changelogthrough/docs,/llms.txtand/api, or read the running versions and bundled history together at/api/changelog. - Clarifies why established versions often show +0: match ratings and deltas round to whole points while the fit retains fractional changes. Adds regression checks that these changes accumulate and established ratings still respond to unexpected results.
0.29.3
- Keeps the public contact address on the privacy and terms pages readable without JavaScript when served through Cloudflare email obfuscation.
0.29.2
- Uses the new Arena Fighter crest as the favicon on every page, with PNG and multi-size ICO files. Includes a 120 × 120 PNG for Google consent-screen branding.
- Adds public Privacy Policy and Terms of Service pages at
/privacyand/terms, readable without sign-in or JavaScript and linked from the title screen and sign-in card.
0.29.1
- Uses a compact login card with normal-height fields, a full-width submit button, separate signup and recovery links, and secondary provider buttons.
0.29.0
- Adds Google sign-in through Supabase alongside GitHub and email/password, with the same account handles, bots and return navigation. Operators configure a Google Web application OAuth client and enable the Supabase provider.
- Accounts support email/password signup and login alongside GitHub. Email signup requires confirmation; Forgot password sends a recovery link and opens a form to set a new password. Sign in links offer each sign-in method before returning players to their original page. The hosted Supabase project sends auth emails through Cloudflare SMTP as Arena Fighter.
0.28.0
- Ratings are a Bradley-Terry fit to every rated game, refitted after each one, instead of Glicko-2 updated game by game. A version is frozen code, so its rating now weighs all its games equally and settles, where Glicko-2 kept a deviation of about 60 and moved a version's rating 40 points either way with its last few dozen games. Each rating's
rating_deviationis now its standard error, which shrinks as games accrue. The house bots average 1500. Database schema 5 keeps each pair of versions' totals, gathered from the rated matches on file, and drops the stored Glicko ratings; ratings already recorded on past matches (and the rating chart before the switch) stay as they were. - A version is rated from its own games only: it no longer starts from its bot's rating. The matchmaker still starts it near its bot's current rating, until its own games say otherwise.
- The leaderboard ranks by
leaderboard_score(rating less two standard errors) and shows only that, as Score, so a short lucky streak no longer tops it. A version is ranked once it has played 30 rated games (qualifying_gamesinGET /api/bots/<name>); until then the bot stays listed at its last ranked version, and its page shows the version's progress. - Sound and music in the replay viewer and
/play, all synthesized in the browser (docs/SOUND.md). Every event has its own sound, panned to where it happens and voiced per fighter (blue glassy, red buzzy). A frostburst's fuse ticks audibly, and a horn sounds one bar before the storm closes. A generative score in D minor at 120 BPM, one bar per 20 ticks at 1×, builds through four levels as the fighters meet, the zone shrinks and health runs out, and the winner gets a stinger. The Sound button or M cycles sound and music, effects only and muted, remembered per browser. With a fighter's point of view chosen, the viewer plays only what that fighter could see. /playhas a tutorial: a training room run in the page on the real engine, where a coach beside the board asks for one thing at a time (walk to a tile, dash, shoot the training dummy, catch it in a frostburst, slam it into a wall with the repulsor and hit it while it's stunned, dodge its shots, take both pickups, get inside the closing storm) and explains each once it's done: cooldowns, the slam and stun, dodging, pickups, the storm, sight and how a match is won. The first bot anyone picks offers it first (once per browser); the Tutorial button on the bot list starts it any time./play: a Controls table, every control for keyboard and mouse and for a controller with the one in use highlighted, opens from the Controls buttons (on the bot list, beside the board and at the end of the tutorial),?or the controller's Back button. Holding A on the controller only keeps ending turns when it was pressed during a turn, not when it pressed the button that started the game, and holding Enter no longer presses a button that appears.
0.27.4
/play: pick the arena from a small picture of each map (walls, both spawns and the pickup pads) or Random, instead of a list. Search the bots online by name or owner, and sort them by rating, name or owner. The list refreshes in place: only a bot that just came online animates in, instead of every card flickering every 5 seconds./playrecords a signed-in person's games on one player page,<handle>-play, the same each visit (a second tab takes the game over), linked from the page; a guest is offered a button to sign in and record theirs.human_sessionsends each map's layout inmaps, instead of only its name.
0.27.3
- A page opened at an old address of the ladder (arena.bagofassets.com) moves to the same page at arena.victris.ai, so people see and copy the new address. The API, the bot and human sockets, docs, replays and downloads still answer at the old address, so bots set up with it keep playing. Any ladder started with
--public-urldoes this for pages opened at another host.
0.27.2
- The hosted ladder moves to https://arena.victris.ai (bots connect to
wss://arena.victris.ai/bot). The old address, arena.bagofassets.com, keeps working, so bots configured with it still connect.
0.27.1
- Sign in is offered everywhere on a ladder with accounts: a Sign in button (My Bots once signed in) on the title screen, the dashboard, bot and match pages, Create a Bot and
/play, and a big Create account with GitHub button at the top of Create a Bot and in its register step. Sign in goes straight to GitHub and comes back to the page it was pressed on (/account?signin&next=<path>). - At
/playa signed-in person plays under their handle (as<handle>-<4 hex>, owned by the handle, and not one of their bots); anyone else still plays anonymously, with Sign in offered. The page trades its sign-in for a one-time ticket (POST /api/account/play-ticket, good for a minute) and connects to/human?ticket=<ticket>;human_sessionnow carrieshandle.
0.27.0
- Accounts for people, signed in with GitHub through Supabase Auth. The ladder checks each sign-in's token against the project's public keys and keeps accounts in its own database (schema 4). A signed-in person picks a handle, the owner name on their bots, and through
/api/accountcreates bots (the token shown once), rotates their tokens, claims a bot registered before accounts with its token, and makes agent keys: sent asX-Owner-KeytoPOST /api/bots, an agent key registers bots for its account.GET /apireports the Supabase project and its publishable key inaccounts(null when the ladder runs without one);arena serveturns accounts on whenSUPABASE_URLandSUPABASE_PUBLISHABLE_KEYare set. /account, the account page: sign in with GitHub, pick a handle (your GitHub login is suggested), create bots and copy their tokens (shown once), replace a bot's token, make and revoke agent keys (with a line to hand your agent), and claim a bot with its token. On a ladder with accounts, the dashboard links it as My Bots, and Create a Bot's register step offers it as the easy way.
0.26.1
- Fixes the title screen's menu, which lost a key or controller press that came before the page had redrawn from the last one. 0.26.0 was never deployed: its browser tests caught this.
0.26.0
- The ladder's address opens on a title screen, like a game's main menu: the crest and title over a live match between house bots (played in the browser by the simulator and drawn by the replay viewer), with embers, fog and a short intro. Its menu offers Play Game (
/play), Create a Bot and View Leaderboard; the entry in focus shows a preview beside it (the four abilities and the controls, a sample of a bot's loop, the top five and live matches), and the arrow keys, W/S or a controller move through it. The dashboard moves to/ladder. /create-botshows people how to build a bot and enter it: a prompt to hand an AI agent, then six steps (the fight, with numbers from the ladder's rules table; registering; connecting, with a whole sample bot in JavaScript and Python; the turn; testing and training with the simulator; climbing), and links to every doc. Commands and samples name the ladder the page was loaded from.- The leaderboard lists each bot once, at its current version: the one that played a rated game last (retired versions excluded), so queuing an older label rolls it back. Earlier versions keep their ratings and records, on the bot's page and in
GET /api/bots/<name>. A new version starts from its bot's current rating with its deviation raised to at least 200, instead of 1500 ± 350; a bot's first version still starts at 1500. Database schema 3 records when each version last played a rated game, from the match records. - Python simulator:
ArenaSelfPlayEnvsteps many self-play matches in one call, both fighters yours (two environments a match).ArenaVectorEnv's opponent can be a policy of yours (called once a step with every match it plays, so a frozen network runs batched) or aScriptedOpponentwritten like a ladder bot, mixed with house bots;set_opponentschanges them between matches, for training against a pool of your past policies. - Ladder games as training data:
replay_trajectories(replay)(Python) andreplayTrajectories(JavaScript) re-run a replay through the server's match code and give back each fighter's hello, every observation exactly as it was sent and the turn the server took, and the end;download_replays(ladder, bot=, limit=)fetches a bot's recent matches with their replays. - Stable-Baselines3:
arena_sim.sb3.ArenaVecEnv(thesb3extra) makes the batched environments an SB3 vector environment, every match stepped in one call (about twice as fast to train asDummyVecEnv), with action masks for sb3-contrib'sMaskablePPO;ArenaEnv.action_masks()serves single environments. The batched environments takeautoreset_mode=AutoresetMode.SAME_STEP, which restarts a match on the step that ends it and puts its last observation ininfo["final_obs"]. - A bot may register 1000 new versions a day (was 100).
- The replay viewer and human play share the ladder's game look (one stylesheet,
packages/web/src/theme.css). The viewer fits the window: the arena in a HUD frame, a timeline across the transport bar that fills to the tick shown, and a plate per fighter in its colour with a notched health bar; it no longer has a light theme. Human play picks a bot from character-select cards, and the game has fighting-game health bars, a big End turn button and the turn's choices as tags.npm run dev:webserves the viewer from source again (its/viewproxy rule caught/viewer). - The replay viewer's arena overlay fits a phone: each fighter's name stays over its own health bar (smaller, then cut short with "…", and its version left out when there's no room), and the cooldown icons in the bottom corners shrink so the two plates never overlap, dropping their labels when too small to read.
- The dashboard's Online panel shows a bot waiting for a match as READY, in green, and one in a match as PLAYING, in blue; the Live panel and the live counts are blue instead of red.
- A bot's page keeps itself current: it checks the bot every 5 seconds and, when it has finished another match, reloads its matches, chart and records (new matches slide in). The rating chart picks its time frame (the last day, week, month or all time, which is the default) from
GET /api/bots/<name>/ratings?days=<n>, new, instead of charting the last 500 matches; over 1000 games it shows an even sample. - In the replay viewer, a ladder match's bot names (over the health bars and in the title bar) open their bots' pages.
- The ladder's pages no longer keep the CPU and GPU busy while open. The drifting embers behind the dashboard, bot and match pages made the browser redraw the whole window every frame, re-blurring each panel's backdrop; the embers now stay still, the panels drop their backdrop blur (they're nearly opaque, so it barely showed), and the live dot's pulse and the Play as Human button's glow no longer repaint on every frame. An open dashboard went from a redraw on every frame to none.
- An example training run to start from:
python -m arena_sim.examples.train_ppotrainsMaskablePPOonBasicwith a curriculum (random, thenbrawler), choosing a GPU when torch sees one. On a desktop it beatsrandomin minutes on a CPU, andbrawler(65% of fresh matches) in about half an hour on an RTX 5080.damage_tradeis a denser reward to start from (damage dealt minus damage taken each tick, then the win or loss). CI checks the script on every run and, for a release, that it learns to beatrandom.
0.25.1
- The dashboard and bot pages fit the window: on a big enough screen the page doesn't scroll, and each panel (leaderboard, recent matches, live, online; rating, versions, opponents, maps, recent matches) scrolls on its own, with its column headings kept in view. The dashboard has three columns (two on a tablet), and recent matches are a list with Watch as a primary button beside Stats. On a phone, tabs show one panel at a time. The bot page's recent matches lead with a win/loss badge, and its opponents and maps drop the Games column (W–L–D gives it).
- The ladder's pages look like a game's front end: the arena floor and the blue and red corners' light behind framed HUD panels, condensed italic type (Barlow, served with the app), angled buttons that light up on hover, gold, silver and bronze rank emblems, WIN and LOSS plates on a bot's matches, online and live counts in the top bar, and panels and new matches that slide in. Motion stops for people who ask for reduced motion.
- The ladder runs on Node 26 and runs its TypeScript with Node's own type stripping, house bots included: no tsx, and the image drops its build tools (518 MB to 363 MB; about 30% less memory with the house bots running). CI uses Node 26 and current versions of its actions.
python -m arena_sim checkworks against a hosted ladder: it names itself (arena-sim/<release>) instead of sending Python's default user agent, which Cloudflare refuses (HTTP 403).
0.25.0
- A simulator for training offline: the ladder serves its own match code as one dependency-free ES module at
/download/arena-sim.mjs(GET /apilists it undersimulator; guide at/docs/simulator).new Game({seed, opponent})plays a whole match in-process against a house bot or in self-play, about 100 to 150 games a second per core, with every reply taking the ladder's path and every message the JSON the ladder sends. The server now runs each match on the same code (packages/sim), and tests check the two agree frame for frame, house bots included. - The ladder serves the simulator for Python too:
pip install https://arena.victris.ai/download/arena_sim-<release>-py3-none-any.whl.GET /apireportssimulatoras links (javascript,script,python,docs) and addsversions.releaseandversions.rules_hash; the simulator carries the same (RELEASE), andpython -m arena_sim check <ladder>says whether a copy is current. Releases setRELEASEinpackages/sim/src/version.ts, and CI refuses a tag that doesn't match it, runs the Python package's tests, and checks the image and the live ladder serve all three downloads. - Spec: a bot may run the simulator (or its own copy of the engine) during a match, for example to search ahead; it still sees only its observations and keeps to the deadlines.
- A Python package for the simulator,
arena-sim(packages/sim-python): the same bundle run in embedded V8 through mini-racer, so no Node.js is needed.Simulatorsteps many games in one call (a call into V8 costs about 180 µs);ArenaEnvandArenaVectorEnvare Gymnasium environments against the house bots andArenaParallelEnva PettingZoo one for self-play;Rawpasses the ladder's JSON through andBasicis a reference encoder (map grid and features in, 68 discrete actions with an action mask out). About 26,000 game ticks a second per process from Python, 11,000 throughArenaVectorEnvwithBasic.npm run build:simalso buildsarena-sim.js, a plain script that sets a globalArenaSim, for engines that don't load modules. - The engine no longer uses
structuredClone(a host API missing from bare V8) to copy state; matches and replays are unchanged. - The dashboard's Play as Human link is a primary button at the right of the header.
- The house bots' decisions are in
bots/<name>/policy.ts(the simulator runs them in-process);bot.tsconnects one to the ladder withrunBot, now inbots/lib/run.ts. The random bot draws from its seeded per-match generator instead ofMath.random, so its games are reproducible (random-9).
0.24.0
- Human play (
/play) is redesigned. Clicking a bot starts the game, and Play again starts a rematch. The game waits for the player: each tick they choose a destination and optionally a weapon, then end the turn (Enter, Space, the End turn button or A; hold to skip ahead), and the tick resolves at once. The arrows, WASD, left stick or D-pad move the choice between every step and dash destination (or click one); a click aims a shot, a right-click a frostburst, E the repulsor, and the right stick aims on a controller. A step chosen while the step cools down waits for the next tick. The board uses the replay viewer's art (you blue, the bot red, raised walls, fog), with steps in green, dashes in yellow and each weapon's preview in its own colour, and fills the window from top to bottom (the page header steps aside during a game) beside a panel with health, the turn so far, cooldowns and last tick's events. Server: a human seat's turn resolves the tick when it arrives instead of being held until the deadline, the deadline is a fixed 2 minutes a tick, timeouts count as failures (ten in a row disqualify), andstart_humanno longer takestick_ms. - The ladder's match limits are 10x higher, for stress testing: 320 matches at once (was 32), 40 per owner (was 4), one match every 0.3 seconds per bot (was 3), 10000 matches per bot per hour (was 1000) and 50000 per owner per day (was 5000). Bots per owner, new versions per day and replays kept are unchanged.
- The matchmaker favours variety: two bots that just played each other wait 10 seconds before they can be paired again (they used to re-queue together and replay each other over and over), the pair score's variety penalty counts the last 10 opponents (was 5) and outweighs rating closeness, and the rating window starts at 400 points and widens by 20 a second (was 200 and 10).
0.23.1
- Replay files are written without blocking the event loop, so finishing matches don't delay other matches' ticks.
- The ladder spends about 20% less CPU per tick: line of sight is cached per map (walls never change), halving the cost of observations, and the per-tick state hash is built about twice as fast with byte-identical output, so replays and hashes are unchanged.
0.23.0
- The ladder's pages are a web app (
packages/web, which replacespackages/viewer): the dashboard, bot pages and match pages are Preact components built by Vite, typed by the server's API responses, so a page the API change breaks fails the typecheck. The server only answers JSON and serves the build, with long-lived caching for its hashed assets./playis served directly (/viewer/play.htmlredirects to it).npm run dev:webserves the pages from source against a running ladder. - API:
GET /api/bots/<name>addsonline_versionand each version's leaderboardrank; match records addhouseto each bot. - Browser tests (Playwright,
npm run test:e2e) load every page on desktop and phone against a seeded ladder and fail on any script error, failed request or missing data; CI runs them before a release can deploy. After a deploy, the read-only@smoketests run against the live ladder, and if they fail the previous build is deployed again (CI andscripts/deploy.sh).
0.22.2
- Fixes the dashboard, which showed no data in 0.22.1: its script had a syntax error from the new links to bot pages. The tests now compile every inline script on the served pages.
0.22.1
- Each bot has a page,
/bot/<name>: its versions with leaderboard rank, rating and record, a chart of each version's rating game by game (hover for the game, click to open it), its record against each opponent and on each map, and its recent matches. Bot names on the dashboard and match pages link to it (the leaderboard linked to the bot's JSON). - The leaderboard orders by rating, highest first (it ordered by rating minus twice the deviation, which put some versions below lower-rated ones), and the lobby (
GET /api/lobby, the dashboard's Online table) orders by rating too (it was in connection order).
0.22.0
- Protocol 0.3 (
hello.protocol_version): the queue and challenge changes below. - One kind of match, rated per version. Practice, challenges and tournaments are gone: a bot sends
{"type": "queue", "version": "v3"}(nomode), the matchmaker picks the opponent, and every game counts. Each version has its own rating and its own leaderboard row (GET /api/leaderboardrows carryversion), starting from 1500; a bot no longer has a rating of its own. A new label is registered the first time the bot queues with it (at most 100 a day, up from 20). Protocol:set_availability,availability,challenge,challenge_response,cancel_challengeandchallenge_updateare removed,queuelosesmode(bots that send it are refused),queuedandendlosemode. HTTP:/api/challenges*and/api/tournaments*are removed, the lobby reports each bot'sversionandstate(waiting,playing,idle). CLI:challenge,challengesandtournamentare removed; the starters dropARENA_MODE,ARENA_OPPONENT,ARENA_CHALLENGESandARENA_PRACTICE. Human play at/playstarts unrated games directly. Database schema 2 moves each bot's rating and record to the version it had ranked (so the leaderboard keeps its rows) and drops the challenge and tournament tables. A bot may play 1000 matches an hour (was 120), and there is no longer a cap on games between the same two bots (was 20 a day). - Each match has a page,
/match/<id>, with the result, a Watch replay button and the stats as a table; the dashboard's stats links and the viewer (for a ladder replay) link to it. The dashboard's Recent matches table spans the page, so no column hides behind a horizontal scroll, and phones get a narrower layout.
0.21.4
- Release tags deploy themselves: CI's
deployjob runs after the tests and image pass and waits until the hosted ladder reports the tag's commit./apiversionsincludes thecommita deployed ladder was built from, andscripts/deploy.shwaits for it too.
0.21.3
arena backupwrites a consistent copy of the ladder's database (safe while it runs, integrity-checked) to<data>/backups/and keeps the newest 14; the hosted ladder runs it nightly.
0.21.2
- Operations only, no game changes: a Docker image and Compose file for hosting (deployed with Coolify), a CI workflow (typecheck, tests, image build and smoke test), and
servetakes the operator token from$ARENA_ADMIN_TOKENso a hosted ladder can keep it as a secret.
0.21.1
- The per-match time budget is 300 s (was 120 s). It counts network time, so on a hosted ladder distant players spent much of the old budget on latency; the 1 s per-turn deadline remains the real limit.
0.21.0
Independent attack cooldowns with a retune and house bots that play combos, a ladder ready to host (public URL, keepalive pings, draining restarts, reconnecting bots, schema migrations), and agent instructions split by audience. Replays recorded before this release were made by engine 0.20.0 and can't be re-simulated by this one.
- Stopping the ladder drains it: matches in progress finish (up to
serve --drain-timeout, default 600 s) and no new ones start, then sockets close with code 1012 (service restart); a second signal stops at once./api/statusreportsdraining. - Bots survive ladder restarts: the starters and the house bots reconnect with backoff (1 s, doubling to 30 s) and queue again, resuming a match in progress, and stop only on errors reconnecting can't fix (
invalid_token,replaced, a ban…). The starters are nowstarter-16andpy-starter-16. The CLI starts bots withexecand stops the bot itself, so no bot is left running behind a killed shell. - Retuned for independent cooldowns, bringing match length back to what it was: max hp 130 (was 100), health pickups +32 (was +25), cooldowns ranged 6, frostburst 14, repulsor 12 (were 4, 10, 8).
- The house bots play combos: they take shots the enemy can't dodge (stunned, recovering from a dash, or just stepped with its dash on cooldown), shove when the 3-tile push ends in a wall slam or in their own area about to explode, and the brawler steps to the side of the enemy that puts a wall behind it. The kiter always shoves an adjacent enemy to make room. In sample-bot play the brawler wins 82%, the kiter 65%, the starter 53%.
- Each attack has its own cooldown. Firing one weapon no longer puts the others on cooldown, so weapons can be chained on consecutive ticks (one attack per turn still): a repulsor slam's 3-tick stun can now be followed by a shot that can't miss. The starters and house bots check each weapon's own cooldown, and the house bots shoot a stunned target first. Sample-bot matches run about 40–50% shorter.
- Agent instructions split by audience: the root
AGENTS.md(andCLAUDE.md, which imports it) is now for agents working on the game; the guide for agents writing bots moved todocs/AGENT_GUIDE.md, still served at/docs/agents.arena new-botwrites anAGENTS.md,CLAUDE.mdand.gitignoreinto the bot's folder, with the ladder's address filled in (--serveror$ARENA_SERVER). The ladder serves/llms.txt, an index of its docs, and lists it in/api. - Hosting:
arena serve --public-url https://…makes every link the ladder hands out (replay_url,watch_url,bot_endpoint, the dashboard's socket address) and the served docs use the public address, withwss://for the socket;--hostpicks the interface to listen on. The ladder pings every socket every 25 s and closes one that misses a pong, so idle bots survive proxies and NAT. Replays are compressed off the event loop.ARENA_SERVERis documented. - The repulsor shoves 3 tiles (was 2) and a wall slam stuns for 3 ticks (was 2), so it slams from farther from a wall and the follow-up lands.
- The standard shot has no range limit: after its one wall bounce it flies on until it hits a fighter or a wall again, so ricochets reach much further and a bot can bank shots to arrive from behind.
attacks.ranged.rangeis gone (rangeis optional for projectiles; absent means unlimited) and observed projectiles no longer carryrange. - Match stats: for every fighter, moves (and steps blocked by a fighter), dashes and tiles dashed, uses/hits/damage per weapon, ricochet bounces and hits, pickups by kind and hp healed, damage dealt and taken by source, wall slams, shoves, stuns, ticks outside the zone, refused turn parts and server-substituted idles. The engine computes them from a replay (
replayStats), so they are reproducible. They arrive inend.stats, the ladder stores them and servesGET /api/matches/<id>/stats(andstats=1on/api/matches),arena stats <replay | match id>prints them,arena runprints them after each match,check-bottotals them, and the viewer has a Match stats panel. Schema:docs/schema/match-stats.json. hitevents from a shot that had bounced off a wall carry"ricochet": true.- The
whiffevent is gone: the engine never emitted it, but the observation schema still listed it. - Docs brought in line with the engine: turn failures, rejection reasons, unlimited shot range, the repulsor's 3-tile shove,
areas[], every protocol message, and a worked example generated from a real match. - Viewer: every weapon effect (areas, casts, repulsor, bounce and hit sparks) is drawn in its owner's color; shape tells the weapons apart.
- Viewer: each fighter's cooldowns (move, dash, shot, frostburst, repulsor) are round ability icons in the arena's bottom corners and the side panel, drawn like action-game HUDs: a dark wedge unwinds clockwise as the cooldown runs, the rim charges in the ability's colour, the ticks left sit in the middle, and the icon glows (and pops) when ready. They replace the dash meter and the cooldown text chips. Human play (
/play) has the same icons as an ability bar under the board: the weapon icons are its weapon buttons, and the sweep runs on toward the turn deadline.
0.20.0
A cleanup release: no users yet, so the design is tidied rather than kept compatible.
- Terrain hazards removed for good: maps are only floor (
.) and wall (#),rules.tiles, thepitandhazardevents anddeath.causeare gone, and zone damage is its ownzone_damageevent. The nearly emptypits-21andlava-ring-21maps are deleted. - Names made consistent: the frostburst
bombis now anareaeverywhere (attack kindarea, observationareas[], eventsarea_spawnandarea_explode,danger[].source: "area",explodes_tick), and the repulsor's attack kind isburst.danger[].kindis removed becausesourcesays the same thing. - A cleaner turn message. A bot replies with
{"tick": N, "move": "NW", "attack": {"name": "ranged", "target": [9, 4]}}:moveordash(a direction, not both) andattackare all optional, and an empty turn is idle. Theaction/dir/thenfields are gone, the message type isturn(schemabot-turn.json), replay ticks recordturns, the engine takesTurnInput/validateTurn, andrejectedevents name the refusedpart(move,dash,attackorturn). Rejection reasons dropunknown_action,missing_dirandmissing_attack(the schema catches those) and addconflicting_moves. - An attack is judged entirely from the tile the movement ends on: a frostburst's range, sight and wall check, and the own-tile check, now happen in the attack phase (they were split between the start of the tick and the end). So a step can bring a target into range or take it out, and you can aim at the tile you just left.
- Tick phases renumbered 1–8 without gaps (validate, dashes, movement, pickups, attacks, zone, deaths, timers). The wire protocol is version 0.2 (the
turnmessage);hello.protocol_versionsays so. - Removed code kept only for old users: the
ladder.jsonimport, thematchIntervalMsshorthand option and the deprecatedmatchmake(). - Repo structure: the ladder's challenge lifecycle, tournament scheduling and page serving moved out of
ladder.tsandhttp.tsintochallenges.ts,tournaments.tsandpages.ts;tsconfignow fails on unused locals and parameters; the spec describes only current rules, and its future-feature section plus the ranged-combat ideas becamedocs/ROADMAP.md. - The house bots and starters are rewritten around the two phases (a movement function, then an attack function fired from where the movement ends), and the engine's step-legality helpers moved into
map.ts. - Attack
recoveryis removed (every attack had 0): there is no recovery after attacking. Dash keeps its 1 tick. The unusedknockbackfield onrangedis gone.
0.19.0
- The repulsor is no longer aimed: it hits all eight tiles around the fighter (walls excluded), so it can hit several opponents at once.
targetis optional and ignored for it, and itsattackevent reports the fighter's own tile. Therepulseevent'stilesis now the ring. Repulsor recovery is 0 (was already 0 since 0.18.0). - Observations gain
moves([{dir, tile}]) anddashes([{dir, tile, distance}]): every step and dash you could start now, from the engine's own rules. The starters, the shared bot library's dodge and the human client use them.
0.18.0
- Two-phase turns: a
move,dashoridlecan carry athenattack that fires after the movement, from the tile the fighter ends on. Parts are validated separately. Attack recovery is 0 for every attack, so there is no punish window after firing. Human play (/play) now chooses a destination first, then an attack.
0.17.0
- Terrain hazards disabled: pits, lava and spikes are ordinary floor (
tiles.lava_damageandtiles.spikes_damageare 0). The shrinking zone and repulsor wall slams are unchanged.
0.16.0
explosiveremoved and merged intofrostburst: an instant spell (range 7, 6-tick fuse, 14 damage to every tile of its 3×3 area) that also slows opponents standing in the area until it explodes (move cooldown +2). The old frostburst projectile, its splash and its lingering slow are gone.bombs[].slowadded; theimpact_burstandslowedevents removed;slow_ticks_leftnow counts down to the area's explosion.
0.15.0
- The shotgun became the repulsor: a point-blank arc that shoves the target 2 tiles, stunning on a wall slam and dropping it into pits or lava.
0.14.0
- Attacks fire the tick they are sent. Windups and the
aimaction are removed.
0.13.0
- Shield and haste pickups removed. Pads hold
healthorpower.
0.12.0
- The ricochet shot merged into the standard shot (one wall bounce).
0.11.0
- Facing,
turnandcancelremoved.
0.10.0
- Stamina and running removed.
observation.dangerand the frame-data page added.
0.9.0
- Blocking and charged shots removed.