mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-13 19:33:46 +00:00
f806244586
Adds a teleprompter at /teleprompter which builds its script from the rundown rather than from an uploaded file, so the read follows the show. The script comes from a text custom field chosen per view, and the whole rundown renders as one continuous document with a heading per segment. That is how broadcast prompters work: the operator scrolls to the right section as the show moves, so a hard cut on every event change would take the tail of the line the talent is still reading. Following the loaded event is a soft jump which releases when the user scrolls by hand, the same interaction the operator view already uses. Controls are local, and match the convention shared by prompter software: space to run, arrows for speed and nudge, home to rewind, F to flip. That convention doubles as the hardware protocol, since foot pedals and hand controllers are USB HID devices emitting these keystrokes, so they work with no setup. Space is claimed back from the navigation menu for the lifetime of the view via a small store, since the router renders the menu generically for presets and a prop would not reach it. Scrolling uses native scrollTop on an overflow container, with the animation frame loop as its only writer. Position is kept as a float in a ref: at readable speeds the per frame movement is well under a pixel, so rounding every frame would stall the scroll, and holding it in state would re-render the document sixty times a second. Scroll anchoring and smooth scroll behaviour are both disabled because each would be a second writer. Notable details: - flip applies to the view root, so a beam splitter inverts the scroll direction along with the text - content padding is derived from the viewport height, not a percentage, which resolves against width and would strand the first line - image custom fields are refused even when typed into the URL - script text is rendered as a text node, never as markup Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Cb8RVPNQ2ETPJxdy4b8CHf