Ink Underline
A hand-dragged ink stroke that draws itself across in a few stop-motion poses
Installation
$ pnpm dlx shadcn@latest add @remocn/ink-underlineUsage
The stroke renders in normal flow — a block of width by thickness + 4 — so it
stacks under text in a flex column. Pair it with handwrite and start the drag
the moment the writing finishes:
// src/Root.tsx
import { AbsoluteFill, Composition } from "remotion";
import { Handwrite, handwriteDuration } from "@/components/remocn/handwrite";
import { InkUnderline } from "@/components/remocn/ink-underline";
const url = "remocn.dev";
const InkUnderlineScene = () => (
<AbsoluteFill
style={{
background: "#f1eee7",
alignItems: "center",
justifyContent: "center",
flexDirection: "column",
gap: 4,
}}
>
<div style={{ position: "relative", width: 420, height: 96 }}>
<Handwrite text={url} fontSize={64} />
</div>
<InkUnderline width={420} delay={handwriteDuration(url)} />
</AbsoluteFill>
);
export const RemotionRoot = () => (
<Composition
id="InkUnderline"
component={InkUnderlineScene}
durationInFrames={60}
fps={30}
width={1280}
height={720}
/>
);Handwrite centres itself inside its nearest positioned ancestor, which is why
it sits in a sized position: relative box here. The underline needs no such
box — it is a block in the flow.
The wobble in the stroke comes from seed: the same seed always draws the same
curve, and changing it gives a different hand. durationSteps is how many
stop-motion poses the drag takes, so the real length in frames is
durationSteps * step.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
widthrequired | number | — | Stroke length in pixels |
color | string | "#6f7f35" | Ink colour (any valid CSS color) |
thickness | number | 9 | Brush width in pixels at full pressure |
pressure | number | 1 | Weight the brush lands on, as a fraction of thickness |
release | number | 0.15 | Weight the brush lifts off at; below pressure it thins into a dry tail |
grain | number | 1 | Edge roughness; breaks the thin tail into dry-brush flecks, 0 gives clean edges |
delay | number | 0 | Frames on the local clock before the drag begins |
durationSteps | number | 5 | Stop-motion poses the drag takes |
seed | string | "ink" | Seed for the curve wobble — same seed, same stroke |
step | number | 3 | Frames per stop-motion pose — the tempo control |