Skip to content

Instantly share code, notes, and snippets.

@svale
Created March 18, 2026 15:21
Show Gist options
  • Select an option

  • Save svale/5ee9021a14eaba520885be1ac4c63299 to your computer and use it in GitHub Desktop.

Select an option

Save svale/5ee9021a14eaba520885be1ac4c63299 to your computer and use it in GitHub Desktop.
Size Multiplier — Visual comparison of text sizing across format aspect ratios
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Size Multiplier — Visual Comparison</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, sans-serif; background: #f5f5f5; color: #1a1a1a; padding: 32px; }
h1 { font-size: 1.3rem; margin-bottom: 4px; }
p.sub { color: #666; font-size: 0.9rem; margin-bottom: 24px; }
.controls { display: flex; align-items: center; gap: 16px; margin-bottom: 24px; background: #fff; padding: 16px 20px; border-radius: 8px; border: 1px solid #ddd; flex-wrap: wrap; }
.controls label { font-weight: 600; font-size: 0.9rem; }
.controls input[type=range] { width: 260px; }
.controls .val { font-size: 1.1rem; font-variant-numeric: tabular-nums; min-width: 180px; }
.controls .val span { color: #3784a0; font-weight: 700; }
.formats { display: flex; gap: 32px; align-items: flex-start; flex-wrap: wrap; }
.format-card { background: #fff; border-radius: 8px; border: 1px solid #ddd; overflow: hidden; }
.format-card h2 { font-size: 0.85rem; padding: 10px 14px; background: #f0f0f0; border-bottom: 1px solid #ddd; }
.format-card h2 span { font-weight: 400; color: #888; }
.format-frame { position: relative; background: #1a1a1a; display: flex; align-items: flex-end; padding: 12px; overflow: hidden; }
.format-frame .text { color: #fff; font-family: system-ui, sans-serif; font-weight: 300; line-height: 1; white-space: nowrap; }
.ruler { display: flex; align-items: flex-start; gap: 32px; margin-top: 32px; flex-wrap: wrap; }
.ruler-card { background: #fff; border-radius: 8px; border: 1px solid #ddd; padding: 20px; }
.ruler-card h2 { font-size: 0.85rem; margin-bottom: 12px; }
.ruler-text { color: #1a1a1a; font-weight: 300; line-height: 1; white-space: nowrap; }
.stats { margin-top: 24px; background: #fff; border-radius: 8px; border: 1px solid #ddd; padding: 16px 20px; font-size: 0.85rem; }
.stats table { width: 100%; border-collapse: collapse; }
.stats th, .stats td { padding: 6px 12px; text-align: right; border-bottom: 1px solid #eee; }
.stats th { text-align: right; font-weight: 600; border-bottom: 2px solid #ccc; }
.stats th:first-child, .stats td:first-child { text-align: left; }
.stats .match { color: #2a7d3f; font-weight: 600; }
</style>
</head>
<body>
<h1>Text Size Comparison — 1:1 vs 16:9</h1>
<p class="sub">How does the sizeMultiplier correction affect perceived text size across formats?</p>
<div class="controls">
<label for="alpha">α</label>
<input type="range" id="alpha" min="0" max="100" value="45" step="1">
<div class="val">α = <span id="alphaVal">0.45</span> → multiplier = <span id="multVal">1.295</span></div>
</div>
<h2 style="font-size: 0.95rem; margin-bottom: 12px;">In context — text inside proportional format frames</h2>
<div class="formats" id="formats"></div>
<h2 style="font-size: 0.95rem; margin-top: 32px; margin-bottom: 12px;">Absolute comparison — same baseline, isolated text</h2>
<div class="ruler" id="ruler"></div>
<div class="stats" id="stats"></div>
<script>
const ratio169 = 16 / 9;
const GRID_ROWS = 32;
const TEXT_ROWS = 3; // simulated text size = 3 grid rows
const BASE_WIDTH = 300; // px width for display
const formats = [
{ name: '1:1', w: 1, h: 1 },
{ name: '16:9', w: 16, h: 9 },
{ name: '9:16', w: 9, h: 16 },
{ name: 'A4 landscape', w: 297, h: 210 },
];
const slider = document.getElementById('alpha');
const alphaVal = document.getElementById('alphaVal');
const multVal = document.getElementById('multVal');
function update() {
const alpha = slider.value / 100;
alphaVal.textContent = alpha.toFixed(2);
const m169 = Math.pow(ratio169, alpha);
multVal.textContent = m169.toFixed(3);
const formatsEl = document.getElementById('formats');
const rulerEl = document.getElementById('ruler');
const statsEl = document.getElementById('stats');
formatsEl.innerHTML = '';
rulerEl.innerHTML = '';
// Reference: 1:1 fontSize in px (for display)
const refGridRowH = BASE_WIDTH / GRID_ROWS; // 1:1 at BASE_WIDTH
const refFontSize = TEXT_ROWS * refGridRowH; // ~28px
const results = formats.map(f => {
const aspectRatio = f.w / f.h;
const displayW = BASE_WIDTH;
const displayH = BASE_WIDTH / aspectRatio;
const gridRowH = displayH / GRID_ROWS;
const sm = Math.pow(aspectRatio, alpha);
const fontSize = TEXT_ROWS * gridRowH * sm;
const pctOfRef = (fontSize / refFontSize * 100);
return { ...f, displayW, displayH, gridRowH, sm, fontSize, pctOfRef };
});
// In-context cards
results.forEach(r => {
const card = document.createElement('div');
card.className = 'format-card';
card.innerHTML = `
<h2>${r.name} <span>— ×${r.sm.toFixed(3)}</span></h2>
<div class="format-frame" style="width:${r.displayW}px; height:${r.displayH}px;">
<div class="text" style="font-size:${r.fontSize}px;">Nasjonalmuseet</div>
</div>
`;
formatsEl.appendChild(card);
});
// Absolute ruler cards
results.forEach(r => {
const card = document.createElement('div');
card.className = 'ruler-card';
card.innerHTML = `
<h2>${r.name} — ${r.fontSize.toFixed(1)}px <span style="color:#888">(${r.pctOfRef.toFixed(0)}% of 1:1)</span></h2>
<div class="ruler-text" style="font-size:${r.fontSize}px;">Nasjonalmuseet</div>
`;
rulerEl.appendChild(card);
});
// Stats table
let rows = results.map(r => `
<tr>
<td>${r.name}</td>
<td>${(r.w/r.h).toFixed(3)}</td>
<td>${r.gridRowH.toFixed(2)}px</td>
<td>×${r.sm.toFixed(3)}</td>
<td>${r.fontSize.toFixed(1)}px</td>
<td class="${Math.abs(r.pctOfRef - 100) < 1 ? 'match' : ''}">${r.pctOfRef.toFixed(1)}%</td>
</tr>
`).join('');
statsEl.innerHTML = `
<table>
<thead><tr><th>Format</th><th>Ratio</th><th>gridRowH</th><th>Multiplier</th><th>fontSize</th><th>% of 1:1</th></tr></thead>
<tbody>${rows}</tbody>
</table>
<p style="margin-top: 12px; color: #888;">At α=1.0, all formats produce identical absolute font size (100% of 1:1). Drag the slider to find the perceptual sweet spot.</p>
`;
}
slider.addEventListener('input', update);
update();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment