react-native-webrtc-kaleidoscope 2.6.1 → 2.7.1

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 (34) hide show
  1. package/android/src/main/java/com/simiancraft/kaleidoscope/gpu/ShadersGenerated.kt +205 -31
  2. package/catalog/composites/nebula/nebula.thumb.webp +0 -0
  3. package/catalog/shaders/data-mesh/data-mesh.form.tsx +53 -0
  4. package/catalog/shaders/data-mesh/data-mesh.frag +205 -0
  5. package/catalog/shaders/data-mesh/data-mesh.ts +225 -0
  6. package/catalog/shaders/index.ts +4 -0
  7. package/catalog/shaders/nebula/nebula.frag +11 -3
  8. package/catalog/shaders/outrun-grid/outrun-grid.frag +40 -36
  9. package/catalog/shaders/outrun-grid/outrun-grid.ts +2 -2
  10. package/dist/catalog/composites/nebula/nebula.thumb.webp +0 -0
  11. package/dist/catalog/shaders/data-mesh/data-mesh.d.ts +50 -0
  12. package/dist/catalog/shaders/data-mesh/data-mesh.d.ts.map +1 -0
  13. package/dist/catalog/shaders/data-mesh/data-mesh.form.d.ts +3 -0
  14. package/dist/catalog/shaders/data-mesh/data-mesh.form.d.ts.map +1 -0
  15. package/dist/catalog/shaders/data-mesh/data-mesh.form.js +15 -0
  16. package/dist/catalog/shaders/data-mesh/data-mesh.form.js.map +1 -0
  17. package/dist/catalog/shaders/data-mesh/data-mesh.js +179 -0
  18. package/dist/catalog/shaders/data-mesh/data-mesh.js.map +1 -0
  19. package/dist/catalog/shaders/index.d.ts +4 -0
  20. package/dist/catalog/shaders/index.d.ts.map +1 -1
  21. package/dist/catalog/shaders/index.js +3 -1
  22. package/dist/catalog/shaders/index.js.map +1 -1
  23. package/dist/catalog/shaders/outrun-grid/outrun-grid.js +2 -2
  24. package/dist/catalog/shaders/outrun-grid/outrun-grid.js.map +1 -1
  25. package/dist/web-driver/shaders.generated.d.ts +3 -2
  26. package/dist/web-driver/shaders.generated.d.ts.map +1 -1
  27. package/dist/web-driver/shaders.generated.js +205 -32
  28. package/dist/web-driver/shaders.generated.js.map +1 -1
  29. package/ios/KaleidoscopeModule/shaders/GENERATIVE.txt +1 -0
  30. package/ios/KaleidoscopeModule/shaders/SHADERS.txt +1 -0
  31. package/ios/KaleidoscopeModule/shaders/data-mesh.metalsrc +99 -0
  32. package/ios/KaleidoscopeModule/shaders/nebula.metalsrc +56 -51
  33. package/ios/KaleidoscopeModule/shaders/outrun-grid.metalsrc +12 -14
  34. package/package.json +8 -1
