mirror of
https://github.com/Ku6epXBOCTuK/easy-png-tools.git
synced 2026-11-13 17:08:20 +00:00
docs: update a lot of plans, readmes, descriptions
This commit is contained in:
+77
-99
@@ -1,22 +1,30 @@
|
||||
# Backlog
|
||||
|
||||
> Статус: **active**. Продуктовые, UX- и инфраструктурные задачи. Здесь только
|
||||
> **открытые** задачи: выполненные удаляются, а критичные для проекта факты из
|
||||
> них переносятся в тематический документ (архитектура, quality gates, lint,
|
||||
> e2e) по мере закрытия.
|
||||
>
|
||||
> «Что сознательно не вводим и почему» живёт в `docs/decisions.md`, архитектура
|
||||
> — в `docs/architecture.md`. Raw-находки UX-аудита — `docs/tools-audit.md`, их
|
||||
> разбивка на волны — `docs/plan-fields-audit-fixes.md`.
|
||||
>
|
||||
> Ids инструментов сверять с `web/src/lib/registry/`; полный список —
|
||||
> `docs/tools-map.md`.
|
||||
|
||||
## lint и прочие правила
|
||||
|
||||
- [x] Кросс-языковой линтер словарей (warn-only: паритет ключей, пустые
|
||||
значения, совпадение `{placeholder}`-переменных между всеми локалями) —
|
||||
правило `i18n/dict-consistency`, детали в `web/eslint-plugins/README.md`.
|
||||
Правило реализовано; Q2 перевёл i18n baseline к zero-warning через
|
||||
policy-aware fallback.
|
||||
- [x] Проверка текстов в svelte/ts/html — реализовано правилом
|
||||
`i18n/no-hardcoded-user-text` (warn, baseline 0): ловит текст в шаблоне и
|
||||
в пользовательских атрибутах, исключения — бренд, форматы, имена файлов,
|
||||
registry-строки и `/kit`. Детали в `web/eslint-plugins/README.md`.
|
||||
- [ ] расширить `i18n/no-hardcoded-user-text` на `web/src/routes/**`: сейчас
|
||||
правило навешено только на `components/**` (без `/kit`), поэтому
|
||||
захардкоженный текст в `routes/**` проходит молча (`web/eslint.config.js`,
|
||||
`web/eslint-plugins/README.md`)
|
||||
- [ ] `tseslint.config(...)` deprecated: сигнатура
|
||||
`(...configs: InfiniteDepthConfigWithExtends[]): ConfigArray` помечена
|
||||
устаревшей, нужен переход на `defineConfig` из `typescript-eslint` —
|
||||
`web/eslint.config.js`.
|
||||
- [ ] удалить мёртвые `tools.*.params` из root i18n после проверки потребителей;
|
||||
до этого Q2 держит pattern-based policy-исключение
|
||||
до этого действует pattern-based policy-исключение
|
||||
(`web/eslint-plugins/README.md`, раздел `dict-consistency`)
|
||||
|
||||
## Мелочи всякие
|
||||
|
||||
@@ -90,14 +98,13 @@
|
||||
|
||||
## Переезд
|
||||
|
||||
- [x] добавить i18n в preview
|
||||
- [ ] множественные числа (часть/части/частей; «N параметров», счётчики) —
|
||||
`tPlural()` и формат `PluralForms`; детали и критерии — в этом backlog
|
||||
|
||||
## SEO/GEO
|
||||
|
||||
Общий план: `docs/plan-seo.md` (S0–S4). C17 выполнен; старт возможен — пока
|
||||
только domain-free часть S1.
|
||||
Общий план: `docs/plan-seo.md` (S0–S4). Переезд preview на реальные маршруты
|
||||
выполнен; старт возможен — пока только domain-free часть S1.
|
||||
|
||||
- [ ] переименование бренда + домен: чек-лист в локальном плане
|
||||
`docs/plan-domain.local.md` (вне git, имя домена в репо не публикуется;
|
||||
@@ -125,38 +132,12 @@
|
||||
|
||||
## Качество production UI
|
||||
|
||||
Q5–Q6 и Q7–Q8 закрывают известные preview-проблемы, special fixtures, smoke,
|
||||
layout/view-model инварианты, browser matrix, coverage-гейт и линтеры; активных
|
||||
`test.fixme` в e2e больше нет.
|
||||
Политика проверок — `docs/quality-gates.md`, e2e — `docs/testing-strategy.md`.
|
||||
|
||||
- [x] Генераторы auto-run без кнопки Generate — `web/e2e/generators.spec.ts`.
|
||||
- [x] `resize-png` и `crop-png` используют размеры текущего source через общий
|
||||
source-aware schema resolver — `web/e2e/pipeline.spec.ts`.
|
||||
- [x] Reset сохраняет source/text, восстанавливает defaults и запускает deferred
|
||||
auto-run — `web/e2e/pipeline.spec.ts`.
|
||||
- [x] Ошибки хранят i18n key/vars и переводятся при выводе; изменение языка
|
||||
обновляет alert — `web/e2e/i18n.spec.ts`.
|
||||
- [x] Malformed/special PNG fixtures: CRC, truncated, palette и 16-bit проходят
|
||||
через upload без краша — `web/e2e/png-fixtures.spec.ts`.
|
||||
- [x] Registry-wide smoke покрывает все 122 инструмента по input/result-типу —
|
||||
`web/e2e/tools-smoke.spec.ts`, `generators.spec.ts`,
|
||||
`text-and-verdicts.spec.ts`.
|
||||
- [x] Layout-группировка вынесена в `resolveLayoutGroups` и покрыта
|
||||
unit-тестами; `SchemaFields.svelte` использует общий seam.
|
||||
- [x] `SchemaPreview` view-model вынесена в `buildSchemaPreviewModel` и покрыта
|
||||
unit-тестами для всех input/result-типов.
|
||||
- [x] Browser matrix: полный Chromium, Firefox/WebKit для browser-critical
|
||||
спецификаций и mobile Chromium 390×844 — `web/playwright.config.ts`.
|
||||
- [x] Расхождение декодеров зафиксировано как ожидаемое поведение: Firefox и
|
||||
WebKit декодируют `truncated-no-iend` и `idat-cut`, а WebKit ещё и
|
||||
`crc-bad-idat`. Таблица движков живёт в `web/e2e/png-fixtures.spec.ts`,
|
||||
продукт не ужесточается, и любая выгрузка битого файла обязана давать
|
||||
alert, а не падение или «пустой» результат.
|
||||
- [ ] Component-тесты `SchemaToolView`/`SchemaPreview` требуют отдельного
|
||||
решения: node Vitest не имеет DOM/canvas, а e2e уже покрывает поведение.
|
||||
- [ ] Ошибка декодирования изображения из `createImageBitmap` пока показывается
|
||||
сырым сообщением браузера; нужен `ToolError`-маппер и i18n-ключ. Это
|
||||
продуктовая задача, не Q6d.
|
||||
сырым сообщением браузера; нужен `ToolError`-маппер и i18n-ключ.
|
||||
|
||||
## Идеи
|
||||
|
||||
@@ -178,7 +159,7 @@ layout/view-model инварианты, browser matrix, coverage-гейт и л
|
||||
4. **Batch-обработка архивов выбранным chain** — оценка L. Вход — zip-архив
|
||||
картинок (распаковка в браузере), прогон текущего или выбранного сохранённого
|
||||
chain по каждому файлу, сборка результата обратно в zip для скачивания.
|
||||
Зависит от п.4 (выбор цепочки) и от экспортного формата pipeline JSON;
|
||||
Зависит от идеи 3 (выбор цепочки) и от экспортного формата pipeline JSON;
|
||||
прогресс и ошибки — пофайлово.
|
||||
|
||||
5. **Избранные инструменты (fav tools)** — оценка S/M. Тоггл-звёздочка на
|
||||
@@ -188,59 +169,48 @@ layout/view-model инварианты, browser matrix, coverage-гейт и л
|
||||
|
||||
6. **Конвертация формата — НЕ отдельный инструмент, а выбор в кнопке Download**
|
||||
— оценка M/L. Инструменты `convert-png-to-jpg` / `convert-png-to-webp` (и др.
|
||||
форматы) не должны жить как самостоятельные инструменты цепочки. Вместо этого
|
||||
— бесшовное внедрение выбора формата/качества прямо в кнопку/диалог
|
||||
**Download**: юзер скачивает результат в нужном формате (mime/ext/quality), а
|
||||
pipeline при этом не усложняется лишним звеном. **Сделано (2026-09):**
|
||||
механическая часть реализована в preview — `ToolEntry.output`
|
||||
(`OutputFormat`: mime/ext/qualityParamId) в `web/src/lib/registry/types.ts`;
|
||||
`SchemaToolView.download()` кодирует по `output` (jpg/webp/bmp уже настроены;
|
||||
`png-to-bmp` переведён сюда же). Q6c покрывает этот фиксированный контракт
|
||||
unit/E2E-проверками; переключатель форматов и quality остаётся отдельным
|
||||
UX-райзом. **Осталось (UX-райз «Download»):**
|
||||
форматы) не должны жить как самостоятельные инструменты цепочки. Механическая
|
||||
часть уже есть: `ToolEntry.output` (`OutputFormat`: mime/ext/qualityParamId)
|
||||
и кодирование по нему в `SchemaToolView.download()` — `docs/architecture.md`,
|
||||
раздел 3. Осталось (UX-райз «Download»):
|
||||
- выбор формата/качества прямо в кнопке/диалоге Download для любого
|
||||
результата (не отдельными конвертерами);
|
||||
- экспорт с лимитом размера → закрывает отложенный `reduce-to-size-png`
|
||||
(целевой KB, бинарный поиск по k из квантования). Проработать вместе с
|
||||
достройкой download-флоу нового UI.
|
||||
|
||||
7. **`watermark-image-png` (водяной знак картинкой)** — оценка M. Отложен из
|
||||
миграции (`archive/plan-migrate-remaining.md`). Нужна overlay-механика:
|
||||
второй источник изображения (getOverlay/store), параметры scale/opacity/
|
||||
position/margin/aspect. Решается вместе с вопросом, как второй источник
|
||||
картинки вписывается в schema-driven preview (`SchemaToolView`).
|
||||
7. **`watermark-image-png` (водяной знак картинкой)** — оценка M. Нужна
|
||||
overlay-механика: второй источник изображения (getOverlay/store), параметры
|
||||
scale/opacity/position/margin/aspect. Решается вместе с вопросом, как второй
|
||||
источник картинки вписывается в schema-driven preview (`SchemaToolView`).
|
||||
|
||||
8. **`png-info` (детальная информация о PNG)** — оценка M/L. Отложен из
|
||||
миграции. Отдельный райз: exif-теги, редактирование, структурированный вывод;
|
||||
нужен свой отдельный случай в UI, не «ещё один text/verdict». возможно нужна
|
||||
вообще отдельная страница, несовместимая с другими инструментами: 1) она
|
||||
работает не с изображением, а с мета данными из файла, 2) она не может быть
|
||||
частью цепочки, т.к. результат не является изображением, 3) если надо
|
||||
изменить теги, никакого форматирования и изменения в изображение вносить не
|
||||
надо, только в мета информацияю
|
||||
8. **`png-info` (детальная информация о PNG)** — оценка M/L. Отдельный райз:
|
||||
exif-теги, редактирование, структурированный вывод; нужен свой отдельный
|
||||
случай в UI, не «ещё один text/verdict». Возможно нужна вообще отдельная
|
||||
страница, несовместимая с другими инструментами: 1) она работает не с
|
||||
изображением, а с метаданными из файла, 2) она не может быть частью цепочки,
|
||||
т.к. результат не является изображением, 3) если надо изменить теги, никакого
|
||||
форматирования и изменения в изображение вносить не надо, только в
|
||||
метаинформацию.
|
||||
|
||||
9. **Region-инструменты** (censor/erase/pixelate-area/blur-area/sharpen-area/
|
||||
reverse-area) — ждут UI выделения области на превью. Из
|
||||
`archive/plan-gap-waves.md` («вне очереди»).
|
||||
reverse-area) — ждут UI выделения области на превью. Вне очереди.
|
||||
|
||||
10. **Мультифайловые инструменты-потребители** (gif-to-frames, separate-colors)
|
||||
— механизм «результат = набор файлов» (1 → many) реализован: `FileResult` +
|
||||
`result: "files"` + скачивание zip-архивом + грид-превью частей. Первый
|
||||
потребитель — `split-into-parts-png`. Остальные подключаются по мере нужды.
|
||||
— механизм «результат = набор файлов» (1 → many) уже есть
|
||||
(`docs/architecture.md`, раздел 7), первый потребитель —
|
||||
`split-into-parts-png`. Остальные подключаются по мере нужды.
|
||||
|
||||
11. **Анимационные** (slow-reveal/fade/scrolling) — выход не PNG; отдельное
|
||||
решение о формате. Из `archive/plan-gap-waves.md`.
|
||||
решение о формате.
|
||||
|
||||
12. **HARD-серия** (glitch, barcode, signature-extract, handwritten-digital). Из
|
||||
`archive/plan-gap-waves.md`.
|
||||
12. **HARD-серия** (glitch, barcode, signature-extract, handwritten-digital).
|
||||
|
||||
13. **Контраст текста на акцентных кнопках — частично закрыт**. Для dark-темы
|
||||
`--color-main`/`--color-accent` подняты до tone 56, чтобы пройти текущий
|
||||
порог `palette.test.ts` 4.0; targeted-тест проходит. Light-тема сохраняет
|
||||
контраст ~4.1–4.3, что ниже AA 4.5 для обычного текста, поэтому после
|
||||
завершения редизайна нужно повторно поднять тона и вернуть порог 4.5. Также
|
||||
проверить `--color-danger` (dark, тон 55): текст на нём 4.93 — ок, но
|
||||
light-danger tone 48 = 4.25 на границе.
|
||||
13. **Контраст текста на акцентных кнопках — частично закрыт**. Тона
|
||||
`--color-main`/`--color-accent` подняты под текущий порог `palette.test.ts`;
|
||||
targeted-тест проходит. Light-тема всё ещё ниже AA 4.5 для обычного текста,
|
||||
а `--color-danger` в light-теме на границе: после завершения редизайна
|
||||
вернуть порог 4.5 и перепроверить оба токена.
|
||||
|
||||
14. **Отображение маски для инструментов (runMask/preview-mask)** — придумать и
|
||||
реализовать процесс показа маски результата. **Контекст:** в старом
|
||||
@@ -252,25 +222,32 @@ layout/view-model инварианты, browser matrix, coverage-гейт и л
|
||||
возможность вернуть (или инструмент — объявить) `runMask` — ч/б изображение
|
||||
маски изменений либо иной подход (отдельное поле `mask` + функция маски,
|
||||
второй результат, overlay). Оценка — на усмотрение при проработке (S/M).
|
||||
Пока живём без неё. **Идея 2:** каждый `run` возвращает два изображения -
|
||||
для отображения (показывает маску или сам результат), и для передачи в
|
||||
следующий инструмент (всегда результат. Оценка — на усмотрение при
|
||||
Пока живём без неё. **Идея 2:** каждый `run` возвращает два изображения —
|
||||
для отображения (показывает маску или сам результат) и для передачи в
|
||||
следующий инструмент (всегда результат). Оценка — на усмотрение при
|
||||
проработке (S/M). Пока живём без неё.
|
||||
|
||||
15. **Процесс работы с инструментами 1 → many и many → 1** — абстракция
|
||||
результата «набор файлов» оформлена и работает: тип `FileResult`,
|
||||
`result: "files"` в реестре, сериализация через executor, скачивание
|
||||
zip-архивом, грид-превью частей. Реализовано на первом потребителе
|
||||
`split-into-parts-png` (2026-09, `docs/archive/plan-split-into-parts.md`).
|
||||
Q6b закрывает контракт ZIP/download: unit-тесты `web/src/lib/zip.test.ts` и
|
||||
browser-сценарий `web/e2e/pipeline.spec.ts` проверяют имена частей и
|
||||
содержимое архива. **1 → many:** подключение остальных потребителей
|
||||
(gif-to-frames, separate-colors) при необходимости; формат/качество файлов
|
||||
внутри zip — отложено до UX-райза «Download» (п.7). **many → 1** (вход =
|
||||
архив/несколько картинок → единый результат): не реализовано. Зависит от
|
||||
batch-обработки архивов (п.5 идей, roadmap фаза 8 «batch-страница»). Нужна
|
||||
отдельная проработка входа (распаковка zip в браузере, порядок файлов,
|
||||
поведение в пайплайне — такие инструменты терминальны, как и 1 → many).
|
||||
15. **Набор файлов в пайплайне: 1 → many не должен быть терминальным** — оценка
|
||||
L. **Сейчас** `execute` принимает один `source: PixelImage | undefined` и
|
||||
возвращает один `ToolResult`, а `SchemaToolView` раскладывает вывод в
|
||||
`result` / `fileResult` / `textResult` по `resultKind` — поэтому шаг с
|
||||
`result: "files"` упирается в конец цепочки. **Направление:** следующий
|
||||
инструмент применяется **ко всем картинкам** предыдущего результата
|
||||
(fan-out), а many → 1 (вход = архив или несколько файлов) — обратная сторона
|
||||
того же контракта. Терминальными остаются только результаты, которые не
|
||||
картинка (text, verdict). Что обдумать:
|
||||
- где проходит граница: один вызов `run(ctx)` на файл (имя части склеивается
|
||||
в `FileResult.files`) или батч целиком на стороне исполнителя;
|
||||
`executor/protocol.ts` `files` уже сериализуются, но при батче нужен
|
||||
прогресс и отмена;
|
||||
- частичные ошибки: один битый файл не должен ронять весь шаг — нужен
|
||||
per-file отчёт, а не один `ToolError` на шаг;
|
||||
- имена частей на каждом шаге и Download для набора (сейчас zip по
|
||||
`tool.id`, `SchemaToolView.download()`);
|
||||
- обратная сторона: распаковка zip в браузере, порядок файлов, поведение
|
||||
many → 1 → many в одной цепочке. Зависит от идеи 10 (остальные потребители
|
||||
1 → many) и идеи 4 (batch по архиву), `docs/roadmap.md` фаза 8
|
||||
«batch-страница».
|
||||
|
||||
16. **Главная должна отличаться от каталога** — оценка S. Сейчас
|
||||
`src/routes/+page.svelte` и `src/routes/list-tools/+page.svelte` побайтово
|
||||
@@ -278,5 +255,6 @@ layout/view-model инварианты, browser matrix, coverage-гейт и л
|
||||
рабочий маршрут: на него ссылается крошка в `+layout.svelte` и он открыт
|
||||
e2e-сценариями `catalog.spec.ts`, `i18n.spec.ts`, `navigation.spec.ts`.
|
||||
Замысел: главная — крупнее и с более простым поиском, без категорий; каталог
|
||||
остаётся группировкой с фильтрами. Найдено измерением дублирования разметки
|
||||
по 65 `.svelte`-файлам: файлы побайтово идентичны.
|
||||
остаётся группировкой с фильтрами. Детектор дублирования разметки
|
||||
сознательно не вводим — `docs/decisions.md`, раздел 1, поэтому расхождение
|
||||
ловится на ревью.
|
||||
|
||||
Reference in New Issue
Block a user