zx-kit 0.2.3 → 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.
package/README.md CHANGED
@@ -195,7 +195,7 @@ Wraps the Web Audio API for authentic 1-bit square-wave sound. All audio goes th
195
195
 
196
196
  #### `initAudio(volume?): void`
197
197
 
198
- Creates the `AudioContext` and master gain. Idempotent — safe to call multiple times.
198
+ Creates the `AudioContext` and master gain. Idempotent — safe to call multiple times. `volume` is clamped to 0.0–1.0.
199
199
 
200
200
  ```ts
201
201
  window.addEventListener('keydown', () => initAudio(), { once: true })
@@ -214,6 +214,33 @@ Returns the current context, or `null` before `initAudio()`.
214
214
 
215
215
  Returns the master gain node. Connect custom oscillators here to respect global volume.
216
216
 
217
+ #### `getMasterVolume(): number`
218
+
219
+ Returns the current master volume (0.0–1.0), or `0` before `initAudio()`.
220
+
221
+ #### `setMasterVolume(volume): void`
222
+
223
+ Sets master volume. Clamped to 0.0–1.0. No-op before `initAudio()`.
224
+
225
+ ```ts
226
+ setMasterVolume(0.5) // 50%
227
+ setMasterVolume(0) // mute
228
+ setMasterVolume(1) // full
229
+ ```
230
+
231
+ #### `increaseVolume(): void` / `decreaseVolume(): void`
232
+
233
+ Adjusts master volume by ±0.1, clamped at 0.0–1.0.
234
+
235
+ ```ts
236
+ // Volume keys
237
+ if (consumeAnyKey()) increaseVolume() // example: + key
238
+ decreaseVolume() // example: - key
239
+
240
+ // Current state
241
+ const vol = getMasterVolume() // e.g. 0.4 after one increaseVolume()
242
+ ```
243
+
217
244
  #### `Note` interface
218
245
 
219
246
  ```ts
@@ -271,11 +298,11 @@ type Direction = 'up' | 'down' | 'left' | 'right'
271
298
 
272
299
  #### `initInput(repeatDelay?, repeatInterval?): void`
273
300
 
274
- Attaches `keydown`/`keyup` listeners. Keys: arrows = movement, `F` = flag, `P` = pause, `Ctrl+Shift+B` = debug.
301
+ Attaches `keydown`/`keyup` listeners. Idempotent — timing params are always updated; listeners are only attached on the first call. Keys: arrows = movement, `F` = flag, `P` = pause, `Ctrl+Shift+B` = debug.
275
302
 
276
303
  ```ts
277
304
  initInput() // 150ms delay, 80ms repeat
278
- initInput(200, 60) // custom timing
305
+ initInput(200, 60) // custom timing; safe to call again to reconfigure
279
306
  ```
280
307
 
281
308
  #### `tickMovement(dtMs): Direction | null`
@@ -306,6 +333,140 @@ Returns whether a key is currently held. Argument is `KeyboardEvent.key`.
306
333
  if (isHeld('ArrowUp')) { ... }
