{
  "license": "CC0-1.0",
  "shader": {
    "id": "uj2ujb2l",
    "title": "brontosoarin",
    "license": "CC0-1.0",
    "provenance_type": "witnessed_generation",
    "made_with": "pi + GLSLOP Studio",
    "status": "active",
    "compile_ok": true,
    "render_hash": "1e18ed63f7ff2e0c",
    "tags": [
      "3d",
      "illustration",
      "dinosaur",
      "paper-plane",
      "clouds"
    ],
    "parents": [],
    "author": "zazi5inxhmgi",
    "author_name": "ufffd",
    "author_url": "/u/ufffd",
    "created_at": "2026-10-03T16:36:14.994Z",
    "poster_url": "/posters/uj2ujb2l.avif",
    "stats": {
      "slops": 0,
      "views": 178,
      "forks": 0
    },
    "self": "/api/v1/shaders/uj2ujb2l",
    "isf": "/*{\n  \"DESCRIPTION\": \"Opal Slipstream: Cloudsurf with wind-carried, flight-reactive smoke. Translucent vapor and twisting pearl folds follow previous emitter poses, fan through banks and change their apparent thickness and opal highlights as the camera moves.\",\n  \"CATEGORIES\": [\n    \"3D\",\n    \"illustration\"\n  ],\n  \"INPUTS\": [\n    {\n      \"NAME\": \"azimuth\",\n      \"LABEL\": \"Camera azimuth\",\n      \"TYPE\": \"float\",\n      \"DEFAULT\": 50.36,\n      \"MIN\": 35,\n      \"MAX\": 115\n    },\n    {\n      \"NAME\": \"elevation\",\n      \"LABEL\": \"Camera elevation\",\n      \"TYPE\": \"float\",\n      \"DEFAULT\": 12.012,\n      \"MIN\": 8,\n      \"MAX\": 42\n    },\n    {\n      \"NAME\": \"flight\",\n      \"LABEL\": \"Flight motion\",\n      \"TYPE\": \"float\",\n      \"DEFAULT\": 0.912,\n      \"MIN\": 0,\n      \"MAX\": 1.5\n    },\n    {\n      \"NAME\": \"smoke\",\n      \"LABEL\": \"Smoke ribbon\",\n      \"TYPE\": \"float\",\n      \"DEFAULT\": 1.5,\n      \"MIN\": 0,\n      \"MAX\": 1.5\n    },\n    {\n      \"NAME\": \"curl\",\n      \"LABEL\": \"Smoke curls\",\n      \"TYPE\": \"float\",\n      \"DEFAULT\": 1.6,\n      \"MIN\": 0,\n      \"MAX\": 1.6\n    },\n    {\n      \"NAME\": \"opalescence\",\n      \"LABEL\": \"Smoke opalescence\",\n      \"TYPE\": \"float\",\n      \"DEFAULT\": 1,\n      \"MIN\": 0,\n      \"MAX\": 1\n    },\n    {\n      \"NAME\": \"skin\",\n      \"LABEL\": \"Mint to jade\",\n      \"TYPE\": \"float\",\n      \"DEFAULT\": 0.534,\n      \"MIN\": 0,\n      \"MAX\": 1\n    },\n    {\n      \"NAME\": \"sky\",\n      \"LABEL\": \"Sky warmth\",\n      \"TYPE\": \"float\",\n      \"DEFAULT\": 1,\n      \"MIN\": 0,\n      \"MAX\": 1\n    },\n    {\n      \"NAME\": \"papergrain\",\n      \"LABEL\": \"Paper grain\",\n      \"TYPE\": \"float\",\n      \"DEFAULT\": 0.514,\n      \"MIN\": 0,\n      \"MAX\": 1\n    },\n    {\n      \"NAME\": \"softness\",\n      \"LABEL\": \"Light softness\",\n      \"TYPE\": \"float\",\n      \"DEFAULT\": 0.13111546903730154,\n      \"MIN\": 0,\n      \"MAX\": 1\n    },\n    {\n      \"NAME\": \"journey\",\n      \"LABEL\": \"Camera journey\",\n      \"TYPE\": \"float\",\n      \"DEFAULT\": 0.627542615913452,\n      \"MIN\": 0,\n      \"MAX\": 1\n    },\n    {\n      \"NAME\": \"clouds\",\n      \"LABEL\": \"Cloud sea\",\n      \"TYPE\": \"float\",\n      \"DEFAULT\": 0.7219870608089806,\n      \"MIN\": 0,\n      \"MAX\": 1\n    }\n  ]\n}*/\n#ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#endif\n\nmat2 turn(float a) { float c=cos(a),s=sin(a); return mat2(c,-s,s,c); }\nfloat sat(float x) { return clamp(x,0.0,1.0); }\nfloat blend(float a,float b,float k) {\n  float h=sat(0.5+0.5*(b-a)/k); return mix(b,a,h)-k*h*(1.0-h);\n}\nfloat ell(vec3 p,vec3 r) {\n  float a=length(p/r), b=length(p/(r*r)); return a*(a-1.0)/max(b,0.0001);\n}\nfloat rod(vec3 p,vec3 a,vec3 b,float r0,float r1) {\n  vec3 v=b-a; float h=sat(dot(p-a,v)/dot(v,v));\n  return length(p-a-v*h)-mix(r0,r1,h);\n}\n// Continuous cubic sweep, not a chain of capsules. Minimize distance to\n// variable-radius spheres on the curve with a sampled bracket and safeguarded\n// Newton steps. Unbracketed Newton jumps across thin tips and creates speckles.\n// Hull rejection keeps irrelevant curves out of the ray/normal/shadow budget.\nfloat bezierTube(vec3 p,vec3 a,vec3 b,vec3 c,vec3 d,float r0,float r1,float ceiling) {\n  vec3 lo=min(min(a,b),min(c,d)),hi=max(max(a,b),max(c,d));\n  float lower=length(max(max(lo-p,p-hi),0.0))-max(r0,r1);\n  if(lower>ceiling+0.15) return lower;\n  vec3 k1=3.0*(b-a),k2=3.0*(a-2.0*b+c),k3=d-a+3.0*(b-c);\n  float dr=r0-r1;\n  float best=100.0,t=0.0;\n  for(int s=0;s<=16;s++) {\n    float u=float(s)/16.0;\n    float f=length(a+u*(k1+u*(k2+u*k3))-p)-r1-dr*(1.0-u)*(1.0-u);\n    if(f<best) { best=f; t=u; }\n  }\n  float left=max(0.0,t-0.0625),right=min(1.0,t+0.0625);\n  for(int j=0;j<8;j++) {\n    vec3 v=a+t*(k1+t*(k2+t*k3))-p;\n    vec3 v1=k1+t*(2.0*k2+3.0*t*k3),v2=2.0*k2+6.0*t*k3;\n    float len=max(length(v),0.00001),r=r1+dr*(1.0-t)*(1.0-t);\n    best=min(best,len-r);\n    float slope=dot(v,v1)/len;\n    float g=slope+2.0*dr*(1.0-t);\n    float h=(dot(v1,v1)+dot(v,v2)-slope*slope)/len-2.0*dr;\n    if(g>0.0) right=t; else left=t;\n    float next=t-g/max(h,0.00001);\n    if(h<=0.00001 || next<=left || next>=right) next=0.5*(left+right);\n    t=next;\n  }\n  return best;\n}\nvec2 pick(vec2 a,vec2 b) { return a.x<b.x?a:b; }\n\nconst float RUN=26.0;\nfloat ease(float a,float b,float x) {\n  float u=sat((x-a)/(b-a)); return u*u*u*(10.0+u*(-15.0+6.0*u));\n}\nfloat beat(float x,float a,float b,float c,float d) {\n  return ease(a,b,x)*(1.0-ease(c,d,x));\n}\n// The course is expressed in world X so the clouds and craft share the same\n// corridor without solving a closest path or integrating hidden camera state.\nvec2 course(float x) {\n  float s=mod(x/3.5,RUN);\n  return journey*vec2(-2.10*beat(s,4.0,9.0,11.0,18.0)\n    +1.45*beat(s,14.0,20.0,21.0,26.0),\n    8.0*beat(s,6.0,12.0,15.0,23.0));\n}\nvec3 positionAt(float t) {\n  float x=3.5*t-journey*6.0*(sin(t*6.2831853/RUN+0.3)-sin(0.3));\n  vec2 yz=course(x); return vec3(x,yz.x,yz.y);\n}\n// Analytic velocity/acceleration avoid subtracting large world positions to\n// recover a tiny turn rate (which can otherwise cause long-run bank jitter).\nvec2 easeDerivatives(float a,float b,float x) {\n  float u=sat((x-a)/(b-a)),v=1.0-u;\n  return vec2(30.0*u*u*v*v/(b-a),60.0*u*(2.0*u*u-3.0*u+1.0)/((b-a)*(b-a)));\n}\nvec2 beatDerivatives(float x,float a,float b,float c,float d) {\n  return easeDerivatives(a,b,x)-easeDerivatives(c,d,x);\n}\nvoid motionAt(float t,out vec3 v,out vec3 acc) {\n  float k=6.2831853/RUN,theta=k*t+0.3;\n  float x=positionAt(t).x,phase=mod(x/3.5,RUN);\n  float speed=3.5-journey*6.0*k*cos(theta),push=journey*6.0*k*k*sin(theta);\n  vec2 y=journey*(-2.10*beatDerivatives(phase,4.0,9.0,11.0,18.0)\n    +1.45*beatDerivatives(phase,14.0,20.0,21.0,26.0))/vec2(3.5,12.25);\n  vec2 z=journey*8.0*beatDerivatives(phase,6.0,12.0,15.0,23.0)/vec2(3.5,12.25);\n  v=vec3(speed,y.x*speed,z.x*speed);\n  acc=vec3(push,y.y*speed*speed+y.x*push,z.y*speed*speed+z.x*push);\n}\nvec3 velocityAt(float t) { vec3 v,a; motionAt(t,v,a); return v; }\nmat3 frameAt(float t,out float bank,out float pitch) {\n  vec3 v,acc; motionAt(t,v,acc);\n  vec3 f=normalize(v),side=normalize(cross(f,vec3(0,1,0))),up=cross(side,f);\n  bank=clamp(atan(dot(acc,side)*0.70),-0.48,0.48);\n  pitch=atan(v.y,length(v.xz));\n  return mat3(f,up*cos(bank)+side*sin(bank),side*cos(bank)-up*sin(bank));\n}\nvec3 localVector(vec3 p,mat3 frame) { return vec3(dot(p,frame[0]),dot(p,frame[1]),dot(p,frame[2])); }\nfloat gSway,gNod,gBank,gFlutter,gTime;\nmat3 gFrame;\nvec3 restPoint(vec3 p) {\n  p.z-=gSway*smoothstep(0.72,1.70,p.y);\n  p.x-=gNod*smoothstep(1.0,1.85,p.y);\n  return p;\n}\n\n\n// A single continuous animal. Feet sit on the ridge; neck and tail are not\n// independently rotating ornaments. Small details have their own materials.\nvec2 animal(vec3 p) {\n  p=restPoint(p);\n  float d=ell(p-vec3(-0.30,0.64,0.0),vec3(0.65,0.36,0.30));\n  d=blend(d,bezierTube(p,vec3(0.10,0.65,0.0),vec3(0.78,0.86,0.0),\n    vec3(0.13,1.70,0.0),vec3(0.91,1.855,0.0),0.25,0.104,d),0.13);\n  d=blend(d,ell(p-vec3(0.99,1.87,0.0),vec3(0.29,0.155,0.155)),0.10);\n  vec3 leg=p; leg.z=abs(leg.z);\n  d=blend(d,bezierTube(leg,vec3(-0.65,0.59,0.21),vec3(-0.85,0.44,0.22),\n    vec3(-0.73,0.26,0.25),vec3(-0.66,0.16,0.23),0.145,0.105,d),0.08);\n  d=blend(d,bezierTube(leg,vec3(0.07,0.57,0.21),vec3(-0.04,0.44,0.22),\n    vec3(0.21,0.29,0.25),vec3(0.11,0.16,0.23),0.13,0.092,d),0.08);\n  float wag=0.11*sin(TIME*0.85*flight)+0.35*gBank;\n  d=blend(d,bezierTube(p,vec3(-0.76,0.65,0.0),vec3(-1.30,0.43,wag*0.5),\n    vec3(-1.30,1.28,wag),vec3(-2.08,0.99+0.035*sin(TIME*flight),wag+0.025),0.20,0.010,d),0.12);\n  // Flat foot contact with the actual creased upper sheet. The low tracking\n  // shot must not reveal the old rounded toe tips piercing the paper underside.\n  float run=(2.18-p.x)/3.73;\n  float deck=0.04-0.07025*run+0.3625*abs(p.z);\n  if(abs(p.z)>0.58*run) {\n    float slope=(0.06+(p.z>0.0?gFlutter:-0.4*gFlutter))/0.52;\n    deck=0.04+(0.14-0.58*slope)*run+slope*abs(p.z);\n  }\n  d=max(d,deck+0.002-p.y);\n  vec2 result=vec2(d,1.0);\n  // Half-lidded eyes, small nostrils, and a relaxed mouth line on both sides.\n  vec3 q=p; q.z=abs(q.z);\n  result=pick(result,vec2(ell(q-vec3(1.015,1.945,0.139),vec3(0.060,0.037,0.024)),3.0));\n  result=pick(result,vec2(ell(q-vec3(1.027,1.944,0.160),vec3(0.030,0.017,0.014)),4.0));\n  result=pick(result,vec2(ell(q-vec3(1.214,1.912,0.10),vec3(0.018,0.012,0.012)),4.0));\n  result=pick(result,vec2(rod(p,vec3(1.215,1.826,0.022),vec3(1.69,1.784,0.022),0.035,0.027),5.0));\n  result=pick(result,vec2(rod(p,vec3(1.66,1.786,0.022),vec3(1.705,1.782,0.022),0.028,0.027),6.0));\n  return result;\n}\n\nvoid face(vec3 ro,vec3 rd,vec3 a,vec3 b,vec3 c,float id,inout float t,inout vec3 n,inout float m) {\n  vec3 e=b-a,f=c-a,h=cross(rd,f); float det=dot(e,h);\n  if(abs(det)<0.00001) return;\n  vec3 s=ro-a; float u=dot(s,h)/det;\n  vec3 q=cross(s,e); float v=dot(rd,q)/det;\n  float z=dot(f,q)/det;\n  if(u>=0.0 && v>=0.0 && u+v<=1.0 && z>0.0 && z<t) {\n    t=z; n=normalize(cross(e,f)); if(dot(n,rd)>0.0) n=-n; m=id;\n  }\n}\nvoid paper(vec3 ro,vec3 rd,inout float t,inout vec3 n,inout float m) {\n  vec3 nose=vec3(2.18,0.04,0.0);\n  // One connected folded sheet. A common straight trailing cut replaces the\n  // old staggered triangles; two creased wing panels taper into the same nose.\n  // A narrow V body hangs below the wing roots, instead of an upright dorsal fin.\n  vec3 root=vec3(-1.55,0.035,0.18);\n  vec3 fold=vec3(-1.55,0.18,0.58);\n  vec3 tip=vec3(-1.55,0.24+gFlutter,1.10);\n  vec3 keel=vec3(-1.55,-0.31,0.0);\n  face(ro,rd,nose,fold,tip,10.0,t,n,m);\n  face(ro,rd,nose,root,fold,11.0,t,n,m);\n  face(ro,rd,nose,keel,root,14.0,t,n,m);\n  root.z=-root.z; fold.z=-fold.z; tip.z=-tip.z; tip.y-=1.4*gFlutter;\n  face(ro,rd,nose,tip,fold,13.0,t,n,m);\n  face(ro,rd,nose,fold,root,12.0,t,n,m);\n  face(ro,rd,nose,root,keel,15.0,t,n,m);\n}\nvec2 bounds(vec3 ro,vec3 rd) {\n  vec3 inv=1.0/(rd+vec3(0.000001));\n  vec3 a=(vec3(-2.20,0.03,-0.49)-ro)*inv;\n  vec3 b=(vec3(1.80,2.15,0.49)-ro)*inv;\n  vec3 lo=min(a,b),hi=max(a,b);\n  return vec2(max(max(lo.x,lo.y),lo.z),min(min(hi.x,hi.y),hi.z));\n}\n// Smooth model-space pulp and fibres. Frequencies above the approximate pixel\n// footprint fade out rather than becoming screen noise as the plane banks.\nfloat paperHash(vec2 p) {\n  vec3 h=fract(vec3(p.xyx)*0.1031);\n  h+=dot(h,h.yzx+33.33);\n  return fract((h.x+h.y)*h.z);\n}\nfloat paperNoise(vec2 p) {\n  vec2 i=floor(p),f=fract(p); f=f*f*(3.0-2.0*f);\n  return mix(mix(paperHash(i),paperHash(i+vec2(1,0)),f.x),\n    mix(paperHash(i+vec2(0,1)),paperHash(i+vec2(1,1)),f.x),f.y);\n}\nvec3 paperSurface(vec3 p,float footprint) {\n  vec2 sheet=vec2(p.x,p.z+0.35*p.y);\n  float pulp=(paperNoise(sheet*4.5)-0.5)*(1.0-smoothstep(0.35,0.85,footprint*4.5));\n  float fibre=(paperNoise(sheet*vec2(7.0,27.0))-0.5)*(1.0-smoothstep(0.25,0.8,footprint*27.0));\n  vec3 base=vec3(0.91,0.89,0.83)*(1.0+papergrain*(0.10*pulp+0.09*fibre));\n  float run=sat((2.18-p.x)/3.73);\n  float w=max(0.014,footprint*0.7);\n  float ridge=(abs(p.z)-0.58*run)/w;\n  float root=(abs(p.z)-0.18*run)/w;\n  // Integrated narrow creases: wider but fainter when subpixel. Not black ink.\n  base*=1.0-(0.085*exp(-ridge*ridge)+0.06*exp(-root*root))*0.014/w;\n  return base;\n}\nfloat shadow(vec3 p,vec3 l) {\n  vec2 span=bounds(p,l);\n  if(span.x>span.y || span.y<0.025) return 1.0;\n  float t=max(0.012,span.x),s=1.0;\n  for(int i=0;i<28;i++) {\n    float h=animal(p+l*t).x;\n    s=min(s,mix(14.0,4.0,softness)*max(h,0.0)/t);\n    t+=clamp(h,0.018,0.20);\n    if(h<0.001 || t>min(2.7,span.y)) break;\n  }\n  return 0.26+0.74*sat(s);\n}\nvec3 normal(vec3 p) {\n  vec2 e=vec2(1.0,-1.0)*0.001;\n  return normalize(e.xyy*animal(p+e.xyy).x+e.yyx*animal(p+e.yyx).x\n    +e.yxy*animal(p+e.yxy).x+e.xxx*animal(p+e.xxx).x);\n}\n// Reconstruct a short-lived parcel from its emission pose. World wind, lift\n// and bounded inertial drift replace a sine wave translated with the aircraft.\n// No camera coordinates enter the trajectory: changing views reveals real depth.\nvoid smokeSample(float u,float lifetime,out vec3 center,out vec3 spread,out float age,out float pulse) {\n  age=lifetime*u;\n  float emitted=TIME-age,past=gTime-age*flight/0.65;\n  float bank,pitch; mat3 pose=frameAt(past,bank,pitch);\n  vec3 v,acc; motionAt(past,v,acc);\n  float pace=flight/0.65;\n  v*=pace; acc=clamp(acc*pace*pace,vec3(-5.0),vec3(5.0));\n  vec3 ember=vec3(1.71-0.12*pitch*smoothstep(1.0,1.85,1.788),\n    1.788,0.022-0.14*bank);\n  center=positionAt(past)+pose*ember;\n  vec3 forward=normalize(v+vec3(0.85,0.0,0.10));\n  vec3 side=normalize(cross(forward,vec3(0,1,0))),lift=cross(side,forward);\n  // Newly emitted smoke inherits velocity, then loses it to the surrounding air.\n  center+=v*(0.22*(1.0-exp(-age/0.22)));\n  vec3 wind=vec3(-0.85,0.0,0.26*sin(emitted*0.71+center.x*0.10));\n  wind+=vec3(0.12*sin(emitted*0.47),0.08*sin(emitted*0.9+1.0),\n    0.20*sin(emitted*0.43+center.z*0.23));\n  center+=wind*age-acc*(0.085*age*age);\n  center.y+=0.80*age+0.28*(1.0-exp(-age*4.0));\n  float opening=smoothstep(0.025,0.24,u)*pow(u,0.70);\n  float theta=13.0*age-1.8*emitted+0.95*sin(emitted*0.57+age*2.1);\n  float radius=(0.08+0.38*curl)*opening*(0.78+0.22*sin(emitted*1.3+age*3.2));\n  radius*=1.0+0.60*abs(bank);\n  center+=radius*(side*cos(theta)+lift*0.72*sin(theta));\n  center+=side*(0.11*curl*opening*sin(19.0*age+emitted*0.9));\n  float twist=theta*0.57+emitted*0.34+bank*0.9;\n  spread=side*cos(twist)+lift*sin(twist);\n  pulse=0.78+0.16*sin(emitted*2.3)+0.06*sin(emitted*5.1+0.7);\n}\n// Analytic ray integral through an oriented Gaussian parcel. Segment-length\n// weights remove the old subdivision-dependent bright knots; an ellipse turns\n// from a diffuse veil to a fine edge as the camera and the wake move past it.\nvec2 smokeParcel(vec3 ro,vec3 rd,vec3 p,vec3 tangent,vec3 across,vec3 normal,\n  vec3 widths,float segmentLength,float hit) {\n  vec3 q=p-ro;\n  vec3 o=vec3(dot(q,tangent),dot(q,across),dot(q,normal))/widths;\n  vec3 v=vec3(dot(rd,tangent),dot(rd,across),dot(rd,normal))/widths;\n  float aa=max(dot(v,v),0.00001),depth=dot(o,v)/aa;\n  vec3 nearest=o-v*depth;\n  float radial=dot(nearest,nearest),rayWidth=inversesqrt(aa);\n  // Smooth truncation approximates the finite ray integral at opaque surfaces.\n  float visible=smoothstep(-rayWidth,rayWidth,depth)\n    *smoothstep(-rayWidth,rayWidth,hit-depth);\n  float mass=segmentLength/max(widths.x,0.001);\n  return vec2(exp(-radial)*rayWidth*mass*visible,depth);\n}\n\nfloat cloudHash(vec3 p) {\n  p=fract(p*0.1031); p+=dot(p,p.yzx+31.32); return fract((p.x+p.y)*p.z);\n}\nfloat cloudNoise(vec3 p) {\n  vec3 i=floor(p),f=fract(p); f=f*f*(3.0-2.0*f);\n  return mix(mix(mix(cloudHash(i),cloudHash(i+vec3(1,0,0)),f.x),\n    mix(cloudHash(i+vec3(0,1,0)),cloudHash(i+vec3(1,1,0)),f.x),f.y),\n    mix(mix(cloudHash(i+vec3(0,0,1)),cloudHash(i+vec3(1,0,1)),f.x),\n    mix(cloudHash(i+vec3(0,1,1)),cloudHash(i+vec3(1,1,1)),f.x),f.y),f.z);\n}\nfloat cloudDensity(vec3 p) {\n  vec2 cell=floor(p.xz/7.0),f=fract(p.xz/7.0)-0.5;\n  float d=p.y+5.7;\n  for(int j=-1;j<=1;j++) for(int i=-1;i<=1;i++) {\n    vec2 offset=vec2(float(i),float(j));\n    float seed=paperHash(cell+offset);\n    vec2 jitter=vec2(paperHash(cell+offset+4.7),paperHash(cell+offset+15.3))-0.5;\n    vec3 q=vec3((f.x-offset.x-jitter.x*0.4)*7.0,p.y+4.7-seed*0.3,\n      (f.y-offset.y-jitter.y*0.4)*7.0);\n    vec3 radius=vec3(2.55+seed,1.6+seed*1.0,2.6+seed*0.9);\n    d=blend(d,(length(q/radius)-1.0)*radius.y,0.65);\n  }\n  // Two shoulders motivate the bank. A clear, world-space channel follows the\n  // same course as the aircraft; the camera never relies on a moving fog eraser.\n  float x=mod(p.x+5.0,91.0)-5.0;\n  vec3 a=(vec3(x,p.y,p.z)-vec3(35.0,-3.8,0.5))/vec3(6.0,5.3,5.6);\n  vec3 b=(vec3(x,p.y,p.z)-vec3(60.0,-4.8,11.5))/vec3(5.5,4.0,4.7);\n  d=blend(d,(length(a)-1.0)*4.5+0.75*(0.5-cloudNoise(p*0.55)),0.85);\n  d=blend(d,(length(b)-1.0)*4.0,0.85);\n  d+=(0.5-cloudNoise(p*1.05))*0.65+(0.5-cloudNoise(p*2.3))*0.18;\n  vec2 yz=course(p.x);\n  float corridor=length(vec2(p.z-yz.y,(p.y-yz.x-0.65)*0.86));\n  return (1.0-smoothstep(-0.60,0.45,d))*smoothstep(-8.0,-7.0,p.y)\n    *smoothstep(1.30,2.65,corridor);\n}\nvec3 skyColor(vec3 rd) {\n  vec3 sun=normalize(vec3(-0.54,0.22,-0.84));\n  float horizon=pow(1.0-max(rd.y,0.0),5.0);\n  vec3 zenith=mix(vec3(0.16,0.43,0.65),vec3(0.13,0.29,0.48),sky);\n  vec3 haze=mix(vec3(0.77,0.88,0.91),vec3(0.98,0.72,0.49),sky);\n  vec3 bg=mix(zenith,haze,horizon);\n  float sunDot=max(dot(rd,sun),0.0);\n  bg+=vec3(0.48,0.28,0.095)*pow(sunDot,48.0);\n  return mix(bg,vec3(1.0,0.96,0.77),smoothstep(0.9983,0.9988,sunDot));\n}\nvec2 cloudSpan(vec3 ro,vec3 rd,float hit) {\n  float vy=abs(rd.y)<0.00001?0.00001:rd.y;\n  float a=(-8.0-ro.y)/vy,b=(2.8-ro.y)/vy;\n  return vec2(max(0.0,min(a,b)),min(min(hit,95.0),max(a,b)));\n}\nvec3 cloudComposite(vec3 ro,vec3 rd,vec3 background,float hit) {\n  if(clouds<0.001) return background;\n  vec2 span=cloudSpan(ro,rd,hit);\n  float t=span.x,trans=1.0; vec3 sum=vec3(0);\n  vec3 sun=normalize(vec3(-0.54,0.22,-0.84));\n  vec3 haze=mix(vec3(0.77,0.88,0.91),vec3(0.98,0.72,0.49),sky);\n  float sunDot=max(dot(rd,sun),0.0);\n  // Near samples are dense and deterministic. End exactly at opaque geometry:\n  // a cloud shoulder can pass IN FRONT of a wing without a flat screen overlay.\n  for(int i=0;i<160;i++) {\n    if(t>=span.y || trans<0.018) break;\n    float ds=min(max(0.14,t*0.028),span.y-t);\n    vec3 p=ro+rd*(t+0.5*ds);\n    float d=cloudDensity(p);\n    if(d>0.005) {\n      float optical=1.1*cloudDensity(p+sun*0.65)+0.9*cloudDensity(p+sun*1.8);\n      float light=0.20+0.80*exp(-optical);\n      vec3 cc=mix(vec3(0.40,0.47,0.59),vec3(1.03,0.90,0.74),light);\n      cc+=vec3(0.25,0.17,0.09)*pow(sunDot,16.0)*light;\n      cc=mix(cc,haze,smoothstep(14.0,70.0,t)*0.90);\n      float a=1.0-exp(-d*ds*0.85*clouds);\n      sum+=trans*a*cc; trans*=1.0-a;\n    }\n    t+=ds;\n  }\n  return sum+trans*background;\n}\nfloat smokeTransmission(vec3 ro,vec3 rd,float depth) {\n  vec2 span=cloudSpan(ro,rd,depth);\n  if(span.y<=span.x || clouds<0.001) return 1.0;\n  float ds=(span.y-span.x)/8.0,tau=0.0;\n  for(int i=0;i<8;i++) tau+=cloudDensity(ro+rd*(span.x+(float(i)+0.5)*ds))*ds;\n  return exp(-0.85*clouds*tau);\n}\n\nvoid main() {\n  vec2 uv=(gl_FragCoord.xy-0.5*RENDERSIZE)/min(RENDERSIZE.x,RENDERSIZE.y)*2.0;\n  float tm=TIME*flight/0.65;\n  gTime=tm;\n  float bank,pitch; mat3 pose=frameAt(tm,bank,pitch);\n  gFrame=pose; gBank=bank; gSway=-0.14*bank; gNod=-0.12*pitch;\n  vec3 origin=positionAt(tm);\n  float phase=mod(origin.x/3.5,RUN);\n  float dive=beat(phase,4.0,8.0,9.0,13.0);\n  float carve=beat(phase,8.0,11.0,14.0,18.0);\n  float reveal=beat(phase,18.0,22.0,23.0,26.0);\n  gFlutter=journey*(0.010+0.018*dive)*sin(tm*8.4);\n  vec3 lag=velocityAt(tm-0.65);\n  float az=azimuth*0.017453293+0.60*atan(lag.z,lag.x)\n    +journey*(0.23*carve-0.13*dive+0.16*reveal);\n  float el=clamp(elevation+journey*(-5.0+14.0*dive-6.0*carve+11.0*reveal),5.0,50.0)*0.017453293;\n  vec3 low=mix(vec3(0.77,0.89,0.90),vec3(0.96,0.82,0.66),sky);\n  vec3 target=origin+vec3(0.0,1.02,0.0)+pose[0]*(0.10*dive);\n  float distance=7.10+journey*(-0.40*carve+1.5*reveal+0.35*cos(tm*6.2831853/RUN));\n  vec3 worldRo=target+distance*vec3(cos(az)*cos(el),sin(el),sin(az)*cos(el))\n    -velocityAt(tm)*(0.10*journey*dive);\n  vec3 fw=normalize(target-worldRo),rt=normalize(cross(fw,vec3(0,1,0))),up=cross(rt,fw);\n  vec2 lens=turn(bank*0.22)*uv;\n  float focal=2.43+journey*(-0.15*dive+0.10*carve);\n  vec3 worldRd=normalize(rt*lens.x+up*lens.y+fw*focal);\n  vec3 col=skyColor(worldRd);\n  vec3 ro=localVector(worldRo-origin,pose),rd=localVector(worldRd,pose);\n  float hit=100.0,material=0.0; vec3 n=vec3(0,1,0);\n  paper(ro,rd,hit,n,material);\n  vec2 span=bounds(ro,rd);\n  float t=max(span.x,0.0),end=min(span.y,hit);\n  for(int i=0;i<116;i++) {\n    if(t>end) break;\n    vec2 d=animal(ro+rd*t);\n    if(d.x<0.0015) { hit=t; material=d.y; n=normal(ro+rd*t); break; }\n    t+=max(d.x*0.78,0.0008);\n  }\n  if(material>0.5) {\n    vec3 p=ro+rd*hit;\n    vec3 light=localVector(normalize(vec3(-0.65,1.3,1.8)),pose);\n    vec3 base=mix(vec3(0.38,0.73,0.48),vec3(0.13,0.47,0.39),skin);\n    if(material<2.0) {\n      vec3 q=restPoint(p);\n      float belly=(1.0-smoothstep(0.48,0.66,q.y))*smoothstep(-0.93,-0.45,q.x)*(1.0-smoothstep(0.12,0.28,q.x));\n      base=mix(base,vec3(0.72,0.80,0.50),belly*0.7);\n      float freckles=sin(q.x*31.0)*sin(q.y*28.0)*sin(q.z*25.0);\n      base*=1.0-0.07*smoothstep(0.65,0.9,freckles);\n      // A mouth marking lives on the skin rather than floating beside it.\n      float mouth=abs(q.y-1.822)+max(1.00-q.x,0.0)+max(q.x-1.235,0.0);\n      base=mix(base,vec3(0.055,0.15,0.10),0.7*(1.0-smoothstep(0.002,0.009,mouth)));\n    } else if(material<3.5) base=vec3(0.92,0.94,0.74);\n    else if(material<4.5) base=vec3(0.025,0.08,0.065);\n    else if(material<5.5) base=vec3(0.96,0.90,0.71);\n    else if(material<7.0) base=vec3(0.34,0.095,0.025);\n    else {\n      float footprint=2.0*hit/(focal*min(RENDERSIZE.x,RENDERSIZE.y)*max(0.12,abs(dot(n,rd))));\n      base=paperSurface(p,footprint);\n      if(material>10.5 && material<12.5) base*=0.975;\n      if(material>13.5) base*=vec3(0.88,0.92,0.96);\n    }\n    // Share the two expensive distance evaluations across material branches.\n    // Close paper contact stays dark while the directional penumbra opens out.\n    float nearAO=material>7.0?0.075:0.12,farAO=material>7.0?0.22:0.30;\n    float ao=1.0-(material>7.0?0.30:0.27)*sat((nearAO-animal(p+n*nearAO).x)/nearAO);\n    ao-=(material>7.0?0.12:0.15)*sat((farAO-animal(p+n*farAO).x)/farAO);\n    float wrap=0.16*softness;\n    float dif=sat((dot(n,light)+wrap)/(1.0+wrap)),sh=shadow(p+n*0.009,light);\n    vec3 ambient=mix(vec3(0.27,0.28,0.27),vec3(0.44,0.53,0.61),0.5+0.5*n.y);\n    // A little diffuse skin fill keeps the jade buoyant under this softer key.\n    // Warm reflected paper light under the belly, rather than a grey cavity.\n    if(material<2.0) {\n      ambient+=vec3(0.035,0.070,0.035);\n      ambient+=vec3(0.13,0.10,0.055)*(1.0-smoothstep(0.25,0.95,p.y))*sat(0.4-n.y);\n    }\n    float opening=1.0-journey*0.20*carve+journey*0.12*reveal;\n    col=base*(ambient*ao+vec3(0.75,0.68,0.55)*dif*sh*opening);\n    float spec=pow(max(dot(n,normalize(light-rd)),0.0),mix(30.0,13.0,softness));\n    if(material<2.0) col+=vec3(0.075,0.080,0.067)*mix(1.0,0.52,softness)*spec*sh;\n    if(material>7.0) col+=base*vec3(0.07,0.055,0.035)*pow(max(dot(-n,light),0.0),2.0);\n    if(material>5.5 && material<7.0) col+=vec3(0.40,0.10,0.015)*(0.85+0.15*sin(TIME*2.2));\n    col+=vec3(0.24,0.16,0.065)*pow(1.0-max(dot(n,-rd),0.0),3.0)*sat(n.y+0.35);\n    col=mix(col,low,0.025);\n  }\n  col=cloudComposite(worldRo,worldRd,col,hit);\n  // Diffuse vapor and two twisting opal folds. Geometry lives in world space;\n  // view-dependent thickness and pearl color supply the camera response.\n  if(smoke>0.001) {\n    float speed=length(velocityAt(tm))*flight/0.65;\n    float lifetime=1.50/(1.0+0.13*speed);\n    float strain=smoothstep(2.0,10.0,speed);\n    float vapor=0.0,depthSum=0.0; vec3 pearl=vec3(0);\n    vec3 previous,previousSpread; float previousAge,previousPulse;\n    smokeSample(0.0,lifetime,previous,previousSpread,previousAge,previousPulse);\n    for(int i=1;i<=64;i++) {\n      float u=float(i)/64.0,age,pulse;\n      vec3 next,spread; smokeSample(u,lifetime,next,spread,age,pulse);\n      vec3 segment=next-previous; float len=max(length(segment),0.00001);\n      vec3 tangent=segment/len,across=spread+previousSpread;\n      across-=tangent*dot(across,tangent);\n      if(dot(across,across)<0.0001) {\n        vec3 ref=abs(tangent.y)<0.9?vec3(0,1,0):vec3(0,0,1);\n        across=cross(tangent,ref);\n      }\n      across=normalize(across); vec3 norm=normalize(cross(tangent,across));\n      vec3 p=0.5*(previous+next);\n      float grow=smoothstep(0.0,0.25,u);\n      float width=(0.026+0.25*pow(u,0.75))*(1.0-0.24*strain);\n      float thin=mix(width*0.90,width*0.26,grow);\n      float along=max(0.065,len*0.85);\n      vec2 mist=smokeParcel(worldRo,worldRd,p,tangent,across,norm,\n        vec3(max(along,width*0.7),width*1.45,width*0.95),len,hit);\n      // Older folds peel away from the diffuse core, rather than drawing two\n      // perfectly parallel ropes. Each parcel's phase follows emission time.\n      float emitted=TIME-age;\n      float shed=smoothstep(0.10,0.85,u)*(0.08+0.28*curl);\n      vec3 split=across*width*(0.65+0.45*sin(12.0*age+emitted))\n        +norm*shed*0.80;\n      vec2 silk=smokeParcel(worldRo,worldRd,p+split,\n        tangent,across,norm,vec3(along,width*0.65,thin),len,hit);\n      vec2 lace=smokeParcel(worldRo,worldRd,p-split*0.65+norm*shed*0.6*sin(9.0*age+emitted*0.6),\n        tangent,across,norm,vec3(along,width*0.46,thin*0.65),len,hit);\n      float fade=(1.0-smoothstep(0.58,1.0,u))*exp(-u*0.45)*pulse;\n      float dm=mist.x*0.85*fade,ds=silk.x*3.1*fade,dl=lace.x*2.6*fade;\n      float facing=abs(dot(norm,-worldRd));\n      float pearlShift=0.5+0.5*sin(6.0*u-emitted*0.85+2.6*facing);\n      vec3 opal=mix(vec3(0.68,0.89,0.97),vec3(0.94,0.76,0.95),pearlShift);\n      opal=mix(vec3(0.92,0.94,0.96),opal,opalescence);\n      vec3 glow=mix(opal,vec3(0.98,0.94,0.86),0.22*pow(1.0-facing,2.0));\n      float lighting=0.78+0.22*abs(dot(norm,normalize(vec3(-0.54,0.22,-0.84))));\n      vec3 haze=mix(vec3(0.79,0.83,0.87),opal*0.88,opalescence)*lighting;\n      float density=dm+ds+dl;\n      vapor+=density; depthSum+=dm*mist.y+ds*silk.y+dl*lace.y;\n      pearl+=dm*haze+ds*glow+dl*mix(opal,vec3(0.76,0.80,0.99),0.25*opalescence);\n      previous=next; previousSpread=spread;\n    }\n    if(vapor>0.00001) {\n      float visibility=smokeTransmission(worldRo,worldRd,max(0.0,depthSum/vapor));\n      col=mix(col,pearl/vapor,0.82*(1.0-exp(-vapor*smoke*1.65/0.82))*visibility);\n    }\n  }\n  // Output is display-referred; avoid an extra gamma lift that bleaches the paper.\n  gl_FragColor=vec4(clamp(col,0.0,1.0),1.0);\n}\n",
    "generator": {
      "model": "gpt-6.1-sol",
      "provider": "openai",
      "prompt": "A brontosaurus smoking a joint while riding a flying paper plane above the clouds. Thrilling cloud-surfing flight and camera work; an unbothered pilot and beautiful shifting opalescent smoke.",
      "params": null
    }
  }
}