littlejsengine 1.18.4 → 1.18.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/COPYRIGHT.txt +38 -0
  2. package/FAQ.md +633 -0
  3. package/README.md +19 -1
  4. package/dist/littlejs.d.ts +349 -54
  5. package/dist/littlejs.esm.js +1469 -448
  6. package/dist/littlejs.esm.min.js +1 -1
  7. package/dist/littlejs.js +1438 -436
  8. package/dist/littlejs.min.js +1 -1
  9. package/dist/littlejs.release.js +1438 -436
  10. package/package.json +8 -1
  11. package/plugins/box2d.js +32 -7
  12. package/{src/engineMedals.js → plugins/medalSystem.js} +248 -196
  13. package/plugins/pathFinder.js +758 -0
  14. package/plugins/pluginExport.js +19 -0
  15. package/plugins/tween.js +1 -1
  16. package/plugins/tweenSystem.js +509 -0
  17. package/plugins/uiSystem.js +150 -11
  18. package/src/engine.js +2 -141
  19. package/src/engineAudio.js +8 -5
  20. package/src/engineBuild.mjs +4 -2
  21. package/src/engineDebug.js +1 -1
  22. package/src/engineDraw.js +21 -3
  23. package/src/engineExport.js +12 -12
  24. package/src/engineInput.js +1 -1
  25. package/src/engineLogo.js +146 -0
  26. package/src/engineMath.js +10 -3
  27. package/src/engineObject.js +11 -5
  28. package/src/engineParticles.js +6 -3
  29. package/src/engineRelease.js +1 -1
  30. package/src/engineSettings.js +0 -47
  31. package/src/engineUtilities.js +7 -2
  32. package/src/engineWebGL.js +34 -7
  33. package/src/jsconfig.json +3 -1
  34. package/.github/workflows/test.yml +0 -17
  35. package/AI.md +0 -173
  36. package/CLAUDE.md +0 -1
  37. package/examples/box2d/game.js +0 -192
  38. package/examples/box2d/gameObjects.js +0 -564
  39. package/examples/box2d/index.html +0 -9
  40. package/examples/box2d/scenes.js +0 -194
  41. package/examples/box2d/tiles.png +0 -0
  42. package/examples/breakout/game.js +0 -175
  43. package/examples/breakout/gameObjects.js +0 -147
  44. package/examples/breakout/index.html +0 -8
  45. package/examples/breakout/tiles.png +0 -0
  46. package/examples/breakoutTutorial/README.md +0 -521
  47. package/examples/breakoutTutorial/game.js +0 -191
  48. package/examples/breakoutTutorial/images/1.png +0 -0
  49. package/examples/breakoutTutorial/images/10.png +0 -0
  50. package/examples/breakoutTutorial/images/11.png +0 -0
  51. package/examples/breakoutTutorial/images/2.png +0 -0
  52. package/examples/breakoutTutorial/images/3.png +0 -0
  53. package/examples/breakoutTutorial/images/4.png +0 -0
  54. package/examples/breakoutTutorial/images/5.png +0 -0
  55. package/examples/breakoutTutorial/images/6.png +0 -0
  56. package/examples/breakoutTutorial/images/7.png +0 -0
  57. package/examples/breakoutTutorial/images/8.png +0 -0
  58. package/examples/breakoutTutorial/images/9.png +0 -0
  59. package/examples/breakoutTutorial/index.html +0 -8
  60. package/examples/electron/build.mjs +0 -127
  61. package/examples/electron/electron.js +0 -35
  62. package/examples/electron/game.js +0 -54
  63. package/examples/electron/index.html +0 -13
  64. package/examples/electron/package.json +0 -5
  65. package/examples/electron/tiles.png +0 -0
  66. package/examples/empty/game.js +0 -51
  67. package/examples/empty/index.html +0 -5
  68. package/examples/empty/tiles.png +0 -0
  69. package/examples/favicon.png +0 -0
  70. package/examples/games.jpg +0 -0
  71. package/examples/htmlMenu/game.js +0 -82
  72. package/examples/htmlMenu/index.html +0 -45
  73. package/examples/htmlMenu/tiles.png +0 -0
  74. package/examples/index.html +0 -62
  75. package/examples/logo.png +0 -0
  76. package/examples/logo2.png +0 -0
  77. package/examples/module/build.mjs +0 -124
  78. package/examples/module/game.js +0 -132
  79. package/examples/module/index.html +0 -10
  80. package/examples/module/tiles.png +0 -0
  81. package/examples/particles/index.html +0 -426
  82. package/examples/particles/tiles.png +0 -0
  83. package/examples/platformer/data/gameLevelData.tmx +0 -143
  84. package/examples/platformer/data/gameLevelData.tsx +0 -4
  85. package/examples/platformer/game.js +0 -147
  86. package/examples/platformer/gameCharacter.js +0 -309
  87. package/examples/platformer/gameEffects.js +0 -278
  88. package/examples/platformer/gameLevel.js +0 -205
  89. package/examples/platformer/gameLevelData.json +0 -171
  90. package/examples/platformer/gameObjects.js +0 -378
  91. package/examples/platformer/gamePlayer.js +0 -35
  92. package/examples/platformer/index.html +0 -9
  93. package/examples/platformer/tiles.png +0 -0
  94. package/examples/platformer/tilesLevel.png +0 -0
  95. package/examples/puzzle/game.js +0 -331
  96. package/examples/puzzle/index.html +0 -8
  97. package/examples/puzzle/tiles.png +0 -0
  98. package/examples/screenshot.jpg +0 -0
  99. package/examples/shorts/animation.js +0 -18
  100. package/examples/shorts/base.html +0 -54
  101. package/examples/shorts/blending.js +0 -14
  102. package/examples/shorts/box2d.js +0 -51
  103. package/examples/shorts/box2dCar.js +0 -59
  104. package/examples/shorts/box2dPool.js +0 -107
  105. package/examples/shorts/box2dTileLayer.js +0 -48
  106. package/examples/shorts/cameraDrag.js +0 -22
  107. package/examples/shorts/clock.js +0 -21
  108. package/examples/shorts/colors.js +0 -25
  109. package/examples/shorts/debugDraw.js +0 -37
  110. package/examples/shorts/empty.js +0 -30
  111. package/examples/shorts/flappyGame.js +0 -55
  112. package/examples/shorts/fontImage.js +0 -17
  113. package/examples/shorts/fps.js +0 -90
  114. package/examples/shorts/helloWorld.js +0 -11
  115. package/examples/shorts/hillGlideGame.js +0 -63
  116. package/examples/shorts/input.js +0 -64
  117. package/examples/shorts/landerGame.js +0 -57
  118. package/examples/shorts/maze.js +0 -48
  119. package/examples/shorts/medals.js +0 -51
  120. package/examples/shorts/music.js +0 -78
  121. package/examples/shorts/musicPlayer.js +0 -137
  122. package/examples/shorts/nineSlice.js +0 -40
  123. package/examples/shorts/parallax.js +0 -72
  124. package/examples/shorts/particles.js +0 -28
  125. package/examples/shorts/piano.js +0 -44
  126. package/examples/shorts/platformer.js +0 -45
  127. package/examples/shorts/pongGame.js +0 -41
  128. package/examples/shorts/postProcess.js +0 -62
  129. package/examples/shorts/sequencer.js +0 -124
  130. package/examples/shorts/shader.js +0 -29
  131. package/examples/shorts/shapes.js +0 -21
  132. package/examples/shorts/slidingPuzzle.js +0 -52
  133. package/examples/shorts/song.mp3 +0 -0
  134. package/examples/shorts/sound.js +0 -36
  135. package/examples/shorts/spaceGame.js +0 -58
  136. package/examples/shorts/spriteAtlas.js +0 -31
  137. package/examples/shorts/starfield.js +0 -15
  138. package/examples/shorts/texture.js +0 -16
  139. package/examples/shorts/textureWrapped.js +0 -12
  140. package/examples/shorts/tileLayer.js +0 -48
  141. package/examples/shorts/tileRaycast.js +0 -39
  142. package/examples/shorts/tiles.png +0 -0
  143. package/examples/shorts/tiltedView.js +0 -63
  144. package/examples/shorts/timers.js +0 -53
  145. package/examples/shorts/topDown.js +0 -38
  146. package/examples/shorts/tween.js +0 -24
  147. package/examples/shorts/uiSystem.js +0 -61
  148. package/examples/shorts/video.webm +0 -0
  149. package/examples/shorts/videoPlayer.js +0 -34
  150. package/examples/shorts.js +0 -743
  151. package/examples/starter/build.bat +0 -7
  152. package/examples/starter/build.mjs +0 -126
  153. package/examples/starter/game.js +0 -137
  154. package/examples/starter/index.html +0 -35
  155. package/examples/starter/tiles.png +0 -0
  156. package/examples/stress/index.html +0 -173
  157. package/examples/style.css +0 -150
  158. package/examples/tweenSystem/game.js +0 -171
  159. package/examples/tweenSystem/index.html +0 -10
  160. package/examples/tweenSystem/tiles.png +0 -0
  161. package/examples/typescript/build.mjs +0 -60
  162. package/examples/typescript/game.js +0 -100
  163. package/examples/typescript/game.ts +0 -132
  164. package/examples/typescript/index.html +0 -10
  165. package/examples/typescript/tiles.png +0 -0
  166. package/examples/typescript/tsconfig.json +0 -17
  167. package/examples/uiSystem/game.js +0 -139
  168. package/examples/uiSystem/index.html +0 -10
  169. package/examples/uiSystem/tiles.png +0 -0
  170. package/jsconfig.json +0 -12
  171. package/plugins/desktop.ini +0 -2
  172. package/reference.md +0 -448
  173. package/test/math.test.mjs +0 -774
  174. package/test/setup.mjs +0 -22
  175. package/test/smoke.test.mjs +0 -274
  176. package/test/tween.test.mjs +0 -576
  177. package/test/util.test.mjs +0 -80
