# MOV8mm v3 — Project Spec (Step-by-Step Pipeline)

**Purpose:** the authoritative, build-order list of steps for the v3 pipeline.
Each step states *what it does* and the *proposed technology*. Detailed rationale
lives in [V3_BUILD_Recomendation.md](V3_BUILD_Recomendation.md); this file is the working checklist.

**Convention:** each heavy/conflicting step is its own app in its own folder with
its own virtualenv named `env`, called by the orchestrator via subprocess. Cheap
classical steps run in-process in the orchestrator's own `env`. Stages hand off
via lossless files on disk.

---

## Part A — Infrastructure (build once, before any footage)

| # | Step | What it does | Proposed technology |
|---|------|--------------|---------------------|
| A1 | Repo scaffold | Folder layout, git, gitignore, docs | git + standard layout (orchestrator/ runners/ work/ config/) |
| A2 | Orchestrator env | Lightweight, conflict-free venv for the boss | Python venv `env` + numpy, opencv-python, scenedetect, colour-science |
| A3 | GPU driver update | Unlock NVENC AV1 hardware encode | NVIDIA driver ≥570 (595.97+) for RTX 4060 |
| A4 | FFmpeg I/O layer | Read/write video without pipe deadlock | FFmpeg (gyan.dev build, libvidstab) — stdin-only pattern, or PyAV/ffmpegcv |
| A5 | Lossless intermediates | Standard hand-off format between stages | FFV1 in MKV (or PNG sequence where a model needs frames) |
| A6 | State / manifest | Track (shot × stage) status, enable resume | JSON manifest + params_hash invalidation |
| A7 | Orchestrator core | Job-grid runner, subprocess dispatch, resume | Python (`pipeline.py`, `shots.py`, `state.py`) |
| A8 | Validation harness | Automated metrics per build, regression gate | Python + ArcFace embeddings, optical-flow variance, landmark jitter |

---

## Part B — Processing pipeline (per reel, in order)

| # | Step | What it does | Proposed technology |
|---|------|--------------|---------------------|
| B0 | **Cut & stitch** *(optional front step)* | Keep only chosen time ranges and stitch them into a shorter working clip, so the whole pipeline only touches frames you care about | FFmpeg frame-accurate select+concat (`cut.py`); CLI `--keep` or JSON edit-list (`--edl`) |
| B1 | Ingest | Load reel (or the B0 cut), normalize to lossless working copy | FFmpeg → FFV1/MKV |
| B2 | **Shot detection** *(keystone)* | Split reel into individual shots | PySceneDetect 0.7 `AdaptiveDetector` (+ optional TransNetV2 cross-check) |
| B3 | Stabilization | Remove gate-weave / jitter, per shot | FFmpeg vid.stab (2-pass); optional ProPainter de-crop for hero shots |
| B4 | Photometric normalization | Kill brightness pulsing, per shot | Scale-time / midway histogram equalization (NumPy/OpenCV); FFmpeg `deflicker` stopgap |
| B5 | Denoise | Remove temporal noise, keep detail | VapourSynth TemporalDegrain2 + BM3DCUDA prefilter |
| B6 | Scratch / dust / defect | Remove transient damage | VapourSynth SpotLess/SpotDelta + RemoveDirtMC; DeScratch (vertical); ProPainter (severe) |
| B7 | Super-resolution — bulk | Upscale whole archive, temporally | BasicVSR++ via `vsbasicvsrpp` |
| B7q | Super-resolution — hero (opt-in) | High-quality upscale, short clips only | SeedVR2-3B (GGUF+BlockSwap, ComfyUI) or FlashVSR+ |
| B8 | Face restoration | Restore recognizable faces, per shot | KEEP (video-native); optional reference-guided (InstantRestore/RestorerID); CodeFormer fidelity 0.2–0.4 fallback |
| B9 | Color restoration | Cast removal + white balance + look, per shot | NumPy percentile stretch + gray-world WB; optional Deep White-Balance; film LUT (colour-science / FFmpeg lut3d) for Modern mode |
| B10 | Reassemble | Stitch processed shots back into the reel | FFmpeg concat (lossless) |
| B11 | Grain (Modern mode) | Re-inject authentic grain | TemporalDegrain2 `postMix`, or SVT-AV1 `--film-grain` at encode, or grav1synth table |
| B12 | Frame interpolation *(optional, off)* | Smooth motion 20→40 fps | Practical-RIFE 4.25; or FFmpeg `tmix` shutter-blur |
| B13 | Encode (3 tiers) | Final deliverables from lossless master | Archival: FFV1/MKV · Viewing: SVT-AV1 10-bit · Sharing: x264 10-bit · Preview: NVENC AV1 |

---

## Ordering rules (non-negotiable)

- **B0 cut & stitch runs before ingest** — the stitched clip becomes the working
  master, so every later stage only ever sees the kept frames. Changing the kept
  ranges re-cuts and cascades invalidation through the whole pipeline.
- **Shot detection runs first** — everything photometric is per-shot.
- **Denoise before super-resolution** — never amplify grain.
- **Faces after denoise + deflicker + upscale** — KEEP fails on heavy degradation.
- **White balance per shot, never per frame** — per-frame estimation flickers.

---

## Build sequence (by leverage-per-effort)

- **Phase 0 — Infra:** A1–A8, B0 (cut & stitch front step), B13 (3-tier encode)
- **Phase 1 — Shot-aware core:** B1, B2, B4, B9 (Python/NumPy, biggest visual win)
- **Phase 2 — Faces:** B8 (most emotional impact) → **MVP = Phases 0–2**
- **Phase 3 — VapourSynth:** B5, B6, B11
- **Phase 4 — Super-resolution:** B7 (+ B7q hero track)
- **Phase 5 — Polish:** B3, B12, dual-mode presets, full regression run

---

## Dual-mode output

- **Faithful:** light denoise, high-fidelity faces, BasicVSR++, minimal color, no LUT, native fps.
- **Modern:** aggressive denoise + grain re-inject, reference-guided faces, diffusion SR on hero shots, full color + LUT.
- Implemented as config presets selecting which steps/params run.
