minimojs 1.0.0-alpha.2 → 1.0.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/minimo.d.ts CHANGED
@@ -22,10 +22,7 @@
22
22
  * @example
23
23
  * ```ts
24
24
  * // Direct instantiation
25
- * const coin = new Sprite("🪙");
26
- * coin.x = 300;
27
- * coin.y = 200;
28
- * coin.size = 32;
25
+ * const coin = new Sprite("🪙", 300, 200, 32);
29
26
  * game.add(coin);
30
27
  * ```
31
28
  *
@@ -36,10 +33,7 @@
36
33
  * health = 3;
37
34
  *
38
35
  * constructor(x: number, y: number) {
39
- * super("🐢");
40
- * this.x = x;
41
- * this.y = y;
42
- * this.size = 48;
36
+ * super("🐢", x, y, 48);
43
37
  * this.gravityScale = 1;
44
38
  * }
45
39
  * }
@@ -68,10 +62,47 @@ export declare class Sprite {
68
62
  */
69
63
  y: number;
70
64
  /**
71
- * Width and height of the sprite's bounding square, in pixels.
72
- * Used for both canvas rendering (font size) and AABB collision detection.
65
+ * Base width and height of this sprite in pixels.
66
+ *
67
+ * This value is read-only after construction and defines the glyph-cache
68
+ * render size. The visible and collision size during gameplay is exposed by
69
+ * {@link Sprite.displaySize}.
70
+ */
71
+ get size(): number;
72
+ /**
73
+ * Visual scale multiplier applied to {@link Sprite.size}.
74
+ * Default: `1`.
75
+ *
76
+ * Set this at runtime to resize a sprite without changing its base cached
77
+ * glyph size.
78
+ */
79
+ scale: number;
80
+ /**
81
+ * Effective rendered/collision size in pixels.
82
+ * Computed as `size * scale` with non-negative clamping.
73
83
  */
74
- size: number;
84
+ get displaySize(): number;
85
+ /**
86
+ * CSS text color used when rendering this sprite.
87
+ *
88
+ * This mainly affects monochrome glyphs and symbol-style sprites.
89
+ * Full-color emoji may ignore this and render with their native colors,
90
+ * depending on browser behavior.
91
+ */
92
+ color: string;
93
+ /**
94
+ * Physics body type flag.
95
+ *
96
+ * - `false` (default): the sprite is dynamic and can be moved by velocity,
97
+ * gravity, and explicit collision resolution.
98
+ * - `true`: the sprite is static and is not moved by the engine's built-in
99
+ * velocity/gravity integration. Static sprites act as stable obstacles for
100
+ * simple platform collisions.
101
+ *
102
+ * Static sprites can still be repositioned manually by setting `x` and `y`
103
+ * directly in your own game code.
104
+ */
105
+ isStatic: boolean;
75
106
  /**
76
107
  * Visual rotation of the sprite in degrees.
77
108
  * `0` = upright. Positive values rotate clockwise.
@@ -137,7 +168,7 @@ export declare class Sprite {
137
168
  */
138
169
  gravityScale: number;
139
170
  /**
140
- * Creates a new Sprite with the given emoji and optional position.
171
+ * Creates a new Sprite with the given emoji, optional position, and base size.
141
172
  * All other properties use their defaults and can be set after construction.
142
173
  *
143
174
  * @param sprite - The emoji character to render. Must be a single emoji.
@@ -145,15 +176,15 @@ export declare class Sprite {
145
176
  * @example "🔥", "⭐", "🐢", "💣", "👾"
146
177
  * @param x - Initial X position in world space (center), in pixels. Default: `0`.
147
178
  * @param y - Initial Y position in world space (center), in pixels. Default: `0`.
179
+ * @param size - Base sprite size in pixels. Default: `32`.
148
180
  *
149
181
  * @example
150
182
  * ```ts
151
- * const enemy = new Sprite("👾", 200, 100);
152
- * enemy.size = 40;
183
+ * const enemy = new Sprite("👾", 200, 100, 40);
153
184
  * game.add(enemy);
154
185
  * ```
155
186
  */
156
- constructor(sprite: string, x?: number, y?: number);
187
+ constructor(sprite: string, x?: number, y?: number, size?: number);
157
188
  }
158
189
  /**
159
190
  * Snapshot of an active pointer tracked by the engine.
@@ -181,6 +212,36 @@ export interface PointerInfo {
181
212
  */