@@ -1,378 +0,0 @@
1
- /*
2
- LittleJS Platformer Example - Objects
3
- - Base GameObject class for objects with health
4
- - Crate object collides with player, can be destroyed
5
- - Weapon is held and fires bullets with some settings
6
- - Bullet is the projectile launched by a weapon
7
- */
8
-
9
- 'use strict';
10
-
11
- // import LittleJS module
12
- import * as LJS from '../../dist/littlejs.esm.js';
13
- import * as GameEffects from './gameEffects.js';
14
- import * as Game from './game.js';
15
- const {vec2, hsl, rgb, Timer} = LJS;
16
-
17
- export class GameObject extends LJS.EngineObject
18
- {
19
- constructor(pos, size, tileInfo, angle)
20
- {
21
- super(pos, size, tileInfo, angle);
22
- this.health = 0;
23
- this.isGameObject = 1;
24
- this.damageTimer = new Timer;
25
- }
26
-
27
- update()
28
- {
29
- // flash white when damaged
30
- let brightness = 0;
31
- if (!this.isDead() && this.damageTimer.isSet())
32
- brightness = .5*LJS.percent(this.damageTimer, .15, 0);
33
- this.additiveColor = hsl(0,0,brightness,0);
34
-
35
- // kill if below level
36
- if (!this.isDead() && this.pos.y < -9)
37
- this.kill();
38
- }
39
-
40
- damage(damage, damagingObject)
41
- {
42
- LJS.ASSERT(damage >= 0);
43
- if (this.isDead())
44
- return 0;
45
-
46
- // set damage timer;
47
- this.damageTimer.set();
48
- for (const child of this.children)
49
- child.damageTimer && child.damageTimer.set();
50
-
51
- // apply damage and kill if necessary
52
- const newHealth = LJS.max(this.health - damage, 0);
53
- if (!newHealth)
54
- this.kill(damagingObject);
55
-
56
- // set new health and return amount damaged
57
- return this.health - (this.health = newHealth);
58
- }
59
-
60
- isDead() { return !this.health; }
61
- kill(damagingObject) { this.destroy(); }
62
- }
63
-
64
- ///////////////////////////////////////////////////////////////////////////////
65
-
66
- export class Crate extends GameObject
67
- {
68
- constructor(pos)
69
- {
70
- super(pos, vec2(.999), Game.spriteAtlas.crate, (LJS.randInt(4))*LJS.PI/2);
71
-
72
- this.color = hsl(LJS.rand(),1,.8);
73
- this.health = 5;
74
-
75
- // make it a solid object for collision
76
- this.setCollision();
77
- }
78
-
79
- kill()
80
- {
81
- if (this.destroyed)
82
- return;
83
-
84
- GameEffects.sound_destroyObject.play(this.pos);
85
- GameEffects.makeDebris(this.pos, this.color, 30);
86
- this.destroy();
87
- }
88
- }
89
-
90
- ///////////////////////////////////////////////////////////////////////////////
91
-
92
- export class Coin extends LJS.EngineObject
93
- {
94
- constructor(pos)
95
- {
96
- super(pos, vec2(1), Game.spriteAtlas.coin);
97
- this.color = hsl(.15,1,.5);
98
- this.mass = 0;
99
- }
100
-
101
- render()
102
- {
103
- // side of coin
104
- LJS.drawTile(this.pos, vec2(.1, .6), 0, this.color);
105
-
106
- // make it appear to spin
107
- const t = LJS.time+this.pos.x/4+this.pos.y/4;
108
- const spinSize = vec2(.5+.5*LJS.sin(t*2*LJS.PI), 1);
109
- if (spinSize.x > .1)
110
- LJS.drawTile(this.pos, spinSize, this.tileInfo, this.color);
111
- }
112
-
113
- update()
114
- {
115
- if (!Game.player)
116
- return;
117
-
118
- // check if player in range
119
- const d = this.pos.distanceSquared(Game.player.pos);
120
- if (d > .5)
121
- return;
122
-
123
- // award points and destroy
124
- Game.addToScore();
125
- GameEffects.sound_score.play(this.pos);
126
- this.destroy();
127
- }
128
- }
129
-
130
- ///////////////////////////////////////////////////////////////////////////////
131
-
132
- export class Enemy extends GameObject
133
- {
134
- constructor(pos)
135
- {
136
- super(pos, vec2(.9,.9), Game.spriteAtlas.enemy);
137
-
138
- this.drawSize = vec2(1);
139
- this.color = hsl(LJS.rand(), 1, .7);
140
- this.health = 5;
141
- this.bounceTime = new Timer(LJS.rand(1e3));
142
- this.setCollision(true, false);
143
- }
144
-
145
- update()
146
- {
147
- super.update();
148
-
149
- if (!Game.player)
150
- return;
151
-
152
- // jump around randomly
153
- if (this.groundObject && LJS.rand() < .01 && this.pos.distance(Game.player.pos) < 20)
154
- this.velocity = vec2(LJS.rand(.1,-.1), LJS.rand(.4,.2));
155
-
156
- // damage player if touching
157
- if (this.isOverlappingObject(Game.player))
158
- Game.player.damage(1, this);
159
- }
160
-
161
- kill()
162
- {
163
- if (this.destroyed)
164
- return;
165
-
166
- Game.addToScore();
167
- GameEffects.sound_score.play(this.pos);
168
- GameEffects.makeDebris(this.pos, this.color);
169
- this.destroy();
170
- }
171
-
172
- render()
173
- {
174
- // bounce by changing size
175
- const bounceTime = this.bounceTime*6;
176
- this.drawSize = vec2(1-.1*LJS.sin(bounceTime), 1+.1*LJS.sin(bounceTime));
177
-
178
- // make bottom flush
179
- let bodyPos = this.pos;
180
- bodyPos = bodyPos.add(vec2(0,(this.drawSize.y-this.size.y)/2));
181
- LJS.drawTile(bodyPos, this.drawSize, this.tileInfo, this.color, this.angle, this.mirror, this.additiveColor);
182
- }
183
- }
184
-
185
- ///////////////////////////////////////////////////////////////////////////////
186
-
187
- export class Grenade extends GameObject
188
- {
189
- constructor(pos)
190
- {
191
- super(pos, vec2(.2), Game.spriteAtlas.grenade);
192
-
193
- this.beepTimer = new Timer(1);
194
- this.restitution = .3;
195
- this.friction = .9;
196
- this.angleDamping = .96;
197
- this.renderOrder = 1e8;
198
- this.setCollision(true,false);
199
- }
200
-
201
- update()
202
- {
203
- super.update();
204
-
205
- if (this.getAliveTime() > 3)
206
- {
207
- GameEffects.explosion(this.pos);
208
- this.destroy();
209
- }
210
- else if (this.beepTimer.elapsed())
211
- {
212
- GameEffects.sound_grenade.play(this.pos)
213
- this.beepTimer.set(1);
214
- }
215
- }
216
-
217
- render()
218
- {
219
- LJS.drawTile(this.pos, vec2(.5), this.tileInfo, this.color, this.angle);
220
-
221
- // draw additive flash exploding
222
- LJS.setBlendMode(true);
223
- const flash = LJS.cos(this.getAliveTime()*2*LJS.PI);
224
- LJS.drawTile(this.pos, vec2(2), Game.spriteAtlas.circle, hsl(0,1,.5,.2-.2*flash));
225
- LJS.setBlendMode(false);
226
- }
227
- }
228
-
229
- ///////////////////////////////////////////////////////////////////////////////
230
-
231
- export class Weapon extends LJS.EngineObject
232
- {
233
- constructor(pos)
234
- {
235
- super(pos, vec2(.6), Game.spriteAtlas.gun);
236
-
237
- // weapon settings
238
- this.fireRate = 8;
239
- this.bulletSpeed = .5;
240
- this.bulletSpread = .1;
241
- this.damage = 1;
242
-
243
- // prepare to fire
244
- this.fireTimeBuffer = this.localAngle = 0;
245
- this.recoilTimer = new Timer;
246
-
247
- // shell effect
248
- this.addChild(this.shellEmitter = new LJS.ParticleEmitter(
249
- vec2(), 0, 0, 0, 0, .1, // pos, angle, size, time, rate, cone
250
- 0, // tileInfo
251
- rgb(1,.8,.5), rgb(.9,.7,.5), // colorStartA, colorStartB
252
- rgb(1,.8,.5), rgb(.9,.7,.5), // colorEndA, colorEndB
253
- 3, .1, .1, .15, .1, // time, sizeStart, sizeEnd, speed, angleSpeed
254
- 1, .95, 1, 0, 0, // damp, angleDamp, gravity, particleCone, fade
255
- .1, 1 // randomness, collide
256
- ), vec2(.1,0), -.8);
257
- this.shellEmitter.restitution = .5;
258
- this.shellEmitter.particleDestroyCallback = GameEffects.persistentParticleDestroyCallback;
259
- }
260
-
261
- update()
262
- {
263
- // update recoil
264
- if (this.recoilTimer.active())
265
- this.localAngle = LJS.lerp(this.localAngle, 0, this.recoilTimer.getPercent());
266
-
267
- this.mirror = this.parent.mirror;
268
- this.fireTimeBuffer += LJS.timeDelta;
269
- if (this.triggerIsDown)
270
- {
271
- // try to fire
272
- for (; this.fireTimeBuffer > 0; this.fireTimeBuffer -= 1/this.fireRate)
273
- {
274
- // create bullet
275
- GameEffects.sound_shoot.play(this.pos);
276
- this.localAngle = -LJS.rand(.2,.25);
277
- this.recoilTimer.set(.1);
278
- const direction = vec2(this.bulletSpeed*this.getMirrorSign(), 0);
279
- const velocity = direction.rotate(LJS.rand(-1,1)*this.bulletSpread);
280
- new Bullet(this.pos, this.parent, velocity, this.damage);
281
-
282
- // spawn shell particle
283
- this.shellEmitter.emitParticle();
284
- }
285
- }
286
- else
287
- this.fireTimeBuffer = LJS.min(this.fireTimeBuffer, 0);
288
- }
289
- }
290
-
291
- ///////////////////////////////////////////////////////////////////////////////
292
-
293
- export class Bullet extends LJS.EngineObject
294
- {
295
- constructor(pos, attacker, velocity, damage)
296
- {
297
- super(pos, vec2());
298
- this.color = rgb(1,1,0);
299
- this.velocity = velocity;
300
- this.attacker = attacker;
301
- this.damage = damage;
302
- this.damping = 1;
303
- this.gravityScale = 0;
304
- this.renderOrder = 100;
305
- this.drawSize = vec2(.2,.5);
306
- this.range = 5;
307
- this.setCollision(1,0);
308
- }
309
-
310
- update()
311
- {
312
- // check if hit someone
313
- LJS.engineObjectsCallback(this.pos, this.size, (o)=>
314
- {
315
- if (o.isGameObject)
316
- this.collideWithObject(o)
317
- });
318
-
319
- this.angle = this.velocity.angle();
320
- this.range -= this.getSpeed();
321
- if (this.range < 0)
322
- {
323
- new LJS.ParticleEmitter(
324
- this.pos, 0, .2, .1, 50, 3.14, Game.spriteAtlas.circle, // pos, emit info, tileInfo
325
- rgb(1,1,.1), rgb(1,1,1), // colorStartA, colorStartB
326
- rgb(1,1,.1,0), rgb(1,1,1,0), // colorEndA, colorEndB
327
- .1, .5, .1, .05, 0, // particleTime, sizeStart, sizeEnd, speed, angleSpeed
328
- 1, 1, .5, 3.14, .1, // damping, angleDamping, gravityScale, cone, fadeRate,
329
- .5, 0, 1 // randomness, collide, additive, randomColorLinear
330
- );
331
-
332
- this.destroy();
333
- }
334
- }
335
-
336
- collideWithObject(o)
337
- {
338
- if (o.isGameObject && o != this.attacker)
339
- {
340
- o.damage(this.damage, this);
341
- o.applyForce(this.velocity.scale(.1));
342
- }
343
-
344
- this.kill();
345
- return true;
346
- }
347
-
348
- collideWithTile(data, pos)
349
- {
350
- if (data <= 0)
351
- return false;
352
-
353
- GameEffects.destroyTile(pos);
354
- this.kill();
355
- return true;
356
- }
357
-
358
- kill()
359
- {
360
- if (this.destroyed)
361
- return;
362
- this.destroy();
363
-
364
- // spark effects
365
- const emitter = new LJS.ParticleEmitter(
366
- this.pos, 0, 0, .1, 100, .5, // pos, angle, size, time, rate, cone
367
- 0, // tileInfo
368
- rgb(1,1,0), rgb(1,0,0), // colorStartA, colorStartB
369
- rgb(1,1,0), rgb(1,0,0), // colorEndA, colorEndB
370
- .2, .2, 0, .1, .1, // time, sizeStart, sizeEnd, speed, angleSpeed
371
- 1, 1, .5, 3.14, .1, // damp, angleDamp, gravityScale, particleCone, fade,
372
- .5, 1, 1 // randomness, collide, additive
373
- );
374
- emitter.trailScale = 1;
375
- emitter.restitution = .3;
376
- emitter.angle = this.velocity.angle() + LJS.PI;
377
- }
378
- }
@@ -1,35 +0,0 @@
1
- /*
2
- LittleJS Platformer Example - Player
3
- - Extends character class
4
- - Uses character physics system
5
- - Player can jump, shoot, roll, and throw grenades
6
- - Supports keyboard, mouse, and gamepad controls
7
- - Keeps track of player deaths
8
- */
9
-
10
- 'use strict';
11
-
12
- // import LittleJS module
13
- import * as LJS from '../../dist/littlejs.esm.js';
14
- import * as GameCharacter from './gameCharacter.js';
15
- import * as Game from './game.js';
16
-
17
- export class Player extends GameCharacter.Character
18
- {
19
- update()
20
- {
21
- // movement control
22
- this.moveInput = LJS.isUsingGamepad ? LJS.gamepadStick(0) : LJS.keyDirection();
23
- this.holdingJump = LJS.keyIsDown('ArrowUp') || LJS.gamepadIsDown(0);
24
- this.holdingShoot = !LJS.isUsingGamepad && LJS.mouseIsDown(0) || LJS.keyIsDown('KeyZ') || LJS.gamepadIsDown(2);
25
- this.pressingThrow = LJS.keyIsDown('KeyC') || LJS.mouseIsDown(1) || LJS.gamepadIsDown(1);
26
- this.pressedDodge = LJS.keyIsDown('KeyX') || LJS.mouseIsDown(2) || LJS.gamepadIsDown(3);
27
- super.update();
28
- }
29
-
30
- kill()
31
- {
32
- Game.addToDeaths();
33
- super.kill();
34
- }
35
- }
@@ -1,9 +0,0 @@
1
- <!DOCTYPE html><head>
2
- <title>LittleJS Platforming Game</title>
3
- <meta charset=utf-8>
4
- <meta name=viewport content=width=device-width,height=device-height,initial-scale=1,maximum-scale=1>
5
- <meta name=apple-mobile-web-app-capable content=yes>
6
- <meta name=mobile-web-app-capable content=yes>
7
- <link rel=icon type=image/png href=../favicon.png>
8
- </head><body>
9
- <script src=game.js type=module></script>
Binary file
Binary file