# Инструкция для новой лекции для AI

Создай отдельный JSON-файл для Graph Player по теме пользователя. Используй UTF-8 и строгий JSON без комментариев, завершающих запятых и Markdown-обёртки. Верни готовый файл с именем по теме.

## Спланируй лекцию до написания текста

1. Выбери сквозной пример. Определи, что слушатель должен суметь объяснить или сделать после лекции.
2. Выпиши ключевые сущности, их связи и порядок знакомства с ними. Для каждой сущности укажи шаг первого объяснения. Показывай её на графе в этот момент, если она помогает понять тему. Случайные упоминания отдельного узла не требуют.
3. Разбей материал на сцены. Для каждой заранее реши, какие узлы нужны в кадре, какие понадобятся позже и какие можно окончательно убрать.

## Напиши текст для озвучки

Используй русский язык. Если нужен один лектор, укажи только `speaker: "teacher"`. Для диалога добавляй реплики ученика там, где вопрос помогает перейти к следующему понятию.

Вводи понятия постепенно: сначала конкретная ситуация, затем определение, объяснение механизма и пример. Разбивай длинное объяснение на короткие шаги. Оставляй место для связок и пояснений, чтобы текст звучал как устная лекция. Объясняй тему, не озвучивай команды редактирования схемы.

## Собери сцены графа

- Меняй сцену при переходе к новому вопросу. Оставляй в кадре узлы и связи, нужные для текущего объяснения, и возвращай общие узлы, когда они снова нужны.
- Для временного скрытия используй `view.hide` на каждом нужном шаге. Если узел больше не понадобится, удали его через `remove-node`. Вместе с ним удалятся его связи. Отдельную завершившуюся связь убирай через `remove-edge`.
- Создавай узлы вместе с первым объяснением, связывай их с уже понятными сущностями и используй фокус для направления внимания. При смене сцены перепроверь, что фокус, маршрут, подсветка и потоки не ссылаются на скрытые или удалённые элементы.

## Формат файла

В корне находятся `format`, `version`, `title`, `language` и `turns`. Минимальный пример:

```json
{
  "format": "graph-lecture",
  "version": 1,
  "title": "Как работает изоляция",
  "language": "ru-RU",
  "turns": [
    {
      "speaker": "teacher",
      "sentences": [
        {
          "text": "Bubblewrap запускает процесс в ограниченном окружении.",
          "focus": ["bwrap", "process"],
          "actions": [
            {"op": "node", "id": "bwrap", "label": "bwrap", "color": "cyan"},
            {"op": "node", "id": "process", "label": "Процесс", "color": "blue"},
            {"op": "edge", "from": "bwrap", "to": "process", "label": "запускает", "negative": false}
          ],
          "view": {"dim": true, "highlight": ["bwrap→process"], "flow": [["bwrap", "process"]]}
        }
      ]
    }
  ]
}
```

`turns` — реплики с `speaker` = `teacher` или `student`; `sentences` — отдельные предложения, произносимые последовательно. У каждого предложения обязательный `text`, опциональные `actions`, `focus` и `view`.

- `actions`: `node` (создание, с `id`, `label`, `color`), `edge` (стрелка, `from`, `to`, однословный `label`, `negative`), `update`, `update-edge`, `remove-node`, `remove-edge`.
- Цвета: `cyan`, `blue`, `purple`, `amber`, `coral`; название вершины — одно или два слова.
- `focus`: идентификаторы вершин для автоматической камеры.
- `view`: временное представление только на время предложения: `dim` (приглушить остальное), `highlight` (пары `"id→id"`), `hide` (временно скрыть), `tour` (маршрут камеры), `flow` (списки путей движения точек).
- Сначала создавайте вершины, затем стрелки; используйте уже существующие идентификаторы для `focus`, `view` и обновлений. Удаление вершины удаляет и её стрелки.
- При перемотке граф восстанавливается из истории `actions`. Временные эффекты `view` не меняют данные графа.

Если JSON содержит ошибку, проигрыватель покажет сообщение и сохранит предыдущую открытую лекцию. HTML и текст JSON не выполняются как JavaScript. Максимальный размер выбранного файла — 10 МБ.

## Темп графа

Плеер сам ставит действия графа в очередь. Первый шаг начинается не раньше чем через секунду после начала предложения. Сначала по одному создаются узлы, затем по одному обновляются узлы, с интервалом в секунду между шагами. Связь с новым узлом появляется вместе с последним из двух её узлов. Связи между уже существующими узлами добавляются по одной после шагов с узлами. Сила притяжения новой связи нарастает ещё одну секунду.

Озвучка идёт параллельно с анимацией текущей реплики. Следующая реплика автоматически начинается, когда завершились и озвучка, и анимация. Распределяй большие перестройки графа по нескольким предложениям, чтобы слушатель успевал увидеть то, о чём идёт речь. Если нужен `view.flow`, держи очередь короткой: поток запускается после последнего шага, только пока это предложение ещё текущее. Тайминги в JSON добавлять не нужно.

