Long Exposure
Handheld long exposure that's a real camera path, not a smear
- image
- subject_mask
- image
Don't call this a motion blur node, or the author will be annoyed. A long exposure isn't one smear - it's the image integrated over a sequence of camera poses. That's what this node does: it samples the exposure across poses camera positions and gathers them into the final frame, so the movement physically accumulates the way it does on a sensor. That's also why it never tears or leaves holes - it gathers instead of pushing. And it's fast: about 0.2s at 1024 on GPU.
The path it integrates has two physically distinct parts, and that split is the whole point. First, the deliberate gesture: the hand doesn't travel at a steady rate, it dwells, then swoops - non-stationary movement with a real direction. That dwelling is what leaves a readable core with the smear trailing off it. Second, the involuntary tremor: the node uses a measured physiological hand spectrum - roughly 90% of the movement below 3.5Hz and 24% in the 7.5–12.5Hz tremor band - and it does not speed up just because the gesture does. Because the path wanders back over its own track, edges pick up ghosted doubled copies. That's the single most recognizable signature of a real handheld exposure, and a one-angle smear can't produce it.
The inputs. Four are required, and they're well-named:
exposure_px- how far the camera wanders, in pixels. This is your intensity dial: shutter speed and hand steadiness rolled into one. 0 returns the image bit-exact, untouched.hand_steadiness- the character of the shake, not its size. 1.0 is a real human hand. 0 is a smooth tripod-like drift; above 1 the jitter starts reading as digital, not photographic.variety- how much the movement changes during the exposure. 1.0 gives roughly a 4x spread between slowest and fastest stretches, 2.0 about 6x. This is the dwell-vs-swoop knob.roll_deg- twist about the lens axis. It's the only part of the shake that varies across the frame: corners sit further from the axis so they smear more, and the centre stays exactly still. 0 gives a pure shift.
Then seed - literally "which hand" - and poses (96 default), which trades between smooth smears and a strobe look at the low end.
The pro input is subject_mask. This is the one thing a single camera path cannot express: a subject moving separately from the camera. Mask the subject and it smears against a still background; invert it and the subject holds sharp while the world blurs around it. If you've ever tried to fake "person standing still, city moving past" with a regular blur node and given up, this is the fix.
Install. ComfyUI Manager, search "Darkroom", or:
cd ComfyUI/custom_nodes/
git clone https://github.com/jeremieLouvaert/ComfyUI-Darkroom.git
pip install -r ComfyUI-Darkroom/requirements.txt
Restart, and it's under AKURATE/Darkroom/Lens. Just scipy and opensimplex in requirements - no models, no API keys. The output is a single image, so it slots straight into a preview or save node. Start at the defaults (exposure_px 45, hand_steadiness 1, variety 1) and adjust exposure_px until the smear feels right - most people dial it down, because 45px at a readable subject is already a lot of motion.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| exposure_px | FLOAT | 450–300 | How far the camera wanders during the exposure, in pixels. The intensity dial: it is the shutter speed and the steadiness of the hand rolled into one. 0 returns the image untouched, exactly. |
| hand_steadiness | FLOAT | 1.000–4 | Character of the shake, not its size. 1.0 is a real human hand -- the default reproduces the measured tremor spectrum (about 90% of the movement below 3.5Hz, 24% in the 7.5-12.5Hz tremor band). 0 is a perfectly smooth drift, like a slow tripod pan. Above 1 the hand gets jittery and the smear starts to read as digital rather than photographic. |
| variety | FLOAT | 1.000–3 | How much the movement CHANGES during the exposure. This is intentional camera movement, so the hand does not travel at one steady rate: it dwells, then swoops, or whips and then settles. 0 gives a uniform drift (every part of the exposure moving at the same speed, which reads mechanical). 1.0 gives roughly a 4x spread between the slowest and fastest stretch; 2.0 about 6x. Dwelling is what leaves a readable core with the smear trailing off it. |
| roll_deg | FLOAT | 1.50–15 | How much the camera twists about the lens axis. This is the only part of the shake that varies ACROSS the frame: corners are further from the axis, so they travel further than the centre, which is exactly zero. Set 0 for a pure shift. |
| seed | INT | 00–4294967295 | Which shake. Same seed gives the same hand. |
| subject_maskopt | MASK | Where the movement applies, 0 to 1. This is how a SUBJECT moves separately from the camera -- the one thing a single camera path cannot express. Mask the subject to smear it against a still background, or invert it to hold the subject sharp while the world moves around it. | |
| posesopt | INT | 968–256 | How many camera positions the exposure is sampled at. Too few and the smear breaks into visible separate copies (which is a real look, just a different one -- a strobe rather than a smear). Cost is linear in this. |
| vary_per_frameopt | BOOLEAN | false | Re-roll the shake for each frame of a batch. Off means one exposure applied to every frame. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |