All articles

How to Create a Dynamic Animated Brush in Rive with Path Effect Scripts

|7 min read

How to Create a Dynamic Animated Brush in Rive with Path Effect Scripts

Path Effect Scripts are one of the more advanced features in Rive, and they open up a lot of creative possibilities.

In this tutorial, we'll use them to build a dynamic, animated brush effect — the kind of rough, hand-drawn highlight you'd see on a UI label or headline.

The goal isn't to create a "perfect" brush. It's to show how a small script can evolve into something expressive and reusable.

Starting With a Simple Shape

We begin with a basic setup: a rectangle used as a background shape behind a text label.

I used Rive's Layouts feature to make sure the rectangle always resizes to fit the text with a bit of padding. From here, we'll gradually add complexity using scripting.

Creating the First Path Effect Script

To start working with scripting, we create a Path Effect Script and apply it to the shape's Fill layer. The update() function runs on every frame — this is actually a good sign. It tells us the script is wired correctly.

Verifying the Script Works

Before building anything complex, it's worth confirming the pipeline works.

Instead of writing logic manually, we ask the Agent to slightly distort the shape along the Y-axis — just to verify the script is applied correctly.

Prompt — Basic distortion test:

Use the existing Script. Modify the path update so that all points are slightly offset on the Y axis using a simple sine function. Do not use time. Keep the result deterministic.

Once applied, the shape shows a subtle distortion. Nothing fancy — just confirmation that the script is running. After that, we remove this temporary logic and start fresh.

What Makes a Brush Feel Hand-Drawn?

A hand-drawn brush isn't about perfection. It's defined by:

  • Slightly uneven edges
  • Inconsistent thickness
  • Small variations that make it feel organic, not mathematical

To simulate that imperfection — and make it dynamic — we introduce three core properties.

Core Brush Properties

Amplitude

Controls how strong the distortion is.

  • Low values = subtle, soft distortion
  • High values = bold, aggressive distortion

You can think of this as how much you allow yourself to "break" the shape.

Frequency

Controls how often the distortion appears along the shape.

  • Low values = wide, loose variations
  • High values = dense, tightly packed variations

Seed

Introduces variation. Changing the seed gives you different versions of the same brush, preventing every instance from looking identical.

Generating the Brush

Instead of implementing all of this manually, we use the Agent again — this time with a more intentional prompt. We ask it to use the existing script, implement the three properties, keep the distortion soft and UI-friendly, and make sure the result is static and deterministic (no time-based animation yet).

Prompt — Brush generation with Amplitude / Frequency / Seed:

Create a Path Effect Script that produces a static, organic brush-like edge for a rectangular shape. The goal is to gently break the perfect geometry so the shape feels hand-drawn but still clean and readable. Apply smooth, continuous distortion along all four edges (top, bottom, left, right) with rounded, flowing curves rather than sharp angles. The distortion should be strongest near the center of each edge and gradually fade out toward the corners. Keep corners soft and stable. Avoid sharp spikes, jagged shapes, or visible teeth. Expose exactly three inputs: amplitude (range 0–50, default 10), frequency (range 0–50, default 5), seed (range 0–50, default 1). Keep the effect static and deterministic — do not use time or animation. Geometry changes should occur only in update().

Adding Direction for a More Natural Feel

Real brush strokes are rarely symmetrical. They usually have a direction — top to bottom or left to right.

Direction

Defines the dominant stroke direction:

  • 0 = no dominant direction
  • 1 = vertical stroke (top to bottom)
  • 2 = horizontal stroke (left to right)

The distortion becomes stronger perpendicular to the stroke direction.

Direction Strength

Controls how noticeable that directional difference is:

  • Low values = very subtle
  • High values = clearly directional

Together, these properties make the brush feel more natural and intentional.

Prompt — Adding Direction and Direction Strength:

Extend the existing brush-like path distortion by adding a directional bias to break symmetry. Add two new inputs: direction (number, default 0 — 0 = uniform all edges, 1 = horizontal bias: top and bottom edges distort more, left and right edges distort less, 2 = vertical bias: left and right edges distort more, top and bottom edges distort less); directionStrength (range 0–10, default 3 — controls how strong the directional bias is). Apply the directional bias smoothly and gradually without creating sharp transitions or breaking the shape. The goal is to make the brush feel more hand-drawn by introducing controlled asymmetry while keeping the result clean and suitable for UI.

Adding Animation (Stop Motion Style)

At this point, we have a solid brush effect. We could keep refining it — adding more properties and inputs — but let's introduce animation.

Because this brush is meant to feel rough and hand-made, a stop-motion style animation works well. Stop motion uses small, stepped movements, creating a slightly jittery, imperfect motion that complements the organic shape.

Prompt — Animation logic:

Extend the existing brush-like path distortion with an optional stop-motion style animation. Add two new inputs: animate (boolean, default false — enables/disables animation); animationSpeed (number, default 0.5 — controls how often the distortion updates; lower values = slower, subtler motion; higher values = faster, more noticeable changes). When animation is enabled: update the distortion only at discrete time intervals to create a stop-motion feel. Slightly offset the existing distortion pattern (for example, shifting the seed) rather than generating a completely new shape. Keep each frame stable until the next update. When animation is disabled: the brush should remain completely static and deterministic. The animation should feel subtle, hand-drawn, and suitable for UI — not fluid or noisy.

Once applied, we can enable animation, adjust speed live, and see the effect update in real time.

Using the Brush in Real UI

Finally, we can turn this effect into something reusable.

The brush becomes a component, connected to Data Binding, and reused across multiple UI elements — for example, different text labels with different brush styles.

The same script drives:

  • Shape distortion
  • Animation
  • Responsiveness
  • Visual consistency

This is where scripting really shines. A small piece of logic becomes a reusable, expressive UI system.

Wrapping Up

Path Effect Scripts can turn simple shapes into dynamic, animated, and reusable UI elements.

The brush we built isn't "final" — and that's the point. You can keep refining it, extending it, and connecting it to more systems as your project grows.

Get more Rive tips

Weekly tutorials, new lessons, and Rive community highlights — no spam.