Nodes/ComfyTimeline/Timeline Image Viewer
ComfyUI Node

Timeline Image Viewer

Scrub an image batch like a video, and every node scrubs with it

By FemtoStudio·Created 3 months ago·Updated about a month ago· 0
Timeline Image Viewer
  • images
  • mask
    start_frame0

    The 30-second pitch

    You generate a 30-frame batch, ComfyUI auto-plays a preview that's over before you've located frame 12, and dragging the slider leaves you asking "which frame is this again?" Timeline Image Viewer exists to fix exactly that: it turns an IMAGE batch into a frame-accurate sequence viewer you scrub against one shared playhead - the same playhead every other timeline-aware node in the ComfyTimeline pack follows.

    It's frontend-only. No output sockets, no processing. You feed it images, it shows them, and it never gets in the way.

    Why you'd actually use it

    The killer feature is the shared playhead. In any animation workflow - per-frame strength modulation, a Wan or LTX clip you're grading frame by frame, or just a stack of img2img passes you want to walk through - the viewer and the pack's Timeline Animation curve editor move together. Scrub to frame 57 in the viewer, and every timeline-aware node is sitting on 57 too. One timeline for the whole graph instead of each node guessing its own.

    It's also cache-correct in a way that matters: the playhead is deliberately not part of the node's cache key. The source comments spell out why - a current_frame widget would rewrite every temp JPEG and re-run downstream on each scrub-plus-queue. Here, scrubbing is for your eyes, not the graph, so poking the bar never burns GPU time.

    How it works

    The Python side is deliberately minimal. It normalizes the batch, writes each frame as a JPEG (quality 85) into ComfyUI's temp directory, and hands the file names back through the standard ui payload - the same /view endpoint path PreviewImage uses, so no giant base64 blobs end up in the workflow JSON. The JS layer preloads those images and displays whichever one matches current_frame on the global bar. That preload is why scrubbing feels instant rather than choppy.

    Frames map by index: image 0 is the animation-range start frame, image N is start+N. Scrub outside the range and it doesn't error - it clamps to the nearest edge image.

    Inputs and outputs

    Three inputs, and only one you ever touch:

    • images - the IMAGE batch you want to view.
    • start_frame - maps the first image to a frame number; driven by the timeline bar's anim-range start, hidden on the node.
    • current_frame - display-only playhead, also driven by the bar. It does not alter the output.

    That's it. No outputs - it's a terminal display node, the end of a wire, not the start of one.

    Install

    Same as the whole pack. In ComfyUI Manager, search "ComfyTimeline", or:

    cd ComfyUI/custom_nodes
    git clone https://github.com/FemtoStudio/comfyui-timeline
    

    Restart, then open the Timeline tab - the bottom panel is hidden by default, so hit Alt+T (or View → Bottom Panel). No Python dependencies, no model downloads. One real caveat: the pack targets ComfyUI's newer node API (requires-comfyui >= 0.10.0), so if you're on an older ComfyUI the nodes simply won't register - update ComfyUI first.

    Where people get burned

    • The viewer doesn't export anything. It's a preview tool; when you're happy with a sequence, wire the batch into SaveAnimatedWEBP or an FFMPEG node for actual output.
    • You installed the pack and can't find the node - check the hidden bottom panel first, not the node menu. Alt+T.
    • You want scrubbing to "do something" to the output - it won't, and that's the design, not a bug. The playhead follows you; the graph only runs when you queue it.
    • Very large batches: preview work is capped at 10,000 frames and a 512 MiB CPU working-set limit. If a giant batch fails validation silently, that's the guardrail talking.
    CategoryAnimation/Timeline

    Inputs (3)

    NameTypeDefaultDescription
    imagesIMAGEImage batch to display as a sequence.
    start_frameINT0-9007199254740991–9007199254740991Frame number that maps to the first image in the batch. Driven by the global Timeline bar (anim-range start); hidden on the node.
    maskoptMASKOptional matte. When wired, each frame is multiplied by its mask (white = keep, black = out) before display. A single mask broadcasts across the batch; resolution mismatches are resized to the image.

    Outputs (0)

    No outputs