Strokes

Every shape node accepts a stroke prop. Strokes paint a border along the shape's path using the same fill system as shape fills.

Basic usage

// Solid stroke
<Rect stroke={{ weight: 3, fill: 'white' }} />

// Gradient stroke
<Rect stroke={{
  weight: 4,
  fill: { type: 'linear-gradient', colors: ['#4f80ff', '#e84393'], stops: [0, 1] },
}} />

Props

PropTypeDefaultDescription
weightnumber1Stroke width in pixels
fillFillPropStroke color or gradient
dashnumber | number[]Dash pattern (e.g. [10, 5] for 10px on, 5px off)
dashOffsetnumber0Offset into the dash pattern
alignnumber | 'inside' | 'center' | 'outside''center'Where the stroke sits relative to the path edge
cap'butt' | 'round' | 'square''butt'Shape of open-path ends and dash ends
join'miter' | 'round' | 'bevel''miter'Shape of corners where segments meet
miterLimitnumber4Max miter-length / width ratio before a 'miter' join bevels

Caps and joins

cap controls how the ends of an open stroke (and the end of each dash) are shaped; join controls how corners are shaped where two segments meet:

// Cap — only visible on open paths and dashes
<Line points={[[0, 0], [200, 0]]} stroke={{ weight: 16, fill: 'white', cap: 'round' }} />
<Line points={[[0, 0], [200, 0]]} stroke={{ weight: 16, fill: 'white', cap: 'square' }} />

// Join — visible at every corner
<Rect stroke={{ weight: 16, fill: 'royalblue', join: 'round' }} />
<Rect stroke={{ weight: 16, fill: 'royalblue', join: 'bevel' }} />

A sharp 'miter' join on a tight corner can spike far past the path; miterLimit caps that. Once the miter would be longer than miterLimit × weight, the join falls back to a bevel.


Alignment

align controls whether the stroke grows inward, outward, or straddles the path edge:

<Rect stroke={{ weight: 8, fill: 'royalblue', align: 'inside' }} />
<Rect stroke={{ weight: 8, fill: 'royalblue', align: 'center' }} />
<Rect stroke={{ weight: 8, fill: 'royalblue', align: 'outside' }} />

// Numeric — any value from -1 (fully inside) to 1 (fully outside)
<Rect stroke={{ weight: 8, fill: 'royalblue', align: 0.5 }} />

Dashed strokes

// Equal dashes and gaps
<Rect stroke={{ weight: 2, fill: '#aaa', dash: 10 }} />

// Custom pattern: 12px dash, 4px gap, 4px dash, 4px gap
<Rect stroke={{ weight: 2, fill: 'white', dash: [12, 4, 4, 4] }} />

Animated dash offset

Animating dashOffset is a clean way to produce a draw-on or marching-ants effect:

import { createScene, Rect, createRef } from '@motion-script/core';

export default createScene(function* (stage) {
  const box = createRef<Rect>();

  stage.add(
    <Rect ref={box} width={300} height={200} cornerRadius={12}
      stroke={{ weight: 3, fill: 'white', dash: [16, 8], dashOffset: 0 }} />
  );

  // March the ants
  yield* box().to({ stroke: { dashOffset: 100 } }, 2);
});

Multiple strokes

Pass an array to layer strokes. They paint in order, bottom to top:

<Rect stroke={[
  { weight: 8, fill: 'black', align: 'outside' },
  { weight: 4, fill: 'white', align: 'outside' },
]} />

Animating strokes

All stroke props are animatable:

yield* box().to({ stroke: { weight: 8, fill: '#e84393' } }, 0.6);