Own camera: mirror consistently in preview, tile and large view; not a camera facing away
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -43,6 +43,9 @@ class ScreenShare {
|
||||
host = $state.raw<Session | null>(null);
|
||||
stream = $state.raw<MediaStream | null>(null);
|
||||
kind = $state<ShareKind>('screen');
|
||||
// Show our own camera mirrored to ourselves, as a mirror would. Not a camera pointing away
|
||||
// from us (a phone's back camera), and never what the others get.
|
||||
mirror = $state(false);
|
||||
viewers = $state(0);
|
||||
// Streams we receive: one screen at a time, and any number of cameras next to it
|
||||
watches = $state.raw<Watching[]>([]);
|
||||
@@ -142,6 +145,7 @@ class ScreenShare {
|
||||
}
|
||||
this.usesVirtualMic = usesVirtualMic;
|
||||
this.kind = kind;
|
||||
this.mirror = kind === 'camera' && stream.getVideoTracks()[0]?.getSettings().facingMode !== 'environment';
|
||||
this.host = s;
|
||||
this.stream = stream;
|
||||
this.send(s, this.others(s), SHARE.on, kind);
|
||||
|
||||
@@ -220,7 +220,7 @@
|
||||
<span class="label">Preview</span>
|
||||
<div class="preview">
|
||||
<!-- svelte-ignore a11y_media_has_caption -->
|
||||
<video bind:this={video} autoplay playsinline muted></video>
|
||||
<video bind:this={video} class:mirror={kind === 'camera' && preview?.getVideoTracks()[0]?.getSettings().facingMode !== 'environment'} autoplay playsinline muted></video>
|
||||
{#if !preview}<p>Nothing chosen yet</p>{/if}
|
||||
</div>
|
||||
|
||||
@@ -280,6 +280,8 @@
|
||||
.name { font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.preview { position: relative; background: #000; aspect-ratio: 16 / 9; max-height: 240px; margin: 0 auto; width: 100%; }
|
||||
.preview video { width: 100%; height: 100%; object-fit: contain; display: block; }
|
||||
/* Your own camera as a mirror shows you; a camera facing away is left as it is */
|
||||
.preview video.mirror { transform: scaleX(-1); }
|
||||
.preview p { position: absolute; inset: 0; margin: 0; display: flex; align-items: center; justify-content: center; color: #aaa; font-size: 13px; }
|
||||
.check { display: flex; align-items: center; gap: 8px; text-transform: none; font-weight: 400; letter-spacing: 0; font-size: 14px; color: var(--text); margin-top: 12px; }
|
||||
.check input { width: auto; }
|
||||
|
||||
@@ -267,7 +267,7 @@
|
||||
{:else}
|
||||
<div class="pic" role="presentation" oncontextmenu={streamMenu}
|
||||
ontouchstart={touchStart} ontouchend={touchEnd} ontouchmove={touchEnd} ontouchcancel={touchEnd}>
|
||||
<video bind:this={spotVideo} use:media={focused} autoplay playsinline muted ondblclick={fullscreen}></video>
|
||||
<video bind:this={spotVideo} class:mirror={focus === self.session && share.mirror} use:media={focused} autoplay playsinline muted ondblclick={fullscreen}></video>
|
||||
{#if focus !== self.session && focusWatch && focusWatch.state !== 'live'}
|
||||
<p class="pending" class:bad={focusWatch.state === 'failed'}>{focusWatch.state === 'failed'
|
||||
? 'Could not connect to the stream. Across the internet both of you need a STUN server; networks that block direct connections need a relay. Both are in Settings, Voice.'
|
||||
@@ -298,7 +298,7 @@
|
||||
aria-label={stream ? `${focus === u.session ? 'Hide' : 'Show'} the ${sharing || 'stream'} of ${store.displayName(u)}` : sharing && !isSelf ? `Watch the ${sharing} of ${store.displayName(u)}` : store.displayName(u)}>
|
||||
{#if cam}
|
||||
<!-- svelte-ignore a11y_media_has_caption -->
|
||||
<video class:mirror={isSelf} use:media={cam} autoplay playsinline muted></video>
|
||||
<video class:mirror={isSelf && share.mirror} use:media={cam} autoplay playsinline muted></video>
|
||||
{:else}
|
||||
<Avatar name={u.name} size={avatar} speaking={talking(u.session)} />
|
||||
{/if}
|
||||
@@ -414,7 +414,7 @@
|
||||
/* A camera keeps its own shape inside the tile, whatever size the tile is: nothing is cut
|
||||
off, a phone held upright gets bars at the sides. Your own is mirrored, like a mirror. */
|
||||
.tile video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; background: #000; }
|
||||
.tile video.mirror { transform: scaleX(-1); }
|
||||
.tile video.mirror, .spot video.mirror { transform: scaleX(-1); }
|
||||
.icon-btn.live, .icon-btn.live:hover { color: var(--speaking); }
|
||||
.camgrid { position: relative; display: flex; flex-direction: column; flex: none; }
|
||||
/* Name tag over the lower left corner */
|
||||
|
||||
Reference in New Issue
Block a user