С бета-сборки 12.10.283300 от 8 октября клиент Telegram для macOS несёт модуль HTMLBubbles: сообщения, свёрстанные на HTML и CSS, со встроенным JavaScript, которые живут прямо в пузыре чата, без окна мини-приложения. 11 октября, в сборке 13.0.283309, к нему добавилась библиотека three.js и три 3D-игры с управлением стрелками. Касается это пока только тех, кто стоит на бета-канале macOS: модуль работает на демо-переписках, зашитых в саму сборку, и серверного типа сообщения под него в схеме API нет.
Что лежит в сборке
Бета macOS раздаётся через фид обновлений mac-updates.telegram.org, и каждая сборка — обычный zip с приложением. В 12.10.283299 модуля нет, в 12.10.283300 рядом с ресурсами появляется пакет HTMLBubbles_HTMLBubbles.bundle. Сборку разобрали в тот же день.
Внутри пакета — двенадцать файлов .chat. Это не данные с сервера, а сценарии демо-переписок: заголовок, список участников с цветами аватарок и сообщения, каждое из которых — кусок HTML со своими <style> и <script>. Названия говорят о задаче сами: «Design Crew», «Deploy Bot», «Stress Test», «Playground», «Long Reads», «Trip to Lisbon», «Shop Assistant», «Analytics», «Live Scripts», «Code Review», «Game Night», «Motion Lab». Подпись к «Stress Test» прямо называет движок — «что litehtml вытягивает, а что нет».
В строках исполняемого файла лежит каталог демо-сообщений, около полусотни карточек: посадочный талон с вкладками по дням, страница товара с выбором размера и цвета, воронка конверсии, когортное удержание, пул-реквест с кнопкой Approve, CI-сборка с кнопками Promote и Roll back, крестики-нолики против бота, кубики, «которые правда катятся», музыкальный плеер с живым эквалайзером и ответ, «который печатает сам себя, как ИИ».
Отдельный бот-собеседник, HTML Bot, представляется так: каждый ответ — HTML и CSS, сети нет; наберите /, чтобы выбрать сообщение. Там же правило для собственного кода: любой HTML со стилями и скриптом показывается во всю ширину без пузыря, а обёрнутый в <div class="widget"> — внутри пузыря.
Что добавила сборка от 11 октября
В 13.0.283309 в пакете появились две вещи. Первая — lib/three.js весом 1,27 МБ: библиотека three.js ревизии r160 под лицензией MIT, пересобранная, по комментарию в первой строке файла, «для HTML-сообщений» — модуль исполняется одним скриптом и кладёт себя в глобальный объект THREE. Сообщение подключает её не адресом в сети, а внутренней ссылкой app:three.
Вторая — тринадцатая переписка, «3D Lab», с подписью «сцены three.js, нарисованные Metal-рендерером приложения». В ней три сообщения: аркада Chicken Cross, где курица перебегает дороги, демо-сцена «three.js on Metal» и шахматы против бота. Управление в Chicken Cross — стрелки или WASD после клика по полю, Esc отпускает фокус; под полем дублирующие кнопки для мыши.
Там же появилась папка ported со ста с лишним отдельными HTML-файлами — те же демо-сообщения, разложенные по перепискам. Строка «twidget has no port of this card» в бинарнике подсказывает назначение: карточки переносят под второй движок отрисовки и проверяют, какие переехали.
Что это значит для пользователей и разработчиков ботов
Стабильный Telegram для macOS, Telegram Desktop, iOS и Android таких сообщений не показывают. В бете модуль работает на собственных демо-переписках: прислать собеседнику HTML-сообщение со скриптом через сервер нечем — в схеме API (слой 230) нет типа сообщения, который доставлял бы получателю исходную разметку со стилями и скриптом.
Ближайшее публичное — Rich Messages, которые появились в Bot API 10.1 11 июня 2026 года. Бот может отправить сообщение в HTML или Markdown через sendRichMessage, но документация описывает HTML только как способ записи: каждый тег сводится к блоку из фиксированного набора — абзац, заголовок, список, таблица, цитата, раскрывающийся блок, формула, фото, видео. В схеме API это видно по типам: на вход принимается inputRichMessageHTML со строкой разметки, а получатель видит richMessage со списком блоков — тех же, из которых собираются страницы Instant View. Ни тега <script>, ни <style> среди поддерживаемых Bot API не перечисляет.
Связи HTMLBubbles с Rich Messages сборка не показывает: демо-переписки грузятся из пакета внутри приложения, а не из сообщений сервера. Тексты демо зашиты в бинарник по-английски, на платформе переводов macOS их нет.
Как сообщение рисуется в пузыре
Основной путь обходится без браузера. Разметку разбирает litehtml — открытый движок вёрстки HTML и CSS под лицензией BSD, который сам ничего не рисует: он раскладывает элементы по координатам, а отрисовку отдаёт приложению. HTML он читает парсером Gumbo, и отладочные строки Gumbo («Entering adoption agency algorithm», «Noah's ark clause») попали в бинарник вместе с ним. Отрисовку приложение делает само, и у HTML Bot в строках три режима сравнения: litehtml, litehtml-gpu — та же вёрстка с выводом через Metal — и twidget (WebKit).
Скрипт в таком сообщении не правит разметку напрямую. Он объявляет функцию render(), которая возвращает строку HTML для текущего состояния, и обработчики: onAction(name, value) — на клик по элементу с атрибутом data-action, onKey, onPointer и onFocus — для игр. После каждого события клиент вызывает render() и перерисовывает пузырь на месте. Поверх этого — набор помощников для анимации: tween(), animate(), кривые ease.*, transition('pop') для нативной смены содержимого. Статичный HTML вокруг <script> служит запасным видом, если скрипт не запустился.
По тексту демо «Live Scripts», каждый скрипт исполняется в своей песочнице JavaScriptCore — движке JavaScript из состава macOS. Правой кнопкой по карточке открывается «Script Log…» с её консолью, а команда /stats в чате с HTML Bot включает поверх каждого сообщения время отрисовки кадра, частоту кадров, процессор и память — инструмент для замеров, не для пользователя.
Песочница и сеть
Демо «Runaway scripts the sandbox stops» показывает пределы прямо в карточках: бесконечный цикл при загрузке, по их тексту, JavaScriptCore прерывает через 50 мс и оставляет статичный HTML; карточка с кнопкой Hang запускает такой же цикл внутри onAction; таймер, который каждые 100 мс занимает процессор на 40 мс, выбивается из бюджета 200 мс процессорного времени в секунду.
Режим WebKit живёт в отдельном модуле WidgetSandbox и закрыт от сети тремя слоями сразу. Страница получает политику безопасности контента с connect-src 'none' и скриптами только по одноразовому ключу; к WebView подключён список правил, который блокирует все адреса http, https, ws, wss и ftp; перед кодом сообщения из окна удаляются fetch, XMLHttpRequest, WebSocket, EventSource, RTCPeerConnection, воркеры и window.open. Картинки и медиа разрешены только из data: и blob:, файлы вроде three.js отдаются внутренним обработчиком схемы.
Как устроены 3D-сцены
Игры из «3D Lab» пишутся обычным кодом three.js: сцена, ортогональная камера, свет с тенями, геометрия из кубиков. Рендерер создаётся как THREE.WebGLRenderer, но с параметром cornerRadius, которого у three.js нет, — его понимает только обвязка приложения. В бинарнике лежит обвязка для страничного режима WebKit: она подменяет WebGLRenderer наследником, вставляет его холст в элемент с атрибутом data-3d, следит за размером и пробрасывает стрелки, WASD, пробел и Enter в onKey игры — с Cmd, Ctrl или Alt клавиши уходят приложению.
В пузыре, по подписи переписки, ту же сцену рисует Metal-рендерер приложения; в модуле есть классы HTMLBubbleGPU, HTMLBubbleGPUPool и буферы под ресурсы Metal. На Mac без Metal игра показывает заглушку «3D needs a Mac with Metal».
Telegram Serverless и tgcloud.ai
Ни в пакете HTMLBubbles, ни в строках бинарника, ни в схеме API нет ссылок на Telegram Serverless, tgcloud.ai или иной серверный исполнитель: демо-сообщения лежат локально, а у HTML Bot сети нет по построению. Связь между ними пока не подтверждается ничем, кроме совпадения по времени.




