{
  "license": "CC0-1.0",
  "shader": {
    "id": "pu2wh1yj",
    "title": "Tide Cathedral II",
    "license": "CC0-1.0",
    "provenance_type": "user_upload",
    "made_with": "glslop",
    "status": "active",
    "compile_ok": true,
    "render_hash": "2400bd3e3cbd1224",
    "tags": [
      "stained-glass",
      "voronoi",
      "kaleidoscope",
      "rose-window",
      "caustics",
      "seamless-loop",
      "water"
    ],
    "parents": [],
    "author": "zazi5inxhmgi",
    "author_name": "ufffd",
    "author_url": "/u/ufffd",
    "created_at": "2026-08-01T00:40:54.288Z",
    "poster_url": "/posters/pu2wh1yj.avif",
    "stats": {
      "slops": 0,
      "views": 139,
      "forks": 0
    },
    "self": "/api/v1/shaders/pu2wh1yj",
    "isf": "/*{\n  \"DESCRIPTION\": \"Tide Cathedral II — the flooded rose window, deepened. 12-fold stained glass breathing under water, stone mullions, travelling glints, and a counter-rotating sea of glass beyond the circlet. Seamless 16s loop.\",\n  \"CREDIT\": \"kimi-k2-thinking\",\n  \"INPUTS\": [\n    { \"NAME\": \"scale\",  \"TYPE\": \"float\", \"DEFAULT\": 3.2,  \"MIN\": 2.0, \"MAX\": 9.0 },\n    { \"NAME\": \"warp\",   \"TYPE\": \"float\", \"DEFAULT\": 0.28, \"MIN\": 0.0, \"MAX\": 0.7 },\n    { \"NAME\": \"hue\",    \"TYPE\": \"float\", \"DEFAULT\": 0.58, \"MIN\": 0.0, \"MAX\": 1.0 },\n    { \"NAME\": \"glow\",   \"TYPE\": \"float\", \"DEFAULT\": 1.0,  \"MIN\": 0.2, \"MAX\": 2.0 }\n  ]\n}*/\n\n#define PI  3.14159265359\n#define TAU 6.28318530718\n#define PERIOD 16.0\n#define SECTORS 12.0\n\nmat2 rot(float a){ float c = cos(a), s = sin(a); return mat2(c, -s, s, c); }\n\nvec2 hash2(vec2 p){\n  p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3)));\n  return fract(sin(p) * 43758.5453);\n}\n\nfloat hash1(vec2 p){ return fract(sin(dot(p, vec2(41.3, 289.1))) * 43758.5453); }\n\n// loop-safe value noise: offset orbits a circle over the period\nfloat vnoise(vec2 p, float ang){\n  p += 1.5 * vec2(cos(ang), sin(ang));\n  vec2 i = floor(p), f = fract(p);\n  vec2 u = f * f * (3.0 - 2.0 * f);\n  return mix(mix(hash1(i),               hash1(i + vec2(1, 0)), u.x),\n             mix(hash1(i + vec2(0, 1)),  hash1(i + vec2(1, 1)), u.x), u.y);\n}\n\n// jewel palette: deep, cohesive, spread across the wheel\nvec3 pal(float t){\n  return 0.5 + 0.5 * cos(TAU * (t + vec3(0.0, 0.33, 0.67)));\n}\n\n// ---- deep glass sea: a dim counter-rotating second window, seen beyond the circlet ----\nvec3 seaGlass(vec2 uv, float ang){\n  float r0 = length(uv);\n  float a0 = atan(uv.y, uv.x) - ang;\n  float sect = TAU / SECTORS;\n  a0 = mod(a0, sect);\n  a0 = abs(a0 - 0.5 * sect);\n  vec2 rp = vec2(cos(a0), sin(a0)) * r0;\n\n  float cellScale = scale * 0.55;\n  vec2 q = rp * cellScale;\n  vec2 w = vec2(vnoise(q * 0.9 + 3.1, ang) - 0.5,\n                vnoise(q * 0.9 - 7.7, ang + PI) - 0.5);\n  vec2 p = q + warp * scale * 0.35 * w;\n\n  vec2 ip = floor(p), fp = fract(p);\n  float f1 = 8.0, f2 = 8.0;\n  vec2 siteId = vec2(0.0);\n  for (int j = -1; j <= 1; j++)\n  for (int i = -1; i <= 1; i++){\n    vec2 g = vec2(float(i), float(j));\n    vec2 h = hash2(ip + g);\n    vec2 o = 0.5 + 0.42 * vec2(sin(ang + TAU * h.x), cos(ang + TAU * h.y));\n    vec2 r = g + o - fp;\n    float d = dot(r, r);\n    if (d < f1){ f2 = f1; f1 = d; siteId = ip + g; }\n    else if (d < f2){ f2 = d; }\n  }\n  f1 = sqrt(f1); f2 = sqrt(f2);\n  float edge = f2 - f1;\n\n  float id = hash1(siteId);\n  vec3 tint = pal(hue + 0.30 + 0.55 * id + 0.45 * (a0 / sect) + 0.30 * r0\n                  + 0.08 * sin(ang + TAU * id));\n  tint = mix(tint, tint * tint, 0.45);\n\n  float heart = exp(-2.1 * f1);\n  float caust = pow(0.5 + 0.5 * sin(dot(p, vec2(2.6, 1.8)) - 2.0 * ang), 3.0)\n              + pow(0.5 + 0.5 * sin(dot(p, vec2(-1.4, 2.9)) + 3.0 * ang), 3.0);\n  float glass = (0.30 + 0.55 * heart) + 0.45 * caust * (0.3 + 0.7 * heart);\n\n  vec3 col = tint * glass;\n  float line = 1.0 - smoothstep(0.0, 0.09, edge);\n  col = mix(col, vec3(0.014, 0.012, 0.034), line);\n\n  col = mix(col, vec3(dot(col, vec3(0.3333))), 0.4) * 0.35;   // dim, distant\n  return col;\n}\n\nvoid main(){\n  vec2 uv = (gl_FragCoord.xy - 0.5 * RENDERSIZE) / RENDERSIZE.y;\n  float ph  = fract(TIME / PERIOD);\n  float ang = TAU * ph;\n\n  // breathing zoom\n  uv *= 1.0 + 0.015 * sin(ang);\n\n  // ---- rose window fold: mirror the plane into sectors, one full turn per loop ----\n  float r0 = length(uv);\n  float a0 = atan(uv.y, uv.x) + ang;\n  float sect = TAU / SECTORS;\n  a0 = mod(a0, sect);\n  a0 = abs(a0 - 0.5 * sect);\n  vec2 rp = vec2(cos(a0), sin(a0)) * r0;\n\n  // cells tighten toward the rim, breathing open at the medallion\n  float cellScale = scale * mix(0.85, 1.5, smoothstep(0.02, 0.55, r0));\n\n  // liquid domain warp — two orbiting noise fields\n  vec2 q = rp * cellScale;\n  vec2 w = vec2(vnoise(q * 0.9 + 3.1, ang) - 0.5,\n                vnoise(q * 0.9 - 7.7, ang + PI) - 0.5);\n  vec2 p = q + warp * scale * 0.5 * w;\n\n  // ---- animated Voronoi: sites breathe on integer multiples of the loop ----\n  vec2 ip = floor(p), fp = fract(p);\n  float f1 = 8.0, f2 = 8.0;\n  vec2 siteId = vec2(0.0);\n  vec2 toSite = vec2(0.0);\n  for (int j = -1; j <= 1; j++)\n  for (int i = -1; i <= 1; i++){\n    vec2 g = vec2(float(i), float(j));\n    vec2 h = hash2(ip + g);\n    vec2 o = 0.5 + 0.42 * vec2(sin(ang + TAU * h.x), cos(ang + TAU * h.y));\n    vec2 r = g + o - fp;\n    float d = dot(r, r);\n    if (d < f1){ f2 = f1; f1 = d; siteId = ip + g; toSite = r; }\n    else if (d < f2){ f2 = d; }\n  }\n  f1 = sqrt(f1); f2 = sqrt(f2);\n  float edge = f2 - f1;                    // distance-to-border proxy\n\n  float id = hash1(siteId);\n  float accent = hash1(siteId + 7.3);\n\n  // ---- cell glass ----\n  vec3 tint = pal(hue + 0.55 * id + 0.45 * (a0 / sect) + 0.30 * r0 + 0.08 * sin(ang + TAU * id));\n  tint = mix(tint, tint * tint, 0.45);     // deepen saturation toward jewel tones\n  tint = mix(tint, vec3(0.95, 0.45, 0.10), smoothstep(0.72, 0.9, accent));\n  tint = mix(tint, vec3(0.46, 0.14, 0.72), smoothstep(0.10, 0.0, accent)); // violet panes\n  tint *= 0.78 + 0.38 * hash1(siteId + 3.9); // per-pane luminance variation\n\n  // streaky hand-rolled glass: anisotropic noise along a per-pane direction\n  vec2 sdir = rot(TAU * id) * vec2(1.0, 0.0);\n  float streak = vnoise(vec2(dot(p, sdir) * 6.0, dot(p, sdir.yx * vec2(-1.0, 1.0)) * 0.8), 2.0 * ang);\n  streak = 0.82 + 0.36 * streak;\n\n  // inner glow: brighter toward cell heart, softly pooled\n  float heart = exp(-2.1 * f1);\n  // caustic shimmer — two integer-multiple travelling waves crossing\n  float caust = pow(0.5 + 0.5 * sin(dot(p, vec2(2.6, 1.8)) - 2.0 * ang), 3.0)\n              + pow(0.5 + 0.5 * sin(dot(p, vec2(-1.4, 2.9)) + 3.0 * ang), 3.0);\n  float glass = (0.30 + 0.55 * heart) * streak + 0.45 * caust * (0.3 + 0.7 * heart);\n\n  vec3 col = tint * glass * glow;\n\n  // faint vertical light gradient, as if the window is lit from above\n  col *= 0.8 + 0.45 * smoothstep(-0.7, 0.8, uv.y);\n\n  // ---- central medallion: a warm heart of light with radiating spokes ----\n  float spoke = pow(0.5 + 0.5 * cos((atan(uv.y, uv.x) + ang) * SECTORS), 2.0);\n  float halo = exp(-5.0 * r0);\n  col += vec3(0.95, 0.58, 0.22) * halo * (0.36 + 0.40 * spoke + 0.30 * caust);\n\n  // molten ripples in the gold\n  col += vec3(1.0, 0.8, 0.5) * 0.07 * (0.5 + 0.5 * sin(r0 * 55.0 - 2.0 * ang)) * exp(-2.5 * r0);\n\n  // dust motes drifting in the beam\n  float mote = smoothstep(0.955, 0.995, vnoise(p * 24.0 + 31.0, 2.0 * ang));\n  col += mote * vec3(1.0, 0.88, 0.65) * 1.1 * smoothstep(0.47, 0.40, r0);\n\n  // ---- lead came ----\n  float line = 1.0 - smoothstep(0.0, 0.09, edge);       // thick dark grout\n  float rim  = (1.0 - smoothstep(0.0, 0.22, edge))\n             * smoothstep(0.02, 0.09, edge);            // soft halo hugging the lead\n  vec3 grout = vec3(0.014, 0.012, 0.034) * (0.7 + 0.6 * caust);\n  col = mix(col, grout, line);\n  col += rim * tint * 0.35;                              // light bleeding around the lead\n\n  // catch-light on the lead: thin bright seam on the light-facing side\n  float seam = smoothstep(0.05, 0.015, edge) * (1.0 - line);\n  col += seam * vec3(0.35, 0.4, 0.55) * (0.25 + 0.45 * caust);\n\n  // ---- travelling glints: sparse pane centers catching the sun ----\n  float gsel = hash1(siteId + 11.7);\n  float tw = pow(max(sin(2.0 * ang + TAU * gsel), 0.0), 6.0);\n  float glint = step(0.88, gsel) * tw * smoothstep(0.28, 0.06, f1);\n  col += glint * vec3(1.2, 1.15, 1.0) * (0.4 + 0.6 * caust);\n\n  // ---- stone tracery: radial mullions + concentric rings ----\n  float md = a0 * r0;                                     // arc distance to sector seam\n  float mull = 1.0 - smoothstep(0.006, 0.015, md);\n  mull *= smoothstep(0.055, 0.11, r0) * (1.0 - smoothstep(0.37, 0.425, r0));\n  float rs2 = min(abs(r0 - 0.16), abs(r0 - 0.30));\n  float ringStone = 1.0 - smoothstep(0.005, 0.012, rs2);\n  ringStone *= 1.0 - smoothstep(0.37, 0.425, r0);\n  float stoneMask = max(mull, ringStone);\n  vec3 stone = vec3(0.030, 0.027, 0.055) * (0.7 + 0.6 * caust);\n  stone += pal(hue + 0.3) * 0.03 * stoneMask;             // faint reflected glasslight\n  col = mix(col, stone, stoneMask);\n\n  // ---- the deep glass sea ghosting through the panes ----\n  vec3 sea = seaGlass(uv, ang);\n  col = mix(col, col * 0.8 + sea * 0.6, 0.12 * smoothstep(0.10, 0.30, edge));\n\n  // ---- architectural ring: a lead circlet with a gilt edge ----\n  float ringD = abs(r0 - 0.44);\n  float ring = 1.0 - smoothstep(0.0, 0.028, ringD);\n  float gilt = smoothstep(0.055, 0.028, ringD) * (1.0 - ring);\n  col = mix(col, vec3(0.008, 0.007, 0.02), ring);\n  col += gilt * vec3(0.85, 0.62, 0.28) * (0.35 + 0.65 * caust);\n\n  // beyond the circlet: the counter-rotating sea of glass, sinking into dark\n  float outer = smoothstep(0.45, 0.52, r0);\n  col = mix(col, sea * (1.0 - 0.6 * smoothstep(0.5, 0.75, r0)), outer);\n\n  // vignette + tonemap + gamma\n  col *= 1.0 - 0.42 * dot(uv, uv);\n  // saturation boost to survive the tone-map\n  col = mix(vec3(dot(col, vec3(0.3333))), col, 1.18);\n  col = 1.0 - exp(-col * 1.35);\n  col = pow(max(col, 0.0), vec3(0.85));\n  gl_FragColor = vec4(col, 1.0);\n}\n"
  }
}