Анимированная диаграмма последовательности: от кода Mermaid до видео и сайта с озвучкой

Я сделал редактор, в котором диаграмма последовательности превращается в презентацию с голосом диктора. Диаграмму можно писать кодом Mermaid или собирать мышью, а потом выгрузить как видео или как сайт на GitHub Pages. Попробовать можно здесь: evsikoff.github.io/sequence-diagram-animator.
Откуда взялась задача
В моём проекте для хакатона есть окно с презентацией выдуманной интеграции с внешним сервисом. Это диаграмма последовательности с озвучкой: пока диктор говорит, стрелки прорисовываются одна за другой. Прошлые сцены становятся серыми, схема прокручивается за последней стрелкой, а сцены переключаются автоматически или стрелками на клавиатуре.
Сделано это было вручную: отдельный React-компонент на 500 строк и JSON со сценарием. Для следующей такой презентации пришлось бы писать всё заново. Поэтому я решил сделать из этого инструмент.
Что я хотел от инструмента:
делить диаграмму на реплики диктора;
для каждой реплики решать, какие элементы показать, какие подсветить и какую часть схемы видит камера;
выгружать результат в видео;
выгружать результат в web-приложение на GitHub, где, как в оригинале, переключаются эпизоды.
Сначала поискал готовое
Хотелось взять инструмент с открытым кодом, в котором диаграмму можно править и кодом, и мышью, и добавить к нему анимацию. Вот что нашлось:
Инструмент | Лицензия | Кодом | Мышью | В чём дело |
|---|---|---|---|---|
MIT | да | нет | Стандарт «диаграмм как кода»: GitHub и GitLab рисуют его сами. Визуальный редактор есть только платный | |
GPL-3.0 и другие сборки | да | нет | Самый полный UML, но работает на Java | |
MIT | да | нет | Свой синтаксис, правка только текстом | |
MPL-2.0 | да | нет | Умеет пошаговые сценарии, визуальный D2 Studio платный | |
Apache-2.0 | разовый импорт | да | Обратной связи с кодом нет | |
Apache-2.0 | Python API | да | Настоящий UML-моделлер, но десктопный и без анимации | |
закрытая | да | да | Лучше всех сочетает код и мышь, но код закрыт |
Вывод оказался простым. Веб-инструмента с открытым кодом, где диаграмма последовательности синхронно правится кодом и мышью, нет. Анимации по репликам нет нигде.
Поэтому за основу я взял язык Mermaid, а всё остальное сделал сам: визуальный редактор, анимацию и экспорт. Код диаграммы остаётся обычным Mermaid, его можно вставить в README на GitHub.
Диаграмма: кодом и мышью
Слева в редакторе код Mermaid, в центре схема, справа свойства выделенного элемента. Правка в любом из мест сразу видна в остальных.
Что можно делать мышью:
щёлкнуть по элементу — он выделится, а в коде подсветится его строка;
перетащить участника влево или вправо, а сообщение — выше или ниже;
нарисовать стрелку от одной линии жизни к другой — получится новое сообщение;
дважды щёлкнуть по подписи и поправить её прямо на схеме;
обернуть сообщение во фрагмент
alt,loop,optи другие, добавить заметку или разделитель.
Редактор пишет обычный Mermaid. Я прогоняю его через настоящий парсер Mermaid 12 в тестах, чтобы не разойтись со стандартом. Расширение одно — разделитель, он же граница эпизода. Для Mermaid это просто комментарий:
sequenceDiagram
participant user as Пользователь<br/>браузер
participant portal as Портал<br/>сервер
participant idp as ID партнёра<br/>Keycloak
%% == 1. Вход через ID партнёра ==
user->>portal: Связать профиль<br/>{partner_id}
portal-->>user: 302 → вход партнёра<br/>client_id=portal, PKCE
user->>idp: Логин, пароль, код 2FAПервая строка подписи рисуется над стрелкой, вторая — мелким моноширинным шрифтом под ней. Стрелки — по нотации UML: вызов сплошной линией с закрашенным наконечником, ответ пунктиром, асинхронное событие открытым наконечником.
Анимация: эпизоды и реплики
Презентация делится на эпизоды, эпизод — на реплики. Эпизод — это то, между чем переключается зритель. Реплика — одна фраза диктора, она же субтитр.
Для каждой реплики задаётся три вещи:
Что показано. Каждый элемент диаграммы скрыт, показан или приглушён. Это накапливается: сообщение, показанное в третьей реплике, остаётся на схеме, пока его не скроют.
Что подсвечено. Подсветка действует только в этой реплике: диктор говорит о Keycloak — Keycloak светится.
Куда смотрит камера. Автоматически камера следит за новыми стрелками. Можно вписать в кадр выбранные элементы, показать всю диаграмму или просто нарисовать кадр прямоугольником на схеме.

