Открой два окна — зал увидит песню
Это окно — большой экран зала. В ·16 «СУФЛЁР» включи галочку «⌇ в зал» — слова, колбаски и счёт полетят сюда без единого сервера (BroadcastChannel, фолбэк — localStorage). Из этого окна можно рулить плеером СУФЛЁРА кнопками пульта. Телевизор с браузером = экран зала; ноутбук/телефон = сцена.
Пульт команды летят в ·16 СУФЛЁР
Команды применяются в том окне СУФЛЁРА, где включена трансляция. Зал ничего не скачивает и не играет — он только показывает.
Демо проверка зала без СУФЛЁРА
Демо имитирует источник: поток STATE с нотами, счётом и словами. Так проверяют зал на одном устройстве — второе окно с «ЗАЛом» должно оживить в ту же секунду.
⤳ Телефон = микрофон и пульт air-gapped WebRTC · SQ1-SQ2 · по ТЗ KARAOKE_TREND
Сигналинг (QR/код) передаётся один раз любым способом — дальше связь чистый P2P:
RTCPeerConnection(iceServers: []), DataChannel singulyar_p2p_data
(ordered: false, maxRetransmits: 0). Ни роутера-сервера, ни облака: голос и команды летят напрямую.
python -m http.server).
Протокол открытый, версионированный
Канал singulyar-hall, пакеты {ver:1, t:HELLO|STATE|CMD|BYE|CRDT|CRDTHI|CRDTSNAP, src, seq, ts, v:значение для seek, …}.
Транспорт-двойник: BroadcastChannel + localStorage-события, дедуп по src:seq. Зал — только
рендер и пульт; аудио всегда живёт в окне сцены (·16). CRDT-конверты несут свой src реплики —
транспорт их не перезаписывает.
Синхрон CRDT · сходится во всех окнах
Очередь событий + CRDT (GSet / ORSet / LWW-регистр): каждое окно — своя реплика,
сходятся к одному значению без ведущего. ★ — тумблер: второе нажатие снимает метку (OR-set —
снимаются наблюдённые теги, новая метка возвращает песню). ♪ — последнее слово побеждает
детерминированно (лэмпорт + src). Опоздавшее окно догоняет снимком; офлайн-окно доотправляет
журнал при встрече; повторная доставка не меняет результат. Журнал живёт в памяти окна —
честно. Канон: ДОКУМЕНТЫ/ТРЕКИ/LADOM_SINGULAR/src/sync-crdt.js — тот же файл,
что гоняют тесты трека (18/18). Существующий STATE/CMD не тронут.
Круг своих локальные профили · согласие · повторный контакт без QR
Первый контакт — по-прежнему QR/код (физика air-gapped WebRTC: SDP свеж при каждой
встрече); рукопожатие по открытому каналу записывает профиль в круг. Повторный контакт — по памяти
круга, без повторного QR: зал держит рендеву krug-ключ — мост вкладок того же браузера
(чистый офлайн) и комната Nostr-релеев между устройствами (как звонки ·23; релеям нужен интернет —
честная пометка, сам контакт остаётся P2P). Через рендеву зал доставляет свежий оффер WebRTC — канал
встаёт как при QR. Согласие живёт только на твоём устройстве: «разрешено» впускает без вопроса,
«спрошено» спрашивает, «запрещено» — честный отказ, «забыть» удаляет профиль. Канон:
ДОКУМЕНТЫ/ТРЕКИ/LADOM_SINGULAR/src/krug-profiles.js — тот же файл, что гоняют тесты
трека (22/22).
ЭФИР ДОМА · mesh-wire/0.1 (М1, этап 2 — такт v11.29 «КОНТУР»)
Лестница: вещание (вкладки этого браузера, BroadcastChannel) → данные (мост КС5) → релей (КС8). При импорте — ноль подключений; эфир открывается только по твоей кнопке.
вещание: ждёт · данные: не собраны · релей: не собран