scripts/15_color/ — сквозной, по требованию: не часть run_pipeline, как 3.8 Sync и 0.2 Media Prep. Живой пример — съёмочный день YTEVO03: 163 клипа, три камеры, две гаммы.M01.XML · тег контейнера DJI com.dji.camera.ColorGammaSxS · запись прошлого замера в {CODE}_lut_plan.json) — никаких догадок по имени камеры. Не измерилась — список кандидатов пуст и прогон встаёт. Ровно эта снисходительность стоила дня: 61 клип из 163 (37 %) красился чужой математикой, потому что старый код ставил флаг «mismatch» и ехал дальше.Пока цвет был одной ступенью, в одном кубе жили и проявка, и покраска — и всё это под S-Log3. Снятое в другой гамме красилось чужой математикой.
03_dark_scene у 115 клипов из 163 — не выбор, а петля обратной связи на собственной ошибке.Критерий, который работает, — зажатые тени. Исходники дня проверены: чистого чёрного в них 0,00 %, значит всё зажатое создаёт лут, а не съёмка. Зажатую тень не вернуть ничем.
| Кандидат проявки | Серый клин | Тёмный кадр дня | Кадров зажато |
|---|---|---|---|
Sony S-Log3 · neutral | 12,3 % | 14,9 % | 32 из 132 |
Sony S-Log3 · neutral legacy ✓ выбран | 0,0 % | 0,01 % | 0 из 132 |
DJI D-Log2 · plus | 9,2 % | 55,7 % | — |
DJI D-Log2 · minus ✓ выбран | 6,2 % | 0,11 % | — |
| прежний единственный куб канала | 9,23 % | — | 62 из 132 |
neutral и neutral legacy — один и тот же проявочный лут в двух авторских вариантах, legacy контрастнее; у DJI та же пара называется plus / minus.исходник в LOG ├─ 1. PRE-LUT (необязательно) ── буст динамического диапазона ├─ 2. ПРОЯВОЧНЫЙ ── log → Rec.709, ПО КАМЕРЕ И ГАММЕ. Технический шаг. └─ 3. ПОКРАСОЧНЫЙ ── look поверх нормальной картинки. ДНК канала.
Буст динамического диапазона до проявки. Необязательная: в библиотеке два куба, в витрине выбора не участвует.
log → Rec.709. Решает не вкус, а гамма клипа. Машина даёт кандидатов и рекомендацию числами, человек подписывает.
Характер картинки поверх нормального Rec.709. Единственное по-настоящему вкусовое решение — и одно на весь канал.
| Ступень | Что решает | Кто решает | Уровень | Где живёт решение |
|---|---|---|---|---|
develop проявка | log → Rec.709 | машина считает, подписывает человек | по гамме | YTs/{КАНАЛ}/color_profile.json → develop.{гамма}.lut |
look покраска | характер картинки | человек | один на канал | color_profile.json → look.id |
| экспозиция | сдвиг в стопах | машина считает промах, человек правит | по клипу | {проект}/01_Source/00_LUT/_build/{CODE}_color_choice.json → exposure |
Basic Correction: LUT (проявка) → BasicCorrection3 (здесь Exposure) Creative: LUT (покраска)А решаем мы в обратном порядке: сначала две настройки на весь канал, и только потом экспозиция по каждому клипу под ними. Выбирать экспозицию, не зная look, бессмысленно — он сдвигает яркость. Превью обязано повторять порядок Lumetri, иначе оно врёт про результат в Premiere.
lut3d, а не склеенным кубом. Склейка проявки с покраской точна только для гладких look'ов: замер на реальной паре — Baza 0,98/255, Film 1 23,9/255, GOLD 54,3/255, и уплотнение сетки до 129³ (49 МБ на куб) GOLD не лечит. Критерий «≤ 1/255» из старого хэндоффа недостижим, поэтому склейка — условный путь, а не основной; вопрос решается после пробы Input LUT в Premiere.Одна гамма — один проявочный лут на канале. Клип не «подбирают на глаз»: его гамму читают, по гамме берут запись из профиля канала, из записи — куб. Человек подписывает профиль, а не каждый клип.
RYA-ZVE1-1928.MP4 получил свою проявку1. КЛЮЧ ПЛАНА 12_Site_Blessing/RYA-ZVE1-1928.MP4 слаг 12_Site_Blessing_RYA_ZVE1_1928 # имя без разделителей — ключ выбора человека камера CAM-B_ZVE1 2. ГАММА сырая строка "s-log3-cine" → нормализовано в S-Log3 источник кэш (legacy_lut_plan) # не замер: оригинал — симлинк на карту 3. ПРОФИЛЬ YTs/YTEVO/color_profile.json → develop["S-Log3"].lut develop_source: "профиль: гамма S-Log3" # откуда взялось — записано рядом 4. КУБ sony__slog3_sgamut3cine__rec709__neutral__legacy в проекте YTAI_sony__slog3_sgamut3cine__rec709__neutral__legacy.cube 5. ДАЛЬШЕ экспозиция: витрина +2.0 → Lumetri +4.8 (×2,4) покраска look__newstar # одна на канал, к камере не привязана
+1, Роман поставил +2. Это один из 18 случаев дня, где человек пошёл против машины. Сама экспозиция — 3.8 · 4."12_Site_Blessing/RYA-ZVE1-1928.MP4": {
"gamma": "S-Log3", "gamma_raw": "s-log3-cine", "source": "legacy_lut_plan",
"cam": "CAM-B_ZVE1", "pix_fmt": "yuv422p10le", "size": null, "mtime": null,
"measured": "2026-09-21T10:32:49+0300"
}
size и mtime равны null не по ошибке: оригиналы дня — симлинки на съёмную карту, и пока том не примонтирован, файла для замера нет. Поэтому запись прошлого замера — не кэш «для скорости», а единственный источник гаммы на размонтированной карте. Источник печатается рядом с клипом, чтобы «откуда мы это знаем» читалось глазом, а не лежало в логе.| Гамма | Проявочный лут | Камеры | Клипов дня |
|---|---|---|---|
S-Log3 | sony__slog3_sgamut3cine__rec709__neutral__legacy | CAM-A_FX3 CAM-B_ZVE1 | 101 |
D-Log2 | dji_pocket4p__dlog2__rec709__minus | CAM-C_Pocket | 61 |
Rec.709 | — проявка не нужна | CAM-B_ZVE1 | 1 пропуск |
neutral legacy, minus: полный id нужен манифесту, не глазу. Имя файла в проекте выводится из id с префиксом: YTAI_<id>.cube.color_profile.json как есть# ~/YTAI/YTs/YTEVO/color_profile.json "develop": { "S-Log3": { "lut": "sony__slog3_sgamut3cine__rec709__neutral__legacy", "cameras": ["CAM-A_FX3", "CAM-B_ZVE1"], "decided_by": "roman", "decided_at": "2026-09-22" }, "D-Log2": { "lut": "dji_pocket4p__dlog2__rec709__minus", "cameras": ["CAM-C_Pocket"], "decided_by": "roman", "decided_at": "2026-09-22" } }, "look": { "id": "look__newstar", "decided_by": "roman" }, "exposure": { "target_face_luma": 134 }
134 — не догадка, а выученное по выбору Романа число; она живёт здесь же, потому что переживает проект.Критерий один и измеримый: сколько картинки лут утапливает в чистый чёрный. Зажатую тень не вернуть ничем.
| Куб | Серый клин | Реальные кадры дня | Кадров с зажимом > 1 % |
|---|---|---|---|
DJI D-Log2 plus | 9,23 % | 23,39 % | 52 из 76 |
DJI D-Log2 minus ✓ выбран | 6,15 % | 0,04 % | 0 из 76 |
Sony neutral | 12,31 % | 2,01 % | 32 из 132 |
Sony neutral legacy ✓ выбран | 0,00 % | 0,00 % | 0 из 132 |
старый 02_normal_scene | 15,38 % | 9,23 % | 62 из 132 |
старый 03_dark_scene | 9,23 % | 0,15 % | 1 из 132 |
minus выигрывает у plus всего 6,15 % против 9,23 %, а на реальных кадрах разрыв — 0,04 % против 23,39 %, и 52 испорченных кадра из 76 против нуля.9,23 % у DJI plus — это клин; 9,23 % у 02_normal_scene — это реальные кадры; ещё один 9,23 % — клин у 03_dark_scene. Совпадение случайное, колонки разные. Сравнивать кубы можно только внутри одной колонки: 03_dark_scene с клином 9,23 % портит 1 кадр из 132, а 02_normal_scene с теми же 9,23 % по другой колонке — 62 из 132.| Исход | Когда | Что делает слой | На дне YTEVO03 |
|---|---|---|---|
planned | гамма известна, в профиле есть запись | записывает в план проявку, экспозицию и look | 162 |
skipped штатно | проявлять нечего — клип уже Rec.709 | пропускает с причиной, прогон идёт дальше | 1 |
refused стоп | гамма незнакомая или её нет в профиле канала | называет клип и останавливается — чужой математикой не красит | 0 |
# единственный пропуск дня, как он записан в плане "skipped": { "12_Site_Blessing/RYA-ZVE1-1927.MP4": "снято в Rec.709 — проявка не нужна" }, "refused": {}
RYA-ZVE1-1928.MP4 с той же камеры CAM-B_ZVE1 проявку получил, а 1927 — нет. Это и есть доказательство, что гамма — свойство клипа, а не камеры: одна тушка в один день дала и s-log3-cine, и rec709.refused перестаёт быть доказательством.{проект}/01_Source/00_LUT/ # рабочие кубы ПЛОСКО, без подпапок
YTAI_sony__slog3_sgamut3cine__rec709__neutral__legacy.cube
YTAI_dji_pocket4p__dlog2__rec709__minus.cube
YTAI_look__newstar.cube
README.md
_build/ # кухня выбора
{CODE}_color_choice.json # выбор человека по дню
{CODE}_color_plan.json # раскладка на таймлайн
{CODE}_gamma_cache.json # замер гамм
{CODE}_lut_board.html + _files/ # витрина
{проект}/00_Setup/01_Ingest/{CODE}_lut_plan.json # ⚠️ ЛЕГАСИ, НЕ переезжает
~/YTAI/YTs/{КАНАЛ}/color_profile.json # ДНК канала
~/Library/Application Support/Adobe/Common/LUTs/Input/YTAI/ # проявочные
~/Library/Application Support/Adobe/Common/LUTs/Creative/YTAI/ # покрасочные
Creative, Input, Output. Папки Technical не существует — на этом уже обожглись.{CODE}_lut_plan.json в 00_Setup/01_Ingest/ не переезжает. Это легаси-файл, его читает UXP-панель; он же служит запасным источником гаммы (source: "legacy_lut_plan" в примере выше).manifest.json, 169 записей (develop 137 · look 27 · pre 2 · legacy 3); store/ — 559 МБ, восстанавливается с Shared Drive YTAI (_color/lut_library/). Подробности — 3.8 · 6.YTEVO03_color_plan.json собран и подписан, но Input LUT и Exposure в Premiere программно ни разу не ставились — проба не сделана. Всё выше описывает выбор проявки, а не покрашенный таймлайн. Сам множитель 2,4 тоже выведен из блоба шаблона Lumetri, а не замерен на живой программе — в плане это помечено флагом exposure_verified_against_premiere: false. Писать «у нас автоцветокор на таймлайне» рано.V=~/YTAI/environment/.venv_vlm/bin/python3 # витрина: кадры + кандидаты $V ~/YTAI/scripts/15_color/1502_lut_pick/lut_board.py --project "<путь>" --frames-from <прокси> --jobs 6 # вернуть выбор человека $V ~/YTAI/scripts/15_color/1502_lut_pick/lut_board.py --project "<путь>" --feedback <файл.json> # раскладка: без --apply ничего не пишется python3 ~/YTAI/scripts/15_color/1503_color_apply/color_apply.py --project "<путь>" python3 ~/YTAI/scripts/15_color/1503_color_apply/color_apply.py --project "<путь>" --apply python3 ~/YTAI/scripts/15_color/1503_color_apply/color_apply.py --project "<путь>" --install --apply # свести луты проекта в один дом 00_LUT python3 ~/YTAI/scripts/15_color/lut_home.py --project YTEVO03 --apply
--install копирует кубы в общие папки Adobe. ⚠️ Общая папка читается при старте Premiere: копировать нужно до запуска, изнутри программы уже поздно.Экспозиция — не куб, а число в стопах, и стоит оно между двумя кубами: lut3d(проявка) → exposure → lut3d(look). Проявка одна на гамму, look один на канал, а это число — своё у каждого клипа. В Premiere это слайдер Exposure в Basic Correction: куб непрозрачен, слайдер видно — монтажёр может подвинуть.
exposure в ffmpeg поверх гамма-кодированного Rec.709: это простое умножение кода на 2^X. Lumetri по блобу шаблона идёт цепочкой LUT → Linearize «Gamma 2.4 to Linear» → BasicCorrection3 (Exposure), то есть линеаризует ДО экспозиции. Один и тот же «+1» даёт разную картинку.
# один пиксель клипа RYA-ZVE1-1928, код 64, ступень витрины +1 EV витрина (ffmpeg) 64 · 2^1 = 128 # умножение кода Lumetri, +1 ((64/255)^2.4 · 2^1)^(1/2.4) · 255 ≈ 85 # линеаризация съедает больше половины стопа Lumetri, +2.4 ((64/255)^2.4 · 2^(2.4·1))^(1/2.4) · 255 = 128 # ровно то, что человек видел # тождество, из которого берётся множитель: code · 2^X == ((code/255)^2.4 · 2^(2.4X))^(1/2.4) · 255
стопы Lumetri = 2,4 × стопы витрины — проверено на 30 комбинациях кодов и стопов, расхождений нет. Кадры, которые человек смотрел и утверждал, верны как изображение: расходится только число, и пересчитывается оно одной константой при раскладке. Перевыбирать день не нужно."Gamma 2.4 to Linear" внутри блоба шаблона — это чтение файла, а не замер на живой программе. В раскладке это записано прямо: "exposure_verified_against_premiere": false. До пробы Premiere так и считать.| Ступень витрины | Число в Lumetri | Клипов дня | Что это за клипы |
|---|---|---|---|
| −1,0 | −2,40 | 1 | единственный за день, который пришлось темнить на полный стоп |
| −0,5 | −1,20 | 11 | лицо выше цели — половина ступени вниз |
| +0,0 | 0,00 | 60 | экспозицию не трогаем: лицо уже на цели либо лица на кадре нет |
| +0,5 | +1,20 | 33 | базовая лестница |
| +1,0 | +2,40 | 40 | самая частая ненулевая поправка дня |
| +1,5 | +3,60 | 8 | доборная ступень |
| +2,0 | +4,80 | 3 | здесь лежит RYA-ZVE1-1928 — разбор ниже |
| +2,5 | +6,00 | 6 | максимум дня; в Lumetri это всё ещё внутри ±7 |
12_Site_Blessing/RYA-ZVE1-1927.MP4 пропущен с причиной «снято в Rec.709 — проявка не нужна» и в план не попал. Отказов — 0. Доборные ступени берутся не по порядку: +2.5 встретилась 6 раз, а +2.0 — 3, потому что ladder_for(промах) достраивает лестницу под конкретный промах, а не проходит её подряд.±7 (LUMETRI_EXPOSURE_LIMIT = 7.0, из таблицы параметров шаблона). Витринный потолок ±3 — это EXPOSURE_MAX = 3.0, предел фильтра exposure в ffmpeg; после множителя он превращается в ±7,2, то есть край лестницы в Premiere поставить нельзя. На этом дне пронесло: максимум +2.5 → +6,0, запас есть. Но клип, которому диапазона не хватит, обязан стать отказом с именем, а не молча зажатым числом на границе.12_Site_Blessing_RYA_ZVE1_1928sony__slog3_sgamut3cine__rec709__neutral__legacy — выбрана не по клипу, а по гамме: в раскладке это записано как develop_source: "профиль: гамма S-Log3", и профиль канала держит эту проявку для всей пары CAM-A_FX3 · CAM-B_ZVE1+1.0, человек поставил +2.0 — это один из 18 случаев из 162, где подпись разошлась с рекомендацией; в файле выбора пара лежит целиком: corrected["12_Site_Blessing_RYA_ZVE1_1928"] = [1, 2]. Машина мерит медиану яркости лица и считает промах до цели; человек смотрит на кадр целиком.+4.8 — руками его никто не набирает, пересчёт делает код по константе 2,4.{"gamma":"S-Log3","gamma_raw":"s-log3-cine","source":"legacy_lut_plan",
"cam":"CAM-B_ZVE1","pix_fmt":"yuv422p10le","size":null,"mtime":null,
"measured":"2026-09-21T10:32:49+0300"}
size и mtime — null: оригинал лежит симлинком на съёмную карту, и пока том не примонтирован, сверять нечего. Сырая строка s-log3-cine нормализуется в S-Log3 — в манифесте гамма пишется одним способом.{проект}/01_Source/00_LUT/_build/
YTEVO03_color_choice.json # exposure[слаг] = 2, corrected[слаг] = [1, 2]
YTEVO03_color_plan.json # plan["12_Site_Blessing/RYA-ZVE1-1928.MP4"].exposure = 4.8
YTEVO03_gamma_cache.json # запись выше
YTEVO03_lut_board.html # витрина; кадры рядом — YTEVO03_lut_board_files/
YTEVO03_color_plan.20260922_234159.bak.json # снимок прошлой раскладки, --apply их копит
{проект}/00_Setup/01_Ingest/YTEVO03_lut_plan.json
# ЛЕГАСИ и НЕ переезжает: это он подписан в кэше как source "legacy_lut_plan",
# и его же читает UXP-панель
V=~/YTAI/environment/.venv_vlm/bin/python3 # так +2.0 попал в файл выбора: витрина сохраняет и выходит, ничего не рендерит $V ~/YTAI/scripts/15_color/1502_lut_pick/lut_board.py --project "{путь}" --feedback {файл.json}
| Величина | Кто решает | Где живёт |
|---|---|---|
Цель по лицу target_face_luma | человек — 134, выучена по выбору Романа; TARGET_FACE_LUMA_DEFAULT = 150.0 было стартовой догадкой, именно догадкой | ~/YTAI/YTs/YTEVO/color_profile.json — ДНК канала, переживает проект |
| Промах в стопах | машина — log2(цель / медиана яркости лица) на проявленном кадре | нигде: считается на проб-кадрах и умирает |
Ступень витрины −1.0 … +2.5 | машина предлагает, человек подписывает — 18 правок из 162 | _build/YTEVO03_color_choice.json — ключи exposure и corrected |
| Множитель 2,4 | код — константа пересчёта, руками не набирается | 1502_lut_pick/color_plan.py — LUMETRI_GAMMA = 2.4; color_apply.py только пишет её в раскладку как exposure_multiplier |
Число в Lumetri +4.8 | код — выводится из ступени, в выборе человека не хранится | _build/YTEVO03_color_plan.json — секция plan, поле exposure |
| Правка после раскладки | монтажёр — слайдер открыт, куб непрозрачен | проект Premiere |
Input LUT и Exposure программно не ставились ни разу, проба Premiere не сделана, и раскладка сама это признаёт полем "exposure_verified_against_premiere": false. Раскладка существует как файл, а не как покрашенная секвенция — писать «у нас автоцветокор на таймлайне» рано.
# сухо — только печатает раскладку, в проект не пишет python3 ~/YTAI/scripts/15_color/1503_color_apply/color_apply.py --project "{путь}" # с записью и с установкой кубов в Adobe — на живом Premiere ещё не доказано python3 ~/YTAI/scripts/15_color/1503_color_apply/color_apply.py --project "{путь}" --install --apply
Look ложится на уже нормальный Rec.709 и к камере не привязан. Выбор YTEVO — look__newstar, подписан 22.09.2026.
YTs/{КАНАЛ}/color_profile.json вместе с проявками и целью по лицу, и переживает проект.look__film_1 лежит в покрасочных, а ведёт себя как проявка (наклон 1,47 при пороге 1,41); look__baza сам топит 6,2 % серого клина в чёрное. Ступень берётся из папки-источника, метрика ставит флаг — и только..cube. Переименовал куб — у всех проектов, где этот Look выбран, он «не тот». Поэтому файлы в библиотеке кладутся байт-в-байт и ставятся chmod 0444: они не редактируются руками и не переименовываются. Новое имя — это новый куб, а не правка старого.Этап scripts/15_color/1501_lut_library/. 169 кубов на полке, 3 доехали до дня YTEVO03. Байты неизменяемы, в git лежит только манифест, а имя куба проходит три превращения: имя автора → id → имя при установке.
| Ступень | Кубов | Где лежит | Живой пример — id | В git? |
|---|---|---|---|---|
| develop | 137 | store/develop/ | sony__slog3_sgamut3cine__rec709__neutral__legacy — 101 клип дня YTEVO03dji_pocket4p__dlog2__rec709__minus — 61 клип | байты НЕТ · запись в manifest.json да |
| look | 27 | store/look/ | look__newstar — покраска канала YTEVO, одна на все 162 клипа | байты НЕТ · запись да |
| pre | 2 | store/pre/ | pre__applelog__wdr и pre__any__wdr — приводят к общему знаменателю до проявки; в дне YTEVO03 ни один не участвовал | байты НЕТ · запись да |
| legacy | 3 | store/legacy/{author_slug}/ — сейчас один автор: arthur_popov | legacy_arthur_popov__slog3__rec709__pull ← 01_bright_scene…__flat ← 02_normal_scene · …__push ← 03_dark_sceneстарые имена живут в поле aliases, рядом лежит ATTRIBUTION.md | байты НЕТ · запись да |
| итого | 169 | 1501_lut_library/store/ — 559 МБ | из них в проект YTEVO03 уехало 3: две проявки и один look | manifest.json в git · store/ и */state/ в .gitignore |
lut-manifest-v1 держит на каждый куб sha256, размер, сетку, диалект, вход/выход, вендора и камеру, семейство и вариант, aliases, метрики, evidence, conflicts и confidence. История правок манифеста и есть история библиотеки — байты восстановимы, решения нет.{проект}/01_Source/00_LUT/ # дом лутов: рабочие кубы ПЛОСКО, без подпапок ├── YTAI_sony__slog3_sgamut3cine__rec709__neutral__legacy.cube # проявка Sony · 101 клип · chmod 0444 ├── YTAI_dji_pocket4p__dlog2__rec709__minus.cube # проявка DJI · 61 клип · chmod 0444 ├── YTAI_look__newstar.cube # покраска канала · 162 клипа ├── 01_bright_scene.cube · 02_normal_scene.cube · 03_dark_scene.cube │ # ⚠️ одноступенчатая тройка прошлого поколения — ЕЩЁ ЛЕЖИТ РЯДОМ ├── README.md # пишет lut_home; ⚠️ в v1.0 «рабочей тройкой» названа ещё старая └── _build/ # кухня выбора — монтажёру не нужна, нам через полгода нужна ├── YTEVO03_color_choice.json # выбор человека: 162 экспозиции, 18 правок, look ├── YTEVO03_color_plan.json (+ .bak) # раскладка: клип → проявка + стопы + look ├── YTEVO03_gamma_cache.json # гаммы 163 клипов; переживает размонтированную карту ├── YTEVO03_lut_board.html + _files/ # витрина, по которой выбирали └── YTEVO03_lut_review.html + _files/ # витрина прошлого поколения — оставлена как история {проект}/00_Setup/01_Ingest/YTEVO03_lut_plan.json # ⚠️ ЛЕГАСИ — НЕ переезжает: его читает UXP-панель ~/YTAI/YTs/YTEVO/color_profile.json # ДНК канала: проявки по гаммам, look, цель по лицу 134 ~/YTAI/scripts/15_color/1501_lut_library/ ├── manifest.json # 169 записей — В GIT └── store/ # 559 МБ байтов — НЕ в git, тянется с Drive ~/Library/Application Support/Adobe/Common/LUTs/Input/YTAI/ # проявочные → Basic Correction → Input LUT ~/Library/Application Support/Adobe/Common/LUTs/Creative/YTAI/ # покрасочные → Lumetri → Creative → Look
01_Source/00_LUT/. Всё, как выбирали, — в _build/, рядом с кубами, а не в 00_Setup, куда никто не пойдёт. Правило папки: ничего не удаляем, лишнее — в _build/.YTAI_* лежит одноступенчатая тройка 01_bright_scene · 02_normal_scene · 03_dark_scene, и README.md версии lut_home v1.0 называет рабочей именно её. Пока это не разведено, «открыл папку и взял» не работает: монтажёру надо говорить, какие три из шести.install.project_dir — единственный путь, который едет.{CODE}_lut_plan.json остаётся в 00_Setup/01_Ingest/. Это легаси-файл, его читают UXP-панель и lut_board.py; план ссылается на него как на sources.legacy_lut_plan. Перенести его «для порядка» — сломать чужой работающий код.python3 ~/YTAI/scripts/15_color/lut_home.py --project YTEVO03 # сухо: расскажет, что сделал бы python3 ~/YTAI/scripts/15_color/lut_home.py --project YTEVO03 --apply # свести луты в один дом
Creative / Input / Output. Папки «Technical» НЕ СУЩЕСТВУЕТ — на этом уже обожглись: план выписывается в несуществующий путь, и обнаруживается это только в Premiere. Сверено с диском: в Input/ рядом с нашими уже лежат peresvet.cube и nedosvet.cube прошлого поколения — байт в байт та же пара, что 01_bright_scene и 03_dark_scene. Второе: общая папка Adobe читается при старте Premiere — копировать нужно до запуска, изнутри программы панель уже опоздала.YTEVO03_gamma_cache.json все 163 из 163 записей несут "source": "legacy_lut_plan": гамма взята из старого YTEVO03_lut_plan.json, ffprobe по клипам не ходил. Раскладка по гаммам — S-Log3 101 · D-Log2 61 · Rec.709 1 — ровно повторяет старый план, а не измерение. Поле measured в записи — это когда занесли в кэш, а не чем померили.develop/ {vendor}[_{camera}]__{gamma}_{gamut}__rec709__{family}[__{variant}].cube
look/ look__{name}[__{variant}].cube
pre/ pre__{scope}__{target}.cube
legacy/ {author_slug}/legacy_{author_slug}__{gamma}__rec709__{role}.cube
# герой дня YTEVO03 — проявка, которой покрашен 101 клип из 162
sony__slog3_sgamut3cine__rec709__neutral__legacy
│ │ │ │ │ └───── variant : авторский вариант
│ │ │ │ └────────────── family : семейство, характер проявки
│ │ │ └────────────────────── выход : всегда Rec.709 у проявки
│ │ └─────────────────────────────────── gamut : S-Gamut3.Cine
│ └───────────────────────────────────────── gamma : S-Log3 — вход
└─────────────────────────────────────────────── vendor : Sony
| Блок | В нашем примере | Что значит и откуда взялось |
|---|---|---|
sony | вендор | Из архива-источника Sony SLOG3.zip, не из имени файла: путь архива — доказательство рангом выше имени. В манифесте это видно в evidence: archive:SLOG3 → S-Log3. |
| тушка | её в id нет | Оригинал называется Neutral A7s3-Legacy.cube, в манифесте стоит camera: ["a7s3"] — но S-Log3 одинаков у всех тушек Sony, поэтому тушка в id не пишется. У DJI наоборот, тушка обязательна: dji_pocket4__dlog__rec709__plus и dji_pocket4p__dlog__rec709__plus — два разных куба из двух разных архивов (DJI Pocket 4.zip и DJI Pocket 4p.zip). Выброси тушку — и они схлопнутся в один id. |
slog3_sgamut3cine | вход: S-Log3 / S-Gamut3.Cine | Внутри блока разделители выбрасываются, а не заменяются на _: S-Gamut3.Cine → sgamut3cine, D-Log2 → dlog2. Иначе _ внутри блока размывает границу блоков, которую держит __. |
rec709 | выход | Куда куб приводит картинку. У ступени develop это всегда Rec.709 — проявка кончается нормальным изображением, а не полуфабрикатом. |
neutral | семейство | Замысел автора: нейтральная проявка без характера. Характер — дело ступени look. Семейство может и отсутствовать: у героя-соседа dji_pocket4p__dlog2__rec709__minus в манифесте family: null, и minus стоит уже в слоте варианта. |
legacy | вариант | У Sony их два: neutral и neutral__legacy. В профиль YTEVO встал именно legacy — он единственный дал 0,00 % на клине и 0,00 % на реальных кадрах, против 12,31 % / 2,01 % у соседа neutral. |
push / pull — наша лестница экспозиции (что лут делает), plus / minus — авторский вариант контраста. У одного id не может стоять и то, и другое. Имя описывает, что лут делает, а не каким снят кадр: архивный 01_bright_scene (пересвеченный кадр) лежит в библиотеке как …__pull, потому что он тянет вниз.YTAI_# 1 · имя автора — как пришло из архива, живёт в манифесте и больше нигде orig_name = "Neutral A7s3-Legacy.cube" origin.archive = "Проявочные LUTs для LOG (sony, canon, panasonic, apple)/Sony SLOG3.zip" origin.member = "SLOG3/Neutral A7s3-Legacy.cube" # 2 · id — вечный адрес: по нему ссылаются профиль канала, план и витрина sony__slog3_sgamut3cine__rec709__neutral__legacy store/develop/sony__slog3_sgamut3cine__rec709__neutral__legacy.cube # байты, chmod 0444 # 3 · имя при установке — выводится из id префиксом YTAI_ YTAI_sony__slog3_sgamut3cine__rec709__neutral__legacy.cube → {проект}/01_Source/00_LUT/ # уезжает к монтажёру → ~/Library/…/Adobe/Common/LUTs/Input/YTAI/ # видит Premiere YTAI_look__newstar.cube → ~/Library/…/Adobe/Common/LUTs/Creative/YTAI/
look__newstar.cube в общей Creative-папке рядом с чужими кубами — столкновение, ждущее своего часа: у проекта «тот же Look», а куб под ним другой.id, а не из orig_name. Переименовывать луты в сданных проектах нельзя никогда, значит имя должно быть выводимым и вечным: из id оно получается одной строкой — YTAI_{id}.cube, — а из авторского Neutral A7s3-Legacy.cube не получается ниоткуда.chmod 0444): руками не редактируются и не переименовываются. В проекте у трёх YTAI_* права тоже 0444 — это проверяется глазом в ls -l.store/ — 559 МБ, в репозиторий не кладётся; зеркало — rclone copy (не bisync) в _color/lut_library/ на Shared Drive YTAI. На Drive уезжает весь store целиком — это резерв для новой машины; персональная выборка канала — это те 3 куба, что color_apply кладёт в проект.
V=~/YTAI/environment/.venv_vlm/bin/python3 L=~/YTAI/scripts/15_color/1501_lut_library/lut_lib.py $V $L --validate --deep # проверить store и манифест, посчитать метрики $V $L --list --stage develop --camera pocket4p # фильтр по камере — по СЛАГУ манифеста, не по маркетинговому имени $V $L --sync --push --apply # зеркало store → Shared Drive YTAI (--push — режим по умолчанию) $V $L --sync --pull --apply # восстановить 559 МБ на новой машине python3 ~/YTAI/scripts/15_color/1503_color_apply/color_apply.py --project "<путь>" # сухо python3 ~/YTAI/scripts/15_color/1503_color_apply/color_apply.py --project "<путь>" --install --apply
lut_lib.py режимы --import · --validate · --list · --legacy · --sync взаимоисключающие и обязательные — ровно один за вызов; без --apply ничего не записывается. --camera — подстрока по слагу из манифеста (pocket4p, a7s3): «DJI Pocket 4 Pro» не совпадёт ни с чем и вернёт пустой список. Про квоты и режимы Drive — 0.4 Drive Quota.Input LUT и Exposure ни разу не ставились программно, и проба в Premiere не сделана. В самом плане это записано полем exposure_verified_against_premiere: false. Пока оно false, {CODE}_color_plan.json — это намерение, а не покрашенный день.Два этапа, а не один. 1502_lut_pick/lut_board.py рисует кадры дня и принимает подпись человека; 1503_color_apply/color_apply.py превращает подпись в раскладку по клипам. Витрина ничего в проекте не меняет, кроме своей папки кадров и своей страницы, и обе живут в доме лутов — {проект}/01_Source/00_LUT/_build/.
CAM-A_FX3 49 клипов · CAM-B_ZVE1 53 · CAM-C_Pocket 61. Гаммы: S-Log3 101 · D-Log2 61 · Rec.709 1 — этот один и есть пропуск.V=~/YTAI/environment/.venv_vlm/bin/python3 P="/Volumes/T9-Black-RYA/YTEVO/YTEVO03_Plechko_day" # 1 — витрина: кадры дня через каждого кандидата $V ~/YTAI/scripts/15_color/1502_lut_pick/lut_board.py \ --project "$P" --frames-from ~/Desktop/YTEVO03_01_Source_Proxy --jobs 6 # 2 — подпись: кнопка «скопировать» в витрине отдаёт JSON $V ~/YTAI/scripts/15_color/1502_lut_pick/lut_board.py \ --project "$P" --feedback "~/Downloads/choice.json" # 3 — раскладка: СНАЧАЛА сухо, файл не пишется python3 ~/YTAI/scripts/15_color/1503_color_apply/color_apply.py --project "$P" python3 ~/YTAI/scripts/15_color/1503_color_apply/color_apply.py --project "$P" --apply # 4 — кубы по местам: папки Adobe + дом лутов проекта python3 ~/YTAI/scripts/15_color/1503_color_apply/color_apply.py --project "$P" --install --apply python3 ~/YTAI/scripts/15_color/lut_home.py --project YTEVO03 --apply # свести луты в один дом
| Шаг | Что делает | Что появляется на диске |
|---|---|---|
| 1 витрина | кадр на каждый клип через каждого кандидата, цепочкой проявка → экспозиция → look | _build/YTEVO03_lut_board.html + _build/YTEVO03_lut_board_files/ — 192 кадра, 53 МБ. Имя кадра несёт id проявки:01_Morning_Run_RYA_FX3_1213__sony__slog3_sgamut3cine__rec709__neutral__legacy__exp00.jpg |
| 2 подпись | сохраняет выбор и выходит — ничего не рендерит | _build/YTEVO03_color_choice.json (схема color-choice-v1) и ДНК канала ~/YTAI/YTs/YTEVO/color_profile.json. Печатает: «клипов: 162 · поправлено против машины: 18» |
| 3 раскладка | сводит выбор дня и профиль канала в план по клипам, пересчитывает экспозицию ×2,4 | без --apply — НИЧЕГО, только отчёт в консоль. С --apply: _build/YTEVO03_color_plan.json, прошлая версия уезжает в YTEVO03_color_plan.20260923_100231.bak.json, doc_version растёт (сейчас 3), и всегда переписывается _build/YTEVO03_gamma_cache.json |
| 4 кубы | копирует три куба плана в две папки Adobe и в дом лутов проекта | Input/YTAI/ — две проявочные, Creative/YTAI/ — YTAI_look__newstar.cube, и та же тройка плоско в 01_Source/00_LUT/ рядом с README.md |
01_Source/00_LUT/ уезжает к монтажёру с проектом. ⚠️ У Adobe есть Creative, Input и Output — папки Technical не существует, на ней уже обожглись.{проект}/01_Source/00_LUT/
├── YTAI_sony__slog3_sgamut3cine__rec709__neutral__legacy.cube # рабочие кубы ПЛОСКО
├── YTAI_dji_pocket4p__dlog2__rec709__minus.cube
├── YTAI_look__newstar.cube
├── README.md # что это, откуда, почему выбрано
└── _build/ # кухня выбора, монтажёру не нужна
├── YTEVO03_color_choice.json # выбор человека по дню
├── YTEVO03_color_plan.json # раскладка по клипам, ждёт панель
├── YTEVO03_gamma_cache.json # гаммы клипов, 163 записи
├── YTEVO03_lut_board.html + _files/
└── *.bak.json # прошлые версии плана и кэша
{проект}/00_Setup/01_Ingest/YTEVO03_lut_plan.json # ⚠️ ЛЕГАСИ, НЕ переезжает
~/YTAI/YTs/YTEVO/color_profile.json # ДНК канала
~/Library/Application Support/Adobe/Common/LUTs/Input/YTAI/ # проявочные
~/Library/Application Support/Adobe/Common/LUTs/Creative/YTAI/ # покрасочные
YTAI_<id>.cube. Сами байты в git не лежат — store/ это 559 МБ, восстанавливается с Shared Drive YTAI (_color/lut_library/); в git только manifest.json, 169 записей (137 develop · 27 look · 2 pre · 3 legacy).| Файл | Что внутри | Пишет | Читает |
|---|---|---|---|
_build/{CODE}_color_choice.json | color-choice-v1: проявка по камерам, look__newstar, target_face_luma 134, экспозиция на 162 клипа, corrected — 18 пар «машина, человек», decided_by: roman | lut_board.py --feedback | color_apply.py |
~/YTAI/YTs/{КАНАЛ}/color_profile.json | color-profile-v1, ДНК канала: проявка по гамме (не по камере), один look, цель по лицу | lut_board.py --feedback | color_apply.py для всех будущих дней канала |
_build/{CODE}_gamma_cache.json | gamma-cache-v1: гамма каждого из 163 клипов, сырая строка, камера, pix_fmt, дата записи | lut_board.py при замере и color_apply.py --apply — всегда | color_apply.py, когда оригиналы недоступны |
_build/{CODE}_color_plan.json | color-plan-v1: plan (что ставить), clips (паспорт клипа), develops, look, install, skipped, refused, stats, doc_version | color_apply.py --apply | UXP-панель — когда её напишут |
_build/{CODE}_lut_board.html + _files/ | витрина: кадры дня под каждым кандидатом, кнопка «скопировать выбор» | lut_board.py | человек, глазами |
00_Setup/01_Ingest/{CODE}_lut_plan.json | ⚠️ легаси. Единственный источник гамм этого дня, пока кэш не лёг на диск | инструмент, который уже в архиве | UXP-панель и lut_board.py — поэтому файл не переезжает |
01_Source/00_LUT/README.md | что за кубы лежат в папке, откуда взялись, почему выбраны | lut_home.py --apply | монтажёр |
Герой — 12_Site_Blessing/RYA-ZVE1-1928.MP4, один из 18 клипов дня, где человек пошёл против машины.
// YTEVO03_gamma_cache.json → clips — откуда мы знаем гамму "12_Site_Blessing/RYA-ZVE1-1928.MP4": { "gamma": "S-Log3", "gamma_raw": "s-log3-cine", "source": "legacy_lut_plan", "cam": "CAM-B_ZVE1", "pix_fmt": "yuv422p10le", "size": null, "mtime": null, // оригинал — симлинк на снятую карту "measured": "2026-09-21T10:32:49+0300" } // YTEVO03_color_plan.json → clips — паспорт клипа: что мы про него выяснили "12_Site_Blessing/RYA-ZVE1-1928.MP4": { "scene": "12_Site_Blessing", "clip": "RYA-ZVE1-1928.MP4", "slug": "12_Site_Blessing_RYA_ZVE1_1928", "cam": "CAM-B_ZVE1", "gamma": "S-Log3", "gamma_source": "кэш (legacy_lut_plan)", "develop_source": "профиль: гамма S-Log3", "exposure_preview": 2.0, "exposure_source": "roman", "src": ".../01_Source/12_Site_Blessing/CAM-B_ZVE1/RYA-ZVE1-1928.MP4" } // YTEVO03_color_plan.json → plan — ровно то, что панель поставит на клип "12_Site_Blessing/RYA-ZVE1-1928.MP4": { "develop": "sony__slog3_sgamut3cine__rec709__neutral__legacy", "exposure": 4.8, // 2.0 витрины × 2,4 = стопы Lumetri "look": "look__newstar" }
clips отвечает «почему», plan — «что ставить». Панели нужен второй блок, человеку через полгода — первый. Разделены намеренно: plan читается машиной и не разрастается, clips хранит происхождение каждого решения.develop_source: "профиль: гамма S-Log3", и в color_profile.json у S-Log3 стоит sony__slog3_sgamut3cine__rec709__neutral__legacy с камерами CAM-A_FX3 и CAM-B_ZVE1. Решает гамма, камера идёт справкой.corrected["12_Site_Blessing_RYA_ZVE1_1928"] = [1, 2] — машина предлагала +1, Роман поставил +2. Пара хранится целиком, а не одним итогом: иначе не на чем учить цель target_face_luma 134, которая и выучена по таким расхождениям.source: "legacy_lut_plan", живых замеров 0: оригиналы — симлинки на съёмную карту, и пока карта не в слоте, size и mtime остаются null. Отсюда правило: легаси-файл 00_Setup/01_Ingest/{CODE}_lut_plan.json не переносят и не удаляют.| Витрина, стопы | Lumetri, ×2,4 | Клипов | Доля дня |
|---|---|---|---|
| −1.0 | −2.40 | 1 | 0,6 % |
| −0.5 | −1.20 | 11 | 6,8 % |
| +0.0 | 0 | 60 | 37,0 % |
| +0.5 | +1.20 | 33 | 20,4 % |
| +1.0 | +2.40 | 40 | 24,7 % |
| +1.5 | +3.60 | 8 | 4,9 % |
| +2.0 | +4.80 | 3 | 1,9 % |
| +2.5 | +6.00 | 6 | 3,7 % |
| Итого в плане | 162 | 100 % | |
±7 не достигнут: витринный максимум дня +2,5 даёт +6,0.| Проявка | Клипов | Откуда |
|---|---|---|
sony__slog3_sgamut3cine__rec709__neutral__legacy | 101 | профиль канала, гамма S-Log3 (CAM-A_FX3, CAM-B_ZVE1) |
dji_pocket4p__dlog2__rec709__minus | 61 | профиль канала, гамма D-Log2 (CAM-C_Pocket) |
пропущен 12_Site_Blessing/RYA-ZVE1-1927.MP4 | 1 | skipped: «снято в Rec.709 — проявка не нужна» |
skipped с человеческой причиной. Отказы (refused) — другое: их на этом дне 0.refused — и файл не пишется вовсе. Клип, которому не из чего собрать проявку или чья экспозиция не влезает в ползунок ±7, уходит в refused, и тогда color_apply.py падает с кодом 3, а {CODE}_color_plan.json НЕ ЗАПИСАН — ни целиком, ни частично.
--allow-refused. Флаг есть, он не по умолчанию, и он означает «я посмотрел на причины выше».__lut__<id> в refused — это «куба нет в манифесте» или «не сошёлся sha256»; блок такого лута в план не попадает вообще, чтобы --allow-refused не записал план с дырой на месте проявки.YTEVO03_color_plan.json собран, подписан и лежит на диске — но Input LUT и Exposure ни разу не ставились программно, проба в Premiere не сделана. В самом файле это записано честно: "exposure_verified_against_premiere": false.
code·2^X == ((code/255)^2.4 · 2^(2.4X))^(1/2.4)·255 — но это расчёт, а не проверка на Premiere.DJI Action basic.cube содержит внутри # Mavic 3 Pro, D-Log M, и байт-в-байт тот же файл лежит как DJI OSMO Osmo Nano D-Log M.cube. Модель принимается, только если её подтверждает комментарий внутри куба или человек.S-Log3 → slog3, D-Log2 → dlog2; но «Contr −» и «Contr +» — часть названия, и дописываются явно. Через общую таблицу замен «S-Log3» превращается в sminuslog3.4╤Ç вместо 4р; лечится name.encode('cp437').decode('utf-8'). Имена папок macOS приходят в NFD — любое сравнение только после normalize('NFC', …).._*.cube внутри архивов имеют собственные sha256 и без фильтра по префиксу заводят фантомные записи в манифест.*.cube в .gitignore глобально — нельзя: под git уже лежат 12 кубов (шаблоны папок проектов и бандл UXP-панели). Игнорируется только store/.store не может лежать внутри коллекции-источника — импорт читал бы собственный вывод; проверка стоит на старте.identity_rmse255 — перекрытие 158 из 166, neutral_drift255 — полное, black_share — 141, slope_mid — 43. В папке «проявочные для DJI» лежат 19 кубов с наклоном 0,97–1,38, то есть по поведению look'и. Папка говорит о замысле автора, метрики — о поведении, и это разные вещи..cube быстрее всего меняется КРАСНЫЙ: reshape(N,N,N,3) даёт индексацию [b,g,r]. Перепутать — получить куб, переставляющий каналы в тенях; на глаз ловится не сразу, поэтому самопроверка гоняется на каждом запуске..cube: Resolve (пробелы, LF) и LUT Editor (таб после LUT_3D_SIZE, CRLF, без TITLE). line.split() без аргумента ест оба.white_share для проявки — не флаг: проявки уходят в белое со входа 0,855–0,867, это осознанный ролловф. Предупреждение остаётся только для look'ов.Canon Vision — просадка 0,59/255, это квантование), а перевёрнутая кривая теряет десятки. Отсюда порог 2,0/255.pre — смысл, а не ошибка: Alexa709 to WDR доходит до 1,051, 3,03 % значений вне диапазона. Для develop и look это ошибка.+ / − различается на клине на 3 пункта (9,2 % против 6,2 %), а на материале дня — на 23 (23,4 % против 0,04 %, замер по 76 кадрам). Клин отбирает кандидатов, решают кадры.im.load().content-visibility:auto и contain-intrinsic-size браузер считает раскладку для всех сразу, и прокрутка дёргается.