react-native-webrtc-kaleidoscope 2.6.0 → 2.7.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 (33) hide show
  1. package/android/src/main/java/com/simiancraft/kaleidoscope/gpu/ShadersGenerated.kt +173 -3
  2. package/catalog/composites/clouds/clouds.ts +5 -5
  3. package/catalog/composites/nebula/nebula.thumb.webp +0 -0
  4. package/catalog/shaders/data-mesh/data-mesh.form.tsx +53 -0
  5. package/catalog/shaders/data-mesh/data-mesh.frag +205 -0
  6. package/catalog/shaders/data-mesh/data-mesh.ts +225 -0
  7. package/catalog/shaders/index.ts +4 -0
  8. package/catalog/shaders/nebula/nebula.frag +11 -3
  9. package/dist/catalog/composites/clouds/clouds.d.ts +5 -5
  10. package/dist/catalog/composites/clouds/clouds.js +5 -5
  11. package/dist/catalog/composites/clouds/clouds.js.map +1 -1
  12. package/dist/catalog/composites/nebula/nebula.thumb.webp +0 -0
  13. package/dist/catalog/shaders/data-mesh/data-mesh.d.ts +50 -0
  14. package/dist/catalog/shaders/data-mesh/data-mesh.d.ts.map +1 -0
  15. package/dist/catalog/shaders/data-mesh/data-mesh.form.d.ts +3 -0
  16. package/dist/catalog/shaders/data-mesh/data-mesh.form.d.ts.map +1 -0
  17. package/dist/catalog/shaders/data-mesh/data-mesh.form.js +15 -0
  18. package/dist/catalog/shaders/data-mesh/data-mesh.form.js.map +1 -0
  19. package/dist/catalog/shaders/data-mesh/data-mesh.js +179 -0
  20. package/dist/catalog/shaders/data-mesh/data-mesh.js.map +1 -0
  21. package/dist/catalog/shaders/index.d.ts +4 -0
  22. package/dist/catalog/shaders/index.d.ts.map +1 -1
  23. package/dist/catalog/shaders/index.js +3 -1
  24. package/dist/catalog/shaders/index.js.map +1 -1
  25. package/dist/web-driver/shaders.generated.d.ts +2 -1
  26. package/dist/web-driver/shaders.generated.d.ts.map +1 -1
  27. package/dist/web-driver/shaders.generated.js +173 -4
  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/package.json +8 -1
@@ -740,9 +740,11 @@ const float MIN_DIVIDE = 64.0;
740
740
  const float MAX_DIVIDE = 0.01;
741
741
  // Number of stacked starfield layers. Compile-time constant so the layer
742
742
  // 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;
743
+ // 7 (was 8 #74, was 12 #39) for cost; the work is linear in the count and
744
+ // dimByDensity rebalances per-star brightness automatically. 7 keeps the dense
745
+ // look essentially intact (6 was visibly sparser at some animation phases);
746
+ // paired with the empty-cell early-out below it lands ~34% under the old 8.
747
+ const int STARFIELD_LAYERS_COUNT = 7;
746
748
 
