A fast, subscription-free raw photo editor for macOS.
Adobe's grip on raw editing makes serious photo work expensive for students and hobbyists. The open alternatives are capable but dated or hard to learn. Orion aims at the gap: a GPU pipeline quick enough that adjustments feel instant, a toolset capable of transforming an image rather than nudging it, and an interface that stays out of the way of the photograph.
Status: M0–M4 complete. It browses a folder, culls, develops, crops, masks, heals and exports with metadata and a color profile. The panel covers white balance, tone, a tone curve, three-way color grading, an eight-band color mixer, profiled noise reduction, lens corrections from a bundled 2,600-lens database, sharpening, highlight recovery, clarity, dehaze, exposure fusion, creative LUTs, film grain, a creative vignette, crop and straighten. Masks come in six kinds — linear, radial, brush, subject matte, luminance range and colour range — combined as a list and optionally feathered onto the photograph's own edges. Undo is unlimited and edits persist per photo in XMP sidecars.
Not there yet: tethering, X-Trans sensors, a Windows port. See
planning/ROADMAP.md and
planning/STATUS.md, which is the honest list — including
the one shipped defect: a 24 MP frame allocates more intermediate memory than an
8 GB Mac has, so it will not open there.
A C++20 engine drives a Metal compute graph; a SwiftUI shell displays its output texture directly, with no readback. Shaders are authored in Slang so a Vulkan or D3D backend stays reachable.
Edits form a DAG, not a chain, so moving a slider recomputes only what sits downstream of it. On an M4, a 24 MP Sony ARW re-renders an exposure change in about 8 ms against a 16 ms budget — at full resolution, with no preview proxy. That is why zooming to 100% shows real pixels: the full-resolution result is already in a texture.
decode → linearize + white balance + white clip → RCD demosaic
→ highlight reconstruction → wavelet denoise (4 scales)
→ lens corrections → sharpen → camera matrix
→ guided filter → tone, color → three-way grade
→ AgX display transform + curve → crop, straighten, orientation
27 nodes, about 4 GiB of intermediates on a 24 MP frame.
Everything between the camera matrix and the display transform is scene-linear and unbounded. There is exactly one display transform, and it is at the end.
The white clip in the first node is small and load-bearing. A sensor saturates at one count for every channel, so a blown highlight arrives as (S, S, S); white balance then multiplies each channel by its own gain and what was a white light is, in ratio, the gains themselves. Nothing downstream can undo that, because every stage after it preserves ratios. Without the clip, every clipped light in a night frame renders magenta.
Every non-trivial filter cites a published reference in research/,
and anything that does not is listed honestly in
research/UNSOURCED.md.
This rule exists because plausible-looking constants once shipped a purple cast on every image — a class of bug that is invisible to inspection and obvious to arithmetic. Citing the source makes the numbers checkable; testing the invariant keeps them right.
Notable ports: RCD demosaic, the fast guided filter (He & Sun, arXiv:1505.00996) for local highlight and shadow recovery, AgX (Sobotka) as the display transform, monotone cubic Hermite (Fritsch & Carlson, 1980) for tone curves, à-trous wavelet denoising (Starck et al., 2007) with a per-frame Poisson–Gaussian noise fit (Foi et al., 2008), cross-channel highlight reconstruction (Masood, Zhu & Tappen, CGF 2009), ASC CDL v1.2 for the grading wheels, and lensfun's lens correction models.
No GPL code is copied. Implementing a published algorithm from its description is fine — mathematics is not copyrightable — and each entry says which it is.
Requires macOS 14+, Xcode with the Metal toolchain, and Homebrew.
brew install cmake ninja libraw little-cms2
# Slang: extract a macOS release from github.com/shader-slang/slang
# into third_party/slang/
cmake -S . -B build -G Ninja
cmake --build build
open build/Orion.app./build/apps/tests/orion-tests # engine maths, plus real GPU renders
./build/orion-viewport-tests # canvas geometry
./build/apps/bench/orion-bench file.ARW # latency gate and per-control checks889 engine checks, 3711 viewport checks, 42 recorded repro scenarios, and five lint gates.
The GPU tests matter most. Pure maths tests pass happily on code that renders garbage, because they never touch a texture — two shipped bugs proved it.
./build/Orion.app/Contents/MacOS/Orion --screenshot out.png --photo x.ARW \
--scene light [--measure x,y,w,h] [--size 1680x1050]Renders the real view hierarchy offscreen, so no Screen Recording permission is
needed. --measure prints per-channel mean, standard deviation, saturation and
luma over a region of the engine's output — which is how "there is purple in my
photo" became a number that could be watched going down.
What it cannot see: the Metal canvas (AppKit cannot capture a Metal layer,
so it draws a still), and any 3D transform (cacheDisplay skips them). Both
limits are recorded in planning/STATUS.md rather than left to be rediscovered.
Apache License 2.0 — see LICENSE.
You may use, modify and redistribute Orion, including commercially. The licence
carries an explicit patent grant, which is why it was chosen over MIT: see
planning/DECISIONS.md #174 for why patents are treated as a separate question
from copyright in this project, and #188 for this decision.
⚠ NOTICE has to travel with any redistribution (Apache-2.0
§4(d)). It carries obligations that are not Orion's to waive:
| What | Terms |
|---|---|
| LibRaw | LGPL-2.1 / CDDL-1.0, linked dynamically |
data/lensfun/ |
CC BY-SA 3.0 — share-alike binds the data, so a corrected calibration goes back under the same licence |
| Adobe DNG | royalty-free patent grant, conditional on the notice appearing |
web/fonts/ |
SIL OFL 1.1 |
⚠ A licence is not a freedom-to-operate assessment, and none has been done.
CLAUDE.md says this in as many words: a method can be published, dated,
correctly attributed and still be covered by a live patent. Every algorithm here
is implemented from a published description and cited in research/, and no
GPL source was read to write any of it — but nobody has searched the patent
literature.