react-native-webrtc-kaleidoscope 2.3.0 → 2.4.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.
Files changed (62) hide show
  1. package/README.md +12 -3
  2. package/android/src/main/java/com/simiancraft/kaleidoscope/gpu/ShadersGenerated.kt +354 -0
  3. package/catalog/shaders/aurora-silk/aurora-silk.form.tsx +35 -0
  4. package/catalog/shaders/aurora-silk/aurora-silk.frag +106 -0
  5. package/catalog/shaders/aurora-silk/aurora-silk.ts +92 -0
  6. package/catalog/shaders/halftone-waves/halftone-waves.form.tsx +35 -0
  7. package/catalog/shaders/halftone-waves/halftone-waves.frag +84 -0
  8. package/catalog/shaders/halftone-waves/halftone-waves.ts +100 -0
  9. package/catalog/shaders/index.ts +16 -0
  10. package/catalog/shaders/kaleidoscope/kaleidoscope.form.tsx +35 -0
  11. package/catalog/shaders/kaleidoscope/kaleidoscope.frag +93 -0
  12. package/catalog/shaders/kaleidoscope/kaleidoscope.ts +81 -0
  13. package/catalog/shaders/neo-memphis/neo-memphis.form.tsx +35 -0
  14. package/catalog/shaders/neo-memphis/neo-memphis.frag +152 -0
  15. package/catalog/shaders/neo-memphis/neo-memphis.ts +84 -0
  16. package/dist/catalog/shaders/aurora-silk/aurora-silk.d.ts +26 -0
  17. package/dist/catalog/shaders/aurora-silk/aurora-silk.d.ts.map +1 -0
  18. package/dist/catalog/shaders/aurora-silk/aurora-silk.form.d.ts +3 -0
  19. package/dist/catalog/shaders/aurora-silk/aurora-silk.form.d.ts.map +1 -0
  20. package/dist/catalog/shaders/aurora-silk/aurora-silk.form.js +13 -0
  21. package/dist/catalog/shaders/aurora-silk/aurora-silk.form.js.map +1 -0
  22. package/dist/catalog/shaders/aurora-silk/aurora-silk.js +70 -0
  23. package/dist/catalog/shaders/aurora-silk/aurora-silk.js.map +1 -0
  24. package/dist/catalog/shaders/halftone-waves/halftone-waves.d.ts +26 -0
  25. package/dist/catalog/shaders/halftone-waves/halftone-waves.d.ts.map +1 -0
  26. package/dist/catalog/shaders/halftone-waves/halftone-waves.form.d.ts +3 -0
  27. package/dist/catalog/shaders/halftone-waves/halftone-waves.form.d.ts.map +1 -0
  28. package/dist/catalog/shaders/halftone-waves/halftone-waves.form.js +13 -0
  29. package/dist/catalog/shaders/halftone-waves/halftone-waves.form.js.map +1 -0
  30. package/dist/catalog/shaders/halftone-waves/halftone-waves.js +78 -0
  31. package/dist/catalog/shaders/halftone-waves/halftone-waves.js.map +1 -0
  32. package/dist/catalog/shaders/index.d.ts +16 -0
  33. package/dist/catalog/shaders/index.d.ts.map +1 -1
  34. package/dist/catalog/shaders/index.js +9 -1
  35. package/dist/catalog/shaders/index.js.map +1 -1
  36. package/dist/catalog/shaders/kaleidoscope/kaleidoscope.d.ts +24 -0
  37. package/dist/catalog/shaders/kaleidoscope/kaleidoscope.d.ts.map +1 -0
  38. package/dist/catalog/shaders/kaleidoscope/kaleidoscope.form.d.ts +3 -0
  39. package/dist/catalog/shaders/kaleidoscope/kaleidoscope.form.d.ts.map +1 -0
  40. package/dist/catalog/shaders/kaleidoscope/kaleidoscope.form.js +14 -0
  41. package/dist/catalog/shaders/kaleidoscope/kaleidoscope.form.js.map +1 -0
  42. package/dist/catalog/shaders/kaleidoscope/kaleidoscope.js +61 -0
  43. package/dist/catalog/shaders/kaleidoscope/kaleidoscope.js.map +1 -0
  44. package/dist/catalog/shaders/neo-memphis/neo-memphis.d.ts +26 -0
  45. package/dist/catalog/shaders/neo-memphis/neo-memphis.d.ts.map +1 -0
  46. package/dist/catalog/shaders/neo-memphis/neo-memphis.form.d.ts +3 -0
  47. package/dist/catalog/shaders/neo-memphis/neo-memphis.form.d.ts.map +1 -0
  48. package/dist/catalog/shaders/neo-memphis/neo-memphis.form.js +13 -0
  49. package/dist/catalog/shaders/neo-memphis/neo-memphis.form.js.map +1 -0
  50. package/dist/catalog/shaders/neo-memphis/neo-memphis.js +62 -0
  51. package/dist/catalog/shaders/neo-memphis/neo-memphis.js.map +1 -0
  52. package/dist/web-driver/shaders.generated.d.ts +4 -0
  53. package/dist/web-driver/shaders.generated.d.ts.map +1 -1
  54. package/dist/web-driver/shaders.generated.js +351 -1
  55. package/dist/web-driver/shaders.generated.js.map +1 -1
  56. package/ios/KaleidoscopeModule/shaders/GENERATIVE.txt +4 -0
  57. package/ios/KaleidoscopeModule/shaders/SHADERS.txt +4 -0
  58. package/ios/KaleidoscopeModule/shaders/aurora-silk.metalsrc +51 -0
  59. package/ios/KaleidoscopeModule/shaders/halftone-waves.metalsrc +41 -0
  60. package/ios/KaleidoscopeModule/shaders/kaleidoscope.metalsrc +45 -0
  61. package/ios/KaleidoscopeModule/shaders/neo-memphis.metalsrc +181 -0
  62. package/package.json +30 -2
