zx-kit 0.38.1 → 0.40.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
@@ -187,6 +187,7 @@ Zero runtime dependencies, `sideEffects: false`, fully tree-shakeable.
187
187
  | `lighting` | Dithered cave darkness, one blit per frame | [rendering](docs/rendering.md#lightingts--dithered-cave-darkness) |
188
188
  | `audio` | 1-bit beeper: square-wave notes, patterns, stereo pan, volume + built-in auto-hide volume bar | [audio](docs/audio.md#audiots--beeper-audio) |
189
189
  | `ay` | AY-3-8912: 3-channel tone, LFSR noise, 16 envelopes, per-channel stereo pan + volume | [audio](docs/audio.md#ayts--ay-3-8912-melodik-audio) |
190
+ | `aydump` | Real ZX-scene tunes: PSG register-dump player, sample-accurate AudioWorklet chip emulator | [audio](docs/audio.md#aydump--real-zx-scene-tunes-psg-register-dumps--experimental-037) |
190
191
  | `music` | AY music by note name (`A5`, `C#4`) + looping | [audio](docs/audio.md#musicts--note-name-ay-music) |
191
192
  | `collision` | AABB / rect-vs-tile / pixel-precise mask overlap | [collision](docs/collision.md) |
192
193
  | `save` | Typed save/load: versioning, migration, slots, throttle, optional tamper signature | [save](docs/save.md) |
@@ -230,6 +231,8 @@ zx-kit/
230
231
  │ ├── ay.ts # AY-3-8912: createAY, playAY, AYChannel, AYNote, AYChip,
231
232
  │ │ # AYHandle, AYStereoMode (pan / setStereoMode / volume / fade),
232
233
  │ │ # AY_VOL, AY_CLOCK, AY_ENVELOPE_SHAPES
234
+ │ ├── aydump.ts # PSG register-dump player: parsePSG, loadPSG, playAYDump,
235
+ │ │ # renderAYDump (AudioWorklet AY/YM chip emulator)
233
236
  │ ├── music.ts # noteToFreq, seq, playAYLoop (note-name AY music)
234
237
  │ ├── input.ts # initInput, tickMovement, consumeFlag,
235
238
  │ │ # consumePause, consumeDebug, consumeAnyKey,
@@ -248,6 +251,8 @@ zx-kit/
248
251
  │ ├── camera.ts # scrolling viewport, lerp, deadzone, bounds
249
252
  │ ├── scene.ts # stack-based scene manager
250
253
  │ ├── save.ts # typed localStorage save/load with migrations
254
+ │ ├── hiscore.ts # high-score table over the save envelope:
255
+ │ │ # createHighScores, insertScore, isHighScore
251
256
  │ ├── presentation.ts # blinkVisible, drawBlinkingText, drawTapeStripes, drawMenuOptions
252
257
  │ ├── debug.ts # createDebugMonitor, beginFrame/endFrame, drawDebugOverlay
253
258
  │ └── i18n.ts # pickLocale runtime locale selection
@@ -58,6 +58,10 @@ export interface AttrScreen {
58
58
  readonly cellInk: Uint32Array;
59
59
  /** Packed RGBA paper colour per cell, `cols*rows`. */
60
60
  readonly cellPaper: Uint32Array;
61
+ /** Per-cell **GLOW** flag — `1` = emissive light source (opt-in, like the FLASH
62
+ * attribute bit). Set by `stampMono(..., glow=true)`; `0` otherwise. The normal
63
+ * clash flush ignores it; {@link drawAttrGlowSources} feeds it to `glow.ts`. */
64
+ readonly cellGlow: Uint8Array;
61
65
  /** Resolved RGBA frame buffer (`width*height*4`), filled by {@link flushAttrScreen}. */
62
66
  readonly rgba: Uint8ClampedArray;
63
67
  /** Reusable `ImageData` backing {@link rgba} (`null` when headless). */
@@ -83,8 +87,25 @@ export declare function clearAttrScreen(scr: AttrScreen, paper: SpectrumColor, i
83
87
  * the pixel plane and re-attributes every cell that receives a lit pixel, per
84
88
  * `policy` (default `'both'`). Lit-pixel-only: existing pixels are never cleared,
85
89
  * so other sprites/background in a touched cell bleed to the new colour.
90
+ *
91
+ * **`glow`** (default `false`, opt-in): also flags every cell this stamp touches as
92
+ * an emissive GLOW source ({@link AttrScreen.cellGlow}), for `glow.ts`'s bloom via
93
+ * {@link drawAttrGlowSources}. Leaving it `false` is byte-for-byte the old behaviour.
94
+ */
95
+ export declare function stampMono(scr: AttrScreen, bitmap: Bitmap, x: number, y: number, ink: SpectrumColor, paper: SpectrumColor, policy?: AttrPolicy, glow?: boolean): void;
96
+ /**
97
+ * Draws every {@link AttrScreen.cellGlow}-flagged cell as a solid 8×8 block in its
98
+ * ink colour into the emissive context `g`. Use it as the `drawSources` callback of
99
+ * `glow.ts`'s `renderGlow`, so an attribute screen's glow cells feed the bloom.
100
+ * Cell-level, exactly like the FLASH bit — the whole flagged cell is the light
101
+ * source. Draws nothing when no cell is flagged; needs no canvas of its own.
102
+ *
103
+ * @example
104
+ * ```ts
105
+ * renderGlow(glowLayer, ctx, (g) => drawAttrGlowSources(scr, g))
106
+ * ```
86
107
  */
87
- export declare function stampMono(scr: AttrScreen, bitmap: Bitmap, x: number, y: number, ink: SpectrumColor, paper: SpectrumColor, policy?: AttrPolicy): void;
108
+ export declare function drawAttrGlowSources(scr: AttrScreen, g: CanvasRenderingContext2D): void;
88
109
  /**
89
110
  * Resolves the two planes into RGBA (each pixel takes its cell's ink or paper)
90
111
  * and uploads the result with one `putImageData` + `drawImage`. The image is
@@ -1 +1 @@
1
- {"version":3,"file":"attrscreen.d.ts","sourceRoot":"","sources":["../src/attrscreen.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,OAAO,EAAQ,KAAK,aAAa,EAAE,MAAM,cAAc,CAAA;AACvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAE3C;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,YAAY,CAAA;AAE3D,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;IAC3B,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;IAC7B,sDAAsD;IACtD,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAA;IAC/B,wFAAwF;IACxF,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAA;IAChC,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAA;IAChC,kFAAkF;IAClF,QAAQ,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAA;CAC1C;AAqBD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,SAAK,EAAE,IAAI,SAAK,GAAG,UAAU,CAiCjE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,GAAE,aAAqB,GAAG,IAAI,CAIvG;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,UAAU,EACf,MAAM,EAAE,MAAM,EACd,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,GAAG,EAAE,aAAa,EAClB,KAAK,EAAE,aAAa,EACpB,MAAM,GAAE,UAAmB,GAC1B,IAAI,CA+BN;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,wBAAwB,EAAE,GAAG,EAAE,UAAU,GAAG,IAAI,CAoBpF"}
1
+ {"version":3,"file":"attrscreen.d.ts","sourceRoot":"","sources":["../src/attrscreen.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,OAAO,EAAQ,KAAK,aAAa,EAAE,MAAM,cAAc,CAAA;AACvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAE3C;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,YAAY,CAAA;AAE3D,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;IAC3B,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;IAC7B,sDAAsD;IACtD,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAA;IAC/B;;qFAEiF;IACjF,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAA;IAC7B,wFAAwF;IACxF,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAA;IAChC,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAA;IAChC,kFAAkF;IAClF,QAAQ,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAA;CAC1C;AAqBD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,SAAK,EAAE,IAAI,SAAK,GAAG,UAAU,CAkCjE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,GAAE,aAAqB,GAAG,IAAI,CAKvG;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,UAAU,EACf,MAAM,EAAE,MAAM,EACd,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,GAAG,EAAE,aAAa,EAClB,KAAK,EAAE,aAAa,EACpB,MAAM,GAAE,UAAmB,EAC3B,IAAI,UAAQ,GACX,IAAI,CAgCN;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,UAAU,EAAE,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAWtF;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,wBAAwB,EAAE,GAAG,EAAE,UAAU,GAAG,IAAI,CAoBpF"}
@@ -89,6 +89,7 @@ export function createAttrScreen(cols = 32, rows = 24) {
89
89
  pixels: new Uint8Array(width * height),
90
90
  cellInk: new Uint32Array(cols * rows),
91
91
  cellPaper: new Uint32Array(cols * rows),
92
+ cellGlow: new Uint8Array(cols * rows),
92
93
  rgba,
93
94
  image,
94
95
  canvas,
@@ -103,6 +104,7 @@ export function clearAttrScreen(scr, paper, ink = paper) {
103
104
  scr.pixels.fill(0);
104
105
  scr.cellPaper.fill(hexToU32(paper));
105
106
  scr.cellInk.fill(hexToU32(ink));
107
+ scr.cellGlow.fill(0); // glow is per-frame opt-in — nothing glows until a stamp sets it
106
108
  }
107
109
  /**
108
110
  * Stamps a monochrome {@link Bitmap} at screen pixel `(x, y)` (rounded; may be
@@ -110,8 +112,12 @@ export function clearAttrScreen(scr, paper, ink = paper) {
110
112
  * the pixel plane and re-attributes every cell that receives a lit pixel, per
111
113
  * `policy` (default `'both'`). Lit-pixel-only: existing pixels are never cleared,
112
114
  * so other sprites/background in a touched cell bleed to the new colour.
115
+ *
116
+ * **`glow`** (default `false`, opt-in): also flags every cell this stamp touches as
117
+ * an emissive GLOW source ({@link AttrScreen.cellGlow}), for `glow.ts`'s bloom via
118
+ * {@link drawAttrGlowSources}. Leaving it `false` is byte-for-byte the old behaviour.
113
119
  */
114
- export function stampMono(scr, bitmap, x, y, ink, paper, policy = 'both') {
120
+ export function stampMono(scr, bitmap, x, y, ink, paper, policy = 'both', glow = false) {
115
121
  const inkU32 = hexToU32(ink);
116
122
  const paperU32 = hexToU32(paper);
117
123
  const setInk = policy !== 'paper-only';
@@ -144,10 +150,37 @@ export function stampMono(scr, bitmap, x, y, ink, paper, policy = 'both') {
144
150
  scr.cellInk[cell] = inkU32;
145
151
  if (setPaper)
146
152
  scr.cellPaper[cell] = paperU32;
153
+ if (glow)
154
+ scr.cellGlow[cell] = 1;
147
155
  }
148
156
  }
149
157
  }
150
158
  }
159
+ /**
160
+ * Draws every {@link AttrScreen.cellGlow}-flagged cell as a solid 8×8 block in its
161
+ * ink colour into the emissive context `g`. Use it as the `drawSources` callback of
162
+ * `glow.ts`'s `renderGlow`, so an attribute screen's glow cells feed the bloom.
163
+ * Cell-level, exactly like the FLASH bit — the whole flagged cell is the light
164
+ * source. Draws nothing when no cell is flagged; needs no canvas of its own.
165
+ *
166
+ * @example
167
+ * ```ts
168
+ * renderGlow(glowLayer, ctx, (g) => drawAttrGlowSources(scr, g))
169
+ * ```
170
+ */
171
+ export function drawAttrGlowSources(scr, g) {
172
+ const { cellGlow, cellInk, cols, rows } = scr;
173
+ for (let row = 0; row < rows; row++) {
174
+ for (let col = 0; col < cols; col++) {
175
+ const cell = row * cols + col;
176
+ if (!cellGlow[cell])
177
+ continue;
178
+ const u = cellInk[cell]; // packed little-endian RGBA (a<<24 | b<<16 | g<<8 | r)
179
+ g.fillStyle = `rgba(${u & 0xff},${(u >> 8) & 0xff},${(u >> 16) & 0xff},${((u >>> 24) & 0xff) / 255})`;
180
+ g.fillRect(col * CELL, row * CELL, CELL, CELL);
181
+ }
182
+ }
183
+ }
151
184
  /**
152
185
  * Resolves the two planes into RGBA (each pixel takes its cell's ink or paper)
153
186
  * and uploads the result with one `putImageData` + `drawImage`. The image is
@@ -1 +1 @@
1
- {"version":3,"file":"attrscreen.js","sourceRoot":"","sources":["../src/attrscreen.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"attrscreen.js","sourceRoot":"","sources":["../src/attrscreen.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,OAAO,EAAE,IAAI,EAAsB,MAAM,cAAc,CAAA;AAoCvD;;;;;GAKG;AACH,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAA;AACxC,SAAS,QAAQ,CAAC,GAAkB;IAClC,IAAI,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACvB,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;QACpB,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QACvC,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QACvC,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QACvC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAA;QAClD,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;IACpB,CAAC;IACD,OAAO,CAAC,CAAA;AACV,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAI,GAAG,EAAE,EAAE,IAAI,GAAG,EAAE;IACnD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC;QACjF,MAAM,IAAI,KAAK,CAAC,kEAAkE,IAAI,IAAI,IAAI,EAAE,CAAC,CAAA;IACnG,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,GAAG,IAAI,CAAA;IACzB,MAAM,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IAC1B,IAAI,MAAM,GAA6B,IAAI,CAAA;IAC3C,IAAI,KAAK,GAAqB,IAAI,CAAA;IAClC,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;QACpC,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAA;QACzC,MAAM,CAAC,KAAK,GAAG,KAAK,CAAA;QACpB,MAAM,CAAC,MAAM,GAAG,MAAM,CAAA;QACtB,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;QACnC,IAAI,GAAG,EAAE,CAAC;YACR,GAAG,CAAC,qBAAqB,GAAG,KAAK,CAAA;YACjC,KAAK,GAAG,GAAG,CAAC,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;QAC5C,CAAC;IACH,CAAC;IACD,iFAAiF;IACjF,oFAAoF;IACpF,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,iBAAiB,CAAC,KAAK,GAAG,MAAM,GAAG,CAAC,CAAC,CAAA;IAC3E,OAAO;QACL,IAAI;QACJ,IAAI;QACJ,KAAK;QACL,MAAM;QACN,MAAM,EAAE,IAAI,UAAU,CAAC,KAAK,GAAG,MAAM,CAAC;QACtC,OAAO,EAAE,IAAI,WAAW,CAAC,IAAI,GAAG,IAAI,CAAC;QACrC,SAAS,EAAE,IAAI,WAAW,CAAC,IAAI,GAAG,IAAI,CAAC;QACvC,QAAQ,EAAE,IAAI,UAAU,CAAC,IAAI,GAAG,IAAI,CAAC;QACrC,IAAI;QACJ,KAAK;QACL,MAAM;KACP,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,GAAe,EAAE,KAAoB,EAAE,MAAqB,KAAK;IAC/F,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAClB,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAA;IACnC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAA;IAC/B,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA,CAAC,iEAAiE;AACxF,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,SAAS,CACvB,GAAe,EACf,MAAc,EACd,CAAS,EACT,CAAS,EACT,GAAkB,EAClB,KAAoB,EACpB,SAAqB,MAAM,EAC3B,IAAI,GAAG,KAAK;IAEZ,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAA;IAC5B,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAChC,MAAM,MAAM,GAAG,MAAM,KAAK,YAAY,CAAA;IACtC,MAAM,QAAQ,GAAG,MAAM,KAAK,UAAU,CAAA;IACtC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,MAAM,CAAA;IAC9C,MAAM,WAAW,GAAG,EAAE,IAAI,CAAC,CAAA;IAC3B,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACxB,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAExB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC;QAClC,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,CAAA;QACnB,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,MAAM;YAAE,SAAQ;QACxC,MAAM,WAAW,GAAG,GAAG,GAAG,WAAW,CAAA;QACrC,MAAM,UAAU,GAAG,EAAE,GAAG,GAAG,CAAC,KAAK,CAAA;QACjC,MAAM,WAAW,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,CAAA;QACxC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;YACvD,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,CAAA;YACxC,IAAI,CAAC,IAAI;gBAAE,SAAQ;YACnB,MAAM,OAAO,GAAG,OAAO,IAAI,CAAC,CAAA;YAC5B,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;gBACjC,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC;oBAAE,SAAQ;gBACrC,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,GAAG,GAAG,CAAA;gBAC7B,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,KAAK;oBAAE,SAAQ;gBACvC,GAAG,CAAC,MAAM,CAAC,UAAU,GAAG,EAAE,CAAC,GAAG,CAAC,CAAA;gBAC/B,MAAM,IAAI,GAAG,WAAW,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAA;gBACpC,IAAI,MAAM;oBAAE,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,CAAA;gBACtC,IAAI,QAAQ;oBAAE,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAA;gBAC5C,IAAI,IAAI;oBAAE,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YAClC,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAe,EAAE,CAA2B;IAC9E,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,GAAG,CAAA;IAC7C,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;QACpC,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;YACpC,MAAM,IAAI,GAAG,GAAG,GAAG,IAAI,GAAG,GAAG,CAAA;YAC7B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,SAAQ;YAC7B,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA,CAAC,uDAAuD;YAC/E,CAAC,CAAC,SAAS,GAAG,QAAQ,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,GAAG,GAAG,CAAA;YACrG,CAAC,CAAC,QAAQ,CAAC,GAAG,GAAG,IAAI,EAAE,GAAG,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;QAChD,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,GAA6B,EAAE,GAAe;IAC5E,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,CAAA;IAC/D,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAC5C,IAAI,CAAC,GAAG,CAAC,CAAA;IACT,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,IAAI,CAAA;QAChC,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC;YAClC,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAA;YAChC,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;YACpD,CAAC,EAAE,CAAA;QACL,CAAC;IACH,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;QAC1C,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;YACpC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;QACjC,CAAC;IACH,CAAC;AACH,CAAC"}
package/dist/glow.d.ts ADDED
@@ -0,0 +1,104 @@
1
+ /**
2
+ * @module glow
3
+ *
4
+ * **Optional phosphor GLOW / bloom — opt-in, purely additive.** The additive twin
5
+ * of {@link "lighting" | renderDarkness}: where lighting *subtracts* (dithered
6
+ * darkness), glow *adds* (a soft emissive bloom). A game marks its **light
7
+ * sources** — a torch, the moon, a sonar/radar blip — and their colour bleeds into
8
+ * the neighbours, so overlapping haloes sum into *perceived* extra colours **on the
9
+ * glass only**, while the crisp pixel-art framebuffer keeps its flat palette.
10
+ *
11
+ * **Emissive, not brighter (path B).** Glow is a marker on *sources of light*, not
12
+ * a lighter flat colour — the palette is never diluted. Everything the game does
13
+ * NOT draw into the glow layer stays exactly as before: this module adds new
14
+ * exports only, touches no existing render path, and a game that never calls
15
+ * {@link createGlowLayer} / {@link renderGlow} is byte-for-byte unaffected (it
16
+ * tree-shakes away).
17
+ *
18
+ * **Cheap bloom, no WebGL:** the emissive layer is **downscaled** to a small buffer
19
+ * and **upscaled** back with bilinear smoothing — that scaling IS the blur, for
20
+ * free — then blitted onto the frame with `globalCompositeOperation = 'lighter'`
21
+ * (additive). One offscreen buffer, a couple of `drawImage`s, headless-safe.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const glow = createGlowLayer(256, 192) // once, view-sized
26
+ * // each frame, AFTER drawing the scene, BEFORE scanlines:
27
+ * renderGlow(glow, ctx, (g) => {
28
+ * drawGlowSource(g, { x: torchX, y: torchY, radius: 24, color: C.B_YELLOW, intensity: 0.9 })
29
+ * drawGlowSource(g, { x: moonX, y: moonY, radius: 40, color: C.B_WHITE, intensity: 0.5 })
30
+ * // …or draw sprites/pixels directly for pixel-exact glow
31
+ * })
32
+ * ```
33
+ */
34
+ import { type SpectrumColor } from './palette.js';
35
+ /** Tunables for a {@link GlowLayer}. All optional; defaults are an eye-tuning start. */
36
+ export interface GlowOptions {
37
+ /** Blur strength: the emissive layer is scaled down by this factor before the
38
+ * bilinear upscale spreads it. Bigger = softer & cheaper. Clamped ≥ 1. Default `4`. */
39
+ downscale?: number;
40
+ /** How many additive blits of the bloom (brightness/saturation of the halo).
41
+ * Clamped ≥ 1. Default `1`. */
42
+ passes?: number;
43
+ /** Global bloom strength, `0..1` — the `globalAlpha` of each additive blit.
44
+ * Clamped to `0..1`. Default `0.5`. */
45
+ alpha?: number;
46
+ }
47
+ /** A view-sized glow layer: one emissive canvas + one downscale buffer. Allocate
48
+ * once, reuse across frames. Both canvases are `null` when headless (no document). */
49
+ export interface GlowLayer {
50
+ readonly width: number;
51
+ readonly height: number;
52
+ readonly downscale: number;
53
+ readonly passes: number;
54
+ readonly alpha: number;
55
+ /** Emissive layer — sources drawn here each frame (transparent elsewhere). `null` headless. */
56
+ readonly source: HTMLCanvasElement | null;
57
+ /** Small downscale buffer (the blur). `null` headless. */
58
+ readonly blur: HTMLCanvasElement | null;
59
+ }
60
+ /** A single light source for {@link drawGlowSource}: a soft coloured blob whose
61
+ * bloom is scaled by `intensity`. Blooms in its **own** `color` — never white-only. */
62
+ export interface GlowSource {
63
+ /** Centre in screen px. */
64
+ x: number;
65
+ y: number;
66
+ /** Reach in px (the blob's radius). */
67
+ radius: number;
68
+ /** The source's colour — the halo takes this colour. */
69
+ color: SpectrumColor;
70
+ /** Brightness scale `0..1` (default `1`). A dim torch vs a bright radar. */
71
+ intensity?: number;
72
+ }
73
+ /**
74
+ * Downscale-buffer dimensions for a `width`×`height` view at `downscale` — pure,
75
+ * exported for tests. Each axis is floored, never below 1.
76
+ */
77
+ export declare function glowBufferSize(width: number, height: number, downscale: number): {
78
+ w: number;
79
+ h: number;
80
+ };
81
+ /**
82
+ * Creates a view-sized glow layer. `opts` tune the bloom ({@link GlowOptions}).
83
+ * Allocate once; reuse. Headless (no `document`): both canvases are `null` and
84
+ * {@link renderGlow} becomes a no-op.
85
+ */
86
+ export declare function createGlowLayer(width: number, height: number, opts?: GlowOptions): GlowLayer;
87
+ /**
88
+ * Draws one {@link GlowSource} — a soft radial blob in the source's own colour,
89
+ * scaled by `intensity` — into the emissive canvas context `g` (the one handed to
90
+ * the {@link renderGlow} callback). The blob fades to transparent at `radius`, so
91
+ * it adds nothing outside its reach when the layer is blitted with `'lighter'`.
92
+ */
93
+ export declare function drawGlowSource(g: CanvasRenderingContext2D, source: GlowSource): void;
94
+ /**
95
+ * Renders the bloom onto `ctx`, additively. Call each frame AFTER the scene is
96
+ * drawn (and before scanlines / `curveDisplay`). `drawSources` receives the
97
+ * emissive canvas context — draw your light sources into it (via
98
+ * {@link drawGlowSource} or any drawing). Their colour is then blurred (downscale
99
+ * → bilinear upscale) and blitted onto `ctx` with `'lighter'` at the layer's
100
+ * `alpha`, `passes` times. Restores `ctx`'s composite/alpha/smoothing afterwards,
101
+ * so it composes cleanly with the rest of the frame. Headless: a silent no-op.
102
+ */
103
+ export declare function renderGlow(layer: GlowLayer, ctx: CanvasRenderingContext2D, drawSources: (g: CanvasRenderingContext2D) => void): void;
104
+ //# sourceMappingURL=glow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glow.d.ts","sourceRoot":"","sources":["../src/glow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAA;AAEjD,wFAAwF;AACxF,MAAM,WAAW,WAAW;IAC1B;4FACwF;IACxF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;oCACgC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;4CACwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;uFACuF;AACvF,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,+FAA+F;IAC/F,QAAQ,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAA;IACzC,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAA;CACxC;AAED;wFACwF;AACxF,MAAM,WAAW,UAAU;IACzB,2BAA2B;IAC3B,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAA;IACd,wDAAwD;IACxD,KAAK,EAAE,aAAa,CAAA;IACpB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAQD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAGzG;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,SAAS,CAqBhG;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,wBAAwB,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAWpF;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,SAAS,EAChB,GAAG,EAAE,wBAAwB,EAC7B,WAAW,EAAE,CAAC,CAAC,EAAE,wBAAwB,KAAK,IAAI,GACjD,IAAI,CA6BN"}
package/dist/glow.js ADDED
@@ -0,0 +1,128 @@
1
+ /**
2
+ * @module glow
3
+ *
4
+ * **Optional phosphor GLOW / bloom — opt-in, purely additive.** The additive twin
5
+ * of {@link "lighting" | renderDarkness}: where lighting *subtracts* (dithered
6
+ * darkness), glow *adds* (a soft emissive bloom). A game marks its **light
7
+ * sources** — a torch, the moon, a sonar/radar blip — and their colour bleeds into
8
+ * the neighbours, so overlapping haloes sum into *perceived* extra colours **on the
9
+ * glass only**, while the crisp pixel-art framebuffer keeps its flat palette.
10
+ *
11
+ * **Emissive, not brighter (path B).** Glow is a marker on *sources of light*, not
12
+ * a lighter flat colour — the palette is never diluted. Everything the game does
13
+ * NOT draw into the glow layer stays exactly as before: this module adds new
14
+ * exports only, touches no existing render path, and a game that never calls
15
+ * {@link createGlowLayer} / {@link renderGlow} is byte-for-byte unaffected (it
16
+ * tree-shakes away).
17
+ *
18
+ * **Cheap bloom, no WebGL:** the emissive layer is **downscaled** to a small buffer
19
+ * and **upscaled** back with bilinear smoothing — that scaling IS the blur, for
20
+ * free — then blitted onto the frame with `globalCompositeOperation = 'lighter'`
21
+ * (additive). One offscreen buffer, a couple of `drawImage`s, headless-safe.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const glow = createGlowLayer(256, 192) // once, view-sized
26
+ * // each frame, AFTER drawing the scene, BEFORE scanlines:
27
+ * renderGlow(glow, ctx, (g) => {
28
+ * drawGlowSource(g, { x: torchX, y: torchY, radius: 24, color: C.B_YELLOW, intensity: 0.9 })
29
+ * drawGlowSource(g, { x: moonX, y: moonY, radius: 40, color: C.B_WHITE, intensity: 0.5 })
30
+ * // …or draw sprites/pixels directly for pixel-exact glow
31
+ * })
32
+ * ```
33
+ */
34
+ import {} from './palette.js';
35
+ const clampInt1 = (n, dflt) => Number.isFinite(n) && n >= 1 ? Math.floor(n) : dflt;
36
+ const clamp01 = (n, dflt) => Number.isFinite(n) ? (n < 0 ? 0 : n > 1 ? 1 : n) : dflt;
37
+ /**
38
+ * Downscale-buffer dimensions for a `width`×`height` view at `downscale` — pure,
39
+ * exported for tests. Each axis is floored, never below 1.
40
+ */
41
+ export function glowBufferSize(width, height, downscale) {
42
+ const d = clampInt1(downscale, 4);
43
+ return { w: Math.max(1, Math.floor(width / d)), h: Math.max(1, Math.floor(height / d)) };
44
+ }
45
+ /**
46
+ * Creates a view-sized glow layer. `opts` tune the bloom ({@link GlowOptions}).
47
+ * Allocate once; reuse. Headless (no `document`): both canvases are `null` and
48
+ * {@link renderGlow} becomes a no-op.
49
+ */
50
+ export function createGlowLayer(width, height, opts = {}) {
51
+ if (!Number.isInteger(width) || width <= 0 || !Number.isInteger(height) || height <= 0) {
52
+ throw new Error(`createGlowLayer: width and height must be positive integers, got ${width}×${height}`);
53
+ }
54
+ const downscale = clampInt1(opts.downscale ?? 4, 4);
55
+ const passes = clampInt1(opts.passes ?? 1, 1);
56
+ const alpha = clamp01(opts.alpha ?? 0.5, 0.5);
57
+ let source = null;
58
+ let blur = null;
59
+ if (typeof document !== 'undefined') {
60
+ const { w, h } = glowBufferSize(width, height, downscale);
61
+ source = document.createElement('canvas');
62
+ source.width = width;
63
+ source.height = height;
64
+ blur = document.createElement('canvas');
65
+ blur.width = w;
66
+ blur.height = h;
67
+ }
68
+ return { width, height, downscale, passes, alpha, source, blur };
69
+ }
70
+ /**
71
+ * Draws one {@link GlowSource} — a soft radial blob in the source's own colour,
72
+ * scaled by `intensity` — into the emissive canvas context `g` (the one handed to
73
+ * the {@link renderGlow} callback). The blob fades to transparent at `radius`, so
74
+ * it adds nothing outside its reach when the layer is blitted with `'lighter'`.
75
+ */
76
+ export function drawGlowSource(g, source) {
77
+ const intensity = clamp01(source.intensity ?? 1, 1);
78
+ if (intensity <= 0 || source.radius <= 0)
79
+ return;
80
+ const grad = g.createRadialGradient(source.x, source.y, 0, source.x, source.y, source.radius);
81
+ grad.addColorStop(0, source.color);
82
+ grad.addColorStop(1, 'transparent');
83
+ const prevAlpha = g.globalAlpha;
84
+ g.globalAlpha = intensity;
85
+ g.fillStyle = grad;
86
+ g.fillRect(source.x - source.radius, source.y - source.radius, source.radius * 2, source.radius * 2);
87
+ g.globalAlpha = prevAlpha;
88
+ }
89
+ /**
90
+ * Renders the bloom onto `ctx`, additively. Call each frame AFTER the scene is
91
+ * drawn (and before scanlines / `curveDisplay`). `drawSources` receives the
92
+ * emissive canvas context — draw your light sources into it (via
93
+ * {@link drawGlowSource} or any drawing). Their colour is then blurred (downscale
94
+ * → bilinear upscale) and blitted onto `ctx` with `'lighter'` at the layer's
95
+ * `alpha`, `passes` times. Restores `ctx`'s composite/alpha/smoothing afterwards,
96
+ * so it composes cleanly with the rest of the frame. Headless: a silent no-op.
97
+ */
98
+ export function renderGlow(layer, ctx, drawSources) {
99
+ const { source, blur, width, height, passes, alpha } = layer;
100
+ if (!source || !blur)
101
+ return; // headless → nothing to draw
102
+ // Draw the emissive sources, then downscale into the small blur buffer. In a
103
+ // browser both contexts exist; headless-ish (jsdom, getContext null) this block
104
+ // is skipped and only the blit below runs — mirrors renderDarkness.
105
+ const g = source.getContext('2d');
106
+ const b = blur.getContext('2d');
107
+ if (g && b) {
108
+ g.clearRect(0, 0, width, height); // transparent = additive-neutral
109
+ drawSources(g);
110
+ b.imageSmoothingEnabled = true;
111
+ b.clearRect(0, 0, blur.width, blur.height);
112
+ b.drawImage(source, 0, 0, blur.width, blur.height); // downscale (average)
113
+ }
114
+ // Upscale + additive blit: drawing the small buffer back to full size with
115
+ // smoothing on IS the blur; 'lighter' sums the haloes over the flat scene.
116
+ const prevSmooth = ctx.imageSmoothingEnabled;
117
+ const prevOp = ctx.globalCompositeOperation;
118
+ const prevAlpha = ctx.globalAlpha;
119
+ ctx.imageSmoothingEnabled = true;
120
+ ctx.globalCompositeOperation = 'lighter';
121
+ ctx.globalAlpha = alpha;
122
+ for (let i = 0; i < passes; i++)
123
+ ctx.drawImage(blur, 0, 0, width, height);
124
+ ctx.imageSmoothingEnabled = prevSmooth;
125
+ ctx.globalCompositeOperation = prevOp;
126
+ ctx.globalAlpha = prevAlpha;
127
+ }
128
+ //# sourceMappingURL=glow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glow.js","sourceRoot":"","sources":["../src/glow.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -19,6 +19,7 @@ export * from './save.js';
19
19
  export * from './hiscore.js';
20
20
  export * from './i18n.js';
21
21
  export * from './lighting.js';
22
+ export * from './glow.js';
22
23
  export * from './cache.js';
23
24
  export * from './attrscreen.js';
24
25
  export * from './monoscreen.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,SAAS,CAAA;AACvB,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,SAAS,CAAA;AACvB,cAAc,cAAc,CAAA;AAC5B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,mBAAmB,CAAA;AACjC,cAAc,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,SAAS,CAAA;AACvB,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,SAAS,CAAA;AACvB,cAAc,cAAc,CAAA;AAC5B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,mBAAmB,CAAA;AACjC,cAAc,YAAY,CAAA"}
package/dist/index.js CHANGED
@@ -19,6 +19,7 @@ export * from './save.js';
19
19
  export * from './hiscore.js';
20
20
  export * from './i18n.js';
21
21
  export * from './lighting.js';
22
+ export * from './glow.js';
22
23
  export * from './cache.js';
23
24
  export * from './attrscreen.js';
24
25
  export * from './monoscreen.js';
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,SAAS,CAAA;AACvB,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,SAAS,CAAA;AACvB,cAAc,cAAc,CAAA;AAC5B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,mBAAmB,CAAA;AACjC,cAAc,YAAY,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,SAAS,CAAA;AACvB,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,SAAS,CAAA;AACvB,cAAc,cAAc,CAAA;AAC5B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,mBAAmB,CAAA;AACjC,cAAc,YAAY,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zx-kit",
3
- "version": "0.38.1",
3
+ "version": "0.40.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/zrebec/zx-kit.git"
@@ -23,7 +23,8 @@
23
23
  "scripts": {
24
24
  "build": "tsc",
25
25
  "prepublishOnly": "npm run build",
26
- "test": "vitest run"
26
+ "test": "vitest run",
27
+ "test:coverage": "vitest run --coverage"
27
28
  },
28
29
  "keywords": [
29
30
  "zx-spectrum",