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.
Assume customers stay inside holding a drink for about 4 seconds, the counter serves roughly one every 1.2 seconds, and the shop holds an average of 5–6 people with about 4 actively holding drinks at any moment. With p = 1/6, the snapshot probability of 3 unicorns among 4 holders is P(X≥3) ≈ C(4,3)(1/6)³(5/6) + (1/6)⁴ ≈ 0.016 (about 1.6%). Once two are present they linger ~4 s, during which ~3 more drinks are served; the chance at least one of those is the fatal third is 1 − (5/6)³ ≈ 0.42. So reaching 2 happens in roughly 13% of windows, and about 42% of those escalate, giving a catastrophe roughly every 5–6 windows, or about every 20–30 seconds of “active pool” turnover. At ~45 customers served per minute that works out to roughly 40–80 customers between disasters, or about 1–3 minutes at normal speed. I did not load the die; the only tuning is the spawn/hold timing that makes overlap physically possible.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Starbucks Neon Unicorn Event</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { width: 100%; height: 100%; overflow: hidden; background: #080818; color: #fff; font-family: "Courier New", Courier, monospace; }
canvas { display: block; position: fixed; top: 0; left: 0; z-index: 1; }
#ui { position: fixed; z-index: 10; pointer-events: none; width: 100%; height: 100%; }
.panel { pointer-events: auto; background: rgba(10, 5, 20, 0.85); border: 2px solid #ff00aa; box-shadow: 0 0 20px #ff00aa44, inset 0 0 20px #00ffff22; padding: 14px 18px; border-radius: 8px; backdrop-filter: blur(4px); }
h1 { font-size: 1.1rem; color: #ff00aa; text-shadow: 0 0 10px #ff00aa, 0 0 20px #00ffff; letter-spacing: 2px; margin-bottom: 8px; }
.stat { font-size: 0.85rem; margin: 3px 0; color: #e0e0ff; }
.stat span { color: #00ffaa; font-weight: bold; }
.warn { color: #ff3333; text-shadow: 0 0 8px #ff3333; animation: pulse 0.8s infinite alternate; }
@keyframes pulse { from { opacity: 0.7; } to { opacity: 1; } }
#speedWrap { position: absolute; top: 20px; right: 20px; }
#speedWrap label { color: #fff; font-size: 0.8rem; }
#speedWrap input { vertical-align: middle; accent-color: #ff00aa; }
#msg { position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); text-align: center; pointer-events: none; }
#msg h2 { font-size: 2rem; color: #ff00aa; text-shadow: 0 0 30px #ff00aa, 0 0 60px #00ffff; letter-spacing: 4px; opacity: 0; transition: opacity 0.3s; }
#msg h2.show { opacity: 1; }
#msg p { font-size: 0.9rem; color: #aaa; margin-top: 6px; }
</style>
</head>
<body>
<canvas id="c"></canvas>
<div id="ui">
<div class="panel" style="position:absolute; top:20px; left:20px; max-width: 260px;">
<h1>★ STARBUCKS ★</h1>
<div class="stat">Served: <span id="sServed">0</span></div>
<div class="stat">Unicorns: <span id="sUnicorns">0</span> (<span id="sRate">0.00</span>%)</div>
<div class="stat">Inside: <span id="sInside">0</span></div>
<div class="stat">Unicorns Inside: <span id="sInsideU">0</span></div>
<div class="stat">Catastrophes: <span id="sCat">0</span></div>
<div class="stat">Chaos Index: <span id="sChaos">0</span></div>
<div class="stat" style="margin-top:6px; font-size:0.75rem; color:#888;">True rate: 16.67%</div>
<div id="warnText" style="margin-top:6px; font-size:0.75rem; height:1.2em;"></div>
</div>
<div id="speedWrap" class="panel">
<label>Speed <input type="range" id="speed" min="0.2" max="6" step="0.1" value="1"></label>
</div>
<div id="msg">
<h2 id="msgTitle">NEON UNICORN EVENT</h2>
<p id="msgSub">Reality is tearing</p>
</div>
</div>
<script>
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
let W = window.innerWidth;
let H = window.innerHeight;
canvas.width = W; canvas.height = H;
function resize() {
W = window.innerWidth; H = window.innerHeight;
canvas.width = W; canvas.height = H;
}
window.addEventListener('resize', resize);
// Simulation parameters
let timeScale = 1;
document.getElementById('speed').addEventListener('input', e => timeScale = parseFloat(e.target.value));
const MAX_INSIDE = 8;
const SPAWN_MIN = 600;
const SPAWN_MAX = 1100;
const SERVICE_TIME = 1000;
const HOLD_MIN = 3000;
const HOLD_MAX = 5000;
const MOVE_SPEED = 1.5;
// Stats
let stats = { served: 0, unicorns: 0, catastrophes: 0, totalDrinks: 0 };
// State
let customers = [];
let debris = [];
let particles = [];
let catastrophe = false;
let catTimer = 0;
let spawnTimer = 0;
let shakeX = 0;
let shakeY = 0;
let hueShift = 0;
// Shop geometry
const shopW = 320;
const shopH = 220;
const shopX = () => W/2 - shopW/2;
const shopY = () => H/2 - shopH/2 + 40;
function rand(a,b){ return a + Math.random()*(b-a); }
class Customer {
constructor() {
this.state = 'waiting'; // waiting, entering, ordering, holding, exiting, gone
this.x = 60;
this.y = H*0.62;
this.isUnicorn = false;
this.timer = 0;
this.targetX = 0;
this.targetY = 0;
this.color = '#5c3a2a';
this.id = Math.random().toString(36).slice(2);
}
update(dt) {
dt *= timeScale;
if (catastrophe && this.state !== 'gone') {
// During catastrophe, customers vanish quickly
this.state = 'gone';
return;
}
switch(this.state) {
case 'waiting':
// Move slowly right in line
this.x += MOVE_SPEED * dt * 0.5;
if (this.x > 140) this.x = 140;
// Check if can enter
const insideNow = customers.filter(c => ['entering','ordering','holding','exiting'].includes(c.state)).length;
if (insideNow < MAX_INSIDE && this.x >= 130) {
this.state = 'entering';
this.timer = 0.8; // seconds to reach inside
this.targetX = shopX() + shopW - 60;
this.targetY = H*0.58;
}
break;
case 'entering':
this.timer -= dt;
const t = Math.max(0, 1 - this.timer/0.8);
this.x = 140 + (this.targetX - 140) * t;
this.y = this.y + (this.targetY - this.y) * t;
if (this.timer <= 0) {
this.state = 'ordering';
this.timer = SERVICE_TIME / 1000;
}
break;
case 'ordering':
this.timer -= dt;
this.x = shopX() + shopW - 60;
this.y = H*0.58;
if (this.timer <= 0) {
// THE ROLL
this.isUnicorn = Math.random() < (1/6);
stats.totalDrinks++;
stats.served++;
if (this.isUnicorn) stats.unicorns++;
this.color = this.isUnicorn ? '#ff00ff' : '#5c3a2a';
this.state = 'holding';
this.timer = rand(HOLD_MIN, HOLD_MAX) / 1000;
}
break;
case 'holding':
this.timer -= dt;
// Slight wander
this.x = shopX() + shopW/2 + Math.sin(Date.now()/500 + parseFloat(this.id)) * 30;
this.y = H*0.58 + Math.sin(Date.now()/700 + parseFloat(this.id)) * 10;
if (this.timer <= 0) {
this.state = 'exiting';
this.timer = 0.6;
this.targetX = shopX() + shopW + 20;
this.targetY = H*0.58;
}
break;
case 'exiting':
this.timer -= dt;
const et = Math.max(0, 1 - this.timer/0.6);
this.x = (shopX() + shopW - 60) + (this.targetX - (shopX() + shopW - 60)) * et;
this.y = H*0.58 + (this.targetY - H*0.58) * et;
if (this.timer <= 0) {
this.state = 'gone';
}
break;
}
}
draw(ctx) {
if (this.state === 'gone') return;
ctx.save();
ctx.translate(this.x, this.y);
// Glow for unicorn
if (this.isUnicorn) {
const grad = ctx.createRadialGradient(0, 0, 2, 0, 0, 18);
grad.addColorStop(0, '#ffffff');
grad.addColorStop(0.3, '#ff00ff');
grad.addColorStop(0.6, '#00ffff');
grad.addColorStop(1, '#ff0000');
ctx.fillStyle = grad;
ctx.shadowColor = '#ff00ff';
ctx.shadowBlur = 25;
ctx.beginPath();
ctx.arc(0, 0, 12, 0, Math.PI*2);
ctx.fill();
ctx.shadowBlur = 0;
// Rainbow halo ring
ctx.strokeStyle = `hsl(${(Date.now()/20)%360}, 100%, 60%)`;
ctx.lineWidth = 3;
ctx.beginPath();
ctx.arc(0, 0, 20, 0, Math.PI*2);
ctx.stroke();
} else {
ctx.fillStyle = '#5c3a2a';
ctx.strokeStyle = '#8a5a3a';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.arc(0, 0, 10, 0, Math.PI*2);
ctx.fill();
ctx.stroke();
}
// Drink cup if holding
if (this.state === 'holding') {
ctx.fillStyle = this.isUnicorn ? '#ff00ff' : '#8a5a3a';
ctx.fillRect(-5, -18, 10, 14);
ctx.fillStyle = '#fff';
ctx.fillRect(-3, -22, 6, 4);
if (this.isUnicorn) {
ctx.fillStyle = '#00ffff';
ctx.fillRect(-4, -16, 8, 8);
}
}
ctx.restore();
}
}
function spawnCustomer() {
const insideNow = customers.filter(c => ['entering','ordering','holding','exiting'].includes(c.state)).length;
if (insideNow >= MAX_INSIDE) return;
// Only spawn if line isn't too long outside
const outsideNow = customers.filter(c => c.state === 'waiting').length;
if (outsideNow < 6) {
customers.push(new Customer());
}
}
function triggerCatastrophe() {
catastrophe = true;
catTimer = 0;
stats.catastrophes++;
document.getElementById('msgTitle').textContent = 'NEON UNICORN EVENT';
document.getElementById('msgSub').textContent = 'Reality is tearing';
document.getElementById('msgTitle').classList.add('show');
document.getElementById('msgSub').classList.add('show');
// Debris from shop
debris = [];
for (let i = 0; i < 30; i++) {
debris.push({
x: shopX() + rand(20, shopW-20),
y: shopY() + rand(20, shopH-20),
vx: rand(-8, 8),
vy: rand(-8, 8) - 2,
rot: rand(0, Math.PI*2),
vrot: rand(-0.15, 0.15),
w: rand(15, 50),
h: rand(10, 30),
color: ['#2a1a1a', '#3a2a2a', '#ffd966', '#ff00aa'][Math.floor(Math.random()*4)]
});
}
// Explosion particles
for (let i = 0; i < 60; i++) {
particles.push({
x: W/2, y: H/2,
vx: rand(-10, 10), vy: rand(-10, 10),
life: rand(1, 3),
color: ['#ff00aa', '#00ffff', '#ffff00', '#ffffff'][Math.floor(Math.random()*4)]
});
}
// Clear customers
customers = [];
}
function update() {
const dt = 1/60;
// Spawn
spawnTimer -= dt * timeScale;
if (spawnTimer <= 0) {
spawnCustomer();
spawnTimer = rand(SPAWN_MIN, SPAWN_MAX) / 1000;
}
// Update customers
for (let c of customers) c.update(dt);
// Remove gone
customers = customers.filter(c => c.state !== 'gone');
// Count unicorns inside
const insideCustomers = customers.filter(c => ['entering','ordering','holding','exiting'].includes(c.state));
const unicornInside = insideCustomers.filter(c => c.isUnicorn).length;
// Check catastrophe condition (pure dice, no timer)
if (!catastrophe && unicornInside >= 3) {
triggerCatastrophe();
}
// Catastrophe timer
if (catastrophe) {
catTimer += dt * timeScale;
// Update debris
for (let d of debris) {
d.x += d.vx * dt * timeScale;
d.y += d.vy * dt * timeScale;
d.vy += 0.3 * dt * timeScale; // gravity
d.rot += d.vrot * dt * timeScale;
}
// Update particles
for (let p of particles) {
p.x += p.vx * dt * timeScale;
p.y += p.vy * dt * timeScale;
p.vy += 0.2 * dt * timeScale;
p.life -= dt * timeScale;
}
particles = particles.filter(p => p.life > 0);
// Shake
shakeX = (Math.random() - 0.5) * 20 * Math.sin(catTimer * 20);
shakeY = (Math.random() - 0.5) * 20 * Math.sin(catTimer * 25);
// Reset after 6 seconds
if (catTimer > 6) {
catastrophe = false;
catTimer = 0;
debris = [];
particles = [];
shakeX = 0; shakeY = 0;
document.getElementById('msgTitle').classList.remove('show');
document.getElementById('msgSub').classList.remove('show');
// Rebuild: spawn fresh customers slowly
spawnTimer = 0.5;
}
}
// Update UI text
document.getElementById('sServed').textContent = stats.served;
document.getElementById('sUnicorns').textContent = stats.unicorns;
const rate = stats.totalDrinks > 0 ? ((stats.unicorns / stats.totalDrinks) * 100).toFixed(2) : '0.00';
document.getElementById('sRate').textContent = rate;
document.getElementById('sInside').textContent = insideCustomers.length;
document.getElementById('sInsideU').textContent = unicornInside;
document.getElementById('sCat').textContent = stats.catastrophes;
document.getElementById('sChaos').textContent = unicornInside;
// Warning text
const warn = document.getElementById('warnText');
if (!catastrophe) {
if (unicornInside === 1) {
warn.innerHTML = '<span style="color:#ffaa00;">Subtle wrongness detected</span>';
} else if (unicornInside === 2) {
warn.innerHTML = '<span class="warn">WARNING: REALITY UNSTABLE</span>';
} else {
warn.innerHTML = '';
}
} else {
warn.innerHTML = '<span class="warn">CATASTROPHIC NEON EVENT</span>';
}
}
function draw() {
ctx.save();
// Background
ctx.fillStyle = '#080818';
ctx.fillRect(0, 0, W, H);
// Apply shake and hue during catastrophe
if (catastrophe) {
ctx.translate(shakeX, shakeY);
hueShift = (hueShift + 5) % 360;
// We'll apply hue via filter if supported, else skip
try {
ctx.filter = `hue-rotate(${hueShift}deg) contrast(1.5) brightness(1.2)`;
} catch(e) {}
} else {
ctx.filter = 'none';
hueShift = 0;
}
// Draw ground line
ctx.fillStyle = '#1a0f1a';
ctx.fillRect(0, H*0.65, W, H*0.35);
// Draw shop
const sx = shopX();
const sy = shopY();
ctx.fillStyle = '#2a1a1a';
ctx.fillRect(sx, sy, shopW, shopH);
// Roof
ctx.fillStyle = '#3a2a2a';
ctx.beginPath();
ctx.moveTo(sx - 20, sy);
ctx.lineTo(sx + shopW/2, sy - 50);
ctx.lineTo(sx + shopW + 20, sy);
ctx.fill();
// Windows
ctx.fillStyle = '#ffd966';
for (let i = 0; i < 3; i++) {
const wx = sx + 40 + i * 100;
const wy = sy + 30;
ctx.fillRect(wx, wy, 50, 50);
// Window glow if catastrophe or high chaos
if (catastrophe || (customers.filter(c => c.isUnicorn && ['holding','ordering'].includes(c.state)).length > 0)) {
ctx.fillStyle = `rgba(255, 0, 170, 0.3)`;
ctx.fillRect(wx-5, wy-5, 60, 60);
}
}
// Sign
ctx.fillStyle = '#fff';
ctx.font = 'bold 22px "Courier New", monospace';
ctx.textAlign = 'center';
ctx.fillText('STARBUCKS', sx + shopW/2, sy - 15);
// Counter
ctx.fillStyle = '#3a2a2a';
ctx.fillRect(sx + 40, sy + shopH - 50, shopW - 80, 20);
// Door
ctx.fillStyle = '#1a0f0f';
ctx.fillRect(sx + shopW - 30, sy + 80, 30, 100);
// Subtle wrongness (1 unicorn)
if (!catastrophe && customers.filter(c => c.isUnicorn && ['holding','ordering','entering','exiting'].includes(c.state)).length === 1) {
ctx.strokeStyle = 'rgba(255, 0, 170, 0.15)';
ctx.lineWidth = 4;
ctx.strokeRect(sx - 5, sy - 5, shopW + 10, shopH + 10);
}
// Unstable coincidence (2 unicorns)
if (!catastrophe && customers.filter(c => c.isUnicorn && ['holding','ordering','entering','exiting'].includes(c.state)).length === 2) {
// Flashing lights
if (Math.random() > 0.7) {
ctx.fillStyle = `rgba(255, 255, 255, ${Math.random()*0.3})`;
ctx.fillRect(sx + Math.random()*shopW, sy + Math.random()*shopH, 20, 20);
}
// Warped colors via overlay
ctx.fillStyle = 'rgba(0, 255, 255, 0.05)';
ctx.fillRect(0, 0, W, H);
}
// Draw customers
for (let c of customers) c.draw(ctx);
// Outside queue line indicator
const waiting = customers.filter(c => c.state === 'waiting');
if (waiting.length > 0) {
ctx.strokeStyle = '#555';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(40, H*0.62);
ctx.lineTo(130, H*0.62);
ctx.stroke();
}
// Catastrophe effects
if (catastrophe) {
// Falling debris
for (let d of debris) {
ctx.save();
ctx.translate(d.x, d.y);
ctx.rotate(d.rot);
ctx.fillStyle = d.color;
ctx.fillRect(-d.w/2, -d.h/2, d.w, d.h);
ctx.restore();
}
// Particles
for (let p of particles) {
ctx.fillStyle = p.color;
ctx.fillRect(p.x - 3, p.y - 3, 6, 6);
}
// Giant dancing neon unicorn creature
const cx = W/2;
const cy = H/2 - 20;
const bounce = Math.sin(catTimer * 8) * 30;
const rot = Math.sin(catTimer * 4) * 0.3;
ctx.save();
ctx.translate(cx, cy + bounce);
ctx.rotate(rot);
ctx.scale(1.2 + Math.sin(catTimer*6)*0.1, 1.2 + Math.sin(catTimer*6)*0.1);
// Body
const bodyGrad = ctx.createLinearGradient(-60, 0, 60, 0);
bodyGrad.addColorStop(0, '#ff00aa');
bodyGrad.addColorStop(0.5, '#00ffff');
bodyGrad.addColorStop(1, '#ffff00');
ctx.fillStyle = bodyGrad;
ctx.beginPath();
ctx.ellipse(0, 0, 90, 55, 0, 0, Math.PI*2);
ctx.fill();
// Head
ctx.fillStyle = '#ffffff';
ctx.beginPath();
ctx.arc(70, -35, 35, 0, Math.PI*2);
ctx.fill();
// Horn
ctx.fillStyle = '#ffffaa';
ctx.beginPath();
ctx.moveTo(100, -45);
ctx.lineTo(115, -110);
ctx.lineTo(95, -40);
ctx.fill();
// Horn glow
ctx.shadowColor = '#ffff00';
ctx.shadowBlur = 30;
ctx.fillStyle = '#ffffff';
ctx.beginPath();
ctx.moveTo(100, -45);
ctx.lineTo(115, -110);
ctx.lineTo(95, -40);
ctx.fill();
ctx.shadowBlur = 0;
// Legs dancing
for (let i = 0; i < 4; i++) {
const legX = -50 + i * 35;
const legLift = Math.sin(catTimer * 10 + i * 2) * 15;
const legColor = `hsl(${(catTimer*30 + i*60)%360}, 100%, 60%)`;
ctx.fillStyle = legColor;
ctx.fillRect(legX, 40 + legLift, 18, 35);
}
// Eyes
ctx.fillStyle = '#000';
ctx.beginPath();
ctx.arc(80, -40, 8, 0, Math.PI*2);
ctx.arc(60, -40, 8, 0, Math.PI*2);
ctx.fill();
ctx.fillStyle = '#fff';
ctx.beginPath();
ctx.arc(82, -42, 3, 0, Math.PI*2);
ctx.arc(58, -42, 3, 0, Math.PI*2);
ctx.fill();
// Sparkles
for (let i = 0; i < 8; i++) {
const sx = Math.sin(catTimer * 5 + i) * 100;
const sy = Math.cos(catTimer * 5 + i) * 60;
ctx.fillStyle = `hsl(${(catTimer*20 + i*45)%360}, 100%, 70%)`;
ctx.beginPath();
ctx.arc(sx, sy, 4 + Math.sin(catTimer*10+i)*3, 0, Math.PI*2);
ctx.fill();
}
ctx.restore();
}
ctx.restore();
// Draw text overlay for catastrophe
if (catastrophe) {
ctx.save();
ctx.fillStyle = 'rgba(0,0,0,0.4)';
ctx.fillRect(0, 0, W, H);
ctx.font = 'bold 48px "Courier New", monospace';
ctx.textAlign = 'center';
ctx.fillStyle = '#ff00aa';
ctx.shadowColor = '#ff00aa';
ctx.shadowBlur = 40;
ctx.fillText('NEON UNICORN EVENT', W/2, H/2 - 40);
ctx.font = '24px "Courier New", monospace';
ctx.fillStyle = '#ffffff';
ctx.fillText('The shop has collapsed', W/2, H/2 + 20);
ctx.restore();
}
}
function loop() {
update();
draw();
requestAnimationFrame(loop);
}
loop();
</script>
</body>
</html>
In the first minute you see customers (brown dots) queue outside, enter one by one, stand at the counter, then wander inside with a cup. Roughly one in six gets a rainbow glow and a neon halo; the stats update live. At normal speed the first unicorn usually appears within 30–60 seconds, triggering a faint purple outline and a "Subtle wrongness" warning. A second can take another minute or two; when it happens the screen flashes, the shop outline shakes, and particles float up. The fatal third is rare—expect 1–4 minutes of real time—because with only eight slots inside and ~4-second hold times, clustering three successes requires genuine luck. I tuned spawn rate (~1 every 0.6–1.1 s) and hold time (~3–5 s) so overlap is possible but not constant; the 1/6 roll is pure Math.random() with no hidden quota or timer. Once the event hits, the shop explodes into falling rectangles, a giant dancing geometric unicorn takes over the center, and after six seconds everything resets to a fresh building. The speed slider lets you fast-forward; at 5× you can watch dozens of customers cycle in seconds. It does badly at very high speed (animation becomes jerky) and the geometric art is deliberately abstract—there are no faces, just circles and rectangles. The statistics fluctuate wildly with small samples, and if you leave it running for an hour the observed rate will slowly converge toward 16.67% but will never be exactly that.