minimojs 1.0.0-alpha.2 → 1.0.0-alpha.21
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/README.md +82 -285
- package/dist/internal/AnimationSystem.js +345 -0
- package/dist/internal/AssetSystem.d.ts +1 -0
- package/dist/internal/AssetSystem.js +101 -0
- package/dist/internal/BackgroundSystem.d.ts +1 -0
- package/dist/internal/BackgroundSystem.js +26 -0
- package/dist/internal/CanvasSystem.d.ts +1 -0
- package/dist/internal/CanvasSystem.js +51 -0
- package/dist/internal/ExplosionSystem.d.ts +1 -0
- package/dist/internal/ExplosionSystem.js +540 -0
- package/dist/internal/InputSystem.d.ts +1 -0
- package/dist/internal/InputSystem.js +265 -0
- package/dist/internal/LoopSystem.d.ts +1 -0
- package/dist/internal/LoopSystem.js +61 -0
- package/dist/internal/PhysicsSystem.d.ts +1 -0
- package/dist/internal/PhysicsSystem.js +174 -0
- package/dist/internal/RenderSystem.d.ts +1 -0
- package/dist/internal/RenderSystem.js +910 -0
- package/dist/internal/SoundSystem.d.ts +1 -0
- package/dist/internal/SoundSystem.js +55 -0
- package/dist/internal/SpriteSystem.d.ts +1 -0
- package/dist/internal/SpriteSystem.js +32 -0
- package/dist/internal/TextSystem.d.ts +1 -0
- package/dist/internal/TextSystem.js +16 -0
- package/dist/internal/TimerSystem.d.ts +1 -0
- package/dist/internal/TimerSystem.js +43 -0
- package/dist/internal/TrailSystem.d.ts +1 -0
- package/dist/internal/TrailSystem.js +116 -0
- package/dist/internal/TransitionSystem.d.ts +1 -0
- package/dist/internal/TransitionSystem.js +74 -0
- package/dist/internal/arcade-racer/ArcadeRacerCollisionSystem.d.ts +1 -0
- package/dist/internal/arcade-racer/ArcadeRacerCollisionSystem.js +198 -0
- package/dist/internal/arcade-racer/ArcadeRacerLaneSystem.d.ts +1 -0
- package/dist/internal/arcade-racer/ArcadeRacerLaneSystem.js +120 -0
- package/dist/internal/arcade-racer/ArcadeRacerRenderSystem.d.ts +1 -0
- package/dist/internal/arcade-racer/ArcadeRacerRenderSystem.js +599 -0
- package/dist/internal/arcade-racer/ArcadeRacerRoadSprite.d.ts +1 -0
- package/dist/internal/arcade-racer/ArcadeRacerRoadSprite.js +13 -0
- package/dist/internal/arcade-racer/ArcadeRacerTrackSystem.d.ts +1 -0
- package/dist/internal/arcade-racer/ArcadeRacerTrackSystem.js +447 -0
- package/dist/minimo-arcaderacer.d.ts +1431 -0
- package/dist/minimo-arcaderacer.js +2060 -0
- package/dist/minimo.d.ts +1412 -162
- package/dist/minimo.js +2083 -816
- package/package.json +3 -2
- package/dist/animations.js +0 -30
- package/dist/audio.js +0 -17
- package/dist/game.js +0 -1105
- package/dist/input.js +0 -185
- package/dist/internal-types.js +0 -4
- package/dist/physics.js +0 -10
- package/dist/render.js +0 -75
- package/dist/sprite.js +0 -149
- package/dist/timers.js +0 -23
- /package/dist/{pointer-info.js → internal/AnimationSystem.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,333 +1,130 @@
|
|
|
1
1
|
# MinimoJS v1
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
> Emoji-only sprites · Degrees rotation · Milliseconds timing · rAF loop · TypeScript-first · LLM-friendly
|
|
3
|
+
Ultra-minimal, deterministic 2D web game engine for browser games.
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
MinimoJS focuses on a flat API, direct game-loop control, and fast iteration for small games and agent-generated prototypes.
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
This README is intentionally high-level. It explains what the project is and how to use it quickly, without listing the full API surface.
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
npm install minimojs
|
|
12
|
-
```
|
|
9
|
+
## What MinimoJS Is
|
|
13
10
|
|
|
14
|
-
|
|
11
|
+
- ESM-only TypeScript-first engine
|
|
12
|
+
- Single `Game` entry point
|
|
13
|
+
- Image-backed sprite rendering, with emoji as a zero-asset alternative
|
|
14
|
+
- rAF-driven loop (timers/animations/updates)
|
|
15
|
+
- Responsive auto-centered canvas
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
npm install
|
|
18
|
-
npm run build
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
Output: `dist/minimo.js` + `dist/minimo.d.ts`
|
|
17
|
+
## Core Conventions
|
|
22
18
|
|
|
23
|
-
|
|
19
|
+
- Time arguments are milliseconds (`ms`)
|
|
20
|
+
- Rotation uses degrees
|
|
21
|
+
- Runtime update delta (`dt`) is seconds
|
|
22
|
+
- Coordinate system is center-based world space
|
|
23
|
+
- Positive Y goes downward
|
|
24
|
+
- For new mobile-first games, prefer a portrait canvas of `720x1280`
|
|
24
25
|
|
|
25
|
-
##
|
|
26
|
+
## What It Intentionally Avoids
|
|
26
27
|
|
|
27
|
-
-
|
|
28
|
-
-
|
|
28
|
+
- Heavy scene-manager/ECS architecture
|
|
29
|
+
- Heavy physics engine features
|
|
30
|
+
- Spritesheets, texture atlases, and asset pipelines
|
|
31
|
+
- Nested subsystem APIs
|
|
32
|
+
- `setTimeout` / `setInterval` game loops
|
|
29
33
|
|
|
30
|
-
|
|
34
|
+
## Install
|
|
31
35
|
|
|
32
36
|
```bash
|
|
33
|
-
|
|
37
|
+
npm install minimojs
|
|
34
38
|
```
|
|
35
39
|
|
|
36
|
-
Open:
|
|
37
|
-
|
|
38
|
-
`http://localhost:3000/examples/chickens-eggs-basket/`
|
|
39
|
-
|
|
40
|
-
`http://localhost:3000/examples/run-dino-run/`
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
40
|
## Quick Start
|
|
45
41
|
|
|
46
|
-
```html
|
|
47
|
-
<script type="module">
|
|
48
|
-
import { Game, Sprite } from "./dist/minimo.js";
|
|
49
|
-
|
|
50
|
-
const game = new Game(800, 600);
|
|
51
|
-
game.gravityY = 980;
|
|
52
|
-
|
|
53
|
-
const player = new Sprite("🐢");
|
|
54
|
-
player.x = 400;
|
|
55
|
-
player.y = 300;
|
|
56
|
-
player.size = 48;
|
|
57
|
-
player.gravityScale = 1;
|
|
58
|
-
game.add(player);
|
|
59
|
-
|
|
60
|
-
game.onUpdate = (dt) => {
|
|
61
|
-
if (game.isKeyDown("ArrowLeft")) player.vx = -200;
|
|
62
|
-
else if (game.isKeyDown("ArrowRight")) player.vx = 200;
|
|
63
|
-
else player.vx = 0;
|
|
64
|
-
|
|
65
|
-
if (game.isKeyPressed(" ") && player.y >= 550) player.vy = -600;
|
|
66
|
-
|
|
67
|
-
if (player.y > 700) game.reset();
|
|
68
|
-
|
|
69
|
-
game.drawText(`x: ${Math.round(player.x)}`, 10, 10, 16, "#ffffff");
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
game.start();
|
|
73
|
-
</script>
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
---
|
|
77
|
-
|
|
78
|
-
## Core Rules
|
|
79
|
-
|
|
80
|
-
| Rule | Value |
|
|
81
|
-
|---|---|
|
|
82
|
-
| All time parameters | **milliseconds** |
|
|
83
|
-
| All rotations | **degrees** |
|
|
84
|
-
| Game loop | **requestAnimationFrame only** |
|
|
85
|
-
| Sprites | **emoji only** |
|
|
86
|
-
| Canvas layout | **auto-centered + responsive scaling** |
|
|
87
|
-
| Coordinate system | **center-based world space** |
|
|
88
|
-
| Y-axis | **positive = down** |
|
|
89
|
-
|
|
90
|
-
---
|
|
91
|
-
|
|
92
|
-
## API Reference
|
|
93
|
-
|
|
94
|
-
### `new Game(width?, height?)`
|
|
95
|
-
|
|
96
|
-
Creates the engine, creates its own canvas, and appends it to the page.
|
|
97
|
-
Canvas is automatically centered and scaled to the maximum viewport space
|
|
98
|
-
while keeping aspect ratio.
|
|
99
|
-
|
|
100
42
|
```ts
|
|
101
|
-
|
|
102
|
-
```
|
|
43
|
+
import { DrawSprite, EmojiSprite, Game, type IScene } from "minimojs";
|
|
103
44
|
|
|
104
|
-
|
|
45
|
+
const game = new Game(720, 1280);
|
|
46
|
+
game.gravityY = 980;
|
|
105
47
|
|
|
106
|
-
|
|
48
|
+
class MeterSprite extends DrawSprite {
|
|
49
|
+
public value = 0.5;
|
|
107
50
|
|
|
108
|
-
| Method | Description |
|
|
109
|
-
|---|---|
|
|
110
|
-
| `game.add(sprite)` | Register a Sprite instance with the engine and return it |
|
|
111
|
-
| `game.destroySprite(sprite)` | Remove a sprite from the engine |
|
|
112
|
-
| `game.getSprites()` | Read-only snapshot of all sprites |
|
|
113
|
-
|
|
114
|
-
**Creating sprites** — instantiate `Sprite` directly or subclass it:
|
|
115
|
-
|
|
116
|
-
```ts
|
|
117
|
-
// Plain instantiation
|
|
118
|
-
const coin = new Sprite("🪙");
|
|
119
|
-
coin.x = 300; coin.y = 200; coin.size = 32;
|
|
120
|
-
game.add(coin);
|
|
121
|
-
|
|
122
|
-
// Subclassing
|
|
123
|
-
class Enemy extends Sprite {
|
|
124
|
-
health = 3;
|
|
125
51
|
constructor(x: number, y: number) {
|
|
126
|
-
super(
|
|
127
|
-
this.x = x; this.y = y; this.size = 40; this.gravityScale = 1;
|
|
52
|
+
super(160, 28, x, y);
|
|
128
53
|
}
|
|
129
|
-
}
|
|
130
|
-
const enemy = game.add(new Enemy(600, 100));
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
**Sprite properties and defaults:**
|
|
134
|
-
|
|
135
|
-
| Property | Type | Default | Description |
|
|
136
|
-
|---|---|---|---|
|
|
137
|
-
| `sprite` | `string` | — | **Required in constructor.** Single emoji |
|
|
138
|
-
| `x` | `number` | `0` | World X (center), pixels |
|
|
139
|
-
| `y` | `number` | `0` | World Y (center), pixels |
|
|
140
|
-
| `size` | `number` | `32` | Bounding square size, pixels |
|
|
141
|
-
| `rotation` | `number` | `0` | Degrees, clockwise |
|
|
142
|
-
| `flipX` | `boolean` | `false` | Visual horizontal mirror |
|
|
143
|
-
| `flipY` | `boolean` | `false` | Visual vertical mirror |
|
|
144
|
-
| `ignoreScroll` | `boolean` | `false` | Render in screen space (ignore `scrollX`/`scrollY`) |
|
|
145
|
-
| `alpha` | `number` | `1` | Opacity 0–1 |
|
|
146
|
-
| `visible` | `boolean` | `true` | Render toggle |
|
|
147
|
-
| `layer` | `number` | `0` | Render order (higher = on top) |
|
|
148
|
-
| `vx` | `number` | `0` | Horizontal velocity, px/s |
|
|
149
|
-
| `vy` | `number` | `0` | Vertical velocity, px/s |
|
|
150
|
-
| `gravityScale` | `number` | `0` | Gravity multiplier |
|
|
151
|
-
|
|
152
|
-
---
|
|
153
|
-
|
|
154
|
-
### Public State
|
|
155
|
-
|
|
156
|
-
| Property | Type | Description |
|
|
157
|
-
|---|---|---|
|
|
158
|
-
| `game.gravityX` | `number` | Horizontal gravity acceleration, px/s² |
|
|
159
|
-
| `game.gravityY` | `number` | Vertical gravity acceleration, px/s² |
|
|
160
|
-
| `game.scrollX` | `number` | Camera scroll X offset, pixels |
|
|
161
|
-
| `game.scrollY` | `number` | Camera scroll Y offset, pixels |
|
|
162
|
-
| `game.background` | `string \| null` | Solid canvas background color |
|
|
163
|
-
| `game.backgroundGradient` | `{ from: string; to: string } \| null` | Vertical canvas gradient (`from` top, `to` bottom) |
|
|
164
|
-
| `game.pageBackground` | `string \| null` | Full page (`document.body`) background color |
|
|
165
|
-
| `game.pointerX` | `number` | Pointer X in screen space, pixels (read-only) |
|
|
166
|
-
| `game.pointerY` | `number` | Pointer Y in screen space, pixels (read-only) |
|
|
167
|
-
| `game.width` | `number` | Canvas width, pixels (read-only) |
|
|
168
|
-
| `game.height` | `number` | Canvas height, pixels (read-only) |
|
|
169
|
-
| `game.onCreate` | `() => void` | Scene creation callback (start + reset) |
|
|
170
|
-
| `game.onUpdate` | `(dt: number) => void` | Frame callback. `dt` = seconds |
|
|
171
|
-
|
|
172
|
-
---
|
|
173
|
-
|
|
174
|
-
### Background
|
|
175
|
-
|
|
176
|
-
```ts
|
|
177
|
-
game.background = "#92d7ff"; // solid canvas background
|
|
178
|
-
game.backgroundGradient = { from: "#92d7ff", to: "#5ca44f" }; // vertical gradient
|
|
179
|
-
game.pageBackground = "#f4e4bc"; // page background
|
|
180
|
-
// If backgroundGradient is set, it takes priority over background.
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
---
|
|
184
|
-
|
|
185
|
-
### Collision (AABB, no resolution)
|
|
186
54
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
---
|
|
195
|
-
|
|
196
|
-
### Input
|
|
197
|
-
|
|
198
|
-
```ts
|
|
199
|
-
// Keyboard
|
|
200
|
-
game.isKeyDown("ArrowRight") // true every frame while held
|
|
201
|
-
game.isKeyPressed("ArrowRight") // true only on first frame of press
|
|
202
|
-
|
|
203
|
-
// Pointer (mouse / touch)
|
|
204
|
-
game.isPointerDown() // true every frame while held
|
|
205
|
-
game.isPointerPressed() // true only on first frame of press
|
|
206
|
-
game.pointerX // screen space X
|
|
207
|
-
game.pointerY // screen space Y
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
---
|
|
211
|
-
|
|
212
|
-
### Sound
|
|
213
|
-
|
|
214
|
-
```ts
|
|
215
|
-
game.sound(freq, durationMs)
|
|
216
|
-
// Square wave only. freq in Hz. durationMs in milliseconds.
|
|
217
|
-
game.sound(440, 100); // 440 Hz beep for 100ms
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
---
|
|
55
|
+
redraw(ctx: CanvasRenderingContext2D) {
|
|
56
|
+
ctx.fillStyle = "#1a2236";
|
|
57
|
+
ctx.fillRect(0, 0, this.width, this.height);
|
|
58
|
+
ctx.fillStyle = "#7ce7ff";
|
|
59
|
+
ctx.fillRect(0, 0, this.width * this.value, this.height);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
221
62
|
|
|
222
|
-
|
|
63
|
+
class DemoScene implements IScene {
|
|
64
|
+
private player: EmojiSprite | null = null;
|
|
65
|
+
private meter: MeterSprite | null = null;
|
|
223
66
|
|
|
224
|
-
|
|
225
|
-
game.
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
---
|
|
67
|
+
onCreate() {
|
|
68
|
+
this.player = game.add(new EmojiSprite("🐢", 360, 640, 48));
|
|
69
|
+
this.player.gravityScale = 1;
|
|
70
|
+
this.meter = game.add(new MeterSprite(360, 80));
|
|
71
|
+
this.meter.ignoreScroll = true;
|
|
72
|
+
}
|
|
232
73
|
|
|
233
|
-
|
|
74
|
+
onUpdate(dt: number) {
|
|
75
|
+
if (!this.player) return;
|
|
234
76
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
// rAF-driven (no setTimeout). delayMs in milliseconds.
|
|
239
|
-
// repeat=true fires every delayMs; repeat=false fires once then removes.
|
|
240
|
-
// All timers cleared on game.reset().
|
|
241
|
-
```
|
|
77
|
+
if (game.isKeyDown("ArrowLeft")) this.player.vx = -200;
|
|
78
|
+
else if (game.isKeyDown("ArrowRight")) this.player.vx = 200;
|
|
79
|
+
else this.player.vx = 0;
|
|
242
80
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
81
|
+
if (game.isKeyPressed(" ")) this.player.vy = -600;
|
|
82
|
+
if (this.meter) this.meter.value = Math.abs(this.player.vx) / 200;
|
|
83
|
+
game.drawText("MinimoJS", 10, 10, 16);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
246
86
|
|
|
247
|
-
|
|
248
|
-
game.drawText(text, x, y, fontSize, color?, centered?)
|
|
249
|
-
// Screen space (ignores scroll). Must be called every frame.
|
|
250
|
-
// Always renders on top of all sprites.
|
|
251
|
-
// Font is always monospace (fixed by engine).
|
|
252
|
-
// Default color: "#ffffff"
|
|
253
|
-
// centered=true makes (x, y) the center anchor (both axes).
|
|
87
|
+
game.start(new DemoScene());
|
|
254
88
|
```
|
|
255
89
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
### Misc
|
|
90
|
+
Note: `drawText()` uses `"Press Start 2P", monospace`. Load the font in your HTML if you want pixel-font styling.
|
|
259
91
|
|
|
260
|
-
|
|
261
|
-
game.isMobileDevice() // true on likely mobile/touch-first devices (heuristic)
|
|
262
|
-
game.random() // Math.random() wrapper → [0, 1)
|
|
263
|
-
game.reset() // Full state clear + calls onCreate() for scene rebuild
|
|
264
|
-
game.start() // Start rAF loop
|
|
265
|
-
game.stop() // Stop rAF loop
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
---
|
|
92
|
+
## Examples
|
|
269
93
|
|
|
270
|
-
|
|
94
|
+
- `examples/chickens-eggs-basket/`
|
|
95
|
+
- `examples/run-dino-run/`
|
|
96
|
+
- `examples/space-invader/`
|
|
97
|
+
- `examples/super-minimo-bros/`
|
|
98
|
+
- `examples/scale-shift/`
|
|
99
|
+
- `examples/background-desert/`
|
|
100
|
+
- `examples/scene-lab/`
|
|
101
|
+
- `examples/image-sprite-sad-plush/`
|
|
102
|
+
- `examples/draw-sprite/`
|
|
103
|
+
- `examples/pseudo-3d-racer/`
|
|
104
|
+
- `examples/animations/`
|
|
271
105
|
|
|
272
|
-
|
|
106
|
+
Run locally from the `minimojs` directory:
|
|
273
107
|
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
// Scene init — called on start and after reset()
|
|
277
|
-
const skull = new Sprite("💀");
|
|
278
|
-
skull.x = 400; skull.y = 300; skull.size = 96;
|
|
279
|
-
game.add(skull);
|
|
280
|
-
};
|
|
281
|
-
|
|
282
|
-
function goToGameOver() {
|
|
283
|
-
game.reset(); // clears everything, calls onCreate()
|
|
284
|
-
}
|
|
108
|
+
```bash
|
|
109
|
+
npx serve .
|
|
285
110
|
```
|
|
286
111
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
## Forbidden Features
|
|
112
|
+
## Full API Reference
|
|
290
113
|
|
|
291
|
-
|
|
114
|
+
For complete API details, use source/docs generated from types:
|
|
292
115
|
|
|
293
|
-
-
|
|
294
|
-
-
|
|
295
|
-
- Physics engine
|
|
296
|
-
- Camera zoom
|
|
297
|
-
- Nested APIs
|
|
298
|
-
- Text input
|
|
299
|
-
- Parallax
|
|
300
|
-
- Multiple cameras
|
|
301
|
-
- Collision resolution
|
|
302
|
-
- Image sprites (PNG/SVG)
|
|
303
|
-
- `setTimeout` / `setInterval`
|
|
116
|
+
- `dist/minimo.d.ts`
|
|
117
|
+
- `src/minimo.ts` (JSDoc)
|
|
304
118
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
## Build
|
|
119
|
+
## Development
|
|
308
120
|
|
|
309
121
|
```bash
|
|
310
|
-
npm run build
|
|
311
|
-
npm run clean
|
|
312
|
-
npm run rebuild
|
|
313
|
-
npm run pack:check
|
|
122
|
+
npm run build
|
|
123
|
+
npm run clean
|
|
124
|
+
npm run rebuild
|
|
125
|
+
npm run pack:check
|
|
314
126
|
```
|
|
315
127
|
|
|
316
|
-
TypeScript target: **ES2020**, module: **ES2020**, strict mode, declaration files enabled.
|
|
317
|
-
|
|
318
|
-
---
|
|
319
|
-
|
|
320
|
-
## NPM Publish Notes
|
|
321
|
-
|
|
322
|
-
- `prepack` runs `npm run build` automatically before packaging.
|
|
323
|
-
- `files` whitelist includes only:
|
|
324
|
-
- `dist/`
|
|
325
|
-
- `README.md`
|
|
326
|
-
- `LICENSE`
|
|
327
|
-
- Example code under `examples/` is for repository usage and is excluded from the npm package.
|
|
328
|
-
|
|
329
|
-
---
|
|
330
|
-
|
|
331
128
|
## License
|
|
332
129
|
|
|
333
130
|
MIT
|