Conversation
…pt-in) Adds two independent, opt-in audio subsystems and fixes several latent bugs found while wiring them up. WHAT - FMOD Engine as an alternative playback backend (--fmod, LUX_ENABLE_FMOD). AudioEngine/AudioSource/AudioListener now compile against either miniaudio (default) or FMOD Core, selected by #ifdef within each .cpp, so call sites never see the backend and the default build has no FMOD dependency. AudioEngine::Update() pumps FMOD::System::update() once per frame from Application::Run; it is a no-op under miniaudio. - RaytracedAudioScene (--raytraced-audio, LUX_ENABLE_RAYTRACED_AUDIO): wraps the Vercidium Audio SDK behind a Pimpl. One VAWorld per Scene, created on OnRuntimeStart, mirroring static MeshCollider geometry and tracking one emitter per AudioSourceComponent. Its per-source occlusion/reverb results feed FMOD's Channel::set3DOcclusion / setReverbProperties. Built without the SDK every method is a no-op, matching the DiscordSocial pattern. Both SDKs are proprietary and gitignored; their EULAs forbid redistributing the SDK itself, so they are fetched manually. Configure.py warns when a feature is enabled without its SDK present. BUGS FIXED ALONG THE WAY - AudioSourceComponent/AudioListenerComponent were never serialized, and a legacy-schema guard hard-rejected any scene containing them. Both now round-trip through SceneSerializer. - The same two components were missing from AllComponents/DuplicateComponents, so Scene::Copy silently dropped them on Play - audio could never work at runtime regardless of backend. - AttenuationModel was emitted as uint8_t; yaml-cpp writes unsigned char as a *character*, so saving a scene with an audio source wrote a raw control byte and corrupted the .luxscene. Now uint32_t both directions. - VA emitters default to zero rays of every type, so sources produced no occlusion or reverb at all. Ray counts are now set explicitly. - GetResult() segfaulted inside the SDK when querying an emitter created in the same frame, before its first vaWorldUpdate. Now guarded. - Stop() destroyed emitters the world still owned pending their reverb tail (vaWorldRemoveEmitter answers VA_PENDING_REMOVAL), double-freeing them in vaWorldDestroy. Teardown now only destroys what it actually removed. - Linux-Build.sh regenerated makefiles without the feature flags, silently producing a build with the features compiled out. It now forwards LUX_PREMAKE_OPTIONS. VERIFICATION Core, Editor and Lux-Runtime all build clean with --fmod --raytraced-audio. FMOD initialises against a real device; scene loads; VA world creation and static-geometry mirroring verified correct in-editor (mirrored AABB matches the source transform exactly); per-emitter results reach the playback layer (Valid=true). Every VA and FMOD call site was additionally compiled against the real vendored headers in standalone harnesses. KNOWN ISSUES - --raytraced-audio should stay OFF by default - Creating a VAWorld inside the engine process corrupts the heap on Play. Isolated: FMOD-only is clean, and the identical VA calls are clean in a standalone harness, so it is an interaction, root cause not yet found. - VA occlusion output does not respond to geometry (identical values with no wall and with a 100x75m wall), reproducible standalone. Open with Vercidium. - Windows FMOD paths in Dependencies.lua are unverified placeholders; only the Linux package has been fetched. - Static geometry is mirrored once at Play start and does not follow moving colliders; all geometry is hardcoded to VAMaterialConcrete. Requires project regeneration (new files + premake changes). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DsM8FJLGY8SzZqumBdRKh5
Three strands of work on the audio stack. Ray-traced acoustics (Vercidium) -------------------------------- Rebuilt to the topology Vercidium's docs describe: the listener is the only ray caster, casting all five ray types (including the ambient pair we were leaving at zero), and every source is registered as one of its targets. Adding a source now costs a target on the listener's existing ray budget rather than a second budget of its own. The simulation's full EAX/I3DL2 reverb set is read (vaEmitterGetEAX) and mapped onto FMOD_REVERB_PROPERTIES - previously one field of ~25 was used. Every value is clamped to FMOD's documented range because FMOD rejects the whole struct if one field is out, silently keeping the old reverb. Occlusion is applied as two bands rather than one scalar: the low-frequency gain scales the channel's volume (how much gets through) and the relative high-frequency loss drives the occlusion filter (how much more the highs are cut). Feeding HF straight into set3DOcclusion double-counts the loss and makes an occluded source inaudible instead of muffled. The frame is now explicitly two-phase - WaitForResults, then mutate and read, then OnUpdate - because the simulation is asynchronous and results were being read while workers were still writing them. Stop() also waits unconditionally before draining: vaWorldGetThreadsRunning reads false for work that has been queued but not started, which skipped the drain entirely. Measured end to end: reverb decay tracks room size (0.10s open field, 0.32s small room, 1.39s large hall) and reaches FMOD accepted. Occlusion does not respond to geometry at all - a Vercidium defect, with a self-contained repro under docs/vercidium-repro/ that includes reverb from the same emitter as a control, proving the rays do reach the geometry. 3D visualisation and the Audio Debugger --------------------------------------- Visualisation rays are delivered on Vercidium's worker threads and are valid only inside the callback, so they are copied out under a lock and copied again by the renderer. A ray that hits nothing still occupies its slot, filled with a far out-of-world sentinel, so bounces are classified by world containment and each polyline stops at its first miss. New AudioDebugPanel (View -> Audio Debugger) renders both halves of the stack, with the reverb the simulation produced and the values FMOD actually received side by side. Deliberately free of LUX_ENABLE_FMOD / LUX_ENABLE_RAYTRACED_AUDIO, which are Core-only defines: each backend names itself through its stats struct instead. FMOD Studio pipeline -------------------- Studio is linked alongside Core and owns it - Studio::System::initialize creates the core system, so Shutdown releases only Studio (releasing both is a double free) and Update calls Studio then Core. Studio's update does NOT recompute Core's 3D attenuation; measured with Channel::getAudibility, Studio alone leaves audibility frozen at the geometry a channel started with, which is indistinguishable from spatialisation being off. AudioBankBuilder shells out to fmodstudiocl the way ScriptBuilder shells out to dotnet, and is not behind LUX_ENABLE_FMOD - building banks needs the Studio application, not the SDK. Banks rebuild on Play when the .fspro is newer, and load strings-bank-first (it carries the path table; loading it late makes every event lookup fail unhelpfully). .fspro and .bank are asset types so the Content Browser can show and activate them - activation opens FMOD Studio. Both the browser and the asset registry treat a Studio project directory as opaque: it is dozens of GUID-named XML files plus gitignored build output, and importing the banks would put regenerable files into the tracked registry. Known gap: the binary runtime project format does not carry the Studio settings and runtime export does not copy banks, so an exported game ships without audio. That belongs with the runtime export work. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DsM8FJLGY8SzZqumBdRKh5
Sources can now reference an authored FMOD Studio event instead of a raw
audio file. When an event is set it supersedes the file: spatialisation,
attenuation, cones, doppler and randomisation are authored in the event, and
the component's config fields for those no longer apply.
Events are referenced by GUID, not by path. The path is stored alongside it
purely as a label and is refreshed from the loaded banks on display - never
used to resolve. Renaming or moving an event in FMOD Studio changes its path
but not its GUID, so a path-referencing scene would go silently mute the
first time a designer reorganises the project, with no error anywhere.
AudioEventInstance wraps FMOD::Studio::EventInstance. Two details worth
knowing: IsPlaying counts SUSTAINING, because an event holding at a sustain
point is audible even though its state is neither STARTING nor PLAYING; and
the destructor stops IMMEDIATE rather than ALLOWFADEOUT, because it runs
during teardown where a fade would outlive the thing being torn down.
Scene owns instances per entity. A null entry in that map is meaningful - it
records an event that could not be resolved, so the "not in any loaded bank"
warning is logged once rather than on every frame. Instances are released
both per entity and with the runtime, since they hold Studio resources.
Ray-traced acoustics reach events as named parameters (Occlusion,
ReverbSend) rather than as a filter applied by the engine. That is the
philosophical difference between the two paths: on the legacy path the
engine decides what occlusion does to a sound, while an event is told what
was measured and its author decides what it means. An event declaring
neither parameter is simply unaffected.
The inspector gains an event picker listing what the loaded banks describe,
with the GUID and 3D/oneshot shown on hover. An assigned event missing from
the loaded banks is flagged rather than reading as "nothing assigned".
The legacy raw-file path is retained and marked as such. The project's
.fspro has no authored sounds yet, so removing it now would leave the engine
playing nothing at all.
Verified end to end: a 3D event authored through fmodstudiocl's scripting
API and built into the master bank is enumerated by the engine on project
open ("Loaded 2 bank(s) describing 1 event(s)"), which exercises bank
enumeration, GUID formatting and the list the picker and serializer share.
Note for anyone adding to this: AudioEventInstance.cpp is a new translation
unit, so the projects need regenerating - and regeneration drops the
--fmod / --raytraced-audio options, which must be passed again.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DsM8FJLGY8SzZqumBdRKh5
…path
Adds one authored event to the sample project's FMOD Studio project so the
engine's event path can actually be exercised: without an event in a bank,
the picker is empty, no GUID can be resolved and nothing about the Studio
integration is testable.
The event is 3D (created with a spatializer on its master track) and
assigned to the Master bank, but has no sound on its timeline - what it
exists to prove is bank enumeration, GUID resolution, the inspector picker
and scene serialization, none of which need it to be audible.
Created through fmodstudiocl's scripting API rather than by hand, so it is
reproducible:
workspace.addEvent("LuxTestEvent", true)
ev.relationships.banks.add(masterBank)
Separate from the code change so it can be dropped on its own once the
project has real authored audio.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DsM8FJLGY8SzZqumBdRKh5
The Studio configuration added with the bank pipeline reached ProjectConfig and the serializer but never the settings UI, so pointing a project at its .fspro meant hand-editing the .luxproj YAML. Setting up audio was therefore undocumentable as an editor workflow, which is how the gap surfaced. Project Settings -> Audio now exposes the Studio project path, bank output directory, rebuild-on-play and live update, alongside the existing streaming threshold. Below them is live state rather than settings: how many banks and events are currently loaded, and buttons to build banks or open the project in FMOD Studio without entering Play. Both report clearly when they cannot work - a missing .fspro, or fmodstudiocl not being installed - since neither is recoverable from inside the editor and the fix is an environment variable. Live update is labelled as taking effect on the next project open, because the audio engine is initialised from Project::SetActive and the flag is read there. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DsM8FJLGY8SzZqumBdRKh5
…should Two related passes over AudioSourceComponent. Picking an event ---------------- Events now record which bank describes them, captured during enumeration - the only place that relationship is known without asking FMOD again. The inspector picker becomes two stages, bank then event, with a search inside the dropdown, because one flat list is fine for five events and unusable for five hundred. Strings banks are excluded from the bank list: they carry the path table rather than events, so they would offer a permanently empty list. The bank is stored on the component as a hint, exactly like the event path - refreshed from the loaded banks on display and never used to resolve. The GUID still resolves the event on its own, whichever bank it turns out to live in. Filter and search state live on the panel rather than the component, since they are a view preference, not something to serialize into scenes. Trimming the component ---------------------- AudioSourceConfig carried fifteen fields, most of which an FMOD Studio event now owns. Keeping them was worse than useless: visible, editable, and silently ignored the moment an event was assigned. Removed Spatialization, AttenuationModel, RollOff, Min/MaxGain, Min/MaxDistance, the three cone angles and DopplerFactor, along with the AttenuationModelType enum and the setters that fed them. What remains is volume, pitch, play-on-awake, and looping for the legacy path. The playlist goes with them - AudioData, the four component helpers, its runtime storage and about forty-five lines of index juggling in Scene. A multi-instrument does the same job in Studio, with weighting and no-repeat. Removing the struct also exposed an OnComponentAdded<AudioData> specialization that had always been dead, since AudioData was never a component. In their place, ParameterOverrides: name/value pairs applied once when the instance is created, so two entities can share one event and still sound different. Scripts will drive parameters continuously through the C# API; these are the authored starting point. Behaviour changes worth knowing ------------------------------- Spatialization defaulted to false, which quietly made every raw source 2D unless someone ticked it. The legacy path is now always 3D with FMOD's default rolloff - tuning raw-file attenuation is precisely what an event should be doing instead. Old scenes still carry the removed keys. The deserializer ignores them deliberately, with the reason recorded: reading them would resurrect settings that no longer reach the mixer. Scenes keep playing, with default attenuation rather than whatever was tuned in the component. Paused now defaults to true so play-on-awake fires once for events. That required OnRuntimeStart to clear it when it starts a raw source - otherwise the per-frame path stays armed and restarts the source every time it finishes, turning a one-shot into an unintended loop. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DsM8FJLGY8SzZqumBdRKh5
…lines Physics colliders previously drew through the selection wireframe pass, which has depth testing off so selection stays visible through geometry. Colliders inherited that and floated in front of the walls containing them. They now have their own pass with depth testing on and depth writes off, reusing the pre-depth output; the on-top behaviour is still available through the existing Show Physics Colliders On Top option, which routes back to the wireframe pass. The render graph declares the collider depth read so the dependency is real rather than incidental. Grid and wireframe pipelines gain BackfaceCulling off and DepthWrite off, which is what those passes actually want - they overlay rather than contribute occlusion. Selection outlines sample the jump-flood mask and distance buffers with a point sampler instead of a linear one. Those textures hold mask classes and distance vectors, not colour: interpolating them blends values across the selection boundary, which is meaningless and shows up as a frayed outline. The composite's alpha ramp is inverted to match, so the edge falls off outward. The jump-flood ping-pong reuses one pass across iterations, so its input is now bound inside the render queue rather than at record time - otherwise the first draw of an iteration can observe the previous iteration's binding. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DsM8FJLGY8SzZqumBdRKh5
Transform gizmos operated on the entity's local transform, so dragging a child moved it in its parent's space rather than the world the handles were drawn in. They now take the world matrix and convert the edit back through the parent. They also use the un-reversed projection: ImGuizmo does its own depth maths and does not expect a reversed-Z matrix. Scale snap joins translation and rotation snap, bound through the same editor-preferences path so it persists. The editor camera built its view matrix with a fixed world-up vector, which is degenerate when looking straight down or straight up - exactly the top/bottom orthographic views. It now uses the camera's own up direction, which stays perpendicular at every orientation. Grid visibility is restored from settings on startup instead of always defaulting on. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DsM8FJLGY8SzZqumBdRKh5
Imports fart-01.wav into the FMOD Studio project and places it on LuxTestEvent's timeline, with the encoding setting FMOD generated for it. The event was created empty, which was enough to verify the engine side - bank enumeration, GUID resolution, the inspector picker and scene serialization all work without the event being audible. Making a sound is the one part of the chain that was still unproven. Also includes SampleProject.fspackage, FMOD's exported project archive. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DsM8FJLGY8SzZqumBdRKh5
Adds the PostProcess block the serializer now writes for every scene. No authored change - the scene was saved by the editor and picked up defaults that did not exist when it was first written. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DsM8FJLGY8SzZqumBdRKh5
The complete design for LuxEngine's audio, from the current state to a general-purpose shipping system. A planning document, not a description of what exists - Architecture-LuxEngine.md remains the authority on that. Records the decisions it is built on so the reasoning is inspectable rather than implicit: general-purpose rather than genre-specific, further investment in Vercidium, all four subsystems at equal depth, a full runtime C# API, the legacy raw-file path deleted once events work, a seam left for networking, comprehensive accessibility, and Windows plus eventual consoles. Sixteen parts covering principles, architecture and ownership, the core runtime with function signatures, components, ray-traced acoustics, ambience and reverb zones, surfaces and physics audio, interactive music, dialogue and subtitles, accessibility, the C# API, editor tooling, performance budgets, platforms and shipping, a fifteen-phase roadmap, and six open questions left explicitly undecided so they are not settled by accident. Includes the known-broken items rather than only the aspirations: runtime export ships silent, VA occlusion is blocked upstream, and the premake feature flags are dropped on every regeneration. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DsM8FJLGY8SzZqumBdRKh5
Validate bank build inputs and report build failures through the editor.
Preserve event lifetime and playback state across source operations and teardown. Includes FMOD-only implementations and callback support used by phase 4.
Support indexed, weighted listeners and attenuation targets, with prefab reference remapping and a reusable entity picker. Update VA listener integration.
Expose bank loading, components, one-shots, owned instances, parameters and mixer controls. Marshal callbacks on the main thread and invalidate handles safely during reload. Regenerate projects for the new native source.
Keep overlapping phase changes together: bank revisions versus instance generations, runtime source controls, listener synchronization, component persistence, prefab overrides, and editor picking. Documents the resulting FMOD/VA architecture. This integration and the backend build commit complete the preceding phase commits; intermediate commits were not built independently.
Require both SDKs, deploy shared libraries for Editor and Runtime, and read raw-file metadata through FMOD. Raw AudioSource compatibility remains through FMOD Core; this does not complete the planned runtime export or full legacy API removal. Regenerate projects. Combined tree previously verified with Linux Release Core/Editor/Runtime builds and real FMOD/VA headless tests.
Provide a camera/listener, scripted event emitter, mesh collider geometry, bank paths and step-by-step FMOD setup. Includes the authored sample event replacement and asset registry updates. Game assembly build, scene references, managed lifecycle and native Coral loading verified; no visual or audible editor verification.
Persist the current Audio Debugger layout separately from engine and sample changes.
Add a bounded bank manifest to runtime format 17 while preserving reads of older formats. Export validates bank output, copies banks and required FMOD/VA libraries, and preserves asset-relative bank paths. Runtime loads the exact bank manifest before scenes and scripts and rejects failed loads. Update the export UI, setup guide, architecture reference, and Windows Studio DLL deployment. Regenerate Premake projects for AudioBankManifest.cpp. Verified Linux Release Core, Editor, and Lux-Runtime builds by artifact timestamps. Headless tests cover relocated FMOD playback, bank failures, library copying, manifest validation, and actual project serializer v17 roundtrip/v16 compatibility. Windows execution and interactive playback remain untested.
The editor reset the GPU under the sample scene. Four separate defects, each verified with the Khronos validation layer and sync validation on: - Tone mapping bound PreDepth as a colour+depth attachment while also sampling it. Give SceneComposite a colour-only framebuffer sharing the composite image; the depth-bearing framebuffer stays the target for world/editor overlays. Drops the suppressed PreDepth layout VUIDs in Window.cpp, which were masking this. - Compute-to-draw barriers took StorageBuffer from main-thread Get(), which can select a different frame's buffer than the recorded draw uses. Add StorageBufferSet overloads that resolve RT_Get() at record time, and map IndirectCommandRead to nvrhi IndirectArgument so the indirect-draw barrier transitions to the right state. - Mesh-culling outputs (VisibleObjectIndexes, IndirectDrawCommands) were CPU-visible; NVRHI skips state transitions for those, so the barriers above were no-ops. Make them GPUOnly - CPU init already goes through writeBuffer. - PCSS indexed the 64-entry Poisson table dynamically, which RADV expands into per-fragment scratch copies and hangs the deferred lighting draw. Use constant-index lookups; tests/rendering/run_shadow_shader.py compiles the shader and fails if the local tables come back. Also drops the unused u_SceneColor binding from DeferredLighting, which caused a further invalid transition of the pass's own colour output. Verified: Debug editor, sample scene, PCSS soft shadows, grid and entity icons on - no validation errors, no SYNC-HAZARD, no GPU reset over a multi-minute run, clean shutdown. Debug and Release build Core, Editor and Lux-Runtime. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019xjdPqbKRShx5nfKeYeZYN
Ctrl+clicking where the cursor already was merged the new cursor back into the main one, but Cursors::update() used else-if when re-finding the main and current indices. A cursor that was both left 'current' pointing past the end of the vector, and the next at(current) threw std::out_of_range, closing the editor. The editor body and diff view also drew in the proportional UI font while TextEditor lays glyphs on a fixed '#'-wide grid, spacing text out. Push the Mono font around both renders. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- plan-le: source-grounded phased planning with a verified ledger, user decisions, engine-fit analysis and independently verifiable phases. - profile: measurement-first performance workflow (present ceiling, CPU vs GPU, Tracy/RenderDoc, fixed benchmark protocol). - shader-debug: triage for compile errors, cache fallback, manual reload, binding collisions, black output, startup crashes and device loss. - Conventions.md: ImGui correctness section (every scope closed on every path, unique IDs per scope, verify in the editor). Enforced as must-fix rule 11 in the shared review list, and referenced from /dev, /cr and /plan-le. - Codex adapters under .agents/skills and CLAUDE.md/AGENTS.md index. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…layout Asset registry write times refreshed by the editor, a spatialiser distance rolloff change on one FMOD Studio event, and the saved ImGui layout. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- docs/BEAM_EDITOR_PLAN.md: phased plan (0-11) to rework Beam into a full in-engine code editor with VS Code / Visual Studio / JetBrains / Vim features, in-process shader and C# diagnostics, and no extra installs. Includes a verified current-state ledger, decisions, risks and a research brief. - CLAUDE.md / AGENTS.md: Product Principle - self-contained, small, refined; no new mandatory installs for game makers. - send-pr: requiring a separate install is must-fix (rule 10). - plan-le: web research step with a compacted research brief, a pinned goal card, and the product principle as a standing rule. - Sample FMODDemo scene and editor layout saved by the editor. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…Gui headers AudioPerformance enabled input metering on the head DSP of Studio's bus channel groups. With FMOD Live Update on (the sample project's setting), changing metering on a Studio-owned DSP makes every later Studio::System::update return FMOD_ERR_BADCOMMAND. The engine only logs when the result changes, so it appeared once while failing every frame. Found by bisecting on Windows; failures stop with the metering call removed or with Live Update off. The monitor now meters through a pass-through fader DSP it owns, inserted at index 1 directly behind the head DSP so it measures the same signal, and detaches and releases it before banks unload. Also close PropertyGridHeader tree nodes that were never popped: Audio Debugger "Budgets and Bus Meters" (open by default, leaked every frame) and "Audio Validation", and Project Settings "Surface Sounds", "Dialogue Lines" and "Audio Accessibility". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical and moderate correctness issues remain.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
This PR replaces miniaudio with FMOD Studio and Vercidium Audio, adding authored audio, acoustics, scripting, runtime export, accessibility, and related platform/editor fixes.
Changes:
- Adds FMOD/VA runtime integration, components, C# APIs, banks, acoustics, music, dialogue, and accessibility.
- Adds serialization, asset-pack, SDK, managed, shader, and resource-copy tests.
- Updates build tooling, sample assets, editor panels, shaders, and workflow documentation.
File summaries
| File | Reviewed change |
|---|---|
tests/runtime/run_resources.py |
Runtime resource-copy regression test |
tests/rendering/run_shadow_shader.py |
Offline shadow-shader validation |
tests/audio/SourceSerializationTests.cpp |
Audio source serialization tests |
tests/audio/run_sdk_layout.py |
SDK layout validation |
tests/audio/run_managed.py |
Managed audio test runner |
tests/audio/README.md |
Audio test instructions |
tests/audio/PlatformTests.cpp |
Platform and focus tests |
tests/audio/MusicSerializationTests.cpp |
Music serialization tests |
tests/audio/GeometrySerializationTests.cpp |
Geometry serialization tests |
tests/audio/FileStreamTests.cpp |
File-stream tests |
tests/audio/AuthorFixture.js |
FMOD authoring fixture |
tests/audio/AssetPackFailureTests.cpp |
Asset-pack failure tests |
scripts/Win-GenProjects.py |
Windows project generation |
scripts/Setup.py |
SDK setup tooling |
scripts/Linux-Build.sh |
Linux build updates |
scripts/Configure.py |
Build configuration |
ScriptCore/Source/Lux/Music.cs |
Managed music API |
ScriptCore/Source/Lux/AudioPortal.cs |
Managed audio portal API |
premake5.lua |
Audio SDK configuration |
Lux-Runtime/src/RuntimeLayer.h |
Runtime layer declarations |
Lux-Runtime/src/RuntimeLayer.cpp |
Runtime layer integration |
Lux-Runtime/src/RuntimeApplication.cpp |
Runtime application setup |
Lux-Runtime/premake5.lua |
Runtime build configuration |
Editor/Source/RuntimeExportUtils.h |
Runtime export utilities |
Editor/Source/Panels/TextEditorPanel.cpp |
Text editor fixes |
Editor/Source/Panels/ProjectSettingsWindow.h |
Project audio settings declarations |
Editor/Source/Panels/ContentBrowserPanel.h |
Content browser declarations |
Editor/Source/Panels/AudioDebugPanel.h |
Audio debugger declarations |
Editor/Source/Panels/ApplicationSettingsPanel.h |
Application settings declarations |
Editor/Source/Panels/ApplicationSettingsPanel.cpp |
Application settings integration |
Editor/Source/EditorLayer.h |
Editor-layer declarations |
Editor/Resources/Shaders/JumpFlood_Pass.glsl |
Jump-flood pass shader |
Editor/Resources/Shaders/JumpFlood_Init.glsl |
Jump-flood initialization shader |
Editor/Resources/Shaders/JumpFlood_Composite.glsl |
Jump-flood composite shader |
Editor/Resources/Shaders/Include/GLSL/ShadowMapping.glslh |
Shadow-mapping shader helpers |
Editor/Resources/Shaders/DeferredLighting.glsl |
Deferred-lighting shader fixes |
Editor/premake5.lua |
Editor build configuration |
Editor/LuxSampleProject/LuxSample.luxproj |
Sample project configuration |
Editor/LuxSampleProject/Assets/Scripts/Source/FmodAudioDemo.cs |
FMOD sample demo script |
Editor/LuxSampleProject/Assets/Scenes/AudioTest.luxscene |
Audio test scene |
Editor/LuxSampleProject/Assets/Audio/SampleProject/SampleProject.fspro |
FMOD Studio sample project |
Editor/LuxSampleProject/Assets/Audio/SampleProject/Metadata/Workspace.xml |
FMOD workspace metadata |
Editor/LuxSampleProject/Assets/Audio/SampleProject/Metadata/Tags.xml |
FMOD tag metadata |
Editor/LuxSampleProject/Assets/Audio/SampleProject/Metadata/SnapshotGroup/{7fefaf03-60b0-4058-9f39-dc582b445d97}.xml |
FMOD snapshot metadata |
Editor/LuxSampleProject/Assets/Audio/SampleProject/Metadata/SandboxFolder/{6d7ac61e-abd8-4a55-a9f4-6ff6f6021e22}.xml |
FMOD sandbox metadata |
Editor/LuxSampleProject/Assets/Audio/SampleProject/Metadata/Return/{905d9352-a23b-4b62-82f8-918d93be45b2}.xml |
FMOD return metadata |
Editor/LuxSampleProject/Assets/Audio/SampleProject/Metadata/ProfilerFolder/{5f35c254-3410-4f97-89af-5c30feb88606}.xml |
FMOD profiler metadata |
Editor/LuxSampleProject/Assets/Audio/SampleProject/Metadata/Platform/{c2de980e-8d10-499f-b068-81c40b5763ae}.xml |
FMOD platform metadata |
Editor/LuxSampleProject/Assets/Audio/SampleProject/Metadata/ParameterPresetFolder/{73d54407-c59f-4995-bd0b-b53fe44ed322}.xml |
FMOD parameter metadata |
Editor/LuxSampleProject/Assets/Audio/SampleProject/Metadata/Mixer.xml |
FMOD mixer metadata |
Editor/LuxSampleProject/Assets/Audio/SampleProject/Metadata/Master.xml |
FMOD master-bus metadata |
Editor/LuxSampleProject/Assets/Audio/SampleProject/Metadata/EventFolder/{19572dc8-1f88-4500-8575-511b176c5352}.xml |
FMOD event metadata |
Editor/LuxSampleProject/Assets/Audio/SampleProject/Metadata/EncodingSetting/{fca1d20d-6b81-4cfe-9ef1-7c4a23ea540e}.xml |
FMOD encoding metadata |
Editor/LuxSampleProject/Assets/Audio/SampleProject/Metadata/EncodingSetting/{2ea4f6be-52d7-47a5-851c-e4f4c0f2d144}.xml |
FMOD encoding metadata |
Editor/LuxSampleProject/Assets/Audio/SampleProject/Metadata/EffectPresetFolder/{7e638cd8-0692-469f-b2aa-d1f7ff41fa82}.xml |
FMOD effect metadata |
Editor/LuxSampleProject/Assets/Audio/SampleProject/Metadata/BankFolder/{f4906ec4-3038-4329-8214-9491f8ee21d1}.xml |
FMOD bank metadata |
Editor/LuxSampleProject/Assets/Audio/SampleProject/Metadata/Bank/{fa0b1bba-b14d-4ea4-ad1c-423a63954b99}.xml |
FMOD bank definition |
Editor/LuxSampleProject/Assets/Audio/SampleProject/Metadata/AudioFile/{339ff415-7661-4c23-9d01-5a8c5cc80aed}.xml |
FMOD audio-file metadata |
Editor/LuxSampleProject/Assets/Audio/SampleProject/Metadata/Asset/{d0f2bd5e-829b-40b5-9a32-1d715d011040}.xml |
FMOD asset metadata |
Editor/LuxSampleProject/Assets/Audio/SampleProject/Metadata/Asset/{c14602ef-22ef-4740-b80c-9c19e7016f58}.xml |
FMOD asset metadata |
Editor/LuxSampleProject/Assets/Audio/SampleProject/Metadata/Asset/{a090b716-2b34-48c3-a0f2-ac0a3de23214}.xml |
FMOD asset metadata |
Editor/LuxSampleProject/Assets/Audio/SampleProject/Metadata/Asset/{942e11f9-8e64-4d92-b86b-2b4a9e6e22c6}.xml |
FMOD asset metadata |
docs/vercidium-repro/occlusion_output.txt |
Vercidium occlusion diagnostics |
docs/AUDIO_PERFORMANCE_VALIDATION.md |
Audio performance validation |
Core/Source/Lux/Vendor/TextEditor.cpp |
Text editor implementation |
Core/Source/Lux/Utilities/FileSystem.h |
Filesystem declarations |
Core/Source/Lux/Serialization/FileStream.h |
File-stream declarations |
Core/Source/Lux/Serialization/FileStream.cpp |
File-stream implementation |
Core/Source/Lux/Serialization/AssetPackSerializer.h |
Asset-pack serializer declarations |
Core/Source/Lux/Serialization/AssetPackSerializer.cpp |
Asset-pack serialization |
Core/Source/Lux/Serialization/AssetPack.cpp |
Asset-pack implementation |
Core/Source/Lux/Scripting/ScriptGlue.cpp |
Script glue integration |
Core/Source/Lux/Scripting/ScriptEngine.cpp |
Script engine integration |
Core/Source/Lux/Scripting/AudioScriptBindings.h |
Managed audio bindings |
Core/Source/Lux/Scene/Prefab.cpp |
Prefab audio support |
Core/Source/Lux/Scene/EntityTemplates.h |
Entity audio templates |
Core/Source/Lux/Renderer/SceneRenderer.h |
Scene renderer declarations |
Core/Source/Lux/Renderer/PipelineCompute.h |
Compute-pipeline declarations |
Core/Source/Lux/Renderer/PipelineCompute.cpp |
Compute-pipeline synchronization |
Core/Source/Lux/Renderer/FrameRenderPacket.h |
Frame render data |
Core/Source/Lux/Project/ProjectSerializer.h |
Project serializer declarations |
Core/Source/Lux/Project/ProjectRuntimeFormat.h |
Runtime project format |
Core/Source/Lux/Project/Project.cpp |
Project integration |
Core/Source/Lux/Physics/PhysicsScene.h |
Physics scene declarations |
Core/Source/Lux/Physics/PhysicsScene.cpp |
Physics scene integration |
Core/Source/Lux/Physics/PhysicsContactEvent.h |
Physics contact events |
Core/Source/Lux/Physics/JoltPhysics/JoltContactListener.h |
Jolt contact listener declarations |
Core/Source/Lux/Physics/JoltPhysics/JoltContactListener.cpp |
Jolt contact event capture |
Core/Source/Lux/ImGui/ImGuiEx.h |
ImGui helpers |
Core/Source/Lux/ImGui/AudioWidgets.h |
Audio widget declarations |
Core/Source/Lux/ImGui/AudioWidgets.cpp |
Audio widgets |
Core/Source/Lux/ImGui/AudioAccessibilityWidgets.h |
Accessibility widget declarations |
Core/Source/Lux/Editor/SceneHierarchyPanel.h |
Scene hierarchy declarations |
Core/Source/Lux/Editor/EditorCamera.cpp |
Editor camera integration |
Core/Source/Lux/Core/Window.cpp |
Window integration |
Core/Source/Lux/Core/Log.cpp |
Logging updates |
Core/Source/Lux/Core/Application.cpp |
Application audio lifecycle |
Core/Source/Lux/Audio/PhysicsAudioSystem.h |
Physics audio system |
Core/Source/Lux/Audio/MusicDirector.h |
Music director |
Core/Source/Lux/Audio/DialogueTable.h |
Dialogue table |
Core/Source/Lux/Audio/DialogueDirector.h |
Dialogue director |
Core/Source/Lux/Audio/AudioZoneSystem.h |
Audio zones |
Core/Source/Lux/Audio/AudioZoneSettings.h |
Audio zone settings |
Core/Source/Lux/Audio/AudioValidation.h |
Audio validation |
Core/Source/Lux/Audio/AudioSurfaceTable.h |
Surface sound table |
Core/Source/Lux/Audio/AudioSurfaceTable.cpp |
Surface sound table implementation |
Core/Source/Lux/Audio/AudioSourcePlayback.h |
Audio playback state |
Core/Source/Lux/Audio/AudioSource.h |
Audio source component |
Core/Source/Lux/Audio/AudioPerformanceSettings.h |
Performance settings |
Core/Source/Lux/Audio/AudioPerformance.h |
Performance monitoring |
Core/Source/Lux/Audio/AudioListener.h |
Audio listener component |
Core/Source/Lux/Audio/AudioGeometrySystem.h |
Acoustic geometry system |
Core/Source/Lux/Audio/AudioGeometrySettings.h |
Geometry settings |
Core/Source/Lux/Audio/AudioFocus.cpp |
Audio focus handling |
Core/Source/Lux/Audio/AudioEventRef.h |
Audio event references |
Core/Source/Lux/Audio/AudioBankManifest.h |
Bank manifest declarations |
Core/Source/Lux/Audio/AudioBankManifest.cpp |
Bank manifest implementation |
Core/Source/Lux/Audio/AudioBankBuilder.h |
Bank builder |
Core/Source/Lux/Audio/AudioAccessibilitySettings.h |
Accessibility settings |
Core/Source/Lux/Audio/AudioAccessibilityMixer.h |
Accessibility mixer |
Core/Source/Lux/Audio/AudioAccessibility.h |
Accessibility system |
Core/Source/Lux/Audio/AcousticMaterial.h |
Acoustic material |
Core/Source/Lux/Asset/DialogueTableSerializer.h |
Dialogue serializer declarations |
Core/Source/Lux/Asset/DialogueTableSerializer.cpp |
Dialogue serialization |
Core/Source/Lux/Asset/AudioSurfaceTableSerializer.h |
Surface serializer declarations |
Core/Source/Lux/Asset/AudioSurfaceTableSerializer.cpp |
Surface serialization |
Core/Source/Lux/Asset/AssetTypes.h |
Audio asset types |
Core/Source/Lux/Asset/AssetManager/EditorAssetManager.cpp |
Editor asset discovery |
Core/Source/Lux/Asset/AssetManager.h |
Asset manager declarations |
Core/Source/Lux/Asset/AssetManager.cpp |
Asset manager integration |
Core/Source/Lux/Asset/AssetImporter.cpp |
Asset importing |
Core/Source/Lux/Asset/AssetExtensions.h |
Asset extensions |
Core/premake5.lua |
Core build configuration |
Core/Platform/Windows/WindowsFileSystem.cpp |
Windows atomic file replacement |
Core/Platform/Linux/LinuxFileSystem.cpp |
Linux atomic file replacement |
CLAUDE.md |
Repository workflow guidance |
AGENTS.md |
Agent workflow guidance |
.gitignore |
SDK and generated-output exclusions |
.claude/skills/send-pr/SKILL.md |
Pull-request workflow |
.claude/skills/dev/SKILL.md |
Development workflow |
.claude/skills/cr/SKILL.md |
Code-review workflow |
.claude/docs/Threading.md |
Threading guidance |
.claude/docs/Rendering.md |
Rendering guidance |
.claude/docs/Building.md |
Build guidance |
.agents/skills/shader-debug/SKILL.md |
Shader-debug workflow |
.agents/skills/send-pr/SKILL.md |
Pull-request workflow |
.agents/skills/profile/SKILL.md |
Profiling workflow |
.agents/skills/plan-le/SKILL.md |
Planning workflow |
Review details
Suppressed comments (5)
Core/Source/Lux/Asset/AssetManager/EditorAssetManager.cpp:759
- This disables recursion at the FMOD project root, so the recursive iterator never visits the
.fsprofile inside it; the project is therefore absent from a freshly scanned asset registry despite the newAudioProjecttype and activation callback. Prune only the generated subdirectories, or import the project file before disabling recursion.
Core/Source/Lux/Audio/AudioGeometrySystem.cpp:113 - When
RemoveGeometryfails, this path leavesentry.Queuedfalse and continues. On the next frame the unchanged input compares equal toentry.Desired, so it is never queued again and the stale VA primitive can remain forever. Keep the key pending when removal fails (and apply the same retry behavior to the other world-operation failures below).
Core/Source/Lux/Audio/AudioGeometrySystem.cpp:131 - A failed
SetGeometryis treated as a completed queue item:Queuedwas already cleared, and identical inputs will not be enqueued again. If VA is temporarily unable to accept the update (or mesh data becomes available after the builder attempt), this geometry never appears until an unrelated component change. Requeue the key on this failure; the analogousUpdateGeometryfailure at line 136 needs the same treatment.
Core/Source/Lux/Audio/AudioGeometrySystem.cpp:136 UpdateGeometryfailures also consume the only queued attempt. Becauseentry.Queuedwas cleared before this branch and the desired input is unchanged, a transient VA update failure leaves the old transform/material permanently stale; requeue this key before continuing.
Editor/LuxSampleProject/Assets/Audio/SampleProject/SampleProject.fspro:2- The bundled sample cannot execute this new demo from the committed state: this
.fsprocontains no authored events, whileFmodAudioDemoloadsMaster.bank/Master.strings.bankand createsevent:/Fart; the generatedBuild/banks are ignored andtests/audio/AuthorFixture.jsis never applied to this project. A fresh sample project therefore logs bank/event-loading failure rather than exercising the advertised audio path. Add the authored fixture/banks to the sample workflow or remove/disable the demo references until they exist.
- Files reviewed: 161/229 changed files
- Comments generated: 4
- Review effort level: Lite
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| std::scoped_lock lock(m_Mutex); | ||
| m_Events.push_back(event); |
| path.touch() | ||
| environment = dict(os.environ, LUX_FMOD_SDK=str(fmod), LUX_VA_SDK=str(va)) | ||
| for platform, files in platforms.items(): | ||
| command = [str(ROOT / "premake5"), "--file=" + str(probe), "--os=" + platform, "check-audio-sdk"] |
| std::ofstream file(Project::GetActiveAssetDirectory() / metadata.FilePath); | ||
| file << table->ToYAML(); | ||
| file.flush(); | ||
| if (!file) | ||
| LUX_CORE_ERROR_TAG("Audio", "Failed to save surface table '{}'", metadata.FilePath.string()); |
Artifacts on a public repository are downloadable by anyone, and both EULAs forbid redistributing their runtime libraries outside a game build (FMOD also forbids shipping them as part of a game engine or tool set). Windows removes fmod*.dll and vaudionative*.dll; Linux removes the libfmod, libfmodstudio and libvaudionative shared objects, and its ldd completeness check now allows only those libraries to be unresolved. Both steps fail if any remain, and add AUDIO_LIBRARIES_REQUIRED.txt explaining which files to copy from the user's own SDK downloads. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both SDKs are licensed and cannot live in this public repository, so every CI build failed at project generation. Both jobs now check out the private repository named by the AUDIO_SDK_REPOSITORY variable into .audio-sdk/ with the AUDIO_SDK_TOKEN secret (persist-credentials off) and point LUX_FMOD_SDK and LUX_VA_SDK at it. Missing configuration, including fork pull requests that cannot read secrets, fails early with an explicit message. scripts/ci/StageAudioSDKs.py populates that repository from the user's own SDK downloads with only headers, link/runtime libraries and licence files (Windows FMOD package, Linux FMOD package or .tar.gz with symlinks copied as files, and Vercidium Audio for every platform it contains). It refuses to write inside the public repository. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Core's post-build copies Coral.Managed from Build/Release only (pinned on purpose so one Coral build is deployed). On Windows the solution still built Coral.Managed in its own configuration, so a clean Debug or Dist build never produced Build/Release and the copy failed (MSB3073). It only worked locally because an earlier Release build had left the files behind; CI exposed it. Reopen Coral.Managed in premake5.lua (the vendored submodule stays untouched) with a configmap to Release for Debug, Debug-AS and Dist. Verified by moving Build/Release aside and building Debug: Coral.Managed built in Release first and Core's post-build copied all four files. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…irement libvaudionative.so from Vercidium Audio 1.8.0 references sqrtf, log10f and acosf at GLIBC_2.43, so linking the editor failed on ubuntu-24.04 (glibc 2.39). Ubuntu 26.04 runners (generally available 2026-09-17) ship glibc 2.43. Documented in Building.md, including that the same floor applies to Linux machines building or running LuxEngine and exported games. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- FMODDemo scene: house test scene for ray-traced acoustics.
- FMOD Studio metadata: edited event {0e6cd051} and new event {b1db803c}.
- CubeScene import material and its asset-registry entry.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Phased plan (0-14) for a material editor with live preview, thumbnails, a full standard material, Unreal-style instances and a node graph built on imgui-node-editor, grounded in the current code (no material editing is reachable in the editor today) and research on Godot, Unreal, OpenPBR and Blender. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…terial thumbnails Material editor plan phases 0-2. - MaterialEditorPanel (View > Material Editor): one tab per material, explicit Save/Revert, unsaved-tab close prompt, and one undo step per finished edit. Opens from a Content Browser double-click and from the Inspector's Edit buttons. - MaterialPreview: a private Scene + Viewport (own SceneRenderer, no editor targets) showing the material on the project's default meshes; orbit and zoom. - MaterialThumbnailer: renders stale material thumbnails one at a time, reads the pixels back on the render thread and hands CPU pixels to ThumbnailCache. Thumbnails are drawn padded with rounded corners. - Inspector: Material Slots section for multi-submesh meshes. - Remove the unregistered MaterialEditorPanel / MaterialsPanel. Fix: MaterialAsset kept its values only in the shader push-constant block, which the opaque shader lacks Transparency for and the transparent shader lacks entirely, so reading them was an out-of-bounds read (crash on opening a material) and transparent materials lost colour and opacity. The asset now owns its values; MaterialScene reads them from the asset. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- MaterialSurfaceParameters on MaterialAsset: emissive colour + map, occlusion map + strength, packed-map (ORM) channel selection for metalness / roughness / occlusion, specular, normal strength, height map as bump, and UV tiling / offset / rotation. Defaults reproduce existing shading (verified byte-identical on a material thumbnail). - GPUMaterialData / GPUMaterial grow in step (144 bytes, std430). - Emission is written by the G-buffer pass straight into scene color (loaded, not cleared); deferred lighting blends additively on top, so emissive maps keep their colour without a new G-buffer target. - Renderer::BeginRenderPass honours per-attachment AttachmentLoadOp; FramebufferBlendMode::Additive is implemented (it hit VERIFY(false)). - MaterialSerializer: new keys written only when non-default; files from before emissive colour migrate as data; transparent materials keep roughness and normal map. - Assimp import maps emissive colour/strength/texture and occlusion textures. - Material Editor: Emission, packed-channel, occlusion, bump and UV controls. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…fer barrier, SDK test - AudioSurfaceTableSerializer: enforce the 1 MiB limit on save, as the loader and asset pack already do, so an oversized table is refused instead of saved unloadable. - JoltContactListener: queue a Begin/Persist only if the contact is still live under the second lock, so a removal between the locks cannot be followed by a stale event that resurrects the contact. - PipelineCompute: a barrier on an unallocated storage buffer is a no-op again (regressed to a shipped VERIFY in 71eb9b3; a StorageBufferSet can resolve a null buffer mid-resize or before first use). - tests/audio/run_sdk_layout.py: find premake the way Linux-Build.sh does (root, then vendor/bin, .exe on Windows) and compare missing-file paths in both slash forms. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
What
Replaces the miniaudio backend with FMOD Studio + Vercidium Audio (both required) and builds the full audio system from
docs/AUDIO_SYSTEM_PLAN.mdin 15 phases: Studio events and banks, listeners, C# API, runtime export of banks, acoustic materials, zones/snapshots, surfaces and physics audio, interactive music, localized dialogue and subtitles, accessibility, dynamic acoustic geometry and portals, voice budgets and validation, and desktop platform profiles.Also on this branch: Windows fixes found while verifying it, the Beam editor multi-cursor/monospace fixes, deferred-lighting GPU-reset/sync fixes, and agent workflow docs (
/plan-le,/profile,/shader-debug, the ImGui correctness rule, the self-contained product principle, anddocs/BEAM_EDITOR_PLAN.md).Why
The old audio path was raw-file playback with no authoring pipeline, no occlusion or reverb, no C# API, and silent exported games. This gives an authored FMOD Studio pipeline with ray-traced acoustics, a complete scripting surface, and working runtime export.
Fixes found during Windows verification (latest commit
a51e7012)update()failed every frame with Live Update on.AudioPerformanceenabled metering on a DSP Studio owns; with Live Update enabled, every laterStudio::System::updatereturnedFMOD_ERR_BADCOMMAND(logged only once because the engine logs on change). Bisected on Windows; the monitor now meters through its own pass-through fader DSP at index 1 and releases it before bank unload.TreePop): Audio Debugger "Budgets and Bus Meters" (open by default, leaked every frame) and "Audio Validation"; Project Settings "Surface Sounds", "Dialogue Lines", "Audio Accessibility".Verification
fmod.dll,fmodstudio.dll,vaudionative.dllpresent next to Editor and Lux-Runtime.LuxSampleProject, FMOD Studio initializes with Live Update, zero[error]lines, clean shutdown (exit code 0). Before the fix, ~14,900 failing updates in 41 s; after, none.tests/audio/run.py,run_managed.py) — not re-run for the latest commit (Linux-only harness).docs/vercidium-repro/).Review
/send-prrule list applied as automated checks over all added lines (raw new/delete,shared_ptr, Core→Editor includes, untagged logs, ImGui scope balance) plus manual review of UI scope paths and component completeness (all five new components are inAllComponents, scene copy, both serializer directions, the hierarchy UI, and C#). The full ~23k-line diff was not reviewed line by line; each audio phase was reviewed when it landed.Consider-tier, left as is:
static std::stringUI buffers in the Dialogue Lines editor (ProjectSettingsWindow.cpp).Regeneration
Required — many files added/removed (miniaudio removed, new Audio sources). Run
scripts\Win-GenProjects.bat --last. FMOD Engine SDK must be inCore/vendor/FMOD/(orLUX_FMOD_SDK) and Vercidium Audio inCore/vendor/VA_RAY/(orLUX_VA_SDK); generation fails with the exact missing file otherwise.Doc updates
.claude/docs/Architecture-LuxEngine.md(§ 2.10 Audio, metering ownership rule),Threading.md(audio budgets),Conventions.md(ImGui correctness),Building.md(audio SDKs),CLAUDE.md/AGENTS.md(product principle, skills), and phase docs underdocs/AUDIO_*.md.🤖 Generated with Claude Code