Compare commits

...
10 Commits
Author SHA1 Message Date
emil28092005 4cc58d8c59 Configure LuaLS for single-file script workspaces
Native and manual checks / native (ubuntu-24.04) (push) Waiting to run
Native and manual checks / native (windows-2025) (push) Waiting to run
Native and manual checks / manual (push) Waiting to run
Windows editor and software Vulkan / windows-graphics (push) Waiting to run
2026-09-18 11:57:23 +03:00
emil28092005 5a67735ff4 Add optional Lua scripting module, examples, and validation 2026-09-18 11:28:50 +03:00
Emil 06210aac23 Preserve artifact provenance across Git text normalization 2026-09-18 06:24:57 +03:00
Emil dd02f9cae8 Complete MVP acceptance, publish platform evidence and finalize the manual
Native and manual checks / native (ubuntu-24.04) (push) Waiting to run
Native and manual checks / native (windows-2025) (push) Waiting to run
Native and manual checks / manual (push) Waiting to run
Windows editor and software Vulkan / windows-graphics (push) Waiting to run
2026-09-18 06:23:32 +03:00
Emil 4cb82556de Preserve source locations across cached imports and record MVP acceptance 2026-09-18 05:55:29 +03:00
Emil 0f34b03631 Checkpoint 5: complete asset freshness, schema migrations and editor diagnostics 2026-09-18 05:43:02 +03:00
Emil e0b965166e Compare canonical Windows launcher paths in UI acceptance 2026-09-18 05:33:21 +03:00
Emil b2fcd7a956 Separate historical engine research from current implementation evidence 2026-09-18 05:26:39 +03:00
Emil 7481a2e029 Validate gameplay metadata before publishing build generations 2026-09-18 05:21:31 +03:00
Emil afd773fffb Register pinned Vulkan software driver on elevated Windows CI 2026-09-18 05:19:59 +03:00
143 changed files with 10720 additions and 281 deletions
+6
View File
@@ -68,6 +68,12 @@ jobs:
- name: Test Linux
if: runner.os == 'Linux'
run: ctest --preset linux-debug
- name: Verify Lua-free native build
if: runner.os == 'Linux'
run: |
cmake -S . -B build/no-lua -G Ninja -DCMAKE_BUILD_TYPE=Debug -DFASET_ENABLE_LUA=OFF -DFASET_BUILD_RENDERER=OFF -DFASET_BUILD_EDITOR=OFF
cmake --build build/no-lua --target faset_schema_exporter faset_runtime_tests --parallel 2
ctest --test-dir build/no-lua --output-on-failure -R '^(runtime_contracts|lua_cli_contracts)$'
- name: Test Windows
if: runner.os == 'Windows'
run: ctest --preset windows-debug -LE gpu
+9 -2
View File
@@ -50,13 +50,20 @@ jobs:
.cache/windows-graphics/sdk
.cache/windows-graphics/driver
- name: Probe Vulkan loader and SwiftShader before compiling the engine
# Hosted Windows jobs are elevated, so Khronos correctly ignores driver
# environment overrides. Register the software ICD only on this disposable VM.
# https://github.com/KhronosGroup/Vulkan-Loader/blob/main/docs/LoaderDriverInterface.md#driver-discovery-on-windows
env:
VK_LOADER_DEBUG: all
run: python tools/ci/probe_windows_vulkan.py
run: |
$driverKey = 'HKLM:\SOFTWARE\Khronos\Vulkan\Drivers'
New-Item -Path $driverKey -Force | Out-Null
New-ItemProperty -Path $driverKey -Name $env:VK_DRIVER_FILES -PropertyType DWord -Value 0 -Force | Out-Null
python tools/ci/probe_windows_vulkan.py
- name: Fetch checksum-verified Slang compiler
run: python tools/fetch_slang.py
- name: Configure full editor and Player
run: cmake --preset windows-debug -DFASET_BUILD_RENDERER=ON -DFASET_BUILD_EDITOR=ON
run: cmake --preset windows-debug -DFASET_BUILD_RENDERER=ON -DFASET_BUILD_EDITOR=ON -DFASET_DEBUG_IMGUI=ON
- name: Build full editor and tests
run: cmake --build --preset windows-debug --parallel 2
- name: CPU contracts and software GPU pixel tests
+12 -1
View File
@@ -10,6 +10,7 @@ option(FASET_BUILD_RENDERER "Build the SDL3/Vulkan renderer and graphical applic
option(FASET_SANITIZERS "Enable address and undefined behavior sanitizers" OFF)
option(FASET_DEBUG_IMGUI "Build optional Dear ImGui diagnostics library" OFF)
option(FASET_BUILD_RUNTIME "Build ECS and physics runtime" ON)
option(FASET_ENABLE_LUA "Build the optional sandboxed Lua scripting module" ON)
option(FASET_BUILD_ASSETS "Build asset import tools" ON)
option(FASET_BUILD_AUTHORING "Build scene authoring and metadata" ON)
option(FASET_BUILD_EDITOR "Build retained UI and editor applications" ON)
@@ -32,6 +33,12 @@ target_include_directories(faset_core PUBLIC include)
target_link_libraries(faset_core PUBLIC nlohmann_json::nlohmann_json Threads::Threads)
target_compile_definitions(faset_core PUBLIC FASET_VERSION="${PROJECT_VERSION}")
# Manifest/snapshot support is independent of the Lua VM and available to tooling
# even when the selected game is C++-only.
add_library(faset_scripting_project STATIC src/scripting/project.cpp)
target_include_directories(faset_scripting_project PUBLIC include)
target_link_libraries(faset_scripting_project PUBLIC faset_core)
# Modules are independent targets; Player never links authoring, editor or MCP.
foreach(module Authoring Runtime Assets)
if(module STREQUAL "Authoring" AND NOT FASET_BUILD_AUTHORING)
@@ -47,6 +54,9 @@ foreach(module Authoring Runtime Assets)
include(cmake/${module}.cmake)
endif()
endforeach()
if(FASET_ENABLE_LUA AND TARGET faset_runtime)
include(cmake/Lua.cmake)
endif()
if(FASET_BUILD_RENDERER AND EXISTS "${PROJECT_SOURCE_DIR}/cmake/Renderer.cmake")
include(cmake/Renderer.cmake)
endif()
@@ -56,7 +66,7 @@ endif()
if(TARGET faset_authoring AND EXISTS "${PROJECT_SOURCE_DIR}/cmake/EditorCommands.cmake")
include(cmake/EditorCommands.cmake)
endif()
if(TARGET faset_assets AND EXISTS "${PROJECT_SOURCE_DIR}/cmake/BuildService.cmake")
if(TARGET faset_assets AND TARGET faset_authoring AND EXISTS "${PROJECT_SOURCE_DIR}/cmake/BuildService.cmake")
include(cmake/BuildService.cmake)
endif()
if(TARGET faset_editor_commands AND TARGET faset_build_service)
@@ -107,5 +117,6 @@ if(BUILD_TESTING)
endif()
include(cmake/Tutorials.cmake)
include(cmake/Diagnostics.cmake)
include(cmake/WindowsPlatform.cmake)
+71 -69
View File
@@ -1,8 +1,8 @@
# План разработки Faset Engine
Версия 1.1 · 18 сентября 2026 года.
Версия 1.2 · 18 сентября 2026 года.
**Статус:** идёт реализация MVP. Готовность этапов определяется всеми их критериями, включая проверку обеих ОС; отдельные работающие подсистемы ещё не закрывают этап целиком. Текущие результаты и ограничения записаны в [журнале реализации](docs/IMPLEMENTATION.md). Этот документ определяет порядок работ; контракты подсистем находятся в [ARCHITECTURE.md](docs/ARCHITECTURE.md).
**Статус:** C++ MVP реализован и принят; первый tag — **v0.1.0-mvp**. Исходники движка проверены на `4cb82556de31268d2bde73948dd1ff1b6c02f162`; финальная публикация добавляет документацию и свидетельства, сохраняя код движка. [Досье M0M9](docs/validation/mvp-acceptance.md) связывает каждый этап с проверками и точными revisions. Linux проверен на RTX 2080 Ti, Windows — в native CI через SwiftShader; это не сертификация всех GPU/драйверов. Системный IME и физические переходы между мониторами не проверены, native Wayland restore имеет явный skip; XWayland и Windows lifecycle прошли. Текст/DPI проверены на уровне widgets и SDL. Эти границы покрытия сохраняются открыто и не выдаются за пройденные сценарии. Контракты находятся в [ARCHITECTURE.md](docs/ARCHITECTURE.md), история — в [журнале реализации](docs/IMPLEMENTATION.md).
## 1. Результат MVP
@@ -42,12 +42,12 @@ Lua, C++ hot reload, Blender live link, встроенное изображен
**Результат:** минимальный C++-проект собирается в согласованной среде Linux и Windows.
- [ ] Создать targets Core, Runtime, Editor, Player, SchemaExporter, инструментов и примеров; запретить зависимости Runtime/Player на Editor/MCP.
- [ ] Настроить CMake presets, Ninja, Clang/clang-cl, development/release и базовые проверки CI обеих ОС.
- [ ] Зафиксировать стандарт C++, версии компиляторов, Windows SDK/runtime, библиотек и Slang; определить проверяемую матрицу ОС, архитектур и GPU.
- [ ] Закрепить EnTT, SDL3, Slang, Box2D, Box3D и отладочный ImGui с воспроизводимым получением, notices и возможностью локальной сборки. Research commits не считать автоматически dependency versions.
- [ ] Определить ошибки, журналирование, проверки инвариантов, владение ресурсами и формат диагностик.
- [ ] Выбрать необходимые библиотеки шрифтов/текста, изображений и glTF, зафиксировать их лицензии и владельцев интеграции.
- [x] Создать targets Core, Runtime, Editor, Player, SchemaExporter, инструментов и примеров; запретить зависимости Runtime/Player на Editor/MCP.
- [x] Настроить CMake presets, Ninja, Clang/clang-cl, development/release и базовые проверки CI обеих ОС.
- [x] Зафиксировать стандарт C++, версии компиляторов, Windows SDK/runtime, библиотек и Slang; определить проверяемую матрицу ОС, архитектур и GPU.
- [x] Закрепить EnTT, SDL3, Slang, Box2D, Box3D и отладочный ImGui с воспроизводимым получением, notices и возможностью локальной сборки. Research commits не считать автоматически dependency versions.
- [x] Определить ошибки, журналирование, проверки инвариантов, владение ресурсами и формат диагностик.
- [x] Выбрать необходимые библиотеки шрифтов/текста, изображений и glTF, зафиксировать их лицензии и владельцев интеграции.
**Готово:** чистая сборка проходит на обеих ОС, пример запускается, версии видны в отчёте. Офлайн-сборка проверяется с заранее подготовленными инструментами и зависимостями; обязательных облачных сервисов нет.
@@ -55,12 +55,12 @@ Lua, C++ hot reload, Blender live link, встроенное изображен
**Зависит от:** M0. **Результат:** авторский документ корректно меняется и сохраняется без GUI.
- [ ] Реализовать постоянные ID ресурсов, объектов, компонентов, типов и полей; временные runtime handles с world/session и generation хранить отдельно.
- [ ] Создать явную типизированную C++-регистрацию схем, декларативные constraints и подсказки Inspector; отделить описание данных от исполняемых callbacks.
- [ ] Ввести версионированные JSON-форматы проекта, сцены, материала и import settings; стабильную запись и сохранение неизвестных данных отсутствующего модуля.
- [ ] Создать AuthoringService: query, команды, транзакции, validation, revisions, Undo/Redo, dirty state, атомарное сохранение и recovery.
- [ ] Поддержать объекты, компоненты, изменение полей и иерархии, batch-команды и понятные ошибки.
- [ ] Добавить миграции с fixtures: переименование при прежнем FieldId, новый default, несовместимый тип и отсутствующая схема.
- [x] Реализовать постоянные ID ресурсов, объектов, компонентов, типов и полей; временные runtime handles с world/session и generation хранить отдельно.
- [x] Создать явную типизированную C++-регистрацию схем, декларативные constraints и подсказки Inspector; отделить описание данных от исполняемых callbacks.
- [x] Ввести версионированные JSON-форматы проекта, сцены, материала и import settings; стабильную запись и сохранение неизвестных данных отсутствующего модуля.
- [x] Создать AuthoringService: query, команды, транзакции, validation, revisions, Undo/Redo, dirty state, атомарное сохранение и recovery.
- [x] Поддержать объекты, компоненты, изменение полей и иерархии, batch-команды и понятные ошибки.
- [x] Добавить миграции с fixtures: переименование при прежнем FieldId, новый default, несовместимый тип и отсутствующая схема.
**Готово:** round-trip сохраняет смысл и ID; неверная транзакция не применяется частично; Undo/Redo восстанавливает ссылки; устаревшая revision даёт конфликт. Документы не содержат EnTT handles или адресов памяти.
@@ -68,13 +68,13 @@ Lua, C++ hot reload, Blender live link, встроенное изображен
**Зависит от:** M0; загрузка сцены подключается к M1.
- [ ] Подключить SDL3 через Faset Platform: окно, ввод, текст, DPI и Vulkan surface.
- [ ] Реализовать Vulkan 1.3 backend с прямыми вызовами Vulkan API, проверкой features/limits/formats, ресурсами, синхронизацией и освобождением после завершения GPU; изолировать Vulkan handles и команды от gameplay и редакторских API.
- [ ] Создать Render Graph на одной graphics queue с явными чтениями/записями и barriers; подключить validation и метки проходов.
- [ ] Компилировать Slang в SPIR-V с закреплёнными layout/binding conventions; выгружать reflection в собственный формат. Проверить совместимый HLSL-пример.
- [ ] Получить спрайты, прозрачность и слои для 2D; static meshes, текстуры, базовый PBR, свет и обычную shadow map для 3D.
- [ ] Использовать direct draws и CPU frustum culling как эталон; ввести CPU/GPU timings и счётчики ресурсов.
- [ ] Обновлять шейдер с безопасной заменой pipeline: ошибка сохраняет рабочий вариант, изменение layout требует проверки совместимости.
- [x] Подключить SDL3 через Faset Platform: окно, ввод, текст, DPI и Vulkan surface.
- [x] Реализовать Vulkan 1.3 backend с прямыми вызовами Vulkan API, проверкой features/limits/formats, ресурсами, синхронизацией и освобождением после завершения GPU; изолировать Vulkan handles и команды от gameplay и редакторских API.
- [x] Создать Render Graph на одной graphics queue с явными чтениями/записями и barriers; подключить validation и метки проходов.
- [x] Компилировать Slang в SPIR-V с закреплёнными layout/binding conventions; выгружать reflection в собственный формат. Проверить совместимый HLSL-пример.
- [x] Получить спрайты, прозрачность и слои для 2D; static meshes, текстуры, базовый PBR, свет и обычную shadow map для 3D.
- [x] Использовать direct draws и CPU frustum culling как эталон; ввести CPU/GPU timings и счётчики ресурсов.
- [x] Обновлять шейдер с безопасной заменой pipeline: ошибка сохраняет рабочий вариант, изменение layout требует проверки совместимости.
**Готово:** корректны resize/minimize, пересоздание attachments и повторный запуск; validation не сообщает ошибок в проверяемых сценариях. В игру идут SPIR-V и метаданные без обязательного Slang compiler. Создание pipelines драйвером остаётся отдельным этапом.
@@ -82,14 +82,14 @@ Lua, C++ hot reload, Blender live link, встроенное изображен
**Зависит от:** M1 и M2 для визуального запуска.
- [ ] Преобразовывать authoring-сцену в EnTT-мир с картой происхождения и удобным typed API объектов/компонентов.
- [ ] Создать gameplay static library и SchemaExporter с теми же регистрациями: экспорт схем без запуска gameplay lifecycle или графического окна. Editor читает проверяемый декларативный результат.
- [ ] Реализовать OnStart, Update, FixedUpdate, LateUpdate, OnDestroy и события физики; регистрировать только нужные обработчики.
- [ ] Зафиксировать tick (default 60 Гц): structural commands → ввод → FixedUpdate → физика → readback/events → реакции. Spawn/despawn и изменение состава компонентов вступают в силу со следующего tick.
- [ ] Вызывать Update один раз за игровой кадр, LateUpdate после подготовки отображаемых положений. Интерполяция не пишет обратно в симуляцию.
- [ ] Подключить независимые адаптеры Box2D/Box3D: тела и коллайдеры для демо, collision layers, события и debug drawing. Динамическим телом управляет физика; телепортация явная.
- [ ] Ограничить catch-up (начальный лимит четыре ticks за проход); лишнее время локального Player отбрасывать с диагностикой. После pause/reset не догонять паузу; teleport/spawn сбрасывает историю интерполяции.
- [ ] Запускать Player отдельным процессом/окном из текущего снимка сцены, включая несохранённые правки; реализовать Play/Stop, pause/single-step, логи и обработку завершения.
- [x] Преобразовывать authoring-сцену в EnTT-мир с картой происхождения и удобным typed API объектов/компонентов.
- [x] Создать gameplay static library и SchemaExporter с теми же регистрациями: экспорт схем без запуска gameplay lifecycle или графического окна. Editor читает проверяемый декларативный результат.
- [x] Реализовать OnStart, Update, FixedUpdate, LateUpdate, OnDestroy и события физики; регистрировать только нужные обработчики.
- [x] Зафиксировать tick (default 60 Гц): structural commands → ввод → FixedUpdate → физика → readback/events → реакции. Spawn/despawn и изменение состава компонентов вступают в силу со следующего tick.
- [x] Вызывать Update один раз за игровой кадр, LateUpdate после подготовки отображаемых положений. Интерполяция не пишет обратно в симуляцию.
- [x] Подключить независимые адаптеры Box2D/Box3D: тела и коллайдеры для демо, collision layers, события и debug drawing. Динамическим телом управляет физика; телепортация явная.
- [x] Ограничить catch-up (начальный лимит четыре ticks за проход); лишнее время локального Player отбрасывать с диагностикой. После pause/reset не догонять паузу; teleport/spawn сбрасывает историю интерполяции.
- [x] Запускать Player отдельным процессом/окном из текущего снимка сцены, включая несохранённые правки; реализовать Play/Stop, pause/single-step, логи и обработку завершения.
**Готово:** C++-поведение появляется в Inspector через schema export, двигает объект и реагирует на физику. Stop сохраняет авторскую сцену. Ошибка сборки оставляет старую схему/сборку с явным статусом устаревания; старый результат не выдаётся за новый. Player не содержит MCP и не требует Editor.
@@ -97,13 +97,13 @@ Lua, C++ hot reload, Blender live link, встроенное изображен
**Зависит от:** M1, M2.
- [ ] Построить retained tree, layout, clipping/scroll, события, focus, keyboard navigation, drag/drop и lifecycle widgets.
- [ ] Подключить шрифты/shaping по выбору M0; проверить кириллицу, выделение/редактирование текста, clipboard, IME и разный DPI.
- [ ] Разделить C++-поведение, декларативную компоновку и стили с тёмной темой; поддержать программное создание Inspector.
- [ ] Реализовать кнопки, текстовые/числовые поля, списки/дерево, выбор ресурса, вкладки, панели и разделители.
- [ ] Оформить встроенные подписи, команды, подсказки и сообщения на английском; проверить, что Unicode-текст проекта отображается и редактируется независимо от языка интерфейса.
- [ ] Добавить минимальный docking в одном окне и сохранение раскладки; дополнительные системные окна редактора отложить.
- [ ] Перезагружать layout/styles с проверкой и сохранением рабочего состояния; ImGui использовать для диагностики.
- [x] Построить retained tree, layout, clipping/scroll, события, focus, keyboard navigation, drag/drop и lifecycle widgets.
- [x] Подключить шрифты/shaping по выбору M0; проверить кириллицу, выделение/редактирование текста, clipboard, IME и разный DPI.
- [x] Разделить C++-поведение, декларативную компоновку и стили с тёмной темой; поддержать программное создание Inspector.
- [x] Реализовать кнопки, текстовые/числовые поля, списки/дерево, выбор ресурса, вкладки, панели и разделители.
- [x] Оформить встроенные подписи, команды, подсказки и сообщения на английском; проверить, что Unicode-текст проекта отображается и редактируется независимо от языка интерфейса.
- [x] Добавить минимальный docking в одном окне и сохранение раскладки; дополнительные системные окна редактора отложить.
- [x] Перезагружать layout/styles с проверкой и сохранением рабочего состояния; ImGui использовать для диагностики.
**Готово:** интерфейс доступен клавиатурой, текст и DPI работают, стили меняются без C++ rebuild. Правка widget вызывает AuthoringService; один drag создаёт один Undo.
@@ -111,14 +111,14 @@ Lua, C++ hot reload, Blender live link, встроенное изображен
**Зависит от:** M1, M2; UI состояния подключается по M4.
- [ ] Реализовать AssetId, import settings, dependency graph, artifacts и manifest готового поколения.
- [ ] Включить в ключ кэша входы, настройки, версии importer/toolchain и целевой профиль; показывать ошибки/устаревшие результаты.
- [ ] Импортировать профиль glTF/GLB и изображения для демо; описать PBR-подмножество, единицы, оси и collider policy.
- [ ] Поддержать обычный GLB без Blender add-on; явно ограничить matching после rename/restructure без устойчивых IDs.
- [ ] Создать минимальное необязательное дополнение обычного Blender: export button, сохраняемые IDs и manifest; записывать версию exporter и профиль.
- [ ] Обновлять только импортированную основу, сохраняя gameplay/physics settings и overrides Faset. Исчезновение цели создаёт конфликт.
- [ ] Публиковать GLB/manifest/зависимости как согласованное поколение; ошибка/отмена оставляет последний рабочий artifact.
- [ ] Предоставить одинаковый импорт через UI/CLI/MCP редактора; длительная операция имеет ID, progress и cancellation.
- [x] Реализовать AssetId, import settings, dependency graph, artifacts и manifest готового поколения.
- [x] Включить в ключ кэша входы, настройки, версии importer/toolchain и целевой профиль; показывать ошибки/устаревшие результаты.
- [x] Импортировать профиль glTF/GLB и изображения для демо; описать PBR-подмножество, единицы, оси и collider policy.
- [x] Поддержать обычный GLB без Blender add-on; явно ограничить matching после rename/restructure без устойчивых IDs.
- [x] Создать минимальное необязательное дополнение обычного Blender: export button, сохраняемые IDs и manifest; записывать версию exporter и профиль.
- [x] Обновлять только импортированную основу, сохраняя gameplay/physics settings и overrides Faset. Исчезновение цели создаёт конфликт.
- [x] Публиковать GLB/manifest/зависимости как согласованное поколение; ошибка/отмена оставляет последний рабочий artifact.
- [x] Предоставить одинаковый импорт через UI/CLI/MCP редактора; длительная операция имеет ID, progress и cancellation.
**Готово:** изменение mesh в Blender обновляет несколько экземпляров без потери компонентов/overrides; rename со стабильным ID сохраняет связь, удаление создаёт понятный конфликт. Игра использует cooked assets без Blender.
@@ -126,13 +126,13 @@ Lua, C++ hot reload, Blender live link, встроенное изображен
**Зависит от:** M1, M3, M4, M5.
- [ ] Собрать Scene Tree, Inspector, Asset Browser, 2D/3D viewport, Console, Project Settings и команды Save/Play/Build.
- [ ] Реализовать selection, focus, gizmos, создание объектов/компонентов, поиск и основные shortcuts.
- [ ] Ввести шаблон как scene asset: InstanceId, исходные ObjectId/ComponentId, sparse overrides и вложенные экземпляры без циклов.
- [ ] Адресовать overrides по цепочке инстанцирования и IDs, независимо от имён/parenting; при duplicate remap внутренних ссылок, внешние сохранить.
- [ ] Поддержать локальные добавления, suppression, ограниченный reparent внутри экземпляра с явным local/world transform; массивы переопределять целиком.
- [ ] Показывать происхождение значения, Revert и открытие источника. Сохранять конфликтующие данные исчезнувших targets/types; Apply to template и inherited variants отложить.
- [ ] Обеспечить одинаковые операции и Undo/Redo для 2D/3D; восстановить проект с очищенным кэшем.
- [x] Собрать Scene Tree, Inspector, Asset Browser, 2D/3D viewport, Console, Project Settings и команды Save/Play/Build.
- [x] Реализовать selection, focus, gizmos, создание объектов/компонентов, поиск и основные shortcuts.
- [x] Ввести шаблон как scene asset: InstanceId, исходные ObjectId/ComponentId, sparse overrides и вложенные экземпляры без циклов.
- [x] Адресовать overrides по цепочке инстанцирования и IDs, независимо от имён/parenting; при duplicate remap внутренних ссылок, внешние сохранить.
- [x] Поддержать локальные добавления, suppression, ограниченный reparent внутри экземпляра с явным local/world transform; массивы переопределять целиком.
- [x] Показывать происхождение значения, Revert и открытие источника. Сохранять конфликтующие данные исчезнувших targets/types; Apply to template и inherited variants отложить.
- [x] Обеспечить одинаковые операции и Undo/Redo для 2D/3D; восстановить проект с очищенным кэшем.
**Готово:** пользователь создаёт сцену без ручного JSON, размещает два экземпляра, меняет один, обновляет источник, отменяет правки и переоткрывает проект без потери идентичности.
@@ -140,12 +140,12 @@ Lua, C++ hot reload, Blender live link, встроенное изображен
**Зависит от:** M1, M5, M6; headless проверки возможны раньше GUI.
- [ ] Подключить MCP к AuthoringService: документы/query/schema, create/delete/set, batches, Undo/Redo, import/build/export, Play/Stop и диагностика редактора.
- [ ] Ввести capabilities и структурированные ошибки. Headless authoring/build не требует GUI; screenshot editor viewport требует render backend и GPU.
- [ ] Проверять revisions и конфликты ручных/MCP-изменений; не повторять слепую запись поверх нового состояния. Повтор запроса не дублирует завершённую транзакцию.
- [ ] Предоставить jobs ID/progress/result/cancellation; отделить отмену задачи от Undo документа.
- [ ] Загружать editor DLL/SO при старте: manifest, exact SDK/build compatibility, зависимости и владельцы регистраций. Обновление — через перезапуск.
- [ ] Проверить extension-пакет с runtime-компонентом и editor-командой/панелью; правки документов проходят через command API.
- [x] Подключить MCP к AuthoringService: документы/query/schema, create/delete/set, batches, Undo/Redo, import/build/export, Play/Stop и диагностика редактора.
- [x] Ввести capabilities и структурированные ошибки. Headless authoring/build не требует GUI; screenshot editor viewport требует render backend и GPU.
- [x] Проверять revisions и конфликты ручных/MCP-изменений; не повторять слепую запись поверх нового состояния. Повтор запроса не дублирует завершённую транзакцию.
- [x] Предоставить jobs ID/progress/result/cancellation; отделить отмену задачи от Undo документа.
- [x] Загружать editor DLL/SO при старте: manifest, exact SDK/build compatibility, зависимости и владельцы регистраций. Обновление — через перезапуск.
- [x] Проверить extension-пакет с runtime-компонентом и editor-командой/панелью; правки документов проходят через command API.
**Готово:** ручные и MCP-операции дают эквивалентные канонические документы и историю. Нет MCP runtime-entity read/write; MCP transport отсутствует в Player и SchemaExporter. Отключённый пакет не уничтожает данные неизвестного компонента; экспорт сообщает о нерешённой зависимости.
@@ -153,12 +153,12 @@ Lua, C++ hot reload, Blender live link, встроенное изображен
**Зависит от:** M3, M5, M6, M7.
- [ ] Создать BuildService: validate → C++/schema build → resource/Slang cook → package → проверить результат.
- [ ] Разделить development/release manifests; исключить Editor, MCP, Blender, schema helpers и shader compiler из обязательного runtime игры.
- [ ] Подготовить две маленькие 2D/3D-игры с исходниками, понятным управлением и сценариями проверки.
- [ ] Проверить stop/build/restart, save/reopen, nested scenes, Blender reimport и shader compile failure.
- [ ] Собрать обе игры на каждой целевой ОС и запустить в чистой среде с поддерживаемым GPU-драйвером и документированными runtime-зависимостями.
- [ ] Сформировать notices, manifest ресурсов/toolchain, отчёт и инструкции разработчику/игроку.
- [x] Создать BuildService: validate → C++/schema build → resource/Slang cook → package → проверить результат.
- [x] Разделить development/release manifests; исключить Editor, MCP, Blender, schema helpers и shader compiler из обязательного runtime игры.
- [x] Подготовить две маленькие 2D/3D-игры с исходниками, понятным управлением и сценариями проверки.
- [x] Проверить stop/build/restart, save/reopen, nested scenes, Blender reimport и shader compile failure.
- [x] Собрать обе игры на каждой целевой ОС и запустить в чистой среде с поддерживаемым GPU-драйвером и документированными runtime-зависимостями.
- [x] Сформировать notices, manifest ресурсов/toolchain, отчёт и инструкции разработчику/игроку.
**Готово:** все четыре сочетания «2D/3D × Linux/Windows» запускаются без исходного дерева Faset и редактора. Недостающий asset или библиотека обнаруживаются до публикации пакета.
@@ -166,17 +166,19 @@ Lua, C++ hot reload, Blender live link, встроенное изображен
**Зависит от:** M0M8.
- [ ] Пройти новую установку и создание проекта по документации на обеих ОС.
- [ ] Повторить authoring-сценарий руками и через MCP; проверить Undo/Redo и конфликт revision при одновременной правке.
- [ ] Проверить recovery после сбоя сохранения, импорта, сборки и завершения Player с ошибкой.
- [ ] Записать startup, edit/build/run, import, CPU/GPU frame time и memory с оборудованием/сценами; по результатам установить бюджеты следующего этапа.
- [ ] Устранить блокирующие дефекты UX, текста, DPI, форматов и exports; записать ограничения.
- [ ] Обновить docs, приложить проверенные результаты и только затем поставить первый MVP tag.
- [x] Пройти новую установку и создание проекта по документации на обеих ОС.
- [x] Повторить authoring-сценарий руками и через MCP; проверить Undo/Redo и конфликт revision при одновременной правке.
- [x] Проверить recovery после сбоя сохранения, импорта, сборки и завершения Player с ошибкой.
- [x] Записать startup, edit/build/run, import, CPU/GPU frame time и memory с оборудованием/сценами; по результатам установить бюджеты следующего этапа.
- [x] Устранить блокирующие дефекты UX, текста, DPI, форматов и exports; записать ограничения.
- [x] Обновить docs, приложить проверенные результаты и только затем поставить первый MVP tag.
## 4. Развитие после MVP
### P1. Lua и скорость итераций
Начальные бюджеты отслеживания для конкретных демо и Linux reference host: frame p95 ≤ 4 мс, GPU/readback p95 ≤ 1 мс, simulation/snapshot p95 ≤ 0,5 мс, явные Vulkan allocations ≤ 20 MiB, startup от `main()` ≤ 500 мс. [Методика и исходные измерения](docs/validation/linux-release-2026-09-18/README.md) ограничивают область этих чисел; для других сцен/ОС нужны отдельные baselines. Это бюджеты P1, а не обещание такой производительности любой игры.
Добавить Lua runtime/editor пакет поверх публичного API, проверяемых handles и схем. Предусмотреть диагностику, отладку, Inspector и явный lifecycle перезагрузки. Сохранение состояния при reload проектируется отдельно. Проверка: C++ и Lua используют одни данные/фазы; C++-only export не включает Lua.
Улучшать schema/build cache, сообщения компилятора, шаблоны проектов, переход к коду, autosave и измеренное время «изменение → результат». Dynamic gameplay loading рассматривать при подтверждённой проблеме линковки.
+10 -5
View File
@@ -2,7 +2,7 @@
Faset is an independent engine project for desktop **2D and 3D games on Linux and Windows**. Its priorities are a custom editor that is comfortable to use by hand and through MCP, integration with Blender, and a path toward advanced graphics.
**Current status: MVP acceptance is in progress.** The native Editor, shared GUI/MCP authoring, C++ gameplay builds, Vulkan Player, standalone export and two playable sample games are integrated. Linux GPU workflows are tested; complete Windows graphics/export acceptance and final validation remain in progress. See the [implementation checkpoints](docs/IMPLEMENTATION.md) for observed results; a technology appearing in the plan does not mean it is complete or benchmarked.
**Current status: the C++ MVP is implemented and accepted for the recorded Linux and Windows test profiles.** It includes the native Editor, shared GUI/MCP authoring, gameplay builds, Vulkan Player, Blender import and standalone export. Both playable games passed Release export and relocated execution on both operating systems. Windows graphics acceptance used software Vulkan; physical Windows GPUs, system IME and mixed-monitor transitions need additional coverage. See the [acceptance dossier](docs/validation/mvp-acceptance.md) for exact revisions, checks and limits, and the [implementation checkpoints](docs/IMPLEMENTATION.md) for the development record.
## Start here
@@ -18,7 +18,8 @@ After following the manual's build setup, run `build/linux-debug/faset_editor`
(or `build/windows-debug/faset_editor.exe`) to open the project launcher. The
[`collect-2d`](examples/projects/collect-2d) and
[`collect-3d`](examples/projects/collect-3d) projects include playable C++ examples;
the 3D example includes an original Blender asset and import instructions.
the 3D example includes an original Blender asset and import instructions. Import its
`Assets/exit-arch/manifest.json` once before Play, including after clearing its cache.
## Language
@@ -28,7 +29,7 @@ This README is in English. The current planning documents, studies, and research
## Accepted foundation
- **C++** for the core and the first gameplay implementation. **Lua** will follow as a separate module and will be optional for individual games.
- **C++** for the core and native gameplay. **Lua 5.4** is an optional sandboxed gameplay module, with Inspector schemas, development reload, and standalone export. See the [Lua guide](docs/manual/scripting/lua.md).
- Objects, components, and nested scene templates for authoring; **EnTT** for the runtime ECS. JSON authoring data, stable IDs, and cooked binary assets for export.
- A custom **Vulkan 1.3** backend, RenderGraph, and renderer. The backend calls Vulkan directly; gameplay uses Faset APIs. **Slang** compiles shaders, including compatible HLSL, to SPIR-V. The baseline renderer does not require ray tracing.
- **SDL3** behind Faset's platform API; **Box2D** and **Box3D** for physics.
@@ -38,7 +39,7 @@ This README is in English. The current planning documents, studies, and research
- **Editor-only MCP:** authoring, assets, import, builds, export, Play/Stop, and editor diagnostics. MCP is absent from the Player and exported games.
- Standard, **unmodified Blender**, glTF/GLB import, and an optional add-on for convenient export and stable IDs.
MVP is complete when two small games, one 2D and one 3D, can be created, saved, played, and exported for both operating systems. GPU-driven rendering, HZB, advanced shadows, temporal reconstruction, and dynamic global illumination follow the baseline.
The MVP provides two small games, one 2D and one 3D, with scene editing, C++ behavior, physics, Play and standalone export. A [Lua-only example](examples/lua) demonstrates the optional scripting module. GPU-driven rendering, HZB, advanced shadows, temporal reconstruction and dynamic global illumination follow this baseline.
## Run the research map
@@ -56,6 +57,10 @@ Open [localhost:4178](http://localhost:4178). The map is a documentation viewer,
## Repository contents
Documentation, studies, the source manifest, and the map's code are tracked in Git. Third-party engine source trees, installed dependencies, build outputs, and caches are excluded. Source links are pinned to the commits examined during research; Unreal Engine links may require access through Epic.
Faset's C++ source, tests, sample games, Blender add-on, Manual, architecture, studies,
selected validation evidence, and research map are tracked in Git. Third-party engine
source trees, installed dependencies, build outputs, and caches are excluded. Research
source links are pinned to the commits examined; Unreal Engine links may require
access through Epic.
See the [publication notes](docs/PUBLICATION.md) for publication scope and licensing status. A license for Faset's own content has not yet been selected. Third-party projects retain their own license terms.
+26 -3
View File
@@ -3,6 +3,9 @@
#include <faset/core/io.hpp>
#include <faset/editor/editor_ui.hpp>
#include <faset/editor/mcp.hpp>
#ifdef FASET_HAS_DEBUG_OVERLAY
#include <faset/editor/debug_overlay.hpp>
#endif
#include <thread>
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb_image_write.h>
@@ -54,6 +57,22 @@ int run_editor_ui(Session& session, bool enable_mcp, std::uint64_t max_frames,
const auto font = session.config().engine_root / "assets/fonts/NotoSans.ttf";
const auto theme = session.config().engine_root / "assets/ui/dark.json";
EditorUI ui(session, renderer, font, theme);
#ifdef FASET_HAS_DEBUG_OVERLAY
DebugOverlay diagnostics;
auto previous_frame = std::chrono::steady_clock::now();
#endif
const auto draw_frame = [&] {
#ifdef FASET_HAS_DEBUG_OVERLAY
const auto now = std::chrono::steady_clock::now();
const auto delta = std::chrono::duration<float>(now - previous_frame).count();
previous_frame = now;
auto snapshot = ui.snapshot();
diagnostics.append(snapshot, renderer, delta);
renderer.render(snapshot);
#else
renderer.render(ui.snapshot());
#endif
};
ui.set_project_switch_enabled(!enable_mcp);
McpServer server(session.commands());
StdioTransport transport;
@@ -66,7 +85,7 @@ int run_editor_ui(Session& session, bool enable_mcp, std::uint64_t max_frames,
[&](const Json& arguments) {
session.poll();
ui.frame({});
renderer.render(ui.snapshot());
draw_frame();
auto region =
arguments.value("viewport_only", true)
? ui.snapshot().scene_rect
@@ -101,8 +120,12 @@ int run_editor_ui(Session& session, bool enable_mcp, std::uint64_t max_frames,
}
}
session.poll();
ui.frame(renderer.poll_events());
renderer.render(ui.snapshot());
auto events = renderer.poll_events();
#ifdef FASET_HAS_DEBUG_OVERLAY
events = diagnostics.process_events(events);
#endif
ui.frame(events);
draw_frame();
if (ui.project_switch_requested())
return 3; // Application-level request: destroy this Session before opening another.
++frame;
+170 -37
View File
@@ -7,8 +7,13 @@
#include <faset/player/SceneView.hpp>
#include <faset/runtime/Runtime.hpp>
#include <faset/runtime/schema.hpp>
#include <faset/scripting/project.hpp>
#if defined(FASET_HAS_LUA)
#include <faset/scripting/LuaModule.hpp>
#endif
#include <filesystem>
#include <iostream>
#include <memory>
#include <set>
#include <stdexcept>
#include <vector>
@@ -177,28 +182,35 @@ void validatePackagedShaders(const std::filesystem::path& directory) {
int player_main(int argc, char** argv) {
const auto started = Clock::now();
try {
std::filesystem::path scenePath, assetsPath, capturePath, controlPath, profilePath;
bool headless = false, validateOnly = false, debugPhysics = false;
std::filesystem::path scenePath, assetsPath, capturePath, controlPath, profilePath,
projectRoot;
bool headless = false, validateOnly = false, debugPhysics = false, watchLua = false;
std::uint64_t maximumFrames = 0;
std::set<std::string> options;
for (int i = 1; i < argc; ++i) {
const std::string arg = argv[i];
if (arg == "--help") {
std::cout << "faset_player [--scene PATH] [--assets CACHE] [--frames N] "
"[--headless] [--capture PATH.ppm] [--validate] [--control PATH] "
"[--profile PATH.json] [--debug-physics]\n"
"No --scene: open scene.fscene beside the executable. CACHE contains "
"assets/<id>/.\n"
"Headless uses offscreen Vulkan; --frames uses the configured fixed "
"simulation delta.\n"
"--validate checks scene/resources on CPU without gameplay callbacks "
"or Vulkan initialization.\n"
"--control is an optional editor mailbox for pause/resume/step/stop, "
"without world queries.\n"
"--profile requires explicit --frames 1..100000; measured durations "
"include the first frame and renderer GPU waits/readback.\n"
"Keys: A/D horizontal, W/S vertical, Space jump, E interact, P pause, "
"N single-step, F3 physics boxes, Escape quit.\n";
std::cout
<< "faset_player [--scene PATH] [--assets CACHE] [--frames N] "
"[--headless] [--capture PATH.ppm] [--validate] [--control PATH] "
"[--profile PATH.json] [--debug-physics] [--project ROOT] "
"[--watch-lua]\n"
"No --scene: open scene.fscene beside the executable. CACHE contains "
"assets/<id>/.\n"
"Headless uses offscreen Vulkan; --frames uses the configured fixed "
"simulation delta.\n"
"--validate checks scene/resources on CPU without gameplay callbacks "
"or Vulkan initialization.\n"
"--control is an optional editor mailbox for pause/resume/step/stop, "
"without world queries.\n"
"--project loads Lua declared in project.faset.json; packaged projects "
"are discovered beside the scene or executable.\n"
"--watch-lua enables development-only script reload (or control "
"reload-lua): the scene restarts, runtime state is not preserved.\n"
"--profile requires explicit --frames 1..100000; measured durations "
"include the first frame and renderer GPU waits/readback.\n"
"Keys: A/D horizontal, W/S vertical, Space jump, E interact, P pause, "
"N single-step, F3 physics boxes, Escape quit.\n";
return 0;
}
if (!options.insert(arg).second)
@@ -218,6 +230,8 @@ int player_main(int argc, char** argv) {
controlPath = faset::path_from_utf8(value());
else if (arg == "--profile")
profilePath = faset::path_from_utf8(value());
else if (arg == "--project")
projectRoot = faset::path_from_utf8(value());
else if (arg == "--frames")
maximumFrames = count(value());
else if (arg == "--headless")
@@ -226,6 +240,8 @@ int player_main(int argc, char** argv) {
validateOnly = true;
else if (arg == "--debug-physics")
debugPhysics = true;
else if (arg == "--watch-lua")
watchLua = true;
else
throw std::invalid_argument("Unknown option: " + arg);
}
@@ -234,9 +250,22 @@ int player_main(int argc, char** argv) {
validateOnly))
throw std::invalid_argument("--profile requires an output path and explicit --frames "
"1..100000, without --validate");
if (options.contains("--project") && projectRoot.empty())
throw std::invalid_argument("--project requires a nonempty root path");
if (scenePath.empty())
scenePath = executableDirectory(argv[0]) / "scene.fscene";
scenePath = std::filesystem::absolute(scenePath).lexically_normal();
const auto executableRoot = executableDirectory(argv[0]);
if (projectRoot.empty()) {
if (std::filesystem::is_regular_file(scenePath.parent_path() / "project.faset.json"))
projectRoot = scenePath.parent_path();
else if (std::filesystem::is_regular_file(executableRoot / "project.faset.json"))
projectRoot = executableRoot;
}
if (!projectRoot.empty())
projectRoot = std::filesystem::absolute(projectRoot).lexically_normal();
if (watchLua && (projectRoot.empty() || validateOnly))
throw std::invalid_argument("--watch-lua requires a project, without --validate");
if (assetsPath.empty())
assetsPath = scenePath.parent_path();
if (!std::filesystem::is_directory(assetsPath))
@@ -246,10 +275,31 @@ int player_main(int argc, char** argv) {
maximumFrames = 1;
const auto sceneReadStarted = Clock::now();
const auto document = faset::player::readScene(scenePath);
faset::runtime::validate_scene_schemas(document, faset::gameplay::schema());
const auto nativeSchema = faset::gameplay::schema();
if (!nativeSchema.is_array())
throw std::runtime_error("Gameplay schema() must return a type array");
const auto luaProject = projectRoot.empty() ? faset::scripting::LuaProject{}
: faset::scripting::loadLuaProject(projectRoot);
auto schema = nativeSchema;
#if defined(FASET_HAS_LUA)
std::unique_ptr<faset::scripting::LuaModule> lua;
if (luaProject.enabled()) {
lua = std::make_unique<faset::scripting::LuaModule>(luaProject);
for (const auto& type : lua->schema())
schema.push_back(type);
}
#else
if (luaProject.enabled() || watchLua)
throw std::runtime_error("This Player was built without Lua support; configure "
"FASET_ENABLE_LUA=ON for this project");
#endif
faset::runtime::validate_scene_schemas(document, schema);
#if defined(FASET_HAS_LUA)
if (lua)
lua->validateScene(document);
#endif
const auto config = simulationConfig(document);
const auto sceneReadFinished = Clock::now();
const auto executableRoot = executableDirectory(argv[0]);
if (scenePath.extension() == ".fscene" &&
std::filesystem::equivalent(scenePath.parent_path(), executableRoot))
validatePackagedShaders(executableRoot);
@@ -272,9 +322,24 @@ int player_main(int argc, char** argv) {
return 0;
}
const auto worldStarted = Clock::now();
faset::runtime::Runtime world(config);
faset::gameplay::registerGameplay(world);
world.load(document);
auto world = std::make_unique<faset::runtime::Runtime>(config);
faset::gameplay::registerGameplay(*world);
#if defined(FASET_HAS_LUA)
if (lua)
lua->registerBehaviors(*world);
#endif
world->load(document);
std::size_t logCursor = 0;
auto printGameplayLogs = [&]() {
while (logCursor < world->diagnostics().size())
std::cerr << world->diagnostics()[logCursor++] << '\n';
#if defined(FASET_HAS_LUA)
if (lua)
for (const auto& message : lua->takeLogs())
std::cerr << message << '\n';
#endif
};
printGameplayLogs();
faset::player::SceneView view(assetsPath);
const auto rendererStarted = Clock::now();
faset::render::Renderer renderer(
@@ -287,16 +352,78 @@ int player_main(int argc, char** argv) {
std::set<std::string> held;
bool stop = false;
std::uint64_t frames = 0;
std::size_t logCursor = 0;
std::set<std::string> reported;
std::uint64_t controlSequence = 0;
std::string previousControl;
auto previous = std::chrono::steady_clock::now();
#if defined(FASET_HAS_LUA)
auto lastLuaCheck = Clock::now();
std::string lastLuaFingerprint = luaProject.fingerprint;
std::string lastLuaReloadError;
auto reloadLua = [&](bool force) {
if (!watchLua)
return;
const auto now = Clock::now();
if (!force && now - lastLuaCheck < std::chrono::milliseconds(500))
return;
lastLuaCheck = now;
std::string candidateFingerprint;
try {
const auto candidateProject = faset::scripting::loadLuaProject(projectRoot);
candidateFingerprint = candidateProject.fingerprint;
if (!force && candidateProject.fingerprint == lastLuaFingerprint)
return;
// Do not repeatedly execute a broken candidate every half-second.
// A corrected source or manifest produces a new fingerprint.
lastLuaFingerprint = candidateProject.fingerprint;
auto candidateSchema = nativeSchema;
std::unique_ptr<faset::scripting::LuaModule> candidateLua;
if (candidateProject.enabled()) {
candidateLua = std::make_unique<faset::scripting::LuaModule>(candidateProject);
for (const auto& type : candidateLua->schema())
candidateSchema.push_back(type);
}
faset::runtime::validate_scene_schemas(document, candidateSchema);
if (candidateLua)
candidateLua->validateScene(document);
auto candidateWorld = std::make_unique<faset::runtime::Runtime>(config);
faset::gameplay::registerGameplay(*candidateWorld);
if (candidateLua)
candidateLua->registerBehaviors(*candidateWorld);
candidateWorld->load(document);
// Runtime isolates callback exceptions into diagnostics. A bad
// on_start must not replace the currently running scene.
if (!candidateWorld->diagnostics().empty())
throw std::runtime_error(candidateWorld->diagnostics().front());
candidateWorld->setPaused(world->paused());
world->clear();
printGameplayLogs();
world = std::move(candidateWorld);
lua = std::move(candidateLua);
logCursor = 0;
printGameplayLogs();
lastLuaReloadError.clear();
// Compilation and initialization are not simulation wall time.
previous = Clock::now();
std::cerr << "Lua reloaded: scene restarted; runtime state reset\n";
} catch (const std::exception& error) {
const std::string message =
std::string("Lua reload rejected; previous scene retained: ") + error.what();
// Bad/missing manifests may fail before a fingerprint exists.
// Retry them on the next poll but report an unchanged failure once.
const auto failure = candidateFingerprint + "\n" + message;
if (force || failure != lastLuaReloadError)
std::cerr << message << '\n';
lastLuaReloadError = failure;
}
};
#endif
while (!stop && !renderer.should_close() &&
(maximumFrames == 0 || frames < maximumFrames)) {
const auto frameStarted = Clock::now();
faset::runtime::InputState input;
bool singleStep = false;
bool requestLuaReload = false;
if (!controlPath.empty() && std::filesystem::is_regular_file(controlPath)) {
try {
if (std::filesystem::file_size(controlPath) > 65536)
@@ -314,14 +441,16 @@ int player_main(int argc, char** argv) {
if (value > controlSequence) {
const auto command = message.at("command").get<std::string>();
if (command == "pause")
world.setPaused(true);
world->setPaused(true);
else if (command == "resume")
world.setPaused(false);
world->setPaused(false);
else if (command == "step") {
world.setPaused(true);
world->setPaused(true);
singleStep = true;
} else if (command == "stop")
stop = true;
else if (command == "reload-lua" && watchLua)
requestLuaReload = true;
else
throw std::invalid_argument("unsupported control command");
controlSequence = value;
@@ -355,7 +484,7 @@ int player_main(int argc, char** argv) {
if (key == "E")
input.interactPressed = true;
if (key == "P")
world.setPaused(!world.paused());
world->setPaused(!world->paused());
if (key == "N")
singleStep = true;
if (key == "F3")
@@ -365,6 +494,11 @@ int player_main(int argc, char** argv) {
}
if (stop)
break;
#if defined(FASET_HAS_LUA)
reloadLua(requestLuaReload);
#else
(void)requestLuaReload;
#endif
input.horizontal = float(held.contains("D") || held.contains("RIGHT")) -
float(held.contains("A") || held.contains("LEFT"));
input.vertical = float(held.contains("W") || held.contains("UP")) -
@@ -375,14 +509,15 @@ int player_main(int argc, char** argv) {
: std::chrono::duration<double>(now - previous).count();
previous = now;
const auto simulationStarted = Clock::now();
const auto runtimeStats = singleStep && world.paused() ? world.singleStep(input)
: world.advance(elapsed, input);
const auto runtimeStats = singleStep && world->paused()
? world->singleStep(input)
: world->advance(elapsed, input);
const auto simulationFinished = Clock::now();
const auto presentation = world.snapshotJson();
const auto presentation = world->snapshotJson();
auto snapshot = view.build(presentation, static_cast<float>(renderer.width()) /
std::max(1u, renderer.height()));
if (debugPhysics)
view.appendPhysicsDebug(snapshot, physicsScene(world, presentation));
view.appendPhysicsDebug(snapshot, physicsScene(*world, presentation));
const auto snapshotFinished = Clock::now();
for (const auto& diagnostic : view.diagnostics()) {
if (diagnostic.starts_with("error:"))
@@ -390,8 +525,7 @@ int player_main(int argc, char** argv) {
if (reported.insert(diagnostic).second)
std::cerr << diagnostic << '\n';
}
while (logCursor < world.diagnostics().size())
std::cerr << world.diagnostics()[logCursor++] << '\n';
printGameplayLogs();
const auto renderStarted = Clock::now();
renderer.render(snapshot);
const auto frameFinished = Clock::now();
@@ -409,12 +543,11 @@ int player_main(int argc, char** argv) {
}
++frames;
}
const auto completedTicks = world.snapshot().tick;
const auto completedTicks = world->snapshot().tick;
// Run normal shutdown while diagnostics are still observable. Runtime's
// destructor is a fallback and cannot print messages after this scope ends.
world.clear();
while (logCursor < world.diagnostics().size())
std::cerr << world.diagnostics()[logCursor++] << '\n';
world->clear();
printGameplayLogs();
if (!capturePath.empty()) {
if (frames == 0)
throw std::runtime_error("No frame was rendered for capture");
+28 -4
View File
@@ -1,27 +1,51 @@
#include "Gameplay.hpp"
#include <faset/core/io.hpp>
#include <faset/runtime/schema.hpp>
#include <faset/scripting/project.hpp>
#if defined(FASET_HAS_LUA)
#include <faset/scripting/LuaModule.hpp>
#endif
#include <iostream>
#include <stdexcept>
int schema_main(int argc, char** argv) {
try {
std::filesystem::path output;
std::filesystem::path output, projectRoot;
for (int i = 1; i < argc; ++i) {
const std::string argument = argv[i];
if (argument == "--help") {
std::cout << "faset_schema_exporter [--output PATH]\nExports declarative gameplay "
"schemas without creating a world.\n";
std::cout << "faset_schema_exporter [--output PATH] [--project ROOT]\n"
"Exports C++ and declared Lua gameplay schemas without creating a "
"world or invoking lifecycle callbacks.\n";
return 0;
}
if (argument == "--output" && i + 1 < argc && output.empty())
output = faset::path_from_utf8(argv[++i]);
else if (argument == "--project" && i + 1 < argc && projectRoot.empty())
projectRoot = faset::path_from_utf8(argv[++i]);
else
throw std::invalid_argument("Unknown, repeated or incomplete argument: " +
argument);
}
const auto types = faset::gameplay::schema();
auto types = faset::gameplay::schema();
if (!types.is_array())
throw std::runtime_error("Gameplay schema() must return a type array");
if (!projectRoot.empty()) {
const auto project = faset::scripting::loadLuaProject(projectRoot);
if (project.enabled()) {
#if defined(FASET_HAS_LUA)
faset::scripting::LuaModule lua(project);
for (const auto& type : lua.schema())
types.push_back(type);
#else
throw std::runtime_error("This schema exporter was built without Lua support; "
"configure FASET_ENABLE_LUA=ON for this project");
#endif
}
}
// Check all IDs, including unused types, before publishing a manifest.
// This player-side boundary intentionally has no authoring dependency.
faset::runtime::validate_scene_schemas({{"entities", nlohmann::json::array()}}, types);
const nlohmann::json manifest{{"format", "faset.schema"}, {"version", 1}, {"types", types}};
if (output.empty())
std::cout << manifest.dump(2) << '\n';
+8 -1
View File
@@ -1,10 +1,17 @@
add_library(faset_build_service STATIC ${PROJECT_SOURCE_DIR}/src/editor/build_service.cpp)
target_include_directories(faset_build_service PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_compile_features(faset_build_service PUBLIC cxx_std_20)
target_link_libraries(faset_build_service PUBLIC faset_core PRIVATE faset_asset_data Threads::Threads)
target_link_libraries(faset_build_service PUBLIC faset_core faset_scripting_project PRIVATE faset_assets faset_authoring Threads::Threads)
if(BUILD_TESTING)
add_executable(faset_build_service_tests ${PROJECT_SOURCE_DIR}/tests/build_service_tests.cpp)
target_link_libraries(faset_build_service_tests PRIVATE faset_build_service faset_assets)
target_compile_definitions(faset_build_service_tests PRIVATE FASET_ENGINE_SOURCE="${PROJECT_SOURCE_DIR}")
add_test(NAME process_and_cook COMMAND faset_build_service_tests)
add_executable(faset_build_schema_tool ${PROJECT_SOURCE_DIR}/tests/build_schema_tool.cpp)
target_link_libraries(faset_build_schema_tool PRIVATE faset_core)
add_executable(faset_build_schema_tests ${PROJECT_SOURCE_DIR}/tests/build_schema_tests.cpp)
target_link_libraries(faset_build_schema_tests PRIVATE faset_build_service faset_authoring faset_editor_commands)
add_dependencies(faset_build_schema_tests faset_build_schema_tool)
add_test(NAME build_schema_publication COMMAND faset_build_schema_tests $<TARGET_FILE:faset_build_schema_tool> ${PROJECT_SOURCE_DIR})
set_tests_properties(build_schema_publication PROPERTIES TIMEOUT 60)
endif()
+15
View File
@@ -0,0 +1,15 @@
if(FASET_DEBUG_IMGUI AND TARGET faset_imgui AND TARGET faset_render)
add_library(faset_debug_overlay STATIC ${PROJECT_SOURCE_DIR}/src/editor/debug_overlay.cpp)
target_include_directories(faset_debug_overlay PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_link_libraries(faset_debug_overlay PUBLIC faset_render PRIVATE faset_imgui)
if(TARGET faset_editor AND TARGET faset_editor_ui)
target_link_libraries(faset_editor PRIVATE faset_debug_overlay)
target_compile_definitions(faset_editor PRIVATE FASET_HAS_DEBUG_OVERLAY=1)
endif()
if(BUILD_TESTING)
add_executable(faset_debug_overlay_tests ${PROJECT_SOURCE_DIR}/tests/editor_debug_overlay.cpp)
target_link_libraries(faset_debug_overlay_tests PRIVATE faset_debug_overlay)
add_test(NAME editor_debug_overlay COMMAND faset_debug_overlay_tests)
set_tests_properties(editor_debug_overlay PROPERTIES LABELS "gpu")
endif()
endif()
+38
View File
@@ -0,0 +1,38 @@
# Official Lua sources are checksum-pinned in dependencies.lock.json. Build only
# the VM and libraries, never the standalone lua/luac executables or a system ABI.
faset_dependency(lua)
set(lua_src "${FASET_lua_SOURCE_DIR}/src")
add_library(faset_lua_vendor STATIC
${lua_src}/lapi.c ${lua_src}/lcode.c ${lua_src}/lctype.c
${lua_src}/ldebug.c ${lua_src}/ldo.c ${lua_src}/ldump.c
${lua_src}/lfunc.c ${lua_src}/lgc.c ${lua_src}/llex.c
${lua_src}/lmem.c ${lua_src}/lobject.c ${lua_src}/lopcodes.c
${lua_src}/lparser.c ${lua_src}/lstate.c ${lua_src}/lstring.c
${lua_src}/ltable.c ${lua_src}/ltm.c ${lua_src}/lundump.c
${lua_src}/lvm.c ${lua_src}/lzio.c ${lua_src}/lauxlib.c
${lua_src}/lbaselib.c ${lua_src}/lmathlib.c ${lua_src}/lstrlib.c
${lua_src}/ltablib.c ${lua_src}/lutf8lib.c)
target_include_directories(faset_lua_vendor SYSTEM PUBLIC "${lua_src}")
if(NOT MSVC)
# Upstream intentionally uses compiler-supported computed gotos in the VM.
target_compile_options(faset_lua_vendor PRIVATE -Wno-pedantic)
endif()
if(UNIX)
target_link_libraries(faset_lua_vendor PUBLIC m)
endif()
add_library(faset_lua STATIC ${PROJECT_SOURCE_DIR}/src/scripting/LuaModule.cpp)
add_library(Faset::Lua ALIAS faset_lua)
target_include_directories(faset_lua PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_link_libraries(faset_lua PUBLIC faset_runtime faset_scripting_project PRIVATE faset_lua_vendor)
if(BUILD_TESTING)
add_executable(faset_lua_tests ${PROJECT_SOURCE_DIR}/tests/lua_tests.cpp)
target_link_libraries(faset_lua_tests PRIVATE faset_lua)
target_compile_definitions(faset_lua_tests PRIVATE FASET_SOURCE_DIR="${PROJECT_SOURCE_DIR}")
add_test(NAME lua_contracts COMMAND faset_lua_tests)
set_tests_properties(lua_contracts PROPERTIES TIMEOUT 30)
add_executable(faset_lua_safety_tests ${PROJECT_SOURCE_DIR}/tests/lua_safety_tests.cpp)
target_link_libraries(faset_lua_safety_tests PRIVATE faset_lua)
add_test(NAME lua_safety_contracts COMMAND faset_lua_safety_tests)
set_tests_properties(lua_safety_contracts PROPERTIES TIMEOUT 30)
endif()
+34 -3
View File
@@ -1,6 +1,10 @@
if(TARGET faset_gameplay)
add_executable(faset_schema_exporter ${PROJECT_SOURCE_DIR}/apps/schema_exporter_main.cpp)
target_link_libraries(faset_schema_exporter PRIVATE faset_core faset_gameplay)
target_link_libraries(faset_schema_exporter PRIVATE faset_core faset_gameplay faset_scripting_project)
if(TARGET faset_lua)
target_link_libraries(faset_schema_exporter PRIVATE faset_lua)
target_compile_definitions(faset_schema_exporter PRIVATE FASET_HAS_LUA=1)
endif()
endif()
if(TARGET faset_runtime AND TARGET faset_render AND TARGET faset_assets)
@@ -14,7 +18,11 @@ if(TARGET faset_runtime AND TARGET faset_render AND TARGET faset_assets)
target_compile_definitions(faset_scene_view PRIVATE FASET_HAS_STB=1)
endif()
add_executable(faset_player ${PROJECT_SOURCE_DIR}/apps/player_main.cpp)
target_link_libraries(faset_player PRIVATE faset_scene_view faset_runtime faset_gameplay)
target_link_libraries(faset_player PRIVATE faset_scene_view faset_runtime faset_gameplay faset_scripting_project)
if(TARGET faset_lua)
target_link_libraries(faset_player PRIVATE faset_lua)
target_compile_definitions(faset_player PRIVATE FASET_HAS_LUA=1)
endif()
install(TARGETS faset_player RUNTIME DESTINATION .)
if(BUILD_TESTING)
add_executable(faset_player_tests ${PROJECT_SOURCE_DIR}/tests/runtime_player_tests.cpp)
@@ -28,7 +36,11 @@ if(TARGET faset_runtime AND TARGET faset_render AND TARGET faset_assets)
${PROJECT_SOURCE_DIR}/tests/player_diagnostics/Gameplay.cpp)
target_include_directories(faset_player_diagnostics PRIVATE
${PROJECT_SOURCE_DIR}/tests/player_diagnostics)
target_link_libraries(faset_player_diagnostics PRIVATE faset_scene_view faset_runtime)
target_link_libraries(faset_player_diagnostics PRIVATE faset_scene_view faset_runtime faset_scripting_project)
if(TARGET faset_lua)
target_link_libraries(faset_player_diagnostics PRIVATE faset_lua)
target_compile_definitions(faset_player_diagnostics PRIVATE FASET_HAS_LUA=1)
endif()
find_package(Python3 COMPONENTS Interpreter REQUIRED)
add_test(NAME player_shutdown_diagnostics COMMAND ${Python3_EXECUTABLE}
${PROJECT_SOURCE_DIR}/tests/player_diagnostics_test.py
@@ -36,3 +48,22 @@ if(TARGET faset_runtime AND TARGET faset_render AND TARGET faset_assets)
set_tests_properties(player_shutdown_diagnostics PROPERTIES LABELS "gpu" TIMEOUT 60)
endif()
endif()
if(BUILD_TESTING AND TARGET faset_schema_exporter)
find_package(Python3 COMPONENTS Interpreter REQUIRED)
set(FASET_LUA_CLI_TEST_ARGS --exporter $<TARGET_FILE:faset_schema_exporter>)
if(TARGET faset_player)
list(APPEND FASET_LUA_CLI_TEST_ARGS --player $<TARGET_FILE:faset_player>)
endif()
if(NOT TARGET faset_lua)
list(APPEND FASET_LUA_CLI_TEST_ARGS --disabled)
endif()
add_test(NAME lua_cli_contracts COMMAND ${Python3_EXECUTABLE}
${PROJECT_SOURCE_DIR}/tests/lua_cli_test.py ${FASET_LUA_CLI_TEST_ARGS})
set_tests_properties(lua_cli_contracts PROPERTIES TIMEOUT 90)
if(TARGET faset_lua AND TARGET faset_player)
add_test(NAME lua_player_reload COMMAND ${Python3_EXECUTABLE}
${PROJECT_SOURCE_DIR}/tests/lua_player_reload_test.py $<TARGET_FILE:faset_player>)
set_tests_properties(lua_player_reload PROPERTIES LABELS "gpu" TIMEOUT 90)
endif()
endif()
+5 -2
View File
@@ -7,8 +7,11 @@ target_include_directories(faset_runtime PUBLIC ${CMAKE_CURRENT_LIST_DIR}/../inc
target_link_libraries(faset_runtime PUBLIC nlohmann_json::nlohmann_json PRIVATE EnTT::EnTT box2d box3d)
set(FASET_GAMEPLAY_SOURCE_DIR "${PROJECT_SOURCE_DIR}/examples/gameplay" CACHE PATH "Directory containing the game's Gameplay.cpp and Gameplay.hpp")
if(NOT EXISTS "${FASET_GAMEPLAY_SOURCE_DIR}/Gameplay.cpp" OR NOT EXISTS "${FASET_GAMEPLAY_SOURCE_DIR}/Gameplay.hpp")
message(FATAL_ERROR "FASET_GAMEPLAY_SOURCE_DIR must contain Gameplay.cpp and Gameplay.hpp")
if(NOT EXISTS "${FASET_GAMEPLAY_SOURCE_DIR}/Gameplay.cpp" AND NOT EXISTS "${FASET_GAMEPLAY_SOURCE_DIR}/Gameplay.hpp" AND FASET_ENABLE_LUA)
# A Lua-only game needs the same stable native entry points, but no user C++.
set(FASET_GAMEPLAY_SOURCE_DIR "${PROJECT_SOURCE_DIR}/src/scripting/empty_gameplay")
elseif(NOT EXISTS "${FASET_GAMEPLAY_SOURCE_DIR}/Gameplay.cpp" OR NOT EXISTS "${FASET_GAMEPLAY_SOURCE_DIR}/Gameplay.hpp")
message(FATAL_ERROR "Provide both Gameplay.cpp and Gameplay.hpp, or enable Lua for a Lua-only project")
endif()
add_library(faset_gameplay STATIC "${FASET_GAMEPLAY_SOURCE_DIR}/Gameplay.cpp")
add_library(Faset::Gameplay ALIAS faset_gameplay)
+8
View File
@@ -1,6 +1,14 @@
{
"format": 1,
"dependencies": {
"lua": {
"repository": "https://www.lua.org",
"version": "5.4.9",
"commit": "5.4.9",
"url": "https://www.lua.org/ftp/lua-5.4.9.tar.gz",
"sha256": "2335b6c582a52654f94612bf10d2f4672805d05329aa6568b1d8cd9e5c6fb8e6",
"license": "MIT"
},
"sdl3": {
"repository": "https://github.com/libsdl-org/SDL",
"version": "release-3.2.20",
+2
View File
@@ -47,6 +47,8 @@ Entry function плагина согласует версию интерфейс
`TypeId/FieldId` описывают смысл сохраняемых данных и не зависят от имени C++, offset, порядка членов или `typeid`. Layout fingerprint нужен для совместимости конкретной сборки. Переименование сохраняет ID; изменение смысла/единиц требует миграции. Отсутствующий плагин не уничтожает неизвестные записи. Lua позже использует явно экспортированный runtime API и проверяемые handles; наличие metadata не делает каждый native-метод доступным MCP или Lua.
MVP доставляет декларативные шаги миграции через тот же schema manifest: `default`, `scale` и `require_manual`. Вся схема и правила проверяются до публикации Player/schema generation. Старые версии открываются как opaque data; миграция выполняется явно командой `component.migrate` с revision, одним Undo и записью recovery. Inherited component изменяется в исходной сцене; sparse overrides других экземпляров требуют явного обзора при изменении смысла или единиц. Произвольный C++ migration callback в Editor не загружается. Контракт и проверяемый пример — в [Manual](manual/scripting/api.md#editor-data-migrations).
## 5. Авторские данные, сцены и редактор — принято
Пользователь работает со сценами, объектами, компонентами и ресурсами. Сцены допускают **вложенные экземпляры шаблонов**. JSON хранит ссылку на исходный шаблон и **sparse overrides** — только локальные отличия, с устойчивыми адресами полей/объектов. Подписи и пути не являются идентичностью. Для добавления, удаления и изменения вложенного содержимого нужны явные операции; потерянная цель override становится диагностируемым конфликтом, а не молчаливым удалением данных.
+132
View File
@@ -3,6 +3,11 @@
This log records working implementation and observed validation. It does not replace
the acceptance criteria in `PLAN.md`. Incomplete platform or workflow checks remain open.
**Current result:** the C++ MVP is accepted in the recorded Linux and Windows profiles.
The [final dossier](validation/mvp-acceptance.md) maps M0M9 to evidence and keeps
unverified compatibility scenarios explicit. Earlier pending/failure statements below
describe their respective checkpoints, not the final status.
## Checkpoint 1 — native foundation and independent subsystems
Implemented:
@@ -206,3 +211,130 @@ The final build-service review also reproduced a publication defect: an invalid
custom-field default can pass the build stage's shallow schema check before the
Editor rejects it. Full schema validation before publishing `last_build.json` is the
next bounded correction; checkpoint 4 does not claim this gate is already complete.
## Acceptance corrections after checkpoint 4
Gameplay schema publication now uses the same complete metadata validation as the
Editor, before either the Player generation or `last_build.json` is published.
A native fixture drives the real BuildService with valid custom schema v2 and twelve
invalid manifests, checking that the previous binary, schema, manifest and pointer
remain unchanged. The focused authoring/process/schema/Session/MCP suite passed 5/5.
An authoring-disabled Player configuration still builds without editor services.
Windows native checks passed for checkpoint 4 (`45bc352`) and `afd773f`, including
the previous long-path regression. The full graphics runner also passed its Vulkan
1.3 device probe after registering the pinned software ICD on the disposable elevated
runner. Full Windows graphics and export acceptance is still in progress; a successful
probe alone does not close that gate.
The final audit identified additional bounded work: source/dependency freshness in
the Assets panel, scrolling keyboard focus into view, delivery of explicit gameplay
schema migrations, GPU pass labels, and wiring optional ImGui diagnostics. These
remain under implementation and verification; the research map now links current
implementation evidence instead of claiming the engine has not been started.
## Checkpoint 5 — close the final authoring and diagnostics gaps
- Asset freshness compares source, bundle payload, external buffer/image, recipe,
importer and profile contents without publishing a generation. GUI and MCP expose
the same state/reasons; selecting a stale imported row prepares Reimport. Cook and
export reject stale referenced sources while keeping the previous successful result.
- Gameplay schemas carry validated declarative migration steps. Inspector and MCP
apply `component.migrate` as an explicit revision-checked Undo transaction. Opening
old data remains possible without rules. Tests cover local components, instance-local
additions, opening inherited sources, missing/manual rules and overflow rollback.
The Manual explains the sparse-override limitation when field units change.
- Keyboard focus scrolls long and nested Inspector/Assets lists into view at 1×/2×,
preserves unfinished text and keeps invalid numeric edits visible. Template preview
and conflicts are also invalidated when schema metadata changes without a scene edit.
- Vulkan passes emit optional debug-utils labels. An optional `FASET_DEBUG_IMGUI=ON`
Editor module shows real renderer diagnostics via F12; the Player remains independent.
GPU tests cover textured/clipped ImGui geometry and event ownership for gestures
crossing the panel in either direction. Offscreen clipboard operations are local
to that renderer and never touch the desktop clipboard.
- The Windows launcher fixture compares canonical filesystem identities, including
hosted-runner short TEMP aliases, and now distinguishes selection/path failures.
Integrated Linux with optional diagnostics enabled: **34 passed, 1 skipped, 0 failed**
of 35 tests. The skip remains native Wayland programmatic restore; XWayland passed.
ASan/UBSan passed **18/18**, including process cleanup, metadata publication and
migration transactions. Strict MkDocs and local Markdown file-link checks passed.
Windows run `35299805623` at `e0b9651` passed all **34** tests in its CPU/GPU/UI suite,
including the launcher fix, and proceeded to real native Release exports. That run
predates checkpoint 5's new authoring/diagnostic changes, whose Windows checks remain
separate. The next full Windows build enables the optional diagnostic module too.
No MVP tag is claimed at this checkpoint.
## Checkpoint 5 acceptance and source relocation correction
The clean `0f34b03` Linux checkout built offline with 20/20 CPU tests, then created
and rendered a fresh project using the Manual's command. Both checked-in games were
exported in Release, moved outside the SDK into Unicode paths and run for 120 frames
with source projects hidden; Khronos validation was active with no errors. All seven
recovery scenarios and the real Blender/live-Editor round-trip passed. Exact inputs,
hashes and limits are in [the Linux acceptance record](validation/checkpoint5-linux-2026-09-18/README.md).
A subsequent source-relocation regression was reproduced and corrected: a cache-hit
rename/move updated the logical source pointer while retaining the historical payload
path, so the new freshness check incorrectly kept the asset stale. Publication now
stores both paths atomically. Earlier pointers remain readable by resolving the
payload relative to the moved logical source; immutable content generations and cache
keys are unchanged. Regression cases cover PNG, Blender bundles and external glTF
buffers/images, with both new and legacy pointer records. Full Linux integration
remains 34 passed / 1 explicit Wayland skip / 0 failed; targeted ASan/UBSan asset/cook
checks passed 2/2 after this correction.
Windows run `35299805623` at `e0b9651` completed successfully, including both Release
integration exports, incremental C++ rebuilding, and the two checked-in games with
Unicode relocation. It used SwiftShader without the Khronos validation layer and is
functional software-Vulkan evidence, not a physical-GPU benchmark. Checkpoint 5's
newer Windows graphics/export run and the relocation correction have their own
revision-specific gates.
## MVP acceptance — `v0.1.0-mvp`
Final engine source: `4cb82556de31268d2bde73948dd1ff1b6c02f162`. The publication
commit adds documentation, acceptance records and research-viewer wording; it does
not change the accepted engine, gameplay, shader or build-system sources.
- [Final Linux evidence](validation/final-linux-2026-09-18/README.md): 34 passed,
one explicit native Wayland restore skip, zero failed. Both exact-source Release
games passed manifest validation and 120 frames after Unicode relocation with
their source projects hidden. An additional private namespace hid the entire SDK,
build directories, Editor and cached tools; both games still passed another 120
frames with matching captures, active Khronos validation and zero errors.
- [Final Windows evidence](validation/windows-software-vulkan-2026-09-18/README.md):
[run 35301244334](https://github.com/emil28092005/Faset_Engine/actions/runs/35301244334)
passed the fresh full Editor build with ImGui diagnostics, **35/35 tests**, real
BuildService Release exports/incremental Debug rebuild and both checked-in games
after Unicode relocation. Each rendered 120 frames. SwiftShader supplied software
Vulkan; the Khronos layer was unavailable. This is functional Windows execution,
not physical Windows GPU or hardware-performance evidence.
- [Native/manual CI](https://github.com/emil28092005/Faset_Engine/actions/runs/35301244366)
passed for the same final source. The earlier clean offline build and first project
launch, seven recovery scenarios, actual Blender/live-Editor round-trip and full
18-test sanitizer run retain their `0f34b03` provenance. The two affected asset/cook
sanitizer checks passed again after the relocation correction.
- PLAN now closes M0M9 against the dossier. The English Manual documents the working
C++ tutorials, metadata/migrations, authoring, assets, MCP, extensions and export.
A final instruction check corrected the 3D sample's required first bundle import.
The recorded reference-scene thresholds are initial P1 tracking budgets.
Final publication checks passed: strict MkDocs build, both research-map tests and its
production build, 318 local Markdown links, retained Windows evidence hashes, all
validation JSON records and `git diff --check`. The engine-source diff from the
accepted commit is empty; no untested engine changes were bundled into publication.
The post-publication documentation check also verified hashes against Git blobs,
which normalize Windows JSON line endings to LF. Evidence indices now identify both
the retained repository bytes and original CRLF artifacts explicitly. This follow-up
changes only documentation metadata and preserves the first MVP tag and engine code.
Known coverage limits remain: real OS IME composition, movement between physical
monitors with different scales, native Wayland programmatic restore and additional
GPU/driver families. Widget composition/DPI, SDL text-input boundaries, XWayland and
Windows window lifecycle have their own passing evidence. The narrow static-mesh,
root-level box-physics, one-window/C++ MVP profile remains explicit. Lua and advanced
graphics are later work. UI references guide appearance; they do not define behavior.
+3 -3
View File
@@ -4,9 +4,9 @@
## Что публикуется
Собственные архитектурные описания и планы Faset, исследования со ссылками на первичные источники, манифест исследованных snapshots и исходники локальной карты документации. Утверждённый план не выдаётся за готовую реализацию движка.
Собственный C++-код Faset, тесты, примеры игр, Blender add-on, пользовательский Manual, архитектура и план, исследования со ссылками на первичные источники, манифест исследованных snapshots и исходники локальной карты документации. Выбранные воспроизводимые отчёты и измерения публикуются в docs/validation с указанием исходного состояния и ограничений. Готовность MVP определяется критериями PLAN, а не наличием отдельных подсистем.
Сторонние source checkouts, локальные индексы graphify, node_modules, dist, логи, credentials и пользовательские рабочие каталоги не входят в публикацию. Браузерный source viewer предназначен для локального использования и не является сервисом публичной раздачи стороннего кода.
Сторонние source checkouts, локальные индексы graphify, node_modules, dist, временные логи, credentials и пользовательские рабочие каталоги не входят в публикацию. Браузерный source viewer предназначен для локального использования и не является сервисом публичной раздачи стороннего кода.
Исходники Unreal требуют соответствующего доступа Epic; публикация ссылки на commit не предоставляет этот доступ. У Godot, UnityCsReference, Blender и остальных источников остаются их собственные условия. Подробности — в [DEPENDENCIES.md](DEPENDENCIES.md).
@@ -16,6 +16,6 @@
## Проверки публикации
Проверяются состав Git, отсутствие локальных секретов и чужих source trees, внутренние ссылки, source pins, запуск/сборка карты и границы её файлового API. Проверки карты и документов не являются тестами будущего C++-движка, Blender integration или графической производительности.
Проверяются состав Git, отсутствие локальных секретов и чужих source trees, внутренние ссылки, source pins, запуск/сборка карты и границы её файлового API. Проверки карты и документов не заменяют тесты C++-движка, Blender integration или графической производительности. Native CI, GPU-проверки, автономные exports и приёмочные сценарии описаны отдельно в [журнале реализации](IMPLEMENTATION.md) и [результатах проверок](validation/README.md).
Локальные source paths в манифесте являются необязательными относительными подсказками. Публичные Markdown-ссылки на исходники закреплены на upstream commits и не зависят от имени пользователя или расположения Desktop.
+1 -1
View File
@@ -1,6 +1,6 @@
# Документация Faset Engine
Актуализировано 18.09.2026 по принятым решениям. Реализация MVP ведётся параллельно с проверками и пользовательским руководством.
Актуализировано 18.09.2026. C++ MVP реализован и принят в зафиксированных профилях Linux и Windows; результаты и пределы проверок — в [досье приёмки](validation/mvp-acceptance.md). Manual описывает текущие функции, PLAN отделяет их от следующих этапов.
## Канонические документы
+11 -7
View File
@@ -13,9 +13,10 @@ compiler, platform, CRT, configuration, dependencies and SDK source identity.
- **Linux CI:** Ubuntu 24.04, x86-64, Clang **18.1.3**. The headless CPU suite and
manual run on this profile. It is not evidence for desktop rendering on that runner.
- **Windows CI:** Windows Server 2025 runner, x86-64, clang-cl **20.1.8**,
MSVC toolset **14.51.36231**, Windows SDK **10.0.26100.0**. Headless tests have
passed. Full Editor, software Vulkan and Release-package acceptance are tracked
separately in the implementation log until that job completes.
MSVC toolset **14.51.36231**, Windows SDK **10.0.26100.0**. Native headless tests,
the full Editor with optional diagnostics, all 35 CPU/software-GPU tests and both
relocated Release games passed. See the
[Windows record](validation/windows-software-vulkan-2026-09-18/README.md).
These are recorded validation profiles, not a claim that every intermediate Clang
release or every supported Windows desktop has been tested. The presets deliberately
@@ -78,8 +79,11 @@ An offline build is recorded only after a clean build directory is configured an
built with network access disabled. A warm incremental build or archive checksum
verification alone is not that acceptance check.
Commit `d834cfad67cd81d8c4998b90c16791361ca8c0f8` passed this check on Linux: full
native build and 19 CPU tests in a new user/network namespace with no external
connectivity, using a `git archive` checkout and only prefetched inputs. See
[`validation/offline-linux-2026-09-18.json`](validation/offline-linux-2026-09-18.json).
Commit `0f34b036313c011861dbfd5828ed45c4f7940b05` passed this check on Linux: full
native build and 20 CPU tests in a new user/network namespace with no external
connectivity, using a `git archive` checkout and only prefetched inputs. A fresh
project was then created and rendered from that SDK. See the
[checkpoint 5 record](validation/checkpoint5-linux-2026-09-18/README.md).
The [earlier offline run](validation/offline-linux-2026-09-18.json) retains its own
`d834cfa` revision and 19-test result.
Reproduce using `python3 tools/verify_offline_build.py --output .cache/offline-check`.
+23
View File
@@ -0,0 +1,23 @@
Lua 5.4.9 — MIT License
https://www.lua.org/license.html
Copyright (C) 1994-2026 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+12
View File
@@ -26,6 +26,18 @@ With MCP, call `faset_import`, then query `faset_job` using the returned job ID.
`faset_job_cancel` requests cancellation. Cancelling an import does not Undo an
authoring edit. See [MCP and CLI](mcp.md) for transport setup and errors.
The Assets panel marks an imported asset **Stale** when its source, external glTF
buffer/image, Blender bundle, saved import settings, importer, or target profile
differs from the active generation. Select the imported row, then **Import / Reimport**;
the Console reports the changed input. **Refresh** checks immediately, and the panel
also refreshes periodically. `faset_assets` exposes the same `freshness.state` and
structured `freshness.reasons` to MCP clients. Checks compare contents, including
files whose size and timestamp stayed unchanged. The last good cooked asset remains
visible until reimport succeeds; checking freshness never publishes a generation.
Cook and export refuse referenced stale or unavailable sources and explain which
input needs reimport. A standalone exported game uses only its packaged cooked
generation and never needs the original source files.
## Import an image
PNG and JPEG become image assets. Drag an imported image into a scene to create a
+19
View File
@@ -0,0 +1,19 @@
# Developer diagnostics
The optional Dear ImGui overlay shows renderer counters inside the Editor. The Editor's normal interface remains the retained Faset UI. Enable the diagnostic build explicitly:
```sh
cmake --preset linux-debug -DFASET_DEBUG_IMGUI=ON
cmake --build --preset linux-debug --parallel 4
build/linux-debug/faset_editor --project examples/projects/collect-3d --gui
```
On Windows, use `windows-debug` for both presets and `build/windows-debug/faset_editor.exe`. Press **F12** to show or hide the panel. Drag its title bar to move it; **Freeze counters** holds a completed-frame sample for inspection. Closing the panel does not stop rendering. Pointer gestures inside the overlay are kept out of the authoring UI.
The panel reports the previous completed frame: renderer wall time, GPU timestamp time where available, synchronous readback time, draw calls, packed vertices, culled meshes, textures, explicit Vulkan allocation sizes, actual validation availability/errors, and GPU pass-label count. Renderer wall time includes waiting for GPU work; it is not thread CPU usage. Memory excludes driver-internal allocations. The overlay itself adds drawing work, so hide it for a baseline performance measurement.
The Vulkan backend emits `VK_EXT_debug_utils` labels for `ShadowMap`, `ForwardAndUI`, `Readback`, and, when presenting, `Presentation`. A graphics capture tool that supports this extension can identify those command-buffer regions. Labels remain available without the Khronos validation layer when the extension is exposed; unsupported systems continue rendering and report labels unavailable. A submitted-label count confirms calls were emitted, not that an external capture tool was tested.
This module is disabled by default and is linked only to the graphical Editor and its dedicated test when enabled. Player and exported games do not link ImGui. No overlay control changes authoring documents, gameplay state or export settings.
Run `ctest --test-dir build/linux-debug -R '^editor_debug_overlay$' --output-on-failure` in an enabled build to check actual ImGui geometry/font rendering, F12 toggling, pointer isolation and restoration of the underlying frame. The regular renderer pixel test also verifies GPU labels and clipped UI triangles.
+11 -3
View File
@@ -103,9 +103,17 @@ check **Jobs** and **Console**. A successful build and schema export refresh the
Inspector. A failed build retains the previous metadata and reports the failure.
A missing schema or unsupported component version appears as read-only raw fields
with **Copy raw fields**. The Editor preserves that data. Restore the matching module
or provide a migration and rebuild before expecting normal field editing or Play.
See [Build, Play, and export](export.md) for the C++ iteration loop.
with **Copy raw fields**. Restore a missing module to make its schema available.
For an older component, declare [data migration rules](../scripting/api.md#editor-data-migrations),
choose **Build C++**, then **Migrate to v…** in the Inspector. This is one undoable
authoring edit; save explicitly afterward. Inherited components show **Open source
to migrate** instead. Top-level local additions migrate in their owning instance.
Missing rules or conversion errors preserve the data and appear in Console.
Opening or recovering a scene never migrates it automatically. Future versions
stay opaque and cannot be downgraded. Review instance overrides separately when
changing the source field's units or meaning. See [Build, Play, and export](export.md)
for the C++ iteration loop.
## Project settings
+41 -9
View File
@@ -1,12 +1,13 @@
# Build from source
!!! note "Implementation checkpoint"
Linux Editor, Player and export integration are tested. Final Windows graphics/export
acceptance is tracked separately in the implementation report.
!!! note "Verified build profiles"
The Editor, Player and both sample exports passed the recorded Linux and Windows
profiles. Linux rendering used an RTX 2080 Ti; Windows CI used SwiftShader. This
does not certify every graphics driver or display configuration.
## Linux prerequisites
The selected toolchain is C++20, CMake 3.25 or later, Ninja, and Clang.
The selected toolchain is C++20, CMake 3.25 or later, Ninja, Clang, and Python 3.12+.
Graphical builds need Vulkan 1.3 headers/loader and a compatible driver.
SDL3, FreeType and HarfBuzz are built from pinned source archives.
@@ -39,13 +40,32 @@ build/linux-debug/faset_editor --project "$PWD/MyGame" --new MyGame --dimension
You can also run `build/linux-debug/faset_editor` without arguments to open the
project launcher and create or select a project using the native interface.
Use **Build C++** after changing `MyGame/Scripts/Gameplay.cpp`, then **Play**.
Use **Build** after changing `MyGame/Scripts/Gameplay.cpp`, then **Play**.
The Player runs separately. Stop it before changing and rebuilding C++ gameplay.
See [MCP and CLI](../editor/mcp.md) for headless authoring and automation.
For an optimized build use `linux-release`. The `linux-sanitize` preset enables
AddressSanitizer and UndefinedBehaviorSanitizer for tests without the graphics backend.
## Optional Lua module
Engine development builds enable `FASET_ENABLE_LUA` by default. Lua 5.4.9 is compiled
from its checksum-pinned source archive; no system Lua installation is required.
Pass `-DFASET_ENABLE_LUA=OFF` to omit the VM and bindings. The Editor's project
build/export service selects this flag from `scripting.lua.scripts` in
`project.faset.json`, so C++-only games do not link Lua.
See the [Lua guide](../scripting/lua.md) for the manifest, a Lua-only project,
hot reload, and external-editor/LuaLS setup. Headless CPU checks can be run with:
```sh
cmake --preset linux-debug -DFASET_BUILD_RENDERER=OFF -DFASET_BUILD_EDITOR=OFF
cmake --build --preset linux-debug --parallel
ctest --preset linux-debug
```
These checks do not verify the graphical Player or renderer.
## Dependencies and offline builds
Dependency source URLs, commits, and archive SHA-256 values are stored in
@@ -64,8 +84,10 @@ disconnecting. Prefetching source archives alone is not a complete offline SDK.
## Windows prerequisites
Use an x64 Visual Studio Developer shell with the Windows SDK, MSVC runtime libraries,
LLVM `clang-cl`, Ninja, CMake, and the Vulkan SDK available. Then use the
`windows-debug` or `windows-release` presets.
LLVM `clang-cl`, Ninja, CMake 3.25+, Python 3.12+, and the Vulkan SDK available.
The commands below use the Python `py` launcher; substitute `python` if your
installation exposes that command instead. Use the `windows-debug` or
`windows-release` presets.
Enable **Win32 long paths** on the Windows development machine before starting the
build shell. Faset's executable manifest declares long-path support, and its direct
@@ -89,8 +111,18 @@ cmake --build --preset windows-debug --parallel
ctest --preset windows-debug
```
Windows acceptance is tracked separately from Linux; a successful Linux build does
not verify a Windows build.
Windows acceptance uses a fresh native CI checkout, full Editor build, launcher
Create/Open tests, native window/MCP tests and standalone Release exports. Its
software Vulkan driver is a CI fixture; install your normal hardware Vulkan driver
on a development desktop. See the
[acceptance dossier](https://github.com/emil28092005/Faset_Engine/blob/main/docs/validation/mvp-acceptance.md)
for observed results.
Native Wayland programmatic restore was skipped when the tested compositor declined
the operation; XWayland passed. If this affects your desktop, run the Editor with
`SDL_VIDEODRIVER=x11`. Real system IME composition and movement between physical
monitors with different scale factors remain compatibility checks, beyond the
passing deterministic text/DPI tests.
The repository's `docs/TOOLCHAINS.md` records the exact compiler, SDK and GPU profiles
used in observed validation, separately from the minimum tool requirements above.
+12 -7
View File
@@ -4,13 +4,16 @@ Faset is a C++ engine for desktop 2D and 3D games on Linux and Windows.
This manual focuses on writing gameplay: small working examples, the functions they use,
and how those functions interact with scenes, physics, and the editor.
!!! warning "Development status"
MVP implementation is in progress. A planned feature is not a working feature.
Individual guides state their prerequisites and validation status. The current
Editor, gameplay tutorials, two playable sample games and Linux export can be built
and tested. Final Windows graphics/export acceptance is still in progress.
!!! note "MVP scope"
The C++ MVP includes the Editor, compiled gameplay tutorials, two playable games,
Blender import and standalone Linux/Windows export. Acceptance used a physical
Linux GPU and software Vulkan on Windows. See the
[acceptance dossier](https://github.com/emil28092005/Faset_Engine/blob/main/docs/validation/mvp-acceptance.md)
for exact source revisions and coverage limits. The optional Lua module is
documented separately; those historical acceptance results do not certify later
changes. Advanced graphics remain later milestones.
Start with [how C++ gameplay works](scripting/index.md), then read
Start with [how gameplay works](scripting/index.md), then read
[frame and physics updates](scripting/lifecycle.md). See
[Build from source](getting-started/build.md) for the toolchain and build commands.
@@ -28,7 +31,9 @@ The manual grows alongside tested engine capabilities, in this order:
5. Work with scene templates, assets, and references.
6. Import from Blender and export a standalone game.
Lua is planned after the C++ foundation. It is not a current scripting option.
For interpreted gameplay, follow [Lua gameplay](scripting/lua.md): declare component
fields, write callbacks, and reload scripts during development Play. The Lua-only
example in `examples/lua` uses the same physics and scene model as the C++ tutorials.
## Preview this manual
+76
View File
@@ -76,6 +76,82 @@ automatic migrations or authoring-style custom-field constraint validation.
`snapshot()` returns a value snapshot for rendering; `snapshotJson()` provides its JSON representation. `diagnostics()` returns a read-only vector of runtime messages. These are native C++ APIs for the Player and tests, **not MCP endpoints**.
## Editor data migrations
Gameplay schema versions describe saved component data. When a field changes units
or meaning, increase the type's `version` and include declarative `migrations` in
that type returned by `gameplay::schema()`. For example, this type declaration
converts version 1 speed values from centimetres per second to metres per second:
```json
{
"id": "game.mover",
"version": 2,
"fields": {
"speed": {"type": "number", "default": 2.5, "min": 0, "max": 10},
"enabled": {"type": "boolean", "default": true}
},
"migrations": [
{
"from_version": 1,
"fields": {
"speed": {"scale": 0.01},
"enabled": {"default": true}
}
}
]
}
```
Build C++ to export and validate the declaration. The Editor reads these rules
from the same schema manifest as field metadata; it does not load the gameplay
library or execute a migration callback. Invalid metadata or migration rules fail
the build before replacing the last published binary/schema generation.
Each step upgrades `from_version` to the next integer version. A component at
version 1 needs both steps 1 and 2 to reach version 3. Empty `fields` explicitly
allows a version step with no value conversion. Supported field operations are:
- `default`: insert a value only when the field is absent.
- `scale`: multiply an existing numeric field by a finite number.
- `require_manual`: when `true`, stop if the field is present, so incompatible data
requires an explicit manual conversion.
Rules preserve component/entity IDs and fields they do not mention. The final
values must satisfy the current field schema. Unsupported operations, repeated
steps, invalid version ranges, invalid rules and non-finite scale values are
rejected when the schema is loaded. Arithmetic overflow during conversion also
fails without applying the transaction.
Opening or recovering a scene preserves older component versions as opaque data;
it never migrates them automatically. Missing rules therefore do not prevent
opening the scene. Choose **Migrate to v…** in the Inspector after rebuilding the
schema, or use the same editor's `faset_scene_edit` operation with the current
document revision:
```json
{
"document": "document-id",
"revision": 3,
"operations": [
{"op": "component.migrate", "entity": "entity-id", "component": "component-id"}
]
}
```
The whole batch is one Undo step and is written to the recovery journal. Save
explicitly to update the scene file. Missing steps, a manual-conversion requirement
or a validation error leave the document and revision unchanged. Future versions
cannot be downgraded. The same operation accepts an `instance` ID when `entity`
and `component` identify a top-level instance-local addition using its original
stored IDs, rather than resolved preview IDs.
Inherited components belong to their source document: open that source to migrate
them. Sparse field overrides in other instances are not automatically converted;
review and explicitly update overrides when changing a field's units or meaning.
The Player performs no migration and still requires the scene version to match its
linked gameplay schema before Play or exported-game validation.
## Inspect a running Player locally
The Player has local development controls in addition to gameplay input: **P** toggles
+2 -2
View File
@@ -51,8 +51,8 @@ Schema declarations are tested for stable map-key/FieldId matching and defaults.
## Play complete small projects
`examples/projects/collect-2d` and `examples/projects/collect-3d` contain complete projects with a manifest, scene, and a separate `Scripts` module. Open either folder with the Editor's `--project` option, then use Play. Each project's README also provides a direct Player build command.
`examples/projects/collect-2d` and `examples/projects/collect-3d` contain complete projects with a manifest, scene, and a separate `Scripts` module. Open either folder with the Editor's `--project` option. The 2D project is ready to Play. For the 3D project, first import `Assets/exit-arch/manifest.json` from the Assets panel, then Play. Repeat this import after clearing its cache or cloning the project. Each project's README also provides the exact import and direct Player build commands.
Move the blue block with A/D in 2D or WASD in 3D, jump with Space, collect three gold cubes, and reach the green exit after its red gate opens. E resets the round. One pickup is on a raised platform. A visible gold marker and the Player log confirm completion; these initial examples use geometric progress displays instead of a text HUD.
The `playable_2d` and `playable_3d` CTests drive the actual modules through input, including the jump, objective, reset, and fresh session. The 3D module also explicitly registers a separately packaged `example.beacon` component from its local `Scripts/Extensions/Beacon.hpp`. Both projects use built-in geometry and need no imported assets to start.
The `playable_2d` and `playable_3d` CTests drive the actual modules through input, including the jump, objective, reset, and fresh session. The 3D module also explicitly registers a separately packaged `example.beacon` component from its local `Scripts/Extensions/Beacon.hpp`. Gameplay geometry uses built-in primitives; the 3D scene additionally references the imported Blender arch. Its GLB bundle is included, so Blender is only needed to edit or recreate that source asset.
+1 -1
View File
@@ -44,7 +44,7 @@ Read the callback from top to bottom:
The `[](...) { ... }` expression is a C++ lambda: a function stored in `Behavior::update`. Empty brackets mean it captures no local variables. `registerBehavior` takes ownership of the callback object. Register before calling `load`; registration while entities exist or a callback is running is rejected.
The `schema()` function describes editable configuration. It does not create a runtime object. `tutorial.move_x` is the stable `TypeId`; `speed` is a stable `FieldId` within that type. Keep these IDs when changing a display label. Changing a field's meaning or units needs an explicit data migration, not just a new label.
The `schema()` function describes editable configuration. It does not create a runtime object. `tutorial.move_x` is the stable `TypeId`; `speed` is a stable `FieldId` within that type. Keep these IDs when changing a display label. Changing a field's meaning or units needs an [explicit data migration](api.md#editor-data-migrations), not just a new label.
## Attach the behavior
+7 -3
View File
@@ -1,8 +1,12 @@
# C++ gameplay
# Gameplay scripting
In Faset, a gameplay script is **C++ compiled into the Player**. You write ordinary functions and register the callbacks an object needs. There is no C++ interpreter or live replacement of compiled classes. Stop Play, rebuild, export the schema, and start a new Player session.
Faset supports **C++ compiled into the Player** and optional [Lua gameplay](lua.md).
Both languages register component schemas and callbacks on the same runtime.
For C++, there is no interpreter or live replacement of compiled classes: stop Play,
rebuild, export the schema, and start a new Player session.
Lua is planned for a later stage. The APIs and tutorials in this section describe the C++ implementation available now.
The following tutorials describe C++. See [Lua gameplay](lua.md) for Lua-only or
mixed projects, the Lua API, source reload, and external-editor completion.
## Start here
+238
View File
@@ -0,0 +1,238 @@
# Lua gameplay
Faset embeds **Lua 5.4.9** as an optional gameplay module. Lua and compiled C++
behaviors share the same runtime lifecycle, typed entity operations, scene components,
and Inspector metadata. The Editor does not run gameplay code in its own process.
There is no built-in script editor: edit `.lua` files in Zed or another external editor.
## Enable Lua in a project
Add explicit entry scripts to `project.faset.json`:
```json
"scripting": {
"lua": {
"scripts": ["Scripts/player.lua", "Scripts/beacon.lua"]
}
}
```
This is a manifest fragment, not a complete project file. Each entry must return one
`faset.behavior` table with a unique custom TypeId. All sources live beneath `Scripts`
and are captured as an immutable build/export snapshot. Paths must be project-relative;
symlinks and paths outside `Scripts` are rejected. Auxiliary modules do not need to
appear in the entry list.
A Lua-only project can omit both `Scripts/Gameplay.cpp` and `Scripts/Gameplay.hpp`.
A mixed project keeps that pair and adds the Lua declaration. TypeIds must be unique
across both languages, and the `faset.*` namespace is reserved for native components.
The engine developer option `FASET_ENABLE_LUA` defaults to `ON`. Project builds select
it from the manifest, so a C++-only game does not link the Lua VM. Lua is pinned and
built from source; no system Lua installation is required.
The complete `examples/lua` project includes a playable
2D controller, a non-physical animated beacon, and a shared module. Its scripts are
also loaded by the Lua contract test.
## Write a behavior
```lua
local Player = faset.behavior {
id = "game.player",
version = 1,
name = "Player",
fields = {
speed = {
name = "Move speed", type = "number", default = 5,
min = 0, max = 30, units = "m/s"
}
}
}
function Player:on_start()
self.state.elapsed = 0
end
function Player:fixed_update(delta)
self.state.elapsed = self.state.elapsed + delta
local velocity = self.entity:velocity()
velocity.x = faset.input().horizontal * self.fields.speed
self.entity:set_velocity(velocity)
end
return Player
```
Attach a component with `type: "game.player"`, `version: 1`, and the desired field
overrides to an entity with a 2D or 3D rigid body. Refresh schemas to expose the
behavior in **Add Component** and its `speed` field in the Inspector. Saved scenes
store the stable TypeId and data, not an instance of a Lua object.
Each entity/component gets its own instance:
- `self.entity`: an opaque runtime handle, checked on every call.
- `self.fields`: a configuration copy, combining schema defaults and scene overrides.
- `self.state`: a fresh mutable table for counters, timers, and retained handles.
Changing either table does not modify the saved scene or create an Undo operation.
Module-local variables are shared by instances of that module; put per-entity state
in `self.state`. Lua tables returned by getters are copies, not native pointers.
## Lifecycle
Use colon definitions so Lua supplies `self`:
| Callback | When it runs |
|---|---|
| `on_start()` | Once after the instance and initial scene objects exist |
| `fixed_update(delta)` | Before each fixed physics step; delta is seconds |
| `on_collision(event)` | After physics, for contact begin/end |
| `update(delta)` | Once per rendered frame after fixed steps |
| `late_update(delta)` | After presentation interpolation |
| `on_destroy()` | Before component/entity removal, while the handle is still valid |
Omit unused callbacks. The same [timing rules](lifecycle.md) as C++ apply, including
input edges, fixed-tick catch-up, deferred structural changes, pause and single-step.
Do not multiply velocity by delta; multiply a manually calculated displacement.
An error is reported with source location/traceback and disables the offending
instance for that generation and releases its instance state. Other instances can continue.
The VM quota is shared: allocations retained by module-level variables can still
affect other behaviors. A restart/reload creates
fresh instances; disabled instances are not automatically retried every frame.
Changes already made or queued by a failing callback are not rolled back.
## Runtime API
`faset.find("scene-id")` returns an entity handle or `nil`. Handles support equality
and `:valid()`. Retained handles become invalid after destruction or scene restart;
calling other methods on a stale handle reports an error.
| Entity method | Contract |
|---|---|
| `:transform()` / `:presentation()` | Copy of simulation/display transform |
| `:set_transform(pose)` | Non-physical objects only |
| `:set_presentation(pose)` | Display-only write during `late_update` |
| `:teleport(pose)` | Explicit discontinuous pose change; preserves velocity |
| `:fields(type_id)` | Copy of the named component's stored fields |
| `:velocity()` / `:set_velocity(v)` | Linear velocity, rigid bodies only |
| `:apply_impulse(v)` | Impulse at the rigid body's centre |
| `:is_grounded()` | Support from completed native physics contacts |
| `:destroy()` | Queue entity/descendant removal |
| `:add_component(record)` | Queue a complete component record |
| `:remove_component(type_id)` | Queue component removal |
Typed vectors are `{x = 1, y = 2, z = 0}`. Transforms contain `position`, `rotation`,
and `scale`, each a named vector. Positions use metres; rotations use XYZ Euler
radians. In contrast, **scene/component JSON arrays** are represented as ordinary
1-based Lua arrays, such as `fields.position = {1, 2, 0}`. Use `faset.null` to retain
an explicit JSON null; Lua `nil` removes a table key.
An empty Lua table converts to a JSON object; an empty schema default with
`type = "array"` is normalized to an empty JSON array.
`faset.input()` returns `horizontal`, `vertical`, `jump_pressed`, and
`interact_pressed`. Player mappings are A/D or arrows, W/S or arrows, Space, and E.
`faset.log(...)` sends a bounded message to Player logs and the Editor Console.
Collision events contain `first`, `second`, `other` (the opposite entity), and `began`.
They are copied for Lua, but retained entity handles still need validity checks.
`faset.spawn(record)` queues a full scene entity record. It returns **no handle**:
use `faset.find(id)` after the next fixed-tick barrier. Spawn, destroy, add and remove
operations follow FIFO order and do not mutate Editor documents. For example:
```lua
faset.spawn {
id = "effect-1", name = "Effect", parent = faset.null,
components = {
{
id = "effect-transform", type = "faset.transform", version = 1,
fields = { position = {0, 2, 0} }
}
}
}
```
## Shared modules and sandbox
`require("util.motion")` resolves `Scripts/util/motion.lua`, then
`Scripts/util/motion/init.lua`, inside the captured source snapshot. A module is
evaluated once and its result cached within the VM. Missing modules, cycles, and
path-like names are errors. There is no native module search, package installation,
network access, or arbitrary file access.
Basic Lua operations and the `math`, `string`, `table`, and `utf8` libraries are
available. `io`, `os`, `debug`, dynamic `load`, `loadfile`, `dofile`, `pcall`, `xpcall`,
`setmetatable`, `collectgarbage`, `string.dump`, and coroutines are not exposed.
Engine-owned metatables are locked; arbitrary finalizers cannot run during shutdown.
The restricted API intentionally prevents scripts
from catching execution-limit errors and continuing indefinitely.
The VM has memory and instruction budgets (`LuaLimits`, default 16 MiB and one
million instructions per protected entry/callback). These are gameplay reliability
limits, not a promise that executing untrusted code is equivalent to OS isolation.
JSON conversion also limits nesting, node count and expanded string/key bytes
(16 MiB), including repeated references to the same Lua string. Structural commands
are limited to 1,024 operations and 16 MiB of marshaled payload per callback.
The Player already runs separately from the Editor; only trusted local game projects
should be opened and built. C++ gameplay is native code and is not sandboxed.
Schema extraction evaluates entry scripts in the bounded VM but does not create a
world or invoke lifecycle callbacks. Keep top-level code declarative: calling runtime
operations there is an error. Metadata supports the same fields, constraints and
declarative [migration rules](api.md#editor-data-migrations) as C++ schemas. Runtime
loading does not migrate saved data automatically.
## Edit, reload, and export
The Editor command palette exposes:
| Command | Purpose |
|---|---|
| `faset_lua_refresh` | Build if needed, extract schemas, refresh Inspector metadata |
| `faset_lua_reload` | Request a Lua reload in a development Player |
| `faset_lua_setup` | Install Faset LuaLS declarations/configuration |
| `faset_script_open` | Open a script in an external editor |
The external-editor default is `zed`. Set `editor.script_editor` in
`project.faset.json` to an argument array such as `["code", "--goto", "{file}"]`,
or pass an `editor` argument array to `faset_script_open`. Exact `{file}` and
`{project}` arguments are substituted; a missing file argument is appended. The
command launches the executable directly, without a shell. The Assets panel lists
Lua sources under `Scripts` and provides **Open Script**.
Development Play watches Lua changes. The Player's `--watch-lua` option enables this
for direct development runs. A candidate source generation is loaded and validated
before replacement; an invalid candidate leaves the preceding generation running.
Successful reload **restarts the scene**, invalidates old handles, and resets all
script state. This is not state-preserving hot swapping. C++ source changes still
require a rebuild and a new Player process.
Export captures the declared entry list and Lua modules with the game. The exported
Player runs without the Editor or a separate Lua installation; development watching
is not enabled by ordinary exported-game launch. Exported Lua remains readable source,
not encrypted code. A C++-only project continues to export without the Lua VM.
## Zed and LuaLS
Run `faset_lua_setup`. It copies annotation-only declarations to
`.faset/lua/faset.lua` and creates `.luarc.json` **only if it does not already exist**.
It also creates `Scripts/.luarc.json` for editors that open an individual Lua file
with `Scripts` as the workspace root. Existing configuration files are preserved.
For an existing LuaLS configuration, merge these settings yourself:
```json
{
"runtime.version": "Lua 5.4",
"runtime.path": ["Scripts/?.lua", "Scripts/?/init.lua"],
"workspace.library": [".faset/lua"],
"workspace.checkThirdParty": false,
"diagnostics.globals": ["faset"]
}
```
Use an editor with LuaLS integration and open the project directory. Annotations
describe the Faset API for completion and diagnostics; they are not runtime code and
must not be `require`d. The engine does not embed an LSP client, code editor, or a
breakpoint debugger. Player logs/tracebacks are the first debugging surface.
@@ -20,7 +20,7 @@
6. **Более богатые материалы.** Из Substrate взять ограниченные классы сложности и обработку по тайлам; из glints — фильтруемое распределение микробликов. Небольшой фиксированный clear-coat/двухслойный набор часто разумнее произвольного графа BSDF.
7. **Большие наборы текстур.** Virtual Texturing полезна, когда именно residency и объём текстур стали проблемой. Стриминг целых mip-уровней проще; переход на страницы имеет смысл по измеренному рабочему набору.
## Принятый план Faset — реализация ещё не начата
## Принятый план Faset — продвинутая графика после MVP
Решения обновлены 18 сентября 2026. Подробные критерии продукта — в [PLAN.md](../../PLAN.md), технические границы — в [архитектуре](../ARCHITECTURE.md). Результаты чтения UE ниже сохраняются; они не означают, что эти системы уже есть в Faset, входят в MVP или обязательно будут воспроизведены целиком.
@@ -2,7 +2,7 @@
**Принято 18.09.2026: редактор, MCP и интеграции пользуются одним сервисом авторских данных.** Сам сервис умеет работать без окон; GUI добавляет выделение, gizmos и preview, MCP — типизированный доступ для агента, Blender — подготовку и обновление ассетов. Пользователь должен свободно переходить между этими способами, сохраняя историю, идентификаторы, проверки и результат.
Это принятый проект архитектуры, не реализованная интеграция; код движка ещё не создан. Актуальные решения — в [архитектуре](../ARCHITECTURE.md), этапы и критерии готовности — в [PLAN.md](../../PLAN.md). **MCP существует только в Editor/headless editor services: authoring, import, build, Play/Stop и журналы редактора. Никаких runtime inspection/mutation, world/session tools, MCP в Player, экспортной игре или SchemaExporter.** Он дополняет [UX редактора](./02-editor-ux.md), [разбор Godot](./08-godot-ux-source-study.md), [паттерны Blender](./10-blender-editor-patterns.md) и [ECS](./11-ecs-and-ergonomics.md). Исходники сверены в прежних commits: Godot `9c776068d6ed23acd0c78bfe534272d1d2a3a619`, Blender `28d47268bddcb9dc69143f0e2d9410969da16311`. Документация проверена 17.09.2026; для MCP зафиксирована редакция **2026-07-28**, поддержка которой конкретным клиентом не предполагается автоматически.
Это исследовательский проект контрактов от 17–18.09.2026. Реализованный MVP-профиль, точные имена tools и проверки описаны в [Manual MCP](../manual/editor/mcp.md), [Manual ресурсов](../manual/editor/assets.md) и [журнале реализации](../IMPLEMENTATION.md). Более широкие API-примеры ниже не являются обещанием текущей реализации. Актуальные решения — в [архитектуре](../ARCHITECTURE.md), этапы и критерии готовности — в [PLAN.md](../../PLAN.md). **MCP существует только в Editor/headless editor services: authoring, import, build, Play/Stop и журналы редактора. Никаких runtime inspection/mutation, world/session tools, MCP в Player, экспортной игре или SchemaExporter.** Он дополняет [UX редактора](./02-editor-ux.md), [разбор Godot](./08-godot-ux-source-study.md), [паттерны Blender](./10-blender-editor-patterns.md) и [ECS](./11-ecs-and-ergonomics.md). Исходники сверены в прежних commits: Godot `9c776068d6ed23acd0c78bfe534272d1d2a3a619`, Blender `28d47268bddcb9dc69143f0e2d9410969da16311`. Документация проверена 17.09.2026; для MCP зафиксирована редакция **2026-07-28**, поддержка которой конкретным клиентом не предполагается автоматически.
## 1. AuthoringService как самостоятельное ядро редактора
@@ -76,7 +76,7 @@ Manifest хранится вместе с authoring-данными в Git: `asse
## 8. Контракт формата и следующий шаг live link
Профиль импорта должен последовательно покрыть triangle meshes, UV/нормали/tangents и metal-rough PBR; skinning, clips и morph targets вводятся на соответствующих этапах [плана](../../PLAN.md). Поддержка пока не реализована и не проверена. Процедурные node graphs и Geometry Nodes не превращаются в engine shaders: нужен bake/evaluated mesh и отчёт о потерях. glTF описывает свою систему материалов, а Blender exporter распознаёт поддержанные узлы. [Blender: glTF materials](https://docs.blender.org/manual/en/4.0/addons/import_export/scene_gltf2.html).
Профиль импорта должен последовательно покрыть triangle meshes, UV/нормали/tangents и metal-rough PBR; skinning, clips и morph targets вводятся на соответствующих этапах [плана](../../PLAN.md). Текущее проверенное статическое подмножество перечислено в [Manual ресурсов](../manual/editor/assets.md); skinning, clips и morph targets остаются за пределами MVP. Процедурные node graphs и Geometry Nodes не превращаются в engine shaders: нужен bake/evaluated mesh и отчёт о потерях. glTF описывает свою систему материалов, а Blender exporter распознаёт поддержанные узлы. [Blender: glTF materials](https://docs.blender.org/manual/en/4.0/addons/import_export/scene_gltf2.html).
glTF использует правую систему координат, Y-up и метры; наши engine-конвенции фиксируются в recipe, с преобразованием ровно на одной границе. Проверять root transforms, nonuniform/negative scale, winding и tangent handedness. Имена glTF не гарантируют уникальность. [glTF 2.0: координаты и структуры](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html).
+1 -1
View File
@@ -2,7 +2,7 @@
**Принято 18.09.2026:** C++ core/gameplay, затем Lua отдельным модулем (необязателен для конкретной игры); EnTT; собственный retained C++ editor UI с декларативными layout/styles и тёмной темой, ImGui для debug; Vulkan 1.3 и собственный RenderGraph, Slang/совместимый HLSL; SDL3 за API Faset; CMake+Ninja, Clang Linux и clang-cl Windows. Gameplay — статическая библиотека в Player dev/release, Editor plugins — DLL/SO под точный SDK с restart. Сравнение альтернатив ниже — **история исследования**, не открытый выбор. Канон — [архитектура](../ARCHITECTURE.md), этапы — [PLAN.md](../../PLAN.md). MCP только в Editor/headless editor services, без runtime inspection/mutation и без MCP в Player/SchemaExporter.
Исходные требования: Linux и Windows desktop, игры 2D и 3D, продвинутая графика, полноценное ручное редактирование и управление через MCP. Текущие рекомендации ниже описывают принятый проект; pipeline и движок ещё не реализованы. Исторические варианты помечены отдельно. Проверка источников: 17 сентября 2026. Локальный Godot: `9c776068d6ed23acd0c78bfe534272d1d2a3a619`, версия дерева 4.8-dev; официальные текущие страницы Unity показывают 6.6. Исследованы тела desktop exporter, сбор зависимостей, remap импортированных ресурсов, кэш преобразования, запись PCK и конфигурация editor/player. Unity здесь изучен по документации, без утверждения о просмотре закрытой реализации.
Исходные требования: Linux и Windows desktop, игры 2D и 3D, продвинутая графика, полноценное ручное редактирование и управление через MCP. Рекомендации ниже фиксируют проект на этапе исследования; текущая реализация pipeline и её проверки описаны в [Manual экспорта](../manual/editor/export.md) и [журнале реализации](../IMPLEMENTATION.md). Исторические варианты помечены отдельно. Проверка источников: 17 сентября 2026. Локальный Godot: `9c776068d6ed23acd0c78bfe534272d1d2a3a619`, версия дерева 4.8-dev; официальные текущие страницы Unity показывают 6.6. Исследованы тела desktop exporter, сбор зависимостей, remap импортированных ресурсов, кэш преобразования, запись PCK и конфигурация editor/player. Unity здесь изучен по документации, без утверждения о просмотре закрытой реализации.
## Что именно должна делать кнопка Build
+3 -3
View File
@@ -2,13 +2,13 @@
**Название проекта — Faset Engine. Синхронизация решений: 18.09.2026.** Каноническая архитектура — [ARCHITECTURE.md](../ARCHITECTURE.md), последовательность до и после MVP — [PLAN.md](../../PLAN.md). Этот отчёт сохраняет исследовательские аргументы и обновлённые принятые решения. Прежние альтернативы отмечены **superseded**; факты о чужих движках не означают, что соответствующие возможности реализованы в Faset.
Дата: 17 сентября 2026. Цель — новый движок для **Linux и Windows, десктопных 2D/3D-игр**, одинаково удобный при ручной работе и через **MCP**, с интеграцией как минимум с **Blender**. Это исследовательская основа реализации. Код нового движка ещё не создавался; ниже принятые архитектурные правила отделены от экспериментальных графических направлений и деталей будущих прототипов.
Дата: 17 сентября 2026. Цель — новый движок для **Linux и Windows, десктопных 2D/3D-игр**, одинаково удобный при ручной работе и через **MCP**, с интеграцией как минимум с **Blender**. Это исследовательская основа реализации. На момент первоначального исследования код нового движка ещё не создавался; текущая реализация описана в [журнале](../IMPLEMENTATION.md), ниже принятые архитектурные правила отделены от экспериментальных графических направлений и деталей будущих прототипов.
## Уточнения после обсуждения исследования
**Подтверждённый выбор пользователя: Box2D для 2D-физики, Box3D для 3D-физики.** Под Box3D имеется в виду [erincatto/box3d](https://github.com/erincatto/box3d), анонсированный Erin Catto 30 июня 2026. Это отдельная 3D-библиотека с C API и реализацией на C17; репозиторий указывает поддержку Windows и Linux. [Анонс](https://box2d.org/posts/2026/06/announcing-box3d/), [Box2D overview](https://box2d.org/documentation/). Версии и commits зависимостей пока не выбраны, интеграция и собственные физические тесты не выполнялись.
**Подтверждённый выбор пользователя: Box2D для 2D-физики, Box3D для 3D-физики.** Под Box3D имеется в виду [erincatto/box3d](https://github.com/erincatto/box3d), анонсированный Erin Catto 30 июня 2026. Это отдельная 3D-библиотека с C API и реализацией на C17; репозиторий указывает поддержку Windows и Linux. [Анонс](https://box2d.org/posts/2026/06/announcing-box3d/), [Box2D overview](https://box2d.org/documentation/). На момент исследования версии ещё не выбирались и собственные физические тесты не выполнялись. Теперь версии закреплены в [dependency lock](../../dependencies.lock.json), а результаты интеграции записаны в [журнале реализации](../IMPLEMENTATION.md).
Принятый принцип интеграции: отдельные PhysicsWorld2D/PhysicsWorld3D, компоненты RigidBody2D/3D и Collider2D/3D, единые правила регистрации, идентичности, Inspector и диагностики. Миры 2D и 3D не сталкиваются автоматически друг с другом. Физика получает команды перед фиксированным шагом; после завершения шага движок переносит результаты и события в runtime. Для динамического тела физика владеет рассчитанным transform; runtime teleport и управление кинематическим телом — отдельные операции. События связываются с entity через проверяемые handles. Названия API предварительны; адаптеры ещё не реализованы.
Принятый принцип интеграции: отдельные PhysicsWorld2D/PhysicsWorld3D, компоненты RigidBody2D/3D и Collider2D/3D, единые правила регистрации, идентичности, Inspector и диагностики. Миры 2D и 3D не сталкиваются автоматически друг с другом. Физика получает команды перед фиксированным шагом; после завершения шага движок переносит результаты и события в runtime. Для динамического тела физика владеет рассчитанным transform; runtime teleport и управление кинематическим телом — отдельные операции. События связываются с entity через проверяемые handles. Названия API в этом исследовательском описании предварительны; фактический API адаптеров и gameplay описан в [Manual](../manual/scripting/api.md).
**Решение от 18.09.2026: сначала ядро и игровая логика на C++, затем добавляем Lua отдельным модулем. Его будущая реализация принята, использование конкретной игрой необязательно.** Игра на C++ не должна зависеть от Lua; точный Lua API и срок этапа уточняются по [плану](../../PLAN.md). Python и C# сохраняются в сравнении как ранее рассмотренные альтернативы. Каноническое решение записано в [архитектуре](../ARCHITECTURE.md).
@@ -129,4 +129,4 @@ D3D12 подтверждает переносимость самой идеи,
Главное дополнение к 07: фиксированные CPU draw templates совместимы с GPU instance visibility; velocity target не требуется для первого HZB; history extraction — output/lifetime контракт; camera reset заменяет весь previous-view набор; indirect и vertex reads требуют разных зависимостей; неполный Main HZB может быть начальным вариантом истории с измеряемой ценой в эффективности.
Прочитаны тела UE `FInstanceCullingContext` создания buffers/submission, `InstanceCullBuildInstanceIdBufferCS`, `ClearIndirectArgInstanceCountCS`, Nanite `FBoxCull::HZB`, `WriteOccludedInstance` и main/HZB/post orchestration; `BuildHZB`, `HZBBuildCS` и HZB parameter helpers; previous-view setup/reset в SceneVisibility; RDG import/extraction, barrier compile/collection и resource reference handling. В Godot — indirect draw validation/tracking и named render-buffer creation/configuration/cleanup. В интернете — официальные Vulkan indirect/features/synchronization и Microsoft D3D12 indirect signatures. Формат/driver capability matrix для конкретных машин и runtime-поведение пока не проверялись.
Прочитаны тела UE `FInstanceCullingContext` создания buffers/submission, `InstanceCullBuildInstanceIdBufferCS`, `ClearIndirectArgInstanceCountCS`, Nanite `FBoxCull::HZB`, `WriteOccludedInstance` и main/HZB/post orchestration; `BuildHZB`, `HZBBuildCS` и HZB parameter helpers; previous-view setup/reset в SceneVisibility; RDG import/extraction, barrier compile/collection и resource reference handling. В Godot — indirect draw validation/tracking и named render-buffer creation/configuration/cleanup. В интернете — официальные Vulkan indirect/features/synchronization и Microsoft D3D12 indirect signatures. В этом исследовании не проверялись формат/driver capability matrix и runtime-поведение. Позднейшие проверки базового Faset renderer публикуются отдельно в [docs/validation](../validation/README.md); они не подтверждают GPU-driven техники этого раздела.
@@ -139,4 +139,4 @@ Collider recipe включает source output, 2D projection/3D local frame, е
Новые относительно предыдущего обзора выводы: UID файла недостаточен для rename частей; UUID property наследуется при duplicate; Actions и outputs могут иметь соответствие многие-ко-многим; зависимости source/artifact/settings нужно различать; публикация source и активация imported generation — две разные точки; physics geometry имеет отдельную идентичность, версию и срок жизни.
**Охват источников.** Локальные тела Godot `9c776068d6ed23acd0c78bfe534272d1d2a3a619`, Blender `28d47268bddcb9dc69143f0e2d9410969da16311`, UnityCsReference `6b50e5544f6efcca1f44dbace3d1778b465ac6d0` соответствуют [манифесту](source-manifest.json). Недостающие пять Blender exporter files прочитаны из official raw source того же commit без расширения sparse checkout. Дополнительно прочитаны отдельные Box2D files commit `77619f4f7baebe5117a2e3ddc3ac8c404e82d243` и Box3D files/docs commit `f555ee42084e0b43cbffa863f40bff8117c08896`; это исследовательские pins, не выбор версий Faset. Их permalink lines сверены по скачанным файлам. Веб-сверка: спецификация glTF 2.0, Unity 6.0 API, Box2D collision documentation; Blender Manual 4.0 использован только для общего material workflow, текущие механизмы сверены по source 5.3 alpha. Native asset database Unity, весь exporter, автоматическая convex decomposition и переносимость cooked binaries не исследованы полностью. Производительность и roundtrip пока не измерялись.
**Охват источников.** Локальные тела Godot `9c776068d6ed23acd0c78bfe534272d1d2a3a619`, Blender `28d47268bddcb9dc69143f0e2d9410969da16311`, UnityCsReference `6b50e5544f6efcca1f44dbace3d1778b465ac6d0` соответствуют [манифесту](source-manifest.json). Недостающие пять Blender exporter files прочитаны из official raw source того же commit без расширения sparse checkout. Дополнительно прочитаны отдельные Box2D files commit `77619f4f7baebe5117a2e3ddc3ac8c404e82d243` и Box3D files/docs commit `f555ee42084e0b43cbffa863f40bff8117c08896`; это исследовательские pins, не выбор версий Faset. Их permalink lines сверены по скачанным файлам. Веб-сверка: спецификация glTF 2.0, Unity 6.0 API, Box2D collision documentation; Blender Manual 4.0 использован только для общего material workflow, текущие механизмы сверены по source 5.3 alpha. Native asset database Unity, весь exporter, автоматическая convex decomposition и переносимость cooked binaries не исследованы полностью. В рамках этого статического исследования производительность и roundtrip не измерялись. Позднейшие проверки собственного MVP-профиля Faset с Blender опубликованы в [результатах проверок](../validation/README.md).
+1 -1
View File
@@ -1,6 +1,6 @@
# 18. Сборка, cook и доставка: как сделать результат объяснимым
Дата исследования: 17.09.2026; актуализация решений: **18.09.2026**. Дополнение к [исследованию стеков](13-build-pipeline-and-stack.md). **Приняты** CMake+Ninja, Clang Linux/clang-cl Windows, C++ core/gameplay первым и Lua следующим модулем. Gameplay статически линкуется в отдельный Player dev/release; schema export выполняется служебным процессом; Editor plugins — DLL/SO под точный SDK/restart. MCP существует только в Editor/headless editor services, без runtime inspection/mutation и без MCP в Player/SchemaExporter. Канон — [архитектура](../ARCHITECTURE.md), этапы — [PLAN.md](../../PLAN.md). Ниже описан выбранный проект, не реализованный build service.
Дата исследования: 17.09.2026; актуализация решений: **18.09.2026**. Дополнение к [исследованию стеков](13-build-pipeline-and-stack.md). **Приняты** CMake+Ninja, Clang Linux/clang-cl Windows, C++ core/gameplay первым и Lua следующим модулем. Gameplay статически линкуется в отдельный Player dev/release; schema export выполняется служебным процессом; Editor plugins — DLL/SO под точный SDK/restart. MCP существует только в Editor/headless editor services, без runtime inspection/mutation и без MCP в Player/SchemaExporter. Канон — [архитектура](../ARCHITECTURE.md), этапы — [PLAN.md](../../PLAN.md). Ниже сохранён проект BuildService на этапе исследования. Реализованный MVP-профиль и проверки — в [Manual экспорта](../manual/editor/export.md) и [журнале реализации](../IMPLEMENTATION.md).
Исходники: Unreal Engine 5.8.2, commit `16d75d84714512edfb744e1fd0a59e9c74d57873`; [общий манифест](source-manifest.json). Ни UE, ни будущий Faset в этом исследовании не собирались. Ниже — чтение тел функций и официальной документации, затем собственный проект контрактов и проверок.
+1 -1
View File
@@ -2,7 +2,7 @@
Обновлено 18.09.2026. Исходники и официальная документация исследовались прежде всего 17.09.2026; затем результаты согласованы с принятой архитектурой.
**Актуальные решения — в [ARCHITECTURE.md](../ARCHITECTURE.md), порядок реализации — в [PLAN.md](../../PLAN.md).** Движок ещё не реализован. Исследования дают обоснования и проверочные сценарии, а не доказанные показатели будущего Faset.
**Актуальные решения — в [ARCHITECTURE.md](../ARCHITECTURE.md), порядок реализации — в [PLAN.md](../../PLAN.md).** Реализация MVP и проверки идут отдельно: [журнал реализации](../IMPLEMENTATION.md), [результаты проверок](../validation/README.md), [пользовательский Manual](../manual/index.md). Исследования дают обоснования и проверочные сценарии; их статический анализ не является измерением Faset.
## Принято по результатам обсуждения
+3 -3
View File
@@ -1,8 +1,8 @@
# Карта исследования Faset Engine
Локальное React-приложение с интерактивной картой, просмотром Markdown и переходами к строкам исходников. `research.tsx` хранится здесь же; сборка не зависит от Codex, абсолютного пути к рабочему столу или файлов в домашнем каталоге. Карта показывает принятые решения и будущие критерии этапов; движок ещё не реализован.
Локальное React-приложение с интерактивной картой, просмотром Markdown и переходами к строкам исходников. `research.tsx` хранится здесь же; сборка не зависит от Codex, абсолютного пути к рабочему столу или файлов в домашнем каталоге. Карта показывает принятые решения и критерии этапов. Текущее состояние C++-реализации и проверок записано в [журнале реализации](../../IMPLEMENTATION.md).
Главные документы: [о проекте](../../../README.md), [план до/после MVP](../../../PLAN.md), [архитектура](../../ARCHITECTURE.md), [исследования](../README.md). Актуальный охват: собственный Vulkan 1.3/Render Graph, Slang, SDL3, C++/EnTT, retained editor UI; две демки в MVP, продвинутая графика и Lua после него. MCP запланирован строго в Editor, без доступа к runtime worlds/сессиям и без MCP в Player.
Главные документы: [о проекте](../../../README.md), [план до/после MVP](../../../PLAN.md), [архитектура](../../ARCHITECTURE.md), [исследования](../README.md). Актуальный охват: собственный Vulkan 1.3/Render Graph, Slang, SDL3, C++/EnTT, retained editor UI; две демки в MVP, продвинутая графика и Lua после него. MCP работает строго в Editor, без доступа к runtime worlds/сессиям и без MCP в Player.
В этой папке, с установленными Node.js 20+ и npm:
@@ -33,6 +33,6 @@ workspace/
Без внешнего checkout локальная source-ссылка показывает пояснение. Карточки UE также ведут на upstream конкретного research commit; доступ к Unreal Engine регулируется Epic. Номера строк проверялись на snapshots из [source-manifest.json](../source-manifest.json); иной локальный commit может иметь другие строки. Исходники движков не копируются в сборку карты.
API принимает пути относительно корня проекта, проверяет реальные пути и разрешает только текстовые файлы из перечисленных областей размером до 8 MiB. Скрытые каталоги и `node_modules` исключены. Сервер предназначен для локального чтения исследования, без изменения файлов. Его следует запускать локально; это не публичный file server и не MCP будущего редактора.
API принимает пути относительно корня проекта, проверяет реальные пути и разрешает только текстовые файлы из перечисленных областей размером до 8 MiB. Скрытые каталоги и `node_modules` исключены. Сервер предназначен для локального чтения исследования, без изменения файлов. Его следует запускать локально; это не публичный file server и не MCP редактора.
Проверка разрешения ссылок и границ файлового API: `npm test`.
+4 -4
View File
@@ -71,7 +71,7 @@ function Architecture() {
[560, 225, 245, "Player · отдельный процесс", "EnTT · C++ · physics · без MCP"],
[560, 330, 245, "Vulkan 1.3 renderer", "MVP: direct draws + CPU frustum"],
] as const;
return <div style={{ overflowX: "auto" }}><svg viewBox="0 0 825 425" role="img" aria-label="Принятая архитектура Faset; реализация запланирована" style={{ width: "100%", minWidth: 650 }}>
return <div style={{ overflowX: "auto" }}><svg viewBox="0 0 825 425" role="img" aria-label="Принятая архитектура и границы подсистем Faset" style={{ width: "100%", minWidth: 650 }}>
<defs><marker id="engine-arrow" markerWidth="7" markerHeight="7" refX="6" refY="3.5" orient="auto"><path d="M0 0 L7 3.5 L0 7" fill={t.text.tertiary}/></marker></defs>
<g fill="none" stroke={t.stroke.primary} strokeWidth="1.5" markerEnd="url(#engine-arrow)">
<path d="M140 80 V118 M410 80 V118 M685 80 V118 M560 155 H537 M140 185 V223 M265 258 H288 M535 258 H558 M685 185 V223 M685 290 V328"/>
@@ -101,7 +101,7 @@ export default function EngineResearch() {
<Stack gap={5}><Text size="small" tone="tertiary">FASET ENGINE · РЕШЕНИЯ 18.09.2026</Text><H1>Архитектура, MVP и развитие графики</H1><Text tone="secondary">Linux + Windows · 2D / 3D · C++ Editor · Blender</Text></Stack>
<Row gap={8} wrap><Button onClick={() => open("README.md")}>О проекте</Button><Button onClick={() => open("PLAN.md")}>План до / после MVP</Button><Button onClick={() => open("docs/ARCHITECTURE.md")}>Архитектура</Button></Row>
</Row>
<Card><CardBody><Text><strong>Архитектура принята; реализация движка запланирована.</strong> Эта карта работающий просмотрщик исследования, не редактор Faset. GPU-бенчмарки и сборки движка ещё не выполнены. MCP предусмотрен строго в Editor; Player не содержит MCP и не предоставляет ему runtime worlds или игровые сессии.</Text></CardBody></Card>
<Card><CardBody><Text><strong>C++ MVP принят в зафиксированных профилях Linux и Windows.</strong> Эта карта работающий просмотрщик исследования, не редактор Faset. Результаты и ограничения опубликованы в docs/validation/mvp-acceptance.md: Windows проверен через software Vulkan, физические Windows GPU и системный IME требуют отдельного покрытия. Исследовательские графические направления не считаются готовыми функциями. MCP предусмотрен строго в Editor; Player не содержит MCP и не предоставляет ему runtime worlds или игровые сессии.</Text></CardBody></Card>
<Row gap={7} wrap>{["Решение", "Графика", "ECS и данные", "MCP и Blender", "Стек и экспорт", "Прототипы", "Источники"].map(name => <span key={name}><Pill active={tab === name} onClick={() => setTab(name)}>{name}</Pill></span>)}</Row>
<Divider/>
@@ -192,7 +192,7 @@ export default function EngineResearch() {
]}/>
<Text>UI, CLI и MCP редактора запускают один BuildRequest. Компиляторы работают в дочерних процессах; staging публикуется после проверки. Планируемый контракт отмены сохраняет последнюю успешную сборку; cache корректность и повторяемость требуют тестов, а не только hash-ключей.</Text>
<Text>Windows и Linux сборки проверяются в своих окружениях. Player не включает Editor/MCP, shader compiler или editor plugins. Драйвер всё равно создаёт GPU pipelines; shader hot reload требует собственной проверки bindings/layout и безопасной замены ресурсов.</Text>
<Text size="small" tone="secondary">Версии toolchain/dependencies и проверенная GPU/driver matrix ещё не закреплены. C#/.NET и Rust + wgpu остаются историей сравнения вариантов, не параллельными реализациями Faset.</Text>
<Text size="small" tone="secondary">Версии закреплены в dependencies.lock.json и документации toolchain; фактически проверенные GPU/driver окружения указаны в docs/validation. C#/.NET и Rust + wgpu остаются историей сравнения вариантов, не параллельными реализациями Faset.</Text>
<Row gap={8} wrap><Button onClick={() => open(root + reports[7].path)}>Исследование сборки и вариантов стека</Button><Button onClick={() => open(root + reports[11].path)}>Build service, cache и delivery</Button></Row>
</Stack>}
@@ -215,7 +215,7 @@ export default function EngineResearch() {
<Text tone="secondary">Карта и отчёты открываются без локальных копий движков. Optional source viewer использует sibling checkout; исходники чужих движков не входят в Faset. Dev/alpha snapshots материалы исследования, не выбранные production-зависимости.</Text>
<Row gap={8} wrap><Button onClick={() => open("README.md")}>README</Button><Button onClick={() => open("PLAN.md")}>PLAN</Button><Button onClick={() => open("docs/ARCHITECTURE.md")}>Архитектура</Button><Button onClick={() => open(root + "source-manifest.json")}>Полные source SHA и охват</Button></Row>
<Stack gap={7}>{reports.map(r => <div key={r.path}><Row><Button onClick={() => open(root + r.path)}>{r.name}</Button></Row></div>)}</Stack>
<Text size="small" tone="tertiary">Прочитаны выбранные тела функций и официальные документы. Движки не собирались; UX-сравнение и GPU-бенчмарки не выполнены. Принятые решения не означают готовую реализацию.</Text>
<Text size="small" tone="tertiary">В исследованиях прочитаны выбранные тела функций и официальные документы. Сравнительные UX-тесты и GPU-бенчмарки изучаемых движков не проводились. Проверки реализованных функций Faset описаны отдельно в досье приёмки.</Text>
</Stack>}
</Stack>;
}
+5 -2
View File
@@ -2,13 +2,16 @@
These files preserve bounded checks and their inputs. Each record states its source revision or working-tree limitation; a passing record does not certify later commits or every supported platform.
- [MVP acceptance dossier](mvp-acceptance.md): criterion-by-criterion closure, tested revisions and remaining compatibility coverage.
- [Windows software Vulkan](windows-software-vulkan-2026-09-18/README.md): fresh native build, 35 tests, launcher/window/MCP workflows and both relocated Release games on SwiftShader.
- [Checkpoint 5 Linux acceptance](checkpoint5-linux-2026-09-18/README.md): clean offline source build, first Editor launch, exact-candidate standalone games and live Blender checks.
- [Final Linux source checks](final-linux-2026-09-18/README.md): `4cb8255` integrated test results and both Release games after the asset-relocation correction, including package manifests and standalone captures.
- [Linux offline build](offline-linux-2026-09-18.json): a fresh build from committed `d834cfad67cd81d8c4998b90c16791361ca8c0f8`, prefetched dependency inputs, and a network namespace without external connectivity. CPU tests ran; graphics execution is separate.
- [Linux Release export and rendering](linux-release-2026-09-18/README.md): two relocated playable games, Unicode paths, imported Blender geometry, raw frame profiles and exact package hashes. This measurement used an evolving working tree around `5ac4db4`, not a clean checkout of the current commit.
- [Live Blender reimport](blender-live-linux-2026-09-18.json): actual Blender 4.5.3 exports and two live Editor instances, preserving authoring/gameplay/physics while refreshing geometry.
- [Editor recovery](editor-recovery-linux-2026-09-18.json): killed Editor, explicit journal recovery, failed save/import/build and failed Player startup with last-good preservation.
- [Native window boundaries](native-window-linux-2026-09-18.json): XWayland lifecycle, isolated Unicode clipboard, SDL text-input rectangles and the explicit native Wayland restore limitation.
- [Linux native window and input boundaries](native-window-linux-2026-09-18.json): XWayland resize/minimize/restore and SDL text-input-area checks; isolated Xvfb Unicode clipboard roundtrip with restoration. Native Wayland restore remains unconfirmed; real OS IME composition was not tested.
The Linux records do not establish Windows correctness, physical Windows GPU performance, native Wayland restore support, or editor responsiveness under large workloads. Windows CI artifacts record their own commit and software Vulkan results. A skipped compositor operation is not a completed acceptance check.
Performance budgets below are proposals for P1 regression tracking, not completed release requirements. Repeat measurements on a controlled reference host and add representative content before treating them as engine-wide targets.
The thresholds in the [Release baseline](linux-release-2026-09-18/README.md) are the initial P1 tracking budgets for its exact scenes and reference host. They are not engine-wide guarantees or enforced MVP performance gates. Repeat measurements on a controlled reference host and add representative content before expanding their scope.
@@ -0,0 +1,38 @@
# Checkpoint 5 Linux acceptance
These functional checks used the engine source at
`0f34b036313c011861dbfd5828ed45c4f7940b05`. They supplement the earlier Release
performance baseline; export runs overlapped compilation and are not benchmarks.
- [Clean offline build](offline.json): committed source extracted with `git archive`,
empty build directory, external networking disabled, prefetched dependencies and
toolchain. Full default native build and 20 CPU tests passed in 205.77 seconds.
- [First Editor launch](first-run.json): that freshly built default Editor created
a new 3D project following the Manual's command, copied the correct gameplay
templates and rendered three native X11/Xvfb frames before closing successfully.
- [Both standalone games](playable-exports.json): the real Editor produced Release
packages, verified package hashes, moved them outside the SDK into Unicode paths,
hid source projects, then validated and rendered 120 frames per game without
scene/asset overrides. RTX 2080 Ti, Khronos validation active, zero validation
errors. The packages contained 17 files for 2D and 22 for 3D.
- [Blender round-trip](blender.json): unmodified Blender 4.5.3 and the actual live
Editor probe updated two instances while preserving IDs, transforms, tint, physics,
opaque gameplay and document revision. Removed outputs kept the last good visible
generation. The verification harness was updated to distinguish source freshness
from active-generation preservation; its separate hash is included in the report.
- [Editor recovery](recovery.json): seven failure/recovery scenarios passed against
the same source revision and recorded Editor hash: interrupted process, explicit
journal recovery, failed save/import/build/Player startup, and subsequent recovery.
The integrated build with optional diagnostics also passed 34 tests with one
explicit native Wayland restore skip; the sanitizer configuration passed 18/18.
These results describe Linux. Windows has separate CI and export evidence.
Native OS IME composition and moving between physical monitors were not exercised;
widget composition, DPI and native SDL input-boundary tests have narrower scope.
The following image is an actual Editor capture from the Blender probe, after
rename/geometry reimport. It is not the generated UI reference. The test scene has
two placed instances and no selected object.
![Native Faset Editor after Blender reimport](editor-blender.png)
@@ -0,0 +1,70 @@
{
"source_commit": "0f34b036313c011861dbfd5828ed45c4f7940b05",
"recorded_at_utc": "2026-09-18T02:45:37.886125+00:00",
"platform": "Linux-7.0.0-31-generic-x86_64-with-glibc2.43",
"working_tree_diff": [
" M tools/verify_blender_roundtrip.py"
],
"candidate_binaries_note": "Existing integrated Debug binaries from checkpoint5 build; SHA256 captured after this run. Engine source unchanged; verification harness has explicit freshness assertions patched after candidate commit.",
"command": "python3 tools/verify_blender_roundtrip.py --blender .cache/blender/blender --editor build/linux-debug/faset_editor --ui-probe build/linux-debug/faset_blender_editor_probe --output .cache/blender-final-candidate/verified",
"hashes": {
"build/linux-debug/faset_editor": "04baf2ec09f3f097657553d5b862ba5c90749d2cdbf4a239c6b92a45dee56ee9",
"build/linux-debug/faset_blender_editor_probe": "141433f89ae20202a16597525bfdcd59586bf17ab72ada29104ca324857b5842",
".cache/blender/blender": "5e15447670804c855fef6033ac9b8fd82696b762095becf0df79b1c2f8034397",
"tools/verify_blender_roundtrip.py": "ce3bb9d02500a6fe8becef23a7c966449a13d7d9d00d92f2177c0c431ac7f930",
"tests/blender/generate_fixture.py": "6d7951c0d35b8e4e71b81644af31d66af4e395511d929452a178f81ba30e487b",
"tests/editor_blender_reimport_probe.cpp": "0474276d04e8c18c1d2d8d55ff2cff8cfabba815bb3428af51394e22649e3923",
"tools/blender_addon/__init__.py": "e1a44aed99e09a6ad208966eb2e3808110d87311f5721774575a14471ed852e2",
"tools/blender_addon/bundle.py": "f0fd9707b853662be00d08440ab9cc65928cec5a8e053561834bd64fd43d1488",
"dependencies.lock.json": "0583b24061dfc6ba3db76be89ceeaf408cac18d237773833204074af5d8a81d5",
".cache/blender-final-candidate/verified/fixture/initial/manifest.json": "830818ee07a003aad63ed1345b0179852b9de1ab9a322142bd23e50fb501ba7d",
".cache/blender-final-candidate/verified/fixture/removed/manifest.json": "45e07ec2c4ae98c6a9b74a1b60089a2da1ff2ade1b9822d048b33de640d80665",
".cache/blender-final-candidate/verified/fixture/renamed/manifest.json": "dfbe56099ec026eaedd4a25218f3e3270ac075a933d77d37f8b784963792250c",
".cache/blender-final-candidate/verified/fixture/initial/payload/81fdfbd230989c9f4985963cddf63edcfb89c13a0ef4a9265c853006830be488.glb": "81fdfbd230989c9f4985963cddf63edcfb89c13a0ef4a9265c853006830be488",
".cache/blender-final-candidate/verified/fixture/removed/payload/3a9c9671bc1804454227d14f38705b9deacfd95492bf0aea1d2754ba198f128b.glb": "3a9c9671bc1804454227d14f38705b9deacfd95492bf0aea1d2754ba198f128b",
".cache/blender-final-candidate/verified/fixture/renamed/payload/568624163d90cf20f71629ca1cb11f128898260bc521ae66bfc1a3ae6bf4b3e6.glb": "568624163d90cf20f71629ca1cb11f128898260bc521ae66bfc1a3ae6bf4b3e6",
".cache/blender-final-candidate/verified/live-editor/initial.ppm": "363273f070f212580088d52b273baf94cebd62410bb9cf775dee14792f18bd99",
".cache/blender-final-candidate/verified/live-editor/renamed.ppm": "973a99aa43d4e32345bba023ec34dd443db9dc747590c128f996f5f258fd9038",
".cache/blender-final-candidate/verified/live-editor/initial.png": "57313599964308512499eb94d35d8711ff230ec6e8f4542802a147741efc77d4",
".cache/blender-final-candidate/verified/live-editor/renamed.png": "7df8f30b892f58af00ebfe48db3ddfb58150c1faffa19fa2fc792e3e65e8cfe1"
},
"results": {
"blender": "Blender 4.5.3 LTS",
"asset_id": "54c039e4-c19f-4365-a9f8-a38416ec6e3f",
"initial_generation": "499f254ce440ecb86118f2f6803f21013e763d35cfdba1c4356be7a457eec718",
"renamed_generation": "797e63652213752dc7c92029c4e9743517c5f40547b97eac748e60b17f142926",
"stable_output_ids": true,
"removed_output_conflict": true,
"failed_import_keeps_generation": true,
"authoring_preserved": true,
"changed_source_marked_stale": true,
"invalid_bundle_marked_stale": true,
"live_editor": {
"conflict_keeps_visible_generation": true,
"instances": 2,
"live_geometry_updated": true,
"opaque_gameplay_preserved": true,
"physics_fields_preserved": true,
"placement_and_tint_preserved": true,
"status": "passed",
"validation_enabled": true,
"validation_errors": 0
}
},
"limits": [
"Linux offscreen Vulkan Editor snapshot with validation; not a physical desktop input test.",
"No native OS IME or physical mixed-monitor DPI exercised.",
"Static geometry/material fixture; no skeleton/animation or arbitrary Blender shader fidelity claim.",
"Windows export and native platform acceptance are separate."
],
"original_harness_failure": "Whole faset_assets response equality was invalidated by new freshness current->stale; immutable active manifests remain equal. Revised harness separately verifies stale bundle.changed/bundle.unavailable and last-good generation.",
"hardware_context": {
"host_gpu": "NVIDIA GeForce RTX 2080 Ti",
"nvidia_driver": "595.84"
},
"screenshot": {
"path": ".cache/blender-final-candidate/verified/live-editor/renamed.png",
"stage": "After successful stable-ID rename and geometry reimport, before removed-output conflict.",
"conversion": "PNG encoded from renderer-produced renamed.ppm without resizing, cropping, recoloring or content changes."
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

@@ -0,0 +1,20 @@
{
"source_commit": "0f34b036313c011861dbfd5828ed45c4f7940b05",
"recorded_at_utc": "2026-09-18T02:50:10.534440+00:00",
"platform": "Linux-7.0.0-31-generic-x86_64-with-glibc2.43",
"source": "Fresh offline git archive checkout, default options, no previous build directory",
"command": "xvfb-run -a <clean-sdk>/build/linux-debug/faset_editor --project <new-directory>/MyGame --new MyGame --dimension 3 --frames 3 --capture <evidence>/editor.ppm",
"editor_sha256": "71182902617d617749d383ff87d29929013751b9597dcdbcb5f25ce323ebb64b",
"checks": {
"exit_code": 0,
"project_name": "MyGame",
"dimension": 3,
"gameplay_files_match_templates": true,
"rendered_capture": [
1440,
900
],
"capture_sha256": "e15c1e50106a4a188c817e9acb6382f13f094f163768a937ae39ddee3637971b"
},
"scope": "Manual build prerequisites already installed; engine built from clean source. Three native X11/Xvfb Editor frames; GPU execution does not prove physical OS IME or mixed-monitor behavior."
}
@@ -0,0 +1,12 @@
{
"format": "faset.offline-build",
"version": 1,
"revision": "0f34b036313c011861dbfd5828ed45c4f7940b05",
"recorded_at_utc": "2026-09-18T02:47:01.536454+00:00",
"seconds": 205.76940188600202,
"returncode": 0,
"network": "fresh user/network namespace; external connection must fail",
"source": "git archive of committed HEAD; no existing build directory",
"inputs": "prefetched archives + Slang; system compiler, SDK and development libraries",
"tests": "full native build, CPU CTests; GPU/window execution verified separately"
}
@@ -0,0 +1,452 @@
{
"format": "faset.playable-export-verification",
"version": 1,
"started_utc": "2026-09-18T02:43:37.045153+00:00",
"platform": "linux",
"engine": "/home/emil/Desktop/Faset_Engine",
"editor": "/home/emil/Desktop/Faset_Engine/build/linux-debug/faset_editor",
"standalone_root": "/tmp/faset-playable-exports-25rumkwv",
"frames_per_game": 120,
"status": "passed",
"projects": [
{
"name": "collect-2d",
"dimension": 2,
"source_inputs": [
{
"path": ".gitignore",
"sha256": "53aa4d7124d4c8d93b8d7c4cb470b6c82b844e019a660d6243ffeadc50602de1"
},
{
"path": "README.md",
"sha256": "d6c35206b10ee28efd5cc02da77a3ce9b6e1f8ce085793150bbf2f23bd925d65"
},
{
"path": "Scenes/main.scene.json",
"sha256": "be48a6d21385e717b6c8ebf9a3b4322eebbeff6bb067428e089ab5214be79854"
},
{
"path": "Scripts/Gameplay.cpp",
"sha256": "6b581b24da613e1915819de0a0f0ea820dd3333efa62c4b479a9ea7ffdbc6bcc"
},
{
"path": "Scripts/Gameplay.hpp",
"sha256": "4121587182ed4f74901b1c0757c53daadbf309af1d6bb5dd87fef142130ccbbe"
},
{
"path": "project.faset.json",
"sha256": "36e2acd32210f5489372a2331346a3294ead2395f0713e3e5fd2da4e83263689"
}
],
"generation": "2bf52972-98ee-4379-8b7c-eb6f0dfca6a5",
"configuration": "Release",
"standalone_directory": "/tmp/faset-playable-exports-25rumkwv/Faset Café 世界/collect-2d",
"executable": "faset_player",
"package_file_count": 17,
"asset_generations": {},
"device": "NVIDIA GeForce RTX 2080 Ti",
"validation_enabled": true,
"validation_errors": 0,
"completed_frames": 120,
"summary_ms": {
"gpu": {
"max": 0.592896,
"min": 0.558112,
"p50": 0.55904,
"p95": 0.577952,
"samples": 120
},
"render_call": {
"max": 4.604147,
"min": 1.474391,
"p50": 1.713513,
"p95": 2.008409,
"samples": 120
},
"renderer_cpu": {
"max": 4.60056,
"min": 1.472197,
"p50": 1.710667,
"p95": 2.00375,
"samples": 120
},
"renderer_readback_cpu": {
"max": 2.634671,
"min": 0.395376,
"p50": 0.449368,
"p95": 0.596425,
"samples": 120
},
"simulation": {
"max": 0.394364,
"min": 0.133442,
"p50": 0.146897,
"p95": 0.212962,
"samples": 120
},
"snapshot": {
"max": 0.208042,
"min": 0.125827,
"p50": 0.134384,
"p95": 0.182785,
"samples": 120
},
"wall": {
"max": 5.039538,
"min": 1.763687,
"p50": 2.01393,
"p95": 2.375862,
"samples": 120
}
},
"capture": {
"width": 1280,
"height": 720,
"sampled_colors": 7,
"sha256": "f9d74067d87c1ebf30c6db372a26d93b7285791c8cb0307a24af5adb23bf201a"
},
"source_project_paths_unavailable": true,
"status": "passed"
},
{
"name": "collect-3d",
"dimension": 3,
"source_inputs": [
{
"path": ".gitignore",
"sha256": "53aa4d7124d4c8d93b8d7c4cb470b6c82b844e019a660d6243ffeadc50602de1"
},
{
"path": "Assets/exit-arch/create.py",
"sha256": "9c7291124fb1498a3f992ef74afc39cd98f9cc3e2ff4687c633bece85d580905"
},
{
"path": "Assets/exit-arch/manifest.json",
"sha256": "7a13347adc89761fb02ebeab3c58ba87f319cd62f53ec87a3bb61bcd066ffa55"
},
{
"path": "Assets/exit-arch/manifest.json.faset-import.json",
"sha256": "ef4eef28a18a0cc40a40df75db34c97faa5d783b891265f862633f3aec514afc"
},
{
"path": "Assets/exit-arch/payload/ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3.glb",
"sha256": "ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3"
},
{
"path": "Assets/exit-arch/source.blend",
"sha256": "ff2676bec97ab778e531e87a185ad716049ea3b05b4a4f0027a6345737735035"
},
{
"path": "README.md",
"sha256": "2df5ca4df47ab5d3d05d41508201296d4ad5ec876245f19f061767ade6a30e8f"
},
{
"path": "Scenes/main.scene.json",
"sha256": "61b65baf79e52f07ac386a7f98acf985a1b09e88770cdde37ef461dc94b9dcd7"
},
{
"path": "Scripts/Extensions/Beacon.hpp",
"sha256": "c60d56161eead16f541835053ad32ac3333383d83015709c060b7d45e0af5a97"
},
{
"path": "Scripts/Gameplay.cpp",
"sha256": "5d419786a6861d7f14ed4eca54634694d8cd43be5dbbd60a2c6790db665c3a6a"
},
{
"path": "Scripts/Gameplay.hpp",
"sha256": "4121587182ed4f74901b1c0757c53daadbf309af1d6bb5dd87fef142130ccbbe"
},
{
"path": "project.faset.json",
"sha256": "43d273b1054ec9069369073f54cc1fc7efb3d6b699dcd342c552a2dc2ef852ef"
}
],
"import": {
"asset_id": "5832763b-3ed0-44d6-9088-0b524f196a91",
"cache_hit": false,
"diagnostics": [],
"generation": "4a5bfcc1437a7b4d65c388da2beace0308cceda8e16503d08ce676260f21d5c2",
"manifest": {
"asset_id": "5832763b-3ed0-44d6-9088-0b524f196a91",
"files": [
{
"path": "meshes/mesh-fc069a07a87e0f831fd92efdbc4efa1f-0.fmesh",
"sha256": "98b38aca7d2786c58a2265ba4d1f2255123f03d31d947e239232cf55bfdc2c97",
"size": 928
},
{
"path": "meshes/mesh-0961e2a3f92977836a3aa80cab09277e-0.fmesh",
"sha256": "98b38aca7d2786c58a2265ba4d1f2255123f03d31d947e239232cf55bfdc2c97",
"size": 928
},
{
"path": "meshes/mesh-93b5b3e52cb6bb120fefb80e2d8e222b-0.fmesh",
"sha256": "3875c16ea628d4126373ebfe07816621fbad3961596a2fcd112f1eec0e378071",
"size": 928
}
],
"generation": "4a5bfcc1437a7b4d65c388da2beace0308cceda8e16503d08ce676260f21d5c2",
"importer": "faset-gltf-1/cgltf-1.15",
"input_key": {
"bundle_sha256": "7a13347adc89761fb02ebeab3c58ba87f319cd62f53ec87a3bb61bcd066ffa55",
"dependencies": {},
"importer": "faset-gltf-1/cgltf-1.15",
"settings": {},
"source": "ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3",
"target_profile": "desktop-static-pbr-v1",
"toolchain": {
"cgltf": "360db1a95480fe102ae9c69b27c5d101167ff5ba",
"stb": "2c980bb59875b0d32144a71867fbdebb2f77cd20"
}
},
"kind": "scene",
"materials": [
{
"alpha_cutoff": 0.5,
"alpha_mode": "OPAQUE",
"base_color": [
0.2199999988079071,
0.28999999165534973,
0.3400000035762787,
1.0
],
"base_color_texture": -1,
"double_sided": true,
"emissive": [
0.0,
0.0,
0.0
],
"emissive_texture": -1,
"format": "faset.material",
"id": "material-bb63b094febbf90bb7049c9bcf7587bc",
"metallic": 0.07999999821186066,
"metallic_roughness_texture": -1,
"name": "Weathered stone",
"normal_texture": -1,
"occlusion_texture": -1,
"roughness": 0.800000011920929,
"unlit": false,
"version": 1
}
],
"meshes": [
{
"id": "mesh-fc069a07a87e0f831fd92efdbc4efa1f",
"name": "Cube.001",
"primitives": [
{
"material": 0,
"path": "meshes/mesh-fc069a07a87e0f831fd92efdbc4efa1f-0.fmesh"
}
]
},
{
"id": "mesh-0961e2a3f92977836a3aa80cab09277e",
"name": "Cube.002",
"primitives": [
{
"material": 0,
"path": "meshes/mesh-0961e2a3f92977836a3aa80cab09277e-0.fmesh"
}
]
},
{
"id": "mesh-93b5b3e52cb6bb120fefb80e2d8e222b",
"name": "Cube.003",
"primitives": [
{
"material": 0,
"path": "meshes/mesh-93b5b3e52cb6bb120fefb80e2d8e222b-0.fmesh"
}
]
}
],
"nodes": [
{
"id": "node-cec6e8cea80cf5a98ba3263a0156bee4",
"local_transform": [
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.4500000476837158,
1.2999999523162842,
1.0
],
"mesh": 0,
"name": "Left post",
"parent_id": "",
"stable_source_id": true
},
{
"id": "node-5f8a90a6c4d27020d20bd4fa81d1d958",
"local_transform": [
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.4500000476837158,
-1.2999999523162842,
1.0
],
"mesh": 1,
"name": "Right post",
"parent_id": "",
"stable_source_id": true
},
{
"id": "node-482463e486a8d1fd741340c653cd128f",
"local_transform": [
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
3.0,
0.0,
1.0
],
"mesh": 2,
"name": "Lintel",
"parent_id": "",
"stable_source_id": true
}
],
"outputs": [
"node-cec6e8cea80cf5a98ba3263a0156bee4",
"node-5f8a90a6c4d27020d20bd4fa81d1d958",
"node-482463e486a8d1fd741340c653cd128f",
"mesh-fc069a07a87e0f831fd92efdbc4efa1f",
"mesh-0961e2a3f92977836a3aa80cab09277e",
"mesh-93b5b3e52cb6bb120fefb80e2d8e222b",
"material-bb63b094febbf90bb7049c9bcf7587bc"
],
"payload_source": "/home/emil/Desktop/Faset_Engine/.cache/playable-final-candidate/Faset Café 世界/collect-3d/Assets/exit-arch/payload/ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3.glb",
"schema_version": 1,
"settings": {},
"source": "/home/emil/Desktop/Faset_Engine/.cache/playable-final-candidate/Faset Café 世界/collect-3d/Assets/exit-arch/manifest.json",
"source_sha256": "ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3",
"textures": []
},
"previous_generation": "",
"removed_output_ids": []
},
"generation": "b0a40126-7d6c-414f-843a-23a677ad6f8f",
"configuration": "Release",
"standalone_directory": "/tmp/faset-playable-exports-25rumkwv/Faset Café 世界/collect-3d",
"executable": "faset_player",
"package_file_count": 22,
"asset_generations": {
"5832763b-3ed0-44d6-9088-0b524f196a91": "4a5bfcc1437a7b4d65c388da2beace0308cceda8e16503d08ce676260f21d5c2"
},
"device": "NVIDIA GeForce RTX 2080 Ti",
"validation_enabled": true,
"validation_errors": 0,
"completed_frames": 120,
"summary_ms": {
"gpu": {
"max": 0.615584,
"min": 0.578944,
"p50": 0.58096,
"p95": 0.597312,
"samples": 120
},
"render_call": {
"max": 4.88184,
"min": 1.554402,
"p50": 1.842957,
"p95": 2.153072,
"samples": 120
},
"renderer_cpu": {
"max": 4.876761,
"min": 1.552489,
"p50": 1.838648,
"p95": 2.149254,
"samples": 120
},
"renderer_readback_cpu": {
"max": 2.787459,
"min": 0.398262,
"p50": 0.483592,
"p95": 0.577219,
"samples": 120
},
"simulation": {
"max": 0.38139,
"min": 0.16457,
"p50": 0.192834,
"p95": 0.278605,
"samples": 120
},
"snapshot": {
"max": 0.816561,
"min": 0.155042,
"p50": 0.172175,
"p95": 0.243289,
"samples": 120
},
"wall": {
"max": 6.073458,
"min": 1.902519,
"p50": 2.248081,
"p95": 2.61298,
"samples": 120
}
},
"capture": {
"width": 1280,
"height": 720,
"sampled_colors": 42,
"sha256": "914060401de93d08b33bf09a1e210859e491a0060c331e5e2044f517356f4980"
},
"source_project_paths_unavailable": true,
"status": "passed"
}
],
"finished_utc": "2026-09-18T02:47:27.268249+00:00",
"engine_commit": "0f34b036313c011861dbfd5828ed45c4f7940b05",
"editor_sha256": "04baf2ec09f3f097657553d5b862ba5c90749d2cdbf4a239c6b92a45dee56ee9",
"working_tree_clean_at_start": true,
"engine_commit_at_completion": "0f34b036313c011861dbfd5828ed45c4f7940b05",
"timings_are_benchmark_evidence": false,
"timing_note": "Functional export/relocation/validation/profile completeness acceptance; timings are not benchmark evidence because a separate build runs concurrently.",
"visual_inspection": {
"status": "passed",
"notes": [
"2D capture shows player, platforms, three collectibles, barrier and exit marker.",
"3D capture shows player, room, collectibles, platform, gate and imported exit structure without missing geometry."
],
"png_previews": [
"evidence/collect-2d.png",
"evidence/collect-3d.png"
]
}
}
@@ -0,0 +1,36 @@
{
"format": "faset.editor-recovery-verification",
"version": 1,
"status": "passed",
"checks": [
"acknowledged unsaved edit survives killed Editor and explicit recovery",
"failed save preserves live authoring and last saved file",
"failed Player process is reported without changing authoring data",
"Undo repairs the scene, then Play and Stop leave authoring unchanged",
"failed C++ build keeps prior schema and reports stale status",
"fixed C++ rebuild restores current schema status",
"failed import preserves authoring"
],
"recorded_at_utc": "2026-09-18T02:50:13.733355+00:00",
"platform": "Linux-7.0.0-31-generic-x86_64-with-glibc2.43",
"editor_sha256": "04baf2ec09f3f097657553d5b862ba5c90749d2cdbf4a239c6b92a45dee56ee9",
"logs": [
"build completed",
"Gameplay schema loaded",
"Play started in a separate Player process",
"Player failed: unsupported builtin component version: faset.transform\n",
"Player exited with code 1",
"build completed",
"Gameplay schema loaded",
"Play started in a separate Player process",
"New round: collect the three gold cubes, then reach the green exit. E resets.\n{\"device\":\"NVIDIA GeForce RTX 2080 Ti\",\"dimension\":2,\"frames\":411,\"ticks\":104,\"validation_errors\":0}\n",
"Play stopped; authoring scene unchanged",
"build failed: Process exited with code 1; see job log; previous gameplay metadata remains available and is marked stale",
"build completed",
"Gameplay schema loaded",
"Asset import failed: Cannot read: /home/emil/Desktop/Faset_Engine/.cache/editor-recovery-final-candidate/project/Assets/missing.glb\n"
],
"engine_commit": "0f34b036313c011861dbfd5828ed45c4f7940b05",
"engine_commit_at_completion": "0f34b036313c011861dbfd5828ed45c4f7940b05",
"source_note": "Completed before pending moved-input freshness changes to asset_data.cpp/asset_pipeline.cpp; final-candidate committed engine source."
}
@@ -0,0 +1,61 @@
# Final Linux source checks — 2026-09-18
Engine source: **`4cb82556de31268d2bde73948dd1ff1b6c02f162`**. Both Release games
were exported from a clean working tree at this commit, which remained unchanged
through completion. Editor SHA-256:
`05e2b40c6c05282af71a03990c98c89c673c48a3cf1da0e17a59f911a947049a`.
The [export report](playable-exports.json) records both checked-in projects, their
source hashes, package generations and relocation. The 2D package contains 17 files;
the 3D package contains 22, including the imported Blender arch. Each package passed
CPU validation and 120 offscreen frames after being moved into a `Faset Café 世界`
directory outside the SDK, with the disposable source-project paths hidden. No scene
or asset-directory override was supplied. Package hashes are preserved in the
[2D manifest](collect-2d-manifest.json) and [3D manifest](collect-3d-manifest.json).
Both ran on the physical NVIDIA RTX 2080 Ti with the Khronos validation layer active
and zero reported errors. The [2D run](collect-2d-run.json) and
[3D run](collect-3d-run.json) retain the observed device and counters. Capture hashes
match the preceding checkpoint 5 candidate exactly. These runs are functional
acceptance evidence; the timings retained in the export report are not a controlled
performance benchmark. The separately scoped
[240-frame baseline](../linux-release-2026-09-18/README.md) remains historical evidence.
A further [SDK-unavailable check](sdk-unavailable.json) ran these same packages in a
private user/mount namespace with an empty read-only filesystem covering the entire
Faset checkout, including Editor, builds, cached tools and project copies. Each used
an unrelated empty working directory and fresh home/config/cache directories. Both
passed validation and another 120 frames, with active Vulkan validation, zero errors
and identical capture hashes. File/process tracing found no SDK path accesses or
helper executables; dynamic dependencies resolved to system libraries, with no ELF
RPATH/RUNPATH. The outer SDK was never renamed or hidden and remained unchanged.
The report preserves namespace/mount details and hashes of the retained local traces
and harness. This establishes SDK independence on this Linux host, not universal
distribution or driver compatibility; Windows has separate package checks.
[Test results](tests.json) record 34 passed, one explicit native Wayland restore skip
and zero failed in the 35-test integrated suite with optional diagnostics enabled.
The compositor declined programmatic restore; the skip does not establish that
operation's correctness. XWayland has its own passing
[window record](../native-window-linux-2026-09-18.json). Full ASan/UBSan passed 18/18
on `0f34b03`; the two affected asset/cook tests passed again after the source-location
correction at `4cb8255`.
The preceding [checkpoint 5 record](../checkpoint5-linux-2026-09-18/README.md)
retains the clean offline build, first project launch, all seven recovery scenarios
and live Blender reimport with their exact source/harness provenance. These checks
were not silently relabeled as runs of a later commit. Physical OS IME composition,
mixed-monitor transitions and other GPU/driver families need separate coverage.
Reproduce the export check from the repository root:
```sh
python3 tools/verify_playable_exports.py --editor build/linux-debug/faset_editor \
--output .cache/playable-verification
```
Actual standalone captures:
![2D standalone game](collect-2d.png)
![3D standalone game with the imported Blender arch](collect-3d.png)
@@ -0,0 +1,143 @@
{
"asset_generations": {},
"build_fingerprint": "0adaba82211a3869537b75939521e2877834b23fb06c1d8d0fdd37446c2704ee",
"configuration": "Release",
"executable": "faset_player",
"files": [
{
"path": "scene.fscene",
"sha256": "0d7b221abc1cae5e9f1d04357c684ac6993f5878d634b4b950eec66dd8e55b2a",
"size": 6214
},
{
"path": "faset_player",
"sha256": "f7902f414ab64573a697a8f36b59e203370779990f63c63fbd90c88a7eb1397b",
"size": 5829824
},
{
"path": "shaders/vertexMain.spv",
"sha256": "1ad2631c35d654f48166321ae43d4165043e1b919b14f1dc61caf97b1ada0898",
"size": 1224
},
{
"path": "shaders/fragmentMain.spv",
"sha256": "f5c4f289917ecab5d00d543c053aac1d10e6cca311fd172daf06d315160a3505",
"size": 7436
},
{
"path": "shaders/shadowMain.spv",
"sha256": "7643b4d688492b5ee923b9606f0b0e70343ca05fa67673838206119a6f86d8d8",
"size": 784
},
{
"path": "shaders/vertexMain.reflection.json",
"sha256": "c584f3b957ebf194a292451362a98590f85ff3cfbfd8f917b1c1265039381777",
"size": 2639
},
{
"path": "shaders/fragmentMain.reflection.json",
"sha256": "72ebf8d32452830650416dc4717d89a4324e97ece7028dfb97c66803c8dce71f",
"size": 2649
},
{
"path": "shaders/shadowMain.reflection.json",
"sha256": "e3fd0889cd2f569d410f5d7558a4091d9f57f247a1dcf1788462f67525340819",
"size": 2645
},
{
"path": "Notices/sdl3/LICENSE.txt",
"sha256": "97f35b302b361680ec1e891e95d2d52097bb95abff361434916d99dc1305f127",
"size": 884
},
{
"path": "Notices/entt/LICENSE",
"sha256": "0785027ce472d7c61f05fba664a1d3ba6639c1593ced351ad9e4bed868765d99",
"size": 1097
},
{
"path": "Notices/box2d/LICENSE",
"sha256": "68a3e676d7e94093b102d5cba0d4e04af812040d6f230c3db67a6664574e43d2",
"size": 1067
},
{
"path": "Notices/box3d/LICENSE",
"sha256": "da5e31a26bf3cfd5ba5c96d6823e480128c81e76c107ef9d3ee5d94789184b90",
"size": 1067
},
{
"path": "Notices/json/LICENSE.MIT",
"sha256": "46a65cffd1ea955132d95a8dd921640714a8d6b537d2e4e482d31145ae95b603",
"size": 1076
},
{
"path": "Notices/stb/LICENSE",
"sha256": "bebfe904b14301657e4e5d655c811d51fd31b97c455b9cc2d8600d6bac6cff63",
"size": 2510
},
{
"path": "Notices/dependencies.json",
"sha256": "a54639ad2d9ad13c2e5f1ec90d6775f5dfc493656789b78c7e44debe2a378fdc",
"size": 2206
},
{
"path": "Notices/Faset-NOTICE.txt",
"sha256": "30c2e7e80f5153b31ab57675e07246aef9165965d64e36022b426a26449ece3f",
"size": 204
},
{
"path": "README.txt",
"sha256": "4dc2f0271c69fe39017ff96aa2dfa00b625bec1401d924dc396193ce71c09f3e",
"size": 225
}
],
"format": "faset.export",
"generation": "a0bc193b-3d79-4372-98c2-8875621d4ab3",
"platform": "linux",
"prerequisites": [
"Linux x86_64",
"Vulkan 1.3 driver",
"Compatible glibc and libstdc++ runtime"
],
"renderer_profile": {
"api": "Vulkan 1.3",
"materials": [
"base-color factor and texture",
"metallic and roughness factors"
],
"required_features": [
"dynamicRendering",
"synchronization2"
],
"shadow_map": {
"resolution": 1024,
"world_extent": 40
},
"texture_sampling": "linear clamp, one mip level",
"unsupported_material_features": [
"normal maps",
"metallic-roughness maps",
"emissive and occlusion maps",
"alpha mode selection",
"unlit mode",
"per-material face culling"
]
},
"scene_hash": "fdfa1c49cf78a1cf52cd41b201c35bb0b5f852c90b7626b2a7f17da3e2e3e24c",
"simulation": {
"fixed_delta": 0.016666666666666666,
"gravity": [
0,
-9.81,
0
],
"max_catch_up_ticks": 4,
"physics_substeps": 4
},
"units": {
"angle": "radian",
"coordinates": "right-handed Y-up",
"distance": "metre"
},
"validation_log": "{\"dimension\":2,\"validated\":true}\n",
"version": 1
}
@@ -0,0 +1,18 @@
{
"arguments": [
"/tmp/faset-playable-exports-rnbvn4tk/Faset Café 世界/collect-2d/faset_player",
"--headless",
"--frames",
"120",
"--capture",
"/tmp/faset-playable-exports-rnbvn4tk/Faset Café 世界/collect-2d/verification.ppm",
"--profile",
"/tmp/faset-playable-exports-rnbvn4tk/Faset Café 世界/collect-2d/profile.json"
],
"cwd": "/tmp/faset-playable-exports-rnbvn4tk/empty-working-directory",
"seconds": 0.5882121719987481,
"exit_code": 0,
"timed_out": false,
"stdout": "New round: collect the three gold cubes, then reach the green exit. E resets.\n{\"device\":\"NVIDIA GeForce RTX 2080 Ti\",\"dimension\":2,\"frames\":120,\"ticks\":120,\"validation_errors\":0}\n",
"stderr": ""
}
@@ -0,0 +1,12 @@
{
"arguments": [
"/tmp/faset-playable-exports-rnbvn4tk/Faset Café 世界/collect-2d/faset_player",
"--validate"
],
"cwd": "/tmp/faset-playable-exports-rnbvn4tk/empty-working-directory",
"seconds": 0.004741746000945568,
"exit_code": 0,
"timed_out": false,
"stdout": "{\"dimension\":2,\"validated\":true}\n",
"stderr": ""
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

@@ -0,0 +1,170 @@
{
"asset_generations": {
"5832763b-3ed0-44d6-9088-0b524f196a91": "4a5bfcc1437a7b4d65c388da2beace0308cceda8e16503d08ce676260f21d5c2"
},
"build_fingerprint": "36eac0c6901b352478ec474b922d0543fb0a4ccbf33bd5fa49cca887cf8e7a74",
"configuration": "Release",
"executable": "faset_player",
"files": [
{
"path": "scene.fscene",
"sha256": "21c364140669ec82c6886102667b255df5ccdf0ec77e0ca64060f84dd7b86632",
"size": 8639
},
{
"path": "faset_player",
"sha256": "5537942ff7cd999de044168420b730c772a6f21c3cf81ece389e9495c9eae974",
"size": 5834840
},
{
"path": "shaders/vertexMain.spv",
"sha256": "1ad2631c35d654f48166321ae43d4165043e1b919b14f1dc61caf97b1ada0898",
"size": 1224
},
{
"path": "shaders/fragmentMain.spv",
"sha256": "f5c4f289917ecab5d00d543c053aac1d10e6cca311fd172daf06d315160a3505",
"size": 7436
},
{
"path": "shaders/shadowMain.spv",
"sha256": "7643b4d688492b5ee923b9606f0b0e70343ca05fa67673838206119a6f86d8d8",
"size": 784
},
{
"path": "shaders/vertexMain.reflection.json",
"sha256": "c584f3b957ebf194a292451362a98590f85ff3cfbfd8f917b1c1265039381777",
"size": 2639
},
{
"path": "shaders/fragmentMain.reflection.json",
"sha256": "72ebf8d32452830650416dc4717d89a4324e97ece7028dfb97c66803c8dce71f",
"size": 2649
},
{
"path": "shaders/shadowMain.reflection.json",
"sha256": "e3fd0889cd2f569d410f5d7558a4091d9f57f247a1dcf1788462f67525340819",
"size": 2645
},
{
"path": "assets/5832763b-3ed0-44d6-9088-0b524f196a91/generations/4a5bfcc1437a7b4d65c388da2beace0308cceda8e16503d08ce676260f21d5c2/meshes/mesh-fc069a07a87e0f831fd92efdbc4efa1f-0.fmesh",
"sha256": "98b38aca7d2786c58a2265ba4d1f2255123f03d31d947e239232cf55bfdc2c97",
"size": 928
},
{
"path": "assets/5832763b-3ed0-44d6-9088-0b524f196a91/generations/4a5bfcc1437a7b4d65c388da2beace0308cceda8e16503d08ce676260f21d5c2/meshes/mesh-0961e2a3f92977836a3aa80cab09277e-0.fmesh",
"sha256": "98b38aca7d2786c58a2265ba4d1f2255123f03d31d947e239232cf55bfdc2c97",
"size": 928
},
{
"path": "assets/5832763b-3ed0-44d6-9088-0b524f196a91/generations/4a5bfcc1437a7b4d65c388da2beace0308cceda8e16503d08ce676260f21d5c2/meshes/mesh-93b5b3e52cb6bb120fefb80e2d8e222b-0.fmesh",
"sha256": "3875c16ea628d4126373ebfe07816621fbad3961596a2fcd112f1eec0e378071",
"size": 928
},
{
"path": "assets/5832763b-3ed0-44d6-9088-0b524f196a91/generations/4a5bfcc1437a7b4d65c388da2beace0308cceda8e16503d08ce676260f21d5c2/manifest.json",
"sha256": "ee3f68794c6dc44ab492b1ba4640aa74e4de79a5ec10aed8dcdd45a03afc508e",
"size": 4532
},
{
"path": "assets/5832763b-3ed0-44d6-9088-0b524f196a91/current.json",
"sha256": "b0732959808ce61ef5a3223fba2d9ad8c17a3ea7873d4a81c00aadee6c51032e",
"size": 134
},
{
"path": "Notices/sdl3/LICENSE.txt",
"sha256": "97f35b302b361680ec1e891e95d2d52097bb95abff361434916d99dc1305f127",
"size": 884
},
{
"path": "Notices/entt/LICENSE",
"sha256": "0785027ce472d7c61f05fba664a1d3ba6639c1593ced351ad9e4bed868765d99",
"size": 1097
},
{
"path": "Notices/box2d/LICENSE",
"sha256": "68a3e676d7e94093b102d5cba0d4e04af812040d6f230c3db67a6664574e43d2",
"size": 1067
},
{
"path": "Notices/box3d/LICENSE",
"sha256": "da5e31a26bf3cfd5ba5c96d6823e480128c81e76c107ef9d3ee5d94789184b90",
"size": 1067
},
{
"path": "Notices/json/LICENSE.MIT",
"sha256": "46a65cffd1ea955132d95a8dd921640714a8d6b537d2e4e482d31145ae95b603",
"size": 1076
},
{
"path": "Notices/stb/LICENSE",
"sha256": "bebfe904b14301657e4e5d655c811d51fd31b97c455b9cc2d8600d6bac6cff63",
"size": 2510
},
{
"path": "Notices/dependencies.json",
"sha256": "a54639ad2d9ad13c2e5f1ec90d6775f5dfc493656789b78c7e44debe2a378fdc",
"size": 2206
},
{
"path": "Notices/Faset-NOTICE.txt",
"sha256": "30c2e7e80f5153b31ab57675e07246aef9165965d64e36022b426a26449ece3f",
"size": 204
},
{
"path": "README.txt",
"sha256": "4dc2f0271c69fe39017ff96aa2dfa00b625bec1401d924dc396193ce71c09f3e",
"size": 225
}
],
"format": "faset.export",
"generation": "66aa0bad-fb8a-424a-a82a-a41e58b4a13d",
"platform": "linux",
"prerequisites": [
"Linux x86_64",
"Vulkan 1.3 driver",
"Compatible glibc and libstdc++ runtime"
],
"renderer_profile": {
"api": "Vulkan 1.3",
"materials": [
"base-color factor and texture",
"metallic and roughness factors"
],
"required_features": [
"dynamicRendering",
"synchronization2"
],
"shadow_map": {
"resolution": 1024,
"world_extent": 40
},
"texture_sampling": "linear clamp, one mip level",
"unsupported_material_features": [
"normal maps",
"metallic-roughness maps",
"emissive and occlusion maps",
"alpha mode selection",
"unlit mode",
"per-material face culling"
]
},
"scene_hash": "ee12794145c14ba5b599c5d9ae21648cccdfa91c47ee7742549f60d5fe7bc3e0",
"simulation": {
"fixed_delta": 0.016666666666666666,
"gravity": [
0,
-9.81,
0
],
"max_catch_up_ticks": 4,
"physics_substeps": 4
},
"units": {
"angle": "radian",
"coordinates": "right-handed Y-up",
"distance": "metre"
},
"validation_log": "warning: material material-bb63b094febbf90bb7049c9bcf7587bc has features beyond the initial base-color/PBR renderer\n{\"dimension\":3,\"validated\":true}\n",
"version": 1
}
@@ -0,0 +1,18 @@
{
"arguments": [
"/tmp/faset-playable-exports-rnbvn4tk/Faset Café 世界/collect-3d/faset_player",
"--headless",
"--frames",
"120",
"--capture",
"/tmp/faset-playable-exports-rnbvn4tk/Faset Café 世界/collect-3d/verification.ppm",
"--profile",
"/tmp/faset-playable-exports-rnbvn4tk/Faset Café 世界/collect-3d/profile.json"
],
"cwd": "/tmp/faset-playable-exports-rnbvn4tk/empty-working-directory",
"seconds": 0.5726850880018901,
"exit_code": 0,
"timed_out": false,
"stdout": "New round: collect the three gold cubes, then reach the green exit. E resets.\n{\"device\":\"NVIDIA GeForce RTX 2080 Ti\",\"dimension\":3,\"frames\":120,\"ticks\":120,\"validation_errors\":0}\n",
"stderr": "warning: material material-bb63b094febbf90bb7049c9bcf7587bc has features beyond the initial base-color/PBR renderer\n"
}
@@ -0,0 +1,12 @@
{
"arguments": [
"/tmp/faset-playable-exports-rnbvn4tk/Faset Café 世界/collect-3d/faset_player",
"--validate"
],
"cwd": "/tmp/faset-playable-exports-rnbvn4tk/empty-working-directory",
"seconds": 0.005225719000009121,
"exit_code": 0,
"timed_out": false,
"stdout": "{\"dimension\":3,\"validated\":true}\n",
"stderr": "warning: material material-bb63b094febbf90bb7049c9bcf7587bc has features beyond the initial base-color/PBR renderer\n"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

@@ -0,0 +1,455 @@
{
"format": "faset.playable-export-verification",
"version": 1,
"started_utc": "2026-09-18T02:56:47.916086+00:00",
"platform": "linux",
"engine": "/home/emil/Desktop/Faset_Engine",
"editor": "/home/emil/Desktop/Faset_Engine/build/linux-debug/faset_editor",
"standalone_root": "/tmp/faset-playable-exports-rnbvn4tk",
"frames_per_game": 120,
"status": "passed",
"projects": [
{
"name": "collect-2d",
"dimension": 2,
"source_inputs": [
{
"path": ".gitignore",
"sha256": "53aa4d7124d4c8d93b8d7c4cb470b6c82b844e019a660d6243ffeadc50602de1"
},
{
"path": "README.md",
"sha256": "d6c35206b10ee28efd5cc02da77a3ce9b6e1f8ce085793150bbf2f23bd925d65"
},
{
"path": "Scenes/main.scene.json",
"sha256": "be48a6d21385e717b6c8ebf9a3b4322eebbeff6bb067428e089ab5214be79854"
},
{
"path": "Scripts/Gameplay.cpp",
"sha256": "6b581b24da613e1915819de0a0f0ea820dd3333efa62c4b479a9ea7ffdbc6bcc"
},
{
"path": "Scripts/Gameplay.hpp",
"sha256": "4121587182ed4f74901b1c0757c53daadbf309af1d6bb5dd87fef142130ccbbe"
},
{
"path": "project.faset.json",
"sha256": "36e2acd32210f5489372a2331346a3294ead2395f0713e3e5fd2da4e83263689"
}
],
"generation": "a0bc193b-3d79-4372-98c2-8875621d4ab3",
"configuration": "Release",
"standalone_directory": "/tmp/faset-playable-exports-rnbvn4tk/Faset Café 世界/collect-2d",
"executable": "faset_player",
"package_file_count": 17,
"asset_generations": {},
"device": "NVIDIA GeForce RTX 2080 Ti",
"validation_enabled": true,
"validation_errors": 0,
"completed_frames": 120,
"summary_ms": {
"gpu": {
"max": 0.580928,
"min": 0.558752,
"p50": 0.561056,
"p95": 0.577536,
"samples": 120
},
"render_call": {
"max": 4.353283,
"min": 1.355868,
"p50": 1.575242,
"p95": 1.779117,
"samples": 120
},
"renderer_cpu": {
"max": 4.349596,
"min": 1.354355,
"p50": 1.572978,
"p95": 1.777063,
"samples": 120
},
"renderer_readback_cpu": {
"max": 2.542697,
"min": 0.357785,
"p50": 0.393262,
"p95": 0.477721,
"samples": 120
},
"simulation": {
"max": 0.256133,
"min": 0.12707,
"p50": 0.136477,
"p95": 0.187975,
"samples": 120
},
"snapshot": {
"max": 0.263748,
"min": 0.120477,
"p50": 0.12702,
"p95": 0.16401,
"samples": 120
},
"wall": {
"max": 4.772504,
"min": 1.625006,
"p50": 1.861853,
"p95": 2.054506,
"samples": 120
}
},
"capture": {
"width": 1280,
"height": 720,
"sampled_colors": 7,
"sha256": "f9d74067d87c1ebf30c6db372a26d93b7285791c8cb0307a24af5adb23bf201a"
},
"source_project_paths_unavailable": true,
"status": "passed"
},
{
"name": "collect-3d",
"dimension": 3,
"source_inputs": [
{
"path": ".gitignore",
"sha256": "53aa4d7124d4c8d93b8d7c4cb470b6c82b844e019a660d6243ffeadc50602de1"
},
{
"path": "Assets/exit-arch/create.py",
"sha256": "9c7291124fb1498a3f992ef74afc39cd98f9cc3e2ff4687c633bece85d580905"
},
{
"path": "Assets/exit-arch/manifest.json",
"sha256": "7a13347adc89761fb02ebeab3c58ba87f319cd62f53ec87a3bb61bcd066ffa55"
},
{
"path": "Assets/exit-arch/manifest.json.faset-import.json",
"sha256": "ef4eef28a18a0cc40a40df75db34c97faa5d783b891265f862633f3aec514afc"
},
{
"path": "Assets/exit-arch/payload/ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3.glb",
"sha256": "ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3"
},
{
"path": "Assets/exit-arch/source.blend",
"sha256": "ff2676bec97ab778e531e87a185ad716049ea3b05b4a4f0027a6345737735035"
},
{
"path": "README.md",
"sha256": "2df5ca4df47ab5d3d05d41508201296d4ad5ec876245f19f061767ade6a30e8f"
},
{
"path": "Scenes/main.scene.json",
"sha256": "61b65baf79e52f07ac386a7f98acf985a1b09e88770cdde37ef461dc94b9dcd7"
},
{
"path": "Scripts/Extensions/Beacon.hpp",
"sha256": "c60d56161eead16f541835053ad32ac3333383d83015709c060b7d45e0af5a97"
},
{
"path": "Scripts/Gameplay.cpp",
"sha256": "5d419786a6861d7f14ed4eca54634694d8cd43be5dbbd60a2c6790db665c3a6a"
},
{
"path": "Scripts/Gameplay.hpp",
"sha256": "4121587182ed4f74901b1c0757c53daadbf309af1d6bb5dd87fef142130ccbbe"
},
{
"path": "project.faset.json",
"sha256": "43d273b1054ec9069369073f54cc1fc7efb3d6b699dcd342c552a2dc2ef852ef"
}
],
"import": {
"asset_id": "5832763b-3ed0-44d6-9088-0b524f196a91",
"cache_hit": false,
"diagnostics": [],
"generation": "4a5bfcc1437a7b4d65c388da2beace0308cceda8e16503d08ce676260f21d5c2",
"manifest": {
"asset_id": "5832763b-3ed0-44d6-9088-0b524f196a91",
"files": [
{
"path": "meshes/mesh-fc069a07a87e0f831fd92efdbc4efa1f-0.fmesh",
"sha256": "98b38aca7d2786c58a2265ba4d1f2255123f03d31d947e239232cf55bfdc2c97",
"size": 928
},
{
"path": "meshes/mesh-0961e2a3f92977836a3aa80cab09277e-0.fmesh",
"sha256": "98b38aca7d2786c58a2265ba4d1f2255123f03d31d947e239232cf55bfdc2c97",
"size": 928
},
{
"path": "meshes/mesh-93b5b3e52cb6bb120fefb80e2d8e222b-0.fmesh",
"sha256": "3875c16ea628d4126373ebfe07816621fbad3961596a2fcd112f1eec0e378071",
"size": 928
}
],
"generation": "4a5bfcc1437a7b4d65c388da2beace0308cceda8e16503d08ce676260f21d5c2",
"importer": "faset-gltf-1/cgltf-1.15",
"input_key": {
"bundle_sha256": "7a13347adc89761fb02ebeab3c58ba87f319cd62f53ec87a3bb61bcd066ffa55",
"dependencies": {},
"importer": "faset-gltf-1/cgltf-1.15",
"settings": {},
"source": "ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3",
"target_profile": "desktop-static-pbr-v1",
"toolchain": {
"cgltf": "360db1a95480fe102ae9c69b27c5d101167ff5ba",
"stb": "2c980bb59875b0d32144a71867fbdebb2f77cd20"
}
},
"kind": "scene",
"materials": [
{
"alpha_cutoff": 0.5,
"alpha_mode": "OPAQUE",
"base_color": [
0.2199999988079071,
0.28999999165534973,
0.3400000035762787,
1.0
],
"base_color_texture": -1,
"double_sided": true,
"emissive": [
0.0,
0.0,
0.0
],
"emissive_texture": -1,
"format": "faset.material",
"id": "material-bb63b094febbf90bb7049c9bcf7587bc",
"metallic": 0.07999999821186066,
"metallic_roughness_texture": -1,
"name": "Weathered stone",
"normal_texture": -1,
"occlusion_texture": -1,
"roughness": 0.800000011920929,
"unlit": false,
"version": 1
}
],
"meshes": [
{
"id": "mesh-fc069a07a87e0f831fd92efdbc4efa1f",
"name": "Cube.001",
"primitives": [
{
"material": 0,
"path": "meshes/mesh-fc069a07a87e0f831fd92efdbc4efa1f-0.fmesh"
}
]
},
{
"id": "mesh-0961e2a3f92977836a3aa80cab09277e",
"name": "Cube.002",
"primitives": [
{
"material": 0,
"path": "meshes/mesh-0961e2a3f92977836a3aa80cab09277e-0.fmesh"
}
]
},
{
"id": "mesh-93b5b3e52cb6bb120fefb80e2d8e222b",
"name": "Cube.003",
"primitives": [
{
"material": 0,
"path": "meshes/mesh-93b5b3e52cb6bb120fefb80e2d8e222b-0.fmesh"
}
]
}
],
"nodes": [
{
"id": "node-cec6e8cea80cf5a98ba3263a0156bee4",
"local_transform": [
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.4500000476837158,
1.2999999523162842,
1.0
],
"mesh": 0,
"name": "Left post",
"parent_id": "",
"stable_source_id": true
},
{
"id": "node-5f8a90a6c4d27020d20bd4fa81d1d958",
"local_transform": [
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.4500000476837158,
-1.2999999523162842,
1.0
],
"mesh": 1,
"name": "Right post",
"parent_id": "",
"stable_source_id": true
},
{
"id": "node-482463e486a8d1fd741340c653cd128f",
"local_transform": [
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
3.0,
0.0,
1.0
],
"mesh": 2,
"name": "Lintel",
"parent_id": "",
"stable_source_id": true
}
],
"outputs": [
"node-cec6e8cea80cf5a98ba3263a0156bee4",
"node-5f8a90a6c4d27020d20bd4fa81d1d958",
"node-482463e486a8d1fd741340c653cd128f",
"mesh-fc069a07a87e0f831fd92efdbc4efa1f",
"mesh-0961e2a3f92977836a3aa80cab09277e",
"mesh-93b5b3e52cb6bb120fefb80e2d8e222b",
"material-bb63b094febbf90bb7049c9bcf7587bc"
],
"payload_source": "/home/emil/Desktop/Faset_Engine/.cache/playable-release-final/Faset Café 世界/collect-3d/Assets/exit-arch/payload/ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3.glb",
"schema_version": 1,
"settings": {},
"source": "/home/emil/Desktop/Faset_Engine/.cache/playable-release-final/Faset Café 世界/collect-3d/Assets/exit-arch/manifest.json",
"source_sha256": "ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3",
"textures": []
},
"previous_generation": "",
"removed_output_ids": []
},
"generation": "66aa0bad-fb8a-424a-a82a-a41e58b4a13d",
"configuration": "Release",
"standalone_directory": "/tmp/faset-playable-exports-rnbvn4tk/Faset Café 世界/collect-3d",
"executable": "faset_player",
"package_file_count": 22,
"asset_generations": {
"5832763b-3ed0-44d6-9088-0b524f196a91": "4a5bfcc1437a7b4d65c388da2beace0308cceda8e16503d08ce676260f21d5c2"
},
"device": "NVIDIA GeForce RTX 2080 Ti",
"validation_enabled": true,
"validation_errors": 0,
"completed_frames": 120,
"summary_ms": {
"gpu": {
"max": 0.609888,
"min": 0.5784,
"p50": 0.580288,
"p95": 0.600416,
"samples": 120
},
"render_call": {
"max": 4.356229,
"min": 1.486144,
"p50": 1.670422,
"p95": 1.897079,
"samples": 120
},
"renderer_cpu": {
"max": 4.352772,
"min": 1.484541,
"p50": 1.668107,
"p95": 1.894835,
"samples": 120
},
"renderer_readback_cpu": {
"max": 2.37976,
"min": 0.36052,
"p50": 0.407479,
"p95": 0.460479,
"samples": 120
},
"simulation": {
"max": 0.282002,
"min": 0.164811,
"p50": 0.176523,
"p95": 0.235354,
"samples": 120
},
"snapshot": {
"max": 0.7686,
"min": 0.154722,
"p50": 0.166093,
"p95": 0.187914,
"samples": 120
},
"wall": {
"max": 5.493053,
"min": 1.819833,
"p50": 2.0303,
"p95": 2.317552,
"samples": 120
}
},
"capture": {
"width": 1280,
"height": 720,
"sampled_colors": 42,
"sha256": "914060401de93d08b33bf09a1e210859e491a0060c331e5e2044f517356f4980"
},
"source_project_paths_unavailable": true,
"status": "passed"
}
],
"finished_utc": "2026-09-18T03:00:21.028754+00:00",
"engine_commit": "4cb82556de31268d2bde73948dd1ff1b6c02f162",
"editor_sha256": "05e2b40c6c05282af71a03990c98c89c673c48a3cf1da0e17a59f911a947049a",
"engine_commit_at_completion": "4cb82556de31268d2bde73948dd1ff1b6c02f162",
"working_tree_changes_at_start": [],
"timings_are_benchmark_evidence": false,
"timing_note": "Final release source functional export/relocation/validation/profile completeness acceptance. Timings are retained as functional evidence, not a controlled performance benchmark.",
"capture_comparison_to_candidate": {
"collect-2d": {
"prior_engine_commit": "0f34b036313c011861dbfd5828ed45c4f7940b05",
"exact_capture_sha256_match": true
},
"collect-3d": {
"prior_engine_commit": "0f34b036313c011861dbfd5828ed45c4f7940b05",
"exact_capture_sha256_match": true
}
},
"png_previews": [
"evidence/collect-2d.png",
"evidence/collect-3d.png"
]
}
@@ -0,0 +1,115 @@
{
"format": "faset.sdk-unavailable-verification",
"version": 1,
"status": "passed",
"started_utc": "2026-09-18T03:10:58.685939+00:00",
"engine_commit": "4cb82556de31268d2bde73948dd1ff1b6c02f162",
"editor_sha256": "05e2b40c6c05282af71a03990c98c89c673c48a3cf1da0e17a59f911a947049a",
"sdk_paths_unavailable": {
"/home/emil/Desktop/Faset_Engine/CMakeLists.txt": true,
"/home/emil/Desktop/Faset_Engine/build/linux-debug/faset_editor": true,
"/home/emil/Desktop/Faset_Engine/build/linux-debug/shaders": true,
"/home/emil/Desktop/Faset_Engine/.cache/deps-src": true,
"/home/emil/Desktop/Faset_Engine/.cache/playable-release-final": true
},
"sdk_empty": true,
"mount_namespace": "mnt:[4026533743]",
"outer_mount_namespace": "mnt:[4026531832]",
"sdk_mount": [
"1374 111 0:82 / /home/emil/Desktop/Faset_Engine ro,nosuid,nodev,relatime - tmpfs faset-sdk-hidden ro,size=1024k,uid=1000,gid=1000,inode64"
],
"environment": {
"PATH": "/usr/bin:/bin",
"LANG": "C.UTF-8",
"HOME": "/tmp/faset-sdk-unavailable-fp5gnvp2/home",
"XDG_CACHE_HOME": "/tmp/faset-sdk-unavailable-fp5gnvp2/cache",
"XDG_CONFIG_HOME": "/tmp/faset-sdk-unavailable-fp5gnvp2/config",
"XDG_DATA_HOME": "/tmp/faset-sdk-unavailable-fp5gnvp2/data"
},
"timings_are_benchmark_evidence": false,
"projects": [
{
"name": "collect-2d",
"package": "/tmp/faset-playable-exports-rnbvn4tk/Faset Café 世界/collect-2d",
"player_sha256": "f7902f414ab64573a697a8f36b59e203370779990f63c63fbd90c88a7eb1397b",
"verified_package_files": 17,
"default_scene_and_assets": true,
"validation_passed": true,
"device": "NVIDIA GeForce RTX 2080 Ti",
"validation_enabled": true,
"validation_errors": 0,
"frames": 120,
"capture_sha256": "f9d74067d87c1ebf30c6db372a26d93b7285791c8cb0307a24af5adb23bf201a",
"capture_matches_final_release": true,
"status": "passed",
"trace_sdk_path_mentions": 0,
"traced_execve": [
"2514912 execve(\"/tmp/faset-playable-exports-rnbvn4tk/Faset Caf\\303\\251 \\344\\270\\226\\347\\225\\214/collect-2d/faset_player\", [\"/tmp/faset-playable-exports-rnbv\"..., \"--headless\", \"--frames\", \"120\", \"--capture\", \"/tmp/faset-sdk-unavailable-fp5gn\"..., \"--profile\", \"/tmp/faset-sdk-unavailable-fp5gn\"...], 0x7ffc06cf8bb0 /* 6 vars */) = 0"
],
"dependency_paths_outside_sdk": true,
"elf_has_rpath_or_runpath": false,
"dependencies": [
"\tlinux-vdso.so.1 (0x00007c4f9ae17000)",
"\tlibvulkan.so.1 => /usr/lib/x86_64-linux-gnu/libvulkan.so.1 (0x00007c4f9a7c5000)",
"\tlibm.so.6 => /usr/lib/x86_64-linux-gnu/libm.so.6 (0x00007c4f9a69f000)",
"\tlibstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007c4f9a200000)",
"\tlibgcc_s.so.1 => /usr/lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007c4f9a671000)",
"\tlibc.so.6 => /usr/lib/x86_64-linux-gnu/libc.so.6 (0x00007c4f99e00000)",
"\t/lib64/ld-linux-x86-64.so.2 (0x00007c4f9ae19000)"
]
},
{
"name": "collect-3d",
"package": "/tmp/faset-playable-exports-rnbvn4tk/Faset Café 世界/collect-3d",
"player_sha256": "5537942ff7cd999de044168420b730c772a6f21c3cf81ece389e9495c9eae974",
"verified_package_files": 22,
"default_scene_and_assets": true,
"validation_passed": true,
"device": "NVIDIA GeForce RTX 2080 Ti",
"validation_enabled": true,
"validation_errors": 0,
"frames": 120,
"capture_sha256": "914060401de93d08b33bf09a1e210859e491a0060c331e5e2044f517356f4980",
"capture_matches_final_release": true,
"status": "passed",
"trace_sdk_path_mentions": 0,
"traced_execve": [
"2514989 execve(\"/tmp/faset-playable-exports-rnbvn4tk/Faset Caf\\303\\251 \\344\\270\\226\\347\\225\\214/collect-3d/faset_player\", [\"/tmp/faset-playable-exports-rnbv\"..., \"--headless\", \"--frames\", \"120\", \"--capture\", \"/tmp/faset-sdk-unavailable-fp5gn\"..., \"--profile\", \"/tmp/faset-sdk-unavailable-fp5gn\"...], 0x7ffe821118e0 /* 6 vars */) = 0"
],
"dependency_paths_outside_sdk": true,
"elf_has_rpath_or_runpath": false,
"dependencies": [
"\tlinux-vdso.so.1 (0x000071bca491d000)",
"\tlibvulkan.so.1 => /usr/lib/x86_64-linux-gnu/libvulkan.so.1 (0x000071bca42ca000)",
"\tlibm.so.6 => /usr/lib/x86_64-linux-gnu/libm.so.6 (0x000071bca41a4000)",
"\tlibstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x000071bca3e00000)",
"\tlibgcc_s.so.1 => /usr/lib/x86_64-linux-gnu/libgcc_s.so.1 (0x000071bca4176000)",
"\tlibc.so.6 => /usr/lib/x86_64-linux-gnu/libc.so.6 (0x000071bca3a00000)",
"\t/lib64/ld-linux-x86-64.so.2 (0x000071bca491f000)"
]
}
],
"finished_utc": "2026-09-18T03:11:01.278406+00:00",
"outer_sdk_unchanged_after_namespace": true,
"outer_editor_sha256_after": "05e2b40c6c05282af71a03990c98c89c673c48a3cf1da0e17a59f911a947049a",
"retained_evidence_hashes": {
"collect-2d-dependencies.json": "c3882b5fec209be8e140b3a47bc4cd6e4c644baca4ce37308fb9420076fdd094",
"collect-2d-elf.json": "aa615e898a2ec9f7d68491d13f6bb5742a566ded87ce0d6c9c0ebe8fbe342de3",
"collect-2d-file-trace.log": "3fe847b2f8f8de66aeb04db69d02ba1b5bb311ffd64a057d405b527daa2e221d",
"collect-2d-profile.json": "5ab9c3e01d55e5f5a51d4e7d7d53bc1e39d3cac1d98544de246c8e1e05ef8a80",
"collect-2d-run.json": "b382c0582482d98c4c184949cb40d1c60939e18f772717b9c3d22f4ec94adba6",
"collect-2d-validate.json": "4fdf30c0fda6a275984a746b787f61c1ea50952558706da2232e97ca684a7bd1",
"collect-2d.ppm": "f9d74067d87c1ebf30c6db372a26d93b7285791c8cb0307a24af5adb23bf201a",
"collect-3d-dependencies.json": "0839c22cd4269a9461106b6f64c9d7255378639f571bec892ed189f0803cdfe6",
"collect-3d-elf.json": "c0f212cfec469cf493d517108f7859638b5aa4529216f42097170bfa0dbd49ba",
"collect-3d-file-trace.log": "3df4929e94c9b21e69f8a4dc3aed5d7182c60606af52840c9f945531cb54d6d0",
"collect-3d-profile.json": "e461b8c882f7ba487a0dc0704d20c96eafcbfe51785f50796bd70d611896ba27",
"collect-3d-run.json": "2a4703d596c1a3aa5450b205ee382cfed9578884bf63a965fde04e6e672c5ca8",
"collect-3d-validate.json": "15f128930142c0fc233eeb2b8e3b2a4d5d80e9e578f54f78538e6ce74c93d4cd",
"collect-3d.ppm": "914060401de93d08b33bf09a1e210859e491a0060c331e5e2044f517356f4980",
"inner.py": "a24ef1b36550a8f1944bda95b13c90eca5d2ddd81f49bfddbceba291c75d3857",
"outer-mount-namespace.txt": "b38992f03c046722594e95d6dcdbb4fb1b75a0f4f0156c26cb2059b1bafecdd4",
"prior.json": "d0d1ea7b6c4ffc8e6d1ac7dfe0e8dcfa1875780abd8eeb8377621db810c84883",
"run.sh": "dad0a2d008508eb2b2f2e0b4d7b86a6f38e3de1bdd6f0272d4d99bfcde201489"
}
}
@@ -0,0 +1,318 @@
{
"recorded_date": "2026-09-18",
"profiles": "Ubuntu 26.04 x86-64; Clang 21.1.8; NVIDIA RTX 2080 Ti 595.84; see docs/TOOLCHAINS.md",
"checks": [
{
"source_commit": "4cb82556de31268d2bde73948dd1ff1b6c02f162",
"description": "Full Debug with optional ImGui diagnostics",
"raw_log_sha256": "4f44fa2bc6b9cc560f89d0000b63cf87e200da237b432de87c5b64f299dc58a9",
"tests": [
{
"name": "authoring",
"status": "passed",
"seconds": 0.05
},
{
"name": "runtime_contracts",
"status": "passed",
"seconds": 0.12
},
{
"name": "assets_pipeline",
"status": "passed",
"seconds": 0.12
},
{
"name": "assets_blender_bundle",
"status": "passed",
"seconds": 0.07
},
{
"name": "render_graph",
"status": "passed",
"seconds": 0.01
},
{
"name": "render_offscreen",
"status": "passed",
"seconds": 0.35
},
{
"name": "render_sprite_alpha",
"status": "passed",
"seconds": 0.31
},
{
"name": "render_shader_reload",
"status": "passed",
"seconds": 2.47
},
{
"name": "render_window_lifecycle",
"status": "skipped",
"seconds": 4.02
},
{
"name": "player_scene_contracts",
"status": "passed",
"seconds": 0.01
},
{
"name": "player_shutdown_diagnostics",
"status": "passed",
"seconds": 0.37
},
{
"name": "editor_mcp",
"status": "passed",
"seconds": 0.02
},
{
"name": "process_and_cook",
"status": "passed",
"seconds": 0.29
},
{
"name": "build_schema_publication",
"status": "passed",
"seconds": 5.25
},
{
"name": "editor_plugins",
"status": "passed",
"seconds": 0.02
},
{
"name": "editor_session_settings",
"status": "passed",
"seconds": 0.01
},
{
"name": "ui_widgets",
"status": "passed",
"seconds": 0.12
},
{
"name": "ui_render",
"status": "passed",
"seconds": 0.43
},
{
"name": "editor_ui_import_conflicts",
"status": "passed",
"seconds": 0.71
},
{
"name": "editor_ui_project_settings",
"status": "passed",
"seconds": 0.83
},
{
"name": "editor_ui_reload",
"status": "passed",
"seconds": 3.9
},
{
"name": "editor_ui_launcher",
"status": "passed",
"seconds": 0.6
},
{
"name": "editor_ui_templates",
"status": "passed",
"seconds": 2.01
},
{
"name": "editor_ui_gizmos",
"status": "passed",
"seconds": 0.78
},
{
"name": "editor_ui_authoring",
"status": "passed",
"seconds": 1.2
},
{
"name": "editor_mcp_stdio",
"status": "passed",
"seconds": 0.28
},
{
"name": "editor_gui_mcp",
"status": "passed",
"seconds": 4.39
},
{
"name": "core",
"status": "passed",
"seconds": 0.1
},
{
"name": "tutorial_moving",
"status": "passed",
"seconds": 0.02
},
{
"name": "tutorial_following",
"status": "passed",
"seconds": 0.01
},
{
"name": "tutorial_spawning",
"status": "passed",
"seconds": 0.02
},
{
"name": "tutorial_physics",
"status": "passed",
"seconds": 0.06
},
{
"name": "playable_2d",
"status": "passed",
"seconds": 0.4
},
{
"name": "playable_3d",
"status": "passed",
"seconds": 0.88
},
{
"name": "editor_debug_overlay",
"status": "passed",
"seconds": 0.35
}
],
"counts": {
"passed": 34,
"skipped": 1,
"failed": 0
}
},
{
"source_commit": "4cb82556de31268d2bde73948dd1ff1b6c02f162",
"description": "Targeted ASan/UBSan after source-location correction",
"raw_log_sha256": "955813d41b1d28cf53df0af7bfe42d3b05009a1e00cfa266d75b8955f08003e1",
"tests": [
{
"name": "assets_pipeline",
"status": "passed",
"seconds": 0.59
},
{
"name": "process_and_cook",
"status": "passed",
"seconds": 0.54
}
],
"counts": {
"passed": 2,
"skipped": 0,
"failed": 0
}
},
{
"source_commit": "0f34b036313c011861dbfd5828ed45c4f7940b05",
"description": "Complete ASan/UBSan suite before the bounded source-location correction",
"raw_log_sha256": "fc34eb7195105c1cc7755eafa20580cdc23022c4edff86fe2f0571cb6cac8ba8",
"tests": [
{
"name": "authoring",
"status": "passed",
"seconds": 0.18
},
{
"name": "runtime_contracts",
"status": "passed",
"seconds": 0.76
},
{
"name": "assets_pipeline",
"status": "passed",
"seconds": 0.44
},
{
"name": "assets_blender_bundle",
"status": "passed",
"seconds": 0.07
},
{
"name": "editor_mcp",
"status": "passed",
"seconds": 0.08
},
{
"name": "process_and_cook",
"status": "passed",
"seconds": 0.53
},
{
"name": "build_schema_publication",
"status": "passed",
"seconds": 30.02
},
{
"name": "editor_plugins",
"status": "passed",
"seconds": 0.12
},
{
"name": "editor_session_settings",
"status": "passed",
"seconds": 0.09
},
{
"name": "ui_widgets",
"status": "passed",
"seconds": 0.35
},
{
"name": "editor_mcp_stdio",
"status": "passed",
"seconds": 0.58
},
{
"name": "core",
"status": "passed",
"seconds": 0.26
},
{
"name": "tutorial_moving",
"status": "passed",
"seconds": 0.14
},
{
"name": "tutorial_following",
"status": "passed",
"seconds": 0.06
},
{
"name": "tutorial_spawning",
"status": "passed",
"seconds": 0.14
},
{
"name": "tutorial_physics",
"status": "passed",
"seconds": 0.39
},
{
"name": "playable_2d",
"status": "passed",
"seconds": 2.16
},
{
"name": "playable_3d",
"status": "passed",
"seconds": 4.64
}
],
"counts": {
"passed": 18,
"skipped": 0,
"failed": 0
}
}
],
"skip_note": "The Wayland compositor declined programmatic restore. The XWayland lifecycle record is separate; this skipped invocation is not a passed native Wayland check."
}
@@ -15,14 +15,14 @@ Live Vulkan allocations stayed at 15,750,288 bytes (2D) and 15,787,008 bytes (3D
`render_call` includes GPU waits and synchronous readback; it is not CPU utilization. GPU timestamps cover submitted rendering. Frame timings exclude profile bookkeeping and final file writes. Synthetic 1/60-second simulation ticks run as fast as the offscreen loop allows. The resulting numbers are not display FPS or a real-time gameplay pacing test. Small sample scenes, one GPU, 240 frames and a static camera cannot establish scalability, a memory-leak guarantee, or broad performance claims. The imported 3D material also emits the recorded warning about unsupported material features in its manifest.
Proposed P1 budgets for these exact scenes on this reference-class Linux host, at the same resolution and validation/readback settings:
Initial P1 tracking budgets for these exact scenes on this reference-class Linux host, at the same resolution and validation/readback settings:
- Measured frame p95 ≤ 4 ms; GPU p95 ≤ 1 ms; readback p95 ≤ 1 ms.
- Simulation and snapshot p95 ≤ 0.5 ms each.
- Explicit live Vulkan memory ≤ 20 MiB, with no growth after warmup over a future 3,000-frame resource-lifecycle run.
- Startup from `main()` ≤ 500 ms for these tiny packages.
These initial thresholds leave headroom above the observed values. They are **proposed**, not enforced acceptance criteria. P1 should retain cold-start results separately, run repeated sessions, measure editor input latency and larger content, and collect independent Windows hardware baselines before adopting release gates.
These initial thresholds leave headroom above the observed values. They are tracking budgets for P1, not enforced MVP acceptance criteria or engine-wide guarantees. P1 should retain cold-start results separately, run repeated sessions, measure editor input latency and larger content, and collect independent Windows hardware baselines before adopting release gates.
Reproduce export validation from the repository with `python tools/verify_playable_exports.py --editor build/linux-debug/faset_editor --output <new-empty-directory>`. Run each retained standalone Player with `--headless --frames 240 --profile <output.json>` to repeat the longer measurement. A new run builds current sources and produces new immutable generations; use the stored hashes to distinguish it from this record.
+55
View File
@@ -0,0 +1,55 @@
# Lua module validation
Local implementation checks, 2026-09-18. These results supplement, not replace,
the earlier MVP acceptance record. Toolchain: Linux x86-64, GCC 13.3, CMake 4.4.3,
Ninja 1.13.2; pinned Lua 5.4.9.
## Observed results
| Configuration | Result |
|---|---|
| Lua enabled, renderer/editor UI disabled | 20/20 CTest tests passed |
| Lua disabled, renderer/editor UI disabled | 18/18 CTest tests passed |
| AddressSanitizer + UndefinedBehaviorSanitizer, Lua suites | 3/3 tests passed |
| Renderer-linked native Player and SchemaExporter | Built successfully; CPU Lua CLI contracts passed |
| Lua-only project without project C++ files | Empty native adapter built; sample validated; exactly two Lua schemas exported |
| Native Editor and Editor UI library | Compiled and linked; Editor `--help` ran |
| Manual | MkDocs strict build passed |
The Lua tests exercise lifecycle ordering, per-instance fields/state, VM ownership,
stale/cross-world handles, deferred structural operations, native physics contacts,
`require`, invalid schemas, CPU/memory limits and the shipped example scene. Additional
safety cases cover deep/cyclic JSON, repeated-string/key expansion, structural queue
limits, protected metatables, repeated OOM and reclamation of a failing instance.
BuildService tests exercise source snapshots, fingerprints, changes during a build,
Lua-only projects, export contents/notices, and switching back to Lua-free games.
Their native build/export fixture is a stand-in, not a graphical Player execution.
## Reproduce the CPU suite
```sh
cmake -S . -B build/lua-check -G Ninja -DCMAKE_BUILD_TYPE=Debug \
-DFASET_ENABLE_LUA=ON -DFASET_BUILD_RENDERER=OFF -DFASET_BUILD_EDITOR=OFF
cmake --build build/lua-check --parallel
ctest --test-dir build/lua-check --output-on-failure
```
Use a separate build directory with `-DFASET_ENABLE_LUA=OFF` for the optional-module
check. For sanitizers, configure with `-DFASET_SANITIZERS=ON`, build the
`faset_lua_tests`, `faset_lua_safety_tests`, and `faset_schema_exporter` targets, then
run `ctest --test-dir <build> --output-on-failure -R '^lua_'`.
## Not verified here
- Windows compilation or execution of the new module.
- Graphical/window interaction and real-time Lua reload in a running rendered game.
`lua_player_reload` is provided as a GPU-labelled integration test for an equipped host.
- A complete real Release export launched on a separate machine.
- LeakSanitizer: this execution environment uses tracing incompatible with its
process inspection, so sanitizer runs used `ASAN_OPTIONS=detect_leaks=0` and
`UBSAN_OPTIONS=halt_on_error=1`. Address/undefined-behavior checks stayed enabled.
The renderer-linked CPU checks used the existing Vulkan loader, repo-pinned Vulkan
headers and cached Slang, with SDL X11/Wayland disabled. No system graphics packages
were installed. This proves linkage and CPU validation, not graphics compatibility.
+92
View File
@@ -0,0 +1,92 @@
# MVP acceptance dossier
Accepted engine source: **`4cb82556de31268d2bde73948dd1ff1b6c02f162`**. Recorded 18 September 2026. Release tag: **`v0.1.0-mvp`**, including the final documentation/evidence commit.
**Status: the C++ MVP is accepted for the recorded Linux and Windows profiles.** This dossier maps [PLAN M0M9](../../PLAN.md) to implemented behavior and bounded evidence. The final publication changes documentation and the research viewer, not the tested engine/gameplay code. Test names below are CTest names, not claims of additional runs. Acceptance does not certify untested devices or turn the compatibility coverage limits below into passing checks.
## Evidence and revision boundaries
- **Final candidate Linux:** the integrated suite has **34 passed, 1 skipped, 0 failed** out of 35 tests, with optional ImGui diagnostics enabled. The skip is native Wayland programmatic restore. Both exact-candidate Release games also passed standalone relocation/validation and 120 frames each. See the [final Linux record](final-linux-2026-09-18/README.md) and [test outcomes](final-linux-2026-09-18/tests.json). The earlier XWayland lifecycle scenario is separate.
- **Final candidate native/manual CI:** [run 35301244366](https://github.com/emil28092005/Faset_Engine/actions/runs/35301244366) passed. This is separate from the full Windows graphics/export workflow.
- **Sanitizers:** the [recorded configurations](final-linux-2026-09-18/tests.json) show complete `0f34b03` ASan/UBSan **18/18** and final-candidate asset/cook **2/2** after the source-relocation correction. This is not a claim that the complete sanitizer suite was repeated on `4cb8255`.
- **Exact earlier Linux candidate:** [checkpoint 5 evidence](checkpoint5-linux-2026-09-18/README.md) records clean offline build, first project launch, standalone games, recovery and real Blender reimport at `0f34b036313c011861dbfd5828ed45c4f7940b05`. The Blender report separately identifies the updated verification harness. These reports retain their original provenance.
- **Final source Windows:** [run 35301244334](https://github.com/emil28092005/Faset_Engine/actions/runs/35301244334) passed the fresh Editor/Player build, all **35 tests with no skips**, real BuildService Release exports/incremental rebuilding, and both checked-in games after standalone Unicode relocation. The [Windows evidence](windows-software-vulkan-2026-09-18/README.md) separates this exact `4cb8255` result from the preceding successful `0f34b03` run. SwiftShader is software Vulkan; the Khronos validation layer was unavailable.
## Criterion map
### M0 — reproducible foundation
CMake separates Core, Runtime, Editor, Player and SchemaExporter; gameplay is static, and Player does not link Editor/MCP/import services. Presets, compiler/SDK/runtime requirements, dependency hashes, Slang and third-party notices are recorded in [toolchains](../TOOLCHAINS.md), [dependency pins](../../dependencies.lock.json) and [target definitions](../../cmake/Player.cmake). Core tests cover IDs, hashing, atomic IO, Unicode paths and subprocess behavior.
Evidence: `core`, `process_and_cook`, native CI, and the [clean offline build](checkpoint5-linux-2026-09-18/offline.json): committed `0f34b03`, empty build directory, external network disabled, prepared tools/dependencies, 20 CPU tests. A prepared offline build does not establish a fresh installation of every system prerequisite. Windows records the clean checkout, pinned tools, configure/build commands and native test execution separately.
### M1 — documents, metadata and commands
Persistent source IDs are separate from runtime handles. Typed metadata describes stable fields, constraints and versions; unknown data survives round-trip. Authoring transactions validate candidates before publication and share revision conflicts, retry keys, Undo/Redo, save and recovery. Explicit declarative migrations preserve IDs and unknown fields; missing/manual/incompatible rules fail without partial edits.
Evidence: `authoring`, `build_schema_publication`, `editor_session_settings`, `editor_mcp`, and migration actions in `editor_ui_authoring`; [authoring fixtures](../../tests/authoring_tests.cpp) and [metadata publication fixtures](../../tests/build_schema_tests.cpp). Opening older data does not migrate it automatically. Changing field units requires reviewing separately stored instance overrides, as described in the [schema API guide](../manual/scripting/api.md).
### M2 — platform and baseline graphics
SDL window/input/text/DPI feeds a direct Vulkan 1.3 backend with capability checks, explicit synchronization and resource lifetime handling. The serial Render Graph declares reads/writes, barriers and optional GPU labels. Pinned Slang produces SPIR-V and normalized reflection; incompatible or failed shader reload preserves the working pipeline. Baseline rendering includes sprite transparency/layers, static textured meshes, basic PBR, directional shadows, CPU culling and timing/resource counters.
Evidence: `render_graph`, `render_offscreen`, `render_sprite_alpha`, `render_shader_reload`, `render_window_lifecycle`, and `editor_debug_overlay`; [shader reload regression](../../tests/render_reload_tests.cpp) and [native window evidence](native-window-linux-2026-09-18.json). Shipping packages contain SPIR-V rather than requiring Slang. Native Wayland restore and physical-device limits are stated below.
### M3 — runtime, C++, physics and Player
EnTT-backed runtime APIs preserve source identity and validate handles. Deferred structural changes, input/fixed/physics/event phases, bounded catch-up, interpolation and lifecycle callbacks have contract tests. Box2D/Box3D support the demo bodies, layers/events, grounding and debug shapes. A separate statically linked Player receives an immutable resolved authoring snapshot, including unsaved edits; Play/Stop/pause/step do not write simulation state into the document. Failed C++ or metadata publication keeps the previous build and reports stale status.
Evidence: `runtime_contracts`, `player_scene_contracts`, `player_shutdown_diagnostics`, four `tutorial_*` tests, `playable_2d`, `playable_3d`, `build_schema_publication`, and the [seven recovery scenarios](checkpoint5-linux-2026-09-18/recovery.json). The supported physics profile remains root-level box bodies, not arbitrary mesh-collider cooking.
### M4 — retained editor UI
The main UI uses retained IDs, layout/styles, clipping/scroll, keyboard focus, editing/selection, drag/drop, one-window docking and dynamic metadata fields. One gesture creates one authoring Undo. FreeType/HarfBuzz and UTF-8 text support Cyrillic; focus reveals long/nested lists at 1×/2×. Layout/style reload validates candidates and preserves working state. Optional F12 ImGui diagnostics displays real renderer counters without replacing the main UI.
Evidence: `ui_widgets`, `ui_render`, `editor_ui_reload`, `editor_ui_gizmos`, `editor_ui_authoring`, `editor_debug_overlay`; [widget regression](../../tests/ui_tests.cpp) covers composition events, clipboard callbacks, DPI rasterization/hit testing and scroll/focus behavior. These deterministic events do **not** establish physical OS IME or mixed-monitor behavior.
### M5 — resources and Blender
The importer owns cooked geometry/material/texture data, persists source identity/settings, hashes inputs/dependencies/toolchain/profile and publishes complete generations atomically. Ordinary GLB and PNG/JPEG work without Blender. Freshness is visible through UI/MCP; stale sources cannot silently pass cook/export. Removal review pins both candidate and active generations; failed/cancelled imports retain the last good result. The final relocation correction updates logical source and payload together while keeping immutable generations and old pointers readable.
Evidence: `assets_pipeline`, `assets_blender_bundle`, `editor_ui_import_conflicts`; [asset fixtures](../../tests/assets_pipeline.cpp) cover cache rebuild, stable/unstable rename, removal, failure/cancel, freshness, moved PNG/bundle/external glTF and legacy pointers. The [real Blender report](checkpoint5-linux-2026-09-18/blender.json) shows unmodified Blender 4.5.3 updating two live Editor instances while preserving placement, tint, physics, opaque gameplay and revision. It used `0f34b03` binaries; relocation coverage is from the subsequent final-candidate tests. The [documented import profile](../manual/editor/assets.md) limits material/geometry transfer.
### M6 — scene editing and reusable scenes
Scene Tree, Inspector, Assets, viewport selection/gizmos, Console, project/simulation settings and Save/Play/Build are real authoring controls. Templates use stable nested instance/object/component addresses, sparse overrides, local additions/suppression and restricted local/world reparenting. Origin, Revert, source navigation and conflicts are visible. Schema changes invalidate resolved previews even without a document revision change.
Evidence: `editor_ui_launcher`, `editor_ui_project_settings`, `editor_ui_templates`, `editor_ui_gizmos`, `editor_ui_authoring`. The [template workflow](../../tests/editor_ui_templates.cpp) saves through UI, opens a new Session and compares nested IDs, origins and values. Cache clearing/reimport is covered separately by `assets_pipeline`. [First launch](checkpoint5-linux-2026-09-18/first-run.json) follows the Manual on the clean `0f34b03` Linux build. The [Windows record](windows-software-vulkan-2026-09-18/README.md) ties its fresh source build to actual launcher Create/Open and native Editor/MCP tests; it does not claim a retail installer or a human usability study.
### M7 — editor MCP and extensions
GUI and MCP share commands, canonical documents, revisions and history. Headless authoring/build, structured errors and cancellable jobs are separate from GPU screenshots. MCP is confined to editor services; Player and SchemaExporter contain no runtime-world MCP API. Startup DLL/SO extensions use exact SDK/build compatibility, dependencies and registration ownership.
Evidence: `editor_mcp`, `editor_mcp_stdio`, `editor_gui_mcp`, `editor_plugins`; [GUI/stdio regression](../../tests/editor_gui_mcp_test.py) covers actual captures and conflicting edits/Undo; [plugin fixtures](../../tests/plugin_tests.cpp) cover the runtime-component/editor-panel package, compatibility rejection and unknown-data preservation. This is the supported protocol/workflow scope, not certification of every MCP client.
### M8 — standalone games and export
BuildService validates metadata, builds C++, cooks resources/shaders, assembles a manifest/notices and validates the standalone Player before publishing. Editor/MCP/Blender/schema helpers/compiler are not required by the exported game. Both checked-in C++ games exercise controls, physics, pickups, a gate/exit and reset; the 3D game uses the Blender arch.
Evidence: `process_and_cook`, `build_schema_publication`, `playable_2d`, `playable_3d`, shader/template/Blender regressions, and [exact `4cb8255` Linux exports](final-linux-2026-09-18/playable-exports.json). Both packages ran 120 frames after Unicode-path relocation with source projects hidden and zero errors under active Khronos validation. [2D](final-linux-2026-09-18/collect-2d-manifest.json) and [3D](final-linux-2026-09-18/collect-3d-manifest.json) manifests retain package hashes. An additional [Linux namespace check](final-linux-2026-09-18/sdk-unavailable.json) hid the entire SDK/build/tool tree and repeated validation/120 frames with identical captures. [Final Windows exports](windows-software-vulkan-2026-09-18/README.md) passed the same project relocation checks on SwiftShader. **All four dimension/platform combinations passed.** The entire-SDK hiding check was Linux-only; it is not silently attributed to Windows.
### M9 — final acceptance
Existing evidence covers shared GUI/MCP authoring, revision conflicts, Undo/Redo, interrupted Editor recovery and failed save/import/build/Player startup. The [Release baseline](linux-release-2026-09-18/README.md) records scene/hardware/settings, startup and CPU/GPU/readback/memory data; the [implementation log](../IMPLEMENTATION.md) records build/import iteration measurements. Its scoped thresholds serve as initial P1 tracking budgets for the recorded scenes/reference host, not engine-wide guarantees or enforced MVP performance gates. Those measurements retain their original revision and workload limits and are not a benchmark of the final candidate or every platform.
The native build/export gates, first-project workflows and recovery checks are complete for the profiles below. PLAN and the Manual record current capabilities, with compatibility coverage limits retained explicitly. The first release is a source MVP for these small projects, not a claim of production readiness for arbitrary games.
## Final disposition
- **LINUX-EXPORT-4CB — passed:** [final report](final-linux-2026-09-18/README.md), source clean at `4cb8255` through completion; both Release packages validated and rendered 120 frames after Unicode relocation with source paths unavailable. RTX 2080 Ti, Khronos validation active, zero errors. Package hashes and per-game counters are linked from that record; the earlier `0f34b03` reports retain their provenance.
- **WINDOWS-TEST-4CB — passed:** [run 35301244334](https://github.com/emil28092005/Faset_Engine/actions/runs/35301244334), fresh build with optional diagnostics, 35/35 tests, no failures/skips. Exact outcomes and native UI/window observations are retained in the [Windows dossier](windows-software-vulkan-2026-09-18/README.md).
- **WINDOWS-EXPORT-4CB — passed:** both Release games, package hash checks, Unicode relocation, disposable source projects unavailable, 120 rendered frames each. Required system/runtime libraries and the software Vulkan driver remain part of the target environment. No physical Windows GPU or active Khronos layer is claimed.
- **FIRST-PROJECT — passed within the developer setup profile:** clean Linux SDK plus the Manual's create-project command; fresh Windows checkout/toolchain configure/build followed by actual Create/Open, native window and GUI/MCP execution. System prerequisites were prepared on Linux or provided/prepared by the Windows runner. No graphical retail installer was planned or tested.
- **RELEASE — `v0.1.0-mvp`:** M0M9 are closed for the documented profiles. Remaining native IME, mixed-monitor, native Wayland restore and additional hardware-driver coverage stay visible below; Lua and subsequent feature work remain in P1P6. The UI references guide appearance only; architecture, PLAN and working authoring contracts define behavior.
## Coverage limits that must remain visible
- **Physical OS IME:** synthetic preedit/commit and SDL input-area checks passed; an actual system IME/candidate window/composition workflow was not exercised. Clipboard checks do not substitute for it.
- **Physical mixed-monitor DPI:** tests cover 1×/2× layout, glyph density, input coordinates, focus and live-scale state preservation; moving a native window between actual monitors with different scales was not tested.
- **Native Wayland restore:** the compositor declined the programmatic restore scenario, which is explicitly skipped. XWayland passing is useful alternative-backend evidence, not native Wayland completion.
- **Platform and performance scope:** Linux hardware results do not certify physical Windows GPUs. Software-driver functional coverage does not establish hardware performance. Small fixed scenes and static frame profiles do not establish large-project responsiveness.
These are verification limits, not proof that the feature is broken; they also cannot be silently counted as verified. The supported MVP profile remains static glTF/UV0/basic PBR, root-level box physics, one editor window and C++ gameplay. Lua, advanced rendering/animation, live link, variants and C++ hot replacement remain outside this acceptance scope as specified by PLAN.
@@ -0,0 +1,24 @@
# Windows software Vulkan acceptance
[The final source record](final-source/evidence.json) documents a successful fresh-checkout build of `4cb82556de31268d2bde73948dd1ff1b6c02f162` in [GitHub Actions run 35301244334](https://github.com/emil28092005/Faset_Engine/actions/runs/35301244334). The hosted Windows Server 2025 image supplied Visual Studio tools and Clang 20.1.8 (`clang-cl`). The job prepared the pinned Vulkan loader/SwiftShader toolchain, fetched the verified Slang compiler, configured the Editor with `FASET_DEBUG_IMGUI=ON`, then built the Editor, Player and tests. All **35 CTests passed**, with no failures or skips.
The [test summary](final-source/tests.json) preserves the concrete acceptance cases and selected output:
- `editor_ui_launcher`: Create/Open, Unicode project paths, validation, recent projects, directory browsing and keyboard navigation through the instrumented retained UI. This is developer setup and first-project evidence, not a retail-installer test.
- `render_window_lifecycle`: native SDL window resize, Unicode clipboard roundtrip, text-input rectangle conversion, 12 fresh frames while minimized, and restore. Real OS IME composition was not exercised.
- `editor_gui_mcp`: a visible native Editor plus MCP stdio shared authoring, conflict/Undo handling and 12 fresh PNG captures without loss of responsiveness.
- `editor_debug_overlay`: the optional ImGui font/triangle rendering, F12 toggling and pointer-event isolation, including gestures crossing the overlay boundary.
Both the BuildService export/incremental-build integration and [the checked-in playable project verifier](final-source/playable-report.json) passed. Each game was built in **Release** from its own C++ scripts, packaged, checked against its manifest, moved outside the engine tree into a `Faset Café 世界` path, and run from an unrelated working directory with its disposable source project unavailable. Each standalone Player passed CPU scene validation and rendered 120 frames at 1280×720. The 3D case includes a real imported Blender arch bundle. Exact source input hashes, generations, packaged file hashes, process results and captures are retained.
The [toolchain](final-source/toolchain.json) and [probe](final-source/probe.json) identify **SwiftShader Vulkan 1.3, a CPU device**. The Khronos validation layer was absent (`validation_enabled=false`); zero reported validation errors must not be read as validation-layer coverage. These records establish functional behavior on a hosted Windows VM, not physical desktop GPU performance, a manually operated desktop, or a large-workload benchmark. Timing fields retained in the original verifier report are diagnostic data only.
Original detailed job logs and raw frame profiles are available in the linked CI artifact while its retention period lasts. This folder keeps the compact acceptance evidence and hashes of the original CTest/CI logs.
Git stores these JSON records with LF line endings. Each retained-file `sha256` and
`size` describes those repository bytes; where the original Windows artifact used
CRLF, `original_artifact_sha256` and `original_artifact_size` preserve that separate
byte identity. The documentation correction after the first MVP tag records this
normalization explicitly; it does not change the test outcomes or packaged games.
The earlier [checkpoint 5 record](checkpoint5/evidence.json) preserves the independently successful run of `0f34b036313c011861dbfd5828ed45c4f7940b05`. The final source run additionally covers the relocated importer metadata fix through `assets_pipeline`, followed by the complete export matrix again. [2D capture](final-source/collect-2d.png) · [3D capture](final-source/collect-3d.png).
@@ -0,0 +1,148 @@
{
"asset_generations": {},
"build_fingerprint": "1ce6b1c87ae16d24ae0df4da94b379805d976d550c31f3540cad9f64829542b7",
"configuration": "Release",
"executable": "faset_player.exe",
"files": [
{
"path": "faset_player.exe",
"sha256": "a9616a9547c599ecc27b88a3d5807c5c0a7daa1cd7ec7663743d286411520809",
"size": 4278272
},
{
"path": "Notices/box2d/LICENSE",
"sha256": "68a3e676d7e94093b102d5cba0d4e04af812040d6f230c3db67a6664574e43d2",
"size": 1067
},
{
"path": "Notices/box3d/LICENSE",
"sha256": "da5e31a26bf3cfd5ba5c96d6823e480128c81e76c107ef9d3ee5d94789184b90",
"size": 1067
},
{
"path": "Notices/dependencies.json",
"sha256": "a54639ad2d9ad13c2e5f1ec90d6775f5dfc493656789b78c7e44debe2a378fdc",
"size": 2206
},
{
"path": "Notices/entt/LICENSE",
"sha256": "0785027ce472d7c61f05fba664a1d3ba6639c1593ced351ad9e4bed868765d99",
"size": 1097
},
{
"path": "Notices/Faset-NOTICE.txt",
"sha256": "30c2e7e80f5153b31ab57675e07246aef9165965d64e36022b426a26449ece3f",
"size": 204
},
{
"path": "Notices/json/LICENSE.MIT",
"sha256": "46a65cffd1ea955132d95a8dd921640714a8d6b537d2e4e482d31145ae95b603",
"size": 1076
},
{
"path": "Notices/sdl3/LICENSE.txt",
"sha256": "97f35b302b361680ec1e891e95d2d52097bb95abff361434916d99dc1305f127",
"size": 884
},
{
"path": "Notices/stb/LICENSE",
"sha256": "bebfe904b14301657e4e5d655c811d51fd31b97c455b9cc2d8600d6bac6cff63",
"size": 2510
},
{
"path": "README.txt",
"sha256": "c62b83aa59e8eec3b3508f9e9ad5e78eb4554a2369242c830debe8d5ffbab924",
"size": 229
},
{
"path": "scene.fscene",
"sha256": "0d7b221abc1cae5e9f1d04357c684ac6993f5878d634b4b950eec66dd8e55b2a",
"size": 6214
},
{
"path": "shaders/fragmentMain.reflection.json",
"sha256": "ba43159da6ef0e8c305ba9a88414551ec273c487cdc7d324403998ba2d296f10",
"size": 2777
},
{
"path": "shaders/fragmentMain.spv",
"sha256": "f5c4f289917ecab5d00d543c053aac1d10e6cca311fd172daf06d315160a3505",
"size": 7436
},
{
"path": "shaders/shadowMain.reflection.json",
"sha256": "3f785e549f40abad75115d5dfc16b409f81bbb0eced6281c6eda33c2eb439249",
"size": 2772
},
{
"path": "shaders/shadowMain.spv",
"sha256": "7643b4d688492b5ee923b9606f0b0e70343ca05fa67673838206119a6f86d8d8",
"size": 784
},
{
"path": "shaders/vertexMain.reflection.json",
"sha256": "4459cc3113377b7fbc41b880529cf5ad474ad07d299e033eb9169ac7849894cf",
"size": 2768
},
{
"path": "shaders/vertexMain.spv",
"sha256": "1ad2631c35d654f48166321ae43d4165043e1b919b14f1dc61caf97b1ada0898",
"size": 1224
},
{
"path": "Windows-Runtime.txt",
"sha256": "1c53b7b6890d4a10408acfa7a27760ca1b176bb43dba9c25f3e5d2ac2d7d15db",
"size": 227
}
],
"format": "faset.export",
"generation": "16e0f91d-c1ab-4c66-b4d7-3dc88459caa9",
"platform": "windows",
"prerequisites": [
"Windows x64",
"Vulkan 1.3 driver",
"Microsoft Visual C++ x64 Redistributable (Visual Studio 2022 or newer)"
],
"renderer_profile": {
"api": "Vulkan 1.3",
"materials": [
"base-color factor and texture",
"metallic and roughness factors"
],
"required_features": [
"dynamicRendering",
"synchronization2"
],
"shadow_map": {
"resolution": 1024,
"world_extent": 40
},
"texture_sampling": "linear clamp, one mip level",
"unsupported_material_features": [
"normal maps",
"metallic-roughness maps",
"emissive and occlusion maps",
"alpha mode selection",
"unlit mode",
"per-material face culling"
]
},
"scene_hash": "fdfa1c49cf78a1cf52cd41b201c35bb0b5f852c90b7626b2a7f17da3e2e3e24c",
"simulation": {
"fixed_delta": 0.016666666666666666,
"gravity": [
0,
-9.81,
0
],
"max_catch_up_ticks": 4,
"physics_substeps": 4
},
"units": {
"angle": "radian",
"coordinates": "right-handed Y-up",
"distance": "metre"
},
"validation_log": "{\"dimension\":2,\"validated\":true}\r\n",
"version": 1
}
@@ -0,0 +1,18 @@
{
"arguments": [
"C:\\Users\\runneradmin\\AppData\\Local\\Temp\\faset-playable-exports-do2lq63x\\Faset Café 世界\\collect-2d\\faset_player.exe",
"--headless",
"--frames",
"120",
"--capture",
"C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-do2lq63x\\Faset Café 世界\\collect-2d\\verification.ppm",
"--profile",
"C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-do2lq63x\\Faset Café 世界\\collect-2d\\profile.json"
],
"cwd": "C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-do2lq63x\\empty-working-directory",
"seconds": 0.5779999999999745,
"exit_code": 0,
"timed_out": false,
"stdout": "New round: collect the three gold cubes, then reach the green exit. E resets.\n{\"device\":\"SwiftShader Device (LLVM 10.0.0)\",\"dimension\":2,\"frames\":120,\"ticks\":120,\"validation_errors\":0}\n",
"stderr": "[Faset] Vulkan validation layer/debug-utils unavailable; validation disabled.\n"
}
@@ -0,0 +1,12 @@
{
"arguments": [
"C:\\Users\\runneradmin\\AppData\\Local\\Temp\\faset-playable-exports-do2lq63x\\Faset Café 世界\\collect-2d\\faset_player.exe",
"--validate"
],
"cwd": "C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-do2lq63x\\empty-working-directory",
"seconds": 0.03199999999992542,
"exit_code": 0,
"timed_out": false,
"stdout": "{\"dimension\":2,\"validated\":true}\n",
"stderr": ""
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

@@ -0,0 +1,175 @@
{
"asset_generations": {
"5832763b-3ed0-44d6-9088-0b524f196a91": "e8eb8805673cc22596d1c5b48fc6b8fbdf600d1c6a15c9633d14014a7eb1d11f"
},
"build_fingerprint": "2df2988bbee68e7cb0819b84708006393d85217630475289df5ef603fac4e0c3",
"configuration": "Release",
"executable": "faset_player.exe",
"files": [
{
"path": "assets/5832763b-3ed0-44d6-9088-0b524f196a91/current.json",
"sha256": "32a37e4497f1129c0c78f3ccab4c53e802afe60cabc7a445a31114bf071ff90a",
"size": 134
},
{
"path": "assets/5832763b-3ed0-44d6-9088-0b524f196a91/generations/e8eb8805673cc22596d1c5b48fc6b8fbdf600d1c6a15c9633d14014a7eb1d11f/manifest.json",
"sha256": "c13287d0ebbef75aa610af4a5d3e687e232b2450f3daaff6926fe6128250ead6",
"size": 4532
},
{
"path": "assets/5832763b-3ed0-44d6-9088-0b524f196a91/generations/e8eb8805673cc22596d1c5b48fc6b8fbdf600d1c6a15c9633d14014a7eb1d11f/meshes/mesh-0961e2a3f92977836a3aa80cab09277e-0.fmesh",
"sha256": "98b38aca7d2786c58a2265ba4d1f2255123f03d31d947e239232cf55bfdc2c97",
"size": 928
},
{
"path": "assets/5832763b-3ed0-44d6-9088-0b524f196a91/generations/e8eb8805673cc22596d1c5b48fc6b8fbdf600d1c6a15c9633d14014a7eb1d11f/meshes/mesh-93b5b3e52cb6bb120fefb80e2d8e222b-0.fmesh",
"sha256": "3875c16ea628d4126373ebfe07816621fbad3961596a2fcd112f1eec0e378071",
"size": 928
},
{
"path": "assets/5832763b-3ed0-44d6-9088-0b524f196a91/generations/e8eb8805673cc22596d1c5b48fc6b8fbdf600d1c6a15c9633d14014a7eb1d11f/meshes/mesh-fc069a07a87e0f831fd92efdbc4efa1f-0.fmesh",
"sha256": "98b38aca7d2786c58a2265ba4d1f2255123f03d31d947e239232cf55bfdc2c97",
"size": 928
},
{
"path": "faset_player.exe",
"sha256": "4eb9cf7a6d0c2d5e274fb2fe5d6ce6048abda7775dd41927edd77250ecc3eb3a",
"size": 4292096
},
{
"path": "Notices/box2d/LICENSE",
"sha256": "68a3e676d7e94093b102d5cba0d4e04af812040d6f230c3db67a6664574e43d2",
"size": 1067
},
{
"path": "Notices/box3d/LICENSE",
"sha256": "da5e31a26bf3cfd5ba5c96d6823e480128c81e76c107ef9d3ee5d94789184b90",
"size": 1067
},
{
"path": "Notices/dependencies.json",
"sha256": "a54639ad2d9ad13c2e5f1ec90d6775f5dfc493656789b78c7e44debe2a378fdc",
"size": 2206
},
{
"path": "Notices/entt/LICENSE",
"sha256": "0785027ce472d7c61f05fba664a1d3ba6639c1593ced351ad9e4bed868765d99",
"size": 1097
},
{
"path": "Notices/Faset-NOTICE.txt",
"sha256": "30c2e7e80f5153b31ab57675e07246aef9165965d64e36022b426a26449ece3f",
"size": 204
},
{
"path": "Notices/json/LICENSE.MIT",
"sha256": "46a65cffd1ea955132d95a8dd921640714a8d6b537d2e4e482d31145ae95b603",
"size": 1076
},
{
"path": "Notices/sdl3/LICENSE.txt",
"sha256": "97f35b302b361680ec1e891e95d2d52097bb95abff361434916d99dc1305f127",
"size": 884
},
{
"path": "Notices/stb/LICENSE",
"sha256": "bebfe904b14301657e4e5d655c811d51fd31b97c455b9cc2d8600d6bac6cff63",
"size": 2510
},
{
"path": "README.txt",
"sha256": "c62b83aa59e8eec3b3508f9e9ad5e78eb4554a2369242c830debe8d5ffbab924",
"size": 229
},
{
"path": "scene.fscene",
"sha256": "21c364140669ec82c6886102667b255df5ccdf0ec77e0ca64060f84dd7b86632",
"size": 8639
},
{
"path": "shaders/fragmentMain.reflection.json",
"sha256": "ba43159da6ef0e8c305ba9a88414551ec273c487cdc7d324403998ba2d296f10",
"size": 2777
},
{
"path": "shaders/fragmentMain.spv",
"sha256": "f5c4f289917ecab5d00d543c053aac1d10e6cca311fd172daf06d315160a3505",
"size": 7436
},
{
"path": "shaders/shadowMain.reflection.json",
"sha256": "3f785e549f40abad75115d5dfc16b409f81bbb0eced6281c6eda33c2eb439249",
"size": 2772
},
{
"path": "shaders/shadowMain.spv",
"sha256": "7643b4d688492b5ee923b9606f0b0e70343ca05fa67673838206119a6f86d8d8",
"size": 784
},
{
"path": "shaders/vertexMain.reflection.json",
"sha256": "4459cc3113377b7fbc41b880529cf5ad474ad07d299e033eb9169ac7849894cf",
"size": 2768
},
{
"path": "shaders/vertexMain.spv",
"sha256": "1ad2631c35d654f48166321ae43d4165043e1b919b14f1dc61caf97b1ada0898",
"size": 1224
},
{
"path": "Windows-Runtime.txt",
"sha256": "1c53b7b6890d4a10408acfa7a27760ca1b176bb43dba9c25f3e5d2ac2d7d15db",
"size": 227
}
],
"format": "faset.export",
"generation": "e8819c35-cd05-45d9-b7f4-3de060f62836",
"platform": "windows",
"prerequisites": [
"Windows x64",
"Vulkan 1.3 driver",
"Microsoft Visual C++ x64 Redistributable (Visual Studio 2022 or newer)"
],
"renderer_profile": {
"api": "Vulkan 1.3",
"materials": [
"base-color factor and texture",
"metallic and roughness factors"
],
"required_features": [
"dynamicRendering",
"synchronization2"
],
"shadow_map": {
"resolution": 1024,
"world_extent": 40
},
"texture_sampling": "linear clamp, one mip level",
"unsupported_material_features": [
"normal maps",
"metallic-roughness maps",
"emissive and occlusion maps",
"alpha mode selection",
"unlit mode",
"per-material face culling"
]
},
"scene_hash": "ee12794145c14ba5b599c5d9ae21648cccdfa91c47ee7742549f60d5fe7bc3e0",
"simulation": {
"fixed_delta": 0.016666666666666666,
"gravity": [
0,
-9.81,
0
],
"max_catch_up_ticks": 4,
"physics_substeps": 4
},
"units": {
"angle": "radian",
"coordinates": "right-handed Y-up",
"distance": "metre"
},
"validation_log": "warning: material material-bb63b094febbf90bb7049c9bcf7587bc has features beyond the initial base-color/PBR renderer\r\n{\"dimension\":3,\"validated\":true}\r\n",
"version": 1
}
@@ -0,0 +1,18 @@
{
"arguments": [
"C:\\Users\\runneradmin\\AppData\\Local\\Temp\\faset-playable-exports-do2lq63x\\Faset Café 世界\\collect-3d\\faset_player.exe",
"--headless",
"--frames",
"120",
"--capture",
"C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-do2lq63x\\Faset Café 世界\\collect-3d\\verification.ppm",
"--profile",
"C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-do2lq63x\\Faset Café 世界\\collect-3d\\profile.json"
],
"cwd": "C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-do2lq63x\\empty-working-directory",
"seconds": 2.2810000000001764,
"exit_code": 0,
"timed_out": false,
"stdout": "New round: collect the three gold cubes, then reach the green exit. E resets.\n{\"device\":\"SwiftShader Device (LLVM 10.0.0)\",\"dimension\":3,\"frames\":120,\"ticks\":120,\"validation_errors\":0}\n",
"stderr": "[Faset] Vulkan validation layer/debug-utils unavailable; validation disabled.\nwarning: material material-bb63b094febbf90bb7049c9bcf7587bc has features beyond the initial base-color/PBR renderer\n"
}
@@ -0,0 +1,12 @@
{
"arguments": [
"C:\\Users\\runneradmin\\AppData\\Local\\Temp\\faset-playable-exports-do2lq63x\\Faset Café 世界\\collect-3d\\faset_player.exe",
"--validate"
],
"cwd": "C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-do2lq63x\\empty-working-directory",
"seconds": 0.03099999999994907,
"exit_code": 0,
"timed_out": false,
"stdout": "{\"dimension\":3,\"validated\":true}\n",
"stderr": "warning: material material-bb63b094febbf90bb7049c9bcf7587bc has features beyond the initial base-color/PBR renderer\n"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

@@ -0,0 +1,250 @@
{
"format": "faset.validation-evidence",
"version": 1,
"status": "passed",
"scope": "Hosted Windows developer build, first-project UI contracts, software Vulkan and relocated Release games",
"source_checkout": {
"commit": "0f34b036313c011861dbfd5828ed45c4f7940b05",
"fresh_checkout": true,
"clean_commit_match": true,
"checkout_step": "actions/checkout on a fresh GitHub-hosted runner; engine and game targets configured and built in this job"
},
"ci": {
"run_url": "https://github.com/emil28092005/Faset_Engine/actions/runs/35300447535",
"job_url": "https://github.com/emil28092005/Faset_Engine/actions/runs/35300447535/job/105463031708",
"started_utc": "2026-09-18T02:49:42Z",
"finished_utc": "2026-09-18T03:04:40Z",
"conclusion": "success",
"steps": [
{
"name": "Set up job",
"conclusion": "success"
},
{
"name": "Run actions/checkout@11d5960a326750d5838078e36cf38b85af677262",
"conclusion": "success"
},
{
"name": "Run actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065",
"conclusion": "success"
},
{
"name": "Visual Studio x64 environment",
"conclusion": "success"
},
{
"name": "Enable the documented Windows long-path developer profile",
"conclusion": "success"
},
{
"name": "Identify pinned Vulkan source cache",
"conclusion": "success"
},
{
"name": "Restore pinned Vulkan test tools",
"conclusion": "success"
},
{
"name": "Build official Vulkan loader and SwiftShader from pinned sources",
"conclusion": "success"
},
{
"name": "Save successfully built Vulkan test tools",
"conclusion": "skipped"
},
{
"name": "Probe Vulkan loader and SwiftShader before compiling the engine",
"conclusion": "success"
},
{
"name": "Fetch checksum-verified Slang compiler",
"conclusion": "success"
},
{
"name": "Configure full editor and Player",
"conclusion": "success"
},
{
"name": "Build full editor and tests",
"conclusion": "success"
},
{
"name": "CPU contracts and software GPU pixel tests",
"conclusion": "success"
},
{
"name": "Real Release exports, 2D and 3D execution, incremental Debug rebuild",
"conclusion": "success"
},
{
"name": "Export and relocate both checked-in playable games",
"conclusion": "success"
},
{
"name": "Preserve graphics and export evidence",
"conclusion": "success"
},
{
"name": "Post Run actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065",
"conclusion": "success"
},
{
"name": "Post Run actions/checkout@11d5960a326750d5838078e36cf38b85af677262",
"conclusion": "success"
},
{
"name": "Complete job",
"conclusion": "success"
}
]
},
"environment": {
"runner_label": "windows-2025",
"observed_setup": [
"Microsoft Windows Server 2025",
"Image: windows-2025-vs2026",
"Version: 20260907.229.1",
"-- The CXX compiler identification is Clang 20.1.8 with MSVC-like command-line"
],
"compiler": "Clang 20.1.8 clang-cl, x64 MSVC ABI",
"editor_configuration": "Debug, FASET_DEBUG_IMGUI=ON",
"export_configuration": "Release, independent Ninja build with custom project C++ sources",
"windows_long_paths_enabled": true,
"device": "SwiftShader Device (LLVM 10.0.0)",
"validation_layer_available": false
},
"tests": {
"total": 35,
"passed": 35,
"failed": 0,
"skipped": 0,
"details": "tests.json"
},
"first_project_evidence": {
"test": "editor_ui_launcher",
"observed": "Create/Open through the instrumented launcher, Unicode paths, recents, directory browsing, validation and keyboard navigation; actual retained UI and software-rendered frame"
},
"games": [
{
"name": "collect-2d",
"generation": "16e0f91d-c1ab-4c66-b4d7-3dc88459caa9",
"configuration": "Release",
"frames": 120,
"validation_enabled": false,
"validation_errors": 0,
"source_paths_hidden": true,
"capture": {
"width": 1280,
"height": 720,
"sampled_colors": 7,
"sha256": "f9d74067d87c1ebf30c6db372a26d93b7285791c8cb0307a24af5adb23bf201a"
},
"export_compiler_evidence": [
"-- The C compiler identification is Clang 20.1.8 with MSVC-like command-line",
"-- The CXX compiler identification is Clang 20.1.8 with MSVC-like command-line"
]
},
{
"name": "collect-3d",
"generation": "e8819c35-cd05-45d9-b7f4-3de060f62836",
"configuration": "Release",
"frames": 120,
"validation_enabled": false,
"validation_errors": 0,
"source_paths_hidden": true,
"capture": {
"width": 1280,
"height": 720,
"sampled_colors": 43,
"sha256": "0edc88eef9f641a780ef44664f58c811a22bd201c8d29e1fcb7531b88f251900"
},
"export_compiler_evidence": [
"-- The C compiler identification is Clang 20.1.8 with MSVC-like command-line",
"-- The CXX compiler identification is Clang 20.1.8 with MSVC-like command-line"
]
}
],
"limitations": [
"Software Vulkan on a GitHub-hosted Windows Server VM, not a physical desktop GPU qualification or performance benchmark.",
"Khronos validation layer is absent. Zero reported validation errors does not establish validation-layer coverage.",
"Fresh developer-toolchain setup and first-project tests are covered; no retail installer or manual OS IME composition acceptance is claimed."
],
"original_ci_log_sha256": "5ef915923837881ffba85d03f73fb879acef2849d425fa6c90d6401781cc5937",
"retained_files": [
{
"path": "collect-2d-manifest.json",
"sha256": "f65466a16a53bad75cf758952cdb6169c1717e1995257333ca0e882aabda63b3",
"size": 4315
},
{
"path": "collect-2d-run.json",
"sha256": "afd99e711f732aff500fdb5ff710c4ecfc9fa7185ac376880959c457692c21ea",
"size": 993,
"original_artifact_sha256": "9dda395b5012051bfa225be27577bde0eff9d56ccc5f7e64ae8ed7dbd9748d02",
"original_artifact_size": 1011
},
{
"path": "collect-2d-validate.json",
"sha256": "3cc2e458a2ac3c8e0c08cb6475ebc7a8a9c9fcc3580d423dcca60f690db9afda",
"size": 433,
"original_artifact_sha256": "1789f7b2d8de3bd55be3974d6b1e8fbc76424b5c73633e0a2052fb07482ce474",
"original_artifact_size": 445
},
{
"path": "collect-2d.png",
"sha256": "c380583f2fd8bc09c5b0e1c6e755c35c3d64b5385ed66177b04d1bbdb532b236",
"size": 4525
},
{
"path": "collect-3d-manifest.json",
"sha256": "35350b5d34dd2d1caed5cbbc1216274479fcc2ed5139e2de53369df0f2a9b929",
"size": 5923
},
{
"path": "collect-3d-run.json",
"sha256": "a19ce25b92a84eb04a5f0a50907c661251f73bc25bed94687ea0a7ae03dbcc88",
"size": 1110,
"original_artifact_sha256": "0fd945b0ea7d8373832db5ef017b1d57155ba8a26fd245e43d45732a0aacb5f9",
"original_artifact_size": 1128
},
{
"path": "collect-3d-validate.json",
"sha256": "199938c31d5fbeda2ee94148a00ce7c6d67f7239b216fb39f171313b36e90ad4",
"size": 550,
"original_artifact_sha256": "3c6f05871ac8d462505c0f4021cb18d9740060955bad22aead701a4dec8bebb0",
"original_artifact_size": 562
},
{
"path": "collect-3d.png",
"sha256": "48ef9a82378f74e8ad5a0c438bb730773d684cce809afcef461756a38476375e",
"size": 20366
},
{
"path": "playable-report.json",
"sha256": "bfb1ee2a6632978ad95428025fddfed77ec330256acd68b0152140beb6fe8a41",
"size": 14094,
"original_artifact_sha256": "d754700b5bfb23e3e5f6f78cc77336daea0503d71fe82bec7c80454f194ac293",
"original_artifact_size": 14529
},
{
"path": "probe.json",
"sha256": "fbc4c5f01a5d23c901fbdab366537da331002709bfbce42e06a84b1a64a1b396",
"size": 987,
"original_artifact_sha256": "0c85c12510dbb0d895faefb7d14f26935a5add675cf0477b29f543d72eed40d6",
"original_artifact_size": 1019
},
{
"path": "tests.json",
"sha256": "ac25ad1d3d9368e28cc9b1bd01275ee7ec154d8a654fbed95ceb6f2d91592c2e",
"size": 4730
},
{
"path": "toolchain.json",
"sha256": "daf1ce634e438ff9cd3a84a2c21313f3530279dfb27f15acf8b217833e06548d",
"size": 914,
"original_artifact_sha256": "969162d1f994724ff6f98d20353e62e3881477ebce98759ca325c8febb175176",
"original_artifact_size": 937
}
],
"retained_file_hash_basis": "Repository bytes with LF text line endings. Where normalization changed original Windows artifact bytes, original_artifact_sha256 and original_artifact_size preserve their original provenance."
}
@@ -0,0 +1,435 @@
{
"format": "faset.playable-export-verification",
"version": 1,
"started_utc": "2026-09-18T03:00:26.437450+00:00",
"platform": "win32",
"engine": "D:\\a\\Faset_Engine\\Faset_Engine",
"editor": "D:\\a\\Faset_Engine\\Faset_Engine\\build\\windows-debug\\faset_editor.exe",
"standalone_root": "C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-do2lq63x",
"frames_per_game": 120,
"status": "passed",
"projects": [
{
"name": "collect-2d",
"dimension": 2,
"source_inputs": [
{
"path": ".gitignore",
"sha256": "3bb936ff6f84f3db041c75d6e207138a9107997cc9ad372621f657456c9c0665"
},
{
"path": "project.faset.json",
"sha256": "27bd0e432381f8f884e78f6d68e9d0dc13d49222e70f3a5e34fef1d57d379b0b"
},
{
"path": "README.md",
"sha256": "7543b24c9ac87d6a7390d61d5289518e5f5725f3c0052675659f6da716883bdd"
},
{
"path": "Scenes/main.scene.json",
"sha256": "9e2ad049f60a9ff7f98e31061a8f107648fbf672e5b9292f53e6672e5bae66f1"
},
{
"path": "Scripts/Gameplay.cpp",
"sha256": "99fb965e6589b138049a2e6cf95c5c61baea70761ffab33082a8058c91a687ff"
},
{
"path": "Scripts/Gameplay.hpp",
"sha256": "9d1fa36da50886fa7d84f8a8b3d1ae42856ae74aae1e52be5015b60977634dc0"
}
],
"generation": "16e0f91d-c1ab-4c66-b4d7-3dc88459caa9",
"configuration": "Release",
"standalone_directory": "C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-do2lq63x\\Faset Café 世界\\collect-2d",
"executable": "faset_player.exe",
"package_file_count": 18,
"asset_generations": {},
"device": "SwiftShader Device (LLVM 10.0.0)",
"validation_enabled": false,
"validation_errors": 0,
"completed_frames": 120,
"summary_ms": {
"gpu": {
"max": 128.739,
"min": 1.839,
"p50": 1.9465,
"p95": 2.362,
"samples": 120
},
"render_call": {
"max": 129.6447,
"min": 2.0406,
"p50": 2.1546,
"p95": 2.5774,
"samples": 120
},
"renderer_cpu": {
"max": 129.6266,
"min": 2.0373,
"p50": 2.1516,
"p95": 2.5745,
"samples": 120
},
"renderer_readback_cpu": {
"max": 0.7806,
"min": 0.1451,
"p50": 0.1478,
"p95": 0.1646,
"samples": 120
},
"simulation": {
"max": 0.3316,
"min": 0.2683,
"p50": 0.283,
"p95": 0.3148,
"samples": 120
},
"snapshot": {
"max": 0.2707,
"min": 0.1572,
"p50": 0.2213,
"p95": 0.2435,
"samples": 120
},
"wall": {
"max": 130.7666,
"min": 2.5456,
"p50": 2.6691,
"p95": 3.0846,
"samples": 120
}
},
"capture": {
"width": 1280,
"height": 720,
"sampled_colors": 7,
"sha256": "f9d74067d87c1ebf30c6db372a26d93b7285791c8cb0307a24af5adb23bf201a"
},
"source_project_paths_unavailable": true,
"status": "passed"
},
{
"name": "collect-3d",
"dimension": 3,
"source_inputs": [
{
"path": ".gitignore",
"sha256": "3bb936ff6f84f3db041c75d6e207138a9107997cc9ad372621f657456c9c0665"
},
{
"path": "Assets/exit-arch/create.py",
"sha256": "5d9dc30a3f939376d2474cf958065e6daab140c7220444cedecd3bf5edf6e3d1"
},
{
"path": "Assets/exit-arch/manifest.json",
"sha256": "d72d44184d665148109de74782bc695d79392e43be12782e48096a7d79e37c4f"
},
{
"path": "Assets/exit-arch/manifest.json.faset-import.json",
"sha256": "7639d4fa33f2ac52e10d1cf79280a93aeb680399d217fda167acec1c6edcae00"
},
{
"path": "Assets/exit-arch/payload/ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3.glb",
"sha256": "ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3"
},
{
"path": "Assets/exit-arch/source.blend",
"sha256": "ff2676bec97ab778e531e87a185ad716049ea3b05b4a4f0027a6345737735035"
},
{
"path": "project.faset.json",
"sha256": "9a0ee78fa0ea56982a99cf707948a33db37266ab84de9d3f12a24aabb98afda5"
},
{
"path": "README.md",
"sha256": "a2378adc9dbd5ffb6bfa65abb7770051827d08279e48761046f30d932a5eab8c"
},
{
"path": "Scenes/main.scene.json",
"sha256": "b1b668a2d633deda0074b475460c82019dbcf592b76502906192eaf1f2345a7e"
},
{
"path": "Scripts/Extensions/Beacon.hpp",
"sha256": "650e75bbc55a3339647bcf67ba10fd9b20cece3531bb688b4221155e97959d5e"
},
{
"path": "Scripts/Gameplay.cpp",
"sha256": "c76fbb0bf28a85cc88732a905f2bc9be3e24c58d02cbf2ecccbf77c99093c029"
},
{
"path": "Scripts/Gameplay.hpp",
"sha256": "9d1fa36da50886fa7d84f8a8b3d1ae42856ae74aae1e52be5015b60977634dc0"
}
],
"import": {
"asset_id": "5832763b-3ed0-44d6-9088-0b524f196a91",
"cache_hit": false,
"diagnostics": [],
"generation": "e8eb8805673cc22596d1c5b48fc6b8fbdf600d1c6a15c9633d14014a7eb1d11f",
"manifest": {
"asset_id": "5832763b-3ed0-44d6-9088-0b524f196a91",
"files": [
{
"path": "meshes/mesh-fc069a07a87e0f831fd92efdbc4efa1f-0.fmesh",
"sha256": "98b38aca7d2786c58a2265ba4d1f2255123f03d31d947e239232cf55bfdc2c97",
"size": 928
},
{
"path": "meshes/mesh-0961e2a3f92977836a3aa80cab09277e-0.fmesh",
"sha256": "98b38aca7d2786c58a2265ba4d1f2255123f03d31d947e239232cf55bfdc2c97",
"size": 928
},
{
"path": "meshes/mesh-93b5b3e52cb6bb120fefb80e2d8e222b-0.fmesh",
"sha256": "3875c16ea628d4126373ebfe07816621fbad3961596a2fcd112f1eec0e378071",
"size": 928
}
],
"generation": "e8eb8805673cc22596d1c5b48fc6b8fbdf600d1c6a15c9633d14014a7eb1d11f",
"importer": "faset-gltf-1/cgltf-1.15",
"input_key": {
"bundle_sha256": "d72d44184d665148109de74782bc695d79392e43be12782e48096a7d79e37c4f",
"dependencies": {},
"importer": "faset-gltf-1/cgltf-1.15",
"settings": {},
"source": "ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3",
"target_profile": "desktop-static-pbr-v1",
"toolchain": {
"cgltf": "360db1a95480fe102ae9c69b27c5d101167ff5ba",
"stb": "2c980bb59875b0d32144a71867fbdebb2f77cd20"
}
},
"kind": "scene",
"materials": [
{
"alpha_cutoff": 0.5,
"alpha_mode": "OPAQUE",
"base_color": [
0.2199999988079071,
0.28999999165534973,
0.3400000035762787,
1.0
],
"base_color_texture": -1,
"double_sided": true,
"emissive": [
0.0,
0.0,
0.0
],
"emissive_texture": -1,
"format": "faset.material",
"id": "material-bb63b094febbf90bb7049c9bcf7587bc",
"metallic": 0.07999999821186066,
"metallic_roughness_texture": -1,
"name": "Weathered stone",
"normal_texture": -1,
"occlusion_texture": -1,
"roughness": 0.800000011920929,
"unlit": false,
"version": 1
}
],
"meshes": [
{
"id": "mesh-fc069a07a87e0f831fd92efdbc4efa1f",
"name": "Cube.001",
"primitives": [
{
"material": 0,
"path": "meshes/mesh-fc069a07a87e0f831fd92efdbc4efa1f-0.fmesh"
}
]
},
{
"id": "mesh-0961e2a3f92977836a3aa80cab09277e",
"name": "Cube.002",
"primitives": [
{
"material": 0,
"path": "meshes/mesh-0961e2a3f92977836a3aa80cab09277e-0.fmesh"
}
]
},
{
"id": "mesh-93b5b3e52cb6bb120fefb80e2d8e222b",
"name": "Cube.003",
"primitives": [
{
"material": 0,
"path": "meshes/mesh-93b5b3e52cb6bb120fefb80e2d8e222b-0.fmesh"
}
]
}
],
"nodes": [
{
"id": "node-cec6e8cea80cf5a98ba3263a0156bee4",
"local_transform": [
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.4500000476837158,
1.2999999523162842,
1.0
],
"mesh": 0,
"name": "Left post",
"parent_id": "",
"stable_source_id": true
},
{
"id": "node-5f8a90a6c4d27020d20bd4fa81d1d958",
"local_transform": [
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.4500000476837158,
-1.2999999523162842,
1.0
],
"mesh": 1,
"name": "Right post",
"parent_id": "",
"stable_source_id": true
},
{
"id": "node-482463e486a8d1fd741340c653cd128f",
"local_transform": [
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
3.0,
0.0,
1.0
],
"mesh": 2,
"name": "Lintel",
"parent_id": "",
"stable_source_id": true
}
],
"outputs": [
"node-cec6e8cea80cf5a98ba3263a0156bee4",
"node-5f8a90a6c4d27020d20bd4fa81d1d958",
"node-482463e486a8d1fd741340c653cd128f",
"mesh-fc069a07a87e0f831fd92efdbc4efa1f",
"mesh-0961e2a3f92977836a3aa80cab09277e",
"mesh-93b5b3e52cb6bb120fefb80e2d8e222b",
"material-bb63b094febbf90bb7049c9bcf7587bc"
],
"payload_source": "D:\\a\\Faset_Engine\\Faset_Engine\\.cache\\windows-playable-exports\\Faset Café 世界\\collect-3d\\Assets\\exit-arch\\payload/ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3.glb",
"schema_version": 1,
"settings": {},
"source": "D:\\a\\Faset_Engine\\Faset_Engine\\.cache\\windows-playable-exports\\Faset Café 世界\\collect-3d\\Assets\\exit-arch\\manifest.json",
"source_sha256": "ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3",
"textures": []
},
"previous_generation": "",
"removed_output_ids": []
},
"generation": "e8819c35-cd05-45d9-b7f4-3de060f62836",
"configuration": "Release",
"standalone_directory": "C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-do2lq63x\\Faset Café 世界\\collect-3d",
"executable": "faset_player.exe",
"package_file_count": 23,
"asset_generations": {
"5832763b-3ed0-44d6-9088-0b524f196a91": "e8eb8805673cc22596d1c5b48fc6b8fbdf600d1c6a15c9633d14014a7eb1d11f"
},
"device": "SwiftShader Device (LLVM 10.0.0)",
"validation_enabled": false,
"validation_errors": 0,
"completed_frames": 120,
"summary_ms": {
"gpu": {
"max": 191.1372,
"min": 14.892,
"p50": 15.2367,
"p95": 20.1033,
"samples": 120
},
"render_call": {
"max": 192.1372,
"min": 15.1555,
"p50": 15.5375,
"p95": 20.4063,
"samples": 120
},
"renderer_cpu": {
"max": 192.1253,
"min": 15.1507,
"p50": 15.5268,
"p95": 20.3959,
"samples": 120
},
"renderer_readback_cpu": {
"max": 0.7794,
"min": 0.1471,
"p50": 0.1602,
"p95": 0.187,
"samples": 120
},
"simulation": {
"max": 0.5079,
"min": 0.2905,
"p50": 0.4613,
"p95": 0.4892,
"samples": 120
},
"snapshot": {
"max": 2.8905,
"min": 0.1883,
"p50": 0.2104,
"p95": 0.3207,
"samples": 120
},
"wall": {
"max": 196.1393,
"min": 15.8274,
"p50": 16.2321,
"p95": 21.1248,
"samples": 120
}
},
"capture": {
"width": 1280,
"height": 720,
"sampled_colors": 43,
"sha256": "0edc88eef9f641a780ef44664f58c811a22bd201c8d29e1fcb7531b88f251900"
},
"source_project_paths_unavailable": true,
"status": "passed"
}
],
"finished_utc": "2026-09-18T03:04:35.903012+00:00"
}
@@ -0,0 +1,32 @@
{
"format": "faset.windows-vulkan-probe",
"version": 1,
"status": "passed",
"loader": "D:\\a\\Faset_Engine\\Faset_Engine\\.cache\\windows-graphics\\sdk\\bin\\vulkan-1.dll",
"driver_manifest": "D:\\a\\Faset_Engine\\Faset_Engine\\.cache\\windows-graphics\\driver\\vk_swiftshader_icd.json",
"driver_library": "D:\\a\\Faset_Engine\\Faset_Engine\\.cache\\windows-graphics\\driver\\vk_swiftshader.dll",
"manifest": {
"file_format_version": "1.0.0",
"ICD": {
"library_path": ".\\vk_swiftshader.dll",
"api_version": "1.0.5"
}
},
"loader_debug": "all",
"pointer_bits": 64,
"icd_negotiate_result": 0,
"icd_interface_version": 7,
"enumerate_version_result": 0,
"loader_api_version": "1.4.341",
"create_instance_result": 0,
"devices": [
{
"name": "SwiftShader Device (LLVM 10.0.0)",
"api_version": "1.3.0",
"driver_version": 20971520,
"vendor_id": 6880,
"device_id": 49374,
"device_type": 4
}
]
}
@@ -0,0 +1,206 @@
{
"format": "faset.ctest-summary",
"version": 1,
"source_commit": "0f34b036313c011861dbfd5828ed45c4f7940b05",
"passed": 35,
"failed": 0,
"skipped": 0,
"source_log_sha256": "784a057ec9067fc35e38e3eb87804f583b55745147e72c009f84fb87112361ba",
"tests": [
{
"name": "authoring",
"status": "passed",
"seconds": 1.76
},
{
"name": "runtime_contracts",
"status": "passed",
"seconds": 0.26
},
{
"name": "assets_pipeline",
"status": "passed",
"seconds": 0.95,
"observations": [
"assets: geometry/PBR/texture, GLB/glTF, cache, rename, deletion, overrides, failure, cancellation, standalone PNG/JPEG OK"
]
},
{
"name": "assets_blender_bundle",
"status": "passed",
"seconds": 0.42
},
{
"name": "render_graph",
"status": "passed",
"seconds": 0.25
},
{
"name": "render_offscreen",
"status": "passed",
"seconds": 0.62
},
{
"name": "render_sprite_alpha",
"status": "passed",
"seconds": 0.26
},
{
"name": "render_shader_reload",
"status": "passed",
"seconds": 2.65
},
{
"name": "render_window_lifecycle",
"status": "passed",
"seconds": 1.03,
"observations": [
"driver=windows stage=created",
"stage=resized width=360 height=300 resize_events=2",
"clipboard=unicode_roundtrip_passed",
"text_input_area=coordinate_conversion_passed",
"stage=minimized fresh_frames=12 minimize_events=1 focus_lost_events=1",
"stage=restored restored_events=1 activation_required=0 frames=54 validation_enabled=0 validation_errors=0"
]
},
{
"name": "player_scene_contracts",
"status": "passed",
"seconds": 0.16
},
{
"name": "player_shutdown_diagnostics",
"status": "passed",
"seconds": 0.17
},
{
"name": "editor_mcp",
"status": "passed",
"seconds": 0.06
},
{
"name": "process_and_cook",
"status": "passed",
"seconds": 0.64
},
{
"name": "build_schema_publication",
"status": "passed",
"seconds": 7.29
},
{
"name": "editor_plugins",
"status": "passed",
"seconds": 0.24
},
{
"name": "editor_session_settings",
"status": "passed",
"seconds": 0.19
},
{
"name": "ui_widgets",
"status": "passed",
"seconds": 0.14
},
{
"name": "ui_render",
"status": "passed",
"seconds": 0.48
},
{
"name": "editor_ui_import_conflicts",
"status": "passed",
"seconds": 0.93
},
{
"name": "editor_ui_project_settings",
"status": "passed",
"seconds": 1.23
},
{
"name": "editor_ui_reload",
"status": "passed",
"seconds": 4.26
},
{
"name": "editor_ui_launcher",
"status": "passed",
"seconds": 0.65,
"observations": [
"Launcher Unicode/create/open/validation/recents/directory browser/keyboard passed. C:\\Users\\runneradmin\\AppData\\Local\\Temp\\faset-проекты-1425bd32-d184-42d7-9ece-402897e8d0b2"
]
},
{
"name": "editor_ui_templates",
"status": "passed",
"seconds": 2.98
},
{
"name": "editor_ui_gizmos",
"status": "passed",
"seconds": 1.16
},
{
"name": "editor_ui_authoring",
"status": "passed",
"seconds": 1.98
},
{
"name": "editor_mcp_stdio",
"status": "passed",
"seconds": 0.59
},
{
"name": "editor_gui_mcp",
"status": "passed",
"seconds": 4.66,
"observations": [
"Native GUI + MCP shared authoring, revision conflict, Undo, 12 fresh PNG captures and continued responsiveness passed"
]
},
{
"name": "core",
"status": "passed",
"seconds": 0.16
},
{
"name": "tutorial_moving",
"status": "passed",
"seconds": 0.03
},
{
"name": "tutorial_following",
"status": "passed",
"seconds": 0.01
},
{
"name": "tutorial_spawning",
"status": "passed",
"seconds": 0.04
},
{
"name": "tutorial_physics",
"status": "passed",
"seconds": 0.1
},
{
"name": "playable_2d",
"status": "passed",
"seconds": 0.62
},
{
"name": "playable_3d",
"status": "passed",
"seconds": 1.34
},
{
"name": "editor_debug_overlay",
"status": "passed",
"seconds": 0.21,
"observations": [
"ImGui diagnostics, F12, font atlas, clipping and event isolation passed"
]
}
]
}
@@ -0,0 +1,23 @@
{
"sources": {
"headers": {
"repository": "KhronosGroup/Vulkan-Headers",
"commit": "0d3f509e57041fbd073a1ee84cd9ccd36d148446",
"sha256": "e82005a6bd3289ce213232ef41e0f8722d1365ed72bf5cc4be56911c56bc30e0"
},
"loader": {
"repository": "KhronosGroup/Vulkan-Loader",
"commit": "32fcb949e253cbeb40cda7ea76122b492db579ae",
"sha256": "610fa9017226c49bc4f19398d94fce9e3c9ff94c14f6420f9fe24822707feacf"
},
"swiftshader": {
"repository": "google/swiftshader",
"commit": "1e80438d2b93ef36a7c05f8d2b81233bac0e3d16",
"sha256": "1c3a1afc397c7aa4d3275790bc9b451e80b144a1db665135d5519838bacf44a8"
}
},
"validation_layer": false,
"vulkan_sdk": "D:\\a\\Faset_Engine\\Faset_Engine\\.cache\\windows-graphics\\sdk",
"driver": "D:\\a\\Faset_Engine\\Faset_Engine\\.cache\\windows-graphics\\driver\\vk_swiftshader_icd.json",
"loader_only": false
}
@@ -0,0 +1,148 @@
{
"asset_generations": {},
"build_fingerprint": "4f93c7bc328f4f1ec19cc143e94fca71cb3075f4fae8dc26a812d968426e015b",
"configuration": "Release",
"executable": "faset_player.exe",
"files": [
{
"path": "faset_player.exe",
"sha256": "4674615a5a89fb1151619d4cfc5a4e96743a036308739fdec95f72843bc9c586",
"size": 4278272
},
{
"path": "Notices/box2d/LICENSE",
"sha256": "68a3e676d7e94093b102d5cba0d4e04af812040d6f230c3db67a6664574e43d2",
"size": 1067
},
{
"path": "Notices/box3d/LICENSE",
"sha256": "da5e31a26bf3cfd5ba5c96d6823e480128c81e76c107ef9d3ee5d94789184b90",
"size": 1067
},
{
"path": "Notices/dependencies.json",
"sha256": "a54639ad2d9ad13c2e5f1ec90d6775f5dfc493656789b78c7e44debe2a378fdc",
"size": 2206
},
{
"path": "Notices/entt/LICENSE",
"sha256": "0785027ce472d7c61f05fba664a1d3ba6639c1593ced351ad9e4bed868765d99",
"size": 1097
},
{
"path": "Notices/Faset-NOTICE.txt",
"sha256": "30c2e7e80f5153b31ab57675e07246aef9165965d64e36022b426a26449ece3f",
"size": 204
},
{
"path": "Notices/json/LICENSE.MIT",
"sha256": "46a65cffd1ea955132d95a8dd921640714a8d6b537d2e4e482d31145ae95b603",
"size": 1076
},
{
"path": "Notices/sdl3/LICENSE.txt",
"sha256": "97f35b302b361680ec1e891e95d2d52097bb95abff361434916d99dc1305f127",
"size": 884
},
{
"path": "Notices/stb/LICENSE",
"sha256": "bebfe904b14301657e4e5d655c811d51fd31b97c455b9cc2d8600d6bac6cff63",
"size": 2510
},
{
"path": "README.txt",
"sha256": "c62b83aa59e8eec3b3508f9e9ad5e78eb4554a2369242c830debe8d5ffbab924",
"size": 229
},
{
"path": "scene.fscene",
"sha256": "0d7b221abc1cae5e9f1d04357c684ac6993f5878d634b4b950eec66dd8e55b2a",
"size": 6214
},
{
"path": "shaders/fragmentMain.reflection.json",
"sha256": "ba43159da6ef0e8c305ba9a88414551ec273c487cdc7d324403998ba2d296f10",
"size": 2777
},
{
"path": "shaders/fragmentMain.spv",
"sha256": "f5c4f289917ecab5d00d543c053aac1d10e6cca311fd172daf06d315160a3505",
"size": 7436
},
{
"path": "shaders/shadowMain.reflection.json",
"sha256": "3f785e549f40abad75115d5dfc16b409f81bbb0eced6281c6eda33c2eb439249",
"size": 2772
},
{
"path": "shaders/shadowMain.spv",
"sha256": "7643b4d688492b5ee923b9606f0b0e70343ca05fa67673838206119a6f86d8d8",
"size": 784
},
{
"path": "shaders/vertexMain.reflection.json",
"sha256": "4459cc3113377b7fbc41b880529cf5ad474ad07d299e033eb9169ac7849894cf",
"size": 2768
},
{
"path": "shaders/vertexMain.spv",
"sha256": "1ad2631c35d654f48166321ae43d4165043e1b919b14f1dc61caf97b1ada0898",
"size": 1224
},
{
"path": "Windows-Runtime.txt",
"sha256": "1c53b7b6890d4a10408acfa7a27760ca1b176bb43dba9c25f3e5d2ac2d7d15db",
"size": 227
}
],
"format": "faset.export",
"generation": "260a10cf-3fe6-4689-ac7b-69b577954cc2",
"platform": "windows",
"prerequisites": [
"Windows x64",
"Vulkan 1.3 driver",
"Microsoft Visual C++ x64 Redistributable (Visual Studio 2022 or newer)"
],
"renderer_profile": {
"api": "Vulkan 1.3",
"materials": [
"base-color factor and texture",
"metallic and roughness factors"
],
"required_features": [
"dynamicRendering",
"synchronization2"
],
"shadow_map": {
"resolution": 1024,
"world_extent": 40
},
"texture_sampling": "linear clamp, one mip level",
"unsupported_material_features": [
"normal maps",
"metallic-roughness maps",
"emissive and occlusion maps",
"alpha mode selection",
"unlit mode",
"per-material face culling"
]
},
"scene_hash": "fdfa1c49cf78a1cf52cd41b201c35bb0b5f852c90b7626b2a7f17da3e2e3e24c",
"simulation": {
"fixed_delta": 0.016666666666666666,
"gravity": [
0,
-9.81,
0
],
"max_catch_up_ticks": 4,
"physics_substeps": 4
},
"units": {
"angle": "radian",
"coordinates": "right-handed Y-up",
"distance": "metre"
},
"validation_log": "{\"dimension\":2,\"validated\":true}\r\n",
"version": 1
}
@@ -0,0 +1,18 @@
{
"arguments": [
"C:\\Users\\runneradmin\\AppData\\Local\\Temp\\faset-playable-exports-8qma4esl\\Faset Café 世界\\collect-2d\\faset_player.exe",
"--headless",
"--frames",
"120",
"--capture",
"C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-8qma4esl\\Faset Café 世界\\collect-2d\\verification.ppm",
"--profile",
"C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-8qma4esl\\Faset Café 世界\\collect-2d\\profile.json"
],
"cwd": "C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-8qma4esl\\empty-working-directory",
"seconds": 0.5939999999999372,
"exit_code": 0,
"timed_out": false,
"stdout": "New round: collect the three gold cubes, then reach the green exit. E resets.\n{\"device\":\"SwiftShader Device (LLVM 10.0.0)\",\"dimension\":2,\"frames\":120,\"ticks\":120,\"validation_errors\":0}\n",
"stderr": "[Faset] Vulkan validation layer/debug-utils unavailable; validation disabled.\n"
}
@@ -0,0 +1,12 @@
{
"arguments": [
"C:\\Users\\runneradmin\\AppData\\Local\\Temp\\faset-playable-exports-8qma4esl\\Faset Café 世界\\collect-2d\\faset_player.exe",
"--validate"
],
"cwd": "C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-8qma4esl\\empty-working-directory",
"seconds": 0.031000000000062755,
"exit_code": 0,
"timed_out": false,
"stdout": "{\"dimension\":2,\"validated\":true}\n",
"stderr": ""
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

@@ -0,0 +1,175 @@
{
"asset_generations": {
"5832763b-3ed0-44d6-9088-0b524f196a91": "e8eb8805673cc22596d1c5b48fc6b8fbdf600d1c6a15c9633d14014a7eb1d11f"
},
"build_fingerprint": "460296d2322c47856e907b7c7ca070004d2a94f53e40a9bfb791d4dd8e9e9e45",
"configuration": "Release",
"executable": "faset_player.exe",
"files": [
{
"path": "assets/5832763b-3ed0-44d6-9088-0b524f196a91/current.json",
"sha256": "32a37e4497f1129c0c78f3ccab4c53e802afe60cabc7a445a31114bf071ff90a",
"size": 134
},
{
"path": "assets/5832763b-3ed0-44d6-9088-0b524f196a91/generations/e8eb8805673cc22596d1c5b48fc6b8fbdf600d1c6a15c9633d14014a7eb1d11f/manifest.json",
"sha256": "c13287d0ebbef75aa610af4a5d3e687e232b2450f3daaff6926fe6128250ead6",
"size": 4532
},
{
"path": "assets/5832763b-3ed0-44d6-9088-0b524f196a91/generations/e8eb8805673cc22596d1c5b48fc6b8fbdf600d1c6a15c9633d14014a7eb1d11f/meshes/mesh-0961e2a3f92977836a3aa80cab09277e-0.fmesh",
"sha256": "98b38aca7d2786c58a2265ba4d1f2255123f03d31d947e239232cf55bfdc2c97",
"size": 928
},
{
"path": "assets/5832763b-3ed0-44d6-9088-0b524f196a91/generations/e8eb8805673cc22596d1c5b48fc6b8fbdf600d1c6a15c9633d14014a7eb1d11f/meshes/mesh-93b5b3e52cb6bb120fefb80e2d8e222b-0.fmesh",
"sha256": "3875c16ea628d4126373ebfe07816621fbad3961596a2fcd112f1eec0e378071",
"size": 928
},
{
"path": "assets/5832763b-3ed0-44d6-9088-0b524f196a91/generations/e8eb8805673cc22596d1c5b48fc6b8fbdf600d1c6a15c9633d14014a7eb1d11f/meshes/mesh-fc069a07a87e0f831fd92efdbc4efa1f-0.fmesh",
"sha256": "98b38aca7d2786c58a2265ba4d1f2255123f03d31d947e239232cf55bfdc2c97",
"size": 928
},
{
"path": "faset_player.exe",
"sha256": "cb5f4167643d33adb11770f6746a9c29259abe6ff41fba9acc55aeb062a8c449",
"size": 4292096
},
{
"path": "Notices/box2d/LICENSE",
"sha256": "68a3e676d7e94093b102d5cba0d4e04af812040d6f230c3db67a6664574e43d2",
"size": 1067
},
{
"path": "Notices/box3d/LICENSE",
"sha256": "da5e31a26bf3cfd5ba5c96d6823e480128c81e76c107ef9d3ee5d94789184b90",
"size": 1067
},
{
"path": "Notices/dependencies.json",
"sha256": "a54639ad2d9ad13c2e5f1ec90d6775f5dfc493656789b78c7e44debe2a378fdc",
"size": 2206
},
{
"path": "Notices/entt/LICENSE",
"sha256": "0785027ce472d7c61f05fba664a1d3ba6639c1593ced351ad9e4bed868765d99",
"size": 1097
},
{
"path": "Notices/Faset-NOTICE.txt",
"sha256": "30c2e7e80f5153b31ab57675e07246aef9165965d64e36022b426a26449ece3f",
"size": 204
},
{
"path": "Notices/json/LICENSE.MIT",
"sha256": "46a65cffd1ea955132d95a8dd921640714a8d6b537d2e4e482d31145ae95b603",
"size": 1076
},
{
"path": "Notices/sdl3/LICENSE.txt",
"sha256": "97f35b302b361680ec1e891e95d2d52097bb95abff361434916d99dc1305f127",
"size": 884
},
{
"path": "Notices/stb/LICENSE",
"sha256": "bebfe904b14301657e4e5d655c811d51fd31b97c455b9cc2d8600d6bac6cff63",
"size": 2510
},
{
"path": "README.txt",
"sha256": "c62b83aa59e8eec3b3508f9e9ad5e78eb4554a2369242c830debe8d5ffbab924",
"size": 229
},
{
"path": "scene.fscene",
"sha256": "21c364140669ec82c6886102667b255df5ccdf0ec77e0ca64060f84dd7b86632",
"size": 8639
},
{
"path": "shaders/fragmentMain.reflection.json",
"sha256": "ba43159da6ef0e8c305ba9a88414551ec273c487cdc7d324403998ba2d296f10",
"size": 2777
},
{
"path": "shaders/fragmentMain.spv",
"sha256": "f5c4f289917ecab5d00d543c053aac1d10e6cca311fd172daf06d315160a3505",
"size": 7436
},
{
"path": "shaders/shadowMain.reflection.json",
"sha256": "3f785e549f40abad75115d5dfc16b409f81bbb0eced6281c6eda33c2eb439249",
"size": 2772
},
{
"path": "shaders/shadowMain.spv",
"sha256": "7643b4d688492b5ee923b9606f0b0e70343ca05fa67673838206119a6f86d8d8",
"size": 784
},
{
"path": "shaders/vertexMain.reflection.json",
"sha256": "4459cc3113377b7fbc41b880529cf5ad474ad07d299e033eb9169ac7849894cf",
"size": 2768
},
{
"path": "shaders/vertexMain.spv",
"sha256": "1ad2631c35d654f48166321ae43d4165043e1b919b14f1dc61caf97b1ada0898",
"size": 1224
},
{
"path": "Windows-Runtime.txt",
"sha256": "1c53b7b6890d4a10408acfa7a27760ca1b176bb43dba9c25f3e5d2ac2d7d15db",
"size": 227
}
],
"format": "faset.export",
"generation": "66191118-07cc-477b-9dc7-1e870be5ebc3",
"platform": "windows",
"prerequisites": [
"Windows x64",
"Vulkan 1.3 driver",
"Microsoft Visual C++ x64 Redistributable (Visual Studio 2022 or newer)"
],
"renderer_profile": {
"api": "Vulkan 1.3",
"materials": [
"base-color factor and texture",
"metallic and roughness factors"
],
"required_features": [
"dynamicRendering",
"synchronization2"
],
"shadow_map": {
"resolution": 1024,
"world_extent": 40
},
"texture_sampling": "linear clamp, one mip level",
"unsupported_material_features": [
"normal maps",
"metallic-roughness maps",
"emissive and occlusion maps",
"alpha mode selection",
"unlit mode",
"per-material face culling"
]
},
"scene_hash": "ee12794145c14ba5b599c5d9ae21648cccdfa91c47ee7742549f60d5fe7bc3e0",
"simulation": {
"fixed_delta": 0.016666666666666666,
"gravity": [
0,
-9.81,
0
],
"max_catch_up_ticks": 4,
"physics_substeps": 4
},
"units": {
"angle": "radian",
"coordinates": "right-handed Y-up",
"distance": "metre"
},
"validation_log": "warning: material material-bb63b094febbf90bb7049c9bcf7587bc has features beyond the initial base-color/PBR renderer\r\n{\"dimension\":3,\"validated\":true}\r\n",
"version": 1
}
@@ -0,0 +1,18 @@
{
"arguments": [
"C:\\Users\\runneradmin\\AppData\\Local\\Temp\\faset-playable-exports-8qma4esl\\Faset Café 世界\\collect-3d\\faset_player.exe",
"--headless",
"--frames",
"120",
"--capture",
"C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-8qma4esl\\Faset Café 世界\\collect-3d\\verification.ppm",
"--profile",
"C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-8qma4esl\\Faset Café 世界\\collect-3d\\profile.json"
],
"cwd": "C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-8qma4esl\\empty-working-directory",
"seconds": 2.312999999999988,
"exit_code": 0,
"timed_out": false,
"stdout": "New round: collect the three gold cubes, then reach the green exit. E resets.\n{\"device\":\"SwiftShader Device (LLVM 10.0.0)\",\"dimension\":3,\"frames\":120,\"ticks\":120,\"validation_errors\":0}\n",
"stderr": "[Faset] Vulkan validation layer/debug-utils unavailable; validation disabled.\nwarning: material material-bb63b094febbf90bb7049c9bcf7587bc has features beyond the initial base-color/PBR renderer\n"
}
@@ -0,0 +1,12 @@
{
"arguments": [
"C:\\Users\\runneradmin\\AppData\\Local\\Temp\\faset-playable-exports-8qma4esl\\Faset Café 世界\\collect-3d\\faset_player.exe",
"--validate"
],
"cwd": "C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-8qma4esl\\empty-working-directory",
"seconds": 0.01599999999996271,
"exit_code": 0,
"timed_out": false,
"stdout": "{\"dimension\":3,\"validated\":true}\n",
"stderr": "warning: material material-bb63b094febbf90bb7049c9bcf7587bc has features beyond the initial base-color/PBR renderer\n"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

@@ -0,0 +1,250 @@
{
"format": "faset.validation-evidence",
"version": 1,
"status": "passed",
"scope": "Hosted Windows developer build, first-project UI contracts, software Vulkan and relocated Release games",
"source_checkout": {
"commit": "4cb82556de31268d2bde73948dd1ff1b6c02f162",
"fresh_checkout": true,
"clean_commit_match": true,
"checkout_step": "actions/checkout on a fresh GitHub-hosted runner; engine and game targets configured and built in this job"
},
"ci": {
"run_url": "https://github.com/emil28092005/Faset_Engine/actions/runs/35301244334",
"job_url": "https://github.com/emil28092005/Faset_Engine/actions/runs/35301244334/job/105465851154",
"started_utc": "2026-09-18T03:04:44Z",
"finished_utc": "2026-09-18T03:19:49Z",
"conclusion": "success",
"steps": [
{
"name": "Set up job",
"conclusion": "success"
},
{
"name": "Run actions/checkout@11d5960a326750d5838078e36cf38b85af677262",
"conclusion": "success"
},
{
"name": "Run actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065",
"conclusion": "success"
},
{
"name": "Visual Studio x64 environment",
"conclusion": "success"
},
{
"name": "Enable the documented Windows long-path developer profile",
"conclusion": "success"
},
{
"name": "Identify pinned Vulkan source cache",
"conclusion": "success"
},
{
"name": "Restore pinned Vulkan test tools",
"conclusion": "success"
},
{
"name": "Build official Vulkan loader and SwiftShader from pinned sources",
"conclusion": "success"
},
{
"name": "Save successfully built Vulkan test tools",
"conclusion": "skipped"
},
{
"name": "Probe Vulkan loader and SwiftShader before compiling the engine",
"conclusion": "success"
},
{
"name": "Fetch checksum-verified Slang compiler",
"conclusion": "success"
},
{
"name": "Configure full editor and Player",
"conclusion": "success"
},
{
"name": "Build full editor and tests",
"conclusion": "success"
},
{
"name": "CPU contracts and software GPU pixel tests",
"conclusion": "success"
},
{
"name": "Real Release exports, 2D and 3D execution, incremental Debug rebuild",
"conclusion": "success"
},
{
"name": "Export and relocate both checked-in playable games",
"conclusion": "success"
},
{
"name": "Preserve graphics and export evidence",
"conclusion": "success"
},
{
"name": "Post Run actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065",
"conclusion": "success"
},
{
"name": "Post Run actions/checkout@11d5960a326750d5838078e36cf38b85af677262",
"conclusion": "success"
},
{
"name": "Complete job",
"conclusion": "success"
}
]
},
"environment": {
"runner_label": "windows-2025",
"observed_setup": [
"Microsoft Windows Server 2025",
"Image: windows-2025-vs2026",
"Version: 20260907.229.1",
"-- The CXX compiler identification is Clang 20.1.8 with MSVC-like command-line"
],
"compiler": "Clang 20.1.8 clang-cl, x64 MSVC ABI",
"editor_configuration": "Debug, FASET_DEBUG_IMGUI=ON",
"export_configuration": "Release, independent Ninja build with custom project C++ sources",
"windows_long_paths_enabled": true,
"device": "SwiftShader Device (LLVM 10.0.0)",
"validation_layer_available": false
},
"tests": {
"total": 35,
"passed": 35,
"failed": 0,
"skipped": 0,
"details": "tests.json"
},
"first_project_evidence": {
"test": "editor_ui_launcher",
"observed": "Create/Open through the instrumented launcher, Unicode paths, recents, directory browsing, validation and keyboard navigation; actual retained UI and software-rendered frame"
},
"games": [
{
"name": "collect-2d",
"generation": "260a10cf-3fe6-4689-ac7b-69b577954cc2",
"configuration": "Release",
"frames": 120,
"validation_enabled": false,
"validation_errors": 0,
"source_paths_hidden": true,
"capture": {
"width": 1280,
"height": 720,
"sampled_colors": 7,
"sha256": "f9d74067d87c1ebf30c6db372a26d93b7285791c8cb0307a24af5adb23bf201a"
},
"export_compiler_evidence": [
"-- The C compiler identification is Clang 20.1.8 with MSVC-like command-line",
"-- The CXX compiler identification is Clang 20.1.8 with MSVC-like command-line"
]
},
{
"name": "collect-3d",
"generation": "66191118-07cc-477b-9dc7-1e870be5ebc3",
"configuration": "Release",
"frames": 120,
"validation_enabled": false,
"validation_errors": 0,
"source_paths_hidden": true,
"capture": {
"width": 1280,
"height": 720,
"sampled_colors": 43,
"sha256": "0edc88eef9f641a780ef44664f58c811a22bd201c8d29e1fcb7531b88f251900"
},
"export_compiler_evidence": [
"-- The C compiler identification is Clang 20.1.8 with MSVC-like command-line",
"-- The CXX compiler identification is Clang 20.1.8 with MSVC-like command-line"
]
}
],
"limitations": [
"Software Vulkan on a GitHub-hosted Windows Server VM, not a physical desktop GPU qualification or performance benchmark.",
"Khronos validation layer is absent. Zero reported validation errors does not establish validation-layer coverage.",
"Fresh developer-toolchain setup and first-project tests are covered; no retail installer or manual OS IME composition acceptance is claimed."
],
"original_ci_log_sha256": "ada23530651f10bba0e4aec1e0bbe3f4ba243c6dbf9dd5416a744598b4988552",
"retained_files": [
{
"path": "collect-2d-manifest.json",
"sha256": "53b70e2ffc6e4c455fa5cad21eee2735f1c3182e83ed3051b6b5457cb11af615",
"size": 4315
},
{
"path": "collect-2d-run.json",
"sha256": "c65e56ff39059612afb9456f26c2bd0674e883057f60551216875643d6a349cd",
"size": 993,
"original_artifact_sha256": "9dcc203502d2504ffcc9dcfed4ecde118bda954ee8d4604e0b6992839390b731",
"original_artifact_size": 1011
},
{
"path": "collect-2d-validate.json",
"sha256": "9d94363e13ac5df29f2a236356384564dcab3b73115d8e65f02b891ee655805f",
"size": 434,
"original_artifact_sha256": "ffd23bb53b1d0f7da885ec40f6ab932f3aee3cc17afc3c620abc16ec4a661d4c",
"original_artifact_size": 446
},
{
"path": "collect-2d.png",
"sha256": "c380583f2fd8bc09c5b0e1c6e755c35c3d64b5385ed66177b04d1bbdb532b236",
"size": 4525
},
{
"path": "collect-3d-manifest.json",
"sha256": "4f86450eec32e773fbdbfa93d0da69abab3056cf869b6fa1b4e4647fe27ccc3d",
"size": 5923
},
{
"path": "collect-3d-run.json",
"sha256": "3dbf47e49bb1a27f68e1ffd222b2251a270469942cb20b08415f619a33b3c6c6",
"size": 1109,
"original_artifact_sha256": "cd21db5286b96f4d4a9a3e381563797230d0b1d8cdd8fbfb644eb272e9b82af6",
"original_artifact_size": 1127
},
{
"path": "collect-3d-validate.json",
"sha256": "f15afce2a5248a0e74179bc69a4b653976ecc07ad7e28cb29669b07bfe89297c",
"size": 550,
"original_artifact_sha256": "6dedaca4e4ffa573b7991856e5f3464bf93f6e825192ad4c4d35693d731531ad",
"original_artifact_size": 562
},
{
"path": "collect-3d.png",
"sha256": "48ef9a82378f74e8ad5a0c438bb730773d684cce809afcef461756a38476375e",
"size": 20366
},
{
"path": "playable-report.json",
"sha256": "e3e6743832ce6fd216b3352609d80ce1de63ec1c2c58c58034bd361967cb7a5d",
"size": 14093,
"original_artifact_sha256": "3783533ba50b9b4b2fe29fa3e13cbaf7c43b96d29dce8365fa72ae014bc960f1",
"original_artifact_size": 14528
},
{
"path": "probe.json",
"sha256": "fbc4c5f01a5d23c901fbdab366537da331002709bfbce42e06a84b1a64a1b396",
"size": 987,
"original_artifact_sha256": "0c85c12510dbb0d895faefb7d14f26935a5add675cf0477b29f543d72eed40d6",
"original_artifact_size": 1019
},
{
"path": "tests.json",
"sha256": "1115633850520f66159d204210249bd5eacf57e5b0f9c5f5f70834cd149a0634",
"size": 4731
},
{
"path": "toolchain.json",
"sha256": "daf1ce634e438ff9cd3a84a2c21313f3530279dfb27f15acf8b217833e06548d",
"size": 914,
"original_artifact_sha256": "969162d1f994724ff6f98d20353e62e3881477ebce98759ca325c8febb175176",
"original_artifact_size": 937
}
],
"retained_file_hash_basis": "Repository bytes with LF text line endings. Where normalization changed original Windows artifact bytes, original_artifact_sha256 and original_artifact_size preserve their original provenance."
}
@@ -0,0 +1,435 @@
{
"format": "faset.playable-export-verification",
"version": 1,
"started_utc": "2026-09-18T03:15:38.883680+00:00",
"platform": "win32",
"engine": "D:\\a\\Faset_Engine\\Faset_Engine",
"editor": "D:\\a\\Faset_Engine\\Faset_Engine\\build\\windows-debug\\faset_editor.exe",
"standalone_root": "C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-8qma4esl",
"frames_per_game": 120,
"status": "passed",
"projects": [
{
"name": "collect-2d",
"dimension": 2,
"source_inputs": [
{
"path": ".gitignore",
"sha256": "3bb936ff6f84f3db041c75d6e207138a9107997cc9ad372621f657456c9c0665"
},
{
"path": "project.faset.json",
"sha256": "27bd0e432381f8f884e78f6d68e9d0dc13d49222e70f3a5e34fef1d57d379b0b"
},
{
"path": "README.md",
"sha256": "7543b24c9ac87d6a7390d61d5289518e5f5725f3c0052675659f6da716883bdd"
},
{
"path": "Scenes/main.scene.json",
"sha256": "9e2ad049f60a9ff7f98e31061a8f107648fbf672e5b9292f53e6672e5bae66f1"
},
{
"path": "Scripts/Gameplay.cpp",
"sha256": "99fb965e6589b138049a2e6cf95c5c61baea70761ffab33082a8058c91a687ff"
},
{
"path": "Scripts/Gameplay.hpp",
"sha256": "9d1fa36da50886fa7d84f8a8b3d1ae42856ae74aae1e52be5015b60977634dc0"
}
],
"generation": "260a10cf-3fe6-4689-ac7b-69b577954cc2",
"configuration": "Release",
"standalone_directory": "C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-8qma4esl\\Faset Café 世界\\collect-2d",
"executable": "faset_player.exe",
"package_file_count": 18,
"asset_generations": {},
"device": "SwiftShader Device (LLVM 10.0.0)",
"validation_enabled": false,
"validation_errors": 0,
"completed_frames": 120,
"summary_ms": {
"gpu": {
"max": 129.9081,
"min": 1.8272,
"p50": 2.0341,
"p95": 2.6394,
"samples": 120
},
"render_call": {
"max": 131.02,
"min": 2.0275,
"p50": 2.2678,
"p95": 2.8731,
"samples": 120
},
"renderer_cpu": {
"max": 130.9907,
"min": 2.0248,
"p50": 2.2649,
"p95": 2.869,
"samples": 120
},
"renderer_readback_cpu": {
"max": 0.9709,
"min": 0.1456,
"p50": 0.155,
"p95": 0.1856,
"samples": 120
},
"simulation": {
"max": 0.4173,
"min": 0.267,
"p50": 0.2905,
"p95": 0.3238,
"samples": 120
},
"snapshot": {
"max": 0.4839,
"min": 0.1555,
"p50": 0.2226,
"p95": 0.2468,
"samples": 120
},
"wall": {
"max": 132.1731,
"min": 2.5367,
"p50": 2.7893,
"p95": 3.4346,
"samples": 120
}
},
"capture": {
"width": 1280,
"height": 720,
"sampled_colors": 7,
"sha256": "f9d74067d87c1ebf30c6db372a26d93b7285791c8cb0307a24af5adb23bf201a"
},
"source_project_paths_unavailable": true,
"status": "passed"
},
{
"name": "collect-3d",
"dimension": 3,
"source_inputs": [
{
"path": ".gitignore",
"sha256": "3bb936ff6f84f3db041c75d6e207138a9107997cc9ad372621f657456c9c0665"
},
{
"path": "Assets/exit-arch/create.py",
"sha256": "5d9dc30a3f939376d2474cf958065e6daab140c7220444cedecd3bf5edf6e3d1"
},
{
"path": "Assets/exit-arch/manifest.json",
"sha256": "d72d44184d665148109de74782bc695d79392e43be12782e48096a7d79e37c4f"
},
{
"path": "Assets/exit-arch/manifest.json.faset-import.json",
"sha256": "7639d4fa33f2ac52e10d1cf79280a93aeb680399d217fda167acec1c6edcae00"
},
{
"path": "Assets/exit-arch/payload/ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3.glb",
"sha256": "ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3"
},
{
"path": "Assets/exit-arch/source.blend",
"sha256": "ff2676bec97ab778e531e87a185ad716049ea3b05b4a4f0027a6345737735035"
},
{
"path": "project.faset.json",
"sha256": "9a0ee78fa0ea56982a99cf707948a33db37266ab84de9d3f12a24aabb98afda5"
},
{
"path": "README.md",
"sha256": "a2378adc9dbd5ffb6bfa65abb7770051827d08279e48761046f30d932a5eab8c"
},
{
"path": "Scenes/main.scene.json",
"sha256": "b1b668a2d633deda0074b475460c82019dbcf592b76502906192eaf1f2345a7e"
},
{
"path": "Scripts/Extensions/Beacon.hpp",
"sha256": "650e75bbc55a3339647bcf67ba10fd9b20cece3531bb688b4221155e97959d5e"
},
{
"path": "Scripts/Gameplay.cpp",
"sha256": "c76fbb0bf28a85cc88732a905f2bc9be3e24c58d02cbf2ecccbf77c99093c029"
},
{
"path": "Scripts/Gameplay.hpp",
"sha256": "9d1fa36da50886fa7d84f8a8b3d1ae42856ae74aae1e52be5015b60977634dc0"
}
],
"import": {
"asset_id": "5832763b-3ed0-44d6-9088-0b524f196a91",
"cache_hit": false,
"diagnostics": [],
"generation": "e8eb8805673cc22596d1c5b48fc6b8fbdf600d1c6a15c9633d14014a7eb1d11f",
"manifest": {
"asset_id": "5832763b-3ed0-44d6-9088-0b524f196a91",
"files": [
{
"path": "meshes/mesh-fc069a07a87e0f831fd92efdbc4efa1f-0.fmesh",
"sha256": "98b38aca7d2786c58a2265ba4d1f2255123f03d31d947e239232cf55bfdc2c97",
"size": 928
},
{
"path": "meshes/mesh-0961e2a3f92977836a3aa80cab09277e-0.fmesh",
"sha256": "98b38aca7d2786c58a2265ba4d1f2255123f03d31d947e239232cf55bfdc2c97",
"size": 928
},
{
"path": "meshes/mesh-93b5b3e52cb6bb120fefb80e2d8e222b-0.fmesh",
"sha256": "3875c16ea628d4126373ebfe07816621fbad3961596a2fcd112f1eec0e378071",
"size": 928
}
],
"generation": "e8eb8805673cc22596d1c5b48fc6b8fbdf600d1c6a15c9633d14014a7eb1d11f",
"importer": "faset-gltf-1/cgltf-1.15",
"input_key": {
"bundle_sha256": "d72d44184d665148109de74782bc695d79392e43be12782e48096a7d79e37c4f",
"dependencies": {},
"importer": "faset-gltf-1/cgltf-1.15",
"settings": {},
"source": "ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3",
"target_profile": "desktop-static-pbr-v1",
"toolchain": {
"cgltf": "360db1a95480fe102ae9c69b27c5d101167ff5ba",
"stb": "2c980bb59875b0d32144a71867fbdebb2f77cd20"
}
},
"kind": "scene",
"materials": [
{
"alpha_cutoff": 0.5,
"alpha_mode": "OPAQUE",
"base_color": [
0.2199999988079071,
0.28999999165534973,
0.3400000035762787,
1.0
],
"base_color_texture": -1,
"double_sided": true,
"emissive": [
0.0,
0.0,
0.0
],
"emissive_texture": -1,
"format": "faset.material",
"id": "material-bb63b094febbf90bb7049c9bcf7587bc",
"metallic": 0.07999999821186066,
"metallic_roughness_texture": -1,
"name": "Weathered stone",
"normal_texture": -1,
"occlusion_texture": -1,
"roughness": 0.800000011920929,
"unlit": false,
"version": 1
}
],
"meshes": [
{
"id": "mesh-fc069a07a87e0f831fd92efdbc4efa1f",
"name": "Cube.001",
"primitives": [
{
"material": 0,
"path": "meshes/mesh-fc069a07a87e0f831fd92efdbc4efa1f-0.fmesh"
}
]
},
{
"id": "mesh-0961e2a3f92977836a3aa80cab09277e",
"name": "Cube.002",
"primitives": [
{
"material": 0,
"path": "meshes/mesh-0961e2a3f92977836a3aa80cab09277e-0.fmesh"
}
]
},
{
"id": "mesh-93b5b3e52cb6bb120fefb80e2d8e222b",
"name": "Cube.003",
"primitives": [
{
"material": 0,
"path": "meshes/mesh-93b5b3e52cb6bb120fefb80e2d8e222b-0.fmesh"
}
]
}
],
"nodes": [
{
"id": "node-cec6e8cea80cf5a98ba3263a0156bee4",
"local_transform": [
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.4500000476837158,
1.2999999523162842,
1.0
],
"mesh": 0,
"name": "Left post",
"parent_id": "",
"stable_source_id": true
},
{
"id": "node-5f8a90a6c4d27020d20bd4fa81d1d958",
"local_transform": [
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.4500000476837158,
-1.2999999523162842,
1.0
],
"mesh": 1,
"name": "Right post",
"parent_id": "",
"stable_source_id": true
},
{
"id": "node-482463e486a8d1fd741340c653cd128f",
"local_transform": [
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
3.0,
0.0,
1.0
],
"mesh": 2,
"name": "Lintel",
"parent_id": "",
"stable_source_id": true
}
],
"outputs": [
"node-cec6e8cea80cf5a98ba3263a0156bee4",
"node-5f8a90a6c4d27020d20bd4fa81d1d958",
"node-482463e486a8d1fd741340c653cd128f",
"mesh-fc069a07a87e0f831fd92efdbc4efa1f",
"mesh-0961e2a3f92977836a3aa80cab09277e",
"mesh-93b5b3e52cb6bb120fefb80e2d8e222b",
"material-bb63b094febbf90bb7049c9bcf7587bc"
],
"payload_source": "D:\\a\\Faset_Engine\\Faset_Engine\\.cache\\windows-playable-exports\\Faset Café 世界\\collect-3d\\Assets\\exit-arch\\payload/ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3.glb",
"schema_version": 1,
"settings": {},
"source": "D:\\a\\Faset_Engine\\Faset_Engine\\.cache\\windows-playable-exports\\Faset Café 世界\\collect-3d\\Assets\\exit-arch\\manifest.json",
"source_sha256": "ee6c748a212905fc9c465cbe95c033e94b80be643624f4f240ad5353761205b3",
"textures": []
},
"previous_generation": "",
"removed_output_ids": []
},
"generation": "66191118-07cc-477b-9dc7-1e870be5ebc3",
"configuration": "Release",
"standalone_directory": "C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\faset-playable-exports-8qma4esl\\Faset Café 世界\\collect-3d",
"executable": "faset_player.exe",
"package_file_count": 23,
"asset_generations": {
"5832763b-3ed0-44d6-9088-0b524f196a91": "e8eb8805673cc22596d1c5b48fc6b8fbdf600d1c6a15c9633d14014a7eb1d11f"
},
"device": "SwiftShader Device (LLVM 10.0.0)",
"validation_enabled": false,
"validation_errors": 0,
"completed_frames": 120,
"summary_ms": {
"gpu": {
"max": 203.9357,
"min": 14.9149,
"p50": 15.2496,
"p95": 18.9976,
"samples": 120
},
"render_call": {
"max": 205.0598,
"min": 15.1706,
"p50": 15.5334,
"p95": 19.2678,
"samples": 120
},
"renderer_cpu": {
"max": 205.0432,
"min": 15.166,
"p50": 15.5286,
"p95": 19.2578,
"samples": 120
},
"renderer_readback_cpu": {
"max": 0.8953,
"min": 0.1466,
"p50": 0.1597,
"p95": 0.2174,
"samples": 120
},
"simulation": {
"max": 0.5335,
"min": 0.3274,
"p50": 0.4679,
"p95": 0.5036,
"samples": 120
},
"snapshot": {
"max": 3.3124,
"min": 0.1893,
"p50": 0.2114,
"p95": 0.2532,
"samples": 120
},
"wall": {
"max": 209.6105,
"min": 15.8408,
"p50": 16.2166,
"p95": 19.948,
"samples": 120
}
},
"capture": {
"width": 1280,
"height": 720,
"sampled_colors": 43,
"sha256": "0edc88eef9f641a780ef44664f58c811a22bd201c8d29e1fcb7531b88f251900"
},
"source_project_paths_unavailable": true,
"status": "passed"
}
],
"finished_utc": "2026-09-18T03:19:42.166192+00:00"
}
@@ -0,0 +1,32 @@
{
"format": "faset.windows-vulkan-probe",
"version": 1,
"status": "passed",
"loader": "D:\\a\\Faset_Engine\\Faset_Engine\\.cache\\windows-graphics\\sdk\\bin\\vulkan-1.dll",
"driver_manifest": "D:\\a\\Faset_Engine\\Faset_Engine\\.cache\\windows-graphics\\driver\\vk_swiftshader_icd.json",
"driver_library": "D:\\a\\Faset_Engine\\Faset_Engine\\.cache\\windows-graphics\\driver\\vk_swiftshader.dll",
"manifest": {
"file_format_version": "1.0.0",
"ICD": {
"library_path": ".\\vk_swiftshader.dll",
"api_version": "1.0.5"
}
},
"loader_debug": "all",
"pointer_bits": 64,
"icd_negotiate_result": 0,
"icd_interface_version": 7,
"enumerate_version_result": 0,
"loader_api_version": "1.4.341",
"create_instance_result": 0,
"devices": [
{
"name": "SwiftShader Device (LLVM 10.0.0)",
"api_version": "1.3.0",
"driver_version": 20971520,
"vendor_id": 6880,
"device_id": 49374,
"device_type": 4
}
]
}
@@ -0,0 +1,206 @@
{
"format": "faset.ctest-summary",
"version": 1,
"source_commit": "4cb82556de31268d2bde73948dd1ff1b6c02f162",
"passed": 35,
"failed": 0,
"skipped": 0,
"source_log_sha256": "1d2038ce1751098d5fe99cf3a8da9e743ce4bf1c0fa014613abbbd5dd6cedbe7",
"tests": [
{
"name": "authoring",
"status": "passed",
"seconds": 0.89
},
{
"name": "runtime_contracts",
"status": "passed",
"seconds": 0.21
},
{
"name": "assets_pipeline",
"status": "passed",
"seconds": 1.03,
"observations": [
"assets: geometry/PBR/texture, GLB/glTF, cache, rename, deletion, overrides, failure, cancellation, standalone PNG/JPEG OK"
]
},
{
"name": "assets_blender_bundle",
"status": "passed",
"seconds": 0.28
},
{
"name": "render_graph",
"status": "passed",
"seconds": 0.14
},
{
"name": "render_offscreen",
"status": "passed",
"seconds": 0.64
},
{
"name": "render_sprite_alpha",
"status": "passed",
"seconds": 0.26
},
{
"name": "render_shader_reload",
"status": "passed",
"seconds": 2.56
},
{
"name": "render_window_lifecycle",
"status": "passed",
"seconds": 1.03,
"observations": [
"driver=windows stage=created",
"stage=resized width=360 height=300 resize_events=2",
"clipboard=unicode_roundtrip_passed",
"text_input_area=coordinate_conversion_passed",
"stage=minimized fresh_frames=12 minimize_events=1 focus_lost_events=1",
"stage=restored restored_events=1 activation_required=0 frames=54 validation_enabled=0 validation_errors=0"
]
},
{
"name": "player_scene_contracts",
"status": "passed",
"seconds": 0.14
},
{
"name": "player_shutdown_diagnostics",
"status": "passed",
"seconds": 0.19
},
{
"name": "editor_mcp",
"status": "passed",
"seconds": 0.05
},
{
"name": "process_and_cook",
"status": "passed",
"seconds": 0.62
},
{
"name": "build_schema_publication",
"status": "passed",
"seconds": 6.47
},
{
"name": "editor_plugins",
"status": "passed",
"seconds": 0.17
},
{
"name": "editor_session_settings",
"status": "passed",
"seconds": 0.18
},
{
"name": "ui_widgets",
"status": "passed",
"seconds": 0.15
},
{
"name": "ui_render",
"status": "passed",
"seconds": 0.49
},
{
"name": "editor_ui_import_conflicts",
"status": "passed",
"seconds": 0.94
},
{
"name": "editor_ui_project_settings",
"status": "passed",
"seconds": 1.16
},
{
"name": "editor_ui_reload",
"status": "passed",
"seconds": 4.25
},
{
"name": "editor_ui_launcher",
"status": "passed",
"seconds": 0.67,
"observations": [
"Launcher Unicode/create/open/validation/recents/directory browser/keyboard passed. C:\\Users\\runneradmin\\AppData\\Local\\Temp\\faset-проекты-427259f4-0109-4b0c-b901-4af129291d3a"
]
},
{
"name": "editor_ui_templates",
"status": "passed",
"seconds": 2.88
},
{
"name": "editor_ui_gizmos",
"status": "passed",
"seconds": 1.15
},
{
"name": "editor_ui_authoring",
"status": "passed",
"seconds": 1.94
},
{
"name": "editor_mcp_stdio",
"status": "passed",
"seconds": 0.57
},
{
"name": "editor_gui_mcp",
"status": "passed",
"seconds": 4.77,
"observations": [
"Native GUI + MCP shared authoring, revision conflict, Undo, 12 fresh PNG captures and continued responsiveness passed"
]
},
{
"name": "core",
"status": "passed",
"seconds": 0.16
},
{
"name": "tutorial_moving",
"status": "passed",
"seconds": 0.03
},
{
"name": "tutorial_following",
"status": "passed",
"seconds": 0.02
},
{
"name": "tutorial_spawning",
"status": "passed",
"seconds": 0.04
},
{
"name": "tutorial_physics",
"status": "passed",
"seconds": 0.11
},
{
"name": "playable_2d",
"status": "passed",
"seconds": 0.62
},
{
"name": "playable_3d",
"status": "passed",
"seconds": 1.33
},
{
"name": "editor_debug_overlay",
"status": "passed",
"seconds": 0.22,
"observations": [
"ImGui diagnostics, F12, font atlas, clipping and event isolation passed"
]
}
]
}
@@ -0,0 +1,23 @@
{
"sources": {
"headers": {
"repository": "KhronosGroup/Vulkan-Headers",
"commit": "0d3f509e57041fbd073a1ee84cd9ccd36d148446",
"sha256": "e82005a6bd3289ce213232ef41e0f8722d1365ed72bf5cc4be56911c56bc30e0"
},
"loader": {
"repository": "KhronosGroup/Vulkan-Loader",
"commit": "32fcb949e253cbeb40cda7ea76122b492db579ae",
"sha256": "610fa9017226c49bc4f19398d94fce9e3c9ff94c14f6420f9fe24822707feacf"
},
"swiftshader": {
"repository": "google/swiftshader",
"commit": "1e80438d2b93ef36a7c05f8d2b81233bac0e3d16",
"sha256": "1c3a1afc397c7aa4d3275790bc9b451e80b144a1db665135d5519838bacf44a8"
}
},
"validation_layer": false,
"vulkan_sdk": "D:\\a\\Faset_Engine\\Faset_Engine\\.cache\\windows-graphics\\sdk",
"driver": "D:\\a\\Faset_Engine\\Faset_Engine\\.cache\\windows-graphics\\driver\\vk_swiftshader_icd.json",
"loader_only": false
}
+19
View File
@@ -0,0 +1,19 @@
# Lua playground
A Lua-only project: there is no project `Gameplay.cpp`. The native engine and Player
are built normally; the two gameplay behaviors are loaded from Lua source.
Open this folder as a project in the Editor, refresh Lua schemas, open
`Scenes/main.scene.json`, then Play. **A/D** or arrows move, **Space** jumps from
ground, and **E** resets the player. The gold beacon shows non-physical animation
and a shared `require("util.motion")` module.
Change `Scripts/player.lua` in an external editor and save. Development Play watches
Lua sources; a successful reload restarts the scene and resets script state. Invalid
source leaves the previous generation running and reports the error. Export copies
the captured Lua files into the game; a Lua executable or separately installed Lua
library is not needed.
Run `faset_lua_setup` through the Editor command palette to install the Faset LuaLS
declarations and, if absent, `.luarc.json`. See the
[Lua manual](../../docs/manual/scripting/lua.md) for the API and sandbox boundaries.
+71
View File
@@ -0,0 +1,71 @@
{
"format": "faset.scene",
"version": 1,
"id": "example-lua-scene",
"name": "Lua playground — A/D / Space / E",
"dimension": 2,
"simulation": {
"fixed_delta": 0.016666666666666666,
"max_catch_up_ticks": 4,
"physics_substeps": 4,
"gravity": [0, -9.81, 0]
},
"entities": [
{
"id": "floor", "name": "Ground", "parent": null,
"components": [
{
"id": "floor-transform", "type": "faset.transform", "version": 1,
"fields": {"position": [0, -0.5, 0]}
},
{
"id": "floor-sprite", "type": "faset.sprite", "version": 1,
"fields": {"size": [16, 1], "color": [0.2, 0.3, 0.4, 1]}
},
{
"id": "floor-body", "type": "faset.rigid_body_2d", "version": 1,
"fields": {"body_type": "static", "half_extents": [8, 0.5]}
}
]
},
{
"id": "player", "name": "Player", "parent": null,
"components": [
{
"id": "player-transform", "type": "faset.transform", "version": 1,
"fields": {"position": [-2, 1.5, 0]}
},
{
"id": "player-sprite", "type": "faset.sprite", "version": 1,
"fields": {"size": [0.8, 1], "color": [0.2, 0.75, 0.9, 1]}
},
{
"id": "player-body", "type": "faset.rigid_body_2d", "version": 1,
"fields": {"body_type": "dynamic", "half_extents": [0.4, 0.5], "friction": 0.3}
},
{
"id": "player-controller", "type": "example.lua_player", "version": 1,
"fields": {"move_speed": 5, "jump_speed": 7}
}
]
},
{
"id": "beacon", "name": "Beacon", "parent": null,
"components": [
{
"id": "beacon-transform", "type": "faset.transform", "version": 1,
"fields": {"position": [3, 2, 0]}
},
{
"id": "beacon-sprite", "type": "faset.sprite", "version": 1,
"fields": {"size": [0.5, 0.5], "color": [1, 0.7, 0.2, 1]}
},
{
"id": "beacon-behavior", "type": "example.lua_beacon", "version": 1,
"fields": {"amplitude": 0.3, "frequency": 0.7}
}
]
}
],
"instances": []
}
+27
View File
@@ -0,0 +1,27 @@
local motion = require("util.motion")
local Beacon = faset.behavior {
id = "example.lua_beacon",
version = 1,
name = "Lua Beacon",
fields = {
amplitude = { name = "Height", type = "number", default = 0.3, min = 0, max = 2 },
frequency = { name = "Frequency", type = "number", default = 0.7, min = 0, max = 5 }
}
}
function Beacon:on_start()
self.state.origin_y = self.entity:transform().position.y
self.state.elapsed = 0
end
function Beacon:update(delta)
self.state.elapsed = self.state.elapsed + delta
local pose = self.entity:transform()
pose.position.y = self.state.origin_y
+ motion.bob(self.state.elapsed, self.fields.frequency, self.fields.amplitude)
pose.rotation.z = self.state.elapsed
self.entity:set_transform(pose)
end
return Beacon
+47
View File
@@ -0,0 +1,47 @@
local Player = faset.behavior {
id = "example.lua_player",
version = 1,
name = "Lua Player",
fields = {
move_speed = {
name = "Move speed", type = "number", default = 5,
min = 0, max = 30, units = "m/s"
},
jump_speed = {
name = "Jump speed", type = "number", default = 7,
min = 0, max = 20, units = "m/s"
}
}
}
function Player:on_start()
self.state.origin = self.entity:transform()
self.state.jumps = 0
faset.log("Lua player ready: A/D move, Space jump, E reset")
end
function Player:fixed_update(delta)
local input = faset.input()
if input.interact_pressed then
self.entity:teleport(self.state.origin)
self.entity:set_velocity { x = 0, y = 0, z = 0 }
self.state.jumps = 0
return
end
local velocity = self.entity:velocity()
velocity.x = input.horizontal * self.fields.move_speed
if input.jump_pressed and self.entity:is_grounded() then
velocity.y = self.fields.jump_speed
self.state.jumps = self.state.jumps + 1
faset.log("Jump", self.state.jumps)
end
self.entity:set_velocity(velocity)
if self.entity:transform().position.y < -10 then
self.entity:teleport(self.state.origin)
self.entity:set_velocity { x = 0, y = 0, z = 0 }
end
end
return Player
+7
View File
@@ -0,0 +1,7 @@
local motion = {}
function motion.bob(time, frequency, amplitude)
return math.sin(time * frequency * 2 * math.pi) * amplitude
end
return motion
+13
View File
@@ -0,0 +1,13 @@
{
"format": "faset.project",
"version": 1,
"id": "example-lua-project",
"name": "Lua playground",
"dimension": 2,
"start_scene": "Scenes/main.scene.json",
"scripting": {
"lua": {
"scripts": ["Scripts/player.lua", "Scripts/beacon.lua"]
}
}
}
+1 -1
View File
@@ -41,7 +41,7 @@ The Player window title and console identify the controls and objective; the gam
`project.faset.json` chooses `Scenes/main.scene.json`. The scene stores object/component IDs, transforms, physics settings, and entity references in the collector component. `Scripts/Gameplay.cpp` owns the round's transient C++ state and registers its editable schema. `speed` and `jump_speed` use metres per second.
Change JSON and restart Play to see new level data. Change C++ or its schema, then stop, build, and restart; C++ hot reload is not implemented. Runtime pickup progress does not rewrite the authoring scene or create Undo entries.
Edit the scene through the Inspector and restart Play to see new level data. Change C++ or its schema, then stop, build, and restart; C++ hot reload is not implemented. Runtime pickup progress does not rewrite the authoring scene or create Undo entries.
## Verify
+3
View File
@@ -66,6 +66,9 @@ class AssetPipeline : public AssetStore {
explicit AssetPipeline(std::filesystem::path cache_root);
ImportResult import_asset(const ImportRequest& request, ImportJob& job);
ImportResult import_asset(const ImportRequest& request);
// Inspect source/recipe/dependency hashes without importing or changing the
// active generation. Only editor tools need source freshness; Player does not.
Json freshness(const std::string& asset_id) const;
// Overrides are authoring data beside the source, never generated cache contents.
Json overrides(const std::string& asset_id) const;
void set_overrides(const std::string& asset_id, const Json& overrides);
+3
View File
@@ -56,5 +56,8 @@ template <class T> class TypeRegistration {
Json schema_;
};
SchemaRegistry builtin_schemas();
// Validate a gameplay schema array/types manifest, reserving native TypeIds and
// rejecting repeated gameplay TypeIds. The result includes built-in schemas.
SchemaRegistry gameplay_schemas(const Json& manifest);
void validate_field(const Json& value, const Json& descriptor);
} // namespace faset::authoring
+5
View File
@@ -36,4 +36,9 @@ class Process {
std::unique_ptr<Impl> impl_;
};
std::filesystem::path find_executable(const std::string& name);
// Launch an explicitly selected external application without an owning Process/job.
// UTF-8 arguments remain literal (no shell); inherited environment, discarded stdio.
// This does not grant permission to execute arbitrary project files as programs.
void launch_detached(const std::vector<std::string>& arguments,
const std::filesystem::path& working_directory = {});
} // namespace faset

Some files were not shown because too many files have changed in this diff Show More