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
22:14GPT-6.1 Terra Pro vs Terra: How Much Better Is Pro?
Oct 27, 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
You write simulations where the interesting behavior is supposed to come out of the dice rather than be animated by hand.
Build me a single HTML page: a Starbucks-style coffee shop running a bizarre promotion, simulated live.
data: URIs are fine.localStorage, sessionStorage, cookies or indexedDB — sandboxed frame, they throw.html block.One paragraph, before the file. Given your own timings — how long a customer stays inside holding a drink, how fast the counter serves — roughly how many customers should pass through between catastrophes? Show the working, not just the number.
The single fenced html block.
Having written it, what does the page do in its first few minutes? Name anything you tuned, special-cased or nudged. Say what it does badly — I am going to leave it running and watch the counters.
The counter serves one drink at a time; with the walk-up and hand-off it clears a customer roughly every 2.5 s, so throughput ≈ 0.4 customers/s. Each drink is independently a Neon Unicorn with p = 1/6, so unicorns are "born" at μ = 0.4 × 1/6 ≈ 0.067 per second (one every ~15 s). A customer holds their (possibly unicorn) drink inside for about 9–10 s from hand-off to exit. The number of unicorns simultaneously inside is therefore roughly Poisson with mean ρ = μ × hold ≈ 0.067 × 9 ≈ 0.6. A catastrophe needs a third unicorn present at once — the in-shop unicorn count rising from 2 to 3. Since arrivals are Poisson, PASTA says that up-crossing happens at rate P(N=2) × μ, where P(N=2) = e^(−ρ)·ρ²/2 ≈ e^(−0.6)·0.18 ≈ 0.10. So the catastrophe rate ≈ 0.10 × 0.067 ≈ 0.0066 per second — a mean gap of ~150 s (about 2½ minutes at 1×), during which ~0.4 × 150 ≈ 60 customers pass through. That's a mean only: the gaps are roughly exponential, so expect clusters and droughts (anywhere from ~20 s to several minutes). Nothing is loaded — the only trigger is three unicorns in the room.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Neon Unicorn Frappuccino — Live</title>
<style>
:root{
--bg:#070a10; --panel:rgba(10,16,26,.74); --line:rgba(120,200,255,.18);
--neon:#39ff9e; --pink:#ff2fd6; --cyan:#37e6ff; --ink:#dfe8f2; --dim:#8aa0b6;
}
*{box-sizing:border-box}
html,body{margin:0;height:100%}
body{
background:radial-gradient(1200px 700px at 50% -10%, #101a2b 0%, var(--bg) 60%);
color:var(--ink); font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
display:flex; align-items:center; justify-content:center; min-height:100%;
padding:14px; overflow:hidden;
}
#stage{position:relative; width:min(96vw,1000px);}
canvas{
display:block; width:100%; height:auto; border-radius:16px;
background:#05070c;
box-shadow:0 0 0 1px var(--line), 0 24px 70px rgba(0,0,0,.6),
0 0 60px rgba(57,255,158,.10);
}
.mono{font-family:ui-monospace,"SF Mono",Menlo,Consolas,monospace;font-variant-numeric:tabular-nums}
#panel{
position:absolute; top:12px; left:12px; width:268px;
background:var(--panel); backdrop-filter:blur(7px);
border:1px solid var(--line); border-radius:13px; padding:11px 12px;
font-size:12.5px; box-shadow:0 8px 30px rgba(0,0,0,.45);
}
#panel .title{font-weight:700; letter-spacing:.3px; margin-bottom:8px; font-size:13px}
#panel .title em{color:var(--dim); font-style:normal; font-weight:500}
#panel .grid{display:grid; grid-template-columns:1fr auto; gap:3px 10px; align-items:baseline}
#panel .grid span{color:var(--dim)}
#panel .grid b{text-align:right}
#panel small{color:var(--dim); font-weight:400}
.neon{color:var(--neon); text-shadow:0 0 10px rgba(57,255,158,.6)}
.pink{color:var(--pink); text-shadow:0 0 10px rgba(255,47,214,.6)}
.ratewrap{margin-top:9px; border-top:1px solid var(--line); padding-top:8px}
.ratelabel{display:flex; justify-content:space-between; align-items:baseline; margin-bottom:5px}
.ratelabel b{color:var(--cyan)}
.ratebar{position:relative; height:9px; border-radius:6px; background:rgba(255,255,255,.07); overflow:hidden}
#rateFill{position:absolute; left:0; top:0; bottom:0; width:0%;
background:linear-gradient(90deg,#1e7a4f,var(--neon)); border-radius:6px; transition:width .18s}
.truemark{position:absolute; top:-2px; bottom:-2px; left:41.6%; width:2px; background:var(--pink);
box-shadow:0 0 8px var(--pink)}
.sanitybar{margin-top:8px; height:7px; border-radius:6px; background:rgba(255,255,255,.07); overflow:hidden}
#sanityFill{height:100%; width:100%; background:linear-gradient(90deg,#ff2f6d,#ffd166,#39ff9e); transition:width .18s}
#banner{
position:absolute; top:12px; left:50%; transform:translateX(-50%);
padding:7px 16px; border-radius:999px; font-weight:800; letter-spacing:1px; font-size:14px;
border:1px solid var(--line); background:var(--panel); backdrop-filter:blur(7px);
white-space:nowrap; transition:color .2s, box-shadow .2s;
}
#banner.calm{color:var(--dim)}
#banner.warn1{color:var(--neon); box-shadow:0 0 22px rgba(57,255,158,.35)}
#banner.warn2{color:#ffd166; box-shadow:0 0 26px rgba(255,209,102,.5); animation:bl .35s infinite alternate}
#banner.event{color:#fff; background:linear-gradient(90deg,#ff2fd6,#37e6ff,#39ff9e,#ffd166,#ff2fd6);
background-size:300% 100%; animation:slide 1.1s linear infinite; box-shadow:0 0 40px rgba(255,47,214,.7)}
@keyframes bl{from{filter:brightness(1)}to{filter:brightness(1.6)}}
@keyframes slide{from{background-position:0 0}to{background-position:300% 0}}
#speed{
position:absolute; bottom:12px; left:50%; transform:translateX(-50%);
display:flex; gap:6px; padding:7px; border-radius:12px;
background:var(--panel); border:1px solid var(--line); backdrop-filter:blur(7px);
}
#speed button{
font:inherit; font-size:12.5px; font-weight:700; color:var(--ink); cursor:pointer;
background:rgba(255,255,255,.05); border:1px solid var(--line); border-radius:8px;
padding:6px 10px; transition:.12s;
}
#speed button:hover{background:rgba(255,255,255,.12)}
#speed button.on{background:linear-gradient(180deg,#1e7a4f,#0c3a28); border-color:var(--neon);
box-shadow:0 0 14px rgba(57,255,158,.4)}
#hint{position:absolute; bottom:14px; right:14px; color:var(--dim); font-size:11px; max-width:210px; text-align:right}
@media (max-width:720px){ #panel{width:210px; font-size:11px} #hint{display:none} }
</style</style>
</head>
<body>
<div id="stage">
<canvas id="c" width="960" height="600"></canvas>
<div id="banner" class="calm mono">CALM</div>
<div id="panel">
<div class="title">☕ THE DAILY GRIND <em>· neon promo live</em></div>
<div class="grid mono">
<span>Served</span><b id="served">0</b>
<span>Neon Unicorns</span><b id="uni" class="neon">0</b>
<span>Catastrophes</span><b id="cats" class="pink">0</b>
<span>Inside now</span><b id="inside">0/8</b>
<span>Unicorns inside</span><b id="uin" class="neon">0</b>
<span>Calm streak</span><b><span id="streak">0</span> <small>(best <span id="longest">0</span>)</small></b>
<span>Sparkles emitted</span><b id="spark">0</b>
<span>Barista sanity</span><b><span id="sanityFace">🙂</span> <span id="sanity">100%</span></b>
</div>
<div class="ratewrap">
<div class="ratelabel mono"><span>Unicorn rate</span><span><b id="rate">0.0%</b> <small>vs true 16.67%</small></span></div>
<div class="ratebar"><div id="rateFill"></div><div class="truemark"></div></div>
</div>
<div class="sanitybar"><div id="sanityFill"></div></div>
</div>
<div id="speed" class="mono">
<button data-s="0">⏸</button>
<button data-s="0.5">0.5×</button>
<button data-s="1" class="on">1×</button>
<button data-s="2">2×</button>
<button data-s="4">4×</button>
<button data-s="8">8×</button>
<button data-s="16">16×</button>
</div>
<div id="hint">The event fires only when 3 unicorns are inside at once. Nothing else. Crank the speed to skip ahead.</div>
</div>
<script>
(function(){
"use strict";
const cv = document.getElementById('c');
const ctx = cv.getContext('2d');
const W = cv.width, H = cv.height;
/* ---------- config (tuned; the 1/6 is NOT tuned) ---------- */
const CFG = {
insideCap: 8,
serviceTime: 2.0, // seconds at the counter (order+handoff)
lingerTime: 7.0, // seconds standing with the drink
unicornP: 1/6, // TRUE odds, rolled per drink, never touched
lineCap: 12,
spawnInterval: 1.25
};
/* ---------- layout ---------- */
const L = {
groundY: 500,
shop: {x:420, y:150, w:500, h:350},
door: {x:420, y:380, h:92},
counter: {x:600, y:214, w:290, h:42},
menu: {x:600, y:166, w:290, h:40},
orderSpot: {x:745, y:288},
barista: {x:700, y:196}
};
L.counter.cx = L.counter.x + L.counter.w/2;
const lingerSpots = [
{x:498,y:342},{x:576,y:432},{x:672,y:356},{x:806,y:346},
{x:512,y:456},{x:848,y:446},{x:642,y:458},{x:766,y:436}
];
function lineSlot(i){
const col = i % 12, row = (i/12)|0;
return { x: 398 - col*30 - row*12, y: 432 + row*40 };
}
/* ---------- palettes ---------- */
const OUTFIT = ['#e05a8a','#f2a541','#5ac8fa','#9b5de5','#00d9a3','#ff6b6b','#ffd166','#4cc9f0','#f15bb5','#8ce99a','#ff922b','#74c0fc'];
const DEBRIS = ['#123a2e','#0c2a22','#e8dcc0','#caa06a','#1e7a4f','#0a1f1a'];
const SKIN = ['#f0c9a0','#e0ac7e','#c68a5e','#8d5a3b','#f6d6b8'];
/* ---------- state ---------- */
let S;
function reset(){
S = {
time:0, speed:1, phase:'normal',
customers:[], nextId:0,
served:0, unicornsProduced:0, catastrophes:0,
unicornsInside:0, insideCount:0,
calmStreak:0, longestCalm:0, sparkles:0, sanity:100,
spawnTimer:0, counterBusy:null, cat:null,
particles:[], debris:[], rings:[]
};
}
reset();
/* stars (static) */
const stars = [];
for(let i=0;i<70;i++) stars.push({x:Math.random()*W, y:Math.random()*360, r:Math.random()*1.4+0.3, p:Math.random()*7});
/* ---------- tiny helpers ---------- */
function rr(x,y,w,h,r){ ctx.beginPath(); ctx.moveTo(x+r,y);
ctx.arcTo(x+w,y,x+w,y+h,r); ctx.arcTo(x+w,y+h,x,y+h,r);
ctx.arcTo(x,y+h,x,y,r); ctx.arcTo(x,y,x+w,y,r); ctx.closePath(); }
function cir(x,y,r){ ctx.beginPath(); ctx.arc(x,y,r,0,Math.PI*2); }
function ell(x,y,rx,ry,rot){ ctx.beginPath(); ctx.ellipse(x,y,rx,ry,rot||0,0,Math.PI*2); }
function pick(a){ return a[(Math.random()*a.length)|0]; }
function moveToward(c,dt){
const dx=c.tx-c.x, dy=c.ty-c.y, d=Math.hypot(dx,dy), step=c.speed*dt;
if(d<=step){ c.x=c.tx; c.y=c.ty; return true; }
c.x+=dx/d*step; c.y+=dy/d*step; return false;
}
/* ---------- particles ---------- */
function spawnSparkle(x,y,spread){
const a=Math.random()*Math.PI*2, sp=Math.random()*spread;
S.particles.push({type:'spark', x, y, vx:Math.cos(a)*sp, vy:Math.sin(a)*sp-40,
life:0.6+Math.random()*0.9, max:1.5, size:1.4+Math.random()*2.6, hue:Math.random()*360});
S.sparkles++;
if(S.particles.length>720) S.particles.splice(0, S.particles.length-720);
}
function spawnConfetti(){
S.particles.push({type:'confetti', x:Math.random()*W, y:-10,
vx:(Math.random()-0.5)*50, vy:40+Math.random()*90,
life:2.4+Math.random()*2, max:4.4, size:3+Math.random()*4,
hue:Math.random()*360, rot:Math.random()*7, vr:(Math.random()-0.5)*12});
if(S.particles.length>720) S.particles.splice(0, S.particles.length-720);
}
function updateParticles(dt){
const P=S.particles;
for(let i=P.length-1;i>=0;i--){
const p=P[i];
if(p.type==='spark'){ p.vy+=150*dt; p.vx*=0.985; p.x+=p.vx*dt; p.y+=p.vy*dt; }
else { p.vy+=42*dt; p.x+=p.vx*dt + Math.sin(S.time*3+p.rot)*0.4; p.y+=p.vy*dt; p.rot+=p.vr*dt; }
p.life-=dt;
if(p.life<=0 || p.y>H+24) P.splice(i,1);
}
}
function drawParticles(){
ctx.save(); ctx.globalCompositeOperation='lighter';
for(const p of S.particles){
const a=Math.max(0,Math.min(1,p.life/p.max));
if(p.type==='spark'){
ctx.fillStyle=`hsla(${(p.hue+S.time*120)%360},100%,68%,${a})`;
cir(p.x,p.y,p.size); ctx.fill();
}
}
ctx.restore();
for(const p of S.particles){
if(p.type!=='confetti') continue;
const a=Math.max(0,Math.min(1,p.life/p.max));
ctx.save(); ctx.translate(p.x,p.y); ctx.rotate(p.rot);
ctx.fillStyle=`hsla(${p.hue},95%,60%,${a})`;
ctx.fillRect(-p.size/2,-p.size/2,p.size,p.size*1.6);
ctx.restore();
}
}
/* ---------- debris & rings ---------- */
function updateDebris(dt){
const D=S.debris;
for(let i=D.length-1;i>=0;i--){
const d=D[i]; d.vy+=900*dt; d.x+=d.vx*dt; d.y+=d.vy*dt; d.rot+=d.vr*dt; d.life-=dt*0.32;
if(d.life<=0 || d.y>H+80) D.splice(i,1);
}
}
function drawDebris(){
for(const d of S.debris){
ctx.save(); ctx.translate(d.x,d.y); ctx.rotate(d.rot);
ctx.globalAlpha=Math.max(0,Math.min(1,d.life));
ctx.fillStyle=d.color; ctx.fillRect(-d.w/2,-d.h/2,d.w,d.h);
ctx.restore();
}
ctx.globalAlpha=1;
}
function updateRings(dt){
for(let i=S.rings.length-1;i>=0;i--){
const r=S.rings[i]; r.r+=r.vr*dt; r.alpha-=dt*1.1;
if(r.alpha<=0) S.rings.splice(i,1);
}
}
function drawRings(){
ctx.save(); ctx.globalCompositeOperation='lighter';
for(const r of S.rings){
ctx.strokeStyle=`hsla(${(S.time*200)%360},100%,70%,${Math.max(0,r.alpha)})`;
ctx.lineWidth=6; cir(r.x,r.y,r.r); ctx.stroke();
}
ctx.restore();
}
/* ---------- customers ---------- */
function spawnCustomer(){
S.customers.push({
id:++S.nextId, x:-30-Math.random()*50, y:432+(Math.random()-0.5)*22,
tx:0, ty:0, speed:105+Math.random()*45,
phase:'line', timer:0, bob:Math.random()*7,
outfit:pick(OUTFIT), skin:pick(SKIN), scale:0.9+Math.random()*0.25,
isUnicorn:false, hasDrink:false, lingerIdx:-1,
inside:false, exited:false, nearDoor:false
});
}
function getFreeLinger(){
const used=new Set();
for(const c of S.customers)
if(c.lingerIdx>=0 && (c.phase==='toLinger'||c.phase==='linger')) used.add(c.lingerIdx);
for(let i=0;i<lingerSpots.length;i++) if(!used.has(i)) return i;
return (Math.random()*lingerSpots.length)|0;
}
function finishOrder(c){
c.hasDrink=true;
c.isUnicorn = Math.random() < CFG.unicornP; // the one and only roll
S.served++; S.calmStreak++;
if(c.isUnicorn){ S.unicornsProduced++; spawnSparkle(c.x, c.y-22, 70); }
c.lingerIdx = getFreeLinger();
const spot = lingerSpots[c.lingerIdx];
c.phase='toLinger'; c.tx=spot.x; c.ty=spot.y;
S.counterBusy=null;
}
function updateNormal(dt){
// spawn to keep a perpetual line
S.spawnTimer-=dt;
let lineCount=0; for(const c of S.customers) if(c.phase==='line') lineCount++;
if(S.spawnTimer<=0 && lineCount<CFG.lineCap){
spawnCustomer(); S.spawnTimer=CFG.spawnInterval*(0.7+Math.random()*0.6);
}
// count inside
let inside=0;
for(const c of S.customers)
if(c.inside && !c.exited && c.phase!=='line') inside++;
// admit one from the line
if(!S.counterBusy && inside<CFG.insideCap){
const front=S.customers.find(c=>c.phase==='line');
if(front){ front.phase='enter'; front.inside=true;
front.tx=L.orderSpot.x; front.ty=L.orderSpot.y; S.counterBusy=front; }
}
// advance everyone
let lineIdx=0;
for(const c of S.customers){
c.bob+=dt*6;
if(c.phase==='line'){ const s=lineSlot(lineIdx++); c.tx=s.x; c.ty=s.y; moveToward(c,dt); }
else if(c.phase==='enter'){ if(moveToward(c,dt)){ c.phase='order'; c.timer=CFG.serviceTime; } }
else if(c.phase==='order'){ c.timer-=dt; if(c.timer<=0) finishOrder(c); }
else if(c.phase==='toLinger'){ if(moveToward(c,dt)){ c.phase='linger'; c.timer=CFG.lingerTime; } }
else if(c.phase==='linger'){ c.timer-=dt; if(c.timer<=0){ c.lingerIdx=-1; c.phase='leave'; c.tx=388; c.ty=426; } }
else if(c.phase==='leave'){
if(!c.nearDoor){ if(moveToward(c,dt)){ c.nearDoor=true; c.tx=-40; c.ty=432; } }
else if(moveToward(c,dt)){ c.exited=true; }
}
}
S.customers = S.customers.filter(c=>!c.exited);
// recount
inside=0; let uin=0;
for(const c of S.customers){
if(c.inside && c.phase!=='line') inside++;
if(c.isUnicorn && c.hasDrink) uin++;
}
S.insideCount=inside; S.unicornsInside=uin;
// sanity drift
if(uin>0) S.sanity=Math.max(0, S.sanity - dt*uin*6);
else S.sanity=Math.min(100, S.sanity + dt*4);
// THE trigger — and the only trigger
if(uin>=3) triggerCatastrophe();
}
/* ---------- catastrophe ---------- */
function triggerCatastrophe(){
S.phase='catastrophe';
S.catastrophes++;
S.longestCalm=Math.max(S.longestCalm, S.calmStreak);
S.calmStreak=0;
S.sanity=0;
S.unicornsInside=0; S.insideCount=0;
// everyone is vaporised in the chaos
for(const c of S.customers) spawnSparkle(c.x, c.y, 90);
S.customers.length=0; S.counterBusy=null;
S.cat={ t:0, stage:'charge', shake:0, flash:0, uniScale:0 };
}
function explode(){
const c=S.cat, sh=L.shop, cx=sh.x+sh.w/2, cy=sh.y+sh.h/2;
c.flash=1; c.shake=26; c.uniScale=0;
S.rings.push({x:cx,y:cy,r:20,vr:920,alpha:1});
S.rings.push({x:cx,y:cy,r:10,vr:520,alpha:1});
for(let i=0;i<80;i++){
const x=sh.x+Math.random()*sh.w, y=sh.y+Math.random()*sh.h;
const ang=Math.atan2(y-cy,x-cx)+(Math.random()-0.5)*0.8, sp=120+Math.random()*430;
S.debris.push({x,y,vx:Math.cos(ang)*sp, vy:Math.sin(ang)*sp-150,
rot:Math.random()*7, vr:(Math.random()-0.5)*14,
w:10+Math.random()*34, h:8+Math.random()*22, color:pick(DEBRIS), life:1});
}
for(let i=0;i<150;i++) spawnSparkle(cx,cy,540);
}
function updateCatastrophe(dt){
const c=S.cat; c.t+=dt;
const cx=L.shop.x+L.shop.w/2;
if(c.stage==='charge'){
c.shake=Math.min(16, c.shake+dt*40);
if(Math.random()<0.4) spawnSparkle(cx+(Math.random()-0.5)*260, 320+(Math.random()-0.5)*160, 60);
if(c.t>=0.7){ explode(); c.stage='boom'; c.t=0; }
} else {
c.shake*=Math.pow(0.1,dt); if(c.shake<0.2) c.shake=0;
if(c.stage==='boom'){
c.uniScale=Math.min(1, c.uniScale+dt*1.4);
if(c.t>=1.1){ c.stage='dance'; c.t=0; }
} else if(c.stage==='dance'){
c.uniScale=1;
if(Math.random()<0.85) spawnSparkle(cx+(Math.random()-0.2)*180, 250+(Math.random()-0.5)*180, 130);
if(Math.random()<0.55) spawnConfetti();
if(c.t>=5.0){ c.stage='rebuild'; c.t=0; }
} else if(c.stage==='rebuild'){
if(c.t>=1.3) finishCatastrophe();
}
}
c.flash*=Math.pow(0.02,dt);
}
function finishCatastrophe(){
S.phase='normal'; S.cat=null;
S.debris.length=0; S.rings.length=0;
S.spawnTimer=0; S.unicornsInside=0; S.insideCount=0; S.sanity=100;
}
/* ---------- master update ---------- */
function update(dt){
S.time+=dt;
if(S.phase==='normal') updateNormal(dt);
else updateCatastrophe(dt);
updateParticles(dt); updateDebris(dt); updateRings(dt);
}
/* ---------- drawing: world ---------- */
function drawSky(){
const g=ctx.createLinearGradient(0,0,0,H);
g.addColorStop(0,'#0a1430'); g.addColorStop(0.55,'#0a1226'); g.addColorStop(1,'#05070c');
ctx.fillStyle=g; ctx.fillRect(0,0,W,H);
for(const s of stars){
const tw=0.4+0.6*Math.abs(Math.sin(S.time*1.5+s.p));
ctx.fillStyle=`rgba(200,225,255,${0.25+tw*0.5})`;
cir(s.x,s.y,s.r); ctx.fill();
}
}
function drawGround(){
ctx.fillStyle='#0a0f18'; ctx.fillRect(0,L.groundY,W,H-L.groundY);
ctx.strokeStyle='rgba(120,200,255,.10)'; ctx.lineWidth=2;
ctx.beginPath(); ctx.moveTo(0,L.groundY); ctx.lineTo(W,L.groundY); ctx.stroke();
}
function drawShop(esc, alpha){
const sh=L.shop;
ctx.save();
ctx.globalAlpha=alpha;
// colour warp
let hue=0, sat=1;
if(S.phase==='catastrophe'){ hue=(S.time*420)%360; sat=2.2; }
else if(esc>=2){ hue=(S.time*70)%360; sat=1.45; }
else if(esc===1){ hue=Math.sin(S.time*2)*10; sat=1.08; }
if(hue||sat!==1) ctx.filter=`hue-rotate(${hue}deg) saturate(${sat})`;
// base shadow
ctx.fillStyle='rgba(0,0,0,.4)'; ell(sh.x+sh.w/2, sh.y+sh.h+6, sh.w*0.52, 16); ctx.fill();
// walls
ctx.fillStyle='#123a2e'; rr(sh.x,sh.y,sh.w,sh.h,14); ctx.fill();
ctx.lineWidth=4; ctx.strokeStyle='#e8dcc0'; ctx.stroke();
// roof band
ctx.fillStyle='#0c2a22'; rr(sh.x-12,sh.y-20,sh.w+24,32,9); ctx.fill();
ctx.strokeStyle='rgba(232,220,192,.5)'; ctx.lineWidth=2; ctx.stroke();
// logo
const lx=sh.x+56, ly=sh.y-4;
ctx.fillStyle='#1e7a4f'; cir(lx,ly,22); ctx.fill();
ctx.strokeStyle='#e8dcc0'; ctx.lineWidth=3; cir(lx,ly,22); ctx.stroke();
ctx.fillStyle='#e8dcc0'; star(lx,ly,10,4.5,5); ctx.fill();
// sign text
ctx.fillStyle='#e8dcc0'; ctx.font='700 20px system-ui,sans-serif'; ctx.textAlign='left'; ctx.textBaseline='middle';
ctx.fillText('THE DAILY GRIND', sh.x+88, sh.y-6);
ctx.fillStyle='#39ff9e'; ctx.font='700 12px ui-monospace,monospace';
ctx.fillText('★ NEON UNICORN FRAPPUCCINO — 1 IN 6 ★', sh.x+88, sh.y+14);
// windows (warm glow)
for(let i=0;i<2;i++){
const wx=sh.x+40+i*180, wy=sh.y+250;
ctx.fillStyle='rgba(255,214,120,.16)'; rr(wx,wy,120,70,8); ctx.fill();
ctx.strokeStyle='rgba(232,220,192,.4)'; ctx.lineWidth=2; ctx.stroke();
}
// door opening (left wall)
ctx.fillStyle='#05100c'; ctx.fillRect(sh.x-3, L.door.y, 12, L.door.h);
ctx.strokeStyle='rgba(232,220,192,.5)'; ctx.lineWidth=2;
ctx.strokeRect(sh.x-3, L.door.y, 12, L.door.h);
// menu board
ctx.fillStyle='#0a1f1a'; rr(L.menu.x,L.menu.y,L.menu.w,L.menu.h,6); ctx.fill();
ctx.strokeStyle='rgba(57,255,158,.35)'; ctx.lineWidth=1.5; ctx.stroke();
ctx.textAlign='left'; ctx.textBaseline='middle';
ctx.font='11px ui-monospace,monospace';
const glitch = (esc>=1 && Math.random()<0.06);
ctx.fillStyle= glitch? '#ff2fd6' : '#9fe8c8';
ctx.fillText('MENU', L.menu.x+12, L.menu.y+13);
ctx.fillStyle='#7fb7a0';
ctx.fillText('latte · mocha · cold brew', L.menu.x+12, L.menu.y+29);
if(glitch){ ctx.fillStyle='#ff2fd6'; ctx.font='700 12px ui-monospace,monospace';
ctx.fillText('UNICORN??', L.menu.x+200, L.menu.y+13); }
// counter
ctx.fillStyle='#caa06a'; rr(L.counter.x,L.counter.y,L.counter.w,L.counter.h,8); ctx.fill();
ctx.fillStyle='#a97f4c'; ctx.fillRect(L.counter.x,L.counter.y+L.counter.h-10,L.counter.w,10);
ctx.strokeStyle='rgba(0,0,0,.25)'; ctx.lineWidth=2; ctx.stroke();
// espresso machine
ctx.fillStyle='#2a2f38'; rr(L.counter.x+18,L.counter.y-24,54,26,5); ctx.fill();
ctx.fillStyle='#ff5a5a'; cir(L.counter.x+30,L.counter.y-12,3); ctx.fill();
ctx.fillStyle='#39ff9e'; cir(L.counter.x+44,L.counter.y-12,3); ctx.fill();
// barista
const bx=L.barista.x, by=L.barista.y;
ctx.fillStyle='#0e2a22'; ell(bx,by+14,20,10); ctx.fill();
ctx.fillStyle='#e8dcc0'; cir(bx,by,10); ctx.fill(); // head
ctx.fillStyle='#1e7a4f'; rr(bx-12,by-16,24,8,3); ctx.fill(); // cap
ctx.fillStyle='#123a2e'; rr(bx-14,by+6,28,18,5); ctx.fill(); // apron
ctx.filter='none';
ctx.restore();
ctx.globalAlpha=1;
}
function star(cx,cy,R,r,n){
ctx.beginPath();
for(let i=0;i<n*2;i++){
const rad=i%2?r:R, a=-Math.PI/2 + i*Math.PI/n;
const x=cx+Math.cos(a)*rad, y=cy+Math.sin(a)*rad;
i?ctx.lineTo(x,y):ctx.moveTo(x,y);
}
ctx.closePath();
}
function drawCup(x,y,uni){
ctx.save(); ctx.translate(x,y);
if(uni){ ctx.shadowBlur=16; ctx.shadowColor=`hsl(${(S.time*200)%360},100%,60%)`; }
// liquid / cup
if(uni){
const g=ctx.createLinearGradient(-5,-8,5,6);
g.addColorStop(0,`hsl(${(S.time*260)%360},100%,62%)`);
g.addColorStop(1,`hsl(${(S.time*260+120)%360},100%,62%)`);
ctx.fillStyle=g;
} else ctx.fillStyle='#efe6d8';
ctx.beginPath(); ctx.moveTo(-5,-8); ctx.lineTo(5,-8); ctx.lineTo(4,6); ctx.lineTo(-4,6); ctx.closePath(); ctx.fill();
// sleeve
ctx.shadowBlur=0;
ctx.fillStyle= uni? `hsl(${(S.time*200+40)%360},90%,55%)` : '#1e7a4f';
ctx.fillRect(-5,-2,10,5);
// cream
ctx.fillStyle='#ffffff'; cir(0,-9,4); ctx.fill();
// straw
ctx.strokeStyle= uni? `hsl(${(S.time*200+200)%360},100%,65%)` : '#e05a8a';
ctx.lineWidth=2; ctx.beginPath(); ctx.moveTo(2,-9); ctx.lineTo(6,-18); ctx.stroke();
if(uni){ // tiny horn
ctx.fillStyle='#ffd84d'; ctx.beginPath(); ctx.moveTo(-2,-12); ctx.lineTo(2,-12); ctx.lineTo(0,-19); ctx.closePath(); ctx.fill();
}
ctx.restore();
}
function drawCustomer(c){
const bob=Math.sin(c.bob)*2, x=c.x, y=c.y+bob, s=c.scale;
// shadow
ctx.fillStyle='rgba(0,0,0,.32)'; ell(c.x, c.y+13*s, 10*s, 4*s); ctx.fill();
// unicorn aura
if(c.isUnicorn && c.hasDrink){
ctx.save(); ctx.globalCompositeOperation='lighter';
const g=ctx.createRadialGradient(x,y,2,x,y,28*s);
g.addColorStop(0,`hsla(${(S.time*140)%360},100%,66%,.6)`);
g.addColorStop(1,'rgba(0,0,0,0)');
ctx.fillStyle=g; cir(x,y,28*s); ctx.fill(); ctx.restore();
}
// body + head
ctx.fillStyle=c.outfit; cir(x,y,10*s); ctx.fill();
ctx.fillStyle=c.skin; cir(x, y-11*s, 6*s); ctx.fill();
// drink
if(c.hasDrink) drawCup(x+9*s, y-1, c.isUnicorn);
}
/* ---------- escalation overlay ---------- */
function drawEscalation(esc){
const cx=L.shop.x+L.shop.w/2, cy=L.shop.y+L.shop.h/2;
const pulse=0.5+0.5*Math.sin(S.time*4);
const r=200+esc*120+pulse*40;
const g=ctx.createRadialGradient(cx,cy,20,cx,cy,r);
const hue=(S.time*80)%360, a= esc===1?0.10:0.18+0.10*pulse;
g.addColorStop(0,`hsla(${hue},100%,60%,${a})`);
g.addColorStop(1,'rgba(0,0,0,0)');
ctx.save(); ctx.globalCompositeOperation='lighter';
ctx.fillStyle=g; ctx.fillRect(0,0,W,H);
if(esc>=2){
for(let i=0;i<3;i++) if(Math.random()<0.3){
ctx.fillStyle=`hsla(${(S.time*220+i*120)%360},100%,72%,${0.14+Math.random()*0.22})`;
ctx.fillRect(L.shop.x+40+i*150, L.shop.y+8, 92, 22);
}
if(Math.random()<0.5) spawnSparkle(cx+(Math.random()-0.5)*320, cy+(Math.random()-0.5)*220, 60);
}
ctx.restore();
}
/* ---------- the payoff ---------- */
function drawGiantUnicorn(cx, cy, s, t){
const R=o=>`hsl(${(t*120+o)%360},100%,62%)`;
// aura
ctx.save(); ctx.globalCompositeOperation='lighter';
const ag=ctx.createRadialGradient(cx,cy,10,cx,cy,270*s);
ag.addColorStop(0,`hsla(${(t*120)%360},100%,60%,.35)`);
ag.addColorStop(1,'rgba(0,0,0,0)');
ctx.fillStyle=ag; cir(cx,cy,270*s); ctx.fill(); ctx.restore();
ctx.save();
ctx.translate(cx, cy + Math.sin(t*3)*14*s);
ctx.rotate(Math.sin(t*1.5)*0.05);
ctx.scale(s,s);
ctx.lineCap='round'; ctx.lineJoin='round'; ctx.shadowBlur=34;
// legs (prancing)
const lp=t*6, legs=[[-46,0],[-24,Math.PI],[34,Math.PI],[56,0]];
for(const [lx,ph] of legs){
const sw=Math.sin(lp+ph)*16;
ctx.strokeStyle=R(lx+300); ctx.lineWidth=13;
ctx.beginPath(); ctx.moveTo(lx,28); ctx.lineTo(lx+sw*0.4,66); ctx.lineTo(lx+sw,102); ctx.stroke();
ctx.fillStyle=R(lx+340); cir(lx+sw,104,9); ctx.fill();
}
// tail
for(let k=0;k<5;k++){
ctx.strokeStyle=R(200+k*28); ctx.lineWidth=9;
ctx.beginPath(); ctx.moveTo(-66,-4);
ctx.bezierCurveTo(-104,-28+Math.sin(t*4+k)*18, -128,18+Math.cos(t*3+k)*18, -150,-8+Math.sin(t*5+k)*26);
ctx.stroke();
}
// body
const bg=ctx.createLinearGradient(-70,-40,70,40);
bg.addColorStop(0,R(0)); bg.addColorStop(.5,R(120)); bg.addColorStop(1,R(240));
ctx.fillStyle=bg; ell(0,0,72,44); ctx.fill();
// neck
ctx.strokeStyle=R(60); ctx.lineWidth=32;
ctx.beginPath(); ctx.moveTo(44,-24); ctx.lineTo(90,-90); ctx.stroke();
// mane
for(let k=0;k<7;k++){
ctx.strokeStyle=R(150+k*24); ctx.lineWidth=9;
const p=k/7, mx=48+p*46, my=-28-p*62;
ctx.beginPath(); ctx.moveTo(mx,my);
ctx.quadraticCurveTo(mx-26+Math.sin(t*5+k)*10, my-6, mx-40+Math.sin(t*4+k)*16, my+20);
ctx.stroke();
}
// head
ctx.save(); ctx.translate(102,-102); ctx.rotate(-0.5);
ctx.fillStyle=R(90); ell(0,0,34,22); ctx.fill();
ell(26,6,16,12); ctx.fill();
ctx.fillStyle=R(150); ctx.beginPath(); ctx.moveTo(-8,-16); ctx.lineTo(-2,-40); ctx.lineTo(12,-14); ctx.closePath(); ctx.fill();
ctx.shadowBlur=0;
ctx.fillStyle='#fff'; cir(8,-4,6); ctx.fill();
ctx.fillStyle='#111'; cir(10,-4,3); ctx.fill();
ctx.restore();
// horn
ctx.shadowBlur=28;
const hg=ctx.createLinearGradient(120,-124,150,-186);
hg.addColorStop(0,'#ffffff'); hg.addColorStop(1,R(50));
ctx.fillStyle=hg;
ctx.save(); ctx.translate(118,-122); ctx.rotate(-0.85);
ctx.beginPath(); ctx.moveTo(-9,0); ctx.lineTo(9,0); ctx.lineTo(0,-58); ctx.closePath(); ctx.fill();
ctx.strokeStyle='rgba(255,255,255,.75)'; ctx.lineWidth=2;
for(let i=1;i<5;i++){ const yy=-i*11, ww=9*(1-i/5.5); ctx.beginPath(); ctx.moveTo(-ww,yy); ctx.lineTo(ww,yy-4); ctx.stroke(); }
ctx.restore();
ctx.restore();
}
function drawCatastrophe(){
const c=S.cat; if(!c) return;
const cx=L.shop.x+L.shop.w/2, cy=L.shop.y+L.shop.h/2;
if(c.stage==='charge'){
const p=c.t/0.7;
ctx.save(); ctx.globalCompositeOperation='lighter';
const r=20+p*170, g=ctx.createRadialGradient(cx,cy,0,cx,cy,r);
g.addColorStop(0,`rgba(255,255,255,${0.6*p})`);
g.addColorStop(0.5,`hsla(${(S.time*300)%360},100%,60%,${0.5*p})`);
g.addColorStop(1,'rgba(0,0,0,0)');
ctx.fillStyle=g; cir(cx,cy,r); ctx.fill(); ctx.restore();
}
if(c.uniScale>0.02 && (c.stage==='boom'||c.stage==='dance'||c.stage==='rebuild')){
let a=1; if(c.stage==='rebuild') a=Math.max(0,1-c.t/0.6);
const riseY = 300 + (1-c.uniScale)*230;
ctx.save(); ctx.globalAlpha=a;
drawGiantUnicorn(cx, riseY, c.uniScale*1.7, S.time);
ctx.restore();
}
}
/* ---------- vignette ---------- */
function drawVignette(){
const g=ctx.createRadialGradient(W/2,H/2,H*0.35,W/2,H/2,H*0.85);
g.addColorStop(0,'rgba(0,0,0,0)'); g.addColorStop(1,'rgba(0,0,0,.55)');
ctx.fillStyle=g; ctx.fillRect(0,0,W,H);
}
/* ---------- render ---------- */
function render(){
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0,0,W,H);
drawSky();
const esc = S.phase==='catastrophe'?3:S.unicornsInside;
let shake=0;
if(S.phase==='catastrophe' && S.cat) shake=S.cat.shake;
else if(esc>=2) shake=(esc-1)*2.2;
else if(esc===1) shake=0.5;
const jx=(Math.random()*2-1)*shake, jy=(Math.random()*2-1)*shake;
ctx.save(); ctx.translate(jx,jy);
drawGround();
const exploded = S.phase==='catastrophe' && S.cat && (S.cat.stage==='boom'||S.cat.stage==='dance');
const rebuilding = S.phase==='catastrophe' && S.cat && S.cat.stage==='rebuild';
if(!exploded){
const alpha = rebuilding? Math.min(1,S.cat.t/1.0) : 1;
drawShop(esc, alpha);
}
if(S.phase==='normal'){
for(const c of S.customers) if(c.phase==='line') drawCustomer(c);
const ins=S.customers.filter(c=>c.phase!=='line').sort((a,b)=>a.y-b.y);
for(const c of ins) drawCustomer(c);
}
drawDebris();
drawParticles();
drawRings();
if(S.phase==='normal' && esc>=1) drawEscalation(esc);
if(S.phase==='catastrophe') drawCatastrophe();
ctx.restore();
if(S.phase==='catastrophe' && S.cat && S.cat.flash>0.01){
ctx.fillStyle=`rgba(255,255,255,${S.cat.flash})`; ctx.fillRect(0,0,W,H);
}
drawVignette();
}
/* ---------- HUD ---------- */
const el = id=>document.getElementById(id);
const H_ = {
served:el('served'), uni:el('uni'), cats:el('cats'), inside:el('inside'),
uin:el('uin'), streak:el('streak'), longest:el('longest'), spark:el('spark'),
sanity:el('sanity'), sanityFace:el('sanityFace'), sanityFill:el('sanityFill'),
rate:el('rate'), rateFill:el('rateFill'), banner:el('banner')
};
function updateHUD(){
H_.served.textContent=S.served;
H_.uni.textContent=S.unicornsProduced;
H_.cats.textContent=S.catastrophes;
H_.inside.textContent=S.insideCount+'/'+CFG.insideCap;
H_.uin.textContent=S.unicornsInside;
H_.streak.textContent=S.calmStreak;
H_.longest.textContent=S.longestCalm;
H_.spark.textContent=S.sparkles;
const san=Math.round(S.sanity);
H_.sanity.textContent=san+'%';
H_.sanityFill.style.width=san+'%';
H_.sanityFace.textContent = san>66?'🙂':san>33?'😰':san>1?'😱':'💀';
const rate = S.served? S.unicornsProduced/S.served*100 : 0;
H_.rate.textContent=rate.toFixed(1)+'%';
H_.rateFill.style.width=Math.min(100, rate/40*100)+'%';
let txt, cls;
if(S.phase==='catastrophe'){ txt='☄ NEON UNICORN EVENT ☄'; cls='event'; }
else if(S.unicornsInside>=2){ txt='⚠ REALITY DESTABILIZING'; cls='warn2'; }
else if(S.unicornsInside===1){ txt='~ something is off ~'; cls='warn1'; }
else { txt='CALM'; cls='calm'; }
if(H_.banner.textContent!==txt) H_.banner.textContent=txt;
H_.banner.className='mono '+cls;
}
/* ---------- speed control ---------- */
document.querySelectorAll('#speed button').forEach(b=>{
b.addEventListener('click',()=>{
S.speed=parseFloat(b.dataset.s);
document.querySelectorAll('#speed button').forEach(x=>x.classList.remove('on'));
b.classList.add('on');
});
});
/* ---------- main loop ---------- */
let last=performance.now();
function frame(now){
let realDt=(now-last)/1000; last=now;
if(realDt>0.1) realDt=0.1;
const simDt=realDt*S.speed;
if(simDt>0){
const step=1/60;
const n=Math.min(40, Math.ceil(simDt/step));
const sdt=simDt/n;
for(let i=0;i<n;i++) update(sdt);
}
render();
updateHUD();
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
})();
</script>
</body>
</html>
In the first few minutes you'll see a calm shop: dots stream in from the left, queue outside, one at a time crosses to the counter, gets a cup, and drifts to a standing spot before leaving. Roughly one drink every ~2.5 s, so the "Served" counter climbs steadily and the observed unicorn rate wobbles around 16–17% (it's noisy early, converges over a few hundred drinks). Most of the time 0 or 1 unicorn is inside; when one is, the whole scene gets a faint rainbow vignette, a slow hue wobble, and the menu board occasionally glitches to "UNICORN??". When a second is inside, the building jitters, the ceiling lights flicker, colors rotate hard, and sparkles start venting. The instant a third unicorn is handed over, it's the event: white flash, the shop bursts into flying debris and a shockwave, and a big geometric neon unicorn prances out of the wreckage for ~5 s trailing confetti, then everything fades and rebuilds and the line resumes.
What I tuned (and what I refused to): the 1-in-6 is a raw Math.random() < 1/6 per drink, rolled once at the counter — never touched. Everything that sets the pace is tuned: service ≈ 2 s at the counter, ~7 s lingering (so a unicorn is "in the room" ~9–10 s), spawn interval ~1.25 s with a 12-person line cap and an 8-inside cap, 8 linger spots. Those give ~0.4 served/s and ρ≈0.6 unicorns-inside, which is where the ~60-customers / ~2.5-min estimate comes from.
What it does badly, so you're not surprised while watching counters:
ctx.filter hue-warp drives the level-2 color chaos; on a browser that doesn't support it, you just get less color warping (the shake, lights and particles still carry it).