On this page Используйте при создании креативных браузерных демо с @chenglou/pretext — DOM-независимая верстка текста для ASCII-арта, типографического потока вокруг препятствий, игр с текстом как геометрией, кинетической типографики и генеративного искусства на основе текста. По умолчанию создаёт однофайловые HTML-демо.
Метаданные навыка¶
| |
|---|---|
Источник| Встроенный (устанавливается по умолчанию)
Путь| skills/creative/pretext
Версия| 1.0.0
Автор| Hermes Agent
Лицензия| MIT
Теги| creative-coding, typography, pretext, ascii-art, canvas, generative, text-layout, kinetic-typography
Связанные навыки| p5js, claude-design, excalidraw, architecture-diagram
Справочник: полный SKILL.md¶
info Ниже приведено полное определение навыка, которое Hermes загружает при его активации. Это то, что агент видит в качестве инструкций, когда навык активен.
Pretext — креативные демо¶
Обзор¶
@chenglou/pretext — это TypeScript-библиотека размером 15 КБ без зависимостей от Ченга Лу (React core, ReasonML, Midjourney) для DOM-независимого измерения и верстки многострочного текста. Она делает одну вещь: по заданным (text, font, width) возвращает переносы строк, ширину каждой строки, позиции каждой графемы и общую высоту — всё через измерение на canvas, без перекомпоновки.
Звучит как техническая деталь. Это не так. Поскольку библиотека быстрая и геометрическая, она является креативным примитивом: вы можете перекомпоновывать абзацы вокруг движущегося спрайта на 60fps, создавать игры, геометрия уровней которых состоит из реальных слов, управлять ASCII-логотипами через прозу, разбивать текст на частицы с точными начальными позициями каждой графемы или создавать компактные многострочные интерфейсы без лишних вызовов getBoundingClientRect.
Этот навык существует, чтобы Hermes мог создавать крутые демо с его помощью — такие, которые публикуют в X. Смотрите pretext.cool и chenglou.me/pretext для подборки демо сообщества.
Когда использовать¶
Используйте, когда пользователь просит: * «демо pretext» / «крутую штуку на pretext» / «текст как X» * Текст, обтекающий движущуюся фигуру (геройские секции, редакторские макеты, анимированные длинные страницы) * Эффекты ASCII-арта с использованием реальных слов или прозы, а не моноширинных растров * Игры, где игровое поле / препятствия / блоки сделаны из текста (Тетрис из букв, Арканоид из прозы) * Кинетическая типографика с физикой для каждого глифа (разрушение, разброс, стая, поток) * Типографическое генеративное искусство, особенно с нелатинскими или смешанными шрифтами * Многострочные интерфейсы «shrink-wrap» (минимальная ширина контейнера, в который всё ещё помещается текст) * Всё, что требует знания переносов строк до рендеринга
Не используйте для:
* Статических SVG/HTML-страниц, где CSS уже решает задачу компоновки — просто используйте CSS
* Текстовых редакторов, движков общего форматирования (pretext намеренно узконаправлен)
* Преобразования изображения в текст (используйте навыки ascii-art / ascii-video)
* Чистого canvas-генеративного искусства без текста — используйте p5js
Творческий стандарт¶
Это визуальное искусство, отображаемое в браузере. Pretext возвращает числа; вы рисуете объект.
* Не сдавайте демо «hello world». Шаблон hello-orb-flow.html — это отправная точка. Каждое готовое демо должно добавлять осмысленный цвет, движение, композицию и одну визуальную деталь, которую пользователь не просил, но оценит.
* Тёмный фон, тёплая основа, продуманная палитра. Классический янтарь на чёрном (CRT/терминал) работает, но также подходят холодный белый на тёмно-сером (редакторский стиль) и десатурированные пастельные тона (ризограф). Выберите одно и придерживайтесь.
* Пропорциональные шрифты — в этом суть. Вся идея pretext в том, что он «не моноширинный» — используйте это. Применяйте Iowan Old Style, Inter, JetBrains Mono, Helvetica Neue или вариативный шрифт. Никогда не используйте шрифт без засечек по умолчанию.
* Реальный источник/текст, не рыба. Текст должен что-то значить. Короткие манифесты, поэзия, реальный исходный код, найденный текст, сам README библиотеки — никогда не используйте lorem ipsum.
* Отличный первый кадр. Никаких состояний загрузки, пустых кадров. Демо должно выглядеть готовым к публикации в момент открытия.
Стек¶
Один самодостаточный HTML-файл на каждое демо. Без этапа сборки.
Слой| Инструмент| Назначение
|---|---|---
Ядро| @chenglou/pretext через CDN esm.sh| Измерение текста + верстка строк
Рендеринг| HTML5 Canvas 2D| Отрисовка глифов, покадровая композиция
Сегментация| Intl.Segmenter (встроенный)| Разделение на графемы для эмодзи / CJK / комбинирующих символов
Взаимодействие| Сырые DOM-события| Мышь / касание / колесо — без фреймворка
[code]
[/code]
Фиксируйте версию. @0.0.6 на момент написания — проверьте npm на предмет последней версии, если поведение демо отличается.
Два сценария использования¶
Почти всё сводится к одной из этих двух форм. Изучите обе.
Сценарий 1 — измерение с последующим рендерингом через CSS/DOM¶
[code]
const prepared = prepare(text, "16px Inter");
const { height, lineCount } = layout(prepared, 320, 20);
[/code] Вы всё ещё позволяете браузеру рисовать текст. Pretext просто сообщает вам, какой высоты будет блок при заданной ширине, без чтения DOM. Используйте для: * Виртуализированных списков, где строки содержат переносящийся текст * Каменной кладки (masonry) с точной высотой карточек * Проверок «помещается ли эта метка?» на этапе разработки * Предотвращения смещения макета при загрузке удалённого текста
Держитеfont и letterSpacing строго синхронизированными с вашим CSS. Формат ctx.font на canvas (например, "16px Inter", "500 17px 'JetBrains Mono'") должен соответствовать рендерингу в CSS, иначе измерения расходятся.
Сценарий 2 — измерение и рендеринг самостоятельно¶
[code]
const prepared = prepareWithSegments(text, FONT);
const { lines } = layoutWithLines(prepared, 320, 26);
for (let i = 0; i < lines.length; i++) {
ctx.fillText(lines[i].text, 0, i * 26);
}
[/code] Здесь и происходит творческая работа. Вы управляете рисованием, поэтому можете: * Рендерить на canvas, SVG, WebGL или любую систему координат * Применять трансформации для каждого глифа (поворот, дрожание, масштаб, прозрачность) * Использовать метаданные строки (ширину, позиции графем) как геометрию
Для потока с переменной шириной строки (текст вокруг фигуры, текст в кольцевой полосе, текст в непрямоугольной колонке):
[code]
let cursor = { segmentIndex: 0, graphemeIndex: 0 };
let y = 0;
while (true) {
const lineWidth = widthAtY(y); // ваша функция: какой ширины коридор на этой высоте y?
const range = layoutNextLineRange(prepared, cursor, lineWidth);
if (!range) break;
const line = materializeLineRange(prepared, range);
ctx.fillText(line.text, leftEdgeAtY(y), y);
cursor = range.end;
y += lineHeight;
}
[/code] Это самый важный паттерн во всей библиотеке. Именно он реализует «текст, обтекающий перетаскиваемый спрайт» — демо, которое стало вирусным в X.
Полезные вспомогательные функции¶
measureLineStats(prepared, maxWidth)→{ lineCount, maxLineWidth }— самая широкая строка, т.е. ширина многострочного shrink-wrap.walkLineRanges(prepared, maxWidth, callback)— итерация по строкам без выделения строк. Используйте для статистики/физики над графемами, когда символы не нужны.@chenglou/pretext/rich-inline— та же система, но для абзацев, смешивающих шрифты/чипы/упоминания. Импортируйте из подпути.
Паттерны для демо-рецептов¶
Коллекция сообщества (см. references/patterns.md) группируется в несколько сильных паттернов. Выберите один и импровизируйте — не изобретайте новую категорию, если не просили.
Паттерн| Ключевой API| Пример идеи
|---|---|---
Обтекание препятствия| layoutNextLineRange + функция ширины по строкам| Редакторский абзац, разделяющийся вокруг перетаскиваемого спрайта курсора
Игра «текст-как-геометрия»| layoutWithLines + прямоугольники коллизий по строкам| Арканоид, где каждый кирпич — это измеренное слово
Разрушение / частицы| walkLineRanges → координаты (x,y) каждой графемы → физика| Предложение, взрывающееся на буквы по клику
ASCII-препятствия типографика| layoutNextLineRange + измеренные препятствия по строкам| Битмап ASCII-логотип, морфинг форм и перетаскиваемые проволочные объекты, заставляющие текст открываться вокруг их реальной геометрии
Редакторская многоколоночность| layoutNextLineRange на колонку + общий курсор| Анимированный журнальный разворот с выносными цитатами
Кинетический шрифт| layoutWithLines + трансформация строк во времени| Вступление «Звёздных войн», волна, подпрыгивание, глитч
Многострочный shrink-wrap| measureLineStats| Карточка с цитатой, автоматически подстраивающаяся под минимальный контейнер
Смотрите templates/donut-orbit.html и templates/hello-orb-flow.html для работающих однофайловых заготовок.
Рабочий процесс¶
- Выберите паттерн из таблицы выше на основе задачи пользователя.
- Начните с шаблона:
templates/hello-orb-flow.html— текст, обтекающий движущуюся сферу (паттерн «обтекание препятствия»)templates/donut-orbit.html— продвинутый пример: измеренные ASCII-препятствия в виде логотипов, перетаскиваемая проволочная сфера/куб, морфинг полей форм, выбираемый DOM-текст и отладочные элементы управленияwrite_fileв новый.htmlв/tmp/или в рабочую директорию пользователя.
- Замените текст на осмысленный в соответствии с задачей. Реальная проза, 10–100 предложений, без lorem.
- Настройте эстетику — шрифт, палитру, композицию, взаимодействие. Это основная работа; не пропускайте.
- Проверьте локально:
[code] cd
&& python3 -m http.server 8765
# затем откройте http://localhost:8765/.html
[/code]
6. Проверьте консоль — pretext выдаст ошибку, если prepareWithSegments вызван с некорректной строкой шрифта; Intl.Segmenter доступен в каждом современном браузере.
7. Покажите пользователю путь к файлу, а не только код — он хочет его открыть.
Замечания по производительности¶
prepare()/prepareWithSegments()— это дорогой вызов. Делайте его один раз для каждой пары текст+шрифт. Кешируйте хендл.- При изменении размера выполняйте только
layout()/layoutWithLines()— никогда не переподготавливайте. - Для покадровых анимаций, где текст не меняется, но геометрия меняется,
layoutNextLineRangeв плотном цикле достаточно быстр для выполнения на каждом кадре при 60fps для абзацев обычной длины. - При рендеринге ASCII-масок на каждый кадр держите буфер ячеек (
Uint8Array/типизированные массивы), вычисляйте измеренные диапазоны препятствий по строкам из ячеек или проекционной геометрии, объединяйте диапазоны, затем передавайте их вlayoutNextLineRangeперед отрисовкой текста. - Держите визуальную анимацию и анимацию компоновки связанными. Если сфера морфирует в куб, анимируйте как буфер ячеек, так и диапазоны препятствий с одним и тем же значением; иначе демо будет выглядеть нарисованным поверх, а не физически перекомпонованным.
- Для затуханий предпочитайте прозрачность слоя изменению интенсивности глифов или масштаба препятствий. Помещайте временные ASCII-спрайты на отдельный canvas и затухайте canvas с помощью CSS/GSAP opacity, чтобы геометрия не казалась уменьшающейся.
- Установка
ctx.fontна canvas на удивление медленная; устанавливайте её один раз на кадр, если шрифт не меняется, а не перед каждым вызовомfillText.
Частые ошибки¶
- Расхождение строк шрифта CSS/canvas.
ctx.font = "16px Inter"измерено, но CSS говоритfont-family: Inter, sans-serif; font-size: 16px. Всё хорошо, если Inter загрузится. Если Inter возвращает 404, CSS откатывается к sans-serif, и измерения расходятся на 5–20%. Всегдаpreloadшрифт или используйте веб-безопасное семейство. - Переподготовка внутри цикла анимации. Только
layout*дёшев. Повторный вызовprepareна каждом кадре убьёт производительность. Держите подготовленный хендл в области видимости модуля. - Забыли про
Intl.Segmenterдля разделения графем. Эмодзи, комбинирующие символы, CJK —"é".split("")даёт два символа. Используйтеnew Intl.Segmenter(undefined, { granularity: "grapheme" })при извлечении отдельных видимых глифов. - Чипы
break: 'never'безextraWidth. Вrich-inline, если вы используетеbreak: 'never'для атомарного чипа/упоминания, вы также должны указатьextraWidthдля отступов пилюли — иначе оформление чипа выйдет за пределы контейнера. - Использование
@chenglou/pretextизunpkgс TypeScript-точкой входа. Используйтеesm.sh— он автоматически компилирует TypeScript-экспорты в готовый для браузера ESM.unpkgвернёт 404 или отдаст сырой TypeScript. - Моноширинные запасные варианты молча стирают весь смысл. Пользователи, видящие вывод, похожий на моноширинный, часто имеют CSS
font-family, который откатился доmonospace. Проверяйте фактически отображаемый шрифт через DevTools. - Пропуск строк вместо настройки ширины при обтекании фигуры. Если коридор на этой строке слишком узок для строки, пропустите строку (
y += lineHeight; continue;), а не передавайте крошечную maxWidth вlayoutNextLineRange— pretext вернёт строки из одной графемы, которые будут выглядеть поломанными. - Сдача холодного демо. Первый кадр по умолчанию выглядит как учебный. Добавьте: виньетку, незаметные линии развёртки, автоматическое движение в простое, одну тщательно выбранную интерактивную реакцию (перетаскивание, наведение, прокрутка, клик). Без этого «крутое демо pretext» воспринимается как «внутренняя репродукция README».
Чек-лист проверки¶
- Демо — один самодостаточный
.htmlфайл — открывается двойным кликом или черезpython3 -m http.server @chenglou/pretextимпортирован черезesm.shс фиксированной версией- Текст — реальная проза, не lorem ipsum, и соответствует концепции демо
- Строка шрифта, переданная в
prepare, точно соответствует CSS-шрифту prepare()/prepareWithSegments()вызван один раз, не на каждый кадр- Тёмный фон + продуманная палитра — не стандартный белый canvas
- Как минимум одна интерактивная реакция (перетаскивание / наведение / прокрутка / клик) или автоматическое движение в простое
- Проверено локально через
python3 -m http.serverи подтверждено отсутствие ошибок в консоли - 60fps на среднестатистическом ноутбуке (или документированная плавная деградация)
- Одна деталь «сверх ожиданий», которую пользователь не просил
Справочник: демо сообщества¶
Клонируйте для вдохновения / паттернов (все MIT-like, ссылки с pretext.cool):
* Pretext Breaker — арканоид со словами-кирпичами — github.com/rinesh/pretext-breaker
* Tetris × Pretext — github.com/shinichimochizuki/tetris-pretext
* Dragon animation — github.com/qtakmalay/PreTextExperiments
* Somnai editorial engine — github.com/somnai-dreams/pretext-demos
* Bad Apple!! ASCII — github.com/frmlinn/bad-apple-pretext
* Drag-sprite reflow — github.com/dokobot/pretext-demo
* Alarmy editorial clock — github.com/SmisLee/alarmy-pretext-demo
Официальная песочница: chenglou.me/pretext — accordion, bubbles, dynamic-layout, editorial-engine, justification-comparison, masonry, markdown-chat, rich-note. * Метаданные навыка * Справочник: полный SKILL.md * Обзор * Когда использовать * Творческий стандарт * Стек * Два сценария использования * Сценарий 1 — измерение с последующим рендерингом через CSS/DOM * Сценарий 2 — измерение и рендеринг самостоятельно * Полезные вспомогательные функции * Паттерны для демо-рецептов * Рабочий процесс * Замечания по производительности * Частые ошибки * Чек-лист проверки * Справочник: демо сообщества