[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6MN844V71Z63BXF74DH4MEF":3,"skill-same:01M6MN844V71Z63BXF74DH4MEF":75},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":28,"publishedAt":49,"linkOnly":50,"markdownContent":51,"markdownBody":52,"frontMatter":53,"refName":54,"commitSha":55,"skillDirectory":56,"forksCount":57,"repositoryHtmlUrl":58,"repositoryHomepageUrl":6,"ownerHtmlUrl":59,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":60,"install":61,"resources":74},"01M6MN844V71Z63BXF74DH4MEF","slide-authoring",null,"Technical reference for writing or editing open-slide pages — file contract, 1920×1080 canvas, type scale, layout, palette\u002Fvisual direction, and assets. Consult this whenever you are about to write or modify any file under `slides\u002F\u003Cid>\u002F`, including from inside the `create-slide` or `apply-comments` workflows, or for any ad-hoc slide edit. Triggers on phrases like \"edit slide\", \"tweak this page\", \"fix the layout\", \"change the palette\", \"investigate the slide framework\", \"how do slides work here\".","arkhe-genesis\u002FArkhe-OS","arkhe-genesis","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F272629719?v=4","01M6KJDTSTJD2AD5RFPVZNGYCP","Rafael Oliveira","01M6KJDTXSTA997KDK184EA55A",1,"Apache-2.0","https:\u002F\u002Fgithub.com\u002Farkhe-genesis\u002FArkhe-OS\u002Fblob\u002Fmain\u002Ftools\u002F.agents\u002Fskills\u002Fslide-authoring\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000037","律师与法务","PROFESSION","适用职业",[29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48],"slide authoring","authoring","write","you","palette","direction","layout","do","fix","edit","writing","work","consult","how","open","framework","create","change","workflows","canvas","2026-11-10 10:12:30",false,"---\nname: slide-authoring\ndescription: Technical reference for writing or editing open-slide pages — file contract, 1920×1080 canvas, type scale, layout, palette\u002Fvisual direction, and assets. Consult this whenever you are about to write or modify any file under `slides\u002F\u003Cid>\u002F`, including from inside the `create-slide` or `apply-comments` workflows, or for any ad-hoc slide edit. Triggers on phrases like \"edit slide\", \"tweak this page\", \"fix the layout\", \"change the palette\", \"investigate the slide framework\", \"how do slides work here\".\n---\n\n# Authoring open-slide pages\n\nThis skill is the **technical reference** for everything that happens inside `slides\u002F\u003Cid>\u002Findex.tsx`. It does not own a workflow:\n\n- `create-slide` owns \"draft a new deck\" — it asks the user scoping questions, then delegates the *how* to this skill.\n- `apply-comments` owns \"process inspector markers\" — it finds markers and applies edits, but the edits themselves follow the rules here.\n- Any ad-hoc slide edit (manual tweak, one-off fix) should also consult this skill before touching the file.\n\nWhen any of those paths reach the point of *writing React code for a page*, this is the source of truth. Do not duplicate the knowledge below into other skills — link here instead.\n\n## Hard rules\n\n- Put the slide under `slides\u002F\u003Ckebab-case-id>\u002F`.\n- Entry is `slides\u002F\u003Cid>\u002Findex.tsx`. Images\u002Fvideos\u002Ffonts go under `slides\u002F\u003Cid>\u002Fassets\u002F`.\n- Do **not** touch `package.json`, `open-slide.config.ts`, or other slides.\n- Do not add dependencies. Only `react` and standard web APIs are available.\n- Do not create `README.md` or other prose files inside the slide folder — just `index.tsx` + `assets\u002F`.\n\n## File contract\n\n```tsx\n\u002F\u002F slides\u002F\u003Cid>\u002Findex.tsx\nimport type { Page, SlideMeta } from '@open-slide\u002Fcore';\n\nconst Cover: Page = () => \u003Cdiv>…\u003C\u002Fdiv>;\nconst Body: Page = () => \u003Cdiv>…\u003C\u002Fdiv>;\n\nexport const meta: SlideMeta = { title: 'My slide' };\nexport default [Cover, Body] satisfies Page[];\n```\n\n- `export default` is a **non-empty array of zero-prop React components**, one per page, in order.\n- `meta.title` (optional) shows in the slide header. Default is the folder name.\n- The slide id is the kebab-case folder name. Pick something short and descriptive (`q2-roadmap`, `team-offsite-2026`).\n\n## Canvas\n\nEvery page renders into a fixed **1920 × 1080** canvas. The framework scales it; you design as if the viewport is literally 1920×1080.\n\n- Use **absolute pixel values** for `font-size`, padding, positioning. No `rem`, no `vw`\u002F`vh`, no `%` for type.\n- The root element of each page should fill the canvas: `width: '100%'; height: '100%'`.\n- Prefer inline `style={{ … }}`. Any CSS you load is global — scope classnames carefully.\n\n### Type scale (start here, adjust to taste)\n\n| Element          | Size       |\n| ---------------- | ---------- |\n| Hero title       | 140–200px  |\n| Section heading  | 80–120px   |\n| Page heading     | 56–80px    |\n| Body text        | 32–44px    |\n| Caption \u002F label  | 22–28px    |\n\n### Spacing\n\n- Content padding: **100–160px** from canvas edges. Never let text touch the edge.\n- Line-height: 1.2 for headings, 1.5–1.7 for body.\n- Breathing room between elements: 32–64px.\n\n### Vertical budget — content MUST fit 1080px\n\nThe canvas does **not** scroll. Anything below 1080px is silently cropped. Before writing JSX, do the math on paper and confirm the page fits. This is the #1 cause of broken slides — assume you will overflow unless you've checked.\n\n**Usable height** = `1080 − top_padding − bottom_padding`. With 120px padding on each side that's **840px**. With 160px each side, **760px**. Pick the padding first, then design within that budget.\n\n**Element height** = `font_size × line_height × number_of_lines`. A bullet that wraps to 2 lines counts as 2 lines. Add the gap below it (32–64px) before summing the next element.\n\n**Worked example — single content page, 120px padding (budget = 840px):**\n\n| Element                                  | Height                  |\n| ---------------------------------------- | ----------------------- |\n| Heading: 80px × 1.2 × 1 line             | 96px                    |\n| Gap                                      | 64px                    |\n| Body paragraph: 40px × 1.6 × 3 lines     | 192px                   |\n| Gap                                      | 48px                    |\n| 5 bullets: 40px × 1.6 × 1 line each      | 320px (5 × 64px)        |\n| 4 gaps between bullets: 24px each        | 96px                    |\n| **Total**                                | **816px ✅ fits in 840** |\n\nSwap the heading to 120px or add a 6th bullet and you're over. **Verify every page like this before you write it.**\n\n**Page-level rules:**\n\n- One heading + body OR one heading + ≤5 short bullets. Not both blocks of body copy *and* a long bullet list.\n- A bullet should fit on one line at the chosen font size. If it wraps, either shorten the copy or move it to its own page.\n- Hero title pages (140–200px) carry a title + 1 subtitle + maybe an eyebrow — nothing else.\n- Section headings (80–120px) need almost nothing else on the page.\n- If you find yourself raising padding, shrinking type below the scale's lower bound, or tightening line-height under 1.4 to make things fit — **split into two pages instead**. Splitting is always the right answer when the budget is tight.\n\n**Never** use `overflow: auto\u002Fscroll`, negative margins, or transforms to hide overflow. The canvas is fixed; cropped content is gone.\n\n## Visual direction\n\nPick a coherent look and hold it across every page:\n\n- **Palette** — 1 background, 1 primary text, 1 accent, 1 muted. Define as constants at the top of the file.\n- **Typography** — one display font + one body font. System stack unless the user specifies. Heavy weight for headlines (800–900), normal for body (400–500).\n- **Layout grid** — pick a single content padding (e.g. 120px) and stick to it. Left-aligned content feels editorial; centered feels ceremonial.\n- **Aesthetic commitment** — choose ONE: minimal, maximalist, editorial, retro, brutalist, soft\u002Fpastel, neon, paper\u002Fprint. Don't mix.\n\nConsult the `frontend-design` skill for deeper aesthetic guidance if the user wants something bold.\n\n## Themes\n\nIf `themes\u002F\u003Cid>.md` exists at the project root and the slide is meant to follow it, **the theme file overrides the defaults in this skill** — its palette, typography, layout padding, and Title\u002FFooter components are authoritative. Read the theme file before applying anything else in this section.\n\nThemes are produced by the `create-theme` skill and are pure documentation: copy the palette and the paste-ready Title \u002F Footer \u002F Eyebrow components straight into your slide. If the theme's frontmatter has `mode: dark` or `mode: light`, treat that as the slide's background mode (e.g. when picking which logo variant to import).\n\n## Design system (opt-in, per-slide)\n\nA slide can declare its own typed design tokens at the top of `index.tsx`:\n\n```tsx\nimport type { DesignSystem, Page } from '@open-slide\u002Fcore';\n\nexport const design: DesignSystem = {\n  palette: { bg: '#f7f5f0', text: '#1a1814', accent: '#6d4cff' },\n  fonts: {\n    display: 'Georgia, \"Times New Roman\", serif',\n    body: '-apple-system, BlinkMacSystemFont, \"Inter\", system-ui, sans-serif',\n  },\n  typeScale: { hero: 168, body: 36 },\n  radius:    12,\n};\n```\n\n`export` it (rather than plain `const`) so the framework can read the object and inject CSS variables at the canvas root automatically.\n\nThe shape is intentionally minimal — it only covers what the Design panel can currently tweak. Anything outside this set (heading sizes, spacing, motion, extra palette colors) belongs as plain hard-coded constants in the slide file.\n\nThere are **two consumption surfaces**, and you should mix them inside the same slide:\n\n- **`var(--osd-X)` for visual properties (color, font, font-size, radius)** — these get instant updates while the user drags a slider in the Design panel, before any file write.\n  ```tsx\n  \u003Cdiv style={{ background: 'var(--osd-bg)', color: 'var(--osd-text)', borderRadius: 'var(--osd-radius)', fontFamily: 'var(--osd-font-body)', fontSize: 'var(--osd-size-body)' }}>\n  ```\n  Available vars: `--osd-bg`, `--osd-text`, `--osd-accent`, `--osd-font-display`, `--osd-font-body`, `--osd-size-hero`, `--osd-size-body`, `--osd-radius`.\n\n- **Direct `design.X` reads** — when you need a JS number for arithmetic or to label something in the UI. These update via HMR after the panel commits the file, not while dragging.\n  ```tsx\n  \u003Cp>{design.typeScale.hero}px\u003C\u002Fp>\n  ```\n\nThe dev UI has a **Design** button in the slide header (next to Inspect). Edits update an in-memory draft and the live-preview overlay; a floating Save \u002F Discard bar at the bottom of the canvas commits or reverts. The const stays the single source of truth — production builds bake the saved values.\n\n**Default to using it.** Every new slide should declare a `design` const so it stays tweakable from the panel after generation — this is the expected baseline. Only fall back to the local `palette` constants pattern (see starter template) for a one-off slide whose palette is intentionally locked and not meant to be re-themed. Both styles can coexist across slides — the panel only operates on the *currently viewed* slide.\n\nFormat constraints (for the panel's AST writer):\n- Must be `[export] const design: DesignSystem = { … }` (or `as DesignSystem` \u002F `satisfies DesignSystem`) at module top level.\n- Object initializer must be a literal — no spreads, no helper calls. Plain values only.\n- `DesignSystem` must be imported from `@open-slide\u002Fcore` (the panel adds the import automatically when creating a fresh block).\n\n## Starter template\n\n```tsx\nimport type { DesignSystem, Page, SlideMeta } from '@open-slide\u002Fcore';\n\nexport const design: DesignSystem = {\n  palette: { bg: '#0f172a', text: '#f8fafc', accent: '#fbbf24' },\n  fonts: {\n    display: 'system-ui, -apple-system, sans-serif',\n    body: 'system-ui, -apple-system, sans-serif',\n  },\n  typeScale: { hero: 180, body: 40 },\n  radius: 12,\n};\n\n\u002F\u002F Extra colors \u002F sizes outside the DesignSystem shape stay as plain consts.\nconst muted = '#94a3b8';\n\nconst fill = {\n  width: '100%',\n  height: '100%',\n  fontFamily: 'var(--osd-font-body)',\n} as const;\n\nconst Cover: Page = () => (\n  \u003Cdiv\n    style={{\n      ...fill,\n      background: 'var(--osd-bg)',\n      color: 'var(--osd-text)',\n      display: 'flex',\n      flexDirection: 'column',\n      justifyContent: 'center',\n      padding: '0 160px',\n    }}\n  >\n    \u003Cdiv style={{ fontSize: 28, color: 'var(--osd-accent)', letterSpacing: '0.2em' }}>\n      CHAPTER 01\n    \u003C\u002Fdiv>\n    \u003Ch1\n      style={{\n        fontFamily: 'var(--osd-font-display)',\n        fontSize: 'var(--osd-size-hero)',\n        fontWeight: 900,\n        margin: '32px 0',\n        lineHeight: 1.05,\n      }}\n    >\n      The Big Idea\n    \u003C\u002Fh1>\n    \u003Cp style={{ fontSize: 'var(--osd-size-body)', color: muted, maxWidth: 1200 }}>\n      A short subtitle that explains what this slide is about.\n    \u003C\u002Fp>\n  \u003C\u002Fdiv>\n);\n\nconst Content: Page = () => (\n  \u003Cdiv style={{ ...fill, background: 'var(--osd-bg)', color: 'var(--osd-text)', padding: 120 }}>\n    \u003Ch2 style={{ fontFamily: 'var(--osd-font-display)', fontSize: 80, fontWeight: 800, margin: 0 }}>\n      Section heading\n    \u003C\u002Fh2>\n    \u003Cul style={{ fontSize: 'var(--osd-size-body)', lineHeight: 1.6, marginTop: 64, paddingLeft: 48 }}>\n      \u003Cli>One clear point per line\u003C\u002Fli>\n      \u003Cli>Keep to 3–5 bullets\u003C\u002Fli>\n      \u003Cli>Let the space breathe\u003C\u002Fli>\n    \u003C\u002Ful>\n  \u003C\u002Fdiv>\n);\n\nexport const meta: SlideMeta = { title: 'The Big Idea' };\nexport default [Cover, Content] satisfies Page[];\n```\n\n## Assets\n\nPlace files under `slides\u002F\u003Cid>\u002Fassets\u002F`. Import them as ES modules:\n\n```tsx\nimport hero from '.\u002Fassets\u002Fhero.jpg';\n\u002F\u002F …\n\u003Cimg src={hero} style={{ width: '100%', height: '100%', objectFit: 'cover' }} \u002F>\n```\n\nFor URL-only access:\n\n```tsx\nconst videoUrl = new URL('.\u002Fassets\u002Fintro.mp4', import.meta.url).href;\n```\n\nSkip the `assets\u002F` folder entirely for pure-text slides.\n\n## Image placeholders\n\nWhen a page genuinely needs a real image **the user has to provide** — a product screenshot, a team photo, a chart from their data — leave a typed placeholder instead of inventing a stand-in:\n\n```tsx\nimport { ImagePlaceholder } from '@open-slide\u002Fcore';\n\n\u003CImagePlaceholder hint=\"Product hero screenshot\" width={1280} height={720} \u002F>\n```\n\nThe user uploads the real file via the Assets panel, then clicks the placeholder in the inspector and picks \"Replace…\" — the JSX is rewritten to a real `\u003Cimg>` with the import added.\n\n**Use a placeholder only when** a specific concrete image is required by the deck's topic. Examples that warrant one: a product-intro deck (product screenshot per feature), an offsite recap (team photo), a case study (customer logo, dashboard screenshot).\n\n**Do not use a placeholder** for decoration, generic \"stock photo\" filler, hero imagery on a text-heavy slide, or anywhere a typographic \u002F iconographic \u002F illustrative solution would do. If you can carry the page with type, layout, and color — do that. Empty placeholders the user has to fill are friction; only spend that friction when the alternative is worse.\n\nSize the placeholder to the slot it occupies. Pass `width`\u002F`height` when the layout has a fixed image box; omit them when the placeholder fills a flex\u002Fgrid cell. The `hint` should describe the *content* the user needs (\"Q3 revenue chart\") not the *role* (\"hero image\").\n\n## Runtime behavior you get for free\n\n- Home page lists every folder under `slides\u002F`.\n- Clicking a slide shows a left thumbnail rail, main page, prev\u002Fnext, page counter.\n- Arrow keys \u002F PageUp \u002F PageDown navigate. `F` enters fullscreen play mode.\n- In play mode: Space\u002F→ next, ← prev, Esc exit.\n- Hot reload: edit `index.tsx` and the browser updates live.\n\n## Self-review before finishing\n\n- [ ] `slides\u002F\u003Cid>\u002Findex.tsx` `export default`s a non-empty `Page[]`.\n- [ ] Every page's root fills `100% × 100%`.\n- [ ] Content lives inside padding (no text kisses the edge).\n- [ ] **For every page, sum (font_size × line_height × lines) + gaps + 2×padding ≤ 1080px.** If close, split the page. No `overflow: auto` escape hatches.\n- [ ] No bullet wraps to a second line at the chosen font size.\n- [ ] One coherent visual direction across every page (palette + type scale).\n- [ ] Slide declares a top-level `export const design: DesignSystem = { … }` and references the values via `var(--osd-X)` (use `design.X` only when you need a JS number for arithmetic). Only omit the `design` const for a one-off slide whose palette is intentionally locked.\n- [ ] One idea per page.\n- [ ] All imported assets exist on disk under `slides\u002F\u003Cid>\u002Fassets\u002F`.\n- [ ] Every `\u003CImagePlaceholder>` corresponds to a real image the user must supply — not decorative filler. If it could be replaced by typography or layout, it should be.\n- [ ] Nothing outside `slides\u002F\u003Cid>\u002F` was edited.\n\n## Anti-patterns\n\n- ❌ Walls of text. If a page has more than ~40 words, split it.\n- ❌ Using the full canvas for body copy. Respect 100–160px padding.\n- ❌ Overflowing 1080px vertically. Cropped content is invisible — split the page.\n- ❌ `overflow: auto` \u002F `overflow: scroll` \u002F `overflow: hidden` to \"hide\" too much content. The canvas doesn't scroll; you've just hidden the bug.\n- ❌ Shrinking type below the scale's lower bound, or padding below 100px, to cram more in. Split instead.\n- ❌ Bullets that wrap to a second line — either shorten or move to its own page.\n- ❌ Body type under 28px — unreadable on a projector.\n- ❌ Inconsistent palette across pages.\n- ❌ Installing packages. Only `react` and standard web APIs are available.\n- ❌ Writing CSS to a shared file. Inline styles or scoped classnames only.\n- ❌ Creating `README.md` or other prose files inside the slide folder.\n- ❌ Editing `package.json`, `open-slide.config.ts`, or other slides.\n- ❌ Sprinkling `\u003CImagePlaceholder>` across pages \"for visual interest\". Placeholders are for content the user owns; they're not stock-photo slots.\n- ❌ Using a placeholder for an icon or decorative shape — those are typography\u002FSVG problems, not asset problems.\n","# Authoring open-slide pages\n\nThis skill is the **technical reference** for everything that happens inside `slides\u002F\u003Cid>\u002Findex.tsx`. It does not own a workflow:\n\n- `create-slide` owns \"draft a new deck\" — it asks the user scoping questions, then delegates the *how* to this skill.\n- `apply-comments` owns \"process inspector markers\" — it finds markers and applies edits, but the edits themselves follow the rules here.\n- Any ad-hoc slide edit (manual tweak, one-off fix) should also consult this skill before touching the file.\n\nWhen any of those paths reach the point of *writing React code for a page*, this is the source of truth. Do not duplicate the knowledge below into other skills — link here instead.\n\n## Hard rules\n\n- Put the slide under `slides\u002F\u003Ckebab-case-id>\u002F`.\n- Entry is `slides\u002F\u003Cid>\u002Findex.tsx`. Images\u002Fvideos\u002Ffonts go under `slides\u002F\u003Cid>\u002Fassets\u002F`.\n- Do **not** touch `package.json`, `open-slide.config.ts`, or other slides.\n- Do not add dependencies. Only `react` and standard web APIs are available.\n- Do not create `README.md` or other prose files inside the slide folder — just `index.tsx` + `assets\u002F`.\n\n## File contract\n\n```tsx\n\u002F\u002F slides\u002F\u003Cid>\u002Findex.tsx\nimport type { Page, SlideMeta } from '@open-slide\u002Fcore';\n\nconst Cover: Page = () => \u003Cdiv>…\u003C\u002Fdiv>;\nconst Body: Page = () => \u003Cdiv>…\u003C\u002Fdiv>;\n\nexport const meta: SlideMeta = { title: 'My slide' };\nexport default [Cover, Body] satisfies Page[];\n```\n\n- `export default` is a **non-empty array of zero-prop React components**, one per page, in order.\n- `meta.title` (optional) shows in the slide header. Default is the folder name.\n- The slide id is the kebab-case folder name. Pick something short and descriptive (`q2-roadmap`, `team-offsite-2026`).\n\n## Canvas\n\nEvery page renders into a fixed **1920 × 1080** canvas. The framework scales it; you design as if the viewport is literally 1920×1080.\n\n- Use **absolute pixel values** for `font-size`, padding, positioning. No `rem`, no `vw`\u002F`vh`, no `%` for type.\n- The root element of each page should fill the canvas: `width: '100%'; height: '100%'`.\n- Prefer inline `style={{ … }}`. Any CSS you load is global — scope classnames carefully.\n\n### Type scale (start here, adjust to taste)\n\n| Element          | Size       |\n| ---------------- | ---------- |\n| Hero title       | 140–200px  |\n| Section heading  | 80–120px   |\n| Page heading     | 56–80px    |\n| Body text        | 32–44px    |\n| Caption \u002F label  | 22–28px    |\n\n### Spacing\n\n- Content padding: **100–160px** from canvas edges. Never let text touch the edge.\n- Line-height: 1.2 for headings, 1.5–1.7 for body.\n- Breathing room between elements: 32–64px.\n\n### Vertical budget — content MUST fit 1080px\n\nThe canvas does **not** scroll. Anything below 1080px is silently cropped. Before writing JSX, do the math on paper and confirm the page fits. This is the #1 cause of broken slides — assume you will overflow unless you've checked.\n\n**Usable height** = `1080 − top_padding − bottom_padding`. With 120px padding on each side that's **840px**. With 160px each side, **760px**. Pick the padding first, then design within that budget.\n\n**Element height** = `font_size × line_height × number_of_lines`. A bullet that wraps to 2 lines counts as 2 lines. Add the gap below it (32–64px) before summing the next element.\n\n**Worked example — single content page, 120px padding (budget = 840px):**\n\n| Element                                  | Height                  |\n| ---------------------------------------- | ----------------------- |\n| Heading: 80px × 1.2 × 1 line             | 96px                    |\n| Gap                                      | 64px                    |\n| Body paragraph: 40px × 1.6 × 3 lines     | 192px                   |\n| Gap                                      | 48px                    |\n| 5 bullets: 40px × 1.6 × 1 line each      | 320px (5 × 64px)        |\n| 4 gaps between bullets: 24px each        | 96px                    |\n| **Total**                                | **816px ✅ fits in 840** |\n\nSwap the heading to 120px or add a 6th bullet and you're over. **Verify every page like this before you write it.**\n\n**Page-level rules:**\n\n- One heading + body OR one heading + ≤5 short bullets. Not both blocks of body copy *and* a long bullet list.\n- A bullet should fit on one line at the chosen font size. If it wraps, either shorten the copy or move it to its own page.\n- Hero title pages (140–200px) carry a title + 1 subtitle + maybe an eyebrow — nothing else.\n- Section headings (80–120px) need almost nothing else on the page.\n- If you find yourself raising padding, shrinking type below the scale's lower bound, or tightening line-height under 1.4 to make things fit — **split into two pages instead**. Splitting is always the right answer when the budget is tight.\n\n**Never** use `overflow: auto\u002Fscroll`, negative margins, or transforms to hide overflow. The canvas is fixed; cropped content is gone.\n\n## Visual direction\n\nPick a coherent look and hold it across every page:\n\n- **Palette** — 1 background, 1 primary text, 1 accent, 1 muted. Define as constants at the top of the file.\n- **Typography** — one display font + one body font. System stack unless the user specifies. Heavy weight for headlines (800–900), normal for body (400–500).\n- **Layout grid** — pick a single content padding (e.g. 120px) and stick to it. Left-aligned content feels editorial; centered feels ceremonial.\n- **Aesthetic commitment** — choose ONE: minimal, maximalist, editorial, retro, brutalist, soft\u002Fpastel, neon, paper\u002Fprint. Don't mix.\n\nConsult the `frontend-design` skill for deeper aesthetic guidance if the user wants something bold.\n\n## Themes\n\nIf `themes\u002F\u003Cid>.md` exists at the project root and the slide is meant to follow it, **the theme file overrides the defaults in this skill** — its palette, typography, layout padding, and Title\u002FFooter components are authoritative. Read the theme file before applying anything else in this section.\n\nThemes are produced by the `create-theme` skill and are pure documentation: copy the palette and the paste-ready Title \u002F Footer \u002F Eyebrow components straight into your slide. If the theme's frontmatter has `mode: dark` or `mode: light`, treat that as the slide's background mode (e.g. when picking which logo variant to import).\n\n## Design system (opt-in, per-slide)\n\nA slide can declare its own typed design tokens at the top of `index.tsx`:\n\n```tsx\nimport type { DesignSystem, Page } from '@open-slide\u002Fcore';\n\nexport const design: DesignSystem = {\n  palette: { bg: '#f7f5f0', text: '#1a1814', accent: '#6d4cff' },\n  fonts: {\n    display: 'Georgia, \"Times New Roman\", serif',\n    body: '-apple-system, BlinkMacSystemFont, \"Inter\", system-ui, sans-serif',\n  },\n  typeScale: { hero: 168, body: 36 },\n  radius:    12,\n};\n```\n\n`export` it (rather than plain `const`) so the framework can read the object and inject CSS variables at the canvas root automatically.\n\nThe shape is intentionally minimal — it only covers what the Design panel can currently tweak. Anything outside this set (heading sizes, spacing, motion, extra palette colors) belongs as plain hard-coded constants in the slide file.\n\nThere are **two consumption surfaces**, and you should mix them inside the same slide:\n\n- **`var(--osd-X)` for visual properties (color, font, font-size, radius)** — these get instant updates while the user drags a slider in the Design panel, before any file write.\n  ```tsx\n  \u003Cdiv style={{ background: 'var(--osd-bg)', color: 'var(--osd-text)', borderRadius: 'var(--osd-radius)', fontFamily: 'var(--osd-font-body)', fontSize: 'var(--osd-size-body)' }}>\n  ```\n  Available vars: `--osd-bg`, `--osd-text`, `--osd-accent`, `--osd-font-display`, `--osd-font-body`, `--osd-size-hero`, `--osd-size-body`, `--osd-radius`.\n\n- **Direct `design.X` reads** — when you need a JS number for arithmetic or to label something in the UI. These update via HMR after the panel commits the file, not while dragging.\n  ```tsx\n  \u003Cp>{design.typeScale.hero}px\u003C\u002Fp>\n  ```\n\nThe dev UI has a **Design** button in the slide header (next to Inspect). Edits update an in-memory draft and the live-preview overlay; a floating Save \u002F Discard bar at the bottom of the canvas commits or reverts. The const stays the single source of truth — production builds bake the saved values.\n\n**Default to using it.** Every new slide should declare a `design` const so it stays tweakable from the panel after generation — this is the expected baseline. Only fall back to the local `palette` constants pattern (see starter template) for a one-off slide whose palette is intentionally locked and not meant to be re-themed. Both styles can coexist across slides — the panel only operates on the *currently viewed* slide.\n\nFormat constraints (for the panel's AST writer):\n- Must be `[export] const design: DesignSystem = { … }` (or `as DesignSystem` \u002F `satisfies DesignSystem`) at module top level.\n- Object initializer must be a literal — no spreads, no helper calls. Plain values only.\n- `DesignSystem` must be imported from `@open-slide\u002Fcore` (the panel adds the import automatically when creating a fresh block).\n\n## Starter template\n\n```tsx\nimport type { DesignSystem, Page, SlideMeta } from '@open-slide\u002Fcore';\n\nexport const design: DesignSystem = {\n  palette: { bg: '#0f172a', text: '#f8fafc', accent: '#fbbf24' },\n  fonts: {\n    display: 'system-ui, -apple-system, sans-serif',\n    body: 'system-ui, -apple-system, sans-serif',\n  },\n  typeScale: { hero: 180, body: 40 },\n  radius: 12,\n};\n\n\u002F\u002F Extra colors \u002F sizes outside the DesignSystem shape stay as plain consts.\nconst muted = '#94a3b8';\n\nconst fill = {\n  width: '100%',\n  height: '100%',\n  fontFamily: 'var(--osd-font-body)',\n} as const;\n\nconst Cover: Page = () => (\n  \u003Cdiv\n    style={{\n      ...fill,\n      background: 'var(--osd-bg)',\n      color: 'var(--osd-text)',\n      display: 'flex',\n      flexDirection: 'column',\n      justifyContent: 'center',\n      padding: '0 160px',\n    }}\n  >\n    \u003Cdiv style={{ fontSize: 28, color: 'var(--osd-accent)', letterSpacing: '0.2em' }}>\n      CHAPTER 01\n    \u003C\u002Fdiv>\n    \u003Ch1\n      style={{\n        fontFamily: 'var(--osd-font-display)',\n        fontSize: 'var(--osd-size-hero)',\n        fontWeight: 900,\n        margin: '32px 0',\n        lineHeight: 1.05,\n      }}\n    >\n      The Big Idea\n    \u003C\u002Fh1>\n    \u003Cp style={{ fontSize: 'var(--osd-size-body)', color: muted, maxWidth: 1200 }}>\n      A short subtitle that explains what this slide is about.\n    \u003C\u002Fp>\n  \u003C\u002Fdiv>\n);\n\nconst Content: Page = () => (\n  \u003Cdiv style={{ ...fill, background: 'var(--osd-bg)', color: 'var(--osd-text)', padding: 120 }}>\n    \u003Ch2 style={{ fontFamily: 'var(--osd-font-display)', fontSize: 80, fontWeight: 800, margin: 0 }}>\n      Section heading\n    \u003C\u002Fh2>\n    \u003Cul style={{ fontSize: 'var(--osd-size-body)', lineHeight: 1.6, marginTop: 64, paddingLeft: 48 }}>\n      \u003Cli>One clear point per line\u003C\u002Fli>\n      \u003Cli>Keep to 3–5 bullets\u003C\u002Fli>\n      \u003Cli>Let the space breathe\u003C\u002Fli>\n    \u003C\u002Ful>\n  \u003C\u002Fdiv>\n);\n\nexport const meta: SlideMeta = { title: 'The Big Idea' };\nexport default [Cover, Content] satisfies Page[];\n```\n\n## Assets\n\nPlace files under `slides\u002F\u003Cid>\u002Fassets\u002F`. Import them as ES modules:\n\n```tsx\nimport hero from '.\u002Fassets\u002Fhero.jpg';\n\u002F\u002F …\n\u003Cimg src={hero} style={{ width: '100%', height: '100%', objectFit: 'cover' }} \u002F>\n```\n\nFor URL-only access:\n\n```tsx\nconst videoUrl = new URL('.\u002Fassets\u002Fintro.mp4', import.meta.url).href;\n```\n\nSkip the `assets\u002F` folder entirely for pure-text slides.\n\n## Image placeholders\n\nWhen a page genuinely needs a real image **the user has to provide** — a product screenshot, a team photo, a chart from their data — leave a typed placeholder instead of inventing a stand-in:\n\n```tsx\nimport { ImagePlaceholder } from '@open-slide\u002Fcore';\n\n\u003CImagePlaceholder hint=\"Product hero screenshot\" width={1280} height={720} \u002F>\n```\n\nThe user uploads the real file via the Assets panel, then clicks the placeholder in the inspector and picks \"Replace…\" — the JSX is rewritten to a real `\u003Cimg>` with the import added.\n\n**Use a placeholder only when** a specific concrete image is required by the deck's topic. Examples that warrant one: a product-intro deck (product screenshot per feature), an offsite recap (team photo), a case study (customer logo, dashboard screenshot).\n\n**Do not use a placeholder** for decoration, generic \"stock photo\" filler, hero imagery on a text-heavy slide, or anywhere a typographic \u002F iconographic \u002F illustrative solution would do. If you can carry the page with type, layout, and color — do that. Empty placeholders the user has to fill are friction; only spend that friction when the alternative is worse.\n\nSize the placeholder to the slot it occupies. Pass `width`\u002F`height` when the layout has a fixed image box; omit them when the placeholder fills a flex\u002Fgrid cell. The `hint` should describe the *content* the user needs (\"Q3 revenue chart\") not the *role* (\"hero image\").\n\n## Runtime behavior you get for free\n\n- Home page lists every folder under `slides\u002F`.\n- Clicking a slide shows a left thumbnail rail, main page, prev\u002Fnext, page counter.\n- Arrow keys \u002F PageUp \u002F PageDown navigate. `F` enters fullscreen play mode.\n- In play mode: Space\u002F→ next, ← prev, Esc exit.\n- Hot reload: edit `index.tsx` and the browser updates live.\n\n## Self-review before finishing\n\n- [ ] `slides\u002F\u003Cid>\u002Findex.tsx` `export default`s a non-empty `Page[]`.\n- [ ] Every page's root fills `100% × 100%`.\n- [ ] Content lives inside padding (no text kisses the edge).\n- [ ] **For every page, sum (font_size × line_height × lines) + gaps + 2×padding ≤ 1080px.** If close, split the page. No `overflow: auto` escape hatches.\n- [ ] No bullet wraps to a second line at the chosen font size.\n- [ ] One coherent visual direction across every page (palette + type scale).\n- [ ] Slide declares a top-level `export const design: DesignSystem = { … }` and references the values via `var(--osd-X)` (use `design.X` only when you need a JS number for arithmetic). Only omit the `design` const for a one-off slide whose palette is intentionally locked.\n- [ ] One idea per page.\n- [ ] All imported assets exist on disk under `slides\u002F\u003Cid>\u002Fassets\u002F`.\n- [ ] Every `\u003CImagePlaceholder>` corresponds to a real image the user must supply — not decorative filler. If it could be replaced by typography or layout, it should be.\n- [ ] Nothing outside `slides\u002F\u003Cid>\u002F` was edited.\n\n## Anti-patterns\n\n- ❌ Walls of text. If a page has more than ~40 words, split it.\n- ❌ Using the full canvas for body copy. Respect 100–160px padding.\n- ❌ Overflowing 1080px vertically. Cropped content is invisible — split the page.\n- ❌ `overflow: auto` \u002F `overflow: scroll` \u002F `overflow: hidden` to \"hide\" too much content. The canvas doesn't scroll; you've just hidden the bug.\n- ❌ Shrinking type below the scale's lower bound, or padding below 100px, to cram more in. Split instead.\n- ❌ Bullets that wrap to a second line — either shorten or move to its own page.\n- ❌ Body type under 28px — unreadable on a projector.\n- ❌ Inconsistent palette across pages.\n- ❌ Installing packages. Only `react` and standard web APIs are available.\n- ❌ Writing CSS to a shared file. Inline styles or scoped classnames only.\n- ❌ Creating `README.md` or other prose files inside the slide folder.\n- ❌ Editing `package.json`, `open-slide.config.ts`, or other slides.\n- ❌ Sprinkling `\u003CImagePlaceholder>` across pages \"for visual interest\". Placeholders are for content the user owns; they're not stock-photo slots.\n- ❌ Using a placeholder for an icon or decorative shape — those are typography\u002FSVG problems, not asset problems.\n",{"name":5,"description":7},"main","74cd3c4137064fdcde71ed9fe5c4bff58921d899","tools\u002F.agents\u002Fskills\u002Fslide-authoring",0,"https:\u002F\u002Fgithub.com\u002Farkhe-genesis\u002FArkhe-OS","https:\u002F\u002Fgithub.com\u002Farkhe-genesis","2026-11-08 09:08:55",{"source":8,"skillName":5,"commands":62,"prompt":72,"zipAvailable":73},[63,66,69],{"tool":64,"command":65},"npx","npx skills add arkhe-genesis\u002FArkhe-OS --skill slide-authoring",{"tool":67,"command":68},"bunx","bunx skills add arkhe-genesis\u002FArkhe-OS --skill slide-authoring",{"tool":70,"command":71},"pnpm","pnpm dlx skills add arkhe-genesis\u002FArkhe-OS --skill slide-authoring","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Farkhe-genesis\u002FArkhe-OS\u002Fblob\u002Fmain\u002Ftools\u002F.agents\u002Fskills\u002Fslide-authoring\u002FSKILL.md",true,[],[76,99,116,134,159,176],{"skillNo":77,"name":78,"nameZh":6,"description":79,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":80,"categories":81,"keywords":82,"publishedAt":49},"01M6MN97RPP1Q9BG489WHW70R8","career-ops","AI job search command center -- evaluate offers, generate CVs, scan portals, track applications","https:\u002F\u002Fgithub.com\u002Farkhe-genesis\u002FArkhe-OS\u002Fblob\u002Fmain\u002Ftools\u002F.ai-integrations\u002Fvscode\u002F.claude\u002Fskills\u002Fcareer-ops\u002FSKILL.md",[],[83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98],"ops","career","career ops","track","applications","evaluate","mode","true","command center","cvs","scan","command","offers","Job Search","search","generate",{"skillNo":100,"name":101,"nameZh":6,"description":102,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":103,"categories":104,"keywords":105,"publishedAt":49},"01M6MN93GFX8W9J1PCKDKZVD3N","zoom-out","Tell the agent to zoom out and give broader context or a higher-level perspective. Use when you're unfamiliar with a section of code or need to understand how it fits into the bigger picture.","https:\u002F\u002Fgithub.com\u002Farkhe-genesis\u002FArkhe-OS\u002Fblob\u002Fmain\u002Ftools\u002F.agents\u002Fskills\u002Fzoom-out\u002FSKILL.md",[],[106,107,108,42,109,110,111,112,90,113,32,114,115],"zoom out","zoom","use","context","code","it","perspective","re","with","understand",{"skillNo":117,"name":118,"nameZh":6,"description":119,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":120,"categories":121,"keywords":125,"publishedAt":49},"01M6MN8Y2ETBC91BGREF4D39JH","write-a-skill","Create new agent skills with proper structure, progressive disclosure, and bundled resources. Use when user wants to create, write, or build a new skill.","https:\u002F\u002Fgithub.com\u002Farkhe-genesis\u002FArkhe-OS\u002Fblob\u002Fmain\u002Ftools\u002F.agents\u002Fskills\u002Fwrite-a-skill\u002FSKILL.md",[122],{"categoryNo":123,"categoryName":124,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[31,126,127,114,128,129,130,131,132,108,133,45],"write a skill","progressive disclosure","resources","new agent","structure","new skill","build","user",{"skillNo":135,"name":136,"nameZh":6,"description":137,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":138,"categories":139,"keywords":141,"publishedAt":49},"01M6MN8RWE2V2PPFVPD0G8FHKF","triage","Triage issues through a state machine driven by triage roles. Use when user wants to create an issue, triage issues, review incoming bugs or feature requests, prepare issues for an AFK agent, or manage issue workflow.","https:\u002F\u002Fgithub.com\u002Farkhe-genesis\u002FArkhe-OS\u002Fblob\u002Fmain\u002Ftools\u002F.agents\u002Fskills\u002Ftriage\u002FSKILL.md",[140],{"categoryNo":123,"categoryName":124,"taxonomyType":21,"taxonomyTypeDesc":22},[136,142,143,45,144,145,146,147,148,149,150,108,151,152,153,154,155,156,157,158],"bugs","state machine","requests","machine","feature","roles","issue workflow","manage","issue","issues","state","for","feature requests","prepare","triage issues","workflow","review",{"skillNo":160,"name":161,"nameZh":6,"description":162,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":163,"categories":164,"keywords":168,"publishedAt":49},"01M6MN8KVDBD28672WMER7HPXM","to-prd","Turn the current conversation context into a PRD and publish it to the project issue tracker. Use when user wants to create a PRD from the current context.","https:\u002F\u002Fgithub.com\u002Farkhe-genesis\u002FArkhe-OS\u002Fblob\u002Fmain\u002Ftools\u002F.agents\u002Fskills\u002Fto-prd\u002FSKILL.md",[165],{"categoryNo":166,"categoryName":167,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000031","产品经理",[169,170,108,133,109,171,45,150,172,111,173,174,175],"to prd","prd","publish","issue tracker","project","conversation","tracker",{"skillNo":177,"name":178,"nameZh":6,"description":179,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":180,"categories":181,"keywords":182,"publishedAt":49},"01M6MN8E9CGYVWVDDR0NJEFDBB","to-issues","Break a plan, spec, or PRD into independently-grabbable issues on the project issue tracker using tracer-bullet vertical slices. Use when user wants to convert a plan into issues, create implementation tickets, or break down work into issues.","https:\u002F\u002Fgithub.com\u002Farkhe-genesis\u002FArkhe-OS\u002Fblob\u002Fmain\u002Ftools\u002F.agents\u002Fskills\u002Fto-issues\u002FSKILL.md",[],[151,183,184,173,185,186,172,187,188,175,150,189,108,133,40,190,191,170,45],"to issues","spec","down","break","break down","tickets","implementation","convert","plan"]