From 1d78090e19e04e32b4d936289e469855b72048cf Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 18 Aug 2026 12:17:48 +0000 Subject: [PATCH] fix(teleprompter): larger text, a cue triangle and a corner close Follow-up to the review pass: - 40px was too small once it was on a screen. 52px over the 1.3 line height keeps most of the density win, at 16 lines on a 1080p screen against the 11 the original defaults gave. - The speed follows the text size, since a larger font puts fewer words on a line. 14 lines per minute measures at 136 wpm on the new defaults, where 12 had dropped to 116. - The reading indicator is a triangle pointing in at the line rather than a bar. It is the shape prompter cue indicators have settled on: it names the line from the margin without putting a mark near the words. - The help dialog closes from an x in its corner, as the navigation menu and the params editor already do, rather than from a button under the list. - Teleprompter sits above Project Info in the navigation menu. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Cb8RVPNQ2ETPJxdy4b8CHf --- apps/client/src/viewerConfig.ts | 2 +- .../src/views/teleprompter/Teleprompter.scss | 26 +++++++++++++------ .../__tests__/teleprompter.options.test.ts | 4 +-- .../teleprompter/help-overlay/HelpOverlay.tsx | 14 +++++----- .../teleprompter/teleprompter.options.ts | 2 +- .../views/teleprompter/teleprompter.scroll.ts | 11 ++++---- 6 files changed, 36 insertions(+), 23 deletions(-) diff --git a/apps/client/src/viewerConfig.ts b/apps/client/src/viewerConfig.ts index ddde17547..6f4f3bac3 100644 --- a/apps/client/src/viewerConfig.ts +++ b/apps/client/src/viewerConfig.ts @@ -4,8 +4,8 @@ export const navigatorConstants = [ { url: 'timeline', label: 'Timeline' }, { url: 'studio', label: 'Studio Clock' }, { url: 'countdown', label: 'Countdown' }, - { url: 'info', label: 'Project Info' }, { url: 'teleprompter', label: 'Teleprompter' }, + { url: 'info', label: 'Project Info' }, ]; // default time format to use for users in 12 hour clocks diff --git a/apps/client/src/views/teleprompter/Teleprompter.scss b/apps/client/src/views/teleprompter/Teleprompter.scss index 99475a132..ca97c5a1b 100644 --- a/apps/client/src/views/teleprompter/Teleprompter.scss +++ b/apps/client/src/views/teleprompter/Teleprompter.scss @@ -151,15 +151,22 @@ pointer-events: none; } +/** + * A triangle pointing in at the line, which is the shape prompter cue + * indicators have settled on: it names one line without touching the words, + * and it reads as a pointer from the edge rather than as punctuation in the + * script. Clipped from a filled box rather than built from borders so its + * height stays tied to the parent's single line. + */ .teleprompter__reading-marker { position: absolute; top: 0; bottom: 0; /* sits in the gutter beside the column, never over the words */ - right: calc(100% + 0.4em); - width: 0.16em; - border-radius: 0.08em; + right: calc(100% + 0.35em); + width: 0.45em; background: $accent-color; + clip-path: polygon(0 0, 100% 50%, 0 100%); font-size: var(--tp-font-size); } @@ -238,10 +245,17 @@ font-size: 1rem; } +.teleprompter__help-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + margin-bottom: 1.25rem; +} + .teleprompter__help-title { font-size: 1.25rem; font-weight: 600; - margin-bottom: 1.25rem; } .teleprompter__help-groups { @@ -297,7 +311,3 @@ color: $viewer-label-color; font-size: calc(1rem - 5px); } - -.teleprompter__help-close { - margin-top: 1.5rem; -} diff --git a/apps/client/src/views/teleprompter/__tests__/teleprompter.options.test.ts b/apps/client/src/views/teleprompter/__tests__/teleprompter.options.test.ts index f5dafcee0..eb8a63ead 100644 --- a/apps/client/src/views/teleprompter/__tests__/teleprompter.options.test.ts +++ b/apps/client/src/views/teleprompter/__tests__/teleprompter.options.test.ts @@ -12,7 +12,7 @@ describe('getOptionsFromParams()', () => { showGroups: true, speed: DEFAULT_SPEED, followLoaded: true, - fontSize: 40, + fontSize: 52, lineHeight: 1.3, textWidth: 80, dimPast: true, @@ -60,7 +60,7 @@ describe('getOptionsFromParams()', () => { // Number(null) is 0, so a naive parse would silently produce a speed of zero expect(getOptionsFromParams(new URLSearchParams('speed=fast')).speed).toBe(DEFAULT_SPEED); expect(getOptionsFromParams(new URLSearchParams('speed=')).speed).toBe(DEFAULT_SPEED); - expect(getOptionsFromParams(new URLSearchParams('fontSize=huge')).fontSize).toBe(40); + expect(getOptionsFromParams(new URLSearchParams('fontSize=huge')).fontSize).toBe(52); }); test('rejects an unknown value for an enumerated option', () => { diff --git a/apps/client/src/views/teleprompter/help-overlay/HelpOverlay.tsx b/apps/client/src/views/teleprompter/help-overlay/HelpOverlay.tsx index 15ede9be6..4b47cf414 100644 --- a/apps/client/src/views/teleprompter/help-overlay/HelpOverlay.tsx +++ b/apps/client/src/views/teleprompter/help-overlay/HelpOverlay.tsx @@ -1,7 +1,8 @@ import { Dialog } from '@base-ui/react/dialog'; import type { PropsWithChildren } from 'react'; +import { IoClose } from 'react-icons/io5'; -import Button from '../../../common/components/buttons/Button'; +import IconButton from '../../../common/components/buttons/IconButton'; import Kbd from '../../../common/components/kbd/Kbd'; interface HelpOverlayProps { @@ -32,7 +33,12 @@ export default function HelpOverlay({ isOpen, onClose }: HelpOverlayProps) { - Prompter shortcuts +
+ Prompter shortcuts + + + +
@@ -94,10 +100,6 @@ export default function HelpOverlay({ isOpen, onClose }: HelpOverlayProps) {
- -
diff --git a/apps/client/src/views/teleprompter/teleprompter.options.ts b/apps/client/src/views/teleprompter/teleprompter.options.ts index 44dc0038e..3cba2bb65 100644 --- a/apps/client/src/views/teleprompter/teleprompter.options.ts +++ b/apps/client/src/views/teleprompter/teleprompter.options.ts @@ -38,7 +38,7 @@ const defaults = { showGroups: true, speed: DEFAULT_SPEED, followLoaded: true, - fontSize: 40, + fontSize: 52, lineHeight: 1.3, textWidth: 80, readingLine: true, diff --git a/apps/client/src/views/teleprompter/teleprompter.scroll.ts b/apps/client/src/views/teleprompter/teleprompter.scroll.ts index e6013640e..c2acad7d2 100644 --- a/apps/client/src/views/teleprompter/teleprompter.scroll.ts +++ b/apps/client/src/views/teleprompter/teleprompter.scroll.ts @@ -10,14 +10,15 @@ * * The default is calibrated against the reading rate rather than picked for * feel: broadcast presenters read at 140-160 words per minute and conference - * talent slower still, and at the default column width a line carries a dozen - * or so words. Twelve lines per minute lands in that band. The ceiling is set - * where the text stops being readable at all, not at the fastest the loop can - * physically scroll, so the arrow keys stay useful across their whole range. + * talent slower still, and at the default size a line carries around ten words. + * Fourteen lines per minute measures at 136 wpm, a presenter's pace rather than + * a news reader's. The ceiling is set where the text stops being readable at + * all, not at the fastest the loop can physically scroll, so the arrow keys + * stay useful across their whole range. */ export const MIN_SPEED = 1; export const MAX_SPEED = 40; -export const DEFAULT_SPEED = 12; +export const DEFAULT_SPEED = 14; /** how much one speed adjustment moves, shared by the keymap and the overlay */ export const SPEED_STEP = 1;