diff --git a/.gitignore b/.gitignore index 2c62fc9..cdd216c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ __pycache__/ media/ .superpowers/ *.egg-info/ +# Simulator sample media (look-tuning only; populate via setup_sample_media.py) +simulator/sample_media/forest/*.mp4 diff --git a/simulator/sample_media/README.md b/simulator/sample_media/README.md new file mode 100644 index 0000000..ff9f08d --- /dev/null +++ b/simulator/sample_media/README.md @@ -0,0 +1,12 @@ +# Simulator sample media + +`manifest.json` is committed; the `.mp4` binaries are **not** (gitignored). They +are look-tuning samples, not shipped installation content. + +Populate them from the session-0008 POC artifacts: + + python simulator/setup_sample_media.py + +This copies `~/hef-poc/out/neutral.mp4` → `forest/base.mp4` and +`~/hef-poc/out/right_flow.mp4` → `forest/right4.mp4` (the real flow-stabilized +restyle), and generates placeholder strengths `forest/right1..3.mp4`. diff --git a/simulator/sample_media/manifest.json b/simulator/sample_media/manifest.json new file mode 100644 index 0000000..730e5b9 --- /dev/null +++ b/simulator/sample_media/manifest.json @@ -0,0 +1,31 @@ +{ + "clips": [ + { + "id": "forest", + "title": "Yosemite Falls (neutral base, POC sample)", + "base_file": "forest/base.mp4", + "license": "poc-sample (look-tuning only; not shipped content)", + "source": "hef-poc/out/neutral.mp4", + "right_variants": { + "1": {"file": "forest/right1.mp4", "model": "placeholder"}, + "2": {"file": "forest/right2.mp4", "model": "placeholder"}, + "3": {"file": "forest/right3.mp4", "model": "placeholder"}, + "4": {"file": "forest/right4.mp4", "model": "sd-turbo+farneback-flow"} + }, + "annotations": [ + {"key": "detected.water", "box": [0.30, 0.10, 0.18, 0.70], "min_level": 1}, + {"key": "detected.rock_face", "box": [0.05, 0.30, 0.20, 0.55], "min_level": 2}, + {"key": "detected.conifer", "box": [0.70, 0.20, 0.22, 0.45], "min_level": 3}, + {"key": "measure.flow_rate", "box": [0.34, 0.55, 0.14, 0.08], "min_level": 4} + ], + "strings": { + "en": { + "detected.water": "flowing water", + "detected.rock_face": "granite face", + "detected.conifer": "conifer stand", + "measure.flow_rate": "~2.1 m³/s" + } + } + } + ] +} diff --git a/simulator/setup_sample_media.py b/simulator/setup_sample_media.py new file mode 100644 index 0000000..6f947a6 --- /dev/null +++ b/simulator/setup_sample_media.py @@ -0,0 +1,53 @@ +"""Populate simulator/sample_media/forest/ from the session-0008 POC artifacts. + +Copies the real neutral base + the real flow-stabilized Right restyle out of +~/hef-poc/out/, and generates placeholder intermediate Right strengths (1..3) by +blending the base toward the real restyle with ffmpeg. The media binaries are +gitignored; only the manifest is committed. Sample footage is for look-tuning +only, not shipped content. + +Usage: python simulator/setup_sample_media.py +Requires: ffmpeg on PATH (or `pip install imageio-ffmpeg`), and ~/hef-poc/out/. +""" + +from __future__ import annotations + +import shutil +import subprocess +from pathlib import Path + +POC = Path.home() / "hef-poc" / "out" +DEST = Path(__file__).parent / "sample_media" / "forest" + + +def _ffmpeg() -> str: + if shutil.which("ffmpeg"): + return "ffmpeg" + import imageio_ffmpeg + return imageio_ffmpeg.get_ffmpeg_exe() + + +def main() -> None: + DEST.mkdir(parents=True, exist_ok=True) + base = DEST / "base.mp4" + right4 = DEST / "right4.mp4" + shutil.copyfile(POC / "neutral.mp4", base) + shutil.copyfile(POC / "right_flow.mp4", right4) + ff = _ffmpeg() + # Placeholder strengths 1..3: opacity-blend base toward the real restyle. + for strength, alpha in ((1, 0.25), (2, 0.5), (3, 0.75)): + out = DEST / f"right{strength}.mp4" + subprocess.run( + [ff, "-y", "-i", str(base), "-i", str(right4), + "-filter_complex", + f"[1:v]format=yuva444p,colorchannelmixer=aa={alpha}[top];" + f"[0:v][top]overlay=shortest=1[v]", + "-map", "[v]", "-an", str(out)], + check=True, + ) + print(f"generated {out.name} (alpha {alpha})") + print(f"sample media ready in {DEST}") + + +if __name__ == "__main__": + main()