@@ -0,0 +1,84 @@
1
+ // Halftone waves: a dot lattice whose dot size is modulated by slow traveling
2
+ // interference waves; the late-2000s "mathematical" tech texture as an opaque
3
+ // BACKGROUND layer (issue #61). The cheapest of the corporate-abstract set:
4
+ // per pixel, one hash-free cell lookup, two sines evaluated at the CELL CENTER
5
+ // (so every pixel of a dot agrees), and one blended distance metric. No noise,
6
+ // no pow, no loops.
7
+ //
8
+ // Overdrive surface: the two-tone palette inverts the whole mood (ink on
9
+ // paper vs paper on ink), uPitch sets the texture scale, uShape morphs the
10
+ // dots diamond -> circle -> square, uWaveAmp and uSpeed set how alive it is.
11
+ // uCalm eases the wave modulation near frame center, where the masked
12
+ // subject's face sits.
13
+ //
14
+ // UV convention: matches passthrough.vert. vUv = (0, 0) at bottom-left,
15
+ // (1, 1) at top-right. fragCoord is reconstructed as vUv * uResolution; no
16
+ // gl_FragCoord. Fully procedural: no input texture, zero net texture flips on
17
+ // every runtime.
18
+ //
19
+ // Precision: highp float, matching the other procedural shaders; the cell
20
+ // math is plain fract/floor and would survive mediump, but consistency wins.
21
+
22
+ #version 300 es
23
+ precision highp float;
24
+
25
+ uniform float uTime; // seconds, monotonically increasing; range [0, inf)
26
+ uniform vec2 uResolution; // framebuffer size in pixels; both components > 0
27
+ uniform vec3 uPaper; // field color (behind the dots)
28
+ uniform vec3 uInk; // dot color
29
+ uniform float uPitch; // dot-grid cells across frame height
30
+ uniform float uDotSize; // base dot radius in cell units, 0..0.5
31
+ uniform float uWaveAmp; // radius modulation depth, 0..1
32
+ uniform float uSpeed; // wave travel rate; 0 freezes
33
+ uniform float uShape; // dot shape: 0 diamond, 1 circle, 2 square
34
+ uniform float uAngle; // wave direction, radians
35
+ uniform float uCalm; // 0..1 eases the waves at frame center (face zone)
36
+
37
+ in highp vec2 vUv;
38
+ out vec4 oColor;
39
+
40
+ // Antialias half-width in cell units; ~1px at the default pitch.
41
+ const float AA = 0.06;
42
+
43
+ void main() {
44
+ // Aspect-correct, screen-centered coordinates (matches plasma/nebula).
45
+ vec2 fragCoord = vUv * uResolution;
46
+ vec2 uv = (fragCoord - 0.5 * uResolution) / uResolution.y;
47
+ float centerDist = length(uv);
48
+
49
+ vec2 luv = uv * uPitch;
50
+ vec2 id = floor(luv);
51
+ vec2 gv = fract(luv) - 0.5;
52
+ // Wave phase is sampled at the CELL CENTER so a dot's radius is uniform
53
+ // across its own pixels (true halftone, not a warped field).
54
+ vec2 c = (id + 0.5) / uPitch;
55
+
56
+ float t = uTime * uSpeed;
57
+ vec2 dir1 = vec2(cos(uAngle), sin(uAngle));
58
+ vec2 dir2 = vec2(cos(uAngle + 2.2), sin(uAngle + 2.2));
59
+ // Two traveling waves at incommensurate frequencies: interference patterns
60
+ // that drift forever without visibly repeating.
61
+ float w = 0.5 + 0.25 * sin(dot(c, dir1) * 3.1 + t) + 0.25 * sin(dot(c, dir2) * 4.7 - t * 0.77);
62
+
63
+ // uCalm: flatten the modulation toward its midpoint near frame center.
64
+ float calm = uCalm * (1.0 - smoothstep(0.15, 0.62, centerDist));
65
+ w = mix(w, 0.5, calm);
66
+
67
+ float radius = uDotSize * mix(1.0 - uWaveAmp, 1.0 + uWaveAmp, w);
68
+
69
+ // Blended distance metric, pow-free (variable-exponent pow lowers to
70
+ // exp2+log2 on mobile): diamond (L1) -> circle (L2) -> square (Linf).
71
+ vec2 q = abs(gv);
72
+ float dDiamond = (q.x + q.y) * 0.7071;
73
+ float dCircle = length(q);
74
+ float dSquare = max(q.x, q.y);
75
+ float d = (uShape < 1.0)
76
+ ? mix(dDiamond, dCircle, clamp(uShape, 0.0, 1.0))
77
+ : mix(dCircle, dSquare, clamp(uShape - 1.0, 0.0, 1.0));
78
+
79
+ float m = smoothstep(radius + AA, radius - AA, d);
80
+ vec3 color = mix(uPaper, uInk, m);
81
+
82
+ // Opaque procedural background; the person is composited over it downstream.
83
+ oColor = vec4(color, 1.0);
84
+ }
@@ -0,0 +1,100 @@
1
+ // Halftone-waves layer-shader interface: typed uniforms + control descriptor.
2
+ // A dot lattice with traveling-wave size modulation (the late-2000s
3
+ // "mathematical" tech texture), an opaque BACKGROUND layer (issue #61). One
4
+ // halftone-waves.frag fans out into the book presets (boardroom, press,
5
+ // ripple) by varying these uniforms; the two-tone palette is the big lever.
6
+ // Shader source is shaders/halftone-waves.frag.
7
+
8
+ import type { RGB } from '../../../src/lib/primitives.types';
9
+ import type { UniformControl } from '../_shared/types';
10
+
11
+ /** Typed uniforms for the `halftone-waves` layer shader. */
12
+ export type HalftoneWavesUniforms = {
13
+ /** Field color behind the dots. */
14
+ readonly uPaper: RGB;
15
+ /** Dot color. */
16
+ readonly uInk: RGB;
17
+ /** Dot-grid cells across frame height; higher = finer texture. */
18
+ readonly uPitch: number;
19
+ /** Base dot radius in cell units. */
20
+ readonly uDotSize: number;
21
+ /** Wave modulation depth; 0 = static even dots. */
22
+ readonly uWaveAmp: number;
23
+ /** Wave travel rate; 0 freezes. */
24
+ readonly uSpeed: number;
25
+ /** Dot shape: 0 diamond, 1 circle, 2 square. */
26
+ readonly uShape: number;
27
+ /** Wave direction in radians. */
28
+ readonly uAngle: number;
29
+ /** Eases the waves at frame center (the face zone); 0 = off. */
30
+ readonly uCalm: number;
31
+ };
32
+
33
+ /** The `halftone-waves` shader's tunables; defaults are the "boardroom" look. */
34
+ export const HALFTONE_WAVES_CONTROLS: readonly UniformControl[] = [
35
+ { name: 'uPaper', kind: 'color', default: [0.95, 0.95, 0.94], doc: 'Field color.' },
36
+ { name: 'uInk', kind: 'color', default: [0.62, 0.66, 0.7], doc: 'Dot color.' },
37
+ {
38
+ name: 'uPitch',
39
+ kind: 'float',
40
+ default: 26,
41
+ min: 8,
42
+ max: 60,
43
+ step: 1,
44
+ doc: 'Dot-grid cells across frame height.',
45
+ },
46
+ {
47
+ name: 'uDotSize',
48
+ kind: 'float',
49
+ default: 0.26,
50
+ min: 0.05,
51
+ max: 0.5,
52
+ step: 0.01,
53
+ doc: 'Base dot radius in cell units.',
54
+ },
55
+ {
56
+ name: 'uWaveAmp',
57
+ kind: 'float',
58
+ default: 0.55,
59
+ min: 0,
60
+ max: 1,
61
+ step: 0.01,
62
+ doc: 'Wave modulation depth.',
63
+ },
64
+ {
65
+ name: 'uSpeed',
66
+ kind: 'float',
67
+ default: 0.5,
68
+ min: 0,
69
+ max: 2,
70
+ step: 0.01,
71
+ doc: 'Wave travel rate; 0 freezes.',
72
+ },
73
+ {
74
+ name: 'uShape',
75
+ kind: 'float',
76
+ default: 1,
77
+ min: 0,
78
+ max: 2,
79
+ step: 0.05,
80
+ doc: 'Dot shape: 0 diamond, 1 circle, 2 square.',
81
+ },
82
+ {
83
+ name: 'uAngle',
84
+ kind: 'float',
85
+ default: 0.6,
86
+ min: 0,
87
+ max: 6.28,
88
+ step: 0.01,
89
+ doc: 'Wave direction, radians.',
90
+ },
91
+ {
92
+ name: 'uCalm',
93
+ kind: 'float',
94
+ default: 0,
95
+ min: 0,
96
+ max: 1,
97
+ step: 0.01,
98
+ doc: 'Eases the waves at frame center (face zone).',
99
+ },
100
+ ];
@@ -4,19 +4,25 @@
4
4
  // re-exported individually; a consumer imports the one its preset's layer needs.
