Check pinned frames
Give it the renders of one shot, the pinned first and last stills, and the
shot's length; get back, per render, its frame count against the shot's, the
overage, SSIM of frame 0 against the first still, and the frame where it best
matches the last still. Models run long: this says whether the extra is a hold
after landing (trim it) or slower action (the take lands late). For a
first-frame-only render, pass the original shot's last frame as the last still.
SSIM here locates frames; it doesn't judge framing. Read it next to
python-measure-layout-drift, which does.
Run it
Write references/pinned-frames.md's script into the project folder as
pinned_frames.py, as is, and run it with exec python:
exec python pinned_frames.py --videos <shot>_seedance_a.mp4 <shot>_seedance_b.mp4 \
--first <shot>_first.png --last <shot>_last.png --frames 78 --fps 24 \
--out <video folder>/measurements.json
--frames and --fps are the shot's length, not the render's. --out merges
into an existing measurements file, keyed by render name.
What you get
| Field | Meaning |
|---|---|
fps, frames, duration | the render's own (frames counted, not estimated) |
target_frames, overage_frames, overage_s | the shot's length and how far past it the render runs |
ssim_frame0_vs_first | did it open on the pinned first frame |
best_last_index, landing_time_s, best_last_ssim | where it matches the last still best, and how well |
ssim_final_vs_last | the render's final frame against the last still |
tail_after_landing | frames after the landing: a hold you can trim |
Reading the numbers
- Opening: first-frame i2v holds frame 0 at ~0.996 (Kling v3) to ~0.997
(Seedance 2.5); pinned H3 Max chunks matched at 0.999. A ref2vid mode with no
first frame redraws the opening (0.2–0.5); so can a take that kept the layout
but zoomed 2%, so when frame 0 reads low, run
python-measure-layout-driftbefore rejecting it. - Lands, then holds (
tail_after_landing≥overage_frames): trim the tail to the shot's length. - Lands late (
landing_time_spast the shot's end): the action is slow. Don't speed it up (it reads badly); re-brief it to act in real time and hold the final pose, or start the trim later to skip an idle opening. - Pinned end frames sit past the requested length: H3 Max ran 0.05–0.7 s over, so the true end frame lies after the cut; at the cut the frame still matched the still at 0.996–0.999.
best_last_ssimwell under the opening's means it never reached the last still: look at the take before trimming.
Tips and traps
- Check the render's frame rate first (
ffprobe-inspect-media): a 25 or 30 fps render against a 24 fps shot changes every frame count here. - Both curves are computed in greyscale at 480 px wide: good for finding frames,
too coarse for grading detail (
python-measure-detaildoes that). - Put the landing frame and overage in the candidate's note on the review page.
Check it
Run it on the source shot itself with its own first and last frames: frame 0 reads ~1.0, it lands on its last frame, and the overage is 0.


