{"_id":"@alife-sdk/phaser","_rev":"7-e3d24bea062b40071087a4a135a63358","name":"@alife-sdk/phaser","dist-tags":{"latest":"0.5.0"},"versions":{"0.1.0":{"name":"@alife-sdk/phaser","version":"0.1.0","keywords":["alife","phaser","game-ai","simulation","npc","adapter"],"author":{"name":"Eugene Rusakov"},"license":"MIT","_id":"@alife-sdk/phaser@0.1.0","maintainers":[{"name":"eurusik","email":"john.rusakov@gmail.com"}],"homepage":"https://github.com/eurusik/alife-sdk#readme","bugs":{"url":"https://github.com/eurusik/alife-sdk/issues"},"dist":{"shasum":"4cd1bf0646037ddfd3e21ad21557587d0eb154d3","tarball":"https://registry.npmjs.org/@alife-sdk/phaser/-/phaser-0.1.0.tgz","fileCount":67,"integrity":"sha512-U0028luYiXQK57/VW4UMslZ/aNDSBZtVIRO3w4Kba2B4aeD5o++zVwxBXsnp9rPMt3IgWeygRrg3TcWlsXI0rQ==","signatures":[{"sig":"MEUCIQC6X1+aQBBzVVk0W82DIDxyPgh9wCGBAQXhlcW9aXluswIgOUHRxo4fAe0xMYe92gynd9dNagVURD6o3ShycvKwTgw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":119213},"main":"dist/index.js","type":"module","_from":"file:alife-sdk-phaser-0.1.0.tgz","types":"dist/index.d.ts","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./scene":{"types":"./dist/scene/index.d.ts","import":"./dist/scene/index.js"},"./types":{"types":"./dist/types/index.d.ts","import":"./dist/types/index.js"},"./online":{"types":"./dist/online/index.d.ts","import":"./dist/online/index.js"},"./adapters":{"types":"./dist/adapters/index.d.ts","import":"./dist/adapters/index.js"}},"scripts":{"dev":"tsc --watch","test":"vitest run","build":"tsc"},"_npmUser":{"name":"eurusik","email":"john.rusakov@gmail.com"},"_resolved":"/private/var/folders/jv/cpf6x8mj1g11mppj8rpdhlmr0000gn/T/0b53455cdbcf87db670ddfd32462b098/alife-sdk-phaser-0.1.0.tgz","_integrity":"sha512-U0028luYiXQK57/VW4UMslZ/aNDSBZtVIRO3w4Kba2B4aeD5o++zVwxBXsnp9rPMt3IgWeygRrg3TcWlsXI0rQ==","repository":{"url":"git+https://github.com/eurusik/alife-sdk.git","type":"git","directory":"packages/alife-phaser"},"_npmVersion":"10.8.1","description":"Phaser 3 adapter for @alife-sdk — entity adapters, online/offline manager, NPC AI bridge","directories":{},"sideEffects":false,"_nodeVersion":"20.16.0","dependencies":{"@alife-sdk/ai":"0.1.0","@alife-sdk/core":"0.1.0","@alife-sdk/social":"0.1.0","@alife-sdk/simulation":"0.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.0.18","typescript":"^5.9.3"},"peerDependencies":{"phaser":"^3.60.0"},"peerDependenciesMeta":{"phaser":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/phaser_0.1.0_1772739946429_0.9524463794483267","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@alife-sdk/phaser","version":"0.1.1","keywords":["alife","phaser","game-ai","simulation","npc","adapter"],"author":{"name":"Eugene Rusakov"},"license":"MIT","_id":"@alife-sdk/phaser@0.1.1","maintainers":[{"name":"eurusik","email":"john.rusakov@gmail.com"}],"homepage":"https://github.com/eurusik/alife-sdk#readme","bugs":{"url":"https://github.com/eurusik/alife-sdk/issues"},"dist":{"shasum":"b18ca01065ec34a9f1f970526db7af8379dbc5ee","tarball":"https://registry.npmjs.org/@alife-sdk/phaser/-/phaser-0.1.1.tgz","fileCount":67,"integrity":"sha512-MISkaTMFcWGUzh/IzquSolYxF8O/0NBVkU7i10ZyFYGWfs1XdStbEZ24z0pn6IfIkSAaX426Vbac+8GrxTCNyw==","signatures":[{"sig":"MEQCIDxWg0s3R1Zca0U/0NNNEhK651VK+MZk1ghu7LUzbDcZAiAYUr7zjm8+DUqlVNr4DhAQK7tj2YmHRYcsmssWVwmDsg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":122657},"main":"dist/index.js","type":"module","_from":"file:alife-sdk-phaser-0.1.1.tgz","types":"dist/index.d.ts","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./scene":{"types":"./dist/scene/index.d.ts","import":"./dist/scene/index.js"},"./types":{"types":"./dist/types/index.d.ts","import":"./dist/types/index.js"},"./online":{"types":"./dist/online/index.d.ts","import":"./dist/online/index.js"},"./adapters":{"types":"./dist/adapters/index.d.ts","import":"./dist/adapters/index.js"}},"scripts":{"dev":"tsc --watch","test":"vitest run","build":"tsc"},"_npmUser":{"name":"eurusik","email":"john.rusakov@gmail.com"},"_resolved":"/tmp/4d2add5baa6407d28344bce0197019e3/alife-sdk-phaser-0.1.1.tgz","_integrity":"sha512-MISkaTMFcWGUzh/IzquSolYxF8O/0NBVkU7i10ZyFYGWfs1XdStbEZ24z0pn6IfIkSAaX426Vbac+8GrxTCNyw==","repository":{"url":"git+https://github.com/eurusik/alife-sdk.git","type":"git","directory":"packages/alife-phaser"},"_npmVersion":"10.8.2","description":"Phaser 3 adapter for @alife-sdk — entity adapters, online/offline manager, NPC AI bridge","directories":{},"sideEffects":false,"_nodeVersion":"20.20.0","dependencies":{"@alife-sdk/ai":"0.1.1","@alife-sdk/core":"0.1.1","@alife-sdk/social":"0.1.1","@alife-sdk/simulation":"0.1.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.0.18","typescript":"^5.9.3"},"peerDependencies":{"phaser":"^3.60.0"},"peerDependenciesMeta":{"phaser":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/phaser_0.1.1_1772742735513_0.029323880195580854","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@alife-sdk/phaser","version":"0.2.0","keywords":["alife","phaser","game-ai","simulation","npc","adapter"],"author":{"name":"Eugene Rusakov"},"license":"MIT","_id":"@alife-sdk/phaser@0.2.0","maintainers":[{"name":"eurusik","email":"john.rusakov@gmail.com"}],"homepage":"https://github.com/eurusik/alife-sdk#readme","bugs":{"url":"https://github.com/eurusik/alife-sdk/issues"},"dist":{"shasum":"e7cbdf8aeef03204d09ce0995dd57710e347a427","tarball":"https://registry.npmjs.org/@alife-sdk/phaser/-/phaser-0.2.0.tgz","fileCount":67,"integrity":"sha512-4mUmS5vtR8uWWmrQCxwquePxrLljBDEatdQxCem3mp9aGxaftl+Ru0J092GNTkwmMJj+jwB8VVBVFqqaM2I2yQ==","signatures":[{"sig":"MEQCIAOdw1rOUshUKRkfe3F/LjmTb/05KCCdmuQI0+6nRtTrAiB/cvmhNGOlqPRsFEzcrRxg8M22y1lql5YhmQ4PC27tZw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":122657},"main":"dist/index.js","type":"module","_from":"file:alife-sdk-phaser-0.2.0.tgz","types":"dist/index.d.ts","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./scene":{"types":"./dist/scene/index.d.ts","import":"./dist/scene/index.js"},"./types":{"types":"./dist/types/index.d.ts","import":"./dist/types/index.js"},"./online":{"types":"./dist/online/index.d.ts","import":"./dist/online/index.js"},"./adapters":{"types":"./dist/adapters/index.d.ts","import":"./dist/adapters/index.js"}},"scripts":{"dev":"tsc --watch","test":"vitest run","build":"tsc"},"_npmUser":{"name":"eurusik","email":"john.rusakov@gmail.com"},"_resolved":"/tmp/9eba6a977df9f6d941119d8fcf64db6b/alife-sdk-phaser-0.2.0.tgz","_integrity":"sha512-4mUmS5vtR8uWWmrQCxwquePxrLljBDEatdQxCem3mp9aGxaftl+Ru0J092GNTkwmMJj+jwB8VVBVFqqaM2I2yQ==","repository":{"url":"git+https://github.com/eurusik/alife-sdk.git","type":"git","directory":"packages/alife-phaser"},"_npmVersion":"10.8.2","description":"Phaser 3 adapter for @alife-sdk — entity adapters, online/offline manager, NPC AI bridge","directories":{},"sideEffects":false,"_nodeVersion":"20.20.0","dependencies":{"@alife-sdk/ai":"0.1.1","@alife-sdk/core":"0.1.1","@alife-sdk/social":"0.1.1","@alife-sdk/simulation":"0.2.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.0.18","typescript":"^5.9.3"},"peerDependencies":{"phaser":"^3.60.0"},"peerDependenciesMeta":{"phaser":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/phaser_0.2.0_1772774311328_0.8170750987290711","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@alife-sdk/phaser","version":"0.3.0","keywords":["alife","phaser","game-ai","simulation","npc","adapter"],"author":{"name":"Eugene Rusakov"},"license":"MIT","_id":"@alife-sdk/phaser@0.3.0","maintainers":[{"name":"eurusik","email":"john.rusakov@gmail.com"}],"homepage":"https://github.com/eurusik/alife-sdk#readme","bugs":{"url":"https://github.com/eurusik/alife-sdk/issues"},"dist":{"shasum":"fcdc638702282e6de7fc598526549e5c7c173e3b","tarball":"https://registry.npmjs.org/@alife-sdk/phaser/-/phaser-0.3.0.tgz","fileCount":67,"integrity":"sha512-XWb+UB6knl9yh/cUr3g3kjtG1xw7x/1EH1IZRfKi3tmfZCz4kFDEvzxP3buRtkHuGpoV8T9wo53StY27DKXlEg==","signatures":[{"sig":"MEUCICw4oQHNmxoCdPS9O7fpwWnkxjKGEsz0KbbM/FC0XhSnAiEAhKg4uXxQp7elPMCDcJfIq9+G9PD3H3ImcVjSto9nDis=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":122657},"main":"dist/index.js","type":"module","_from":"file:alife-sdk-phaser-0.3.0.tgz","types":"dist/index.d.ts","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./scene":{"types":"./dist/scene/index.d.ts","import":"./dist/scene/index.js"},"./types":{"types":"./dist/types/index.d.ts","import":"./dist/types/index.js"},"./online":{"types":"./dist/online/index.d.ts","import":"./dist/online/index.js"},"./adapters":{"types":"./dist/adapters/index.d.ts","import":"./dist/adapters/index.js"}},"scripts":{"dev":"tsc --watch","test":"vitest run","build":"tsc"},"_npmUser":{"name":"eurusik","email":"john.rusakov@gmail.com"},"_resolved":"/tmp/c92e41a05b0c8e8c9e26d0c319445f2c/alife-sdk-phaser-0.3.0.tgz","_integrity":"sha512-XWb+UB6knl9yh/cUr3g3kjtG1xw7x/1EH1IZRfKi3tmfZCz4kFDEvzxP3buRtkHuGpoV8T9wo53StY27DKXlEg==","repository":{"url":"git+https://github.com/eurusik/alife-sdk.git","type":"git","directory":"packages/alife-phaser"},"_npmVersion":"10.8.2","description":"Phaser 3 adapter for @alife-sdk — entity adapters, online/offline manager, NPC AI bridge","directories":{},"sideEffects":false,"_nodeVersion":"20.20.0","dependencies":{"@alife-sdk/ai":"0.3.0","@alife-sdk/core":"0.3.0","@alife-sdk/social":"0.3.0","@alife-sdk/simulation":"0.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.0.18","typescript":"^5.9.3"},"peerDependencies":{"phaser":"^3.60.0"},"peerDependenciesMeta":{"phaser":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/phaser_0.3.0_1772789682721_0.5866249893552311","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@alife-sdk/phaser","version":"0.4.0","keywords":["alife","phaser","game-ai","simulation","npc","adapter"],"author":{"name":"Eugene Rusakov"},"license":"MIT","_id":"@alife-sdk/phaser@0.4.0","maintainers":[{"name":"eurusik","email":"john.rusakov@gmail.com"}],"homepage":"https://github.com/eurusik/alife-sdk#readme","bugs":{"url":"https://github.com/eurusik/alife-sdk/issues"},"dist":{"shasum":"a0de31885413d18a540e91b19a2b6bc80a4bcc79","tarball":"https://registry.npmjs.org/@alife-sdk/phaser/-/phaser-0.4.0.tgz","fileCount":67,"integrity":"sha512-CUACy/c/fkqy+GWmLyivAh2+7T951By2vnCdgFznfy+aidQ+XD8O48p7FT8CWk+tL5D5ySu6YzQIdZEAL1gcSw==","signatures":[{"sig":"MEQCIGttSG1cdJfUfPcI7YjQVtzvJlYGi2i1s1rzlea9TovtAiBcxeY0zsW1UDElDcZAn5hSD1wNZA6iJlMGpDgpqKpqPg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":122657},"main":"dist/index.js","type":"module","_from":"file:alife-sdk-phaser-0.4.0.tgz","types":"dist/index.d.ts","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./scene":{"types":"./dist/scene/index.d.ts","import":"./dist/scene/index.js"},"./types":{"types":"./dist/types/index.d.ts","import":"./dist/types/index.js"},"./online":{"types":"./dist/online/index.d.ts","import":"./dist/online/index.js"},"./adapters":{"types":"./dist/adapters/index.d.ts","import":"./dist/adapters/index.js"}},"scripts":{"dev":"tsc --watch","test":"vitest run","build":"tsc"},"_npmUser":{"name":"eurusik","email":"john.rusakov@gmail.com"},"_resolved":"/tmp/49cde7bcd510b805f6cb6d6ce1246042/alife-sdk-phaser-0.4.0.tgz","_integrity":"sha512-CUACy/c/fkqy+GWmLyivAh2+7T951By2vnCdgFznfy+aidQ+XD8O48p7FT8CWk+tL5D5ySu6YzQIdZEAL1gcSw==","repository":{"url":"git+https://github.com/eurusik/alife-sdk.git","type":"git","directory":"packages/alife-phaser"},"_npmVersion":"10.8.2","description":"Phaser 3 adapter for @alife-sdk — entity adapters, online/offline manager, NPC AI bridge","directories":{},"sideEffects":false,"_nodeVersion":"20.20.0","dependencies":{"@alife-sdk/ai":"0.4.0","@alife-sdk/core":"0.4.0","@alife-sdk/social":"0.4.0","@alife-sdk/simulation":"0.4.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.0.18","typescript":"^5.9.3"},"peerDependencies":{"phaser":"^3.60.0"},"peerDependenciesMeta":{"phaser":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/phaser_0.4.0_1772823546372_0.8101872133367958","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"@alife-sdk/phaser","version":"0.4.1","keywords":["alife","phaser","game-ai","simulation","npc","adapter"],"author":{"name":"Eugene Rusakov"},"license":"MIT","_id":"@alife-sdk/phaser@0.4.1","maintainers":[{"name":"eurusik","email":"john.rusakov@gmail.com"}],"homepage":"https://github.com/eurusik/alife-sdk#readme","bugs":{"url":"https://github.com/eurusik/alife-sdk/issues"},"dist":{"shasum":"d876ce0dbc7b9de10683940523b16778e0a8b773","tarball":"https://registry.npmjs.org/@alife-sdk/phaser/-/phaser-0.4.1.tgz","fileCount":67,"integrity":"sha512-vBjORzX+UGgYW74H9qpwqFH/FkjgcPF2gISVo6oHxOdo475oty54fXVqzpdUWMeIfKq2oygo5uZL5vrXAc5ZXw==","signatures":[{"sig":"MEUCIFt/By8pRPQVt1ryNCsqbw3ochBnHoAxA76JzS9A4KYyAiEA2IJIvqK0F29jidhZYD/mCJKSyzopHdD1NlKH9Px702o=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":122689},"main":"dist/index.js","type":"module","_from":"file:alife-sdk-phaser-0.4.1.tgz","types":"dist/index.d.ts","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./scene":{"types":"./dist/scene/index.d.ts","import":"./dist/scene/index.js"},"./types":{"types":"./dist/types/index.d.ts","import":"./dist/types/index.js"},"./online":{"types":"./dist/online/index.d.ts","import":"./dist/online/index.js"},"./adapters":{"types":"./dist/adapters/index.d.ts","import":"./dist/adapters/index.js"}},"scripts":{"dev":"tsc --watch","test":"vitest run","build":"tsc"},"_npmUser":{"name":"eurusik","email":"john.rusakov@gmail.com"},"_resolved":"/tmp/f539c22fd675294f2e91936b52c4e8e6/alife-sdk-phaser-0.4.1.tgz","_integrity":"sha512-vBjORzX+UGgYW74H9qpwqFH/FkjgcPF2gISVo6oHxOdo475oty54fXVqzpdUWMeIfKq2oygo5uZL5vrXAc5ZXw==","repository":{"url":"git+https://github.com/eurusik/alife-sdk.git","type":"git","directory":"packages/alife-phaser"},"_npmVersion":"10.8.2","description":"Phaser 3 adapter for @alife-sdk — entity adapters, online/offline manager, NPC AI bridge","directories":{},"sideEffects":false,"_nodeVersion":"20.20.1","dependencies":{"@alife-sdk/ai":"0.4.1","@alife-sdk/core":"0.4.1","@alife-sdk/social":"0.4.1","@alife-sdk/simulation":"0.4.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.0.18","typescript":"^5.9.3"},"peerDependencies":{"phaser":"^3.60.0"},"peerDependenciesMeta":{"phaser":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/phaser_0.4.1_1773837144421_0.5012416767523893","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@alife-sdk/phaser","version":"0.5.0","description":"Phaser 3 adapter for @alife-sdk — entity adapters, online/offline manager, NPC AI bridge","type":"module","sideEffects":false,"main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./types":{"types":"./dist/types/index.d.ts","import":"./dist/types/index.js"},"./adapters":{"types":"./dist/adapters/index.d.ts","import":"./dist/adapters/index.js"},"./online":{"types":"./dist/online/index.d.ts","import":"./dist/online/index.js"},"./scene":{"types":"./dist/scene/index.d.ts","import":"./dist/scene/index.js"}},"keywords":["alife","phaser","game-ai","simulation","npc","adapter"],"license":"MIT","author":{"name":"Eugene Rusakov"},"repository":{"type":"git","url":"git+https://github.com/eurusik/alife-sdk.git","directory":"packages/alife-phaser"},"homepage":"https://github.com/eurusik/alife-sdk#readme","bugs":{"url":"https://github.com/eurusik/alife-sdk/issues"},"engines":{"node":">=20.0.0"},"publishConfig":{"access":"public"},"peerDependencies":{"phaser":"^3.60.0"},"dependencies":{"@alife-sdk/core":"0.4.1","@alife-sdk/ai":"0.5.0","@alife-sdk/simulation":"0.4.1","@alife-sdk/social":"0.4.1"},"devDependencies":{"typescript":"^5.9.3","vitest":"^4.0.18"},"peerDependenciesMeta":{"phaser":{"optional":true}},"scripts":{"build":"tsc","dev":"tsc --watch","test":"vitest run"},"_id":"@alife-sdk/phaser@0.5.0","_integrity":"sha512-ZWrGnv2znax3gUFzf5bxBRDcSri+BzcXEUP1sewS/RovtyJeJ3TvUBPG9Y4mBcI//ZjRtiJuYBF6hcmvdLunXA==","_resolved":"/tmp/14823e094817467f12390c72fca32332/alife-sdk-phaser-0.5.0.tgz","_from":"file:alife-sdk-phaser-0.5.0.tgz","_nodeVersion":"20.20.1","_npmVersion":"10.8.2","dist":{"integrity":"sha512-ZWrGnv2znax3gUFzf5bxBRDcSri+BzcXEUP1sewS/RovtyJeJ3TvUBPG9Y4mBcI//ZjRtiJuYBF6hcmvdLunXA==","shasum":"f1e22d1c46f6be739150f755d56800d267279e2e","tarball":"https://registry.npmjs.org/@alife-sdk/phaser/-/phaser-0.5.0.tgz","fileCount":67,"unpackedSize":123097,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIAh+kTU0Xe5E6bzXzWq29tmlij3UCo7sCmcR7PE6LBObAiBbya19qvb4aV36timS9R7wu7PW7DGap0I/n6p2ijBXKw=="}]},"_npmUser":{"name":"eurusik","email":"john.rusakov@gmail.com"},"directories":{},"maintainers":[{"name":"eurusik","email":"john.rusakov@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/phaser_0.5.0_1773866620992_0.2824254701801019"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-05T19:45:46.353Z","modified":"2026-03-18T20:43:41.294Z","0.1.0":"2026-03-05T19:45:46.580Z","0.1.1":"2026-03-05T20:32:15.659Z","0.2.0":"2026-03-06T05:18:31.478Z","0.3.0":"2026-03-06T09:34:42.876Z","0.4.0":"2026-03-06T18:59:06.537Z","0.4.1":"2026-03-18T12:32:24.620Z","0.5.0":"2026-03-18T20:43:41.155Z"},"bugs":{"url":"https://github.com/eurusik/alife-sdk/issues"},"author":{"name":"Eugene Rusakov"},"license":"MIT","homepage":"https://github.com/eurusik/alife-sdk#readme","keywords":["alife","phaser","game-ai","simulation","npc","adapter"],"repository":{"type":"git","url":"git+https://github.com/eurusik/alife-sdk.git","directory":"packages/alife-phaser"},"description":"Phaser 3 adapter for @alife-sdk — entity adapters, online/offline manager, NPC AI bridge","maintainers":[{"name":"eurusik","email":"john.rusakov@gmail.com"}],"readme":"# @alife-sdk/phaser\n\nPhaser 3 adapter layer for the A-Life SDK. Provides duck-typed Phaser\ninterfaces, ready-to-use adapter implementations, and a one-call kernel factory.\nThis package is designed for single-player or local Phaser scenes. For online multiplayer, implement network sync on top of the SDK.\n\n```ts\n// Sub-path imports keep bundles small — each path is a separate chunk.\n// Import only what you use; the rest is tree-shaken out.\nimport { createPhaserKernel }                    from '@alife-sdk/phaser/scene';\nimport { PhaserEntityAdapter, PhaserEntityFactory,\n         PhaserSimulationBridge, PhaserPlayerPosition } from '@alife-sdk/phaser/adapters';\nimport { OnlineOfflineManager }                  from '@alife-sdk/phaser/online';\n```\n\n```bash\nnpm install @alife-sdk/phaser @alife-sdk/core @alife-sdk/simulation @alife-sdk/ai @alife-sdk/social\n\n# peer dependency (optional — only if using Phaser 3 engine directly)\nnpm install phaser@^3.60.0\n```\n\n`phaser` is an optional peer dependency — required only if you use `PhaserEntityAdapter` and related\nadapters. Without it, the types still compile.\n\n---\n\n## Quick Start\n\nThe absolute minimum to get one NPC simulating in a Phaser scene — no online/offline\nmanagement, no squad logic, just a brain ticking every frame.\n\n```ts\nimport Phaser from 'phaser';\nimport { createPhaserKernel } from '@alife-sdk/phaser/scene';\nimport {\n  PhaserEntityAdapter,\n  PhaserEntityFactory,\n  PhaserSimulationBridge,\n  PhaserPlayerPosition,\n} from '@alife-sdk/phaser/adapters';\nimport { SmartTerrain, TerrainBuilder } from '@alife-sdk/core/terrain';\n\nexport class GameScene extends Phaser.Scene {\n  private kernel!:     ReturnType<typeof createPhaserKernel>['kernel'];\n  private simulation!: NonNullable<ReturnType<typeof createPhaserKernel>['simulation']>;\n  private adapter!:    PhaserEntityAdapter;\n\n  constructor() { super({ key: 'GameScene' }); }\n\n  create(): void {\n    // Spawn the player sprite — PhaserPlayerPosition reads x/y from it live.\n    const player = this.physics.add.sprite(400, 300, 'player');\n\n    // Adapter: maps entity IDs to Phaser sprites for the SDK.\n    this.adapter = new PhaserEntityAdapter();\n    // Bridge: tracks NPC HP so the simulation can apply damage.\n    const bridge = new PhaserSimulationBridge();\n    // PlayerPosition: supplies the player's world coordinates each tick.\n    const playerPos = new PhaserPlayerPosition(player);\n    // Factory: SDK calls these when it needs to spawn or despawn an entity.\n    const factory = new PhaserEntityFactory({\n      // req: INPCSpawnRequest from @alife-sdk/core\n      // req: { npcTypeId, factionId, x, y, rank, squadId?, metadata? }\n      createNPC: (req) => {\n        const sprite = this.physics.add.sprite(req.x, req.y, 'npc'); // spawn sprite\n        const id = `npc_${req.npcTypeId}`;\n        this.adapter.register(id, sprite);                            // register before returning\n        bridge.register(id, { currentHp: 100, maxHp: 100 });\n        return id;\n      },\n      // req: IMonsterSpawnRequest from @alife-sdk/core\n      // req: { monsterTypeId, x, y, lairTerrainId?, packIndex?, metadata? }\n      createMonster: (req) => {\n        const sprite = this.physics.add.sprite(req.x, req.y, 'monster');\n        const id = `monster_${req.monsterTypeId}`;\n        this.adapter.register(id, sprite);\n        return id;\n      },\n      destroyEntity: (id) => {\n        this.adapter.getSprite(id)?.destroy();\n        this.adapter.unregister(id);\n        bridge.unregister(id);\n      },\n    });\n\n    // Wire everything into a kernel. 'simulation' preset includes SimulationPlugin\n    // but skips AI and Social plugins — enough for basic NPC behaviour.\n    const result = createPhaserKernel({\n      ports: { entityAdapter: this.adapter, playerPosition: playerPos,\n               entityFactory: factory, simulationBridge: bridge },\n      data: {\n        factions: [{ id: 'stalker', displayName: 'Stalker' }],         // at least one faction\n        terrains: [\n          new SmartTerrain(\n            new TerrainBuilder('camp')\n              .name('Camp').bounds({ x: 100, y: 100, width: 400, height: 400 })\n              .capacity(5).addJob({ type: 'patrol', slots: 5 }).build()\n          ),\n        ],\n      },\n      config: { preset: 'simulation' },\n    });\n\n    this.kernel     = result.kernel;\n    this.simulation = result.simulation!;   // non-null when preset !== 'minimal'\n\n    this.kernel.init();\n\n    // Register the NPC — call once per entity at startup.\n    this.simulation.registerNPC({\n      entityId: 'stalker_1', factionId: 'stalker',\n      position: { x: 300, y: 280 }, rank: 3, combatPower: 50, currentHp: 100,\n      behaviorConfig: {\n        retreatThreshold: 0.1, panicThreshold: -0.7,\n        searchIntervalMs: 5_000, dangerTolerance: 3, aggression: 0.5,\n      },\n      options: { type: 'human' },   // 'human' → schedules/equipment; 'monster' → lair-based\n    });\n\n    this.kernel.start();  // enables frame-based updates\n  }\n\n  update(_time: number, delta: number): void {\n    // Drive the kernel every frame — NPC brains do not tick without this call.\n    this.kernel.update(delta);  // delta is milliseconds (Phaser default)\n  }\n}\n```\n\n> **`preset: 'simulation'`** includes the SimulationPlugin (NPC records, HP, offline brains)\n> but omits AI and Social plugins. Switch to `preset: 'full'` when you need the full\n> behaviour tree and faction relationship system.\n>\n> **Preset plugin summary:**\n>\n> | Preset | Plugins included |\n> |--------|-----------------|\n> | `minimal` | FactionsPlugin, SpawnPlugin |\n> | `simulation` | + SimulationPlugin (default) |\n> | `full` | + AIPlugin, SocialPlugin |\n>\n> `simulationBridge` is optional but **required** for HP tracking when using the\n> `simulation` or `full` presets. Omit it only with the `minimal` preset.\n\n### Offline vs online AI\n\nWhen an NPC is **offline** (beyond the player's range), `SimulationPlugin`'s brain runs pure\nJavaScript logic — no Phaser physics involved. HP, morale, and damage are tracked through\n`PhaserSimulationBridge`, which maintains lightweight HP records and routes `applyDamage` /\n`adjustMorale` calls without touching any sprite.\n\nWhen an NPC goes **online**, `OnlineAIDriver` takes over: it wraps a `PhaserNPCContext` backed\nby your `IPhaserNPCHost` implementation and drives a full FSM with real Phaser physics — velocity,\ncollision, perception — every frame. The transition is triggered by `simulation.setNPCOnline(id, true)`\nand managed by `OnlineOfflineManager.evaluate()`.\n\n---\n\n## Complete Example\n\nA full Phaser 3 scene that wires the SDK end-to-end. Copy this as your starting point,\nthen replace texture keys and faction IDs with your own.\n\n```ts\nimport Phaser from 'phaser';\nimport { createPhaserKernel } from '@alife-sdk/phaser/scene';\nimport {\n  PhaserEntityAdapter,\n  PhaserEntityFactory,\n  PhaserSimulationBridge,\n  PhaserPlayerPosition,\n} from '@alife-sdk/phaser/adapters';\nimport { OnlineOfflineManager } from '@alife-sdk/phaser/online';\nimport type { IOnlineRecord } from '@alife-sdk/phaser/types';\nimport { SmartTerrain, TerrainBuilder } from '@alife-sdk/core/terrain';\nimport type { ALifeKernel } from '@alife-sdk/core';\nimport type { SimulationPlugin } from '@alife-sdk/simulation';\n\nexport class GameScene extends Phaser.Scene {\n  private kernel!: ALifeKernel;\n  private simulation!: SimulationPlugin;\n  private onlineOffline!: OnlineOfflineManager;\n  private adapter!: PhaserEntityAdapter;\n  private bridge!: PhaserSimulationBridge;\n  private player!: Phaser.Physics.Arcade.Sprite;\n\n  // Throttle the online/offline check — runs at most once per second.\n  private oomAccumMs = 0;\n\n  constructor() {\n    super({ key: 'GameScene' });\n  }\n\n  create(): void {\n    // --- 1. Spawn the player sprite ---\n    this.player = this.physics.add.sprite(400, 300, 'player');\n\n    // --- 2. Create all four adapters ---\n    //   EntityAdapter  — maps entity IDs to Phaser sprites\n    //   SimBridge      — tracks HP and damage for offline NPCs\n    //   PlayerPosition — reads x/y from the live player sprite\n    //   EntityFactory  — delegates sprite creation/destruction to callbacks\n    this.adapter = new PhaserEntityAdapter();\n    this.bridge  = new PhaserSimulationBridge();\n\n    const playerPos = new PhaserPlayerPosition(this.player);\n\n    const factory = new PhaserEntityFactory({\n      createNPC: (req) => {\n        // Spawn the sprite, register it in both adapters, then return its ID.\n        // req.x / req.y are world-space pixel coordinates from the spawn request.\n        const sprite = this.physics.add.sprite(req.x, req.y, 'npc');\n        const id = `npc_${req.npcTypeId}`;\n        this.adapter.register(id, sprite);\n        // HP is managed by the simulation — default to 100/100 here;\n        // the real values come from registerNPC() below.\n        this.bridge.register(id, { currentHp: 100, maxHp: 100 });\n        return id;\n      },\n      createMonster: (req) => {\n        const sprite = this.physics.add.sprite(req.x, req.y, 'monster');\n        const id = `monster_${req.monsterTypeId}`;\n        this.adapter.register(id, sprite);\n        return id;\n      },\n      destroyEntity: (id) => {\n        const sprite = this.adapter.getSprite(id);\n        sprite?.destroy();\n        this.adapter.unregister(id);\n        this.bridge.unregister(id);\n      },\n    });\n\n    // --- 3. Wire the kernel (preset 'full' includes AI + Social plugins) ---\n    const result = createPhaserKernel({\n      ports: {\n        entityAdapter:    this.adapter,\n        playerPosition:   playerPos,\n        entityFactory:    factory,\n        simulationBridge: this.bridge,\n      },\n      data: {\n        factions: [\n          { id: 'stalker', displayName: 'Stalker', relations: { bandit: -60, military: -20 } },\n          { id: 'bandit',  displayName: 'Bandit',  relations: { stalker: -60, military: -80 } },\n        ],\n        terrains: [\n          new SmartTerrain(\n            new TerrainBuilder('main_camp')\n              .name('Main Camp')\n              .bounds({ x: 100, y: 100, width: 400, height: 400 })\n              .capacity(10)\n              .addJob({ type: 'patrol', slots: 5 })\n              .addJob({ type: 'guard',  slots: 5, position: { x: 300, y: 300 } })\n              .build()\n          ),\n        ],\n      },\n      config: {\n        preset: 'full',\n        onlineOffline: { switchDistance: 500, hysteresisFactor: 0.15 },\n      },\n    });\n\n    this.kernel      = result.kernel;\n    this.simulation  = result.simulation!;\n    this.onlineOffline = result.onlineOffline;\n\n    this.kernel.init();\n\n    // --- 4. Register NPCs — called once per NPC at scene startup ---\n    const behaviorConfig = {\n      retreatThreshold: 0.1,\n      panicThreshold:   -0.7,\n      searchIntervalMs: 5_000,\n      dangerTolerance:  3,\n      aggression:       0.5,\n    };\n\n    this.simulation.registerNPC({\n      entityId: 'stalker_guard_1', factionId: 'stalker',\n      position: { x: 320, y: 280 }, rank: 3, combatPower: 55, currentHp: 100,\n      behaviorConfig,\n      options: { type: 'human' }, // 'human' → HumanBrain (schedules, equipment, money)\n    });\n    this.simulation.registerNPC({\n      entityId: 'bandit_scout_1', factionId: 'bandit',\n      position: { x: 640, y: 400 }, rank: 2, combatPower: 40, currentHp: 80,\n      behaviorConfig,\n      options: { type: 'human' },\n    });\n    this.simulation.registerNPC({\n      entityId: 'stalker_vet_1', factionId: 'stalker',\n      position: { x: 200, y: 500 }, rank: 5, combatPower: 80, currentHp: 120,\n      behaviorConfig,\n      options: { type: 'human' }, // use { type: 'monster', lairTerrainId: '...' } for creatures\n    });\n\n    // --- 5. Start the kernel ---\n    this.kernel.start();\n  }\n\n  update(_time: number, delta: number): void {\n    // Always drive the kernel with delta milliseconds (Phaser passes ms by default).\n    this.kernel.update(delta);\n\n    // --- Online/offline check (run at most once per second) ---\n    this.oomAccumMs += delta;\n    if (this.oomAccumMs >= 1_000) {\n      this.oomAccumMs = 0;\n\n      // Build a snapshot of every NPC's current position and online state.\n      const records: IOnlineRecord[] = [];\n      for (const [, record] of this.simulation.getAllNPCRecords()) {\n        const brain = this.simulation.getNPCBrain(record.entityId);\n        const pos   = brain?.lastPosition ?? record.lastPosition;\n        records.push({\n          entityId: record.entityId,\n          x:        pos.x,\n          y:        pos.y,\n          isOnline: record.isOnline,\n          isAlive:  record.currentHp > 0,\n        });\n      }\n\n      const squadManager  = this.simulation.getSquadManager();\n      const squadResolver = (npcId: string) => {\n        const squad = squadManager.getSquadForNPC(npcId);\n        return squad ? squad.getMembers() : null;\n      };\n\n      const { goOnline, goOffline } = this.onlineOffline.evaluate(\n        this.player.x, this.player.y, records, squadResolver,\n      );\n\n      // Apply transitions — swap control between Phaser physics and sim brain.\n      for (const id of goOnline) {\n        this.simulation.setNPCOnline(id, true);\n        // Activate the sprite so Phaser physics/AI takes over from here.\n        const sprite = this.adapter.getSprite(id);\n        sprite?.setActive(true).setVisible(true);\n      }\n      for (const id of goOffline) {\n        this.simulation.setNPCOnline(id, false);\n        // Snap sprite to the brain's last known position, then park it.\n        const record = this.simulation.getNPCRecord(id);\n        const sprite  = this.adapter.getSprite(id);\n        if (sprite && record?.lastPosition) {\n          sprite.setPosition(record.lastPosition.x, record.lastPosition.y);\n        }\n        sprite?.setActive(false).setVisible(false);\n      }\n    }\n  }\n}\n```\n\n> **Note on `SmartTerrain`:** import it from `@alife-sdk/core` and construct instances before\n> passing them in the `data.terrains` array. Each terrain needs an `id`, `name`,\n> `bounds: { x, y, width, height }`, and `capacity` (max simultaneous NPC jobs).\n\n---\n\n## Modules\n\n| Module | What it contains |\n|--------|-----------------|\n| [`types`](src/types/README.md) | Duck-typed Phaser interfaces, `IOnlineOfflineConfig`, `IOnlineRecord` |\n| [`adapters`](src/adapters/README.md) | 6 adapter classes bridging SDK ports to Phaser |\n| [`online`](src/online/README.md) | `OnlineOfflineManager` + `PhaserNPCContext` |\n| [`scene`](src/scene/README.md) | `createPhaserKernel` — full kernel wiring in one call |\n\n---\n\n## Quick start\n\n```ts\n// 1. Create adapters\nconst adapter  = new PhaserEntityAdapter(logger);\nconst bridge   = new PhaserSimulationBridge(logger);\nconst playerPos = new PhaserPlayerPosition(playerSprite);\nconst factory  = new PhaserEntityFactory({\n  createNPC:     (req) => spawnNPC(req, adapter, bridge),\n  createMonster: (req) => spawnMonster(req, adapter, bridge),\n  destroyEntity: (id)  => despawn(id, adapter, bridge),\n});\n\n// 2. Wire the kernel\nconst { kernel, simulation, onlineOffline } = createPhaserKernel({\n  ports:  { entityAdapter: adapter, playerPosition: playerPos,\n            entityFactory: factory, simulationBridge: bridge },\n  data:   { factions: FACTION_DEFS, terrains: TERRAINS },\n  config: { preset: 'full' },\n});\n\nkernel.init();\nkernel.start();\n\n// 3. Phaser update loop\nfunction update(_time: number, delta: number) {\n  kernel.update(delta);\n\n  // Run online/offline check at your preferred cadence (e.g. every 1 s):\n  if (shouldCheckOnlineOffline) {\n    const { goOnline, goOffline } = onlineOffline.evaluate(\n      playerSprite.x, playerSprite.y,\n      getOnlineRecords(),\n      (id) => squadManager.getMemberIds(id),\n    );\n    goOnline.forEach(id  => bringOnline(id));\n    goOffline.forEach(id => bringOffline(id));\n  }\n}\n```\n\n---\n\n## Architecture\n\n```\n┌─────────────────────────────────────────────────────────────────┐\n│                        @alife-sdk/phaser                        │\n│                                                                 │\n│  ┌─────────────┐  ┌──────────────┐  ┌────────────────────────┐ │\n│  │   adapters  │  │    online    │  │         scene          │ │\n│  │─────────────│  │──────────────│  │────────────────────────│ │\n│  │ EntityAd.   │  │ OnlineOff.   │  │ createPhaserKernel()   │ │\n│  │ EntityFact. │  │ Manager      │  │   → kernel             │ │\n│  │ SimBridge   │  │──────────────│  │   → simulation         │ │\n│  │ SocProvider │  │ PhaserNPC    │  │   → onlineOffline      │ │\n│  │ SocPresenter│  │ Context      │  └────────────────────────┘ │\n│  │ PlayerPos   │  └──────────────┘                             │\n│  └─────────────┘                                               │\n└─────────────────────────────────────────────────────────────────┘\n         ↓ implements                      ↓ creates\n┌─────────────────────────────────────────────────────────────────┐\n│   @alife-sdk/core  ·  @alife-sdk/simulation  ·  @alife-sdk/ai  │\n│   @alife-sdk/social                                             │\n└─────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## How adapters work\n\n**Why no direct Phaser import in the SDK core.**\nThe SDK never imports from `phaser` at compile time. Every Phaser object is accepted through a\nminimal duck-typed interface (`IArcadeSprite`, `IArcadeBody`, `IArcadeAnims`). This means:\n- Tests pass plain JavaScript objects with the right shape — no Phaser install needed in CI.\n- You can swap the real Phaser sprite for any object that satisfies the interface (e.g. a\n  server-side position stub).\n\n**What each adapter does:**\n\n| Adapter | Responsibility |\n|---------|---------------|\n| `PhaserEntityAdapter` | Stores a sprite registry keyed by entity ID; the SDK calls `setPosition`, `setVelocity`, `playAnimation`, etc. on it. |\n| `PhaserEntityFactory` | Delegates `createNPC`, `createMonster`, and `destroyEntity` to your callbacks — you write the sprite-creation code. |\n| `PhaserSimulationBridge` | Tracks NPC HP records; the simulation calls `applyDamage` and `adjustMorale` through it. |\n| `PhaserPlayerPosition` | Reads `x`/`y` from any object (sprite, registry entry, plain object) and returns it as `Vec2`. |\n| `PhaserNPCSocialProvider` | Supplies online NPC data and faction relationship queries to the social plugin via user-provided callbacks. |\n| `PhaserSocialPresenter` | Delegates social presentation events (speech bubbles, etc.) to a user-provided `showBubble` callback. |\n\n**Swapping adapters.** All six are plain classes implementing SDK interfaces (`IEntityAdapter`,\n`IEntityFactory`, `ISimulationBridge`, `IPlayerPositionProvider`, `INPCSocialProvider`,\n`ISocialPresenter`). Replace any of them with a custom class that implements the same interface —\nthe kernel does not care about the concrete type.\n\n---\n\n## Key design decisions\n\n**No Phaser import at compile time.** All Phaser objects are accepted through\nduck-typed interfaces (`IArcadeSprite`, `IArcadeBody`, `IArcadeAnims`). Tests\npass plain objects; the real Phaser sprites satisfy the interfaces at runtime.\n\n**Callback-based factories.** `PhaserEntityFactory`, `PhaserNPCSocialProvider`,\nand `PhaserSocialPresenter` delegate to user-provided callbacks instead of\nsubclassing. This keeps sprite creation and UI presentation game-specific\nwithout requiring inheritance.\n\n**OnlineOfflineManager is pure.** It evaluates NPC records and returns\ntransition lists — it never mutates records or calls Phaser APIs. The caller\ndecides when to run the check and how to apply the results.\n\n**PhaserNPCContext wraps your sprite host.** Implement `IPhaserNPCHost` on\nyour NPC entity class (15 methods), then pass a `PhaserNPCContext` to\n`OnlineAIDriver`. The driver intercepts `transition()` and manages the FSM;\nthe host handles all sprite-level operations.\n\n**PhaserNPCContext is the online AI bridge — one instance per active NPC.**\nIt implements `INPCContext` by delegating every call (position, velocity,\nevents, subsystems) to your `IPhaserNPCHost` implementation. Wrap it with\n`OnlineAIDriver` (imported from `@alife-sdk/ai`) to get a fully managed FSM\nthat calls `enter` / `update` / `exit` on your state handlers each frame.\nSee [`online/README.md`](src/online/README.md) for the full usage guide\nincluding `IPhaserNPCHost`, subsystem wiring, and a complete example.\n\n---\n\n## Testing\n\nThe package has **187 tests** (vitest). Run them:\n\n```\npnpm --filter @alife-sdk/phaser test\n```\n\nAll adapters use duck-typed Phaser interfaces — no real Phaser import is needed\nfor tests. Pass a plain object that satisfies the interface shape:\n\n```ts\n// Mock Phaser sprite — just needs the shape, not real Phaser\nconst mockSprite = { x: 10, y: 20, active: true, visible: true, setActive: vi.fn(), setVisible: vi.fn() };\nconst adapter = new PhaserEntityAdapter();           // optional logger arg\nadapter.register('mock_entity_1', mockSprite);       // attach sprite to entity ID\n```\n\nCovers: all 6 adapter classes (`PhaserEntityAdapter`, `PhaserEntityFactory`,\n`PhaserSimulationBridge`, `PhaserPlayerPosition`, `PhaserNPCSocialProvider`,\n`PhaserSocialPresenter`), `OnlineOfflineManager`, `PhaserNPCContext`,\n`createPhaserKernel`, and 5 integration scenarios.\n\n---\n\n## Common Mistakes\n\n**Forgetting `kernel.update(delta)` in Phaser's `update()` method.**\nWithout this call, no plugin ticks — NPC brains never update, the clock never advances, and\nonline/offline transitions never fire. Every Phaser scene that uses the kernel must call\n`kernel.update(delta)` on every frame, where `delta` is the millisecond value Phaser passes\nas the second argument to `update(_time, delta)`.\n\n**Not registering the sprite with the adapter before calling `simulation.registerNPC()`.**\n`PhaserEntityFactory.createNPC` is the right place to call `adapter.register(id, sprite)`.\nIf the sprite is registered after `registerNPC`, the adapter cannot find it during the\nfirst brain update and logs warnings for every position/velocity mutation. Register the sprite\nfirst, then return the ID from the factory callback.\n\n**Not driving `OnlineOfflineManager.evaluate()` each check interval.**\n`OnlineOfflineManager` is stateless — it evaluates a snapshot and returns lists. It does not\nschedule itself. If you never call `evaluate()`, NPCs stay in their initial online/offline state\nforever. Call it on a timer (e.g. every 1 s) and apply the returned `goOnline`/`goOffline` lists\nby calling `simulation.setNPCOnline(id, true/false)`.\n\n**Passing Phaser's absolute game time instead of the frame delta.**\n`kernel.update(time)` expects elapsed milliseconds since the last frame — the `delta` parameter,\nnot the `time` parameter. Passing total elapsed time causes all plugin timers (brain tick\nintervals, surge cooldowns, spawn cooldowns) to fire on the very first frame and then never again.\nUse `kernel.update(delta)` where `delta` is typically 16–17 ms at 60 fps.\n\n---\n\n## Adding to an existing Phaser project\n\n1. **Install the package.**\n   ```bash\n   npm install @alife-sdk/phaser @alife-sdk/core @alife-sdk/simulation @alife-sdk/ai @alife-sdk/social\n   ```\n\n2. **Create adapters in `Scene.create()`.**\n   Instantiate `PhaserEntityAdapter`, `PhaserSimulationBridge`, `PhaserPlayerPosition` (passing\n   your player sprite), and `PhaserEntityFactory` (with `createNPC`, `createMonster`, and\n   `destroyEntity` callbacks).\n\n3. **Wrap entity creation in `PhaserEntityFactory` callbacks.**\n   Inside each callback, spawn your sprite, call `adapter.register(id, sprite)` and\n   `bridge.register(id, { currentHp, maxHp })`, then return the entity ID string.\n\n4. **Call `kernel.update(delta)` in `Scene.update()`.**\n   Pass the `delta` argument (milliseconds since last frame) — not `time`. Without this, no\n   plugin ticks and NPC brains never update.\n\n5. **Register existing sprites with `adapter.register()`.**\n   Any sprite already in your scene that the SDK should control must be registered before\n   calling `simulation.registerNPC()`. Register first, then hand the ID to `registerNPC`.\n","readmeFilename":"README.md"}