Methodology

Votes

Each battle shows one prompt and two clips side by side, in random order. Names stay hidden until you vote: left, right, tie or both bad.

Voting opens once both clips have played, and votes sent within a few seconds of loading are not counted. Each battle takes one vote, and each visitor is limited per hour. Addresses are never stored, only a daily one-way hash.

Scores

Scores are a Bradley-Terry fit over all pairwise votes, shown as 1000 + 400 × log10(strength). A tie or both bad counts as half a win for each side. A 100 point gap means the higher model is preferred about 64% of the time.

The 95% interval comes from 200 bootstrap resamples. Models with fewer than 30 votes are marked preliminary. Category boards use only votes on that category's prompts.

Clips

Every clip in this round was made on 2026-10-20 with image to video from the same start frame and the same motion prompt, with audio off. Clip length follows each model's nearest option to 5 seconds (4 to 6 seconds).

Clips run at 720p, except Seedance 2.5 at 480p and Hailuo 02 at 768p. Each clip was re-encoded to the same H.264 settings for the web. Nothing was cherry-picked: each model got one take per prompt. One start frame that came out sideways was regenerated, and every model was re-run on the new frame.

Generation time

Generation time is the median seconds from submitting a clip to receiving it in this round, including queue time. It varies by provider and load.

Prices

Public list prices, not Korpi costs. The leaderboard compares a 5 second clip.

Questions

How are the video models ranked?
Visitors watch two clips made from the same start frame and prompt without seeing the model names, then pick the better one, a tie or both bad. Scores come from a Bradley-Terry fit on every vote, the method LMArena uses, shown on an Elo-like scale centred on 1000.
What does the score interval mean?
It is a 95% bootstrap interval. When two models' intervals overlap, the arena cannot yet say which is better, so their rank is shown as a range.
Where do the prices come from?
Each price is the model maker's own API list price when they publish one, otherwise a public marketplace list price. Every price links to its source and shows the date it was checked. They are not Korpi's costs.
Why are some models missing?
A model joins when it can be run through an API for the same image-to-video test. Sora 2 and newer models are not in this round.

Make this video in Korpi

Script, scenes, voice and captions in one place.

Run Grok Imagine via the API

Pay per clip on api.korpi.ai

Get API key
JavaScript
async function readResponse(response) {
  const result = await response.json();
  if (!response.ok || result.error || result.status === "failed") {
    throw new Error(JSON.stringify(result));
  }
  return result;
}

const res = await fetch("https://backend.korpi.ai/v1/videos/generations", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.KORPI_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "model": "grok-imagine",
    "prompt": "A girl with a red scarf turns toward the camera on a neon rooftop at dusk",
    "aspect_ratio": "9:16",
    "duration": 6
  }),
});
let result = await readResponse(res);

const deadline = Date.now() + 30 * 60_000;
while (true) {
  let next = result.result_url;
  if (!next && ["queued", "in_progress", "pending"].includes(result.status)) {
    next = `https://backend.korpi.ai/v1/videos/generations/${result.id}`;
  }
  if (!next) break;
  if (Date.now() >= deadline) throw new Error("Polling timed out");
  await new Promise((resolve) => setTimeout(resolve, 3000));
  const poll = await fetch(new URL(next, "https://backend.korpi.ai"), {
    headers: { Authorization: `Bearer ${process.env.KORPI_API_KEY}` },
  });
  result = await readResponse(poll);
}
console.log(result);