182
213
  pressed: boolean;
183
214
  }
215
+ /**
216
+ * Information about a resolved AABB collision.
217
+ *
218
+ * Flags are reported relative to the **first** sprite passed to
219
+ * {@link Game.collide}. For example, `bottom = true` means the bottom side of
220
+ * the first sprite contacted the top side of the second sprite.
221
+ */
222
+ export interface CollisionInfo {
223
+ /**
224
+ * `true` when the first sprite's left side hit the second sprite.
225
+ */
226
+ left: boolean;
227
+ /**
228
+ * `true` when the first sprite's right side hit the second sprite.
229
+ */
230
+ right: boolean;
231
+ /**
232
+ * `true` when the first sprite's top side hit the second sprite from below.
233
+ */
234
+ top: boolean;
235
+ /**
236
+ * `true` when the first sprite's bottom side landed on the second sprite.
237
+ */
238
+ bottom: boolean;
239
+ /**
240
+ * Convenience flag for platformers.
241
+ * Equivalent to `bottom = true`.
242
+ */
243
+ grounded: boolean;
244
+ }
184
245
  /**
185
246
  * # MinimoJS v1 — AI Agent Integration Guide
186
247
  *
@@ -190,17 +251,63 @@ export interface PointerInfo {
190
251
  *
191
252
  * ---
192
253
  *
193
- * ## Quick Start
254
+ * ## ES Module Only
255
+ *
256
+ * MinimoJS is an **ES module only** package.
257
+ * You must import it with standard ESM syntax such as:
194
258
  *
195
259
  * ```ts
196
260
  * import { Game, Sprite } from "minimojs";
261
+ * ```
262
+ *
263
+ * In the browser, use it from a module script:
264
+ *
265
+ * ```html
266
+ * <script type="module">
267
+ * import { Game, Sprite } from "./dist/minimo.js";
268
+ * </script>
269
+ * ```
270
+ *
271
+ * Or from a CDN:
272
+ *
273
+ * ```ts
274
+ * import { Game, Sprite } from "https://cdn.jsdelivr.net/npm/minimojs@<version>/dist/minimo.js";
275
+ * ```
276
+ *
277
+ * Do NOT use a classic `<script>` tag without `type="module"`.
278
+ * Do NOT expect a global `window.MinimoJS`.
279
+ * Do NOT use `require("minimojs")` (CommonJS is not supported).
280
+ *
281
+ * ---
282
+ *
283
+ * ## Required Font Setup
284
+ *
285
+ * `drawText()` renders with `"Press Start 2P", monospace`.
286
+ * You MUST load `Press Start 2P` yourself in your `index.html` before starting
287
+ * the game. MinimoJS does NOT download, inject, or manage web fonts for you.
288
+ * If the font is missing, the browser falls back to `monospace`.
289
+ *
290
+ * Example `index.html` `<head>` setup:
291
+ *
292
+ * ```html
293
+ * <link rel="preconnect" href="https://fonts.googleapis.com" />
294
+ * <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
295
+ * <link
296
+ * href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap"
297
+ * rel="stylesheet"
298
+ * />
299
+ * ```
300
+ *
301
+ * ---
302
+ *
303
+ * ## Quick Start
304
+ *
305
+ * ```ts
306
+ * import { Game, Sprite } from "https://cdn.jsdelivr.net/npm/minimojs@<version>/dist/minimo.js";
197
307
  *
198
308
  * const game = new Game(800, 600);
199
309
  *
200
- * const player = new Sprite("🐢");
201
- * player.x = 400;
202
- * player.y = 500;
203
- * player.size = 48;
310
+ * const player = new Sprite("🐢", 400, 500, 48);
204
311
  * game.add(player);
205
312
  *
206
313
  * game.onUpdate = (dt) => {
@@ -227,7 +334,8 @@ export interface PointerInfo {
227
334
  * ## Flat API
228
335
  *
229
336
  * ALL engine functionality is on the `game` object.
230
- * Do not look for sub-objects like `game.physics`, `game.input`, etc. They do not exist.
337
+ * Do not look for nested subsystem objects like `game.input.keyboard`,
338
+ * `game.physics.world`, etc. They do not exist in MinimoJS v1.
231
339
  *
232
340
  * ---
233
341
  *
@@ -333,8 +441,7 @@ export interface PointerInfo {
333
441
  * ```ts
334
442
  * game.onCreate = () => {
335
443
  * // scene init: add sprites, setup timers
336
- * const skull = new Sprite("💀");
337
- * skull.x = 400; skull.y = 300; skull.size = 96;
444
+ * const skull = new Sprite("💀", 400, 300, 96);
338
445
  * game.add(skull);
339
446
  * };
340
447
  *
@@ -371,7 +478,7 @@ export interface PointerInfo {
371
478
  * - Text input / HTML form elements
372
479
  * - Parallax layers
373
480
  * - Multiple cameras
374
- * - Collision resolution (only detection is supported)
481
+ * - Full physics engine (only basic explicit AABB collision helpers are provided)
375
482
  * - Image sprites (PNG, SVG, canvas, etc.)
376
483
  * - `setTimeout` or `setInterval`
377
484
  */
