The Code Therapy

The 80s On ASCIID

This is a piece that brings me back to the amazing aesthetics of my childhood, by using simple mathematical patterns that were widely explored back in the demoscene days.

Created by marcogomez on Thu, 27 May 2021 21:35:57 GMT.


// ╔═════════════╦════════════════╗
// ║ Marco Gomez ║ https://mgz.me ║
// ╚═════════════╩════════════════╝
precision highp float;

uniform sampler2D prgm1Texture;
uniform sampler2D prgm7Texture;
uniform vec2 resolution;
uniform float time;

varying vec2 vUv;

const float PI = acos(-1.0);
const float TAU = PI * 2.0;
const float SQRTAU = sqrt(TAU);
const bool customTime = true;
const float frameScale = 12.00;

const float postAmount = 1.0;
const float reinhardAmount = 0.3;
const float contrast = 1.0;
const float brightness = 1.4;
const float saturation = 1.0;
const float vignetteMix = 1.0;
const float vignetteRoundness = 0.12;
const float vignetteSmoothness = 0.42;
const vec2 vignetteSize = vec2(0.25, 0.25);
const float W = 1.2;
const float T = 7.5;

float filmicReinhardCurve(float x) {
  float q = (T * T + 1.0) * x * x;
  return q / (q + x + T * T);
}

vec3 filmicReinhard(vec3 c) {
  float w = filmicReinhardCurve(W);
  return vec3(
    filmicReinhardCurve(c.r),
    filmicReinhardCurve(c.g),
    filmicReinhardCurve(c.b)
  ) / w;
}

vec3 BSC(vec3 color, float brt, float sat, float con) {
  const float AvgLumR = 0.5;
  const float AvgLumG = 0.5;
  const float AvgLumB = 0.5;
  const vec3 LumCoeff = vec3(0.2125, 0.7154, 0.0721);
  vec3 AvgLumin = vec3(AvgLumR, AvgLumG, AvgLumB);
  vec3 brtColor = color * brt;
  vec3 intensity = vec3(dot(brtColor, LumCoeff));
  vec3 satColor = mix(intensity, brtColor, sat);
  vec3 conColor = mix(AvgLumin, satColor, con);
  return conColor;
}

float sdSquare(vec2 point, float width) {
  vec2 d = abs(point) - width;
  return min(max(d.x, d.y), 0.0) + length(max(d, 0.0));
}

float vignette(vec2 uv, vec2 size, float roundness, float smoothness) {
  uv -= 0.5;
  float minWidth = min(size.x, size.y);
  uv.x = sign(uv.x) * clamp(abs(uv.x) - abs(minWidth - size.x), 0.0, 1.0);
  uv.y = sign(uv.y) * clamp(abs(uv.y) - abs(minWidth - size.y), 0.0, 1.0);
  float boxSize = minWidth * (1.0 - roundness);
  float dist = sdSquare(uv, boxSize) - (minWidth * roundness);
  return 1.0 - smoothstep(0.0, smoothness, dist);
}

float gaussian(float z, float u, float o) {
  return (
    (1.0 / (o * SQRTAU)) *
    (exp(-(((z - u) * (z - u)) / (2.0 * (o * o)))))
  );
}

vec3 gaussgrain(float t) {
  vec2 ps = vec2(1.01) / resolution.xy;
  vec2 uv = gl_FragCoord.xy * ps;
  float seed = dot(uv, vec2(12.9898, 78.233));
  float noise = fract(sin(seed) * 43758.5453123 + t);
  noise = gaussian(noise, 0.0, 0.5);
  return vec3(noise);
}

vec2 warp(vec2 uv, vec2 warpAmount) {
  uv = uv * 2.0 - 1.0;
  uv *= 0.85;
  vec2 offset = abs(uv.yx) / vec2(warpAmount.x, warpAmount.y);
  uv = uv + uv * offset * offset;
  uv = uv * 0.5 + 0.5;
  return uv;
}

void main() {
  vec2 uv = gl_FragCoord.xy / resolution.xy;
  uv = uv * 2.0 - 1.0; uv *= 0.92; uv = uv * 0.5 + 0.5;
  float ar = resolution.x / resolution.y;
  uv = warp(uv, vec2(7.0, 3.0 * ar));
  vec4 texel = texture2D(prgm7Texture, uv);
  if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {
    texel.rgb *= 0.0;
  }
  vec4 t = texture2D(prgm1Texture, gl_FragCoord.xy / resolution.xy);
  vec3 color = texel.rgb;
  vec3 copy = color;
  vec3 reinhard = filmicReinhard(color);
  color = mix(color, reinhard, reinhardAmount);
  color = BSC(color, brightness, saturation, contrast);
  float v = vignette(uv, vignetteSize, vignetteRoundness, vignetteSmoothness);
  vec3 vig = color * v;
  color = mix(color, vig, vignetteMix);
  color = clamp(mix(copy, color, postAmount), 0.0, 1.0);
  float frameTime = (customTime) ? floor((0.1 + time) * frameScale) / frameScale : time;
  color -= gaussgrain(frameTime) * 0.05;
  gl_FragColor = vec4(color, 1.0) * min(time * 0.1, 1.0);
}

