commit 64f618ff748c68713b5a9f75e3d2beac725ee594
parent c43fb140f19986879a7ceff383e8d35ea556921c
Author: Hunter
Date:   Mon, 27 Jul 2026 23:26:26 -0400

(attempt to) render onscreen elements at print size

Diffstat:
Mscript.js | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mstyle.css | 23++++++++++-------------
2 files changed, 65 insertions(+), 13 deletions(-)

diff --git a/script.js b/script.js @@ -50,6 +50,8 @@ function isSafari() { const isUsingSafari = isSafari(); +const isUsingWindows = navigator.userAgent.includes('Windows'); + // Parse URL parameters for custom cell size function parseCellSizeFromURL() { const urlParams = new URLSearchParams(window.location.search); @@ -82,6 +84,58 @@ function parseCellSizeFromURL() { // Initialize cell size from URL CELL_SIZE_MM = parseCellSizeFromURL(); +const PANEL_PPI = { + 1920: 141, // 15.6" 1080p laptop + 2560: 109, // 27" 1440p + 2736: 267, // 12.3" 3:2 tablet + 2880: 267, // 13" 3:2 tablet + 3840: 163 // 27" 4K +}; + +function estimateWindowsPPI() { + const pixelRatio = window.devicePixelRatio; + if (pixelRatio === 1) return null; + + const nativeWidth = screen.width * pixelRatio; + if (nativeWidth >= 3800 && pixelRatio >= 2) return null; + + const panel = Object.keys(PANEL_PPI).find(width => Math.abs(width - nativeWidth) <= width * 0.02); + + return panel ? PANEL_PPI[panel] / pixelRatio : null; +} + +function estimateScreenPPI() { + const logicalWidth = screen.width; + const pixelRatio = window.devicePixelRatio; + + if (isUsingWindows) { + const windowsPPI = estimateWindowsPPI(); + if (windowsPPI) return windowsPPI; + } + + if (logicalWidth >= 3840) return 163; // 27" 4K, OS scaling off + if (logicalWidth >= 2048) return 109; // 27" 5K retina or 1440p + if (logicalWidth >= 1800) return 92.6; // 23.8" 1080p and friends + + return pixelRatio > 1 ? 127.7 : 92.6; // retina laptop (2560px / 227ppi), else standard density +} + +// Life-size page width; CSS clamps this to the viewport so it never overflows horizontally +function applyPageWidth() { + const pageWidth = (LETTER_WIDTH_MM / 25.4) * estimateScreenPPI(); + document.documentElement.style.setProperty('--page-width', `${pageWidth}px`); + updateGridLineWidth(); +} + +const baselinePixelRatio = window.devicePixelRatio; + +function updateGridLineWidth() { + const zoom = window.devicePixelRatio / baselinePixelRatio; + document.documentElement.style.setProperty('--line-width', `${Math.min(1, 1 / zoom)}px`); +} + +applyPageWidth(); + // Calculate grid dimensions based on cell size const gridDimensions = calculateGridDimensions(CELL_SIZE_MM); GRID_COLS = gridDimensions.cols; @@ -1109,6 +1163,7 @@ document.addEventListener('wheel', (e) => { // Update all image positions when window resizes (for responsive scaling) window.addEventListener('resize', () => { + applyPageWidth(); // display or zoom may have changed images.forEach(img => { updateImagePosition(img); }); diff --git a/style.css b/style.css @@ -123,15 +123,13 @@ body { display: flex; justify-content: center; align-items: flex-start; + align-items: safe center; min-height: 100vh; padding: 20px; } .page { - /* Scale down on narrow screens, but never larger than 8.5in */ - max-width: min(8.5in, calc(100vw - 40px)); - width: 100%; - /* Maintain 8.5:11 aspect ratio (11/8.5 = 1.294117647) */ + width: min(100%, var(--page-width, 8.5in)); aspect-ratio: 8.5 / 11; background: var(--page); position: relative; @@ -159,8 +157,8 @@ body { width: 100%; height: 100%; box-sizing: border-box; - border-top: 1px dashed var(--grid-line); - border-left: 1px dashed var(--grid-line); + border-top: var(--line-width, 1px) dashed var(--grid-line); + border-left: var(--line-width, 1px) dashed var(--grid-line); margin: 0; padding: 0; display: block; @@ -168,14 +166,14 @@ body { /* Add right border to rightmost column */ .grid-cell.right-edge { - border-right: 1px dashed var(--grid-line); - width: calc(100% + 1px); + border-right: var(--line-width, 1px) dashed var(--grid-line); + width: calc(100% + var(--line-width, 1px)); } /* Add bottom border to bottom row */ .grid-cell.bottom-edge { - border-bottom: 1px dashed var(--grid-line); - height: calc(100% + 1px); + border-bottom: var(--line-width, 1px) dashed var(--grid-line); + height: calc(100% + var(--line-width, 1px)); } /* Solid grid lines for cell sizes <= 3.56mm (screen preview only) */ @@ -202,7 +200,6 @@ body { } .page { - max-width: 100vw; box-shadow: none; } @@ -216,13 +213,13 @@ body { .grid-cell.right-edge { border-right-style: solid; border-right-color: var(--grid-line-light); - width: calc(100% + 1px); + width: calc(100% + var(--line-width, 1px)); } .grid-cell.bottom-edge { border-bottom-style: solid; border-bottom-color: var(--grid-line-light); - height: calc(100% + 1px); + height: calc(100% + var(--line-width, 1px)); } }