{"_id":"@caputchin/preset-phaser","name":"@caputchin/preset-phaser","dist-tags":{"latest":"0.2.0"},"versions":{"0.2.0":{"name":"@caputchin/preset-phaser","version":"0.2.0","description":"Run a FULL headless Phaser 4 game (Arcade physics included) as a Caputchin deterministic-replay sim. The engine itself is the server run: the @caputchin/determinism kit makes it deterministic (transcendental Math swap + headless DOM boot), plus a seeded R","keywords":["caputchin","replay","phaser","deterministic","captcha","headless"],"homepage":"https://github.com/Caputchin/caputchin-sdk#readme","repository":{"type":"git","url":"git+https://github.com/Caputchin/caputchin-sdk.git"},"bugs":{"url":"https://github.com/Caputchin/caputchin-sdk/issues"},"license":"Apache-2.0","type":"module","publishConfig":{"access":"public"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./install":{"types":"./dist/install.d.ts","import":"./dist/install.js","require":"./dist/install.cjs"},"./live":{"types":"./dist/live.d.ts","import":"./dist/live.js","require":"./dist/live.cjs"},"./build":{"types":"./dist/build.d.ts","import":"./dist/build.js","require":"./dist/build.cjs"}},"sideEffects":["./dist/install.js","./dist/install.cjs","./dist/live.js","./dist/live.cjs"],"peerDependencies":{"phaser":"^4.1.0"},"dependencies":{"@caputchin/determinism":"0.2.0","@caputchin/replay-contract":"0.3.0"},"devDependencies":{"@types/node":"^22.0.0","phaser":"^4.1.0","tsup":"^8.0.0","typescript":"^5.4.0","typedoc":"^0.28.19","typedoc-plugin-markdown":"^4.11.0","vitest":"^2.0.0","@vitest/coverage-v8":"^2.0.0"},"scripts":{"build":"tsup","dev":"tsup --watch","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest","coverage":"vitest run --coverage","docs":"typedoc && node ../../scripts/normalize-docs.mjs docs"},"_id":"@caputchin/preset-phaser@0.2.0","_integrity":"sha512-xtonxCoCSu4mIoQYmeVX1kz018hkyWjZ2v5g5qT+n9nRLFKn3++DYqOVewVaLUGC/ol20FQxRTKBZKReWaycPg==","_resolved":"/tmp/2d0595b6dbe06d948a4e8c4f813bb042/caputchin-preset-phaser-0.2.0.tgz","_from":"file:caputchin-preset-phaser-0.2.0.tgz","_nodeVersion":"24.16.0","_npmVersion":"11.13.0","dist":{"integrity":"sha512-xtonxCoCSu4mIoQYmeVX1kz018hkyWjZ2v5g5qT+n9nRLFKn3++DYqOVewVaLUGC/ol20FQxRTKBZKReWaycPg==","shasum":"d91ee268a36d4b1c190b4fd33a8b1c2a8ae3666a","tarball":"https://registry.npmjs.org/@caputchin/preset-phaser/-/preset-phaser-0.2.0.tgz","fileCount":19,"unpackedSize":41276,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHaDu7mlmZmhQTzxzbrJDQq9Kz70Bj3Fe1aJK24eWsU5AiBhxaWu14E+Xp2QvsGXI9kzkfG6eTFs2exVycJfCpA8rg=="}]},"_npmUser":{"name":"caputchiner","email":"info@caputchin.com"},"directories":{},"maintainers":[{"name":"caputchiner","email":"info@caputchin.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/preset-phaser_0.2.0_1780536364096_0.9385579284689585"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-04T01:26:03.946Z","0.2.0":"2026-06-04T01:26:04.232Z","modified":"2026-06-04T01:26:04.509Z"},"maintainers":[{"name":"caputchiner","email":"info@caputchin.com"}],"description":"Run a FULL headless Phaser 4 game (Arcade physics included) as a Caputchin deterministic-replay sim. The engine itself is the server run: the @caputchin/determinism kit makes it deterministic (transcendental Math swap + headless DOM boot), plus a seeded R","homepage":"https://github.com/Caputchin/caputchin-sdk#readme","keywords":["caputchin","replay","phaser","deterministic","captcha","headless"],"repository":{"type":"git","url":"git+https://github.com/Caputchin/caputchin-sdk.git"},"bugs":{"url":"https://github.com/Caputchin/caputchin-sdk/issues"},"license":"Apache-2.0","readme":"# @caputchin/preset-phaser\n\nRun a headless [Phaser 4](https://phaser.io) game as a Caputchin deterministic-replay sim. Phaser itself is the server `run` (the engine is the sim, not a hand-rolled stand-in): the same scene logic renders in the player's browser and re-executes on the server isolate over the recorded trace.\n\nThis preset depends on no shared replay kit. Phaser boots headless via its own `headlessStep`, gameplay randomness comes from `Phaser.Math.RandomDataGenerator` seeded from the platform seed, and a small boot shim supplies the deterministic stubs Phaser needs inside the sealed isolate (no DOM, frozen clock, codegen disabled).\n\n## Install\n\n```sh\npnpm add @caputchin/preset-phaser @caputchin/game-sdk phaser\n```\n\n`phaser` is a peer dependency: you pin the Phaser version your game targets (`^4.1`).\n\n## The one rule: import the shim first in your run entry\n\nPhaser reads `window` and `Image` while its module evaluates, not only at `new Phaser.Game(...)`. So the headless shim must be installed before phaser is imported. In your replay entry, make `@caputchin/preset-phaser/install` the **first** import, before anything that pulls phaser:\n\n```ts\n// src/run.ts (the headless replay entry)\nimport '@caputchin/preset-phaser/install'; // MUST be first\nimport { makePhaserRun } from '@caputchin/preset-phaser';\nimport { gameSim, decode } from './sim.js'; // imports phaser\n\nexport const run = makePhaserRun({\n  width: 640,\n  height: 400,\n  maxTicks: 60 * 60, // hard ceiling (~60s at 60Hz)\n  decode,\n  sim: gameSim, // ({ seed, config, currentTick, currentAction, rng }) => hooks\n});\n```\n\n`makePhaserRun` returns a conforming `run(seed, config, trace) => Verdict`. Do not import `/install` in your live (browser) build: the real DOM is present there.\n\n## Sharing one scene across live and replay\n\nWrite the sim hooks (`create` / `update` / `result` / optional `isOver`) once and use them in both entries. The live entry records the player's per-tick action into the trace and renders with Phaser as usual; the replay entry feeds the recorded actions back through the same hooks. Seed all gameplay randomness with `seedFromPlatform(seed)` so both sides draw the identical sequence.\n\n```ts\n// src/index.ts (the live entry)\nimport { register } from '@caputchin/game-sdk';\nimport { seedFromPlatform } from '@caputchin/preset-phaser';\n// ... live Phaser game, render + input capture, bridge.pass({ trace }) on win\n```\n\n## Build\n\n```ts\n// tsup.config.ts\nimport { defineConfig } from 'tsup';\nimport { definePhaserBuild } from '@caputchin/preset-phaser/build';\n\nexport default defineConfig(definePhaserBuild({ gameId: 'my-game' }));\n```\n\nThis emits a minified IIFE live bundle (`dist/my-game.js`, phaser and assets inlined for the iframe CSP) and a minified ESM headless bundle (`dist/run.js`) for the replay isolate.\n\n## Determinism\n\nThe sim must be reproducible bit-for-bit across the browser and the server isolate. Keep gameplay math integer or fixed-point, avoid native trig (`Math.sin` and friends diverge across CPUs; reflect by flipping velocity components instead), and take all randomness from `seedFromPlatform`. The shim freezes the clock and seeds Phaser's internal `Math.random`, matching the isolate. Verify before publish with `caputchin-selfcheck dist/run.js`.\n\n## API\n\n| Export | Purpose |\n|---|---|\n| `@caputchin/preset-phaser/install` | side-effect import that installs the headless shim at module load |\n| `makePhaserRun(opts)` | build the conforming `run` from your sim hooks |\n| `seedFromPlatform(seed)` | a `Phaser.Math.RandomDataGenerator` seeded from the platform seed |\n| `bootHeadlessPhaser(config)` | boot a `Phaser.HEADLESS` game and resolve when ready (advanced) |\n| `applyPhaserShim(seed?)` | install the shim manually (advanced) |\n| `@caputchin/preset-phaser/build` `definePhaserBuild(opts)` | the dual live + headless tsup config |\n","readmeFilename":"README.md","_rev":"1-6cf0112113d6e60971bb57710fe5b050"}