Imported from kaikunnnn/bono-training (
.claude/design-system/SKILL.md). Install upstream withnpx skills add kaikunnnn/bono-training --skill design-system. Copyright stays with the author.
BONO Design System — Skill (for Claude Code)
This file is the canonical instruction set for Claude Code when adding, editing, or migrating UI in the bono-training codebase. Read this file before touching any UI.
Where this system lives
.claude/design-system/
├── SKILL.md ← you are reading this
├── INSTALL.md ← one-time setup steps
├── README.md ← human-readable overview
├── colors_and_type.css ← source of truth for tokens
├── assets/
│ ├── bono-logo.svg / .png
│ ├── favicon-dev.svg
│ └── emoji/ ← hand-drawn 3D emoji set
├── fonts/ ← LINE Seed JP (.otf, all weights)
├── preview/ ← visual reference cards (HTML, do not import)
└── ui_kits/
├── marketing-top/ ← /top page kit (Hero, GoalButtons, TrainingCards, GoalSection)
└── training/ ← lesson/training detail kit
preview/*.html are documentation only — never import them into the app.
ui_kits/*.jsx are reference code — copy into the app and adapt; do not import directly.
The single rule
All colors, type, radii, shadows, and spacing in product code must resolve to a token defined in
colors_and_type.css. No raw hex, rgb, or px values for these properties in components.
If a value you need is missing from the tokens, add it to colors_and_type.css first, then use it. Do not bypass.
Setup expectations
The host app is Next.js (App Router). The system also works for the legacy Vite/CRA app during migration. See INSTALL.md for the one-time setup. After setup the following is true:
app/globals.cssimports.claude/design-system/colors_and_type.css- LINE Seed JP is registered via
next/font/localfrom.claude/design-system/fonts/ tailwind.config.tscolor/font/radius/shadow tokens reference CSS variables (var(--text-primary), etc.) — never hexCLAUDE.mdat the repo root tells Claude Code to read this file before UI work
How to use the system
1. Pick the right token, every time
| You want… | Use this token | Tailwind class |
|---|---|---|
| App background | --bg-base |
bg-base |
| Card surface | --bg-surface |
bg-surface |
| Primary text | --text-primary |
text-text-primary |
| Muted text | --text-muted |
text-text-muted |
| Primary CTA fill | --btn-primary-bg (#102720) |
bg-btn-primary |
| Outlined CTA stroke | --text-primary |
border-text-primary |
| 見出し/タイトル font | --font-heading (M PLUS 1 / weights 500,700) |
font-heading |
| 本文 font(サイト既定) | --font-body = 既定 --font-sans (Noto Sans JP) |
font-body / font-noto-sans-jp |
| 英数字ディスプレイ font | --font-latin (system font stack, DLなし) |
font-latin |
| コード font | --font-mono (Geist Mono) |
font-mono |
| Card radius (md) | --radius-md (32px) |
rounded-md-card |
| Card radius (xl) | --radius-xl (64px) |
rounded-xl-card |
| Button radius | --radius-btn (14px) |
rounded-btn |
| Pill (goal buttons) | --radius-pill (200px) |
rounded-pill |
(See colors_and_type.css for the full list.)
フォントの正規ロール(4種)— これ以外を新規で増やさない
| ロール | フォント | 使うクラス | ロードウェイト |
|---|---|---|---|
| 見出し・タイトル | M PLUS 1 | font-heading |
500, 700 |
| 本文(=サイト既定) | Noto Sans JP | font-body(既定 font-sans) |
400, 500, 700 |
| 英数字ディスプレイ | system font stack(DLなし・最速) | font-latin |
— |
| コード | Geist Mono | font-mono |
— |
- 既定(クラス未指定)は本文= Noto Sans JP。日本語は原則 Noto、見出しだけ M PLUS 1。
- 非推奨エイリアス(後方互換で残置、順次
font-heading/font-latinへ移行し最終的に削除):font-rounded-mplus→見出し /font-inter・font-hind・font-geist→英数字。名前が実体と異なるので新規では使わない。 - LINE Seed JP(
font-line-seed-jp)は workshop / docs 専用のブランド字体。トップや汎用UIでは使わない。 - 実ロード定義は
src/app/layout.tsx(next/font)とsrc/app/globals.css(@themeトークン)。このロール表と一致させること。
2. Look at the kit before writing new UI
For information-structure patterns (focused flows, flow shells, cards, empty states, permission gates), read patterns.md in this directory first.
Before writing a hero, CTA, card, badge, or section header from scratch, check:
ui_kits/marketing-top/index.htmlfor/top-style marketing surfacesui_kits/training/for training/lesson surfacespreview/buttons.html,preview/cards.html,preview/badges.htmlfor atom-level reference
If a matching pattern exists, copy it and adapt. Do not invent a new variant.
3. Canonical button shapes (committed to memory)
| Variant | Height | Radius | Fill | Text |
|---|---|---|---|---|
| Primary CTA (large) | h-14 (56px) |
rounded-[14px] |
#102720 |
#fff |
| Primary CTA (small) | h-12 (48px) |
rounded-[14px] |
#081C17 |
#fff |
| Secondary outlined | h-14 |
rounded-[14px] |
transparent | #0F172A + border-2 |
| On-dark primary | h-12 |
rounded-[14px] |
#fff |
#081C17 |
| On-dark secondary | h-12 |
rounded-[14px] |
transparent | #fff + inset 0 0 0 1px #fff |
| Goal button (pill) | h-[117px] |
rounded-[200px] |
bg-surface |
per content |
The legacy rounded-full PrimaryButton component is deprecated — do not propagate it.
4. Canonical card radii
- Outer marketing cards (Goal Section):
rounded-[64px]lg /48pxsm /32pxmobile - Goal-section content blocks (
bg-[rgba(70,87,83,0.04)]):rounded-[40px]/32px/24px - Training cards:
rounded-[32px]lg /28pxmobile - RoadmapCardV2 outer:
rounded-[64px]lg with 2.5px white padding ring - Inner thumbnail in roadmap card:
rounded-[30px]lg /22pxmd /16pxsm - Standard content surfaces (article, lesson):
rounded-[20px]
5. Roadmap gradients (use the preset, never improvise)
There are 5 canonical roadmap gradients in colors_and_type.css (--gradient-roadmap-*). Each maps to a slug:
| Slug | Token |
|---|---|
uiux-career-change |
--gradient-roadmap-career |
ui-beginner |
--gradient-roadmap-ui-beginner |
ui-visual |
--gradient-roadmap-ui-visual |
information-architecture |
--gradient-roadmap-info-arch |
ux-design-basic |
--gradient-roadmap-ux-design |
When rendering a roadmap detail hero or card with variant="gradient", resolve the gradient by slug. Never hard-code a gradient inline.
6. Iconography
- Hand-drawn 3D emoji live in
assets/emoji/. They are PNG-baked SVGs (one per file). Always use them via a path, never inline base64 in components. - Goal buttons use Fluent 3D emoji at
/images/goal-buttons/*_3d.png. Match thegoalFluentIconsmapping. - Lucide icons are allowed for utility (chevrons, checkmarks, close). Stroke width
2.5for primary CTAs.
Next.js-specific rules
Server vs Client Components
UI kit files in ui_kits/ are written as plain JSX. When copying into the app:
- Server Component (default): static marketing UI (Hero copy, GoalSection layout, training card chrome). Strip any
useState/useEffect/motion.*and convert to plain elements. - Client Component (
'use client'): anything with state, scroll listeners, framer-motion, click handlers that don't navigate, orlocalStorage. The TopPageNew Hero's intro animation belongs here — split it into a small Client wrapper around an otherwise-Server tree.
Pattern: keep the page Server, push interactivity to the smallest leaf Client component.
Imports & assets
| Concern | Use |
|---|---|
<a href="..."> internal |
import Link from 'next/link' |
<img src="..."> |
import Image from 'next/image' (always pass alt, width, height or fill) |
| Local fonts | next/font/local from .claude/design-system/fonts/. Do not add a @font-face block in CSS. |
| Google Fonts | next/font/google for M PLUS 1(見出し / 500,700), Noto Sans JP(本文 / 400,500,700), Geist Mono(コード)。英数字ディスプレイは system font stack(font-latin, DLなし)。新規フォントを増やさない。 |
| Sanity fetches | Server Components with client.fetch(...). No useRoadmaps/useLessons hooks in Server trees. |
react-router <Link> |
Replace with next/link <Link>. The to= prop becomes href=. |
Tailwind config
Tailwind v4 (current — @theme inline in globals.css)
/* good — reference the design-system variable */
@theme inline {
--color-text-primary: var(--text-primary);
}
/* bad — hard-coded hex bypasses the design system */
@theme inline {
--color-text-primary: #021710;
}
Tailwind v3 (legacy — tailwind.config.ts)
// good
colors: { 'text-primary': 'var(--text-primary)' }
// bad
colors: { 'text-primary': '#021710' }
This keeps the design system as the single source of truth and lets us flip themes later.
Workflow for Claude Code
When asked to build or migrate a screen:
- Read this file (
.claude/design-system/SKILL.md) andINSTALL.mdif setup is unclear. - Open the relevant UI kit (
ui_kits/marketing-top/index.htmlorui_kits/training/). Identify the closest existing pattern. - Open the relevant preview cards to confirm token usage (e.g.
preview/buttons.htmlbefore placing a CTA). - Decide Server vs Client for each component you produce.
- Write the component using token-backed Tailwind classes only. No raw hex/rgb/px for color/type/radius/shadow.
- If a token is missing, add it to
colors_and_type.css(and totailwind.config.tsif it needs a Tailwind alias), then use it. - Self-check:
- No raw hex/rgb in JSX (
grep -nE '#[0-9a-f]{3,8}|rgb\(' src/**/*.{tsx,ts,css}should return nothing new) - No
react-routerimports left in migrated files - No
<img>for static assets — usenext/image - Buttons match the canonical shape table above
- Radii match the canonical card radii table above
- No raw hex/rgb in JSX (
Updating the design system
The system itself can be edited directly via Claude Code. Rules:
- Adding a token: edit
colors_and_type.css→ add totailwind.config.tsif needed → update or add apreview/*.htmlcard → update the table in this file. - Adding a UI kit pattern: add to
ui_kits/<kit>/with a sibling note in the kit's README. Reference it from this file's "kit before writing" section. - Deprecating a pattern: mark it
@deprecatedin the kit file with a one-line replacement note. Do not delete immediately — give consumers a migration window. - Versioning: bump the version line at the top of
README.md. Use semver: minor for additions, major for breaking token renames. - Commits: prefix with
ds:(e.g.ds: add danger-strong color token). PR description must list affected tokens and a screenshot of the updated preview card.
Anti-patterns (do not do these)
- Inline
style={{ color: '#021710' }}— use the token. bg-[#102720]Tailwind arbitrary values when a token exists — usebg-btn-primary.- Importing from
ui_kits/directly — copy into the app instead. - Adding a new gradient inline on a roadmap card — extend
--gradient-roadmap-*and reference by slug. - Inventing a 7th button shape — extend the table in §3 above and add a preview.
- Using
react-routerLinkin any migrated file —next/linkonly. - Using emoji as text glyphs (e.g.
🎯) when the design calls for hand-drawn 3D — use the asset fromassets/emoji/or/images/goal-buttons/*. - Hardcoding LINE Seed JP via
@font-facein app code — usenext/font/localonce, inapp/fonts.ts.
Quick reference — common tasks
"Add a new marketing CTA"
→ preview/buttons.html → primary or secondary → copy class names → token-backed.
"Build a new training detail page"
→ ui_kits/training/ → identify which sections you need → Server Component shell, Client islands for tabs/accordions.
"Add a new roadmap"
→ Pick or add a --gradient-roadmap-* → wire slug → use RoadmapCardV2 with variant="gradient".
"Gate content behind login/membership"
→ Don't hand-write a Lock icon + Card. For a preview-cutoff (text continues below a "become a member" CTA), use src/components/premium/ContentPreviewOverlay (isLoggedIn, redirectTo props) — used in articles/[slug], stories/[slug], questions/[slug]. For video, use src/components/premium/PremiumVideoLock. Both are Client Components fed isLoggedIn/hasMemberAccess from a Server Component via getSubscriptionStatus().
"Theme tweak (color shift)"
→ Edit colors_and_type.css only. No code changes elsewhere should be required. If they are, the consumer was bypassing the system — fix that consumer.