A generated transition between two AI video clips is an ordinary media asset at delivery time. Before you publish it, assert the things a player actually depends on: container, codec, duration, frame rate, resolution, and whether the two clips share a compatible frame size. Treat the transition as a build artifact and give it a regression check.
The fixture below is the real AI Video Clip Transitions example from Voor AI. The page currently runs Seedance 1.5 Pro with audio, and the example clip is a public file you can inspect.
Define the contract before the visual review
Write the contract in source coordinates, not by eye:
- container
mp4, video codech264, audio codecaac - a known duration in seconds (record what you requested, allow a small tolerance)
- a fixed
fpsand a fixedWxH - both clips share the same
WxH,pix_fmt, and time base
Open the AI video clip transition generator to produce a candidate. On September 12, 2026, the live form exposed Image, End frame, Prompt, Aspect ratio (16:9, 4:3, 1:1, 3:4, 9:16, 21:9, 9:21), Resolution (480p, 720p, 1080p), Duration, Generate audio, and 24 FPS. The observed model line was Seedance 1.5 Pro / Audio with a 91-credit quote and Public · watermarked visibility. Recheck the quote before spending it.
Probe the file instead of trusting the editor
ffprobe turns the contract into numbers:
ffprobe -v error -select_streams v:0 \
-show_entries stream=codec_name,width,height,r_frame_rate,nb_frames,pix_fmt \
-show_entries format=duration,format_name -of json transition.mp4
Assert the result in a small script so the check runs the same way every time:
import json, subprocess
def probe(path: str) -> dict:
out = subprocess.run(
["ffprobe", "-v", "error", "-select_streams", "v:0",
"-show_entries", "stream=codec_name,width,height,r_frame_rate,nb_frames,pix_fmt",
"-show_entries", "format=duration,format_name",
"-of", "json", path],
capture_output=True, text=True, check=True).stdout
d = json.loads(out)
stream, fmt = d["streams"][0], d["format"]
num, den = stream["r_frame_rate"].split("/")
return {
"codec": stream["codec_name"], "w": stream["width"], "h": stream["height"],
"fps": round(int(num) / int(den), 2), "frames": int(stream["nb_frames"]),
"pix_fmt": stream["pix_fmt"], "duration": round(float(fmt["duration"]), 3),
"container": fmt["format_name"],
}
def assert_contract(p, want):
assert p["codec"] == "h264", p
assert p["container"].find("mp4") >= 0, p
assert (p["w"], p["h"]) == (want["w"], want["h"]), p
assert abs(p["fps"] - want["fps"]) <= 0.01, p
assert abs(p["duration"] - want["duration"]) <= want["tol"], p
return True
Check the seam, not only the endpoints
The two frames above are the outgoing clip state and the incoming clip state. A transition can pass every container assertion and still cut on a mismatched exposure or a mirrored subject. Extract the last frame of clip A and the first frame of clip B and compare them:
ffmpeg -y -sseof -0.05 -i clipA.mp4 -frames:v 1 a_end.png
ffmpeg -y -i clipB.mp4 -frames:v 1 b_start.png
Reject a pass when the frame size, exposure, or subject orientation jumps at the seam. That is a creative failure the container check cannot see.
Limits
ffprobe proves properties, not intent. It cannot tell you that the transition looks right, that the audio stays in sync after concatenation, or that the result is safe to publish. It also cannot repair a clip; it only fails the build. Keep the contract next to the fixture so the next person can rerun it.
For a first candidate, run the transition validator against your own clip, confirm the current quote and visibility, and treat a green check as permission to review — not permission to ship.


Top comments (0)