PPTClaw is a local-first presentation editor. Decks are JSON files on disk — you create and edit them directly, and the editor syncs changes live via WebSocket.
If pptclaw is not installed, install it globally:
pnpm add -g pptclaw # or: npm install -g pptclaw
A deck is a folder with this structure:
my-deck/
├── manifest.json # Title, theme, viewport, slide order
├── slides/
│ ├── 001-abc123.json # Slide files: <NNN>-<id>.json
│ ├── 002-def456.json
│ └── ...
└── assets/ # Images and other media
├── hero.jpg
└── ...
{
"title": "My Presentation",
"format": "1",
"viewport": { "width": 1920, "ratio": 0.5625 },
"theme": {
"primary": "#2563eb",
"secondary": "#7c3aed",
"tx1": "#1e293b",
"accents": ["#2563eb", "#7c3aed", "#5b9bd5", "#ff6b6b", "#4ecdc4", "#95e1d3"],
"fontHeading": "YouSheBiaoTiHei",
"fontBody": "Microsoft YaHei"
}
}
viewport.ratio is height/width (0.5625 = 16:9, giving 1920x1080)theme.accents is an array of 6 colors used sequentially for chart series, infographic items, etc.Each slide file contains one slide object:
{
"id": "abc123",
"elements": [ /* PPTElement objects */ ],
"background": { "type": "solid", "color": "#ffffff" },
"remark": "Speaker notes text",
"type": "content"
}
type: "cover", "contents", "transition", "content", "end"elements: array of typed element objects (see below)background: optional, defaults to whiteremark: optional speaker notes (plain text)Every element shares these fields:
id: string // Unique element ID
left: number // X position (px from left edge)
top: number // Y position (px from top edge)
width: number // Element width (px)
height: number // Element height (px)
rotate: number // Rotation in degrees, default 0
lock?: boolean // Lock element from editing
groupId?: string // Elements with same groupId form a group
name?: string // Display name
link?: { type: 'web' | 'slide', target: string }
Exception: line elements omit height and rotate — they use start/end points instead.
Use CSS variable references instead of hardcoded hex values to stay consistent with the deck's theme:
| Variable | Purpose |
|---|---|
| ---------- | --------- |
var(--primary) | Primary brand color |
var(--secondary) | Secondary/accent color |
var(--tx1) | Text color |
var(--accent1) to var(--accent6) | Chart/emphasis colors |
Brightness variants — append a suffix to any theme variable:
var(--primary-plus-50) — lighter (+50 brightness)var(--primary-minus-25) — darker (-25 brightness)Theme fonts:
var(--font-heading) — for titles, subtitles, headersvar(--font-body) — for body text, content, items{ style?: 'solid' | 'dashed' | 'dotted', width?: number, color?: string }
{ offset: number, angle: number, blur: number, color: string, alpha: number }
// offset: 0-100, angle: 0-359, blur: 0-100 (pt), alpha: 0-100 (0=transparent)
{
type: 'linear' | 'radial',
colors: [{ pos: number, color: string, alpha?: number }], // pos: 0-100%
rotate?: number,
radialStart?: 'center' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
}
Text is the most common element type, so its full schema is included here. For other element types, run pptclaw element-docs .
interface PPTTextElement extends PPTBaseElement {
type: 'text'
content: string // ProseMirror HTML
defaultColor: string // Fallback color (overridden by inline HTML styles)
fill?: string // Background fill color
lineHeight?: number // Line height multiplier, default 1.5
wordSpace?: number // Letter spacing, default 0
paragraphSpace?: number // Paragraph spacing (px), default 5
opacity?: number // 0-1, default 1
vertical?: boolean // Vertical text mode
outline?: Outline
shadow?: Shadow
textType?: 'title' | 'subtitle' | 'content' | 'item' | 'itemTitle' | 'notes' | 'header' | 'footer'
}
The content field uses ProseMirror HTML with inline styles:
<p style="font-size: 72px; font-family: var(--font-heading); font-weight: bold;">Title Text</p>
<p style="font-size: 36px; font-family: var(--font-body);">Body paragraph</p>
Supported inline styles: font-size (px), color, font-weight, font-style, text-decoration, text-align, font-family.
Font sizes in HTML are in px, which equals 2x the PowerPoint pt value. This matters because presentations are viewed on large screens — small text becomes unreadable.
| Role | Pt | Px | Notes |
|---|---|---|---|
| ------ | ---- | ---- | ------- |
| Title | 36pt | 72px | Minimum for slide titles |
| Subtitle | 24pt | 48px | |
| Body | 18pt | 36px | Recommended 36-40px |
| Minimum | 16pt | 32px | Nothing smaller than this |
Common mistake: using web-scale sizes like 14px, 16px, 18px — these are too small for presentations.
{
"background": {
"type": "solid",
"color": "var(--primary-plus-80)"
}
}
Types: "solid" (with color) or "gradient" (with gradient object). Set backgrounds on the slide object, not by creating a full-canvas shape.
To horizontally center an element: left = (1920 - width) / 2
Note: left: 960 does NOT center — it places the element's left edge at the midpoint, pushing it right.
Before finalizing element positions, verify:
Beyond the text element documented above, PPTClaw supports these element types:
| Type | Description | Key Fields |
|---|---|---|
| ------ | ------------- | ------------ |
image | Image with cover/fill, clipping, masking | imageSource, fit, clipShape, mask |
shape | Vector shape with optional inner text | shapeId, fill, gradient, text |
line | Line/arrow/connector (no height/rotate) | start, end, points, width (stroke) |
chart | Data visualization (8 chart types) | chartType, data, color |
table | Grid table with styled cells | data (2D TableCell), colWidths, theme |
icon | SVG icon by keyword search | keyword, color |
artText | Decorative wave text (cover pages only) | content, style, defaultColor |
infographic | Template-based infographic/diagram | template, data, color |
Get the full schema for any type:
pptclaw element-docs <type> # e.g., pptclaw element-docs image
pptclaw element-docs chart table # multiple types at once
pptclaw element-docs # list all types
All commands support -p, --port (default: 3059).
Start the editor server as a background daemon. Optionally open a deck immediately.
pptclaw serve # start server
pptclaw serve ./my-deck # start and open deck
pptclaw serve --port 4000 # custom port
Exit code: 0 on success, 1 if server fails to start.
Open a deck folder in the running editor.
pptclaw open ./my-deck
pptclaw open ./my-deck --session custom-id
Output: session ID, path, slide count.
Validate a deck folder structure and content. Returns JSON with valid, errors, warnings.
pptclaw validate ./my-deck
Exit code: 0 if valid, 1 if errors found. Requires running server.
List active sessions (open decks) with slide counts.
pptclaw list-decks
Show server status, auth state, and active sessions as JSON.
Copy the PPTClaw skill file to .claude/skills/pptclaw/SKILL.md in the current directory.
Print element type documentation.
pptclaw element-docs # list available types
pptclaw element-docs image # print image element docs
pptclaw element-docs chart table # print multiple
Search Unsplash images. Returns JSON array of results with id, description, dimensions.
Download an image to a deck's assets folder.
```bash
mkdir -p my-deck/slides my-deck/assets
```
manifest.json with title, theme, and viewportslides/ (numbered: 001-.json , 002-.json , ...)```bash
pptclaw validate ./my-deck
```
```bash
pptclaw serve ./my-deck
```
elements array — add, update, or remove elementspptclaw validate ./my-deck```bash
pptclaw search-images "mountain landscape"
```
```bash
pptclaw download-image
```
imageSource field on an image element共 1 个版本