diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index 961a1c8..159407c 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -45,12 +45,12 @@ Get-Content .\state\evidence.jsonl -Tail 8 - Fensalir owns production GPU fusion, UI, and Spout2 publication. - `MimirSceneEditorState` is currently a 2D OBS-shaped program mixer owner, not a camera/3D scene editor. Synced video buffers become program layers with - normalized placement; the Eve/CultUI surface is Video Sources plus - source-adjacent layer actions on the left, a chrome-free program canvas in - the center, and Audio Mix on the right. Camera/SDF/model editor affordances - and numeric transform inspector controls have no live UI authority, and - editor camera/SDF/spline output no longer contributes to the runtime frame. - Smoke with `--scene-editor-smoke`. + normalized placement; the Eve/CultUI surface is Video Sources on the left, a + chrome-free program canvas in the center, Audio Mixer docked underneath that + canvas, and a Unity-style Inspector on the right for the selected layer's + properties. Camera/SDF/model editor affordances have no live UI authority, + and editor camera/SDF/spline output no longer contributes to the runtime + frame. Smoke with `--scene-editor-smoke`. - Live camera image buffers should use Fensalir-owned texture leases when they are rendering inputs: Mimir asks the engine broker for a keyed D3D12 Texture2D/fence lease, writes decoded frames into that texture, commits the diff --git a/src/Mimir.Runtime/MimirRuntime.cs b/src/Mimir.Runtime/MimirRuntime.cs index 529623e..d40c752 100644 --- a/src/Mimir.Runtime/MimirRuntime.cs +++ b/src/Mimir.Runtime/MimirRuntime.cs @@ -863,22 +863,10 @@ public sealed class MimirRuntime : IAquariumRuntime, IAquariumRuntimeServicesRec graph.Options("video.source-select", "Feed", () => presentationControls.SelectedVideoIndex, SelectVideoLayer, VideoFeedOptions()); graph.Text("video.program-summary", DescribeProgramVideo, "caption", weight: 0.75f); graph.Text("video.layer-list", sceneEditor.DescribeHierarchy, "mono", weight: 3.8f); - graph.Row("video.source-state", state => + graph.Row("video.nav", nav => { - state.Toggle("video.visible", "Visible", () => sceneEditor.SelectedNode?.Visible ?? false, SetSelectedVideoVisible); - state.Toggle("video.solo", "Solo", () => presentationControls.SelectedVideo?.Solo ?? false, SetSelectedVideoSolo); - }); - graph.Slider("video.opacity", "Opacity", () => presentationControls.SelectedVideo?.Opacity ?? 1.0f, SetSelectedVideoOpacity, 0.0f, 1.0f, "0.00"); - graph.Row("video.layer-fit", fit => - { - fit.Button("video.center", "Center", sceneEditor.CenterSelectedProgramLayer); - fit.Button("video.fit", "Fit", sceneEditor.FitSelectedProgramLayer); - fit.Button("video.fill", "Fill", sceneEditor.FillSelectedProgramLayer); - }); - graph.Row("video.layer-order", order => - { - order.Button("video.layer-up", "Layer Up", () => MoveSelectedVideoLayer(-1)); - order.Button("video.layer-down", "Layer Down", () => MoveSelectedVideoLayer(1)); + nav.Button("video.previous", "Previous", sceneEditor.SelectPrevious); + nav.Button("video.next", "Next", sceneEditor.SelectNext); }); graph.Text("video.selected", sceneEditor.DescribeSelection, "caption", weight: 1.2f); }, weight: 0.85f); @@ -886,15 +874,43 @@ public sealed class MimirRuntime : IAquariumRuntime, IAquariumRuntimeServicesRec shell.Vertical("mimir.editor-center", center => { center.Preview("scene.view-preview", "", () => sceneEditor.PreviewItems, weight: 1.0f); - }, weight: 2.1f); + center.Pane("mimir.audio-mixer", "Audio Mixer", mixer => + { + mixer.Options("audio.stem", "Stem", () => presentationControls.SelectedAudioIndex, SelectAudioStem, AudioFeedOptions()); + mixer.Row("audio.toggles", toggles => + { + toggles.Toggle("audio.mute", "Mute", () => presentationControls.SelectedAudio?.Muted ?? false, SetSelectedAudioMuted); + toggles.Toggle("audio.solo", "Solo", () => presentationControls.SelectedAudio?.Solo ?? false, SetSelectedAudioSolo); + }); + mixer.Slider("audio.gain", "Gain", () => presentationControls.SelectedAudio?.Gain ?? 1.0f, SetSelectedAudioGain, 0.0f, 2.0f, "0.00"); + mixer.Text("audio.program", DescribeProgramAudio, "caption", weight: 0.8f); + }, weight: 0.72f); + }, weight: 1.75f); - shell.Pane("mimir.audio-inspector", "Audio Mix", inspector => + shell.Pane("mimir.inspector", "Inspector", inspector => { - inspector.Options("audio.stem", "Stem", () => presentationControls.SelectedAudioIndex, SelectAudioStem, AudioFeedOptions()); - inspector.Toggle("audio.mute", "Mute", () => presentationControls.SelectedAudio?.Muted ?? false, SetSelectedAudioMuted); - inspector.Toggle("audio.solo", "Solo", () => presentationControls.SelectedAudio?.Solo ?? false, SetSelectedAudioSolo); - inspector.Slider("audio.gain", "Gain", () => presentationControls.SelectedAudio?.Gain ?? 1.0f, SetSelectedAudioGain, 0.0f, 2.0f, "0.00"); - inspector.Text("audio.program", DescribeProgramAudio, "caption", weight: 1.2f); + inspector.Text("inspector.selection", sceneEditor.DescribeSelection, "strong"); + inspector.Options("inspector.video-feed", "Feed", () => presentationControls.SelectedVideoIndex, SelectVideoLayer, VideoFeedOptions()); + inspector.Toggle("video.visible", "Visible", () => sceneEditor.SelectedNode?.Visible ?? false, SetSelectedVideoVisible); + inspector.Toggle("video.solo", "Solo", () => presentationControls.SelectedVideo?.Solo ?? false, SetSelectedVideoSolo); + inspector.Slider("video.opacity", "Opacity", () => presentationControls.SelectedVideo?.Opacity ?? 1.0f, SetSelectedVideoOpacity, 0.0f, 1.0f, "0.00"); + inspector.Text("inspector.program-placement", "Program Frame", "strong"); + inspector.Slider("program.x", "X", () => sceneEditor.SelectedProgramX, sceneEditor.SetSelectedProgramX, 0.0f, 1.0f, "0.000"); + inspector.Slider("program.y", "Y", () => sceneEditor.SelectedProgramY, sceneEditor.SetSelectedProgramY, 0.0f, 1.0f, "0.000"); + inspector.Slider("program.w", "W", () => sceneEditor.SelectedProgramWidth, sceneEditor.SetSelectedProgramWidth, 0.01f, 1.0f, "0.000"); + inspector.Slider("program.h", "H", () => sceneEditor.SelectedProgramHeight, sceneEditor.SetSelectedProgramHeight, 0.01f, 1.0f, "0.000"); + inspector.Slider("program.rotation", "Rotation", () => sceneEditor.SelectedNode?.Transform.RotationRadians ?? 0.0f, sceneEditor.SetSelectedRotation, -MathF.PI, MathF.PI, "0.00"); + inspector.Row("program.fit", fit => + { + fit.Button("program.center", "Center", sceneEditor.CenterSelectedProgramLayer); + fit.Button("program.fit-selected", "Fit", sceneEditor.FitSelectedProgramLayer); + fit.Button("program.fill-selected", "Fill", sceneEditor.FillSelectedProgramLayer); + }); + inspector.Row("program.order", order => + { + order.Button("program.layer-up", "Layer Up", () => MoveSelectedVideoLayer(-1)); + order.Button("program.layer-down", "Layer Down", () => MoveSelectedVideoLayer(1)); + }); }, weight: 0.95f); }); }); diff --git a/state/evidence.jsonl b/state/evidence.jsonl index c7c28d6..8be6d86 100644 --- a/state/evidence.jsonl +++ b/state/evidence.jsonl @@ -289,5 +289,6 @@ {"ts": "2026-05-31T22:30:36+01:00", "type": "verification", "status": "partial", "note": "Added sync_sweep.py plus stdlib-only Nightwing witness helpers. Live receipt artifacts/runtime/sync-sweep-hints-live proved Nightwing owns Eye/Move localization locally: nw-eye-0 and nw-eye-1 each captured about 1874 frames at 320x240@187 with zero sequence gaps and emitted 8/8 compact mimir.move_controller_observation_state.v1 hints, while Starfire analyzed its own ASIO/DShow/Kiyo streams. Nightwing builtin mic capture works but the cheap local chirp hint is not yet reliable enough to score as a timing witness."} {"ts":"2026-05-31T22:45:00+01:00","type":"implementation","status":"ok","note":"Mimir editor authority was cut back to a 2D OBS-shaped program mixer. SceneEditorState no longer creates default SDF/model content, preview items are video-feed-only, runtime editor camera/SDF/spline output is silent, and the Eve/CultUI surface is Video Sources with source-adjacent layer actions left, chrome-free program canvas center, and Audio Mix right. Numeric transform inspector controls were removed from the live surface. `--scene-editor-smoke` now verifies only camera+video feed nodes, video-only preview items, and normalized program placement.","files":["src/Mimir.Runtime/MimirRuntime.cs","src/Mimir.Runtime/Synchronization/MimirSceneEditorState.cs","src/Mimir.BufferSmoke/Program.cs"],"source":"dotnet build src/Mimir.Runtime/Mimir.Runtime.csproj; dotnet build src/Mimir.BufferSmoke/Mimir.BufferSmoke.csproj; dotnet run --no-build --project src/Mimir.BufferSmoke/Mimir.BufferSmoke.csproj -- --scene-editor-smoke; Mimir.App --headless --headless-width 1280 --headless-height 720 --capture-frame artifacts/runtime/mimir-editor-flat-2d-program-mixer-headless.png"} {"ts": "2026-05-31T22:46:40+01:00", "type": "implementation", "status": "ok", "note": "Added the first Starfire-owned camera frustum solve. MimirCameraFrustumCalibrationSolver consumes stable LED/marker correspondences, scene-space marker points, and seed frustums, then emits position, rotation, horizontal/vertical tangent half-FOV, correspondence count, clipspace reprojection residual, and confidence. BufferSmoke --frustum-calibration-smoke solves five synthetic frustums for ps3-eye-0, ps3-eye-1, kiyo-pro-rgb, leap-stereo-ir, and eve-camera with mean clip error 0.000000; room calibration lock still passes. Eve is now modeled like Nightwing as eve-local-sensor-witness/eve-local-sensors: it owns local camera/mic flash and chirp solves and ships typed hints, not raw placement authority."} +{"ts":"2026-05-31T23:05:00+01:00","type":"implementation","status":"ok","note":"Corrected the Mimir editor layout ownership after the flat-canvas pass: the center remains a chrome-free program compositor canvas, Audio Mixer is docked underneath that center canvas, and the right rail is again a Unity-style Inspector for the selected video layer's properties. Video Sources on the left now selects and navigates sources rather than carrying the property surface.","files":["src/Mimir.Runtime/MimirRuntime.cs","notes/fresh-workspace-handoff.md"],"source":"dotnet build src/Mimir.App/Mimir.App.csproj; dotnet run --no-build --project src/Mimir.BufferSmoke/Mimir.BufferSmoke.csproj -- --scene-editor-smoke; Mimir.App --headless --headless-width 1280 --headless-height 720 --capture-frame artifacts/runtime/mimir-editor-unity-inspector-audio-bottom-headless.png"} {"ts": "2026-05-31T22:52:47+01:00", "type": "implementation", "status": "ok", "note": "Extended MimirCameraFrustumCalibrationSolver beyond LED strips: it now also consumes MimirFeatureTrackFieldCandidate plus scene-space TrackId anchors, so PS Move sphere histories, sparse Eye tracks, and Eve-local marker tracks enter the same Starfire-owned frustum authority. BufferSmoke --frustum-calibration-smoke now proves five LED-spline frustums and five feature-track frustums for ps3-eye-0, ps3-eye-1, kiyo-pro-rgb, leap-stereo-ir, and eve-camera with mean clip error 0.000000."} {"ts": "2026-05-31T22:55:38+01:00", "type": "implementation", "status": "ok", "note": "Added mimir.local_frustum_hint_state.v1 as the CultMesh document for local witness frustum solves. It carries producer node, calibration id, candidate key, marker set id, per-camera pose/frustum snapshots, residuals, point counts, and confidence, so Eve/Nightwing can publish compact solved hints while Starfire remains canonical global placement authority."}