From 51cb34a1639cff25a773c440a81a459f5ff00e18 Mon Sep 17 00:00:00 2001 From: Rene Luria Date: Mon, 31 Aug 2026 21:14:27 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20arbitrage=20e4=20(sans=20r=C3=A9p=C3=A9?= =?UTF-8?q?tition,=20-r=20FPS)=20dans=20spec=20et=20plan?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/superpowers/plans/2026-08-31-stopmotion-script.md | 7 +++---- .../specs/2026-08-31-stopmotion-script-design.md | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/superpowers/plans/2026-08-31-stopmotion-script.md b/docs/superpowers/plans/2026-08-31-stopmotion-script.md index 549594b..0de63c1 100644 --- a/docs/superpowers/plans/2026-08-31-stopmotion-script.md +++ b/docs/superpowers/plans/2026-08-31-stopmotion-script.md @@ -4,7 +4,7 @@ **Goal :** un script bash `stopmotion.sh` qui génère une vidéo stop motion MP4 (H.264) à partir d'un dossier d'images (jpg/jpeg/png/heic), avec options CLI. -**Architecture :** un seul fichier `stopmotion.sh` à la racine. Découverte des images via `find` trié → fichier `ffconcat` temporaire (une entrée `duration` par image, dernière image répétée — contournement du concat demuxer qui ignore sinon la dernière frame) → encodage ffmpeg (libx264, yuv420p, +faststart). Le fichier ffconcat est créé dans le dossier du fichier de sortie (les chemins d'images y sont absolus, le concat demuxer résout les chemins relativement à l'emplacement de la liste). +**Architecture :** un seul fichier `stopmotion.sh` à la racine. Découverte des images via `find` trié → fichier `ffconcat` temporaire (une entrée `duration` par image) → encodage ffmpeg (libx264, yuv420p, +faststart, `-r FPS` en sortie pour une cadence CFR qui garantit la durée complète de la dernière frame). Le fichier ffconcat est créé dans le dossier du fichier de sortie (les chemins d'images y sont absolus, le concat demuxer résout les chemins relativement à l'emplacement de la liste). (Amendement 2026-08-31, arbitrage utilisateur : la répétition de la dernière image prévue initialement créait une 43e frame dupliquée avec la timebase 1/25 des HEIC — variante e4 validée par framehash.) **Tech Stack :** bash 3.2 (bash système de macOS — pas de tableaux associatifs, pas de `${var,,}`), ffmpeg 8.x (Homebrew, décode le HEIC), `find` BSD. @@ -16,7 +16,7 @@ - Aucun commentaire dans le code. - Compatible bash 3.2 (macOS) : pas de fonctionnalités bash 4+. - Fonctionnement vérifié avec le build ffmpeg 8.1.2 Homebrew (`-pattern_type glob` non supporté → concat demuxer obligatoire). -- Encodage : `-c:v libx264 -pix_fmt yuv420p -movflags +faststart`, filtre `scale=S:S:force_original_aspect_ratio=decrease:force_divisible_by=2`. +- Encodage : `-c:v libx264 -pix_fmt yuv420p -movflags +faststart`, `-r "$FPS"` en sortie, filtre `scale=S:S:force_original_aspect_ratio=decrease:force_divisible_by=2`. - Validation stricte avant tout traitement : `-f` et `-s` numériques strictement positifs. - Scénario de référence (validation finale) : `./images` (42 HEIC 3056x3056) sans option → 42 frames, 12 fps, 1080x1080, ~3,5 s. @@ -210,13 +210,12 @@ DURATION=$(awk -v f="$FPS" 'BEGIN{printf "%.6f", 1/f}') quote_ffconcat "$img" printf 'duration %s\n' "$DURATION" done <<< "$IMAGES" - last=$(printf '%s\n' "$IMAGES" | tail -n 1) - quote_ffconcat "$last" } > "$LIST_FILE" if ! ffmpeg -y -hide_banner -loglevel error -stats \ -f concat -safe 0 -i "$LIST_FILE" \ -vf "scale=${SIZE}:${SIZE}:force_original_aspect_ratio=decrease:force_divisible_by=2" \ + -r "$FPS" \ -c:v libx264 -pix_fmt yuv420p -movflags +faststart \ "$OUT_DIR/$OUT_NAME"; then rm -f "$OUT_DIR/$OUT_NAME" diff --git a/docs/superpowers/specs/2026-08-31-stopmotion-script-design.md b/docs/superpowers/specs/2026-08-31-stopmotion-script-design.md index e8ddddc..ba87522 100644 --- a/docs/superpowers/specs/2026-08-31-stopmotion-script-design.md +++ b/docs/superpowers/specs/2026-08-31-stopmotion-script-design.md @@ -35,8 +35,8 @@ Objectif : un script réutilisable pour regénérer la vidéo depuis n'importe q 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 ` + `duration 1/fps` ; dernière image répétée sans durée (contrainte du concat demuxer qui sinon ignore la dernière frame). Les chemins contenant des apostrophes sont échappés (`'` → `'\''`). -5. Encode avec ffmpeg : `-f concat -safe 0`, `libx264`, `yuv420p`, `-movflags +faststart`, filtre `scale=S:S:force_original_aspect_ratio=decrease:force_divisible_by=2`. +4. Génère un fichier `ffconcat` temporaire (mktemp + trap de nettoyage) : en-tête `ffconcat version 1.0`, puis pour chaque image `file ` + `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. ## Gestion des erreurs