ANDRO Seam Check
Your tiled VAE decode is leaving a softer frame every 24 frames and nobody notices
- images
- sharpness_plot
- report
When a video latent is too big to decode in one shot, ComfyUI tiles the decode - spatially and, for video VAEs, in time. The temporal kind is the sneaky one. A diffusion decoder has no context at a temporal tile edge, so the blend leaves a visibly softer frame on every seam. And it's smooth, not a jump, which is exactly why you never catch it: a frame-to-frame difference check doesn't see it, because there's no sudden change, just one frame that's slightly soft before the next recovers.
Tile Seam Check measures per-frame sharpness, finds the local dips, and only flags them when several sit on one regular grid. That regularity requirement is the whole idea - motion in the shot produces isolated soft frames too, and the node refuses to cry wolf about those. Here's the README's real output from a bad setting, on a 121-frame LTX-2.5 generation:
temporal: 121 frame(s), median sharpness 0.00738
soft frames at [12, 25, 49, 66, 73, 97]
PERIODIC: 4 of them every 24 frames ([25, 49, 73, 97]) - that is a temporal tiling seam.
off-grid, most likely motion in the shot: [12, 66]
Same generation with temporal tiling off: soft frames at [66] - no regular spacing, these look like content. That's the node earning its keep - telling a real artefact from normal video in the same clip.
Inputs
images- the decoded video batch (IMAGE). Feed it whatever your decode produced; you want the finished frames, not the latent.dip_threshold(default 0.93) - a frame counts as a dip when its sharpness falls below this fraction of the previous frame's. Lower it to only catch harder drops, raise it to catch gentler softening. 0.93 is a sensible default; the seams the README measures are clear dips.check_spatial(default on) - also checks for spatial (within-frame) seams. It looks for several regularly-spaced sharpness peaks along an axis, not a single strong column - because a hard edge in the content looks identical to one seam. Same regularity principle as the temporal check.
Outputs
report- the plain-language verdict above: dips, whether they're periodic, and if spatial, the pixel spacing. Wire it to a text display or read the console.sharpness_plot- an IMAGE of the per-frame sharpness trace with the dips marked. This is the one you actually look at: a regular sawtooth is a seam, a single isolated valley is motion blur or content.
The fix it's pointing you at
If the node finds a temporal seam, the README's measurements are unambiguous: raise temporal_size (or turn temporal tiling off entirely) and cut tile_size instead. The 24-frame period in the example is arithmetic - a temporal_size of 32 with overlap 8 means the tile steps 3 latent frames, which is 24 pixel frames at 8× compression. Meanwhile the spatial tile is where the memory wall actually lives: in the pack's testing, cutting spatial tile size from 768 to 384 took a 912-second, VRAM-thrashing float32 decode down to 60 seconds with no visible seam (spatial tile-boundary excess measured 1.03–1.05× - noise). In bf16 tile size costs nothing; in float32, 768 is a 28× cliff. The short version: temporal tiling buys you a soft frame every N frames, spatial tiling buys you the same memory savings without the artefact. Tile space, never time.
One caveat: the sharpness heuristic is exactly that. Grain or heavy film-look post-processing will lower absolute sharpness and could make everything read as "soft" - if the report floods with dips at dip_threshold 0.93, the node is measuring your grain, not a seam. Raise the threshold a notch before you blame the decode.
Install
ComfyUI Manager (search "comfyui-vae-float32"), or:
cd ComfyUI/custom_nodes
git clone https://github.com/AndreiOrehov/comfyui-vae-float32
Restart. No extra dependencies. It's a diagnostic node - you run it once per tiling setup, read the verdict, set your tiling once, and mostly forget it exists. Which is the right relationship with a tool that exists to catch the bug you can't see.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | The decoded sequence to inspect. Needs enough frames for a pattern to show - a handful of frames cannot prove periodicity. | |
| dip_threshold | FLOAT | 0.9300.5–0.999 | A frame is called soft when its sharpness drops below this fraction of the previous frame's - 0.93 means a 7% fall. Lower it to catch fainter seams at the cost of flagging ordinary motion blur; raise it if a fast-moving shot reports dips everywhere. Isolated dips are usually content: only REGULARLY spaced ones are a tiling seam, and the report says which it found. |
| check_spatial | BOOLEAN | true | Also look for vertical/horizontal seams left by SPATIAL tiling. Only regular, repeating peaks are reported - a single strong edge is content, not a seam. |
| predict_from_temporal_sizeopt | INT | 00–4096 | Set this to the temporal_size the decode used and the node will PREDICT where soft frames must land, instead of only finding them afterwards. The spacing is arithmetic, not luck: tile_t = temporal_size / the VAE's temporal compression, and a seam falls every (tile_t - overlap_t) x compression frames. 0 = predict nothing, just measure what is in the batch. |
| predict_from_temporal_overlapopt | INT | 80–4096 | The temporal_overlap that went with it. Only read when predict_from_temporal_size is not 0. |
| temporal_compressionopt | INT | 81–64 | How many output frames the VAE packs into one latent frame - 8 for LTX-2.5. Wrong value here shifts the predicted spacing by the same factor, so check it against your VAE rather than assuming. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| sharpness_plot | IMAGE | Per-frame sharpness as a plot, with the soft frames marked - a temporal seam shows up as evenly spaced dips. |
| report | STRING | Which frames went soft, whether their spacing is regular enough to be a tiling seam rather than motion, and what to change if it is. |