# Pipeline Analog Lab

Zpracování má dvě vrstvy. Barevný look je 3D LUT. Prostorové vady a rámeček
jsou až po LUT.

## Tok

```text
fotka (fixtures/sample.jpg, vlastní soubor) / testovací chart
        │
        ▼
   WebGL 2 textura + mipmapy (upload jen při změně zdroje nebo rozlišení)
        │
        ▼
 fragment shader
   barrel → CA → soft/halo → LUT → kontrast těla → teplota → viněta → leak → zrno
        │                                   │
        ▼                                   ▼
  2D canvas film: rámeček + datumka   2D canvas originál: stejný rámeček
        │                                   │
        ▼                                   ▼
   náhled / JPEG                      překryv se clip-path při srovnání
```

## LUT

Adobe/Iridas `.cube` má R nejrychleji, pak G, pak B. WebGL `texImage3D` má X
nejrychleji. Pořadí je shodné, `packLut3D` data jen kopíruje. Shader čte
`sampler3D` a vzorkuje `vec3(R, G, B)`. Test `cube-lut.test.mjs` ověřuje na
X-Trans Velvia, že červená zůstane červená a hnědá teplá.

Výchozí paleta jsou G'MIC `.cube` 13³ z YahiaAngelo/Film-Luts. Film bez
souboru (položka Bez filmu) se peče do identity 32³. Síla filmu míchá
původní RGB a LUT. Vlastní `.cube` LUT paletu nahradí, shaderové vady ne.

Parser **musí** odmítnout 1D LUT a nesedící počet RGB řádků. DOMAIN_MIN a
DOMAIN_MAX shader použije před lookupem.

## Sady a jezdce

`KITS` ve `film-presets.mjs` drží kombinace film + tělo + sklo + rámeček +
datumka. `kitSelection` vrátí výběr, `matchKit` najde sadu k aktuálnímu výběru.
`mixExtras(camera, lens, film)` je základ jezdců. Ruční jezdec je zámek:
`locks` mapa id → hodnota. Při přepnutí filmu, těla nebo skla se nezamčené
jezdce přepíšou základem, zamčené zůstanou. Sada zámky zruší.

## Paměť

`localStorage["analog-lab:v2"]` = `{ v, selection, locks, customLut }`.
`selection` má film, camera, lens, frame, dateStamp. `customLut` je text
`.cube` do 400 KB. Při startu se neplatná id ignorují a platí sada
`lcaPortra`.

## Srovnání

Dvě 2D plátna ve stejném `stack` boxu. Film je vespod, originál nahoře
s `clip-path: inset(0 calc(100% - X) 0 0)`. `X` je poloha myši v boxu.
`pointerleave` originál skryje. Dotyk drží srovnání mezi `pointerdown`
a `pointerup`. Klávesa O nastaví `X = 100 %`. `fitStack` počítá velikost boxu
z rozměru plátna a volného místa, ResizeObserver ho přepočítá.

## 35 mm rámeček

Obraz je brána 24×36 mm. Vnější krátká strana je 35 mm. KS dírky mají stoupání
4,75 mm. U landscape snímku jsou nahoře a dole, u portrait vlevo a vpravo.

Rámeček se kreslí až na 2D canvas, aby JPEG dostal stejnou perforaci jako
náhled.

## Datumka

Razítko je 7segmentové LCD vpravo dole uvnitř obrazové brány, až po LUT a
vinětě. Datum **musí** jít z `DateTimeOriginal`, jinak z `DateTimeDigitized`
nebo `DateTime`. Když EXIF chybí, laboratoř vezme `lastModified` souboru.
Ukázkový chart používá `'98 08 15`. Kompakt 90. léta a jednorázák datumku
zapnou.

## LC-A

Tělo `lca` nastaví kulatou vinětu 62, leak 10 a contrast boost 0,12. Sklo
`minitar` přidá soudkovitost 12 a CA 12. Holga má `vigRound` 0,28, takže
viněta zůstane hranatější, a jako jediné tělo nese soudkovitost.
