Paper
Paper fiber texture: thin lines at slightly off-axis angles on three repeat intervals, which avoids moire. White fibers by default, recolored for light grounds; three intensities.
pnpm dlx shadcn add @01orbital/paperimport { cn } from "cn"
type Intensity = "fine" | "default" | "rich"
// One scale for every texture; `default` is the unscaled value.
const INTENSITY_MULT: Record<Intensity, number> = {
fine: 0.6,
default: 1,
rich: 1.45,
}
const alpha = (base: number, mult: number) => (base * mult).toFixed(4)
// Full-bleed art layer — drop inside a `relative` parent; sits behind content.
// Off-axis fiber angles (3°, -2°, 1°) + three repeat intervals avoid moiré.
function Paper({
intensity = "default",
className,
...props
}: React.ComponentProps<"div"> & {
// Fiber alpha multiplier. Ink is white; set --paper-color on a light ground.
intensity?: Intensity
}) {
const m = INTENSITY_MULT[intensity]
return (
<div
className={cn("pointer-events-none absolute inset-0", className)}
aria-hidden="true"
data-slot="paper"
{...props}
>
<div
className="absolute inset-0"
style={{
backgroundImage: `
repeating-linear-gradient(3deg in srgb, transparent 0px, transparent 6px, oklch(from var(--paper-color, oklch(1 0 0)) l c h / ${alpha(0.04, m)}) 6px, oklch(from var(--paper-color, oklch(1 0 0)) l c h / ${alpha(0.02, m)}) 7px),
repeating-linear-gradient(-2deg in srgb, transparent 0px, transparent 8px, oklch(from var(--paper-color, oklch(1 0 0)) l c h / ${alpha(0.03, m)}) 8px, oklch(from var(--paper-color, oklch(1 0 0)) l c h / ${alpha(0.01, m)}) 9px),
repeating-linear-gradient(1deg in srgb, transparent 0px, transparent 12px, oklch(from var(--paper-color, oklch(1 0 0)) l c h / ${alpha(0.02, m)}) 12px, oklch(from var(--paper-color, oklch(1 0 0)) l c h / ${alpha(0.01, m)}) 13px)
`,
}}
/>
</div>
)
}
export { Paper }
import { Paper } from "@/components/texture/paper"
import {
Card,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"
/** A sized paper surface with readable studio details. */
export default function PaperDemo() {
return (
<div className="flex min-h-full w-full flex-1 items-center justify-center p-4 sm:p-8">
<Card className="relative isolate w-full max-w-sm gap-6 overflow-hidden rounded-xl bg-[#eee6d5] p-6 wrap-anywhere text-[#302e29] shadow-sm ring-1 ring-black/10 [--muted-foreground:#59554b] sm:p-8">
<Paper intensity="rich" className="[--paper-color:#302e29]" />
<CardHeader className="relative z-20 gap-6 px-0">
<p className="text-sm font-medium">Common Press</p>
<div className="grid gap-1">
<CardTitle className="text-2xl/8 font-medium tracking-tight">
Elliot Park
</CardTitle>
<CardDescription>Editor & book designer</CardDescription>
</div>
</CardHeader>
<CardFooter className="relative z-20 flex-wrap justify-between gap-3 border-t border-current/20 px-0 pt-5 text-xs/5">
<span>12 Chapel Yard, Norwich</span>
<a
href="mailto:hello@commonpress.example"
className="break-all underline underline-offset-4 focus-visible:outline-2 focus-visible:outline-offset-4"
>
hello@commonpress.example
</a>
</CardFooter>
</Card>
</div>
)
}
The example also uses card. Install it too:
pnpm dlx shadcn add @01orbital/cardnpx shadcn add @01orbital/cardyarn shadcn add @01orbital/cardbunx --bun shadcn add @01orbital/cardUsage
import { Paper } from "@/components/texture/paper"
import {
Card,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"
/** A sized paper surface with readable studio details. */
export default function PaperDemo() {
return (
<div className="flex min-h-full w-full flex-1 items-center justify-center p-4 sm:p-8">
<Card className="relative isolate w-full max-w-sm gap-6 overflow-hidden rounded-xl bg-[#eee6d5] p-6 wrap-anywhere text-[#302e29] shadow-sm ring-1 ring-black/10 [--muted-foreground:#59554b] sm:p-8">
<Paper intensity="rich" className="[--paper-color:#302e29]" />
<CardHeader className="relative z-20 gap-6 px-0">
<p className="text-sm font-medium">Common Press</p>
<div className="grid gap-1">
<CardTitle className="text-2xl/8 font-medium tracking-tight">
Elliot Park
</CardTitle>
<CardDescription>Editor & book designer</CardDescription>
</div>
</CardHeader>
<CardFooter className="relative z-20 flex-wrap justify-between gap-3 border-t border-current/20 px-0 pt-5 text-xs/5">
<span>12 Chapel Yard, Norwich</span>
<a
href="mailto:hello@commonpress.example"
className="break-all underline underline-offset-4 focus-visible:outline-2 focus-visible:outline-offset-4"
>
hello@commonpress.example
</a>
</CardFooter>
</Card>
</div>
)
}Examples
New
paper-studio-card
New
paper-workshop-invitation
New
paper-seasonal-menu
New
paper-field-note
New
paper-edition-cover
New
paper-order-receipt
New
paper-collection-label
New
paper-studio-letter
New
paper-quote-card
New
paper-day-programme
API reference
Prop
Type
It also accepts the HTML attributes of the element it renders.
Dependencies
npm: cn. The CLI installs them for you.
No other registry pieces.