Back to Skills

winston-presentations

by Ian Cook

Patrick Winston-inspired presentation coaching and deck revision. Use when the user wants help creating, restructuring, tightening, or rehearsing a talk, keynote, lecture, pitch, or slideshow, especially when they share a .pptx deck. Extracts slide text and speaker notes from PPTX files, then critiques and rewrites content, structure, pacing, openings, transitions, and endings using Winston-style heuristics from Lore. Do NOT use for pixel-level visual design polish from screenshots alone.

0.1.0
$ npx skills add https://github.com/ianpcook/skills-nat --skill winston-presentations

Files

SKILL.mdMain
5.5 KB
---
name: winston-presentations
version: "0.1.0"
author: "Ian Cook"
category: "Productivity"
license: "MIT"
compatibility: "Works best in OpenClaw. Also usable in Claude Code, Cursor, or Codex when Python 3 is available and Winston source material is accessible."
description: Patrick Winston-inspired presentation coaching and deck revision. Use when the user wants help creating, restructuring, tightening, or rehearsing a talk, keynote, lecture, pitch, or slideshow, especially when they share a .pptx deck. Extracts slide text and speaker notes from PPTX files, then critiques and rewrites content, structure, pacing, openings, transitions, and endings using Winston-style heuristics from Lore. Do NOT use for pixel-level visual design polish from screenshots alone.
metadata: {"openclaw":{"emoji":"🎤","requires":{"bins":["python3"]}}}
---

# Winston Presentations

Help the user make a presentation stronger in the style of Patrick Winston.

This skill is for:
- starting a talk from a blank page
- revising an existing deck
- tightening a long presentation
- improving pacing, transitions, and narrative flow
- turning a PPTX into a critiqueable text representation

This skill is **not** for:
- fine-grained visual design critique from raw PPTX structure alone
- animations, fonts, theme files, or layout QA
- speaker teleprompter scripting without first understanding the talk structure

## Inputs this skill can handle

- a rough topic or talk goal
- a plain-text outline
- notes pasted into chat
- a `.pptx` file containing slide text and speaker notes

## First move

Before giving major advice, look at Winston source material in Lore.

Start with at least these searches:
- `lore search "Patrick Winston How to Speak" --limit 5`
- `lore search "Patrick Winston teaching heuristics" --limit 5`
- `lore search "Patrick Winston lecture theatre" --limit 5`

Use the Lore material as the primary source. Do not rely on internet paraphrases if the Winston corpus in Lore already covers the point.

See `references/winston-principles.md` for the distilled working rules.

## Workflow

### 1. Understand the presentation job

Establish or infer:
- audience
- desired action or takeaway
- time budget
- setting (conference, internal review, board, keynote, workshop, sales, fundraising, classroom)
- whether the goal is to inform, persuade, teach, or win approval

If any of those are missing and the omission blocks good advice, ask briefly.

### 2. If the user provides a PPTX, extract it first

Run:

```bash
python3 {baseDir}/scripts/pptx_extract.py /path/to/deck.pptx --markdown
```

This outputs a text representation of:
- slide titles
- body text
- speaker notes
- word counts per slide

If the user wants a machine-readable version, use:

```bash
python3 {baseDir}/scripts/pptx_extract.py /path/to/deck.pptx --json
```

### 3. Diagnose the deck or outline

Evaluate the talk on Winston dimensions:

1. **Promise** — Does the opening clearly state what the audience will be able to do, understand, decide, or remember?
2. **Throughline** — Is there a clean spine, or just a pile of adjacent facts?
3. **Cycle** — Does the talk preview, deliver, and reinforce key points?
4. **Stories / examples** — Are there concrete examples, near-misses, or memorable cases?
5. **Powerful ideas** — Does it teach something consequential, not just a procedure?
6. **Slide discipline** — Are slides supporting speech, or competing with it?
7. **Pacing** — Is there enough breathing room for emphasis, transitions, and human comprehension?
8. **Ending** — Does the talk land cleanly, or just stop?

### 4. Produce useful output, not vague praise

Default output structure:

1. **Diagnosis** — what is weak, strong, and confused
2. **Recommended structure** — a better arc for the whole talk
3. **Slide surgery** — what to cut, merge, reorder, or rewrite
4. **Pacing plan** — how much time per section and where to slow down
5. **Opening / closing options** — specific language when useful
6. **Next draft guidance** — what the user should change first

If the user shared a deck, be concrete by slide number.

### 5. Offer the next layer

After the critique, offer one or more of these:
- revised outline
- revised slide-by-slide structure
- speaker notes / talk track
- shorter version for a stricter time budget
- Winston-style opening and ending
- a “cut ruthlessly” pass for overloaded decks

## Review standards

A good Winston-style recommendation should usually do most of these:
- lead with audience empowerment, not topic throat-clearing
- favor memorable examples over abstract exposition
- reduce slide text density
- make transitions explicit
- make the big idea unmistakable
- preserve the speaker as the main event, with slides as support

## Important limitation: PPTX reading

The extractor reads textual content and speaker notes from PPTX files.
It does **not** reliably capture:
- visual hierarchy
- color choices
- precise object placement
- animation timing
- image quality

So if the user wants design critique, ask for screenshots, PDF export, or images of key slides.

## When the deck is weak

Be direct. Do not flatter a confused talk.

Say things like:
- “The deck has information, but no promise.”
- “This feels like a memo chopped into slides.”
- “You are making the audience read instead of listen.”
- “The talk does not yet know what it wants the audience to carry out of the room.”

Then fix it.

## Files

- Winston principles: `references/winston-principles.md`
- PPTX extractor: `scripts/pptx_extract.py`
references/winston-principles.md
4.3 KB
# Winston Principles

Distilled from the Winston corpus in Lore, especially:
- How to Speak (lecture transcript)
- MIT OCW course page
- Teaching Heuristics
- Large Lecture as Theatre
- speaking.pdf

Use these as primary-source guidance.

## 1. Begin with a promise

Winston repeatedly says to start with an **empowerment promise**.

The audience should know, early, what they will be able to do, understand, or decide by the end.

Bad opening:
- topic throat-clearing
- autobiography
- agenda with no payoff

Better opening:
- “By the end of this talk, you’ll know X.”
- “I want to show you how to Y.”
- “You’ll leave with a way to decide Z.”

## 2. Cycle the main idea

Winston explicitly recommends cycling the main content.

Practical adaptation:
- preview the idea
- develop it
- return to it in stronger form

Not all talks need a cheesy “tell them what you’ll tell them” template, but the audience should not hear the central idea only once.

## 3. Ask questions that create tension

A carefully chosen question can create curiosity and orient the room.

Questions should:
- be answerable within the logic of the talk
- create appetite for the next section
- sharpen the promise

Do not use random engagement theater. The question has to matter.

## 4. Teach powerful ideas, not just procedures

Winston’s teaching heuristics emphasize that skills alone are not enough.

A good presentation should include:
- what matters
- why it matters
- what larger pattern it belongs to
- what people should carry beyond the specific case

If the deck is just a sequence of steps, enrich it with the bigger idea.

## 5. Use stories and examples

Winston values stories as central to intelligence and education.

A presentation improves when it includes:
- concrete examples
- case studies
- near-misses
- revealing anecdotes
- examples of doubt, failure, or resistance

Stories are not decoration. They are the memory system.

## 6. Slides are condiments, not the meal

This is one of the most important working rules.

The speaker is primary. Slides support the speaker.

Implications:
- reduce text density
- do not duplicate the exact spoken sentence on the slide
- avoid making the audience choose between reading and listening
- use slides to anchor, illustrate, or punctuate, not to replace speech

When a slide contains too much text, say so plainly.

## 7. Prefer progressive revelation where possible

Winston likes the board partly because it unfolds at human speed.

Practical adaptation for modern decks:
- reveal ideas in stages
- avoid overwhelming summary slides too early
- build complexity gradually
- make the audience track one thing at a time

Even in static slides, structure should mimic revelation instead of dumping.

## 8. Use verbal punctuation and explicit transitions

One thing many decks lack is spoken structure.