// ╔═════════════╦════════════════╗
// ║ Marco Gomez ║ https://mgz.me ║
// ╚═════════════╩════════════════╝
precision highp float;

uniform vec2 resolution;
uniform float time;

const bool customTime = false;
const float frameScale = 24.00;

const float PI = acos(-1.0);
const float HALFPI = PI / 2.0;
const float ttp = 1.0 / 3.0;
const float ssp = 1.0 / 6.0;

const vec2 hashV = vec2(12.9898, 78.233);
const float hashF = 43758.5453123;

float osc(float s, float e, float t, float ts) {
  return (e - s) / 2.0 + s + sin(t * ts) * (e - s) * 0.5;
}

vec2 rotate(vec2 uv, float a) {
  return vec2(uv.x * cos(a) - uv.y * sin(a), uv.x * sin(a) + uv.y * cos(a));
}

float hash(vec2 uv) {
  return fract(sin(dot(uv.xy, hashV)) * hashF);
}

float noise(vec2 uv) {
  const vec2 O = vec2(0.0, 1.0);
  vec2 b = floor(uv);
  return mix(mix(hash(b), hash(b + O.yx), 0.5), mix(hash(b + O), hash(b + O.yy), 0.5), 0.5);
}

float waves(vec2 uv, float frac, float t) {
  float t2 = t * -0.5;
  uv.y += t2;
  float w = sin(uv.y - frac * 2.0 * PI + 1.5 * PI) * 0.5 + 0.5;
  w += sin(uv.x * 4.0 - uv.y * 4.0 - t * 2.0) * ttp * 0.07;
  return clamp(w, 0.0, 1.0);
}

float atanStar(vec2 uv, float t) {
  vec2 cp = normalize(vec3(uv.xy, 1.0)).xy;
  cp = mix(uv, cp, 0.7);
  float pAtan = atan(cp.x, cp.y) + cp.x;
  float star = sin(pAtan * 7.0 - t * 7.45) * 0.5 + 0.5;
  return clamp(star, 0.0, 1.0);
}

vec2 truchetPattern(vec2 uv, float index) {
  index = fract(((index - 0.5) * 2.0));
  if (index > 0.75) { uv = vec2(1.0) - uv; }
  else if (index > 0.50) { uv = vec2(1.0 - uv.x, uv.y); }
  else if (index > 0.25) { uv = 1.0 - vec2(1.0 - uv.x, uv.y); }
  return uv;
}

float curvedTruchet(vec2 uv, float t) {
  vec2 ouv = uv;
  uv *= 1.7;
  uv.x -= t * 1.2;
  vec2 ipos = floor(uv);
  vec2 fpos = fract(uv);
  vec2 tile = truchetPattern(fpos, hash(ipos));
  float a = (
    (step(length(tile), 0.6) - step(length(tile), 0.4)) +
    (step(length(tile - vec2(1.0)), 0.6) - step(length(tile - vec2(1.0)), 0.4))
  );
  float curves = a / length(ouv * 0.8) * 0.5;
  return clamp(curves, 0.0, 1.0);
}

float pacman(vec2 uv, float frac, float t) {
  float value = 0.0;
  uv *= 4.0;
  vec2 pacmanCenter = vec2(6.7 - frac * 30.0, 0.0);
  vec2 delta = uv - pacmanCenter;
  float theta = abs(atan(delta.y, -delta.x));
  float mouth = step(max(0.0, sin(t * 10.0) * 0.4 + 0.35), theta);
  float dist = distance(uv, pacmanCenter);
  value += sqrt( clamp(20.0 - dist * 20.0, 0.0, 1.0) * mouth);
  if (uv.x > pacmanCenter.x + 0.5) { return value; }
  uv.y += sin((5.0 * t) + uv.x * 0.5) * 0.15;
  vec2 center = vec2(floor(uv.x) + 0.5, 0.0);
  if (uv.x < pacmanCenter.x - 0.95) {
    value += max(0.0, 6.0 - distance(uv , center) * 30.0) * 1.5 - distance(pacmanCenter , center);
  }
  if (uv.x < pacmanCenter.x - 0.9) {
    value += max(0.0, 6.0 - distance(uv , center) * 30.0) * 0.60;
  } else if (uv.x < pacmanCenter.x - 0.6) {
    value += max(0.0, 6.0 - distance(uv , center) * 30.0) * 0.30;
  } else if (uv.x < pacmanCenter.x - 0.3) {
    value += max(0.0, 6.0 - distance(uv , center) * 30.0) * 0.15;
  } else if (uv.x < pacmanCenter.x + 0.25) {
    value += max(0.0, 6.0 - distance(uv , center) * 30.0) * 0.07;
  }
  return clamp(value, 0.0, 1.0);
}

