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">
<title>oiia cat — click to spin</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
html,body{height:100%;background:#070607;color:#fff;font-family:Verdana,system-ui,sans-serif;overflow:hidden}
body{display:flex;align-items:center;justify-content:center;background:radial-gradient(120% 100% at 50% 0%,#1a1518 0%,#070607 60%)}
#frame{width:min(96vw,920px);user-select:none}
#topbar{display:flex;justify-content:space-between;align-items:center;padding:10px 4px;font-size:12px;letter-spacing:.14em}
#stageName{color:#ffdf9e;text-transform:uppercase}
#stageName b{color:#fff}
#controls{display:flex;gap:8px;align-items:center}
button{cursor:pointer;border:1px solid #ffffff33;background:#ffffff14;color:#fff;border-radius:99px;padding:6px 12px;font-size:12px;letter-spacing:.08em}
button:hover{background:#ffffff2c}
#stage{position:relative;width:100%;aspect-ratio:16/10;border-radius:18px;overflow:hidden;background:#111;box-shadow:0 30px 100px #000,0 0 0 1px #ffffff18;cursor:default}
#roomInner{position:absolute;inset:-6%;transform-origin:50% 62%;will-change:transform,filter}
/* ROOM */
.wall{position:absolute;left:0;right:0;top:0;height:68%;background:
linear-gradient(180deg,#00000055 0%,transparent 18%),
radial-gradient(60% 90% at 22% 20%,#fff6dfcc 0%,#fff6df22 28%,transparent 60%),
linear-gradient(180deg,#cbb99e 0%,#b8a586 55%,#9c8a6f 68%,#7a6a55 100%)}
.wall::after{content:"";position:absolute;inset:0;opacity:.35;background:repeating-linear-gradient(0deg,transparent 0 46px,#00000018 46px 48px),repeating-linear-gradient(90deg,transparent 0 86px,#00000010 86px 88px)}
.baseboard{position:absolute;left:0;right:0;top:calc(68% - 14px);height:14px;background:linear-gradient(#efe6d3,#b9a88d);box-shadow:0 2px 6px #0008}
.floor{position:absolute;left:-10%;right:-10%;top:68%;bottom:0;background:
linear-gradient(180deg,#3a2c20 0%,#5a4630 12%,#7a5f42 35%,#8d7050 100%);transform:perspective(600px) rotateX(18deg);transform-origin:top center}
.floor::before{content:"";position:absolute;inset:0;background:repeating-linear-gradient(90deg,transparent 0 78px,#00000055 78px 81px),repeating-linear-gradient(0deg,#ffffff10 0 2px,transparent 2px 26px)}
.floor::after{content:"";position:absolute;inset:0;background:radial-gradient(55% 70% at 50% 18%,#ffedbbaa 0%,transparent 60%)}
.window{position:absolute;left:6%;top:9%;width:22%;height:44%;background:linear-gradient(#dff1ff,#a9cbe8);border:10px solid #4a3a2a;border-radius:6px;box-shadow:0 0 60px #fff8dcaa,inset 0 0 30px #ffffffaa}
.window::before{content:"";position:absolute;inset:0;background:linear-gradient(90deg,transparent 46%,#4a3a2a 46% 54%,transparent 54%),linear-gradient(0deg,transparent 48%,#4a3a2a 48% 52%,transparent 52%)}
.window::after{content:"";position:absolute;left:10%;top:8%;width:34%;height:30%;background:linear-gradient(#ffffffee,#ffffff00);border-radius:40px;transform:rotate(-18deg)}
.shaft{position:absolute;left:12%;top:18%;width:46%;height:70%;background:linear-gradient(105deg,#fff3c488 0%,#fff3c422 55%,transparent 75%);clip-path:polygon(10% 0,42% 0,100% 100%,20% 100%);mix-blend-mode:screen;pointer-events:none}
.sofa{position:absolute;right:5%;top:42%;width:34%;height:28%;transition:transform .3s}
.sofa .back{position:absolute;left:0;right:0;top:0;height:55%;background:linear-gradient(#7a4a3a,#4e2e24);border-radius:18px 18px 6px 6px;box-shadow:inset 0 4px 8px #ffffff33}
.sofa .seat{position:absolute;left:2%;right:2%;bottom:8%;height:48%;background:linear-gradient(#9a6350,#6b4235);border-radius:10px;box-shadow:0 10px 20px #000a}
.sofa .armL,.sofa .armR{position:absolute;top:18%;width:12%;height:74%;background:linear-gradient(#8a5646,#5a352b);border-radius:12px}
.sofa .armL{left:-2%}.sofa .armR{right:-2%}
.lamp{position:absolute;right:42%;top:18%;width:8%;height:52%}
.lamp .pole{position:absolute;left:48%;top:18%;bottom:0;width:6px;background:#2b2118}
.lamp .shade{position:absolute;top:0;left:0;right:0;height:26%;background:linear-gradient(#ffdf9e,#c99a4a);clip-path:polygon(20% 0,80% 0,100% 100%,0 100%);box-shadow:0 0 50px 18px #ffbe5a66}
.shelf{position:absolute;left:34%;top:14%;width:26%;height:8%;background:#4a3525;box-shadow:0 6px 12px #000a}
.shelf::before{content:"";position:absolute;left:6%;right:6%;top:-68%;height:68%;background:linear-gradient(90deg,#7a5a3a 0 12%,#5a7a8a 12% 24%,#a05a5a 24% 38%,#5a8a5a 38% 55%,#8a7a4a 55% 72%,#6a5a8a 72% 100%);box-shadow:0 -2px 0 #0006}
.rug{position:absolute;left:50%;top:78%;width:52%;height:22%;transform:translateX(-50%);background:radial-gradient(ellipse at center,#a33c3c 0 28%,#d9c9a8 28% 34%,#7a2e2e 34% 62%,#3a1e1e 62% 72%,transparent 72%);border-radius:50%;box-shadow:0 10px 30px #0009}
.plant{position:absolute;left:4%;top:48%;width:10%;height:22%;background:radial-gradient(circle at 50% 90%,#3a5a2a 0 18%,transparent 19%),radial-gradient(ellipse at 50% 40%,#4a7a35 0 60%,transparent 61%)}
/* CAT */
#catZone{position:absolute;left:50%;top:54%;width:300px;height:340px;transform:translateX(-50%);cursor:pointer;z-index:5}
#catShadow{position:absolute;left:50%;bottom:6px;width:190px;height:34px;transform:translateX(-50%);background:radial-gradient(ellipse,#000c 0%,transparent 70%);filter:blur(2px);z-index:1}
#lev{position:absolute;inset:0;will-change:transform}
#catSpin{position:absolute;left:50%;bottom:30px;width:230px;height:290px;transform:translateX(-50%);transform-origin:50% 80%;will-change:transform,filter}
.ghost{position:absolute;left:50%;bottom:30px;width:230px;height:290px;transform:translateX(-50%);opacity:0;pointer-events:none;filter:blur(6px) saturate(1.4)}
#catSpin svg,.ghost svg{width:100%;height:100%;display:block;overflow:visible}
.shade{position:absolute;inset:0;pointer-events:none;border-radius:50%;mix-blend-mode:overlay;opacity:0}
#halo{position:absolute;left:50%;bottom:40px;width:260px;height:260px;transform:translate(-50%,20%);background:radial-gradient(circle,#ffedbbaa 0%,transparent 65%);opacity:0;pointer-events:none}
#spinText{position:absolute;left:50%;top:8%;transform:translateX(-50%);font-weight:900;font-size:clamp(18px,4vw,44px);letter-spacing:.1em;color:#fff;text-shadow:0 0 18px #ff9a00,0 2px 0 #000;opacity:0;white-space:nowrap}
#bigOiia{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%) scale(.8);font-weight:900;font-size:120px;letter-spacing:-.05em;color:transparent;-webkit-text-stroke:3px #ffffffaa;opacity:0;pointer-events:none}
.mini{position:absolute;width:64px;height:80px;opacity:0;pointer-events:none;z-index:6}
.dust{position:absolute;width:5px;height:5px;background:#fff8;border-radius:50%;animation:float 7s linear infinite}
@keyframes float{0%{transform:translateY(0);opacity:0}15%{opacity:.8}100%{transform:translateY(-180px) translateX(30px);opacity:0}}
#vignette{position:absolute;inset:0;pointer-events:none;background:radial-gradient(120% 100% at 50% 45%,transparent 55%,#000a 100%);z-index:20}
#grain{position:absolute;inset:0;opacity:.12;pointer-events:none;z-index:21;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence baseFrequency='0.9'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)' opacity='0.6'/%3E%3C/svg%3E")}
#hint{position:absolute;left:50%;bottom:12px;transform:translateX(-50%);font-size:13px;letter-spacing:.12em;background:#000a;padding:8px 16px;border-radius:99px;border:1px solid #ffffff22;z-index:30;white-space:nowrap}
#hint span{color:#ffdf9e}
body.s1 #hint,body.s2 #hint,body.s3 #hint,body.s4 #hint{animation:hintPulse .5s infinite alternate}
@keyframes hintPulse{to{transform:translateX(-50%) scale(1.06)}}
/* stage looks */
body.s1 #roomInner{animation:sway 2.2s ease-in-out infinite}
body.s2 #roomInner{animation:shake .35s linear infinite}
body.s3 #roomInner{animation:shake .18s linear infinite}
body.s4 #roomInner{animation:shake .1s linear infinite}
@keyframes sway{0%,100%{transform:rotate(-1deg) scale(1.03)}50%{transform:rotate(1deg) scale(1.05)}}
@keyframes shake{0%{transform:translate(0,0) rotate(-1.2deg) scale(1.08)}25%{transform:translate(6px,-5px) rotate(1deg) scale(1.1)}50%{transform:translate(-6px,4px) rotate(-.6deg) scale(1.09)}75%{transform:translate(4px,5px) rotate(.8deg) scale(1.11)}100%{transform:translate(0,0) rotate(-1.2deg) scale(1.08)}}
#caption{padding:10px 4px 0;font-size:13px;color:#ffffffaa;letter-spacing:.04em;line-height:1.5}
#caption b{color:#fff}
</style>
</head>
<body class="s0">
<div id="frame">
<div id="topbar">
<div id="stageName">STAGE <b id="stNum">0 / IDLE</b> — <span id="stDesc">a cat. doing nothing.</span></div>
<div id="controls"><button id="muteBtn">🔇 MUTED — CLICK CAT</button><button id="resetBtn">reset</button></div>
</div>
<div id="stage">
<div id="roomInner">
<div class="wall"></div><div class="baseboard"></div><div class="floor"></div>
<div class="window"></div><div class="shaft"></div>
<div class="shelf"></div><div class="plant"></div>
<div class="lamp" id="lamp"><div class="shade"></div><div class="pole"></div></div>
<div class="sofa" id="sofa"><div class="back"></div><div class="armL"></div><div class="armR"></div><div class="seat"></div></div>
<div class="rug"></div>
<div id="halo"></div>
<div id="spinText">oiia oiia oiia ooooiai</div>
<div id="bigOiia">OIIA</div>
<div id="catZone">
<div id="catShadow"></div>
<div id="lev">
<div class="ghost" id="g1"></div>
<div class="ghost" id="g2"></div>
<div id="catSpin">
<svg viewBox="0 0 230 290" id="catSvg" aria-label="cream cat staring at camera">
<defs>
<radialGradient id="fur" cx="45%" cy="35%" r="75%"><stop offset="0%" stop-color="#fff8e8"/><stop offset="45%" stop-color="#f2e4c8"/><stop offset="100%" stop-color="#c9b18d"/></radialGradient>
<radialGradient id="whiteFur" cx="50%" cy="30%" r="80%"><stop offset="0%" stop-color="#ffffff"/><stop offset="100%" stop-color="#e8dcc5"/></radialGradient>
<filter id="soft"><feGaussianBlur stdDeviation="0.4"/></filter>
</defs>
<!-- TAIL -->
<g id="tail"><ellipse cx="52" cy="250" rx="34" ry="18" fill="#e9dcc0" stroke="#b89f78" stroke-width="2"/><ellipse cx="52" cy="250" rx="18" ry="9" fill="#fffaf0"/></g>
<!-- BODY sitting square -->
<g id="catFront">
<ellipse cx="115" cy="210" rx="72" ry="68" fill="url(#fur)" stroke="#a68e68" stroke-width="2"/>
<ellipse cx="115" cy="225" rx="42" ry="52" fill="url(#whiteFur)"/>
<ellipse cx="88" cy="268" rx="20" ry="16" fill="#f6ecd6" stroke="#a68e68" stroke-width="2"/>
<ellipse cx="142" cy="268" rx="20" ry="16" fill="#f6ecd6" stroke="#a68e68" stroke-width="2"/>
<path d="M88 258 l-4 12 M142 258 l4 12" stroke="#8a755a" stroke-width="2"/>
<!-- HEAD -->
<ellipse cx="115" cy="115" rx="68" ry="62" fill="url(#fur)" stroke="#a68e68" stroke-width="2"/>
<polygon points="58,78 48,28 92,52" fill="#e9dcc0" stroke="#a68e68" stroke-width="2"/>
<polygon points="172,78 182,28 138,52" fill="#e9dcc0" stroke="#a68e68" stroke-width="2"/>
<polygon points="62,68 56,38 84,54" fill="#f5a8b0"/>
<polygon points="168,68 174,38 146,54" fill="#f5a8b0"/>
<!-- stripes -->
<path d="M95 58 q4 12 0 20 M115 55 q0 14 0 22 M135 58 q-4 12 0 20" stroke="#c9ad82" stroke-width="4" stroke-linecap="round" fill="none" opacity=".7"/>
<!-- EYES WIDE staring -->
<g id="eyes">
<ellipse cx="86" cy="118" rx="22" ry="24" fill="#fff" stroke="#5a4a35" stroke-width="2"/>
<ellipse cx="144" cy="118" rx="22" ry="24" fill="#fff" stroke="#5a4a35" stroke-width="2"/>
<ellipse cx="86" cy="120" rx="13" ry="15" fill="#6aa84f"/>
<ellipse cx="144" cy="120" rx="13" ry="15" fill="#6aa84f"/>
<ellipse cx="86" cy="120" rx="7" ry="11" fill="#0a0a0a"/>
<ellipse cx="144" cy="120" rx="7" ry="11" fill="#0a0a0a"/>
<circle cx="83" cy="114" r="3.5" fill="#fff"/><circle cx="141" cy="114" r="3.5" fill="#fff"/>
</g>
<ellipse cx="115" cy="152" rx="10" ry="7" fill="#e88a96" stroke="#8a4a55" stroke-width="1.5"/>
<path d="M115 159 q0 8 -10 10 M115 159 q0 8 10 10" stroke="#5a4a35" stroke-width="2" fill="none"/>
<g stroke="#fff" stroke-width="1.6" opacity=".9"><path d="M40 145 L12 138 M42 155 L14 158 M190 145 L218 138 M188 155 L216 158"/></g>
<!-- fur tufts -->
<path d="M60 200 l-8 10 10 -2 -6 12 12 -4 M170 200 l8 10 -10 -2 6 12 -12 -4" stroke="#fffaf0" stroke-width="3" fill="none" opacity=".9"/>
</g>
<g id="catBack" style="display:none">
<ellipse cx="115" cy="200" rx="74" ry="72" fill="#e3d2b2" stroke="#a68e68" stroke-width="2"/>
<ellipse cx="115" cy="115" rx="66" ry="60" fill="#e3d2b2" stroke="#a68e68" stroke-width="2"/>
<polygon points="58,78 48,28 92,52" fill="#d9c5a0" stroke="#a68e68" stroke-width="2"/>
<polygon points="172,78 182,28 138,52" fill="#d9c5a0" stroke="#a68e68" stroke-width="2"/>
<path d="M80 90 q35 30 70 0 M75 150 q40 35 80 0 M78 210 q37 30 74 0" stroke="#c2a87f" stroke-width="6" fill="none" opacity=".6" stroke-linecap="round"/>
</g>
<!-- speed streaks -->
<g id="streaks" style="display:none" opacity=".55"><rect x="55" y="40" width="12" height="220" rx="6" fill="#fff"/><rect x="85" y="40" width="8" height="220" rx="4" fill="#fff"/><rect x="135" y="40" width="8" height="220" rx="4" fill="#fff"/><rect x="160" y="40" width="12" height="220" rx="6" fill="#fff"/></g>
</svg>
<div class="shade" id="cylShade"></div>
</div>
</div>
</div>
<div id="orbit"></div>
</div>
<div id="vignette"></div><div id="grain"></div>
<div id="hint">👆 <span>click the cat</span> — it only gets worse</div>
</div>
<div id="caption"><b>oiia cat.</b> starts as a photo. ends as a weather event. click 4 times. sound on after first click. <span id="lyric">oiia…</span></div>
</div>
<script>
(function(){
const body=document.body, catZone=document.getElementById('catZone'),
lev=document.getElementById('lev'), spinEl=document.getElementById('catSpin'),
g1=document.getElementById('g1'), g2=document.getElementById('g2'),
shadow=document.getElementById('catShadow'), halo=document.getElementById('halo'),
spinText=document.getElementById('spinText'), bigOiia=document.getElementById('bigOiia'),
front=document.getElementById('catFront'), back=document.getElementById('catBack'),
streaks=document.getElementById('streaks'), cylShade=document.getElementById('cylShade'),
lyric=document.getElementById('lyric'), stNum=document.getElementById('stNum'),
stDesc=document.getElementById('stDesc'), hint=document.getElementById('hint'),
muteBtn=document.getElementById('muteBtn'), resetBtn=document.getElementById('resetBtn'),
sofa=document.getElementById('sofa'), lamp=document.getElementById('lamp'),
orbit=document.getElementById('orbit'), stageEl=document.getElementById('stage');
const svgHTML=document.getElementById('catSvg').outerHTML;
g1.innerHTML=svgHTML; g2.innerHTML=svgHTML;
// orbiting minis for stage 3/4
let minis=[];
for(let i=0;i<6;i++){let d=document.createElement('div');d.className='mini';d.innerHTML=svgHTML;orbit.appendChild(d);minis.push(d);}
// dust
for(let i=0;i<14;i++){let s=document.createElement('div');s.className='dust';s.style.left=(5+Math.random()*90)+'%';s.style.top=(40+Math.random()*55)+'%';s.style.animationDelay=(Math.random()*7)+'s';s.style.animationDuration=(5+Math.random()*6)+'s';stageEl.appendChild(s);}
const STAGES=[
{n:'0 / IDLE',d:'a cat. doing nothing.',speed:0,lev:0},
{n:'1 / LIFTOFF',d:'it leaves the floor. oiia begins.',speed:9,lev:70},
{n:'2 / OVERDRIVE',d:'blur + ghosts. furniture nervous.',speed:22,lev:125},
{n:'3 / ORBITAL',d:'face unreadable. room joins the spin.',speed:44,lev:175},
{n:'4 / ASCENSION',d:'too fast too loud. send to a friend.',speed:76,lev:210}
];
let stage=0, angle=0, speed=0, levY=0, t=0, last=performance.now();
let muted=false, audioOn=false;
// ---- AUDIO: formant "oiia" locked to spin phase ----
let AC=null, master, voiceGain, osc, sub, f1,f2,f3, shaper, delaySend;
function initAudio(){
if(AC) return;
AC=new (window.AudioContext||window.webkitAudioContext)();
master=AC.createGain(); master.gain.value=0.9; master.connect(AC.destination);
voiceGain=AC.createGain(); voiceGain.gain.value=0.0;
shaper=AC.createWaveShaper();
let curve=new Float32Array(256); for(let i=0;i<256;i++){let x=i/128-1;curve[i]=Math.tanh(2.2*x);}
shaper.curve=curve;
voiceGain.connect(shaper); shaper.connect(master);
// echo for space at high stages
let dly=AC.createDelay(0.5); dly.delayTime.value=0.19;
let fb=AC.createGain(); fb.gain.value=0.35;
dly.connect(fb); fb.connect(dly); dly.connect(master);
delaySend=AC.createGain(); delaySend.gain.value=0.25; shaper.connect(delaySend); delaySend.connect(dly);
osc=AC.createOscillator(); osc.type='sawtooth'; osc.frequency.value=150;
sub=AC.createOscillator(); sub.type='square'; sub.frequency.value=75;
let subG=AC.createGain(); subG.gain.value=0.25; sub.connect(subG); subG.connect(voiceGain);
// breath
let nb=AC.createBuffer(1,AC.sampleRate*1,AC.sampleRate); let ch=nb.getChannelData(0);
for(let i=0;i<ch.length;i++) ch[i]=Math.random()*2-1;
let noise=AC.createBufferSource(); noise.buffer=nb; noise.loop=true;
let ng=AC.createGain(); ng.gain.value=0.06; noise.connect(ng); ng.connect(voiceGain); noise.start();
// 3 parallel formants fed by buzz
function bp(q){let b=AC.createBiquadFilter();b.type='bandpass';b.Q.value=q;return b;}
f1=bp(9);f2=bp(11);f3=bp(12);
let g1f=AC.createGain();g1f.gain.value=1.0; let g2f=AC.createGain();g2f.gain.value=0.6; let g3f=AC.createGain();g3f.gain.value=0.35;
osc.connect(f1);osc.connect(f2);osc.connect(f3);
f1.connect(g1f);g1f.connect(voiceGain); f2.connect(g2f);g2f.connect(voiceGain); f3.connect(g3f);g3f.connect(voiceGain);
osc.connect(voiceGain); // buzz through
let lp=AC.createBiquadFilter();lp.type='lowpass';lp.frequency.value=3200;
// keep simple: osc direct already; start
osc.start(); sub.start();
if(AC.state==='suspended') AC.resume();
}
function lerp(a,b,k){return a+(b-a)*k;}
// vowel formants: o,i,a
const V={o:[480,950,2900],i:[340,2300,3050],a:[800,1250,2600]};
function vowelAt(ph){ // ph 0..1 = one oiia per revolution
let F;
if(ph<0.22){let k=ph/0.22;F=[lerp(V.o[0],V.i[0],k),lerp(V.o[1],V.i[1],k),lerp(V.o[2],V.i[2],k)];}
else if(ph<0.55){F=V.i;}
else if(ph<0.8){let k=(ph-0.55)/0.25;F=[lerp(V.i[0],V.a[0],k),lerp(V.i[1],V.a[1],k),lerp(V.i[2],V.a[2],k)];}
else{let k=(ph-0.8)/0.2;F=[lerp(V.a[0],V.o[0],k),lerp(V.a[1],V.o[1],k),lerp(V.a[2],V.o[2],k)];}
return F;
}
function setStage(s){
stage=s; body.className='s'+s;
stNum.textContent=STAGES[s].n; stDesc.textContent=STAGES[s].d;
hint.innerHTML = s===0 ? '👆 <span>click the cat</span> — it only gets worse'
: s<4 ? '👆 <span>click again</span> — stage '+(s+1)+' is worse' : '👆 <span>click</span> to calm it down (maybe)';
if(s===0){muted=false;}
updateMuteBtn();
}
function updateMuteBtn(){
muteBtn.textContent = !audioOn ? '🔇 MUTED — CLICK CAT' : (muted?'🔇 MUTED':'🔊 OIIA: ON');
}
muteBtn.onclick=(e)=>{e.stopPropagation(); if(!audioOn) return; muted=!muted; if(master) master.gain.value=muted?0:0.9; updateMuteBtn();};
resetBtn.onclick=(e)=>{e.stopPropagation(); setStage(0);};
catZone.addEventListener('click',()=>{
initAudio(); audioOn=true; muted=false; if(master) master.gain.value=0.9;
setStage(stage>=4?0:stage+1);
if(AC&&AC.state==='suspended') AC.resume();
updateMuteBtn();
});
const words=['oiia','oiia','oiiaiooooiai','OIIA','oiiiaaa','oi-oi-oi'];
function frame(now){
let dt=Math.min(0.05,(now-last)/1000); last=now; t+=dt;
let tgt=STAGES[stage].speed, tgtLev=STAGES[stage].lev;
speed+=(tgt-speed)*Math.min(1,dt*(stage===0?2.2:1.1));
levY+=(tgtLev-levY)*Math.min(1,dt*2);
angle+=speed*dt;
// idle life when quiet
let breathe = stage===0 ? Math.sin(t*2.2)*3 : 0;
let blink = stage===0 && (t%4.2)<0.12 ? 0.12 : 1;
let c=Math.cos(angle), s=Math.sin(angle);
let edge=Math.abs(c);
let thin=Math.max(0.07,edge);
let stretch = 1+Math.min(0.22,speed*0.0025);
let wob = stage>=3 ? Math.sin(t*30)*4 : 0;
// main cat
let showFront = c>=0;
front.style.display=showFront?'':'none'; back.style.display=showFront?'none':'';
let blur = speed>14 ? Math.min(7,(speed-14)/9) : 0;
spinEl.style.transform=`translateX(-50%) translateY(${-levY}px) rotate(${wob}deg) scaleX(${thin}) scaleY(${stretch})`;
spinEl.style.filter = blur?`blur(${blur}px) saturate(${1+speed/40})`:'';
document.getElementById('eyes').style.transform=`scaleY(${blink})`;
document.getElementById('eyes').style.transformOrigin='center';
document.getElementById('eyes').style.transformBox='fill-box';
streaks.style.display = speed>30?'':'none';
cylShade.style.opacity = stage===0?0:Math.min(0.8,speed/60);
cylShade.style.background=`linear-gradient(90deg,rgba(0,0,0,.55),transparent 30% 70%,rgba(0,0,0,.55))`;
// ghosts = delayed angles
function ghost(el,delay,op){
if(speed<12||stage<2){el.style.opacity=0;return;}
let a2=angle-speed*delay, c2=Math.abs(Math.cos(a2));
el.style.opacity=op; el.style.transform=`translateX(-50%) translateY(${-levY+6}px) scaleX(${Math.max(0.07,c2)}) scaleY(${stretch})`;
}
ghost(g1,0.035,stage>=2?0.45:0); ghost(g2,0.07,stage>=3?0.35:0);
// shadow + halo
let shScale=Math.max(0.35,1-levY/320), shOp=Math.max(0.08,0.55-levY/380);
shadow.style.transform=`translateX(-50%) scaleX(${shScale})`;
shadow.style.opacity=shOp;
halo.style.opacity=stage===0?0:Math.min(0.9,speed/70);
halo.style.transform=`translate(-50%,20%) scale(${1+Math.sin(t*8)*0.08+speed/90})`;
// room extras
spinText.style.opacity=stage===0?0:Math.min(1,speed/25);
let reps=Math.floor(2+speed/8);
spinText.textContent=new Array(reps).fill('oiia').join(' ')+' ooooiai';
spinText.style.transform=`translateX(-50%) scale(${1+Math.sin(t*(4+speed/6))*0.06})`;
spinText.style.filter=`hue-rotate(${t*60}deg)`;
bigOiia.style.opacity=stage>=4?0.85:stage===3?0.3:0;
bigOiia.style.transform=`translate(-50%,-50%) scale(${1+speed/60+Math.sin(t*10)*0.08}) rotate(${Math.sin(t*3)*6}deg)`;
// furniture panic
if(stage>=2){sofa.style.transform=`translate(${Math.sin(t*13)*6}px,${-stage*4+Math.sin(t*17)*4}px) rotate(${Math.sin(t*11)*3}deg)`;lamp.style.transform=`translate(${Math.cos(t*15)*7}px,${-stage*6}px) rotate(${Math.cos(t*12)*4}deg)`;}
else{sofa.style.transform='';lamp.style.transform='';}
stageEl.style.filter = stage>=4?`saturate(${1.6+Math.sin(t*6)*0.4}) hue-rotate(${t*40}deg)` : stage===3?`saturate(1.4)`:'';
// orbiting minis
minis.forEach((m,i)=>{
if(stage<3){m.style.opacity=0;return;}
let n=stage===4?6:3; if(i>=n){m.style.opacity=0;return;}
m.style.opacity=0.95;
let R=stage===4?150+i*12:120, a=t*(2+speed/14)+i*(Math.PI*2/n);
m.style.left=`calc(50% + ${Math.cos(a)*R}px)`; m.style.top=`calc(58% + ${Math.sin(a)*R*0.55 - levY*0.3}px)`;
m.style.transform=`scaleX(${Math.abs(Math.cos(a*2))||0.2}) rotate(${Math.sin(a)*20}deg)`;
});
lyric.textContent = stage===0?'oiia…':('“'+new Array(Math.min(8,2+Math.floor(speed/10))).fill('oiia').join(' ')+'”').slice(0,60);
// ---- AUDIO locked to spin ----
if(AC&&audioOn){
let ph=((angle/(Math.PI*2))%1+1)%1;
let F=vowelAt(ph);
let pitch=130+speed*4.6+Math.sin(angle*2)*8+Math.sin(t*30)* (stage>=4?14:4);
let tt=AC.currentTime;
osc.frequency.setTargetAtTime(Math.max(60,pitch),tt,0.015);
sub.frequency.setTargetAtTime(Math.max(30,pitch/2),tt,0.02);
f1.frequency.setTargetAtTime(F[0]*(pitch/180+0.6),tt,0.012);
f2.frequency.setTargetAtTime(F[1]*(pitch/220+0.7),tt,0.012);
f3.frequency.setTargetAtTime(F[2],tt,0.015);
let loud = stage===0?0:(0.22+Math.min(0.7,speed/90));
let syll = 0.55+0.45*Math.abs(Math.sin(ph*Math.PI*2));
voiceGain.gain.setTargetAtTime(muted?0:loud*syll,tt,0.03);
if(delaySend) delaySend.gain.setTargetAtTime(stage>=3?0.4:0.15,tt,0.1);
}
requestAnimationFrame(frame);
}
setStage(0); requestAnimationFrame(frame);
})();
</script>
</body>
</html>
scaleX=|cos(angle)| with a front-face / back-of-head swap at the zero-crossing plus a moving cylindrical shade, so it reads as turning around, not rolling; speed ramps until blur + streaks + ghosts erase the face, with the "oiia" text riding alongside.angle/2π selects the vowel by morphing F1/F2/F3 through o→i→a, while spin speed sets pitch and loudness, so one revolution literally equals one "oiia" and rate/pitch climb together.