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.0">
<title>OIIA</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; user-select: none; }
html, body { width: 100%; height: 100%; overflow: hidden; background: #0c0a09; font-family: system-ui, -apple-system, sans-serif; }
canvas { display: block; width: 100vw; height: 100vh; cursor: pointer; }
#ui {
position: fixed; top: 18px; right: 18px; display: flex; gap: 10px; z-index: 10;
align-items: center; pointer-events: none;
}
.btn {
pointer-events: auto;
background: rgba(20, 18, 16, 0.58);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
color: rgba(255, 250, 242, 0.88);
border: 1px solid rgba(255, 255, 255, 0.14);
border-radius: 999px;
padding: 8px 14px;
font-size: 12px;
font-weight: 500;
letter-spacing: 0.06em;
text-transform: uppercase;
cursor: pointer;
transition: background 0.2s, transform 0.1s, opacity 0.4s;
}
.btn:hover { background: rgba(38, 34, 30, 0.78); }
.btn:active { transform: scale(0.96); }
#stage-pill {
opacity: 0;
background: rgba(20, 18, 16, 0.45);
backdrop-filter: blur(8px);
color: rgba(255, 250, 240, 0.8);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 999px;
padding: 7px 13px;
font-size: 11px;
letter-spacing: 0.08em;
text-transform: uppercase;
transition: opacity 0.35s;
}
#stage-pill.visible { opacity: 1; }
#hint {
position: fixed; bottom: 22px; left: 50%; transform: translateX(-50%);
color: rgba(255, 248, 236, 0.52);
font-size: 12px; letter-spacing: 0.12em; text-transform: uppercase;
pointer-events: none; transition: opacity 0.6s;
text-shadow: 0 1px 6px rgba(0,0,0,0.75);
}
</style>
</head>
<body>
<canvas id="gl"></canvas>
<div id="ui">
<div id="stage-pill">Stage 1</div>
<button class="btn" id="reset-btn" style="display:none">Calm Down</button>
<button class="btn" id="mute-btn" aria-label="Toggle Mute">Sound: On</button>
</div>
<div id="hint">Click the cat</div>
<script>
(() => {
const canvas = document.getElementById('gl');
const gl = canvas.getContext('webgl2', { antialias: false, powerPreference: 'high-performance' });
const stagePill = document.getElementById('stage-pill');
const muteBtn = document.getElementById('mute-btn');
const resetBtn = document.getElementById('reset-btn');
const hintEl = document.getElementById('hint');
if (!gl) {
document.body.innerHTML = '<div style="color:#fff;padding:40px">WebGL2 is required to view this piece.</div>';
return;
}
// ---------- SHADERS ----------
const vsSource = `#version 300 es
in vec2 a_pos;
out vec2 v_uv;
void main() {
v_uv = a_pos * 0.5 + 0.5;
gl_Position = vec4(a_pos, 0.0, 1.0);
}`;
const fsSource = `#version 300 es
precision highp float;
in vec2 v_uv;
out vec4 fragColor;
uniform vec2 u_res;
uniform float u_time;
uniform float u_stage; // smooth stage 0..4
uniform int u_stageInt; // discrete target stage
uniform float u_spinAngle; // accumulated rotation angle
uniform float u_spinSpeed; // current rad/s
uniform float u_lift; // vertical lift 0..1.6
uniform float u_blur; // azimuthal motion blur 0..1
uniform float u_vocalEnergy; // formant pulse 0..1
uniform float u_bassPulse; // beat kick 0..1
uniform float u_camShake; // shake amount
#define PI 3.14159265359
#define TAU 6.28318530718
// --- Hash & Noise ---
float hash12(vec2 p) {
vec3 p3 = fract(vec3(p.xyx) * .1031);
p3 += dot(p3, p3.yzx + 33.33);
return fract((p3.x + p3.y) * p3.z);
}
float hash13(vec3 p3) {
p3 = fract(p3 * .1031);
p3 += dot(p3, p3.zyx + 31.32);
return fract((p3.x + p3.y) * p3.z);
}
float noise3(vec3 x) {
vec3 i = floor(x);
vec3 f = fract(x);
f = f * f * (3.0 - 2.0 * f);
return mix(
mix(mix(hash13(i + vec3(0,0,0)), hash13(i + vec3(1,0,0)), f.x),
mix(hash13(i + vec3(0,1,0)), hash13(i + vec3(1,1,0)), f.x), f.y),
mix(mix(hash13(i + vec3(0,0,1)), hash13(i + vec3(1,0,1)), f.x),
mix(hash13(i + vec3(0,1,1)), hash13(i + vec3(1,1,1)), f.x), f.y), f.z);
}
float fbm2(vec2 p) {
float v = 0.0, a = 0.5;
mat2 rot = mat2(0.8, 0.6, -0.6, 0.8);
for (int i = 0; i < 4; i++) {
v += a * noise3(vec3(p, 1.5));
p = rot * p * 2.03;
a *= 0.5;
}
return v;
}
// --- SDF Primitives & Ops ---
float smin(float a, float b, float k) {
float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0);
return mix(b, a, h) - k * h * (1.0 - h);
}
float smax(float a, float b, float k) {
return -smin(-a, -b, k);
}
float sdBox(vec3 p, vec3 b) {
vec3 q = abs(p) - b;
return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
}
float sdRoundBox(vec3 p, vec3 b, float r) {
vec3 q = abs(p) - b;
return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0) - r;
}
float sdEllipsoid(vec3 p, vec3 r) {
float k0 = length(p / r);
float k1 = length(p / (r * r));
return k0 * (k0 - 1.0) / max(k1, 0.0001);
}
float sdCapsule(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 sdCappedCylinder(vec3 p, float h, float r) {
vec2 d = abs(vec2(length(p.xz), p.y)) - vec2(r, h);
return min(max(d.x, d.y), 0.0) + length(max(d, 0.0));
}
float sdTorus(vec3 p, vec2 t) {
vec2 q = vec2(length(p.xz) - t.x, p.y);
return length(q) - t.y;
}
mat2 rot2(float a) {
float c = cos(a), s = sin(a);
return mat2(c, -s, s, c);
}
// --- Cat SDF (Ethel / Oiia Meme Loaf-Sit) ---
// Material IDs:
// 1.0 = Cat fur/eyes/nose
// 2.0 = Hardwood floor & rug
// 3.0 = Walls & baseboard
// 4.0 = Sofa
// 5.0 = Coffee table / mug / books
// 6.0 = Floor lamp / plant pot / frame
// 7.0 = Lamp shade (emissive warm)
// 8.0 = Plant leaves
vec3 catToLocal(vec3 p) {
vec3 cPos = vec3(0.0, u_lift, 0.0);
// Subtle hover bob when lifted
if (u_stage > 0.05) {
cPos.y += sin(u_time * 3.8) * 0.035 * clamp(u_stage, 0.0, 2.0);
}
vec3 q = p - cPos;
// Slight tilt during extreme spin/vortex
float tilt = sin(u_time * 5.0) * 0.06 * smoothstep(1.5, 3.5, u_stage);
q.xy = rot2(tilt) * q.xy;
q.xz = rot2(-u_spinAngle) * q.xz;
return q;
}
// Evaluate pure cat in local cat coordinates (feet at y=0, facing +Z)
float sdCatLocal(vec3 p, float blurAmt) {
// Bounding check
float bound = length(p - vec3(0.0, 0.34, 0.0)) - 0.65;
if (bound > 0.15) return bound;
// Breathing when calm
float breath = (1.0 - smoothstep(0.0, 0.5, u_stage)) * sin(u_time * 2.1) * 0.006;
// 1. Plump sitting body (pear/loaf upright)
vec3 bp = p - vec3(0.0, 0.24, -0.03);
// Widen base, taper shoulders
float taper = clamp((bp.y + 0.24) / 0.48, 0.0, 1.0);
vec3 bodyRad = vec3(mix(0.225, 0.145, taper) + breath, 0.245, mix(0.245, 0.165, taper) + breath);
float body = sdEllipsoid(bp, bodyRad);
// Chest puff (front bib)
float chest = sdEllipsoid(p - vec3(0.0, 0.31, 0.095), vec3(0.145, 0.155, 0.125));
body = smin(body, chest, 0.06);
// Haunches
vec3 sp = vec3(abs(p.x), p.y, p.z);
float haunch = sdEllipsoid(sp - vec3(0.115, 0.13, -0.06), vec3(0.115, 0.135, 0.155));
body = smin(body, haunch, 0.055);
// Tucked / neat front paws (tucked when spinning fast!)
float tuck = smoothstep(0.15, 0.85, u_spinSpeed / 12.0);
vec3 pawPos = mix(vec3(0.068, 0.042, 0.175), vec3(0.055, 0.095, 0.135), tuck);
float paws = sdEllipsoid(sp - pawPos, vec3(0.052, 0.042, 0.068));
float legs = sdCapsule(sp, vec3(0.075, 0.24, 0.09), pawPos + vec3(0.0, 0.02, -0.015), 0.046);
body = smin(body, smin(paws, legs, 0.03), 0.035);
// 2. Round meme head, slightly low-slung into shoulders, staring dead straight
vec3 hp = p - vec3(0.0, 0.505, 0.065);
float head = sdEllipsoid(hp, vec3(0.168, 0.148, 0.152));
// Chubby cheeks
vec3 hsp = vec3(abs(hp.x), hp.y, hp.z);
float cheek = sdEllipsoid(hsp - vec3(0.085, -0.032, 0.048), vec3(0.088, 0.072, 0.082));
head = smin(head, cheek, 0.05);
// Muzzle / whisker pads
float muzzle = sdEllipsoid(hsp - vec3(0.034, -0.042, 0.132), vec3(0.044, 0.034, 0.042));
head = smin(head, muzzle, 0.028);
// Chin
float chin = sdEllipsoid(hp - vec3(0.0, -0.078, 0.115), vec3(0.045, 0.026, 0.038));
head = smin(head, chin, 0.025);
// Ears (small-medium triangular, slightly wide-set for startled stare)
vec3 ep = hsp - vec3(0.105, 0.125, -0.005);
ep.xy = rot2(-0.28) * ep.xy;
ep.yz = rot2(0.12) * ep.yz;
float earH = clamp(ep.y / 0.105, 0.0, 1.0);
float ear = sdRoundBox(ep - vec3(0.0, 0.035, 0.0), vec3(mix(0.046, 0.006, earH), 0.052, mix(0.028, 0.006, earH)), 0.008);
// Ear hollow
float earCup = sdEllipsoid(ep - vec3(0.0, 0.03, 0.022), vec3(0.026 * (1.0 - earH*0.6), 0.04, 0.018));
ear = smax(ear, -earCup, 0.008);
head = smin(head, ear, 0.026);
// Bulging round eyesockets / eyeballs
float eye = length(hsp - vec3(0.062, 0.012, 0.124)) - 0.036;
head = smin(head, eye, 0.008);
// Wrap-around tail curled neatly around right side
float tailAngle = atan(p.z + 0.02, p.x);
// Tail wraps from back (-PI/2) around right (+X) toward front
vec3 tp = p - vec3(0.0, 0.045 + tuck * 0.04, -0.02);
float tr = mix(0.225, 0.185, tuck);
float tailRing = length(vec2(length(tp.xz) - tr, tp.y)) - 0.034;
// Clip tail arc
float arcMask = max(-tp.x - 0.08, tp.z - 0.15);
tailRing = smax(tailRing, arcMask, 0.04);
float d = smin(body, head, 0.055);
d = smin(d, tailRing, 0.03);
// At high spin speeds, blend smoothly toward a spun lathe silhouette (true motion blur volume!)
if (blurAmt > 0.01) {
float r = length(p.xz);
// Lathe profile of the cat
vec3 lp = vec3(0.0, p.y, r);
float latheBody = length(vec2(r, (p.y - 0.25) * 0.92)) - 0.225;
float latheHead = length(vec2(r, (p.y - 0.505) * 1.02)) - 0.162;
float lathe = smin(latheBody, latheHead, 0.06);
lathe = max(lathe, -p.y);
d = mix(d, smin(d, lathe, 0.03), blurAmt * 0.82);
}
// Micro fur silhouette displacement (fades into sleekness when blurred)
if (d < 0.03) {
float fur = (noise3(p * 85.0) - 0.5) * 0.0045 * (1.0 - blurAmt * 0.75);
d += fur;
}
return d;
}
// Transform floating furniture piece in stages 2..4
vec3 floatItem(vec3 p, vec3 pivot, float seed, float weight) {
float active = smoothstep(1.2 + weight * 0.6, 3.2, u_stage);
if (active <= 0.001) return p - pivot;
// Orbit around the cat vortex in stages 3-4!
float orbitAmt = smoothstep(2.1, 3.8, u_stage);
float orbitAng = u_time * (0.9 + seed * 0.7) * orbitAmt + sin(u_time * 1.3 + seed * 6.0) * 0.15 * active;
vec3 wp = p;
wp.xz = rot2(-orbitAng * orbitAmt) * wp.xz;
vec3 targetPivot = pivot;
targetPivot.y += active * (0.35 + 0.55 * sin(u_time * 1.7 + seed * 5.0) * 0.5 + 0.45 * active) / (0.6 + weight);
// Pull slightly inward/outward in vortex
targetPivot.xz *= mix(1.0, 1.12 + 0.15 * sin(u_time + seed * 4.0), orbitAmt);
vec3 q = wp - targetPivot;
float tumble = active * (0.35 * sin(u_time * 1.5 + seed * 3.1) + orbitAmt * u_time * (1.2 + seed));
q.xy = rot2(tumble) * q.xy;
q.yz = rot2(tumble * 0.7) * q.yz;
return q;
}
// Full Scene SDF: returns vec2(distance, materialID)
vec2 mapScene(vec3 p) {
float blurAmt = u_blur;
vec2 res = vec2(1e5, 0.0);
// 1. Cat (Main)
vec3 cp = catToLocal(p);
float dCat = sdCatLocal(cp, blurAmt);
res = vec2(dCat, 1.0);
// Stage 4: Orbiting Mini Spectral Oiia Cats!
if (u_stage > 3.05) {
float cloneAppear = smoothstep(3.05, 3.65, u_stage);
float rad = mix(2.8, 1.35, cloneAppear) + 0.12 * sin(u_time * 4.0);
float ang = atan(p.z, p.x) - u_time * 2.6;
float sector = TAU / 5.0;
float id = floor((ang + sector * 0.5) / sector);
float aMod = mod(ang + sector * 0.5, sector) - sector * 0.5;
float rXZ = length(p.xz);
vec3 mp = vec3(rXZ * cos(aMod) - rad, p.y - (0.72 + 0.22 * sin(u_time * 3.5 + id * 2.1)), rXZ * sin(aMod));
mp /= (0.42 * cloneAppear + 0.001);
mp.xz = rot2(-u_spinAngle * 1.4 - id) * mp.xz;
float dMini = sdCatLocal(mp, 0.75) * (0.42 * cloneAppear + 0.001);
if (dMini < res.x) res = vec2(dMini, 1.5);
}
// Room Warp in Stage 3-4 (reality bends softly around the vortex)
vec3 rp = p;
float roomSpin = smoothstep(1.8, 3.8, u_stage);
if (roomSpin > 0.001) {
float distFromAxis = length(rp.xz);
float twist = roomSpin * 0.18 * sin(u_time * 2.0 - distFromAxis * 0.9);
rp.xz = rot2(twist) * rp.xz;
}
// 2. Floor (dips into a gravity well in stage 4)
float well = smoothstep(2.6, 3.9, u_stage) * 0.45 * exp(-dot(rp.xz, rp.xz) * 0.65);
float dFloor = rp.y + well;
// Woven round rug slightly raised (lifts like a magic saucer in stage 3-4)
float rugLift = smoothstep(2.0, 3.5, u_stage) * 0.16;
vec3 rugP = rp - vec3(0.0, rugLift - well * 0.5, -0.05);
if (u_stage > 1.8) rugP.xy = rot2(sin(u_time * 3.0) * 0.05 * roomSpin) * rugP.xy;
float dRug = sdCappedCylinder(rugP, 0.011, 1.18) - 0.004;
float dFloorAll = min(dFloor, dRug);
if (dFloorAll < res.x) {
res = vec2(dFloorAll, (dRug < dFloor) ? 2.5 : 2.0);
}
// 3. Walls & Ceiling (Room box: X in [-3.4, 3.4], Z in [-2.6, 4.5], Y in [0, 3.0])
// Back wall at Z = -2.25, Left wall with window at X = -2.85, Right wall at X = 3.1
float dBackWall = rp.z + 2.25;
float dLeftWall = rp.x + 2.85;
// Cut window opening on left wall for warm afternoon sunlight!
float winHole = sdBox(rp - vec3(-2.85, 1.55, -0.35), vec3(0.35, 0.85, 0.95));
dLeftWall = max(dLeftWall, -winHole);
float dRightWall = 3.15 - rp.x;
float dCeiling = 2.95 - rp.y;
float dWalls = min(min(dBackWall, dLeftWall), min(dRightWall, dCeiling));
// Baseboard along back & left wall
float baseboard = min(
sdBox(rp - vec3(0.0, 0.065, -2.23), vec3(3.5, 0.065, 0.022)),
sdBox(rp - vec3(-2.83, 0.065, 0.5), vec3(0.022, 0.065, 3.2))
);
dWalls = min(dWalls, baseboard);
if (dWalls < res.x) res = vec2(dWalls, (baseboard <= dWalls + 0.001) ? 3.5 : 3.0);
// 4. Cozy Mid-Century Sofa (behind cat, slightly right)
{
vec3 sp = floatItem(p, vec3(0.32, 0.0, -1.62), 0.17, 1.3);
// Bound check
float sb = length(sp - vec3(0.0, 0.45, 0.0)) - 1.55;
if (sb < res.x) {
float seat = sdRoundBox(sp - vec3(0.0, 0.24, 0.05), vec3(1.12, 0.14, 0.42), 0.05);
float back = sdRoundBox(sp - vec3(0.0, 0.56, -0.31), vec3(1.12, 0.28, 0.11), 0.055);
vec3 armP = vec3(abs(sp.x), sp.y, sp.z);
float arms = sdRoundBox(armP - vec3(1.12, 0.38, 0.02), vec3(0.10, 0.22, 0.44), 0.05);
// Cushions
float cush = sdRoundBox(vec3(abs(sp.x) - 0.52, sp.y - 0.39, sp.z - 0.06), vec3(0.49, 0.065, 0.37), 0.04);
// Throw pillow
vec3 pp = sp - vec3(-0.82, 0.54, -0.06);
pp.xy = rot2(0.28) * pp.xy;
pp.xz = rot2(0.22) * pp.xz;
float pillow = sdEllipsoid(pp, vec3(0.21, 0.20, 0.095));
// Wooden sofa legs
vec3 lp = vec3(abs(sp.x) - 1.02, sp.y - 0.06, abs(sp.z) - 0.34);
float legs = sdCappedCylinder(lp, 0.07, 0.025);
float dSofa = smin(seat, back, 0.03);
dSofa = smin(dSofa, arms, 0.03);
dSofa = min(dSofa, cush);
float dAll = min(min(dSofa, pillow), legs);
if (dAll < res.x) {
float m = 4.0;
if (pillow <= dAll + 0.001) m = 4.5;
else if (legs <= dAll + 0.001) m = 5.0;
res = vec2(dAll, m);
}
}
}
// 5. Low Wooden Coffee Table + Ceramic Mug + Art Book (left-back)
{
vec3 tp = floatItem(p, vec3(-1.18, 0.0, -0.78), 0.53, 0.65);
float tb = length(tp - vec3(0.0, 0.25, 0.0)) - 0.85;
if (tb < res.x) {
float top = sdRoundBox(tp - vec3(0.0, 0.33, 0.0), vec3(0.46, 0.022, 0.32), 0.018);
vec3 lp = vec3(abs(tp.x) - 0.36, tp.y - 0.16, abs(tp.z) - 0.22);
float legs = sdCappedCylinder(lp, 0.16, 0.018);
float dTable = min(top, legs);
if (dTable < res.x) res = vec2(dTable, 5.0);
}
// Mug (floats off earlier than table!)
vec3 mp = floatItem(p, vec3(-1.05, 0.36, -0.70), 0.88, 0.15);
float dMug = sdCappedCylinder(mp - vec3(0.0, 0.055, 0.0), 0.055, 0.045) - 0.004;
dMug = max(dMug, -sdCappedCylinder(mp - vec3(0.0, 0.07, 0.0), 0.05, 0.036));
if (dMug < res.x) res = vec2(dMug, 5.5);
// Hardcover book
vec3 bp = floatItem(p, vec3(-1.30, 0.365, -0.84), 0.31, 0.22);
bp.xz = rot2(0.35) * bp.xz;
float dBook = sdRoundBox(bp - vec3(0.0, 0.018, 0.0), vec3(0.13, 0.018, 0.17), 0.005);
if (dBook < res.x) res = vec2(dBook, 4.5);
}
// 6. Warm Floor Lamp (right-back)
{
vec3 lp = floatItem(p, vec3(1.82, 0.0, -1.42), 0.71, 0.85);
float lb = length(lp - vec3(0.0, 0.85, 0.0)) - 1.1;
if (lb < res.x) {
float base = sdCappedCylinder(lp - vec3(0.0, 0.02, 0.0), 0.02, 0.18);
float pole = sdCappedCylinder(lp - vec3(0.0, 0.78, 0.0), 0.76, 0.016);
// Tapered linen drum shade
vec3 sp = lp - vec3(0.0, 1.48, 0.0);
float shR = mix(0.23, 0.17, clamp((sp.y + 0.18) / 0.36, 0.0, 1.0));
float shade = sdCappedCylinder(sp, 0.18, shR);
shade = max(shade, -sdCappedCylinder(sp, 0.20, shR - 0.012));
float dStand = min(base, pole);
if (dStand < res.x) res = vec2(dStand, 6.0);
if (shade < res.x) res = vec2(shade, 7.0);
}
}
// 7. Potted Plant (left back corner near sunlit window) + Wall Frame
{
vec3 pp = floatItem(p, vec3(-2.12, 0.0, -1.58), 0.42, 0.75);
float pb = length(pp - vec3(0.0, 0.55, 0.0)) - 0.85;
if (pb < res.x) {
float potR = mix(0.14, 0.19, clamp(pp.y / 0.34, 0.0, 1.0));
float pot = sdCappedCylinder(pp - vec3(0.0, 0.17, 0.0), 0.17, potR) - 0.008;
if (pot < res.x) res = vec2(pot, 6.5);
// Broad tropical leaves
vec3 lf = pp - vec3(0.0, 0.46, 0.0);
float dLeaves = 1e5;
for (int i = 0; i < 5; i++) {
float fi = float(i);
vec3 q = lf;
q.xz = rot2(fi * 1.256 + 0.4) * q.xz;
q.xy = rot2(-0.55 - 0.12 * sin(fi * 2.0)) * q.xy;
float leaf = sdEllipsoid(q - vec3(0.20, 0.06, 0.0), vec3(0.22, 0.018, 0.095));
dLeaves = min(dLeaves, leaf);
}
if (dLeaves < res.x) res = vec2(dLeaves, 8.0);
}
// Framed wall art above sofa
vec3 fp = floatItem(p, vec3(0.32, 1.52, -2.21), 0.94, 0.45);
float dFrame = sdBox(fp, vec3(0.46, 0.58, 0.022));
if (dFrame < res.x) res = vec2(dFrame, 6.2);
}
return res;
}
vec3 calcNormal(vec3 p) {
vec2 e = vec2(0.0012, -0.0012);
return normalize(
e.xyy * mapScene(p + e.xyy).x +
e.yyx * mapScene(p + e.yyx).x +
e.yxy * mapScene(p + e.yxy).x +
e.xxx * mapScene(p + e.xxx).x
);
}
// Soft shadow toward sun or lamp
float calcSoftShadow(vec3 ro, vec3 rd, float mint, float maxt, float k) {
float res = 1.0;
float t = mint;
for (int i = 0; i < 28; i++) {
float h = mapScene(ro + rd * t).x;
res = min(res, k * h / t);
t += clamp(h, 0.02, 0.22);
if (res < 0.005 || t > maxt) break;
}
return clamp(res, 0.0, 1.0);
}
float calcAO(vec3 pos, vec3 nor) {
float occ = 0.0;
float sca = 1.0;
for (int i = 0; i < 5; i++) {
float h = 0.02 + 0.075 * float(i);
float d = mapScene(pos + h * nor).x;
occ += (h - d) * sca;
sca *= 0.72;
}
return clamp(1.0 - 2.4 * occ, 0.0, 1.0);
}
// Window gobo pattern (warm afternoon sunbeams coming through window panes & blinds)
float windowLightMask(vec3 p, vec3 sunDir) {
// Intersect ray from p along sunDir with left wall plane x = -2.85
if (sunDir.x >= -0.01) return 0.0;
float t = (-2.85 - p.x) / sunDir.x;
if (t < 0.0) return 0.0;
vec3 hit = p + sunDir * t;
// Window bounds: y in [0.7, 2.4], z in [-1.3, 0.6]
vec2 wuv = vec2((hit.z + 0.35) / 0.95, (hit.y - 1.55) / 0.85);
vec2 box = smoothstep(vec2(1.02), vec2(0.92), abs(wuv));
// Window mullions
float mullionZ = smoothstep(0.015, 0.045, abs(wuv.x));
float mullionY = smoothstep(0.015, 0.045, abs(wuv.y - 0.08));
// Leafy tree dapple outside window
float dapple = smoothstep(0.22, 0.72, fbm2(wuv * 2.8 + vec2(u_time * 0.04, 0.0)));
return box.x * box.y * mullionZ * mullionY * (0.55 + 0.45 * dapple);
}
// Color & Facial detail of the Oiia Cat (Cream/Ginger-Buff Saddle & Crisp White Bib/Muzzle, Giant Stare)
vec3 shadeCatAlbedo(vec3 localP, vec3 localN, float blurAmt, out float rough, out float eyeSpec) {
rough = 0.82;
eyeSpec = 0.0;
// Fine directional fur strand noise
vec3 furCoord = vec3(atan(localP.x, localP.z) * 14.0, localP.y * 95.0, length(localP.xz) * 40.0);
float strand = noise3(furCoord);
float finePatch = noise3(localP * 11.0);
vec3 whiteFur = vec3(0.95, 0.93, 0.89) * (0.93 + 0.12 * strand);
vec3 creamBuff = vec3(0.83, 0.63, 0.41) * (0.90 + 0.16 * strand);
vec3 gingerTabby = vec3(0.72, 0.47, 0.25) * (0.88 + 0.18 * strand);
// Faint mackerel stripes in the cream patches
float stripes = sin(localP.y * 52.0 + sin(localP.x * 24.0) * 1.5) * 0.5 + 0.5;
vec3 patchCol = mix(creamBuff, gingerTabby, stripes * 0.42 + finePatch * 0.25);
// Classic Oiia / Ethel bicolor markings:
// White chest, white belly, white paws, inverted-V white blaze up muzzle/nose, cream cap/ears & back saddle
float frontMask = smoothstep(-0.04, 0.09, localP.z); // white in front
// Head cap: cream over crown & ears, parting in an inverted V between the eyes
vec3 hp = localP - vec3(0.0, 0.505, 0.065);
float blazeV = smoothstep(0.015, -0.035, hp.y - abs(hp.x) * 1.35 - 0.025);
float headWhite = frontMask * blazeV;
float bodyWhite = smoothstep(-0.05, 0.08, localP.z + (0.18 - localP.y) * 0.35);
// White paws all around at bottom
float socks = 1.0 - smoothstep(0.055, 0.095, localP.y);
// Irregular organic patch edge
float edgeNoise = (finePatch - 0.5) * 0.08;
float isWhite = clamp(max(mix(bodyWhite, headWhite, smoothstep(0.36, 0.43, localP.y)) + edgeNoise, socks), 0.0, 1.0);
vec3 furCol = mix(patchCol, whiteFur, isWhite);
// Inner pink ears
vec3 hsp = vec3(abs(hp.x), hp.y, hp.z);
float inEar = smoothstep(0.055, 0.02, length(hsp - vec3(0.095, 0.155, 0.025))) * smoothstep(-0.1, 0.3, localN.z);
furCol = mix(furCol, vec3(0.89, 0.62, 0.60), inEar * 0.78);
// Cute tiny pink nose triangle
vec2 np = vec2(hp.x, hp.y + 0.028);
float noseDist = max(abs(np.x) * 1.3 - np.y * 0.7, np.y - 0.013);
float isNose = (1.0 - smoothstep(0.008, 0.014, noseDist)) * smoothstep(0.135, 0.152, hp.z) * smoothstep(-0.048, -0.038, hp.y);
furCol = mix(furCol, vec3(0.88, 0.52, 0.53), isNose);
// Tiny mouth "w" / startled "o" when singing OIIA!
float mouthOpen = u_vocalEnergy * (1.0 - blurAmt * 0.5);
float mouthDist = length((hp - vec3(0.0, -0.056, 0.145)) * vec3(1.0, 1.25 - mouthOpen * 0.45, 1.0));
float isMouth = (1.0 - smoothstep(0.008 + mouthOpen * 0.014, 0.014 + mouthOpen * 0.016, mouthDist)) * smoothstep(0.11, 0.135, hp.z);
furCol = mix(furCol, vec3(0.24, 0.09, 0.10), isMouth * (0.35 + 0.65 * mouthOpen));
// WIDE UNBLINKING STARE EYES (the heart of Oiia Cat!)
vec3 eyeCenter = vec3(0.062, 0.012, 0.124);
float dEye = length(hsp - eyeCenter);
if (dEye < 0.040 && hp.z > 0.10) {
// Dark eyeliner rim
float rim = smoothstep(0.039, 0.034, dEye);
// Warm greenish-amber iris
vec2 ep = (hsp.xy - eyeCenter.xy) / 0.034;
float rEye = length(ep);
vec3 iris = mix(vec3(0.58, 0.62, 0.26), vec3(0.32, 0.38, 0.16), smoothstep(0.35, 0.98, rEye));
//Huge dilated round meme pupil!
float pupilSize = 0.66 + 0.10 * clamp(u_stage * 0.3, 0.0, 0.25);
float pupil = 1.0 - smoothstep(pupilSize - 0.05, pupilSize + 0.03, rEye);
vec3 eyeCol = mix(iris, vec3(0.015, 0.015, 0.02), pupil);
eyeCol = mix(vec3(0.12, 0.09, 0.08), eyeCol, smoothstep(1.02, 0.88, rEye));
furCol = mix(furCol, eyeCol, rim * (1.0 - blurAmt * 0.88));
rough = mix(rough, 0.05, rim * (1.0 - blurAmt * 0.7));
eyeSpec = rim * (1.0 - blurAmt * 0.7);
}
// Azimuthal colour streak when spinning fast (horizontal cream & white motion bands!)
if (blurAmt > 0.02) {
float bandY = localP.y;
vec3 spunBand = mix(patchCol, whiteFur, smoothstep(0.46, 0.22, bandY) * 0.65 + 0.2);
// Dark eye band streak!
float eyeBand = exp(-pow((bandY - 0.517) / 0.028, 2.0)) * 0.38;
spunBand = mix(spunBand, vec3(0.22, 0.18, 0.14), eyeBand);
furCol = mix(furCol, spunBand, blurAmt * 0.84);
}
return furCol;
}
// Psychedelic / Rave / Hyperspace Aura for Escalation Stages
vec3 rainbow(float t) {
return 0.5 + 0.5 * cos(TAU * (t + vec3(0.0, 0.33, 0.67)));
}
void main() {
vec2 uv = (gl_FragCoord.xy - 0.5 * u_res) / u_res.y;
// Subtle handheld breathing at Stage 0 -> Escalating bass shake at higher stages
vec2 shake = vec2(
sin(u_time * 37.0) + cos(u_time * 53.0),
cos(u_time * 41.0) - sin(u_time * 61.0)
) * 0.0035 * u_camShake;
uv += shake;
// Camera framing: eye-level kneeling in living room, cat resting squarely in foreground
float stageZoom = smoothstep(0.0, 1.5, u_stage) * 0.15 - smoothstep(2.2, 4.0, u_stage) * 0.42;
vec3 ro = vec3(
sin(u_time * 0.45) * 0.012 + sin(u_time * 0.8) * 0.18 * smoothstep(1.8, 3.8, u_stage),
0.52 + u_lift * 0.32 + sin(u_time * 0.6) * 0.008,
2.02 - stageZoom
);
vec3 ta = vec3(0.0, 0.35 + u_lift * 0.78, 0.0);
// Slight Dutch roll in Stage 3 & 4
float dutch = sin(u_time * 2.2) * 0.09 * smoothstep(2.0, 3.9, u_stage);
vec3 ww = normalize(ta - ro);
vec3 uu = normalize(cross(ww, vec3(sin(dutch), cos(dutch), 0.0)));
vec3 vv = cross(uu, ww);
// FOV widens dramatically in Stage 4 ("warp lens")
float fov = 1.45 - 0.38 * smoothstep(2.2, 4.0, u_stage) + u_bassPulse * 0.05;
vec3 rd = normalize(uv.x * uu + uv.y * vv + fov * ww);
// Raymarch + Volumetric God-Rays / Rave Beams accumulator
float t = 0.0;
float maxT = 9.5;
vec2 hit = vec2(0.0);
bool didHit = false;
vec3 sunDir = normalize(vec3(-0.82, 0.44, 0.36)); // Warm late-afternoon sun from left window
vec3 lampPos = vec3(1.82, 1.48, -1.42);
if (u_stage > 1.7) {
// Lamp floats too!
lampPos.y += smoothstep(1.7, 3.4, u_stage) * 0.45;
}
vec3 volGlow = vec3(0.0);
float dither = hash12(gl_FragCoord.xy + fract(u_time) * 100.0);
for (int i = 0; i < 86; i++) {
vec3 p = ro + rd * t;
hit = mapScene(p);
// Accumulate subtle sunlit dust rays in calm room + crazy laser/vortex glow in higher stages
if (i % 2 == 0 && t < 5.5) {
float stepW = max(hit.x, 0.05) * 0.035;
float wMask = windowLightMask(p, sunDir);
volGlow += vec3(1.0, 0.83, 0.58) * wMask * stepW * 0.42 * (1.0 - smoothstep(2.2, 3.6, u_stage) * 0.7);
// Stage 2+: Swirling energy vortex & laser beams around cat
if (u_stage > 1.15) {
float raveAmt = smoothstep(1.15, 2.8, u_stage);
float cylDist = length(p.xz);
float ang = atan(p.z, p.x);
float laser = pow(max(0.0, sin(ang * 6.0 - u_time * 9.0 + p.y * 2.5)), 12.0);
vec3 beamCol = rainbow(ang / TAU - u_time * 0.6 + p.y * 0.2);
float ringGlow = exp(-abs(cylDist - (0.55 + 0.35 * sin(p.y * 3.0 - u_time * 6.0))) * 4.5);
volGlow += beamCol * (laser * 0.65 + ringGlow * 0.45) * stepW * raveAmt * (0.7 + 0.8 * u_vocalEnergy) / (0.35 + cylDist * 0.6);
}
}
if (hit.x < 0.0014 * (1.0 + t * 0.35)) {
didHit = true;
break;
}
t += hit.x * (0.86 + 0.06 * dither);
if (t > maxT) break;
}
vec3 col = vec3(0.0);
if (!didHit) {
// Bright blown-out afternoon exterior seen through window, or cosmic hyperspace in Stage 4!
vec3 daySky = mix(vec3(1.4, 1.25, 1.02), vec3(0.85, 1.05, 1.25), clamp(rd.y * 1.5, 0.0, 1.0));
if (u_stage > 2.5) {
float warp = smoothstep(2.5, 3.9, u_stage);
float a = atan(rd.y, rd.x) + u_time * 2.5;
vec3 hyper = rainbow(a / TAU + length(rd.xy) * 2.0 - u_time * 1.2) * (0.8 + 0.6 * sin(length(rd.xy) * 30.0 - u_time * 18.0));
daySky = mix(daySky, hyper * 1.6, warp);
}
col = daySky;
} else {
vec3 p = ro + rd * t;
vec3 n = calcNormal(p);
vec3 v = -rd;
float m = hit.y;
vec3 albedo = vec3(0.5);
float rough = 0.7;
float emissive = 0.0;
float eyeSpec = 0.0;
bool isCat = false;
if (m < 1.8) {
// Main Cat (1.0) or Stage 4 Spectral Mini Cat (1.5)
isCat = true;
vec3 lp = (m < 1.2) ? catToLocal(p) : vec3(0.0, 0.3, 0.15);
vec3 ln = n;
ln.xz = rot2(-u_spinAngle) * ln.xz;
if (m > 1.2) {
albedo = mix(vec3(0.95, 0.85, 0.72), rainbow(u_time * 0.8 + p.y), 0.55);
rough = 0.4;
emissive = 0.45;
} else {
albedo = shadeCatAlbedo(lp, ln, u_blur, rough, eyeSpec);
}
} else if (m < 2.2) {
// Realistic Oak Hardwood Planks
vec2 fuv = p.xz;
float plankW = 0.21;
float plankId = floor(fuv.x / plankW);
float plankZ = fuv.y + hash12(vec2(plankId, 3.1)) * 2.4;
float boardId = floor(plankZ / 1.45);
vec2 seam = abs(vec2(fract(fuv.x / plankW) - 0.5, fract(plankZ / 1.45) - 0.5));
float groove = smoothstep(0.47, 0.495, seam.x) + smoothstep(0.492, 0.499, seam.y);
float grain = fbm2(vec2(fuv.x * 26.0, plankZ * 3.8 + plankId * 7.1));
float rings = sin(grain * 18.0 + fuv.x * 45.0) * 0.5 + 0.5;
float toneVar = hash12(vec2(plankId, boardId)) * 0.16;
albedo = mix(vec3(0.34, 0.21, 0.11), vec3(0.48, 0.31, 0.17), grain * 0.65 + rings * 0.25 + toneVar);
albedo *= (1.0 - groove * 0.55);
rough = clamp(0.28 + grain * 0.22 + groove * 0.4, 0.18, 0.85);
} else if (m < 2.8) {
// Textured Bouclé Cream/Oatmeal Area Rug
float r = length(p.xz - vec2(0.0, -0.05));
float weave = noise3(vec3(p.x * 110.0, 0.0, p.z * 110.0));
float braid = sin(r * 85.0) * 0.5 + 0.5;
albedo = mix(vec3(0.68, 0.63, 0.56), vec3(0.78, 0.74, 0.67), weave * 0.6 + braid * 0.3);
// Subtle terracotta border ring
float border = smoothstep(0.04, 0.01, abs(r - 1.04));
albedo = mix(albedo, vec3(0.56, 0.34, 0.25), border * 0.65);
rough = 0.94;
} else if (m < 3.2) {
// Warm plaster walls (and Stage 4 portal ripples!)
float plaster = fbm2(p.xy * 4.5 + p.zy * 3.0);
albedo = vec3(0.84, 0.80, 0.74) * (0.96 + 0.06 * plaster);
rough = 0.88;
if (u_stage > 2.4) {
float portal = smoothstep(2.4, 3.85, u_stage);
float rad = length(p.xy - vec2(0.0, 1.1));
float ang = atan(p.y - 1.1, p.x);
vec3 hyp = rainbow(rad * 0.45 - u_time * 1.3 + sin(ang * 4.0 + u_time * 3.0) * 0.15);
float grid = smoothstep(0.92, 0.99, max(sin(p.x * 8.0 + u_time * 2.0), sin(p.y * 8.0 - u_time * 3.0)));
albedo = mix(albedo, hyp * (0.45 + 0.55 * grid), portal * 0.82);
emissive = portal * 0.65;
}
} else if (m < 3.8) {
// Painted off-white trim/baseboard
albedo = vec3(0.90, 0.88, 0.84);
rough = 0.45;
} else if (m < 4.3) {
// Olive-sage woven linen sofa
float fab = noise3(p * 75.0);
albedo = vec3(0.30, 0.35, 0.29) * (0.92 + 0.16 * fab);
rough = 0.90;
} else if (m < 4.8) {
// Terracotta accent pillow / book
albedo = vec3(0.68, 0.34, 0.22) * (0.93 + 0.14 * noise3(p * 60.0));
rough = 0.85;
} else if (m < 5.3) {
// Walnut wood furniture
float g = fbm2(p.xz * 12.0 + p.xy * 6.0);
albedo = mix(vec3(0.22, 0.13, 0.07), vec3(0.34, 0.20, 0.11), g);
rough = 0.38;
} else if (m < 5.8) {
// Ceramic mug
albedo = vec3(0.90, 0.87, 0.82);
rough = 0.16;
} else if (m < 6.1) {
// Brushed brass lamp stand
albedo = vec3(0.72, 0.56, 0.30);
rough = 0.26;
} else if (m < 6.35) {
// Framed wall print
vec3 fp = floatItem(p, vec3(0.32, 1.52, -2.21), 0.94, 0.45);
bool inner = abs(fp.x) < 0.41 && abs(fp.y) < 0.53 && fp.z > 0.015;
if (inner) {
float artCircle = smoothstep(0.24, 0.23, length(fp.xy - vec2(0.0, 0.04)));
albedo = mix(vec3(0.91, 0.87, 0.80), vec3(0.72, 0.38, 0.24), artCircle);
rough = 0.65;
} else {
albedo = vec3(0.24, 0.15, 0.09);
rough = 0.4;
}
} else if (m < 6.8) {
// Terracotta plant pot
albedo = vec3(0.62, 0.35, 0.23);
rough = 0.78;
} else if (m < 7.5) {
// Warm glowing linen lamp shade
albedo = vec3(1.0, 0.86, 0.64);
rough = 0.8;
emissive = 1.35;
} else {
// Deep Monstera/Ficus green leaves
albedo = vec3(0.14, 0.28, 0.13) * (0.9 + 0.2 * noise3(p * 20.0));
rough = 0.42;
}
// --- Physically Inspired Room Lighting ---
float ao = calcAO(p, n);
// 1. Key Light: Warm afternoon sunlight streaming through left window
float winMask = windowLightMask(p, sunDir);
float ndlSun = max(dot(n, sunDir), 0.0);
float sunVis = (ndlSun > 0.001 && winMask > 0.01) ? calcSoftShadow(p + n * 0.004, sunDir, 0.02, 5.0, 14.0) : 0.0;
vec3 sunCol = vec3(1.55, 1.24, 0.92) * winMask * sunVis;
// 2. Warm Floor Lamp Point Light
vec3 toLamp = lampPos - p;
float lampDist = length(toLamp);
vec3 lampDir = toLamp / max(lampDist, 0.001);
float lampAtten = 1.0 / (1.0 + 0.45 * lampDist * lampDist);
float lampShad = calcSoftShadow(p + n * 0.004, lampDir, 0.02, lampDist - 0.22, 8.0);
vec3 lampCol = vec3(1.15, 0.76, 0.42) * lampAtten * (0.35 + 0.65 * lampShad);
// 3. Cool Skylight / Room Bounce GI + Warm Floor Bounce
vec3 skyBounce = mix(vec3(0.22, 0.17, 0.13), vec3(0.26, 0.30, 0.36), 0.5 + 0.5 * n.y);
// Window area soft fill
vec3 winCenterDir = normalize(vec3(-2.85, 1.5, -0.3) - p);
float winFill = max(dot(n, winCenterDir), 0.0) / (1.0 + 0.12 * dot(vec3(-2.85, 1.5, -0.3) - p, vec3(-2.85, 1.5, -0.3) - p));
vec3 ambient = (skyBounce * 0.65 + vec3(0.45, 0.44, 0.46) * winFill * 0.85) * ao;
// Contact shadow directly under cat on the rug (grounds the opening frame!)
if (!isCat && p.y < 0.04) {
float catGroundDist = length(p.xz);
float contactFade = 1.0 / (1.0 + u_lift * 4.5);
float cOcc = 1.0 - 0.68 * exp(-catGroundDist * catGroundDist * 16.0) * contactFade;
ambient *= cOcc;
sunCol *= mix(1.0, cOcc, 0.5);
}
// Stage 2..4 Dynamic Rave / Rainbow Vortex Under-Light from the Spinning Cat!
vec3 raveLight = vec3(0.0);
if (u_stage > 0.75) {
vec3 catCenter = vec3(0.0, 0.32 + u_lift, 0.0);
vec3 toCat = catCenter - p;
float cd = length(toCat);
vec3 cDir = toCat / max(cd, 0.001);
float ravePower = smoothstep(0.75, 2.8, u_stage) * (0.8 + 0.9 * u_vocalEnergy);
float discoAngle = atan(p.z, p.x) - u_spinAngle * 0.5;
vec3 discoCol = rainbow(discoAngle / TAU + u_time * 0.4);
// Project rotating club gobos onto walls & floor
float gobo = 0.55 + 0.45 * sin(discoAngle * 5.0 + p.y * 4.0);
raveLight = discoCol * gobo * ravePower * max(dot(n, cDir) * 0.6 + 0.4, 0.0) / (0.6 + cd * cd * 0.55);
}
// Diffuse + Specular + Fur Rim Sheen
vec3 diff = albedo * (ambient + sunCol * ndlSun + lampCol * max(dot(n, lampDir), 0.0) + raveLight);
// GGX-ish Specular
vec3 hSun = normalize(sunDir + v);
vec3 hWin = normalize(winCenterDir + v);
float specPow = mix(180.0, 6.0, rough * rough);
float specNorm = (specPow + 2.0) * 0.04;
float fresnel = pow(1.0 - max(dot(n, v), 0.0), 5.0);
float f0 = (eyeSpec > 0.1) ? 0.06 : 0.03;
float F = f0 + (1.0 - f0) * fresnel * (1.0 - rough * 0.7);
vec3 spec = sunCol * pow(max(dot(n, hSun), 0.0), specPow) * specNorm * F * 2.0;
spec += vec3(0.95, 0.96, 1.0) * winFill * pow(max(dot(n, hWin), 0.0), specPow * 0.5) * specNorm * F * 2.5;
// Crisp realistic window catchlights in the cat's wide eyes!
if (eyeSpec > 0.05) {
vec3 eyeRefl = reflect(-v, n);
// Primary sunlit window catchlight (upper-left)
float catch1 = smoothstep(0.93, 0.985, dot(eyeRefl, normalize(vec3(-0.55, 0.52, 0.65))));
// Secondary warm lamp catchlight
float catch2 = smoothstep(0.965, 0.992, dot(eyeRefl, normalize(vec3(0.55, 0.35, 0.75))));
spec += (vec3(2.4, 2.35, 2.25) * catch1 + vec3(1.6, 1.1, 0.7) * catch2) * eyeSpec;
}
// Soft backlit fur rim-scatter on the cat (makes fur read fuzzy, not plastic!)
if (isCat) {
float rim = pow(1.0 - max(dot(n, v), 0.0), 3.2);
float sunBack = max(dot(-sunDir, v), 0.0) * 0.5 + 0.5;
diff += albedo * vec3(1.15, 0.95, 0.75) * rim * 0.42 * ao * sunBack;
if (u_stage > 1.5) {
diff += rainbow(u_time * 1.1 + p.y) * rim * smoothstep(1.5, 3.5, u_stage) * (0.6 + u_vocalEnergy);
}
}
col = diff + spec + albedo * emissive;
// Floor subtle planar reflection bounce on polished oak planks
if (m > 1.9 && m < 2.2) {
vec3 reflDir = reflect(rd, n);
float flWin = windowLightMask(p, reflDir);
col += vec3(0.55, 0.48, 0.40) * flWin * F * 0.85;
}
}
// Add volumetric dust / rave beams
col += volGlow;
// Stage 3 & 4 Radial Speed-Lines at Screen Edges (never blinding, keeps center sharp!)
if (u_stage > 2.1) {
float edgeDist = length(uv);
float speedAmt = smoothstep(2.1, 3.9, u_stage) * smoothstep(0.28, 0.82, edgeDist);
float sAng = atan(uv.y, uv.x);
float streaks = pow(0.5 + 0.5 * sin(sAng * 38.0 + sin(u_time * 24.0) * 3.0), 8.0);
col += rainbow(sAng / TAU + u_time * 1.5) * streaks * speedAmt * (0.35 + 0.45 * u_vocalEnergy);
}
// ACES Filmic Tone Mapping
col *= 0.92;
col = (col * (2.51 * col + 0.03)) / (col * (2.43 * col + 0.59) + 0.14);
col = clamp(col, 0.0, 1.0);
// Subtle photographic vignette + warm film grain in Stage 0
float vig = 1.0 - 0.28 * dot(uv, uv);
col *= clamp(vig, 0.0, 1.0);
// Gamma
col = pow(col, vec3(1.0 / 2.2));
// Tiny photographic sensor grain so the opening frame feels like a real camera exposure
float grain = (hash12(gl_FragCoord.xy + fract(u_time * 17.3) * 100.0) - 0.5) * 0.022;
col += grain;
fragColor = vec4(col, 1.0);
}`;
function compileShader(type, src) {
const sh = gl.createShader(type);
gl.shaderSource(sh, src);
gl.compileShader(sh);
if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS)) {
console.error(gl.getShaderInfoLog(sh));
}
return sh;
}
const prog = gl.createProgram();
gl.attachShader(prog, compileShader(gl.VERTEX_SHADER, vsSource));
gl.attachShader(prog, compileShader(gl.FRAGMENT_SHADER, fsSource));
gl.linkProgram(prog);
gl.useProgram(prog);
const quadBuf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, quadBuf);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, -1,1, 1,-1, 1,1]), gl.STATIC_DRAW);
const aPos = gl.getAttribLocation(prog, 'a_pos');
gl.enableVertexAttribArray(aPos);
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);
const locs = {
res: gl.getUniformLocation(prog, 'u_res'),
time: gl.getUniformLocation(prog, 'u_time'),
stage: gl.getUniformLocation(prog, 'u_stage'),
stageInt: gl.getUniformLocation(prog, 'u_stageInt'),
spinAngle: gl.getUniformLocation(prog, 'u_spinAngle'),
spinSpeed: gl.getUniformLocation(prog, 'u_spinSpeed'),
lift: gl.getUniformLocation(prog, 'u_lift'),
blur: gl.getUniformLocation(prog, 'u_blur'),
vocalEnergy: gl.getUniformLocation(prog, 'u_vocalEnergy'),
bassPulse: gl.getUniformLocation(prog, 'u_bassPulse'),
camShake: gl.getUniformLocation(prog, 'u_camShake')
};
function resize() {
// Cap pixel ratio slightly for smooth 60fps raymarching while staying crisp
const dpr = Math.min(window.devicePixelRatio || 1, 1.65);
canvas.width = Math.floor(window.innerWidth * dpr);
canvas.height = Math.floor(window.innerHeight * dpr);
gl.viewport(0, 0, canvas.width, canvas.height);
}
window.addEventListener('resize', resize);
resize();
// ---------- STATE & PHYSICS ----------
let targetStage = 0; // 0 = sitting photo, 1..4 = escalating meme stages
let smoothStage = 0;
let spinAngle = 0; // starts at 0 facing camera squarely
let spinSpeed = 0; // rad/s
let lift = 0;
let vocalEnergy = 0;
let bassPulse = 0;
let isMuted = false;
const STAGE_NAMES = [
'',
'Stage 1 · OIIA Spin',
'Stage 2 · Anti-Gravity Groove',
'Stage 3 · Vortex Rave',
'Stage 4 · OIIA Singularity'
];
// ---------- WEB AUDIO FORMANT VOICE + RAVE SYNTHESIZER ----------
// Synthesizes the iconic nasal "o-i-i-a, o-i-i-a, o-i-i-a-i-o-o-o-o-i-a-i" vocal loop
// using a glottal sawtooth/pulse source routed through 3 parallel resonant vocal-tract formant filters!
let audioCtx = null;
let masterGain = null;
let glottalSaw = null;
let glottalSub = null;
let aspirationGain = null;
let voiceAmp = null;
let formants = [];
let beatClock = 0;
let stepAccum = 0;
let currentStep = 0;
// Vowel Formants [F1, F2, F3] in Hz (tuned slightly bright/compressed like the viral meme sample)
const VOWELS = {
O: [440, 860, 2550], // rounded "oh"
I: [300, 2320, 3050], // bright pinched "ee"
A: [780, 1280, 2600], // open nasal "ah"
U: [350, 740, 2450], // tight "oo"
_: [400, 1200, 2500] // brief articulation dip / rest
};
// Classic 32-step "oiia oiia | oiiaiooooiai" meme phrase!
// Each entry: [vowelKey, semitoneOffset, gateStrength]
const PHRASE = [
// "o - i - i - a"
['O', 0, 1.0], ['I', 2, 0.95], ['I', 2, 0.92], ['A', 0, 1.0],
['A', -1, 0.55], ['_', 0, 0.06],
// "o - i - i - a"
['O', 0, 1.0], ['I', 2, 0.95], ['I', 3, 0.95], ['A', 0, 1.0],
['A', -1, 0.55], ['_', 0, 0.06],
// "o - i - i - a - i - o - o - o - o - i - a - i"
['O', 0, 1.0], ['I', 3, 0.96], ['I', 3, 0.92], ['A', 2, 1.0],
['I', 5, 0.98], ['O', 3, 1.0], ['O', 2, 0.96], ['U', 0, 0.94],
['O', 0, 0.96], ['I', 3, 0.98], ['A', 2, 1.0], ['I', 5, 0.95],
['A', 0, 0.85], ['_', 0, 0.05]
];
function initAudio() {
if (audioCtx) {
if (audioCtx.state === 'suspended') audioCtx.resume();
return;
}
const AC = window.AudioContext || window.webkitAudioContext;
audioCtx = new AC();
masterGain = audioCtx.createGain();
masterGain.gain.value = isMuted ? 0.0 : 0.72;
// Gentle compressor so stage 4 rave + voice stays punchy and never clips harshly
const comp = audioCtx.createDynamicsCompressor();
comp.threshold.value = -14;
comp.knee.value = 12;
comp.ratio.value = 5;
comp.attack.value = 0.004;
comp.release.value = 0.12;
masterGain.connect(comp);
comp.connect(audioCtx.destination);
// Glottal vocal cord source (rich harmonics + subtle warmth)
glottalSaw = audioCtx.createOscillator();
glottalSaw.type = 'sawtooth';
glottalSaw.frequency.value = 185;
glottalSub = audioCtx.createOscillator();
glottalSub.type = 'square';
glottalSub.frequency.value = 185;
const subMix = audioCtx.createGain();
subMix.gain.value = 0.28;
glottalSub.connect(subMix);
// Consonant / breathiness noise burst
const nBuf = audioCtx.createBuffer(1, audioCtx.sampleRate, audioCtx.sampleRate);
const nData = nBuf.getChannelData(0);
for (let i = 0; i < nData.length; i++) nData[i] = Math.random() * 2 - 1;
const noiseSrc = audioCtx.createBufferSource();
noiseSrc.buffer = nBuf;
noiseSrc.loop = true;
aspirationGain = audioCtx.createGain();
aspirationGain.gain.value = 0.05;
noiseSrc.connect(aspirationGain);
// Pre-emphasis filter for crisp vocal cord buzz
const glottalTilt = audioCtx.createBiquadFilter();
glottalTilt.type = 'lowpass';
glottalTilt.frequency.value = 3800;
glottalSaw.connect(glottalTilt);
subMix.connect(glottalTilt);
aspirationGain.connect(glottalTilt);
voiceAmp = audioCtx.createGain();
voiceAmp.gain.value = 0.0;
// Meme telephone/TikTok slight saturation & mid-presence
const shaper = audioCtx.createWaveShaper();
const curve = new Float32Array(256);
for (let i = 0; i < 256; i++) {
const x = (i / 127.5) - 1;
curve[i] = Math.tanh(x * 2.1);
}
shaper.curve = curve;
// 3 Parallel Bandpass Formant Resonators
const qs = [6.5, 9.0, 11.0];
const gains = [1.0, 0.82, 0.38];
for (let i = 0; i < 3; i++) {
const bp = audioCtx.createBiquadFilter();
bp.type = 'bandpass';
bp.frequency.value = VOWELS.O[i];
bp.Q.value = qs[i];
const fg = audioCtx.createGain();
fg.gain.value = gains[i];
glottalTilt.connect(bp);
bp.connect(fg);
fg.connect(shaper);
formants.push(bp);
}
shaper.connect(voiceAmp);
voiceAmp.connect(masterGain);
glottalSaw.start();
glottalSub.start();
noiseSrc.start();
}
// Trigger punchy electronic kick + euphoric Eurodance/Hyperpop rave chord stabs in Stages 2..4
function triggerRaveBeat(beatIdx, stageVal, pitchScale) {
if (!audioCtx || stageVal < 1.6) return;
const now = audioCtx.currentTime;
// 4-on-the-floor Kick in Stage 2+
if (beatIdx % 2 === 0) {
const osc = audioCtx.createOscillator();
const g = audioCtx.createGain();
osc.type = 'sine';
const punch = Math.min((stageVal - 1.4) * 0.42, 0.48);
osc.frequency.setValueAtTime(155, now);
osc.frequency.exponentialRampToValueAtTime(44, now + 0.09);
g.gain.setValueAtTime(punch, now);
g.gain.exponentialRampToValueAtTime(0.001, now + 0.18);
osc.connect(g);
g.connect(masterGain);
osc.start(now);
osc.stop(now + 0.19);
bassPulse = Math.min(1.0, punch * 1.9);
}
// Off-beat crisp hi-hat & rave supersaw arp in Stage 3 & 4!
if (stageVal >= 2.6) {
if (beatIdx % 2 === 1) {
// Offbeat Eurodance bass/lead stab
const notes = [220, 261.63, 329.63, 392.00, 440, 523.25];
const freq = notes[(beatIdx * 2 + (stageVal > 3.5 ? 2 : 0)) % notes.length] * (stageVal > 3.5 ? 1.25 : 1.0);
[-5, 5].forEach(det => {
const s = audioCtx.createOscillator();
const sg = audioCtx.createGain();
const sf = audioCtx.createBiquadFilter();
s.type = 'sawtooth';
s.frequency.value = freq;
s.detune.value = det;
sf.type = 'lowpass';
sf.frequency.setValueAtTime(2800, now);
sf.frequency.exponentialRampToValueAtTime(600, now + 0.14);
const vol = Math.min((stageVal - 2.4) * 0.085, 0.13);
sg.gain.setValueAtTime(vol, now);
sg.gain.exponentialRampToValueAtTime(0.001, now + 0.15);
s.connect(sf);
sf.connect(sg);
sg.connect(masterGain);
s.start(now);
s.stop(now + 0.16);
});
}
}
}
function updateAudio(dt) {
if (!audioCtx) return;
const now = audioCtx.currentTime;
if (targetStage === 0 && spinSpeed < 0.35) {
voiceAmp.gain.setTargetAtTime(0.0, now, 0.05);
vocalEnergy *= 0.85;
return;
}
// LOCK VOICE DIRECTLY TO SPIN SPEED!
// As spinSpeed climbs from ~2 rad/s up to ~48 rad/s, syllable rate & fundamental pitch & formant shift all climb together!
const normSpin = Math.min(spinSpeed / 36.0, 1.45);
const syllablesPerSec = 3.2 + spinSpeed * 0.46; // rides directly with angular velocity!
stepAccum += dt * syllablesPerSec;
if (stepAccum >= 1.0) {
const adv = Math.floor(stepAccum);
stepAccum -= adv;
currentStep = (currentStep + adv) % PHRASE.length;
const [vKey, semi, gate] = PHRASE[currentStep];
const baseVowel = VOWELS[vKey];
// Pitch climbs with spin speed (the iconic pitched-up chipmunk/rave Oiia escalation)
const baseHz = 162 * Math.pow(2, normSpin * 1.12 + semi / 12.0);
const glide = Math.max(0.008, 0.032 - normSpin * 0.018);
glottalSaw.frequency.setTargetAtTime(baseHz, now, glide);
glottalSub.frequency.setTargetAtTime(baseHz * 0.5, now, glide);
// Formant frequencies scale slightly upward as the voice pitches up (head-size shift so it stays intelligible as "o-i-i-a"!)
const formantScale = 1.0 + normSpin * 0.28;
for (let i = 0; i < 3; i++) {
formants[i].frequency.setTargetAtTime(baseVowel[i] * formantScale, now, glide * 0.85);
}
// Syllabic articulation envelope so "o-i-i-a" pops as distinct syllables instead of a flat drone
const ampTarget = gate * Math.min(spinSpeed / 4.5, 1.0) * 0.52;
voiceAmp.gain.cancelScheduledValues(now);
voiceAmp.gain.setValueAtTime(ampTarget * 0.45, now);
voiceAmp.gain.linearRampToValueAtTime(ampTarget, now + 0.012);
voiceAmp.gain.setTargetAtTime(ampTarget * 0.58, now + 0.025, 0.035);
aspirationGain.gain.setTargetAtTime(vKey === 'I' ? 0.08 : 0.03, now, 0.015);
vocalEnergy = gate;
} else {
// Subtle vibrato on sustained vowels
vocalEnergy = Math.max(0.0, vocalEnergy - dt * 3.2);
}
// Rave beat clock synced to escalation
if (smoothStage > 1.5) {
const bpm = 128 + smoothStage * 16;
beatClock += dt * (bpm / 60) * 2.0; // eighth notes
if (beatClock >= 1.0) {
const bIdx = Math.floor(performance.now() / 100) | 0;
beatClock -= Math.floor(beatClock);
triggerRaveBeat(currentStep, smoothStage, normSpin);
}
}
}
// ---------- INTERACTION ----------
function updateUI() {
if (targetStage === 0) {
stagePill.classList.remove('visible');
resetBtn.style.display = 'none';
} else {
stagePill.textContent = STAGE_NAMES[targetStage];
stagePill.classList.add('visible');
resetBtn.style.display = 'block';
hintEl.style.opacity = targetStage < 4 ? '0.42' : '0.0';
if (targetStage === 1) hintEl.textContent = 'Click again to go further';
else if (targetStage === 2) hintEl.textContent = 'Click again — break gravity';
else if (targetStage === 3) hintEl.textContent = 'One more click for maximum OIIA';
}
}
canvas.addEventListener('pointerdown', (e) => {
initAudio();
hintEl.style.opacity = '0';
if (targetStage < 4) {
targetStage++;
// Give an immediate satisfying spin & bounce kick on click
spinSpeed += 3.2 + targetStage * 2.4;
bassPulse = 0.85;
} else {
// Clicking again in Stage 4 triggers a turbo burst!
spinSpeed += 14.0;
bassPulse = 1.0;
}
updateUI();
});
muteBtn.addEventListener('click', (e) => {
e.stopPropagation();
isMuted = !isMuted;
muteBtn.textContent = isMuted ? 'Sound: Muted' : 'Sound: On';
if (masterGain && audioCtx) {
masterGain.gain.setTargetAtTime(isMuted ? 0.0 : 0.72, audioCtx.currentTime, 0.04);
}
});
resetBtn.addEventListener('click', (e) => {
e.stopPropagation();
targetStage = 0;
hintEl.textContent = 'Click the cat';
hintEl.style.opacity = '0.5';
updateUI();
});
// ---------- MAIN LOOP ----------
let lastT = performance.now();
function frame(nowMs) {
const dt = Math.min((nowMs - lastT) / 1000, 0.05);
lastT = nowMs;
const tSec = nowMs * 0.001;
// Target physics per stage:
// Stage 0: Quiet, realistic sitting cat on the living room rug
// Stage 1: Lifts into midair, accelerates into the classic blurry OIIA spin
// Stage 2: Higher hover, colorful disco gobos & bass kick, mug/book/table start losing gravity
// Stage 3: Full Living-Room Vortex — sofa, plant, lamp levitate & orbit, rave lasers & supersaws erupt
// Stage 4: OIIA Singularity — warp-lens hyperspace room bend, floor gravity-well, 5 spectral mini Oiia cats orbiting in formation!
const targetSpeeds = [0.0, 15.5, 25.0, 36.0, 52.0];
const targetLifts = [0.0, 0.34, 0.56, 0.74, 0.88];
smoothStage += (targetStage - smoothStage) * Math.min(1.0, dt * 2.2);
const desiredSpeed = targetSpeeds[targetStage];
if (targetStage === 0) {
// Smoothly decelerate and settle squarely facing camera (angle mod TAU -> 0)
spinSpeed *= Math.pow(0.18, dt);
if (spinSpeed < 1.8) {
const rem = ((spinAngle % (Math.PI * 2)) + Math.PI * 2) % (Math.PI * 2);
const shortest = rem > Math.PI ? rem - Math.PI * 2 : rem;
spinAngle -= shortest * Math.min(1.0, dt * 6.0);
if (Math.abs(shortest) < 0.01) spinSpeed = 0;
}
} else {
// Wind up smoothly like the meme edit accelerating into a blur
const accelRate = targetStage === 1 ? 1.35 : 2.4;
spinSpeed += (desiredSpeed - spinSpeed) * Math.min(1.0, dt * accelRate);
}
spinAngle += spinSpeed * dt;
lift += (targetLifts[targetStage] - lift) * Math.min(1.0, dt * 2.6);
bassPulse = Math.max(0.0, bassPulse - dt * 4.5);
updateAudio(dt);
const blurAmt = Math.min(1.0, Math.max(0.0, (spinSpeed - 10.0) / 24.0));
const camShake = Math.max(0.0, (smoothStage - 1.2) * 0.45) + bassPulse * 0.55 * (targetStage > 0 ? 1 : 0);
gl.uniform2f(locs.res, canvas.width, canvas.height);
gl.uniform1f(locs.time, tSec);
gl.uniform1f(locs.stage, smoothStage);
gl.uniform1i(locs.stageInt, targetStage);
gl.uniform1f(locs.spinAngle, spinAngle);
gl.uniform1f(locs.spinSpeed, spinSpeed);
gl.uniform1f(locs.lift, lift);
gl.uniform1f(locs.blur, blurAmt);
gl.uniform1f(locs.vocalEnergy, vocalEnergy);
gl.uniform1f(locs.bassPulse, bassPulse);
gl.uniform1f(locs.camShake, camShake);
gl.drawArrays(gl.TRIANGLES, 0, 6);
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
})();
</script>
</body>
</html>
BiquadFilterNode bandpasses tuned to the $F_1, F_2, F_3$ vocal-tract formants for /o/, /i/, /a/, and /u/ with soft waveshaper saturation, while both the syllable sequencer clock rate and the fundamental/formant frequencies are driven directly as functions of spinSpeed so the voice audibly winds up and winds down as the physical spin itself.