Skip to content

Wrong size or blurry

The animation renders, but it is the wrong size, stretched, cropped, blurry, or sharp only after a resize.

Use this when

  • The animation looks pixelated on Retina / 4K displays.
  • The animation does not fill the slot you put it in.
  • It gets sharper or larger only when you resize the browser window.
  • It jumps in size on first load.

What you need

The two golden rules

Rule 1 — Size with CSS, not with width/height attributes

html
<!-- WRONG -->
<canvas id="rive-canvas" width="500" height="500"></canvas>

<!-- RIGHT -->
<div style="width:100%; aspect-ratio: 16/9;">
  <canvas
    id="rive-canvas"
    style="width:100%; height:100%; display:block; touch-action:none;"
  ></canvas>
</div>

The width / height HTML attributes set the canvas's internal backing-store size and reset the WebGL context. Always size the canvas with CSS on the wrapper.

Rule 2 — Call resizeDrawingSurfaceToCanvas() on load and on resize

js
const r = new Rive({
  src: "/animations/hero.riv",
  canvas,
  autoplay: true,
  stateMachines: "State Machine 1",
  onLoad: () => r.resizeDrawingSurfaceToCanvas(),
});

window.addEventListener("resize", () => r.resizeDrawingSurfaceToCanvas());

This is what tells Rive to match the canvas backing store to the actual CSS size and the device pixel ratio (DPR). Without it, Retina screens render the animation at half-resolution — that is what "blurry" usually means.

If you use the React useRive hook, this is handled for you. If you use Framer, the prebuilt component does it. If you wrote your own code, you need both lines.

Fit and alignment

Match what handoff.md specifies. Common values:

js
import { Layout, Fit, Alignment } from "@rive-app/webgl2";

new Rive({
  // ...
  layout: new Layout({ fit: Fit.Contain, alignment: Alignment.Center }),
});
FitBehaviourWhen to use
ContainWhole animation fits, may leave empty space around itDefault — preserves design
CoverFills the canvas, crops the animationHero banners
FillStretches to fill, ignores aspect ratioAlmost never — distorts the design
NoneRenders at the artboard's native sizePixel-exact UI elements
LayoutResponsive layout engine (artboard adapts)Only when handoff.md says so

Aspect ratio mismatch

If your container is 16:9 but the artboard is 1:1, Contain leaves bars on the sides. Either match the container aspect to the artboard, or use Cover if cropping is acceptable.

Animation looks fine until I resize

Most often: resizeDrawingSurfaceToCanvas() is only called in onLoad. Add the window resize listener:

js
window.addEventListener("resize", () => r.resizeDrawingSurfaceToCanvas());

If your container resizes for reasons other than window resize (responsive layout shifts, parent collapse/expand), call it then too:

js
const ro = new ResizeObserver(() => r.resizeDrawingSurfaceToCanvas());
ro.observe(canvas.parentElement);

Do not let ResizeObserver write to canvas.width / canvas.height

Some examples online use a ResizeObserver callback that sets canvas.width = entry.contentRect.width and canvas.height = .... That breaks the renderer. Only call resizeDrawingSurfaceToCanvas() — Rive sets the backing store internally.

Mobile-specific

  • Set touch-action: none on the canvas to stop the browser from interpreting drags as scroll/zoom.
  • Set pointer-events: auto to ensure overlays do not block input.
  • Test on a real device — DPR on phones (often 2 or 3) shows blur issues that desktop hides.

Common mistakes

  • <canvas width="..." height="..."> in HTML. Remove those attributes.
  • Manually setting canvas.width = window.innerWidth in JS. Don't. Use CSS + resizeDrawingSurfaceToCanvas().
  • No parent height. A canvas with height: 100% inside a parent with no height is 0px tall. Give the parent an aspect-ratio or fixed height.
  • Forgetting the window resize listener. Renders fine at load, blurs after resize.
  • Using Fit.Fill when Contain was intended — distorts the design.

If stuck, send this to Lupian

  • A screenshot at the broken size and a screenshot of the intended look.
  • Your CSS for the canvas wrapper.
  • The Fit and aspect ratio you used.
  • See Ask Lupian for help.

Developer support for Lupian-delivered Rive animations