47:51Ranking major U.S. Open-Weights Models. (Where does Ripple 65B fit in?)
Nov 6, 2026 · YouTube
38:58Testing Particle-1: a post-trained DeepSeek V4.1 Flash specializing in coding and efficiency
Oct 28, 2026 · YouTube
29:55Kimi K3.1 Pro Looked Incredible. Then I Kept Testing.
Oct 26, 2026 · YouTube
22:47Mistral Large 4 Is Cheap. But Is It Good Enough to Compete?
Oct 6, 2026 · YouTube
16:54Stealth Union Alpha: Is this another cheap GPT model? (better than Luna, cheaper than Terra?)
Sep 16, 2026 · YouTube
16:45DeepSeek V4.1 Flash Is Shockingly Good for the Price
Sep 10, 2026 · YouTube
17:14How much better is GPT-6 Astra over Claude Opus 5? Real Website and Coding Tests
Sep 5, 2026 · YouTube
29:13Implementing a multiplayer game with GPT-6 Astra (+ Gemini 3.8, Opus 5, Sol Pro)
Sep 5, 2026 · YouTube
19:42Meta Muse Spark 1.3 Review: A Huge Leap Forward
Sep 2, 2026 · YouTube
17:31Testing Gemini 3.8 Flash on Real Coding Challenges (vs. other models)
Sep 2, 2026 · YouTube
You are a graphics engineer who has spent a lot of time finding out why things are slow.
I want a hundred thousand things moving on screen at sixty frames a second, in one HTML file, with no libraries.
data: URIs are fine.localStorage, sessionStorage, cookies or indexedDB — sandboxed frame, they throw.html block.One paragraph, before the file. Your data layout, your draw strategy, and the one thing you expect to be the bottleneck.
The single fenced html block.
This is the section I care most about. Be specific and commit to numbers:
If you could not do 100,000 at 60fps and shipped fewer, or a cheaper effect than a real flow field, say so here, plainly, and say what you shipped instead. Write Nothing dropped. if you delivered the brief in full.
I am going to open the file and read the FPS counter.
Then I am going to compare it against your prediction. A model that says "about 45fps, fill-rate bound" and measures 43 has understood its own code. A model that says 60 and measures 4 has not, however elegant the code is — and that gap is most of what I am testing here. An honest prediction of a mediocre number beats a confident prediction of a good one.
Four Float32Array buffers of length 100,000 (px, py, pvx, pvy) — cache-friendly Structure-of-Arrays, no per-particle object overhead. The flow field is held as a 150 × 100 grid; per frame I resample a 2D value-noise scalar potential onto that grid with a slow time offset, then derive the velocity field by central finite-difference curl of the potential (u = ∂ψ/∂y, v = −∂ψ/∂x). The result is genuinely divergence-free, so particles form eddies instead of piling at sinks. Each particle bilinearly samples the field, blends toward it, integrates, and wraps. Draw strategy: one Path2D of 100,000 moveTo+lineTo pairs (short segments showing instantaneous velocity), a single stroke(), with a rgba(0,0,6,0.16) fillRect over the canvas each frame to give the "ink in water" decay. The bottleneck I expect is the Path2D stroke + alpha blend of 100k short segments on integrated graphics, plus the 200k FFI calls into Canvas2D to build the path.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Flow Field — 100k</title>
<style>
html, body { margin: 0; padding: 0; background: #000; overflow: hidden; font: 12px/1.5 ui-monospace, Menlo, Consolas, monospace; }
canvas { display: block; }
#hud { position: fixed; top: 8px; left: 10px; color: #b8dcff; text-shadow: 0 0 6px #000; pointer-events: none; }
#hud b { color: #fff; font-weight: 600; }
</style>
</head>
<body>
<canvas id="c" width="900" height="600"></canvas>
<div id="hud">
<div><b id="fps">--</b> fps · <b id="ft">--</b> ms / frame</div>
<div>particles: <b id="cnt">--</b></div>
</div>
<script>
(() => {
'use strict';
const c = document.getElementById('c');
const $ = c.getContext('2d', { alpha: false, desynchronized: true });
const W = c.width, H = c.height;
const fpsEl = document.getElementById('fps');
const ftEl = document.getElementById('ft');
const cntEl = document.getElementById('cnt');
// --- particles: Structure-of-Arrays, all 100k individually held & updated ---
const N = 100000;
const px = new Float32Array(N);
const py = new Float32Array(N);
const pvx = new Float32Array(N);
const pvy = new Float32Array(N);
for (let i = 0; i < N; i++) {
px[i] = Math.random() * W;
py[i] = Math.random() * H;
pvx[i] = (Math.random() - 0.5) * 0.3;
pvy[i] = (Math.random() - 0.5) * 0.3;
}
cntEl.textContent = px.length.toLocaleString();
// --- flow field: scalar potential -> curl -> (u, v); genuinely divergence-free ---
const FW = 150, FH = 100;
const psi = new Float32Array(FW * FH);
const fU = new Float32Array(FW * FH);
const fV = new Float32Array(FW * FH);
const FX_INV = (FW - 1) / W;
const FY_INV = (FH - 1) / H;
// Fast 2D value noise (hash + smoothstep interp)
const INV2_32 = 1 / 4294967295;
function hash2(x, y) {
let h = (Math.imul(x | 0, 73856093) ^ Math.imul(y | 0, 19349663)) | 0;
h = Math.imul(h ^ (h >>> 15), 0x5bd1e995);
return ((h >>> 0) * INV2_32) * 2 - 1;
}
function sm(t) { return t * t * (3 - 2 * t); }
function noise(x, y) {
const xi = x | 0, yi = y | 0;
const xf = x - xi, yf = y - yi;
const u = sm(xf), v = sm(yf);
const a = hash2(xi, yi);
const b = hash2(xi + 1, yi);
const c = hash2(xi, yi + 1);
const d = hash2(xi + 1, yi + 1);
return (a * (1 - u) + b * u) * (1 - v) + (c * (1 - u) + d * u) * v;
}
let T = 0;
function regen() {
const sc = 0.075;
const ts = T * 0.35;
// 1) sample scalar potential onto the grid; slow time offset = evolving field
for (let j = 0; j < FH; j++) {
const yb = j * sc;
const row = j * FW;
for (let i = 0; i < FW; i++) {
psi[row + i] = noise(i * sc + ts, yb - ts * 0.7);
}
}
// 2) curl of the potential -> (u, v), toroidal wrap
const sc2 = 2.0;
for (let j = 0; j < FH; j++) {
const jn = j === 0 ? FH - 1 : j - 1;
const jp = j === FH - 1 ? 0 : j + 1;
const rN = jn * FW, rP = jp * FW, rJ = j * FW;
for (let i = 0; i < FW; i++) {
const in_ = i === 0 ? FW - 1 : i - 1;
const ip = i === FW - 1 ? 0 : i + 1;
fU[rJ + i] = (psi[rP + i] - psi[rN + i]) * sc2;
fV[rJ + i] = -(psi[rJ + ip] - psi[rJ + in_]) * sc2;
}
}
}
// --- honest rolling-average frame-time meter ---
const FN = 60;
const fb = new Float32Array(FN);
let fi = 0, fc = 0, fs = 0, lt = performance.now();
// prime the canvas
$.fillStyle = '#000';
$.fillRect(0, 0, W, H);
function frame() {
const now = performance.now();
const raw = now - lt;
lt = now;
const dt = raw > 100 ? 100 : raw; // ignore tab-switch spikes
if (fc < FN) { fs += dt; fb[fi] = dt; fc++; }
else { fs += dt - fb[fi]; fb[fi] = dt; }
fi = (fi + 1) % FN;
const avg = fs / fc;
T += dt * 0.001;
regen();
// --- per-particle update: bilinear sample of field, blend, integrate, wrap ---
const st = FW;
const lerp = 0.07;
for (let i = 0; i < N; i++) {
const x = px[i], y = py[i];
const gx = x * FX_INV;
const gy = y * FY_INV;
const gi = gx | 0;
const gj = gy | 0;
const idx = gj * st + gi;
const fx = gx - gi;
const fy = gy - gj;
const u00 = fU[idx], u10 = fU[idx + 1];
const u01 = fU[idx + st], u11 = fU[idx + st + 1];
const v00 = fV[idx], v10 = fV[idx + 1];
const v01 = fV[idx + st], v11 = fV[idx + st + 1];
const u0 = u00 + (u10 - u00) * fx;
const u1 = u01 + (u11 - u01) * fx;
const v0 = v00 + (v10 - v00) * fx;
const v1 = v01 + (v11 - v01) * fx;
const u = u0 + (u1 - u0 ) * fy;
const v = v0 + (v1 - v0 ) * fy;
const nvx = pvx[i] + (u - pvx[i]) * lerp;
const nvy = pvy[i] + (v - pvy[i]) * lerp;
pvx[i] = nvx;
pvy[i] = nvy;
let nx = x + nvx;
let ny = y + nvy;
if (nx >= W) nx -= W; else if (nx < 0) nx += W;
if (ny >= H) ny -= H; else if (ny < 0) ny += H;
px[i] = nx;
py[i] = ny;
}
// --- draw: fade the previous frame, then a single stroked path of 100k short velocity ticks ---
$.fillStyle = 'rgba(0, 0, 6, 0.16)';
$.fillRect(0, 0, W, H);
$.strokeStyle = 'rgba(170, 215, 255, 0.7)';
$.lineWidth = 1;
$.beginPath();
for (let i = 0; i < N; i++) {
const x = px[i], y = py[i];
const vx = pvx[i], vy = pvy[i];
$.moveTo(x, y);
$.lineTo(x + vx * 1.4, y + vy * 1.4);
}
$.stroke();
fpsEl.textContent = (1000 / avg).toFixed(1);
ftEl.textContent = avg.toFixed(2);
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
})();
</script>
</body>
</html>
drawArraysInstanced call with no JS per-particle work and no FFI. That is the technique — not "optimize more".Nothing dropped.