Files
easy-png-tools2/docs/backlog.md
T

271 lines
26 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Backlog
> Статус: **active**. Открытые задачи. Подробные планы, разбор решений и сырые
> находки — `docs/plan-seo.md`, `docs/plan-platform.md`,
> `docs/plan-fields-audit-fixes.md`, `docs/tools-audit.md`, `docs/decisions.md`.
>
> Все пункты — чекбоксы; нумерация «Идея N» в тексте сквозная по документу и
> сохраняется ради перекрёстных ссылок («идея 4 зависит от идеи 3»). Оценки
> (S/M/L) — оценка труда, не приоритет.
## Pipeline
- [ ] названия инструментов — в pipeline инструмент называется «обрезать png»,
но он работает с любыми картинками, наверное надо убрать; в заголовке
страницы — возможно, надо указать все форматы (связано с SEO)
- [ ] кнопка «добавить инструмент» в pipeline — обдумать селектор с нормальным
поиском, фильтром возможных инструментов и т.д.
- [ ] посмотреть реализацию flip animation svelte для анимации переключения
режима aligned\normal
- [ ] переделать визуал toggle компонента (которым режим переключается)
- [ ] **Идея 1. Заменить инструмент шага без удаления** — оценка M. В заголовке
карточки шага кнопка «поменять инструмент»: заменяет инструмент на месте
(любой шаг, не только первый), остальные шаги и их параметры сохраняются,
вход перечитывается. Открытый вопрос: что делать с несовместимыми входами
(text-source ↔ file).
- [ ] **Идея 3. Несколько цепочек: сохранение и загрузка** — оценка M.
Именованные цепочки в localStorage (список, создать/переименовать/
удалить), быстрое переключение. Формат экспортного JSON расширить
опциональным полем имени; обратной совместимости со старыми выгрузками не
делаем — формат не устоялся: он появится вместе с фазой 11
`docs/roadmap.md` и до её старта может измениться. Плюс отдельная страница
со списком всех цепочек: удалить, переименовать, добавить новую,
«использовать» (переход на страницу инструмента с этой цепочкой). На
странице — упрощённый вид: только список инструментов цепочки, без
реального выполнения и параметров.
- [ ] **Идея 4. Batch-обработка архивов выбранным chain** — оценка L. Вход —
zip-архив картинок (распаковка в браузере), прогон текущего или выбранного
сохранённого chain по каждому файлу, сборка результата обратно в zip для
скачивания. Зависит от идеи 3 (выбор цепочки) и от экспортного формата
pipeline JSON; прогресс и ошибки — пофайлово.
- [ ] **Идея 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 по `page.slug`,
`SchemaToolView.download()`); - обратная сторона: распаковка zip в
браузере, порядок файлов, поведение many → 1 → many в одной цепочке.
Зависит от идеи 10 (остальные потребители 1 → many) и идеи 4 (batch по
архиву), `docs/roadmap.md` фаза 8 «batch-страница».
## Инструменты
- [ ] remove-alpha-channel - дубль инструмента с выбором цвета на замену, что с
такими делать вообще? оставить как seo? можно ли под капотом использовать
другой инструмент с хардкодед настройками?
- [ ] qr code to text, text to qr code
- [ ] bar code to text, text to bar code
- [ ] нужен инструмент для удаления фона по выбранной точке - удалять внутри
выделенной области
- [ ] сделать конвертацию в смайлики\награды для твитча (6 размеров или выбор
какой размер - 112\56\28px или 72\36\18)
- [ ] сделать несколько проходное сжатие png для получения необходимого размера
файлов, посмотреть реализацию в
[twitch-emote-resizer](https://github.com/tma02/twitch-emote-resizer)
- [ ] Font Style - обдумать выбор шрифта (google fonts???) как организовать
шрифты с кириллицей? сделать галочку "только с кириллицей"??? (решение о
наборе и лицензиях: `docs/plan-platform.md` §4 — только OFL/Apache с
паспортом, семейства с кириллицей)
- [ ] Свести convert-страницы (`convert-png-to-jpg`, `convert-png-to-webp`,
`png-to-bmp`) на один инструмент `convert` — зависит от S1f
(`docs/plan-seo.md` §4). Мешает не только `quality` (он живёт в схеме
инструмента), а сама модель: `output` с mime/ext — свойство `Tool`, а
`PageStep` умеет только `{ id, params? }`, поэтому страницы на общий `id`
получат одинаковый формат вывода. Нужно научить шаг переопределять формат
вывода
- [ ] **Идея 6. Конвертация формата — НЕ отдельный инструмент, а выбор в кнопке
Download** — оценка M/L. Решение и продуктовое обоснование:
`docs/plan-seo.md` §0 и задача **S1f**; почему селектор не заменяет
существующие convert-страницы — `docs/plan-seo.md` §5. Механическая часть
уже есть: `Tool.output` (`OutputFormat`: mime/ext/qualityParamId) и
кодирование по нему в `SchemaToolView.download()` —
`docs/architecture.md`, раздел 3. Что осталось сверх S1f: - экспорт с
лимитом размера → «сжатие до целевого КБ»: для lossy это quality в
селекторе формата, для PNG — бинарный поиск по k из квантования. Нужна ли
отдельная страница под этот интент — открытый вопрос с вордстатом, имя не
выбрано (`docs/plan-seo.md` §5). Проработать вместе с достройкой
download-флоу.
- [ ] **Идея 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) если надо
изменить теги, никакого форматирования и изменения в изображение вносить
не надо, только в метаинформацию.
- [ ] **Идея 9. Region-инструменты** (censor/erase/pixelate-area/blur-area/
sharpen-area/reverse-area) — ждут UI выделения области на превью. Вне
очереди.
- [ ] **Идея 10. Мультифайловые инструменты-потребители** (gif-to-frames,
separate-colors) — механизм «результат = набор файлов» (1 → many) уже есть
(`docs/architecture.md`, раздел 7), первый потребитель —
`split-into-parts-png`. Остальные подключаются по мере нужды.
- [ ] **Идея 11. Анимационные** (slow-reveal/fade/scrolling) — выход не PNG;
отдельное решение о формате.
- [ ] **Идея 12. HARD-серия** (glitch, barcode, signature-extract,
handwritten-digital).
- [ ] **Идея 14. Отображение маски для инструментов (`runMask`)** — придумать и
реализовать процесс показа маски результата. **Контекст:** удалённый UI-v1
умел показывать ч/б превью-маску «что будет вырезано» отдельным полем; при
переходе на единый `run(ctx)` этого поля не осталось — executor и
schema-превью зовут `run()` напрямую, маска не возвращается. **Идея 1:**
дать каждому `run` возможность вернуть (или инструмент — объявить)
`runMask` — ч/б изображение маски изменений либо иной подход (отдельное
поле `mask` + функция маски, второй результат, overlay). Оценка — на
усмотрение при проработке (S/M). Пока живём без неё. **Идея 2:** каждый
`run` возвращает два изображения — для отображения (показывает маску или
сам результат) и для передачи в следующий инструмент (всегда результат).
Оценка — на усмотрение при проработке (S/M). Пока живём без неё. Первые
кандидаты на маску: `remove-color-from-png`, `remove-background-png`.
## UI и качество
- [ ] split to parts - посмотреть вариант с toggle component - может будет
удобнее чем sectioned buttons
- [ ] неудобно настраивать ползунками, некоторые инструменты удобнее настроить
через drag-n-drop. звучит сложно, но надо придумать процесс
- [ ] fav: текущий ui слишком дерганный — при клике на звёздочку элементы
мгновенно пересортировываются и под мышкой оказывается другой элемент.
Нужна или анимация, или механизм отложенного обновления позиций
- [ ] просмотр картинки в оригинальном размере, и возможно с зумом отдельных
областей, чтобы просмотреть мелкие артефакты, выбор разных подложек -
черная\белая\цветные\серая для проверки прозрачных картинок
- [ ] обдумать объединение пар `inputMode + source` и `resultKind + result` в
единую структуру, позволит упростить некоторые вещи - например
`sourceValue` \ `resultValue` в `SchemaPreview.svelte`
- [ ] Рассмотреть необходимость всех этих пропсов в `SchemaPreview.svelte` они
дублируют друг друга `ontextsource`, `onrendertext`, `oncopytext`,
`ondownloadtxt`, `ondownload`,
- [ ] resize keep aspect - работает, но немного не очевидное поведение при
прямоугольной картинке и выборе размера через быстрые кнопки (например
256х256). Воспроизведение поведения: keep aspect включено, загружаем
прямоугольную картинку 832 × 1232, картинка рескейлится до 173 × 256,
выключаем keep aspect, картинка рескейлится до 256 × 256 (с искажением
пропорций), включаем keep aspect - картинка рескейлится до размера 256 ×
379
- [ ] Переделать внешний вид инструментов без настроек, например Remove alpha
channel PNG "remove-alpha-channel-png". Сейчас выглядит слишком пустым.
- [ ] Пересмотреть поля - Plate, Position, Font Style - сейчас второй label
- [ ] поле ввода текста - сделать по умолчанию нормального размера, а не одну
строку для svg - форматирование или подсветку синтаксиса??? для bin\hex -
форматирование по колонкам??? для hex\bytes\rgba - пример в placeholder
- [ ] прикрутить кастомный color picker, добавить прозрачность (range?)
- [ ] обновить страницу kit или сделать storybook
- [ ] `PreviewTile`: высота плитки задана только `min-height: clamp(...)`,
поэтому она не следует за пропорциями результата — широкий результат
уезжает в узкую полосу, а высокий упирается в `max-height: 100vh`. Нужно,
чтобы соотношение сторон выбиралось по результату в диапазоне 16:9…9:16
(`web/src/lib/components/schema/PreviewTile.svelte`).
- [ ] Радиусы бордеров: `--radius-m` ненулевой и применён ко всем бордерам
(`app.css`, `SchemaToolView.svelte`). Решить, где скругления реально есть
в дизайне, а где должен быть 0
- [ ] Component-тесты `SchemaToolView`/`SchemaPreview` требуют отдельного
решения: node Vitest не имеет DOM/canvas, а e2e уже покрывает поведение.
- [ ] **Идея 13. Контраст текста на акцентных кнопках — частично закрыт**. Тона
`--color-main`/`--color-accent` подняты под текущий порог
`palette.test.ts`; targeted-тест проходит. Light-тема всё ещё ниже AA 4.5
для обычного текста, а `--color-danger` в light-теме на границе: после
завершения редизайна вернуть порог 4.5 и перепроверить оба токена.
- [ ] **Идея 16. Главная должна отличаться от каталога** — оценка S. Сейчас
`src/routes/+page.svelte` и `src/routes/list-tools/+page.svelte` побайтово
идентичны (совпадают script, шаблон и стили), при этом `/list-tools` —
рабочий маршрут: на него ссылается крошка в `+layout.svelte` и он открыт
e2e-сценариями `catalog.spec.ts`, `i18n.spec.ts`, `navigation.spec.ts`.
Замысел: главная — крупнее и с более простым поиском, без категорий;
каталог остаётся группировкой с фильтрами. Детектор дублирования разметки
сознательно не вводим — `docs/decisions.md`, раздел 1, поэтому расхождение
ловится на ревью.
## Тесты и lint
- [ ] `tseslint.config(...)` deprecated: сигнатура
`(...configs: InfiniteDepthConfigWithExtends[]): ConfigArray` помечена
устаревшей, нужен переход на `defineConfig` из `eslint/config` (ESLint
core, а не `typescript-eslint`) — `web/eslint.config.js`.
- [ ] удалить мёртвые `tools.*.params` из root i18n после проверки потребителей;
до этого действует pattern-based policy-исключение
(`web/eslint-plugins/README.md`, раздел `dict-consistency`)
- [ ] e2e: `i18n.spec.ts` и `text-and-verdicts.spec.ts` дублируют локаторы из
`helpers/page.ts` вместо вызова — правило «спека зовёт helpers»
(`docs/testing-strategy.md`, раздел 5)
- [ ] Пересмотреть тесты — убрать точные совпадения текстов и любые селекторы,
привязанные к разметке или svelte-классам (сейчас остались:
`tool-flows.spec.ts`, `schema-tool-strings.test.ts`)
- [ ] можно ли в тестах получать i18n ключ вместо текста? можно ли написать lint
правило такое (запретить toContain без i18n)
- [ ] чистка под новые конвенции комментариев и тестов: правила
`conventions/ascii-only` (тесты — ASCII), `conventions/comments-english`
(комментарии — английский), `conventions/comment-format` (≤5 строк на
блок, ≤15% файла) уже работают в warn-режиме, но в `lint:all` отключены
через override в `web/scripts/lint-all.mjs` (baseline ≠ 0). Критерий
закрытия: ноль срабатываний по всем трём правилам, overrides удалены,
правила переведены с warn на error
- [ ] убрать в тестах все нестандартные символы `→`, длинные тире, русский язык
и т.д. — часть чистки под `conventions/ascii-only` (см. выше)
- [ ] комментарии на английском — часть чистки под
`conventions/comments-english` (см. выше)
## SEO/GEO
- [ ] переименование бренда + домен: чек-лист в локальном файле
`plan-domain.local.md` (в git не входит, в клоне отсутствует; подробности
и порядок — `docs/plan-seo.md` §6, R1/R2)
- [ ] снять `noindex` со страниц инструментов, когда будут sitemap, canonical и
контент (S1h; блокирует индексацию всего сайта) — `docs/plan-seo.md` §4
- [ ] форматные страницы по конкурентным слагам (`crop-jpeg`, …) — только по
вордстату с уникальным контентом; редиректы только для опечаток и
переименований уже опубликованных страниц; клонов с canonical не делать
(`docs/plan-seo.md` §5)
- [ ] sitemap.xml из реестра + `Sitemap:` в robots.txt (S1b/S1c)
- [ ] Seo.svelte: per-tool OG-картинки (S1e) — у каждой страницы инструмента
своя превью-карточка 1200×630 для соцсетей/мессенджеров: имя инструмента,
бренд, иконка. Сейчас все страницы ссылаются на общую
`static/og/default.png` (генерирует `pnpm --dir web gen:og` —
Playwright-скриншот HTML-карточки в `web/scripts/gen-og.mjs`). Что делать:
расширить gen-og.mjs — проход по реестру страниц, карточка с названием
инструмента в `static/og/[slug].png`, в `Seo.svelte` подставлять og-URL по
slug страницы. Критерий приёмки: у `/tools/flip-png` в og:image своя
картинка с названием инструмента, файл лежит в `static/og/`
- [ ] контент страницы инструмента: seo-блок в словарях, how-to/FAQ/related (S2)
- [ ] JSON-LD (SoftwareApplication/FAQPage/Breadcrumb) + llms.txt (S3)
- [ ] дистрибуция: закрепить репо, alternative.to, Product Hunt, Reddit/HN (S4c)
- [ ] GSC: подключить домен, отправить sitemap, мониторинг индексации (S4a)
- [ ] GA4: cookieless-конфигурация, отключить рекламные audiences и signals,
`anonymize_ip` — сейчас в `web/src/routes/+layout.svelte` голый
`gtag('config')` (S4b)
## Платформа (API/PWA)
- [ ] Vercel: переезд хостинга с GitHub Pages + глобальная статистика
популярности инструментов через Vercel KV (serverless-функция: INCR при
открытии инструмента, чтение топа для скоринга поиска).
- [ ] PWA: manifest + service worker, оффлайн-режим, установка (после S1)
- [ ] API: спайк серверного ядра (нативный Rust vs edge-wasm), ключи, free tier
(после wasm-фаз 5–7)
- [ ] Шрифты: лицензирование (F1–F4) и DOM-free рендер (F5–F6) — до фазы 8
(`docs/plan-platform.md` §4)
## Переезд
- [ ] множественные числа (часть/части/частей; «N параметров», счётчики) —
функция `tPlural(path, n)` и форма `PluralForms` (обязательное `other`,
опциональные `one`/`few`/`many`); первые потребители — `part`/`parts` в
подписи результата и счётчики параметров. **Критерий приёмки:** у ключа с
plurals есть все формы, для которых нужен перевод, `other` никогда не
пустой, число подставляется в текст без склейки