From 64fb3a000f930a5102c33640aaa2dc9cbb16dae1 Mon Sep 17 00:00:00 2001 From: Storozhenko Evgeny Date: Sat, 19 Sep 2026 17:48:38 +0000 Subject: [PATCH] =?UTF-8?q?openspec:=20=D0=B0=D1=80=D1=85=D0=B8=D0=B2=20ch?= =?UTF-8?q?ange=20header-typewriter=20(=D1=81=D0=BF=D0=B5=D0=BA=D0=B0=20si?= =?UTF-8?q?te-header-typewriter=20=D0=B2=20specs/)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2026-09-19-header-typewriter}/design.md | 0 .../2026-09-19-header-typewriter}/proposal.md | 0 .../specs/site-header-typewriter/spec.md | 0 .../2026-09-19-header-typewriter}/tasks.md | 0 openspec/specs/site-header-typewriter/spec.md | 85 +++++++++++++++++++ 5 files changed, 85 insertions(+) rename openspec/changes/{header-typewriter => archive/2026-09-19-header-typewriter}/design.md (100%) rename openspec/changes/{header-typewriter => archive/2026-09-19-header-typewriter}/proposal.md (100%) rename openspec/changes/{header-typewriter => archive/2026-09-19-header-typewriter}/specs/site-header-typewriter/spec.md (100%) rename openspec/changes/{header-typewriter => archive/2026-09-19-header-typewriter}/tasks.md (100%) create mode 100644 openspec/specs/site-header-typewriter/spec.md 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** используется фолбэк-список по умолчанию, анимация работает