
Geist Learning Lab
Scaffold a Next.js App Router learning or course site with nested layouts, MDX lessons, and Geist typography patterns.
Install
npx skills add https://github.com/vercel-labs/skill-geist-learning-labs --skill geist-learning-labWhat is this skill?
- Documents a full App Router hierarchy from landing through course, module, lesson, and spaced-repetition review routes
- Shows nested layouts that add catalog chrome, progress rail, and per-course shells
- Covers Geist Sans and Geist Mono via next/font/local with CSS variables
- Targets MDX-backed lesson content inside a learn/[courseSlug]/… dynamic segment tree
- Patterns oriented toward resume banners, catalogs, and module progress on overview pages
Adoption & trust: 75 installs on skills.sh; 16 GitHub stars; 3/3 security scanners passed (skills.sh audits).
Recommended Skills
Frontend Designanthropics/skills
Vercel React Best Practicesvercel-labs/agent-skills
Remotion Best Practicesremotion-dev/skills
Vercel Composition Patternsvercel-labs/agent-skills
Develop Userscriptsxixu-me/skills
Next Best Practicesvercel-labs/next-skills
Journey fit
Primary fit
Canonical shelf is Build because the skill documents app structure, routes, and UI chrome for shipping a learning product—not discovery or launch tactics. Frontend subphase fits route hierarchies, layout nesting, fonts, and lesson shells rather than backend APIs or deploy.
Common Questions / FAQ
Is Geist Learning Lab safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.
SKILL.md
READMESKILL.md - Geist Learning Lab
# Architecture & Patterns Next.js App Router structure, MDX content system, state management, and file organization for learning apps. ## App Router Structure ### Route Hierarchy ``` app/ ├── layout.tsx → Root layout (fonts, theme, global providers) ├── page.tsx → Landing / course picker ├── learn/ │ ├── layout.tsx → Learn layout (catalog chrome) │ ├── page.tsx → Course catalog + resume banner │ └── [courseSlug]/ │ ├── layout.tsx → Course layout (progress rail sidebar) │ ├── page.tsx → Course overview (modules, progress, review queue) │ ├── review/ │ │ └── page.tsx → Spaced repetition review page │ └── [moduleSlug]/ │ ├── layout.tsx → Module layout (optional) │ ├── page.tsx → Module overview │ └── [lessonSlug]/ │ └── page.tsx → Lesson shell + content ``` ### Layout Nesting Each layout adds a layer of chrome: ```tsx // app/layout.tsx — Root: fonts, theme, global CSS import localFont from "next/font/local"; const geistSans = localFont({ src: "./fonts/GeistVF.woff", variable: "--font-sans" }); const geistMono = localFont({ src: "./fonts/GeistMonoVF.woff", variable: "--font-mono" }); export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en" className="dark"> <body className={`${geistSans.variable} ${geistMono.variable} font-sans bg-background-100 text-gray-1000 antialiased`}> {children} </body> </html> ); } ``` ```tsx // app/learn/[courseSlug]/layout.tsx — Course: sidebar + progress rail import { ProgressRail } from "@/components/learning/ProgressRail"; export default function CourseLayout({ children, params, }: { children: React.ReactNode; params: { courseSlug: string }; }) { // Load course data, modules, progress return ( <div className="flex min-h-screen"> <aside className="hidden lg:block w-64 border-r border-gray-400 bg-background-100"> <ProgressRail modules={modules} currentLesson={currentLesson} /> </aside> <main className="flex-1">{children}</main> </div> ); } ``` ## Content System: MDX ### File Structure ``` content/ ├── courses/ │ ├── binary-search/ │ │ ├── course.json → { title, description, modules: [...] } │ │ ├── basics/ │ │ │ ├── what-is-binary-search.mdx │ │ │ ├── the-algorithm.mdx │ │ │ └── edge-cases.mdx │ │ └── advanced/ │ │ ├── lower-bound.mdx │ │ └── rotated-arrays.mdx │ └── react-hooks/ │ ├── course.json │ └── ... ``` ### course.json Schema ```json { "title": "Binary Search", "description": "Master the divide-and-conquer search algorithm.", "modules": [ { "slug": "basics", "title": "Fundamentals", "lessons": [ { "slug": "what-is-binary-search", "title": "What Is Binary Search?" }, { "slug": "the-algorithm", "title": "The Algorithm" }, { "slug": "edge-cases", "title": "Edge Cases" } ] }, { "slug": "advanced", "title": "Advanced Patterns", "lessons": [ { "slug": "lower-bound", "title": "Lower Bound" }, { "slug": "rotated-arrays", "title": "Rotated Arrays" } ] } ] } ``` ### MDX Component Mapping ```tsx // lib/mdx-components.tsx import { CodePlayground } from "@/components/learning/CodePlayground"; import { QuickCheck } from "@/components/learning/QuickCheck"; import { Callout } from "@/components/learning/Callout"; import { ParameterDock } from "@/components/learning/ParameterDock"; import { CheckpointCard } from "@/components/learning/CheckpointCard"; import { GlossaryPopover } from "@/components/learning/GlossaryPopover"; import { WorkedExample } from "@/components/learning/WorkedExample"; import { BeforeAfterSplit } from "@/components/learning/BeforeAfterSplit"; import { HintLadde