/slide-dsl
The complete slide DSL manual — the canvas and its background, the ten element types field by field with units, defaults and legal values, where each type keeps its words, which field the renderer actually paints when two disagree, exactly what happens to the HTML you put in
Claude Code
$ npx -y skills add thu-maic/openmaic --skill slide-dsl --agent claude-code
Codex
$ npx skills add thu-maic/openmaic --skill slide-dsl -a codex -y
Cursor
$ npx skills add thu-maic/openmaic --skill slide-dsl -a cursor -y
Gemini CLI
$ npx skills add thu-maic/openmaic --skill slide-dsl -a gemini-cli -y
GitHub Copilot
$ npx skills add thu-maic/openmaic --skill slide-dsl -a github-copilot -y
OpenCode
$ npx skills add thu-maic/openmaic --skill slide-dsl -a opencode -y
Windsurf
$ npx skills add thu-maic/openmaic --skill slide-dsl -a windsurf -y
SKILL.md
slide-dsl.SKILL.mdname: slide-dsl
title: "页面数据结构"
description: The complete slide DSL manual — the canvas and its background, the ten element types field by field with units, defaults and legal values, where each type keeps its words, which field the renderer actually paints when two disagree, exactly what happens to the HTML you put in `content`, and the structure schema that is now the ONLY thing a write is checked against. Nothing filters your markup and nothing normalises your values, so this manual is the whole of what makes a page render correctly. Load it before patching a field you have not patched before, when a patch comes back rejected, when a patch lands but nothing moves on screen, or when you need to know where a colour, a font, a table cell or a code line really lives. This is a field reference and not a procedure — `page-clone` and `pro-editing` decide which pages to touch, `slide-craft` decides what a good page looks like, and this one says what the JSON means.
The slide DSL
A slide page is a JSON document. Editing it well means writing the exact field that holds the thing you want to change, in the exact shape the renderer reads, and leaving every neighbouring field byte-identical.
**Read this part first, because it changes how you should use everything below.** The write path stores what you send. There is no markup allow-list, no sanitizer, no colour or font normalisation, no geometry clamping, no house style applied on the way in. `patch_stage` checks one thing — that the resulting document still matches the DSL **structure** schema (field names, types, required fields, closed objects) — and then persists your value byte for byte.
So there is nothing between you and the screen. A structurally legal page can still be an unreadable page: markup the renderer never styles, a colour on a field nothing paints, a formula snapshot that disagrees with its source. The guard rail catches shape, not meaning. **This manual is the meaning.** Where it tells you how the renderer behaves, that is the whole of your knowledge — write against it, then read the page back and check what you wrote is what is there.
Contents
1. [Reading before writing](#reading-before-writing) — the three read depths 2. [The document](#the-document) — `content` → `canvas` 3. [The canvas](#the-canvas) — viewport, theme, background, animations, paint order 4. [How an edit reaches the JSON](#how-an-edit-reaches-the-json) — three ops, pointer rules 5. [What the structure schema refuses](#what-the-structure-schema-refuses) — the only hard boundary 6. [Two renderers paint your page](#two-renderers-paint-your-page) — playback vs. preview 7. [Fields every element carries](#fields-every-element-carries) 8. [The ten element types](#the-ten-element-types) — one section each 9. [The rendering truth of `content` HTML](#the-rendering-truth-of-content-html) — the most important section 10. [Quick reference](#quick-reference) — one row per element type 11. [Where this sits](#where-this-sits) 12. [Hard rules](#hard-rules)
Reading before writing
`read_stage` has three depths — `detail:"tree"`, `detail:"source"` and `detail:"text"` — and they are not interchangeable.
| `detail` | What comes back | Use it for | | --------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------- | | `inventory` (default) | One compact line per element — `id`, `type`, plain-text `text`, `left`, `top`, `width`, `height`, `src` | Finding an element. **Never** as a patch source. | | `source` | The exact persisted page JSON — the root every patch path is written against | Every patch. Read it again after a write. | | `text` | Every text-bearing element as `{ path, id, type, text }` plus one page-wide `combinedText` | Proving old copy left no residue. |
- **`inventory` strips the markup.** Its `text` is the element's HTML with tags
replaced by spaces and whitespace collapsed. A patch built from it invents style values that were never there and deletes the ones that were.
- **`source` always returns the whole page.** There is no per-element
projection, so array indices cannot drift between what you read and what you write. It returns the full `content` object — `type`, `schemaVersion` and the complete `canvas`, background, theme and animations included.
- **`detail:"text"` gives you pointers.** Each `path` is that element's own
`/content/canvas/elements/N`, so a residue check hands you the pointer to fix. Note that its `text` for a `latex` element is the LaTeX source, for `code` the lines joined by newlines, and for `table` the cells joined by ` | `.
The document
A slide scene's `content` is:
{ type: 'slide', schemaVersion?: number, canvas: Slide }`type` and `schemaVersion` sit **outside** `/content/canvas/` and are therefore not reachable by a slide-canvas patch path — such a pointer begins `/content/canvas/`. Everything you can write lives under `canvas`.
The canvas
| Field | Required | Meaning | | --------------- | -------- | ------------------------------------------------------------------------------------------- | | `id` | yes | Page identity. Changing it is rejected. | | `viewportSize` | yes | Canvas **width in px** — **1000** in this product | | `viewportRatio` | yes | Height ÷ width — **0.5625**, so the canvas is **1000 × 562.5 px** | | `theme` | yes | `backgroundColor`, `themeColors[]`, `fontColor`, `fontN
Read more
name: slide-dsl title: "页面数据结构" description: The complete slide DSL manual — the canvas and its background, the ten element types field by field with units, defaults and legal values, where each type keeps its words, which field the renderer actually paints when two disagree, exactly what happens to the HTML you put in `content`, and the structure schema that is now the ONLY thing a write is checked against. Nothing filters your markup and nothing normalises your values, so this manual is the whole of what makes a page render correctly. Load it before patching a field you have not patched before, when a patch comes back rejected, when a patch lands but nothing moves on screen, or when you need to know where a colour, a font, a table cell or a code line really lives. This is a field reference and not a procedure — `page-clone` and `pro-editing` decide which pages to touch, `slide-craft` decides what a good page looks like, and this one says what the JSON means.
The slide DSL
A slide page is a JSON document. Editing it well means writing the exact field that holds the thing you want to change, in the exact shape the renderer reads, and leaving every neighbouring field byte-identical.
**Read this part first, because it changes how you should use everything below.** The write path stores what you send. There is no markup allow-list, no sanitizer, no colour or font normalisation, no geometry clamping, no house style applied on the way in. `patch_stage` checks one thing — that the resulting document still matches the DSL **structure** schema (field names, types, required fields, closed objects) — and then persists your value byte for byte.
So there is nothing between you and the screen. A structurally legal page can still be an unreadable page: markup the renderer never styles, a colour on a field nothing paints, a formula snapshot that disagrees with its source. The guard rail catches shape, not meaning. **This manual is the meaning.** Where it tells you how the renderer behaves, that is the whole of your knowledge — write against it, then read the page back and check what you wrote is what is there.
Contents
1. [Reading before writing](#reading-before-writing) — the three read depths 2. [The document](#the-document) — `content` → `canvas` 3. [The canvas](#the-canvas) — viewport, theme, background, animations, paint order 4. [How an edit reaches the JSON](#how-an-edit-reaches-the-json) — three ops, pointer rules 5. [What the structure schema refuses](#what-the-structure-schema-refuses) — the only hard boundary 6. [Two renderers paint your page](#two-renderers-paint-your-page) — playback vs. preview 7. [Fields every element carries](#fields-every-element-carries) 8. [The ten element types](#the-ten-element-types) — one section each 9. [The rendering truth of `content` HTML](#the-rendering-truth-of-content-html) — the most important section 10. [Quick reference](#quick-reference) — one row per element type 11. [Where this sits](#where-this-sits) 12. [Hard rules](#hard-rules)
Reading before writing
`read_stage` has three depths — `detail:"tree"`, `detail:"source"` and `detail:"text"` — and they are not interchangeable.
| `detail` | What comes back | Use it for | | --------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------- | | `inventory` (default) | One compact line per element — `id`, `type`, plain-text `text`, `left`, `top`, `width`, `height`, `src` | Finding an element. **Never** as a patch source. | | `source` | The exact persisted page JSON — the root every patch path is written against | Every patch. Read it again after a write. | | `text` | Every text-bearing element as `{ path, id, type, text }` plus one page-wide `combinedText` | Proving old copy left no residue. |
- **`inventory` strips the markup.** Its `text` is the element's HTML with tags
replaced by spaces and whitespace collapsed. A patch built from it invents style values that were never there and deletes the ones that were.
- **`source` always returns the whole page.** There is no per-element
projection, so array indices cannot drift between what you read and what you write. It returns the full `content` object — `type`, `schemaVersion` and the complete `canvas`, background, theme and animations included.
- **`detail:"text"` gives you pointers.** Each `path` is that element's own
`/content/canvas/elements/N`, so a residue check hands you the pointer to fix. Note that its `text` for a `latex` element is the LaTeX source, for `code` the lines joined by newlines, and for `table` the cells joined by ` | `.
The document
A slide scene's `content` is:
{ type: 'slide', schemaVersion?: number, canvas: Slide }`type` and `schemaVersion` sit **outside** `/content/canvas/` and are therefore not reachable by a slide-canvas patch path — such a pointer begins `/content/canvas/`. Everything you can write lives under `canvas`.
The canvas
| Field | Required | Meaning | | --------------- | -------- | ------------------------------------------------------------------------------------------- | | `id` | yes | Page identity. Changing it is rejected. | | `viewportSize` | yes | Canvas **width in px** — **1000** in this product | | `viewportRatio` | yes | Height ÷ width — **0.5625**, so the canvas is **1000 × 562.5 px** | | `theme` | yes | `backgroundColor`, `themeColors[]`, `fontColor`, `fontN
Open Multi-Agent Interactive Classroom — Get an immersive, multi-agent learning experience in just one click
Other skills on openmaic.
More skills from other plugins.
blueprint-figure
Draws static SVG figures for lessons, READMEs and manuals in the AI Engineering from Scratch look: paper panel, blueprint accent,…
concept-workflow
End-to-end workflow for creating complete JavaScript concept documentation, orchestrating all skills from research to final review
lesson-quiz
Test a learner on a single Claude Code tutorial lesson (01-10) with 10 questions, scoring answers and flagging weak spots. Use…
harness-creator
Build, audit, and improve harnesses that make AI coding agents reliable: AGENTS.md/CLAUDE.md instruction files, feature/state…
Questions about slide-dsl.
- Which coding agents can use slide-dsl?
- slide-dsl installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

