From a402d1c035d4721778bc0f7e7af07d0a2576b5a2 Mon Sep 17 00:00:00 2001 From: Kibi Kelburton Date: Thu, 1 Oct 2026 22:19:51 +0200 Subject: [PATCH] Streams open large by default; tiles never carry the picture Co-Authored-By: Claude Opus 5.5 --- README.md | 2 +- src/ui/VoiceStage.svelte | 29 +++++++++++++++-------------- test/e2e/share.e2e.ts | 16 +++++++++------- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 495f57d..a4f13e7 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ mumh5 keeps the foundation and replaces the experience. - Share a screen or a window with the mumh5 users in your channel. A dialog lets you choose what to show, with a live preview, which sound goes with it and the quality, before anything is sent - Sound: on Linux one program or everything except mumh5 itself (through PipeWire, so viewers do not hear the voice chat twice); on Windows the whole system; in a browser what the browser offers -- People in the channel see an indicator next to your name, on your tile and in your profile, and click to watch. The tiles above the chat fill a stage you can drag taller or shorter. A sharer's tile shows the picture; a click makes it large with everyone else in a strip below, like a meeting, and it can move to a window of its own. Viewers set the stream's volume +- People in the channel see an indicator next to your name, on your tile and in your profile, and click to watch. The tiles above the chat fill a stage you can drag taller or shorter. A stream opens large, with everyone as a strip of tiles below, like a meeting, and can move to a window of its own; in the stacked layout it is just the picture, as wide as the chat. Sounds announce streams and viewers. Viewers set the stream's volume - No server setup and no extra account: the setup messages travel through the Mumble server, the stream goes directly between the two clients (WebRTC), up to 8 viewers. Regular Mumble clients do not see streams - Direct connections mean sharer and viewer see each other's IP address; mumh5 says so before the first use. Across the internet both sides need a STUN server. The browser version uses the one built into its proxy; in the desktop app you enter one in Settings, Voice (the proxy's address works there too), and none is contacted unless you do - Tested between two desktop instances on one machine with a test picture. Sound capture, real screens, connections across the internet, Windows and the browser build are untested diff --git a/src/ui/VoiceStage.svelte b/src/ui/VoiceStage.svelte index 5885ae0..d96e5af 100644 --- a/src/ui/VoiceStage.svelte +++ b/src/ui/VoiceStage.svelte @@ -12,8 +12,8 @@ import ResizeHandle from './ResizeHandle.svelte'; // People in your voice channel as tiles. Shown on windows too narrow for the member list - // (always), and on any window while someone in the channel shares a screen: a sharer's tile - // carries the picture, and clicking it puts it on a large stage with the tiles as a strip. + // (always), and on any window while someone in the channel shares a screen. A stream is shown + // large above the tiles, which become a strip; the tiles themselves never carry the picture. // videoOnly: just the picture, as wide as the chat (stacked layout, where the channel list // above already shows who is here) let { always = false, videoOnly = false }: { always?: boolean; videoOnly?: boolean } = $props(); @@ -34,7 +34,7 @@ return watching?.session === s ? watching.stream : null; } - // Tiles with a picture come first, then other people who share, so streams sit at the top left + // People with a stream we can show come first, then others who share const rank = (s: number) => streamOf(s) ? 0 : session.sharing[s] ? 1 : 2; const people = $derived([...inChannel].sort((a, b) => rank(a.session) - rank(b.session))); @@ -52,7 +52,14 @@ lastWatch = now; } }); - $effect(() => { if (focus === self?.session && !mine) focus = null; }); + // Our own stream opens large when it starts, unless another one is on the stage + let hadMine = false; + $effect(() => { + const has = !!mine; + if (has && !hadMine && focus == null && self) focus = self.session; + else if (!has && focus === self?.session) focus = null; + hadMine = has; + }); // Without tiles there is nothing to choose: the watched stream, else our own $effect(() => { if (videoOnly) focus = watching ? watching.session : mine ? self?.session ?? null : null; }); @@ -264,17 +271,12 @@ {@const sharing = !!session.sharing[u.session]} {@const isSelf = u.session === self.session}
  • -