307
334
  ```
308
335
 
336
+ #### `resetInput(): void`
337
+
338
+ Clears all pending key state immediately. Call on game phase transitions to prevent stale inputs carrying over.
339
+
340
+ ```ts
341
+ appPhase = 'gameover'
342
+ resetInput() // discard any queued keypresses from the previous phase
343
+ ```
344
+
345
+ ---
346
+
347
+ ### `ui.ts` — ZX-style UI primitives
348
+
349
+ High-level drawing helpers and a stateful widget system for HUD elements.
350
+ All primitives operate in game pixels and enforce the Spectrum palette via `SpectrumColor`.
351
+
352
+ #### Types
353
+
354
+ **`BorderOptions`**
355
+
356
+ | Field | Type | Default | Description |
357
+ |-------|------|---------|-------------|
358
+ | `enabled` | `boolean` | `true` | Set to `false` to suppress the border without removing the object |
359
+ | `thickness` | `number` | `1` | Border thickness in pixels |
360
+ | `color` | `SpectrumColor` | same as ink/color | Overrides the parent function's foreground color |
361
+ | `style` | `'solid' \| 'dashed'` | `'solid'` | Solid = continuous lines; dashed = 2 px on / 2 px off |
362
+
363
+ **`DrawProgressBarOptions`**
364
+
365
+ | Field | Type | Default | Description |
366
+ |-------|------|---------|-------------|
367
+ | `id` | `string` | `"${x},${y}"` | Stable key for managed redraws |
368
+ | `x` | `number` | — | Left edge in game pixels |
369
+ | `y` | `number` | — | Top edge in game pixels |
370
+ | `width` | `number` | — | Total width in game pixels (multiples of `CELL = 8` recommended) |
371
+ | `value` | `number` | — | Current value |
372
+ | `min` | `number` | `0` | Value at the left (empty) edge |
373
+ | `max` | `number` | `1` | Value at the right (full) edge |
374
+ | `ink` | `SpectrumColor` | `C.B_WHITE` | Filled-block color |
375
+ | `paper` | `SpectrumColor` | `C.BLACK` | Empty-block background |
376
+ | `border` | `BorderOptions` | — | Optional border around the bar |
377
+ | `visibilityLength` | `number` | `500` | Ms to stay visible after last call; `0` = permanent |
378
+
379
+ #### Stateless primitives
380
+
381
+ ##### `drawBox(ctx, options): void`
382
+
383
+ Fills a rectangle with `paper` and draws an optional border.
384
+
385
+ ```ts
386
+ drawBox(ctx, {
387
+ x: 8, y: 8, width: 112, height: 40,
388
+ paper: C.BLACK, ink: C.B_WHITE,
389
+ border: { style: 'solid', thickness: 1 },
390
+ })
391
+ ```
392
+
393
+ ##### `drawFrame(ctx, options): void`
394
+
395
+ Draws a border only — no background fill.
396
+
397
+ ```ts
398
+ drawFrame(ctx, { x: 0, y: 0, width: 256, height: 176, color: C.B_CYAN })
399
+ drawFrame(ctx, { x: 16, y: 16, width: 64, height: 32, color: C.B_RED,
400
+ border: { style: 'dashed' } })
401
+ ```
402
+
403
+ ##### `drawPanelTitle(ctx, options): void`
404
+
405
+ Renders a text strip (height = `CELL + padding * 2`) with optional background fill.
406
+ Does NOT draw the surrounding container — use `drawBox` / `drawFrame` separately.
407
+
408
+ ```ts
409
+ drawBox(ctx, { x: 8, y: 24, width: 128, height: 56, paper: C.BLACK })
410
+ drawPanelTitle(ctx, {
411
+ text: 'OPTIONS', x: 8, y: 24,
412
+ ink: C.B_YELLOW, paper: C.BLACK,
413
+ centered: true, width: 128,
414
+ })
415
+ ```
416
+
417
+ #### Stateful widget — progress bar
418
+
419
+ The progress bar is a managed widget: after a `drawProgressBar` call, the bar is
420
+ re-rendered automatically on subsequent frames by `renderUI` until `visibilityLength`
421
+ milliseconds have elapsed. Calling `drawProgressBar` again resets the timer.
422
+
423
+ ##### `drawProgressBar(ctx, options): void`
424
+
425
+ Draws the bar immediately **and** registers it for managed redraws.
426
+
427
+ ```ts
428
+ // On value change:
429
+ drawProgressBar(ctx, {
430
+ id: 'volume', x: 88, y: 88, width: 80,
431
+ value: getMasterVolume(),
432
+ ink: C.B_GREEN, paper: C.BLACK,
433
+ border: { style: 'solid' },
434
+ visibilityLength: 1500,
435
+ })
436
+
437
+ // Permanent HUD element:
438
+ drawProgressBar(ctx, {
439
+ id: 'health', x: 0, y: 184, width: 40,
440
+ value: lives, min: 0, max: 3,
441
+ ink: C.B_GREEN, paper: C.BLACK,
442
+ visibilityLength: 0,
443
+ })
444
+ ```
445
+
446
+ ##### `tickUI(dtMs): void`
447
+
448
+ Advances all managed bar timers. Expired bars are removed. Call once per frame.
449
+
450
+ ##### `renderUI(ctx): void`
451
+
452
+ Redraws all currently visible bars. Call every frame **after** the game world render.
453
+
454
+ ##### `resetUI(): void`
455
+
456
+ Clears all managed state. Call alongside `resetInput()` on phase transitions.
457
+
458
+ ```ts
459
+ // Typical game loop:
460
+ renderFrame(ctx, state)
461
+ tickUI(dt)
462
+ renderUI(ctx)
463
+
464
+ // Phase transition:
465
+ resetInput()
466
+ resetUI()
467
+ appPhase = 'intro'
468
+ ```
469
+
309
470
  ---
310
471
 
311
472
  ## File structure
@@ -322,9 +483,14 @@ zx-kit/
322
483
  │ ├── renderer.ts # setupCanvas, mirrorSprite, drawSprite, drawChar, drawText,
323
484
  │ │ # drawTextCentered, flashBorder
324
485
  │ ├── audio.ts # initAudio, resumeAudio, beep, playPattern, Note,
325
- │ │ # getAudioContext, getMasterGain
326
- └── input.ts # initInput, tickMovement, consumeFlag/Debug/Pause/AnyKey,
327
- # isHeld, Direction
486
+ │ │ # getAudioContext, getMasterGain,
487
+ # getMasterVolume, setMasterVolume,
488
+ # increaseVolume, decreaseVolume
489
+ │ ├── input.ts # initInput, tickMovement, consumeFlag/Debug/Pause/AnyKey,
490
+ │ │ # isHeld, resetInput, Direction
491
+ │ └── ui.ts # drawBox, drawFrame, drawPanelTitle,
492
+ │ # drawProgressBar, tickUI, renderUI, resetUI,
493
+ │ # BorderOptions, DrawProgressBarOptions
328
494
  └── dist/ # compiled output (generated by npm run build)
329
495
  ├── index.js / .d.ts
330
496
  └── ...
package/dist/audio.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * multiple times (subsequent calls are no-ops).
4
4
  * Must be called inside a user-gesture handler (click or keydown) due to browser autoplay policy.
5
5
  *
6
- * @param volume - Master gain value (0.0–1.0, default `0.3`)
6
+ * @param volume - Master gain value (0.0–1.0, default `0.3`). Clamped to valid range.
7
7
  *
8
8
  * @example
9
9
  * window.addEventListener('keydown', () => initAudio(), { once: true })
@@ -36,6 +36,37 @@ export declare function getAudioContext(): AudioContext | null;
36
36
  * osc.connect(getMasterGain()!)
37
37
  */
38
38
  export declare function getMasterGain(): GainNode | null;
39
+ /**
40
+ * Returns the current master volume (0.0–1.0), or `0` before `initAudio()`.
41
+ *
42
+ * @example
43
+ * const vol = getMasterVolume() // e.g. 0.3
44
+ */
45
+ export declare function getMasterVolume(): number;
46
+ /**
47
+ * Sets the master volume. Clamped to 0.0–1.0. No-op before `initAudio()`.
48
+ *
49
+ * @param volume - Target gain value (0.0–1.0)
50
+ *
51
+ * @example
52
+ * setMasterVolume(0.5) // 50%
53
+ * setMasterVolume(0) // mute
54
+ */
55
+ export declare function setMasterVolume(volume: number): void;
56
+ /**
57
+ * Increases master volume by 0.1, up to a maximum of 1.0.
58
+ *
59
+ * @example
60
+ * increaseVolume() // 0.3 → 0.4
61
+ */
62
+ export declare function increaseVolume(): void;
63
+ /**
64
+ * Decreases master volume by 0.1, down to a minimum of 0.0.
65
+ *
66
+ * @example
67
+ * decreaseVolume() // 0.3 → 0.2
68
+ */
69
+ export declare function decreaseVolume(): void;
39
70
  /** A single note in a melody pattern. Use `freq: 0` for a rest (silence). */
40
71
  export interface Note {
41
72
  freq: number;
@@ -1 +1 @@
1
- {"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,MAAM,SAAM,GAAG,IAAI,CAM5C;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,IAAI,YAAY,GAAG,IAAI,CAErD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,IAAI,QAAQ,GAAG,IAAI,CAE/C;AAED,6EAA6E;AAC7E,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;CACZ;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,UAAU,SAAI,GAAG,IAAI,CAS/D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAc9E"}
1
+ {"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"AASA;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,MAAM,SAAM,GAAG,IAAI,CAM5C;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,IAAI,YAAY,GAAG,IAAI,CAErD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,IAAI,QAAQ,GAAG,IAAI,CAE/C;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAGpD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED,6EAA6E;AAC7E,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;CACZ;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,UAAU,SAAI,GAAG,IAAI,CAS/D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAc9E"}
package/dist/audio.js CHANGED
@@ -1,11 +1,15 @@
1
1
  let ctx = null;
2
2
  let masterGain = null;
3
+ const VOLUME_STEP = 0.1;
4
+ function clampVolume(v) {
5
+ return Math.max(0, Math.min(1, v));
6
+ }
3
7
  /**
4
8
  * Creates the shared `AudioContext` and master `GainNode`. Idempotent — safe to call
5
9
  * multiple times (subsequent calls are no-ops).
6
10
  * Must be called inside a user-gesture handler (click or keydown) due to browser autoplay policy.
7
11
  *
8
- * @param volume - Master gain value (0.0–1.0, default `0.3`)
12
+ * @param volume - Master gain value (0.0–1.0, default `0.3`). Clamped to valid range.
9
13
  *
10
14
  * @example
11
15
  * window.addEventListener('keydown', () => initAudio(), { once: true })
@@ -15,7 +19,7 @@ export function initAudio(volume = 0.3) {
15
19
  return;
16
20
  ctx = new AudioContext();
17
21
  masterGain = ctx.createGain();
18
- masterGain.gain.value = volume;
22
+ masterGain.gain.value = clampVolume(volume);
19
23
  masterGain.connect(ctx.destination);
20
24
  }
21
25
  /**
@@ -52,6 +56,47 @@ export function getAudioContext() {
52
56
  export function getMasterGain() {
53
57
  return masterGain;
54
58
  }
59
+ /**
60
+ * Returns the current master volume (0.0–1.0), or `0` before `initAudio()`.
61
+ *
62
+ * @example
63
+ * const vol = getMasterVolume() // e.g. 0.3
64
+ */
65
+ export function getMasterVolume() {
66
+ return masterGain?.gain.value ?? 0;
67
+ }
68
+ /**
69
+ * Sets the master volume. Clamped to 0.0–1.0. No-op before `initAudio()`.
70
+ *
71
+ * @param volume - Target gain value (0.0–1.0)
72
+ *
73
+ * @example
74
+ * setMasterVolume(0.5) // 50%
75
+ * setMasterVolume(0) // mute
76
+ */
77
+ export function setMasterVolume(volume) {
78
+ if (!masterGain)
79
+ return;
80
+ masterGain.gain.value = clampVolume(volume);
81
+ }
82
+ /**
83
+ * Increases master volume by 0.1, up to a maximum of 1.0.
84
+ *
85
+ * @example
86
+ * increaseVolume() // 0.3 → 0.4
87
+ */
88
+ export function increaseVolume() {
89
+ setMasterVolume(getMasterVolume() + VOLUME_STEP);
90
+ }
91
+ /**
92
+ * Decreases master volume by 0.1, down to a minimum of 0.0.
93
+ *
94
+ * @example
95
+ * decreaseVolume() // 0.3 → 0.2
96
+ */
97
+ export function decreaseVolume() {
98
+ setMasterVolume(getMasterVolume() - VOLUME_STEP);
99
+ }
55
100
  /**
56
101
  * Schedules a sequence of notes on the shared `AudioContext`.
57
102
  * Silently exits if audio has not been initialised yet.
package/dist/audio.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"audio.js","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"AAAA,IAAI,GAAG,GAAwB,IAAI,CAAA;AACnC,IAAI,UAAU,GAAoB,IAAI,CAAA;AAEtC;;;;;;;;;GASG;AACH,MAAM,UAAU,SAAS,CAAC,MAAM,GAAG,GAAG;IACpC,IAAI,GAAG;QAAE,OAAM;IACf,GAAG,GAAG,IAAI,YAAY,EAAE,CAAA;IACxB,UAAU,GAAG,GAAG,CAAC,UAAU,EAAE,CAAA;IAC7B,UAAU,CAAC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAA;IAC9B,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;AACrC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW;IACzB,IAAI,GAAG,IAAI,GAAG,CAAC,KAAK,KAAK,WAAW;QAAE,KAAK,GAAG,CAAC,MAAM,EAAE,CAAA;AACzD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,UAAU,CAAA;AACnB,CAAC;AAQD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,UAAU,GAAG,CAAC;IACvD,MAAM,KAAK,GAAG,eAAe,EAAE,CAAA;IAC/B,IAAI,CAAC,KAAK;QAAE,OAAM;IAClB,WAAW,EAAE,CAAA;IACb,IAAI,MAAM,GAAG,UAAU,CAAA;IACvB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC;YAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,WAAW,GAAG,MAAM,GAAG,IAAI,CAAC,CAAA;QAC/E,MAAM,IAAI,IAAI,CAAC,GAAG,CAAA;IACpB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,IAAI,CAAC,IAAY,EAAE,UAAkB,EAAE,SAAiB;IACtE,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU;QAAE,OAAM;IAC/B,MAAM,GAAG,GAAG,GAAG,CAAC,gBAAgB,EAAE,CAAA;IAClC,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,EAAE,CAAA;IAC7B,GAAG,CAAC,IAAI,GAAG,QAAQ,CAAA;IACnB,GAAG,CAAC,SAAS,CAAC,KAAK,GAAG,IAAI,CAAA;IAC1B,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,SAAS,CAAC,CAAA;IACtC,IAAI,CAAC,IAAI,CAAC,uBAAuB,CAAC,GAAG,EAAE,SAAS,GAAG,KAAK,CAAC,CAAA;IACzD,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,SAAS,GAAG,UAAU,GAAG,IAAI,GAAG,KAAK,CAAC,CAAA;IACpE,IAAI,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,IAAI,CAAC,CAAA;IACnE,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IACjB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IACxB,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;IACpB,GAAG,CAAC,IAAI,CAAC,SAAS,GAAG,UAAU,GAAG,IAAI,GAAG,IAAI,CAAC,CAAA;AAChD,CAAC"}
1
+ {"version":3,"file":"audio.js","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -3,4 +3,5 @@ export * from './font.js';
3
3
  export * from './renderer.js';
4
4
  export * from './audio.js';
5
5
  export * from './input.js';
6
+ export * from './ui.js';
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,SAAS,CAAA"}
package/dist/index.js CHANGED
@@ -3,4 +3,5 @@ export * from './font.js';
3
3
  export * from './renderer.js';
4
4
  export * from './audio.js';
5
5
  export * from './input.js';
6
+ export * from './ui.js';
6
7
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,SAAS,CAAA"}
package/dist/input.d.ts CHANGED
@@ -49,4 +49,14 @@ export declare function consumeAnyKey(): boolean;
49
49
  * if (isHeld('ArrowUp')) { ... }
50
50
  */
51
51
  export declare function isHeld(key: string): boolean;
52
+ /**
53
+ * Clears all pending key state immediately.
54
+ * Call when entering a new game phase (e.g. after game-over or menu transition)
55
+ * to prevent stale inputs from carrying over.
56
+ *
57
+ * @example
58
+ * appPhase = 'gameover'
59
+ * resetInput() // discard any queued keypresses from the previous phase
60
+ */
61
+ export declare function resetInput(): void;
52
62
  //# sourceMappingURL=input.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AAoBxD;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,WAAW,SAAM,EAAE,cAAc,SAAK,GAAG,IAAI,CAoCtE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAe3D;AAED,sGAAsG;AACtG,wBAAgB,WAAW,IAAI,OAAO,CAA+D;AAErG,gGAAgG;AAChG,wBAAgB,YAAY,IAAI,OAAO,CAA8D;AAErG,kFAAkF;AAClF,wBAAgB,YAAY,IAAI,OAAO,CAA8D;AAErG;;;GAGG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAA6D;AAErG;;;;;;;GAOG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAyB"}
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AAoBxD;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,WAAW,SAAM,EAAE,cAAc,SAAK,GAAG,IAAI,CAoCtE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAe3D;AAED,sGAAsG;AACtG,wBAAgB,WAAW,IAAI,OAAO,CAA+D;AAErG,gGAAgG;AAChG,wBAAgB,YAAY,IAAI,OAAO,CAA8D;AAErG,kFAAkF;AAClF,wBAAgB,YAAY,IAAI,OAAO,CAA8D;AAErG;;;GAGG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAA6D;AAErG;;;;;;;GAOG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAyB;AAErE;;;;;;;;GAQG;AACH,wBAAgB,UAAU,IAAI,IAAI,CASjC"}
package/dist/input.js CHANGED
@@ -113,4 +113,23 @@ export function consumeAnyKey() { const v = pendingAnyKey; pendingAnyKey = false
113
113
  * if (isHeld('ArrowUp')) { ... }
114
114
  */
115
115
  export function isHeld(key) { return held.has(key); }
116
+ /**
117
+ * Clears all pending key state immediately.
118
+ * Call when entering a new game phase (e.g. after game-over or menu transition)
119
+ * to prevent stale inputs from carrying over.
120
+ *
121
+ * @example
122
+ * appPhase = 'gameover'
123
+ * resetInput() // discard any queued keypresses from the previous phase
124
+ */
125
+ export function resetInput() {
126
+ held.clear();
127
+ pendingFlag = false;
128
+ pendingDebug = false;
129
+ pendingPause = false;
130
+ pendingAnyKey = false;
131
+ repeatDir = null;
132
+ repeatPhase = 'idle';
133
+ pendingImmediate = null;
134
+ }
116
135
  //# sourceMappingURL=input.js.map
package/dist/input.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"input.js","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"input.js","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,MAAM,EACb,KAAK,SAAM,EACX,MAAM,SAAM,GACX,wBAAwB,CAS1B;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAUxD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,wBAAwB,EAC7B,MAAM,EAAE,UAAU,EAClB,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GACzB,IAAI,CAUN;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,QAAQ,CACtB,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAC1B,IAAI,CAYN;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,QAAQ,CACtB,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAC1B,IAAI,CAIN;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EACT,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAC1B,IAAI,CAGN;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,UAAU,GAAE,MAAgB,GAC3B,IAAI,CAWN"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAiBA;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,MAAM,EACb,KAAK,SAAM,EACX,MAAM,SAAM,GACX,wBAAwB,CAS1B;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAUxD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,wBAAwB,EAC7B,MAAM,EAAE,UAAU,EAClB,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GACzB,IAAI,CAKN;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,QAAQ,CACtB,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAC1B,IAAI,CAON;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,QAAQ,CACtB,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAC1B,IAAI,CAIN;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EACT,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAC1B,IAAI,CAGN;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,UAAU,GAAE,MAAgB,GAC3B,IAAI,CAWN"}
package/dist/renderer.js CHANGED
@@ -1,5 +1,14 @@
1
1
  import { C, CELL } from './palette.js';
2
2
  import { getCharRow } from './font.js';
3
+ function drawBitmap(ctx, getByte, x, y) {
4
+ for (let row = 0; row < 8; row++) {
5
+ const byte = getByte(row);
6
+ for (let bit = 0; bit < 8; bit++) {
7
+ if (byte & (0x80 >> bit))
8
+ ctx.fillRect(x + bit, y + row, 1, 1);
9
+ }
10
+ }
11
+ }
3
12
  /**
4
13
  * Initialises a canvas element for pixel-perfect scaled rendering.
5
14
  * Sets canvas dimensions, applies CSS size, disables image smoothing, applies `ctx.scale()`,
@@ -65,13 +74,7 @@ export function drawSprite(ctx, sprite, x, y, ink, paper) {
65
74
  ctx.fillStyle = paper;
66
75
  ctx.fillRect(x, y, CELL, CELL);
67
76
  ctx.fillStyle = ink;
68
- for (let row = 0; row < 8; row++) {
69
- const byte = sprite[row];
70
- for (let bit = 0; bit < 8; bit++) {
71
- if (byte & (0x80 >> bit))
72
- ctx.fillRect(x + bit, y + row, 1, 1);
73
- }
74
- }
77
+ drawBitmap(ctx, row => sprite[row], x, y);
75
78
  }
76
79
  /**
77
80
  * Draws a single ASCII character at game coordinates using the ROM font.
@@ -94,13 +97,7 @@ export function drawChar(ctx, code, x, y, ink, paper) {
94
97
  ctx.fillRect(x, y, CELL, CELL);
95
98
  }
96
99
  ctx.fillStyle = ink;
97
- for (let row = 0; row < 8; row++) {
98
- const byte = getCharRow(code, row);
99
- for (let bit = 0; bit < 8; bit++) {
100
- if (byte & (0x80 >> bit))
101
- ctx.fillRect(x + bit, y + row, 1, 1);
102
- }
103
- }
100
+ drawBitmap(ctx, row => getCharRow(code, row), x, y);
104
101
  }
105
102
  /**
106
103
  * Draws a string left-to-right starting at game coordinates `(x, y)`.
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.js","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"renderer.js","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"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"}
package/dist/ui.d.ts ADDED
@@ -0,0 +1,231 @@
1
+ import type { SpectrumColor } from './palette.js';
2
+ /**
3
+ * Border configuration for UI primitives.
4
+ * When the `border` object is present on a parent option, a border is rendered.
5
+ * `enabled` defaults to `true` — set it to `false` to suppress the border
6
+ * while keeping the object in place for future toggling.
7
+ */
8
+ export type BorderOptions = {
9
+ /** Enable/disable border rendering. Default: `true` */
10
+ enabled?: boolean;
11
+ /** Border thickness in pixels. Default: `1` */
12
+ thickness?: number;
13
+ /**
14
+ * Border color. Default: same as the primary `ink` / `color` of the parent function.
15
+ * Accepts any {@link SpectrumColor} value.
16
+ */
17
+ color?: SpectrumColor;
18
+ /**
19
+ * Border style.
20
+ * - `'solid'` — continuous lines (default)
21
+ * - `'dashed'` — alternating 2 px on / 2 px off segments
22
+ */
23
+ style?: 'solid' | 'dashed';
24
+ };
25
+ /**
26
+ * Options for {@link drawProgressBar}.
27
+ */
28
+ export type DrawProgressBarOptions = {
29
+ /**
30
+ * Stable key for managed-visibility mode.
31
+ * The bar's last-drawn state is registered under this key so `renderUI` can
32
+ * redraw it on subsequent frames. Defaults to `"${x},${y}"` when omitted.
33
+ */
34
+ id?: string;
35
+ /** Left edge of the bar in game pixels. */
36
+ x: number;
37
+ /** Top edge of the bar in game pixels. */
38
+ y: number;
39
+ /**
40
+ * Total width of the bar in game pixels.
41
+ * Should be a multiple of `CELL` (8) — any remainder is left blank.
42
+ */
43
+ width: number;
44
+ /** Current value to represent. */
45
+ value: number;
46
+ /** Minimum value (left edge = empty). Default: `0` */
47
+ min?: number;
48
+ /** Maximum value (right edge = full). Default: `1` */
49
+ max?: number;
50
+ /** Filled-block foreground color. Default: `C.B_WHITE` */
51
+ ink?: SpectrumColor;
52
+ /** Empty-block background color. Default: `C.BLACK` */
53
+ paper?: SpectrumColor;
54
+ /** Optional border around the entire bar. */
55
+ border?: BorderOptions;
56
+ /**
57
+ * How long the bar stays visible after the last `drawProgressBar` call (ms).
58
+ * - `> 0` — auto-hides after this many milliseconds.
59
+ * - `0` — permanent; only cleared by `resetUI()`.
60
+ * Default: `500`
61
+ */
62
+ visibilityLength?: number;
63
+ };
64
+ /**
65
+ * Draws a filled rectangular box using ZX-style rendering.
66
+ *
67
+ * Renders a solid background (`paper`) and an optional border.
68
+ * Coordinates are in game pixels (already scaled by `setupCanvas`).
69
+ * Does NOT render text — use `drawPanelTitle` for labelled panels.
70
+ *
71
+ * @example
72
+ * drawBox(ctx, {
73
+ * x: 8, y: 8, width: 112, height: 40,
74
+ * paper: C.BLACK, ink: C.B_WHITE,
75
+ * border: { style: 'solid', thickness: 1 },
76
+ * })
77
+ */
78
+ export declare function drawBox(ctx: CanvasRenderingContext2D, options: {
79
+ /** Left edge in game pixels */
80
+ x: number;
81
+ /** Top edge in game pixels */
82
+ y: number;
83
+ /** Width in game pixels */
84
+ width: number;
85
+ /** Height in game pixels */
86
+ height: number;
87
+ /** Background fill color */
88
+ paper: SpectrumColor;
89
+ /** Foreground color — used as default border color when `border.color` is omitted */
90
+ ink?: SpectrumColor;
91
+ /** Optional border */
92
+ border?: BorderOptions;
93
+ }): void;
94
+ /**
95
+ * Draws a rectangular frame — border only, no background fill.
96
+ *
97
+ * Unlike `drawBox`, the inside area is left untouched.
98
+ * Useful for selection highlights, overlays, and ZX-style panels
99
+ * where the background is already painted.
100
+ *
101
+ * @example
102
+ * drawFrame(ctx, { x: 0, y: 0, width: 256, height: 176, color: C.B_CYAN })
103
+ * drawFrame(ctx, { x: 16, y: 16, width: 64, height: 32, color: C.B_RED,
104
+ * border: { style: 'dashed', thickness: 1 } })
105
+ */
106
+ export declare function drawFrame(ctx: CanvasRenderingContext2D, options: {
107
+ /** Left edge in game pixels */
108
+ x: number;
109
+ /** Top edge in game pixels */
110
+ y: number;
111
+ /** Width in game pixels */
112
+ width: number;
113
+ /** Height in game pixels */
114
+ height: number;
115
+ /** Frame color */
116
+ color: SpectrumColor;
117
+ /** Border configuration — `color` here overrides the top-level `color` */
118
+ border?: BorderOptions;
119
+ }): void;
120
+ /**
121
+ * Draws a ZX-style panel title — a text strip with an optional background fill.
122
+ *
123
+ * Does NOT draw the surrounding container (`drawBox` / `drawFrame` are separate).
124
+ * The strip height is always `CELL + padding * 2` pixels.
125
+ *
126
+ * @example
127
+ * // Labelled panel:
128
+ * drawBox(ctx, { x: 8, y: 24, width: 128, height: 56, paper: C.BLACK })
129
+ * drawPanelTitle(ctx, { text: 'OPTIONS', x: 8, y: 24, ink: C.B_YELLOW,
130
+ * paper: C.BLACK, centered: true, width: 128 })
131
+ *
132
+ * // No background — ink only:
133
+ * drawPanelTitle(ctx, { text: 'DEBUG', x: 0, y: 0, ink: C.B_CYAN })
134
+ */
135
+ export declare function drawPanelTitle(ctx: CanvasRenderingContext2D, options: {
136
+ /** Title text (ASCII — rendered via ZX ROM font) */
137
+ text: string;
138
+ /** Left edge in game pixels */
139
+ x: number;
140
+ /** Top edge of the title strip in game pixels */
141
+ y: number;
142
+ /** Text color */
143
+ ink: SpectrumColor;
144
+ /** Background behind the title strip. Omit for transparent (ink-only rendering) */
145
+ paper?: SpectrumColor;
146
+ /** Padding inside the strip in pixels. Default: `2` */
147
+ padding?: number;
148
+ /**
149
+ * Center the title horizontally within `width`.
150
+ * Requires `width` to be provided; ignored otherwise.
151
+ */
152
+ centered?: boolean;
153
+ /** Width used for centering (game pixels). Required when `centered: true`. */
154
+ width?: number;
155
+ }): void;
156
+ /**
157
+ * Draws a ZX-style progress / value bar and registers it for managed redraws.
158
+ *
159
+ * The bar is drawn **immediately** on every call. Additionally, the options are
160
+ * stored internally so `renderUI` can repaint the bar each frame for
161
+ * `visibilityLength` ms without requiring the caller to supply the state again.
162
+ *
163
+ * Calling `drawProgressBar` again with the same `id` **resets the timer** — use
164
+ * this to refresh the display when the value changes.
165
+ *
166
+ * **Typical pattern:**
167
+ * ```ts
168
+ * // On value change only:
169
+ * if (consumeVolUp()) {
170
+ * increaseVolume()
171
+ * drawProgressBar(ctx, { id: 'volume', x: 88, y: 88, width: 80,
172
+ * value: getMasterVolume(), visibilityLength: 1500 })
173
+ * }
174
+ *
175
+ * // Every frame (after game world render):
176
+ * tickUI(dt)
177
+ * renderUI(ctx)
178
+ * ```
179
+ *
180
+ * @example
181
+ * // Permanent HUD health bar:
182
+ * drawProgressBar(ctx, {
183
+ * id: 'health', x: 0, y: 184, width: 40, value: lives, min: 0, max: 3,
184
+ * ink: C.B_GREEN, paper: C.BLACK, visibilityLength: 0,
185
+ * })
186
+ *
187
+ * // Temporary volume indicator (auto-hides after 1.5 s):
188
+ * drawProgressBar(ctx, {
189
+ * id: 'volume', x: 88, y: 88, width: 80, value: getMasterVolume(),
190
+ * ink: C.B_GREEN, paper: C.BLACK,
191
+ * border: { style: 'solid' },
192
+ * visibilityLength: 1500,
193
+ * })
194
+ */
195
+ export declare function drawProgressBar(ctx: CanvasRenderingContext2D, options: DrawProgressBarOptions): void;
196
+ /**
197
+ * Advances all managed bar timers by `dtMs` milliseconds.
198
+ * Bars whose timer reaches zero are removed and will no longer appear in `renderUI`.
199
+ * Call once per frame, typically just before `renderUI`.
200
+ *
201
+ * @param dtMs - Frame delta in milliseconds
202
+ *
203
+ * @example
204
+ * // End of game loop:
205
+ * tickUI(dt)
206
+ * renderUI(ctx)
207
+ */
208
+ export declare function tickUI(dtMs: number): void;
209
+ /**
210
+ * Redraws all currently visible managed bars (timer > 0 or permanent).
211
+ * Call every frame **after** the game world has been rendered so bars appear on top.
212
+ *
213
+ * @param ctx - Canvas 2D rendering context
214
+ *
215
+ * @example
216
+ * renderFrame(ctx, state)
217
+ * tickUI(dt)
218
+ * renderUI(ctx)
219
+ */
220
+ export declare function renderUI(ctx: CanvasRenderingContext2D): void;
221
+ /**
222
+ * Clears all managed UI state — removes every active bar timer and its stored options.
223
+ * Call alongside `resetInput()` when transitioning between major game phases.
224
+ *
225
+ * @example
226
+ * resetInput()
227
+ * resetUI()
228
+ * appPhase = 'intro'
229
+ */
230
+ export declare function resetUI(): void;
231
+ //# sourceMappingURL=ui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"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"}
package/dist/ui.js ADDED
@@ -0,0 +1,210 @@
1
+ import { C, CELL } from './palette.js';
2
+ import { drawChar, drawText } from './renderer.js';
3
+ const _bars = new Map();
4
+ // ─── Private helpers ──────────────────────────────────────────────────────────
5
+ function _drawBorder(ctx, x, y, width, height, border, fallbackColor) {
6
+ if (border.enabled === false)
7
+ return;
8
+ const color = border.color ?? fallbackColor;
9
+ const t = border.thickness ?? 1;
10
+ ctx.fillStyle = color;
11
+ if (border.style !== 'dashed') {
12
+ ctx.fillRect(x, y, width, t); // top
13
+ ctx.fillRect(x, y + height - t, width, t); // bottom
14
+ ctx.fillRect(x, y, t, height); // left
15
+ ctx.fillRect(x + width - t, y, t, height); // right
16
+ }
17
+ else {
18
+ const d = 2; // dash length in pixels
19
+ for (let i = 0; i < width; i += d * 2) {
20
+ ctx.fillRect(x + i, y, Math.min(d, width - i), t); // top
21
+ ctx.fillRect(x + i, y + height - t, Math.min(d, width - i), t); // bottom
22
+ }
23
+ for (let i = 0; i < height; i += d * 2) {
24
+ ctx.fillRect(x, y + i, t, Math.min(d, height - i)); // left
25
+ ctx.fillRect(x + width - t, y + i, t, Math.min(d, height - i)); // right
26
+ }
27
+ }
28
+ }
29
+ function _renderBar(ctx, o) {
30
+ const min = o.min ?? 0;
31
+ const max = o.max ?? 1;
32
+ const ink = o.ink ?? C.B_WHITE;
33
+ const paper = o.paper ?? C.BLACK;
34
+ const chars = Math.floor(o.width / CELL);
35
+ const ratio = Math.max(0, Math.min(1, (o.value - min) / (max - min)));
36
+ const filled = Math.round(ratio * chars);
37
+ ctx.fillStyle = paper;
38
+ ctx.fillRect(o.x, o.y, chars * CELL, CELL);
39
+ for (let i = 0; i < filled; i++) {
40
+ drawChar(ctx, 127, o.x + i * CELL, o.y, ink, paper); // 127 = solid block █
41
+ }
42
+ if (o.border)
43
+ _drawBorder(ctx, o.x, o.y, chars * CELL, CELL, o.border, ink);
44
+ }
45
+ // ─── Public API — stateless primitives ───────────────────────────────────────
46
+ /**
47
+ * Draws a filled rectangular box using ZX-style rendering.
48
+ *
49
+ * Renders a solid background (`paper`) and an optional border.
50
+ * Coordinates are in game pixels (already scaled by `setupCanvas`).
51
+ * Does NOT render text — use `drawPanelTitle` for labelled panels.
52
+ *
53
+ * @example
54
+ * drawBox(ctx, {
55
+ * x: 8, y: 8, width: 112, height: 40,
56
+ * paper: C.BLACK, ink: C.B_WHITE,
57
+ * border: { style: 'solid', thickness: 1 },
58
+ * })
59
+ */
60
+ export function drawBox(ctx, options) {
61
+ const { x, y, width, height, paper, ink, border } = options;
62
+ ctx.fillStyle = paper;
63
+ ctx.fillRect(x, y, width, height);
64
+ if (border)
65
+ _drawBorder(ctx, x, y, width, height, border, ink ?? paper);
66
+ }
67
+ /**
68
+ * Draws a rectangular frame — border only, no background fill.
69
+ *
70
+ * Unlike `drawBox`, the inside area is left untouched.
71
+ * Useful for selection highlights, overlays, and ZX-style panels
72
+ * where the background is already painted.
73
+ *
74
+ * @example
75
+ * drawFrame(ctx, { x: 0, y: 0, width: 256, height: 176, color: C.B_CYAN })
76
+ * drawFrame(ctx, { x: 16, y: 16, width: 64, height: 32, color: C.B_RED,
77
+ * border: { style: 'dashed', thickness: 1 } })
78
+ */
79
+ export function drawFrame(ctx, options) {
80
+ const { x, y, width, height, color, border = {} } = options;
81
+ _drawBorder(ctx, x, y, width, height, { ...border, color }, color);
82
+ }
83
+ /**
84
+ * Draws a ZX-style panel title — a text strip with an optional background fill.
85
+ *
86
+ * Does NOT draw the surrounding container (`drawBox` / `drawFrame` are separate).
87
+ * The strip height is always `CELL + padding * 2` pixels.
88
+ *
89
+ * @example
90
+ * // Labelled panel:
91
+ * drawBox(ctx, { x: 8, y: 24, width: 128, height: 56, paper: C.BLACK })
92
+ * drawPanelTitle(ctx, { text: 'OPTIONS', x: 8, y: 24, ink: C.B_YELLOW,
93
+ * paper: C.BLACK, centered: true, width: 128 })
94
+ *
95
+ * // No background — ink only:
96
+ * drawPanelTitle(ctx, { text: 'DEBUG', x: 0, y: 0, ink: C.B_CYAN })
97
+ */
98
+ export function drawPanelTitle(ctx, options) {
99
+ const { text, x, y, ink, paper, padding = 2, centered, width } = options;
100
+ const textW = text.length * CELL;
101
+ const stripW = centered && width !== undefined ? width : textW + padding * 2;
102
+ if (paper !== undefined) {
103
+ ctx.fillStyle = paper;
104
+ ctx.fillRect(x, y, stripW, CELL + padding * 2);
105
+ }
106
+ const tx = centered && width !== undefined
107
+ ? x + Math.floor((width - textW) / 2)
108
+ : x + padding;
109
+ drawText(ctx, text, tx, y + padding, ink, paper);
110
+ }
111
+ // ─── Public API — stateful widget ────────────────────────────────────────────
112
+ /**
113
+ * Draws a ZX-style progress / value bar and registers it for managed redraws.
114
+ *
115
+ * The bar is drawn **immediately** on every call. Additionally, the options are
116
+ * stored internally so `renderUI` can repaint the bar each frame for
117
+ * `visibilityLength` ms without requiring the caller to supply the state again.
118
+ *
119
+ * Calling `drawProgressBar` again with the same `id` **resets the timer** — use
120
+ * this to refresh the display when the value changes.
121
+ *
122
+ * **Typical pattern:**
123
+ * ```ts
124
+ * // On value change only:
125
+ * if (consumeVolUp()) {
126
+ * increaseVolume()
127
+ * drawProgressBar(ctx, { id: 'volume', x: 88, y: 88, width: 80,
128
+ * value: getMasterVolume(), visibilityLength: 1500 })
129
+ * }
130
+ *
131
+ * // Every frame (after game world render):
132
+ * tickUI(dt)
133
+ * renderUI(ctx)
134
+ * ```
135
+ *
136
+ * @example
137
+ * // Permanent HUD health bar:
138
+ * drawProgressBar(ctx, {
139
+ * id: 'health', x: 0, y: 184, width: 40, value: lives, min: 0, max: 3,
140
+ * ink: C.B_GREEN, paper: C.BLACK, visibilityLength: 0,
141
+ * })
142
+ *
143
+ * // Temporary volume indicator (auto-hides after 1.5 s):
144
+ * drawProgressBar(ctx, {
145
+ * id: 'volume', x: 88, y: 88, width: 80, value: getMasterVolume(),
146
+ * ink: C.B_GREEN, paper: C.BLACK,
147
+ * border: { style: 'solid' },
148
+ * visibilityLength: 1500,
149
+ * })
150
+ */
151
+ export function drawProgressBar(ctx, options) {
152
+ _renderBar(ctx, options);
153
+ const id = options.id ?? `${options.x},${options.y}`;
154
+ const visibilityLength = options.visibilityLength ?? 500;
155
+ _bars.set(id, {
156
+ options,
157
+ timer: visibilityLength,
158
+ permanent: visibilityLength === 0,
159
+ });
160
+ }
161
+ /**
162
+ * Advances all managed bar timers by `dtMs` milliseconds.
163
+ * Bars whose timer reaches zero are removed and will no longer appear in `renderUI`.
164
+ * Call once per frame, typically just before `renderUI`.
165
+ *
166
+ * @param dtMs - Frame delta in milliseconds
167
+ *
168
+ * @example
169
+ * // End of game loop:
170
+ * tickUI(dt)
171
+ * renderUI(ctx)
172
+ */
173
+ export function tickUI(dtMs) {
174
+ for (const [id, bar] of _bars) {
175
+ if (bar.permanent)
176
+ continue;
177
+ bar.timer -= dtMs;
178
+ if (bar.timer <= 0)
179
+ _bars.delete(id);
180
+ }
181
+ }
182
+ /**
183
+ * Redraws all currently visible managed bars (timer > 0 or permanent).
184
+ * Call every frame **after** the game world has been rendered so bars appear on top.
185
+ *
186
+ * @param ctx - Canvas 2D rendering context
187
+ *
188
+ * @example
189
+ * renderFrame(ctx, state)
190
+ * tickUI(dt)
191
+ * renderUI(ctx)
192
+ */
193
+ export function renderUI(ctx) {
194
+ for (const bar of _bars.values()) {
195
+ _renderBar(ctx, bar.options);
196
+ }
197
+ }
198
+ /**
199
+ * Clears all managed UI state — removes every active bar timer and its stored options.
200
+ * Call alongside `resetInput()` when transitioning between major game phases.
201
+ *
202
+ * @example
203
+ * resetInput()
204
+ * resetUI()
205
+ * appPhase = 'intro'
206
+ */
207
+ export function resetUI() {
208
+ _bars.clear();
209
+ }
210
+ //# sourceMappingURL=ui.js.map
package/dist/ui.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.js","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "zx-kit",
3
- "version": "0.2.3",
4
- "description": "Reusable ZX Spectrum primitives: font, palette, renderer, audio, input",
3
+ "version": "0.4.0",
4
+ "description": "Reusable ZX Spectrum primitives: font, palette, renderer, audio, input, ui",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": {