@@ -565,34 +565,38 @@ void main() {
565
565
 
566
566
  col = mix(col, sunCol, sunBody);
567
567
  } else {
568
- // --- FLOOR --- perspective grid. Guard the divide; shade only below horizon.
569
- float depth = 1.0 / max(h - fy, 1.5e-3); // large near the horizon
570
- float depthMin = 1.0 / h; // depth at the very front (fy = 0)
571
-
572
- // Grid coordinates: x widens with depth (perspective); uGridDensity sets the
573
- // cell count; the scroll is in cell units so its rate is density-independent.
574
- vec2 g = vec2(fx * depth, depth) * uGridDensity;
575
- g.y += uTime * uSpeed * 2.0;
576
- vec2 cell = abs(fract(g) - 0.5); // 0 on a line .. 0.5 mid-cell, per axis
577
-
578
- // Per-axis, depth-scaled line half-width: the rungs (g.y) compress toward the
579
- // horizon as depth^2 and the verticals (g.x) ~linearly, so widening each axis'
580
- // line band at its own compression rate holds the on-screen line width roughly
581
- // constant. Far lines fuse into a band instead of a sub-pixel sheet that
582
- // shimmers as it scrolls; near lines stay crisp. Written 1 - smoothstep(0, w, .)
583
- // (NOT the reversed-edge smoothstep(w, 0, .), which is undefined on GLSL ES /
584
- // Metal) and derivative-free, so it is portable and mobile-precision safe.
585
- vec2 w = max(vec2(depth, depth * depth * 0.2) * uGridDensity * 0.0013, vec2(1e-4));
586
- vec2 core = 1.0 - smoothstep(vec2(0.0), w, cell);
587
- vec2 halo = (1.0 - smoothstep(vec2(0.0), w * 6.0, cell)) * (0.5 * uGridGlow);
588
- float gridVal = clamp(core.x + core.y + halo.x + halo.y, 0.0, 1.5);
589
-
590
- // Distance fog: fade the grid out toward the horizon for the converging look.
591
- float fog = clamp(1.0 - (depth - depthMin) / (depthMin * 10.0), 0.0, 1.0);
592
- fog *= fog;
593
-
594
- vec3 floorBase = mix(vec3(0.0), uSkyHorizon * 0.16, fog * 0.6);
595
- col = floorBase + uGridColor * gridVal * fog * calm;
568
+ // --- FLOOR --- perspective grid, a faithful port of a known-good community
569
+ // outrun grid (prior versions read as a too-dense, flickering sheet). Work in
570
+ // the reference's centered frame: cx is full-width centered x, dy is the
571
+ // centered distance BELOW the horizon. The additive offset caps the depth at
572
+ // the horizon, and putting big cells in the near field (low min depth) is what
573
+ // keeps the line spacing above a pixel, so it neither sheets nor shimmers.
574
+ float cx = 2.0 * fx; // = (2*vUv.x - 1) * aspect
575
+ float dy = 2.0 * (h - fy); // centered distance below the horizon (> 0)
576
+
577
+ // Cell count: uGridDensity 4 -> numerator 1.0 (sparse, big near cells). x
578
+ // widens with depth (the 0.7 factor); scroll is a slow drift toward the viewer.
579
+ float num = uGridDensity * 0.25;
580
+ float depth = num / (dy + 0.05);
581
+ vec2 g = vec2(cx * depth * 0.7, depth);
582
+ g.y += uTime * uSpeed * 0.3;
583
+ vec2 e = abs(fract(g) - 0.5);
584
+
585
+ // PIXEL-CALIBRATED line width: each line core is a fixed ~px wide in SCREEN
586
+ // PIXELS (via uResolution), the same at every depth and every resolution. The
587
+ // old depth^2*const width was constant in theory but landed sub-pixel, so
588
+ // discrete sampling rendered some rungs thick and others thin -> the uneven
589
+ // rungs that read as flicker. Solving sz so screen thickness == px: the rungs
590
+ // (g.y, compression ~depth^2/num) need sz.y = depth^2 * pf / num; the verticals
591
+ // (g.x) need sz.x = depth * 0.7 * pf. uGridGlow sets px (0.5 -> 2 px).
592
+ float pf = (uGridGlow * 4.0) / uResolution.y;
593
+ vec2 sz = vec2(depth * 0.7 * pf, depth * depth * pf / num);
594
+ vec2 lines = 1.0 - smoothstep(vec2(0.0), sz, e);
595
+ lines += (1.0 - smoothstep(vec2(0.0), sz * 4.0, e)) * 0.5;
596
+ float gridVal = clamp(lines.x + lines.y, 0.0, 1.0);
597
+
598
+ vec3 floorBase = uSkyHorizon * 0.06;
599
+ col = mix(floorBase, uGridColor, gridVal * calm);
596
600
  }
597
601
 
598
602
  // Glowing horizon seam where floor meets sky.
@@ -740,9 +744,11 @@ const float MIN_DIVIDE = 64.0;
740
744
  const float MAX_DIVIDE = 0.01;
741
745
  // Number of stacked starfield layers. Compile-time constant so the layer
742
746
  // loop has a fixed integer bound (cross-compile-safe; no float loop counter).
743
- // 8 (was 12) for low-end-mobile cost (issue #39); the work is linear in the
744
- // count and dimByDensity rebalances per-star brightness automatically.
745
- const int STARFIELD_LAYERS_COUNT = 8;
747
+ // 7 (was 8 #74, was 12 #39) for cost; the work is linear in the count and
748
+ // dimByDensity rebalances per-star brightness automatically. 7 keeps the dense
749
+ // look essentially intact (6 was visibly sparser at some animation phases);
750
+ // paired with the empty-cell early-out below it lands ~34% under the old 8.
751
+ const int STARFIELD_LAYERS_COUNT = 7;
746
752
 
