#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Slide Generator - Generates HTML slides using design tokens ALL styles MUST use CSS variables from design-tokens.css NO hardcoded colors, fonts, or spacing allowed """ import argparse import json from pathlib import Path from datetime import datetime # Paths SCRIPT_DIR = Path(__file__).parent DATA_DIR = SCRIPT_DIR.parent / "data" TOKENS_CSS = Path(__file__).resolve().parents[4] / "assets" / "design-tokens.css" TOKENS_JSON = Path(__file__).resolve().parents[4] / "assets" / "design-tokens.json" OUTPUT_DIR = Path(__file__).resolve().parents[4] / "assets" / "designs" / "slides" # ============ BRAND-COMPLIANT SLIDE TEMPLATE ============ # ALL values reference CSS variables from design-tokens.css SLIDE_TEMPLATE = ''' {title}
{slides_content}
''' # ============ SLIDE GENERATORS ============ def generate_title_slide(data): """Title slide with gradient headline""" return f'''
{data.get('badge', 'Pitch Deck')}

{data.get('title', 'Your Title Here')}

{data.get('subtitle', 'Your compelling subtitle')}

{data.get('cta', 'Get Started')} {data.get('secondary_cta', 'Learn More')}
''' def generate_problem_slide(data): """Problem statement slide using PAS formula""" return f'''
The Problem

{data.get('headline', 'The problem your audience faces')}

01

{data.get('pain_1_title', 'Pain Point 1')}

{data.get('pain_1_desc', 'Description of the first pain point')}

02

{data.get('pain_2_title', 'Pain Point 2')}

{data.get('pain_2_desc', 'Description of the second pain point')}

03

{data.get('pain_3_title', 'Pain Point 3')}

{data.get('pain_3_desc', 'Description of the third pain point')}

''' def generate_solution_slide(data): """Solution slide with feature highlights""" return f'''
The Solution

{data.get('headline', 'How we solve this')}

{data.get('feature_1_title', 'Feature 1')}

{data.get('feature_1_desc', 'Description of feature 1')}

{data.get('feature_2_title', 'Feature 2')}

{data.get('feature_2_desc', 'Description of feature 2')}

{data.get('feature_3_title', 'Feature 3')}

{data.get('feature_3_desc', 'Description of feature 3')}

Product screenshot or demo

''' def generate_metrics_slide(data): """Traction/metrics slide with large numbers""" metrics = data.get('metrics', [ {'value': '10K+', 'label': 'Active Users'}, {'value': '95%', 'label': 'Retention Rate'}, {'value': '3x', 'label': 'Revenue Growth'}, {'value': '$2M', 'label': 'ARR'} ]) metrics_html = ''.join([f'''
{m['value']}
{m['label']}
''' for m in metrics[:4]]) return f'''
Traction

{data.get('headline', 'Our Growth')}

{metrics_html}
''' def generate_chart_slide(data): """Chart slide with CSS bar chart""" bars = data.get('bars', [ {'label': 'Q1', 'value': 40}, {'label': 'Q2', 'value': 60}, {'label': 'Q3', 'value': 80}, {'label': 'Q4', 'value': 100} ]) bars_html = ''.join([f'''
{b.get('display', str(b['value']) + '%')} {b['label']}
''' for b in bars]) return f'''
{data.get('badge', 'Growth')}

{data.get('headline', 'Revenue Growth')}

{data.get('chart_title', 'Quarterly Revenue')}
{bars_html}
''' def generate_testimonial_slide(data): """Social proof slide""" return f'''
What They Say

"{data.get('quote', 'This product changed how we work. Incredible results.')}"

{data.get('author', 'Jane Doe')}

{data.get('role', 'CEO, Example Company')}

''' def generate_cta_slide(data): """Closing CTA slide""" return f'''

{data.get('headline', 'Ready to get started?')}

{data.get('subheadline', 'Join thousands of teams already using our solution.')}

