# doer-9x16.mp4: POV of the doer on moneycanbuy.fun

A 30-second vertical POV video. You do the dare, someone calls fake, the NFTs vote it fake, you appeal, the IMD swarm rules legit, you get paid, the trophy is minted and the YOLO burns.

## Output

| item | value |
|---|---|
| file | `doer-9x16.mp4` (3.94 MB) |
| duration | 30.000 s, 720 frames, constant 24 fps |
| video | 1080x1920, H.264 High, yuv420p, CRF 18, `+faststart` |
| audio | AAC-LC 256 kb/s, 48 kHz stereo, 30.0 s, original 120 BPM track plus UI sounds, all synthesised in code |
| also delivered | `contact-sheet.png` (decoded middle frame of every scene), `captions.srt`, `safe-zone.md`, `audio-check.md`, `src/` |

## Scenes (hard cuts on the beat, no crossfades)

| # | s | caption | picture |
|---|---|---|---|
| 1 | 0-2 | scroll. stop. | feed-hero-yolo.png, quick pan up that eases to a stop on the card, then a slow creep |
| 2 | 2-4 | you'd scream for that? | yolo-dare-135.png cropped below the author line, push in on YOU GET |
| 3 | 4-6 | you did it. bond in. | yolo-submit-bond.png, push in on the Total line |
| 4 | 6-8 | proof sent. | yolo-submit-button.png, push in, tap ring on Submit proof (beside the label) at 6.90 s |
| 5 | 8-10 | 24h for anyone to object. | yolo-submitted.png, push in |
| 6 | 10-12 | someone calls fake. | milk-disputed.png, hard zoom (1.0 to 1.6x) |
| 7 | 12-14 | NFT holders vote. | vote-row-0-0.png, push in on LEGIT / FAKE |
| 8 | 14-16 | it's going against you. | vote-0-10.png, push in on 10 FAKE |
| 9 | 16-18 | they got it wrong. | nfts-said-fake.png, slow push in |
| 10 | 18-20 | you appeal. | appeal-button.png, tap ring on Appeal (beside the label) at 19.25 s |
| 11 | 20-23 | the IMD swarm judges. | swarm card: IMD logo, 8 NFTs turning slowly, one lights green per beat, chip REVIEWING, riser |
| 12 | 23-25 | verdict: legit. | verdict card: all NFTs green, LEGIT chip lands on the drop with the gavel |
| 13 | 25-26.5 | you get paid. | yolo-paid-135.png cropped below the author line, push in on YOU GOT, coin ticks |
| 14 | 26.5-28 | trophy minted. YOLO burned. | yolo-mint-button.png with a tap at 26.70 s, then at 27.0 s yolo-trophy-minted.png (only the "Trophy minted. It's onchain." row) with fire under it |
| 15 | 28-30 | do the dare. | mark-transparent-1024.png, wordmark.png and "moneycanbuy.fun", held to the end |

## Tools

- Python 3.12 with Pillow 13 and numpy 2: `src/render.py` composes every frame from the repository PNGs, vector shapes, Quicksand Bold text and eased keyframes. Bands are only cropped and uniformly scaled (one LANCZOS resize per frame), shown 952 px wide, zoom at most 1.6x. The fire is a cellular flame automaton with sparks, redrawn every frame in #FF3B1F / #FF8A00 / #FFD24A.
- `src/music.py` synthesises the 120 BPM track and the UI sounds (taps, coin ticks, gavel, fire crackle) in numpy. A look-ahead limiter with smooth gain holds sample peaks at -4.5 dBFS (no clipping). `build.sh` measures the AAC with ffmpeg `ebur128` and corrects the gain to -14 LUFS.
- ffmpeg 7.0.2 (static build, libx264, native AAC) for the encode, the measurements and frame decoding; ffprobe for the probe.
- No generation model, stock material, voice, or image source outside the repository.

## Offline rebuild

From the repository root, with python3 (numpy + Pillow) and ffmpeg/ffprobe available, and no network:

```
sh pov/doer-video/build.sh
```

(`FFMPEG` and `FFPROBE` env vars choose the binaries. The default is `imd-media ffmpeg` / `imd-media ffprobe`.) The same source is in `src/` here and in `pov/doer-video/` in the repository.

## Repository files used (sha256)

