punter.js 1.0.0 → 1.1.0

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 CHANGED
@@ -2,62 +2,52 @@
2
2
 
3
3
  <p align="center"><img src="images/punterjs.png" width="290" height="174" /></p>
4
4
 
5
- A simple, dependency-free 2D game engine for the browser.
6
-
7
- **Why?** Back in the Amiga days, AMOS let you build games in BASIC without touching assembly - sprites, sound, and input just worked, so you could get a character moving in minutes. `punter.js` brings that same philosophy to the browser: no build step, no ES6, no dependencies - just a small single file with a readable API.
5
+ A simple, dependency-free 2D game engine for the browser. No build step, no frameworks - just one script tag.
8
6
 
9
7
  **Features**
10
- * **Auto-scaling** - fixed internal coordinates scale and automatically reposition sprites on resize
11
- * **Retina support** - renders at up to 2× device pixel ratio automatically
8
+ * **Auto-scaling** - sprites automatically reposition on resize
9
+ * **Retina support** - renders at up to 2× device pixel ratio
12
10
  * **Pixel-accurate collision** - bounding boxes ignore transparent pixels
13
- * **HTML state attributes** - `data-punter-*` attributes on `<html>` let you drive CSS from game state
14
- * **CSS variables** - `--punter-vpw`/`--punter-vph` on `<html>`, updated on resize
15
11
 
16
12
  ## Contents
17
13
 
