From 5fe39539fc09dccc0b87f0c6e8b8f4ecbc7505da Mon Sep 17 00:00:00 2001 From: Waters Church Date: Thu, 10 Sep 2026 15:23:07 -0400 Subject: [PATCH] Timers: admin "Timer font" option with a monospace choice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A new Display-group select (Default / Monospace) sets the font for the timer and LTC digits. Monospace keeps the numbers from shifting sideways as they change — easier to read on a fast-moving countdown or timecode. Flows through server state → client applies a `tm-mono` class and re-fits the digit sizing; both timer and LTC values (.tm-time) honor it. Co-Authored-By: Claude Opus 4.8 --- README.md | 5 +++-- modules/propresenter-timers/client.js | 8 ++++++++ modules/propresenter-timers/module.json | 10 ++++++++++ modules/propresenter-timers/server.js | 7 +++++-- modules/propresenter-timers/style.css | 7 +++++++ 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 37d4bd2..993caa1 100644 --- a/README.md +++ b/README.md @@ -176,9 +176,10 @@ below. Nothing is installed without someone clicking. discovered timer (and the LTC card) as its own tile, or add "All timers" and pick a selection via the tile's "Timers ▾" menu; overruns are unmistakably red. Read-only — no start/stop controls. Admin config is in - two groups: **ProPresenter** (endpoint host : port, API password) and + three groups: **ProPresenter** (endpoint host : port, API password), **LTC Timecode** (the listener switch, and — when it's on — the audio - device and channel). + device and channel), and **Display** (Timer font — Default or Monospace, + which keeps the digits from shifting as the numbers change). ProPresenter exposes no timecode over any API, so LTC is decoded from the audio signal, behind the admin **LTC listener** switch (off ⇒ no LTC tile diff --git a/modules/propresenter-timers/client.js b/modules/propresenter-timers/client.js index c88bad5..94dd235 100644 --- a/modules/propresenter-timers/client.js +++ b/modules/propresenter-timers/client.js @@ -393,6 +393,14 @@ export default function create({ root, moduleApi }) { rebuildMenu(); updateLtcAnchor(); + // Admin-chosen digit font. A font swap changes glyph metrics, so re-fit + // the digit sizing when it actually changes. + const mono = state?.timerFont === 'monospace'; + if (mono !== wrap.classList.contains('tm-mono')) { + wrap.classList.toggle('tm-mono', mono); + fit(); + } + let hint = ''; if (state && !state.enabled && !state.ltc?.supported) { hint = 'No ProPresenter connection — set the host and port in Admin.'; diff --git a/modules/propresenter-timers/module.json b/modules/propresenter-timers/module.json index f8db865..4ca1bd3 100644 --- a/modules/propresenter-timers/module.json +++ b/modules/propresenter-timers/module.json @@ -42,6 +42,16 @@ "group": "LTC Timecode", "showWhen": "ltcEnabled", "default": 1 + }, + "timerFont": { + "type": "select", + "label": "Timer font", + "group": "Display", + "default": "default", + "options": [ + { "value": "default", "label": "Default (system)" }, + { "value": "monospace", "label": "Monospace — steadier changing digits" } + ] } } } diff --git a/modules/propresenter-timers/server.js b/modules/propresenter-timers/server.js index a2c0fc8..41b2926 100644 --- a/modules/propresenter-timers/server.js +++ b/modules/propresenter-timers/server.js @@ -57,10 +57,11 @@ const { createLtcListener } = require('./ltc-listener'); /** Set by init(), read by the routes — both are rebuilt together on remount. */ let current = null; -function clearedState(enabled, ltcEnabled = false) { +function clearedState(enabled, ltcEnabled = false, timerFont = 'default') { return { enabled, ltcEnabled, + timerFont, reachable: false, lastError: '', timers: [], @@ -86,8 +87,9 @@ module.exports = { const ltcEnabled = Boolean(config.ltcEnabled); const ltcDevice = String(config.ltcDevice || ''); const ltcChannel = Math.max(1, Math.trunc(Number(config.ltcChannel)) || 1); + const timerFont = config.timerFont === 'monospace' ? 'monospace' : 'default'; - let latest = clearedState(enabled, ltcEnabled); + let latest = clearedState(enabled, ltcEnabled, timerFont); let lastFrame = ''; let stopped = false; let pollTimer = null; @@ -207,6 +209,7 @@ module.exports = { latest = { enabled, ltcEnabled, + timerFont, reachable: latest.reachable, lastError: latest.lastError, timers: latest.timers, diff --git a/modules/propresenter-timers/style.css b/modules/propresenter-timers/style.css index 6ea1828..129771e 100644 --- a/modules/propresenter-timers/style.css +++ b/modules/propresenter-timers/style.css @@ -113,6 +113,13 @@ white-space: nowrap; } +/* Admin "Timer font: Monospace" — steadier digits as the numbers change. + Applies to timer and LTC values alike (both are .tm-time). */ +[data-module="propresenter-timers"] .tm-mono .tm-time { + font-family: ui-monospace, "SF Mono", "Menlo", "Cascadia Mono", "Consolas", monospace; + letter-spacing: 0; +} + [data-module="propresenter-timers"] .tm-state { flex: none; max-width: 100%;