Plasma Mesh Background

  • Skia
  • Reanimated

A drifting colour field built from value noise, warped through itself twice. It is one shader with no textures, and the most interesting line in it exists because of a bug that only appeared on real hardware.

A grid warped twice

Plain noise looks like fog. Here a first pair of noise fields displaces the sampling coordinates, and a second pair is sampled through that displacement, which is what produces folds and filaments rather than blobs. Each stage carries its own clock, two of them running backwards, so the field never settles into a loop the eye can catch.

float2 q;q.x = fbm(uv + float2(0.0, 0.0) + 0.15 * t, gain);q.y = fbm(uv + float2(5.2, 1.3) - 0.12 * t, gain);float2 r;r.x = fbm(uv + warp * q + float2(1.7, 9.2) + 0.20 * t, gain);r.y = fbm(uv + warp * q + float2(8.3, 2.8) - 0.18 * t, gain);

Octaves that interfere instead of banding

Doubling the frequency each octave and leaving the lattice where it is stacks every ridge on the same axes, and the result reads as a grid. Rotating the coordinates about half a radian per octave puts each layer's ridges across the last one's. Turbulence raises the persistence as well as the warp, so a busier field is also a sharper one.

float c = cos(0.5);float s = sin(0.5);float2x2 rot = float2x2(c, -s, s, c);for (int i = 0; i < 4; i++) {  total += amp * vnoise(p);  p = rot * p * 2.0;  amp *= gain;}

Why the lattice wraps at 256 cells

The warp scrolls the coordinate without limit, and after a while fract(coord * 456.21) runs out of fractional precision on a lower-precision fragment unit — adjacent cells hash to the same value and the field collapses into rectangles. It survived the simulator, which computes in fp32, and failed on an Adreno device. Wrapping the lattice into 256 cells fixes it; the repeat is a hundred screens away.

float2 wrap256(float2 p) { return mod(p, 256.0); }// …float a = hash(wrap256(i));float b = hash(wrap256(i + float2(1.0, 0.0)));float c = hash(wrap256(i + float2(0.0, 1.0)));float d = hash(wrap256(i + float2(1.0, 1.0)));

Tuning

  • #3A1C71
  • #D76D77
  • 1
  • 0.6
<PlasmaMeshBackground params={{ colorA: "#3A1C71", colorB: "#D76D77", turbulence: 1, speed: 0.6 }} fireSignal={0} />