From 82207c82f246ef39de0f8d25d7cac117c6e078be Mon Sep 17 00:00:00 2001 From: Ku6epXBOCTuK Date: Sun, 27 Sep 2026 07:48:18 +0500 Subject: [PATCH] docs: update a lot of plans, readmes, descriptions --- .gitignore | 9 +- AGENTS.md | 189 +++---- README.md | 84 ++- docs/README.md | 117 ++-- docs/agent-workflow.md | 99 +--- docs/architecture.md | 172 ++++++ docs/archive/README.md | 23 +- docs/archive/demo-fidelity.md | 118 ---- docs/archive/design-system.md | 140 ----- docs/archive/mvp-plan.md | 237 -------- docs/archive/plan-audit.md | 213 -------- docs/archive/plan-c17.md | 114 ---- docs/archive/plan-composite-params.md | 593 --------------------- docs/archive/plan-design-fix.md | 139 ----- docs/archive/plan-easy-batch.md | 99 ---- docs/archive/plan-easy-wave3.md | 87 --- docs/archive/plan-gap-waves.md | 97 ---- docs/archive/plan-hero-search.md | 83 --- docs/archive/plan-i18n.md | 111 ---- docs/archive/plan-inline-params.md | 83 --- docs/archive/plan-list-tools.md | 103 ---- docs/archive/plan-medium-wave1.md | 97 ---- docs/archive/plan-medium-wave2.md | 95 ---- docs/archive/plan-migrate-remaining.md | 181 ------- docs/archive/plan-run-unify.md | 131 ----- docs/archive/plan-sliders-pipette.md | 104 ---- docs/archive/plan-split-into-parts.md | 82 --- docs/archive/plan-tech-debt.md | 95 ---- docs/archive/plan-testing-preview.md | 194 ------- docs/archive/plan-text-wave.md | 81 --- docs/archive/plan-theme.md | 61 --- docs/archive/plan-tool-workbench.md | 98 ---- docs/archive/plan-update-ux.md | 118 ---- docs/archive/plan-workspace.md | 130 ----- docs/backlog.md | 176 +++--- docs/checklist-manual-testing.md | 41 +- docs/decisions.md | 155 ++++++ docs/plan-fields-audit-fixes.md | 35 +- docs/plan-seo.md | 126 +++-- docs/quality-gates.md | 224 ++------ docs/roadmap.md | 111 ++-- docs/testing-strategy.md | 74 +-- docs/tools-audit.md | 6 + docs/tools-map.md | 153 +++--- web/README.md | 45 -- web/eslint-plugins/README.md | 2 +- web/src/lib/registry/tools-map-doc.test.ts | 119 +++++ 47 files changed, 1029 insertions(+), 4615 deletions(-) create mode 100644 docs/architecture.md delete mode 100644 docs/archive/demo-fidelity.md delete mode 100644 docs/archive/design-system.md delete mode 100644 docs/archive/mvp-plan.md delete mode 100644 docs/archive/plan-audit.md delete mode 100644 docs/archive/plan-c17.md delete mode 100644 docs/archive/plan-composite-params.md delete mode 100644 docs/archive/plan-design-fix.md delete mode 100644 docs/archive/plan-easy-batch.md delete mode 100644 docs/archive/plan-easy-wave3.md delete mode 100644 docs/archive/plan-gap-waves.md delete mode 100644 docs/archive/plan-hero-search.md delete mode 100644 docs/archive/plan-i18n.md delete mode 100644 docs/archive/plan-inline-params.md delete mode 100644 docs/archive/plan-list-tools.md delete mode 100644 docs/archive/plan-medium-wave1.md delete mode 100644 docs/archive/plan-medium-wave2.md delete mode 100644 docs/archive/plan-migrate-remaining.md delete mode 100644 docs/archive/plan-run-unify.md delete mode 100644 docs/archive/plan-sliders-pipette.md delete mode 100644 docs/archive/plan-split-into-parts.md delete mode 100644 docs/archive/plan-tech-debt.md delete mode 100644 docs/archive/plan-testing-preview.md delete mode 100644 docs/archive/plan-text-wave.md delete mode 100644 docs/archive/plan-theme.md delete mode 100644 docs/archive/plan-tool-workbench.md delete mode 100644 docs/archive/plan-update-ux.md delete mode 100644 docs/archive/plan-workspace.md create mode 100644 docs/decisions.md delete mode 100644 web/README.md create mode 100644 web/src/lib/registry/tools-map-doc.test.ts diff --git a/.gitignore b/.gitignore index 09d2743..c21ad10 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,6 @@ node_modules -# Reference source (legacy Next.js design in refs/): branding icons are not needed -refs/public/icon.svg -refs/public/icon-dark-32x32.png -refs/public/icon-light-32x32.png -refs/public/apple-icon.png -refs/public/placeholder-logo.svg -refs/public/placeholder-logo.png -refs/public/placeholder.svg +# Отчёты разовых аудитов и артефакты прогонов web/audit/cdp-audit*.txt css-lint.txt web/coverage diff --git a/AGENTS.md b/AGENTS.md index d6a75e8..4a57690 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,129 +1,102 @@ # AGENTS.md -Инструкции для агентов (и IDE-ассистентов) по работе с этим репозиторием. +Краткий обязательный контракт. Правило: **у каждой темы ровно один источник +истины**; здесь только то, что агент обязан знать до чтения остального, и то, +что линтер не проверяет. Подробности — по ссылкам ниже. -## Стек +## Стек и команды - **SvelteKit** (`web/`) — основное приложение, Svelte 5 (runes). -- Менеджер пакетов: **pnpm**. Запускать команды из `web/`, либо через обёртки в - корне: `pnpm build`, `pnpm dev` (это `pnpm --dir web ...`). Не использовать - npm. -- Сборка: `pnpm --dir web build`, проверка типов: `pnpm --dir web check`, тесты: - `pnpm --dir web test` (Vitest), тесты с coverage-гейтом: - `pnpm --dir web test:coverage`, тесты lint-правил: - `pnpm --dir web test:rules`, e2e: `pnpm --dir web test:e2e` (Playwright, - `web/e2e/`, свой webServer на `pnpm build` + `scripts/serve-static.mjs`, порт - 4173). -- Форматирование: `pnpm format` в корне (оба прогона) или - `pnpm --dir web format` (только код web/). Проверка: `pnpm check:docs` - (docs) + `pnpm --dir web format:check` (код). -- Полный быстрый gate: `pnpm verify`; подробная матрица команд и CI — - `docs/quality-gates.md`. -- После пуша результат CI проверяется явно: смотреть статусы отдельных job, а не - общий conclusion прогона. У `e2e` стоит `continue-on-error`, поэтому прогон с - упавшим e2e помечается как `success`. `Quality` workflow запускается на каждом - пуше в `main` и на `pull_request`, поэтому browser matrix проверяется сама; - ручной запуск нужен только для старого коммита. -- Линтинг: `pnpm --dir web lint` (ESLint). Полный прогон дизайн-проверок: - `pnpm --dir web lint:all` (ESLint + stylelint + токен-аудит). Каждый шаг - выполняется, даже если предыдущий упал. Новые изменения не должны добавлять - предупреждения без записи в baseline. +- **pnpm** обязателен, npm не использовать. Команды — из корня (`pnpm build`, + `pnpm dev`, `pnpm verify`) или из `web/` с префиксом `pnpm --dir web`. -## Правила кода +| Что | Команда | +| ----------------------- | ------------------------------------------------- | +| Полный быстрый gate | `pnpm verify` | +| Типы | `pnpm --dir web check` | +| Юнит-тесты | `pnpm --dir web test` | +| Тесты lint-правил | `pnpm --dir web test:rules` | +| Линтинг | `pnpm --dir web lint:all` | +| E2E | `pnpm --dir web test:e2e` | +| Форматирование | `pnpm format` (код + docs) | +| Проверка форматирования | `pnpm check:docs` + `pnpm --dir web format:check` | -Синтаксические ограничения описывать не нужно — они проверяются линтером (весь -список правил и токены-префиксы в `web/eslint-plugins/README.md`, прогон: -`pnpm --dir web lint` / `pnpm --dir web lint:all`). Здесь — только то, что -линтер не умеет. +## Что читать под задачу -### Svelte 5 +Читать только нужную строку, а не все документы подряд. -Типизация пропсов через локальный `interface Props` закреплена правилом -`conventions/interface-props`; руками его нигде дублировать не надо. +| Задача | Документ | +| --------------------------------------------- | ---------------------------------- | +| Слои, поток данных, новый инструмент/поле | `docs/architecture.md` | +| Какие проверки запускать, пороги, CI | `docs/quality-gates.md` | +| Правка самих гейтов: «почему так, а не иначе» | `docs/decisions.md` | +| Порядок работы, нагрузка на машину | `docs/agent-workflow.md` | +| Locator-ы, fixtures, browser matrix | `docs/testing-strategy.md` | +| Детали lint-правил и токенов | `web/eslint-plugins/README.md` | +| Задачи и идеи | `docs/backlog.md` | +| Актуальный список инструментов | `docs/tools-map.md` | +| Ручная приёмка UI | `docs/checklist-manual-testing.md` | +| Индекс остальных документов | `docs/README.md` | -### E2E +## Инварианты, которые линтер не проверяет -- Сначала используй `role`, `aria-*`, label и стабильный `href`; `data-testid` - разрешён только для source/result/verdict/empty-state. -- `test.fixme` допускается только для зарегистрированной задачи в backlog или - checklist; после исправления тест и ссылку обновляют вместе. -- Полные переводы проверяются в unit-тестах; e2e проверяет поведение. -- Playwright-прогоны запускаются только по явной команде пользователя, по одному - прогону, без циклов повторов и без фонового запуска: локально matrix идёт с - `workers: 1`. Отзывчивость компьютера пользователя важнее скорости проверки — - подробности в `docs/agent-workflow.md`. +- **Сначала искать.** Новая константа, тип или утилита не заводится, пока не + найдено существующее определение — по ключу в соседних модулях и по всему + `web/src/`. +- **Комментарий объясняет «почему»**, а не пересказывает код. `TODO`/`FIXME` — + только для зарегистрированной задачи: ссылка на `docs/backlog.md` и критерий + закрытия. +- **Один шаг — одна проблема**, примерно до 500 строк; не смешивать lint, i18n, + UI и рефакторинг. +- **Не коммитить.** Коммит и пуш делает разработчик после ревью. +- **Не запускать тяжёлое без спроса.** Playwright — только по явной команде + пользователя, один прогон, без циклов повторов и фонового запуска. +- **Не писать изменяемые числа** (количество инструментов, тестов, локалей, + проценты покрытия): вместо числа — ссылка на источник или команда. Число + допустимо, только если его проверяет конфиг или тест. Обоснование и границы + автоматизации — `docs/decisions.md`, раздел 3. +- **Результат CI смотреть по отдельным job**: у `e2e` стоит `continue-on-error`, + поэтому общий conclusion может быть зелёным при красном e2e + (`docs/decisions.md`, раздел 10). -### Сначала искать +## Границы изменений -Новая константа или тип не заводится, пока не произведён поиск существующего -определения (по ключу в соседних модулях и по всему `web/src/`). Это правило в -первую очередь для ИИ-агентов: дублирующее определение ухудшает правки в -нескольких местах и запутывает. (Синтаксис самих определений — под линтером: -строка `conventions/no-string-union-alias` и т.д.) +- Production-UI — `web/src/routes/**` и `web/src/lib/components/**`. Старый UI + (`/v1/**`) удалён и не возвращается. +- `web/src/lib/core/**` и `web/src/lib/theme.svelte.ts` — общие модули: их + правка проверяется unit-тестами и smoke-сценариями production-потребителей. +- Направление зависимостей, точки расширения и рецепт правки (инструмент, вид + поля, маршрут, токен) — `docs/architecture.md`, разделы 1–2, 7, 8. -### Границы изменений +## Что проверяется линтером -- Production — только текущие маршруты и `web/src/lib/components/**`. Старый - UI (`/v1/**`) удалён и не возвращается: без redirects и совместимого режима; - исторические упоминания живят только в `docs/archive/`. Будущий API-контракт - `POST /v1/process` из `docs/plan-platform.md` не связан с удалённым UI-v1. -- `core/` и `theme/` — общие модули: их изменение проверяется unit-тестами и - smoke-сценариями production-потребителей. +`pnpm --dir web lint:all` — ESLint с `--max-warnings=0` (warn-only правила тоже +блокируют gate), Stylelint и token audit. Синтаксические ограничения здесь не +дублируются: полный список правил и префиксы токенов — +`web/eslint-plugins/README.md`; новое правило сначала появляется в warn-only +режиме с fixtures и тестами (`test:rules`). -### i18n +- **E2E линтером не покрыт:** порядок locator-ов, допустимые `data-testid`, + `test.fixme` — `docs/testing-strategy.md`. -- Новый пользовательский текст — только через словари и `t()`. Исключения: - бренд, форматы и имена файлов, технические значения, registry source strings и - `/kit`. Проверяется warn-правилом `i18n/no-hardcoded-user-text`, детали и - список исключений — в `web/eslint-plugins/README.md`. -- Новые ключи добавляются во **все** локали сразу: паритет ключей и - плейсхолдеров проверяет `i18n/dict-consistency`. +## Дизайн -### Комментарии - -- Комментарий объясняет «почему», а не пересказывает код. -- `TODO`/`FIXME` — только зарегистрированные задачи: ссылка на `docs/backlog.md` - или issue и критерий закрытия. В коде незарегистрированных пометок не - оставляем. - -### Новые lint-правила - -Новое правило сначала появляется в report-only/warn-only режиме, получает -fixtures и тесты (`test:rules`), и только после очистки baseline может стать -blocking. Учитывай: `lint:all` гоняет ESLint с `--max-warnings=0`, поэтому -warn-правило обязано приземлиться без срабатываний на текущем коде. - - -### Дизайн - -Источник правды по визуальному языку — сам код: `web/src/app.css` (дизайн-токены -и глобальные стили), `web/src/lib/components/**` (компоненты и локальные стили) -и витрина `/kit`. Приёмка — `docs/checklist-manual-testing.md`, ограничения -линтера — `web/eslint-plugins/README.md`. Общие правила, которые линтер не -проверяет: - -- Новый дизайн живёт в `web/src/app.css` и применяется ко всем - production-маршрутам. -- Все повторяющиеся визуальные элементы — отдельные компоненты в - `web/src/lib/components/`, даже «просто div с двумя стилями». -- Дизайн-токены (цвета, размеры, длительности, z-index) — только из - CSS-переменных; детали ограничений — в `web/eslint-plugins/README.md`. -- Новый токен появляется вместе с потребителем: `pnpm --dir web lint:tokens` - сообщает о неиспользуемых токенах, и это не блокирует CI только потому, что - проверка оставлена предупреждением. +Источник правды по визуальному языку — код: `web/src/app.css` (дизайн-токены и +глобальные стили), `web/src/lib/components/**` и витрина `/kit`. Новый дизайн +живёт в `app.css` и применяется ко всем production-маршрутам; повторяющийся +визуальный элемент — отдельный компонент, даже «просто div с двумя стилями»; +дизайн-токены — только из CSS-переменных, новый токен появляется вместе с +потребителем (`pnpm --dir web lint:tokens` сообщает о неиспользуемых). Приёмка — +`docs/checklist-manual-testing.md`. ## Документация -- Здесь держать только обязательные инварианты, команды и ссылки на подробные - документы; не превращать `AGENTS.md` в полный справочник. -- Индекс активных документов: `docs/README.md`; подробный workflow: - `docs/agent-workflow.md`; quality gates: `docs/quality-gates.md`; тестовая - архитектура: `docs/testing-strategy.md`. -- Новые подробные правила, процедуры и таблицы хранить в `docs/`, а детали - конкретных lint-правил — в `web/eslint-plugins/README.md`. -- Завершённые или устаревшие документы переносить в `docs/archive/`, указывать - дату архивирования и срок удаления; архив — только справка, не источник - требований. - -- Trunk-based: коммиты делает разработчик после ревью, самому не коммитить. - Изменения делать небольшими (< ~500 строк), атомарными. +- Новый документ создаётся, только если темы нет в существующем; иначе + обновляется источник истины. У документа есть статус (`draft`, `active`, + `completed`, `archived`). +- Не дублировать длинные объяснения в нескольких файлах: короткая формулировка и + ссылка на канонический документ. +- **Backlog живёт открытыми задачами:** выполненные удаляются, а критичные для + проекта факты переносятся в тематический документ. Завершённые планы и + исследования — в `docs/archive/`, удаляются через 30 дней; процедура в + `docs/archive/README.md`. diff --git a/README.md b/README.md index 7e1abcc..4a08e8d 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,35 @@ # easy-png-tools -Browser-based PNG utility toolkit — no server, no data upload, everything runs -locally. +Browser-based image utility toolkit — no server, no data upload, everything runs +locally in your browser. Inspired by online services like onlinepngtools.com, but fully offline-capable and open source. ## Features -- **Pixel-level image processing** — format conversion, transparency/alpha - channel, color transformations, geometry, filters/convolutions, morphology, - quantization & palettes, image generation, text/watermarks, analysis & checks +- **A full set of image tools** across categories: conversion, + transparency/alpha, color, channel decomposition, geometry, filters, + pixel-property masks, generation, text/watermarks, analysis & verdicts — the + current list lives in [`docs/tools-map.md`](docs/tools-map.md) - **Pipeline system (workspace)** — load image → chain multiple tool steps → sequential application → download result; pipelines saved to localStorage, exportable as JSON - **Web Worker execution** — heavy operations run off the main thread with automatic fallback to direct calls -- **i18n** — full Russian and English localization with search matching +- **i18n** — full Russian and English localization - **Dark/Light themes** — persisted to localStorage - **Pure TypeScript core** — `lib/core/` operates on `ImageData`/`Uint8ClampedArray` with no DOM dependency -- **~30+ tools** across categories: transparency, color, geometry, filters, - morphology, palettes, generation, text, analysis +- **Fully static** — no backend, no analytics, no tracking ## Tech Stack - **SvelteKit** (Svelte 5, runes mode) with static adapter — pure static export, no server - **Vite** + **TypeScript** (strict) -- **Vitest** for unit tests -- **ESLint** + **Prettier** +- **Vitest** for unit tests, **Playwright** for e2e +- **ESLint** (incl. local plugins) + Stylelint + Prettier - **pnpm** (required, ^11.20.0) - **Lucide** icons, **IBM Plex** fonts (self-hosted) @@ -54,54 +54,44 @@ pnpm build Static output is written to `web/build/`. -### Other Commands +### Commands -| Command | Description | -| ------------------------ | ------------------------------ | -| `pnpm verify` | Run the full fast quality gate | -| `pnpm --dir web test` | Run unit tests (Vitest) | -| `pnpm --dir web check` | Type-check (svelte-check) | -| `pnpm --dir web lint` | Lint (ESLint) | -| `pnpm --dir web format` | Format code (Prettier) | -| `pnpm format:docs` | Format docs (Prettier) | -| `pnpm --dir web preview` | Preview production build | +Run from the repository root; `pnpm --dir web …` targets the app package. -## Project Structure - -```txt -easy-png-tools/ -├── web/ # Main SvelteKit application -│ ├── src/ -│ │ ├── lib/ -│ │ │ ├── core/ # Pure TS image processing (ImageData-based) -│ │ │ ├── components/ # UI components -│ │ │ ├── tools/ # Pipeline, executor, overlay store -│ │ │ ├── i18n/ # Localization (ru/en) -│ │ │ └── registry.ts # Tool registry (source of truth) -│ │ └── routes/ # SvelteKit routes -│ └── build/ # Static export output -├── docs/ # Architecture docs, roadmap, plans -└── refs/ # Design reference (Next.js, not part of runtime) +```bash +pnpm install +pnpm dev # dev server +pnpm verify # full fast quality gate — the pre-review gate +pnpm build # static production export → web/build/ ``` +Полный список команд и матрица «какие проверки запускать при каком изменении» — +в `AGENTS.md` и `docs/quality-gates.md`. + ## Architecture -The project is built around a **tool registry** (`registry.ts`) — each tool is a -self-contained entry with `{id, title, description, category, params, run}`. -Pages, forms, and pipelines are generated from this registry. +Everything is built around the **tool registry** (`web/src/lib/registry/`): each +tool is a self-contained entry +`{id, title, description, category, schema, run}`. Pages, forms, and pipelines +are generated from it, and all execution goes through a single +`executor.execute` entry point. -Core image processing lives in `lib/core/` and operates directly on `ImageData` -objects with no browser API dependencies, making it portable to other -environments (WASM, CLI) in the future. +Core image processing lives in `web/src/lib/core/` and operates directly on +`ImageData`, with no browser API dependencies. + +Layering, data flow, and the recipe for adding a tool or a field kind: +[`docs/architecture.md`](docs/architecture.md). ## Roadmap -See [docs/roadmap.md](docs/roadmap.md) for the full development plan. Current -phases: +See [`docs/roadmap.md`](docs/roadmap.md) for phases and +[`docs/plan-platform.md`](docs/plan-platform.md) for the API/PWA direction. The +current focus is SEO/GEO ([`docs/plan-seo.md`](docs/plan-seo.md)) plus the +product tasks in [`docs/backlog.md`](docs/backlog.md). -1. **Phase 1** — TypeScript core + web UI (in progress) -2. **Phase 2** — Rust/WASM core for performance-critical operations -3. **Phase 3** — CLI tool +## For AI agents + +Read [`AGENTS.md`](AGENTS.md) first — it is the mandatory short contract. ## License diff --git a/docs/README.md b/docs/README.md index a06db89..e81e50e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,89 +1,56 @@ # Документация проекта -> Статус: **active**. Это индекс документов и карта источников истины для -> разработчиков и агентов. Подробные правила находятся в самих документах, а -> обязательный краткий контракт — в `AGENTS.md`. +> Статус: **active**. Индекс документов. Обязательный краткий контракт — в +> `AGENTS.md`, подробные правила — в самих документах. ## Порядок чтения -1. `AGENTS.md` — команды и обязательные инварианты. +1. `AGENTS.md` — команды, инварианты и карта «что читать под задачу». 2. Этот файл — выбрать актуальный документ по теме. 3. Соответствующий план или checklist темы. 4. Исходники, конфигурация и тесты рядом с изменяемым кодом. ## Активные документы -| Документ | Роль | Статус | -| ---------------------------------- | ---------------------------------------------------- | ------ | -| `AGENTS.md` | Краткий обязательный контракт для агента | active | -| `docs/agent-workflow.md` | Подробный порядок исследования, изменения и проверки | active | -| `docs/testing-strategy.md` | Locator, fixture, i18n и fixme-policy для e2e | active | -| `docs/quality-gates.md` | Команды проверки, warnings и CI | active | -| `docs/backlog.md` | Продуктовые, UX- и инфраструктурные задачи | active | -| `docs/roadmap.md` | Общие направления развития | active | -| `docs/plan-seo.md` | SEO/GEO-план | active | -| `docs/plan-platform.md` | PWA/API/WASM-план | active | -| `docs/checklist-manual-testing.md` | Ручная приёмка production UI | active | -| `docs/tools-map.md` | Живая карта инструментов | active | -| `web/eslint-plugins/README.md` | Детали custom lint rules и token policy | active | -| `docs/archive/README.md` | Правила архивирования и удаления старых документов | active | +| Документ | Когда читать | Статус | +| ---------------------------------- | -------------------------------------------------- | ------ | +| `AGENTS.md` | Всегда: контракт агента | active | +| `docs/architecture.md` | Слои, поток данных, новый инструмент/поле/маршрут | active | +| `docs/quality-gates.md` | Какие проверки запускать, пороги, coverage, CI | active | +| `docs/decisions.md` | Правка самих гейтов; чтение CI после пуша | active | +| `docs/agent-workflow.md` | Порядок работы, нагрузка на машину, протокол ревью | active | +| `docs/testing-strategy.md` | Правка e2e: locator-ы, fixtures, browser matrix | active | +| `docs/backlog.md` | Продуктовые, UX- и инфраструктурные задачи | active | +| `docs/roadmap.md` | Направления развития, фазы 1–10 | active | +| `docs/tools-map.md` | Актуальный список инструментов против реестра | active | +| `docs/tools-audit.md` | Сырые UX/UI-находки по инструментам (вход аудита) | active | +| `docs/plan-fields-audit-fixes.md` | Разбивка аудита на волны правок | draft | +| `docs/plan-seo.md` | SEO/GEO-план | active | +| `docs/plan-platform.md` | API/PWA/шрифты-план | active | +| `docs/checklist-manual-testing.md` | Ручная приёмка production UI | active | +| `web/eslint-plugins/README.md` | Правка lint-правил, токенов и их конфигов | active | +| `docs/archive/README.md` | Архивирование и удаление старых документов | active | -`docs/archive/` содержит временную историческую справку и не является текущим -источником критериев приёмки. Для старых документов действует срок хранения 30 -дней; после него их удаляют, а при необходимости достают из git history. +`docs/plan-domain.local.md` исключён из git через `.gitignore` (выбранное имя +домена не должно попасть в историю до покупки). Ссылки на него в `plan-seo.md` и +`backlog.md` при клонировании репозитория не разрешаются — это ожидаемо. -## Где хранить новую информацию +## Правила -- Поведение, которое агент обязан соблюдать сразу, — кратко в `AGENTS.md`. -- Точные команды, параметры скриптов и критерии качества — в - `docs/quality-gates.md` или в README соответствующей подсистемы. -- Архитектура, потоки данных и границы модулей — в отдельном architecture-плане - или документе, не дублируя существующие планы. -- Реализация lint-правил, fixtures и технические детали ESLint — в - `web/eslint-plugins/README.md` и исходниках правил. -- Продуктовые решения и ручная приёмка — в backlog, плане и checklist. - -У документа должен быть один источник истины: остальные файлы ссылаются на него, -а не пересказывают. Подробные материалы хранятся в `docs/`, чтобы не засорять -корень репозитория. Не создавать отдельные `docs/commands.md`, -`docs/known-issues.md` или копию backlog: команды принадлежат `quality-gates`, -известные проблемы — backlog и checklist. `README.md` в корне остаётся кратким -обзором продукта, а не вторым руководством агента. - -Новый документ создаётся только когда темы нет в существующем файле; иначе -обновляется источник истины. Активный документ имеет статус (`draft`, `active`, -`completed`) и понятную область применения. - -Подробные материалы хранятся в `docs/`, а не в корне. Новый файл создаётся -только если темы нет в существующем документе; иначе обновляется источник -истины. - -## Текущий baseline - -- production registry содержит 122 инструмента; -- `pnpm --dir web check` проходит без ошибок и предупреждений; -- `pnpm --dir web test` — 46 test files / 534 tests, включая тесты token audit, - PostCSS HCT-плагина и правил линтинга; -- `pnpm --dir web test:rules` — 5 test files / 104 tests; -- `pnpm --dir web lint:all` — 0 errors, 0 i18n warnings и 0 unused design tokens - от token audit; -- coverage `src/lib` — statements 91.77%, branches 83.3%, functions 74.31%, - lines 92.53% при порогах 90 / 82 / 72 / 91; -- `pnpm verify` проходит; -- `pnpm --dir web test:e2e` — 276 тестов в четырёх проектах: 276 passed, 0 - skipped, 0 failed. Отказ декодера битого PNG зафиксирован per-engine в - `web/e2e/png-fixtures.spec.ts`. - -Состав проверок и их семантика описаны в `docs/quality-gates.md`, тестовая -архитектура — в `docs/testing-strategy.md`. Baseline обновляется здесь при -изменении любого из гейтов. - -## Правила актуальности - -- У активного документа есть статус: `draft`, `active`, `completed` или - `archived`. -- Ссылки на конкретный файл или команду проверяются при изменении источника - истины. -- Архивный документ не возвращается в live-критерии без явной сверки. -- После каждого шага плана агент останавливается, показывает изменённые файлы, - проверки и нерешённые решения, и ждёт ревью. +- У каждой темы ровно один владелец: остальные документы ссылаются на него, а не + пересказывают. Новый документ создаётся, только если темы нет в существующем. +- У документа есть статус (`draft`, `active`, `completed`, `archived`) и + понятная область применения. Ссылки на конкретный файл или команду проверяются + при изменении источника истины. +- Подробные материалы живут в `docs/`, а не в корне. Не создавать отдельные + `docs/commands.md` или `docs/known-issues.md`: команды принадлежат + `quality-gates`, известные проблемы — backlog и checklist. `README.md` в корне + остаётся кратким обзором продукта, а не вторым руководством агента. +- Ссылаясь на инструмент по id, сверять id с реестром (`web/src/lib/registry/`): + исторические названия в старых планах не действуют. +- `docs/backlog.md` содержит только открытые задачи: выполненные удаляются, а + критичные для проекта факты из них переносятся в тематический документ. +- `docs/archive/` — временная историческая справка, не источник критериев + приёмки; срок хранения 30 дней, файлы восстановимы из git history. +- Протокол «остановиться и показать изменения» — `docs/agent-workflow.md`, + раздел 6. diff --git a/docs/agent-workflow.md b/docs/agent-workflow.md index bfe790a..2a35e6e 100644 --- a/docs/agent-workflow.md +++ b/docs/agent-workflow.md @@ -1,46 +1,31 @@ # Workflow для агентов -> Статус: **active**. Подробная процедура работы с репозиторием; краткие -> обязательные правила остаются в `AGENTS.md`. Этот документ не заменяет source -> of truth конкретной подсистемы. +> Статус: **active**. Порядок исследования, изменения и проверки. Обязательные +> инварианты — в `AGENTS.md`, этот документ не заменяет source of truth +> подсистемы. ## 1. Подготовка к задаче -1. Прочитать `AGENTS.md` и `docs/README.md`. +1. Прочитать `AGENTS.md` и выбрать документ по карте «что читать под задачу». 2. Найти релевантный активный план, backlog или checklist. 3. Проверить `git status`: не перезаписывать чужие незакоммиченные изменения. -4. Найти существующие типы, константы, helpers и тестовые паттерны до создания - нового определения. -5. Определить границу изменения: - - production UI — `web/src/routes/**` и `web/src/lib/components/**`; - - shared — `web/src/lib/core/**` и `web/src/lib/theme.svelte.ts`. - -Изменение shared-кода требует проверки production-потребителей. Не добавлять -исключения линтера ради отдельных модулей без записи в baseline. +4. Определить границу изменения: production UI, shared-модуль или инфраструктура + — `AGENTS.md`, раздел «Границы изменений». Изменение shared-кода требует + проверки production-потребителей. +5. Не добавлять исключения линтера ради отдельных модулей без записи в baseline. ## 2. Порядок изменения - Сначала исправляются тесты или контракт, который фиксирует неверное поведение, затем production-код — если это не отдельная продуктовая задача. -- Один PR решает одну проблему и не объединяет lint, i18n, UI и архитектурный - рефакторинг без необходимости. -- Изменения держатся небольшими и атомарными, примерно до 500 строк или меньше. -- Не добавлять комментарии, которые пересказывают код. Комментарий объясняет - причину решения или фиксирует неочевидный инвариант. -- Не коммитить изменения автоматически: коммит делает разработчик после ревью. +- Не начинать следующий этап плана в том же шаге: изменение атомарное, ревью + идёт между шагами (раздел 6). ## 3. Проверки -Команды и их область применения перечислены в `AGENTS.md`; точная матрица и -текущая политика warnings/errors поддерживаются в `docs/quality-gates.md`. - -| Изменение | Минимальная проверка | -| ------------------------------------------------------- | ------------------------------------------------------ | -| Только Markdown | `pnpm check:docs` | -| TypeScript/Svelte | `pnpm --dir web check`, `pnpm --dir web test` | -| Lint-конфиг или custom rule | `pnpm --dir web test:rules`, `pnpm --dir web lint:all` | -| Маршрут, загрузка, результат, download, тема или локаль | `pnpm --dir web test:e2e` | -| Перед релизом | полный quality gate из плана Q1 | +Матрица «изменение → минимальный набор проверок», состав `pnpm verify`, политика +warnings и чтение CI — в `docs/quality-gates.md`. Здесь только то, что относится +к работе агента. `lint:all` может завершиться успешно при warnings. Это не означает чистый baseline: нужно отдельно показать число errors, warnings и token warnings. @@ -56,75 +41,47 @@ E2E запускается отдельно от быстрых проверок - Playwright-прогоны запускаются только по явной команде пользователя: один прогон за раз, без циклов повторов и без фонового запуска. -- Локально `workers: 1` (`web/playwright.config.ts`). Browser matrix из четырёх - проектов проходит медленно, зато не забирает память и не мешает работе - пользователя. Скорость проверки уступает отзывчивости компьютера. +- Локально `workers: 1` (`web/playwright.config.ts`). Browser matrix проходит + медленно, зато не забирает память и не мешает работе пользователя. Скорость + проверки уступает отзывчивости компьютера. - Нельзя запускать тяжёлый прогон параллельно с другим прогоном или в момент, когда пользователь работает с приложением. - Диагностика флаков идёт от меньшего к большему: один spec, один проект, `--workers=1`, и только затем полный прогон. - Таймауты не подбираются под конкретную машину. Если проверка падает из-за нехватки ресурсов, это фиксируется как ограничение окружения, а не лечится - увеличением `expect.timeout`. + увеличением `expect.timeout` (обоснование — `docs/decisions.md`, раздел 7). - При необходимости повторного прогона сначала спрашивается пользователь. ## 4. Работа с тестами +Политика locator-ов, запрещённые зависимости, fixtures, browser matrix и +`test.fixme` — в `docs/testing-strategy.md`. Здесь только рабочая рутина: + - Поведенческий тест проверяет пользовательский контракт, а не текущую реализацию. -- Сначала предпочитать `role`, `aria-*`, label, stable id или href. -- `data-testid` ограничен source/result/verdict/empty-state; общие - locator-паттерны собраны в `web/e2e/helpers/page.ts`, policy — в - `docs/testing-strategy.md`. -- `data-testid` использовать только там, где семантического locator нет. +- Спецификация вызывает общие операции из `web/e2e/helpers/page.ts`, а не + повторяет raw-селекторы. - Не фиксировать абсолютное число инструментов, если проверка не связана с этим инвариантом. -- Точные переводы проверять в словарях и i18n helpers; в e2e проверять поведение - и отдельный locale smoke. -- `test.fixme` допускается только для зарегистрированной проблемы или явного - тестового долга, с ссылкой на backlog или checklist. После исправления тест и - его issue обновляются вместе. - Новые fixtures должны быть воспроизводимыми и не требовать ручного создания больших бинарных файлов. ## 5. Документация -Источник истины выбирается по теме: - -- обязательное поведение агента — `AGENTS.md`; -- индекс и карта документов — `docs/README.md`; -- качество и точные команды — `docs/quality-gates.md`; -- тестовая архитектура — `docs/testing-strategy.md`; -- lint implementation — `web/eslint-plugins/README.md`; -- продуктовые решения — backlog и активные планы. - -Не дублировать длинные объяснения в нескольких файлах. Если правило требует -пояснения, в `AGENTS.md` оставить короткую понятную формулировку и ссылку на -подробный документ. - -### Архивирование завершённых документов - -- Если план или исследование больше не является рабочим источником, перенести - файл в `docs/archive/`. -- В начало файла добавить `Статус`, `Архивирован`, `Удалить после` и причину. -- Архив хранить 30 дней для быстрой справки; после срока удалить после проверки - ссылок. Если решение понадобится снова, использовать git history. -- Не переносить активный план в архив только потому, что он пока не начат. +Порядок работы с документами и карта источников истины — `docs/README.md`. +Архивирование — `docs/archive/README.md`. ## 6. Протокол ревью между шагами После каждого шага плана агент: -1. останавливается и не начинает следующий Q-этап; +1. останавливается и не начинает следующий этап; 2. перечисляет изменённые файлы и принятые решения; 3. указывает выполненные проверки и их фактический результат; 4. отдельно перечисляет warnings, fixme, долги и вопросы; 5. ждёт подтверждения на продолжение. -Коммит и пуш делает разработчик. После пуша агент проверяет результат CI и -сообщает его вместе с локальными проверками, включая случай, когда нужный job не -запускался: статусы смотрятся по отдельным job, потому что общий conclusion -прогона с `continue-on-error` у `e2e` остаётся зелёным. Процедура описана в -`docs/quality-gates.md`. - -Следующий шаг начинается только после ревью текущего изменения. +Коммит и пуш делает разработчик. Следующий шаг начинается только после ревью +текущего изменения; после пуша результат CI читается по процедуре из +`docs/decisions.md`, раздел 10. diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..8dcd385 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,172 @@ +# Архитектура + +> Статус: **active**. Описание текущего кода: границы модулей, поток данных от +> реестра до скачивания, точки расширения. Канонический источник истины — сам +> код; этот документ объясняет, **куда смотреть и что с чем связано**, и не +> дублирует сигнатуры. + +## 1. Слои + +```txt +web/src/lib/ + registry/ # источник истины: записи ToolEntry + registry-schema.ts # декларативная схема параметров + санитизация дефолтов + catalog.ts # группировка и счётчики для /list-tools + categories.ts # id/названия категорий + tool-icons.ts # id → иконка + core/ # чистый TS: операции над ImageData, без DOM + executor/ # единственная точка исполнения инструментов + i18n/ # словари ru/en, t(), списки для i18n-правил линтера + components/ # UI (fields/, layout/, ui/, schema-компоненты) + zip.ts # сборка мультифайлового результата (1 → many) + theme.svelte.ts # light/dark + localStorage +web/src/routes/ + +page.svelte # главная + list-tools/ # каталог + tools/[id]/ # страница инструмента + kit/ # витрина компонентов (production, но исключена из i18n-гейта) +``` + +Правило зависимостей: `components/**` и `routes/**` знают про `registry/**`, +`executor/**` и `core/**`; `core/**` не знает ни о ком и не зависит от DOM; +`registry/**` описывает данные и знает только `core/**` и `registry-schema.ts`. +Нарушение этого порядка — повод не заводить импорт, а инвертировать зависимость. + +## 2. Поток данных + +```txt +registry/*.ts ──(TOOLS: ToolEntry[]) + │ + ├─► catalog.ts ──► routes/list-tools (каталог, поиск, фильтры) + │ + └─► routes/tools/[id]/+page.svelte + │ getTool(id) → запись реестра + ▼ + SchemaToolView.svelte оркестратор страницы + │ schema = tool.schema + ├─► SchemaFields.svelte поля из schema.fields (FIELDS: kind → контрол) + ├─► SchemaSourceTile/SchemaTextSource.svelte вход + └─► SchemaPreview + schema-preview-model.ts вид превью + │ buildSchemaPreviewModel(inputMode, resultKind, …) → source/result/hasResult + ▼ + executor.execute(ctx) единственная точка исполнения + │ сериализация параметров → worker → worker-handler → tool.run(ctx) + ▼ + core/* пиксели + │ + ▼ + SchemaResultTile / SchemaTextResult + SchemaActions (download/copy) + │ кодирование по ToolEntry.output (mime/ext/quality) + └─► zip.ts, если result === "files" +``` + +Ключевые решения: + +- **Реестр — единственный источник истины.** Страница, форма и пайплайн строятся + из записи; новый инструмент = новая запись + функция `run`. +- **Исполнение идёт только через `executor.execute`.** Компоненты не зовут + `tool.run` напрямую — иначе нельзя перенести тяжёлое в worker/wasm без правки + вызывающего кода. +- **Форма параметров не знает про инструмент.** Она рендерится из + `registry-schema.ts`, поэтому добавление вида поля не трогает страницы. +- **Модель превью отделена от вёрстки.** `schema-preview-model.ts` — чистая + функция, покрыта unit-тестами; `SchemaPreview.svelte` только рисует её вывод. + +## 3. Запись реестра + +`ToolEntry` (`web/src/lib/registry/types.ts`): + +| Поле | Смысл | +| ------------- | ------------------------------------------------------------ | +| `id` | уникальный ключ; он же URL-anchor и ключ в пайплайне | +| `title` | EN-строка реестра, переводится через `tools.*.title` | +| `description` | EN-строка реестра, переводится через `tools.*.description` | +| `category` | id из `categories.ts` | +| `schema` | `toolSchema({ fields, layout?, meta? })` | +| `input` | `"image" \| "text" \| "none"` — что ждёт инструмент на входе | +| `result` | `"image" \| "text" \| "verdict" \| "files"` — что отдаёт | +| `output` | mime/ext/quality для download (не у всех инструментов) | +| `run(ctx)` | чистая функция: `ctx` → `ToolResult` | + +Хелперы `genTool` / `imgTool` / `textGen` из `types.ts` задают `run` для типовых +случаев (приведение типа результата), чтобы запись не повторяла обвязку. `TOOLS` +собирается в `registry/index.ts` из восьми групп; `getTool(id)` — единственный +способ достать запись по id. + +## 4. Схема параметров + +`registry-schema.ts` — единственное место, где описаны виды полей. + +- **Виды поля** (`fieldSpecs`): `number`, `slider`, `color`, `select`, `text`, + `checkbox`, `dimension`, `color-pair`, `colors`, `offset`, `position9`, + `font-style`, `plate`, `gradient`. +- **Фабрика `field.*`** создаёт `Field`; UI-контрол подбирается в + `SchemaFields.svelte` по `spec.kind` через карту `FIELDS`. +- **`schema.layout`** группирует поля (`resolveLayoutGroups`); раскладка + разделов — единственное место, где живёт порядок и группировка. +- **Значения по умолчанию** даёт `defaultSchemaParams`; `applySourceDefaults` + подставляет размеры текущего source; `sanitizeSchemaParams` приводит мусор к + допустимому виду. Правка поведения полей идёт здесь, а не в компоненте. + +Новый вид поля требует: спека + фабрика `field.*` → запись в `fieldSpecs` → +контрол в `components/fields/schema/` → ключ в `FIELDS` → дефолт и санитизация → +i18n-подписи → тест в `registry-schema.test.ts`. + +## 5. Исполнение + +`executor/executor.ts` — фабрика `createExecutor(factories?)` плюс готовый +экспорт `execute`. Контракт асинхронный (`Promise`), параметры сериализуются, +исполнение уходит в `executor.worker.ts`; `worker-handler.ts` разбирает +сообщение и зовёт `run`. Если worker недоступен — прямой вызов. + +Отсюда следует: подключение wasm позже означает замену реализации **внутри** +исполнителя, а не правку компонентов. + +## 6. i18n + +Словари — `web/src/lib/i18n/` (`en.ts`, `ru.ts`, общий `dict.ts` с +`LOCALES`/`BASE_LOCALE`). Пользовательский текст живёт только в словарях и +читается через `t()`; строки реестра (`title`/`description`) — источник для +EN-ключей `tools.*` и словарь-переводчик. Инварианты паритета ключей, +плейсхолдеров и запрет хардкода проверяются линтером, детали — +`web/eslint-plugins/README.md`. + +## 7. Точки расширения + +| Задача | Где править | +| ------------------------------ | ----------------------------------------------------------------- | +| Новый инструмент | запись в `registry/.ts` + i18n-ключи + тесты (рецепт ниже) | +| Новый вид поля | `registry-schema.ts` + контрол + `FIELDS` (раздел 4) | +| Новый маршрут/страница | `web/src/routes/**` + ссылка в каталоге | +| Новый визуальный элемент | компонент в `components/**` по образцу `ui/` или `layout/` | +| Новый дизайн-токен | `web/src/app.css` (только там) + потребитель сразу | +| Тяжёлая операция → worker/wasm | `executor/**`, без правок компонентов | +| Мультифайловый результат | `result: "files"` + `zip.ts` | + +## 8. Рецепт: добавить инструмент + +1. **Найти соседей.** Поиск по ключу в `registry/.ts` и по всему + `web/src/` — не заводить дублирующую константу, тип или утилиту. +2. **Выбрать группу** (`geometry`/`alpha`/`color`/`convert`/`filters`/ + `generate`/`text`/`analyze`) и положить запись в её экспорт; при новой + категории — сначала `categories.ts`. +3. **Описать схему** через `field.*`, задать `layout`, если поля нужно + сгруппировать. +4. **Написать `run`** поверх `core/*`; пиксельные операции — чистые функции в + `core/`, без DOM. +5. **Проверить обязательные контракты** для нового id: entry попадает в `TOOLS`, + страница `/tools/` prerender-ится, `input`/`result` согласованы с тем, + что делает `run`. +6. **Добавить i18n-ключи во все локали** сразу. +7. **Тесты:** unit — в `registry/*.test.ts` или рядом с `core`-функцией; + e2e-smoke — существующий spec по типу `input`/`result` (правила — + `docs/testing-strategy.md`). +8. **Обновить `docs/tools-map.md`:** новый инструмент обязателен в разделе + «Реализовано», формат строки — в шапке раздела. Проверяет + `web/src/lib/registry/tools-map-doc.test.ts`: отсутствующий в карте id и + несуществующий в реестре id роняют тест. Обоснование и границы автоматизации + — `docs/decisions.md`, раздел 4. + +Ожидаемый минимум проверок: `pnpm --dir web check` и `pnpm --dir web test`; для +инструмента, меняющего пользовательский поток, — e2e (см. раздел 3 +`docs/quality-gates.md`). diff --git a/docs/archive/README.md b/docs/archive/README.md index d0a2748..39054cc 100644 --- a/docs/archive/README.md +++ b/docs/archive/README.md @@ -10,7 +10,10 @@ актуальных правил используются `AGENTS.md`, `docs/README.md` и активные планы. Если решение снова понадобится, его можно восстановить из git history или -создать новый активный документ. +создать новый активный документ: **архивные файлы удаляются, а не хранятся +вечно.** Удалённые планы восстановимы через +`git log --diff-filter=D -- name-only -- docs/archive/` и +`git show ^:`. ## Обязательные метаданные @@ -24,19 +27,18 @@ > Использование: только историческая справка ``` -Дата `Удалить после` — дата архивирования плюс 30 дней. Старые файлы, созданные -до введения политики, могут не иметь этих дат; они также считаются архивными и -не являются активными требованиями. При следующем касании их можно удалить или -привести к шаблону. +Дата `Удалить после` — дата архивирования плюс 30 дней. ## Порядок архивирования 1. Убедиться, что документ действительно завершён, отменён или заменён более актуальным источником. -2. Добавить обязательные метаданные. -3. Переместить файл в `docs/archive/`. -4. Проверить ссылки из backlog, планов, checklist и `docs/README.md`. -5. Не менять архивный документ под новые требования. +2. Убрать из него ссылки на несуществующие пути и артефакты прошлых волн. +3. Добавить обязательные метаданные. +4. Переместить файл в `docs/archive/`. +5. Проверить ссылки из backlog, планов, checklist и `docs/README.md`: удалённые + файлы должны потерять и входящие ссылки. +6. Не менять архивный документ под новые требования. ## Удаление @@ -44,8 +46,7 @@ - проверить, что документ не нужен для текущей работы; - найти и удалить оставшиеся ссылки на него из активных документов; -- удалить файл из `docs/archive/`; -- при необходимости отметить удаление в истории изменений. +- удалить файл из `docs/archive/`. До истечения срока архивный файл не превращается обратно в live-документ: если он снова актуален, создаётся новый документ или возвращается версия из git diff --git a/docs/archive/demo-fidelity.md b/docs/archive/demo-fidelity.md deleted file mode 100644 index a2e2b67..0000000 --- a/docs/archive/demo-fidelity.md +++ /dev/null @@ -1,118 +0,0 @@ -# Demo fidelity: /preview/demo vs refs-html/demo.html - -> ⚠️ **УТРАТИЛ АКТУАЛЬНОСТЬ — архивная копия.** Актуальный план фикса верности и -> текущий статус пунктов B/F — в `docs/plan-design-fix.md` (Этап 1). Аудит -> верности теперь автоматизирован (`pnpm audit` → `web/audit/audit-report.md`; -> пиксель-дифф не используется); темы в `refs-html` переключаются (скрипт -> инжектится в `scripts/extract-static.mjs`). Ниже — исходный текст на момент -> написания. - -Метод: Playwright, viewport 1440×900, скриншоты обеих страниц + замер -вычисленных стилей ключевых элементов + пиксель-дифф (без чтения картинки -моделью). Пиксель-дифф: **24.9%** (наш скролл 1731px, реф 1579px). Зоны различий -размазаны по всей высоте → править надо глобально, не точечно. - -Теперь процесс автоматизирован: `pnpm audit` (Playwright) пишет -`web/audit/audit-report.md` — light/dark токены + поэлементный дифф стилей по -тексту. Пиксель-дифф убран (неудобен для работы). Фиксы можно делать в любой -момент и перепроверять аудитом. - -## Баги (объективно, правим в любом случае) - -- **B1. Кнопки/инпуты рендерятся шрифтом Arial, а не IBM Plex Sans.** - Доказательство: пробы `Reset pipeline` → `fontFamily: Arial`. Причина: у - `button/input` не задан `font-family: inherit`. Фикс: добавить в reset - `design2.css` `button, input, select, textarea { font-family: inherit; }`. - Влияет на все страницы. (P1) -- **B2. Двойной топбар.** Страница демо рендерит свой `.topbar` (brand / AUTO - PIPELINE / help / theme / lang), который перекрывается глобальным `fixed` - Header из `preview/+layout.svelte` (в нём только theme-toggle). В рефе — один - топбар. Контент демо-топбара (brand, статус, язык) визуально спрятан за - фикс-хедером. Фикс: убрать кастомный `.topbar` из демо и сделать хедер лейаута - реф-стайл топбаром (brand + version + status + help + theme + lang) — улучшит - и C9/C10. (P1) - -## Расхождения дизайна (нужно решение) - -- **F1. Фон холста.** Реф: плоский серый `#EEF1F4`. Наш: белый + - blueprint-сетка. Решение: совпасть с рефом (убрать сетку на демо) или оставить - сетку как сигнатуру нового дизайна. -- **F2. Бейдж типа шага** (BACKGROUND/TRANSFORM/STYLE). Реф: приглушённый серый - `#6D787F`. Решено C16: `StepCard` рендерит `type` как приглушённый моно-текст - (не синий бейдж); индекс шага (`step-index`) — синий `#1769D2`, как в рефе. -- **F3. Подписи превью-тайлов** (SOURCE / STEP 01 / FINAL OUTPUT). Реф: синий - `#1769D2`, weight 400. Решено C16: `PreviewTile` label — синий `#1769D2`. -- **F4. Раскладка preview-stack.** Реф: одна колонка (5 строк, выше). Наш: 2 - колонки (grid). Решение: одна колонка (как реф) или оставить 2 колонки как - выбор нового дизайна. -- **F5. Вес лейблов контролов.** Реф: 400. Наш (`MonoLabel`): 500. Мелко. -- **F6. Мета-подписи** (DIMENSIONS/FORMAT/SIZE): реф fs 9px, наш 10px. Мелко. -- **F7. Копирайт:** `Add tool` у нас `+ Add tool`; кнопка `Download result` — - сверить стиль (в рефе синяя с белым текстом 478×42). Пробы - `Download result`/`Add tool`/`DIRECTION` вернули NOT FOUND — скорее артефакт - замера (вложенный текст/чип размера), проверить визуально. -- **F8. h1 line-height** чуть выше (наш 150px vs реф 115px) — мелкий зазор. -- **F9. Вертикальный ритм:** контент на ~152px выше, зазоры между секциями - отличаются (pipeline-head y 434 vs 400 и т.д.) — подровнять паддинги под реф. -- **F10. Внутренние отступы preview-панели** (Hide intermediate x 907 vs 1218) — - паддинг панели. - -## Темы (отложено — F1-F4) - -Серый фон `#EEF1F4` — это **светлая** тема. Уточнение по F1: наш токен -`--background` уже равен `#EEF1F4` (совпадает с рефом); видимое отличие — только -blueprint-сетка поверх фона, а не «белый vs серый». То есть F1 = «сетка против -плоского», не цвет фона. - -Перед тем как сверять цвета бейджей/тайлов/раскладок (F2-F4), нужно сначала -зафиксировать палитры light/dark как единый источник токенов. Сейчас они есть в -`web/src/lib/styles/design2.css` (`:root` + `[data-theme="dark"]`), но не -сверены с рефом. - -**Как проверить темы в refs-html:** - -- Открыть `refs-html/demo.html` (и соседние `gradient.html`, - `background-remover.html`) через Playwright/браузер. -- Нажать theme-toggle в топбаре рефа (иконка луны/солнца) — переключает тему - (скорее всего меняет атрибут/класс на `` или `.page` и переопределяет - CSS-переменные). -- Снять скриншоты светлой и тёмной темы, замерить computed-стиль `:root` - переменных рефа (через - `getComputedStyle(document.documentElement).getPropertyValue('--...')`) и - сопоставить с нашими токенами в `design2.css`. -- Рефы, похоже, не доделаны по тёмной теме — зафиксировать, какие именно токены - меняются и где расхождения. На основе этого выровнять наши токены, затем - вернуться к F2 (бейдж типа), F3 (тайлы), F4 (раскладка preview-stack). - -Решение по F1-F4 принимается только после сверки токенов светлой/тёмной темы с -рефом. - -**Состояние тем (уточнение):** наша dark-тема реализована в `design2.css` -(`[data-theme="dark"]`), но пока подключена только на preview-маршрутах (старые -страницы грузят `app.css`). Этого достаточно для сверки: токены, отличные от -light, соберём по всем `refs-html/*.html` (не только `demo.html`), остальные -токены не меняются. Light-токены уже совпадают с рефом (`--background`, -`--panel`, `--foreground`, `--muted`, `--line`, `--blue` равны). - -## Состояние (C16) - -Цветовые расхождения против `refs-html/demo.html` устранены: стек шрифтов сверен -с рефом (`"IBM Plex Sans", sans-serif` / `"IBM Plex Mono", monospace`), бренд -топбара — `--foreground`, индекс шага — синий, тип шага и подпись плитки — как в -рефе, `Segmented` — 10px/32px. Аудит: токены light 10 / dark 16, элементы 47. -Остаток — sub-pixel (10px→9px лейблы, letter-spacing) и структурные -(`display`/`rect` от наших flex/grid раскладок против статичного мока); -визуально незначимы, правим точечно при желании. Старые тесты (583) — без -регрессий. - -## План действий (предлагаю) - -> Актуальный пошаговый план фикса вынесен в `docs/plan-design-fix.md` (Этапы -> 0–1: рефакторинг + верность). Ниже — исходные наброски. - -1. Сразу поправить B1 + B2 (чёткие баги, улучшают все страницы). -2. По F1–F4 — решение за тобой (совпадать с рефом дословно ИЛИ оставить как - сигнатуру нового дизайна). -3. F5–F10 — мелочи, подчистить в том же проходе, если решаем «совпадать с - рефом». -4. Переснять скриншоты и перепроверить пиксель-дифф. diff --git a/docs/archive/design-system.md b/docs/archive/design-system.md deleted file mode 100644 index 7c72971..0000000 --- a/docs/archive/design-system.md +++ /dev/null @@ -1,140 +0,0 @@ -# План: единая дизайн-система - -> **СТАТУС: ВЫПОЛНЕН 2026-08-22.** - -## 1. Цели и принципы - -1. **Один источник правды** — все визуальные константы живут в токенах - `web/src/app.css`; ни один компонент не пишет «магические» цвета/размеры - напрямую. -2. **Никакого дублирования** — повторяющийся визуальный рецепт оформляется один - раз: либо токен, либо глобальный утилитарный класс, либо компонент в `ui/`. -3. **Простые компоненты важнее умных** — если проще сделать отдельные - `SliderField` и `TextField`, делаем два маленьких компонента, а не один - конфигурируемый монстр. -4. **Scoped-стили — только для раскладки** конкретного компонента (сетка, - отступы между блоками). Внешний вид контролов и текстов — из дизайн-системы. - -## 2. Аудит: что дублируется прямо сейчас - -- **«Приглушённый текст»** (`--text-muted` + размер 0.85–0.95rem) — повторён в - семи местах: `ToolPage` (.description, .hint), главная (.lead, .card-desc), - лейаут (.nav-link, footer), `Preview` (.dims), `ParamForm` (label), - `InfoPanel` (dt). -- **«Заголовок секции капсом»** (uppercase, letter-spacing, muted) — точная - копипаста в `ToolPage` и на главной. -- **Базовые инпуты** (padding, border, radius) — живут только внутри - `ParamForm`; любые новые типы контролов (слайдеры, пипетка цвета) пришлось бы - копировать вручную. -- **Блок «label + отступы»** — дублировался бы в каждом `*Field`; решается - обёрткой `Field.svelte`. -- **«Панель»** (surface + border + radius) — три ручные реализации одного - паттерна: `DropZone`, карточки главной, строки `InfoPanel`. -- **Кнопки** — глобальные классы `.primary`/`.secondary` без компонента; - состояния «занят/недоступен» каждый описывает заново. -- **Ошибка-баннер** — только в `ToolPage`, а понадобится минимум ещё раз в - workspace. - -## 3. Токены (расширение `app.css`) - -Существующие остаются; добавляются недостающие группы: - -```css -:root { - /* типографика */ - --text-xs: 0.8rem; - --text-s: 0.85rem; - --text-m: 0.95rem; - --text-l: 1.1rem; - --text-xl: 1.25rem; - --text-xxl: 1.75rem; - --leading-tight: 1.25; - - /* тени */ - --shadow-card: 0 4px 14px rgb(37 99 235 / 12%); - - /* фокус */ - --focus-ring: 2px solid var(--accent); - - /* контрольные размеры контролов */ - --control-height: 2.4rem; - --control-max-width: 16rem; -} -``` - -Правило именования: семантика, не значение (`--text-muted`, а не `--gray-500`). - -## 4. Глобальные утилиты (`app.css`) - -Только то, что не требует JS и не является интерактивным: - -- `.text-muted` — приглушённый текст (размер наследуется); -- `.text-caption` — мелкий текст `--text-s`; -- `.heading-section` — заголовок секции капсом (вместо двух копипаст); -- `.panel` — поверхность с бордером/радиусом (DropZone, карточки, - InfoPanel-строки); -- `.error-banner` — баннер ошибки; -- `.visually-hidden` — скрытый, но читаемый скринридерами. - -Элементные стили из текущего `app.css` (голые `input, select { ... }`) убрать — -внешний вид контролов переезжает в компоненты `ui/`. - -## 5. Состав UI-компонентов (`web/src/lib/components/ui/`) - -Все — тонкие обёртки над нативными элементами, без состояний кроме своих: - -| Компонент | Пропы | Заменяет | -| ---------------------- | -------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | -| `Field.svelte` | `id`, `label`, `hint?`, слот контрола | label + раскладка поля; единая точка для hint'ов и ошибок валидации | -| `Button.svelte` | `variant: 'primary' \| 'secondary'`, `disabled`, `busy`, слот текста | глобальные `.primary`/`.secondary`, локальный busy в `DownloadButton` | -| `TextField.svelte` | `id`, `label`, `type: 'number' \| 'text'`, `min/max/step`, `value = $bindable()` | number/text ветки `ParamForm` | -| `SliderField.svelte` | `id`, `label`, `min/max/step`, `value = $bindable()`, показ значения рядом | ничего — готовая база для будущих слайдеров (яркость, качество, порог) | -| `SelectField.svelte` | `id`, `label`, `options`, `value = $bindable()` | select-ветка `ParamForm` | -| `CheckboxField.svelte` | `id`, `label`, `checked = $bindable()` | чекбокс `ParamForm` | -| `ColorField.svelte` | `id`, `label`, `value = $bindable()` | color-ветка `ParamForm`; точка будущего расширения пипеткой | -| `EmptyState.svelte` | `title`, `hint`, слот действия | «Обработка…», будущие пустые панели исходника/результата | - -`Field` — чисто раскладочная обёртка -(`
`), ничего не знает о -типе контрола. На ней построены `TextField`, `SliderField`, `SelectField`, -`ColorField`. Исключение — `CheckboxField`: у чекбокса label оборачивает контрол -(кликабельная строка), поэтому у него своя раскладка. - -## 6. Миграция существующего - -1. `ParamForm` — переписывается на `Field` + `*Field`-компоненты; собственная - стилизация контролов и label удаляется. -2. `DownloadButton` и кнопки `ToolPage` — на `Button`. -3. `DropZone`, карточки главной, строки `InfoPanel` — на `.panel` + свои - раскладочные стили. -4. `ToolPage`, главная, лейаут — приглушённые тексты на `.text-*`, заголовки - секций на `.heading-section`, баннер на `.error-banner`. -5. Из `app.css` удалить глобальные классы кнопок и голые стили инпутов после - перехода. - -## 7. Порядок работ - -| Этап | Содержимое | Проверка | -| ------------ | ----------------------------------------------------- | -------------------------------------------------------------------- | -| A. Фундамент | Токены + утилиты в `app.css` | `pnpm check` | -| B. Примитивы | Восемь компонентов в `components/ui/` | `pnpm check`; каждый используется хотя бы раз после этапа C | -| C. Миграция | Переделка пяти файлов из §6 | Визуально: страницы выглядят как раньше; `test/check/build` зелёные | -| D. Чистка | Удаление устаревших классов и дублей из scoped-стилей | grep: в `components/` нет hex-цветов и `var(--space…)` вне раскладки | - -## 8. Критерии готовности - -- Ни один компонент не задаёт цвет/радиус/шрифт мимо токенов или классов - системы. -- Все интерактивные контролы на страницах — экземпляры `ui/*`. -- `grep -E '#[0-9a-f]{3,6}' web/src/lib/components` не находит ничего, кроме - токенов в `app.css`. -- Визуальной регрессии нет (ручная сверка всех страниц до/после), тесты и билд - зелёные. - -## 9. Что сознательно не делаем - -- Никаких CSS-фреймворков и препроцессоров — обычный CSS, как решено на старте. -- Никаких тем/тёмного режима — но токены сразу семантические, чтобы тема - добавилась заменой значений `:root`. -- Никаких сложных составных компонентов (модалки, таблицы) — они появятся, когда - потребуется реальная задача. diff --git a/docs/archive/mvp-plan.md b/docs/archive/mvp-plan.md deleted file mode 100644 index 27e9d97..0000000 --- a/docs/archive/mvp-plan.md +++ /dev/null @@ -1,237 +0,0 @@ -# План начальной реализации: минимальный рабочий MVP - -> **СТАТУС: ВЫПОЛНЕН 2026-08-22.** -> -> **Что сделано по плану:** -> -> - Шаг 0 — каркас: SvelteKit + adapter-static, design-токены на CSS, лейаут с -> навигацией по категориям ✔ -> - Шаг 1 — ядро: `PixelImage`, декодирование файлов, кодирование PNG/JPEG/WebP, -> скачивание ✔ -> - Шаг 2 — операции ядра: color / geometry / alpha / analyze, чистые функции -> без DOM ✔ -> - Шаг 3 — реестр из 11 инструментов + санитизация параметров ✔ -> - Шаг 4 — универсальные UI-компоненты (DropZone, Preview, ParamForm, -> DownloadButton, InfoPanel, ToolPage) ✔ -> - Шаг 5 — маршруты: `/tools/[id]` с prerender всех страниц, главная-каталог по -> категориям ✔ -> - Шаги 6–7 — обработка ошибок, состояния, полировка; верификация ✔ -> -> **Checkpoint пройден:** все 11 инструментов вручную проверены в браузере -> (загрузка → применение → скачивание), включая найденный и исправленный баг -> resize с сохранением пропорций. Тесты 75/75, svelte-check 0 ошибок, -> статический экспорт собирается. -> -> **Попутные улучшения сверх плана:** корневой скрипт `pnpm dev`; -> `sanitizeParams` против пустых/невалидных значений полей; семантика «вписать в -> размеры» для resize. - -## 0. Зафиксированные решения - -- **Объём MVP:** только одиночные инструменты «загрузил → настроил → скачал». - Пайплайн-workspace (`/workspace`) вне скоупа этого плана. -- **Набор инструментов первого среза:** ~11 базовых EASY (см. §3). Достаточно, - чтобы проверить насквозь ядро → реестр → универсальную страницу. -- **Стили:** обычный CSS без фреймворка — design-токены на CSS custom - properties, ноль зависимостей. -- **Стек:** SvelteKit + `@sveltejs/adapter-static` + TypeScript, пакетный - менеджер pnpm (уже зафиксирован в корневом `package.json`). Весь код сайта — в - `web/`. -- **Ядро без DOM:** все пиксельные операции — чистые функции над `PixelImage`; - DOM/canvas допускается только в модуле IO и компонентах превью. - ---- - -## 1. Шаг 0 — Каркас проекта - -1. Создать SvelteKit-приложение в `web/`: `npx sv create web` (шаблон minimal, - TypeScript, без лишних аддонов). -2. `pnpm install` внутри `web/`. -3. `svelte.config.js`: заменить адаптер на `@sveltejs/adapter-static`. -4. `src/routes/+layout.ts`: `export const prerender = true;` — весь сайт - prerenderится в статику. -5. `src/app.css`: дизайн-токены (палитра, типографика, отступы, радиусы через - CSS custom properties) + минимальный сброс стилей. -6. `src/routes/+layout.svelte`: шапка с названием сайта и навигацией по - категориям инструментов (категории — константа из реестра), футер. - -**Проверка:** `pnpm dev` открывает пустой каркас; `pnpm build && pnpm preview` -отдаёт статический экспорт. - ---- - -## 2. Шаг 1 — Ядро: типы и ввод-вывод - -Файлы в `web/src/lib/core/`: - -- `types.ts` - - ```ts - export type PixelImage = { - width: number; - height: number; - data: Uint8ClampedArray; - }; // RGBA, как ImageData - ``` - -- `io.ts` — единственное место ядра, где разрешён canvas/DOM: - - `decodeFile(file: File): Promise` — `createImageBitmap(file)` → - отрисовка на canvas → `getImageData`; - - `encode(img: PixelImage, mime: 'image/png' | 'image/jpeg' | 'image/webp', quality?: number): Promise` - — `putImageData` → `canvas.toBlob`; - - `downloadBlob(blob: Blob, filename: string): void`. - -**Проверка:** юнит-смоук — декодировать фикстурный PNG, закодировать обратно, -размеры совпадают. - ---- - -## 3. Шаг 2 — Операции ядра (чистые функции) - -Файлы в `web/src/lib/core/`, каждая функция: `(img, params) => new PixelImage`, -без мутации входа: - -- `color.ts`: `grayscale(img)` (luma), `invert(img)`, - `brightnessContrast(img, brightness −100..100, contrast −100..100)`. -- `geometry.ts`: `flip(img, axis)`, `rotate90(img, turns)`, - `crop(img, x, y, w, h)` — индексная математика; `resize(img, w, h)` — - билинейная интерполяция на TS (не `drawImage`, чтобы ядро осталось DOM-free и - воспроизводимым бит-в-бит). -- `alpha.ts`: `removeColorToAlpha(img, hex, tolerancePercent)` — цветовое - расстояние → альфа 0. -- `analyze.ts`: `imageInfo(img)` → `{ width, height, hasAlpha, colorCount }`. - -**Проверка:** vitest на маленьких матрицах пикселей (2×2, 3×3): flip, rotate, -crop, grayscale — ожидаемые значения руками. - ---- - -## 4. Шаг 3 — Реестр инструментов - -`web/src/lib/registry.ts` — источник истины для страниц, форм и навигации: - -```ts -export type ParamDef = - | { - id: string; - label: string; - type: "number"; - min?: number; - max?: number; - step?: number; - default: number; - } - | { - id: string; - label: string; - type: "select"; - options: { value: string; label: string }[]; - default: string; - } - | { id: string; label: string; type: "checkbox"; default: boolean } - | { id: string; label: string; type: "color"; default: string }; - -export type ToolEntry = { - id: string; // slug маршрута - title: string; - description: string; - category: CategoryId; - params: ParamDef[]; - run: ( - img: PixelImage, - params: Record, - ) => Promise | PixelImage; -}; -``` - -Категории (константа там же): `convert`, `alpha`, `color`, `geometry`, -`analyze`. - -### Состав первого среза — 11 инструментов - -| # | id | Категория | Параметры | -| --- | -------------------------------- | --------- | ----------------------------------------------------- | -| 1 | `resize-png` | geometry | width, height, checkbox «сохранять пропорции» | -| 2 | `crop-png` | geometry | x, y, width, height | -| 3 | `rotate-png` | geometry | select: 90 / 180 / 270 | -| 4 | `flip-png` | geometry | select: horizontal / vertical | -| 5 | `grayscale-png` | color | — | -| 6 | `invert-colors-png` | color | — | -| 7 | `adjust-brightness-contrast-png` | color | brightness −100..100, contrast −100..100 | -| 8 | `convert-png-to-jpg` | convert | background color (подложка под альфу), quality 0..100 | -| 9 | `convert-png-to-webp` | convert | quality 0..100 | -| 10 | `remove-color-from-png` | alpha | hex color, tolerance % | -| 11 | `png-info` | analyze | — особый случай: не картинка, а текстовая сводка | - -Для `png-info` в записи реестра добавляется флаг `resultType: 'info'`; остальные -— `'image'`. - -**Проверка:** импорт реестра в тесте — все id уникальны, у каждого `params` -имеют дефолты, `run` определён. - ---- - -## 5. Шаг 4 — Универсальные UI-компоненты - -`web/src/lib/components/`: - -- `DropZone.svelte` — drag&drop + клик; эмитит `File`; проверка MIME - (PNG/JPEG/WebP/GIF/BMP). -- `Preview.svelte` — рендер `PixelImage` на canvas с fit-масштабированием; - шахматный фон под прозрачность. -- `ParamForm.svelte` — генерирует контролы из `ParamDef[]`, двусторонний - `bind:values`. -- `DownloadButton.svelte` — encode выбранного формата + `downloadBlob`, имя - `.`. -- `InfoPanel.svelte` — текстовый вывод для `resultType: 'info'`. -- `ToolPage.svelte` — оркестратор страницы инструмента; состояния - `idle → loaded → processing → done | error`; раскладка: слева DropZone, справа - превью + форма параметров + кнопки «Применить» / «Скачать». - -**Правило:** новый инструмент = новая запись в реестре (+ функция операции). -Компоненты и маршрут не трогаем. - ---- - -## 6. Шаг 5 — Маршруты - -- `/` (`src/routes/+page.svelte`) — сетка карточек инструментов, сгруппированных - по категориям; данные из реестра. -- `/tools/[id]` — универсальная страница: - - `+page.ts`: `entries()` возвращает все `id` из реестра (обязательное условие - prerender при adapter-static); - - `load()` возвращает запись реестра по `id`, неизвестный id → 404; - - `+page.svelte` — тонкая обёртка над `ToolPage`. - -**Проверка:** `pnpm build` — в `build/tools/` лежат все 11 страниц; главная -содержит ссылки на каждую. - ---- - -## 7. Шаг 6 — Ошибки и минимальная полировка - -- Обработка ошибок: неподдерживаемый формат, ошибка декода, некорректные - параметры crop (выход за границы — клампы или понятная ошибка). -- Состояния: «перетащите файл», спиннер во время обработки, disabled-кнопки до - загрузки. -- Тексты описаний для всех 11 инструментов (title/description уже в реестре). - ---- - -## 8. Шаг 7 — Верификация и checkpoint - -Команды: - -```bash -cd web && pnpm dev # разработка -cd web && pnpm build # статический экспорт должен проходить без ошибок -cd web && pnpm test # vitest: ядро (геометрия/цвет) + целостность реестра -``` - -Ручной smoke-тест каждого из 11 инструментов: загрузка PNG → применить → скачать -→ открыть результат. - -**Checkpoint MVP:** любой из 11 инструментов доступен по прямому URL с главной -страницы; PNG загружается drag&drop; параметры применяются; результат -скачивается; всё работает офлайн со статического хостинга; ни одной серверной -зависимости. diff --git a/docs/archive/plan-audit.md b/docs/archive/plan-audit.md deleted file mode 100644 index 0655e48..0000000 --- a/docs/archive/plan-audit.md +++ /dev/null @@ -1,213 +0,0 @@ -# План: аудит верности `preview/*` против `refs-html` (DOM → CSS) - -> **СТАТУС: РЕАЛИЗОВАН (2026-09-07) — устарел.** Скрипты -> `web/scripts/audit-dom.mjs`, `audit-css.mjs`, `audit-cdp.mjs`, -> `audit-cdp-responsive.mjs` и npm-скрипты `refs-dom-audit` / `refs-css-audit` / -> `refs-cdp-audit` на месте; старый текстовый `audit.mjs` удалён. Актуальная -> доводка верности и статус пунктов F — в `plan-design-fix.md`. - -> Статус: к выполнению. Ветка `feat/redesign`. Источник правды по пикселям: -> `refs-html/*.html` (статический экспорт рефа). Актуальный рабочий аудит сейчас -> — `pnpm refs-audit` (`scripts/audit.mjs`), но он **сломан** (см. «Почему -> текущий аудит не работает») и подлежит замене. - -## Почему текущий аудит не работает - -`scripts/audit.mjs` сопоставляет элементы **только по тексту** и берёт в -сравнение **только листовые узлы** (у которых нет детей). Контейнеры/карточки/ -панели, несущие `border-radius`, отступы и позиционирование, в сравнение -**вообще не попадают** (`byText` кладёт в мапу только элементы с непустым -`text`). Следствия: - -- разница радиусов у карточек невидима (карточка — родитель без своего текста); -- позиция кнопки (`Download result`) не ловится — это структурная разница; -- `onlyOurs / onlyRef` — это просто счётчик текстовых строк на одной стороне, - **не метрика верности**. - -Плюс он не делает пиксельного сравнения, то есть принципиально не может сказать -«выглядит по-другому». Это текстовый дифф стилей листовых текстов — и всё. - -## Решения (подтверждены автором) - -1. **Копирайт превью — через i18n `t()` с EN-базой.** Сейчас RU-литералы - хардкодом только в `preview/+page.svelte:26-27` и - `preview/list-tools/+page.svelte:31` (эти страницы не используют i18n, в - отличие от `(old)/` и компонентов `DownloadButton`/`ChainToolBlock`/…). - Заводим их через `t()` — совпадёт с рефом (EN). -2. **Имена классов НЕ сводим к рефу.** Матчинг делаем по **структурному пути**, - а не по классу. Компоненты `kit/` остаются идиоматичными, Stage 0 не - откатываем. Требуется только эквивалентность _структуры_ (теги, вложенность, - порядок сиблингов, наличие узлов, текст). -3. **Пиксельный дифф (Playwright + pixelmatch) пока НЕ делаем.** DOM+CSS-аудита - достаточно; добавим как сеть позже, если стили что-то упустят. -4. **Порядок прогона маршрутов:** `demo` → `list-tools` → затем 2 инструмента - (`tools/linear-gradient-png` ↔ `gradient.html`, `tools/remove-background-png` - ↔ `background-remover.html`). - -## Принципы - -- Никаких правок старого дизайна `(old)/` и старого `ui/`. -- Коммиты атомарные (< ~500 строк), по 1–2 компонента/скрипта; после каждого — - `lint` + `svelte-check` + `build` + соответствующий аудит (diff не должен - расти без причины). -- Коммиты делает автор (агент не коммитит). -- Шрифты уже совпадают: `design2.css:1-6` грузит IBM Plex Sans/Mono через - `@fontsource`, токены `:34-35` — `"IBM Plex Sans"/"IBM Plex Mono"` (как в рефе - `demo.html:67-68`). Пиксельный шум от шрифтов не предвидится. - -## Подход: две фазы - -Корень проблемы — нет **стабильного ключа сопоставления**. Разбиваем на две -фазы: сначала доводим DOM до структурного равенства с рефом (фаза A), затем на -стабильном DOM сравниваем стили по тому же пути (фаза B). Фаза A сама по себе -ловит именно то, из-за чего возникли претензии (кнопка не в том родителе, -лишние/недостающие обёртки, перепутанный порядок) — и без эстетических решений. - ---- - -## Фаза A — DOM/структурный аудит (`scripts/audit-dom.mjs`) - -**Цель:** Svelte рендерит структуру, идентичную `refs-html` (дерево тегов, -вложенность, порядок сиблингов, наличие узлов, текст). Имена классов могут -отличаться. - -### Нормализация узла (ключ сравнения) - -Для каждого элемента (пропускаем `SCRIPT`/`STYLE`/`NOSCRIPT` и скрытые -поддеревья, игнорируем служебное): - -- **тег** (`tagName` в lower-case); -- **классы** — как отсортированный набор (для инфо, не для матчинга); -- **нормализованный текст** — `trim`, `collapse-whitespace`, без SVG-иконок - внутри (текст иконок игнорируем); -- **порядок детей** — позиция среди сиблингов (`nth-child`). - -Матчинг — по **структурному пути** от корня сравнения: -`tag:nth-child(i) > tag:nth-child(j) …`. Не по классу и не по тексту. - -### Полное соответствие, без IGNORE - -Оболочка (наш `TopBar`/`AppShell`/`preview-footer` vs рефовый -`.topbar`/`.footer`/`.language`) тоже сводим к рефу — **IGNORE-список не -заводим**. Сравниваем всё дерево от `` (без пропуска служебного, кроме -Svelte-атрибутов и комментов гидрации), чтобы получить полное структурное -соответствие, а не только контента. Шапка/футер/переключатель языка — часть -верности; позже, после полного фикса дизайна, всё равно планируется рефакторинг -компонентов, где оболочку приведём в порядок и унифицируем. Аудит на этом этапе -просто показывает все расхождения, включая оболочечные. - -### Дифф - -Для каждого маршрута — набор дельт: - -- `added` — у нас, нет в рефе; -- `removed` — в рефе, нет у нас; -- `moved` — тот же текст/тег, другой путь (перепутанный порядок/родитель); -- `textMismatch` — нормализованный текст различается (в т.ч. RU vs EN). - -Класс-мисматч — **только информационно**, не блокирует (классы свои по решению -№2). Счётчики: `added / removed / moved / textMismatch`. - -### Рендеринг - -- **наше:** dev-сервер на `5179` (как сейчас в `audit.mjs`). -- **реф:** `pathToFileURL` к `refs-html/.html` (`file://`). Реф — - самодостаточный (инлайн `