float truchet(vec2 uv, float t) {
  float shade = abs(uv.y);
  uv *= 3.0;
  uv.x -= t * 1.7;
  uv = rotate(uv, PI * 0.25);
  vec2 gv = fract(uv) - 0.5;
  vec2 id = floor(uv);
  float n = hash(id);
  float w = 0.21;
  if (n < 0.5) { gv.x *= -1.0; }
  float dist = abs(abs(gv.x + gv.y) - 0.5);
  float mask = smoothstep(0.01, -0.01, dist - w);
  return clamp(mask - shade * 0.5, 0.0, 1.0);
}

float plasma(vec2 uv, float t) {
  vec2 ouv = uv;
  uv *= 0.7 + osc(-0.2, 0.2, t, 0.12);
  uv = rotate(uv, t * 0.12);
  uv.y *= max(resolution.x, resolution.y) / min(resolution.x, resolution.y);
  float t1 = t * 0.12, t2 = t * 0.21;
  uv *= vec2(40.0, 12.0), uv = floor(uv), uv /= vec2(80.0, 24.0);
  float color = 0.0;
  color += 0.7 * sin(00.5 * uv.x + t1);
  color += 3.0 * sin(01.6 * uv.y + t1);
  color += 1.0 * sin(10.0 * (uv.y * sin(t2) + uv.x * cos(t1)) + t2);
  float cx = uv.x + 0.5 * sin(t2);
  float cy = uv.y + 0.5 * cos(t2 * 0.5);
  color += +0.4 * sin(sqrt(100.0 * cx * cx + 100.0 *cy * cy + 1.0) + t);
  color += +0.9 * sin(sqrt(075.0 * cx * cx + 025.0 *cy * cy + 1.0) + t);
  color += -1.4 * sin(sqrt(256.0 * cx * cx + 025.0 *cy * cy + 1.0) + t);
  color += +0.3 * sin(0.5 * uv.y + uv.x + sin(t));
  float plasma = (3.0 * (0.5 + 0.499 * sin(color))) * ttp;
  plasma = plasma / length(ouv * 0.8) * 0.5;
  return clamp(plasma, 0.0, 1.0);
}

float sdBox(vec3 p, vec3 b) {
  vec3 d = abs(p) - b;
  return (
    min(max(d.x, max(d.y, d.z)), 0.0) + length(max(d,0.0))
  );
}

float mapCube(vec3 p, float t) {
  p.xz *= mat2(cos(t), sin(t), -sin(t), cos(t));
  p.xy *= mat2(cos(t), sin(t), -sin(t), cos(t));
  p.yz *= mat2(cos(t), sin(t), -sin(t), cos(t));
  float k = sdBox(p, vec3(1.0));
  float o = 0.85;
  k = max(k, -sdBox(p, vec3(2.0, o, o)));
  k = max(k, -sdBox(p, vec3(o, 2.0, o)));
  k = max(k, -sdBox(p, vec3(o, o, 2.0)));
  return k;
}

float traceCube(vec3 o, vec3 r, float t) {
  float td = 0.0;
  for (int i = 0; i < 32; ++i) {
    vec3 p = o + r * td;
    float d = mapCube(p, t) * 0.9;
    td += d;
  }
  return td;
}

float cube(vec2 uv, float ft) {
  vec3 origin = vec3(0.0, 0.0, -2.1);
  vec3 r = vec3(uv, 0.8);
  float t = traceCube(origin, r, ft * 7.0);
  float c = 1.0 / (1.0 + t * t * 0.1) * 0.9;
  return c;
}

float stars(vec2 uv, float t) {
  vec2 ouv = uv;
  uv.y += 1.5;
  float stars = 0.0, fl, s;
  for (int layer = 3; layer < 8; layer++) {
    fl = float(layer);
    s = (100.0 - fl * 16.0);
    float d = pow(abs(noise(mod(vec2(uv.x * s + (t + 7.0) * -12.0 - fl * 16.0, uv.y * s), resolution.x))), 16.0);
    stars += step(0.15, d);
  }
  stars = stars / length(ouv * 0.5) * 0.5;
  return clamp(stars, 0.0, 1.0);
}

float spiral(vec2 uv, float t) {
  vec2 ouv = uv;
  uv *= 0.42;
  uv = vec2(atan(uv.x, uv.y) / PI * 4.0, log(length(uv) + 1.0) * 8.0);
  uv.x += (t + 10.0) * 0.5;
  uv.y -= uv.x * 0.5 + t * 1.0;
  vec2 f = fract(uv) * 1.5 - 0.5;
  float spiral = max(f.x - uv.x, uv.y);
  spiral = spiral / length(ouv * 0.5) * 0.5;
  return clamp(spiral, 0.0, 1.0);
}

