Agent Skills

presentation-maker

Build a complete, on-brand presentation from a single topic or outline file. The skill is a pipeline of small, single-purpose scripts — one command per stage — so each step is inspectable, debuggable, and composable.

Russian triggers: сделай презентацию, презентация, слайды, pptx, сделай доклад, собери слайды, структура слайдов, аутлайн презентации, 16:9 слайды, презентация в powerpoint.

Pipeline

topic / outline.md
      │  strategy.py            (pick narrative arc + mood + density + layouts)
      ▼
   deck.md  ──(deck_md.py)──▶  deck.json
      │
      ├──(build_html.py)──▶  slides.html
      │      внутри build_html.py уже вызываются (не отдельные ручные шаги):
      │        • content_profile.py  [Слой 1: роль/вес/геометрия каждого слайда]
      │        • creative_brief.py   [Слой 2: ритм + сигнатурный приём деки, seed = title+topic+audience]
      │        • composer.py         (выбор параметров ограничен profile+brief, не голый хэш)
      │        • fit_solver.py       [Слой 3: геометрия в реальном CSS деки, retry до 3 попыток]
      │      побочные файлы рядом с slides.html: .profile.json, .brief.json, .fit_report.json
      │
      ├──(verify_slides.py slides.html --spec deck.json)──▶ PASS/FAIL   [геометрия, MANDATORY]
      │
      ├──(vision_qa.py shoot slides.html)──▶ скриншоты + рубрика
      │      АГЕНТ смотрит на каждый скриншот (инструментом чтения изображений,
      │      не текстом!) и оценивает по 7-пунктовой рубрике, затем:
      │  (vision_qa.py record slides.html --slide N --verdict PASS|FAIL ...)  ×N
      │  (vision_qa.py finalize slides.html)──▶ PASS/FAIL   [Слой 4, MANDATORY]
      │      без реального просмотра слайд считается непроверенным = FAIL,
      │      автоматического "PASS по умолчанию" нет
      │
      ├──(build_pptx.py deck.json deck.pptx)──▶ qa_pptx.py ──▶ PASS/FAIL  [геометрия PPTX]
      ├──(build_pdf.py)──▶ deck.pdf   (из slides.html, Playwright)
      ├──(deck_audit.py)──▶ quality report (JSON)
      └──(qa_bento.py *.bento.html)──▶ PASS/FAIL  [structural validation]

Дека НЕ считается готовой, пока не пройдены все четыре gate: verify_slides.py PASS, fit_solver PASS внутри build_html.py (смотри .fit_report.json), vision_qa.py finalize PASS (реально просмотрено, не имитация), и qa_pptx.py PASS для pptx-варианта. content_profile.py и creative_brief.py также можно запускать отдельно (для отладки/просмотра решений) — build_html.py их не требует как отдельный шаг, но выведет те же .profile.json/.brief.json сам.

Every stage reads/writes the same deck.json contract, so you can regenerate any artifact after editing the spec.

Stage commands

All commands run from the repo root. Scripts live in scripts/.

python3 skills/presentation-maker/scripts/strategy.py --goal keynote
python3 skills/presentation-maker/scripts/strategy.py --audience "SaaS investors" --topic "Series A"
python3 skills/presentation-maker/scripts/strategy.py --list          # all presets
python3 skills/presentation-maker/scripts/strategy.py --show pitch    # one preset

Flags: --goal (pitch|consulting|keynote|report|edu), --audience, --topic, --language (ru|en), --list, --show <goal>. If goal is omitted it is inferred from audience/topic keywords, else defaults to pitch. The chosen strategy (arc / mood / density / palette_name / layouts) is auto-applied by deck_md.py when the matching frontmatter fields are absent.

2. Outline → spec

python3 skills/presentation-maker/scripts/deck_md.py outline.md -o deck.json
# overrides (take precedence over frontmatter):
python3 skills/presentation-maker/scripts/deck_md.py outline.md -o deck.json \
    --goal keynote --audience "investors" --lang ru --palette swift --tone confident