18
- - [Installation](#installation)
19
- - [Running the Example](#running-the-example)
20
- - [Quick Start](#quick-start)
21
- - [punter.init()](#punter-init)
14
+ - [Install](#install)
15
+ - [Run the Example](#run-the-example)
16
+ - [How it Works](#how-it-works)
17
+ - [Setup](#setup)
22
18
  - [Scenes](#scenes)
23
19
  - [Events](#events)
24
20
  - [Sprites](#sprites)
25
- - [Creating a Sprite](#creating-a-sprite)
26
- - [Sprite Properties](#sprite-properties)
27
- - [Sprite Methods](#sprite-methods)
28
- - [Collision Detection](#collision-detection)
29
- - [Animation](#animation)
30
- - [Scrolling & Parallax](#scrolling--parallax)
31
21
  - [Sound](#sound)
32
22
  - [Input](#input)
33
- - [Game Loop Control](#game-loop-control)
34
23
  - [Engine Properties](#engine-properties)
24
+ - [Game Loop Control](#game-loop-control)
35
25
  - [CSS & HTML Hooks](#css--html-hooks)
36
26
  - [Debug Mode](#debug-mode)
37
27
  - [Browser Support](#browser-support)
38
28
 
39
- ## Installation
29
+ ## Install
40
30
 
41
- Download `punter.js` and include it with a script tag - before your game code:
31
+ Download `punter.js` and include it with a script tag before your game code:
42
32
 
43
33
  ```html
44
34
  <!doctype html>
45
35
  <html>
46
36
  <head>
47
37
  <script src="punter.js"></script>
48
- <script>
49
- // your game code here
50
- </script>
51
38
  </head>
52
39
  <body>
53
40
  <canvas id="game"></canvas>
41
+ <script>
42
+ // your game code here
43
+ </script>
54
44
  </body>
55
45
  </html>
56
46
  ```
57
47
 
58
- ## Running the Example
48
+ ## Run the Example
59
49
 
60
- The repo includes a Pong game in `games/pong.html`. Because it loads local files, you need a simple web server rather than opening the file directly in a browser.
50
+ The repo includes a Pong game in `games/pong.html`. Open it with a local web server - browsers block local file loading without one.
61
51
 
62
52
  ```bash
63
53
  npm start
@@ -65,33 +55,29 @@ npm start
65
55
 
66
56
  Then open **http://localhost:3000/games/pong.html** in your browser.
67
57
 
68
- > `npm start` uses `npx serve` no install step needed beyond having Node.js.
58
+ > `npm start` uses `npx serve` - no install step needed beyond having Node.js.
59
+
60
+ ## How it Works
69
61
 
70
- ## Quick Start
62
+ Every punter.js game follows the same three-step pattern:
63
+
64
+ 1. **setup** - specify which canvas to use and which images/sounds to preload
65
+ 2. **scene** - define a named scene (level, menu, etc.) with update/draw logic
66
+ 3. **ready** - switch to a scene once everything has loaded
71
67
 
72
68
  ```js
73
- punter.init({
69
+ // 1. Load assets
70
+ punter.setup({
74
71
  canvas: '#game',
75
- sprites: {
76
- player: 'images/player.png'
77
- },
78
- sounds: {
79
- jump: 'sounds/jump.mp3'
80
- }
72
+ images: { player: 'images/player.png' },
73
+ sounds: { jump: 'sounds/jump.mp3' }
81
74
  });
82
75
 
83
- // level 1 game loop
76
+ // 2. Define a scene
84
77
  punter.scene('level1', function () {
85
78
 
86
- // create a sprite
87
- var player = punter.createSprite({
88
- id: 'player',
89
- key: 'player',
90
- x: '50%',
91
- y: '50%'
92
- });
79
+ var player = punter.createSprite({ id: 'player', key: 'player', x: '50%', y: '50%' });
93
80
 
94
- // move it on ever frame if required
95
81
  punter.on('update', function () {
96
82
  if (punter.keys['ArrowRight']) player.moveX(3);
97
83
  if (punter.keys['ArrowLeft']) player.moveX(-3);
@@ -99,204 +85,127 @@ punter.scene('level1', function () {
99
85
  if (punter.keys['ArrowDown']) player.moveY(3);
100
86
  });
101
87
 
102
- // draw it to every frame
103
88
  punter.on('draw', function () {
104
- player.draw(this);
89
+ player.draw(this); // 'this' is the canvas 2D context
105
90
  });
106
91
  });
107
92
 
108
- // when the game engine ready, go to level 1
93
+ // 3. Start when ready
109
94
  punter.on('ready', function () {
110
95
  punter.go('level1');
111
96
  });
112
97
  ```
113
98
 
114
- ## `punter.init()`
99
+ ## Setup
115
100
 
116
- This is the engine's start-up call. You tell it which canvas to draw on, which images to preload, and which sounds to load. Nothing else will work until `init` has finished loading everything - that's what the `ready` event is for.
101
+ Call this once at the start. The `ready` event fires once all assets have loaded.
117
102
 
118
103
  ```js
119
- punter.init({
120
- canvas: '#game', // the canvas to draw on
121
- debug: false, // set to true to show FPS, bounding boxes, and labels
122
- sprites: {
123
- player: 'images/player.png',
124
- enemy: 'images/enemy.png',
125
- coin: 'images/coin.png'
104
+ punter.setup({
105
+ canvas: '#game', // CSS selector or HTMLCanvasElement
106
+ debug: false, // true = show FPS and bounding boxes
107
+ images: {
108
+ player: 'images/player.png',
109
+ coin: 'images/coin.png'
126
110
  },
127
111
  sounds: {
128
- jump: 'sounds/jump.mp3',
129
- collect: 'sounds/collect.mp3'
112
+ jump: 'sounds/jump.mp3'
130
113
  }
131
114
  });
132
-
133
- punter.on('ready', function () {
134
- // safe to create sprites and go to a scene here
135
- punter.go('menu');
136
- });
137
115
  ```
138
116
 
139
- ### Config Options
140
-
141
- Option | Type | Required | Description
142
- ----------|---------------------------------|----------|-------------------------------------------------------------------------
143
- `canvas` | `string` or `HTMLCanvasElement` | Yes | A CSS selector (`'#game'`) or a direct canvas element reference
144
- `debug` | `boolean` | No | Enables the debug overlay (FPS, sprite bounds, labels). Default: `false`
145
- `sprites` | `object` | No | Key/URL pairs of images to preload: `{ key: 'path/to/image.png' }`
146
- `sounds` | `object` | No | Key/URL pairs of audio files to preload: `{ key: 'path/to/sound.mp3' }`
117
+ Option | Required | Description
118
+ ----------|----------|------------------------------------------------
119
+ `canvas` | Yes | CSS selector (`'#game'`) or `HTMLCanvasElement`
120
+ `images` | No | Key/path pairs of images to preload
121
+ `sounds` | No | Key/path pairs of audio files to preload
122
+ `debug` | No | Enables the debug overlay. Default: `false`
147
123
 
148
124
  ## Scenes
149
125
 
150
- Scenes are the different "screens" in your game - the main menu, level 1, a game over screen, etc. You define each scene as a named function, then switch between them with `punter.go()`.
126
+ Scenes are the different screens in your game - a menu, level 1, game over. Define each with `punter.scene()`, then switch between them with `punter.go()`. Switching scenes automatically clears the previous update/draw handlers.
151
127
 
152
128
  ```js
153
- // Define scenes anywhere before calling punter.go()
154
129
  punter.scene('menu', function () {
155
-
156
- var title = punter.createSprite({ id: 'title', key: 'titleImage', x: '50%', y: '30%' });
157
-
158
- punter.on('draw', function () {
159
- title.draw(this);
160
- });
161
-
162
130
  punter.on('update', function () {
163
- // switch to level1 when the screen is tapped or clicked
164
- if (punter.mouse.clicked) {
165
- punter.go('level1');
166
- }
131
+ if (punter.mouse.clicked) punter.go('level1');
167
132
  });
168
-
169
133
  });
170
134
 
171
135
  punter.scene('level1', function () {
172
136
  // level setup here
173
137
  });
174
-
175
- // Switching scenes clears the previous update/draw handlers automatically
176
- punter.go('menu');
177
138
  ```
178
139
 
179
- ### Methods
180
-
181
- Method | Description
182
- -------------------------|-------------------------------------------------------------------------------------------------------
183
- `punter.scene(name, fn)` | Registers a scene. `name` is a string key; `fn` is the setup function that runs when the scene starts.
184
- `punter.go(name)` | Switches to the named scene. Starts the game loop if it isn't already running. Clears all input state.
185
-
186
140
  ## Events
187
141
 
188
- Events let your code react to things the engine does. The two you'll use most are `update` (run your game logic here) and `draw` (draw your sprites here). These are called automatically by the engine ~60 times per second.
142
+ Register handlers with `punter.on()`. Each event can only have one handler at a time - calling `punter.on()` again for the same event replaces the previous one.
189
143
 
190
144
  ```js
191
145
  punter.on('ready', function () {
192
- // fires once - all images and sounds are loaded, safe to start
146
+ // fires once - all assets loaded, safe to create sprites
193
147
  punter.go('level1');
194
148
  });
195
149
 
196
150
  punter.on('update', function () {
197
- // fires ~60 times/sec - move things, check collisions, handle input
151
+ // fires ~60 times/sec - move things, check input, check collisions
198
152
  });
199
153
 
200
154
  punter.on('draw', function () {
201
- // fires every frame - draw your sprites
202
- // 'this' inside draw is the canvas 2D context
155
+ // fires every frame - 'this' is the canvas 2D context
203
156
  player.draw(this);
204
157
  });
205
158
 
206
159
  punter.on('resize', function () {
207
- // fires when the browser window or device orientation changes
208
- });
209
-
210
- punter.on('go', function (sceneName) {
211
- // fires every time punter.go() is called - receives the new scene name
160
+ // fires when the browser window resizes
212
161
  });
213
162
  ```
214
163
 
215
- ### Event Reference
216
-
217
- Event | Callback signature | When it fires
218
- ---------|-----------------------|--------------------------------------------------------------
219
- `ready` | `function()` | Once, after all sprites and sounds have finished loading
220
- `update` | `function()` | Every logic tick (~60/sec) - put movement and game logic here
221
- `draw` | `function()` | Every render frame - `this` is the canvas 2D context
222
- `resize` | `function()` | When the browser window resizes or orientation changes
223
- `go` | `function(sceneName)` | When `punter.go()` is called; receives the new scene name
224
-
225
- > Each event can only have one handler at a time. Calling `punter.on('update', fn)` again replaces the previous handler. Switching scenes via `punter.go()` automatically clears the `update` and `draw` handlers.
226
-
227
164
  ## Sprites
228
165
 
229
- A sprite is any image in your game - a character, an obstacle, a background, a coin. You create a sprite by giving it an ID, pointing it at a preloaded image, and setting its starting position. The engine handles scaling, cropping, and drawing it to the canvas.
230
-
231
- ### Creating a Sprite
166
+ A sprite is any image in your game - a character, enemy, coin, background tile. Create one with `punter.createSprite()`:
232
167
 
233
168
  ```js
234
169
  var player = punter.createSprite({
235
- id: 'player', // unique ID - no two sprites can share one
236
- key: 'player', // matches a key from config.sprites
237
- x: '50%', // horizontal position - number (pixels) or percent string
238
- y: '80%' // vertical position - number (pixels) or percent string
239
- });
240
-
241
- // Sprite with a fixed size
242
- var background = punter.createSprite({
243
- id: 'bg',
244
- key: 'background',
245
- x: 0,
246
- y: 0,
247
- w: '100%', // width as percent of canvas width
248
- h: '100%' // height as percent of canvas height
170
+ id: 'player', // unique name - no two sprites can share one
171
+ key: 'player', // matches a key from config.sprites
172
+ x: '50%', // position - number (pixels) or percent string
173
+ y: '80%'
249
174
  });
250
175
  ```
251
176
 
252
177
  ### Creation Options
253
178
 
254
- Option | Type | Default | Description
255
- -----------------|------------------------|------------|-----------------------------------------------------------------------------------------------------------
256
- `id` | `string` | - | **Required.** Unique identifier for this sprite.
257
- `key` | `string` or `string[]` | - | **Required.** Image key from `config.sprites`. Pass an array for animation frames: `['frame1', 'frame2']`.
258
- `x` | `number` or `string` | - | **Required.** Horizontal position in pixels or as `'50%'`.
259
- `y` | `number` or `string` | - | **Required.** Vertical position in pixels or as `'50%'`.
260
- `w` | `number` or `string` | auto | Width in pixels or percent. Inferred from image if omitted.
261
- `h` | `number` or `string` | auto | Height in pixels or percent. Inferred from image if omitted.
262
- `preserveAspect` | `boolean` | `true` | Keep the image's aspect ratio when only one dimension is set.
263
- `collidable` | `boolean` | `true` | Compute a pixel-accurate bounding box for collision checks.
264
- `outline` | `string` | `null` | Draw a coloured border around the sprite (e.g. `'red'`). Useful for debugging.
265
- `repeatX` | `boolean` | `false` | Tile the image horizontally across the full canvas width (e.g. for a floor).
266
- `repeatY` | `boolean` | `false` | Tile the image vertically across the full canvas height (e.g. for a wall).
267
- `clipHeight` | `number` | `null` | Limit how many pixels tall the sprite is drawn - useful for fill/progress bars.
268
- `clipFrom` | `string` | `'bottom'` | Which end to clip from: `'top'` or `'bottom'`.
179
+ Option | Default | Description
180
+ -----------------|------------|----------------------------------------------------------------------------------------------------
181
+ `id` | - | **Required.** Unique name for this sprite.
182
+ `key` | - | **Required.** Image key from `config.images`. Pass an array (`['frame1','frame2']`) for animation.
183
+ `x` | - | **Required.** Horizontal position in pixels or `'50%'`.
184
+ `y` | - | **Required.** Vertical position in pixels or `'50%'`.
185
+ `w` | auto | Width in pixels or percent. Inferred from the image if omitted.
186
+ `h` | auto | Height in pixels or percent. Inferred from the image if omitted.
187
+ `preserveAspect` | `true` | Maintain aspect ratio when only one dimension is set.
188
+ `collidable` | `true` | Compute a collision bounding box for this sprite.
189
+ `repeatX` | `false` | Tile horizontally across the canvas (e.g. a floor).
190
+ `repeatY` | `false` | Tile vertically across the canvas (e.g. a wall).
191
+ `clipHeight` | `null` | Limit the drawn height in pixels - useful for health/fill bars.
192
+ `clipFrom` | `'bottom'` | Which end to clip from: `'top'` or `'bottom'`.
269
193
 
270
194
  ### Sprite Properties
271
195
 
272
- After creation, these properties are available on the sprite object:
273
-
274
- Property | Type | Writable | Description
275
- --------------|----------------------|----------|---------------------------------------------------------------------------------------------
276
- `x` | `number` | Yes | Current horizontal position in pixels.
277
- `y` | `number` | Yes | Current vertical position in pixels.
278
- `w` | `number` | Yes | Current width in pixels.
279
- `h` | `number` | Yes | Current height in pixels.
280
- `actualW` | `number` | No | Rendered width (floored). Read-only.
281
- `actualH` | `number` | No | Rendered height, respecting `clipHeight`. Read-only.
282
- `initialX` | `number` | Yes | The x position the sprite started at (used by `bounce()`).
283
- `initialY` | `number` | Yes | The y position the sprite started at (used by `bounce()`).
284
- `frame` | `number\ | null` | Yes | Override the current animation frame index. Set to `null` to let `animate()` control it.
285
- `visible` | `boolean` | No | `true` if any part of the sprite is within the canvas bounds. Read-only.
286
- `seen` | `boolean` | Yes | Becomes `true` once the sprite has been visible on screen. Can be reset manually.
287
- `destroyed` | `boolean` | No | `true` after `destroy()` has been called. Read-only.
288
- `bounds` | `object` | No | Pixel-accurate bounding box: `{ x, y, w, h }`. Updated each frame after `draw()`. Read-only.
289
- `collidable` | `boolean` | Yes | Whether to compute collision bounds.
290
- `clipHeight` | `number\ | null` | Yes | Current clip height.
291
- `key` | `string\ | string[]` | Yes | The image key (or array of keys for animation).
292
- `id` | `string` | No | The sprite's unique ID.
293
- `aspectRatio` | `number` | No | Width-to-height ratio of the original image. Read-only.
196
+ Property | Description
197
+ ------------|-----------------------------------------------------------------------------------------
198
+ `x`, `y` | Position in pixels. Set directly to move the sprite.
199
+ `w`, `h` | Size in pixels.
200
+ `visible` | `true` if any part of the sprite is within the canvas. Read-only.
201
+ `bounds` | Pixel-accurate bounding box `{ x, y, w, h }`. Updated each frame. Read-only.
202
+ `frame` | Override the current animation frame index. Set to `null` to let `animate()` control it.
203
+ `destroyed` | `true` after `destroy()` has been called. Read-only.
294
204
 
295
205
  ### Sprite Methods
296
206
 
297
207
  #### `sprite.draw(ctx)`
298
-
299
- Draws the sprite to the canvas. Call this inside your `draw` event handler. `ctx` is the canvas 2D context passed as `this` in the `draw` callback.
208
+ Draws the sprite. Call inside your `draw` handler - `ctx` is `this`.
300
209
 
301
210
  ```js
302
211
  punter.on('draw', function () {
@@ -306,356 +215,194 @@ punter.on('draw', function () {
306
215
  ```
307
216
 
308
217
  #### `sprite.moveX(dx)` / `sprite.moveY(dy)`
309
-
310
- Move the sprite by `dx` pixels horizontally or `dy` pixels vertically. Call these in your `update` handler.
218
+ Move by `dx` / `dy` pixels. Call in `update`.
311
219
 
312
220
  ```js
313
221
  punter.on('update', function () {
314
222
  if (punter.keys['ArrowRight']) player.moveX(3);
315
223
  if (punter.keys['ArrowLeft']) player.moveX(-3);
316
- if (punter.keys['Space']) player.moveY(-5); // jump
317
224
  });
318
225
  ```
319
226
 
320
227
  #### `sprite.center(offsetX?, offsetY?)`
321
-
322
- Centers the sprite on the canvas. Optional pixel offsets shift it from the centre.
323
-
324
- ```js
325
- player.center(); // perfectly centred
326
- player.center(0, -50); // centred, but 50px above the middle
327
- ```
328
-
329
- Also available as `sprite.centerX(offsetX?)` and `sprite.centerY(offsetY?)` to centre on one axis only.
330
-
331
- #### `sprite.bounce(range?, speed?)`
332
-
333
- Makes the sprite float up and down in a smooth sine-wave motion. Call every frame in `update`.
228
+ Centre the sprite on the canvas. Optional offsets shift it from the centre.
334
229
 
335
230
  ```js
336
- punter.on('update', function () {
337
- coin.bounce(6, 12); // range: 6px, speed: 12 (higher = slower)
338
- });
231
+ player.center(); // perfectly centred
232
+ player.center(0, -50); // centred, 50px above the middle
339
233
  ```
340
234
 
341
- Parameter | Type | Default | Description
342
- ----------|----------|---------|--------------------------------------------------
343
- `range` | `number` | `8` | Max pixels to move up/down from `initialY`.
344
- `speed` | `number` | `10` | Controls how fast the bounce is. Higher = slower.
235
+ Use `sprite.centerX()` or `sprite.centerY()` to centre on one axis only.
345
236
 
346
237
  #### `sprite.animate(delayMs)`
347
-
348
- Advances to the next animation frame. Call every frame in `update`. Requires `key` to be an array of image keys.
238
+ Advance to the next animation frame. Requires `key` to be an array of image keys.
349
239
 
350
240
  ```js
351
241
  var run = punter.createSprite({
352
- id: 'runner',
353
- key: ['run1', 'run2', 'run3', 'run4'],
242
+ id: 'runner',
243
+ key: ['run1', 'run2', 'run3'],
354
244
  x: 100, y: 200
355
245
  });
356
246
 
357
247
  punter.on('update', function () {
358
- run.animate(120); // switch frame every 120ms
248
+ run.animate(120); // new frame every 120ms
359
249
  });
360
250
  ```
361
251
 
362
- > Set `sprite.frame` to a specific index to manually control the frame instead of letting `animate()` cycle through.
252
+ Set `sprite.frame = 2` to jump to a specific frame. Set it to `null` to let `animate()` take over again.
363
253
 
364
- #### `sprite.destroy()`
365
-
366
- Removes the sprite from the engine. Any subsequent `draw()` calls on it will be ignored. The `sprite.destroyed` property becomes `true`.
254
+ #### `sprite.bounce(range?, speed?)`
255
+ Float up and down in a smooth wave. Call every frame in `update`.
367
256
 
368
257
  ```js
369
- if (player.isCollidingWith(enemy)) {
370
- enemy.destroy();
371
- punter.playSound('explosion');
372
- }
258
+ punter.on('update', function () {
259
+ coin.bounce(6, 12); // 6px range, speed 12 (higher = slower)
260
+ });
373
261
  ```
374
262
 
375
- ### Collision Detection
376
-
377
- Collision detection lets you know when two sprites are touching or overlapping. The engine uses each image's actual pixel content to build a tight bounding box - transparent areas around the image are ignored - so collisions feel accurate even for irregularly shaped sprites.
263
+ #### `sprite.isCollidingWith(other)`
264
+ Returns `true` if the bounding boxes of two sprites overlap. Both must have `collidable: true` (the default). Always call `sprite.draw()` before checking - bounds are updated during draw.
378
265
 
379
266
  ```js
380
267
  punter.on('update', function () {
381
268
  if (player.isCollidingWith(bullet)) {
382
- punter.playSound('hit');
383
269
  bullet.destroy();
384
- // handle player damage
270
+ punter.playSound('hit');
385
271
  }
386
272
  });
387
273
  ```
388
274
 
389
- #### `sprite.isCollidingWith(otherSprite)`
390
-
391
- Returns `true` if the bounding boxes of the two sprites overlap, `false` otherwise. Both sprites must have `collidable: true` (which is the default).
392
-
393
- ```js
394
- var hit = player.isCollidingWith(enemy); // true or false
395
- ```
396
-
397
- > Bounding boxes are automatically updated each frame when the sprite is drawn. Always call `sprite.draw()` before checking collisions.
398
-
399
- ### Animation
400
-
401
- Sprites can cycle through multiple images to create animations. Pass an array of keys to `key` when creating the sprite, then call `animate()` each frame:
402
-
403
- ```js
404
- punter.init({
405
- sprites: {
406
- idle1: 'images/idle1.png',
407
- idle2: 'images/idle2.png',
408
- idle3: 'images/idle3.png'
409
- }
410
- });
411
-
412
- var character = punter.createSprite({
413
- id: 'char',
414
- key: ['idle1', 'idle2', 'idle3'],
415
- x: 100, y: 100
416
- });
417
-
418
- punter.on('update', function () {
419
- character.animate(150); // new frame every 150ms
420
- });
421
-
422
- punter.on('draw', function () {
423
- character.draw(this);
424
- });
425
- ```
426
-
427
- To manually jump to a specific frame, set `character.frame = 2`. To hand control back to `animate()`, set it to `null`.
428
-
429
- ### Scrolling & Parallax
430
-
431
- Three methods are available for scrolling behaviour on sprites used as backgrounds or moving scenery:
432
-
433
- #### `sprite.parallaxScrollX(speed, respawnAfterMs, offset?)`
434
-
435
- Moves the sprite left or right continuously. When it goes fully off-screen, it waits `respawnAfterMs` milliseconds then reappears from the opposite edge. Great for clouds, birds, or background layers.
436
-
437
- ```js
438
- var cloud = punter.createSprite({ id: 'cloud1', key: 'cloud', x: 0, y: 50, w: 120, h: 60 });
439
-
440
- punter.on('update', function () {
441
- cloud.parallaxScrollX(-2, 1000); // move left at 2px/frame, respawn after 1 second
442
- });
443
- ```
444
-
445
- Parameter | Type | Description
446
- -----------------|----------|----------------------------------------------------------------------
447
- `speed` | `number` | Pixels per frame. Negative = left, positive = right.
448
- `respawnAfterMs` | `number` | Milliseconds to wait before reappearing from the opposite edge.
449
- `offset` | `number` | Extra pixels beyond the screen edge before respawning. Default: `50`.
450
-
451
- #### `sprite.parallaxScrollY(speed, respawnAfterMs, offset?)`
452
-
453
- Same as `parallaxScrollX` but moves vertically.
454
-
455
- ```js
456
- punter.on('update', function () {
457
- rain.parallaxScrollY(4, 500); // fall down at 4px/frame, respawn after 0.5s
458
- });
459
- ```
275
+ #### `sprite.destroy()`
276
+ Removes the sprite. All subsequent `draw()` calls are silently ignored.
460
277
 
461
- #### `sprite.loopScrollX(speed)`
278
+ #### Scrolling
462
279
 
463
- Moves the sprite horizontally and immediately wraps it to the other side when it exits the canvas - no delay. Useful for seamlessly looping backgrounds.
280
+ Method | Description
281
+ ---------------------------------------------------------|------------------------------------------------------------------------
282
+ `sprite.parallaxScrollX(speed, respawnAfterMs, offset?)` | Scroll horizontally. Respawns from the opposite edge after a delay.
283
+ `sprite.parallaxScrollY(speed, respawnAfterMs, offset?)` | Scroll vertically. Respawns from the opposite edge after a delay.
284
+ `sprite.loopScrollX(speed)` | Scroll horizontally and wrap immediately. Good for looping backgrounds.
464
285
 
465
286
  ```js
466
- var ground = punter.createSprite({ id: 'ground', key: 'ground', x: 0, y: '90%', w: '100%', h: 64 });
467
-
468
287
  punter.on('update', function () {
469
- ground.loopScrollX(-3); // scroll left and wrap
288
+ cloud.parallaxScrollX(-2, 1000); // move left, respawn after 1s
289
+ ground.loopScrollX(-3); // loop left seamlessly
470
290
  });
471
291
  ```
472
292
 
473
293
 
474
294
  ## Sound
475
295
 
476
- punter.js preloads audio files and lets you play and stop them by name. Works on mobile too - sounds are decoded using the Web Audio API, so they play instantly without delay.
477
-
478
296
  ```js
479
- punter.init({
480
- sounds: {
481
- jump: 'sounds/jump.mp3',
482
- music: 'sounds/theme.mp3'
483
- }
297
+ punter.setup({
298
+ sounds: { jump: 'sounds/jump.mp3', music: 'sounds/theme.mp3' }
484
299
  });
485
300
 
486
301
  punter.on('ready', function () {
487
- // play background music, looping
488
- punter.playSound('music', { loop: true, volume: 0.5 });
489
-
302
+ punter.playSound('music', { loop: true, volume: 0.5 }); // background music
490
303
  punter.go('level1');
491
304
  });
492
305
 
493
- // play a one-shot sound effect
494
- punter.playSound('jump');
495
-
496
- // stop a sound that's playing
497
- punter.stopSound('music');
306
+ punter.playSound('jump'); // one-shot effect
307
+ punter.stopSound('music'); // stop a playing sound
498
308
  ```
499
309
 
500
310
  ### `punter.playSound(name, options?)`
501
311
 
502
- Plays a preloaded sound. If the sound is already playing, it stops and restarts it.
503
-
504
- Option | Type | Default | Description
505
- ---------|-----------|---------|--------------------------------------------------------------------
506
- `volume` | `number` | `1` | Volume from `0` (silent) to `1` (full).
507
- `loop` | `boolean` | `false` | If `true`, the sound repeats indefinitely.
508
- `once` | `boolean` | `false` | If `true`, the sound is not tracked - `stopSound()` cannot stop it.
509
- `speed` | `number` | `1` | Playback speed multiplier. `0.5` = half speed, `2` = double speed.
312
+ Option | Default | Description
313
+ ---------|---------|--------------------------------------------
314
+ `volume` | `1` | Volume from `0` (silent) to `1` (full).
315
+ `loop` | `false` | Repeat indefinitely.
316
+ `speed` | `1` | Playback speed. `0.5` = half, `2` = double.
317
+ `once` | `false` | If `true`, `stopSound()` cannot stop it.
510
318
 
511
319
  ### `punter.stopSound(name)`
512
-
513
- Stops all currently playing instances of the named sound.
320
+ Stops all playing instances of the named sound.
514
321
 
515
322
 
516
323
  ## Input
517
324
 
518
- The engine tracks keyboard keys and mouse/touch taps for you. You check the current state of these in your `update` handler each frame. Touch events on mobile are automatically translated into mouse events, so the same code works on phones and desktops.
325
+ Check input state inside your `update` handler each frame. Touch events on mobile are automatically translated into mouse events.
519
326
 
520
327
  ### Keyboard
521
328
 
522
- `punter.keys` is a plain object where each key name maps to `true` when held down and `false` (or absent) when released.
523
-
524
329
  ```js
525
330
  punter.on('update', function () {
526
331
  if (punter.keys['ArrowLeft']) player.moveX(-3);
527
332
  if (punter.keys['ArrowRight']) player.moveX(3);
528
- if (punter.keys['ArrowUp']) player.moveY(-3);
529
- if (punter.keys['ArrowDown']) player.moveY(3);
530
- if (punter.keys[' ']) player.moveY(-8); // spacebar to jump
333
+ if (punter.keys[' ']) player.moveY(-8); // spacebar
531
334
  if (punter.keys['Escape']) punter.go('menu');
532
335
  });
533
336
  ```
534
337
 
535
- Key names match the browser's [KeyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) values: `'ArrowLeft'`, `'ArrowRight'`, `'ArrowUp'`, `'ArrowDown'`, `'Enter'`, `'Escape'`, `' '` (space), letter keys (`'a'`, `'A'`), etc.
338
+ Key names follow the browser's [`KeyboardEvent.key`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) values.
536
339
 
537
340
  ### Mouse & Touch
538
341
 
539
- `punter.mouse` tracks the current pointer position and whether a click or tap has occurred.
540
-
541
342
  ```js
542
343
  punter.on('update', function () {
543
344
  if (punter.mouse.clicked) {
544
- // player tapped or clicked - punter.mouse.x / .y has the position
545
345
  fireAt(punter.mouse.x, punter.mouse.y);
546
346
  }
547
347
  });
548
348
  ```
549
349
 
550
- Property | Type | Description
551
- -----------------------|-----------|--------------------------------------------------------------
552
- `punter.mouse.x` | `number` | Horizontal position of the last click/tap in canvas pixels.
553
- `punter.mouse.y` | `number` | Vertical position of the last click/tap in canvas pixels.
554
- `punter.mouse.clicked` | `boolean` | `true` for one update tick after a click or tap, then auto-cleared.
555
-
556
- > Coordinates are in canvas pixel space — the same coordinate system as `punter.width` / `punter.height` and sprite `x`/`y` values.
350
+ Property | Description
351
+ -----------------------|---------------------------------------------------
352
+ `punter.mouse.x` | X position of the last click/tap in canvas pixels.
353
+ `punter.mouse.y` | Y position of the last click/tap in canvas pixels.
354
+ `punter.mouse.clicked` | `true` for one update tick after a click or tap.
557
355
 
558
356
  ### `punter.clearInput()`
559
-
560
- Resets all keyboard key states to `false` and clears `mouse.clicked`. Called automatically whenever `punter.go()` switches scenes.
561
-
562
- ```js
563
- punter.on('update', function () {
564
- if (punter.mouse.clicked) {
565
- punter.go('level1');
566
- // no need to clear - punter.go() does it automatically
567
- }
568
- });
569
- ```
570
-
571
- ## Game Loop Control
572
-
573
- The game loop is what makes `update` and `draw` fire continuously. It starts automatically when you call `punter.go()`. These methods let you pause and resume it manually - for example, when showing a pause menu.
574
-
575
- ```js
576
- // Pause the loop (stops update and draw from firing)
577
- punter.pause();
578
-
579
- // Resume from where it left off
580
- punter.resume();
581
-
582
- // Force a single redraw without running update logic
583
- // Useful after a resize when the loop isn't running
584
- punter.redraw();
585
- ```
586
-
587
- Method | Description
588
- ------------------|-------------------------------------------------------
589
- `punter.pause()` | Stops the game loop. The screen freezes.
590
- `punter.resume()` | Restarts the game loop.
591
- `punter.redraw()` | Redraws all sprites once without advancing game logic.
357
+ Resets all key states and clears `mouse.clicked`. Called automatically on `punter.go()`.
592
358
 
593
359
 
594
360
  ## Engine Properties
595
361
 
596
- These are read-only properties available on the `punter` object at any time:
597
-
598
- Property | Type | Description
599
- ---------------------|----------------------------|----------------------------------------------------------------------------
600
- `punter.width` | `number` | Internal canvas width in pixels (adjusted for device pixel ratio).
601
- `punter.height` | `number` | Internal canvas height in pixels (adjusted for device pixel ratio).
602
- `punter.dpr` | `number` | Device pixel ratio used for rendering (capped at `2`).
603
- `punter.frame` | `number` | Current frame counter, cycling 1–60.
604
- `punter.totalFrames` | `number` | Total number of frames rendered since the loop started.
605
- `punter.running` | `boolean` | `true` if the game loop is currently running.
606
- `punter.paused` | `boolean` | `true` if the loop has been paused.
607
- `punter.resized` | `boolean` | `true` for one frame after a resize event.
608
- `punter.isMobile` | `boolean` | `true` if the engine detected a mobile device.
609
- `punter.isDesktop` | `boolean` | `true` if the engine detected a desktop device.
610
- `punter.orientation` | `string` | `'portrait'` or `'landscape'` based on current window dimensions.
611
- `punter.sceneName` | `string` | The name of the currently active scene, or `''` if none.
612
- `punter.debug` | `boolean` | Whether debug mode is active. Can be set at runtime: `punter.debug = true`.
613
- `punter.canvas` | `HTMLCanvasElement` | The raw canvas element.
614
- `punter.ctx` | `CanvasRenderingContext2D` | The canvas 2D drawing context.
615
- `punter.sprites` | `Sprite[]` | Array of all live (non-destroyed) sprites.
362
+ Property | Description
363
+ ---------------------|-----------------------------------------------------
364
+ `punter.width` | Canvas width in pixels (DPR-adjusted).
365
+ `punter.height` | Canvas height in pixels (DPR-adjusted).
366
+ `punter.dpr` | Device pixel ratio (capped at `2`).
367
+ `punter.frame` | Frame counter, cycling 1–60.
368
+ `punter.running` | `true` if the game loop is running.
369
+ `punter.paused` | `true` if the loop is paused.
370
+ `punter.isMobile` | `true` on mobile devices.
371
+ `punter.orientation` | `'portrait'` or `'landscape'`.
372
+ `punter.sceneName` | Name of the current scene.
373
+ `punter.debug` | Toggle debug mode at runtime: `punter.debug = true`.
616
374
 
617
375
  ### `punter.getSprite(id)`
618
-
619
- Retrieves a sprite by its ID. Returns `null` if not found.
376
+ Returns a sprite by ID, or `null` if not found.
620
377
 
621
378
  ```js
622
379
  var player = punter.getSprite('player');
623
- if (player) player.moveX(5);
624
380
  ```
625
381
 
626
382
 
627
- ## CSS & HTML Hooks
628
-
629
- As the engine runs, it automatically sets CSS variables and HTML attributes on the `<html>` element. You can use these in your CSS to style the page differently based on the current game state - for example, hiding the loader once assets are ready, or applying a different layout in landscape mode.
630
-
631
- ### HTML Attributes
383
+ ## Game Loop Control
632
384
 
633
- The engine adds these attributes to the `<html>` element:
385
+ The loop starts automatically when you call `punter.go()`. Pause and resume it manually - for example, when showing a pause menu.
634
386
 
635
- Attribute | Values | Description
636
- --------------------------|------------------------------|--------------------------------------------------------------
637
- `data-punter-loading` | `"true"` / removed | Present while assets are loading; removed when `ready` fires.
638
- `data-punter-debug` | `"true"` / removed | Present when debug mode is on.
639
- `data-punter-device` | `"mobile"` / `"desktop"` | Set based on user agent detection.
640
- `data-punter-orientation` | `"portrait"` / `"landscape"` | Updated on every resize.
641
- `data-punter-scene` | scene name string | The name of the current scene; updated on `punter.go()`.
387
+ ```js
388
+ punter.pause(); // stop update + draw
389
+ punter.resume(); // restart
390
+ punter.redraw(); // single redraw without running update logic
391
+ ```
642
392
 
643
- **Example - show a loading screen:**
644
393
 
645
- ```css
646
- /* show loader until engine is ready */
647
- #loader { display: block; }
648
- html[data-punter-loading] #loader { display: block; }
649
- html:not([data-punter-loading]) #loader { display: none; }
394
+ ## CSS & HTML Hooks
650
395
 
651
- /* different layout per orientation */
652
- html[data-punter-orientation="landscape"] .controls { flex-direction: row; }
653
- html[data-punter-orientation="portrait"] .controls { flex-direction: column; }
654
- ```
396
+ The engine sets attributes on `<html>` as the game runs. Use them in CSS to react to game state.
655
397
 
656
- ### CSS Variables
398
+ Attribute | When set
399
+ --------------------------|-------------------------------------------------------------
400
+ `data-punter-loading` | Present while assets are loading; removed when `ready` fires
401
+ `data-punter-scene` | Updated on every `punter.go()` - value is the scene name
402
+ `data-punter-orientation` | `"portrait"` or `"landscape"`, updated on resize
403
+ `data-punter-device` | `"mobile"` or `"desktop"`, set on init
657
404
 
658
- These are set on the `<html>` element and updated whenever the window resizes:
405
+ It also exposes CSS variables on `:root`, updated on resize:
659
406
 
660
407
  Variable | Description
661
408
  ---------------|------------------------------------------
@@ -663,68 +410,32 @@ Variable | Description
663
410
  `--punter-vph` | Viewport height in pixels (e.g. `667px`).
664
411
 
665
412
  ```css
666
- .hud {
667
- width: var(--punter-vpw);
668
- height: var(--punter-vph);
669
- }
413
+ /* hide loader once assets are ready */
414
+ html[data-punter-loading] #loader { display: block; }
415
+ html:not([data-punter-loading]) #loader { display: none; }
670
416
  ```
671
417
 
672
418
 
673
419
  ## Debug Mode
674
420
 
675
- Turning on debug mode overlays useful information directly onto the game canvas - handy when you're trying to understand why a sprite is in the wrong place or why a collision isn't triggering.
676
-
677
- Enable it in `punter.init()`:
678
-
679
421
  ```js
680
- punter.init({ canvas: '#game', debug: true, sprites: { ... } });
422
+ punter.setup({ canvas: '#game', debug: true }); // enable at startup
423
+ punter.debug = true; // or toggle at runtime
681
424
  ```
682
425
 
683
- Or toggle it at any time:
684
-
685
- ```js
686
- punter.debug = true;
687
- punter.debug = false;
688
- ```
689
-
690
- When debug mode is active, the engine draws:
691
-
692
- - **FPS counter** and current canvas resolution in the bottom-right corner
693
- - **Red bounding boxes** around each collidable sprite's collision area
694
- - **Position and size labels** (`x=100 y=200 (32x32)`) near each sprite
695
-
696
- ### Customising the Debug Overlay
697
-
698
- The overlay colours and font are pulled from CSS variables on `:root`. Add these to your stylesheet to customise them:
699
-
700
- ```css
701
- :root {
702
- --punter-debug-background: rgba(0, 0, 0, 0.6);
703
- --punter-debug-text: #00ff00;
704
- --punter-debug-font: 11px 'Courier New', monospace;
705
- }
706
- ```
707
-
708
- Variable | Default | Description
709
- ----------------------------|-------------------------|----------------------------------------
710
- `--punter-debug-background` | `rgba(255,255,255,0.7)` | Background colour of debug label boxes.
711
- `--punter-debug-text` | `red` | Text colour of debug labels.
712
- `--punter-debug-font` | `12px monospace` | Font for debug labels.
426
+ When active, the engine draws:
427
+ - **FPS** and canvas resolution in the bottom-right corner
428
+ - **Red bounding boxes** around each collidable sprite
429
+ - **Position and size labels** near each sprite
713
430
 
714
431
 
715
432
  ## Browser Support
716
433
 
717
- Works with all major browsers _(Chrome, Firefox, Safari, Edge)_. For older browsers, polyfills for `fetch` and `Promise` are sufficient.
718
-
719
- punter.js requires:
434
+ Works in all modern browsers (Chrome, Firefox, Safari, Edge). For older browsers, polyfills for `fetch` and `Promise` are enough.
720
435
 
721
- - `fetch` (for loading sounds)
722
- - `Promise`
723
- - `requestAnimationFrame`
724
- - `AudioContext` / `webkitAudioContext`
725
- - `canvas` 2D context with `getImageData`
436
+ Requires: `fetch`, `Promise`, `requestAnimationFrame`, `AudioContext`, canvas `getImageData`.
726
437
 
727
- NOTE: Don't manually resize the canvas - the engine owns that via `resize()`.
438
+ > Don't manually resize the canvas - the engine manages that internally.
728
439
 
729
440
  ## License
730
441
 
package/games/pong.html CHANGED
@@ -1,13 +1,26 @@
1
1
  <!doctype html>
2
2
  <html>
3
3
  <head>
4
+ <title>Pong</title>
4
5
  <meta charset="utf-8">
5
6
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title>Pong</title>
7
7
  <style>
8
- * { margin: 0; padding: 0; box-sizing: border-box; }
9
- html, body { width: 100%; height: 100%; background: #1e2230; overflow: hidden; }
10
- canvas { display: block; }
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ box-sizing: border-box;
12
+ }
13
+
14
+ html, body {
15
+ width: 100%;
16
+ height: 100%;
17
+ background: #1e2230;
18
+ overflow: hidden;
19
+ }
20
+
21
+ canvas {
22
+ display: block;
23
+ }
11
24
  </style>
12
25
  <script src="../punter.js"></script>
13
26
  </head>
@@ -80,9 +93,9 @@
80
93
  // SETUP
81
94
  // Load the two sprite images before the game starts.
82
95
  // =========================================================
83
- punter.init({
96
+ punter.setup({
84
97
  canvas: '#game',
85
- sprites: {
98
+ images: {
86
99
  paddle: '../images/pong/sprites/paddle.png',
87
100
  ball: '../images/pong/sprites/ball.png'
88
101
  }
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "punter.js",
3
- "version": "1.0.0",
4
- "description": "A lightweight, dependency-free JavaScript 2D game engine for the browser. Drop in a script tag and start building.",
3
+ "version": "1.1.0",
4
+ "description": "A simple, dependency-free 2D game engine for the browser. No build step, no frameworks - just one script tag.",
5
5
  "main": "punter.js",
6
6
  "directories": {
7
7
  "test": "tests"
8
8
  },
9
9
  "scripts": {
10
10
  "start": "npx serve .",
11
+ "start:pong": "npx serve . -l 4000 & npx open-cli http://localhost:4000/games/pong.html",
11
12
  "test": ". \"$NVM_DIR/nvm.sh\" && nvm use && NODE_ENV=test TZ=UTC node_modules/.bin/jasmine --config=tests/jasmine/config.json"
12
13
  },
13
14
  "repository": {
package/punter.js CHANGED
@@ -106,11 +106,11 @@
106
106
  })();
107
107
 
108
108
  /**
109
- * Initialises the engine with canvas, sprites, sounds, and buttons
109
+ * Initialises the engine with canvas, images, sounds, and buttons
110
110
  * @param {Object} config - configuration object
111
111
  * @returns {void}
112
112
  */
113
- function init(config) {
113
+ function setup(config) {
114
114
 
115
115
  config = config || {};
116
116
 
@@ -151,11 +151,11 @@
151
151
  _boundsCanvas = document.createElement('canvas');
152
152
  _boundsCtx = _boundsCanvas.getContext('2d', { willReadFrequently: true });
153
153
 
154
- loadSprites(config.sprites || {}).then(function() {
154
+ loadImages(config.images || {}).then(function() {
155
155
 
156
156
  // precompute bounds for all sprite frames
157
- if (config.sprites) {
158
- for (var key in config.sprites) {
157
+ if (config.images) {
158
+ for (var key in config.images) {
159
159
  var img = images[key];
160
160
  if (img && img.complete && img.naturalWidth) {
161
161
  // this warms up the boundingCache
@@ -182,13 +182,13 @@
182
182
  }
183
183
 
184
184
  /**
185
- * Loads and decodes all sprite images
186
- * @param {Object} sprites - Key-value map of sprite keys to image URLs
185
+ * Loads and decodes all images
186
+ * @param {Object} images - Key-value map of image keys to image URLs
187
187
  * @returns {Promise} - Resolves when all images are loaded and decoded
188
188
  */
189
- function loadSprites(sprites) {
189
+ function loadImages(imageMap) {
190
190
 
191
- var keys = Object.keys(sprites);
191
+ var keys = Object.keys(imageMap);
192
192
  var total = keys.length;
193
193
 
194
194
  if (!total) return Promise.resolve();
@@ -234,7 +234,7 @@
234
234
 
235
235
  for (var i = 0; i < total; i++) {
236
236
  var key = keys[i];
237
- var url = sprites[key];
237
+ var url = imageMap[key];
238
238
  var img = new Image();
239
239
  img.key = key; // for debugging
240
240
  img.onload = handleLoad.bind(img, key);
@@ -1003,7 +1003,7 @@
1003
1003
  */
1004
1004
  function startLoop() {
1005
1005
 
1006
- if (!_initilised) throw new Error('punter.init must be called first');
1006
+ if (!_initilised) throw new Error('punter.setup must be called first');
1007
1007
 
1008
1008
  _canvasCtx = _canvas.getContext('2d', { alpha: true, desynchronized: true });
1009
1009
  _canvasCtx.imageSmoothingEnabled = false;
@@ -1067,7 +1067,7 @@
1067
1067
 
1068
1068
  function pauseLoop() {
1069
1069
 
1070
- if (!_initilised) throw new Error('punter.init must be called first');
1070
+ if (!_initilised) throw new Error('punter.setup must be called first');
1071
1071
 
1072
1072
  if (_loopId !== null) {
1073
1073
  cancelAnimationFrame(_loopId);
@@ -1090,7 +1090,7 @@
1090
1090
  */
1091
1091
  function playSound(name, options) {
1092
1092
 
1093
- if (!_initilised) throw new Error('punter.init must be called first');
1093
+ if (!_initilised) throw new Error('punter.setup must be called first');
1094
1094
 
1095
1095
  var buffer = sounds[name];
1096
1096
  if (!buffer) return;
@@ -1131,7 +1131,7 @@
1131
1131
 
1132
1132
  function stopSound(name) {
1133
1133
 
1134
- if (!_initilised) throw new Error('punter.init must be called first');
1134
+ if (!_initilised) throw new Error('punter.setup must be called first');
1135
1135
 
1136
1136
  var arr = playingSounds[name];
1137
1137
  if (!arr || !arr.length) return;
@@ -1296,7 +1296,7 @@
1296
1296
  var api = {
1297
1297
 
1298
1298
  // initialization
1299
- init: init,
1299
+ setup: setup,
1300
1300
 
1301
1301
  // scene lifecycle
1302
1302
  scene: function (name, handler) {
@@ -1304,7 +1304,7 @@
1304
1304
  },
1305
1305
  go: function (name) {
1306
1306
 
1307
- if (!_initilised) throw new Error('punter.init must be called first');
1307
+ if (!_initilised) throw new Error('punter.setup must be called first');
1308
1308
  if (!_scenes[name]) throw new Error('punter.go: unknown scene "' + name + '"');
1309
1309
 
1310
1310
  // remove existing game loop handlers
@@ -1355,7 +1355,7 @@
1355
1355
 
1356
1356
  // sprite factory
1357
1357
  createSprite: function(opts) {
1358
- if (!_initilised) throw new Error('createSprite: punter.init must be called first');
1358
+ if (!_initilised) throw new Error('createSprite: punter.setup must be called first');
1359
1359
  return new Sprite(opts);
1360
1360
  },
1361
1361
  getSprite: function(id) {
@@ -20,9 +20,9 @@
20
20
  window.__ready = true;
21
21
  });
22
22
 
23
- punter.init({
23
+ punter.setup({
24
24
  canvas: '#game',
25
- sprites: { hero: heroImg },
25
+ images: { hero: heroImg },
26
26
  sounds: { beep: '/tests/fixtures/silence.wav' }
27
27
  });
28
28
  </script>
@@ -19,7 +19,7 @@ describe('Interface', function () {
19
19
  it('exposes the expected methods', async function () {
20
20
  var result = await page.evaluate(function () {
21
21
  return {
22
- init: typeof punter.init,
22
+ setup: typeof punter.setup,
23
23
  scene: typeof punter.scene,
24
24
  go: typeof punter.go,
25
25
  on: typeof punter.on,