js-game-zero 0.0.0-stage → 0.4.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.
Files changed (53) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +138 -2
  3. package/dist/active-service.d.ts +21 -0
  4. package/dist/actor.d.ts +182 -0
  5. package/dist/animation.d.ts +61 -0
  6. package/dist/assets.d.ts +148 -0
  7. package/dist/audio.d.ts +150 -0
  8. package/dist/browser-asset-backends.d.ts +8 -0
  9. package/dist/browser.d.ts +10 -0
  10. package/dist/chunk-q9m20c2h.js +7972 -0
  11. package/dist/clock.d.ts +29 -0
  12. package/dist/color.d.ts +15 -0
  13. package/dist/events.d.ts +145 -0
  14. package/dist/friendly-names.d.ts +43 -0
  15. package/dist/geometry.d.ts +125 -0
  16. package/dist/helpers.d.ts +28 -0
  17. package/dist/host.d.ts +58 -0
  18. package/dist/host.js +435 -0
  19. package/dist/index.d.ts +340 -0
  20. package/dist/index.js +258 -0
  21. package/dist/input.d.ts +200 -0
  22. package/dist/inspection.d.ts +58 -0
  23. package/dist/jgz.js +8545 -0
  24. package/dist/node.d.ts +14 -0
  25. package/dist/node.js +145 -0
  26. package/dist/pixel-density.d.ts +23 -0
  27. package/dist/random.d.ts +31 -0
  28. package/dist/reference/actor.md +197 -0
  29. package/dist/reference/audio.md +128 -0
  30. package/dist/reference/clock.md +150 -0
  31. package/dist/reference/helpers.md +46 -0
  32. package/dist/reference/hooks.md +379 -0
  33. package/dist/reference/index.d.ts +2 -0
  34. package/dist/reference/index.js +39 -0
  35. package/dist/reference/loaders.md +164 -0
  36. package/dist/reference/rect.md +129 -0
  37. package/dist/reference/runtime.md +478 -0
  38. package/dist/reference/screen.md +392 -0
  39. package/dist/reference/storage.md +90 -0
  40. package/dist/rendering.d.ts +216 -0
  41. package/dist/runtime-contracts.d.ts +117 -0
  42. package/dist/runtime-diagnostics.d.ts +37 -0
  43. package/dist/runtime-persistence.d.ts +32 -0
  44. package/dist/runtime-source.d.ts +82 -0
  45. package/dist/runtime.d.ts +81 -0
  46. package/dist/source-scan.d.ts +49 -0
  47. package/dist/storage-path.d.ts +3 -0
  48. package/dist/storage.d.ts +88 -0
  49. package/dist/tone.d.ts +81 -0
  50. package/dist/touch-controls.d.ts +24 -0
  51. package/dist/touch-pointer.d.ts +11 -0
  52. package/dist/util.d.ts +62 -0
  53. package/package.json +69 -4
