Sizing and units

Size and place layers in CSS units (px, %, vw, rem, and canvas units) that stay correct as the canvas and window resize.

A shape takes the same lengths you'd write in CSS:

<Shader className="w-full h-96">
  <RoundedRect width="50%" height="12rem" rounding="24px" />
</Shader>

The rectangle is half the canvas wide and 192px tall, and it stays that way as the canvas resizes.

Writing a length

A length is a number with a unit. Write it as a string, the way you would in CSS:

<Circle radius="10vmin" :center="{ x: '0', y: '-24px' }" />

You can also write it as an object with a value and a unit:

<Circle :radius="{ value: 10, unit: 'vmin' }" />

Both forms work on props and in bounding boxes. A string needs a unit, except '0'.

Choosing a unit

Each unit measures against something different:

UnitMeasures againstUse it for
pxCSS pixelsFixed sizes: badges, logos, UI chrome
%The canvas, on the prop's own axisLayouts that scale with the canvas
cw, ch1% of the canvas width or heightSizing one axis from the other
cmin, cmax1% of the canvas's shorter or longer sideShapes that fit any aspect ratio
vw, vh1% of the browser window's width or heightMatching DOM elements sized in vw or vh
vmin, vmax1% of the window's shorter or longer sideMatching DOM elements sized in vmin or vmax
remThe page's root font sizeMatching your typography

Canvas units follow the <Shader> element. Viewport units follow the browser window, so the two only differ when the canvas isn't full-screen. In a canvas that fills a sidebar, 50cw is half the sidebar and 50vw is half the window.

vw and vh match CSS exactly, including on mobile, where the address bar changes the window's height but not the size of 100vh. Without a browser window, as in server rendering, viewport units fall back to the canvas size and rem falls back to 16px.

Sizing a shape

A length on a size prop sets the shape's full size on screen, the way CSS width does:

<Circle radius="120px" />
<Star radius="20cmin" />

The circle is 120px across, not 120px from its center. The star fills a square that's 20% of the canvas's shorter side.

Props that take lengths include:

  • Shape position and size: center and the size props of every shape, such as radius, width, and height.
  • Shape details: rounding on rounded rectangles and softness on circles.
  • Text: fontSize and width.
  • Layout and patterns: Repeater gaps, radius, and spacing, plus Checkerboard cells, where a length sets the size of one cell.

Each prop's row in the component reference says when it accepts CSS units.

Using %

% measures the canvas on the prop's own axis. width and x use the canvas width, and height and y use its height:

<RoundedRect width="80%" height="50%" />

Some props have no axis: a circle's radius, rounding, softness, and Text's fontSize. They don't accept %, the same way CSS rejects % on border-width. Shaders ignores the value, uses the prop's default, and logs one console warning. Use cmin, px, or rem for these instead.

Positioning with lengths

A length in center is an offset from the edge named by the shape's origin. Shapes default to origin: 'center', so offsets start from the middle of the canvas and '0' is centered. Positive y moves down, as in CSS. This circle sits 24px above the middle:

<Shader className="w-full h-96">
  <Circle radius="80px" center={{ x: '0', y: '-24px' }} />
</Shader>

To pin a shape to a corner, set origin. The offset then measures from that edge of the canvas to the same edge of the shape, like CSS right and top. This circle sits 24px in from the top-right corner at any canvas size:

<Circle origin="top-right" radius="64px" :center="{ x: '24px', y: '24px' }" />

Sizing a bounding box

boundingBox takes the same units. Its x and y place the box's edge, like left and top on a positioned element, and a bare number means pixels:

<Shader className="w-full h-96">
  <LinearGradient />
  <Blur boundingBox={{ x: 24, y: '1rem', width: '50vw', height: '40%', origin: 'bottom-right' }} />
</Shader>

The blurred region sits 24px from the right edge and 16px from the bottom. See Transforms for origins, rotation, and how each kind of layer fills its box.

Reading bare numbers on shape props

On shape props, a bare number keeps its original meaning: a fraction of the canvas. radius: 0.5 isn't 0.5px. Shape props worked this way before units existed, and changing it would move every shape already written with numbers. Add a unit when you want CSS behavior: radius="50cmin".

In center, a bare 0 is the left or top edge of the canvas, while '0' with a centered origin is the middle.

Resizing and animating lengths

Shaders recalculates every length when the canvas resizes, and recalculates viewport and rem lengths when the window resizes. A recalculated length updates a uniform, a value the GPU reads every frame, so nothing recompiles.

Dynamic prop ranges take lengths in the object form. This circle grows from 80px to 240px across:

<Circle :radius="{
  type: 'auto-animate',
  mode: 'ping-pong',
  outputMin: { value: 80, unit: 'px' },
  outputMax: { value: 240, unit: 'px' }
}" />

A range is converted to the canvas once, when the prop is set. Resizing the canvas or window doesn't update it, so a % range keeps the size it had at that moment.

The design editor offers % and px only. The other units work in code.

Next steps