The presenter should signal movement:
- “First…”
- “Now the important shift…”
- “So far we’ve established…”
- “This matters because…”
- “Let me give you the example that makes this concrete.”

A talk with weak transitions feels longer than it is.

## 9. Performance matters

From “Large Lecture as Theatre”:
- lectures become performance at scale
- preparation is extensive
- rehearsal is part of the work
- room energy matters

So when advising on a talk, include:
- where to slow down
- where to emphasize
- where to pause
- where the speaker needs energy, contrast, or release

## 10. End cleanly and memorably

Winston likes ending with something fun or satisfying.

In practice, the ending should do one or more of these:
- restate the central contribution
- return to the promise and fulfill it
- leave the audience with a strong image, question, or line
- make the next action obvious

Avoid weak endings such as:
- “That’s all I have”
- limp Q&A handoff
- generic thank-you slide with no final thought

## How to use this file in critiques

When reviewing a deck, score it informally against these questions:

1. What is the promise?
2. What is the big idea?
3. What will the audience remember?
4. Where is the story?
5. Which slides are stealing attention from the speaker?
6. Where does the talk drag?
7. Does the ending pay off the beginning?

If the answer to several of those is fuzzy, the talk needs restructuring before line editing.
scripts/pptx_extract.py
6.4 KB
#!/usr/bin/env python3
"""Extract text and speaker notes from a .pptx deck.

Outputs either markdown or JSON so an agent can critique structure, pacing,
and content without needing PowerPoint itself.
"""

from __future__ import annotations

import argparse
import json
import sys
import zipfile
from pathlib import Path
from xml.etree import ElementTree as ET

NS = {
    "a": "http://schemas.openxmlformats.org/drawingml/2006/main",
    "p": "http://schemas.openxmlformats.org/presentationml/2006/main",
    "r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
    "rel": "http://schemas.openxmlformats.org/package/2006/relationships",
}

TITLE_TYPES = {"title", "ctrTitle", "subTitle"}
NOTES_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide"


def read_xml(zf: zipfile.ZipFile, name: str) -> ET.Element:
    return ET.fromstring(zf.read(name))


def text_from_elem(elem: ET.Element) -> str:
    texts = []
    for t in elem.findall('.//a:t', NS):
        if t.text:
            texts.append(t.text)
    return " ".join(part.strip() for part in texts if part and part.strip()).strip()


def slide_rels(zf: zipfile.ZipFile, slide_no: int) -> dict[str, str]:
    rel_path = f'ppt/slides/_rels/slide{slide_no}.xml.rels'
    if rel_path not in zf.namelist():
        return {}
    root = read_xml(zf, rel_path)
    out = {}
    for rel in root.findall('rel:Relationship', NS):
        rid = rel.attrib.get('Id')
        target = rel.attrib.get('Target', '')
        if rid and target:
            out[rid] = target
    return out


def normalize_target(base: str, target: str) -> str:
    base_parts = Path(base).parent
    return str((base_parts / target).as_posix()).replace('../', 'ppt/')


def extract_slide(zf: zipfile.ZipFile, slide_no: int) -> dict:
    slide_path = f'ppt/slides/slide{slide_no}.xml'
    root = read_xml(zf, slide_path)

    title = ''
    subtitle = ''
    bodies = []

    for sp in root.findall('.//p:sp', NS):
        ph = sp.find('.//p:nvSpPr/p:nvPr/p:ph', NS)
        ph_type = ph.attrib.get('type') if ph is not None else None
        txt = text_from_elem(sp)
        if not txt:
            continue
        if ph_type in TITLE_TYPES:
            if ph_type == 'subTitle' and not subtitle:
                subtitle = txt
            elif not title:
                title = txt
            else:
                bodies.append(txt)
        else:
            bodies.append(txt)

    if not title and bodies:
        title = bodies[0][:120]

    notes = ''
    rels = slide_rels(zf, slide_no)
    notes_rel = None
    for rid, target in rels.items():
        rel_path = f'ppt/slides/_rels/slide{slide_no}.xml.rels'
        rel_root = read_xml(zf, rel_path)
        for rel in rel_root.findall('rel:Relationship', NS):
            if rel.attrib.get('Id') == rid and rel.attrib.get('Type') == NOTES_REL:
                notes_rel = normalize_target(slide_path, target)
                break
        if notes_rel:
            break
    if notes_rel and notes_rel in zf.namelist():
        notes_root = read_xml(zf, notes_rel)
        notes = text_from_elem(notes_root)

    body_word_count = sum(len(b.split()) for b in bodies)
    notes_word_count = len(notes.split()) if notes else 0

    return {
        'slide_number': slide_no,
        'title': title,
        'subtitle': subtitle,
        'body': bodies,
        'notes': notes,
        'body_word_count': body_word_count,
        'notes_word_count': notes_word_count,
    }


