Веб-студия производства faceless-роликов: стиль, мастер-ассеты, кадры, шоты.
Веб-студия производства faceless-роликов: стиль → мастер-ассеты → сцены и кадры → видеошоты. Документ написан 17.08.2026 после двух раундов брифа с Тимуром и шести направлений ресёрча. При расхождении кода с этим документом прав документ.
Исходники, на которых он стоит: research/R1-gemini-image.md, R2-veo.md, R3a-krea.md, R3b-scenario.md, R4-canvas-ux.md, R5-consistency.md, JTBD.md, конспекты справочника Magnific Spaces (spaces-docs-*.md).
Слово должно означает обязательство: без этого версия не принимается. Слово можно означает разрешённую, но не обязательную возможность. Пометка проверить означает, что факт не удалось подтвердить документацией и он закрывается одним дешёвым тестовым вызовом до боевого прогона.
Три вещи, которые определяют эту версию и которых в текущей системе нет вообще:
Ролик делается не «генерацией картинок», а удержанием одного и того же героя, места и манеры через десятки кадров. У диффузионной модели нет персистентного представления персонажа: каждый вызов это новая выборка, и лицо уплывает. Держат только два механизма: пиксельный якорь (утверждённая картинка, которая идёт референсом) и единый лексикон признаков (одна и та же формулировка во всех промптах). Оба подтверждены ресёрчем, оба ложатся в основу архитектуры.
Поэтому студия это не генератор картинок, а база знаний канала, из которой промпт собирается сам:
стиль канала ──┐ персонаж ├──→ промпт кадра ──→ кадр ──→ клип ──→ шот ролика локация │ предмет ──┘
Ценность системы равна сумме накопленного: залоченные стили, мастер-листы персонажей, паспорта локаций. Скорость одной генерации вторична, потому что дорого стоит не генерация, а пересборка того, что уже было.
Кто пользуется. Один человек, Тимур, за паролем. Совместной работы нет и не планируется. Роль системы в его работе: он режиссёр и приёмщик, система исполнитель и память.
| Входит | Не входит (следующими заходами) |
|---|---|
| Стили канала: библиотека, разбор референсов, фиксация, копии | Сценарий и автораскадровка сцен |
| Мастер-ассеты трёх типов, их состояния и инстансы | Обложки для YouTube |
| Мастер-листы: персонаж, предмет, локация | Озвучка, музыка, звук |
| Сцены, ключевые кадры, роли A и B, дополнительные ракурсы | Монтаж, склейка, экспорт готового ролика |
| Оживление кадров в клипы, дубли, выбор лучшего | Публикация и аналитика |
| Доводка любого результата, дерево итераций | Кисть-маска при доводке |
| Полная прозрачная экономика | Переиспользуемые рецепты цепочек (аналог Flows) |
| Просмотр и приёмка, библиотека канала, поиск | Совместная работа, шаринг, публичные шаблоны |
Решение о границах принято Тимуром в первом раунде брифа: сначала ядро создания ассетов и шотов, остальное после. Каркас под невходящее закладывается там, где это ничего не стоит (типы этапов как данные, слой драйверов моделей), но код под него не пишется.
Gemini 3 Pro Image, Gemini 3.1 Flash Image, Gemini 2.5 Flash Image для картинок, Veo 3.1 в трёх вариантах для видео. Расширение на других вендоров предусмотрено архитектурой (слой драйверов), но в этой версии не подключается.
Система устроена как библиотека компонентов, поэтому аналогия с Figma точная и её стоит держать в голове: мастер-ассет это компонент, состояние это вариант компонента, инстанс это размещённая копия, которая наследует мастера.
| Объект | Что это | Чем удерживается |
|---|---|---|
| Канал | контейнер: формат кадра по умолчанию, свои стили, свои ассеты, свои ролики | — |
| Стиль | манера канала: техника, палитра, свет, оптика, эпоха, анти-признаки | залоченная версия неизменяема навсегда |
| Мастер-ассет | персонаж, локация или предмет с алиасом @hero | якорной картинкой плюс списком признаков |
| Состояние | вариант мастер-ассета: старше, ранен, ночь, зима | ссылкой на родителя, его якорь идёт первым референсом |
| Инстанс | использование ассета в конкретном кадре | живой ссылкой на ассет и выбранное состояние |
| Сцена | момент истории: место, участники, время суток, описание | заводится руками, кадры внутри наследуют её |
| Кадр | один ключевой кадр сцены с ролью A, B или дополнительный ракурс | промптом, якорями и параметрами съёмки |
| Шот | клип, полученный оживлением кадра или пары кадров | кадрами-концами и motion-промптом |
| Ролик | последовательность сцен и шотов | форматом и выбранными стилями |
| Генерация | один факт вызова модели: настройки, входы, результат, цена | неизменяема, в историю только добавляется |
| Итерация | генерация, у которой родителем стоит другая генерация | ссылкой на родителя |
1. Ассет это объект первого класса. Промпт ссылается на @alias, а не переписывает описание. Поправил ассет один раз, поправилось везде, где он снят.
2. Медиа на диске это источник правды, база это индекс. База обязана пересобираться с диска без потери связей.
3. Этапы производства это данные, а не код. Появился новый этап, добавляется запись в каталог, а не ветка if в интерфейсе. На обратном умер video-cabinet.
4. Холст это представление. Он не хранит ничего, кроме раскладки. Ассет, заведённый любым способом, обязан появиться на холсте. Узел, удалённый с холста, не удаляет ассет.
Из ответа Тимура: залоченный стиль редактировать нельзя, для докрутки делается копия, при генерации выбирается один из зафиксированных. Отсюда устройство:
Стиль (залочен)
└─ Мастер-ассет ── собран на стиле S1, якорь A1, признаки T1
├─ Состояние «старше» ── родитель = мастер, референс = A1, признаки = T1 + дельта
└─ Инстанс в кадре ── живая ссылка на (ассет, состояние по выбору)
Три правила, которые нельзя нарушать:
Таблица обязательна к реализации: это ответ на требование «не должно быть конфликтов».
| Ситуация | Поведение системы |
|---|---|
| Кадр собран на стиле S2, ассет в нём собран на S1 | Предупреждение на карточке до запуска: «герой собран на стиле v1, кадр идёт на v2, манера может разойтись». Запуск разрешён |
| Промпт кадра противоречит стиль-блоку (просит другую технику) | Стиль-блок главнее и вклеивается дословно. Конфликтующая фраза в промпте подсвечивается |
| Изменился якорь ассета | Все кадры с его инстансами помечаются «устарело». Пиксели не трогаются, деньги не тратятся |
| Изменилось актуальное состояние ассета | То же: пометка, не перегенерация |
| Два героя назначены в один слот референса | Блокировка запуска: модель не выберет, чьё лицо брать |
| Референсов больше, чем держит выбранная модель | Предупреждение с выбором способа сборки (см. 5.4). Молчаливое отбрасывание запрещено |
| Промпт кадра без стиль-блока | Блокировка: кадры разъедутся по манере |
| Пустое описание сцены | Блокировка: генерировать нечего |
| У персонажа нет профильного ракурса в мастер-листе | Предупреждение: главная причина «лицо плывёт на повороте» |
| Референс взят из предыдущего клипа, цепочка длиннее пяти шагов | Предупреждение о ре-якорении на мастер-лист |
| Выбран режим оживления, несовместимый с моделью | Вход гаснет с объяснением, запуск невозможен |
| Разрешение видео требует фиксированной длительности | Длительность фиксируется автоматически, показывается причина |
| Алиас в промпте не найден среди ассетов канала | Предупреждение: в промпт уйдёт как есть, модель его не поймёт |
Ключевое отличие от версии 1: граф это единственная модель, а не второе представление поверх доменных таблиц. Прошлая попытка провалилась именно из-за двойной модели, где карточки на холсте оставались полупустыми, потому что данные жили в другом месте.
channel(id, slug, name, aspect_default, format, created_at, meta_json)
-- СТИЛЬ: библиотека, лок неизменяем
style(id, channel_id, title, status, guide_json, prompt_en, prompt_ru, negatives,
copied_from_style_id, is_primary, created_at, locked_at)
-- status: draft | locked
-- АССЕТЫ: мастер, состояние как вариант, оба в одной таблице через parent
asset(id, channel_id, kind, alias, name, summary, status,
parent_asset_id, -- NULL у мастера, у состояния = мастер
style_id, -- на каком стиле собран
anchor_image_id, -- утверждённый якорь
sheet_image_id, -- утверждённый мастер-лист
traits_json, -- лексикон признаков, до 4 опорных
created_at)
-- kind: character | location | prop
-- status: draft | anchored | sheeted | stale
-- ГЕНЕРАЦИИ: неизменяемый факт, дерево через parent
generation(id, target_kind, target_id, kind, model, params_json,
prompt_en, prompt_ru, prompt_layers_json, refs_json,
parent_generation_id, -- NULL у корневой, иначе доводка
status, cost_usd_est, cost_usd_real, similarity_score,
error_text, created_at, finished_at)
-- kind: image | image_edit | video | style_extract | prompt_build
image(id, generation_id, path, preview_path, role, width, height, meta_json, created_at)
-- role: ref | candidate | anchor | sheet | keyframe | plate | template
clip(id, generation_id, path, poster_path, duration_sec, resolution, mode, meta_json)
-- РОЛИК, СЦЕНЫ, КАДРЫ, ШОТЫ
video(id, channel_id, slug, title, aspect, status, target_sec, created_at)
scene(id, video_id, idx, title, location_asset_id, time_of_day, summary, style_id)
frame(id, scene_id, role, idx, code, shot_size, camera_angle, camera_move, composition,
lighting, lens, prompt_en, prompt_ru, negatives, model, aspect, quality,
anchor_image_id, status)
-- role: A | B | alt
shot(id, scene_id, frame_a_id, frame_b_id, motion_en, motion_ru, model, duration_sec,
resolution, chosen_clip_id, anchor_distance, status)
-- ИНСТАНСЫ: связь кадра с ассетом, живая ссылка
frame_asset(id, frame_id, asset_id, state_asset_id, role, slot, use_sheet_panel)
-- role: hero | prop | location | style
-- ГРАФ И ХОЛСТ
node(id, scope_kind, scope_id, type, ref_kind, ref_id, x, y, w, h, collapsed, config_json, state)
edge(id, source_node, source_port, target_node, target_port, data_type)
canvas_version(id, scope_kind, scope_id, title, snapshot_json, is_auto, created_at)
-- СПРАВОЧНИКИ И СЛУЖЕБНОЕ
knowledge(id, category, key, name_ru, name_en, fragment_en, description_ru, tags, sort)
model_card(id, model, family, capabilities_json, prices_json, checked_at)
job(id, kind, target_kind, target_id, status, payload_json, progress_json, cost_est,
cost_real, result_json, created_at, started_at, finished_at)
trash(id, object_kind, object_id, payload_json, deleted_at, purge_after)
event(id, at, kind, payload_json)
Данные текущих трёх каналов не переносятся: Тимур разрешил чистый старт. Старая база и медиа остаются на диске нетронутыми, новая пишется рядом.
Требование Тимура, повторённое дважды: интерфейс обязан знать, что умеет выбранная модель, и подстраиваться. Это отдельный слой данных, а не набор условий в коде.
model: gemini-3-pro-image # ключ в системе
vertex_id: gemini-3-pro-image # реальный id в Vertex
name_ru: Gemini 3 Pro Image # что видит человек
family: image | video | vision
tier: draft | final
location: global | us-central1
modes: [text_to_image, edit, sheet] # какие операции доступны
refs:
slots_object: 6 # предметы
slots_character: 5 # персонажи
slots_style: 0 # стилевые референсы
recommended_total: 3 # практический предел качества
exclusive_with: [] # с чем несовместимы референсы
params:
aspect: [1:1, 3:2, 2:3, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9]
quality: [1K, 2K, 4K]
negative_prompt: false # отдельного поля нет, только текстом
seed: unverified
thinking_level: false
constraints:
- quality=4K → cost×2
prices:
per_image: {1K: 0.134, 2K: 0.134, 4K: 0.24}
per_reference: 0.0011
timing:
seconds_per_call: 25
checked_at: 2026-08-17
Интерфейс читает паспорт и гасит недоступные входы и настройки, а рядом пишет причину: не «поле неактивно», а «эта модель не принимает конечный кадр, выбери другую или другой режим». Смета берёт цены оттуда же. Дата проверки видна человеку: цифры стареют.
| Возможность | Gemini 3 Pro Image | Gemini 3.1 Flash Image | Gemini 2.5 Flash Image |
|---|---|---|---|
| Слоты референсов | 6 предметов и 5 персонажей | до 14 всего: 10 предметов, 4 персонажа, 3 стиля | данных нет, держим 2 |
| Практический предел качества | 3, мягкое предупреждение с 4 | 3, мягкое предупреждение с 4 | 2 |
| Разрешения | 1K, 2K, 4K | 0.5K, 1K, 2K, 4K | 1K |
| Цена за изображение | 0.134 / 0.134 / 0.24 | 0.067 / 0.101 / 0.151 | 0.039 (1K) |
| Отдельное поле негатива | нет, вернёт ошибку 400 | нет | нет |
| Маска | только смысловая, словами | то же | то же |
| Многошаговая доводка | да, через идентификатор предыдущего шага | да | да |
| Ручка качества рассуждения | нет | есть, minimal и high | нет |
| Форматы входа | PNG, JPEG, WEBP, HEIC, HEIF | те же | те же |
Прайс проекта занижал стоимость черновой модели: 1K и 2K стояли одинаково по 0.06 при реальных 0.067 и 0.101, то есть кнопка показывала цену на 40 процентов ниже факта на разрешении по умолчанию. Правится в первую очередь: без этого обещание прозрачной экономики пустое. Цены дорогой модели совпали точно.
Отдельный факт для дисциплины: формат .gif в маппинге типов есть, а в списке поддерживаемых форматов Gemini его нет. Убрать, чтобы не получать тихий отказ.
| Возможность | veo-3.1 | veo-3.1-fast | veo-3.1-lite |
|---|---|---|---|
| Оживление первого кадра | да | да | да |
| Первый плюс последний кадр | да | да | проверить |
| Референсы-ингредиенты (ASSET) | до 3 | до 3 | проверить, возможно нет |
| Стилевой референс | скорее нет на всём семействе 3.1 | нет | нет |
| Продление клипа | да, в API есть | да | проверить |
| Длительности | 4, 6, 8 секунд | те же | те же |
| Разрешения | 720p, 1080p, 4K | те же | 720p, 1080p |
| Цена за секунду 720p / 1080p / 4K | 0.40 / 0.40 / 0.60 | 0.10 / 0.12 / 0.30 | 0.05 / 0.08 / нет |
| Негатив отдельным полем | да | да | да |
| Звук | генерируется, отключаемость проверить | то же | то же |
Если переданы референсы-ингредиенты, то поля первого кадра, последнего кадра и продления не поддерживаются. Последний кадр невозможен без первого. Продление начинается от видео, а не от кадра. Отсюда прямое требование к интерфейсу: на карточке оживления явный переключатель режима (кадры или ингредиенты или продление), при котором входы других режимов гаснут. Пять входов, из которых половина молча игнорируется, недопустимы.
Разрешение диктует длительность: 1080p и 4K требуют восьми секунд. Значение проверить одним вызовом, но заложить в паспорт сразу.
Промпт кадра не пишется руками целиком. Он собирается слоями, каждый со своей зоной ответственности, и человек видит его целиком до запуска:
[1] стиль-блок залоченная версия, вклеивается дословно [2] сцена и действие что происходит, с раскрытыми алиасами [3] ремесло крупность, ракурс, композиция, свет, оптика из справочника [4] референсы ролевые обращения: герой с рефа 1, реквизит с рефа 2 [5] идентичность до четырёх опорных признаков каждого участника [6] негативы текстом, потому что отдельного поля у модели нет
Порядок «стиль первым» это осознанное решение, а не ошибка: официальный гайд Google описывает одиночную генерацию с нуля и советует порядок «субъект, контекст, стиль», у нас же стиль это рамка канала на сотни кадров. Доказательств, что порядок меняет качество у этих моделей, ресёрч не нашёл ни в одну сторону.
Ограничение длины: слой идентичности должен резаться по тем же четырём признакам, что и краткое описание ассета. Сейчас в коде описание режется, а идентичность нет, и это единственная найденная нестыковка кода с самим собой. Рабочие примеры индустрии держат три-пять признаков, не абзац.
[1] движение что именно движется в кадре [2] камера одно основное движение, не смесь [3] настроение и свет из гайда стиля и параметров кадра [4] идентичность постоянная клауза против морфинга и лишних людей негативы уходят отдельным полем API, в текст не вклеиваются
Официальная формула Google для Veo: кинематография, субъект, действие, контекст, стиль и атмосфера. Отдельно сказано: определить крупность, ракурс и одно основное движение камеры, не смешивать несколько. Негативы формулировать через то, что должно быть в кадре, а не через «нет» и «без».
Комментарий в текущем коде утверждает, что порядок блоков «так требует Veo». Подтверждения для Veo нет, правило пришло из опыта с другим движком в другом проекте. Переформулировать как нашу практику.
Структурного поля роли у API нет. Роль передаётся текстовой подписью перед каждой картинкой, и это согласуется с официальными примерами Google, где роли называются естественным языком. Требования:
Требование Тимура: должен быть выбор, а не решение за него. Три способа, каждый с честной ценой и последствиями на экране:
| Способ | Как работает | Цена | Когда брать |
|---|---|---|---|
| Поэтапная сборка (по умолчанию для двух и более героев) | первый вызов ставит героя А, результат фиксируется и идёт основой во второй вызов с героем Б | вызовов столько, сколько героев | когда важна узнаваемость лиц |
| Композитный якорь | якоря склеиваются на нашей стороне в одну картинку с подписями и уходят одним слотом | один вызов | когда героев много, а лица не крупным планом |
| Урезание по приоритету | оставляем героев, отбрасываем второстепенный реквизит, честно показывая что отброшено | один вызов | быстрые черновые пробы |
Поэтапная сборка это задокументированное лечение подмены лиц, а не наша выдумка: рекомендация звучит как «собирать по одному персонажу за раз, фиксируя результат». Композит прямого подтверждения не имеет, поэтому он не по умолчанию.
Стиль-блок вклеивается в промпты дословно, без перефразирования агентом. Любая переформулировка на ходу это дрейф манеры.
описание словами ──→ [Создать промпт] ──→ ПРОМПТ (узел, правится)
│
▼
ВАРИАНТЫ (по умолчанию 1)
│ выбрал
▼
ЯКОРЬ ассета
│
▼
МАСТЕР-ЛИСТ (по типу ассета)
Правила этапа промпта:
Правила этапа вариантов:
Одна картинка, панели одного масштаба, ровный серый фон, одна и та же одежда и причёска во всех панелях, нейтральный свет, без реквизита и текста.
Состав пересматривается по итогам ресёрча. Утверждённый 17.08 эталон даёт четыре панели: полный рост спереди и сзади, голова крупно спереди и сзади. Индустрия сходится на четырёх ракурсах (фронт, левый профиль, спина, правый профиль) с обоснованием «четырёхугловая система убирает анатомические ошибки», и во всех рекомендациях по составу отдельно стоит строгий профиль, которого у нас нет. Профиль это ровно то, что держит лицо на поворотах.
Предлагается шесть панелей 3×2: полный рост три четверти спереди, полный рост строгий профиль, полный рост сзади, голова спереди, голова в профиль, голова сзади. Эталон компоновки на зелёном манекене перегенерируется под новую сетку один раз и утверждается Тимуром. Решение за ним: если он оставляет четыре панели, профиль добавляется отдельной панелью пятой.
Механика та же, что утверждена и подтверждена ресёрчем как индустриальная практика: эталон компоновки идёт первым референсом, якорь персонажа вторым, промпт прямо говорит, что зелёное это плейсхолдер и его надо заменить героем.
Если одна панель вышла плохой: две кнопки, по умолчанию доснять эту панель отдельным вызовом и подменить её в листе на нашей стороне, второй вариант перегенерировать лист целиком. Досъёмка дешевле и не ломает остальные панели.
Проблема, названная Тимуром: шаблон не должен навязывать силуэт, предметы не должны плыть в ракурсах, а форма должна наследоваться. Болванка на эталоне работает для человека, но меч и кресло в одну болванку не влезают, а персонажный шаблон индустрии прямо завязан на слова «полный рост, позы».
Так форма гарантированно наследуется от утверждённой картинки, а не от чужой болванки. Проверяется на двух заведомо разных формах: вытянутой (меч, посох) и объёмной (кресло, сундук).
Turnaround для места бессмыслен. Вместо него четыре вида:
Практика «снять место пустым и переиспользовать» задокументирована под именем background plate и подтверждена ресёрчем. Шаг «снять локацию пустой» это первый шаг мастера локации, а не побочный продукт первого сюжетного кадра. Иначе якорем случайно станет кадр с героем, и герой полезет во все следующие кадры этого места.
Состояния локации из коробки: день, ночь, дождь, зима. Механика та же, что у состояний персонажа: референсом идёт главный фон, промпт меняет только свет и погоду.
Состояние это полноценный вариант со своим якорем и, если нужно, своим мастер-листом, но растущий из родителя. Реализация:
О чём система предупреждает: смена стиля одновременно со сменой состояния, слишком большой шаг изменения без опорных признаков, отсутствие текстового якоря структурных черт.
Инстанс это использование ассета в кадре. Он хранит ссылку на ассет, выбранное состояние (или пометку «актуальное»), роль в кадре и слот референса. Инстанс не хранит копию описания и не может «отвязаться» от мастера, кроме явной операции «сделать самостоятельный ассет из этого инстанса» (создаёт копию).
Главный новый механизм. Он общий для любой генерации: промпт, вариант ассета, мастер-лист, кадр, клип. У каждого результата ровно два пути дальше.
| Путь | Что делает | Как устроено |
|---|---|---|
| Сгенерировать заново | тот же промпт, другая выборка | новый вызов, новая корневая генерация в истории |
| Доработать этот | правится именно этот результат | результат идёт входной картинкой, промптом уходит только правка |
Правила доводки:
Пиксельной маски у моделей Gemini нет вообще, ни в каком виде: маска только смысловая, словами. Значит «обвести область» реализуется одним из двух способов, и оба идут после ядра: либо формулировкой правки по смыслу («только левая бровь»), либо нашей обработкой на бэкенде — вырезать область, догенерировать отдельно, вклеить обратно с растушёвкой. Второе честнее и точнее, но это своя инженерия, а не кнопка в API. В этой версии не делаем, в архитектуру закладываем место.
Ресёрч дал важное предупреждение: ни Midjourney, ни Krea, ни Figma не рисуют историю графом ветвления на основном экране, все используют линейную ленту или сетку плюс явную ссылку на родителя. Поэтому:
Ответ на пункт, который Тимур оставил открытым.
Числовое управление камерой существует только у моделей, специально обученных под это (у одного из конкурентов горизонталь ноль-360 градусов, вертикаль минус тридцать плюс девяносто, зум ноль-десять). У наших моделей, ни у Gemini, ни у Veo, параметра камеры нет вообще. Значит числа передавать некуда, и любой виджет с градусами будет имитацией.
Поэтому три инструмента, работающие вместе:
Обязателен пункт 1. Пункт 2 включается автоматически при наличии листа. Пункт 3 по желанию.
Термины живут в справочнике режиссуры как данные: крупность, ракурс, движение камеры, композиция, свет, оптика. Русское название для человека, английский фрагмент в промпт, описание «когда применять». Единый лексикон это не украшение: расплывчатые формулировки дрейфуют между генерациями, точные нет.
Сцена заводится руками (автосоздание появится вместе с автопилотом по сценарию). Сцена хранит место, участников, время суток, короткое описание момента и выбранный стиль. Кадры внутри это наследуют, поэтому дополнительный ракурс не приходится описывать заново.
Кадр имеет явную роль, видную на карточке:
| Роль | Смысл |
|---|---|
| A | начальный кадр шота |
| B | конечный кадр шота |
| alt | тот же момент другой камерой, вне пары A и B |
Операции с кадра:
Кадр без ассетов, только промпт и стиль, разрешён: перебивки и пейзажи.
Планировщик покрытия предупреждает, если пропорции планов в ролике перекошены (общие пятнадцать-двадцать процентов, средние тридцать-сорок, крупные двадцать-двадцать пять, макро десять-пятнадцать) и если два одинаковых плана идут подряд. Это предупреждение, не блокировка.
На карточке шота явный переключатель режима, потому что режимы взаимоисключающие на уровне API:
| Режим | Входы | Когда |
|---|---|---|
| По одному кадру | кадр A | оживить статичный кадр |
| По двум кадрам | кадр A и кадр B | самый предсказуемый результат, полный контроль начала и конца |
| По ингредиентам | до трёх референсов, без кадров | собрать движение из ассетов без готового кадра |
| Продление | готовый клип | продолжить с последней секунды |
При выборе режима входы других гаснут с объяснением. Длительность и разрешение берутся из паспорта модели: 1080p и 4K требуют восьми секунд, у самой дешёвой модели 4K нет.
Motion-промпт пишется отдельно от промпта кадра, слоями из раздела 5.2, с одним основным движением камеры. Негатив уходит отдельным полем: у видеомоделей это официальный параметр, в отличие от картинок.
Дублей столько, сколько запрошено, все лежат в истории, лучший помечается рабочим шотом, остальные не удаляются. У клипа есть выходы «первый кадр» и «последний кадр», чтобы сцеплять сцены, но система считает расстояние от якоря и после трёх-пяти шагов требует ре-якорения на мастер-лист. Первые три шага почти незаметны, четвёртый-пятый дают сдвиг цвета, дальше плывут черты лица и фон.
Звук по умолчанию выключен, если отключаемость подтвердится тестом. Звук делается отдельным трактом, и лишняя дорожка в клипе только мешает монтажу.
Узел делает ровно одну вещь. У каждого типа жёстко задано: входы, выходы, настройки на карточке, содержимое, действия, состояние.
| Узел | Входы | Выход | Что на карточке |
|---|---|---|---|
| Заметка | — | — | текст на полотне, в генерации не участвует |
| Текст | — | текст | поле, форматирование, цвет карточки, упоминания других узлов |
| Картинка | — | картинка | превью, загрузка файлом, перетаскиванием и Ctrl+V |
| Стиль канала | референсы, пожелания текстом | стиль-блок | превью референсов, карта стиля, «Разобрать», «Зафиксировать», «Копия», пробы |
| Промпт | стиль, описание, ассеты | промпт | собранный промпт целиком EN и RU, правка руками, версии |
| Генерация картинки | промпт, референсы | картинка | модель, количество, формат, разрешение, запуск с ценой, лента истории, шорт-лист |
| Мастер-ассет | стиль, промпт, референсы | якорь, паспорт | алиас, тип, накопленные картинки, «Сделать якорем», статус |
| Состояние | мастер-ассет, описание правки | якорь состояния | родитель виден, дельта признаков |
| Мастер-лист | якорь ассета, эталон компоновки | лист | панели, досъёмка отдельной панели, «Утвердить» |
| Сцена | локация, участники | контекст сцены | место, время суток, участники, стиль |
| Кадр | сцена, промпт, референсы | картинка | роль A/B/alt, компас ракурса, крупность, свет, лента истории |
| Оживление | кадр A, кадр B, референсы, движение | видео | переключатель режима, модель, длительность, разрешение, запуск с ценой, дубли |
| Ролик | сцены | — | обложка, число сцен и шотов, переход внутрь |
| Группа | — | динамические, по содержимому | рамка, двигается вместе с содержимым, цвет |
Типы данных и цвета связей: текст синий, картинка фиолетовая, видео зелёное. Соединяются только одинаковые типы, несовместимое физически не прилипает.
Холст канала: стили, ассеты, состояния, мастер-листы, ролики как узлы-входы. Холст ролика: сцены рамками-группами, кадры внутри, шоты. Переход внутрь ролика двойным кликом, возврат по хлебным крошкам. Причина разделения: ролик на тридцать пять кадров это сто пятьдесят узлов, и в одном полотне со стилями и кастом это каша. У Magnific Spaces для того же придуманы страницы внутри пространства.
Дефолт библиотеки холста это поведение карты: драг двигает полотно, колесо зумит. Для дизайнера с двенадцатью годами Figma это ломает мышечную память в первый же час. У библиотеки есть официальный рецепт режима Figma, его и включаем по умолчанию:
| Действие | Как |
|---|---|
| Панорама | колесо или трекпад двумя пальцами, средняя кнопка, пробел с драгом |
| Зум | Cmd/Ctrl с колесом, пинч на трекпаде |
| Выделение рамкой | обычный левый драг по пустому месту, частичное пересечение выделяет |
| Вписать всё в экран | Cmd/Ctrl+0 |
| Множественный выбор | Cmd/Ctrl с кликом |
Режим переключаемый в настройках. В ComfyUI однажды сменили жесты между версиями молча и получили волну откатов и жалоб. Жест меняется только явным выбором человека.
Три способа, все три обязательны: пробел или слэш открывает поиск узлов; связь, вытянутая в пустоту, открывает тот же поиск, отфильтрованный по типу порта, и ставит узел уже подключённым; правый клик на холсте открывает список. Плюс миникарта в углу, поиск по холсту с прыжком к найденному, группы с цветом и заголовком, заметки, стикеры-флажки.
Карточка живёт в двух состояниях: свёрнутом (превью, имя, статус, цена последней генерации) и развёрнутом (промпт, настройки, лента истории). Размер тянется за угол, позиция и размер запоминаются. Узлы имеют иконку типа и цветовой код: признанная проблема ComfyUI это узлы, отличающиеся только подписью, их не читает глаз.
Три режима на каждой запускаемой карточке:
| Режим | Что делает |
|---|---|
| Только этот узел | пересчитать один шаг на готовых входах |
| Всю цепочку | от начала до конца |
| Отсюда и дальше | этот узел и всё после него, готовое выше не трогаем |
Порядок вычисляется сам: источники первыми, генераторы когда входы готовы, независимые ветви параллельно. Состояния узла: ждёт, в очереди, идёт, готово, ошибка, отменён. Отмена сохраняет уже готовые шаги.
Шаг, который нечем посчитать, пропускается с предупреждением, а не рушит весь прогон. Останавливает запуск только проблема того узла, который нажали.
Прямая находка ресёрча и главное отличие от наивной реализации. Смешивать в одну очередь отмены бесплатные правки и платные генерации нельзя: это источник вопроса «а что вообще делает эта кнопка».
| Слой | Что внутри | Отменяемо |
|---|---|---|
| A. Правки холста | позиции узлов, связи, тексты промптов до запуска, настройки, состав группы | да, Cmd/Ctrl+Z, паттерн команд, не снимки |
| B. Версии холста | именованные снимки структуры целиком, автоснимки между вехами схлопываются | восстановление версии, как история версий Figma |
| C. История генераций | факты вызовов с результатами и ценой | нет. Деньги потрачены, результат остаётся навсегда |
Отмена во время выполнения это не отмена действия, а отдельная операция «стоп»: готовые шаги сохраняют результат, отменяются текущий и ожидающие.
Требование Тимура: по миниатюрам решение принимать невозможно.
Второй режим просмотра канала это библиотека: таблица всех ассетов и кадров с превью, фильтром по типу, статусу и стилю, сортировкой и поиском. На пятидесяти ассетах холст плохо ищет, и это нормально: у холста другая работа.
Генерация идёт от тридцати секунд до двух минут. Отсюда жёсткие требования:
Лимита трат нет, это решение Тимура. Взамен полная прозрачность:
| Где | Что видно |
|---|---|
| Кнопка запуска | цена до запуска, пересчитывается вживую при смене модели, количества, разрешения |
| Подтверждение платного запуска | разбивка: модель, число вызовов, разрешение, референсы, сумма, ожидаемое время |
| Карточка генерации | сколько стоила именно она |
| Карточка ассета | сумма по всем его генерациям |
| Холст ролика | сумма по ролику |
| Канал | сумма по каналу и за месяц |
| Панель сессии | сколько потрачено за текущую сессию работы |
| Журнал трат | список всех генераций с фильтром по дате, модели, объекту, разбивкой по моделям |
| Отдельная строка | сожжено на невыбранное: сумма генераций, которые не стали якорем и не попали в шорт-лист |
Возможность, найденная ресёрчем и стоящая ноль: сравнение лиц через локальные эмбеддинги (DeepFace или InsightFace, обе библиотеки открытые, работают офлайн, порог берётся из их собственных таблиц).
Как встроено: после генерации кадра с героем воркер локально считает похожесть лица на кадре против якоря ассета. Если ниже порога, карточка помечается флажком «герой мог уплыть, посмотри внимательно». Это подсказка, а не блокировка: у эмбеддингов есть ложные срабатывания на крайних ракурсах и свете, решение всегда за человеком. Тем же механизмом закрывается вопрос, который до сих пор висел без источника: реальный процент попадания на нашем пайплайне станет известен из собственных цифр, а не из чужих оценок.
Требование Тимура: система должна летать. Чек-лист, обязательный к реализации, собран из официальной документации холста и замеров:
Холст канала с двадцатью узлами открывается меньше секунды, полотно с тремя сотнями узлов панорамируется без заметных рывков, превью карточки весит десятки килобайт, а не мегабайт.
┌───────────────────────── браузер ──────────────────────────┐
│ React 19 + Vite + Tailwind + @xyflow/react │
│ холст канала · холст ролика · библиотека · просмотр │
│ стор Zustand с узкими селекторами, паттерн команд для undo │
└───────────────┬────────────────────────────────────────────┘
│ REST + подписка на состояние (поллинг состояния графа)
┌───────────────▼────────────────────────────────────────────┐
│ FastAPI (порт 8310) │
│ api/ граф, ассеты, стили, сцены, кадры, шоты, экономика │
│ media/ стрим картинок и клипов с Range, превью │
│ models/ паспорта возможностей моделей и прайс │
│ compose/ сборка промптов по слоям │
└──────┬───────────────────────────────┬─────────────────────┘
│ │
┌──────▼─────────┐ ┌──────────▼───────────┐
│ воркер gen │ │ воркер agent │
│ Vertex image │ │ headless claude -p │
│ Vertex veo │ │ разбор стиля, промпты│
│ тратит деньги │ │ бесплатно, подписка │
│ конкурентность │ │ конкурентность 1 │
│ 2 карт / 1 вид │ └──────────────────────┘
└──────┬─────────┘
│ ┌──────────────────────┐
└───────────────────▶│ SQLite (индекс) │
│ файлы медиа (правда) │
│ локальная проверка │
│ похожести лиц │
└──────────────────────┘
Что переиспользуется из версии 1 без переписывания: сборка промпта по слоям с проверками дисциплины, прайс и смета (после исправления цифр), адаптер Vertex с ретраями, генерация превью, справочник режиссуры, эталон компоновки мастер-листа, паттерн «кнопка в вебе, headless-агент работает, статусы live», отработанный в кабинете ревью chronicles.
Что пишется заново: графовое ядро как единственная модель данных, каталог типов узлов, движок выполнения с тремя режимами, весь фронт холста, доводка как механизм, паспорта моделей, экономика по срезам, библиотека канала, просмотр и приёмка.
Развёртывание. Новая версия поднимается на отдельном адресе, старая продолжает работать. Переключение на studio.obahoba.com только после приёмки Тимуром. Basic auth, systemd с автоперезапуском, данные и медиа вне git, логи с ротацией.
Ресёрч оставил семь фактов, которые документация не подтверждает. Каждый закрывается одним-двумя вызовами на дешёвой модели, и все они делаются до первого боевого прогона.
| Что проверяем | Почему важно | Как |
|---|---|---|
| Отключается ли звук у Veo | лишняя дорожка мешает монтажу | один клип с флагом выключения |
| Работают ли референсы у самой дешёвой видеомодели | прайс считает, что да, документация молчит | один вызов с одним референсом |
| Стилевой референс на Veo 3.1 | код умеет его отправлять, источники говорят, что модель его не берёт | один вызов, ловим ошибку |
| Требуют ли 1080p и 4K ровно восьми секунд | иначе непонятная ошибка от API вместо честного объяснения | два вызова, четыре и восемь секунд |
| Регистр значения разрешения 4K | наш ключ с большой буквы, примеры с маленькой | один вызов |
| Детерминизм seed у картинок | если работает, экономит перебор | два вызова с одним seed и промптом |
| Сколько референсов реально держит дорогая модель | документация говорит шесть, анонс четырнадцать | серия: три, шесть, девять референсов, смотрим где ломается |
Результаты пишутся в паспорта моделей с датой. Паспорт с непроверенным полем помечается явно.
Проверяются мышью на живом сервисе, а не зелёными тестами. Зелёный прогон тестов ничего не доказывает. Каждый пункт привязан к работе из research/JTBD.md.
Порядок жёсткий и повторяется: спроектировал, зафиксировал контракт, запустил волну исполнителей, принял и свёл. Субагенты только на Sonnet, не больше пяти одновременно. Главная сессия проектирует и принимает, а не набирает код руками: иначе кончается контекст на середине.
| Волна | Что делается | Результат |
|---|---|---|
| 0. Фундамент | исправление прайса, паспорта моделей, семь дешёвых тестов из раздела 20, схема базы, каталог типов узлов, контракт API | документ контракта и зелёная схема |
| 1. Ядро графа | хранилище графа, валидация связей, движок выполнения с тремя режимами, очередь, состояния, история генераций как дерево | сквозной прогон в черновом режиме |
| 2. Холст | полотно с портами и связями, режим жестов Figma, поиск узлов, карточки узлов, панель действий, группы и заметки, производительность по чек-листу | холст, на котором можно работать |
| 3. Ассеты | стили с библиотекой и локом, мастер-ассеты в два этапа, мастер-листы трёх типов, состояния, доводка, просмотр и приёмка, библиотека канала | закрыты работы J1-J10, J16 |
| 4. Кадры и шоты | сцены, кадры с ролями, компас ракурса, поэтапная сборка, оживление с режимами, дубли | закрыты работы J11-J15 |
| 5. Экономика и надёжность | срезы трат, журнал, невыбранное, durable-сессии, уведомления, корзина, автопроверка похожести | закрыты работы J17-J22 |
| 6. Приёмка | прогон всех двадцати двух критериев мышью, переключение адреса | версия сдана |
Внутри волн Тимур контролирует каждый шаг сам, по факту работы: промпты, варианты, мастер-листы. Любой шаг обязан быть остановимым, правимым и повторяемым без потери сделанного. Отдельных гейтов между волнами нет, но и промежуточных отчётов «фаза готова» тоже: показывается работающее.
А. Работы по JTBD — research/JTBD.md, двадцать две работы с критериями закрытия.
Б. Фактическая база с источниками — research/R1-gemini-image.md (референсы, доводка, параметры, цены картинок), R2-veo.md (матрица видеомоделей, взаимоисключения, промпт движения, паспорт), R3a-krea.md и R3b-scenario.md (как решают ракурсы и мастер-листы живые продукты), R4-canvas-ux.md (производительность холста, жесты, отмена, просмотр, антипаттерны), R5-consistency.md (якоря, лексикон, ре-якорение, локации, два героя, автопроверка), spaces-docs-*.md (конспект справочника Magnific Spaces).
В. Правки в сборку промпта — десять пунктов в конце R5-consistency.md: кап признаков в слое идентичности, фраза против подмены лиц при двух героях, ссылка состояния на канон родителя, поэтапный режим, переформулировка комментария про порядок блоков видео, тест формулировки негативов, автопроверка похожести, снятие непроверенной цифры попадания.
Г. Чего в системе нет и не будет в этой версии — апскейл, редактор изображений, склейка видео, аудио, графический редактор, совместная работа, публичные шаблоны, батч-списки. Причина: студия решает одну задачу, держать героя и манеру одинаковыми через весь ролик. Всё остальное увеличивает поверхность обслуживания и уводит от неё.
Д. Антипаттерны, которых избегаем (из R4-canvas-ux.md): молчаливая смена жестов между версиями; смешение бесплатных правок и платных генераций в одной очереди отмены; снимки всего холста на каждое действие; дерево итераций как основной режим холста; зависимость длинной операции от открытой вкладки; узлы без визуального языка, отличающиеся только подписью; цепочки без группировки; несинхронный зум при сравнении.