Created
March 18, 2026 15:21
-
-
Save svale/5ee9021a14eaba520885be1ac4c63299 to your computer and use it in GitHub Desktop.
Size Multiplier — Visual comparison of text sizing across format aspect ratios
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!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