mirror of
https://github.com/Ku6epXBOCTuK/easy-png-tools.git
synced 2026-11-13 17:08:20 +00:00
513 lines
47 KiB
Markdown
513 lines
47 KiB
Markdown
# План: SEO + GEO — индексация и конкуренция в image tools
|
||
|
||
> **Статус: active.** Адреса страниц инструментов — `/tools/<slug>` (`crop-png`
|
||
> и подобные), каталог — `/list-tools`; реестр двухслойный: страница `slug`
|
||
> ссылается на инструмент по `id` (`docs/architecture.md`, раздел 3).
|
||
>
|
||
> **`noindex, nofollow` выставлен на каждой странице инструмента**
|
||
> (`web/src/routes/tools/[slug]/+page.svelte`) — осознанно, до появления
|
||
> уникального контента (S2). Пока он стоит, сайт не индексируется вообще, и
|
||
> **S1b–S1e (sitemap, `robots.txt` с `Sitemap:`, canonical, OG) не дают
|
||
> эффекта**: их имеет смысл делать вместе со снятием `noindex`, а не вместо
|
||
> него. Условие снятия и порядок — §4, S1.
|
||
>
|
||
> **Цель:** страница каждого инструмента — индексируемый лендинг под конкретный
|
||
> интент («crop png», «make png transparent», «jpg to png»…) плюс попадание в
|
||
> ответы генеративных систем (ChatGPT, Perplexity, AI Overviews) — GEO.
|
||
>
|
||
> **Позиционирование:** не «PNG-инструменты», а **image tools с PNG-ядром** —
|
||
> любой инструмент принимает PNG/JPG/WebP/GIF/BMP и отдаёт результат в
|
||
> PNG/JPG/WebP/BMP через селектор в кнопке Download. Дифференциатор —
|
||
> прозрачность/альфа/фон и no-upload-приватность. Референс-конкурент по ядру —
|
||
> onlinepngtools.com (§2). Долгосрочно ядро переезжает на wasm и обрастает API +
|
||
> PWA (`docs/plan-platform.md`); для SEO это аргументы дистрибуции и GEO-факты,
|
||
> схему сайта они не меняют.
|
||
>
|
||
> **Слаги в этом документе:** `jpg-to-png`, `crop-jpeg` и подобное — интенты и
|
||
> URL конкурента, а не наши страницы. Наши страницы — в `docs/tools-map.md`
|
||
> (карта перечисляет `slug`, не `id`); в тексте ниже названия инструментов
|
||
> приводятся по этим слагам, потому что для SEO важны адреса.
|
||
|
||
## 0. Решения
|
||
|
||
- **Бренд: `easy-image-tools`, домен `easy-image-tools.com`.** Переименование до
|
||
индексации выполнено (R1): хардкод убран, точка истины — константа `brand` в
|
||
i18n + README (хардкод в компонентах недопустим). Домен зарегистрирован
|
||
2026-10-11 (R2); остался перевод прода на него (DNS, HTTPS, снятие
|
||
`BASE_PATH`, `PUBLIC_SITE_ORIGIN`, 301 со старого GitHub Pages) — теперь это
|
||
блокер S1-domain (§4). Легенда честная: «started as PNG tools, now all
|
||
formats» — это контент-плюс, а не баг. Адреса страниц (`/tools/crop-png`) и
|
||
localStorage-ключи не переименовывать (localStorage-ключи бренда не содержат).
|
||
- **Форматы: формат = выбор в UI, не отдельные страницы.** Download-кнопка
|
||
каждого инструмента — с селектором PNG/JPG/WebP/BMP (+quality для lossy). Райз
|
||
«выбор формата/качества в Download» вытащен из backlog №7 в S1f: механика уже
|
||
есть (`Tool.output`), нужна как продуктовая основа «image
|
||
tools»-позиционирования. В направлении «из формата в PNG» отдельных
|
||
инструментов нет (загрузка принимает любой формат) — см. §5.
|
||
- **Адреса страниц `-png` сохраняются, внутренние имена — без.** Инструмент
|
||
работает с любым форматом, поэтому его `id` не должен врать (`crop`, а не
|
||
`crop-png`); png-интент держат адрес страницы и имя скачиваемого файла.
|
||
**Реализовано:** реестр разделён на инструменты (`registry/tools/`, уникальный
|
||
`id`) и страницы (`registry/pages/`, уникальный `slug`), роут —
|
||
`tools/[slug]/`; модель — `docs/architecture.md`, раздел 3. **Следствие для
|
||
SEO: редиректы не понадобились, canonical и sitemap не меняются, адреса те
|
||
же** — поэтому это была безопасная правка до индексации, а не после. Побочная
|
||
выгода: широкие интенты («crop image online») переносятся теми же страницами
|
||
контентом — H1 «Crop image», текст «works with PNG, JPG, WebP»; URL-алиасы без
|
||
`-png` по-прежнему не создаются (канонический беспорядок). Побочный эффект
|
||
модели: страница может ссылаться на один инструмент, а инструмент —
|
||
обслуживать много страниц, поэтому следующие шаги (свести convert-страницы на
|
||
один `convert`, селектор формата в Download — S1f) не требуют новой миграции
|
||
реестра. Задача на консолидацию — `docs/backlog.md`.
|
||
- **Индексируемая локаль — EN** (базовая; конкурент англоязычный). RU-версия —
|
||
отдельно и позже: префикс `/ru/`, prerender обеих локалей, hreflang
|
||
(сознательно отложено). Пока язык переключается на клиенте (localStorage) —
|
||
для SEO не учитываем.
|
||
- **Прод-домен без `BASE_PATH`.** Сборка с базой (GitHub Pages `/repo/`, см.
|
||
`BASE_PATH` в `web/vite.config.ts` и `deploy.yml`) ломает абсолютные URL,
|
||
canonical и «корневость» страниц. Свой домен + корень. Текущий деплой — GitHub
|
||
Pages (`.github/workflows/deploy.yml`); перенос на свой домен выполняется
|
||
сменой origin в CI и `PUBLIC_SITE_ORIGIN`.
|
||
- **URL-схема инструментов:** короткие плоские адреса — `/tools/<slug>` для
|
||
страницы, `/list-tools` для каталога, где `<slug>` берётся из записи
|
||
`registry/pages/`. Схему не менять без отдельного SEO-плана: после индексации
|
||
переименование URL означает 301 и потерю позиций. Разделение инструмента и
|
||
страницы (решение выше) адресов не меняет.
|
||
- **Аналитика — GA4, в режиме «только агрегаты».** GA4 уже стоит в проде
|
||
(`web/src/app.html`, prerender-оболочка, значит на каждой странице). Решение —
|
||
не выпиливать, а ограничить: cookieless-конфигурация, без рекламных audiences,
|
||
signals и ремаркетинга. Граница приватности проходит по данным изображения: GA
|
||
не видит ни файла, ни его содержимого, ни результата инструмента — только факт
|
||
открытия страницы. **Рекламу и ремаркетинг не ставим** — они противоречат
|
||
позиционированию, в отличие от счётчика посещений. Формулировку «без трекинга»
|
||
на публичных страницах не использовать: она теперь неточна, см. §1 и S4b.
|
||
- **Три разных артефакта на странице, три разных источника.** `<title>` для
|
||
выдачи (`seo.metaTitle`, ~55–60 символов **без префикса бренда** — «Crop PNG
|
||
Online - Free Image Cropper, No Upload»: бренд не приносит собственных
|
||
поисковых запросов и съедает треть выдачи), `meta description`
|
||
(`seo.metaDescription`, ~150–160 символов) и H1 (`pages.<slug>.title`, чистый
|
||
интент: «Crop PNG online»). **Решение по «free / no upload / нет лимитов»:**
|
||
прямо в H1 они не идут — Google не вознаграждает ключи в заголовке,
|
||
переписывает title примерно в 60% случаев, а список выгод в H1 читается как
|
||
сборка ключей. Эти обещания работают в `meta description` (влияет на
|
||
кликабельность) и в первом абзаце. **Форматы в H1 не перечисляем:** широкие
|
||
интенты («crop jpg») закрывает текст первого абзаца, description и FAQ, а не
|
||
заголовок; это же запрещено §5 как doorway-подход. Реестр не трогаем: `title`
|
||
в нём остаётся для каталога и цепочек, SEO-заголовки живут в словаре.
|
||
- **Честные методы.** Никакого клонированного текста, дорвеев, PBN. Контент — по
|
||
каждому инструменту, с ручной вычиткой.
|
||
|
||
## 1. Аудит (2026-09-09)
|
||
|
||
Фундамент уже есть:
|
||
|
||
- SvelteKit + `adapter-static`, `prerender = true` на весь сайт
|
||
(`web/src/routes/+layout.ts`) — весь контент в статичном HTML, ботам не нужен
|
||
JS. Это главный технический козырь.
|
||
- Страницы в `web/src/lib/registry/pages` со «SEO-шными» slug (`crop-png`,
|
||
`add-border-png`, …) — URL уже повторяют паттерн конкурента, при этом
|
||
внутренние имена инструментов png-интента не держат. Актуальный состав:
|
||
`docs/tools-map.md`.
|
||
- На корневых страницах инструментов есть базовые `<title>` и `robots`; полный
|
||
SEO-слой (canonical, OG, content и JSON-LD) остаётся S1/S2.
|
||
- Каталог со ссылками на все инструменты (внутренняя перелинковка) и карта
|
||
инструментов против конкурента: `docs/tools-map.md`.
|
||
- EN-тексты в реестре + i18n-словари ru/en.
|
||
|
||
Чего нет (пробелы закрываются этапами ниже):
|
||
|
||
| Пробел | Где сейчас | Этап |
|
||
| -------------------------------------------------- | -------------------------------- | ---- |
|
||
| `noindex` на страницах инструментов | стоит (`+page.svelte`) | S1 |
|
||
| `sitemap.xml` | генерируется при сборке (S1b) | — |
|
||
| `robots.txt` без `Sitemap:` | allow-all + `Sitemap:` (S1c) | — |
|
||
| `rel=canonical` | есть, `Seo.svelte` (S1d) | — |
|
||
| OG/Twitter-теги | есть; per-tool картинки — S1e | S1 |
|
||
| Контент страницы (how-to, FAQ, related) | title, robots и отрендеренный H1 | S2 |
|
||
| JSON-LD (SoftwareApplication, FAQPage, Breadcrumb) | нет | S3 |
|
||
| `llms.txt`, хабы категорий с текстом | нет | S3 |
|
||
| GSC + доводка GA до cookieless-конфигурации | GA4 стоит, GSC не подключён | S4 |
|
||
|
||
Строка `noindex` — первая не потому, что её сложнее всего, а потому, что она
|
||
блокирует всё остальное: пока тег стоит, остальные строки таблицы не дают
|
||
трафика. Подробности и условие снятия — §4, S1.
|
||
|
||
## 2. Конкурент (onlinepngtools.com)
|
||
|
||
Снято с живого сайта (2026-09-09):
|
||
|
||
- ~311 URL в sitemap, все плоские (`/crop-png`, `/create-transparent-png`);
|
||
title вида «Crop a PNG – Online PNG Maker».
|
||
- Страница инструмента: h1 + 2–3 абзаца («World's simplest…», import/crop
|
||
примеры), примеры «before/after», how-to-блок, огромные футерные перелинковки
|
||
(серии Logo*/Icon*/Stamp*), страницы-хабы, price-wall.
|
||
- Сила: возраст домена, ссылочная масса, бренд, охват, серии-клоны под длинные
|
||
хвосты.
|
||
- Слабость (наш контраргумент): реклама, ежедневные лимиты free-плана, платное
|
||
коммерческое использование, апселл-модалки, страницы по ~450 КБ.
|
||
- Наш ответ в контенте каждой страницы: **no upload (всё локально в браузере),
|
||
no signup, no limits, бесплатно в т.ч. для коммерческого использования, open
|
||
source**.
|
||
|
||
## 3. Стратегия
|
||
|
||
1. **Не лобовая, а ядро интентов.** 80% объёма поиска приносят ~30–50 запросов.
|
||
Покрытие инструментов у нас почти полное (список — `docs/tools-map.md`);
|
||
приоритет — контент и качество страниц ядра, затем хвосты.
|
||
2. **Страница = лендинг, а не «пустая коробка».** Шаблон контента: H1 → 1–2
|
||
абзаца «что делает» → как использовать (шаги) → параметры → FAQ (3–5 вопросов
|
||
уровня People-Also-Ask) → related tools по категории.
|
||
3. **CWV как измеримое преимущество.** Лёгкие быстрые страницы против ~450-КБ
|
||
страниц конкурента; после редизайна не потерять скорость.
|
||
4. **GEO.** LLM-системы цитируют страницы с прямыми определениями, списками,
|
||
таблицами и уникальными фактами. Всё это уже есть в данных реестра — отдавать
|
||
в HTML-структуре, без воды.
|
||
5. **Информационный контур — потом, не вместо.** Гайды по форматам (PNG/JPEG/
|
||
WebP: история, модификации, lossy/lossless, прозрачность, «png vs jpeg») дают
|
||
E-E-A-T, перехватывают сравнительные запросы и служат хабами внутренних
|
||
ссылок на инструменты. Но это этап S3e и только после того, как написано ядро
|
||
S2: транзакционная страница приносит конверсию, информационная — только
|
||
трафик. Тонкие FAQ-страницы «про всё» не заводить — несколько сильных
|
||
материалов с ссылками на несколько связанных инструментов.
|
||
6. **Дистрибуция.** GitHub-репо (звёзды/форки = сигналы), alternative.to,
|
||
Product Hunt, Reddit по интенту — реальный путь набрать первые бэклинки без
|
||
бюджетов.
|
||
|
||
## 4. Этапы
|
||
|
||
### S1. Технический минимум (закрывает блокер индексации)
|
||
|
||
Разбито на две группы: **domain-free** (делаем параллельно с покупкой домена) и
|
||
**domain-required** (после покупки и DNS-настройки).
|
||
|
||
- [x] **[S1h]** Robots-тег на страницах инструментов — **сделано 2026-10-12, но
|
||
не снят, а сделан условным** (`web/src/routes/tools/[slug]/+page.svelte`):
|
||
`index, follow` ставится **тогда и только тогда, когда у страницы есть
|
||
EN-`seo`-блок** (`isPageIndexable()` в
|
||
`web/src/lib/i18n/schema-tool-strings.ts`), иначе `noindex, nofollow`.
|
||
Единого места правки нет: индексность следует за контентом, поэтому
|
||
страницу нельзя забыть при написании текста и нельзя проиндексировать с
|
||
заготовкой. Читается базовый словарь, а не объединённый, — переключение
|
||
посетителя на RU не переворачивает тег. Тот же признак выкидывает
|
||
noindex-страницы из sitemap (`gen-sitemap.mjs`), так что список в sitemap
|
||
и набор индексируемых страниц не могут разойтись. **Страховка от «сломать
|
||
руками»:** контентный гейт вынесен в
|
||
`web/src/lib/i18n/schema-tool-strings.test.ts` — страница с `seo`-блоком
|
||
обязана иметь ≥250 слов, ≥3 шага how-to, ≥3 FAQ и title/description в
|
||
границах SERP, иначе тест падает до индексации. Проверено на сборке:
|
||
`index, follow` ровно на страницах с текстом, `noindex` на остальных,
|
||
sitemap совпадает с этим набором. **Осталось:** снять `noindex` совсем,
|
||
когда текст появится у всех страниц, которые имеет смысл индексировать.
|
||
|
||
#### S1-free: без домена
|
||
|
||
- [ ] **[S1e]** OG-картинки per-tool: генерация PNG-карточек скриптом на
|
||
существующем ядре (мы сами умеем рисовать PNG) — имя инструмента + бренд,
|
||
файл `static/og/[slug].png`, ссылка из `Seo.svelte`. Путь к картинке
|
||
строить через `resolve()` из `$app/paths` (как favicon в
|
||
`+layout.svelte`), а не литералом `/og/…`: под `BASE_PATH` корневой путь
|
||
ломается. Домен для этого не нужен; при деплое на собственном домене
|
||
OG-картинки будут абсолютными и корректными.
|
||
- [x] **[S1f]** Download-кнопка с селектором формата PNG/JPG/WebP/BMP (+quality
|
||
для lossy) для всех инструментов — механика `Tool.output` уже есть
|
||
(`docs/backlog.md`, «Идеи» №6, UX-райз «Download»). Продуктовая основа
|
||
«image tools»-позиционирования: без неё сайт остаётся PNG-сайтом. Вести
|
||
параллельно с текущими quality-задачами. Побочно снимает `quality` из схем
|
||
**конвертеров** — после этого convert-страницы сводятся на один инструмент
|
||
(`docs/backlog.md`). Не из всех схем: у `jpeg-artifacts` `quality` —
|
||
функциональное поле (сила артефактов), а `output` у инструмента нет, так
|
||
что селектор формата его не покрывает.
|
||
- [ ] **[S1g]** Поведение конвертеров после S1f: не предлагать в меню форматов
|
||
формат исходника (disable) — чтобы `convert-png-to-jpg` не мог сохранить в
|
||
png. **Под вопросом:** блок мешает легальному сценарию «сохранить
|
||
обработанный PNG / JPEG с другим качеством»; решение не принято, см.
|
||
`docs/backlog.md`. Существующие страницы не трогать: `convert-png-to-jpg`,
|
||
`convert-png-to-webp`, `png-to-bmp` остаются самостоятельными лендингами
|
||
со своим контентом (§5).
|
||
|
||
#### S1-domain: свой домен (подключён; §6 R2-cut)
|
||
|
||
- [x] **[S1a]** Перевести прод на собственный домен — **сделано 2026-10-11**:
|
||
`BASE_PATH` убран из `deploy.yml`, задан `PUBLIC_SITE_ORIGIN`, добавлен
|
||
`web/static/CNAME`. Редирект `https://<юзер>/<repo>/…` → корневые URL
|
||
(301) делает сам GitHub Pages при включённом кастомном домене. Делается
|
||
одновременно с S1d (canonical), чтобы Google проиндексировал сразу с
|
||
правильным доменом.
|
||
- [x] **[S1b]** Скрипт `web/scripts/gen-sitemap.mjs` — **сделано 2026-10-12**:
|
||
пишет `sitemap.xml` в `build/` после `vite build` (вызов добавлен в
|
||
`pnpm build`). Адреса берутся **из собранного HTML**, а не из импорта
|
||
`PAGES`: список prerender-страниц и есть фактический набор URL, а страницы
|
||
с `noindex` в HTML автоматически исключаются — sitemap не может разойтись
|
||
с тем, что реально задеплоено, и не рекламирует то, что мы просим
|
||
краулеров игнорировать. Проверено: в sitemap попадают `/`, `/list-tools`,
|
||
`/chains`, но не `/kit`, `/pipeline` и страницы инструментов (пока S1h).
|
||
Origin — `PUBLIC_SITE_ORIGIN`, фолбэк — `static/CNAME` (тот же домен, что
|
||
публикует GitHub Pages, без третьей копии литерала); опциональный
|
||
`BASE_PATH` учитывается как в `vite.config.ts`.
|
||
- [x] **[S1c]** `robots.txt` — **сделано 2026-10-12**: `Sitemap:` добавлен,
|
||
allow-all сохранён. **Служебный `/kit` закрыт не через `Disallow:`, а
|
||
через `noindex` в HTML** (как `/pipeline`): заблокированный краулером, но
|
||
не помеченный noindex URL Google помечает «проиндексирован, несмотря на
|
||
блокировку в robots.txt» и оставляет старый сниппет. Побочная выгода: тот
|
||
же признак автоматически выкидывает `/kit` из sitemap.
|
||
- [x] **[S1d]** Компонент `Seo.svelte` (kit) — **был сделан до S1b, отмечено
|
||
2026-10-12**: canonical (абсолютный URL от `PUBLIC_SITE_ORIGIN` +
|
||
`SITE_URL`, `web/src/lib/seo.ts`), OG (title/description/type/url/image) и
|
||
`twitter:card`. Подключён на `/`, `/list-tools`, `/chains`,
|
||
`/tools/[slug]`. Картинка пока общая `og/default.png` — per-tool остаётся
|
||
за S1e.
|
||
|
||
> **Порядок S1:** S1e/S1f/S1g → покупка домена → S1a+S1b+S1c+S1d → **S1h**
|
||
> (снятие `noindex`) → S2-контент. Гейты: `pnpm --dir web build` зелёный; в
|
||
> `build/` лежит корректный `sitemap.xml` со всеми страницами инструментов;
|
||
> canonical/OG присутствуют на всех страницах; `noindex` отсутствует в собранном
|
||
> HTML (`pnpm --dir web build` и проверка `build/tools/*/index.html`);
|
||
> `pnpm --dir web test:e2e` — по правилам `docs/quality-gates.md`, в CI job
|
||
> `e2e` non-blocking, поэтому его статус читается по отдельному job
|
||
> (`docs/decisions.md`, раздел 10).
|
||
>
|
||
> **Фактически (2026-10-12) порядок изменился:** S2-контент написан раньше
|
||
> снятия `noindex`, а S1h сделан условным — индексность страницы равна наличию
|
||
> её текста (S1h). Гейт выше в части «`noindex` отсутствует» выполняется для
|
||
> страниц с текстом; полное снятие тега остаётся отдельной задачей.
|
||
|
||
### S2. Контентный слой (параллельно quality-плану, волнами по категориям)
|
||
|
||
- [x] **[S2a]** Схема данных: `seo`-блок per-tool — **сделано 2026-10-12**: тип
|
||
`SeoContent` (`longDescription`, `howTo: string[]`, `faq: {q, a}[]`) в
|
||
`web/src/lib/i18n/dict.ts`, поле `seo?` в `PageStrings`, доступ
|
||
`pageSeo(page)` в `web/src/lib/i18n/schema-tool-strings.ts`. Хранится в
|
||
словаре `pages.<slug>.seo`, не в реестре: у реестра нет EN-копии длинного
|
||
текста по определению, а словарь — единственное место, где лежит текст.
|
||
**Пока EN-only:** `ignoreMissingPatterns: ["pages.*.seo"]` в
|
||
`web/eslint.config.js` снимает требование паритета локалей для этого
|
||
блока, RU появится вместе с `/ru/` (§0). Первые тексты — `crop-png`,
|
||
`resize-png`.
|
||
- [x] **[S2b]** Компонент контента страницы инструмента — **сделано 2026-10-12**
|
||
минимальной версией: `web/src/lib/components/PageContent.svelte` рендерит
|
||
`longDescription` абзацем, `howTo` списком `<ol>`, `faq` через `<details>`
|
||
(текст в DOM, ответ не требует скролла); подключён в
|
||
`web/src/routes/tools/[slug]/+page.svelte` под рабочей областью
|
||
инструмента и рендерится только при наличии `seo`-блока, так что страницы
|
||
без текста не меняются. Новый токен `--size-content-prose` (мера колонки
|
||
текста) появился вместе с потребителем. **Не сделано и вынесено в S2c:**
|
||
related tools и хлебные крошки.
|
||
- [ ] **[S2c]** Хлебные крошки (Каталог → Категория → Инструмент) в UI. Related
|
||
tools по категории (2–3 «соседних» интента) — здесь же: это внутренняя
|
||
перелинковка, без неё страницы ядра плохо связаны между собой.
|
||
- [ ] **[S2d]** Первая волна контента — топ приоритетных инструментов ядра
|
||
(приоритет по вордстату: transparent png, jpg→png, compress, resize, crop,
|
||
rotate, circle crop, add text, pixelate, grayscale…); отбор — §5. **Ядро
|
||
закрыто: 20 страниц из §5** — `crop-png`, `resize-png`,
|
||
`remove-background-png`, `convert-png-to-jpg`, `pixelate-png`,
|
||
`grayscale-png`, `rotate-png`, `create-empty-png`, `linear-gradient-png`,
|
||
`change-png-opacity`, `set-alpha-channel-png`, `round-corners-png`,
|
||
`invert-colors-png`, `flip-png`, `convert-png-to-webp`, `png-to-bmp`,
|
||
`svg-to-png`, `png-to-base64`, `change-aspect-ratio-png`, `add-text-png`.
|
||
Каждая: `title` (H1), `metaTitle` (38–54 симв.), `metaDescription`
|
||
(134–159 симв.), `longDescription`, how-to (3–5 шагов) и 4 FAQ. Текст
|
||
написан по фактической схеме инструмента (параметры реестра), без
|
||
шаблонной подстановки. **Правило набора текста, которое доказало себя на
|
||
пилоте:** H1 — чистый интент, «free / no upload» — в `metaTitle` и
|
||
`metaDescription`, форматы — в первом абзаце и FAQ, ограничения
|
||
инструмента проговариваются прямо («это не AI-удаление фона», «только
|
||
90/180/270, произвольный угол ресемплит»). Честное ограничение работает
|
||
лучше приписывания. Остальное ядро §5 — тем же шаблоном.
|
||
- Гейты: на каждой странице инструмента — уникальный текст ≥ 300 слов, H1
|
||
совпадает с интентом, FAQ ≥ 3, related ≥ 3; текст в статике (prerender), не в
|
||
рантайме.
|
||
|
||
### S3. Структурированные данные + GEO
|
||
|
||
- [ ] **[S3a]** JSON-LD: `SoftwareApplication` (+ `offers` price 0) и `FAQPage`
|
||
на страницах инструментов; `WebSite` + `Organization` на главной;
|
||
`BreadcrumbList` на всех внутренних. Учесть: Google ограничил rich results
|
||
по FAQ/HowTo для мелких сайтов — разметка нужна прежде всего для
|
||
LLM-парсинга, она безвредна.
|
||
- [ ] **[S3b]** `llms.txt` в статике: короткий манифест сайта + список
|
||
инструментов с одним предложением на каждый (генерится из реестра тем же
|
||
скриптом, что sitemap).
|
||
- [ ] **[S3c]** Хабы категорий с текстом: 2–3 абзаца на категорию (что за
|
||
группа, когда какие инструменты применять), не голые списки карточек.
|
||
- [ ] **[S3d]** GEO-редактура: каждое описание начинается прямым определением
|
||
(«Crop PNG is a free tool that cuts a rectangular area from a PNG image
|
||
right in your browser»), списки/таблицы для фактов, без вводных «в
|
||
современном мире…». Проверка: страница отвечает на запрос одним абзацем
|
||
«без скролла».
|
||
- [ ] **[S3e]** _(опционально)_ Информационные гайды по форматам: 3–4 сильных
|
||
материала (`/guides/png-format`, `/guides/jpeg-vs-png`, …): история и
|
||
модификации формата, lossy/lossless, прозрачность, когда какой формат
|
||
выбирать. Каждый — с ссылками на 3–5 связанных инструментов (хабы
|
||
перелинковки), FAQ из гайдов продублирован как FAQPage-разметка. Приоритет
|
||
ниже S2/S3a–d: только когда ядро написано и есть ресурс.
|
||
- Гейты: валидация JSON-LD (Rich Results Test без ошибок); `llms.txt` актуален
|
||
при добавлении инструментов (генерация, а не ручное редактирование).
|
||
|
||
### S4. Измерение и запуск
|
||
|
||
- [ ] **[S4a]** Google Search Console: собственность на домен, отправка sitemap,
|
||
мониторинг индексации и запросов. Бесплатно и обязательно.
|
||
- [ ] **[S4b]** Довести GA4 до решения §0: cookieless-конфигурация, отключённые
|
||
рекламные audiences и signals, `anonymize_ip`, запрет на передачу
|
||
параметров с данными картинки. Мусорные попадания уже отсечены: тег
|
||
подключается только при `PUBLIC_GA_ENABLED=true` (выставлен в
|
||
deploy-workflow, `+layout.svelte`). GA/ЯМ как замена счётчику не
|
||
рассматриваем.
|
||
- [ ] **[S4c]** Дистрибуция: закрепить GitHub-репо (README со скриншотами),
|
||
подача на alternative.to (страница против конкурента), Product Hunt,
|
||
тематические Reddit/HN-треды. Бэклинки — главный дефицит для конкуренции.
|
||
- [ ] **[S4d]** _(опционально, позже)_ Сравнительные посадочные «vs …» (без
|
||
негатива: «no limits, no signup, no upload») — по мере роста доверия
|
||
домена.
|
||
- [ ] **[S4e]** Контроль CWV: Lighthouse на страницы ядра после каждого крупного
|
||
этапа редизайна; цель — зелёные метрики на мобильных.
|
||
|
||
## 5. Приоритизация инструментов (первая волна контента)
|
||
|
||
Источник — `docs/tools-map.md` (наш состав и замер по конкуренту — §2). Слаги
|
||
ниже — **фактические `slug` страниц** из `docs/tools-map.md` §1; первая волна —
|
||
топ-интенты, где конкуренты ранжируются, а у нас уже есть инструмент и он не
|
||
хуже:
|
||
|
||
- прозрачность/фон: create-empty-png, remove-background-png, change-png-opacity,
|
||
set-alpha-channel-png, round-corners-png
|
||
- конвертация: convert-png-to-jpg, convert-png-to-webp, png-to-bmp, svg-to-png,
|
||
png-to-base64
|
||
- геометрия: crop-png, resize-png, rotate-png, flip-png, change-aspect-ratio-png
|
||
- цвет/фильтры: grayscale-png, invert-colors-png, pixelate-png
|
||
- текст: add-text-png, watermark-tile-png
|
||
- генерация: linear-gradient-png
|
||
|
||
> Группы здесь — по категории страницы в реестре (`registry/pages/`), а не по
|
||
> смыслу: `round-corners-png` лежит в `alpha`, `add-text-png` и
|
||
> `watermark-tile-png` — в `text`.
|
||
>
|
||
> **Открытый вопрос по интенту «сжать до N КБ».** Лимит размера теперь живёт в
|
||
> кнопке Download (`fitWithinBytes` в `web/src/lib/core/io.ts`); интенты вида
|
||
> «compress png to 500kb / 1mb» — high-volume и лимит-ориентированные, селектор
|
||
> в Download их не закрывает как посадочная. Решение (отдельная страница / приём
|
||
> в контенте существующих / ничего) требует вордстата; имя страницы не выбрано.
|
||
> Прорабатывать вместе с вопросом «из формата в PNG» выше.
|
||
>
|
||
> **Открытый вопрос по интентам «из формата в PNG».** У конкурента есть
|
||
> `jpg-to-png`, `webp-to-png`, `gif-to-png` как отдельные страницы; у нас таких
|
||
> инструментов нет и создавать их не хочется — загрузка файла уже принимает
|
||
> любой формат, а конвертер «во что-то» закрывает обратное направление. Это
|
||
> high-volume интент без посадочной страницы. Решение (страница-обёртка на
|
||
> существующий инструмент / приём в H1 и тексте / ничего) требует вордстата и
|
||
> должно быть принято до старта S2, иначе первая волна контента закроет не ядро
|
||
> запросов.
|
||
|
||
Новая волна форматов (после S1f): jpg↔webp и другие конвертации «формат →
|
||
формат» — только по подтверждённому вордстату; базовые кейсы закрывает селектор
|
||
формата в Download (S1f), страницы заводим лишь там, где интент стабильно
|
||
ищется.
|
||
|
||
- **crop-png: H1 «Crop image online — free, no upload»**, текст «works with PNG,
|
||
JPG, WebP» — широкий интент обслуживается контентом страницы с png-слагом,
|
||
слаг при этом остаётся якорем дешёвого png-интента.
|
||
|
||
### Форматные варианты страниц (`crop-jpeg`, `crop-webp`, …)
|
||
|
||
Три возможных механики — важно не перепутать:
|
||
|
||
1. **301-редирект на существующую страницу** (`/crop-jpg` → `/crop-jpeg`, или
|
||
`/crop-png` → новый слаг после переименования) — законно **только** для
|
||
опечаток, альтернативных написаний и переименований **уже опубликованной**
|
||
страницы: URL, которого никогда не было в индексе, редиректом не закрывается.
|
||
Для самостоятельного запроса редирект — это отказ от страницы: Google
|
||
перестаёт показывать редирект, ранжировать будет только цель. Как посадочная
|
||
под «crop jpeg» не работает вообще.
|
||
2. **Зеркало с canonical на `/crop-png`** — технически легально, но бесполезно:
|
||
canonical-дубль в индекс не попадает, видимости не добавляет, а массовое
|
||
производство таких зеркал выглядит как накрутка площади и при ошибке в
|
||
canonical превращается в дорвейный кластер. Не делаем.
|
||
3. **Самостоятельная страница = самостоятельный контент.** Заводить `/crop-jpeg`
|
||
можно только если: (а) интент подтверждён вордстатом, (б) на странице
|
||
собственный текст — H1 «Crop JPEG», FAQ про качество/артефакты/ когда
|
||
выбирать JPEG вместо PNG, отличия от png-кейса, (в) текст написан или выверен
|
||
человеком, а не получен подстановкой формата в шаблон. Реестром
|
||
автоматизировать **данные** (тот же tool, другой дефолтный output) — можно;
|
||
автоматизировать **текст** — нельзя: массовая подстановка {tool}×{format} в
|
||
шаблон — doorway-паттерн, риск deindex всего сайта.
|
||
|
||
Как правильно получать видимость под «jpeg»/«webp» без клонов: широкие
|
||
формулировки закрывает контент существующей страницы (H1 «Crop image», «works
|
||
with PNG, JPG, WebP» в тексте + селектор формата в Download, S1f). Отдельные
|
||
форматные страницы — точечные исключения по вордстату, не серия.
|
||
|
||
### Convert-инструменты: страницы и «универсальный конвертер»
|
||
|
||
Разводить два разных интента:
|
||
|
||
- **«convert png to jpg»** — интент «страница-конвертер»: пользователь ищет
|
||
конкретную пару форматов (лучшее качество конверсии, меньше ошибок), это
|
||
готовые лендинги. Существующие (`convert-png-to-jpg`, `convert-png-to-webp`,
|
||
`png-to-bmp`, `svg-to-png`, `base64-to-png`, …) **оставить и наполнить
|
||
контентом как все**: свой H1 («Convert PNG to JPG — free, no upload»), FAQ про
|
||
качество/прозрачность/фон, related. Селектор формата (S1f) их **не заменяет**
|
||
— он про «уже открыл инструмент и хочу другой формат на выходе».
|
||
- **«convert image» / «image converter»** — интент «швейцарский нож». Под него —
|
||
**один будущий инструмент `/convert-image`**: сначала пустой **core-tool** в
|
||
`core/` — функция ре-энкода («копия с перекодированием»: декодирует любой
|
||
поддержанный исходник в ImageData и кодирует в выбранный формат; поверх неё
|
||
S1f строит селектор формата). Инструмент и страницу добавлять **только вместе
|
||
|
||
с собственным текстом** («Convert any image to PNG, JPG or WebP in your
|
||
browser») — core в коде не обязывает к странице. Этот же шаблон потом
|
||
закрывает форматные волны (jpg→webp и т.п.) без новых страниц.
|
||
|
||
Не делать: серию `convert-jpeg`/`convert-webp`-клонов с подстановкой формата
|
||
(doorway, см. выше) и «универсальный конвертер» как единственную страницу вместо
|
||
форматных лендингов — теряется ядро «convert png to jpg»-запросов.
|
||
|
||
Правило добавления новых инструментов: брать из хвоста конкурента только те
|
||
интенты, которые подтверждены вордстатом, и сразу с контентом S2 (страница без
|
||
текста — потраченный URL).
|
||
|
||
## 6. Переименование бренда и домен
|
||
|
||
Бренд — `easy-image-tools`, домен — `easy-image-tools.com`.
|
||
|
||
- [x] **[R1]** Переезд бренда выполнен (2026-10-11): хардкод в компонентах
|
||
убран, бренд — i18n-константа `t("brand")` (точка истины — словари
|
||
`brand` + README). Репозиторий переименован в `easy-image-tools`, remote
|
||
обновлён, привязанные к репо ссылки/пути переключены: `BASE_PATH` в
|
||
`deploy.yml`, GitHub-URL в `TopBar.svelte`, `repository` в `cog.toml`.
|
||
**НЕ трогать:** адреса страниц инструментов (`/tools/crop-png`),
|
||
localStorage-ключи (бренда не содержат), историю `docs/archive`.
|
||
- [x] **[R2]** Домен `easy-image-tools.com` зарегистрирован (2026-10-11);
|
||
`SITE_URL` в `web/src/lib/seo.ts` переключён на него.
|
||
- [x] **[R2-cut]** Прод переведён на домен без `BASE_PATH` (§0) — **сделано
|
||
2026-10-11**: DNS + HTTPS, `PUBLIC_SITE_ORIGIN` =
|
||
`https://easy-image-tools.com` в `deploy.yml`, `web/static/CNAME`. 301 со
|
||
старого GitHub Pages делает сам GitHub при включённом кастомном домене.
|
||
Canonical и sitemap генерятся от `PUBLIC_SITE_ORIGIN`.
|
||
- **Порядок:** R1(код), покупка домена и cutover (R2-cut) сделаны. Осталось
|
||
S1-domain (canonical + sitemap: S1b/S1c/S1d), а S1-domain — блокер для S1h
|
||
(снятие `noindex`). Переименование делали до индексации (до S1h): после снятия
|
||
`noindex` это был бы переезд с 301 и потеря позиций — не делать.
|
||
|
||
## 7. Что осознанно НЕ делаем
|
||
|
||
- Клонирование всего каталога конкурента (низкокачественные дубли + нет ресурсов
|
||
на контент) — вместо этого ядро + обоснованные хвосты.
|
||
- RU-локаль в индексе до решения о структуре `/ru/` + hreflang.
|
||
- Реклама, ремаркетинг, pixels сторонних сетей — противоречит позиционированию.
|
||
Счётчик посещений GA4 — не противоречит, условия ограничений — §0 и S4b.
|
||
- Дорвеи, программные зеркала, покупные ссылки.
|
||
- Массово-сгенерированные форматные клоны (`crop-jpeg`/`crop-webp` как копии
|
||
`crop-png` с подстановкой формата в шаблонный текст) — doorway-паттерн, риск
|
||
deindex всего сайта. Форматная страница — только уникальный контент + вордстат
|
||
(§5); редиректы — только для опечаток/переименований.
|
||
- URL-алиасы без `-png` для существующих инструментов и зеркальные
|
||
страницы-конвертеры «на каждый формат» без вордстата.
|
||
|
||
## 8. Связанные документы
|
||
|
||
- `docs/tools-map.md` — карта «наш инструмент ↔ интент конкурента».
|
||
- `docs/backlog.md` — пункты SEO/GEO в общем бэклоге.
|
||
- `docs/roadmap.md` — фазы 2–8 (ядро TS→Rust/wasm, CLI), фаза 11 (пайплайн);
|
||
фазы 9–10 — API и PWA.
|
||
- `docs/plan-platform.md` — планы API и PWA (общее ядро, оффлайн-режим).
|