В режиме «Анимация» схема показывает конец выбранной реплики. Скрытые элементы видны бледно, оранжевая рамка — кадр камеры. Инструментами «Показать», «Подсветить» и «Приглушить» достаточно щёлкать по элементам. То же самое делается в таблице элементов справа.
Раскладывать сообщения по репликам вручную не обязательно. Кнопка «Разбить…» заводит эпизод на каждом разделителе и реплику на каждые N сообщений. Длинный текст диктора делится на реплики по предложениям.
Озвучка
Запись можно загрузить файлом или записать с микрофона прямо в редакторе. Для неё есть два варианта:
одна запись на эпизод — тогда реплики становятся метками внутри неё; метки без значения расставляются пропорционально длине текста;
своя запись у каждой реплики — тогда реплика длится столько, сколько её запись.
Нет записи — реплика идёт в темпе чтения, 14 символов в секунду.
Экспорт: видео и сайт
Видео
Видео собирается прямо в браузере, без сервера. Кадры рисуются на канвасе, кодируются WebCodecs через библиотеку mediabunny, а записи диктора сводятся в одну дорожку.
Размер кадра: Full HD, HD, 4K, вертикальное и квадратное видео.
Субтитры с текстом диктора — по желанию.
Формат: MP4 (H.264 там, где браузер его кодирует, иначе VP9) или WebM.
Рендер идёт быстрее реального времени: в моих тестах 55 секунд видео 960×540 собирались за 6 секунд. Если нужно без интерфейса, есть команда:
npm run render -- diagram.mmd diagram.mp4На вход она принимает проект или просто код Mermaid. Во втором случае нарезка на эпизоды и реплики делается автоматически.
Web-приложение
Второй вариант — статический сайт с плеером. В нём, как в оригинале, эпизоды переключаются кнопками «Назад» и «Вперёд», списком и стрелками на клавиатуре. Щелчок по схеме и пробел ставят паузу. Номер эпизода попадает в адрес, так что ссылкой можно поделиться.

Сайт можно скачать ZIP-архивом или сразу опубликовать на GitHub. Для публикации редактор просит токен, создаёт репозиторий, делает один коммит и включает GitHub Pages. В репозитории оказывается код плеера, диаграмма в Mermaid, сценарий, записи и workflow для Pages.
Экспортированный сайт открывается даже просто из папки, двойным щелчком по index.html. А его project.json можно снова открыть в редакторе и доправить.
Как это устроено внутри
Три решения, без которых всё развалилось бы.
Устойчивые id элементов. Реплика ссылается на сообщения диаграммы. Если вставить строку в код или переименовать участника, ссылки не должны съехать. Код Mermaid id не хранит, поэтому после каждой правки новые элементы сопоставляются со старыми: сначала по наибольшей общей подпоследовательности, затем по типу в промежутках. Сообщение с исправленным текстом остаётся тем же сообщением.
Кадр как функция времени. Что видно в момент t эпизода, считается одной детерминированной функцией. Она возвращает, насколько прорисована каждая стрелка, что приглушено, что подсвечено и где камера. Поэтому предпросмотр, плеер на сайте и видео показывают один и тот же кадр.
Один рендер на всё. Раскладка превращается в список примитивов: линии, прямоугольники, текст. Этот список рисуется в SVG в редакторе и плеере и на канвасе при экспорте видео. Отдельной «видео-версии» диаграммы нет.
Ещё о проверках: 37 unit-тестов и 10 e2e-тестов в Playwright. Последние кликают по схеме, рисуют стрелку, экспортируют видео и открывают выгруженный сайт.
Чего пока нет
Синтеза речи. Записи диктора нужно загрузить или наговорить самому. Голос браузера есть только для прослушивания реплики, в видео он не попадает.
H.264 везде. Это зависит от браузера: Chrome, Edge и Safari его кодируют, сборки Chromium без проприетарных кодеков — нет.
Импорта PlantUML. Пока только Mermaid.
Точной синхронизации с речью. Если запись одна на эпизод, границы реплик ставятся пропорционально тексту, а не по фактическим паузам. Точное начало реплики придётся указать руками.
Попробовать
Редактор работает в браузере, регистрация не нужна: evsikoff.github.io/sequence-diagram-animator. Проект сохраняется в браузере, на сервер ничего не уходит.
С чего начать:
Откройте пример: «Файл → Пример: связка профиля с партнёром». Это вход по OpenID Connect, вебхук и сверка — шесть эпизодов с озвучкой.
Нажмите «▶ Смотреть».
Переключитесь в режим «Анимация» и поменяйте, что подсвечено в какой-нибудь реплике.
Вставьте свой код Mermaid и нажмите «Разбить…».
Исходники лежат на GitHub: Evsikoff/sequence-diagram-animator. Буду рад замечаниям в комментариях и в issues: особенно интересно, каких конструкций Mermaid и каких форматов экспорта вам не хватает.
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.