diff --git a/openspec/changes/header-typewriter/design.md b/openspec/changes/archive/2026-09-19-header-typewriter/design.md similarity index 100% rename from openspec/changes/header-typewriter/design.md rename to openspec/changes/archive/2026-09-19-header-typewriter/design.md diff --git a/openspec/changes/header-typewriter/proposal.md b/openspec/changes/archive/2026-09-19-header-typewriter/proposal.md similarity index 100% rename from openspec/changes/header-typewriter/proposal.md rename to openspec/changes/archive/2026-09-19-header-typewriter/proposal.md diff --git a/openspec/changes/header-typewriter/specs/site-header-typewriter/spec.md b/openspec/changes/archive/2026-09-19-header-typewriter/specs/site-header-typewriter/spec.md similarity index 100% rename from openspec/changes/header-typewriter/specs/site-header-typewriter/spec.md rename to openspec/changes/archive/2026-09-19-header-typewriter/specs/site-header-typewriter/spec.md diff --git a/openspec/changes/header-typewriter/tasks.md b/openspec/changes/archive/2026-09-19-header-typewriter/tasks.md similarity index 100% rename from openspec/changes/header-typewriter/tasks.md rename to openspec/changes/archive/2026-09-19-header-typewriter/tasks.md diff --git a/openspec/specs/site-header-typewriter/spec.md b/openspec/specs/site-header-typewriter/spec.md new file mode 100644 index 0000000..7ad1f5d --- /dev/null +++ b/openspec/specs/site-header-typewriter/spec.md @@ -0,0 +1,85 @@ +# site-header-typewriter Specification + +## Purpose +Логотип `dedinit()` в шапке сайта анимирован эффектом печатной машинки: +внутри скобок блочный курсор печатает темы блога, замирает, стирает их и +переходит к следующей — обыгрывая название как вызов функции `dedinit(...)`. + +## Requirements + +### Requirement: Анимация «печатная машинка» в логотипе + +Система SHALL анимировать текст в скобках логотипа `dedinit()` на всех +страницах сайта: блочный курсор печатает слово по одному символу, удерживает +его ~1 секунду, стирает по одному символу, мигает на пустом месте и печатает +следующее слово — бесконечным циклом по списку тем блога. + +#### Scenario: Логотип печатает слова по циклу + +- **GIVEN** открыта любая страница сайта (`/` или внутренняя), JS включён +- **WHEN** страница загружена +- **THEN** в `dedinit()` между скобками присутствует контейнер + `#dedinit-typewriter` с блочным мигающим курсором, и текст посимвольно + печатается из списка тем (например, `linux` → `llm` → `politics` → ...) + +#### Scenario: Цикл без остановки + +- **GIVEN** анимация запущена +- **WHEN** прошло более 3 слов печати/стирания +- **THEN** анимация продолжает цикл (после последнего слова переходит к + первому), не останавливаясь и не накапливая ошибок + +### Requirement: Бесшовный вывод (прогрессивное улучшение) + +Система SHALL оставаться декоративным улучшением: при выключенном JS логотип +остаётся обычным текстом `dedinit()`; при его включении — анимация +накладывается, не ломая вёрстку и навигацию шапки. + +#### Scenario: JS отключён — логотип статичен + +- **GIVEN** браузер с отключённым JavaScript +- **WHEN** страница загружена +- **THEN** в шапке отображается обычный текст `dedinit()` без скобочного + контейнера и без ошибок + +### Requirement: Доступность (prefers-reduced-motion) + +Система SHALL уважать системную настройку `prefers-reduced-motion: reduce`: +при ней показывать первое слово списка статически, без анимации и мигания. + +#### Scenario: Уменьшение движения + +- **GIVEN** у пользователя включено `prefers-reduced-motion: reduce` +- **WHEN** страница загружена +- **THEN** внутри скобок логотипа отображается первое слово списка статично, + курсор не мигает (CSS `animation: none`), JS-цикл не запускается + +### Requirement: Минимальный размер и отсутствие зависимостей + +Система SHALL реализовывать эффект без внешних зависимостей (без Alpine.js, +без jQuery): инлайн-скрипт и CSS суммарно не более ~2 КБ. + +#### Scenario: Нет внешних библиотек + +- **GIVEN** собранный сайт +- **WHEN** просматривается HTML страницы +- **THEN** в ``/футере не подключено никаких сторонних JS-библиотек для + эффекта (только собственный инлайн-скрипт и CSS темы) + +### Requirement: Список тем конфигурируется + +Система SHALL позволять задавать список тем через `hugo.toml` +(`[params.typewriter] words = [...]`), со встроенным фолбэком по умолчанию +(`linux, llm, politics, homelab, nix`) при его отсутствии. + +#### Scenario: Слова из конфига + +- **GIVEN** в `hugo.toml` задан `[params.typewriter] words = ["linux","llm","politics"]` +- **WHEN** страница собрана и открыта +- **THEN** анимация печатает именно эти слова, в заданном порядке + +#### Scenario: Конфиг не задан + +- **GIVEN** в `hugo.toml` нет `[params.typewriter]` +- **WHEN** страница собрана и открыта +- **THEN** используется фолбэк-список по умолчанию, анимация работает