react-native-webrtc-kaleidoscope 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -4
- package/android/build.gradle +3 -1
- package/android/src/main/java/com/simiancraft/kaleidoscope/Registration.kt +2 -2
- package/android/src/main/java/com/simiancraft/kaleidoscope/gpu/GpuEffectProcessor.kt +1 -1
- package/android/src/main/java/com/simiancraft/kaleidoscope/gpu/Shaders.kt +13 -51
- package/android/src/main/java/com/simiancraft/kaleidoscope/gpu/ShadersGenerated.kt +64 -0
- package/app.plugin.js +254 -4
- package/dist/backgrounds/index.d.ts +3 -0
- package/dist/backgrounds/index.d.ts.map +1 -0
- package/dist/backgrounds/index.js +6 -0
- package/dist/backgrounds/index.js.map +1 -0
- package/dist/backgrounds/office-1.d.ts +3 -0
- package/dist/backgrounds/office-1.d.ts.map +1 -0
- package/dist/backgrounds/office-1.js +5 -0
- package/dist/backgrounds/office-1.js.map +1 -0
- package/dist/backgrounds/office-1.web.d.ts +3 -0
- package/dist/backgrounds/office-1.web.d.ts.map +1 -0
- package/dist/backgrounds/office-1.web.js +8 -0
- package/dist/backgrounds/office-1.web.js.map +1 -0
- package/dist/backgrounds/office-1.webp +0 -0
- package/dist/backgrounds/office-2.d.ts +3 -0
- package/dist/backgrounds/office-2.d.ts.map +1 -0
- package/dist/backgrounds/office-2.js +5 -0
- package/dist/backgrounds/office-2.js.map +1 -0
- package/dist/backgrounds/office-2.web.d.ts +3 -0
- package/dist/backgrounds/office-2.web.d.ts.map +1 -0
- package/dist/backgrounds/office-2.web.js +8 -0
- package/dist/backgrounds/office-2.web.js.map +1 -0
- package/dist/backgrounds/office-2.webp +0 -0
- package/dist/backgrounds/preset-source.types.d.ts +2 -0
- package/dist/backgrounds/preset-source.types.d.ts.map +1 -0
- package/dist/backgrounds/preset-source.types.js +2 -0
- package/dist/backgrounds/preset-source.types.js.map +1 -0
- package/dist/{backgrounds.d.ts → backgrounds/presets.d.ts} +1 -1
- package/dist/backgrounds/presets.d.ts.map +1 -0
- package/dist/{backgrounds.js → backgrounds/presets.js} +1 -1
- package/dist/backgrounds/presets.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -12
- package/dist/index.js.map +1 -1
- package/dist/index.web.d.ts +11 -1
- package/dist/index.web.d.ts.map +1 -1
- package/dist/index.web.js +30 -7
- package/dist/index.web.js.map +1 -1
- package/dist/livekit.d.ts +24 -0
- package/dist/livekit.d.ts.map +1 -0
- package/dist/livekit.js +57 -0
- package/dist/livekit.js.map +1 -0
- package/dist/web/effects/blur.d.ts.map +1 -1
- package/dist/web/effects/blur.js +34 -1
- package/dist/web/effects/blur.js.map +1 -1
- package/dist/web/effects/passthrough.d.ts.map +1 -1
- package/dist/web/effects/passthrough.js +2 -2
- package/dist/web/effects/passthrough.js.map +1 -1
- package/dist/web/insertable-streams.d.ts +11 -1
- package/dist/web/insertable-streams.d.ts.map +1 -1
- package/dist/web/insertable-streams.js +22 -4
- package/dist/web/insertable-streams.js.map +1 -1
- package/dist/web/shaders.d.ts +1 -3
- package/dist/web/shaders.d.ts.map +1 -1
- package/dist/web/shaders.generated.d.ts +4 -0
- package/dist/web/shaders.generated.d.ts.map +1 -0
- package/dist/web/shaders.generated.js +54 -0
- package/dist/web/shaders.generated.js.map +1 -0
- package/dist/web/shaders.js +29 -103
- package/dist/web/shaders.js.map +1 -1
- package/ios/Kaleidoscope.podspec +75 -12
- package/ios/KaleidoscopeModule/Registration.swift +35 -13
- package/ios/KaleidoscopeModule/effects/BackgroundImageProcessor.swift +226 -0
- package/ios/KaleidoscopeModule/effects/BlurProcessor.swift +172 -18
- package/ios/KaleidoscopeModule/effects/FrameBridge.swift +40 -0
- package/ios/KaleidoscopeModule/effects/MirrorProcessor.swift +129 -10
- package/ios/KaleidoscopeModule/gpu/MetalRenderer.swift +423 -0
- package/ios/KaleidoscopeModule/gpu/ShaderLibrary.swift +100 -0
- package/ios/KaleidoscopeModule/gpu/TextureBridge.swift +120 -0
- package/ios/KaleidoscopeModule/resources/backgrounds/office-1.png +0 -0
- package/ios/KaleidoscopeModule/resources/backgrounds/office-2.png +0 -0
- package/ios/KaleidoscopeModule/segmentation/MaskTuning.swift +23 -0
- package/ios/KaleidoscopeModule/segmentation/Segmenter.swift +120 -24
- package/ios/KaleidoscopeModule/shaders/SHADERS.txt +5 -0
- package/ios/KaleidoscopeModule/shaders/blur.metalsrc +72 -0
- package/ios/KaleidoscopeModule/shaders/composite.metalsrc +22 -0
- package/ios/KaleidoscopeModule/shaders/nebula.metalsrc +72 -0
- package/ios/KaleidoscopeModule/shaders/passthrough.metalsrc +20 -0
- package/ios/KaleidoscopeModule/shaders/simianlights.metalsrc +72 -0
- package/package.json +44 -9
- package/src/backgrounds/README.md +78 -0
- package/src/backgrounds/assets.d.ts +7 -0
- package/src/backgrounds/index.ts +7 -0
- package/src/backgrounds/office-1.ts +6 -0
- package/src/backgrounds/office-1.web.ts +9 -0
- package/src/backgrounds/office-1.webp +0 -0
- package/src/backgrounds/office-2.ts +6 -0
- package/src/backgrounds/office-2.web.ts +9 -0
- package/src/backgrounds/office-2.webp +0 -0
- package/src/backgrounds/preset-source.types.ts +5 -0
- package/src/index.ts +45 -17
- package/src/index.web.ts +40 -8
- package/src/livekit.ts +65 -0
- package/src/web/effects/blur.ts +36 -1
- package/src/web/effects/passthrough.ts +2 -2
- package/src/web/insertable-streams.ts +33 -5
- package/src/web/shaders.generated.ts +56 -0
- package/src/web/shaders.ts +29 -106
- package/dist/backgrounds.d.ts.map +0 -1
- package/dist/backgrounds.js.map +0 -1
- package/plugin/build/withKaleidoscope.d.ts +0 -3
- package/plugin/build/withKaleidoscope.js +0 -14
- package/plugin/build/withKaleidoscope.js.map +0 -1
- /package/src/{backgrounds.ts → backgrounds/presets.ts} +0 -0
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
## Status
|
|
16
16
|
|
|
17
|
-
**Active development; not yet production-ready.** Published to npm
|
|
17
|
+
**Active development; not yet production-ready.** Published to npm at `1.0.0` (semantic-release cut the first tag at 1.0.0; the number reflects release automation, not a maturity claim). The npm presentation, marketing, and release-quality polish will come in a later pass; right now the README's job is to tell the truth about what works.
|
|
18
18
|
|
|
19
19
|
### What works today
|
|
20
20
|
|
|
@@ -27,12 +27,11 @@
|
|
|
27
27
|
|---|---|---|---|---|
|
|
28
28
|
| Web (Chrome / Edge) | ✓ | ✓ | ✓ | MediaStreamTrackProcessor + MediaPipe Selfie Segmentation (WASM, CDN) |
|
|
29
29
|
| Android (API 24+) | ✓ | ✓ | ✓ | OpenGL ES 3.0 + MLKit Selfie Segmentation |
|
|
30
|
-
| iOS (≥ 15) |
|
|
30
|
+
| iOS (≥ 15) | ✓ | ✓ | ✓ | Metal + Vision (person segmentation), verified on device. Older A11 devices (iPhone X) run at a lower frame rate |
|
|
31
31
|
| Safari / Firefox | — | — | — | No Insertable Streams; `applyVideoEffects` throws a typed error |
|
|
32
32
|
|
|
33
33
|
### Coming soon
|
|
34
34
|
|
|
35
|
-
- **iOS support**, via the canonical GLSL transpiled to Metal Shading Language (`glslangValidator` → `spirv-cross --msl`). The pipeline is in the repo at `scripts/transpile-shaders.ts` and the GLSL canonical source lives in `shaders/`. The Swift host code that loads the metallib and runs the Metal pipeline is the next chunk of work.
|
|
36
35
|
- **Procedural backgrounds** (animated shaders behind the person, not just still images). Same composite path; the only new piece is each effect's background producer.
|
|
37
36
|
- A careful pass over the npm presentation, install docs, and demo polish before any "we recommend you use this" framing.
|
|
38
37
|
|
|
@@ -54,6 +53,24 @@ bun add @livekit/react-native @livekit/react-native-webrtc react-native-webrtc-k
|
|
|
54
53
|
|
|
55
54
|
Pick one fork. Installing both upstream `react-native-webrtc` and `@livekit/react-native-webrtc` in the same app will cause native class collisions; that's the consumer's problem to resolve.
|
|
56
55
|
|
|
56
|
+
**Native wiring.** `@livekit/react-native` hands you a `LocalVideoTrack`; apply effects to its underlying `MediaStreamTrack`:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { applyVideoEffects } from 'react-native-webrtc-kaleidoscope';
|
|
60
|
+
|
|
61
|
+
applyVideoEffects(localCameraTrack.mediaStreamTrack, ['blur']);
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Web wiring.** On web, LiveKit owns the `RTCRtpSender`, so you cannot swap the track yourself; go through LiveKit's processor API instead. The opt-in `/livekit` subpath ships a ready-made processor (it needs `livekit-client`, which a LiveKit app already has):
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import { KaleidoscopeProcessor } from 'react-native-webrtc-kaleidoscope/livekit';
|
|
68
|
+
|
|
69
|
+
await localVideoTrack.setProcessor(new KaleidoscopeProcessor(['blur']), true);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The second argument 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.
|
|
73
|
+
|
|
57
74
|
## Configure
|
|
58
75
|
|
|
59
76
|
Add the config plugin to `app.config.ts`:
|
|
@@ -110,6 +127,16 @@ Effects chain in array order.
|
|
|
110
127
|
|
|
111
128
|
The library ships neutral defaults (8, 0.5, 0.5) and consumers tune at runtime via the API above; whether to ship the dialed-in values as platform-specific defaults is an open question waiting on iOS data.
|
|
112
129
|
|
|
130
|
+
## Web and native differences
|
|
131
|
+
|
|
132
|
+
The API surface is the same across platforms, but the runtimes differ in ways worth knowing before you wire effects in:
|
|
133
|
+
|
|
134
|
+
- **Effect parameters.** Web reads tuning from the global setters (`setBlurSigma`, `setMaskHardness`, `setMaskThreshold`) on the next frame. Native currently ignores per-call `EffectSpec` parameters such as `{ name: 'blur', sigma: 12 }`; tuning is global through the same setters. Per-call uniforms through the native registry are a follow-up.
|
|
135
|
+
- **Background source.** `background-image.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.
|
|
136
|
+
- **Background presets ship as tree-shakeable files.** Two example backgrounds (`office-1`, `office-2`) are importable per preset: `import { office1 } from 'react-native-webrtc-kaleidoscope/backgrounds/office-1'`. Each preset is its own file behind its own subpath export, and the package sets `sideEffects: false`, so an unused preset is dropped by web bundlers — and, since Metro doesn't tree-shake, 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 [`src/backgrounds/README.md`](./src/backgrounds/README.md).
|
|
137
|
+
- **Segmentation model on web.** The web blur and background-image effects load 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. Mirror needs no model.
|
|
138
|
+
- **Browser support on web.** Effects use Insertable Streams (`MediaStreamTrackProcessor` and `MediaStreamTrackGenerator`), which ship in Chromium-based browsers; Safari and Firefox throw a typed capability error.
|
|
139
|
+
|
|
113
140
|
## What this isn't
|
|
114
141
|
|
|
115
142
|
- **Not a fork of `react-native-webrtc`.** A thin layer over its undocumented `_setVideoEffects` registry on native, and `MediaStreamTrackProcessor` on web. Install alongside `react-native-webrtc`.
|
|
@@ -124,7 +151,7 @@ The codebase lives across four surfaces:
|
|
|
124
151
|
- `src/` — JS facade and shared types. `applyVideoEffects(track, effects)` plus runtime tuning setters.
|
|
125
152
|
- `src/web/` — WebGL2 pipeline. MediaPipe segmentation + GLSL composite. One shader file per stage in `src/web/shaders.ts`.
|
|
126
153
|
- `android/` — OpenGL ES 3.0 pipeline. MLKit segmentation (async, worker-thread, last-known-mask cache) + GLSL composite. Shaders inline in `gpu/Shaders.kt` as `const val` strings.
|
|
127
|
-
- `ios/` —
|
|
154
|
+
- `ios/` — Metal pipeline (Swift) with Vision person segmentation. The canonical GLSL in `shaders/` transpiles to Metal Shading Language via `scripts/build-shaders.ts`. Implemented and verified on device.
|
|
128
155
|
|
|
129
156
|
The composite shader (`shaders/composite.frag`) is the same GLSL source for every effect category (blur, background-image, future procedural backgrounds). Per-effect difference is upstream of the composite: how the `uBackground` texture gets produced.
|
|
130
157
|
|
package/android/build.gradle
CHANGED
|
@@ -4,7 +4,9 @@ apply plugin: 'com.android.library'
|
|
|
4
4
|
apply plugin: 'kotlin-android'
|
|
5
5
|
|
|
6
6
|
group = 'com.simiancraft.kaleidoscope'
|
|
7
|
-
version
|
|
7
|
+
// Single source of truth for the version is package.json (the iOS podspec reads
|
|
8
|
+
// it the same way), so the three platforms cannot drift apart.
|
|
9
|
+
version = new groovy.json.JsonSlurper().parseText(file("../package.json").text).version
|
|
8
10
|
|
|
9
11
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
10
12
|
if (expoModulesCorePlugin.exists()) {
|
|
@@ -32,8 +32,8 @@ object Registration {
|
|
|
32
32
|
BackgroundImageFactory(context, "office-2"),
|
|
33
33
|
)
|
|
34
34
|
|
|
35
|
-
//
|
|
36
|
-
// pass before v0.1 ships.
|
|
35
|
+
// Temporary architecture-proof passthrough hook from the GPU bring-up.
|
|
36
|
+
// Removed in the cleanup pass before v0.1 ships.
|
|
37
37
|
ProcessorProvider.addProcessor("gpu-passthrough", GpuEffectFactory())
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// invokes process() per frame on the SurfaceTextureHelper's GL thread, so
|
|
3
3
|
// every GL call is implicitly on the correct context.
|
|
4
4
|
//
|
|
5
|
-
//
|
|
5
|
+
// Initial GPU bring-up: this version is a passthrough — sample the OES
|
|
6
6
|
// camera texture and emit it as a 2D-backed VideoFrame, no other math.
|
|
7
7
|
// Architecture proof for the OES -> shader -> TextureBufferImpl -> renderer
|
|
8
8
|
// round-trip. Effect-specific math (blur, composite, image background) lands
|
|
@@ -15,15 +15,10 @@ internal object Shaders {
|
|
|
15
15
|
// 1 -> (2,0) -> ( 1,-1), uv (1,0)
|
|
16
16
|
// 2 -> (0,2) -> (-1, 1), uv (0,1)
|
|
17
17
|
// 3 -> (2,2) -> ( 1, 1), uv (1,1)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
vec2 p = vec2(float((gl_VertexID & 1) << 1), float(gl_VertexID & 2));
|
|
23
|
-
vUv = p * 0.5;
|
|
24
|
-
gl_Position = vec4(p - 1.0, 0.0, 1.0);
|
|
25
|
-
}
|
|
26
|
-
"""
|
|
18
|
+
// Canonical source: shaders/passthrough.vert. Generated into
|
|
19
|
+
// ShadersGenerated by `bun run build:shaders`; delegated here so call sites
|
|
20
|
+
// keep using Shaders.PASSTHROUGH_VERT.
|
|
21
|
+
val PASSTHROUGH_VERT = ShadersGenerated.PASSTHROUGH_VERT
|
|
27
22
|
|
|
28
23
|
// Sample the OES external camera texture and emit as 2D RGBA. The first
|
|
29
24
|
// pass of every effect runs this so subsequent passes can use sampler2D.
|
|
@@ -56,24 +51,10 @@ void main() {
|
|
|
56
51
|
// uAxis is (1/width, 0) for the horizontal pass and (0, 1/height) for the
|
|
57
52
|
// vertical pass. uOffsets[0] is the center tap (zero); offsets are in
|
|
58
53
|
// pixel units, so the shader multiplies by uAxis to convert to UV space.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
uniform float uWeights[9];
|
|
64
|
-
uniform float uOffsets[9];
|
|
65
|
-
in highp vec2 vUv;
|
|
66
|
-
out vec4 oColor;
|
|
67
|
-
void main() {
|
|
68
|
-
vec4 color = texture(uTex, vUv) * uWeights[0];
|
|
69
|
-
for (int i = 1; i < 9; i++) {
|
|
70
|
-
vec2 off = uAxis * uOffsets[i];
|
|
71
|
-
color += texture(uTex, vUv + off) * uWeights[i];
|
|
72
|
-
color += texture(uTex, vUv - off) * uWeights[i];
|
|
73
|
-
}
|
|
74
|
-
oColor = color;
|
|
75
|
-
}
|
|
76
|
-
"""
|
|
54
|
+
// Canonical source: shaders/blur.frag. Generated into ShadersGenerated by
|
|
55
|
+
// `bun run build:shaders`; delegated here. BlurFactory computes the 9 weights
|
|
56
|
+
// and offsets from sigma on the CPU and uploads the arrays each program use.
|
|
57
|
+
val BLUR_FRAG = ShadersGenerated.BLUR_FRAG
|
|
77
58
|
|
|
78
59
|
// Composite: mix(background, original, mask). One shader, byte-identical
|
|
79
60
|
// to src/web/shaders.ts's COMPOSITE_FRAG_SRC.
|
|
@@ -102,28 +83,9 @@ void main() {
|
|
|
102
83
|
// blurred copy. For background-image, the caller computes them to perform
|
|
103
84
|
// a cover-fit center crop so an arbitrarily-shaped image fills the output
|
|
104
85
|
// without distortion.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
uniform vec2 uBgUvScale;
|
|
111
|
-
uniform vec2 uBgUvOffset;
|
|
112
|
-
uniform vec2 uMaskUvScale;
|
|
113
|
-
uniform vec2 uMaskUvOffset;
|
|
114
|
-
uniform float uMaskLo;
|
|
115
|
-
uniform float uMaskHi;
|
|
116
|
-
in highp vec2 vUv;
|
|
117
|
-
out vec4 oColor;
|
|
118
|
-
void main() {
|
|
119
|
-
vec2 maskUv = vUv * uMaskUvScale + uMaskUvOffset;
|
|
120
|
-
float raw = texture(uMask, maskUv).r;
|
|
121
|
-
float safeHi = max(uMaskHi, uMaskLo + 0.001);
|
|
122
|
-
float m = smoothstep(uMaskLo, safeHi, raw);
|
|
123
|
-
vec3 orig = texture(uOriginal, vUv).rgb;
|
|
124
|
-
vec2 bgUv = clamp(vUv * uBgUvScale + uBgUvOffset, 0.0, 1.0);
|
|
125
|
-
vec3 bg = texture(uBackground, bgUv).rgb;
|
|
126
|
-
oColor = vec4(mix(bg, orig, m), 1.0);
|
|
127
|
-
}
|
|
128
|
-
"""
|
|
86
|
+
// Canonical source: shaders/composite.frag. Generated into ShadersGenerated
|
|
87
|
+
// by `bun run build:shaders`; delegated here. The per-platform mask/bg
|
|
88
|
+
// orientation differences live in the uniforms the host sets (see above),
|
|
89
|
+
// not in the shader, so the same generated body serves every runtime.
|
|
90
|
+
val COMPOSITE_FRAG = ShadersGenerated.COMPOSITE_FRAG
|
|
129
91
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// @generated by scripts/build-shaders.ts from shaders/. DO NOT EDIT.
|
|
2
|
+
// Run `bun run build:shaders` to regenerate.
|
|
3
|
+
//
|
|
4
|
+
// Cross-runtime shared shaders. Platform-local shaders (OES external texture,
|
|
5
|
+
// 2D passthrough) stay hand-written in Shaders.kt, which delegates the consts
|
|
6
|
+
// below.
|
|
7
|
+
|
|
8
|
+
package com.simiancraft.kaleidoscope.gpu
|
|
9
|
+
|
|
10
|
+
internal object ShadersGenerated {
|
|
11
|
+
const val PASSTHROUGH_VERT = """#version 300 es
|
|
12
|
+
precision highp float;
|
|
13
|
+
out highp vec2 vUv;
|
|
14
|
+
void main() {
|
|
15
|
+
vec2 p = vec2(float((gl_VertexID & 1) << 1), float(gl_VertexID & 2));
|
|
16
|
+
vUv = p * 0.5;
|
|
17
|
+
gl_Position = vec4(p - 1.0, 0.0, 1.0);
|
|
18
|
+
}
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
const val COMPOSITE_FRAG = """#version 300 es
|
|
22
|
+
precision mediump float;
|
|
23
|
+
uniform sampler2D uOriginal;
|
|
24
|
+
uniform sampler2D uBackground;
|
|
25
|
+
uniform sampler2D uMask;
|
|
26
|
+
uniform vec2 uBgUvScale;
|
|
27
|
+
uniform vec2 uBgUvOffset;
|
|
28
|
+
uniform vec2 uMaskUvScale;
|
|
29
|
+
uniform vec2 uMaskUvOffset;
|
|
30
|
+
uniform float uMaskLo;
|
|
31
|
+
uniform float uMaskHi;
|
|
32
|
+
in highp vec2 vUv;
|
|
33
|
+
out vec4 oColor;
|
|
34
|
+
void main() {
|
|
35
|
+
vec2 maskUv = vUv * uMaskUvScale + uMaskUvOffset;
|
|
36
|
+
float raw = texture(uMask, maskUv).r;
|
|
37
|
+
float safeHi = max(uMaskHi, uMaskLo + 0.001);
|
|
38
|
+
float m = smoothstep(uMaskLo, safeHi, raw);
|
|
39
|
+
vec3 orig = texture(uOriginal, vUv).rgb;
|
|
40
|
+
vec2 bgUv = clamp(vUv * uBgUvScale + uBgUvOffset, 0.0, 1.0);
|
|
41
|
+
vec3 bg = texture(uBackground, bgUv).rgb;
|
|
42
|
+
oColor = vec4(mix(bg, orig, m), 1.0);
|
|
43
|
+
}
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
const val BLUR_FRAG = """#version 300 es
|
|
47
|
+
precision mediump float;
|
|
48
|
+
uniform sampler2D uTex;
|
|
49
|
+
uniform vec2 uAxis;
|
|
50
|
+
uniform float uWeights[9];
|
|
51
|
+
uniform float uOffsets[9];
|
|
52
|
+
in highp vec2 vUv;
|
|
53
|
+
out vec4 oColor;
|
|
54
|
+
void main() {
|
|
55
|
+
vec4 color = texture(uTex, vUv) * uWeights[0];
|
|
56
|
+
for (int i = 1; i < 9; i++) {
|
|
57
|
+
vec2 off = uAxis * uOffsets[i];
|
|
58
|
+
color += texture(uTex, vUv + off) * uWeights[i];
|
|
59
|
+
color += texture(uTex, vUv - off) * uWeights[i];
|
|
60
|
+
}
|
|
61
|
+
oColor = color;
|
|
62
|
+
}
|
|
63
|
+
"""
|
|
64
|
+
}
|
package/app.plugin.js
CHANGED
|
@@ -1,5 +1,255 @@
|
|
|
1
|
-
// Expo config plugin
|
|
2
|
-
//
|
|
3
|
-
|
|
1
|
+
// Expo config plugin. Native registration happens via the Expo Module's
|
|
2
|
+
// OnCreate hook (see android/.../KaleidoscopeModule.kt and
|
|
3
|
+
// ios/.../KaleidoscopeModule.swift), not through a plugin-time mod.
|
|
4
|
+
//
|
|
5
|
+
// This plugin's job is narrowly scoped: patch the consumer's iOS build to
|
|
6
|
+
// satisfy this library's hard requirements that cannot be expressed in the
|
|
7
|
+
// Expo Module manifest or the podspec alone. Today that means two patches,
|
|
8
|
+
// both installed by a single iOS `dangerous` mod:
|
|
9
|
+
//
|
|
10
|
+
// 1. Declare `pod 'react-native-webrtc', :modular_headers => true` in the
|
|
11
|
+
// generated Podfile so Swift sources can `import react_native_webrtc`
|
|
12
|
+
// (see modular-headers detail below).
|
|
13
|
+
// 2. Raise `ios.deploymentTarget` in `Podfile.properties.json` to the value
|
|
14
|
+
// required by `ios/Kaleidoscope.podspec`. The default Expo Podfile
|
|
15
|
+
// platform (iOS 13.4) is lower than this library's minimum (iOS 15.0
|
|
16
|
+
// for Apple Vision person segmentation), and `expo-modules-autolinking`
|
|
17
|
+
// silently drops pods whose declared minimum exceeds the Podfile
|
|
18
|
+
// platform — the library would build, install, and then be absent from
|
|
19
|
+
// the generated `ExpoModulesProvider.swift` at runtime.
|
|
20
|
+
//
|
|
21
|
+
// Bounding invariant for future patches in this mod:
|
|
22
|
+
// Every patch this mod installs must be (a) idempotent across re-prebuilds,
|
|
23
|
+
// (b) non-downgrading (never reduce a value the consumer or another plugin
|
|
24
|
+
// set higher), and (c) recoverable via a logged manual instruction on I/O
|
|
25
|
+
// failure (no throwing — prebuild must keep going).
|
|
26
|
+
//
|
|
27
|
+
// Ordering note: this mod must run AFTER any consumer plugin that writes the
|
|
28
|
+
// same files (notably `expo-build-properties`). Expo executes plugins in
|
|
29
|
+
// declaration order from `plugins[]`, so consumers must list this plugin
|
|
30
|
+
// AFTER `expo-build-properties` in their `app.config.js`. The demo's
|
|
31
|
+
// `app.config.js` already does so.
|
|
32
|
+
//
|
|
33
|
+
// Modular-headers detail: our Swift sources do `import react_native_webrtc`
|
|
34
|
+
// to reach the Obj-C `ProcessorProvider` class and `VideoFrameProcessorDelegate`
|
|
35
|
+
// protocol that live inside the react-native-webrtc pod. For a Swift target to
|
|
36
|
+
// `import` an Objective-C CocoaPod as a Clang module, that pod must be built with
|
|
37
|
+
// modular headers. react-native-webrtc is NOT built with modular headers by
|
|
38
|
+
// default in a React Native / Expo app, so a default prebuild produces Swift
|
|
39
|
+
// that fails to compile with "no such module 'react_native_webrtc'".
|
|
40
|
+
//
|
|
41
|
+
// We deliberately do NOT emit a global `use_modular_headers!`: that flips every
|
|
42
|
+
// pod to build as a Clang module, which regularly breaks React Native core
|
|
43
|
+
// pods that ship non-modular umbrella headers. A single per-pod opt-in is the
|
|
44
|
+
// narrow, supported fix that react-native-webrtc's own docs recommend.
|
|
45
|
+
//
|
|
46
|
+
// WHY this file requires nothing but Node builtins (no @expo/config-plugins):
|
|
47
|
+
// Expo's plugin resolver hardcodes the entry filename to `app.plugin.js` and
|
|
48
|
+
// loads it with `require()` from the file's REAL path. In the demo we consume
|
|
49
|
+
// this library via `file:..`, so on EAS the realpath is the repo root, where
|
|
50
|
+
// there is no node_modules (EAS only installs the demo subdirectory). A
|
|
51
|
+
// top-level `require('@expo/config-plugins')` therefore throws
|
|
52
|
+
// "Cannot find module '@expo/config-plugins'" on the EAS worker. Registering
|
|
53
|
+
// the dangerous mod by mutating `config.mods.ios.dangerous` directly removes
|
|
54
|
+
// that dependency, so the plugin loads identically from the symlinked demo, a
|
|
55
|
+
// normally-installed external consumer, and the EAS worker. The mod contract is
|
|
56
|
+
// the one @expo/config-plugins' own dangerous base provider calls: it invokes
|
|
57
|
+
// our mod as `nextMod({ ...config, modResults, modRequest })` and only requires
|
|
58
|
+
// the returned value to be the config object (it asserts `.mods` exists).
|
|
59
|
+
//
|
|
60
|
+
// This file is CommonJS, and the package is deliberately `type: commonjs`:
|
|
61
|
+
// Expo's plugin resolver loads app.plugin.js with `require()`, and a CommonJS
|
|
62
|
+
// entry sidesteps ESM-interop variance across the Node versions EAS workers run
|
|
63
|
+
// (older SDK images run Node 18, which cannot `require()` an ESM module at all;
|
|
64
|
+
// newer images run Node 20/22). The ESM-authored library source lives in `src/`
|
|
65
|
+
// and is consumed by Metro via the `react-native` export condition, never
|
|
66
|
+
// loaded by Node.
|
|
4
67
|
|
|
5
|
-
|
|
68
|
+
const fs = require('node:fs');
|
|
69
|
+
const path = require('node:path');
|
|
70
|
+
|
|
71
|
+
// A sentinel comment lets us find our own injection on re-prebuilds and stay
|
|
72
|
+
// idempotent regardless of how Expo regenerates the surrounding Podfile.
|
|
73
|
+
const SENTINEL = '# react-native-webrtc-kaleidoscope: modular headers (managed)';
|
|
74
|
+
|
|
75
|
+
// Mirrors ios/Kaleidoscope.podspec :ios => '15.0'. Bumping the podspec
|
|
76
|
+
// requires bumping this constant; the drift cost is a silent pod-install
|
|
77
|
+
// drop (the bug this plan fixes).
|
|
78
|
+
const IOS_DEPLOYMENT_TARGET = '15.0';
|
|
79
|
+
|
|
80
|
+
// Compare two dotted version strings element-wise. Returns true iff `existing`
|
|
81
|
+
// is strictly less than `target`. Missing/empty existing counts as "less than".
|
|
82
|
+
// We avoid `semver` so this file stays dependency-free for EAS workers that
|
|
83
|
+
// don't install the library's node_modules. The library's iOS deployment
|
|
84
|
+
// target is a plain three-part version like '15.0' (or '15.0.1' if Apple ever
|
|
85
|
+
// requires it); pre-release/build metadata is not part of the contract.
|
|
86
|
+
function isVersionLessThan(existing, target) {
|
|
87
|
+
if (typeof existing !== 'string' || existing.length === 0) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
const toParts = (s) => s.split('.').map((part) => Number(part) || 0);
|
|
91
|
+
const a = toParts(existing);
|
|
92
|
+
const b = toParts(target);
|
|
93
|
+
const max = Math.max(a.length, b.length);
|
|
94
|
+
for (let i = 0; i < max; i += 1) {
|
|
95
|
+
const av = a[i] || 0;
|
|
96
|
+
const bv = b[i] || 0;
|
|
97
|
+
if (av < bv) return true;
|
|
98
|
+
if (av > bv) return false;
|
|
99
|
+
}
|
|
100
|
+
return false; // equal
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Resolve which react-native-webrtc fork the consumer installed, and return its
|
|
104
|
+
// CocoaPods pod name + npm package directory (used to build the `:path` for
|
|
105
|
+
// the Podfile declaration). Two forks ship the same JS/native surface under
|
|
106
|
+
// different names (mirrors the dual probe in android/build.gradle):
|
|
107
|
+
// - @livekit/react-native-webrtc -> pod `livekit-react-native-webrtc`
|
|
108
|
+
// - react-native-webrtc -> pod `react-native-webrtc`
|
|
109
|
+
// We prefer the fork when both are present, matching the Swift import order
|
|
110
|
+
// (`#if canImport(livekit_react_native_webrtc)` first). Declaring a pod for a
|
|
111
|
+
// package that is not installed would break `pod install`, so we return null
|
|
112
|
+
// (and skip patching) when neither is found.
|
|
113
|
+
function resolveWebrtcPod(projectRoot) {
|
|
114
|
+
if (!projectRoot) {
|
|
115
|
+
return { podName: 'react-native-webrtc', packageDir: 'react-native-webrtc' };
|
|
116
|
+
}
|
|
117
|
+
const fork = path.join(projectRoot, 'node_modules', '@livekit', 'react-native-webrtc');
|
|
118
|
+
const upstream = path.join(projectRoot, 'node_modules', 'react-native-webrtc');
|
|
119
|
+
if (fs.existsSync(fork)) {
|
|
120
|
+
return { podName: 'livekit-react-native-webrtc', packageDir: '@livekit/react-native-webrtc' };
|
|
121
|
+
}
|
|
122
|
+
if (fs.existsSync(upstream)) {
|
|
123
|
+
return { podName: 'react-native-webrtc', packageDir: 'react-native-webrtc' };
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Ensure the Podfile builds the resolved react-native-webrtc pod with modular
|
|
129
|
+
// headers so our Swift can `import` it as a Clang module. Declare with an
|
|
130
|
+
// explicit `:path` (instead of a bare `pod 'name'`) so the build works even
|
|
131
|
+
// when RN autolinking does not register the pod for us — e.g. react-native-webrtc's
|
|
132
|
+
// own `react-native.config.js` only sets `module.exports` under
|
|
133
|
+
// `--use-react-native-macos`, and on EAS workers `use_native_modules!` has been
|
|
134
|
+
// observed to skip the pod entirely as a result. With `:path` provided here,
|
|
135
|
+
// CocoaPods resolves the local podspec directly; when autolinking also picks
|
|
136
|
+
// it up, the two identical-path declarations are merged and modular_headers
|
|
137
|
+
// is applied. Idempotent: running prebuild twice neither duplicates the line
|
|
138
|
+
// nor corrupts the Podfile.
|
|
139
|
+
function patchPodfile(contents, pod) {
|
|
140
|
+
if (contents.includes(SENTINEL)) {
|
|
141
|
+
return contents;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const block = `${SENTINEL}\n pod '${pod.podName}', :path => '../node_modules/${pod.packageDir}', :modular_headers => true`;
|
|
145
|
+
const lines = contents.split('\n');
|
|
146
|
+
|
|
147
|
+
// Insert just inside the first `target ... do` block so the per-pod
|
|
148
|
+
// declaration sits in the same scope as the autolinked React Native pods.
|
|
149
|
+
const targetIndex = lines.findIndex((line) => /^\s*target\s+['"].*['"]\s+do\b/.test(line));
|
|
150
|
+
if (targetIndex !== -1) {
|
|
151
|
+
lines.splice(targetIndex + 1, 0, block);
|
|
152
|
+
return lines.join('\n');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// No `target` block found (unexpected for an Expo-generated Podfile); append
|
|
156
|
+
// the declaration so the build requirement is at least present.
|
|
157
|
+
return `${contents.trimEnd()}\n${block}\n`;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const withKaleidoscope = (config) => {
|
|
161
|
+
if (!config.mods) {
|
|
162
|
+
config.mods = {};
|
|
163
|
+
}
|
|
164
|
+
if (!config.mods.ios) {
|
|
165
|
+
config.mods.ios = {};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Chain any previously registered iOS dangerous mod so we cooperate with
|
|
169
|
+
// other plugins instead of clobbering them.
|
|
170
|
+
const previousMod = config.mods.ios.dangerous;
|
|
171
|
+
|
|
172
|
+
config.mods.ios.dangerous = async (modConfig) => {
|
|
173
|
+
const result = typeof previousMod === 'function' ? await previousMod(modConfig) : modConfig;
|
|
174
|
+
const modRequest = result.modRequest || {};
|
|
175
|
+
const platformProjectRoot = modRequest.platformProjectRoot;
|
|
176
|
+
const pod = resolveWebrtcPod(modRequest.projectRoot);
|
|
177
|
+
if (platformProjectRoot && pod) {
|
|
178
|
+
const podfilePath = path.join(platformProjectRoot, 'Podfile');
|
|
179
|
+
try {
|
|
180
|
+
const original = fs.readFileSync(podfilePath, 'utf8');
|
|
181
|
+
const patched = patchPodfile(original, pod);
|
|
182
|
+
if (patched !== original) {
|
|
183
|
+
fs.writeFileSync(podfilePath, patched);
|
|
184
|
+
}
|
|
185
|
+
} catch (error) {
|
|
186
|
+
// Non-fatal: surface a clear instruction rather than failing prebuild.
|
|
187
|
+
const manualLine = `pod '${pod.podName}', :path => '../node_modules/${pod.packageDir}', :modular_headers => true`;
|
|
188
|
+
console.warn(
|
|
189
|
+
`[react-native-webrtc-kaleidoscope] Could not patch the Podfile to build ${pod.podName} with modular headers; add "${manualLine}" inside your app target manually. ${String(error)}`,
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (platformProjectRoot) {
|
|
194
|
+
// Raise the consumer's iOS deployment target via Podfile.properties.json.
|
|
195
|
+
// The generated Podfile reads `podfile_properties['ios.deploymentTarget']`
|
|
196
|
+
// at the top, so this is the canonical, no-Podfile-edit override seam.
|
|
197
|
+
// `expo-modules-autolinking`'s package-filter silently drops any pod
|
|
198
|
+
// whose declared minimum platform exceeds the Podfile platform; without
|
|
199
|
+
// this bump the Kaleidoscope pod is dropped and the runtime module
|
|
200
|
+
// lookup throws.
|
|
201
|
+
const propsPath = path.join(platformProjectRoot, 'Podfile.properties.json');
|
|
202
|
+
try {
|
|
203
|
+
let parsed = {};
|
|
204
|
+
try {
|
|
205
|
+
const raw = fs.readFileSync(propsPath, 'utf8');
|
|
206
|
+
try {
|
|
207
|
+
const candidate = JSON.parse(raw);
|
|
208
|
+
if (candidate && typeof candidate === 'object' && !Array.isArray(candidate)) {
|
|
209
|
+
parsed = candidate;
|
|
210
|
+
}
|
|
211
|
+
} catch (jsonError) {
|
|
212
|
+
// Corrupt JSON: warn but proceed with `{}` so the build still gets
|
|
213
|
+
// the bump it needs. The next prebuild will fully regenerate the
|
|
214
|
+
// file anyway.
|
|
215
|
+
console.warn(
|
|
216
|
+
`[react-native-webrtc-kaleidoscope] Could not parse ${propsPath}; rewriting with defaults. ${String(jsonError)}`,
|
|
217
|
+
);
|
|
218
|
+
parsed = {};
|
|
219
|
+
}
|
|
220
|
+
} catch (readError) {
|
|
221
|
+
if (readError && readError.code === 'ENOENT') {
|
|
222
|
+
parsed = {};
|
|
223
|
+
} else {
|
|
224
|
+
// Transient I/O failure (EACCES, EMFILE, ...). Don't clobber the
|
|
225
|
+
// file when we couldn't actually read it; warn and bail.
|
|
226
|
+
console.warn(
|
|
227
|
+
`[react-native-webrtc-kaleidoscope] Could not read ${propsPath}; skipping iOS deployment-target bump. ${String(readError)}`,
|
|
228
|
+
);
|
|
229
|
+
return result;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// Explicit own-key copy into a fresh object to foreclose
|
|
233
|
+
// `__proto__`-as-literal-key surprises from JSON.parse.
|
|
234
|
+
const next = {};
|
|
235
|
+
for (const key of Object.keys(parsed)) {
|
|
236
|
+
next[key] = parsed[key];
|
|
237
|
+
}
|
|
238
|
+
const existing = next['ios.deploymentTarget'];
|
|
239
|
+
if (isVersionLessThan(existing, IOS_DEPLOYMENT_TARGET)) {
|
|
240
|
+
next['ios.deploymentTarget'] = IOS_DEPLOYMENT_TARGET;
|
|
241
|
+
}
|
|
242
|
+
fs.writeFileSync(propsPath, `${JSON.stringify(next, null, 2)}\n`);
|
|
243
|
+
} catch (error) {
|
|
244
|
+
console.warn(
|
|
245
|
+
`[react-native-webrtc-kaleidoscope] Could not patch ${propsPath} to raise iOS deployment target; add "ios.deploymentTarget": "${IOS_DEPLOYMENT_TARGET}" to Podfile.properties.json under your demo/ios directory manually. ${String(error)}`,
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return result;
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
return config;
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
module.exports = withKaleidoscope;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/backgrounds/index.ts"],"names":[],"mappings":"AAKA,YAAY,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC","sourcesContent":["// Barrel for the backgrounds feature: the platform-agnostic preset catalog.\n// Preset *sources* are not re-exported here; import them per preset so each\n// pulls only its own WebP, e.g.\n// `import { office1 } from 'react-native-webrtc-kaleidoscope/backgrounds/office-1'`.\n\nexport type { BackgroundPresetName } from './presets';\nexport { BACKGROUND_PRESETS } from './presets';\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Barrel for the backgrounds feature: the platform-agnostic preset catalog.
|
|
2
|
+
// Preset *sources* are not re-exported here; import them per preset so each
|
|
3
|
+
// pulls only its own WebP, e.g.
|
|
4
|
+
// `import { office1 } from 'react-native-webrtc-kaleidoscope/backgrounds/office-1'`.
|
|
5
|
+
export { BACKGROUND_PRESETS } from './presets';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/backgrounds/index.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,4EAA4E;AAC5E,gCAAgC;AAChC,qFAAqF;AAGrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC","sourcesContent":["// Barrel for the backgrounds feature: the platform-agnostic preset catalog.\n// Preset *sources* are not re-exported here; import them per preset so each\n// pulls only its own WebP, e.g.\n// `import { office1 } from 'react-native-webrtc-kaleidoscope/backgrounds/office-1'`.\n\nexport type { BackgroundPresetName } from './presets';\nexport { BACKGROUND_PRESETS } from './presets';\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"office-1.d.ts","sourceRoot":"","sources":["../../src/backgrounds/office-1.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAK1D,eAAO,MAAM,OAAO,EAAE,YAAyB,CAAC","sourcesContent":["import type { PresetSource } from './preset-source.types';\n\n// Native variant. The native module loads its own bundled resource by name, so\n// the source is just the preset name; no WebP import, no expo-asset on native.\n// Web is handled by office-1.web.ts.\nexport const office1: PresetSource = 'office-1';\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Native variant. The native module loads its own bundled resource by name, so
|
|
2
|
+
// the source is just the preset name; no WebP import, no expo-asset on native.
|
|
3
|
+
// Web is handled by office-1.web.ts.
|
|
4
|
+
export const office1 = 'office-1';
|
|
5
|
+
//# sourceMappingURL=office-1.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"office-1.js","sourceRoot":"","sources":["../../src/backgrounds/office-1.ts"],"names":[],"mappings":"AAEA,+EAA+E;AAC/E,+EAA+E;AAC/E,qCAAqC;AACrC,MAAM,CAAC,MAAM,OAAO,GAAiB,UAAU,CAAC","sourcesContent":["import type { PresetSource } from './preset-source.types';\n\n// Native variant. The native module loads its own bundled resource by name, so\n// the source is just the preset name; no WebP import, no expo-asset on native.\n// Web is handled by office-1.web.ts.\nexport const office1: PresetSource = 'office-1';\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"office-1.web.d.ts","sourceRoot":"","sources":["../../src/backgrounds/office-1.web.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAK1D,eAAO,MAAM,OAAO,EAAE,YAAiD,CAAC","sourcesContent":["/// <reference path=\"./assets.d.ts\" />\nimport { Asset } from 'expo-asset';\nimport office1Asset from './office-1.webp';\nimport type { PresetSource } from './preset-source.types';\n\n// Web variant. The bundled WebP's URL, which the background-image effect\n// fetches. Resolved with expo-asset because react-native-web has no\n// Image.resolveAssetSource; `.uri` is set synchronously by fromModule.\nexport const office1: PresetSource = Asset.fromModule(office1Asset).uri;\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/// <reference path="./assets.d.ts" />
|
|
2
|
+
import { Asset } from 'expo-asset';
|
|
3
|
+
import office1Asset from './office-1.webp';
|
|
4
|
+
// Web variant. The bundled WebP's URL, which the background-image effect
|
|
5
|
+
// fetches. Resolved with expo-asset because react-native-web has no
|
|
6
|
+
// Image.resolveAssetSource; `.uri` is set synchronously by fromModule.
|
|
7
|
+
export const office1 = Asset.fromModule(office1Asset).uri;
|
|
8
|
+
//# sourceMappingURL=office-1.web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"office-1.web.js","sourceRoot":"","sources":["../../src/backgrounds/office-1.web.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,YAAY,MAAM,iBAAiB,CAAC;AAG3C,yEAAyE;AACzE,oEAAoE;AACpE,uEAAuE;AACvE,MAAM,CAAC,MAAM,OAAO,GAAiB,KAAK,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC","sourcesContent":["/// <reference path=\"./assets.d.ts\" />\nimport { Asset } from 'expo-asset';\nimport office1Asset from './office-1.webp';\nimport type { PresetSource } from './preset-source.types';\n\n// Web variant. The bundled WebP's URL, which the background-image effect\n// fetches. Resolved with expo-asset because react-native-web has no\n// Image.resolveAssetSource; `.uri` is set synchronously by fromModule.\nexport const office1: PresetSource = Asset.fromModule(office1Asset).uri;\n"]}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"office-2.d.ts","sourceRoot":"","sources":["../../src/backgrounds/office-2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAK1D,eAAO,MAAM,OAAO,EAAE,YAAyB,CAAC","sourcesContent":["import type { PresetSource } from './preset-source.types';\n\n// Native variant. The native module loads its own bundled resource by name, so\n// the source is just the preset name; no WebP import, no expo-asset on native.\n// Web is handled by office-2.web.ts.\nexport const office2: PresetSource = 'office-2';\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Native variant. The native module loads its own bundled resource by name, so
|
|
2
|
+
// the source is just the preset name; no WebP import, no expo-asset on native.
|
|
3
|
+
// Web is handled by office-2.web.ts.
|
|
4
|
+
export const office2 = 'office-2';
|
|
5
|
+
//# sourceMappingURL=office-2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"office-2.js","sourceRoot":"","sources":["../../src/backgrounds/office-2.ts"],"names":[],"mappings":"AAEA,+EAA+E;AAC/E,+EAA+E;AAC/E,qCAAqC;AACrC,MAAM,CAAC,MAAM,OAAO,GAAiB,UAAU,CAAC","sourcesContent":["import type { PresetSource } from './preset-source.types';\n\n// Native variant. The native module loads its own bundled resource by name, so\n// the source is just the preset name; no WebP import, no expo-asset on native.\n// Web is handled by office-2.web.ts.\nexport const office2: PresetSource = 'office-2';\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"office-2.web.d.ts","sourceRoot":"","sources":["../../src/backgrounds/office-2.web.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAK1D,eAAO,MAAM,OAAO,EAAE,YAAiD,CAAC","sourcesContent":["/// <reference path=\"./assets.d.ts\" />\nimport { Asset } from 'expo-asset';\nimport office2Asset from './office-2.webp';\nimport type { PresetSource } from './preset-source.types';\n\n// Web variant. The bundled WebP's URL, which the background-image effect\n// fetches. Resolved with expo-asset because react-native-web has no\n// Image.resolveAssetSource; `.uri` is set synchronously by fromModule.\nexport const office2: PresetSource = Asset.fromModule(office2Asset).uri;\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/// <reference path="./assets.d.ts" />
|
|
2
|
+
import { Asset } from 'expo-asset';
|
|
3
|
+
import office2Asset from './office-2.webp';
|
|
4
|
+
// Web variant. The bundled WebP's URL, which the background-image effect
|
|
5
|
+
// fetches. Resolved with expo-asset because react-native-web has no
|
|
6
|
+
// Image.resolveAssetSource; `.uri` is set synchronously by fromModule.
|
|
7
|
+
export const office2 = Asset.fromModule(office2Asset).uri;
|
|
8
|
+
//# sourceMappingURL=office-2.web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"office-2.web.js","sourceRoot":"","sources":["../../src/backgrounds/office-2.web.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,YAAY,MAAM,iBAAiB,CAAC;AAG3C,yEAAyE;AACzE,oEAAoE;AACpE,uEAAuE;AACvE,MAAM,CAAC,MAAM,OAAO,GAAiB,KAAK,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC","sourcesContent":["/// <reference path=\"./assets.d.ts\" />\nimport { Asset } from 'expo-asset';\nimport office2Asset from './office-2.webp';\nimport type { PresetSource } from './preset-source.types';\n\n// Web variant. The bundled WebP's URL, which the background-image effect\n// fetches. Resolved with expo-asset because react-native-web has no\n// Image.resolveAssetSource; `.uri` is set synchronously by fromModule.\nexport const office2: PresetSource = Asset.fromModule(office2Asset).uri;\n"]}
|
|
Binary file
|