Autopilot

A cursor that uses your product on its own. It glides to buttons and presses them, types and drags across real markup on a script you write, and steps aside the moment a visitor wants to try it.

  • Cursor
  • Interaction
  • Showcase

Uses motion, clsx, tailwind-merge

Open in ChatGPTOpen in Claude
14Calendar
Tue14
Wed15
Thu16
10 AM
11 AM
12 PM
1 PM
2 PM
3 PM
4 PM

Standup

Roadmap sync

11 – 12:30pm

Customer calls

1 – 3pm

Standup

Lunch & learn

12 – 1pm

Sprint review

3 – 5pm

Hiring panel

10 – 11:30am

Design crit

1 – 2pm

Installation

Add the component on its own with the CLI, or copy the file in by hand.

The CLI writes components/ui/autopilot.tsx and installs motion, clsx and tailwind-merge. It needs the @keyframeui registry in components.json; add it once per project.

npx shadcn@latest add @keyframeui/autopilot

Examples

Finished sections built with Autopilot. Each one installs whole, with the component included.

Design Review

Two teammates on a design canvas, with their steps running at the same time. Maya drags the Features frame into place, and its snap guides show through `data-autopilot-drop`, while Leo drops a comment pin and asks a question. Then Maya replies and Leo likes it. Move your mouse in and both step aside, and the canvas is yours: drag the frame or leave a comment.

Landing v3

MLY
Hero
Pricing
24
Features

Three Clicks

A SaaS app sets up a project in three clicks, one chapter each, with `chapterStrip` showing Create, Invite and Ship underneath. Click a chapter to jump there, or pause from the strip. On a phone, tap the app to take over and press Resume to hand it back.

Projects

Start a project

Pick a template. You can change everything later.

Props

cursorsRequired

TypeAutopilotCursor[]

The cursors on the stage, as { id, label, color, home? }. label is the pill's text when the cursor isn't saying anything, and home is where it waits at the start and between loops, as fractions of the stage. Steps without a cursor belong to the first.

chaptersRequired

TypeAutopilotChapter[]

The script, as { title, setup?, steps }. setup puts the UI in the state the chapter starts from. It runs every time the chapter starts, so after a takeover, a jump or a loop the chapter replays from a known state.

childrenRequired

TypeReact.ReactNode

The UI the cursors use. Mark targets with data-autopilot="<name>". While a cursor is on one it gets data-autopilot-hover, -press, -focus, -drag or -drop, so style them next to hover:, active: and focus:.

chapterStrip

TypebooleanDefaultfalse

Show the chapters under the stage. The current one fills like a story timer, and clicking one jumps to it. The pause button moves into the strip.

loop

TypebooleanDefaulttrue

Start over after the last chapter: the finished state holds for 2s, the stage crossfades back and the cursors glide home. With false it stops on the finished state and shows Play.

park

Type"bottom-right" | "bottom-left" | "top-right" | "top-left"Default"bottom-right"

The corner the cursors step aside to while the visitor has control, and wait in unless they have a home. Pick one your UI keeps clear.

yieldLabel

TypestringDefault"Your turn"

The parked cursor's label while the visitor has control.

onChapterChange

Type(index: number) => void

Called as each chapter starts.

stageClassName

Typestring

Classes for the stage, the box the cursors move in. Borders, rounding and overflow-hidden go here.

className

Typestring

Classes for the outer wrapper, which also holds the chapter strip. The strip draws in the text color, so set text-* here to recolor it.

step.move

Typestring

AutopilotStep: glide to the target with this name and rest over it.

step.click

Typestring

AutopilotStep: go to the target, wait a beat, then press and release. Pointer, mouse and click events fire on it with real coordinates, so the UI's own handlers run.

step.type / step.into

Typestring

AutopilotStep: click into the input or textarea named by into (or the one inside it) and type the text at a person's pace, so onChange runs per key. {Enter} and {Backspace} press those keys. Real focus never moves; the field gets data-autopilot-focus.

step.drag / step.to

Typestring

AutopilotStep: lift the target, carry it onto the to target and set it down. The item moves with translate and scale while it's held.

step.drop

Type() => void

AutopilotStep: with drag, called as the item is set down. Move it in your state here; it settles from the drop point into its new place.

step.wait

Typenumber

AutopilotStep: rest for this many ms.

step.do

Type() => void | Promise<void>

AutopilotStep: run a callback for state the demo owns. A returned promise is awaited.

step.cursor

Typestring

AutopilotStep: the cursor that takes the step. Each cursor takes its own steps in order, and different cursors' steps run at the same time.

step.say

Typestring | null

AutopilotStep: change the cursor's label as the step starts. It stays until the next say; null goes back to the cursor's label.

step.at

Type[number, number]

AutopilotStep: where on the target to point, as fractions of its width and height. By default it lands near the middle, never dead center, and toward the start of a text field.