Ink Arrow
A hand-drawn arrow that draws itself from one point to another in stop-motion poses
Installation
$ pnpm dlx shadcn@latest add @remocn/ink-arrowUsage
from and to are in the arrow's own local space — you place the component,
the arrow draws inside it. The SVG lets its contents overflow, so the bow and
the head are never clipped.
// src/Root.tsx
import { AbsoluteFill, Composition } from "remotion";
import { InkArrow } from "@/components/remocn/ink-arrow";
const InkArrowScene = () => (
<AbsoluteFill style={{ background: "#f1eee7" }}>
<h1 style={{ position: "absolute", left: 200, top: 150 }}>Start here</h1>
<div style={{ position: "absolute", left: 300, top: 210 }}>
<InkArrow from={{ x: 20, y: 20 }} to={{ x: 300, y: 210 }} />
</div>
<div style={{ position: "absolute", left: 600, top: 400 }}>
<YourCard />
</div>
</AbsoluteFill>
);
export const RemotionRoot = () => (
<Composition
id="InkArrow"
component={InkArrowScene}
durationInFrames={120}
fps={30}
width={1280}
height={720}
/>
);The pen drags the curve over drawDur frames, quantized to the stop-motion
clock. When the line lands, the head is drawn rather than dropped in: one
stroke out from the tip, then the other, over headDur frames split evenly
between them.
curvature is the perpendicular bow as a fraction of the distance between the
two points, so the arc keeps its shape as the arrow gets longer. Flip its sign
to bow the other way. Each control point also carries a small per-seed
wobble, which is what stops the curve looking machine-drawn; the same seed
always gives the same hand.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
fromrequired | { x: number; y: number } | — | Start point, in the component's local space |
torequired | { x: number; y: number } | — | End point — where the head lands |
curvature | number | 0.35 | Perpendicular bow as a fraction of the distance; negative bows the other way |
color | string | "#26242c" | Ink colour (any valid CSS color) |
strokeWidth | number | 8 | Brush width in pixels at full pressure |
pressure | number | 0.2 | Weight the brush opens on, as a fraction of strokeWidth |
release | number | 1 | Weight the brush reaches at the head; above pressure the shaft thickens as it travels |
grain | number | 1 | Edge roughness; breaks the thin opening into dry-brush flecks, 0 gives clean edges |
delay | number | 0 | Frames on the local clock before the drag begins |
drawDur | number | 36 | Frames the contour takes to draw |
headSize | number | 24 | Length of each head stroke in pixels; a floor, never shrinking below what the brush width needs |
headDur | number | step * 4 | Frames to draw both head strokes, split evenly between them |
seed | string | "arrow" | Seed for the curve wobble — same seed, same arrow |
step | number | 3 | Frames per stop-motion pose — the tempo control |