---
name: burst-photo-processing
description: Identify true camera bursts from RAW or JPEG shoots, create vision-readable previews, validate motion continuity, and render organized forward-reverse video clips. Use for repeatable burst-photo processing and burst-to-video work; do not use for unrelated photo sorting.
---

# Burst-to-video workflow

Preserve original photos. Build plans, preview caches, grouped symlink folders, and rendered media in new output directories; never move, rename, overwrite, or delete RAW/JPEG originals without explicit authorization.

## Choose the source at each stage

- Use CR3 capture metadata and embedded previews for early grouping. This avoids developing every RAW before knowing which frames belong together.
- Vision models should not receive CR3 files directly. Use [scripts/extract_cr3_previews.py](scripts/extract_cr3_previews.py) to create oriented JPEG proxies plus a manifest back to every CR3. Give the vision model those proxies while retaining CR3 metadata as the source of truth for timing and identity.
- Do not treat an FFmpeg decode of CR3 as a final-quality Lightroom replacement; it may use an embedded camera preview and it omits the user's Lightroom treatment.
- Render final clips from filename-matched Lightroom exports. Prefer full-resolution 16-bit TIFF, sRGB, with no resizing for the strongest editing source. Full-resolution quality-95-to-100 JPEG in sRGB is the efficient alternative.
- When Lightroom exports do not exist and the user authorizes direct RAW development, use [scripts/render_cr3_boomerangs.py](scripts/render_cr3_boomerangs.py). Its `developed` mode uses full CR3 sensor data through `dcraw_emu`; its faster `embedded` mode uses the full-size camera JPEG stored inside each CR3 and must not be described as 16-bit RAW development.
- For already-exported JPEG jobs, inspect their actual pixel dimensions before describing them as full quality.

## Group and qualify bursts

1. Sort on `DateTimeOriginal` plus `SubSecTimeOriginal`, with the numeric filename as the stable tiebreaker.
2. Distinguish a shoot/session cluster from a true shutter burst. Start a new true burst when the gap between adjacent captures exceeds 0.25 seconds for the observed 6, 8, and 10 fps modes. Treat 0.25 seconds as a camera-specific default to validate, not a universal constant.
3. Infer playback cadence from short within-run gaps and snap to the camera's observed 6, 8, or 10 fps modes.
4. Visually inspect sampled frames across every candidate and both sides of its largest time gaps. Split on a genuine action/scene discontinuity; do not certify grouping from timestamps alone.
5. Keep true bursts with at least five source photographs by default. Put one-to-four-frame fragments in `Fragments_Review`; do not discard them.
6. Apply the three-second rule to the finished clip, not to the amount of unique motion. Preserve the detected capture cadence and repeat whole endpoint-deduplicated ping-pong cycles until the finished clip is at least three seconds. Never merge separate shutter bursts merely to reach the duration target.

Use [scripts/plan_bursts.py](scripts/plan_bursts.py) for a deterministic timing plan from a flat RAW/JPEG source. When existing folders may combine several shutter bursts, run [scripts/analyze_true_bursts.py](scripts/analyze_true_bursts.py), then [scripts/build_true_burst_groups.py](scripts/build_true_burst_groups.py) to create non-destructive symlink groups plus kept/review manifests. Use extracted CR3 proxies for the visual boundary audit, not as final-quality render sources. Read [references/workflow.md](references/workflow.md) when choosing Lightroom export, ProRes, framing, or social-delivery settings.

## Render boomerangs

Build the frame order as `first ... last ... second`, omitting duplicated endpoint frames at both turns. Keep whole ping-pong cycles intact when repeating to the requested finished duration. Never create a visual pause at the turnaround. For a five-frame burst at 10 fps, the eight-frame cycle is 0.8 seconds and repeats four times to make a 3.2-second clip.

- Prefer ProRes 422 HQ, 10-bit, for a DaVinci editing master when the source is full-resolution TIFF or high-quality JPEG.
- Prefer H.264 High profile, yuv420p, Rec.709 for preview and social delivery.
- Preserve the full 2:3 photo composition in the master unless the user approves a 9:16 crop. For full-resolution sources, 2560x3840 is a useful vertical master; deliver Instagram/Reels at 1080x1920 after reframing.
- Normalize orientation once for the sequence. Edited JPEGs can lose EXIF orientation even when the matching RAW is valid.

Use [scripts/render_boomerangs.py](scripts/render_boomerangs.py) on visually approved grouped export folders.

Use [scripts/render_cr3_boomerangs.py](scripts/render_cr3_boomerangs.py) when the approved group folders define membership but final frames must be developed from matching CR3 files. Process one burst at a time, keep temporary developed frames outside the source tree, and remove only the script-owned temporary directory after a successful encode.

When the user wants full-motion clips first, use [scripts/organize_by_motion_length.py](scripts/organize_by_motion_length.py) on a verified preview batch. Treat one natural forward/back cycle as the unique-motion measure: long is at least 3.0 seconds, medium is 1.5–2.99 seconds, and short bounce is under 1.5 seconds by default. Create a non-destructive link view and sort each tier longest-first; do not merge independent bursts to manufacture a longer motion.

## Verify before reporting completion

Confirm group counts, duplicates, filename continuity, missing metadata, source/export matches, codec, dimensions, pixel format, color tags, fps, decoded frame count, duration, and orientation around any repaired frame. Produce a manifest and a concise exception report. Say which conclusions came from metadata, visual sampling, and full decoded validation.

After rendering, run [scripts/verify_video_batch.py](scripts/verify_video_batch.py) against the batch manifest. Pass the intended codec, profile, dimensions, and pixel format; do not report the batch complete unless every expected file passes both metadata checks and a full FFmpeg decode.
