Releases: Hekbas/Luth
v2.8.3 — tracy-on-demand
Date: 2026-04-25
Issue: #30
Overview
Hotfix for two memory leaks that share a single root cause: Tracy's per-thread serial queue accumulates zone, frame-mark, and (post-v2.8.2) global allocation events even when no profiler client is connected to drain them. Defining TRACY_ON_DEMAND makes every Tracy macro short-circuit to a no-op until Profiler::IsConnected() is true. Same leak at two scales — got dramatically worse after v2.8.2 wired global new/delete to TracyAlloc/TracyFree.
Key Changes
- Add
TRACY_ON_DEMANDto Debug + Release across all four premake configs (Tracy lib,Luth,Luthien, runtime) - Fixes ~10 MB/s ProjectLauncher leak (post-v2.8.2 regression) and ~0.2 MB/s in-game leak at 240 fps (#30, opened 3 weeks earlier)
MemoryTrackerreads remained balanced — leaked bytes lived inside Tracy's own buffers, outside theLH_NEW/LH_DELETEpath- Capture experience unchanged with Tracy GUI connected; trace begins at connection time (no retroactive history — acceptable trade-off for a development-only feature)
- Tracy excluded from Dist as before — no impact there
Build Verification
Debug x64 builds clean. Launcher and in-game RSS flat over 60 s and 5 min respectively with no Tracy client. Capture flow unchanged with client connected.
v2.8.2 — engine-consolidation
Date: 2026-04-25
Issue: #95
Overview
Audit-driven housekeeping pass before resuming feature work. Restructures the roadmap, adds four arch sub-docs covering systems that existed in code but lacked documentation (memory / profiling / validation-layers / version-glossary), sanitizes comment banners across 14 files, wires Tracy global memory hooks for STL/heap visibility, and fills Tracy CPU coverage gaps across editor panels and individual render-graph passes.
Key Changes
- ROADMAP: terse summaries, Effort scale (S/M/L/XL replaces calendar estimates), v2.7/v2.8 rows reordered chronologically
- 4 new
docs/development/arch/sub-docs: memory, profiling, validation-layers, version-glossary - Comment banners normalized to v2.7.0
// ── Section ──form across jobs/, memory/, renderer/ (–104 LOC of cruft) - Tracy memory hooks via global
operator new/deleteoverrides — STL containers + third-party libs visible in Memory tab - Tracy CPU coverage filled: 10 editor panels, RG individual passes,
PickingSystem::Update, shader hot-reload - Issue renames: #92
frame-debugger-scrub→frame-debugger-polish, #93animation-assets→animation-quick-pass(rescoped)
Build Verification
10 atomic commits on chore/engine-consolidation, each builds Debug x64 clean. Vulkan validation runs without new warnings.
v2.8.1 — game-panel
Date: 2026-04-24
Issue: #91
Overview
Dedicated Game panel rendering the first Component::Camera entity — letterbox/pillarbox respects the camera's aspect ratio; no editor overlays. Scene panel goes back to always using the editor camera. Replaces the v2.8.0 scene-camera-override stopgap and rebuilds the renderer to cleanly support multi-view.
Key Changes
RenderViewthreads per-view input (targets + camera + overlay flags) throughRenderPipeline::Execute.ViewResourcescache keyed byFrameTargets*— per-view GlobalUBO + Set 0 + bloom/GTAO textures + PP/GTAO/outline/grid descriptor sets; multiple subgraphs share one primary command buffer without mid-frame descriptor aliasing.Renderer::ExecuteGraphsplit intoBeginPrimaryCmd+RecordGraph+EndPrimaryCmdAndSubmit;RenderingSystem::Updaterecords queued views + scene view into one cmd buffer, one submit + present per frame.RS::QueueViewAPI; shared indirect buffer carries per-view regions (k_MaxViews * k_IndirectRegionsPerView).ViewportRenderer::BeginViewport(aspectRatio)centers + letterboxes when > 0; GamePanel passesCamera.AspectRatioand pulls IBL/skybox intensities fromEditorSettings.- Per-instance resize callback replaces the single-subscriber
RenderResizeEventbus. - Drive-by fixes (validation-layer hardening): depth textures gain
VK_IMAGE_USAGE_TRANSFER_SRC_BIT; GeometryPass declares explicitbuilder.Read(gtaoFinal); PickingSystem barrier uses the actualCOLOR_ATTACHMENT_OPTIMALsource layout.
Build Verification
Debug x64 clean across 12 commits on feat/game-panel. No new warnings. Manual smoke: scene + game panels render correctly in all play states, frame debugger enable/disable is clean, picking works, runtime target still links.
v2.8.0 — play-mode
Date: 2026-04-23
Issue: #66
Overview
First feature epic after the post-v2.6 editor architecture review. Adds an Editing → Playing → Paused → Editing state machine with scene snapshot / restore so Stop reverts cleanly. Gateway for v2.9.0 jolt-physics and any future gameplay-only system.
Key Changes
SceneSerializer::SaveToString/LoadFromString(preserveAssets)for in-memory JSON snapshot;Scene::ClearPreservingAssetsskipsAssetManagerreload on StopLuth::PlayStateonIEditorHooks(nullptr-safe default keeps headless runtime ticking normally)App::RungatesAnimationSystemonPlaying || (Paused && step) || (Editing && preview)- New
PlayModeController+CommandHistory::SetBlocked— Inspector edits and Ctrl+Z are no-ops during play; snapshot rewind discards mutations on Stop ScenePaneltransport bar (Play/Pause/Stop/Step) with green/yellow viewport tint + scene-camera override when aComponent::Cameraentity exists- Fix: pre-existing skinned-mesh freeze on scene reload —
GPUObjectBuffersnow mirrorsDrawListBuilder's entity-or-parent bone-offset lookup
Build Verification
10 atomic commits on feat/play-mode, every commit builds Debug x64 clean. User-tested Play→Stop cycles on skinned characters; transport controls + undo gating + scene-camera override all behave per checklist.
v2.7.5 — editor-scene-panel-slim
Date: 2026-04-23
Issue: #90
Overview
Sixth and final epic of the post-v2.6 editor architecture review. ScenePanel.cpp (1001 LOC) split across three dedicated collaborators under a new luthien/source/luthien/viewport/ folder. Pure refactor — no behavior change.
Key Changes
- New
ViewportRenderer— viewport size/bounds/focus/hover + scene-colorVkDescriptorSetlifetime + per-frame resize-event dispatch. - New
GizmoController— ImGuizmo operation + drag-undo coalesce + Q/W/E/R shortcuts + icon-click latch. - New
ViewportOverlays— bone/light/camera/AABB overlays + 5 projection-and-clipping helpers as private methods; routes icon clicks throughGizmoController::DrawGizmoIconso the latch stays on the controller. ScenePanelretains toolbar, picking dispatch, F/Shift-F camera framing, controls overlay,EditorCamera.ScenePanel.cpp1001 → 443 LOC (−56%);ScenePanel.h82 → 44 LOC.
Build Verification
4 atomic commits; every commit builds Debug x64 clean (no new warnings). Runtime smoke: viewport renders + resizes cleanly, TRS gizmo + QWER shortcuts + drag-coalesced undo, all four overlays toggle, icon-click selection, F / Shift-F framing, controls-overlay chip.
v2.7.4 — editor-component-registry
Date: 2026-04-23
Issue: #89
Overview
Replace InspectorPanel::DrawEntityComponents' hand-written 12-arm DrawComponent<T> switch and 70-LOC Add Component dropdown with a type-erased ComponentDrawerRegistry. One drawer per component file; the inspector iterates the registry for both rendering and add-menu enumeration. Pure refactor — every command, IsDirty flag, and init-value quirk preserved. InspectorPanel.cpp shrinks 976 → 255 LOC (−73%).
Key Changes
- New
ComponentDrawerRegistry— static class holdingstd::vector<ComponentDrawerDescriptor>.Register<T>(name, drawFn, opts)closes overTat template instantiation; wraps the user lambda inBeginCollapsingHeader + Remove-context-menu; defaultOnAddissuesComponentAddCommand<T>. - 8 per-component
.cpps underluthien/source/luthien/inspectors/component_drawers/(Transform / Camera / MeshRenderer / Animation / BoneAttachment / AnimationController / DirectionalLight / PointLight) +DebugDrawers.cppconsolidating ID/Parent/Children/WorldTransform under a single#if DEBUGguard. Canonical order held by insertion order inRegisterComponentDrawers.cpp. - Init-value / dependency quirks preserved via custom
OnAdd+CanAdd: Animation snapshotsMeshRenderer.ModelUUID; AnimationController requires Animation present and seeds a baseBlendLayerfrom current Animation state. - MeshRenderer → MaterialEditor handoff via new
InspectorPanel::SetActiveMaterial(UUID)+m_ActiveMaterialUUIDmember (reset per frame) —MeshRendererDraweraccesses it viaEditor::GetPanel<InspectorPanel>(). - Transform + ID:
Removable=false; Transform + ID + all DEBUG drawers:ShowInAddMenu=false.DrawComponent<T>template deleted; legacy DEBUG-only Tag/Parent/Children add-menu entries dropped (hierarchy-managed, not user-addable).
Build Verification
6 atomic commits on refactor/editor-component-registry; every commit builds Debug x64 clean. Runtime smoke-tested: property edits + undo/redo, vector ops on AnimationController.Layers, Add-menu gating + init-value seeding, scene round-trip identical.
v2.7.3 — editor-undo-gaps
Date: 2026-04-23
Issue: #88
Overview
Wrap the 14 Editor::MarkDirty() callsites in InspectorPanel.cpp so the edits go through CommandHistory and survive Ctrl+Z. Most were vector-element edits inside AnimationController::Layers that bypassed undo because ComponentPropertyCommand<C, T> only addresses single member-pointers, not vec[i].field. EE4 of the post-v2.6 editor architecture review.
Key Changes
- New
commands/VectorCommands.htemplates:VectorElementPropertyCommand<C, Elem, T>,VectorInsertCommand<C, Elem>,VectorEraseCommand<C, Elem>. Per-boneBoneMask[i]workaround: snapshot the wholestd::vector<bool>(sidesteps proxy refs). - New
EntityActiveCommand;BoneAttachmentTarget/Bone combos wrapped viaBeginCompound/EndCompoundso multi-field edits undo atomically. - New
EXEC_COMPONENT_PROPmacro derivesTfromdecltype(OLD)and collapses the 6-linemake_unique<ComponentPropertyCommand<...>>(...)boilerplate; applied to 8 representative existing callsites. - Drive-by: spurious
MarkDirty()onEditorSettings::showBoneDebugdeleted (editor preference, not scene state). - Drive-by fix surfaced by smoke test:
Entity::isActivewas aboolon the wrapper struct, destroyed on everyScene::FindEntityByUUIDrebind — toggle visually snapped back next frame and active state never round-tripped through save/load. Replaced with aComponent::Disabledempty tag (sparse registry storage);Entity::SetActive/IsActivenow read/write via the registry.
Build Verification
7 atomic commits on epic/editor-undo-gaps; each builds Debug x64 clean. Runtime smoke (user-tested): all animation-layer + bone-mask + add/remove + entity-active + bone-attachment edits undo and redo correctly; entity-active toggle now persists across frames and across scene save/load.
v2.7.2 — editor-widgets-reorg
Date: 2026-04-19
Issue: #87
Overview
Split luthien/UI.{h,cpp} (506 LOC, ambiguous "UI" name) into five focused widget files under luthien/source/luthien/widgets/. All symbols stay in namespace Luth::UI so the 12 callsites only update their #include. EE3 of the post-v2.6 editor architecture review.
Key Changes
- New widgets:
Properties.{h,cpp}(Property<T>/PropertyColor/PropertyCombo+ per-axis vector reset rows),AssetSlot.{h,cpp}(PropertyAsset+ drag-drop),CollapsingHeader.{h,cpp},InfoTable.{h,cpp},TexturePreview.{h,cpp}(Vulkan ImGui descriptor cache). PropertyLabelpromoted to public soAssetSlotreuses the row layout fromProperties.widgets/Widgets.humbrella re-includes the five widget headers; rootUI.h/UI.cppdeleted; perl bulk-rewrite migrated all callers.- Drive-by: dead
static PushMultiItemsWidthsin oldUI.cppremoved (real callsite usesImGui::PushMultiItemsWidths).
Build Verification
6 atomic commits on epic/editor-widgets-reorg; each builds Debug x64 clean. Runtime smoke (user-tested): panels render, inspector drawers + asset drag-drop + texture previews work, no Vulkan validation warnings on shutdown.
v2.7.1 — editor-style-assets
Date: 2026-04-19
Issue: #86
Overview
StylePreset data moved from source into JSON assets under luth/assets/styles/. EditorStyle.cpp 616 → 280 LOC; Style menu gains Save / Load entries; Editor::LoadStyle(nameOrPath) replaces the four per-preset setters.
Key Changes
- Flat JSON schema:
name,font { mainFont, mainSize, mergeMainWithSolid, iconSize }, scalar style fields,colors { }keyed by stableImGui::GetStyleColorNamestrings (obsolete aliasesTabActive/TabUnfocused/NavHighlightresolve to canonical names). EditorStyle::LoadBuiltin(name)+LoadFromFile/SaveToFilehelpers.EditorSettings::activeStylePathpersists user-loaded paths; takes precedence overactiveStyle.- Public API collapses from
Set{Custom,Bubblegum,Matrix,Rider}Styleto a single deferredEditor::LoadStyle(nameOrPath). - Drive-by fix: Bubblegum and Matrix now merge FA-Solid into the main font — previously panel titles like
ICON_FA_LIST " Hierarchy"dropped their text glyphs under those styles.
Build Verification
7 atomic commits on epic/editor-style-assets; Debug x64 clean throughout. Runtime smoke: 4 built-in styles render, Save/Load round-trips, custom path persists, Bubblegum/Matrix panel titles fixed.
v2.7.0 - editor-cleanup
Date: 2026-04-19
Issue: #85
Overview
First epic of the post-v2.6 editor architecture review. Low-risk housekeeping across luthien/ — removes vestigial files, upgrades data structures, decomposes the Editor::Init() monolith, and establishes comment conventions for later editor-review epics. No runtime behavior change.
Key Changes
Command.cpp(2 stale comment lines) deleted;Command.hmoved tocommands/Commands.h.CommandHistorystacksstd::vector→std::deque— FIFO eviction now O(1) instead of O(N).Editor::GetPanel<T>()lineardynamic_castscan replaced bystd::unordered_map<std::type_index, Panel*>lookup (O(1)).Editor::Init()decomposed intoInitImGui+InitPanels+ApplyPersistence; publicInitis a 5-line orchestrator.- Comment sweep across
luthien/**: triple-line// ======banners →// ── Section ──one-liners, stale TODO/debt blocks removed,///doxygen normalized to//, redundant "what this field holds" prose dropped; WHY/gotcha comments preserved.
Build Verification
6 atomic commits on epic/editor-cleanup; Debug x64 clean. Runtime smoke (user-tested): all 9 panels render, undo/redo works, style switching works, settings persist across restart. Follow-up commit 776f1b3 on main fixed a font-atlas crash regression (fonts must load before the Vulkan atlas is built).