Flags: positional md (topic or outline file), --out (default deck.json), --goal, --audience, --tone, --palette (theme name or mood), --lang/--language. The outline format is documented in references/strategy.md; in short: a leading YAML-ish frontmatter (title, goal, audience, language, theme, density, topic) followed by slide blocks separated by a line containing only ---, each starting with # Headline.

3. HTML slides (16:9)

python3 skills/presentation-maker/scripts/build_html.py deck.json slides.html

Builds from the modular base (templates/base.html — tokens, typography, components, navigation, all pattern/composition CSS included). Internally runs content_profilecreative_briefcomposer (constrained by both) → fit_solver (geometry retry, up to 3 attempts per slide) before writing the final HTML — see the Pipeline diagram above. Writes slides.profile.json, slides.brief.json, slides.fit_report.json next to the output for inspection. If any slide still fails fit after retries, the build succeeds but prints the failing slide + reason to stderr — check .fit_report.json before treating the deck as done. Output is a self-contained 16:9 deck.

4. Verification gate (MANDATORY)

python3 skills/presentation-maker/scripts/verify_slides.py slides.html --spec deck.json

Runs in real Chromium (Playwright) and checks, per slide: a heading + non-empty content, no horizontal overflow, cards/rows hold their content (no clipping or spill), text containers do not clip, and keyboard navigation switches slides. Exit 0 = pass; exit 1 = fail.

4b. Visual QA gate (MANDATORY) — vision_qa.py

python3 skills/presentation-maker/scripts/vision_qa.py shoot slides.html --out-dir vision_shots

Screenshots every slide (via .active toggling, waiting out the CSS transition) and prints the fixed 7-point rubric + the list of image paths. This script cannot judge the images itself — only the agent running the skill has vision. The agent MUST view each screenshot (image-reading tool, not by re-reading the JSON) and score it against the printed rubric, then record every verdict:

python3 skills/presentation-maker/scripts/vision_qa.py record slides.html \
    --slide 4 --verdict PASS --recommendation "..."   # one call per slide
python3 skills/presentation-maker/scripts/vision_qa.py finalize slides.html

finalize exits 0 only if every slide has a recorded verdict AND all are PASS. A slide with no recorded verdict is FAIL (“не проверено”), never a silent pass — there is no structural auto-pass fallback. Ни одна презентация не считается готовой, пока не пройдены все четыре gate: fit_solver PASS (Слой 3, внутри build_html.py — см. .fit_report.json), verify_slides.py PASS, vision_qa.py finalize PASS (Слой 4, реально просмотрено агентом), qa_pptx.py PASS (для pptx-варианта).

5. PowerPoint

python3 skills/presentation-maker/scripts/build_pptx.py deck.json deck.pptx

Draws a real .pptx via python-pptx on a 1600×900 design canvas (13.333×7.5”, 16:9, PX=7620 EMU/px): all 14 slide types rendered through the shared PPTX design system — eyebrow, ghost page numbers, chrome (logo + page indicator), decor ovals, tinted “sandwich” bookends, shadowed cards, numbered step ovals, square bullet markers, oversized metrics/quote/hero numbers. Fonts are Arial (never Inter — LibreOffice substitutes matter for QA). See “PPTX design system” below for the full element set and contracts.

# geometric QA gate — run after every build (exit 0 = pass):
python3 skills/presentation-maker/scripts/qa_pptx.py deck.pptx --render

Checks per slide: shapes inside canvas, content above BOTTOM_STOP, no text-overlap, tables fit; --render additionally exports JPEGs via LibreOffice → pdftoppm for human/vision review. Design elements named ghost*, decor*, chrome-* are exempt from bounds/content checks.

intern (MIT) is an open-source CLI linter for .pptx: alignment (CLOSE_X/CLOSE_Y), text quality (DOUBLE_SPACE, EMPTY_TEXTBOX, REPEATED_WORD), margins, font/color variety. It catches issues our geometric gate does not model — it already found a real bug (triple spaces around · in the footer).

Install once (any of):

