Initial commit
This commit is contained in:
424
skills/presentation-master/README.md
Normal file
424
skills/presentation-master/README.md
Normal file
@@ -0,0 +1,424 @@
|
||||
# Presentation Master
|
||||
|
||||
> **World-class presentation creation skill that embodies best practices from presentation masters and adapts to your needs.**
|
||||
|
||||
## Overview
|
||||
|
||||
Presentation Master is not just a presentation generator—it's a **presentation coach** that teaches world-class design principles while creating slides. Built on decades of wisdom from Garr Reynolds, Nancy Duarte, Guy Kawasaki, Seth Godin, TED speakers, Edward Tufte, and Steve Jobs, this skill ensures every presentation meets the highest standards.
|
||||
|
||||
## Key Innovation
|
||||
|
||||
Instead of just making slides, this skill:
|
||||
- **Teaches** presentation best practices through guided creation
|
||||
- **Validates** against proven design principles automatically
|
||||
- **Adapts** to different presentation types and audiences
|
||||
- **Coaches** you through checkpoints to ensure quality
|
||||
- **Learns** from each presentation to improve future recommendations
|
||||
|
||||
## What Makes a Great Presentation?
|
||||
|
||||
Based on research of thousands of successful presentations, the masters agree on these principles:
|
||||
|
||||
1. **Simplicity** - Less is always more (Seth Godin: 6 words max per slide)
|
||||
2. **Visual Dominance** - Show, don't write (Garr Reynolds: Pictures > text)
|
||||
3. **Story Structure** - Random facts don't stick; stories do (Nancy Duarte: Sparkline)
|
||||
4. **One Idea Per Slide** - Cognitive load is real (Guy Kawasaki: 10 slides max)
|
||||
5. **Audience as Hero** - It's their transformation, not your information (Duarte)
|
||||
6. **Data Integrity** - Visual truth matters (Edward Tufte: Lie factor 0.95-1.05)
|
||||
|
||||
## Features
|
||||
|
||||
### Guided Creation with Checkpoints
|
||||
|
||||
**Phase 1: Discovery & Context Analysis**
|
||||
- Analyzes topic, audience, duration, purpose
|
||||
- Detects presentation type (board update, keynote, training, TED-style)
|
||||
- Recommends story framework
|
||||
|
||||
**Phase 2: Content Development**
|
||||
- Researches topic if needed
|
||||
- Extracts key concepts (max 10 per Kawasaki)
|
||||
- Drafts slide outline with one concept per slide
|
||||
- Identifies slides needing visuals
|
||||
|
||||
**Phase 3: Visual Strategy**
|
||||
- Proposes image types (infographic, photo, diagram, data viz)
|
||||
- Suggests visual concepts and metaphors
|
||||
- Estimates generation costs
|
||||
- Gets approval before generating
|
||||
|
||||
**Phase 4: Generation & Validation**
|
||||
- Generates approved images in parallel
|
||||
- Builds slides using selected format (PPTX/Slides/Canva)
|
||||
- Applies design rules automatically
|
||||
- Runs validation scoring (0-100)
|
||||
- Generates quality report
|
||||
|
||||
**Phase 5: Iteration & Refinement** (if needed)
|
||||
- Applies requested changes
|
||||
- Re-validates quality
|
||||
- Saves to Obsidian with metadata
|
||||
- Documents learnings
|
||||
|
||||
### Automatic Quality Validation
|
||||
|
||||
Every presentation is scored 0-100 against these criteria:
|
||||
|
||||
- **Simplicity** (10pts): Word count, visual clutter
|
||||
- **Visual Dominance** (10pts): Image quality, text-to-visual ratio
|
||||
- **Story Structure** (10pts): Narrative arc, emotional beats
|
||||
- **One Idea/Slide** (10pts): Concept clarity
|
||||
- **Typography** (8pts): Size (30pt+ minimum), consistency
|
||||
- **Layout** (7pts): Hierarchy, whitespace, alignment
|
||||
- **Color/Contrast** (7pts): Readability (4.5:1 minimum)
|
||||
- **Media Quality** (8pts): Image resolution, relevance
|
||||
- **Cognitive Load** (20pts): Mayer's 12 multimedia principles
|
||||
- **Data Integrity** (10pts): Tufte principles (if applicable)
|
||||
|
||||
**Target Score**: 85+ for high-quality presentations
|
||||
|
||||
### Critical Violations (Auto-Fail)
|
||||
|
||||
- Font size < 30pt
|
||||
- >10 core concepts
|
||||
- Bullet points detected
|
||||
- Paragraphs (>2 sentences)
|
||||
- Poor contrast (<4.5:1)
|
||||
- Default templates
|
||||
|
||||
### Multi-Format Support
|
||||
|
||||
**Phase 1 (Current)**: PPTX
|
||||
- Uses existing pptx skill
|
||||
- Direct PptxGenJS API for simple slides
|
||||
- Saves to Obsidian Research folder
|
||||
|
||||
**Phase 2 (Coming)**: Google Slides
|
||||
- Google Slides API v1
|
||||
- Supports all 3 accounts (psd, kh, hrg)
|
||||
- Returns shareable link
|
||||
|
||||
**Phase 3 (Future)**: Canva
|
||||
- Canva REST API
|
||||
- Auto-applies brand kits
|
||||
|
||||
## Slide Patterns
|
||||
|
||||
Six proven patterns that form the foundation of world-class presentations:
|
||||
|
||||
### 1. Title Slide
|
||||
**Purpose**: Set tone, introduce topic
|
||||
**Elements**: 3-6 words, strong visual or clean typography
|
||||
**Best for**: Opening, section breaks
|
||||
|
||||
### 2. One Big Idea
|
||||
**Purpose**: Maximum impact, single concept
|
||||
**Elements**: 1-3 words max, 60-120pt font
|
||||
**Best for**: Key insights, memorable moments (Seth Godin's 6-word rule)
|
||||
|
||||
### 3. Visual + Caption
|
||||
**Purpose**: Visual storytelling with context
|
||||
**Elements**: Large high-quality image (70-80%), short caption (1 line)
|
||||
**Best for**: Concepts, examples, emotional moments
|
||||
|
||||
### 4. Data Visualization
|
||||
**Purpose**: Show quantitative information clearly
|
||||
**Elements**: Clean charts following Tufte principles
|
||||
**Best for**: Evidence, trends, comparisons
|
||||
|
||||
### 5. Timeline / Process
|
||||
**Purpose**: Show progression, sequence, chronology
|
||||
**Elements**: 3-7 steps, visual connections, minimal text
|
||||
**Best for**: Processes, roadmaps, historical progression
|
||||
|
||||
### 6. Transition / Section Break
|
||||
**Purpose**: Signal major shifts
|
||||
**Elements**: 1-5 words, distinct visual treatment
|
||||
**Best for**: Moving between major sections
|
||||
|
||||
See `principles/slide-patterns.md` for comprehensive details on each pattern.
|
||||
|
||||
## Story Frameworks
|
||||
|
||||
Choose the right narrative structure for your presentation:
|
||||
|
||||
### Nancy Duarte's Sparkline
|
||||
**Duration**: 20-30 minutes
|
||||
**Slides**: 18-25
|
||||
**Best for**: Keynotes, vision casting, inspirational talks
|
||||
**Structure**: Alternate "what is" (reality) with "what could be" (aspiration)
|
||||
|
||||
### Steve Jobs' Rule of Three
|
||||
**Duration**: 15-30 minutes
|
||||
**Slides**: 12-18
|
||||
**Best for**: Product launches, demos, persuasive presentations
|
||||
**Structure**: Three main sections, three points per section
|
||||
|
||||
### TED Talk Structure
|
||||
**Duration**: 15-20 minutes
|
||||
**Slides**: 12-18
|
||||
**Best for**: Idea-centric, inspirational talks
|
||||
**Structure**: Hook → Personal → Core Idea → Call to Action → Close
|
||||
|
||||
### Classic Three-Act Structure
|
||||
**Duration**: 20-45 minutes
|
||||
**Slides**: 15-35
|
||||
**Best for**: Case studies, transformation narratives
|
||||
**Structure**: Setup (25%) → Confrontation (50%) → Resolution (25%)
|
||||
|
||||
See `principles/story-frameworks.md` for detailed breakdowns.
|
||||
|
||||
## Adaptive Pattern Selection
|
||||
|
||||
The skill automatically recommends pattern distribution based on presentation type:
|
||||
|
||||
**Board Update**: 40% Data Viz, 30% Visual+Caption, 20% Transitions, 10% Titles
|
||||
**Keynote**: 40% Big Ideas, 30% Visual+Caption, 20% Titles, 10% Transitions
|
||||
**Training**: 40% Process, 30% Data Viz, 20% Visual+Caption, 10% Titles
|
||||
**Pitch**: 30% Data Viz, 30% Big Ideas, 25% Visual+Caption, 15% Titles/Transitions
|
||||
|
||||
## Image Generation Integration
|
||||
|
||||
Intelligent visual recommendations based on slide content:
|
||||
|
||||
- **Numeric data** → Infographic
|
||||
- **Abstract concepts** → Conceptual image/metaphor
|
||||
- **Concrete examples** → Realistic photography
|
||||
- **Processes/flows** → Diagrams
|
||||
- **Trends/comparisons** → Data visualization
|
||||
|
||||
**Cost Management**:
|
||||
- Shows estimated cost before generating ($0.13-$0.24 per image at 2K)
|
||||
- Allows opt-out of specific images
|
||||
- Tracks spending in presentation metadata
|
||||
|
||||
**Naming Convention**:
|
||||
```
|
||||
{presentation-id}-slide-{number}-{type}.png
|
||||
Example: cybersecurity-2025-slide-02-threat-timeline.png
|
||||
```
|
||||
|
||||
## Brand Integration
|
||||
|
||||
Automatically applies branding:
|
||||
- **PSD presentations**: Uses psd-brand-guidelines skill
|
||||
- **Personal presentations**: Uses personal brand (if defined)
|
||||
- **Client presentations**: Custom brand kit (future)
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
presentation-master/
|
||||
├── SKILL.md # Main skill documentation
|
||||
├── README.md # This file
|
||||
├── package.json # Dependencies
|
||||
├── principles/
|
||||
│ ├── masters.md # Best practices from experts (1,200+ lines)
|
||||
│ ├── validation-rules.md # Quality scoring system
|
||||
│ ├── slide-patterns.md # Template library (3,500+ lines)
|
||||
│ └── story-frameworks.md # Narrative structures (5,000+ lines)
|
||||
├── scripts/
|
||||
│ ├── analyze-context.js # ✅ Detect presentation type & recommend framework
|
||||
│ ├── validate-presentation.js # ✅ Score presentation 0-100
|
||||
│ └── suggest-images.js # ✅ Visual recommendations & cost estimation
|
||||
└── adapters/
|
||||
├── pptx-adapter.js # ✅ PowerPoint translation layer
|
||||
├── slides-adapter.js # ✅ Google Slides translation layer
|
||||
└── canva-adapter.js # (future) Canva integration
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Example 1: Board Update
|
||||
|
||||
```
|
||||
User: "Create presentation on cybersecurity trends for school board, 15 minutes"
|
||||
|
||||
Geoffrey:
|
||||
**Context Analysis**
|
||||
- Type: Board/Executive Update
|
||||
- Audience: School board (non-technical)
|
||||
- Duration: 15 minutes
|
||||
- Purpose: Inform + Recommend action
|
||||
|
||||
**Recommended Structure**
|
||||
Current State → Trends → Implications → Recommendations (10 slides)
|
||||
|
||||
[After approval]
|
||||
|
||||
**Draft Outline**
|
||||
1. Title: Cybersecurity Trends 2025
|
||||
2. Current Threat Landscape [visual: threat timeline]
|
||||
3. Trend 1: AI-Powered Attacks [visual: concept illustration]
|
||||
...
|
||||
|
||||
**Visual Strategy**
|
||||
- 7 images recommended
|
||||
- Estimated cost: $0.94 (2K resolution)
|
||||
- Mix: 3 infographics, 2 charts, 1 diagram, 1 illustration
|
||||
|
||||
[After approval and generation]
|
||||
|
||||
**Quality Score: 91/100**
|
||||
✓ All fonts 36pt+
|
||||
✓ Avg 4.2 words/slide
|
||||
✓ High contrast (8.5:1)
|
||||
⚠ Slide 8 has 7 words (rec: 6 max)
|
||||
|
||||
Created: /Obsidian/Research/cybersecurity-trends-2025-board.pptx
|
||||
```
|
||||
|
||||
### Example 2: Keynote
|
||||
|
||||
```
|
||||
User: "Create keynote on future of education for conference, 30 minutes"
|
||||
|
||||
Geoffrey:
|
||||
**Context Analysis**
|
||||
- Type: Keynote/TED-style
|
||||
- Audience: Education professionals + parents
|
||||
- Duration: 30 minutes
|
||||
- Purpose: Inspire + Shift perspective
|
||||
|
||||
**Recommended Structures**
|
||||
1. Sparkline: What is → What could be (12 slides) ⭐
|
||||
2. Rule of Three: Past → Present → Future (9 slides)
|
||||
3. Three-Act: Problem → Trials → New reality (10 slides)
|
||||
|
||||
[Continues with guided creation...]
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
- `pptxgenjs`: PowerPoint generation library (current Phase 1)
|
||||
- `image-gen` skill: Visual content generation
|
||||
- `psd-brand-guidelines` skill: Brand colors/logos
|
||||
- `research` skill: Content development
|
||||
- `obsidian-manager` skill: Knowledge storage
|
||||
|
||||
## Installation
|
||||
|
||||
This skill is part of Geoffrey's skill library. No separate installation needed.
|
||||
|
||||
Ensure dependencies are installed:
|
||||
```bash
|
||||
cd /Users/hagelk/non-ic-code/geoffrey/skills/presentation-master
|
||||
bun install
|
||||
```
|
||||
|
||||
## Triggers
|
||||
|
||||
Natural language activation:
|
||||
- "create presentation"
|
||||
- "make presentation"
|
||||
- "build presentation"
|
||||
- "design deck"
|
||||
- "make slides"
|
||||
- "create slides"
|
||||
- "presentation for..."
|
||||
- "slides for..."
|
||||
|
||||
## Version
|
||||
|
||||
**Current**: 1.2.0 (Phases 1-3 Complete)
|
||||
- ✅ Phase 1: PPTX support via pptx skill
|
||||
- ✅ Phase 2: Visual Intelligence (analyze-context, suggest-images, validate-presentation scripts)
|
||||
- ✅ Phase 3: Google Slides support via google-workspace skill
|
||||
**Future**: 1.3.0 (Canva integration)
|
||||
|
||||
## Learning & Iteration
|
||||
|
||||
After each presentation, metadata is saved to Obsidian:
|
||||
|
||||
```json
|
||||
{
|
||||
"presentation_id": "cybersecurity-2025-board",
|
||||
"type": "board-update",
|
||||
"duration": "15min",
|
||||
"slides": 10,
|
||||
"quality_score": 91,
|
||||
"images_generated": 7,
|
||||
"generation_cost": 0.94,
|
||||
"user_edits": ["slide-8-wording"],
|
||||
"effectiveness": "approved-minor-changes",
|
||||
"created": "2025-11-24",
|
||||
"learnings": "Board prefers data charts over concept graphics"
|
||||
}
|
||||
```
|
||||
|
||||
This enables:
|
||||
- Quality score trending
|
||||
- Pattern library expansion
|
||||
- User preference learning
|
||||
- Cost optimization
|
||||
|
||||
## Philosophy
|
||||
|
||||
**Code Before Prompts** (Geoffrey Principle):
|
||||
- Deterministic design rules codified in software
|
||||
- AI orchestrates, doesn't improvise design
|
||||
- Validation is automatic, not subjective
|
||||
|
||||
**Progressive Disclosure** (Geoffrey Principle):
|
||||
- Tier 1: Core workflow (always loaded)
|
||||
- Tier 2: Detailed principles (loaded when skill activates)
|
||||
- Tier 3: Scripts and data (fetched just-in-time)
|
||||
|
||||
**Checkpoints Are Non-Negotiable**:
|
||||
- Structure approval before content development
|
||||
- Outline approval before visual strategy
|
||||
- Visual approval before generation
|
||||
- Quality review before finalization
|
||||
|
||||
## References
|
||||
|
||||
**Books**:
|
||||
- *Presentation Zen* by Garr Reynolds
|
||||
- *Resonate* by Nancy Duarte
|
||||
- *slide:ology* by Nancy Duarte
|
||||
- *The Visual Display of Quantitative Information* by Edward Tufte
|
||||
- *Multimedia Learning* by Richard Mayer
|
||||
|
||||
**Articles**:
|
||||
- Guy Kawasaki: The 10/20/30 Rule of PowerPoint
|
||||
- Seth Godin: Really Bad PowerPoint
|
||||
- TED: Create + Prepare Slides Guide
|
||||
|
||||
**Principles Documentation**:
|
||||
- `principles/masters.md` - Comprehensive best practices
|
||||
- `principles/validation-rules.md` - Quality scoring details
|
||||
- `principles/slide-patterns.md` - Pattern specifications
|
||||
- `principles/story-frameworks.md` - Narrative structures
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
**Phase 4: Canva Integration**
|
||||
- Canva REST API adapter
|
||||
- Auto-apply brand kits
|
||||
- Template library integration
|
||||
|
||||
**Phase 5: Advanced Features**
|
||||
- Auto-generate speaker notes
|
||||
- Rehearsal timing suggestions
|
||||
- A/B test different structures
|
||||
- Effectiveness tracking
|
||||
- Personal pattern library from successes
|
||||
|
||||
## Contributing
|
||||
|
||||
Improvements welcome! When adding new features:
|
||||
1. Follow existing architectural patterns
|
||||
2. Document in appropriate principles file
|
||||
3. Add examples to SKILL.md
|
||||
4. Update version in package.json
|
||||
5. Add learning to metadata tracking
|
||||
|
||||
## License
|
||||
|
||||
MIT License - See LICENSE file for details
|
||||
|
||||
---
|
||||
|
||||
**Remember**: The best presentations are simple, visual, story-driven, and focused on the audience's transformation—not the speaker's information.
|
||||
|
||||
Built with ❤️ by Geoffrey
|
||||
449
skills/presentation-master/SKILL.md
Normal file
449
skills/presentation-master/SKILL.md
Normal file
@@ -0,0 +1,449 @@
|
||||
---
|
||||
name: presentation-master
|
||||
description: World-class presentation creation embodying principles from Garr Reynolds, Nancy Duarte, Guy Kawasaki, Seth Godin, and TED
|
||||
triggers:
|
||||
- "create presentation"
|
||||
- "make presentation"
|
||||
- "build presentation"
|
||||
- "design deck"
|
||||
- "make slides"
|
||||
- "create slides"
|
||||
- "build deck"
|
||||
- "presentation for"
|
||||
- "slides for"
|
||||
allowed-tools: Read, Write, Bash, WebSearch, Skill, AskUserQuestion
|
||||
version: 1.0.0
|
||||
---
|
||||
|
||||
# Presentation Master
|
||||
|
||||
World-class presentation creation skill that embodies best practices from presentation masters and adapts to your needs.
|
||||
|
||||
## Philosophy
|
||||
|
||||
**Key Innovation**: This isn't just a presentation generator—it's a presentation *coach* that teaches world-class design while creating slides.
|
||||
|
||||
Principles from:
|
||||
- **Garr Reynolds** (Presentation Zen) - Simplicity and visual storytelling
|
||||
- **Nancy Duarte** (Resonate) - Story structure and audience as hero
|
||||
- **Guy Kawasaki** - 10/20/30 rule (10 slides, 20 minutes, 30pt fonts)
|
||||
- **Seth Godin** - 6 words maximum per slide
|
||||
- **TED** - Visual-first, minimal text, high impact
|
||||
- **Edward Tufte** - Data integrity and information design
|
||||
- **Steve Jobs** - Rule of Three and surprise moments
|
||||
|
||||
## Workflow: Guided Creation with Checkpoints
|
||||
|
||||
### Phase 1: Discovery & Context Analysis
|
||||
|
||||
**User provides**: Topic + Audience + Duration
|
||||
|
||||
**Skill analyzes**:
|
||||
- Presentation type (board update, keynote, training, TED-style)
|
||||
- Audience level (technical, executive, general public)
|
||||
- Key message and desired transformation
|
||||
- Story framework recommendation
|
||||
|
||||
**Checkpoint 1**: Present 3 structure options with rationale → user approves
|
||||
|
||||
### Phase 2: Content Development
|
||||
|
||||
**Skill develops**:
|
||||
- Research topic if needed (web search, Obsidian knowledge)
|
||||
- Extract maximum 10 core concepts (Kawasaki rule)
|
||||
- Apply "what is / what could be" alternation (Duarte)
|
||||
- Draft slide outline with one concept per slide
|
||||
- Identify slides needing visuals
|
||||
|
||||
**Checkpoint 2**: Present outline + visual plan → user approves
|
||||
|
||||
### Phase 3: Visual Strategy
|
||||
|
||||
**Skill proposes** for each visual slide:
|
||||
- Image type (infographic, photo, diagram, data visualization)
|
||||
- Visual concept/metaphor
|
||||
- Aesthetic direction (colors from brand, style, mood)
|
||||
- Estimated generation cost ($0.13-$0.24 per image)
|
||||
|
||||
**Checkpoint 3**: Present visual strategy → user approves images to generate
|
||||
|
||||
### Phase 4: Generation & Validation
|
||||
|
||||
**Skill executes**:
|
||||
1. Generate approved images in parallel using image-gen skill
|
||||
2. Build slides using selected adapter (PPTX/Google Slides/Canva)
|
||||
3. Apply design rules automatically:
|
||||
- 30pt+ fonts minimum
|
||||
- <6 words per slide (Godin standard)
|
||||
- High contrast (4.5:1 minimum)
|
||||
- No bullet points
|
||||
- No paragraphs
|
||||
4. Run validation scoring (0-100 scale)
|
||||
5. Generate quality report
|
||||
|
||||
**Checkpoint 4**: Present presentation + quality report → user reviews
|
||||
|
||||
### Phase 5: Iteration & Refinement (if needed)
|
||||
|
||||
**Skill refines**:
|
||||
- Apply requested changes
|
||||
- Re-validate quality score
|
||||
- Save final presentation to Obsidian Research folder
|
||||
- Document learnings and metadata
|
||||
|
||||
## Validation Scoring (0-100)
|
||||
|
||||
### CRITICAL Violations (Auto-fail)
|
||||
- Font size < 30pt
|
||||
- >10 core concepts
|
||||
- Bullet points detected
|
||||
- Paragraphs (>2 consecutive sentences)
|
||||
- Poor contrast ratio (<4.5:1)
|
||||
- Default template usage
|
||||
|
||||
### WARNING Flags
|
||||
- >6 words per slide
|
||||
- >15 slides for 20-min presentation
|
||||
- No images in presentation
|
||||
- Text-heavy slides (>3 lines)
|
||||
- Inconsistent fonts (>2 families)
|
||||
- Low-resolution images
|
||||
|
||||
### Quality Score Breakdown
|
||||
- **Simplicity** (10pts): Word count, visual clutter
|
||||
- **Visual Dominance** (10pts): Image quality, text-to-visual ratio
|
||||
- **Story Structure** (10pts): Narrative arc, emotional beats
|
||||
- **One Idea/Slide** (10pts): Concept clarity
|
||||
- **Typography** (8pts): Size, consistency
|
||||
- **Layout** (7pts): Hierarchy, whitespace, alignment
|
||||
- **Color/Contrast** (7pts): Readability, brand consistency
|
||||
- **Media Quality** (8pts): Image resolution, relevance
|
||||
- **Cognitive Load** (20pts): Mayer's 12 multimedia principles
|
||||
- **Data Integrity** (10pts): Tufte principles (if data present)
|
||||
|
||||
**Target Score**: 85+ for high-quality presentations
|
||||
|
||||
## Slide Pattern Library
|
||||
|
||||
### Six Core Patterns
|
||||
|
||||
1. **Title Slide** - Minimal text, strong visual, sets tone
|
||||
2. **One Big Idea** - Single word/number/image, max 6 words
|
||||
3. **Visual + Caption** - Large high-quality image, short caption
|
||||
4. **Data Visualization** - Charts following Tufte principles (maximize data-ink ratio)
|
||||
5. **Timeline/Process** - Linear flow, minimal text per step
|
||||
6. **Transition/Section Break** - Single word or phrase, signals shift
|
||||
|
||||
### Adaptive Pattern Selection
|
||||
|
||||
**Board/Executive Update**: Patterns 3, 4, 6 (data-focused, professional)
|
||||
**Keynote/TED-style**: Patterns 1, 2, 3 (story-focused, visual-first)
|
||||
**Training/Education**: Patterns 4, 5 (process-focused, clarity)
|
||||
**Pitch/Demo**: Patterns 2, 3, 4 (impact-focused, evidence-based)
|
||||
|
||||
## Story Frameworks
|
||||
|
||||
### Nancy Duarte's Sparkline
|
||||
- Alternate "what is" (current reality) with "what could be" (aspiration)
|
||||
- Build tension through contrast between present and future
|
||||
- End with transformation and new reality
|
||||
|
||||
### The Rule of Three (Steve Jobs)
|
||||
- Break presentation into 3 main sections
|
||||
- 3 key features/points per section
|
||||
- Memorable and dramatic
|
||||
|
||||
### TED Structure
|
||||
- Hook (first 30 seconds) - Grab attention
|
||||
- Personal connection - Why this matters to you
|
||||
- Core idea with evidence - The meat
|
||||
- Call to action - What next
|
||||
- Strong close - Never end with Q&A
|
||||
|
||||
## Output Format Support
|
||||
|
||||
### Current: PPTX (Phase 1)
|
||||
- Uses existing pptx skill
|
||||
- Direct PptxGenJS API for simple slides
|
||||
- html2pptx.js for complex layouts
|
||||
- Saves to Obsidian Research folder
|
||||
- Generates quality validation report
|
||||
|
||||
### Coming: Google Slides (Phase 2)
|
||||
- Google Slides API v1
|
||||
- Integrates with google-workspace skill
|
||||
- Supports all 3 accounts (psd, kh, hrg)
|
||||
- Returns shareable link
|
||||
|
||||
### Future: Canva (Phase 3)
|
||||
- Canva REST API
|
||||
- Auto-apply brand kits
|
||||
- Returns shareable link
|
||||
|
||||
## Image Generation Integration
|
||||
|
||||
### Intelligent Visual Recommendations
|
||||
|
||||
For each slide, analyzes:
|
||||
- **Numeric data** → Infographic recommendation
|
||||
- **Abstract concepts** → Conceptual image/metaphor (especially for keynotes)
|
||||
- **Concrete examples** → Photo/realistic imagery
|
||||
- **Processes/flows** → Diagram recommendation
|
||||
- **Trends/comparisons** → Chart/data visualization
|
||||
|
||||
### Prompt Generation (6-Step Process)
|
||||
|
||||
From image-gen skill:
|
||||
1. Extract narrative from slide content
|
||||
2. Choose visual concept/metaphor
|
||||
3. Apply aesthetic (brand colors, presentation style)
|
||||
4. Construct detailed prompt
|
||||
5. Execute generation
|
||||
6. Validate output
|
||||
|
||||
### Cost Management
|
||||
- Show total estimated cost before generating
|
||||
- Allow opt-out of specific images
|
||||
- Cache generated images for reuse
|
||||
- Track spending in presentation metadata
|
||||
|
||||
### Naming Convention
|
||||
```
|
||||
{presentation-id}-slide-{number}-{type}.png
|
||||
|
||||
Examples:
|
||||
cybersecurity-2025-slide-02-threat-timeline.png
|
||||
port-ai-2025-slide-04-breakthroughs.png
|
||||
```
|
||||
|
||||
## Brand Integration
|
||||
|
||||
Automatically detects and applies branding:
|
||||
- **PSD presentations**: Use psd-brand-guidelines skill (Sea Glass, Pacific, etc.)
|
||||
- **Personal presentations**: Use personal brand (if defined)
|
||||
- **Client presentations**: Custom brand kit (future)
|
||||
|
||||
Applies to:
|
||||
- Color palettes
|
||||
- Typography choices
|
||||
- Logo placement
|
||||
- Overall aesthetic
|
||||
|
||||
## Learning & Metadata Tracking
|
||||
|
||||
After each presentation, save metadata to Obsidian:
|
||||
|
||||
```json
|
||||
{
|
||||
"presentation_id": "cybersecurity-2025-board",
|
||||
"type": "board-update",
|
||||
"audience": "school-board",
|
||||
"duration": "15min",
|
||||
"slides": 10,
|
||||
"quality_score": 91,
|
||||
"images_generated": 7,
|
||||
"generation_cost": 0.94,
|
||||
"validation_warnings": 1,
|
||||
"user_edits": ["slide-8-wording"],
|
||||
"effectiveness": "approved-minor-changes",
|
||||
"created": "2025-11-24",
|
||||
"tools_used": ["research", "image-gen", "pptx"],
|
||||
"learnings": "Board prefers data charts over concept graphics"
|
||||
}
|
||||
```
|
||||
|
||||
## Integration with Existing Skills
|
||||
|
||||
**Dependencies**:
|
||||
- `image-gen` - Visual content generation
|
||||
- `pptx` - PowerPoint creation (Phase 1)
|
||||
- `google-workspace` - Google Slides (Phase 2)
|
||||
- `psd-brand-guidelines` - Brand colors/logos
|
||||
- `research` - Content development
|
||||
- `obsidian-manager` - Knowledge storage
|
||||
|
||||
**Coordination Pattern**:
|
||||
```
|
||||
presentation-master (orchestrator)
|
||||
├── calls research for content depth
|
||||
├── calls image-gen for visuals
|
||||
├── calls pptx/slides/canva adapter for output
|
||||
├── calls psd-brand-guidelines for colors/logos
|
||||
└── calls obsidian-manager to save final + metadata
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Example 1: Board Update
|
||||
```
|
||||
User: "Create presentation on cybersecurity trends for school board, 15 minutes"
|
||||
|
||||
Geoffrey: I'll create a board update presentation on cybersecurity trends.
|
||||
|
||||
**Context Analysis**
|
||||
- Type: Board/Executive Update
|
||||
- Audience: School board (non-technical)
|
||||
- Duration: 15 minutes
|
||||
- Purpose: Inform + Recommend action
|
||||
|
||||
**Recommended Structures**
|
||||
1. Problem → Solution → Action (8 slides)
|
||||
2. Current State → Trends → Implications → Recommendations (10 slides) ⭐
|
||||
3. Story: Recent incident → Broader context → Our response (7 slides)
|
||||
|
||||
Which structure resonates?
|
||||
|
||||
[User selects #2]
|
||||
|
||||
**Draft Outline** (10 slides, one concept each)
|
||||
1. Title: Cybersecurity Trends 2025
|
||||
2. Current Threat Landscape [visual: threat timeline]
|
||||
3. Trend 1: AI-Powered Attacks [visual: concept illustration]
|
||||
4. Trend 2: Ransomware Evolution [visual: data chart]
|
||||
5. Trend 3: Supply Chain Risks [visual: network diagram]
|
||||
6. Impact on Education Sector [visual: stat infographic]
|
||||
7. Our Current Posture [visual: assessment chart]
|
||||
8. Gaps & Vulnerabilities [text-focused, high contrast]
|
||||
9. Recommended Actions [visual: roadmap]
|
||||
10. Investment & Timeline [visual: budget chart]
|
||||
|
||||
**Visual Strategy**
|
||||
- 7 images recommended
|
||||
- Estimated cost: $0.94 (2K resolution)
|
||||
- Mix: 3 infographics, 2 charts, 1 diagram, 1 illustration
|
||||
|
||||
Approve and proceed?
|
||||
|
||||
[User approves]
|
||||
|
||||
Generating 7 visuals in parallel...
|
||||
✓ All generated (0.94 total)
|
||||
|
||||
Building presentation with PSD brand colors...
|
||||
Validating against best practices...
|
||||
|
||||
**Quality Score: 91/100**
|
||||
✓ All fonts 36pt+
|
||||
✓ Avg 4.2 words/slide
|
||||
✓ High contrast (8.5:1)
|
||||
✓ Story arc present
|
||||
✓ Cognitive load optimized
|
||||
⚠ Slide 8 has 7 words (rec: 6 max)
|
||||
|
||||
Created: /Obsidian/Research/cybersecurity-trends-2025-board.pptx
|
||||
```
|
||||
|
||||
### Example 2: Keynote
|
||||
```
|
||||
User: "Create keynote on future of education for conference, 30 minutes"
|
||||
|
||||
Geoffrey: I'll create a TED-style keynote on the future of education.
|
||||
|
||||
**Context Analysis**
|
||||
- Type: Keynote/TED-style
|
||||
- Audience: Education professionals + parents
|
||||
- Duration: 30 minutes
|
||||
- Purpose: Inspire + Shift perspective
|
||||
|
||||
**Recommended Structures** (Nancy Duarte's Sparkline)
|
||||
1. What education is today → What it could be → Transformation (12 slides) ⭐
|
||||
2. Steve Jobs Rule of Three: Past → Present → Future (9 slides)
|
||||
3. Hero's Journey: Problem → Trials → New reality (10 slides)
|
||||
|
||||
Which framework?
|
||||
|
||||
[Continues with guided creation...]
|
||||
```
|
||||
|
||||
## Quality Checklist
|
||||
|
||||
Before presenting to user, verify:
|
||||
|
||||
**Content**
|
||||
- [ ] One main idea per slide
|
||||
- [ ] Clear story arc (beginning/middle/end)
|
||||
- [ ] Audience positioned as hero
|
||||
- [ ] Emotional connection established
|
||||
- [ ] Maximum 10 core concepts
|
||||
|
||||
**Design**
|
||||
- [ ] All fonts 30pt+ minimum
|
||||
- [ ] High contrast (4.5:1+)
|
||||
- [ ] No bullet points
|
||||
- [ ] No paragraphs
|
||||
- [ ] Maximum 6 words per slide (or justified exception)
|
||||
- [ ] All images high-resolution
|
||||
- [ ] Consistent fonts/colors/alignment
|
||||
- [ ] No transitions or animations
|
||||
|
||||
**Data Visualization** (if applicable)
|
||||
- [ ] Lie factor 0.95-1.05
|
||||
- [ ] Maximum data-ink ratio
|
||||
- [ ] Clear, detailed labeling
|
||||
- [ ] No chart junk (3D effects, unnecessary borders)
|
||||
|
||||
**Structure**
|
||||
- [ ] Follows chosen framework (Duarte/Jobs/TED)
|
||||
- [ ] Creates tension and resolution
|
||||
- [ ] Includes surprise/memorable moments
|
||||
- [ ] Ends strong (not with Q&A)
|
||||
- [ ] Appropriate length for time
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### Context Detection
|
||||
|
||||
Automatically infers presentation type from cues:
|
||||
- "board meeting" → Board update (data-focused)
|
||||
- "keynote" or "conference" → Keynote (story-focused)
|
||||
- "training" or "workshop" → Educational (process-focused)
|
||||
- "pitch" or "investor" → Pitch (evidence-focused)
|
||||
|
||||
### Smart Defaults
|
||||
|
||||
Based on detected type:
|
||||
- **Board update**: 10 slides, 8 with visuals, professional tone
|
||||
- **Keynote**: 12-15 slides, minimal text, emotional arc
|
||||
- **Training**: 15-20 slides, process diagrams, step-by-step
|
||||
- **Pitch**: 10 slides (Kawasaki rule), data-driven, ROI focus
|
||||
|
||||
### Accessibility
|
||||
|
||||
Ensures presentations are accessible:
|
||||
- High contrast text (4.5:1 minimum, aim for 7:1)
|
||||
- Large fonts (30pt minimum, 36pt+ preferred)
|
||||
- Clear hierarchy and flow
|
||||
- Alt text for images (future enhancement)
|
||||
|
||||
## Limitations & Future Enhancements
|
||||
|
||||
**Current Limitations**:
|
||||
- No animation support (by design - Godin principle)
|
||||
- No video embedding yet (future enhancement)
|
||||
- No speaker notes generation (Phase 2)
|
||||
- No slide master editing (uses templates)
|
||||
|
||||
**Future Enhancements**:
|
||||
- Auto-generate speaker notes from slide content
|
||||
- Suggest rehearsal timing
|
||||
- A/B test different structures
|
||||
- Track presentation effectiveness scores
|
||||
- Build personal pattern library from successful presentations
|
||||
|
||||
## References
|
||||
|
||||
Full principles documentation in:
|
||||
- `principles/masters.md` - Expert best practices
|
||||
- `principles/validation-rules.md` - Quality scoring system
|
||||
- `principles/slide-patterns.md` - Template library
|
||||
- `principles/story-frameworks.md` - Narrative structures
|
||||
|
||||
Scripts and adapters:
|
||||
- `scripts/analyze-context.js` - Type detection
|
||||
- `adapters/pptx-adapter.js` - PowerPoint output
|
||||
- `adapters/slides-adapter.js` - Google Slides (Phase 2)
|
||||
- `adapters/canva-adapter.js` - Canva (Phase 3)
|
||||
|
||||
---
|
||||
|
||||
**Remember**: The best presentations are simple, visual, story-driven, and focused on the audience's transformation—not the speaker's information.
|
||||
397
skills/presentation-master/adapters/pptx-adapter.js
Normal file
397
skills/presentation-master/adapters/pptx-adapter.js
Normal file
@@ -0,0 +1,397 @@
|
||||
#!/usr/bin/env bun
|
||||
|
||||
/**
|
||||
* PPTX Adapter
|
||||
*
|
||||
* Converts presentation specification to PPTX format specification.
|
||||
* Integrates with pptx skill for actual file generation.
|
||||
*
|
||||
* Usage:
|
||||
* bun pptx-adapter.js --presentation presentation.json --output pptx-spec.json
|
||||
*
|
||||
* Output: PPTX specification that pptx skill can execute
|
||||
*/
|
||||
|
||||
// PSD Brand Colors
|
||||
const PSD_COLORS = {
|
||||
primary_teal: '6CA18A',
|
||||
dark_blue: '25424C',
|
||||
cream: 'FFFAEC',
|
||||
warm_gray: 'EEEBE4',
|
||||
black: '000000',
|
||||
white: 'FFFFFF'
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate PPTX specification from presentation
|
||||
*/
|
||||
function generatePptxSpec(presentation, options = {}) {
|
||||
const brand = options.brand || null;
|
||||
const outputPath = options.output_path || null;
|
||||
|
||||
const spec = {
|
||||
title: presentation.title,
|
||||
author: options.author || 'Geoffrey',
|
||||
subject: presentation.description || presentation.title,
|
||||
layout: '16x9',
|
||||
output_path: outputPath,
|
||||
slides: []
|
||||
};
|
||||
|
||||
// Apply default theme if brand specified
|
||||
if (brand === 'psd') {
|
||||
spec.theme = {
|
||||
background: PSD_COLORS.warm_gray,
|
||||
primary_color: PSD_COLORS.primary_teal,
|
||||
secondary_color: PSD_COLORS.dark_blue,
|
||||
text_color: PSD_COLORS.black,
|
||||
accent_color: PSD_COLORS.cream
|
||||
};
|
||||
}
|
||||
|
||||
// Convert slides
|
||||
for (const slide of presentation.slides) {
|
||||
const slideSpec = convertSlide(slide, brand);
|
||||
spec.slides.push(slideSpec);
|
||||
}
|
||||
|
||||
return spec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert individual slide based on pattern
|
||||
*/
|
||||
function convertSlide(slide, brand) {
|
||||
switch (slide.pattern) {
|
||||
case 'title':
|
||||
return convertTitleSlide(slide, brand);
|
||||
|
||||
case 'big-idea':
|
||||
return convertBigIdeaSlide(slide, brand);
|
||||
|
||||
case 'visual-caption':
|
||||
return convertVisualCaptionSlide(slide, brand);
|
||||
|
||||
case 'data-viz':
|
||||
return convertDataVizSlide(slide, brand);
|
||||
|
||||
case 'process':
|
||||
case 'timeline':
|
||||
return convertProcessSlide(slide, brand);
|
||||
|
||||
case 'transition':
|
||||
return convertTransitionSlide(slide, brand);
|
||||
|
||||
default:
|
||||
return convertDefaultSlide(slide, brand);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Title Slide
|
||||
*/
|
||||
function convertTitleSlide(slide, brand) {
|
||||
const spec = {
|
||||
type: 'title',
|
||||
background: brand === 'psd' ? PSD_COLORS.dark_blue : 'FFFFFF',
|
||||
elements: []
|
||||
};
|
||||
|
||||
// Title
|
||||
spec.elements.push({
|
||||
type: 'text',
|
||||
text: slide.title,
|
||||
x: '10%',
|
||||
y: '35%',
|
||||
w: '80%',
|
||||
h: '30%',
|
||||
fontSize: 48,
|
||||
bold: true,
|
||||
color: brand === 'psd' ? PSD_COLORS.cream : '000000',
|
||||
align: 'center',
|
||||
valign: 'middle',
|
||||
fontFace: 'Arial'
|
||||
});
|
||||
|
||||
// Subtitle if present
|
||||
if (slide.text) {
|
||||
spec.elements.push({
|
||||
type: 'text',
|
||||
text: slide.text,
|
||||
x: '15%',
|
||||
y: '65%',
|
||||
w: '70%',
|
||||
h: '10%',
|
||||
fontSize: 24,
|
||||
color: brand === 'psd' ? PSD_COLORS.cream : '666666',
|
||||
align: 'center',
|
||||
fontFace: 'Arial'
|
||||
});
|
||||
}
|
||||
|
||||
return spec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Big Idea Slide
|
||||
*/
|
||||
function convertBigIdeaSlide(slide, brand) {
|
||||
// Calculate font size based on text length
|
||||
const textLength = slide.title.length;
|
||||
const fontSize = Math.min(120, Math.max(60, Math.floor(300 / textLength)));
|
||||
|
||||
const spec = {
|
||||
type: 'big-idea',
|
||||
background: 'FFFFFF',
|
||||
elements: [{
|
||||
type: 'text',
|
||||
text: slide.title,
|
||||
x: '10%',
|
||||
y: '25%',
|
||||
w: '80%',
|
||||
h: '50%',
|
||||
fontSize,
|
||||
bold: true,
|
||||
color: brand === 'psd' ? PSD_COLORS.primary_teal : '000000',
|
||||
align: 'center',
|
||||
valign: 'middle',
|
||||
fontFace: 'Arial'
|
||||
}]
|
||||
};
|
||||
|
||||
return spec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visual + Caption Slide
|
||||
*/
|
||||
function convertVisualCaptionSlide(slide, brand) {
|
||||
const spec = {
|
||||
type: 'visual-caption',
|
||||
background: brand === 'psd' ? PSD_COLORS.warm_gray : 'FFFFFF',
|
||||
elements: []
|
||||
};
|
||||
|
||||
// Image (70-80% of slide)
|
||||
if (slide.image) {
|
||||
spec.elements.push({
|
||||
type: 'image',
|
||||
path: slide.image.url || slide.image.path,
|
||||
x: '5%',
|
||||
y: '5%',
|
||||
w: '90%',
|
||||
h: '70%',
|
||||
sizing: {
|
||||
type: 'contain',
|
||||
w: '90%',
|
||||
h: '70%'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Caption (bottom)
|
||||
spec.elements.push({
|
||||
type: 'text',
|
||||
text: slide.text || slide.title,
|
||||
x: '5%',
|
||||
y: '80%',
|
||||
w: '90%',
|
||||
h: '15%',
|
||||
fontSize: 24,
|
||||
color: '000000',
|
||||
align: 'center',
|
||||
valign: 'top',
|
||||
fontFace: 'Arial'
|
||||
});
|
||||
|
||||
return spec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data Visualization Slide
|
||||
*/
|
||||
function convertDataVizSlide(slide, brand) {
|
||||
const spec = {
|
||||
type: 'data-viz',
|
||||
background: brand === 'psd' ? PSD_COLORS.warm_gray : 'FFFFFF',
|
||||
elements: []
|
||||
};
|
||||
|
||||
// Header bar if PSD brand
|
||||
if (brand === 'psd') {
|
||||
spec.elements.push({
|
||||
type: 'rect',
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: '100%',
|
||||
h: '12%',
|
||||
fill: { color: PSD_COLORS.dark_blue }
|
||||
});
|
||||
|
||||
spec.elements.push({
|
||||
type: 'text',
|
||||
text: slide.title,
|
||||
x: '5%',
|
||||
y: '1%',
|
||||
w: '90%',
|
||||
h: '10%',
|
||||
fontSize: 36,
|
||||
bold: true,
|
||||
color: PSD_COLORS.cream,
|
||||
fontFace: 'Arial'
|
||||
});
|
||||
} else {
|
||||
spec.elements.push({
|
||||
type: 'text',
|
||||
text: slide.title,
|
||||
x: '5%',
|
||||
y: '5%',
|
||||
w: '90%',
|
||||
h: '10%',
|
||||
fontSize: 36,
|
||||
bold: true,
|
||||
color: '000000',
|
||||
fontFace: 'Arial'
|
||||
});
|
||||
}
|
||||
|
||||
// Chart/Data visualization
|
||||
if (slide.chart || slide.image) {
|
||||
const yOffset = brand === 'psd' ? '18%' : '18%';
|
||||
spec.elements.push({
|
||||
type: 'image',
|
||||
path: (slide.chart || slide.image).url || (slide.chart || slide.image).path,
|
||||
x: '7.5%',
|
||||
y: yOffset,
|
||||
w: '85%',
|
||||
h: '70%',
|
||||
sizing: {
|
||||
type: 'contain',
|
||||
w: '85%',
|
||||
h: '70%'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return spec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process/Timeline Slide
|
||||
*/
|
||||
function convertProcessSlide(slide, brand) {
|
||||
const spec = {
|
||||
type: 'process',
|
||||
background: brand === 'psd' ? PSD_COLORS.warm_gray : 'FFFFFF',
|
||||
elements: []
|
||||
};
|
||||
|
||||
// Title
|
||||
spec.elements.push({
|
||||
type: 'text',
|
||||
text: slide.title,
|
||||
x: '5%',
|
||||
y: '5%',
|
||||
w: '90%',
|
||||
h: '12%',
|
||||
fontSize: 36,
|
||||
bold: true,
|
||||
color: brand === 'psd' ? PSD_COLORS.dark_blue : '000000',
|
||||
fontFace: 'Arial'
|
||||
});
|
||||
|
||||
// Process diagram
|
||||
if (slide.image) {
|
||||
spec.elements.push({
|
||||
type: 'image',
|
||||
path: slide.image.url || slide.image.path,
|
||||
x: '5%',
|
||||
y: '25%',
|
||||
w: '90%',
|
||||
h: '65%',
|
||||
sizing: {
|
||||
type: 'contain',
|
||||
w: '90%',
|
||||
h: '65%'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return spec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transition Slide
|
||||
*/
|
||||
function convertTransitionSlide(slide, brand) {
|
||||
const spec = {
|
||||
type: 'transition',
|
||||
background: 'FFFFFF',
|
||||
elements: [{
|
||||
type: 'text',
|
||||
text: slide.title,
|
||||
x: '10%',
|
||||
y: '35%',
|
||||
w: '80%',
|
||||
h: '30%',
|
||||
fontSize: 42,
|
||||
bold: true,
|
||||
color: brand === 'psd' ? PSD_COLORS.primary_teal : '000000',
|
||||
align: 'center',
|
||||
valign: 'middle',
|
||||
fontFace: 'Arial'
|
||||
}]
|
||||
};
|
||||
|
||||
return spec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default Slide (fallback)
|
||||
*/
|
||||
function convertDefaultSlide(slide, brand) {
|
||||
return convertTitleSlide(slide, brand);
|
||||
}
|
||||
|
||||
// CLI Interface
|
||||
function main() {
|
||||
const args = {};
|
||||
|
||||
for (let i = 2; i < process.argv.length; i++) {
|
||||
if (process.argv[i].startsWith('--')) {
|
||||
const key = process.argv[i].replace(/^--/, '');
|
||||
const value = process.argv[i + 1];
|
||||
args[key] = value;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!args.presentation) {
|
||||
console.error('Usage: bun pptx-adapter.js --presentation presentation.json [--brand psd] [--output pptx-spec.json]');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const fs = require('fs');
|
||||
const presentation = JSON.parse(fs.readFileSync(args.presentation, 'utf-8'));
|
||||
|
||||
const options = {
|
||||
brand: args.brand || null,
|
||||
output_path: args['output-path'] || null,
|
||||
author: args.author || 'Geoffrey'
|
||||
};
|
||||
|
||||
const pptxSpec = generatePptxSpec(presentation, options);
|
||||
|
||||
if (args.output) {
|
||||
fs.writeFileSync(args.output, JSON.stringify(pptxSpec, null, 2));
|
||||
console.log(`PPTX specification written to ${args.output}`);
|
||||
} else {
|
||||
console.log(JSON.stringify(pptxSpec, null, 2));
|
||||
}
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
main();
|
||||
}
|
||||
|
||||
export { generatePptxSpec, convertSlide };
|
||||
794
skills/presentation-master/adapters/slides-adapter.js
Normal file
794
skills/presentation-master/adapters/slides-adapter.js
Normal file
@@ -0,0 +1,794 @@
|
||||
#!/usr/bin/env bun
|
||||
|
||||
/**
|
||||
* Google Slides Adapter
|
||||
*
|
||||
* Converts presentation specification to Google Slides API requests.
|
||||
* Integrates with google-workspace skill for authentication and API access.
|
||||
*
|
||||
* Usage:
|
||||
* bun slides-adapter.js --presentation presentation.json --account psd --output slides-spec.json
|
||||
*
|
||||
* Output: Google Slides API request specification that google-workspace skill can execute
|
||||
*/
|
||||
|
||||
// PSD Brand Colors (from psd-brand-guidelines skill)
|
||||
const PSD_COLORS = {
|
||||
primary_teal: '#6CA18A',
|
||||
dark_blue: '#25424C',
|
||||
cream: '#FFFAEC',
|
||||
warm_gray: '#EEEBE4',
|
||||
black: '#000000',
|
||||
white: '#FFFFFF'
|
||||
};
|
||||
|
||||
// Slide dimensions (16:9 aspect ratio)
|
||||
const SLIDE_DIMENSIONS = {
|
||||
width: { magnitude: 10, unit: 'INCHES' },
|
||||
height: { magnitude: 5.625, unit: 'INCHES' }
|
||||
};
|
||||
|
||||
// Convert points to EMU (English Metric Units) for Google Slides API
|
||||
function pointsToEmu(points) {
|
||||
return Math.round(points * 12700);
|
||||
}
|
||||
|
||||
// Convert inches to EMU
|
||||
function inchesToEmu(inches) {
|
||||
return Math.round(inches * 914400);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Google Slides API requests for creating a presentation
|
||||
*/
|
||||
function generateSlidesRequests(presentation, options = {}) {
|
||||
const account = options.account || 'psd';
|
||||
const applyBrand = options.brand !== false;
|
||||
|
||||
const requests = [];
|
||||
|
||||
// 1. Create presentation
|
||||
const createRequest = {
|
||||
operation: 'create_presentation',
|
||||
params: {
|
||||
title: presentation.title,
|
||||
locale: 'en-US'
|
||||
}
|
||||
};
|
||||
|
||||
// 2. Delete default slide
|
||||
const deleteDefaultSlide = {
|
||||
operation: 'delete_object',
|
||||
params: {
|
||||
objectId: '{{DEFAULT_SLIDE_ID}}' // Will be replaced after creation
|
||||
}
|
||||
};
|
||||
|
||||
// 3. Apply master theme if PSD brand
|
||||
let masterThemeRequests = [];
|
||||
if (applyBrand && account === 'psd') {
|
||||
masterThemeRequests = generatePsdTheme();
|
||||
}
|
||||
|
||||
// 4. Create slides
|
||||
const slideRequests = [];
|
||||
for (let i = 0; i < presentation.slides.length; i++) {
|
||||
const slide = presentation.slides[i];
|
||||
const slideId = `slide_${i}`;
|
||||
|
||||
// Create slide
|
||||
slideRequests.push({
|
||||
operation: 'create_slide',
|
||||
params: {
|
||||
objectId: slideId,
|
||||
insertionIndex: i,
|
||||
slideLayoutReference: { predefinedLayout: 'BLANK' }
|
||||
}
|
||||
});
|
||||
|
||||
// Add slide content based on pattern
|
||||
const contentRequests = generateSlideContent(slide, slideId, applyBrand ? account : null);
|
||||
slideRequests.push(...contentRequests);
|
||||
}
|
||||
|
||||
return {
|
||||
account,
|
||||
presentation_title: presentation.title,
|
||||
requests: [
|
||||
createRequest,
|
||||
...masterThemeRequests,
|
||||
...slideRequests
|
||||
],
|
||||
post_creation_steps: [
|
||||
'Delete default slide if present',
|
||||
'Return shareable link with edit permissions'
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate PSD brand theme
|
||||
*/
|
||||
function generatePsdTheme() {
|
||||
return [
|
||||
{
|
||||
operation: 'update_page_properties',
|
||||
params: {
|
||||
objectId: '{{MASTER_SLIDE_ID}}',
|
||||
pageProperties: {
|
||||
pageBackgroundFill: {
|
||||
solidFill: {
|
||||
color: { rgbColor: hexToRgb(PSD_COLORS.warm_gray) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate slide content based on pattern
|
||||
*/
|
||||
function generateSlideContent(slide, slideId, brand) {
|
||||
const requests = [];
|
||||
|
||||
switch (slide.pattern) {
|
||||
case 'title':
|
||||
requests.push(...generateTitleSlide(slide, slideId, brand));
|
||||
break;
|
||||
|
||||
case 'big-idea':
|
||||
requests.push(...generateBigIdeaSlide(slide, slideId, brand));
|
||||
break;
|
||||
|
||||
case 'visual-caption':
|
||||
requests.push(...generateVisualCaptionSlide(slide, slideId, brand));
|
||||
break;
|
||||
|
||||
case 'data-viz':
|
||||
requests.push(...generateDataVizSlide(slide, slideId, brand));
|
||||
break;
|
||||
|
||||
case 'process':
|
||||
case 'timeline':
|
||||
requests.push(...generateProcessSlide(slide, slideId, brand));
|
||||
break;
|
||||
|
||||
case 'transition':
|
||||
requests.push(...generateTransitionSlide(slide, slideId, brand));
|
||||
break;
|
||||
|
||||
default:
|
||||
requests.push(...generateDefaultSlide(slide, slideId, brand));
|
||||
}
|
||||
|
||||
return requests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Title Slide Pattern
|
||||
*/
|
||||
function generateTitleSlide(slide, slideId, brand) {
|
||||
const requests = [];
|
||||
|
||||
if (brand === 'psd') {
|
||||
// Background
|
||||
requests.push({
|
||||
operation: 'update_page_properties',
|
||||
params: {
|
||||
objectId: slideId,
|
||||
pageProperties: {
|
||||
pageBackgroundFill: {
|
||||
solidFill: {
|
||||
color: { rgbColor: hexToRgb(PSD_COLORS.dark_blue) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Title text
|
||||
const titleBoxId = `${slideId}_title`;
|
||||
requests.push({
|
||||
operation: 'create_shape',
|
||||
params: {
|
||||
objectId: titleBoxId,
|
||||
shapeType: 'TEXT_BOX',
|
||||
elementProperties: {
|
||||
pageObjectId: slideId,
|
||||
size: {
|
||||
width: { magnitude: 8, unit: 'INCHES' },
|
||||
height: { magnitude: 2, unit: 'INCHES' }
|
||||
},
|
||||
transform: {
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
translateX: inchesToEmu(1),
|
||||
translateY: inchesToEmu(1.8),
|
||||
unit: 'EMU'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Insert title text
|
||||
requests.push({
|
||||
operation: 'insert_text',
|
||||
params: {
|
||||
objectId: titleBoxId,
|
||||
text: slide.title,
|
||||
insertionIndex: 0
|
||||
}
|
||||
});
|
||||
|
||||
// Style title text
|
||||
requests.push({
|
||||
operation: 'update_text_style',
|
||||
params: {
|
||||
objectId: titleBoxId,
|
||||
textRange: { type: 'ALL' },
|
||||
style: {
|
||||
fontFamily: 'Arial',
|
||||
fontSize: { magnitude: 48, unit: 'PT' },
|
||||
bold: true,
|
||||
foregroundColor: {
|
||||
opaqueColor: {
|
||||
rgbColor: brand === 'psd'
|
||||
? hexToRgb(PSD_COLORS.cream)
|
||||
: hexToRgb('#FFFFFF')
|
||||
}
|
||||
}
|
||||
},
|
||||
fields: 'fontFamily,fontSize,bold,foregroundColor'
|
||||
}
|
||||
});
|
||||
|
||||
// Center align
|
||||
requests.push({
|
||||
operation: 'update_paragraph_style',
|
||||
params: {
|
||||
objectId: titleBoxId,
|
||||
textRange: { type: 'ALL' },
|
||||
style: {
|
||||
alignment: 'CENTER'
|
||||
},
|
||||
fields: 'alignment'
|
||||
}
|
||||
});
|
||||
|
||||
return requests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Big Idea Slide Pattern
|
||||
*/
|
||||
function generateBigIdeaSlide(slide, slideId, brand) {
|
||||
const requests = [];
|
||||
|
||||
// Massive text in center
|
||||
const textBoxId = `${slideId}_bigidea`;
|
||||
requests.push({
|
||||
operation: 'create_shape',
|
||||
params: {
|
||||
objectId: textBoxId,
|
||||
shapeType: 'TEXT_BOX',
|
||||
elementProperties: {
|
||||
pageObjectId: slideId,
|
||||
size: {
|
||||
width: { magnitude: 8, unit: 'INCHES' },
|
||||
height: { magnitude: 3, unit: 'INCHES' }
|
||||
},
|
||||
transform: {
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
translateX: inchesToEmu(1),
|
||||
translateY: inchesToEmu(1.3),
|
||||
unit: 'EMU'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
requests.push({
|
||||
operation: 'insert_text',
|
||||
params: {
|
||||
objectId: textBoxId,
|
||||
text: slide.title,
|
||||
insertionIndex: 0
|
||||
}
|
||||
});
|
||||
|
||||
// Giant font size (60-120pt)
|
||||
const fontSize = Math.min(120, Math.max(60, Math.floor(300 / slide.title.length)));
|
||||
|
||||
requests.push({
|
||||
operation: 'update_text_style',
|
||||
params: {
|
||||
objectId: textBoxId,
|
||||
textRange: { type: 'ALL' },
|
||||
style: {
|
||||
fontFamily: 'Arial',
|
||||
fontSize: { magnitude: fontSize, unit: 'PT' },
|
||||
bold: true,
|
||||
foregroundColor: {
|
||||
opaqueColor: {
|
||||
rgbColor: brand === 'psd'
|
||||
? hexToRgb(PSD_COLORS.primary_teal)
|
||||
: hexToRgb('#000000')
|
||||
}
|
||||
}
|
||||
},
|
||||
fields: 'fontFamily,fontSize,bold,foregroundColor'
|
||||
}
|
||||
});
|
||||
|
||||
requests.push({
|
||||
operation: 'update_paragraph_style',
|
||||
params: {
|
||||
objectId: textBoxId,
|
||||
textRange: { type: 'ALL' },
|
||||
style: {
|
||||
alignment: 'CENTER'
|
||||
},
|
||||
fields: 'alignment'
|
||||
}
|
||||
});
|
||||
|
||||
return requests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visual + Caption Slide Pattern
|
||||
*/
|
||||
function generateVisualCaptionSlide(slide, slideId, brand) {
|
||||
const requests = [];
|
||||
|
||||
// Image (70-80% of slide)
|
||||
if (slide.image) {
|
||||
const imageId = `${slideId}_image`;
|
||||
requests.push({
|
||||
operation: 'create_image',
|
||||
params: {
|
||||
objectId: imageId,
|
||||
url: slide.image.url,
|
||||
elementProperties: {
|
||||
pageObjectId: slideId,
|
||||
size: {
|
||||
width: { magnitude: 9, unit: 'INCHES' },
|
||||
height: { magnitude: 4, unit: 'INCHES' }
|
||||
},
|
||||
transform: {
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
translateX: inchesToEmu(0.5),
|
||||
translateY: inchesToEmu(0.3),
|
||||
unit: 'EMU'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Caption (1 line, bottom)
|
||||
const captionId = `${slideId}_caption`;
|
||||
requests.push({
|
||||
operation: 'create_shape',
|
||||
params: {
|
||||
objectId: captionId,
|
||||
shapeType: 'TEXT_BOX',
|
||||
elementProperties: {
|
||||
pageObjectId: slideId,
|
||||
size: {
|
||||
width: { magnitude: 9, unit: 'INCHES' },
|
||||
height: { magnitude: 0.8, unit: 'INCHES' }
|
||||
},
|
||||
transform: {
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
translateX: inchesToEmu(0.5),
|
||||
translateY: inchesToEmu(4.6),
|
||||
unit: 'EMU'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
requests.push({
|
||||
operation: 'insert_text',
|
||||
params: {
|
||||
objectId: captionId,
|
||||
text: slide.text || slide.title,
|
||||
insertionIndex: 0
|
||||
}
|
||||
});
|
||||
|
||||
requests.push({
|
||||
operation: 'update_text_style',
|
||||
params: {
|
||||
objectId: captionId,
|
||||
textRange: { type: 'ALL' },
|
||||
style: {
|
||||
fontFamily: 'Arial',
|
||||
fontSize: { magnitude: 24, unit: 'PT' },
|
||||
foregroundColor: {
|
||||
opaqueColor: {
|
||||
rgbColor: hexToRgb('#000000')
|
||||
}
|
||||
}
|
||||
},
|
||||
fields: 'fontFamily,fontSize,foregroundColor'
|
||||
}
|
||||
});
|
||||
|
||||
requests.push({
|
||||
operation: 'update_paragraph_style',
|
||||
params: {
|
||||
objectId: captionId,
|
||||
textRange: { type: 'ALL' },
|
||||
style: {
|
||||
alignment: 'CENTER'
|
||||
},
|
||||
fields: 'alignment'
|
||||
}
|
||||
});
|
||||
|
||||
return requests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data Visualization Slide Pattern
|
||||
*/
|
||||
function generateDataVizSlide(slide, slideId, brand) {
|
||||
const requests = [];
|
||||
|
||||
// Header
|
||||
if (brand === 'psd') {
|
||||
const headerId = `${slideId}_header`;
|
||||
requests.push({
|
||||
operation: 'create_shape',
|
||||
params: {
|
||||
objectId: headerId,
|
||||
shapeType: 'RECTANGLE',
|
||||
elementProperties: {
|
||||
pageObjectId: slideId,
|
||||
size: {
|
||||
width: { magnitude: 10, unit: 'INCHES' },
|
||||
height: { magnitude: 0.8, unit: 'INCHES' }
|
||||
},
|
||||
transform: {
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
translateX: 0,
|
||||
translateY: 0,
|
||||
unit: 'EMU'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
requests.push({
|
||||
operation: 'update_shape_properties',
|
||||
params: {
|
||||
objectId: headerId,
|
||||
shapeProperties: {
|
||||
shapeBackgroundFill: {
|
||||
solidFill: {
|
||||
color: { rgbColor: hexToRgb(PSD_COLORS.dark_blue) }
|
||||
}
|
||||
}
|
||||
},
|
||||
fields: 'shapeBackgroundFill'
|
||||
}
|
||||
});
|
||||
|
||||
// Header text
|
||||
const headerTextId = `${slideId}_header_text`;
|
||||
requests.push({
|
||||
operation: 'create_shape',
|
||||
params: {
|
||||
objectId: headerTextId,
|
||||
shapeType: 'TEXT_BOX',
|
||||
elementProperties: {
|
||||
pageObjectId: slideId,
|
||||
size: {
|
||||
width: { magnitude: 9, unit: 'INCHES' },
|
||||
height: { magnitude: 0.6, unit: 'INCHES' }
|
||||
},
|
||||
transform: {
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
translateX: inchesToEmu(0.5),
|
||||
translateY: inchesToEmu(0.1),
|
||||
unit: 'EMU'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
requests.push({
|
||||
operation: 'insert_text',
|
||||
params: {
|
||||
objectId: headerTextId,
|
||||
text: slide.title,
|
||||
insertionIndex: 0
|
||||
}
|
||||
});
|
||||
|
||||
requests.push({
|
||||
operation: 'update_text_style',
|
||||
params: {
|
||||
objectId: headerTextId,
|
||||
textRange: { type: 'ALL' },
|
||||
style: {
|
||||
fontFamily: 'Arial',
|
||||
fontSize: { magnitude: 36, unit: 'PT' },
|
||||
bold: true,
|
||||
foregroundColor: {
|
||||
opaqueColor: {
|
||||
rgbColor: hexToRgb(PSD_COLORS.cream)
|
||||
}
|
||||
}
|
||||
},
|
||||
fields: 'fontFamily,fontSize,bold,foregroundColor'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Chart/Image placeholder
|
||||
if (slide.chart || slide.image) {
|
||||
const chartId = `${slideId}_chart`;
|
||||
const yOffset = brand === 'psd' ? 1.0 : 0.5;
|
||||
|
||||
requests.push({
|
||||
operation: 'create_image',
|
||||
params: {
|
||||
objectId: chartId,
|
||||
url: (slide.chart || slide.image).url,
|
||||
elementProperties: {
|
||||
pageObjectId: slideId,
|
||||
size: {
|
||||
width: { magnitude: 8.5, unit: 'INCHES' },
|
||||
height: { magnitude: 4, unit: 'INCHES' }
|
||||
},
|
||||
transform: {
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
translateX: inchesToEmu(0.75),
|
||||
translateY: inchesToEmu(yOffset),
|
||||
unit: 'EMU'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return requests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process/Timeline Slide Pattern
|
||||
*/
|
||||
function generateProcessSlide(slide, slideId, brand) {
|
||||
const requests = [];
|
||||
|
||||
// Title
|
||||
const titleId = `${slideId}_title`;
|
||||
requests.push({
|
||||
operation: 'create_shape',
|
||||
params: {
|
||||
objectId: titleId,
|
||||
shapeType: 'TEXT_BOX',
|
||||
elementProperties: {
|
||||
pageObjectId: slideId,
|
||||
size: {
|
||||
width: { magnitude: 9, unit: 'INCHES' },
|
||||
height: { magnitude: 0.8, unit: 'INCHES' }
|
||||
},
|
||||
transform: {
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
translateX: inchesToEmu(0.5),
|
||||
translateY: inchesToEmu(0.3),
|
||||
unit: 'EMU'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
requests.push({
|
||||
operation: 'insert_text',
|
||||
params: {
|
||||
objectId: titleId,
|
||||
text: slide.title,
|
||||
insertionIndex: 0
|
||||
}
|
||||
});
|
||||
|
||||
requests.push({
|
||||
operation: 'update_text_style',
|
||||
params: {
|
||||
objectId: titleId,
|
||||
textRange: { type: 'ALL' },
|
||||
style: {
|
||||
fontFamily: 'Arial',
|
||||
fontSize: { magnitude: 36, unit: 'PT' },
|
||||
bold: true,
|
||||
foregroundColor: {
|
||||
opaqueColor: {
|
||||
rgbColor: brand === 'psd'
|
||||
? hexToRgb(PSD_COLORS.dark_blue)
|
||||
: hexToRgb('#000000')
|
||||
}
|
||||
}
|
||||
},
|
||||
fields: 'fontFamily,fontSize,bold,foregroundColor'
|
||||
}
|
||||
});
|
||||
|
||||
// Process diagram/image
|
||||
if (slide.image) {
|
||||
const imageId = `${slideId}_process`;
|
||||
requests.push({
|
||||
operation: 'create_image',
|
||||
params: {
|
||||
objectId: imageId,
|
||||
url: slide.image.url,
|
||||
elementProperties: {
|
||||
pageObjectId: slideId,
|
||||
size: {
|
||||
width: { magnitude: 9, unit: 'INCHES' },
|
||||
height: { magnitude: 3.5, unit: 'INCHES' }
|
||||
},
|
||||
transform: {
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
translateX: inchesToEmu(0.5),
|
||||
translateY: inchesToEmu(1.5),
|
||||
unit: 'EMU'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return requests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transition Slide Pattern
|
||||
*/
|
||||
function generateTransitionSlide(slide, slideId, brand) {
|
||||
const requests = [];
|
||||
|
||||
// Simple centered text
|
||||
const textId = `${slideId}_transition`;
|
||||
requests.push({
|
||||
operation: 'create_shape',
|
||||
params: {
|
||||
objectId: textId,
|
||||
shapeType: 'TEXT_BOX',
|
||||
elementProperties: {
|
||||
pageObjectId: slideId,
|
||||
size: {
|
||||
width: { magnitude: 8, unit: 'INCHES' },
|
||||
height: { magnitude: 2, unit: 'INCHES' }
|
||||
},
|
||||
transform: {
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
translateX: inchesToEmu(1),
|
||||
translateY: inchesToEmu(1.8),
|
||||
unit: 'EMU'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
requests.push({
|
||||
operation: 'insert_text',
|
||||
params: {
|
||||
objectId: textId,
|
||||
text: slide.title,
|
||||
insertionIndex: 0
|
||||
}
|
||||
});
|
||||
|
||||
requests.push({
|
||||
operation: 'update_text_style',
|
||||
params: {
|
||||
objectId: textId,
|
||||
textRange: { type: 'ALL' },
|
||||
style: {
|
||||
fontFamily: 'Arial',
|
||||
fontSize: { magnitude: 42, unit: 'PT' },
|
||||
bold: true,
|
||||
foregroundColor: {
|
||||
opaqueColor: {
|
||||
rgbColor: brand === 'psd'
|
||||
? hexToRgb(PSD_COLORS.primary_teal)
|
||||
: hexToRgb('#000000')
|
||||
}
|
||||
}
|
||||
},
|
||||
fields: 'fontFamily,fontSize,bold,foregroundColor'
|
||||
}
|
||||
});
|
||||
|
||||
requests.push({
|
||||
operation: 'update_paragraph_style',
|
||||
params: {
|
||||
objectId: textId,
|
||||
textRange: { type: 'ALL' },
|
||||
style: {
|
||||
alignment: 'CENTER'
|
||||
},
|
||||
fields: 'alignment'
|
||||
}
|
||||
});
|
||||
|
||||
return requests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default Slide Pattern (fallback)
|
||||
*/
|
||||
function generateDefaultSlide(slide, slideId, brand) {
|
||||
// Use title slide pattern as default
|
||||
return generateTitleSlide(slide, slideId, brand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: Convert hex color to RGB object
|
||||
*/
|
||||
function hexToRgb(hex) {
|
||||
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
return result ? {
|
||||
red: parseInt(result[1], 16) / 255,
|
||||
green: parseInt(result[2], 16) / 255,
|
||||
blue: parseInt(result[3], 16) / 255
|
||||
} : { red: 0, green: 0, blue: 0 };
|
||||
}
|
||||
|
||||
// CLI Interface
|
||||
function main() {
|
||||
const args = {};
|
||||
|
||||
for (let i = 2; i < process.argv.length; i++) {
|
||||
if (process.argv[i].startsWith('--')) {
|
||||
const key = process.argv[i].replace(/^--/, '');
|
||||
const value = process.argv[i + 1];
|
||||
args[key] = value;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!args.presentation) {
|
||||
console.error('Usage: bun slides-adapter.js --presentation presentation.json --account psd [--output slides-spec.json]');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const fs = require('fs');
|
||||
const presentation = JSON.parse(fs.readFileSync(args.presentation, 'utf-8'));
|
||||
|
||||
const options = {
|
||||
account: args.account || 'psd',
|
||||
brand: args.brand !== 'false'
|
||||
};
|
||||
|
||||
const slidesSpec = generateSlidesRequests(presentation, options);
|
||||
|
||||
if (args.output) {
|
||||
fs.writeFileSync(args.output, JSON.stringify(slidesSpec, null, 2));
|
||||
console.log(`Google Slides specification written to ${args.output}`);
|
||||
} else {
|
||||
console.log(JSON.stringify(slidesSpec, null, 2));
|
||||
}
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
main();
|
||||
}
|
||||
|
||||
export { generateSlidesRequests, generateSlideContent, hexToRgb };
|
||||
46
skills/presentation-master/package.json
Normal file
46
skills/presentation-master/package.json
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "presentation-master",
|
||||
"version": "1.2.0",
|
||||
"description": "World-class presentation creation skill embodying principles from Garr Reynolds, Nancy Duarte, Guy Kawasaki, Seth Godin, TED, Edward Tufte, and Steve Jobs",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"No tests yet\" && exit 0",
|
||||
"validate": "bun scripts/validate-presentation.js",
|
||||
"analyze": "bun scripts/analyze-context.js",
|
||||
"suggest-images": "bun scripts/suggest-images.js",
|
||||
"adapt-pptx": "bun adapters/pptx-adapter.js",
|
||||
"adapt-slides": "bun adapters/slides-adapter.js"
|
||||
},
|
||||
"keywords": [
|
||||
"presentations",
|
||||
"slides",
|
||||
"powerpoint",
|
||||
"google-slides",
|
||||
"keynote",
|
||||
"design",
|
||||
"storytelling",
|
||||
"presentation-zen",
|
||||
"nancy-duarte",
|
||||
"ted-talks",
|
||||
"visual-communication",
|
||||
"data-visualization",
|
||||
"slide-design"
|
||||
],
|
||||
"author": "Geoffrey (Kris Hagel)",
|
||||
"license": "MIT",
|
||||
"dependencies": {},
|
||||
"devDependencies": {},
|
||||
"engines": {
|
||||
"node": ">=18.0.0",
|
||||
"bun": ">=1.0.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/hagelk/geoffrey.git",
|
||||
"directory": "skills/presentation-master"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/hagelk/geoffrey/issues"
|
||||
},
|
||||
"homepage": "https://github.com/hagelk/geoffrey/tree/main/skills/presentation-master#readme"
|
||||
}
|
||||
468
skills/presentation-master/principles/masters.md
Normal file
468
skills/presentation-master/principles/masters.md
Normal file
@@ -0,0 +1,468 @@
|
||||
# Presentation Masters - Best Practices
|
||||
|
||||
Codified wisdom from the world's best presenters and presentation designers.
|
||||
|
||||
## Core Universal Principles
|
||||
|
||||
### 1. Simplicity Above All
|
||||
|
||||
**Garr Reynolds (Presentation Zen)**
|
||||
> "Restraint in preparation, simplicity in design, naturalness in delivery"
|
||||
|
||||
**Seth Godin**
|
||||
- Maximum 6 words per slide
|
||||
- No bullet points
|
||||
- No transitions/animations
|
||||
|
||||
**TED Guidelines**
|
||||
- Eliminate headlines and bullet points
|
||||
- Image-rich, minimal text
|
||||
- Rather than one complex slide, show several slides with each containing one idea
|
||||
|
||||
**Steve Jobs**
|
||||
- Sometimes just 19 total words in entire presentations
|
||||
- Single image or thought per slide
|
||||
|
||||
**Universal Rule**: Less is always more. Every element must earn its place.
|
||||
|
||||
---
|
||||
|
||||
### 2. Visual Over Textual
|
||||
|
||||
**Garr Reynolds**
|
||||
> "Narration with pictures is better than narration alone"
|
||||
|
||||
**Richard Mayer (Multimedia Principle)**
|
||||
> "People learn better from words and pictures than from words alone"
|
||||
|
||||
**Universal Rule**: Show, don't write. Slides support speech, they don't replace it.
|
||||
|
||||
**Application**:
|
||||
- Use full-bleed images
|
||||
- Minimal text overlays
|
||||
- Let visuals carry 80% of the message
|
||||
|
||||
---
|
||||
|
||||
### 3. Audience as Hero
|
||||
|
||||
**Nancy Duarte**
|
||||
> "The audience is the hero, the speaker is the mentor"
|
||||
|
||||
**Application**:
|
||||
- Focus on transformation, not information
|
||||
- What will the audience be able to do after?
|
||||
- Their journey, not your expertise
|
||||
|
||||
**Universal Rule**: The presentation is about the audience's journey, not your content.
|
||||
|
||||
---
|
||||
|
||||
### 4. Story Structure Matters
|
||||
|
||||
**Nancy Duarte's Sparkline**
|
||||
- Alternate "what is" (current reality) with "what could be" (aspiration)
|
||||
- Build tension through contrast
|
||||
- End with transformation
|
||||
|
||||
**Steve Jobs' Rule of Three**
|
||||
- Every presentation in three parts
|
||||
- Three key features per product
|
||||
- More dramatic than two, easier to remember than six
|
||||
|
||||
**TED Structure**
|
||||
- Hook (first 30 seconds)
|
||||
- Personal connection
|
||||
- Core idea with evidence
|
||||
- Call to action
|
||||
- Strong close (never end with Q&A)
|
||||
|
||||
**Universal Rule**: Structure creates meaning. Random facts don't stick; stories do.
|
||||
|
||||
---
|
||||
|
||||
### 5. One Idea Per Slide
|
||||
|
||||
**TED**
|
||||
> "Rather than one complex slide, show several slides with each containing one idea"
|
||||
|
||||
**Guy Kawasaki**
|
||||
- 10 slides maximum for hour presentation
|
||||
- One concept per slide
|
||||
|
||||
**Seth Godin**
|
||||
- 6 words maximum = one focused thought
|
||||
|
||||
**Universal Rule**: Cognitive load is real. One slide, one concept, one moment.
|
||||
|
||||
---
|
||||
|
||||
### 6. Rehearsal Is Non-Negotiable
|
||||
|
||||
**Steve Jobs**
|
||||
- Rehearsed weeks in advance
|
||||
- Every gesture choreographed
|
||||
- Nothing left to chance
|
||||
|
||||
**TED**
|
||||
> "Rehearse, rehearse, rehearse"
|
||||
|
||||
**Universal Rule**: Natural delivery requires unnatural preparation.
|
||||
|
||||
---
|
||||
|
||||
## Design Principles
|
||||
|
||||
### Typography
|
||||
|
||||
**Font Size Minimums**:
|
||||
- **TED**: 42 points minimum
|
||||
- **Guy Kawasaki**: 30 points minimum (the "30" in 10/20/30 rule)
|
||||
- **Our Standard**: 30pt minimum, 36pt+ preferred
|
||||
|
||||
**Font Choice**:
|
||||
- **TED**: Sans serif (Helvetica, Verdana) over serif for readability
|
||||
- **2025 Trends**: Bold serifs and character-filled sans-serifs as design elements
|
||||
- Limit to 1-2 font families maximum
|
||||
|
||||
**Text Limits**:
|
||||
- **Seth Godin**: 6 words maximum per slide
|
||||
- **TED**: 1-2 lines ideal, 6 lines absolute maximum
|
||||
- No paragraphs, ever
|
||||
|
||||
---
|
||||
|
||||
### Color & Contrast
|
||||
|
||||
**High Contrast Essential**:
|
||||
- Minimum 4.5:1 ratio (WCAG AA standard)
|
||||
- Aim for 7:1+ ratio (WCAG AAA standard)
|
||||
- Test in bright room conditions
|
||||
|
||||
**Steve Jobs Approach**:
|
||||
- Large white fonts on dark gradient backgrounds
|
||||
- Simple, bold color palette
|
||||
|
||||
**Consistency**:
|
||||
- Use same color palette throughout
|
||||
- Colors should reinforce brand and message
|
||||
|
||||
---
|
||||
|
||||
### Layout & Spacing
|
||||
|
||||
**Visual Hierarchy** (Garr Reynolds):
|
||||
- Make most important information the focal point
|
||||
- Use size, color, position to guide eye
|
||||
|
||||
**Reading Patterns**:
|
||||
- Z-pattern for Western audiences (top-left → top-right → bottom-left → bottom-right)
|
||||
- F-pattern for text-heavy slides (avoid these!)
|
||||
|
||||
**Whitespace** (Essential):
|
||||
- Creates hierarchy by isolating key points
|
||||
- Essential for emphasis
|
||||
- Don't fear empty space
|
||||
|
||||
**CRAP Principles**:
|
||||
- **C**ontrast: Make different elements very different
|
||||
- **R**epetition: Repeat design elements for unity
|
||||
- **A**lignment: Every element should align with something
|
||||
- **P**roximity: Related items should be grouped
|
||||
|
||||
---
|
||||
|
||||
### Images
|
||||
|
||||
**Quality Requirements**:
|
||||
- High-resolution only (TED requirement)
|
||||
- Must own or have permission
|
||||
- Avoid generic stock photos
|
||||
- Images must enhance message, not decorate
|
||||
|
||||
**Types of Images**:
|
||||
- Data visualizations (charts, graphs)
|
||||
- Conceptual illustrations
|
||||
- Real-world photography
|
||||
- Diagrams and infographics
|
||||
|
||||
---
|
||||
|
||||
## Guy Kawasaki's 10/20/30 Rule
|
||||
|
||||
**Originally for VC Pitches, Applicable to All Presentations**:
|
||||
|
||||
**10 Slides Maximum**
|
||||
- Audiences can't comprehend more than 10 concepts in one sitting
|
||||
- Forces you to identify truly important points
|
||||
|
||||
**20 Minutes Maximum**
|
||||
- Shorter is better
|
||||
- Leaves time for discussion
|
||||
- Respects audience attention span
|
||||
|
||||
**30-Point Font Minimum**
|
||||
- If you need smaller fonts, you have too much content
|
||||
- Forces simplicity
|
||||
- Ensures readability from back of room
|
||||
|
||||
---
|
||||
|
||||
## Edward Tufte's Data Visualization Principles
|
||||
|
||||
### Graphical Integrity
|
||||
|
||||
**Lie Factor**: Visual representation must tell the truth
|
||||
- Formula: (Size of effect shown in graphic) / (Size of effect in data)
|
||||
- Acceptable range: 0.95 to 1.05
|
||||
- Outside this range = distortion
|
||||
|
||||
**Rules**:
|
||||
- Don't use area to show one-dimensional data
|
||||
- Use consistent scales
|
||||
- Representations of numbers should be proportional to numerical quantities
|
||||
|
||||
---
|
||||
|
||||
### Maximize Data-Ink Ratio
|
||||
|
||||
**Data-Ink Ratio** = Data-ink / Total ink used in graphic
|
||||
|
||||
**Eliminate**:
|
||||
- Chartjunk (unnecessary decoration)
|
||||
- 3D effects
|
||||
- Unnecessary grid lines
|
||||
- Excessive borders
|
||||
- Non-data backgrounds
|
||||
|
||||
**Maximize**:
|
||||
- Data points
|
||||
- Trend lines
|
||||
- Comparisons
|
||||
- Actual information
|
||||
|
||||
---
|
||||
|
||||
### Small Multiples
|
||||
|
||||
Instead of one complex chart, use series of small charts with same axes to show:
|
||||
- Changes over time
|
||||
- Comparisons across categories
|
||||
- Pattern recognition
|
||||
|
||||
---
|
||||
|
||||
## Mayer's 12 Principles of Multimedia Learning
|
||||
|
||||
### Reducing Extraneous Processing
|
||||
|
||||
1. **Coherence**: Remove extraneous material
|
||||
2. **Signaling**: Highlight organization and essential material
|
||||
3. **Redundancy**: Don't show text + say same text verbatim
|
||||
4. **Spatial Contiguity**: Put related elements near each other
|
||||
5. **Temporal Contiguity**: Present related elements simultaneously
|
||||
|
||||
### Managing Essential Processing
|
||||
|
||||
6. **Segmentation**: Break into logical chunks
|
||||
7. **Pretraining**: Introduce key concepts early
|
||||
8. **Modality**: Graphics + narration better than graphics + on-screen text
|
||||
|
||||
### Fostering Generative Processing
|
||||
|
||||
9. **Multimedia**: Use words + pictures together
|
||||
10. **Personalization**: Use conversational style
|
||||
11. **Voice**: Informal voice over formal
|
||||
12. **Image**: Speaker image not required (focus on content)
|
||||
|
||||
---
|
||||
|
||||
## Steve Jobs Presentation Techniques
|
||||
|
||||
### Create Moments
|
||||
|
||||
**The Surprise**:
|
||||
- MacBook Air pulled from envelope
|
||||
- "One more thing..."
|
||||
- Rehearsed spontaneity
|
||||
|
||||
**The Demo**:
|
||||
- Live product demonstrations
|
||||
- Make it real and tangible
|
||||
- Show, don't just tell
|
||||
|
||||
**The Analogy**:
|
||||
- "1,000 songs in your pocket" (not "5GB MP3 player")
|
||||
- Make it relatable
|
||||
- Connect to audience experience
|
||||
|
||||
---
|
||||
|
||||
### The Rule of Three
|
||||
|
||||
**Three Acts**:
|
||||
- Setup → Conflict → Resolution
|
||||
- Past → Present → Future
|
||||
- Problem → Journey → Solution
|
||||
|
||||
**Three Features**:
|
||||
- Never showed more than 3 key features
|
||||
- Each feature given dedicated focus
|
||||
- Memorable and digestible
|
||||
|
||||
---
|
||||
|
||||
## Common Mistakes to Avoid
|
||||
|
||||
### Critical Errors
|
||||
|
||||
1. **Reading from slides** - Slides support, don't replace you
|
||||
2. **Too much text** - Paragraphs and long bullets
|
||||
3. **Poor contrast** - Can't read from back of room
|
||||
4. **Information overload** - Trying to fit too much
|
||||
5. **Default templates** - Generic and forgettable
|
||||
6. **Ending with Q&A** - Always end strong with your message
|
||||
|
||||
---
|
||||
|
||||
### Design Flaws
|
||||
|
||||
1. **Chart junk** - 3D effects, unnecessary decoration
|
||||
2. **Inconsistent styling** - Random fonts, colors
|
||||
3. **Low-res images** - Pixelated, stretched photos
|
||||
4. **Excessive transitions** - Distracting animations
|
||||
5. **Bullet point addiction** - Lazy content organization
|
||||
|
||||
---
|
||||
|
||||
### Content Issues
|
||||
|
||||
1. **Not tailoring to audience** - One size fits all approach
|
||||
2. **No emotional connection** - Just facts and figures
|
||||
3. **Missing story arc** - Disjointed information
|
||||
4. **Too many concepts** - Violating 10-concept rule
|
||||
5. **Insufficient rehearsal** - "Winging it"
|
||||
|
||||
---
|
||||
|
||||
## Presentation Type Guidelines
|
||||
|
||||
### Board/Executive Update
|
||||
|
||||
**Characteristics**:
|
||||
- Data-driven
|
||||
- Professional tone
|
||||
- Clear recommendations
|
||||
- Time-efficient
|
||||
|
||||
**Best Practices**:
|
||||
- 8-10 slides maximum
|
||||
- Heavy use of data visualizations
|
||||
- Clear "What/So What/Now What" structure
|
||||
- Executive summary up front
|
||||
|
||||
---
|
||||
|
||||
### Keynote/TED-Style
|
||||
|
||||
**Characteristics**:
|
||||
- Story-driven
|
||||
- Emotional connection
|
||||
- Inspirational
|
||||
- Transformative
|
||||
|
||||
**Best Practices**:
|
||||
- 12-15 slides
|
||||
- Minimal text (<3 words often)
|
||||
- Personal stories
|
||||
- Strong emotional arc
|
||||
- Surprise moments
|
||||
|
||||
---
|
||||
|
||||
### Training/Educational
|
||||
|
||||
**Characteristics**:
|
||||
- Process-focused
|
||||
- Step-by-step
|
||||
- Retention-optimized
|
||||
- Practice-oriented
|
||||
|
||||
**Best Practices**:
|
||||
- 15-20 slides
|
||||
- Clear progression
|
||||
- Mayer's principles critical
|
||||
- Examples and exercises
|
||||
- Summaries and reviews
|
||||
|
||||
---
|
||||
|
||||
### Pitch/Sales
|
||||
|
||||
**Characteristics**:
|
||||
- Problem-solution focused
|
||||
- Evidence-based
|
||||
- ROI-driven
|
||||
- Competitive positioning
|
||||
|
||||
**Best Practices**:
|
||||
- 10 slides (Kawasaki rule)
|
||||
- Clear problem statement
|
||||
- Unique value proposition
|
||||
- Market validation
|
||||
- Call to action
|
||||
|
||||
---
|
||||
|
||||
## Quality Assessment Questions
|
||||
|
||||
Before presenting, ask:
|
||||
|
||||
**Content**:
|
||||
- Can I explain the core message in one sentence?
|
||||
- Is there exactly one idea per slide?
|
||||
- Does each slide support the overall story?
|
||||
- Is the audience positioned as the hero?
|
||||
|
||||
**Design**:
|
||||
- Can I read all text from 10 feet away?
|
||||
- Have I eliminated all non-essential elements?
|
||||
- Is the visual hierarchy clear?
|
||||
- Are related elements grouped together?
|
||||
|
||||
**Data** (if applicable):
|
||||
- Is my lie factor between 0.95-1.05?
|
||||
- Have I maximized data-ink ratio?
|
||||
- Are all charts clearly labeled?
|
||||
- Can I explain the "so what" for each visualization?
|
||||
|
||||
**Story**:
|
||||
- Does my presentation have clear beginning/middle/end?
|
||||
- Is there tension and resolution?
|
||||
- Will the audience remember the key message?
|
||||
- Have I included a surprise or memorable moment?
|
||||
|
||||
---
|
||||
|
||||
## Sources & Further Reading
|
||||
|
||||
**Books**:
|
||||
- Presentation Zen by Garr Reynolds
|
||||
- Resonate by Nancy Duarte
|
||||
- slide:ology by Nancy Duarte
|
||||
- The Visual Display of Quantitative Information by Edward Tufte
|
||||
- Multimedia Learning by Richard Mayer
|
||||
|
||||
**Articles**:
|
||||
- Guy Kawasaki: The 10/20/30 Rule of PowerPoint
|
||||
- Seth Godin: Really Bad PowerPoint
|
||||
- TED: How to Create Slides for Your TED Talk
|
||||
|
||||
**Websites**:
|
||||
- presentationzen.com
|
||||
- duarte.com
|
||||
- ted.com/participate/organize-a-local-tedx-event/tedx-organizer-guide/speakers-program/prepare-your-speaker
|
||||
|
||||
---
|
||||
|
||||
**Remember**: These principles are not rigid rules—they're wisdom distilled from thousands of successful presentations. Adapt them to your context, but respect the underlying truths they represent.
|
||||
1057
skills/presentation-master/principles/slide-patterns.md
Normal file
1057
skills/presentation-master/principles/slide-patterns.md
Normal file
File diff suppressed because it is too large
Load Diff
976
skills/presentation-master/principles/story-frameworks.md
Normal file
976
skills/presentation-master/principles/story-frameworks.md
Normal file
@@ -0,0 +1,976 @@
|
||||
# Story Frameworks - Comprehensive Guide
|
||||
|
||||
Great presentations aren't collections of slides—they're stories. This document details proven narrative structures from the world's best presenters and storytellers, providing specific frameworks you can apply to any presentation.
|
||||
|
||||
---
|
||||
|
||||
## Why Story Structure Matters
|
||||
|
||||
### The Science
|
||||
|
||||
**Cognitive Processing**:
|
||||
- Stories activate more parts of the brain than facts alone
|
||||
- Narrative structure helps memory consolidation
|
||||
- Emotional engagement increases retention by 65-70%
|
||||
- Pattern recognition makes information easier to recall
|
||||
|
||||
**Psychological Impact**:
|
||||
- Stories create empathy and connection
|
||||
- Narrative arc sustains attention through tension/resolution
|
||||
- Relatable characters (even abstract ones) engage audience
|
||||
- Transformation provides satisfying conclusion
|
||||
|
||||
**Communication Efficiency**:
|
||||
- Structure eliminates "what comes next?" confusion
|
||||
- Clear framework helps presenter stay on track
|
||||
- Audience can follow complex information more easily
|
||||
- Memorable structure aids post-presentation recall
|
||||
|
||||
### The Problem with "Information Dumps"
|
||||
|
||||
**Why Random Facts Fail**:
|
||||
- No connective tissue between points
|
||||
- Audience can't predict where you're going
|
||||
- Equal weight given to all information
|
||||
- No emotional journey
|
||||
- Forgettable within hours
|
||||
|
||||
**What Structure Provides**:
|
||||
- Predictable (but interesting) flow
|
||||
- Rising and falling action
|
||||
- Emphasis through positioning
|
||||
- Emotional engagement
|
||||
- Memorable narrative
|
||||
|
||||
---
|
||||
|
||||
## Framework 1: Nancy Duarte's Sparkline
|
||||
|
||||
### Overview
|
||||
|
||||
Nancy Duarte analyzed hundreds of successful presentations and discovered a pattern: the best presenters alternate between "what is" (current reality) and "what could be" (aspirational future), creating a sparkline that builds tension until resolving in a transformed new reality.
|
||||
|
||||
### The Structure
|
||||
|
||||
```
|
||||
What Is (Reality) ────┐
|
||||
↓
|
||||
What Could Be (Aspiration)
|
||||
↑
|
||||
What Is (Obstacle) ───┘
|
||||
↓
|
||||
What Could Be (Vision)
|
||||
↑
|
||||
What Is (Challenge) ──┘
|
||||
↓
|
||||
What Could Be (Transformation)
|
||||
↑
|
||||
───┘
|
||||
New Bliss (Transformed Reality)
|
||||
```
|
||||
|
||||
**The Pattern**:
|
||||
1. Start with current reality (what is)
|
||||
2. Contrast with what could be
|
||||
3. Return to reality to show obstacle
|
||||
4. Present vision of overcoming it
|
||||
5. Show another challenge
|
||||
6. Present bigger vision
|
||||
7. Build to crescendo
|
||||
8. End with new transformed reality
|
||||
|
||||
### Detailed Breakdown
|
||||
|
||||
**Act 1: What Is (Current Reality)**
|
||||
- **Purpose**: Establish baseline, create identification
|
||||
- **Duration**: 10-15% of presentation
|
||||
- **Content**: Current state, familiar situation, status quo
|
||||
- **Tone**: Matter-of-fact, relatable
|
||||
- **Example**: "Today, students spend 6 hours in traditional classrooms..."
|
||||
|
||||
**Act 2: What Could Be (First Aspiration)**
|
||||
- **Purpose**: Create contrast, spark imagination
|
||||
- **Duration**: 5-10% of presentation
|
||||
- **Content**: Brief glimpse of possibility
|
||||
- **Tone**: Hopeful, intriguing
|
||||
- **Example**: "Imagine if they could learn at their own pace, exploring what they're curious about..."
|
||||
|
||||
**Act 3: What Is (First Obstacle)**
|
||||
- **Purpose**: Acknowledge challenges, build credibility
|
||||
- **Duration**: 10-15% of presentation
|
||||
- **Content**: Real barriers, legitimate concerns
|
||||
- **Tone**: Honest, not dismissive
|
||||
- **Example**: "But our current infrastructure doesn't support personalized learning at scale..."
|
||||
|
||||
**Act 4: What Could Be (Expanded Vision)**
|
||||
- **Purpose**: Show how obstacle can be overcome
|
||||
- **Duration**: 10-15% of presentation
|
||||
- **Content**: Specific solutions, evidence
|
||||
- **Tone**: Confident, inspiring
|
||||
- **Example**: "With adaptive learning platforms, each student could have a customized curriculum..."
|
||||
|
||||
**Act 5: What Is (Deeper Challenge)**
|
||||
- **Purpose**: Raise stakes, show full scope
|
||||
- **Duration**: 10-15% of presentation
|
||||
- **Content**: Systemic issues, harder problems
|
||||
- **Tone**: Serious, urgent
|
||||
- **Example**: "The real challenge isn't technology—it's transforming teacher mindset and assessment methods..."
|
||||
|
||||
**Act 6: What Could Be (Ultimate Vision)**
|
||||
- **Purpose**: Present comprehensive transformation
|
||||
- **Duration**: 15-20% of presentation
|
||||
- **Content**: Full picture of change, compelling future
|
||||
- **Tone**: Bold, inspiring
|
||||
- **Example**: "When we reimagine education entirely, students don't just learn—they discover who they are..."
|
||||
|
||||
**Act 7: New Bliss (Transformed Reality)**
|
||||
- **Purpose**: Land the vision, call to action
|
||||
- **Duration**: 10-15% of presentation
|
||||
- **Content**: What life looks like after transformation
|
||||
- **Tone**: Aspirational, actionable
|
||||
- **Example**: "This is the future of learning—and it starts with what we decide today."
|
||||
|
||||
### Application Guidelines
|
||||
|
||||
**Best Used For**:
|
||||
- Keynote speeches
|
||||
- Vision presentations
|
||||
- Change management
|
||||
- Inspirational talks
|
||||
- Fundraising pitches
|
||||
- Long-form presentations (20+ minutes)
|
||||
|
||||
**Not Recommended For**:
|
||||
- Quick updates (under 10 minutes)
|
||||
- Pure data presentations
|
||||
- Training/how-to sessions
|
||||
- Time-constrained board meetings
|
||||
|
||||
**Slide Count Implications**:
|
||||
- Minimum: 12-15 slides
|
||||
- Optimal: 18-25 slides
|
||||
- Pattern: 2-3 slides per "what is," 2-3 slides per "what could be"
|
||||
|
||||
### Example: Education Technology Pitch
|
||||
|
||||
**Slide 1-2 (What Is)**: Current education system—standardized, one-size-fits-all
|
||||
**Slide 3-4 (What Could Be)**: Personalized learning paths
|
||||
**Slide 5-6 (What Is)**: Current technology inadequate, teacher resistance
|
||||
**Slide 7-9 (What Could Be)**: Our platform + professional development
|
||||
**Slide 10-11 (What Is)**: Broader systemic challenges
|
||||
**Slide 12-15 (What Could Be)**: Complete transformation vision
|
||||
**Slide 16-17 (New Bliss)**: Students thriving, teachers empowered, results proven
|
||||
**Slide 18 (Call to Action)**: Join us in transforming education
|
||||
|
||||
### Tips for Success
|
||||
|
||||
**Create Real Contrast**:
|
||||
- Don't make "what is" too bleak or "what could be" too unrealistic
|
||||
- Contrast should be significant but believable
|
||||
- Use specific examples, not generalities
|
||||
|
||||
**Build Tension**:
|
||||
- Each "what is" should raise slightly different challenges
|
||||
- Don't repeat same obstacle
|
||||
- Escalate the stakes progressively
|
||||
|
||||
**Earn the Vision**:
|
||||
- Don't jump to big vision too early
|
||||
- Build credibility through smaller contrasts first
|
||||
- Show you understand obstacles before presenting solutions
|
||||
|
||||
**Visual Representation**:
|
||||
- Use darker colors/images for "what is" slides
|
||||
- Use lighter/brighter for "what could be" slides
|
||||
- Visual distinction reinforces narrative contrast
|
||||
|
||||
---
|
||||
|
||||
## Framework 2: Steve Jobs' Rule of Three
|
||||
|
||||
### Overview
|
||||
|
||||
Steve Jobs structured every presentation around the number three. Three main sections. Three key features. Three supporting points. This wasn't arbitrary—it's rooted in cognitive science and storytelling tradition.
|
||||
|
||||
### Why Three Works
|
||||
|
||||
**Cognitive Load**:
|
||||
- Two items: Too simple, lacks pattern
|
||||
- Three items: Perfect pattern recognition
|
||||
- Four+ items: Difficult to remember
|
||||
- Three balances complexity with memorability
|
||||
|
||||
**Storytelling Tradition**:
|
||||
- Three-act structure (setup, confrontation, resolution)
|
||||
- Three wishes in fairy tales
|
||||
- Three little pigs, three bears, three musketeers
|
||||
- Cultural familiarity makes it instantly recognizable
|
||||
|
||||
**Rhetorical Power**:
|
||||
- "Life, liberty, and the pursuit of happiness"
|
||||
- "Government of the people, by the people, for the people"
|
||||
- "Blood, sweat, and tears"
|
||||
- Tricolon creates rhythm and emphasis
|
||||
|
||||
### The Structure
|
||||
|
||||
**Level 1: Three Main Sections**
|
||||
```
|
||||
ACT 1: Setup (25% of presentation)
|
||||
└─ Establish context, introduce topic
|
||||
|
||||
ACT 2: Confrontation (50% of presentation)
|
||||
└─ Explore depth, show features/evidence
|
||||
|
||||
ACT 3: Resolution (25% of presentation)
|
||||
└─ Conclusion, call to action
|
||||
```
|
||||
|
||||
**Level 2: Three Points Per Section**
|
||||
```
|
||||
ACT 1: Setup
|
||||
├─ Point 1: Current situation
|
||||
├─ Point 2: Problem/opportunity
|
||||
└─ Point 3: Why now matters
|
||||
|
||||
ACT 2: Confrontation
|
||||
├─ Point 1: First key feature/benefit
|
||||
├─ Point 2: Second key feature/benefit
|
||||
└─ Point 3: Third key feature/benefit
|
||||
|
||||
ACT 3: Resolution
|
||||
├─ Point 1: What this means
|
||||
├─ Point 2: What you should do
|
||||
└─ Point 3: What the future looks like
|
||||
```
|
||||
|
||||
**Level 3: Three Supporting Elements Per Point**
|
||||
```
|
||||
Feature 1
|
||||
├─ What it is
|
||||
├─ Why it matters
|
||||
└─ Proof/example
|
||||
```
|
||||
|
||||
### Detailed Breakdown
|
||||
|
||||
**Act 1: Setup (Minutes 1-5 of 20-minute presentation)**
|
||||
|
||||
*Purpose: Hook attention, establish relevance*
|
||||
|
||||
**Point 1: The Hook (1-2 minutes)**
|
||||
- Surprising statistic, provocative question, or bold statement
|
||||
- Creates immediate engagement
|
||||
- Example: "73% of students can't apply what they learn in school"
|
||||
|
||||
**Point 2: The Context (1-2 minutes)**
|
||||
- Why this topic matters now
|
||||
- Broader landscape or trend
|
||||
- Example: "As AI transforms the workplace, education must evolve"
|
||||
|
||||
**Point 3: The Promise (1-2 minutes)**
|
||||
- What audience will get from this presentation
|
||||
- Sets expectations
|
||||
- Example: "Today I'll show you three ways we're solving this"
|
||||
|
||||
**Act 2: Confrontation (Minutes 6-15 of 20-minute presentation)**
|
||||
|
||||
*Purpose: Deliver core value, show evidence*
|
||||
|
||||
**Feature/Point 1 (3-4 minutes)**
|
||||
- Introduction: What is this feature/point?
|
||||
- Explanation: How does it work?
|
||||
- Demo/Example: Show it in action
|
||||
- Benefit: Why does it matter?
|
||||
|
||||
**Feature/Point 2 (3-4 minutes)**
|
||||
- Same structure as Feature 1
|
||||
- Should build on or complement first point
|
||||
- Adds new dimension, doesn't repeat
|
||||
|
||||
**Feature/Point 3 (3-4 minutes)**
|
||||
- Same structure
|
||||
- Often the most powerful or surprising
|
||||
- "One more thing..." moment if applicable
|
||||
- Culmination of the three
|
||||
|
||||
**Act 3: Resolution (Minutes 16-20 of 20-minute presentation)**
|
||||
|
||||
*Purpose: Land the message, inspire action*
|
||||
|
||||
**Summary (1-2 minutes)**
|
||||
- Quickly recap the three main points
|
||||
- Reinforce core message
|
||||
- Example: "We've seen how personalization, engagement, and measurement transform learning"
|
||||
|
||||
**Implication (1-2 minutes)**
|
||||
- What this means for audience
|
||||
- Broader significance
|
||||
- Example: "This isn't just better education—it's preparing students for an unknowable future"
|
||||
|
||||
**Call to Action (1-2 minutes)**
|
||||
- Specific next steps
|
||||
- Clear ask
|
||||
- Inspiring close
|
||||
- Example: "Join us in reimagining education. Let's talk after about pilot opportunities."
|
||||
|
||||
### Application Guidelines
|
||||
|
||||
**Best Used For**:
|
||||
- Product launches
|
||||
- Feature demonstrations
|
||||
- Persuasive presentations
|
||||
- Short-to-medium presentations (15-30 minutes)
|
||||
- When you have natural groupings of concepts
|
||||
|
||||
**Not Recommended For**:
|
||||
- Complex technical deep-dives requiring more categories
|
||||
- Highly detailed training
|
||||
- Presentations where content doesn't naturally group into threes
|
||||
|
||||
**Slide Count Implications**:
|
||||
- Minimum: 10 slides (following Kawasaki's 10/20/30 rule)
|
||||
- Typical: 12-18 slides
|
||||
- Pattern:
|
||||
- Act 1: 3-4 slides
|
||||
- Act 2: 6-9 slides (2-3 per feature)
|
||||
- Act 3: 3-4 slides
|
||||
|
||||
### Example: Product Launch
|
||||
|
||||
**ACT 1: Setup (Slides 1-3)**
|
||||
- Slide 1 (Title): Product name and tagline
|
||||
- Slide 2 (Problem): Current pain point—"Students forget 70% within 24 hours"
|
||||
- Slide 3 (Promise): "Three breakthroughs that change everything"
|
||||
|
||||
**ACT 2: Three Features (Slides 4-12)**
|
||||
- Slides 4-6 (Feature 1): Adaptive spaced repetition
|
||||
- Slide 4: What it is
|
||||
- Slide 5: How it works (demo)
|
||||
- Slide 6: Results—"85% retention improvement"
|
||||
- Slides 7-9 (Feature 2): Real-time engagement tracking
|
||||
- Slide 7: What it is
|
||||
- Slide 8: Dashboard demo
|
||||
- Slide 9: Teacher testimonial
|
||||
- Slides 10-12 (Feature 3): AI-generated practice problems
|
||||
- Slide 10: What it is
|
||||
- Slide 11: Examples
|
||||
- Slide 12: Student success story
|
||||
|
||||
**ACT 3: Resolution (Slides 13-15)**
|
||||
- Slide 13: Quick recap—"Remember: Adapt, Track, Practice"
|
||||
- Slide 14: Vision—"This is the future of learning"
|
||||
- Slide 15: Call to action—"Available now—let's get your students started"
|
||||
|
||||
### Jobs' Additional Techniques
|
||||
|
||||
**The "One More Thing"**:
|
||||
- After seemingly concluding
|
||||
- Introduce surprise fourth element
|
||||
- Works because you've established the three pattern
|
||||
- Violates expectation in delightful way
|
||||
- Use sparingly—once per presentation maximum
|
||||
|
||||
**The Superlative**:
|
||||
- "This is the best [X] we've ever made"
|
||||
- "The most important [Y]"
|
||||
- Bold claims create memorable moments
|
||||
- Must be backed by evidence
|
||||
|
||||
**The Human Moment**:
|
||||
- Demo goes wrong → handle gracefully
|
||||
- Personal story interlude
|
||||
- Audience interaction
|
||||
- Breaks script pattern, feels authentic
|
||||
|
||||
---
|
||||
|
||||
## Framework 3: TED Talk Structure
|
||||
|
||||
### Overview
|
||||
|
||||
TED enforces strict format: 18 minutes maximum, focus on "ideas worth spreading." Thousands of talks have revealed common patterns among the most successful presentations.
|
||||
|
||||
### The Structure
|
||||
|
||||
```
|
||||
Part 1: HOOK (30-90 seconds)
|
||||
└─ Grab attention immediately
|
||||
|
||||
Part 2: PERSONAL CONNECTION (1-3 minutes)
|
||||
└─ Why this matters to speaker
|
||||
|
||||
Part 3: CORE IDEA (10-12 minutes)
|
||||
├─ The insight/discovery
|
||||
├─ Evidence and examples
|
||||
└─ Implications
|
||||
|
||||
Part 4: CALL TO ACTION (2-3 minutes)
|
||||
└─ What audience should do
|
||||
|
||||
Part 5: MEMORABLE CLOSE (30-60 seconds)
|
||||
└─ Full circle back to hook OR powerful statement
|
||||
```
|
||||
|
||||
### Detailed Breakdown
|
||||
|
||||
**Part 1: The Hook (30-90 seconds)**
|
||||
|
||||
*Purpose: Capture attention in first 30 seconds or lose audience*
|
||||
|
||||
**Hook Types**:
|
||||
|
||||
1. **Provocative Question**
|
||||
- "What if I told you everything you know about [X] is wrong?"
|
||||
- Must be genuinely interesting, not rhetorical fluff
|
||||
- Should connect to core idea
|
||||
|
||||
2. **Surprising Statistic**
|
||||
- "73% of teachers report..."
|
||||
- Must be truly surprising, not common knowledge
|
||||
- Contextual setup in 1-2 sentences max
|
||||
|
||||
3. **Personal Anecdote**
|
||||
- Brief story (60 seconds max at this stage)
|
||||
- Must relate directly to topic
|
||||
- Should be unexpected or emotionally engaging
|
||||
|
||||
4. **Bold Declaration**
|
||||
- "Everything is about to change"
|
||||
- "We've been solving the wrong problem"
|
||||
- Must be backed up—don't make claims you can't support
|
||||
|
||||
5. **Visual Surprise**
|
||||
- Striking image with no context
|
||||
- "This is [unexpected thing]"
|
||||
- Explain connection to topic
|
||||
|
||||
**Critical Elements**:
|
||||
- Start immediately—no "thanks for having me" preamble
|
||||
- No agenda slide—jump right in
|
||||
- Create curiosity gap that demands resolution
|
||||
- Under 90 seconds total
|
||||
|
||||
**Part 2: Personal Connection (1-3 minutes)**
|
||||
|
||||
*Purpose: Establish credibility and authentic investment*
|
||||
|
||||
**What to Share**:
|
||||
- How you discovered this topic
|
||||
- Why it matters personally to you
|
||||
- Moment of realization or transformation
|
||||
- Authentic vulnerability (not staged)
|
||||
|
||||
**What NOT to Share**:
|
||||
- Full resume/credentials (boring)
|
||||
- Lengthy backstory (self-indulgent)
|
||||
- Unrelated personal details
|
||||
- False humility
|
||||
|
||||
**Structure**:
|
||||
```
|
||||
"I first encountered this problem when..."
|
||||
↓
|
||||
"It challenged everything I believed about..."
|
||||
↓
|
||||
"That's when I realized..."
|
||||
```
|
||||
|
||||
**Example**:
|
||||
"Five years ago, my daughter came home from school and said, 'I'm stupid at math.' She's brilliant—but the system had convinced her otherwise. That moment launched my obsession with understanding why our brightest students lose confidence. What I discovered shocked me."
|
||||
|
||||
**Part 3: Core Idea (10-12 minutes)**
|
||||
|
||||
*Purpose: Deliver the insight, backed by evidence*
|
||||
|
||||
**Sub-Structure**:
|
||||
|
||||
**A. State the Idea Clearly (1 minute)**
|
||||
- One sentence summary
|
||||
- No jargon, plain language
|
||||
- Memorable phrasing
|
||||
- Example: "We've been teaching subjects when we should be teaching thinking"
|
||||
|
||||
**B. Explain Why Current Understanding is Wrong/Incomplete (2-3 minutes)**
|
||||
- What's the prevailing view?
|
||||
- Why does it persist?
|
||||
- What are we missing?
|
||||
- Use specific examples
|
||||
|
||||
**C. Present Your Insight (3-4 minutes)**
|
||||
- How did you discover this?
|
||||
- What's the evidence?
|
||||
- Show, don't just tell
|
||||
- Use visuals, demos, examples
|
||||
|
||||
**D. Address Skepticism (2-3 minutes)**
|
||||
- Anticipate objections
|
||||
- Provide counter-evidence
|
||||
- Show edge cases or limitations
|
||||
- Builds credibility through honesty
|
||||
|
||||
**E. Expand Implications (2-3 minutes)**
|
||||
- If this is true, what else becomes possible?
|
||||
- Connect to broader themes
|
||||
- Show systemic impact
|
||||
- Paint the bigger picture
|
||||
|
||||
**Pacing**:
|
||||
- Vary between explanation and example
|
||||
- Use visuals liberally (minimal text)
|
||||
- Build complexity gradually
|
||||
- Create "aha" moments through revelation
|
||||
|
||||
**Part 4: Call to Action (2-3 minutes)**
|
||||
|
||||
*Purpose: Make the idea actionable*
|
||||
|
||||
**Not Generic**:
|
||||
- ❌ "Think about this differently"
|
||||
- ❌ "Spread the word"
|
||||
- ❌ "Let's make a change"
|
||||
|
||||
**Specific and Achievable**:
|
||||
- ✅ "Tomorrow, ask your child what they're curious about, not what they learned"
|
||||
- ✅ "Visit this website and take the 5-minute assessment"
|
||||
- ✅ "Share one thing you're uncertain about at your next team meeting"
|
||||
|
||||
**Scaling Calls to Action**:
|
||||
1. **Individual**: What can one person do?
|
||||
2. **Collective**: What can we do together?
|
||||
3. **Systemic**: What policy/institutional change is needed?
|
||||
|
||||
**Format**:
|
||||
```
|
||||
"Here's what I'm asking you to do..."
|
||||
↓
|
||||
[Specific action]
|
||||
↓
|
||||
"If enough of us do this..."
|
||||
↓
|
||||
[Collective impact]
|
||||
```
|
||||
|
||||
**Part 5: Memorable Close (30-60 seconds)**
|
||||
|
||||
*Purpose: Leave lasting impression*
|
||||
|
||||
**Closing Techniques**:
|
||||
|
||||
1. **Full Circle**
|
||||
- Return to opening hook
|
||||
- Show how it's now understood differently
|
||||
- "Remember that question I asked? Now you know the answer."
|
||||
|
||||
2. **Vision of Future**
|
||||
- Paint specific picture of transformed world
|
||||
- Make it tangible and emotional
|
||||
- "Imagine a world where..."
|
||||
|
||||
3. **Powerful Quote**
|
||||
- From relevant source
|
||||
- Must genuinely add insight, not decorative
|
||||
- Brief setup, then quote
|
||||
|
||||
4. **Personal Commitment**
|
||||
- What you're dedicating yourself to
|
||||
- Inspires through example
|
||||
- "I'm going to spend the next decade..."
|
||||
|
||||
5. **Direct Challenge**
|
||||
- Bold ask or provocative question
|
||||
- Leaves them thinking
|
||||
- "So I ask you: what are you willing to question?"
|
||||
|
||||
**Critical Elements**:
|
||||
- NEVER end with Q&A
|
||||
- NEVER end with "Thank you"
|
||||
- NEVER trail off or rush
|
||||
- End with power and intention
|
||||
|
||||
### Application Guidelines
|
||||
|
||||
**Best Used For**:
|
||||
- Conference keynotes
|
||||
- Inspirational talks
|
||||
- Idea-centric presentations (vs. product/sales)
|
||||
- 15-20 minute time slots
|
||||
- Presentations that will be recorded/shared
|
||||
|
||||
**Not Recommended For**:
|
||||
- Internal updates
|
||||
- Highly technical content
|
||||
- Sales pitches (too obvious)
|
||||
- Very short presentations (<10 minutes)
|
||||
|
||||
**Slide Count Implications**:
|
||||
- Minimum: 8-10 slides
|
||||
- Typical: 12-18 slides
|
||||
- Maximum: 25 slides
|
||||
- Heavy visual focus—many slides with single images
|
||||
|
||||
### Example: Education Innovation
|
||||
|
||||
**Hook (Slide 1)**: Photo of frustrated student. "What if school is making kids less curious, not more?"
|
||||
|
||||
**Personal (Slides 2-3)**:
|
||||
- Slide 2: Photo of speaker's daughter
|
||||
- Slide 3: Story of her losing interest in learning
|
||||
|
||||
**Core Idea (Slides 4-12)**:
|
||||
- Slide 4: "We're teaching answers. We should teach questions."
|
||||
- Slide 5-6: Research on curiosity and learning
|
||||
- Slide 7-8: Examples of question-driven classrooms
|
||||
- Slide 9: Data on outcomes
|
||||
- Slide 10: Addressing "but standards..." objection
|
||||
- Slide 11-12: Bigger implications for society
|
||||
|
||||
**Call to Action (Slides 13-14)**:
|
||||
- Slide 13: "Three questions to ask tomorrow"
|
||||
- Slide 14: How to join the movement
|
||||
|
||||
**Close (Slide 15)**: Back to daughter's photo. "She's asking questions again. Let's make sure every kid can."
|
||||
|
||||
---
|
||||
|
||||
## Framework 4: Classic Three-Act Structure
|
||||
|
||||
### Overview
|
||||
|
||||
The oldest storytelling structure, dating back to Aristotle. Still relevant because it mirrors natural narrative arc and audience expectations.
|
||||
|
||||
### The Structure
|
||||
|
||||
```
|
||||
ACT 1: SETUP (25% of presentation)
|
||||
├─ Introduce "characters" (people, problems, concepts)
|
||||
├─ Establish ordinary world/current state
|
||||
└─ Inciting incident (why this matters now)
|
||||
|
||||
ACT 2: CONFRONTATION (50% of presentation)
|
||||
├─ Explore problem deeply
|
||||
├─ Failed attempts or challenges
|
||||
├─ Rising action and complications
|
||||
├─ Midpoint revelation or shift
|
||||
└─ Escalation to crisis point
|
||||
|
||||
ACT 3: RESOLUTION (25% of presentation)
|
||||
├─ Climax (solution or insight)
|
||||
├─ Falling action (how it works)
|
||||
└─ Denouement (new equilibrium)
|
||||
```
|
||||
|
||||
### Detailed Breakdown
|
||||
|
||||
**Act 1: Setup (25%)**
|
||||
|
||||
*Purpose: Establish context and create investment*
|
||||
|
||||
**1.1 Ordinary World (5-8% of presentation)**
|
||||
- Current state of affairs
|
||||
- Familiar, relatable situation
|
||||
- Establishes baseline for measuring change
|
||||
- Example: "For 150 years, education has looked like this..."
|
||||
|
||||
**1.2 Introduction of "Characters" (5-8%)**
|
||||
- Who is affected? (students, teachers, parents)
|
||||
- What are their goals and challenges?
|
||||
- Make audience care about these people
|
||||
- Example: "Meet Sarah, a third-grade teacher who..."
|
||||
|
||||
**1.3 Inciting Incident (10-12%)**
|
||||
- The catalyst—why now?
|
||||
- What changed or was discovered?
|
||||
- Creates urgency and forward momentum
|
||||
- Example: "Then COVID-19 forced the entire system online overnight..."
|
||||
|
||||
**Act 2: Confrontation (50%)**
|
||||
|
||||
*Purpose: Explore depth, build tension, earn the resolution*
|
||||
|
||||
**2.1 Exploring the Problem (10-15%)**
|
||||
- Dig deeper into challenges
|
||||
- Show why obvious solutions don't work
|
||||
- Build complexity and nuance
|
||||
- Example: "Virtual learning exposed three fundamental flaws..."
|
||||
|
||||
**2.2 Failed Attempts / Obstacles (10-15%)**
|
||||
- What's been tried?
|
||||
- Why didn't it work?
|
||||
- Shows understanding of difficulty
|
||||
- Builds credibility
|
||||
- Example: "Districts spent millions on tablets. Engagement actually decreased..."
|
||||
|
||||
**2.3 Midpoint Shift (5-8%)**
|
||||
- New information or perspective
|
||||
- "What we discovered changed everything"
|
||||
- Turning point in understanding
|
||||
- Example: "But one school tried something different..."
|
||||
|
||||
**2.4 Escalating Complexity (10-15%)**
|
||||
- Deeper implications emerge
|
||||
- Stakes get higher
|
||||
- "It's not just about X, it's about Y"
|
||||
- Example: "This isn't a technology problem—it's an identity crisis for educators..."
|
||||
|
||||
**2.5 Crisis Point (5-8%)**
|
||||
- Moment of maximum tension
|
||||
- "We have to choose"
|
||||
- Forces decision or action
|
||||
- Example: "We can keep pretending this works, or we can reimagine education entirely"
|
||||
|
||||
**Act 3: Resolution (25%)**
|
||||
|
||||
*Purpose: Deliver payoff, show path forward*
|
||||
|
||||
**3.1 Climax (8-10%)**
|
||||
- The solution, insight, or breakthrough
|
||||
- Moment of greatest revelation
|
||||
- "Here's what actually works"
|
||||
- Example: "When we let students drive their own learning..."
|
||||
|
||||
**3.2 How It Works (10-12%)**
|
||||
- Practical implementation
|
||||
- Evidence and examples
|
||||
- Concrete details
|
||||
- Example: "Here's what it looks like in practice..."
|
||||
|
||||
**3.3 New Equilibrium (7-8%)**
|
||||
- What's different now?
|
||||
- How has world transformed?
|
||||
- Call to action
|
||||
- Future vision
|
||||
- Example: "This is education for 2025 and beyond. Here's how we get there..."
|
||||
|
||||
### Application Guidelines
|
||||
|
||||
**Best Used For**:
|
||||
- Story-driven presentations
|
||||
- Case studies
|
||||
- Transformation narratives
|
||||
- Problem-solution structures
|
||||
- Medium to long presentations (20-45 minutes)
|
||||
|
||||
**Not Recommended For**:
|
||||
- Pure data presentations
|
||||
- Quick updates
|
||||
- Highly technical content without narrative
|
||||
- Very short presentations (<15 minutes)
|
||||
|
||||
**Slide Count Implications**:
|
||||
- Short version (20 min): 15-20 slides
|
||||
- Act 1: 4-5 slides
|
||||
- Act 2: 8-10 slides
|
||||
- Act 3: 4-5 slides
|
||||
- Long version (45 min): 25-35 slides
|
||||
- Act 1: 6-9 slides
|
||||
- Act 2: 13-18 slides
|
||||
- Act 3: 6-9 slides
|
||||
|
||||
---
|
||||
|
||||
## Framework Comparison Matrix
|
||||
|
||||
| Framework | Duration | Slide Count | Best For | Emotional Arc | Complexity |
|
||||
|-----------|----------|-------------|----------|---------------|------------|
|
||||
| **Sparkline** | 20-30 min | 18-25 | Keynotes, vision casting | High peaks and valleys | High |
|
||||
| **Rule of Three** | 15-30 min | 12-18 | Product launches, demos | Steady building | Medium |
|
||||
| **TED Structure** | 15-20 min | 12-18 | Idea-centric, inspirational | Single climactic peak | Medium-High |
|
||||
| **Three-Act** | 20-45 min | 15-35 | Case studies, narratives | Rising to climax, resolution | High |
|
||||
|
||||
---
|
||||
|
||||
## Choosing the Right Framework
|
||||
|
||||
### Decision Tree
|
||||
|
||||
**Start Here**: What's your primary goal?
|
||||
|
||||
**If INSPIRE/TRANSFORM**:
|
||||
- Duration 20+ minutes → Sparkline
|
||||
- Duration <20 minutes → TED Structure
|
||||
|
||||
**If PERSUADE/SELL**:
|
||||
- Product-focused → Rule of Three
|
||||
- Story-driven → Three-Act Structure
|
||||
|
||||
**If INFORM/EDUCATE**:
|
||||
- Problem-solution → Three-Act Structure
|
||||
- Feature demonstration → Rule of Three
|
||||
|
||||
**If QUICK UPDATE**:
|
||||
- None of these—use simple structure
|
||||
- Opening → Key Points → Close
|
||||
|
||||
### Hybrid Approaches
|
||||
|
||||
You can combine frameworks:
|
||||
|
||||
**Sparkline + Rule of Three**:
|
||||
- Use sparkline emotional arc
|
||||
- Organize "what could be" sections into three main points
|
||||
- Example: Three visions of future, each contrasted with reality
|
||||
|
||||
**TED + Three-Act**:
|
||||
- Hook and personal connection (Act 1)
|
||||
- Core idea as confrontation (Act 2)
|
||||
- Call to action as resolution (Act 3)
|
||||
- Natural alignment
|
||||
|
||||
**Rule of Three + Sparkline**:
|
||||
- Three main features/points
|
||||
- Each point uses mini sparkline (is/could be contrast)
|
||||
- Builds to overall transformation
|
||||
|
||||
---
|
||||
|
||||
## Common Mistakes Across All Frameworks
|
||||
|
||||
### Structural Errors
|
||||
|
||||
1. **Starting with agenda slide**
|
||||
- Kills momentum
|
||||
- Signals boring presentation
|
||||
- Better: Jump right into hook
|
||||
|
||||
2. **No clear inciting incident**
|
||||
- Presentation lacks urgency
|
||||
- "Why now?" is unclear
|
||||
- Audience questions relevance
|
||||
|
||||
3. **Unearned climax**
|
||||
- Big reveal without proper buildup
|
||||
- Audience isn't prepared to appreciate it
|
||||
- Falls flat
|
||||
|
||||
4. **Multiple climaxes**
|
||||
- Trying to make everything important
|
||||
- Dilutes actual peak moments
|
||||
- Confuses audience
|
||||
|
||||
5. **Weak ending**
|
||||
- Trailing off
|
||||
- "Any questions?" as close
|
||||
- Not landing the message
|
||||
|
||||
### Content Errors
|
||||
|
||||
1. **Too much setup**
|
||||
- Spending 40% on background
|
||||
- Audience loses patience
|
||||
- Core message gets rushed
|
||||
|
||||
2. **No conflict/tension**
|
||||
- All smooth sailing
|
||||
- Boring, not engaging
|
||||
- No stakes
|
||||
|
||||
3. **Ignoring obstacles**
|
||||
- Presenting solution without acknowledging challenges
|
||||
- Seems naive or dishonest
|
||||
- Reduces credibility
|
||||
|
||||
4. **Missing emotional beats**
|
||||
- All facts, no feeling
|
||||
- Cognitively exhausting
|
||||
- Forgettable
|
||||
|
||||
---
|
||||
|
||||
## Advanced Techniques
|
||||
|
||||
### The Nested Story
|
||||
|
||||
Embed smaller stories within main framework:
|
||||
|
||||
```
|
||||
Main Framework: Three-Act Structure
|
||||
Act 2 includes:
|
||||
→ Customer story (mini three-act)
|
||||
→ Team journey (mini three-act)
|
||||
→ Product development (mini three-act)
|
||||
```
|
||||
|
||||
Each nested story has own arc but serves larger narrative.
|
||||
|
||||
### The Recurring Motif
|
||||
|
||||
Introduce element in opening, revisit throughout:
|
||||
|
||||
- Physical object that represents theme
|
||||
- Phrase that gains new meaning
|
||||
- Image that appears multiple times
|
||||
- Question that gets progressively answered
|
||||
|
||||
Example: "What makes a teacher great?" asked at start, explored through presentation, answered with new depth at end.
|
||||
|
||||
### The Parallel Structure
|
||||
|
||||
Tell two stories simultaneously that converge:
|
||||
|
||||
```
|
||||
Story A (Problem): Traditional education path
|
||||
Story B (Solution): New approach
|
||||
↓ ↓
|
||||
Converge: Shows contrast
|
||||
```
|
||||
|
||||
Slides alternate between Story A and Story B until they meet.
|
||||
|
||||
### The Revelation Sequence
|
||||
|
||||
Withhold key information, reveal progressively:
|
||||
|
||||
```
|
||||
Slide 1: "We tested 10 approaches"
|
||||
Slide 2: "9 failed"
|
||||
Slide 3: "But one..."
|
||||
Slide 4: [The one that worked]
|
||||
```
|
||||
|
||||
Builds suspense through controlled information release.
|
||||
|
||||
---
|
||||
|
||||
## Testing Your Structure
|
||||
|
||||
### Before Finalizing
|
||||
|
||||
**The Elevator Test**:
|
||||
- Can you summarize arc in 30 seconds?
|
||||
- If not, structure is too complex
|
||||
|
||||
**The Emotional Check**:
|
||||
- Map emotional intensity across slides
|
||||
- Should have valleys and peaks, not flat line
|
||||
- Highest peak should be near end (not middle)
|
||||
|
||||
**The "So What?" Test**:
|
||||
- After each major section: "So what?"
|
||||
- If you can't answer, section doesn't earn its place
|
||||
|
||||
**The Memory Test**:
|
||||
- What will audience remember 24 hours later?
|
||||
- Structure should make key points memorable
|
||||
- If everything is equally important, nothing is
|
||||
|
||||
### After First Rehearsal
|
||||
|
||||
**The Timing Test**:
|
||||
- Does reality match planned percentages?
|
||||
- If Act 1 is taking 40% of time, rebalance
|
||||
|
||||
**The Flow Test**:
|
||||
- Do transitions feel natural?
|
||||
- Is there a clear through-line?
|
||||
- Can you feel the momentum?
|
||||
|
||||
**The Engagement Test**:
|
||||
- Present to test audience
|
||||
- Where do they lean in?
|
||||
- Where do they check out?
|
||||
- Adjust structure accordingly
|
||||
|
||||
---
|
||||
|
||||
This comprehensive guide to story frameworks provides the architectural foundation for presentations that aren't just informative—they're transformative. Master these structures, and you'll never wonder "what comes next?" again.
|
||||
149
skills/presentation-master/principles/validation-rules.md
Normal file
149
skills/presentation-master/principles/validation-rules.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# Validation Rules & Scoring System
|
||||
|
||||
Automatic quality assessment for presentations.
|
||||
|
||||
## Scoring Formula (0-100)
|
||||
|
||||
### Simplicity (10 points)
|
||||
- **Word count per slide**: 0-3 words = 10pts, 4-6 words = 8pts, 7-10 words = 5pts, >10 words = 0pts
|
||||
- **Visual clutter**: Single element = 10pts, 2-3 elements = 8pts, 4-5 elements = 5pts, >5 elements = 0pts
|
||||
|
||||
### Visual Dominance (10 points)
|
||||
- **Image quality**: All high-res = 10pts, some low-res = 5pts, no images = 0pts
|
||||
- **Text-to-visual ratio**: 20/80 or better = 10pts, 50/50 = 5pts, 80/20 = 0pts
|
||||
|
||||
### Story Structure (10 points)
|
||||
- **Narrative arc**: Clear beginning/middle/end = 10pts, partial = 5pts, none = 0pts
|
||||
- **Emotional beats**: 3+ moments = 10pts, 1-2 moments = 5pts, none = 0pts
|
||||
|
||||
### One Idea Per Slide (10 points)
|
||||
- **Concept clarity**: All slides single-concept = 10pts, most = 7pts, mixed = 3pts, confused = 0pts
|
||||
|
||||
### Typography (8 points)
|
||||
- **Font size**: All 36pt+ = 8pts, all 30pt+ = 6pts, some <30pt = 2pts, any <24pt = 0pts
|
||||
- **Consistency**: 1 font family = 8pts, 2 families = 6pts, 3+ families = 0pts
|
||||
|
||||
### Layout (7 points)
|
||||
- **Visual hierarchy**: Clear focal points = 7pts, somewhat clear = 4pts, unclear = 0pts
|
||||
- **Whitespace**: 40%+ = 7pts, 20-40% = 4pts, <20% = 0pts
|
||||
- **Alignment**: All aligned = 7pts, mostly = 4pts, inconsistent = 0pts
|
||||
|
||||
### Color/Contrast (7 points)
|
||||
- **Readability**: 7:1+ contrast = 7pts, 4.5:1+ = 5pts, <4.5:1 = 0pts
|
||||
- **Consistency**: Single palette = 7pts, mixed = 3pts, chaotic = 0pts
|
||||
|
||||
### Media Quality (8 points)
|
||||
- **Image resolution**: All 2K+ = 8pts, all 1K+ = 6pts, some low-res = 2pts
|
||||
- **Relevance**: All relevant = 8pts, mostly = 5pts, decorative = 0pts
|
||||
|
||||
### Cognitive Load (20 points)
|
||||
- **Mayer's 12 principles adherence**: 10-12 = 20pts, 7-9 = 15pts, 4-6 = 10pts, 1-3 = 5pts, 0 = 0pts
|
||||
|
||||
### Data Integrity (10 points, if applicable)
|
||||
- **Lie factor**: 0.95-1.05 = 10pts, 0.90-1.10 = 7pts, 0.80-1.20 = 3pts, outside = 0pts
|
||||
- **Data-ink ratio**: Maximized = 10pts, good = 7pts, poor = 3pts, terrible = 0pts
|
||||
|
||||
## Critical Violations (Auto-Fail)
|
||||
|
||||
These cause immediate score reduction or failure:
|
||||
|
||||
1. **Font size < 30pt** → -20 points
|
||||
2. **>10 core concepts** → -15 points (Kawasaki violation)
|
||||
3. **Bullet points detected** → -10 points per slide
|
||||
4. **Paragraphs (>2 sentences)** → -10 points per slide
|
||||
5. **Contrast ratio <4.5:1** → -15 points
|
||||
6. **Default template detected** → -20 points
|
||||
|
||||
## Warning Flags
|
||||
|
||||
These reduce score but don't fail:
|
||||
|
||||
1. **>6 words per slide** → -2 points per violation (Godin standard)
|
||||
2. **>15 slides for 20-min presentation** → -5 points
|
||||
3. **No images** → -10 points
|
||||
4. **Text-heavy slides (>3 lines)** → -3 points per slide
|
||||
5. **Inconsistent fonts (>2 families)** → -5 points
|
||||
6. **Low-res images** → -3 points per image
|
||||
|
||||
## Score Interpretation
|
||||
|
||||
- **90-100**: Exceptional - TED/Keynote quality
|
||||
- **80-89**: Excellent - Professional standard
|
||||
- **70-79**: Good - Solid presentation
|
||||
- **60-69**: Acceptable - Needs improvement
|
||||
- **<60**: Poor - Major revisions needed
|
||||
|
||||
## Automated Checks (JavaScript)
|
||||
|
||||
```javascript
|
||||
function validatePresentation(slides) {
|
||||
let score = 0;
|
||||
const issues = [];
|
||||
|
||||
// Check each slide
|
||||
slides.forEach((slide, i) => {
|
||||
const wordCount = slide.text.split(' ').length;
|
||||
const fontSize = slide.minFontSize;
|
||||
const hasBullets = slide.text.includes('•') || slide.text.includes('-');
|
||||
|
||||
// Word count scoring
|
||||
if (wordCount <= 3) score += 10 / slides.length;
|
||||
else if (wordCount <= 6) score += 8 / slides.length;
|
||||
else if (wordCount <= 10) score += 5 / slides.length;
|
||||
else issues.push(`Slide ${i+1}: ${wordCount} words (recommend ≤6)`);
|
||||
|
||||
// Font size critical check
|
||||
if (fontSize < 30) {
|
||||
score -= 20;
|
||||
issues.push(`CRITICAL: Slide ${i+1} has ${fontSize}pt font (minimum 30pt)`);
|
||||
}
|
||||
|
||||
// Bullet point check
|
||||
if (hasBullets) {
|
||||
score -= 10;
|
||||
issues.push(`CRITICAL: Slide ${i+1} has bullet points (use individual slides)`);
|
||||
}
|
||||
});
|
||||
|
||||
return { score: Math.max(0, Math.min(100, score)), issues };
|
||||
}
|
||||
```
|
||||
|
||||
## Quality Report Template
|
||||
|
||||
```markdown
|
||||
# Presentation Quality Report
|
||||
|
||||
**Overall Score**: {score}/100
|
||||
**Status**: {Exceptional|Excellent|Good|Acceptable|Poor}
|
||||
|
||||
## Strengths
|
||||
- {List what scores well}
|
||||
|
||||
## Critical Issues
|
||||
- {Font size violations}
|
||||
- {Bullet points}
|
||||
- {Contrast problems}
|
||||
|
||||
## Warnings
|
||||
- {Word count}
|
||||
- {Slide count}
|
||||
- {Consistency issues}
|
||||
|
||||
## Recommendations
|
||||
1. {Highest priority fix}
|
||||
2. {Second priority}
|
||||
3. {Third priority}
|
||||
|
||||
## Score Breakdown
|
||||
- Simplicity: {score}/10
|
||||
- Visual Dominance: {score}/10
|
||||
- Story Structure: {score}/10
|
||||
- One Idea/Slide: {score}/10
|
||||
- Typography: {score}/8
|
||||
- Layout: {score}/7
|
||||
- Color/Contrast: {score}/7
|
||||
- Media Quality: {score}/8
|
||||
- Cognitive Load: {score}/20
|
||||
- Data Integrity: {score}/10 (if applicable)
|
||||
```
|
||||
370
skills/presentation-master/scripts/analyze-context.js
Normal file
370
skills/presentation-master/scripts/analyze-context.js
Normal file
@@ -0,0 +1,370 @@
|
||||
#!/usr/bin/env bun
|
||||
|
||||
/**
|
||||
* Presentation Context Analyzer
|
||||
*
|
||||
* Analyzes topic, audience, duration, purpose to detect presentation type
|
||||
* and recommend appropriate story framework.
|
||||
*
|
||||
* Usage:
|
||||
* bun analyze-context.js --topic "Cybersecurity Trends" --audience "School Board" --duration "15min" --purpose "inform"
|
||||
*
|
||||
* Output: JSON with presentation type, recommended framework, pattern distribution
|
||||
*/
|
||||
|
||||
const PRESENTATION_TYPES = {
|
||||
BOARD_UPDATE: {
|
||||
name: 'board-update',
|
||||
indicators: ['board', 'executive', 'update', 'quarterly', 'status', 'report'],
|
||||
characteristics: {
|
||||
audience_technical: 'low',
|
||||
focus: 'data-driven',
|
||||
primary_goal: 'inform + recommend',
|
||||
typical_duration: '15-20min'
|
||||
},
|
||||
pattern_distribution: {
|
||||
'data-viz': 0.40,
|
||||
'visual-caption': 0.30,
|
||||
'transition': 0.20,
|
||||
'title': 0.10
|
||||
},
|
||||
recommended_frameworks: ['classic-three-act', 'rule-of-three']
|
||||
},
|
||||
|
||||
KEYNOTE: {
|
||||
name: 'keynote',
|
||||
indicators: ['keynote', 'conference', 'inspire', 'vision', 'future', 'transform'],
|
||||
characteristics: {
|
||||
audience_technical: 'mixed',
|
||||
focus: 'inspirational',
|
||||
primary_goal: 'shift perspective',
|
||||
typical_duration: '20-30min'
|
||||
},
|
||||
pattern_distribution: {
|
||||
'big-idea': 0.40,
|
||||
'visual-caption': 0.30,
|
||||
'title': 0.20,
|
||||
'transition': 0.10
|
||||
},
|
||||
recommended_frameworks: ['sparkline', 'rule-of-three', 'ted']
|
||||
},
|
||||
|
||||
TRAINING: {
|
||||
name: 'training',
|
||||
indicators: ['training', 'workshop', 'tutorial', 'learn', 'how-to', 'guide'],
|
||||
characteristics: {
|
||||
audience_technical: 'variable',
|
||||
focus: 'educational',
|
||||
primary_goal: 'teach + practice',
|
||||
typical_duration: '30-60min'
|
||||
},
|
||||
pattern_distribution: {
|
||||
'process': 0.40,
|
||||
'data-viz': 0.30,
|
||||
'visual-caption': 0.20,
|
||||
'title': 0.10
|
||||
},
|
||||
recommended_frameworks: ['classic-three-act']
|
||||
},
|
||||
|
||||
PITCH: {
|
||||
name: 'pitch',
|
||||
indicators: ['pitch', 'proposal', 'investment', 'funding', 'sell', 'convince'],
|
||||
characteristics: {
|
||||
audience_technical: 'mixed',
|
||||
focus: 'persuasive',
|
||||
primary_goal: 'convince + action',
|
||||
typical_duration: '10-20min'
|
||||
},
|
||||
pattern_distribution: {
|
||||
'data-viz': 0.30,
|
||||
'big-idea': 0.30,
|
||||
'visual-caption': 0.25,
|
||||
'title-transition': 0.15
|
||||
},
|
||||
recommended_frameworks: ['rule-of-three', 'classic-three-act']
|
||||
},
|
||||
|
||||
TED_STYLE: {
|
||||
name: 'ted-style',
|
||||
indicators: ['ted', 'idea', 'story', 'personal', 'change the world'],
|
||||
characteristics: {
|
||||
audience_technical: 'general',
|
||||
focus: 'idea-centric',
|
||||
primary_goal: 'inspire + spread idea',
|
||||
typical_duration: '15-20min'
|
||||
},
|
||||
pattern_distribution: {
|
||||
'big-idea': 0.35,
|
||||
'visual-caption': 0.35,
|
||||
'transition': 0.20,
|
||||
'title': 0.10
|
||||
},
|
||||
recommended_frameworks: ['ted']
|
||||
}
|
||||
};
|
||||
|
||||
const STORY_FRAMEWORKS = {
|
||||
'sparkline': {
|
||||
name: "Nancy Duarte's Sparkline",
|
||||
duration: '20-30min',
|
||||
slides: '18-25',
|
||||
best_for: ['keynote', 'ted-style'],
|
||||
structure: 'Alternate "what is" (reality) with "what could be" (aspiration)',
|
||||
complexity: 'high'
|
||||
},
|
||||
|
||||
'rule-of-three': {
|
||||
name: "Steve Jobs' Rule of Three",
|
||||
duration: '15-30min',
|
||||
slides: '12-18',
|
||||
best_for: ['keynote', 'pitch', 'board-update'],
|
||||
structure: 'Three main sections, three points per section',
|
||||
complexity: 'medium'
|
||||
},
|
||||
|
||||
'ted': {
|
||||
name: 'TED Talk Structure',
|
||||
duration: '15-20min',
|
||||
slides: '12-18',
|
||||
best_for: ['ted-style', 'keynote'],
|
||||
structure: 'Hook → Personal → Core Idea → Call to Action → Close',
|
||||
complexity: 'medium'
|
||||
},
|
||||
|
||||
'classic-three-act': {
|
||||
name: 'Classic Three-Act Structure',
|
||||
duration: '20-45min',
|
||||
slides: '15-35',
|
||||
best_for: ['training', 'board-update', 'pitch'],
|
||||
structure: 'Setup (25%) → Confrontation (50%) → Resolution (25%)',
|
||||
complexity: 'low'
|
||||
}
|
||||
};
|
||||
|
||||
function parseDuration(durationStr) {
|
||||
// Parse strings like "15min", "20 minutes", "1 hour", "45m"
|
||||
const matches = durationStr.toLowerCase().match(/(\d+)\s*(min|minute|minutes|m|hour|hours|h)/);
|
||||
if (!matches) return null;
|
||||
|
||||
const value = parseInt(matches[1]);
|
||||
const unit = matches[2];
|
||||
|
||||
if (unit.startsWith('h')) {
|
||||
return value * 60; // convert to minutes
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function detectPresentationType(topic, audience, purpose) {
|
||||
const combined = `${topic} ${audience} ${purpose}`.toLowerCase();
|
||||
const scores = {};
|
||||
|
||||
for (const [key, type] of Object.entries(PRESENTATION_TYPES)) {
|
||||
let score = 0;
|
||||
|
||||
// Check for indicator keywords
|
||||
for (const indicator of type.indicators) {
|
||||
if (combined.includes(indicator)) {
|
||||
score += 10;
|
||||
}
|
||||
}
|
||||
|
||||
scores[type.name] = score;
|
||||
}
|
||||
|
||||
// Find highest scoring type
|
||||
const sortedTypes = Object.entries(scores).sort((a, b) => b[1] - a[1]);
|
||||
|
||||
if (sortedTypes[0][1] === 0) {
|
||||
// No clear match, default based on purpose
|
||||
if (purpose.includes('teach') || purpose.includes('train')) return 'training';
|
||||
if (purpose.includes('inspire') || purpose.includes('motivate')) return 'keynote';
|
||||
if (purpose.includes('convince') || purpose.includes('sell')) return 'pitch';
|
||||
return 'board-update'; // conservative default
|
||||
}
|
||||
|
||||
return sortedTypes[0][0];
|
||||
}
|
||||
|
||||
function recommendFrameworks(presentationType, durationMinutes) {
|
||||
const type = Object.values(PRESENTATION_TYPES).find(t => t.name === presentationType);
|
||||
if (!type) return [];
|
||||
|
||||
// Get recommended frameworks for this type
|
||||
const recommendations = type.recommended_frameworks.map(fw => {
|
||||
const framework = STORY_FRAMEWORKS[fw];
|
||||
|
||||
// Parse framework duration range
|
||||
const durationMatch = framework.duration.match(/(\d+)-(\d+)min/);
|
||||
if (!durationMatch) return { ...framework, key: fw, fit_score: 50 };
|
||||
|
||||
const minDuration = parseInt(durationMatch[1]);
|
||||
const maxDuration = parseInt(durationMatch[2]);
|
||||
|
||||
// Score based on duration fit
|
||||
let fit_score = 50;
|
||||
if (durationMinutes >= minDuration && durationMinutes <= maxDuration) {
|
||||
fit_score = 100;
|
||||
} else if (durationMinutes < minDuration) {
|
||||
fit_score = Math.max(0, 100 - ((minDuration - durationMinutes) * 5));
|
||||
} else {
|
||||
fit_score = Math.max(0, 100 - ((durationMinutes - maxDuration) * 5));
|
||||
}
|
||||
|
||||
return {
|
||||
key: fw,
|
||||
...framework,
|
||||
fit_score
|
||||
};
|
||||
});
|
||||
|
||||
// Sort by fit score
|
||||
return recommendations.sort((a, b) => b.fit_score - a.fit_score);
|
||||
}
|
||||
|
||||
function estimateSlideCount(durationMinutes, presentationType) {
|
||||
// Guy Kawasaki: 10 slides for 20 minutes = 0.5 slides/min
|
||||
// Adjust based on presentation type
|
||||
|
||||
const rates = {
|
||||
'board-update': 0.5, // More data-heavy, slower pace
|
||||
'keynote': 0.7, // More visuals, faster pace
|
||||
'training': 0.4, // More explanation needed
|
||||
'pitch': 0.6, // Balanced
|
||||
'ted-style': 0.8 // Fast-paced, visual
|
||||
};
|
||||
|
||||
const rate = rates[presentationType] || 0.5;
|
||||
const baseCount = Math.round(durationMinutes * rate);
|
||||
|
||||
// Kawasaki's hard limit: max 10 core concepts
|
||||
// But we can have transition/title slides
|
||||
const maxCoreSlides = 10;
|
||||
const coreSlides = Math.min(baseCount, maxCoreSlides);
|
||||
const supportSlides = Math.ceil(coreSlides * 0.3); // 30% support slides
|
||||
|
||||
return {
|
||||
total: coreSlides + supportSlides,
|
||||
core: coreSlides,
|
||||
support: supportSlides,
|
||||
recommendation: coreSlides + supportSlides <= 15 ? 'optimal' : 'consider-simplifying'
|
||||
};
|
||||
}
|
||||
|
||||
function analyzeAudience(audienceStr) {
|
||||
const lower = audienceStr.toLowerCase();
|
||||
|
||||
// Technical level
|
||||
let technical_level = 'medium';
|
||||
if (lower.match(/board|executive|c-suite|non-technical/)) {
|
||||
technical_level = 'low';
|
||||
} else if (lower.match(/engineer|developer|technical|expert|specialist/)) {
|
||||
technical_level = 'high';
|
||||
}
|
||||
|
||||
// Decision-making power
|
||||
let decision_power = 'medium';
|
||||
if (lower.match(/board|executive|ceo|cio|cto|director|vp/)) {
|
||||
decision_power = 'high';
|
||||
} else if (lower.match(/staff|team|individual contributor|ic/)) {
|
||||
decision_power = 'low';
|
||||
}
|
||||
|
||||
// Size
|
||||
let size = 'medium';
|
||||
if (lower.match(/small|intimate|1:1|one-on-one/)) {
|
||||
size = 'small';
|
||||
} else if (lower.match(/large|conference|hundreds|auditorium/)) {
|
||||
size = 'large';
|
||||
}
|
||||
|
||||
return {
|
||||
technical_level,
|
||||
decision_power,
|
||||
size,
|
||||
recommendations: {
|
||||
font_size: size === 'large' ? '42pt+' : '36pt+',
|
||||
detail_level: technical_level === 'high' ? 'can-include-technical-details' : 'avoid-jargon',
|
||||
call_to_action: decision_power === 'high' ? 'specific-next-steps' : 'awareness-building'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function generateAnalysis(args) {
|
||||
const topic = args.topic || '';
|
||||
const audience = args.audience || '';
|
||||
const duration = args.duration || '20min';
|
||||
const purpose = args.purpose || '';
|
||||
|
||||
const durationMinutes = parseDuration(duration);
|
||||
const presentationType = detectPresentationType(topic, audience, purpose);
|
||||
const typeDetails = Object.values(PRESENTATION_TYPES).find(t => t.name === presentationType);
|
||||
const frameworks = recommendFrameworks(presentationType, durationMinutes);
|
||||
const slideEstimate = estimateSlideCount(durationMinutes, presentationType);
|
||||
const audienceAnalysis = analyzeAudience(audience);
|
||||
|
||||
return {
|
||||
input: {
|
||||
topic,
|
||||
audience,
|
||||
duration,
|
||||
purpose
|
||||
},
|
||||
analysis: {
|
||||
presentation_type: presentationType,
|
||||
type_characteristics: typeDetails.characteristics,
|
||||
audience_analysis: audienceAnalysis,
|
||||
duration_minutes: durationMinutes,
|
||||
slide_estimate: slideEstimate,
|
||||
pattern_distribution: typeDetails.pattern_distribution
|
||||
},
|
||||
recommendations: {
|
||||
primary_framework: frameworks[0],
|
||||
alternative_frameworks: frameworks.slice(1),
|
||||
key_principles: [
|
||||
'Maximum 6 words per slide (Seth Godin)',
|
||||
`Font size minimum: ${audienceAnalysis.recommendations.font_size}`,
|
||||
`${slideEstimate.core} core concepts maximum (Guy Kawasaki)`,
|
||||
'One idea per slide',
|
||||
'Visual dominance over text'
|
||||
]
|
||||
},
|
||||
warnings: [
|
||||
slideEstimate.recommendation === 'consider-simplifying'
|
||||
? `⚠️ ${slideEstimate.total} slides may be too many - consider simplifying to ${Math.min(slideEstimate.core, 10)} core concepts`
|
||||
: null,
|
||||
durationMinutes > 30
|
||||
? '⚠️ Presentations >30min risk losing audience attention - consider breaking into sections'
|
||||
: null,
|
||||
audienceAnalysis.technical_level === 'low' && topic.toLowerCase().match(/technical|technology|ai|software/)
|
||||
? '⚠️ Non-technical audience + technical topic = extra emphasis on visual metaphors'
|
||||
: null
|
||||
].filter(w => w !== null)
|
||||
};
|
||||
}
|
||||
|
||||
// CLI Interface
|
||||
function main() {
|
||||
const args = {};
|
||||
|
||||
for (let i = 2; i < process.argv.length; i += 2) {
|
||||
const key = process.argv[i].replace(/^--/, '');
|
||||
const value = process.argv[i + 1];
|
||||
args[key] = value;
|
||||
}
|
||||
|
||||
if (!args.topic && !args.audience && !args.duration) {
|
||||
console.error('Usage: bun analyze-context.js --topic "Topic" --audience "Audience" --duration "15min" [--purpose "Purpose"]');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const analysis = generateAnalysis(args);
|
||||
console.log(JSON.stringify(analysis, null, 2));
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
main();
|
||||
}
|
||||
|
||||
export { generateAnalysis, detectPresentationType, recommendFrameworks, estimateSlideCount, analyzeAudience };
|
||||
342
skills/presentation-master/scripts/suggest-images.js
Normal file
342
skills/presentation-master/scripts/suggest-images.js
Normal file
@@ -0,0 +1,342 @@
|
||||
#!/usr/bin/env bun
|
||||
|
||||
/**
|
||||
* Visual Recommendation Engine
|
||||
*
|
||||
* Analyzes slide content and recommends visual types and generation prompts
|
||||
* for the image-gen skill.
|
||||
*
|
||||
* Usage:
|
||||
* bun suggest-images.js --slides slides.json --presentation-id "cyber-2025"
|
||||
*
|
||||
* Output: JSON with image recommendations, prompts, cost estimates
|
||||
*/
|
||||
|
||||
const IMAGE_COSTS = {
|
||||
'1K': 0.065, // 1024x1024
|
||||
'2K': 0.13, // 2048x2048
|
||||
'4K': 0.24 // 4096x4096
|
||||
};
|
||||
|
||||
const VISUAL_TYPES = {
|
||||
INFOGRAPHIC: {
|
||||
name: 'infographic',
|
||||
best_for: ['statistics', 'comparisons', 'processes', 'timelines'],
|
||||
style_keywords: ['clean', 'modern', 'professional', 'data-driven', 'minimalist'],
|
||||
default_resolution: '2K',
|
||||
prompt_template: 'Clean, modern infographic showing {concept}. Minimalist design, professional color palette, clear visual hierarchy. {specifics}. High contrast, data-focused, no text.'
|
||||
},
|
||||
|
||||
CONCEPTUAL: {
|
||||
name: 'conceptual',
|
||||
best_for: ['abstract ideas', 'metaphors', 'themes', 'emotions'],
|
||||
style_keywords: ['metaphorical', 'symbolic', 'artistic', 'thought-provoking'],
|
||||
default_resolution: '2K',
|
||||
prompt_template: 'Conceptual image representing {concept}. Symbolic, thought-provoking visual metaphor. {specifics}. Artistic but professional, high quality, suitable for business presentation.'
|
||||
},
|
||||
|
||||
REALISTIC: {
|
||||
name: 'realistic',
|
||||
best_for: ['examples', 'scenarios', 'people', 'places', 'objects'],
|
||||
style_keywords: ['photographic', 'realistic', 'professional', 'high-quality'],
|
||||
default_resolution: '2K',
|
||||
prompt_template: 'Professional photograph of {concept}. Realistic, high-quality, well-lit. {specifics}. Commercial photography style, suitable for corporate presentation.'
|
||||
},
|
||||
|
||||
DIAGRAM: {
|
||||
name: 'diagram',
|
||||
best_for: ['technical concepts', 'architectures', 'flows', 'relationships'],
|
||||
style_keywords: ['technical', 'schematic', 'architectural', 'structured'],
|
||||
default_resolution: '2K',
|
||||
prompt_template: 'Clean technical diagram illustrating {concept}. {specifics}. Professional, minimal color, clear connections, no labels or text.'
|
||||
},
|
||||
|
||||
DATA_VIZ: {
|
||||
name: 'data-visualization',
|
||||
best_for: ['trends', 'growth', 'decline', 'distributions', 'correlations'],
|
||||
style_keywords: ['chart', 'graph', 'visualization', 'quantitative'],
|
||||
default_resolution: '2K',
|
||||
prompt_template: 'Modern data visualization showing {concept}. {specifics}. Clean design, professional color scheme, Tufte-style minimalism, no grid lines or labels.'
|
||||
},
|
||||
|
||||
ABSTRACT: {
|
||||
name: 'abstract',
|
||||
best_for: ['innovation', 'transformation', 'future', 'technology'],
|
||||
style_keywords: ['abstract', 'modern', 'technological', 'futuristic'],
|
||||
default_resolution: '2K',
|
||||
prompt_template: 'Abstract visual representing {concept}. Modern, technological feel. {specifics}. Clean, professional, suitable for corporate presentation.'
|
||||
}
|
||||
};
|
||||
|
||||
const CONTENT_PATTERNS = {
|
||||
// Numeric indicators
|
||||
numeric: {
|
||||
patterns: [/\d+%/, /\$\d+/, /\d+[KMB]/, /\d+ (percent|million|billion|thousand)/i],
|
||||
recommended_types: ['infographic', 'data-visualization']
|
||||
},
|
||||
|
||||
// Comparison indicators
|
||||
comparison: {
|
||||
patterns: [/vs\.?/i, /versus/i, /compared to/i, /before.*after/i, /old.*new/i],
|
||||
recommended_types: ['infographic', 'data-visualization']
|
||||
},
|
||||
|
||||
// Process indicators
|
||||
process: {
|
||||
patterns: [/step/i, /phase/i, /stage/i, /process/i, /workflow/i, /pipeline/i],
|
||||
recommended_types: ['diagram', 'infographic']
|
||||
},
|
||||
|
||||
// Time indicators
|
||||
timeline: {
|
||||
patterns: [/timeline/i, /history/i, /evolution/i, /\d{4}/, /past.*future/i],
|
||||
recommended_types: ['infographic', 'diagram']
|
||||
},
|
||||
|
||||
// Abstract concepts
|
||||
abstract: {
|
||||
patterns: [/future/i, /innovation/i, /transform/i, /vision/i, /imagine/i, /potential/i],
|
||||
recommended_types: ['conceptual', 'abstract']
|
||||
},
|
||||
|
||||
// People/scenarios
|
||||
human: {
|
||||
patterns: [/people/i, /user/i, /student/i, /teacher/i, /team/i, /customer/i],
|
||||
recommended_types: ['realistic', 'conceptual']
|
||||
},
|
||||
|
||||
// Technical
|
||||
technical: {
|
||||
patterns: [/architecture/i, /system/i, /infrastructure/i, /network/i, /api/i],
|
||||
recommended_types: ['diagram', 'abstract']
|
||||
}
|
||||
};
|
||||
|
||||
function analyzeSlideContent(slide) {
|
||||
const content = `${slide.title || ''} ${slide.text || ''} ${slide.notes || ''}`.toLowerCase();
|
||||
|
||||
// Detect patterns
|
||||
const detectedPatterns = [];
|
||||
for (const [patternName, pattern] of Object.entries(CONTENT_PATTERNS)) {
|
||||
for (const regex of pattern.patterns) {
|
||||
if (regex.test(content)) {
|
||||
detectedPatterns.push({
|
||||
pattern: patternName,
|
||||
recommended_types: pattern.recommended_types
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return detectedPatterns;
|
||||
}
|
||||
|
||||
function selectVisualType(patterns, slidePattern) {
|
||||
// If no patterns detected, use slide pattern to guide
|
||||
if (patterns.length === 0) {
|
||||
switch (slidePattern) {
|
||||
case 'data-viz':
|
||||
return VISUAL_TYPES.DATA_VIZ;
|
||||
case 'process':
|
||||
case 'timeline':
|
||||
return VISUAL_TYPES.DIAGRAM;
|
||||
case 'big-idea':
|
||||
return VISUAL_TYPES.CONCEPTUAL;
|
||||
default:
|
||||
return VISUAL_TYPES.REALISTIC;
|
||||
}
|
||||
}
|
||||
|
||||
// Count type recommendations
|
||||
const typeCounts = {};
|
||||
for (const p of patterns) {
|
||||
for (const type of p.recommended_types) {
|
||||
typeCounts[type] = (typeCounts[type] || 0) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Get highest scoring type
|
||||
const sorted = Object.entries(typeCounts).sort((a, b) => b[1] - a[1]);
|
||||
const typeName = sorted[0][0];
|
||||
|
||||
// Find matching visual type
|
||||
for (const visualType of Object.values(VISUAL_TYPES)) {
|
||||
if (visualType.name === typeName) {
|
||||
return visualType;
|
||||
}
|
||||
}
|
||||
|
||||
return VISUAL_TYPES.CONCEPTUAL; // fallback
|
||||
}
|
||||
|
||||
function extractConcepts(slide) {
|
||||
// Extract key concepts from slide content
|
||||
const title = slide.title || '';
|
||||
const text = slide.text || '';
|
||||
|
||||
// Primary concept is the title (simplified)
|
||||
const concept = title.replace(/[?!.]/g, '').trim();
|
||||
|
||||
// Secondary details from text
|
||||
const specifics = text
|
||||
? text.split(/[.!?]/).slice(0, 2).join('. ').trim()
|
||||
: '';
|
||||
|
||||
return { concept, specifics };
|
||||
}
|
||||
|
||||
function generatePrompt(visualType, slide) {
|
||||
const { concept, specifics } = extractConcepts(slide);
|
||||
|
||||
// Use template
|
||||
let prompt = visualType.prompt_template
|
||||
.replace('{concept}', concept)
|
||||
.replace('{specifics}', specifics);
|
||||
|
||||
// Add brand context if available
|
||||
if (slide.brand) {
|
||||
if (slide.brand === 'psd') {
|
||||
prompt += ' Peninsula School District brand: teal/green color palette (#6CA18A), professional education context.';
|
||||
} else if (slide.brand === 'personal') {
|
||||
prompt += ' Modern, clean aesthetic.';
|
||||
}
|
||||
}
|
||||
|
||||
return prompt;
|
||||
}
|
||||
|
||||
function estimateCost(imageCount, resolution = '2K') {
|
||||
const perImage = IMAGE_COSTS[resolution];
|
||||
return {
|
||||
per_image: perImage,
|
||||
total: perImage * imageCount,
|
||||
resolution,
|
||||
currency: 'USD'
|
||||
};
|
||||
}
|
||||
|
||||
function shouldGenerateImage(slide) {
|
||||
// Skip image generation for certain patterns
|
||||
if (slide.pattern === 'title' && slide.index === 0) {
|
||||
return false; // Title slide often doesn't need generated image
|
||||
}
|
||||
|
||||
if (slide.pattern === 'transition') {
|
||||
return false; // Transitions are usually text-only
|
||||
}
|
||||
|
||||
if (slide.pattern === 'big-idea' && !slide.needs_visual) {
|
||||
return false; // Some big ideas are typography-only
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function generateRecommendations(slides, presentationId, options = {}) {
|
||||
const brand = options.brand || null;
|
||||
const resolution = options.resolution || '2K';
|
||||
const autoInclude = options.auto_include !== false;
|
||||
|
||||
const recommendations = [];
|
||||
|
||||
for (let i = 0; i < slides.length; i++) {
|
||||
const slide = { ...slides[i], index: i, brand };
|
||||
|
||||
if (!shouldGenerateImage(slide)) {
|
||||
recommendations.push({
|
||||
slide_index: i,
|
||||
slide_title: slide.title,
|
||||
recommendation: 'no-image-needed',
|
||||
reason: `Pattern '${slide.pattern}' typically doesn't require generated image`
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
// Analyze content
|
||||
const patterns = analyzeSlideContent(slide);
|
||||
const visualType = selectVisualType(patterns, slide.pattern);
|
||||
|
||||
// Generate prompt
|
||||
const prompt = generatePrompt(visualType, slide);
|
||||
|
||||
// Generate filename
|
||||
const slideNum = String(i + 1).padStart(2, '0');
|
||||
const slugTitle = slide.title
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/^-+|-+$/g, '')
|
||||
.substring(0, 40);
|
||||
const filename = `${presentationId}-slide-${slideNum}-${slugTitle}.png`;
|
||||
|
||||
recommendations.push({
|
||||
slide_index: i,
|
||||
slide_title: slide.title,
|
||||
slide_pattern: slide.pattern,
|
||||
visual_type: visualType.name,
|
||||
prompt,
|
||||
filename,
|
||||
resolution,
|
||||
auto_include: autoInclude,
|
||||
confidence: patterns.length > 0 ? 'high' : 'medium'
|
||||
});
|
||||
}
|
||||
|
||||
// Calculate costs
|
||||
const imagesToGenerate = recommendations.filter(r => r.recommendation !== 'no-image-needed');
|
||||
const costEstimate = estimateCost(imagesToGenerate.length, resolution);
|
||||
|
||||
return {
|
||||
presentation_id: presentationId,
|
||||
total_slides: slides.length,
|
||||
images_recommended: imagesToGenerate.length,
|
||||
cost_estimate: costEstimate,
|
||||
recommendations,
|
||||
summary: {
|
||||
by_type: imagesToGenerate.reduce((acc, r) => {
|
||||
acc[r.visual_type] = (acc[r.visual_type] || 0) + 1;
|
||||
return acc;
|
||||
}, {}),
|
||||
high_confidence: imagesToGenerate.filter(r => r.confidence === 'high').length,
|
||||
medium_confidence: imagesToGenerate.filter(r => r.confidence === 'medium').length
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// CLI Interface
|
||||
function main() {
|
||||
const args = {};
|
||||
|
||||
for (let i = 2; i < process.argv.length; i++) {
|
||||
if (process.argv[i].startsWith('--')) {
|
||||
const key = process.argv[i].replace(/^--/, '');
|
||||
const value = process.argv[i + 1];
|
||||
args[key] = value;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!args.slides || !args['presentation-id']) {
|
||||
console.error('Usage: bun suggest-images.js --slides slides.json --presentation-id "cyber-2025" [--brand psd] [--resolution 2K]');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Read slides from file
|
||||
const fs = require('fs');
|
||||
const slidesData = JSON.parse(fs.readFileSync(args.slides, 'utf-8'));
|
||||
const slides = Array.isArray(slidesData) ? slidesData : slidesData.slides;
|
||||
|
||||
const options = {
|
||||
brand: args.brand || null,
|
||||
resolution: args.resolution || '2K'
|
||||
};
|
||||
|
||||
const recommendations = generateRecommendations(slides, args['presentation-id'], options);
|
||||
console.log(JSON.stringify(recommendations, null, 2));
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
main();
|
||||
}
|
||||
|
||||
export { generateRecommendations, analyzeSlideContent, selectVisualType, generatePrompt, estimateCost };
|
||||
549
skills/presentation-master/scripts/validate-presentation.js
Normal file
549
skills/presentation-master/scripts/validate-presentation.js
Normal file
@@ -0,0 +1,549 @@
|
||||
#!/usr/bin/env bun
|
||||
|
||||
/**
|
||||
* Presentation Quality Validator
|
||||
*
|
||||
* Scores presentations 0-100 against best practices from presentation masters.
|
||||
* Implements validation rules from principles/validation-rules.md
|
||||
*
|
||||
* Usage:
|
||||
* bun validate-presentation.js --presentation presentation.json
|
||||
*
|
||||
* Output: JSON with score, breakdown, critical issues, warnings, recommendations
|
||||
*/
|
||||
|
||||
const SCORING_WEIGHTS = {
|
||||
simplicity: 10,
|
||||
visual_dominance: 10,
|
||||
story_structure: 10,
|
||||
one_idea_per_slide: 10,
|
||||
typography: 8,
|
||||
layout: 7,
|
||||
color_contrast: 7,
|
||||
media_quality: 8,
|
||||
cognitive_load: 20,
|
||||
data_integrity: 10
|
||||
};
|
||||
|
||||
const CRITICAL_VIOLATIONS = {
|
||||
font_too_small: { penalty: -20, threshold: 30 },
|
||||
too_many_concepts: { penalty: -15, threshold: 10 },
|
||||
bullet_points: { penalty: -10 },
|
||||
paragraphs: { penalty: -10 },
|
||||
poor_contrast: { penalty: -15, threshold: 4.5 },
|
||||
default_template: { penalty: -20 }
|
||||
};
|
||||
|
||||
const WARNING_FLAGS = {
|
||||
too_many_words: { penalty: -2, threshold: 6 },
|
||||
too_many_slides: { penalty: -5, ratio: 0.75 },
|
||||
no_images: { penalty: -10 },
|
||||
text_heavy: { penalty: -3, threshold: 3 },
|
||||
inconsistent_fonts: { penalty: -5, threshold: 2 },
|
||||
low_res_images: { penalty: -3 }
|
||||
};
|
||||
|
||||
function countWords(text) {
|
||||
if (!text) return 0;
|
||||
return text.trim().split(/\s+/).filter(w => w.length > 0).length;
|
||||
}
|
||||
|
||||
function detectBulletPoints(text) {
|
||||
if (!text) return false;
|
||||
return /[•\-*]\s/.test(text) || /^\s*[\d]+\.\s/m.test(text);
|
||||
}
|
||||
|
||||
function detectParagraphs(text) {
|
||||
if (!text) return false;
|
||||
const sentences = text.split(/[.!?]/).filter(s => s.trim().length > 0);
|
||||
return sentences.length > 2;
|
||||
}
|
||||
|
||||
function estimateContrastRatio(slide) {
|
||||
// Simplified contrast estimation
|
||||
// In real implementation, would analyze actual colors
|
||||
if (slide.contrast_ratio) return slide.contrast_ratio;
|
||||
|
||||
// Conservative default
|
||||
return 7.0;
|
||||
}
|
||||
|
||||
function countElements(slide) {
|
||||
let elements = 0;
|
||||
if (slide.title) elements++;
|
||||
if (slide.text) elements++;
|
||||
if (slide.image) elements++;
|
||||
if (slide.chart) elements++;
|
||||
return elements;
|
||||
}
|
||||
|
||||
function scoreSimplicity(slides) {
|
||||
let score = 0;
|
||||
const maxScore = SCORING_WEIGHTS.simplicity;
|
||||
|
||||
for (const slide of slides) {
|
||||
const wordCount = countWords(slide.text);
|
||||
const elements = countElements(slide);
|
||||
|
||||
// Word count scoring
|
||||
let wordScore = 0;
|
||||
if (wordCount <= 3) wordScore = 10;
|
||||
else if (wordCount <= 6) wordScore = 8;
|
||||
else if (wordCount <= 10) wordScore = 5;
|
||||
else wordScore = 0;
|
||||
|
||||
// Visual clutter scoring
|
||||
let elementScore = 0;
|
||||
if (elements === 1) elementScore = 10;
|
||||
else if (elements <= 3) elementScore = 8;
|
||||
else if (elements <= 5) elementScore = 5;
|
||||
else elementScore = 0;
|
||||
|
||||
score += (wordScore + elementScore) / 2;
|
||||
}
|
||||
|
||||
return Math.min(maxScore, score / slides.length);
|
||||
}
|
||||
|
||||
function scoreVisualDominance(slides) {
|
||||
let score = 0;
|
||||
const maxScore = SCORING_WEIGHTS.visual_dominance;
|
||||
|
||||
const slidesWithImages = slides.filter(s => s.image || s.chart).length;
|
||||
const imageRatio = slidesWithImages / slides.length;
|
||||
|
||||
// Image quality check
|
||||
const highResImages = slides.filter(s => {
|
||||
if (!s.image) return false;
|
||||
return s.image.resolution >= 2000;
|
||||
}).length;
|
||||
|
||||
const imageQualityScore = slidesWithImages > 0
|
||||
? (highResImages / slidesWithImages) * 10
|
||||
: 0;
|
||||
|
||||
// Text-to-visual ratio
|
||||
const textVsVisualScore = imageRatio >= 0.8 ? 10 :
|
||||
imageRatio >= 0.5 ? 5 : 0;
|
||||
|
||||
score = (imageQualityScore + textVsVisualScore) / 2;
|
||||
|
||||
return Math.min(maxScore, score);
|
||||
}
|
||||
|
||||
function scoreStoryStructure(presentation) {
|
||||
const maxScore = SCORING_WEIGHTS.story_structure;
|
||||
|
||||
// Check if presentation has defined structure
|
||||
if (!presentation.framework) return maxScore * 0.3; // partial credit
|
||||
|
||||
const framework = presentation.framework.toLowerCase();
|
||||
|
||||
// Narrative arc check
|
||||
let narrativeScore = 0;
|
||||
if (presentation.slides.length >= 3) {
|
||||
const hasOpening = presentation.slides[0].pattern === 'title';
|
||||
const hasClosing = presentation.slides[presentation.slides.length - 1].pattern === 'transition' ||
|
||||
presentation.slides[presentation.slides.length - 1].pattern === 'big-idea';
|
||||
|
||||
if (hasOpening && hasClosing) narrativeScore = 10;
|
||||
else if (hasOpening || hasClosing) narrativeScore = 5;
|
||||
}
|
||||
|
||||
// Emotional beats check
|
||||
const bigIdeaSlides = presentation.slides.filter(s => s.pattern === 'big-idea').length;
|
||||
const emotionalScore = bigIdeaSlides >= 3 ? 10 :
|
||||
bigIdeaSlides >= 1 ? 5 : 0;
|
||||
|
||||
return Math.min(maxScore, (narrativeScore + emotionalScore) / 2);
|
||||
}
|
||||
|
||||
function scoreOneIdeaPerSlide(slides) {
|
||||
const maxScore = SCORING_WEIGHTS.one_idea_per_slide;
|
||||
|
||||
let clearSlides = 0;
|
||||
for (const slide of slides) {
|
||||
const wordCount = countWords(slide.text);
|
||||
const hasBullets = detectBulletPoints(slide.text);
|
||||
const elements = countElements(slide);
|
||||
|
||||
// Single concept if: few words, no bullets, few elements
|
||||
if (wordCount <= 10 && !hasBullets && elements <= 3) {
|
||||
clearSlides++;
|
||||
}
|
||||
}
|
||||
|
||||
const ratio = clearSlides / slides.length;
|
||||
|
||||
if (ratio === 1.0) return maxScore;
|
||||
if (ratio >= 0.7) return maxScore * 0.7;
|
||||
if (ratio >= 0.5) return maxScore * 0.3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
function scoreTypography(slides) {
|
||||
const maxScore = SCORING_WEIGHTS.typography;
|
||||
|
||||
// Font size check
|
||||
const minFontSize = Math.min(...slides.map(s => s.min_font_size || 36));
|
||||
|
||||
let fontSizeScore = 0;
|
||||
if (minFontSize >= 36) fontSizeScore = 8;
|
||||
else if (minFontSize >= 30) fontSizeScore = 6;
|
||||
else if (minFontSize >= 24) fontSizeScore = 2;
|
||||
else fontSizeScore = 0;
|
||||
|
||||
// Font consistency
|
||||
const fontFamilies = new Set(slides.map(s => s.font_family || 'default'));
|
||||
let consistencyScore = 0;
|
||||
if (fontFamilies.size === 1) consistencyScore = 8;
|
||||
else if (fontFamilies.size === 2) consistencyScore = 6;
|
||||
else consistencyScore = 0;
|
||||
|
||||
return Math.min(maxScore, (fontSizeScore + consistencyScore) / 2);
|
||||
}
|
||||
|
||||
function scoreLayout(slides) {
|
||||
const maxScore = SCORING_WEIGHTS.layout;
|
||||
|
||||
// Simplified layout scoring
|
||||
// In real implementation, would analyze actual layouts
|
||||
let hierarchyScore = 7; // assume good by default
|
||||
let whitespaceScore = 7; // assume good by default
|
||||
let alignmentScore = 7; // assume good by default
|
||||
|
||||
return Math.min(maxScore, (hierarchyScore + whitespaceScore + alignmentScore) / 3);
|
||||
}
|
||||
|
||||
function scoreColorContrast(slides) {
|
||||
const maxScore = SCORING_WEIGHTS.color_contrast;
|
||||
|
||||
const avgContrast = slides.reduce((sum, s) => sum + estimateContrastRatio(s), 0) / slides.length;
|
||||
|
||||
let contrastScore = 0;
|
||||
if (avgContrast >= 7.0) contrastScore = 7;
|
||||
else if (avgContrast >= 4.5) contrastScore = 5;
|
||||
else contrastScore = 0;
|
||||
|
||||
return Math.min(maxScore, contrastScore);
|
||||
}
|
||||
|
||||
function scoreMediaQuality(slides) {
|
||||
const maxScore = SCORING_WEIGHTS.media_quality;
|
||||
|
||||
const slidesWithMedia = slides.filter(s => s.image || s.chart);
|
||||
if (slidesWithMedia.length === 0) return 0;
|
||||
|
||||
// Resolution check
|
||||
const highRes = slidesWithMedia.filter(s => {
|
||||
if (s.image) return s.image.resolution >= 2000;
|
||||
return true; // charts assumed high quality
|
||||
}).length;
|
||||
|
||||
const resolutionScore = (highRes / slidesWithMedia.length) * 8;
|
||||
|
||||
// Relevance is assumed (would need manual review)
|
||||
const relevanceScore = 8;
|
||||
|
||||
return Math.min(maxScore, (resolutionScore + relevanceScore) / 2);
|
||||
}
|
||||
|
||||
function scoreCognitiveLoad(slides, presentation) {
|
||||
const maxScore = SCORING_WEIGHTS.cognitive_load;
|
||||
|
||||
// Mayer's 12 principles adherence (simplified)
|
||||
let principlesFollowed = 0;
|
||||
|
||||
// 1. Coherence (extraneous material excluded)
|
||||
const avgWordCount = slides.reduce((sum, s) => sum + countWords(s.text), 0) / slides.length;
|
||||
if (avgWordCount <= 10) principlesFollowed++;
|
||||
|
||||
// 2. Signaling (essential material highlighted)
|
||||
const hasTransitions = slides.some(s => s.pattern === 'transition');
|
||||
if (hasTransitions) principlesFollowed++;
|
||||
|
||||
// 3. Redundancy (graphics + narration, not graphics + text + narration)
|
||||
const textHeavySlides = slides.filter(s => countWords(s.text) > 15).length;
|
||||
if (textHeavySlides / slides.length < 0.2) principlesFollowed++;
|
||||
|
||||
// 4. Spatial contiguity (related words/pictures near each other)
|
||||
principlesFollowed++; // assume good
|
||||
|
||||
// 5. Temporal contiguity (corresponding narration/animation together)
|
||||
principlesFollowed++; // assume good
|
||||
|
||||
// 6. Segmenting (user-paced)
|
||||
principlesFollowed++; // presentations are inherently segmented
|
||||
|
||||
// 7. Pre-training (key concepts introduced early)
|
||||
const hasOpening = slides[0]?.pattern === 'title';
|
||||
if (hasOpening) principlesFollowed++;
|
||||
|
||||
// 8. Modality (graphics + narration better than graphics + text)
|
||||
const avgTextPerSlide = slides.reduce((sum, s) => sum + (s.text || '').length, 0) / slides.length;
|
||||
if (avgTextPerSlide < 100) principlesFollowed++;
|
||||
|
||||
// 9-12: Multimedia, personalization, voice, image principles
|
||||
principlesFollowed += 4; // assume followed
|
||||
|
||||
// Score based on principles followed
|
||||
if (principlesFollowed >= 10) return maxScore;
|
||||
if (principlesFollowed >= 7) return maxScore * 0.75;
|
||||
if (principlesFollowed >= 4) return maxScore * 0.5;
|
||||
return maxScore * 0.25;
|
||||
}
|
||||
|
||||
function scoreDataIntegrity(slides) {
|
||||
const maxScore = SCORING_WEIGHTS.data_integrity;
|
||||
|
||||
const dataSlides = slides.filter(s => s.chart || s.pattern === 'data-viz');
|
||||
if (dataSlides.length === 0) return maxScore; // not applicable, full credit
|
||||
|
||||
// Lie factor check (if provided)
|
||||
let lieFactor = 1.0; // assume honest by default
|
||||
if (dataSlides[0].lie_factor) {
|
||||
lieFactor = dataSlides[0].lie_factor;
|
||||
}
|
||||
|
||||
let lieFactorScore = 0;
|
||||
if (lieFactor >= 0.95 && lieFactor <= 1.05) lieFactorScore = 10;
|
||||
else if (lieFactor >= 0.90 && lieFactor <= 1.10) lieFactorScore = 7;
|
||||
else if (lieFactor >= 0.80 && lieFactor <= 1.20) lieFactorScore = 3;
|
||||
else lieFactorScore = 0;
|
||||
|
||||
// Data-ink ratio (assume maximized by default)
|
||||
const dataInkScore = 10;
|
||||
|
||||
return Math.min(maxScore, (lieFactorScore + dataInkScore) / 2);
|
||||
}
|
||||
|
||||
function checkCriticalViolations(slides, presentation) {
|
||||
const violations = [];
|
||||
|
||||
// Font size check
|
||||
const minFont = Math.min(...slides.map(s => s.min_font_size || 36));
|
||||
if (minFont < CRITICAL_VIOLATIONS.font_too_small.threshold) {
|
||||
violations.push({
|
||||
type: 'font_too_small',
|
||||
penalty: CRITICAL_VIOLATIONS.font_too_small.penalty,
|
||||
message: `CRITICAL: Minimum font size is ${minFont}pt (required: 30pt+)`,
|
||||
slides_affected: slides.filter(s => (s.min_font_size || 36) < 30).map(s => s.index)
|
||||
});
|
||||
}
|
||||
|
||||
// Concept count check
|
||||
if (slides.length > CRITICAL_VIOLATIONS.too_many_concepts.threshold) {
|
||||
violations.push({
|
||||
type: 'too_many_concepts',
|
||||
penalty: CRITICAL_VIOLATIONS.too_many_concepts.penalty,
|
||||
message: `CRITICAL: ${slides.length} slides exceeds Kawasaki's 10 core concepts limit`
|
||||
});
|
||||
}
|
||||
|
||||
// Bullet points check
|
||||
const bulletSlides = slides.filter(s => detectBulletPoints(s.text));
|
||||
if (bulletSlides.length > 0) {
|
||||
violations.push({
|
||||
type: 'bullet_points',
|
||||
penalty: CRITICAL_VIOLATIONS.bullet_points.penalty * bulletSlides.length,
|
||||
message: `CRITICAL: ${bulletSlides.length} slides have bullet points`,
|
||||
slides_affected: bulletSlides.map(s => s.index)
|
||||
});
|
||||
}
|
||||
|
||||
// Paragraphs check
|
||||
const paragraphSlides = slides.filter(s => detectParagraphs(s.text));
|
||||
if (paragraphSlides.length > 0) {
|
||||
violations.push({
|
||||
type: 'paragraphs',
|
||||
penalty: CRITICAL_VIOLATIONS.paragraphs.penalty * paragraphSlides.length,
|
||||
message: `CRITICAL: ${paragraphSlides.length} slides have paragraphs (>2 sentences)`,
|
||||
slides_affected: paragraphSlides.map(s => s.index)
|
||||
});
|
||||
}
|
||||
|
||||
// Contrast check
|
||||
const avgContrast = slides.reduce((sum, s) => sum + estimateContrastRatio(s), 0) / slides.length;
|
||||
if (avgContrast < CRITICAL_VIOLATIONS.poor_contrast.threshold) {
|
||||
violations.push({
|
||||
type: 'poor_contrast',
|
||||
penalty: CRITICAL_VIOLATIONS.poor_contrast.penalty,
|
||||
message: `CRITICAL: Average contrast ratio ${avgContrast.toFixed(1)}:1 (required: 4.5:1+)`
|
||||
});
|
||||
}
|
||||
|
||||
return violations;
|
||||
}
|
||||
|
||||
function checkWarnings(slides, presentation) {
|
||||
const warnings = [];
|
||||
|
||||
// Word count warnings
|
||||
const wordySlides = slides.filter(s => countWords(s.text) > WARNING_FLAGS.too_many_words.threshold);
|
||||
if (wordySlides.length > 0) {
|
||||
warnings.push({
|
||||
type: 'too_many_words',
|
||||
penalty: WARNING_FLAGS.too_many_words.penalty * wordySlides.length,
|
||||
message: `${wordySlides.length} slides exceed 6-word limit (Seth Godin standard)`,
|
||||
slides_affected: wordySlides.map(s => ({
|
||||
index: s.index,
|
||||
words: countWords(s.text)
|
||||
}))
|
||||
});
|
||||
}
|
||||
|
||||
// Slide count for duration
|
||||
if (presentation.duration_minutes) {
|
||||
const recommendedSlides = presentation.duration_minutes * WARNING_FLAGS.too_many_slides.ratio;
|
||||
if (slides.length > recommendedSlides) {
|
||||
warnings.push({
|
||||
type: 'too_many_slides',
|
||||
penalty: WARNING_FLAGS.too_many_slides.penalty,
|
||||
message: `${slides.length} slides for ${presentation.duration_minutes}min (recommended: ≤${Math.round(recommendedSlides)})`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Images check
|
||||
const slidesWithImages = slides.filter(s => s.image || s.chart).length;
|
||||
if (slidesWithImages === 0) {
|
||||
warnings.push({
|
||||
type: 'no_images',
|
||||
penalty: WARNING_FLAGS.no_images.penalty,
|
||||
message: 'No images detected - presentations should be visual-dominant'
|
||||
});
|
||||
}
|
||||
|
||||
return warnings;
|
||||
}
|
||||
|
||||
function generateRecommendations(violations, warnings, scores) {
|
||||
const recommendations = [];
|
||||
|
||||
// Address critical violations first
|
||||
if (violations.length > 0) {
|
||||
recommendations.push({
|
||||
priority: 'CRITICAL',
|
||||
action: 'Fix all critical violations before presenting',
|
||||
details: violations.map(v => v.message)
|
||||
});
|
||||
}
|
||||
|
||||
// Typography recommendations
|
||||
if (scores.typography < 6) {
|
||||
recommendations.push({
|
||||
priority: 'high',
|
||||
action: 'Increase font sizes to 36pt minimum',
|
||||
details: ['Guy Kawasaki: 30pt absolute minimum', 'TED: 42pt recommended']
|
||||
});
|
||||
}
|
||||
|
||||
// Simplicity recommendations
|
||||
if (scores.simplicity < 7) {
|
||||
recommendations.push({
|
||||
priority: 'high',
|
||||
action: 'Simplify slides - reduce word count and elements',
|
||||
details: ['Seth Godin: 6 words maximum per slide', 'One idea per slide']
|
||||
});
|
||||
}
|
||||
|
||||
// Visual recommendations
|
||||
if (scores.visual_dominance < 7) {
|
||||
recommendations.push({
|
||||
priority: 'medium',
|
||||
action: 'Add more high-quality images',
|
||||
details: ['Garr Reynolds: Pictures > text', '80% of slides should have visuals']
|
||||
});
|
||||
}
|
||||
|
||||
return recommendations;
|
||||
}
|
||||
|
||||
function validatePresentation(presentation) {
|
||||
const slides = presentation.slides || [];
|
||||
|
||||
// Calculate scores
|
||||
const scores = {
|
||||
simplicity: scoreSimplicity(slides),
|
||||
visual_dominance: scoreVisualDominance(slides),
|
||||
story_structure: scoreStoryStructure(presentation),
|
||||
one_idea_per_slide: scoreOneIdeaPerSlide(slides),
|
||||
typography: scoreTypography(slides),
|
||||
layout: scoreLayout(slides),
|
||||
color_contrast: scoreColorContrast(slides),
|
||||
media_quality: scoreMediaQuality(slides),
|
||||
cognitive_load: scoreCognitiveLoad(slides, presentation),
|
||||
data_integrity: scoreDataIntegrity(slides)
|
||||
};
|
||||
|
||||
// Calculate total
|
||||
const baseScore = Object.values(scores).reduce((sum, score) => sum + score, 0);
|
||||
|
||||
// Check violations
|
||||
const violations = checkCriticalViolations(slides, presentation);
|
||||
const warnings = checkWarnings(slides, presentation);
|
||||
|
||||
// Apply penalties
|
||||
const violationPenalty = violations.reduce((sum, v) => sum + v.penalty, 0);
|
||||
const warningPenalty = warnings.reduce((sum, w) => sum + w.penalty, 0);
|
||||
|
||||
const finalScore = Math.max(0, Math.min(100, baseScore + violationPenalty + warningPenalty));
|
||||
|
||||
// Generate report
|
||||
const status = finalScore >= 90 ? 'Exceptional' :
|
||||
finalScore >= 80 ? 'Excellent' :
|
||||
finalScore >= 70 ? 'Good' :
|
||||
finalScore >= 60 ? 'Acceptable' : 'Poor';
|
||||
|
||||
const recommendations = generateRecommendations(violations, warnings, scores);
|
||||
|
||||
return {
|
||||
overall_score: Math.round(finalScore),
|
||||
status,
|
||||
score_breakdown: Object.entries(scores).map(([category, score]) => ({
|
||||
category,
|
||||
score: Math.round(score * 10) / 10,
|
||||
max: SCORING_WEIGHTS[category]
|
||||
})),
|
||||
critical_violations: violations,
|
||||
warnings,
|
||||
recommendations,
|
||||
summary: {
|
||||
total_slides: slides.length,
|
||||
avg_words_per_slide: Math.round(slides.reduce((sum, s) => sum + countWords(s.text), 0) / slides.length),
|
||||
slides_with_images: slides.filter(s => s.image || s.chart).length,
|
||||
min_font_size: Math.min(...slides.map(s => s.min_font_size || 36))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// CLI Interface
|
||||
function main() {
|
||||
const args = {};
|
||||
|
||||
for (let i = 2; i < process.argv.length; i++) {
|
||||
if (process.argv[i].startsWith('--')) {
|
||||
const key = process.argv[i].replace(/^--/, '');
|
||||
const value = process.argv[i + 1];
|
||||
args[key] = value;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!args.presentation) {
|
||||
console.error('Usage: bun validate-presentation.js --presentation presentation.json');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const fs = require('fs');
|
||||
const presentation = JSON.parse(fs.readFileSync(args.presentation, 'utf-8'));
|
||||
|
||||
const report = validatePresentation(presentation);
|
||||
console.log(JSON.stringify(report, null, 2));
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
main();
|
||||
}
|
||||
|
||||
export { validatePresentation };
|
||||
Reference in New Issue
Block a user