{
  "license": "CC0-1.0",
  "shader": {
    "id": "pu9wd0wh",
    "title": "Playa Cracks",
    "license": "CC0-1.0",
    "provenance_type": "witnessed_generation",
    "made_with": "glslop",
    "status": "active",
    "compile_ok": true,
    "render_hash": "f06039f7fff716a4",
    "tags": [
      "desert",
      "sand",
      "playa",
      "heat",
      "voronoi",
      "texture"
    ],
    "parents": [],
    "author": "4vflyg0gs2at",
    "author_name": "depatchedmode",
    "author_url": "/u/depatchedmode",
    "created_at": "2026-08-04T04:36:49.958Z",
    "poster_url": "/posters/pu9wd0wh.avif",
    "stats": {
      "slops": 0,
      "views": 148,
      "forks": 0
    },
    "self": "/api/v1/shaders/pu9wd0wh",
    "isf": "/*{\n  \"DESCRIPTION\": \"Sun-baked playa: warped mineral plates, deep irregular gaps, and sparse hairline fractures.\",\n  \"CREDIT\": \"depatchedmode\",\n  \"CATEGORIES\": [\"Generator\", \"Texture\"],\n  \"INPUTS\": [\n    { \"NAME\": \"plateScale\", \"TYPE\": \"float\", \"DEFAULT\": 20.0, \"MIN\": 3.0, \"MAX\": 20.0 },\n    { \"NAME\": \"gapWidth\", \"TYPE\": \"float\", \"DEFAULT\": 0.025, \"MIN\": 0.025, \"MAX\": 0.14 },\n    { \"NAME\": \"gapVariance\", \"TYPE\": \"float\", \"DEFAULT\": 0.55, \"MIN\": 0.0, \"MAX\": 1.0 },\n    { \"NAME\": \"gapDebris\", \"TYPE\": \"float\", \"DEFAULT\": 0.58, \"MIN\": 0.0, \"MAX\": 1.0 },\n    { \"NAME\": \"fragmentAmount\", \"TYPE\": \"float\", \"DEFAULT\": 0.46, \"MIN\": 0.0, \"MAX\": 1.0 },\n    { \"NAME\": \"hairlineAmount\", \"TYPE\": \"float\", \"DEFAULT\": 0.25, \"MIN\": 0.0, \"MAX\": 1.0 },\n    { \"NAME\": \"relief\", \"TYPE\": \"float\", \"DEFAULT\": 0.47, \"MIN\": 0.0, \"MAX\": 1.4 },\n    { \"NAME\": \"curlCoverage\", \"TYPE\": \"float\", \"DEFAULT\": 0.42, \"MIN\": 0.0, \"MAX\": 1.0 },\n    { \"NAME\": \"curlWidthVariance\", \"TYPE\": \"float\", \"DEFAULT\": 0.51, \"MIN\": 0.0, \"MAX\": 1.0 },\n    { \"NAME\": \"cupping\", \"TYPE\": \"float\", \"DEFAULT\": 0.2, \"MIN\": 0.0, \"MAX\": 1.5 },\n    { \"NAME\": \"cuppingIrregularity\", \"TYPE\": \"float\", \"DEFAULT\": 0.86, \"MIN\": 0.0, \"MAX\": 1.0 },\n    { \"NAME\": \"heightVariance\", \"TYPE\": \"float\", \"DEFAULT\": 0.22, \"MIN\": 0.0, \"MAX\": 1.0 },\n    { \"NAME\": \"lightAngle\", \"TYPE\": \"float\", \"DEFAULT\": 1.27, \"MIN\": 0.0, \"MAX\": 6.283 },\n    { \"NAME\": \"lightElevation\", \"TYPE\": \"float\", \"DEFAULT\": 0.63, \"MIN\": 0.1, \"MAX\": 1.5 },\n    { \"NAME\": \"sunStrength\", \"TYPE\": \"float\", \"DEFAULT\": 1.33, \"MIN\": 0.0, \"MAX\": 1.5 },\n    { \"NAME\": \"moonStrength\", \"TYPE\": \"float\", \"DEFAULT\": 1.25, \"MIN\": 0.0, \"MAX\": 1.5 },\n    { \"NAME\": \"warmth\", \"TYPE\": \"float\", \"DEFAULT\": 0.55, \"MIN\": 0.0, \"MAX\": 1.0 },\n    { \"NAME\": \"mineralVariation\", \"TYPE\": \"float\", \"DEFAULT\": 0.24, \"MIN\": 0.0, \"MAX\": 1.0 },\n    { \"NAME\": \"clayColor\", \"TYPE\": \"color\", \"DEFAULT\": [0.72, 0.70, 0.64, 1.0] },\n    { \"NAME\": \"crackColor\", \"TYPE\": \"color\", \"DEFAULT\": [0.404, 0.380, 0.337, 1.0] },\n    { \"NAME\": \"crackSpeed\", \"TYPE\": \"float\", \"DEFAULT\": 0.46, \"MIN\": 0.0, \"MAX\": 1.5 },\n    { \"NAME\": \"hairlineSpeed\", \"TYPE\": \"float\", \"DEFAULT\": 1.31, \"MIN\": 0.0, \"MAX\": 1.5 },\n    { \"NAME\": \"edgeSpeed\", \"TYPE\": \"float\", \"DEFAULT\": 1.35, \"MIN\": 0.0, \"MAX\": 1.5 },\n    { \"NAME\": \"seed\", \"TYPE\": \"float\", \"DEFAULT\": 2.8, \"MIN\": 0.0, \"MAX\": 20.0 }\n  ]\n}*/\n\nprecision highp float;\n\n// The browser preview supplies these from its location-aware celestial clock.\n// They default to manual daylight when opened in an ISF host without that clock.\nuniform float celestialLighting;\nuniform vec3 celestialSunDirection;\nuniform vec3 celestialMoonDirection;\nuniform vec3 celestialSunColor;\nuniform vec3 celestialMoonColor;\nuniform vec3 celestialAmbient;\nuniform float celestialSunIntensity;\nuniform float celestialMoonIntensity;\n\nfloat hash11(float p) {\n  p = fract(p * 0.1031);\n  p *= p + 33.33;\n  return fract(p * (p + p));\n}\n\nvec2 hash22(vec2 p) {\n  vec3 q = fract(vec3(p.xyx) * vec3(0.1031, 0.1030, 0.0973));\n  q += dot(q, q.yzx + 33.33);\n  return fract((q.xx + q.yz) * q.zy);\n}\n\nfloat valueNoise(vec2 p) {\n  vec2 cell = floor(p);\n  vec2 local = fract(p);\n  local = local * local * (3.0 - 2.0 * local);\n\n  float a = hash11(dot(cell, vec2(127.1, 311.7)));\n  float b = hash11(dot(cell + vec2(1.0, 0.0), vec2(127.1, 311.7)));\n  float c = hash11(dot(cell + vec2(0.0, 1.0), vec2(127.1, 311.7)));\n  float d = hash11(dot(cell + vec2(1.0), vec2(127.1, 311.7)));\n  return mix(mix(a, b, local.x), mix(c, d, local.x), local.y);\n}\n\nfloat fbm(vec2 p) {\n  float sum = 0.0;\n  float weight = 0.5;\n  mat2 turn = mat2(0.80, -0.60, 0.60, 0.80);\n  for (int octave = 0; octave < 4; octave++) {\n    sum += weight * valueNoise(p);\n    p = turn * p * 2.03 + 9.17;\n    weight *= 0.5;\n  }\n  return sum;\n}\n\nvec2 featurePoint(vec2 cellId, vec2 motionPhase, float motionRadius) {\n  vec2 center = 0.14 + 0.72 * hash22(cellId + seed);\n  vec2 axisX = hash22(cellId + seed + vec2(19.17, 73.11)) - 0.5;\n  vec2 axisY = vec2(-axisX.y, axisX.x);\n  return center + (axisX * motionPhase.x + axisY * motionPhase.y) * motionRadius;\n}\n\nvec4 plateMaterialVariation(float plateKey) {\n  if (mineralVariation <= 0.001) {\n    return vec4(0.0);\n  }\n\n  vec2 primary = hash22(vec2(\n    plateKey * 137.2 + seed * 1.7,\n    plateKey * 61.8 - seed * 2.3\n  ));\n  vec2 secondary = hash22(primary * 83.1 + vec2(plateKey, seed));\n  return (vec4(primary, secondary) - 0.5) * mineralVariation;\n}\n\n// Captures the closest edge direction during the existing boundary search for the cupping profile.\nvec4 voronoiPlate(\n  vec2 p,\n  vec2 motionPhase,\n  float motionRadius,\n  out float plateKey,\n  out vec2 edgeDirection,\n  out float edgeKey,\n  out float cornerness\n) {\n  vec2 cell = floor(p);\n  vec2 local = fract(p);\n  vec2 nearestOffset = vec2(0.0);\n  vec2 nearestCell = vec2(0.0);\n  float nearestDistance = 8.0;\n\n  for (int y = -1; y <= 1; y++) {\n    for (int x = -1; x <= 1; x++) {\n      vec2 neighbor = vec2(float(x), float(y));\n      vec2 feature = featurePoint(cell + neighbor, motionPhase, motionRadius);\n      vec2 offset = neighbor + feature - local;\n      float distanceSquared = dot(offset, offset);\n      if (distanceSquared < nearestDistance) {\n        nearestDistance = distanceSquared;\n        nearestOffset = offset;\n        nearestCell = neighbor;\n      }\n    }\n  }\n\n  float borderDistance = 8.0;\n  float secondBorderDistance = 8.0;\n  vec2 edgeNeighbor = nearestCell;\n  edgeDirection = vec2(0.0);\n  vec2 secondEdgeDirection = vec2(0.0);\n  for (int y = -2; y <= 2; y++) {\n    for (int x = -2; x <= 2; x++) {\n      vec2 neighbor = nearestCell + vec2(float(x), float(y));\n      vec2 feature = featurePoint(cell + neighbor, motionPhase, motionRadius);\n      vec2 offset = neighbor + feature - local;\n      vec2 delta = offset - nearestOffset;\n      if (dot(delta, delta) > 0.0001) {\n        vec2 candidateDirection = normalize(delta);\n        float candidateDistance = dot(0.5 * (nearestOffset + offset), candidateDirection);\n        if (candidateDistance < borderDistance) {\n          secondBorderDistance = borderDistance;\n          secondEdgeDirection = edgeDirection;\n          borderDistance = candidateDistance;\n          edgeDirection = candidateDirection;\n          edgeNeighbor = neighbor;\n        } else if (candidateDistance < secondBorderDistance) {\n          secondBorderDistance = candidateDistance;\n          secondEdgeDirection = candidateDirection;\n        }\n      }\n    }\n  }\n\n  vec2 plateId = cell + nearestCell;\n  vec2 opposingPlateId = cell + edgeNeighbor;\n  vec2 edgeIdSum = plateId + opposingPlateId;\n  vec2 edgeIdDifference = abs(plateId - opposingPlateId);\n  plateKey = hash11(dot(plateId, vec2(57.2, 113.7)) + seed * 3.1);\n  edgeKey = hash11(\n    dot(edgeIdSum, vec2(23.17, 47.13)) +\n    dot(edgeIdDifference, vec2(91.7, 13.9)) +\n    seed * 5.1\n  );\n  float boundarySeparation = max(secondBorderDistance - borderDistance, 0.0);\n  cornerness = 1.0 - smoothstep(0.025, 0.18, boundarySeparation);\n  vec2 blendedEdgeDirection = mix(edgeDirection, secondEdgeDirection, cornerness * 0.5);\n  float blendedLengthSquared = max(dot(blendedEdgeDirection, blendedEdgeDirection), 0.0001);\n  edgeDirection = blendedEdgeDirection * inversesqrt(blendedLengthSquared);\n  float centerDistance = sqrt(max(nearestDistance, 0.0001));\n  vec2 centerDirection = nearestOffset / centerDistance;\n  return vec4(borderDistance, centerDistance, centerDirection);\n}\n\nvec3 organicCupProfile(\n  vec4 plate,\n  float plateKey,\n  vec2 plateVariation\n) {\n  float irregularity = cuppingIrregularity;\n  if (irregularity <= 0.001) {\n    return vec3(plate.zw, smoothstep(0.04, 0.52, plate.y));\n  }\n\n  vec2 shiftedCenter = plate.zw * plate.y + plateVariation * irregularity * 0.28;\n  float shiftedDistance = max(length(shiftedCenter), 0.0001);\n  vec2 radialDirection = shiftedCenter / shiftedDistance;\n\n  float profileScale = mix(1.0, 0.72 + plateKey * 0.56, irregularity);\n  float slope = smoothstep(0.04 * profileScale, 0.52 * profileScale, shiftedDistance);\n  float directionalBias = dot(radialDirection, normalize(plateVariation + vec2(0.0001, 0.0)));\n  slope *= 1.0 + directionalBias * irregularity * 0.22;\n  slope *= mix(1.0, 0.65 + plateKey * 0.75, irregularity);\n  return vec3(radialDirection, slope);\n}\n\nvec3 edgeCurl(\n  vec2 p,\n  float border,\n  float localGap,\n  float pixelWidth,\n  vec2 edgeDirection,\n  float edgeKey,\n  float cornerness\n) {\n  if (relief <= 0.001 || curlCoverage <= 0.001) {\n    return vec3(0.0);\n  }\n\n  vec2 noiseOffset = vec2(edgeKey * 17.3, edgeKey * -11.7) + seed;\n  vec2 edgeTangent = vec2(-edgeDirection.y, edgeDirection.x);\n  float dominantDirection = abs(edgeTangent.x) > abs(edgeTangent.y) ? edgeTangent.x : edgeTangent.y;\n  edgeTangent *= sign(dominantDirection);\n  float curlTravel = TIME * edgeSpeed * 0.035;\n  float placementNoise = valueNoise(p * 1.45 + noiseOffset + edgeTangent * curlTravel);\n  float curlPatch = smoothstep(0.70, 0.80, placementNoise);\n\n  float edgeGate = smoothstep(\n    1.0 - curlCoverage,\n    1.10 - curlCoverage,\n    edgeKey\n  );\n  float widthSeed = fract(edgeKey * 7.618 + 0.37);\n  float variedWidth = mix(0.065, 0.24, widthSeed);\n  float curlWidth = mix(0.13, variedWidth, curlWidthVariance);\n  float surfaceEdgeDistance = max(border - localGap, 0.0);\n  float curlStart = min(pixelWidth * 1.5, curlWidth * 0.5);\n  float curlSlope = 1.0 - smoothstep(curlStart, curlWidth, surfaceEdgeDistance);\n  float cornerFade = 1.0 - smoothstep(0.20, 0.88, cornerness);\n  float curlMask = edgeGate * curlPatch * cornerFade;\n  float curlOcclusion = curlMask * (1.0 - smoothstep(localGap, localGap + curlWidth * 0.48, border));\n  return vec3(edgeDirection * curlSlope * curlMask * relief * 0.72, curlOcclusion);\n}\n\nfloat fineFractures(vec2 p, float macroBorder, vec2 motionPhase) {\n  vec2 fineP = p * 2.65 + vec2(17.3, -9.1);\n  vec2 cell = floor(fineP);\n  vec2 local = fract(fineP);\n  vec2 closestCell = vec2(0.0);\n  float nearestDistance = 8.0;\n  float secondDistance = 8.0;\n\n  for (int y = -1; y <= 1; y++) {\n    for (int x = -1; x <= 1; x++) {\n      vec2 neighbor = vec2(float(x), float(y));\n      vec2 feature = featurePoint(cell + neighbor, motionPhase, 0.18);\n      vec2 offset = neighbor + feature - local;\n      float distanceSquared = dot(offset, offset);\n      if (distanceSquared < nearestDistance) {\n        secondDistance = nearestDistance;\n        nearestDistance = distanceSquared;\n        closestCell = neighbor;\n      } else if (distanceSquared < secondDistance) {\n        secondDistance = distanceSquared;\n      }\n    }\n  }\n\n  float borderDistance = 0.5 * (sqrt(secondDistance) - sqrt(nearestDistance));\n  float cellKey = hash11(dot(cell + closestCell, vec2(41.7, 89.2)) + seed * 7.0);\n  float brokenNetwork = smoothstep(0.40, 0.78, cellKey + 0.22 * valueNoise(fineP * 0.55));\n  float hairline = 1.0 - smoothstep(0.010, 0.030, borderDistance);\n  float awayFromGaps = smoothstep(gapWidth * 1.9, gapWidth * 3.4, macroBorder);\n  return hairline * brokenNetwork * awayFromGaps * hairlineAmount;\n}\n\nvec3 crumblyGapFloor(\n  vec2 p,\n  float border,\n  float localGap,\n  vec2 lightPlanar,\n  vec3 gapColor,\n  vec3 clay\n) {\n  if (gapDebris <= 0.001 && fragmentAmount <= 0.001) {\n    return gapColor;\n  }\n\n  float floorPosition = clamp(border / max(localGap, 0.0001), 0.0, 1.0);\n  float wideGap = smoothstep(0.82, 1.28, localGap / max(gapWidth, 0.0001));\n  float coarseGrain = valueNoise(p * 19.0 + seed * 8.7);\n  float fineGrain = valueNoise(p * 57.0 + vec2(seed * 3.1, -seed * 4.7));\n  float grain = mix(coarseGrain, fineGrain, 0.38) - 0.5;\n\n  float wallShadow = smoothstep(0.58, 1.0, floorPosition);\n  float floorPlacement = 1.0 - smoothstep(0.72, 0.98, floorPosition);\n  float debrisStrength = gapDebris * mix(0.42, 1.0, wideGap);\n  gapColor *= 1.0 + grain * debrisStrength * 0.42;\n  gapColor *= 1.0 - wallShadow * debrisStrength * 0.36;\n\n  float debrisThreshold = mix(0.94, 0.69, gapDebris);\n  float debrisField = fineGrain + (coarseGrain - 0.5) * 0.18;\n  float debrisMask = smoothstep(debrisThreshold, debrisThreshold + 0.055, debrisField);\n  debrisMask *= floorPlacement * debrisStrength;\n  vec3 debrisColor = mix(gapColor, clay, 0.32 + coarseGrain * 0.16);\n  gapColor = mix(gapColor, debrisColor, debrisMask * 0.76);\n\n  if (fragmentAmount <= 0.001) {\n    return gapColor;\n  }\n\n  vec2 fragmentOffset = vec2(seed * 5.3, -seed * 2.9);\n  float fragmentField = valueNoise(p * 34.0 + fragmentOffset) + grain * 0.16;\n  float fragmentThreshold = mix(0.94, 0.70, fragmentAmount);\n  float fragmentShape = smoothstep(fragmentThreshold, fragmentThreshold + 0.055, fragmentField);\n  float fragmentOpacity = fragmentAmount * mix(0.28, 1.0, wideGap);\n  float fragments = fragmentShape * floorPlacement * fragmentOpacity;\n\n  float planarLength = max(length(lightPlanar), 0.0001);\n  vec2 shadowOffset = lightPlanar / planarLength * 0.018;\n  float shadowField = valueNoise((p + shadowOffset) * 34.0 + fragmentOffset) + grain * 0.16;\n  float shiftedShape = smoothstep(fragmentThreshold, fragmentThreshold + 0.055, shadowField);\n  float fragmentShadow = max(shiftedShape - fragmentShape, 0.0);\n  fragmentShadow *= floorPlacement * fragmentOpacity;\n  gapColor *= 1.0 - fragmentShadow * 0.58;\n\n  vec3 fragmentColor = clay * mix(0.62, 0.88, fineGrain);\n  return mix(gapColor, fragmentColor, fragments * 0.88);\n}\n\nvoid main() {\n  vec2 uv = isf_FragNormCoord;\n  vec2 p = (uv - 0.5) * vec2(RENDERSIZE.x / RENDERSIZE.y, 1.0);\n  p *= plateScale;\n\n  float broadWarp = fbm(p * 0.19 + seed);\n  vec2 warp = vec2(\n    valueNoise(p * 0.31 + vec2(seed, 4.2)),\n    valueNoise(p * 0.31 + vec2(8.3, seed))\n  ) - 0.5;\n  p += warp * 0.88 + vec2(broadWarp - 0.5, 0.0) * 0.42;\n\n  float crackAngle = TIME * crackSpeed;\n  vec2 crackPhase = vec2(cos(crackAngle), sin(crackAngle));\n  float plateRandom;\n  vec2 edgeDirection;\n  float edgeKey;\n  float cornerness;\n  vec4 plate = voronoiPlate(\n    p,\n    crackPhase,\n    0.20,\n    plateRandom,\n    edgeDirection,\n    edgeKey,\n    cornerness\n  );\n  float hairlineAngle = TIME * hairlineSpeed + 1.7;\n  vec2 hairlinePhase = vec2(cos(hairlineAngle), sin(hairlineAngle));\n  float edgePhase = TIME * edgeSpeed;\n  vec2 edgeOrbit = vec2(cos(edgePhase), sin(edgePhase));\n  float chippedEdge = (valueNoise(p * 6.7 + edgeOrbit * 2.8 + 23.0) - 0.5) * 0.022;\n  float border = plate.x + chippedEdge;\n  float widthNoise = valueNoise(p * 1.45 + 31.0);\n  float gapIrregularity = mix(1.0, 0.55 + 0.90 * widthNoise, gapVariance);\n  float localGap = gapWidth * gapIrregularity;\n  float pixelWidth = plateScale / max(RENDERSIZE.y, 1.0);\n  float plateMask = smoothstep(localGap, localGap + pixelWidth * 1.7, border);\n\n  float mineral = fbm(p * 1.9 + plateRandom * 19.0);\n  float grit = valueNoise(p * 8.0 + seed * 13.0);\n  float stains = fbm(p * 0.53 + vec2(7.0, -12.0));\n  vec4 plateMaterial = plateMaterialVariation(plateRandom);\n\n  vec3 coolClay = clayColor.rgb * vec3(0.95, 0.98, 1.04);\n  vec3 warmClay = clayColor.rgb * vec3(1.06, 0.98, 0.86);\n  vec3 clay = mix(coolClay, warmClay, warmth);\n  clay *= vec3(\n    1.0 + plateMaterial.x * 0.09,\n    1.0 + plateMaterial.x * 0.025,\n    1.0 - plateMaterial.x * 0.08\n  );\n  clay *= 0.955 + plateMaterial.y * 0.16;\n  clay *= 0.86 + 0.23 * mineral;\n  clay += vec3(0.055, 0.050, 0.038) * (grit - 0.5);\n  if (mineralVariation > 0.001) {\n    float poreNoise = valueNoise(p * 31.0 + plateRandom * 29.0 + seed * 5.7);\n    float poreThreshold = 0.72 - plateMaterial.z * 0.22;\n    float pores = smoothstep(poreThreshold, poreThreshold + 0.10, poreNoise);\n    clay *= 1.0 - pores * mineralVariation * 0.045;\n  }\n  float stainShift = plateMaterial.w * 0.22;\n  float stainMask = smoothstep(0.62 - stainShift, 0.88 - stainShift, stains);\n  float stainStrength = 0.24 * (1.0 + plateMaterial.w * 0.55);\n  clay = mix(clay, clay * vec3(0.73, 0.69, 0.60), stainMask * stainStrength);\n\n  bool usesCelestialLighting = celestialLighting > 0.5;\n  vec2 manualLightPlanar = vec2(cos(lightAngle), sin(lightAngle)) * cos(lightElevation);\n  vec3 manualLightDirection = vec3(manualLightPlanar, sin(lightElevation));\n  vec2 lightPlanar = manualLightPlanar;\n  if (usesCelestialLighting) {\n    lightPlanar = celestialSunDirection.xy * celestialSunIntensity * sunStrength;\n    lightPlanar += celestialMoonDirection.xy * celestialMoonIntensity * moonStrength;\n  }\n  vec2 randomTilt = hash22(vec2(plateRandom * 91.7, seed + 4.3)) - 0.5;\n  vec3 cupProfile = organicCupProfile(plate, plateRandom, randomTilt);\n  vec2 heightGradient = cupProfile.xy * cupping * 0.62 * cupProfile.z;\n  heightGradient += randomTilt * heightVariance * 0.42;\n  vec3 curlData = edgeCurl(\n    p,\n    border,\n    localGap,\n    pixelWidth,\n    edgeDirection,\n    edgeKey,\n    cornerness\n  );\n  heightGradient += curlData.xy;\n  vec3 surfaceNormal = normalize(vec3(-heightGradient, 1.0));\n  if (!usesCelestialLighting) {\n    float diffuse = max(dot(surfaceNormal, manualLightDirection), 0.0);\n    clay *= 1.0 + sunStrength * (diffuse - 0.58) * 0.72;\n  }\n  clay *= 1.0 + (plateRandom - 0.5) * heightVariance * 0.22;\n  clay *= 1.0 - curlData.z * relief * 0.10;\n\n  float fissureNoise = fbm(p * 2.4 + 40.0);\n  vec3 gapColor = mix(crackColor.rgb * 0.78, crackColor.rgb * 1.62, fissureNoise);\n  gapColor *= 0.84 + 0.22 * smoothstep(0.0, localGap, border);\n  if (plateMask < 1.0) {\n    gapColor = crumblyGapFloor(p, border, localGap, lightPlanar, gapColor, clay);\n  }\n\n  float hairlines = fineFractures(p, border, hairlinePhase);\n  clay = mix(clay, clay * vec3(0.43, 0.41, 0.37), hairlines * 0.72);\n\n  vec3 color = mix(gapColor, clay, plateMask);\n  if (usesCelestialLighting) {\n    float sunDiffuse = max(dot(surfaceNormal, celestialSunDirection), 0.0);\n    float moonDiffuse = max(dot(surfaceNormal, celestialMoonDirection), 0.0);\n    vec3 sunlight = celestialSunColor * celestialSunIntensity * sunStrength * (0.22 + 0.78 * sunDiffuse);\n    vec3 moonlight = celestialMoonColor * celestialMoonIntensity * moonStrength * (0.18 + 0.82 * moonDiffuse);\n    color *= celestialAmbient + sunlight * 0.62 + moonlight * 0.55;\n  }\n  float dust = hash11(dot(gl_FragCoord.xy, vec2(12.9898, 78.233)) + seed * 101.0) - 0.5;\n  color += dust * 0.018;\n  color *= 0.93 + 0.10 * smoothstep(0.0, 1.0, uv.y);\n  color = pow(max(color, 0.0), vec3(0.94));\n\n  gl_FragColor = vec4(color, 1.0);\n}\n",
    "generator": {
      "model": "chatgpt-5.6-terra",
      "provider": null,
      "prompt": null,
      "params": null
    }
  }
}