Setup Guide
One-time setup for using DECK // NEXT components. Add these to your project, then copy any component from the theme.
The cn() utility combines clsx and tailwind-merge for conditional class names. Install both packages.
npm install clsx tailwind-mergeCreate lib/utils.ts with the cn() helper. Every component imports this for class name merging.
import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]): string {
return twMerge(clsx(inputs))
}Add the DECK // NEXT design tokens to your globals.css. These define colors, fonts, and animation tokens used by every component in the theme.
@theme {
/* ── Colors ─────────────────────────────────────────── */
--color-deck-bg: #0c0b09;
--color-deck-surface: #141310;
--color-deck-lift: #1c1a16;
--color-deck-card: #1f1d19;
--color-deck-ink: #ede9e2;
--color-deck-white: #f5f1ea;
--color-deck-muted: #8a8477;
--color-deck-dim: #4a4740;
--color-deck-orange: #FF5C00;
--color-deck-orange-dark: #cc4a00;
--color-deck-yellow: #DEFF00;
--color-deck-yellow-soft: rgba(222, 255, 0, 0.10);
--color-deck-border: rgba(255, 255, 255, 0.07);
--color-deck-border-rough: rgba(255, 255, 255, 0.12);
/* ── Fonts ──────────────────────────────────────────── */
--font-display: var(--font-permanent-marker, 'Permanent Marker'), cursive;
--font-mono: var(--font-ibm-plex-mono, 'IBM Plex Mono'), monospace;
--font-body: var(--font-ibm-plex-mono, 'IBM Plex Mono'), monospace;
/* ── Animations ─────────────────────────────────────── */
--animate-spray-drip: spray-drip 2.5s ease-in infinite;
--animate-grain-shift: grain-shift 0.8s steps(2) infinite;
}Each component may need its own CSS classes in your globals.css. Copy the styles for the components you use.
/* ─── Buttons ────────────────────────────────────────── */
.btn-base {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
font-family: var(--font-mono);
font-weight: 700;
border: none;
cursor: pointer;
text-decoration: none;
line-height: 1;
letter-spacing: 0.06em;
transition: transform 0.1s ease, box-shadow 0.1s ease;
white-space: nowrap;
clip-path: polygon(
0% 3px, 3px 0%, calc(100% - 3px) 0%, 100% 3px,
100% calc(100% - 3px), calc(100% - 3px) 100%, 3px 100%, 0% calc(100% - 3px)
);
}
.btn-base:hover { transform: translate(-2px, -2px); text-decoration: none; }
.btn-base:active { transform: translate(2px, 2px) !important; box-shadow: none !important; }
.btn-sm { font-size: 12px; padding: 8px 16px; }
.btn-md { font-size: 13px; padding: 12px 24px; }
.btn-lg { font-size: 14px; padding: 14px 32px; }
.btn-primary {
background: var(--color-deck-orange);
color: #000;
box-shadow: 4px 4px 0 rgba(255, 92, 0, 0.25), 8px 8px 0 rgba(0,0,0,0.3);
}
.btn-primary:hover {
box-shadow: 6px 6px 0 rgba(255, 92, 0, 0.3), 10px 10px 0 rgba(0,0,0,0.3);
color: #000;
}
.btn-secondary {
background: var(--color-deck-lift);
color: var(--color-deck-ink);
border: 1px solid var(--color-deck-border-rough);
box-shadow: 3px 3px 0 rgba(0,0,0,0.3);
}
.btn-secondary:hover {
box-shadow: 5px 5px 0 rgba(0,0,0,0.3);
color: var(--color-deck-ink);
}
.btn-ghost {
background: transparent;
color: var(--color-deck-ink);
border: 1.5px solid var(--color-deck-border-rough);
box-shadow: none;
}
.btn-ghost:hover {
border-color: var(--color-deck-orange);
color: var(--color-deck-orange);
}/* ─── Badges ─────────────────────────────────────────── */
.badge {
display: inline-flex;
align-items: center;
gap: 4px;
font-family: var(--font-mono);
font-weight: 700;
font-size: 10px;
letter-spacing: 0.15em;
text-transform: uppercase;
padding: 3px 10px;
border: 1px solid transparent;
clip-path: polygon(
0% 2px, 2px 0%, calc(100% - 2px) 0%, 100% 2px,
100% calc(100% - 2px), calc(100% - 2px) 100%, 2px 100%, 0% calc(100% - 2px)
);
}
.badge--orange { background: rgba(255, 92, 0, 0.12); color: var(--color-deck-orange); border-color: rgba(255, 92, 0, 0.35); }
.badge--yellow { background: rgba(222, 255, 0, 0.08); color: var(--color-deck-yellow); border-color: rgba(222, 255, 0, 0.2); }
.badge--ink { background: rgba(237, 233, 226, 0.08); color: var(--color-deck-ink); border-color: rgba(237, 233, 226, 0.15); }
.badge--dim { background: rgba(74, 71, 64, 0.2); color: var(--color-deck-muted); border-color: rgba(74, 71, 64, 0.4); }/* ─── Text Variants ──────────────────────────────────── */
.text-body { font-family: var(--font-mono); font-size: 13px; line-height: 1.7; font-weight: 400; color: var(--color-deck-muted); }
.text-caption { font-family: var(--font-mono); font-size: 12px; font-weight: 400; color: var(--color-deck-dim); }
.text-label { font-family: var(--font-mono); font-size: 10px; font-weight: 700; letter-spacing: 0.2em; text-transform: uppercase; color: var(--color-deck-dim); }
.text-code { font-family: var(--font-mono); font-size: 12px; color: var(--color-deck-orange); }/* ─── Features Section ───────────────────────────────── */
.deck-card {
background: var(--color-deck-card);
padding: 32px 28px;
border: 1px solid var(--color-deck-border);
position: relative;
overflow: hidden;
transition: background 0.2s;
}
.deck-card:hover { background: var(--color-deck-lift); }
.deck-card::before {
content: '';
position: absolute;
top: 0; left: 0; right: 0;
height: 2px;
background: linear-gradient(90deg, var(--color-deck-orange), transparent);
opacity: 0;
transition: opacity 0.2s;
}
.deck-card:hover::before { opacity: 1; }
.card-num {
position: absolute;
top: 16px;
right: 20px;
font-family: var(--font-mono);
font-size: 10px;
font-weight: 700;
color: var(--color-deck-dim);
letter-spacing: 0.1em;
}
.card-title {
font-family: var(--font-mono);
font-weight: 700;
font-size: 13px;
letter-spacing: 0.06em;
color: var(--color-deck-ink);
margin-bottom: 8px;
}
.card-description {
font-family: var(--font-mono);
font-size: 12px;
color: var(--color-deck-muted);
line-height: 1.6;
}Button
Skate deck art button with primary, secondary, and ghost variants in three sizes. Rough-cut clip-path corners, spray-paint orange accent. Renders as a Next.js Link when an href is provided.
Badge
Spray-paint styled badge with four color variants: orange, yellow, ink, and dim. Suited for category labels, tags, and status indicators.
Text
Polymorphic text primitive with body, caption, label, and code variants. IBM Plex Mono body font. Renders as p, span, or div via the `as` prop.
Card
Composable card with Card, CardHeader, CardBody, and CardFooter sub-components. Dark woodgrain surfaces with spray-paint accent borders.