Video Motion Contact Sheet
The storyboard that tells a model what happened
- video
- frames
- contact_sheet
- sampled_frames
- prompt_hint
Every so often someone on r/comfyui asks "how do I show a video's motion in one image?" - and the answer used to be: decode frames manually, grid them with an image node, and hope the timing survives. Video Motion Contact Sheet (Experimental) is that idea, done properly: it samples an N×N chronological storyboard from a video or a frame batch, arranges it as a contact sheet, and - the genuinely clever part - can weight the sampling toward the frames where things actually move.
The name is the summary. This is a motion contact sheet, not a uniform one: leave sampling on uniform and you get evenly spaced frames preserving timing; switch to motion_weighted and the panels concentrate where visual change is strongest, which is what you want when the interesting action happens in one burst and the rest of the clip is two people standing still.
How it works
It decodes exactly grid_size² frames in chronological row-major order, measures per-interval visual change to build motion scores, and renders each panel with an optional "film strip" treatment - rails, perforations, and labels on the lower rail. There's a prompt_hint output that's a ready-made instruction string telling an image model to "read its frames from left to right, then top to bottom... do not reproduce frame numbers, timestamps, film borders, perforations." That's the trick that makes this more than a debug view: the contact sheet is designed to be fed back into an image or video model as reference conditioning.
The inputs that matter
- video or frames - exactly one.
videotakes a loaded ComfyUIVIDEO;framestakes an already-decodedIMAGEbatch. Connect both and it errors on purpose. - grid_size - 2 to 8, default 3. That's 4 to 64 panels.
- sampling -
uniform(default) ormotion_weighted. - width / height - 0 derives from the source aspect and the other dimension. These are for the sheet, not the panels.
- film_border - default on: film rails and perforations with labels on the lower rail. Off uses a narrow caption rail for labels instead.
- annotation -
none,index,timestamp, orindex_timestamp. Timestamps derive fromimage_frame_rate(default 24) when the source is a frame batch. - gap - black pixels between panels; resize_mode -
fit,crop,stretchfor how each frame fills its panel.
Outputs: contact_sheet (the rendered grid), sampled_frames (the raw selected frames, if you want them separately), and prompt_hint (the instruction string).
How to install
Ships with ComfyUI Turing Utils ("comfyui-svdint4" in Manager):
cd ComfyUI/custom_nodes
git clone https://github.com/wjie98/comfyui-svdint4
cd comfyui-svdint4
python -m pip install -v --no-build-isolation -e ./kernel
Pure Python and image work - no kernel dependency for this node, but the pack installs as a unit.
The honest take
This is the one node in the pack you'd reach for even on a modern card, because it's not about performance - it's about seeing. Use uniform when you're eyeballing timing, motion_weighted when you want the story of the action, and feed the sheet plus prompt_hint into a reference-conditioned model when you want a continuation to understand what already happened. It's marked experimental, and it is - the film-border look is optional taste, not quality. But for "what actually happened in this clip, at a glance," it's the best answer in this pack.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| grid_size | INT | 32–8 | Sample exactly grid_size squared frames in chronological row-major order. |
| sampling | COMBO | uniform | Uniform preserves timing. Motion weighted allocates more panels to intervals with stronger visual change. |
| width | INT | 00–8192 | Final sheet width. 0 derives it from the source aspect and the height setting. |
| height | INT | 00–8192 | Final sheet height. 0 derives it from the source aspect and the width setting. |
| resize_mode | COMBO | fit | How each sampled frame is fitted into its panel. |
| gap | INT | 00–64 | Black pixels between adjacent panels. |
| film_border | BOOLEAN | true | Wrap every panel in film rails and perforations. Labels are printed on the lower rail. |
| annotation | COMBO | index | Optional chronological label. Without the film border, labels use a narrow caption rail outside the frame. |
| image_frame_rate | FLOAT | 24.000.01–1000 | Used only to derive timestamps when the source is an IMAGE batch. |
| videoopt | VIDEO | A loaded ComfyUI VIDEO. Connect either video or frames, not both. | |
| framesopt | IMAGE | An already decoded video frame batch. Connect either frames or video, not both. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| contact_sheet | IMAGE | — |
| sampled_frames | IMAGE | — |
| prompt_hint | STRING | — |