# Proposal ## Why Тоновая кривая сейчас ведёт себя не как инструмент из Lightroom: крайние узлы не существуют до первых кликов, линия строится по прямым сегментам, а готовых пресетов контраста и пользовательских пресетов нет. Пользователь не может быстро применить типовой контраст или сохранить свою кривую. Дополнительно `PATCH /auth/me/preferences` заменяет весь объект настроек, поэтому хранение пресетов в профиле без мержа затирало бы другие разделы. ## What Changes - **Кривая.** Крайние узлы `(0,0)` и `(1,1)` существуют сразу и являются обычными точками; первый клик добавляет точку между ними. Крайние узлы двигаются по x и y, вне них кривая постоянна («полки», как на скрине). Линия и рендер используют плавную монотонную кубическую интерполяцию (PCHIP): SVG-путь и LUT в Go/TS. «Сбросить» возвращает линейную кривую. - **Встроенные пресеты.** `Линейный`, `Средний контраст`, `Сильный контраст` — каждый описывает все четыре канала: контраст задаётся кривой RGB, каналы R/G/B остаются линейными. Подпись показывает активный пресет; при ручной правке любого канала — `Пользовательский`. - **Пользовательские пресеты.** Пресет описывает кривые всех каналов (`name`, `channels: { rgb, red, green, blue }`). Сохранение текущих кривых всех каналов, применение заменяет все четыре кривые, переименование и удаление. Хранение в `users.preferences.curve_presets` (профиль пользователя), приватно для пользователя. - **Мерж настроек.** `PATCH /auth/me/preferences` принимает `photo_info` и `curve_presets` по отдельности, мержит переданные разделы с сохранёнными, валидирует и возвращает полный merged-объект. Сохранение «Сведений» больше не затирает пресеты, и наоборот. - **Импорт/экспорт.** JSON-файл `{ version: 1, presets: [...] }`: экспорт пользовательских пресетов, импорт с добавлением в профиль (при совпадении имени — перезапись). - **Совместимость.** Миграций схемы нет: пресеты лежат в JSON-блобе `preferences`. Старые пресеты формата `{ channel, points }` конвертируются в четыре канала при чтении и перезаписываются при следующем сохранении. Существующие сохранённые кривые начнут интерполироваться плавно, поэтому их визуальный результат может немного измениться. ## Capabilities ### New Capabilities Нет — поведение входит в существующие способности `photos` и `auth`. ### Modified Capabilities - `photos`: добавляются требования «Тоновая кривая» (крайние узлы, плавная интерполяция, встроенные пресеты, сброс) и «Пользовательские пресеты кривой» (пресет из четырёх каналов, сохранение/применение/переименование/удаление, импорт/экспорт). - `auth`: требование «Хранение пользовательских настроек интерфейса» расширяется мержем разделов и хранением пользовательских пресетов кривой; добавляется сценарий «сохранение одного раздела не затирает другие». ## Impact - `backend/internal/auth/handlers.go` — `preferencesPayload` с `curve_presets`, мерж разделов, валидация имени и кривых всех четырёх каналов. - `backend/internal/auth/store.go` / `sqlite_store.go` — без изменений схемы; запись merged-JSON через существующий `UpdatePreferences`. - `backend/internal/photos/edit.go` — `curveEval`/`curveLUT` переходят на PCHIP; тесты Go на гладкость/LUT. - `frontend/src/lib/edit.ts` — PCHIP в `buildCurveLUT`, типы и нормализация пресетов, точки кривой. - `frontend/src/lib/components/PhotoEditPanel.svelte` — узлы-углы, плавный SVG-путь, меню пресетов, сохранение/переименование/удаление, импорт/экспорт. - `frontend/src/lib/types.ts`, `stores/auth.svelte.ts`, `api.ts` — тип `Preferences.curve_presets`, сохранение через существующий endpoint. - Новые вспомогательные модули: меню/диалоги пресетов, импорт/экспорт JSON. - Тесты: `edit_test.go`, `edit.test.ts`, тесты мержа/валидации preferences, e2e сохранения пресетов в профиле.