.words.json, тайминги до миллисекунд), эти транскрипты и становятся якорем синхрона.creation_time в контейнерах. Не нужно: для одной камеры (линейная сборка) и когда есть общий таймкод (jam-sync).истина = creation_time + Δ_cam. Одно Δ на камеру на день — за смену дрейф кварца незаметен (<1с).T_k (имя файла — только начальное приближение).r_ik — позицию начала клипа на таймлайне куска: creation_time_i + Δ_cam(i) ≈ T_k + r_ik.ct + Δ_cam — она уже откалибрована остальными клипами.
t_chunk − t_clip. Плотный кластер голосов = кандидат-совпадение; медиана кластера = измерение. ASR-ошибки не мешают: голосуют только совпавшие триграммы, а их тысячи.
--ref-cam): её клипы становятся якорным пулом, рамка = её часы, T фиксированы. Остальные камеры пришиваются рёбрами. Важно: в якорный пул идут все транскрипты опорной камеры (даже клипы, не попавшие в выборку) — больше рёбер, точнее Δ. Так собрано интервью YTUVI-706: ZVE1 пришит к FX3A (кварц ZVE1 спешил на +3м15с).Синхрон, который нельзя проверить, не существует. Каждый уровень ловит свой класс ошибок; все пять зелёные → можно строить таймлайн.
wordsync.py --selftest — сгенерированный «день» с врущим именем куска и настоящим эхом дубля. Проверяет и решатель, и защиту от эха (echo_rejections ≥ 1). Гоняется после любого изменения кода.ct + Δ_cam. Норма < 1с (тип. 0.2–0.6с). Большой резидуал = клип пришит к чужому дублю или у камеры нестабильные часы — смотреть руками.gap ≈ 0. На YTUVI-704 сплит-пары сошлись в +0.006с / −0.054с / +0.014с — независимое подтверждение всей системы. Зазор в секунды = решение неверно.wall_offset до/после — идентичны до мс. Проверяется diff'ом двух прогонов.validate_ingest.py — все требования UXP-билдера, включая ТИХИЕ отказы (fallback в linear, выпадение петли, «unknown_cam», коллизии имён — билдер резолвит клипы по имени глобально). qc_html.py — тёмная витрина: таймлайн дня, часы камер, поправки имён, рёбра/эхо/резидуалы каждого клипа, первые слова матча.~/YTAI/scripts/999_extra/wordsync_multicam/ — README там = полный контракт билдера и грабли. Подробный ранбук для пошагового исполнения (в т.ч. слабыми моделями): scripts/05_editing/0500_uxp/docs/wordsync/WORDSYNC_RUNBOOK.md.
# 1. решить день (петля)
python3 wordsync.py --day /Volumes/DISK/DAY --cam-map "CAM1=CAM1_Name,..."
# 1'. решить день (без петли)
python3 wordsync.py --day /Volumes/DISK/DAY --ref-cam CAM1-FX3A --only-file selected.txt
# 2. ingest + симлинк-раскладка (мультикам-сцена; --add = merge в общий ingest)
python3 make_ingest.py --project PROJ --scene 05_Interview --add \
--result .../_wordsync/wordsync_result.json --cam-order CAM1,CAM2
# 2'. линейная сцена (selects/b-roll, одна дорожка)
python3 make_ingest.py --project PROJ --scene 04_Stones --add \
--linear --files-from stones.txt --folder STONES
# 3. проверки + витрина
python3 validate_ingest.py PROJ/00_Setup/01_Ingest/CODE_ingest.json
python3 qc_html.py --result .../wordsync_result.json --tr .../Transcription --out qc.html
# 4. Premiere → UXP «YTAI Assembly» → Ingest → Build Ingest
Ingest готов и провалидирован → дальше всё делает UXP-панель «YTAI Assembly». Дорожки раскладывает не Premiere и не ты — их на 100% задаёт ingest. Ниже — как загрузить, собрать и убедиться, что легло ровно.
{PROJECT}.prproj. Панель грузится через Adobe UXP Developer Tool: Add Plugin → выбрать ~/YTAI/scripts/05_editing/0500_uxp/manifest.json → Load. В Premiere появится панель «YTAI Assembly» (id com.ytai.assembly.panel). Если панель уже грузилась раньше — в UDT просто Load/Reload.{PROJECT}/00_Setup/01_Ingest/{CODE}_ingest.json (код проекта берётся из имени папки по ^(YT[A-Z]{2,4}\d+)_). Кнопка Build Ingest должна стать активной.files:{} или битый JSON. Прогони validate_ingest.py — он назовёт точную причину.layout_mode:"wallclock" или хоть у одного клипа нет числового wall_offset). Наш генератор это исключает, но если ingest правили руками — validate_ingest поймает.{CODE}_{scene} (напр. YTUVI01_04_Studio). Клипы каждой камеры лягут на свою V-дорожку на позиции wall_offset; недостающие дорожки создаются автоматически, лимита нет.cam_layers[scene] в ingest, слева направо: первый элемент → V1, второй → V2… Задаётся флагом --cam-order у make_ingest.py. Имена в массиве обязаны байт-в-байт совпадать с именами папок-родителей клипов (симлинк-папки камер) — иначе клипы камеры молча выпадут (warning unknown_cam в логе панели).--cam-order "CAM1_VostorgB,CAM2_VostorgA,CAM3_VostorgC,CAM4_FX3" → V1 = B (основная), V2 = A (верхняя, руки), V3 = C (детали), V4 = FX3 (лайв) · A1–A4 звук камер · A5 петля DJI.--cam-order (wall_offset'ы не изменятся — проверено diff'ом) → в панели снова Build Ingest → панель построит НОВУЮ секвенцию с правильным порядком → старую удалить или переименовать в *_old, чтобы не путаться. Финальная докрутка синхрона (если нужна): панель Offset / Sync Audio / Export Audio Map.Offset/Sync Audio.