Hypernatural

TechniqueBy HypernaturalVersion 1, Oct 21, 2026

ffmpeg-grain-for-plastic-skin

Add moving film grain to a finished take whose skin reads plastic, waxy or over-smooth, with ffmpeg, instead of re-rendering it. Builds a ladder of grain strengths at size 2 and a 100% crop sheet against the source so the strength is picked by eye. Use for a client note like 'skin looks plastic' on an otherwise good take.

SKILL.md

Grain for plastic skin

Give it a take that is right in every way except that skin and surfaces look too smooth (a typical note on H3 Max and other fast models); get back the same take with moving, brightness-neutral film grain, at a strength picked from a ladder. It is the cheapest fix for a texture note: seconds of ffmpeg instead of a re-render. It won't fix shine that is in the lighting, or detail the render never had (hair strands, stubble): for those, re-render on a model with photographic texture.

Inputs

  • The take at its delivery size: after topaz-upscale if it needs one, since grain size is in output pixels.
  • Its width, height and frame rate (ffprobe-inspect-media).
  • The source shot it has to match, and a box on a face or a flat patch (a wall) for the crop sheet, as w:h:x:y at 1080p.

Run it

One command per rung. The noise is generated at half resolution (size 2) and scaled up, so each grain is 2 px wide. For a 1920×1080, 24 fps take at strength 10:

exec ffmpeg -hide_banner -loglevel error -y
  -i <job>/rev1/shot03.mp4
  -f lavfi -i "color=c=0x808080:s=960x540:r=24,format=yuv420p,noise=c0s=10:c0f=t+u,scale=1920:1080:flags=bicubic"
  -filter_complex "[0:v]format=yuv420p[a];[a][1:v]blend=all_mode=grainmerge:shortest=1,format=yuv420p"
  -c:v libx264 -crf 14 -preset slow -pix_fmt yuv420p -c:a aac -b:a 192k
  -movflags +faststart
  <job>/shot03_grain_ladder/shot03_size2_s10.mp4
  • The noise source is mid grey (0x808080), so grainmerge adds texture without moving brightness.
  • s= is the take's size divided by the grain size (W/2 × H/2), r= is the take's frame rate, and scale= brings it back to W × H.
  • c0s= is the strength; c0f=t+u makes it temporal (new every frame) and uniform.
  • shortest=1 ends the output with the take, so the frame count is unchanged.

Run the ladder at strengths 7, 10 and 14 (name the files <shot>_size2_s<strength>.mp4), then a 100% crop sheet of one frame (frame 12 here) across the source, the take without grain and every rung, left to right:

exec ffmpeg -v error -y
  -i <source shot> -i <take> -i <…_s7.mp4> -i <…_s10.mp4> -i <…_s14.mp4>
  -filter_complex "[0]select=eq(n\,12),crop=384:320:760:60[c0];[1]select=eq(n\,12),crop=384:320:760:60[c1];[2]select=eq(n\,12),crop=384:320:760:60[c2];[3]select=eq(n\,12),crop=384:320:760:60[c3];[4]select=eq(n\,12),crop=384:320:760:60[c4];[c0][c1][c2][c3][c4]hstack=5"
  -frames:v 1 <job>/shot03_grain_ladder/shot03_compare_source_none_7_10_14.png

Look at the sheet, then put the sheet and the rungs on a review page next to the source and let the person pick.

What you get

One grained take per rung and a crop sheet. On the first job, strength 10 at size 2 was picked ("light") for a manager's face that the client called plastic and shiny; 7 is lighter, 14 heavier. Keep the ungrained take beside the picked one.

Tips and traps

  • Size 2, not 1. Grain one pixel wide vanishes whenever the clip plays scaled down (a review grid, a phone), so the note comes back. Half-resolution noise survives.
  • Judge at 100%. A review page shows clips scaled down, where every rung looks alike; the crop sheet is the evidence. Open the lightbox at full size for the moving clip.
  • Grain does nothing for shine baked into the lighting. If the note is about shine, say so before spending time on a ladder.

Check it

  • The frame count equals the take's (exec ffmpeg -v error -i <out> -map 0:v -f framemd5 -, counting lines that don't start with #).
  • Measure the same flat patch or face on the source, the take and the pick with python-measure-detail, and compare the numbers against the source's.

Go make something cool.

Install the app, open your agent, describe the video. That's the whole onboarding.

Sticker HypernaturalSticker BannerSticker TVBoy