VOLTAIC · GIZA
GREAT PYRAMID · base 230.33 m · height 146.6 m
face slope 51°50′40″ (51.84°) · h/½base ≈ 1.273
mueve VENUS · la pirámide le lanza el rayo · toca = descarga
wogl.io
#version 300 es
in vec2 p; void main(){ gl_Position=vec4(p,0.,1.); }
#version 300 es
precision highp float;
out vec4 frag;
uniform vec2 uRes;
uniform float uTime, uFlash;
uniform vec2 uGaze;
uniform int uFbmOct;
uniform vec3 uTint, uTint2;
float hash(vec2 p){ p=fract(p*vec2(123.34,456.21)); p+=dot(p,p+45.32); return fract(p.x*p.y); }
float noise(vec2 p){ vec2 i=floor(p),f=fract(p);
float a=hash(i),b=hash(i+vec2(1,0)),c=hash(i+vec2(0,1)),d=hash(i+vec2(1,1));
vec2 u=f*f*(3.0-2.0*f); return mix(mix(a,b,u.x),mix(c,d,u.x),u.y); }
float fbm(vec2 p,int oct){ float v=0.0,a=0.55; for(int i=0;i<4;i++){ if(i>=oct) break; v+=a*noise(p); p=p*2.03+vec2(1.7,9.2); a*=0.5; } return v; }
float segd(vec2 p, vec2 a, vec2 b){ vec2 pa=p-a, ba=b-a; float h=clamp(dot(pa,ba)/dot(ba,ba),0.0,1.0); return length(pa-ba*h); }
// arco eléctrico entre a y b (zigzag por ruido, se pega en los extremos)
float bolt(vec2 p, vec2 a, vec2 b, float t, float seed, int oct){
vec2 dir=b-a; float len=length(dir); if(len<1e-4) return 0.0;
vec2 n=normalize(vec2(-dir.y,dir.x));
float h=clamp(dot(p-a,dir)/dot(dir,dir),0.0,1.0);
float amp=len*0.11;
float wob=(fbm(vec2(h*8.0+seed, t*9.0), oct)-0.5)*amp
+(fbm(vec2(h*19.0-seed, t*14.0), oct)-0.5)*amp*0.4;
wob*=sin(h*3.14159);
vec2 base=a+dir*h + n*wob;
float d=length(p-base);
return 0.0022/(d+0.001) + 0.008/(d*d*45.0+0.02)*0.5;
}
// ── geometría EXACTA de Giza (pendiente 51.84°, h/½base = 1.273) ──
const float B = 0.62; // semi-base en pantalla
const float BY = -0.52; // línea de base
const float SL = 1.2730; // altura / semi-base (real)
// apex:
const float AY = BY + B*SL; // = -0.52 + 0.789 = 0.269
vec3 wShoulder(vec3 c){
c = max(c, 0.0);
float p = max(c.r, max(c.g, c.b));
if (p <= 0.70) return c;
float s = 0.70 + 0.30 * (1.0 - exp(-(p - 0.70) / 0.30));
return c * (s / p);
}
void main(){
vec2 uv=gl_FragCoord.xy/uRes;
vec2 p=(gl_FragCoord.xy-0.5*uRes)/uRes.y;
float t=uTime;
vec2 A=vec2(0.0, AY), L=vec2(-B, BY), R=vec2(B, BY);
vec2 g=uGaze;
// ── cielo nocturno ──
vec3 col=mix(vec3(0.03,0.035,0.07), vec3(0.01,0.01,0.03), uv.y);
// estrellas
// stars: the cell picks which ones exist, the distance to the seed draws them round
vec2 sg=p*46.0, sc=floor(sg), sf=fract(sg)-0.5;
float sv=hash(sc);
vec2 sj=vec2(hash(sc+11.3), hash(sc+27.7))-0.5; // the star sits off-centre in its cell
float sd=length(sf-sj*0.7);
float mag=smoothstep(0.986,1.0,sv); // how many, and how bright
float core=exp(-sd*sd*(900.0-760.0*mag)); // gaussian: a point with a halo, never an edge
float spike=exp(-abs(sf.x-sj.x*0.7)*190.0)+exp(-abs(sf.y-sj.y*0.7)*190.0);
float twinkle=0.55+0.45*sin(t*3.0+sv*40.0);
float star=mag*twinkle*(core+spike*core*0.55);
col+=vec3(0.9,0.95,1.0)*star*step(BY,p.y);
// aurora eléctrica tenue en el horizonte
col+=uTint*0.10*pow(fbm(p*2.2+vec2(t*0.05,0.0), uFbmOct),3.0)*smoothstep(BY,0.5,p.y);
// ── arena ──
if(p.y<BY){
float dune=fbm(p*3.0+vec2(0.0,1.0), uFbmOct);
col=mix(vec3(0.05,0.04,0.035), vec3(0.09,0.07,0.05), dune);
col+=uTint*0.05/(dot(p-vec2(0.0,BY),p-vec2(0.0,BY))*8.0+0.3); // reflejo del glow
}
// ── LA PIRÁMIDE (perfil a escala) ──
float halfW=B*(AY-p.y)/(AY-BY);
float inside=step(BY,p.y)*step(p.y,AY)*step(abs(p.x),halfW);
if(inside>0.5){
// luz de luna desde la izquierda: cara izq más clara
float face=(p.x<0.0)?0.82:0.5;
vec3 stone=mix(vec3(0.10,0.09,0.075), vec3(0.16,0.14,0.11), face);
// hiladas de bloques (courses) + junta vertical alternada
float row=(AY-p.y)*44.0;
float ry=fract(row);
float course=smoothstep(0.10,0.0,abs(ry-0.5));
float off=step(0.5,fract(floor(row)*0.5));
float col2=fract(p.x*34.0+off*0.5);
float joint=smoothstep(0.09,0.0,abs(col2-0.5));
stone*=1.0-0.35*course-0.22*joint;
stone*=0.85+0.3*fbm(p*30.0, uFbmOct);
// gradiente de altura (base más oscura)
stone*=mix(0.75,1.12, (p.y-BY)/(AY-BY));
col=stone;
}
// ── electricidad ──
float E=0.0;
// aristas de la pirámide electrificadas (siempre crepitan)
E += bolt(p, A, L, t, 1.3, uFbmOct)*(0.6+0.4*sin(t*6.0));
E += bolt(p, A, R, t, 4.7, uFbmOct)*(0.6+0.4*sin(t*6.0+2.0));
E += bolt(p, L, R, t, 8.1, uFbmOct)*0.35; // base
// rayos que BUSCAN el dedo (desde apex y las dos esquinas → chain)
E += bolt(p, A, g, t, 2.2, uFbmOct)*(1.15+uFlash); // apex → Venus (principal)
E += bolt(p, L, g, t+0.3, 5.5, uFbmOct)*0.45;
E += bolt(p, R, g, t+0.6, 9.9, uFbmOct)*0.45;
vec3 spark=mix(uTint, vec3(1.0), clamp(E*0.6,0.0,1.0));
col += spark*clamp(E,0.0,2.2);
col += uTint2*clamp(E*0.4,0.0,1.0);
// ── capstone (pyramidion) brillando en el apex ──
float ad=length(p-A);
col += mix(uTint, vec3(1.0,0.92,0.6), 0.5)*(0.006/(ad*ad*70.0+0.008))*(0.7+0.5*sin(t*8.0)+uFlash);
// destello global
col += uTint*uFlash*0.22;
// ── VENUS (el cursor) ──
{
vec2 vd=p-g; float vr=length(vd);
float R=0.060;
// resplandor deslumbrante (Venus es el objeto más brillante del cielo)
col += vec3(1.0,0.95,0.76)*(0.005/(vr*vr*38.0+0.012))*(0.7+0.7*uFlash);
col += vec3(0.9,0.85,0.7)*exp(-vr*vr/(R*R*6.0))*0.5;
// disco del planeta con fase (Venus muestra fases como la Luna)
float in2=R*R-dot(vd,vd);
if(in2>0.0){
float z=sqrt(in2)/R;
vec3 N=normalize(vec3(vd/R, z));
vec3 Ld=normalize(vec3(-0.55,0.5,0.75));
float lit=clamp(dot(N,Ld),0.0,1.0);
float cl=fbm(vd*26.0+vec2(t*0.08,0.0), uFbmOct);
vec3 vcol=mix(vec3(0.32,0.26,0.16), vec3(0.98,0.93,0.72), pow(lit,0.8));
vcol*=0.82+0.32*cl; // bandas de nubes amarillas
vcol+=vec3(1.0,0.96,0.8)*pow(lit,6.0)*0.4; // brillo especular
float edge=smoothstep(R,R-0.004,vr);
col=mix(col, vcol, edge);
col+=vec3(1.0,0.9,0.6)*smoothstep(R-0.010,R,vr)*edge*lit*0.6; // limbo iluminado
}
// Venus refulge cuando el rayo la golpea
col += uTint*clamp(E,0.0,1.0)*smoothstep(0.15,0.0,vr)*0.45;
}
// acabado
col*=mix(0.68,1.0, smoothstep(1.45,0.2,length(p)));
col+=(hash(gl_FragCoord.xy+fract(t))-0.5)*0.025;
frag=vec4(wShoulder(col),1.0);
}