Put the LUTs you love on RAW photos, right in the browser.
Drop one camera RAW file, preview it locally, choose a look or declared
.cube LUT contract, compare the result, and export a
full-resolution JPEG.
Open the RAW lab · Product page · Help · Run locally · Architecture
Many photographers already have LUTs they like: camera looks, film recipes,
cinematic finishes, or a small personal collection of .cube files.
LumaForge
makes that workflow approachable for RAW photos without asking the user to study
every detail of gamuts, log curves, signal ranges, and output transforms first.
The product focuses on one clear path:
single RAW file -> preview -> look or LUT -> compare -> JPEG export
It keeps the source image on the device, turns the color details a LUT needs into guided contract choices, and lets the user stay focused on finishing the photo.
| What the user wants | How LumaForge helps |
|---|---|
| Try favorite LUTs on RAW photos. | Search or choose the LUT input and output profile with plain labels. |
| See the image quickly. | Use embedded, quick, and bounded HQ preview stages. |
| Keep the photo private. | Process the selected file locally in the browser. |
| Finish one photo without setup. | Avoid accounts, uploads, native helpers, and license managers. |
| Export confidently. | Rebuild the full-resolution JPEG through the worker path when the source and contract are supported. |
Professional tools such as Lightroom, Capture One, and DaVinci Resolve remain excellent when a photographer wants full editing control, catalogs, node graphs, or production-grade grading freedom. LumaForge chooses a smaller, friendlier route for the moment when someone simply wants to turn one RAW file into a finished JPEG with a look they already enjoy.
- Load a single RAW file locally from common camera formats such as ARW, NEF, RAF, RW2, ORF, DNG, CR2, CR3, PEF, SRW, IIQ, 3FR, FFF, and related RAW extensions.
- See an early visible image through embedded, quick, and bounded HQ preview stages.
- Compare original and processed output: a split with the WebGPU preview, or an original toggle in the slower CPU preview. On a phone the compare lens sits on the photo, and a hold peeks at the original.
- Pick a look from the LumaForge LUT catalog, or from another catalog you add by URL. Catalog LUTs usually come with their input and output contract; when one does not, LumaForge asks for it.
- Fine-tune with a bounded set of controls: exposure, contrast, highlights, shadows, whites, and blacks; temperature and tint; saturation and vibrance; eight HSL bands; and look strength. They stop short of a full development cockpit, and the export reproduces every one of them.
- Straighten and reframe with Transform: upright modes, manual vertical and horizontal perspective, rotate, aspect, scale, and offset, with constrained crop on by default. The full-resolution export reproduces the committed framing and refuses a geometry it cannot plan.
- Upload a custom
.cubeLUT and declare its input and output contract. - Work with profile families such as ARRI LogC, RED Log3G10, Sony S-Log, Panasonic V-Log, Fujifilm F-Log, Canon Log, Nikon N-Log, ACES, and display sRGB.
- Export a full-resolution JPEG (quality 0.92) through a bounded worker path, with download, share, and clipboard actions where the browser supports them. If an earlier export of the same file was interrupted, the next export you start uses a safer setting; nothing resumes or exports on its own.
The color path is scene-referred until final JPEG output:
RAW file
-> @lumaforge/luma-raw-runtime
-> metadata, embedded preview, quick/HQ decode, export capability facts
-> Linear ProPhoto scene-referred working image
-> white balance, tone, saturation, and HSL adjustments
-> LUT input gamut and transfer/log encoding
-> declared .cube LUT, at the chosen strength
-> declared LUT output transform
-> Rec.709/sRGB JPEG output
At export, a committed Transform is resampled at full resolution before this color path runs.
LUT contracts are the small bit of structure that lets LumaForge apply creative looks to RAW files without making the user build a color pipeline by hand. When the LUT already carries useful metadata, LumaForge can use it. When it needs more information, the app asks for the LUT input and output profile with a searchable contract browser.
If the selected source file or LUT contract is not supported by the full-resolution export path yet, LumaForge explains what is missing and holds export until the final JPEG can be reproduced by the authoritative worker path.
LumaForge is an active browser RAW + LUT pipeline. The current supported baseline is a modern desktop browser with WebGPU. Browsers without WebGPU use a slower CPU preview with the same color output as export. Mobile browsers, unusual RAW layouts, and files that cannot expose the required processed-window facts may be marked experimental or unsupported.
The product deliberately does not include:
- cloud upload as a requirement;
- accounts or project catalogs;
- batch processing;
- a local daemon or native helper;
- a full desktop-style RAW development panel;
- AI denoise, masking, lens correction, or unlimited adjustment stacks.
The app is split around the same boundary the product sells: interactive preview and authoritative export share color intent, but they are not the same executor.
packages/luma-raw-runtime: browser RAW metadata, preview extraction, decode sessions, processed-window access, export capability facts, and pinned native artifacts.packages/luma-color-runtime: pure TypeScript color math, LUT contracts, transfer/gamut transforms, graph logic, row processing, and WGSL helpers.packages/luma-jpeg-runtime: bounded row-oriented JPEG encoding.packages/render-engine: the headless engine shared by/rawandlmfg: full-resolution export and its fail-closed gates, export geometry, the CPU preview renderer, resource policy, and render manifests.src/lib/webgpu: WebGPU interactive preview rendering. Without WebGPU the preview falls back to the engine's CPU preview worker.src/lib/export: the browser worker shell and output sinks for the engine's full-resolution export.src/lib/transform: the Transform controls' geometry, upright detection, and the preview worker that shows the framing; export reproduces the committed geometry in the engine.src/modules/raw-processor: the/rawworkflow for upload, preview, look and LUT selection, Adjust, Transform, LUT contract selection, compare, status, and export actions.
packages/lmfg-cli ships lmfg, a Node.js CLI for agents and scripts that
runs the same RAW → look → export pipeline headlessly with sealed render
manifests. Its params carry no geometry, so it cannot author a Transform;
render replay reapplies the geometry a full-resolution export manifest
records. See packages/lmfg-cli/README.md for the agent loop, JSON protocol,
and exit codes. packages/lmfg-mcp serves the same commands, plus two
image-reading tools, over MCP stdio. Build both with pnpm cli:build.
Requirements:
- Node.js compatible with the repo toolchain
- pnpm 10.18.0
- A modern desktop browser with WebGPU
Install dependencies:
pnpm installStart the development server:
pnpm devOpen:
http://localhost:5173/raw
Common checks:
pnpm lint
pnpm test:run
pnpm buildScoped checks for a smaller change:
pnpm test:app # app, tooling, and color runtime tests
pnpm test:runtime # runtime packages and the app's runtime adapters
pnpm test:cli # lmfg and lmfg-mcp (cli:build first)
pnpm test:webgpu # WebGPU preview against the export executor
pnpm test:browser # Playwright specs under tests/browser
pnpm check:structure # unused code and import cyclesAGENTS.md maps which checks a change needs and where each contract lives.
This repository uses pnpm only.
The RAW and JPEG runtimes are workspace packages.
Their native inputs are pinned
and rebuilt from recorded sources.
Do not make the app depend on libraw-wasm,
LibRaw-Wasm, or local baseline artifact paths; the current RAW boundary is
@lumaforge/luma-raw-runtime.
Production builds prefer the prebuilt @lumaforge/luma-native-artifacts package
when its native files are available.
Development serving defaults to workspace
source artifacts.
Override selection with LUMAFORGE_NATIVE_RUNTIME_MODE:
auto: prefer prebuilt artifacts, then fall back to workspace artifacts.prebuilt: require@lumaforge/luma-native-artifactsartifacts.source: require workspacepackages/*/dist/nativeartifacts.
Native commands:
pnpm native:prepare
pnpm native:build
pnpm native:verify
pnpm --filter @lumaforge/luma-raw-runtime testBefore publishing refreshed native artifacts:
pnpm native:build
pnpm native:verify
pnpm native:artifacts:sync
pnpm native:artifacts:verify
pnpm native:artifacts:packPublic RAW smoke fixtures can be fetched with:
pnpm --filter @lumaforge/luma-raw-runtime fixtures:fetch-publicKeep contributions aligned with the product boundary: one RAW file, local preview, look or LUT, comparison, and trustworthy JPEG export. Color and LUT changes should keep contracts explicit: declared input gamut, transfer/log curve, LUT role, output handling, and export-readiness behavior should remain clear to users.
LumaForge is distributed under GPL-3.0. See LICENSE.
The RAW and native artifact packages carry third-party native notices for LibRaw, Little CMS, libjpeg-turbo, and the pinned Emscripten toolchain. See packages/luma-raw-runtime/THIRD_PARTY_NOTICES.md before redistributing native artifacts.