Nodes/ComfyUI-Darkroom/Reciprocity Failure
ComfyUI Node

Reciprocity Failure

Reciprocity Failure — the color cast no digital sensor has

By jeremieLouvaert·Created 5 months ago·Updated 2 days ago· 101
Reciprocity Failure
  • image
  • image
filmKodak Portra 400
exposure_time1.0
strength1.00

Reciprocity Failure is one of those Darkroom nodes that exists purely because the author actually shot long exposures on film. Digital sensors keep their sensitivity and color no matter how long you expose; film doesn't. Past a certain shutter time, the emulsion's response stops being linear - it loses speed, and different color layers lose it at different rates. That's the Schwarzschild effect, and it produces a color cast plus crushed shadows that are a dead giveaway of real long-exposure film. This node simulates both.

It's a niche effect, and you should treat it as such. Nobody needs reciprocity failure on every image. But for night shots, astrophotography, long-exposure seascapes, or any image you want to sell as "shot on film at 30 seconds," it's the detail that makes the difference between a grade and a believable capture. In the film-emulation flow you'd run it early - it's part of the negative-side chain, before Print Stock - and it's color-only, so it's fully legal in a LUT bake.

How it works

The model is grounded in manufacturer datasheets - Kodak E-31 and Fuji's published reciprocity corrections - not eyeballed numbers. Each film has a table of exposure times mapping to two quantities: stop loss (how much speed the film gives up, which drives the shadow crush) and the CC correcting filter Kodak/Fuji recommend at that exposure. The node's key insight: a film's native cast is the inverse of the recommended correction filter. So the E100 datasheet says "add a CC filter to fix cyan-blue" - and that means the uncorrected film goes cyan-blue. The cast is rendered as a color shift (renormalized to keep brightness steady), and shadow crush follows the stops lost, toe-weighted so deep shadows drop faster than midtones.

Below a film's reciprocity onset, the effect is zero - the node doesn't invent drama where physics says there is none.

The inputs

  • film (enum, default Kodak Portra 400) - six choices: B&W (general), Kodak T-Max, Kodak Portra 400, Kodak Ektachrome E100 (cyan/blue cast), Fuji Provia 100F (magenta), Fuji Velvia 50 (green). Pick the stock whose cast you want; the names are the character.
  • exposure_time (0.5–600 s, default 1) - your metered exposure time. It drives the magnitude through the film's log-time table; past the onset, longer = stronger cast and crush.
  • strength (0–1, default 1) - blend between the original and the simulated result, like every node in the pack.

Output is image. Chain it right after your film stock and before Print Stock for the full photochemical pipeline.

Install & notes

Same as every Darkroom node: Manager → search "Darkroom", or git clone https://github.com/jeremieLouvaert/ComfyUI-Darkroom + pip install -r requirements.txt + restart. Pure numpy, no GPU, no downloads.

The honest caveat: this is datasheet-character-grounded, not per-roll calibrated - film aging and batch variance are real and outside the model. And if your image isn't actually a long exposure, the effect reads as "random color cast." Use it deliberately. Set exposure_time to what the scene was shot at, and let the datasheets do the arguing.

CategoryAKURATE/Darkroom/Film

Inputs (4)

NameTypeDefaultDescription
imageIMAGE
filmCOMBOKodak Portra 400Film stock — sets the reciprocity character (speed loss + long-exposure color cast)
exposure_timeFLOAT1.00.5–600Metered exposure time in seconds. Drives the magnitude via the film's log-time table. Below the film's reciprocity onset = no effect
strengthFLOAT1.000–1Blend between original (0) and simulated (1)

Outputs (1)

NameTypeDescription
imageIMAGE