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
30:00Did Elon Musk's team "train the gay away"... and make Grok 4.7 worse?
Sep 26, 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
29:00Grok 4.7: improved, but GLM 5.3 FlashX beat it anyway (benchmark against Gemini, Sol, etc.)
Sep 22, 2026 · YouTube
You write simulations where the interesting behavior is supposed to emerge rather than be animated by hand.
Build me a single HTML page: a side-view escalator carrying 15 to 20 people. Then the escalator reverses, at high speed.
data: URIs are fine.localStorage, sessionStorage, cookies or indexedDB — sandboxed frame, they throw.html block.One paragraph, before the file: how a person is represented, what makes one lose balance, and what happens when two of them occupy the same place.
The single fenced html block.
Having written it, what does the page do when the escalator reverses? Name anything you special-cased or nudged. Say what it does badly — I am going to press the button and watch.
Each person is a rigid rod with three collision circles (foot, hip, head) and a centre of mass 55 px above the foot. While upright, an ankle-torque controller (PD on lean angle, capped at 20 000 units) holds them vertical; the foot is held to the moving escalator surface only by Coulomb friction (μ = 1.0), so when the surface accelerates harder than friction can transmit, the feet slip and the body lags. When the lean passes 0.55 rad the controller switches off and the body becomes a free rigid body — it falls, slides, and collides. Two bodies in the same place resolve through sequential impulses at their circle contacts (normal + friction, no restitution), so a downed figure is simply three more circles that the ones behind have to climb over or be stopped by. Getting up is the same controller with a larger torque budget, gated on a "room" check: foot on the ground and no other body's circles within ~16 px of the head or ~13 px of the hip.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Escalator</title>
<style>
html, body {
margin: 0; padding: 0; height: 100%;
background: #05070a; overflow: hidden;
display: flex; align-items: center; justify-content: center;
}
canvas { display: block; }
#ui { position: fixed; top: 16px; left: 16px; z-index: 10; }
button {
font: 600 13px/1 ui-sans-serif, system-ui, -apple-system, sans-serif;
letter-spacing: 0.1em;
padding: 11px 20px;
border-radius: 6px;
border: 1px solid #3d4450;
background: #1c2128;
color: #e6edf3;
cursor: pointer;
transition: background 0.12s;
}
button:hover { background: #262c36; }
button:active { background: #30363d; }
</style>
</head>
<body>
<canvas id="c"></canvas>
<div id="ui"><button id="btn">REVERSE</button></div>
<script>
(function () {
'use strict';
// ---------- canvas ----------
const LW = 1000, LH = 620;
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
function resize() {
const dpr = window.devicePixelRatio || 1;
const s = Math.min(window.innerWidth / LW, window.innerHeight / LH);
canvas.width = Math.round(LW * s * dpr);
canvas.height = Math.round(LH * s * dpr);
canvas.style.width = Math.round(LW * s) + 'px';
canvas.style.height = Math.round(LH * s) + 'px';
ctx.setTransform(s * dpr, 0, 0, s * dpr, 0, 0);
}
window.addEventListener('resize', resize);
resize();
// ---------- geometry ----------
const G = { x1: 220, y1: 560, x2: 720, y2: 280 };
G.slope = (G.y2 - G.y1) / (G.x2 - G.x1);
G.len = Math.hypot(G.x2 - G.x1, G.y2 - G.y1);
G.ux = (G.x2 - G.x1) / G.len;
G.uy = (G.y2 - G.y1) / G.len;
function groundY(x) {
if (x <= G.x1) return G.y1;
if (x >= G.x2) return G.y2;
return G.y1 + G.slope * (x - G.x1);
}
function groundSlope(x) {
if (x <= G.x1 || x >= G.x2) return 0;
return G.slope;
}
// ---------- constants ----------
const GRAV = 620;
const KP = 90000, KD = 16000, TMAX = 20000;
const FALL_ANGLE = 0.55;
const KP_UP = 90000, KD_UP = 20000, TMAX_UP = 65000;
const MU = 1.0;
const ITER = 10;
const FOOT_Y = 55, HIP_Y = 5, HEAD_Y = -42;
const R_FOOT = 10, R_HIP = 12, R_HEAD = 12;
const INERTIA = 1500;
// ---------- escalator ----------
let escSpeed = 35;
let escTarget = 35;
let escDir = 1;
let escPhase = 0;
function updateEscalator(dt) {
const maxAccel = 800;
const diff = escTarget - escSpeed;
const maxD = maxAccel * dt;
escSpeed += Math.max(-maxD, Math.min(maxD, diff));
}
function groundVel(x) {
if (x > G.x1 && x < G.x2) {
return { x: escSpeed * G.ux, y: escSpeed * G.uy };
}
return { x: 0, y: 0 };
}
// ---------- bodies ----------
const bodies = [];
const COLORS = ['#f97583','#79c0ff','#7ee787','#ffa657','#d2a8ff','#ff7b72','#a5d6ff','#ffd33d','#56d364','#ff9bce'];
function makeBody(x, y, color) {
return {
x, y, vx: 0, vy: 0, a: 0, w: 0,
m: 1, invM: 1, I: INERTIA, invI: 1 / INERTIA,
state: 'stand', color,
};
}
function bodyPoints(b) {
const c = Math.cos(b.a), s = Math.sin(b.a);
return [
{ x: b.x - FOOT_Y * s, y: b.y + FOOT_Y * c, r: R_FOOT },
{ x: b.x - HIP_Y * s, y: b.y + HIP_Y * c, r: R_HIP },
{ x: b.x - HEAD_Y * s, y: b.y + HEAD_Y * c, r: R_HEAD },
];
}
// ---------- contacts ----------
function buildContacts() {
const cs = [];
for (const b of bodies) {
const pts = bodyPoints(b);
for (const p of pts) {
const gy = groundY(p.x);
const sl = groundSlope(p.x);
const invLen = 1 / Math.sqrt(1 + sl * sl);
const nx = sl * invLen, ny = -invLen;
const dist = (gy - p.y) * invLen;
const pen = p.r - dist;
if (pen > -0.5) {
const gv = groundVel(p.x);
cs.push({
A: b, B: null,
px: p.x - nx * p.r, py: p.y - ny * p.r,
nx, ny,
pen: Math.max(0, pen),
mu: MU,
vgx: gv.x, vgy: gv.y,
});
}
if (p.x - p.r < 10) {
cs.push({
A: b, B: null,
px: 10, py: p.y,
nx: 1, ny: 0,
pen: 10 - (p.x - p.r),
mu: 0.5,
vgx: 0, vgy: 0,
});
}
}
}
for (let i = 0; i < bodies.length; i++) {
const A = bodies[i];
for (let j = i + 1; j < bodies.length; j++) {
const B = bodies[j];
const dx = B.x - A.x, dy = B.y - A.y;
if (dx * dx + dy * dy > 180 * 180) continue;
const pa = bodyPoints(A), pb = bodyPoints(B);
for (const p of pa) {
for (const q of pb) {
const ddx = q.x - p.x, ddy = q.y - p.y;
const d2 = ddx * ddx + ddy * ddy;
const rr = p.r + q.r;
if (d2 < rr * rr && d2 > 0.0001) {
const d = Math.sqrt(d2);
const dirx = ddx / d, diry = ddy / d;
const pen = rr - d;
cs.push({
A, B,
px: p.x + dirx * (p.r - pen * 0.5),
py: p.y + diry * (p.r - pen * 0.5),
nx: -dirx, ny: -diry,
pen,
mu: 0.6,
vgx: 0, vgy: 0,
});
}
}
}
}
}
return cs;
}
// ---------- solver ----------
function solveContacts(cs, dt) {
for (const c of cs) {
const A = c.A, B = c.B;
c.rax = c.px - A.x; c.ray = c.py - A.y;
if (B) { c.rbx = c.px - B.x; c.rby = c.py - B.y; }
else { c.rbx = 0; c.rby = 0; }
const rnA = c.rax * c.ny - c.ray * c.nx;
const rnB = B ? (c.rbx * c.ny - c.rby * c.nx) : 0;
c.massN = 1 / (A.invM + (B ? B.invM : 0) + rnA * rnA * A.invI + (B ? rnB * rnB * B.invI : 0));
const tx = -c.ny, ty = c.nx;
const rtA = c.rax * ty - c.ray * tx;
const rtB = B ? (c.rbx * ty - c.rby * tx) : 0;
c.massT = 1 / (A.invM + (B ? B.invM : 0) + rtA * rtA * A.invI + (B ? rtB * rtB * B.invI : 0));
c.jn = 0; c.jt = 0;
c.bias = Math.min(0.15 / dt * Math.max(0, c.pen - 0.5), 120);
}
for (let it = 0; it < ITER; it++) {
for (const c of cs) {
const A = c.A, B = c.B;
let vax = A.vx - A.w * c.ray;
let vay = A.vy + A.w * c.rax;
let vbx = c.vgx, vby = c.vgy;
if (B) { vbx = B.vx - B.w * c.rby; vby = B.vy + B.w * c.rbx; }
const rvx = vax - vbx, rvy = vay - vby;
const vn = rvx * c.nx + rvy * c.ny;
let jn = (-vn + c.bias) * c.massN;
const oldJn = c.jn;
c.jn = Math.max(0, oldJn + jn);
jn = c.jn - oldJn;
if (jn !== 0) {
A.vx += jn * c.nx * A.invM;
A.vy += jn * c.ny * A.invM;
A.w += (c.rax * jn * c.ny - c.ray * jn * c.nx) * A.invI;
if (B) {
B.vx -= jn * c.nx * B.invM;
B.vy -= jn * c.ny * B.invM;
B.w -= (c.rbx * jn * c.ny - c.rby * jn * c.nx) * B.invI;
}
}
vax = A.vx - A.w * c.ray;
vay = A.vy + A.w * c.rax;
vbx = c.vgx; vby = c.vgy;
if (B) { vbx = B.vx - B.w * c.rby; vby = B.vy + B.w * c.rbx; }
const rvx2 = vax - vbx, rvy2 = vay - vby;
const tx = -c.ny, ty = c.nx;
const vt = rvx2 * tx + rvy2 * ty;
let jt = -vt * c.massT;
const maxF = c.mu * c.jn;
const oldJt = c.jt;
c.jt = Math.max(-maxF, Math.min(maxF, oldJt + jt));
jt = c.jt - oldJt;
if (jt !== 0) {
A.vx += jt * tx * A.invM;
A.vy += jt * ty * A.invM;
A.w += (c.rax * jt * ty - c.ray * jt * tx) * A.invI;
if (B) {
B.vx -= jt * tx * B.invM;
B.vy -= jt * ty * B.invM;
B.w -= (c.rbx * jt * ty - c.rby * jt * tx) * B.invI;
}
}
}
}
}
// ---------- get up ----------
function canGetUp(b) {
const pts = bodyPoints(b);
const foot = pts[0], hip = pts[1], head = pts[2];
const gy = groundY(foot.x);
const sl = groundSlope(foot.x);
const invLen = 1 / Math.sqrt(1 + sl * sl);
if ((gy - foot.y) * invLen > foot.r + 14) return false;
for (const o of bodies) {
if (o === b) continue;
const opts = bodyPoints(o);
for (const p of opts) {
if (Math.hypot(p.x - head.x, p.y - head.y) < p.r + 16) return false;
if (Math.hypot(p.x - hip.x, p.y - hip.y) < p.r + 13) return false;
}
}
return true;
}
// ---------- step ----------
function step(dt) {
for (const b of bodies) b.vy += GRAV * dt;
for (const b of bodies) {
if (b.state === 'stand') {
let tq = -KP * b.a - KD * b.w;
tq = Math.max(-TMAX, Math.min(TMAX, tq));
b.w += tq * b.invI * dt;
if (Math.abs(b.a) > FALL_ANGLE) b.state = 'fall';
} else if (b.state === 'rise') {
if (!canGetUp(b)) {
b.state = 'fall';
} else {
let tq = -KP_UP * b.a - KD_UP * b.w;
tq = Math.max(-TMAX_UP, Math.min(TMAX_UP, tq));
b.w += tq * b.invI * dt;
b.w = Math.max(-3.5, Math.min(3.5, b.w));
if (Math.abs(b.a) > 0.9) b.state = 'fall';
else if (Math.abs(b.a) < 0.22 && Math.abs(b.w) < 1.2) b.state = 'stand';
}
}
}
const cs = buildContacts();
solveContacts(cs, dt);
for (const b of bodies) {
b.x += b.vx * dt;
b.y += b.vy * dt;
b.a += b.w * dt;
if (b.a > Math.PI) b.a -= 2 * Math.PI;
if (b.a < -Math.PI) b.a += 2 * Math.PI;
b.vx *= 0.9995;
b.vy *= 0.9995;
b.w *= 0.999;
}
for (const b of bodies) {
if (b.state === 'fall') {
const sp2 = b.vx * b.vx + b.vy * b.vy;
if (Math.abs(b.a) > 1.0 && Math.abs(b.w) < 1.5 && sp2 < 400) {
if (canGetUp(b)) b.state = 'rise';
}
}
}
}
// ---------- init ----------
const N = 18;
for (let i = 0; i < N; i++) {
const x = 250 + i * 26;
const gy = groundY(x);
const sl = groundSlope(x);
const invLen = 1 / Math.sqrt(1 + sl * sl);
const footY = gy - R_FOOT / invLen;
bodies.push(makeBody(x, footY - FOOT_Y, COLORS[i % COLORS.length]));
}
// ---------- render ----------
function draw() {
const bg = ctx.createLinearGradient(0, 0, 0, LH);
bg.addColorStop(0, '#0a0e14');
bg.addColorStop(1, '#05070a');
ctx.fillStyle = bg;
ctx.fillRect(0, 0, LW, LH);
ctx.beginPath();
ctx.moveTo(0, G.y1);
ctx.lineTo(G.x1, G.y1);
ctx.lineTo(G.x2, G.y2);
ctx.lineTo(LW, G.y2);
ctx.lineTo(LW, LH);
ctx.lineTo(0, LH);
ctx.closePath();
ctx.fillStyle = '#0f141a';
ctx.fill();
const stepW = 26;
ctx.beginPath();
ctx.moveTo(G.x1, G.y1);
let x = G.x1, y = G.y1;
while (x < G.x2 - 0.01) {
const nx = Math.min(x + stepW, G.x2);
const ny = G.y1 + G.slope * (nx - G.x1);
ctx.lineTo(nx, y);
ctx.lineTo(nx, ny);
x = nx; y = ny;
}
ctx.lineTo(G.x2, G.y2 + 34);
ctx.lineTo(G.x1, G.y1 + 34);
ctx.closePath();
ctx.fillStyle = '#151b23';
ctx.fill();
ctx.strokeStyle = '#2d3540';
ctx.lineWidth = 1.5;
ctx.stroke();
ctx.beginPath();
ctx.moveTo(0, G.y1);
ctx.lineTo(G.x1, G.y1);
ctx.lineTo(G.x2, G.y2);
ctx.lineTo(LW, G.y2);
ctx.strokeStyle = '#3d4450';
ctx.lineWidth = 3;
ctx.stroke();
const hOff = 72;
ctx.beginPath();
ctx.moveTo(G.x1, G.y1 - hOff);
ctx.lineTo(G.x2, G.y2 - hOff);
ctx.strokeStyle = '#2a313b';
ctx.lineWidth = 7;
ctx.lineCap = 'round';
ctx.stroke();
ctx.save();
ctx.beginPath();
ctx.moveTo(G.x1, G.y1 - hOff);
ctx.lineTo(G.x2, G.y2 - hOff);
ctx.setLineDash([10, 22]);
ctx.lineDashOffset = -escPhase;
ctx.strokeStyle = '#5a6572';
ctx.lineWidth = 3;
ctx.stroke();
ctx.restore();
for (const b of bodies) drawPerson(b);
}
function drawPerson(b) {
const c = Math.cos(b.a), s = Math.sin(b.a);
const P = (lx, ly) => ({ x: b.x + lx * c - ly * s, y: b.y + lx * s + ly * c });
const hip = P(0, HIP_Y);
const head = P(0, HEAD_Y);
const shoulder = P(0, HEAD_Y + 14);
ctx.strokeStyle = b.color;
ctx.lineWidth = 3;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
const l1 = P(7, FOOT_Y - 3);
const l2 = P(-7, FOOT_Y - 3);
ctx.beginPath();
ctx.moveTo(hip.x, hip.y);
ctx.lineTo(l1.x, l1.y);
ctx.moveTo(hip.x, hip.y);
ctx.lineTo(l2.x, l2.y);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(hip.x, hip.y);
ctx.lineTo(shoulder.x, shoulder.y);
ctx.stroke();
const flail = Math.max(-1, Math.min(1, b.w * 0.35));
const a1 = P(24 + flail * 8, HEAD_Y + 30);
const a2 = P(-24 + flail * 8, HEAD_Y + 30);
ctx.beginPath();
ctx.moveTo(shoulder.x, shoulder.y);
ctx.lineTo(a1.x, a1.y);
ctx.moveTo(shoulder.x, shoulder.y);
ctx.lineTo(a2.x, a2.y);
ctx.stroke();
ctx.beginPath();
ctx.arc(head.x, head.y, 10, 0, Math.PI * 2);
ctx.fillStyle = b.color;
ctx.fill();
}
// ---------- loop ----------
let last = performance.now();
let acc = 0;
const FIXED = 1 / 60;
function loop(now) {
let dt = (now - last) / 1000;
last = now;
if (dt > 0.1) dt = 0.1;
acc += dt;
let guard = 0;
while (acc >= FIXED && guard < 5) {
updateEscalator(FIXED);
escPhase += escSpeed * FIXED;
step(FIXED);
acc -= FIXED;
guard++;
}
if (guard >= 5) acc = 0;
draw();
requestAnimationFrame(loop);
}
document.getElementById('btn').addEventListener('click', function () {
escDir *= -1;
escTarget = escDir > 0 ? 35 : -170;
});
requestAnimationFrame(loop);
})();
</script>
</body>
</html>
Press the button and the escalator surface ramps from +35 px/s to −170 px/s over about a quarter second — roughly 800 px/s² of deceleration. Friction at each foot can only transmit about 540 px/s² (μ = 1.0 against a normal load of m·g·cos α), so the feet slip, the bodies lag, and the ankle-torque controller saturates at 20 000 units. Past 0.55 rad of lean the controller is switched off and the figure becomes a free rigid body: it topples, hits the ramp, slides down, and collides with whoever is below. Because a downed figure is just three more collision circles, the ones arriving behind it are stopped by it, climb over it, or wedge into it — the pile is whatever the contact solver produces. Figures get up when their foot is on the surface and no other body's circles are within 16 px of their head or 13 px of their hip; getting up is the same PD controller with a 65 000-unit budget and a 3.5 rad/s speed cap, so a figure in the middle of a pile simply never satisfies the room check and stays down.
Special-cased / nudged: the two controllers (standing and getting-up) and their torque caps and cutoff angles; the "room" heuristic for standing up; the 800 px/s² acceleration limit on the escalator; the left wall at x = 10; the fact that the escalator surface is a smooth ramp with a decorative staircase drawn under it, so feet sit on the nosing line rather than on individual treads. No keyframes, no timeline, no per-figure scripting.
What it does badly: the pile is jittery under load and bodies interpenetrate a little when several are stacked; the standing controller holds people at a slightly non-physical backward lean on the incline (about 3°) because it targets vertical rather than the true equilibrium; the get-up check is a crude circle-proximity test, so people sometimes refuse to get up in a gap that looks big enough, or squeeze up through one that looks too small; and because the escalator is a ramp rather than real steps, a body sliding down never catches on a nosing — it just accelerates smoothly into the pile.