747
749
  mat2 Rotate(float angle) {
748
750
  float s = sin(angle);
@@ -810,6 +812,12 @@ vec3 StarFieldLayer(vec2 uv, float rotAngle) {
810
812
  float size = fract(randomN * 1356.33);
811
813
  float flareSwitch = smoothstep(0.9, 1.0, size);
812
814
  float star = Star(randomPosition, flareSwitch, rotAngle, randomN);
815
+ // The per-cell color below is multiplied by `star` at the end, so for any
816
+ // cell whose star is 0 (Star() returns exactly 0 for d >= 1.0, i.e. the
817
+ // empty-sky majority of the 8x9 = 72 cells/pixel) the whole term is 0.
818
+ // Skipping the sin(vec3) color work for those cells is output-identical and
819
+ // is the bulk of the win (issue #74).
820
+ if (star <= 0.0) continue;
813
821
 
814
822
  // fract trick: random colors
815
823
  float randomStarColorSeed = fract(randomN * 2150.0) * (3.0 * PI) * deltaTimeTwinkle;
@@ -1678,6 +1686,167 @@ void main() {
1678
1686
  // Premultiplied output; tint grades the (premultiplied) color, not alpha.
1679
1687
  oColor = vec4(blobCol * uColor, blobAlpha);
1680
1688
  }
1689
+ """
1690
+
1691
+ const val DATA_MESH_FRAG = """#version 300 es
1692
+ precision highp float;
1693
+
1694
+ uniform float uTime; // seconds, monotonically increasing; range [0, inf)
1695
+ uniform vec2 uResolution; // framebuffer size in pixels; both components > 0
1696
+ uniform vec3 uBgTop; // background gradient color at the top of frame
1697
+ uniform vec3 uBgBottom; // background gradient color at the bottom of frame
1698
+ uniform vec3 uLineColor; // mid wireframe-line tint (the trough/body color)
1699
+ uniform vec3 uCrestColor; // crest highlight color (brightest along the peaks)
1700
+ uniform vec3 uHazeColor; // atmospheric haze tint on the far rows
1701
+ uniform vec3 uAccentColor; // the one restrained accent (e.g. enterprise red)
1702
+ uniform float uWaveScale; // wave-field spatial frequency; lower = looser, broader hills
1703
+ uniform float uWaveAmp; // vertical wave displacement amount (near rows)
1704
+ uniform float uWaveSpeed; // animation rate; 0 freezes the surface
1705
+ uniform float uGridX; // column-grid density across the surface; keep loose
1706
+ uniform float uHorizon; // horizon height in uv.y units (rows converge toward it)
1707
+ uniform float uFarScale; // perspective scale of the farthest row, 0.05..0.5 (>0)
1708
+ uniform float uSlant; // diagonal tilt; raises the right side for corner composition
1709
+ uniform float uLineWidth; // wireframe line half-width (smaller = finer, sharper)
1710
+ uniform float uNodeMix; // 0..1 emphasis of glowing intersection nodes (dot reading)
1711
+ uniform float uStrutMix; // 0..1 emphasis of vertical struts (wireframe reading)
1712
+ uniform float uGlow; // overall additive mesh-glow / bloom strength
1713
+ uniform float uHaze; // atmospheric far-haze strength
1714
+ uniform float uParticles; // floating-particle intensity; 0 disables the field
1715
+ uniform float uAccent; // lone accent-mote intensity; 0 disables it
1716
+ uniform float uCalm; // 0..1 eases the additive glow at frame center (face zone)
1717
+
1718
+ in highp vec2 vUv;
1719
+ out vec4 oColor;
1720
+
1721
+ // ROWS / PARTICLES must stay compile-time constants (GLSL ES loop bounds). ROWS is
1722
+ // kept modest on purpose (loose mesh); perspective bunching toward the horizon
1723
+ // makes it read as far more lines than it costs.
1724
+ #define ROWS 18
1725
+ #define PARTICLES 10
1726
+ #define WAVE_DEPTH_SPAN 4.5 // world-depth the eased row range maps across
1727
+ #define COL_SHARP 48.0 // column-stripe sharpness in cell-phase units
1728
+ #define Y_NEAR (-0.62) // nearest row baseline (just below the bottom edge)
1729
+
1730
+ // Cheap stable hash for the particle field (highp; the 43758.5453 multiplier
1731
+ // bands under mediump, same note as clouds/nebula).
1732
+ float hash11(float n) {
1733
+ return fract(sin(n * 12.9898) * 43758.5453123);
1734
+ }
1735
+
1736
+ // The shared surface. x is perspective world-x, z is eased world-depth, t is time.
1737
+ // A small sum of sines whose x/z cross terms produce the hills, valleys, and
1738
+ // saddles; bounded to roughly [-1.6, 1.6].
1739
+ float waveField(float x, float z, float t) {
1740
+ float h = 0.0;
1741
+ h += sin(x * 1.00 + z * 0.55 + t) * 0.60;
1742
+ h += sin(x * 0.55 - z * 0.95 - t * 0.70) * 0.45;
1743
+ h += sin((x + z) * 0.45 + t * 0.40 + 1.7) * 0.40; // diagonal ridges -> saddles
1744
+ h += sin(x * 1.70 - z * 0.30 + t * 1.20) * 0.16; // fine ripple
1745
+ return h;
1746
+ }
1747
+
1748
+ void main() {
1749
+ vec2 fragCoord = vUv * uResolution;
1750
+ vec2 uv = (fragCoord - 0.5 * uResolution) / uResolution.y; // centered, aspect-correct
1751
+
1752
+ // Background: smooth vertical gradient, no texture. g = 0 bottom .. 1 top.
1753
+ float g = clamp(uv.y + 0.5, 0.0, 1.0);
1754
+ vec3 col = mix(uBgBottom, uBgTop, g);
1755
+
1756
+ // Ease additive glow near the frame center (the subject's face sits there).
1757
+ float calm = 1.0 - uCalm * (1.0 - smoothstep(0.18, 0.62, length(uv)));
1758
+
1759
+ float t = uTime * uWaveSpeed;
1760
+ float horizon = clamp(uHorizon, -0.2, 0.45);
1761
+
1762
+ // Line-glow widths from the half-width. The core line keeps the one exp() (its
1763
+ // sharp gaussian is the wireframe signature); the bloom halo and the vertical
1764
+ // strut use rational falloffs (1/(1+k·dy^2)) instead of more exp() calls, which
1765
+ // are ~8x-weighted transcendentals on the hot per-row path. The node reuses the
1766
+ // core exp directly. Net: 2 exp/row (core + column), down from 5.
1767
+ float coreSharp = 1.0 / max(uLineWidth * uLineWidth, 1e-5);
1768
+ float haloK = coreSharp * 0.14; // rational-bloom width (matches the old halo half-width)
1769
+ float strutK = coreSharp * 0.14; // rational vertical-bridge width
1770
+
1771
+ vec3 mesh = vec3(0.0);
1772
+ vec3 haze = vec3(0.0);
1773
+
1774
+ for (int i = 0; i < ROWS; i++) {
1775
+ float rowT = float(i) / float(ROWS - 1); // 0 near .. 1 far
1776
+ float om = 1.0 - rowT;
1777
+ float f = 1.0 - om * om; // eased depth: rows bunch toward horizon
1778
+ float persp = mix(1.0, uFarScale, f);
1779
+ persp = max(persp, uFarScale); // guard the divide (uFarScale > 0)
1780
+
1781
+ // Row baseline in screen-y, with a diagonal tilt for corner composition.
1782
+ float baseY = mix(Y_NEAR, horizon, f) + uv.x * uSlant * persp;
1783
+
1784
+ // Early-out: skip the sines for any row that cannot reach this pixel. Margin
1785
+ // covers the max wave displacement plus the strut's vertical bridge.
1786
+ float reach = persp * uWaveAmp * 1.7 + uLineWidth * 3.0 + 0.06;
1787
+ if (abs(uv.y - baseY) > reach) continue;
1788
+
1789
+ float worldX = uv.x / persp;
1790
+ float h = waveField(worldX * uWaveScale, f * WAVE_DEPTH_SPAN, t);
1791
+ float surfY = baseY + persp * uWaveAmp * h;
1792
+ float dy = uv.y - surfY;
1793
+
1794
+ // Crest factor: peaks of the field glow white, troughs stay the line tint.
1795
+ float crest = smoothstep(0.2, 1.4, h);
1796
+
1797
+ // Horizontal ribbon: sharp gaussian core (the line) + rational bloom halo.
1798
+ float dy2 = dy * dy;
1799
+ float core = exp(-dy2 * coreSharp);
1800
+ float ribbon = core + 0.22 / (1.0 + dy2 * haloK);
1801
+
1802
+ // Column grid: one bright stripe per cell of worldX. cph = 0 at the stripe.
1803
+ float cph = fract(worldX * uGridX) - 0.5;
1804
+ float colLine = exp(-cph * cph * COL_SHARP);
1805
+
1806
+ // Vertical strut (rational falloff in y so it bridges toward neighbors, gated
1807
+ // by the column) and the intersection node (core line x column -> a glowing
1808
+ // dot; reuses the core exp, no extra transcendental).
1809
+ float strut = colLine / (1.0 + dy2 * strutK);
1810
+ float node = core * colLine;
1811
+
1812
+ // Atmospheric fade: far rows dim and tint toward the haze color.
1813
+ float fade = om * om; // 1 near .. 0 far
1814
+ float lit = ribbon + uStrutMix * strut + uNodeMix * node * 2.0;
1815
+ vec3 lineCol = mix(uLineColor, uCrestColor, crest);
1816
+
1817
+ // Crest-dominant brightness: troughs stay dim, peaks carry the illumination.
1818
+ mesh += lineCol * lit * fade * (0.35 + 1.0 * crest);
1819
+ haze += uHazeColor * ribbon * (1.0 - fade) * crest;
1820
+ }
1821
+
1822
+ col += mesh * uGlow * calm;
1823
+ col += haze * uHaze * calm;
1824
+
1825
+ // Sparse floating particles; index 0 is the lone accent mote (independent of
1826
+ // uParticles so an accent can show with the particle field off).
1827
+ if (uParticles > 0.0 || uAccent > 0.0) {
1828
+ vec3 motes = vec3(0.0);
1829
+ for (int p = 0; p < PARTICLES; p++) {
1830
+ float fp = float(p);
1831
+ vec2 seed = vec2(hash11(fp * 1.7 + 0.3), hash11(fp * 3.1 + 1.9));
1832
+ vec2 ppos = (seed * 2.0 - 1.0) * vec2(0.92, 0.46);
1833
+ ppos.x += sin(uTime * 0.07 + fp * 2.3) * 0.03;
1834
+ ppos.y += cos(uTime * 0.05 + fp * 1.7) * 0.03;
1835
+ float twinkle = 0.5 + 0.5 * sin(uTime * (0.6 + hash11(fp * 5.0)) + fp * 4.0);
1836
+ float pd = length(uv - ppos);
1837
+ float glint = exp(-pd * pd * 2300.0) * twinkle;
1838
+ vec3 pcol = (p == 0) ? uAccentColor * uAccent : uCrestColor * uParticles;
1839
+ motes += pcol * glint;
1840
+ }
1841
+ col += motes * calm;
1842
+ }
1843
+
1844
+ // Soft highlight rolloff: fold the additive foreground pile-up into clean white
1845
+ // crests instead of a clipped slab; leaves the dark gradient essentially intact.
1846
+ col = vec3(1.0) - exp(-col);
1847
+
1848
+ oColor = vec4(col, 1.0);
1849
+ }
1681
1850
  """
1682
1851
 
1683
1852
  // Generative background shaders, by name. The generic shader processor and
@@ -1698,5 +1867,6 @@ void main() {
1698
1867
  "anamorphic-lensflare" to ANAMORPHIC_LENSFLARE_FRAG,
1699
1868
  "light-beams-and-motes" to LIGHT_BEAMS_AND_MOTES_FRAG,
1700
1869
  "corporate-blobs" to CORPORATE_BLOBS_FRAG,
1870
+ "data-mesh" to DATA_MESH_FRAG,
1701
1871
  )
1702
1872
  }
@@ -17,13 +17,13 @@ export const clouds = {
17
17
  uSkyHighColor: [0.04, 0.03, 0.86],
18
18
  uCloudLightColor: [1.0, 0.91, 0.77],
19
19
  uCloudDarkColor: [0.3, 0.3, 0.5],
20
- uExposure: 1.18,
20
+ uExposure: 1.27,
21
21
  uStepSize: 0.16,
22
- uCloudSpeed: 0.16,
22
+ uCloudSpeed: 0.52,
23
23
  uCloudScale: 1.08,
24
- uDensity: 0.235,
25
- uCoverage: 0.42,
26
- uSoftness: 0.39,
24
+ uDensity: 0.245,
25
+ uCoverage: 0.47,
26
+ uSoftness: 0.28,
27
27
  },
28
28
  },
29
29
  // You, under the sky.
@@ -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
+ }