# План: составные типы параметров и полная типизация pipeline > Статус: **обсуждение завершено, решения приняты. Реализация пока НЕ начата** > (ждут готовности UI). Док отражает итоговую целевую архитектуру. > > Файлы: `web/src/lib/registry.ts` (3918 строк), `web/src/lib/preview/tool-views.ts` (193 строки). ## Ключевая стратегия: параллельная сборка, старый UI не трогаем Старый UI (группа `(old)/`, `ParamForm.svelte` + старый pipeline) **продолжает работать как сейчас, без рефакторинга**. Новый `ToolSchema
` строится рядом и служит источником для **нового UI**. Инструменты переписываются под новый registry по мере нужды — для нового UI. Это та же логика, что в `plan-redesign.md` применена к дизайну: параллельная сборка, изоляция от старого, затем новый становится основным и старый удаляется вместе со старым дизайном. **Разделение схем: две независимые схемы.** | Схема | Источник | Использование | | --------------------- | ------------------------------------------------- | ---------------------------------------------------------------- | | Старый `ParamDef[]` | В `ToolEntry.params` — **остаётся без изменений** | Старый UI, старый pipeline (`ParamForm.svelte`, executor, chain) | | Новый `ToolSchema
` | Новое поле `ToolEntry.schema` — добавляется рядом | Новый UI (kit/`ParamControl`, новый pipeline) |
- Старая и новая схемы **не выводятся друг из друга** — это два независимых
описания инструмента.
- Пока новый UI не готов — `schema` просто отсутствует у большинства
инструментов, старый UI ничего не замечает.
- Удаление старого UI (после перехода) попутно удаляет и старый `ParamDef[]`
## Проблема (текущая)
- `ParamDef` — плоский union из 6 примитивов (`number | slider | select |
checkbox | color | text`). Параметры инструмента — отдельные записи в плоском
массиве.
- `run()`/`generate()` получают `Record `
строится рядом для нового UI (см. «Ключевая стратегия» выше).
## Целевая архитектура (на примере «добавить рамку»)
Цель: «добавить рамку: ширина и цвет» — **один интерфейс**, а не два
слабо связанных поля.
```ts
// 1. Runtime-тип — что получает run/generate
interface AddBorderParams {
thickness: number; // рамка: ширина
color: string; // рамка: цвет
}
// 2. Типизированная UI-схема, проверяемая компилятором против Params
// Ключи схемы обязаны совпадать с полями Params; default совместим с типом.
const addBorderSchema = toolSchema : проверяет, что ключи схемы === полям P и типы сходятся ───
type FieldsOf (fields: FieldsOf ): ToolSchema { ... }
// TS выдаст ошибку, если schema содержит ключ, отсутствующий в Params, или
// если type поля не совпадает с типом Params[K].
```
Ключевая идея связки: **builder `field.x ` заставляет ключи схемы
совпадать с ключами `P`. Это и есть защита от рассинхрона.
## Составные типы (для переиспользования и группировки)
| Тип | Под-поля | Инструментов |
| ------------ | -------------------------- | ------------ |
| `dimension` | width + height | 12 |
| `color-pair` | from + to | 4 |
| `offset` | x + y | 4 |
| `gradient` | from + to + dir (+ type?) | 1 |
| `position9` | position (3×3 grid) | 3 |
| `font-style` | font + size + bold + color | 3-4 |
| `plate` | enabled + color + opacity | 2-3 |
Составной тип = группы полей, которые в интерфейсе `Params` могут разворачиваться
во вложенный объект или плоские ключи — решается на этапе реализации.
Пример для `gradient`:
```ts
interface GradientParams {
from: string;
to: string;
dir: string;
}
// схема: field.color(from), field.color(to), field.select(dir)
// плюс annotation в схеме: { group: "gradient" } → UI рисует как цветовой переход
```
## Инвентарь: какие инструменты мигрировать
### dimension (12)
resize-png*, crop-png*, fit-on-background-png, create-empty-png,
single-color-png, random-noise-png, linear-gradient-png, color-spectrum-png,
random-colors-png, draw-grid-png, placeholder-png, change-canvas-size-png
(\* у resize/crop — не просто dimension, есть специфика: keepAspect, x/y и т.д.)
### color-pair (4)
blend-two-png, step-colors-png, linear-gradient-png, two-colors-png
### offset (4)
circle-mask-png, square-mask-png, star-mask-png, wavy-mask-png
### position9 (3)
add-text-png, date-stamp-png, watermark-image-png
### font-style (3-4)
text-to-png, add-text-png, date-stamp-png
### plate (2-3)
add-text-png, date-stamp-png
## Пошаговый план перевода инструментов
> Каждый шаг — **атомарное, маленькое изменение** (в идеале 1 инструмент =
> 1 diff, укладывается в правило «коммиты < ~500 строк»). После каждого шага —
> ревью; параллельно можно делать UI нового инструмента.
>
> **Принцип малых шагов:** перевод инструмента не меняет поведение старой
> схемы (`params` остаётся), не ломает старый UI. Инструмент получает ДОПОЛНИТЕЛЬНО
> новое поле `schema` + `interface Params`, старое `run`/`params` не трогаем.
> Это гарантирует, что старый UI продолжает работать без регресса.
### Фаза 0 — фундамент (без инструментов, ещё не мигрируем)
1. **Typed field builders** (`field.slider`, `field.color`, …) + тип `Field ()`** + тип `ToolSchema ` — проверка соответствия схемы
полям Params. Diff: добавление функции в тот же файл. Без изменений registry.
3. **`ToolEntry ` generic + поле `schema`** (рядом с `params`). Diff: правка
типа `ToolEntry` в registry.ts (~10 строк). Компилируется, поведения не
меняет — `schema` опционален.
4. **Новые `defaultParams`/`sanitizeParams`** для схемы (старые не трогаем).
Diff: добавление функций рядом. Никто ещё не вызывает — просто присутствуют.
Результат фазы 0: инфраструктура готова, registry работает как раньше, ни один
инструмент не изменён. Старый UI/тесты не затронуты.
### Фаза 1 — эталонный инструмент (вертикальный срез)
5. **Инструмент «добавить рамку» (`add-border-png`)** — первый пилот:
- добавить `interface AddBorderParams { thickness: number; color: string }`
- добавить `const addBorderSchema = toolSchema `; собрать макет
на пилоте add-border-png из Фазы 1.
32. Составные виджеты (dimension, color-pair, offset, position9, font-style,
plate, gradient) — по одному, каждый с ревью.
33. Пер-инструмент layout (`schema.layout`): группировка полей рамки и т.п.
34. Для каждого переведённого инструмента — UI-макет, принимается отдельно.
### Фаза 5 — зачистка
35. Поглощение `tool-views.ts` (preview/lede/layout → meta инструмента).
36. После перехода на новый дизайн — удаление старого UI и старого `ParamDef[]`.
### Как ревьюить каждый шаг
- Diff **только один инструмент** (или фундамент без инструментов).
- Старый `params`/`run`/`defaultParams`/`sanitizeParams` — **не изменены** (кроме
добаление `schema`, если это пилот).
- Старый UI и старые тесты продолжают работать — запустить
`pnpm --dir web test` и `pnpm --dir web exec svelte-check`.
- Порядок полей в `interface Params` и в `schema` совпадает; дефолты в сeme
равны старым `default` из `params`.
- После принятия макета — можно делать UI инструмента, не блокируя остальных.
## Поток данных (runtime)
### Старый pipeline (не трогаем)
Всё как сейчас: старое `defaultParams`/`sanitizeParams`/executor/chain работают
на `ParamDef[]` и `Record `.
- **defaultParams / sanitizeParams (новые)** — выводятся из `ToolSchema `,
дефолты лежат в схеме. Старые функции не трогаем, добавляем новые рядом.
- **Executor/worker (новые)** — получает `Record `; поддержка составных типов и пер-инструмент layout
(`schema.layout`).
- `tool-views.ts` — со временем поглощается registry (preview/lede/layout →
meta инструмента). Отдельный шаг, НЕ блокирует типизацию params.
## Оценка трудозатрат
| Часть | Сложность | Время |
| ----------------------------------------------------- | ------------------------ | ---------------------- |
| Typed field builders + toolSchema\ | Средняя | ~2ч |
| Новые defaultParams/sanitizeParams под схему | Средняя | ~2-3ч |
| ToolEntry\ generic + поле schema (рядом с params) | Низкая-Средняя | ~1-2ч |
| Новый executor/worker/pipeline под схему | Средняя | ~2-3ч |
| Миграция инструментов на interface Params + схемы | Механическая, но крупная | ~8-12ч |
| Новый рендер (kit/ParamControl) + составные виджеты | Средняя | ~4-5ч |
| Поглощение tool-views.ts | Средняя | ~1-2ч |
| **Итого** | | **~20-29ч** (поэтапно) |
> Оценка выросла по сравнению с ранней версией плана, потому что принят путь
> «явный interface Params + схема + общий рендер с пер-инструмент layout» —
> это полный рефакторинг pipeline, а не только добавление составных типов.
>
> Старый UI/`ParamDef[]`/старый pipeline в смету **не входят** — они не
> рефакторятся, а продолжают работать до перехода (затем удаляются вместе со
> старым дизайном).
## Порядок реализации (кратко)
Детальный пошаговый план с атомарными изменениями и порядком ревью — в разделе
«Пошаговый план перевода инструментов» выше. Здесь краткая сводка фаз:
1. **Фаза 0** — фундамент: builders + `toolSchema ` + `ToolEntry .schema` +
новые default/sanitize. Ни одного инструмента не изменено.
2. **Фаза 1** — эталонный пилот «добавить рамку» (вертикальный срез), ревью.
3. **Фаза 2** — простые/одиночные инструменты, 1 инструмент = 1 диф.
4. **Фаза 3** — инструменты с составными типами (dimension → color-pair →
offset → position9 → font-style → plate → gradient), пилот каждого типа
отдельно.
5. **Фаза 4** — связка с новым UI: рендер `ToolSchema `, составные виджеты,
пер-инструмент layout (для каждого инструмента — UI-макет).
6. **Фаза 5** — поглощение `tool-views.ts`, затем удаление старого UI/`ParamDef[]`
## Зависимости
- **UI сперва доделать** — текущая активная работа; типизация params ожидает
готовности нового дизайна.
- Ветка redesign (`plan-redesign.md`) — параллельная, учесть при миграции
kit/`ParamControl.svelte` и `overlay-store`.
- Старый pipeline остаётся рабочим и шippable на всём протяжении перехода
(аналогично стратегии `plan-redesign.md`).