iOS — Fotufilm
A live film camera that develops the viewfinder in real time, plus offline video development. Everything runs on the device.
Most film simulation is a LUT — a curve pushed onto display values until the result resembles a photograph of a photograph. Fotufilm instead models the chain of physical processes between scene light and a finished print: spectral exposure, lens flare, scattering inside the emulsion, halation off the film base, development inhibitors bleeding between layers, the characteristic curve, grain, and the dyes' own absorption.
Grain, halation and colour crossover aren't painted on. They fall out of the physics, which is why they respond correctly to exposure, resolution and scene content.
One frame straight out of a digital camera, then the same frame developed four times. Nothing was graded or retouched in between — the only instruction given was the name of the stock.
Look at the white globes on the lamp: their highlights roll into the film's
shoulder instead of clipping flat. The two colour negatives differ only in
contrast and how far the reds sit back — that separation is colour crossover,
and it falls out of the three emulsion layers disagreeing about the same
light rather than a hue knob turned somewhere. Kodachrome stands apart from
both because it is a reversal stock: it develops straight to a positive, and
its layers run a gamma near three where a colour negative runs about six
tenths, which is the whole of why the sky deepens and the reds intensify.
The black and white frame
comes from the same engine with one dye layer instead of three, which is why
the red flowers go nearly black while the blue sky stays mid grey, exactly as
an unfiltered panchromatic film renders them. It uses
example-monochrome-100, a synthetic pack — plausible textbook
parameters rather than a measurement of any real emulsion.
A grain clump has a physical diameter and an areal density on the negative, so a smaller gauge enlarged to the same picture shows coarser grain — the clumps are the same size, there are just fewer of them across the frame. Below is one sky, developed on PRO 400H at three gauges, shown at 1:1 pixels. Nothing else changed.
The 16mm frame is a third the height of the 35mm one, so every clump is enlarged more than three times as much to fill the same picture. That is the whole mechanism — no grain texture is composited on, and no setting was touched between these three.
Light that the emulsion misses crosses the base, reflects off its rear surface and exposes the emulsion again a little way out. Red survives that round trip best, so bright edges bleed warm. Here it is on the lamp globes, at 16mm, with grain switched off so only the glow moves.
Turned up six times, because this source is an ordinary JPEG: its highlights were already clipped by the camera, so there is little of the above-white energy that drives halation on real film. At the stock's own strength the effect measures three times stronger in red than in blue — correct, but too subtle to see at this size. Feed the engine raw and it has the headroom to do this on its own.
Pick a frame, pick an emulsion, and adjust what the film itself does. The whole engine runs on the device — the stock strip renders every thumbnail live, from your own photograph.
Real screenshots, and the render is the same engine as everywhere else — the Kodachrome 25 frame in the middle is the one the command line produces from that photograph.
Scene-referred linear RGB goes in. Each stage models one physical process, in the order the light actually meets it.
# the whole thing, from the command line
brew install halide
swift run -c release filmsim photo.dng out.png --stock kodachrome64
swift run -c release filmsim render.exr out.tif --depth 16
A stock's numbers aren't compiled in. They arrive at run time as a JSON pack,
so the model and the emulsions it renders stay separable — any stock with a
published datasheet can be calibrated from scratch using the pipeline in
tools/calibration/, which ships with the engine.
Three skies photographed for MUA Studio, one stock each — a gradient is the hardest thing to render without banding or a colour cast, which makes it a good test of a pack.
The five calibrated packs were traced from the manufacturers' own
sensitometric and spectral plots. All five are discontinued products, and the
publications themselves are only ever fetched, never redistributed. The two
example- packs are synthetic — plausible parameter sets, not
measurements of anything — so every branch of the model can be exercised
without leaning on a real emulsion.
The FilmSim Swift package, with a Halide kernel shared by every
surface and a Metal path for real time.
A live film camera that develops the viewfinder in real time, plus offline video development. Everything runs on the device.
Stills and video through the same engine, decoded and encoded with AVFoundation.
filmsim takes JPEG, PNG, HEIC, 16-bit TIFF, OpenEXR, gain-map
HDR and camera raw.
A local bench for pulling sliders — exposure, grain, halation, couplers — against a live develop.
Fotufilm is free software under the GNU Affero General Public License, version 3. You may use, study, modify and redistribute it; if you run a modified version as a network service, the AGPL asks that you offer that version's source to its users. Third-party components and their terms are listed in THIRD_PARTY_NOTICES.md.