Frame Studio
- Gaussian splats (PLY, SPZ v2-v4), PLY vertex colours, panorama skies
- Copy, cut, paste and duplicate for objects, splats and world items
- Walkable-area rebake moved off the UI thread; viewport one frame sooner;
refresh-locked pacing (FS_PACE=timer for the old one)
- Fixed: bundle thumbnail use-after-free crash, auto-save deleting
environments, saves into scratch copies, edits lost on non-ASCII paths,
unopenable manifests with inf/nan, bundle save data loss, opening a home
marking it changed, gizmo NaN, long paths, many malformed-file crashes
- Updater verifies sha256, journals the swap and never leaves the exe missing
Frame Home
- Seats turn you to face their way
- Draw batching (Hand Tutorials up to ~20% less GPU time), cut-out EQUAL pass,
late head-pose read before submit
- Proper queue-family hand-over to the compositor layer; layer descriptor
generations and seqlocked slots; structural SPIR-V check
- Fixed: hangs/crashes on damaged .fenv files and shaders, render-pass
validation error, sync hazard in the foveation smoothing pass, unverified
update downloads, half-done installs
Tests: tests_loco/env_share/spv_check wired into CMake (FRAME_TESTS) and CI.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VsaXGU27gsrXjDoFtyFJP9
The PC compositor-layer work (the Direct3D 11 proxy, its installer, its notes) now lives in pc-streaming/, clearly
separate and marked experimental, so the main project is the Steam Frame build and the fixes that help it. The PC
layer can't change the Steam Frame's home (the Steam Frame renders it on the headset), and this keeps it from
crowding the Steam Frame release while preserving it for a tethered PC headset.
The shared Windows renderer support (src/, behind #ifdef _WIN32 / FRAME_HOME_PC) stays put: it only compiles into a
PC build and never touches the Steam Frame build. Build and README references updated to the new paths.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A probe in vrserver and the device/draw diagnostics established that the Steam Frame renders its home on the headset,
not on the PC (the compositor draws nothing, the vrlink streaming driver makes no environment shaders), so a PC-side
layer can't change its home. Kept as the record of that investigation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The compositor records its environment on a deferred D3D11 context, a different object with its own vtable than the
immediate context we hooked — so our draw hooks never saw it and the home never replaced Aurora (connected, but 0
draws). Hook every context's vtable: the immediate one, and each deferred one as CreateDeferredContext /
CreateDeferredContext1 makes it, keeping each vtable's own original draw/PSSetShader so calls dispatch correctly.
classify and the constant-buffer upload now work on whichever context records the draw.
Also fix the crash guard false-tripping: it armed when Frame Home connected and disarmed only after 30 drawn frames,
so when the home never drew (this very bug) every compositor restart counted as a crash and it wrote . Arm only
once we actually swap a draw, so never-drawing can't be mistaken for crashing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
On a real headset the layer connected but replaced nothing, so the compositor draws its environment through a path
the layer wasn't catching. Track the bound pixel shader per device context (not only the immediate one we hooked, in
case the environment is recorded on a deferred context), name every pixel shader from its .fxo, and the first time
each is drawn log its name and whether it was on our context or another. The 5-second heartbeat now always prints
(home draws, distinct shaders seen here/other, connected). This makes one short headset session show exactly which
shaders and context the environment uses, to aim the fix. The diagnostic stops itself after a few seconds of draws.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
On the Steam Frame a layer inside SteamVR's compositor draws the home where it would draw Aurora, so the home is the
environment itself: at boot, during game loads, behind the Steam menu, with the controllers and passthrough, and it
steps aside for a game the instant it opens. On a PC this was faked with SteamVR's home-app slot and a flat 360 photo
in the gaps, which launched and handed off like an app and showed a picture, not the live home. This does it properly
on any PC that runs SteamVR, the Frame's way:
- Windows: the compositor is Direct3D 11, so the layer is a proxy d3d11.dll beside the compositor (layer/
frame_home_layer_d3d11.cpp, built from the .def that forwards every other export to the real d3d11.dll, kept as
fh_d3d11real.dll). It wraps the compositor's device, finds Aurora's draws by their shader bytecode and draws the
home over the sky, leaving the floor and stars off; everything else passes straight through. Pure pass-through in
any process that isn't vrcompositor.
- The home's frames cross from Frame Home (Vulkan) to the compositor (D3D11): the layer owns kSlots shared textures
and hands Frame Home their NT handles over a named pipe; Frame Home imports them (VK_KHR_external_memory_win32) and
renders into them. No cross-API lock — a slot is published only once the GPU has finished it and the four rotate,
as on Linux. The shared State stays Frame Home's.
- The Environments panel runs frame-home --system and keeps it alive (one at a time, a pid file across panel
restarts), the same systemEnv path as the Frame. The installer places/removes the proxy and marks the layer with a
root/layer folder, in place of the old home-app registration and background pictures.
- Safe like the Vulkan layer: no home, or one stale over half a second, and the compositor draws Aurora as usual;
the layer turns itself off after two unhealthy compositor starts, and root/layer/off turns it off by hand.
Linux keeps its Vulkan layer (unchanged). Verified without a headset on the null driver: the proxy loads and wraps
the compositor without crashing, recognises Aurora's shaders, and the frame hand-over completes (Frame Home connects,
imports the textures, renders). The compositor only draws the environment while presenting to a headset, so the final
on-headset image is the one step the null driver can't exercise.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Frame Studio now builds for Windows (x64, x86, ARM64), Linux (x64, x86, ARM64)
and macOS (Apple Silicon, Intel):
- studio/platform.h with Win32 and POSIX implementations (dialogs through
tinyfiledialogs on Linux/macOS), a GLFW window beside the Win32 one, and a
platform-neutral frame pacer
- MoltenVK support in the renderer (portability enumeration) and bundled in
the macOS app
- 32-bit builds: large-address-aware, LZMA packing within a 32-bit address space
- unaligned file reads in the loaders go through loadUnaligned (no UB)
- scripts/build-studio.sh, studio/build_windows.bat [x64|x86|arm64],
cmake/llvm-mingw.cmake, and a GitHub Actions workflow building every target
Frame Home installs without Studio: frame/install-frame-home.{sh,ps1} and
"Install Frame Home.bat" (packaged as FrameHome-installer.zip).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>