float spiralB(float t, float ft) {
  vec2 c = gl_FragCoord.xy;
  vec4 s = resolution.xyxy;
  float o = osc(0.2, 0.4, ft, 0.25);
  s = length(c += c - s.xy) / s;
  s = sin(s.w - o) * vec4(sin(8.0 / s + atan(c.x, c.y) * 12.0 - t * 3.0).w < 0.2);
  return clamp(s.x, 0.0, 1.0);
}

float pong(vec2 uv, float t) {
  uv *= 0.4;
  uv.x *= 1.5;
  uv.x += 0.5;
  uv.y *= 1.2;
  vec2 b;
  b.x = mod(t / 1.7, 1.88) + 0.03;
  b.y = mod(t / 2.5, 1.08) - 0.27;
  b = min(b, vec2(1.94, 0.54) - b);
  float c = smoothstep(1.0, 0.9, 70.0 * distance(uv, b));
  float l = mix(b.y, sin(t * 3.1) * 0.2, b.x);
  float r = mix(cos(t * 3.7) / 4.5, b.y * 0.9, b.x);
  if (
    (uv.x < 0.040 && uv.x > 0.01 && abs(l - uv.y) < 0.06) ||
    (uv.x > 0.955 && uv.x < 0.99 && abs(r - uv.y) < 0.06)
  ) { c = 1.0; }
  if (uv.x < +0.001 || uv.x > 0.999 || uv.y < -0.27 || uv.y > 0.27) { c = 1.0; }
  if (uv.x < -0.020 || uv.x > 1.020 || uv.y < -0.29 || uv.y > 0.29) { c = 0.0; }
  return c;
}

float corridor(vec2 uv, float t) {
  uv.y = abs(uv.y);
  uv.y = max(0.08, uv.y);
  uv.x /= uv.y;
  uv.x += t;
  float c = mod(floor(uv.x) + floor(uv.y * 2.0), 2.0) + 0.5;
  float dist = sqrt(uv.y);
  c = c * max(0.1, min(1.0, dist * 1.3));
  return c;
}

float rings(vec2 uv, float t) {
  float scale = resolution.y / 50.0;
  float ring = 64.0;
  float radius = resolution.x;
  float gap = scale * 0.25;
  float d = length(uv);
  d += scale - t * 0.1;
  float v = mod(d + radius / (ring * 2.0), radius / ring);
  v = abs(v - radius / (ring * 2.0));
  v = clamp(v - gap, 0.0, 1.0);
  d += v;
  float m = fract((d - 1.0) * (ring * -0.5, -ring, ring * 0.25) * 0.25);
  return m;
}

float wave(vec2 uv, float t) {
  vec2 ouv = uv;
  uv.x += t * 0.2 + (3.0 + sin(t) * 0.25);
  float w = sin(uv.x * 14.0 + t * 1.2) / 4.0;
  float d = abs(uv.y - w) * 4.0;
  w += cos(uv.x * 18.0 + t) / 8.0;
  d *= (abs(uv.y - w) * 18.0) * 0.25;
  float wave = 0.25 / d;
  wave = 1.0 - wave;
  wave = wave / length(ouv * 0.7) * 0.5;
  return clamp(sqrt(wave) * 12.0 * wave * wave * wave * wave, 0.0, 1.0);
}

float flippingSquares(vec2 uv, float t) {
  vec2 ouv = uv;
  uv = rotate(uv, t * -0.5);
  uv *= 2.5;
  uv.y += t * 0.5;
  float size = 20.0 + abs(sin(t * 0.5)) * 150.0;
  float hsm = 1.5 / resolution.y * size * 0.5;
  vec2 id = floor(uv);
  uv = fract(uv) - 0.5;
  float a = t;
  float phase = mod(floor(a / HALFPI), 2.0);
  float mask = 0.0;
  for (float y =- 1.0; y <= 1.0; y++) {
    for (float x =- 1.0; x <= 1.0; x++) {
      vec2 ruv = uv + vec2(x, y);
      vec2 rid = id + vec2(x, y);
      ruv *= mat2(cos(a + vec4(0.0, 33.0, 11.0, 0.0)));
      vec2 maskXY = smoothstep(0.5 + hsm, 0.5 - hsm, abs(ruv));
      float maskI = maskXY.x * maskXY.y;
      vec2 idm = mod(rid, 2.0);
      float draw = abs(idm.x * idm.y + (1.0 - idm.x) * (1.0 - idm.y) - phase);
      mask += maskI * draw;
    }
  }
  float squares = abs(mask - phase);
  squares = squares / length(ouv * 0.6) * 0.5;
  return clamp(squares, 0.0, 1.0);
}

bool detect(vec2 cir, vec2 curr, float size ) {
  return (distance(cir, curr) < size);
}

float snake(vec2 uv, float t) {
  uv *= 0.5;
  uv += 0.5;
  float s = 0.0;
  for (int k = 0; k < 60; k++) {
    float x = float(k);
    float shift = t + x / 9.0 * 1.1416;
    if (detect(uv, vec2((sin(shift) * x / 100.0 * 0.9), (cos(shift) * 0.1)) + 0.5, x / 768.0)) {
      s = 0.01 * x;
    }
  }
  return s * s * 4.0;
}

