├── .github
└── workflows
│ └── .ci.yml
├── .gitignore
├── .prettierrc.json
├── README.md
├── deploy.sh
├── package.json
├── src
├── babylon.html
├── canvas.html
├── dom.html
├── excalibur.html
├── hilo.html
├── index.html
├── kaboom.html
├── kaplay.html
├── kontra.html
├── melon.html
├── partials
│ ├── container.html
│ ├── footer.html
│ ├── head.html
│ └── header.html
├── phaser.html
├── pixi.html
├── public
│ ├── favicon.svg
│ ├── sprite.png
│ ├── spritesheet.png
│ └── style.css
├── scripts
│ ├── babylon.js
│ ├── canvas.js
│ ├── dom.js
│ ├── engine.js
│ ├── excalibur.js
│ ├── hilo.js
│ ├── kaboom.js
│ ├── kaplay.js
│ ├── kontra.js
│ ├── melon.js
│ ├── phaser.js
│ ├── pixi.js
│ ├── three.js
│ └── two.js
├── three.html
└── two.html
├── vite.config.js
└── yarn.lock
/.github/workflows/.ci.yml:
--------------------------------------------------------------------------------
1 | name: 'CI'
2 | on:
3 | - push
4 | - pull_request
5 |
6 | jobs:
7 | build:
8 | runs-on: ubuntu-latest
9 | if: github.ref == 'refs/heads/master'
10 | permissions:
11 | contents: write
12 |
13 | steps:
14 | - uses: actions/checkout@v3
15 | - uses: actions/setup-node@v3
16 | with:
17 | node-version: 16
18 | cache: 'yarn'
19 | - run: yarn install --frozen-lockfile --ignore-engines
20 |
21 | - name: Build
22 | run: |
23 | yarn build
24 | echo > ./dist/.nojekyll
25 | env:
26 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27 | - name: Deploy to GitHub Pages
28 | uses: peaceiris/actions-gh-pages@v3
29 | with:
30 | github_token: ${{ secrets.GITHUB_TOKEN }}
31 | publish_dir: ./dist
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "es5",
3 | "tabWidth": 2,
4 | "semi": true,
5 | "singleQuote": true
6 | }
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Javascript rendering/game engines comparison
2 |
3 | https://shirajuki.js.org/js-game-rendering-benchmark/
4 |
5 | This is a sprite-based performance test that compares a set of Javascript-based rendering/game engines that are currently maintained. The test includes rendering a set of graphics/shapes and sprites.
6 |
7 | ## Description
8 |
9 | - A preset of up to 10.000 different sprites moving on a canvas with various speed
10 | - A custom option through the count query is also available for comparing sprite counts between libraries more freely. Be aware that drawing a large number of sprites on specific libraries may cause the test to freeze.
11 | - Compare drawing of graphics/shapes and sprites through the type query
12 | - Different libraries used to render the scene are chosen only if they have been maintained in the previous month of this benchmark. The following libraries compared and sorted by popularity (stars) are:
13 |
14 | | Name | Stars | Last Commit | Description | Game engine |
15 | | ------------------------------------------------------- | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
16 | | [three.js](https://github.com/mrdoob/three.js) |  |  | JavaScript 3D library. | no |
17 | | [PixiJS](https://github.com/pixijs/pixi.js) |  |  | The HTML5 Creation Engine: Create beautiful digital content with the fastest, most flexible 2D WebGL renderer. | no |
18 | | [Phaser](https://github.com/photonstorm/phaser) |  |  | Phaser is a fun, free and fast 2D game framework for making HTML5 games for desktop and mobile web browsers, supporting Canvas and WebGL rendering. | yes |
19 | | [Babylon.js](https://github.com/BabylonJS/Babylon.js) |  |  | Babylon.js is a powerful, beautiful, simple, and open game and rendering engine packed into a friendly JavaScript framework. | yes |
20 | | [Two.js](https://github.com/jonobr1/two.js) |  |  | A renderer agnostic two-dimensional drawing api for the web. | no |
21 | | [Hilo](https://github.com/hiloteam/Hilo) |  |  | A Cross-end HTML5 Game development solution developed by Alibaba Group | yes |
22 | | [MelonJS](https://github.com/melonjs/melonjs) |  |  | A fresh & lightweight javascript game engine. | yes |
23 | | [Kaboom](https://github.com/replit/kaboom) (deprecated) |  |  | 💥 JavaScript game library. | yes |
24 | | [Excalibur](https://github.com/excaliburjs/Excalibur) |  |  | 🎮 Your friendly TypeScript 2D game engine for the web 🗡️ | yes |
25 | | [Kaplay](https://github.com/kaplayjs/kaplay) |  |  | 🦖 A JavaScript/TypeScript Game Library that feels like a game. | yes |
26 | | [Kontra](https://github.com/straker/kontra) |  |  | A lightweight JavaScript gaming micro-library, optimized for js13kGames. | yes |
27 |
28 | ## Canvas and WebGL
29 |
30 | As a baseline for benchmarking, a DOM engine and Canvas engine for rendering shapes and sprites are included. Canvas is a 2D rendering context that lets us draw and manipulate sprites on an HTML canvas element. It's simple to use and supported by the majority of modern browsers, making it a popular choice for creating simple graphics, animations, and games.
31 |
32 | In contrast to Canvas, WebGL is a more powerful and versatile alternative. WebGL allows for more detailed and interactive 3D graphics, as well as access to the GPU, which improves performance even more than Canvas. As a result, WebGL is the most powerful choice for any web application that needs graphics-intensive rendering or interactive 3D scenes. However, when comparing Canvas and WebGL performance benchmarks with 2D graphics and sprites, it is important to remember that there may be some bias depending on the specific implementation as well as the environment in which the tests are run. Because WebGL is designed primarily for 3D graphics, it may not provide a significant performance boost over Canvas in a 2D context due to its higher resource requirements.
33 |
34 | To summarize, both technologies have advantages and are used in different scenarios depending on the project's specific needs. As a result, comparing the differences between canvas and WebGL with 2D sprites may be biased.
35 |
36 | ## Game engines and rendering engines
37 |
38 | A game engine is a software framework that gives one the tools and functionality one need to create and develop games. Input handling, physics, collision detection, and sprite animation are examples of the common features. A rendering engine, on the other hand, is a software component that is in charge of displaying and rendering graphics on the screen. It usually does not include the full set of tools and features found in a game engine. Three.js, Pixi.js, and Two.js are examples of such rendering engines.
39 |
40 | The rendering engine libraries Three.js, Pixi.js, and Two.js were tested on rendering 2D graphics and sprites for the performance benchmark. The most performant was discovered to be Pixi.js, followed by Three.js and Two.js. As a fallback, all of these support rendering in both the WebGL and Canvas contexts.
41 |
42 | In terms of performance, Babylon.js and Phaser outperformed the other game engines tested. The former is a game engine designed primarily for 3D games capable of rendering 2D sprites, whereas the latter has a longer history and a larger user base. Babylon.js was discovered to be slightly faster than Phaser, but both game engines performed reasonably well when tested.
43 |
44 | ## Conclusion
45 |
46 | It should be noted that being faster is not always preferable. Aside from performance, one must consider the features a library provides such as asset loading, sprite animation, input, etc. to easily create various games. In addition to this, some rendering/game engines may have a steeper learning curve than others, making them less desirable to use. It is important to consider user experience as well as speed in game development.
47 |
48 | Results of the benchmark on 10.000 sprites:
49 |
50 | 1. **Babylon.js**: [56 FPS] Babylon.js outperforms Three.js and has the best overall performance when it comes to rendering 2D sprites, despite being one of only two 3D engines in this benchmark - game engine. [(link)](https://shirajuki.js.org/js-game-rendering-benchmark/babylon.html?count=10000&type=sprite)
51 | 2. **Pixi.js**: [47 FPS] Good performance - rendering engine. [(link)](https://shirajuki.js.org/js-game-rendering-benchmark/pixi.html?count=10000&type=sprite)
52 | 3. **Phaser**: [43 FPS] The most popular library for HTML5 game development, and the performance demonstrates why. Overall, a good performance - game engine. [(link)](https://shirajuki.js.org/js-game-rendering-benchmark/phaser.html?count=10000&type=sprite)
53 |
54 | Honourable mentions:
55 |
56 | - **Kontra**: [60 FPS] To avoid frame rate issues, the game loop implementation of Kontra uses a time-based animation with a fixed dt. As a result, each update call is always guaranteed set to be 1/60 of a second. The update at 60 FPS in this case is not as smooth as in the other tests above, ranking it lower. - lightweight game engine. [(link)](https://shirajuki.js.org/js-game-rendering-benchmark/kontra.html?count=10000&type=sprite)
57 | - **Kaboom**: [3 FPS] Despite being one of the slowest libraries in terms of performance, developing with Kaboom was the most enjoyable. The library is jam-packed with features that make development simple and enjoyable. It has a straightforward syntax, and the code is simple to read and understand. The documentation and examples are also among the best of any library - game engine. [(link)](https://shirajuki.js.org/js-game-rendering-benchmark/kaboom.html?count=10000&type=sprite)
58 |
59 | The performance of the different libraries was measured by running a benchmark test on a computer with the following specifications:
60 |
61 | - OS: `Microsoft Windows 11 Home - 10.0.22621 Build 22621`
62 | - CPU: `AMD Ryzen 5 4500U`
63 | - RAM: `8GB 2666MHz`
64 | - Browser: `Microsoft Edge - Version 109.0.1518.55 (Official build) (64-bit)`
65 |
66 | ## Readings
67 |
68 | - [A collection of WebGL and WebGPU frameworks and libraries](https://gist.github.com/dmnsgn/76878ba6903cf15789b712464875cfdc)
69 | - [A collection of primarily HTML5 based game engines and frameworks](https://github.com/bebraw/jswiki/wiki/Game-Engines)
70 | - [quidmonkey's Benchmark comparison of pixijs and impactjs](https://github.com/quidmonkey/particle_test)
71 | - [slaylines' benchmark comparison of some popular canvas engines](https://github.com/slaylines/canvas-engines-comparison)
72 |
--------------------------------------------------------------------------------
/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | # abort on errors
4 | set -e
5 |
6 | # build
7 | npm run build
8 |
9 | # navigate into the build output directory
10 | cd dist
11 |
12 | # place .nojekyll to bypass Jekyll processing
13 | echo > .nojekyll
14 |
15 | git init
16 | git checkout -B master
17 | git add -A
18 | git commit -m 'ci: deploy web build'
19 |
20 | git push -f git@github.com:shirajuki/js-game-rendering-benchmark.git master:gh-pages
21 |
22 | cd -
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "js-game-rendering-benchmark",
3 | "private": true,
4 | "version": "1.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "NODE_ENV=development vite",
8 | "build": "vite build",
9 | "deploy": "bash deploy.sh",
10 | "preview": "vite preview"
11 | },
12 | "devDependencies": {
13 | "vite": "^4.0.0",
14 | "vite-plugin-handlebars": "^1.6.0"
15 | },
16 | "dependencies": {
17 | "babylonjs": "^5.42.0",
18 | "excalibur": "^0.30.3",
19 | "fpsmeter": "^0.3.1",
20 | "hilojs": "^2.0.2",
21 | "kaboom": "^2000.2.10",
22 | "kaplay": "^3001.0.12",
23 | "kontra": "^8.0.0",
24 | "melonjs": "^14.5.0",
25 | "phaser": "^3.55.2",
26 | "pixi.js": "^7.1.0",
27 | "three": "^0.148.0",
28 | "two.js": "^0.8.10"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/babylon.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{#> head }} Babylon.js — JS Game Rendering Benchmark {{/head}}
4 |
5 | {{> header }}
6 |
7 | {{> container }}
8 |
9 |
10 | {{> footer }}
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/canvas.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{#> head }} Canvas — JS Game Rendering Benchmark {{/head}}
4 |
5 | {{> header }}
6 |
7 | {{> container }}
8 |
9 |
10 | {{> footer }}
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/dom.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{#> head }} DOM — JS Game Rendering Benchmark {{/head}}
4 |
5 | {{> header }}
6 |
7 | {{> container }}
8 |
9 |
10 | {{> footer }}
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/excalibur.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{#> head }} Excalibur — JS Game Rendering Benchmark {{/head}}
4 |
5 | {{> header }}
6 |
7 | {{> container }}
8 |
9 |
10 | {{> footer }}
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/hilo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{#> head }} Hilo — JS Game Rendering Benchmark {{/head}}
4 |
5 | {{> header }}
6 |
7 | {{> container }}
8 |
9 |
10 | {{> footer }}
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{#> head index=1 }} Index — JS Game Rendering Benchmark {{/head}}
4 |
5 | {{> header }}
6 |
7 | {{> container }}
8 |
9 |
10 | {{> footer }}
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/kaboom.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{#> head }} Kaboom v2000 — JS Game Rendering Benchmark {{/head}}
4 |
5 | {{> header }}
6 |
7 | {{> container }}
8 |
9 |
10 | {{> footer }}
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/kaplay.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{#> head }} Kaboom v3000 — JS Game Rendering Benchmark {{/head}}
4 |
5 | {{> header }}
6 |
7 | {{> container }}
8 |
9 |
10 | {{> footer }}
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/kontra.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{#> head }} Kontra — JS Game Rendering Benchmark {{/head}}
4 |
5 | {{> header }}
6 |
7 | {{> container }}
8 |
9 |
10 | {{> footer }}
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/melon.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{#> head }} melonJS — JS Game Rendering Benchmark {{/head}}
4 |
5 | {{> header }}
6 |
7 | {{> container }}
8 |
9 |
10 | {{> footer }}
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/partials/container.html:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/src/partials/footer.html:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/src/partials/head.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
12 | {{> @partial-block }}
13 | {{#if index }}
14 |
15 |
18 | {{/if}}
19 |
20 |
38 |
39 |
45 |
77 |
--------------------------------------------------------------------------------
/src/partials/header.html:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/src/phaser.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{#> head }} Phaser — JS Game Rendering Benchmark {{/head}}
4 |
5 | {{> header }}
6 |
7 | {{> container }}
8 |
9 |
10 | {{> footer }}
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/pixi.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{#> head }} Pixi.js — JS Game Rendering Benchmark {{/head}}
4 |
5 | {{> header }}
6 |
7 | {{> container }}
8 |
9 |
10 | {{> footer }}
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/public/sprite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirajuki/js-game-rendering-benchmark/09f38e74716aeb3749a0c908d900e345c4fd0912/src/public/sprite.png
--------------------------------------------------------------------------------
/src/public/spritesheet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirajuki/js-game-rendering-benchmark/09f38e74716aeb3749a0c908d900e345c4fd0912/src/public/spritesheet.png
--------------------------------------------------------------------------------
/src/public/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | }
4 |
5 | :root {
6 | font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
7 | font-size: 16px;
8 | line-height: 24px;
9 | font-weight: 400;
10 |
11 | color: rgba(255, 255, 255, 0.87);
12 | background-color: #242424;
13 |
14 | font-synthesis: none;
15 | text-rendering: optimizeLegibility;
16 | -webkit-font-smoothing: antialiased;
17 | -moz-osx-font-smoothing: grayscale;
18 | -webkit-text-size-adjust: 100%;
19 | }
20 |
21 | a {
22 | font-weight: 500;
23 | color: #9c64ff;
24 | text-decoration: none;
25 | border-bottom: 1px solid #9c64ff;
26 | transition: color 0.2s, filter 0.2s, border-color 0.2s;
27 | }
28 |
29 | a:hover {
30 | color: #934ddd;
31 | }
32 |
33 | html {
34 | zoom: 0.9;
35 | }
36 |
37 | body {
38 | margin: 0;
39 | min-width: 320px;
40 | min-height: 100vh;
41 | font-size: 18px;
42 | }
43 |
44 | header {
45 | padding: 2rem;
46 | min-height: 90px;
47 | font-size: 26px;
48 | }
49 |
50 | nav {
51 | display: flex;
52 | flex-wrap: wrap;
53 | gap: 1rem;
54 | }
55 |
56 | main {
57 | padding: 0 2rem;
58 | max-width: 100vw;
59 | overflow-x: hidden;
60 | }
61 |
62 | footer {
63 | position: fixed;
64 | display: flex;
65 | flex-direction: column;
66 | justify-content: flex-end;
67 | gap: 0.25rem;
68 | bottom: 0;
69 | width: 100%;
70 | height: 90px;
71 | padding: 2rem;
72 | }
73 |
74 | footer .name {
75 | font-size: 26px;
76 | }
77 |
78 | footer span {
79 | font-size: 14px;
80 | margin-left: 0.75rem;
81 | opacity: 0.7;
82 | }
83 |
84 | main>div {
85 | display: grid;
86 | grid-template-columns: 1fr 140px;
87 | min-height: 60px;
88 | align-items: center;
89 | width: 1024px;
90 | }
91 |
92 | .container {
93 | position: relative;
94 | margin-top: 0.2rem;
95 | margin-bottom: 0.8rem;
96 | }
97 |
98 | .fps-container {
99 | position: relative;
100 | transform: translate(4px, 13px);
101 | }
102 |
103 | .fps-container>div {
104 | height: 40px !important;
105 | border-radius: 6px;
106 | }
107 |
108 | .container span {
109 | font-size: 0.9rem;
110 | }
111 |
112 | .count-container>div {
113 | margin-top: 0.1rem;
114 | }
115 |
116 | .count-container a:last-of-type:not(.active) {
117 | pointer-events: none;
118 | opacity: 0.7;
119 | border-bottom: 1px solid transparent;
120 | filter: grayscale(1);
121 | }
122 |
123 | .container a {
124 | position: relative;
125 | display: inline-block;
126 | border-radius: 6px;
127 | border: 1px solid transparent;
128 | padding: 0.3em 0.6em;
129 | font-size: 1em;
130 | font-weight: 500;
131 | font-family: inherit;
132 | cursor: pointer;
133 | background-color: #1a1a1a;
134 | border-color: #9c64ff;
135 | transition: border-color 0.2s, color 0.2s;
136 | }
137 |
138 | .container a.active {
139 | border-color: #fff !important;
140 | border-bottom-color: #fff !important;
141 | }
142 |
143 | .count-container a:last-of-type {
144 | border-color: transparent;
145 | }
146 |
147 | .container a::before {
148 | content: '';
149 | position: absolute;
150 | }
151 |
152 | .options-container {
153 | position: absolute;
154 | bottom: 0;
155 | right: 142px;
156 | }
157 |
158 | .active {
159 | color: white;
160 | pointer-events: none;
161 | }
162 |
163 | a.active {
164 | border-bottom: 1px solid transparent;
165 | }
166 |
167 | .particle {
168 | position: absolute;
169 | border: 1px solid white;
170 | border-radius: 50%;
171 | }
172 |
173 | .particle.fill {
174 | background-color: white;
175 | border: 1px solid black;
176 | }
177 |
178 | .particle.sprite {
179 | border: initial;
180 | border-radius: initial;
181 | }
182 |
183 | canvas,
184 | .canvas {
185 | display: inline-block;
186 | position: relative;
187 | overflow: hidden;
188 | width: 1024px;
189 | height: 480px;
190 | background-color: #1a1a1a;
191 | border-radius: 0.5rem;
192 | transform: translateZ(0);
193 | pointer-events: none;
194 | }
195 |
196 | button {
197 | border-radius: 8px;
198 | border: 1px solid transparent;
199 | padding: 0.6em 1.2em;
200 | font-size: 1em;
201 | font-weight: 500;
202 | font-family: inherit;
203 | background-color: #1a1a1a;
204 | cursor: pointer;
205 | transition: border-color 0.25s;
206 | }
207 |
208 | button:hover {
209 | border-color: #9c64ff;
210 | }
211 |
212 | button:focus,
213 | button:focus-visible {
214 | outline: 4px auto -webkit-focus-ring-color;
215 | }
--------------------------------------------------------------------------------
/src/scripts/babylon.js:
--------------------------------------------------------------------------------
1 | import * as BABYLON from 'babylonjs';
2 | import Engine from './engine.js';
3 |
4 | class BabylonEngine extends Engine {
5 | init() {
6 | super.init();
7 |
8 | // Clear the canvas
9 | this.canvas.innerHTML = '';
10 | window.cancelAnimationFrame(this.request);
11 |
12 | // Load the 3D engine
13 | if (this.engine) this.engine.stopRenderLoop();
14 | this.engine = new BABYLON.Engine(this.canvas, true, {
15 | preserveDrawingBuffer: true,
16 | stencil: true,
17 | });
18 | // Create a basic BJS Scene object
19 | this.scene = new BABYLON.Scene(this.engine);
20 | this.scene.clearColor = new BABYLON.Color3(0.098, 0.098, 0.098);
21 | // Create a FreeCamera, and set its position to {x: 0, y: 5, z: -10}
22 | const camera = new BABYLON.FreeCamera(
23 | 'camera1',
24 | new BABYLON.Vector3(0, 1, 0),
25 | this.scene
26 | );
27 | // We chose an orthographic view to simplify at most our mesh creation
28 | camera.mode = BABYLON.Camera.ORTHOGRAPHIC_CAMERA;
29 | // Setup the camera to fit with our canvas coordinates
30 | camera.orthoLeft = 0;
31 | camera.orthoTop = 0;
32 | camera.orthoRight = this.width;
33 | camera.orthoBottom = this.height;
34 | camera.fov = 0.9;
35 | // Target the camera to scene origin
36 | camera.setTarget(BABYLON.Vector3.Zero());
37 |
38 | const light0 = new BABYLON.HemisphericLight(
39 | 'Hemi0',
40 | new BABYLON.Vector3(0, 0, 0),
41 | this.scene
42 | );
43 | light0.diffuse = new BABYLON.Color3(1, 1, 1);
44 | light0.specular = new BABYLON.Color3(1, 1, 1);
45 | light0.groundColor = new BABYLON.Color3(1, 1, 1);
46 |
47 | const optimizerOptions = new BABYLON.SceneOptimizerOptions(60, 500);
48 | optimizerOptions.addOptimization(
49 | new BABYLON.HardwareScalingOptimization(0, 1)
50 | );
51 | // Optimizer
52 | const optimizer = new BABYLON.SceneOptimizer(this.scene, optimizerOptions);
53 |
54 | // Spritemanager
55 | const spriteManager = new BABYLON.SpriteManager(
56 | 'textures',
57 | 'sprite.png',
58 | 1000000,
59 | { width: 64, height: 64 },
60 | this.scene
61 | );
62 |
63 | // Particle creation
64 | const particles = new Array(this.count);
65 | const rnd = [1, -1];
66 | const circles = {};
67 | for (let i = 0; i < this.count; i++) {
68 | const size = 10 + Math.random() * 80;
69 | const x = Math.random() * this.width;
70 | const y = Math.random() * (this.height - size);
71 | const [dx, dy] = [
72 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
73 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
74 | ];
75 |
76 | let particle;
77 | let filled;
78 | if (this.type === 'sprite') {
79 | particle = new BABYLON.Sprite('sprite', spriteManager);
80 | particle.width = 64;
81 | particle.height = 64;
82 | particle.angle = Math.PI;
83 | particle.invertU = true;
84 | particle.position.x = -x;
85 | particle.position.z = -y;
86 | particle.position.y = -i;
87 | } else {
88 | // Create circles by drawing lines in a 360 degree radius
89 | let points = [];
90 | if (circles[size]) {
91 | points = circles[size];
92 | } else {
93 | const radius = size;
94 | for (let i = -Math.PI; i <= Math.PI; i += Math.PI / 360) {
95 | points.push(
96 | new BABYLON.Vector3(radius * Math.cos(i), 0, radius * Math.sin(i))
97 | );
98 | }
99 | circles[size] = points;
100 | }
101 | particle = BABYLON.MeshBuilder.CreateLines(
102 | 'circle',
103 | { points: points, updatable: false },
104 | this.scene
105 | );
106 | particle.color = new BABYLON.Color3.White();
107 | particle.position.x = -x;
108 | particle.position.z = -y;
109 | particle.position.y = -i - 1;
110 | if (this.type === 'fill') {
111 | const mat = new BABYLON.StandardMaterial('mat1', this.scene);
112 | mat.alpha = 1;
113 | mat.diffuseColor = new BABYLON.Color3(1, 1, 1);
114 | mat.emissiveColor = new BABYLON.Color3.White();
115 | mat.backFaceCulling = false;
116 | filled = BABYLON.MeshBuilder.CreateRibbon(
117 | 'filled_circle',
118 | {
119 | pathArray: [points],
120 | closePath: true,
121 | },
122 | this.scene
123 | );
124 | filled.color = BABYLON.Color3.White();
125 | filled.material = mat;
126 | filled.position.x = -x;
127 | filled.position.z = -y;
128 | filled.position.y = -i;
129 | particle.color = new BABYLON.Color3.Black();
130 | }
131 | }
132 |
133 | particles[i] = { x, y, size: size, dx, dy, el: [particle, filled] };
134 | }
135 | this.particles = particles;
136 | }
137 | render() {
138 | this.engine.runRenderLoop(() => {
139 | // Particle animation
140 | const particles = this.particles;
141 | for (let i = 0; i < this.count; i++) {
142 | const r = particles[i];
143 | r.x -= r.dx;
144 | r.y -= r.dy;
145 | if (r.x + r.size < 0) r.dx *= -1;
146 | else if (r.y + r.size < 0) r.dy *= -1;
147 | if (r.x > this.width) r.dx *= -1;
148 | else if (r.y > this.height) r.dy *= -1;
149 | r.el[0].position.x = -r.x;
150 | r.el[0].position.z = -r.y;
151 | if (r.el[1]) {
152 | r.el[1].position.x = -r.x;
153 | r.el[1].position.z = -r.y;
154 | }
155 | }
156 | this.scene.render();
157 | this.fpsmeter.tick();
158 | });
159 | }
160 | }
161 |
162 | document.addEventListener('DOMContentLoaded', () => {
163 | const engine = new BabylonEngine();
164 | engine.render();
165 | });
166 |
--------------------------------------------------------------------------------
/src/scripts/canvas.js:
--------------------------------------------------------------------------------
1 | import Engine from './engine.js';
2 |
3 | class CanvasEngine extends Engine {
4 | init() {
5 | super.init();
6 |
7 | // Clear the canvas
8 | this.canvas.innerHTML = '';
9 | window.cancelAnimationFrame(this.request);
10 |
11 | if (this.type === 'sprite') {
12 | this.sprite = new Image();
13 | this.sprite.src = 'sprite.png';
14 | }
15 |
16 | // Particle creation
17 | const particles = new Array(this.count);
18 | const rnd = [1, -1];
19 | for (let i = 0; i < this.count; i++) {
20 | const size = 10 + Math.random() * 80;
21 | const x = Math.random() * this.width;
22 | const y = Math.random() * (this.height - size);
23 | const [dx, dy] = [
24 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
25 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
26 | ];
27 | particles[i] = { x, y, size: size, dx, dy };
28 | }
29 | this.particles = particles;
30 |
31 | this.ctx = this.canvas.getContext('2d');
32 | this.ctx.strokeStyle = this.type === 'stroke' ? 'white' : 'black';
33 | if (this.type === 'fill') this.ctx.fillStyle = 'white';
34 | this.ctx.lineWidth = 1;
35 | }
36 | render() {
37 | // Clear the canvas
38 | this.ctx.clearRect(0, 0, this.width, this.height);
39 |
40 | // Particle animation
41 | const particles = this.particles;
42 | for (let i = 0; i < this.count; i++) {
43 | const r = particles[i];
44 | r.x -= r.dx;
45 | r.y -= r.dy;
46 | if (r.x + r.size < 0) r.dx *= -1;
47 | else if (r.y + r.size < 0) r.dy *= -1;
48 | if (r.x > this.width) r.dx *= -1;
49 | else if (r.y > this.height) r.dy *= -1;
50 | if (this.type === 'sprite') {
51 | if (this.sprite.complete) {
52 | this.ctx.beginPath();
53 | this.ctx.drawImage(this.sprite, r.x, r.y);
54 | }
55 | } else {
56 | this.ctx.beginPath();
57 | this.ctx.arc(r.x, r.y, r.size, 0, 2 * Math.PI);
58 | if (this.type === 'fill') this.ctx.fill();
59 | if (this.type !== 'sprite') this.ctx.stroke();
60 | }
61 | }
62 |
63 | this.fpsmeter.tick();
64 | this.request = window.requestAnimationFrame(() => this.render());
65 | }
66 | }
67 |
68 | document.addEventListener('DOMContentLoaded', () => {
69 | const engine = new CanvasEngine();
70 | engine.render();
71 | });
72 |
--------------------------------------------------------------------------------
/src/scripts/dom.js:
--------------------------------------------------------------------------------
1 | import Engine from './engine.js';
2 |
3 | class DOMEngine extends Engine {
4 | init() {
5 | super.init();
6 |
7 | // Clear the canvas
8 | this.canvas.innerHTML = '';
9 | window.cancelAnimationFrame(this.request);
10 |
11 | // Particle creation
12 | const particles = new Array(this.count);
13 | const rnd = [1, -1];
14 | for (let i = 0; i < this.count; i++) {
15 | const size = 10 + Math.random() * 80 * 2;
16 | const x = Math.random() * this.width;
17 | const y = Math.random() * (this.height - size);
18 | const [dx, dy] = [
19 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
20 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
21 | ];
22 |
23 | let particle;
24 | if (this.type === 'sprite') {
25 | particle = document.createElement('img');
26 | particle.src = 'sprite.png';
27 | particle.className = 'particle sprite';
28 | } else {
29 | particle = document.createElement('div');
30 | if (this.type === 'stroke') particle.className = 'particle';
31 | else if (this.type === 'fill') particle.className = 'particle fill';
32 | particle.style.width = `${size}px`;
33 | particle.style.height = `${size}px`;
34 | }
35 | particle.style.left = `${x}px`;
36 | particle.style.top = `${y}px`;
37 | this.canvas.appendChild(particle);
38 | particles[i] = { x, y, size: size, dx, dy, el: particle };
39 | }
40 | this.particles = particles;
41 | }
42 | render() {
43 | // Particle animation
44 | const particles = this.particles;
45 | for (let i = 0; i < this.count; i++) {
46 | const r = particles[i];
47 | r.x -= r.dx;
48 | r.y -= r.dy;
49 | if (r.x + r.size < 0) r.dx *= -1;
50 | else if (r.y + r.size < 0) r.dy *= -1;
51 | if (r.x > this.width) r.dx *= -1;
52 | else if (r.y > this.height) r.dy *= -1;
53 | r.el.style.left = `${r.x}px`;
54 | r.el.style.top = `${r.y}px`;
55 | }
56 |
57 | this.fpsmeter.tick();
58 | this.request = window.requestAnimationFrame(() => this.render());
59 | }
60 | }
61 |
62 | document.addEventListener('DOMContentLoaded', () => {
63 | const engine = new DOMEngine();
64 | engine.render();
65 | });
66 |
--------------------------------------------------------------------------------
/src/scripts/engine.js:
--------------------------------------------------------------------------------
1 | import 'fpsmeter';
2 |
3 | const getCount = (search) =>
4 | search
5 | .substring(1)
6 | .split('&')
7 | .filter((s) => s.startsWith('count='))
8 | .map((s) => Number.parseInt(s.split('=')[1]))[0];
9 |
10 | const getType = (search) =>
11 | search
12 | .substring(1)
13 | .split('&')
14 | .filter((s) => s.startsWith('type='))
15 | .map((s) => s.split('=')[1])[0];
16 |
17 | class Engine {
18 | constructor() {
19 | this.canvas = document.querySelector('#canvas');
20 | this.fpsContainer = document.querySelector('.fps-container');
21 | this.countLinks = document.querySelectorAll('.count-container a');
22 | this.typeLinks = document.querySelectorAll('.options-container a');
23 | canvas.width = 1024;
24 | canvas.height = 480;
25 | this.width = this.canvas.width;
26 | this.height = this.canvas.height;
27 | this.count = 0;
28 |
29 | this.initCountLink();
30 | this.initTypeLink();
31 | this.init();
32 | }
33 |
34 | initFpsmeter() {
35 | this.fpsContainer.innerHTML = '';
36 | this.fpsmeter = new window.FPSMeter(this.fpsContainer, {
37 | top: 0,
38 | left: 0,
39 | heat: 1,
40 | theme: 'dark',
41 | graph: 1,
42 | history: 25,
43 | transform: 'translateY(-50%)',
44 | });
45 | }
46 |
47 | initCountLink() {
48 | const toggleCountLinks = (count) => {
49 | for (const link of this.countLinks) {
50 | link.classList.toggle('active', false);
51 | }
52 | const link = [...this.countLinks].filter((l) => Number.parseInt(l.innerText) === count)[0];
53 | if (link) {
54 | link.classList.toggle('active', true);
55 | this.count = count;
56 | } else
57 | this.countLinks[this.countLinks.length - 1].classList.toggle(
58 | 'active',
59 | true
60 | );
61 | };
62 | const { search, pathname } = window.location;
63 | const count = getCount(search);
64 | this.count = count || 1000;
65 | toggleCountLinks(this.count);
66 | this.countLinks.forEach((link, _index) => {
67 | link.addEventListener('click', (event) => {
68 | event.preventDefault();
69 | event.stopPropagation();
70 | const count = Number.parseInt(link.innerText);
71 | const type = getType(search) || this.type;
72 | if (count) {
73 | if (type)
74 | window.history.replaceState(
75 | {},
76 | pathname,
77 | `?count=${count}&type=${type}`
78 | );
79 | else window.history.replaceState({}, pathname, `?count=${count}`);
80 | toggleCountLinks(count);
81 | this.init();
82 | this.render();
83 | }
84 | });
85 | });
86 | }
87 |
88 | initTypeLink() {
89 | const toggleTypeLinks = (type) => {
90 | for (const link of this.typeLinks) {
91 | link.classList.toggle('active', false);
92 | }
93 | const link = [...this.typeLinks].filter((l) => l.innerText.toLowerCase() === type)[0];
94 | if (link) {
95 | link.classList.toggle('active', true);
96 | this.type = type;
97 | } else
98 | this.typeLinks[this.typeLinks.length - 1].classList.toggle(
99 | 'active',
100 | true
101 | );
102 | };
103 | const { search, pathname } = window.location;
104 | const type = getType(search);
105 | this.type = ['stroke', 'fill', 'sprite'].includes(type)
106 | ? type
107 | : null || 'stroke';
108 | toggleTypeLinks(this.type);
109 | this.typeLinks.forEach((link, _index) => {
110 | link.addEventListener('click', (event) => {
111 | event.preventDefault();
112 | event.stopPropagation();
113 | const type = link.innerText.toLowerCase();
114 | const count = getCount(search) || this.count;
115 | if (type) {
116 | if (count)
117 | window.history.replaceState(
118 | {},
119 | pathname,
120 | `?count=${count}&type=${type}`
121 | );
122 | else window.history.replaceState({}, pathname, `?type=${type}`);
123 | toggleTypeLinks(type);
124 | this.init();
125 | this.render();
126 | }
127 | });
128 | });
129 | }
130 |
131 | initNavLink() {
132 | const navLinks = document.querySelectorAll('header > nav > a');
133 | const { search, pathname } = window.location;
134 |
135 | for (const ml of [...navLinks]) {
136 | if (ml.pathname === pathname) ml.classList.add('active');
137 | ml.addEventListener('click', (event) => {
138 | event.preventDefault();
139 | event.stopPropagation();
140 | const count = getCount(search);
141 | const type = getType(search);
142 | let href = count ? `${ml.pathname}?count=${count}` : ml.pathname;
143 | if (type) href += `${count ? '&' : '?'}type=${type}`;
144 | window.location.href = href;
145 | });
146 | }
147 | }
148 |
149 | init() {
150 | this.initFpsmeter();
151 | this.initNavLink();
152 | }
153 |
154 | render() { }
155 | }
156 |
157 | export default Engine;
158 |
--------------------------------------------------------------------------------
/src/scripts/excalibur.js:
--------------------------------------------------------------------------------
1 | import * as ex from 'excalibur';
2 | import Engine from './engine.js';
3 |
4 | export class Scene extends ex.Scene {
5 | onActivate(ctx) {
6 | const engine = ctx.engine;
7 | this.engine = ctx.data.engine;
8 |
9 | this.clear();
10 |
11 | // Particle creation
12 | const particles = new Array(this.engine.count);
13 | const rnd = [1, -1];
14 | const spriteImage = new ex.ImageSource('sprite.png');
15 | spriteImage.load();
16 | for (let i = 0; i < this.engine.count; i++) {
17 | const size = 10 + Math.random() * 80;
18 | const x = Math.random() * this.engine.width;
19 | const y = Math.random() * (this.engine.height - size);
20 | const [dx, dy] = [
21 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
22 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
23 | ];
24 |
25 | const particle = new ex.Actor({
26 | x: x,
27 | y: y,
28 | radius: size,
29 | });
30 |
31 | if (this.engine.type === 'sprite') {
32 | const sprite = ex.Sprite.from(spriteImage);
33 | particle.graphics.use(sprite);
34 | } else {
35 | const circle = new ex.Circle({
36 | x: x,
37 | y: y,
38 | radius: size,
39 | color:
40 | this.engine.type === 'stroke'
41 | ? ex.Color.Transparent
42 | : ex.Color.fromRGB(255, 255, 255),
43 | strokeColor:
44 | this.engine.type === 'stroke'
45 | ? ex.Color.fromRGB(255, 255, 255)
46 | : ex.Color.fromRGB(0, 0, 0),
47 | strokeWidth: this.engine.type === 'stroke' ? 1 : undefined,
48 | });
49 | particle.graphics.use(circle);
50 | }
51 | this.add(particle);
52 |
53 | particles[i] = { x, y, size: size, dx, dy, el: particle };
54 |
55 | particle.on("postupdate", () => {
56 | const r = particles[i];
57 | r.x -= r.dx;
58 | r.y -= r.dy;
59 | if (r.x + r.size < 0) r.dx *= -1;
60 | else if (r.y + r.size < 0) r.dy *= -1;
61 | if (r.x > engine.screen.drawWidth) r.dx *= -1;
62 | else if (r.y > engine.screen.drawHeight) r.dy *= -1;
63 | r.el.pos.x = r.x;
64 | r.el.pos.y = r.y;
65 | });
66 | }
67 | }
68 | onPostUpdate() {
69 | this.engine.fpsmeter.tick();
70 | }
71 | }
72 |
73 | class ExcaliburEngine extends Engine {
74 | init() {
75 | super.init();
76 |
77 | window.cancelAnimationFrame(this.request);
78 | if (this.game) {
79 | this.game.dispose();
80 | this.canvas = document.createElement("canvas");
81 | this.canvas.id = "canvas";
82 | this.canvas.className = "canvas";
83 | this.canvas.width = this.width;
84 | this.canvas.height = this.height;
85 | document.querySelector("main").appendChild(this.canvas);
86 | }
87 |
88 | const game = new ex.Engine({
89 | width: this.width,
90 | height: this.height,
91 | canvasElement: this.canvas,
92 | backgroundColor: ex.Color.fromRGB(26, 26, 26),
93 | scenes: { scene: Scene }
94 | });
95 | this.game = game;
96 | }
97 | render() {
98 | this.game.start().then(() => {
99 | this.game.goToScene('scene', { sceneActivationData: { engine: this } });
100 | });
101 | }
102 | }
103 |
104 | document.addEventListener('DOMContentLoaded', () => {
105 | const engine = new ExcaliburEngine();
106 | engine.render();
107 | });
108 |
--------------------------------------------------------------------------------
/src/scripts/hilo.js:
--------------------------------------------------------------------------------
1 | import Hilo from 'hilojs';
2 | import Engine from './engine.js';
3 |
4 | class HiloEngine extends Engine {
5 | init() {
6 | const GraphicScene = Hilo.Class.create({
7 | Extends: Hilo.Container,
8 | constructor: function (properties) {
9 | GraphicScene.superclass.constructor.call(this, properties);
10 | this.init(properties);
11 | },
12 | init: (_properties) => {
13 | return;
14 | },
15 | onUpdate: function (_properties) {
16 | if (!this.engine) return;
17 | // Particle animation
18 | const particles = this.engine.particles;
19 | for (let i = 0; i < this.engine.count; i++) {
20 | const r = particles[i];
21 | r.x -= r.dx;
22 | r.y -= r.dy;
23 | if (r.x + r.size < 0) r.dx *= -1;
24 | else if (r.y + r.size < 0) r.dy *= -1;
25 | if (r.x > this.engine.width) r.dx *= -1;
26 | else if (r.y > this.engine.height) r.dy *= -1;
27 | r.el.x = r.x;
28 | r.el.y = r.y;
29 | }
30 |
31 | this.engine.fpsmeter.tick();
32 | },
33 | loadEngine: function (engine) {
34 | this.engine = engine;
35 | },
36 | });
37 |
38 | super.init();
39 |
40 | if (this.ticker) this.ticker.stop();
41 |
42 | // Clear the canvas
43 | this.canvas.innerHTML = '';
44 | window.cancelAnimationFrame(this.request);
45 | const main = document.querySelector('main');
46 | main.removeChild(main.lastElementChild);
47 |
48 | // Init stage and scene
49 | this.stage = new Hilo.Stage({
50 | renderType: 'canvas',
51 | container: main,
52 | width: this.width,
53 | height: this.height,
54 | });
55 | this.graphicScene = new GraphicScene({
56 | width: this.width,
57 | height: this.height,
58 | engine: this,
59 | }).addTo(this.stage);
60 | this.graphicScene.loadEngine(this);
61 |
62 | // Particle creation
63 | const particles = new Array(this.count);
64 | const rnd = [1, -1];
65 | for (let i = 0; i < this.count; i++) {
66 | const size = 10 + Math.random() * 80;
67 | const x = Math.random() * this.width;
68 | const y = Math.random() * (this.height - size);
69 | const [dx, dy] = [
70 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
71 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
72 | ];
73 | let particle;
74 | if (this.type === 'sprite') {
75 | particle = new Hilo.Bitmap({
76 | image: 'sprite.png',
77 | }).addTo(this.graphicScene);
78 | } else {
79 | particle = new Hilo.Graphics({
80 | width: size * 2,
81 | height: size * 2,
82 | x: x,
83 | y: y,
84 | });
85 | if (this.type === 'stroke')
86 | particle
87 | .lineStyle(1, '#ffffff')
88 | .drawCircle(1, 1, size - 1)
89 | .closePath()
90 | .endFill()
91 | .addTo(this.graphicScene);
92 | else if (this.type === 'fill')
93 | particle
94 | .beginFill('#fff')
95 | .lineStyle(1, '#000000')
96 | .drawCircle(1, 1, size - 1)
97 | .closePath()
98 | .endFill()
99 | .addTo(this.graphicScene);
100 | }
101 | particles[i] = { x, y, size: size, dx, dy, el: particle };
102 | }
103 | this.particles = particles;
104 | }
105 | render() {
106 | // Start game loop
107 | this.ticker = new Hilo.Ticker(60);
108 | this.ticker.addTick(this.stage);
109 | this.ticker.start();
110 | }
111 | }
112 |
113 | document.addEventListener('DOMContentLoaded', () => {
114 | const engine = new HiloEngine();
115 | engine.render();
116 | });
117 |
--------------------------------------------------------------------------------
/src/scripts/kaboom.js:
--------------------------------------------------------------------------------
1 | import kaboom from 'kaboom';
2 | import Engine from './engine.js';
3 |
4 | class KaboomEngine extends Engine {
5 | init() {
6 | super.init();
7 |
8 | const k = kaboom({
9 | background: [26, 26, 26],
10 | global: false,
11 | canvas: this.canvas,
12 | width: this.width,
13 | height: this.height,
14 | });
15 | k.loadSprite('sprite', 'sprite.png');
16 | this.k = k;
17 |
18 | // Clear the canvas
19 | this.canvas.innerHTML = '';
20 | window.cancelAnimationFrame(this.request);
21 |
22 | // Particle creation
23 | const particles = new Array(this.count);
24 | const rnd = [1, -1];
25 | for (let i = 0; i < this.count; i++) {
26 | const size = 10 + Math.random() * 80;
27 | const x = Math.random() * this.width;
28 | const y = Math.random() * (this.height - size);
29 | const [dx, dy] = [
30 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
31 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
32 | ];
33 | let particle;
34 | if (this.type === 'sprite') {
35 | particle = k.add([k.sprite('sprite'), k.pos(x, y)]);
36 | } else {
37 | particle = k.add([
38 | k.pos(x, y),
39 | k.circle(size),
40 | k.opacity(this.type === 'stroke' ? 0 : 1),
41 | k.outline(
42 | 1,
43 | this.type === 'stroke' ? k.rgb(255, 255, 255) : k.rgb(0, 0, 0)
44 | ),
45 | ]);
46 | }
47 |
48 | particles[i] = { x, y, size: size, dx, dy, el: particle };
49 | }
50 | this.particles = particles;
51 | }
52 | render() {
53 | const k = this.k;
54 | k.onUpdate(() => {
55 | // Particle animation
56 | const particles = this.particles;
57 | for (let i = 0; i < this.count; i++) {
58 | const r = particles[i];
59 | r.x -= r.dx;
60 | r.y -= r.dy;
61 | if (r.x + r.size < 0) r.dx *= -1;
62 | else if (r.y + r.size < 0) r.dy *= -1;
63 | if (r.x > this.width) r.dx *= -1;
64 | else if (r.y > this.height) r.dy *= -1;
65 | r.el.pos.x = r.x;
66 | r.el.pos.y = r.y;
67 | }
68 | this.fpsmeter.tick();
69 | });
70 | }
71 | }
72 |
73 | document.addEventListener('DOMContentLoaded', () => {
74 | const engine = new KaboomEngine();
75 | engine.render();
76 | });
77 |
--------------------------------------------------------------------------------
/src/scripts/kaplay.js:
--------------------------------------------------------------------------------
1 | import kaplay from 'kaplay';
2 | import Engine from './engine.js';
3 |
4 | class KaplayEngine extends Engine {
5 | init() {
6 | super.init();
7 |
8 | const k = kaplay({
9 | background: [26, 26, 26],
10 | global: false,
11 | canvas: this.canvas,
12 | width: this.width,
13 | height: this.height,
14 | });
15 | k.loadSprite('sprite', 'sprite.png');
16 | this.k = k;
17 |
18 | // Clear the canvas
19 | this.canvas.innerHTML = '';
20 | window.cancelAnimationFrame(this.request);
21 |
22 | // Particle creation
23 | const particles = new Array(this.count);
24 | const rnd = [1, -1];
25 | for (let i = 0; i < this.count; i++) {
26 | const size = 10 + Math.random() * 80;
27 | const x = Math.random() * this.width;
28 | const y = Math.random() * (this.height - size);
29 | const [dx, dy] = [
30 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
31 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
32 | ];
33 | let particle;
34 | if (this.type === 'sprite') {
35 | particle = k.add([k.sprite('sprite'), k.pos(x, y)]);
36 | } else {
37 | particle = k.add([
38 | k.pos(x, y),
39 | k.circle(size),
40 | k.opacity(this.type === 'stroke' ? 0 : 1),
41 | k.outline(
42 | 1,
43 | this.type === 'stroke' ? k.rgb(255, 255, 255) : k.rgb(0, 0, 0)
44 | ),
45 | ]);
46 | }
47 |
48 | particles[i] = { x, y, size: size, dx, dy, el: particle };
49 | }
50 | this.particles = particles;
51 | }
52 | render() {
53 | const k = this.k;
54 | k.onUpdate(() => {
55 | // Particle animation
56 | const particles = this.particles;
57 | for (let i = 0; i < this.count; i++) {
58 | const r = particles[i];
59 | r.x -= r.dx;
60 | r.y -= r.dy;
61 | if (r.x + r.size < 0) r.dx *= -1;
62 | else if (r.y + r.size < 0) r.dy *= -1;
63 | if (r.x > this.width) r.dx *= -1;
64 | else if (r.y > this.height) r.dy *= -1;
65 | r.el.pos.x = r.x;
66 | r.el.pos.y = r.y;
67 | }
68 | this.fpsmeter.tick();
69 | });
70 | }
71 | }
72 |
73 | document.addEventListener('DOMContentLoaded', () => {
74 | const engine = new KaplayEngine();
75 | engine.render();
76 | });
77 |
--------------------------------------------------------------------------------
/src/scripts/kontra.js:
--------------------------------------------------------------------------------
1 | import { init, GameLoop, Sprite } from 'kontra';
2 | import Engine from './engine.js';
3 |
4 | class KontraEngine extends Engine {
5 | init() {
6 | super.init();
7 |
8 | // Clear the canvas
9 | this.canvas.innerHTML = '';
10 | window.cancelAnimationFrame(this.request);
11 |
12 | if (!this.loop) {
13 | const { context } = init();
14 | this.ctx = context;
15 | this.ctx.strokeStyle = 'white';
16 | this.ctx.lineWidth = 1;
17 | }
18 | if (this.type === 'fill') {
19 | this.ctx.strokeStyle = 'black';
20 | this.ctx.fillStyle = 'white';
21 | }
22 | const image = new Image();
23 | image.src = 'sprite.png';
24 |
25 | // Particle creation
26 | const particles = new Array(this.count);
27 | const rnd = [1, -1];
28 | for (let i = 0; i < this.count; i++) {
29 | const size = 10 + Math.random() * 80;
30 | const x = Math.random() * this.width;
31 | const y = Math.random() * (this.height - size);
32 | const [dx, dy] = [
33 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
34 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
35 | ];
36 | let sprite;
37 | if (this.type === 'sprite') {
38 | sprite = Sprite({
39 | x: x,
40 | y: y,
41 | anchor: { x: 0.5, y: 0.5 },
42 | image: image,
43 | });
44 | }
45 | particles[i] = { x, y, size: size, dx, dy, el: sprite };
46 | }
47 | this.particles = particles;
48 | }
49 | render() {
50 | if (this.loop) return;
51 | this.loop = GameLoop({
52 | update: () => {
53 | // Particle animation
54 | for (let i = 0; i < this.count; i++) {
55 | const r = this.particles[i];
56 | r.x -= r.dx;
57 | r.y -= r.dy;
58 | if (r.x + r.size < 0) r.dx *= -1;
59 | else if (r.y + r.size < 0) r.dy *= -1;
60 | if (r.x > this.width) r.dx *= -1;
61 | else if (r.y > this.height) r.dy *= -1;
62 | if (r.el) {
63 | r.el.x = r.x;
64 | r.el.y = r.y;
65 | }
66 | }
67 | },
68 | render: () => {
69 | for (let i = 0; i < this.count; i++) {
70 | const r = this.particles[i];
71 | if (this.type === 'sprite') {
72 | r.el.render();
73 | } else {
74 | this.ctx.beginPath();
75 | this.ctx.arc(r.x, r.y, r.size, 0, 2 * Math.PI);
76 | if (this.type === 'fill') this.ctx.fill();
77 | this.ctx.stroke();
78 | }
79 | }
80 | this.fpsmeter.tick();
81 | },
82 | });
83 | this.loop.start();
84 | }
85 | }
86 |
87 | document.addEventListener('DOMContentLoaded', () => {
88 | const engine = new KontraEngine();
89 | engine.render();
90 | });
91 |
--------------------------------------------------------------------------------
/src/scripts/melon.js:
--------------------------------------------------------------------------------
1 | import * as me from 'melonjs';
2 | import Engine from './engine.js';
3 |
4 | class Graphics extends me.Renderable {
5 | constructor(engine) {
6 | super(0, 0, engine.width, engine.heigth);
7 | this.engine = engine;
8 | this.anchorPoint.set(0, 0);
9 | me.state.change(me.state.DEFAULT, true);
10 |
11 | // Particle creation
12 | const particles = new Array(engine.count);
13 | const rnd = [1, -1];
14 | for (let i = 0; i < engine.count; i++) {
15 | const size = 10 + Math.random() * 80;
16 | const x = Math.random() * engine.width;
17 | const y = Math.random() * (engine.height - size);
18 | const [dx, dy] = [
19 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
20 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
21 | ];
22 | let sprite;
23 | if (engine.type === 'sprite') {
24 | sprite = new me.Sprite(x, y, {
25 | image: '/sprite.png',
26 | framewidth: 64,
27 | frameheight: 64,
28 | anchorPoint: new me.Vector2d(0.5, 0.5),
29 | });
30 | me.game.world.addChild(sprite);
31 | }
32 | particles[i] = { x, y, size: size, dx, dy, el: sprite };
33 | }
34 | engine.particles = particles;
35 | }
36 | update() {
37 | return true;
38 | }
39 | draw(renderer) {
40 | // Particle animation
41 | const particles = this.engine.particles;
42 | for (let i = 0; i < this.engine.count; i++) {
43 | const r = particles[i];
44 | r.x -= r.dx;
45 | r.y -= r.dy;
46 | if (r.x + r.size < 0) r.dx *= -1;
47 | else if (r.y + r.size < 0) r.dy *= -1;
48 | if (r.x > this.engine.width) r.dx *= -1;
49 | else if (r.y > this.engine.height) r.dy *= -1;
50 | if (this.engine.type === 'stroke') {
51 | renderer.setColor('#ffffff');
52 | renderer.strokeArc(r.x, r.y, r.size, 0, Math.PI * 2);
53 | } else if (this.engine.type === 'fill') {
54 | renderer.setColor('#ffffff');
55 | renderer.fillArc(r.x, r.y, r.size, 0, Math.PI * 2, false);
56 | renderer.setColor('#000000');
57 | renderer.strokeArc(r.x, r.y, r.size, 0, Math.PI * 2, false);
58 | } else if (this.engine.type === 'sprite' && r.el) {
59 | r.el.pos.set(r.x, r.y);
60 | }
61 | }
62 | this.engine.fpsmeter.tick();
63 | }
64 | }
65 |
66 | class MelonEngine extends Engine {
67 | init() {
68 | super.init();
69 |
70 | // Clear the canvas
71 | this.canvas.innerHTML = '';
72 | window.cancelAnimationFrame(this.request);
73 |
74 | // Create if new, else reset/empty the game world
75 | this.textureLoaded = false;
76 | if (me.game.world) {
77 | me.game.world.reset();
78 | } else {
79 | const main = document.querySelector('main');
80 | main.removeChild(main.lastElementChild);
81 | me.video.init(this.width, this.height, {
82 | parent: 'main',
83 | renderer: me.video.AUTO,
84 | preferWebGL1: false,
85 | subPixel: false,
86 | });
87 | me.game.world.backgroundColor.setColor('#1a1a1a');
88 | }
89 | me.loader.preload(
90 | [
91 | {
92 | name: 'sprite',
93 | type: 'image',
94 | src: 'sprite.png',
95 | },
96 | ],
97 | () => {
98 | this.textureLoaded = true;
99 | this.render();
100 | }
101 | );
102 | }
103 | render() {
104 | if (this.textureLoaded) me.game.world.addChild(new Graphics(this));
105 | }
106 | }
107 |
108 | document.addEventListener('DOMContentLoaded', () => {
109 | const engine = new MelonEngine();
110 | engine.render();
111 | });
112 |
--------------------------------------------------------------------------------
/src/scripts/phaser.js:
--------------------------------------------------------------------------------
1 | import * as Phaser from 'phaser';
2 | import Engine from './engine.js';
3 |
4 | const scene = (engine) => {
5 | return {
6 | preload() {
7 | this.load.image('sprite', 'sprite.png');
8 | },
9 | create() {
10 | for (let i = 0; i < engine.count; i++) {
11 | const r = engine.particles[i];
12 | let particle;
13 | if (engine.type === 'sprite') {
14 | particle = this.add.sprite(r.x, r.y, 'sprite');
15 | } else {
16 | particle = this.add.circle(r.x, r.y, r.size, 0xffffff);
17 | if (engine.type === 'stroke') {
18 | particle.setStrokeStyle(1, 0xffffff);
19 | particle.isFilled = false;
20 | } else if (engine.type === 'fill')
21 | particle.setStrokeStyle(1, 0x000000);
22 | }
23 |
24 | engine.particles[i].el = particle;
25 | }
26 | },
27 | update(_time, _delta) {
28 | // Particle animation
29 | const particles = engine.particles;
30 | for (let i = 0; i < engine.count; i++) {
31 | const r = particles[i];
32 | r.x -= r.dx;
33 | r.y -= r.dy;
34 | if (r.x + r.size < 0) r.dx *= -1;
35 | else if (r.y + r.size < 0) r.dy *= -1;
36 | if (r.x > engine.width) r.dx *= -1;
37 | else if (r.y > engine.height) r.dy *= -1;
38 | if (r.el) {
39 | r.el.x = r.x;
40 | r.el.y = r.y;
41 | }
42 | }
43 | engine.fpsmeter.tick();
44 | },
45 | };
46 | };
47 |
48 | class CanvasEngine extends Engine {
49 | init() {
50 | super.init();
51 |
52 | // Clear the canvas
53 | this.canvas.innerHTML = '';
54 | window.cancelAnimationFrame(this.request);
55 |
56 | // Configure phaser with custom scene
57 | this.config = {
58 | type: Phaser.WEBGL,
59 | width: this.width,
60 | height: this.height,
61 | canvas,
62 | physics: {
63 | default: 'arcade',
64 | arcade: {
65 | gravity: { y: 0 },
66 | debug: false,
67 | fps: 60,
68 | },
69 | },
70 | backgroundColor: '#1a1a1a',
71 | scene: [scene(this)],
72 | render: { pixelArt: false, antialias: true },
73 | };
74 |
75 | // Particle creation
76 | const particles = new Array(this.count);
77 | const rnd = [1, -1];
78 | for (let i = 0; i < this.count; i++) {
79 | const size = 10 + Math.random() * 80;
80 | const x = Math.random() * this.width;
81 | const y = Math.random() * (this.height - size);
82 | const [dx, dy] = [
83 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
84 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
85 | ];
86 | particles[i] = { x, y, size: size, dx, dy };
87 | }
88 | this.particles = particles;
89 | }
90 | render() {
91 | if (this.game) this.game.destroy(false, false);
92 | this.game = new Phaser.Game(this.config);
93 | }
94 | }
95 |
96 | document.addEventListener('DOMContentLoaded', () => {
97 | const engine = new CanvasEngine();
98 | engine.render();
99 | });
100 |
--------------------------------------------------------------------------------
/src/scripts/pixi.js:
--------------------------------------------------------------------------------
1 | import * as PIXI from 'pixi.js';
2 | import Engine from './engine.js';
3 |
4 | class PixiEngine extends Engine {
5 | async init() {
6 | super.init();
7 |
8 | // Clear the canvas
9 | this.canvas.innerHTML = '';
10 | window.cancelAnimationFrame(this.request);
11 |
12 | // Setup application and stage
13 | if (this.app) this.app.ticker.destroy();
14 | this.app = new PIXI.Application({
15 | width: this.width,
16 | height: this.height,
17 | backgroundColor: 0x1a1a1a,
18 | antialias: true,
19 | });
20 | this.app.view.classList.add('canvas');
21 |
22 | // Update canvas with application view
23 | const main = document.querySelector('main');
24 | main.removeChild(main.lastElementChild);
25 | main.appendChild(this.app.view);
26 |
27 | // Particle creation
28 | if (this.type === 'sprite') {
29 | this.texture = PIXI.Texture.from('sprite.png');
30 | }
31 | const particles = new Array(this.count);
32 | const rnd = [1, -1];
33 | for (let i = 0; i < this.count; i++) {
34 | const size = 10 + Math.random() * 80;
35 | const x = Math.random() * this.width;
36 | const y = Math.random() * (this.height - size);
37 | const [dx, dy] = [
38 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
39 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
40 | ];
41 | let particle;
42 | if (this.type === 'sprite') {
43 | particle = new PIXI.Sprite(this.texture);
44 | } else {
45 | particle = new PIXI.Graphics();
46 | if (this.type === 'stroke') {
47 | particle.lineStyle(1, 0xffffff, 1);
48 | particle.drawCircle(-size / 2, -size / 2, size, 0, Math.PI);
49 | } else if (this.type === 'fill') {
50 | particle.beginFill(0xffffff);
51 | particle.lineStyle(1, 0x000000, 1);
52 | particle.drawCircle(-size / 2, -size / 2, size, 0, Math.PI);
53 | particle.endFill();
54 | }
55 | }
56 | particle.position.set(x, y);
57 | this.app.stage.addChild(particle);
58 | particles[i] = { x, y, size: size, dx, dy, el: particle };
59 | }
60 | this.particles = particles;
61 | }
62 | render() {
63 | this.app.ticker.add(() => {
64 | // Particle animation
65 | const particles = this.particles;
66 | for (let i = 0; i < this.count; i++) {
67 | const r = particles[i];
68 | r.x -= r.dx;
69 | r.y -= r.dy;
70 | if (r.x + r.size < 0) r.dx *= -1;
71 | else if (r.y + r.size < 0) r.dy *= -1;
72 | if (r.x > this.width) r.dx *= -1;
73 | else if (r.y > this.height) r.dy *= -1;
74 | r.el.position.x = r.x;
75 | r.el.position.y = r.y;
76 | }
77 |
78 | this.fpsmeter.tick();
79 | });
80 | }
81 | }
82 |
83 | document.addEventListener('DOMContentLoaded', () => {
84 | const engine = new PixiEngine();
85 | engine.render();
86 | });
87 |
--------------------------------------------------------------------------------
/src/scripts/three.js:
--------------------------------------------------------------------------------
1 | import * as THREE from 'three';
2 | import Engine from './engine.js';
3 |
4 | class ThreeEngine extends Engine {
5 | init() {
6 | super.init();
7 |
8 | // Clear the canvas
9 | this.canvas.innerHTML = '';
10 | window.cancelAnimationFrame(this.request);
11 |
12 | // Setup application and stage
13 | this.camera = new THREE.PerspectiveCamera(
14 | 50,
15 | this.width / this.height,
16 | 0.1,
17 | 2000
18 | );
19 | this.camera.position.set(this.width / 2, this.height / 2, 500);
20 | this.renderer = new THREE.WebGLRenderer({
21 | antialias: true,
22 | depth: false,
23 | precision: 'lowp',
24 | });
25 | this.renderer.setSize(this.width, this.height);
26 | this.renderer.sortObjects = false;
27 | this.renderer.domElement.classList.add('canvas');
28 |
29 | if (this.scene) this.scene.clear();
30 | this.scene = new THREE.Scene();
31 | this.scene.background = new THREE.Color('#1a1a1a');
32 |
33 | // Update canvas with renderer view
34 | const main = document.querySelector('main');
35 | main.removeChild(main.lastElementChild);
36 | main.appendChild(this.renderer.domElement);
37 |
38 | // Particle creation
39 | const particles = new Array(this.count);
40 | const rnd = [1, -1];
41 | const meshMaterial = new THREE.MeshBasicMaterial({
42 | color: 0xffffff,
43 | side: THREE.FrontSide,
44 | depthTest: false,
45 | });
46 | let lineMaterial = new THREE.LineBasicMaterial({ color: 0xffffff });
47 | if (this.type === 'fill')
48 | lineMaterial = new THREE.LineBasicMaterial({ color: 0x000000 });
49 |
50 | // Sprite texture
51 | const map = new THREE.TextureLoader().load('sprite.png');
52 | const material = new THREE.SpriteMaterial({ map: map });
53 |
54 | for (let i = 0; i < this.count; i++) {
55 | const size = 10 + Math.random() * 80;
56 | const x = Math.random() * this.width;
57 | const y = Math.random() * (this.height - size);
58 | const [dx, dy] = [
59 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
60 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
61 | ];
62 |
63 | const geometry = new THREE.CircleGeometry(size);
64 | let line;
65 | let plane;
66 | if (this.type === 'sprite') {
67 | line = new THREE.Sprite(material);
68 | line.scale.x = 64;
69 | line.scale.y = 64;
70 | } else {
71 | if (this.type === 'fill') {
72 | plane = new THREE.Mesh(geometry, meshMaterial);
73 | plane.position.set(x, y, 0);
74 | this.scene.add(plane);
75 | }
76 | const edges = new THREE.EdgesGeometry(geometry);
77 | line = new THREE.LineSegments(edges, lineMaterial);
78 | }
79 | line.position.set(x, y, 0);
80 | this.scene.add(line);
81 | particles[i] = { x, y, size: size, dx, dy, el: [line, plane] };
82 | }
83 | this.particles = particles;
84 | }
85 | render() {
86 | // Particle animation
87 | const particles = this.particles;
88 | for (let i = 0; i < this.count; i++) {
89 | const r = particles[i];
90 | r.x -= r.dx;
91 | r.y -= r.dy;
92 | if (r.x + r.size < 0) r.dx *= -1;
93 | else if (r.y + r.size < 0) r.dy *= -1;
94 | if (r.x > this.width) r.dx *= -1;
95 | else if (r.y > this.height) r.dy *= -1;
96 |
97 | r.el[0].position.x = r.x;
98 | r.el[0].position.y = r.y;
99 | if (r.el[1]) {
100 | r.el[1].position.x = r.x;
101 | r.el[1].position.y = r.y;
102 | }
103 | }
104 | this.renderer.render(this.scene, this.camera);
105 |
106 | this.fpsmeter.tick();
107 | this.request = window.requestAnimationFrame(() => this.render());
108 | }
109 | }
110 |
111 | document.addEventListener('DOMContentLoaded', () => {
112 | const engine = new ThreeEngine();
113 | engine.render();
114 | });
115 |
--------------------------------------------------------------------------------
/src/scripts/two.js:
--------------------------------------------------------------------------------
1 | import Two from 'two.js';
2 | import Engine from './engine.js';
3 |
4 | class TwoEngine extends Engine {
5 | init() {
6 | super.init();
7 |
8 | // Clear the canvas
9 | this.canvas.innerHTML = '';
10 | window.cancelAnimationFrame(this.request);
11 |
12 | const main = document.querySelector('main');
13 | main.removeChild(main.lastElementChild);
14 | if (this.two) {
15 | this.two.unbind('update');
16 | this.two.clear();
17 | }
18 | this.two = new Two({
19 | type: Two.Types.webgl,
20 | width: this.width,
21 | height: this.height,
22 | autostart: true,
23 | }).appendTo(main);
24 |
25 | // Particle creation
26 | const particles = new Array(this.count);
27 | const rnd = [1, -1];
28 | for (let i = 0; i < this.count; i++) {
29 | const size = 10 + Math.random() * 80;
30 | const x = Math.random() * this.width;
31 | const y = Math.random() * (this.height - size);
32 | const [dx, dy] = [
33 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
34 | 3 * Math.random() * rnd[Math.floor(Math.random() * 2)],
35 | ];
36 | let particle;
37 | if (this.type === 'sprite') {
38 | particle = new Two.Sprite('sprite.png', x, y, 1, 1);
39 | this.two.add(particle);
40 | } else {
41 | particle = this.two.makeCircle(0, 0, size);
42 | if (this.type === 'stroke') particle.noFill().stroke = '#ffffff';
43 | else if (this.type === 'fill') particle.stroke = '#000000';
44 | }
45 | particle.position.set(0, 0);
46 | particles[i] = { x, y, size: size, dx, dy, el: particle };
47 | }
48 | this.particles = particles;
49 | }
50 | render() {
51 | this.two.bind('update', () => {
52 | // Particle animation
53 | const particles = this.particles;
54 | for (let i = 0; i < this.count; i++) {
55 | const r = particles[i];
56 | r.x -= r.dx;
57 | r.y -= r.dy;
58 | if (r.x + r.size < 0) r.dx *= -1;
59 | else if (r.y + r.size < 0) r.dy *= -1;
60 | if (r.x > this.width) r.dx *= -1;
61 | else if (r.y > this.height) r.dy *= -1;
62 | r.el.translation.set(r.x, r.y);
63 | }
64 | this.fpsmeter.tick();
65 | });
66 | }
67 | }
68 |
69 | document.addEventListener('DOMContentLoaded', () => {
70 | const engine = new TwoEngine();
71 | engine.render();
72 | });
73 |
--------------------------------------------------------------------------------
/src/three.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{#> head }} Three.js — JS Game Rendering Benchmark {{/head}}
4 |
5 | {{> header }}
6 |
7 | {{> container }}
8 |
9 |
10 | {{> footer }}
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/two.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{#> head }} Two.js — JS Game Rendering Benchmark {{/head}}
4 |
5 | {{> header }}
6 |
7 | {{> container }}
8 |
9 |
10 | {{> footer }}
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 | import { resolve } from 'path';
3 | import handlebars from 'vite-plugin-handlebars';
4 |
5 | const input = {};
6 | fs.readdirSync('src').forEach((file) => {
7 | if (file.endsWith('.html')) {
8 | if (file === 'index.html') return;
9 | input[file.split('.')[0]] = resolve('src', file);
10 | }
11 | });
12 |
13 | export default {
14 | root: 'src',
15 | base:
16 | process.env.NODE_ENV === 'development'
17 | ? './'
18 | : '/js-game-rendering-benchmark/',
19 | build: {
20 | outDir: '../dist',
21 | emptyOutDir: true,
22 | rollupOptions: {
23 | input: {
24 | main: resolve('src', 'index.html'),
25 | ...input,
26 | },
27 | },
28 | },
29 | plugins: [
30 | handlebars({
31 | partialDirectory: resolve('src', 'partials'),
32 | }),
33 | ],
34 | };
35 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@esbuild/android-arm64@0.16.17":
6 | version "0.16.17"
7 | resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz#cf91e86df127aa3d141744edafcba0abdc577d23"
8 | integrity sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==
9 |
10 | "@esbuild/android-arm@0.16.17":
11 | version "0.16.17"
12 | resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.16.17.tgz#025b6246d3f68b7bbaa97069144fb5fb70f2fff2"
13 | integrity sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==
14 |
15 | "@esbuild/android-x64@0.16.17":
16 | version "0.16.17"
17 | resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.16.17.tgz#c820e0fef982f99a85c4b8bfdd582835f04cd96e"
18 | integrity sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==
19 |
20 | "@esbuild/darwin-arm64@0.16.17":
21 | version "0.16.17"
22 | resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz#edef4487af6b21afabba7be5132c26d22379b220"
23 | integrity sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==
24 |
25 | "@esbuild/darwin-x64@0.16.17":
26 | version "0.16.17"
27 | resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz#42829168730071c41ef0d028d8319eea0e2904b4"
28 | integrity sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==
29 |
30 | "@esbuild/freebsd-arm64@0.16.17":
31 | version "0.16.17"
32 | resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz#1f4af488bfc7e9ced04207034d398e793b570a27"
33 | integrity sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==
34 |
35 | "@esbuild/freebsd-x64@0.16.17":
36 | version "0.16.17"
37 | resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz#636306f19e9bc981e06aa1d777302dad8fddaf72"
38 | integrity sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==
39 |
40 | "@esbuild/linux-arm64@0.16.17":
41 | version "0.16.17"
42 | resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz#a003f7ff237c501e095d4f3a09e58fc7b25a4aca"
43 | integrity sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==
44 |
45 | "@esbuild/linux-arm@0.16.17":
46 | version "0.16.17"
47 | resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz#b591e6a59d9c4fe0eeadd4874b157ab78cf5f196"
48 | integrity sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==
49 |
50 | "@esbuild/linux-ia32@0.16.17":
51 | version "0.16.17"
52 | resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz#24333a11027ef46a18f57019450a5188918e2a54"
53 | integrity sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==
54 |
55 | "@esbuild/linux-loong64@0.14.54":
56 | version "0.14.54"
57 | resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz#de2a4be678bd4d0d1ffbb86e6de779cde5999028"
58 | integrity sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==
59 |
60 | "@esbuild/linux-loong64@0.16.17":
61 | version "0.16.17"
62 | resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz#d5ad459d41ed42bbd4d005256b31882ec52227d8"
63 | integrity sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==
64 |
65 | "@esbuild/linux-mips64el@0.16.17":
66 | version "0.16.17"
67 | resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz#4e5967a665c38360b0a8205594377d4dcf9c3726"
68 | integrity sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==
69 |
70 | "@esbuild/linux-ppc64@0.16.17":
71 | version "0.16.17"
72 | resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz#206443a02eb568f9fdf0b438fbd47d26e735afc8"
73 | integrity sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==
74 |
75 | "@esbuild/linux-riscv64@0.16.17":
76 | version "0.16.17"
77 | resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz#c351e433d009bf256e798ad048152c8d76da2fc9"
78 | integrity sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==
79 |
80 | "@esbuild/linux-s390x@0.16.17":
81 | version "0.16.17"
82 | resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz#661f271e5d59615b84b6801d1c2123ad13d9bd87"
83 | integrity sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==
84 |
85 | "@esbuild/linux-x64@0.16.17":
86 | version "0.16.17"
87 | resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz"
88 | integrity sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==
89 |
90 | "@esbuild/netbsd-x64@0.16.17":
91 | version "0.16.17"
92 | resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz#7d4f4041e30c5c07dd24ffa295c73f06038ec775"
93 | integrity sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==
94 |
95 | "@esbuild/openbsd-x64@0.16.17":
96 | version "0.16.17"
97 | resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz#970fa7f8470681f3e6b1db0cc421a4af8060ec35"
98 | integrity sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==
99 |
100 | "@esbuild/sunos-x64@0.16.17":
101 | version "0.16.17"
102 | resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz#abc60e7c4abf8b89fb7a4fe69a1484132238022c"
103 | integrity sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==
104 |
105 | "@esbuild/win32-arm64@0.16.17":
106 | version "0.16.17"
107 | resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz#7b0ff9e8c3265537a7a7b1fd9a24e7bd39fcd87a"
108 | integrity sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==
109 |
110 | "@esbuild/win32-ia32@0.16.17":
111 | version "0.16.17"
112 | resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz#e90fe5267d71a7b7567afdc403dfd198c292eb09"
113 | integrity sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==
114 |
115 | "@esbuild/win32-x64@0.16.17":
116 | version "0.16.17"
117 | resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz#c5a1a4bfe1b57f0c3e61b29883525c6da3e5c091"
118 | integrity sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==
119 |
120 | "@pixi/accessibility@7.1.0":
121 | version "7.1.0"
122 | resolved "https://registry.npmjs.org/@pixi/accessibility/-/accessibility-7.1.0.tgz"
123 | integrity sha512-bbDW4LgMPtZPBTxa5uX/RASwKobfrr11/2c7haGFjTeESzwCkTTsEWdbNE3RRZYJVEKgkXCOyfZZVIunU1502w==
124 |
125 | "@pixi/app@7.1.0":
126 | version "7.1.0"
127 | resolved "https://registry.npmjs.org/@pixi/app/-/app-7.1.0.tgz"
128 | integrity sha512-9zuyNagKwOm7zYQHV35McgMIAtEnnMMhyhyvOAJ20xfiwUdAVRCYfQ3kOkAyvIpD1iA+9SGxOzzksY21Y9CF9A==
129 |
130 | "@pixi/assets@7.1.0":
131 | version "7.1.0"
132 | resolved "https://registry.npmjs.org/@pixi/assets/-/assets-7.1.0.tgz"
133 | integrity sha512-rwv8IsGSZjp6hqC7RZ7gxFsJssn+nSIJQcpXiCx9wFspS9b05IshNJ5VIzeHMEBzvEw53fCoYzejO2bf0VsBoA==
134 | dependencies:
135 | "@types/css-font-loading-module" "^0.0.7"
136 |
137 | "@pixi/compressed-textures@7.1.0":
138 | version "7.1.0"
139 | resolved "https://registry.npmjs.org/@pixi/compressed-textures/-/compressed-textures-7.1.0.tgz"
140 | integrity sha512-QfYetHnhrfyzNcHyXVeNvhjVNlJk0EbFNRg7Q9qJF6G9P78sFf7zB9rGq9T9bPuYQ8dEJndcwJVgGNfM9cF2Zw==
141 |
142 | "@pixi/constants@7.1.0":
143 | version "7.1.0"
144 | resolved "https://registry.npmjs.org/@pixi/constants/-/constants-7.1.0.tgz"
145 | integrity sha512-6HGMxhzNRyAYgjtTt9LFilqucBgl/Me6g1xEAYCt+8yMYYo2PVbI6Zxn160ggiwVYdOVROfL8HVdrsGxzy7ufA==
146 |
147 | "@pixi/core@7.1.0":
148 | version "7.1.0"
149 | resolved "https://registry.npmjs.org/@pixi/core/-/core-7.1.0.tgz"
150 | integrity sha512-r+tZdMYodBE0m9LCoCLz3UwxGAO2CW3+YEDt4vlsv7WmdKZVJhuYFUPTGAO49dzEL7bjS0qYVcUxvuUVXI/yww==
151 | dependencies:
152 | "@pixi/constants" "7.1.0"
153 | "@pixi/extensions" "7.1.0"
154 | "@pixi/math" "7.1.0"
155 | "@pixi/runner" "7.1.0"
156 | "@pixi/settings" "7.1.0"
157 | "@pixi/ticker" "7.1.0"
158 | "@pixi/utils" "7.1.0"
159 | "@types/offscreencanvas" "^2019.6.4"
160 |
161 | "@pixi/display@7.1.0":
162 | version "7.1.0"
163 | resolved "https://registry.npmjs.org/@pixi/display/-/display-7.1.0.tgz"
164 | integrity sha512-F9PCrjc7Z1uzkeeRahV/KihXEjvVA68veVPkwCgFTweWuu7quiIuaSAd1m5yCkcj4VjwyFlDoumqDejibYTrBg==
165 |
166 | "@pixi/events@7.1.0":
167 | version "7.1.0"
168 | resolved "https://registry.npmjs.org/@pixi/events/-/events-7.1.0.tgz"
169 | integrity sha512-AYevA+08Q8cw+ble0/Km7M1+EZ8JP+K0a+q4Hx6tRBTDTsn18OuwSP9vXW6/dAMEE3d8mcdquEjkoqOv5494QA==
170 |
171 | "@pixi/extensions@7.1.0":
172 | version "7.1.0"
173 | resolved "https://registry.npmjs.org/@pixi/extensions/-/extensions-7.1.0.tgz"
174 | integrity sha512-J2//MlKRAGZmaRgmSOuYGK1sTQjzv1rag8kIB96DjQb4SbkaLACZLN/QHbj+7Cf7ZcZ9XUMHzJU38V1epVPVGQ==
175 |
176 | "@pixi/extract@7.1.0":
177 | version "7.1.0"
178 | resolved "https://registry.npmjs.org/@pixi/extract/-/extract-7.1.0.tgz"
179 | integrity sha512-HTVQ9wKBZUb7AShUfnUkjPGrqVvFUuU4x1BIXKLtpkbMRjTkfgW/0d1PkhlQxanzMlCR/eOU43igzjB5zeVkZg==
180 |
181 | "@pixi/filter-alpha@7.1.0":
182 | version "7.1.0"
183 | resolved "https://registry.npmjs.org/@pixi/filter-alpha/-/filter-alpha-7.1.0.tgz"
184 | integrity sha512-tuCVvJXQRUXg8+DCKViOSobjRANYRlMEdfVOfrxmfve4nId1qJyw7VkEIpD3pOSOxHd8s0BZIkcLIMO+oOJu6w==
185 |
186 | "@pixi/filter-blur@7.1.0":
187 | version "7.1.0"
188 | resolved "https://registry.npmjs.org/@pixi/filter-blur/-/filter-blur-7.1.0.tgz"
189 | integrity sha512-JefcMjcQVngVNixvlYUnaFOiGdJqkfzWO90e0Cs7yqPHJpyzbdXtJbzWGTsnbYO8Q+q1j5pu7zYUbT5a3jUfaw==
190 |
191 | "@pixi/filter-color-matrix@7.1.0":
192 | version "7.1.0"
193 | resolved "https://registry.npmjs.org/@pixi/filter-color-matrix/-/filter-color-matrix-7.1.0.tgz"
194 | integrity sha512-IbdfIaV/sYWhHwGIRBNCo65n5Fi4GBzMpB5+dZBfarWjMOhO/MA43d49vLnTNNLrh2ZpjMuzc7IramRrUPLsyQ==
195 |
196 | "@pixi/filter-displacement@7.1.0":
197 | version "7.1.0"
198 | resolved "https://registry.npmjs.org/@pixi/filter-displacement/-/filter-displacement-7.1.0.tgz"
199 | integrity sha512-FNgDzkSqT3GzazBkITu+BXa+AVk5oxlgGKo/a0GsS7k7qNioS74o/p3U4ymARvDdQHdOxdP/SqIGxvJ45/7iGQ==
200 |
201 | "@pixi/filter-fxaa@7.1.0":
202 | version "7.1.0"
203 | resolved "https://registry.npmjs.org/@pixi/filter-fxaa/-/filter-fxaa-7.1.0.tgz"
204 | integrity sha512-tkqXJFKuRAi7gw32jIK2L0HTKDIOpPI8VWH4VnnC5bZf/7d1/y5b7WUcayxWUnyt10U8dicQrzsH9oZ9ESSpVA==
205 |
206 | "@pixi/filter-noise@7.1.0":
207 | version "7.1.0"
208 | resolved "https://registry.npmjs.org/@pixi/filter-noise/-/filter-noise-7.1.0.tgz"
209 | integrity sha512-i68BOZAxxSJ8/v2gWoKldKIQ6nwiCUlcK38Kh87b+3X4FXyBp98gW6ShzzpCpJ60BDVHDyEGGKYEReTVJbfMoQ==
210 |
211 | "@pixi/graphics@7.1.0":
212 | version "7.1.0"
213 | resolved "https://registry.npmjs.org/@pixi/graphics/-/graphics-7.1.0.tgz"
214 | integrity sha512-snZdUhlG0MFolMeR7codSGdGO7sFsciBrtiCuIU49zILZ7/TbC82Tv2GGZuseYI3TTkBdYfoLXlvHrzAk/g8Dw==
215 |
216 | "@pixi/math@7.1.0":
217 | version "7.1.0"
218 | resolved "https://registry.npmjs.org/@pixi/math/-/math-7.1.0.tgz"
219 | integrity sha512-du0H9egUtducS6WExFDRzoZM88DAHYSRMr2/PcEOpd2IEI6LvVCAonxFp0P1e7c62yMWYA1kAJV0qLlsiOCzzA==
220 |
221 | "@pixi/mesh-extras@7.1.0":
222 | version "7.1.0"
223 | resolved "https://registry.npmjs.org/@pixi/mesh-extras/-/mesh-extras-7.1.0.tgz"
224 | integrity sha512-P9zEsjTJFZlPI0eMazxl6WWY4HEGm81R4lYy3dfqQbIpj+7l8Av1FEAC24A6WKsI6+mA91GtJc+wc+TyTqtdYw==
225 |
226 | "@pixi/mesh@7.1.0":
227 | version "7.1.0"
228 | resolved "https://registry.npmjs.org/@pixi/mesh/-/mesh-7.1.0.tgz"
229 | integrity sha512-Kh6jKeL5kwYosZ3YQUSI+u8TyOLqrhx8BVKxiCHuQtDBM1EzwmfRbppNLzsz6TYnqgs9KwzgAJ2YU2qApiA+aA==
230 |
231 | "@pixi/mixin-cache-as-bitmap@7.1.0":
232 | version "7.1.0"
233 | resolved "https://registry.npmjs.org/@pixi/mixin-cache-as-bitmap/-/mixin-cache-as-bitmap-7.1.0.tgz"
234 | integrity sha512-MjjmICn62dPFS4Ut68iAZ8nh/ycJpivp1sxh2gLZnExVDslcSMhitoYZE4ESq57S//g5k2j3B0hTiURGTwkvgg==
235 |
236 | "@pixi/mixin-get-child-by-name@7.1.0":
237 | version "7.1.0"
238 | resolved "https://registry.npmjs.org/@pixi/mixin-get-child-by-name/-/mixin-get-child-by-name-7.1.0.tgz"
239 | integrity sha512-RHbQvh+xqE9Um1c9vKGf7czSjTgba0RdsIpkUWvlTIDX197yucmBmSxqt/gKHbgi4//AypJ6Zju/dvBDhNlwAQ==
240 |
241 | "@pixi/mixin-get-global-position@7.1.0":
242 | version "7.1.0"
243 | resolved "https://registry.npmjs.org/@pixi/mixin-get-global-position/-/mixin-get-global-position-7.1.0.tgz"
244 | integrity sha512-3MWUuccUQKf9eP2tp3HA46U+e7nav9JWVv8V3+SavfKADnnka1L3qnOlnk3EdPWbIEGc5JNguf84oLg2+sTBKw==
245 |
246 | "@pixi/particle-container@7.1.0":
247 | version "7.1.0"
248 | resolved "https://registry.npmjs.org/@pixi/particle-container/-/particle-container-7.1.0.tgz"
249 | integrity sha512-Mmz6eVDCMl3Cxttj06ozX1GYK7H0v8OD9i0/gHjdU89loQNNMKsSopgzeXTgmP37YPlElyLGqSYw4UX+Q8AAig==
250 |
251 | "@pixi/prepare@7.1.0":
252 | version "7.1.0"
253 | resolved "https://registry.npmjs.org/@pixi/prepare/-/prepare-7.1.0.tgz"
254 | integrity sha512-zmQcDe4dX/8HMXOtJRiDh0YaVpjamk/wvuOv0Xia7vs2GeUoxF3jXlnLyFzn0upMKbWbyvTblaKm/BX7u0cCKw==
255 |
256 | "@pixi/runner@7.1.0":
257 | version "7.1.0"
258 | resolved "https://registry.npmjs.org/@pixi/runner/-/runner-7.1.0.tgz"
259 | integrity sha512-Heuvu3zb+VGLUdwad2AE8w9HD1i3r1wbwTG/zuL0KrCa6SaEgV0Ro/GOE9HpCWppCylruToxEPsVKW/YJ1zL3w==
260 |
261 | "@pixi/settings@7.1.0":
262 | version "7.1.0"
263 | resolved "https://registry.npmjs.org/@pixi/settings/-/settings-7.1.0.tgz"
264 | integrity sha512-VnRI0R3vgglKZxbyA0lJVyS/qJHDEZlLYkVXb79CRF+wimaVgETtTLBpNaDxTMjwVwt2yqM1HvykvABuJ8YxNQ==
265 | dependencies:
266 | "@pixi/constants" "7.1.0"
267 | "@types/css-font-loading-module" "^0.0.7"
268 |
269 | "@pixi/sprite-animated@7.1.0":
270 | version "7.1.0"
271 | resolved "https://registry.npmjs.org/@pixi/sprite-animated/-/sprite-animated-7.1.0.tgz"
272 | integrity sha512-b6uQuW4H8MxLUQ95OOoAKshqqTiSyBDcSKJEzsn8n80P7/7zN9CokxFd9dCdEVGBdaUO3z69LZArBNaAROgn3g==
273 |
274 | "@pixi/sprite-tiling@7.1.0":
275 | version "7.1.0"
276 | resolved "https://registry.npmjs.org/@pixi/sprite-tiling/-/sprite-tiling-7.1.0.tgz"
277 | integrity sha512-MHM7hLnrYHC6m+4AFZ046uRMJ29nzNOdAGkQm3ZnsiwfHSJ5IVO2uF+5zScGiJMB4NJqK8enkE6Un7bfAChxpw==
278 |
279 | "@pixi/sprite@7.1.0":
280 | version "7.1.0"
281 | resolved "https://registry.npmjs.org/@pixi/sprite/-/sprite-7.1.0.tgz"
282 | integrity sha512-Nm9Aa/54OK+3T813OEHJdEjt/LTnktuCb+YUNpPf8WjNCGNiHGrfGS9YAj/F1PYtFpK006UPECE+bJCqjPw2ug==
283 |
284 | "@pixi/spritesheet@7.1.0":
285 | version "7.1.0"
286 | resolved "https://registry.npmjs.org/@pixi/spritesheet/-/spritesheet-7.1.0.tgz"
287 | integrity sha512-esbeVQ8G6QML0sDtdY9x9a0CFcRv4VAfuQkENZqbFrP3ZHbDODXy8WqbkMrukK4dxvfT0aCt1dMRQTMgLkxxwg==
288 |
289 | "@pixi/text-bitmap@7.1.0":
290 | version "7.1.0"
291 | resolved "https://registry.npmjs.org/@pixi/text-bitmap/-/text-bitmap-7.1.0.tgz"
292 | integrity sha512-2lYv6KbfE/3bXI9S8Pk73MVAJbu8sVx7cF5ldneXwNQYEXsy3+Abiq+1caOx9AXYoPtye03OFzFd5BR5Og7iHw==
293 |
294 | "@pixi/text@7.1.0":
295 | version "7.1.0"
296 | resolved "https://registry.npmjs.org/@pixi/text/-/text-7.1.0.tgz"
297 | integrity sha512-owcPLrvLMNRj4I8euXNwxE29f3FfIGg67ibZ/GO02lIR1HvVfNFYatNPt2xdpxdJM61+Qy5dH2m+dAh2w28YXA==
298 |
299 | "@pixi/ticker@7.1.0":
300 | version "7.1.0"
301 | resolved "https://registry.npmjs.org/@pixi/ticker/-/ticker-7.1.0.tgz"
302 | integrity sha512-P95JcTMsoqSJDFIp3v8ClhyFs/Eqv7/XbYxA6FuaHISFfX1I3xIywejqSvrtquQJZDyNED8QgGWR1xCZy0tBZw==
303 | dependencies:
304 | "@pixi/extensions" "7.1.0"
305 | "@pixi/settings" "7.1.0"
306 | "@pixi/utils" "7.1.0"
307 |
308 | "@pixi/utils@7.1.0":
309 | version "7.1.0"
310 | resolved "https://registry.npmjs.org/@pixi/utils/-/utils-7.1.0.tgz"
311 | integrity sha512-QPrugQvwR/Rw23TXAnLXIZwvto2f8/pgxIFvFOAVPBozBWBkibHuGevq7Jlcaybn95KafLfY9nFMbM0qRInWCg==
312 | dependencies:
313 | "@pixi/constants" "7.1.0"
314 | "@pixi/settings" "7.1.0"
315 | "@types/earcut" "^2.1.0"
316 | earcut "^2.2.4"
317 | eventemitter3 "^4.0.0"
318 | url "^0.11.0"
319 |
320 | "@teppeis/multimaps@^2.0.0":
321 | version "2.0.0"
322 | resolved "https://registry.npmjs.org/@teppeis/multimaps/-/multimaps-2.0.0.tgz"
323 | integrity sha512-TL1adzq1HdxUf9WYduLcQ/DNGYiz71U31QRgbnr0Ef1cPyOUOsBojxHVWpFeOSUucB6Lrs0LxFRA14ntgtkc9w==
324 |
325 | "@types/css-font-loading-module@^0.0.7":
326 | version "0.0.7"
327 | resolved "https://registry.npmjs.org/@types/css-font-loading-module/-/css-font-loading-module-0.0.7.tgz"
328 | integrity sha512-nl09VhutdjINdWyXxHWN/w9zlNCfr60JUqJbd24YXUuCwgeL0TpFSdElCwb6cxfB6ybE19Gjj4g0jsgkXxKv1Q==
329 |
330 | "@types/earcut@^2.1.0":
331 | version "2.1.1"
332 | resolved "https://registry.npmjs.org/@types/earcut/-/earcut-2.1.1.tgz"
333 | integrity sha512-w8oigUCDjElRHRRrMvn/spybSMyX8MTkKA5Dv+tS1IE/TgmNZPqUYtvYBXGY8cieSE66gm+szeK+bnbxC2xHTQ==
334 |
335 | "@types/offscreencanvas@^2019.6.4":
336 | version "2019.7.0"
337 | resolved "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz"
338 | integrity sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg==
339 |
340 | babylonjs@^5.42.0:
341 | version "5.42.0"
342 | resolved "https://registry.npmjs.org/babylonjs/-/babylonjs-5.42.0.tgz"
343 | integrity sha512-Ri/nJbS99NVmg2qTa7+EcL3QV2wzUxiavNmX6iqc3VJSmT5dPH4db9nqPQfN49UEV+ER1zuaJwrJ2bWlP1K+UA==
344 |
345 | core-js@^3.27.2:
346 | version "3.28.0"
347 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.28.0.tgz#ed8b9e99c273879fdfff0edfc77ee709a5800e4a"
348 | integrity sha512-GiZn9D4Z/rSYvTeg1ljAIsEqFm0LaN9gVtwDCrKL80zHtS31p9BAjmTxVqTQDMpwlMolJZOFntUG2uwyj7DAqw==
349 |
350 | earcut@2.2.4, earcut@^2.2.4:
351 | version "2.2.4"
352 | resolved "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz"
353 | integrity sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==
354 |
355 | esbuild-android-64@0.14.54:
356 | version "0.14.54"
357 | resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz#505f41832884313bbaffb27704b8bcaa2d8616be"
358 | integrity sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==
359 |
360 | esbuild-android-arm64@0.14.54:
361 | version "0.14.54"
362 | resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz#8ce69d7caba49646e009968fe5754a21a9871771"
363 | integrity sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==
364 |
365 | esbuild-darwin-64@0.14.54:
366 | version "0.14.54"
367 | resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz#24ba67b9a8cb890a3c08d9018f887cc221cdda25"
368 | integrity sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==
369 |
370 | esbuild-darwin-arm64@0.14.54:
371 | version "0.14.54"
372 | resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz#3f7cdb78888ee05e488d250a2bdaab1fa671bf73"
373 | integrity sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==
374 |
375 | esbuild-freebsd-64@0.14.54:
376 | version "0.14.54"
377 | resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz#09250f997a56ed4650f3e1979c905ffc40bbe94d"
378 | integrity sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==
379 |
380 | esbuild-freebsd-arm64@0.14.54:
381 | version "0.14.54"
382 | resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz#bafb46ed04fc5f97cbdb016d86947a79579f8e48"
383 | integrity sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==
384 |
385 | esbuild-linux-32@0.14.54:
386 | version "0.14.54"
387 | resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz#e2a8c4a8efdc355405325033fcebeb941f781fe5"
388 | integrity sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==
389 |
390 | esbuild-linux-64@0.14.54:
391 | version "0.14.54"
392 | resolved "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz"
393 | integrity sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==
394 |
395 | esbuild-linux-arm64@0.14.54:
396 | version "0.14.54"
397 | resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz#dae4cd42ae9787468b6a5c158da4c84e83b0ce8b"
398 | integrity sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==
399 |
400 | esbuild-linux-arm@0.14.54:
401 | version "0.14.54"
402 | resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz#a2c1dff6d0f21dbe8fc6998a122675533ddfcd59"
403 | integrity sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==
404 |
405 | esbuild-linux-mips64le@0.14.54:
406 | version "0.14.54"
407 | resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz#d9918e9e4cb972f8d6dae8e8655bf9ee131eda34"
408 | integrity sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==
409 |
410 | esbuild-linux-ppc64le@0.14.54:
411 | version "0.14.54"
412 | resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz#3f9a0f6d41073fb1a640680845c7de52995f137e"
413 | integrity sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==
414 |
415 | esbuild-linux-riscv64@0.14.54:
416 | version "0.14.54"
417 | resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz#618853c028178a61837bc799d2013d4695e451c8"
418 | integrity sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==
419 |
420 | esbuild-linux-s390x@0.14.54:
421 | version "0.14.54"
422 | resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz#d1885c4c5a76bbb5a0fe182e2c8c60eb9e29f2a6"
423 | integrity sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==
424 |
425 | esbuild-netbsd-64@0.14.54:
426 | version "0.14.54"
427 | resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz#69ae917a2ff241b7df1dbf22baf04bd330349e81"
428 | integrity sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==
429 |
430 | esbuild-openbsd-64@0.14.54:
431 | version "0.14.54"
432 | resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz#db4c8495287a350a6790de22edea247a57c5d47b"
433 | integrity sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==
434 |
435 | esbuild-sunos-64@0.14.54:
436 | version "0.14.54"
437 | resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz#54287ee3da73d3844b721c21bc80c1dc7e1bf7da"
438 | integrity sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==
439 |
440 | esbuild-windows-32@0.14.54:
441 | version "0.14.54"
442 | resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz#f8aaf9a5667630b40f0fb3aa37bf01bbd340ce31"
443 | integrity sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==
444 |
445 | esbuild-windows-64@0.14.54:
446 | version "0.14.54"
447 | resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz#bf54b51bd3e9b0f1886ffdb224a4176031ea0af4"
448 | integrity sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==
449 |
450 | esbuild-windows-arm64@0.14.54:
451 | version "0.14.54"
452 | resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz#937d15675a15e4b0e4fafdbaa3a01a776a2be982"
453 | integrity sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==
454 |
455 | esbuild@^0.14.27:
456 | version "0.14.54"
457 | resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.14.54.tgz"
458 | integrity sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==
459 | optionalDependencies:
460 | "@esbuild/linux-loong64" "0.14.54"
461 | esbuild-android-64 "0.14.54"
462 | esbuild-android-arm64 "0.14.54"
463 | esbuild-darwin-64 "0.14.54"
464 | esbuild-darwin-arm64 "0.14.54"
465 | esbuild-freebsd-64 "0.14.54"
466 | esbuild-freebsd-arm64 "0.14.54"
467 | esbuild-linux-32 "0.14.54"
468 | esbuild-linux-64 "0.14.54"
469 | esbuild-linux-arm "0.14.54"
470 | esbuild-linux-arm64 "0.14.54"
471 | esbuild-linux-mips64le "0.14.54"
472 | esbuild-linux-ppc64le "0.14.54"
473 | esbuild-linux-riscv64 "0.14.54"
474 | esbuild-linux-s390x "0.14.54"
475 | esbuild-netbsd-64 "0.14.54"
476 | esbuild-openbsd-64 "0.14.54"
477 | esbuild-sunos-64 "0.14.54"
478 | esbuild-windows-32 "0.14.54"
479 | esbuild-windows-64 "0.14.54"
480 | esbuild-windows-arm64 "0.14.54"
481 |
482 | esbuild@^0.16.3:
483 | version "0.16.17"
484 | resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz"
485 | integrity sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==
486 | optionalDependencies:
487 | "@esbuild/android-arm" "0.16.17"
488 | "@esbuild/android-arm64" "0.16.17"
489 | "@esbuild/android-x64" "0.16.17"
490 | "@esbuild/darwin-arm64" "0.16.17"
491 | "@esbuild/darwin-x64" "0.16.17"
492 | "@esbuild/freebsd-arm64" "0.16.17"
493 | "@esbuild/freebsd-x64" "0.16.17"
494 | "@esbuild/linux-arm" "0.16.17"
495 | "@esbuild/linux-arm64" "0.16.17"
496 | "@esbuild/linux-ia32" "0.16.17"
497 | "@esbuild/linux-loong64" "0.16.17"
498 | "@esbuild/linux-mips64el" "0.16.17"
499 | "@esbuild/linux-ppc64" "0.16.17"
500 | "@esbuild/linux-riscv64" "0.16.17"
501 | "@esbuild/linux-s390x" "0.16.17"
502 | "@esbuild/linux-x64" "0.16.17"
503 | "@esbuild/netbsd-x64" "0.16.17"
504 | "@esbuild/openbsd-x64" "0.16.17"
505 | "@esbuild/sunos-x64" "0.16.17"
506 | "@esbuild/win32-arm64" "0.16.17"
507 | "@esbuild/win32-ia32" "0.16.17"
508 | "@esbuild/win32-x64" "0.16.17"
509 |
510 | eventemitter3@^4.0.0, eventemitter3@^4.0.7:
511 | version "4.0.7"
512 | resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz"
513 | integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
514 |
515 | eventemitter3@^5.0.0:
516 | version "5.0.0"
517 | resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.0.tgz"
518 | integrity sha512-riuVbElZZNXLeLEoprfNYoDSwTBRR44X3mnhdI1YcnENpWTCsTTVZ2zFuqQcpoyqPQIUXdiPEU0ECAq0KQRaHg==
519 |
520 | excalibur@^0.30.3:
521 | version "0.30.3"
522 | resolved "https://registry.yarnpkg.com/excalibur/-/excalibur-0.30.3.tgz#e005ae22f85b64bddf6bb788b406e42d3a8a0946"
523 | integrity sha512-RUP3qQ6tFe9BJxvqh6p/I0B9rKMu+KGlHZruJyVOohiYUtCP0LsRgkVHxezvWtWsvCElVBL4PeCooE4KPlIldA==
524 |
525 | fpsmeter@^0.3.1:
526 | version "0.3.1"
527 | resolved "https://registry.npmjs.org/fpsmeter/-/fpsmeter-0.3.1.tgz"
528 | integrity sha512-i3zzNJwGkA+9WWIXpAtP0TCN64eO5VkKQgirYE7ZCVqyC3NfUPszU35R044fmSCjiMqefiBs5NiGKvD7lFJ87Q==
529 |
530 | fsevents@~2.3.2:
531 | version "2.3.2"
532 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
533 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
534 |
535 | function-bind@^1.1.1:
536 | version "1.1.1"
537 | resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
538 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
539 |
540 | handlebars@^4.7.6:
541 | version "4.7.7"
542 | resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz"
543 | integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==
544 | dependencies:
545 | minimist "^1.2.5"
546 | neo-async "^2.6.0"
547 | source-map "^0.6.1"
548 | wordwrap "^1.0.0"
549 | optionalDependencies:
550 | uglify-js "^3.1.4"
551 |
552 | has@^1.0.3:
553 | version "1.0.3"
554 | resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz"
555 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
556 | dependencies:
557 | function-bind "^1.1.1"
558 |
559 | hilojs@^2.0.2:
560 | version "2.0.2"
561 | resolved "https://registry.npmjs.org/hilojs/-/hilojs-2.0.2.tgz"
562 | integrity sha512-PgRuYHTnXMeT4cP/rnhWqFX3xVY0BJ6+mwqIQI19MzSJ2eqLNlt0JpF2EjRJNGhtaLFH3QsXLkYnRjb7W+HGuA==
563 |
564 | howler@2.2.3:
565 | version "2.2.3"
566 | resolved "https://registry.npmjs.org/howler/-/howler-2.2.3.tgz"
567 | integrity sha512-QM0FFkw0LRX1PR8pNzJVAY25JhIWvbKMBFM4gqk+QdV+kPXOhleWGCB6AiAF/goGjIHK2e/nIElplvjQwhr0jg==
568 |
569 | inherits@2.0.3:
570 | version "2.0.3"
571 | resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz"
572 | integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==
573 |
574 | is-core-module@^2.9.0:
575 | version "2.11.0"
576 | resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz"
577 | integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==
578 | dependencies:
579 | has "^1.0.3"
580 |
581 | kaboom@^2000.2.10:
582 | version "2000.2.10"
583 | resolved "https://registry.yarnpkg.com/kaboom/-/kaboom-2000.2.10.tgz#b8b6efa3f0e2d104e81dae5f3900f8f25d34a504"
584 | integrity sha512-OHWdRuRMNkTkpO0/1R4ljS4+vpPtf6PvN+S0WTe+PkPB6Z61rmunw4SKTQDkrCt7dDzEIZTnK1G6s7rttd61Bw==
585 |
586 | kaplay@^3001.0.12:
587 | version "3001.0.12"
588 | resolved "https://registry.yarnpkg.com/kaplay/-/kaplay-3001.0.12.tgz#ba1176b03ffbbc85301100af0815f3b7a81c94a6"
589 | integrity sha512-J4QOmQQRgSGg2qkiTwBTYdxGASlXGygIAZQhYIE2I5il5njOoFC7e1OTA5hEQZLjHajc/+lNhKYS8MLY4lgmyg==
590 |
591 | kontra@^8.0.0:
592 | version "8.0.0"
593 | resolved "https://registry.npmjs.org/kontra/-/kontra-8.0.0.tgz"
594 | integrity sha512-7Go/K4S+6gtyillSKSkSlNq46neuIWGvof9PYyzBwiBKGrs+1GHzsDknaeIID3GulV+sK1oKcV0hB2CyyO7ePQ==
595 |
596 | melonjs@^14.5.0:
597 | version "14.5.0"
598 | resolved "https://registry.yarnpkg.com/melonjs/-/melonjs-14.5.0.tgz#4a1393ef85ff12d18de6ac5d7fcaa60ecde2b5e0"
599 | integrity sha512-ePZp3Jm4GlsO242Kk9zSp4Y40yPLvAh8ZlouvitkqVmB7DyeXdvQ+0Q+7VoOEbuuCAnrHfmpS3V4QbSZs6NugQ==
600 | dependencies:
601 | "@teppeis/multimaps" "^2.0.0"
602 | core-js "^3.27.2"
603 | earcut "2.2.4"
604 | eventemitter3 "^5.0.0"
605 | howler "2.2.3"
606 |
607 | minimist@^1.2.5:
608 | version "1.2.7"
609 | resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz"
610 | integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==
611 |
612 | nanoid@^3.3.4:
613 | version "3.3.4"
614 | resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz"
615 | integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
616 |
617 | neo-async@^2.6.0:
618 | version "2.6.2"
619 | resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz"
620 | integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
621 |
622 | path-parse@^1.0.7:
623 | version "1.0.7"
624 | resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz"
625 | integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
626 |
627 | path@^0.12.7:
628 | version "0.12.7"
629 | resolved "https://registry.npmjs.org/path/-/path-0.12.7.tgz"
630 | integrity sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==
631 | dependencies:
632 | process "^0.11.1"
633 | util "^0.10.3"
634 |
635 | phaser@^3.55.2:
636 | version "3.55.2"
637 | resolved "https://registry.npmjs.org/phaser/-/phaser-3.55.2.tgz"
638 | integrity sha512-amKXsbb2Ht29dGPKvt1edq3yGGYKtq8373GpJYGKPNPnneYY6MtVTOgjHDuZwtmUyK4v86FugkT3hzW/N4tjxQ==
639 | dependencies:
640 | eventemitter3 "^4.0.7"
641 | path "^0.12.7"
642 |
643 | picocolors@^1.0.0:
644 | version "1.0.0"
645 | resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz"
646 | integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
647 |
648 | pixi.js@^7.1.0:
649 | version "7.1.0"
650 | resolved "https://registry.npmjs.org/pixi.js/-/pixi.js-7.1.0.tgz"
651 | integrity sha512-CNWikodkMhOThr8l5fWOLjvkmp2po8Gu3HpQFZnjJK3yukY7z8Nao6XnGlBZy7xq3GFrRTulbvrToAZqql7GRQ==
652 | dependencies:
653 | "@pixi/accessibility" "7.1.0"
654 | "@pixi/app" "7.1.0"
655 | "@pixi/assets" "7.1.0"
656 | "@pixi/compressed-textures" "7.1.0"
657 | "@pixi/core" "7.1.0"
658 | "@pixi/display" "7.1.0"
659 | "@pixi/events" "7.1.0"
660 | "@pixi/extensions" "7.1.0"
661 | "@pixi/extract" "7.1.0"
662 | "@pixi/filter-alpha" "7.1.0"
663 | "@pixi/filter-blur" "7.1.0"
664 | "@pixi/filter-color-matrix" "7.1.0"
665 | "@pixi/filter-displacement" "7.1.0"
666 | "@pixi/filter-fxaa" "7.1.0"
667 | "@pixi/filter-noise" "7.1.0"
668 | "@pixi/graphics" "7.1.0"
669 | "@pixi/mesh" "7.1.0"
670 | "@pixi/mesh-extras" "7.1.0"
671 | "@pixi/mixin-cache-as-bitmap" "7.1.0"
672 | "@pixi/mixin-get-child-by-name" "7.1.0"
673 | "@pixi/mixin-get-global-position" "7.1.0"
674 | "@pixi/particle-container" "7.1.0"
675 | "@pixi/prepare" "7.1.0"
676 | "@pixi/sprite" "7.1.0"
677 | "@pixi/sprite-animated" "7.1.0"
678 | "@pixi/sprite-tiling" "7.1.0"
679 | "@pixi/spritesheet" "7.1.0"
680 | "@pixi/text" "7.1.0"
681 | "@pixi/text-bitmap" "7.1.0"
682 |
683 | postcss@^8.4.13, postcss@^8.4.20:
684 | version "8.4.21"
685 | resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz"
686 | integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==
687 | dependencies:
688 | nanoid "^3.3.4"
689 | picocolors "^1.0.0"
690 | source-map-js "^1.0.2"
691 |
692 | process@^0.11.1:
693 | version "0.11.10"
694 | resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz"
695 | integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==
696 |
697 | punycode@1.3.2:
698 | version "1.3.2"
699 | resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz"
700 | integrity sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==
701 |
702 | querystring@0.2.0:
703 | version "0.2.0"
704 | resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz"
705 | integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==
706 |
707 | resolve@^1.22.0, resolve@^1.22.1:
708 | version "1.22.1"
709 | resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz"
710 | integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
711 | dependencies:
712 | is-core-module "^2.9.0"
713 | path-parse "^1.0.7"
714 | supports-preserve-symlinks-flag "^1.0.0"
715 |
716 | "rollup@>=2.59.0 <2.78.0":
717 | version "2.77.3"
718 | resolved "https://registry.npmjs.org/rollup/-/rollup-2.77.3.tgz"
719 | integrity sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==
720 | optionalDependencies:
721 | fsevents "~2.3.2"
722 |
723 | rollup@^3.7.0:
724 | version "3.10.0"
725 | resolved "https://registry.npmjs.org/rollup/-/rollup-3.10.0.tgz"
726 | integrity sha512-JmRYz44NjC1MjVF2VKxc0M1a97vn+cDxeqWmnwyAF4FvpjK8YFdHpaqvQB+3IxCvX05vJxKZkoMDU8TShhmJVA==
727 | optionalDependencies:
728 | fsevents "~2.3.2"
729 |
730 | source-map-js@^1.0.2:
731 | version "1.0.2"
732 | resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz"
733 | integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
734 |
735 | source-map@^0.6.1:
736 | version "0.6.1"
737 | resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
738 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
739 |
740 | supports-preserve-symlinks-flag@^1.0.0:
741 | version "1.0.0"
742 | resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz"
743 | integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
744 |
745 | three@^0.148.0:
746 | version "0.148.0"
747 | resolved "https://registry.npmjs.org/three/-/three-0.148.0.tgz"
748 | integrity sha512-8uzVV+qhTPi0bOFs/3te3RW6hb3urL8jYEl6irjCWo/l6sr8MPNMcClFev/MMYeIxr0gmDcoXTy/8LXh/LXkfw==
749 |
750 | two.js@^0.8.10:
751 | version "0.8.10"
752 | resolved "https://registry.yarnpkg.com/two.js/-/two.js-0.8.10.tgz#d01f8bb1c9401f850730a79abb9784b900ccde0b"
753 | integrity sha512-Rg0jn1n/0MWdDBrW47L245GWlWpbWlJ3Cv8xFlP05pSFqUT0Wn6w4yaOcxUCzAJQGRGdtmXOW3UI2W0LEEUD9Q==
754 |
755 | uglify-js@^3.1.4:
756 | version "3.17.4"
757 | resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz"
758 | integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==
759 |
760 | url@^0.11.0:
761 | version "0.11.0"
762 | resolved "https://registry.npmjs.org/url/-/url-0.11.0.tgz"
763 | integrity sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==
764 | dependencies:
765 | punycode "1.3.2"
766 | querystring "0.2.0"
767 |
768 | util@^0.10.3:
769 | version "0.10.4"
770 | resolved "https://registry.npmjs.org/util/-/util-0.10.4.tgz"
771 | integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==
772 | dependencies:
773 | inherits "2.0.3"
774 |
775 | vite-plugin-handlebars@^1.6.0:
776 | version "1.6.0"
777 | resolved "https://registry.npmjs.org/vite-plugin-handlebars/-/vite-plugin-handlebars-1.6.0.tgz"
778 | integrity sha512-/TZ2FadScvJW6fmQ+3m3stm6ns+tDZ3VAgzEkSQYQurAnaQ/3MJfidhmTXzD1Hu1iwgkI3lNuEqybzjjKemCTg==
779 | dependencies:
780 | handlebars "^4.7.6"
781 | vite "^2.0.0"
782 |
783 | vite@^2.0.0:
784 | version "2.9.15"
785 | resolved "https://registry.npmjs.org/vite/-/vite-2.9.15.tgz"
786 | integrity sha512-fzMt2jK4vQ3yK56te3Kqpkaeq9DkcZfBbzHwYpobasvgYmP2SoAr6Aic05CsB4CzCZbsDv4sujX3pkEGhLabVQ==
787 | dependencies:
788 | esbuild "^0.14.27"
789 | postcss "^8.4.13"
790 | resolve "^1.22.0"
791 | rollup ">=2.59.0 <2.78.0"
792 | optionalDependencies:
793 | fsevents "~2.3.2"
794 |
795 | vite@^4.0.0:
796 | version "4.0.4"
797 | resolved "https://registry.npmjs.org/vite/-/vite-4.0.4.tgz"
798 | integrity sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==
799 | dependencies:
800 | esbuild "^0.16.3"
801 | postcss "^8.4.20"
802 | resolve "^1.22.1"
803 | rollup "^3.7.0"
804 | optionalDependencies:
805 | fsevents "~2.3.2"
806 |
807 | wordwrap@^1.0.0:
808 | version "1.0.0"
809 | resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz"
810 | integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==
811 |
--------------------------------------------------------------------------------