def extract_pptx(path: Path) -> dict:
    with zipfile.ZipFile(path) as zf:
        slide_nums = []
        for name in zf.namelist():
            if name.startswith('ppt/slides/slide') and name.endswith('.xml'):
                try:
                    slide_nums.append(int(Path(name).stem.replace('slide', '')))
                except ValueError:
                    pass
        slide_nums.sort()
        slides = [extract_slide(zf, n) for n in slide_nums]

    deck_title = slides[0]['title'] if slides and slides[0]['title'] else path.stem
    total_body_words = sum(s['body_word_count'] for s in slides)
    total_notes_words = sum(s['notes_word_count'] for s in slides)
    return {
        'file': str(path),
        'deck_title': deck_title,
        'slide_count': len(slides),
        'total_body_words': total_body_words,
        'total_notes_words': total_notes_words,
        'slides': slides,
    }


def to_markdown(deck: dict) -> str:
    lines = []
    lines.append(f"# {deck['deck_title']}")
    lines.append('')
    lines.append(f"- File: `{deck['file']}`")
    lines.append(f"- Slides: {deck['slide_count']}")
    lines.append(f"- Total slide-body words: {deck['total_body_words']}")
    lines.append(f"- Total speaker-notes words: {deck['total_notes_words']}")
    lines.append('')
    for slide in deck['slides']:
        lines.append(f"## Slide {slide['slide_number']}: {slide['title'] or '[untitled]'}")
        lines.append('')
        if slide['subtitle']:
            lines.append(f"**Subtitle:** {slide['subtitle']}")
            lines.append('')
        if slide['body']:
            lines.append('**Slide text:**')
            for item in slide['body']:
                lines.append(f"- {item}")
            lines.append('')
        else:
            lines.append('**Slide text:** *(none detected)*')
            lines.append('')
        if slide['notes']:
            lines.append('**Speaker notes:**')
            lines.append(slide['notes'])
            lines.append('')
        lines.append(f"**Stats:** slide words={slide['body_word_count']}, notes words={slide['notes_word_count']}")
        lines.append('')
    return '\n'.join(lines).strip() + '\n'


def main() -> int:
    ap = argparse.ArgumentParser(description='Extract text and notes from a PPTX deck')
    ap.add_argument('pptx', help='Path to a .pptx file')
    fmt = ap.add_mutually_exclusive_group()
    fmt.add_argument('--markdown', action='store_true', help='Output markdown (default)')
    fmt.add_argument('--json', action='store_true', help='Output JSON')
    args = ap.parse_args()

    path = Path(args.pptx).expanduser()
    if not path.exists():
        print(f'File not found: {path}', file=sys.stderr)
        return 1
    if path.suffix.lower() != '.pptx':
        print('Expected a .pptx file', file=sys.stderr)
        return 1

    deck = extract_pptx(path)
    if args.json:
        print(json.dumps(deck, indent=2, ensure_ascii=False))
    else:
        print(to_markdown(deck))
    return 0


if __name__ == '__main__':
    raise SystemExit(main())

Compatible Agents

Claude CodeclaudeCodexOpenClawAntigravityGemini

Details

Category
Productivity
Version
0.1.0
Stars
0
Added
April 18, 2026
Updated
April 18, 2026

Actions

Download .zip

Upload this .zip to Claude Desktop via Settings → Capabilities → Skills

Vote: