Попросить языковую модель собрать презентацию несложно. Трудности начинаются потом, когда на готовом слайде надо поправить одну строку: слайды вышли, а править их нечем. Либо это картинки, либо разметка, в которую страшно лезть. Dashi PPT решает задачу с другого конца: модель не рисует слайды, а заполняет текстом готовые макеты, и на выходе получается не файл, а веб-редактор, в котором у каждого слайда своя панель настроек.
Репозиторий создан 10 июня 2026 года, у него больше девяти тысяч звёзд и восьмисот форков. README обещает 12 тем, 1020 макетов и экспорт в настоящий редактируемый PPTX. Я разобрал исходный код версии 0.4.14 и сверил обещания с тем, что написано в скриптах. Сам инструмент я не запускал, поэтому всё ниже — о коде, а не о поведении в работе.
Коротко о результате. Большая часть обещаний кодом подтверждается. Но в нескольких местах README и код говорят разное — в том числе про сеть и про то, кому виден локальный сервер. А самая интересная часть проекта закрыта. Теперь по порядку.
Что это и из чего состоит
Dashi PPT — не приложение и не сервис, а навык (skill) для ИИ-агента: папка с инструкцией SKILL.md, генератором на Node.js и набором скриптов. Агент читает инструкцию, сам вызывает скрипты и отдаёт пользователю ссылку на готовую презентацию. Нужен агент с доступом к файлам и командной строке. Для веб-чатов без локального окружения навык не годится, и README говорит об этом прямо — за это ему плюс.
Папка навыка весит около 56 МБ ещё до установки зависимостей. Внутри:
project/src— рендер на React 18, исходники читаемые;project/scripts— запросы к каталогу макетов, проверки, сервер предпросмотра, экспорт;project/dist/theme-runtime— 24 готовых минифицированных бандла с компонентами тем;project/packages/html-deck-to-pptx— движок экспорта, тоже только в собранном виде;project/layout-manifest.json— каталог макетов на 3,5 МБ;project/assets— шаблон редактора, 186 файлов шрифтов, иконки.
Первым делом я пересчитал цифры из README по каталогу макетов. Сошлось: в нём ровно 12 тем, 1020 макетов и 8576 элементов управления. Из них 4276 переключателей, 2372 ползунка и 1825 выпадающих списков. На один макет приходится от одного до пятнадцати элементов, в среднем около восьми.
А вот «20 ролей страниц» — обложка, оглавление, метрики, тренд, сравнение, риски и так далее — в каталоге не записаны. Роль макету назначается в момент поиска, по ключевым словам в его названии. То есть это таксономия для запроса, а не свойство макета. Не обман, но цифра из README звучит весомее, чем есть на деле.
Свободного выбора цвета нет: палитра — это список из готовых вариантов. Автор объясняет это в FAQ: стабильный результат важнее произвольной раскраски. Я с ним согласен: чем меньше свободы у модели в оформлении, тем меньше шансов получить неожиданный слайд.
Как агент собирает презентацию
Раз модель не рисует слайды, то чем она занята? Инструкция ведёт агента по жёсткому маршруту. Писать HTML слайдов руками ему запрещено.
- Бриф. Тема, цель, аудитория, число страниц. По умолчанию около десяти, не меньше восьми.
- Тема и медиа. Агент обязан показать пользователю картинку с двенадцатью темами и спросить, нужны ли изображения. Выбирать за пользователя разрешено, только если тот прямо сказал «решай сам».
- Подбор макетов. Команда
layout:queryвозвращает кандидатов по теме и роли страницы. Выбор зависит от зерна случайности, поэтому при том же зерне и тех же входных данных макеты получаются те же. - Контракт макета.
inspect:layoutсообщает, какие у макета текстовые поля, сколько символов в них помещается и сколько элементов видно в списках. - Содержание. Агент пишет
page-content-pack.json: у каждой страницы одна главная мысль, заголовок и резюме в полной и короткой форме, факты, данные для графика. - План.
goal:scaffoldпревращает содержание вgoal.json— полное описание презентации. - Рендер. Один скрипт проверяет план, собирает HTML, проверяет результат и поднимает сервер предпросмотра.
Сам скрипт рендера короткий. По нему хорошо видно, сколько проверок стоит вокруг генерации:
npm run props:safe -- --goal "$SPEC_PATH" --write
npm run validate:goal-spec -- "$SPEC_PATH"
npm run render:goal -- "$SPEC_PATH" "$OUT_PATH"
npm run validate:swiss -- "$OUT_PATH"
npm run validate:goal-copy -- "$SPEC_PATH" "$OUT_PATH"
npm run preview:start -- "$OUT_DIR" "$PREVIEW_PORT"
Шесть строк, и собственно рендер из них — одна. До рендера план сверяется со схемой, после — готовый HTML сверяется с планом: все ли файлы на месте и весь ли текст из плана дошёл до страницы. В текстовых полях проверка пропускает только простые теги вроде <b>, <em> и <br>; остальные теги, обработчики событий и ссылки javascript: отклоняются. Вот это мне нравится: тексту, который написала модель, здесь не верят на слово.
После машинных проверок инструкция требует от агента приёмки по смыслу: попадает ли презентация в цель, все ли выводы на месте, не остался ли демо-текст из шаблона. Статусов три — принято, нужна правка, заблокировано. На исправления даётся два круга.
Четыре варианта каждой страницы
Маршрут объясняет, как получается одна страница. Но генератор делает не одну. Главное архитектурное решение проекта — правило «три плюс один»: на каждую логическую страницу выходит четыре варианта.
- Три шаблонных: настоящие макеты из каталога, в которых заменён только текст. Оформление, структура, число блоков и тип графика остаются как в макете.
- Один авторский: агент сам раскладывает страницу на сетке 12 × 8 из семи типов элементов — текст, метрика, список, цитата, медиа, фигура, график. Цвета и шрифты наследуются от темы, свободный HTML и стили запрещены схемой, элементов не больше 32.
Содержание страницы хранится один раз, а варианты получают его через таблицу соответствий: какое поле макета откуда брать. Поэтому переключение между вариантами не теряет текст.
В предпросмотре десять логических страниц превращаются в сорок физических слайдов, и на каждой странице можно выбрать вариант. Экспортировать можно либо все сорок, либо только выбранные.
Бесплатно это не даётся. Цена — токены и время: каждая страница описывается и рендерится четырежды. В README названа оценка в 100 тысяч токенов на десять страниц. Размен честный: вместо «переделай слайд» человек просто выбирает другой вариант. Но платит за этот выбор он заранее и за все страницы сразу.
Редактор внутри готового файла
Выбрать вариант — половина дела, дальше слайд хочется поправить. Результат лежит в папке output/<имя>/ppt/: файл index.html и каталог assets/ с библиотеками, шрифтами и картинками темы. Шрифты и текстуры разложены локально, презентация открывается без интернета.
Редактор — часть самого файла. Его код лежит в шаблоне страницы на 476 КБ и написан на обычном читаемом JavaScript без фреймворка; React отвечает только за содержимое слайдов. В редакторе можно править текст кликом, менять картинки перетаскиванием, двигать ползунки панели, переставлять, скрывать и дублировать страницы, включать режим показа.
Автосохранение устроено в два слоя. Каждая правка сразу пишется в хранилище браузера, а через две секунды уходит на локальный сервер. Сервер принимает только известные поля состояния — порядок слайдов, скрытые и удалённые страницы, текст, параметры, выбранные варианты — и переписывает блок состояния прямо в index.html. Вставленные картинки при этом сохраняются файлами в assets/user-media/.
Отсюда следствие, о котором легко не подумать: файл презентации сам себя изменяет, но только пока открыт через сервер навыка. Если открыть index.html двойным кликом или раздать его любым другим статическим сервером, правки останутся в браузере и до файла не дойдут. Инструкция запрещает агенту подменять сервер именно по этой причине. Решение остроумное, но хрупкое: вся схема держится на том, что файл открыли правильным способом.
Сервер предпросмотра
Значит, без сервера редактор наполовину не работает, и на сервер стоит посмотреть внимательнее. Он запускается отдельным фоновым процессом и переживает сессию агента. По умолчанию завершается сам после четырёх часов простоя. Порт по умолчанию 5200; если он занят, перебираются следующие.
Про доступность сервера README и код расходятся. В README сказано, что предпросмотр доступен в локальной сети для просмотра. Меня это насторожило, и я пошёл искать строку с адресом. В коде адрес по умолчанию — 127.0.0.1, а для сети нужно явно задать переменную:
const host = process.env.DASHI_PPT_PREVIEW_HOST || process.env.HOST || '127.0.0.1';
Редкий случай: код безопаснее документации. Но если сервер всё же открыть в сеть, стоит понимать, как он защищён. Пароля и токена нет. Запросы к /api/* — сохранение и экспорт — проверяются по заголовкам Origin и Referer: источник должен быть из списка разрешённых. При открытии в сеть в этот список попадают и адреса машины в локальной сети. Запросы без обоих заголовков принимаются, только когда сервер слушает локальный адрес. Статические файлы презентации отдаются без проверок. По коду выходит, что браузер с другой машины в той же сети, открывший страницу, сможет и сохранять правки; на практике это поведение не подтверждено. Я бы в сеть этот сервер не выставлял.
HTTP и HTTPS живут на одном порту: сервер смотрит на первый байт соединения и сам решает, поднимать ли TLS. Сертификат самоподписанный, на 365 дней, создаётся системным openssl и лежит в папке навыка.
Экспорт в PPTX и PDF
Редактор в браузере — это хорошо, но презентацию обычно просят прислать файлом. Экспорт в PPTX — самая интересная и самая закрытая часть проекта. Сервер запускает браузер без интерфейса через playwright-core, открывает в нём собственную страницу предпросмотра и передаёт её движку html-deck-to-pptx. Движок обходит живой DOM активного слайда и собирает файл через библиотеку pptxgenjs:
- текстовые узлы становятся обычными текстовыми блоками PowerPoint с подбором шрифта и межстрочного интервала;
- прямоугольники и рамки — фигурами;
- то, что в формат не переводится (градиенты, SVG, маски, шейдерные фоны), снимается картинкой, а текст поверх извлекается из DOM отдельно, без распознавания.
Дальше хотелось прочитать, как движок выбирает между фигурой и картинкой. Не вышло: он распространяется только в собранном виде, и точные правила по коду не прослеживаются. В описании пакета названа доля редактируемых элементов 0,851; набор тестов, на котором она получена, в репозиторий не входит. Так что цифру остаётся принять на веру, а я такие цифры принимать не люблю. FAQ формулирует осторожнее: PowerPoint не умеет всего, что умеет HTML, но редактируемость сохраняется, где возможно.
Если сервер не может запустить браузер, PPTX собирается прямо в браузере пользователя и загружается на сервер готовым файлом.
PDF устроен проще: это снимки страниц, собранные в файл. Выделяемого текста в таком PDF нет.
Для экспорта нужен Chrome, Chromium или Edge. Путь к нему можно задать переменной CHROME_PATH; если её нет, скрипт ищет браузер в стандартных местах macOS и Windows. Экспортированные файлы складываются не рядом с презентацией, а в project/output/exports/ внутри папки навыка. Место неочевидное, и ниже станет понятно, почему оно ещё и неудачное.
Что уходит в сеть
Фоновый сервер, скачанный браузер, реестр пакетов — самое время спросить, что из этого выходит наружу. README утверждает: содержимое документов не покидает машину, а к сети обращаются только две вещи — установка зависимостей и тихая проверка версии. Первая часть кодом подтверждается: сетевой телеметрии в читаемом коде нет, запросы редактора идут только на собственный сервер. Вторая часть неполна. Обращений к сети я насчитал не два, а четыре:
| Что | Куда | Когда |
|---|---|---|
| Установка зависимостей | реестр npm или зеркало | первый рендер |
| Проверка доступности реестра | registry.npmjs.org, зеркало |
один раз перед установкой |
| Загрузка браузера для экспорта | серверы Playwright или зеркало | при каждом рендере, если браузера ещё нет |
| Проверка версии | registry.npmmirror.com, registry.npmjs.org, raw.githubusercontent.com |
после каждой задачи |
Проверка версии — обычный GET-запрос без тела и без номера текущей версии, с таймаутом пять секунд. Сам запрос безобидный. Не нравится мне другое: выключателя у него нет. Проверку запускает агент, потому что так написано в инструкции. Отключить её можно, только убрав строку из SKILL.md или сам скрипт.
Отдельная деталь для тех, кто следит за цепочкой поставки: в файле .npmrc проекта по умолчанию прописано китайское зеркало registry.npmmirror.com. Перед первой установкой скрипт проверяет, доступен ли основной реестр npm, и если да — убирает зеркало. Если проверка не прошла, зависимости и браузер ставятся с зеркала. Я бы сделал наоборот: основной реестр по умолчанию, зеркало — по явному желанию.
Содержимое минифицированных бандлов — тем, движка экспорта, библиотеки шейдерных фонов — по коду не проверяется. В библиотеке фонов есть зашитые адреса внешних хранилищ; комментарий в коде говорит, что текстуры сохранены локально как раз чтобы запросов не было, но подтвердить это можно только наблюдением за трафиком.
Установка и запуск
Нужны Node.js 20 или новее и npm; для экспорта — браузер на базе Chromium. Требование к версии Node записано в документации, в коде проверки нет.
npx dashi-ppt-skill@latest
Установщик ищет каталоги навыков в домашней директории — ~/.agents/skills, ~/.codex/skills и ещё два. Здесь README опять расходится с кодом: написано, что навык ставится во все найденные каталоги, а на деле — в один. Во все он ставится только с флагом --all, а при неоднозначности установщик останавливается и просит указать путь через --dir. И снова код осторожнее своего описания.
Обновление — та же команда. Папка навыка заменяется целиком и атомарно, через временный каталог и переименование. Установленные зависимости при этом переносятся. Всё остальное — нет: экспортированные файлы из project/output/ и собственные правки в SKILL.md после обновления пропадают. Вот почему место для экспорта неудачное: готовые PPTX лежат в папке, которую обновление стирает.
Дальше работа идёт через агента: ему отдаётся документ и просьба сделать презентацию. Экспорт доступен из редактора кнопкой и из командной строки:
npm --prefix <папка-проекта> run export:pptx -- <папка-презентации>/ppt out.pptx
npm --prefix <папка-проекта> run export:pdf -- <папка-презентации>/ppt
Полезные переменные окружения:
DASHI_PPT_PREVIEW_PORT— порт сервера;DASHI_PPT_PREVIEW_HOST— адрес, на котором он слушает;DASHI_PPT_PREVIEW_IDLE_HOURS— через сколько часов простоя сервер завершится;CHROME_PATH— путь к браузеру для экспорта.
Лицензии
С лицензиями у проекта три слоя, и читать надо все три.
Корневая лицензия — AGPL-3.0. Пользоваться, менять и распространять можно, в том числе коммерчески; но изменённую версию или сервис на её основе придётся открыть на тех же условиях.
Из этого есть исключение, и оно касается самой ценной части. Движок экспорта html-deck-to-pptx — проприетарный компонент: его разрешено использовать только в составе навыка, а извлекать, распространять отдельно, менять и разбирать запрещено. До версии 0.2.7 он выходил под MIT, и это разрешение действует только для тех версий. В самом пакете при этом осталась рассогласованность: файл лицензии проприетарный, а его README всё ещё называет MIT.
Третий слой — библиотека анимации GSAP, которая копируется в каждую презентацию. Она распространяется по собственной бесплатной лицензии GreenSock, а не по открытой.
Ограничения и риски
Всё, что набралось по ходу разбора, одним списком.
- Открыт не весь код. Оркестрация, проверки, сервер и редактор читаются. Компоненты тем и движок экспорта поставляются только собранными: что именно рисует конкретный макет и как принимается решение при экспорте, по исходникам не проверить.
- Публикуется сборка, а не разработка. Запись о происхождении сборки ссылается на коммит рабочего репозитория, которого в публичном нет, а большинство коммитов называются «Publish skill» с номером версии. Изменения в закрытых частях между версиями по git не проследить.
- Документация на китайском.
SKILL.md, справочники и подписи элементов управления написаны по-китайски. Английский интерфейс редактора собирается из словаря, а для некитайской презентации агент должен явно указать язык в плане. - Фоновый процесс. Сервер живёт до четырёх часов после последнего обращения и пишет сертификат и экспортированные файлы в папку навыка.
- Сервер без аутентификации. Пока он слушает локальный адрес, это приемлемо. Открывать его в сеть стоит, только понимая, что защита — проверка заголовков.
- Зависимость от системных утилит. Для сертификата нужен
openssl, для подготовки медиа —sips(только macOS),magickиffmpeg. - Windows. Есть отдельный скрипт рендера на PowerShell и поиск браузера по путям Windows. При этом проверка живого процесса сервера вызывает
ps; на системе без этой утилиты старый сервер, судя по коду, не будет остановлен перед запуском нового. Поведение не подтверждено тестами. - PDF без текста. Это снимки страниц.
- Оформление в рамках темы. Свои цвета, шрифты и CSS навык менять не даёт — ни пользователю, ни агенту.
- Расход токенов. Четыре варианта каждой страницы стоят вчетверо больше одного.
Итог: кому подойдёт
Что получилось хорошо. Модели оставлена работа, с которой она справляется: разобрать документ на страницы и написать текст нужной длины. Вёрстка, проверки и экспорт вынесены в детерминированный код, а последнее слово — в редактор, где человек доводит результат сам. По-моему, самое ценное в проекте — именно этот подход, а не темы. К хорошему я отношу и проверки вокруг рендера, и адрес 127.0.0.1 по умолчанию.
Что плохо. README в нескольких местах описывает не то, что делает код: сервер в локальной сети, установка во все каталоги, два обращения к сети вместо четырёх. Две части — компоненты тем и движок экспорта — закрыты, и вторая ещё и под проприетарной лицензией. Обновление стирает экспортированные файлы.
Dashi PPT хорошо ложится на типовые рабочие презентации: отчёт, обзор рынка, разбор конкурентов, план проекта, внутреннее обучение. Там важнее цельная структура и аккуратный вид, чем уникальный дизайн, а возможность поправить слайд ползунком экономит круг переписки с агентом.
Он не подойдёт для презентаций в собственном фирменном стиле — темы закрыты и не настраиваются — и для сред, где нельзя ставить зависимости из внешних реестров или держать фоновый процесс. Тем, кому важна проверяемость всего кода, стоит помнить о двух закрытых частях: проверить их по исходникам не получится.