@@ -0,0 +1,150 @@
1
+ # Clock And Animation
2
+
3
+ ## `clock`
4
+
5
+ `clock` schedules callbacks against the game's own timeline, which only
6
+ advances while your game is running (driven by the frame loop's `dt`, not by
7
+ wall-clock time) — so a scheduled callback never fires while the tab is
8
+ backgrounded and the game is effectively paused.
9
+
10
+ ### `clock.schedule(callback, delay)`
11
+
12
+ Calls `callback` once, `delay` seconds from now.
13
+
14
+ ```js
15
+ clock.schedule(spawnEnemy, 2); // spawn one enemy, 2 seconds from now
16
+ ```
17
+
18
+ A callback scheduled by another scheduled callback waits for the next tick,
19
+ even with a delay of `0`, so one that schedules itself again with
20
+ `clock.schedule(loop, 0)` runs once a frame.
21
+
22
+ ### `clock.scheduleInterval(callback, interval)`
23
+
24
+ Calls `callback` repeatedly, every `interval` seconds, until unscheduled.
25
+ `interval` must be greater than `0`.
26
+
27
+ ```js
28
+ clock.scheduleInterval(spawnEnemy, 3); // a new enemy every 3 seconds
29
+ ```
30
+
31
+ Every schedule, and `eachTick`, takes the function itself, without brackets.
32
+ `clock.scheduleInterval(spawnEnemy(), 3)` would call it once right away and
33
+ hand over what it returned, so it throws a `TypeError` that says to drop the
34
+ brackets.
35
+
36
+ ### `clock.scheduleUnique(callback, delay)`
37
+
38
+ Like `schedule`, but first cancels any existing scheduled call for the same
39
+ `callback` function — useful when an event might restart a timer that's
40
+ already pending and you only want the latest one to count.
41
+
42
+ ### `clock.unschedule(callback)`
43
+
44
+ Cancels a pending `schedule`, `scheduleInterval`, or `eachTick` callback
45
+ registered with that exact function reference. Safe to call even if nothing
46
+ matching is scheduled.
47
+
48
+ ### `clock.eachTick(callback)`
49
+
50
+ Calls `callback(dt)` on every single frame, forever (until unscheduled) —
51
+ this is what `animate()` uses internally to advance animations, and it's
52
+ useful directly for continuous per-frame effects that don't fit naturally
53
+ into your top-level `update()`.
54
+
55
+ ### `clock.clear()`
56
+
57
+ Cancels every scheduled call and every `eachTick` callback at once — handy
58
+ when resetting a level or restarting a game so old timers from the previous
59
+ run don't fire.
60
+
61
+ ### `clock.now()`
62
+
63
+ Returns the clock's current time in seconds (the running total of every
64
+ `dt` it has been ticked with).
65
+
66
+ ### Error handling
67
+
68
+ In a game, a scheduled or `eachTick` callback that throws (an animation's
69
+ `onFinished` too) stops the game, as an error in `update()` does: the game
70
+ fails in the `clock` phase (`handle.failure.phase` is `"clock"`), and a
71
+ `runtime-error` diagnostic reports `clock failed: …`. The other callbacks
72
+ due on that tick still run, but `update()` and `draw()` don't.
73
+
74
+ A `Clock` you make yourself with `new Clock()` keeps going instead: it logs
75
+ the error to the console and unschedules only that callback.
76
+ `new Clock({ onError })` hands the error to `onError` instead of logging it.
77
+
78
+ ## Animation
79
+
80
+ ### `animate(object, options)`
81
+
82
+ ```ts
83
+ function animate<T extends object>(
84
+ object: T,
85
+ options: AnimationOptions<T>,
86
+ ): Animation<T>;
87
+ ```
88
+
89
+ Smoothly interpolates one or more numeric properties on `object` over time.
90
+ Any key in `options` other than `tween`, `duration`, and `onFinished` is
91
+ treated as a target value for a same-named property that must already exist
92
+ on `object` — animating a property `object` doesn't have throws an error.
93
+
94
+ ```js
95
+ animate(player, { x: 300, y: 120, duration: 0.5, tween: "decelerate" });
96
+ ```
97
+
98
+ - `duration` — seconds, default `1`.
99
+ - `tween` — the easing curve name (see the table below), default
100
+ `"linear"`. An unknown name throws with a "did you mean ...?" suggestion.
101
+ - `onFinished` — called once, when the animation reaches its target. It
102
+ isn't called when the animation is stopped, even with `stop(true)`.
103
+ - Each target value must be a finite number, or an array of finite numbers
104
+ matching the shape of the property's current value (e.g. animating a
105
+ `[x, y]`-shaped property to another two-number array).
106
+
107
+ Starting a new `animate()` call for a property that's already mid-animation
108
+ replaces just that property's animation; other properties being animated by
109
+ an earlier call keep running.
110
+
111
+ `animate()` returns an `Animation` instance:
112
+
113
+ - `.running: boolean`
114
+ - `.stop(complete = false)` — stops the animation. `stop(true)` jumps the
115
+ properties to their final values first. Neither calls `onFinished`.
116
+ - `.removeTarget(property)` — stops animating a single property, leaving
117
+ any others on the same call running.
118
+
119
+ ### Tween names
120
+
121
+ | Name | What the motion looks like |
122
+ | ---------------- | ---------------------------------------------------------------------------- |
123
+ | `linear` | Constant speed. |
124
+ | `easeIn` | Starts slow, speeds up (CSS's name). Same as `accelerate`. |
125
+ | `easeOut` | Starts fast, slows to a stop (CSS's name). Same as `decelerate`. |
126
+ | `easeInOut` | Speeds up, then slows down (CSS's name). Same as `accelDecel`. |
127
+ | `bounce` | Bounces to a stop at the target, like a dropped ball. Same as `bounceEnd`. |
128
+ | `spring` | Shoots past the target, then wobbles back and settles. Same as `outElastic`. |
129
+ | `accelerate` | Starts slow, speeds up. |
130
+ | `decelerate` | Starts fast, eases to a stop. |
131
+ | `accelDecel` | Eases in, then eases out. |
132
+ | `inElastic` | Wobbles around the starting point, then snaps to the target at the end. |
133
+ | `outElastic` | Shoots past the target right away, then wobbles back and settles. |
134
+ | `inOutElastic` | Wobbles at the start, then again around the target. |
135
+ | `bounceEnd` | Bounces to a stop at the target, like a dropped ball. |
136
+ | `bounceStart` | Bounces around the starting point, then heads for the target. |
137
+ | `bounceStartEnd` | Bounces at both ends. |
138
+ | `endElastic` | Same as `inElastic`: the wobble comes near the end. |
139
+ | `startElastic` | Same as `outElastic`: the wobble comes near the start. |
140
+ | `bothElastic` | Same as `inOutElastic`. |
141
+
142
+ That's all 18 names `tween` accepts: Pygame Zero's 10 curves, the five
143
+ plain-language names, and `endElastic`, `startElastic` and `bothElastic`,
144
+ names from Pygame Zero's older docs (`end_elastic` and so on) that its code
145
+ doesn't accept. To check a name in code, import the same list as
146
+ `tweenNames` (`import { tweenNames } from "js-game-zero"`); it isn't a
147
+ global in a game file. Like every other name, they're camelCase:
148
+ `tween: "bounce_end"` throws, suggesting `bounceEnd`. If you're not
149
+ sure which to pick, try `easeOut` for smooth movement, `bounce` for things
150
+ that land, and `spring` for things that pop into place.
@@ -0,0 +1,46 @@
1
+ # Helpers
2
+
3
+ Small functions for things almost every game needs. In a game file they're
4
+ ready to use, like `screen` and `Actor`; in import mode, import them from
5
+ `js-game-zero`.
6
+
7
+ ## `randomInt(min, max)`
8
+
9
+ A random whole number from `min` to `max`, **including both ends**.
10
+
11
+ ```js
12
+ let roll = randomInt(1, 6); // a die: 1, 2, 3, 4, 5 or 6
13
+ let x = randomInt(20, WIDTH - 20); // somewhere across the screen
14
+ ```
15
+
16
+ Fractional ends are rounded inward (`randomInt(0.5, 3.5)` picks 1, 2 or 3).
17
+ Putting the bigger number first throws an error that says so.
18
+
19
+ ## `randomChoice(list)`
20
+
21
+ A random item from a list.
22
+
23
+ ```js
24
+ let color = randomChoice(["red", "gold", "skyblue"]);
25
+ ball.vx = randomChoice([-200, 200]); // left or right
26
+ ```
27
+
28
+ An empty list throws, since there's nothing to choose.
29
+
30
+ ## `clamp(value, min, max)`
31
+
32
+ `value`, moved inside `min`–`max` if it's outside; values already inside
33
+ come back unchanged.
34
+
35
+ ```js
36
+ player.x = clamp(player.x, 0, WIDTH);
37
+ plane.angle = clamp(-plane.vy / 8, -25, 75);
38
+ ```
39
+
40
+ To keep a whole sprite on screen, `player.clampIp(screen.bounds())` (see
41
+ [`actor.md`](actor.md)) uses the sprite's real edges.
42
+
43
+ ## `rgb(red, green, blue, alpha?)`
44
+
45
+ A color mixed from red, green and blue, each `0`–`255`, as in
46
+ `rgb(255, 140, 105)`. See [Colors](screen.md#colors).
@@ -0,0 +1,379 @@
1
+ # Hooks And Input Constants
2
+
3
+ Your game is a set of top-level functions and settings. The runtime calls the
4
+ functions it recognizes, in zero-boilerplate mode as plain `function`
5
+ declarations and in import mode as properties on the object you pass to
6
+ `run()`. This page documents the settings, every hook, then the `keys`,
7
+ `keymods`, and `mouse` constant tables used by the input hooks.
8
+
9
+ Hook names are camelCase (`onKeyDown`, `onMouseDown`, ...), and work the
10
+ same way in both modes. (A game made with `defineGame()` is the exception:
11
+ its input hooks receive one event object — see [`runtime.md`](runtime.md).)
12
+ A hook spelled another way, such as Pygame Zero's `on_key_down`, is never
13
+ called; the runtime warns about it with a `hook-typo` diagnostic that names
14
+ the camelCase hook to rename it to.
15
+
16
+ A hook's arguments are matched **by parameter name** first. The runtime reads
17
+ your function's declared parameter names and passes the value with that name,
18
+ in whatever order you wrote them. That means
19
+ `function onKeyDown(mod, key) {}` receives `mod` and `key` correctly even
20
+ though the "natural" order is `key, mod`.
21
+
22
+ A parameter with any other name receives the next value in the hook's
23
+ documented order that isn't already taken by name, just like an ordinary
24
+ JavaScript function: `function onKeyDown(k) {}` gets the key, and
25
+ `function onMouseDown(position) {}` gets `pos`. The runtime adds a
26
+ `hook-parameter` warning saying which value such a parameter receives, since
27
+ `onMouseDown(btn)` gets the position, not the button. Name your parameters
28
+ as shown below to avoid the warning.
29
+
30
+ One name is different: a hook whose only parameter is called `event`
31
+ receives all of its values in one object, as a `defineGame()` hook does, so
32
+ `function onKeyDown(event) {}` reads `event.key` and `event.mod`.
33
+
34
+ ## Settings
35
+
36
+ Set these at the top of a game, like `WIDTH = 480;`.
37
+
38
+ | Setting | What it does | Default |
39
+ | ---------------- | ---------------------------------------------------------------------------------------------------------- | ------------------------ |
40
+ | `WIDTH` | The game's width in pixels, rounded down to a whole number. `screen` and the mouse use it. | `800` |
41
+ | `HEIGHT` | The game's height in pixels, rounded down to a whole number. | `600` |
42
+ | `TITLE` | The page's title, shown on its tab. | The page's own title |
43
+ | `ICON` | The name of an image in `images/`, as `Actor` takes it (`ICON = "ship";`), shown as the page's icon. | The page's own icon |
44
+ | `PIXEL_DENSITY` | How many canvas pixels each game pixel gets. See [`screen.md`](screen.md#pixel_density-and-screendensity). | The device's pixel ratio |
45
+ | `TOUCH_CONTROLS` | On-screen buttons for touch screens. See [Touch controls](#touch-controls). | None |
46
+
47
+ A `WIDTH` or `HEIGHT` that isn't a positive number is ignored, with an
48
+ `invalid-config` warning, and so is an `ICON` that isn't an image name. In
49
+ import mode, put the settings on the game module or in `run()`'s options
50
+ (see [`runtime.md`](runtime.md#runoptions)).
51
+
52
+ ## draw()
53
+
54
+ ```ts
55
+ function draw(): void;
56
+ ```
57
+
58
+ Called once per animation frame after `update` and after any pending assets
59
+ have loaded. `draw` must not declare any parameters — `run()` throws a
60
+ `TypeError` at startup if it does, since a `draw(dt)` typo (mixing it up with
61
+ `update`) is a common beginner mistake worth catching immediately.
62
+
63
+ ```js
64
+ function draw() {
65
+ screen.fill("#0f172a");
66
+ screen.draw.filledCircle([160, 90], 40, "gold");
67
+ }
68
+ ```
69
+
70
+ ## update() / update(dt)
71
+
72
+ ```ts
73
+ function update(): void;
74
+ function update(dt: number): void;
75
+ ```
76
+
77
+ Called once per frame, before `draw`. Declare zero parameters if you don't
78
+ need frame timing, or one parameter (conventionally named `dt`) to receive the
79
+ seconds elapsed since the previous frame — use it to make movement
80
+ frame-rate-independent. When the game runs on its own, `dt` is clamped to at
81
+ most `0.25` seconds so a dropped frame (e.g. the tab was backgrounded) can't
82
+ cause a huge jump. A host stepping the game itself, as `handle.step(dt)` and
83
+ the CLI's `step` do, passes its `dt` through unchanged.
84
+
85
+ ```js
86
+ function update(dt) {
87
+ if (keyboard.right) player.x += 200 * dt; // 200 px/sec, any frame rate
88
+ }
89
+ ```
90
+
91
+ ## onKeyDown(key, mod, unicode, repeat) / onKeyUp(key, mod, unicode, repeat)
92
+
93
+ ```ts
94
+ function onKeyDown(
95
+ key: number,
96
+ mod: number,
97
+ unicode: string,
98
+ repeat: boolean,
99
+ ): void;
100
+ function onKeyUp(
101
+ key: number,
102
+ mod: number,
103
+ unicode: string,
104
+ repeat: boolean,
105
+ ): void;
106
+ ```
107
+
108
+ Fired on `keydown`/`keyup`.
109
+
110
+ - `key` — **a numeric key constant from `keys`**, not a string. This is the
111
+ single most common mistake when porting from other frameworks: compare it
112
+ with `key === keys.LEFT`, never `key === "left"` or `key === "ArrowLeft"`.
113
+ - `mod` — a bitmask of currently-held modifier keys from `keymods` (see
114
+ below). Test a specific modifier with `mod & keymods.SHIFT`.
115
+ - `unicode` — the typed character as a one-character string (`""` for
116
+ non-printable keys like arrows or function keys).
117
+ - `repeat` — `true` if this event is an OS-generated key-repeat while the key
118
+ is held down, rather than the initial press. It's always `false` for
119
+ `onKeyUp`.
120
+
121
+ ```js
122
+ function onKeyDown(key, mod) {
123
+ if (key === keys.SPACE) jump();
124
+ if (key === keys.R && mod & keymods.CTRL) restartLevel();
125
+ }
126
+ ```
127
+
128
+ `keyboard.left`, `keyboard.a`, and similar boolean properties (see below) are
129
+ usually a better fit for continuous movement inside `update`; use
130
+ `onKeyDown`/`onKeyUp` for one-shot actions like jumping or firing.
131
+
132
+ ## Touch controls
133
+
134
+ Set `TOUCH_CONTROLS` near `WIDTH` and `HEIGHT` to add controls below your
135
+ game on phones, tablets, and computers with touch input. The runtime fits
136
+ the canvas into the space above the controls, preserving its aspect ratio
137
+ and logical `WIDTH`/`HEIGHT`. Keyboard code works with these buttons too:
138
+
139
+ ```js
140
+ TOUCH_CONTROLS = {
141
+ left: keys.LEFT,
142
+ right: keys.RIGHT,
143
+ a: keys.SPACE,
144
+ start: keys.RETURN,
145
+ };
146
+ ```
147
+
148
+ In portrait mode, the dock places the D-pad on the left and the action
149
+ buttons on the right, with Start/Select beneath them; a game with no A or B
150
+ puts Start/Select on the right instead. A sits above and to the right of B
151
+ in a Game Boy-style diagonal arrangement. Three or four directions join into
152
+ one cross; left and right alone (or up and down) stay two separate keys. The
153
+ dock stays below the canvas in both portrait and landscape layouts, near the
154
+ bottom of the game's viewport. In portrait, the canvas is centered
155
+ vertically with at least 48px above the control dock. On shorter screens it
156
+ moves upward as needed to keep the game and controls visible. Landscape
157
+ keeps a 16px gap. Bottom padding keeps buttons clear of the device's home
158
+ indicator.
159
+
160
+ Only the buttons you list appear. Supported names are `up`, `down`, `left`,
161
+ `right`, `a`, `b`, `start`, and `select`. Each value must be a numeric
162
+ constant from `keys`; the button's label is independent of its mapped key.
163
+ For example, `a: keys.SPACE` makes A trigger a game's existing Space action.
164
+ Omitting `TOUCH_CONTROLS`, or setting it to `false`, hides the controls.
165
+
166
+ `TOUCH_CONTROLS = true` enables this full preset:
167
+
168
+ | Button | Mapped key |
169
+ | ------------------------ | ---------------------------------------------------- |
170
+ | Up / Down / Left / Right | `keys.UP` / `keys.DOWN` / `keys.LEFT` / `keys.RIGHT` |
171
+ | A | `keys.SPACE` |
172
+ | B | `keys.X` |
173
+ | Start | `keys.RETURN` |
174
+ | Select | `keys.ESCAPE` |
175
+
176
+ The default `show: "auto"` displays controls when the browser reports touch
177
+ support or a coarse pointing device. Add `show: "always"` to a mapping to
178
+ preview them on desktop. These are native buttons, so mouse clicks and
179
+ Tab followed by Space or Enter work as well.
180
+
181
+ Holding a button updates `keyboard` and fires `onKeyDown` once; releasing
182
+ it fires `onKeyUp`. Virtual presses have `mod: keymods.NONE`,
183
+ `unicode: ""`, and `repeat: false`; use `update(dt)` for repeated actions.
184
+ Multiple fingers can hold directions and action buttons together. Slide a
185
+ finger across the D-pad to change direction. Each mapped key stays held
186
+ until every touch button and physical key holding it has
187
+ been released. Cancellation, loss of pointer capture, leaving the window,
188
+ and hiding the page clear held inputs. Stopping or reloading a game removes
189
+ its controls and listeners.
190
+
191
+ A page that hosts a game can restyle the dock by setting these CSS custom
192
+ properties on any element around the canvas, such as `:root`:
193
+
194
+ | Property | What it sets | Default |
195
+ | -------------------------------------------------- | -------------------------------------------------------------------- | --------------------------------------- |
196
+ | `--jgz-key-size` | A key's size; the cross is three keys across | `clamp(40px, 10vw, 52px)` |
197
+ | `--jgz-key-fill`, `--jgz-key-ink` | A key's fill, and its label and arrow color | `#263244`, `#fff` |
198
+ | `--jgz-key-line`, `--jgz-key-line-width` | A key's outline | `#718096`, `2px` |
199
+ | `--jgz-key-pressed-fill`, `--jgz-key-pressed-line` | A held key's fill and outline | `#4267a0`, `#b9d5ff` |
200
+ | `--jgz-key-shadow-x`, `-y`, `-color` | A hard shadow under each key and the cross; a held key moves onto it | `0px`, `0px`, `transparent` |
201
+ | `--jgz-key-radius` | Separate keys' corners (any `border-radius`) | `12px` |
202
+ | `--jgz-dpad-radius` | The cross's outer corners | `10px` |
203
+ | `--jgz-dpad-dot` | The dot in the middle of the cross | `rgba(255, 255, 255, 0.16)` |
204
+ | `--jgz-key-font`, `--jgz-action-font` | Start/Select labels, and A/B labels (a `font` shorthand) | `bold 13px` and `bold 18px` `system-ui` |
205
+ | `--jgz-action-line-width` | A and B's outline | `--jgz-key-line-width` |
206
+ | `--jgz-system-height`, `--jgz-system-radius` | Start and Select's height and corners | `40px`, `12px` |
207
+ | `--jgz-focus-ring` | The keyboard focus outline | `#facc15` |
208
+ | `--jgz-dock-gap` | The least space between the canvas and the dock | `48px` portrait, `16px` landscape |
209
+
210
+ In import mode, put `TOUCH_CONTROLS` on the module returned by `defineGame`,
211
+ on a raw game module, or in the options passed to `run`. TypeScript exports
212
+ `TouchButton`, `TouchControlsConfig`, and `TouchControlsOptions`.
213
+
214
+ ### Tapping and dragging the canvas
215
+
216
+ Canvas touch and pen input work even without a control dock. A primary
217
+ touch triggers `onMouseDown`, dragging triggers `onMouseMove` with
218
+ `mouse.LEFT` in `buttons`, and releasing or cancelling triggers
219
+ `onMouseUp`. Positions and movement are converted to logical game
220
+ coordinates when the canvas is scaled. The pointer remains captured when
221
+ it leaves the canvas; extra canvas touches are ignored until the first is
222
+ released. Touch buttons do not trigger canvas mouse hooks.
223
+
224
+ The canvas and control buttons disable native touch panning during play;
225
+ the surrounding page retains its normal gestures. Games can therefore use
226
+ tap-to-flap or drag-to-steer without adding separate touch hooks.
227
+
228
+ For embedding, give each canvas a parent with a defined height. While the
229
+ dock is visible, the runtime groups the canvas and controls into a column
230
+ that fills the available space, anchors controls at the bottom, and centers
231
+ the portrait canvas when space permits. It accounts for visible siblings,
232
+ padding, and row gaps, and restores the original canvas placement when the
233
+ dock is hidden or the game stops.
234
+ The sandbox preview handles this automatically.
235
+
236
+ ## onMouseDown(pos, button) / onMouseUp(pos, button)
237
+
238
+ ```ts
239
+ function onMouseDown(pos: [number, number], button: number): void;
240
+ function onMouseUp(pos: [number, number], button: number): void;
241
+ ```
242
+
243
+ Fired on `mousedown`/`mouseup`, and also for **wheel scroll**: a wheel event
244
+ is reported as `onMouseDown` with `button` set to `mouse.WHEEL_UP` or
245
+ `mouse.WHEEL_DOWN` (matching pygame's convention of treating the scroll wheel
246
+ as buttons 4 and 5, rather than a separate event). There is no
247
+ `onMouseWheel` hook — check `button` inside `onMouseDown` instead.
248
+
249
+ ```js
250
+ function onMouseDown(pos, button) {
251
+ if (button === mouse.LEFT) fireAt(pos);
252
+ if (button === mouse.WHEEL_UP) zoom += 1;
253
+ if (button === mouse.WHEEL_DOWN) zoom -= 1;
254
+ }
255
+ ```
256
+
257
+ ## onMouseMove(pos, rel, buttons)
258
+
259
+ ```ts
260
+ function onMouseMove(
261
+ pos: [number, number],
262
+ rel: [number, number],
263
+ buttons: Set<number>,
264
+ ): void;
265
+ ```
266
+
267
+ Fired on `mousemove`. `rel` is the movement since the previous event (from
268
+ the browser's `movementX`/`movementY` when available). `buttons` is a `Set`
269
+ of currently held mouse buttons (`mouse.LEFT`, `mouse.MIDDLE`, `mouse.RIGHT`)
270
+ — check membership with `buttons.has(mouse.LEFT)`.
271
+
272
+ ## onMusicEnd()
273
+
274
+ ```ts
275
+ function onMusicEnd(): void;
276
+ ```
277
+
278
+ Fired once the active `music` track (and any queued tracks) finish playing
279
+ with nothing left to play.
280
+
281
+ ## `keyboard`
282
+
283
+ `keyboard` is a live object of boolean properties reflecting which keys are
284
+ currently held down, one for each key in `keys` under the same name in any
285
+ capitalization (`keyboard.left`, `keyboard.space`, `keyboard.a`, and
286
+ `keyboard.K_1` for the digit keys). Read it inside `update()` for continuous
287
+ movement:
288
+
289
+ ```js
290
+ function update(dt) {
291
+ if (keyboard.left) player.x -= 150 * dt;
292
+ if (keyboard.right) player.x += 150 * dt;
293
+ }
294
+ ```
295
+
296
+ Accessing an attribute that isn't a real key name throws an error (`The key
297
+ "..." does not exist`) instead of silently returning `false` — this catches
298
+ typos like `keyboard.lfet` immediately rather than letting your character
299
+ quietly fail to move. A misspelling says which key it's closest to:
300
+ `keyboard.lfet doesn't exist. Did you mean keyboard.left?`. `keyboard.pressed()` returns a sorted array of every
301
+ currently-held key constant, for debugging.
302
+
303
+ ## `keys`
304
+
305
+ Numeric key constants, one property per key. The full set includes:
306
+
307
+ | Category | Names |
308
+ | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
309
+ | Letters | `keys.A` … `keys.Z` |
310
+ | Digits | `keys.K_0` … `keys.K_9` |
311
+ | Arrows | `keys.UP`, `keys.DOWN`, `keys.LEFT`, `keys.RIGHT` |
312
+ | Editing | `keys.BACKSPACE`, `keys.TAB`, `keys.RETURN` (alias `keys.ENTER`), `keys.DELETE`, `keys.ESCAPE`, `keys.SPACE` |
313
+ | Function keys | `keys.F1` … `keys.F15` |
314
+ | Navigation | `keys.HOME`, `keys.END`, `keys.PAGEUP`, `keys.PAGEDOWN`, `keys.INSERT` |
315
+ | Modifiers (as key presses) | `keys.LSHIFT`, `keys.RSHIFT`, `keys.LCTRL`, `keys.RCTRL`, `keys.LALT`, `keys.RALT`, `keys.LMETA`, `keys.RMETA` |
316
+ | Numpad | `keys.KP0` … `keys.KP9`, `keys.KP_PERIOD`, `keys.KP_DIVIDE`, `keys.KP_MULTIPLY`, `keys.KP_MINUS`, `keys.KP_PLUS`, `keys.KP_ENTER`, `keys.KP_EQUALS` |
317
+ | Punctuation | `keys.MINUS`, `keys.EQUALS`, `keys.LEFTBRACKET`, `keys.RIGHTBRACKET`, `keys.BACKSLASH`, `keys.SEMICOLON`, `keys.QUOTE`, `keys.BACKQUOTE`, `keys.COMMA`, `keys.PERIOD`, `keys.SLASH` |
318
+ | Locks | `keys.CAPSLOCK`, `keys.NUMLOCK`, `keys.SCROLLOCK` |
319
+
320
+ The values are arbitrary integers (matching SDL/pygame's numbering) — never
321
+ hardcode them, always compare against the named constant. Constants are
322
+ upper case. In a game file, any other spelling such as `keys.space` or
323
+ `keys.SPCE` throws with a suggestion (`Did you mean keys.SPACE?`) instead of
324
+ quietly comparing against `undefined`. The same goes for `keymods` and
325
+ `mouse`.
326
+
327
+ ## `keymods`
328
+
329
+ A bitmask of held modifier keys, combined with `|` and tested with `&`:
330
+
331
+ | Constant | Meaning |
332
+ | ----------------------------------- | ----------------------------------------- |
333
+ | `keymods.NONE` | No modifier held |
334
+ | `keymods.SHIFT` | Either Shift key (`LSHIFT \| RSHIFT`) |
335
+ | `keymods.CTRL` | Either Control key (`LCTRL \| RCTRL`) |
336
+ | `keymods.ALT` | Either Alt/Option key (`LALT \| RALT`) |
337
+ | `keymods.META` | Either Cmd/Windows key (`LMETA \| RMETA`) |
338
+ | `keymods.LSHIFT` / `keymods.RSHIFT` | Left/right Shift specifically |
339
+ | `keymods.LCTRL` / `keymods.RCTRL` | Left/right Control specifically |
340
+ | `keymods.LALT` / `keymods.RALT` | Left/right Alt specifically |
341
+ | `keymods.LMETA` / `keymods.RMETA` | Left/right Cmd/Windows specifically |
342
+ | `keymods.CAPS` | Caps Lock is toggled on |
343
+ | `keymods.NUM` | Num Lock is toggled on |
344
+ | `keymods.MODE` | AltGr / alternate-graphics modifier |
345
+
346
+ ```js
347
+ function onKeyDown(key, mod) {
348
+ if (mod & keymods.SHIFT) console.log("shift-modified key");
349
+ }
350
+ ```
351
+
352
+ ## `mouse`
353
+
354
+ In a game file, `mouse` also says where the mouse is right now, for code in
355
+ `update()` that follows or aims at it — the way `keyboard` does for keys:
356
+
357
+ | Property | Meaning |
358
+ | --------------- | ----------------------------------------------------------------------------- |
359
+ | `mouse.pos` | `[x, y]` of the mouse (or a finger) over the game. The center until it moves. |
360
+ | `mouse.x` | The same `x`. |
361
+ | `mouse.y` | The same `y`. |
362
+ | `mouse.buttons` | A `Set` of buttons held now: `mouse.buttons.has(mouse.LEFT)`. |
363
+ | `mouse.down` | `true` while any button, or a finger, is down. |
364
+
365
+ ```js
366
+ function update(dt) {
367
+ ship.angle = ship.angleTo(mouse.pos); // aim at the mouse
368
+ }
369
+ ```
370
+
371
+ Button constants:
372
+
373
+ | Constant | Value | Meaning |
374
+ | ------------------ | ----- | ---------------------------------------------------- |
375
+ | `mouse.LEFT` | 1 | Left mouse button |
376
+ | `mouse.MIDDLE` | 2 | Middle mouse button (wheel click) |
377
+ | `mouse.RIGHT` | 3 | Right mouse button |
378
+ | `mouse.WHEEL_UP` | 4 | Scroll wheel moved up (reported via `onMouseDown`) |
379
+ | `mouse.WHEEL_DOWN` | 5 | Scroll wheel moved down (reported via `onMouseDown`) |
@@ -0,0 +1,2 @@
1
+ /** js-game-zero's API reference: every page's Markdown by its file name, such as "actor.md". */
2
+ export declare const reference: Readonly<Record<string, string>>;