Требования к сценам

Этот документ задаёт целевые требования к новым сценам Vrata. Он опирается на текущий контракт runtime для Scene Bundle v1 и на диагностику старых сцен, экспортированных для staging. Старые сцены полезны только как технические пробы. Новые сцены должны быть оригинальными или иметь надлежащую лицензию. Копировать из старых сцен меши, текстуры, планировки, названия, фирменный стиль и узнаваемую визуальную композицию нельзя.

Основной процесс создания сцен силами проекта описан в docs/arch/2026-08-29-agentic-deterministic-scene-authoring.md. Эти требования проверяют готовую сцену и не зависят от того, какая LLM, какой оркестратор агентов, DCC-пакет или структура репозиториев использовались при её создании.

Цели

Каждая сцена также подчиняется общему контракту качества и шаблону постановки задачи. Техническая совместимость, воспроизводимость и пороги регрессии изображений не закрывают его проверки User/Builder/Physics и проверки визуального качества. Применяйте эти требования к комнатам любого типа.

Требования для человека

Оригинальность и права

Опыт пользователя

Совместимость с runtime

Структура пакета

Пакеты для production должны иметь такую структуру:

assets/scenes/<scene-id>/
  scene.json
  scene.glb
  preview.webp
  LICENSES.md

Правила:

Требования к манифесту

Сейчас runtime разбирает Scene Bundle v1. Валидаторы для новых сцен должны быть строже парсера runtime.

Поле Уровень Требование
schemaVersion fail Должно быть равно 1, пока не выйдет новая схема runtime.
sceneId fail ID в нижнем kebab-case, стабильный и неизменный для опубликованной версии, совпадает с именем каталога пакета.
label fail Понятное человеку название длиной 3–60 символов, без внутренних кодовых имён и сторонних брендов, если на них нет лицензии.
source fail Строка о происхождении, безопасная для публикации, а не локальный абсолютный путь.
glbPath fail Относительный путь к .glb; в production-пакетах абсолютные URL запрещены.
renderMode warn Должен быть default или clean; выбирайте clean, только если ассет проверен при освещении runtime в режиме clean.
spawnPoints fail Непустой массив; первая запись должна быть main и должна быть пригодной к использованию.
bounds fail Обязательно для продуктовых сцен; описывает задуманную область перемещения по комнате, а не габариты, которые дают экспортёр или вспомогательные объекты.
anchors.teleportFloorY warn Обязательно, если в сцене ожидаются телепорт или места; обычно 0.
anchors.seatAnchors warn/fail Обязательно, если видимые места входят в то, что обещает сцена; необязательно для пустых галерей и сценических площадок.
materialOverrides warn Лучше не указывать. Временно допускается до 5 точечных переопределений с тикетом и сроком действия.
preview fail Обязательно для продуктовых сцен и должно указывать на существующее изображение превью.
rights fail Обязательно для валидаторов, хотя runtime сейчас это поле игнорирует.

Рекомендуемый блок прав:

{
  "rights": {
    "owner": "vrata",
    "license": "internal-original",
    "clearedFor": ["staging", "production", "web-runtime", "screenshots", "optimization"],
    "sourceAssets": [
      {
        "id": "asset-library-or-ticket-id",
        "type": "mesh|texture|hdr|audio|font",
        "author": "Vrata",
        "licenseRef": "LICENSES.md"
      }
    ]
  }
}

Требования к координатам и масштабу

Требования к точкам появления

Сейчас точкой входа в runtime служит первая точка появления.

Проверка Уровень Требование
spawnPoints[0].id fail Должно быть main.
Конечная позиция fail x, y и z должны быть конечными числами.
На полу fail abs(position.y - teleportFloorY) <= 0.1, если комната намеренно не начинается на платформе.
Внутри границ fail Точка появления должна находиться внутри границ манифеста и не ближе 0.5m к стенам и краям.
Место над головой fail Не меньше 2.0m свободного пространства по вертикали над точкой появления.
Свободный радиус fail Не меньше 0.75m свободного радиуса вокруг корня игрока.
Читаемость первого вида fail Скриншот runtime из точки появления должен пройти визуальные пороги, описанные ниже.
Будущий yaw warn Добавьте yaw, когда его поддержат схема и runtime; до этого стройте комнату так, чтобы поворот по умолчанию был удобен.

Проверки точек появления на staging должны использовать ?debug=1&scenefit=0. С ?debug=1 по умолчанию включается отладочная автоподгонка, которая заменяет точку появления из манифеста. Поэтому скриншот или поза, снятые без scenefit=0, не подтверждают точку появления.

Якоря мест и взаимодействия

Якоря мест — это метаданные предметной области, а не декоративные имена мешей.

Требования к геометрии

Требования к материалам и освещению