## Что писать на рёбрах

Подпись `label` состоит из одного слова. Обычно выбирай точный глагол. Читай стрелку как «исходный узел — глагол — целевой узел». Если фраза не передаёт мысль лектора, уточни глагол, поменяй направление или выбери другой узел.

| Вид отношения | Примеры глаголов | Пример стрелки |
| --- | --- | --- |
| Состав и принадлежность | содержит, включает, объединяет | Процесс → содержит → Поток |
| Создание и запуск | создаёт, запускает, порождает | fork → создаёт → Дочерний процесс |
| Вызов и выполнение | вызывает, выполняет, обрабатывает | Оболочка → вызывает → waitpid |
| Ссылка и доступ | указывает, адресует, открывает | Дескриптор → адресует → Описание файла |
| Передача и получение | передаёт, получает, возвращает | waitpid → возвращает → PID |
| Управление ресурсами | ограничивает, учитывает, выделяет | cgroup → ограничивает → Память |
| Условие и зависимость | требует, разрешает, запрещает | Запуск → требует → Разрешение |
| Воздействие | пробуждает, блокирует, прерывает | Таймер → пробуждает → Поток |
| Изменение состояния | заменяет, обновляет, освобождает | execve → заменяет → Образ процесса |
| Наблюдение | показывает, описывает, измеряет | procfs → описывает → Процесс |

Избегай расплывчатого «связан», когда можно назвать отношение точнее. Направление зависит от смысла: «Процесс → содержит → Поток» и «Поток → принадлежит → Процессу» описывают одно отношение с разных сторон. Для временных рёбер действуют те же правила. Если отрицание задаётся через `negative: true`, оставь глагол утвердительным и поясни отрицание в тексте реплики.

## Временные стрелки

Добавляй стрелки только на текущее предложение через `view.edges`. Например, `"view": {"edges": [{"from": "a", "to": "b", "label": "сравнивает"}], "highlight": ["a→b"]}`. Оба узла должны существовать после действий текущего предложения и быть видимыми. Подпись состоит из одного слова. Можно добавить `"negative": true` и использовать стрелку в `highlight` и `flow`.

Временная стрелка исчезает на следующем шаге, притягивает вершины с половиной силы постоянной связи и не требует удаления. Не дублируй постоянную стрелку в том же направлении.

## Точные поля операций

| Операция | Обязательные поля помимо op | Необязательные поля |
| --- | --- | --- |
| node | id, label, color | |
| update | id | label, color |
| remove-node | id | |
| edge | from, to, label | negative |
| update-edge | from, to | label, negative |
| remove-edge | from, to | |

## Проверка перед выдачей

1. Проверь синтаксис JSON. Укажи format = graph-lecture, version = 1 и language = ru-RU.
2. Используй от 1 до 1000 непустых реплик и до 5000 предложений. Текст каждого предложения должен быть непустым и не длиннее 4000 символов. На предложение допускается до 250 операций.
3. Проиграй actions последовательно с пустого графа. Создавай вершины до использования их ID, не дублируй вершины или стрелки с одинаковыми from и to. ID короче 80 символов, без стрелки → и пробелов по краям.
4. Проверяй focus и view по состоянию графа после actions данного предложения. hide и tour содержат ID вершин. highlight содержит ключи существующих стрелок в виде «from→to». В flow каждый путь содержит минимум две вершины, а каждая соседняя пара соединена стрелкой в нужном направлении. Не используй скрытые вершины во focus, tour, flow или в выделенных стрелках.
5. Проверь, что файл меньше 10 МБ. Если доступен проигрыватель, открой JSON через «Открыть JSON» и проверь начало, перемотку и последний фрагмент.

## Итерации перед выдачей JSON

После первой версии сделай минимум 10 циклов «проверка → правки → повторная проверка». В каждом цикле прочитай лекцию по порядку и сверь рассказ с состоянием графа на каждом шаге.

- Проверь, что понятия вводятся до использования, а примеры и выводы согласованы между собой.
- Сверь появление узлов, смысл и направление стрелок, фокус и временные эффекты с тем, что говорит лектор в этот момент.
- Исправь найденные расхождения и запусти валидатор плеера на обновлённом JSON. Валидатор проверяет структуру, а смысл рассказа и графа проверяй отдельно.

Если последняя проверка выявила расхождения, повтори цикл. Отправляй пользователю итоговый JSON только после того, как повторная проверка не обнаружит расхождений и файл пройдёт валидацию.

## Временные вершины

Для примера на одну реплику добавь вершину в `view.nodes`, например `{"id":"example","label":"Пример","color":"amber"}`. Используй обычные правила для ID, подписи и цвета. ID временной вершины должен отличаться от ID постоянных вершин и других временных вершин этой реплики. Связывай её через `view.edges`. Временную вершину можно включить в `focus`, маршрут и потоки этой реплики. Она плавно исчезает при смене реплики и не входит в историю постоянного графа. Чтобы показать её снова, объяви её заново в нужной реплике.
