# Design ## Context Неразрушающее редактирование фото уже реализовано: параметры правок хранятся в `photo.edit_params` (`map[string]any` JSON-блоб), сервер рендерит отредактированную копию как отдельные объекты ролей `edit`, `edit_thumb`, `edit_medium`, `edit_preview` рядом с исходными, оригинал не меняется. На сегодня поддерживается только блок «Свет» (`LightParams` в `backend/internal/photos/edit.go`, зеркало на клиенте `frontend/src/lib/edit.ts`, живой превью через `frontend/wasm/light/` → `static/light.wasm` с тестом паритета `wasmMatchesReference`). Хранение в JSON-блобе обратноли не требует миграции: старые фото без ключа `color` рендерятся без цветовых правок. ## Goals / Non-Goals **Goals:** - Добавить блок «Цвет» к неразрушающему редактированию: баланс белого (Темп, Оттенок), Вибрация, Насыщенность, Цветовой микшер по оттенкам, Точечный цвет, Цветокоррекция. - Живой клиентский превью с паритетом трёх реализаций: сервер Go, клиент TypeScript, WASM (Rust) — как для «Света». - Рендер цветовых правок по пикселям исходного объекта, после световых правок. - Обратная совместимость: фото без ключа `color` в `edit_params` рендерятся как прежде. **Non-Goals:** - Синхронизация правок между устройствами или через Android-клиент. - Изменение ролей хранения или формата объектов (`edit`, `edit_thumb`, … остаются). - Миграция схемы базы данных. ## Decisions **Цвет хранится в том же `edit_params`, рядом с `light`.** - Обоснование: `EditParams` уже расширяется полем `Color ColorParams`; `map[string]any` на бэкенде и `EditParams` на клиенте принимают новый ключ без cambios схемы. - Альтернатива: отдельная колонка/таблица для цветовых правок — отвергнута, добавила бы миграцию и не сочетается с текущей моделью хранения. **Порядок операций при рендере: свет, затем цвет.** - Обоснование: цветовые коррекции (баланс белого, насыщенность) логично применять к уже скорректированной по тональности картинке; сервер и клиент должны следовать одному порядку, иначе превью не совпадёт с результатом. - Альтернатива: цвет до света — отвергнуто, несоответствие Lightroom-поведению и текущему клиентскому конвейеру. **Цветовая математика реализована трижды и держится в паритете: Go (сервер), TypeScript (клиент), Rust/WASM (живой превью).** - Обоснование: текущий подход со «Светом» (`applyLight` в Go, `applyLightToPixels` в TS, `light.wasm` в Rust, тест `wasmMatchesReference`) гарантирует, что превью в браузере совпадает с финальным рендером. Для цвета повторяем эту схему. - Альтернатива: считать цвет только на сервере и показывать превью после рендера — отвергнуто, пользователь ожидает мгновенного отклика при движении ползунков, как сейчас со светом. **Цветовые параметры применяются в пространстве RGB с промежуточным HSL.** - Обоснование: баланс белого, вибрация, насыщенность и тонирование естественно выражаются через HSL; пиксели хранятся в RGBA, поэтому пересчёт RGB→HSL→RGB на пиксельном цикле. - Альтернатива: чистые операции над RGB-каналами — отвергнуто, менее точно соответствует цветовым инструментам Lightroom. ## Risks / Trade-offs [Расхождение реализаций Go / TS / Rust] → mitigation: тест паритета `wasmMatchesReference` расширяется на цвет, изменение любой реализации требует обновления остальных и теста. [Сложность UI] → mitigation: цветовой микшер по 8 оттенкам и точечное тонирование добавляют много элементов управления в `PhotoEditPanel`; раздел «Цвет» делаем сворачиваемым, как «Свет». [Производительность рендера] → mitigation: цвет добавляет один пиксельный проход (или объединяется с существующим циклом света); параллелизация по строкам (`applyLightRows`) остаётся. [Обратная совместимость] → mitigation: отсутствие ключа `color` в `edit_params` трактуется как нулевые цветовые правки; старые фото не затрагиваются. ## Migration Plan Миграция схемы не требуется: `edit_params` — JSON-блоб, новый ключ `color` дополняет существующий `light`. Откат: удаление ключа `color` из `edit_params` возвращает фото к состоянию без цветовых правок. ## Open Questions Нет — все проектные решения (объём цвета, живой превью с паритетом) согласованы.