brew install markusz/intern/intern        # macOS
# or prebuilt binary: curl -L https://github.com/markusz/intern/releases/latest/download/intern-$(uname -m|sed s/x86_64/x86_64-apple-darwin/|sed s/arm64/aarch64-apple-darwin/).tar.gz | tar xz

Run through our wrapper (it whitelists design-system elements by shape name — ghost*, decor*, chrome-*, quote-*, process-card, step-num, toc-* — and can drop token rules for token-driven decks):

python3 skills/presentation-maker/scripts/qa_intern.py deck.pptx --skip-token-rules
# exit 0 = clean after design-filter; 1 = real violations; 2 = intern missing/error

--skip-token-rules ignores FONT_SIZE_VARIETY/COLOR_VARIETY — our design system intentionally uses a token hierarchy (eyebrow 11pt … metrics 64pt, quote mark 120pt). For non-token decks omit it to keep those checks.

6. PDF export

python3 skills/presentation-maker/scripts/build_pdf.py slides.html deck.pdf
# optional: python3 skills/presentation-maker/scripts/build_pdf.py slides.html deck.pdf --viewport 1600x900

Renders the same themed slides.html into a multi-page 16:9 PDF (one slide per page) using Playwright — no separate layout/theme is re-implemented, so the PDF is visually 1:1 with the HTML. See references/pdf.md.

7. Quality audit

python3 skills/presentation-maker/scripts/deck_audit.py deck.json --html slides.html

Deterministic, browser-free aesthetic gate (exit 0/1). Checks WCAG contrast, no raw hex outside :root, ≤4 accent roles, assertion headlines, words-per-slide budget, and a single mood across the deck. See references/audit.md.

JSON spec schema (deck.json)

{
  "title": "Deck title",
  "goal": "keynote",                 // pitch|consulting|keynote|report|edu
  "topic": "optional topic",
  "audience": "optional audience",
  "language": "ru",                  // ru|en
  "tone": "optional voice note",
  "theme": {
    "name": "swift",                // theme file name (see templates/themes/)
    "mood": "glass",                // swiss|editorial|flat|glass|dark
    "palette": {                    // injected into :root CSS variables
      "primary": "#007AFF",
      "background": "#FFFFFF",
      "card": "#F5F5F7",
      "stroke": "#E5E5EA",
      "background_text": "#FFFFFF",  // text on primary
      "primary_text": "#1C1C1E",
      "muted": "#6E6E73",
      "accent_soft": "#E8F0FE",
      "graph_0": "#007AFF",          // up to graph_4
      "font": "Inter",
      "font_display": "Inter",
      "font_url": "https://...",     // optional web font
      "mood": "glass",
      "radius": "18px",
      "radius_sm": "10px",
      "eyebrow_track": "uppercase"
    }
  },
  "strategy": {
    "arc": "sparkline",
    "density": "concise",            // concise|standard|text-heavy
    "layouts": ["big_number", "quote", "divider"]
  },
  "slides": [ /* slide objects, see below */ ]
}

Slide object (content)

Each slide has a type (or auto/omitted → inferred from content) plus type-specific fields. Common types and their key fields:

type key fields
title / closing title, subtitle?, presenter?, date?
divider title, subtitle?
bullets title, bullets[]
comparison title, columns[]{heading, points[]}
table title, table{headers[], rows[][], highlight_col?}
chart title, chart{categories[], series[]→{name,values[]}, note?}
process title, steps[]
metrics title, metrics[]{value, label, icon?}
big_number title?, value, label?, subtitle?, accent?
quote title?, quote, attribution?
feature title, features[]{title, text?, icon?}
image_showcase title, image, desc?, points?
timeline title, items[]{title, desc?}
kpi_row title, kpis[] / metrics[]
logos title, logos[], note?
table_of_contents title, items[]{title, desc?}
centered_header title, subtitle?, panel?

Valid type values: title, divider, bullets, comparison, table, chart, process, metrics, feature, big_number, quote, table_of_contents, timeline, image_showcase, centered_header, kpi_row, logos, closing.

Theme + palette model

