@zakkster/lite-scratch-fx 1.2.0 → 1.3.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/CHANGELOG.md CHANGED
@@ -1,12 +1,39 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.3.0] - 2026-08-22
4
+
5
+ Abortable, self-restoring reveals. A reveal can now be cancelled, and the host scratch
6
+ layer is returned to exactly the inline style it had before the reveal on completion,
7
+ cancel, AND destroy -- so a grid can reset every round. Purely additive.
8
+
9
+ ### Added
10
+ - **`controller.cancel()`** on both the standalone controller and stage-managed
11
+ controllers -- abort an in-flight reveal: stop the effect, restore the host canvas's
12
+ inline style, and do NOT fire `onDone`; the controller is revealable again afterwards.
13
+ A no-op when idle or destroyed. A stage `cancel()` does not touch other controllers'
14
+ in-flight reveals and does not reclaim the sub-range. See
15
+ `decisions/0002-host-style-and-cancel.md`.
16
+ - `src/HostStyle.js` -- `captureHostStyle` / `restoreHostStyle`, a shared cold-path helper
17
+ that snapshots and restores the host layer's 5 inline style props.
18
+ - **`dpr` option** for sharp rendering on high-DPI displays; recipes still author in CSS pixels.
19
+
20
+ ### Fixed
21
+ - **Recipes stranded inline style on the host `sourceCanvas`.** The reveal recipes write
22
+ `opacity`, `transform`, `filter`, `clipPath`, and `transformOrigin` on the host layer
23
+ during `tick`; `opacity` was never restored and the others only on the completion frame,
24
+ so an aborted (or opacity-fading) reveal left the cover invisible or transformed forever.
25
+ The controller now snapshots those 5 props at reveal start and restores them on every
26
+ terminal transition -- completion, cancel, and destroy -- via a single `endReveal`
27
+ terminator. No inline `opacity`/`transform`/`filter`/`clipPath`/`transformOrigin`
28
+ survives a reveal.
29
+
3
30
  ## [1.2.0] - 2026-08-22
4
31
 
5
32
  Concurrent scratch-card reveals over one shared particle pool. Purely additive --
6
33
  `createScratchController` and its options are unchanged.
7
34
 
8
35
  ### Added
9
- - **`createScratchStage({ maxParticles, seed })`** a stage that owns one particle
36
+ - **`createScratchStage({ maxParticles, seed })`** -- a stage that owns one particle
10
37
  engine and lets any number of controllers reveal **at the same time** over that one
11
38
  pool (where `{ engine }` allowed only one reveal at a time). Each
12
39
  `stage.createController(src, fx, { capacity })` reserves a fixed sub-range of the lanes,
@@ -14,8 +41,10 @@ Concurrent scratch-card reveals over one shared particle pool. Purely additive -
14
41
  and keeps its own deterministic RNG. `stage.tick(dt)` (seconds) drives every active reveal
15
42
  from one clock; reserving past `maxParticles` throws. Stage-managed controllers have no
16
43
  `tick` of their own. See `decisions/0001-concurrent-shared-reveals.md`.
17
- - `src/PixelScan.js` the reveal-scan logic extracted into a shared `createPixelScanner`,
44
+ - `src/PixelScan.js` -- the reveal-scan logic extracted into a shared `createPixelScanner`,
18
45
  now used by both the controller and the stage (no behaviour change).
46
+ - A `VERSION`-matches-`package.json` test, and a README rebuilt on the LiteSepforge
47
+ documentation spine. No API or behaviour change.
19
48
 
20
49
  ### Notes
21
50
  - Feasible with no change to `@zakkster/lite-soa-particle-engine`: raw-mode `tick(dt)` is
@@ -25,28 +54,28 @@ Concurrent scratch-card reveals over one shared particle pool. Purely additive -
25
54
  ## [1.1.0] - 2026-08-22
26
55
 
27
56
  Recipe organization and an extensible registry, modeled on `@zakkster/lite-ambient-fx`.
28
- No behaviour change to any recipe all 21 bodies are byte-identical to 1.0.0.
57
+ No behaviour change to any recipe -- all 21 bodies are byte-identical to 1.0.0.
29
58
 
30
59
  ### Added
31
- - **`RECIPE_META`** a live array of `{ id, name, category, themeable, needsUntaintedCanvas }`
60
+ - **`RECIPE_META`** -- a live array of `{ id, name, category, themeable, needsUntaintedCanvas }`
32
61
  for every recipe, so a host can build a picker (group by `category`, filter by `themeable`)
33
62
  without hardcoding the list. Mirrors lite-ambient's `THEME_META`.
34
- - **`registerRecipe(id, factory, meta?)`** register a custom recipe or override a built-in;
63
+ - **`registerRecipe(id, factory, meta?)`** -- register a custom recipe or override a built-in;
35
64
  it lands in `RECIPES` and `RECIPE_META` immediately so existing pickers keep working.
36
65
  Mirrors lite-ambient's `registerTheme()`. Omitted meta fields fall back to the prior entry,
37
66
  then a de-camelCased name, `category: 'custom'`, and `false` flags.
