Installation & OnboardingNext.js App Router + TypeScript
Get started with FRAME/12
Go from zero to a verified FRAME/12 storyboard sheet in five steps. Switch between the New Next.js App and Existing Project tracks below.
Scaffold Next.js and bind the three font variables
Create a fresh Next.js App Router project with TypeScript, then load the display, body, and monospace typefaces through next/font/google so fonts are self-hosted at build time.
npx create-next-app@latest my-frame12-app --typescript --app --eslintimport { Dela_Gothic_One, Zen_Kaku_Gothic_New, M_PLUS_1_Code } from 'next/font/google';
import '@/styles/frame12.css';
const displayFont = Dela_Gothic_One({ weight: '400', subsets: ['latin'], variable: '--font-f-display', display: 'swap' });
const bodyFont = Zen_Kaku_Gothic_New({ weight: ['400', '500', '700'], subsets: ['latin'], variable: '--font-f-body', display: 'swap' });
const monoFont = M_PLUS_1_Code({ weight: ['400', '500', '700'], subsets: ['latin'], variable: '--font-f-mono', display: 'swap' });
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" className={`${displayFont.variable} ${bodyFont.variable} ${monoFont.variable}`}>
<body>{children}</body>
</html>
);
}Add the registry kit
Install the complete kit (frame12.json) or pick individual components into components/frame12/ from frame12.dev (or from your local dev server at http://localhost:3000/r/frame12.json):
npx shadcn@latest add https://frame12.dev/r/frame12.jsonnpx shadcn@latest add http://localhost:3000/r/frame12.jsonImport frame12.css
Every component works standalone with frame12.css. Using Tailwind v4? Import frame12-tailwind.css for @theme token utilities:
npx shadcn@latest add https://frame12.dev/r/frame12-styles.jsonCompose your first Sheet + Scene + Panel
Number each panel sequentially in reading order starting at cut 01. Place your establishing chart in the wide left column and pair coupled KPIs across a 12px slanted gutter on the right.
'use client';
import {
Sheet,
Scene,
Panel,
PanelPair,
Metric,
ToneAreaChart,
Tag,
fmtCurrency,
} from '@/components/frame12';
export default function RecoveryPage() {
return (
<Sheet pegs motion="stepped">
<header className="f12-hd">
<div className="f12-hd-text">
<p className="f12-eyebrow">Fernwood Supply Co. <Tag>Live</Tag></p>
<h1 className="f12-title">Revenue recovery</h1>
</div>
</header>
<Scene gutter="scene" layout="split">
<Panel cut="C-01" label="Recovered revenue over time">
<Metric label="Recovered revenue" value={120054} format={fmtCurrency} big />
<ToneAreaChart
data={[
{ label: 'Oct 29', value: 3820 },
{ label: 'Oct 30', value: 4410 },
{ label: 'Oct 31', value: 5190 },
]}
seriesLabel="Recovered revenue"
labelColumnHeader="Date"
formatValue={fmtCurrency}
/>
</Panel>
<PanelPair
top={{ cut: 'C-02', label: 'Incremental profit', children: <Metric label="Incremental profit" value={38420} format={fmtCurrency} /> }}
bottom={{ cut: 'C-03', label: 'Conversion lift', children: <Metric label="Conversion lift" value={55} format={(v) => `+${Math.round(v)} bps`} /> }}
/>
</Scene>
</Sheet>
);
}Wire check-frame12.mjs and ESLint into your test script
Run node scripts/check-frame12.mjs in CI and enable eslint.frame12.mjs in your editor so hard-coded colors, illegal gutters, marker misuse, and out-of-order cut numbers are caught immediately.
node scripts/check-frame12.mjs src app// eslint.config.mjs
import frame12Rules from './skills/frame12/eslint.frame12.mjs';
export default [
...frame12Rules,
];