# Ink Underline
URL: https://remocn.dev/docs/typography/ink-underline

A hand-dragged ink stroke that draws itself across in a few stop-motion poses

- Install: `npx shadcn@latest add @remocn/ink-underline`
- Vibe: paper
- Natural length: 120f @ 30fps

## Installation

```bash
npx shadcn@latest add @remocn/ink-underline
```

## Usage

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:

```tsx
// 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 |
|---|---|---|---|
| `width` (required) | `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 |

## Use when
- A hand-dragged ink underline belongs beneath a written headline, URL, or stat — pairs with `handwrite`, with `delay` set from `handwriteDuration`.
- The scene already runs on the stop-motion clock and the stroke should arrive in the same discrete poses.

## Don't use when
- You are painting a highlight behind a word inside a sentence — use `marker-highlight`.
- You want to circle or strike through something: neither is this component.