关于 create-theme
create-theme 是面向幻灯片作者的技能,用于生成可复用的视觉主题。它会配套创建编写指南和实时预览模块,同时避免改动正式幻灯片及项目配置。
主要功能
- 01创建主题文档与预览文件
- 02从图片、文字或现有幻灯片提取主题
- 03定义配色、字体、布局、组件和动效
- 04以 2–3 页示例预览主题
- 05仅修改 themes/ 下的文件
适用场景
- 01将品牌素材整理为可复用的幻灯片主题
- 02从现有幻灯片提取视觉风格
- 03在用于创建幻灯片前预览主题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ open-slide/ open-slide --skill create-theme安装后在 Claude Code 中输入/create-theme确认已加载。
详细介绍
创建幻灯片主题
此技能会在 themes/ 下生成一个主题包:两个配套文件,共同描述可重复使用的视觉标识。
themes/<id>.md— 面向 Agent 的文档:调色板、字体排印、布局、固定的 Title/Footer/Eyebrow 组件、动效。作者选择主题时,create-slide会读取此文件。themes/<id>.demo.tsx— 可运行的迷你幻灯片(普通幻灯片模块:export default Page[]),通过 2–3 页展示主题。开发 UI 的 Themes 面板会加载此文件,并将其渲染为主题的实时预览。
两个文件使用相同的主文件名,以便运行时自动配对。
主题不同于幻灯片的 design 常量。主题 Markdown 描述的是创作时的美学方向(create-slide 会将其复制到实际幻灯片的源文件中)。演示 .tsx 是独立的预览,不是真正的幻灯片,不会显示在幻灯片列表中。每张幻灯片中的 const design: DesignSystem = { … }(在 slides/<id>/index.tsx 顶部声明)是运行时令牌对象,用户可以通过 Design 面板对其进行调整。Markdown 确定方向;每张幻灯片的 design 常量让幻灯片可调整;演示 .tsx 让主题可预览。
只在 themes/<id>.md 和 themes/<id>.demo.tsx 下写入文件。切勿修改实际幻灯片或其他配置。主题可覆盖的画布和字号比例默认值位于 slide-authoring 技能中——编写主题前请先阅读该技能,以便明确说明覆盖项。
第 1 步 — 确定输入来源
主题可从以下三种输入形式中的任意组合衍生:
- 图像参考 — 幻灯片截图、情绪板图片、品牌素材的路径或 URL。
- 自由文本描述 — 描述所需调色板、字体和风格的文字。
- 现有幻灯片 —
slides/<id>/index.tsx,其视觉标识应提取出来,作为可重复使用的主题。
如果用户的原始消息已明确指定输入,则跳过提问并继续。否则,调用 AskUserQuestion(多选),让用户选择一个或多个来源,并仅在需要时追问(路径、幻灯片 id、描述)。
第 2 步 — 收集原始输入
- 图像:使用
Read工具读取每个路径(该工具支持读取图像)。记录主色的十六进制值、字重/字形、布局节奏、装饰图案,以及重复出现的界面元素(标题栏、页脚线、页码)。 - 文本:提取明确的令牌(十六进制代码、字体名称、动效动词)和隐含的风格词语(“编辑风”“俏皮”“粗野主义”)。将含糊的描述转化为具体决定后再行编写。
- 现有幻灯片:读取
slides/<id>/index.tsx并提取:design.palette对象(或文件顶部的旧式palette常量)→ 调色板部分。design.fonts/ 字体常量以及任何font-size模式 → 字体排印部分。- 内边距/对齐模式 → 布局部分。
- 重复出现的组件(TrafficLights、Eyebrow、Footer 样式辅助函数、WindowShell,……)→ 固定组件部分。
@keyframes块和共享的styles字符串 → 动效部分。- 设计所体现的美学风格 → 美学段落。
如果输入彼此冲突(例如,图像使用蓝色,但描述要求绿色),请询问用户应以哪一方为准。
第 3 步 — 选择主题 id
使用简短且能描述主题的 kebab-case。示例:editorial-noir、brutalist-mono、pastel-soft、dev-terminal。检查 themes/,避免名称冲突。
第 4 步 — 编写 themes/<id>.md
按以下确切顺序生成文件中的各个章节。章节正文可根据主题调整;所有主题的标题必须保持一致。
---
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>
);
```
第 4b 步 — 编写 themes/<id>.demo.tsx
演示文件是一个普通的幻灯片模块——结构与 slides/<id>/index.tsx 相同,只是放在 themes/ 下,让运行时知道它仅用于预览。开发 UI 的 Themes 面板会导入它,并在 SlideCanvas(1920×1080)中渲染。
约定:
import { type Page, useSlidePageNumber } from '@open-slide/core';- 内联主题 Markdown 中定义的同一组
Title、Footer、Eyebrow组件——逐字照搬,不做抽象,也不从其他地方导入。演示文件必须与 Markdown 保持同步,这样用户在面板中看到的内容才会与create-slide粘贴到实际幻灯片中的内容一致。 - 导出 2–3 个
Page组件和一个默认数组。建议包含:一个封面(Eyebrow + Title + 副标题)、一个展示正文排版和强调色的内容页,以及一个结束页或“End”卡片。Markdown 底部的“Example usage”代码块是不错的起点——在此基础上扩展。 - 如果主题包含值得在后续 Design 面板中展示的运行时可调整令牌,还需
export const design: DesignSystem = {...}(在基础导入旁添加import type { DesignSystem } from '@open-slide/core';)。 - 不导入资源文件,不从
@/导入,不使用仅供幻灯片使用的辅助组件(例如真实幻灯片中的WindowShell)。在内联<style>中使用 Web 字体样式表@imports 没问题——这是对webfonts.md加载规则的有意例外,因为演示文件只会在 Themes 面板中挂载。演示文件必须自包含。
骨架:
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];
第 5 步 — 自我审查
完成前运行以下检查清单:
- 配色至少包含
bg/text/accent/muted,且全部使用十六进制值。 - Frontmatter 包含
mode,并与配色中的背景相匹配。 - 字体比例指定 hero、heading、body、caption 的字号(或明确沿用
slide-authoring默认值)。 - 至少定义了
Title和Footer,使用可直接粘贴的 React 代码和具体的内联样式。 - 动效部分明确选择 static / subtle / rich 之一。
- 美学描述明确指出一个统一的风格方向。
- 两个文件都已写入:
themes/<id>.md和themes/<id>.demo.tsx。不修改幻灯片,不修改配置。 - 演示
.tsx导出 2–3 个页面,并内联与 Markdown 中定义的相同Title/Footer/Eyebrow组件。 - 演示
.tsx可以在 Themes 面板中正常加载:阅读文件并根据第 4b 步的约定进行核对——不要启动服务器。
第 6 步 — 交接
告知用户:
- 主题 ID 和两个文件路径(
themes/<id>.md+themes/<id>.demo.tsx)。 - 演示会以实时卡片和详情视图的形式出现在开发 UI 的 Themes 面板中(HMR——无需重启)。
/create-slide下次运行时会将该主题列为可选项。- 用一句话概述外观(配色 + 美学风格)。
不要运行开发服务器。不要修改真实幻灯片——即使是为了展示主题也不行;.tsx 演示文件就是展示用的。
反模式
- ❌ 在带标签的组件代码片段之外,于
themes/<id>.md中编写可执行代码——Markdown 是文档。 - ❌ 只生成 Markdown 而没有演示文件,或只生成演示文件而没有 Markdown。主题是一个组合包——每次都必须包含两个文件。
- ❌ 将
themes/<id>.demo.tsx当作真实幻灯片。它仅用于预览,位于幻灯片列表之外;绝不要将其放在slides/下。 - ❌ 在演示文件中从
@/或任何幻灯片专用辅助模块导入。演示文件必须自包含。 - ❌ 用户提供了图片或现有幻灯片时,不要凭空编造配色或字体。应提取,而不是虚构。
- ❌ 不要编辑
slides/、packages/、package.json或open-slide.config.ts。 - ❌ 不要跳过 Fixed components 部分。
Title和Footer最常见的复用目标必须是可直接粘贴的。