| file | sha256 | note |
|---|---|---|
| `pov/screens/feed-hero-yolo.png` | `c698d5e22cec8dce9497874534b0f97b9160f82bdf8e67902aaf6df019c1f8e6` | matches pov/README.md |
| `pov/screens/yolo-dare-135.png` | `def714e9ef6a1594d23634b4fd628f2fb795bfbe66a958cf7d1082e09335f4e9` | matches pov/README.md |
| `pov/screens/yolo-submit-bond.png` | `1de463e72260e4937c6a912dfc5719e0dc3e443532b2126d9c7d6652ad00b183` | matches pov/README.md |
| `pov/screens/yolo-submit-button.png` | `caa95c3100f7c0792f7592f3a3a16757b35b17542da6af259e85b887ba773d62` | matches pov/README.md |
| `pov/screens/yolo-submitted.png` | `38de9a7ed055ad4a61de81232af38985169c84aa14d959140a2b261682400468` | matches pov/README.md |
| `pov/screens/milk-disputed.png` | `1ce825b03699733d41b9a6dc144471c8c0918b2c3f1bb1256985c7ee2ec7e63c` | matches pov/README.md |
| `pov/screens/vote-row-0-0.png` | `1b97586d1a497d8f3f6325d15ae1cc802774af3381b6359eda92e5b6306a175e` | matches pov/README.md |
| `pov/screens/vote-0-10.png` | `3992aa1e373a89c9279dcd5c54821ca3e1936147c8e17bafe95c8081e1b0000a` | matches pov/README.md |
| `pov/screens/nfts-said-fake.png` | `831b45870a880869bf306ce5266e8144db506aba1b3b81f75561dc0deb2b9453` | matches pov/README.md |
| `pov/screens/appeal-button.png` | `524df8ccd09eaecf852194a1b4ac6a05f92a291d69e0464f13d00c2af60295ee` | matches pov/README.md |
| `pov/screens/yolo-paid-135.png` | `ce20dc372aa899f561e77d6dfd299c5f985ce5a720ec41ab1dda4558c9162734` | matches pov/README.md |
| `pov/screens/yolo-mint-button.png` | `1abd82b8f51a5e96e8180bc9f8119abc92a16c3c22ae796013007f48b93dafa5` | matches pov/README.md |
| `pov/screens/yolo-trophy-minted.png` | `182d8eb7dbb0309c66b57d8b2aef9ad1ee63afefec4b857176ce10282cd5a8ba` | matches pov/README.md |
| `explainers/imd/imd-token-logo.png` | `72d55ed4c3e160e66aa61cb4a3da394d5fd51f5f6d3e32535ab1c595da546c36` | read-only, unmodified in git |
| `explainers/imd/nft-1.png` | `5a3a264c277a00d716496285a2e2329404052ced169a0872280aa13daac94a07` | read-only, unmodified in git |
| `explainers/imd/nft-7.png` | `f5d713e709bf79e1579bb3dbc948d6f1851f2f845bf73a6950ca67fb8b9b6e37` | read-only, unmodified in git |
| `explainers/imd/nft-42.png` | `62d012c2f17d82fac098c2c4853d821606d4f3f7c3029c3a8f7754993754eca0` | read-only, unmodified in git |
| `explainers/imd/nft-256.png` | `6a17db0c36d243dd26c222d6e21b3b3b6ac068f3bac377fa8256a7e81ea336da` | read-only, unmodified in git |
| `explainers/imd/nft-777.png` | `4b75af0328ccc9e3d390adb9ad0c685b4b3fc44694703d8aa0e7dc942b689669` | read-only, unmodified in git |
| `explainers/imd/nft-1311.png` | `c32a72b6c067262a17903e294f0423ce8e132cccae05c2fcf61dbcb72d07107a` | read-only, unmodified in git |
| `explainers/imd/nft-1626.png` | `4e0dd6b5011ceb22b4c7d278bd458968ce61b7bd5a63ac78fe3ccbda67643849` | read-only, unmodified in git |
| `explainers/imd/nft-1999.png` | `7815233c233bf283bcb6b289c247755d375896aca9ce93ec9ca05a839a38066b` | read-only, unmodified in git |
| `explainers/brand/mark-transparent-1024.png` | `cb2eabccda8b2aaac6ecbe94c3e625ca8e6bb9a251ba5c2d8d2c3e52f10b0738` | read-only, unmodified in git |
| `explainers/brand/wordmark.png` | `94fa6c462a8df39bd21e4a90cd72b2da8c13ac89012407ded1be886a45c9527c` | read-only, unmodified in git |
| `explainers/brand/fonts/Quicksand-VariableFont_wght.ttf` | `39c9b64223561f56aaff6062a6f04063c4fc86809ad6768722c06614d977e1cc` | read-only, unmodified in git |

## Self-check

| check | result | status |
|---|---|---|
| ffprobe duration 30.000 s +-0.04 | 30.000 s | PASS |
| 720 video frames | 720 (nb_frames), 720 decoded | PASS |
| 24 fps constant | r_frame_rate 24/1, avg_frame_rate 24/1 | PASS |
| 1080x1920, H.264 High, yuv420p | 1080x1920 h264 High yuv420p | PASS |
| audio AAC 48 kHz stereo, 30.0 s | aac 48000 Hz 2 ch, stream 30.000 s, decoded 30.016 s | PASS |
| file under 40 MB, faststart | 3.94 MB | PASS |
| middle frame of every scene shows its caption | checked by eye on contact-sheet.png against captions.srt | PASS |
| safe-zone.md zero FAIL | 539 rows, 0 FAIL | PASS |
| no two scene groups share a frame | hard cuts at frames 48,96,...,672; each frame is drawn from exactly one scene, no crossfades | PASS |
| no frame repeated > 12 frames before 28 s | longest identical run 2 frames (ending at frame 191) | PASS |
| every number outside the bands is in NUMBERS | numbers found: 24 | PASS |
| bands, logo, NFT, mark, wordmark files unmodified (sha256) | see table | PASS |
| audio-check.md within MUSIC limits | -14.4 LUFS, -1.7 dBTP, crest 11.64 dB, 0.0000 % above -1 dBFS | PASS |

## Limitations

- The caption check is visual: no OCR tool was available. Every scene's middle frame in `contact-sheet.png` was read against `captions.srt`.
- The wordmark.png lockup includes its own small toad, as drawn by the brand. It appears only on the final card.
- yolo-dare-135.png and yolo-paid-135.png are cropped to start at the YOU GET / YOU GOT row, so the author wallet line is not shown. yolo-trophy-minted.png is cropped to the "Trophy minted" row, so its "$YOLO … 0x…dEaD" line is not shown. appeal-button.png shows its own "+ $YOLO" label, partly cropped by the push-in.
- The tap ring is green #3ECF7A, at most 106 px across including a thin dark edge so it reads on the green buttons. It sits inside the button, to the right of the label, so it never covers text.
- numpy, Pillow and ffmpeg are not vendored in the repository. The rebuild needs them installed.
