{"id":22300052,"url":"https://github.com/pkmn/engine","last_synced_at":"2026-05-09T07:12:44.674Z","repository":{"id":111604109,"uuid":"426400802","full_name":"pkmn/engine","owner":"pkmn","description":"A minimal, complete, Pokémon battle simulation engine optimized for performance","archived":false,"fork":false,"pushed_at":"2026-05-05T23:20:05.000Z","size":6361,"stargazers_count":349,"open_issues_count":1,"forks_count":13,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-05-05T23:24:08.699Z","etag":null,"topics":["engine","game","pokemon","simulator"],"latest_commit_sha":null,"homepage":"","language":"Zig","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pkmn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"docs/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-11-09T22:05:12.000Z","updated_at":"2026-05-05T23:20:09.000Z","dependencies_parsed_at":null,"dependency_job_id":"453a8903-d658-42e6-8402-51942cbfff15","html_url":"https://github.com/pkmn/engine","commit_stats":{"total_commits":1977,"total_committers":3,"mean_commits":659.0,"dds":0.004046535154274111,"last_synced_commit":"09d1baec2b1fe3eb0d2c8b49f6ca9ace9fd33c0d"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/pkmn/engine","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pkmn%2Fengine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pkmn%2Fengine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pkmn%2Fengine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pkmn%2Fengine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pkmn","download_url":"https://codeload.github.com/pkmn/engine/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pkmn%2Fengine/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32810469,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-08T08:22:46.396Z","status":"online","status_checked_at":"2026-05-09T02:00:06.633Z","response_time":123,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["engine","game","pokemon","simulator"],"created_at":"2024-12-03T18:08:56.204Z","updated_at":"2026-05-09T07:12:44.661Z","avatar_url":"https://github.com/pkmn.png","language":"Zig","funding_links":[],"categories":["Zig"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg alt=\"pkmn/engine\" width=\"192\" height=\"192\" src=\"https://pkmn.cc/engine.svg\" /\u003e\n  \u003cbr /\u003e\n  \u003cbr /\u003e\n  \u003ca href=\"https://github.com/pkmn/engine/actions/workflows/test.yml\"\u003e\n    \u003cimg alt=\"Test Status\" src=\"https://github.com/pkmn/engine/actions/workflows/test.yml/badge.svg\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"#status\"\u003e\n    \u003cimg alt=\"WIP\" src=\"https://img.shields.io/badge/status-WIP-red.svg\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/pkmn/engine/blob/master/LICENSE\"\u003e\n    \u003cimg alt=\"License\" src=\"https://img.shields.io/badge/License-MIT-blue.svg\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003e [!WARNING]  \n\u003e **This project is under heavy development** and currently the `main` branch contains numerous breaking\n\u003e changes which may not work and which are not fully documented. Please **wait for the forthcoming\n\u003e initial v0.1 release** before depending on this project (code from the\n\u003e [`old`](https://github.com/pkmn/engine/releases/tag/old) tag can also be used to experiment with a\n\u003e more stable version of the codebase).\n\n\u003chr /\u003e\n\nA minimal, complete, Pokémon battle simulation engine optimized for performance and\n[designed](docs/DESIGN.md) for tooling, embedded systems, and [artificial\nintelligence](https://github.com/pkmn/0-ERROR) use cases. This engine aims to be a frame-accurate and\n[bug-for-bug compatible](http://www.catb.org/jargon/html/B/bug-for-bug-compatible.html)\nimplementation of both Pokémon battles as defined by the original game code and the [Pokémon\nShowdown](https://pokemonshowdown.com/)[^1] simulator which represents Pokémon battling as practically\ninterpreted online.\n\nThe pkmn engine is [**more than 1000× faster**](docs/TESTING.md#results) than the\n[patched](docs/TESTING.md#patches) [Pokémon Showdown simulator\ncode](https://github.com/smogon/pokemon-showdown) when playing out supported formats in\ncompatibility mode and is extensively [tested](docs/TESTING.md) and [documented](docs). Note,\nhowever, that the engine is **not a fully featured simulator** but is instead a low-level library\nwhich can be used as a building block for more advanced use cases.\n\n## Installation\n\nThis repository hosts both the engine code (written in [Zig](https://ziglang.org/)) and the\nreference driver code (written in [TypeScript](https://www.typescriptlang.org/)).\n\n### `libpkmn`\n\nBinaries of the engine code can be downloaded from the\n[releases](https://github.com/pkmn/engine/releases) tab on GitHub, or you can [download the source\ncode](https://github.com/pkmn/engine/archive/refs/heads/main.zip) directly and build it with the\nlatest `zig` compiler, see `zig build --help` for build options:\n\n```sh\n$ curl https://github.com/pkmn/engine/archive/refs/heads/main.zip -o engine.zip\n$ unzip engine.zip\n$ cd engine\n$ zig build --prefix /usr/local -Doptimize=ReleaseFast\n```\n\nThe Zig website has [installation instructions](https://ziglang.org/learn/getting-started/) which\nwalk through how to install Zig on each platform - the engine code should work on Zig v0.16.0,\nthough tracks Zig's master branch so this may change in the future if breaking language changes are\nintroduced. Note that **due to a [bug in the Zig\ncompiler](https://github.com/ziglang/zig/issues/17768), building a version of [Zig from\nsource](https://codeberg.org/ziglang/zig#building-from-source) after having applied a\n[patch](zig.patch) to revert [ziglang/zig#17391](https://github.com/ziglang/zig/pull/17391) is\nrecommended for performance**.\n\n`libpkmn` can be built with `-Dshowdown` to instead produce the Pokémon Showdown compatible\n`libpkmn-showdown` library. Furthermore, protocol message logging can be enabled through `-Dlog`.\nThe `libpkmn` and `libpkmn-showdown` objects available in the binary release are both compiled with\nthe `-Dlog` flag by default.\n\n### `@pkmn/engine`\n\nThe driver code can be installed from [npm](https://www.npmjs.com/package/@pkmn/engine):\n\n```sh\n$ npm install @pkmn/engine\n```\n\nThe driver depends on being able to find compiled Node/WASM addons in\n`node_modules/@pkmn/engine/build/lib` to be useful. When you install the package a [`postinstall`\nlifecycle script](https://docs.npmjs.com/cli/v8/using-npm/scripts) runs\n[`install-pkmn-engine`](src/bin/install-pkmn-engine) which checks for a compatible `zig` compiler\n(see earlier regarding minimum version) and download one to `node_module/@pkmn/engine/build/bin` if\nit can't find one, as well as looking for (and downloading, if necessary) the required Node headers\nneeded to successfully build the addons natively.\n\n**If you have configured `npm` to `--ignore-scripts` you must either run `npx install-pkmn-engine`\ndirectly or build the addons manually and place the artifacts in the expected paths.**\n\n### `pkmn`\n\nTo include `pkmn`, add it as a dependency in your project's\n[`build.zig.zon`](https://github.com/ziglang/zig/blob/master/doc/build.zig.zon.md) using [Zig's\nPackage Management\nsystem](https://ziglang.org/download/0.11.0/release-notes.html#Package-Management):\n\n```zig\n.dependencies = .{\n    .pkmn = .{\n        .url = \"https://github.com/pkmn/engine/archive/RELEASE.tar.gz\",\n    },\n},\n```\n\nReplace `RELEASE` with the tag for the [release](https://github.com/pkmn/engine/releases) you wish\nto use (e.g. `0.1.0` or `nightly`) or the specific hash of any commit. Next, run `zig build` and\ncopy the expected hash from the error message into your `build.zig.zon` alongside the `.url`:\n\n```sh\n$ zig build\nerror: dependency is missing hash field\n            .url = \"https://github.com/pkmn/engine/archive/nightly.tar.gz\",\n                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nnote: expected .hash = \"122056b93b403033cb7d9bed96a02c2eb8cc1275515976167726ada6eb4207e8ef8a\",\n```\n\nNote that this hash is **not** going to be the same as the commit hash. After adding the hash to\nyour `build.zig.zon` you will be able to import the `pkmn` package's build helpers into your\n`build.zig`:\n\n```zig\nconst std = @import(\"std\");\n\npub fn build(b: *std.Build) void {\n    ...\n    const pkmn = b.dependency(\"pkmn\", .{ .showdown = true, .log = true });\n    exe.root_module.addImport(\"pkmn\", pkmn.module(\"pkmn\"));\n    ...\n}\n```\n\nThe `pkmn` package can be configured with various options such as whether or not Pokémon Showdown\ncompatibility mode or protocol message logging should be enabled. Alternatively, you may set options\nvia a `pkmn_options` [root source file\ndeclaration](https://ziglang.org/documentation/master/#Root-Source-File). There are several\nundocumented internal options that can be tweaked as well via build or root options, though these\noptions aren't officially supported, affect correctness, and may change meaning or behavior without\nwarning. Use at your own risk.\n\n```zig\npub const pkmn_options = .{ .showdown = true, .log = true };\n```\n\n## Usage\n\nFor each Pokémon generation, the engine provides a battle structure with two functions - a function\nto `update` the battle's state based on both players' choices and a function that defines which\n`choices` are valid at that decision point (at the beginning of a battle both player's must \"pass\"\nas their first choice to switch in the first member of their party). If `-Dlog` protocol logging is\nenabled each update produces logs which can be decoded into a buffer (`LOGS_SIZE` constants are\nprovided to make it easy to allocate a buffer of the correct size). Each `update` returns a result\nto indicate either that the battle has terminated or which types of choices are available for each\nplayer.\n\nUnlike [Pokémon Showdown's\nSIM-PROTOCOL](https://github.com/smogon/pokemon-showdown/blob/master/sim/SIM-PROTOCOL.md#choice-requests)\nwhich provides a rich request object at each decision point, the pkmn engine computes the possible\nchoices on demand based on the result of the previous `update` and the battle state (`CHOICES_SIZE`\nis a good size to initialize the buffer passed to `choices`). **Attempting to update the battle with\na choice not present in the options returned by `choices` is undefined behavior and may corrupt\nstate or cause the engine to crash.**\n\nBattles may be played out from any point but to freshly initialize a battle which is yet to start\nthe turn count and active Pokémon should be zeroed out (driver code should handle this for you).\nMost driver code should also provide helpers to make initializing battle convenient - check the\nrespective documentation and examples for the bindings being used. The engine's [protocol\ndocumentation](docs/PROTOCOL.md) goes into greater detail on the specifics of updates and the\npotential logs that may result.\n\n*The snippets below are meant to merely illustrate in broad strokes how the pkmn engine can be used\n\\- the [`examples`](examples) directory contains fully commented and runnable code.*\n\n### C\n\n[`pkmn.h`](src/include/pkmn.h) exports the C API for `libpkmn`. Symbols are all prefixed with\n`pkmn_` to avoid name collisions. If `-Dlog` is enabled and logging throws an error then the error\nis encoded in the `pkmn_result` and can be checked with `pkmn_error`.\n\n```c\n#include \u003cpkmn.h\u003e\n\npkmn_battle_options options;\npkmn_gen1_battle_options_set(\u0026options, ...);\npkmn_battle battle = ...;\n\npkmn_result result;\npkmn_choice c1 = 0, c2 = 0;\nwhile (!pkmn_result_type(result = pkmn_battle_update(\u0026battle, c1, c2, \u0026options))) {\n  c1 = choose(PKMN_PLAYER_P1, pkmn_result_p1(result));\n  c2 = choose(PKMN_PLAYER_P2, pkmn_result_p2(result));\n  pkmn_gen1_battle_options_set(\u0026options, ...);\n}\nif (pkmn_error(result)) exit(1);\n```\n\n[(full code)](examples/c/example.c)\n\nThe C API doesn't export any helpers for creating or accessing the opaque battle objects - it's\ninstead intended to be used as the foundation for more ergonomic bindings in [other\nlanguages](#other) (the lack of namespaces and bit fields having an implementation-defined layout in\nC are the main contributing factors to the sparseness of what `libpkmn` chooses to expose).\n\n### JavaScript / TypeScript\n\n`@pkmn/engine` depends on the [`@pkmn/data`](https://www.npmjs.com/package/@pkmn/data) package which\nrequires a `Dex` implementation to be provided as well. The `Battle.create` function can be used to\ninitialize a `Battle` from the beginning, or `Battle.restore` can be used to re-instantiate a battle\nwhich is already in progress. If logging is enabled the output can be turned into Pokémon Showdown\nprotocol via `Log.parse`.\n\n```ts\nimport {Dex} from '@pkmn/dex';\nimport {Generations} from '@pkmn/data';\nimport {Battle, Choice} from '@pkmn/engine';\n\nconst gens = new Generations(Dex);\nconst battle = Battle.create(...);\n\nconst choose = (choices: Choice[]) =\u003e\n  choices[Math.floor(Math.random() * choices.length)];\n\nlet result: Result;\nlet c1: Choice, c2: Choice;\nwhile (!(result = battle.update(c1, c2)).type) {\n  c1 = choose(battle.choices('p1', result));\n  c2 = choose(battle.choices('p2', result));\n}\n\nconsole.log(result);\n```\n\n[(full code)](examples/js/example.ts)\n\nBy default, the `@pkmn/engine` package compiles the engine with `-Dshowdown`, though by running\n`install-pkmn-engine` directly and passing in `--options` you can override this default and build\ndifferent configurations of the extension for the driver to use. The driver can support\nconfigurations both with and without Pokémon Showdown compatibility simultaneously if present. On\nupdate, the post-install script attempts to rebuild whichever extensions it finds with the same\nconfiguration parameters that were originally used meaning updating to the newest version of the\nlibrary should be seamless.\n\nDespite relying on the native engine code, the `@pkmn/engine` code is designed to also work in\nbrowsers which support [WebAssembly](https://webassembly.org/). Running `npm run start:web` from the\n[`examples`](examples/js) directory starts a server that can be used to demonstrate the engine\nrunning in the browser.\n\n### Zig\n\nThe `pkmn` Zig package exposes helper methods to simplify state instantiation and any `Writer` can\nbe used when logging is enabled to allow for easily printing e.g. to standard out or a buffer.\n\n```zig\nconst std = @import(\"std\");\nconst pkmn = @import(\"pkmn\");\n\nvar prng: std.Random.DefaultPrng = .init(seed);\nvar random = prng.random();\nvar choices: [pkmn.CHOICES_SIZE]pkmn.Choice = undefined;\n\nvar battle = ...\nvar options = pkmn.battle.options(...);\n\nvar c1: pkmn.Choice = .{};\nvar c2: pkmn.Choice = .{};\n\nvar result = try battle.update(c1, c2, \u0026options);\nwhile (result.type == .None) : (result = try battle.update(c1, c2, \u0026options)) {\n    c1 = choices[random.uintLessThan(u8, battle.choices(.P1, result.p1, \u0026choices))];\n    c2 = choices[random.uintLessThan(u8, battle.choices(.P2, result.p2, \u0026choices))];\n}\n\nstd.debug.print(\"{}\\n\", .{result.type});\n```\n\n[(full code)](examples/zig/example.zig)\n\nThe Zig package also supports some APIs which are difficult to expose elsewhere such as the\n`FixedRNG` which allows you to fully specify the exact RNG frames (which can be useful for ensuring\ncertain outcomes/effects always occur) for a battle, though doing so changes the size of the\n`Battle` object.\n\n### Other\n\nDevelopers who wish to use the engine in other languages should find writing bindings against\n[`libpkmn`](#libpkmn) relatively straightforward based on the existing documentation, though to\nsimplify the process even further [`src/data`](src/data) contains JSON dumps of all of the Pokémon\ndata, structure sizes and offsets, and protocol information used by the reference driver code. The\nfollowing is a list of known `libpkmn` bindings written by developers outside of the [pkmn\norganization](https://github.com/pkmn) that may be helpful (though note that these projects may not\nnecessarily be up-to-date/complete/correct - inclusion in this list doesn't imply endorsement):\n\n| Language   | License   | URL                                  |\n| ---------- | --------- | ------------------------------------ |\n| **C++**    | `BSL-1.0` | https://github.com/pasyg/wrapsire    |\n| **Python** | `MIT`     | https://github.com/AnnikaCodes/PyKMN |\n\n\n#### `pkmn-debug`\n\nThe [`@pkmn/engine`](#pkmnengine) package ships with a `pkmn-debug` tool which exists to decode the\nbinary data structures and protocols used by the engine and to output a [standalone\nwebpage](https://pkmn.cc/debug.html) that can be used for debugging. To use this tool in a folder\nthat has the `@pkmn/engine` package installed locally you can use `npx pkmn-debug`, though you may\nalso wish to install the package globally to be able to use this tool anywhere without\n[`npx`](https://docs.npmjs.com/cli/v7/commands/npx):\n\n```sh\n$ npm install --global @pkmn/engine\n```\n\nBy default, `pkmn-debug` expects to read [binary debug protocol](docs/PROTOCOL.md#debugging) from\n[standard input](https://en.wikipedia.org/wiki/Standard_streams) and output HTML to standard output:\n\n```sh\n$ \u003ccmd\u003e | pkmn-debug \u003e index.html\n```\n\nAlternatively, if a single filename argument is passed to the `pkmn-debug` it reads from that\ninstead:\n\n```sh\n$ pkmn-debug \u003cfile\u003e \u003e index.html\n```\n\nFinally, `pkmn-debug` also supports a `--json` flag which causes the decoded data to be dumped as\nJSON instead of HTML:\n\n```sh\n$ pkmn-debug --json \u003cfile\u003e \u003e index.json\n```\n\n## Status\n\nThe engine is currently expected to be developed over multiple stages:\n\n| Stage   | Deliverables                                    |\n| ------- | ----------------------------------------------- |\n| **0**   | documentation, integration, benchmark, protocol |\n| **1**   | RBY \u0026 GSC                                       |\n| **2**   | ADV \u0026 DPP                                       |\n| ***3*** | *modern generations*                            |\n\nCurrently, most of the foundational work from stage 0 is done:\n\n- [benchmark and integration testing](src/test) infrastructure\n- [documentation](docs) about design, research, methodology, etc\n- definition and implementation of the [protocol](docs/PROTOCOL.md) that's used by the engine\n\n**Stage 1 is currently in progress** and involves the implementation of the actual Generation I \u0026 II\nbattle engines, followed by Generation III \u0026 IV in stage 2. The implementation of further Pokémon\ngenerations is in scope for the project but shouldn't be considered part of the immediate roadmap\n(i.e. exploring the options for broadening support for old generation APIs is given higher priority\nthan implementing more modern generations). Furthermore, implementation of modern generations is\nsoft-blocked on the [availability of high quality\ndecompilations](https://github.com/orgs/pret/repositories) of the original games in question.\n\nCertain features will always be deemed **out of scope**:\n\n- team/set validation or custom rule (\"format\") enforcement\n- first-class support for \"mods\" to core Pokémon data and mechanics\n- [battle variants](https://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_battle#Battle_variants)\n  other than single (full) or double battles\n- code for exposing the engine to users (input validation, game socket server, etc)\n\n## License\n\nThe pkmn engine is distributed under the terms of the [MIT License](LICENSE).\n\n[^1]: In the case of Pokémon Showdown, only bugs which stem from a misimplementation of specific\n  effects are reproduced in the engine, bugs which are the result of a misunderstanding of the\n  fundamental mechanics of Pokémon or which simply arise due to specific Pokémon Showdown\n  implementation details that aren't replicable without making the same (incorrect) architectural\n  choices aren't. Furthermore, the \"Pokémon Showdown\" code referenced by this project includes\n  several [patches](docs/TESTING.md#patches) to improve accuracy and smooth over some of the more\n  egregious implementation issues. In practical terms, the vast majority of games played out in the\n  pkmn engine's compatibility mode and on this patched Pokémon Showdown simulator are the same,\n  it's only in a well defined and documented set of circumstances where the two implementations\n  diverge.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpkmn%2Fengine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpkmn%2Fengine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpkmn%2Fengine/lists"}