PINBALL // NEXT

Setup Guide

One-time setup for using PINBALL // NEXT components. Add these to your project, then copy any component from the theme.

1
Install dependencies

The cn() utility combines clsx and tailwind-merge for conditional class names. Install both packages.

BASH
npm install clsx tailwind-merge
2
Add utility function

Create lib/utils.ts with the cn() helper. Every component imports this for class name merging.

TS
import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'

export function cn(...inputs: ClassValue[]): string {
  return twMerge(clsx(inputs))
}
3
Add design tokens

Add the PINBALL // NEXT design tokens to your globals.css. These define colors, fonts, and animation tokens used by every component in the theme.

CSS
@theme {
  /* ── Colors ─────────────────────────────────────────── */
  --color-pinball-midnight:         #0D0D2B;
  --color-pinball-midnight-deep:    #06061A;
  --color-pinball-midnight-light:   #151540;
  --color-pinball-magenta:          #FF2D8A;
  --color-pinball-magenta-dim:      #cc2470;
  --color-pinball-yellow:           #FFE814;
  --color-pinball-yellow-dim:       #d4c210;
  --color-pinball-chrome-light:     #e0e0f0;
  --color-pinball-chrome-mid:       #8888aa;
  --color-pinball-chrome-dark:      #44446a;
  --color-pinball-white:            #f0f0ff;
  --color-pinball-white-dim:        #a0a0c0;
  --color-pinball-green:            #44dd88;
  --color-pinball-cyan:             #44ddff;

  /* ── Fonts ───────────────────────────────────────────── */
  --font-display: var(--font-bungee);
  --font-body:    var(--font-space-grotesk);

  /* ── Animations ──────────────────────────────────────── */
  --animate-blink:       blink-cursor 0.8s step-end infinite;
  --animate-pulse-soft:  pulse-soft 2.5s ease-in-out infinite;
}
4
Add component styles

Each component may need its own CSS classes in your globals.css. Copy the styles for the components you use.

CSS
/* ─── Buttons ────────────────────────────────────────── */

.btn-base {
  display:         inline-flex;
  align-items:     center;
  justify-content: center;
  gap:             8px;
  font-family:     var(--font-display);
  font-weight:     400;
  border:          none;
  cursor:          pointer;
  text-decoration: none;
  line-height:     1;
  letter-spacing:  2px;
  transition:      background 0.2s, transform 0.12s;
  white-space:     nowrap;
  clip-path:       polygon(10px 0, 100% 0, calc(100% - 10px) 100%, 0 100%);
}

.btn-base:hover  { text-decoration: none; }

.btn-base:active { transform: scale(0.97); }

.btn-sm { font-size: 11px; padding: 10px 24px; }

.btn-md { font-size: 13px; padding: 14px 32px; }

.btn-lg { font-size: 14px; padding: 16px 40px; }

.btn-primary {
  background: var(--color-pinball-magenta);
  color:      var(--color-pinball-white);
}

.btn-primary:hover {
  background: var(--color-pinball-magenta-dim);
  color:      var(--color-pinball-white);
}

.btn-secondary {
  background:   transparent;
  color:        var(--color-pinball-white-dim);
  border:       1px solid var(--color-pinball-chrome-dark);
  clip-path:    none;
  font-family:  var(--font-body);
  font-weight:  500;
  letter-spacing: 0.02em;
}

.btn-secondary:hover {
  color:        var(--color-pinball-yellow);
  border-color: var(--color-pinball-yellow);
}

.btn-ghost {
  background:   transparent;
  color:        var(--color-pinball-white-dim);
  clip-path:    none;
  font-family:  var(--font-body);
  font-weight:  500;
  letter-spacing: 0.02em;
}

.btn-ghost:hover {
  color: var(--color-pinball-yellow);
}
CSS
/* ─── Badges ─────────────────────────────────────────── */

.badge {
  display:         inline-flex;
  align-items:     center;
  gap:             4px;
  font-weight:     700;
  font-size:       10px;
  letter-spacing:  2px;
  text-transform:  uppercase;
  padding:         4px 12px;
  clip-path:       polygon(4px 0, 100% 0, calc(100% - 4px) 100%, 0 100%);
}

.badge--magenta  { background: var(--color-pinball-magenta); color: var(--color-pinball-midnight-deep); }

.badge--yellow   { background: var(--color-pinball-yellow);  color: var(--color-pinball-midnight-deep); }

.badge--chrome   { background: var(--color-pinball-chrome-mid); color: var(--color-pinball-midnight-deep); }

.badge--green    { background: var(--color-pinball-green);   color: var(--color-pinball-midnight-deep); }

.badge--cyan     { background: var(--color-pinball-cyan);    color: var(--color-pinball-midnight-deep); }
CSS
/* ─── Text Variants ──────────────────────────────────── */

.text-body    { font-size: 14px; line-height: 1.7; font-weight: 400; color: var(--color-pinball-white-dim); }

.text-caption { font-size: 12px; font-weight: 500; color: var(--color-pinball-chrome-mid); }

.text-label   { font-size: 11px; font-weight: 500; letter-spacing: 3px; text-transform: uppercase; }

.text-code    { font-family: monospace; font-size: 13px; }
CSS
/* ─── Horizontal Scroll Features ─────────────────────── */

.pinball-card {
  flex:        0 0 360px;
  scroll-snap-align: start;
  background:  var(--color-pinball-midnight-light);
  border:      2px solid transparent;
  background-clip: padding-box;
  position:    relative;
  padding:     36px 32px;
  min-height:  320px;
  display:     flex;
  flex-direction: column;
}

.pinball-card::before {
  content:    '';
  position:   absolute;
  inset:      -2px;
  z-index:    -1;
  background: linear-gradient(135deg, var(--color-pinball-chrome-light) 0%, var(--color-pinball-chrome-dark) 40%, var(--color-pinball-chrome-mid) 60%, var(--color-pinball-chrome-light) 100%);
}

.card-number {
  font-family:  var(--font-display);
  font-size:    48px;
  color:        var(--color-pinball-magenta);
  opacity:      0.3;
  line-height:  1;
  margin-bottom: 16px;
}

.card-title {
  font-family:    var(--font-display);
  font-size:      18px;
  color:          var(--color-pinball-yellow);
  letter-spacing: 1px;
  margin-bottom:  12px;
}

.card-description {
  font-size:   14px;
  line-height: 1.7;
  color:       var(--color-pinball-white-dim);
  flex:        1;
}

@media (max-width: 768px) {
  .features-header { padding: 0 20px 24px; }
  .features-track { padding: 0 20px 60px; gap: 16px; }
  .pinball-card { flex: 0 0 300px; }
  .scroll-hint { padding: 12px 20px 24px; }
}
PINBALL // NEXT Components
PINBALL // NEXTUI

Button

Arcade button with primary, secondary, and ghost variants in three sizes. Magenta accent, chrome borders, uppercase Bungee labels. Renders as a Next.js Link when an href is provided.

PINBALL // NEXTUI

Badge

Arcade badge with magenta, yellow, chrome, green, and cyan variants. Bold uppercase labels on dark surfaces.

PINBALL // NEXTUI

Text

Polymorphic text component with body, caption, label, and code variants. Bungee for display, Space Grotesk for body.

PINBALL // NEXTUI

Card

Arcade card with numbered index, tag badge, title, and description. Chrome borders with parallelogram clip-path shapes.