Roughly Hand-drawn Vector Annotations - Drafting & Stationery Artwork

Roughly

Organic, hand-drawn vector annotations designed for high-friction digital typography. Wobbly underlines, pen circles, editorial strikethroughs, curly brackets, and tactile highlights.

$pnpm dlx shadcn@latest addhttps://void-ui.vercel.app/r/roughly.json
Scroll

Interactive Playground

9 styles
Stroke Width2.5px
Duration750ms
Live Canvas
Interfaces with visceral depth
React Component Snippet
1<RoughUnderline strokeWidth={2.5}>
2 Interfaces with visceral depth
3</RoughUnderline>

Editorial Typography Demonstration

Void UI components are designed with tactile physical friction, transforming sterile digital surfaces into visceral instruments. Rather than flattening user interfaces, we introduce deliberate resistance and dynamic spring dynamics.

In traditional software development, designers often rely on bland grey boxes and lifeless borders. With Roughly, you can draw attention to critical insights or mark deprecated features with an organic cross out.

• Zero layout shift on page reloads

• Sized to encompass all tall ascenders and low descenders

• Scroll-triggered hardware-accelerated SVG draw animation

Every annotation is enclosed in a hand-drawn rough frame with natural corner overshoots and fluid double stroke sketch loops.

Direct the reader's gaze with an expressive Direct vector pointing ✨hand-drawn callout arrow that automatically calculates its trajectory, clearance, and entry angle directly onto the target word.

How to Use

Install via Void UI CLI

Add Void UI's Roughly annotations directly into your project via the shadcn CLI. This downloads the source code into components/ui/roughly/ and automatically resolves all peer dependencies.

$pnpm dlx shadcn@latest add https://void-ui.vercel.app/r/roughly.json

Import Components

Import the individual annotation subcomponents from your local UI directory for optimal tree-shaking, or use the unified compound <Roughly> component.

Named Imports
1import {
2 Roughly,
3 RoughCircle,
4 RoughUnderline,
5 RoughHighlight,
6 RoughBox,
7 RoughBracket,
8 RoughStrike,
9 RoughCross,
10 RoughArrow,
11} from "@/components/ui/roughly";

Annotate Text & Keywords

Wrap any word, phrase, or inline block. Annotations automatically measure bounding boxes and draw with organic hand-drawn roughness when scrolled into view.

Example Component
1import {
2 RoughHighlight,
3 RoughCircle,
4 RoughUnderline,
5 RoughBox,
6} from "@/components/ui/roughly";
7 
8export default function ArticleHero() {
9 return (
10 <div className="space-y-4">
11 {/* Tactile Marker Highlight */}
12 <h1 className="text-3xl font-bold text-white">
13 Design with <RoughHighlight color="#4338CA">physical friction</RoughHighlight>
14 </h1>
15 
16 {/* Hand-drawn Pen Circle */}
17 <p className="text-neutral-300">
18 Focus on <RoughCircle color="#6366F1">critical insights</RoughCircle> inside body copy.
19 </p>
20 
21 {/* Wavy Underline */}
22 <p className="text-neutral-300">
23 Add energy with <RoughUnderline variant="wavy" color="#10B981">expressive underlines</RoughUnderline>.
24 </p>
25 
26 {/* Sketch Box Frame */}
27 <p className="text-neutral-300">
28 Enclose cards in a <RoughBox color="#F59E0B" variant="double">hand-drawn frame</RoughBox>.
29 </p>
30 </div>
31 );
32}

Expressive Callout Arrows

Wrap any CTA button or keyword with <RoughArrow> to anchor an arrow with dynamic curve trajectories and handwritten callout notes.

Arrow Callout
1import { RoughArrow } from "@/components/ui/roughly";
2 
3export function CalloutDemo() {
4 return (
5 <div className="p-12 flex justify-center">
6 <RoughArrow
7 placement="top-right"
8 variant="curved"
9 arrowhead="open"
10 color="#F59E0B"
11 label="Interactive Studio ✨"
12 labelFont="caveat"
13 distance={65}
14 >
15 <button className="px-6 py-3 rounded-xl bg-white text-black font-semibold shadow-lg">
16 Launch Console
17 </button>
18 </RoughArrow>
19 </div>
20 );
21}

Handwritten Callout Fonts Setup

To use handwriting script for callouts ("caveat", "reenie-beanie", or "kalam"), load Google Fonts in your root layout:

app/layout.tsx
1<head>
2 <link
3 rel="stylesheet"
4 href="https://fonts.googleapis.com/css2?family=Caveat:wght@500;700&family=Kalam:wght@300;400;700&family=Reenie+Beanie&display=swap"
5 />
6</head>

API Reference

PropTypeDefaultDescription
typeRoughlyType"underline""underline" | "circle" | "strike-through" | "cross-off" | "bracket" | "box" | "highlight" | "arrow" | "handwriting"
colorstringPreset by typeAny valid CSS color string (Hex, RGB, HSL)
strokeWidthnumber2Thickness of pen strokes in pixels
animatebooleantrueTriggers pen stroke drawing on scroll viewport entry
animationDurationnumber650Duration of drawing in milliseconds
side / bracketsBracketSide"left""left" | "right" | "both" | "top" | "bottom" (for bracket type)
bracketStyleBracketStyle"curly""curly" ({ }) | "square" ([ ])
variantstring"single""single" | "double" | "wavy" (underline) • "single" | "double" | "triple" (strike) • "single" | "double" (cross & box)
iterationsnumber2Number of stroke passes (e.g. 2 for double strokes in box, arrow, highlight, and circle)
placementArrowPlacement"top-right"Direction from which the arrow points at the target: "top-left" | "top" | "top-right" | "right" | "bottom-right" | "bottom" | "bottom-left" | "left"
arrowVariant / variantArrowVariant"curved"Curve trajectory: "curved" (parabolic arc) | "s-curve" (double wave) | "straight"
arrowheadArrowheadStyle"open"Style of arrow tip: "open" (>) | "filled" (solid triangle)
labelReactNodeundefinedHandwritten callout text displayed at the tail of the arrow
labelFontArrowLabelFont"caveat"Handwriting font family for callout text: "caveat" (default) | "reenie-beanie" | "kalam"
labelFontSizenumber20 | 26Font size in pixels for handwritten callout text
labelPlacementArrowLabelPlacement"auto"Placement relative to arrow tail: "auto" | "top" | "bottom" | "left" | "right"
labelDistancenumber8Gap distance in pixels between arrow tail and label
labelRotatenumber0Custom label rotation angle in degrees
labelOffsetX / labelOffsetYnumber0Fine-tuning pixel nudges along X and Y axes
labelColorstringcolorCustom color override for the callout text (defaults to arrow color)
curveLabelbooleantrueWhen true, renders callout text along a smooth mathematical SVG arc with zero misalignment
fontHandwritingFont"reenie-beanie"Font family for handwriting type: "reenie-beanie" (default) | "caveat" | "kalam"
fontSizenumber40Font size in pixels used to generate handwriting glyph paths
editablebooleanfalseEnables interactive live-typing mode for handwriting with real-time SVG stroke tracing