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.
Keep particle state in two GPU buffers, each holding 100,000 interleaved (x, y, vx, vy) records. Handwritten WebGL2 transform feedback updates every particle and rasterizes its new position in the same draw call, then swaps buffers. The flow is the analytic curl of three slowly changing wave functions, with drift and velocity inertia—not random kicks or a static texture. A persistent framebuffer supplies fading trails. FPS comes from a rolling average of actual animation-frame intervals; the displayed count comes from the particle buffer’s byte size. I expect the bottleneck to be the per-particle vertex-shader field evaluation.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>100,000 — evolving flow</title>
<style>
* { box-sizing: border-box; }
html, body { margin: 0; min-height: 100%; background: #060b13; }
body {
display: grid;
place-items: center;
min-height: 100vh;
color: #d9f5ff;
font-family: ui-monospace, Consolas, monospace;
}
main {
position: relative;
width: 900px;
max-width: 100vw;
box-shadow: 0 0 60px #0008;
}
canvas {
display: block;
width: 100%;
height: auto;
background: #02060d;
}
#hud {
position: absolute;
top: 12px;
left: 12px;
padding: 10px 13px;
background: #04101ee8;
border: 1px solid #91d7ff30;
border-radius: 6px;
pointer-events: none;
font-size: 13px;
line-height: 1.7;
font-variant-numeric: tabular-nums;
}
#fps, #count { color: #8fffe5; }
.small { color: #87a3b6; font-size: 11px; }
#error {
position: absolute;
inset: 100px 20px auto;
background: #28121e;
color: #ffd8de;
white-space: pre-wrap;
padding: 18px;
}
[hidden] { display: none !important; }
</style>
</head>
<body>
<main>
<canvas id="canvas" width="900" height="600"
aria-label="One hundred thousand particles moving through evolving fluid-like flow"></canvas>
<div id="hud">
<div><span id="fps">Measuring…</span> <span class="small">rolling frame-time average</span></div>
<div><span id="count">Initializing…</span> particles</div>
<div class="small">900 × 600 · GPU update + individual point draw</div>
</div>
<pre id="error" hidden></pre>
</main>
<script>
"use strict";
(() => {
const errorBox = document.getElementById("error");
try {
const canvas = document.getElementById("canvas");
const fpsElement = document.getElementById("fps");
const countElement = document.getElementById("count");
const W = canvas.width, H = canvas.height;
const STRIDE = 4 * Float32Array.BYTES_PER_ELEMENT;
const gl = canvas.getContext("webgl2", {
alpha: false,
antialias: false,
depth: false,
stencil: false,
preserveDrawingBuffer: false,
powerPreference: "high-performance"
});
if (!gl) throw new Error(
"WebGL2 is required. No reduced-particle fallback is substituted."
);
function shader(type, source) {
const s = gl.createShader(type);
gl.shaderSource(s, source);
gl.compileShader(s);
if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {
throw new Error(gl.getShaderInfoLog(s));
}
return s;
}
function program(vertexSource, fragmentSource, feedbackNames) {
const p = gl.createProgram();
const vs = shader(gl.VERTEX_SHADER, vertexSource);
const fs = shader(gl.FRAGMENT_SHADER, fragmentSource);
gl.attachShader(p, vs);
gl.attachShader(p, fs);
if (feedbackNames) {
gl.transformFeedbackVaryings(
p, feedbackNames, gl.INTERLEAVED_ATTRIBS
);
}
gl.linkProgram(p);
if (!gl.getProgramParameter(p, gl.LINK_STATUS)) {
throw new Error(gl.getProgramInfoLog(p));
}
gl.deleteShader(vs);
gl.deleteShader(fs);
return p;
}
const particleProgram = program(
`#version 300 es
precision highp float;
layout(location = 0) in vec4 state;
uniform vec2 extent;
uniform vec4 phase;
uniform float dt;
uniform float follow;
out vec4 nextState;
out vec3 ink;
void main() {
vec2 p = state.xy;
float a = p.x * 0.009 + phase.x;
float b = p.y * 0.009 + phase.y;
float c = (p.x - p.y) * 0.015 + phase.z;
float d = (p.x + 2.0 * p.y) * 0.006 + phase.w;
// Curl of a time-dependent streamfunction:
//
// psi = (46/.009) sin(a) sin(b)
// - (20/.015) sin(c)
// + (14/.006) sin(d)
//
// velocity = (d psi/dy, -d psi/dx) + uniform drift.
// The target field is smooth and divergence-free.
float cc = cos(c);
float cd = cos(d);
vec2 flow = vec2(
46.0 * sin(a) * cos(b) + 20.0 * cc + 28.0 * cd,
-46.0 * cos(a) * sin(b) + 20.0 * cc - 14.0 * cd
) + vec2(15.0, -5.0);
// Each particle retains its own velocity, with finite response time.
vec2 velocity = mix(state.zw, flow, follow);
p = mod(p + velocity * dt, extent);
// This record is written to the other GPU buffer by transform feedback.
nextState = vec4(p, velocity);
// Rasterize this very same updated particle; no instanced substitutes.
gl_Position = vec4(p / extent * 2.0 - 1.0, 0.0, 1.0);
gl_PointSize = 1.0;
float speed = clamp(length(velocity) / 100.0, 0.0, 1.0);
ink = mix(vec3(0.12, 0.39, 0.72),
vec3(0.48, 0.96, 0.80), speed);
}`,
`#version 300 es
precision mediump float;
in vec3 ink;
out vec4 color;
void main() {
color = vec4(ink, 0.085);
}`,
["nextState"]
);
const fadeProgram = program(
`#version 300 es
precision highp float;
void main() {
vec2 p = vec2(
float((gl_VertexID << 1) & 2),
float(gl_VertexID & 2)
);
gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);
}`,
`#version 300 es
precision mediump float;
uniform float fade;
out vec4 color;
void main() {
color = vec4(0.006, 0.012, 0.026, fade);
}`
);
const uExtent = gl.getUniformLocation(particleProgram, "extent");
const uPhase = gl.getUniformLocation(particleProgram, "phase");
const uDt = gl.getUniformLocation(particleProgram, "dt");
const uFollow = gl.getUniformLocation(particleProgram, "follow");
const uFade = gl.getUniformLocation(fadeProgram, "fade");
// CPU seed data is uploaded once. Current particle state thereafter
// lives entirely in the two GPU buffers.
const states = [];
{
const seed = new Float32Array(100000 * 4);
let rng = 0x12345678;
function random() {
rng ^= rng << 13;
rng ^= rng >>> 17;
rng ^= rng << 5;
return (rng >>> 0) / 4294967296;
}
for (let i = 0; i < seed.length; i += 4) {
seed[i] = random() * W;
seed[i + 1] = random() * H;
seed[i + 2] = 0;
seed[i + 3] = 0;
}
for (let i = 0; i < 2; ++i) {
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, seed, gl.DYNAMIC_COPY);
// Count is derived from the actual allocated particle buffer.
const count =
gl.getBufferParameter(gl.ARRAY_BUFFER, gl.BUFFER_SIZE) / STRIDE;
const vao = gl.createVertexArray();
gl.bindVertexArray(vao);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 4, gl.FLOAT, false, STRIDE, 0);
states.push({ buffer, vao, count });
}
}
gl.bindVertexArray(null);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
const feedback = gl.createTransformFeedback();
const emptyVAO = gl.createVertexArray();
// Persistent trails use an explicit framebuffer, not an assumption
// that the browser preserves the default framebuffer between frames.
const trailTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, trailTexture);
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, W, H);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
const trailFBO = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, trailFBO);
gl.framebufferTexture2D(
gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D, trailTexture, 0
);
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !==
gl.FRAMEBUFFER_COMPLETE) {
throw new Error("Could not allocate the trail framebuffer.");
}
gl.viewport(0, 0, W, H);
gl.clearColor(0.006, 0.012, 0.026, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.disable(gl.DEPTH_TEST);
gl.disable(gl.DITHER);
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.useProgram(particleProgram);
gl.uniform2f(uExtent, W, H);
let current = 0;
function showActualCount() {
gl.bindBuffer(gl.ARRAY_BUFFER, states[current].buffer);
const bytes =
gl.getBufferParameter(gl.ARRAY_BUFFER, gl.BUFFER_SIZE);
countElement.textContent = (bytes / STRIDE).toLocaleString("en-US");
gl.bindBuffer(gl.ARRAY_BUFFER, null);
}
showActualCount();
// Average frame TIME, then invert. Never average instantaneous FPS.
const frameTimes = new Float64Array(120);
let sampleIndex = 0, sampleCount = 0, timeSum = 0;
let previous = null, lastHud = -Infinity, simulationTime = 0;
let running = true;
canvas.addEventListener("webglcontextlost", event => {
event.preventDefault();
running = false;
fpsElement.textContent = "Stopped";
errorBox.hidden = false;
errorBox.textContent = "Graphics context lost. Reload to restart.";
});
function frame(now) {
if (!running) return;
let elapsed = 1000 / 60;
if (previous !== null) {
elapsed = now - previous;
timeSum -= frameTimes[sampleIndex];
frameTimes[sampleIndex] = elapsed;
timeSum += elapsed;
sampleIndex = (sampleIndex + 1) % frameTimes.length;
sampleCount = Math.min(sampleCount + 1, frameTimes.length);
}
previous = now;
// Cap simulation jumps after a suspended tab, but NOT FPS samples.
const dt = Math.min(elapsed * 0.001, 0.05);
simulationTime += dt;
gl.bindFramebuffer(gl.FRAMEBUFFER, trailFBO);
// Fade existing trails in place. No texture is sampled while attached.
gl.useProgram(fadeProgram);
gl.bindVertexArray(emptyVAO);
gl.uniform1f(uFade, 1 - Math.exp(-2.4 * dt));
gl.drawArrays(gl.TRIANGLES, 0, 3);
const source = states[current];
const destination = states[current ^ 1];
gl.useProgram(particleProgram);
gl.uniform1f(uDt, dt);
gl.uniform1f(uFollow, 1 - Math.exp(-2.4 * dt));
// Different phase speeds change both the field's position and shape.
const tau = Math.PI * 2;
gl.uniform4f(
uPhase,
(simulationTime * 0.071) % tau,
(simulationTime * -0.053) % tau,
(simulationTime * 0.109 + 1.7) % tau,
(simulationTime * -0.083 + 0.4) % tau
);
gl.bindVertexArray(source.vao);
gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, feedback);
gl.bindBufferBase(
gl.TRANSFORM_FEEDBACK_BUFFER, 0, destination.buffer
);
// Rasterizer discard intentionally stays OFF:
// one invocation updates one particle and draws its one-pixel point.
gl.beginTransformFeedback(gl.POINTS);
gl.drawArrays(gl.POINTS, 0, source.count);
gl.endTransformFeedback();
gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, null);
gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
gl.bindVertexArray(null);
current ^= 1;
// Present the completed trail image without CPU readback.
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, trailFBO);
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
gl.blitFramebuffer(
0, 0, W, H, 0, 0, W, H,
gl.COLOR_BUFFER_BIT, gl.NEAREST
);
if (now - lastHud >= 250) {
if (sampleCount && timeSum > 0) {
fpsElement.textContent =
(sampleCount * 1000 / timeSum).toFixed(1) + " FPS";
}
showActualCount();
lastHud = now;
}
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
} catch (error) {
document.getElementById("fps").textContent = "Unavailable";
errorBox.hidden = false;
errorBox.textContent = String(error.message || error);
}
})();
</script>
</body>
</html>
Nothing dropped.