float vsine(vec2 uv) {
  float s = 1.0;
  s *= smoothstep(
    sqrt(abs(1.0 / (sin(0.5 * uv.x + sin(2.0 * uv.y + time * 2.0) * 0.1) * 5.0))),
    -0.2,
    0.4
  );
  return clamp(s, 0.0, 1.0);
}

float checkerboard(vec2 uv) {
  float xpos = floor(20.0 * uv.x);
  float ypos = floor(5.0 * uv.y);
  float c = mod(xpos, 2.0);
  if (mod(ypos, 2.0) > 0.0) {
    c = (c > 0.0) ? 0.0: 1.0;
  }
  return c;
}

float tunnel(vec2 uv) {
  float s = 0.0325;
  float a = atan(uv.y, uv.x);
  float r = length(uv);
  vec2 p = vec2(0.091 / r + s * time, (a + s * (time) * PI * 2.0) / PI);
  float tun = checkerboard(p);
  tun = smoothstep(tun, 1.1, 0.2);
  r = r * r * 21.0;
  return clamp(r * tun, 0.065 + r * 0.0002, 1.0);
}

float getEffect(int fx, vec2 uv, float frac, float frameTime) {
  float effects = 18.0;
  int idx = int(effects) - 1;
  fx = int(fract(float(fx) * 1.61456) * effects);
  int temp = int(float(fx) / float(idx));
  fx -= temp * idx;
  float value = 0.0;
  uv *= 1.0;
       if (fx == 0) { value = waves(uv, frac, frameTime); }
  else if (fx == 1) { value = atanStar(uv, frameTime); }
  else if (fx == 2) { value = curvedTruchet(uv, frameTime); }
  else if (fx == 3) { value = spiralB(frameTime, frac); }
  else if (fx == 4) { value = plasma(uv, frameTime); }
  else if (fx == 5) { value = cube(uv, frac); }//eye(uv, frac, frameTime); }
  else if (fx == 6) { value = truchet(uv, frameTime); }
  else if (fx == 7) { value = corridor(uv, frameTime); }
  else if (fx == 8) { value = pacman(uv, frac, frameTime); }
  else if (fx == 9) { value = stars(uv, frameTime); }
  else if (fx == 10) { value = pong(uv, frameTime); }
  else if (fx == 11) { value = rings(uv, frameTime); }
  else if (fx == 12) { value = wave(uv, frameTime); }
  else if (fx == 13) { value = flippingSquares(uv, frameTime); }
  else if (fx == 14) { value = snake(uv, frameTime); }
  else if (fx == 15) { value = spiral(uv, frameTime); }
  else if (fx == 16) { value = vsine(uv); }
  else if (fx == 17) { value = tunnel(uv); }
  else { value = truchet(uv, frameTime); }
  return value;
}

float transition(vec2 uv, float effectLength, float frameTime) {
  int fx = int(frameTime / effectLength);
  float frac = mod(frameTime, effectLength) / effectLength;
  float valueA = getEffect(fx, uv, 0.0, frameTime);
  float valueB = getEffect(fx - 1, uv, frac, frameTime);
  return mix(valueB, valueA, smoothstep(ssp, 1.0, frac));
}

float draw(vec2 frag, float effectLength, float ledSize, float cellSize, float frameTime) {
  float size = ledSize * cellSize;
  vec2 cell = floor((frag + 2.0) / size) * size * 1.0 - resolution.xy;
  cell /= resolution.y;
  float brightness = transition(cell, effectLength, frameTime);
  return brightness;
}

void main(void) {
  const vec3 CA = vec3(0.02, 0.07, 0.04);
  vec3 CB = vec3(0.3, 1.0, 0.9);
  const float EFFECT_LENGTH = 11.1;
  const float LED_SIZE = 2.0;
  const float CELL_SIZE = 3.0;
  const float SIZE = LED_SIZE * CELL_SIZE;
  float frameTime = (customTime) ? floor(time * frameScale) / frameScale : time;
  float d = draw(gl_FragCoord.xy * 2.0, EFFECT_LENGTH, LED_SIZE, CELL_SIZE, frameTime);
  vec3 col = sqrt(d * CB) + (CA * 1.25) + 0.06;
  gl_FragColor = vec4(col * col, 1.0) * 1.05;
}

// ╔═════════════╦════════════════╗
// ║ Marco Gomez ║ https://mgz.me ║
// ╚═════════════╩════════════════╝
precision highp float;

uniform sampler2D prgm1Texture;
uniform vec2 resolution;
uniform float time;

varying vec2 vUv;

const float zoom = 1.0;
const float amount = 1.0;
const bool bypass = false;
const float chx = 12.0;
const float chy = 18.0;
const float PI = acos(-1.0);
const float TAU = PI * 2.0;
const float SQRTAU = sqrt(TAU);