5
5
 
6
6
  import type { AnamorphicLensFlareUniforms } from './anamorphic-lensflare/anamorphic-lensflare';
7
+ import type { AuroraSilkUniforms } from './aurora-silk/aurora-silk';
7
8
  import type { BlurUniforms } from './blur/blur';
8
9
  import type { CloudsUniforms } from './clouds/clouds';
9
10
  import type { CorporateBlobsUniforms } from './corporate-blobs/corporate-blobs';
10
11
  import type { FirefliesUniforms } from './fireflies/fireflies';
11
12
  import type { GodraysUniforms } from './godrays/godrays';
13
+ import type { HalftoneWavesUniforms } from './halftone-waves/halftone-waves';
14
+ import type { KaleidoscopeShaderUniforms } from './kaleidoscope/kaleidoscope';
12
15
  import type { LightBeamsAndMotesUniforms } from './light-beams-and-motes/light-beams-and-motes';
13
16
  import type { NebulaUniforms } from './nebula/nebula';
17
+ import type { NeoMemphisUniforms } from './neo-memphis/neo-memphis';
14
18
  import type { PlasmaUniforms } from './plasma/plasma';
15
19
  import type { SimianlightsUniforms } from './simianlights/simianlights';
16
20
 
17
21
  export { defaultUniforms, type UniformControl } from './_shared/types';
