# События и сцена Договорённость на срез после портретов (60–62) и ремесла, не текущий код. Портреты: [`portrait-models.md`](../off-queue/portrait-models.md), [`portrait-loras-embeds.md`](../off-queue/portrait-loras-embeds.md), [`portrait-prompt-craft.md`](../off-queue/portrait-prompt-craft.md). Экран: [`near-term.md`](../01-shell/near-term.md). Defs: [`defs.md`](../01-shell/defs.md). Сессия (хозяин / гость): [`session.md`](../08-session/session.md). Погода и вещи: [`inventory.md`](../07-inventory/inventory.md). Протокол: [`protocol.md`](../../protocol.md). Мир начинает **говорить** в две стороны: игроку — тостом или варнингом; генератору — коротким вкладом в промпт, если объект реально в кадре. Подписка — не общая C# шина на весь раствор. Симуляция поднимает факт, работник складывает уведомление, клиент рисует. Сборщик кадра **спрашивает комнату**, а не слушает шину. Срез отвечает на вопросы «что только что случилось», «почему часы встали» и «почему в промпте снег и доска». Оценок, хроники за год, арта локации на карте и LLM нет. ## Что увидит игрок В углу — короткое info-сообщение (утро, звонок на урок): само гаснет, клик закрывает раньше, часы идут. Варнинг и ошибка ставят паузу; Play не включает часы, пока карточка не закрыта. На части карточек — только текст; на части — кнопка «создать картинку» (портрет человека из события, уже с вкладом сцены). Новая школа рисует только Krea 2. «Показать промпт» может содержать комнату, погоду и вещи с непустым вкладом — не список всех стульев. ## На какие вопросы отвечает - Как факт симуляции доходит до UI, не нарушая инварианты 1, 3, 4 и 7. - Какие уведомления паузат школу и переживают F5. - Как почти любой def может добавить позитив/негатив/LoRA/embed в кадр, не раздув промпт. - Чем новая школа генерирует после отказа от SDXL. ## Чего нет - Третьей колонки-ленты на весь учебный год. Тосты и модал — не журнал. - Отдельного kind `scene` (коридор без человека). Кадр по-прежнему человек. - ControlNet, позы в UI, перегенерации старых PNG. - Общего `EventBus` во всех сборках. Симуляция не знает Swarm и тосты. - Автогенерации всех лиц. LLM. Звука. Лифта живых `portraitSettings`. - Отдельной SDXL-ветки промпта: ванильный каталог — только Krea 2. ## Что меняется в уже принятом | Было | Стало | Почему | | --- | --- | --- | | Отдельной панели событий нет ([`near-term.md`](../01-shell/near-term.md)) | Оверлей: info-тост и модал warning/error | Ленты всё ещё нет; пустая колонка не возвращается | | «Общая лента школы — не этот срез» ([`social.md`](../09-social/social.md)) | Уведомления есть; хроники за год нет | Игрок видит звонок и аварию генерации, не дневник | | Каталог Swarm: SDXL + Muse + Realism v2.5; child — DreamShaper | Только Muse и Realism v2.5; child тоже v2.5 | Krea 2 — не SDXL; «только Krea» значит без Lightning/DreamShaper | | Промпт: модель → стиль → кадр → extra → поза → внешность → одежда | Плюс вклад сцены после одежды, с бюджетом | Стул без текста молчит; доска и снег могут сказать фразу | | LoRA/embed только модель/пресет/кадр | Плюс вклад вещей и комнаты в том же кадре, тоже с бюджетом | Вещь может принести свою сеть, не меняя пресет школы | | Play всегда включает часы у хозяина | Пока висит pausing-уведомление, `SetRunning(true)` игнорируется | Варнинг должен остановить игру, а не проситься в углу | | Гость только смотрит часы | Гость видит те же уведомления, не закрывает pausing и не жмёт «создать картинку» | Как пауза и портрет: хозяин | Протокол: новый кадр уведомления и намерение закрыть. Версию сокета бампит **коммит фазы 64**, не этот документ. HTTP: dismiss и генерация с уведомления. Сейв: очередь незакрытых warning/error. ## Этап A — только Krea 2 Из `swarmui.json` уходят четыре SDXL, в том числе DreamShaper у `child`. Остаются `museByStableYogi_v30TurboGguf.gguf` и `realismByStableYogi_v25INT8Turbo.safetensors` (8 / CFG 1 / euler / simple). Пресет `default` и `child` — Realism v2.5; стиль и кадр `child` — проза без `(word:1.4)`. Пикер по-прежнему Swarm ∩ каталог. Живые школы **не лифтим**: копия в сейве как после фазы 62. Новая школа не видит babes / epicrealism / lustify / DreamShaper, даже если они ещё лежат в Swarm. После этапа школа целая: портреты рисуются, сцена в промпт ещё не вкладывается. ## Этап B — лента ### Факт и уведомление Новый вид `EventDef`. Триггер — короткое перечисление, не скрипт: - `dayStart` — рабочее утро (тот же край, что утренняя одежда / семейное); - `lessonStart` — звонок на урок, **один** на школу, не по классам; - `generationFailed` — Swarm не нарисовал (не симуляция: сервис портретов). Системы отдают факт тем же швом, что `AffinityEvent`: список, без UI. Работник сопоставляет `EventDef`, кладёт `Notice` на школу, шлёт кадр в исходящие. Симуляция не ссылается на ASP.NET, сокеты и Swarm. Подписчик в этом срезе — открытый клиент. Сборщик промпта на шину не подписывается. ### Важность | `severity` | На экране | Часы | Сейв | | --- | --- | --- | --- | | `info` | Тост, TTL со стены клиента (ваниль 8 с), клик закрывает | Идут | Нет | | `warning` / `error` | Модал, висит | Пауза, пока очередь pausing не пуста | Да, до dismiss | `pause` на дефе явное: ваниль info — нет, warning/error — да. Play не автозапускается после последнего закрытия. Несколько info — стопка (потолок, старые гаснут). Pausing — очередь модалов, на экране один; закрыли — следующий. Не больше восьми sticky; девятый не эмитим. ### Экран и права Не колонка. Тост поверх школы. Текст из локали мода (`defName`, как у стула), не с клиента. Хозяин закрывает pausing (сокет-намерение, одно поле — id). Гость видит, dismiss pausing и кнопка картинки — `403` / кадр игнор, как чужой `SetRunning`. Info гость может спрятать у себя; сервер info не хранит. Открытие школы: sticky заново. Info не повторяем. После этапа школа целая, даже если стул в промпте молчит. ## Этап C — вклад в кадр «На сцене» при генерации **этого человека**: его узел, `RoomDef`/`TerritoryDef`, fill карты, надетое и ноша с непустым вкладом, погода **только если место улица** (как тепло). Общий блок на `ThingDef`, `RoomDef` и осадках климата (дождь / снег / ясно на улице): ```jsonc "prompt": { "positive": "a classroom blackboard with chalk notes", "negative": "", "weight": 1, "positiveLoras": [], "negativeLoras": [], "positiveEmbeddings": [], "negativeEmbeddings": [] } ``` Пустой блок — вещь молчит. Ваниль заполняет немного: доска, снег, при необходимости форма (extra к уже существующему слою одежды). Обычный `Chair` без текста. Сборка: прежние слои, затем фрагменты сцены (вес по убыванию, при равенстве `defName`). LoRA сцены — в `loras` / `loraweights` как в фазе 61; embeddings — ``. **Бюджет** (числа в `SimulationOptions` / настройке портрета с дефолтом, не магические константы в сборщике): - не больше **6** текстовых фрагментов сцены; - фрагмент ≤ **120** символов (длиннее на загрузке каталога — ошибка); - не больше **2** LoRA и **2** embeddings сцены сверх слоёв модели/пресета/кадра. «Показать промпт» показывает то же, что уйдёт в Swarm. Нового kind нет. После этапа портрет знает комнату; кнопки на событии ещё может не быть. ## Этап D — действие на событии У `EventDef` поле `action`: `none` | `generateImage`. `generateImage` требует `personId` в `Notice` (кто в кадре). Кнопка на модале/тосте зовёт тот же портретный путь (ваниль — `full`), со сборкой сцены этапа C. Не рисуем пустую локацию. Ваниль: `DayStarted` / `LessonStarted` — info, `none`. `GenerationFailed` — error, пауза, кнопка повторить того же человека и kind. ## Где живёт код | Что | Куда | | --- | --- | | `EventDef`, блок `prompt` на вещах/комнатах/погоде | `HSchool.Content` + JSONC `core` | | Края дня и звонка как факты | `HSchool.Simulation` (без тостов и Swarm) | | Доска уведомлений, пауза, исходящие, сейв sticky | `HSchool.Server` (поток школы) | | Кадры notice / dismiss | `HSchool.Protocol`, `protocol.ts`, `docs/protocol.md` | | Тост, модал, кнопка | `src/HSchool.Client/src/ui` + `t(...)` | | Вклад сцены в промпт | `PortraitPromptBuilder` / сервис портретов на работнике | | Каталог Krea | `swarmui.json` + create-копия | Новой игровой библиотеки нет. Инвариант 4 держим: Simulation не ссылается на хост. ## Советы, которые стоит принять сразу - Не возвращать третью колонку «События» из среза 1: оверлей дешевле и не отжимает карту. - Не клеить уведомление к кадру часов: одно намерение на сообщение; часы 20 Гц, тост — нет. - Не эмитить «урок начался» по каждому классу: один звонок на школу. - Не вкладывать в промпт все fill комнаты: только непустой блок и бюджет. - Не лифтить живые школы «заодно с Krea». - Не автозапускать часы после dismiss. - Гость не закрывает pausing — иначе двое смотрящих дерутся за Play. ## Заведомо не сейчас - Журнал школы, фильтры ленты, звук, бейджи на вкладке. - Kind `scene`, арт узла на дереве карты, ControlNet, поза в UI. - Условия EventDef как произвольный скрипт (голод < 0.2, мнение < −40). - Общий EventBus, подписка ИИ на тосты, LLM-текст. - Лифт `portraitSettings`, Realism v2.0, SDXL в ванильном каталоге. - Автопортрет каждому ученику утром. ## Зафиксировано этим разговором | Тема | Решение | | --- | --- | | Форма | Один срез, не два и не side-work | | Сцена | Вклад в портрет человека в его узле, не отдельный kind | | Бюджет | 6 фрагментов, 2 LoRA, 2 embed сцены; пустой def молчит | | Поля вклада | На Thing / Room / осадках, не отдельный PromptContributorDef | | Пауза | Сервер; Play игнор, пока есть pausing notice; dismiss не Play | | Info | Тост, TTL, клик, часы идут, не в сейве | | Warning/error | Модал до закрытия, в сейве, очередь | | Права | Pausing dismiss и картинка — хозяин | | Подписка | Клиент через сокет; сборщик спрашивает комнату | | Krea | Только Muse + v2.5; child на v2.5; без лифта | | Картинка с события | Тот же портрет + сцена; нужен personId | | Ваниль | День, звонок, ошибка генерации | | Стоп | После B школа с тостами; после C — сцена в промпте без кнопки | | Протокол | +1 в коммите фазы 64 | | Ваниль/пак | `core`, не отдельный пак |