SPL Meter: measure the room, not just watch it #10

Merged
michael merged 7 commits from claude/spl-meter-module into main 2026-09-17 16:18:17 -04:00
3 changed files with 42 additions and 7 deletions
Showing only changes of commit 543795f9fd - Show all commits
+35 -1
View File
@@ -196,6 +196,38 @@ function readoutView(root, moduleApi) {
const unit = root.querySelector('.spl-unit'); const unit = root.querySelector('.spl-unit');
const sub = root.querySelector('.spl-sub'); const sub = root.querySelector('.spl-sub');
const box = root.querySelector('.spl-readout'); const box = root.querySelector('.spl-readout');
const value = root.querySelector('.spl-value');
let fitKey = '';
/**
* Grow the number until it fills the tile, measuring the text we actually
* have rather than assuming a digit count.
*
* The CSS can only guess at width — it has to pick a cqw coefficient for
* some number of characters, and then "-100.5" overflows the tile that
* "-45.9" merely filled. Measuring costs one layout read, and only when
* the tile size or the length of the reading changes.
*/
function fit() {
const w = root.clientWidth, h = root.clientHeight;
const key = `${w}x${h}:${num.textContent.length}:${unit.textContent}`;
if (key === fitKey || w < 2 || h < 2) return;
fitKey = key;
const TRIAL = 100;
num.style.fontSize = `${TRIAL}px`;
unit.style.fontSize = `${TRIAL * 0.26}px`;
const natural = value.scrollWidth || 1;
// Leave the caption its room when it is showing, and a little air either
// way so descenders and the tile's padding never clip.
const subH = sub.offsetParent ? sub.getBoundingClientRect().height + 6 : 0;
const byHeight = (h - subH) * 0.92;
const byWidth = ((w - 8) * TRIAL) / natural;
const size = Math.max(12, Math.min(byHeight, byWidth));
num.style.fontSize = `${size}px`;
unit.style.fontSize = `${size * 0.26}px`;
}
return { return {
render(payload) { render(payload) {
@@ -205,6 +237,7 @@ function readoutView(root, moduleApi) {
num.textContent = '––.–'; num.textContent = '––.–';
sub.textContent = payload && payload.error ? payload.error : ''; sub.textContent = payload && payload.error ? payload.error : '';
box.dataset.level = 'idle'; box.dataset.level = 'idle';
fit();
return; return;
} }
const value = readValue(ch, s); const value = readValue(ch, s);
@@ -225,8 +258,9 @@ function readoutView(root, moduleApi) {
if (ch.clip) parts.push('CLIP'); if (ch.clip) parts.push('CLIP');
if (!payload.calibrated) parts.push('uncalibrated'); if (!payload.calibrated) parts.push('uncalibrated');
sub.textContent = parts.join(' · '); sub.textContent = parts.join(' · ');
fit();
}, },
resize() {}, resize() { fitKey = ''; fit(); },
destroy() { root.innerHTML = ''; }, destroy() { root.innerHTML = ''; },
}; };
} }
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"id": "spl-meter", "id": "spl-meter",
"name": "SPL Meter", "name": "SPL Meter",
"version": "0.2.0", "version": "0.2.1",
"proddash": ">=1.5.0", "proddash": ">=1.5.0",
"description": "Calibrated sound level, Leq and RTA from an audio input on this machine", "description": "Calibrated sound level, Leq and RTA from an audio input on this machine",
"permissions": [ "permissions": [
+6 -5
View File
@@ -30,18 +30,19 @@
color: var(--text); color: var(--text);
} }
/* Sized off the tile, so one cell and six cells both read well. Height has /* A first-paint size only. client.js measures the text and sets the real
to be in the min() as well as width: a 2x1 tile is wide and short, and one inline, because CSS has to assume a digit count and gets it wrong the
sizing on width alone pushes the digits straight out through the top. */ moment the reading needs a sixth character: the coefficient that fills a
tile for "-45.9" pushes "-100.5" straight out through the side. */
[data-module="spl-meter"] .spl-num { [data-module="spl-meter"] .spl-num {
font-size: clamp(1.25rem, min(20cqw, 42cqh), 6rem); font-size: clamp(1.25rem, min(26cqw, 60cqh), 100rem);
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;
font-weight: 600; font-weight: 600;
letter-spacing: -0.02em; letter-spacing: -0.02em;
} }
[data-module="spl-meter"] .spl-unit { [data-module="spl-meter"] .spl-unit {
font-size: clamp(0.65rem, min(6cqw, 13cqh), 1.5rem); font-size: clamp(0.65rem, min(7cqw, 15cqh), 26rem);
color: var(--muted); color: var(--muted);
} }