---
name: falkster-design-system
description: The design system every prototype on falkster.com is built on. Drop this into Claude (as a SKILL.md, a system prompt, or a chat paste) and every prototype Claude builds will match the site's look, feel, and voice.
version: 1.0.0
owner: Falk Gottlob
site: https://falkster.com
updated: 2026-04-20
---

# Falkster Design System, for Claude

This file is the source of truth for every prototype you build in my style. It's
the tokens, components, and copy rules the site itself runs on. Use it any time
I ask for a prototype, landing page, feature page, or internal tool that should
look like it belongs on falkster.com.

There are three ways to plug this into Claude.

## How to use

### Mode 1, paste into Claude chat

Paste this whole file at the start of a conversation, then say:

> Build a `{page | feature | prototype}` that does `{…}`, using the falkster
> design system above. Next.js 16, Tailwind v4, TypeScript. Output the full
> file(s) only, no commentary.

### Mode 2, Claude Code skill

Save this file at `.claude/skills/falkster-design-system/SKILL.md` in any repo.
Claude Code will load it automatically when it sees words like "prototype",
"landing page", "style the…", etc. Then just prompt:

```
/skill falkster-design-system
Build a pricing page for a PM automation tool.
```

### Mode 3, API system prompt

Use the **Compact preamble** at the bottom of this file as a system prompt for
API calls. It's ~400 tokens and covers 90% of cases. Expand from the full spec
if the output drifts.

---

## The voice rules (these come first)

Before any code, match the voice. Every prototype ships with copy, not lorem.

- **First person.** "My practice", "I've found", not "our users" or "we".
- **No em dashes (, ).** Ever. Use commas, periods, or "and".
- **Short sentences.** One idea per sentence. No throat-clearing.
- **No AI tells.** Banned words: *genuinely, furthermore, it's worth noting,
  fundamentally, consequential, leverage* (as a verb), *unlock, delve, nuanced,
  robust, streamline.*
- **Concrete over abstract.** Name a real tool, a real number, a real moment.
- **End with action.** "Pick one thing this week." "Try it tomorrow."
- **Credit sources** when you borrow a concept (Torres, Cagan, Reforge).

If you're writing a button label, use a verb: "Ship it", "See the eval", "Open
the lab". Never "Learn More" or "Click Here".

---

## Tech stack (assume unless told otherwise)

- **Next.js 16** App Router, React 19, TypeScript strict mode
- **Tailwind CSS v4** with CSS-first `@theme` config (not `tailwind.config.js`)
- **Fonts** loaded via Google Fonts in `globals.css`: Inter (body), DM Sans
  (display), JetBrains Mono (captions/code), Source Serif 4 (prose)
- **Icons** `lucide-react`
- **No component libraries.** No shadcn, no Radix. Tailwind utilities only.
- **Deployment** Railway, Nixpacks builder

---

## Design tokens

Copy this `@theme` block straight into `globals.css` under `@import "tailwindcss";`.
These are the *real* values the site runs on, current as of the last update.

```css
@import url('https://fonts.googleapis.com/css2?family=DM+Sans:opsz,wght@9..40,400;9..40,500;9..40,600;9..40,700&family=Inter:wght@400;500;600;700&family=Source+Serif+4:opsz,wght@8..60,400;8..60,500;8..60,600;8..60,700&family=JetBrains+Mono:wght@400&display=swap');
@import "tailwindcss";

@theme {
  /* Surfaces, cool moonlit navy */
  --color-bg:           #0a0e1a;
  --color-bg-elevated:  #12182b;
  --color-bg-card:      #1c2337;
  --color-bg-hover:     #272f44;
  --color-border:       #2d3548;
  --color-border-bright:#3a4760;

  /* Text, cool whites */
  --color-text:         #e6ecf4;
  --color-text-muted:   #9eafc7;
  --color-text-dim:     #6b7a94;

  /* Primary accent, vivid sky */
  --color-accent:        #38bdf8;  /* sky-400 */
  --color-accent-bright: #7dd3fc;  /* sky-300 */
  --color-accent-glow:   rgba(56, 189, 248, 0.28);

  /* Category accents, cool, saturated, each carries clear identity */
  --color-neon-cyan:   #22d3ee;   /* cyan-400  · methodology, analytics  */
  --color-neon-green:  #34d399;   /* emerald-400 · AI agents, go, signals */
  --color-neon-pink:   #e879f9;   /* fuchsia-400 · foundation, alerts     */
  --color-neon-orange: #818cf8;   /* indigo-400  · leadership, execution  */

  /* Typography */
  --font-sans:    "Inter", "Google Sans Text", "Roboto", ui-sans-serif, system-ui, sans-serif;
  --font-display: "DM Sans", "Google Sans Display", "Google Sans", "Inter", system-ui, sans-serif;
  --font-serif:   "Source Serif 4", Georgia, "Times New Roman", serif;
  --font-mono:    "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* Base body */
body {
  background-color: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: 17px;
  line-height: 1.6;
  letter-spacing: -0.003em;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  letter-spacing: -0.018em;
  font-weight: 600;
}
h1 { line-height: 1.05; }
h2 { line-height: 1.15; }
h3 { line-height: 1.25; }

/* Gradient display text */
.gradient-text {
  background: linear-gradient(120deg, #38bdf8 0%, #22d3ee 45%, #e879f9 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* Accent glow for primary CTAs */
.glow-accent {
  box-shadow:
    0 0 0 1px rgba(56, 189, 248, 0.40),
    0 10px 34px -6px rgba(56, 189, 248, 0.55),
    0 0 24px -4px rgba(34, 211, 238, 0.35);
}
```

