Create Chronophotography
Turn any video into a Marey-style motion ghost still
- frames
- masks
- chronophotography
You know the look even if you don't know the name: a golfer mid-swing repeated four or five times along the arc of the club, a dancer frozen at every position of a spin, all in one frame. That's chronophotography, the 1870s-80s trick Étienne-Jules Marey and Eadweard Muybridge pioneered to study motion frame by frame - and it's exactly what CreateChronophotography reproduces from your video.
It's a tiny, honest little node: no model weights, no diffusion, no API, no key. The README pitches it as turning video into "motion stock image," and that's accurate. Feed it a batch of frames plus a mask per frame, and it composites the moving subject into one still that looks like the shot was taken with a camera that never closed its shutter.
Where it sits in a workflow
The catch is in that "plus a mask per frame." This node does not do segmentation - it's a pure compositor, and it will sit there staring at you if you only hand it frames. The included example workflow wires it as: VHS_LoadVideo → SAM2 video segmentation (with point prompts to track the subject) → CreateChronophotography → PreviewImage. So the real skill here is upstream: get a good per-frame mask of the moving subject (SAM2 video tracking, or a segmentation/background-removal pass like BiRefNet on sampled frames), and this node does the rest.
How it works
The mechanism is straightforward and worth knowing because it explains every knob. First it picks which frames to render, in one of two modes:
- arange -
start_frame,step_frame,stop_frame; takes everystep_frame-th frame in that range (defaults 0/30/100). - list -
render_framesas a comma-separated string of explicit indices like0,30,60,90.
The last picked frame becomes the background. Every earlier picked frame is then composited back onto it in reverse order: its mask is cleaned up (morphological open → close → dilate, keeping only the largest connected region so stray specks don't ghost into the shot), blurred into a soft alpha using gaussian_blur_size, and blended in. Earlier positions end up as progressively fainter ghosts behind the newest one. Output is a single IMAGE (chronophotography) - just wire it to a save or preview node.
The inputs that matter
frames(IMAGE) andmasks(MASK) - a batch of frames and one aligned mask per frame. Same count, same order, or it silently skips whatever doesn't line up.mode-arangeorlist; pick your poison for choosing which frames appear.gaussian_blur_size(default 21, odd, 1–101) - the big artistic knob. Higher = softer, more ethereal ghosts; lower = crisp stacked copies.morphology_kernel_size(default 5, odd, 1–15) - how aggressively it denoises the masks before compositing.
That's honestly the whole thing. Two knobs you'll actually touch, everything else defaults fine.
Installing it
The easy way: ComfyUI Manager → search "ComfyUI-chronophotography" → install. Or manually:
cd ComfyUI/custom_nodes
git clone https://github.com/kusurin/ComfyUI-chronophotography
# restart ComfyUI
Refreshingly light on dependencies - requirements.txt is just numpy and opencv-python (torch comes with ComfyUI). No model files to download. If you see a cv2 import error, it means opencv-python didn't get installed; pip install opencv-python in your ComfyUI environment fixes it.
Gotchas
- Don't feed it bare frames. Without masks the compositing has nothing to blend, and you'll get a single, boring background frame - which is also what it does silently when none of your frame indices are valid. If it "did nothing," check your indices against the actual batch length first.
- Default
step_frameis 30. On a 24–30 fps video that's roughly a second between ghosts, which is the right vintage-motion-study spacing - but on a slow-moving subject you may want smaller steps or thelistmode. - It keeps only the largest mask region per frame. If your subject is two disconnected things (a dancer and a swirling prop), only the biggest survives each frame. That's a deliberate choice in the code, not a bug - but it will surprise you the first time.
It's a niche tool with zero fanfare behind it, but when you want that specific "one frame, many positions" poster shot, it's the exact node you'd hand-roll anyway - just in a tidy package.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| frames | IMAGE | — | |
| masks | MASK | — | |
| mode | COMBO | arange | 2 options: arange, list |
| start_frameopt | INT | 0 | — |
| step_frameopt | INT | 30 | — |
| stop_frameopt | INT | 100 | — |
| render_framesopt | STRING | 0,30,60,90 | — |
| gaussian_blur_sizeopt | INT | 211–101 | — |
| morphology_kernel_sizeopt | INT | 51–15 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| chronophotography | IMAGE | — |