Pelican on a bicycle: Kimi K3.1 Pro vs DeepSeek V4.1 Flash, measured

Same one-line brief, two models at their maximum reasoning setting, five days apart. The first page solves the legs with inverse kinematics. The second spins its wheels 2.3 times faster than the road it rides on.

Neither fact shows up in a screenshot. Both are a few lines of code away from being right.

The brief

"Generate an SVG of a pelican riding a bicycle" is Simon Willison's unofficial benchmark, and it has been running long enough that his blog holds 152 posts under that tag. A Chinese-language variant asks for an HTML page with a 2D SVG animation instead of a still, which produces much longer artefacts. The pelican gallery has collected 187 of them from 50 models as of 19 October 2026, with model, reasoning effort, harness, wall-clock time and cost attached to each run.

There is a small literature on what this test does and does not measure. Dylan Castillo ran 48 prompts, eight animals by six vehicles, three samples each, through seven models, and found no evidence that any lab has trained specifically for pelicans on bicycles.

Both builds here came from that animation brief. One line, no constraints.

Build A is DeepSeek V4.1 Flash 1017 at max reasoning, 19 October. Build B is Kimi K3.1 Pro at max reasoning, 24 October, with an English variant of the same page two minutes after the Chinese one.

What people check when they look at one is mostly anatomy. Willison's notes read like a vet's report: "feet on either side of the frame touching the pedals", "chain in the right place", "a good beak and pouch". Readers of the gallery do the same in the comments: is the bird recognizable, is the frame the right shape, is the pouch big enough.

None of that is about mechanics. For a still image it does not need to be. For an animation, the mechanics are the difference between a drawing that moves and a bicycle.

Three checks, all cheap:

  • Does the leg reach the pedal, on every frame?
  • Does the wheel turn at the speed the road moves?
  • Is there a gear ratio between the crank and the wheel?

The two builds fail differently.

Build A: DeepSeek solves the legs

397 lines, 16.7 KB. The scene is CSS @keyframes throughout: wheels, hills, clouds, a drifting ground tile, speed lines.

A pelican riding a bicycle
DeepSeek V4.1 Flash 1017, max reasoning, 19 October. Live, as shipped: the legs are solved frame by frame from the crank angle, and the feet stay on the pedals through the whole stroke.

That ground tile is 300 px wide and takes 1.35 s to travel its own width, so the road moves at 222 px/s. The wheels are r=55 and turn once every 1.5 s, which puts the rim at 230 px/s. Three point seven percent too fast. Nobody notices 3.7 percent, which is presumably why it survived.

The legs are the interesting part. There is no keyframed pose anywhere. A two-bone IK solver runs on every frame.

var CX = 455, CY = 425, R = 22;   // bottom bracket, crank radius
var HX = 433, HY = 322;           // hip, fixed under the body
var L1 = 68, L2 = 68;             // thigh, shin
var PERIOD = 1.1;                 // seconds per pedal revolution

function solveKnee(fx, fy) {
  var dx = fx - HX, dy = fy - HY;
  var d = Math.hypot(dx, dy);
  var cosA = (L1*L1 + d*d - L2*L2) / (2*L1*d);   // law of cosines
  var a1 = Math.acos(Math.min(1, Math.max(-1, cosA)));
  var base = Math.atan2(dy, dx);
  // knee placed on the forward side of the hip-to-pedal chord
}

Each frame it takes the pedal position from the crank angle, clamps it if the leg cannot reach, solves for the knee, and rewrites one polyline. The reach margin is 8.7 px: the hip sits 105 px from the bottom bracket, the pedal swings out to 127 px, the leg is 136 px. The foot never leaves the pedal, not even at the bottom of the stroke.

Two more numbers, both easy to get wrong. The wheel period is 1.5 s against a 1.1 s crank, a 1.36:1 ratio. Low for a bicycle, where 2.5 to 3:1 is normal, but a ratio. And the body bob is Math.sin(a * 2) * 2.5, twice per revolution, which is once per leg push.

Build B: Kimi directs the eye

556 lines, 25 KB. No JavaScript runs the animation. Twenty-seven <animate> and <animateTransform> elements do all of it, and the only script on the page wires a pause button to pauseAnimations().

