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…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.