TimeSlice Effect
A rolling shutter you can art-direct
- images
- mask
- images
- mask
- num_frames
- slice_edges
The one-line pitch: take a video clip, split each frame into parallel bands, and show every band from a different moment in time. That's the whole trick - the same one a rolling-shutter camera or a slit-scan rig does by accident, except here you get sliders for it.
Why you'd reach for it: you generate a clip in ComfyUI - AnimateDiff, Wan, whatever - and it lands flat, because every frame is just a frame. TimeSlice Effect is the post-process that turns motion into streaks. It's deterministic, it runs in milliseconds, and it needs no model download, no LoRA, no heavy GPU pass. In ecosystem terms this sits in the post-processing corner of the graph (the WAS-Nodes / after-the-sampler corner, per the KB's ComfyUI-ecosystem essay), not the generation corner: it rearranges pixels you already have.
How it works. Don't think of it as a blur - think of it as a gather. Each pixel is assigned to a slice (via the angle's projection axis), each slice gets a frame offset, and the output pixel is read from whichever frame that offset lands on. Slice 0 reads the current frame, slice 5 reads frame t+5, and the band sweeps later in time as it crosses the frame - a cascade of motion trails. All of it is a vectorised numpy/torch index-and-gather, which is why it's instant and why there's no model to download.
The inputs that matter (most have sensible defaults):
- images - your clip. It has to be a batch of frames, not a single image. With one frame there's nothing to displace and the node has nothing to do.
- num_slices - bands per frame. 20 is chunky and blocky; 40+ gets smooth and silky.
- offset - frame step between neighbouring slices.
1= subtle smear, higher = longer time trails. Negative reverses the direction. - angle -
0= vertical slices,90= horizontal,45= diagonal. It decides where the trails point. - spacing - how slice widths are distributed.
random+ a fixed seed gives irregular, glitchy bands. - direction - where the displacement builds:
forward,reverse,center_out,edges_in. - loop_mode - what happens at the clip ends.
loopwraps (seamless for looping clips),ping_pongbounces,trimshortens the output so nothing ever wraps. - blend_width - soft cross-fade across band edges.
0= hard razor edges, which is honestly a good default for this look. - mask (optional) - slice only inside the white area; the rest of the frame stays untouched original footage.
The animate block - num_slices_end, offset_end, angle_end, temporal_curve, frame_count - is off by default, and worth switching on once a static cascade bores you. It interpolates slice count, offset and angle from start to end over the clip, so the effect can grow or swing mid-take.
Outputs. images goes straight to a Preview/Save Video node. slice_edges is a mask of the boundary lines - feed it into a glow or glitch overlay for the extra-credit look. num_frames is the real output length after trim chops it down; wire it into your saver so it doesn't throw a frame-count fit. mask passes your input mask through (or a solid white one if you didn't use one).
Install
ComfyUI Manager → search "TimeSlice Nodes" → Install, then restart. Or the manual route:
cd ComfyUI/custom_nodes
git clone https://github.com/systms-ai/TimeSlice-Nodes.git
Then restart ComfyUI. The only dependency is numpy - requirements.txt lists it, and torch comes from the ComfyUI runtime. No models to download. The node lives under Systms → effects.
Where people get burned
Feeding in a single still and seeing nothing happen - you need frames, full stop. Using trim and letting a saver assume the input length - read num_frames. And RAM: the node holds the whole clip in memory, so a long 1080p clip will chug on a modest machine no matter how fast the math is. That's not a flaw, it's the price of an in-memory effect; the README says it plainly. The good news: the blend is fully vectorised, so 2000 slices costs about the same as 20 - the clip size is what you actually pay for.
Recipe to start: num_slices 40, offset 1, angle 90, everything else default - a clean classic slit-scan. Then push offset to 6–10 and switch spacing to random with slice_jitter 4–10 for the glitchier cousin.
Inputs (18)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | Source video frames to slice. | |
| num_slices | INT | 201–2000 | Number of slices to divide the frame into |
| offset | INT | 1-120–120 | Frame offset step between slices. Negative reverses time. |
| angle | FLOAT | 0-180–180 | Slice angle in degrees. 0 = vertical, 90 = horizontal, 45 = diagonal. |
| spacing | COMBO | How slice widths are distributed across the frame: even (linear), eased toward one side, or random. | |
| direction | COMBO | Which slices carry the most time offset: building from one edge (forward/reverse), from the centre, or from both edges. | |
| loop_mode | COMBO | How out-of-range frame indices are handled: wrap around (loop), bounce back (ping_pong), or shorten the clip (trim). | |
| blend_width | INT | 00–400 | Soft blend width (px) across boundaries. 0 = hard edges. |
| seed | INT | 00–4294967295 | Seed for 'random' spacing and slice jitter |
| cascade_curveopt | COMBO | How the per-slice offset grows across slices. | |
| slice_jitteropt | INT | 00–60 | Random +/- frames added per slice (seeded). Adds glitchy irregularity. |
| animateopt | BOOLEAN | false | Animate slices/offset/angle from start -> end over the clip. |
| num_slices_endopt | INT | 601–2000 | Target slice count reached at the end of the animation. |
| offset_endopt | INT | 6-120–120 | Target per-slice frame offset at the end of the animation. |
| angle_endopt | FLOAT | 0-180–180 | Target slice angle (degrees) at the end of the animation. |
| temporal_curveopt | COMBO | Easing applied to the start -> end animation over time. | |
| frame_countopt | INT | 00–100000 | Frames over which the animation completes. 0 = use clip length. |
| maskopt | MASK | Optional mask. Slicing is applied only inside the white area; outside keeps the original frame. |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| images | IMAGE | — |
| mask | MASK | — |
| num_frames | INT | — |
| slice_edges | MASK | — |