From b42b10829a561cb1a8ad266f4677ba576802a106 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 16 Aug 2026 09:04:34 +0000 Subject: [PATCH] refactor(teleprompter): drop the two options that cannot justify themselves yet Options are permanent surface. They live in URLs and in saved presets, so one can be added later without breaking anything while removing one breaks every preset that named it. That asymmetry says to keep only what earns its place before the view ships, not after. Autoplay goes. Its own code said as much: it was the single option needing a lint suppression because it is a starting condition rather than a live setting, which is not how any other option here behaves. It also has no coherent use. Starting a scroll on load runs the script at a fixed rate whether or not anybody is speaking, and following the loaded event, which is on by default, immediately pulls the position somewhere else. Anyone wanting a prompter to roll unattended needs the transport control we have not built. Alignment goes. Nothing in the research pointed at it as a control operators reach for, and centring multi line paragraphs leaves a ragged left edge which is harder to track back to on each new line. Left is the safer default and the option can come back cheaply if somebody asks for it. Seventeen options remain, and each maps to something the research called for or to the font and colour trio the other views already share. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Cb8RVPNQ2ETPJxdy4b8CHf --- .../src/views/teleprompter/Teleprompter.scss | 1 - .../src/views/teleprompter/Teleprompter.tsx | 2 -- .../__tests__/teleprompter.options.test.ts | 6 +---- .../teleprompter/teleprompter.options.ts | 25 ------------------- .../views/teleprompter/teleprompter.types.ts | 2 -- .../teleprompter/useTeleprompterScroll.ts | 10 -------- 6 files changed, 1 insertion(+), 45 deletions(-) diff --git a/apps/client/src/views/teleprompter/Teleprompter.scss b/apps/client/src/views/teleprompter/Teleprompter.scss index 1d404349f..e0f81b222 100644 --- a/apps/client/src/views/teleprompter/Teleprompter.scss +++ b/apps/client/src/views/teleprompter/Teleprompter.scss @@ -64,7 +64,6 @@ font-size: var(--tp-font-size); line-height: var(--tp-line-height); - text-align: var(--tp-align); /** * The first line has to be able to reach the reading line, and the last line diff --git a/apps/client/src/views/teleprompter/Teleprompter.tsx b/apps/client/src/views/teleprompter/Teleprompter.tsx index 747700704..bdb46d759 100644 --- a/apps/client/src/views/teleprompter/Teleprompter.tsx +++ b/apps/client/src/views/teleprompter/Teleprompter.tsx @@ -87,7 +87,6 @@ function Teleprompter({ rundown, rundownMetadata, customFields }: TeleprompterDa atEnd, } = useTeleprompterScroll({ initialSpeed: options.speed, - autoplay: options.autoplay, followLoaded: options.followLoaded, selectedEventId, readingLinePos: options.readingLinePos, @@ -121,7 +120,6 @@ function Teleprompter({ rundown, rundownMetadata, customFields }: TeleprompterDa // the overlays and by 1dvh for the content padding. Percentage padding would // resolve against width and put the first line nowhere near the reading line '--tp-reading-line': options.readingLinePos, - '--tp-align': options.align, '--tp-background': options.keyColour, '--tp-color': options.textColour, ...(options.font ? { '--font-family-override': options.font } : {}), 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 1ed835265..de549fe5b 100644 --- a/apps/client/src/views/teleprompter/__tests__/teleprompter.options.test.ts +++ b/apps/client/src/views/teleprompter/__tests__/teleprompter.options.test.ts @@ -11,12 +11,10 @@ describe('getOptionsFromParams()', () => { hideEmpty: true, showGroups: true, speed: DEFAULT_SPEED, - autoplay: false, followLoaded: true, fontSize: 64, lineHeight: 1.5, textWidth: 90, - align: 'left', dimPast: true, readingLine: 'line', readingLinePos: 40, @@ -44,10 +42,9 @@ describe('getOptionsFromParams()', () => { }); test('booleans which default to false can be turned on', () => { - const options = getOptionsFromParams(new URLSearchParams('autoplay=true&flipH=true&flipV=true')); + const options = getOptionsFromParams(new URLSearchParams('flipH=true&flipV=true')); expect(options).toMatchObject({ - autoplay: true, flipH: true, flipV: true, }); @@ -68,7 +65,6 @@ describe('getOptionsFromParams()', () => { test('rejects an unknown value for an enumerated option', () => { expect(getOptionsFromParams(new URLSearchParams('heading=banana')).heading).toBe('title'); expect(getOptionsFromParams(new URLSearchParams('readingLine=banana')).readingLine).toBe('line'); - expect(getOptionsFromParams(new URLSearchParams('align=banana')).align).toBe('left'); }); test('adds the hash back to colour params', () => { diff --git a/apps/client/src/views/teleprompter/teleprompter.options.ts b/apps/client/src/views/teleprompter/teleprompter.options.ts index fcc36c8fa..39af31329 100644 --- a/apps/client/src/views/teleprompter/teleprompter.options.ts +++ b/apps/client/src/views/teleprompter/teleprompter.options.ts @@ -23,14 +23,8 @@ const readingLineOptions = [ { value: 'none', label: 'None' }, ]; -const alignOptions = [ - { value: 'left', label: 'Left' }, - { value: 'center', label: 'Centre' }, -]; - const headingSources: readonly HeadingSource[] = ['none', 'title', 'cue', 'both']; const readingLineVariants: readonly ReadingLineVariant[] = ['none', 'line', 'arrows']; -const alignments = ['left', 'center'] as const; /** * Defaults and bounds for every option, in one place. @@ -45,12 +39,10 @@ const defaults = { hideEmpty: true, showGroups: true, speed: DEFAULT_SPEED, - autoplay: false, followLoaded: true, fontSize: 64, lineHeight: 1.5, textWidth: 90, - align: 'left', readingLine: 'line', readingLinePos: 40, dimPast: true, @@ -110,13 +102,6 @@ export const getTeleprompterOptions = (customFields: CustomFields): ViewOption[] type: 'number', defaultValue: defaults.speed, }, - { - id: 'autoplay', - title: 'Start scrolling on load', - description: 'Whether the script starts scrolling as soon as the view opens', - type: 'boolean', - defaultValue: defaults.autoplay, - }, { id: 'followLoaded', title: 'Follow loaded event', @@ -171,14 +156,6 @@ export const getTeleprompterOptions = (customFields: CustomFields): ViewOption[] type: 'number', defaultValue: defaults.textWidth, }, - { - id: 'align', - title: 'Text alignment', - description: 'Alignment of the script text', - type: 'option', - values: alignOptions, - defaultValue: defaults.align, - }, { id: 'readingLine', title: 'Reading line', @@ -288,13 +265,11 @@ export function getOptionsFromParams( showGroups: toBoolean(getValue('showGroups'), defaults.showGroups), speed: clampSpeed(toNumber(getValue('speed'), bounds.speed, defaults.speed)), - autoplay: toBoolean(getValue('autoplay'), defaults.autoplay), followLoaded: toBoolean(getValue('followLoaded'), defaults.followLoaded), fontSize: toNumber(getValue('fontSize'), bounds.fontSize, defaults.fontSize), lineHeight: toNumber(getValue('lineHeight'), bounds.lineHeight, defaults.lineHeight), textWidth: toNumber(getValue('textWidth'), bounds.textWidth, defaults.textWidth), - align: toEnum(getValue('align'), alignments, defaults.align), dimPast: toBoolean(getValue('dimPast'), defaults.dimPast), readingLine: toEnum(getValue('readingLine'), readingLineVariants, defaults.readingLine), readingLinePos: toNumber(getValue('readingLinePos'), bounds.readingLinePos, defaults.readingLinePos), diff --git a/apps/client/src/views/teleprompter/teleprompter.types.ts b/apps/client/src/views/teleprompter/teleprompter.types.ts index f44955a53..08b9cd056 100644 --- a/apps/client/src/views/teleprompter/teleprompter.types.ts +++ b/apps/client/src/views/teleprompter/teleprompter.types.ts @@ -32,12 +32,10 @@ export type TeleprompterOptions = { showGroups: boolean; /** lines per minute */ speed: number; - autoplay: boolean; followLoaded: boolean; fontSize: number; lineHeight: number; textWidth: number; - align: 'left' | 'center'; font?: string; keyColour: string; textColour: string; diff --git a/apps/client/src/views/teleprompter/useTeleprompterScroll.ts b/apps/client/src/views/teleprompter/useTeleprompterScroll.ts index ed53f344f..299cfc7c8 100644 --- a/apps/client/src/views/teleprompter/useTeleprompterScroll.ts +++ b/apps/client/src/views/teleprompter/useTeleprompterScroll.ts @@ -27,7 +27,6 @@ const EXTERNAL_SCROLL_EPSILON = 2; interface UseTeleprompterScrollArgs { initialSpeed: number; - autoplay: boolean; followLoaded: boolean; selectedEventId: string | null; /** percentage from the top of the screen */ @@ -52,7 +51,6 @@ interface UseTeleprompterScrollArgs { */ export function useTeleprompterScroll({ initialSpeed, - autoplay, followLoaded, selectedEventId, readingLinePos, @@ -234,14 +232,6 @@ export function useTeleprompterScroll({ return () => document.removeEventListener('visibilitychange', onVisibilityChange); }, []); - // autoplay once, on mount - useEffect(() => { - if (!autoplay) return; - runningRef.current = true; - setIsRunning(true); - // eslint-disable-next-line react-hooks/exhaustive-deps -- autoplay is a starting condition, not a live one - }, []); - /** * Whether the loaded event currently has a block to scroll to. *