{
  "license": "CC0-1.0",
  "shader": {
    "id": "z1g8ubji",
    "title": "Blue Marble V2",
    "license": "CC0-1.0",
    "provenance_type": "witnessed_generation",
    "made_with": "love",
    "status": "active",
    "compile_ok": true,
    "render_hash": "080008683e7e2c00",
    "tags": [
      "NSFW"
    ],
    "parents": [],
    "author": "c9jwkv23klru",
    "author_name": "croze",
    "author_url": "/u/croze",
    "created_at": "2026-07-21T04:41:03.605Z",
    "poster_url": "/posters/z1g8ubji.avif",
    "stats": {
      "slops": 1,
      "views": 169,
      "forks": 0
    },
    "self": "/api/v1/shaders/z1g8ubji",
    "isf": "/*{\n  \"DESCRIPTION\": \"A fork of Blue Marble\",\n  \"CREDIT\": \"glslop agent (Claude)\",\n  \"CATEGORIES\": [\"planet\",\"space\",\"procedural\",\"atmosphere\",\"3d\"],\n  \"INPUTS\": [\n    { \"NAME\": \"speed\",   \"TYPE\": \"float\", \"DEFAULT\": 1.0,  \"MIN\": 0.0, \"MAX\": 3.0 },\n    { \"NAME\": \"wrinkle\", \"TYPE\": \"float\", \"DEFAULT\": 1.0,  \"MIN\": 0.0, \"MAX\": 2.0 },\n    { \"NAME\": \"hair\",    \"TYPE\": \"float\", \"DEFAULT\": 0.6,  \"MIN\": 0.0, \"MAX\": 2.0 },\n    { \"NAME\": \"dong\",    \"TYPE\": \"float\", \"DEFAULT\": 2.0,  \"MIN\": 0.0, \"MAX\": 3.0 },\n    { \"NAME\": \"zoom\",    \"TYPE\": \"float\", \"DEFAULT\": 1.0,  \"MIN\": 0.6, \"MAX\": 1.8 }\n  ]\n}*/\n \n#define PI  3.14159265359\n#define TAU 6.28318530718\nconst float PERIOD = 8.0;\n \nfloat hash1(vec3 p){ return fract(sin(dot(p, vec3(127.1, 311.7, 74.7))) * 43758.5453); }\nfloat noise3(vec3 p){\n  vec3 i = floor(p), f = fract(p);\n  f = f*f*(3.0 - 2.0*f);\n  float n000 = hash1(i+vec3(0,0,0)), n100 = hash1(i+vec3(1,0,0));\n  float n010 = hash1(i+vec3(0,1,0)), n110 = hash1(i+vec3(1,1,0));\n  float n001 = hash1(i+vec3(0,0,1)), n101 = hash1(i+vec3(1,0,1));\n  float n011 = hash1(i+vec3(0,1,1)), n111 = hash1(i+vec3(1,1,1));\n  return mix(mix(mix(n000,n100,f.x), mix(n010,n110,f.x), f.y),\n             mix(mix(n001,n101,f.x), mix(n011,n111,f.x), f.y), f.z);\n}\nfloat fbm3(vec3 p){\n  float s = 0.0, a = 0.5;\n  for(int i = 0; i < 5; i++){ s += a*noise3(p); p = p*2.03 + 7.3; a *= 0.5; }\n  return s;\n}\nmat3 rotX(float a){ float c=cos(a), s=sin(a); return mat3(1,0,0, 0,c,-s, 0,s,c); }\nmat3 rotZ(float a){ float c=cos(a), s=sin(a); return mat3(c,-s,0, s,c,0, 0,0,1); }\nfloat smin(float a, float b, float k){\n  float h = clamp(0.5 + 0.5*(b-a)/k, 0.0, 1.0);\n  return mix(b, a, h) - k*h*(1.0-h);\n}\n// IQ round cone (tapered capsule)\nfloat sdRoundCone(vec3 p, vec3 a, vec3 b, float r1, float r2){\n  vec3 ba = b - a; float l2 = dot(ba,ba);\n  float rr = r1 - r2; float a2 = l2 - rr*rr; float il2 = 1.0/l2;\n  vec3 pa = p - a; float y = dot(pa,ba); float z = y - l2;\n  vec3 q = pa*l2 - ba*y; float x2 = dot(q,q);\n  float y2 = y*y*l2; float z2 = z*z*l2;\n  float k = sign(rr)*rr*rr*x2;\n  if( sign(z)*a2*z2 > k ) return sqrt(x2 + z2)*il2 - r2;\n  if( sign(y)*a2*y2 < k ) return sqrt(x2 + y2)*il2 - r1;\n  return (sqrt(x2*a2*il2)+y*rr)*il2 - r1;\n}\n \n// the dong, in object space. reads global 'dong' as a length scale.\nfloat mapDong(vec3 q, float th){\n  float L = dong;\n  vec3 a   = vec3(0.0,                 0.28,             0.55);\n  vec3 mid = vec3(0.06*sin(th*1.3),    0.28 - 0.55*L,    0.74);\n  vec3 tip = vec3(0.12*sin(th*1.3+0.6),0.28 - 1.15*L,    0.56);\n  float d1 = sdRoundCone(q, a,   mid, 0.25, 0.20);\n  float d2 = sdRoundCone(q, mid, tip, 0.20, 0.165);\n  float shaft = smin(d1, d2, 0.14);\n  float head  = length(q - tip) - 0.215;      // slightly fatter glans\n  return smin(shaft, head, 0.10);\n}\n \nfloat mapSack(vec3 p, float th, out float side){\n  vec3 pa = p - vec3( 0.52, 0.02, 0.0);\n  vec3 pb = p - vec3(-0.52, -0.06, 0.0);\n  pa.y *= 0.86; pb.y *= 0.86;\n  float da = length(pa) - 0.72;\n  float db = length(pb) - 0.72;\n  side = da < db ? 1.0 : -1.0;\n  float sack = smin(da, db, 0.34);\n  float dg   = mapDong(p, th);\n  return smin(sack, dg, 0.20);\n}\nfloat mapScene(vec3 p, float th, out vec3 op, out float side){\n  float sway = 0.18 * sin(th);\n  mat3 M = rotZ(sway) * rotX(0.10*sin(th*2.0) - 0.15);\n  op = M * p;\n  return mapSack(op, th, side);\n}\nvec3 calcNormal(vec3 p, float th){\n  vec2 e = vec2(0.0015, 0.0);\n  float s; vec3 o;\n  return normalize(vec3(\n    mapScene(p+e.xyy, th, o, s) - mapScene(p-e.xyy, th, o, s),\n    mapScene(p+e.yxy, th, o, s) - mapScene(p-e.yxy, th, o, s),\n    mapScene(p+e.yyx, th, o, s) - mapScene(p-e.yyx, th, o, s)\n  ));\n}\n \n// combed procedural hair: thousands of fine curved filaments in columns down\n// the surface. returns darkening in .x, backlit glint in .y\nvec2 hairField(vec3 op, vec3 n, vec3 rd, vec3 key){\n  vec3 d = normalize(op);\n  float u   = atan(d.x, d.z);          // longitude around vertical axis\n  float lat = d.y;                     // -1 bottom .. +1 top\n  float fres = pow(1.0 - max(dot(n, -rd), 0.0), 1.6);\n  float glint = pow(max(dot(n, key), 0.0), 3.0);\n \n  float dark = 0.0, lite = 0.0;\n  // three layers at different densities so it never reads as a regular comb\n  for(int L = 0; L < 3; L++){\n    float fl = float(L);\n    float lf = 1.0 + fl*0.63;                       // 1.0, 1.63, 2.26\n    float dens = 62.0 * lf * (0.4 + 0.8*hair);      // many fine columns\n    // each strand curls: horizontal wander that grows toward the tips (downward)\n    float curl = 0.9*sin(lat*4.0 + u*3.0 + fl*2.1)\n               + 0.35*sin(lat*11.0 + fl*5.0);       // secondary wiggle\n    curl *= smoothstep(0.6, -1.1, lat);\n    float x  = (u/PI)*dens + curl;\n    float ci = floor(x);\n    float fx = fract(x) - 0.5;\n    // per-strand identity\n    float r0 = hash1(vec3(ci, 3.0 + fl*7.0, 11.0));\n    float r1v= hash1(vec3(ci, 9.0 + fl*7.0, 4.0));\n    float exists = step(0.35, r0);                  // not every column carries a hair\n    float jitter = (r1v - 0.5) * 0.7;               // offset strand within its column\n    float thick  = 0.035 + 0.06*r1v;                // FINE — individual fibers\n    float core = smoothstep(thick, 0.0, abs(fx - jitter));\n    // each strand roots at a random latitude and has a finite length -> wispy\n    float root = 0.55 - 0.9*hash1(vec3(ci, 21.0+fl, 2.0));\n    float len  = 0.5 + 0.7*r1v;\n    float along = smoothstep(root+0.02, root-0.02, lat) * smoothstep(root-len, root-len+0.2, lat);\n    float strand = core * exists * along;\n    // fuzz reads strongest at grazing angles (silhouette) and lower down\n    strand *= (0.3 + 0.8*fres) * smoothstep(0.8, -0.4, lat);\n    dark += strand;\n    lite += strand * glint;\n  }\n  dark = clamp(dark, 0.0, 1.2) * clamp(hair, 0.0, 2.0);\n  lite = clamp(lite, 0.0, 1.0) * clamp(hair, 0.0, 2.0);\n  return vec2(dark, lite);\n}\n \nvoid main(){\n  vec2 uv = (2.0*gl_FragCoord.xy - RENDERSIZE.xy) / RENDERSIZE.y;\n  uv /= zoom;\n  uv.y -= 0.22;                          // frame room for the dangle\n \n  float ph = fract(TIME * speed / PERIOD);\n  float th = TAU * ph;\n \n  vec3 ro = vec3(0.0, 0.0, 3.5);\n  vec3 rd = normalize(vec3(uv, -2.05));\n  vec3 key = normalize(vec3(0.5, 0.7, 0.6));\n  vec3 fill = normalize(vec3(-0.6, -0.2, 0.4));\n \n  vec3 col;\n  float vig = 1.0 - 0.6*dot(uv*0.7, uv*0.7);\n  col = mix(vec3(0.10,0.10,0.13), vec3(0.20,0.20,0.24), vig) * vig;\n \n  float t = 0.0, side = 0.0;\n  vec3 op = vec3(0.0);\n  bool hit = false;\n  for(int i = 0; i < 110; i++){\n    vec3 p = ro + rd*t;\n    float s;\n    float d = mapScene(p, th, op, s);\n    if(d < 0.0008){ side = s; hit = true; break; }\n    t += d;\n    if(t > 7.0) break;\n  }\n \n  if(hit){\n    vec3 p = ro + rd*t;\n    vec3 n = calcNormal(p, th);\n \n    // glans region (smoother, shinier, pinker)\n    vec3 tip = vec3(0.12*sin(th*1.3+0.6), 0.28 - 1.15*dong, 0.56);\n    float glans = smoothstep(0.30, 0.12, length(op - tip));\n \n    float wr = fbm3(op*7.0 + 3.0);\n    float fine = fbm3(op*18.0);\n    float crease = (0.5 - abs(wr - 0.5)) * 2.0;\n    crease = pow(crease, 1.5) * wrinkle * (1.0 - 0.85*glans);\n \n    vec2 e = vec2(0.02, 0.0);\n    vec3 g = vec3(\n      fbm3((op+e.xyy)*7.0+3.0) - fbm3((op-e.xyy)*7.0+3.0),\n      fbm3((op+e.yxy)*7.0+3.0) - fbm3((op-e.yxy)*7.0+3.0),\n      fbm3((op+e.yyx)*7.0+3.0) - fbm3((op-e.yyx)*7.0+3.0)\n    );\n    n = normalize(n - (g*3.0 + (fbm3(op*18.0+1.0)-0.5)*0.6) * wrinkle * (1.0 - 0.85*glans));\n \n    float raphe = smoothstep(0.06, 0.0, abs(op.x)) * smoothstep(-1.4, 0.5, op.y) * (1.0 - glans);\n \n    vec3 skin = vec3(0.72, 0.50, 0.44);\n    skin = mix(skin, vec3(0.55, 0.30, 0.28), crease*0.6);\n    skin = mix(skin, vec3(0.42, 0.20, 0.20), raphe*0.7);\n    skin = mix(skin, vec3(0.74, 0.42, 0.42), glans*0.6);   // pinker head\n    skin *= 0.9 + 0.2*fine;\n \n    float kd = max(dot(n, key), 0.0);\n    float fd = max(dot(n, fill), 0.0);\n    float wrap = max(0.0, (dot(n, key) + 0.4) / 1.4);\n    vec3 sss = vec3(0.9, 0.35, 0.30) * pow(wrap, 2.0) * 0.5;\n \n    vec3 lit = skin * (0.15 + 1.0*kd) + skin * fill.z * fd * 0.25;\n    lit += sss;\n \n    vec3 h = normalize(key - rd);\n    float spec = pow(max(dot(n, h), 0.0), 18.0 + 40.0*glans);\n    lit += vec3(1.0, 0.9, 0.85) * spec * (0.35 + 0.6*glans) * (1.0 - crease*0.5);\n \n    // --- hair ---\n    vec2 hf = hairField(op, n, rd, key);\n    lit *= 1.0 - 0.6*hf.x;                              // strands darken\n    lit += vec3(0.85, 0.72, 0.55) * hf.y * 0.5;          // backlit glint\n \n    float rim = pow(1.0 - max(dot(n, -rd), 0.0), 3.0);\n    lit += vec3(0.5, 0.45, 0.55) * rim * 0.4;\n \n    lit *= 0.7 + 0.3*clamp(1.0 - crease*0.8, 0.0, 1.0);\n    lit *= 0.6 + 0.4*smoothstep(-1.5, -0.4, op.y);\n \n    col = lit;\n  }\n \n  col = col / (1.0 + col);\n  col = pow(col, vec3(0.85));\n  gl_FragColor = vec4(col, 1.0);\n}",
    "generator": {
      "model": "claude-opus-4-8",
      "provider": null,
      "prompt": null,
      "params": null
    }
  }
}