├── .gitignore ├── README.md ├── client ├── dist │ └── assets │ │ ├── License.txt │ │ ├── ship_0000.png │ │ ├── ship_0001.png │ │ ├── ship_0002.png │ │ ├── ship_0003.png │ │ ├── ship_0004.png │ │ ├── ship_0005.png │ │ ├── ship_0006.png │ │ ├── ship_0007.png │ │ ├── ship_0008.png │ │ ├── ship_0009.png │ │ ├── ship_0010.png │ │ ├── ship_0011.png │ │ ├── ship_0012.png │ │ ├── ship_0013.png │ │ ├── ship_0014.png │ │ ├── ship_0015.png │ │ ├── ship_0016.png │ │ ├── ship_0017.png │ │ ├── ship_0018.png │ │ ├── ship_0019.png │ │ ├── ship_0020.png │ │ ├── ship_0021.png │ │ ├── ship_0022.png │ │ └── ship_0023.png ├── index.html ├── package-lock.json ├── package.json ├── src │ ├── backend.ts │ ├── index.ts │ └── scenes │ │ ├── Part1Scene.ts │ │ ├── Part2Scene.ts │ │ ├── Part3Scene.ts │ │ ├── Part4Scene.ts │ │ └── SceneSelector.ts └── tsconfig.json └── server ├── .env.development ├── .env.production ├── .gitignore ├── README.md ├── loadtest └── example.ts ├── package-lock.json ├── package.json ├── src ├── app.config.ts ├── index.ts └── rooms │ ├── Part1Room.ts │ ├── Part2Room.ts │ ├── Part3Room.ts │ └── Part4Room.ts ├── test └── MyRoom_test.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .parcel-cache 3 | client/dist/*.js 4 | client/dist/*.map 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Phaser: Real-time Multiplayer with Colyseus 2 | 3 | Full source-code for the step-by-step tutorial on how to use Phaser + Colyseus together. 4 | 5 | - [Live Demo](https://colyseus-phaser-tutorial.glitch.me/) 6 | - [See step-by-step Tutorial](https://colyseus.io/learn/phaser/) 7 | - [See Colyseus documentation](https://docs.colyseus.io/) 8 | 9 | ## How to run the **server** 10 | 11 | - Download and install [Node.js LTS](https://nodejs.org/en/download/) 12 | - Clone or download this repository. 13 | - Run the following commands: 14 | 15 | ``` 16 | cd server 17 | npm install 18 | npm start 19 | ``` 20 | 21 | The WebSocket server should be available locally at `ws://localhost:2567` ([http://localhost:2567](http://localhost:2567) should be accessible.) 22 | 23 | ## How to run the **client** 24 | 25 | In a new Terminal tab, run the following commands: 26 | 27 | ``` 28 | cd client 29 | npm install 30 | npm start 31 | ``` 32 | 33 | The client should be accessible at [`http://localhost:1234`](`http://localhost:1234`). 34 | 35 | ## License 36 | 37 | - Source-code is licensed under MIT License. 38 | - The [assets](https://www.kenney.nl/assets/pixel-shmup) are licensed under [CC0 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/). 39 | -------------------------------------------------------------------------------- /client/dist/assets/License.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | Pixel Shmup (1.1) 4 | 5 | Created/distributed by Kenney (www.kenney.nl) 6 | Creation date: 01-11-2021 7 | 8 | ------------------------------ 9 | 10 | License: (Creative Commons Zero, CC0) 11 | http://creativecommons.org/publicdomain/zero/1.0/ 12 | 13 | This content is free to use in personal, educational and commercial projects. 14 | 15 | Support us by crediting Kenney or www.kenney.nl (this is not mandatory) 16 | 17 | ------------------------------ 18 | 19 | Donate: http://support.kenney.nl 20 | Patreon: http://patreon.com/kenney/ 21 | 22 | Follow on Twitter for updates: 23 | http://twitter.com/KenneyNL -------------------------------------------------------------------------------- /client/dist/assets/ship_0000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0000.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0001.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0002.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0003.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0004.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0005.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0006.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0007.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0008.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0009.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0010.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0011.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0011.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0012.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0012.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0013.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0013.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0014.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0014.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0015.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0015.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0016.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0017.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0017.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0018.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0018.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0019.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0019.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0020.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0020.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0021.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0021.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0022.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0022.png -------------------------------------------------------------------------------- /client/dist/assets/ship_0023.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colyseus/tutorial-phaser/b9459544ab7bf5f907df88edd7f828f51a45a9b6/client/dist/assets/ship_0023.png -------------------------------------------------------------------------------- /client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Colyseus + Phaser Example 8 | 18 | 19 | 20 | 21 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /client/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "client", 9 | "version": "1.0.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "colyseus.js": "^0.16.0", 13 | "phaser": "^3.55.2" 14 | }, 15 | "devDependencies": { 16 | "buffer": "^6.0.3", 17 | "parcel": "^2.4.0", 18 | "process": "^0.11.10", 19 | "typescript": "^4.6.3" 20 | } 21 | }, 22 | "node_modules/@babel/code-frame": { 23 | "version": "7.24.7", 24 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", 25 | "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", 26 | "dev": true, 27 | "dependencies": { 28 | "@babel/highlight": "^7.24.7", 29 | "picocolors": "^1.0.0" 30 | }, 31 | "engines": { 32 | "node": ">=6.9.0" 33 | } 34 | }, 35 | "node_modules/@babel/helper-validator-identifier": { 36 | "version": "7.24.7", 37 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", 38 | "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", 39 | "dev": true, 40 | "engines": { 41 | "node": ">=6.9.0" 42 | } 43 | }, 44 | "node_modules/@babel/highlight": { 45 | "version": "7.24.7", 46 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", 47 | "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", 48 | "dev": true, 49 | "dependencies": { 50 | "@babel/helper-validator-identifier": "^7.24.7", 51 | "chalk": "^2.4.2", 52 | "js-tokens": "^4.0.0", 53 | "picocolors": "^1.0.0" 54 | }, 55 | "engines": { 56 | "node": ">=6.9.0" 57 | } 58 | }, 59 | "node_modules/@babel/highlight/node_modules/ansi-styles": { 60 | "version": "3.2.1", 61 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 62 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 63 | "dev": true, 64 | "dependencies": { 65 | "color-convert": "^1.9.0" 66 | }, 67 | "engines": { 68 | "node": ">=4" 69 | } 70 | }, 71 | "node_modules/@babel/highlight/node_modules/chalk": { 72 | "version": "2.4.2", 73 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 74 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 75 | "dev": true, 76 | "dependencies": { 77 | "ansi-styles": "^3.2.1", 78 | "escape-string-regexp": "^1.0.5", 79 | "supports-color": "^5.3.0" 80 | }, 81 | "engines": { 82 | "node": ">=4" 83 | } 84 | }, 85 | "node_modules/@babel/highlight/node_modules/color-convert": { 86 | "version": "1.9.3", 87 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 88 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 89 | "dev": true, 90 | "dependencies": { 91 | "color-name": "1.1.3" 92 | } 93 | }, 94 | "node_modules/@babel/highlight/node_modules/color-name": { 95 | "version": "1.1.3", 96 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 97 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", 98 | "dev": true 99 | }, 100 | "node_modules/@babel/highlight/node_modules/has-flag": { 101 | "version": "3.0.0", 102 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 103 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", 104 | "dev": true, 105 | "engines": { 106 | "node": ">=4" 107 | } 108 | }, 109 | "node_modules/@babel/highlight/node_modules/supports-color": { 110 | "version": "5.5.0", 111 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 112 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 113 | "dev": true, 114 | "dependencies": { 115 | "has-flag": "^3.0.0" 116 | }, 117 | "engines": { 118 | "node": ">=4" 119 | } 120 | }, 121 | "node_modules/@colyseus/msgpackr": { 122 | "version": "1.10.5", 123 | "resolved": "https://registry.npmjs.org/@colyseus/msgpackr/-/msgpackr-1.10.5.tgz", 124 | "integrity": "sha512-ZSWPpEEnSe/oMzifiLKkNdE5UR0B8STagWR1JcKV5qw6ISM/z8d7ArZgGstqBrrZAXAOIZDpvOyrTloiR9zRlg==", 125 | "license": "MIT", 126 | "optionalDependencies": { 127 | "msgpackr-extract": "^3.0.2" 128 | } 129 | }, 130 | "node_modules/@colyseus/schema": { 131 | "version": "3.0.12", 132 | "resolved": "https://registry.npmjs.org/@colyseus/schema/-/schema-3.0.12.tgz", 133 | "integrity": "sha512-KifxbFwljtMTyvcMF6XIFczgblmHa4CsGT9bzIv/n/YE6keXekrCagRlO87epQy/8kmN+EapBivjWrZbQdPKUA==", 134 | "license": "MIT", 135 | "bin": { 136 | "schema-codegen": "bin/schema-codegen", 137 | "schema-debug": "bin/schema-debug" 138 | } 139 | }, 140 | "node_modules/@lezer/common": { 141 | "version": "1.2.1", 142 | "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.1.tgz", 143 | "integrity": "sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==", 144 | "dev": true 145 | }, 146 | "node_modules/@lezer/lr": { 147 | "version": "1.4.1", 148 | "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.1.tgz", 149 | "integrity": "sha512-CHsKq8DMKBf9b3yXPDIU4DbH+ZJd/sJdYOW2llbW/HudP5u0VS6Bfq1hLYfgU7uAYGFIyGGQIsSOXGPEErZiJw==", 150 | "dev": true, 151 | "dependencies": { 152 | "@lezer/common": "^1.0.0" 153 | } 154 | }, 155 | "node_modules/@lmdb/lmdb-darwin-arm64": { 156 | "version": "2.8.5", 157 | "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.8.5.tgz", 158 | "integrity": "sha512-KPDeVScZgA1oq0CiPBcOa3kHIqU+pTOwRFDIhxvmf8CTNvqdZQYp5cCKW0bUk69VygB2PuTiINFWbY78aR2pQw==", 159 | "cpu": [ 160 | "arm64" 161 | ], 162 | "dev": true, 163 | "optional": true, 164 | "os": [ 165 | "darwin" 166 | ] 167 | }, 168 | "node_modules/@mischnic/json-sourcemap": { 169 | "version": "0.1.1", 170 | "resolved": "https://registry.npmjs.org/@mischnic/json-sourcemap/-/json-sourcemap-0.1.1.tgz", 171 | "integrity": "sha512-iA7+tyVqfrATAIsIRWQG+a7ZLLD0VaOCKV2Wd/v4mqIU3J9c4jx9p7S0nw1XH3gJCKNBOOwACOPYYSUu9pgT+w==", 172 | "dev": true, 173 | "dependencies": { 174 | "@lezer/common": "^1.0.0", 175 | "@lezer/lr": "^1.0.0", 176 | "json5": "^2.2.1" 177 | }, 178 | "engines": { 179 | "node": ">=12.0.0" 180 | } 181 | }, 182 | "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { 183 | "version": "3.0.3", 184 | "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", 185 | "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==", 186 | "cpu": [ 187 | "arm64" 188 | ], 189 | "dev": true, 190 | "optional": true, 191 | "os": [ 192 | "darwin" 193 | ] 194 | }, 195 | "node_modules/@parcel/bundler-default": { 196 | "version": "2.12.0", 197 | "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.12.0.tgz", 198 | "integrity": "sha512-3ybN74oYNMKyjD6V20c9Gerdbh7teeNvVMwIoHIQMzuIFT6IGX53PyOLlOKRLbjxMc0TMimQQxIt2eQqxR5LsA==", 199 | "dev": true, 200 | "dependencies": { 201 | "@parcel/diagnostic": "2.12.0", 202 | "@parcel/graph": "3.2.0", 203 | "@parcel/plugin": "2.12.0", 204 | "@parcel/rust": "2.12.0", 205 | "@parcel/utils": "2.12.0", 206 | "nullthrows": "^1.1.1" 207 | }, 208 | "engines": { 209 | "node": ">= 12.0.0", 210 | "parcel": "^2.12.0" 211 | }, 212 | "funding": { 213 | "type": "opencollective", 214 | "url": "https://opencollective.com/parcel" 215 | } 216 | }, 217 | "node_modules/@parcel/cache": { 218 | "version": "2.12.0", 219 | "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.12.0.tgz", 220 | "integrity": "sha512-FX5ZpTEkxvq/yvWklRHDESVRz+c7sLTXgFuzz6uEnBcXV38j6dMSikflNpHA6q/L4GKkCqRywm9R6XQwhwIMyw==", 221 | "dev": true, 222 | "dependencies": { 223 | "@parcel/fs": "2.12.0", 224 | "@parcel/logger": "2.12.0", 225 | "@parcel/utils": "2.12.0", 226 | "lmdb": "2.8.5" 227 | }, 228 | "engines": { 229 | "node": ">= 12.0.0" 230 | }, 231 | "funding": { 232 | "type": "opencollective", 233 | "url": "https://opencollective.com/parcel" 234 | }, 235 | "peerDependencies": { 236 | "@parcel/core": "^2.12.0" 237 | } 238 | }, 239 | "node_modules/@parcel/codeframe": { 240 | "version": "2.12.0", 241 | "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.12.0.tgz", 242 | "integrity": "sha512-v2VmneILFiHZJTxPiR7GEF1wey1/IXPdZMcUlNXBiPZyWDfcuNgGGVQkx/xW561rULLIvDPharOMdxz5oHOKQg==", 243 | "dev": true, 244 | "dependencies": { 245 | "chalk": "^4.1.0" 246 | }, 247 | "engines": { 248 | "node": ">= 12.0.0" 249 | }, 250 | "funding": { 251 | "type": "opencollective", 252 | "url": "https://opencollective.com/parcel" 253 | } 254 | }, 255 | "node_modules/@parcel/compressor-raw": { 256 | "version": "2.12.0", 257 | "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.12.0.tgz", 258 | "integrity": "sha512-h41Q3X7ZAQ9wbQ2csP8QGrwepasLZdXiuEdpUryDce6rF9ZiHoJ97MRpdLxOhOPyASTw/xDgE1xyaPQr0Q3f5A==", 259 | "dev": true, 260 | "dependencies": { 261 | "@parcel/plugin": "2.12.0" 262 | }, 263 | "engines": { 264 | "node": ">= 12.0.0", 265 | "parcel": "^2.12.0" 266 | }, 267 | "funding": { 268 | "type": "opencollective", 269 | "url": "https://opencollective.com/parcel" 270 | } 271 | }, 272 | "node_modules/@parcel/config-default": { 273 | "version": "2.12.0", 274 | "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.12.0.tgz", 275 | "integrity": "sha512-dPNe2n9eEsKRc1soWIY0yToMUPirPIa2QhxcCB3Z5RjpDGIXm0pds+BaiqY6uGLEEzsjhRO0ujd4v2Rmm0vuFg==", 276 | "dev": true, 277 | "dependencies": { 278 | "@parcel/bundler-default": "2.12.0", 279 | "@parcel/compressor-raw": "2.12.0", 280 | "@parcel/namer-default": "2.12.0", 281 | "@parcel/optimizer-css": "2.12.0", 282 | "@parcel/optimizer-htmlnano": "2.12.0", 283 | "@parcel/optimizer-image": "2.12.0", 284 | "@parcel/optimizer-svgo": "2.12.0", 285 | "@parcel/optimizer-swc": "2.12.0", 286 | "@parcel/packager-css": "2.12.0", 287 | "@parcel/packager-html": "2.12.0", 288 | "@parcel/packager-js": "2.12.0", 289 | "@parcel/packager-raw": "2.12.0", 290 | "@parcel/packager-svg": "2.12.0", 291 | "@parcel/packager-wasm": "2.12.0", 292 | "@parcel/reporter-dev-server": "2.12.0", 293 | "@parcel/resolver-default": "2.12.0", 294 | "@parcel/runtime-browser-hmr": "2.12.0", 295 | "@parcel/runtime-js": "2.12.0", 296 | "@parcel/runtime-react-refresh": "2.12.0", 297 | "@parcel/runtime-service-worker": "2.12.0", 298 | "@parcel/transformer-babel": "2.12.0", 299 | "@parcel/transformer-css": "2.12.0", 300 | "@parcel/transformer-html": "2.12.0", 301 | "@parcel/transformer-image": "2.12.0", 302 | "@parcel/transformer-js": "2.12.0", 303 | "@parcel/transformer-json": "2.12.0", 304 | "@parcel/transformer-postcss": "2.12.0", 305 | "@parcel/transformer-posthtml": "2.12.0", 306 | "@parcel/transformer-raw": "2.12.0", 307 | "@parcel/transformer-react-refresh-wrap": "2.12.0", 308 | "@parcel/transformer-svg": "2.12.0" 309 | }, 310 | "funding": { 311 | "type": "opencollective", 312 | "url": "https://opencollective.com/parcel" 313 | }, 314 | "peerDependencies": { 315 | "@parcel/core": "^2.12.0" 316 | } 317 | }, 318 | "node_modules/@parcel/core": { 319 | "version": "2.12.0", 320 | "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.12.0.tgz", 321 | "integrity": "sha512-s+6pwEj+GfKf7vqGUzN9iSEPueUssCCQrCBUlcAfKrJe0a22hTUCjewpB0I7lNrCIULt8dkndD+sMdOrXsRl6Q==", 322 | "dev": true, 323 | "dependencies": { 324 | "@mischnic/json-sourcemap": "^0.1.0", 325 | "@parcel/cache": "2.12.0", 326 | "@parcel/diagnostic": "2.12.0", 327 | "@parcel/events": "2.12.0", 328 | "@parcel/fs": "2.12.0", 329 | "@parcel/graph": "3.2.0", 330 | "@parcel/logger": "2.12.0", 331 | "@parcel/package-manager": "2.12.0", 332 | "@parcel/plugin": "2.12.0", 333 | "@parcel/profiler": "2.12.0", 334 | "@parcel/rust": "2.12.0", 335 | "@parcel/source-map": "^2.1.1", 336 | "@parcel/types": "2.12.0", 337 | "@parcel/utils": "2.12.0", 338 | "@parcel/workers": "2.12.0", 339 | "abortcontroller-polyfill": "^1.1.9", 340 | "base-x": "^3.0.8", 341 | "browserslist": "^4.6.6", 342 | "clone": "^2.1.1", 343 | "dotenv": "^7.0.0", 344 | "dotenv-expand": "^5.1.0", 345 | "json5": "^2.2.0", 346 | "msgpackr": "^1.9.9", 347 | "nullthrows": "^1.1.1", 348 | "semver": "^7.5.2" 349 | }, 350 | "engines": { 351 | "node": ">= 12.0.0" 352 | }, 353 | "funding": { 354 | "type": "opencollective", 355 | "url": "https://opencollective.com/parcel" 356 | } 357 | }, 358 | "node_modules/@parcel/diagnostic": { 359 | "version": "2.12.0", 360 | "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.12.0.tgz", 361 | "integrity": "sha512-8f1NOsSFK+F4AwFCKynyIu9Kr/uWHC+SywAv4oS6Bv3Acig0gtwUjugk0C9UaB8ztBZiW5TQZhw+uPZn9T/lJA==", 362 | "dev": true, 363 | "dependencies": { 364 | "@mischnic/json-sourcemap": "^0.1.0", 365 | "nullthrows": "^1.1.1" 366 | }, 367 | "engines": { 368 | "node": ">= 12.0.0" 369 | }, 370 | "funding": { 371 | "type": "opencollective", 372 | "url": "https://opencollective.com/parcel" 373 | } 374 | }, 375 | "node_modules/@parcel/events": { 376 | "version": "2.12.0", 377 | "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.12.0.tgz", 378 | "integrity": "sha512-nmAAEIKLjW1kB2cUbCYSmZOGbnGj8wCzhqnK727zCCWaA25ogzAtt657GPOeFyqW77KyosU728Tl63Fc8hphIA==", 379 | "dev": true, 380 | "engines": { 381 | "node": ">= 12.0.0" 382 | }, 383 | "funding": { 384 | "type": "opencollective", 385 | "url": "https://opencollective.com/parcel" 386 | } 387 | }, 388 | "node_modules/@parcel/fs": { 389 | "version": "2.12.0", 390 | "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.12.0.tgz", 391 | "integrity": "sha512-NnFkuvou1YBtPOhTdZr44WN7I60cGyly2wpHzqRl62yhObyi1KvW0SjwOMa0QGNcBOIzp4G0CapoZ93hD0RG5Q==", 392 | "dev": true, 393 | "dependencies": { 394 | "@parcel/rust": "2.12.0", 395 | "@parcel/types": "2.12.0", 396 | "@parcel/utils": "2.12.0", 397 | "@parcel/watcher": "^2.0.7", 398 | "@parcel/workers": "2.12.0" 399 | }, 400 | "engines": { 401 | "node": ">= 12.0.0" 402 | }, 403 | "funding": { 404 | "type": "opencollective", 405 | "url": "https://opencollective.com/parcel" 406 | }, 407 | "peerDependencies": { 408 | "@parcel/core": "^2.12.0" 409 | } 410 | }, 411 | "node_modules/@parcel/graph": { 412 | "version": "3.2.0", 413 | "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-3.2.0.tgz", 414 | "integrity": "sha512-xlrmCPqy58D4Fg5umV7bpwDx5Vyt7MlnQPxW68vae5+BA4GSWetfZt+Cs5dtotMG2oCHzZxhIPt7YZ7NRyQzLA==", 415 | "dev": true, 416 | "dependencies": { 417 | "nullthrows": "^1.1.1" 418 | }, 419 | "engines": { 420 | "node": ">= 12.0.0" 421 | }, 422 | "funding": { 423 | "type": "opencollective", 424 | "url": "https://opencollective.com/parcel" 425 | } 426 | }, 427 | "node_modules/@parcel/logger": { 428 | "version": "2.12.0", 429 | "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.12.0.tgz", 430 | "integrity": "sha512-cJ7Paqa7/9VJ7C+KwgJlwMqTQBOjjn71FbKk0G07hydUEBISU2aDfmc/52o60ErL9l+vXB26zTrIBanbxS8rVg==", 431 | "dev": true, 432 | "dependencies": { 433 | "@parcel/diagnostic": "2.12.0", 434 | "@parcel/events": "2.12.0" 435 | }, 436 | "engines": { 437 | "node": ">= 12.0.0" 438 | }, 439 | "funding": { 440 | "type": "opencollective", 441 | "url": "https://opencollective.com/parcel" 442 | } 443 | }, 444 | "node_modules/@parcel/markdown-ansi": { 445 | "version": "2.12.0", 446 | "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.12.0.tgz", 447 | "integrity": "sha512-WZz3rzL8k0H3WR4qTHX6Ic8DlEs17keO9gtD4MNGyMNQbqQEvQ61lWJaIH0nAtgEetu0SOITiVqdZrb8zx/M7w==", 448 | "dev": true, 449 | "dependencies": { 450 | "chalk": "^4.1.0" 451 | }, 452 | "engines": { 453 | "node": ">= 12.0.0" 454 | }, 455 | "funding": { 456 | "type": "opencollective", 457 | "url": "https://opencollective.com/parcel" 458 | } 459 | }, 460 | "node_modules/@parcel/namer-default": { 461 | "version": "2.12.0", 462 | "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.12.0.tgz", 463 | "integrity": "sha512-9DNKPDHWgMnMtqqZIMiEj/R9PNWW16lpnlHjwK3ciRlMPgjPJ8+UNc255teZODhX0T17GOzPdGbU/O/xbxVPzA==", 464 | "dev": true, 465 | "dependencies": { 466 | "@parcel/diagnostic": "2.12.0", 467 | "@parcel/plugin": "2.12.0", 468 | "nullthrows": "^1.1.1" 469 | }, 470 | "engines": { 471 | "node": ">= 12.0.0", 472 | "parcel": "^2.12.0" 473 | }, 474 | "funding": { 475 | "type": "opencollective", 476 | "url": "https://opencollective.com/parcel" 477 | } 478 | }, 479 | "node_modules/@parcel/node-resolver-core": { 480 | "version": "3.3.0", 481 | "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-3.3.0.tgz", 482 | "integrity": "sha512-rhPW9DYPEIqQBSlYzz3S0AjXxjN6Ub2yS6tzzsW/4S3Gpsgk/uEq4ZfxPvoPf/6TgZndVxmKwpmxaKtGMmf3cA==", 483 | "dev": true, 484 | "dependencies": { 485 | "@mischnic/json-sourcemap": "^0.1.0", 486 | "@parcel/diagnostic": "2.12.0", 487 | "@parcel/fs": "2.12.0", 488 | "@parcel/rust": "2.12.0", 489 | "@parcel/utils": "2.12.0", 490 | "nullthrows": "^1.1.1", 491 | "semver": "^7.5.2" 492 | }, 493 | "engines": { 494 | "node": ">= 12.0.0" 495 | }, 496 | "funding": { 497 | "type": "opencollective", 498 | "url": "https://opencollective.com/parcel" 499 | } 500 | }, 501 | "node_modules/@parcel/optimizer-css": { 502 | "version": "2.12.0", 503 | "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.12.0.tgz", 504 | "integrity": "sha512-ifbcC97fRzpruTjaa8axIFeX4MjjSIlQfem3EJug3L2AVqQUXnM1XO8L0NaXGNLTW2qnh1ZjIJ7vXT/QhsphsA==", 505 | "dev": true, 506 | "dependencies": { 507 | "@parcel/diagnostic": "2.12.0", 508 | "@parcel/plugin": "2.12.0", 509 | "@parcel/source-map": "^2.1.1", 510 | "@parcel/utils": "2.12.0", 511 | "browserslist": "^4.6.6", 512 | "lightningcss": "^1.22.1", 513 | "nullthrows": "^1.1.1" 514 | }, 515 | "engines": { 516 | "node": ">= 12.0.0", 517 | "parcel": "^2.12.0" 518 | }, 519 | "funding": { 520 | "type": "opencollective", 521 | "url": "https://opencollective.com/parcel" 522 | } 523 | }, 524 | "node_modules/@parcel/optimizer-htmlnano": { 525 | "version": "2.12.0", 526 | "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.12.0.tgz", 527 | "integrity": "sha512-MfPMeCrT8FYiOrpFHVR+NcZQlXAptK2r4nGJjfT+ndPBhEEZp4yyL7n1y7HfX9geg5altc4WTb4Gug7rCoW8VQ==", 528 | "dev": true, 529 | "dependencies": { 530 | "@parcel/plugin": "2.12.0", 531 | "htmlnano": "^2.0.0", 532 | "nullthrows": "^1.1.1", 533 | "posthtml": "^0.16.5", 534 | "svgo": "^2.4.0" 535 | }, 536 | "engines": { 537 | "node": ">= 12.0.0", 538 | "parcel": "^2.12.0" 539 | }, 540 | "funding": { 541 | "type": "opencollective", 542 | "url": "https://opencollective.com/parcel" 543 | } 544 | }, 545 | "node_modules/@parcel/optimizer-htmlnano/node_modules/css-select": { 546 | "version": "4.3.0", 547 | "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", 548 | "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", 549 | "dev": true, 550 | "dependencies": { 551 | "boolbase": "^1.0.0", 552 | "css-what": "^6.0.1", 553 | "domhandler": "^4.3.1", 554 | "domutils": "^2.8.0", 555 | "nth-check": "^2.0.1" 556 | }, 557 | "funding": { 558 | "url": "https://github.com/sponsors/fb55" 559 | } 560 | }, 561 | "node_modules/@parcel/optimizer-htmlnano/node_modules/css-tree": { 562 | "version": "1.1.3", 563 | "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", 564 | "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", 565 | "dev": true, 566 | "dependencies": { 567 | "mdn-data": "2.0.14", 568 | "source-map": "^0.6.1" 569 | }, 570 | "engines": { 571 | "node": ">=8.0.0" 572 | } 573 | }, 574 | "node_modules/@parcel/optimizer-htmlnano/node_modules/csso": { 575 | "version": "4.2.0", 576 | "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", 577 | "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", 578 | "dev": true, 579 | "dependencies": { 580 | "css-tree": "^1.1.2" 581 | }, 582 | "engines": { 583 | "node": ">=8.0.0" 584 | } 585 | }, 586 | "node_modules/@parcel/optimizer-htmlnano/node_modules/mdn-data": { 587 | "version": "2.0.14", 588 | "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", 589 | "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", 590 | "dev": true 591 | }, 592 | "node_modules/@parcel/optimizer-htmlnano/node_modules/svgo": { 593 | "version": "2.8.0", 594 | "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", 595 | "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", 596 | "dev": true, 597 | "dependencies": { 598 | "@trysound/sax": "0.2.0", 599 | "commander": "^7.2.0", 600 | "css-select": "^4.1.3", 601 | "css-tree": "^1.1.3", 602 | "csso": "^4.2.0", 603 | "picocolors": "^1.0.0", 604 | "stable": "^0.1.8" 605 | }, 606 | "bin": { 607 | "svgo": "bin/svgo" 608 | }, 609 | "engines": { 610 | "node": ">=10.13.0" 611 | } 612 | }, 613 | "node_modules/@parcel/optimizer-image": { 614 | "version": "2.12.0", 615 | "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.12.0.tgz", 616 | "integrity": "sha512-bo1O7raeAIbRU5nmNVtx8divLW9Xqn0c57GVNGeAK4mygnQoqHqRZ0mR9uboh64pxv6ijXZHPhKvU9HEpjPjBQ==", 617 | "dev": true, 618 | "dependencies": { 619 | "@parcel/diagnostic": "2.12.0", 620 | "@parcel/plugin": "2.12.0", 621 | "@parcel/rust": "2.12.0", 622 | "@parcel/utils": "2.12.0", 623 | "@parcel/workers": "2.12.0" 624 | }, 625 | "engines": { 626 | "node": ">= 12.0.0", 627 | "parcel": "^2.12.0" 628 | }, 629 | "funding": { 630 | "type": "opencollective", 631 | "url": "https://opencollective.com/parcel" 632 | }, 633 | "peerDependencies": { 634 | "@parcel/core": "^2.12.0" 635 | } 636 | }, 637 | "node_modules/@parcel/optimizer-svgo": { 638 | "version": "2.12.0", 639 | "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.12.0.tgz", 640 | "integrity": "sha512-Kyli+ZZXnoonnbeRQdoWwee9Bk2jm/49xvnfb+2OO8NN0d41lblBoRhOyFiScRnJrw7eVl1Xrz7NTkXCIO7XFQ==", 641 | "dev": true, 642 | "dependencies": { 643 | "@parcel/diagnostic": "2.12.0", 644 | "@parcel/plugin": "2.12.0", 645 | "@parcel/utils": "2.12.0", 646 | "svgo": "^2.4.0" 647 | }, 648 | "engines": { 649 | "node": ">= 12.0.0", 650 | "parcel": "^2.12.0" 651 | }, 652 | "funding": { 653 | "type": "opencollective", 654 | "url": "https://opencollective.com/parcel" 655 | } 656 | }, 657 | "node_modules/@parcel/optimizer-svgo/node_modules/css-select": { 658 | "version": "4.3.0", 659 | "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", 660 | "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", 661 | "dev": true, 662 | "dependencies": { 663 | "boolbase": "^1.0.0", 664 | "css-what": "^6.0.1", 665 | "domhandler": "^4.3.1", 666 | "domutils": "^2.8.0", 667 | "nth-check": "^2.0.1" 668 | }, 669 | "funding": { 670 | "url": "https://github.com/sponsors/fb55" 671 | } 672 | }, 673 | "node_modules/@parcel/optimizer-svgo/node_modules/css-tree": { 674 | "version": "1.1.3", 675 | "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", 676 | "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", 677 | "dev": true, 678 | "dependencies": { 679 | "mdn-data": "2.0.14", 680 | "source-map": "^0.6.1" 681 | }, 682 | "engines": { 683 | "node": ">=8.0.0" 684 | } 685 | }, 686 | "node_modules/@parcel/optimizer-svgo/node_modules/csso": { 687 | "version": "4.2.0", 688 | "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", 689 | "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", 690 | "dev": true, 691 | "dependencies": { 692 | "css-tree": "^1.1.2" 693 | }, 694 | "engines": { 695 | "node": ">=8.0.0" 696 | } 697 | }, 698 | "node_modules/@parcel/optimizer-svgo/node_modules/mdn-data": { 699 | "version": "2.0.14", 700 | "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", 701 | "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", 702 | "dev": true 703 | }, 704 | "node_modules/@parcel/optimizer-svgo/node_modules/svgo": { 705 | "version": "2.8.0", 706 | "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", 707 | "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", 708 | "dev": true, 709 | "dependencies": { 710 | "@trysound/sax": "0.2.0", 711 | "commander": "^7.2.0", 712 | "css-select": "^4.1.3", 713 | "css-tree": "^1.1.3", 714 | "csso": "^4.2.0", 715 | "picocolors": "^1.0.0", 716 | "stable": "^0.1.8" 717 | }, 718 | "bin": { 719 | "svgo": "bin/svgo" 720 | }, 721 | "engines": { 722 | "node": ">=10.13.0" 723 | } 724 | }, 725 | "node_modules/@parcel/optimizer-swc": { 726 | "version": "2.12.0", 727 | "resolved": "https://registry.npmjs.org/@parcel/optimizer-swc/-/optimizer-swc-2.12.0.tgz", 728 | "integrity": "sha512-iBi6LZB3lm6WmbXfzi8J3DCVPmn4FN2lw7DGXxUXu7MouDPVWfTsM6U/5TkSHJRNRogZ2gqy5q9g34NPxHbJcw==", 729 | "dev": true, 730 | "dependencies": { 731 | "@parcel/diagnostic": "2.12.0", 732 | "@parcel/plugin": "2.12.0", 733 | "@parcel/source-map": "^2.1.1", 734 | "@parcel/utils": "2.12.0", 735 | "@swc/core": "^1.3.36", 736 | "nullthrows": "^1.1.1" 737 | }, 738 | "engines": { 739 | "node": ">= 12.0.0", 740 | "parcel": "^2.12.0" 741 | }, 742 | "funding": { 743 | "type": "opencollective", 744 | "url": "https://opencollective.com/parcel" 745 | } 746 | }, 747 | "node_modules/@parcel/package-manager": { 748 | "version": "2.12.0", 749 | "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.12.0.tgz", 750 | "integrity": "sha512-0nvAezcjPx9FT+hIL+LS1jb0aohwLZXct7jAh7i0MLMtehOi0z1Sau+QpgMlA9rfEZZ1LIeFdnZZwqSy7Ccspw==", 751 | "dev": true, 752 | "dependencies": { 753 | "@parcel/diagnostic": "2.12.0", 754 | "@parcel/fs": "2.12.0", 755 | "@parcel/logger": "2.12.0", 756 | "@parcel/node-resolver-core": "3.3.0", 757 | "@parcel/types": "2.12.0", 758 | "@parcel/utils": "2.12.0", 759 | "@parcel/workers": "2.12.0", 760 | "@swc/core": "^1.3.36", 761 | "semver": "^7.5.2" 762 | }, 763 | "engines": { 764 | "node": ">= 12.0.0" 765 | }, 766 | "funding": { 767 | "type": "opencollective", 768 | "url": "https://opencollective.com/parcel" 769 | }, 770 | "peerDependencies": { 771 | "@parcel/core": "^2.12.0" 772 | } 773 | }, 774 | "node_modules/@parcel/packager-css": { 775 | "version": "2.12.0", 776 | "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.12.0.tgz", 777 | "integrity": "sha512-j3a/ODciaNKD19IYdWJT+TP+tnhhn5koBGBWWtrKSu0UxWpnezIGZetit3eE+Y9+NTePalMkvpIlit2eDhvfJA==", 778 | "dev": true, 779 | "dependencies": { 780 | "@parcel/diagnostic": "2.12.0", 781 | "@parcel/plugin": "2.12.0", 782 | "@parcel/source-map": "^2.1.1", 783 | "@parcel/utils": "2.12.0", 784 | "lightningcss": "^1.22.1", 785 | "nullthrows": "^1.1.1" 786 | }, 787 | "engines": { 788 | "node": ">= 12.0.0", 789 | "parcel": "^2.12.0" 790 | }, 791 | "funding": { 792 | "type": "opencollective", 793 | "url": "https://opencollective.com/parcel" 794 | } 795 | }, 796 | "node_modules/@parcel/packager-html": { 797 | "version": "2.12.0", 798 | "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.12.0.tgz", 799 | "integrity": "sha512-PpvGB9hFFe+19NXGz2ApvPrkA9GwEqaDAninT+3pJD57OVBaxB8U+HN4a5LICKxjUppPPqmrLb6YPbD65IX4RA==", 800 | "dev": true, 801 | "dependencies": { 802 | "@parcel/plugin": "2.12.0", 803 | "@parcel/types": "2.12.0", 804 | "@parcel/utils": "2.12.0", 805 | "nullthrows": "^1.1.1", 806 | "posthtml": "^0.16.5" 807 | }, 808 | "engines": { 809 | "node": ">= 12.0.0", 810 | "parcel": "^2.12.0" 811 | }, 812 | "funding": { 813 | "type": "opencollective", 814 | "url": "https://opencollective.com/parcel" 815 | } 816 | }, 817 | "node_modules/@parcel/packager-js": { 818 | "version": "2.12.0", 819 | "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.12.0.tgz", 820 | "integrity": "sha512-viMF+FszITRRr8+2iJyk+4ruGiL27Y6AF7hQ3xbJfzqnmbOhGFtLTQwuwhOLqN/mWR2VKdgbLpZSarWaO3yAMg==", 821 | "dev": true, 822 | "dependencies": { 823 | "@parcel/diagnostic": "2.12.0", 824 | "@parcel/plugin": "2.12.0", 825 | "@parcel/rust": "2.12.0", 826 | "@parcel/source-map": "^2.1.1", 827 | "@parcel/types": "2.12.0", 828 | "@parcel/utils": "2.12.0", 829 | "globals": "^13.2.0", 830 | "nullthrows": "^1.1.1" 831 | }, 832 | "engines": { 833 | "node": ">= 12.0.0", 834 | "parcel": "^2.12.0" 835 | }, 836 | "funding": { 837 | "type": "opencollective", 838 | "url": "https://opencollective.com/parcel" 839 | } 840 | }, 841 | "node_modules/@parcel/packager-raw": { 842 | "version": "2.12.0", 843 | "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.12.0.tgz", 844 | "integrity": "sha512-tJZqFbHqP24aq1F+OojFbQIc09P/u8HAW5xfndCrFnXpW4wTgM3p03P0xfw3gnNq+TtxHJ8c3UFE5LnXNNKhYA==", 845 | "dev": true, 846 | "dependencies": { 847 | "@parcel/plugin": "2.12.0" 848 | }, 849 | "engines": { 850 | "node": ">= 12.0.0", 851 | "parcel": "^2.12.0" 852 | }, 853 | "funding": { 854 | "type": "opencollective", 855 | "url": "https://opencollective.com/parcel" 856 | } 857 | }, 858 | "node_modules/@parcel/packager-svg": { 859 | "version": "2.12.0", 860 | "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.12.0.tgz", 861 | "integrity": "sha512-ldaGiacGb2lLqcXas97k8JiZRbAnNREmcvoY2W2dvW4loVuDT9B9fU777mbV6zODpcgcHWsLL3lYbJ5Lt3y9cg==", 862 | "dev": true, 863 | "dependencies": { 864 | "@parcel/plugin": "2.12.0", 865 | "@parcel/types": "2.12.0", 866 | "@parcel/utils": "2.12.0", 867 | "posthtml": "^0.16.4" 868 | }, 869 | "engines": { 870 | "node": ">= 12.0.0", 871 | "parcel": "^2.12.0" 872 | }, 873 | "funding": { 874 | "type": "opencollective", 875 | "url": "https://opencollective.com/parcel" 876 | } 877 | }, 878 | "node_modules/@parcel/packager-wasm": { 879 | "version": "2.12.0", 880 | "resolved": "https://registry.npmjs.org/@parcel/packager-wasm/-/packager-wasm-2.12.0.tgz", 881 | "integrity": "sha512-fYqZzIqO9fGYveeImzF8ll6KRo2LrOXfD+2Y5U3BiX/wp9wv17dz50QLDQm9hmTcKGWxK4yWqKQh+Evp/fae7A==", 882 | "dev": true, 883 | "dependencies": { 884 | "@parcel/plugin": "2.12.0" 885 | }, 886 | "engines": { 887 | "node": ">=12.0.0", 888 | "parcel": "^2.12.0" 889 | }, 890 | "funding": { 891 | "type": "opencollective", 892 | "url": "https://opencollective.com/parcel" 893 | } 894 | }, 895 | "node_modules/@parcel/plugin": { 896 | "version": "2.12.0", 897 | "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.12.0.tgz", 898 | "integrity": "sha512-nc/uRA8DiMoe4neBbzV6kDndh/58a4wQuGKw5oEoIwBCHUvE2W8ZFSu7ollSXUGRzfacTt4NdY8TwS73ScWZ+g==", 899 | "dev": true, 900 | "dependencies": { 901 | "@parcel/types": "2.12.0" 902 | }, 903 | "engines": { 904 | "node": ">= 12.0.0" 905 | }, 906 | "funding": { 907 | "type": "opencollective", 908 | "url": "https://opencollective.com/parcel" 909 | } 910 | }, 911 | "node_modules/@parcel/profiler": { 912 | "version": "2.12.0", 913 | "resolved": "https://registry.npmjs.org/@parcel/profiler/-/profiler-2.12.0.tgz", 914 | "integrity": "sha512-q53fvl5LDcFYzMUtSusUBZSjQrKjMlLEBgKeQHFwkimwR1mgoseaDBDuNz0XvmzDzF1UelJ02TUKCGacU8W2qA==", 915 | "dev": true, 916 | "dependencies": { 917 | "@parcel/diagnostic": "2.12.0", 918 | "@parcel/events": "2.12.0", 919 | "chrome-trace-event": "^1.0.2" 920 | }, 921 | "engines": { 922 | "node": ">= 12.0.0" 923 | }, 924 | "funding": { 925 | "type": "opencollective", 926 | "url": "https://opencollective.com/parcel" 927 | } 928 | }, 929 | "node_modules/@parcel/reporter-cli": { 930 | "version": "2.12.0", 931 | "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.12.0.tgz", 932 | "integrity": "sha512-TqKsH4GVOLPSCanZ6tcTPj+rdVHERnt5y4bwTM82cajM21bCX1Ruwp8xOKU+03091oV2pv5ieB18pJyRF7IpIw==", 933 | "dev": true, 934 | "dependencies": { 935 | "@parcel/plugin": "2.12.0", 936 | "@parcel/types": "2.12.0", 937 | "@parcel/utils": "2.12.0", 938 | "chalk": "^4.1.0", 939 | "term-size": "^2.2.1" 940 | }, 941 | "engines": { 942 | "node": ">= 12.0.0", 943 | "parcel": "^2.12.0" 944 | }, 945 | "funding": { 946 | "type": "opencollective", 947 | "url": "https://opencollective.com/parcel" 948 | } 949 | }, 950 | "node_modules/@parcel/reporter-dev-server": { 951 | "version": "2.12.0", 952 | "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.12.0.tgz", 953 | "integrity": "sha512-tIcDqRvAPAttRlTV28dHcbWT5K2r/MBFks7nM4nrEDHWtnrCwimkDmZTc1kD8QOCCjGVwRHcQybpHvxfwol6GA==", 954 | "dev": true, 955 | "dependencies": { 956 | "@parcel/plugin": "2.12.0", 957 | "@parcel/utils": "2.12.0" 958 | }, 959 | "engines": { 960 | "node": ">= 12.0.0", 961 | "parcel": "^2.12.0" 962 | }, 963 | "funding": { 964 | "type": "opencollective", 965 | "url": "https://opencollective.com/parcel" 966 | } 967 | }, 968 | "node_modules/@parcel/reporter-tracer": { 969 | "version": "2.12.0", 970 | "resolved": "https://registry.npmjs.org/@parcel/reporter-tracer/-/reporter-tracer-2.12.0.tgz", 971 | "integrity": "sha512-g8rlu9GxB8Ut/F8WGx4zidIPQ4pcYFjU9bZO+fyRIPrSUFH2bKijCnbZcr4ntqzDGx74hwD6cCG4DBoleq2UlQ==", 972 | "dev": true, 973 | "dependencies": { 974 | "@parcel/plugin": "2.12.0", 975 | "@parcel/utils": "2.12.0", 976 | "chrome-trace-event": "^1.0.3", 977 | "nullthrows": "^1.1.1" 978 | }, 979 | "engines": { 980 | "node": ">= 12.0.0", 981 | "parcel": "^2.12.0" 982 | }, 983 | "funding": { 984 | "type": "opencollective", 985 | "url": "https://opencollective.com/parcel" 986 | } 987 | }, 988 | "node_modules/@parcel/resolver-default": { 989 | "version": "2.12.0", 990 | "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.12.0.tgz", 991 | "integrity": "sha512-uuhbajTax37TwCxu7V98JtRLiT6hzE4VYSu5B7Qkauy14/WFt2dz6GOUXPgVsED569/hkxebPx3KCMtZW6cHHA==", 992 | "dev": true, 993 | "dependencies": { 994 | "@parcel/node-resolver-core": "3.3.0", 995 | "@parcel/plugin": "2.12.0" 996 | }, 997 | "engines": { 998 | "node": ">= 12.0.0", 999 | "parcel": "^2.12.0" 1000 | }, 1001 | "funding": { 1002 | "type": "opencollective", 1003 | "url": "https://opencollective.com/parcel" 1004 | } 1005 | }, 1006 | "node_modules/@parcel/runtime-browser-hmr": { 1007 | "version": "2.12.0", 1008 | "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.12.0.tgz", 1009 | "integrity": "sha512-4ZLp2FWyD32r0GlTulO3+jxgsA3oO1P1b5oO2IWuWilfhcJH5LTiazpL5YdusUjtNn9PGN6QLAWfxmzRIfM+Ow==", 1010 | "dev": true, 1011 | "dependencies": { 1012 | "@parcel/plugin": "2.12.0", 1013 | "@parcel/utils": "2.12.0" 1014 | }, 1015 | "engines": { 1016 | "node": ">= 12.0.0", 1017 | "parcel": "^2.12.0" 1018 | }, 1019 | "funding": { 1020 | "type": "opencollective", 1021 | "url": "https://opencollective.com/parcel" 1022 | } 1023 | }, 1024 | "node_modules/@parcel/runtime-js": { 1025 | "version": "2.12.0", 1026 | "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.12.0.tgz", 1027 | "integrity": "sha512-sBerP32Z1crX5PfLNGDSXSdqzlllM++GVnVQVeM7DgMKS8JIFG3VLi28YkX+dYYGtPypm01JoIHCkvwiZEcQJg==", 1028 | "dev": true, 1029 | "dependencies": { 1030 | "@parcel/diagnostic": "2.12.0", 1031 | "@parcel/plugin": "2.12.0", 1032 | "@parcel/utils": "2.12.0", 1033 | "nullthrows": "^1.1.1" 1034 | }, 1035 | "engines": { 1036 | "node": ">= 12.0.0", 1037 | "parcel": "^2.12.0" 1038 | }, 1039 | "funding": { 1040 | "type": "opencollective", 1041 | "url": "https://opencollective.com/parcel" 1042 | } 1043 | }, 1044 | "node_modules/@parcel/runtime-react-refresh": { 1045 | "version": "2.12.0", 1046 | "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.12.0.tgz", 1047 | "integrity": "sha512-SCHkcczJIDFTFdLTzrHTkQ0aTrX3xH6jrA4UsCBL6ji61+w+ohy4jEEe9qCgJVXhnJfGLE43HNXek+0MStX+Mw==", 1048 | "dev": true, 1049 | "dependencies": { 1050 | "@parcel/plugin": "2.12.0", 1051 | "@parcel/utils": "2.12.0", 1052 | "react-error-overlay": "6.0.9", 1053 | "react-refresh": "^0.9.0" 1054 | }, 1055 | "engines": { 1056 | "node": ">= 12.0.0", 1057 | "parcel": "^2.12.0" 1058 | }, 1059 | "funding": { 1060 | "type": "opencollective", 1061 | "url": "https://opencollective.com/parcel" 1062 | } 1063 | }, 1064 | "node_modules/@parcel/runtime-service-worker": { 1065 | "version": "2.12.0", 1066 | "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.12.0.tgz", 1067 | "integrity": "sha512-BXuMBsfiwpIEnssn+jqfC3jkgbS8oxeo3C7xhSQsuSv+AF2FwY3O3AO1c1RBskEW3XrBLNINOJujroNw80VTKA==", 1068 | "dev": true, 1069 | "dependencies": { 1070 | "@parcel/plugin": "2.12.0", 1071 | "@parcel/utils": "2.12.0", 1072 | "nullthrows": "^1.1.1" 1073 | }, 1074 | "engines": { 1075 | "node": ">= 12.0.0", 1076 | "parcel": "^2.12.0" 1077 | }, 1078 | "funding": { 1079 | "type": "opencollective", 1080 | "url": "https://opencollective.com/parcel" 1081 | } 1082 | }, 1083 | "node_modules/@parcel/rust": { 1084 | "version": "2.12.0", 1085 | "resolved": "https://registry.npmjs.org/@parcel/rust/-/rust-2.12.0.tgz", 1086 | "integrity": "sha512-005cldMdFZFDPOjbDVEXcINQ3wT4vrxvSavRWI3Az0e3E18exO/x/mW9f648KtXugOXMAqCEqhFHcXECL9nmMw==", 1087 | "dev": true, 1088 | "engines": { 1089 | "node": ">= 12.0.0" 1090 | }, 1091 | "funding": { 1092 | "type": "opencollective", 1093 | "url": "https://opencollective.com/parcel" 1094 | } 1095 | }, 1096 | "node_modules/@parcel/source-map": { 1097 | "version": "2.1.1", 1098 | "resolved": "https://registry.npmjs.org/@parcel/source-map/-/source-map-2.1.1.tgz", 1099 | "integrity": "sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew==", 1100 | "dev": true, 1101 | "dependencies": { 1102 | "detect-libc": "^1.0.3" 1103 | }, 1104 | "engines": { 1105 | "node": "^12.18.3 || >=14" 1106 | } 1107 | }, 1108 | "node_modules/@parcel/source-map/node_modules/detect-libc": { 1109 | "version": "1.0.3", 1110 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", 1111 | "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", 1112 | "dev": true, 1113 | "bin": { 1114 | "detect-libc": "bin/detect-libc.js" 1115 | }, 1116 | "engines": { 1117 | "node": ">=0.10" 1118 | } 1119 | }, 1120 | "node_modules/@parcel/transformer-babel": { 1121 | "version": "2.12.0", 1122 | "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.12.0.tgz", 1123 | "integrity": "sha512-zQaBfOnf/l8rPxYGnsk/ufh/0EuqvmnxafjBIpKZ//j6rGylw5JCqXSb1QvvAqRYruKeccxGv7+HrxpqKU6V4A==", 1124 | "dev": true, 1125 | "dependencies": { 1126 | "@parcel/diagnostic": "2.12.0", 1127 | "@parcel/plugin": "2.12.0", 1128 | "@parcel/source-map": "^2.1.1", 1129 | "@parcel/utils": "2.12.0", 1130 | "browserslist": "^4.6.6", 1131 | "json5": "^2.2.0", 1132 | "nullthrows": "^1.1.1", 1133 | "semver": "^7.5.2" 1134 | }, 1135 | "engines": { 1136 | "node": ">= 12.0.0", 1137 | "parcel": "^2.12.0" 1138 | }, 1139 | "funding": { 1140 | "type": "opencollective", 1141 | "url": "https://opencollective.com/parcel" 1142 | } 1143 | }, 1144 | "node_modules/@parcel/transformer-css": { 1145 | "version": "2.12.0", 1146 | "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.12.0.tgz", 1147 | "integrity": "sha512-vXhOqoAlQGATYyQ433Z1DXKmiKmzOAUmKysbYH3FD+LKEKLMEl/pA14goqp00TW+A/EjtSKKyeMyHlMIIUqj4Q==", 1148 | "dev": true, 1149 | "dependencies": { 1150 | "@parcel/diagnostic": "2.12.0", 1151 | "@parcel/plugin": "2.12.0", 1152 | "@parcel/source-map": "^2.1.1", 1153 | "@parcel/utils": "2.12.0", 1154 | "browserslist": "^4.6.6", 1155 | "lightningcss": "^1.22.1", 1156 | "nullthrows": "^1.1.1" 1157 | }, 1158 | "engines": { 1159 | "node": ">= 12.0.0", 1160 | "parcel": "^2.12.0" 1161 | }, 1162 | "funding": { 1163 | "type": "opencollective", 1164 | "url": "https://opencollective.com/parcel" 1165 | } 1166 | }, 1167 | "node_modules/@parcel/transformer-html": { 1168 | "version": "2.12.0", 1169 | "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.12.0.tgz", 1170 | "integrity": "sha512-5jW4dFFBlYBvIQk4nrH62rfA/G/KzVzEDa6S+Nne0xXhglLjkm64Ci9b/d4tKZfuGWUbpm2ASAq8skti/nfpXw==", 1171 | "dev": true, 1172 | "dependencies": { 1173 | "@parcel/diagnostic": "2.12.0", 1174 | "@parcel/plugin": "2.12.0", 1175 | "@parcel/rust": "2.12.0", 1176 | "nullthrows": "^1.1.1", 1177 | "posthtml": "^0.16.5", 1178 | "posthtml-parser": "^0.10.1", 1179 | "posthtml-render": "^3.0.0", 1180 | "semver": "^7.5.2", 1181 | "srcset": "4" 1182 | }, 1183 | "engines": { 1184 | "node": ">= 12.0.0", 1185 | "parcel": "^2.12.0" 1186 | }, 1187 | "funding": { 1188 | "type": "opencollective", 1189 | "url": "https://opencollective.com/parcel" 1190 | } 1191 | }, 1192 | "node_modules/@parcel/transformer-html/node_modules/srcset": { 1193 | "version": "4.0.0", 1194 | "resolved": "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz", 1195 | "integrity": "sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==", 1196 | "dev": true, 1197 | "engines": { 1198 | "node": ">=12" 1199 | }, 1200 | "funding": { 1201 | "url": "https://github.com/sponsors/sindresorhus" 1202 | } 1203 | }, 1204 | "node_modules/@parcel/transformer-image": { 1205 | "version": "2.12.0", 1206 | "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.12.0.tgz", 1207 | "integrity": "sha512-8hXrGm2IRII49R7lZ0RpmNk27EhcsH+uNKsvxuMpXPuEnWgC/ha/IrjaI29xCng1uGur74bJF43NUSQhR4aTdw==", 1208 | "dev": true, 1209 | "dependencies": { 1210 | "@parcel/plugin": "2.12.0", 1211 | "@parcel/utils": "2.12.0", 1212 | "@parcel/workers": "2.12.0", 1213 | "nullthrows": "^1.1.1" 1214 | }, 1215 | "engines": { 1216 | "node": ">= 12.0.0", 1217 | "parcel": "^2.12.0" 1218 | }, 1219 | "peerDependencies": { 1220 | "@parcel/core": "^2.12.0" 1221 | } 1222 | }, 1223 | "node_modules/@parcel/transformer-js": { 1224 | "version": "2.12.0", 1225 | "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.12.0.tgz", 1226 | "integrity": "sha512-OSZpOu+FGDbC/xivu24v092D9w6EGytB3vidwbdiJ2FaPgfV7rxS0WIUjH4I0OcvHAcitArRXL0a3+HrNTdQQw==", 1227 | "dev": true, 1228 | "dependencies": { 1229 | "@parcel/diagnostic": "2.12.0", 1230 | "@parcel/plugin": "2.12.0", 1231 | "@parcel/rust": "2.12.0", 1232 | "@parcel/source-map": "^2.1.1", 1233 | "@parcel/utils": "2.12.0", 1234 | "@parcel/workers": "2.12.0", 1235 | "@swc/helpers": "^0.5.0", 1236 | "browserslist": "^4.6.6", 1237 | "nullthrows": "^1.1.1", 1238 | "regenerator-runtime": "^0.13.7", 1239 | "semver": "^7.5.2" 1240 | }, 1241 | "engines": { 1242 | "node": ">= 12.0.0", 1243 | "parcel": "^2.12.0" 1244 | }, 1245 | "funding": { 1246 | "type": "opencollective", 1247 | "url": "https://opencollective.com/parcel" 1248 | }, 1249 | "peerDependencies": { 1250 | "@parcel/core": "^2.12.0" 1251 | } 1252 | }, 1253 | "node_modules/@parcel/transformer-json": { 1254 | "version": "2.12.0", 1255 | "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.12.0.tgz", 1256 | "integrity": "sha512-Utv64GLRCQILK5r0KFs4o7I41ixMPllwOLOhkdjJKvf1hZmN6WqfOmB1YLbWS/y5Zb/iB52DU2pWZm96vLFQZQ==", 1257 | "dev": true, 1258 | "dependencies": { 1259 | "@parcel/plugin": "2.12.0", 1260 | "json5": "^2.2.0" 1261 | }, 1262 | "engines": { 1263 | "node": ">= 12.0.0", 1264 | "parcel": "^2.12.0" 1265 | }, 1266 | "funding": { 1267 | "type": "opencollective", 1268 | "url": "https://opencollective.com/parcel" 1269 | } 1270 | }, 1271 | "node_modules/@parcel/transformer-postcss": { 1272 | "version": "2.12.0", 1273 | "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.12.0.tgz", 1274 | "integrity": "sha512-FZqn+oUtiLfPOn67EZxPpBkfdFiTnF4iwiXPqvst3XI8H+iC+yNgzmtJkunOOuylpYY6NOU5jT8d7saqWSDv2Q==", 1275 | "dev": true, 1276 | "dependencies": { 1277 | "@parcel/diagnostic": "2.12.0", 1278 | "@parcel/plugin": "2.12.0", 1279 | "@parcel/rust": "2.12.0", 1280 | "@parcel/utils": "2.12.0", 1281 | "clone": "^2.1.1", 1282 | "nullthrows": "^1.1.1", 1283 | "postcss-value-parser": "^4.2.0", 1284 | "semver": "^7.5.2" 1285 | }, 1286 | "engines": { 1287 | "node": ">= 12.0.0", 1288 | "parcel": "^2.12.0" 1289 | }, 1290 | "funding": { 1291 | "type": "opencollective", 1292 | "url": "https://opencollective.com/parcel" 1293 | } 1294 | }, 1295 | "node_modules/@parcel/transformer-posthtml": { 1296 | "version": "2.12.0", 1297 | "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.12.0.tgz", 1298 | "integrity": "sha512-z6Z7rav/pcaWdeD+2sDUcd0mmNZRUvtHaUGa50Y2mr+poxrKilpsnFMSiWBT+oOqPt7j71jzDvrdnAF4XkCljg==", 1299 | "dev": true, 1300 | "dependencies": { 1301 | "@parcel/plugin": "2.12.0", 1302 | "@parcel/utils": "2.12.0", 1303 | "nullthrows": "^1.1.1", 1304 | "posthtml": "^0.16.5", 1305 | "posthtml-parser": "^0.10.1", 1306 | "posthtml-render": "^3.0.0", 1307 | "semver": "^7.5.2" 1308 | }, 1309 | "engines": { 1310 | "node": ">= 12.0.0", 1311 | "parcel": "^2.12.0" 1312 | }, 1313 | "funding": { 1314 | "type": "opencollective", 1315 | "url": "https://opencollective.com/parcel" 1316 | } 1317 | }, 1318 | "node_modules/@parcel/transformer-raw": { 1319 | "version": "2.12.0", 1320 | "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.12.0.tgz", 1321 | "integrity": "sha512-Ht1fQvXxix0NncdnmnXZsa6hra20RXYh1VqhBYZLsDfkvGGFnXIgO03Jqn4Z8MkKoa0tiNbDhpKIeTjyclbBxQ==", 1322 | "dev": true, 1323 | "dependencies": { 1324 | "@parcel/plugin": "2.12.0" 1325 | }, 1326 | "engines": { 1327 | "node": ">= 12.0.0", 1328 | "parcel": "^2.12.0" 1329 | }, 1330 | "funding": { 1331 | "type": "opencollective", 1332 | "url": "https://opencollective.com/parcel" 1333 | } 1334 | }, 1335 | "node_modules/@parcel/transformer-react-refresh-wrap": { 1336 | "version": "2.12.0", 1337 | "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.12.0.tgz", 1338 | "integrity": "sha512-GE8gmP2AZtkpBIV5vSCVhewgOFRhqwdM5Q9jNPOY5PKcM3/Ff0qCqDiTzzGLhk0/VMBrdjssrfZkVx6S/lHdJw==", 1339 | "dev": true, 1340 | "dependencies": { 1341 | "@parcel/plugin": "2.12.0", 1342 | "@parcel/utils": "2.12.0", 1343 | "react-refresh": "^0.9.0" 1344 | }, 1345 | "engines": { 1346 | "node": ">= 12.0.0", 1347 | "parcel": "^2.12.0" 1348 | }, 1349 | "funding": { 1350 | "type": "opencollective", 1351 | "url": "https://opencollective.com/parcel" 1352 | } 1353 | }, 1354 | "node_modules/@parcel/transformer-svg": { 1355 | "version": "2.12.0", 1356 | "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.12.0.tgz", 1357 | "integrity": "sha512-cZJqGRJ4JNdYcb+vj94J7PdOuTnwyy45dM9xqbIMH+HSiiIkfrMsdEwYft0GTyFTdsnf+hdHn3tau7Qa5hhX+A==", 1358 | "dev": true, 1359 | "dependencies": { 1360 | "@parcel/diagnostic": "2.12.0", 1361 | "@parcel/plugin": "2.12.0", 1362 | "@parcel/rust": "2.12.0", 1363 | "nullthrows": "^1.1.1", 1364 | "posthtml": "^0.16.5", 1365 | "posthtml-parser": "^0.10.1", 1366 | "posthtml-render": "^3.0.0", 1367 | "semver": "^7.5.2" 1368 | }, 1369 | "engines": { 1370 | "node": ">= 12.0.0", 1371 | "parcel": "^2.12.0" 1372 | }, 1373 | "funding": { 1374 | "type": "opencollective", 1375 | "url": "https://opencollective.com/parcel" 1376 | } 1377 | }, 1378 | "node_modules/@parcel/types": { 1379 | "version": "2.12.0", 1380 | "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.12.0.tgz", 1381 | "integrity": "sha512-8zAFiYNCwNTQcglIObyNwKfRYQK5ELlL13GuBOrSMxueUiI5ylgsGbTS1N7J3dAGZixHO8KhHGv5a71FILn9rQ==", 1382 | "dev": true, 1383 | "dependencies": { 1384 | "@parcel/cache": "2.12.0", 1385 | "@parcel/diagnostic": "2.12.0", 1386 | "@parcel/fs": "2.12.0", 1387 | "@parcel/package-manager": "2.12.0", 1388 | "@parcel/source-map": "^2.1.1", 1389 | "@parcel/workers": "2.12.0", 1390 | "utility-types": "^3.10.0" 1391 | } 1392 | }, 1393 | "node_modules/@parcel/utils": { 1394 | "version": "2.12.0", 1395 | "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.12.0.tgz", 1396 | "integrity": "sha512-z1JhLuZ8QmDaYoEIuUCVZlhcFrS7LMfHrb2OCRui5SQFntRWBH2fNM6H/fXXUkT9SkxcuFP2DUA6/m4+Gkz72g==", 1397 | "dev": true, 1398 | "dependencies": { 1399 | "@parcel/codeframe": "2.12.0", 1400 | "@parcel/diagnostic": "2.12.0", 1401 | "@parcel/logger": "2.12.0", 1402 | "@parcel/markdown-ansi": "2.12.0", 1403 | "@parcel/rust": "2.12.0", 1404 | "@parcel/source-map": "^2.1.1", 1405 | "chalk": "^4.1.0", 1406 | "nullthrows": "^1.1.1" 1407 | }, 1408 | "engines": { 1409 | "node": ">= 12.0.0" 1410 | }, 1411 | "funding": { 1412 | "type": "opencollective", 1413 | "url": "https://opencollective.com/parcel" 1414 | } 1415 | }, 1416 | "node_modules/@parcel/watcher": { 1417 | "version": "2.4.1", 1418 | "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.4.1.tgz", 1419 | "integrity": "sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA==", 1420 | "dev": true, 1421 | "dependencies": { 1422 | "detect-libc": "^1.0.3", 1423 | "is-glob": "^4.0.3", 1424 | "micromatch": "^4.0.5", 1425 | "node-addon-api": "^7.0.0" 1426 | }, 1427 | "engines": { 1428 | "node": ">= 10.0.0" 1429 | }, 1430 | "funding": { 1431 | "type": "opencollective", 1432 | "url": "https://opencollective.com/parcel" 1433 | }, 1434 | "optionalDependencies": { 1435 | "@parcel/watcher-android-arm64": "2.4.1", 1436 | "@parcel/watcher-darwin-arm64": "2.4.1", 1437 | "@parcel/watcher-darwin-x64": "2.4.1", 1438 | "@parcel/watcher-freebsd-x64": "2.4.1", 1439 | "@parcel/watcher-linux-arm-glibc": "2.4.1", 1440 | "@parcel/watcher-linux-arm64-glibc": "2.4.1", 1441 | "@parcel/watcher-linux-arm64-musl": "2.4.1", 1442 | "@parcel/watcher-linux-x64-glibc": "2.4.1", 1443 | "@parcel/watcher-linux-x64-musl": "2.4.1", 1444 | "@parcel/watcher-win32-arm64": "2.4.1", 1445 | "@parcel/watcher-win32-ia32": "2.4.1", 1446 | "@parcel/watcher-win32-x64": "2.4.1" 1447 | } 1448 | }, 1449 | "node_modules/@parcel/watcher-darwin-arm64": { 1450 | "version": "2.4.1", 1451 | "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.1.tgz", 1452 | "integrity": "sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA==", 1453 | "cpu": [ 1454 | "arm64" 1455 | ], 1456 | "dev": true, 1457 | "optional": true, 1458 | "os": [ 1459 | "darwin" 1460 | ], 1461 | "engines": { 1462 | "node": ">= 10.0.0" 1463 | }, 1464 | "funding": { 1465 | "type": "opencollective", 1466 | "url": "https://opencollective.com/parcel" 1467 | } 1468 | }, 1469 | "node_modules/@parcel/watcher/node_modules/detect-libc": { 1470 | "version": "1.0.3", 1471 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", 1472 | "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", 1473 | "dev": true, 1474 | "bin": { 1475 | "detect-libc": "bin/detect-libc.js" 1476 | }, 1477 | "engines": { 1478 | "node": ">=0.10" 1479 | } 1480 | }, 1481 | "node_modules/@parcel/workers": { 1482 | "version": "2.12.0", 1483 | "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.12.0.tgz", 1484 | "integrity": "sha512-zv5We5Jmb+ZWXlU6A+AufyjY4oZckkxsZ8J4dvyWL0W8IQvGO1JB4FGeryyttzQv3RM3OxcN/BpTGPiDG6keBw==", 1485 | "dev": true, 1486 | "dependencies": { 1487 | "@parcel/diagnostic": "2.12.0", 1488 | "@parcel/logger": "2.12.0", 1489 | "@parcel/profiler": "2.12.0", 1490 | "@parcel/types": "2.12.0", 1491 | "@parcel/utils": "2.12.0", 1492 | "nullthrows": "^1.1.1" 1493 | }, 1494 | "engines": { 1495 | "node": ">= 12.0.0" 1496 | }, 1497 | "funding": { 1498 | "type": "opencollective", 1499 | "url": "https://opencollective.com/parcel" 1500 | }, 1501 | "peerDependencies": { 1502 | "@parcel/core": "^2.12.0" 1503 | } 1504 | }, 1505 | "node_modules/@swc/core": { 1506 | "version": "1.6.5", 1507 | "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.6.5.tgz", 1508 | "integrity": "sha512-tyVvUK/HDOUUsK6/GmWvnqUtD9oDpPUA4f7f7JCOV8hXxtfjMtAZeBKf93yrB1XZet69TDR7EN0hFC6i4MF0Ig==", 1509 | "dev": true, 1510 | "hasInstallScript": true, 1511 | "dependencies": { 1512 | "@swc/counter": "^0.1.3", 1513 | "@swc/types": "^0.1.9" 1514 | }, 1515 | "engines": { 1516 | "node": ">=10" 1517 | }, 1518 | "funding": { 1519 | "type": "opencollective", 1520 | "url": "https://opencollective.com/swc" 1521 | }, 1522 | "optionalDependencies": { 1523 | "@swc/core-darwin-arm64": "1.6.5", 1524 | "@swc/core-darwin-x64": "1.6.5", 1525 | "@swc/core-linux-arm-gnueabihf": "1.6.5", 1526 | "@swc/core-linux-arm64-gnu": "1.6.5", 1527 | "@swc/core-linux-arm64-musl": "1.6.5", 1528 | "@swc/core-linux-x64-gnu": "1.6.5", 1529 | "@swc/core-linux-x64-musl": "1.6.5", 1530 | "@swc/core-win32-arm64-msvc": "1.6.5", 1531 | "@swc/core-win32-ia32-msvc": "1.6.5", 1532 | "@swc/core-win32-x64-msvc": "1.6.5" 1533 | }, 1534 | "peerDependencies": { 1535 | "@swc/helpers": "*" 1536 | }, 1537 | "peerDependenciesMeta": { 1538 | "@swc/helpers": { 1539 | "optional": true 1540 | } 1541 | } 1542 | }, 1543 | "node_modules/@swc/core-darwin-arm64": { 1544 | "version": "1.6.5", 1545 | "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.6.5.tgz", 1546 | "integrity": "sha512-RGQhMdni2v1/ANQ/2K+F+QYdzaucekYBewZcX1ogqJ8G5sbPaBdYdDN1qQ4kHLCIkPtGP6qC7c71qPEqL2RidQ==", 1547 | "cpu": [ 1548 | "arm64" 1549 | ], 1550 | "dev": true, 1551 | "optional": true, 1552 | "os": [ 1553 | "darwin" 1554 | ], 1555 | "engines": { 1556 | "node": ">=10" 1557 | } 1558 | }, 1559 | "node_modules/@swc/counter": { 1560 | "version": "0.1.3", 1561 | "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", 1562 | "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", 1563 | "dev": true 1564 | }, 1565 | "node_modules/@swc/helpers": { 1566 | "version": "0.5.11", 1567 | "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.11.tgz", 1568 | "integrity": "sha512-YNlnKRWF2sVojTpIyzwou9XoTNbzbzONwRhOoniEioF1AtaitTvVZblaQRrAzChWQ1bLYyYSWzM18y4WwgzJ+A==", 1569 | "dev": true, 1570 | "dependencies": { 1571 | "tslib": "^2.4.0" 1572 | } 1573 | }, 1574 | "node_modules/@swc/types": { 1575 | "version": "0.1.9", 1576 | "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.9.tgz", 1577 | "integrity": "sha512-qKnCno++jzcJ4lM4NTfYifm1EFSCeIfKiAHAfkENZAV5Kl9PjJIyd2yeeVv6c/2CckuLyv2NmRC5pv6pm2WQBg==", 1578 | "dev": true, 1579 | "dependencies": { 1580 | "@swc/counter": "^0.1.3" 1581 | } 1582 | }, 1583 | "node_modules/@trysound/sax": { 1584 | "version": "0.2.0", 1585 | "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", 1586 | "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", 1587 | "dev": true, 1588 | "engines": { 1589 | "node": ">=10.13.0" 1590 | } 1591 | }, 1592 | "node_modules/abortcontroller-polyfill": { 1593 | "version": "1.7.5", 1594 | "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz", 1595 | "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==", 1596 | "dev": true 1597 | }, 1598 | "node_modules/ansi-styles": { 1599 | "version": "4.3.0", 1600 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 1601 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 1602 | "dev": true, 1603 | "dependencies": { 1604 | "color-convert": "^2.0.1" 1605 | }, 1606 | "engines": { 1607 | "node": ">=8" 1608 | }, 1609 | "funding": { 1610 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 1611 | } 1612 | }, 1613 | "node_modules/argparse": { 1614 | "version": "2.0.1", 1615 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 1616 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 1617 | "dev": true 1618 | }, 1619 | "node_modules/base-x": { 1620 | "version": "3.0.9", 1621 | "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", 1622 | "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", 1623 | "dev": true, 1624 | "dependencies": { 1625 | "safe-buffer": "^5.0.1" 1626 | } 1627 | }, 1628 | "node_modules/base64-js": { 1629 | "version": "1.5.1", 1630 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 1631 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 1632 | "dev": true, 1633 | "funding": [ 1634 | { 1635 | "type": "github", 1636 | "url": "https://github.com/sponsors/feross" 1637 | }, 1638 | { 1639 | "type": "patreon", 1640 | "url": "https://www.patreon.com/feross" 1641 | }, 1642 | { 1643 | "type": "consulting", 1644 | "url": "https://feross.org/support" 1645 | } 1646 | ] 1647 | }, 1648 | "node_modules/boolbase": { 1649 | "version": "1.0.0", 1650 | "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", 1651 | "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", 1652 | "dev": true 1653 | }, 1654 | "node_modules/braces": { 1655 | "version": "3.0.3", 1656 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", 1657 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", 1658 | "dev": true, 1659 | "dependencies": { 1660 | "fill-range": "^7.1.1" 1661 | }, 1662 | "engines": { 1663 | "node": ">=8" 1664 | } 1665 | }, 1666 | "node_modules/browserslist": { 1667 | "version": "4.23.1", 1668 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz", 1669 | "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", 1670 | "dev": true, 1671 | "funding": [ 1672 | { 1673 | "type": "opencollective", 1674 | "url": "https://opencollective.com/browserslist" 1675 | }, 1676 | { 1677 | "type": "tidelift", 1678 | "url": "https://tidelift.com/funding/github/npm/browserslist" 1679 | }, 1680 | { 1681 | "type": "github", 1682 | "url": "https://github.com/sponsors/ai" 1683 | } 1684 | ], 1685 | "dependencies": { 1686 | "caniuse-lite": "^1.0.30001629", 1687 | "electron-to-chromium": "^1.4.796", 1688 | "node-releases": "^2.0.14", 1689 | "update-browserslist-db": "^1.0.16" 1690 | }, 1691 | "bin": { 1692 | "browserslist": "cli.js" 1693 | }, 1694 | "engines": { 1695 | "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" 1696 | } 1697 | }, 1698 | "node_modules/buffer": { 1699 | "version": "6.0.3", 1700 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", 1701 | "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", 1702 | "dev": true, 1703 | "funding": [ 1704 | { 1705 | "type": "github", 1706 | "url": "https://github.com/sponsors/feross" 1707 | }, 1708 | { 1709 | "type": "patreon", 1710 | "url": "https://www.patreon.com/feross" 1711 | }, 1712 | { 1713 | "type": "consulting", 1714 | "url": "https://feross.org/support" 1715 | } 1716 | ], 1717 | "dependencies": { 1718 | "base64-js": "^1.3.1", 1719 | "ieee754": "^1.2.1" 1720 | } 1721 | }, 1722 | "node_modules/callsites": { 1723 | "version": "3.1.0", 1724 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 1725 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 1726 | "dev": true, 1727 | "engines": { 1728 | "node": ">=6" 1729 | } 1730 | }, 1731 | "node_modules/caniuse-lite": { 1732 | "version": "1.0.30001636", 1733 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz", 1734 | "integrity": "sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==", 1735 | "dev": true, 1736 | "funding": [ 1737 | { 1738 | "type": "opencollective", 1739 | "url": "https://opencollective.com/browserslist" 1740 | }, 1741 | { 1742 | "type": "tidelift", 1743 | "url": "https://tidelift.com/funding/github/npm/caniuse-lite" 1744 | }, 1745 | { 1746 | "type": "github", 1747 | "url": "https://github.com/sponsors/ai" 1748 | } 1749 | ] 1750 | }, 1751 | "node_modules/chalk": { 1752 | "version": "4.1.2", 1753 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 1754 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 1755 | "dev": true, 1756 | "dependencies": { 1757 | "ansi-styles": "^4.1.0", 1758 | "supports-color": "^7.1.0" 1759 | }, 1760 | "engines": { 1761 | "node": ">=10" 1762 | }, 1763 | "funding": { 1764 | "url": "https://github.com/chalk/chalk?sponsor=1" 1765 | } 1766 | }, 1767 | "node_modules/chrome-trace-event": { 1768 | "version": "1.0.4", 1769 | "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", 1770 | "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", 1771 | "dev": true, 1772 | "engines": { 1773 | "node": ">=6.0" 1774 | } 1775 | }, 1776 | "node_modules/clone": { 1777 | "version": "2.1.2", 1778 | "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", 1779 | "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", 1780 | "dev": true, 1781 | "engines": { 1782 | "node": ">=0.8" 1783 | } 1784 | }, 1785 | "node_modules/color-convert": { 1786 | "version": "2.0.1", 1787 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 1788 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 1789 | "dev": true, 1790 | "dependencies": { 1791 | "color-name": "~1.1.4" 1792 | }, 1793 | "engines": { 1794 | "node": ">=7.0.0" 1795 | } 1796 | }, 1797 | "node_modules/color-name": { 1798 | "version": "1.1.4", 1799 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 1800 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 1801 | "dev": true 1802 | }, 1803 | "node_modules/colyseus.js": { 1804 | "version": "0.16.3", 1805 | "resolved": "https://registry.npmjs.org/colyseus.js/-/colyseus.js-0.16.3.tgz", 1806 | "integrity": "sha512-JyBz5D6Pmk10ACvivUc/WyMePmnSrC5DpYYBvM8bl4xfB3BQL7H5l94EPHA1VTII7rsjhXxew4OvbVr1viSA7g==", 1807 | "license": "MIT", 1808 | "dependencies": { 1809 | "@colyseus/msgpackr": "^1.10.5", 1810 | "@colyseus/schema": "^3.0.0", 1811 | "httpie": "^2.0.0-next.13", 1812 | "tslib": "^2.1.0", 1813 | "ws": "^8.13.0" 1814 | }, 1815 | "engines": { 1816 | "node": ">= 12.x" 1817 | }, 1818 | "funding": { 1819 | "url": "https://github.com/sponsors/endel" 1820 | } 1821 | }, 1822 | "node_modules/commander": { 1823 | "version": "7.2.0", 1824 | "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", 1825 | "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", 1826 | "dev": true, 1827 | "engines": { 1828 | "node": ">= 10" 1829 | } 1830 | }, 1831 | "node_modules/cosmiconfig": { 1832 | "version": "9.0.0", 1833 | "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", 1834 | "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", 1835 | "dev": true, 1836 | "dependencies": { 1837 | "env-paths": "^2.2.1", 1838 | "import-fresh": "^3.3.0", 1839 | "js-yaml": "^4.1.0", 1840 | "parse-json": "^5.2.0" 1841 | }, 1842 | "engines": { 1843 | "node": ">=14" 1844 | }, 1845 | "funding": { 1846 | "url": "https://github.com/sponsors/d-fischer" 1847 | }, 1848 | "peerDependencies": { 1849 | "typescript": ">=4.9.5" 1850 | }, 1851 | "peerDependenciesMeta": { 1852 | "typescript": { 1853 | "optional": true 1854 | } 1855 | } 1856 | }, 1857 | "node_modules/css-select": { 1858 | "version": "5.1.0", 1859 | "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", 1860 | "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", 1861 | "dev": true, 1862 | "optional": true, 1863 | "peer": true, 1864 | "dependencies": { 1865 | "boolbase": "^1.0.0", 1866 | "css-what": "^6.1.0", 1867 | "domhandler": "^5.0.2", 1868 | "domutils": "^3.0.1", 1869 | "nth-check": "^2.0.1" 1870 | }, 1871 | "funding": { 1872 | "url": "https://github.com/sponsors/fb55" 1873 | } 1874 | }, 1875 | "node_modules/css-select/node_modules/dom-serializer": { 1876 | "version": "2.0.0", 1877 | "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", 1878 | "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", 1879 | "dev": true, 1880 | "optional": true, 1881 | "peer": true, 1882 | "dependencies": { 1883 | "domelementtype": "^2.3.0", 1884 | "domhandler": "^5.0.2", 1885 | "entities": "^4.2.0" 1886 | }, 1887 | "funding": { 1888 | "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" 1889 | } 1890 | }, 1891 | "node_modules/css-select/node_modules/domhandler": { 1892 | "version": "5.0.3", 1893 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", 1894 | "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", 1895 | "dev": true, 1896 | "optional": true, 1897 | "peer": true, 1898 | "dependencies": { 1899 | "domelementtype": "^2.3.0" 1900 | }, 1901 | "engines": { 1902 | "node": ">= 4" 1903 | }, 1904 | "funding": { 1905 | "url": "https://github.com/fb55/domhandler?sponsor=1" 1906 | } 1907 | }, 1908 | "node_modules/css-select/node_modules/domutils": { 1909 | "version": "3.1.0", 1910 | "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", 1911 | "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", 1912 | "dev": true, 1913 | "optional": true, 1914 | "peer": true, 1915 | "dependencies": { 1916 | "dom-serializer": "^2.0.0", 1917 | "domelementtype": "^2.3.0", 1918 | "domhandler": "^5.0.3" 1919 | }, 1920 | "funding": { 1921 | "url": "https://github.com/fb55/domutils?sponsor=1" 1922 | } 1923 | }, 1924 | "node_modules/css-select/node_modules/entities": { 1925 | "version": "4.5.0", 1926 | "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", 1927 | "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", 1928 | "dev": true, 1929 | "optional": true, 1930 | "peer": true, 1931 | "engines": { 1932 | "node": ">=0.12" 1933 | }, 1934 | "funding": { 1935 | "url": "https://github.com/fb55/entities?sponsor=1" 1936 | } 1937 | }, 1938 | "node_modules/css-tree": { 1939 | "version": "2.3.1", 1940 | "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", 1941 | "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", 1942 | "dev": true, 1943 | "optional": true, 1944 | "peer": true, 1945 | "dependencies": { 1946 | "mdn-data": "2.0.30", 1947 | "source-map-js": "^1.0.1" 1948 | }, 1949 | "engines": { 1950 | "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" 1951 | } 1952 | }, 1953 | "node_modules/css-what": { 1954 | "version": "6.1.0", 1955 | "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", 1956 | "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", 1957 | "dev": true, 1958 | "engines": { 1959 | "node": ">= 6" 1960 | }, 1961 | "funding": { 1962 | "url": "https://github.com/sponsors/fb55" 1963 | } 1964 | }, 1965 | "node_modules/csso": { 1966 | "version": "5.0.5", 1967 | "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", 1968 | "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", 1969 | "dev": true, 1970 | "optional": true, 1971 | "peer": true, 1972 | "dependencies": { 1973 | "css-tree": "~2.2.0" 1974 | }, 1975 | "engines": { 1976 | "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", 1977 | "npm": ">=7.0.0" 1978 | } 1979 | }, 1980 | "node_modules/csso/node_modules/css-tree": { 1981 | "version": "2.2.1", 1982 | "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", 1983 | "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", 1984 | "dev": true, 1985 | "optional": true, 1986 | "peer": true, 1987 | "dependencies": { 1988 | "mdn-data": "2.0.28", 1989 | "source-map-js": "^1.0.1" 1990 | }, 1991 | "engines": { 1992 | "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", 1993 | "npm": ">=7.0.0" 1994 | } 1995 | }, 1996 | "node_modules/csso/node_modules/mdn-data": { 1997 | "version": "2.0.28", 1998 | "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", 1999 | "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", 2000 | "dev": true, 2001 | "optional": true, 2002 | "peer": true 2003 | }, 2004 | "node_modules/detect-libc": { 2005 | "version": "2.0.3", 2006 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", 2007 | "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", 2008 | "devOptional": true, 2009 | "engines": { 2010 | "node": ">=8" 2011 | } 2012 | }, 2013 | "node_modules/dom-serializer": { 2014 | "version": "1.4.1", 2015 | "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", 2016 | "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", 2017 | "dev": true, 2018 | "dependencies": { 2019 | "domelementtype": "^2.0.1", 2020 | "domhandler": "^4.2.0", 2021 | "entities": "^2.0.0" 2022 | }, 2023 | "funding": { 2024 | "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" 2025 | } 2026 | }, 2027 | "node_modules/dom-serializer/node_modules/entities": { 2028 | "version": "2.2.0", 2029 | "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", 2030 | "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", 2031 | "dev": true, 2032 | "funding": { 2033 | "url": "https://github.com/fb55/entities?sponsor=1" 2034 | } 2035 | }, 2036 | "node_modules/domelementtype": { 2037 | "version": "2.3.0", 2038 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", 2039 | "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", 2040 | "dev": true, 2041 | "funding": [ 2042 | { 2043 | "type": "github", 2044 | "url": "https://github.com/sponsors/fb55" 2045 | } 2046 | ] 2047 | }, 2048 | "node_modules/domhandler": { 2049 | "version": "4.3.1", 2050 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", 2051 | "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", 2052 | "dev": true, 2053 | "dependencies": { 2054 | "domelementtype": "^2.2.0" 2055 | }, 2056 | "engines": { 2057 | "node": ">= 4" 2058 | }, 2059 | "funding": { 2060 | "url": "https://github.com/fb55/domhandler?sponsor=1" 2061 | } 2062 | }, 2063 | "node_modules/domutils": { 2064 | "version": "2.8.0", 2065 | "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", 2066 | "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", 2067 | "dev": true, 2068 | "dependencies": { 2069 | "dom-serializer": "^1.0.1", 2070 | "domelementtype": "^2.2.0", 2071 | "domhandler": "^4.2.0" 2072 | }, 2073 | "funding": { 2074 | "url": "https://github.com/fb55/domutils?sponsor=1" 2075 | } 2076 | }, 2077 | "node_modules/dotenv": { 2078 | "version": "7.0.0", 2079 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-7.0.0.tgz", 2080 | "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==", 2081 | "dev": true, 2082 | "engines": { 2083 | "node": ">=6" 2084 | } 2085 | }, 2086 | "node_modules/dotenv-expand": { 2087 | "version": "5.1.0", 2088 | "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", 2089 | "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", 2090 | "dev": true 2091 | }, 2092 | "node_modules/electron-to-chromium": { 2093 | "version": "1.4.812", 2094 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.812.tgz", 2095 | "integrity": "sha512-7L8fC2Ey/b6SePDFKR2zHAy4mbdp1/38Yk5TsARO66W3hC5KEaeKMMHoxwtuH+jcu2AYLSn9QX04i95t6Fl1Hg==", 2096 | "dev": true 2097 | }, 2098 | "node_modules/entities": { 2099 | "version": "3.0.1", 2100 | "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", 2101 | "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", 2102 | "dev": true, 2103 | "engines": { 2104 | "node": ">=0.12" 2105 | }, 2106 | "funding": { 2107 | "url": "https://github.com/fb55/entities?sponsor=1" 2108 | } 2109 | }, 2110 | "node_modules/env-paths": { 2111 | "version": "2.2.1", 2112 | "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", 2113 | "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", 2114 | "dev": true, 2115 | "engines": { 2116 | "node": ">=6" 2117 | } 2118 | }, 2119 | "node_modules/error-ex": { 2120 | "version": "1.3.2", 2121 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", 2122 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", 2123 | "dev": true, 2124 | "dependencies": { 2125 | "is-arrayish": "^0.2.1" 2126 | } 2127 | }, 2128 | "node_modules/escalade": { 2129 | "version": "3.1.2", 2130 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", 2131 | "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", 2132 | "dev": true, 2133 | "engines": { 2134 | "node": ">=6" 2135 | } 2136 | }, 2137 | "node_modules/escape-string-regexp": { 2138 | "version": "1.0.5", 2139 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 2140 | "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", 2141 | "dev": true, 2142 | "engines": { 2143 | "node": ">=0.8.0" 2144 | } 2145 | }, 2146 | "node_modules/eventemitter3": { 2147 | "version": "5.0.1", 2148 | "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", 2149 | "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" 2150 | }, 2151 | "node_modules/fill-range": { 2152 | "version": "7.1.1", 2153 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", 2154 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", 2155 | "dev": true, 2156 | "dependencies": { 2157 | "to-regex-range": "^5.0.1" 2158 | }, 2159 | "engines": { 2160 | "node": ">=8" 2161 | } 2162 | }, 2163 | "node_modules/get-port": { 2164 | "version": "4.2.0", 2165 | "resolved": "https://registry.npmjs.org/get-port/-/get-port-4.2.0.tgz", 2166 | "integrity": "sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==", 2167 | "dev": true, 2168 | "engines": { 2169 | "node": ">=6" 2170 | } 2171 | }, 2172 | "node_modules/globals": { 2173 | "version": "13.24.0", 2174 | "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", 2175 | "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", 2176 | "dev": true, 2177 | "dependencies": { 2178 | "type-fest": "^0.20.2" 2179 | }, 2180 | "engines": { 2181 | "node": ">=8" 2182 | }, 2183 | "funding": { 2184 | "url": "https://github.com/sponsors/sindresorhus" 2185 | } 2186 | }, 2187 | "node_modules/has-flag": { 2188 | "version": "4.0.0", 2189 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 2190 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 2191 | "dev": true, 2192 | "engines": { 2193 | "node": ">=8" 2194 | } 2195 | }, 2196 | "node_modules/htmlnano": { 2197 | "version": "2.1.1", 2198 | "resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-2.1.1.tgz", 2199 | "integrity": "sha512-kAERyg/LuNZYmdqgCdYvugyLWNFAm8MWXpQMz1pLpetmCbFwoMxvkSoaAMlFrOC4OKTWI4KlZGT/RsNxg4ghOw==", 2200 | "dev": true, 2201 | "dependencies": { 2202 | "cosmiconfig": "^9.0.0", 2203 | "posthtml": "^0.16.5", 2204 | "timsort": "^0.3.0" 2205 | }, 2206 | "peerDependencies": { 2207 | "cssnano": "^7.0.0", 2208 | "postcss": "^8.3.11", 2209 | "purgecss": "^6.0.0", 2210 | "relateurl": "^0.2.7", 2211 | "srcset": "5.0.1", 2212 | "svgo": "^3.0.2", 2213 | "terser": "^5.10.0", 2214 | "uncss": "^0.17.3" 2215 | }, 2216 | "peerDependenciesMeta": { 2217 | "cssnano": { 2218 | "optional": true 2219 | }, 2220 | "postcss": { 2221 | "optional": true 2222 | }, 2223 | "purgecss": { 2224 | "optional": true 2225 | }, 2226 | "relateurl": { 2227 | "optional": true 2228 | }, 2229 | "srcset": { 2230 | "optional": true 2231 | }, 2232 | "svgo": { 2233 | "optional": true 2234 | }, 2235 | "terser": { 2236 | "optional": true 2237 | }, 2238 | "uncss": { 2239 | "optional": true 2240 | } 2241 | } 2242 | }, 2243 | "node_modules/htmlparser2": { 2244 | "version": "7.2.0", 2245 | "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz", 2246 | "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==", 2247 | "dev": true, 2248 | "funding": [ 2249 | "https://github.com/fb55/htmlparser2?sponsor=1", 2250 | { 2251 | "type": "github", 2252 | "url": "https://github.com/sponsors/fb55" 2253 | } 2254 | ], 2255 | "dependencies": { 2256 | "domelementtype": "^2.0.1", 2257 | "domhandler": "^4.2.2", 2258 | "domutils": "^2.8.0", 2259 | "entities": "^3.0.1" 2260 | } 2261 | }, 2262 | "node_modules/httpie": { 2263 | "version": "2.0.0-next.13", 2264 | "resolved": "https://registry.npmjs.org/httpie/-/httpie-2.0.0-next.13.tgz", 2265 | "integrity": "sha512-KbKOnq8wt0hVEfteYCSnEsPgzaWxcVc4qZ4OaDU9mVOYLRo3XChjWs3MiuRgFu5y+4JDo7sDKdKzkAn1ljQYFA==", 2266 | "engines": { 2267 | "node": ">=10" 2268 | } 2269 | }, 2270 | "node_modules/ieee754": { 2271 | "version": "1.2.1", 2272 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 2273 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", 2274 | "dev": true, 2275 | "funding": [ 2276 | { 2277 | "type": "github", 2278 | "url": "https://github.com/sponsors/feross" 2279 | }, 2280 | { 2281 | "type": "patreon", 2282 | "url": "https://www.patreon.com/feross" 2283 | }, 2284 | { 2285 | "type": "consulting", 2286 | "url": "https://feross.org/support" 2287 | } 2288 | ] 2289 | }, 2290 | "node_modules/import-fresh": { 2291 | "version": "3.3.0", 2292 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", 2293 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", 2294 | "dev": true, 2295 | "dependencies": { 2296 | "parent-module": "^1.0.0", 2297 | "resolve-from": "^4.0.0" 2298 | }, 2299 | "engines": { 2300 | "node": ">=6" 2301 | }, 2302 | "funding": { 2303 | "url": "https://github.com/sponsors/sindresorhus" 2304 | } 2305 | }, 2306 | "node_modules/is-arrayish": { 2307 | "version": "0.2.1", 2308 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 2309 | "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", 2310 | "dev": true 2311 | }, 2312 | "node_modules/is-extglob": { 2313 | "version": "2.1.1", 2314 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 2315 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 2316 | "dev": true, 2317 | "engines": { 2318 | "node": ">=0.10.0" 2319 | } 2320 | }, 2321 | "node_modules/is-glob": { 2322 | "version": "4.0.3", 2323 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 2324 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 2325 | "dev": true, 2326 | "dependencies": { 2327 | "is-extglob": "^2.1.1" 2328 | }, 2329 | "engines": { 2330 | "node": ">=0.10.0" 2331 | } 2332 | }, 2333 | "node_modules/is-json": { 2334 | "version": "2.0.1", 2335 | "resolved": "https://registry.npmjs.org/is-json/-/is-json-2.0.1.tgz", 2336 | "integrity": "sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==", 2337 | "dev": true 2338 | }, 2339 | "node_modules/is-number": { 2340 | "version": "7.0.0", 2341 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 2342 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 2343 | "dev": true, 2344 | "engines": { 2345 | "node": ">=0.12.0" 2346 | } 2347 | }, 2348 | "node_modules/js-tokens": { 2349 | "version": "4.0.0", 2350 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 2351 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 2352 | "dev": true 2353 | }, 2354 | "node_modules/js-yaml": { 2355 | "version": "4.1.0", 2356 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 2357 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 2358 | "dev": true, 2359 | "dependencies": { 2360 | "argparse": "^2.0.1" 2361 | }, 2362 | "bin": { 2363 | "js-yaml": "bin/js-yaml.js" 2364 | } 2365 | }, 2366 | "node_modules/json-parse-even-better-errors": { 2367 | "version": "2.3.1", 2368 | "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", 2369 | "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", 2370 | "dev": true 2371 | }, 2372 | "node_modules/json5": { 2373 | "version": "2.2.3", 2374 | "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", 2375 | "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", 2376 | "dev": true, 2377 | "bin": { 2378 | "json5": "lib/cli.js" 2379 | }, 2380 | "engines": { 2381 | "node": ">=6" 2382 | } 2383 | }, 2384 | "node_modules/lightningcss": { 2385 | "version": "1.25.1", 2386 | "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.25.1.tgz", 2387 | "integrity": "sha512-V0RMVZzK1+rCHpymRv4URK2lNhIRyO8g7U7zOFwVAhJuat74HtkjIQpQRKNCwFEYkRGpafOpmXXLoaoBcyVtBg==", 2388 | "dev": true, 2389 | "dependencies": { 2390 | "detect-libc": "^1.0.3" 2391 | }, 2392 | "engines": { 2393 | "node": ">= 12.0.0" 2394 | }, 2395 | "funding": { 2396 | "type": "opencollective", 2397 | "url": "https://opencollective.com/parcel" 2398 | }, 2399 | "optionalDependencies": { 2400 | "lightningcss-darwin-arm64": "1.25.1", 2401 | "lightningcss-darwin-x64": "1.25.1", 2402 | "lightningcss-freebsd-x64": "1.25.1", 2403 | "lightningcss-linux-arm-gnueabihf": "1.25.1", 2404 | "lightningcss-linux-arm64-gnu": "1.25.1", 2405 | "lightningcss-linux-arm64-musl": "1.25.1", 2406 | "lightningcss-linux-x64-gnu": "1.25.1", 2407 | "lightningcss-linux-x64-musl": "1.25.1", 2408 | "lightningcss-win32-x64-msvc": "1.25.1" 2409 | } 2410 | }, 2411 | "node_modules/lightningcss-darwin-arm64": { 2412 | "version": "1.25.1", 2413 | "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.25.1.tgz", 2414 | "integrity": "sha512-G4Dcvv85bs5NLENcu/s1f7ehzE3D5ThnlWSDwE190tWXRQCQaqwcuHe+MGSVI/slm0XrxnaayXY+cNl3cSricw==", 2415 | "cpu": [ 2416 | "arm64" 2417 | ], 2418 | "dev": true, 2419 | "optional": true, 2420 | "os": [ 2421 | "darwin" 2422 | ], 2423 | "engines": { 2424 | "node": ">= 12.0.0" 2425 | }, 2426 | "funding": { 2427 | "type": "opencollective", 2428 | "url": "https://opencollective.com/parcel" 2429 | } 2430 | }, 2431 | "node_modules/lightningcss/node_modules/detect-libc": { 2432 | "version": "1.0.3", 2433 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", 2434 | "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", 2435 | "dev": true, 2436 | "bin": { 2437 | "detect-libc": "bin/detect-libc.js" 2438 | }, 2439 | "engines": { 2440 | "node": ">=0.10" 2441 | } 2442 | }, 2443 | "node_modules/lines-and-columns": { 2444 | "version": "1.2.4", 2445 | "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", 2446 | "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", 2447 | "dev": true 2448 | }, 2449 | "node_modules/lmdb": { 2450 | "version": "2.8.5", 2451 | "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.8.5.tgz", 2452 | "integrity": "sha512-9bMdFfc80S+vSldBmG3HOuLVHnxRdNTlpzR6QDnzqCQtCzGUEAGTzBKYMeIM+I/sU4oZfgbcbS7X7F65/z/oxQ==", 2453 | "dev": true, 2454 | "hasInstallScript": true, 2455 | "dependencies": { 2456 | "msgpackr": "^1.9.5", 2457 | "node-addon-api": "^6.1.0", 2458 | "node-gyp-build-optional-packages": "5.1.1", 2459 | "ordered-binary": "^1.4.1", 2460 | "weak-lru-cache": "^1.2.2" 2461 | }, 2462 | "bin": { 2463 | "download-lmdb-prebuilds": "bin/download-prebuilds.js" 2464 | }, 2465 | "optionalDependencies": { 2466 | "@lmdb/lmdb-darwin-arm64": "2.8.5", 2467 | "@lmdb/lmdb-darwin-x64": "2.8.5", 2468 | "@lmdb/lmdb-linux-arm": "2.8.5", 2469 | "@lmdb/lmdb-linux-arm64": "2.8.5", 2470 | "@lmdb/lmdb-linux-x64": "2.8.5", 2471 | "@lmdb/lmdb-win32-x64": "2.8.5" 2472 | } 2473 | }, 2474 | "node_modules/lmdb/node_modules/node-addon-api": { 2475 | "version": "6.1.0", 2476 | "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", 2477 | "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", 2478 | "dev": true 2479 | }, 2480 | "node_modules/lmdb/node_modules/node-gyp-build-optional-packages": { 2481 | "version": "5.1.1", 2482 | "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.1.1.tgz", 2483 | "integrity": "sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==", 2484 | "dev": true, 2485 | "dependencies": { 2486 | "detect-libc": "^2.0.1" 2487 | }, 2488 | "bin": { 2489 | "node-gyp-build-optional-packages": "bin.js", 2490 | "node-gyp-build-optional-packages-optional": "optional.js", 2491 | "node-gyp-build-optional-packages-test": "build-test.js" 2492 | } 2493 | }, 2494 | "node_modules/mdn-data": { 2495 | "version": "2.0.30", 2496 | "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", 2497 | "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", 2498 | "dev": true, 2499 | "optional": true, 2500 | "peer": true 2501 | }, 2502 | "node_modules/micromatch": { 2503 | "version": "4.0.7", 2504 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", 2505 | "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", 2506 | "dev": true, 2507 | "dependencies": { 2508 | "braces": "^3.0.3", 2509 | "picomatch": "^2.3.1" 2510 | }, 2511 | "engines": { 2512 | "node": ">=8.6" 2513 | } 2514 | }, 2515 | "node_modules/msgpackr": { 2516 | "version": "1.10.2", 2517 | "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.10.2.tgz", 2518 | "integrity": "sha512-L60rsPynBvNE+8BWipKKZ9jHcSGbtyJYIwjRq0VrIvQ08cRjntGXJYW/tmciZ2IHWIY8WEW32Qa2xbh5+SKBZA==", 2519 | "dev": true, 2520 | "optionalDependencies": { 2521 | "msgpackr-extract": "^3.0.2" 2522 | } 2523 | }, 2524 | "node_modules/msgpackr-extract": { 2525 | "version": "3.0.3", 2526 | "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz", 2527 | "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", 2528 | "hasInstallScript": true, 2529 | "optional": true, 2530 | "dependencies": { 2531 | "node-gyp-build-optional-packages": "5.2.2" 2532 | }, 2533 | "bin": { 2534 | "download-msgpackr-prebuilds": "bin/download-prebuilds.js" 2535 | }, 2536 | "optionalDependencies": { 2537 | "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", 2538 | "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", 2539 | "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", 2540 | "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", 2541 | "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", 2542 | "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" 2543 | } 2544 | }, 2545 | "node_modules/node-addon-api": { 2546 | "version": "7.1.0", 2547 | "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.0.tgz", 2548 | "integrity": "sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==", 2549 | "dev": true, 2550 | "engines": { 2551 | "node": "^16 || ^18 || >= 20" 2552 | } 2553 | }, 2554 | "node_modules/node-gyp-build-optional-packages": { 2555 | "version": "5.2.2", 2556 | "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", 2557 | "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", 2558 | "optional": true, 2559 | "dependencies": { 2560 | "detect-libc": "^2.0.1" 2561 | }, 2562 | "bin": { 2563 | "node-gyp-build-optional-packages": "bin.js", 2564 | "node-gyp-build-optional-packages-optional": "optional.js", 2565 | "node-gyp-build-optional-packages-test": "build-test.js" 2566 | } 2567 | }, 2568 | "node_modules/node-releases": { 2569 | "version": "2.0.14", 2570 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", 2571 | "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", 2572 | "dev": true 2573 | }, 2574 | "node_modules/nth-check": { 2575 | "version": "2.1.1", 2576 | "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", 2577 | "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", 2578 | "dev": true, 2579 | "dependencies": { 2580 | "boolbase": "^1.0.0" 2581 | }, 2582 | "funding": { 2583 | "url": "https://github.com/fb55/nth-check?sponsor=1" 2584 | } 2585 | }, 2586 | "node_modules/nullthrows": { 2587 | "version": "1.1.1", 2588 | "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", 2589 | "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", 2590 | "dev": true 2591 | }, 2592 | "node_modules/ordered-binary": { 2593 | "version": "1.5.1", 2594 | "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.1.tgz", 2595 | "integrity": "sha512-5VyHfHY3cd0iza71JepYG50My+YUbrFtGoUz2ooEydPyPM7Aai/JW098juLr+RG6+rDJuzNNTsEQu2DZa1A41A==", 2596 | "dev": true 2597 | }, 2598 | "node_modules/parcel": { 2599 | "version": "2.12.0", 2600 | "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.12.0.tgz", 2601 | "integrity": "sha512-W+gxAq7aQ9dJIg/XLKGcRT0cvnStFAQHPaI0pvD0U2l6IVLueUAm3nwN7lkY62zZNmlvNx6jNtE4wlbS+CyqSg==", 2602 | "dev": true, 2603 | "dependencies": { 2604 | "@parcel/config-default": "2.12.0", 2605 | "@parcel/core": "2.12.0", 2606 | "@parcel/diagnostic": "2.12.0", 2607 | "@parcel/events": "2.12.0", 2608 | "@parcel/fs": "2.12.0", 2609 | "@parcel/logger": "2.12.0", 2610 | "@parcel/package-manager": "2.12.0", 2611 | "@parcel/reporter-cli": "2.12.0", 2612 | "@parcel/reporter-dev-server": "2.12.0", 2613 | "@parcel/reporter-tracer": "2.12.0", 2614 | "@parcel/utils": "2.12.0", 2615 | "chalk": "^4.1.0", 2616 | "commander": "^7.0.0", 2617 | "get-port": "^4.2.0" 2618 | }, 2619 | "bin": { 2620 | "parcel": "lib/bin.js" 2621 | }, 2622 | "engines": { 2623 | "node": ">= 12.0.0" 2624 | }, 2625 | "funding": { 2626 | "type": "opencollective", 2627 | "url": "https://opencollective.com/parcel" 2628 | } 2629 | }, 2630 | "node_modules/parent-module": { 2631 | "version": "1.0.1", 2632 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 2633 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 2634 | "dev": true, 2635 | "dependencies": { 2636 | "callsites": "^3.0.0" 2637 | }, 2638 | "engines": { 2639 | "node": ">=6" 2640 | } 2641 | }, 2642 | "node_modules/parse-json": { 2643 | "version": "5.2.0", 2644 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", 2645 | "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", 2646 | "dev": true, 2647 | "dependencies": { 2648 | "@babel/code-frame": "^7.0.0", 2649 | "error-ex": "^1.3.1", 2650 | "json-parse-even-better-errors": "^2.3.0", 2651 | "lines-and-columns": "^1.1.6" 2652 | }, 2653 | "engines": { 2654 | "node": ">=8" 2655 | }, 2656 | "funding": { 2657 | "url": "https://github.com/sponsors/sindresorhus" 2658 | } 2659 | }, 2660 | "node_modules/phaser": { 2661 | "version": "3.80.1", 2662 | "resolved": "https://registry.npmjs.org/phaser/-/phaser-3.80.1.tgz", 2663 | "integrity": "sha512-VQGAWoDOkEpAWYkI+PUADv5Ql+SM0xpLuAMBJHz9tBcOLqjJ2wd8bUhxJgOqclQlLTg97NmMd9MhS75w16x1Cw==", 2664 | "dependencies": { 2665 | "eventemitter3": "^5.0.1" 2666 | } 2667 | }, 2668 | "node_modules/picocolors": { 2669 | "version": "1.0.1", 2670 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", 2671 | "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", 2672 | "dev": true 2673 | }, 2674 | "node_modules/picomatch": { 2675 | "version": "2.3.1", 2676 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 2677 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 2678 | "dev": true, 2679 | "engines": { 2680 | "node": ">=8.6" 2681 | }, 2682 | "funding": { 2683 | "url": "https://github.com/sponsors/jonschlinkert" 2684 | } 2685 | }, 2686 | "node_modules/postcss-value-parser": { 2687 | "version": "4.2.0", 2688 | "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", 2689 | "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", 2690 | "dev": true 2691 | }, 2692 | "node_modules/posthtml": { 2693 | "version": "0.16.6", 2694 | "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.6.tgz", 2695 | "integrity": "sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==", 2696 | "dev": true, 2697 | "dependencies": { 2698 | "posthtml-parser": "^0.11.0", 2699 | "posthtml-render": "^3.0.0" 2700 | }, 2701 | "engines": { 2702 | "node": ">=12.0.0" 2703 | } 2704 | }, 2705 | "node_modules/posthtml-parser": { 2706 | "version": "0.10.2", 2707 | "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.10.2.tgz", 2708 | "integrity": "sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg==", 2709 | "dev": true, 2710 | "dependencies": { 2711 | "htmlparser2": "^7.1.1" 2712 | }, 2713 | "engines": { 2714 | "node": ">=12" 2715 | } 2716 | }, 2717 | "node_modules/posthtml-render": { 2718 | "version": "3.0.0", 2719 | "resolved": "https://registry.npmjs.org/posthtml-render/-/posthtml-render-3.0.0.tgz", 2720 | "integrity": "sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==", 2721 | "dev": true, 2722 | "dependencies": { 2723 | "is-json": "^2.0.1" 2724 | }, 2725 | "engines": { 2726 | "node": ">=12" 2727 | } 2728 | }, 2729 | "node_modules/posthtml/node_modules/posthtml-parser": { 2730 | "version": "0.11.0", 2731 | "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.11.0.tgz", 2732 | "integrity": "sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==", 2733 | "dev": true, 2734 | "dependencies": { 2735 | "htmlparser2": "^7.1.1" 2736 | }, 2737 | "engines": { 2738 | "node": ">=12" 2739 | } 2740 | }, 2741 | "node_modules/process": { 2742 | "version": "0.11.10", 2743 | "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", 2744 | "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", 2745 | "dev": true, 2746 | "engines": { 2747 | "node": ">= 0.6.0" 2748 | } 2749 | }, 2750 | "node_modules/react-error-overlay": { 2751 | "version": "6.0.9", 2752 | "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz", 2753 | "integrity": "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==", 2754 | "dev": true 2755 | }, 2756 | "node_modules/react-refresh": { 2757 | "version": "0.9.0", 2758 | "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.9.0.tgz", 2759 | "integrity": "sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==", 2760 | "dev": true, 2761 | "engines": { 2762 | "node": ">=0.10.0" 2763 | } 2764 | }, 2765 | "node_modules/regenerator-runtime": { 2766 | "version": "0.13.11", 2767 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", 2768 | "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", 2769 | "dev": true 2770 | }, 2771 | "node_modules/resolve-from": { 2772 | "version": "4.0.0", 2773 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 2774 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 2775 | "dev": true, 2776 | "engines": { 2777 | "node": ">=4" 2778 | } 2779 | }, 2780 | "node_modules/safe-buffer": { 2781 | "version": "5.2.1", 2782 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 2783 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 2784 | "dev": true, 2785 | "funding": [ 2786 | { 2787 | "type": "github", 2788 | "url": "https://github.com/sponsors/feross" 2789 | }, 2790 | { 2791 | "type": "patreon", 2792 | "url": "https://www.patreon.com/feross" 2793 | }, 2794 | { 2795 | "type": "consulting", 2796 | "url": "https://feross.org/support" 2797 | } 2798 | ] 2799 | }, 2800 | "node_modules/semver": { 2801 | "version": "7.6.2", 2802 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", 2803 | "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", 2804 | "dev": true, 2805 | "bin": { 2806 | "semver": "bin/semver.js" 2807 | }, 2808 | "engines": { 2809 | "node": ">=10" 2810 | } 2811 | }, 2812 | "node_modules/source-map": { 2813 | "version": "0.6.1", 2814 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 2815 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 2816 | "dev": true, 2817 | "engines": { 2818 | "node": ">=0.10.0" 2819 | } 2820 | }, 2821 | "node_modules/source-map-js": { 2822 | "version": "1.2.0", 2823 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", 2824 | "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", 2825 | "dev": true, 2826 | "optional": true, 2827 | "peer": true, 2828 | "engines": { 2829 | "node": ">=0.10.0" 2830 | } 2831 | }, 2832 | "node_modules/srcset": { 2833 | "version": "5.0.1", 2834 | "resolved": "https://registry.npmjs.org/srcset/-/srcset-5.0.1.tgz", 2835 | "integrity": "sha512-/P1UYbGfJVlxZag7aABNRrulEXAwCSDo7fklafOQrantuPTDmYgijJMks2zusPCVzgW9+4P69mq7w6pYuZpgxw==", 2836 | "dev": true, 2837 | "optional": true, 2838 | "peer": true, 2839 | "engines": { 2840 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 2841 | }, 2842 | "funding": { 2843 | "url": "https://github.com/sponsors/sindresorhus" 2844 | } 2845 | }, 2846 | "node_modules/stable": { 2847 | "version": "0.1.8", 2848 | "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", 2849 | "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", 2850 | "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility", 2851 | "dev": true 2852 | }, 2853 | "node_modules/supports-color": { 2854 | "version": "7.2.0", 2855 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 2856 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 2857 | "dev": true, 2858 | "dependencies": { 2859 | "has-flag": "^4.0.0" 2860 | }, 2861 | "engines": { 2862 | "node": ">=8" 2863 | } 2864 | }, 2865 | "node_modules/svgo": { 2866 | "version": "3.3.2", 2867 | "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", 2868 | "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", 2869 | "dev": true, 2870 | "optional": true, 2871 | "peer": true, 2872 | "dependencies": { 2873 | "@trysound/sax": "0.2.0", 2874 | "commander": "^7.2.0", 2875 | "css-select": "^5.1.0", 2876 | "css-tree": "^2.3.1", 2877 | "css-what": "^6.1.0", 2878 | "csso": "^5.0.5", 2879 | "picocolors": "^1.0.0" 2880 | }, 2881 | "bin": { 2882 | "svgo": "bin/svgo" 2883 | }, 2884 | "engines": { 2885 | "node": ">=14.0.0" 2886 | }, 2887 | "funding": { 2888 | "type": "opencollective", 2889 | "url": "https://opencollective.com/svgo" 2890 | } 2891 | }, 2892 | "node_modules/term-size": { 2893 | "version": "2.2.1", 2894 | "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", 2895 | "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", 2896 | "dev": true, 2897 | "engines": { 2898 | "node": ">=8" 2899 | }, 2900 | "funding": { 2901 | "url": "https://github.com/sponsors/sindresorhus" 2902 | } 2903 | }, 2904 | "node_modules/timsort": { 2905 | "version": "0.3.0", 2906 | "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", 2907 | "integrity": "sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==", 2908 | "dev": true 2909 | }, 2910 | "node_modules/to-regex-range": { 2911 | "version": "5.0.1", 2912 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 2913 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 2914 | "dev": true, 2915 | "dependencies": { 2916 | "is-number": "^7.0.0" 2917 | }, 2918 | "engines": { 2919 | "node": ">=8.0" 2920 | } 2921 | }, 2922 | "node_modules/tslib": { 2923 | "version": "2.6.3", 2924 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", 2925 | "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" 2926 | }, 2927 | "node_modules/type-fest": { 2928 | "version": "0.20.2", 2929 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", 2930 | "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", 2931 | "dev": true, 2932 | "engines": { 2933 | "node": ">=10" 2934 | }, 2935 | "funding": { 2936 | "url": "https://github.com/sponsors/sindresorhus" 2937 | } 2938 | }, 2939 | "node_modules/typescript": { 2940 | "version": "4.9.5", 2941 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", 2942 | "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", 2943 | "dev": true, 2944 | "bin": { 2945 | "tsc": "bin/tsc", 2946 | "tsserver": "bin/tsserver" 2947 | }, 2948 | "engines": { 2949 | "node": ">=4.2.0" 2950 | } 2951 | }, 2952 | "node_modules/update-browserslist-db": { 2953 | "version": "1.0.16", 2954 | "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", 2955 | "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", 2956 | "dev": true, 2957 | "funding": [ 2958 | { 2959 | "type": "opencollective", 2960 | "url": "https://opencollective.com/browserslist" 2961 | }, 2962 | { 2963 | "type": "tidelift", 2964 | "url": "https://tidelift.com/funding/github/npm/browserslist" 2965 | }, 2966 | { 2967 | "type": "github", 2968 | "url": "https://github.com/sponsors/ai" 2969 | } 2970 | ], 2971 | "dependencies": { 2972 | "escalade": "^3.1.2", 2973 | "picocolors": "^1.0.1" 2974 | }, 2975 | "bin": { 2976 | "update-browserslist-db": "cli.js" 2977 | }, 2978 | "peerDependencies": { 2979 | "browserslist": ">= 4.21.0" 2980 | } 2981 | }, 2982 | "node_modules/utility-types": { 2983 | "version": "3.11.0", 2984 | "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", 2985 | "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", 2986 | "dev": true, 2987 | "engines": { 2988 | "node": ">= 4" 2989 | } 2990 | }, 2991 | "node_modules/weak-lru-cache": { 2992 | "version": "1.2.2", 2993 | "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", 2994 | "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", 2995 | "dev": true 2996 | }, 2997 | "node_modules/ws": { 2998 | "version": "8.17.1", 2999 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", 3000 | "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", 3001 | "engines": { 3002 | "node": ">=10.0.0" 3003 | }, 3004 | "peerDependencies": { 3005 | "bufferutil": "^4.0.1", 3006 | "utf-8-validate": ">=5.0.2" 3007 | }, 3008 | "peerDependenciesMeta": { 3009 | "bufferutil": { 3010 | "optional": true 3011 | }, 3012 | "utf-8-validate": { 3013 | "optional": true 3014 | } 3015 | } 3016 | } 3017 | } 3018 | } 3019 | -------------------------------------------------------------------------------- /client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "version": "1.0.0", 4 | "description": "Colyseus + Phaser: Client-side", 5 | "scripts": { 6 | "start": "parcel serve index.html", 7 | "build": "parcel build index.html", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "colyseus", 12 | "phaser" 13 | ], 14 | "author": "Endel Dreyer", 15 | "license": "MIT", 16 | "devDependencies": { 17 | "buffer": "^6.0.3", 18 | "parcel": "^2.4.0", 19 | "process": "^0.11.10", 20 | "typescript": "^4.6.3" 21 | }, 22 | "dependencies": { 23 | "colyseus.js": "^0.16.0", 24 | "phaser": "^3.55.2" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /client/src/backend.ts: -------------------------------------------------------------------------------- 1 | export const BACKEND_URL = (window.location.href.indexOf("localhost") === -1) 2 | ? `${window.location.protocol.replace("http", "ws")}//${window.location.hostname}${(window.location.port && `:${window.location.port}`)}` 3 | : "ws://localhost:2567" 4 | 5 | export const BACKEND_HTTP_URL = BACKEND_URL.replace("ws", "http"); -------------------------------------------------------------------------------- /client/src/index.ts: -------------------------------------------------------------------------------- 1 | import Phaser from "phaser"; 2 | 3 | import { SceneSelector } from "./scenes/SceneSelector"; 4 | import { Part1Scene } from "./scenes/Part1Scene"; 5 | import { Part2Scene } from "./scenes/Part2Scene"; 6 | import { Part3Scene } from "./scenes/Part3Scene"; 7 | import { Part4Scene } from "./scenes/Part4Scene"; 8 | 9 | import { BACKEND_HTTP_URL } from "./backend"; 10 | 11 | const config: Phaser.Types.Core.GameConfig = { 12 | type: Phaser.AUTO, 13 | fps: { 14 | target: 60, 15 | forceSetTimeOut: true, 16 | smoothStep: false, 17 | }, 18 | width: 800, 19 | height: 600, 20 | // height: 200, 21 | backgroundColor: '#b6d53c', 22 | parent: 'phaser-example', 23 | physics: { 24 | default: "arcade" 25 | }, 26 | pixelArt: true, 27 | scene: [SceneSelector, Part1Scene, Part2Scene, Part3Scene, Part4Scene], 28 | }; 29 | 30 | const game = new Phaser.Game(config); 31 | 32 | /** 33 | * Create FPS selector 34 | */ 35 | 36 | // current fps label 37 | const fpsInput = document.querySelector("input#fps"); 38 | const fpsValueLabel = document.querySelector("#fps-value"); 39 | fpsValueLabel.innerText = fpsInput.value; 40 | 41 | fpsInput.oninput = function(event: InputEvent) { 42 | const value = (event.target as HTMLInputElement).value; 43 | fpsValueLabel.innerText = value; 44 | 45 | // destroy previous loop 46 | game.loop.destroy(); 47 | 48 | // create new loop 49 | game.loop = new Phaser.Core.TimeStep(game, { 50 | target: parseInt(value), 51 | forceSetTimeOut: true, 52 | smoothStep: false, 53 | }); 54 | 55 | // start new loop 56 | game.loop.start(game.step.bind(game)); 57 | }; 58 | 59 | /** 60 | * Create latency simulation selector 61 | */ 62 | let fetchLatencySimulationInterval: number; 63 | 64 | // latency simulation label 65 | const latencyInput = document.querySelector("input#latency"); 66 | 67 | if (latencyInput) { 68 | // current latency label 69 | const selectedLatencyLabel = document.querySelector("#latency-value") 70 | selectedLatencyLabel.innerText = `${latencyInput.value} ms`; 71 | 72 | latencyInput.onpointerdown = (event: PointerEvent) => 73 | clearInterval(fetchLatencySimulationInterval); 74 | 75 | latencyInput.oninput = (event: InputEvent) => 76 | selectedLatencyLabel.innerText = `${latencyInput.value} ms`; 77 | 78 | latencyInput.onchange = function (event: InputEvent) { 79 | // request server to update its latency simulation 80 | fetch(`${BACKEND_HTTP_URL}/simulate-latency/${latencyInput.value}`); 81 | 82 | setIntervalFetchLatencySimulation(); 83 | }; 84 | 85 | function setIntervalFetchLatencySimulation() { 86 | // 87 | // Keep fetching latency simulation number from server to keep all browser tabs in sync 88 | // 89 | fetchLatencySimulationInterval = setInterval(() => { 90 | fetch(`${BACKEND_HTTP_URL}/latency`) 91 | .then((response) => response.json()) 92 | .then((value) => { 93 | latencyInput.value = value; 94 | latencyInput.oninput(undefined); 95 | }); 96 | }, 1000); 97 | } 98 | setIntervalFetchLatencySimulation(); 99 | } -------------------------------------------------------------------------------- /client/src/scenes/Part1Scene.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * --------------------------- 3 | * Phaser + Colyseus - Part 1. 4 | * --------------------------- 5 | * - Connecting with the room 6 | * - Sending inputs at the user's framerate 7 | * - Update each player's positions WITHOUT interpolation 8 | */ 9 | 10 | import Phaser from "phaser"; 11 | import { Room, Client, getStateCallbacks } from "colyseus.js"; 12 | import { BACKEND_URL } from "../backend"; 13 | 14 | // Import the state type from server-side code 15 | import type { MyRoomState } from "../../../server/src/rooms/Part1Room"; 16 | 17 | export class Part1Scene extends Phaser.Scene { 18 | room: Room; 19 | playerEntities: { [sessionId: string]: Phaser.Types.Physics.Arcade.ImageWithDynamicBody } = {}; 20 | 21 | debugFPS: Phaser.GameObjects.Text; 22 | 23 | cursorKeys: Phaser.Types.Input.Keyboard.CursorKeys; 24 | 25 | inputPayload = { 26 | left: false, 27 | right: false, 28 | up: false, 29 | down: false, 30 | }; 31 | 32 | constructor() { 33 | super({ key: "part1" }); 34 | } 35 | 36 | async create() { 37 | this.cursorKeys = this.input.keyboard.createCursorKeys(); 38 | this.debugFPS = this.add.text(4, 4, "", { color: "#ff0000", }); 39 | 40 | // connect with the room 41 | await this.connect(); 42 | 43 | const $ = getStateCallbacks(this.room); 44 | 45 | $(this.room.state).players.onAdd((player, sessionId) => { 46 | const entity = this.physics.add.image(player.x, player.y, 'ship_0001'); 47 | this.playerEntities[sessionId] = entity; 48 | 49 | // listening for server updates 50 | $(player).onChange(() => { 51 | // 52 | // update local position immediately 53 | // (WE WILL CHANGE THIS ON PART 2) 54 | // 55 | entity.x = player.x; 56 | entity.y = player.y; 57 | }); 58 | }); 59 | 60 | // remove local reference when entity is removed from the server 61 | $(this.room.state).players.onRemove((player, sessionId) => { 62 | const entity = this.playerEntities[sessionId]; 63 | if (entity) { 64 | entity.destroy(); 65 | delete this.playerEntities[sessionId] 66 | } 67 | }); 68 | 69 | // this.cameras.main.startFollow(this.ship, true, 0.2, 0.2); 70 | // this.cameras.main.setZoom(1); 71 | this.cameras.main.setBounds(0, 0, 800, 600); 72 | } 73 | 74 | async connect() { 75 | // add connection status text 76 | const connectionStatusText = this.add 77 | .text(0, 0, "Trying to connect with the server...") 78 | .setStyle({ color: "#ff0000" }) 79 | .setPadding(4) 80 | 81 | const client = new Client(BACKEND_URL); 82 | 83 | try { 84 | this.room = await client.joinOrCreate("part1_room", {}); 85 | 86 | // connection successful! 87 | connectionStatusText.destroy(); 88 | 89 | } catch (e) { 90 | // couldn't connect 91 | connectionStatusText.text = "Could not connect with the server."; 92 | } 93 | 94 | } 95 | 96 | update(time: number, delta: number): void { 97 | // skip loop if not connected with room yet. 98 | if (!this.room) { 99 | return; 100 | } 101 | 102 | // send input to the server 103 | this.inputPayload.left = this.cursorKeys.left.isDown; 104 | this.inputPayload.right = this.cursorKeys.right.isDown; 105 | this.inputPayload.up = this.cursorKeys.up.isDown; 106 | this.inputPayload.down = this.cursorKeys.down.isDown; 107 | this.room.send(0, this.inputPayload); 108 | 109 | this.debugFPS.text = `Frame rate: ${this.game.loop.actualFps}`; 110 | } 111 | 112 | } -------------------------------------------------------------------------------- /client/src/scenes/Part2Scene.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * --------------------------- 3 | * Phaser + Colyseus - Part 2. 4 | * --------------------------- 5 | * - Connecting with the room 6 | * - Sending inputs at the user's framerate 7 | * - Update each player's positions WITH interpolation 8 | */ 9 | 10 | import Phaser from "phaser"; 11 | import { Room, Client, getStateCallbacks } from "colyseus.js"; 12 | import { BACKEND_URL } from "../backend"; 13 | 14 | // Import the state type from server-side code 15 | import type { MyRoomState } from "../../../server/src/rooms/Part2Room"; 16 | 17 | export class Part2Scene extends Phaser.Scene { 18 | room: Room; 19 | 20 | currentPlayer: Phaser.Types.Physics.Arcade.ImageWithDynamicBody; 21 | playerEntities: { [sessionId: string]: Phaser.Types.Physics.Arcade.ImageWithDynamicBody } = {}; 22 | 23 | debugFPS: Phaser.GameObjects.Text; 24 | 25 | cursorKeys: Phaser.Types.Input.Keyboard.CursorKeys; 26 | 27 | inputPayload = { 28 | left: false, 29 | right: false, 30 | up: false, 31 | down: false, 32 | }; 33 | 34 | constructor() { 35 | super({ key: "part2" }); 36 | } 37 | 38 | async create() { 39 | this.cursorKeys = this.input.keyboard.createCursorKeys(); 40 | this.debugFPS = this.add.text(4, 4, "", { color: "#ff0000", }); 41 | 42 | // connect with the room 43 | await this.connect(); 44 | 45 | const $ = getStateCallbacks(this.room); 46 | 47 | $(this.room.state).players.onAdd((player, sessionId) => { 48 | const entity = this.physics.add.image(player.x, player.y, 'ship_0001'); 49 | this.playerEntities[sessionId] = entity; 50 | 51 | // listening for server updates 52 | $(player).onChange(() => { 53 | // 54 | // do not update local position immediately 55 | // we're going to LERP them during the render loop. 56 | // 57 | entity.setData('serverX', player.x); 58 | entity.setData('serverY', player.y); 59 | }); 60 | }); 61 | 62 | // remove local reference when entity is removed from the server 63 | $(this.room.state).players.onRemove((player, sessionId) => { 64 | const entity = this.playerEntities[sessionId]; 65 | if (entity) { 66 | entity.destroy(); 67 | delete this.playerEntities[sessionId] 68 | } 69 | }); 70 | 71 | // this.cameras.main.startFollow(this.ship, true, 0.2, 0.2); 72 | // this.cameras.main.setZoom(1); 73 | this.cameras.main.setBounds(0, 0, 800, 600); 74 | } 75 | 76 | async connect() { 77 | // add connection status text 78 | const connectionStatusText = this.add 79 | .text(0, 0, "Trying to connect with the server...") 80 | .setStyle({ color: "#ff0000" }) 81 | .setPadding(4) 82 | 83 | const client = new Client(BACKEND_URL); 84 | 85 | try { 86 | this.room = await client.joinOrCreate("part2_room", {}); 87 | 88 | // connection successful! 89 | connectionStatusText.destroy(); 90 | 91 | } catch (e) { 92 | // couldn't connect 93 | connectionStatusText.text = "Could not connect with the server."; 94 | } 95 | 96 | } 97 | 98 | update(time: number, delta: number): void { 99 | // skip loop if not connected yet. 100 | if (!this.room) { return; } 101 | 102 | // send input to the server 103 | this.inputPayload.left = this.cursorKeys.left.isDown; 104 | this.inputPayload.right = this.cursorKeys.right.isDown; 105 | this.inputPayload.up = this.cursorKeys.up.isDown; 106 | this.inputPayload.down = this.cursorKeys.down.isDown; 107 | this.room.send(0, this.inputPayload); 108 | 109 | for (let sessionId in this.playerEntities) { 110 | // interpolate all player entities 111 | const entity = this.playerEntities[sessionId]; 112 | const { serverX, serverY } = entity.data.values; 113 | 114 | entity.x = Phaser.Math.Linear(entity.x, serverX, 0.2); 115 | entity.y = Phaser.Math.Linear(entity.y, serverY, 0.2); 116 | 117 | // entity.x = Phaser.Math.Linear(entity.x, serverX, 0.2); 118 | // entity.y = Phaser.Math.Linear(entity.y, serverY, 0.2); 119 | 120 | } 121 | 122 | this.debugFPS.text = `Frame rate: ${this.game.loop.actualFps}`; 123 | } 124 | 125 | fixedTick(time, delta) { 126 | } 127 | 128 | } -------------------------------------------------------------------------------- /client/src/scenes/Part3Scene.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * --------------------------- 3 | * Phaser + Colyseus - Part 3. 4 | * --------------------------- 5 | * - Connecting with the room 6 | * - Sending inputs at the user's framerate 7 | * - Update other player's positions WITH interpolation (for other players) 8 | * - Client-predicted input for local (current) player 9 | */ 10 | 11 | import Phaser from "phaser"; 12 | import { Room, Client, getStateCallbacks } from "colyseus.js"; 13 | import { BACKEND_URL } from "../backend"; 14 | 15 | // Import the state type from server-side code 16 | import type { MyRoomState } from "../../../server/src/rooms/Part3Room"; 17 | 18 | export class Part3Scene extends Phaser.Scene { 19 | room: Room; 20 | 21 | currentPlayer: Phaser.Types.Physics.Arcade.ImageWithDynamicBody; 22 | playerEntities: { [sessionId: string]: Phaser.Types.Physics.Arcade.ImageWithDynamicBody } = {}; 23 | 24 | debugFPS: Phaser.GameObjects.Text; 25 | 26 | localRef: Phaser.GameObjects.Rectangle; 27 | remoteRef: Phaser.GameObjects.Rectangle; 28 | 29 | cursorKeys: Phaser.Types.Input.Keyboard.CursorKeys; 30 | 31 | inputPayload = { 32 | left: false, 33 | right: false, 34 | up: false, 35 | down: false, 36 | }; 37 | 38 | constructor() { 39 | super({ key: "part3" }); 40 | } 41 | 42 | async create() { 43 | this.cursorKeys = this.input.keyboard.createCursorKeys(); 44 | this.debugFPS = this.add.text(4, 4, "", { color: "#ff0000", }); 45 | 46 | // connect with the room 47 | await this.connect(); 48 | 49 | const $ = getStateCallbacks(this.room); 50 | 51 | $(this.room.state).players.onAdd((player, sessionId) => { 52 | const entity = this.physics.add.image(player.x, player.y, 'ship_0001'); 53 | this.playerEntities[sessionId] = entity; 54 | 55 | // is current player 56 | if (sessionId === this.room.sessionId) { 57 | this.currentPlayer = entity; 58 | 59 | this.localRef = this.add.rectangle(0, 0, entity.width, entity.height); 60 | this.localRef.setStrokeStyle(1, 0x00ff00); 61 | 62 | this.remoteRef = this.add.rectangle(0, 0, entity.width, entity.height); 63 | this.remoteRef.setStrokeStyle(1, 0xff0000); 64 | 65 | $(player).onChange(() => { 66 | this.remoteRef.x = player.x; 67 | this.remoteRef.y = player.y; 68 | }); 69 | 70 | } else { 71 | // listening for server updates 72 | $(player).onChange(() => { 73 | // 74 | // we're going to LERP the positions during the render loop. 75 | // 76 | entity.setData('serverX', player.x); 77 | entity.setData('serverY', player.y); 78 | }); 79 | 80 | } 81 | 82 | }); 83 | 84 | // remove local reference when entity is removed from the server 85 | $(this.room.state).players.onRemove((player, sessionId) => { 86 | const entity = this.playerEntities[sessionId]; 87 | if (entity) { 88 | entity.destroy(); 89 | delete this.playerEntities[sessionId] 90 | } 91 | }); 92 | 93 | // this.cameras.main.startFollow(this.ship, true, 0.2, 0.2); 94 | // this.cameras.main.setZoom(1); 95 | this.cameras.main.setBounds(0, 0, 800, 600); 96 | } 97 | 98 | async connect() { 99 | // add connection status text 100 | const connectionStatusText = this.add 101 | .text(0, 0, "Trying to connect with the server...") 102 | .setStyle({ color: "#ff0000" }) 103 | .setPadding(4) 104 | 105 | const client = new Client(BACKEND_URL); 106 | 107 | try { 108 | this.room = await client.joinOrCreate("part3_room", {}); 109 | 110 | // connection successful! 111 | connectionStatusText.destroy(); 112 | 113 | } catch (e) { 114 | // couldn't connect 115 | connectionStatusText.text = "Could not connect with the server."; 116 | } 117 | 118 | } 119 | 120 | update(time: number, delta: number): void { 121 | // skip loop if not connected yet. 122 | if (!this.currentPlayer) { return; } 123 | 124 | this.debugFPS.text = `Frame rate: ${this.game.loop.actualFps}`; 125 | 126 | const velocity = 2; 127 | this.inputPayload.left = this.cursorKeys.left.isDown; 128 | this.inputPayload.right = this.cursorKeys.right.isDown; 129 | this.inputPayload.up = this.cursorKeys.up.isDown; 130 | this.inputPayload.down = this.cursorKeys.down.isDown; 131 | this.room.send(0, this.inputPayload); 132 | 133 | if (this.inputPayload.left) { 134 | this.currentPlayer.x -= velocity; 135 | 136 | } else if (this.inputPayload.right) { 137 | this.currentPlayer.x += velocity; 138 | } 139 | 140 | if (this.inputPayload.up) { 141 | this.currentPlayer.y -= velocity; 142 | 143 | } else if (this.inputPayload.down) { 144 | this.currentPlayer.y += velocity; 145 | } 146 | 147 | this.localRef.x = this.currentPlayer.x; 148 | this.localRef.y = this.currentPlayer.y; 149 | 150 | for (let sessionId in this.playerEntities) { 151 | // interpolate all player entities 152 | // (except the current player) 153 | if (sessionId === this.room.sessionId) { 154 | continue; 155 | } 156 | 157 | const entity = this.playerEntities[sessionId]; 158 | const { serverX, serverY } = entity.data.values; 159 | 160 | entity.x = Phaser.Math.Linear(entity.x, serverX, 0.2); 161 | entity.y = Phaser.Math.Linear(entity.y, serverY, 0.2); 162 | } 163 | 164 | } 165 | 166 | } -------------------------------------------------------------------------------- /client/src/scenes/Part4Scene.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * --------------------------- 3 | * Phaser + Colyseus - Part 4. 4 | * --------------------------- 5 | * - Connecting with the room 6 | * - Sending inputs at the user's framerate 7 | * - Update other player's positions WITH interpolation (for other players) 8 | * - Client-predicted input for local (current) player 9 | * - Fixed tickrate on both client and server 10 | */ 11 | 12 | import Phaser from "phaser"; 13 | import { Room, Client, getStateCallbacks } from "colyseus.js"; 14 | import { BACKEND_URL } from "../backend"; 15 | 16 | // Import the state type from server-side code 17 | import type { MyRoomState } from "../../../server/src/rooms/Part4Room"; 18 | 19 | export class Part4Scene extends Phaser.Scene { 20 | room: Room; 21 | 22 | currentPlayer: Phaser.Types.Physics.Arcade.ImageWithDynamicBody; 23 | playerEntities: { [sessionId: string]: Phaser.Types.Physics.Arcade.ImageWithDynamicBody } = {}; 24 | 25 | debugFPS: Phaser.GameObjects.Text; 26 | 27 | localRef: Phaser.GameObjects.Rectangle; 28 | remoteRef: Phaser.GameObjects.Rectangle; 29 | 30 | cursorKeys: Phaser.Types.Input.Keyboard.CursorKeys; 31 | 32 | inputPayload = { 33 | left: false, 34 | right: false, 35 | up: false, 36 | down: false, 37 | tick: undefined, 38 | }; 39 | 40 | elapsedTime = 0; 41 | fixedTimeStep = 1000 / 60; 42 | 43 | currentTick: number = 0; 44 | 45 | constructor() { 46 | super({ key: "part4" }); 47 | } 48 | 49 | async create() { 50 | this.cursorKeys = this.input.keyboard.createCursorKeys(); 51 | this.debugFPS = this.add.text(4, 4, "", { color: "#ff0000", }); 52 | 53 | // connect with the room 54 | await this.connect(); 55 | 56 | const $ = getStateCallbacks(this.room); 57 | 58 | $(this.room.state).players.onAdd((player, sessionId) => { 59 | const entity = this.physics.add.image(player.x, player.y, 'ship_0001'); 60 | this.playerEntities[sessionId] = entity; 61 | 62 | // is current player 63 | if (sessionId === this.room.sessionId) { 64 | this.currentPlayer = entity; 65 | 66 | this.localRef = this.add.rectangle(0, 0, entity.width, entity.height); 67 | this.localRef.setStrokeStyle(1, 0x00ff00); 68 | 69 | this.remoteRef = this.add.rectangle(0, 0, entity.width, entity.height); 70 | this.remoteRef.setStrokeStyle(1, 0xff0000); 71 | 72 | $(player).onChange(() => { 73 | this.remoteRef.x = player.x; 74 | this.remoteRef.y = player.y; 75 | }); 76 | 77 | } else { 78 | // listening for server updates 79 | $(player).onChange(() => { 80 | // 81 | // we're going to LERP the positions during the render loop. 82 | // 83 | entity.setData('serverX', player.x); 84 | entity.setData('serverY', player.y); 85 | }); 86 | 87 | } 88 | 89 | }); 90 | 91 | // remove local reference when entity is removed from the server 92 | $(this.room.state).players.onRemove((player, sessionId) => { 93 | const entity = this.playerEntities[sessionId]; 94 | if (entity) { 95 | entity.destroy(); 96 | delete this.playerEntities[sessionId] 97 | } 98 | }); 99 | 100 | // this.cameras.main.startFollow(this.ship, true, 0.2, 0.2); 101 | // this.cameras.main.setZoom(1); 102 | this.cameras.main.setBounds(0, 0, 800, 600); 103 | } 104 | 105 | async connect() { 106 | // add connection status text 107 | const connectionStatusText = this.add 108 | .text(0, 0, "Trying to connect with the server...") 109 | .setStyle({ color: "#ff0000" }) 110 | .setPadding(4) 111 | 112 | const client = new Client(BACKEND_URL); 113 | 114 | try { 115 | this.room = await client.joinOrCreate("part4_room", {}); 116 | 117 | // connection successful! 118 | connectionStatusText.destroy(); 119 | 120 | } catch (e) { 121 | // couldn't connect 122 | connectionStatusText.text = "Could not connect with the server."; 123 | } 124 | 125 | } 126 | 127 | update(time: number, delta: number): void { 128 | // skip loop if not connected yet. 129 | if (!this.currentPlayer) { return; } 130 | 131 | this.elapsedTime += delta; 132 | while (this.elapsedTime >= this.fixedTimeStep) { 133 | this.elapsedTime -= this.fixedTimeStep; 134 | this.fixedTick(time, this.fixedTimeStep); 135 | } 136 | 137 | this.debugFPS.text = `Frame rate: ${this.game.loop.actualFps}`; 138 | } 139 | 140 | fixedTick(time, delta) { 141 | this.currentTick++; 142 | 143 | // const currentPlayerRemote = this.room.state.players.get(this.room.sessionId); 144 | // const ticksBehind = this.currentTick - currentPlayerRemote.tick; 145 | // console.log({ ticksBehind }); 146 | 147 | const velocity = 2; 148 | this.inputPayload.left = this.cursorKeys.left.isDown; 149 | this.inputPayload.right = this.cursorKeys.right.isDown; 150 | this.inputPayload.up = this.cursorKeys.up.isDown; 151 | this.inputPayload.down = this.cursorKeys.down.isDown; 152 | this.inputPayload.tick = this.currentTick; 153 | this.room.send(0, this.inputPayload); 154 | 155 | if (this.inputPayload.left) { 156 | this.currentPlayer.x -= velocity; 157 | 158 | } else if (this.inputPayload.right) { 159 | this.currentPlayer.x += velocity; 160 | } 161 | 162 | if (this.inputPayload.up) { 163 | this.currentPlayer.y -= velocity; 164 | 165 | } else if (this.inputPayload.down) { 166 | this.currentPlayer.y += velocity; 167 | } 168 | 169 | this.localRef.x = this.currentPlayer.x; 170 | this.localRef.y = this.currentPlayer.y; 171 | 172 | for (let sessionId in this.playerEntities) { 173 | // interpolate all player entities 174 | // (except the current player) 175 | if (sessionId === this.room.sessionId) { 176 | continue; 177 | } 178 | 179 | const entity = this.playerEntities[sessionId]; 180 | const { serverX, serverY } = entity.data.values; 181 | 182 | entity.x = Phaser.Math.Linear(entity.x, serverX, 0.2); 183 | entity.y = Phaser.Math.Linear(entity.y, serverY, 0.2); 184 | } 185 | 186 | } 187 | 188 | } -------------------------------------------------------------------------------- /client/src/scenes/SceneSelector.ts: -------------------------------------------------------------------------------- 1 | import Phaser from "phaser"; 2 | 3 | export class SceneSelector extends Phaser.Scene { 4 | 5 | parts = { 6 | '1': "Basic Player Movement", 7 | '2': "Interpolation", 8 | '3': "Client-predicted Input", 9 | '4': "Fixed Tickrate", 10 | }; 11 | 12 | constructor() { 13 | super({ key: "selector", active: true }); 14 | } 15 | 16 | preload() { 17 | // update menu background color 18 | this.cameras.main.setBackgroundColor(0x000000); 19 | 20 | // preload demo assets 21 | // this.load.image('ship_0001', 'assets/ship_0001.png'); 22 | this.load.image('ship_0001', 'https://cdn.glitch.global/3e033dcd-d5be-4db4-99e8-086ae90969ec/ship_0001.png?v=1649945243288'); 23 | } 24 | 25 | create() { 26 | // automatically navigate to hash scene if provided 27 | if (window.location.hash) { 28 | this.runScene(window.location.hash.substring(1)); 29 | return; 30 | } 31 | 32 | const textStyle: Phaser.Types.GameObjects.Text.TextStyle = { 33 | color: "#ff0000", 34 | fontSize: "32px", 35 | // fontSize: "24px", 36 | fontFamily: "Arial" 37 | }; 38 | 39 | for (let partNum in this.parts) { 40 | const index = parseInt(partNum) - 1; 41 | const label = this.parts[partNum]; 42 | 43 | // this.add.text(32, 32 + 32 * index, `Part ${partNum}: ${label}`, textStyle) 44 | this.add.text(130, 150 + 70 * index, `Part ${partNum}: ${label}`, textStyle) 45 | .setInteractive() 46 | .setPadding(6) 47 | .on("pointerdown", () => { 48 | this.runScene(`part${partNum}`); 49 | }); 50 | } 51 | } 52 | 53 | runScene(key: string) { 54 | this.game.scene.switch("selector", key) 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ 22 | // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | 26 | /* Modules */ 27 | "module": "commonjs", /* Specify what module code is generated. */ 28 | // "rootDir": "./", /* Specify the root folder within your source files. */ 29 | // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 30 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 31 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 32 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 33 | // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ 34 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 35 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 36 | // "resolveJsonModule": true, /* Enable importing .json files */ 37 | // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ 38 | 39 | /* JavaScript Support */ 40 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ 41 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 42 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ 43 | 44 | /* Emit */ 45 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 46 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 47 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 48 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 49 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ 50 | // "outDir": "./", /* Specify an output folder for all emitted files. */ 51 | // "removeComments": true, /* Disable emitting comments. */ 52 | // "noEmit": true, /* Disable emitting files from a compilation. */ 53 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 54 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ 55 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 56 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 58 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 59 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 60 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 61 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 62 | // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ 63 | // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ 64 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 65 | // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ 66 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 67 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 68 | 69 | /* Interop Constraints */ 70 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 71 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 72 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ 73 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 74 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 75 | 76 | /* Type Checking */ 77 | "strict": false, /* Enable all strict type-checking options. */ 78 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ 79 | // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ 80 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 81 | // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ 82 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 83 | // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ 84 | // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ 85 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 86 | // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ 87 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ 88 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 89 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 90 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 91 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ 92 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 93 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ 94 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 95 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 96 | 97 | /* Completeness */ 98 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 99 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /server/.env.development: -------------------------------------------------------------------------------- 1 | NODE_ENV=development -------------------------------------------------------------------------------- /server/.env.production: -------------------------------------------------------------------------------- 1 | NODE_ENV=production -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /server/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Colyseus! 2 | 3 | This project has been created using [⚔️ `create-colyseus-app`](https://github.com/colyseus/create-colyseus-app/) - an npm init template for kick starting a Colyseus project in TypeScript. 4 | 5 | [Documentation](http://docs.colyseus.io/) 6 | 7 | ## :crossed_swords: Usage 8 | 9 | ``` 10 | npm start 11 | ``` 12 | 13 | ## Structure 14 | 15 | - `index.ts`: main entry point, register an empty room handler and attach [`@colyseus/monitor`](https://github.com/colyseus/colyseus-monitor) 16 | - `src/rooms/MyRoom.ts`: an empty room handler for you to implement your logic 17 | - `src/rooms/schema/MyRoomState.ts`: an empty schema used on your room's state. 18 | - `loadtest/example.ts`: scriptable client for the loadtest tool (see `npm run loadtest`) 19 | - `package.json`: 20 | - `scripts`: 21 | - `npm start`: runs `ts-node-dev index.ts` 22 | - `npm test`: runs mocha test suite 23 | - `npm run loadtest`: runs the [`@colyseus/loadtest`](https://github.com/colyseus/colyseus-loadtest/) tool for testing the connection, using the `loadtest/example.ts` script. 24 | - `tsconfig.json`: TypeScript configuration file 25 | 26 | 27 | ## License 28 | 29 | MIT 30 | -------------------------------------------------------------------------------- /server/loadtest/example.ts: -------------------------------------------------------------------------------- 1 | import { Room, Client } from "colyseus.js"; 2 | 3 | export function requestJoinOptions (this: Client, i: number) { 4 | return { requestNumber: i }; 5 | } 6 | 7 | export function onJoin(this: Room) { 8 | console.log(this.sessionId, "joined."); 9 | 10 | this.onMessage("*", (type, message) => { 11 | console.log(this.sessionId, "received:", type, message); 12 | }); 13 | } 14 | 15 | export function onLeave(this: Room) { 16 | console.log(this.sessionId, "left."); 17 | } 18 | 19 | export function onError(this: Room, err: any) { 20 | console.log(this.sessionId, "!! ERROR !!", err.message); 21 | } 22 | 23 | export function onStateChange(this: Room, state: any) { 24 | console.log(this.sessionId, "new state:", state); 25 | } 26 | -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "my-app", 4 | "version": "1.0.0", 5 | "description": "npm init template for bootstrapping an empty Colyseus project", 6 | "main": "lib/index.js", 7 | "scripts": { 8 | "start": "tsx watch src/index.ts", 9 | "loadtest": "colyseus-loadtest loadtest/example.ts --room my_room --numClients 2", 10 | "build": "npm run clean && tsc", 11 | "clean": "node node_modules/rimraf/bin lib", 12 | "test": "mocha -r tsx test/**_test.ts --exit --timeout 15000" 13 | }, 14 | "author": "", 15 | "license": "UNLICENSED", 16 | "bugs": { 17 | "url": "https://github.com/colyseus/create-colyseus/issues" 18 | }, 19 | "homepage": "https://github.com/colyseus/create-colyseus#readme", 20 | "devDependencies": { 21 | "@colyseus/loadtest": "^0.16.0", 22 | "@colyseus/testing": "^0.16.0", 23 | "@types/cors": "^2.8.6", 24 | "@types/express": "^4.17.1", 25 | "@types/mocha": "^8.2.3", 26 | "copyfiles": "^2.4.1", 27 | "mocha": "^9.0.2", 28 | "rimraf": "^2.7.1", 29 | "tsx": "^3.12.7", 30 | "typescript": "^4.6.3" 31 | }, 32 | "dependencies": { 33 | "@colyseus/core": "^0.16.0", 34 | "@colyseus/monitor": "^0.16.0", 35 | "@colyseus/playground": "^0.16.0", 36 | "@colyseus/tools": "^0.16.0", 37 | "colyseus": "^0.16.0", 38 | "cors": "^2.8.5", 39 | "express": "^4.16.4" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /server/src/app.config.ts: -------------------------------------------------------------------------------- 1 | import config from "@colyseus/tools"; 2 | import { Server } from "@colyseus/core"; 3 | import { monitor } from "@colyseus/monitor"; 4 | import { playground } from "@colyseus/playground"; 5 | 6 | /** 7 | * Import your Room files 8 | */ 9 | import { Part1Room } from "./rooms/Part1Room"; 10 | import { Part2Room } from "./rooms/Part2Room"; 11 | import { Part3Room } from "./rooms/Part3Room"; 12 | import { Part4Room } from "./rooms/Part4Room"; 13 | 14 | let gameServerRef: Server; 15 | let latencySimulationMs: number = 0; 16 | 17 | export default config({ 18 | options: { 19 | // devMode: true, 20 | }, 21 | 22 | initializeGameServer: (gameServer) => { 23 | /** 24 | * Define your room handlers: 25 | */ 26 | gameServer.define('part1_room', Part1Room); 27 | gameServer.define('part2_room', Part2Room); 28 | gameServer.define('part3_room', Part3Room); 29 | gameServer.define('part4_room', Part4Room); 30 | 31 | // 32 | // keep gameServer reference, so we can 33 | // call `.simulateLatency()` later through an http route 34 | // 35 | gameServerRef = gameServer; 36 | }, 37 | 38 | initializeExpress: (app) => { 39 | /** 40 | * Bind your custom express routes here: 41 | */ 42 | app.get("/hello", (req, res) => { 43 | res.send("It's time to kick ass and chew bubblegum!"); 44 | }); 45 | 46 | // these latency methods are for development purpose only. 47 | app.get("/latency", (req, res) => res.json(latencySimulationMs)); 48 | app.get("/simulate-latency/:milliseconds", (req, res) => { 49 | latencySimulationMs = parseInt(req.params.milliseconds || "100"); 50 | 51 | // enable latency simulation 52 | gameServerRef.simulateLatency(latencySimulationMs); 53 | 54 | res.json({ success: true }); 55 | }); 56 | 57 | if (process.env.NODE_ENV !== "production") { 58 | app.use("/", playground()); 59 | } 60 | 61 | /** 62 | * Bind @colyseus/monitor 63 | * It is recommended to protect this route with a password. 64 | * Read more: https://docs.colyseus.io/tools/monitor/ 65 | */ 66 | app.use("/colyseus", monitor()); 67 | }, 68 | 69 | 70 | beforeListen: () => { 71 | /** 72 | * Before before gameServer.listen() is called. 73 | */ 74 | } 75 | }); 76 | -------------------------------------------------------------------------------- /server/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * IMPORTANT: 3 | * --------- 4 | * Do not manually edit this file if you'd like to use Colyseus Cloud 5 | * 6 | * If you're self-hosting (without Colyseus Cloud), you can manually instantiate a 7 | * Colyseus Server as documented here: 👉 https://docs.colyseus.io/server/api/#constructor-options 8 | */ 9 | import { listen } from "@colyseus/tools"; 10 | 11 | // Import arena config 12 | import appConfig from "./app.config"; 13 | 14 | // Create and listen on 2567 (or PORT environment variable.) 15 | listen(appConfig); 16 | -------------------------------------------------------------------------------- /server/src/rooms/Part1Room.ts: -------------------------------------------------------------------------------- 1 | import { Room, Client } from "colyseus"; 2 | import { Schema, type, MapSchema } from "@colyseus/schema"; 3 | 4 | export class Player extends Schema { 5 | @type("number") x: number; 6 | @type("number") y: number; 7 | } 8 | 9 | export class MyRoomState extends Schema { 10 | @type("number") mapWidth: number; 11 | @type("number") mapHeight: number; 12 | @type({ map: Player }) players = new MapSchema(); 13 | } 14 | 15 | export class Part1Room extends Room { 16 | state = new MyRoomState(); 17 | 18 | onCreate (options: any) { 19 | // set map dimensions 20 | this.state.mapWidth = 800; 21 | this.state.mapHeight = 600; 22 | 23 | // handle player input 24 | this.onMessage(0, (client, input) => { 25 | const player = this.state.players.get(client.sessionId); 26 | const velocity = 2; 27 | 28 | if (input.left) { 29 | player.x -= velocity; 30 | 31 | } else if (input.right) { 32 | player.x += velocity; 33 | } 34 | 35 | if (input.up) { 36 | player.y -= velocity; 37 | 38 | } else if (input.down) { 39 | player.y += velocity; 40 | } 41 | 42 | }); 43 | } 44 | 45 | onJoin (client: Client, options: any) { 46 | console.log(client.sessionId, "joined!"); 47 | 48 | // create player at random position. 49 | const player = new Player(); 50 | player.x = Math.random() * this.state.mapWidth; 51 | player.y = Math.random() * this.state.mapHeight; 52 | 53 | this.state.players.set(client.sessionId, player); 54 | } 55 | 56 | onLeave (client: Client, consented: boolean) { 57 | console.log(client.sessionId, "left!"); 58 | this.state.players.delete(client.sessionId); 59 | } 60 | 61 | onDispose() { 62 | console.log("room", this.roomId, "disposing..."); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /server/src/rooms/Part2Room.ts: -------------------------------------------------------------------------------- 1 | import { Room, Client } from "colyseus"; 2 | import { Schema, type, MapSchema } from "@colyseus/schema"; 3 | 4 | export class Player extends Schema { 5 | @type("number") x: number; 6 | @type("number") y: number; 7 | } 8 | 9 | export class MyRoomState extends Schema { 10 | @type("number") mapWidth: number; 11 | @type("number") mapHeight: number; 12 | @type({ map: Player }) players = new MapSchema(); 13 | } 14 | 15 | export class Part2Room extends Room { 16 | state = new MyRoomState(); 17 | 18 | onCreate (options: any) { 19 | // set map dimensions 20 | this.state.mapWidth = 800; 21 | this.state.mapHeight = 600; 22 | 23 | this.onMessage(0, (client, input) => { 24 | // handle player input 25 | const player = this.state.players.get(client.sessionId); 26 | const velocity = 2; 27 | 28 | if (input.left) { 29 | player.x -= velocity; 30 | 31 | } else if (input.right) { 32 | player.x += velocity; 33 | } 34 | 35 | if (input.up) { 36 | player.y -= velocity; 37 | 38 | } else if (input.down) { 39 | player.y += velocity; 40 | } 41 | 42 | }); 43 | } 44 | 45 | onJoin (client: Client, options: any) { 46 | console.log(client.sessionId, "joined!"); 47 | 48 | // create player at random position. 49 | const player = new Player(); 50 | player.x = Math.random() * this.state.mapWidth; 51 | player.y = Math.random() * this.state.mapHeight; 52 | 53 | this.state.players.set(client.sessionId, player); 54 | } 55 | 56 | onLeave (client: Client, consented: boolean) { 57 | console.log(client.sessionId, "left!"); 58 | this.state.players.delete(client.sessionId); 59 | } 60 | 61 | onDispose() { 62 | console.log("room", this.roomId, "disposing..."); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /server/src/rooms/Part3Room.ts: -------------------------------------------------------------------------------- 1 | import { Room, Client } from "colyseus"; 2 | import { Schema, type, MapSchema } from "@colyseus/schema"; 3 | 4 | export interface InputData { 5 | left: false; 6 | right: false; 7 | up: false; 8 | down: false; 9 | tick: number; 10 | } 11 | 12 | export class Player extends Schema { 13 | @type("number") x: number; 14 | @type("number") y: number; 15 | @type("number") tick: number; 16 | 17 | inputQueue: InputData[] = []; 18 | } 19 | 20 | export class MyRoomState extends Schema { 21 | @type("number") mapWidth: number; 22 | @type("number") mapHeight: number; 23 | @type({ map: Player }) players = new MapSchema(); 24 | } 25 | 26 | export class Part3Room extends Room { 27 | state = new MyRoomState(); 28 | fixedTimeStep = 1000 / 60; 29 | 30 | onCreate (options: any) { 31 | // set map dimensions 32 | this.state.mapWidth = 800; 33 | this.state.mapHeight = 600; 34 | 35 | this.onMessage(0, (client, input) => { 36 | // handle player input 37 | const player = this.state.players.get(client.sessionId); 38 | 39 | // enqueue input to user input buffer. 40 | player.inputQueue.push(input); 41 | }); 42 | 43 | this.setSimulationInterval((deltaTime) => { 44 | this.update(deltaTime); 45 | }); 46 | } 47 | 48 | update(deltaTime: number) { 49 | const velocity = 2; 50 | 51 | this.state.players.forEach(player => { 52 | let input: InputData; 53 | 54 | // dequeue player inputs 55 | while (input = player.inputQueue.shift()) { 56 | if (input.left) { 57 | player.x -= velocity; 58 | 59 | } else if (input.right) { 60 | player.x += velocity; 61 | } 62 | 63 | if (input.up) { 64 | player.y -= velocity; 65 | 66 | } else if (input.down) { 67 | player.y += velocity; 68 | } 69 | 70 | player.tick = input.tick; 71 | } 72 | }); 73 | } 74 | 75 | onJoin (client: Client, options: any) { 76 | console.log(client.sessionId, "joined!"); 77 | 78 | const player = new Player(); 79 | player.x = Math.random() * this.state.mapWidth; 80 | player.y = Math.random() * this.state.mapHeight; 81 | 82 | this.state.players.set(client.sessionId, player); 83 | } 84 | 85 | onLeave (client: Client, consented: boolean) { 86 | console.log(client.sessionId, "left!"); 87 | this.state.players.delete(client.sessionId); 88 | } 89 | 90 | onDispose() { 91 | console.log("room", this.roomId, "disposing..."); 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /server/src/rooms/Part4Room.ts: -------------------------------------------------------------------------------- 1 | import { Room, Client } from "colyseus"; 2 | import { Schema, type, MapSchema } from "@colyseus/schema"; 3 | 4 | export interface InputData { 5 | left: false; 6 | right: false; 7 | up: false; 8 | down: false; 9 | tick: number; 10 | } 11 | 12 | export class Player extends Schema { 13 | @type("number") x: number; 14 | @type("number") y: number; 15 | @type("number") tick: number; 16 | inputQueue: InputData[] = []; 17 | } 18 | 19 | export class MyRoomState extends Schema { 20 | @type("number") mapWidth: number; 21 | @type("number") mapHeight: number; 22 | @type({ map: Player }) players = new MapSchema(); 23 | } 24 | 25 | export class Part4Room extends Room { 26 | state = new MyRoomState(); 27 | fixedTimeStep = 1000 / 60; 28 | 29 | onCreate (options: any) { 30 | // set map dimensions 31 | this.state.mapWidth = 800; 32 | this.state.mapHeight = 600; 33 | 34 | this.onMessage(0, (client, input) => { 35 | // handle player input 36 | const player = this.state.players.get(client.sessionId); 37 | 38 | // enqueue input to user input buffer. 39 | player.inputQueue.push(input); 40 | }); 41 | 42 | let elapsedTime = 0; 43 | this.setSimulationInterval((deltaTime) => { 44 | elapsedTime += deltaTime; 45 | 46 | while (elapsedTime >= this.fixedTimeStep) { 47 | elapsedTime -= this.fixedTimeStep; 48 | this.fixedTick(this.fixedTimeStep); 49 | } 50 | }); 51 | } 52 | 53 | fixedTick(timeStep: number) { 54 | const velocity = 2; 55 | 56 | this.state.players.forEach(player => { 57 | let input: InputData; 58 | 59 | // dequeue player inputs 60 | while (input = player.inputQueue.shift()) { 61 | if (input.left) { 62 | player.x -= velocity; 63 | 64 | } else if (input.right) { 65 | player.x += velocity; 66 | } 67 | 68 | if (input.up) { 69 | player.y -= velocity; 70 | 71 | } else if (input.down) { 72 | player.y += velocity; 73 | } 74 | 75 | player.tick = input.tick; 76 | } 77 | }); 78 | } 79 | 80 | onJoin (client: Client, options: any) { 81 | console.log(client.sessionId, "joined!"); 82 | 83 | const player = new Player(); 84 | player.x = Math.random() * this.state.mapWidth; 85 | player.y = Math.random() * this.state.mapHeight; 86 | 87 | this.state.players.set(client.sessionId, player); 88 | } 89 | 90 | onLeave (client: Client, consented: boolean) { 91 | console.log(client.sessionId, "left!"); 92 | this.state.players.delete(client.sessionId); 93 | } 94 | 95 | onDispose() { 96 | console.log("room", this.roomId, "disposing..."); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /server/test/MyRoom_test.ts: -------------------------------------------------------------------------------- 1 | import assert from "assert"; 2 | import { ColyseusTestServer, boot } from "@colyseus/testing"; 3 | 4 | // import your "arena.config.ts" file here. 5 | import appConfig from "../src/arena.config"; 6 | import { MyRoomState } from "../src/rooms/schema/MyRoomState"; 7 | 8 | describe("testing your Colyseus app", () => { 9 | let colyseus: ColyseusTestServer; 10 | 11 | before(async () => colyseus = await boot(appConfig)); 12 | after(async () => colyseus.shutdown()); 13 | 14 | beforeEach(async () => await colyseus.cleanup()); 15 | 16 | it("connecting into a room", async () => { 17 | // `room` is the server-side Room instance reference. 18 | const room = await colyseus.createRoom("my_room", {}); 19 | 20 | // `client1` is the client-side `Room` instance reference (same as JavaScript SDK) 21 | const client1 = await colyseus.connectTo(room); 22 | 23 | // make your assertions 24 | assert.strictEqual(client1.sessionId, room.clients[0].sessionId); 25 | 26 | // wait for state sync 27 | await room.waitForNextPatch(); 28 | 29 | assert.deepStrictEqual({ mySynchronizedProperty: "Hello world" }, client1.state.toJSON()); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "build", 4 | "target": "ESNext", 5 | "resolveJsonModule":true, 6 | "module": "ESNext", 7 | "moduleResolution": "node", 8 | "strict": true, 9 | "allowJs": true, 10 | "strictNullChecks": false, 11 | "esModuleInterop": true, 12 | "experimentalDecorators": true, 13 | "skipLibCheck": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "useDefineForClassFields": false 16 | }, 17 | "include": [ 18 | "src" 19 | ] 20 | } 21 | --------------------------------------------------------------------------------