A pelican riding a bicycle by the sea A pelican in a coral scarf rides a bicycle along a coastal road. The wheels and pedals spin, its feet take turns pedaling, and the birds, clouds, waves, and road markings move in a continuous loop.
Kimi K3.1 Pro, max reasoning, 24 October. Live, as shipped, plus a pause control. The same brief in one page of SMIL. Keep an eye on the dashed road line under the wheels.

That is a real win in one direction: block JavaScript and this page keeps moving. Build A loses its legs, which stay in the single pose the markup ships.

The character work is better as well. The eye blinks, ry dropping to 0.7 for about 6 percent of a 4.2 s cycle. The pouch wobbles on its own 2.8 s loop. The scarf ends oscillate on two periods, 1.8 s and 1.55 s. The tail flicks, the sun's rays turn once a minute, a sailboat bobs in the distance. None of it is necessary. All of it reads.

Then the legs. No solver. Four keyframes on the d attribute per leg, plus a separate foot path translated through four points that sit 30 px from the crank centre, matching the crank arm exactly. The feet do land on the pedals. Between keyframes the knee travels in straight lines and the ankle angle never changes, but at 1.4 s per revolution you will not see it.

Now the two numbers that will.

The wheels are r=88 and turn once every 1.4 s, which is 395 px/s at the rim. The road is a dashed line on a 180 px pitch, translated 180 px every 1.05 s, or 171 px/s. The wheels spin 2.3 times faster than the road goes. To roll without slipping, the wheel would need 3.23 s per revolution, or the road 0.46 s.

Crank and wheels share that 1.4 s period, which makes it a 1:1 drive: on a real bicycle it would mean pedals bolted straight to the rear axle, no chainring, no chain. The chain this build never drew is, formally, missing.

Body bob runs one 1.4 s cycle per crank revolution, so the rider rises once per two leg pushes. Build A got that right by writing sin(2a), and nobody would have noticed if it had not.

Side by side

Build A, DeepSeek Build B, Kimi
Size 397 lines, 16.7 KB 556 lines, 25 KB
Animation CSS keyframes plus rAF SMIL, 27 elements
Legs two-bone IK, solved per frame four keyframes per leg
Foot on pedal always, 8.7 px to spare at keyframes only
Wheel vs road 230 vs 222 px/s 395 vs 171 px/s
Wheel to crank 1.36:1 1:1
Bobs per revolution 2 1
JavaScript blocked legs freeze animates
Screen readers aria-label, reduced motion, no pause title, desc, labelled, pausable

Neither build is the better one. A is the better bicycle. B is the better picture, and the only one that survives with scripting off.

What "make it English" changed

Kimi shipped an English variant two minutes after the Chinese one. The diff is 14 line pairs: the page title, the h1 and subtitle, both button labels, the SVG title and description, and the two strings the pause button writes. Twenty-five Chinese comments came through untouched, along with a font stack still asking for PingFang SC and Microsoft YaHei.

That is the default shape of a localisation request, strings rather than code, and it is what we asked for. Treat it as a measurement of the phrase, not a complaint.

The DeepSeek build had no English variant, so we wrote one: four visible strings and 44 comments, plus lang="en". Both demos embedded above carry that second, fuller pass. Comments are read by whoever maintains the page next, and a CJK fallback chain on an English page buys nothing unless a glyph is missing.

What we did not touch, in either file, is a single coordinate or duration. Strip the comments from both and every number in the markup is identical to the model's output.

Checking this takes thirty lines

Everything above is arithmetic on two attributes: the wheel radius, and the dur on its rotation. Find every circle inside a rotating group, divide 2πr by the period, do the same for whatever scrolls the ground, compare. On these two files that is about thirty lines of Python and no browser.

We have not run it across the gallery's 187 entries. That is the next cut, and I would bet the prettiest pelicans are not the ones with working drivetrains.


Wallaby runs inference for open-weight models on an OpenAI-compatible endpoint, and we test models on our own time because output shape is what customers buy. Neither page here is a product claim about either model. Both are model output, with strings and comments translated and nothing else. wallabytoken.com

Like the Dispatch? Add Wallaby as a preferred source on Google, or subscribe via RSS.
Did this help?