Требования к текстурам

Бюджеты производительности

Бюджеты задаются для профиля пакета сцены. Валидаторы должны поддерживать выбор профиля и по умолчанию использовать desktop-standard для комнат на staging.

Метрика mobile-lite fail desktop-standard warn desktop-standard fail xr fail
Размер пакета >15 МБ >25 МБ >40 МБ >25 МБ
Размер основного GLB >15 МБ >25 МБ >40 МБ >25 МБ
Треугольники в runtime >90000 >150000 >220000 >120000
Число объектов в runtime >500 >600 >1000 >500
Число мешей в runtime >250 >300 >600 >300
Число материалов в runtime >96 >128 >256 >128
Число текстур в runtime >48 >64 >96 >64
Холодная загрузка на staging с компьютера >20000 мс >15000 мс >30000 мс >20000 мс

Примечания:

Визуальная приёмка в runtime

Приёмку нужно проводить в настоящем браузерном runtime Vrata, а не только статическим разбором GLB.

Обязательная форма команд для автоматических проверок:

open /rooms/<room-id>?debug=1&scenefit=0
wait until window.__VRATA_DEBUG__.sceneBundleState is loaded or failed
read window.__VRATA_DEBUG__.sceneDebug

Безусловные ошибки:

Предупреждения:

Намеренно тёмные сцены:

Поддерживаемые возможности glTF

Разрешено для продуктовых сцен:

Предупреждения для продуктовых сцен:

Ошибки для продуктовых сцен:

ID правил валидатора

Агенты и валидаторы должны сообщать стабильные ID правил. Предлагаемые ID:

ID правила Уровень Проверка
SCENE_RIGHTS_001 fail Метаданные rights есть и разрешают staging, production и web-runtime.
SCENE_RIGHTS_002 fail Нет путей, имён и брендов прежней компании и ссылок на нелицензированные ассеты.
SCENE_MANIFEST_001 fail schemaVersion === 1.
SCENE_MANIFEST_002 fail sceneId записан в нижнем kebab-case и совпадает с именем каталога пакета.
SCENE_MANIFEST_003 fail glbPath — относительный путь к .glb без выхода за пределы каталога.
SCENE_MANIFEST_004 fail У продуктовых сцен есть preview.
SCENE_MANIFEST_005 fail bounds задан, и значения по всем осям — положительные конечные числа.
SCENE_ASSET_001 fail Основной GLB существует, и его размер укладывается в бюджет ошибки выбранного профиля.
SCENE_ASSET_002 fail Все ссылки на ресурсы GLB и пакета разрешаются.
SCENE_GLTF_001 fail GLB — корректный glTF 2.0 ровно с одной сценой по умолчанию или с задокументированным выбором сцены.
SCENE_GLTF_002 fail Нет неподдерживаемых обязательных расширений.
SCENE_GLTF_003 warn Есть устаревшие или игнорируемые расширения.
SCENE_SCALE_001 fail Габариты в runtime конечны, и для обычной сцены в помещении ни одна ось не превышает 200m.
SCENE_SCALE_002 fail Габариты в runtime превышают границы манифеста не больше чем в 3x, если нет одобренного профиля мира.
SCENE_SPAWN_001 fail Первая точка появления — main, её координаты конечны, она находится внутри границ, на полу и со свободным пространством вокруг.
SCENE_SEAT_001 fail У якорей мест уникальные ID, конечная позиция, корректный yaw и положительный радиус.
SCENE_SEAT_002 warn У видимых мест нет якорей, или якоря стоят слишком близко друг к другу либо внутри геометрии.
SCENE_MATERIAL_001 warn Есть неконвертированные имена материалов-заглушек.
SCENE_MATERIAL_002 fail Сцена становится читаемой только с широкими переопределениями материалов.
SCENE_VISUAL_001 fail Сцена в runtime не доходит до состояния loaded.
SCENE_VISUAL_002 fail Список отсутствующих ассетов в runtime не пуст.
SCENE_VISUAL_003 fail Скриншот из точки появления чёрный, прозрачный или нечитаемый.
SCENE_PERF_001 warn Метрики runtime превышают бюджет предупреждения профиля.
SCENE_PERF_002 fail Метрики runtime превышают бюджет ошибки профиля.

Машиночитаемый профиль

Ниже приведён исходный профиль валидатора в формате JSON. Он намеренно строже, чем набор старых сцен на staging.

