GUI: Blasen-Oeffnung positionsgenau zum Sprecher (--ax aus Sitzposition)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113vDKdSNtD3Dwcw4QMu9yV
This commit is contained in:
schakal00783
2026-07-17 01:26:57 +02:00
co-authored by Claude Fable 5
parent 55f03e7389
commit 6a51699e90
3 changed files with 18 additions and 6 deletions
+9 -2
View File
@@ -604,6 +604,10 @@ async function openRecording(id) {
bubble.className = `tbubble ${scls[tu.sp] || ''} arrow-${seat.side}`;
bubble.style.left = '';
bubble.style.top = '';
// Tail x-position along the top/bottom edge = the speaker's seat mapped
// into bubble-local coordinates (bubble is centred, BUBBLE_W wide).
const ax = Math.max(8, Math.min(92, (seat.x - (50 - BUBBLE_W / 2)) / BUBBLE_W * 100));
bubble.style.setProperty('--ax', ax.toFixed(1) + '%');
bubble.querySelector('.tb-name').textContent = spkLabel(tu.sp, i >= 0 ? i : 0);
// The full turn as clickable word spans — highlighted + scrolled below.
bubble.querySelector('.tb-text').innerHTML =
@@ -746,11 +750,14 @@ function escapeHtml(s) { return (s || '').replace(/[&<>"]/g, c => ({ '&': '&amp;
const SEAT_LAYOUTS = {
1: [{ x: 50, y: 84, side: 'bottom' }],
2: [{ x: 50, y: 14, side: 'top' }, { x: 50, y: 84, side: 'bottom' }],
3: [{ x: 50, y: 13, side: 'top' }, { x: 26, y: 84, side: 'bottomleft' }, { x: 74, y: 84, side: 'bottomright' }],
3: [{ x: 50, y: 13, side: 'top' }, { x: 26, y: 84, side: 'bottom' }, { x: 74, y: 84, side: 'bottom' }],
4: [{ x: 50, y: 12, side: 'top' }, { x: 90, y: 50, side: 'right' }, { x: 50, y: 86, side: 'bottom' }, { x: 10, y: 50, side: 'left' }],
5: [{ x: 32, y: 12, side: 'top' }, { x: 68, y: 12, side: 'top' }, { x: 90, y: 60, side: 'right' }, { x: 50, y: 86, side: 'bottom' }, { x: 10, y: 60, side: 'left' }],
6: [{ x: 32, y: 12, side: 'top' }, { x: 68, y: 12, side: 'top' }, { x: 90, y: 50, side: 'right' }, { x: 68, y: 86, side: 'bottomright' }, { x: 32, y: 86, side: 'bottomleft' }, { x: 10, y: 50, side: 'left' }],
6: [{ x: 32, y: 12, side: 'top' }, { x: 68, y: 12, side: 'top' }, { x: 90, y: 50, side: 'right' }, { x: 68, y: 86, side: 'bottom' }, { x: 32, y: 86, side: 'bottom' }, { x: 10, y: 50, side: 'left' }],
};
// Bubble width in scene-% (kept in sync with .tbubble in style.css) — needed to
// map a seat's x onto the bubble edge so the tail points AT the speaker.
const BUBBLE_W = 54;
function tableSeats(n) { return SEAT_LAYOUTS[Math.min(6, Math.max(1, n))] || SEAT_LAYOUTS[6]; }
// Toggle-button icons: three people around a table / a text sheet.
+2 -4
View File
@@ -316,12 +316,10 @@ audio { width: 100%; margin-bottom: 10px; }
display: none;
}
.tbubble[class*="arrow-"]::after { display: block; }
.tbubble.arrow-top::after { top: -7px; left: 50%; transform: translateX(-50%) rotate(-135deg); }
.tbubble.arrow-bottom::after { bottom: -7px; left: 50%; transform: translateX(-50%) rotate(45deg); }
.tbubble.arrow-top::after { top: -7px; left: var(--ax, 50%); transform: translateX(-50%) rotate(-135deg); }
.tbubble.arrow-bottom::after { bottom: -7px; left: var(--ax, 50%); transform: translateX(-50%) rotate(45deg); }
.tbubble.arrow-left::after { left: -7px; top: 50%; transform: translateY(-50%) rotate(135deg); }
.tbubble.arrow-right::after { right: -7px; top: 50%; transform: translateY(-50%) rotate(-45deg); }
.tbubble.arrow-bottomleft::after { bottom: -7px; left: 22%; transform: rotate(45deg); }
.tbubble.arrow-bottomright::after { bottom: -7px; right: 22%; transform: rotate(45deg); }
.tidle { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); font-size: 13px; text-align: center; }
#viewswitch svg { display: block; }