import { Recipe, ColorAdjustments } from '../types'; // Fallback values for every adjustable knob. Old recipes/sessions persisted in // AsyncStorage lack the newer fields — merge this under stored JSON to keep // every adjustment well-defined (see storageUtils.getAllRecipes / App session). export const DEFAULT_ADJUSTMENTS: ColorAdjustments = { exposure: 0, contrast: 0, saturation: 0, temperature: 5500, tint: 0, wbRed: 0, wbBlue: 0, highlight: 0, shadow: 0, denoise: 0, clarity: 0, grain: 0, colorChrome: 'none', colorChromeBlue: 'none', dynamicRange: 'auto', sharpening: 0, hslHue: 0, hslSat: 0, hslLum: 0, exposureCompensation: 0, }; // Standard Fuji film simulations. These are the fixed "look" presets shown at // the front of the PRESETS chip row: tapping one applies the simulation — its // baseFilter colour matrix plus whatever the stock itself carries outside the // matrix (its FILM_TONE curve, and a grain amount when the grain IS the look, // as on Acros). Every other knob still resets to its neutral default (0 / // auto), so a sim is a clean starting point, never a baked recipe; any further // look (DR, CC, contrast, more grain) is added by the user afterwards. export interface FilmSim { id: string; // Recipe-like id used only while the sim is the current selection name: string; baseFilter: Recipe['baseFilter']; adjustments: ColorAdjustments; } export const FILM_SIMS: FilmSim[] = [ { id: 'sim-provia', name: 'PROVIPES', baseFilter: 'provia', adjustments: { ...DEFAULT_ADJUSTMENTS } }, { id: 'sim-velvia', name: 'VELVIPES', baseFilter: 'velvia', adjustments: { ...DEFAULT_ADJUSTMENTS } }, { id: 'sim-classic-chrome', name: 'CLASSIC CHRIPES', baseFilter: 'classic-chrome', adjustments: { ...DEFAULT_ADJUSTMENTS } }, { id: 'sim-classic-vivid', name: 'CLASSIC VIVIDIPES', baseFilter: 'classic-vivid', adjustments: { ...DEFAULT_ADJUSTMENTS } }, { id: 'sim-classic-neg', name: 'CLASSIC NEGIPES', baseFilter: 'classic-neg', adjustments: { ...DEFAULT_ADJUSTMENTS } }, { id: 'sim-astia', name: 'ASTIPES', baseFilter: 'astia', adjustments: { ...DEFAULT_ADJUSTMENTS } }, { id: 'sim-eterna', name: 'ETERNIPES', baseFilter: 'eterna', adjustments: { ...DEFAULT_ADJUSTMENTS } }, { id: 'sim-acros', name: 'ACRIPES', baseFilter: 'monochrome', adjustments: { ...DEFAULT_ADJUSTMENTS, grain: 3 } }, // The rangefinder digital look (M/Q/SL) is not a film stock, so it ships as its own // pair instead of one look that has to compromise: // CLASSIC — the stock character: deep solid darks, natural shadows, rich but // quiet colour. Its micro-contrast is CLARITY (a local unsharp mask in both // renderers), never a global saturation boost, and a whisker of grain // keeps it feeling like film rather than digital sharpness. // VIVID — the same channel separation opened up for the digital era: lifted // exposure, lifted shadows, a little colour. It reads bright and flattering // straight off the shutter, no editing pass needed. // Both share the 'leica'/'leica-vivid' matrices; the tonal half is the sim's // own adjustments, which every apply path now carries into the panel. { id: 'sim-leica', name: 'LC STREETLIFE CLASSIC', baseFilter: 'leica', adjustments: { ...DEFAULT_ADJUSTMENTS, clarity: 2, grain: 1 } }, { id: 'sim-leica-vivid', name: 'LC STREETLIFE VIVID', baseFilter: 'leica-vivid', adjustments: { ...DEFAULT_ADJUSTMENTS, exposure: 2, saturation: 2, clarity: 2, shadow: 1, highlight: -1 } }, ]; // Film sim → full Recipe (never persisted; sims are applied on the fly). export function filmSimToRecipe(sim: FilmSim): Recipe { return { id: sim.id, name: sim.name, baseFilter: sim.baseFilter, adjustments: { ...sim.adjustments }, frameId: 'none', useGeotag: true, }; } export const DEFAULT_RECIPES: Recipe[] = [ { id: 'classic-neg-default', name: 'CLASSIC NEGIPES.', baseFilter: 'classic-neg', adjustments: { exposure: 2, contrast: 1, saturation: -1, temperature: 6300, tint: 2, highlight: -2, shadow: 1, denoise: 1, clarity: 2, grain: 4, colorChrome: 'weak', colorChromeBlue: 'none', dynamicRange: 'auto', sharpening: 0, exposureCompensation: 0, }, frameId: 'none', useGeotag: true, }, { id: 'velvia-default', name: 'VELVIPES VIVID', baseFilter: 'velvia', adjustments: { exposure: 0, contrast: 2, saturation: 3, temperature: 5500, tint: 0, highlight: 1, shadow: -1, denoise: 2, clarity: 4, grain: 1, colorChrome: 'strong', colorChromeBlue: 'none', dynamicRange: 'auto', sharpening: 0, exposureCompensation: 0, }, frameId: 'none', useGeotag: true, }, { id: 'provia-default', name: 'PROVIPES STD', baseFilter: 'provia', adjustments: { exposure: 1, contrast: 0, saturation: 0, temperature: 5000, tint: 0, highlight: 0, shadow: 0, denoise: 2, clarity: 1, grain: 2, colorChrome: 'none', colorChromeBlue: 'none', dynamicRange: 'auto', sharpening: 0, exposureCompensation: 0, }, frameId: 'none', useGeotag: true, }, { id: 'acros-default', name: 'ACRIPES MONO', baseFilter: 'monochrome', adjustments: { exposure: 0, // Low: the deep black comes from FILM_TONE's toe and the micro-contrast // from CLARITY, both of which add separation WITHOUT flattening the grey // ramp. The old 4 / highlight 3 / shadow -2 stack was three global // contrast moves on top of a matrix that was already clipping — it // bought its deep black by throwing away every step below 9% and every // one above 91%. contrast: 2, saturation: 0, temperature: 5000, tint: 0, highlight: 0, shadow: 0, denoise: 0, clarity: 3, grain: 5, colorChrome: 'none', colorChromeBlue: 'none', dynamicRange: 'auto', sharpening: 0, exposureCompensation: 0, }, frameId: 'none', useGeotag: true, }, { id: 'retro-amber-default', name: 'RETRO AMBER 🏮', baseFilter: 'classic-neg', adjustments: { exposure: 3, contrast: 2, saturation: 1, temperature: 7500, tint: -2, highlight: -3, shadow: 2, denoise: 3, clarity: -2, grain: 5, colorChrome: 'strong', colorChromeBlue: 'none', dynamicRange: 'auto', sharpening: 0, exposureCompensation: 0, }, frameId: 'classic-white', useGeotag: true, }, { id: 'cinema-spring-default', name: 'CINEMA SPRING', baseFilter: 'none', adjustments: { exposure: 0, contrast: 1, saturation: 1, temperature: 5800, tint: 0, highlight: -1, shadow: 1, denoise: 2, clarity: 1, grain: 3, colorChrome: 'none', colorChromeBlue: 'none', dynamicRange: 'auto', sharpening: 0, exposureCompensation: 0, }, frameId: 'none', cinema: 'spring', useGeotag: true, }, { id: 'cinema-summer-default', name: 'CINEMA SUMMER', baseFilter: 'none', adjustments: { exposure: 0, contrast: 2, saturation: 2, temperature: 6000, tint: -1, highlight: 1, shadow: -1, denoise: 1, clarity: 2, grain: 2, colorChrome: 'weak', colorChromeBlue: 'none', dynamicRange: 'auto', sharpening: 0, exposureCompensation: 0, }, frameId: 'none', cinema: 'summer', useGeotag: true, }, { id: 'cinema-autumn-default', name: 'CINEMA AUTUMN', baseFilter: 'none', adjustments: { exposure: 0, contrast: 1, saturation: 2, temperature: 7200, tint: -2, highlight: -2, shadow: 1, denoise: 2, clarity: 0, grain: 4, colorChrome: 'weak', colorChromeBlue: 'none', dynamicRange: 'auto', sharpening: 0, exposureCompensation: 0, }, frameId: 'none', cinema: 'autumn', useGeotag: true, }, { id: 'cinema-winter-default', name: 'CINEMA WINTER', baseFilter: 'none', adjustments: { exposure: 1, contrast: -1, saturation: -2, temperature: 4500, tint: 2, highlight: -2, shadow: 2, denoise: 3, clarity: -2, grain: 3, colorChrome: 'none', colorChromeBlue: 'weak', dynamicRange: 'auto', sharpening: 0, exposureCompensation: 0, }, frameId: 'none', cinema: 'winter', useGeotag: true, }, ];