fix: creator feedback batch Branch 1 — TRAX volume, tooltip, meter boost, slider click, backdrop
- TRAX: LocalGain now applies 0.2× factor so music is quieter relative to desktop audio slider - TRAX tooltip: switched to ToolTipService with Placement=Top to fix z-order in Viewbox overlay - Mic meter: MeterLevel multiplied by 1.2× before clamping for ~20% higher visual readout - Volume sliders: click anywhere on track to jump thumb to that position before dragging - Backdrop: Image Visibility now binds to BackdropVisible; compositor checks IsVisible before blit - Renamed 'Backdrop' to 'Game Capture' in EnsureBackdrop + test assertions
This commit is contained in:
+4
-6
@@ -5,10 +5,10 @@
|
||||
> a problem. Conventions: [`schema.md`](schema.md). Rewrite this file at session
|
||||
> end, compaction, or any interruption.
|
||||
|
||||
## Session state (last updated: 2026-08-16, renumbering finalised)
|
||||
## Session state (last updated: 2026-08-17, creator feedback batch Branch 1)
|
||||
|
||||
- **Branch:** `main`, tracking `origin/main`. Working tree: the **TASK 9 reusable-stream slice** is
|
||||
committed + pushed (details below). Local branches `social-bar`/`webcam-validation` untouched (no secrets).
|
||||
- **Branch:** `main`, tracking `origin/main`. Working tree: **TASK 14 Branch 1 (quick fixes)** — TRAX volume, tooltip, mic meter boost, click-to-position sliders, backdrop visibility + rename. Build **0 warnings**, **207 tests passing**. Ready to commit.
|
||||
- **TASK 14 — CREATOR FEEDBACK BATCH — IN PROGRESS.** Branch 1 shipped: TRAX volume 0.2× factor, TRAX tooltip z-order fix, mic meter +20% boost, click-to-position volume sliders, backdrop visibility binding + compositor guard, rename "Backdrop" → "Game Capture". Branch 2 pending: Elements panel, webcam border config, Countdown source (Starting/BRB), Web source.
|
||||
- **TASK 9 — REUSABLE STREAM + HEALTH BANNER — SHIPPED 2026-08-16 (items 1–3).**
|
||||
- **Items 1–2 (reusable stream):** `_rtmpUrlProvider` now yields a real RTMP URL.
|
||||
`YouTubeStreamService` gains `GetOrCreateReusableStreamAsync` (lists `liveStreams?mine=true`,
|
||||
@@ -40,9 +40,7 @@
|
||||
- **TASK 13 added** — marcom/launch kit. Business details moved to `MARCOM.md`. Queued after all v1 features.
|
||||
- **Backlog updated** — removed v0.3 (stream scheduling, not needed for casual streamers). Multi-destination
|
||||
restreaming noted as "congrats, you're ready for OBS" moment.
|
||||
- **Resume point (next branch):** **TASK 9 item 4 — live chat** (`liveChat/messages` poll, right-panel
|
||||
render, Super Chat + membership badges). Then item 5 (error handling), item 6 (visibility unlock),
|
||||
item 7 (full broadcast form), then TASK 10 (billing + unlock + support).
|
||||
- **Resume point (next branch):** **TASK 14 Branch 2** — Elements panel beneath Sources (per-element config with live preview, ✕ revert / ✓ commit), webcam border config (color #RRGGBB + picker, thickness 0–10), Countdown source (Starting/BRB scenes, timer 1–60 min), Web source (all scenes, URI input). Then **TASK 9 item 4 — live chat**.
|
||||
- **TASK 12 — MASTER LIMITER — COMMITTED + PUSHED 2026-08-15.** Queued from the TRAX discussion: the
|
||||
live mix summed mic + loopback with no ceiling, so hot gains could pass 0 dBFS and clip the AAC
|
||||
encode. New pure `Services/Audio/MasterLimiter.cs` (−1 dBFS ceiling, instant attack per frame,
|
||||
|
||||
+3
-1
@@ -389,6 +389,7 @@
|
||||
<!-- Live desktop/game backdrop (bottom layer; the static
|
||||
background renders above it). -->
|
||||
<Image Source="{Binding BackdropImage}" Stretch="UniformToFill"
|
||||
Visibility="{Binding BackdropVisible, Converter={StaticResource BoolToVis}}"
|
||||
IsHitTestVisible="False"/>
|
||||
<Image Source="{Binding ActiveBackgroundImage}" Stretch="UniformToFill"
|
||||
IsHitTestVisible="False"/>
|
||||
@@ -779,7 +780,8 @@
|
||||
desktop audio controls. -->
|
||||
<Button Style="{StaticResource YtButtonSecondary}" Padding="8,2"
|
||||
FontSize="11" VerticalAlignment="Center" Margin="0,0,8,0"
|
||||
ToolTip="{Binding TraxToolTip}"
|
||||
ToolTipService.ToolTip="{Binding TraxToolTip}"
|
||||
ToolTipService.Placement="Top"
|
||||
Click="TraxButton_Click"
|
||||
PreviewMouseRightButtonUp="TraxButton_PreviewMouseRightButtonUp">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
|
||||
@@ -83,6 +83,8 @@ public partial class MainWindow : Window
|
||||
|
||||
private void VolumeSlider_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (sender is Slider slider)
|
||||
SetSliderValueFromClick(slider, e);
|
||||
if (sender is FrameworkElement { DataContext: MainViewModel vm })
|
||||
vm.SetVolumeAdjusting(true);
|
||||
}
|
||||
@@ -101,6 +103,8 @@ public partial class MainWindow : Window
|
||||
|
||||
private void GameVolumeSlider_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (sender is Slider slider)
|
||||
SetSliderValueFromClick(slider, e);
|
||||
if (sender is FrameworkElement { DataContext: MainViewModel vm })
|
||||
vm.SetGameVolumeAdjusting(true);
|
||||
}
|
||||
@@ -117,6 +121,15 @@ public partial class MainWindow : Window
|
||||
vm.SetGameVolumeAdjusting(false);
|
||||
}
|
||||
|
||||
private static void SetSliderValueFromClick(Slider slider, MouseButtonEventArgs e)
|
||||
{
|
||||
var track = slider.Template.FindName("PART_Track", slider) as System.Windows.Controls.Primitives.Track;
|
||||
if (track == null) return;
|
||||
var pos = e.GetPosition(track);
|
||||
var fraction = Math.Clamp(pos.X / track.RenderSize.Width, 0, 1);
|
||||
slider.Value = slider.Minimum + fraction * (slider.Maximum - slider.Minimum);
|
||||
}
|
||||
|
||||
private void MicSpeaker_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (sender is FrameworkElement { DataContext: MainViewModel vm })
|
||||
|
||||
@@ -46,7 +46,7 @@ public sealed class SceneCompositor
|
||||
var elements = scene.Elements;
|
||||
|
||||
var backdrop = elements.OfType<Source>().FirstOrDefault(s => s.IsBackdrop);
|
||||
var backdropFrame = backdrop != null ? frameFor(backdrop) : null;
|
||||
var backdropFrame = backdrop != null && backdrop.IsVisible ? frameFor(backdrop) : null;
|
||||
if (backdropFrame != null)
|
||||
BlitContent(buffer, cropW, cropH, 0, 0, cropW, cropH, backdropFrame, 1f, false, false);
|
||||
|
||||
|
||||
@@ -809,6 +809,21 @@ No changes to `MusicPlayer`, the 0.20 cap, the ducker, or the meter zones. Build
|
||||
|
||||
---
|
||||
|
||||
## TASK 14 — Creator feedback batch: quick fixes (TRAX, meter, backdrop, sliders)
|
||||
|
||||
**Goal:** address creator's immediate UX feedback from testing session.
|
||||
|
||||
### Status: 🔶 In progress — Branch 1 (items 1–5) shipped
|
||||
|
||||
1. ✅ TRAX volume — `LocalGain = GameAudioVolume * 0.2` so TRAX is 20% of the desktop audio slider (was 100%, now quieter)
|
||||
2. ✅ TRAX tooltip — replaced `ToolTip` binding with `ToolTipService.ToolTip` + `Placement="Top"` to fix z-order inside Viewbox overlay
|
||||
3. ✅ Mic meter boost — `MeterLevel` multiplied by 1.2× before clamping so the bar reads ~20% higher at same input level
|
||||
4. ✅ Click-to-position sliders — clicking anywhere on the mic/game volume slider track now jumps the thumb to that position before starting the drag
|
||||
5. ✅ Backdrop visibility — the dedicated `<Image>` now binds `Visibility` to `BackdropVisible` (ViewModel property); compositor checks `IsVisible` before blit
|
||||
6. ✅ Rename "Backdrop" → "Game Capture" in `EnsureBackdrop()` + test assertions
|
||||
|
||||
---
|
||||
|
||||
## Backlog (future versions)
|
||||
|
||||
1. v0.2 — Recording to local file (recordings carry the branding flash — see TASK 3 / `ai.md` Monetization)
|
||||
|
||||
@@ -197,9 +197,14 @@ public class MainViewModel : ViewModelBase
|
||||
private set
|
||||
{
|
||||
if (SetProperty(ref _backdropImage, value))
|
||||
{
|
||||
OnPropertyChanged(nameof(ShowPreviewPlaceholder));
|
||||
OnPropertyChanged(nameof(BackdropVisible));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool BackdropVisible => ActiveScene?.Elements.OfType<Source>().FirstOrDefault(s => s.IsBackdrop)?.IsVisible == true;
|
||||
|
||||
public SceneElement? SelectedElement
|
||||
{
|
||||
@@ -337,7 +342,7 @@ public class MainViewModel : ViewModelBase
|
||||
/// level flashes on the bar) so the creator sees where they're setting it;
|
||||
/// otherwise the realtime live level scaled by volume (raising the volume
|
||||
/// moves ambient noise up the bar). Read-only meter.</summary>
|
||||
private double MeterLevel => MicMuted ? 0 : _volumeAdjusting || _volumeFlash ? MicVolume : Math.Min(1, AudioLevelMeter.ToDisplay((float)AudioLevel) * MicVolume);
|
||||
private double MeterLevel => MicMuted ? 0 : _volumeAdjusting || _volumeFlash ? MicVolume : Math.Min(1, AudioLevelMeter.ToDisplay((float)AudioLevel) * 1.2 * MicVolume);
|
||||
|
||||
public double MeterFillWidth => MeterLevel * 288;
|
||||
|
||||
@@ -595,7 +600,7 @@ public class MainViewModel : ViewModelBase
|
||||
/// Called whenever the game volume/mute change and on TRAX load.</summary>
|
||||
private void UpdateTraxLocalGain()
|
||||
{
|
||||
_musicPlayer.LocalGain = GameMuted ? 0f : (float)GameAudioVolume;
|
||||
_musicPlayer.LocalGain = GameMuted ? 0f : (float)(GameAudioVolume * 0.2);
|
||||
}
|
||||
|
||||
/// <summary>Live desktop/game input level (0..1), fed by the mixer's loopback
|
||||
@@ -1405,7 +1410,7 @@ public class MainViewModel : ViewModelBase
|
||||
|
||||
backdrop = new Source
|
||||
{
|
||||
Name = "Backdrop",
|
||||
Name = "Game Capture",
|
||||
Type = SourceType.DisplayCapture,
|
||||
IsBackdrop = true,
|
||||
IsEnabled = true,
|
||||
@@ -1697,6 +1702,8 @@ public class MainViewModel : ViewModelBase
|
||||
{
|
||||
if (element == null) return;
|
||||
element.IsVisible = !element.IsVisible;
|
||||
if (element is Source { IsBackdrop: true })
|
||||
OnPropertyChanged(nameof(BackdropVisible));
|
||||
}
|
||||
|
||||
private void AddSource(object? parameter)
|
||||
|
||||
@@ -90,7 +90,7 @@ public class LayoutStorePersistenceTests
|
||||
using var store = new LayoutStore(path);
|
||||
var backdrop = new Source
|
||||
{
|
||||
Name = "Backdrop",
|
||||
Name = "Game Capture",
|
||||
Type = SourceType.DisplayCapture,
|
||||
IsBackdrop = true,
|
||||
IsEnabled = true,
|
||||
|
||||
Reference in New Issue
Block a user