← shader.gallery
Fret Filament
‹ patina reed ›
Post-processing

One-click post-FX looks — stack as many as you like. Each card's own sliders fine-tune it.

Embed this background

A one-line web component, loaded from the CDN.

Fragment shader

GLSL ES · MIT · yours to copy

// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2026 E. T. Carter <[email protected]>
// fret (Burnish) - a living labyrinth. A Truchet weave of quarter-turn paths
// connects edge to edge into one continuous meander that fills the whole frame
// (no empty centre, no border band). The paths glow in palette hues, and bright
// currents of light course along them like charge through a circuit. Comments
// short/ASCII on purpose (the headless-gl poster compiler is fussy).
//
// Uniforms: u_time, u_resolution, u_mouse, u_pixelRatio, u_palette[4]
precision highp float;

uniform float u_time;
uniform vec2  u_resolution;
uniform vec2  u_mouse;
uniform float u_pixelRatio;
uniform vec3  u_palette[4];

uniform float u_scale;   // path cell size in CSS px      (default 70)
uniform float u_line;    // path core weight in CSS px     (default 3.0)
uniform float u_flow;    // speed of the travelling light  (default 0.6)
uniform float u_glow;    // halo / glow strength 0..1      (default 0.7)
uniform float u_weld;    // 0 = segmented beads, 1 = seamless flow (default 1)
uniform float u_seed;    // re-rolls which tiles turn -> a new maze (default 0)

float hash21(vec2 p) { p = fract(p * vec2(123.34, 345.45)); p += dot(p, p + 34.345); return fract(p.x * p.y); }
float wheelW(float s, float c) { float d = abs(s - c); return max(0.0, 1.0 - min(d, 4.0 - d)); }
vec3 wheelCol(float k, vec3 c0, vec3 c1, vec3 c2, vec3 c3) {
  float s = fract(k) * 4.0;
  float a = wheelW(s, 0.0), b = wheelW(s, 1.0), cc = wheelW(s, 2.0), dd = wheelW(s, 3.0);
  return (c0 * a + c1 * b + c2 * cc + c3 * dd) / max(a + b + cc + dd, 0.001);
}

void main() {
  float pr  = u_pixelRatio;
  vec2  fc  = gl_FragCoord.xy;
  vec2  res = u_resolution;
  vec2  ctr = res * 0.5;
  float t   = u_time;
  float HALFPI = 1.5707963;

  float refScale = min(res.x, res.y) / (max(pr, 1.0) * 400.0);
  float cell = max(u_scale, 8.0) * refScale * pr;
  vec2  uv = (fc - ctr) / cell;

  vec2 id = floor(uv);
  vec2 f  = fract(uv);
  float hsh = hash21(id + vec2(u_seed * 1.7, u_seed * 2.3));  // u_seed re-rolls the maze
  if (hsh > 0.5) f.x = 1.0 - f.x;          // pick one of the two Truchet turns

  // two quarter-arcs centred at opposite corners, radius 0.5 -> connected paths
  float r1 = length(f - vec2(0.0, 0.0));
  float r2 = length(f - vec2(1.0, 1.0));
  float d1 = abs(r1 - 0.5);
  float d2 = abs(r2 - 0.5);

  // pick the nearer arc and its angle (0..pi/2) for the travelling light
  float d, ang;
  if (d1 < d2) { d = d1; ang = atan(f.y, f.x); }
  else         { d = d2; ang = atan(1.0 - f.y, 1.0 - f.x); }

  float lw = max(u_line, 0.5) * refScale * pr / cell;   // half-width in cell units
  float core = smoothstep(lw, lw * 0.25, d);
  float halo = lw / (d + lw * 1.4);
  halo = halo * halo * (0.4 + 0.7 * u_glow);

  // --- palette ---
  vec3 c0 = u_palette[0], c1 = u_palette[1], c2 = u_palette[2], c3 = u_palette[3];
  if (dot(c0,c0)+dot(c1,c1)+dot(c2,c2)+dot(c3,c3) < 1e-5) {
    c0 = vec3(0.231,0.510,0.965); c1 = vec3(0.659,0.333,0.969);
    c2 = vec3(0.133,0.827,0.933); c3 = vec3(0.957,0.247,0.369);
  }

  // hue varies slowly across the maze so the lines are multi-hue, not one wash.
  // the per-tile hsh jump is faded out by u_weld so colour does not step at seams.
  float hue = dot(uv, vec2(0.06, 0.085)) + hsh * 0.12 * (1.0 - u_weld) + t * 0.02;
  vec3 pathCol = wheelCol(hue, c0, c1, c2, c3);

  // travelling current: a bright pulse running along the paths. the LOCAL phase
  // chains arc-length per tile (the original look) but jumps at every cell edge;
  // the GLOBAL phase is one continuous field across the frame (no seams). u_weld
  // crossfades local -> global so the beads weld into a smooth coursing flow.
  float dirn   = (hsh > 0.5) ? -1.0 : 1.0;
  float sLocal = ang / HALFPI + (id.x + id.y) * 0.5;     // arc-length-ish phase
  float phLoc  = (sLocal - t * u_flow * 0.5) * dirn;
  float phGlob = dot(uv, vec2(0.5, 0.5)) - t * u_flow * 0.5;
  float ph     = mix(phLoc, phGlob, u_weld);
  float pulse  = 0.5 + 0.5 * sin(6.2831853 * ph);
  pulse = pow(pulse, 3.0);

  float lit = core * (0.85 + 1.0 * pulse) + halo * (0.7 + 0.6 * pulse);

  // soft palette ground so gaps are tinted, never dead-black
  float rr = length((fc - ctr) / res);
  vec3 ground = wheelCol(0.55 + rr * 0.3 + t * 0.01, c0, c1, c2, c3) * 0.16;

  vec3 col = ground + pathCol * lit;
  col += pathCol * core * pulse * 0.7;                   // extra glow for bloom

  float vign = 1.0 - smoothstep(0.7, 1.35, rr);
  col *= mix(0.9, 1.0, vign);

  gl_FragColor = vec4(col, 1.0);
}