38
67
  - `resolvePalette` is now exported (and typed) for authors writing themeable recipes.
39
- - **Host-driven mode** `createScratchController(src, fx, { driven: true })` skips the
68
+ - **Host-driven mode** -- `createScratchController(src, fx, { driven: true })` skips the
40
69
  engine's RAF loop; the host calls `controller.tick(dt)` (dt in seconds) so one page clock
41
70
  drives N controllers. `tick()` is a no-op unless driven and a reveal is active.
42
- - **Shared engine** `createScratchController(src, fx, { engine })` reuses a caller-supplied
71
+ - **Shared engine** -- `createScratchController(src, fx, { engine })` reuses a caller-supplied
43
72
  particle engine, so a grid of scratch boxes holds one lane pool instead of one per box.
44
73
  A shared engine serves one reveal at a time (a reveal on a busy shared engine is ignored);
45
74
  `destroy()` never tears down a caller-supplied engine. The two options compose.
46
75
 
47
76
  ### Changed
48
77
  - **The two recipe files are merged into one `src/ScratchRecipes.js`, grouped by family**
49
- (particle / image / beam / css) with section banners replacing the arbitrary
78
+ (particle / image / beam / css) with section banners -- replacing the arbitrary
50
79
  `ScratchRecipes.js` (12) + `ScratchRecipes2.js` (9) split. `ScratchRecipes2.js` is removed
51
80
  from the package. All imports resolve through `index.js`, so the public API is unchanged.
52
81
  - `RECIPES` is now an extensible null-prototype registry (was a frozen object) so
@@ -60,18 +89,18 @@ zero-GC line on the reveal path, and stands up the torture gate.
60
89
 
61
90
  ### Added
62
91
  - `createScratchController(sourceCanvas, effectCanvas, { maxParticles, seed, scanPrecision })`
63
- scans the still-covered pixels of a scratch layer for spawn points, runs a reveal
92
+ -- scans the still-covered pixels of a scratch layer for spawn points, runs a reveal
64
93
  recipe to completion, clears the overlay, and calls the completion callback.
65
94
  - 21 reveal recipes: `burn`, `shatter`, `dissolve`, `explode`, `dragonBreath`,
66
95
  `iceBreath`, `shineWave`, `lightningCrawl`, `shine`, `peel`, `fade`, `implosion`,
67
96
  `glitchReveal`, `matrixDecay`, `goldDust`, `pixelShatter`, `laserScan`,
68
97
  `confettiBlast`, `liquidMelt`, `neonPulse`, `cosmicDust`.
69
98
  - **Themeable palettes.** The 14 recipes with a visible palette take a unified
70
- `{ colors, theme }` pair pass a `{ light, mid, dark }` `theme` shorthand or an
99
+ `{ colors, theme }` pair -- pass a `{ light, mid, dark }` `theme` shorthand or an
71
100
  explicit `colors` ramp; `colors` wins, and both default to the recipe's own palette.
72
101
  Replaces three inconsistent conventions (`color`, `colors`, hardcoded). New
73
102
  `resolvePalette` helper in `src/Palette.js`.
74
- - `RECIPES` registry (short-name factory) and `RECIPE_NAMES` for data-driven pickers.
103
+ - `RECIPES` registry (short-name -> factory) and `RECIPE_NAMES` for data-driven pickers.
75
104
  - Full TypeScript declarations (`index.d.ts`), including `Theme` and `ThemeableRecipeOptions`.
76
105
  - Test suite under `node:test` (46 checks): controller lifecycle, the `data[]` dataFlag
77
106
  indexing invariant, a reveal-to-completion smoke test for every recipe, and theming
@@ -84,7 +113,7 @@ zero-GC line on the reveal path, and stands up the torture gate.
84
113
 
85
114
  ### Changed
86
115
  - **Zero-GC reveal path.** `scanPixels` no longer mints an offscreen canvas or an
87
- object per surviving pixel on every reveal the scan canvas is built once and the
116
+ object per surviving pixel on every reveal -- the scan canvas is built once and the
88
117
  spawn points fill preallocated `Float32Array`s read through one reused `spot` object.
89
118
  The per-frame `tick` no longer allocates a fresh particle-view object; it reuses one.
90
119
  - Test runner is `node:test` (was vitest); `vitest` and `typescript` devDependencies
@@ -97,7 +126,7 @@ zero-GC line on the reveal path, and stands up the torture gate.
97
126
  `engine._loop` every frame, but the SoA engine already owns its own
98
127
  `requestAnimationFrame` loop and computes its own `dt`. Driving it a second time
99
128
  corrupted `dt`, so particle life never decayed and the completion condition
100
- (`alive === 0 && elapsed >= duration`) was never met a reveal would run forever. The
129
+ (`alive === 0 && elapsed >= duration`) was never met -- a reveal would run forever. The
101
130
  external ticker is removed; the engine self-drives via `start()` / `stop()`.
102
131
  - **`count: 0` recipes spawned a full pool.** `recipe.count || maxParticles` turned an
103
132
  explicit `0` (pure-canvas reveals like `shine`, `implosion`, `laserScan`) into