{
  "sceneRequirementsVersion": 1,
  "defaultProfile": "desktop-standard",
  "format": {
    "schemaVersion": 1,
    "productionAssetExtensions": [".glb"],
    "fixtureAssetExtensions": [".glb", ".gltf"],
    "legacyOnlyExtensions": [".fbx"],
    "requiredProductFiles": ["scene.json", "scene.glb", "preview.webp|preview.jpg"],
    "forbiddenPathPatterns": ["..", "^/", "^[A-Za-z]:", "\\\\"]
  },
  "rights": {
    "required": true,
    "requiredClearedFor": ["staging", "production", "web-runtime", "screenshots", "optimization"],
    "forbidUnlicensedThirdPartyAssets": true,
    "forbidPriorCompanyTradeDress": true
  },
  "profiles": {
    "mobile-lite": {
      "maxBundleMb": 15,
      "maxGlbMb": 15,
      "maxRuntimeTriangles": 90000,
      "maxRuntimeObjects": 500,
      "maxRuntimeMeshes": 250,
      "maxRuntimeMaterials": 96,
      "maxRuntimeTextures": 48,
      "maxLoadMs": 20000
    },
    "desktop-standard": {
      "warnBundleMb": 25,
      "maxBundleMb": 40,
      "warnRuntimeTriangles": 150000,
      "maxRuntimeTriangles": 220000,
      "warnRuntimeObjects": 600,
      "maxRuntimeObjects": 1000,
      "warnRuntimeMeshes": 300,
      "maxRuntimeMeshes": 600,
      "warnRuntimeMaterials": 128,
      "maxRuntimeMaterials": 256,
      "warnRuntimeTextures": 64,
      "maxRuntimeTextures": 96,
      "warnLoadMs": 15000,
      "maxLoadMs": 30000
    },
    "xr": {
      "maxBundleMb": 25,
      "maxGlbMb": 25,
      "maxRuntimeTriangles": 120000,
      "maxRuntimeObjects": 500,
      "maxRuntimeMeshes": 300,
      "maxRuntimeMaterials": 128,
      "maxRuntimeTextures": 64,
      "maxLoadMs": 20000
    }
  },
  "scale": {
    "unit": "meter",
    "floorYDefault": 0,
    "floorYTolerance": 0.05,
    "normalIndoorMaxAxisM": 200,
    "manifestBoundsWarnRatio": 1.5,
    "manifestBoundsFailRatio": 3.0,
    "normalIndoorMinWidthDepthM": 4,
    "normalIndoorMaxWidthDepthM": 80,
    "normalIndoorMinHeightM": 2.4,
    "normalIndoorMaxHeightM": 20
  },
  "spawn": {
    "mainSpawnRequired": true,
    "floorToleranceM": 0.1,
    "wallMarginM": 0.5,
    "freeRadiusM": 0.75,
    "headClearanceM": 2.0
  },
  "seating": {
    "idPattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
    "yawMin": -3.141593,
    "yawMax": 3.141593,
    "radiusMinM": 0.35,
    "radiusMaxM": 0.8,
    "seatHeightMinM": 0,
    "seatHeightMaxM": 0.8,
    "minDistanceMultiplier": 1.5
  },
  "visual": {
    "requireLoadedState": true,
    "requireNoFailureReason": true,
    "maxMissingAssets": 0,
    "minAverageAlpha": 250,
    "warnDarkPixelRatio": 0.35,
    "maxDarkPixelRatio": 0.70,
    "warnAverageLuminance": 55,
    "minAverageLuminance": 40,
    "intentionalDarkRequiresHumanReview": true
  },
  "gltf": {
    "allowedExtensions": [
      "KHR_texture_transform",
      "KHR_materials_unlit",
      "KHR_materials_emissive_strength",
      "KHR_lights_punctual",
      "KHR_draco_mesh_compression",
      "EXT_meshopt_compression",
      "KHR_texture_basisu"
    ],
    "warnExtensions": [
      "KHR_animation_pointer",
      "KHR_materials_pbrSpecularGlossiness"
    ],
    "forbidUnsupportedRequiredExtensions": true
  }
}

Порядок приёмки

  1. Статическая проверка манифеста: поля, пути, метаданные прав, структура пакета.
  2. Статическая проверка ассетов: разбор GLB, ссылки на ресурсы, поддержка расширений, размеры файлов, размеры текстур, материалы, преобразования узлов, исходная статистика.
  3. Локальная проверка в runtime: загрузка через runtime Vrata с ?debug=1&scenefit=0, проверка состояния loaded, читаемости скриншота, статистики runtime и отсутствующих ассетов.
  4. Проверка на staging: публикация неизменяемого URL пакета, привязка тестовой комнаты и запуск тех же проверок runtime на staging.
  5. Проверка человеком: убедиться, что сцена оригинальна, читаема, удобна для общения и визуально не происходит от старых сцен, защищённых авторским правом.

Критерии готовности новой сцены

Источник: docs/scene-technical-requirements.md в vrata-labs/platform на ревизии 380b2e7ff1dd, лицензия Apache-2.0. GitHub