# Analog Lab

Lokální WebGL sampler filmového vzhledu. Katalogová stránka je
`/experiments/analog-lab/`. Fotka a `.cube` LUT se zpracují jen v prohlížeči.

## Stav

**PoC ve vývoji, snapshot `2026-09-19-sampler`.** WebGL 2, G'MIC paleta 29×
`.cube` 13³, 13 sad film + tělo + sklo, srovnání s originálem, paměť voleb,
35 mm rámeček s perforací, Lomo LC-A a datumka z EXIF.

## Účel

Ověřit, že jde v prohlížeči skládat film, tělo a sklo bez serveru a bez úniku
fotky. Paleta je komunitní G'MIC Film Emulation, kterou katalog **smí**
licenčně používat. Nejde o laboratorní LUT z Noritsu/Frontier.

## Rychlý start

```bash
npm install
npm run dev
```

Otevřete `/experiments/analog-lab/`. Stránka načte výchozí fotku
`fixtures/sample.jpg` (iPhone, 2400 px, sRGB, EXIF jen s datem). Přetáhněte
vlastní JPEG/PNG/WebP/HEIC nebo `.cube`.

Obnovení palety z pinned commitu:

```bash
node experiments/analog-lab/scripts/vendor-gmic-luts.mjs
```

```bash
node --test experiments/analog-lab/tests/*.test.mjs
```

`npm test` v kořenu katalogu spouští i tyto testy.

## Rozhraní

| Prvek | Chování |
| --- | --- |
| Sada | Nastaví film, tělo, sklo, rámeček a datumku; zruší ruční jezdce |
| Film / tělo / sklo | Samostatná volba; ruční jezdce zůstávají |
| Jezdec Mixu | Hodnota sady; ruční posun je označený tečkou, tečka ho vrátí |
| Vrátit na sadu | Zruší všechny ruční jezdce |
| Srovnání | Myš nad fotkou: vlevo originál, vpravo film; mimo fotku jen film; dotyk drží srovnání; klávesa O drží originál |
| Klávesy ← → | Přepínají film |
| Paměť | Volba, ruční jezdce a vlastní LUT do 400 KB v `localStorage` klíč `analog-lab:v2` |
| Fotka | Textura WebGL 2, náhled max. 1600 px na delší hraně |
| HEIC | Volitelný dekodér z CDN, jen v prohlížeči |
| Film | G'MIC `.cube` 13³ z `/experiments/analog-lab/luts/` |
| `.cube` | Nahradí LUT filmu; 1D LUT se odmítne |
| Rámeček | `none` (výchozí), `35mm`, `120` |
| Datumka | Oranžové LCD `'YY MM DD` vpravo dole; datum z `DateTimeOriginal`, jinak `lastModified` |
| Export | JPEG 0,92, delší hrana max. 2400 px, včetně rámu a datumky |

Fotka **nesmí** opustit prohlížeč. Cloudflare Pages build **nesmí** volat síť kvůli
LUT, fotce ani shaderu. Vlastní `.cube` **musí** jít načíst lokálně. Paleta
**nesmí** obsahovat NC licenci ani placený laboratorní scan.

## Parametry

Zrno vychází z ISO filmu: `18 + 10·log2(ISO/100)`, černobílý film +6, digitální
X-Trans 0. Tělo přidá nejvýše 8. Viněta je tělo + polovina skla, strop 85.
Soudkovitost a CA patří jen sklu; Holga je výjimka s pevným plastovým sklem.
Viněta v shaderu je `smoothstep(0.3, 1.4, dist)`, rohy při 85 % zůstávají
čitelné. Halace, teplota a CA mají při 100 % viditelný, ne destruktivní efekt.

## Výstupy

- živý náhled na `/experiments/analog-lab/`,
- stažený `analog-lab-<film>-<tělo>.jpg`,
- strojové jádro v `src/` bez Astro,
- 29 G'MIC `.cube` v `luts/` + `NOTICE.md`,
- fixture `fixtures/identity-2.cube` a `fixtures/sample.jpg`.

## Testy

Node testy pokrývají parse `.cube` v Adobe pořadí (R nejrychleji), identitu 2³,
zachování červené a hnědé v X-Trans Velvia LUT, 29 vendored G'MIC souborů,
sady a jejich odkazy, zrno z ISO, Lomo LC-A presety, geometrii 35 mm perforace
a datumku z EXIF. WebGL renderer se v Node nespouští.

## Licence

Kód katalogu MIT. Vendored LUT: MIT převod
[YahiaAngelo/Film-Luts](https://github.com/YahiaAngelo/Film-Luts) commit
`af957b631a304e6be94778b96cb3395de3438e9f`, původ G'MIC / Pat David
(CeCILL, CC BY-SA 4.0). Názvy stocků označují vzhled, ne ochrannou známku.
Výchozí fotka je vlastní snímek autora bez GPS. Podrobnosti:
[luts/NOTICE.md](luts/NOTICE.md).

## Hranice

Mimo rozsah: serverové zpracování, věrný scan z Noritsu/Frontier, 1D LUT,
WebGL 1 fallback, objednávka tisku, napojení na First Roll / OPP-003,
CC BY-NC-SA Fuji camera profiles a spektrální datasheetový generátor.
Halace je glow z mipmap, ne scatter v emulzi.
LUT **nedělá** zrno, CA, vinětu ani soudkovitost.
Paměť je jen v jednom prohlížeči, bez URL sdílení.