const bool customTime = true;
const float frameScale = 24.00;

float gaussian(float z, float u, float o) {
  return (
    (1.0 / (o * SQRTAU)) *
    (exp(-(((z - u) * (z - u)) / (2.0 * (o * o)))))
  );
}

vec3 gaussgrain(float t) {
  vec2 ps = vec2(1.0) / resolution.xy;
  vec2 uv = gl_FragCoord.xy * ps;
  float seed = dot(uv, vec2(12.9898, 78.233));
  float noise = fract(sin(seed) * 43758.5453123 + t);
  noise = gaussian(noise, 0.0, 0.5);
  return vec3(noise);
}

float gray(vec3 c) {
  return c.x * 0.299 + c.y * 0.587 + c.z * 0.114;
}

void P(
  in int id,
  in int a, in int b, in int c, in int d,
  in int e, in int f, in int g, in int h,
  inout ivec2 p, inout float cha
) {
  if (id == int(p.y)) {
    int pa = (a + 2 * (b + 2 * (c + 2 * (d + 2 * (e + 2 * (f + 2 * (g + 2 * h)))))));
    cha = floor(mod(float(pa) / pow(abs(2.0), float(p.x) -1.0), 2.0));
  }
}

void main(void) {
  float z = zoom;
  vec2 uv = vec2(
    floor(gl_FragCoord.x / chx / z) * chx * z,
    floor(gl_FragCoord.y / chy / z) * chy * z
  ) / resolution.xy;
  ivec2 p = ivec2(mod(gl_FragCoord.x / z, chx), mod(gl_FragCoord.y / z, chy));
  vec4 prgm1 = texture2D(prgm1Texture, uv);
  float cha = 0.0;
  float g = gray(prgm1.xyz);
  if ( g < 0.125 ) {
    P(11,0,0,0,0,0,0,0,0, p, cha);
    P(10,0,0,0,0,0,0,0,0, p, cha);
    P( 9,0,0,0,0,0,0,0,0, p, cha);
    P( 8,0,0,0,0,0,0,0,0, p, cha);
    P( 7,0,0,0,0,0,0,0,0, p, cha);
    P( 6,0,0,0,0,0,0,0,0, p, cha);
    P( 5,0,0,0,0,0,0,0,0, p, cha);
    P( 4,0,0,0,0,0,0,0,0, p, cha);
    P( 3,0,0,0,0,0,0,0,0, p, cha);
    P( 2,0,0,0,0,0,0,0,0, p, cha);
    P( 1,0,0,0,0,0,0,0,0, p, cha);
    P( 0,0,0,0,0,0,0,0,0, p, cha);
  } else if (g < 0.25) {
    P(11,0,0,0,0,0,0,0,0, p, cha);
    P(10,0,0,0,0,0,0,0,0, p, cha);
    P( 9,0,0,0,0,0,0,0,0, p, cha);
    P( 8,0,0,0,0,0,0,0,0, p, cha);
    P( 7,0,0,0,0,0,0,0,0, p, cha);
    P( 6,0,0,0,0,0,0,0,0, p, cha);
    P( 5,0,0,0,0,0,0,0,0, p, cha);
    P( 4,0,0,0,1,1,0,0,0, p, cha);
    P( 3,0,0,0,1,1,0,0,0, p, cha);
    P( 2,0,0,0,0,0,0,0,0, p, cha);
    P( 1,0,0,0,0,0,0,0,0, p, cha);
    P( 0,0,0,0,0,0,0,0,0, p, cha);
  } else if (g < 0.375) {
    P(11,0,0,0,0,0,0,0,0, p, cha);
    P(10,0,0,0,0,0,0,0,0, p, cha);
    P( 9,0,0,0,0,0,0,0,0, p, cha);
    P( 8,0,0,0,0,0,0,0,0, p, cha);
    P( 7,0,0,0,0,0,0,0,0, p, cha);
    P( 6,0,0,0,0,0,0,0,0, p, cha);
    P( 5,0,0,0,0,0,0,0,0, p, cha);
    P( 4,0,0,0,1,1,0,0,0, p, cha);
    P( 3,0,0,0,1,1,0,0,0, p, cha);
    P( 2,0,0,0,0,1,0,0,0, p, cha);
    P( 1,0,0,0,1,0,0,0,0, p, cha);
    P( 0,0,0,0,0,0,0,0,0, p, cha);
  } else if (g < 0.5) {
    P(11,0,0,0,0,0,0,0,0, p, cha);
    P(10,0,0,0,0,0,0,0,0, p, cha);
    P( 9,0,0,0,0,0,0,0,0, p, cha);
    P( 8,0,0,0,0,0,0,0,0, p, cha);
    P( 7,0,0,0,0,0,0,0,0, p, cha);
    P( 6,1,1,1,1,1,1,1,0, p, cha);
    P( 5,0,0,0,0,0,0,0,0, p, cha);
    P( 4,0,0,0,0,0,0,0,0, p, cha);
    P( 3,0,0,0,0,0,0,0,0, p, cha);
    P( 2,0,0,0,0,0,0,0,0, p, cha);
    P( 1,0,0,0,0,0,0,0,0, p, cha);
    P( 0,0,0,0,0,0,0,0,0, p, cha);
  } else if (g < 0.625) {
    P(11,0,0,0,0,0,0,0,0, p, cha);
    P(10,0,0,0,0,0,0,0,0, p, cha);
    P( 9,0,0,0,1,0,0,0,0, p, cha);
    P( 8,0,0,0,1,0,0,0,0, p, cha);
    P( 7,0,0,0,1,0,0,0,0, p, cha);
    P( 6,1,1,1,1,1,1,1,0, p, cha);
    P( 5,0,0,0,1,0,0,0,0, p, cha);
    P( 4,0,0,0,1,0,0,0,0, p, cha);
    P( 3,0,0,0,1,0,0,0,0, p, cha);
    P( 2,0,0,0,0,0,0,0,0, p, cha);
    P( 1,0,0,0,0,0,0,0,0, p, cha);
    P( 0,0,0,0,0,0,0,0,0, p, cha);
  } else if (g < 0.75) {
    P(11,0,0,0,0,0,0,0,0, p, cha);
    P(10,0,0,0,1,0,0,0,0, p, cha);
    P( 9,1,0,0,1,0,0,1,0, p, cha);
    P( 8,0,1,0,1,0,1,0,0, p, cha);
    P( 7,0,0,1,1,1,0,0,0, p, cha);
    P( 6,0,0,0,1,0,0,0,0, p, cha);
    P( 5,0,0,1,1,1,0,0,0, p, cha);
    P( 4,0,1,0,1,0,1,0,0, p, cha);
    P( 3,1,0,0,1,0,0,1,0, p, cha);
    P( 2,0,0,0,1,0,0,0,0, p, cha);
    P( 1,0,0,0,0,0,0,0,0, p, cha);
    P( 0,0,0,0,0,0,0,0,0, p, cha);
  } else if (g < 0.875) {
    P(11,0,0,0,0,0,0,0,0, p, cha);
    P(10,0,0,1,0,0,1,0,0, p, cha);
    P( 9,0,0,1,0,0,1,0,0, p, cha);
    P( 8,1,1,1,1,1,1,1,0, p, cha);
    P( 7,0,0,1,0,0,1,0,0, p, cha);
    P( 6,0,0,1,0,0,1,0,0, p, cha);
    P( 5,0,1,0,0,1,0,0,0, p, cha);
    P( 4,0,1,0,0,1,0,0,0, p, cha);
    P( 3,1,1,1,1,1,1,1,0, p, cha);
    P( 2,0,1,0,0,1,0,0,0, p, cha);
    P( 1,0,1,0,0,1,0,0,0, p, cha);
    P( 0,0,0,0,0,0,0,0,0, p, cha);
  } else {
    P(11,0,0,0,0,0,0,0,0, p, cha);
    P(10,0,0,1,1,1,1,0,0, p, cha);
    P( 9,0,1,0,0,0,0,1,0, p, cha);
    P( 8,1,0,0,0,1,1,1,0, p, cha);
    P( 7,1,0,0,1,0,0,1,0, p, cha);
    P( 6,1,0,0,1,0,0,1,0, p, cha);
    P( 5,1,0,0,1,0,0,1,0, p, cha);
    P( 4,1,0,0,1,0,0,1,0, p, cha);
    P( 3,1,0,0,1,1,1,1,0, p, cha);
    P( 2,0,1,0,0,0,0,0,0, p, cha);
    P( 1,0,0,1,1,1,1,1,0, p, cha);
    P( 0,0,0,0,0,0,0,0,0, p, cha);
  }
  vec2 gp = vec2(
    mod((gl_FragCoord.x + 1.5) / zoom, chx),
    mod((gl_FragCoord.y + 3.0) / zoom, chy)
  );
  vec3 c = vec3(0.0);
  if (gp.x < 1.5 || gp.y < 3.0) { c = vec3(0.0, 0.0045, 0.0); }
  vec3 col = prgm1.xyz / max(prgm1.x, max(prgm1.y, prgm1.z));
  vec4 charColor = vec4(cha * col, 1.0);
  vec4 color = vec4(mix(prgm1, charColor, amount).xyz, 1.0);
  color.xyz += c;
  float frameTime = (customTime) ? floor(time * frameScale) / frameScale : time;
  color.xyz += gaussgrain(frameTime) * 0.045;
  color.xyz = mix(color.xyz, vec3(0.01, color.y, 0.03), 0.12);
  gl_FragColor = color;
}

