Use this skill when the user wants to create, draft, author, or extract a slide theme in this open-slide repo. Triggers on phrases like "create a theme", "make a theme called X", "extract a theme from <slide>", "build a theme from these images". Produces two paired files under `themes/` — `<id>.md` (palette, typography, layout, fixed Title/Footer components, motion) and `<id>.demo.tsx` (a runnable demo slide that the dev-UI Themes panel previews). Do NOT use for editing real slides — only for authoring the theme bundle.
74
92%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
This skill produces a theme bundle under themes/: two paired files that together describe a reusable visual identity.
themes/<id>.md — agent-facing documentation: palette, typography, layout, fixed Title/Footer/Eyebrow components, motion. This is what create-slide reads when an author picks the theme.themes/<id>.demo.tsx — a runnable mini-slide (a normal slide module: export default Page[]) that demonstrates the theme on 2–3 pages. The dev UI's Themes panel loads this file and renders it as the theme's live preview.Both files share the same stem so the runtime can pair them automatically.
A theme is distinct from a slide's design const. The theme markdown is authoring-time aesthetic direction (copied into a real slide's source by create-slide). The demo .tsx is a self-contained preview, not a real slide — it does not appear in the slides list. A per-slide const design: DesignSystem = { … } (declared at the top of slides/<id>/index.tsx) is the runtime tokens object the user can tweak from the Design panel. The markdown commits the direction; the per-slide design const makes the slide tweakable; the demo .tsx makes the theme previewable.
You only write files under themes/<id>.md and themes/<id>.demo.tsx. Never modify real slides or other configuration. The canvas / type-scale defaults that themes can override live in the slide-authoring skill — read it before writing the theme so your overrides are stated explicitly.
A theme can be derived from any combination of three input shapes:
slides/<id>/index.tsx whose visual identity should be lifted out into a reusable theme.If the user's original message already specifies the inputs unambiguously, skip the question and proceed. Otherwise call AskUserQuestion (multi-select) so they can pick one or more sources, and ask follow-ups (paths, slide id, prose) only as needed.
Read tool (it accepts images). Note dominant colors as hex, type weight/style, layout rhythm, decorative motifs, and any recurring chrome (header bar, footer line, page numbers).slides/<id>/index.tsx and pull:
design.palette object (or a legacy top-of-file palette const) → Palette section.design.fonts / font constants and any font-size patterns → Typography section.@keyframes blocks and the shared styles string → Motion section.When inputs disagree (e.g. images use blue but the description says green), ask the user which to honor.
Use kebab-case, short, descriptive. Examples: editorial-noir, brutalist-mono, pastel-soft, dev-terminal. Check themes/ to avoid collisions.
themes/<id>.mdProduce a file with this exact section order. Section bodies adapt to the theme; the headings stay consistent across all themes.
---
name: <Human title, e.g. "Editorial Noir">
description: <one-line elevator pitch>
mode: <dark | light — whichever matches the palette's bg>
---
# <Theme name>
## Palette
| Role | Value | Notes |
| ------ | --------- | ------------------------------ |
| bg | `#0f172a` | page background |
| text | `#f8fafc` | primary copy |
| accent | `#fbbf24` | callouts, eyebrow, key numbers |
| muted | `#94a3b8` | secondary copy, dividers |
| ... | ... | extend as the theme requires |
## Typography
- Display font: `<stack>` — weight 800–900 for headlines.
- Body font: `<stack>` — weight 400–500.
- Webfont import (omit for system stacks): `<stylesheet URL>` — see `references/webfonts.md` in `slide-authoring` for loading rules.
- Type-scale overrides (only list what differs from `slide-authoring` defaults):
- Hero title: 180 px (default 140–200 ✓)
- Body text: 36 px
## Layout
- Content padding: 120 px from canvas edges (1920 × 1080).
- Alignment: left-aligned, single column.
- Grid notes: optional 12-column overlay at 80 px gutter for content pages.
## Fixed components
These are paste-ready. Copy them verbatim into a slide that uses this theme.
### Title
```tsx
const Title = ({ children }: { children: React.ReactNode }) => (
<h1
style={{
fontSize: 140,
fontWeight: 900,
lineHeight: 1.05,
letterSpacing: '-0.02em',
margin: 0,
color: '#f8fafc',
}}
>
{children}
</h1>
);
```
### Footer
Pull the page number from `useSlidePageNumber()` — never hardcode `pageNum` / `total` props.
```tsx
import { useSlidePageNumber } from '@open-slide/core';
const Footer = () => {
const { current, total } = useSlidePageNumber();
return (
<div
style={{
position: 'absolute',
left: 120,
right: 120,
bottom: 60,
display: 'flex',
justifyContent: 'space-between',
fontSize: 24,
color: '#94a3b8',
}}
>
<span>EDITORIAL NOIR · 2026</span>
<span>{current} / {total}</span>
</div>
);
};
```
### Eyebrow / accents (optional)
```tsx
const Eyebrow = ({ children }: { children: React.ReactNode }) => (
<div style={{ fontSize: 26, letterSpacing: '0.2em', color: '#fbbf24' }}>
{children}
</div>
);
```
## Motion
- Philosophy: static / subtle / rich — pick one and explain in one sentence.
- Reusable keyframes (paste-ready, only if the philosophy is subtle or rich):
```css
@keyframes fadeUp {
from { opacity: 0; transform: translateY(24px); }
to { opacity: 1; transform: translateY(0); }
}
```
## Aesthetic
One paragraph. What it feels like, the references it draws on, what to avoid (e.g. "no rounded corners; no gradients; no decorative emoji"). Commit to a single direction — minimal, maximalist, editorial, retro, brutalist, soft/pastel, neon, paper/print.
## Example usage
```tsx
const Cover: Page = () => (
<div style={{ width: '100%', height: '100%', background: '#0f172a', color: '#f8fafc', padding: 120, display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
<Eyebrow>CHAPTER 01</Eyebrow>
<Title>The Big Idea</Title>
<p style={{ fontSize: 36, color: '#94a3b8', maxWidth: 1200, marginTop: 32 }}>
A short subtitle that explains what this slide is about.
</p>
<Footer />
</div>
);
```themes/<id>.demo.tsxThe demo is a normal slide module — same shape as slides/<id>/index.tsx, just sitting under themes/ so the runtime knows it's preview-only. The dev-UI Themes panel imports it and renders it inside SlideCanvas (1920×1080).
Contract:
import { type Page, useSlidePageNumber } from '@open-slide/core';Title, Footer, Eyebrow components defined in the theme markdown — verbatim, no abstractions, no imports from elsewhere. The demo and the markdown must stay in lockstep so what the user sees in the panel matches what create-slide will paste into a real slide.Page components and a default array. Aim for: a Cover (Eyebrow + Title + subtitle), one Content page exercising body type + accent, and a Closer or "End" card. The "Example usage" block at the bottom of the markdown is a good starting point — extend it.export const design: DesignSystem = {...} (add import type { DesignSystem } from '@open-slide/core'; alongside the base import).import from @/, no slides-only helpers (e.g. WindowShell from a real slide). Webfont stylesheet @imports inside an inline <style> are fine here — a deliberate exception to webfonts.md's loader rules, since the demo only mounts in the Themes panel. Demo files must be self-contained.Skeleton:
import { type Page, useSlidePageNumber } from '@open-slide/core';
const Title = ({ children }: { children: React.ReactNode }) => (
// …same JSX as in themes/<id>.md
);
const Footer = () => {
const { current, total } = useSlidePageNumber();
// …
};
const Eyebrow = ({ children }: { children: React.ReactNode }) => (
// …
);
const Cover: Page = () => (
// …
);
const Content: Page = () => (
// …
);
const Closer: Page = () => (
// …
);
export default [Cover, Content, Closer];Run this checklist before finishing:
bg / text / accent / muted at minimum, all as hex.mode matching the palette's background.slide-authoring defaults).themes/<id>.md and themes/<id>.demo.tsx. No slide changes, no config changes..tsx exports 2–3 pages and inlines the same Title/Footer/Eyebrow components defined in the markdown..tsx will load cleanly in the Themes panel: verify it against the Step 4b contract by reading the file — do not start a server.Tell the user:
themes/<id>.md + themes/<id>.demo.tsx)./create-slide will list the theme as a picker option on its next run.Do not run the dev server. Do not modify real slides — even to demonstrate the theme; the demo .tsx is the demonstration.
themes/<id>.md outside the labeled component snippets — the markdown is documentation.themes/<id>.demo.tsx as a real slide. It is preview-only and lives outside the slides list; never put it under slides/.@/ or any slide-specific helper inside the demo. The demo is self-contained.slides/, packages/, package.json, or open-slide.config.ts.35dc46c
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.