Skip to content
Back to skills

Dpi Scaling

ASecurity

Fix retina/HiDPI blur and layout — devicePixelRatio mismatch between canvas backing store and CSS size

  • 3 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 3, 2026
ai-agentsgo

Works with

  • cli

Security analysis

A100/100

Scanned September 3, 2026

npx -y skills add black141312/ada --skill dpi-scaling --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Dpi Scaling?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Dpi Scaling
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/black141312-dpi-scaling/badge)](https://www.skillsdirectory.com/skills/black141312-dpi-scaling)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: dpi-scaling
description: Fix retina/HiDPI blur and layout — devicePixelRatio mismatch between canvas backing store and CSS size
category: graphics
---

# DPI Scaling

Reach for this when a canvas, chart, or rendered surface looks blurry or soft on retina/HiDPI displays but sharp on standard ones.

1. Confirm the symptom is DPR-related: read `window.devicePixelRatio`. If it's >1 and the canvas looks fuzzy, the backing store is smaller than the displayed pixels and the browser is upscaling.
2. Inspect the two sizes that must differ: CSS size (`canvas.style.width`/`getBoundingClientRect().width`, in CSS px) and backing-store size (`canvas.width`, in device px). The blur appears when `canvas.width === cssWidth` on a DPR-2 screen.
3. Fix the pattern: set `canvas.width = Math.round(cssWidth * dpr)` and `canvas.height = Math.round(cssHeight * dpr)`, keep `canvas.style.width/height` in CSS px, then `ctx.scale(dpr, dpr)` (2D) or `gl.viewport(0,0, canvas.width, canvas.height)` (WebGL) so your draw code stays in CSS units.
4. Re-run on a DPR change: listen for `matchMedia('(resolution: ...)')` or just recompute on `resize`; dragging a window between monitors changes DPR live.
5. Verify text/lines are crisp: a 1px line should hit a single device row — half-pixel offsets cause residual softness, so align strokes to `0.5` in 2D contexts after scaling.
6. Avoid double-scaling: don't both `ctx.scale(dpr)` and multiply coordinates by dpr — pick one (scale the context, draw in CSS px).

## Rules
- Backing store (`canvas.width`) must be CSS size times `devicePixelRatio`; the style width stays in CSS px.
- `ctx.scale(dpr,dpr)` once after sizing lets all draw code stay in logical units — don't also scale coordinates.
- Recompute on resize and on monitor change; `devicePixelRatio` is not constant.
- For WebGL, scale via `gl.viewport` and the drawing-buffer size, not by `ctx.scale`.
- Cap DPR (e.g. min(dpr,2)) for fill-rate-heavy scenes to avoid rendering 9x pixels on a 3x phone.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…