cursor-path
remotionui/cursor-pathFreeComponent
Cursor travelling a path with drawn trail and click ripples
Live preview
live · rendered by the registry
Rendered by remotionui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://remotionui.com/r/cursor-path.jsonSource
1import { interpolate, spring, useCurrentFrame, useVideoConfig } from "remotion";2import { EASING } from "@/remotion/lib/motion-tokens";3import { springSnappy } from "@/remotion/lib/springs";4import {5 clampProgress,6 getPathDrawStyles,7 samplePath,8 waypointProgress,9 waypointsToPath,10 type PathPoint,11} from "@/remotion/lib/path-utils";1213export type CursorPoint = PathPoint;1415export type CursorPathProps = {16 /** Waypoints in the parent's coordinate space. Ignored when `d` is set. */17 points?: CursorPoint[];18 /** Drive the cursor along an authored SVG path instead of waypoints. */19 d?: string;20 durationInFrames?: number;21 delayInFrames?: number;22 color?: string;23 size?: number;24 /** 0 hops in straight lines; higher values round the corners. */25 smoothing?: number;26 /** `draw` reveals the route behind the cursor, `guide` shows it up front. */27 trail?: "draw" | "guide" | "none";28 /** Waypoint indices that get a click ripple as the cursor arrives. */29 clickAt?: number[];30};3132const CLICK_DURATION = 18;3334export const CursorPath: React.FC<CursorPathProps> = ({35 points = [],36 d,37 durationInFrames = 90,38 delayInFrames = 0,39 color = "#e8b86d",40 size = 34,41 smoothing = 0.6,42 trail = "draw",43 clickAt = [],44}) => {45 const frame = useCurrentFrame();46 const { fps } = useVideoConfig();47 const path = d ?? waypointsToPath(points, smoothing);4849 if (!path) {50 return null;51 }5253 // Travel is measured in arc length, not waypoint index, so the cursor holds54 // one speed across a long hop and a short one.55 const progress = clampProgress(56 interpolate(57 frame,58 [delayInFrames, delayInFrames + durationInFrames],59 [0, 1],60 {61 extrapolateLeft: "clamp",62 extrapolateRight: "clamp",63 easing: EASING.editorial,64 },65 ),66 );67 const position = samplePath(path, progress);68 const trailStyles = getPathDrawStyles(progress, path);6970 // A click fires on arrival, so its frame comes from where the waypoint sits71 // along the path rather than from a hand-timed offset.72 const stops = d ? [] : waypointProgress(path, points);73 const clicks = clickAt74 .filter((index) => stops[index] !== undefined)75 .map((index) => ({76 point: points[index],77 startFrame: delayInFrames + stops[index] * durationInFrames,78 }));7980 return (81 <svg style={{ position: "absolute", inset: 0, overflow: "visible" }}>82 {trail === "guide" ? (83 <path84 d={path}85 fill="none"86// … truncated
More from remotionui
All 127 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| audio-pulseaudio-pulse | remotionui | Components | Free | no deps | |
| audiogram-barsaudiogram-bars | remotionui | Components | Free | no deps | |
| blur-focus-inblur-focus-in | remotionui | Components | Free | no deps | |
| blur-inblur-in | remotionui | Components | Free | no deps | |
| blur-revealblur-reveal | remotionui | Components | Free | no deps | |
| caption-highlightcaption-highlight | remotionui | Components | Free | no deps | |
| chromatic-aberration-wipechromatic-aberration-wipe | remotionui | Components | Free | no deps | |
| confetti-burstconfetti-burst | remotionui | Components | Free | no deps |
