Numbers
Film grain that changed every frame made a 30-second video 112 MB
The first Instagram Reel renderer for kokkekunst.no used film grain that changed every frame, and a 30-second video came out at 112 MB against a 20 MB limit. One fixed grain tile and a 4 Mbit/s bitrate cap brought the test video to 13.4 MB, and a second limit now caps Reels at 34 seconds.
The newsroom engine behind kokkekunst.no now turns news stories into Instagram Reels: vertical videos at 1080×1920 and 30 frames per second, with kitchen sounds generated in code. On the evening of 7 October 2026 two fixes, committed seven minutes apart, dealt with two limits the renderer had hit. One was file size and the other was length. This post covers the numbers behind both.
Claude wrote all the renderer code, including the version that produced the oversized file. Henning asked for Reels with the kitchen in them.
What the “film layer” does
Each Reel gets a layer on top of the scenes that makes it look like film. A camera slowly moves in and drifts. Each cut gets a snap zoom and a flash of light. A light moves across the frame, and there is a vignette and film grain.
In the first version, the grain was three pre-made tiles. The renderer swapped tiles on every frame, so the grain looked alive without being drawn again for each frame. The code comment from that version describes it exactly that way.
The number: 112 MB for 30 seconds
According to the commit message, a 30-second Reel came out at 112 MB, and the limit is 20 MB. So the first version was more than five times too large.
The code comment that came with the fix gives the reason in four words: noise does not compress. A video encoder saves space by sending only what changed between frames. When the whole frame is covered in grain that changes every frame, every pixel changes every frame, so the encoder has almost nothing to reuse. The grain was faint (drawn at 55 percent opacity), but the encoder still had to keep it.
The encoder settings were ffmpeg’s medium preset with -crf 20. CRF is a quality target, not a size target, so it lets the bitrate rise as high as the content requires. Fully random grain required a lot.
The fix: one fixed tile and a bitrate cap
The fix did two things.
- One fixed grain tile. Instead of three tiles swapping each frame, one tile now sits over the whole image. The comment in the code explains why this still works: fixed grain over a camera that is moving still looks alive. Grain opacity also dropped from 0.55 to 0.4.
- A ceiling on the bitrate. The ffmpeg call got
-maxrate 4Mand-bufsize 8M. The comment explains that with the film layer (a camera move in every frame, plus grain), CRF alone can produce more than 100 MB. Its stated target is that 4 Mbit/s keeps 40 seconds of video under 20 MB, audio included.
That target checks out with simple arithmetic: 4 megabits per second times 40 seconds is 160 megabits, or 20 megabytes. The cap is the backstop. The fixed tile is what stops the encoder from spending its whole budget on noise.
Result: the wine-map test video came out at 13.4 MB. The commit message records that number. It does not give the test video’s exact length, so we don’t calculate a bitrate from it.
Seven minutes later, a second commit lowered the grain opacity again, from 0.4 to 0.22. The message gives no size figure for that change. It just calls it “milder grain”.
The second limit: 34 seconds
That same evening the “director” went into use. For each Reel, Claude writes a script in the newsroom engine’s worker: mood, light, scenes and music, with all text checked word for word against the story. A script can contain several scenes, such as a number counting up, a map pin, a quote, a price or a list. The changelog describes a Reel as 15 to 30 seconds long.
The commit message for that second fix records the case that led to the limit: “54 vinkart ble 40 s”, which translates to “54 wine-map became 40 s”. The comment in the code adds “with four”. The 40 seconds is above the new cap.
The rule that commit added:
- A Reel can be at most 34 seconds. The constant is defined as the longest Reel allowed before the director’s last scenes are cut.
- Cuts happen from the back, one scene at a time. The renderer adds up the frames of the opening, the director’s scenes and the fixed ending. If the total is over 34 × 30 = 1,020 frames, it removes the director’s last scene and checks again.
- The first director scene is never cut. The loop stops when only one director scene is left. The opening hook and the closing “serving” segment are always kept.
The same commit made the remaining pieces shorter. Each list item now gets about 15 frames before the next one appears instead of 22, and the reading time added to the list scene went from 0.6 to 0.4 of the estimate. The text page after the scenes now stays up for at most 4.5 seconds instead of 5.5 when the Reel has director scenes.
How the limit is tested
An existing test had checked that a Reel with a director’s script was under 40 seconds. It now checks that it is at most 34 seconds.
A new test builds a long script with four scenes (a number, a list, a place and a quote) at the calm tempo (“rolig”) and checks four things:
- the Reel is at most 34 seconds
- the first segment is still the hook
- the last segment is still the serving
- the number scene is kept and the quote scene, which came last, is dropped
The commit also raised the Reel version number from 4 to 5. The code comment says the number is raised when the look changes, so cached videos are made again.
What the numbers say
| Before | After | |
|---|---|---|
| Grain | 3 tiles, swapped each frame, opacity 0.55 | 1 fixed tile, opacity 0.4, then 0.22 |
| Bitrate | CRF 20, no cap | CRF 20, max 4 Mbit/s, buffer 8 Mbit |
| Size | 112 MB for 30 s | 13.4 MB for the wine-map test (length not given) |
| Length | no cap (test allowed under 40 s) | at most 34 s, director scenes cut from the back |
Both limits address the same thing. The film layer and the director made each Reel richer, and nothing in the renderer kept the result within a budget. Now there is a size budget, set by the bitrate cap, and a time budget, set by the frame count. When the director’s script runs too long, its last scenes are dropped.