// ╔═════════════╦════════════════╗
// ║ Marco Gomez ║ https://mgz.me ║
// ╚═════════════╩════════════════╝
precision highp float;

uniform sampler2D prgm2Texture;
uniform vec2 resolution;

const float threshold = 1.2;

void main(void) {
  vec2 uv = gl_FragCoord.xy / resolution.xy;
  gl_FragColor = texture2D(prgm2Texture, uv);
  if (length(gl_FragColor.rgb) < threshold) { gl_FragColor = vec4(0.0); }
}

// ╔═════════════╦════════════════╗
// ║ Marco Gomez ║ https://mgz.me ║
// ╚═════════════╩════════════════╝
precision highp float;

uniform sampler2D prgm3Texture;
uniform vec2 resolution;
uniform float fft;

const float PI = acos(-1.0);
const float TAU = PI * 2.0;
const float gaussf = 1.0 / sqrt(TAU);
const float width = 30.0;

float gaussian(float x, float sigma) {
  x /= sigma;
  return gaussf / (sigma * exp(0.5 * x * x));
}

void main(void) {
  float blur = 5.0 + fft;
  vec2 uv = gl_FragCoord.xy / resolution.xy;
  gl_FragColor = vec4(0.0);
  float total = 0.0;
  for (float x = -width; x < width; x++) {
    float weight = gaussian(x, blur);
    gl_FragColor += vec4(
      texture2D(
        prgm3Texture,
        (gl_FragCoord.xy + vec2(x, 0.0)) / resolution.xy
      ).rgb * weight, weight
    );
  }
  gl_FragColor.rgb /= gl_FragColor.a;
}

