{"_id":"jygame","_rev":"29-3171104d268e4bfb09c1485d500b75a3","name":"jygame","dist-tags":{"latest":"0.8.11"},"versions":{"0.1.0":{"name":"jygame","version":"0.1.0","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.1.0","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://github.com/Bouzidi-Youssef/Jygame#readme","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"5568619b182e55c9c273575d9010e0ef62b8cc6f","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.1.0.tgz","fileCount":18,"integrity":"sha512-/lA51XHgGnTQEX4dxcSU0J3G5kSLKvDqU8jQVBnefmQgYjbbVhFm3H/W5eU5hVZONn4IPzCi8W4caDEP+8tSLw==","signatures":[{"sig":"MEUCIFe8+l5woGxwqOVQKxGoxyN5Hu55CdzzI2pp8qAtiUlUAiEAuensofQKcbLha3hM3DOu3PRs6HyRcGnbXp7LXjwg9NQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":59818},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"56b45a375b6f271f2c86232a1d73b468a8286021","_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"11.9.0","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"25.1.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/jygame_0.1.0_1780608975425_0.36507949126630956","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"jygame","version":"0.2.0","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.2.0","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://github.com/Bouzidi-Youssef/Jygame#readme","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"6f7e31a2d2935bede77007b6e6590074c925f5a8","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.2.0.tgz","fileCount":19,"integrity":"sha512-bWpCa/T6L/EMp8bp4as4D/rfE+nl/ZXOgjw5B1UnKb5rVqx7RXbfm6UESX6ubnYr++C3lvRbkNfz6TE8DFMAAA==","signatures":[{"sig":"MEYCIQCjIh5JjNAZ5yEMFT4+JNQ/P2YwtyxMkFiNWvjHSQTeEgIhAPrYeRQDguG5IrGTwWwKXVI0/BtnoyYT8IpS/Meq1LOy","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":86127},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"82aa09da7018709da6648484dc5fa0c06887c9ea","_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"11.9.0","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"25.1.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/jygame_0.2.0_1780673484166_0.1188516930865895","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"jygame","version":"0.3.0","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.3.0","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://github.com/Bouzidi-Youssef/Jygame#readme","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"39a3ec6628b36a94407851960c551e19fdad6901","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.3.0.tgz","fileCount":19,"integrity":"sha512-p6OhODUYgDyBqA0b1o1D3Gi6ispp8hJbeeuW9WSJTx3iLETdAgLHJ8Hgf4Ac9sQVoptI5nTTF8EgjuVUS6HtdQ==","signatures":[{"sig":"MEUCIQC6F/2sbQ6WjXrPsAGmJ41R2b2qVasAh33KKdUio7SFIwIgXsfhJl6OGLUep54m8nT5X7GLs85i/o0JdoOzybGRnfQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":88798},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"bf77c3c28c79fdcb14539aec1c0091591d8454cf","_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"11.13.0","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"26.2.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/jygame_0.3.0_1780774984089_0.7438657218563436","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"jygame","version":"0.4.0","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.4.0","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://github.com/Bouzidi-Youssef/Jygame#readme","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"a09dd195d653aa3b05c9a9492a56636effe04e49","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.4.0.tgz","fileCount":28,"integrity":"sha512-xruh9ekNqDtOCitZ4E1+sPXyr8i0bryksGmgmBUE4ciPPe2RFbzDRLShmbHII03E3LZCP/asuEhTWacdRiofug==","signatures":[{"sig":"MEUCIQCc71bWcofU4xn4MaO9/GPSnYxPwahNKfRmFK3/e59sFAIgH/KFz0ygIKNkk1keO+jr6ygn3E9ZVhRl1ZMsbyuRAgY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":108798},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"3d99cea2cc03625b20de00d8d3147e195af59948","_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"11.13.0","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"26.2.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/jygame_0.4.0_1780929381332_0.6989360698561862","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"jygame","version":"0.4.1","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.4.1","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://github.com/Bouzidi-Youssef/Jygame#readme","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"5d402cf0137cb27d64bfb48b0ed09a16a5434f44","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.4.1.tgz","fileCount":28,"integrity":"sha512-QgeKTOW67YT5qGIbmArFXe+cKiE8J3NwdmtqScceFkNXk1a7CLN3tr5cjf9+0kexP5Dm1TYY9hnrTVnGtcZNjA==","signatures":[{"sig":"MEUCIDpO9Q7Dmk1Lqtt5PXPt4YUbWUxp7MSt4lNAuvIDsLSVAiEA4fbvOM6XKjH7tK9wgOI+kw7WcF3ZVwjjflpaZ59PS2s=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":110850},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"87bb7c2494c7ed286bb1445953f35c5342e94c71","_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"11.13.0","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"26.2.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/jygame_0.4.1_1780929894469_0.6052861802248286","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"jygame","version":"0.5.0","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.5.0","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"7693731c82ad39ddbbf53315f812be29d829ae15","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.5.0.tgz","fileCount":31,"integrity":"sha512-dcJ2Gaa3MVgmNevO/2jtGpk/nmLb8pk9yMQThb1YK0kFS7wfLYopEy+IIOKQw62zGUrYOTxnCOZjyd8tZ8/SpA==","signatures":[{"sig":"MEUCIDRkbMdWJwjki8fLxx5jgZh2BfueX4aZL+1aOOI52ZLEAiEAsVPy4ljiVDPvy2oz5c11qNW5bN1EkCQ1oqZiaLPXE/0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":129893},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"0d2550c6488a8c2aedd9bd9b9b3fe7d89ab1ebd3","_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"11.13.0","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"26.2.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/jygame_0.5.0_1781004138234_0.7638631876491475","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"jygame","version":"0.6.0","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.6.0","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"9be644ba69bf32de9fc51784dc6645816aaab760","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.6.0.tgz","fileCount":34,"integrity":"sha512-A7dz3+qXybjXELyZYMFYyHQLW9WtCtFd5/UcutZTo13YZG3kdBjDJE3pNiBxxbaF1Jn+nArgh8Qh+L8766Le+w==","signatures":[{"sig":"MEQCIFy51+GlpiI17Y9i22VGWbFMZbtlc+Dww4unsAB28hlHAiB/w2tw87YVC2eIvht+CQoGI6txhJ+uU/P5em6/57itMQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":145320},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"4a0b00f6ba169bafe9a91dbb36004bcafd7c65a3","_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"11.13.0","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"26.2.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/jygame_0.6.0_1781397125847_0.024764988984768976","host":"s3://npm-registry-packages-npm-production"}},"0.7.0":{"name":"jygame","version":"0.7.0","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.7.0","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"aed74919acd67a8d5d873cf122fb9ada3b285a4e","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.7.0.tgz","fileCount":66,"integrity":"sha512-KWV3k6ELqhMPaLXPwz6+YBViYaMDcLqQ9RCLyrmsrED3yQIjRHuAwI51gxTYHhYG0hz4dszTfVv85TCJfLpFfg==","signatures":[{"sig":"MEUCIQDLljNGQ1KtAvMRdjBY0tS6pXBcSUv26s6AbldpoHHJLgIgcEj/eJLXfDTg1TzunV4IdiUOF6ZdYPutDgX7qMYiuOQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":221866},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"2637836018f0f3e7a0bc277087dd29f68c5df2a5","scripts":{"test":"echo \"No tests yet\" && exit 0"},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"11.13.0","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"26.2.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/jygame_0.7.0_1781610550487_0.24482177752284584","host":"s3://npm-registry-packages-npm-production"}},"0.7.1":{"name":"jygame","version":"0.7.1","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.7.1","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"e7e9f67b7cb33a9224258337b328ffbb1545a107","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.7.1.tgz","fileCount":66,"integrity":"sha512-vgm/58DdpQI82Jx65D+694ghnJvm6K+jB3FCBBAQcuXN1zvitz1w8ND2ITaQgNkmNpyI6pUKN+TXbUwCBrHJHw==","signatures":[{"sig":"MEUCIQCDGmgJyZlfEtNZ5mdfey3u3oXGb1TPnzXLGYY0gPFGsAIgNNAjV0UK/1MJnCk61U1DI4BqY3qRsqAC3afssSp2osI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":222488},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"47c4fe26811cfd13279f5b9ee77c661f8f815068","scripts":{"test":"echo \"No tests yet\" && exit 0"},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"10.8.2","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/jygame_0.7.1_1781618825511_0.07863720132540086","host":"s3://npm-registry-packages-npm-production"}},"0.7.2":{"name":"jygame","version":"0.7.2","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.7.2","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"f552060600cfb62e423626a37d4afbec58b72ee0","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.7.2.tgz","fileCount":69,"integrity":"sha512-dOetS953e98fJ1iJC53uJsp4hTvoFBIXmIRGnUdiVR4+m8oTj/UNSEkCTSgY1VgUFhG4CrWklU/kBOQAxHdmAA==","signatures":[{"sig":"MEUCICgN+QeVcdiqfQ8aV8Hb0Uvsr+WIPyHBGN2f9gqpjFGFAiEA6huESYGxDHu0Cup+0MKR8V1n7oK0QERC9GuwGVgpYa8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":228432},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"ef22ae42ca0521a4f9e0d7309c7e034c27ae7b17","scripts":{"test":"echo \"No tests yet\" && exit 0"},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"10.8.2","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/jygame_0.7.2_1781701630246_0.20513077127471013","host":"s3://npm-registry-packages-npm-production"}},"0.7.3":{"name":"jygame","version":"0.7.3","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.7.3","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"326b1e70752e49a8cb4fa66c54897c796366e565","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.7.3.tgz","fileCount":80,"integrity":"sha512-WG8BdpKwkl6cmqor52MP6zg1oVPQKzk/2JyFYhSkeVsEDsuMTp1nPQ58gaSlfA+6RM93C9tt15/p7TiuiB3qvQ==","signatures":[{"sig":"MEUCIQCb+4deRwv4hAS/OALTzCCLY+kZDbPehKDL7YetB8g/UQIgJorcqCdBO95J4bIGmlVxSS4I6QpmABoyFGWRJk+oAvY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":263474},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"ee63417de0c40bbeffd2d99d5d181b769cbca51d","scripts":{"test":"echo \"No tests yet\" && exit 0"},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"10.8.2","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/jygame_0.7.3_1781908827227_0.5507812554001024","host":"s3://npm-registry-packages-npm-production"}},"0.7.4":{"name":"jygame","version":"0.7.4","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.7.4","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"d7e167c928655e2db175ddf482b4895e59a8b54f","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.7.4.tgz","fileCount":80,"integrity":"sha512-PpVUzxNM6Cx1H1yKATrVQ5DLx9F/fxWxU1xLveD8xr4bBO2xOzN+on5Af75U2Z/94l92xErQoOqCxehmklSYdg==","signatures":[{"sig":"MEQCIDZerLhRYbg8A7AA8O0jTLwCgUrJR2kODRLge0V+HQtTAiBuWUdr3kbWD+j4BZZnbsGMeU5AFo08nwUJeQHESSxKzg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":263474},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"fbf564d07877f04f6a6fc90a0478bd0f5c900580","scripts":{"test":"echo \"No tests yet\" && exit 0"},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"10.8.2","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/jygame_0.7.4_1782036575243_0.40820065821403606","host":"s3://npm-registry-packages-npm-production"}},"0.7.5":{"name":"jygame","version":"0.7.5","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.7.5","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"3e57d7f3fedb20da1ad985a8997847b833016a97","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.7.5.tgz","fileCount":82,"integrity":"sha512-LcuM+5EdFdTUA+JR8VNNcu63ke9/RUA8YhyanOJbgT8f7izw99znNGNM6TASQLS7xotKIGPL5xyvUmy2tMvGMQ==","signatures":[{"sig":"MEUCIQDwY1plAW6dsJdJZltaoaSY+YOyQYOOwlPXb/I0G1/B0QIgRAyA1zM4Ku9FH/XXXJLBmXM6UJMHKGPCJgrnFwRLYEM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":269441},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"579b36bab0ff91e55ae210e206d776670628f0fc","scripts":{"test":"echo \"No tests yet\" && exit 0","build:wasm":"node tools/particles/build-wasm.mjs","build:wasm:verify":"node -e \"import('fs').then(f=>{const w=f.readFileSync('particles/backends/death_sweep.wasm');WebAssembly.instantiate(w).then(i=>{console.log('deathSweepFull:',typeof i.instance.exports.deathSweepFull)})})\""},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"10.8.2","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"wabt":"^1.0.39"},"_npmOperationalInternal":{"tmp":"tmp/jygame_0.7.5_1782151974642_0.2541718494217038","host":"s3://npm-registry-packages-npm-production"}},"0.7.6":{"name":"jygame","version":"0.7.6","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.7.6","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"7a409ac10197ca6865a6be2cd098e6cef871f402","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.7.6.tgz","fileCount":160,"integrity":"sha512-dWErpKGtcJXvF7PCLAsSfzmspq6raDjBDgGuwdhuppKiiVljUkRrBmGlkaEQe9SIn+xYaGeehs+GziY4rWgl0Q==","signatures":[{"sig":"MEUCIGfN3J7XvyXYocjkiBSU78oPsSylyEIiPDZpJyACs+KdAiEA06TzFmnRzCPW8KuRc7ZJ/i3H9WS7+OKlbIN1mrw+jI0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":481929},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"19e588b8153af9cb8bd5fd468a443420e42a5387","scripts":{"test":"echo \"No tests yet\" && exit 0","build:wasm":"node tools/particles/build-wasm.mjs","build:wasm:verify":"node -e \"import('fs').then(f=>{const w=f.readFileSync('particles/backends/death_sweep.wasm');WebAssembly.instantiate(w).then(i=>{console.log('deathSweepFull:',typeof i.instance.exports.deathSweepFull)})})\""},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"10.8.2","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"wabt":"^1.0.39"},"_npmOperationalInternal":{"tmp":"tmp/jygame_0.7.6_1782314968865_0.1099592624378638","host":"s3://npm-registry-packages-npm-production"}},"0.7.7":{"name":"jygame","version":"0.7.7","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.7.7","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"99788367995a31ca67bcf42bef00811ac5d455bb","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.7.7.tgz","fileCount":160,"integrity":"sha512-+kVpd6LLmQ87VDjYrNFXy41eENhnTMHo/+mspqwBOTafiFGAbMLtd8yMMAQbPxZKlvNslGgsnwGaNW4U/lcV7g==","signatures":[{"sig":"MEUCIQCWAQTukOUHuT/002whlesQk8H+L4a+O6oSdL9Oo3vkjQIgJPOy5tJvZEkzCJjD7ObnbMECHxqKzKNZLbhguNgcG0A=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":483155},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"2c9e26f26bbf3e1c7b342daf65f8edd607b6aeb4","scripts":{"test":"echo \"No tests yet\" && exit 0","build:wasm":"node tools/particles/build-wasm.mjs","build:wasm:verify":"node -e \"import('fs').then(f=>{const w=f.readFileSync('particles/backends/death_sweep.wasm');WebAssembly.instantiate(w).then(i=>{console.log('deathSweepFull:',typeof i.instance.exports.deathSweepFull)})})\""},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"10.8.2","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"wabt":"^1.0.39"},"_npmOperationalInternal":{"tmp":"tmp/jygame_0.7.7_1782316956407_0.04318368481625945","host":"s3://npm-registry-packages-npm-production"}},"0.7.8":{"name":"jygame","version":"0.7.8","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.7.8","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"0b949f302ccc4e3142505bc6e3228fb02ca7057d","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.7.8.tgz","fileCount":152,"integrity":"sha512-LimG5GDZGM5aQOui7dMpHwJn0aCeGlfiPMg5xtXCBxGcBqWgNOr0byPdp+bFH+2BXBcAyBk9goRHnpLFpzmUvA==","signatures":[{"sig":"MEUCIQCdi2Par3axZolb+TwWFdFXuFdKnKBB5KR+86wcjVhTbQIgEJChhRVjpcpyJYgpS/J61Sfj/P+8RjBYBLoI0wVlCGc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":504295},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"516170ad7fd47d97ecf62c00d4fcc0d9ceec06ea","scripts":{"test":"echo \"No tests yet\" && exit 0","build:wasm":"node tools/particles/build-wasm.mjs","build:wasm:verify":"node -e \"import('fs').then(f=>{const w=f.readFileSync('particles/backends/death_sweep.wasm');WebAssembly.instantiate(w).then(i=>{console.log('deathSweepFull:',typeof i.instance.exports.deathSweepFull)})})\""},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"10.8.2","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"wabt":"^1.0.39"},"_npmOperationalInternal":{"tmp":"tmp/jygame_0.7.8_1782866104365_0.11100793192077751","host":"s3://npm-registry-packages-npm-production"}},"0.7.9":{"name":"jygame","version":"0.7.9","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.7.9","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"2ed31ad59305170a3cb6728b3b4035287a763f0c","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.7.9.tgz","fileCount":152,"integrity":"sha512-DQocbw3LId5XReDsqTmKo6dkAXzg4vHOVkeaf72xw81GEFFqMHD9+xlvHVKvkdLLxrC4iQGtLZ2gnPBl8lsCmA==","signatures":[{"sig":"MEYCIQCv2pmeZP8hTDrMa3dxkYfpiRT2dKiIrAObsjs8VWgOKAIhALLJg5+aXEC6niLBD34Qvtsi+0zo/uTRzvXsaM4mRq0Q","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":512067},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"a350a4eb6758b4666e42b24c647ee950c9301a34","scripts":{"test":"echo \"No tests yet\" && exit 0","build:wasm":"node tools/particles/build-wasm.mjs","build:wasm:verify":"node -e \"import('fs').then(f=>{const w=f.readFileSync('particles/backends/death_sweep.wasm');WebAssembly.instantiate(w).then(i=>{console.log('deathSweepFull:',typeof i.instance.exports.deathSweepFull)})})\""},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"10.8.2","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"wabt":"^1.0.39"},"_npmOperationalInternal":{"tmp":"tmp/jygame_0.7.9_1782989125652_0.1207151619390956","host":"s3://npm-registry-packages-npm-production"}},"0.8.0":{"name":"jygame","version":"0.8.0","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.8.0","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"7c0a828ec4afb3710004a42be3811deee6b5d65a","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.8.0.tgz","fileCount":216,"integrity":"sha512-6GDVQps0HFhh2Ely5qEmBL8Sj0lxVYQeTu1bFKUkAmxNd41RyruY37Nxxhb50eqpSmRWIIUbUhWomb2H/T1ZFQ==","signatures":[{"sig":"MEUCIQDfzm6kafp/yJsRmEu2HcocyxelJSKjJwJTLhx5WM1+lwIgGtYCP/iXV85CX68fWZxEmUg5BNxuedZtfvi7aE9Bk8o=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2270685},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"8456fd191840534fa3f7c9d6c4ae17e758863d10","scripts":{"test":"echo \"No tests yet\" && exit 0","build:wasm":"node tools/particles/build-wasm.mjs","build:wasm:verify":"node -e \"import('fs').then(f=>{const w=f.readFileSync('particles/backends/death_sweep.wasm');WebAssembly.instantiate(w).then(i=>{console.log('deathSweepFull:',typeof i.instance.exports.deathSweepFull)})})\""},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"11.13.0","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"26.2.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"wabt":"^1.0.39"},"_npmOperationalInternal":{"tmp":"tmp/jygame_0.8.0_1782989825119_0.9666600486136627","host":"s3://npm-registry-packages-npm-production"}},"0.8.1":{"name":"jygame","version":"0.8.1","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.8.1","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"8f53d7e128738ffd936c74d0245b42cb794ea3de","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.8.1.tgz","fileCount":218,"integrity":"sha512-G3cRo0qwpbhoSOdCxkNWXu30PRUTh7MKwOgd3z54wThjaN6IRWLOhCwgiHbWrZgacgaFd6pzMA7EAUAjJ0D5YA==","signatures":[{"sig":"MEYCIQCMYOQ4enjahc7V4PujpSuL7sE6lm0QwJ4lKH2VFUGILgIhAMCxFpuvXpE7IKZmMAiOJsKRkb/y2rOxiQz8JCPIYAWo","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":650183},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"735a322e85cb070c098fc66c078962330512116d","scripts":{"test":"echo \"No tests yet\" && exit 0","build:wasm":"node tools/particles/build-wasm.mjs","build:wasm:verify":"node -e \"import('fs').then(f=>{const w=f.readFileSync('particles/backends/death_sweep.wasm');WebAssembly.instantiate(w).then(i=>{console.log('deathSweepFull:',typeof i.instance.exports.deathSweepFull)})})\""},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"10.9.8","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"22.23.1","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"wabt":"^1.0.39"},"_npmOperationalInternal":{"tmp":"tmp/jygame_0.8.1_1783276907216_0.11221115150839678","host":"s3://npm-registry-packages-npm-production"}},"0.8.2":{"name":"jygame","version":"0.8.2","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.8.2","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"439bf9a728fa7d5bc04a8a66381ae521029836ac","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.8.2.tgz","fileCount":339,"integrity":"sha512-nVRHzEDJMY3JrE/8b/y57lzHJu/OAk3xXNy1M7rzuxmiq65rtHipVihP/rgn86QYU+eoo1qxTCERCH2dRQ+dhw==","signatures":[{"sig":"MEQCIELdTyxfy7oZxScEN+e5amkQn/9G4KqCy5hRHH0R9darAiBeSwaqSIeAYfewjpLnILiuHXVht71bKezfkoEoo0kKWA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":949800},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"e99c06fd7020e9ace684290706eec6cd7ce29421","scripts":{"test":"echo \"No tests yet\" && exit 0","build:wasm":"node tools/particles/build-wasm.mjs","build:wasm:verify":"node -e \"import('fs').then(f=>{const w=f.readFileSync('particles/backends/death_sweep.wasm');WebAssembly.instantiate(w).then(i=>{console.log('deathSweepFull:',typeof i.instance.exports.deathSweepFull)})})\""},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"10.9.8","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"22.23.1","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"wabt":"^1.0.39"},"_npmOperationalInternal":{"tmp":"tmp/jygame_0.8.2_1783830535137_0.11970148643332146","host":"s3://npm-registry-packages-npm-production"}},"0.8.3":{"name":"jygame","version":"0.8.3","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.8.3","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"4849b55b8b770c1363b93c86c8572f73839e4f32","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.8.3.tgz","fileCount":339,"integrity":"sha512-l2rJSj8mRqF+PVbXAjDKbXBj5B6/zZWrZLNT+aDk4kRN/607fNn6yttuhA53A6N6X1BD+8k2pU15dIZ8U1AtVw==","signatures":[{"sig":"MEQCIHEq4/SqRXzJmqWcJnbvZXFAK62TwbyY/Pi0WlkiS13KAiBnT0O1lt0XXs9drFOT7qpHRVHtsC1zlnkMjmpbz1bMsw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":958129},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"bd4a63fc66752f77619032d10de936efeff45ea2","scripts":{"test":"echo \"No tests yet\" && exit 0","build:wasm":"node tools/particles/build-wasm.mjs","build:wasm:verify":"node -e \"import('fs').then(f=>{const w=f.readFileSync('particles/backends/death_sweep.wasm');WebAssembly.instantiate(w).then(i=>{console.log('deathSweepFull:',typeof i.instance.exports.deathSweepFull)})})\""},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"10.9.8","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"22.23.1","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"wabt":"^1.0.39"},"_npmOperationalInternal":{"tmp":"tmp/jygame_0.8.3_1783864169650_0.48247150192805544","host":"s3://npm-registry-packages-npm-production"}},"0.8.4":{"name":"jygame","version":"0.8.4","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.8.4","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"1a59b4b7735d93ae4e9076fc7e606bcf604afb1e","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.8.4.tgz","fileCount":356,"integrity":"sha512-Y/yoG+G3xZo7xfRnSv9tt0XncjpnrGilRS9yuMSjGYDuXbR8oGAJ2NOq55UvZJVo7yOejYMSTGKL0vB4BLuZzA==","signatures":[{"sig":"MEUCIQCAQwCT686H3ok+tFXoX9NempW5uy2XyQ94L7biccpT2wIge0M7PLZC1ytl1uqPwHllExC1n5hL4pesFKUABmt1+s8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":987014},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"26ef7f4b1e42e16166ef550dc5883b4b7ff0c38b","scripts":{"test":"echo \"No tests yet\" && exit 0","build:wasm":"node tools/particles/build-wasm.mjs","build:wasm:verify":"node -e \"import('fs').then(f=>{const w=f.readFileSync('particles/backends/death_sweep.wasm');WebAssembly.instantiate(w).then(i=>{console.log('deathSweepFull:',typeof i.instance.exports.deathSweepFull)})})\""},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"10.9.8","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"22.23.1","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"wabt":"^1.0.39"},"_npmOperationalInternal":{"tmp":"tmp/jygame_0.8.4_1783930397258_0.3590099301805487","host":"s3://npm-registry-packages-npm-production"}},"0.8.5":{"name":"jygame","version":"0.8.5","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.8.5","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"5e15cca340c476e53171644270b90eb05c975850","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.8.5.tgz","fileCount":357,"integrity":"sha512-2g59Vw3UtwnrdadNitTqcCtGTq3gIRwwyEwQ03lgoSS+KnZnjjImq1vjazaS2Lnw1GTSUoIawEIQidmD40z9yg==","signatures":[{"sig":"MEUCIQCI2XPbPh01KKy8+/Lk0MPz0sS2WZDanNSmaEuGgkhFRgIgd/gjnSO1helyrGlaKwFhXijNtvlT86nINGqewhe9PLU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":992973},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"414842c0e26141fb6a465cf92a98a2382f4403ad","scripts":{"test":"echo \"No tests yet\" && exit 0","build:wasm":"node tools/particles/build-wasm.mjs","build:wasm:verify":"node -e \"import('fs').then(f=>{const w=f.readFileSync('particles/backends/death_sweep.wasm');WebAssembly.instantiate(w).then(i=>{console.log('deathSweepFull:',typeof i.instance.exports.deathSweepFull)})})\""},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"10.9.8","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"22.23.1","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"wabt":"^1.0.39"},"_npmOperationalInternal":{"tmp":"tmp/jygame_0.8.5_1784114441401_0.13671322855138746","host":"s3://npm-registry-packages-npm-production"}},"0.8.6":{"name":"jygame","version":"0.8.6","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.8.6","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"36234c5aa56bfeb7ab173cf23ef98e36385fa193","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.8.6.tgz","fileCount":363,"integrity":"sha512-Q795CmNpFpreEUNJxEq9kyXQFILLwFyR+4lglAK9X4hLGxF6u6wT5V3c9uc3zn8IyQYbpOJwwUcbum3SiIPtxA==","signatures":[{"sig":"MEQCIFJLE9XJEMnxEjtwIJp8jcAsRL7+zYc/15nEJHIQVAQLAiAPt25UKQBGxalIUXk+QDrtKMgTjvKgo8iv6k1J5QK7zA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1019469},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"9d755d850e7994d09b8f336d2df7810cf6897858","scripts":{"test":"echo \"No tests yet\" && exit 0","build:wasm":"node tools/particles/build-wasm.mjs","build:wasm:verify":"node -e \"import('fs').then(f=>{const w=f.readFileSync('particles/backends/death_sweep.wasm');WebAssembly.instantiate(w).then(i=>{console.log('deathSweepFull:',typeof i.instance.exports.deathSweepFull)})})\""},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"10.9.8","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"22.23.1","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"wabt":"^1.0.39"},"_npmOperationalInternal":{"tmp":"tmp/jygame_0.8.6_1784890460257_0.28705690842471476","host":"s3://npm-registry-packages-npm-production"}},"0.8.7":{"name":"jygame","version":"0.8.7","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.8.7","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"9f76167de1a8bcdfb5fbd2eb0bade72c9a82d74b","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.8.7.tgz","fileCount":363,"integrity":"sha512-bglRljvVYzT64k+WwiKgrxP+V/kFb1yJae+8yZT9ymCgWWEMCt1oUgXfZZf/V8BOny/YMG9FSiDFD7Zr5NWGpA==","signatures":[{"sig":"MEUCIF2Kqq+vQXLluD9nMq5jF71hb2t0l1qknHQC0y0HnNGtAiEA9Ik1md5fUApGHmxNbwpRwzA0igi9Ev2/WV9MPKjkRrY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1036279},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"f820d441b6a7f09490cd566274a54b27d97e2946","scripts":{"test":"echo \"No tests yet\" && exit 0","build:wasm":"node tools/particles/build-wasm.mjs","build:wasm:verify":"node -e \"import('fs').then(f=>{const w=f.readFileSync('particles/backends/death_sweep.wasm');WebAssembly.instantiate(w).then(i=>{console.log('deathSweepFull:',typeof i.instance.exports.deathSweepFull)})})\""},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"10.9.8","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"22.23.1","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"wabt":"^1.0.39"},"_npmOperationalInternal":{"tmp":"tmp/jygame_0.8.7_1785142477587_0.5383134836743217","host":"s3://npm-registry-packages-npm-production"}},"0.8.8":{"name":"jygame","version":"0.8.8","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.8.8","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"ba21386832ab88330fc4635579bf345ba7fded4e","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.8.8.tgz","fileCount":371,"integrity":"sha512-sKx1LuvtcrAzE/InPvWOxaX15gI8W0B1amTQ4WtvB+Rb9hNfgSMcWqprBNi5EUJ44Ekpld7pYQ4kuuszWnfiow==","signatures":[{"sig":"MEQCIDnn+mYX3D8KqalND3bC+XUVsC5ZQXLsyFRNsykAYjdKAiBfwvxpihn2y/rZYLt1c8OeyK5u69yiHFHfFDuavkMImQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1098383},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"b05fbf213cf2cab2e846b2c5c8cbe9bcd45152b4","scripts":{"test":"echo \"No tests yet\" && exit 0","build:wasm":"node tools/particles/build-wasm.mjs","build:wasm:verify":"node -e \"import('fs').then(f=>{const w=f.readFileSync('particles/backends/death_sweep.wasm');WebAssembly.instantiate(w).then(i=>{console.log('deathSweepFull:',typeof i.instance.exports.deathSweepFull)})})\""},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"10.9.8","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"22.23.1","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"wabt":"^1.0.39"},"_npmOperationalInternal":{"tmp":"tmp/jygame_0.8.8_1785597078749_0.5513408076243622","host":"s3://npm-registry-packages-npm-production"}},"0.8.9":{"name":"jygame","version":"0.8.9","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.8.9","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"d13c6c937ecc6c9af1fd1962c52adb01345d4e0d","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.8.9.tgz","fileCount":401,"integrity":"sha512-aIkQ14vEbSA58NQyrQ0DuBF5ah6jBa9MDpeGKaXDu/dQEtwo7pPuW5re74imNCzKLYHQvnCDVyrQJpbW3yETrQ==","signatures":[{"sig":"MEQCIF1WI4jy2TlqwuohZlaFYdC8+4StM0+JR3S7XpDGTdYKAiBGKh/I3Kxh82UK67IqgPMS5OwTqIIVnfoAWyanncCX3w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1311680},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"4a3e6b934e4768471703bb46002e8707b979d62d","scripts":{"test":"echo \"No tests yet\" && exit 0","build:wasm":"node tools/particles/build-wasm.mjs","build:wasm:verify":"node -e \"import('fs').then(f=>{const w=f.readFileSync('particles/backends/death_sweep.wasm');WebAssembly.instantiate(w).then(i=>{console.log('deathSweepFull:',typeof i.instance.exports.deathSweepFull)})})\""},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"10.9.8","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"22.23.1","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"wabt":"^1.0.39"},"_npmOperationalInternal":{"tmp":"tmp/jygame_0.8.9_1786569948518_0.10704399908443385","host":"s3://npm-registry-packages-npm-production"}},"0.8.10":{"name":"jygame","version":"0.8.10","keywords":["game","game-development","2d","canvas","framework"],"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","_id":"jygame@0.8.10","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"dist":{"shasum":"e449322a0883894b92511e847223fbdbb20f1bae","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.8.10.tgz","fileCount":417,"integrity":"sha512-vbym2lqr9wTGZe1p7xFSwnO0aYwLUKMH9A3dXuRTwHotv7cFjQoupTXdJhgwiUaTOXCfPKtAunvFz+mfN39pdw==","signatures":[{"sig":"MEUCICsbb30prNOi4y2o2/NnKPJ9dkfXDenSxcVydpmWYIn7AiEAue3v8QPb9lcC6RkXLslq9rfJ/r+l+j1fcTB2eh7iQe4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1421668},"main":"./jygame.js","type":"module","exports":{".":"./jygame.js"},"gitHead":"63f43b793cb0900dc9c08e2218cc20a4385cc1e4","scripts":{"test":"echo \"No tests yet\" && exit 0","build:wasm":"node tools/particles/build-wasm.mjs","build:wasm:verify":"node -e \"import('fs').then(f=>{const w=f.readFileSync('particles/backends/death_sweep.wasm');WebAssembly.instantiate(w).then(i=>{console.log('deathSweepFull:',typeof i.instance.exports.deathSweepFull)})})\""},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"repository":{"url":"git+https://github.com/Bouzidi-Youssef/Jygame.git","type":"git"},"_npmVersion":"12.0.2","description":"A lightweight 2D game framework for the browser","directories":{},"sideEffects":false,"_nodeVersion":"26.2.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"wabt":"^1.0.39"},"_npmOperationalInternal":{"tmp":"tmp/jygame_0.8.10_1787510124242_0.8198401957619699","host":"s3://npm-registry-packages-npm-production"}},"0.8.11":{"name":"jygame","version":"0.8.11","description":"A lightweight 2D game framework for the browser","type":"module","main":"./jygame.js","exports":{".":"./jygame.js"},"keywords":["game","game-development","2d","canvas","framework"],"repository":{"type":"git","url":"git+https://github.com/Bouzidi-Youssef/Jygame.git"},"homepage":"https://jygame-documentation.vercel.app/","bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"license":"GPL-3.0-only","author":{"name":"Bouzidi Youssef"},"sideEffects":false,"scripts":{"test":"echo \"No tests yet\" && exit 0","build:wasm":"node tools/particles/build-wasm.mjs","build:wasm:verify":"node -e \"import('fs').then(f=>{const w=f.readFileSync('particles/backends/death_sweep.wasm');WebAssembly.instantiate(w).then(i=>{console.log('deathSweepFull:',typeof i.instance.exports.deathSweepFull)})})\""},"devDependencies":{"wabt":"^1.0.39"},"dependencies":{},"gitHead":"d143bc737f81eaa55217dcda73eda383eb77315b","_id":"jygame@0.8.11","_nodeVersion":"26.2.0","_npmVersion":"12.0.2","dist":{"integrity":"sha512-W7NkhzGdPv3A3zfd56Wvnd1Fgahcw4Evzn4c2gkxp9fW/OT304zutz/MSn5XgOcpKqAbvyiV59kuzMuWRvOKtQ==","shasum":"e5a65b0ea19d509906f58fe02615cce3a10fbbcf","tarball":"https://registry.npmjs.org/jygame/-/jygame-0.8.11.tgz","fileCount":417,"unpackedSize":1421754,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCEaWFulLHfV6ZQ5MY3kYUPP96e4haERi1Aj7mP/62x0wIhAPSlwGuERFnPewFJvJlOYThzUxIYIXtf0sBXTsyPFnu8"}]},"_npmUser":{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"},"directories":{},"maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/jygame_0.8.11_1787609528147_0.7828555774405825"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-04T21:36:15.352Z","modified":"2026-08-24T22:12:08.808Z","0.1.0":"2026-06-04T21:36:15.556Z","0.2.0":"2026-06-05T15:31:24.295Z","0.3.0":"2026-06-06T19:43:04.221Z","0.4.0":"2026-06-08T14:36:21.487Z","0.4.1":"2026-06-08T14:44:54.642Z","0.5.0":"2026-06-09T11:22:18.380Z","0.6.0":"2026-06-14T00:32:06.043Z","0.7.0":"2026-06-16T11:49:10.617Z","0.7.1":"2026-06-16T14:07:05.656Z","0.7.2":"2026-06-17T13:07:10.397Z","0.7.3":"2026-06-19T22:40:27.371Z","0.7.4":"2026-06-21T10:09:35.366Z","0.7.5":"2026-06-22T18:12:54.794Z","0.7.6":"2026-06-24T15:29:29.044Z","0.7.7":"2026-06-24T16:02:36.604Z","0.7.8":"2026-07-01T00:35:04.561Z","0.7.9":"2026-07-02T10:45:25.792Z","0.8.0":"2026-07-02T10:57:05.287Z","0.8.1":"2026-07-05T18:41:47.419Z","0.8.2":"2026-07-12T04:28:55.306Z","0.8.3":"2026-07-12T13:49:29.800Z","0.8.4":"2026-07-13T08:13:17.454Z","0.8.5":"2026-07-15T11:20:41.541Z","0.8.6":"2026-07-24T10:54:20.410Z","0.8.7":"2026-07-27T08:54:37.825Z","0.8.8":"2026-08-01T15:11:18.958Z","0.8.9":"2026-08-12T21:25:48.742Z","0.8.10":"2026-08-23T18:35:24.383Z","0.8.11":"2026-08-24T22:12:08.331Z"},"bugs":{"url":"https://github.com/Bouzidi-Youssef/Jygame/issues"},"author":{"name":"Bouzidi Youssef"},"license":"GPL-3.0-only","homepage":"https://jygame-documentation.vercel.app/","keywords":["game","game-development","2d","canvas","framework"],"repository":{"type":"git","url":"git+https://github.com/Bouzidi-Youssef/Jygame.git"},"description":"A lightweight 2D game framework for the browser","maintainers":[{"name":"youssef-bouzidi","email":"youssefbouzidi727@gmail.com"}],"readme":"<p align=\"center\">\n  <img src=\"./logo_jygame.avif\" alt=\"JyGame Logo\" width=\"400\">\n</p>\n\n<div align=\"center\">\n\n⭐ **Consider Supporting The Project with a star** ⭐\n\n</div>\n\n# jygame\n\nA lightweight 2D game framework for the browser built on an **archetype-based ECS** architecture.\n\n```js\nimport {\n  Game, Scene,\n  Sprite, Colors,\n  ActionKind, CompositeBinding, KeyBinding, KeyCode,\n} from \"jygame\";\n\nclass MyScene extends Scene {\n  onEnter() {\n    this.player = new Sprite(100, 100, 32, 32, this.world);\n    this.player.style.fill = Colors.GreenShades.MagicalMalachite;\n\n    const move = new CompositeBinding(ActionKind.VECTOR2, [\n      { binding: new KeyBinding(KeyCode.KEY_D),        vector: [ 1,  0] },\n      { binding: new KeyBinding(KeyCode.KEY_A),        vector: [-1,  0] },\n      { binding: new KeyBinding(KeyCode.KEY_W),        vector: [ 0, -1] },\n      { binding: new KeyBinding(KeyCode.KEY_S),        vector: [ 0,  1] },\n      { binding: new KeyBinding(KeyCode.ARROW_RIGHT),  vector: [ 1,  0] },\n      { binding: new KeyBinding(KeyCode.ARROW_LEFT),   vector: [-1,  0] },\n      { binding: new KeyBinding(KeyCode.ARROW_UP),     vector: [ 0, -1] },\n      { binding: new KeyBinding(KeyCode.ARROW_DOWN),   vector: [ 0,  1] },\n    ]);\n    this._actionMap.bind(\"move\", move, ActionKind.VECTOR2);\n  }\n\n  update(dt) {\n    const speed = 200;\n    const m = this._actionMap.getState(\"move\").vector;\n    this.player.velocity.x = m.x * speed;\n    this.player.velocity.y = m.y * speed;\n  }\n\n  render(ctx) {\n    ctx.fillStyle = this.player.style.fill;\n    ctx.fillRect(this.player.x, this.player.y, this.player.width, this.player.height);\n  }\n}\n\nconst game = new Game({ parent: document.body, width: 800, height: 600 });\ngame.run(new MyScene());\n```\n\n## Install\n\n```sh\nnpm install jygame\n```\n\n## Documentation\n\nFull API reference, guides, and examples: [jygame-documentation.vercel.app](https://jygame-documentation.vercel.app/)\n\n## API\n\n### ECS Core\n\n| Import | Description |\n|---|---|\n| `World` | Archetype-based ECS world. Owns all entities, components, systems, queries, and resources. `update(dt)` runs all registered systems in priority order. |\n| `System` | Base class for all systems. Override `run(ctx, dt)` or use lifecycle hooks (`onInit`, `onBegin`, `onEnd`). Systems declare their component queries and execute on matching archetypes. |\n| `ArchetypeSystem` | Base class for systems that operate on archetype tables. Subclasses override `processEntity(entity, dt)` or `processTable(archetype, dt)` for bulk operations. |\n| `QueryView` | Iterable view into matching entities. Created via `world.query(Transform, Velocity)`. Supports `for...of`, `.forEach()`, `.length`, and optional `TagComponent` filters. |\n| `ComponentSignature` | Bitmask-based signature for matching archetypes to queries. Used internally by `QueryEngine` for O(1) archetype matching. |\n| `EntityManager` | Manages entity creation/destruction, archetype assignment on component add/remove, and entity-to-id mapping. |\n| `ComponentRegistry` | Global registry of component schemas. Each component type gets a unique numeric ID and an `ObjectSchema` describing its field layout for typed-array storage. |\n| `QueryEngine` | Maintains registered queries and notifies them when archetypes are created/destroyed. Supports `beforeAdd`/`afterAdd`/`beforeRemove`/`afterRemove` hooks. |\n| `SystemContext` | Per-world context object passed to system `run()`. Provides access to resources, queries, and the entity manager. |\n| `SystemScheduler` | Runs systems in priority order with `before`/`after` dependency resolution. |\n| `Table` | Columnar data store (SoA — Structure of Arrays) for a single archetype. Each component field is a typed array column. |\n\n### ECS Components\n\n| Import | Description |\n|---|---|\n| `Transform` | Position (`x`, `y`), rotation, scale — the single source of truth for world position. Field layout: `{ x: float64, y: float64, rotation: float64, scale: float64 }` |\n| `WorldTransform` | Computed world-space transform (updated by `HierarchySystem`). Same field layout as `Transform`. |\n| `Velocity` | Per-axis velocity (`x`, `y`) as float64. |\n| `Collider` | AABB dimensions (`width`, `height`) with static helpers. |\n| `Renderable` | Image or shape style. `draw(ctx, w, h)` method. |\n| `Visible` | Tag/flag component: `{ visible: boolean }`. |\n| `RenderBounds` | Cached render bounds for culling (`x`, `y`, `w`, `h`). |\n| `Animation` | Animation state: `{ current: string, frame: uint32, elapsed: float64, playing: boolean }`. |\n| `Trail` | Trail effect state: `{ maxLength, interval, elapsed, points }`. |\n| `Text` | Text state: `{ fontHandle: u16, contentHandle: u32, align: u8, letterSpacing: f32, version: u32 }`. Content strings and cached layouts live in `TextResourcePool`, referenced by `contentHandle`. |\n| `Parent` | Single-component parent reference: `{ entity: uint32 }`. |\n| `Children` | Empty-schema tag component. Entities with children have this component. |\n\n### ECS Tag Components\n\n| Import | Description |\n|---|---|\n| `EnemyTag` | Empty schema — marks an entity as an enemy. |\n| `PlayerTag` | Empty schema — marks an entity as the player. |\n| `ProjectileTag` | Empty schema — marks an entity as a projectile. |\n| `StaticTag` | Empty schema — marks an entity as static (skip collision checks). |\n\n### ECS Systems\n\n| Import | Description |\n|---|---|\n| `MovementSystem` | Reads `Velocity` + `Transform`, writes `Transform.x/y`. Priority: 0. |\n| `AnimationSystem` | Reads `Animation` + `Renderable`, advances frames. Priority: 1. |\n| `CollisionSystem` | Manages broad-phase strategies and collision queries. Priority: 2. |\n| `RenderSystem` | Reads `Transform` + `Renderable` + `Visible`, draws to canvas with camera culling. Priority: 3. |\n| `TrailSystem` | Updates trail point history for entities with `Trail` component. Priority: 4. |\n| `TextSystem` | Lays out `Transform` + `Renderable` + `Text` + `Visible` entities into `RenderQueue` glyph commands. Priority: 4 (after `RenderSystem`'s queue-clear). |\n| `HierarchySystem` | Propagates parent transforms to children (BFS from dirty roots). Priority: -10 (before all others). |\n\n### ECS Resources\n\n| Import | Description |\n|---|---|\n| `SpatialHash` | Spatial partitioning for broad-phase collision acceleration. Stamp-based single-entity dedup. |\n| `CollisionQuery` | Collision query helpers registered on the world. |\n| `RenderQueue` | Sorted render command queue. Supports z-ordering. |\n| `CanvasContext` | Holds the 2D rendering context for the scene. |\n| `TrailManager` | Manages trail effect state across entities. |\n| `TrailBuffer` | Point history buffer for a single trail. |\n| `TextResourcePool` | Dense generation-handled resource pool owning text content strings and cached glyph layouts. Content resources are referenced from the `Text` component via packed `(slot << 16 | generation)` handles. |\n| `AnimationClip` | Frame sequence descriptor with per-clip FPS. |\n| `AnimationClipRegistry` | Global registry of named animation clips. |\n| `AnimationCallbacks` | Per-entity completion observers for the animation system. |\n| `AnimationPlayback` | Per-entity playback intent (persistent request, one-shot, forced, queue). |\n| `HierarchyGraph` | Manages parent-child relationships and dirty-set propagation. |\n| `EventChannel` | Typed event channel for entity-component events. |\n| `Events` | High-level event API for watching component add/remove/change. |\n| `Prefab` | Reusable entity template. Instantiate via `prefab.create(world)`. |\n| `Serializer` | Serializes/deserializes entire world state to/from JSON. |\n| `StreamingCell` | Logical collection of entities within a world. Named, loadable/unloadable. |\n| `StreamingManager` | Manages StreamingCell lifecycle, load/unload orchestration. |\n| `SceneManager` | Manages registry and stack of ECS scenes. |\n\n### Game Engine\n\n| Import | Description |\n|---|---|\n| `Game` | Main game loop with fixed timestep, canvas setup, UI layer, scene stack (`pushScene`, `popScene`, `replaceScene`, `peekScene`, `switchScene`), and lifecycle management. Accepts `debug` option (default `false`) — set `debug: true` and press **Ctrl+F3** to open the debug workspace. |\n| `Scene` | Engine Scene (extends ECS Scene). Lifecycle hooks (`onEnter`, `onExit`, `onCreate`, `pause`, `resume`, `update`, `interpolate`, `render`, `renderUI`, `renderDOM`), blocking properties, stack delegators, auto-cleaned event helpers (`on`, `onSwipe`, `onTap`, `cleanup`), and built-in `_actionMap`/`_inputContext` for input. |\n| `DefaultWorldBuilder` | Creates a pre-configured `World` with all engine components, systems, and resources registered. |\n| `Sprite` | Convenience entity wrapper with `Transform`, `Collider`, `Velocity`, `Renderable`, `Visible`. Exposes `x`, `y`, `width`, `height`, `angle`, `scale`, `velocity`, `image`, `style` shorthands. |\n| `Text` | World-space text entity for bitmap fonts. Composes `Transform` + `Renderable` + `Visible` + `Text`. Exposes `x`, `y`, `angle`, `scale`, `visible`, `value`/`text`/`string`, `font`, `color`, `align`, `letterSpacing`, `layer`, `depth`, `width`, `height`. Also exported as `TextComponent`. |\n| `TextSystem` | ECS system that lays out `Text` entities into `RenderQueue` glyph commands. Priority 4 (after `RenderSystem`'s queue-clear). |\n| `TextResourcePool` | World resource holding text content strings, cached glyph layouts, and measured bounds. |\n| `Group` | Entity container. Iterable (`for...of`). Collision queries delegate to `CollisionSystem`. Optional `SpatialHash` acceleration. `dispose()` for cleanup. |\n| `Camera` | View abstraction — world position, zoom, rotation, coordinate conversion. `Camera.main` auto-set on first construction. `Camera.setMain()` for explicit assignment. |\n| `Vec2` | 2D vector with add, sub, scale, dot, normalize, rotate, lerp. |\n| `Rect` | AABB rectangle utility with collision, containment, overlap, and anchor helpers. |\n| `Clock` | Fixed-timestep accumulator for deterministic updates. |\n| `Timer` | Countdown timer with optional looping. |\n| `Input` | The input facade. Resolves actions, pointer, touch, gamepad, wheel and gestures through the Input System below. |\n| `State` | Observable state container with subscribe/unsubscribe. |\n| `Storage` | `localStorage` wrapper with JSON serialization. |\n| `Color`, `Colors` | Color class with parsing, manipulation, and 96 named palettes. |\n| `Palettes` | Curated color palette collections (96 palettes, ~15 colors each). |\n| `ImageLoader` | Image preloading with in-memory cache. |\n| `FontLoader` | FontFace loading for custom web fonts. |\n| `AudioLoader` | Audio asset loader with in-memory cache. |\n| `AudioManager` | Sound registry with `add(key, asset)` / `get(key)` / `remove(key)`. Manages `Sound` lifecycle. |\n| `AudioScene` | Per-scene audio context with spatial audio support. |\n| `AudioListener` | Positional audio listener (tracks camera position). |\n| `AudioGroup` | Named group of audio instances with shared volume/pause/resume. |\n| `AudioInstance` | Single playable audio instance with volume/loop/pitch/pan. |\n| `AudioDefinition` | Audio asset descriptor with metadata. |\n| `Pool` | Low-level object pool for allocation-free reuse. |\n| `ActivePool` | Lifecycle-aware object pool. Tracks active/inactive objects, O(1) acquire/release via index-tagged objects. |\n\n### Input System\n\n| Import | Description |\n|---|---|\n| `InputSystem` | Orchestrates per-frame input: `snapshot()` → `backend.poll()` → notify consumers → `devices.update()` → `contextStack.evaluate()` → `events.clear()`. |\n| `InputEvent` | Typed event with data payload and metadata. |\n| `InputEventQueue` | Bounded FIFO queue with tier-aware prioritisation. |\n| `EventType` | Enum: `KEY_DOWN`, `KEY_UP`, `POINTER_DOWN`, `POINTER_MOVE`, `POINTER_UP`, `WHEEL`, `COMPOSITION_*`, `GESTURE`, `GAMEPAD_*`. |\n| `Device` | Base class for input devices. Each device `update(queue)` peeks at events read-only. |\n| `DeviceRegistry` | Maps device types to instances. `get(ClassType)` / `getAll(ClassType)`. |\n| `InputBackend` | Abstract backend. `start()` / `stop()` / `poll(queue)`. |\n| `BrowserBackend` | DOM backend — binds `keydown`/`keyup`/`pointer*`/`wheel`/`composition*` on a target element. |\n| `TestBackend` | Programmatic backend for injecting events in tests. Also accepts fake gamepad snapshots via `setGamepads(pads)`. |\n| `KeyCode` | Enum of all physical key codes (e.g. `KEY_W`, `SPACE`, `ARROW_UP`). |\n| `Modifier` | Bitmask flags: `SHIFT`, `CTRL`, `ALT`, `META`. |\n| `Keyboard` | Device. Tracks `pressed`/`justPressed`/`justReleased`/`repeat` for every physical key, plus the logical `event.key` value of each press. |\n| `Gamepad` | Device. Polls the Web Gamepad API, diffs button edges and axes per frame, and tracks up to 4 pads by index. Toggleable via `enabled`; emits `GAMEPAD_*` events; supports minimum-config filtering and axis move thresholds. |\n| `GamepadButton` | Enum of standard button indices (`A`, `B`, `X`, `Y`, `LB`, `RB`, `LT`, `RT`, `BACK`, `START`, `GUIDE`, `LSB`, `RSB`, `DPAD_*`). |\n| `GamepadAxis` | Enum of axis indices (`LEFT_X`, `LEFT_Y`, `RIGHT_X`, `RIGHT_Y`). |\n| `GamepadState` | Per-pad button/axis state with digital edges and analog values. |\n| `MouseButton` | Enum: `LEFT`, `MIDDLE`, `RIGHT`, `BACK`, `FORWARD`. |\n| `Mouse` | Device. Tracks button states, position, and wheel delta. `resetWheel()` to clear. |\n| `PointerType` | Enum: `MOUSE`, `TOUCH`, `PEN`. |\n| `PointerManager` | Device. Tracks all active pointers with history storage. |\n| `TouchSurface` | Device. Multi-touch contact tracking. |\n| `Stylus` | Device. Pen-specific data (pressure, tilt, twist). |\n| `TextInput` | Device. IME composition events and consumed character queue. |\n| `GestureType` | Enum: `TAP`, `DOUBLE_TAP`, `LONG_PRESS`, `DRAG`, `SWIPE`, `PINCH`, `ROTATE`, `PAN`. |\n| `GestureEvent` | Gesture event with type, position, velocity, motion deltas. |\n| `GestureEngine` | Device. Reads from `PointerManager`, pushes `GESTURE` events. |\n| `GestureRecognizer` | Base class. 8 built-in recognizers: `TapRecognizer`, `DoubleTapRecognizer`, `LongPressRecognizer`, `DragRecognizer`, `SwipeRecognizer`, `PinchRecognizer`, `RotateRecognizer`, `PanRecognizer`. |\n\n### Input Actions\n\n| Import | Description |\n|---|---|\n| `ActionKind` | Enum: `DIGITAL` (on/off), `VECTOR2` (analogue 2D). |\n| `ActionState` | Per-action runtime state: `pressed`, `justPressed`, `justReleased`, `strength`, `vector`, `buffer(durationMs)` / `consumeBuffered()`. |\n| `Binding` | Base class for all bindings. `evaluate(deviceRegistry)` returns strength `[0, 1]`. |\n| `KeyBinding` | Evaluates true when a specific `KeyCode` is held. |\n| `MouseButtonBinding` | Evaluates true when a specific `MouseButton` is held. |\n| `WheelBinding` | Reads `Mouse.wheel` delta. |\n| `ChordBinding` | Combines multiple bindings with optional modifers — all must be active. |\n| `CompositeBinding` | Aggregates sub-bindings with per-direction vectors, normalised to unit circle. Ideal for WASD + Arrow stick emulation. |\n| `GestureBinding` | Matches a `GestureType` (e.g. swipe, pinch). |\n| `GamepadButtonBinding` | Gamepad button binding. Evaluates the button's analog value (0–1); digital buttons read 0/1, triggers carry their strength. |\n| `GamepadAxisBinding` | Gamepad axis binding. Evaluates the axis magnitude (0–1). |\n| `GamepadStickBinding` | Gamepad stick as a 2D vector binding for VECTOR2 actions. |\n| `ActionEvaluator` | Runs bindings through optional processors, picks the highest-strength result, and updates the corresponding `ActionState`. |\n| `Processor` | Base class for post-processing binding strength/vector. |\n| `DeadZoneProcessor` | Discards values below a threshold. |\n| `ScaleProcessor` | Multiplies strength by a factor. |\n| `InvertProcessor` | Negates strength or vector axis. |\n| `SmoothProcessor` | Moving-average filter for analogue input. |\n| `ActionMap` | Collection of named actions, each with a list of bindings and an `ActionState`. `bind(name, binding, kind)` / `getState(name)` / `serialize()` / `static deserialize(data)`. |\n| `InputContext` | Named container for an `ActionMap` with `priority` and `consumePolicy` (\"block\"/\"pass\"). |\n| `ContextStack` | Ordered stack of `InputContext`s. Higher-priority contexts shadow lower ones. `evaluate(deviceRegistry)` runs all contexts in priority order. `push()` primes a new context against live device state, so a key already held when the context opens is not reported as a fresh press. |\n| `GestureDispatcher` | Callback layer over `GestureEngine`. Backs `Input.onTap`/`onSwipe` and `Scene.onTap`/`onSwipe`/`onGesture`; `on(type, cb)` returns an unsubscribe function. |\n| `Space` | Enum: `SCREEN`, `VIEWPORT`, `WORLD`, `UI`. |\n| `CoordinateSystem` | Manages transformations between all four spaces. Supports `project`/`unproject` and `worldToScreen`/`screenToWorld` camera interfaces. |\n\n#### Physical vs logical keys\n\n`Input.pressed`, `Input.down` and `Input.released` accept both **physical**\nkeyboard codes and **logical** keyboard keys. The identifier you pass decides\nwhich one is queried — there is no second API and no keyboard-layout setting.\n\n```js\n\"KeyW\" // physical — the key position represented by KeyboardEvent.code\n\"W\"    // logical — the key value represented by KeyboardEvent.key\n```\n\n```js\n// Physical — useful when the game cares about where the key is on the\n// keyboard. Layout-independent, so \"KeyW\" is the same physical position on\n// QWERTY, AZERTY, QWERTZ, Dvorak, ...\nInput.down(\"KeyW\")\nInput.pressed(\"KeyA\")\nInput.released(\"Space\")\n\n// Logical — useful when the actual key value the keyboard produces matters.\n// On a French AZERTY keyboard, the key labelled \"M\" reports event.key === \"m\"\n// but event.code === \"Semicolon\"; the engine never needs to know the layout.\nInput.pressed(\"M\")\nInput.down(\"m\")\n```\n\nPhysical input answers *\"which physical key was pressed?\"* (`KeyboardEvent.code`);\nlogical input answers *\"what key value did the keyboard produce?\"*\n(`KeyboardEvent.key`). The two are genuinely independent, and the same key\nevent can be read either way:\n\n```js\nInput.pressed(\"KeyM\") // physical: true when event.code === \"KeyM\"\nInput.pressed(\"M\")    // logical:  true when event.key === \"M\"\n```\n\nResolution rules:\n\n- An identifier that matches a recognized physical `KeyboardEvent.code`\n  (`KeyA`…`KeyZ`, `Digit0`…`Digit9`, `Space`, `Enter`, `Tab`, `Escape`,\n  `ArrowUp`, `ShiftLeft`, `F1`…`F12`, `Semicolon`, `Numpad0`, …) queries the\n  physical state. Matching is case-insensitive (`\"keyw\"` works), but a made-up\n  name like `\"KeyFoo\"` is not a physical code.\n- Everything else queries the logical state against the exact `event.key`\n  value. Logical keys are **case-sensitive** — `\"m\"` and `\"M\"` are different\n  logical values, exactly as the browser reports them.\n- Stable special keys (`Tab`, `Enter`, `Escape`, `Space`, `ArrowUp`,\n  `Backspace`, `Shift`, …) keep working exactly as before.\n- Long-standing aliases such as `\"UP\"`, `\"ARROW_UP\"`, `\"SPACE\"`, `\"SHIFT\"`,\n  `\"PAGE_UP\"` still resolve to their physical keys.\n\nYou never tell Jygame which keyboard layout the player uses. The browser\nalready exposes both concepts — `event.code` (position) and `event.key`\n(value) — and Jygame passes both through directly.\n\nAction bindings follow the exact same convention: a Scene's `input` map or\n`Input.bind(\"jump\", \"KeyW\")` accepts physical and logical identifiers exactly\nlike the query methods, and the `\"wasd\"` / `\"arrowkeys\"` movement shorthands\nkeep their physical, layout-independent meaning.\n\n### Gamepad\n\nControllers arrive through the Web Gamepad API and are exposed both by name\nand through `Input.gamepad`. A connected pad answers the query methods with\n`\"PAD_*\"` identifiers (and `\"GAMEPAD_*\"` aliases), defaulting to gamepad 0:\n\n```js\nif (Input.pressed(\"PAD_A\"))   { this.jump(); }\nif (Input.down(\"PAD_LB\"))     { /* shoulder held */ }\nconst throttle = Input.value(\"PAD_RT\");        // analog 0–1\nconst dir = Input.axis(\"PAD_LEFT_STICK\");      // dead-zoned { x, y }\n```\n\nButton names: `PAD_A/B/X/Y`, `PAD_LB/RB`, `PAD_LT/RT`, `PAD_BACK/START/GUIDE`,\n`PAD_LSB/RSB`, `PAD_DPAD_UP/DOWN/LEFT/RIGHT`. Sticks: `PAD_LEFT_STICK` /\n`PAD_RIGHT_STICK` (via `axis()`), or the scalar axes `PAD_LEFT_X/Y`,\n`PAD_RIGHT_X/Y` (via `value()`).\n\n`Input.gamepad` is the structured view — handy for multi-pad games and\nrebinding UIs:\n\n```js\nif (Input.gamepad.pressed(GamepadButton.A, 0)) { this.jump(); }\nconst pad = Input.gamepad.get(0);   // { id, buttons: { a: { pressed, value }, ... }, sticks }\nconst dir = Input.gamepad.stick(0, \"left\");     // dead-zoned\n```\n\nPolling can be toggled, filtered and observed:\n\n```js\nInput.gamepad.enabled = false;   // stop the per-frame poll (default is on)\nInput.gamepad.axisMoveThreshold = 0.1; // below this, \"axis\" events stay silent\n\n// ignore junk devices (touchpads, mice, web cameras)\nInput.gamepad.setMinimumGamepadConfiguration({ axis: 4, buttons: 8 });\n\n// scripted responses, Excalibur-style\nconst stop = Input.gamepad.on(\"button\", (e) => {\n  if (e.gamepadIndex === 0 && e.button === GamepadButton.A) this.jump();\n});\nInput.gamepad.on(\"axis\", (e) => {\n  if (e.axis === GamepadAxis.LEFT_X) this.steer(e.value);\n});\nstop(); // unsubscribe\n```\n\nQuery helpers accept a per-call threshold for touchy controllers:\n`Input.gamepad.value(GamepadButton.RT, 0, 0.7)` reads a trigger as 0 below\n0.7, `Input.gamepad.axis(0, GamepadAxis.LEFT_X, 0.2)` ignores stick drift,\nand `Input.gamepad.isDown(GamepadButton.RT, 0, 0.7)` treats a button as\npressed only once it reaches the value.\n\nSticks and triggers are analog: triggers carry their pull strength through\n`value()` and stay \"down\" while pressed, and sticks apply a radial dead zone\n(0.2 by default) before reporting a vector. Gamepad identifiers also work in\nbindings — `jump: \"PAD_A\"` in a Scene's `input` or `Input.bind(\"move\",\n\"PAD_LEFT_STICK\")` for a vector action. Multiple gamepads are addressed by\nindex through `Input.gamepad` (bindings target gamepad 0).\n\nMovement has shorthands too, mirroring `\"wasd\"` / `\"arrowkeys\"`:\n\n```js\ninput: {\n  move: [\"padstick\", \"padd\"],   // left stick + d-pad both drive \"move\"\n  // or: \"pad\" (left stick + d-pad), \"padstick\" (stick only), \"padd\" (d-pad only)\n}\n```\n\n`\"padstick\"` is the left stick (analog 360°), `\"padd\"` is the d-pad (digital\n4/8-direction), and `\"pad\"` means both. They mix freely with the keyboard\nshorthands — `[\"wasd\", \"padstick\"]` gives you keyboard and stick movement on\nthe same action.\n\n### Debug & Diagnostics\n\nThe debug system is opt-in — pass `debug: true` to the Game constructor to enable it. Press **Ctrl+F3** at any time to open the standalone debug workspace in a new window — it displays real-time frame metrics, a system timeline, metric browser, event log, and capture viewer.\n\nPress backtick (`` ` ``) to toggle the in-game overlay, or call `game.debug.show()` programmatically.\n\n`game.debug` is never null — with debug disabled it is a safe no-op, so `game.debug.toggle()` in game code warns once instead of crashing the loop.\n\nSnapshot streaming to the workspace is itself opt-in: the game only builds and sends per-frame world snapshots while a workspace window is open and subscribed. With `debug: true` but no workspace attached, the per-frame cost is a single timestamp comparison.\n\nDebug is off by default, but you can also pass it explicitly for production builds:\n\n```js\nconst game = new Game({ parent: \"#game\", width: 800, height: 600, debug: false });\n```\n\nThis strips diagnostics, the debug overlay, snapshot broadcasting, and the Ctrl+F3 shortcut entirely.\n\n| Import | Description |\n|---|---|\n| `Diagnostics` | Frame-level metric aggregation with timers, counters, and gauges. Built-in budget/warn/crit thresholds. |\n| `DiagnosticsConfig` | Configuration for diagnostics (metric registration, capture limits). |\n| `MetricRegistry` | Global registry of typed metrics. |\n| `MetricDescriptor` | Descriptor for a single metric (name, category, unit, type, budget). |\n| `MetricType` | Enum: `TIMER`, `GAUGE`, `COUNTER`. |\n| `MetricUnit` | Enum: `MILLISECONDS`, `FPS`, `COUNT`, `BYTES`, `PERCENT`. |\n| `MetricCategory` | Enum: `FRAME`, `ECS`, `RENDER`, `INPUT`, `PHYSICS`, `AUDIO`, `ASSETS`, `STREAMING`, `SCENE`. |\n| `CPUTimer` | High-resolution CPU timer backed by `performance.now()`. |\n| `FrameStorage` | Circular buffer of frame snapshots. |\n| `FrameSnapshot` | Snapshot of all metric values at a given frame. |\n| `FrameHistory` | Rolling window of frame data for trend analysis. |\n| `TriggerEngine` | Fires callbacks when metrics cross configurable thresholds. |\n| `Analysis` | Frame analysis utilities (min, max, avg, percentile over a window). |\n| `CaptureResult` | Snapshot of captured metric data. |\n| `resolveMetricIds` | Resolves metric name strings to numeric IDs for fast frame-loop scoping. |\n| `DebugOverlay` | In-game HUD overlay toggled with backtick (`` ` ``). Access via `game.debug`. |\n| `OverlaySession` | Full debug session manager — panels, themes, layout, persistence. |\n| `OverlayContext` | Debug overlay rendering context. |\n| `PanelManager` | Manages debug panel lifecycle. |\n| `LayoutEngine` | Panel layout with `createDefaultLayout()`. |\n| `DarkTheme`, `LightTheme` | Built-in overlay themes. |\n| `PerformancePanel` | Real-time FPS, frame timings, budget bars. |\n| `FrameGraphPanel` | Visual frame-by-frame breakdown (input/update/render). |\n| `TimelinePanel` | System-level timeline view. |\n| `MetricBrowserPanel` | Browse/search all registered metrics. |\n| `EventViewerPanel` | Entity-component event log. |\n| `CaptureBrowserPanel` | Browse saved metric captures. |\n| `SettingsPanel` | Overlay configuration panel. |\n\n### Audio Effects\n\n| Import | Description |\n|---|---|\n| `AudioBackend` | Abstract backend interface for audio playback. |\n| `HtmlAudioBackend` | HTMLAudioElement-based backend. |\n| `WebAudioBackend` | Web Audio API backend with spatial audio support. |\n| `AudioEffect` | Base class for audio effects. |\n| `EffectChain` | Chain of audio effects with connect/disconnect. |\n| `LowPassEffect` | Low-pass filter effect. |\n| `HighPassEffect` | High-pass filter effect. |\n| `BandPassEffect` | Band-pass filter effect. |\n| `DelayEffect` | Delay/echo effect. |\n| `CompressorEffect` | Dynamic range compression. |\n| `DistortionEffect` | Wave-shaping distortion. |\n| `ReverbEffect` | Convolution reverb with IR support. |\n\n### Particle System\n\n| Import | Description |\n|---|---|\n| `ParticleSystem` | SoA particle system with ActivePool-backed lifecycle, modifier pipeline, O(n) update/render, and full statistics. |\n| `Particle` | Lightweight data container for particle effects. Fields: `x`, `y`, `vx`, `vy`, `ax`, `ay`, `life`, `maxLife`, `size`, `rotation`, `alpha`, `color`. |\n| `ParticleEmitter` | Automated spawner on top of `ParticleSystem`. Frame-rate independent accumulator. `start()`, `stop()`, `burst()`, `toggle()`. |\n| `ParticleAsset` | Serializable particle effect definition. |\n| `ParticleEffect` | Runtime particle effect instance from a `ParticleAsset`. |\n| `ParticleAssetRegistry` | Global registry of named `ParticleAsset` definitions. |\n\n### Particle Modifiers\n\n| Import | Description |\n|---|---|\n| `FadeModifier` | Fades alpha over lifetime (`\"out\"`, `\"in\"`, `\"in-out\"`). |\n| `ScaleModifier` | Interpolates size from `from` to `to`. |\n| `VelocityModifier` | Exponential velocity damping with per-axis control. |\n| `ColorModifier` | Color transition (two-stop or multi-stop gradient). |\n| `RotationModifier` | Rotation speed control. |\n| `AnimationModifier` | Per-particle animation state. |\n| `AnimatedSpriteModifier` | Sprite-sheet animation (`once`, `loop`, `pingpong`, `random`). |\n| `WindModifier` | Constant wind force. |\n| `TurbulenceModifier` | Perlin-noise-based turbulence. |\n| `ForceModifier` | Constant force (e.g., gravity). |\n| `AttractionModifier` | Attraction/repulsion toward a point. |\n| `OrbitModifier` | Orbital motion around a point. |\n| `SpawnModifier` | Spawns child particles. |\n| `TrailModifier` | Particle trail effect. |\n| `CollisionModifier` | Particle-world collision. |\n| `KeyframeTrack` | Keyframe-based interpolation for custom modifier values. |\n| `ModifierStack` | Ordered collection of modifiers with priority sorting. |\n| `ModifierRegistry` | Global registry of named modifier types. |\n\n### Emitter Shapes\n\n| Import | Description |\n|---|---|\n| `EmitterShape` | Abstract base for emitter shapes. |\n| `RectangleShape` | Rectangular spawn area. |\n| `CircleShape` | Circular spawn area. |\n| `RingShape` | Annular spawn area. |\n| `LineShape` | Linear spawn area. |\n| `ConeShape` | Conical spawn area. |\n| `PolygonShape` | Arbitrary convex polygon spawn area. |\n| `PathShape` | Bezier/cubic path spawn distribution. |\n| `SplineShape` | Catmull-Rom spline path spawn distribution. |\n| `ShapeRegistry` | Global registry of named emitter shapes. |\n\n## Architecture\n\nSee [`docs/architecture.md`](docs/architecture.md) for the full design.\n\n**Quick summary:** Archetype-based Entity-Component-System architecture.\n\n### World\n\nA `World` owns all entities, components, systems, and resources. Systems\nare registered with a priority and run in order via `world.update(dt)`.\n\n```\nWorld\n├── EntityManager       (create/destroy entities)\n├── ComponentRegistry   (component schema IDs)\n├── QueryEngine         (archetype-indexed queries)\n├── SystemScheduler     (priority-ordered system execution)\n└── Resources           (singletons: SpatialHash, events, prefabs, etc.)\n```\n\n### Archetype Storage\n\nComponents are stored column-wise (SoA) in `Table` instances. Each unique\ncombination of components forms an archetype with its own table.\n\n```\nArchetype Table \"Transform + Renderable + Visible\"\n├── Transform.x:    Float64Array[1000]\n├── Transform.y:    Float64Array[1000]\n├── Transform.rotation: Float64Array[1000]\n├── Transform.scale: Float64Array[1000]\n├── Renderable.image:     (per-row references)\n├── Renderable.style:     (per-row references)\n└── Visible.visible: Uint8Array[1000]\n```\n\nAdding/removing a component moves the entity to a different archetype\ntable. Queries match archetypes by bitmask signature in O(1).\n\n### Systems\n\nSystems extend `System` or `ArchetypeSystem` and declare their component\ndependencies via the base class. The scheduler runs them in priority order:\n\n| Priority | System | Description |\n|---|---|---|\n| -10 | `HierarchySystem` | Propagate parent transforms to children (BFS from dirty roots) |\n| -10 | `SavePrevPositionSystem` | Cache the previous frame's Transform for interpolation |\n| 0 | `MovementSystem` | Apply `Velocity` → `Transform` |\n| 1 | `AnimationSystem` | Advance animation frames |\n| 2 | `CollisionSystem` | Run broad-phase collision queries |\n| 3 | `RenderSystem` | Cull and render visible entities |\n| 4 | `TrailSystem` | Update trail point history |\n| 4 | `TextSystem` | Lay out text entities into `RenderQueue` glyph commands (after `RenderSystem`'s queue-clear) |\n\nSystems access entities through `QueryView` iterables:\n\n```js\nclass GravitySystem extends System {\n  run(ctx, dt) {\n    const view = ctx.queries.get(Transform, Velocity);\n    for (const entity of view) {\n      entity.velocity.y += 9.8 * dt;\n    }\n  }\n}\n```\n\n### Scene\n\nEach `Scene` owns one `World`. The engine `Scene` (core/Scene) extends the\nECS `Scene` (ecs/scene/Scene) and adds DOM integration, input helpers,\nstack navigation, and camera setup.\n\n`DefaultWorldBuilder.createDefault()` creates a World pre-configured with\nall engine components (Transform, Velocity, Collider, Renderable, etc.),\nsystems (Movement, Animation, Collision, Render, Trail, Hierarchy), and\nresources (SpatialHash, RenderQueue, AnimationClipRegistry, etc.).\n\n### Sprite and Group\n\n`Sprite` is a convenience wrapper that creates an ECS entity with\nTransform, Collider, Velocity, Renderable, and Visible components.\nExposes `x`, `y`, `width`, `height`, `velocity`, `style`, `image` shorthands.\n\nAnimated sprites are driven through `sprite.animation`, which distinguishes\n**persistent intent** from **temporary actions**:\n\n```js\n// Persistent requests are safe to issue every frame.\nking.animation.play(Input.down(\"move\") ? \"run\" : \"idle\");\n\n// One-shot actions play to completion, then resume the latest request.\nif (Input.pressed(\"jump\")) king.animation.playOnce(\"jump\");\n\n// Higher-priority states override normal playback and cannot be interrupted.\nking.animation.play(\"hit\", { force: true });\nking.animation.play(\"death\", { force: true, resume: false });\n\n// Sequences play in order, then normal playback resumes.\nking.animation.playOnce(\"attack1\");\nking.animation.queue(\"attack2\");\nking.animation.queue(\"attack3\");\n```\n\n`play()` never restarts an already-active clip; `playOnce()` always plays a\nclip exactly once (even looping clips) and then resumes the latest persistent\nrequest. `onComplete(cb)` fires with the completed clip name each time a finite\nplayback ends. The AnimationSystem owns the transition, so gameplay code does\nnot need to track jump/attack state.\n\n`Group` is a pure entity container (iterable). Collision queries delegate\nto `CollisionSystem`. Optional `SpatialHash` acceleration.\n\n### Text\n\nWorld-space text goes through the ECS (`TextSystem` → `RenderQueue`), so it\nfollows the camera, respects `layer`/`depth` ordering, and renders identically\non Canvas, WebGL, and WebGPU. Retained `Text` rendering is gated by the font's\ndeclared capabilities: a requested render mode that the font does not support\nthrows a clear error instead of silently falling back.\n\n```js\nconst ink = await Font.load(\"Ink\", { image: \"ink.png\", gridX: 16, gridY: 16 });\n\nconst score = new Text(100, 50, \"Ink\", \"Score: 0\", { layer: Layer.ENTITIES, depth: 5 });\nscore.color = \"#ffcc00\";\nscore.align = \"center\";\nscore.letterSpacing = 1;\nscore.value = \"Score: 12\";\nscore.x += 10;\nscore.destroy(); // releases the content resource and the entity\n```\n\n`new Text(x, y, font, content)` accepts a registered font name or a `BitmapFont`\ninstance. The facade is a thin wrapper over `Transform` + `Renderable` +\n`Visible` + `Text`; `width`/`height` are measured from the cached layout.\n\n`Font.render(ctx, ...)` remains the immediate path for screen-space text —\ncorrect for UI/debug overlays in `renderUI()`/`render()`. `Text` is the\nworld-space, camera-following consumer; native fonts (`Font.load(\"Native\",\n{ family: ... })`) are immediate-only in v1.\n\n### Font render-mode capabilities\n\nEvery font type declares which retained `Text` render modes it supports, and\n`Text` asks the font (never switching on the concrete font class). The contract\nis intentional: unsupported combinations fail loudly, they are never silently\nrerouted to another mode.\n\n```text\nBitmap font:\n  glyph rendering: supported          (TextRenderMode.GLYPH)\n  raster rendering: supported         (TextRenderMode.RASTERIZED)\n\nNative font:\n  glyph rendering: not currently supported\n  raster rendering: supported         (TextRenderMode.RASTERIZED)\n```\n\nNative fonts work both immediately and through retained `Text` in raster mode.\n`NativeFont + RASTERIZED` measures the whole string with Canvas2D text metrics\nand rasterizes it with one `fillText` into the same cached text surface that\nrasterized bitmap text produces — so a native `Text` is one textured quad, no\ndifferent to any renderer from a rasterized bitmap `Text`. Glyph mode is the\nhigh-frequency path for per-character text and needs a bitmap font.\n\nThe default render mode is chosen **automatically** from the font's\ncapabilities: a bitmap font defaults to `GLYPH`, a native font (which cannot\ndo glyph) defaults to `RASTERIZED`. An explicit `renderMode` option is a\ndeliberate override — e.g. `bitmap + RASTERIZED`:\n\n```js\nconst pixel = await Font.load(\"Pixel\", \"assets/fonts/pixel.ttf\");\npixel.render(ctx, \"SCORE 0\", 10, 40, { color: \"#ffffff\" }); // immediate canvas text\n\n// Retained Text with a native font — the auto default picks raster:\nconst label = new Text(350, 100, \"Pixel\", \"SCORE 0\");\n\n// Explicit modes are honored as-is, and unsupported ones throw:\nconst bit = new Text(350, 100, \"Ink\", \"SCORE 0\", { renderMode: TextRenderMode.RASTERIZED }); // ok\nconst bad = new Text(350, 100, \"Pixel\", \"SCORE 0\", {\n  renderMode: TextRenderMode.GLYPH, // native fonts cannot render per-glyph\n}); // throws: font \"Pixel\" does not support render mode \"glyph\"\n```\n\nRequesting an unsupported mode throws `Text: font \"<name>\" does not support\nrender mode \"<mode>\".` — both at construction and on any later `font`/`renderMode`\nchange. The capability flags (`font.capabilities`) are part of the font\nabstraction, so the raster/glyph matrix stays a flag change, not a redesign of\n`Text`.\n\n### Input Actions\n\nActions decouple gameplay logic from physical keys via an `ActionMap` + `ContextStack` pipeline.\nBindings are evaluated against the `DeviceRegistry` each frame, processed through optional\n`Processor` chains, and written to `ActionState` instances:\n\n```js\nimport { ActionKind, CompositeBinding, KeyBinding, KeyCode } from \"jygame\";\n\nconst move = new CompositeBinding(ActionKind.VECTOR2, [\n  { binding: new KeyBinding(KeyCode.KEY_D), vector: [ 1,  0] },\n  { binding: new KeyBinding(KeyCode.KEY_A), vector: [-1,  0] },\n  { binding: new KeyBinding(KeyCode.KEY_W), vector: [ 0, -1] },\n  { binding: new KeyBinding(KeyCode.KEY_S), vector: [ 0,  1] },\n]);\nthis._actionMap.bind(\"move\", move, ActionKind.VECTOR2);\n\n// Each frame:\nconst v = this._actionMap.getState(\"move\").vector;\nthis.player.velocity.x = v.x * 200;\nthis.player.velocity.y = v.y * 200;\n```\n\nResolution order: `Physical Key → Device → Binding → Processor → ActionState`.\n`ContextStack` supports priority-based shadowing — a pause menu context at higher\npriority can block gameplay bindings with `consumePolicy: \"block\"`.\n\n## License\n\nGNU General Public License v3.0\n","readmeFilename":"README.md"}