
Roughly
Organic, hand-drawn vector annotations designed for high-friction digital typography. Wobbly underlines, pen circles, editorial strikethroughs, curly brackets, and tactile highlights.
Interactive Playground
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.
Import Components
Import the individual annotation subcomponents from your local UI directory for optimal tree-shaking, or use the unified compound <Roughly> component.
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.
Expressive Callout Arrows
Wrap any CTA button or keyword with <RoughArrow> to anchor an arrow with dynamic curve trajectories and handwritten callout notes.
Handwritten Callout Fonts Setup
To use handwriting script for callouts ("caveat", "reenie-beanie", or "kalam"), load Google Fonts in your root layout:
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| type | RoughlyType | "underline" | "underline" | "circle" | "strike-through" | "cross-off" | "bracket" | "box" | "highlight" | "arrow" | "handwriting" |
| color | string | Preset by type | Any valid CSS color string (Hex, RGB, HSL) |
| strokeWidth | number | 2 | Thickness of pen strokes in pixels |
| animate | boolean | true | Triggers pen stroke drawing on scroll viewport entry |
| animationDuration | number | 650 | Duration of drawing in milliseconds |
| side / brackets | BracketSide | "left" | "left" | "right" | "both" | "top" | "bottom" (for bracket type) |
| bracketStyle | BracketStyle | "curly" | "curly" ({ }) | "square" ([ ]) |
| variant | string | "single" | "single" | "double" | "wavy" (underline) • "single" | "double" | "triple" (strike) • "single" | "double" (cross & box) |
| iterations | number | 2 | Number of stroke passes (e.g. 2 for double strokes in box, arrow, highlight, and circle) |
| placement | ArrowPlacement | "top-right" | Direction from which the arrow points at the target: "top-left" | "top" | "top-right" | "right" | "bottom-right" | "bottom" | "bottom-left" | "left" |
| arrowVariant / variant | ArrowVariant | "curved" | Curve trajectory: "curved" (parabolic arc) | "s-curve" (double wave) | "straight" |
| arrowhead | ArrowheadStyle | "open" | Style of arrow tip: "open" (>) | "filled" (solid triangle) |
| label | ReactNode | undefined | Handwritten callout text displayed at the tail of the arrow |
| labelFont | ArrowLabelFont | "caveat" | Handwriting font family for callout text: "caveat" (default) | "reenie-beanie" | "kalam" |
| labelFontSize | number | 20 | 26 | Font size in pixels for handwritten callout text |
| labelPlacement | ArrowLabelPlacement | "auto" | Placement relative to arrow tail: "auto" | "top" | "bottom" | "left" | "right" |
| labelDistance | number | 8 | Gap distance in pixels between arrow tail and label |
| labelRotate | number | 0 | Custom label rotation angle in degrees |
| labelOffsetX / labelOffsetY | number | 0 | Fine-tuning pixel nudges along X and Y axes |
| labelColor | string | color | Custom color override for the callout text (defaults to arrow color) |
| curveLabel | boolean | true | When true, renders callout text along a smooth mathematical SVG arc with zero misalignment |
| font | HandwritingFont | "reenie-beanie" | Font family for handwriting type: "reenie-beanie" (default) | "caveat" | "kalam" |
| fontSize | number | 40 | Font size in pixels used to generate handwriting glyph paths |
| editable | boolean | false | Enables interactive live-typing mode for handwriting with real-time SVG stroke tracing |