@zakkster/lite-scratch-fx 1.0.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,5 +1,86 @@
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
+
30
+ ## [1.2.0] - 2026-08-22
31
+
32
+ Concurrent scratch-card reveals over one shared particle pool. Purely additive --
33
+ `createScratchController` and its options are unchanged.
34
+
35
+ ### Added
36
+ - **`createScratchStage({ maxParticles, seed })`** -- a stage that owns one particle
37
+ engine and lets any number of controllers reveal **at the same time** over that one
38
+ pool (where `{ engine }` allowed only one reveal at a time). Each
39
+ `stage.createController(src, fx, { capacity })` reserves a fixed sub-range of the lanes,
40
+ renders only its own particles through reused subarray views (zero per-frame allocation),
41
+ and keeps its own deterministic RNG. `stage.tick(dt)` (seconds) drives every active reveal
42
+ from one clock; reserving past `maxParticles` throws. Stage-managed controllers have no
43
+ `tick` of their own. See `decisions/0001-concurrent-shared-reveals.md`.
44
+ - `src/PixelScan.js` -- the reveal-scan logic extracted into a shared `createPixelScanner`,
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.
48
+
49
+ ### Notes
50
+ - Feasible with no change to `@zakkster/lite-soa-particle-engine`: raw-mode `tick(dt)` is
51
+ pure dispatch and the lanes are public typed arrays recipes already write, so a stage can
52
+ partition one pool into per-controller sub-ranges entirely in this package.
53
+
54
+ ## [1.1.0] - 2026-08-22
55
+
56
+ Recipe organization and an extensible registry, modeled on `@zakkster/lite-ambient-fx`.
57
+ No behaviour change to any recipe -- all 21 bodies are byte-identical to 1.0.0.
58
+
59
+ ### Added
60
+ - **`RECIPE_META`** -- a live array of `{ id, name, category, themeable, needsUntaintedCanvas }`
61
+ for every recipe, so a host can build a picker (group by `category`, filter by `themeable`)
62
+ without hardcoding the list. Mirrors lite-ambient's `THEME_META`.
63
+ - **`registerRecipe(id, factory, meta?)`** -- register a custom recipe or override a built-in;
64
+ it lands in `RECIPES` and `RECIPE_META` immediately so existing pickers keep working.
65
+ Mirrors lite-ambient's `registerTheme()`. Omitted meta fields fall back to the prior entry,
66
+ then a de-camelCased name, `category: 'custom'`, and `false` flags.
67
+ - `resolvePalette` is now exported (and typed) for authors writing themeable recipes.
68
+ - **Host-driven mode** -- `createScratchController(src, fx, { driven: true })` skips the
69
+ engine's RAF loop; the host calls `controller.tick(dt)` (dt in seconds) so one page clock
70
+ drives N controllers. `tick()` is a no-op unless driven and a reveal is active.
71
+ - **Shared engine** -- `createScratchController(src, fx, { engine })` reuses a caller-supplied
72
+ particle engine, so a grid of scratch boxes holds one lane pool instead of one per box.
73
+ A shared engine serves one reveal at a time (a reveal on a busy shared engine is ignored);
74
+ `destroy()` never tears down a caller-supplied engine. The two options compose.
75
+
76
+ ### Changed
77
+ - **The two recipe files are merged into one `src/ScratchRecipes.js`, grouped by family**
78
+ (particle / image / beam / css) with section banners -- replacing the arbitrary
79
+ `ScratchRecipes.js` (12) + `ScratchRecipes2.js` (9) split. `ScratchRecipes2.js` is removed
80
+ from the package. All imports resolve through `index.js`, so the public API is unchanged.
81
+ - `RECIPES` is now an extensible null-prototype registry (was a frozen object) so
82
+ `registerRecipe` can add to it. Reads are unaffected.
83
+
3
84
  ## [1.0.0] - 2026-08-22
4
85
 
5
86
  First published release. The effects and controller existed as loose source files; this
@@ -8,18 +89,18 @@ zero-GC line on the reveal path, and stands up the torture gate.
8
89
 
9
90
  ### Added
10
91
  - `createScratchController(sourceCanvas, effectCanvas, { maxParticles, seed, scanPrecision })`
11
- 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
12
93
  recipe to completion, clears the overlay, and calls the completion callback.
13
94
  - 21 reveal recipes: `burn`, `shatter`, `dissolve`, `explode`, `dragonBreath`,
14
95
  `iceBreath`, `shineWave`, `lightningCrawl`, `shine`, `peel`, `fade`, `implosion`,
15
96
  `glitchReveal`, `matrixDecay`, `goldDust`, `pixelShatter`, `laserScan`,
16
97
  `confettiBlast`, `liquidMelt`, `neonPulse`, `cosmicDust`.
17
98
  - **Themeable palettes.** The 14 recipes with a visible palette take a unified
18
- `{ 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
19
100
  explicit `colors` ramp; `colors` wins, and both default to the recipe's own palette.
20
101
  Replaces three inconsistent conventions (`color`, `colors`, hardcoded). New
21
102
  `resolvePalette` helper in `src/Palette.js`.
22
- - `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.
23
104
  - Full TypeScript declarations (`index.d.ts`), including `Theme` and `ThemeableRecipeOptions`.
24
105
  - Test suite under `node:test` (46 checks): controller lifecycle, the `data[]` dataFlag
25
106
  indexing invariant, a reveal-to-completion smoke test for every recipe, and theming
@@ -32,7 +113,7 @@ zero-GC line on the reveal path, and stands up the torture gate.
32
113
 
33
114
  ### Changed
34
115
  - **Zero-GC reveal path.** `scanPixels` no longer mints an offscreen canvas or an
35
- 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
36
117
  spawn points fill preallocated `Float32Array`s read through one reused `spot` object.
37
118
  The per-frame `tick` no longer allocates a fresh particle-view object; it reuses one.
38
119
  - Test runner is `node:test` (was vitest); `vitest` and `typescript` devDependencies
@@ -45,7 +126,7 @@ zero-GC line on the reveal path, and stands up the torture gate.
45
126
  `engine._loop` every frame, but the SoA engine already owns its own
46
127
  `requestAnimationFrame` loop and computes its own `dt`. Driving it a second time
47
128
  corrupted `dt`, so particle life never decayed and the completion condition
48
- (`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
49
130
  external ticker is removed; the engine self-drives via `start()` / `stop()`.
50
131
  - **`count: 0` recipes spawned a full pool.** `recipe.count || maxParticles` turned an
51
132
  explicit `0` (pure-canvas reveals like `shine`, `implosion`, `laserScan`) into