Бесплатный интерактивный курс · aicoding.space
Из записи — в читаемый сайт: курс по skills-transcript-site
Практический курс по пакету @dzhechkov/skills-transcript-site для того, кто впервые ставит его в Claude Code. Вместе с Марго ты поставишь пак навыков, разберёшь конвейер из шести шагов, поймёшь, как генератор режет транскрипт на секции, соберёшь самодостаточную страницу с поиском и тёмной темой, опубликуешь её на GitHub Pages без единого шага сборки и научишься проверять результат, а не верить ему на слово.
Содержание курса
1. Зачем превращать запись в сайт?
Что делает пакет одной фразой — и почему текст выигрывает у видео.
Ключевая мысль: статический сайт из транскрипта без шага сборки
У Марго в облаке лежат записи докладов сообщества: девяносто минут, ещё девяносто, ещё. Смотрит их примерно никто, и целый год Марго была уверена, что дело в темах.
Дело не в темах. Видео нельзя пролистать глазами, внутри него нельзя найти слово, и поисковик не знает, о чём оно. Текст умеет всё это по своей природе — надо только превратить запись в текст и положить его туда, где живут страницы.
Ровно это делает пакет @dzhechkov/skills-transcript-site: он собирает статический сайт из транскрипта без шага сборки. Разберём обещание по словам:
- статический — на выходе обычные файлы:
docs/index.html,docs/static/app.js,docs/static/style.css; браузер открывает их как есть; - из транскрипта — на входе текст расшифровки или ссылка на YouTube, из которой субтитры достанут за тебя;
- без шага сборки — ни
npm run build, ни React, ни Vite: положил папкуdocs/в репозиторий — сайт опубликован.
И сразу главное про удобство: команды из этого курса не надо заучивать. Внутри Claude Code Марго просто говорит: «сделай сайт из вот этой расшифровки» — и навык срабатывает сам. Команды нужны, чтобы ты понимал, что происходит под капотом.
Компромисс: ты получаешь скорость и почти нулевую эксплуатацию ценой потолка сложности. Пока нужна читаемая страница с поиском — попадание в цель; как только захочется личных кабинетов и базы данных, статика закончится.
2. Ставим пак навыков
Три двери установки, сухой прогон до первой записи на диск и ссылки на пакет.
Ключевая мысль: установка пака навыков одной командой npx
Марго открывает терминал в папке проекта. Монтаж короткий — пакет опубликован в npm, и всё сводится к одной строке.
Дверей три, выбирай по привычке:
npx @dzhechkov/skills-transcript-site— разовый запуск, ничего не остаётся в системе;npm install -g @dzhechkov/skills-transcript-site, затемskills-transcript-site init— глобальная команда, если ставишь часто;npx @dzhechkov/skills-transcript-site initв проекте, где уже есть@dzhechkov/keysarium— пак встанет рядом и будет виден вместе с остальной библиотекой навыков.
Перед любой из них сделай сухой прогон: npx @dzhechkov/skills-transcript-site init --dry-run покажет список файлов, которые появятся, и не тронет диск. Марго один раз пропустила этот шаг в чужом репозитории и потом полчаса выясняла, что именно там поменялось.
Полезные ссылки держи под рукой:
- страница пакета — npm: @dzhechkov/skills-transcript-site;
- исходники и баг-трекер — GitHub: dz-harness;
- соседний пакет экосистемы — npm: @dzhechkov/keysarium.
Требования скромные: Node.js не ниже 16 и настроенный Claude Code CLI. yt-dlp понадобится только для ссылок на YouTube — и только тогда.
Компромисс: установка пака навыков кладёт в твой .claude/ чужие файлы, и обновлять их придётся отдельной командой. Взамен навык работает одинаково у всей команды, а не живёт в голове одного человека.
3. Что именно легло в проект
Разбираем содержимое .claude/skills/transcript-site-generator/ по полочкам.
Ключевая мысль: состав пака: один навык, шесть модулей, три справочника, два примера
После установки Марго делает то, что стоит делать всегда: смотрит, что именно появилось. Всё лежит в одной папке проекта — .claude/skills/transcript-site-generator/.
Состав пака запоминается за один взгляд: один навык, шесть модулей, три справочника, два примера.
SKILL.md— оркестратор: когда навык срабатывает, что он обещает на выходе и в каком порядке читает модули.modules/00-input-analysis.md…modules/05-verification.md— шесть шагов конвейера, по файлу на шаг.references/tech-stack.md,references/data-schemas.md,references/component-catalog.md— справочники: чем собираем, какая структура у секции, какие блоки страницы бывают.examples/sample-transcript-site.mdиexamples/sample-text-only-site.md— два готовых примера: с видео и без него.
Зачем такое дробление, а не один длинный файл: модель читает ровно тот модуль, который нужен на текущем шаге. Это экономит контекст и делает поведение навыка предсказуемым — Марго может открыть modules/02-site-generation.md и увидеть в точности то, чем руководствовался генератор, когда собирал её страницу.
Компромисс: десяток мелких файлов труднее охватить взглядом, чем один большой. Но именно они позволяют править один шаг, не задевая остальные пять.
4. Восемь команд установщика
init, --force, --dry-run, update, remove, list, doctor — и когда что применять.
Ключевая мысль: сухой прогон и здоровье установки через doctor
У установщика восемь команд, и Марго держит в голове только две — остальные вспоминаются по смыслу.
Полный список:
init— поставить все компоненты (без аргументов пакет делает то же самое);init --force— перезаписать то, что уже лежит на месте;init --dry-run— сухой прогон: показать изменения и не тронуть диск;update— обновить установленные файлы до свежей версии пакета;remove— чистое удаление, без хвостов;list— показать, что реально установлено сейчас;doctor— проверка здоровья установки: на месте ли файлы, всё ли согласовано.
Две команды, которые стоит запомнить дословно: init --dry-run — до изменений, doctor — после. Первая отвечает на вопрос «что произойдёт», вторая — на вопрос «всё ли в порядке сейчас». Между ними живёт вся остальная жизнь пака.
Отдельно про --force. Он не спрашивает, он перезаписывает. Марго применяет его в одном случае: когда точно знает, что правила файлы навыка руками и хочет вернуть заводское состояние. Во всех остальных сначала list, потом init --dry-run, и только потом решение.
Компромисс: восемь команд — это больше, чем «поставил и забыл». Зато у каждого состояния установки есть своя команда, и ни одно из них не приходится угадывать.
5. Конвейер из шести шагов
Общая карта: что происходит от входа до проверки и где тебя спрашивают.
Ключевая мысль: конвейер из шести шагов с чекпоинтом после каждого
Прежде чем лезть в детали, Марго рисует карту. Навык работает как конвейер из шести шагов с чекпоинтом после каждого — и это самая полезная картинка курса.
Шаги идут строго по порядку, потому что каждый следующий питается выходом предыдущего:
- Разбор входа — понять, что дали: текст, ссылку или оба, вытащить расшифровку и определить язык.
- Нарезка — разложить сплошной транскрипт на секции с заголовками и таймкодами.
- Сборка страницы — собрать
docs/index.htmlсо всем содержимым и SEO-разметкой. - Интерактивность — сгенерировать
docs/static/app.js: поиск, оглавление, тёмная тема. - Публикация — положить конфигурацию GitHub Pages и README рядом.
- Проверка — пройти по чеклисту и сказать вслух, что сошлось, а что нет.
После каждого шага генератор останавливается и показывает чекпоинт: что сделано, какие файлы появились, и приглашение ответить «ok» или дать правку. Это не декорация. Ошибка нарезки, замеченная на втором шаге, стоит одной реплики; она же, замеченная после публикации, стоит переделки страницы целиком.
Марго проверила это на себе: на первом прогоне она проскочила чекпоинт после нарезки, а на пятом шаге обнаружила, что весь доклад уехал в одну гигантскую секцию.
Компромисс: шесть остановок — это шесть мест, где тебя отвлекают. Взамен ты правишь дёшево и рано, а не дорого и поздно.
6. Шаг 0: генератор разбирается, что ему дали
Классификация входа, добыча субтитров через yt-dlp и выбор языка интерфейса.
Ключевая мысль: определение языка интерфейса по преобладающему алфавиту
Марго приносит ссылку на девяностоминутный доклад и никакого текста. Шаг 0 обязан из этого сделать расшифровку — или честно сказать, что не может.
Сначала классификация. Генератор смотрит на вход и решает, что это:
youtube.com/watch?v=илиyoutu.be/— ссылка на видео, расшифровку добываем;- путь к файлу
.txt,.md,.vtt,.srt— читаем файл; - многострочный кусок текста длиннее ста символов — берём как есть;
- ссылка и текст вместе — спрашиваем, а не угадываем: использовать видео только для встраивания, или вытащить расшифровку из него.
Дальше добыча субтитров. Порядок попыток жёсткий: сначала yt-dlp --write-sub (ручные субтитры, они точнее), и только если их нет — --write-auto-sub (автоматические). Если yt-dlp в системе нет, генератор не изображает успех: он говорит, что нужно поставить yt-dlp или вставить текст руками. Отсутствие квитанции — не успех.
Сырой .vtt приходится чистить: выкинуть заголовок WEBVTT, вытащить пары «таймкод + текст», убрать дубли перекрывающихся отрезков, склеить подряд идущие реплики одного спикера и вычистить служебные теги.
И наконец язык. Определение языка интерфейса идёт по преобладающему алфавиту: в первых 500 символах считаются символы по диапазонам Юникода — кириллица, латиница, иероглифы, арабица, — побеждает самый частый. Кириллица даёт русский интерфейс, латиница — английский, всё остальное — английский как запасной вариант.
Важная честная оговорка из документации: это выбор языка только для подписей интерфейса — кнопок, поиска, счётчиков. Сам текст доклада рендерится как есть. И интерфейс есть пока только на русском и английском: украинский или болгарский получат русские подписи как ближайшие доступные.
Компромисс: счёт символов — грубый способ, он ошибётся на смешанном тексте. Зато он не требует ни модели, ни сети и всегда даёт один и тот же ответ на одном и том же входе.
7. Шаг 1: как транскрипт становится секциями
Три стратегии нарезки, заголовки, спикеры и вопрос без единственного ответа.
Ключевая мысль: три стратегии нарезки: явные маркеры, смысловые сдвиги, время
Сплошная стена текста на девяносто минут не читается ни на каком экране. Задача шага 1 — превратить её в секции, по которым можно прыгать.
Генератор перебирает три стратегии нарезки по очереди, пока какая-нибудь не даст хотя бы три секции:
- Явные маркеры. Если в тексте уже есть структура — заголовки markdown, нумерация «1.», жирные подписи, метки спикеров «Ведущий:», разделители — берём её. Дешевле всего и точнее всего.
- Смысловые сдвиги. Маркеров нет — читаем абзацы и группируем по смене темы. Цель — от 5 до 15 секций, каждая на 200–2000 слов.
- Время. Если есть таймкоды, режем на отрезки примерно по пять минут и подвигаем границы к естественным паузам.
Заголовок для каждой секции пишется в 3–8 слов и по существу: «Часть 1» и «Продолжение» — запрещённые названия, потому что по ним нельзя выбрать, куда прыгать.
Попутно шаг 1 вытаскивает спикеров (по меткам вроде «Имя:» или «[Имя]»), проставляет таймкод начала каждой секции, считает слова и время чтения из расчёта 200 слов в минуту, а текст чистит: схлопывает лишние пробелы, чинит фразы, разорванные склейкой субтитров, и экранирует HTML-символы.
Есть и защита от крайностей: секция длиннее 3000 слов режется по границам абзацев автоматически, а если секций получилось всего одна или две — генератор предупреждает и предлагает поделить по времени.
А теперь вопрос без единственного правильного ответа, тот самый, на котором Марго застряла на полчаса: где вообще проходит граница секции? Спикер сменил тему в середине фразы — это новая секция или продолжение старой? Ответ зависит от того, как читатель будет искать: по темам — режь по смыслу; по ходу разговора — режь по времени. Машина здесь не решает за тебя, она предлагает.
Компромисс: автоматическая нарезка почти никогда не идеальна. Зато она даёт черновик за секунды, а чекпоинт после шага 1 — место, где ты его поправишь одной репликой.
8. Шаг 2: одна страница, которая знает о себе всё
Из чего собран index.html: стили без сборки, SEO-разметка и смысловая структура.
Ключевая мысль: самодостаточная страница index.html с полной SEO-разметкой
Шаг 2 выдаёт главный артефакт курса: самодостаточная страница index.html с полной SEO-разметкой. Самодостаточная — значит весь доклад, всё оформление и все метаданные лежат в одном файле; наружу торчат только два CDN-адреса.
Что внутри:
- Tailwind CSS через CDN — тег
scriptвhead, и оформление работает без единой команды сборки. Рядом обязательная строкаtailwind.config = { darkMode: 'class' }: без неё тёмная тема просто не включится. - Font Awesome через CDN — иконки луны и солнца, лупы, копирования, гамбургер-меню.
- SEO-разметка целиком — Open Graph и Twitter Card для красивой карточки в мессенджере, плюс структурные данные JSON-LD:
Articleдля текстового доклада и дополнительноVideoObject, если было видео. - Смысловые теги —
header,nav,main,article,section,footerвместо россыпиdiv: и поисковику понятнее, и программе чтения с экрана. - Содержимое — все секции доклада с уникальными якорями, боковое оглавление на широком экране и гамбургер-меню на узком, встроенное видео в контейнере с фиксированным соотношением сторон.
Марго проверила эффект самой дешёвой проверкой: кинула ссылку в чат сообщества. Раньше прилетала голая ссылка, теперь — карточка с заголовком, описанием и обложкой видео. Работает та самая разметка Open Graph, которую легко счесть необязательной.
Компромисс: один большой файл проще публиковать и невозможно «недоложить», но его тяжелее править руками и он целиком перегенерируется при любом изменении текста. Для доклада, который пишется один раз, это правильная сторона размена.
9. Шаг 3: оживляем страницу без фреймворков
Поиск, оглавление, тёмная тема и одна ловушка порядка загрузки.
Ключевая мысль: интерактивность на ванильном JavaScript без фреймворков
Шаг 3 выдаёт docs/static/app.js — и вот тут курс делает заявление, которое обычно не верят с первого раза: вся интерактивность написана на ванильном JavaScript без фреймворков, в одном файле, с нулём зависимостей.
Что в этом файле живёт:
- Поиск по всему тексту — модалка по Ctrl/Cmd+K, задержка 300 мс перед запросом, подсветка найденного и кусочек контекста вокруг;
- Слежение за оглавлением — активный пункт подсвечивается через
IntersectionObserver, без единого обработчика прокрутки; - Тёмная тема — переключатель с запоминанием выбора в
localStorageи подхватом системной настройки при первом визите; - Полоса прогресса чтения — обновляется через
requestAnimationFrame, а не на каждом событии прокрутки; - Кнопка «наверх» — появляется после 500 пикселей прокрутки;
- Копирование цитаты — кнопка у каждой секции, обработчик один на всю страницу через делегирование по атрибуту
data-copy; - Мобильная навигация — гамбургер, закрытие по клику вне панели и по выбору пункта.
Отдельно — ловушка, из-за которой Марго полчаса ловила «иногда не работает». Если на странице есть видео, YouTube вызывает onYouTubeIframeAPIReady, как только загрузится его скрипт, — и это может случиться раньше, чем сработает DOMContentLoaded. Поэтому обработчик регистрируется на верхнем уровне файла, до всего остального. Спрятать его внутрь DOMContentLoaded — значит получить переход по таймкодам, который работает через раз в зависимости от скорости сети.
И два обязательных предохранителя: escapeHtml не даёт тексту доклада превратиться в разметку, а escapeRegex не даёт символу из поискового запроса сломать регулярное выражение. Пользовательский текст — всегда данные, никогда не код.
Компромисс: без фреймворка нет привычной сборки состояния, и всё держится на аккуратности с идентификаторами блоков. Взамен файл читается целиком за один присест, не устаревает вместе с чужими версиями и грузится мгновенно.
10. Шаг 4: публикация из папки docs
Рабочий процесс GitHub Pages, два способа публикации и типичная ошибка с путём.
Ключевая мысль: публикация из папки docs без шага сборки
Сайт готов и лежит на диске. Шаг 4 отвечает на вопрос «как его увидят люди», и ответ у него один: публикация из папки docs без шага сборки.
Генератор кладёт рядом .github/workflows/deploy.yml. Что в нём важно понимать:
- Запуск — по отправке в ветку
mainи вручную черезworkflow_dispatch. - Права —
pages: writeиid-token: write: без них GitHub откажет в публикации. - Группа параллелизма
pagesс отменой предыдущего запуска — два одновременных выкладывания не подерутся. - Загрузка артефакта с
path: 'docs'— именно эта строка говорит, какую папку публиковать. - Никакого шага сборки в рабочем процессе нет вообще: публиковать нечего собирать.
Потом одна ручная настройка в репозитории: Settings → Pages, источник «GitHub Actions». Есть и второй способ, попроще: источник «Deploy from a branch», ветка main, папка /docs — тогда рабочий процесс необязателен. Марго выбрала первый, потому что в журнале Actions видно, когда и что выложилось.
И грабли, на которые она наступила: она попросила вывести сайт в папку site/ вместо docs/, а path: 'docs' в рабочем процессе остался прежним. Публикация прошла успешно и выложила пустоту. Сменил папку вывода — поменяй путь в рабочем процессе.
Попутно шаг 4 создаёт или обновляет README.md: описание, ссылка на живой сайт, список возможностей и ссылка на исходное видео.
Компромисс: GitHub Pages бесплатен и не требует обслуживания, но привязывает тебя к GitHub и к публичной раздаче статики. Для архива докладов сообщества это ровно то, что нужно.
11. Шаг 5: проверка вместо веры
Чеклист из восьми групп и лестница проверок от самой дешёвой к самой дорогой.
Ключевая мысль: проверка вывода по чеклисту, а не на веру
Последний шаг существует ровно потому, что «выглядит нормально» — это не результат. Шаг 5 — проверка вывода по чеклисту, а не на веру.
Чеклист идёт по восьми группам:
- Файлы на месте —
docs/index.htmlбольше 10 КБ,docs/static/app.jsбольше 5 КБ,style.css,deploy.yml,README.mdсуществуют. - Структура страницы — объявление типа документа,
lang, кодировка,viewport, непустой заголовок, описание, Open Graph, Twitter Card, JSON-LD, подключения Tailwind, Font Awesome иapp.js. - Содержимое — все якоря секций уникальны, число секций совпадает с итогом шага 1, нет пустых секций и не осталось ни одного
{placeholder}или[TODO]. - Поведение — на месте
escapeHtmlиescapeRegex, слежение за оглавлением черезIntersectionObserver, а для видео — обработчик готовности плеера на верхнем уровне. - Доступность — ссылка «к содержимому» перед шапкой, роли
bannerиmain, подпись у бокового меню, роль диалога у поиска, доступные подписи у кнопок-иконок. - Отзывчивость — гамбургер скрыт на широком экране, панель выезжает на узком, текст читается без горизонтальной прокрутки на ширине 320 пикселей.
- Тёмная тема — у каждого светлого класса есть парный тёмный, и конфигурация Tailwind задана.
- SEO и печать — заголовки в разметке совпадают, а
style.cssсодержит правила печати.
Поверх чеклиста — две детерминированные проверки, которые ничего не стоят. node --check docs/static/app.js ловит синтаксическую ошибку до читателя. grep -c '</html>' docs/index.html обязан вернуть ровно 1: не ноль (файл оборвался) и не два (генератор дописал вторую копию). Ровно так Марго нашла обрезанный файл после большого доклада — глазами она бы этого не увидела, потому что верх страницы выглядел безупречно.
Твоя очередь решать. Полный чеклист — это восемь групп и десятки пунктов, и проходить их все каждый раз никто не будет. Выбери три пункта, которые ты будешь проверять всегда, и обоснуй выбор: какая поломка тебе обойдётся дороже всего — незакрытый тег, сломанный поиск или отсутствующая ссылка «к содержимому»? Правильного ответа тут нет, есть твой контекст.
Компромисс: чеклист длинный и его легко пролистать не читая. Зато каждая его строка — это чья-то уже случившаяся поломка, а не гипотеза.
12. Грабли, которые уже собрали за тебя
Список известных ошибок и стратегия работы с очень большим транскриптом.
Ключевая мысль: антипаттерны генератора и стратегия большого транскрипта
Самая приятная страница документации этого пакета — таблица, в которой перечислены антипаттерны генератора: не советы, а список уже случившихся поломок с признаком и лечением.
Вот те, что стоят внимания:
- React или Vite для простого доклада — лишняя сложность там, где хватает статики.
- Доклад, разложенный по нескольким HTML-страницам — вместо одной страницы с якорями; поиск ломается, а навигация становится перезагрузкой.
- Забытый тег Tailwind или строка darkMode — страница без оформления либо с мёртвым переключателем темы.
- Меньше трёх секций — навигации нет, значит, весь смысл сайта потерян.
- Секция длиннее 3000 слов — стена текста внутри страницы против стены текста.
- Поиск без сообщения «ничего не найдено» — пустой экран читается как поломка.
- Встроенное видео фиксированной ширины — на телефоне уезжает за край; нужен контейнер с соотношением сторон.
- Нет запасного пути, если yt-dlp не установлен — падение вместо внятного отказа.
Отдельно — правило, которое спасает чужие репозитории: папка вывода никогда не перезаписывается молча. Если docs/ уже существует, генератор спрашивает: перезаписать, отменить или писать в другую папку.
И финальная история, ради которой Марго вообще дочитала документацию. Её самый длинный доклад дал транскрипт на сорок тысяч слов, а страница на выходе оборвалась на середине. Для таких случаев есть стратегия большого транскрипта — писать не одним куском, а в четыре приёма: сначала оболочка страницы, потом секции пачками по 5–10, потом закрывающие теги, потом проверка целостности. Порог — примерно 30 000 слов, то есть около 150 КБ готового HTML.
Компромисс: запись в четыре приёма медленнее одной большой и требует аккуратности с закрытием тегов. Зато результат не обрывается — а обрыв, напомним, глазами не виден, потому что верх страницы выглядит идеально.
Частые вопросы
- У меня нет YouTube-ссылки, только текстовый файл. Пакет вообще нужен?
Да, это основной сценарий. Ссылка нужна только для встроенного плеера и переходов по таймкодам. На вход принимаются .txt, .md, .srt и .vtt, и весь остальной конвейер работает одинаково.
- Обязательно ли ставить yt-dlp?
Нет. yt-dlp нужен ровно в одном случае — когда вы подаёте ссылку на YouTube и хотите, чтобы генератор сам достал субтитры. Если его нет, шаг 0 честно скажет об этом и предложит вставить текст расшифровки вручную.
- Как посмотреть, что установка изменит в проекте, ничего не сломав?
Запустите npx @dzhechkov/skills-transcript-site init --dry-run: это сухой прогон, он печатает список файлов и не трогает диск. После установки состояние показывает doctor, а список компонентов — list.
- Почему тёмная тема не переключается?
В девяти случаях из десяти в head отсутствует строка tailwind.config = { darkMode: 'class' }. Без неё классы dark: в разметке ничего не значат. Это первый пункт в списке антипаттернов.
- Я вывел сайт не в docs/, а в другую папку — почему по ссылке пусто?
Путь к папке указан ещё и в .github/workflows/deploy.yml в строке path: 'docs'. Смените папку вывода — поменяйте и его, иначе рабочий процесс успешно опубликует пустоту.
- Транскрипт очень длинный, страница обрывается. Что делать?
Начиная примерно с 30 000 слов используйте стратегию большого транскрипта: сначала оболочка страницы, затем секции пачками по 5–10, затем закрывающие теги, затем проверка целостности. Контрольная команда — grep -c '</html>' docs/index.html, ответ должен быть ровно 1.
- Нужно ли запоминать все команды из курса?
Нет. Внутри Claude Code достаточно попросить словами: «сделай сайт из этой расшифровки» или «покажи, что установлено». Команды в курсе нужны, чтобы вы понимали, что происходит под капотом, и могли проверить результат сами.