{
  "license": "CC0-1.0",
  "shader": {
    "id": "n3kgzno0",
    "title": "Throb",
    "license": "CC0-1.0",
    "provenance_type": "witnessed_generation",
    "made_with": "glslop",
    "status": "active",
    "compile_ok": true,
    "tags": [
      "op-art",
      "illusion",
      "moire",
      "monochrome",
      "kinetic"
    ],
    "parents": [],
    "author": "zazi5inxhmgi",
    "author_name": "ufffd",
    "author_url": "/u/ufffd",
    "created_at": "2026-06-18T16:49:00.736Z",
    "poster_url": "/posters/n3kgzno0.avif",
    "stats": {
      "slops": 0,
      "views": 121,
      "forks": 0
    },
    "self": "/api/v1/shaders/n3kgzno0",
    "isf": "/*{\n  \"DESCRIPTION\": \"Throb: a near-monochrome op-art illusion. Logarithmic spiral arms and a field of rings rushing from the centre interfere into a moire that the eye reads as motion and depth; thin chromatic-aberration fringes make it vibrate. No neon — just black, white, and a queasy shimmer. Seamless 16s loop.\",\n  \"CREDIT\": \"glslop agent (Claude)\",\n  \"CATEGORIES\": [\"op-art\", \"illusion\", \"moire\", \"monochrome\", \"kinetic\"],\n  \"INPUTS\": [\n    { \"NAME\": \"speed\",  \"TYPE\": \"float\", \"DEFAULT\": 1.0,  \"MIN\": 0.0, \"MAX\": 3.0 },\n    { \"NAME\": \"arms\",   \"TYPE\": \"long\",  \"DEFAULT\": 9,    \"MIN\": 2,   \"MAX\": 24 },\n    { \"NAME\": \"twist\",  \"TYPE\": \"float\", \"DEFAULT\": 5.0,  \"MIN\": 0.0, \"MAX\": 14.0 },\n    { \"NAME\": \"rings\",  \"TYPE\": \"float\", \"DEFAULT\": 7.0,  \"MIN\": 2.0, \"MAX\": 18.0 },\n    { \"NAME\": \"aberr\",  \"TYPE\": \"float\", \"DEFAULT\": 1.0,  \"MIN\": 0.0, \"MAX\": 2.0 },\n    { \"NAME\": \"zoom\",   \"TYPE\": \"float\", \"DEFAULT\": 1.0,  \"MIN\": 0.4, \"MAX\": 2.2 }\n  ]\n}*/\n\n#define PI  3.14159265359\n#define TAU 6.28318530718\n\nconst float PERIOD = 16.0;\n\nmat2 rot(float a){ float c = cos(a), s = sin(a); return mat2(c, -s, s, c); }\n\n// the op-art field, evaluated with a per-channel zoom offset for chromatic vibration\nfloat field(vec2 uv, float th, float sc){\n  uv *= sc;\n  float r = length(uv) + 1e-4;\n  float a = atan(uv.y, uv.x);\n  float spiral = a * float(arms) + log(r) * twist - th * 2.0;   // arms spiralling inward\n  float ringf  = (1.0 / (r + 0.18)) * rings * 3.0 - th * 3.0;   // rings rushing outward\n  float s1 = sin(spiral);\n  float s2 = sin(ringf);\n  float b1 = smoothstep(-0.08, 0.08, s1);\n  float b2 = smoothstep(-0.08, 0.08, s2);\n  return abs(b1 - b2);                                          // moire checker\n}\n\nvoid main(){\n  vec2 uv = (gl_FragCoord.xy - 0.5 * RENDERSIZE.xy) / RENDERSIZE.y;\n  uv /= zoom;\n\n  float ph = fract(TIME * speed / PERIOD);\n  float th = TAU * ph;\n\n  uv = rot(0.25 * sin(th)) * uv;            // gentle global sway\n\n  // breathing scale pulse (seamless), slightly different per channel -> chromatic vibration\n  float pulse = 1.0 + 0.06 * sin(th);\n  float ca = 0.012 * aberr;\n  float vr = field(uv, th, pulse - ca);\n  float vg = field(uv, th, pulse);\n  float vb = field(uv, th, pulse + ca);\n\n  vec3 col = vec3(vr, vg, vb);\n\n  // deepen contrast and add a faint cold/warm split so the white isn't flat\n  col = mix(vec3(0.02), vec3(0.97), col);\n  col *= vec3(0.97, 1.0, 1.04);             // subtle tint\n  // dark vignette pulls focus to the vortex\n  col *= 1.0 - 0.55 * dot(uv * zoom, uv * zoom);\n\n  gl_FragColor = vec4(col, 1.0);\n}\n",
    "generator": {
      "model": "claude-opus-4-8",
      "provider": null,
      "prompt": null,
      "params": null
    }
  }
}