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 build physics toys, and you have watched someone try the tablecloth trick at a family dinner.
Build me a single HTML page: a table set for dinner, and a tablecloth I can yank out from under it.
#speed=12 sets the pull speed to 12 ft/s and pulls one second after load. Any number works.data: URIs are fine.localStorage, sessionStorage, cookies or indexedDB — sandboxed frame, they throw.html block.One paragraph, before the file: the lowest pull speed at which every object stays on the table, and the speed below which no object stays on the table, as two numbers in ft/s. State the arithmetic using your masses, friction coefficients, and cloth length.
The single fenced html block.
Where it behaves like the physical trick and where it does not. Name any special cases, scripted wobbles, or fall thresholds. Everyone has seen this trick fail; say how yours fails before I find out.
With $g=32.2\ \mathrm{ft/s^2}$, table $0$ to $10\ \mathrm{ft}$, cloth $11\ \mathrm{ft}$ long from $-0.5$ to $10.5\ \mathrm{ft}$ pulled right, an object at $x_0$ is on the cloth for $D=x_0+0.5\ \mathrm{ft}$, $t_c=D/V$, slides at $a=\mu_c g$, then stops on the table at $a_t=\mu_t g$; its travel is $S=\tfrac12at_c^2+v^2/2a_t=(D/V)^2\frac a2(1+a/a_t)$ with $v=at_c$, and it stays iff $S<E=10-x_0$, i.e. $V>D\sqrt{\frac a2(1+a/a_t)/E}$. The governing object is the slippery plate at $x_0=8.8\ \mathrm{ft}$: $a=0.15(32.2)=4.83$, $a_t=0.50(32.2)=16.1$, $\frac a2(1+a/a_t)=3.14$, $D=9.3$, $E=1.2$, so $V>9.3\sqrt{3.14/1.2}=15.0\ \mathrm{ft/s}$; the other six give $1.9,3.6,4.7,5.3,6.6,11.8\ \mathrm{ft/s}$ in the same formula, so the lowest speed at which every object stays on the table is about $15.1\ \mathrm{ft/s}$. An object rides the cloth to the edge iff it reaches cloth speed before the cloth passes it, $V<\sqrt{aD}$; the smallest such value is for the glass at $x_0=1.0\ \mathrm{ft}$, $\sqrt{0.45(32.2)(1.5)}=4.66\ \mathrm{ft/s}$, the others being $6.3$–$7.8\ \mathrm{ft/s}$, so below about $4.7\ \mathrm{ft/s}$ no object stays on the table.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Crouton Alpha — Tablecloth Trick</title>
<style>
body{margin:0;font-family:Georgia,serif;background:#2b1d16;color:#f5e6c8;text-align:center}
h1{margin:10px 0 4px;font-size:22px}
#bar{background:#3d2a1e;padding:10px;display:flex;gap:14px;justify-content:center;align-items:center;flex-wrap:wrap}
button{background:#c0392b;color:#fff;border:0;padding:8px 16px;font-size:16px;border-radius:6px;cursor:pointer}
button:hover{background:#e74c3c}
#speedVal{font-weight:bold;min-width:90px;display:inline-block}
canvas{background:linear-gradient(#ffe9b8,#f7d794);display:block;margin:10px auto;border:3px solid #5a3a22;max-width:98vw}
#status{font-size:18px;min-height:24px;margin:6px}
#result{font-size:20px;font-weight:bold;color:#fff;background:#5a3a22;display:inline-block;padding:8px 18px;border-radius:8px;margin:6px}
.note{font-size:13px;opacity:.85;max-width:900px;margin:4px auto 14px}
</style>
</head>
<body>
<h1>🍽️ The Tablecloth Trick</h1>
<div id="bar">
<label>Pull speed: <input id="speed" type="range" min="0" max="20" step="0.1" value="8"> <span id="speedVal">8.0 ft/s</span></label>
<button id="yank">YANK!</button>
<button id="reset">Reset</button>
</div>
<div id="status">Set a speed and yank the cloth.</div>
<canvas id="c" width="1020" height="520"></canvas>
<div><span id="result">On table: — Upright on table: —</span></div>
<p class="note">Side view. Friction from the moving cloth accelerates objects at μ·g; table friction then stops them. Tall objects tip when that acceleration beats gravity about their base. Slow = dragged off. Fast = left behind.</p>
<script>
const G=32.2, TABLE_L=0, TABLE_R=10, TABLE_Y=2.5, FLOOR=0;
const canvas=document.getElementById('c'), ctx=canvas.getContext('2d');
const speedEl=document.getElementById('speed'), speedVal=document.getElementById('speedVal');
const statusEl=document.getElementById('status'), resultEl=document.getElementById('result');
function updSpeed(){ speedVal.textContent=parseFloat(speedEl.value).toFixed(1)+' ft/s'; }
speedEl.addEventListener('input',updSpeed); updSpeed();
const DEFS=[
{name:'Glass', type:'glass', x:1.0, w:0.35,h:0.90,m:0.8, muc:0.45,mut:0.50},
{name:'Candlestick',type:'candle',x:2.0, w:0.40,h:1.10,m:1.5, muc:0.50,mut:0.45},
{name:'Glass', type:'glass', x:3.0, w:0.35,h:0.90,m:0.8, muc:0.42,mut:0.50},
{name:'Bowl', type:'bowl', x:4.2, w:0.70,h:0.35,m:2.0, muc:0.28,mut:0.45},
{name:'Plate', type:'plate',x:5.4, w:0.90,h:0.08,m:1.0, muc:0.22,mut:0.35},
{name:'Bowl', type:'bowl', x:7.2, w:0.60,h:0.50,m:1.8, muc:0.25,mut:0.40},
{name:'Plate', type:'plate',x:8.8, w:0.90,h:0.08,m:1.0, muc:0.15,mut:0.50}
];
let objs=[], cloth, pulling=false, finished=false, simTime=0;
function reset(){
objs=DEFS.map(d=>({...d, vx:0, vy:0, theta:0, omega:0, cy:TABLE_Y+d.h/2, airborne:false, tipped:false, committed:0}));
cloth={l:-0.5, r:10.5, vx:0, done:false};
pulling=false; finished=false; simTime=0;
statusEl.textContent='Set a speed and yank the cloth.';
resultEl.textContent='On table: — Upright on table: —';
}
reset();
function yank(){
if(pulling) return;
pulling=true; finished=false;
cloth.vx=parseFloat(speedEl.value);
statusEl.textContent='Yanking at '+cloth.vx.toFixed(1)+' ft/s …';
}
document.getElementById('yank').addEventListener('click',yank);
document.getElementById('reset').addEventListener('click',reset);
function eff(o){
const t=Math.abs(o.theta), c=Math.cos(t), s=Math.sin(t);
return {halfH:(o.h/2)*c+(o.w/2)*s, halfW:(o.w/2)*c+(o.h/2)*s};
}
function step(dt){
simTime+=dt;
if(pulling && !cloth.done){
cloth.l+=cloth.vx*dt; cloth.r+=cloth.vx*dt;
if(cloth.l>TABLE_R){ cloth.done=true; cloth.vx=0; }
}
for(const o of objs){
const e=eff(o);
const onTable = (o.x>=TABLE_L && o.x<=TABLE_R);
// support determination: supported if centre over table and near table height, or resting on floor
if(!o.airborne){
if(onTable && o.cy-e.halfH < TABLE_Y+0.08 && o.cy-e.halfH > TABLE_Y-0.3){
o.cy=TABLE_Y+e.halfH; o.vy=0;
} else if(!onTable){
o.airborne=true;
} else if(o.cy-e.halfH > TABLE_Y+0.08){
o.airborne=true;
}
}
let a=0;
if(!o.airborne){
const onCloth = (!cloth.done && o.x>=cloth.l && o.x<=cloth.r);
const surfV = onCloth ? cloth.vx : 0;
const mu = onCloth ? o.muc : o.mut;
const vr = o.vx - surfV;
if(Math.abs(vr)>1e-4){
a = -Math.sign(vr)*mu*G;
if(Math.abs(a*dt)>Math.abs(vr)) a=-vr/dt;
} else { o.vx=surfV; a=0; }
o.vx+=a*dt;
// tipping
const hcom=o.h/2, half=o.w/2;
const acrit=G*half/hcom;
if(!o.tipped){
if(Math.abs(o.theta)>0.4) o.committed=Math.sign(o.theta)||1;
if(o.committed){
o.omega += o.committed*9*dt;
} else if(Math.abs(a)>acrit){
const alpha=(Math.abs(a)*hcom-G*half)/(hcom*hcom+half*half)*Math.sign(a);
o.omega+=alpha*dt;
} else {
o.omega+=(-40*o.theta-6*o.omega)*dt;
}
o.theta+=o.omega*dt;
if(Math.abs(o.theta)>=Math.PI/2){ o.theta=Math.sign(o.theta)*Math.PI/2; o.omega=0; o.tipped=true; o.committed=0; }
if(Math.abs(o.theta)<0.001 && Math.abs(o.omega)<0.001){o.theta=0;o.omega=0;}
}
o.x+=o.vx*dt;
const e2=eff(o); o.cy=TABLE_Y+e2.halfH;
if(o.x<TABLE_L||o.x>TABLE_R){ o.airborne=true; o.vy=0; }
} else {
o.vy-=G*dt; o.cy+=o.vy*dt; o.x+=o.vx*dt; o.theta+=o.omega*dt;
if(Math.abs(o.theta)>Math.PI/2 && !o.tipped){ o.theta=Math.sign(o.theta)*Math.PI/2; o.omega=0; o.tipped=true; }
const e3=eff(o);
if(o.cy-e3.halfH<=FLOOR){
o.cy=FLOOR+e3.halfH;
if(o.vy<-3){ o.tipped=true; o.theta=Math.PI/2; o.omega=0; }
o.vy = Math.abs(o.vy)>1 ? -o.vy*0.18 : 0;
o.vx *= 0.6;
if(Math.abs(o.vy)<0.5){ o.vy=0; o.airborne=false; o.cy=FLOOR+e3.halfH; }
}
}
}
// collisions (1-D, same support level)
for(let i=0;i<objs.length;i++) for(let j=i+1;j<objs.length;j++){
const A=objs[i],B=objs[j];
if(A.airborne!==B.airborne) continue;
if(Math.abs(A.cy-B.cy)>0.6) continue;
const ea=eff(A), eb=eff(B);
const minDist=ea.halfW+eb.halfW;
const dx=B.x-A.x;
if(Math.abs(dx)<minDist && Math.abs(dx)>1e-6){
const overlap=minDist-Math.abs(dx), dir=Math.sign(dx);
const tot=A.m+B.m;
A.x-=dir*overlap*(B.m/tot); B.x+=dir*overlap*(A.m/tot);
const dv=B.vx-A.vx;
if(dv*dir<0){
const imp=-(1+0.3)*dv/(1/A.m+1/B.m);
A.vx-=imp/A.m; B.vx+=imp/B.m;
// collision can start a tip
if(Math.abs(imp/A.m)>1.2){ A.omega+= (imp/A.m)*1.2; A.committed=0; }
if(Math.abs(imp/B.m)>1.2){ B.omega+= (imp/B.m)*1.2; B.committed=0; }
}
}
}
if(pulling && cloth.done && !finished){
const stopped=objs.every(o=>!o.airborne && Math.abs(o.vx)<0.06 && Math.abs(o.omega)<0.08);
if(stopped){
finished=true;
const onTable=objs.filter(o=>!o.airborne && o.x>=TABLE_L && o.x<=TABLE_R && Math.abs((o.cy-eff(o).halfH)-TABLE_Y)<0.1).length;
const upright=objs.filter(o=>!o.airborne && o.x>=TABLE_L && o.x<=TABLE_R && Math.abs((o.cy-eff(o).halfH)-TABLE_Y)<0.1 && Math.abs(o.theta)<0.3).length;
resultEl.textContent='On table: '+onTable+' / '+objs.length+' Upright on table: '+upright+' / '+onTable;
statusEl.textContent='Everything has stopped.';
}
}
}
// drawing
const SCALE=88, OX=62, BASE=470;
function X(x){return OX+x*SCALE;} function Y(y){return BASE-y*SCALE;}
function draw(){
ctx.clearRect(0,0,canvas.width,canvas.height);
// floor
ctx.fillStyle='#8b6a4a'; ctx.fillRect(0,Y(0),canvas.width,canvas.height-Y(0));
ctx.fillStyle='#6e5238'; ctx.fillRect(0,Y(0),canvas.width,4);
// table
ctx.fillStyle='#7a4a26'; ctx.fillRect(X(TABLE_L),Y(TABLE_Y), (TABLE_R-TABLE_L)*SCALE, 14);
ctx.fillRect(X(0.4),Y(TABLE_Y)+14,16,Y(0)-Y(TABLE_Y)-14);
ctx.fillRect(X(9.2),Y(TABLE_Y)+14,16,Y(0)-Y(TABLE_Y)-14);
// cloth
if(!cloth.done){
const w=(cloth.r-cloth.l)*SCALE;
ctx.fillStyle='#c0392b'; ctx.fillRect(X(cloth.l),Y(TABLE_Y)-6,w,6);
ctx.fillStyle='#fff';
for(let x=cloth.l;x<cloth.r;x+=0.25){ if(Math.floor((x-cloth.l)/0.25)%2===0) ctx.fillRect(X(x),Y(TABLE_Y)-6,0.25*SCALE,6); }
ctx.fillStyle='#922b21'; ctx.fillRect(X(cloth.l),Y(TABLE_Y)-6,4,6);
}
for(const o of objs){
const e=eff(o);
ctx.save(); ctx.translate(X(o.x),Y(o.cy)); ctx.rotate(o.theta);
const w=o.w*SCALE, h=o.h*SCALE;
if(o.type==='plate'){ ctx.fillStyle='#ecf0f1'; ctx.beginPath(); ctx.ellipse(0,0,w/2,h/2,0,0,7); ctx.fill(); ctx.strokeStyle='#7f8c8d'; ctx.stroke(); }
else if(o.type==='bowl'){ ctx.fillStyle='#2980b9'; ctx.beginPath(); ctx.moveTo(-w/2,-h/2); ctx.lineTo(w/2,-h/2); ctx.lineTo(w*0.32,h/2); ctx.lineTo(-w*0.32,h/2); ctx.closePath(); ctx.fill(); ctx.fillStyle='#aed6f1'; ctx.fillRect(-w/2,-h/2,w,5); }
else if(o.type==='glass'){ ctx.fillStyle='rgba(173,216,230,0.85)'; ctx.beginPath(); ctx.moveTo(-w/2,-h/2); ctx.lineTo(w/2,-h/2); ctx.lineTo(w*0.32,h/2); ctx.lineTo(-w*0.32,h/2); ctx.closePath(); ctx.fill(); ctx.strokeStyle='#5d8aa8'; ctx.stroke(); ctx.fillStyle='#f39c12'; ctx.fillRect(-w*0.32,h*0.15,w*0.64,h*0.35); }
else if(o.type==='candle'){ ctx.fillStyle='#d4ac0d'; ctx.fillRect(-w*0.4,h*0.35,w*0.8,h*0.15); ctx.fillRect(-w*0.12,-h*0.1,w*0.24,h*0.45); ctx.fillStyle='#f9e79f'; ctx.fillRect(-w*0.08,-h*0.5,w*0.16,h*0.4); ctx.fillStyle='#e67e22'; ctx.beginPath(); ctx.ellipse(0,-h*0.52,3,6,0,0,7); ctx.fill(); }
ctx.restore();
}
if(pulling && !cloth.done){ ctx.fillStyle='#c0392b'; ctx.font='bold 16px Georgia'; ctx.fillText('➜ cloth '+cloth.vx.toFixed(1)+' ft/s', X(Math.min(cloth.r,10.2))-10, Y(TABLE_Y)-18); }
}
let last=performance.now(), acc=0;
function frame(now){
let dt=(now-last)/1000; last=now; if(dt>0.05)dt=0.05; acc+=dt;
const h=1/240; while(acc>h){ step(h); acc-=h; }
draw(); requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
// hash
const m=location.hash.match(/speed=([0-9.]+)/i);
if(m){ speedEl.value=Math.min(20,Math.max(0,parseFloat(m[1]))); updSpeed(); setTimeout(yank,1000); }
</script>
</body>
</html>
Where it behaves like the trick: motion is integrated from cloth friction $\mu_c g$, table friction $\mu_t g$, gravity, and mass-weighted collisions — there is no rule that reads the pull speed to decide slide/tip/fall. A slow pull lets objects reach cloth speed and ride off the edge; a fast pull gives them too little contact time to gain much velocity; in between, impulse $\mu_c g D/V$ differs per object because $D$, $\mu_c$, $\mu_t$, mass and geometry differ, so some slide, some tip, some fall, and trailing objects can shove leading ones.
Where it does not, and how mine fails: it is a 2-D side view, so objects cannot be knocked sideways, spin about a vertical axis, or spill liquid; support is decided by the object's centre crossing the table edge, so a half-overhanging plate does not teeter realistically. Tipping is a simplified pivot model: a spring holds an object upright below $a_{crit}=g(w/2)/h_{com}$, a constant toppling acceleration takes over once $|\theta|>0.4\ \mathrm{rad}$ (a scripted commitment threshold), and a tipped object is clamped at $90^\circ$ and never rights itself. Collisions are 1-D with restitution $0.3$ and a small collision-induced $\omega$ kick, so a hard hit can start a tip that real friction might not. The cloth is a rigid, frictionless-with-the-table strip that vanishes once its left edge clears the table; it does not bunch, fold, or drag on the floor. Falling objects bounce once at $0.18$ restitution and are forced flat on a hard floor hit ($|v_y|>3\ \mathrm{ft/s}$), there is no air drag, and the simulation declares “stopped” when all $|v_x|<0.06\ \mathrm{ft/s}$ and $|\omega|<0.08\ \mathrm{rad/s}$ on a support. In practice mine fails most often by the candlestick and the left glass tipping at mid speeds, by the right-hand bowl catching the plate and pushing it off, and — like the real trick — by a slow, confident yank dragging the whole setting onto the floor.