neko-vue 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/LICENSE +27 -0
- package/README.md +526 -0
- package/dist/NekoPet-B9k9Bf1o.d.mts +262 -0
- package/dist/NekoPet-DMPjoHm0.mjs +402 -0
- package/dist/index-BjAaI8iZ.d.mts +128 -0
- package/dist/index.d.mts +17 -0
- package/dist/index.mjs +5 -0
- package/dist/loadNekoRuntime-CskWI70T.mjs +41 -0
- package/dist/loadNekoRuntime-DLd1lr8Y.d.mts +11 -0
- package/dist/nekoPlacement-DUdnhZoX.mjs +76 -0
- package/dist/nekoPlacement-fXmlU6ys.d.mts +23 -0
- package/dist/nekojsRuntime-DJI-YkCi.mjs +616 -0
- package/dist/placement.d.mts +2 -0
- package/dist/placement.mjs +2 -0
- package/dist/runtime.d.mts +2 -0
- package/dist/runtime.mjs +2 -0
- package/dist/types-Ctrldouo.mjs +50 -0
- package/dist/types.d.mts +2 -0
- package/dist/types.mjs +2 -0
- package/dist/vue.d.mts +2 -0
- package/dist/vue.mjs +2 -0
- package/package.json +98 -0
|
@@ -0,0 +1,616 @@
|
|
|
1
|
+
import { r as DEFAULT_NEKO_BEHAVIOR_CYCLE } from "./types-Ctrldouo.mjs";
|
|
2
|
+
//#region src/runtime/nekoSpritesData.ts
|
|
3
|
+
/**
|
|
4
|
+
* Embedded sprite data (base64 PNG data URLs). Third-party runtime licensing: see repo `LICENSE`.
|
|
5
|
+
*/
|
|
6
|
+
const NEKO_SPRITES = [
|
|
7
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABIklEQVR4nO1WSQ7EMAiDUf//ZeYwoguYLdVIPdSnqklsB0gI0QsMeQJntKAiQuPLG7ILRUQkIUTjqfinMMCI4KcBzUUcpYFsV0oQCTgEBi9TdFwNMB27bakYka455Vc9l4LISCYAB6xBK6zYAtI0b0akg5CvKkLMxpgv+p9hIx/COUsfTmv7s6CF01pKQZT7QU3siIoQ4pxjFWPmy/fUzCT87YvoZKbkn6SAu1XeFW9PMtjDcI6IMWd5BfwjorUidLdZMSZZb1g6BQTqYdghbxkISaMGldXEtAZaJwEczVu9oN2ikZEKlQERkfSBkTWmam1l4BJudNtlhsDa+6dg+CRrIe0FaDdTVBGLIiAqnIkreSZiOBxZtHKyZfh0L+a/eA6+YR662bT+YjsAAAAASUVORK5CYII=",
|
|
8
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA40lEQVR4nO1XyxLDIAiUTv7/l+mhsfUBsogZM233ZkZ2F2SIUpoHN2uaIUGDWrHEXH8iEqlMfq9rboU7wpcRmPeBCpfiUrb527mHk1C1iIGu5Kv2wgauAnJW5rmr5EA/QAYERyNBl8b2CiA9QG1m1hoVhzacqEogVeTqQcSasEj6MRM2oCqCo9jUGUVVWRORqwLC1BS1hk04I57jmtGsYvskNA14s88oqxAyMDuE0NiRgW4AzcAaSPfvgZ83EOqDVfeBlDb+C0Qj74V+SYV5D6eBknjJw+T2Tfj9BqKAX0B/aHgCdIBeOO78F8UAAAAASUVORK5CYII=",
|
|
9
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABDklEQVR4nO1Wyw4DIQiEpv//y/TQuEVXmBG3ySbtnFQQRuWhSh02zLViBG0anXwE1otUU1Oh8JE5907a2MxOzsf1yb7wIBmBzpiqduMRbc3MujECJDASuVqXJvAtQAL+6huiGBjnIDBFROQJNeT85tEVMw5LBNg3XUxNESGzYDSE5m2NIQ4L0YzAzPCMhNsb+qGfAJ3Iy9jT0wQ8iZnD5jSSXUIAGV5x6oGCUCup5TaLgDijK6GqUmnF6h36hM67nSWRD7Ji/wYiB60FRynIABGwanA5EqmB+3fDP4HbEph9WCtYKsUe7CcFYbcUqySF5tJSDAyXe8YygeRUJRJLBIgr3eqeGUxASd3U/2G8AFt7mTLOfRenAAAAAElFTkSuQmCC",
|
|
10
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABF0lEQVR4nO2W3Q6DMAiFYdn7vzK70E5KDpTS6s1GYqJt5XzlR8tUM1H3XPSx9LKIHAzMKRfuomUABKHn1DzUehUBoKCIkIh8gZhZwwl6970DAAExM4EoCR2RaBO8JQIRhH5utycEE21KQQQBrKuFbQCO2NBmAERd2fYb2sjLlTiwQ1tooZDTilEXyMh5NezavAgMxdMCV6qgFhrcLR6m+dY2zJgF2Lb7CsDj4hagZOaH040/AmD/gJbjdoBOrfB17ABWP6+VGrqlDTP9DwGqXbASuQbQKWuHXpXbta0QZ3avAciecpuzKCpaXA9nxRsAOmIzcAzFveesMQBonqC6dy4wPqcAtFj6gIJgZvM/vTiC2eTzbz9oHxxQekFCimcpAAAAAElFTkSuQmCC",
|
|
11
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABKUlEQVR4nOWX3Q7CMAiFD2bv/8p4sdGxFljpT7zwJMaoG+cDCpnAv4sWxOAZj1kABgBmBtEZivnJc33v+mQAmkxrs8q0XBNBpAAsQy9zB6jx+yQASGdWkYGIysu7H2cVH6RHAiCUVCAAEIiHMhW44sddi1qBuwKlElmAtBRwmRgNmQVgPXISsPNGs02ZM2BOgScPsp4Iq6HaRX5vzImoO3vPHHBaoMrFlrlcIwHr917z5sMd++5VNsvAPLUJl0BEG1BkHcL5lBFnreWeAb3j35bPqDnwrEBZFBbQDnN9YWrGV5kDiU2YbcNSgFXjOASw0xw4D6G5ZrMa6b8AvAXalz6qFoxmMXofMPBI5rRneEQKQE8WM5l6+uwK3KvjV8ai7Q+lq9T8oVilL9sKg2SESmbvAAAAAElFTkSuQmCC",
|
|
12
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABGElEQVR4nO2W3Q6DMAiFwfj+r8xupBLKb+vijSfZkilwPmmlA/j0snAhhzbzlwEIAIDo9kcc6csglcTJeCqyAZIlUGTsgLQgjk5wpgu2TpwAtJ6+AUHyvgewZF7QVNcC2DY3ukBeXQ0wgsTOdlWIGcaq7kiUABNhZkBEZgwiAptm3WQAMgbM8nDpLOG0B7rmXheieFBvgV53vGOffRMYVEIc6ubfzD0dhvl1qdZW3nD6Gn8qAAj2mpchLCC5rKr1UrR8GMmiVheqsCkAm0hTQbdlDgB4dhP1vKh0yDMfX77X/eRWF4Li4yfYJ+MISjtgbcTIWAwmTgyXOeyAiqFo6nmHTab2n1Ijz5ukjwNICDSurdT79Ol9/QD98LQSLfZm6wAAAABJRU5ErkJggg==",
|
|
13
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABBklEQVR4nO1V0Q6EMAiDi///y9yLLHUC66Ymd4lNTNQArQWcyIsfgMH1NM8JHxERMxMzS4OeIm8C2OBV8v3jUgGqqh55txMluQsQFOFCbhAxJEcBd4qwgvz0UqMgTAZRUWyZG2Gv12pFQ9hXRDeqdS2Zcc4wdhsJQCFQzB80i2HRO0ANTrAtVB4jYAozg4oCMY9uAVMYgRtVxV0WkIFtyaUWrAJXEX1aHiSS8PDKb6ZboKq0vcxPbJN9Gsk/2NKul3WlsD44G+YJBi4cBGSrwwrJXKpENAGYXAzN0AbPj4T2B1ET0CdHSglEdTI3QkvCA2YRp7YGR/zyl9IinK97fpr3xYs/wxfuy7Lj/kO2hgAAAABJRU5ErkJggg==",
|
|
14
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABHElEQVR4nO2WwRLDIAhEof//z9tLSJUAATTTQ7uHzKSi+6JIIfrry+JCLDat4060DGQcgO3PPHmXQUKDY/Ezhj7BU4y8q/gSQGig40bDFfNoAgyICc4wfw6gCNI+gluA1IJFiFfLJdABLvSg+PruB5hZXO8T7DEAZT7tyDjmAbAqMGmNSalAAECDhTtQgmDmi7kBcdHdEaQgxDh7c8abkskBlq9bkQeXTUKmhbyIVL0FJkS3aHUATMkRabi7dyJCB+CyC5KAACq5AiLi5R2wYLJTz0dTZl+Qci5ew2AdFhIzBwzTa14sAIjc5kXgjLF+B5OBsEAERvcLu/4NvSLFYiaAql94tB+YQLz82AnQKtX7i/vcgun14fz+w3oDTA6XRee9YIQAAAAASUVORK5CYII=",
|
|
15
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABDklEQVR4nO2WSxLDIAxDUaf3v7K7aEKJI/8I7abRMjHWsw0Mrf27kIiRYvwSgG4q8vEHDuFLYFgSGU3pIlDvKaCwA6cfBtwGVYaIFtBRmMkmILxgyRpfgXBHUDVXEMxD9LeHleSqOVlPN7cJ4CWPlDUvA4iICwGgZF4G8CCYuYiEoywDMBmVp2QBIDvvq1rSASZdgDodvV1fA8jqWV2g571X5px/SzIFcMpiGLIToYTWfjgCa1N7AKeTYLU/o9mbMH0coxtS7ZUenHoT6qr321BXFcCivTfeISizCQEgfKYNtCzBCHHQ1Cmwqnc6Yramct/2Loxmuu3qe5i/BLAbkFm7r55VAGPymbW3blG9AHEphjo0CJF9AAAAAElFTkSuQmCC",
|
|
16
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA80lEQVR4nO2WwRLDIAhEoZP//2V6qHZMdHGRNL24M7kosi+IjiI5WfmW9cqYm5mYWQV5HOAWbYC/AxzBeK/Z2jllE9KBUrqeSqpK52a3gDYvwSLk0WQAQuZRiBnAknkEInwKyv7S8zOIEICqiplBiNl8FACWf2RSzVG8gCrQFfAMGECk5ZuwNYnALQF4BuhP2SpEr+LOJCtUgXxmMi8C+FzmgePkqcnTJYQVqM+tEYR3D4zGvKeb24Q/qEAnCFAXZRutrkcQXg98V1y3ooXyxi/wp5zt4EynLExFBn8LfUIvom4AVCKSP9Nlo1Lc07VbW0/qDae6gB08t42YAAAAAElFTkSuQmCC",
|
|
17
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA+0lEQVR4nO1Wyw7EIAiEzf7/L7MXadTKY6gemuwkPRSFGVFBojykfZHNs9/wyZKLXPGktzV7TyZtcLY/EqCMW+fBAk4gI6BPf5RaZG5aQBaCpF7xLTK5/whecQb+ApiZS8Gbn+sMZyASg4qF6gAzk4iYJPP4sTqwEqHkKNICEAIvS2UBHkl19UTBCVUuJbw5d6sMxk2eUin2SFFYW5B+0QBYxrQyoCnbJULI2IboEC6dvDqAxMkIOI5UL3jI4fpng7tXsXoFiYAtsKobImoFqA7MInqSqChtEdAHZ+ZbRiqFCTlgQ1s2fDNzBrziGg7Y/SJCkekRJ/rIOfwAzH6TFVfg/LAAAAAASUVORK5CYII=",
|
|
18
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABA0lEQVR4nO2XzRKDMAiEwfH9X5kebDQSfhOcHurepDPuR8DVAvy78KH7UtSjEuA0Jbr8EW8Wg98KAA0FGkp3swPGJoqaa2as4+Fnt7BiroCU7kDIPAPCiyTUxeWqgth44WtCQs2bryoLfADwIDxlIUUAC8IyQMT0mFSAZshvqEHMmLsAFtjsPpQAZCUloARA2rZXdesB/EQbHJse3h5EPE+kP5nZvdjhmo2aeP31bBpqEkfw5MxDAJkuvTFYTwAHwH62XuIl4NKvY7d9fkItBXkaRgB2B2p4/1d2D+DnAHJDac4r0RwJohuEtScsSUNEGWzza6kBRL8FZwA8hf+MvHrV6wMLunpMS0n3sAAAAABJRU5ErkJggg==",
|
|
19
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABHUlEQVR4nO2WyxbDIAhEh578/y/TRWpKEFCRnm4yS19zeWgCPPqzaHM/756dBbiMmW0GIpLnW4sIAI6MeTP9mGjTm4Fcr9YyAEpnQEIoILLWeYBbJQggIOcdOAAFJWBmMLNrPNJqBsx6Thk5GXhFZrh3b855oAagzc7BM9prLhv9DEBnJsd/YdwBCIgGAj2n7/2svPp3ABLCirpBrIBE5npiqcPl3c+aA7l3YCiRoWGqygFmopaK3oFQzgdmybwB3E4afOGuJszeCK0DJ/FU90WNl4ke+JZgaqM2r8hCyTXMRg+oJmwRRZG1+leYWxu7j46GmfnJWFH3DnhvvlP/7SaQJbD+dMkyqTLXAGV1TQPMqBrObMJgvNT8EQC8AQ4mj0+E62kZAAAAAElFTkSuQmCC",
|
|
20
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABHElEQVR4nO2WwRLDIAhE2U7//5fppVjUFVHTaQ/ZmVwSw74gEEVu/Vi4KI7uxjwFUBER1Y8/UEKmYu8CdMZd4CTIDoBGxgOQoc/jm+YZeQCVupguMX+/M3yxysBs8a6iuN0WuMVa3z7jGkF4AFjlquoIpJOr9ukaBhEWoYGoKjUCELYiA2wh0l1wuAXwIB6i6oLV/l6EAsuiARTzzJ6uqEk52npYHUSXQogkagBAudqg2WyRcVwgntK0BduKkwIM/gUwAGqQaS+fhV1II9uadC2EiWRx+jekLWJBRs/M3A+sVbWRWQT4+8yE1YufE9GZoO0CkKu8bF/MUj4DG2l16kwHlquJUl+R19GRjKR2+XR8dCglMcKvvXXrL/UCkH+5C6s6Dz0AAAAASUVORK5CYII=",
|
|
21
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABAklEQVR4nO2V2xKDMAhE2U7//5fpi1iCXBJL60zHfdKY5CwkINGti4VgnJNvHWJ5eMxM6oYzMzFzbmCb0G2CBSzKMtBtYoADICJCaqDRhAsn8jNwgCkTZ4yE8OHBm+zJbpCBtw3TtU8PDoAKI1GZ7ouqQDwDU2JmieQAnoVqlZcwMkHvaIe6Xlg3GBjOfiGS8s5UCo/AptmCPgWXBroAleQI4Fysn+jQB4aXL2VB94Mq7CVDE/1j3cBqFuQoJztqauB0c9GAbA8AYRW48Cq6qHSzknb7uQeQ8y2qZepS673Kv6GO2sDP1C3brMD7aMHqvaNZCMTdUIcPM3ZNp7p16+/1AoBksuBmmrTtAAAAAElFTkSuQmCC",
|
|
22
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABCElEQVR4nO2XwRLDIAhEodP//2V6aDa1gBEUc+h0T5mUuk8UJUzrkuaZs39+Jgb3A+Qdwpz2HgIIBoe0if59Ro+eOQxhyswkIqdphTnRJwMYjfHcGsB8hwCA3N5qTmSXwOykneYeQEiVUKMyDKmpjvSZ0AsyJXhl7sWqku3CLANEdMC4XldpMhWxAyKyTmXZ8CCmqqBStwIcmfxK5+0Z0BAhAO+qbS+qFUUOovOCas2rNmZ6CSpmvQSwOnM9gSgAV888C2A0C6QzmAFg7PxII6qrxImVLADRcYxGIUTE9JV4D5UcRCMIhDkQMt2QRPoAB8yeKRPew++FwLhnFz4F0Hm/p07/+nm9AC/+b1UxIU8OAAAAAElFTkSuQmCC",
|
|
23
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABJ0lEQVR4nOWW2xLDIAhEl0z//5fpQ6NFJCAa04cy0+klsnsELwX+PWhgDN+gMZ3MzK0/EZUH9fMKhJfIygQaRkMltMNB7BlKU2vM+WwI4GUZn8mdsq6GNfOMuQUQJnpVmYkCoFVNkMg8O3sAOKS4MGAhuDUqgFxUo2WW44iofE/1qACQhJDiRJSqRBZCK4fbzxT5zr75TejLh43ngTa6Slhm+t0CFpVgr63hSbgaEtDaJeFdcJJsMQf6FnQan9zbtmM3kwiggmQh9OyvqjgKkIaIFmYVTQAInXsWJwDKVCArPhRbAK6u6scAMhCz+2toHWgA67jeVgHpA+c8mQWYPZy6PP2XLCvW9SG7RVdbQPo1UJlmzBNrwIVYacEyBPC7CmyP5sLx4g2TyYdbcQVdwQAAAABJRU5ErkJggg==",
|
|
24
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABH0lEQVR4nOVX0RLCIAwrnv//y/EFbgVaGjp2emdedFLSUCCrIhzgfI7j7fs47uLFBpIAAAEwinLxjgiTYzQKGTclq6u8iIpLtcxBCwAgpZQp8USoYqqoZQ76DBjE03hVuqpGSgAaMYsdEadvwTYYmdhZfUdOnIFIgJnZE5S5CZSAJysQnYHSiPTqxpVaz0xyKkCUB6gfZqJh/KgAL+mS+BJ0xgm7B/4QHqlAzZmqQMhPOWHmFrCv5EhA2oRYEV+34p8UsNXTbcDkHQXoPYfI0t9DqLlur2j2hPrgNVvNGlHYQdn5n9gB2xu8+l77MFSjC3JatMWcfauUfs90POA3n96cCdH/Ao8g2ib65GZ8AEaJ01fllhHdTX4HT5nVH+IDSk+VHrQ/yTUAAAAASUVORK5CYII=",
|
|
25
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABHUlEQVR4nOVWWw7DMAiDqfe/MvvoQ4xAMHlok2ZpmloS7AIhEGGQ66efrd37T/FCyEWERKTkGMUxsTcTc9t5iQDmx88ZChFrt+HvEj/7gDVykzFzQ9wRCglAaqAhVyQNcbVeIAHIl48CjsAulGqg7PxMS5cjE+AyR4K82sh4UgEzuV8RASIVheg4es+of7gGdHi9qFg78vWwgIi06xiMAtStyBRjoQiXRODiHIpA6h++jqtA23EmYOoYIiK+3op/UoCd/1bB9WsF6JwLUbe/p9BTVDQnuCOZbasj84AeULrrfP49w4fXG6L4NheQckDWFr13bPVWSZ850+vFCGBgT4PxCjOpQluvxUwfYOeKLhfPbCPimWO6Erua1x/gDfHvngq4OJEYAAAAAElFTkSuQmCC",
|
|
26
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA/ElEQVR4nO2WUQ/DIAiEj2X//y+zF2ksgmCL3UsvWbJM4nfisRbYL24fU5/dcGaXvd1ACAeA7x/hDABUDW70YYHoQBG6TFQaSLW8MwKgLgMpeCvcYiCUPvnjBrSkE48b0J3YNYYuXGfgioEhbcxsbi5QqTFNrYKzaY8kxrIG0mOWBTc2ZwxM4VGLDbDAz1+uwDXAvWcHDszHcKntEsSJSMMjA8tKmBjkjWFJ6FTg0gZuk2d3HhkoG7cILOozcBueabln4AQnojBMuuYKXIoHuLdmmUjsnypg4zfoNe9hYx2gG8mpCbkCgvNH0a9ZJ76dm8X6VVr1W/erV/X6AU6CeC0t3vKrAAAAAElFTkSuQmCC",
|
|
27
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABCElEQVR4nO2WzRKDMAiE2Y7v/8r0kqSISVzS0F5kxoPK8G34U5F803J17ZUNVx2y0wXcwjMFUHARkWM3uNBpf+yEz8BAQ1nmNgF0youQytXsKfDgWp6m9mcCRvYXATYLqQIA+NRffRbiXiKpqgAYQ5wI04ihKYjO+NCsAHYR0WPWAdkgfgypElAL5k7g6iIKLRjG12cF8mkqLyacdlaE9T8KSQBoR0TIRtPgT21ftT3gVuRS012imz1gOTY2PIxtqhnUP3L3p5K3r9KOEzsBVDlrCTCpUxq853hKQ2T+V+CMM/uXsxqf24RGTVeEb2Kzcm8ZzOcY9eqd+NvmjXZelLbzp/exx3LsDfOJkxZk2B+5AAAAAElFTkSuQmCC",
|
|
28
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA+UlEQVR4nO2VSw6AIAxEKfH+V64bwfIpTPm5cRKNgdB50FKd08XPs1W+NcnMAeQbgBMQXYDdEB4NLCCWgtATkKSXMKwvIgprlwNwy3gHhKyBaP4EPyKoCE8AwEe/CyCRTMXudMgiLGpAOxUicsyswZmIqwAzElAQSPUa5jsbAUOv6VAjEgbTDSsAvO7AbkMNIOpBmHNvMe9AsBysRsyNRswVgFhrXoxUDVf0gex3npz49XpRGC2OamEzKtJtiQzdDlQhLZafEYmFS8zjy6jkJAz9IBkqPhBTdXKiGSEASXuWZtq1zHbc9LhakwCZZg6ndkkKJuL++vW9bhYolBau0DkQAAAAAElFTkSuQmCC",
|
|
29
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABA0lEQVR4nO2WSw7DIAxEPVHuf2V30TgyCP8SoJuOVKkthHkG24HIFl+fpTq8QWYWkN8A7IA4KLHVKyHQLXz/vkzbyYCetwRgaGyATIFociBjruZNOZJhEqqtXq6DKB/5MgDRzshFp3yRXdgNga+3XXLWGDNbsKUI3Lp/omqvEIBVICFEP+F2j0C8I6pAjAZDCMmBjCKIUSOC90DFnCjumuHr+I15Rh4AAEzpC94unKM/NQQR8cTmJBXXGFQefn0EfVKWcsDpfqU1SB1HBQCjFpzJk36OhsiGk7kzmuZkdFoAKQDWUfcLBHdHMW/W02NRFURklrkX2KMqqKb+/pvNX3891QdsP4ApjDDinQAAAABJRU5ErkJggg==",
|
|
30
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABBElEQVR4nN2X2wrDQAhEx9L//+XpQ7PB7FVdE2gHCoVtnIOuxgJ/JB4fl15Z5iRBsoA8CsDDOKRdgIu5iACAPAmwZQ4A74DXLN/6zATjJTbX25oRTwlcl83aEVaA0E23QFgAttpsBbECaMyP2g61OvcCNMFJDk1W516AYdp6JsXcG68HQKjZXowMBl3A8py6C5cgNYB+qZzBrCaj3+nv9aWsizVNey1dhtV5RwK0o3j0RBfMWJIpRdrLKKrfBJjNgUcAMnUbgDUbVgAZtdyqFbMAGrOZqWdqelcyEZEzckYmIjsh8B0u7GRE4PxfEAXQhkWhreWWLsjaBzYZ8rdi/5j7BX0ADfCTHKrbEI8AAAAASUVORK5CYII=",
|
|
31
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABCklEQVR4nNWX4Q7DIAiEYdn7vzL7MW3QgnLIlvSSJUus3KcopUQPlrTfkV5ZcxEhEekgaTFq3NzHIMyZWCmAC6QKIpsCbobHeoPP7/Ktx0OEyDJu274MHExJNAWQeZtAFLghEQDYHIHYAaTNoxDwLdidfvR2QADMTCLimuzGUQB32yyTbo7GswCEVK3vRgEDE7DPU2dhCDID6JfMFSxq4j2n/8+Hck7Wcttn6TTsxg0x0b0UezNMsGBKlhTZl1GZngmwqgN/AahUGKCqAUkDaOnT713F6n7ArfGJ+z8IaslmCG8n6LvyUJFAe8LBwFhp2PgUQBt2pToXuB+oVhSAsx8eVQAZ/aZwVOsDqwuPItm/Ur4AAAAASUVORK5CYII=",
|
|
32
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABCklEQVR4nO2WSw7DMAhEcdX7X9ldJFQO5jfYirLISFmkJcOTwcZEr3D189miT4mg920gJQCGGEDuBxhBViAsgE7AEq+UpNmeh1drl5DGSfj/yfCIt3xxAMXcTF6B8IJUCC2ZAxtCbGlCUSZIywAMwUJhIIDI3CpHFaDJhNpyj+9ocqK4SVKNKEGS3ukg9UyQdVf6YBvABcI0KkIgLTsRJLo/9P8CANKsAjSpeg70lb0/ClkBNfn5QxkARU81I+KdKUFqzhuTMvw2KsF4BqhGzoiW38LbZFpuLVn2/LfOBWgXrDQbW5Aoi1uC7A2IY71blPThsphXMivxmAiZhNawcgGS+l9UgfhXz9EPsSqlDRy22m8AAAAASUVORK5CYII=",
|
|
33
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABCUlEQVR4nO2W0a7EIAhEnZv9/1/2vpRdtB0YXLtPnaRJExEPKGhrjx5p6se3XX8yQe+3gMgABrEbpARAQH4P4EHal9mA9xeNHYtxR4DNMUNw64+GDFhqp8ik6PyWVLbn5f4B4B1pFvEuLZ2BI923ACBzDqCSndTwKgMUorK4WqrLZQhA2ooMgnkYJsxRs0wYUDB2Wo8CVKvAoKoQdAssxeZQPfll8MgXc8ii9JBqBpSwTp6iKKNKKW2Bn+e+NMX+HChSAG57DSkAPWsoarTMLgIYStH+lVYdDVcAroiW7FgTam28jk+KmoqiKRtXTsAAaA+4WmAuvawfOLsu3QWJ/DOsqn0Pi0er+gdkMKQLf5051AAAAABJRU5ErkJggg==",
|
|
34
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA9klEQVR4nO2VzRLDIAiEs528/yvTS5NRyvKjTHsJx6jwueDmOJ54Yi2kK9FrpbiItEEwgDB5F4QFkL5hBwRtAUl+wbVBuDPwCyXCIRySf92+A+LMbPIK74alAAAsJVtRYcUH7lgFHSPVAla4ozVlAAC08AesJAvbPFUICt7rQUvMRaqAJ2/UAus7ALEg0gpo6dltE+DTQU8zYQnH4pVBrAJMINMH1XOtTGVIqw/ZtGOtCIOwADLP8MpEYXf8IHJCERHXYnfd0AOY5E6+dbrOTKr0L8hKXWmJOwO7nm+ooROBAVAPsAp4JhUYk6ScMAgU9+uzT/w33t2WoP+qWuSTAAAAAElFTkSuQmCC",
|
|
35
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA70lEQVR4nO1Wyw7DMAgr0/7/l73LmAglBJNKU6X6VDUBm0dCjuPBDYHN9QEvlhxARrJa3xagLBGJklNgBJQJmCy0MhCQtKJnBGQE4UI1C++igJi5GbVFqwQiQv2/XMCVuKeAWe07PUE1oa2xkonI8M2KYbqGOutfMUv/TAmk2uVV8vImh18abEacuLLfzkWkzqN60AF1j+GpH9gxvCNg2owdEd0HSbaBElERAMYha7sSAABpVMnRXNquBAzpjm67TFBgG4qgeoB8kpWQ3gNRNCxcxrwjmQlAhVid24F0chQMLWOPWUGZkIXc720f/BcfQ6ib3RoDepoAAAAASUVORK5CYII=",
|
|
36
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABBElEQVR4nO2W0Q7DIAhFYdmH98/ZEwkiIhebLE16X5bVyj0iRYlePVByOD7og5qLSGayGz8GUJfIRM0hIQBlAyQLrQwEJq3VIwCZQThQzcK3CEBERMw8GHgoP14RBGCDMjOJyPSLCq4BXaWaejj7rKJyBqyx/r/MmD73YLcBIOlFstH+DO8SsmEyFaEJsvgitvGxigkg6MC8A0BkmksEg8aF+oALHlUlvKBuEU6tGT2GTwCW50IHonshyV6AICoAggRE5+4AxJx6YaCk223n7gCGdFfba9QbMgioBsArWUlpH1h1OkQuYz4QrwCkYqzBs8uI3bqgZctqQ5ElM/i+n/vqv/oBKoa/WI/BrT0AAAAASUVORK5CYII=",
|
|
37
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA1ElEQVR4nO1USQ7EIAxzRvP/L6eXgUlTstDCpYqlqmyJTTAAhUKhUCjsB3uTn93kzOyKWCHASt7IXTwVYO0wRQ4A3wXkvR+tB0B6cLYC3D5J3tr6fwo0vJAV0Emt0jIziC4bPM2NRIwjLvH/GJFoGkJgb+y+hiEiAWk3T6In9QQsJW/l1zmnj0CajYhM40lizzdP3oGeVIqYMCwDcOW7R2Alj8blHwDdvgXWvddVkUcwWh+9A6ERIw9oQaofRP9yeIkjQZJw4JmUgLQoqSOx7i73y3AA4giQ7eL+8PYAAAAASUVORK5CYII=",
|
|
38
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA10lEQVR4nO2UUQ7EIAhEYbP3vzL7wxo6IqKpadIwSWNKlXmClahUKpVKpbMSfYb6nDQXCb1vARg5zJ1vABAYrx919zoOgb6bpi05M4cGsJYxmK2AkPYUdnYZMYawHmhH5JljQmbuTLQSrrldo/Oa7wwgZZ7VH9L6nvwNU3oKoJUwAkhdJBmZ0nftW66AOUjEzO2JzKONrN4DHYw18mKBuRARb50BWwUbw7gHg1Dbh9CDsKbYptH85XugSxD03wOC98lqzRElngFZQ4TJAqShLEdi3q73y/QDzYaO9US4bAEAAAAASUVORK5CYII="
|
|
39
|
+
];
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/runtime/nekojsRuntime.ts
|
|
42
|
+
/**
|
|
43
|
+
* Typed pet runtime. Inspired by [nekojs](https://github.com/louisabraham/nekojs); licensing in
|
|
44
|
+
* repo `LICENSE`. Sprite data in `./nekoSpritesData.ts`.
|
|
45
|
+
*/
|
|
46
|
+
const BEHAVIOR_MODE_MIN = 0;
|
|
47
|
+
const BEHAVIOR_MODE_MAX = 6;
|
|
48
|
+
function normalizeBehaviorCycle(raw) {
|
|
49
|
+
const fallback = () => [...DEFAULT_NEKO_BEHAVIOR_CYCLE];
|
|
50
|
+
if (!raw?.length) return fallback();
|
|
51
|
+
const out = [];
|
|
52
|
+
for (const m of raw) if (typeof m === "number" && Number.isInteger(m) && m >= BEHAVIOR_MODE_MIN && m <= BEHAVIOR_MODE_MAX) out.push(m);
|
|
53
|
+
return out.length > 0 ? out : fallback();
|
|
54
|
+
}
|
|
55
|
+
const NekoState = {
|
|
56
|
+
STOP: 0,
|
|
57
|
+
WASH: 1,
|
|
58
|
+
SCRATCH: 2,
|
|
59
|
+
YAWN: 3,
|
|
60
|
+
SLEEP: 4,
|
|
61
|
+
AWAKE: 5,
|
|
62
|
+
U_MOVE: 6,
|
|
63
|
+
D_MOVE: 7,
|
|
64
|
+
L_MOVE: 8,
|
|
65
|
+
R_MOVE: 9,
|
|
66
|
+
UL_MOVE: 10,
|
|
67
|
+
UR_MOVE: 11,
|
|
68
|
+
DL_MOVE: 12,
|
|
69
|
+
DR_MOVE: 13,
|
|
70
|
+
U_CLAW: 14,
|
|
71
|
+
D_CLAW: 15,
|
|
72
|
+
L_CLAW: 16,
|
|
73
|
+
R_CLAW: 17
|
|
74
|
+
};
|
|
75
|
+
const NekoJsBehaviorMode = {
|
|
76
|
+
CHASE_MOUSE: 0,
|
|
77
|
+
RUN_AWAY_FROM_MOUSE: 1,
|
|
78
|
+
RUN_AROUND_RANDOMLY: 2,
|
|
79
|
+
PACE_AROUND_SCREEN: 3,
|
|
80
|
+
RUN_AROUND: 4,
|
|
81
|
+
STAY_STILL: 5,
|
|
82
|
+
RETURN_HOME_AND_STAY: 6
|
|
83
|
+
};
|
|
84
|
+
const BEHAVIOR_DEBUG_NAMES = {
|
|
85
|
+
[NekoJsBehaviorMode.CHASE_MOUSE]: "Chase Mouse",
|
|
86
|
+
[NekoJsBehaviorMode.RUN_AWAY_FROM_MOUSE]: "Run Away From Mouse",
|
|
87
|
+
[NekoJsBehaviorMode.RUN_AROUND_RANDOMLY]: "Run Around Randomly",
|
|
88
|
+
[NekoJsBehaviorMode.PACE_AROUND_SCREEN]: "Pace Around Screen",
|
|
89
|
+
[NekoJsBehaviorMode.RUN_AROUND]: "Run Around",
|
|
90
|
+
[NekoJsBehaviorMode.STAY_STILL]: "Stay Still",
|
|
91
|
+
[NekoJsBehaviorMode.RETURN_HOME_AND_STAY]: "Return Home And Stay"
|
|
92
|
+
};
|
|
93
|
+
const STOP_TIME = 4;
|
|
94
|
+
const WASH_TIME = 10;
|
|
95
|
+
const SCRATCH_TIME = 4;
|
|
96
|
+
const YAWN_TIME = 3;
|
|
97
|
+
const AWAKE_TIME = 3;
|
|
98
|
+
const CLAW_TIME = 10;
|
|
99
|
+
/** Sprite edge length in CSS pixels. */
|
|
100
|
+
const SPRITE_SIZE = 32;
|
|
101
|
+
/**
|
|
102
|
+
* Viewport-fixed sprite pet: chase behaviors, `start` / `stop` / `destroy` lifecycle.
|
|
103
|
+
*
|
|
104
|
+
* Document-level listeners use `AbortController` so {@link Neko.destroy} removes handlers cleanly.
|
|
105
|
+
*/
|
|
106
|
+
var Neko = class {
|
|
107
|
+
/** @internal Consolidates `document` / `window` / element listeners for teardown. */
|
|
108
|
+
listenersAbort = new AbortController();
|
|
109
|
+
fps;
|
|
110
|
+
speed;
|
|
111
|
+
behaviorMode;
|
|
112
|
+
idleThreshold;
|
|
113
|
+
state;
|
|
114
|
+
tickCount;
|
|
115
|
+
stateCount;
|
|
116
|
+
x;
|
|
117
|
+
y;
|
|
118
|
+
logicX;
|
|
119
|
+
logicY;
|
|
120
|
+
prevLogicX;
|
|
121
|
+
prevLogicY;
|
|
122
|
+
targetX;
|
|
123
|
+
targetY;
|
|
124
|
+
oldTargetX;
|
|
125
|
+
oldTargetY;
|
|
126
|
+
moveDX;
|
|
127
|
+
moveDY;
|
|
128
|
+
boundsWidth;
|
|
129
|
+
boundsHeight;
|
|
130
|
+
mouseX = null;
|
|
131
|
+
mouseY = null;
|
|
132
|
+
hasMouseMoved;
|
|
133
|
+
element;
|
|
134
|
+
spriteImages = [];
|
|
135
|
+
allowBehaviorChange;
|
|
136
|
+
animationTable;
|
|
137
|
+
cornerIndex;
|
|
138
|
+
ballX;
|
|
139
|
+
ballY;
|
|
140
|
+
ballVX;
|
|
141
|
+
ballVY;
|
|
142
|
+
running;
|
|
143
|
+
intervalId = null;
|
|
144
|
+
tickAccumulator = 0;
|
|
145
|
+
actionCount = 0;
|
|
146
|
+
lastMoveDX = 0;
|
|
147
|
+
lastMoveDY = 0;
|
|
148
|
+
/** Minimum distance (px) from movement anchor to pointer in chase mode; 0 = legacy snap-to-cursor. */
|
|
149
|
+
cursorStandoffPx;
|
|
150
|
+
/** Modes visited in order on each pet mousedown when behavior change is allowed. */
|
|
151
|
+
behaviorCycle;
|
|
152
|
+
/** Spawn / home top-left from `createNeko`; used by return-home behavior (mode 6). */
|
|
153
|
+
homeX;
|
|
154
|
+
homeY;
|
|
155
|
+
/**
|
|
156
|
+
* @param options - Initial behavior and layout; see {@link NekoOptions}. Empty object uses defaults.
|
|
157
|
+
*/
|
|
158
|
+
constructor(options = {}) {
|
|
159
|
+
this.fps = options.fps || 120;
|
|
160
|
+
this.speed = options.speed || 24;
|
|
161
|
+
this.behaviorMode = options.behaviorMode || NekoJsBehaviorMode.CHASE_MOUSE;
|
|
162
|
+
this.idleThreshold = options.idleThreshold || 6;
|
|
163
|
+
const standoff = options.cursorStandoffPx;
|
|
164
|
+
this.cursorStandoffPx = typeof standoff === "number" && Number.isFinite(standoff) && standoff > 0 ? standoff : 0;
|
|
165
|
+
this.state = NekoState.STOP;
|
|
166
|
+
this.tickCount = 0;
|
|
167
|
+
this.stateCount = 0;
|
|
168
|
+
this.x = options.startX || 0;
|
|
169
|
+
this.y = options.startY || 0;
|
|
170
|
+
this.homeX = this.x;
|
|
171
|
+
this.homeY = this.y;
|
|
172
|
+
this.logicX = this.x;
|
|
173
|
+
this.logicY = this.y;
|
|
174
|
+
this.prevLogicX = this.x;
|
|
175
|
+
this.prevLogicY = this.y;
|
|
176
|
+
this.targetX = this.x;
|
|
177
|
+
this.targetY = this.y;
|
|
178
|
+
this.oldTargetX = this.x;
|
|
179
|
+
this.oldTargetY = this.y;
|
|
180
|
+
this.moveDX = 0;
|
|
181
|
+
this.moveDY = 0;
|
|
182
|
+
this.boundsWidth = document.documentElement.clientWidth - SPRITE_SIZE;
|
|
183
|
+
this.boundsHeight = window.innerHeight - SPRITE_SIZE;
|
|
184
|
+
this.mouseX = null;
|
|
185
|
+
this.mouseY = null;
|
|
186
|
+
this.hasMouseMoved = false;
|
|
187
|
+
this.spriteImages = [];
|
|
188
|
+
this.allowBehaviorChange = options.allowBehaviorChange !== false;
|
|
189
|
+
this.behaviorCycle = normalizeBehaviorCycle(options.behaviorCycle);
|
|
190
|
+
this.animationTable = [
|
|
191
|
+
[28, 28],
|
|
192
|
+
[25, 28],
|
|
193
|
+
[26, 27],
|
|
194
|
+
[29, 29],
|
|
195
|
+
[30, 31],
|
|
196
|
+
[0, 0],
|
|
197
|
+
[1, 2],
|
|
198
|
+
[9, 10],
|
|
199
|
+
[13, 14],
|
|
200
|
+
[5, 6],
|
|
201
|
+
[15, 16],
|
|
202
|
+
[3, 4],
|
|
203
|
+
[11, 12],
|
|
204
|
+
[7, 8],
|
|
205
|
+
[17, 18],
|
|
206
|
+
[23, 24],
|
|
207
|
+
[21, 22],
|
|
208
|
+
[19, 20]
|
|
209
|
+
];
|
|
210
|
+
this.cornerIndex = 0;
|
|
211
|
+
this.ballX = 0;
|
|
212
|
+
this.ballY = 0;
|
|
213
|
+
this.ballVX = 0;
|
|
214
|
+
this.ballVY = 0;
|
|
215
|
+
this.init();
|
|
216
|
+
}
|
|
217
|
+
init() {
|
|
218
|
+
this.element = document.createElement("div");
|
|
219
|
+
this.element.className = "neko";
|
|
220
|
+
this.element.style.cssText = `
|
|
221
|
+
position: fixed;
|
|
222
|
+
width: ${SPRITE_SIZE}px;
|
|
223
|
+
height: ${SPRITE_SIZE}px;
|
|
224
|
+
image-rendering: pixelated;
|
|
225
|
+
pointer-events: ${this.allowBehaviorChange ? "auto" : "none"};
|
|
226
|
+
cursor: ${this.allowBehaviorChange ? "pointer" : "default"};
|
|
227
|
+
z-index: 999999;
|
|
228
|
+
left: ${this.x}px;
|
|
229
|
+
top: ${this.y}px;
|
|
230
|
+
margin: 0;
|
|
231
|
+
padding: 0;
|
|
232
|
+
border: none;
|
|
233
|
+
background: transparent;
|
|
234
|
+
overflow: visible;
|
|
235
|
+
box-sizing: border-box;
|
|
236
|
+
user-select: none;
|
|
237
|
+
-webkit-user-select: none;
|
|
238
|
+
`;
|
|
239
|
+
const img = document.createElement("img");
|
|
240
|
+
img.style.cssText = `
|
|
241
|
+
width: 100%;
|
|
242
|
+
height: 100%;
|
|
243
|
+
background: transparent;
|
|
244
|
+
border: none;
|
|
245
|
+
margin: 0;
|
|
246
|
+
padding: 0;
|
|
247
|
+
max-width: none;
|
|
248
|
+
max-height: none;
|
|
249
|
+
display: block;
|
|
250
|
+
box-sizing: border-box;
|
|
251
|
+
user-select: none;
|
|
252
|
+
-webkit-user-select: none;
|
|
253
|
+
-webkit-user-drag: none;
|
|
254
|
+
pointer-events: none;
|
|
255
|
+
`;
|
|
256
|
+
this.element.appendChild(img);
|
|
257
|
+
document.body.appendChild(this.element);
|
|
258
|
+
const signal = this.listenersAbort.signal;
|
|
259
|
+
if (this.allowBehaviorChange) this.element.addEventListener("mousedown", (e) => {
|
|
260
|
+
e.stopPropagation();
|
|
261
|
+
e.preventDefault();
|
|
262
|
+
this.setState(NekoState.AWAKE);
|
|
263
|
+
this.cycleBehavior();
|
|
264
|
+
}, { signal });
|
|
265
|
+
document.addEventListener("mousemove", (e) => {
|
|
266
|
+
this.mouseX = e.clientX;
|
|
267
|
+
this.mouseY = e.clientY;
|
|
268
|
+
this.hasMouseMoved = true;
|
|
269
|
+
}, { signal });
|
|
270
|
+
window.addEventListener("resize", () => {
|
|
271
|
+
this.boundsWidth = document.documentElement.clientWidth - SPRITE_SIZE;
|
|
272
|
+
this.boundsHeight = window.innerHeight - SPRITE_SIZE;
|
|
273
|
+
}, { signal });
|
|
274
|
+
this.targetX = this.x + SPRITE_SIZE / 2;
|
|
275
|
+
this.targetY = this.y + SPRITE_SIZE - 1;
|
|
276
|
+
this.oldTargetX = this.targetX;
|
|
277
|
+
this.oldTargetY = this.targetY;
|
|
278
|
+
this.updatePosition();
|
|
279
|
+
this.running = false;
|
|
280
|
+
this.intervalId = null;
|
|
281
|
+
}
|
|
282
|
+
/** Starts the render / logic interval (runs at `fps`). */
|
|
283
|
+
start() {
|
|
284
|
+
if (this.running) return;
|
|
285
|
+
this.running = true;
|
|
286
|
+
const interval = 1e3 / this.fps;
|
|
287
|
+
this.intervalId = setInterval(() => {
|
|
288
|
+
this.update();
|
|
289
|
+
}, interval);
|
|
290
|
+
}
|
|
291
|
+
/** Stops the interval; does not remove the DOM node or reset position. */
|
|
292
|
+
stop() {
|
|
293
|
+
this.running = false;
|
|
294
|
+
if (this.intervalId) {
|
|
295
|
+
clearInterval(this.intervalId);
|
|
296
|
+
this.intervalId = null;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/** Assigns PNG data URLs for animation frames (see bundled {@link NEKO_SPRITES}). */
|
|
300
|
+
setSprites(sprites) {
|
|
301
|
+
this.spriteImages = [...sprites];
|
|
302
|
+
this.updateSprite();
|
|
303
|
+
}
|
|
304
|
+
updateSprite() {
|
|
305
|
+
if (this.spriteImages.length === 0) return;
|
|
306
|
+
let frameIndex;
|
|
307
|
+
if (this.state === NekoState.SLEEP) frameIndex = this.animationTable[this.state][this.tickCount >> 2 & 1];
|
|
308
|
+
else frameIndex = this.animationTable[this.state][this.tickCount & 1];
|
|
309
|
+
const img = this.element.querySelector("img");
|
|
310
|
+
if (img && this.spriteImages[frameIndex]) img.src = this.spriteImages[frameIndex];
|
|
311
|
+
}
|
|
312
|
+
updatePosition() {
|
|
313
|
+
this.element.style.left = Math.round(this.x) + "px";
|
|
314
|
+
this.element.style.top = Math.round(this.y) + "px";
|
|
315
|
+
}
|
|
316
|
+
update() {
|
|
317
|
+
this.tickAccumulator += 5 / this.fps;
|
|
318
|
+
while (this.tickAccumulator >= 1) {
|
|
319
|
+
this.tickAccumulator -= 1;
|
|
320
|
+
this.prevLogicX = this.logicX;
|
|
321
|
+
this.prevLogicY = this.logicY;
|
|
322
|
+
this.processOriginalTick();
|
|
323
|
+
}
|
|
324
|
+
const t = this.tickAccumulator;
|
|
325
|
+
this.x = this.prevLogicX + (this.logicX - this.prevLogicX) * t;
|
|
326
|
+
this.y = this.prevLogicY + (this.logicY - this.prevLogicY) * t;
|
|
327
|
+
this.updatePosition();
|
|
328
|
+
}
|
|
329
|
+
processOriginalTick() {
|
|
330
|
+
this.tickCount++;
|
|
331
|
+
if (this.tickCount >= 9999) this.tickCount = 0;
|
|
332
|
+
if (this.tickCount % 2 === 0) this.stateCount++;
|
|
333
|
+
switch (this.behaviorMode) {
|
|
334
|
+
case NekoJsBehaviorMode.CHASE_MOUSE:
|
|
335
|
+
this.chaseMouse();
|
|
336
|
+
break;
|
|
337
|
+
case NekoJsBehaviorMode.RUN_AWAY_FROM_MOUSE:
|
|
338
|
+
this.runAwayFromMouse();
|
|
339
|
+
break;
|
|
340
|
+
case NekoJsBehaviorMode.RUN_AROUND_RANDOMLY:
|
|
341
|
+
this.runRandomly();
|
|
342
|
+
break;
|
|
343
|
+
case NekoJsBehaviorMode.PACE_AROUND_SCREEN:
|
|
344
|
+
this.paceAroundScreen();
|
|
345
|
+
break;
|
|
346
|
+
case NekoJsBehaviorMode.RUN_AROUND:
|
|
347
|
+
this.runAround();
|
|
348
|
+
break;
|
|
349
|
+
case NekoJsBehaviorMode.STAY_STILL:
|
|
350
|
+
this.stayStillBehavior();
|
|
351
|
+
break;
|
|
352
|
+
case NekoJsBehaviorMode.RETURN_HOME_AND_STAY:
|
|
353
|
+
this.returnHomeAndStayBehavior();
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
356
|
+
this.updateSprite();
|
|
357
|
+
}
|
|
358
|
+
chaseMouse() {
|
|
359
|
+
if (!this.hasMouseMoved) {
|
|
360
|
+
this.runTowards(this.logicX + SPRITE_SIZE / 2, this.logicY + SPRITE_SIZE - 1);
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
const mx = this.mouseX;
|
|
364
|
+
const my = this.mouseY;
|
|
365
|
+
if (mx === null || my === null) return;
|
|
366
|
+
const footX = this.logicX + SPRITE_SIZE / 2;
|
|
367
|
+
const footY = this.logicY + SPRITE_SIZE - 1;
|
|
368
|
+
const standoff = this.cursorStandoffPx;
|
|
369
|
+
if (standoff <= 0) {
|
|
370
|
+
this.runTowards(mx, my);
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
const vx = mx - footX;
|
|
374
|
+
const vy = my - footY;
|
|
375
|
+
const d = Math.sqrt(vx * vx + vy * vy);
|
|
376
|
+
if (d <= standoff || d === 0) {
|
|
377
|
+
this.runTowards(footX, footY);
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
const sx = mx - vx / d * standoff;
|
|
381
|
+
const sy = my - vy / d * standoff;
|
|
382
|
+
this.runTowards(sx, sy);
|
|
383
|
+
}
|
|
384
|
+
runAwayFromMouse() {
|
|
385
|
+
if (!this.hasMouseMoved) {
|
|
386
|
+
this.runTowards(this.logicX + SPRITE_SIZE / 2, this.logicY + SPRITE_SIZE - 1);
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
const mx = this.mouseX;
|
|
390
|
+
const my = this.mouseY;
|
|
391
|
+
if (mx === null || my === null) return;
|
|
392
|
+
const dwLimit = this.idleThreshold * 16;
|
|
393
|
+
const xdiff = this.logicX + SPRITE_SIZE / 2 - mx;
|
|
394
|
+
const ydiff = this.logicY + SPRITE_SIZE / 2 - my;
|
|
395
|
+
if (Math.abs(xdiff) < dwLimit && Math.abs(ydiff) < dwLimit) {
|
|
396
|
+
const dLength = Math.sqrt(xdiff * xdiff + ydiff * ydiff);
|
|
397
|
+
let targetX, targetY;
|
|
398
|
+
if (dLength !== 0) {
|
|
399
|
+
targetX = this.logicX + xdiff / dLength * dwLimit;
|
|
400
|
+
targetY = this.logicY + ydiff / dLength * dwLimit;
|
|
401
|
+
} else targetX = targetY = 32;
|
|
402
|
+
this.runTowards(targetX, targetY);
|
|
403
|
+
if (this.state === NekoState.AWAKE) this.calcDirection(targetX - this.logicX, targetY - this.logicY);
|
|
404
|
+
} else this.runTowards(this.targetX, this.targetY);
|
|
405
|
+
}
|
|
406
|
+
runRandomly() {
|
|
407
|
+
if (this.state === NekoState.SLEEP) this.actionCount = (this.actionCount || 0) + 1;
|
|
408
|
+
if ((this.actionCount || 0) > this.idleThreshold * 10) {
|
|
409
|
+
this.actionCount = 0;
|
|
410
|
+
this.targetX = Math.random() * this.boundsWidth;
|
|
411
|
+
this.targetY = Math.random() * this.boundsHeight;
|
|
412
|
+
this.runTowards(this.targetX, this.targetY);
|
|
413
|
+
} else this.runTowards(this.targetX, this.targetY);
|
|
414
|
+
}
|
|
415
|
+
paceAroundScreen() {
|
|
416
|
+
if (this.lastMoveDX === 0 && this.lastMoveDY === 0) this.cornerIndex = ((this.cornerIndex || 0) + 1) % 4;
|
|
417
|
+
const target = [
|
|
418
|
+
[SPRITE_SIZE + SPRITE_SIZE / 2, SPRITE_SIZE + SPRITE_SIZE - 1],
|
|
419
|
+
[SPRITE_SIZE + SPRITE_SIZE / 2, this.boundsHeight - SPRITE_SIZE + SPRITE_SIZE - 1],
|
|
420
|
+
[this.boundsWidth - SPRITE_SIZE + SPRITE_SIZE / 2, this.boundsHeight - SPRITE_SIZE + SPRITE_SIZE - 1],
|
|
421
|
+
[this.boundsWidth - SPRITE_SIZE + SPRITE_SIZE / 2, SPRITE_SIZE + SPRITE_SIZE - 1]
|
|
422
|
+
][this.cornerIndex || 0];
|
|
423
|
+
this.runTowards(target[0], target[1]);
|
|
424
|
+
}
|
|
425
|
+
runAround() {
|
|
426
|
+
const dwBoundingBox = this.speed * 8;
|
|
427
|
+
if (this.ballX === 0 && this.ballY === 0) {
|
|
428
|
+
this.ballX = Math.random() * (this.boundsWidth - dwBoundingBox);
|
|
429
|
+
this.ballY = Math.random() * (this.boundsHeight - dwBoundingBox);
|
|
430
|
+
this.ballVX = (Math.random() < .5 ? 1 : -1) * (this.speed / 2) + 1;
|
|
431
|
+
this.ballVY = (Math.random() < .5 ? 1 : -1) * (this.speed / 2) + 1;
|
|
432
|
+
}
|
|
433
|
+
this.ballX += this.ballVX;
|
|
434
|
+
this.ballY += this.ballVY;
|
|
435
|
+
if (this.ballX < dwBoundingBox) if (this.ballX > 0) this.ballVX++;
|
|
436
|
+
else this.ballVX = -this.ballVX;
|
|
437
|
+
else if (this.ballX > this.boundsWidth - dwBoundingBox) if (this.ballX < this.boundsWidth) this.ballVX--;
|
|
438
|
+
else this.ballVX = -this.ballVX;
|
|
439
|
+
if (this.ballY < dwBoundingBox) if (this.ballY > 0) this.ballVY++;
|
|
440
|
+
else this.ballVY = -this.ballVY;
|
|
441
|
+
else if (this.ballY > this.boundsHeight - dwBoundingBox) if (this.ballY < this.boundsHeight) this.ballVY--;
|
|
442
|
+
else this.ballVY = -this.ballVY;
|
|
443
|
+
this.runTowards(this.ballX, this.ballY);
|
|
444
|
+
}
|
|
445
|
+
/** Idle in place at the current logic position (same target pattern as “wait for mouse”). */
|
|
446
|
+
stayStillBehavior() {
|
|
447
|
+
this.runTowards(this.logicX + SPRITE_SIZE / 2, this.logicY + SPRITE_SIZE - 1);
|
|
448
|
+
}
|
|
449
|
+
/** Move toward spawn, then idle there. */
|
|
450
|
+
returnHomeAndStayBehavior() {
|
|
451
|
+
const targetX = this.homeX + SPRITE_SIZE / 2;
|
|
452
|
+
const targetY = this.homeY + SPRITE_SIZE - 1;
|
|
453
|
+
const dx = targetX - this.logicX - SPRITE_SIZE / 2;
|
|
454
|
+
const dy = targetY - this.logicY - SPRITE_SIZE + 1;
|
|
455
|
+
if (Math.sqrt(dx * dx + dy * dy) <= this.speed) {
|
|
456
|
+
this.logicX = this.homeX;
|
|
457
|
+
this.logicY = this.homeY;
|
|
458
|
+
this.prevLogicX = this.homeX;
|
|
459
|
+
this.prevLogicY = this.homeY;
|
|
460
|
+
}
|
|
461
|
+
this.runTowards(targetX, targetY);
|
|
462
|
+
}
|
|
463
|
+
setState(newState) {
|
|
464
|
+
this.tickCount = 0;
|
|
465
|
+
this.stateCount = 0;
|
|
466
|
+
this.state = newState;
|
|
467
|
+
}
|
|
468
|
+
runTowards(targetX, targetY) {
|
|
469
|
+
this.oldTargetX = this.targetX;
|
|
470
|
+
this.oldTargetY = this.targetY;
|
|
471
|
+
this.targetX = targetX;
|
|
472
|
+
this.targetY = targetY;
|
|
473
|
+
const dx = targetX - this.logicX - SPRITE_SIZE / 2;
|
|
474
|
+
const dy = targetY - this.logicY - SPRITE_SIZE + 1;
|
|
475
|
+
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
476
|
+
if (distance !== 0) if (distance <= this.speed) {
|
|
477
|
+
this.moveDX = Math.trunc(dx);
|
|
478
|
+
this.moveDY = Math.trunc(dy);
|
|
479
|
+
} else {
|
|
480
|
+
this.moveDX = Math.trunc(this.speed * dx / distance);
|
|
481
|
+
this.moveDY = Math.trunc(this.speed * dy / distance);
|
|
482
|
+
}
|
|
483
|
+
else {
|
|
484
|
+
this.moveDX = 0;
|
|
485
|
+
this.moveDY = 0;
|
|
486
|
+
}
|
|
487
|
+
this.lastMoveDX = this.moveDX;
|
|
488
|
+
this.lastMoveDY = this.moveDY;
|
|
489
|
+
const moveStart = !(this.oldTargetX >= this.targetX - this.idleThreshold && this.oldTargetX <= this.targetX + this.idleThreshold && this.oldTargetY >= this.targetY - this.idleThreshold && this.oldTargetY <= this.targetY + this.idleThreshold);
|
|
490
|
+
switch (this.state) {
|
|
491
|
+
case NekoState.STOP:
|
|
492
|
+
if (moveStart) this.setState(NekoState.AWAKE);
|
|
493
|
+
else if (this.stateCount >= STOP_TIME) if (this.moveDX < 0 && this.logicX <= 0) this.setState(NekoState.L_CLAW);
|
|
494
|
+
else if (this.moveDX > 0 && this.logicX >= this.boundsWidth) this.setState(NekoState.R_CLAW);
|
|
495
|
+
else if (this.moveDY < 0 && this.logicY <= 0) this.setState(NekoState.U_CLAW);
|
|
496
|
+
else if (this.moveDY > 0 && this.logicY >= this.boundsHeight) this.setState(NekoState.D_CLAW);
|
|
497
|
+
else this.setState(NekoState.WASH);
|
|
498
|
+
break;
|
|
499
|
+
case NekoState.WASH:
|
|
500
|
+
if (moveStart) this.setState(NekoState.AWAKE);
|
|
501
|
+
else if (this.stateCount >= WASH_TIME) this.setState(NekoState.SCRATCH);
|
|
502
|
+
break;
|
|
503
|
+
case NekoState.SCRATCH:
|
|
504
|
+
if (moveStart) this.setState(NekoState.AWAKE);
|
|
505
|
+
else if (this.stateCount >= SCRATCH_TIME) this.setState(NekoState.YAWN);
|
|
506
|
+
break;
|
|
507
|
+
case NekoState.YAWN:
|
|
508
|
+
if (moveStart) this.setState(NekoState.AWAKE);
|
|
509
|
+
else if (this.stateCount >= YAWN_TIME) this.setState(NekoState.SLEEP);
|
|
510
|
+
break;
|
|
511
|
+
case NekoState.SLEEP:
|
|
512
|
+
if (moveStart) this.setState(NekoState.AWAKE);
|
|
513
|
+
break;
|
|
514
|
+
case NekoState.AWAKE:
|
|
515
|
+
if (this.stateCount >= AWAKE_TIME + Math.floor(Math.random() * 20)) this.calcDirection(this.moveDX, this.moveDY);
|
|
516
|
+
break;
|
|
517
|
+
case NekoState.U_MOVE:
|
|
518
|
+
case NekoState.D_MOVE:
|
|
519
|
+
case NekoState.L_MOVE:
|
|
520
|
+
case NekoState.R_MOVE:
|
|
521
|
+
case NekoState.UL_MOVE:
|
|
522
|
+
case NekoState.UR_MOVE:
|
|
523
|
+
case NekoState.DL_MOVE:
|
|
524
|
+
case NekoState.DR_MOVE:
|
|
525
|
+
let newX = this.logicX + this.moveDX;
|
|
526
|
+
let newY = this.logicY + this.moveDY;
|
|
527
|
+
const wasOutside = newX <= 0 || newX >= this.boundsWidth || newY <= 0 || newY >= this.boundsHeight;
|
|
528
|
+
this.calcDirection(this.moveDX, this.moveDY);
|
|
529
|
+
newX = Math.max(0, Math.min(this.boundsWidth, newX));
|
|
530
|
+
newY = Math.max(0, Math.min(this.boundsHeight, newY));
|
|
531
|
+
const notMoved = newX === this.logicX && newY === this.logicY;
|
|
532
|
+
if (wasOutside && notMoved) this.setState(NekoState.STOP);
|
|
533
|
+
else {
|
|
534
|
+
this.logicX = newX;
|
|
535
|
+
this.logicY = newY;
|
|
536
|
+
}
|
|
537
|
+
break;
|
|
538
|
+
case NekoState.U_CLAW:
|
|
539
|
+
case NekoState.D_CLAW:
|
|
540
|
+
case NekoState.L_CLAW:
|
|
541
|
+
case NekoState.R_CLAW:
|
|
542
|
+
if (moveStart) this.setState(NekoState.AWAKE);
|
|
543
|
+
else if (this.stateCount >= CLAW_TIME) this.setState(NekoState.SCRATCH);
|
|
544
|
+
break;
|
|
545
|
+
default:
|
|
546
|
+
this.setState(NekoState.STOP);
|
|
547
|
+
break;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
calcDirection(dx, dy) {
|
|
551
|
+
let newState;
|
|
552
|
+
if (dx === 0 && dy === 0) newState = NekoState.STOP;
|
|
553
|
+
else {
|
|
554
|
+
const largeX = dx;
|
|
555
|
+
const largeY = -dy;
|
|
556
|
+
const sinTheta = largeY / Math.sqrt(largeX * largeX + largeY * largeY);
|
|
557
|
+
const sinPiPer8 = .3826834323651;
|
|
558
|
+
const sinPiPer8Times3 = .9238795325113;
|
|
559
|
+
if (dx > 0) if (sinTheta > sinPiPer8Times3) newState = NekoState.U_MOVE;
|
|
560
|
+
else if (sinTheta > sinPiPer8) newState = NekoState.UR_MOVE;
|
|
561
|
+
else if (sinTheta > -sinPiPer8) newState = NekoState.R_MOVE;
|
|
562
|
+
else if (sinTheta > -sinPiPer8Times3) newState = NekoState.DR_MOVE;
|
|
563
|
+
else newState = NekoState.D_MOVE;
|
|
564
|
+
else if (sinTheta > sinPiPer8Times3) newState = NekoState.U_MOVE;
|
|
565
|
+
else if (sinTheta > sinPiPer8) newState = NekoState.UL_MOVE;
|
|
566
|
+
else if (sinTheta > -sinPiPer8) newState = NekoState.L_MOVE;
|
|
567
|
+
else if (sinTheta > -sinPiPer8Times3) newState = NekoState.DL_MOVE;
|
|
568
|
+
else newState = NekoState.D_MOVE;
|
|
569
|
+
}
|
|
570
|
+
if (this.state !== newState) this.setState(newState);
|
|
571
|
+
}
|
|
572
|
+
/** @returns True when the sprite is in a stationary / idle animation state. */
|
|
573
|
+
isIdle() {
|
|
574
|
+
return this.state === NekoState.STOP || this.state === NekoState.WASH || this.state === NekoState.SCRATCH || this.state === NekoState.YAWN || this.state === NekoState.SLEEP || this.state === NekoState.AWAKE;
|
|
575
|
+
}
|
|
576
|
+
cycleBehavior() {
|
|
577
|
+
const behaviors = this.behaviorCycle;
|
|
578
|
+
const nextIndex = (behaviors.indexOf(this.behaviorMode) + 1) % behaviors.length;
|
|
579
|
+
this.behaviorMode = behaviors[nextIndex];
|
|
580
|
+
if (this.state === NekoState.SLEEP) this.setState(NekoState.AWAKE);
|
|
581
|
+
const nextMode = behaviors[nextIndex];
|
|
582
|
+
console.log(`Neko behavior: ${BEHAVIOR_DEBUG_NAMES[nextMode] ?? nextMode}`);
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Stops the animation loop, removes listeners, and drops the pet node from the document.
|
|
586
|
+
* Safe to call more than once.
|
|
587
|
+
*/
|
|
588
|
+
destroy() {
|
|
589
|
+
this.stop();
|
|
590
|
+
this.listenersAbort.abort();
|
|
591
|
+
if (this.element?.parentNode) this.element.parentNode.removeChild(this.element);
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
/**
|
|
595
|
+
* Creates a pet, wires bundled sprites, and calls {@link Neko.start}.
|
|
596
|
+
*
|
|
597
|
+
* @param options - Passed to {@link Neko}; see {@link NekoOptions}. Omit for defaults.
|
|
598
|
+
* @returns The running instance (`start` already called).
|
|
599
|
+
*/
|
|
600
|
+
function createNeko(options) {
|
|
601
|
+
const neko = new Neko(options ?? {});
|
|
602
|
+
neko.setSprites(NEKO_SPRITES);
|
|
603
|
+
neko.start();
|
|
604
|
+
return neko;
|
|
605
|
+
}
|
|
606
|
+
function installNekoGlobals() {
|
|
607
|
+
if (typeof globalThis === "undefined" || typeof document === "undefined") return;
|
|
608
|
+
const w = globalThis;
|
|
609
|
+
w.Neko = Neko;
|
|
610
|
+
w.NekoState = NekoState;
|
|
611
|
+
w.BehaviorMode = NekoJsBehaviorMode;
|
|
612
|
+
w.createNeko = createNeko;
|
|
613
|
+
}
|
|
614
|
+
installNekoGlobals();
|
|
615
|
+
//#endregion
|
|
616
|
+
export {};
|
package/dist/runtime.mjs
ADDED