### Color semantics (which token to use when)

| Token | Hex | Use for |
|---|---|---|
| `bg` | `#0a0e1a` | Page background, root |
| `bg-elevated` | `#12182b` | Nav bar, sticky headers, footer |
| `bg-card` | `#1c2337` | Cards, panels, pre/code blocks |
| `bg-hover` | `#272f44` | Hover state on cards and list rows |
| `border` | `#2d3548` | Default dividers, card outlines |
| `border-bright` | `#3a4760` | Hover border, focused outline |
| `text` | `#e6ecf4` | Headings, primary body |
| `text-muted` | `#9eafc7` | Secondary body, descriptions |
| `text-dim` | `#6b7a94` | Captions, timestamps, metadata |
| `accent` | `#38bdf8` | Primary CTA fill, links, active state |
| `accent-bright` | `#7dd3fc` | Hover on accent, link hover |
| `neon-cyan` | `#22d3ee` | Methodology, analytics, "passing" |
| `neon-green` | `#34d399` | AI agents, shipped, "go", signals |
| `neon-pink` | `#e879f9` | Foundation chapters, alerts, high-intensity |
| `neon-orange` | `#818cf8` | Leadership, execution, warning |

### Typography scale

| Role | Classes |
|---|---|
| Display XL (hero) | `text-5xl md:text-7xl font-bold tracking-tight leading-[1.05]` |
| Display L (section hero) | `text-4xl md:text-5xl font-bold tracking-tight leading-tight` |
| Heading 2 | `text-3xl font-bold tracking-tight` |
| Heading 3 | `text-2xl font-semibold` |
| Heading 4 | `text-xl font-semibold` |
| Body large | `text-lg text-text-muted leading-relaxed` |
| Body | `text-base text-text-muted leading-relaxed` |
| Small | `text-sm text-text-dim` |
| Mono caption | `text-[11px] font-mono text-neon-cyan uppercase tracking-wider` |

### Spacing

Tailwind default scale, 4px base. Common steps: `p-2 p-3 p-4 p-5 p-6 p-8 p-10
p-12 p-16 p-24`. Section vertical padding: `py-12 md:py-16` for normal, `py-20
md:py-28` for heroes.

### Radii

`rounded-md` (6px) small controls. `rounded-lg` (8px) buttons, inputs, pills.
`rounded-xl` (12px) cards. `rounded-2xl` (16px) hero panels. `rounded-full`
ticker pills and avatars.

---

## Component patterns (copy-paste ready)

### Primary button

```tsx
<button className="px-5 py-2.5 rounded-lg bg-accent hover:bg-accent-bright text-white font-medium text-sm transition-colors glow-accent">
  Ship it
</button>
```

### Secondary button

```tsx
<button className="px-5 py-2.5 rounded-lg border border-border hover:border-accent text-text hover:text-accent-bright font-medium text-sm transition-all">
  See the eval
</button>
```

### Tinted action buttons (go / warning / destructive)

