{
  "license": "CC0-1.0",
  "shader": {
    "id": "6pxkqozk",
    "title": "Chrome Current: Prism Vortex",
    "license": "CC0-1.0",
    "provenance_type": "witnessed_generation",
    "made_with": "glslop",
    "status": "active",
    "compile_ok": true,
    "tags": [
      "liquid",
      "chrome",
      "feedback",
      "dispersion",
      "metallic"
    ],
    "parents": [
      "7ct3caq1"
    ],
    "author": "zazi5inxhmgi",
    "author_name": "ufffd",
    "author_url": "/u/ufffd",
    "created_at": "2026-07-13T22:44:49.728Z",
    "poster_url": "/posters/6pxkqozk.avif",
    "stats": {
      "slops": 0,
      "views": 129,
      "forks": 1
    },
    "self": "/api/v1/shaders/6pxkqozk",
    "isf": "/*{\n  \"DESCRIPTION\": \"Sculptural liquid chrome with chromatic dispersion, orbiting droplets, and bounded long-exposure flow.\",\n  \"INPUTS\": [\n    { \"NAME\": \"motion\", \"TYPE\": \"float\", \"DEFAULT\": 1.05, \"MIN\": 0.0, \"MAX\": 2.5 },\n    { \"NAME\": \"swirl\", \"TYPE\": \"float\", \"DEFAULT\": 1.15, \"MIN\": 0.0, \"MAX\": 2.0 },\n    { \"NAME\": \"warp\", \"TYPE\": \"float\", \"DEFAULT\": 1.0, \"MIN\": 0.0, \"MAX\": 2.0 },\n    { \"NAME\": \"trail\", \"TYPE\": \"float\", \"DEFAULT\": 0.9980, \"MIN\": 0.97, \"MAX\": 0.9998 },\n    { \"NAME\": \"sparkle\", \"TYPE\": \"float\", \"DEFAULT\": 0.72, \"MIN\": 0.0, \"MAX\": 1.5 },\n    { \"NAME\": \"hueShift\", \"TYPE\": \"float\", \"DEFAULT\": 0.08, \"MIN\": 0.0, \"MAX\": 1.0 }\n  ],\n  \"PASSES\": [\n    { \"TARGET\": \"paint\", \"PERSISTENT\": true, \"FLOAT\": true },\n    {}\n  ]\n}*/\n\n#define TAU 6.28318530718\n\nvec3 palette(float t) {\n  return 0.5 + 0.5 * cos(TAU * (t + hueShift + vec3(0.00, 0.29, 0.57)));\n}\n\nvec2 vortex(vec2 p, vec2 center, float spin) {\n  vec2 d = p - center;\n  float influence = exp(-dot(d, d) * 13.0);\n  return vec2(-d.y, d.x) * influence * spin;\n}\n\nfloat droplet(vec2 p, vec2 center, float size) {\n  return 1.0 - smoothstep(0.0, size, length(p - center));\n}\n\nvoid main() {\n  vec2 uv = isf_FragNormCoord;\n\n  if (PASSINDEX == 0) {\n    float frameStep = min(TIMEDELTA * 60.0, 2.0);\n    float t = TIME * motion;\n    vec2 p = uv - 0.5;\n    p.x *= RENDERSIZE.x / RENDERSIZE.y;\n\n    vec2 a = vec2(0.27 * cos(t * 0.39), 0.24 * sin(t * 0.51));\n    vec2 b = vec2(0.25 * cos(t * 0.35 + 3.1), 0.28 * sin(t * 0.44 + 2.2));\n    vec2 c = vec2(0.19 * sin(t * 0.63 + 0.4), 0.29 * cos(t * 0.31 - 0.7));\n    vec2 vel = vortex(p, a, 2.3) + vortex(p, b, -2.0) + vortex(p, c, 1.35);\n    vel += vec2(\n      sin(TAU * uv.y * 2.0 + t * 0.42),\n      cos(TAU * uv.x * 2.0 - t * 0.33)\n    ) * (0.052 + 0.025 * warp);\n    vel += 0.026 * warp * vec2(sin(p.y * 19.0 + t), cos(p.x * 17.0 - t * 0.8));\n    vel *= swirl;\n    vel.x /= RENDERSIZE.x / RENDERSIZE.y;\n\n    vec2 back = uv - vel * (0.0145 * frameStep * motion);\n    vec2 px = 1.0 / RENDERSIZE;\n    vec3 old = IMG_NORM_PIXEL(paint, back).rgb * 0.64;\n    old += IMG_NORM_PIXEL(paint, back + vec2(px.x, 0.0)).rgb * 0.09;\n    old += IMG_NORM_PIXEL(paint, back - vec2(px.x, 0.0)).rgb * 0.09;\n    old += IMG_NORM_PIXEL(paint, back + vec2(0.0, px.y)).rgb * 0.09;\n    old += IMG_NORM_PIXEL(paint, back - vec2(0.0, px.y)).rgb * 0.09;\n    old *= pow(trail, frameStep);\n\n    // Slight channel separation makes the stored trail feel like reflective glass.\n    old.r = max(old.r, IMG_NORM_PIXEL(paint, back + px * 1.35).r * 0.11);\n    old.b = max(old.b, IMG_NORM_PIXEL(paint, back - px * 1.35).b * 0.11);\n\n    float injectA = droplet(p, a, 0.047);\n    float injectB = droplet(p, b, 0.041);\n    float injectC = droplet(p, c, 0.033);\n    float satellite = droplet(p, 0.56 * a - 0.30 * b, 0.018);\n    vec3 fresh = palette(t * 0.032 + length(a) + 0.10) * injectA;\n    fresh += palette(t * 0.032 + length(b) + 0.62) * injectB;\n    fresh += palette(t * 0.032 + length(c) + 0.36) * injectC;\n    fresh += palette(t * 0.08 + 0.91) * satellite * (0.45 + 0.35 * sin(t * 3.0));\n\n    float ringA = 1.0 - smoothstep(0.0, 0.018, abs(length(p - a) - 0.075));\n    float ringB = 1.0 - smoothstep(0.0, 0.014, abs(length(p - b) - 0.061));\n    fresh += palette(t * 0.04 + 0.24) * (ringA * 0.23 + ringB * 0.18);\n\n    float boundary = smoothstep(0.0, 0.03, uv.x)\n                   * smoothstep(0.0, 0.03, 1.0 - uv.x)\n                   * smoothstep(0.0, 0.03, uv.y)\n                   * smoothstep(0.0, 0.03, 1.0 - uv.y);\n    vec3 next = max(old, fresh * (0.40 + 0.10 * sparkle)) * boundary;\n\n    // Per-channel soft knees prevent positive feedback from turning the whole canvas white.\n    vec3 hot = max(next - vec3(0.70), vec3(0.0));\n    next = min(next, vec3(0.70)) + hot / (1.0 + 0.82 * hot);\n    gl_FragColor = vec4(clamp(next, 0.0, 1.45), 1.0);\n  } else {\n    vec2 px = 1.0 / RENDERSIZE;\n    vec2 q = isf_FragNormCoord;\n    vec3 c0 = IMG_THIS_PIXEL(paint).rgb;\n    vec3 cR = IMG_NORM_PIXEL(paint, q + vec2(px.x * 1.7, 0.0)).rgb;\n    vec3 cL = IMG_NORM_PIXEL(paint, q - vec2(px.x * 1.7, 0.0)).rgb;\n    vec3 cU = IMG_NORM_PIXEL(paint, q + vec2(0.0, px.y * 1.7)).rgb;\n    float l = dot(c0, vec3(0.3333));\n    float lx = dot(cR, vec3(0.3333));\n    float ly = dot(cU, vec3(0.3333));\n    vec2 grad = vec2(lx - l, ly - l);\n    float rim = clamp(length(grad) * 31.0, 0.0, 1.0);\n    float reflection = 0.5 + 0.5 * sin(18.0 * q.x + 12.0 * q.y + TIME * 0.48);\n    float glint = pow(max(0.0, reflection * rim), 3.0) * sparkle;\n\n    vec3 dispersed = vec3(cR.r, c0.g, cL.b);\n    vec3 chrome = mix(c0, dispersed, 0.42);\n    chrome *= 0.30 + 1.38 * l;\n    chrome += rim * palette(0.16 + l * 0.22) * (0.58 + 0.30 * sparkle);\n    chrome += glint * vec3(0.95, 0.98, 1.0);\n    chrome += pow(max(l, 0.0), 3.0) * vec3(0.75, 0.88, 1.0);\n    chrome = chrome / (1.0 + 0.60 * chrome);\n    gl_FragColor = vec4(max(chrome, 0.0), 1.0);\n  }\n}\n",
    "generator": {
      "model": "gpt-5",
      "provider": "openai",
      "prompt": null,
      "params": null
    }
  }
}