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
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
You write crowd simulations where the behavior emerges from rules each person follows.
Build me a single HTML page: a section of a football stadium emptying through one exit gate.
#urgency=0.8&gate=1.2&column=1 starts simulation at load with those settings: urgency 0.0 to 1.0, gate width in yards, column 0 or 1. Any values work.data: URIs are fine.localStorage, sessionStorage, cookies or indexedDB — sandboxed frame, they throw.html block.Before the file, two quantitative predictions: whether increasing urgency from 0.3 to 0.9 increases or decreases evacuation time at gate=1.2 and column=0, with the predicted difference in seconds; and whether enabling the column (column=1) increases or decreases evacuation time at urgency=0.9 and gate=1.2, with the predicted difference in seconds.
The single fenced html block.
Where your crowd behaves like a real one and where it does not. Name anything you special-cased: a nudge that breaks a jam, a speed cap at the gate, an allowance for overlap. If your page never jams at the gate, say so.
I have not run this page, so both numbers are untested predictions.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Stand C7 · single-gate evacuation</title>
<style>
html,body{margin:0;height:100%;background:#0b0f14;overflow:hidden;font-family:system-ui,-apple-system,"Segoe UI",sans-serif;color:#e6edf3}
canvas{position:fixed;inset:0;width:100%;height:100%;display:block}
#panel{position:fixed;left:12px;top:12px;width:258px;background:rgba(13,17,23,.88);border:1px solid #30363d;border-radius:8px;padding:12px 14px;font-size:13px;line-height:1.4;box-sizing:border-box}
#panel h1{font-size:14px;margin:0 0 6px;letter-spacing:.02em}
#panel label{display:block;margin-top:9px}
#panel input[type=range]{width:100%;margin-top:4px}
.val{float:right;color:#8b949e;font-variant-numeric:tabular-nums}
.chk input{margin-right:6px;vertical-align:middle}
button{margin-top:10px;margin-right:6px;background:#21262d;color:#e6edf3;border:1px solid #30363d;border-radius:5px;padding:5px 10px;cursor:pointer;font:inherit}
button:hover{background:#30363d}
#metrics{margin-top:10px;border-top:1px solid #30363d;padding-top:8px;font-variant-numeric:tabular-nums}
#metrics div{display:flex;justify-content:space-between;margin:2px 0}
#metrics .big{font-size:18px;color:#f0f6fc}
</style>
</head>
<body>
<canvas id="c"></canvas>
<div id="panel">
<h1>Stand C7 · one gate</h1>
<label>Urgency <span class="val" id="uV"></span>
<input id="urg" type="range" min="0" max="1" step="0.05"></label>
<label>Gate width <span class="val" id="gV"></span>
<input id="gate" type="range" min="0.5" max="10" step="0.1"></label>
<label class="chk"><input id="col" type="checkbox">Column in front of gate</label>
<div>
<button id="reset">Reset stands</button><button id="pause">Pause</button>
</div>
<div id="metrics">
<div><span>Time</span><span class="big" id="tm">0:00.0</span></div>
<div><span>Remaining</span><span id="rem">–</span></div>
<div><span>Outflow, last 20 s</span><span id="r20">–</span></div>
<div><span>Outflow, average</span><span id="rav">–</span></div>
<div><span>Evacuation time</span><span id="ev">in progress</span></div>
</div>
</div>
<script>
(function(){
"use strict";
const W = 22, H = 16; // section size in yards; gate sits in the bottom wall (y = H)
const N = 260; // people in the stands
const SEED = 7; // fixed seed so reset reproduces the same stands
const SUB = 1/120; // physics substep, seconds
const $ = id => document.getElementById(id);
const cv = $('c'), ctx = cv.getContext('2d');
function resize(){
const d = window.devicePixelRatio || 1;
cv.width = Math.round(innerWidth * d);
cv.height = Math.round(innerHeight * d);
}
resize();
addEventListener('resize', resize);
function mulberry(a){
return function(){
a |= 0; a = a + 0x6D2B79F5 | 0;
let t = Math.imul(a ^ a >>> 15, 1 | a);
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
return ((t ^ t >>> 14) >>> 0) / 4294967296;
};
}
const S = {
u: 0.6, gw: 1.2, col: false,
people: [], walls: [],
t: 0, exits: [], evacT: null, run: true,
alive: 0, total: 0,
gx: W/2, gl: 0, gr: 0,
colX: W/2, colY: H - 2.6, colR: 0.5
};
let nrng = mulberry(4242);
function geom(){
S.gl = W/2 - S.gw/2;
S.gr = W/2 + S.gw/2;
S.gx = W/2;
S.walls = [
[0,0, W,0], // top
[0,0, 0,H], // left
[W,0, W,H], // right
[0,H, S.gl,H], // bottom-left of gate
[S.gr,H, W,H] // bottom-right of gate
];
}
function closest(px,py,ax,ay,bx,by){
const dx = bx-ax, dy = by-ay;
const L = dx*dx + dy*dy;
let t = L > 0 ? ((px-ax)*dx + (py-ay)*dy) / L : 0;
t = t < 0 ? 0 : t > 1 ? 1 : t;
return [ax + dx*t, ay + dy*t];
}
function spawn(){
const rnd = mulberry(SEED);
S.people = [];
let tries = 0;
while (S.people.length < N && tries < 200000){
tries++;
const r = 0.26 + 0.06*rnd();
const x = 1 + rnd()*(W-2), y = 1.2 + rnd()*9.3; // seated area in the stands
let ok = true;
for (const q of S.people){
const dx = q.x-x, dy = q.y-y, m = q.r + r + 0.04;
if (dx*dx + dy*dy < m*m){ ok = false; break; }
}
if (!ok) continue;
S.people.push({
x, y, vx:0, vy:0, ax:0, ay:0, r,
f: 0.85 + 0.3*rnd(), // personal walking-speed factor
col: `hsl(${(rnd()*360)|0} 55% 58%)`,
alive: true
});
}
S.total = S.people.length;
S.alive = S.total;
}
// ---- physics ----------------------------------------------------------
function substep(dt){
const P = S.people, n = P.length, u = S.u;
const base = 0.9 + 1.5*u; // desired speed, yd/s (urgency 0 -> ~0.9, 1 -> ~2.4)
const cK = 30 + 200*u; // contact stiffness, scales with urgency
const A = 6, B = 0.25; // social repulsion amplitude (yd/s^2) and range (yd)
// 1. desired motion + small fluctuation
for (let i = 0; i < n; i++){
const p = P[i]; if (!p.alive) continue;
const ty = p.y < H ? H + 0.3 : H + 6; // aim at gate, then keep walking out
const dx = S.gx - p.x, dy = ty - p.y;
const d = Math.hypot(dx, dy) || 1e-6;
const vd = base * p.f;
p.ax = ((dx/d)*vd - p.vx)/0.5 + (nrng()-0.5)*0.8;
p.ay = ((dy/d)*vd - p.vy)/0.5 + (nrng()-0.5)*0.8;
}
// 2. person-person: social repulsion + contact spring + tangential friction
for (let i = 0; i < n; i++){
const a = P[i]; if (!a.alive) continue;
for (let j = i+1; j < n; j++){
const b = P[j]; if (!b.alive) continue;
let dx = b.x-a.x, dy = b.y-a.y;
const sum = a.r + b.r, Rs = sum + 0.8;
const d2 = dx*dx + dy*dy;
if (d2 >= Rs*Rs) continue;
let d = Math.sqrt(d2);
if (d < 1e-6){ dx = 1e-4; dy = 0; d = 1e-4; }
const nx = dx/d, ny = dy/d, ov = sum - d;
let f = A*Math.exp(ov/B);
if (ov > 0) f += cK*ov;
a.ax -= nx*f; a.ay -= ny*f;
b.ax += nx*f; b.ay += ny*f;
if (ov > 0){
const tx = -ny, ty = nx;
const dvt = (b.vx-a.vx)*tx + (b.vy-a.vy)*ty;
const ft = Math.max(-30, Math.min(30, 3*dvt));
a.ax += tx*ft; a.ay += ty*ft;
b.ax -= tx*ft; b.ay -= ty*ft;
}
}
}
// 3. walls and column: same repulsion + contact form, infinite mass
for (const p of P){
if (!p.alive) continue;
for (const w of S.walls){
const c = closest(p.x,p.y,w[0],w[1],w[2],w[3]);
const dx = p.x-c[0], dy = p.y-c[1], d = Math.hypot(dx,dy);
if (d > p.r + 0.8 || d < 1e-9) continue;
const nx = dx/d, ny = dy/d, ov = p.r - d;
let f = A*Math.exp(ov/B);
if (ov > 0) f += cK*ov;
p.ax += nx*f; p.ay += ny*f;
}
if (S.col){
const dx = p.x-S.colX, dy = p.y-S.colY, d = Math.hypot(dx,dy);
const rad = p.r + S.colR;
if (d < rad + 0.8 && d > 1e-9){
const nx = dx/d, ny = dy/d, ov = rad - d;
let f = A*Math.exp(ov/B);
if (ov > 0) f += cK*ov;
p.ax += nx*f; p.ay += ny*f;
}
}
}
// 4. integrate (speed clamp is a sanity limit, see notes)
for (const p of P){
if (!p.alive) continue;
p.vx += p.ax*dt; p.vy += p.ay*dt;
const sp = Math.hypot(p.vx, p.vy);
if (sp > 4){ p.vx *= 4/sp; p.vy *= 4/sp; }
p.x += p.vx*dt; p.y += p.vy*dt;
}
// 5. hard constraints: no overlaps, walls and column are solid
for (let it = 0; it < 4; it++){
for (let i = 0; i < n; i++){
const a = P[i]; if (!a.alive) continue;
for (const w of S.walls){
const c = closest(a.x,a.y,w[0],w[1],w[2],w[3]);
const dx = a.x-c[0], dy = a.y-c[1], d = Math.hypot(dx,dy);
if (d < a.r){
const nx = d > 1e-9 ? dx/d : 0, ny = d > 1e-9 ? dy/d : 1;
const pen = a.r - d;
a.x += nx*pen; a.y += ny*pen;
const vn = a.vx*nx + a.vy*ny;
if (vn < 0){ a.vx -= vn*nx; a.vy -= vn*ny; }
}
}
if (S.col){
const dx = a.x-S.colX, dy = a.y-S.colY, d = Math.hypot(dx,dy);
const rad = a.r + S.colR;
if (d < rad){
const nx = d > 1e-9 ? dx/d : 0, ny = d > 1e-9 ? dy/d : 1;
const pen = rad - d;
a.x += nx*pen; a.y += ny*pen;
const vn = a.vx*nx + a.vy*ny;
if (vn < 0){ a.vx -= vn*nx; a.vy -= vn*ny; }
}
}
for (let j = i+1; j < n; j++){
const b = P[j]; if (!b.alive) continue;
let dx = b.x-a.x, dy = b.y-a.y;
const sum = a.r + b.r, d2 = dx*dx + dy*dy;
if (d2 >= sum*sum) continue;
let d = Math.sqrt(d2);
if (d < 1e-9){ dx = 1e-4; dy = 0; d = 1e-4; }
const nx = dx/d, ny = dy/d, pen = (sum-d)/2;
a.x -= nx*pen; a.y -= ny*pen;
b.x += nx*pen; b.y += ny*pen;
const vn = (b.vx-a.vx)*nx + (b.vy-a.vy)*ny;
if (vn < 0){
const im = vn/2;
a.vx += nx*im; a.vy += ny*im;
b.vx -= nx*im; b.vy -= ny*im;
}
}
}
}
// 6. exits: anyone who has passed the gate line and cleared it is counted
for (const p of P){
if (p.alive && p.y > H + 1){
p.alive = false;
S.exits.push(S.t);
S.alive--;
}
}
}
// ---- control ----------------------------------------------------------
function reset(){
geom();
spawn();
nrng = mulberry(4242);
S.t = 0; S.exits = []; S.evacT = null; S.run = true;
$('pause').textContent = 'Pause';
}
function fromHash(){
const p = new URLSearchParams(location.hash.replace(/^#/, ''));
if (p.has('urgency')){
const v = parseFloat(p.get('urgency'));
if (isFinite(v)) S.u = Math.min(1, Math.max(0, v));
}
if (p.has('gate')){
const v = parseFloat(p.get('gate'));
if (isFinite(v)) S.gw = Math.min(10, Math.max(0.5, v));
}
if (p.has('column')){
const v = p.get('column'), c = parseFloat(v);
S.col = isFinite(c) ? c !== 0 : v === 'true';
}
$('urg').value = S.u;
$('gate').value = S.gw;
$('col').checked = S.col;
}
$('urg').oninput = e => { S.u = +e.target.value; };
$('gate').oninput = e => { S.gw = +e.target.value; geom(); };
$('col').onchange = e => { S.col = e.target.checked; };
$('reset').onclick = () => reset();
$('pause').onclick = () => {
S.run = !S.run;
$('pause').textContent = S.run ? 'Pause' : 'Run';
};
addEventListener('hashchange', () => { fromHash(); reset(); });
// ---- metrics ----------------------------------------------------------
function fmt(t){
const m = Math.floor(t/60), s = t - m*60;
return m + ':' + (s < 10 ? '0' : '') + s.toFixed(1);
}
function updateUI(){
$('uV').textContent = S.u.toFixed(2);
$('gV').textContent = S.gw.toFixed(1) + ' yd';
$('tm').textContent = fmt(S.evacT !== null ? S.evacT : S.t);
$('rem').textContent = S.alive + ' of ' + S.total;
const t = S.t, w = Math.min(20, t);
if (w >= 3){
let c = 0;
for (const x of S.exits) if (x > t - w) c++;
$('r20').textContent = (c/w*60).toFixed(0) + ' /min';
} else {
$('r20').textContent = '–';
}
$('rav').textContent = t >= 3 ? (S.exits.length/t*60).toFixed(0) + ' /min' : '–';
$('ev').textContent = S.evacT !== null ? S.evacT.toFixed(1) + ' s' : 'in progress';
}
// ---- drawing ----------------------------------------------------------
function draw(){
const cw = cv.width, ch = cv.height;
const s = Math.min(cw/28, ch/22); // device px per yard
const ox = (cw - 28*s)/2 + 3*s, oy = (ch - 22*s)/2 + s;
const X = x => ox + x*s, Y = y => oy + y*s;
ctx.fillStyle = '#0b0f14';
ctx.fillRect(0, 0, cw, ch);
// stands: tiered rows
ctx.fillStyle = '#1a202a';
ctx.fillRect(X(0), Y(0), W*s, 11*s);
for (let y = 0, k = 0; y < 11; y += 0.7, k++){
ctx.fillStyle = k % 2 ? 'rgba(200,70,80,0.22)' : 'rgba(110,150,200,0.12)';
ctx.fillRect(X(0), Y(y), W*s, 0.6*s);
}
// concourse
ctx.fillStyle = '#2a3038';
ctx.fillRect(X(0), Y(11), W*s, (H-11)*s);
// corridor beyond the gate
ctx.fillStyle = '#161b22';
ctx.fillRect(X(S.gl), Y(H), (S.gr-S.gl)*s, 5*s);
ctx.fillStyle = '#d29922';
ctx.fillRect(X(S.gl-0.12), Y(H-0.35), 0.12*s, 0.7*s);
ctx.fillRect(X(S.gr), Y(H-0.35), 0.12*s, 0.7*s);
ctx.font = Math.max(10, 0.45*s) + 'px system-ui, sans-serif';
ctx.textAlign = 'center';
ctx.fillText('EXIT ' + S.gw.toFixed(1) + ' yd', X(W/2), Y(H+3));
// walls
ctx.strokeStyle = '#9aa4af';
ctx.lineWidth = Math.max(2, 0.25*s);
ctx.lineCap = 'square';
for (const w of S.walls){
ctx.beginPath();
ctx.moveTo(X(w[0]), Y(w[1]));
ctx.lineTo(X(w[2]), Y(w[3]));
ctx.stroke();
}
// column
if (S.col){
const cx = X(S.colX), cy = Y(S.colY), cr = S.colR*s;
const g = ctx.createRadialGradient(cx - cr*0.3, cy - cr*0.3, cr*0.1, cx, cy, cr);
g.addColorStop(0, '#9aa4af');
g.addColorStop(1, '#4b5563');
ctx.beginPath();
ctx.arc(cx, cy, cr, 0, Math.PI*2);
ctx.fillStyle = g;
ctx.fill();
}
// people
ctx.lineWidth = Math.max(1, 0.06*s);
ctx.strokeStyle = 'rgba(0,0,0,0.55)';
for (const p of S.people){
if (!p.alive) continue;
ctx.beginPath();
ctx.arc(X(p.x), Y(p.y), p.r*s, 0, Math.PI*2);
ctx.fillStyle = p.col;
ctx.fill();
ctx.stroke();
}
}
// ---- main loop --------------------------------------------------------
let last = performance.now(), acc = 0, lastUI = 0;
function frame(now){
const dt = Math.min(0.05, (now - last)/1000);
last = now;
if (S.run){
acc += dt;
let k = 0;
while (acc >= SUB && k < 16){
S.t += SUB;
substep(SUB);
acc -= SUB; k++;
}
if (acc >= SUB) acc = 0;
if (S.alive === 0 && S.evacT === null){
S.evacT = S.t;
S.run = false;
$('pause').textContent = 'Run';
}
}
draw();
if (now - lastUI > 200){ updateUI(); lastUI = now; }
requestAnimationFrame(frame);
}
// ---- start ------------------------------------------------------------
geom();
fromHash();
reset();
updateUI();
requestAnimationFrame(frame);
})();
</script>
</body>
</html>
Modelled plausibly:
Special-cased or approximated:
Jamming: I did not run this page, so I cannot tell you whether arching occurs at the 1.2 yd gate or at what urgency. The model permits arches: a narrow gate, high contact stiffness, and little noise could lock people into a stalled state. If a jam forms, nothing in the page will break it. I cannot confirm from here that the page never jams at the gate, so treat the predictions above as the hypothesis to check against the running simulation.