18
22
  export type { AnamorphicLensFlareUniforms } from './anamorphic-lensflare/anamorphic-lensflare';
19
23
  export { ANAMORPHIC_LENSFLARE_CONTROLS } from './anamorphic-lensflare/anamorphic-lensflare';
24
+ export type { AuroraSilkUniforms } from './aurora-silk/aurora-silk';
25
+ export { AURORA_SILK_CONTROLS } from './aurora-silk/aurora-silk';
20
26
  export type { BlurUniforms } from './blur/blur';
21
27
  export { BLUR_CONTROLS } from './blur/blur';
22
28
  export type { CloudsUniforms } from './clouds/clouds';
@@ -27,10 +33,16 @@ export type { FirefliesUniforms } from './fireflies/fireflies';
27
33
  export { FIREFLIES_CONTROLS } from './fireflies/fireflies';
28
34
  export type { GodraysUniforms } from './godrays/godrays';
29
35
  export { GODRAYS_CONTROLS } from './godrays/godrays';
36
+ export type { HalftoneWavesUniforms } from './halftone-waves/halftone-waves';
37
+ export { HALFTONE_WAVES_CONTROLS } from './halftone-waves/halftone-waves';
38
+ export type { KaleidoscopeShaderUniforms } from './kaleidoscope/kaleidoscope';
39
+ export { KALEIDOSCOPE_CONTROLS } from './kaleidoscope/kaleidoscope';
30
40
  export type { LightBeamsAndMotesUniforms } from './light-beams-and-motes/light-beams-and-motes';
31
41
  export { LIGHT_BEAMS_AND_MOTES_CONTROLS } from './light-beams-and-motes/light-beams-and-motes';
32
42
  export type { NebulaUniforms } from './nebula/nebula';
33
43
  export { NEBULA_CONTROLS } from './nebula/nebula';
44
+ export type { NeoMemphisUniforms } from './neo-memphis/neo-memphis';
45
+ export { NEO_MEMPHIS_CONTROLS } from './neo-memphis/neo-memphis';
34
46
  export type { PlasmaUniforms } from './plasma/plasma';
35
47
  export { PLASMA_CONTROLS } from './plasma/plasma';
36
48
  export type { SimianlightsUniforms } from './simianlights/simianlights';
@@ -47,10 +59,14 @@ export type ShaderUniformsMap = {
47
59
  readonly clouds: CloudsUniforms;
48
60
  readonly godrays: GodraysUniforms;
49
61
  readonly fireflies: FirefliesUniforms;
62
+ readonly kaleidoscope: KaleidoscopeShaderUniforms;
63
+ readonly 'halftone-waves': HalftoneWavesUniforms;
50
64
  readonly plasma: PlasmaUniforms;
51
65
  readonly nebula: NebulaUniforms;
66
+ readonly 'neo-memphis': NeoMemphisUniforms;
52
67
  readonly simianlights: SimianlightsUniforms;
53
68
  readonly 'anamorphic-lensflare': AnamorphicLensFlareUniforms;
69
+ readonly 'aurora-silk': AuroraSilkUniforms;
54
70
  readonly 'light-beams-and-motes': LightBeamsAndMotesUniforms;
55
71
  readonly 'corporate-blobs': CorporateBlobsUniforms;
56
72
  };
