Line Boil

A hand-drawn outline draws itself, boils on threes like a cel animation, and fills with color while it keeps boiling

Installation
$ pnpm dlx shadcn@latest add @remocn/line-boil

Usage

LineBoil is a full-frame scene. It draws a closed outline with a pen that tapers in and out and varies its pressure along the stroke, then fills the shape with color. The line never sits still. Like a cel animation shot "on threes", the whole drawing is retraced every few frames with a slightly different wobble, cycling through a small set of drawings.

tsx
import { LineBoil } from "@/components/remocn/line-boil";
 
export const Star = () => <LineBoil />;

Pass path to draw your own shape. It takes SVG path data in any coordinate space. The outline is sampled at 160 points along its length, scaled so its longer side is size of the frame's short side, and centered. Use one closed outline: separate subpaths and holes are joined into one continuous stroke.

tsx
import { LineBoil } from "@/components/remocn/line-boil";
 
const heart =
  "M 50 88 C 20 66 4 48 4 30 C 4 14 16 4 30 4 C 40 4 47 10 50 18 C 53 10 60 4 70 4 C 84 4 96 14 96 30 C 96 48 80 66 50 88 Z";
 
export const Heart = () => (
  <LineBoil
    path={heart}
    line="#1C1A17"
    fill="#FF8FB1"
    background="#FFF6E9"
    boilEvery={2}
  />
);

The fill boils with its own seed and a stronger wobble than the line, so the color slips a little past the outline the way a cel fill does.

Timing

At 30 fps and speed={1}:

FramesMotion
0–22The pen draws the outline along the path on an ease-in-out, with tapered ends
28–40The fill grows from the shape's center with a small overshoot
40+The finished drawing keeps boiling

lineBoilLength is 40, the frame the fill lands. The boil runs from frame 0 and never stops: a new drawing every boilEvery frames, cycling through drawings variations. speed scales the draw, the fill and the boil rate together.

Props11

PropTypeDefault
path
string5-point star

Closed outline as SVG path data in any coordinate space, fitted to the frame

boilEvery
number3

Frames each drawing holds before the next one

drawings
number3

Number of distinct drawings the boil cycles through

amplitude
number1

Wobble strength; 1 is a gentle hand-drawn boil, 0 is a steady line

strokeWidth
number9

Base line weight in px at 720p; pen pressure varies it along the stroke

size
number0.66

Size of the shape's longer side as a fraction of the frame's short side

line
string"#111111"

Outline color. Overrides colors.line when set

fill
string"#E5322D"

Shape fill. Overrides colors.fill when set

background
string"#FFFFFF"

Background color. Overrides colors.background when set

colors
{ line?: string; fill?: string; background?: string }{ line: "#111111", fill: "#E5322D", background: "#FFFFFF" }

The same colors as one object; the flat props above take precedence, missing keys keep their defaults

speed
number1

Playback multiplier

  • pathstring

    Closed outline as SVG path data in any coordinate space, fitted to the frame

    Default5-point star

  • boilEverynumber

    Frames each drawing holds before the next one

    Default3

  • drawingsnumber

    Number of distinct drawings the boil cycles through

    Default3

  • amplitudenumber

    Wobble strength; 1 is a gentle hand-drawn boil, 0 is a steady line

    Default1

  • strokeWidthnumber

    Base line weight in px at 720p; pen pressure varies it along the stroke

    Default9

  • sizenumber

    Size of the shape's longer side as a fraction of the frame's short side

    Default0.66

  • linestring

    Outline color. Overrides colors.line when set

    Default"#111111"

  • fillstring

    Shape fill. Overrides colors.fill when set

    Default"#E5322D"

  • backgroundstring

    Background color. Overrides colors.background when set

    Default"#FFFFFF"

  • colors{ line?: string; fill?: string; background?: string }

    The same colors as one object; the flat props above take precedence, missing keys keep their defaults

    Default{ line: "#111111", fill: "#E5322D", background: "#FFFFFF" }

  • speednumber

    Playback multiplier

    Default1