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>Ordinary cat. Ordinary afternoon.</title>
<style>
* { box-sizing: border-box }
html, body { margin: 0; width: 100%; height: 100%; overflow: hidden; background: #302b26 }
body { font-family: Georgia, "Times New Roman", serif; color: #fff8eb }
canvas { display: block; width: 100%; height: 100%; touch-action: manipulation }
.top {
position: fixed; top: 27px; left: 30px; right: 30px;
display: flex; justify-content: space-between; align-items: flex-start;
pointer-events: none; text-shadow: 0 1px 12px #221b15a0;
}
.title { font-size: 15px; letter-spacing: .03em }
.title small {
display: block; font: 10px/1.6 system-ui, sans-serif;
letter-spacing: .19em; text-transform: uppercase; opacity: .65; margin-top: 7px;
}
button {
color: inherit; border: 1px solid #fff5df45; background: #211b1840;
padding: 11px 15px; border-radius: 24px; cursor: pointer;
font: 11px system-ui, sans-serif; letter-spacing: .05em;
backdrop-filter: blur(12px);
}
button:hover { background: #fff5df25; border-color: #fff5df90 }
button:focus-visible { outline: 2px solid #fff1c2; outline-offset: 4px }
.tools { display: flex; gap: 8px; pointer-events: auto }
.bottom {
position: fixed; bottom: 28px; left: 24px; right: 24px;
text-align: center; pointer-events: none;
text-shadow: 0 2px 12px #1c130dc0;
}
#caption { font-size: clamp(19px, 2.3vw, 28px); margin-bottom: 9px }
#hint { font: 11px/1.6 system-ui, sans-serif; letter-spacing: .055em; opacity: .8 }
.steps { display: flex; justify-content: center; gap: 7px; margin: 17px 0 12px }
.steps i { width: 22px; height: 2px; background: #fff5df35; transition: background .5s, box-shadow .5s }
.steps i.on { background: #fff1c9; box-shadow: 0 0 9px #ffe8a577 }
#activate { pointer-events: auto; margin-top: 11px; min-width: 140px }
#reset { display: none }
.credit {
position: fixed; bottom: 22px; left: 25px; font: 9px system-ui, sans-serif;
opacity: .45; letter-spacing: .13em; pointer-events: none;
}
@media (max-width: 600px) {
.top { top: 19px; left: 19px; right: 19px }
.title { font-size: 12px; max-width: 145px }
.title small { font-size: 8px }
.tools { gap: 5px }
button { padding: 10px 12px }
.bottom { bottom: 21px }
.credit { display: none }
}
</style>
</head>
<body>
<canvas id="scene" aria-label="A cream-and-white cat sits in a sunlit living room. Click the cat to make it float and spin."></canvas>
<div class="top">
<div class="title">An ordinary afternoon.<small>A small domestic incident</small></div>
<div class="tools">
<button id="reset" aria-label="Return to the quiet room">Reset</button>
<button id="mute" aria-pressed="false">Sound on</button>
</div>
</div>
<div class="bottom">
<div id="caption">Nothing to see here.</div>
<div id="hint">Click the cat. It has somewhere to be.</div>
<div class="steps" aria-hidden="true"><i></i><i></i><i></i><i></i></div>
<button id="activate">Pet the cat</button>
</div>
<div class="credit">NO CATS WERE SUBJECTED TO GRAVITY</div>
<script>
(() => {
'use strict';
const canvas = document.getElementById('scene');
const ctx = canvas.getContext('2d', { alpha: false });
const W = 1440, H = 960, TAU = Math.PI * 2;
const clamp = (v, a, b) => Math.max(a, Math.min(b, v));
const lerp = (a, b, t) => a + (b - a) * t;
const smooth = (a, b, v) => {
let t = clamp((v - a) / (b - a), 0, 1);
return t * t * (3 - 2 * t);
};
let seed = 70913;
function random() {
seed = (Math.imul(seed, 1664525) + 1013904223) | 0;
return (seed >>> 0) / 4294967296;
}
function surface(w, h) {
const c = document.createElement('canvas');
c.width = w; c.height = h;
return c;
}
function ellipse(c, x, y, rx, ry, fill, rotation = 0) {
c.beginPath(); c.ellipse(x, y, rx, ry, rotation, 0, TAU);
c.fillStyle = fill; c.fill();
}
function linear(c, x, y, xx, yy, stops) {
const g = c.createLinearGradient(x, y, xx, yy);
for (const [p, col] of stops) g.addColorStop(p, col);
return g;
}
function radial(c, x, y, r, stops, rx = x, ry = y) {
const g = c.createRadialGradient(x, y, 0, rx, ry, r);
for (const [p, col] of stops) g.addColorStop(p, col);
return g;
}
function rounded(c, x, y, w, h, r, fill) {
c.beginPath(); c.roundRect(x, y, w, h, r);
c.fillStyle = fill; c.fill();
}
function path(c, d, fill, stroke, width = 1) {
const p = new Path2D(d);
if (fill) { c.fillStyle = fill; c.fill(p); }
if (stroke) { c.strokeStyle = stroke; c.lineWidth = width; c.stroke(p); }
return p;
}
function shadow(c, x, y, rx, ry, opacity) {
c.save(); c.translate(x, y); c.scale(rx, ry);
ellipse(c, 0, 0, 1, 1,
radial(c, 0, 0, 1, [[0, `rgba(31,22,15,${opacity})`], [.45, `rgba(31,22,15,${opacity*.65})`], [1, 'rgba(31,22,15,0)']]));
c.restore();
}
// A single, deterministic, high-resolution room painting.
const room = surface(W, H), r = room.getContext('2d');
r.fillStyle = linear(r, 0, 80, W, 670,
[[0, '#e5dfd0'], [.35, '#cec7b6'], [.72, '#b9b19e'], [1, '#8b8270']]);
r.fillRect(0, 0, W, H);
r.fillStyle = linear(r, 0, 0, 0, 95, [[0, '#a89e8a'], [1, '#e0d9c9']]);
path(r, 'M0 0H1440V46L0 81Z', r.fillStyle);
r.strokeStyle = '#f0eadb88'; r.lineWidth = 3;
r.beginPath(); r.moveTo(0, 81); r.lineTo(W, 46); r.stroke();
// Back-wall corner and warm reflected light.
r.fillStyle = linear(r, 1100, 0, 1440, 0, [[0, '#736a5810'], [1, '#655c4a64']]);
r.fillRect(1100, 46, 340, 575);
r.fillStyle = '#c0b8a5'; r.fillRect(0, 566, W, 19);
r.fillStyle = '#eee7d3'; r.fillRect(0, 566, W, 3);
r.fillStyle = '#756953'; r.fillRect(0, 584, W, 3);
// Window: recess, mullions, outside bokeh, translucent linen.
shadow(r, 240, 315, 220, 252, .12);
rounded(r, 59, 116, 328, 371, 3, '#928c7c');
rounded(r, 66, 121, 315, 360, 2, '#f2eee0');
r.fillStyle = linear(r, 80, 133, 350, 454, [[0, '#d9e1d6'], [.4, '#f7f2d9'], [1, '#b7bda6']]);
r.fillRect(79, 134, 289, 326);
r.save(); r.beginPath(); r.rect(79, 134, 289, 326); r.clip();
for (let i = 0; i < 130; i++) {
ellipse(r, 80 + random()*300, 260 + random()*250, 5+random()*27, 7+random()*29,
['#7c997727', '#a3b18935', '#f7f4d52c'][i%3]);
}
r.restore();
r.fillStyle = '#eeeade'; r.fillRect(214, 134, 9, 326); r.fillRect(79, 283, 289, 9);
r.fillStyle = '#aaa693'; r.fillRect(222, 134, 2, 326);
path(r, 'M55 473L388 473L411 492L44 492Z',
linear(r, 0, 473, 0, 496, [[0, '#f4efde'], [1, '#b8b09c']]));
for (let side = 0; side < 2; side++) {
const x = side ? 342 : 27;
path(r, `M${x} 98 Q${x+35} 106 ${x+73} 96 L${x+65} 506 Q${x+36} 492 ${x-2} 508Z`,
'#f4f0de9c');
for (let i = 0; i < 12; i++) {
r.fillStyle = linear(r, x+i*6, 0, x+i*6+6, 0,
[[0, '#817c6525'], [.5, '#fffff824'], [1, '#aba08b19']]);
r.fillRect(x+i*6, 105, 6, 393);
}
}
r.strokeStyle = '#716955'; r.lineWidth = 5;
r.beginPath(); r.moveTo(20, 96); r.lineTo(425, 96); r.stroke();
// Wood floor, perspective boards, individual grain and narrow bevels.
r.fillStyle = linear(r, 0, 586, 0, 960,
[[0, '#8b7258'], [.4, '#aa8a65'], [1, '#b89a76']]);
r.fillRect(0, 587, W, 373);
const vx = 540, vy = 438;
for (let i = -12; i < 20; i++) {
let a = i * 117, b = (i+1) * 117;
const xa = vx + (a-vx)*.285, xb = vx + (b-vx)*.285;
const p = path(r, `M${xa} 587L${xb} 587L${b} 960L${a} 960Z`,
['#b5997227','#46362519','#f8d19e16','#80634222'][((i%4)+4)%4]);
r.save(); r.clip(p);
for (let j = 0; j < 23; j++) {
const x = lerp(a,b,random()), endX = vx+(x-vx)*.285;
r.beginPath(); r.moveTo(endX, 587);
r.bezierCurveTo(lerp(endX,x,.3)+random()*8,700,
lerp(endX,x,.7)-random()*9,850,x,960);
r.strokeStyle = j%3 ? '#4e392514' : '#ffdfaa22';
r.lineWidth = .5+random()*1.2; r.stroke();
}
r.restore();
r.beginPath(); r.moveTo(xa, 587); r.lineTo(a,960);
r.strokeStyle = '#51402e70'; r.lineWidth = 1; r.stroke();
r.beginPath(); r.moveTo(xa+1, 587); r.lineTo(a+2,960);
r.strokeStyle = '#edd0a849'; r.stroke();
for (let j = 0; j < 3; j++) {
let yy = 638+j*110+random()*55;
let t = (yy-vy)/(960-vy);
r.beginPath(); r.moveTo(vx+(a-vx)*t, yy); r.lineTo(vx+(b-vx)*t, yy);
r.strokeStyle = '#5b463750'; r.stroke();
}
}
// A shaft of window light has the same direction as the cat's highlights.
path(r, 'M35 588L348 588L1005 960L337 960Z',
linear(r, 170, 590, 550, 940, [[0,'#ffefb719'], [.55,'#fff4c751'], [1,'#fff3c110']]));
path(r, 'M208 588L223 588L699 960L674 960Z', '#65563c14');
path(r, 'M68 688L527 688L540 700L70 700Z', '#7c67421c');
// Framed print: glazed surface with a little window reflection.
shadow(r, 812, 258, 151, 156, .16);
rounded(r, 688, 117, 246, 272, 2, '#5d4c36');
rounded(r, 697, 126, 228, 254, 1, '#e8dfca');
r.fillStyle = '#bbb8a2'; r.fillRect(724, 150, 176, 205);
path(r, 'M724 315L773 239L802 268L849 202L900 294V355H724Z', '#7b8374');
path(r, 'M724 330L794 292L850 311L900 286V355H724Z', '#9b967d');
ellipse(r, 772, 195, 22, 22, '#ddd0a2');
path(r, 'M701 132H778L923 325V379H880Z', '#fff9df0c');
r.fillStyle = '#ffffff30'; r.fillRect(698,126,226,1);
// Sofa, deliberately built in lit volumes rather than flat outlines.
shadow(r, 1110, 622, 300, 70, .35);
for (const x of [901, 1304]) {
path(r, `M${x} 601L${x+20} 601L${x+14} 660L${x+3} 660Z`, '#554234');
}
rounded(r, 871, 371, 483, 204, 37,
linear(r, 880, 379, 1360, 590, [[0,'#8e9686'], [.35,'#748071'], [1,'#465447']]));
rounded(r, 897, 390, 211, 167, 26,
linear(r, 900, 390, 1120, 555, [[0,'#a8ae9a'], [.7,'#7e8976'], [1,'#61715e']]));
rounded(r, 1118, 390, 207, 167, 26,
linear(r, 1110, 390, 1328, 555, [[0,'#929e88'], [1,'#63715e']]));
rounded(r, 868, 539, 472, 78, 20,
linear(r, 0, 539, 0, 621, [[0,'#a3ab92'], [.26,'#8d997f'], [.32,'#76866b'], [1,'#59674f']]));
r.strokeStyle = '#394c3960'; r.lineWidth = 2;
r.beginPath(); r.moveTo(1111, 552); r.lineTo(1111, 604); r.stroke();
rounded(r, 837, 458, 65, 157, 27,
linear(r, 837, 459, 903, 610, [[0,'#aab09d'], [.5,'#8a957f'], [1,'#617057']]));
rounded(r, 1303, 457, 68, 157, 25,
linear(r, 1303, 459, 1370, 600, [[0,'#89967d'], [1,'#54654e']]));
r.save(); r.translate(994,470); r.rotate(-.18);
rounded(r,-59,-61,116,126,14,
linear(r,-60,-60,60,70,[[0,'#c8b89b'], [.5,'#bba88c'], [1,'#94806a']]));
path(r, 'M-47 -44Q-15 -37 5 -48M-48 38Q-16 31 25 45M45 -34Q33 0 44 37',
null, '#77644c38', 1.5);
r.restore();
r.save(); r.translate(1211,478); r.rotate(.12);
rounded(r,-52,-61,109,118,13,
linear(r,-50,-50,50,60,[[0,'#ded5b9'], [1,'#b8b094']]));
path(r,'M-42 -44Q0 -36 41 -45M-42 45Q0 37 45 43',null,'#8b836b45');
r.restore();
// Sideboard and its small objects.
shadow(r, 466, 617, 118, 37, .23);
path(r, 'M367 486H569V597H367Z',
linear(r,367,486,568,597,[[0,'#8b6b4b'],[1,'#5d4631']]));
r.fillStyle = '#b18a60'; r.fillRect(358, 475, 220, 14);
r.fillStyle = '#4b3928'; r.fillRect(371, 491, 193, 3);
r.fillRect(459,494,2,99);
for(const x of [377,545]) { r.fillStyle='#604930'; r.fillRect(x,589,10,41) }
for(const x of [444,477]) ellipse(r,x,530,3,3,'#c1ac77');
for (let i=0;i<7;i++) {
r.save(); r.translate(390+i*10,475); r.rotate(i===0 ? -.12 : 0);
rounded(r,0,-48-random()*15,8,58,1,['#a3936b','#61747b','#90715b','#d3c6a4'][i%4]);
r.restore();
}
// Ceramic vase.
path(r,'M503 425Q494 446 496 465Q499 477 518 477Q539 476 538 461Q537 442 527 425L527 410H505Z',
linear(r,496,0,537,0,[[0,'#e3dbc4'],[.35,'#eee8d5'],[1,'#a49c86']]));
ellipse(r,516,411,12,3,'#8b8573');
for(let i=0;i<5;i++) {
r.beginPath(); r.moveTo(516,418);
r.quadraticCurveTo(505+i*5,374,480+i*19,349-i%2*23);
r.strokeStyle='#666c49'; r.lineWidth=1.3; r.stroke();
ellipse(r,490+i*17,363-i%2*25,5,13,'#7c845c',-.5+i*.2);
}
// Floor lamp and plant frame the depth behind the cat.
shadow(r, 1390, 672, 62, 21, .3);
ellipse(r, 1390,663,48,11,'#5e5648');
r.fillStyle='#635d51'; r.fillRect(1386,299,6,362);
path(r,'M1325 232H1450L1471 335H1304Z',
linear(r,1310,240,1460,335,[[0,'#f0e7c9'],[.5,'#ddd3b7'],[1,'#ada48a']]));
ellipse(r,1388,333,84,7,'#ada38a');
shadow(r, 160,650,80,24,.28);
path(r,'M122 543H194L184 642Q159 653 132 642Z',
linear(r,122,0,193,0,[[0,'#a67e5c'],[.3,'#b18a64'],[1,'#6e5039']]));
ellipse(r,158,544,36,8,'#473f2d');
for(let i=0;i<20;i++) {
const x=158+(random()-.5)*125, y=353+random()*183;
r.beginPath(); r.moveTo(160,551); r.quadraticCurveTo(166,470,x,y);
r.strokeStyle='#58634b'; r.lineWidth=2; r.stroke();
ellipse(r,x,y,12+random()*8,31+random()*12,
linear(r,x-15,y-25,x+15,y+25,[[0,'#81886b'],[.5,'#4d6246'],[1,'#344934']]),(x-160)/85);
r.strokeStyle='#b1b08a40'; r.lineWidth=.7;
r.beginPath(); r.moveTo(x,y-22); r.lineTo(x,y+22); r.stroke();
}
// Fine surface texture and lens fall-off, painted once, not flashing each frame.
const grain = r.getImageData(0,0,W,H);
for(let i=0;i<grain.data.length;i+=4) {
const n=(random()-.5)*5;
grain.data[i]+=n; grain.data[i+1]+=n; grain.data[i+2]+=n;
}
r.putImageData(grain,0,0);
r.fillStyle=radial(r,565,370,970,[[0,'#22180a00'],[.55,'#22180a00'],[1,'#21180760']]);
r.fillRect(0,0,W,H);
// Fur is stroked inside individually shaded anatomical volumes.
function fur(c, d, colors, bounds, direction=1, count=1500) {
const p = new Path2D(d);
const [x,y,w,h]=bounds;
c.fillStyle=linear(c,x,y,x+w,y+h,colors); c.fill(p);
c.save(); c.clip(p);
for(let i=0;i<count;i++) {
const xx=x+random()*w, yy=y+random()*h;
const length=2+random()*7;
c.beginPath(); c.moveTo(xx,yy);
c.quadraticCurveTo(xx+(random()-.5)*3,yy+length*.5,
xx+(xx-(x+w/2))*.028+(random()-.5)*3, yy+length*direction);
c.strokeStyle=i%4===0 ? 'rgba(84,62,43,.095)' : 'rgba(255,251,231,.22)';
c.lineWidth=.35+random()*.65; c.stroke();
}
c.restore();
}
const CW=400, CH=560;
function makeCat(back=false) {
const im=surface(CW,CH), c=im.getContext('2d');
// Curled tail, haunches, broad compact shoulders.
fur(c,'M291 373Q387 398 359 491Q349 533 290 530L272 482Q326 478 319 434Z',
[[0,'#c3ab89'],[.5,'#d5c3a6'],[1,'#93806a']],[270,373,94,162],1,1600);
fur(c,'M121 258Q69 305 57 430Q47 492 83 527Q118 542 161 517L171 345Z',
[[0,'#d6c7ab'],[.4,'#ede5d1'],[1,'#b8aa91']],[52,258,121,280],1,2000);
fur(c,'M273 264Q327 324 337 433Q348 487 316 523Q285 541 245 520L236 344Z',
[[0,'#e2d6bc'],[.55,'#c3b295'],[1,'#96866e']],[237,264,107,278],1,2000);
fur(c,'M132 205Q99 250 111 353L120 504Q195 541 275 501L287 343Q303 264 263 205Z',
back
? [[0,'#ddd0b2'],[.4,'#c8b493'],[1,'#a59172']]
: [[0,'#e1d7bd'],[.3,'#f4f0df'],[.7,'#e1ddcc'],[1,'#a69f8b']],
[106,203,190,320],1,4800);
if(!back) {
fur(c,'M142 288Q165 266 190 306L184 508Q177 535 146 528Q126 522 133 495Z',
[[0,'#f5f2e5'],[.55,'#eeeadc'],[1,'#b6b1a0']],[130,281,65,251],1,1200);
fur(c,'M208 303Q231 272 256 291L264 495Q273 529 238 534Q209 533 208 511Z',
[[0,'#ebe7d8'],[.4,'#f1eee0'],[1,'#aaa795']],[207,283,65,254],1,1200);
fur(c,'M130 500Q148 485 177 501Q194 514 184 532Q161 544 132 534Q119 519 130 500Z',
[[0,'#f6f1e1'],[.7,'#ded9c7'],[1,'#aaa38e']],[123,494,66,44],1,600);
fur(c,'M213 501Q234 487 262 503Q277 519 264 535Q238 544 213 533Q205 519 213 501Z',
[[0,'#f2eddc'],[.6,'#ded8c5'],[1,'#a49c87']],[210,494,60,45],1,600);
for(const x of [146,165,230,249]) {
path(c,`M${x} 518Q${x-2} 525 ${x} 532`,null,'#8c82713c',.8);
}
}
// Ears have thickness, velvet interiors, and pale guard hairs.
fur(c,'M112 149Q86 104 92 45Q94 35 106 43L165 94Z',
[[0,'#d1bd98'],[.6,'#c2aa86'],[1,'#998568']],[87,38,82,117],1,1100);
fur(c,'M239 91L294 40Q307 32 309 51Q318 105 287 149Z',
[[0,'#d6c19e'],[.5,'#b69d79'],[1,'#8d785e']],[235,37,83,117],1,1100);
path(c,'M108 63L145 104L110 132Q98 101 108 63Z',
linear(c,105,64,133,133,[[0,'#ae9480'],[.6,'#b69b85'],[1,'#d8c7a9']]));
path(c,'M292 63Q303 101 283 133L257 106Z',
linear(c,292,64,272,139,[[0,'#a58a75'],[1,'#d5bea0']]));
fur(c,'M103 134Q104 95 148 84Q193 69 245 86Q295 93 301 143Q319 177 301 213Q288 257 232 271Q178 280 133 250Q97 226 96 188Z',
[[0,'#e1cda8'],[.3,'#d5bf99'],[.65,'#c4aa82'],[1,'#9e886a']],
[93,78,215,196],1,6500);
// Crown shading / tiny irregular tabby marks, not cartoon stripes.
c.save();
c.globalAlpha=.13;
for(let i=0;i<18;i++) {
path(c,`M${143+i*6} ${96+random()*13}Q${150+i*5} 119 ${151+i*5} ${132+random()*8}`,
null,'#786343',1+random()*2);
}
c.restore();
if(!back) {
fur(c,'M108 190Q128 174 159 190L193 207L220 202Q263 177 293 197Q304 228 272 251Q239 278 196 271Q139 269 115 239Z',
[[0,'#eee5d0'],[.3,'#faf7e8'],[.7,'#eae5d3'],[1,'#bcb29c']],
[107,182,194,95],1,2300);
fur(c,'M183 154Q198 151 210 169L222 216L185 225L172 195Z',
[[0,'#e8dec7'],[.4,'#f8f2df'],[1,'#ded3b8']],[172,153,52,74],1,700);
function eye(x,y,angle) {
c.save(); c.translate(x,y); c.rotate(angle);
ellipse(c,0,0,30,28,'#76694f');
ellipse(c,0,1,27,25,'#242a1d');
ellipse(c,0,0,25.5,24,
radial(c,-8,-7,37,[[0,'#c6c28a'],[.5,'#a4ab6e'],[.78,'#778653'],[1,'#53613d']]));
c.save(); c.beginPath(); c.ellipse(0,0,25,24,0,0,TAU); c.clip();
for(let j=0;j<90;j++) {
const a=j/90*TAU, rr=13+random()*4;
c.beginPath(); c.moveTo(Math.cos(a)*rr,Math.sin(a)*rr);
c.lineTo(Math.cos(a)*24,Math.sin(a)*24);
c.strokeStyle=j%3===0?'#e2d29565':'#47563950'; c.lineWidth=.5; c.stroke();
}
c.restore();
ellipse(c,0,1,12,21,'#10120f');
ellipse(c,-7,-10,6,7,'#fffce2c9');
rounded(c,-10,-13,6,5,1,'#ffffffd0');
ellipse(c,7,13,2,2,'#d5dcbc77');
path(c,'M-28 -5Q-12 -31 9 -25Q22 -22 29 -6',null,'#675940',2);
path(c,'M-26 10Q0 29 24 12',null,'#e4d8bb',1.3);
c.restore();
}
eye(150,171,-.055); eye(249,171,.055);
ellipse(c,179,224,28,21,
radial(c,169,214,38,[[0,'#fcf8e9'],[1,'#c5bca7']]));
ellipse(c,222,224,29,21,
radial(c,212,214,38,[[0,'#f8f4e6'],[1,'#bfb49e']]));
path(c,'M186 208Q198 201 212 208Q211 217 200 223Q191 220 186 208Z',
linear(c,190,203,209,224,[[0,'#a98b79'],[.5,'#b39786'],[1,'#6d594c']]));
path(c,'M200 222L200 232Q188 242 178 233M200 232Q212 241 224 233',
null,'#6c6356',1.3);
ellipse(c,199,249,17,6,'#f9f5e6');
for(let i=0;i<24;i++) {
let side=i%2?-1:1;
ellipse(c,200+side*(17+random()*15),221+random()*11,.65,.65,'#8a7b6660');
}
// Thin whiskers catch the window, on the left more strongly.
for(let side of [-1,1]) for(let j=0;j<7;j++) {
c.beginPath();
c.moveTo(200+side*25,226+j*1.8);
c.quadraticCurveTo(200+side*75,215+j*6,
200+side*(105+random()*20),208+j*11);
c.strokeStyle=side<0?'#fcf5deaa':'#e0d4ba82';
c.lineWidth=.55; c.stroke();
}
}
// Soft silhouette flyaways: sparse and irregular, not a hard vector edge.
for(let i=0;i<620;i++) {
const a=random()*TAU;
const x=200+Math.cos(a)*104, y=178+Math.sin(a)*95;
if(y<99 || y>255) continue;
c.beginPath(); c.moveTo(x,y);
c.lineTo(x+Math.cos(a)*(2+random()*5),y+Math.sin(a)*(2+random()*5));
c.strokeStyle='#e3d4b575'; c.lineWidth=.4; c.stroke();
}
return im;
}
const catFront=makeCat(false), catBack=makeCat(true);
// Portable debris sprites. They are quiet room objects until gravity goes away.
const cushion=surface(130,130), pc=cushion.getContext('2d');
rounded(pc,9,10,110,110,18,
linear(pc,12,12,118,119,[[0,'#ddd3b8'],[.5,'#bbae8f'],[1,'#887d62']]));
path(pc,'M20 22Q60 33 107 22M21 108Q60 97 108 108M22 22Q31 63 21 108M107 22Q97 65 108 108',
null,'#786c5055',1.5);
const book=surface(110,80), bc=book.getContext('2d');
rounded(bc,8,12,96,57,3,'#425c60');
rounded(bc,13,18,83,43,2,'#e0d6bd');
for(let i=0;i<8;i++) { bc.fillStyle='#a99e8370'; bc.fillRect(16,22+i*4,77,1) }
bc.fillStyle='#536e70'; bc.fillRect(7,11,8,59);
let vw=innerWidth, vh=innerHeight, scale=1, ox=0, oy=0;
function resize() {
vw=innerWidth; vh=innerHeight;
const dpr=Math.min(devicePixelRatio||1,2);
canvas.width=Math.round(vw*dpr); canvas.height=Math.round(vh*dpr);
scale=Math.max(vw/W,vh/H);
ox=(vw-W*scale)/2; oy=(vh-H*scale)/2;
}
addEventListener('resize',resize); resize();
let stage=0, extra=0, speed=0, lift=0, theta=0, time=0;
let last=performance.now(), stageAge=0;
let muted=false, audio=null, currentCat={x:720,y:590};
const reduced=matchMedia('(prefers-reduced-motion: reduce)').matches;
const captions=[
'Nothing to see here.',
'The cat has left the floor.',
'The furniture has questions.',
'Gravity has left the chat.',
'The room is now the cat’s problem.'
];
function refreshUI() {
document.getElementById('caption').textContent=captions[stage];
document.getElementById('hint').textContent=stage===0
? 'Click the cat. It has somewhere to be.'
: stage===4
? 'oiia oiia oiiaiooooiai · yes, you can click again'
: 'Click again. It gets considerably less normal.';
document.getElementById('activate').textContent=stage===0?'Pet the cat':stage===4?'Further beyond':'More oiia';
document.getElementById('reset').style.display=stage?'inline-block':'none';
document.querySelectorAll('.steps i').forEach((e,i)=>e.classList.toggle('on',i<stage));
canvas.style.cursor=stage?'pointer':'default';
}
// A voiced glottal source through parallel, moving vocal-tract resonances.
// No prerecorded audio, speech service, or network resources.
function createAudio() {
const AC=window.AudioContext||window.webkitAudioContext;
if(!AC) return null;
const ac=new AC();
const master=ac.createGain(); master.gain.value=0;
const comp=ac.createDynamicsCompressor();
comp.threshold.value=-19; comp.knee.value=12; comp.ratio.value=5;
comp.attack.value=.006; comp.release.value=.1;
master.connect(comp); comp.connect(ac.destination);
const voice=ac.createOscillator();
const real=new Float32Array(65), imag=new Float32Array(65);
// A steep glottal closure supplies the upper harmonics needed for vowels.
for(let h=1;h<65;h++) imag[h]=(1/h)*Math.exp(-h/30)*(1+.14*Math.cos(h*.8));
voice.setPeriodicWave(ac.createPeriodicWave(real,imag));
const source=ac.createGain(); source.gain.value=.65;
voice.connect(source);
const filters=[], gains=[];
for(let i=0;i<4;i++) {
const f=ac.createBiquadFilter(); f.type='bandpass';
f.frequency.value=[450,800,2600,3300][i];
f.Q.value=[6,9,12,10][i];
const g=ac.createGain(); g.gain.value=[1.15,.75,.30,.12][i];
source.connect(f); f.connect(g); g.connect(master);
filters.push(f); gains.push(g);
}
// A very small aspirated component breaks the perfectly electronic timbre.
const noise=ac.createBuffer(1,ac.sampleRate,ac.sampleRate);
const data=noise.getChannelData(0);
let brown=0;
for(let i=0;i<data.length;i++) {
brown=(brown+(Math.random()*2-1)*.06)/1.025;
data[i]=brown;
}
const breath=ac.createBufferSource(); breath.buffer=noise; breath.loop=true;
const hp=ac.createBiquadFilter(); hp.type='highpass'; hp.frequency.value=900;
const ng=ac.createGain(); ng.gain.value=.055;
breath.connect(hp); hp.connect(ng); ng.connect(filters[1]);
voice.start(); breath.start();
return {ac,master,voice,filters,source,breath};
}
// Twelve short syllables, with the long "oooo" and the last broken "iai".
const vowels={
o:[440,790,2500,3300],
i:[270,2250,3010,3500],
a:[780,1230,2640,3400]
};
const phrase=['o','i','i','a','o','i','i','a','o','i','i','a','i','o','o','o','o','i','a','i'];
function soundFrame() {
if(!audio) return;
const {ac,master,voice,filters,source}=audio;
const now=ac.currentTime;
const activity=smooth(0,.6,speed);
// One oiia per 1.4 revolutions; no independent audio-loop clock to drift.
const syllables=theta/TAU/1.4*4;
const n=Math.floor(syllables), f=syllables-n;
const index=((n%phrase.length)+phrase.length)%phrase.length;
const a=vowels[phrase[index]], b=vowels[phrase[(index+1)%phrase.length]];
const transition=smooth(.57,.97,f);
const pitch=110+speed*12.5+Math.sin(theta*.65)*8;
voice.frequency.setTargetAtTime(clamp(pitch,110,420),now,.018);
const formantScale=1+Math.min(speed,18)*.012;
filters.forEach((filter,i)=>filter.frequency.setTargetAtTime(
lerp(a[i],b[i],transition)*formantScale,now,.014));
// Consonant-like separation, not four endlessly sustained organ notes.
const attack=smooth(0,.11,f), release=1-smooth(.88,1,f);
const longO=index>=13&&index<=16;
source.gain.setTargetAtTime((longO?.63:.2+.48*attack*release)*activity,now,.009);
master.gain.setTargetAtTime(muted||stage===0?0:.25+stage*.045,now,.045);
}
function activate() {
if(stage<4) stage++; else extra=Math.min(extra+1,10);
stageAge=0;
if(!audio) {
try { audio=createAudio() } catch(e) { audio=null }
}
if(audio) audio.ac.resume().catch(()=>{});
refreshUI();
}
document.getElementById('activate').addEventListener('click',activate);
document.getElementById('reset').addEventListener('click',()=>{
stage=0; extra=0; speed=0; theta=0; lift=0; stageAge=0;
if(audio) audio.master.gain.setTargetAtTime(0,audio.ac.currentTime,.06);
refreshUI();
});
document.getElementById('mute').addEventListener('click',()=>{
muted=!muted;
document.getElementById('mute').textContent=muted?'Sound off':'Sound on';
document.getElementById('mute').setAttribute('aria-pressed',String(muted));
if(audio) audio.master.gain.setTargetAtTime(muted?0:stage?.25+stage*.045:0,
audio.ac.currentTime,.04);
});
canvas.addEventListener('pointerdown',e=>{
const x=(e.clientX-ox)/scale, y=(e.clientY-oy)/scale;
if(Math.abs(x-currentCat.x)<165 && Math.abs(y-currentCat.y)<235) activate();
});
canvas.addEventListener('pointermove',e=>{
const x=(e.clientX-ox)/scale, y=(e.clientY-oy)/scale;
canvas.style.cursor=Math.abs(x-currentCat.x)<165&&Math.abs(y-currentCat.y)<235?'pointer':'default';
});
function spinningCat(c,x,bottom,height,angle,alpha=1) {
const cosine=Math.cos(angle), sine=Math.sin(angle);
const width=.55+.45*Math.abs(cosine);
c.save(); c.globalAlpha*=alpha;
c.translate(x,bottom);
// Only horizontal foreshortening: this is a yaw, not a cartwheel.
c.scale(height/CH*width,height/CH);
c.drawImage(catBack,-CW/2,-CH);
const front=smooth(-.02,.75,cosine);
if(front>0) {
c.globalAlpha*=front;
c.translate(sine*17,0);
c.drawImage(catFront,-CW/2,-CH);
}
c.restore();
}
function debris(c,x,y,asset,size,angle,alpha=1) {
c.save(); c.globalAlpha*=alpha;
c.translate(x,y); c.rotate(angle);
c.drawImage(asset,-size/2,-size/2,size,size);
c.restore();
}
function portal(c,x,y,amount) {
c.save(); c.translate(x,y);
// A tilted orbital aperture, with a continuous warm-to-violet light field.
c.scale(1,.66);
const glow=radial(c,0,0,445,[
[0,'#0e102ae8'],[.4,'#262340bb'],[.63,'#625086a0'],
[.72,'#c3a7e470'],[.84,'#e6c1b336'],[1,'#bda0ff00']
]);
ellipse(c,0,0,445,445,glow);
for(let i=0;i<9;i++) {
let rad=136+i*30+Math.sin(time*.6+i)*7;
c.beginPath(); c.ellipse(0,0,rad,rad,0,0,TAU);
c.strokeStyle=`rgba(${180+i*5},${154+i*6},240,${.12+(i%3)*.09})`;
c.lineWidth=i%3===0?4:1; c.stroke();
}
// The room returns, smaller and smaller, inside its own gravitational well.
for(let j=5;j>=0;j--) {
const sz=100+j*52;
c.save(); c.rotate(-time*.12+j*.38);
c.globalAlpha=.13+j*.045;
c.beginPath(); c.roundRect(-sz/2,-sz/2,sz,sz,8); c.clip();
c.drawImage(room,380,130,720,720,-sz/2,-sz/2,sz,sz);
c.restore();
}
c.restore();
}
function render(now) {
const dt=Math.min((now-last)/1000,.045); last=now; time+=dt; stageAge+=dt;
const targets=[0,2.7,5.2,8.4,12.8+extra*.55];
const targetLift=[0,82,158,222,265+Math.min(extra*7,45)];
speed=lerp(speed,targets[stage],1-Math.exp(-dt*(stage?1.1:8)));
lift=lerp(lift,targetLift[stage],1-Math.exp(-dt*1.55));
// Reduced-motion retains the physics tableaux without the aggressive camera.
theta+=dt*speed*TAU*(reduced?.3:1);
soundFrame();
const dpr=canvas.width/vw;
ctx.setTransform(dpr,0,0,dpr,0,0);
ctx.fillStyle='#28231f'; ctx.fillRect(0,0,vw,vh);
ctx.translate(ox,oy); ctx.scale(scale,scale);
const chaos=smooth(4.8,11,speed);
const cosmic=stage===4?smooth(0,3,stageAge):0;
const wobble=reduced?0:chaos;
ctx.save();
ctx.translate(720,480);
ctx.rotate(wobble*(Math.sin(time*.73)*.045+Math.sin(time*1.4)*.022));
const zoom=1+chaos*.025;
ctx.scale(zoom,zoom); ctx.translate(-720,-480);
if(stage<3||reduced) ctx.drawImage(room,0,0);
else {
// Gravity bends the architecture in continuous horizontal bands.
const band=12;
for(let y=0;y<H;y+=band) {
const bend=Math.sin(y/H*5+time*.9)*chaos*15
+Math.sin(y/H*9-time*.55)*cosmic*14;
ctx.drawImage(room,0,y,W,band,-24+bend,y,W+48,band+.6);
}
}
// As the cat starts to own the room, the room loses ordinary afternoon light.
ctx.fillStyle=`rgba(19,16,34,${cosmic*.38})`; ctx.fillRect(0,0,W,H);
ctx.restore();
const hover=stage?Math.sin(time*(1.8+stage*.2))*Math.min(lift*.045,10):0;
const cx=720+(stage>=3?Math.sin(time*.65)*22:0);
const bottom=790-lift+hover;
currentCat={x:cx,y:bottom-201};
// The physical shadow stays ON the floor as the cat separates from it.
shadow(ctx,720+lift*.24,792+lift*.035,
135+lift*.16,20+lift*.025,.44*Math.exp(-lift/240));
if(stage) {
ctx.save();
ctx.translate(720,800); ctx.scale(1,.24);
for(let j=0;j<3;j++) {
const radius=80+j*30+lift*.28;
ctx.beginPath(); ctx.arc(0,0,radius,0,TAU);
ctx.strokeStyle=`rgba(236,217,161,${.10+stage*.025-j*.02})`;
ctx.lineWidth=2; ctx.stroke();
}
ctx.restore();
}
if(stage>=2) {
const amount=smooth(0,2,stageAge);
const angle=time*(.8+stage*.18);
// The sofa's cushions and a book become a small satellite system.
for(let i=0;i<3;i++) {
const a=angle+i*TAU/3, depth=Math.sin(a);
const xx=cx+Math.cos(a)*(192+stage*13);
const yy=bottom-145+depth*66;
if(depth<0) debris(ctx,xx,yy,i===1?book:cushion,
(i===1?72:79)*(1+depth*.1)*amount,a*.5);
}
}
if(cosmic>0) {
ctx.save(); ctx.globalAlpha=cosmic;
portal(ctx,cx,bottom-173,cosmic);
// Little living rooms orbit their own living room. No flash cuts.
const satellites=6+Math.min(extra,4);
for(let j=0;j<satellites;j++) {
const a=time*.27+j*TAU/satellites;
const x=cx+Math.cos(a)*(360+Math.sin(j)*28);
const y=bottom-170+Math.sin(a)*215;
const sz=83+(Math.sin(a)+1)*19;
ctx.save(); ctx.translate(x,y); ctx.rotate(a+.2);
ctx.shadowColor='#e2cfff77'; ctx.shadowBlur=15;
rounded(ctx,-sz*.7,-sz*.45,sz*1.4,sz*.9,5,'#c2a8bd');
ctx.shadowBlur=0;
ctx.beginPath(); ctx.roundRect(-sz*.68,-sz*.43,sz*1.36,sz*.86,4); ctx.clip();
ctx.drawImage(room,-sz*.68,-sz*.43,sz*1.36,sz*.86);
spinningCat(ctx,0,sz*.35,sz*.58,theta*.55+j);
ctx.restore();
}
// A coherent, slowly travelling accretion stream, not a white strobe.
for(let j=0;j<95;j++) {
const a=j*2.399+time*.19;
const rad=250+(j%17)*9;
const xx=cx+Math.cos(a)*rad;
const yy=bottom-172+Math.sin(a)*rad*.56;
ellipse(ctx,xx,yy,1+(j%3)*.45,1+(j%3)*.45,
j%3?'#ffe6bd80':'#d7c2ffb0');
}
ctx.restore();
}
if(stage>=3) {
const a=time*.53;
// A miniature sofa detaches into orbit: the furniture has joined the edit.
const x=cx+Math.cos(a)*305, y=bottom-180+Math.sin(a)*150;
ctx.save(); ctx.translate(x,y); ctx.rotate(a*.4);
ctx.globalAlpha=smooth(0,2,stageAge);
ctx.drawImage(room,827,367,550,301,-103,-58,206,113);
ctx.restore();
// The rug that wasn't there before: a continuously turning floor galaxy.
ctx.save(); ctx.translate(720,803); ctx.scale(1,.19); ctx.rotate(time*.35);
for(let j=0;j<4;j++) {
ctx.beginPath();
for(let k=0;k<150;k++) {
const q=k/149, a=q*TAU*1.8+j*TAU/4;
const rad=75+q*295;
const x=Math.cos(a)*rad, y=Math.sin(a)*rad;
k?ctx.lineTo(x,y):ctx.moveTo(x,y);
}
ctx.strokeStyle=`rgba(235,210,174,${.12+cosmic*.10})`;
ctx.lineWidth=3; ctx.stroke();
}
ctx.restore();
}
// At high speed the accumulated exposures erase the face into a cream blur.
const smear=smooth(3.2,9,speed);
if(smear>0) {
ctx.save();
ctx.globalCompositeOperation='screen';
const trails=reduced?2:7;
for(let j=trails;j>0;j--) {
const lag=j*.008*(1+stage*.25);
spinningCat(ctx,cx+Math.sin(theta-lag*speed*TAU)*smear*8,
bottom+Math.cos(theta*.3+j)*smear*2,404,
theta-lag*speed*TAU,smear*.068);
}
ctx.restore();
}
spinningCat(ctx,cx,bottom,404,theta,1-smear*.18);
if(stage>=2) {
const amount=smooth(0,2,stageAge);
const angle=time*(.8+stage*.18);
for(let i=0;i<3;i++) {
const a=angle+i*TAU/3, depth=Math.sin(a);
if(depth>=0) debris(ctx,cx+Math.cos(a)*(192+stage*13),
bottom-145+depth*66,i===1?book:cushion,
(i===1?72:79)*(1+depth*.1)*amount,a*.5);
}
}
if(cosmic>.1) {
// A pair of orbiting Oiias brings the joke back to the cat.
for(let i=0;i<2;i++) {
const a=time*.83+i*Math.PI;
const x=cx+Math.cos(a)*248;
const y=bottom-125+Math.sin(a)*126;
spinningCat(ctx,x,y,108,theta*(i?-.67:.83)+i,cosmic*.92);
}
}
// Deliberately leave the opening entirely still; no animation before the click.
requestAnimationFrame(render);
}
refreshUI();
requestAnimationFrame(render);
})();
</script>
</body>
</html>