Движение и есть продукт
Конструкторы тир-листов относятся к раскладке как к документу: перетащил, скачал, забыл. На стриме зрелище — это сам процесс, и там обычные инструменты рассыпаются: карточки прыгают вместо того чтобы ехать, а зритель до финального скриншота не видит ничего.
Rung построен вокруг двух вещей, которые в эфире и важны. Первая — настоящий FLIP: соседи расступаются, а не телепортируются. Вторая — зритель: по открытой ссылке он видит ту же доску в тот же момент, пока стример её собирает.
Что внутри
Настоящий FLIP
Позиции карточек замеряются до и после изменения, разница компенсируется трансформом и отпускается через Web Animations API. Двигается только composited-слой, поэтому три десятка карточек переставляются без просадки кадров.
Перетаскивание своими руками
Хук на Pointer Events: работает мышью и пальцем, потому что HTML5 drag-and-drop на сенсорных экранах не существует. Взятая карточка наклоняется и поднимается тенью — она в руке, а не «выделена».
Режим показа
Доска крупно, карточки раскрываются по одной пробелом, каждая выходит из размытия в шесть пикселей с задержкой по соседям. Это ритм раскрытия под камеру, а не украшение.
Живая ссылка для чата
Открытая страница без входа обновляется через Server-Sent Events прямо во время перетаскивания и годится как Browser Source в OBS. В редакторе видно, сколько человек смотрит.
Отмена вместо диалогов
Документ живёт в редьюсере, прошлые состояния — в стопке, поэтому Ctrl+Z работает для любого изменения. Ошибиться при зрителях должно стоить одно нажатие.
Своё вместо библиотек
FLIP, перетаскивание, роутер и выгрузка PNG написаны руками: canvas вместо html2canvas, семьдесят строк вместо анимационной библиотеки. Зависимости в рантайме — только React и React DOM.