// ╔═════════════╦════════════════╗
// ║ Marco Gomez ║ https://mgz.me ║
// ╚═════════════╩════════════════╝
precision highp float;

uniform sampler2D prgm4Texture;
uniform vec2 resolution;
uniform float fft;

const float PI = acos(-1.0);
const float TAU = PI * 2.0;
const float gaussf = 1.0 / sqrt(TAU);
const float height = 30.0;

float gaussian(float x, float sigma) {
  x /= sigma;
  return gaussf / (sigma * exp(0.5 * x * x));
}

void main(void) {
  float blur = 4.0 + fft;
  vec2 uv = gl_FragCoord.xy / resolution.xy;
  gl_FragColor = vec4(0.0);
  float total = 0.0;
  for (float y = -height; y < height; y++) {
    float weight = gaussian(y, blur);
    gl_FragColor += vec4(
      texture2D(
        prgm4Texture,
        (gl_FragCoord.xy + vec2(0.0, y)) / resolution.xy
      ).rgb * weight, weight
    );
  }
  gl_FragColor.rgb /= gl_FragColor.a;
}

// ╔═════════════╦════════════════╗
// ║ Marco Gomez ║ https://mgz.me ║
// ╚═════════════╩════════════════╝
precision highp float;

uniform sampler2D prgm2Texture;
uniform sampler2D prgm5Texture;
uniform vec2 resolution;
uniform float fft;

void main(void) {
  float strength = 1.5 + fft * 2.0;
  vec2 uv = gl_FragCoord.xy / resolution.xy;
  gl_FragColor = texture2D(prgm2Texture, uv);
  gl_FragColor += texture2D(prgm5Texture, uv) * strength;
}

// ╔═════════════╦════════════════╗
// ║ Marco Gomez ║ https://mgz.me ║
// ╚═════════════╩════════════════╝
precision highp float;

uniform sampler2D prgm6Texture;
uniform sampler2D prgm7Texture;
uniform vec2 resolution;
uniform float time;
uniform float fft;

float hash(vec2 p) {
  return fract(sin(dot(p, vec2(41.0, 289.0))) * 45758.5453);
}

vec4 when(vec4 x, float y) {
  return max(sign(x - y), 0.0);
}

void main(void) {
  vec2 uv = gl_FragCoord.xy / resolution.xy;
  vec4 col = texture2D(prgm6Texture, uv);
  vec4 old = texture2D(prgm7Texture, uv);
  if (mod(gl_FragCoord.y - 0.5, 3.0) == 0.0) { old *= 0.0; }
  vec4 oc = col;
  float w = 0.1;
  vec2 a = vec2(uv.x - 0.5, uv.y - 0.66);
  vec2 b = a * 0.15 / float(10.0);
  uv += b * (hash(uv.xy + fract(time)) * 2.0);
  if (mod(floor(gl_FragCoord.y), 2.0) == 0.0) {
    for (float i = 1.0; i > 0.9; i-= 0.00125) {
      uv -= 0.5;
      uv *= i;
      uv += 0.5;
      col += texture2D(prgm6Texture, uv) * w * (1.5 + fft * 0.5);
      w *= 0.95 + (fft * 0.02);
    }
    col *= 0.7;
  }
  col = mix(oc, col, 0.25);
  vec4 new = col;
  old *= (0.6 + fft * 0.7) * when(old, 0.1);
  col = max(new, old);
  gl_FragColor = col;
}