Перейти к содержанию

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 для работающих однофайловых заготовок.

Рабочий процесс

  1. Выберите паттерн из таблицы выше на основе задачи пользователя.
  2. Начните с шаблона:
    • templates/hello-orb-flow.html — текст, обтекающий движущуюся сферу (паттерн «обтекание препятствия»)
    • templates/donut-orbit.html — продвинутый пример: измеренные ASCII-препятствия в виде логотипов, перетаскиваемая проволочная сфера/куб, морфинг полей форм, выбираемый DOM-текст и отладочные элементы управления
    • write_file в новый .html в /tmp/ или в рабочую директорию пользователя.
  3. Замените текст на осмысленный в соответствии с задачей. Реальная проза, 10–100 предложений, без lorem.
  4. Настройте эстетику — шрифт, палитру, композицию, взаимодействие. Это основная работа; не пропускайте.
  5. Проверьте локально: [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.

Частые ошибки

  1. Расхождение строк шрифта CSS/canvas. ctx.font = "16px Inter" измерено, но CSS говорит font-family: Inter, sans-serif; font-size: 16px. Всё хорошо, если Inter загрузится. Если Inter возвращает 404, CSS откатывается к sans-serif, и измерения расходятся на 5–20%. Всегда preload шрифт или используйте веб-безопасное семейство.
  2. Переподготовка внутри цикла анимации. Только layout* дёшев. Повторный вызов prepare на каждом кадре убьёт производительность. Держите подготовленный хендл в области видимости модуля.
  3. Забыли проIntl.Segmenter для разделения графем. Эмодзи, комбинирующие символы, CJK — "é".split("") даёт два символа. Используйте new Intl.Segmenter(undefined, { granularity: "grapheme" }) при извлечении отдельных видимых глифов.
  4. Чипы break: 'never' без extraWidth. В rich-inline, если вы используете break: 'never' для атомарного чипа/упоминания, вы также должны указать extraWidth для отступов пилюли — иначе оформление чипа выйдет за пределы контейнера.
  5. Использование@chenglou/pretext из unpkg с TypeScript-точкой входа. Используйте esm.sh — он автоматически компилирует TypeScript-экспорты в готовый для браузера ESM. unpkg вернёт 404 или отдаст сырой TypeScript.
  6. Моноширинные запасные варианты молча стирают весь смысл. Пользователи, видящие вывод, похожий на моноширинный, часто имеют CSS font-family, который откатился до monospace. Проверяйте фактически отображаемый шрифт через DevTools.
  7. Пропуск строк вместо настройки ширины при обтекании фигуры. Если коридор на этой строке слишком узок для строки, пропустите строку (y += lineHeight; continue;), а не передавайте крошечную maxWidth в layoutNextLineRange — pretext вернёт строки из одной графемы, которые будут выглядеть поломанными.
  8. Сдача холодного демо. Первый кадр по умолчанию выглядит как учебный. Добавьте: виньетку, незаметные линии развёртки, автоматическое движение в простое, одну тщательно выбранную интерактивную реакцию (перетаскивание, наведение, прокрутка, клик). Без этого «крутое демо 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 × Pretextgithub.com/shinichimochizuki/tetris-pretext * Dragon animationgithub.com/qtakmalay/PreTextExperiments * Somnai editorial enginegithub.com/somnai-dreams/pretext-demos * Bad Apple!! ASCIIgithub.com/frmlinn/bad-apple-pretext * Drag-sprite reflowgithub.com/dokobot/pretext-demo * Alarmy editorial clockgithub.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 — измерение и рендеринг самостоятельно * Полезные вспомогательные функции * Паттерны для демо-рецептов * Рабочий процесс * Замечания по производительности * Частые ошибки * Чек-лист проверки * Справочник: демо сообщества