```tsx
<button className="px-5 py-2.5 rounded-lg bg-neon-green/10 border border-neon-green/30 text-neon-green hover:bg-neon-green/20 font-medium text-sm transition-colors">
  Run the agent
</button>

<button className="px-5 py-2.5 rounded-lg bg-neon-orange/10 border border-neon-orange/30 text-neon-orange hover:bg-neon-orange/20 font-medium text-sm transition-colors">
  Needs review
</button>

<button className="px-5 py-2.5 rounded-lg bg-neon-pink/10 border border-neon-pink/30 text-neon-pink hover:bg-neon-pink/20 font-medium text-sm transition-colors">
  Kill it
</button>
```

### Status pill / badge

```tsx
<span className="inline-flex items-center gap-1.5 px-2.5 py-1 text-[11px] font-mono uppercase tracking-wider rounded-md border border-neon-green/30 bg-neon-green/5 text-neon-green">
  <span className="w-1.5 h-1.5 rounded-full bg-current" />
  Shipped
</span>
```

Swap `neon-green` for any accent: `neon-cyan` (eval passing), `neon-orange`
(needs review), `neon-pink` (blocked), `accent` (active).

### Section eyebrow (mono caption)

```tsx
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full border border-accent/30 bg-accent/5 text-[11px] font-mono uppercase tracking-wider text-accent-bright">
  <span className="w-1.5 h-1.5 rounded-full bg-accent-bright" />
  Section 01 · Public
</div>
```

### Default card

```tsx
<div className="rounded-xl border border-border bg-bg-card p-5 hover:border-border-bright transition-colors">
  <div className="text-xs font-mono text-accent-bright uppercase tracking-wider mb-2">
    Default
  </div>
  <h4 className="font-semibold text-text mb-2">Card title goes here</h4>
  <p className="text-sm text-text-dim">
    Neutral background, subtle border, the default container.
  </p>
</div>
```

### Accent card (pulls attention)

```tsx
<div className="rounded-xl border border-neon-green/30 bg-neon-green/5 p-5 hover:bg-neon-green/10 transition-colors">
  <div className="text-xs font-mono text-neon-green uppercase tracking-wider mb-2">
    Accent · go
  </div>
  <h4 className="font-semibold text-text mb-2">Accent card</h4>
  <p className="text-sm text-text-dim">
    Use when the card should signal forward motion.
  </p>
</div>
```

### Input (text)

```tsx
<input
  type="text"
  placeholder="The signal you saw today"
  className="w-full px-4 py-3 rounded-lg bg-bg-card border border-border text-text placeholder:text-text-dim focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/20 transition-all"
/>
```

### Inline code + code block

```tsx
<p className="text-sm text-text-muted">
  Reference a token like{" "}
  <code className="px-1.5 py-0.5 rounded bg-bg-card border border-border font-mono text-xs text-accent-bright">
    text-accent-bright
  </code>
  .
</p>

<pre className="rounded-lg border border-border bg-bg-card p-4 text-xs font-mono text-text-muted overflow-auto">
  <code>{`const eval = loadEval('./evals/onboarding.md');
const score = await run(eval, 'claude-sonnet-4-6');
if (score < 0.82) throw new Error('blocked');`}</code>
</pre>
```

### Link (inline)

```tsx
<a className="text-accent-bright underline decoration-1 underline-offset-[3px] hover:text-neon-cyan transition-colors">
  read the handbook
</a>
```

---

## Layout templates

### Page shell

```tsx
export default function Page() {
  return (
    <div className="min-h-screen bg-bg">
      <div className="max-w-5xl mx-auto px-6 py-12 md:py-16">
        {/* content */}
      </div>
    </div>
  );
}
```

Use `max-w-5xl` for prose-ish pages, `max-w-6xl` for dashboards with side rails,
`max-w-7xl` for full tool shells.

### Hero section

```tsx
<section className="pt-16 pb-12 md:pt-24 md:pb-20">
  <div className="inline-flex items-center gap-2 px-3 py-1 rounded-full border border-neon-green/30 bg-neon-green/5 text-[11px] font-mono uppercase tracking-wider text-neon-green mb-6">
    <span className="w-1.5 h-1.5 rounded-full bg-neon-green animate-pulse" />
    Live · 133,562 builders
  </div>
  <h1 className="text-5xl md:text-7xl font-bold tracking-tight leading-[1.05] mb-6">
    Ship the prototype to the customer{" "}
    <span className="gradient-text">before engineering scales it</span>
  </h1>
  <p className="text-lg md:text-xl text-text-muted leading-relaxed max-w-2xl">
    A signal arrived this morning. I shipped a working prototype by lunch. This
    is how builders run now.
  </p>
  <div className="mt-8 flex gap-3">
    <button className="px-5 py-2.5 rounded-lg bg-accent hover:bg-accent-bright text-white font-medium text-sm transition-colors glow-accent">
      See the handbook
    </button>
    <button className="px-5 py-2.5 rounded-lg border border-border hover:border-accent text-text hover:text-accent-bright font-medium text-sm transition-all">
      Open the lab
    </button>
  </div>
</section>
```