{data.get('cta', 'Start Free Trial')}
''' # Slide type mapping SLIDE_GENERATORS = { 'title': generate_title_slide, 'problem': generate_problem_slide, 'solution': generate_solution_slide, 'metrics': generate_metrics_slide, 'traction': generate_metrics_slide, 'chart': generate_chart_slide, 'testimonial': generate_testimonial_slide, 'cta': generate_cta_slide, 'closing': generate_cta_slide } def generate_deck(slides_data, title="Pitch Deck"): """Generate complete deck from slide data list""" slides_html = "" for slide in slides_data: slide_type = slide.get('type', 'title') generator = SLIDE_GENERATORS.get(slide_type) if generator: slides_html += generator(slide) else: print(f"Warning: Unknown slide type '{slide_type}'") # Calculate relative path to tokens CSS tokens_rel_path = "../../../assets/design-tokens.css" return SLIDE_TEMPLATE.format( title=title, tokens_css_path=tokens_rel_path, slides_content=slides_html ) def main(): parser = argparse.ArgumentParser(description="Generate brand-compliant slides") parser.add_argument("--json", "-j", help="JSON file with slide data") parser.add_argument("--output", "-o", help="Output HTML file path") parser.add_argument("--demo", action="store_true", help="Generate demo deck") args = parser.parse_args() if args.demo: # Demo deck showcasing all slide types demo_slides = [ { 'type': 'title', 'badge': 'Investor Deck 2024', 'title': 'ClaudeKit Marketing', 'subtitle': 'Your AI marketing team. Always on.', 'cta': 'Join Waitlist', 'secondary_cta': 'See Demo', 'company': 'ClaudeKit', 'date': 'December 2024' }, { 'type': 'problem', 'headline': 'Marketing teams are drowning', 'pain_1_title': 'Content Overload', 'pain_1_desc': 'Need to produce 10x content with same headcount', 'pain_2_title': 'Tool Fatigue', 'pain_2_desc': '15+ tools that don\'t talk to each other', 'pain_3_title': 'No Time to Think', 'pain_3_desc': 'Strategy suffers when execution consumes all hours', 'company': 'ClaudeKit', 'page': '2' }, { 'type': 'solution', 'headline': 'AI agents that actually get marketing', 'feature_1_title': 'Content Creation', 'feature_1_desc': 'Blog posts, social, email - all on brand, all on time', 'feature_2_title': 'Campaign Management', 'feature_2_desc': 'Multi-channel orchestration with one command', 'feature_3_title': 'Analytics & Insights', 'feature_3_desc': 'Real-time optimization without the spreadsheets', 'company': 'ClaudeKit', 'page': '3' }, { 'type': 'metrics', 'headline': 'Early traction speaks volumes', 'metrics': [ {'value': '500+', 'label': 'Beta Users'}, {'value': '85%', 'label': 'Weekly Active'}, {'value': '4.9', 'label': 'NPS Score'}, {'value': '50hrs', 'label': 'Saved/Week'} ], 'company': 'ClaudeKit', 'page': '4' }, { 'type': 'chart', 'badge': 'Revenue', 'headline': 'Growing month over month', 'chart_title': 'MRR Growth ($K)', 'bars': [ {'label': 'Sep', 'value': 20, 'display': '$5K'}, {'label': 'Oct', 'value': 40, 'display': '$12K'}, {'label': 'Nov', 'value': 70, 'display': '$28K'}, {'label': 'Dec', 'value': 100, 'display': '$45K'} ], 'company': 'ClaudeKit', 'page': '5' }, { 'type': 'testimonial', 'quote': 'ClaudeKit replaced 3 tools and 2 contractors. Our content output tripled while costs dropped 60%.', 'author': 'Sarah Chen', 'role': 'Head of Marketing, TechStartup', 'company': 'ClaudeKit', 'page': '6' }, { 'type': 'cta', 'headline': 'Ship campaigns while you sleep', 'subheadline': 'Early access available. Limited spots.', 'cta': 'Join the Waitlist', 'contact': 'hello@claudekit.ai', 'website': 'claudekit.ai' } ] html = generate_deck(demo_slides, "ClaudeKit Marketing - Pitch Deck") OUTPUT_DIR.mkdir(parents=True, exist_ok=True) output_path = OUTPUT_DIR / f"demo-pitch-{datetime.now().strftime('%y%m%d')}.html" output_path.write_text(html, encoding='utf-8') print(f"Demo deck generated: {output_path}") elif args.json: with open(args.json, 'r') as f: data = json.load(f) html = generate_deck(data.get('slides', []), data.get('title', 'Presentation')) output_path = Path(args.output) if args.output else OUTPUT_DIR / f"deck-{datetime.now().strftime('%y%m%d-%H%M')}.html" output_path.parent.mkdir(parents=True, exist_ok=True) output_path.write_text(html, encoding='utf-8') print(f"Deck generated: {output_path}") else: parser.print_help() if __name__ == "__main__": main()