@@ -401,6 +508,20 @@ export declare class Game {
401
508
  * ```
402
509
  */
403
510
  gravityY: number;
511
+ /**
512
+ * Enables the basic collision-resolution helpers (`collide` / `collideAny`).
513
+ *
514
+ * When `false` (default), overlap detection still works, but collision
515
+ * resolution helpers are unavailable.
516
+ *
517
+ * Set this to `true` for simple platformer-style collision handling.
518
+ *
519
+ * @example
520
+ * ```ts
521
+ * game.physics = true;
522
+ * ```
523
+ */
524
+ physics: boolean;
404
525
  /**
405
526
  * Horizontal scroll offset of the world camera, in pixels.
406
527
  * The canvas viewport is shifted left by `scrollX` — sprites with higher `x`
@@ -508,6 +629,7 @@ export declare class Game {
508
629
  * @example
509
630
  * ```ts
510
631
  * const game = new Game(800, 600);
632
+ * game.physics = true;
511
633
  * ```
512
634
  */
513
635
  constructor(width?: number, height?: number);
@@ -535,8 +657,9 @@ export declare class Game {
535
657
  get pointerY(): number;
536
658
  /**
537
659
  * Registers a {@link Sprite} (or subclass instance) with the engine.
538
- * After calling `add`, the sprite is rendered and receives physics updates
539
- * every frame until {@link Game.destroySprite} or {@link Game.reset} is called.
660
+ * After calling `add`, the sprite is rendered and, if dynamic
661
+ * (`isStatic = false`), receives built-in velocity/gravity integration every
662
+ * frame until {@link Game.destroySprite} or {@link Game.reset} is called.
540
663
  *
541
664
  * **Ownership:** The game instance takes ownership of the sprite from this
542
665
  * point forward. It will appear in {@link Game.getSprites} on the same frame.
@@ -551,16 +674,14 @@ export declare class Game {
551
674
  * @example
552
675
  * ```ts
553
676
  * // Plain sprite
554
- * const coin = new Sprite("🪙");
555
- * coin.x = 300; coin.y = 200; coin.size = 32;
677
+ * const coin = new Sprite("🪙", 300, 200, 32);
556
678
  * game.add(coin);
557
679
  *
558
680
  * // Custom subclass
559
681
  * class Enemy extends Sprite {
560
682
  * speed = 150;
561
683
  * constructor(x: number, y: number) {
562
- * super("👾");
563
- * this.x = x; this.y = y; this.size = 40;
684
+ * super("👾", x, y, 40);
564
685
  * }
565
686
  * }
566
687
  * const enemy = game.add(new Enemy(600, 100));
@@ -606,10 +727,10 @@ export declare class Game {
606
727
  * collision detection.
607
728
  *
608
729
  * Each sprite's bounding box is a square centered at `(x, y)` with side
609
- * length `size`. Rotation is **ignored** — the box is always axis-aligned.
730
+ * length `displaySize`. Rotation is **ignored** — the box is always axis-aligned.
610
731
  *
611
732
  * **No collision resolution is performed.** This method is detection-only.
612
- * If you need bounce or push-apart behavior, implement it in `onUpdate`.
733
+ * Use {@link Game.collide} for the engine's basic explicit push-out helper.
613
734
  *
614
735
  * @param a - First sprite.
615
736
  * @param b - Second sprite.
@@ -647,6 +768,57 @@ export declare class Game {
647
768
  * ```
648
769
  */
649
770
  overlapAny(listA: Sprite[], listB: Sprite[]): [Sprite, Sprite] | null;
771
+ /**
772
+ * Tests and resolves a basic AABB collision between two sprites.
773
+ *
774
+ * This helper is intended for simple platformer-style collision response.
775
+ * It uses the same axis-aligned square bounds as {@link Game.overlap}, but
776
+ * additionally pushes one sprite out of the collision and zeroes velocity on
777
+ * the resolved axis.
778
+ *
779
+ * **Resolution rules:**
780
+ * - If the first sprite is dynamic (`isStatic = false`), the first sprite is resolved.
781
+ * - Otherwise, if the second sprite is dynamic, the second sprite is resolved.
782
+ * - If both sprites are static, collision is reported but no movement occurs.
783
+ *
784
+ * The returned flags are always reported relative to the **first** sprite.
785
+ *
786
+ * @param a - First sprite. Usually the moving actor (for example, the player).
787
+ * @param b - Second sprite. Usually a static obstacle or platform.
788
+ * @returns Collision details, or `null` if the sprites do not overlap.
789
+ * @throws Error if the game's physics helpers are not enabled.
790
+ *
791
+ * @example
792
+ * ```ts
793
+ * const hit = game.collide(player, floorTile);
794
+ * if (hit?.grounded) {
795
+ * canJump = true;
796
+ * }
797
+ * ```
798
+ */
799
+ collide(a: Sprite, b: Sprite): CollisionInfo | null;
800
+ /**
801
+ * Tests and resolves the first collision found between two groups of sprites.
802
+ *
803
+ * This behaves like {@link Game.overlapAny}, but uses the explicit collision
804
+ * rules from {@link Game.collide} and returns the collision details as the
805
+ * third tuple item.
806
+ *
807
+ * @param listA - First group of sprites.
808
+ * @param listB - Second group of sprites.
809
+ * @returns A `[Sprite, Sprite, CollisionInfo]` tuple for the first collision found,
810
+ * or `null` if no pair overlaps.
811
+ * @throws Error if the game's physics helpers are not enabled.
812
+ *
813
+ * @example
814
+ * ```ts
815
+ * const hit = game.collideAny([player], floorTiles);
816
+ * if (hit?.[2].grounded) {
817
+ * canJump = true;
818
+ * }
819
+ * ```
820
+ */
821
+ collideAny(listA: Sprite[], listB: Sprite[]): [Sprite, Sprite, CollisionInfo] | null;
650
822
  /**
651
823
  * Returns `true` while the specified key is held down (every frame it is held).
652
824
  * Use this for continuous actions like movement.
@@ -716,14 +888,14 @@ export declare class Game {
716
888
  * Works with both mouse input and multiple simultaneous touches.
717
889
  *
718
890
  * Pointer hit testing uses a circular area centered on the sprite. The radius
719
- * is `sprite.size * radiusScale`. World-space sprites are tested against the
891
+ * is `sprite.displaySize * radiusScale`. World-space sprites are tested against the
720
892
  * current camera scroll. HUD sprites with `ignoreScroll = true` are tested in
721
893
  * screen space.
722
894
  *
723
895
  * Use this for continuous virtual buttons such as touch movement controls.
724
896
  *
725
897
  * @param sprite - Target sprite to test. If `null` / `undefined`, returns `false`.
726
- * @param radiusScale - Multiplier applied to `sprite.size` to define the hit radius.
898
+ * @param radiusScale - Multiplier applied to `sprite.displaySize` to define the hit radius.
727
899
  * Default: `0.5`.
728
900
  * @returns `true` if any currently held pointer overlaps the sprite hit area.
729
901
  *
@@ -740,14 +912,14 @@ export declare class Game {
740
912
  * sprite. Works with both mouse input and multiple simultaneous touches.
741
913
  *
742
914
  * Pointer hit testing uses a circular area centered on the sprite. The radius
743
- * is `sprite.size * radiusScale`. World-space sprites are tested against the
915
+ * is `sprite.displaySize * radiusScale`. World-space sprites are tested against the
744
916
  * current camera scroll. HUD sprites with `ignoreScroll = true` are tested in
745
917
  * screen space.
746
918
  *
747
919
  * Use this for one-shot virtual buttons such as menu taps.
748
920
  *
749
921
  * @param sprite - Target sprite to test. If `null` / `undefined`, returns `false`.
750
- * @param radiusScale - Multiplier applied to `sprite.size` to define the hit radius.
922
+ * @param radiusScale - Multiplier applied to `sprite.displaySize` to define the hit radius.
751
923
  * Default: `0.5`.
752
924
  * @returns `true` if any pointer began pressing this frame over the sprite hit area.
753
925
  *
@@ -776,7 +948,7 @@ export declare class Game {
776
948
  * const pointers = game.getPointers();
777
949
  * if (pointers.length > 0) {
778
950
  * const first = pointers[0];
779
- * game.text(`Pointer: ${first.x}, ${first.y}`, 10, 10);
951
+ * game.drawText(`Pointer: ${first.x}, ${first.y}`, 10, 10, 14);
780
952
  * }
781
953
  * ```
782
954
  */
@@ -786,7 +958,7 @@ export declare class Game {
786
958
  * the target sprite.
787
959
  *
788
960
  * Pointer hit testing uses a circular area centered on the sprite. The radius
789
- * is `sprite.size * radiusScale`. World-space sprites are tested against the
961
+ * is `sprite.displaySize * radiusScale`. World-space sprites are tested against the
790
962
  * current camera scroll. HUD sprites with `ignoreScroll = true` are tested in
791
963
  * screen space.
792
964
  *
@@ -794,7 +966,7 @@ export declare class Game {
794
966
  * pointer position over a virtual joystick or draggable control.
795
967
  *
796
968
  * @param sprite - Target sprite to test. If `null` / `undefined`, returns an empty array.
797
- * @param radiusScale - Multiplier applied to `sprite.size` to define the hit radius.
969
+ * @param radiusScale - Multiplier applied to `sprite.displaySize` to define the hit radius.
798
970
  * Default: `0.5`.
799
971
  * @returns A read-only array of active pointer snapshots currently over the sprite.
800
972
  *
@@ -954,8 +1126,11 @@ export declare class Game {
954
1126
  * The text overlay list is cleared after each render. Call this inside `onUpdate`.
955
1127
  *
956
1128
  * **Layer:** Text is always drawn on top of all sprites.
957
- * **Font:** Text always uses a fixed `monospace` font family.
958
- * Font family cannot be customized in MinimoJS v1.
1129
+ * **Font:** Text uses `"Press Start 2P", monospace`.
1130
+ * You MUST load `Press Start 2P` yourself in `index.html` (for example via
1131
+ * Google Fonts) before calling {@link Game.start}. MinimoJS does NOT load
1132
+ * external fonts for you. If the font is unavailable, the browser falls back
1133
+ * to `monospace`. Font family cannot be customized in MinimoJS v1.
959
1134
  *
960
1135
  * @param text - The string to render. Supports emoji and Unicode.
961
1136
  * @param x - X position in **screen space** (pixels from canvas left edge).
@@ -976,6 +1151,22 @@ export declare class Game {
976
1151
  * ```
977
1152
  */
978
1153
  drawText(text: string, x: number, y: number, fontSize: number, color?: string, centered?: boolean): void;
1154
+ /**
1155
+ * Clears the internal sprite glyph cache.
1156
+ *
1157
+ * MinimoJS prerenders sprite glyphs into offscreen canvases for more stable
1158
+ * emoji rendering and better performance. In long-running sessions, you can
1159
+ * call this to release cached glyph variants and force them to be rebuilt on
1160
+ * the next render.
1161
+ *
1162
+ * This does not change any sprite state. It only clears cached render data.
1163
+ *
1164
+ * @example
1165
+ * ```ts
1166
+ * game.clearSpriteCache();
1167
+ * ```
1168
+ */
1169
+ clearSpriteCache(): void;
979
1170
  /**
980
1171
  * Returns a pseudo-random floating-point number in the range `[0, 1)`.
981
1172
  * Delegates to `Math.random()`.
@@ -1024,8 +1215,7 @@ export declare class Game {
1024
1215
  *
1025
1216
  * game.onCreate = () => {
1026
1217
  * // Scene init
1027
- * const skull = new Sprite("💀");
1028
- * skull.x = 400; skull.y = 300; skull.size = 96;
1218
+ * const skull = new Sprite("💀", 400, 300, 96);
1029
1219
  * game.add(skull);
1030
1220
  * game.addTimer(3000, false, () => game.reset()); // auto-restart
1031
1221
  * };