frogjs 1.0.0-alpha.1
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 +448 -0
- package/dist/frog.d.ts +165 -0
- package/dist/frog.d.ts.map +1 -0
- package/dist/frog.js +522 -0
- package/dist/frog.js.map +1 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
# 🐸 FrogJS
|
|
2
|
+
|
|
3
|
+
A simple framework for making games with symbols, emojis, and any Unicode characters on a grid-based canvas.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Grid-based 2D canvas rendering with customizable background
|
|
8
|
+
- Simple sprite system with alpha/transparency, z-ordering, rotation, and custom colors
|
|
9
|
+
- Camera system with scrollX/scrollY (viewport scrolling)
|
|
10
|
+
- Fixed sprites for UI elements (ignore camera scroll)
|
|
11
|
+
- Built-in animations (fadeSprite, rotateSprite)
|
|
12
|
+
- Game loop-integrated timeout and timer system
|
|
13
|
+
- Keyboard input handling (arrow keys + space)
|
|
14
|
+
- Pointer/mouse input handling
|
|
15
|
+
- Easy-to-use API
|
|
16
|
+
- Automatic fullscreen canvas sizing
|
|
17
|
+
- Automatic sprite culling (off-screen sprites not rendered)
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
1. Install dependencies:
|
|
22
|
+
```bash
|
|
23
|
+
npm install
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
2. Build the framework:
|
|
27
|
+
```bash
|
|
28
|
+
npm run build
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
### Basic Setup
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
import { Game, Sprite } from './dist/frog.js';
|
|
37
|
+
|
|
38
|
+
// Create a game instance with default settings
|
|
39
|
+
const game = new Game();
|
|
40
|
+
|
|
41
|
+
// Or with custom configuration
|
|
42
|
+
const game = new Game({
|
|
43
|
+
gridWidth: 20,
|
|
44
|
+
gridHeight: 15,
|
|
45
|
+
background: '#001122', // Custom background color
|
|
46
|
+
showGrid: false, // Hide grid lines
|
|
47
|
+
container: document.getElementById('my-container') // optional
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Create and add sprites using Sprite class
|
|
51
|
+
// All properties are optional with sensible defaults
|
|
52
|
+
const player = new Sprite({ symbol: '🟢', x: 10, y: 7 });
|
|
53
|
+
game.addSprite(player);
|
|
54
|
+
|
|
55
|
+
// Specify only what you need
|
|
56
|
+
game.addSprite(new Sprite({ symbol: '🌲', x: 5, y: 5 }));
|
|
57
|
+
|
|
58
|
+
// With custom properties
|
|
59
|
+
const ghost = new Sprite({
|
|
60
|
+
symbol: '👻',
|
|
61
|
+
x: 8,
|
|
62
|
+
y: 8,
|
|
63
|
+
alpha: 0.5,
|
|
64
|
+
color: '#00ffff'
|
|
65
|
+
});
|
|
66
|
+
game.addSprite(ghost);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Note:** The framework automatically:
|
|
70
|
+
- Calculates the optimal cell size to fill the screen
|
|
71
|
+
- Creates a canvas sized to fit the grid
|
|
72
|
+
- Centers the canvas on the screen
|
|
73
|
+
- Handles window resizing (recalculates cell size and canvas dimensions)
|
|
74
|
+
- Uses crisp pixel rendering for sharp symbols
|
|
75
|
+
|
|
76
|
+
The cell size is computed dynamically based on your screen size and the grid dimensions, so the canvas always fills ~95% of the available space.
|
|
77
|
+
|
|
78
|
+
### API Reference
|
|
79
|
+
|
|
80
|
+
#### Creating Sprites
|
|
81
|
+
|
|
82
|
+
Use the `Sprite` class with a config object. All properties are optional with defaults.
|
|
83
|
+
|
|
84
|
+
```javascript
|
|
85
|
+
// Minimal sprite (only required properties)
|
|
86
|
+
const player = new Sprite({ symbol: '🟢', x: 10, y: 7 });
|
|
87
|
+
|
|
88
|
+
// With alpha
|
|
89
|
+
const ghost = new Sprite({ symbol: '👻', x: 5, y: 5, alpha: 0.5 });
|
|
90
|
+
|
|
91
|
+
// With z-order
|
|
92
|
+
const background = new Sprite({ symbol: '🌲', x: 3, y: 3, z: -1 }); // Behind
|
|
93
|
+
const foreground = new Sprite({ symbol: '⭐', x: 3, y: 3, z: 10 }); // In front
|
|
94
|
+
|
|
95
|
+
// With rotation angle (in degrees)
|
|
96
|
+
const rotatedArrow = new Sprite({ symbol: '➡️', x: 10, y: 10, angle: 45 });
|
|
97
|
+
|
|
98
|
+
// UI element (fixed to screen, ignores scroll)
|
|
99
|
+
const uiText = new Sprite({ symbol: '♥', x: 0, y: 0, z: 100, fixed: true });
|
|
100
|
+
|
|
101
|
+
// With custom color
|
|
102
|
+
const redText = new Sprite({ symbol: '!', x: 10, y: 10, color: '#ff0000' });
|
|
103
|
+
|
|
104
|
+
// All properties at once
|
|
105
|
+
const enemy = new Sprite({
|
|
106
|
+
symbol: '👾',
|
|
107
|
+
x: 15,
|
|
108
|
+
y: 5,
|
|
109
|
+
alpha: 1,
|
|
110
|
+
z: 0,
|
|
111
|
+
angle: 0,
|
|
112
|
+
fixed: false,
|
|
113
|
+
color: '#ffffff'
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Default values:
|
|
117
|
+
// - x: 0, y: 0
|
|
118
|
+
// - alpha: 1
|
|
119
|
+
// - z: 0
|
|
120
|
+
// - angle: 0
|
|
121
|
+
// - fixed: false
|
|
122
|
+
// - color: '#ffffff'
|
|
123
|
+
|
|
124
|
+
// Modify sprite properties
|
|
125
|
+
player.x = 5;
|
|
126
|
+
player.y = 3;
|
|
127
|
+
player.symbol = '🔴';
|
|
128
|
+
player.alpha = 0.8;
|
|
129
|
+
player.z = 5;
|
|
130
|
+
player.angle = 90;
|
|
131
|
+
player.fixed = false;
|
|
132
|
+
player.color = '#00ff00';
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
#### `addSprite(sprite)`
|
|
136
|
+
Add a sprite to the game.
|
|
137
|
+
|
|
138
|
+
```javascript
|
|
139
|
+
const s = new Sprite({ symbol: '💎', x: 8, y: 8 });
|
|
140
|
+
game.addSprite(s);
|
|
141
|
+
|
|
142
|
+
// Or in one line
|
|
143
|
+
game.addSprite(new Sprite({ symbol: '⭐', x: 5, y: 5 }));
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
#### `onUpdate`
|
|
147
|
+
Callback executed every frame (via requestAnimationFrame).
|
|
148
|
+
|
|
149
|
+
```javascript
|
|
150
|
+
game.onUpdate = () => {
|
|
151
|
+
// Your game logic here
|
|
152
|
+
if (game.isKeyDown('ArrowRight')) {
|
|
153
|
+
player.x++;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
#### Keyboard Input Methods
|
|
159
|
+
|
|
160
|
+
The framework supports arrow keys and space bar with dedicated methods:
|
|
161
|
+
|
|
162
|
+
```javascript
|
|
163
|
+
// Check if keys are pressed
|
|
164
|
+
game.isLeftKeyDown()
|
|
165
|
+
game.isRightKeyDown()
|
|
166
|
+
game.isUpKeyDown()
|
|
167
|
+
game.isDownKeyDown()
|
|
168
|
+
game.isSpaceKeyDown()
|
|
169
|
+
|
|
170
|
+
// Example usage
|
|
171
|
+
if (game.isUpKeyDown()) {
|
|
172
|
+
player.y--;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (game.isLeftKeyDown() && game.isSpaceKeyDown()) {
|
|
176
|
+
// Left arrow AND space pressed
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Check if NOT pressed
|
|
180
|
+
if (!game.isSpaceKeyDown()) {
|
|
181
|
+
// Space is not pressed
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
#### `onPointerDown(x, y)`
|
|
186
|
+
Callback executed when user clicks/touches down on the canvas.
|
|
187
|
+
|
|
188
|
+
```javascript
|
|
189
|
+
game.onPointerDown = (x, y) => {
|
|
190
|
+
console.log(`Clicked at grid position: ${x}, ${y}`);
|
|
191
|
+
game.makeSprite('⭐', x, y);
|
|
192
|
+
};
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
#### `onPointerUp(x, y)`
|
|
196
|
+
Callback executed when user releases click/touch on the canvas.
|
|
197
|
+
|
|
198
|
+
```javascript
|
|
199
|
+
game.onPointerUp = (x, y) => {
|
|
200
|
+
console.log(`Released at grid position: ${x}, ${y}`);
|
|
201
|
+
};
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
#### `fadeSprite(sprite, startAlpha, endAlpha, duration, callback)`
|
|
205
|
+
Animate a sprite's alpha from startAlpha to endAlpha.
|
|
206
|
+
|
|
207
|
+
```javascript
|
|
208
|
+
// Fade in (from transparent to opaque)
|
|
209
|
+
const ghost = new Sprite({ symbol: '👻', x: 5, y: 5, alpha: 0 });
|
|
210
|
+
game.addSprite(ghost);
|
|
211
|
+
game.fadeSprite(ghost, 0.0, 1.0, 1000);
|
|
212
|
+
|
|
213
|
+
// Fade out (from opaque to transparent)
|
|
214
|
+
const star = new Sprite({ symbol: '⭐', x: 8, y: 8 });
|
|
215
|
+
game.addSprite(star);
|
|
216
|
+
game.fadeSprite(star, 1.0, 0.0, 500, () => {
|
|
217
|
+
game.removeSprite(star);
|
|
218
|
+
console.log('Faded out and removed!');
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// Fade to half transparent
|
|
222
|
+
game.fadeSprite(player, 1.0, 0.5, 300);
|
|
223
|
+
|
|
224
|
+
// Pulse effect
|
|
225
|
+
function pulse(s) {
|
|
226
|
+
game.fadeSprite(s, 1.0, 0.3, 500, () => {
|
|
227
|
+
game.fadeSprite(s, 0.3, 1.0, 500, () => pulse(s));
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
pulse(powerup);
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
#### `rotateSprite(sprite, startAngle, endAngle, duration, callback)`
|
|
234
|
+
Animate a sprite's rotation from startAngle to endAngle (in degrees).
|
|
235
|
+
|
|
236
|
+
```javascript
|
|
237
|
+
const arrow = new Sprite({ symbol: '➡️', x: 10, y: 10 });
|
|
238
|
+
game.addSprite(arrow);
|
|
239
|
+
|
|
240
|
+
// Rotate from 0 to 90 degrees over 1 second
|
|
241
|
+
game.rotateSprite(arrow, 0, 90, 1000);
|
|
242
|
+
|
|
243
|
+
// Spin 360 degrees with callback
|
|
244
|
+
game.rotateSprite(arrow, 0, 360, 2000, () => {
|
|
245
|
+
console.log('Full rotation complete!');
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// Continuous spinning using callback
|
|
249
|
+
function spinContinuous() {
|
|
250
|
+
game.rotateSprite(arrow, 0, 360, 1000, spinContinuous);
|
|
251
|
+
}
|
|
252
|
+
spinContinuous();
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
#### `timeout(delay, callback)`
|
|
256
|
+
Execute a callback after a delay (in milliseconds). Integrated with the game loop.
|
|
257
|
+
|
|
258
|
+
```javascript
|
|
259
|
+
// Execute after 1 second
|
|
260
|
+
game.timeout(1000, () => {
|
|
261
|
+
console.log('One second has passed!');
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// Spawn enemy after 2 seconds
|
|
265
|
+
game.timeout(2000, () => {
|
|
266
|
+
const enemy = new Sprite({ symbol: '👾', x: 10, y: 5 });
|
|
267
|
+
game.addSprite(enemy);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// Chain multiple timeouts
|
|
271
|
+
game.timeout(1000, () => {
|
|
272
|
+
console.log('First');
|
|
273
|
+
game.timeout(1000, () => {
|
|
274
|
+
console.log('Second');
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
#### `timer(delay, callback, times?)`
|
|
280
|
+
Execute a callback repeatedly at specified intervals. Returns a Timer object.
|
|
281
|
+
|
|
282
|
+
```javascript
|
|
283
|
+
// Execute every second, infinitely
|
|
284
|
+
const infiniteTimer = game.timer(1000, () => {
|
|
285
|
+
console.log('Tick!');
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
// Execute 5 times, then stop automatically
|
|
289
|
+
const limitedTimer = game.timer(1000, () => {
|
|
290
|
+
console.log('Limited tick!');
|
|
291
|
+
}, 5);
|
|
292
|
+
|
|
293
|
+
// Spawn enemy every 3 seconds
|
|
294
|
+
const enemySpawner = game.timer(3000, () => {
|
|
295
|
+
const enemy = new Sprite({ symbol: '👾', x: Math.floor(Math.random() * 20), y: 0 });
|
|
296
|
+
game.addSprite(enemy);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
// Stop a timer
|
|
300
|
+
game.stopTimer(enemySpawner);
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
#### `stopTimer(timer)`
|
|
304
|
+
Stop a running timer.
|
|
305
|
+
|
|
306
|
+
```javascript
|
|
307
|
+
const myTimer = game.timer(1000, () => {
|
|
308
|
+
console.log('Running...');
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// Stop after 5 seconds
|
|
312
|
+
game.timeout(5000, () => {
|
|
313
|
+
game.stopTimer(myTimer);
|
|
314
|
+
console.log('Timer stopped!');
|
|
315
|
+
});
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
#### Sprite Rotation Examples
|
|
319
|
+
|
|
320
|
+
```javascript
|
|
321
|
+
// Static rotation
|
|
322
|
+
const arrow = new Sprite({ symbol: '➡️', x: 10, y: 5, angle: 90 }); // Point down
|
|
323
|
+
game.addSprite(arrow);
|
|
324
|
+
|
|
325
|
+
// Animate rotation in game loop
|
|
326
|
+
const spinner = new Sprite({ symbol: '🔄', x: 5, y: 5 });
|
|
327
|
+
game.addSprite(spinner);
|
|
328
|
+
|
|
329
|
+
game.onUpdate = () => {
|
|
330
|
+
spinner.angle += 5; // Rotate 5 degrees per frame
|
|
331
|
+
if (spinner.angle >= 360) spinner.angle = 0;
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
// Rotate towards target
|
|
335
|
+
function rotateTowards(s, targetX, targetY) {
|
|
336
|
+
const dx = targetX - s.x;
|
|
337
|
+
const dy = targetY - s.y;
|
|
338
|
+
s.angle = Math.atan2(dy, dx) * (180 / Math.PI);
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
#### Fixed Sprites (UI Elements)
|
|
343
|
+
|
|
344
|
+
Create sprites that stay fixed on screen regardless of scroll (perfect for HUD/UI).
|
|
345
|
+
|
|
346
|
+
```javascript
|
|
347
|
+
// Health display that doesn't scroll
|
|
348
|
+
const heart = new Sprite({ symbol: '♥', x: 0, y: 0, z: 100, fixed: true });
|
|
349
|
+
game.addSprite(heart);
|
|
350
|
+
|
|
351
|
+
// Score counter
|
|
352
|
+
const scoreSprites = [];
|
|
353
|
+
const scoreText = 'SCORE:1000';
|
|
354
|
+
for (let i = 0; i < scoreText.length; i++) {
|
|
355
|
+
const s = new Sprite({ symbol: scoreText[i], x: i, y: 0, z: 100, fixed: true });
|
|
356
|
+
game.addSprite(s);
|
|
357
|
+
scoreSprites.push(s);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Fixed sprites use screen coordinates, not world coordinates
|
|
361
|
+
// Position (0, 0) is always top-left of screen, even when scrolled
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
#### Camera / Scroll
|
|
365
|
+
|
|
366
|
+
Control the viewport with `scrollX` and `scrollY` (in grid units).
|
|
367
|
+
|
|
368
|
+
```javascript
|
|
369
|
+
// Scroll the camera right 5 cells
|
|
370
|
+
game.scrollX = 5;
|
|
371
|
+
|
|
372
|
+
// Scroll down 3 cells
|
|
373
|
+
game.scrollY = 3;
|
|
374
|
+
|
|
375
|
+
// Follow the player (immediate)
|
|
376
|
+
game.onUpdate = () => {
|
|
377
|
+
// Center camera on player
|
|
378
|
+
game.scrollX = player.x - 10; // 10 = half of grid width (20)
|
|
379
|
+
game.scrollY = player.y - 7; // 7 = half of grid height (15)
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
// Smooth camera follow (optional - you can implement this yourself)
|
|
383
|
+
game.onUpdate = () => {
|
|
384
|
+
const targetScrollX = player.x - 10;
|
|
385
|
+
const targetScrollY = player.y - 7;
|
|
386
|
+
|
|
387
|
+
// Lerp towards target for smooth effect
|
|
388
|
+
game.scrollX += (targetScrollX - game.scrollX) * 0.1;
|
|
389
|
+
game.scrollY += (targetScrollY - game.scrollY) * 0.1;
|
|
390
|
+
};
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
**Note:**
|
|
394
|
+
- The engine's scroll is **immediate** (no built-in smoothing)
|
|
395
|
+
- You can add smooth scrolling yourself using lerp/interpolation (see example above)
|
|
396
|
+
- Sprites outside the visible grid (accounting for scroll) are automatically culled (not rendered)
|
|
397
|
+
- Pointer coordinates (onPointerDown/onPointerUp) are automatically converted to world coordinates
|
|
398
|
+
|
|
399
|
+
#### Additional Methods
|
|
400
|
+
|
|
401
|
+
```javascript
|
|
402
|
+
// Get the sprite at a specific grid cell
|
|
403
|
+
const sprite = game.getSprite(5, 10);
|
|
404
|
+
if (sprite) {
|
|
405
|
+
console.log(`Found sprite: ${sprite.symbol}`);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Get all sprites at a specific grid cell
|
|
409
|
+
const sprites = game.getAllSprites(5, 10);
|
|
410
|
+
for (const sprite of sprites) {
|
|
411
|
+
console.log(`Found: ${sprite.symbol}`);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Remove a specific sprite
|
|
415
|
+
game.removeSprite(player);
|
|
416
|
+
|
|
417
|
+
// Clear all sprites
|
|
418
|
+
game.clearSprites();
|
|
419
|
+
|
|
420
|
+
// Show or hide the grid
|
|
421
|
+
game.setShowGrid(false); // hide grid
|
|
422
|
+
game.setShowGrid(true); // show grid
|
|
423
|
+
|
|
424
|
+
// Clean up when done
|
|
425
|
+
game.destroy();
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
## Examples
|
|
429
|
+
|
|
430
|
+
The framework includes example files in the `examples/` folder:
|
|
431
|
+
|
|
432
|
+
### `examples/basic.html`
|
|
433
|
+
A complete game with star collection mechanics, collision detection, and fade animations.
|
|
434
|
+
|
|
435
|
+
### `examples/minimal.html`
|
|
436
|
+
A minimal setup showing the simplest way to use the framework (just HTML + one script tag).
|
|
437
|
+
|
|
438
|
+
### `examples/pacman.html`
|
|
439
|
+
A Pac-Man style maze game with ghost AI, score tracking, and win/lose conditions.
|
|
440
|
+
|
|
441
|
+
To run any example:
|
|
442
|
+
|
|
443
|
+
1. Build the framework: `npm run build`
|
|
444
|
+
2. Open the example HTML file in a web browser
|
|
445
|
+
|
|
446
|
+
## License
|
|
447
|
+
|
|
448
|
+
MIT
|
package/dist/frog.d.ts
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FrogJS - A simple framework for making games with symbols/emojis on a grid
|
|
3
|
+
*/
|
|
4
|
+
export interface ISprite {
|
|
5
|
+
/** The character/emoji to display */
|
|
6
|
+
symbol: string;
|
|
7
|
+
/** Grid x position */
|
|
8
|
+
x: number;
|
|
9
|
+
/** Grid y position */
|
|
10
|
+
y: number;
|
|
11
|
+
/** Transparency (0.0 = invisible, 1.0 = opaque). Default: 1 */
|
|
12
|
+
alpha: number;
|
|
13
|
+
/** Render order (lower rendered first). Default: 0 */
|
|
14
|
+
z: number;
|
|
15
|
+
/** Rotation angle in degrees. Default: 0 */
|
|
16
|
+
angle: number;
|
|
17
|
+
/** If true, sprite ignores scrollX/scrollY (UI element). Default: false */
|
|
18
|
+
fixed: boolean;
|
|
19
|
+
/** Fill color for the symbol (CSS color). Default: '#ffffff' */
|
|
20
|
+
color: string;
|
|
21
|
+
}
|
|
22
|
+
export declare class Sprite implements ISprite {
|
|
23
|
+
symbol: string;
|
|
24
|
+
x: number;
|
|
25
|
+
y: number;
|
|
26
|
+
alpha: number;
|
|
27
|
+
z: number;
|
|
28
|
+
angle: number;
|
|
29
|
+
fixed: boolean;
|
|
30
|
+
color: string;
|
|
31
|
+
constructor(config: Partial<ISprite>);
|
|
32
|
+
}
|
|
33
|
+
export interface IGameConfig {
|
|
34
|
+
/** HTML element to contain the canvas. If not provided, creates a fullscreen container. Default: auto-created */
|
|
35
|
+
container?: HTMLElement;
|
|
36
|
+
/** Number of grid cells horizontally. Default: 20 */
|
|
37
|
+
gridWidth?: number;
|
|
38
|
+
/** Number of grid cells vertically. Default: 15 */
|
|
39
|
+
gridHeight?: number;
|
|
40
|
+
/** Background color (CSS color). Default: '#000000' */
|
|
41
|
+
background?: string;
|
|
42
|
+
/** Whether to render grid lines. Default: true */
|
|
43
|
+
showGrid?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export interface ITimer {
|
|
46
|
+
/** Unique timer identifier */
|
|
47
|
+
id: number;
|
|
48
|
+
/** Number of times to execute (-1 for infinite) */
|
|
49
|
+
times: number;
|
|
50
|
+
}
|
|
51
|
+
export declare class Game {
|
|
52
|
+
/** Whether to render grid lines. Default: true */
|
|
53
|
+
showGrid: boolean;
|
|
54
|
+
/** Camera horizontal offset in grid units. Default: 0 */
|
|
55
|
+
scrollX: number;
|
|
56
|
+
/** Camera vertical offset in grid units. Default: 0 */
|
|
57
|
+
scrollY: number;
|
|
58
|
+
/** Callback executed every frame. Default: null */
|
|
59
|
+
onUpdate: (() => void) | null;
|
|
60
|
+
/** Callback executed when pointer/mouse is pressed. Receives world grid coordinates (x, y). Default: null */
|
|
61
|
+
onPointerDown: ((x: number, y: number) => void) | null;
|
|
62
|
+
/** Callback executed when pointer/mouse is released. Receives world grid coordinates (x, y). Default: null */
|
|
63
|
+
onPointerUp: ((x: number, y: number) => void) | null;
|
|
64
|
+
constructor(config?: IGameConfig);
|
|
65
|
+
/**
|
|
66
|
+
* Add a sprite to the game
|
|
67
|
+
* @param sprite - The sprite object to add
|
|
68
|
+
* @returns The added sprite
|
|
69
|
+
*/
|
|
70
|
+
addSprite(sprite: ISprite): ISprite;
|
|
71
|
+
/**
|
|
72
|
+
* Check if left arrow key is currently pressed
|
|
73
|
+
* @returns True if left arrow is pressed
|
|
74
|
+
*/
|
|
75
|
+
isLeftKeyDown(): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Check if right arrow key is currently pressed
|
|
78
|
+
* @returns True if right arrow is pressed
|
|
79
|
+
*/
|
|
80
|
+
isRightKeyDown(): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Check if up arrow key is currently pressed
|
|
83
|
+
* @returns True if up arrow is pressed
|
|
84
|
+
*/
|
|
85
|
+
isUpKeyDown(): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Check if down arrow key is currently pressed
|
|
88
|
+
* @returns True if down arrow is pressed
|
|
89
|
+
*/
|
|
90
|
+
isDownKeyDown(): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Check if space key is currently pressed
|
|
93
|
+
* @returns True if space is pressed
|
|
94
|
+
*/
|
|
95
|
+
isSpaceKeyDown(): boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Get the first sprite at a specific grid cell
|
|
98
|
+
* @param x - Grid x coordinate
|
|
99
|
+
* @param y - Grid y coordinate
|
|
100
|
+
* @returns The first sprite found at the position, or null if none exists
|
|
101
|
+
*/
|
|
102
|
+
getSprite(x: number, y: number): ISprite | null;
|
|
103
|
+
/**
|
|
104
|
+
* Get all sprites at a specific grid cell
|
|
105
|
+
* @param x - Grid x coordinate
|
|
106
|
+
* @param y - Grid y coordinate
|
|
107
|
+
* @returns Array of all sprites at the position
|
|
108
|
+
*/
|
|
109
|
+
getAllSprites(x: number, y: number): ISprite[];
|
|
110
|
+
/**
|
|
111
|
+
* Remove a sprite from the game
|
|
112
|
+
* @param sprite - The sprite to remove
|
|
113
|
+
*/
|
|
114
|
+
removeSprite(sprite: ISprite): void;
|
|
115
|
+
/**
|
|
116
|
+
* Clear all sprites from the game
|
|
117
|
+
*/
|
|
118
|
+
clearSprites(): void;
|
|
119
|
+
/**
|
|
120
|
+
* Enable or disable grid rendering
|
|
121
|
+
* @param show - True to show grid, false to hide
|
|
122
|
+
*/
|
|
123
|
+
setShowGrid(show: boolean): void;
|
|
124
|
+
/**
|
|
125
|
+
* Fade a sprite from startAlpha to endAlpha
|
|
126
|
+
* @param sprite - The sprite to animate
|
|
127
|
+
* @param startAlpha - Starting alpha value (0.0 - 1.0)
|
|
128
|
+
* @param endAlpha - Ending alpha value (0.0 - 1.0)
|
|
129
|
+
* @param duration - Duration in milliseconds. Default: 1000
|
|
130
|
+
* @param callback - Optional callback when animation completes
|
|
131
|
+
*/
|
|
132
|
+
fadeSprite(sprite: ISprite, startAlpha: number, endAlpha: number, duration?: number, callback?: () => void): void;
|
|
133
|
+
/**
|
|
134
|
+
* Rotate a sprite from startAngle to endAngle
|
|
135
|
+
* @param sprite - The sprite to animate
|
|
136
|
+
* @param startAngle - Starting angle in degrees
|
|
137
|
+
* @param endAngle - Ending angle in degrees
|
|
138
|
+
* @param duration - Duration in milliseconds. Default: 1000
|
|
139
|
+
* @param callback - Optional callback when animation completes
|
|
140
|
+
*/
|
|
141
|
+
rotateSprite(sprite: ISprite, startAngle: number, endAngle: number, duration?: number, callback?: () => void): void;
|
|
142
|
+
/**
|
|
143
|
+
* Execute a callback after a delay
|
|
144
|
+
* @param delay - Delay in milliseconds
|
|
145
|
+
* @param callback - Function to execute after delay
|
|
146
|
+
*/
|
|
147
|
+
timeout(delay: number, callback: () => void): void;
|
|
148
|
+
/**
|
|
149
|
+
* Execute a callback repeatedly at specified intervals
|
|
150
|
+
* @param delay - Time in milliseconds between executions
|
|
151
|
+
* @param callback - Function to execute
|
|
152
|
+
* @param times - Number of times to execute (-1 or undefined for infinite)
|
|
153
|
+
* @returns Timer object that can be passed to stopTimer()
|
|
154
|
+
*/
|
|
155
|
+
timer(delay: number, callback: () => void, times?: number): ITimer;
|
|
156
|
+
/**
|
|
157
|
+
* Stop a running timer
|
|
158
|
+
*/
|
|
159
|
+
stopTimer(timer: ITimer): void;
|
|
160
|
+
/**
|
|
161
|
+
* Stop the game loop, remove canvas, and clean up resources
|
|
162
|
+
*/
|
|
163
|
+
destroy(): void;
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=frog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frog.d.ts","sourceRoot":"","sources":["../frog.ts"],"names":[],"mappings":"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"}
|
package/dist/frog.js
ADDED
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FrogJS - A simple framework for making games with symbols/emojis on a grid
|
|
3
|
+
*/
|
|
4
|
+
export class Sprite {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.symbol = config.symbol ?? '';
|
|
7
|
+
this.x = config.x ?? 0;
|
|
8
|
+
this.y = config.y ?? 0;
|
|
9
|
+
this.alpha = config.alpha ?? 1;
|
|
10
|
+
this.z = config.z ?? 0;
|
|
11
|
+
this.angle = config.angle ?? 0;
|
|
12
|
+
this.fixed = config.fixed ?? false;
|
|
13
|
+
this.color = config.color ?? '#ffffff';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export class Game {
|
|
17
|
+
constructor(config = {}) {
|
|
18
|
+
/** @internal */
|
|
19
|
+
this.cellSize = 0;
|
|
20
|
+
/** @internal */
|
|
21
|
+
this.sprites = [];
|
|
22
|
+
/** @internal */
|
|
23
|
+
this.keysPressed = new Set();
|
|
24
|
+
/** @internal */
|
|
25
|
+
this.animationFrameId = null;
|
|
26
|
+
/** Whether to render grid lines. Default: true */
|
|
27
|
+
this.showGrid = true;
|
|
28
|
+
/** @internal */
|
|
29
|
+
this.fadeAnimations = [];
|
|
30
|
+
/** @internal */
|
|
31
|
+
this.rotationAnimations = [];
|
|
32
|
+
/** @internal */
|
|
33
|
+
this.timeouts = [];
|
|
34
|
+
/** @internal */
|
|
35
|
+
this.timers = [];
|
|
36
|
+
/** @internal */
|
|
37
|
+
this.nextTimerId = 1;
|
|
38
|
+
/** Camera horizontal offset in grid units. Default: 0 */
|
|
39
|
+
this.scrollX = 0;
|
|
40
|
+
/** Camera vertical offset in grid units. Default: 0 */
|
|
41
|
+
this.scrollY = 0;
|
|
42
|
+
/** Callback executed every frame. Default: null */
|
|
43
|
+
this.onUpdate = null;
|
|
44
|
+
/** Callback executed when pointer/mouse is pressed. Receives world grid coordinates (x, y). Default: null */
|
|
45
|
+
this.onPointerDown = null;
|
|
46
|
+
/** Callback executed when pointer/mouse is released. Receives world grid coordinates (x, y). Default: null */
|
|
47
|
+
this.onPointerUp = null;
|
|
48
|
+
this.gridWidth = config.gridWidth ?? 20;
|
|
49
|
+
this.gridHeight = config.gridHeight ?? 15;
|
|
50
|
+
this.background = config.background ?? '#000000';
|
|
51
|
+
this.showGrid = config.showGrid ?? true;
|
|
52
|
+
// Create container if not provided
|
|
53
|
+
let targetContainer;
|
|
54
|
+
if (!config.container) {
|
|
55
|
+
targetContainer = document.createElement("div");
|
|
56
|
+
targetContainer.id = "frogjs-container";
|
|
57
|
+
document.body.appendChild(targetContainer);
|
|
58
|
+
// Apply fullscreen styling to body and container
|
|
59
|
+
this.applyFullscreenStyles(targetContainer);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
targetContainer = config.container;
|
|
63
|
+
}
|
|
64
|
+
// Create canvas
|
|
65
|
+
this.canvas = document.createElement("canvas");
|
|
66
|
+
targetContainer.appendChild(this.canvas);
|
|
67
|
+
// Calculate cell size and canvas dimensions based on screen/container size
|
|
68
|
+
this.calculateCanvasSize(targetContainer);
|
|
69
|
+
const context = this.canvas.getContext("2d");
|
|
70
|
+
if (!context) {
|
|
71
|
+
throw new Error("Failed to get 2D context");
|
|
72
|
+
}
|
|
73
|
+
this.ctx = context;
|
|
74
|
+
// Set up input handlers
|
|
75
|
+
this.setupInputHandlers();
|
|
76
|
+
// Handle window resize
|
|
77
|
+
window.addEventListener("resize", () => {
|
|
78
|
+
this.calculateCanvasSize(targetContainer);
|
|
79
|
+
});
|
|
80
|
+
// Start the game loop
|
|
81
|
+
this.start();
|
|
82
|
+
}
|
|
83
|
+
/** @internal */
|
|
84
|
+
calculateCanvasSize(container) {
|
|
85
|
+
// Get container dimensions (or use window size)
|
|
86
|
+
const containerWidth = container.clientWidth || window.innerWidth;
|
|
87
|
+
const containerHeight = container.clientHeight || window.innerHeight;
|
|
88
|
+
// Calculate the maximum cell size that fits the screen
|
|
89
|
+
// Use 95% of the screen to leave some margin
|
|
90
|
+
const availableWidth = containerWidth * 0.95;
|
|
91
|
+
const availableHeight = containerHeight * 0.95;
|
|
92
|
+
const cellSizeByWidth = Math.floor(availableWidth / this.gridWidth);
|
|
93
|
+
const cellSizeByHeight = Math.floor(availableHeight / this.gridHeight);
|
|
94
|
+
// Use the smaller cell size to ensure the grid fits in both dimensions
|
|
95
|
+
this.cellSize = Math.min(cellSizeByWidth, cellSizeByHeight);
|
|
96
|
+
// Set canvas size based on calculated cell size
|
|
97
|
+
this.canvas.width = this.gridWidth * this.cellSize;
|
|
98
|
+
this.canvas.height = this.gridHeight * this.cellSize;
|
|
99
|
+
}
|
|
100
|
+
/** @internal */
|
|
101
|
+
applyFullscreenStyles(container) {
|
|
102
|
+
// Reset body margin and padding
|
|
103
|
+
document.body.style.margin = "0";
|
|
104
|
+
document.body.style.padding = "0";
|
|
105
|
+
document.body.style.overflow = "hidden";
|
|
106
|
+
// Style the container to center the canvas
|
|
107
|
+
container.style.position = "fixed";
|
|
108
|
+
container.style.top = "0";
|
|
109
|
+
container.style.left = "0";
|
|
110
|
+
container.style.width = "100vw";
|
|
111
|
+
container.style.height = "100vh";
|
|
112
|
+
container.style.display = "flex";
|
|
113
|
+
container.style.justifyContent = "center";
|
|
114
|
+
container.style.alignItems = "center";
|
|
115
|
+
}
|
|
116
|
+
/** @internal */
|
|
117
|
+
setupInputHandlers() {
|
|
118
|
+
// Keyboard handlers
|
|
119
|
+
window.addEventListener("keydown", (e) => {
|
|
120
|
+
this.keysPressed.add(e.key);
|
|
121
|
+
});
|
|
122
|
+
window.addEventListener("keyup", (e) => {
|
|
123
|
+
this.keysPressed.delete(e.key);
|
|
124
|
+
});
|
|
125
|
+
// Pointer handlers
|
|
126
|
+
this.canvas.addEventListener("pointerdown", (e) => {
|
|
127
|
+
const rect = this.canvas.getBoundingClientRect();
|
|
128
|
+
const canvasX = e.clientX - rect.left;
|
|
129
|
+
const canvasY = e.clientY - rect.top;
|
|
130
|
+
const screenGridX = Math.floor(canvasX / this.cellSize);
|
|
131
|
+
const screenGridY = Math.floor(canvasY / this.cellSize);
|
|
132
|
+
// Convert screen coordinates to world coordinates (account for scroll)
|
|
133
|
+
const worldX = screenGridX + Math.floor(this.scrollX);
|
|
134
|
+
const worldY = screenGridY + Math.floor(this.scrollY);
|
|
135
|
+
if (this.onPointerDown) {
|
|
136
|
+
this.onPointerDown(worldX, worldY);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
this.canvas.addEventListener("pointerup", (e) => {
|
|
140
|
+
const rect = this.canvas.getBoundingClientRect();
|
|
141
|
+
const canvasX = e.clientX - rect.left;
|
|
142
|
+
const canvasY = e.clientY - rect.top;
|
|
143
|
+
const screenGridX = Math.floor(canvasX / this.cellSize);
|
|
144
|
+
const screenGridY = Math.floor(canvasY / this.cellSize);
|
|
145
|
+
// Convert screen coordinates to world coordinates (account for scroll)
|
|
146
|
+
const worldX = screenGridX + Math.floor(this.scrollX);
|
|
147
|
+
const worldY = screenGridY + Math.floor(this.scrollY);
|
|
148
|
+
if (this.onPointerUp) {
|
|
149
|
+
this.onPointerUp(worldX, worldY);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Add a sprite to the game
|
|
155
|
+
* @param sprite - The sprite object to add
|
|
156
|
+
* @returns The added sprite
|
|
157
|
+
*/
|
|
158
|
+
addSprite(sprite) {
|
|
159
|
+
this.sprites.push(sprite);
|
|
160
|
+
return sprite;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Check if left arrow key is currently pressed
|
|
164
|
+
* @returns True if left arrow is pressed
|
|
165
|
+
*/
|
|
166
|
+
isLeftKeyDown() {
|
|
167
|
+
return this.keysPressed.has('ArrowLeft');
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Check if right arrow key is currently pressed
|
|
171
|
+
* @returns True if right arrow is pressed
|
|
172
|
+
*/
|
|
173
|
+
isRightKeyDown() {
|
|
174
|
+
return this.keysPressed.has('ArrowRight');
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Check if up arrow key is currently pressed
|
|
178
|
+
* @returns True if up arrow is pressed
|
|
179
|
+
*/
|
|
180
|
+
isUpKeyDown() {
|
|
181
|
+
return this.keysPressed.has('ArrowUp');
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Check if down arrow key is currently pressed
|
|
185
|
+
* @returns True if down arrow is pressed
|
|
186
|
+
*/
|
|
187
|
+
isDownKeyDown() {
|
|
188
|
+
return this.keysPressed.has('ArrowDown');
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Check if space key is currently pressed
|
|
192
|
+
* @returns True if space is pressed
|
|
193
|
+
*/
|
|
194
|
+
isSpaceKeyDown() {
|
|
195
|
+
return this.keysPressed.has(' ');
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Get the first sprite at a specific grid cell
|
|
199
|
+
* @param x - Grid x coordinate
|
|
200
|
+
* @param y - Grid y coordinate
|
|
201
|
+
* @returns The first sprite found at the position, or null if none exists
|
|
202
|
+
*/
|
|
203
|
+
getSprite(x, y) {
|
|
204
|
+
for (const sprite of this.sprites) {
|
|
205
|
+
if (sprite.x === x && sprite.y === y) {
|
|
206
|
+
return sprite;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Get all sprites at a specific grid cell
|
|
213
|
+
* @param x - Grid x coordinate
|
|
214
|
+
* @param y - Grid y coordinate
|
|
215
|
+
* @returns Array of all sprites at the position
|
|
216
|
+
*/
|
|
217
|
+
getAllSprites(x, y) {
|
|
218
|
+
const result = [];
|
|
219
|
+
for (const sprite of this.sprites) {
|
|
220
|
+
if (sprite.x === x && sprite.y === y) {
|
|
221
|
+
result.push(sprite);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return result;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Remove a sprite from the game
|
|
228
|
+
* @param sprite - The sprite to remove
|
|
229
|
+
*/
|
|
230
|
+
removeSprite(sprite) {
|
|
231
|
+
const index = this.sprites.indexOf(sprite);
|
|
232
|
+
if (index > -1) {
|
|
233
|
+
this.sprites.splice(index, 1);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Clear all sprites from the game
|
|
238
|
+
*/
|
|
239
|
+
clearSprites() {
|
|
240
|
+
this.sprites = [];
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Enable or disable grid rendering
|
|
244
|
+
* @param show - True to show grid, false to hide
|
|
245
|
+
*/
|
|
246
|
+
setShowGrid(show) {
|
|
247
|
+
this.showGrid = show;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Fade a sprite from startAlpha to endAlpha
|
|
251
|
+
* @param sprite - The sprite to animate
|
|
252
|
+
* @param startAlpha - Starting alpha value (0.0 - 1.0)
|
|
253
|
+
* @param endAlpha - Ending alpha value (0.0 - 1.0)
|
|
254
|
+
* @param duration - Duration in milliseconds. Default: 1000
|
|
255
|
+
* @param callback - Optional callback when animation completes
|
|
256
|
+
*/
|
|
257
|
+
fadeSprite(sprite, startAlpha, endAlpha, duration = 1000, callback) {
|
|
258
|
+
// Remove any existing fade animation for this sprite
|
|
259
|
+
this.fadeAnimations = this.fadeAnimations.filter(anim => anim.sprite !== sprite);
|
|
260
|
+
// Set starting alpha
|
|
261
|
+
sprite.alpha = startAlpha;
|
|
262
|
+
// Add new fade animation
|
|
263
|
+
this.fadeAnimations.push({
|
|
264
|
+
sprite,
|
|
265
|
+
startAlpha,
|
|
266
|
+
endAlpha,
|
|
267
|
+
startTime: performance.now(),
|
|
268
|
+
duration,
|
|
269
|
+
callback
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Rotate a sprite from startAngle to endAngle
|
|
274
|
+
* @param sprite - The sprite to animate
|
|
275
|
+
* @param startAngle - Starting angle in degrees
|
|
276
|
+
* @param endAngle - Ending angle in degrees
|
|
277
|
+
* @param duration - Duration in milliseconds. Default: 1000
|
|
278
|
+
* @param callback - Optional callback when animation completes
|
|
279
|
+
*/
|
|
280
|
+
rotateSprite(sprite, startAngle, endAngle, duration = 1000, callback) {
|
|
281
|
+
// Remove any existing rotation animation for this sprite
|
|
282
|
+
this.rotationAnimations = this.rotationAnimations.filter(anim => anim.sprite !== sprite);
|
|
283
|
+
// Set starting angle
|
|
284
|
+
sprite.angle = startAngle;
|
|
285
|
+
// Add new rotation animation
|
|
286
|
+
this.rotationAnimations.push({
|
|
287
|
+
sprite,
|
|
288
|
+
startAngle,
|
|
289
|
+
endAngle,
|
|
290
|
+
startTime: performance.now(),
|
|
291
|
+
duration,
|
|
292
|
+
callback
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Execute a callback after a delay
|
|
297
|
+
* @param delay - Delay in milliseconds
|
|
298
|
+
* @param callback - Function to execute after delay
|
|
299
|
+
*/
|
|
300
|
+
timeout(delay, callback) {
|
|
301
|
+
this.timeouts.push({
|
|
302
|
+
startTime: performance.now(),
|
|
303
|
+
delay,
|
|
304
|
+
callback
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Execute a callback repeatedly at specified intervals
|
|
309
|
+
* @param delay - Time in milliseconds between executions
|
|
310
|
+
* @param callback - Function to execute
|
|
311
|
+
* @param times - Number of times to execute (-1 or undefined for infinite)
|
|
312
|
+
* @returns Timer object that can be passed to stopTimer()
|
|
313
|
+
*/
|
|
314
|
+
timer(delay, callback, times = -1) {
|
|
315
|
+
const timer = {
|
|
316
|
+
id: this.nextTimerId++,
|
|
317
|
+
lastTrigger: performance.now(),
|
|
318
|
+
delay,
|
|
319
|
+
callback,
|
|
320
|
+
times,
|
|
321
|
+
executionCount: 0
|
|
322
|
+
};
|
|
323
|
+
this.timers.push(timer);
|
|
324
|
+
return timer;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Stop a running timer
|
|
328
|
+
*/
|
|
329
|
+
stopTimer(timer) {
|
|
330
|
+
this.timers = this.timers.filter(t => t.id !== timer.id);
|
|
331
|
+
}
|
|
332
|
+
/** @internal */
|
|
333
|
+
start() {
|
|
334
|
+
const gameLoop = () => {
|
|
335
|
+
// Update fade animations
|
|
336
|
+
this.updateAnimations();
|
|
337
|
+
// Update rotation animations
|
|
338
|
+
this.updateRotationAnimations();
|
|
339
|
+
// Update timeouts
|
|
340
|
+
this.updateTimeouts();
|
|
341
|
+
// Update timers
|
|
342
|
+
this.updateTimers();
|
|
343
|
+
// Call user's update callback
|
|
344
|
+
if (this.onUpdate) {
|
|
345
|
+
this.onUpdate();
|
|
346
|
+
}
|
|
347
|
+
// Render the frame
|
|
348
|
+
this.render();
|
|
349
|
+
// Continue the loop
|
|
350
|
+
this.animationFrameId = requestAnimationFrame(gameLoop);
|
|
351
|
+
};
|
|
352
|
+
gameLoop();
|
|
353
|
+
}
|
|
354
|
+
/** @internal */
|
|
355
|
+
updateAnimations() {
|
|
356
|
+
const now = performance.now();
|
|
357
|
+
const completedAnimations = [];
|
|
358
|
+
for (const anim of this.fadeAnimations) {
|
|
359
|
+
const elapsed = now - anim.startTime;
|
|
360
|
+
const progress = Math.min(elapsed / anim.duration, 1.0);
|
|
361
|
+
// Linear interpolation
|
|
362
|
+
anim.sprite.alpha = anim.startAlpha + (anim.endAlpha - anim.startAlpha) * progress;
|
|
363
|
+
// Check if animation is complete
|
|
364
|
+
if (progress >= 1.0) {
|
|
365
|
+
anim.sprite.alpha = anim.endAlpha;
|
|
366
|
+
completedAnimations.push(anim);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
// Remove completed animations and call callbacks
|
|
370
|
+
for (const anim of completedAnimations) {
|
|
371
|
+
this.fadeAnimations = this.fadeAnimations.filter(a => a !== anim);
|
|
372
|
+
if (anim.callback) {
|
|
373
|
+
anim.callback();
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
/** @internal */
|
|
378
|
+
updateRotationAnimations() {
|
|
379
|
+
const now = performance.now();
|
|
380
|
+
const completedAnimations = [];
|
|
381
|
+
for (const anim of this.rotationAnimations) {
|
|
382
|
+
const elapsed = now - anim.startTime;
|
|
383
|
+
const progress = Math.min(elapsed / anim.duration, 1.0);
|
|
384
|
+
// Linear interpolation
|
|
385
|
+
anim.sprite.angle = anim.startAngle + (anim.endAngle - anim.startAngle) * progress;
|
|
386
|
+
// Check if animation is complete
|
|
387
|
+
if (progress >= 1.0) {
|
|
388
|
+
anim.sprite.angle = anim.endAngle;
|
|
389
|
+
completedAnimations.push(anim);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
// Remove completed animations and call callbacks
|
|
393
|
+
for (const anim of completedAnimations) {
|
|
394
|
+
this.rotationAnimations = this.rotationAnimations.filter(a => a !== anim);
|
|
395
|
+
if (anim.callback) {
|
|
396
|
+
anim.callback();
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
/** @internal */
|
|
401
|
+
updateTimeouts() {
|
|
402
|
+
const now = performance.now();
|
|
403
|
+
const completedTimeouts = [];
|
|
404
|
+
for (const timeout of this.timeouts) {
|
|
405
|
+
const elapsed = now - timeout.startTime;
|
|
406
|
+
if (elapsed >= timeout.delay) {
|
|
407
|
+
completedTimeouts.push(timeout);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
// Remove completed timeouts and call callbacks
|
|
411
|
+
for (const timeout of completedTimeouts) {
|
|
412
|
+
this.timeouts = this.timeouts.filter(t => t !== timeout);
|
|
413
|
+
timeout.callback();
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
/** @internal */
|
|
417
|
+
updateTimers() {
|
|
418
|
+
const now = performance.now();
|
|
419
|
+
const completedTimers = [];
|
|
420
|
+
for (const timer of this.timers) {
|
|
421
|
+
const elapsed = now - timer.lastTrigger;
|
|
422
|
+
if (elapsed >= timer.delay) {
|
|
423
|
+
timer.lastTrigger = now;
|
|
424
|
+
timer.executionCount++;
|
|
425
|
+
timer.callback();
|
|
426
|
+
// Check if timer has reached execution limit
|
|
427
|
+
if (timer.times !== -1 && timer.executionCount >= timer.times) {
|
|
428
|
+
completedTimers.push(timer);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
// Remove completed timers
|
|
433
|
+
for (const timer of completedTimers) {
|
|
434
|
+
this.timers = this.timers.filter(t => t.id !== timer.id);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
/** @internal */
|
|
438
|
+
render() {
|
|
439
|
+
// Clear canvas with background color
|
|
440
|
+
this.ctx.fillStyle = this.background;
|
|
441
|
+
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
|
442
|
+
// Draw grid if enabled
|
|
443
|
+
if (this.showGrid) {
|
|
444
|
+
this.drawGrid();
|
|
445
|
+
}
|
|
446
|
+
// Draw sprites
|
|
447
|
+
this.drawSprites();
|
|
448
|
+
}
|
|
449
|
+
/** @internal */
|
|
450
|
+
drawGrid() {
|
|
451
|
+
this.ctx.strokeStyle = "#333333";
|
|
452
|
+
this.ctx.lineWidth = 1;
|
|
453
|
+
// Vertical lines
|
|
454
|
+
for (let x = 0; x <= this.gridWidth; x++) {
|
|
455
|
+
this.ctx.beginPath();
|
|
456
|
+
this.ctx.moveTo(x * this.cellSize, 0);
|
|
457
|
+
this.ctx.lineTo(x * this.cellSize, this.canvas.height);
|
|
458
|
+
this.ctx.stroke();
|
|
459
|
+
}
|
|
460
|
+
// Horizontal lines
|
|
461
|
+
for (let y = 0; y <= this.gridHeight; y++) {
|
|
462
|
+
this.ctx.beginPath();
|
|
463
|
+
this.ctx.moveTo(0, y * this.cellSize);
|
|
464
|
+
this.ctx.lineTo(this.canvas.width, y * this.cellSize);
|
|
465
|
+
this.ctx.stroke();
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
/** @internal */
|
|
469
|
+
drawSprites() {
|
|
470
|
+
this.ctx.textAlign = "center";
|
|
471
|
+
this.ctx.textBaseline = "middle";
|
|
472
|
+
this.ctx.font = `${this.cellSize * 0.8}px monospace`;
|
|
473
|
+
// Sort sprites by z-order (lower z rendered first, higher z on top)
|
|
474
|
+
const sortedSprites = [...this.sprites].sort((a, b) => a.z - b.z);
|
|
475
|
+
for (const sprite of sortedSprites) {
|
|
476
|
+
let screenX;
|
|
477
|
+
let screenY;
|
|
478
|
+
if (sprite.fixed) {
|
|
479
|
+
// Fixed sprites ignore scroll (UI elements)
|
|
480
|
+
screenX = sprite.x;
|
|
481
|
+
screenY = sprite.y;
|
|
482
|
+
}
|
|
483
|
+
else {
|
|
484
|
+
// Apply scroll offset (camera) - floor to ensure integer grid positions
|
|
485
|
+
screenX = sprite.x - Math.floor(this.scrollX);
|
|
486
|
+
screenY = sprite.y - Math.floor(this.scrollY);
|
|
487
|
+
}
|
|
488
|
+
// Skip rendering if sprite is off screen
|
|
489
|
+
if (screenX < 0 || screenX >= this.gridWidth || screenY < 0 || screenY >= this.gridHeight) {
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
492
|
+
const centerX = screenX * this.cellSize + this.cellSize / 2;
|
|
493
|
+
const centerY = screenY * this.cellSize + this.cellSize / 2;
|
|
494
|
+
// Apply alpha and color
|
|
495
|
+
this.ctx.globalAlpha = sprite.alpha;
|
|
496
|
+
this.ctx.fillStyle = sprite.color;
|
|
497
|
+
// Apply rotation if needed
|
|
498
|
+
if (sprite.angle !== 0) {
|
|
499
|
+
this.ctx.save();
|
|
500
|
+
this.ctx.translate(centerX, centerY);
|
|
501
|
+
this.ctx.rotate((sprite.angle * Math.PI) / 180); // Convert degrees to radians
|
|
502
|
+
this.ctx.fillText(sprite.symbol, 0, 0);
|
|
503
|
+
this.ctx.restore();
|
|
504
|
+
}
|
|
505
|
+
else {
|
|
506
|
+
this.ctx.fillText(sprite.symbol, centerX, centerY);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
// Reset alpha
|
|
510
|
+
this.ctx.globalAlpha = 1.0;
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Stop the game loop, remove canvas, and clean up resources
|
|
514
|
+
*/
|
|
515
|
+
destroy() {
|
|
516
|
+
if (this.animationFrameId !== null) {
|
|
517
|
+
cancelAnimationFrame(this.animationFrameId);
|
|
518
|
+
}
|
|
519
|
+
this.canvas.remove();
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
//# sourceMappingURL=frog.js.map
|
package/dist/frog.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frog.js","sourceRoot":"","sources":["../frog.ts"],"names":[],"mappings":"AAAA;;GAEG;AAqBH,MAAM,OAAO,MAAM;IAUjB,YAAY,MAAwB;QAClC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC;QAClC,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC;QACvB,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC;QACvB,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC;QACvB,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC;QACnC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,SAAS,CAAC;IACzC,CAAC;CACF;AAsDD,MAAM,OAAO,IAAI;IA4Cf,YAAY,SAAsB,EAAE;QAnCpC,gBAAgB;QACR,aAAQ,GAAW,CAAC,CAAC;QAG7B,gBAAgB;QACR,YAAO,GAAc,EAAE,CAAC;QAChC,gBAAgB;QACR,gBAAW,GAAgB,IAAI,GAAG,EAAE,CAAC;QAC7C,gBAAgB;QACR,qBAAgB,GAAkB,IAAI,CAAC;QAC/C,kDAAkD;QAC3C,aAAQ,GAAY,IAAI,CAAC;QAChC,gBAAgB;QACR,mBAAc,GAAqB,EAAE,CAAC;QAC9C,gBAAgB;QACR,uBAAkB,GAAyB,EAAE,CAAC;QACtD,gBAAgB;QACR,aAAQ,GAAe,EAAE,CAAC;QAClC,gBAAgB;QACR,WAAM,GAAa,EAAE,CAAC;QAC9B,gBAAgB;QACR,gBAAW,GAAW,CAAC,CAAC;QAEhC,yDAAyD;QAClD,YAAO,GAAW,CAAC,CAAC;QAC3B,uDAAuD;QAChD,YAAO,GAAW,CAAC,CAAC;QAE3B,mDAAmD;QAC5C,aAAQ,GAAwB,IAAI,CAAC;QAC5C,6GAA6G;QACtG,kBAAa,GAA4C,IAAI,CAAC;QACrE,8GAA8G;QACvG,gBAAW,GAA4C,IAAI,CAAC;QAGjE,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC;QACxC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC;QAC1C,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,SAAS,CAAC;QACjD,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,IAAI,CAAC;QAExC,mCAAmC;QACnC,IAAI,eAA4B,CAAC;QACjC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;YACtB,eAAe,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAChD,eAAe,CAAC,EAAE,GAAG,kBAAkB,CAAC;YACxC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;YAE3C,iDAAiD;YACjD,IAAI,CAAC,qBAAqB,CAAC,eAAe,CAAC,CAAC;QAC9C,CAAC;aAAM,CAAC;YACN,eAAe,GAAG,MAAM,CAAC,SAAS,CAAC;QACrC,CAAC;QAED,gBAAgB;QAChB,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAC/C,eAAe,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAEzC,2EAA2E;QAC3E,IAAI,CAAC,mBAAmB,CAAC,eAAe,CAAC,CAAC;QAE1C,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC9C,CAAC;QACD,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC;QAEnB,wBAAwB;QACxB,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAE1B,uBAAuB;QACvB,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,GAAG,EAAE;YACrC,IAAI,CAAC,mBAAmB,CAAC,eAAe,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,sBAAsB;QACtB,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;IAED,gBAAgB;IACR,mBAAmB,CAAC,SAAsB;QAChD,gDAAgD;QAChD,MAAM,cAAc,GAAG,SAAS,CAAC,WAAW,IAAI,MAAM,CAAC,UAAU,CAAC;QAClE,MAAM,eAAe,GAAG,SAAS,CAAC,YAAY,IAAI,MAAM,CAAC,WAAW,CAAC;QAErE,uDAAuD;QACvD,6CAA6C;QAC7C,MAAM,cAAc,GAAG,cAAc,GAAG,IAAI,CAAC;QAC7C,MAAM,eAAe,GAAG,eAAe,GAAG,IAAI,CAAC;QAE/C,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;QACpE,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;QAEvE,uEAAuE;QACvE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,gBAAgB,CAAC,CAAC;QAE5D,gDAAgD;QAChD,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC;QACnD,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC;IACvD,CAAC;IAED,gBAAgB;IACR,qBAAqB,CAAC,SAAsB;QAClD,gCAAgC;QAChC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC;QACjC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC;QAClC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAExC,2CAA2C;QAC3C,SAAS,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC;QACnC,SAAS,CAAC,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC;QAC1B,SAAS,CAAC,KAAK,CAAC,IAAI,GAAG,GAAG,CAAC;QAC3B,SAAS,CAAC,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC;QAChC,SAAS,CAAC,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC;QACjC,SAAS,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;QACjC,SAAS,CAAC,KAAK,CAAC,cAAc,GAAG,QAAQ,CAAC;QAC1C,SAAS,CAAC,KAAK,CAAC,UAAU,GAAG,QAAQ,CAAC;IACxC,CAAC;IAED,gBAAgB;IACR,kBAAkB;QACxB,oBAAoB;QACpB,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;YACvC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;YACrC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,mBAAmB;QACnB,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE;YAChD,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,qBAAqB,EAAE,CAAC;YACjD,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC;YACtC,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC;YACrC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;YACxD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;YAExD,uEAAuE;YACvE,MAAM,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACtD,MAAM,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAEtD,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;gBACvB,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACrC,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE;YAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,qBAAqB,EAAE,CAAC;YACjD,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC;YACtC,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC;YACrC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;YACxD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;YAExD,uEAAuE;YACvE,MAAM,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACtD,MAAM,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAEtD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBACrB,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACnC,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACI,SAAS,CAAC,MAAe;QAC9B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1B,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;OAGG;IACI,aAAa;QAClB,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC3C,CAAC;IAED;;;OAGG;IACI,cAAc;QACnB,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC5C,CAAC;IAED;;;OAGG;IACI,WAAW;QAChB,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACzC,CAAC;IAED;;;OAGG;IACI,aAAa;QAClB,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC3C,CAAC;IAED;;;OAGG;IACI,cAAc;QACnB,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACnC,CAAC;IAED;;;;;OAKG;IACI,SAAS,CAAC,CAAS,EAAE,CAAS;QACnC,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClC,IAAI,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;gBACrC,OAAO,MAAM,CAAC;YAChB,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACI,aAAa,CAAC,CAAS,EAAE,CAAS;QACvC,MAAM,MAAM,GAAc,EAAE,CAAC;QAC7B,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClC,IAAI,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;gBACrC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;OAGG;IACI,YAAY,CAAC,MAAe;QACjC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC;YACf,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED;;OAEG;IACI,YAAY;QACjB,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;IACpB,CAAC;IAED;;;OAGG;IACI,WAAW,CAAC,IAAa;QAC9B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IACvB,CAAC;IAED;;;;;;;OAOG;IACI,UAAU,CAAC,MAAe,EAAE,UAAkB,EAAE,QAAgB,EAAE,WAAmB,IAAI,EAAE,QAAqB;QACrH,qDAAqD;QACrD,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;QAEjF,qBAAqB;QACrB,MAAM,CAAC,KAAK,GAAG,UAAU,CAAC;QAE1B,yBAAyB;QACzB,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC;YACvB,MAAM;YACN,UAAU;YACV,QAAQ;YACR,SAAS,EAAE,WAAW,CAAC,GAAG,EAAE;YAC5B,QAAQ;YACR,QAAQ;SACT,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACI,YAAY,CAAC,MAAe,EAAE,UAAkB,EAAE,QAAgB,EAAE,WAAmB,IAAI,EAAE,QAAqB;QACvH,yDAAyD;QACzD,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;QAEzF,qBAAqB;QACrB,MAAM,CAAC,KAAK,GAAG,UAAU,CAAC;QAE1B,6BAA6B;QAC7B,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC;YAC3B,MAAM;YACN,UAAU;YACV,QAAQ;YACR,SAAS,EAAE,WAAW,CAAC,GAAG,EAAE;YAC5B,QAAQ;YACR,QAAQ;SACT,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACI,OAAO,CAAC,KAAa,EAAE,QAAoB;QAChD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YACjB,SAAS,EAAE,WAAW,CAAC,GAAG,EAAE;YAC5B,KAAK;YACL,QAAQ;SACT,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,KAAa,EAAE,QAAoB,EAAE,QAAgB,CAAC,CAAC;QAClE,MAAM,KAAK,GAAW;YACpB,EAAE,EAAE,IAAI,CAAC,WAAW,EAAE;YACtB,WAAW,EAAE,WAAW,CAAC,GAAG,EAAE;YAC9B,KAAK;YACL,QAAQ;YACR,KAAK;YACL,cAAc,EAAE,CAAC;SAClB,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACI,SAAS,CAAC,KAAa;QAC5B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,gBAAgB;IACR,KAAK;QACX,MAAM,QAAQ,GAAG,GAAG,EAAE;YACpB,yBAAyB;YACzB,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAExB,6BAA6B;YAC7B,IAAI,CAAC,wBAAwB,EAAE,CAAC;YAEhC,kBAAkB;YAClB,IAAI,CAAC,cAAc,EAAE,CAAC;YAEtB,gBAAgB;YAChB,IAAI,CAAC,YAAY,EAAE,CAAC;YAEpB,8BAA8B;YAC9B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,CAAC;YAED,mBAAmB;YACnB,IAAI,CAAC,MAAM,EAAE,CAAC;YAEd,oBAAoB;YACpB,IAAI,CAAC,gBAAgB,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QAC1D,CAAC,CAAC;QAEF,QAAQ,EAAE,CAAC;IACb,CAAC;IAED,gBAAgB;IACR,gBAAgB;QACtB,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAC9B,MAAM,mBAAmB,GAAqB,EAAE,CAAC;QAEjD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACvC,MAAM,OAAO,GAAG,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC;YACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;YAExD,uBAAuB;YACvB,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,QAAQ,CAAC;YAEnF,iCAAiC;YACjC,IAAI,QAAQ,IAAI,GAAG,EAAE,CAAC;gBACpB,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC;gBAClC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;QAED,iDAAiD;QACjD,KAAK,MAAM,IAAI,IAAI,mBAAmB,EAAE,CAAC;YACvC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;YAClE,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IAED,gBAAgB;IACR,wBAAwB;QAC9B,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAC9B,MAAM,mBAAmB,GAAyB,EAAE,CAAC;QAErD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC3C,MAAM,OAAO,GAAG,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC;YACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;YAExD,uBAAuB;YACvB,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,QAAQ,CAAC;YAEnF,iCAAiC;YACjC,IAAI,QAAQ,IAAI,GAAG,EAAE,CAAC;gBACpB,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC;gBAClC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;QAED,iDAAiD;QACjD,KAAK,MAAM,IAAI,IAAI,mBAAmB,EAAE,CAAC;YACvC,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;YAC1E,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IAED,gBAAgB;IACR,cAAc;QACpB,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAC9B,MAAM,iBAAiB,GAAe,EAAE,CAAC;QAEzC,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,MAAM,OAAO,GAAG,GAAG,GAAG,OAAO,CAAC,SAAS,CAAC;YAExC,IAAI,OAAO,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;gBAC7B,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;QAED,+CAA+C;QAC/C,KAAK,MAAM,OAAO,IAAI,iBAAiB,EAAE,CAAC;YACxC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC;YACzD,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,CAAC;IACH,CAAC;IAED,gBAAgB;IACR,YAAY;QAClB,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAC9B,MAAM,eAAe,GAAa,EAAE,CAAC;QAErC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChC,MAAM,OAAO,GAAG,GAAG,GAAG,KAAK,CAAC,WAAW,CAAC;YAExC,IAAI,OAAO,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;gBAC3B,KAAK,CAAC,WAAW,GAAG,GAAG,CAAC;gBACxB,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,KAAK,CAAC,QAAQ,EAAE,CAAC;gBAEjB,6CAA6C;gBAC7C,IAAI,KAAK,CAAC,KAAK,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,cAAc,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;oBAC9D,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC9B,CAAC;YACH,CAAC;QACH,CAAC;QAED,0BAA0B;QAC1B,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,CAAC;YACpC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,gBAAgB;IACR,MAAM;QACZ,qCAAqC;QACrC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC;QACrC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAE/D,uBAAuB;QACvB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,CAAC;QAED,eAAe;QACf,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAED,gBAAgB;IACR,QAAQ;QACd,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,SAAS,CAAC;QACjC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC;QAEvB,iBAAiB;QACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC;YACzC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;YACtC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACvD,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QACpB,CAAC;QAED,mBAAmB;QACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;YAC1C,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;YACtC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;YACtD,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QACpB,CAAC;IACH,CAAC;IAED,gBAAgB;IACR,WAAW;QACjB,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,QAAQ,CAAC;QACjC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,IAAI,CAAC,QAAQ,GAAG,GAAG,cAAc,CAAC;QAErD,oEAAoE;QACpE,MAAM,aAAa,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAElE,KAAK,MAAM,MAAM,IAAI,aAAa,EAAE,CAAC;YACnC,IAAI,OAAe,CAAC;YACpB,IAAI,OAAe,CAAC;YAEpB,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBACjB,4CAA4C;gBAC5C,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC;gBACnB,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC;YACrB,CAAC;iBAAM,CAAC;gBACN,wEAAwE;gBACxE,OAAO,GAAG,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAC9C,OAAO,GAAG,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAChD,CAAC;YAED,yCAAyC;YACzC,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,IAAI,IAAI,CAAC,SAAS,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBAC1F,SAAS;YACX,CAAC;YAED,MAAM,OAAO,GAAG,OAAO,GAAG,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;YAC5D,MAAM,OAAO,GAAG,OAAO,GAAG,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;YAE5D,wBAAwB;YACxB,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC;YACpC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC;YAElC,2BAA2B;YAC3B,IAAI,MAAM,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC;gBACvB,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;gBAChB,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBACrC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,6BAA6B;gBAC9E,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;gBACvC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;YACrB,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;YACrD,CAAC;QACH,CAAC;QAED,cAAc;QACd,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,GAAG,CAAC;IAC7B,CAAC;IAED;;OAEG;IACI,OAAO;QACZ,IAAI,IAAI,CAAC,gBAAgB,KAAK,IAAI,EAAE,CAAC;YACnC,oBAAoB,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAC9C,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;IACvB,CAAC;CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "frogjs",
|
|
3
|
+
"version": "1.0.0-alpha.1",
|
|
4
|
+
"description": "FrogJS - A simple framework for making games with symbols/emojis on a grid",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/frog.js",
|
|
7
|
+
"types": "./dist/frog.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/frog.d.ts",
|
|
11
|
+
"import": "./dist/frog.js",
|
|
12
|
+
"default": "./dist/frog.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"watch": "tsc --watch",
|
|
21
|
+
"prepublishOnly": "npm run build"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"frogjs",
|
|
25
|
+
"game",
|
|
26
|
+
"emoji",
|
|
27
|
+
"symbols",
|
|
28
|
+
"grid",
|
|
29
|
+
"canvas",
|
|
30
|
+
"framework",
|
|
31
|
+
"game-framework",
|
|
32
|
+
"2d-game",
|
|
33
|
+
"browser-game"
|
|
34
|
+
],
|
|
35
|
+
"author": "Arian Fornaris",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"typescript": "^5.3.3"
|
|
39
|
+
},
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "git+https://github.com/yourusername/frogjs.git"
|
|
43
|
+
},
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/yourusername/frogjs/issues"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/yourusername/frogjs#readme"
|
|
48
|
+
}
|