@@ -0,0 +1,35 @@
1
+ // Kaleidoscope's editor form: the shader OWNS its control layout (the plasma
2
+ // pattern). One <Control uniform="…"/> per uniform in declared order; layout
3
+ // or grouping changes are a local edit here. Conventional layer id:
4
+ // "kaleidoscope".
5
+
6
+ import {
7
+ Control,
8
+ ControlForm,
9
+ ControlSection,
10
+ type KaleidoscopeControls,
11
+ } from '../../../src/components/preset-control-panel';
12
+ import { KALEIDOSCOPE_CONTROLS } from './kaleidoscope';
13
+
14
+ export function KaleidoscopeForm({ uniforms, onPatch, disabled }: KaleidoscopeControls) {
15
+ return (
16
+ <ControlForm
17
+ id="kaleidoscope"
18
+ uniforms={uniforms.kaleidoscope ?? {}}
19
+ onPatch={onPatch}
20
+ disabled={disabled}
21
+ controls={KALEIDOSCOPE_CONTROLS}
22
+ >
23
+ <ControlSection title="kaleidoscope">
24
+ <Control uniform="uColorA" />
25
+ <Control uniform="uColorB" />
26
+ <Control uniform="uColorC" />
27
+ <Control uniform="uSegments" />
28
+ <Control uniform="uSpeed" />
29
+ <Control uniform="uRotate" />
30
+ <Control uniform="uZoom" />
31
+ <Control uniform="uCalm" />
32
+ </ControlSection>
33
+ </ControlForm>
34
+ );
35
+ }
@@ -0,0 +1,93 @@
1
+ // Kaleidoscope: the library's namesake. A mirrored polar fold (angle modulo
2
+ // 2pi/N) over a cheap drifting sine field; the fold makes any source field
3
+ // read as ornamental cut glass. An opaque BACKGROUND layer (issue #61).
4
+ //
5
+ // Overdrive surface: uSegments changes the whole character (6 = bold facets,
6
+ // 12 = lace), the three palette colors re-skin it completely, uRotate/uSpeed
7
+ // set the energy. uCalm eases contrast toward frame center, where the masked
8
+ // subject's face sits, so the pattern stays lively at the edges without
9
+ // flickering behind a speaker.
10
+ //
11
+ // UV convention: matches passthrough.vert. vUv = (0, 0) at bottom-left,
12
+ // (1, 1) at top-right. fragCoord is reconstructed as vUv * uResolution so this
13
+ // stays on the vUv convention and never reads gl_FragCoord (whose Y
14
+ // orientation flips between OpenGL and Metal). Fully procedural: no input
15
+ // texture, so there is no texture-origin handoff to flip. Net texture flips:
16
+ // zero on every runtime. The polar fold is rotation-symmetric, so even a
17
+ // hypothetical flip would be invisible here; the convention is kept anyway.
18
+ //
19
+ // Precision: highp float, matching the other procedural shaders (bounded
20
+ // sine sums, but vUv is highp by the passthrough.vert contract and the fold's
21
+ // atan/mod chain benefits from full mantissa at high segment counts).
22
+ //
23
+ // Cost class: plasma plus one atan and a mod; no loops, no noise, no hashing.
24
+
25
+ #version 300 es
26
+ precision highp float;
27
+
28
+ uniform float uTime; // seconds, monotonically increasing; range [0, inf)
29
+ uniform vec2 uResolution; // framebuffer size in pixels; both components > 0
30
+ uniform vec3 uColorA; // base palette color (also the calm midpoint pole)
31
+ uniform vec3 uColorB; // second palette color
32
+ uniform vec3 uColorC; // accent color, layered over the A/B field
33
+ uniform float uSegments; // mirror segment count; floor()ed, clamped >= 3
34
+ uniform float uSpeed; // source-field drift rate; 0 freezes the pattern
35
+ uniform float uRotate; // whole-field rotation rate; sign sets direction
36
+ uniform float uZoom; // pattern scale; higher = more rings of detail
37
+ uniform float uCalm; // 0..1 eases contrast at frame center (face zone)
38
+
39
+ in highp vec2 vUv;
40
+ out vec4 oColor;
41
+
42
+ const float TAU = 6.28318530718;
43
+
44
+ void main() {
45
+ // Aspect-correct, screen-centered coordinates (matches plasma/nebula).
46
+ vec2 fragCoord = vUv * uResolution;
47
+ vec2 uv = (fragCoord - 0.5 * uResolution) / uResolution.y;
48
+ float centerDist = length(uv);
49
+
50
+ // Whole-field rotation: the slow "turning the scope" motion.
51
+ float ra = uTime * uRotate;
52
+ float cs = cos(ra);
53
+ float sn = sin(ra);
54
+ uv = mat2(cs, -sn, sn, cs) * uv;
55
+
56
+ // Mirrored polar fold. The 1e-5 nudge keeps atan() off the undefined (0,0)
57
+ // input under Metal; it is far below one pixel at any resolution.
58
+ float r = centerDist * uZoom * (1.0 + 0.06 * sin(uTime * 0.23));
59
+ float seg = TAU / max(3.0, floor(uSegments));
60
+ float a = atan(uv.y, uv.x + 1e-5);
61
+ a = mod(a, seg);
62
+ a = abs(a - seg * 0.5);
63
+ vec2 p = r * vec2(cos(a), sin(a));
64
+
65
+ float t = uTime * uSpeed;
66
+
67
+ // Drifting source field, plasma-class: a few sines of folded position and
68
+ // time. The off-axis moving center in the length() term keeps the pattern
69
+ // evolving (non-repeating) rather than pulsing in place.
70
+ float f1 = sin(p.x * 6.0 + t)
71
+ + sin((p.x + p.y) * 4.2 - t * 0.7)
72
+ + sin(length(p - vec2(0.9 + 0.25 * sin(t * 0.31), 0.0)) * 7.0 + t * 1.1);
73
+ float f2 = sin(p.y * 5.0 - t * 0.9 + sin(p.x * 3.1 + t * 0.4));
74
+ float m1 = 0.5 + 0.5 * sin(f1);
75
+ float m2 = smoothstep(0.25, 0.9, 0.5 + 0.5 * sin(f2 + f1 * 0.5));
76
+
77
+ vec3 color = mix(uColorA, uColorB, m1);
78
+ color = mix(color, uColorC, m2 * 0.65);
79
+
80
+ // Thin darkening along both mirror lines sells the cut-glass facets.
81
+ float seam = smoothstep(0.035, 0.0, abs(a - seg * 0.5)) + smoothstep(0.035, 0.0, a);
82
+ color *= 1.0 - 0.18 * seam;
83
+
84
+ // uCalm: ease toward the palette midpoint near frame center. Spatial-only
85
+ // (never scales time per pixel, which would shear the field across the
86
+ // falloff ring).
87
+ vec3 mid = 0.5 * (uColorA + uColorB);
88
+ float calm = uCalm * (1.0 - smoothstep(0.15, 0.62, centerDist));
89
+ color = mix(color, mid, calm * 0.6);
90
+
91
+ // Opaque procedural background; the person is composited over it downstream.
92
+ oColor = vec4(color, 1.0);
93
+ }
@@ -0,0 +1,81 @@
1
+ // Kaleidoscope layer-shader interface: typed uniforms + control descriptor.
2
+ // The library's namesake: a mirrored polar fold over a drifting sine field, an
3
+ // opaque BACKGROUND layer (issue #61). One kaleidoscope.frag fans out into the
4
+ // book presets (stained-glass, mandala, prism) by varying these uniforms; the
5
+ // segment count and palette are the big levers. Shader source is
6
+ // shaders/kaleidoscope.frag.
7
+
8
+ import type { RGB } from '../../../src/lib/primitives.types';
9
+ import type { UniformControl } from '../_shared/types';
10
+
11
+ /** Typed uniforms for the `kaleidoscope` layer shader. */
12
+ export type KaleidoscopeShaderUniforms = {
13
+ /** Base palette color; also the pole uCalm eases toward. */
14
+ readonly uColorA: RGB;
15
+ /** Second palette color. */
16
+ readonly uColorB: RGB;
17
+ /** Accent color layered over the A/B field. */
18
+ readonly uColorC: RGB;
19
+ /** Mirror segment count; 6 = bold facets, 12 = lace. */
20
+ readonly uSegments: number;
21
+ /** Source-field drift rate; 0 freezes the pattern. */
22
+ readonly uSpeed: number;
23
+ /** Whole-field rotation rate; sign sets direction. */
24
+ readonly uRotate: number;
25
+ /** Pattern scale; higher = more rings of detail. */
26
+ readonly uZoom: number;
27
+ /** Eases contrast at frame center (the face zone); 0 = off. */
28
+ readonly uCalm: number;
29
+ };
30
+
31
+ /** The `kaleidoscope` shader's tunables; defaults are the "stained glass" look. */
32
+ export const KALEIDOSCOPE_CONTROLS: readonly UniformControl[] = [
33
+ { name: 'uColorA', kind: 'color', default: [0.07, 0.15, 0.36], doc: 'Base palette color.' },
34
+ { name: 'uColorB', kind: 'color', default: [0.1, 0.55, 0.62], doc: 'Second palette color.' },
35
+ { name: 'uColorC', kind: 'color', default: [0.93, 0.69, 0.21], doc: 'Accent color.' },
36
+ {
37
+ name: 'uSegments',
38
+ kind: 'float',
39
+ default: 8,
40
+ min: 3,
41
+ max: 16,
42
+ step: 1,
43
+ doc: 'Mirror segment count; 6 = bold facets, 12 = lace.',
44
+ },
45
+ {
46
+ name: 'uSpeed',
47
+ kind: 'float',
48
+ default: 0.35,
49
+ min: 0,
50
+ max: 2,
51
+ step: 0.01,
52
+ doc: 'Drift rate; 0 freezes.',
53
+ },
54
+ {
55
+ name: 'uRotate',
56
+ kind: 'float',
57
+ default: 0.04,
58
+ min: -0.5,
59
+ max: 0.5,
60
+ step: 0.005,
61
+ doc: 'Whole-field rotation rate; sign sets direction.',
62
+ },
63
+ {
64
+ name: 'uZoom',
65
+ kind: 'float',
66
+ default: 1.6,
67
+ min: 0.5,
68
+ max: 4,
69
+ step: 0.05,
70
+ doc: 'Pattern scale; higher = more rings of detail.',
71
+ },
72
+ {
73
+ name: 'uCalm',
74
+ kind: 'float',
75
+ default: 0,
76
+ min: 0,
77
+ max: 1,
78
+ step: 0.01,
79
+ doc: 'Eases contrast at frame center (face zone).',
80
+ },
81
+ ];
@@ -0,0 +1,35 @@
1
+ // Neo-Memphis's editor form: the shader OWNS its control layout (the plasma
2
+ // pattern). One <Control uniform="…"/> per uniform in declared order.
3
+ // Conventional layer id: "neo-memphis".
4
+
5
+ import {
6
+ Control,
7
+ ControlForm,
8
+ ControlSection,
9
+ type KaleidoscopeControls,
10
+ } from '../../../src/components/preset-control-panel';
11
+ import { NEO_MEMPHIS_CONTROLS } from './neo-memphis';
12
+
13
+ export function NeoMemphisForm({ uniforms, onPatch, disabled }: KaleidoscopeControls) {
14
+ return (
15
+ <ControlForm
16
+ id="neo-memphis"
17
+ uniforms={uniforms['neo-memphis'] ?? {}}
18
+ onPatch={onPatch}
19
+ disabled={disabled}
20
+ controls={NEO_MEMPHIS_CONTROLS}
21
+ >
22
+ <ControlSection title="neo-memphis">
23
+ <Control uniform="uBgColor" />
24
+ <Control uniform="uColorA" />
25
+ <Control uniform="uColorB" />
26
+ <Control uniform="uColorC" />
27
+ <Control uniform="uScale" />
28
+ <Control uniform="uDensity" />
29
+ <Control uniform="uOutline" />
30
+ <Control uniform="uDrift" />
31
+ <Control uniform="uCalm" />
32
+ </ControlSection>
33
+ </ControlForm>
34
+ );
35
+ }
@@ -0,0 +1,152 @@
1
+ // Neo-Memphis: scattered flat-color geometric primitives (discs, rings,
2
+ // triangles, crosses, boxes, squiggles) drifting on a quiet field; the 90s
3
+ // Memphis-design / "Jazz cup" pattern family as an opaque BACKGROUND layer
4
+ // (issue #61). Two parallax cell layers: hero shapes plus a smaller, dimmer
5
+ // backfill texture.
6
+ //
7
+ // Overdrive surface: the four palette colors re-skin it completely (pastel
8
+ // studio / bold primary / duotone), uDensity and uScale set busy-ness,
9
+ // uOutline trades filled shapes for outlined ones, uDrift sets the energy.
10
+ // uCalm fades shapes out near frame center, where the masked subject's face
11
+ // sits.
12
+ //
13
+ // Cost: per pixel, two cell layers each evaluate ONE hash and at most one
14
+ // shape SDF in the HOME cell only; shape extent (size + bob) stays below the
15
+ // half-cell bound, so there is no 3x3 neighbor sweep (contrast nebula's
16
+ // Star). No noise, no pow; one sin per squiggle cell.
17
+ //
18
+ // UV convention: matches passthrough.vert. vUv = (0, 0) at bottom-left,
19
+ // (1, 1) at top-right. fragCoord is reconstructed as vUv * uResolution; no
20
+ // gl_FragCoord. Fully procedural: no input texture, zero net texture flips on
21
+ // every runtime.
22
+ //
23
+ // Precision: highp float. The hash uses large multipliers (fract-of-product
24
+ // tricks); mediump collapses them to banding, same reasoning as nebula.
25
+
26
+ #version 300 es
27
+ precision highp float;
28
+
29
+ uniform float uTime; // seconds, monotonically increasing; range [0, inf)
30
+ uniform vec2 uResolution; // framebuffer size in pixels; both components > 0
31
+ uniform vec3 uBgColor; // field color behind the shapes
32
+ uniform vec3 uColorA; // shape palette color 1
33
+ uniform vec3 uColorB; // shape palette color 2
34
+ uniform vec3 uColorC; // shape palette color 3
35
+ uniform float uScale; // hero-grid cells across frame height
36
+ uniform float uDensity; // probability a cell draws its shape, 0..1
37
+ uniform float uOutline; // probability a shape renders outlined, 0..1
38
+ uniform float uDrift; // scroll + rotation rate; 0 freezes
39
+ uniform float uCalm; // 0..1 fades shapes near frame center (face zone)
40
+
41
+ in highp vec2 vUv;
42
+ out vec4 oColor;
43
+
44
+ const float TAU = 6.28318530718;
45
+ // Antialias half-width in cell units; ~1px at the default pitch.
46
+ const float AA = 0.012;
47
+
48
+ float hash21(vec2 p) {
49
+ p = fract(p * vec2(234.34, 435.345));
50
+ p += dot(p, p + 34.23);
51
+ return fract(p.x * p.y);
52
+ }
53
+
54
+ float sdBox(vec2 p, vec2 b) {
55
+ vec2 d = abs(p) - b;
56
+ return length(max(d, vec2(0.0))) + min(max(d.x, d.y), 0.0);
57
+ }
58
+
59
+ // iq's equilateral triangle, point up, circumradius r.
60
+ float sdTriangle(vec2 p, float r) {
61
+ const float k = 1.7320508;
62
+ p.x = abs(p.x) - r;
63
+ p.y = p.y + r / k;
64
+ if (p.x + k * p.y > 0.0) {
65
+ p = vec2(p.x - k * p.y, -k * p.x - p.y) * 0.5;
66
+ }
67
+ p.x -= clamp(p.x, -2.0 * r, 0.0);
68
+ return -length(p) * sign(p.y);
69
+ }
70
+
71
+ // One cell layer: returns the shape coverage and writes its color.
72
+ // luv is the layer's scrolled cell-space coordinate; backfill restricts the
73
+ // shape menu to dots and crosses and draws smaller.
74
+ float memphisCell(vec2 luv, float seed, float backfill, float t, out vec3 shapeColor) {
75
+ vec2 id = floor(luv);
76
+ vec2 gv = fract(luv) - 0.5;
77
+ float h = hash21(id + seed);
78
+ shapeColor = uBgColor;
79
+ // Density gate: empty cells cost one hash.
80
+ if (h > uDensity) return 0.0;
81
+
82
+ float h2 = fract(h * 57.31);
83
+ float h3 = fract(h * 113.77);
84
+ float h4 = fract(h * 431.13);
85
+ float h5 = fract(h * 891.71);
86
+
87
+ // Per-cell slow spin and a small bob; both bounded so the shape stays
88
+ // inside its cell (max extent 0.34 + 0.04 < 0.5).
89
+ float ang = h2 * TAU + t * (h3 - 0.5) * 0.8;
90
+ float cs = cos(ang);
91
+ float sn = sin(ang);
92
+ gv -= 0.04 * vec2(sin(t * 0.6 + h * TAU), cos(t * 0.8 + h * TAU));
93
+ gv = mat2(cs, -sn, sn, cs) * gv;
94
+
95
+ float r = mix(0.14, 0.30, h3) * mix(1.0, 0.6, backfill);
96
+ float pick = h4 * 6.0;
97
+ float d;
98
+ if (backfill > 0.5) {
99
+ // Backfill texture: dots and crosses only.
100
+ d = (pick < 3.0)
101
+ ? length(gv) - r * 0.45
102
+ : min(sdBox(gv, vec2(r, r * 0.22)), sdBox(gv, vec2(r * 0.22, r)));
103
+ } else if (pick < 1.0) {
104
+ d = length(gv) - r; // disc
105
+ } else if (pick < 2.0) {
106
+ d = abs(length(gv) - r * 0.8) - r * 0.18; // ring
107
+ } else if (pick < 3.0) {
108
+ d = sdTriangle(gv, r); // triangle
109
+ } else if (pick < 4.0) {
110
+ d = min(sdBox(gv, vec2(r, r * 0.24)), sdBox(gv, vec2(r * 0.24, r))); // cross
111
+ } else if (pick < 5.0) {
112
+ d = sdBox(gv, vec2(r * 0.78, r * 0.78)); // box
113
+ } else {
114
+ // Squiggle: a sine-displaced band, clipped to its run length.
115
+ d = max(abs(gv.y - 0.4 * r * sin(gv.x / r * 6.5)) - r * 0.17, abs(gv.x) - r);
116
+ }
117
+
118
+ float fill = smoothstep(AA, -AA, d);
119
+ float ring = smoothstep(AA, -AA, abs(d + r * 0.06) - r * 0.09);
120
+ float m = (h5 < uOutline) ? ring : fill;
121
+
122
+ float colorPick = fract(h * 769.23) * 3.0;
123
+ shapeColor = (colorPick < 1.0) ? uColorA : (colorPick < 2.0) ? uColorB : uColorC;
124
+ return m;
125
+ }
126
+
127
+ void main() {
128
+ // Aspect-correct, screen-centered coordinates (matches plasma/nebula).
129
+ vec2 fragCoord = vUv * uResolution;
130
+ vec2 uv = (fragCoord - 0.5 * uResolution) / uResolution.y;
131
+ float centerDist = length(uv);
132
+
133
+ float t = uTime * uDrift;
134
+ vec3 color = uBgColor;
135
+ vec3 shapeColor;
136
+
137
+ // Backfill layer first (under the hero shapes): smaller, denser, dimmer.
138
+ vec2 luv1 = uv * uScale * 2.3 + vec2(t * 0.045, t * -0.03) + 51.7;
139
+ float m1 = memphisCell(luv1, 7.0, 1.0, t, shapeColor);
140
+ color = mix(color, mix(uBgColor, shapeColor, 0.55), m1);
141
+
142
+ // Hero layer: the big shapes, scrolling the other way.
143
+ vec2 luv0 = uv * uScale + vec2(t * -0.06, t * 0.04);
144
+ float m0 = memphisCell(luv0, 0.0, 0.0, t, shapeColor);
145
+
146
+ // uCalm: fade shapes (not the field) near frame center.
147
+ float calm = 1.0 - uCalm * (1.0 - smoothstep(0.15, 0.62, centerDist));
148
+ color = mix(color, shapeColor, m0 * calm);
149
+
150
+ // Opaque procedural background; the person is composited over it downstream.
151
+ oColor = vec4(color, 1.0);
152
+ }