diff options
| author | user <user@clank> | 2026-08-14 23:57:55 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-08-14 23:57:55 +0200 |
| commit | d66a22cd8e152aed3efc4b340daa345d26ba4855 (patch) | |
| tree | b4f27f88cec966598125ccde54aa48ff00b797ef | |
| parent | contrib: a shadertoy for shader expressions (diff) | |
| download | slosh-d66a22cd8e152aed3efc4b340daa345d26ba4855.tar.gz slosh-d66a22cd8e152aed3efc4b340daa345d26ba4855.tar.xz slosh-d66a22cd8e152aed3efc4b340daa345d26ba4855.zip | |
contrib: draw the shadertoy preview at the size it means
The canvas was 576x432 with `max-width: 100%`, so a wide pane stretched a
576-pixel preview across it and `image-rendering: pixelated` made sure you
could see every one of those pixels doing it. A preview of a terminal that
does not look like a terminal is not much of a preview.
Two sizes now, deliberately: the backing store is device pixels (DPR, capped
at 3) so glyphs stay sharp on a HiDPI screen, and the CSS size is pinned to
the real 576x432 so nothing ever scales it up. A viewport with room to spare
gets space around the preview instead of a blur; one that is genuinely too
small still shrinks it, smoothly, which is the direction where scaling is
fine.
Checked by rendering a frame against a stub canvas under node: the draw path
covers exactly the CSS box while the backing store is twice that at DPR 2.
| -rw-r--r-- | contrib/shadertoy.html | 26 |
1 files changed, 21 insertions, 5 deletions
diff --git a/contrib/shadertoy.html b/contrib/shadertoy.html index 05bf407..cea9b2f 100644 --- a/contrib/shadertoy.html +++ b/contrib/shadertoy.html @@ -61,8 +61,11 @@ .deps b { color: var(--accent); font-weight: 500; } .deps .cached { color: #7fd67f; } .deps .live { color: #f0c674; } - canvas { border: 1px solid var(--line); border-radius: 5px; image-rendering: pixelated; - max-width: 100%; } + /* Never scaled up: the preview is drawn at the size it means, and a + viewport with room to spare gets space around it rather than a blur. + Shrinks (smoothly) when the window is genuinely too small for it. */ + canvas { border: 1px solid var(--line); border-radius: 5px; + max-width: 100%; height: auto; align-self: start; } pre#config { background: var(--panel); border: 1px solid var(--line); border-radius: 5px; padding: 10px; margin: 0; overflow-x: auto; color: var(--fg); font-size: 12px; @@ -395,8 +398,21 @@ function renderPresets() { const canvas = document.getElementById("screen"); const ctx = canvas.getContext("2d"); -canvas.width = COLS * CW; -canvas.height = ROWS * CH; + +/* Two sizes, deliberately. The backing store is device pixels, so text stays + * sharp on a HiDPI screen; the CSS size is the one the layout sees, and it is + * fixed at the real thing so nothing ever stretches a 576-pixel preview + * across a 1400-pixel pane and calls it a terminal. */ +function sizeCanvas() { + const dpr = Math.max(1, Math.min(3, window.devicePixelRatio || 1)); + canvas.width = COLS * CW * dpr; + canvas.height = ROWS * CH * dpr; + canvas.style.width = `${COLS * CW}px`; + canvas.style.height = `${ROWS * CH}px`; + ctx.setTransform(dpr, 0, 0, dpr, 0, 0); +} +sizeCanvas(); +window.addEventListener("resize", sizeCanvas); canvas.addEventListener("mousemove", (e) => { const r = canvas.getBoundingClientRect(); @@ -443,7 +459,7 @@ function refresh() { function draw(now) { ctx.fillStyle = rgb2css(DEFAULT_BG); - ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.fillRect(0, 0, COLS * CW, ROWS * CH); ctx.font = `${CH - 5}px ui-monospace, monospace`; ctx.textBaseline = "top"; |
