react-native-webrtc-kaleidoscope 2.7.3 → 2.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +59 -45
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -44,18 +44,16 @@ Every other turnkey option we could find is a feature welded to one vendor's cal
44
44
 
45
45
  What you get:
46
46
 
47
- - **[Bind a track once, then drive it with three verbs.](#the-three-verbs)** `kaleidoscope` swaps the background, `transform` reorients the frame, and `mask` tunes the segmentation edge. That is the entire runtime surface.
48
- - **[Hand it to an agent and it wires itself.](#with-an-agent)** Point a coding agent at [`llms.txt`](./llms.txt) and it installs the package, writes the config plugin, provisions a preset book, and gets an effect on screen.
49
- - **[Drop-in components, not a pipeline to assemble.](#quick-start)** A picker that reads your preset book, a headless live-editor, and a persistence provider; one import each, wire a callback, done.
50
- - **[Dozens of presets out of the box.](#presets)** Blur, painted worlds, bundled rooms, and animated shaders; every one is a starting point you can retune.
51
- - **[See what every effect costs.](#performance)** Each shader carries a measured GPU-cost annotation and the resolution tier is one knob, so you size the spend before you ship it.
52
- - **[Bench, meter, and thumbnail tools included.](#authoring-tooling)** A SPIR-V cost bench, a live GPU-time meter, a thumbnail renderer, and this README's preset gallery all regenerate from one command set.
53
- - **[Ship only the presets you reference.](#only-ship-what-you-use)** Per-asset subpath exports plus `sideEffects: false`; web tree-shakes by import and `expo prebuild` copies only the assets your book names into the native bundle.
54
- - **[A new shader is one folder.](#make-your-own-presets)** Every effect is a layer in one [compositor](#architecture); drop a `.frag` into `catalog/shaders/` and it codegens to web, Android, and iOS, masked and oriented for free.
47
+ - **Four simple functions.** `bindKaleidoscope(track, { presets })` hands back [`kaleidoscope`, `transform`, `mask`, and `dispose`](#the-four-verbs); that is the whole runtime API.
48
+ - **Agent-first setup.** Point a coding agent at [`llms.txt`](./llms.txt) and it [installs the package, writes the config plugin, and gets an effect on screen](#with-an-agent) without you babysitting it.
49
+ - **Turnkey implementation.** [Drop-in components](#quick-start), a picker, a live editor, and a persistence provider, render [dozens of presets](#presets) over your camera; wire a callback, ship it.
50
+ - **Cost and tooling.** Every shader carries a [measured GPU cost](#performance) you can read before you ship, and the [bench, meter, and thumbnail tools](#authoring-tooling) come in the box.
51
+ - **Won't bloat your binary.** Per-asset subpath exports and `sideEffects: false` mean you [ship only the presets you reference](#only-ship-what-you-use); web tree-shakes and native bundles just the assets your book names.
52
+ - **Built for extension.** A new shader is one folder that codegens to every platform, [clear by construction](#architecture); remix the compositor to [build your own worlds](#make-your-own-presets).
55
53
 
56
54
  ## Presets
57
55
 
58
- Like a synthesizer, the fastest way to judge it is to hear the patches. The demo book ships the gallery below; **every tile is a live link**, so click one and it opens on your own camera. Bring your own with a few lines (see [Make your own presets](#make-your-own-presets)).
56
+ The demo book ships the gallery below; **every tile is a live link**, so click one and it opens on your own camera. Bring your own with a few lines (see [Make your own presets](#make-your-own-presets)).
59
57
 
60
58
  <!-- PRESET-WAFFLE:START -->
61
59
 
@@ -73,7 +71,6 @@ Like a synthesizer, the fastest way to judge it is to hear the patches. The demo
73
71
  <tr><td align="right" valign="middle"><sub><b>Sci-Fi</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=sci-fi-light" title="Landscape"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/sci-fi-light.thumb.webp" alt="Landscape" title="Landscape" width="58" /></a></td></tr>
74
72
  <tr><td align="right" valign="middle"><sub><b>Ocean</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=oceanscape-dark" title="Underwater"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/oceanscape-dark.thumb.webp" alt="Underwater" title="Underwater" width="58" /></a></td></tr>
75
73
  <tr><td align="right" valign="middle"><sub><b>Debug</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=debug-resolutions" title="Resolutions"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/debug-resolutions.thumb.webp" alt="Resolutions" title="Resolutions" width="58" /></a></td></tr>
76
- <tr><td align="right" valign="middle"><sub><b>User</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=wolf-cave" title="Wolf Cave"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/wolf-cave.thumb.webp" alt="Wolf Cave" title="Wolf Cave" width="58" /></a></td></tr>
77
74
  <tr><td align="right" valign="middle"><sub><b>Sky</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=clouds" title="Daytime"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/catalog/composites/clouds/clouds.thumb.webp" alt="Daytime" title="Daytime" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=clouds-dawn" title="Dawn"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/clouds-dawn.thumb.webp" alt="Dawn" title="Dawn" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=clouds-dusk" title="Dusk"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/clouds-dusk.thumb.webp" alt="Dusk" title="Dusk" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=clouds-night" title="Night"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/clouds-night.thumb.webp" alt="Night" title="Night" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=clouds-otherworld" title="Otherworld"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/clouds-otherworld.thumb.webp" alt="Otherworld" title="Otherworld" width="58" /></a></td></tr>
78
75
  <tr><td align="right" valign="middle"><sub><b>Plasma</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=plasma-ocean" title="Ocean"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/plasma-ocean.thumb.webp" alt="Ocean" title="Ocean" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=plasma-sunset" title="Sunset"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/plasma-sunset.thumb.webp" alt="Sunset" title="Sunset" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=plasma-mint" title="Mint"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/plasma-mint.thumb.webp" alt="Mint" title="Mint" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=plasma-fast" title="Fast"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/plasma-fast.thumb.webp" alt="Fast" title="Fast" width="58" /></a></td></tr>
79
76
  <tr><td align="right" valign="middle"><sub><b>Kaleidoscope</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=kaleidoscope-stained-glass" title="Stained Glass"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/kaleidoscope-stained-glass.thumb.webp" alt="Stained Glass" title="Stained Glass" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=kaleidoscope-mandala" title="Mandala"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/kaleidoscope-mandala.thumb.webp" alt="Mandala" title="Mandala" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=kaleidoscope-prism" title="Prism"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/kaleidoscope-prism.thumb.webp" alt="Prism" title="Prism" width="58" /></a></td></tr>
@@ -87,7 +84,7 @@ Like a synthesizer, the fastest way to judge it is to hear the patches. The demo
87
84
  <tr><td align="right" valign="middle"><sub><b>Data-Mesh</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=data-mesh-datafield" title="Datafield"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/data-mesh-datafield.thumb.webp" alt="Datafield" title="Datafield" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=data-mesh-boardroom" title="Boardroom"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/data-mesh-boardroom.thumb.webp" alt="Boardroom" title="Boardroom" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=data-mesh-acid" title="Acid"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/data-mesh-acid.thumb.webp" alt="Acid" title="Acid" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=data-mesh-cobalt" title="Cobalt"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/data-mesh-cobalt.thumb.webp" alt="Cobalt" title="Cobalt" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=data-mesh-slate" title="Slate"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/data-mesh-slate.thumb.webp" alt="Slate" title="Slate" width="58" /></a></td></tr>
88
85
  </table>
89
86
 
90
- <sub>64 presets across 4 families (Effects, Worlds, Backgrounds, Shaders); click any to open it live, or <a href="#make-your-own-presets">make your own</a> in a few lines.</sub>
87
+ <sub>63 presets across 4 families (Effects, Worlds, Backgrounds, Shaders); click any to open it live, or <a href="#make-your-own-presets">make your own</a> in a few lines.</sub>
91
88
 
92
89
  <!-- PRESET-WAFFLE:END -->
93
90
 
@@ -164,14 +161,14 @@ import { presets } from './kaleidoscope.preset-book';
164
161
  const stream = await mediaDevices.getUserMedia({ video: true });
165
162
  const [track] = stream.getVideoTracks();
166
163
 
167
- const { kaleidoscope } = bindKaleidoscope(track, {
164
+ const { kaleidoscope, dispose } = bindKaleidoscope(track, {
168
165
  presets,
169
- // Web rebuilds the pipeline per command and yields a NEW track; read it here.
170
- // Native mutates the bound track in place.
166
+ // Web yields a NEW track per command; read it here. Native mutates in place.
171
167
  onTrack: (out) => {/* setPreviewTrack(out) */},
172
168
  });
173
169
 
174
170
  kaleidoscope('wizard-tower'); // autocompletes from your book
171
+ // call dispose() on unmount to release the track
175
172
  ```
176
173
 
177
174
  For a ready-made gallery, drop in the picker; it reads your book directly:
@@ -206,54 +203,71 @@ On web, LiveKit owns the `RTCRtpSender`, so you cannot swap the track yourself;
206
203
  ```ts
207
204
  import { KaleidoscopeProcessor, setMaskTuning } from 'react-native-webrtc-kaleidoscope/livekit';
208
205
 
209
- await localVideoTrack.setProcessor(new KaleidoscopeProcessor(['blur']), true);
210
- setMaskTuning({ hardness: 0.2, threshold: 0.85 }); // the processor-path twin of the `mask` verb
206
+ // A processor effect is a `composite` spec: the same layer stack a preset projects into.
207
+ const composite = {
208
+ name: 'composite',
209
+ layers: [
210
+ { id: 'bg', shader: 'blur', uniforms: { sigma: 8 } },
211
+ { id: 'you', shader: 'direct', target: 'subject' },
212
+ ],
213
+ };
214
+ await localVideoTrack.setProcessor(
215
+ new KaleidoscopeProcessor([composite]),
216
+ true,
217
+ );
218
+ setMaskTuning({ hardness: 0.2, threshold: 0.85 }); // the processor-path twin of `mask`
211
219
  ```
212
220
 
213
- The processor constructor takes raw effect names (`'blur'`, a shader basename), not preset-book ids. The `true` shows the processed stream in your local preview. The processor tears down its Insertable-Streams pipeline on camera flip (`restart`) and unpublish (`destroy`), so repeated flips do not leak generators.
221
+ The processor takes the same effect inputs as the core API: a `composite` spec (its layer stack), or a bare transform name like `'flip-x'`; not a preset-book id. The `true` shows the processed stream in your local preview. It tears down its Insertable-Streams pipeline on camera flip (`restart`) and unpublish (`destroy`), so repeated flips do not leak generators.
214
222
 
215
223
  ## Concepts
216
224
 
217
- Four nouns, learned in the order you meet them.
225
+ The vocabulary, in the order you meet it.
218
226
 
219
- - **Preset book**: the file you author (`kaleidoscope.preset-book.ts`); a flat, typed map of the effects your app can command. This is your point of entry; everything else hangs off it. Declare it `as const satisfies KaleidoscopePresetBook` for per-layer typing and autocompleting ids.
220
- - **Preset**: one named entry in the book, `{ name, taxonomy, thumbnail?, layers, controls? }`. It is what `kaleidoscope(id)` applies. `taxonomy` is the picker's grouping path, root first (`[group, category]`, e.g. `['Backgrounds', 'Office']`).
221
- - **Layer**: one entry in a preset's stack, `{ id, shader, target?, blend? }` plus the shader's own fields. Layers paint back to front. `id` is unique within the preset and is how you address it for live uniform patches.
222
- - **Composite**: what a preset becomes at runtime, the layer stack rendered into the output frame. There is exactly one registered native effect, `composite`; "one effect" is just a composite with a single layer.
227
+ | Term | What it is |
228
+ |---|---|
229
+ | **Preset book** | The file you author (`kaleidoscope.preset-book.ts`): a flat, typed map of the effects your app can command. Your point of entry; everything hangs off it. Declare `as const satisfies KaleidoscopePresetBook` for per-layer typing and id autocomplete. |
230
+ | **Preset** | One named entry in the book: `{ name, taxonomy, thumbnail?, layers, controls? }`. What `kaleidoscope(id)` applies. `taxonomy` is the picker's grouping path (`[group, category]`). |
231
+ | **Layer** | One entry in a preset's stack, painted back to front, addressed by a unique `id`. Three fields shape it:<br>&bull; **shader**: what it draws (`image`, `direct` the camera, `blur`, or a generative shader like `plasma` or `clouds`).<br>&bull; **target**: where it lands, `background` (fullscreen) or `subject` (stenciled to the person).<br>&bull; **blend**: how it stacks, opaque, `normal` (alpha-over), or `additive`. |
232
+ | **Composite** | What a preset becomes at runtime: the layer stack rendered into the frame. One registered native effect; "one effect" is a composite with a single layer. |
233
+ | **Patch** | A partial uniform override addressed by a layer `id`, merged over the baked values live with no rebuild. The lever the live editor and persistence ride on. |
234
+ | **Controls** | The editor component a preset supplies (`controls?`) so its tunable uniforms get sliders in the live panel. |
223
235
 
224
- A layer's `shader` is what it draws: `image` (a bundled WebP, takes a `source`), `direct` (the ingest-normalized camera frame, upright and non-mirrored), `blur`, or a generative shader (`plasma`, `clouds`, …; these take `uniforms`). Its `target` is where it lands: `background` (fullscreen, the default) or `subject` (stenciled to the segmented person), and the two combine: `direct` + `subject` is the masked person, `direct` + `background` is the raw full frame. Its `blend` is how it stacks: opaque base, `normal` (alpha-over), or `additive`.
236
+ `direct` + `subject` is the masked person; `direct` + `background` is the raw camera frame.
225
237
 
226
- ## The three verbs
238
+ ## The four verbs
227
239
 
228
240
  <p align="center">
229
- <code>kaleidoscope</code> &nbsp;•&nbsp; <code>transform</code> &nbsp;•&nbsp; <code>mask</code>
241
+ <code>kaleidoscope</code> &nbsp;•&nbsp; <code>transform</code> &nbsp;•&nbsp; <code>mask</code> &nbsp;•&nbsp; <code>dispose</code>
230
242
  </p>
231
243
 
232
- `bindKaleidoscope(track, { presets })` returns three functions. That is the whole runtime API.
244
+ `bindKaleidoscope(track, { presets })` returns four functions (plus the live `track`). That is the whole runtime API.
245
+
246
+ | Verb | What it does |
247
+ |---|---|
248
+ | **`kaleidoscope(id, patches?)`** | Swap the background. Pass a preset id; optionally patch a layer's uniforms live, addressed by `id`. Pass `null` to clear. |
249
+ | **`transform(state?)`** | Absolute flip and rotate, snapped to 90°. Every call is the full state from identity; call bare to reset. |
250
+ | **`mask(edge)`** | Tune the one segmentation edge shared by every effect: `hardness` and `threshold`, both `0..1`. |
251
+ | **`dispose()`** | Tear down the pipeline and release the bound track. Call on unmount. |
233
252
 
234
253
  ```ts
235
- const { kaleidoscope, transform, mask } = bindKaleidoscope(track, { presets, onTrack });
236
-
237
- // kaleidoscope: the art axis. Pass a preset id (autocompletes from your book):
238
- kaleidoscope('wizard-tower');
239
- // Override a layer's uniforms live, addressed by id, while the preset is active
240
- // (merged over the baked values, no pipeline rebuild). `shader` is a compile-time
241
- // discriminant that types `uniforms`; the layer is reached by `id`, not by shader:
242
- kaleidoscope('blur-soft', [{ id: 'bg', shader: 'blur', uniforms: { sigma: 9 } }]);
243
- kaleidoscope(null); // clear the art
244
-
245
- // transform: absolute geometry. Every call is the full state from identity;
246
- // re-pass what you want to keep. rotate snaps to the nearest 90°.
254
+ const { kaleidoscope, transform, mask, dispose } =
255
+ bindKaleidoscope(track, { presets, onTrack });
256
+
257
+ kaleidoscope('wizard-tower'); // a preset id
258
+ kaleidoscope('blur-soft', [ // patch a layer live, by id
259
+ { id: 'bg', shader: 'blur', uniforms: { sigma: 9 } },
260
+ ]);
261
+ kaleidoscope(null); // clear the art
262
+
247
263
  transform({ flip: { x: true }, rotate: 90 });
248
- transform(); // reset to identity
264
+ transform(); // reset to identity
249
265
 
250
- // mask: one segmentation edge for the whole composite (not per layer). Both 0..1.
251
266
  mask({ hardness: 0.5, threshold: 0.5 });
267
+ dispose(); // on unmount
252
268
  ```
253
269
 
254
- Many uniforms are normalized `0..1` by convention; others (`sigma`, scales, counts) carry natural units, as the examples above show. JSDoc documents each option's expected range as an IntelliSense hint (ranges are not enforced at runtime; validate in your own layer if you forward them to end users).
255
-
256
- **Tuning note.** All three platforms run MediaPipe selfie segmentation, so the mask edge that suits one may differ slightly from another. `mask` defaults to `0.5 / 0.5`; nudge `hardness` and `threshold` to match your camera and lighting.
270
+ Many uniforms are normalized `0..1`; others (`sigma`, scales, counts) carry natural units, and JSDoc documents each range. `mask` defaults to `0.5 / 0.5`; nudge it to match your camera and lighting.
257
271
 
258
272
  ## Make your own presets
259
273
 
@@ -272,7 +286,7 @@ A preset is a composition: **every preset is a back-to-front stack of N layers**
272
286
  },
273
287
  ```
274
288
 
275
- The packaged `wolf-cave` preset in the [demo book](./demo/kaleidoscope.preset-book.ts) is a worked example of a multi-layer world (a generative shader, a cut-out image, and the masked person).
289
+ The demo book's [`wolf-cave`](./demo/kaleidoscope.preset-book.ts) is a runnable example of a custom composite (a bundled image plus the masked person). It is demo-owned, its image not shipped in the package, which is the point: it shows a consumer adding their own background.
276
290
 
277
291
  - **Bundled images** ship as tree-shakeable `image` layers, filed by category and imported per image (`import { officeDark } from 'react-native-webrtc-kaleidoscope/images/office/office-dark'`). On web a `source` can also be any image URL or data URI; native resolves bundled ids only. See [`catalog/images/README.md`](./catalog/images/README.md).
278
292
  - **New shaders** drop a single `.frag` + typed `.ts` into `catalog/shaders/<name>/`; `bun run build:shaders` codegens the web and Android sources and transpiles the iOS Metal. The canonical upright frame and the mask stencil come for free; you write zero orientation code. See [`catalog/shaders/README.md`](./catalog/shaders/README.md).
@@ -282,7 +296,7 @@ After adding a preset to the demo book, regenerate its thumbnail and this README
282
296
 
283
297
  ## Drop-in UI
284
298
 
285
- Build your own controls against the three verbs, or import the headless, controlled components. All are presentational: they emit a selection or a patch, you apply it.
299
+ Build your own controls against the four verbs, or import the headless, controlled components. All are presentational: they emit a selection or a patch, you apply it.
286
300
 
287
301
  ### The picker
288
302
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-webrtc-kaleidoscope",
3
- "version": "2.7.3",
3
+ "version": "2.7.4",
4
4
  "description": "Live video effects (blur, background replacement, generative backgrounds, flip/rotate) for react-native-webrtc, packaged as a managed-Expo-friendly Expo Module. Working on web, Android, and iOS. Active development.",
5
5
  "keywords": [
6
6
  "react-native",