{
  "license": "CC0-1.0",
  "shader": {
    "id": "wy4iczdt",
    "title": "Pocket Lava",
    "license": "CC0-1.0",
    "provenance_type": "witnessed_generation",
    "made_with": "glslop",
    "status": "active",
    "compile_ok": true,
    "tags": [
      "pixel-art",
      "dithering",
      "gameboy",
      "metaballs",
      "retro"
    ],
    "parents": [],
    "author": "zazi5inxhmgi",
    "author_name": "ufffd",
    "author_url": "/u/ufffd",
    "created_at": "2026-06-18T19:01:20.722Z",
    "poster_url": "/posters/wy4iczdt.avif",
    "stats": {
      "slops": 0,
      "views": 119,
      "forks": 0
    },
    "self": "/api/v1/shaders/wy4iczdt",
    "isf": "/*{\n  \"DESCRIPTION\": \"Handheld dream: morphing lava-lamp metaballs rendered the way a 1989 dot-matrix LCD would have shown them - a low virtual resolution, four shades of swamp-green, and 8x8 ordered (Bayer) dithering standing in for every gradient, complete with the faint grid between liquid-crystal cells. The blobs orbit closed loops for a seamless retro loop.\",\n  \"CREDIT\": \"glslop agent (Claude)\",\n  \"CATEGORIES\": [\"pixel-art\", \"dithering\", \"retro\", \"gameboy\", \"metaballs\"],\n  \"INPUTS\": [\n    { \"NAME\": \"speed\",  \"TYPE\": \"float\", \"DEFAULT\": 1.0,   \"MIN\": 0.0, \"MAX\": 3.0 },\n    { \"NAME\": \"res\",    \"TYPE\": \"float\", \"DEFAULT\": 150.0, \"MIN\": 48.0, \"MAX\": 300.0 },\n    { \"NAME\": \"blobs\",  \"TYPE\": \"long\",  \"DEFAULT\": 5,     \"MIN\": 2,   \"MAX\": 7 },\n    { \"NAME\": \"spread\", \"TYPE\": \"float\", \"DEFAULT\": 1.25,  \"MIN\": 0.5, \"MAX\": 1.6 },\n    { \"NAME\": \"grid\",   \"TYPE\": \"float\", \"DEFAULT\": 0.5,   \"MIN\": 0.0, \"MAX\": 1.0 }\n  ]\n}*/\n\n#define PI  3.14159265359\n#define TAU 6.28318530718\nconst float PERIOD = 16.0;\n\n// recursive ordered (Bayer) dither, no bitwise ops\nfloat bayer2(vec2 a){ a = floor(a); return fract(a.x*0.5 + a.y*a.y*0.75); }\nfloat bayer4(vec2 a){ return bayer2(0.5*a)*0.25 + bayer2(a); }\nfloat bayer8(vec2 a){ return bayer4(0.5*a)*0.25 + bayer2(a); }\n\nvoid main(){\n  float pxSize = RENDERSIZE.y / res;\n  vec2 pc = floor(gl_FragCoord.xy / pxSize);                 // virtual pixel coords\n  vec2 uv = (2.0*(pc*pxSize + 0.5*pxSize) - RENDERSIZE.xy) / RENDERSIZE.y;\n\n  float ph = fract(TIME * speed / PERIOD);\n  float th = TAU * ph;\n\n  // morphing metaballs on closed orbits\n  float field = 0.0;\n  for(int k = 0; k < 7; k++){\n    if(k >= int(blobs)) break;\n    float fk = float(k);\n    float om = (mod(fk, 2.0) < 0.5) ? 1.0 : 2.0;             // integer turns -> loop\n    float R  = (0.34 + 0.15*fk) * spread;\n    float ph2 = fk*2.39996;\n    vec2  c  = R*vec2(cos(om*th + ph2), sin(om*th*1.0 - ph2*1.3));\n    vec2  d  = uv - c;\n    field += (0.060 + 0.012*fk) / (dot(d,d) + 0.035);\n  }\n  field = smoothstep(0.5, 2.1, field);                        // shape the blob falloff\n\n  // dithered quantization to 4 levels\n  float lv = clamp(floor(field*3.0 + bayer8(pc)), 0.0, 3.0);\n\n  // Game Boy DMG palette\n  vec3 g0 = vec3(0.06, 0.22, 0.06);\n  vec3 g1 = vec3(0.19, 0.39, 0.13);\n  vec3 g2 = vec3(0.55, 0.67, 0.06);\n  vec3 g3 = vec3(0.61, 0.74, 0.06);\n  vec3 col = lv < 0.5 ? g0 : (lv < 1.5 ? g1 : (lv < 2.5 ? g2 : g3));\n\n  // faint LCD cell grid between virtual pixels\n  vec2 sub = fract(gl_FragCoord.xy / pxSize);\n  float line = min(smoothstep(0.0, 0.08, sub.x) * smoothstep(0.0, 0.08, sub.y),\n                   smoothstep(0.0, 0.08, 1.0 - sub.x) * smoothstep(0.0, 0.08, 1.0 - sub.y));\n  col *= 1.0 - 0.18 * grid * (1.0 - line);\n\n  // slight green-screen vignette\n  vec2 vv = (2.0*gl_FragCoord.xy - RENDERSIZE.xy) / RENDERSIZE.y;\n  col *= 1.0 - 0.12 * dot(vv, vv);\n\n  gl_FragColor = vec4(col, 1.0);\n}\n",
    "generator": {
      "model": "claude-opus-4-8",
      "provider": null,
      "prompt": null,
      "params": null
    }
  }
}