### Card grid

```tsx
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
  {items.map((item) => (
    <div key={item.id} className="rounded-xl border border-border bg-bg-card p-5 hover:border-border-bright transition-colors">
      <div className="text-xs font-mono text-accent-bright uppercase tracking-wider mb-2">
        {item.category}
      </div>
      <h4 className="font-semibold text-text mb-2">{item.title}</h4>
      <p className="text-sm text-text-dim">{item.description}</p>
    </div>
  ))}
</div>
```

### Two-column with sticky side rail

```tsx
<div className="grid grid-cols-1 lg:grid-cols-[1fr_320px] gap-10">
  <main>{/* primary content */}</main>
  <aside className="lg:sticky lg:top-24 lg:self-start space-y-4">
    {/* related links, articles */}
  </aside>
</div>
```

### Section with eyebrow + title + subtitle

```tsx
<section className="mb-16">
  <div className="mb-6 pb-4 border-b border-border/50">
    <div className="text-xs font-mono uppercase tracking-wider text-neon-cyan mb-2">
      02 · Methodology
    </div>
    <h2 className="text-3xl font-bold tracking-tight text-text mb-1">
      The signal-to-prototype loop
    </h2>
    <p className="text-sm text-text-dim">
      How I go from noticed signal to shipped prototype in under an hour.
    </p>
  </div>
  {/* content */}
</section>
```

---

## Motion patterns

### Scroll reveal (fade + slide up)

Add `data-reveal` to any element. CSS in `globals.css` handles the transition.
Set `html.js-reveal` from a `<ScrollReveal />` island client component.

```tsx
<div data-reveal className="transition-all">
  I fade up when I enter the viewport.
</div>
```

### Live color-cycling pill (shipped events)

```tsx
<div className="live-pill inline-flex items-center gap-2 px-3 py-1 rounded-full border text-[11px] font-mono uppercase tracking-wider">
  <span className="live-dot w-1.5 h-1.5 rounded-full" />
  Live · shipping now
</div>
```

`.live-pill` and `.live-dot` are defined in the `globals.css` block above, they
cycle through the four neon colors on an 8s loop.

### AI border (comet-of-light on hover)

Wrap anything in `.ai-border` to get a Gemini-style traveling light streak on
hover. The CSS is in the globals block.

```tsx
<div className="ai-border rounded-[22px] bg-bg-card p-6">
  Hover me.
</div>
```

### Horizontal ticker / marquee

Duplicate content twice, use the `.ticker-marquee` class, set duration inline.

```tsx
<div className="relative overflow-hidden">
  <div className="ticker-marquee flex gap-8 whitespace-nowrap" style={{ animationDuration: "40s" }}>
    {items.concat(items).map((item, i) => (
      <span key={i} className="text-sm text-text-dim">{item}</span>
    ))}
  </div>
</div>
```

---

## File structure for a new prototype

When I ask for a prototype, create this shape:

```
src/app/{slug}/
├── page.tsx          # server component, exports metadata, returns <Client />
├── {Slug}Client.tsx  # client component with the actual UI
└── (optional files)
```

`page.tsx` template:

```tsx
import type { Metadata } from "next";
import SlugClient from "./SlugClient";

export const metadata: Metadata = {
  title: "The Page | Falkster",
  description: "What this prototype does, in one sentence.",
  alternates: { canonical: "https://falkster.com/slug" },
  openGraph: { title: "The Page | Falkster", description: "…", type: "website" },
};

export default function Page() {
  return <SlugClient />;
}
```

Always include canonical URL and OG metadata, the site is SEO/GEO optimized.

---

## Copy patterns (not just words, structure)

### Hero headline formula

`[action verb] the [noun] [constraint], [contrast clause]`

Good examples from the site:

- "Ship the prototype to the customer before engineering scales it."
- "Kill the roadmap. Build the loop."
- "The eval is the spec."

Bad:

- "Accelerate your product velocity with AI." (vague verb, buzzwords)
- "Empowering PMs to leverage AI." (AI-smell, no stakes)

### Card title + desc formula

Title = 3–6 words, imperative or declarative. Description = one sentence, no
fluff, ends with a period.

- "Kill the status meeting. Replace the ritual with a Loom and a KPI."
- "Your first OST. Pick the outcome you care about. The tree writes itself."

### CTA verbs

Always active. "Ship", "Run", "Open", "See", "Read", "Watch", "Try", "Fork".
Never "Learn more", "Get started", "Discover".

---

## Do / don't

**Do**

- Use `text-text-muted` for body copy by default, not `text-text`. The muted
  cool-blue reads better on the navy than bright white.
- Put the eyebrow (mono uppercase caption) above every section title.
- End every landing page with a clear next action (enter the lab, read the
  handbook, etc).
- Use `neon-green` sparingly, it's for moments of success / signal, not
  decoration.

**Don't**

- Don't use shadcn, Radix, or any component library. Tailwind utilities only.
- Don't use purple. The old theme used purple, the new theme is sky-navy.
  Any `#7c5cff` or `#9d82ff` you see in old screenshots is wrong.
- Don't write "Learn More" on a button. Replace with a verb.
- Don't use em dashes. Ever. Commas, periods, "and".
- Don't center body copy. Left-align prose, only center hero headlines and
  status indicators.
- Don't use drop shadows. Use borders and the `.glow-accent` utility only.

---

## Example prompt (start-to-finish)

Here's what a good prompt looks like once you've loaded this file:

> Build a "Prototype Review Checklist" page at `/prototype/review`.
>
> Three sections:
> 1. Hero: eyebrow "prototype · review", headline "Before I ship to the
>    customer", one-sentence intro in first person.
> 2. Checklist: 8 items across 3 groups (Signal, Build, Ship). Each item is a
>    card with a checkbox, a title, and a one-sentence description.
> 3. Footer CTA: "Open the lab" link to `/prototype/lab`.
>
> Use the design system above. No external libraries beyond `lucide-react`.
> Output `src/app/prototype/review/page.tsx` and
> `src/app/prototype/review/ReviewClient.tsx`.

---

## Compact preamble (~400 tokens, use as a system prompt)

```
You are building a prototype on falkster.com. Match this design system exactly.

Stack: Next.js 16 App Router, React 19, TypeScript strict, Tailwind v4 (CSS-first
@theme, no tailwind.config.js), lucide-react icons. No shadcn, no Radix.

Colors (Tailwind tokens → hex):
bg=#0a0e1a bg-elevated=#12182b bg-card=#1c2337 bg-hover=#272f44
border=#2d3548 border-bright=#3a4760
text=#e6ecf4 text-muted=#9eafc7 text-dim=#6b7a94
accent=#38bdf8 accent-bright=#7dd3fc
neon-cyan=#22d3ee neon-green=#34d399 neon-pink=#e879f9 neon-orange=#818cf8

Fonts: Inter (body), DM Sans (h1-h4 via font-display), JetBrains Mono (captions
and code). Body 17px, line-height 1.6.

Patterns:
- Page: <div class="min-h-screen bg-bg"><div class="max-w-5xl mx-auto px-6 py-12 md:py-16">…
- Eyebrow: px-3 py-1 rounded-full border border-accent/30 bg-accent/5 text-[11px] font-mono uppercase tracking-wider text-accent-bright
- Hero h1: text-5xl md:text-7xl font-bold tracking-tight leading-[1.05]
- Primary btn: px-5 py-2.5 rounded-lg bg-accent hover:bg-accent-bright text-white font-medium text-sm transition-colors
- Secondary btn: px-5 py-2.5 rounded-lg border border-border hover:border-accent text-text hover:text-accent-bright
- Card: rounded-xl border border-border bg-bg-card p-5 hover:border-border-bright
- Pill: inline-flex items-center gap-1.5 px-2.5 py-1 text-[11px] font-mono uppercase tracking-wider rounded-md border border-{color}/30 bg-{color}/5 text-{color}
- Body copy: text-text-muted (not text-text)

Voice: first person, short sentences, no em dashes, no "genuinely /
fundamentally / leverage / unlock", verbs on CTAs ("Ship it", not "Learn
more"), end with an action.

Always export metadata (title, description, canonical) from page.tsx. Put UI
in a client component. Output only full file contents, no commentary.
```
