Nodes/10S-Comfy-nodes/⚡ Latent Motion Sharpener
ComfyUI Node

⚡ Latent Motion Sharpener

Sharpen the moving pixels, leave the static background alone

By TenStrip·Created 4 months ago·Updated 26 days ago· 244
⚡ Latent Motion Sharpener
  • latent
  • latent
base_sharpen0.08
motion_sharpen0.55
motion_thresh0.04
temporal_smooth_masktrue

Video upscaling in latent space has a funny failure mode: the moving parts end up soft and the static parts stay crisp. That's because temporal interpolation and resampling smear whatever is actually moving, while stationary regions just get re-sampled cleanly. A global sharpener fixes the smeared motion but also hammers the already-fine background into that overcrisp, crunchy look nobody wants. LatentMotionSharpener's whole premise is that you don't want a global sharpener at all.

It's a motion-adaptive spatial sharpener: an unsharp-mask pass whose strength is scaled per pixel region by how much inter-frame motion that region has. Areas with no motion get almost no sharpening; areas that are actively moving get a strong boost. The result reads as "crisper video" rather than "an unsharp mask was applied to everything."

How it decides

The node computes per-frame motion maps from the frame-to-frame difference, normalizes them, and maps that onto sharpening strength between two bounds:

  • base_sharpen (0.08) - the sharpening applied everywhere, including static regions. Keep this small; it's the floor.
  • motion_sharpen (0.55) - the additional sharpening applied where motion is detected. This is your main dial.
  • motion_thresh (0.04) - below this normalized motion level, regions are treated as static and only get base_sharpen.
  • temporal_smooth_mask (True) - blurs the motion mask over time (a 3-tap temporal filter) so the sharpening strength doesn't flicker frame-to-frame as the motion map jitters. Leave it on unless you see it smearing a fast-moving edge.

Under the hood it's an unsharp mask in latent space: result = flat + strength * high_freq, where high_freq is the difference from a 3×3 Gaussian-ish blur. Working in latent space matters here - you're sharpening the model's own representation before decode, which avoids the ring-artifacts that aggressive pixel-space sharpening produces.

Where it goes

The pack's recommended fast-motion pipeline puts it before the temporal upsampler:

KSampler @ 24fps → LatentMotionSharpener → LatentTemporalUpsampler → ...

Sharpening before upsampling makes sense: the upsampler interpolates the already-crisp motion, so you get clean edges for the Hermite velocity field to follow. If you run it after upsampling instead, you're sharpening interpolated mush - it helps, but you're chasing your tail.

It's a transparent, cheap, no-training latent op. Input is a LATENT, output is a LATENT - chain it anywhere in the temporal processing chain. Install is the pack-wide clone (10S_Nodes into custom_nodes, restart, or ComfyUI Manager → "10S-Comfy-nodes"); no extra deps, LTX 5D latent layout assumed. If your 24→30fps upscale looks soft exactly where things move, this is the node that's actually aimed at that symptom.

Category10S Nodes/Latents

Inputs (5)

NameTypeDefaultDescription
latentLATENT
base_sharpenoptFLOAT0.080–1
motion_sharpenoptFLOAT0.550–2
motion_threshoptFLOAT0.040–0.5
temporal_smooth_maskoptBOOLEANtrue

Outputs (1)

NameTypeDescription
latentLATENT