27:18Gemini 4 Hydrogen: Cheaper Tokens, More Expensive Answers?
Nov 13, 2026 · YouTube
18:40ERNIE 5.5 Flash Preview vs GLM 5.3 Flash: Baidu's new model is very impressive!
Nov 11, 2026 · YouTube
36:22Fable 5.2 robbing me blind, plus: Nex AGI's N2.6 vs GLM 5.3 Flash
Nov 11, 2026 · YouTube
14:03Gemini 4 Carbon: Can it handle my challenges? (First look with one-shot coding tests)
Nov 10, 2026 · YouTube
47:51Ranking major U.S. Open-Weights Models. (Where does Ripple 65B fit in?)
Nov 6, 2026 · YouTube
10:57"Crouton Alpha": the latest super-efficient coding model by Meta?
Nov 3, 2026 · YouTube
38:58Testing Particle-1: a post-trained DeepSeek V4.1 Flash specializing in coding and efficiency
Oct 28, 2026 · YouTube
29:55Kimi K3.1 Pro Looked Incredible. Then I Kept Testing.
Oct 26, 2026 · YouTube
31:28Is this company reselling GPT Sol 6.1 at a loss (for non-agentic/text-only)?🤔 Is this sustainable?
Oct 20, 2026 · YouTube
17:58Nemotron 3.5 Super VL vs Opus 5.5: Testing NVIDIA’s new coding juggernaut
Oct 15, 2026 · YouTube
16:04Testing a *massive* new open-weights model 🤯: Muse Spark Open (vs. Nemotron, Opus 5.5, and more)
Oct 15, 2026 · YouTube
16:43Gemini 4 Argon: Great 🐈 Animation, but a broken escalator. (Coding challenge vs Opus 5.5, Sol 6.1)
Oct 13, 2026 · YouTube
16:37Meta's new "Muse Wonder" AI is impressive... but can it compete with Anthropic's models?
Oct 12, 2026 · YouTube
11:12WOW... Haiku 5.5 is very impressive. RIP OpenAI?
Oct 7, 2026 · YouTube
22:47Mistral Large 4 Is Cheap. But Is It Good Enough to Compete?
Oct 6, 2026 · YouTube
22:02Is Pareto 26.10 Preview Just Routing to GPT Sol? I Tested It Against Sol 6.1 Pro
Oct 1, 2026 · YouTube
11:22I Tested Sonnet 5.5 Against Opus 5.5. Is It Actually Cheaper?
Sep 28, 2026 · YouTube
19:21I Tested the Stealth "Space Bunny Alpha" Model Before It Went Offline
Sep 23, 2026 · YouTube
10:58So... how much better is Claude Opus 5.5 vs. GPT-6 Sol, really?
Sep 23, 2026 · YouTube
9:38Claude Opus 5.5... the BEST new model for coding!! 🤩
Sep 22, 2026 · YouTube
You make short animated pieces for the web, and you have spent time on the part of the internet that makes cats famous.
Build me a single HTML page: a cat in a living room that lifts off the floor and spins in the air when you click it.
Make this the Oiia Cat — the spinning cat meme, the one whose loop is written out as "oiia oiia oiiaiooooiai". Match the original's look and feel, not a generic rotation:
Build toward what that meme feels like at full speed: too fast, too loud, and funnier every time it goes further.
data: URIs are fine.localStorage, sessionStorage, cookies or indexedDB — sandboxed frame, they throw.html block.The single fenced html block.
Five bullets.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
<title>OIIA — a very normal cat</title>
<style>
:root{color-scheme:dark;--ink:#f5f0e6;--dim:rgba(245,240,230,.58)}
*{box-sizing:border-box}
html,body{width:100%;height:100%;margin:0;overflow:hidden;background:#11100e}
body{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;color:var(--ink)}
canvas{position:fixed;inset:0;width:100%;height:100%;display:block;touch-action:manipulation;cursor:pointer}
.ui{position:fixed;inset:0;pointer-events:none;text-shadow:0 1px 12px rgba(0,0,0,.45)}
.top{position:absolute;top:0;left:0;right:0;display:flex;align-items:flex-start;justify-content:space-between;padding:22px 24px}
.brand{font:700 12px/1 ui-monospace,SFMono-Regular,Consolas,monospace;letter-spacing:.26em}
.brand span{display:block;margin-top:8px;color:var(--dim);font-size:9px;font-weight:500;letter-spacing:.18em}
button{pointer-events:auto;border:1px solid rgba(255,255,255,.2);border-radius:999px;background:rgba(12,12,12,.22);color:var(--ink);padding:9px 13px;font:600 9px/1 ui-monospace,SFMono-Regular,Consolas,monospace;letter-spacing:.12em;text-transform:uppercase;cursor:pointer;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}
button:hover{background:rgba(255,255,255,.12)}
button:focus-visible{outline:2px solid #fff;outline-offset:3px}
#caption{position:absolute;left:25px;bottom:25px;max-width:min(560px,75vw);transition:opacity .2s}
#caption .kicker{font:600 9px/1.2 ui-monospace,SFMono-Regular,Consolas,monospace;letter-spacing:.22em;color:rgba(255,255,255,.62);text-transform:uppercase}
#caption strong{display:block;margin:9px 0 6px;font-size:clamp(24px,3.4vw,48px);font-weight:520;line-height:1;letter-spacing:-.035em}
#caption p{margin:0;color:rgba(255,255,255,.66);font-size:12px;line-height:1.45}
#caption.pop{animation:pop .45s ease-out}
@keyframes pop{0%{opacity:.1;transform:translateY(9px)}100%{opacity:1;transform:none}}
#hint{position:absolute;right:25px;bottom:28px;text-align:right;font:500 9px/1.6 ui-monospace,SFMono-Regular,Consolas,monospace;letter-spacing:.12em;color:rgba(255,255,255,.66);text-transform:uppercase}
#hint b{display:block;color:#fff;font-weight:600}
.ping{position:fixed;width:20px;height:20px;margin:-10px;border:1px solid rgba(255,255,255,.8);border-radius:50%;pointer-events:none;animation:ping .55s ease-out forwards}
@keyframes ping{to{transform:scale(5);opacity:0}}
#fallback{position:fixed;inset:0;display:none;place-items:center;padding:30px;text-align:center;background:#171512;color:#eee}
@media(max-width:600px){.top{padding:17px}.brand span{display:none}#caption{left:17px;bottom:18px;max-width:82vw}#caption p{font-size:11px}#hint{right:17px;bottom:20px}#hint span{display:none}}
@media(prefers-reduced-motion:reduce){.ping{display:none}#caption.pop{animation:none}}
</style>
</head>
<body>
<canvas id="c" role="button" tabindex="0" aria-label="A cream and white cat in a living room. Click the cat to activate it."></canvas>
<div class="ui">
<div class="top">
<div class="brand">OIIA<span>AN UNEVENTFUL LIVING ROOM</span></div>
<button id="mute" aria-pressed="false" title="Mute (M)">sound / on click</button>
</div>
<div id="caption" aria-live="polite">
<div class="kicker" id="kicker">00 / DOMESTIC STILLNESS</div>
<strong id="label">A very normal cat.</strong>
<p id="sub">Please do not make this weird.</p>
</div>
<div id="hint"><b id="hintMain">CLICK THE CAT</b><span id="hintSub">M TO MUTE</span></div>
</div>
<div id="fallback">This little living room needs WebGL 2.<br>Try a current browser with hardware acceleration enabled.</div>
<script>
(() => {
"use strict";
const canvas = document.getElementById("c");
const gl = canvas.getContext("webgl2", {
alpha:false, antialias:false, depth:false, stencil:false,
powerPreference:"high-performance", preserveDrawingBuffer:false
});
if (!gl) {
document.getElementById("fallback").style.display = "grid";
canvas.style.display = "none";
return;
}
const VERT = `#version 300 es
precision highp float;
void main(){
vec2 p=vec2(float((gl_VertexID<<1)&2),float(gl_VertexID&2));
gl_Position=vec4(p*2.0-1.0,0.0,1.0);
}`;
const SCENE = `#version 300 es
precision highp float;
out vec4 outColor;
uniform vec2 uRes;
uniform float uTime,uAngle,uLift,uSpeed,uStageF,uRoomSpin,uBoost;
#define PI 3.14159265359
struct Hit { float t; float mat; float obj; vec3 n; };
Hit emptyHit(){ Hit h; h.t=1e4; h.mat=-1.0; h.obj=-1.0; h.n=vec3(0); return h; }
float hash21(vec2 p){
p=fract(p*vec2(123.34,456.21)); p+=dot(p,p+45.32); return fract(p.x*p.y);
}
float hash31(vec3 p){ return fract(sin(dot(p,vec3(127.1,311.7,74.7)))*43758.5453); }
float noise2(vec2 p){
vec2 i=floor(p),f=fract(p); f=f*f*(3.0-2.0*f);
return mix(mix(hash21(i),hash21(i+vec2(1,0)),f.x),
mix(hash21(i+vec2(0,1)),hash21(i+vec2(1)),f.x),f.y);
}
float noise3(vec3 p){
vec3 i=floor(p),f=fract(p); f=f*f*(3.0-2.0*f);
return mix(mix(mix(hash31(i),hash31(i+vec3(1,0,0)),f.x),
mix(hash31(i+vec3(0,1,0)),hash31(i+vec3(1,1,0)),f.x),f.y),
mix(mix(hash31(i+vec3(0,0,1)),hash31(i+vec3(1,0,1)),f.x),
mix(hash31(i+vec3(0,1,1)),hash31(i+vec3(1,1,1)),f.x),f.y),f.z);
}
vec2 rot2(vec2 p,float a){float c=cos(a),s=sin(a);return vec2(c*p.x-s*p.y,s*p.x+c*p.y);}
vec3 ry(vec3 p,float a){float c=cos(a),s=sin(a);return vec3(c*p.x+s*p.z,p.y,-s*p.x+c*p.z);}
vec3 rz(vec3 p,float a){float c=cos(a),s=sin(a);return vec3(c*p.x-s*p.y,s*p.x+c*p.y,p.z);}
float smin(float a,float b,float k){
float h=clamp(.5+.5*(b-a)/k,0.0,1.0);
return mix(b,a,h)-k*h*(1.0-h);
}
float sdEll(vec3 p,vec3 r){
float k0=length(p/r),k1=length(p/(r*r));
return k0*(k0-1.0)/max(k1,1e-5);
}
float sdCap(vec3 p,vec3 a,vec3 b,float r){
vec3 pa=p-a,ba=b-a;
float h=clamp(dot(pa,ba)/dot(ba,ba),0.0,1.0);
return length(pa-ba*h)-r;
}
float sdTriangle(vec2 p,vec2 p0,vec2 p1,vec2 p2){
vec2 e0=p1-p0,e1=p2-p1,e2=p0-p2;
vec2 v0=p-p0,v1=p-p1,v2=p-p2;
vec2 pq0=v0-e0*clamp(dot(v0,e0)/dot(e0,e0),0.0,1.0);
vec2 pq1=v1-e1*clamp(dot(v1,e1)/dot(e1,e1),0.0,1.0);
vec2 pq2=v2-e2*clamp(dot(v2,e2)/dot(e2,e2),0.0,1.0);
float s=sign(e0.x*e2.y-e0.y*e2.x);
vec2 d=min(min(vec2(dot(pq0,pq0),s*(v0.x*e0.y-v0.y*e0.x)),
vec2(dot(pq1,pq1),s*(v1.x*e1.y-v1.y*e1.x))),
vec2(dot(pq2,pq2),s*(v2.x*e2.y-v2.y*e2.x)));
return -sqrt(d.x)*sign(d.y);
}
float earPrism(vec3 q,vec2 a,vec2 b,vec2 c,float z,float thick){
vec2 d=vec2(sdTriangle(q.xy,a,b,c),abs(q.z-z)-thick);
return min(max(d.x,d.y),0.0)+length(max(d,vec2(0)));
}
void addShape(inout vec2 r,float d,float m){ if(d<r.x) r=vec2(d,m); }
float catScale(int i){
if(i==0){
float s2=smoothstep(1.2,2.0,uStageF),s4=smoothstep(3.25,4.0,uStageF);
return 1.0+.025*s2*sin(uAngle*2.0)+.11*s4+.008*uBoost;
}
return .30+.018*float(i);
}
vec3 catBase(int i){
if(i==0) return vec3(0.0,.045+uLift,.18);
float f=float(i-1);
float a=uTime*(.65+.07*f)+f*1.570796+uBoost*.08;
float radius=1.43+.13*sin(f*2.1);
return vec3(cos(a)*radius,
uLift+.57+.36*sin(a*1.31+f),
.18+sin(a)*radius*.66);
}
float catAngle(int i){
return i==0 ? uAngle : -uAngle*.56+uTime*2.1+float(i)*1.7;
}
float catWobble(int i){
float s2=smoothstep(1.25,2.0,uStageF),s4=smoothstep(3.2,4.0,uStageF);
return (s2*.045+s4*.085)*sin(uTime*2.0+float(i)*1.8);
}
vec3 toCatLocal(vec3 p,int i){
float sc=catScale(i);
vec3 q=p-catBase(i);
q=rz(q,-catWobble(i));
q=ry(q,-catAngle(i));
return q/sc;
}
vec2 catLocal(vec3 q,float lite){
vec2 r=vec2(1e5,100.0);
float breath=.0045*sin(uTime*1.45);
float d=sdEll(q-vec3(0,.69+breath,-.035),vec3(.43,.61,.35));
d=smin(d,sdEll(q-vec3(-.32,.34,-.015),vec3(.27,.31,.30)),.12);
d=smin(d,sdEll(q-vec3(.32,.34,-.015),vec3(.27,.31,.30)),.12);
d=smin(d,sdCap(q,vec3(-.20,.69,.18),vec3(-.20,.16,.25),.115),.08);
d=smin(d,sdCap(q,vec3(.20,.69,.18),vec3(.20,.16,.25),.115),.08);
d=smin(d,sdEll(q-vec3(-.21,.11,.29),vec3(.18,.10,.24)),.065);
d=smin(d,sdEll(q-vec3(.21,.11,.29),vec3(.18,.10,.24)),.065);
d=smin(d,sdEll(q-vec3(0,1.38,0),vec3(.43,.38,.34)),.085);
d=smin(d,sdEll(q-vec3(-.095,1.20,.275),vec3(.155,.115,.13)),.055);
d=smin(d,sdEll(q-vec3(.095,1.20,.275),vec3(.155,.115,.13)),.055);
float earL=earPrism(q,vec2(-.46,1.51),vec2(-.10,1.50),vec2(-.35,1.96),0.0,.085);
float earR=earPrism(q,vec2(.10,1.50),vec2(.46,1.51),vec2(.35,1.96),0.0,.085);
d=smin(d,earL,.025); d=smin(d,earR,.025);
if(lite<.5){
float tail=sdCap(q,vec3(-.30,.26,-.12),vec3(-.57,.15,.03),.105);
tail=smin(tail,sdCap(q,vec3(-.57,.15,.03),vec3(-.65,.11,.34),.10),.05);
tail=smin(tail,sdCap(q,vec3(-.65,.11,.34),vec3(-.43,.105,.57),.095),.05);
tail=smin(tail,sdCap(q,vec3(-.43,.105,.57),vec3(-.16,.10,.60),.085),.04);
d=smin(d,tail,.055);
}
d+=.00135*sin(q.x*119.0+sin(q.y*31.0))*sin(q.y*137.0+q.z*43.0)*sin(q.z*113.0);
r=vec2(d,100.0);
float innerL=earPrism(q,vec2(-.39,1.58),vec2(-.18,1.57),vec2(-.34,1.85),.091,.008);
float innerR=earPrism(q,vec2(.18,1.57),vec2(.39,1.58),vec2(.34,1.85),.091,.008);
addShape(r,innerL,107.0); addShape(r,innerR,107.0);
addShape(r,sdEll(q-vec3(-.165,1.43,.288),vec3(.118,.128,.085)),101.0);
addShape(r,sdEll(q-vec3(.165,1.43,.288),vec3(.118,.128,.085)),101.0);
addShape(r,sdEll(q-vec3(-.165,1.43,.365),vec3(.074,.083,.025)),102.0);
addShape(r,sdEll(q-vec3(.165,1.43,.365),vec3(.074,.083,.025)),102.0);
addShape(r,sdEll(q-vec3(-.165,1.43,.388),vec3(.025,.061,.012)),103.0);
addShape(r,sdEll(q-vec3(.165,1.43,.388),vec3(.025,.061,.012)),103.0);
addShape(r,sdEll(q-vec3(0,1.275,.394),vec3(.057,.038,.025)),104.0);
addShape(r,sdEll(q-vec3(0,1.125,.377),vec3(.050,.067,.025)),105.0);
if(lite<.5){
addShape(r,sdCap(q,vec3(-.12,1.235,.405),vec3(-.61,1.30,.47),.0034),106.0);
addShape(r,sdCap(q,vec3(-.12,1.195,.405),vec3(-.58,1.10,.47),.0032),106.0);
addShape(r,sdCap(q,vec3(.12,1.235,.405),vec3(.61,1.30,.47),.0034),106.0);
addShape(r,sdCap(q,vec3(.12,1.195,.405),vec3(.58,1.10,.47),.0032),106.0);
}
return r;
}
vec2 catWorld(vec3 p,int i){
float sc=catScale(i);
vec2 h=catLocal(toCatLocal(p,i),i==0?0.0:1.0);
h.x*=sc; return h;
}
vec2 sphereBound(vec3 ro,vec3 rd,vec3 c,float r){
vec3 oc=ro-c; float b=dot(oc,rd),cc=dot(oc,oc)-r*r;
float d=b*b-cc; if(d<0.0)return vec2(-1);
d=sqrt(d); return vec2(-b-d,-b+d);
}
Hit traceCat(vec3 ro,vec3 rd,int i,float maxT){
Hit h=emptyHit(); h.obj=float(i);
float sc=catScale(i);
vec3 base=catBase(i);
vec2 bound=sphereBound(ro,rd,base+vec3(0,.96*sc,0),1.30*sc);
if(bound.y<0.0)return h;
float t=max(bound.x,.001),end=min(bound.y,maxT);
if(t>end)return h;
for(int j=0;j<72;j++){
if(t>end || (i>0&&j>44))break;
vec3 p=ro+rd*t;
vec2 d=catWorld(p,i);
if(d.x<.0017*sc){
h.t=t;h.mat=d.y;
vec2 e=vec2(1,-1)*.0022*sc;
h.n=normalize(e.xyy*catWorld(p+e.xyy,i).x+
e.yyx*catWorld(p+e.yyx,i).x+
e.yxy*catWorld(p+e.yxy,i).x+
e.xxx*catWorld(p+e.xxx,i).x);
return h;
}
t+=max(d.x*.79,.00065);
}
return h;
}
vec3 moved(vec3 c,float group){
if(group<1.5)return c;
float lev=smoothstep(1.25,2.0,uStageF);
float orbit=smoothstep(2.25,3.0,uStageF);
float cosmic=smoothstep(3.25,4.0,uStageF);
c.y+=lev*(.065+.095*sin(uTime*1.45+group*1.7));
float a=orbit*.22*sin(uTime*.43+group)+cosmic*.57*sin(uTime*.34+group*1.4);
c.xz=rot2(c.xz,a);
c.y+=orbit*.09+cosmic*(.42+.20*sin(uTime*.8+group));
c.x+=cosmic*.15*sin(uTime*.7+group*2.0);
return c;
}
void setHit(inout Hit h,float t,float mat,vec3 n){
if(t>.0005&&t<h.t){h.t=t;h.mat=mat;h.n=n;h.obj=-1.0;}
}
void boxHit(vec3 ro,vec3 rd,vec3 c,vec3 b,float mat,float group,inout Hit h){
c=moved(c,group);
vec3 inv=1.0/rd,n=inv*(ro-c),k=abs(inv)*b;
vec3 t1=-n-k,t2=-n+k;
float tn=max(max(t1.x,t1.y),t1.z),tf=min(min(t2.x,t2.y),t2.z);
if(tn>tf||tf<0.0||tn<.0005||tn>h.t)return;
vec3 no;
if(tn==t1.x)no=vec3(-sign(rd.x),0,0);
else if(tn==t1.y)no=vec3(0,-sign(rd.y),0);
else no=vec3(0,0,-sign(rd.z));
setHit(h,tn,mat,no);
}
void ellHit(vec3 ro,vec3 rd,vec3 c,vec3 r,float mat,float group,inout Hit h){
c=moved(c,group);
vec3 o=(ro-c)/r,d=rd/r;
float a=dot(d,d),b=dot(o,d),cc=dot(o,o)-1.0;
float disc=b*b-a*cc;if(disc<0.0)return;
float t=(-b-sqrt(disc))/a;
if(t<.0005)t=(-b+sqrt(disc))/a;
if(t<.0005||t>h.t)return;
vec3 p=ro+rd*t-c;
setHit(h,t,mat,normalize(p/(r*r)));
}
void coneHit(vec3 ro,vec3 rd,vec3 c,float hh,float rb,float rt,float mat,float group,inout Hit h){
c=moved(c,group);
vec3 o=ro-c;
float k=(rt-rb)/(2.0*hh),r0=(rb+rt)*.5;
float A=dot(rd.xz,rd.xz)-k*k*rd.y*rd.y;
float B=2.0*(dot(o.xz,rd.xz)-(r0+k*o.y)*k*rd.y);
float C=dot(o.xz,o.xz)-(r0+k*o.y)*(r0+k*o.y);
float disc=B*B-4.0*A*C;
if(disc>=0.0&&abs(A)>1e-7){
float sq=sqrt(disc);
for(int j=0;j<2;j++){
float t=(-B+(j==0?-sq:sq))/(2.0*A);
if(t>.0005&&t<h.t){
vec3 p=o+rd*t;
if(abs(p.y)<=hh){
float rr=r0+k*p.y;
setHit(h,t,mat,normalize(vec3(p.x,-rr*k,p.z)));
}
}
}
}
if(abs(rd.y)>1e-6){
float t=(-hh-o.y)/rd.y;vec3 p=o+rd*t;
if(t>.0005&&dot(p.xz,p.xz)<=rb*rb)setHit(h,t,mat,vec3(0,-1,0));
t=(hh-o.y)/rd.y;p=o+rd*t;
if(t>.0005&&dot(p.xz,p.xz)<=rt*rt)setHit(h,t,mat,vec3(0,1,0));
}
}
Hit traceRoom(vec3 ro,vec3 rd){
Hit h=emptyHit();
if(rd.y<-.00001){float t=-ro.y/rd.y;setHit(h,t,1.0,vec3(0,1,0));}
if(rd.y>.00001){float t=(4.6-ro.y)/rd.y;setHit(h,t,2.0,vec3(0,-1,0));}
if(rd.z<-.00001){float t=(-4.0-ro.z)/rd.z;setHit(h,t,2.0,vec3(0,0,1));}
if(rd.x<-.00001){float t=(-5.0-ro.x)/rd.x;setHit(h,t,2.0,vec3(1,0,0));}
if(rd.x>.00001){float t=(5.0-ro.x)/rd.x;setHit(h,t,2.0,vec3(-1,0,0));}
boxHit(ro,rd,vec3(0,.025,.35),vec3(2.05,.025,1.55),3.0,0.0,h);
boxHit(ro,rd,vec3(0,.11,-3.90),vec3(5,.11,.07),4.0,0.0,h);
boxHit(ro,rd,vec3(-4.93,.11,0),vec3(.07,.11,4),4.0,0.0,h);
boxHit(ro,rd,vec3(4.93,.11,0),vec3(.07,.11,4),4.0,0.0,h);
boxHit(ro,rd,vec3(-2.35,2.25,-3.94),vec3(.96,.86,.025),5.0,0.0,h);
boxHit(ro,rd,vec3(-3.36,2.25,-3.87),vec3(.065,.94,.055),4.0,0.0,h);
boxHit(ro,rd,vec3(-1.34,2.25,-3.87),vec3(.065,.94,.055),4.0,0.0,h);
boxHit(ro,rd,vec3(-2.35,3.16,-3.87),vec3(1.08,.065,.055),4.0,0.0,h);
boxHit(ro,rd,vec3(-2.35,1.34,-3.87),vec3(1.08,.065,.055),4.0,0.0,h);
boxHit(ro,rd,vec3(-2.35,2.25,-3.85),vec3(.035,.86,.045),4.0,0.0,h);
boxHit(ro,rd,vec3(-2.35,2.25,-3.85),vec3(.96,.035,.045),4.0,0.0,h);
boxHit(ro,rd,vec3(-3.52,2.20,-3.70),vec3(.18,1.12,.12),6.0,0.0,h);
boxHit(ro,rd,vec3(-1.18,2.20,-3.70),vec3(.18,1.12,.12),6.0,0.0,h);
boxHit(ro,rd,vec3(.05,2.58,-3.89),vec3(.68,.46,.045),4.0,0.0,h);
boxHit(ro,rd,vec3(.05,2.58,-3.835),vec3(.59,.37,.018),13.0,0.0,h);
ellHit(ro,rd,vec3(2.35,.46,-2.72),vec3(1.45,.37,.62),7.0,2.0,h);
ellHit(ro,rd,vec3(2.35,1.04,-3.15),vec3(1.43,.67,.28),7.0,2.0,h);
ellHit(ro,rd,vec3(1.00,.74,-2.72),vec3(.22,.47,.64),7.0,2.0,h);
ellHit(ro,rd,vec3(3.70,.74,-2.72),vec3(.22,.47,.64),7.0,2.0,h);
ellHit(ro,rd,vec3(1.72,.76,-2.54),vec3(.62,.18,.47),8.0,2.0,h);
ellHit(ro,rd,vec3(2.98,.76,-2.54),vec3(.62,.18,.47),8.0,2.0,h);
ellHit(ro,rd,vec3(1.72,1.16,-2.94),vec3(.59,.45,.17),8.0,2.0,h);
ellHit(ro,rd,vec3(2.98,1.16,-2.94),vec3(.59,.45,.17),8.0,2.0,h);
ellHit(ro,rd,vec3(3.16,1.15,-2.57),vec3(.29,.32,.14),15.0,2.0,h);
ellHit(ro,rd,vec3(-2.52,.57,-2.10),vec3(.57,.075,.46),4.0,3.0,h);
boxHit(ro,rd,vec3(-2.88,.28,-2.30),vec3(.035,.29,.035),4.0,3.0,h);
boxHit(ro,rd,vec3(-2.17,.28,-2.30),vec3(.035,.29,.035),4.0,3.0,h);
boxHit(ro,rd,vec3(-2.52,.28,-1.87),vec3(.035,.29,.035),4.0,3.0,h);
boxHit(ro,rd,vec3(-2.60,.675,-2.08),vec3(.28,.035,.20),14.0,3.0,h);
boxHit(ro,rd,vec3(-2.56,.73,-2.08),vec3(.24,.025,.18),14.0,3.0,h);
ellHit(ro,rd,vec3(-2.25,.79,-2.03),vec3(.11,.14,.11),15.0,3.0,h);
ellHit(ro,rd,vec3(4.05,.055,-2.75),vec3(.31,.055,.31),9.0,4.0,h);
coneHit(ro,rd,vec3(4.05,1.06,-2.75),1.0,.025,.025,9.0,4.0,h);
coneHit(ro,rd,vec3(4.05,2.13,-2.75),.34,.45,.28,10.0,4.0,h);
coneHit(ro,rd,vec3(-3.85,.30,-1.55),.30,.27,.36,12.0,5.0,h);
coneHit(ro,rd,vec3(-3.85,.91,-1.55),.42,.025,.018,11.0,5.0,h);
ellHit(ro,rd,vec3(-3.99,1.18,-1.55),vec3(.16,.43,.09),11.0,5.0,h);
ellHit(ro,rd,vec3(-3.66,1.30,-1.53),vec3(.15,.40,.10),11.0,5.0,h);
ellHit(ro,rd,vec3(-4.08,1.52,-1.55),vec3(.13,.34,.08),11.0,5.0,h);
ellHit(ro,rd,vec3(-3.69,1.67,-1.57),vec3(.12,.32,.09),11.0,5.0,h);
ellHit(ro,rd,vec3(-3.85,1.87,-1.55),vec3(.11,.30,.08),11.0,5.0,h);
ellHit(ro,rd,vec3(-4.12,.94,-1.45),vec3(.30,.12,.13),11.0,5.0,h);
ellHit(ro,rd,vec3(-3.57,1.00,-1.60),vec3(.29,.12,.13),11.0,5.0,h);
return h;
}
vec3 shadeRoom(Hit h,vec3 p,vec3 ro){
float m=h.mat,cosmic=smoothstep(3.2,4.0,uStageF);
vec3 albedo=vec3(.5),N=h.n;
float specPower=16.0,specAmount=.08,emit=0.0;
if(m<1.5){
float plank=floor((p.x+5.0)/.36);
float tone=hash21(vec2(plank,2.7));
float seam=smoothstep(.035,.008,fract((p.x+5.0)/.36));
float endSeam=smoothstep(.025,.006,fract((p.z+plank*.37)/1.75));
float grain=noise2(vec2(p.x*15.0,p.z*2.2))*.65+
.35*sin(p.z*49.0+noise2(vec2(p.x*8.0,p.z*2.0))*5.0);
albedo=mix(vec3(.25,.145,.078),vec3(.42,.28,.15),tone);
albedo*=.91+.12*grain;
albedo*=1.0-.38*max(seam,endSeam);
specPower=42.0;specAmount=.30;
}else if(m<2.5){
float plaster=noise2(p.xy*3.0+p.zy*.7);
albedo=vec3(.61,.58,.51)*(.96+.035*plaster);
albedo=mix(albedo,vec3(.16,.15,.25),cosmic*.72);
specAmount=.015;
}else if(m<3.5){
vec2 q=p.xz-vec2(0,.35);
float border=max(smoothstep(1.72,1.92,abs(q.x)),smoothstep(1.25,1.43,abs(q.y)));
float weave=.88+.12*sin(p.x*210.0)*sin(p.z*180.0);
float motif=.5+.5*sin(q.x*5.0)*sin(q.y*5.0);
albedo=mix(vec3(.20,.25,.245),vec3(.34,.18,.13),border);
albedo*=.88+.15*motif;albedo*=weave;
specPower=5.0;specAmount=.015;
}else if(m<4.5){
albedo=vec3(.19,.105,.052)*(.9+.15*noise2(p.xz*8.0+p.yy*3.0));
specPower=28.0;specAmount=.18;
}else if(m<5.5){
vec2 q=(p.xy-vec2(-2.35,2.25))/vec2(.96,.86);
vec3 sky=mix(vec3(.43,.60,.69),vec3(.77,.82,.79),clamp(q.y*.5+.5,0.0,1.0));
float tree=noise2(vec2(q.x*3.2,q.y*2.0)+vec2(3.1,0));
sky=mix(sky,vec3(.17,.28,.19),smoothstep(.47,.7,tree)*smoothstep(.2,-.65,q.y));
float a=atan(q.y,q.x),r=length(q);
vec3 portal=mix(vec3(.055,.025,.15),vec3(.15,.55,.72),.5+.5*sin(a*4.0-r*8.0+uTime*.5));
float stars=step(.992,hash21(floor((q+2.0)*90.0)));
portal+=stars*vec3(.8,.9,1.0);
return mix(sky*1.12,portal*1.35,cosmic);
}else if(m<6.5){
float pleat=.72+.28*pow(.5+.5*sin(p.x*53.0),2.0);
albedo=vec3(.66,.60,.49)*pleat;specAmount=.025;
}else if(m<7.5){
albedo=vec3(.24,.285,.255)*(.87+.17*noise2(p.xy*70.0+p.zx*9.0));
specPower=7.0;specAmount=.035;
}else if(m<8.5){
albedo=vec3(.36,.40,.35)*(.88+.15*noise2(p.xy*85.0));
specPower=7.0;specAmount=.03;
}else if(m<9.5){
albedo=vec3(.12,.105,.08);specPower=65.0;specAmount=.65;
}else if(m<10.5){
float fabric=.9+.1*sin(p.y*150.0);
albedo=vec3(.72,.53,.30)*fabric;emit=.22;specAmount=.03;
}else if(m<11.5){
albedo=mix(vec3(.055,.16,.075),vec3(.16,.29,.11),noise2(p.xy*5.0+p.zy));
specPower=30.0;specAmount=.28;
}else if(m<12.5){
albedo=vec3(.39,.17,.09)*(.85+.18*noise2(p.xz*17.0+p.yy*4.0));
specAmount=.05;
}else if(m<13.5){
vec2 q=(p.xy-vec2(.05,2.58))/vec2(.59,.37);
albedo=mix(vec3(.12,.25,.29),vec3(.60,.40,.23),clamp(q.y*.5+.55,0.0,1.0));
float sun=1.0-smoothstep(.17,.19,length(q-vec2(.28,.23)));
albedo=mix(albedo,vec3(.91,.68,.35),sun);
albedo*=.9+.1*noise2(q*14.0);specAmount=.01;
}else if(m<14.5){
float id=floor(p.x*7.0)+floor(p.y*19.0);
albedo=mix(vec3(.28,.07,.045),vec3(.075,.18,.22),hash21(vec2(id,3.0)));
}else{
albedo=p.y<1.0?vec3(.63,.60,.51):vec3(.43,.16,.095);
specPower=35.0;specAmount=.25;
}
float occ=1.0;
if(m<1.5||(m>2.5&&m<3.5)){
float rad=.64+.13*uLift;
vec2 cp=(p.xz-vec2(0,.18))/vec2(rad,rad*.77);
float catShadow=exp(-dot(cp,cp)*1.55);
occ*=1.0-(.60/(1.0+.55*uLift))*catShadow;
vec2 sp=(p.xz-vec3(2.35,0,-2.72).xz)*vec2(.65,1.05);
occ*=1.0-.22*exp(-dot(sp,sp)*1.8);
vec2 tp=(p.xz-vec2(-2.52,-2.1));
occ*=1.0-.15*exp(-dot(tp,tp)*3.0);
}
if(m<1.5&&cosmic>.001){
float rr=length(p.xz-vec2(0,.18));
N=normalize(N+vec3(sin(rr*10.0-uTime*2.0),0,cos(rr*9.0-uTime*1.7))*.055*cosmic);
albedo=mix(albedo,vec3(.16,.10,.25),cosmic*.38);
}
vec3 V=normalize(ro-p);
vec3 keyPos=vec3(-3.4,4.0,2.6);
vec3 L=normalize(keyPos-p);
vec3 lampPos=moved(vec3(4.05,2.1,-2.75),4.0);
vec3 LL=normalize(lampPos-p);
float lampDist=length(lampPos-p);
float diff=max(dot(N,L),0.0),ldiff=max(dot(N,LL),0.0);
vec3 keyColor=mix(vec3(1.05,.92,.76),vec3(.66,.78,1.25),cosmic*.65);
vec3 ambient=mix(vec3(.22,.245,.27),vec3(.17,.135,.28),cosmic);
float lampPulse=1.0+.045*smoothstep(.2,1.0,uStageF)*sin(uAngle*.5);
vec3 light=ambient+keyColor*diff*.88+
vec3(1.0,.48,.20)*ldiff*lampPulse*.72/(1.0+.16*lampDist*lampDist);
vec3 col=albedo*light*occ;
vec3 H=normalize(L+V);
col+=keyColor*pow(max(dot(N,H),0.0),specPower)*specAmount*diff;
if(emit>0.0)col+=albedo*emit*(1.0+.15*sin(uAngle*.25));
if(cosmic>.01&&(m<2.5||m<1.5)){
float rings=pow(.5+.5*sin(length(p.xz)*11.0-uTime*2.2),10.0);
col+=vec3(.20,.08,.34)*rings*cosmic*.14;
}
return col;
}
vec3 shadeCat(Hit h,vec3 p,vec3 ro){
int idx=int(h.obj+.5);
vec3 q=toCatLocal(p,idx);
float m=h.mat;
vec3 albedo,N=normalize(h.n);
float specPower=24.0,specAmount=.12;
if(m<100.5){
float broad=noise3(q*28.0),fine=noise3(q*145.0);
vec3 cream=mix(vec3(.53,.405,.265),vec3(.73,.61,.43),broad);
float front=smoothstep(-.04,.23,q.z);
float chest=(1.0-smoothstep(.20,.37,abs(q.x)))*front*(1.0-smoothstep(1.03,1.27,q.y));
float paws=1.0-smoothstep(.19,.32,q.y);
float muzzle=smoothstep(1.01,1.13,q.y)*(1.0-smoothstep(1.25,1.35,q.y))*smoothstep(.13,.29,q.z);
float white=clamp(max(max(chest,paws),muzzle),0.0,1.0);
albedo=mix(cream,vec3(.88,.845,.745),white);
float forehead=smoothstep(1.43,1.57,q.y)*smoothstep(.05,.25,q.z);
float stripes=pow(.5+.5*sin(q.x*31.0+q.y*5.0+noise3(q*9.0)*3.0),9.0);
albedo*=1.0-.13*stripes*forehead;
if(q.y<.23&&abs(q.x)>.38)albedo*=.9+.1*sin(q.x*29.0+q.z*18.0);
albedo*=.91+.13*fine;
float strand=pow(abs(sin((q.x+q.y*.23)*218.0+noise3(q*11.0)*4.0)),14.0);
albedo+=strand*.025;
vec3 fiber=vec3(sin(q.y*173.0+q.z*41.0),sin(q.x*157.0+q.y*67.0),sin(q.z*163.0+q.x*53.0));
N=normalize(N+fiber*.032);
specPower=18.0;specAmount=.08;
}else if(m<101.5){
albedo=vec3(.77,.79,.70);specPower=110.0;specAmount=1.25;
}else if(m<102.5){
vec2 ip=vec2((abs(q.x)-.165)/.074,(q.y-1.43)/.083);
float r=length(ip),a=atan(ip.y,ip.x);
float fibers=.5+.5*sin(a*34.0+r*11.0);
albedo=mix(vec3(.47,.43,.12),vec3(.15,.31,.20),smoothstep(.15,1.0,r));
albedo*=.72+.42*fibers;
specPower=125.0;specAmount=1.4;
}else if(m<103.5){
albedo=vec3(.006,.009,.007);specPower=160.0;specAmount=1.8;
}else if(m<104.5){
albedo=vec3(.43,.18,.155);specPower=45.0;specAmount=.32;
}else if(m<105.5){
albedo=mix(vec3(.025,.009,.012),vec3(.23,.055,.065),smoothstep(1.13,1.07,q.y));
specAmount=.05;
}else if(m<106.5){
albedo=vec3(.86,.84,.75);specPower=40.0;specAmount=.4;
}else{
albedo=vec3(.49,.25,.22)*(.9+.1*noise3(q*90.0));specAmount=.04;
}
vec3 V=normalize(ro-p);
vec3 L=normalize(vec3(-3.4,4.0,2.6)-p);
vec3 lampPos=moved(vec3(4.05,2.1,-2.75),4.0);
vec3 LL=normalize(lampPos-p);
float wrap=clamp((dot(N,L)+.32)/1.32,0.0,1.0);
float diff=max(dot(N,L),0.0);
float fill=max(dot(N,LL),0.0);
float cosmic=smoothstep(3.2,4.0,uStageF);
vec3 keyColor=mix(vec3(1.12,.94,.77),vec3(.74,.83,1.25),cosmic*.55);
vec3 col=albedo*(vec3(.24,.255,.27)+keyColor*wrap*.94+vec3(.65,.32,.16)*fill*.22);
vec3 H=normalize(L+V);
col+=keyColor*pow(max(dot(N,H),0.0),specPower)*specAmount*(.25+.75*diff);
float rim=pow(1.0-max(dot(N,V),0.0),3.0);
col+=mix(vec3(.18,.20,.17),vec3(.24,.15,.48),cosmic)*rim*(m<100.5?.65:.18);
if((m>101.5&&m<103.5)){
vec2 ip=vec2(abs(q.x)-.165,q.y-1.43);
float catchlight=1.0-smoothstep(.012,.026,length(ip-vec2(-.022,.035)));
col+=catchlight*vec3(1.2);
}
return col;
}
vec3 aces(vec3 x){
return clamp((x*(2.51*x+.03))/(x*(2.43*x+.59)+.14),0.0,1.0);
}
void main(){
float s1=smoothstep(.15,1.0,uStageF);
float s2=smoothstep(1.25,2.0,uStageF);
float s3=smoothstep(2.25,3.0,uStageF);
float s4=smoothstep(3.25,4.0,uStageF);
vec3 target=vec3(0,1.02+uLift*.56,.12);
float yaw=s1*.018*sin(uTime*.32)+s3*.11*sin(uRoomSpin*.21)+s4*.08*sin(uTime*.29);
float dist=5.45+.20*s2+.48*s4;
vec3 ro=target+vec3(sin(yaw)*dist,.46+uLift*.02,cos(yaw)*dist);
ro.y+=s4*.018*sin(uTime*3.1);
vec3 fw=normalize(target-ro);
vec3 rr=normalize(cross(fw,vec3(0,1,0))),uu=cross(rr,fw);
float roll=s2*.035*sin(uTime*1.35)+s3*.075*sin(uTime*.72)+s4*.12*sin(uTime*.53);
vec3 right=rr*cos(roll)+uu*sin(roll),up=uu*cos(roll)-rr*sin(roll);
vec2 uv=(2.0*gl_FragCoord.xy-uRes.xy)/uRes.y;
float fov=radians(41.0+4.0*s4);
vec3 rd=normalize(fw+(right*uv.x+up*uv.y)*tan(fov*.5));
Hit h=traceRoom(ro,rd);
Hit c0=traceCat(ro,rd,0,h.t);
if(c0.mat>0.0&&c0.t<h.t)h=c0;
int count=uStageF>3.45?4:(uStageF>2.45?2:0);
for(int i=1;i<5;i++){
if(i>count)break;
Hit c=traceCat(ro,rd,i,h.t);
if(c.mat>0.0&&c.t<h.t)h=c;
}
vec3 col;
if(h.mat<0.0){
col=vec3(.08,.09,.11);
}else{
vec3 p=ro+rd*h.t;
col=h.mat>99.5?shadeCat(h,p,ro):shadeRoom(h,p,ro);
}
col=aces(col*.92);
col=pow(col,vec3(1.0/2.2));
outColor=vec4(col,1.0);
}`;
const MERGE = `#version 300 es
precision highp float;
out vec4 outColor;
uniform sampler2D uCurr,uPrev;
uniform vec2 uRes;
uniform float uPersist,uSwirl,uStageF;
void main(){
vec2 uv=gl_FragCoord.xy/uRes;
vec2 p=uv-vec2(.5,.52);
p.x*=uRes.x/uRes.y;
float c=cos(uSwirl),s=sin(uSwirl);
p=mat2(c,-s,s,c)*p;
p.x/=uRes.x/uRes.y;
vec2 oldUV=vec2(.5,.52)+p;
vec3 curr=texture(uCurr,uv).rgb;
vec3 prev=texture(uPrev,oldUV).rgb;
float valid=step(0.0,oldUV.x)*step(oldUV.x,1.0)*step(0.0,oldUV.y)*step(oldUV.y,1.0);
outColor=vec4(mix(curr,prev,uPersist*valid),1.0);
}`;
const DISPLAY = `#version 300 es
precision highp float;
out vec4 outColor;
uniform sampler2D uTex;
uniform vec2 uRes;
uniform float uTime,uStageF,uBoost;
float hash(vec2 p){return fract(sin(dot(p,vec3(12.9898,78.233).xy))*43758.5453);}
void main(){
vec2 uv=gl_FragCoord.xy/uRes;
vec2 p=uv-vec2(.5,.52);p.x*=uRes.x/uRes.y;
float r=length(p),a=atan(p.y,p.x);
float energy=smoothstep(2.55,4.0,uStageF);
vec2 dir=p/max(r,.001);dir.x/=uRes.x/uRes.y;
float ca=.00125*energy*(1.0+.08*uBoost)*smoothstep(.03,.6,r);
vec3 col;
col.r=texture(uTex,uv+dir*ca).r;
col.g=texture(uTex,uv).g;
col.b=texture(uTex,uv-dir*ca).b;
vec3 bloom=vec3(0);
for(int i=0;i<8;i++){
float an=6.2831853*float(i)/8.0;
vec2 off=vec2(cos(an),sin(an))*4.0/uRes;
bloom+=max(texture(uTex,uv+off).rgb-vec3(.66),vec3(0));
}
col+=bloom*(.026+.014*energy);
float rays=pow(.5+.5*sin(a*12.0-r*30.0+uTime*2.2),14.0);
rays*=smoothstep(.82,.12,r)*smoothstep(.04,.19,r);
vec3 rayColor=mix(vec3(.10,.65,.85),vec3(.62,.16,.85),.5+.5*sin(a*3.0+uTime*.3));
col+=rayColor*rays*energy*(.075+.005*uBoost);
float halo=exp(-abs(r-.31-.025*sin(uTime))*30.0);
col+=rayColor*halo*energy*.025;
col*=1.0-.23*smoothstep(.42,.94,r);
float grain=hash(gl_FragCoord.xy+floor(uTime*47.0))-.5;
col+=grain*(.010+.004*energy);
outColor=vec4(clamp(col,0.0,1.0),1.0);
}`;
function compile(type,src){
const s=gl.createShader(type);gl.shaderSource(s,src);gl.compileShader(s);
if(!gl.getShaderParameter(s,gl.COMPILE_STATUS))throw new Error(gl.getShaderInfoLog(s));
return s;
}
function program(frag){
const p=gl.createProgram();
gl.attachShader(p,compile(gl.VERTEX_SHADER,VERT));
gl.attachShader(p,compile(gl.FRAGMENT_SHADER,frag));
gl.linkProgram(p);
if(!gl.getProgramParameter(p,gl.LINK_STATUS))throw new Error(gl.getProgramInfoLog(p));
return p;
}
function locations(p,names){
const o={};for(const n of names)o[n]=gl.getUniformLocation(p,n);return o;
}
let sceneP,mergeP,displayP;
try{
sceneP=program(SCENE);mergeP=program(MERGE);displayP=program(DISPLAY);
}catch(err){
console.error(err);
document.getElementById("fallback").style.display="grid";
document.getElementById("fallback").textContent="The living room shader could not start on this GPU.";
return;
}
const SU=locations(sceneP,["uRes","uTime","uAngle","uLift","uSpeed","uStageF","uRoomSpin","uBoost"]);
const MU=locations(mergeP,["uCurr","uPrev","uRes","uPersist","uSwirl","uStageF"]);
const DU=locations(displayP,["uTex","uRes","uTime","uStageF","uBoost"]);
gl.bindVertexArray(gl.createVertexArray());
gl.disable(gl.DEPTH_TEST);gl.disable(gl.BLEND);
let sceneTarget,history=[],readIndex=0;
function makeTarget(w,h){
const tex=gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D,tex);
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE);
gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,w,h,0,gl.RGBA,gl.UNSIGNED_BYTE,null);
const fbo=gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER,fbo);
gl.framebufferTexture2D(gl.FRAMEBUFFER,gl.COLOR_ATTACHMENT0,gl.TEXTURE_2D,tex,0);
gl.clearColor(0,0,0,1);gl.clear(gl.COLOR_BUFFER_BIT);
return {tex,fbo};
}
function destroyTarget(t){
if(!t)return;gl.deleteTexture(t.tex);gl.deleteFramebuffer(t.fbo);
}
function resize(){
const dpr=Math.min(window.devicePixelRatio||1,1.35);
let w=Math.max(2,innerWidth*dpr),h=Math.max(2,innerHeight*dpr);
const scale=Math.min(1,Math.sqrt(1000000/(w*h)));
w=Math.max(2,Math.floor(w*scale));h=Math.max(2,Math.floor(h*scale));
if(canvas.width===w&&canvas.height===h&&sceneTarget)return;
canvas.width=w;canvas.height=h;
destroyTarget(sceneTarget);history.forEach(destroyTarget);
sceneTarget=makeTarget(w,h);history=[makeTarget(w,h),makeTarget(w,h)];readIndex=0;
}
addEventListener("resize",resize,{passive:true});
resize();
const muteBtn=document.getElementById("mute");
const caption=document.getElementById("caption");
const kicker=document.getElementById("kicker");
const label=document.getElementById("label");
const sub=document.getElementById("sub");
const hintMain=document.getElementById("hintMain");
const hintSub=document.getElementById("hintSub");
let active=false,stage=0,stageF=0,overdrive=0;
let speed=0,angle=-.10,lift=0,roomSpin=0,voiceKick=0;
let muted=false,last=performance.now(),elapsed=0,uiClock=0;
const copy=[
["00 / DOMESTIC STILLNESS","A very normal cat.","Please do not make this weird."],
["01 / OIIA","Oiia.","The floor has stopped being necessary."],
["02 / GRAVITY LEFT","Gravity has left.","The furniture is negotiating."],
["03 / THE CHORUS","The chorus arrives.","Two smaller mistakes join the orbit."],
["04 / OIIA SINGULARITY","Oiia singularity.","The living room is now a solar system."]
];
function updateCaption(){
const c=copy[stage];
kicker.textContent=c[0];label.textContent=c[1];sub.textContent=c[2];
if(stage===4&&overdrive>0){
kicker.textContent="04 / ENCORE "+(overdrive+1);
sub.textContent="It was already a bad idea. Now it is louder.";
}
caption.classList.remove("pop");void caption.offsetWidth;caption.classList.add("pop");
hintMain.textContent=stage===0?"CLICK THE CAT":stage<4?"CLICK AGAIN · MAKE IT WORSE":"CLICK FOR AN ENCORE";
hintSub.textContent=stage===0?"M TO MUTE":"M MUTE · R RESET";
}
let audio=null;
function ensureAudio(){
if(audio){
if(audio.ctx.state==="suspended")audio.ctx.resume();
return;
}
const AC=window.AudioContext||window.webkitAudioContext;
if(!AC)return;
const ctx=new AC();
const master=ctx.createGain();master.gain.value=0;
const comp=ctx.createDynamicsCompressor();
comp.threshold.value=-20;comp.knee.value=16;comp.ratio.value=5;comp.attack.value=.006;comp.release.value=.16;
comp.connect(master);master.connect(ctx.destination);
const voice=ctx.createGain();voice.gain.value=0;
voice.connect(comp);
const delay=ctx.createDelay(.3),feedback=ctx.createGain(),wet=ctx.createGain();
delay.delayTime.value=.083;feedback.gain.value=.17;wet.gain.value=.17;
voice.connect(delay);delay.connect(feedback);feedback.connect(delay);delay.connect(wet);wet.connect(comp);
const real=new Float32Array(32),imag=new Float32Array(32);
for(let i=1;i<32;i++)imag[i]=(1/i)*(i%2?1:.82);
const wave=ctx.createPeriodicWave(real,imag,{disableNormalization:false});
const osc=ctx.createOscillator(),osc2=ctx.createOscillator();
osc.setPeriodicWave(wave);osc2.setPeriodicWave(wave);
const src=ctx.createGain(),src2=ctx.createGain();
src.gain.value=.64;src2.gain.value=0;
osc.connect(src);osc2.connect(src2);
const filters=[],formantGains=[];
[1.15,.72,.40,.19].forEach((g,i)=>{
const f=ctx.createBiquadFilter(),fg=ctx.createGain();
f.type="bandpass";f.Q.value=[4.5,7,9,11][i];fg.gain.value=g;
src.connect(f);src2.connect(f);f.connect(fg);fg.connect(voice);
filters.push(f);formantGains.push(fg);
});
const chest=ctx.createBiquadFilter(),chestGain=ctx.createGain();
chest.type="lowpass";chest.frequency.value=420;chestGain.gain.value=.055;
src.connect(chest);chest.connect(chestGain);chestGain.connect(voice);
const noiseBuffer=ctx.createBuffer(1,ctx.sampleRate*2,ctx.sampleRate);
const data=noiseBuffer.getChannelData(0);
let brown=0;
for(let i=0;i<data.length;i++){
brown=(brown+(Math.random()*2-1)*.16)*.985;
data[i]=brown;
}
const noise=ctx.createBufferSource();noise.buffer=noiseBuffer;noise.loop=true;
const whooshFilter=ctx.createBiquadFilter(),whoosh=ctx.createGain();
whooshFilter.type="bandpass";whooshFilter.Q.value=.8;whoosh.gain.value=0;
noise.connect(whooshFilter);whooshFilter.connect(whoosh);whoosh.connect(comp);
const drone=ctx.createOscillator(),droneGain=ctx.createGain();
drone.type="sine";drone.frequency.value=54;droneGain.gain.value=0;
drone.connect(droneGain);droneGain.connect(comp);
osc.start();osc2.start();noise.start();drone.start();
audio={ctx,master,voice,osc,osc2,src2,filters,noise,whooshFilter,whoosh,drone,droneGain};
applyMute();
}
function applyMute(){
muteBtn.textContent=muted?"sound / muted":audio?"sound / on":"sound / on click";
muteBtn.setAttribute("aria-pressed",String(muted));
if(audio)audio.master.gain.setTargetAtTime(muted?0:.72,audio.ctx.currentTime,.035);
}
function toggleMute(){muted=!muted;applyMute();}
muteBtn.addEventListener("click",e=>{e.stopPropagation();toggleMute();});
const O=[460,850,2450,3300],I=[285,2250,2950,3500],I2=[330,2050,2800,3400],A=[790,1240,2550,3300];
const clamp01=x=>Math.max(0,Math.min(1,x));
const smooth=(a,b,x)=>{x=clamp01((x-a)/(b-a));return x*x*(3-2*x);};
const mix=(a,b,t)=>a+(b-a)*t;
function vowel(ph){
let x,y,t;
if(ph<.18){x=O;y=I;t=smooth(.07,.18,ph);}
else if(ph<.42){x=y=I;t=0;}
else if(ph<.52){x=I;y=I2;t=smooth(.42,.50,ph);}
else if(ph<.66){x=y=I2;t=0;}
else if(ph<.79){x=I2;y=A;t=smooth(.66,.79,ph);}
else if(ph<.94){x=y=A;t=0;}
else{x=A;y=O;t=smooth(.94,1,ph);}
return x.map((v,i)=>mix(v,y[i],t));
}
function updateAudio(){
if(!audio)return;
const a=audio,t=a.ctx.currentTime;
const ph=((angle/(Math.PI*2))%1+1)%1;
const f=vowel(ph);
for(let i=0;i<4;i++)a.filters[i].frequency.setTargetAtTime(f[i],t,.018);
const syll=(ph*4)%1;
let artic=.28+.72*Math.pow(Math.max(0,Math.sin(Math.PI*syll)),.30);
artic=mix(artic,.60+.40*artic,smooth(18,55,speed));
const f0=Math.min(285,108+speed*1.95+stageF*5+15*Math.sin(ph*Math.PI*2));
a.osc.frequency.setTargetAtTime(f0,t,.025);
a.osc2.frequency.setTargetAtTime(f0*1.012+7,t,.03);
a.src2.gain.setTargetAtTime(smooth(2.35,3,stageF)*.20,t,.08);
const level=active?(.042+Math.min(.20,speed*.0031))*artic+voiceKick*.055:0;
a.voice.gain.setTargetAtTime(level,t,.022);
a.whoosh.gain.setTargetAtTime(active?.002+speed*.00038:0,t,.08);
a.whooshFilter.frequency.setTargetAtTime(180+speed*29,t,.05);
a.droneGain.gain.setTargetAtTime(smooth(3.25,4,stageF)*.035,t,.15);
}
function activate(){
ensureAudio();
if(!active){active=true;stage=1;speed=2.2;}
else if(stage<4)stage++;
else overdrive=Math.min(8,overdrive+1);
voiceKick=1;updateCaption();
}
function reset(){
active=false;stage=0;stageF=0;overdrive=0;speed=0;angle=-.10;lift=0;roomSpin=0;voiceKick=0;
updateCaption();
}
canvas.addEventListener("pointerdown",e=>{
const x=e.clientX/innerWidth,y=e.clientY/innerHeight;
if(!active&&(Math.abs(x-.5)>.23||y<.10||y>.94)){
hintMain.textContent="NO, THE CAT";return;
}
activate();
const p=document.createElement("div");p.className="ping";p.style.left=e.clientX+"px";p.style.top=e.clientY+"px";
document.body.appendChild(p);setTimeout(()=>p.remove(),600);
});
canvas.addEventListener("keydown",e=>{
if(e.key==="Enter"||e.key===" "){e.preventDefault();activate();}
});
addEventListener("keydown",e=>{
if(e.key.toLowerCase()==="m")toggleMute();
if(e.key.toLowerCase()==="r")reset();
});
updateCaption();
function bindTex(unit,tex){
gl.activeTexture(gl.TEXTURE0+unit);gl.bindTexture(gl.TEXTURE_2D,tex);
}
function frame(now){
const dt=Math.min(.04,Math.max(.001,(now-last)/1000));last=now;elapsed+=dt;
if(active){
const targets=[0,23,35,49,64];
const target=targets[stage]+overdrive*3.2;
speed+=(target-speed)*(1-Math.exp(-dt*(stage===1?.72:1.55)));
angle=(angle+speed*dt)%(Math.PI*2);
const lifts=[0,.54,1.02,1.43,1.62];
lift+=(lifts[stage]-lift)*(1-Math.exp(-dt*1.65));
roomSpin=(roomSpin+dt*speed*(.002+.012*smooth(1.8,4,stageF)))%(Math.PI*2);
stageF+=(stage-stageF)*(1-Math.exp(-dt*1.85));
}else{
stageF+=(0-stageF)*(1-Math.exp(-dt*3));
}
voiceKick*=Math.exp(-dt*5.5);
updateAudio();
const w=canvas.width,h=canvas.height;
gl.viewport(0,0,w,h);
gl.bindFramebuffer(gl.FRAMEBUFFER,sceneTarget.fbo);
gl.useProgram(sceneP);
gl.uniform2f(SU.uRes,w,h);
gl.uniform1f(SU.uTime,elapsed);
gl.uniform1f(SU.uAngle,angle);
gl.uniform1f(SU.uLift,lift);
gl.uniform1f(SU.uSpeed,speed);
gl.uniform1f(SU.uStageF,stageF);
gl.uniform1f(SU.uRoomSpin,roomSpin);
gl.uniform1f(SU.uBoost,overdrive);
gl.drawArrays(gl.TRIANGLES,0,3);
const writeIndex=1-readIndex;
const persist=active?Math.min(.74,.59*smooth(8,24,speed)+.15*smooth(25,65,speed)):0;
gl.bindFramebuffer(gl.FRAMEBUFFER,history[writeIndex].fbo);
gl.useProgram(mergeP);
bindTex(0,sceneTarget.tex);bindTex(1,history[readIndex].tex);
gl.uniform1i(MU.uCurr,0);gl.uniform1i(MU.uPrev,1);
gl.uniform2f(MU.uRes,w,h);
gl.uniform1f(MU.uPersist,persist);
gl.uniform1f(MU.uSwirl,active?Math.sin(elapsed*.7)*.0012*smooth(2.2,4,stageF):0);
gl.uniform1f(MU.uStageF,stageF);
gl.drawArrays(gl.TRIANGLES,0,3);
gl.bindFramebuffer(gl.FRAMEBUFFER,null);
gl.useProgram(displayP);
bindTex(0,history[writeIndex].tex);
gl.uniform1i(DU.uTex,0);
gl.uniform2f(DU.uRes,w,h);
gl.uniform1f(DU.uTime,elapsed);
gl.uniform1f(DU.uStageF,stageF);
gl.uniform1f(DU.uBoost,overdrive);
gl.drawArrays(gl.TRIANGLES,0,3);
readIndex=writeIndex;
uiClock+=dt;
if(uiClock>.15){
uiClock=0;
if(active&&!muted){
const rpm=Math.round(speed*60/(Math.PI*2));
muteBtn.textContent="sound / "+rpm+" rpm";
}else if(!muted)applyMute();
}
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
})();
</script>
</body>
</html>
/o/ → /i/ → /i/ → /a/ vowel shapes, syllable amplitude articulation, a little chest resonance, breath noise, compression, and short feedback-delay room ambience. Its vowel phase is derived directly from accumulated spin angle—one “oiia” circuit per revolution—while oscillator pitch follows angular velocity, so rate, articulation, pitch, blur, and whoosh cannot drift apart.