747
753
  mat2 Rotate(float angle) {
748
754
  float s = sin(angle);
@@ -810,6 +816,12 @@ vec3 StarFieldLayer(vec2 uv, float rotAngle) {
810
816
  float size = fract(randomN * 1356.33);
811
817
  float flareSwitch = smoothstep(0.9, 1.0, size);
812
818
  float star = Star(randomPosition, flareSwitch, rotAngle, randomN);
819
+ // The per-cell color below is multiplied by `star` at the end, so for any
820
+ // cell whose star is 0 (Star() returns exactly 0 for d >= 1.0, i.e. the
821
+ // empty-sky majority of the 8x9 = 72 cells/pixel) the whole term is 0.
822
+ // Skipping the sin(vec3) color work for those cells is output-identical and
823
+ // is the bulk of the win (issue #74).
824
+ if (star <= 0.0) continue;
813
825
 
814
826
  // fract trick: random colors
815
827
  float randomStarColorSeed = fract(randomN * 2150.0) * (3.0 * PI) * deltaTimeTwinkle;
@@ -1678,6 +1690,167 @@ void main() {
1678
1690
  // Premultiplied output; tint grades the (premultiplied) color, not alpha.
1679
1691
  oColor = vec4(blobCol * uColor, blobAlpha);
1680
1692
  }
1693
+ """
1694
+
1695
+ const val DATA_MESH_FRAG = """#version 300 es
1696
+ precision highp float;
1697
+
1698
+ uniform float uTime; // seconds, monotonically increasing; range [0, inf)
1699
+ uniform vec2 uResolution; // framebuffer size in pixels; both components > 0
1700
+ uniform vec3 uBgTop; // background gradient color at the top of frame
1701
+ uniform vec3 uBgBottom; // background gradient color at the bottom of frame
1702
+ uniform vec3 uLineColor; // mid wireframe-line tint (the trough/body color)
1703
+ uniform vec3 uCrestColor; // crest highlight color (brightest along the peaks)
1704
+ uniform vec3 uHazeColor; // atmospheric haze tint on the far rows
1705
+ uniform vec3 uAccentColor; // the one restrained accent (e.g. enterprise red)
1706
+ uniform float uWaveScale; // wave-field spatial frequency; lower = looser, broader hills
1707
+ uniform float uWaveAmp; // vertical wave displacement amount (near rows)
1708
+ uniform float uWaveSpeed; // animation rate; 0 freezes the surface
1709
+ uniform float uGridX; // column-grid density across the surface; keep loose
1710
+ uniform float uHorizon; // horizon height in uv.y units (rows converge toward it)
1711
+ uniform float uFarScale; // perspective scale of the farthest row, 0.05..0.5 (>0)
1712
+ uniform float uSlant; // diagonal tilt; raises the right side for corner composition
1713
+ uniform float uLineWidth; // wireframe line half-width (smaller = finer, sharper)
1714
+ uniform float uNodeMix; // 0..1 emphasis of glowing intersection nodes (dot reading)
1715
+ uniform float uStrutMix; // 0..1 emphasis of vertical struts (wireframe reading)
1716
+ uniform float uGlow; // overall additive mesh-glow / bloom strength
1717
+ uniform float uHaze; // atmospheric far-haze strength
1718
+ uniform float uParticles; // floating-particle intensity; 0 disables the field
1719
+ uniform float uAccent; // lone accent-mote intensity; 0 disables it
1720
+ uniform float uCalm; // 0..1 eases the additive glow at frame center (face zone)
1721
+
1722
+ in highp vec2 vUv;
1723
+ out vec4 oColor;
1724
+
1725
+ // ROWS / PARTICLES must stay compile-time constants (GLSL ES loop bounds). ROWS is
1726
+ // kept modest on purpose (loose mesh); perspective bunching toward the horizon
1727
+ // makes it read as far more lines than it costs.
1728
+ #define ROWS 18
1729
+ #define PARTICLES 10
1730
+ #define WAVE_DEPTH_SPAN 4.5 // world-depth the eased row range maps across
1731
+ #define COL_SHARP 48.0 // column-stripe sharpness in cell-phase units
1732
+ #define Y_NEAR (-0.62) // nearest row baseline (just below the bottom edge)
1733
+
1734
+ // Cheap stable hash for the particle field (highp; the 43758.5453 multiplier
1735
+ // bands under mediump, same note as clouds/nebula).
1736
+ float hash11(float n) {
1737
+ return fract(sin(n * 12.9898) * 43758.5453123);
1738
+ }
1739
+
1740
+ // The shared surface. x is perspective world-x, z is eased world-depth, t is time.
1741
+ // A small sum of sines whose x/z cross terms produce the hills, valleys, and
1742
+ // saddles; bounded to roughly [-1.6, 1.6].
1743
+ float waveField(float x, float z, float t) {
1744
+ float h = 0.0;
1745
+ h += sin(x * 1.00 + z * 0.55 + t) * 0.60;
1746
+ h += sin(x * 0.55 - z * 0.95 - t * 0.70) * 0.45;
1747
+ h += sin((x + z) * 0.45 + t * 0.40 + 1.7) * 0.40; // diagonal ridges -> saddles
1748
+ h += sin(x * 1.70 - z * 0.30 + t * 1.20) * 0.16; // fine ripple
1749
+ return h;
1750
+ }
1751
+
1752
+ void main() {
1753
+ vec2 fragCoord = vUv * uResolution;
1754
+ vec2 uv = (fragCoord - 0.5 * uResolution) / uResolution.y; // centered, aspect-correct
1755
+
1756
+ // Background: smooth vertical gradient, no texture. g = 0 bottom .. 1 top.
1757
+ float g = clamp(uv.y + 0.5, 0.0, 1.0);
1758
+ vec3 col = mix(uBgBottom, uBgTop, g);
1759
+
1760
+ // Ease additive glow near the frame center (the subject's face sits there).
1761
+ float calm = 1.0 - uCalm * (1.0 - smoothstep(0.18, 0.62, length(uv)));
1762
+
1763
+ float t = uTime * uWaveSpeed;
1764
+ float horizon = clamp(uHorizon, -0.2, 0.45);
1765
+
1766
+ // Line-glow widths from the half-width. The core line keeps the one exp() (its
1767
+ // sharp gaussian is the wireframe signature); the bloom halo and the vertical
1768
+ // strut use rational falloffs (1/(1+k·dy^2)) instead of more exp() calls, which
1769
+ // are ~8x-weighted transcendentals on the hot per-row path. The node reuses the
1770
+ // core exp directly. Net: 2 exp/row (core + column), down from 5.
1771
+ float coreSharp = 1.0 / max(uLineWidth * uLineWidth, 1e-5);
1772
+ float haloK = coreSharp * 0.14; // rational-bloom width (matches the old halo half-width)
1773
+ float strutK = coreSharp * 0.14; // rational vertical-bridge width
1774
+
1775
+ vec3 mesh = vec3(0.0);
1776
+ vec3 haze = vec3(0.0);
1777
+
1778
+ for (int i = 0; i < ROWS; i++) {
1779
+ float rowT = float(i) / float(ROWS - 1); // 0 near .. 1 far
1780
+ float om = 1.0 - rowT;
1781
+ float f = 1.0 - om * om; // eased depth: rows bunch toward horizon
1782
+ float persp = mix(1.0, uFarScale, f);
1783
+ persp = max(persp, uFarScale); // guard the divide (uFarScale > 0)
1784
+
1785
+ // Row baseline in screen-y, with a diagonal tilt for corner composition.
1786
+ float baseY = mix(Y_NEAR, horizon, f) + uv.x * uSlant * persp;
1787
+
1788
+ // Early-out: skip the sines for any row that cannot reach this pixel. Margin
1789
+ // covers the max wave displacement plus the strut's vertical bridge.
1790
+ float reach = persp * uWaveAmp * 1.7 + uLineWidth * 3.0 + 0.06;
1791
+ if (abs(uv.y - baseY) > reach) continue;
1792
+
1793
+ float worldX = uv.x / persp;
1794
+ float h = waveField(worldX * uWaveScale, f * WAVE_DEPTH_SPAN, t);
1795
+ float surfY = baseY + persp * uWaveAmp * h;
1796
+ float dy = uv.y - surfY;
1797
+
1798
+ // Crest factor: peaks of the field glow white, troughs stay the line tint.
1799
+ float crest = smoothstep(0.2, 1.4, h);
1800
+
1801
+ // Horizontal ribbon: sharp gaussian core (the line) + rational bloom halo.
1802
+ float dy2 = dy * dy;
1803
+ float core = exp(-dy2 * coreSharp);
1804
+ float ribbon = core + 0.22 / (1.0 + dy2 * haloK);
1805
+
1806
+ // Column grid: one bright stripe per cell of worldX. cph = 0 at the stripe.
1807
+ float cph = fract(worldX * uGridX) - 0.5;
1808
+ float colLine = exp(-cph * cph * COL_SHARP);
1809
+
1810
+ // Vertical strut (rational falloff in y so it bridges toward neighbors, gated
1811
+ // by the column) and the intersection node (core line x column -> a glowing
1812
+ // dot; reuses the core exp, no extra transcendental).
1813
+ float strut = colLine / (1.0 + dy2 * strutK);
1814
+ float node = core * colLine;
1815
+
1816
+ // Atmospheric fade: far rows dim and tint toward the haze color.
1817
+ float fade = om * om; // 1 near .. 0 far
1818
+ float lit = ribbon + uStrutMix * strut + uNodeMix * node * 2.0;
1819
+ vec3 lineCol = mix(uLineColor, uCrestColor, crest);
1820
+
1821
+ // Crest-dominant brightness: troughs stay dim, peaks carry the illumination.
1822
+ mesh += lineCol * lit * fade * (0.35 + 1.0 * crest);
1823
+ haze += uHazeColor * ribbon * (1.0 - fade) * crest;
1824
+ }
1825
+
1826
+ col += mesh * uGlow * calm;
1827
+ col += haze * uHaze * calm;
1828
+
1829
+ // Sparse floating particles; index 0 is the lone accent mote (independent of
1830
+ // uParticles so an accent can show with the particle field off).
1831
+ if (uParticles > 0.0 || uAccent > 0.0) {
1832
+ vec3 motes = vec3(0.0);
1833
+ for (int p = 0; p < PARTICLES; p++) {
1834
+ float fp = float(p);
1835
+ vec2 seed = vec2(hash11(fp * 1.7 + 0.3), hash11(fp * 3.1 + 1.9));
1836
+ vec2 ppos = (seed * 2.0 - 1.0) * vec2(0.92, 0.46);
1837
+ ppos.x += sin(uTime * 0.07 + fp * 2.3) * 0.03;
1838
+ ppos.y += cos(uTime * 0.05 + fp * 1.7) * 0.03;
1839
+ float twinkle = 0.5 + 0.5 * sin(uTime * (0.6 + hash11(fp * 5.0)) + fp * 4.0);
1840
+ float pd = length(uv - ppos);
1841
+ float glint = exp(-pd * pd * 2300.0) * twinkle;
1842
+ vec3 pcol = (p == 0) ? uAccentColor * uAccent : uCrestColor * uParticles;
1843
+ motes += pcol * glint;
1844
+ }
1845
+ col += motes * calm;
1846
+ }
1847
+
1848
+ // Soft highlight rolloff: fold the additive foreground pile-up into clean white
1849
+ // crests instead of a clipped slab; leaves the dark gradient essentially intact.
1850
+ col = vec3(1.0) - exp(-col);
1851
+
1852
+ oColor = vec4(col, 1.0);
1853
+ }
1681
1854
  """
1682
1855
 
1683
1856
  // Generative background shaders, by name. The generic shader processor and
@@ -1698,5 +1871,6 @@ void main() {
1698
1871
  "anamorphic-lensflare" to ANAMORPHIC_LENSFLARE_FRAG,
1699
1872
  "light-beams-and-motes" to LIGHT_BEAMS_AND_MOTES_FRAG,
1700
1873
  "corporate-blobs" to CORPORATE_BLOBS_FRAG,
1874
+ "data-mesh" to DATA_MESH_FRAG,
1701
1875
  )
1702
1876
  }
@@ -0,0 +1,53 @@
1
+ // Data-mesh's editor form: the shader OWNS its control layout. One
2
+ // <Control uniform="…"/> per uniform; grouped into palette / surface / glow
3
+ // sections so the big color levers, the structural dials, and the additive extras
4
+ // read as three clusters. A new primitive flows in through <Control> without
5
+ // touching this file. Conventional layer id: "mesh".
6
+
7
+ import {
8
+ Control,
9
+ ControlForm,
10
+ ControlSection,
11
+ type KaleidoscopeControls,
12
+ } from '../../../src/components/preset-control-panel';
13
+ import { DATA_MESH_CONTROLS } from './data-mesh';
14
+
15
+ export function DataMeshForm({ uniforms, onPatch, disabled }: KaleidoscopeControls) {
16
+ return (
17
+ <ControlForm
18
+ id="mesh"
19
+ uniforms={uniforms.mesh ?? {}}
20
+ onPatch={onPatch}
21
+ disabled={disabled}
22
+ controls={DATA_MESH_CONTROLS}
23
+ >
24
+ <ControlSection title="palette">
25
+ <Control uniform="uBgTop" />
26
+ <Control uniform="uBgBottom" />
27
+ <Control uniform="uLineColor" />
28
+ <Control uniform="uCrestColor" />
29
+ <Control uniform="uHazeColor" />
30
+ <Control uniform="uAccentColor" />
31
+ </ControlSection>
32
+ <ControlSection title="surface">
33
+ <Control uniform="uWaveScale" />
34
+ <Control uniform="uWaveAmp" />
35
+ <Control uniform="uWaveSpeed" />
36
+ <Control uniform="uGridX" />
37
+ <Control uniform="uHorizon" />
38
+ <Control uniform="uFarScale" />
39
+ <Control uniform="uSlant" />
40
+ <Control uniform="uLineWidth" />
41
+ <Control uniform="uNodeMix" />
42
+ <Control uniform="uStrutMix" />
43
+ </ControlSection>
44
+ <ControlSection title="glow">
45
+ <Control uniform="uGlow" />
46
+ <Control uniform="uHaze" />
47
+ <Control uniform="uParticles" />
48
+ <Control uniform="uAccent" />
49
+ <Control uniform="uCalm" />
50
+ </ControlSection>
51
+ </ControlForm>
52
+ );
53
+ }
@@ -0,0 +1,205 @@
1
+ // Data-mesh: a mid-2000s corporate digital-futurism background. A large smooth
2
+ // three-dimensional wave surface drawn as a fine wireframe of perspective rows,
3
+ // with glowing nodes at the grid intersections, bent into broad hills, valleys,
4
+ // and saddle curves and receding into deep virtual space. Electric crest glow,
5
+ // soft turquoise bloom, faint atmospheric haze on the far rows, and a sparse
6
+ // drift of particles (one of which is the lone accent mote). Enterprise box-art
7
+ // and OEM-wallpaper idiom (Microsoft / Dell / SQL Server / Alienware era), clean
8
+ // negative space for a logo. An opaque BACKGROUND layer; the masked subject
9
+ // composites over it downstream.
10
+ //
11
+ // Technique (performance-first): NO raymarch, NO fbm, NO variable-exponent pow.
12
+ // The surface is a stack of ROWS perspective-spaced ridgelines. Every row samples
13
+ // ONE shared 2D wave field H(worldX, depth, time), so adjacent rows are continuous
14
+ // and read as a single coherent surface rather than independent lines. A row's
15
+ // screen height is its perspective baseline plus H scaled by that row's
16
+ // perspective factor. Per pixel the bounded ROWS loop accumulates an analytic
17
+ // ribbon + strut + node glow; an early-out skips any row whose baseline is outside
18
+ // this pixel's vertical reach BEFORE the sines run, so most rows cost a compare.
19
+ // Keep the mesh loose: ROWS and uGridX are deliberately modest, not hi-def.
20
+ //
21
+ // Overdrive surface: the color set is the mood (uBgTop/uBgBottom gradient,
22
+ // uLineColor mid tint, uCrestColor peak highlight, uHazeColor far atmosphere,
23
+ // uAccentColor the one restrained accent). Structural dials (uWaveScale/Amp/Speed,
24
+ // uGridX, uHorizon, uFarScale, uSlant) set composition and motion; uNodeMix /
25
+ // uStrutMix grade the lines-vs-dots reading; uGlow / uHaze / uParticles / uAccent
26
+ // set the additive extras. uCalm eases the additive glow near frame center, where
27
+ // the masked subject's face sits.
28
+ //
29
+ // UV convention: matches passthrough.vert. vUv = (0, 0) bottom-left, (1, 1)
30
+ // top-right; fragCoord is reconstructed as vUv * uResolution and the centered,
31
+ // aspect-correct uv divides by height. Fully procedural: no input texture, no
32
+ // gl_FragCoord, so net texture flips are zero on every runtime (web/Android/Metal
33
+ // alike).
34
+ //
35
+ // Cross-target correctness: the only divide is worldX = uv.x / persp, and persp is
36
+ // clamped to max(persp, uFarScale) with uFarScale >= 0.05, so it never approaches
37
+ // zero (no Inf/NaN, no highp-vs-mediump divergence at a vanishing line). No fwidth
38
+ // or derivatives (depth fade and haze are analytic, not screen-space). No
39
+ // variable-exponent pow, no atan, no gl_FragCoord, no arrays, no extensions. ROWS
40
+ // and PARTICLES stay compile-time constants (GLSL ES loop bounds); the dynamic
41
+ // continue/break inside are uniform-flow and survive the SPIR-V -> MSL step.
42
+ //
43
+ // Precision: highp float throughout. worldX grows up to ~0.9 / uFarScale and feeds
44
+ // fract() for the column grid, so the field needs the range and the front-to-far
45
+ // dynamic range; mediump would band the gradient and alias the far columns.
46
+
47
+ #version 300 es
48
+ precision highp float;
49
+
50
+ uniform float uTime; // seconds, monotonically increasing; range [0, inf)
51
+ uniform vec2 uResolution; // framebuffer size in pixels; both components > 0
52
+ uniform vec3 uBgTop; // background gradient color at the top of frame
53
+ uniform vec3 uBgBottom; // background gradient color at the bottom of frame
54
+ uniform vec3 uLineColor; // mid wireframe-line tint (the trough/body color)
55
+ uniform vec3 uCrestColor; // crest highlight color (brightest along the peaks)
56
+ uniform vec3 uHazeColor; // atmospheric haze tint on the far rows
57
+ uniform vec3 uAccentColor; // the one restrained accent (e.g. enterprise red)
58
+ uniform float uWaveScale; // wave-field spatial frequency; lower = looser, broader hills
59
+ uniform float uWaveAmp; // vertical wave displacement amount (near rows)
60
+ uniform float uWaveSpeed; // animation rate; 0 freezes the surface
61
+ uniform float uGridX; // column-grid density across the surface; keep loose
62
+ uniform float uHorizon; // horizon height in uv.y units (rows converge toward it)
63
+ uniform float uFarScale; // perspective scale of the farthest row, 0.05..0.5 (>0)
64
+ uniform float uSlant; // diagonal tilt; raises the right side for corner composition
65
+ uniform float uLineWidth; // wireframe line half-width (smaller = finer, sharper)
66
+ uniform float uNodeMix; // 0..1 emphasis of glowing intersection nodes (dot reading)
67
+ uniform float uStrutMix; // 0..1 emphasis of vertical struts (wireframe reading)
68
+ uniform float uGlow; // overall additive mesh-glow / bloom strength
69
+ uniform float uHaze; // atmospheric far-haze strength
70
+ uniform float uParticles; // floating-particle intensity; 0 disables the field
71
+ uniform float uAccent; // lone accent-mote intensity; 0 disables it
72
+ uniform float uCalm; // 0..1 eases the additive glow at frame center (face zone)
73
+
74
+ in highp vec2 vUv;
75
+ out vec4 oColor;
76
+
77
+ // ROWS / PARTICLES must stay compile-time constants (GLSL ES loop bounds). ROWS is
78
+ // kept modest on purpose (loose mesh); perspective bunching toward the horizon
79
+ // makes it read as far more lines than it costs.
80
+ #define ROWS 18
81
+ #define PARTICLES 10
82
+ #define WAVE_DEPTH_SPAN 4.5 // world-depth the eased row range maps across
83
+ #define COL_SHARP 48.0 // column-stripe sharpness in cell-phase units
84
+ #define Y_NEAR (-0.62) // nearest row baseline (just below the bottom edge)
85
+
86
+ // Cheap stable hash for the particle field (highp; the 43758.5453 multiplier
87
+ // bands under mediump, same note as clouds/nebula).
88
+ float hash11(float n) {
89
+ return fract(sin(n * 12.9898) * 43758.5453123);
90
+ }
91
+
92
+ // The shared surface. x is perspective world-x, z is eased world-depth, t is time.
93
+ // A small sum of sines whose x/z cross terms produce the hills, valleys, and
94
+ // saddles; bounded to roughly [-1.6, 1.6].
95
+ float waveField(float x, float z, float t) {
96
+ float h = 0.0;
97
+ h += sin(x * 1.00 + z * 0.55 + t) * 0.60;
98
+ h += sin(x * 0.55 - z * 0.95 - t * 0.70) * 0.45;
99
+ h += sin((x + z) * 0.45 + t * 0.40 + 1.7) * 0.40; // diagonal ridges -> saddles
100
+ h += sin(x * 1.70 - z * 0.30 + t * 1.20) * 0.16; // fine ripple
101
+ return h;
102
+ }
103
+
104
+ void main() {
105
+ vec2 fragCoord = vUv * uResolution;
106
+ vec2 uv = (fragCoord - 0.5 * uResolution) / uResolution.y; // centered, aspect-correct
107
+
108
+ // Background: smooth vertical gradient, no texture. g = 0 bottom .. 1 top.
109
+ float g = clamp(uv.y + 0.5, 0.0, 1.0);
110
+ vec3 col = mix(uBgBottom, uBgTop, g);
111
+
112
+ // Ease additive glow near the frame center (the subject's face sits there).
113
+ float calm = 1.0 - uCalm * (1.0 - smoothstep(0.18, 0.62, length(uv)));
114
+
115
+ float t = uTime * uWaveSpeed;
116
+ float horizon = clamp(uHorizon, -0.2, 0.45);
117
+
118
+ // Line-glow widths from the half-width. The core line keeps the one exp() (its
119
+ // sharp gaussian is the wireframe signature); the bloom halo and the vertical
120
+ // strut use rational falloffs (1/(1+k·dy^2)) instead of more exp() calls, which
121
+ // are ~8x-weighted transcendentals on the hot per-row path. The node reuses the
122
+ // core exp directly. Net: 2 exp/row (core + column), down from 5.
123
+ float coreSharp = 1.0 / max(uLineWidth * uLineWidth, 1e-5);
124
+ float haloK = coreSharp * 0.14; // rational-bloom width (matches the old halo half-width)
125
+ float strutK = coreSharp * 0.14; // rational vertical-bridge width
126
+
127
+ vec3 mesh = vec3(0.0);
128
+ vec3 haze = vec3(0.0);
129
+
130
+ for (int i = 0; i < ROWS; i++) {
131
+ float rowT = float(i) / float(ROWS - 1); // 0 near .. 1 far
132
+ float om = 1.0 - rowT;
133
+ float f = 1.0 - om * om; // eased depth: rows bunch toward horizon
134
+ float persp = mix(1.0, uFarScale, f);
135
+ persp = max(persp, uFarScale); // guard the divide (uFarScale > 0)
136
+
137
+ // Row baseline in screen-y, with a diagonal tilt for corner composition.
138
+ float baseY = mix(Y_NEAR, horizon, f) + uv.x * uSlant * persp;
139
+
140
+ // Early-out: skip the sines for any row that cannot reach this pixel. Margin
141
+ // covers the max wave displacement plus the strut's vertical bridge.
142
+ float reach = persp * uWaveAmp * 1.7 + uLineWidth * 3.0 + 0.06;
143
+ if (abs(uv.y - baseY) > reach) continue;
144
+
145
+ float worldX = uv.x / persp;
146
+ float h = waveField(worldX * uWaveScale, f * WAVE_DEPTH_SPAN, t);
147
+ float surfY = baseY + persp * uWaveAmp * h;
148
+ float dy = uv.y - surfY;
149
+
150
+ // Crest factor: peaks of the field glow white, troughs stay the line tint.
151
+ float crest = smoothstep(0.2, 1.4, h);
152
+
153
+ // Horizontal ribbon: sharp gaussian core (the line) + rational bloom halo.
154
+ float dy2 = dy * dy;
155
+ float core = exp(-dy2 * coreSharp);
156
+ float ribbon = core + 0.22 / (1.0 + dy2 * haloK);
157
+
158
+ // Column grid: one bright stripe per cell of worldX. cph = 0 at the stripe.
159
+ float cph = fract(worldX * uGridX) - 0.5;
160
+ float colLine = exp(-cph * cph * COL_SHARP);
161
+
162
+ // Vertical strut (rational falloff in y so it bridges toward neighbors, gated
163
+ // by the column) and the intersection node (core line x column -> a glowing
164
+ // dot; reuses the core exp, no extra transcendental).
165
+ float strut = colLine / (1.0 + dy2 * strutK);
166
+ float node = core * colLine;
167
+
168
+ // Atmospheric fade: far rows dim and tint toward the haze color.
169
+ float fade = om * om; // 1 near .. 0 far
170
+ float lit = ribbon + uStrutMix * strut + uNodeMix * node * 2.0;
171
+ vec3 lineCol = mix(uLineColor, uCrestColor, crest);
172
+
173
+ // Crest-dominant brightness: troughs stay dim, peaks carry the illumination.
174
+ mesh += lineCol * lit * fade * (0.35 + 1.0 * crest);
175
+ haze += uHazeColor * ribbon * (1.0 - fade) * crest;
176
+ }
177
+
178
+ col += mesh * uGlow * calm;
179
+ col += haze * uHaze * calm;
180
+
181
+ // Sparse floating particles; index 0 is the lone accent mote (independent of
182
+ // uParticles so an accent can show with the particle field off).
183
+ if (uParticles > 0.0 || uAccent > 0.0) {
184
+ vec3 motes = vec3(0.0);
185
+ for (int p = 0; p < PARTICLES; p++) {
186
+ float fp = float(p);
187
+ vec2 seed = vec2(hash11(fp * 1.7 + 0.3), hash11(fp * 3.1 + 1.9));
188
+ vec2 ppos = (seed * 2.0 - 1.0) * vec2(0.92, 0.46);
189
+ ppos.x += sin(uTime * 0.07 + fp * 2.3) * 0.03;
190
+ ppos.y += cos(uTime * 0.05 + fp * 1.7) * 0.03;
191
+ float twinkle = 0.5 + 0.5 * sin(uTime * (0.6 + hash11(fp * 5.0)) + fp * 4.0);
192
+ float pd = length(uv - ppos);
193
+ float glint = exp(-pd * pd * 2300.0) * twinkle;
194
+ vec3 pcol = (p == 0) ? uAccentColor * uAccent : uCrestColor * uParticles;
195
+ motes += pcol * glint;
196
+ }
197
+ col += motes * calm;
198
+ }
199
+
200
+ // Soft highlight rolloff: fold the additive foreground pile-up into clean white
201
+ // crests instead of a clipped slab; leaves the dark gradient essentially intact.
202
+ col = vec3(1.0) - exp(-col);
203
+
204
+ oColor = vec4(col, 1.0);
205
+ }