react-native-webrtc-kaleidoscope 2.7.2 → 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.
- package/README.md +269 -198
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -1,20 +1,36 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<
|
|
2
|
+
<a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/">
|
|
3
|
+
<img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/evidence/issue-verification/evidence/2026-06-14-readme-demo/showcase.gif" alt="One person held in frame by the live segmentation mask while the background cycles through a parametric blur, painted worlds, and animated generative shaders" width="720" />
|
|
4
|
+
</a>
|
|
3
5
|
</p>
|
|
4
6
|
|
|
5
7
|
<p align="center">
|
|
6
|
-
<a
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
<sub><b>This is the real camera, not a still pasted over a video.</b> The live segmentation mask holds one person while shipped presets swap in behind. Every icon below is a live preset, in the order the loop plays them; click one to run it on your own camera.</sub>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=blur-medium" title="Blur">🌫️</a>
|
|
13
|
+
<a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=kaleidoscope-mandala" title="Kaleidoscope mandala">🔮</a>
|
|
14
|
+
<a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=wizard-tower" title="Wizard's tower">🧙</a>
|
|
15
|
+
<a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=outrun-classic" title="Outrun grid">🌆</a>
|
|
16
|
+
<a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=observation-deck" title="Observation deck">🛸</a>
|
|
17
|
+
<a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=data-mesh-cobalt" title="Cobalt data-mesh">🔷</a>
|
|
18
|
+
<a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=fairy-grotto" title="Fairy grotto">🧚</a>
|
|
19
|
+
<a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=simianlights-hearth" title="Simianlights hearth">🪔</a>
|
|
20
|
+
<a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=simiancraft-dark" title="Simiancraft">🐒</a>
|
|
21
|
+
<sub><a href="#presets">+ dozens more</a></sub>
|
|
9
22
|
</p>
|
|
10
23
|
|
|
11
24
|
<p align="center">
|
|
12
|
-
<
|
|
25
|
+
<a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/">
|
|
26
|
+
<img src="https://img.shields.io/badge/▶%20Live%20demo-blur%20yourself%2C%20swap%20the%20room-8b5cf6?style=for-the-badge" alt="Live demo" />
|
|
27
|
+
</a>
|
|
13
28
|
</p>
|
|
14
29
|
|
|
15
|
-
|
|
30
|
+
<h1>
|
|
31
|
+
<img src="./docs/kaleidoscope-logo-thumb.webp" alt="kaleidoscope logo" width="36" /> react-native-webrtc-kaleidoscope
|
|
32
|
+
</h1>
|
|
16
33
|
|
|
17
|
-
[](#status)
|
|
18
34
|
[](https://www.npmjs.com/package/react-native-webrtc-kaleidoscope)
|
|
19
35
|
[](https://www.npmjs.com/package/react-native-webrtc-kaleidoscope)
|
|
20
36
|
[](https://github.com/simiancraft/react-native-webrtc-kaleidoscope/actions/workflows/ci.yml)
|
|
@@ -22,140 +38,120 @@
|
|
|
22
38
|
[](https://securityscorecards.dev/viewer/?uri=github.com/simiancraft/react-native-webrtc-kaleidoscope)
|
|
23
39
|
[](./LICENSE)
|
|
24
40
|
|
|
25
|
-
|
|
26
|
-
<code>kaleidoscope</code> • <code>transform</code> • <code>mask</code>
|
|
27
|
-
</p>
|
|
41
|
+
> **Blur yourself, swap the room; live, on the device.** Real-time background blur and replacement for React Native and web video calls: bundled images, animated generative shaders, or painted worlds, each stenciled to the person by an on-device segmentation mask. Works with `react-native-webrtc` and LiveKit on Android, iOS, and Chromium browsers; managed-Expo-friendly.
|
|
28
42
|
|
|
29
|
-
|
|
43
|
+
Every other turnkey option we could find is a feature welded to one vendor's calling SDK (Stream, Agora, 100ms, and the rest). This one attaches to `react-native-webrtc` instead, so it rides whatever stack you already run, LiveKit included. And where those vendors ship blur and a static image, this paints animated, generative-shader backgrounds and whole worlds.
|
|
30
44
|
|
|
31
|
-
|
|
45
|
+
What you get:
|
|
32
46
|
|
|
33
|
-
|
|
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).
|
|
34
53
|
|
|
35
|
-
|
|
54
|
+
## Presets
|
|
36
55
|
|
|
37
|
-
|
|
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)).
|
|
38
57
|
|
|
39
|
-
|
|
40
|
-
- **`transform`**: absolute flips and rotation (snapped to 90°), reapplied as full state each call.
|
|
41
|
-
- **`mask`**: the segmentation edge (hardness, threshold) shared by every art effect.
|
|
42
|
-
- **Tree-shaking**: declare a preset book; only the assets you reference ship in your native bundle (web tree-shakes by import).
|
|
43
|
-
- **Drop-in UI (optional)**: a preset-driven `PresetBookMenu` (the menu) under `react-native-webrtc-kaleidoscope/preset-book-menu`, plus a headless live-editor kit (`PresetControlPanel`, mask and transform controls, a theme provider) under `react-native-webrtc-kaleidoscope/preset-control-panel`. Controlled and NativeWind-ready. See [Drop-in UI](#drop-in-ui-optional).
|
|
58
|
+
<!-- PRESET-WAFFLE:START -->
|
|
44
59
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
60
|
+
<table cellspacing="0" cellpadding="2">
|
|
61
|
+
<tr><td align="right" valign="middle"><sub><b>Blur</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=blur-low" title="Low"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/blur-low.thumb.webp" alt="Low" title="Low" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=blur-medium" title="Medium"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/blur-medium.thumb.webp" alt="Medium" title="Medium" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=blur-high" title="High"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/blur-high.thumb.webp" alt="High" title="High" width="58" /></a></td></tr>
|
|
62
|
+
<tr><td align="right" valign="middle"><sub><b>Wizard Tower</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=wizard-tower" title="Wizard Tower"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/catalog/composites/wizard-tower/wizard-tower.thumb.webp" alt="Wizard Tower" title="Wizard Tower" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=wizard-tower-night" title="Night"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/catalog/composites/wizard-tower-night/wizard-tower-night.thumb.webp" alt="Night" title="Night" width="58" /></a></td></tr>
|
|
63
|
+
<tr><td align="right" valign="middle"><sub><b>Spaceship</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=observation-deck" title="Observation Deck"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/catalog/composites/observation-deck/observation-deck.thumb.webp" alt="Observation Deck" title="Observation Deck" width="58" /></a></td></tr>
|
|
64
|
+
<tr><td align="right" valign="middle"><sub><b>Fairy Cave</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=fairy-cave" title="Fairy Cave"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/catalog/composites/fairy-cave/fairy-cave.thumb.webp" alt="Fairy Cave" title="Fairy Cave" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=fairy-grotto" title="Grotto"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/catalog/composites/fairy-grotto/fairy-grotto.thumb.webp" alt="Grotto" title="Grotto" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=fairy-hollow" title="Hollow"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/catalog/composites/fairy-hollow/fairy-hollow.thumb.webp" alt="Hollow" title="Hollow" width="58" /></a></td></tr>
|
|
65
|
+
<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=underwater" title="Underwater"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/catalog/composites/underwater/underwater.thumb.webp" alt="Underwater" title="Underwater" width="58" /></a></td></tr>
|
|
66
|
+
<tr><td align="right" valign="middle"><sub><b>Corporate</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=corporate-blobs" title="Blobs"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/catalog/composites/corporate-blobs/corporate-blobs.thumb.webp" alt="Blobs" title="Blobs" width="58" /></a></td></tr>
|
|
67
|
+
<tr><td align="right" valign="middle"><sub><b>Simiancraft</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=simiancraft-light" title="Simiancraft Light"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/simiancraft-light.thumb.webp" alt="Simiancraft Light" title="Simiancraft Light" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=simiancraft-dark" title="Simiancraft Dark"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/simiancraft-dark.thumb.webp" alt="Simiancraft Dark" title="Simiancraft Dark" width="58" /></a></td></tr>
|
|
68
|
+
<tr><td align="right" valign="middle"><sub><b>Office</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=office-dark" title="Dark Office"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/office-dark.thumb.webp" alt="Dark Office" title="Dark Office" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=office-light" title="Light Office"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/office-light.thumb.webp" alt="Light Office" title="Light Office" width="58" /></a></td></tr>
|
|
69
|
+
<tr><td align="right" valign="middle"><sub><b>Nature</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=landscape-light" title="Nature Light"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/landscape-light.thumb.webp" alt="Nature Light" title="Nature Light" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=landscape-dark" title="Nature Dark"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/landscape-dark.thumb.webp" alt="Nature Dark" title="Nature Dark" width="58" /></a></td></tr>
|
|
70
|
+
<tr><td align="right" valign="middle"><sub><b>Home</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=home-light" title="Home Light"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/home-light.thumb.webp" alt="Home Light" title="Home Light" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=home-dark" title="Home Dark"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/home-dark.thumb.webp" alt="Home Dark" title="Home Dark" width="58" /></a></td></tr>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
77
|
+
<tr><td align="right" valign="middle"><sub><b>Neo-Memphis</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=neo-memphis-jazz-cup" title="Jazz Cup"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/neo-memphis-jazz-cup.thumb.webp" alt="Jazz Cup" title="Jazz Cup" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=neo-memphis-bauhaus" title="Bauhaus"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/neo-memphis-bauhaus.thumb.webp" alt="Bauhaus" title="Bauhaus" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=neo-memphis-confetti" title="Confetti"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/neo-memphis-confetti.thumb.webp" alt="Confetti" title="Confetti" width="58" /></a></td></tr>
|
|
78
|
+
<tr><td align="right" valign="middle"><sub><b>Halftone</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=halftone-boardroom" title="Boardroom"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/halftone-boardroom.thumb.webp" alt="Boardroom" title="Boardroom" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=halftone-press" title="Press"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/halftone-press.thumb.webp" alt="Press" title="Press" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=halftone-ripple" title="Ripple"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/halftone-ripple.thumb.webp" alt="Ripple" title="Ripple" width="58" /></a></td></tr>
|
|
79
|
+
<tr><td align="right" valign="middle"><sub><b>Aurora</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=aurora-corporate-silk" title="Corporate Silk"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/aurora-corporate-silk.thumb.webp" alt="Corporate Silk" title="Corporate Silk" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=aurora-dusk" title="Dusk"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/aurora-dusk.thumb.webp" alt="Dusk" title="Dusk" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=aurora-polar" title="Polar"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/aurora-polar.thumb.webp" alt="Polar" title="Polar" width="58" /></a></td></tr>
|
|
80
|
+
<tr><td align="right" valign="middle"><sub><b>Outrun</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=outrun-classic" title="Classic"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/outrun-classic.thumb.webp" alt="Classic" title="Classic" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=outrun-miami" title="Miami"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/outrun-miami.thumb.webp" alt="Miami" title="Miami" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=outrun-circuit" title="Circuit"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/outrun-circuit.thumb.webp" alt="Circuit" title="Circuit" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=outrun-acid" title="Acid"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/outrun-acid.thumb.webp" alt="Acid" title="Acid" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=outrun-vapor" title="Vapor"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/outrun-vapor.thumb.webp" alt="Vapor" title="Vapor" width="58" /></a></td></tr>
|
|
81
|
+
<tr><td align="right" valign="middle"><sub><b>Nebula</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=nebula" title="Nebula"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/catalog/composites/nebula/nebula.thumb.webp" alt="Nebula" title="Nebula" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=nebula-ember" title="Ember"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/nebula-ember.thumb.webp" alt="Ember" title="Ember" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=nebula-drift" title="Drift"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/nebula-drift.thumb.webp" alt="Drift" title="Drift" width="58" /></a></td></tr>
|
|
82
|
+
<tr><td align="right" valign="middle"><sub><b>Simianlights</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=simianlights" title="Simianlights"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/catalog/composites/simianlights/simianlights.thumb.webp" alt="Simianlights" title="Simianlights" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=simianlights-glacier" title="Glacier"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/simianlights-glacier.thumb.webp" alt="Glacier" title="Glacier" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=simianlights-hearth" title="Hearth"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/simianlights-hearth.thumb.webp" alt="Hearth" title="Hearth" width="58" /></a></td></tr>
|
|
83
|
+
<tr><td align="right" valign="middle"><sub><b>Interior</b></sub></td><td valign="middle"><a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=interior-home" title="Home"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/interior-home.thumb.webp" alt="Home" title="Home" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=interior-office" title="Office"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/interior-office.thumb.webp" alt="Office" title="Office" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=interior-ab-shaft" title="A/B 1-shaft"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/interior-ab-shaft.thumb.webp" alt="A/B 1-shaft" title="A/B 1-shaft" width="58" /></a> <a href="https://simiancraft.github.io/react-native-webrtc-kaleidoscope/?preset=interior-ab-3beam" title="A/B 3-beam"><img src="https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/demo/assets/thumbnails/interior-ab-3beam.thumb.webp" alt="A/B 3-beam" title="A/B 3-beam" width="58" /></a></td></tr>
|
|
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>
|
|
85
|
+
</table>
|
|
51
86
|
|
|
52
|
-
|
|
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>
|
|
53
88
|
|
|
54
|
-
|
|
89
|
+
<!-- PRESET-WAFFLE:END -->
|
|
55
90
|
|
|
56
|
-
|
|
91
|
+
<sub>Runs on Android, iOS, and Chromium browsers (Chrome, Edge), against either `react-native-webrtc` or LiveKit. Platform specifics and the Safari/Firefox fallback are in [Platform support](#platform-support).</sub>
|
|
57
92
|
|
|
58
|
-
|
|
59
|
-
bun add react-native-webrtc react-native-webrtc-kaleidoscope
|
|
60
|
-
```
|
|
93
|
+
## Quick start
|
|
61
94
|
|
|
62
|
-
|
|
95
|
+
Two paths to a working integration: hand it to a coding agent, or wire it yourself. Either way the shape is the same: install, add the config plugin, declare a preset book, bind a track.
|
|
63
96
|
|
|
64
|
-
###
|
|
97
|
+
### With an agent
|
|
65
98
|
|
|
66
|
-
|
|
99
|
+
Point your coding agent (Claude Code, Cursor, Copilot, …) at [`llms.txt`](./llms.txt). It is written for exactly this: a top-to-bottom integration guide that installs the package, writes the config-plugin entry, provisions a runnable preset book, and gets an effect on screen, with a six-file starting set lifted from the working `demo/`.
|
|
67
100
|
|
|
68
|
-
```sh
|
|
69
|
-
bun add @livekit/react-native @livekit/react-native-webrtc react-native-webrtc-kaleidoscope
|
|
70
101
|
```
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
**Native wiring.** `@livekit/react-native` hands you a `LocalVideoTrack`; bind effects to its underlying `MediaStreamTrack`:
|
|
75
|
-
|
|
76
|
-
```ts
|
|
77
|
-
import { bindKaleidoscope } from 'react-native-webrtc-kaleidoscope';
|
|
78
|
-
import { presets } from './kaleidoscope.preset-book';
|
|
79
|
-
|
|
80
|
-
const { kaleidoscope } = bindKaleidoscope(localCameraTrack.mediaStreamTrack, { presets });
|
|
81
|
-
kaleidoscope('blur-soft');
|
|
102
|
+
Read https://raw.githubusercontent.com/simiancraft/react-native-webrtc-kaleidoscope/main/llms.txt
|
|
103
|
+
and integrate react-native-webrtc-kaleidoscope into this Expo app: add the config
|
|
104
|
+
plugin, create a starter preset book, and show the PresetBookMenu over my camera track.
|
|
82
105
|
```
|
|
83
106
|
|
|
84
|
-
|
|
107
|
+
### Manually
|
|
85
108
|
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
await localVideoTrack.setProcessor(new KaleidoscopeProcessor(['blur']), true);
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
The `true` second argument to `setProcessor` 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.
|
|
93
|
-
|
|
94
|
-
To tune the segmentation mask edge on the processor path, use `setMaskTuning`; it is the processor-path twin of the binding's `mask` verb. The mask edge is page-shared state every kaleidoscope pipeline reads per frame, so the write reaches every active processor on the next frame with no rebuild:
|
|
95
|
-
|
|
96
|
-
```ts
|
|
97
|
-
import { setMaskTuning } from 'react-native-webrtc-kaleidoscope/livekit';
|
|
98
|
-
|
|
99
|
-
setMaskTuning({ hardness: 0.2, threshold: 0.85 });
|
|
109
|
+
```sh
|
|
110
|
+
bun add react-native-webrtc react-native-webrtc-kaleidoscope
|
|
100
111
|
```
|
|
101
112
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
Add the config plugin to `app.config.ts`:
|
|
113
|
+
`react-native-webrtc` is a peer dependency; install it explicitly. (Using LiveKit instead? See [Using LiveKit](#using-livekit).) Add the config plugin to `app.config.ts`, then rebuild native code:
|
|
105
114
|
|
|
106
115
|
```ts
|
|
107
|
-
export default {
|
|
108
|
-
expo: {
|
|
109
|
-
plugins: ['react-native-webrtc-kaleidoscope'],
|
|
110
|
-
},
|
|
111
|
-
};
|
|
116
|
+
export default { expo: { plugins: ['react-native-webrtc-kaleidoscope'] } };
|
|
112
117
|
```
|
|
113
118
|
|
|
114
|
-
(`react-native-webrtc` 124.x does not ship a config plugin upstream; do not list it in `plugins`. If you are on a fork that adds one, add it explicitly.)
|
|
115
|
-
|
|
116
|
-
Then rebuild native code:
|
|
117
|
-
|
|
118
119
|
```sh
|
|
119
120
|
bunx expo prebuild
|
|
120
121
|
```
|
|
121
122
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
First declare a **preset book** in your project: a flat catalog of **composites**, the only things you can command. A composite is `{ name, taxonomy, thumbnail?, layers }`, where `taxonomy` is the picker's grouping path, root first (`[group]` or `[group, category]`, e.g. `['Backgrounds', 'Office']`); everything is a layer stack, painted back to front. A layer is `{ id, shader, target?, blend? }` plus the shader's fields: `image` takes a `source`; `direct` samples the ingest-normalized (upright, non-mirrored) camera frame for its target (`target: 'subject'` is the masked person, `target: 'background'` the full frame); `blur` and the generative shaders (`plasma`, `clouds`, …) take `uniforms`. `target` defaults to `'background'` (fullscreen); `'subject'` stencils to the segmented person. Each layer's `id` is unique within its composite. Declare the book `as const satisfies PresetBook` for per-layer typing.
|
|
123
|
+
Declare a **preset book**: a flat catalog of the effects you can command. A rudimentary one is three entries:
|
|
125
124
|
|
|
126
125
|
```ts
|
|
127
126
|
// kaleidoscope.preset-book.ts
|
|
128
|
-
import type {
|
|
127
|
+
import type { KaleidoscopePresetBook } from 'react-native-webrtc-kaleidoscope';
|
|
129
128
|
import { officeDark } from 'react-native-webrtc-kaleidoscope/images/office/office-dark';
|
|
130
|
-
// Packaged composites ship ready to use; import and spread them in.
|
|
131
129
|
import { wizardTower } from 'react-native-webrtc-kaleidoscope/composites/wizard-tower';
|
|
132
130
|
|
|
133
131
|
export const presets = {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
taxonomy: ['Backgrounds', 'Office'],
|
|
138
|
-
thumbnail: officeDark,
|
|
132
|
+
'blur-soft': {
|
|
133
|
+
name: 'Soft blur',
|
|
134
|
+
taxonomy: ['Effects', 'Blur'],
|
|
139
135
|
layers: [
|
|
140
|
-
{ id: '
|
|
136
|
+
{ id: 'bg', shader: 'blur', target: 'background', uniforms: { sigma: 5 } },
|
|
141
137
|
{ id: 'you', shader: 'direct', target: 'subject' },
|
|
142
138
|
],
|
|
143
139
|
},
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
140
|
+
'office-dark': {
|
|
141
|
+
name: 'Dark office',
|
|
142
|
+
taxonomy: ['Backgrounds', 'Office'],
|
|
143
|
+
thumbnail: officeDark,
|
|
148
144
|
layers: [
|
|
149
|
-
{ id: '
|
|
145
|
+
{ id: 'office', shader: 'image', source: officeDark },
|
|
150
146
|
{ id: 'you', shader: 'direct', target: 'subject' },
|
|
151
147
|
],
|
|
152
148
|
},
|
|
153
|
-
// A packaged multi-layer
|
|
149
|
+
// A packaged multi-layer world, imported and spread in.
|
|
154
150
|
'wizard-tower': wizardTower,
|
|
155
|
-
} as const satisfies
|
|
151
|
+
} as const satisfies KaleidoscopePresetBook;
|
|
156
152
|
```
|
|
157
153
|
|
|
158
|
-
|
|
154
|
+
Bind a track once and drive it:
|
|
159
155
|
|
|
160
156
|
```ts
|
|
161
157
|
import { mediaDevices } from 'react-native-webrtc';
|
|
@@ -165,63 +161,150 @@ import { presets } from './kaleidoscope.preset-book';
|
|
|
165
161
|
const stream = await mediaDevices.getUserMedia({ video: true });
|
|
166
162
|
const [track] = stream.getVideoTracks();
|
|
167
163
|
|
|
168
|
-
const { kaleidoscope,
|
|
164
|
+
const { kaleidoscope, dispose } = bindKaleidoscope(track, {
|
|
169
165
|
presets,
|
|
170
|
-
// Web
|
|
171
|
-
|
|
172
|
-
onTrack: (out) => {
|
|
173
|
-
/* setPreviewTrack(out) */
|
|
174
|
-
},
|
|
166
|
+
// Web yields a NEW track per command; read it here. Native mutates in place.
|
|
167
|
+
onTrack: (out) => {/* setPreviewTrack(out) */},
|
|
175
168
|
});
|
|
176
169
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
170
|
+
kaleidoscope('wizard-tower'); // autocompletes from your book
|
|
171
|
+
// call dispose() on unmount to release the track
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
For a ready-made gallery, drop in the picker; it reads your book directly:
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
import { PresetBookMenu } from 'react-native-webrtc-kaleidoscope/preset-book-menu';
|
|
178
|
+
import { presets } from './kaleidoscope.preset-book';
|
|
179
|
+
|
|
180
|
+
<PresetBookMenu presets={presets} value={art} onSelect={setArt} />;
|
|
181
|
+
// route onSelect into kaleidoscope() and the picker is wired.
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Want the selection, live tweaks, and mask edge to survive a reload? Wrap your app in the [persistence provider](#persistence). Want the styled UI and a live tuning panel? See [Drop-in UI](#drop-in-ui).
|
|
185
|
+
|
|
186
|
+
### Using LiveKit
|
|
187
|
+
|
|
188
|
+
If your project uses `@livekit/react-native` it pulls in `@livekit/react-native-webrtc`, a fork that preserves the same `videoEffects` native classes and `_setVideoEffects` JS API. Kaleidoscope works against either fork; the Android Gradle script picks whichever one autolinking surfaced. Pick **one** fork, never both, or the native classes collide.
|
|
189
|
+
|
|
190
|
+
```sh
|
|
191
|
+
bun add @livekit/react-native @livekit/react-native-webrtc react-native-webrtc-kaleidoscope
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
On native, `@livekit/react-native` hands you a `LocalVideoTrack`; bind to its underlying `MediaStreamTrack`:
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
const { kaleidoscope } = bindKaleidoscope(localCameraTrack.mediaStreamTrack, { presets });
|
|
198
|
+
kaleidoscope('blur-soft');
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
On web, LiveKit owns the `RTCRtpSender`, so you cannot swap the track yourself; go through LiveKit's processor API. The opt-in `/livekit` subpath ships a ready-made processor (it needs `livekit-client`, which a LiveKit app already has):
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
import { KaleidoscopeProcessor, setMaskTuning } from 'react-native-webrtc-kaleidoscope/livekit';
|
|
205
|
+
|
|
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`
|
|
219
|
+
```
|
|
220
|
+
|
|
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.
|
|
222
|
+
|
|
223
|
+
## Concepts
|
|
224
|
+
|
|
225
|
+
The vocabulary, in the order you meet it.
|
|
226
|
+
|
|
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>• **shader**: what it draws (`image`, `direct` the camera, `blur`, or a generative shader like `plasma` or `clouds`).<br>• **target**: where it lands, `background` (fullscreen) or `subject` (stenciled to the person).<br>• **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. |
|
|
235
|
+
|
|
236
|
+
`direct` + `subject` is the masked person; `direct` + `background` is the raw camera frame.
|
|
237
|
+
|
|
238
|
+
## The four verbs
|
|
239
|
+
|
|
240
|
+
<p align="center">
|
|
241
|
+
<code>kaleidoscope</code> • <code>transform</code> • <code>mask</code> • <code>dispose</code>
|
|
242
|
+
</p>
|
|
243
|
+
|
|
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. |
|
|
252
|
+
|
|
253
|
+
```ts
|
|
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
|
|
183
262
|
|
|
184
|
-
// transform, absolute geometry. Every call is the full state from identity;
|
|
185
|
-
// re-pass what you want to keep. rotate snaps to the nearest 90°.
|
|
186
263
|
transform({ flip: { x: true }, rotate: 90 });
|
|
187
|
-
transform();
|
|
264
|
+
transform(); // reset to identity
|
|
188
265
|
|
|
189
|
-
// mask, the segmentation edge shared by every art effect. Both required, 0..1.
|
|
190
266
|
mask({ hardness: 0.5, threshold: 0.5 });
|
|
267
|
+
dispose(); // on unmount
|
|
191
268
|
```
|
|
192
269
|
|
|
193
|
-
|
|
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.
|
|
194
271
|
|
|
195
|
-
|
|
272
|
+
## Make your own presets
|
|
196
273
|
|
|
197
|
-
|
|
274
|
+
A preset is a composition: **every preset is a back-to-front stack of N layers**, and the compositor does not care what produces a layer's texture, which is exactly what makes it extensible. To author one, stack layers in the order you want them painted, lowest first, the masked person (`{ shader: 'direct', target: 'subject' }`) usually last so it sits on top.
|
|
198
275
|
|
|
199
|
-
|
|
276
|
+
```ts
|
|
277
|
+
// A generative shader behind the person, with an additive glow layer on top of it.
|
|
278
|
+
'aurora-night': {
|
|
279
|
+
name: 'Aurora night',
|
|
280
|
+
taxonomy: ['Shaders', 'Aurora'],
|
|
281
|
+
layers: [
|
|
282
|
+
{ id: 'sky', shader: 'clouds', target: 'background', uniforms: { coverage: 0.4 } },
|
|
283
|
+
{ id: 'glow', shader: 'godrays', target: 'background', blend: 'additive' },
|
|
284
|
+
{ id: 'you', shader: 'direct', target: 'subject' },
|
|
285
|
+
],
|
|
286
|
+
},
|
|
287
|
+
```
|
|
200
288
|
|
|
201
|
-
|
|
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.
|
|
202
290
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
import
|
|
206
|
-
import { presets } from './kaleidoscope.preset-book';
|
|
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).
|
|
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).
|
|
293
|
+
- **Packaged composites** (the Worlds) live in `catalog/composites/<name>/` behind a `./composites/<name>` subpath export; import and spread one into your book.
|
|
207
294
|
|
|
208
|
-
|
|
209
|
-
function BackgroundControls({ kaleidoscope }) {
|
|
210
|
-
const [art, setArt] = useState<keyof typeof presets | null>(null);
|
|
211
|
-
useEffect(() => {
|
|
212
|
-
if (art) kaleidoscope(art);
|
|
213
|
-
else kaleidoscope(null);
|
|
214
|
-
}, [art, kaleidoscope]);
|
|
295
|
+
After adding a preset to the demo book, regenerate its thumbnail and this README's gallery: `bun run thumbs && bun run gen:waffle` (see [Authoring tooling](#authoring-tooling)).
|
|
215
296
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
297
|
+
## Drop-in UI
|
|
298
|
+
|
|
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.
|
|
219
300
|
|
|
220
|
-
|
|
301
|
+
### The picker
|
|
302
|
+
|
|
303
|
+
`PresetBookMenu` (from `react-native-webrtc-kaleidoscope/preset-book-menu`) is a two-level browser driven by each preset's `taxonomy`: a tab row across the top, one tab per **group** (`taxonomy[0]`), and a left-hand menu of **categories** (`taxonomy[1]`) under the active group; the tile grid filters by both. A flat (depth-1) group shows no category menu. Every preset renders as a uniform tile: a wallpaper when it has a `thumbnail`, a recessed button of the same footprint when it does not, so a thumbnail-less preset never breaks the grid. The same pieces ship as standalone primitives (`PresetGrid`, `PresetTile`, the `usePresetBookMenu` hook, `PresetBookMenuLayout`) for custom layouts.
|
|
221
304
|
|
|
222
305
|
**Styling, three tiers.** Sensible defaults out of the box; override with an RN `style` prop, a `className` prop, or a `renderTile` render-prop slot for full control.
|
|
223
306
|
|
|
224
|
-
**NativeWind-ready.** The components accept `className`.
|
|
307
|
+
**NativeWind-ready.** The components accept `className`. Turn it on by importing the opt-in registration once (`nativewind` is an optional peer; the core `./preset-book-menu` import never pulls it in):
|
|
225
308
|
|
|
226
309
|
```ts
|
|
227
310
|
import { registerKaleidoscopeNativeWind } from 'react-native-webrtc-kaleidoscope/nativewind';
|
|
@@ -240,7 +323,6 @@ import {
|
|
|
240
323
|
TransformControlPanel,
|
|
241
324
|
} from 'react-native-webrtc-kaleidoscope/preset-control-panel';
|
|
242
325
|
|
|
243
|
-
// `controls` is the object from bindKaleidoscope(track, { presets }).
|
|
244
326
|
<KaleidoscopeThemeProvider>
|
|
245
327
|
<PresetControlPanel presets={presets} value={art} onPatch={(p) => controls.kaleidoscope(art, [p])} />
|
|
246
328
|
<MaskControlPanel hardness={h} threshold={t} onChange={setMask} />
|
|
@@ -248,28 +330,19 @@ import {
|
|
|
248
330
|
</KaleidoscopeThemeProvider>
|
|
249
331
|
```
|
|
250
332
|
|
|
251
|
-
Each preset supplies its editor as a `controls` component on the book entry
|
|
252
|
-
|
|
253
|
-
Like the picker, the editor is controlled and presentational: it emits patches and you apply them. `KaleidoscopeThemeProvider` themes every control at once (a slot bank; `style` works everywhere, `className` via the same opt-in NativeWind interop). The sliders need `@react-native-community/slider` (an optional peer; a native module, so installing it needs a dev-client rebuild).
|
|
333
|
+
Each preset supplies its editor as a `controls` component on the book entry; packaged composites export theirs at `react-native-webrtc-kaleidoscope/composites/<name>/controls`. For your own presets, compose `CompositeLayerControlPanel` over a shader's control descriptor (or `makeControls` for a custom widget). `KaleidoscopeThemeProvider` themes every control at once. The sliders need `@react-native-community/slider` (an optional peer; a native module, so it needs a dev-client rebuild). Live per-layer tuning runs on web today; on native the editor renders while the live per-layer uniform channel is in progress. Mask and transform are live on every platform.
|
|
254
334
|
|
|
255
|
-
|
|
335
|
+
### Persistence
|
|
256
336
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
`react-native-webrtc-kaleidoscope/persistence` ships a provider + hook that keep the person's selection across launches: the last applied preset id, the per-layer uniform patches they dialed in through the control panels (kept per preset, so tweaks to several presets all survive), and the mask edge.
|
|
337
|
+
`react-native-webrtc-kaleidoscope/persistence` ships a provider + hook that keep the person's selection across launches: the last applied preset id, the per-layer uniform patches they dialed in (kept per preset), and the mask edge.
|
|
260
338
|
|
|
261
339
|
```tsx
|
|
262
340
|
// App root:
|
|
263
341
|
import { KaleidoscopeStateProvider } from 'react-native-webrtc-kaleidoscope/persistence';
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
<KaleidoscopeStateProvider presets={presets}>
|
|
267
|
-
<App />
|
|
268
|
-
</KaleidoscopeStateProvider>;
|
|
342
|
+
<KaleidoscopeStateProvider presets={presets}><App /></KaleidoscopeStateProvider>;
|
|
269
343
|
|
|
270
344
|
// In the screen that binds the track:
|
|
271
345
|
import { useKaleidoscopeState } from 'react-native-webrtc-kaleidoscope/persistence';
|
|
272
|
-
|
|
273
346
|
const { hydrated, presetId, mask, setPreset, setMask, setPatch, patchesFor, reset } =
|
|
274
347
|
useKaleidoscopeState<typeof presets>();
|
|
275
348
|
|
|
@@ -280,89 +353,87 @@ useEffect(() => {
|
|
|
280
353
|
}, [hydrated, controls, presetId]);
|
|
281
354
|
```
|
|
282
355
|
|
|
283
|
-
Route the picker's `onSelect` into `setPreset`, the editor's `onPatch` into `setPatch(presetId, patch)
|
|
356
|
+
Route the picker's `onSelect` into `setPreset`, the editor's `onPatch` into `setPatch(presetId, patch)`, and the mask panel into `setMask`; every write persists. The default store is [`@react-native-async-storage/async-storage`](https://github.com/react-native-async-storage/async-storage) (an optional peer; localStorage-backed on web). Back it with anything else (MMKV, a server) by passing a `{ load, save }` pair as the `store` prop; the stored shape is versioned and parses tolerantly, so a malformed payload reads as empty rather than throwing.
|
|
284
357
|
|
|
285
|
-
|
|
358
|
+
## Performance
|
|
286
359
|
|
|
287
|
-
|
|
360
|
+
The product is the masked-background composite, and its cost is something you can see, not guess.
|
|
288
361
|
|
|
289
|
-
|
|
362
|
+
- **Annotated shader cost.** Each generative shader's `.ts` carries a measured GPU cost annotation (relative to `plasma` as the cheap baseline), so you know what a preset spends before you ship it.
|
|
363
|
+
- **One resolution knob.** Raw shader compute scales with output resolution, handled by the resolution tier (`targetShortSide`), not by per-effect orientation tricks. Drop the tier on weak GPUs; the mask and composite logic are unchanged.
|
|
364
|
+
- **Bounded work per frame.** Compositing is per-layer through a single mask stencil; a new shader inherits the pipeline's frame budget rather than adding a pass of its own.
|
|
290
365
|
|
|
291
|
-
|
|
292
|
-
|---|---|---|
|
|
293
|
-
| <img src="composites/wizard-tower/wizard-tower.thumb.webp" width="220" alt="wizard-tower" /> | <img src="composites/observation-deck/observation-deck.thumb.webp" width="220" alt="observation-deck" /> | <img src="composites/fairy-cave/fairy-cave.thumb.webp" width="220" alt="fairy-cave" /> |
|
|
294
|
-
| Underwater | Nebula | Simianlights |
|
|
295
|
-
| <img src="composites/underwater/underwater.thumb.webp" width="220" alt="underwater" /> | <img src="composites/nebula/nebula.thumb.webp" width="220" alt="nebula" /> | <img src="composites/simianlights/simianlights.thumb.webp" width="220" alt="simianlights" /> |
|
|
296
|
-
| Corporate Blobs | | |
|
|
297
|
-
| <img src="composites/corporate-blobs/corporate-blobs.thumb.webp" width="220" alt="corporate-blobs" /> | | |
|
|
366
|
+
## Authoring tooling
|
|
298
367
|
|
|
299
|
-
The
|
|
368
|
+
The kit ships the same tools used to build it. All regenerate from the command line.
|
|
300
369
|
|
|
301
|
-
|
|
370
|
+
| Command | What it does |
|
|
371
|
+
|---|---|
|
|
372
|
+
| `bun run bench:shader` | SPIR-V weighted op-cost bench for a shader (good for no-loop shaders; rank by the meter for loop-bound ones). |
|
|
373
|
+
| `bun run shader:view` | WebGL2 A/B viewer with a live GPU-time meter for tuning a shader against the camera. |
|
|
374
|
+
| `bun run thumbs` | Render a `320×180` WebP thumbnail per preset in a book (the gallery tiles and picker wallpapers). |
|
|
375
|
+
| `bun run gen:waffle` | Regenerate this README's [preset gallery](#presets) from the demo book + thumbnails. Run after adding a preset; `--check` gates staleness. |
|
|
302
376
|
|
|
303
|
-
|
|
377
|
+
## Only ship what you use
|
|
304
378
|
|
|
305
|
-
|
|
306
|
-
|---|---|---|
|
|
307
|
-
| Office | <img src="images/office/office-light.thumb.webp" width="220" alt="office-light" /> | <img src="images/office/office-dark.thumb.webp" width="220" alt="office-dark" /> |
|
|
308
|
-
| Home | <img src="images/home/home-light.thumb.webp" width="220" alt="home-light" /> | <img src="images/home/home-dark.thumb.webp" width="220" alt="home-dark" /> |
|
|
309
|
-
| Nature | <img src="images/nature/landscape-light.thumb.webp" width="220" alt="landscape-light" /> | <img src="images/nature/landscape-dark.thumb.webp" width="220" alt="landscape-dark" /> |
|
|
310
|
-
| Sci-Fi | <img src="images/sci-fi/sci-fi-light.thumb.webp" width="220" alt="sci-fi-light" /> | |
|
|
311
|
-
| Underwater | | <img src="images/underwater/oceanscape-dark.thumb.webp" width="220" alt="oceanscape-dark" /> |
|
|
312
|
-
| Simiancraft | <img src="images/simiancraft/simiancraft-light.thumb.webp" width="220" alt="simiancraft-light" /> | <img src="images/simiancraft/simiancraft-dark.thumb.webp" width="220" alt="simiancraft-dark" /> |
|
|
379
|
+
Install size and bundle size are different numbers, and you pay for the second.
|
|
313
380
|
|
|
314
|
-
|
|
381
|
+
- **Per-asset subpath exports.** Each bundled image and packaged composite is its own file behind its own subpath (`./images/<category>/<leaf>`, `./composites/<name>`), and the package sets `sideEffects: false`. A web bundler drops every preset you do not import.
|
|
382
|
+
- **Native ships only what your book references.** Metro does not tree-shake, so an unused preset is simply never imported; and `expo prebuild` copies only the assets your preset book actually names into the native bundle. Declare ten rooms, reference two, ship two.
|
|
383
|
+
- **Assets are WebP.** Backgrounds are 720p WebP; each platform decodes it natively (BitmapFactory on Android, ImageIO / MTKTextureLoader on iOS), so a full image set is a couple of megabytes, not sixteen.
|
|
315
384
|
|
|
316
|
-
|
|
385
|
+
## For LLMs and agents
|
|
317
386
|
|
|
318
|
-
|
|
387
|
+
Feeding this repo into Claude / Cursor / Copilot, or shipping it into an app with an agent? Read [`llms.txt`](./llms.txt) first: the same scope as this README in a denser, parseable shape, with a copy-paste starting fileset that runs on all three platforms. It is the file to hand an agent for a hands-off integration (see [Quick start → With an agent](#with-an-agent)).
|
|
319
388
|
|
|
320
|
-
##
|
|
321
|
-
|
|
322
|
-
The API surface is the same across platforms, but the runtimes differ in ways worth knowing before you wire effects in:
|
|
389
|
+
## Architecture
|
|
323
390
|
|
|
324
|
-
|
|
325
|
-
- **Image source.** An `image` layer's `source` is a bundled preset name on native (the upstream `_setVideoEffects` registry is keyed by flat strings, not URIs), but on web it accepts either a preset name or an arbitrary image URL or data URI.
|
|
326
|
-
- **Background presets ship as tree-shakeable files.** The bundled backgrounds (see [Background presets](#background-presets)) are importable per image: `import { officeDark } from 'react-native-webrtc-kaleidoscope/images/office/office-dark'`. Each image is its own file behind its own subpath export, and the package sets `sideEffects: false`, so an unused preset is dropped by web bundlers; since Metro doesn't tree-shake, it is simply never imported on native. Web resolves the bundled WebP to a URL; native loads its own bundled copy by name. Web also still accepts an arbitrary image URL or data URI. See [`catalog/images/README.md`](./catalog/images/README.md).
|
|
327
|
-
- **Segmentation model on web.** The web compositor loads MediaPipe Selfie Segmentation from the jsdelivr CDN (`cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation`) on first use. A strict Content-Security-Policy must allow that origin for `script-src`, `connect-src`, and the WASM fetch, and the effects do not work offline. The `transform` ops need no model.
|
|
328
|
-
- **Browser support on web.** Effects use Insertable Streams (`MediaStreamTrackProcessor` and `MediaStreamTrackGenerator`), which ship in Chromium-based browsers (Chrome, Edge); Safari and Firefox lack the API, so the effects throw a clear capability error and the demo falls back to the unprocessed track.
|
|
329
|
-
- **Android revokes the camera ~60 s into the background.** Android 11+ disables camera access for backgrounded apps by device policy (`ERROR_CAMERA_DISABLED`); `react-native-webrtc` logs the event but never restarts capture, so after a long background the preview stays black on resume and no effect or preset change can recover it (the frame source is dead, not the pipeline). Re-acquire `getUserMedia` when the app returns from the background; the demo's [`use-loopback-stream.ts`](./demo/src/use-loopback-stream.ts) shows the `AppState` pattern, and effects re-bind to the new track through the normal verbs.
|
|
391
|
+
Every effect is a **layer in one compositor**: a bundled `image`, a `direct` passthrough (the masked person or the raw camera), a camera-sampling `blur`, or a generative shader, composited back to front with per-layer blend. There is one registered native effect, `composite`; its layer stack is delivered out of band and reconciled each command. Adding a background source is adding a layer kind, not a new effect, which is why [a new shader](#make-your-own-presets) reaches all three platforms from one folder.
|
|
330
392
|
|
|
331
|
-
|
|
393
|
+
Canonical assets live in three root, folder-per-item directories, out of the TypeScript build path:
|
|
332
394
|
|
|
333
|
-
-
|
|
334
|
-
-
|
|
335
|
-
-
|
|
336
|
-
- **Not a streaming protocol replacement.** The transformed track plugs into the consumer's existing `RTCPeerConnection` pipeline.
|
|
395
|
+
- `catalog/shaders/<name>/`: each shader's `.frag` plus its typed `.ts` (uniforms + control descriptor). All share one vertex stage; `bun run build:shaders` codegens the web and Android sources and transpiles the iOS Metal.
|
|
396
|
+
- `catalog/images/<category>/`: images filed by category; each is a `<leaf>.webp`, its `<leaf>.thumb.webp`, and the `<leaf>.ts` / `<leaf>.web.ts` loader pair, behind a subpath export.
|
|
397
|
+
- `catalog/composites/<name>/`: each packaged composite, behind a `./composites/<name>` subpath export.
|
|
337
398
|
|
|
338
|
-
|
|
399
|
+
The code spans the platform surfaces: `src/` (JS facade + shared types), `web-driver/` (WebGL2 pipeline), `android/` (OpenGL ES 3.0), and `ios/` (Metal). Orientation is normalized exactly once at the ingest, so effects do zero orientation work. The full contract, including the texture-orientation convention and the mask buffer-ownership rule, is in [`PATTERNS.md`](./PATTERNS.md).
|
|
339
400
|
|
|
340
|
-
|
|
401
|
+
## Platform support
|
|
341
402
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
403
|
+
| Platform | Transform | Blur | Background replacement | Notes |
|
|
404
|
+
|---|---|---|---|---|
|
|
405
|
+
| Web (Chrome / Edge) | ✓ | ✓ | ✓ | MediaStreamTrackProcessor + MediaPipe Selfie Segmentation (WASM, CDN) |
|
|
406
|
+
| Android (API 24+) | ✓ | ✓ | ✓ | OpenGL ES 3.0 + MediaPipe Selfie Segmentation (Tasks) |
|
|
407
|
+
| iOS (≥ 15) | ✓ | ✓ | ✓ | Metal + MediaPipe Selfie Segmentation (Tasks), verified on device. Older A11 devices (iPhone X) run at a lower frame rate |
|
|
408
|
+
| Safari / Firefox | n/a | n/a | n/a | No Insertable Streams; the effects throw a clear capability error and the demo falls back to the unprocessed track |
|
|
345
409
|
|
|
346
|
-
|
|
410
|
+
A few runtime differences worth knowing before you wire effects in:
|
|
347
411
|
|
|
348
|
-
-
|
|
349
|
-
-
|
|
350
|
-
-
|
|
351
|
-
- `ios/`: Metal pipeline (Swift) with MediaPipe Tasks segmentation (`selfie_segmenter.tflite`, the same model Android bundles); the canonical GLSL transpiles to Metal via `scripts/build-shaders.ts`.
|
|
412
|
+
- **Output track.** On web each `kaleidoscope` / `transform` command rebuilds the Insertable-Streams pipeline and yields a NEW `MediaStreamTrack` via `onTrack`; on native the bound track is mutated in place. `mask` updates the running composite with no rebuild on either platform.
|
|
413
|
+
- **Segmentation model on web.** The web compositor loads MediaPipe Selfie Segmentation from the jsDelivr CDN on first use. A strict Content-Security-Policy must allow that origin for `script-src`, `connect-src`, and the WASM fetch, and the effects do not work offline. `transform` needs no model.
|
|
414
|
+
- **Android revokes the camera ~60 s into the background.** Android 11+ disables camera access for backgrounded apps by device policy; `react-native-webrtc` logs it but never restarts capture, so after a long background the preview stays black on resume. Re-acquire `getUserMedia` when the app returns from the background; the demo's [`use-loopback-stream.ts`](./demo/src/use-loopback-stream.ts) shows the `AppState` pattern, and effects re-bind to the new track through the normal verbs.
|
|
352
415
|
|
|
353
|
-
|
|
416
|
+
## What this isn't
|
|
354
417
|
|
|
355
|
-
|
|
418
|
+
- **Not a fork of `react-native-webrtc`.** A thin layer over its undocumented `_setVideoEffects` registry on native, and `MediaStreamTrackProcessor` on web. Install alongside it.
|
|
419
|
+
- **Not a managed cloud SaaS.** Effects run locally on the device; the track stays peer-to-peer. No service, no API key, no per-minute billing.
|
|
420
|
+
- **Not a face-filter SDK.** Effects are background segmentation and frame transforms, not facial AR.
|
|
421
|
+
- **Not a streaming protocol replacement.** The transformed track plugs into your existing `RTCPeerConnection` pipeline.
|
|
356
422
|
|
|
357
423
|
## Reference
|
|
358
424
|
|
|
425
|
+
- [CHANGELOG.md](./CHANGELOG.md): release history (semantic-release, Conventional Commits).
|
|
359
426
|
- [CONTRIBUTING.md](./CONTRIBUTING.md): setup, scripts, commit conventions.
|
|
360
|
-
- [AGENTS.md](./AGENTS.md):
|
|
361
|
-
- [PATTERNS.md](./PATTERNS.md): codebase conventions and how
|
|
427
|
+
- [AGENTS.md](./AGENTS.md): contributor and agent orientation for working on the repo.
|
|
428
|
+
- [PATTERNS.md](./PATTERNS.md): codebase conventions, the orientation contract, and how to extend.
|
|
362
429
|
- [catalog/shaders/README.md](./catalog/shaders/README.md): adding and extending shaders.
|
|
430
|
+
- [catalog/images/README.md](./catalog/images/README.md): the image folder layout and formats.
|
|
431
|
+
- [llms.txt](./llms.txt): dense, agent-oriented integration guide.
|
|
363
432
|
- [SECURITY.md](./SECURITY.md): security policy and reporting.
|
|
364
433
|
- [NOTICE.md](./NOTICE.md): third-party attributions.
|
|
365
434
|
|
|
366
435
|
---
|
|
367
436
|
|
|
368
437
|
MIT licensed. © 2026 Jesse Harlin / [Simiancraft](https://github.com/simiancraft).
|
|
438
|
+
|
|
439
|
+
<p align="center"><sub>Crafted with care by <a href="https://simiancraft.com">Simiancraft</a>.</sub></p>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-webrtc-kaleidoscope",
|
|
3
|
-
"version": "2.7.
|
|
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",
|
|
@@ -587,6 +587,8 @@
|
|
|
587
587
|
"bench:shader": "bun run scripts/shader-cost.ts",
|
|
588
588
|
"shader:view": "bun run scripts/shader-view.ts",
|
|
589
589
|
"thumbs": "bun run build && bun tools/thumbnails/make-thumbnails.ts --book demo/kaleidoscope.preset-book.ts --out demo/assets/thumbnails --repo",
|
|
590
|
+
"gen:waffle": "bun run scripts/gen-preset-waffle.ts",
|
|
591
|
+
"check:waffle": "bun run scripts/gen-preset-waffle.ts --check",
|
|
590
592
|
"demo": "bun run build && cd demo && bun run start",
|
|
591
593
|
"demo:wsl": "bun run build && cd demo && bun run start:wsl",
|
|
592
594
|
"demo:ios": "bun run build && cd demo && bun run ios",
|