Themes are JSON files in templates/themes/ (names: general, modern, executive, momentum, swift, standard, dynamic). Each provides a palette (the :root CSS variables above) and a mood. A mood is one of swiss | editorial | flat | glass | dark and drives the aesthetic regime; DEFAULT_THEMES maps each mood to the nearest theme file (swiss→executive, editorial→standard, flat→modern, glass→swift, dark→dynamic). Icons for metrics/feature slides live in templates/icons/ as inline SVG (no emoji).

Layout families

build_html.py and build_pptx.py share a RENDERERS map keyed by slide type. When type is auto/missing, pick_layout() infers the best fit from content keys (quote → quote, columns → comparison, steps → process, metrics → metrics, numeric table → chart, text table → table, features → feature, logos → logos, etc.), avoiding repeating the previous slide’s type when plausible.

Generative composition layer (v4.0)

Every slide’s composition is synthesized from scratch — not picked from a template list. scripts/composer.py derives a deterministic parameter set from a deck seed (title + date + slide index):

So the same deck rebuilt on another day gets a different composition mix (deterministic and reproducible via the seed). The pattern files in templates/patterns/*.json remain as reference recipes (ideas for the parameter space), not as a fixed menu. verify_slides.py, deck_audit.py, qa_pptx.py, qa_intern.py gates run unchanged.

Accent embedding (two brand colors, no mixing)

Decks may carry two brand accents (e.g. teal primary + rose accent). They are never blended in one element, and text on an accent-colored block is always on-primary (white). The accent is woven into individual slides via modes (build_html.pypick_accent_mode(), spread across the deck, never repeated on adjacent slides):

Set the two accents in the theme: primary (structure: headings, lines, markers, gradients, duotones) and accent (accent points only). Graphs stay in the primary family so gradients/duotones never mix the two brands.

Typography floor (card text)

Body text inside cards must stay readable at 16:9 projection — floor 17px, labels ≥ 17px, metric values 30–48px, timeline descriptions ≥ 15px. Headings scale via --t-* tokens. verify_slides.py re-checks overflow after any font-size change.

Anti-template design rules

Summarized from references/design-system.md (full rules there). Enforced mechanically by deck_audit.py:

PPTX design system (build_pptx.py)

build_pptx.py renders every slide on a 1600×900 design canvas (13.333×7.5”, PX = 7620 EMU/px). Fixed contracts:

Constant Value Meaning
MARGIN_X 96 px horizontal page margin
TITLE_Y / TITLE_H 56 / 96 px title band (autofits ≤ 2 lines)
CONTENT_Y 180 px all content starts below the title band
BOTTOM_STOP 80 px nothing may end lower than H - 80
Font Arial everywhere LibreOffice-safe; never Inter in PPTX

Full element set

# Element Where Spec
1 eyebrow title, divider, toc, quote, closing, content 12 pt bold, tracking 3.6, accent_soft on dark / primary on light; y≈88
2 ghost-num every slide huge translucent page number; name ghost-numexempt from QA bounds
3 chrome every slide logo 30×30 (chrome-logo) + NN / NN page indicator (chrome-page) — exempt
4 decor-ovals title, divider, closing translucent ovals (alpha 15–22%) in graph_1; name decor — exempt
5 tinted sandwich title / divider / closing dark primary background, light text; content slides use background
6 cards bullets, comparison, metrics, process, timeline, feature, toc rounded rect + shadow (blur 10 / dist 3 / alpha 9%), stroke p.stroke
7 step-num / toc-num process, timeline, toc numbered OVAL 36–44 px, NN/01 labels
8 square bullet markers bullets (style="cards") bullet-marker squares in accent color
9 hairline comparison 2 px divider line under column heading
10 metric value metrics 64 pt bold (min 30), color cycles graph_0..7
11 hero number big_number 110 pt bold (min 40) + 30 pt label + 18 pt subtitle
12 opening quote quote 120 pt bold " (min 80), quote 34 pt, attribution 20 pt muted
13 arrow → process 22 pt between step cards

Rules

Dependencies

References

Полный список справочных файлов — в references/references.md.

Boundaries