Files
stop-motion/docs/superpowers/specs/2026-08-31-stopmotion-script-design.md

56 lines
3.6 KiB
Markdown

# Design — Script réutilisable de stop motion
Date : 2026-08-31
Statut : validé par l'utilisateur
## Contexte
Le projet contient un dossier `images/` (42 photos HEIC 3056x3056, prises par iPhone, triées par nom = ordre chronologique) et une vidéo `stop_motion.mp4` générée manuellement avec ffmpeg (12 fps, 1080x1080, 3,5 s). Le build ffmpeg installé (8.1.2, Homebrew) décode le HEIC mais ne supporte pas `-pattern_type glob` ; la génération manuelle a utilisé le concat demuxer avec un fichier `ffconcat`.
Objectif : un script réutilisable pour regénérer la vidéo depuis n'importe quel dossier d'images, sans dépendance au-delà de ffmpeg.
## Décisions
- **Approche choisie** : script bash unique (`stopmotion.sh`) à la racine. Les alternatives (Python/argparse, Makefile) ont été écartées : bash suffit, ffmpeg fait tout le travail, aucune dépendance supplémentaire.
- **Usage visé** : flexible — détection automatique des formats d'images, options CLI simples.
## Interface
```
./stopmotion.sh # ./images → ./stop_motion.mp4, 12 fps, 1080px
./stopmotion.sh -i photos -o film.mp4 -f 15 -s 720 -y
```
| Option | Défaut | Rôle |
|--------|--------|------|
| `-i` | `./images` | dossier d'images |
| `-o` | `./stop_motion.mp4` | fichier de sortie |
| `-f` | `12` | fps (cadence stop motion) |
| `-s` | `1080` | taille max du côté long, ratio préservé |
| `-y` | off | écraser la sortie sans demander |
| `-h` | — | aide |
## Comportement
1. Vérifie la présence de `ffmpeg` dans le PATH ; sinon message clair + exit 1.
2. Liste les images du dossier d'entrée (extensions `jpg`, `jpeg`, `png`, `heic`, insensible à la casse, premier niveau uniquement), triées par nom (`LC_ALL=C sort`).
3. Erreur explicite si le dossier n'existe pas ou ne contient aucune image (exit 1).
4. Génère un fichier `ffconcat` temporaire (mktemp + trap de nettoyage) : en-tête `ffconcat version 1.0`, puis pour chaque image `file <chemin>` + `duration 1/fps`. Les chemins contenant des apostrophes sont échappés (`'` → `'\''`). (Amendement du 2026-08-31, arbitrage utilisateur : la « dernière image répétée » prévue initialement créait une 43e frame dupliquée sur ce build ffmpeg — timebase 1/25 des HEIC ; la cadence finale est garantie par `-r FPS` en sortie, qui couvre aussi la dernière frame.)
5. Encode avec ffmpeg : `-f concat -safe 0`, `libx264`, `yuv420p`, `-movflags +faststart`, `-r FPS`, filtre `scale=S:S:force_original_aspect_ratio=decrease:force_divisible_by=2`.
6. Affiche un récapitulatif : nombre d'images, fps, durée de la vidéo, taille du fichier de sortie.
Pour des fps élevés (ex. `-f 30`), le mapping CFR peut dupliquer une image (arrondi au créneau le plus proche face à la timebase 1/25 des HEIC) sans jamais en perdre ; les valeurs `-f` 12/15/20/24 ont été vérifiées exactes sur le corpus de référence.
## Gestion des erreurs
- Options inconnues ou valeur manquante → usage + exit 1.
- Valeurs non numériques ou non strictement positives pour `-f` et `-s` → erreur + exit 1 (avant tout traitement).
- Dossier d'entrée inexistant ou sans image → message en français + exit 1.
- Échec d'encodage ffmpeg → le fichier de sortie est supprimé s'il est partiel, exit 1.
- Sortie existante sans `-y` → demande confirmation (refus = exit 0 sans rien faire).
- Codes de sortie non nuls pour toute erreur.
## Validation
Rejouer le scénario de référence : `./stopmotion.sh` sans option sur ce projet doit produire une vidéo équivalente à l'actuelle `stop_motion.mp4` (42 frames, 12 fps, 1080x1080, ~3,5 s). Vérifier aussi : `-h`, dossier inexistant, dossier sans image, sortie refusée sans `-y`.