The Redlamp app icon: a glowing ruby safelight lens in a steel bezel

Redlamp

A native, open-source RAW photo editor for Mac, iPad, and iPhone that anyone who knows Lightroom will find familiar.

CI status on main Latest release macOS 26 or later, on Apple Silicon Swift 6.2 License: MPL-2.0
Redlamp's website, redlamp.app Join Redlamp on Discord Support Redlamp on Ko-fi

Redlamp is built from scratch in Swift and Metal for Apple Silicon. It focuses on one thing, *developing* photos, and aims to do it faster and more natively than anything else on the platform. ![Redlamp editing a Sony α7R V raw file](docs/images/hero.png)

Watch the film: Introducing Redlamp (1:42, on YouTube)

> **Status: alpha, iteration 2 (macOS).** The core RAW pipeline and the Develop workspace work today: Basic (with Texture, Clarity and Dehaze), Tone Curve, Color Mixer, Color Grading, Detail (noise reduction and sharpening), Effects, lens corrections, crop and Upright, **masking** (gradients, brush, color and luminance range, Subject, Sky, Background, People and its parts, Objects, Landscape and Depth Range) with local adjustments, **healing and removal** (Heal, Clone, Remove, content-aware or generative, and Remove Dust), **focus stacking**, and **Base Looks** and **Recipes**, Redlamp's profiles and presets, with film looks measured from cameras' own renderings and **[film simulations](#film-simulations)** of 36 film looks from 30 stocks, built from the manufacturers' datasheets. AI Denoise and the rest of Develop parity are next, then 1.0 and the iPad and iPhone apps. See [Where we are](#where-we-are), the [Roadmap](#roadmap), and [how Redlamp compares with Lightroom](docs/lightroom-comparison.md). > > This README is the project's primary status page and is kept up to date as work lands. *Last updated: 4 October 2026.*

Redlamp's measured performance on an Apple M1 Ultra with a Release build, 29 Sep – 27 Oct 2026: 1.8 ms to render a slider change; 160 ms to open a 24 MP raw; 317 MB peak, browsing 50,000 photos (measured under load); 1.3 GB GPU, 1:1 with noise reduction; 30.4 MB to download; 67.5 MB installed.

--- ## Contents - [Why Redlamp](#why-redlamp) - [Goals](#goals) - [Where we are](#where-we-are) - [Film simulations](#film-simulations) - [Screenshots](#screenshots) - [Roadmap](#roadmap) - [Installation](#installation) - [Getting started](#getting-started) - [Component harness](#component-harness) - [Using Redlamp](#using-redlamp) - [Architecture](#architecture) - [Contributing](#contributing) - [Support Redlamp](#support-redlamp) - [License and acknowledgements](#license-and-acknowledgements) --- ## Why Redlamp A **red lamp** is the darkroom safelight: the one light you can work by without fogging the paper. That is the idea behind the project: you can see and shape your photo freely, and the original is never harmed. Lightroom defined how millions of photographers edit, but it is a cross-platform application that doesn't feel at home on a Mac, iPad, or iPhone, and it is tied to a subscription and a cloud. Redlamp keeps the workflow photographers already know, including the panel layout, slider names and ranges, and keyboard shortcuts, and rebuilds everything underneath as a native, GPU-first, open-source application. **Redlamp works on your folders.** It keeps a working set of folders, as Lightroom Classic's Folders panel does, and stores edits in small sidecar files next to the photos. A library built the same way is planned for 1.0 ([roadmap](#roadmap)): folders on your disk stay the organisation, ratings, keywords and collections are saved with each photo, and an index on your Mac, there only for speed, is designed for libraries of a million photos. ## Goals 1. **Immediately familiar to Lightroom users.** The Develop module's layout, panel order, slider names, ranges and defaults, and single-key shortcuts all carry over. We copy conventions, never Adobe's assets. Profiles and presets are kept apart, as in Lightroom, under Redlamp's own names: a profile, film stock or LUT is a **Base Look**, and a preset is a **Recipe**, which can set a Base Look as a preset can include a profile. Base Looks have a panel of their own, before Recipes in the left column, because a photographer chooses the look first and edits from there. Lightroom's words still work as tooltips and in search. 2. **Best-in-class masks.** Masks are part of the architecture from day one. Every edit is a layer (adjustments plus a mask), with Lightroom's model of components combined by add, subtract, and intersect, and on-device AI masks built on Apple Vision and SAM-class models. 3. **Modern, native UI and great UX.** The UI follows the macOS and iOS 26 design language. Liquid Glass is used only on floating chrome, and editing surfaces stay neutral grey so nothing distorts your color judgment. It is direct-manipulation first, every action can be undone, and there are no modal dialogs while you edit. 4. **Extreme responsiveness.** Rendering and UI are strictly separated. Slider changes should reach the screen within a frame (under 16 ms), and the UI thread never waits on the engine, the disk, or the GPU. 5. **Serious color science.** The pipeline is linear and scene-referred up to the tone curve: white balance, exposure, tone, Dehaze and the detail stage, and their masked versions, work on the light the camera recorded, and the color controls, the point curve, vignette and grain work on the tone-mapped image after it ([the pipeline](#architecture)). It uses the camera profiles DNG files embed, and has LUTs, lens profiles, and our own looks. Some looks are fitted by measurement to cameras' own renderings. 6. **Computational photography built into the editing workflow.** - **Best-in-class denoise:** a classical, noise-profiled denoiser plus an on-device AI denoiser that runs directly on raw data. - **Focus stacking in one click,** from detecting a bracketed sequence to an editable result, with pro-level strategies and retouching. This is something Lightroom doesn't offer at all, and dedicated tools only offer with a lot of friction. - **AI where it clearly wins:** masks, removal and upscaling, running on the device with no cloud and no credits. 7. **Mac first, then iPad and iPhone from the same engine.** A single platform-neutral engine sits under thin, native shells. The Mac editor comes first; iPad and iPhone follow once the main features are complete, and edits will move between devices through iCloud Drive, Files, and Photos. 8. **Open source (MPL-2.0).** The license is compatible with the App Store. Algorithms are implemented clean-room from papers and specifications. ## Where we are ### What works today (macOS) **RAW pipeline (our own, GPU-first)** - [x] Decodes RAW files through LibRaw (unpacking only). Black levels, white balance, demosaicing, and color are all done by Redlamp on the GPU. - [x] Bayer demosaic by directional filtering with a posteriori decision (Menon, Andriani and Calvagno, 2007), with a dual pass that takes plain green where the neighbours differ only by noise, Markesteijn's X-Trans demosaic (ported from LibRaw under its CDDL licence), and linear DNG support (for example iPhone ProRAW). - [x] Hot pixels are repaired before demosaicing, judged against each photo's own noise level. - [x] Row and column banding is measured in the sensor's masked (optical-black) margins and subtracted with the black level, only where the margins show more than their own noise. - [x] **DNG gain maps** (OpcodeList2), such as phones' lens shading correction, are applied before demosaicing, and noise reduction scales with the noise they amplify. - [x] **Highlight reconstruction:** channels are no longer clipped at 1 after white balance, and photosites that did clip are rebuilt from their bright unclipped neighbours, using the colour measured around the clipped area. Fully blown areas stay neutral. From process version 15, highlights clipped in one or two colours keep the colour of what's around them when Highlights or Exposure pull them below white, so a clipped sky stays blue instead of turning lilac, and areas clipped in every colour fade smoothly to neutral. - [x] **Each camera's brightness:** for new edits (process version 16), a raw opens about as bright as its camera's own JPEG, from a table of 576 cameras Redlamp measures from the camera bench's CC0 files, never from Adobe's data; a camera it lacks gets its maker's value, and a calibration from a target takes its place. Held out, every maker's photos open within a tenth of a stop of their JPEGs in the median, where Redlamp's default ran up to 0.6 stops darker (CAM-29). - [x] Tested on Sony **ARW**, Canon **CR3**, Nikon **NEF**, Fujifilm **RAF** (X-Trans), Apple **ProRAW DNG** and Google **Pixel DNG**, plus JPEG, HEIC, TIFF, and PNG. - [x] The demosaiced image is cached as a full mip pyramid, so interactive renders sample the right resolution for the zoom level. - [x] A single fused Metal kernel applies every per-pixel adjustment. Frames are delivered as IOSurfaces, so pixels are never copied between engine and UI. - [x] Latest-wins render scheduling: a burst of slider events collapses to the newest one. Stills wait in two lanes, previews (look thumbnails) ahead of exports, and yield to the canvas between tiles, so an export never holds up a frame by more than a tile; a cancelled still stops at its next tile, and exports rest between tiles when the Mac runs hot. - [x] Rendering stays off the main thread while you drag a slider. Frames go straight to the canvas, which a dedicated display-link thread presents, and each view observes only the values it shows. - [x] Both side panels are AppKit: the histogram, tool strip and every Develop and Masking panel on the right, and the Navigator, Folders, Base Looks, Recipes, Snapshots and History on the left, built from the same panel component. The right column's panels match their SwiftUI originals pixel for pixel, and a component harness is used to build and review them (see [Component harness](#component-harness)). - [x] Temperature and tint use a proper camera white-balance model (Robertson's method with the camera's color matrix). As Shot, Auto, and the illuminant presets all work. **Develop adjustments that render** - [x] **White balance:** Temp and Tint, the presets, Auto, and the eyedropper. - [x] **Basic:** Exposure, Contrast, Highlights, Shadows, Whites, Blacks, Vibrance, and Saturation, plus the **Auto** button. - [x] **Treatment** (Color or B&W) and **Base Looks** (Lightroom's profiles) with an Amount slider (0–200) and a browser that renders every look on the photo. There are six built-in looks (Redlamp Color, Neutral, Vivid, Landscape, Portrait and Monochrome) and 15 film-style looks built on 3D look tables: slide, chrome, negative, cinema, bleach and black and white through color filters. Four of them are measured from cameras' own renderings by the look profiler (see [Recipes and looks](#recipes-and-looks)). The Base Look menu lists these, Redlamp Reproduction and a photo's own camera look, and for a raw, the photographer's own Adobe camera profiles for its camera, read where Lightroom Classic or Camera Raw installs them or from files they choose and used on that Mac only (TON-51, TON-52); it shows a film look or an imported LUT first only while it's the photo's look (DEC-74). Every look, film stock and LUT is listed in the **Base Looks** panel, before Recipes in the left column, in folders (Favorites, In This Photo, the photo's camera profiles, Redlamp, Film Styles, Film Stocks, Fujifilm LUTs, Imported and Reproduction) and with its own search, which reads names, summaries, makers and kinds: hover a look to preview it, click it to apply it, and the photo's look is highlighted in its folder. Its **+** menu imports a LUT, chooses camera profiles or opens Fujifilm's LUT page. Right-click an imported look for **Show in Finder** and **Move to Trash**, or an installed look no recipe uses for **Remove from Base Looks**; a look moved to the Trash or removed is listed nowhere afterwards, and the photos that use it keep rendering with it. Right-click a built-in folder (Adobe Raw, Camera Matching, Creative, Redlamp, Film Styles, Film Stocks, Firmware Model or Reproduction) to hide it from the panel, its search and ⌘K, as in **Hide “Film Stocks”**; the panel header's right-click menu shows it again (UX-55). Wherever a look is chosen, a film stock brings its own grain, halation and bloom, and B&W for a monochrome stock, and leaves every other setting as it was; a look that isn't a film stock, chosen in place of one, takes the film's grain, halation and bloom away, and a colour look chosen in place of a monochrome one sets Color (UX-54). - [x] **Tone Curve:** a parametric curve with split points, and a point curve with presets, for all three channels together or for red, green and blue on their own. - [x] **Color Mixer:** HSL (Hue, Saturation, Luminance, and All) and a per-color mode, working in OKLCh. - [x] **Color Grading:** 3-way and individual wheels, Blending, and Balance. It also tints B&W images for split-toning. - [x] **Effects:** post-crop vignette (amount, midpoint, roundness, feather, and Highlights to keep bright areas bright under a darkening vignette) and zoom-stable film grain. - [x] **Noise reduction** (Detail panel): Luminance with Detail and Contrast, and Color with Detail and Smoothness. It is scaled to each photo's own noise: the DNG NoiseProfile tag, else its camera's calibrated profile at its ISO, else measured from the raw data when the file opens (a raw far cleaner than its camera's profile has had noise reduction in camera, so the measurement wins). Luminance keeps fine texture: wavelet shrinkage judges each detail by its neighbourhood, and at 1:1 and in exports a non-local-means pass guided by that result brings back texture where the photo repeats it. It runs as a cached stage in front of the fused kernel, so other sliders stay as fast as before, and exports render in tiles. For new edits (process version 16), values below black are kept from the raw data until after it, so the noise in the deepest shadows averages to their true level: at very high ISO they no longer lift and turn magenta (DN-12). - [x] **Sharpening** (Detail panel): Amount, Radius, Detail and Masking, in the same cached stage after noise reduction. It is noise-aware: detail is measured on a denoised copy of the luminance and applied to the untouched image, so the photo's noise and grain pass through as they were instead of being sharpened. Detail moves from a halo-limited unsharp mask towards Richardson–Lucy deconvolution of the Radius's blur, and holds back halos on strong edges; Masking keeps flat areas untouched. It boosts luminance detail in stops, so it doesn't depend on exposure and leaves colors alone. - [x] **Texture and Clarity** (global): gains on medium (about 2–8 px) and larger (about 8–64 px) luminance detail, taken from the image pyramid in the same cached stage, so tiles and zoom levels agree. Negative values soften. For new edits (process version 9) Clarity is edge-aware: a strong edge isn't its detail, so it puts no bright and dark bands along a skyline or around a tree. From process 11, Texture, Clarity and sharpening read one decomposition of the noise-reduced photo: Texture keeps its strength on texture but no longer outlines strong edges, adds less noise, and matches a downscaled export at every preview size, and dragging Texture, Clarity, Amount, Detail or Masking takes a fraction of a millisecond at 1:1. - [x] **Dehaze** (global and in masks): the dark channel prior (He, Sun and Tang, 2009) with the airlight and a haze map measured when the photo opens; negative values add a veil. For new edits (process version 8) the haze map follows the photo's edges, so the sky beside a tree or a ridge has no pale glow. From process version 18, negative values add haze where the haze map finds it, toward a slightly cool veil, so the distance and bright, unsaturated areas fog over while nearby dark, saturated things keep their contrast (TON-55). **Masking** (Lightroom's model) - [x] Each mask is a layer: its own adjustments plus a mask built from components. Components combine with **Add**, **Subtract**, and **Intersect**, and each can be inverted, as can the whole mask (**Invert**, as Lightroom's). - [x] **Linear and radial gradient** components. - Draw them on the photo. - Drag the handles to move, resize, and rotate; radial gradients also have a Feather control. - Pins select the other masks. - [x] **Brush** (`K`): A and B brushes and Erase (hold Option), with Size, Feather, Flow, Density and Auto Mask, and pen pressure. Strokes are kept as vectors in the edit and painted on the GPU in mask space (up to 4096 px), redrawing only the stroke being painted. `[` and `]` or ⌘-scroll change the size, with Shift the feather; the brush's ring shows its size as it changes, also from the panel's sliders, and Space-drag moves the photo while you paint. In every tool the wheel and pinch zoom. - [x] **Luminance Range** (`⇧Q`) and **Color Range** (`⇧J`): sample with the eyedropper, then shape the range with four handles (Show Luminance Map) or Refine up to five color samples. They select on the photo with its global edit, so the selection follows white balance and exposure. - [x] **AI masks:** Subject, Background and People (each person, or parts: face skin, eyebrows, eye sclera, iris, lips, teeth, and hair from iPhone mattes), with Apple Vision's built-in models and nothing to download. **Objects:** hover to preview, then click, drag a box around the thing or brush over it to select it; click or brush again to add, with Option to take away (Segment Anything 2.1, an 80 MB download on first use). **Depth Range:** from a photo's own depth map (iPhone), or estimated by Depth Anything 3 (or V2 Small). **Landscape:** a picker lists the regions found (water, vegetation, mountains, architecture, natural and artificial ground, and snow), each with its share of the photo, to mask together or one each, with adaptive presets such as Brighten Snow: SAM 3, converted to Core ML (a 988 MB download, under Meta's SAM License, which comes with it; Snow's prompt, added later, is in the app with a copy of the licence, so it needs no new download); the same model adds hair on any photo, facial hair, body skin and clothes to People. Sky is Segment Anything prompted inside a classical sky estimate, combined with Depth Anything 3 (converted to Core ML, a 336 MB download); the first time Sky is chosen without them, Redlamp offers both (416 MB together), and without them Sky is the classical estimate alone, which misses sky that objects cut off from the top of the frame; then every edge pixel is solved at full size against the sky's own colour, so twigs, leaf gaps and wires keep their own coverage. Subject, Background, People and Objects edges are solved per pixel too (closed-form matting), which brings back stray hairs and beard curls (see the [bake-off](docs/research/notes/MSK-17-sky-bakeoff.md)); with ViTMatte downloaded (Settings › Models, 111 MB), Subject, Background and People also gain the stray strands it finds beyond them. - [x] AI masks are computed from the photo without its edit and kept as bitmaps in the edit, so they never move when you edit and render the same everywhere. **Update AI Masks** recomputes them with today's models, pasted settings recompute them for the new photo, **Refine Edges** solves their edges again from the photo, as masks of their kind are made now (bringing back strands an older mask missed), the **Refine Edge Brush** solves an edge again, hair by hair, wherever you paint over it (kept with the mask, so Update AI Masks applies it again), and **Feather** and **Edge** soften an AI mask's edge or move it out or in. From process version 13, coarse AI masks (iPhone mattes, face parts) are refined again at the size the photo is drawn at, so they stay sharp at full size. From process version 14, a Sky mask's edit reaches only the sky's share of each pixel along its edge, so twigs and leaves keep their own colour and brightness when the sky is darkened or warmed, and **Feather** and **Edge** shape an AI mask's body while keeping its stray hairs. - [x] **Mask presets:** Blue Sky, Brighten Subject, Darken Background, Smooth Skin, Even Skin Tone, Whiten Teeth, Pop Eyes, Brighten Snow and Enhance Vegetation compute their masks for each photo, on one photo or every selected photo at once; save your own from any mask. - [x] **Beyond Lightroom:** a mask's **Detail** keeps only its textured (or only its flat) areas, and any mask can be reused as a component of another (**Existing Mask** in Add, Subtract and Intersect). - [x] **Local adjustments:** Temp, Tint, Exposure, Contrast, Highlights, Shadows, Whites, Blacks, Texture, Clarity, Dehaze, Hue, Saturation, Sharpness, Noise, a Color swatch that tints what the mask covers, and Curves (RGB, red, green and blue), plus the mask's Amount (0–200%). **Effects**, as in Lightroom's Effect menu, set a mask's sliders and Curves in one choice: Dodge, Burn, Warm, Cool, Add Detail, Reduce Haze, Smooth Skin, Whiten Teeth and Pop Eyes, with values of Redlamp's own, and your own saved from any mask. - [x] **Mask management:** one picker for every mask, also behind a mask's Add, Subtract and Intersect, which asks for a model's download in place. The list shows a thumbnail of each mask's coverage, and the photo shows the overlay while the pointer is over a mask, a component or a mask's pin. Each mask and each component has a menu (show and hide, rename, duplicate, "duplicate and invert", invert, reset, delete), masks and components drag to reorder, and Option-click on an eye shows one mask alone. **People** opens a picker of who is in the photo, as crops to tick, with the parts to mask, and a mask for each person if you like. A mask overlay (`O`) in Lightroom's modes (Color Overlay, on B&W, Image on Black or White, B&W, Image on B&W), colors and opacity. - [x] **Fast by design:** gradients and ranges are evaluated per pixel inside the same fused GPU kernel, and brush and AI masks are read from GPU textures. Up to 16 masks cost well under a millisecond extra at Fit. - [x] **Models on demand:** Settings › Models lists the downloadable models with their size, and removes them. Every model runs on the Mac; photos are never uploaded. Each shows its licence, which comes with the download. Models still under licence review are offered only when you turn on evaluation models. **Focus stacking** (a separate Stack workspace) - [x] **Stacks are found for you:** runs of frames with the same camera settings a moment apart, whose sharp region moves from frame to frame, get a "Focus stack detected: N frames" banner with **Merge**, and the filmstrip slides up for a few seconds to show it. Bursts, time-lapses and pans aren't offered. **Photo › Merge to Focus Stack…** and **Edit Focus Stack…**, also in the command palette, open the Stack workspace from the menus. - [x] **The result develops like a raw.** Frames are stacked as demosaiced camera RGB before any edit, so every Develop slider, white balance included, works on it. The stack is a small `.redlampstack` document beside the frames; the merged pixels are cached and rebuilt when needed. - [x] Alignment follows focus breathing, rotation and shift, brightness is matched frame to frame, and a depth map records which frame is sharpest where. - [x] **Auto, Smooth and Detail:** Auto takes tone and color from the depth map and fine detail from the sharpest frames near it; Smooth blends between frames for clean surfaces; Detail keeps the sharpest detail from anywhere, for hair and bristles. - [x] **The Stack workspace:** leave frames out, switch methods (each merge is cached), view the depth map, and **retouch** by painting the frame under the cursor, a chosen frame or another method's result over the merge. - [x] One frame is in memory at a time, and `redlamp stack` does the same from the command line. **Workspace** - [x] A Lightroom-style layout. On the left: Navigator, Folders, Base Looks, Recipes, Snapshots, and History, as collapsible panels like the Develop panels. In the center: the photo, with the filmstrip below. The filmstrip slides in when the pointer reaches the bottom of the window and away once it leaves; pinned, with the pin at the right end of its line of text, or with **Hide Automatically** turned off (View › Filmstrip, the filmstrip's own right-click menu, or Settings › Appearance), it stays up, and the photo is fitted above it. F6 hides it altogether. On the right: histogram, tool strip, and the Develop panels in Lightroom's order, each a card whose header shows a grey Edited chip while the panel has edits, with how many kinds of setting it has changed, as Copy Settings lists them ("Edited · 2"); hovering it lists them. - [x] **Folders**, as in Lightroom Classic: add folders with **+**, ⌘O or by dropping them on the window, and they're remembered (by bookmark, so a folder that's renamed or moved is followed). Each shows as a tree with the number of photos in every folder; click one to show it and everything beneath it in the filmstrip, its number counting its subfolders' photos too, as in Lightroom Classic, or turn off **Show Photos in Subfolders** (View menu or the folder's context menu) to see only its own photos. Nothing on disk is moved or changed. The filmstrip follows the disk by itself: photos copied in, deleted, renamed or rewritten appear, leave or update in place, a photo still being copied waits until it's complete, and the selection moves to the next photo when its own is deleted. A folder on a disk that isn't connected is dimmed with a question mark, **Locate…** points it at where it went, and it comes back when the disk does. Each folder reopens on the photo you last had in it. - [x] **Built to stay fast with any number of photos:** a folder lists without reading a single sidecar (badges follow from light reads, visible photos first); thumbnails decode in parallel on every core at the cell's size, from the smallest preview the raw file embeds that's big enough (found by LibRaw; 3 to 11 times faster than ImageIO's full-size one for Sony, Canon and Nikon files), are kept within a 128 MB budget in memory and cached on disk in one file per folder (at most 1 GB), and are warmed in the background while you're not waiting; the filmstrip is AppKit with reused cells, so 50,000 photos cost what a screenful does. Focus stacks are looked for one folder at a time in the background, and remembered. See [Measured performance](#measured-performance) and the [design](docs/plans/2026-10-02-folders-design.md). - [x] **Sliders:** click to jump, drag to adjust, Shift-drag for fine control, double-click to reset, and click the value to type one in or drag it to scrub (Shift for fine control). Option-dragging a tone slider shows clipping, as in Lightroom. The Color Grading wheels' hue, saturation and luminance, the tone curve's splits and its selected point's Input and Output, Base Look Amount, and in the Masks panel the overlay's Opacity, the Refine Edge brush's Size and the four stops of a luminance or depth range have values too. - [x] **Panels:** double-click a panel or group title to reset it, and Option-click a header for Solo Mode. The left column's panels collapse the same way when you click their headers, and Option-click shows only one. - [x] **Panel switches,** as in Lightroom: the eye at the right of every Develop panel's header but Basic's turns the panel's settings off and on, each a step in History. A panel that's off keeps its settings, dimmed, and does nothing to the photo, so Detail off is no sharpening and no noise reduction, and Lens Corrections off leaves out the lens correction the file carries. Changing one of its settings, or resetting it, turns it back on. The switches are saved with the edit and travel with the panel's settings when they're copied, pasted or synced. - [x] **Histogram:** clipping indicators, and you can drag across it to adjust Blacks, Shadows, Exposure, Highlights, or Whites. While the pointer is over the photo, the line under it shows the R, G and B percentages there, or its L\*a\*b\* values (relative to D50) with **Show L\*a\*b\* Values** in the histogram's right-click menu, the View menu or ⌘K, read from the render without the overlays. - [x] **Recipes** (Lightroom's presets), after Base Looks in the left column: 39 bundled recipes in eight groups, including camera-style ones built from Fujifilm-style recipe cards, 20 Mood recipes, and the border recipes of the Borders folder (see [Borders](#borders)). Hover to preview, click to apply, then adjust the recipe's Amount (0–200) at the top of the panel, drawn as the Develop panels' sliders are; a recipe's right-click menu has **Apply Base Look Only**, which previews its look alone while highlighted. Your own and installed recipes also have **Show in Finder**, which selects the recipe's file, and **Move to Trash** in place of Delete Recipe: every version of the recipe goes to the Trash, where it can be recovered, and photos edited with it keep their settings. A bundled folder hides from its right-click menu, as in **Hide “Night”**, and the panel header's right-click menu shows it again; Favorites, My Recipes, your own lists and Installed can't be hidden. A recipe that sets a Base Look still sets it, as a Lightroom preset that includes a profile does, and shows it on its row (the look's icon, such as a film's, or the Base Looks symbol) and names it in its tooltip. You can search recipes (Lightroom's words work; looks are searched in Base Looks), mark favorites, save the current edit as a recipe with a settings checklist (⇧⌘N), and import or export `.redrecipe` files. `.cube`, `.3dl` and HaldCLUT files import into Base Looks, from its + menu or dropped on either panel (LUTs made for camera log footage too, with their input space chosen on import, there and in the Recipe Lab). Lightroom develop presets (`.xmp`) import too, one, several or a folder at a time, by the menu or by dropping them on the panel, with a report of what came across exactly, approximately or not at all ([what maps](docs/recipes/lightroom-presets.md)). Snapshots are also available. - [x] **History** with full undo and redo. Each step shows an icon for what it did, and the value before and after ("Exposure 0.00 → +0.50"). Every time you open a photo a new session starts. The earlier sessions are kept with the photo (the last 20) and listed under the current one, and choosing one of their steps brings that edit back as a new step. - [x] **Camera-recipe controls** in the Effects panel: Dynamic Range, Color Chrome, Chrome FX Blue, and red and blue white-balance shift. - [x] **Viewing:** Fit, Fill, 1:1, and 2:1 zoom, click to zoom, pan, pinch, and a clipping overlay. Zooming out goes past Fit to a quarter of it, to see the photo as from a distance or on a small screen; the wheel and a pinch hold at Fit for a few steps first, so it's easy to stop there. **Sensor clipping** (`⌥J`) marks the photosites the camera clipped, in the colour of each clipped channel (black where all three did), whatever the edit has done since; the **colour-assessment view** (`⇧L`) puts the photo on middle grey inside a white frame (ISO 12646). **Before/After** (`\`) in three layouts, full frame, side by side and a diagonal split, cycled with `Y` and `⇧Y`; the original is rendered once and cached, so edits don't re-render it. - [x] **Themes:** Neutral greys by default, so nothing tints your judgment of color, plus a Redlamp theme and 20 dark and light families with a tint control, from the toolbar's Theme button or **Settings** (⌘,), which also has an About tab. The command palette follows the app's theme or takes one of its own. - [x] **Lightroom Classic's keyboard shortcuts**: 186 actions on 135 key bindings, from one registry that also drives the menus and an in-app ⌘/ reference (see [Keyboard shortcuts](#keyboard-shortcuts)). - [x] **Command palette** (⌘K): every action, with its shortcut shown beside it, every Develop slider, and pickers for white balance, treatment, Base Looks, recipes, Before / After, snapshots and history, all from the keyboard. - ↵ on a slider shrinks the palette to a slider bar over the photo: ← → step it (⇧ ×10, ⌥ finer), ↑ ↓ move to the next slider, and you can type a value or `x+0.3`. A run of presses is one history step. - Typing a name and a value, such as `exposure 0.7` or `temp 5600k`, sets it straight from the search. - Moving through a picker previews each choice on the photo; Esc goes back one level. - A hint bar always shows the keys that work right now, and each opening shows a tip. - ⌘F opens it for sliders only, searching by name or the words people use (Lightroom's older names too). - [x] **Sliders by hand:** ⌘-scroll over any slider adjusts it (Shift coarse, Option fine), and value fields accept arithmetic such as `x+10`. - [x] **Culling while you develop:** star ratings, pick/reject flags and color labels, shown on the filmstrip. There's also an Info overlay (`I`), Lights Out (`L`), full-screen preview (`F`), and Paste from Previous (`⌥⌘V` and the Previous button). - [x] **Copy, paste and sync settings, as Lightroom does:** Copy Settings… (`⇧⌘C`) opens a checklist of every setting and mask, remembered for next time; Paste (`⇧⌘V`) applies what was ticked, and recomputes the pasted AI masks for the photo. ⌘- and ⇧-click select several photos in the filmstrip: Sync… (`⇧⌘S`) and Paste reach all of them in the background, with Undo, and Auto Sync (`⌥⇧⌘A`) repeats every change. Right-click a photo in the filmstrip to copy its settings or paste onto it without opening it; on a selected photo, the menu has the same Copy, Paste and Sync items. - [x] Non-destructive edits, saved automatically to a sidecar file next to each photo (`IMG_1234.ARW.redlamp`). - [x] **Export dialog** (`⇧⌘E`): JPEG, HEIC, AVIF and JPEG XL (lossy, with quality and an optional file size limit) or PNG, TIFF and JPEG XL (lossless, with TIFF compression), 8, 10 or 16 bits, sRGB or Display P3. Resize by long edge, short edge, width and height, megapixels or percentage, keep all metadata, all but the location, or none (the first two also embed the edit recipe in the file's XMP, [format](docs/recipes/sidecar-format.md)), and choose the folder and file name. Built-in and saved presets, and Export with Previous (`⌥⇧⌘E`) repeats the last export without the dialog. - [x] **Report a Bug or Send Feedback** (the toolbar's Feedback button, the Help menu or the command palette, and Report… beside an error): files a GitHub issue for you, with no GitHub account needed, under an area picked from a list that mirrors the app (such as Masking › Objects), suggested from what you were doing. The report carries what you did in the last minutes, the open photo's camera and edit, and the Mac's details, and you see all of it before it's sent ([what it contains](#reporting-bugs-and-feedback)). Help › Your Reports lists what you've sent, with each issue's state and replies. - [x] **Test Your Camera** (Help menu or the command palette): the camera bench checks how your camera's raw files decode and compares Redlamp's rendering of each with the JPEG the camera saved inside it, on your Mac. It groups photos by camera and raw mode, picks a few of each, shows them side by side and asks one question, then sends only the measurements, which you see first, to add to the [cameras page](https://redlamp.app/cameras) ([how it works](docs/camera-bench.md)). `redlamp camera-bench` runs the same checks from the command line. - [x] **What's New:** after an update, the release's highlights open once, in the welcome window's look: the logo rises, the highlights are listed, and each has a page with a screenshot and a button that opens it, such as Test Your Camera…. **Help › What's New in Redlamp** shows the recent ones again. They come from redlamp.app, so they can be written after a release ships; when they can't be had, nothing opens and the next launch tries again. - [x] A headless `redlamp` command-line tool for rendering and export. Exports smaller than the photo are developed at full resolution and downscaled last, so sharpening, noise reduction and texture look the same at every size. ### Recipes and looks - [x] **One `.redrecipe` format** for presets, profiles and LUTs: an explicit list of setting groups, an optional Base Look pinned by content hash, immutable versions, and namespaced ids ready for sharing ([format](docs/recipes/recipe-format.md), [JSON Schema](docs/recipes/recipe-format.schema.json)). - [x] **Camera recipe cards:** Fujifilm-style recipes (film simulation, dynamic range, highlight and shadow tone, color, Color Chrome, white balance shift, grain) are a recipe dialect you can type in as the card lists them ([mapping](docs/recipes/camera-card-mapping.md)). - [x] **Fujifilm's published LUTs.** Download Fujifilm's film-simulation LUTs from [its LUT page](https://www.fujifilm-x.com/global/support/download/lut/) (**Get Fujifilm's LUTs…** in the Base Looks panel's + menu opens it) and drop the unzipped folder on the Base Looks panel: Redlamp recognises each file, reads it in the F-Log, F-Log2 or F-Log2 C space it names, and imports one look per simulation (ten from the GFX ETERNA 55 pack) into its **Fujifilm LUTs** folder, for any camera's raws. Fujifilm's terms allow personal use only, so the looks stay on your Mac and exported recipes carry only a reference to them ([details](docs/recipes/recipe-format.md#fujifilms-published-luts)). - [x] **Measured film looks.** The profiler fits a look to cameras' own JPEGs of the same raw files: Fujifilm raws carry the camera's rendering inside. On photos the fit never saw: | Base Look | Like | Measured from | ΔE to the camera (lower is closer) | | --- | --- | --- | --- | | Standard v3 | Provia | 120 photos, 50 bodies | 3.26 (Redlamp Color: 5.38) | | Vivid Slide v2 | Velvia | 10 bodies | 3.39 (4.45) | | Chrome v3 | Classic Chrome | 18 photos, 5 bodies | 4.61 (5.72) | | Soft Slide v2 | Astia | 5 photos, 3 bodies, provisional | 4.57 (12.84) | The others are hand-designed until there's data for them ([look development](docs/recipes/look-development.md#measured-base-looks-the-profiler)). Looks keep Redlamp's own names. - [x] **Film simulations:** 36 looks from 30 stocks, built physically from the manufacturers' datasheets, including pushed, overexposed, bleach-bypass and cross-processed variants, with halation, bloom and film grain, a **Film Looks** window and each film's icon in the Base Looks panel ([details](#film-simulations)). - [x] **Look-development tools:** lint (neutral axis, skin hue, monotonic lightness, banding, clipping) on a synthetic chart, golden renders per recipe version, style fingerprints and a fitter, and the **Recipe Lab** in the [component harness](#component-harness). - [x] **An agent recipe studio** ([docs](docs/recipes/agent-studio.md)): curator, colorist and critic agents work through `redlamp mcp` on briefs drawn from public-domain references. People approve the briefs and pick the winners in the Recipe Lab, and the critics are only trusted after they agree with human picks on held-out pairs. ### In progress - **Focus stacking:** lens corrections before alignment, halo handling, vendor focus-bracketing tags for detection, and baking a stack to DNG. - **Remove, Heal and Clone** (`Q`): click the photo to add a spot. **Remove** fills it from the photo around it, patch by patch, continuing edges that run into it (content-aware fill), and with Click picks set to Person or Object, a click removes the whole person or object, shaped by its mask. With Object, a box dragged around a thing or a stroke brushed over it removes it too, as the Drag menu says (Rectangle or Brush, the same choice as the Objects mask's), and a stroke over a part a pick left out, such as a cup's handle, adds it to that pick. **Find** outlines things named in words wherever they are in the photo (trash, litter, plastic bags, bottles, cans, cigarette butts, power lines, cables, signs, traffic cones, cars, people and birds, with OWLv2 from Settings › Models), and a click on one removes it the same way, or **Remove All** removes them all; Heal and Clone find their own source nearby; drag the spot or its source to move it, or its handle to resize it, and change Heal or Clone, Size, Feather and Opacity in the panel. Heal matches the source's texture to the light around the spot. Drag instead of clicking to brush a spot along a scratch, wire or twig. `H`, or **Show Spots** at the top of the panel, hides the spots, their outlines and pins, and shows them again, so a fill can be judged with nothing drawn over it; the selected spot stays selected, with its fills still to choose from. **Remove Dust** finds the soft, colourless specks sensor dust leaves on smooth areas (sky, walls, water) and heals them in one step; with several photos selected, it heals the specks found in the same place on the sensor in two or more of them (frames showing the same scene around a speck, as from a tripod, count as one), in all of them (one Undo puts the others back), and **Visualize Spots** shows the photo's edges in white so the rest stand out. Spots are saved with the edit, paste with Copy Settings, and `redlamp render --remove x,y,radius`, `--heal` or `--clone` (or `--remove-brush` and the others through several points) adds one from the command line, as `--remove-dust 50` heals the dust found and `--remove-found car` removes what's found by name. - **Tools not yet working:** the Red Eye tool shows what is coming and when. ### Measured performance Measured on an Apple M1 Ultra with a Release build. Every figure since 29 September, the benchmark harness's runs, and what's got faster or slower are at [redlamp.app/performance](https://redlamp.app/performance), from [`docs/performance/history.jsonl`](docs/performance/history.jsonl); `scripts/perf-record.sh` records a run. The card at the top of this README is drawn from the same history by `scripts/perf-card.py`, each figure from its latest quiet record, and CI fails when the card falls behind the history. Each release's download and installed size is recorded from its zip on GitHub (`scripts/perf-history.py release`). 0.3.4 is a 30.4 MB download and 67.5 MB installed; the AI models download only when a feature first needs them. 0.2.5 added Generative Remove and its MLX frameworks and grew to 115.6 MB installed; 0.2.6 ships stripped of debugging symbols, with LibRaw built hidden so unused code is dropped and the decode service sharing the app's frameworks (AUD-11), and is smaller than 0.2.4 was. 0.2.7 ships its 69 Base Look tables compressed, each read when a render first uses it (AUD-11), and is 17% smaller installed than 0.2.6. 0.3.0 adds the library and is 17.8 MB larger installed than 0.2.9, 10.3 MB of it the library's own framework and 6.1 MB the interface's; its size budget was raised to 64,000 KB, and ARC-18 looks for savings to bring the app back under 60,000 KB. 0.3.1 adds JPEG XL export's encoder (libjxl, about 2 MB) and is still 1.8 MB smaller installed than 0.3.0, its Base Look tables shipped as binary differences under LZMA and MLX's core exporting only its C API (ARC-18). 0.3.2 is 1.0 MB larger installed than 0.3.1, 0.6 MB of it the interface's framework and 0.2 MB the recipes'. 0.3.3 is 3.0 MB larger installed than 0.3.2, 1.4 MB of it the interface's framework and 0.5 MB the library's, and its size budget was raised to 66,000 KB. 0.3.4 is 2.1 MB larger installed than 0.3.3, 1.1 MB of it the interface's framework, 0.7 MB the library's and 0.2 MB the document's, and its size budget was raised to 68,000 KB. The release check fails a bundle with an Intel slice, debugging symbols or more than its size budget (`scripts/check-release-bundle.sh`). | Operation | Time | | --- | --- | | Open a 24–26 MP raw file (decode, GPU upload, demosaic, pyramid) | 70–250 ms | | Interactive render at Fit (every adjustment, fused) | 0.6–3 ms | | Interactive render at Fit with two gradient masks | ~1.3 ms | | Interactive render at 1:1 (full 26 MP frame) | ~13 ms | | Full-resolution export render (24–26 MP) | ~45 ms | | Full-resolution export render with noise reduction (24 MP, tiled) | ~100 ms | | Focus stack of 25 × 17 MP Canon CR3 frames (decode, align, depth map, fuse) | ~8 s | | Focus stack of 109 × 4 MP JPEG frames | ~15 s | | Reopen a merged focus stack from its cache | ~0.1 s | | Detail stage on a 1:1 region (about 10 MP of pyramid texels), GPU time: noise reduction, Texture and Clarity | ~5 ms, ~1 ms | | Detail stage for a 2560 × 1600 view at 1:1 of a 24 MP frame, GPU time: noise reduction alone (Luminance 50); default sharpening, first render; while dragging Radius; while dragging Amount, Detail or Masking (cached analysis); while dragging Luminance | ~3.6 ms, ~7.2 ms, ~5.5 ms, ~2.2 ms, ~4.3 ms | The detail stage holds about 1.3 GB of GPU memory at 1:1 on a 24 MP photo and 2.3 GB on a 60 MP one, with noise reduction and sharpening on (3.1 GB and 7.5 GB before the [memory audit](docs/research/research-tracker.md), AUD-03); large views render in tiles within its budget, and nothing is kept once rendering stops for half a second. Folders and the filmstrip on 50,000 photos in 500 folders (`scripts/make-folder-fixture.sh`, then `--folders-perf`), measured while the Mac was busy with other work (load average about 18): | Operation | Time | | --- | --- | | First photos in the filmstrip, Show Photos in Subfolders on | 14 ms | | All 50,000 photos listed (500 folders, in parallel, in order) | 209 ms | | The visible thumbnails, decoded from the raw files | 33 ms | | Background warming from the raw files | 705 a second | | Thumbnails from the disk cache | 6,210 a second | | Main thread while listing, decoding and warming (p99) | 0.15 ms | | Main thread while scrolling the filmstrip end to end (p99) | 1.4 ms | | Peak memory, 152 MB before opening | 317 MB (531 MB before the [memory budgets](docs/plans/2026-10-02-folders-design.md#memory-budgets)); 207 MB idle after a memory-pressure trim | Dragging a slider at 120 events a second (`scripts/perf-sweep.sh`), with every panel open: | Main thread during the drag | Iteration 2 | Off-main rendering | AppKit panels | | --- | --- | --- | --- | | Time busy | 100% | ~54% | ~34% | | Typical run-loop iteration (median) | — | 2.3 ms | 0.17 ms | | Slowest 5% of iterations | 157 ms | ~8 ms | ~5 ms | | Slowest 1% of iterations | — | ~13 ms | ~8 ms | With both side panels in AppKit, most of what remains is Core Animation committing the redrawn layers and the engine's frames arriving; SwiftUI is down to about 2% of the main thread. ### Known limitations - Highlights and Shadows are edge-aware for new edits (process version 7): each region moves by its brightness and keeps the texture inside it. Edits made before keep the per-pixel version, and they haven't yet been compared against Lightroom's own exports. - Redlamp's exposure for Fujifilm raws differs from the camera's by up to ±0.9 EV depending on the body; the profiler removes it when measuring looks, and the engine fix is tracked (TON-14). - Non-DNG raws use a single-illuminant Adobe-derived matrix (LibRaw's). DNGs interpolate their two calibrations by white balance, and since process 4 apply their embedded profile's HueSatMap, but the Temperature and Tint model still converts with one matrix. The profile's look (LookTable and tone curve) is offered as a Base Look under "In This Photo", Apple ProRAW's look comes with its gain table map, Apple's local tone mapping, so it renders the way the iPhone does. Importing `.dcp` files is deferred. - Landscape masks (mountains, water, vegetation, ground, architecture, snow) and people parts beyond the face (body skin, clothes, and hair without an iPhone matte) come from SAM 3, under Meta's SAM License; a model trained on data Redlamp has rights to, which would replace it, doesn't exist yet ([plan](docs/plans/2026-10-01-masking-plan.md#m8-trained-heads-msk-12-msk-13-only-if-m7-says-so)). - Objects (Segment Anything 2.1), Depth Range and Sky (Depth Anything V2 Small and 3) use open models trained partly on data Redlamp couldn't use itself, offered to everyone by the owner's decisions (tracker DEC-24, DEC-02). Vision's own tap-to-segment arrives with macOS 27. - AI mask edges are solved per pixel when the mask is made, at up to 4096 px on the long side, so on larger photos they're slightly soft at 100%. For new edits (process version 13), masks coarser than that (iPhone mattes, face parts, masks made before edges were solved per pixel) are refined again where the photo is drawn, at its resolution (a guided filter, freedom-to-operate pending as DEC-05); where the photo has no edge for such a mask's to follow, it keeps its own, which is soft at full size. - The app is not sandboxed yet (required later for the Mac App Store), but photos and focus-stack frames decode in a sandboxed service with no file access (`RedlampDecoder.xpc`, sent each file's bytes), never in the app, so a damaged file can't crash the editor while it decodes. These reads still parse files in the app itself: filmstrip thumbnails (a raw's embedded preview, through LibRaw, or ImageIO), the Portrait mattes and depth a photo carries, focus-stack detection, the metadata an export copies from its source, an imported HALD look, and the Camera Bench window (Help › Test Your Camera…). iPad and iPhone come in Phase 5. - Sidecars are read and written under file coordination, so iCloud Drive syncs them safely and conflicting copies merge (the newest edit wins, the others become snapshots, and the rating, flag and label each come from the newest copy that set them). A photo that is open doesn't reload when another Mac changes its edit, but its next save merges the two edits instead of writing over the other Mac's. - Albums added from Apple Photos, kept in Photos or copied into a folder, bring each photo's favourite as a pick, its dates and its original name. What Redlamp keeps of photos kept in Photos, their edits among it, is on this Mac only, so Redlamp on another Mac doesn't see it. Photos' ratings, captions and keywords need macOS 27 and a build made with the macOS 27 SDK; builds are made with the macOS 26.5 SDK for now, so they don't come across yet, even on macOS 27. Titles, people and pets, and memories stay in Photos, since Apple's Photos framework doesn't give them. - Generative Remove has been tested only on Macs with 16 GB of memory or more. Macs with less are offered it with a note that it hasn't been tested on them, where it may be slow or not work (RM-15). - Nikon's High Efficiency NEFs (HE and HE\*) open from the Z 9, Z 8, Z f, Z 6III, Z5 II and Z50 II, through Redlamp's fork of LibRaw (CAM-12, CAM-30); other bodies' HE files, the ZR's among them, are refused until one of their samples is verified. The Z5 II's and Z50 II's NEFs, HE or lossless, open without a colour matrix (CAM-21). **Fixed in iteration 2:** - Phase One IIQ files develop with the back's black levels subtracted and its calibration applied; they had a magenta cast. - Hasselblad FFF files (Phocus's format) open as raws. - White balance now works for linear DNGs such as iPhone ProRAW. - The Navigator outlines the zoomed viewport. - The loading placeholder now shows while a photo decodes. - Dragging a slider no longer stutters. Every change used to re-render every panel and wait on the canvas's drawable on the main thread. ## Film simulations Redlamp's film looks are **physical simulations**, built from the data in each manufacturer's own datasheet: characteristic curves, spectral sensitivities and dye spectra, digitised into [`research/film-data/`](research/film-data/). Most film presets are tuned by eye.
Portra 160 icon
Portra 160
Colour negative
Portra 400 icon
Portra 400
Colour negative
Portra 800 icon
Portra 800
Colour negative
Ektar 100 icon
Ektar 100
Colour negative
Gold 200 icon
Gold 200
Colour negative
UltraMax 400 icon
UltraMax 400
Colour negative
Superia 400 icon
Superia 400
Colour negative
Pro 400H icon
Pro 400H
Colour negative
CineStill 800T icon
CineStill 800T
Tungsten negative
CineStill 50D icon
CineStill 50D
Daylight negative
Vision3 500T icon
Vision3 500T
Cinema print
Vision3 250D icon
Vision3 250D
Cinema print
Vision3 50D icon
Vision3 50D
Cinema print
Eterna Vivid icon
Eterna Vivid
Cinema print
Provia 100F icon
Provia 100F
Slide
Velvia 50 icon
Velvia 50
Slide
Velvia 100 icon
Velvia 100
Slide
Ektachrome icon
Ektachrome
Slide
Kodachrome 64 icon
Kodachrome 64
Slide
Tri-X 400 icon
Tri-X 400
Black and white
T-Max 100 icon
T-Max 100
Black and white
T-Max 400 icon
T-Max 400
Black and white
HP5 Plus icon
HP5 Plus
Black and white
Delta 100 icon
Delta 100
Black and white
Delta 3200 icon
Delta 3200
Black and white
FP4 Plus icon
FP4 Plus
Black and white
Pan F Plus icon
Pan F Plus
Black and white
Darkroom Print icon
Darkroom Print
Grade 2 print
Soft Print icon
Soft Print
Grade 1 print
Hard Print icon
Hard Print
Grade 4 print
Portra 400 · +2 icon
Portra 400 · +2
Overexposed
Portra 800 · 1600 icon
Portra 800 · 1600
Pushed
Tri-X · 1600 icon
Tri-X · 1600
Pushed
2383 Bleach Bypass icon
2383 Bleach Bypass
Cinema print
Velvia 50 · Cross icon
Velvia 50 · Cross
Cross-processed
Provia 100F · Cross icon
Provia 100F · Cross
Cross-processed
### How the film engine works The datasheets drive an offline model that bakes each film into a Base Look table and its effects settings. Only those ship, and the GPU applies them while you edit: ```mermaid flowchart LR pdf["Makers' datasheets
Kodak · Fujifilm · Ilford"] --> data["research/film-data
curves · sensitivities · dyes · granularity"] subgraph model["Film model (offline)"] direction LR spectrum["Scene colour
to spectrum"] --> layers["Layer exposures
spectral sensitivities"] layers --> density["Dye density
curves · interlayer · masking"] density --> view["Print, scan
or light box"] view --> eye["Colour as seen
CIE observer"] end data --> model eye --> table["Base Look
scene-referred 33³ table"] data -- granularity --> effects["Grain · halation · bloom"] table --> recipe["Bundled film recipe"] effects --> recipe recipe --> engine["Develop kernel (Metal)
halation and bloom → film table → grain"] ``` The [film model](docs/plans/2026-09-30-film-looks-design.md) follows the scene's light through the film: 1. Each colour becomes a spectrum. 2. The film's three layers record that spectrum through their own sensitivities. 3. The characteristic curves turn exposure into dye, with interlayer effects and colour masking. 4. A negative is printed on its print stock or scanned the way a lab scanner reads it. A slide is lit on a light box. 5. The result is seen through the colour-matching functions of human vision. Each look ships as a scene-referred Base Look. It takes the place of Redlamp's tone curve, so the film's own toe, shoulder and colour crossovers reach the photo. Each look also comes with the film's **grain, halation and bloom** in the Effects panel. Grain follows each datasheet's published granularity, and halation is strongest on CineStill, which has no anti-halation layer. ![The Film Looks window: the open photo in every film, with Portra 400 applied](docs/images/film-catalog.png) **Using them:** - **Window ▸ Film Looks** (`⇧⌘L`) shows the open photo in every film. Hover over a card to preview the look in the editor; click to apply it with its grain, halation and bloom, as the Base Looks panel does. Hold `⌥` over a card to see the photo before the look. Star a look to keep it under **Favourites**, and in the Base Looks panel's Favorites. The applied look's card has Grain, Halation and Bloom sliders, and the header the Base Look's Amount, as in Basic. Tabs filter by colour negative, cinema, slide, and black and white. - **Base Looks ▸ Film Stocks** in the sidebar lists every film once, with its icon, by kind, each variant beside its stock. Hover to preview, click to apply the look with its grain, halation and bloom, keeping the vignette, light leak, dust and frame as they were; right-click a film and choose **Apply Without Grain, Halation and Bloom** for its colour alone, as a Lightroom profile does, previewed while the item is highlighted. Right-click the Film Stocks folder to open the Film Looks window. - **Basic ▸ Base Look** shows the film first in its menu while it's the photo's look, and otherwise leaves the film stocks to the Base Looks panel (DEC-74). - **Effects ▸ Grain** (with a new **Color** slider for grain in each dye layer), **Halation** and **Bloom** work on any photo. Masks have their own **Halation** and **Bloom** sliders, to add glow to a sign or hold it back from a face. ![CineStill 800T applied in the editor, with its grain, halation and bloom in the Effects panel](docs/images/film-editor.png) ### The catalogue | | Look | Film | Rendered as | Grain / halation | | --- | --- | --- | --- | --- | | | [Portra 160](#portra-160) | Kodak · Colour negative · ISO 160 | Scanned, Frontier-like | 15 / 7 | | | [Portra 400](#portra-400) | Kodak · Colour negative · ISO 400 | Scanned, Frontier-like | 20 / 8 | | | [Portra 800](#portra-800) | Kodak · Colour negative · ISO 800 | Scanned, Frontier-like | 27 / 9 | | | [Portra 800 · Pushed to 1600](#portra-800-1600) | Kodak · Colour negative · ISO 800 pushed to 1600 | Scanned, Frontier-like | 32 / 9 | | | [Ektar 100](#ektar-100) | Kodak · Colour negative · ISO 100 | Scanned, Frontier-like | 8 / 6 | | | [Gold 200](#gold-200) | Kodak · Colour negative · ISO 200 | Scanned, Frontier-like | 23 / 9 | | | [UltraMax 400](#ultramax-400) | Kodak · Colour negative · ISO 400 | Scanned, Frontier-like | 25 / 9 | | | [Superia 400](#superia-400) | Fujifilm · Colour negative · ISO 400 | Scanned, Frontier-like | 24 / 8 | | | [Pro 400H](#pro-400h) | Fujifilm · Colour negative · ISO 400 (discontinued) | Scanned, Frontier-like | 24 / 8 | | | [CineStill 800T](#cinestill-800t) | CineStill · Tungsten colour negative · ISO 800 | Scanned, Noritsu-like | 26 / 70, bloom 8 | | | [CineStill 50D](#cinestill-50d) | CineStill · Daylight colour negative · ISO 50 | Scanned, Noritsu-like | 12 / 60, bloom 6 | | | [Vision3 500T · 2383](#vision3-500t-2383) | Kodak · Cinema negative on print film · ISO 500 | Printed on 2383 and projected | 24 / 14, bloom 6 | | | [Vision3 250D · 2383](#vision3-250d-2383) | Kodak · Cinema negative on print film · ISO 250 | Printed on 2383 and projected | 20 / 12, bloom 6 | | | [Vision3 50D · 2383](#vision3-50d-2383) | Kodak · Cinema negative on print film · ISO 50 | Printed on 2383 and projected | 12 / 10, bloom 5 | | | [Eterna Vivid 250D · 2383](#eterna-vivid-250d-2383) | Fujifilm · Cinema negative on print film · ISO 250 (discontinued) | Printed on 2383 and projected | 21 / 12, bloom 6 | | | [Provia 100F](#provia-100f) | Fujifilm · Slide film · ISO 100 | Slide, viewed on a light box | 8 / 4 | | | [Velvia 50](#velvia-50) | Fujifilm · Slide film · ISO 50 | Slide, viewed on a light box | 9 / 4 | | | [Velvia 100](#velvia-100) | Fujifilm · Slide film · ISO 100 | Slide, viewed on a light box | 8 / 4 | | | [Ektachrome E100](#ektachrome-e100) | Kodak · Slide film · ISO 100 | Slide, viewed on a light box | 8 / 4 | | | [Kodachrome 64](#kodachrome-64) | Kodak · Slide film · ISO 64 (discontinued) | Slide, viewed on a light box | 10 / 4 | | | [Tri-X 400](#tri-x-400) | Kodak · Black and white negative · ISO 400 | Scanned | 37 / 5 | | | [T-Max 100](#t-max-100) | Kodak · Black and white negative · ISO 100 | Scanned | 18 / 4 | | | [T-Max 400](#t-max-400) | Kodak · Black and white negative · ISO 400 | Scanned | 22 / 5 | | | [HP5 Plus](#hp5-plus) | Ilford · Black and white negative · ISO 400 | Scanned | 40 / 5 | | | [Delta 100](#delta-100) | Ilford · Black and white negative · ISO 100 | Scanned | 16 / 4 | | | [Delta 3200](#delta-3200) | Ilford · Black and white negative · ISO 3200 | Scanned | 52 / 6 | | | [FP4 Plus](#fp4-plus) | Ilford · Black and white negative · ISO 125 | Scanned | 24 / 5 | | | [Pan F Plus](#pan-f-plus) | Ilford · Black and white negative · ISO 50 | Scanned | 12 / 4 | | | [Tri-X · Darkroom Print](#tri-x-multigrade) | Kodak · Ilford · Black and white print · grade 2 | Printed on paper | 34 / 5 | | | [Portra 400 · +2](#portra-400-overexposed) | Kodak · Colour negative · ISO 400 rated 100 | Scanned, Frontier-like | 16 / 8 | | | [Tri-X 400 · Pushed to 1600](#tri-x-1600) | Kodak · Black and white negative · ISO 400 pushed to 1600 | Scanned | 46 / 6 | | | [Tri-X · Soft Print](#tri-x-multigrade-soft) | Kodak · Ilford · Black and white print · grade 1 | Printed on paper | 34 / 5 | | | [Tri-X · Hard Print](#tri-x-multigrade-hard) | Kodak · Ilford · Black and white print · grade 4 | Printed on paper | 34 / 5 | | | [Vision3 500T · 2383 Bleach Bypass](#vision3-2383-bleach-bypass) | Kodak · Cinema negative on print film, bleach bypass · ISO 500 | Printed on 2383 and projected | 26 / 12, bloom 6 | | | [Velvia 50 · Cross-Processed](#velvia-50-cross) | Fujifilm · Slide film in C-41 · ISO 50 | Developed in C-41, scanned | 12 / 5 | | | [Provia 100F · Cross-Processed](#provia-100f-cross) | Fujifilm · Slide film in C-41 · ISO 100 | Developed in C-41, scanned | 11 / 5 | Every look on the same photo: ![Every film look on one photo](docs/images/film/overview.jpg) ### Examples Each example shows three CC0 photos from the [look-development set](docs/recipes/look-development.md#the-look-development-set): a landscape, flowers and a night street. The top row is Redlamp's default rendering, the bottom row the film look with its grain, halation and bloom. #### Portra 400 Warm and gentle. Kind to skin, with soft greens and a little extra warmth in the highlights, as a Frontier lab scan renders it. ![Portra 400: the original above, the look below](docs/images/film/look-portra-400.jpg) #### Portra 160 Portra's slower sister: finer grain and an even gentler rendering, for portraits in good light. ![Portra 160: the original above, the look below](docs/images/film/look-portra-160.jpg) #### Portra 800 Fast Portra: warmer and richer, with more grain and a little more contrast. ![Portra 800: the original above, the look below](docs/images/film/look-portra-800.jpg) #### Portra 800 · Pushed to 1600 Portra 800 rated at 1600 and pushed a stop, from Kodak's own push curves: denser shadows, more contrast and grain. ![Portra 800 · Pushed to 1600: the original above, the look below](docs/images/film/look-portra-800-1600.jpg) #### Ektar 100 Kodak's finest-grained colour negative: richer reds and deeper colour than Portra. ![Ektar 100: the original above, the look below](docs/images/film/look-ektar-100.jpg) #### Gold 200 Warm consumer film. Golden yellows, slightly greener foliage and more grain. ![Gold 200: the original above, the look below](docs/images/film/look-gold-200.jpg) #### UltraMax 400 Kodak's punchy everyday film: warm, saturated and a little grainy. ![UltraMax 400: the original above, the look below](docs/images/film/look-ultramax-400.jpg) #### Superia 400 Cooler than the Kodak stocks, with Fujifilm's greens. ![Superia 400: the original above, the look below](docs/images/film/look-superia-400.jpg) #### Pro 400H Fujifilm's discontinued wedding film, with its fourth colour layer: soft contrast, pastel skin and minty greens. ![Pro 400H: the original above, the look below](docs/images/film/look-pro-400h.jpg) #### CineStill 800T Vision3 500T without its anti-halation backing. Bright lights glow red-orange, the look of night streets and neon. ![CineStill 800T: the original above, the look below](docs/images/film/look-cinestill-800t.jpg) #### CineStill 50D Vision3 50D without its anti-halation backing: very fine grain, daylight colour and glowing highlights. ![CineStill 50D: the original above, the look below](docs/images/film/look-cinestill-50d.jpg) #### Vision3 500T · 2383 The motion-picture look: a cinema negative printed on release print film. Softer and denser, with cool shadows and warm highlights. ![Vision3 500T · 2383: the original above, the look below](docs/images/film/look-vision3-500t-2383.jpg) #### Vision3 250D · 2383 Kodak's daylight cinema negative printed on 2383: the bright exterior look of feature films. ![Vision3 250D · 2383: the original above, the look below](docs/images/film/look-vision3-250d-2383.jpg) #### Vision3 50D · 2383 The finest-grained cinema negative on 2383: clean, saturated daylight. ![Vision3 50D · 2383: the original above, the look below](docs/images/film/look-vision3-50d-2383.jpg) #### Eterna Vivid 250D · 2383 Fujifilm's discontinued vivid daylight cinema negative, printed on 2383: more saturated than Vision3. ![Eterna Vivid 250D · 2383: the original above, the look below](docs/images/film/look-eterna-vivid-250d-2383.jpg) #### Provia 100F Clean, natural slide film. Contrasty, with deep skies and dense shadows, exposed for the highlights. ![Provia 100F: the original above, the look below](docs/images/film/look-provia-100f.jpg) #### Velvia 50 The landscape slide: saturated greens, yellows and blues, and more contrast still. ![Velvia 50: the original above, the look below](docs/images/film/look-velvia-50.jpg) #### Velvia 100 Velvia's faster sibling: just as saturated, a touch gentler in the shadows. ![Velvia 100: the original above, the look below](docs/images/film/look-velvia-100.jpg) #### Ektachrome E100 Kodak's modern slide film: clean, neutral to cool, with fine grain. ![Ektachrome E100: the original above, the look below](docs/images/film/look-ektachrome-e100.jpg) #### Kodachrome 64 The legendary K-14 slide film, from Kodak's archived datasheet: warm reds, deep blues and dense shadows. ![Kodachrome 64: the original above, the look below](docs/images/film/look-kodachrome-64.jpg) #### Tri-X 400 Classic black and white. Bright and crisp, with pronounced, sharp grain. ![Tri-X 400: the original above, the look below](docs/images/film/look-tri-x-400.jpg) #### T-Max 100 Kodak's finest-grained black and white: smooth, sharp and long in tone. ![T-Max 100: the original above, the look below](docs/images/film/look-t-max-100.jpg) #### T-Max 400 Modern fast black and white: tighter grain than Tri-X and a longer tonal range. ![T-Max 400: the original above, the look below](docs/images/film/look-t-max-400.jpg) #### HP5 Plus Softer and grainier than Tri-X, with a gentler shoulder. ![HP5 Plus: the original above, the look below](docs/images/film/look-hp5-plus.jpg) #### Delta 100 Ilford's fine-grained modern black and white. ![Delta 100: the original above, the look below](docs/images/film/look-delta-100.jpg) #### Delta 3200 Ilford's fastest film: big, gritty grain and hard contrast for low light. ![Delta 3200: the original above, the look below](docs/images/film/look-delta-3200.jpg) #### FP4 Plus Classic medium-speed black and white with a gentle shoulder. ![FP4 Plus: the original above, the look below](docs/images/film/look-fp4-plus.jpg) #### Pan F Plus Slow, ultra-fine black and white with rich contrast. ![Pan F Plus: the original above, the look below](docs/images/film/look-pan-f-plus.jpg) #### Tri-X · Darkroom Print A darkroom print: deeper blacks and the paper's own contrast. ![Tri-X · Darkroom Print: the original above, the look below](docs/images/film/look-tri-x-multigrade.jpg) ### Variants and processes The same datasheets also describe how a film behaves when it's exposed or processed differently, and the model follows them: - **Exposure.** A lab calibrates its scanner at box speed and prints each frame up or down until mid-grey is right. Overexposed highlights crowd onto the film's shoulder, and underexposed shadows block up at the film base. - **Push processing** uses the datasheet's own curves for longer development. - **Paper grades** use Ilford's published curve for each Multigrade filter. - **Bleach bypass** leaves the developed silver in with the dyes, as neutral density where dye formed. - **Cross-processing** develops a slide emulsion as a negative: its curves are mirrored and there's no orange mask. Slide datasheets don't publish C-41 curves, so this one is an approximation. #### Portra 400 · +2 The popular overexposed Portra: two stops of extra exposure crowd the highlights onto the film's shoulder, for an airy, pastel, soft look. ![Portra 400 · +2: the original above, the look below](docs/images/film/look-portra-400-overexposed.jpg) #### Tri-X 400 · Pushed to 1600 Push processing: two stops underexposed and developed longer, using the datasheet's own longest D-76 curve. The shadows block up and grain and contrast rise. ![Tri-X 400 · Pushed to 1600: the original above, the look below](docs/images/film/look-tri-x-1600.jpg) #### Tri-X · Soft Print A gentle, open darkroom print on a soft grade, using Ilford's published grade 1 curve. ![Tri-X · Soft Print: the original above, the look below](docs/images/film/look-tri-x-multigrade-soft.jpg) #### Tri-X · Hard Print A hard grade: deep blacks and bright whites, using Ilford's published grade 4 curve. ![Tri-X · Hard Print: the original above, the look below](docs/images/film/look-tri-x-multigrade-hard.jpg) #### Vision3 500T · 2383 Bleach Bypass The bleach-bypass print: the silver is left in with the dyes, so the image is desaturated, dense and hard, the look of many war films. ![Vision3 500T · 2383 Bleach Bypass: the original above, the look below](docs/images/film/look-vision3-2383-bleach-bypass.jpg) #### Velvia 50 · Cross-Processed Slide film developed as a negative: punchy, with the colour shifts that a slide emulsion with no orange mask gives. ![Velvia 50 · Cross-Processed: the original above, the look below](docs/images/film/look-velvia-50-cross.jpg) #### Provia 100F · Cross-Processed Provia cross-processed: contrasty, with cool green-cyan shadows. ![Provia 100F · Cross-Processed: the original above, the look below](docs/images/film/look-provia-100f-cross.jpg) ### Mood looks One-tap looks in the spirit of Prequel's filters. Each starts from a film look, with its grain, halation and bloom, and adds the Effects **Light Leak** (Amount, Warmth and Variation) and **Dust & Scratches**. They're in the sidebar under **Recipes ▸ Mood**, and the effects work on any photo. A mood never sets or takes away a border: borders are their own recipes, under [Borders](#borders). | Mood | Built on | Adds | | --- | --- | --- | | Golden Leak | Portra 400 · +2 | a warm light leak and soft bloom | | Lost Roll | Gold 200 | leaks, dust and scratches | | Summer '98 | UltraMax 400 | a warm leak | | Night Glow | CineStill 800T | strong halation, bloom and a little dust | | Blue Hour | Pro 400H | a cool leak and a soft mist | | Mist | Portra 160 | a diffusion filter's glow and gentler contrast | | Home Movie | Vision3 50D · 2383 | projector scratches, dust and a dark edge | | Slide Show | Kodachrome 64 | a few specks of dust, as on projected slides | | Contact Sheet | Tri-X · Hard Print | darkroom dust | | Neon Rain | Provia 100F · Cross-Processed | halation and a cool leak | ![The ten mood looks on three photos, beside the original](docs/images/film/moods.jpg) Lost Roll, Summer '98, Home Movie, Slide Show and Contact Sheet used to carry a frame drawn over the photo's edges; their new versions leave it to [Borders](#borders), and edits made with the old versions keep their frames. Ten more are **tuned on the photographs shot on each film**. `redlamp recipe film --fit-moods` fits the style fingerprint of a film's 20 reference photographs with the recipe studio's fitter, adjusting tone, saturation, grading and grain on top of the film's own look. The fitted values are pinned in the source. Shared film scans are bright and open, and the moods carry that. The fit leaves out per-colour hue and saturation, which follow the photographs' subjects more than the film. | Mood | Built on | Fitted to | | --- | --- | --- | | Portra Days | Portra 400 | bright, airy scans | | Ektar Colour | Ektar 100 | warm, vivid colour with open shadows | | Gold Summer | Gold 200 | sunny warmth, soft contrast, more grain | | Superia Snapshots | Superia 400 | bright, cool-leaning snapshots | | Wedding Day | Pro 400H | pastel, soft wedding scans | | CineStill Nights | CineStill 800T | deep shadows and a cool split tone | | Velvia Landscapes | Velvia 50 | open shadows and rich colour | | Kodachrome Memories | Kodachrome 64 | bright slides with cool shadows | | Tri-X Street | Tri-X 400 | open, bright street prints | | HP5 Documentary | HP5 Plus | bright midtones with deep blacks | ![The ten fitted moods on three photos, beside the original](docs/images/film/moods-fitted.jpg) ### Borders A border goes **around** the photo: the canvas grows to hold it, so nothing of the photo is hidden, as borders made with Lightroom Classic's Print to JPEG or export plug-ins are. Lightroom has no border in Develop; here it's the **Border** panel, the last in Develop, and the **Recipes ▸ Borders** folder, apart from looks and moods, so a mood never sets or takes away a border and a border recipe never touches the look. - **Plain:** Even (the same margin all round), or a shape, 1:1, 4:5, 3:4, 2:3, 9:16, 5:7, 11:14, A paper or custom, turned with the photo or kept Portrait or Landscape, so a carousel of portrait and landscape photos shares one 4:5 canvas. **Size** is the margin on the narrowest sides, in percent of the photo's long side, so a border looks the same at 1080 pixels and at full size; **Vertical** raises the photo for the heavier bottom margin a framer's mat has. **Color** has White, Paper, Grey and Black, and a colour well whose magnifier picks a colour from the photo; a **Keyline** adds a line around the photo, with its width, gap and colour. - **Film and instant frames,** at their formats' published proportions, scaled to the photo: 35 mm film with its rebate, sprocket holes and dot-matrix edge print (the frame number, following the file's number so a set reads as one roll, and the film look's name when the Base Look is a film stock), medium format, instant square, mini and wide cards, card and plastic slide mounts, and a filed-out negative carrier's rough black edge. **Crop to Format** crops the photo to the frame's own shape. - **While editing,** the histogram and clipping warnings count the photo alone, so a white border never reads as clipped; masks, spots and samplers ignore the border; the crop tool and the colour-assessment view (`⇧L`) show the photo without it; the panel's switch takes it away to judge tone, since a white mat makes a photo look darker. - **Recipes ▸ Borders:** White 4:5, Black 4:5, White 3:4, White Square, Black Square, Story 9:16, Thin White, Thin Black, Gallery Mat, Gallery Mat with Keyline, Print 8×10, and the film and instant frames, each previewed on the photo as the pointer passes. Create Recipe leaves Border unticked unless asked, and Copy Settings leaves it unticked too, as it does the crop. - **Export:** a **Border** menu, As Edited, None (for a lab or a client), or a border recipe on every photo exported, saved with presets; sizes include the border, so Long Edge 1350 with White 4:5 writes 1080 × 1350. `redlamp export --border` does the same. TON-25's frames, drawn over the photo's edges, keep rendering in the edits that have them; the Effects panel shows them only there, with **Move to Border**. ![The Borders recipes on one photo](docs/images/borders.jpg) ### Checked against photographs shot on the films `research/film-references/` lists 477 photographs from Wikimedia Commons whose pages name the film. There are 8 to 20 per stock, licensed CC0, CC BY or CC BY-SA, and they're used as references only, never shipped or committed. `redlamp recipe film --validate` renders each look on the look-development set, and `research/film-references/analyse.py` compares them with the photographs in OKLab. It compares contrast and saturation, and the colour of foliage, sky, skin and near-neutral shadows and highlights. The two sets show different scenes, so the useful tests are relative ones: - **Ranking:** do the looks order the stocks as the photographs do? - **Same-scene comparison:** what does each look change against Redlamp's own rendering of the same photos? The check found one clear error, now fixed. The slides were *less* saturated than Redlamp's default, though in the photographs slide films are the most saturated of all. Slides get much of their saturation from strong interimage effects between their layers, which the model had set as mildly as for negatives. With stronger effects calibrated to the photographs' order (version 2 of the slide looks), saturation against the default rendering is: | Look | Saturation | | --- | --- | | Velvia 50 | +31% | | Velvia 100 | +20% | | Provia 100F | +10% | | Ektachrome E100 | +10% | | Kodachrome 64 | +7% | The colour negatives stay within a few percent of the default in saturation and are slightly softer, as lab scans are. The reference photographs differ too much in subject for finer conclusions: Pro 400H's are mostly weddings, CineStill's night streets, and Velvia's landscapes. ### How faithful are they? - **The colour comes from the datasheets.** It follows each stock's own curves, sensitivities and dyes, and the stocks keep their published order of contrast and grain. - **A lab's scan or print timing shapes the rest.** Negatives are scanned by a modelled lab scanner calibrated on a grey scale. Its Frontier-like and Noritsu-like profiles are characterised from how labs describe the two scanners, not measured from them. The 2383 print is timed partway back to neutral, as a colourist would. - **Some data is fitted or uncertain.** Nine colour negatives publish no individual dye curves: Portra 160, 400 and 800, Ektar, Gold, UltraMax, Superia, Pro 400H and Eterna Vivid. Their dyes are Vision3's shapes, fitted until together they match the stock's own published mid-scale neutral. Kodak 2383's sensitivity was re-traced, and both 2383 looks are on version 2. Kodachrome 64 and Eterna Vivid come from Internet Archive copies of Kodak's and Fujifilm's own pages. Ilford publishes only relative scales, which the model's grey balance makes up for. - **CineStill is modelled with no anti-halation layer,** as CineStill sells it. Kodak's current Vision3 datasheets describe an anti-halation undercoat in place of the old rem-jet backing, and no document settles which current CineStill stock has. - **Grain follows film** (process 2, TON-19). It's sized to the frame, so it looks the same on any camera's resolution, and it's strongest in the low midtones and shadows. The fitted preview shows the grain the export will have. Kodak, Portra, Ektar, Gold, Vision3, Tri-X, Fujifilm, Superia, Provia, Velvia, Ilford, HP5, Multigrade and CineStill are trademarks of their owners. Redlamp isn't affiliated with them: its looks are built from the published technical data. **Rebuilding them:** `redlamp recipe film --all --install --readme` builds every look from the datasheets, installs the tables the app bundles, and regenerates the icons and images on this page. Bundled looks are versioned and never change once published; a test fails if the datasheets or the model would build a different look under the same version. ## Screenshots **The command palette (⌘K).** One search for every action, with its shortcut beside it, every Develop slider with its value, and pickers for white balance, treatment, Base Looks, recipes, Before / After, snapshots and history. ![The command palette over a Sony α7R V raw file, searching for “white”: the White Balance and Treatment pickers, sliders with their values, and actions with their shortcuts](docs/images/hero-palette.png) **Adjusting from the keyboard.** ↵ on a slider shrinks the palette to a slider bar over the photo: ← → step it (⇧ ×10, ⌥ finer), ↑ ↓ move to the next slider, and you can type a value or `x+0.3`. A run of presses is one history step. ![The slider bar for Exposure at +0.85 over the photo, with Tint and Contrast beside it and its keys in a hint bar](docs/images/hero-slider.png) **A Subject mask in the red overlay.** Made on the device by Apple Vision, with nothing to download, and given its own Exposure and Clarity. The Masks panel lists the mask's components, which combine by add, subtract and intersect. ![The dancer selected by a Subject mask, shown in the red mask overlay, with the mask's Exposure and Clarity raised in the Masks panel on the right](docs/images/hero-masks.png) **Masking on a Sony A7 III ARW.** A linear gradient darkens and cools the sky, and a feathered radial gradient warms and lifts the trees. The red overlay shows the selected mask's coverage. ![Masking](docs/images/masking.png) **Color grading on a Canon EOS R6 CR3.** Split-toned shadows and highlights with the 3-way wheels. ![Color grading](docs/images/color-grading.png) **A camera recipe on a Fujifilm X-T3 RAF.** Chrome Street, built from a Fujifilm-style recipe card, on the measured Chrome Base Look. The recipe's Amount is in the Recipes panel, and its tone, Color Chrome and grain settings land in the Basic and Effects panels like any other edit. ![A camera recipe](docs/images/recipes.png) **Black & white on a Sony A7 III ARW.** The Selenium recipe plus vignette and grain, with every step in History. ![Black and white](docs/images/black-and-white.png) **Detail at 1:1 on a Canon EOS R6 CR3.** Noise reduction scaled to the photo's measured noise, and noise-aware sharpening that measures detail on a denoised copy, so grain isn't sharpened. ![Detail at 1:1](docs/images/detail.png) **Before and after, side by side, on a Nikon Z 6 NEF.** Exposure, Highlights, Shadows, Dehaze, Clarity and Vibrance; the original renders once and is cached. ![Before and after](docs/images/before-after.png) **Fujifilm X-T3 X-Trans RAF at 1:1.** The full-resolution frame renders in about 13 ms, and the Color Mixer is shown in HSL mode. ![X-Trans at 100%](docs/images/zoom-xtrans.png) **iPhone 12 Pro ProRAW (linear DNG).** Portrait orientation, with highlight recovery and blues tuned in the Color Mixer. ![ProRAW](docs/images/proraw.png) ### The Recipe Lab The Lab lives in the [component harness](#component-harness). It renders every recipe, Base Look and imported LUT on a 40-image CC0 look-development set. **Gallery and split compare.** Thumbnails of every item on the chosen photo, filtered by kind, group, tag and lint result. On the right, the selected recipe (Chrome Street) against the original, with a draggable divider. ![The Recipe Lab gallery and split compare](docs/images/lab-gallery.png) **One recipe across the set.** Gritty Street on landscapes, animals, night streets, foliage and interiors at once, to catch a look that only works on one kind of photo. ![A recipe across the look-development set](docs/images/lab-across-set.png) **A against B.** Two camera recipes, Chrome Street and Bright Slide, on the same photo. ![Two recipes side by side](docs/images/lab-side-by-side.png) **Inspect.** Every included setting with its key, the camera card the recipe was built from, and the Base Look's table statistics and lint. ![Inspecting a recipe](docs/images/lab-inspect.png) **Agent studio runs.** A brief with the public-domain references it was drawn from, and the candidates developed against it with their lineage, lint and distance to the references. Each candidate opens in Compare at full size; pairwise picks and final picks are recorded for the critics' evals. ![A studio run in the Recipe Lab](docs/images/lab-runs.png) The hero image at the top and the first three screenshots are the author's own photos, captured in the default Neutral theme by `scripts/capture-hero.sh`. The other sample images are CC0 files from [raw.pixls.us](https://raw.pixls.us); the brief's references are public-domain and CC0 photos from Wikimedia Commons. Those screenshots are generated by `mise run screenshots`. ## Roadmap The Mac comes first: Phases 1 to 4 build a high-quality editor and engine on macOS, and iPad and iPhone follow in Phase 5, once the main features are complete. The engine stays platform-neutral throughout, so the port is a new shell rather than a rewrite. Where each Lightroom feature stands, done, in progress, planned or left out, is in [Redlamp and Lightroom compared](docs/lightroom-comparison.md), also at [redlamp.app/compare](https://redlamp.app/compare); the [Lightroom feature inventory](docs/lightroom-feature-inventory.md) is the detailed reference. Each item names the [tracker](docs/research/research-tracker.md) rows behind it in a comment, and `scripts/roadmap-sync.py` keeps the boxes in step with them. ### Phase 0: Foundations *(largely done)* - [x] mise and Tuist workspace, module graph with enforced boundaries, and an engine purity gate - [x] LibRaw vendored as a pinned, static XCFramework (macOS, iOS, and Simulator; arm64 only) - [x] Engine API contract, headless CLI, and a unit and engine smoke-test suite - [x] Lightroom feature inventory - [x] GitHub Actions CI: purity gate, SwiftFormat lint, build, and tests, with cached LibRaw and fixtures - [x] A benchmark harness and a recorded performance history, drawn at [redlamp.app/performance](https://redlamp.app/performance) - [ ] Performance lab: a CI runner on Apple Silicon with regression gates that block merges (iPhone and iPad tiers come with Phase 5) - [x] An end-to-end regression suite that works the app through every feature by its keys, menus, clicks and drags, checks for crashes, hangs and slowdowns, and gates every release - [x] Golden-image color regression tests (ΔE2000) for camera files, and a golden render for every bundled recipe version - [ ] Written clean-room policy and a license-audit gate in CI ### Phase 1: First light *(done)* - [x] RAW pipeline core, fused develop kernel, cached pyramid, and latest-wins rendering - [x] Develop workspace on macOS, Basic panel, histogram, before/after, sidecars, undo, and export - [x] Layer and mask engine, with linear and radial gradient masks, local adjustments, and the Masking panel - [x] Sandboxed XPC decode helper - [x] Render scheduler with priority lanes, tile cancellation, and thermal awareness - [x] Coordinated sidecar I/O for iCloud Drive ### Phase 2: Develop parity *(in progress)* - [x] Texture, Clarity and Dehaze, globally and inside masks, and Moiré and Defringe inside masks - [x] Copy Settings with Lightroom's checklist, Sync and Auto Sync across a filmstrip selection - [x] Detail panel: noise reduction scaled to each photo's measured noise, and noise-aware sharpening, with Lightroom's controls - [x] Menon Bayer demosaic with a dual pass for flat noisy areas, hot-pixel repair and highlight reconstruction that keeps a clipped sky's colour - [x] **Recipes:** one format for presets, profiles and LUTs, Base Look tables, camera recipe cards, `.cube`, `.3dl` and HaldCLUT import (with LUTs for S-Log3, LogC3, V-Log and Apple Log footage), 39 bundled recipes, and the Recipe Lab - [x] Before/After layouts, themes and a Settings window - [x] **Export dialog:** JPEG, HEIC, AVIF, PNG and TIFF, a file size limit, 8, 10 or 16 bits, sRGB or Display P3, resizing, metadata, presets and Export with Previous, developed at full resolution and downscaled last - [x] **Command palette** (⌘K): every action, Develop slider and picker from the keyboard, and a slider bar that adjusts by key - [x] **Folders,** as in Lightroom Classic: remembered folders as a tree with counts, and a filmstrip that follows the disk and stays fast with any number of photos - [x] Versions of a photo, as Lightroom's virtual copies, kept in its one sidecar - [x] Edge-aware Highlights and Shadows, and edge-refined Dehaze - [x] Red, green and blue curves in the Tone Curve, as Lightroom's point curve has - [x] **Film effects for recipes:** halation (the red glow around bright lights), bloom and diffusion, film grain that varies with density and scales with output size, and light leaks, dust and scratches, and frames, with Mood recipes built on them - [x] **Film simulations:** 36 looks from 30 stocks, built physically from the manufacturers' datasheets, including pushed, overexposed, bleach-bypass and cross-processed variants, with a Film Looks window and each film's icon in the Base Looks panel - [x] DNG camera profiles: dual-illuminant colour, the embedded HueSatMap, and the profile's own look offered as a Base Look - [ ] Your own Adobe camera profiles in the Base Look menu: each camera's Adobe Standard and Camera Matching profiles, and Adobe Color and Adobe's other looks with their Amount, where Lightroom Classic or Camera Raw installs them or from files you choose, used on your Mac only; where a profile isn't on the Mac, Redlamp's look of the same name stands in - [x] Calibration panel: Shadows Tint and the red, green and blue primaries' Hue and Saturation, and the Process version, which moves an edit to a newer rendering only when you ask - [x] Remove Chromatic Aberration, from the lens profile or measured from the photo's own edges, and Lightroom's Defringe (Purple and Green Amount and Hue) - [x] Lens corrections the raw file carries (DNG opcodes, Sony's and Fujifilm's), and manual Distortion and Vignetting, in the same geometry map - [x] Adobe LCP lens profiles you put in Redlamp's Lens Profiles folder, named in the Lens Corrections panel - [x] Lens profiles as Lightroom uses them: those Lightroom Classic and Camera Raw install, read where they are, profiles made on another body whose sensor covers the photo's, and Lightroom's Setup, Make, Model and Profile menus to choose one by hand - [x] **Crop and straighten** (aspect presets and lock, composition overlays, Angle and the Straighten tool, Constrain to Image), rotate and flip, and the manual Transform sliders, all one geometry map that masks follow - [x] Crop: custom aspect ratios kept in the Aspect menu, a button that swaps portrait and landscape, and turning the photo by dragging outside the crop - [x] Upright: Auto, Level, Vertical and Full from the photo's own straight edges, found by Redlamp's line detector, and Guided from drawn guides. A correction is applied only when the edges agree on it, so a landscape or a still life is levelled at most, and Auto leaves strong perspective partly in place - [x] Brush, color range, and luminance range masks, and Vision AI masks (subject, sky, background, people) - [x] Lightroom XMP preset import, setting by setting, with a report of what came across - [ ] **Best-in-class classical noise reduction** on raw data, profiled per camera and ISO, with the mosaic cleaned before demosaicing and deep shadows kept true - [x] Better X-Trans demosaicing (Markesteijn) - [x] **Camera bench:** test your own camera's raws against the camera's own JPEG on your Mac, and send only the measurements, which build the evidence on the cameras page - [x] Nikon's High Efficiency NEFs and newer bodies such as the Sony A7 V, through Redlamp's own fork of LibRaw - [ ] ICC input profiles - [x] **Point Color**, globally and inside masks, with Capture One's uniformity for evening out skin tones - [ ] Lens corrections from the lensfun database (waits on counsel) - [ ] Slider-feel calibration against Lightroom: response curves fitted against Lightroom's renders - [ ] Photos library integration and a Photos editing extension - [x] Tools that behave like Lightroom's: zoom and pan in every tool, and every brush sized from the keyboard and pointer with its size shown as it changes - [x] The filmstrip hidden automatically or kept up, from its pin or a setting, with the photo fitted above it - [x] The filmstrip: a scroll bar, thumbnails you can resize, Home and End for the first and last photo, and its line of text made optional - [x] Looks in one place: each film stock listed once, with its film's icon, and a short Base Look menu - [x] A Base Looks panel before Recipes: every look, film stock and LUT in one searchable panel, Recipes as presets, and your own recipes and imported looks shown in Finder or moved to the Trash, with built-in folders hidden - [x] The pixel under the pointer under the histogram: its RGB percentages or L\*a\*b\* values - [x] Panel on/off switches, as Lightroom's, and a value on every control that has one, to type (with arithmetic) or scrub - [x] Sensor clipping, which marks the photosites the camera clipped, and a colour-assessment view - [x] A welcome at first launch, What's New after each update, and Report a Bug or Send Feedback from the app with no GitHub account needed, with crash and hang reports offered on the next launch - [x] Masks: reorder masks and components, every overlay mode and its opacity - [x] Masks: a Color swatch - [x] Masks: local Whites and Blacks as true end points - [x] Masks: Detail, which keeps only a mask's textured or flat areas, and any mask reused inside another - [ ] **Mask edges that hold up:** a mask's edit applied to the sky's or the subject's own colour along its edge, so darkening a sky leaves no light rim along twigs and hair, and sky, subject and people edges refined per pixel, with the stray strands ViTMatte finds, that hold up in haze, backlight and flyaway hair ### Phase 3: Pro masking, healing, AI denoise, focus stacking, and looks *(in progress)* - [x] SAM-class object and face-part masks, depth range, mask refinement, mask presets, and recomputing AI masks for pasted settings - [x] Updating AI masks across a selection of photos - [x] Heal and Clone, as spots and brushed strokes, each finding its own source - [x] Content-aware Remove, and removing people, objects and things named in words with a click, taking their cast shadows and reflections with them - [x] Removing an object picked by rectangle or brush, not only with a click - [x] Remove Dust and Visualize Spots, for one photo or across a shoot - [x] **Focus stacking:** stacks found in the filmstrip, alignment through focus breathing, depth-map fusion (Auto, Smooth and Detail), a retouch brush, and results that develop like a raw - [x] `redlamp-profiler`: look matching by black-box measurement against cameras' own JPEGs; four measured film looks ship - [x] Generative fill on the device, for areas too large for content-aware Remove - [ ] Landscape and body-part masks on a model trained on data we have rights to - [x] AI mask edges solved per pixel, coarse masks refined at full resolution, with Feather and Edge sliders - [x] Objects selected by rectangle or brush - [x] Curves inside masks - [x] Snow and adaptive Landscape presets - [x] The Masks panel redesigned: one picker for every mask, its actions on screen, masks that preview themselves, Invert for a whole mask, one mask shown alone, People and Landscape pickers, and presets on every selected photo - [x] Effects for a mask's adjustments, as Lightroom's Effect menu has: Dodge, Burn, Smooth Skin, Whiten Teeth and others, and your own saved from a mask - [ ] **AI Denoise:** an on-device model working on raw data, matching or beating the best commercial denoisers, with a fast 1:1 preview and non-destructive results - [ ] Focus stacking: lens corrections before alignment, halo handling, vendors' focus-bracketing tags, and baking a stack to DNG - [x] Manufacturer lens corrections embedded in Panasonic and OM System raw files: their distortion, from process 16 - [ ] Chromatic aberration and vignetting from the corrections Panasonic and OM System raw files carry, and Fujifilm's 1.25× crop modes - [ ] The remaining film simulations (Eterna, Classic Negative, Nostalgic Negative, Pro Neg, Acros, Reala Ace), which need more photos with the camera's JPEG beside the raw; until then, Fujifilm's own published LUTs for ten simulations, which you download from Fujifilm, import in one step and fill the film slots that recipe cards use; and, as an experiment you turn on in Settings, a model of the camera's own processing for twenty simulations, with their Highlight and Shadow Tone, Color and D-Range settings - [x] **Borders around the photo:** plain borders and gallery mats shaped for Instagram, Stories and paper, film and instant frames, a Borders folder in Recipes apart from the moods, and borders left out or added at export - [ ] **Analogue film stocks:** film and digital shot side by side with charts, scanned and fitted by the profiler, with halation, bloom and grain per stock - [ ] **The agent recipe studio at scale:** many more recipes developed from briefs, once the critics agree with human picks (about 200 pairwise verdicts) - [x] Each raw opens about as bright as its camera's own JPEG, from a table of 576 cameras Redlamp measures, never from Adobe's data - [ ] **Reproduction work:** a scene-referred rendering with no tone curve or look, exposure tied to each camera's metering with readouts in stops, readout points pinned on the photo, and Adobe RGB, ProPhoto and eciRGB v2 export - [ ] **Looks measured from other apps' filters at scale:** look references made on the iPhone with Redlamp Bench, fitted into ranked candidate looks in the Recipe Lab ### Phase 4: 1.0 *(in progress)* - [ ] **Edits made in Lightroom:** each photo's develop settings, from its XMP sidecar or a Lightroom Classic catalog, converted once with a report of what came across, photos edited in Lightroom's first versions included, and a catalog's virtual copies as versions - [ ] HDR and EDR editing and export - [x] Batch export - [x] JPEG XL export, lossy or lossless - [x] The edit embedded in exported files - [ ] **AI-assisted focus stacking:** learned fusion and halo suppression, occlusion and motion handling, and good stacks from fewer or handheld frames - [ ] **AI Super Resolution** (2x and 4x) that stays faithful and doesn't invent detail - [ ] **A library for a million photos:** an index on your Mac of every photo under your folders, kept current as the disks change, with thumbnails and previews that let you browse slow, network and disconnected drives; edits and metadata stay beside each photo, or in Redlamp on this Mac for folders it can't write to, moved between the two from a folder's menu, and several Macs can share the same folders - [ ] Working on your photos away from home over your own private network, such as Tailscale, with the photos left on a drive at home: a study first - [ ] **Library and Develop in one window:** switch with a key or a click, with your selection, source and filmstrip carried across, and a second window for another screen - [ ] **Search and filters:** results as you type, one query language for the filter bar, the command palette, smart collections and `redlamp library`, counts for every filter, traits such as long exposures, panoramas, and wide-open, telephoto and ultra-wide shots, and an empty search that names the filter in its way or a name a typo away - [ ] **Grid and culling:** a grid and loupe that held arrow keys fly through, photos grouped into moments, days, cameras or lenses, Compare and Survey, sensor clipping, a raw histogram and focus peaking while culling, thumbnails that show your edits, and ratings, flags, colour labels and marks on whole selections, with Undo, by key, by mouse or from the command palette - [ ] **Soft frames in bursts:** the sharpest frame of each burst at the camera's focus point, proposed for you to accept - [x] **Your own keyboard shortcuts:** any action on the key you choose, with keymaps for people coming from Lightroom Classic, Photo Mechanic and Bridge - [ ] **Keywords, metadata and collections:** a keyword list with sets and a painter, IPTC fields, metadata presets and corrected capture times, and collections and smart collections, with a target collection and a rule editor, in the left panel beside All Photographs, Previous Import, Marked and Rejected, saved with each photo and carried into exports; other apps' XMP read, and written when you turn it on in Settings › Library, as Lightroom's Automatically write changes into XMP does - [x] **Versions in the library:** each version of a photo shown, rated, labelled and collected as a photo of its own, on the same file, as Lightroom Classic's virtual copies are - [ ] **Files on disk:** naming templates, batch rename, moving and copying files and new folders with Undo and Stop partway, removing photos to the Trash from their menu or the Delete key, importing from cards with a backup copy, stacks, and Library Health: exact duplicates, damaged and misnamed files, and a rule for raw and JPEG pairs, moved to the Trash only from a list you confirm, and photos whose files went missing, found again or removed - [ ] **Coming from Lightroom:** a Lightroom Classic catalog's ratings, keywords and collections, in a window that shows its progress, and other apps' libraries - [ ] **Coming from Apple Photos:** the albums you choose copied into your folders with their favourites, dates and original names, and their ratings, captions and keywords on macOS 27, each album a collection and a photo edited in Photos stacked with its edited version; new photos in those albums offered as they arrive, or imported on their own - [ ] **Apple Photos without copying:** your albums in the library beside your folders, left in Photos, with originals stored in iCloud downloaded when you view, edit or export them - [ ] Library research, and a design measured against a stress harness of up to two million photos on simulated spinning and network disks, with budgets that fail on regressions - [ ] The app in the App Sandbox, which the Mac App Store requires, so that it reaches only the files you give it - [ ] Accessibility, usability testing, and the Mac App Store release ### Phase 5: iPad and iPhone - [ ] The iPhone design, decided before it's built: a study of how photographers edit on a phone, and concepts tried in the harness on the Mac and on the iPhone - [ ] iPad and iPhone shells on the same engine (compact layout, touch, Apple Pencil), with in-process decoding - [ ] Coordinated sidecar I/O through Files, and edits moving between devices - [ ] Tiled rendering for large exports within iPhone and iPad memory - [ ] On-device timing of the AI models on iPhone and iPad, and performance-lab tiers for both - [ ] App Store releases for iPad and iPhone ### Later - CloudKit sync with lightweight proxy RAW files - Panorama and HDR merge - **The library's AI and map:** AI-assisted culling, similar photos, suggested keywords and text search, natural-language search, people, a map, and sensor dust followed from shoot to shoot - **Tethered shooting:** capture sessions with settings for the next captures and a hot folder for any camera, then camera control and Live View for Canon, Nikon, Sony and Fujifilm, wireless, and focus brackets straight into a stack ([research](docs/research/tethering-findings.md)) - Importing your own `.dcp` camera profiles (deferred in October 2026) - More AI features, subject to the research below: lens blur, distraction removal, and personalized auto settings - **Cloud processing** for work too heavy for the Mac, generative fill first and then masking and denoise: through a provider you bring your own key for, a third-party provider, or a ComfyUI server ([study, paused](docs/research/notes/INF-11-README.md)) ### Research The [AI and computational photography brief](docs/research/ai-and-computational-photography-brief.md) covers denoise, AI across the product (upscaling, masks, removal, auto settings), and focus stacking. Its first round of [findings](docs/research/ai-findings.md) gives a verdict for each workstream, a license matrix for every candidate model and dataset, the engine AI architecture, measured Core ML and focus-stacking prototypes (in [`research/prototypes/`](research/prototypes/README.md)), and proposed changes to the phases above. A [study of darktable](docs/research/darktable-findings.md), the most complete open-source raw developer, covers how it handles cameras, color science, modules and masks, presets and sidecars, lenses, performance and UX, and what Redlamp should adopt, do better or skip in each area. A [study of Topaz-style upscaling and sharpening](docs/research/notes/H-topaz-upscale-sharpen.md) includes a measured bake-off of open models. A [study of RapidRAW](docs/research/rapidraw-findings.md), an open-source raw editor whose AI runs built in, on a ComfyUI server the photographer runs or on a paid cloud, compares its AI with Redlamp's and leads to fills from a server on the local network, an AI-Free mode and Generative Remove on 8 GB Macs. Every recommendation from these studies is tracked, with its decision, phase and status, in the [research intake tracker](docs/research/research-tracker.md). ## Installation Redlamp runs on Apple Silicon Macs with **macOS 26** or later. Download the [latest release](https://github.com/pdcgomes/redlamp/releases/latest), a signed and notarized `Redlamp.app`, install it with Homebrew, or build it yourself from source. Move a downloaded copy to Applications before you open it: a copy opened from Downloads or from the disk image can't update itself. ### Homebrew ```bash brew tap pdcgomes/redlamp https://github.com/pdcgomes/redlamp brew install --cask pdcgomes/redlamp/redlamp ``` This installs the latest signed and notarized Redlamp.app in `/Applications` and puts the [`redlamp` command-line tool](#command-line-tool) on your `PATH`. The tap is this repository, so the explicit URL is needed the first time. Since Homebrew 7, casks from taps other than Homebrew's own load only once you trust them, and naming the cask in full, as above, trusts this one. If you tapped Redlamp earlier and Homebrew refuses to load it, run `brew trust --cask pdcgomes/redlamp/redlamp` once. ```bash brew upgrade --cask redlamp # update to the latest release brew uninstall --cask redlamp # remove the app and the CLI brew uninstall --zap --cask redlamp # also remove your recipes, looks and preferences ``` Edits live in sidecars next to your photos (see [where edits are stored](#where-edits-are-stored)), so no uninstall touches them. ### Updates From 0.2.0-prealpha, Redlamp keeps itself up to date with [Sparkle](https://sparkle-project.org), however you installed it. On its second launch it asks whether to check for updates automatically. **Redlamp › Check for Updates…** checks at any time, and **Settings › About** turns the automatic checks on or off. Copies of 0.1.0-prealpha and 0.1.1-prealpha can't update themselves, so download the latest release once more or run `brew upgrade --cask redlamp`. Builds from source never check for updates. After an update, Redlamp asks redlamp.app for the release's highlights, its What's New, on the first launch of each new version and at most once a day after that. The request sends nothing about you, your Mac or your photos: the whole list comes down, and the app picks what its version has. **Settings › About** turns this off, and builds from source show What's New only from the Help menu. ### Build from source You need **Xcode 26** or later and [**mise**](https://mise.jdx.dev). Then: ```bash git clone https://github.com/pdcgomes/redlamp.git && cd redlamp mise install # Tuist, SwiftFormat, SwiftLint at pinned versions mise run generate # builds vendored LibRaw, then generates Redlamp.xcworkspace CONFIGURATION=Release mise run build # the app SCHEME=redlamp CONFIGURATION=Release mise run build # the CLI ``` Both land in `build/DerivedData/Build/Products/Release/`. Copy the app into `/Applications`, and link the CLI from somewhere on your `PATH`. The CLI loads the frameworks next to it, so link it rather than copying it: ```bash ditto build/DerivedData/Build/Products/Release/Redlamp.app /Applications/Redlamp.app mkdir -p ~/.local/bin && ln -sf "$PWD/build/DerivedData/Build/Products/Release/redlamp" ~/.local/bin/redlamp ``` Builds are signed with the project's development team. To sign with your own, set `redlampDevelopmentTeam` in `Tuist/ProjectDescriptionHelpers/Module.swift` to your team ID and run `mise run generate` again. ## Getting started This section is for working on Redlamp. To just use it, see [Installation](#installation). ### Requirements - An Apple Silicon Mac running **macOS 26** or later - **Xcode 26** or later - [**mise**](https://mise.jdx.dev), which installs the pinned Tuist, SwiftFormat, and SwiftLint versions ### Build and run ```bash git clone https://github.com/pdcgomes/redlamp.git && cd redlamp mise install # Tuist, SwiftFormat, SwiftLint at pinned versions mise run generate # builds vendored LibRaw, then generates Redlamp.xcworkspace mise run fixtures # optional: downloads CC0 sample raw files (about 1.4 GB) into tests/fixtures mise run fixtures-shoots # optional: about 800 MB more, for the dust evaluation mise run run -- tests/fixtures/raw # build and launch, opening a folder ``` You can also run `mise run run` on its own and choose **File → Open Folder…** (⌘O), or drop a folder or files onto the window: folders join the Folders panel. Redlamp remembers them and reopens the last folder, collection or Library entry, on the photo you were on. ### Command-line tool The `redlamp` CLI uses the same engine API as the app. It is useful for scripting, quick checks, and reproducing renders. ```bash mise run render -- info ~/Pictures/DSC01234.ARW mise run render -- render ~/Pictures/DSC01234.ARW -o out.jpg --size 2048 \ --set exposure=0.5 --set shadows=30 --wb auto --base-look vivid ``` `redlamp export --to ` exports several photos at once, as the Export dialog does: each with its own edit, read from its sidecar (a photo without one exports as shot), one at a time. A folder gives the photos in it, in name order. `--name` takes a naming template, as Rename Photos does (`{name}-redlamp` by default; `"Trip {sequence:2}"` names them Trip 01, Trip 02…), with `--text` and `--start` for the texts and the first number it asks for, and `--existing number|overwrite|skip` says what happens to an earlier export with the same name; a photo is never written over. The dialog's format, quality, file size limit, TIFF compression, size, bit depth, color space and metadata are options too (`redlamp export --help`). It prints each file it writes and each photo it couldn't export, with why, carries on past a failure, and exits 1 if a photo wasn't exported. `redlamp stack -o out.jpg [--strategy auto|smooth|detail] [--depth depth.png]` merges a focus stack; `--save stack.redlampstack` writes a stack document instead, which `render` and the app open like any photo, and `--detect ` lists the stacks the library would suggest. `redlamp library photos` works with Apple Photos as File › Add Albums from Apple Photos… does, only ever reading Photos and asking macOS for access the first time. `--keep` keeps the albums `--album` names in Photos, copying nothing, beside those kept already, and `--list` lists the albums kept with the photos the library has of each; `--originals` says how much the originals downloaded from iCloud take, and `--evict` empties their cache. `--albums` lists its albums, folders, smart albums and shared albums, with Photos' estimate of the photos in each and its ID. `--census` reports what importing the albums `--album` names would bring (a title, a path of titles such as `Trips/Lisbon`, or an ID, repeated for more; a folder for its albums; without one, every album but smart and shared ones), and writes nothing. `--apply --destination ` imports them, in folders and names from `--folders` and `--names` (`--folders {album}` puts each photo in a folder named after its first album), and `--undo` takes the last import back, its copies to the Trash. `--include-hidden` brings hidden photos, `--index` names the library, `--simulated ` reads a simulated library instead of Photos, and `--json` prints JSON (`redlamp library photos --help`). `redlamp recipe …` holds the look-development tools: list, lint, render, contact sheets, `.cube`, `.3dl` and HaldCLUT import (`--space` for camera log LUTs), export, style fingerprints and fitting, golden renders, and rebuilding the bundled looks. `redlamp mcp` serves the engine and recipe library as an MCP server for agents. See [look development](docs/recipes/look-development.md) and the [agent recipe studio](docs/recipes/agent-studio.md). `redlamp camera-bench ` runs the camera bench: it checks how each raw decodes and compares Redlamp's default rendering with the JPEG the camera embedded, choosing up to eight photos per camera mode (`--all` for every file), and writes the report the app would send (`-o`) and side-by-side pairs (`--pairs`). `scripts/camera-bench-seed.py` runs it over raw.pixls.us, one CC0 file per camera without a verified sample, and `scripts/camera-bench.py` turns reports into the evidence on the cameras page ([the camera bench](docs/camera-bench.md)). `redlamp noise calibrate ` fits a camera's noise profile from calibration frames (pairs of flat frames at several brightnesses per ISO, and bias frames), and `redlamp noise check ` shows which noise each photo renders with: its file's, its camera's profile or the measurement. Profiles ship in `packages/RedlampServices/Resources/NoiseProfiles`. ### Development tasks | Task | What it does | | --- | --- | | `mise run setup` | Once per clone: use the repository's git hooks. The pre-commit hook lints the staged Swift files with SwiftFormat as CI does, and the pre-push hook runs the push gate before anything is pushed to main | | `mise run generate` (`g`) | Vendor LibRaw and generate the Xcode workspace | | `mise run build` (`b`) | Build the macOS app | | `mise run run` (`r`) | Build and launch; pass a folder after `--` | | `mise run test` (`t`) | Engine purity gate plus all unit and engine tests | | `mise run gate` | The push gate, which the pre-push hook runs before every push to main and which stops a push that fails. It checks a commit (HEAD by default, or `-- `) in a worktree of its own beside the main checkout that holds only what's committed: CI's quick checks, and for a push that changes code, SwiftFormat, a build of everything with its tests, and the reference tests, which compare what the code makes with what the repository records (golden renders, process references, recorded reports, the sidecar schema, scenario coverage), in a few minutes. A push that changes only docs, the site, the video, research notes or tools takes seconds. A commit whose files have passed isn't checked again, so running it before pushing makes the push itself immediate. `-- --suite` runs the whole test suite instead, and `-- --full` adds CI's Release builds | | `mise run e2e` (`e`) | The end-to-end regression suite: the smoke tier by default, `-- --tier full`, `release`, `performance` or `soak` (see [Regression suite](#regression-suite)) | | `mise run lint` (`l`) | Purity and focus ring gates, SwiftFormat (lint mode), and SwiftLint | | `mise run vendor` (`v`) | Build the vendored C/C++ libraries (pinned version and SHA in `config/vendored-libs.json`) | | `mise run fixtures` | Download CC0 sample raw files: the development samples into `tests/fixtures/raw`, and the camera coverage set (`tests/decode/samples.json`, checksums verified) into `tests/fixtures/cameras` | | `mise run lookdev` | Download the 40-image CC0 look-development set into `build/look-dev` (checksums verified) | | `mise run profile-data` | Download the CC0 Fujifilm raw and camera-JPEG pairs the look profiler fits against | | `mise run render` | Build and run the `redlamp` CLI | | `mise run screenshots` | Regenerate the README screenshots of the app and the harness, on temporary copies of the fixtures (needs Screen Recording permission, the fixtures and the look-development set) | | `scripts/capture-hero.sh ` | Regenerate the hero shots for the README and redlamp.app (`docs/images/hero*.png`) from a folder of your own photos, in the default Neutral theme, through `scripts/capture-promo.sh`, whose header describes the folder's `promo.txt` (needs Screen Recording permission and a Debug build) | | `mise run harness` (`h`) | Build and launch the UI component harness | | `mise run release` | Build `origin/main` in a clean worktree, with the patch version bumped if it's been released, then sign, notarize and publish it as a GitHub release with its update feed (see [Releasing](#releasing)). `DRY_RUN=1` pushes nothing and stops after signing, and with it `REF=` builds another commit | | `mise run notarize -- ` | Notarize a signed `.app`, `.dmg` or `.zip`, then staple and check it with Gatekeeper | | `scripts/test-update.sh [--auto]` | Update an old copy of a dry run to the dry run itself through Sparkle, from a feed on 127.0.0.1 (see [Releasing](#releasing)) | | `scripts/perf-sweep.sh [Debug\|Release] [parameter] [script]` | Drag a slider for 3 s and report main-thread smoothness, each frame's time from request to frame and the app's CPU, with every panel open by default (`select=3,panel=all`); `REPORT_DIR` names where the run's reports go. `IDLE=` then leaves the app alone that long with the photo open and reports its CPU, wakeups and memory; `PROFILE=1` adds a main-thread profile; `PANELS=swiftui` measures the SwiftUI panels | | `scripts/perf-card.py [--apply\|--check]` | Redraw the performance card at the top of this README (`docs/images/performance-card*.svg`) from `docs/performance/history.jsonl`; `scripts/perf-history.py` runs it whenever it adds a record | | `scripts/make-folder-fixture.sh [folders] [per-folder]` | Build a tree of photos (500 folders of 100 by default) from APFS clones of one sample raw, using no disk space. Put it in a folder ending in `.noindex` so Spotlight leaves it alone | | `--folders-perf [--folders-perf-warm N] [--folders-perf-quit]` (development builds) | Open a tree of photos in an editor of its own and measure listing, thumbnails, warming, the disk cache, the main thread while the filmstrip scrolls, the cores and memory; writes `/tmp/redlamp-perf.txt`, or `perf.txt` in the directory given with `--perf-report ` | | `scripts/photos-census-kit.sh [--app ]` | Make the census of a Photos library (LIB-57) a kit for the Mac that has the library: a development build, under a bundle ID of its own, whose `--photos-census ` measures in the editor's place what Photos keeps under Optimize Mac Storage, through Redlamp's own PhotoKit code, with the `run.sh` its owner runs (`measure`, then `recovered`, `offline` and, a week on, `week`), zipped to send by AirDrop. `read ` checks that a report names nothing and prints it | | `scripts/harness-capture.sh [mode]` | Screenshot a harness scene; with `side` mode, `swift scripts/parity-diff.swift ` scores it and `scripts/parity-rows.swift` compares it row by row | ### Regression suite `mise run e2e` works the real app through its features the way a person does, by keys, menu items, clicks and drags, and fails if something is missing, not wired up, behaving wrongly, crashing, stalling the main thread or slow. Whether an edit renders correctly stays with the engine and golden tests; the suite checks that the features are there and work ([design](docs/plans/2026-10-05-regression-suite-design.md)). - **How it runs.** `scripts/e2e.py` builds a copy of the app with the suite's driver compiled in (`packages/RedlampAutomation`, in Debug and profiling builds only) under the bundle ID `app.redlamp.mac.e2e`, gives it a home of its own (`CFFIXED_USER_HOME`) with clones of the sample raws and of your downloaded models, points Report a Bug and the camera bench at a stub relay on 127.0.0.1, and launches it in the background: it never takes your mouse or keyboard unless you pass `--focus`, keeps out of the run any key you type while one of its menus is open, and checks before and after that your own Redlamp files and preferences are untouched. Runs from any checkout take turns, since they share the test app's defaults: one waits while another holds the test app. The driver writes what happens to `events-*.jsonl` as it goes; the supervisor stops a launch that makes no progress, collects crash reports, retries a failed scenario once in a fresh app (a pass on retry is reported as flaky), and writes `report.md` and `report.json` under `build/e2e/-