From 3ffe8dd76bc90fdf5e20d42345b5220e6be00b04 Mon Sep 17 00:00:00 2001 From: daymade Date: Fri, 7 Aug 2026 14:02:56 +0800 Subject: [PATCH 1/2] =?UTF-8?q?deprecate(slides-creator):=20retire=20to=20?= =?UTF-8?q?stub=EF=BC=88=E6=96=B9=E6=B3=95=E8=AE=BA=E5=B7=B2=E5=B9=B6?= =?UTF-8?q?=E5=85=A5=20deck-creator=20Route=20A=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 与 ppt-creator 同一合并(2026-08-07 PPT 工具链四合一): First Law / ABCDEFG / baoyu 委托协议 / 四层目录治理已整体并入 deck-creator Route A · narrative。公共仓退役为 stub: SKILL.md 改退役通告,references/scripts 移除(git 历史保留; prompt-templates 4 件已先迁入 deck-creator route-a/)。 marketplace 2.0.0 + CHANGELOG。 Co-Authored-By: Claude --- slides-creator/.security-scan-passed | 4 - .../references/content-creation-first-law.md | 116 -------------- .../references/narrative-design-guide.md | 108 ------------- .../prompt-templates/quote-focus.md | 53 ------- .../prompt-templates/split-comparison.md | 53 ------- .../prompt-templates/three-column.md | 54 ------- .../references/prompt-templates/title-hero.md | 52 ------- slides-creator/references/style-gallery.md | 65 -------- slides-creator/scripts/archive_version.py | 65 -------- slides-creator/scripts/extract_notes.py | 120 -------------- slides-creator/scripts/main.ts | 96 ------------ slides-creator/scripts/merge_to_pdf.py | 64 -------- slides-creator/scripts/merge_to_pptx.py | 146 ------------------ slides-creator/scripts/validate_slides.py | 99 ------------ 14 files changed, 1095 deletions(-) delete mode 100644 slides-creator/.security-scan-passed delete mode 100644 slides-creator/references/content-creation-first-law.md delete mode 100644 slides-creator/references/narrative-design-guide.md delete mode 100644 slides-creator/references/prompt-templates/quote-focus.md delete mode 100644 slides-creator/references/prompt-templates/split-comparison.md delete mode 100644 slides-creator/references/prompt-templates/three-column.md delete mode 100644 slides-creator/references/prompt-templates/title-hero.md delete mode 100644 slides-creator/references/style-gallery.md delete mode 100755 slides-creator/scripts/archive_version.py delete mode 100755 slides-creator/scripts/extract_notes.py delete mode 100755 slides-creator/scripts/main.ts delete mode 100755 slides-creator/scripts/merge_to_pdf.py delete mode 100755 slides-creator/scripts/merge_to_pptx.py delete mode 100755 slides-creator/scripts/validate_slides.py diff --git a/slides-creator/.security-scan-passed b/slides-creator/.security-scan-passed deleted file mode 100644 index b80cd6cc..00000000 --- a/slides-creator/.security-scan-passed +++ /dev/null @@ -1,4 +0,0 @@ -Security scan passed -Scanned at: 2026-04-19T23:10:12.585729 -Tool: gitleaks + pattern-based validation -Content hash: 12cbafeb3e9d8320bbd4469335891d8a58bacf49c11d22a6e346dc038a90fb09 diff --git a/slides-creator/references/content-creation-first-law.md b/slides-creator/references/content-creation-first-law.md deleted file mode 100644 index 62aedf65..00000000 --- a/slides-creator/references/content-creation-first-law.md +++ /dev/null @@ -1,116 +0,0 @@ -# Content Creation First Law - -## The Principle - -**AI cannot write high-quality content for the user. It can only help the user express their own content better.** - -> The most important step in creating any piece of content — whether a slide deck, an article, an advertisement, or a course — is **collecting the user's original words first**. -> -> Without the user's source material, AI produces polished, plausible, unusable garbage. It may sound impressive, but it won't sound like the user. It won't reflect their expertise. It won't be something they can confidently deliver or stand behind. - -## Why This Matters - -| Approach | Result | -|----------|--------| -| AI writes alone | Generic, AI-tinged content that the user cannot authentically deliver | -| AI + user's raw material | Content that sounds like the user at their best — authentic, specific, powerful | - -The goal is not to have AI do what the user cannot do. The goal is to **reduce the user's workload** while **preserving and elevating their voice**. - -## The Weight Hierarchy - -All content sources are NOT equal. Use this priority order: - -``` -1. User's own words (highest authority) - - Transcripts of their talks - - Articles they wrote - - Notes they prepared - - Voice memos or recordings - - Their explicit statements during discussion - -2. User-approved external material - - Articles they selected - - References they endorsed - - Research they reviewed - -3. AI synthesis (requires user validation) - - AI-organized structure - - AI-suggested transitions - - AI-generated visual descriptions - -4. AI invention (lowest authority, use sparingly) - - AI-fabricated examples - - AI-generated quotes - - AI-invented statistics - → MUST be labeled as draft, MUST be validated by user -``` - -## The Process - -### Step 1: Collect - -Before creating ANY content, collect from the user: - -- Past transcripts (meetings, talks, interviews) -- Existing writings (articles, drafts, notes) -- Previous decks or materials -- Voice memos or recorded thoughts -- Key messages they want to convey - -If no written material exists, the entire narrative must be extracted through structured conversation. **Do not fabricate.** - -### Step 2: Validate - -For external materials: -- Present findings to the user -- Let them select what is relevant -- Only include user-approved references - -### Step 3: Assist - -With user source material as the foundation: -- Organize and structure their ideas -- Suggest narrative arcs and transitions -- Design visuals that amplify their message -- Polish expression without changing substance - -### Step 4: Verify - -Final content must pass: -- [ ] Could the user actually say this in their own words? -- [ ] Does it reflect their expertise and perspective? -- [ ] Are all claims traceable to user's words or approved sources? -- [ ] Does it sound like them, not like generic AI output? - -## Failure Modes - -| Failure | Symptom | Prevention | -|---------|---------|------------| -| AI hallucinated content | User says "This doesn't sound like me" or "I never said that" | Always ground content in Phase 0 source materials | -| AI invented examples | Examples feel generic or disconnected from user's experience | Ask user for real examples; mark gaps as [TODO] | -| AI-generated quotes | Quotes don't match user's speaking style | Use verbatim from transcripts; don't fabricate | -| AI chose references | User disagrees with included sources | Present options; user selects | -| Content is "AI-flavored" | Long sentences, hedging language, "delve into", "leverage" | Rewrite in user's voice; use their sentence patterns | - -## Application to Different Content Types - -| Content Type | User Source Material | AI's Role | -|--------------|---------------------|-----------| -| **Slide deck** | Transcripts, talk notes, previous decks | Structure narrative, design visuals, synthesize | -| **Article** | Draft notes, voice memos, talking points | Organize structure, improve flow, polish language | -| **Advertisement** | Product description, user testimonials, brand voice guide | Write copy that matches brand voice, suggest hooks | -| **Course** | Teaching notes, workshop transcripts, exercise ideas | Design curriculum, create pacing, build assessments | -| **Email/WeChat** | Their usual writing style, specific message intent | Draft in their voice, suggest phrasing | - -## Corollaries - -1. **If the user has no existing content**, your job is to help them articulate their thoughts through structured conversation — NOT to fabricate content for them. - -2. **External materials must be user-selected**. AI does not decide what is relevant. The user does. - -3. **AI synthesis must be user-validated**. AI can organize and connect, but the user must approve the connections. - -4. **AI invention must be labeled**. Anything AI creates that is not grounded in user source material must be clearly marked as draft and requires user approval. - -5. **The output must be speakable/deliverable**. If the user cannot confidently say it in their own voice, it is not done. diff --git a/slides-creator/references/narrative-design-guide.md b/slides-creator/references/narrative-design-guide.md deleted file mode 100644 index 664c72a0..00000000 --- a/slides-creator/references/narrative-design-guide.md +++ /dev/null @@ -1,108 +0,0 @@ -# Narrative Design Guide (ABCDEFG Model) - -## A - Attention (Hook) - -**Goal**: Capture attention in the first 30 seconds. - -**Techniques**: -- **Contrarian statement**: "Everything you know about X is wrong" -- **Surprising statistic**: "90% of teams fail at this" -- **Personal story**: "Three years ago, I made a $2M mistake..." -- **Demo/Visual**: Show, don't tell -- **Question**: "What if I told you..." - -**Slide design**: Big, bold, minimal text. One visual element that demands attention. - -## B - Benefit (Promise) - -**Goal**: Let the audience know what's in it for them. - -**Techniques**: -- Clear statement of takeaway -- Time-bound promise ("In 30 minutes, you'll learn...") -- Audience-specific benefit ("As engineers, this means...") - -**Slide design**: Headline + 3 bullet points of promised outcomes. - -## C - Credibility (Why Trust You?) - -**Goal**: Establish authority without boasting. - -**Techniques**: -- Relevant experience (not laundry list) -- Social proof (logos, numbers) -- Vulnerability ("I failed at this 3 times before getting it right") - -**Slide design**: Logos, numbers, or a brief bio. Keep it humble. - -## D - Difference (Novel Angle) - -**Goal**: Show what's different about YOUR perspective. - -**Techniques**: -- Reframe common wisdom -- Expose hidden assumptions -- Bridge two unlikely domains - -**Slide design**: Comparison (old way vs new way), or metaphor illustration. - -## E - Evidence (Proof) - -**Goal**: Back up claims with data, demos, or stories. - -**Techniques**: -- Case studies -- Live demos -- Data visualizations -- Customer quotes - -**Slide design**: Charts, screenshots, or story panels. - -## F - Framework (Mental Model) - -**Goal**: Give the audience a reusable mental model. - -**Techniques**: -- 3-part framework -- Matrix/quadrant -- Process flow -- Mnemonic - -**Slide design**: Diagram, flowchart, or structured list. - -## G - Go (Call to Action) - -**Goal**: Tell them exactly what to do next. - -**Techniques**: -- Specific next step (not "think about it") -- Low friction ("Scan this QR code") -- Time-bound ("Join before Friday") - -**Slide design**: Clear CTA, contact info, or QR code. - ---- - -## Narrative Arc Patterns - -### Pattern 1: Problem → Solution → Proof -Best for: Product pitches, tool introductions - -### Pattern 2: What → So What → Now What -Best for: Educational talks, research presentations - -### Pattern 3: Story → Lesson → Application -Best for: Keynotes, inspirational talks - -### Pattern 4: Myth → Truth → Practice -Best for: Debunking talks, contrarian content - ---- - -## Common Pitfalls - -1. **The Wikipedia talk**: Listing facts without a through-line -2. **The feature dump**: Showing everything instead of the best thing -3. **The no-arc**: Flat energy from start to finish -4. **The surprise ending**: No setup for the conclusion -5. **The too-many-things**: Trying to teach 5 topics in 20 minutes diff --git a/slides-creator/references/prompt-templates/quote-focus.md b/slides-creator/references/prompt-templates/quote-focus.md deleted file mode 100644 index dff96a34..00000000 --- a/slides-creator/references/prompt-templates/quote-focus.md +++ /dev/null @@ -1,53 +0,0 @@ -Create a presentation slide image following these guidelines: - -## Image Specifications - -- **Type**: Presentation slide -- **Aspect Ratio**: 16:9 (landscape) -- **Style**: {{style_name}} - -## Core Principles - -- Flat cartoon style throughout - NO realistic or photographic elements -- NO slide numbers, page numbers, footers, headers, or logos -- Clean, uncluttered layouts with clear visual hierarchy -- Each slide conveys ONE clear message - -## Text Style (CRITICAL) - -- **ALL text MUST match the designated style exactly** -- Title text: Large, bold, immediately readable -- Body text: Clear, legible, appropriate sizing -- Max 3-4 text elements per slide - -## Language - -- All text in {{language}} -- Write in direct, confident language - ---- - - -{{style_instructions}} - - ---- - -## SLIDE CONTENT - -**Slide {{slide_number}} of {{total_slides}} — Quote Focus** -**Filename**: {{slide_number}}-slide-{{name}}.png - -// NARRATIVE GOAL -{{narrative_goal}} - -// KEY CONTENT -Headline: {{headline}} -Quote: {{quote_text}} -Attribution: {{attribution}} (optional) - -// VISUAL -{{visual_description}} - -// LAYOUT -Layout: quote-focus. Headline at top. Large centered quote text (largest text on slide). Attribution below quote in smaller text. Optional decorative quotation mark graphic. Clean, minimal, high impact. diff --git a/slides-creator/references/prompt-templates/split-comparison.md b/slides-creator/references/prompt-templates/split-comparison.md deleted file mode 100644 index 99a10cde..00000000 --- a/slides-creator/references/prompt-templates/split-comparison.md +++ /dev/null @@ -1,53 +0,0 @@ -Create a presentation slide image following these guidelines: - -## Image Specifications - -- **Type**: Presentation slide -- **Aspect Ratio**: 16:9 (landscape) -- **Style**: {{style_name}} - -## Core Principles - -- Flat cartoon style throughout - NO realistic or photographic elements -- NO slide numbers, page numbers, footers, headers, or logos -- Clean, uncluttered layouts with clear visual hierarchy -- Each slide conveys ONE clear message - -## Text Style (CRITICAL) - -- **ALL text MUST match the designated style exactly** -- Title text: Large, bold, immediately readable -- Body text: Clear, legible, appropriate sizing -- Max 3-4 text elements per slide - -## Language - -- All text in {{language}} -- Write in direct, confident language - ---- - - -{{style_instructions}} - - ---- - -## SLIDE CONTENT - -**Slide {{slide_number}} of {{total_slides}} — Comparison** -**Filename**: {{slide_number}}-slide-{{name}}.png - -// NARRATIVE GOAL -{{narrative_goal}} - -// KEY CONTENT -Headline: {{headline}} -Left Label: {{left_label}} -Right Label: {{right_label}} - -// VISUAL -{{visual_description}} - -// LAYOUT -Layout: split-comparison. Headline at top. Two columns side by side at center (50/50 split). Clear visual divider between sides. Labels below each column. Optional summary banner at bottom 20%. diff --git a/slides-creator/references/prompt-templates/three-column.md b/slides-creator/references/prompt-templates/three-column.md deleted file mode 100644 index 1e8edf95..00000000 --- a/slides-creator/references/prompt-templates/three-column.md +++ /dev/null @@ -1,54 +0,0 @@ -Create a presentation slide image following these guidelines: - -## Image Specifications - -- **Type**: Presentation slide -- **Aspect Ratio**: 16:9 (landscape) -- **Style**: {{style_name}} - -## Core Principles - -- Flat cartoon style throughout - NO realistic or photographic elements -- NO slide numbers, page numbers, footers, headers, or logos -- Clean, uncluttered layouts with clear visual hierarchy -- Each slide conveys ONE clear message - -## Text Style (CRITICAL) - -- **ALL text MUST match the designated style exactly** -- Title text: Large, bold, immediately readable -- Body text: Clear, legible, appropriate sizing -- Max 3-4 text elements per slide - -## Language - -- All text in {{language}} -- Write in direct, confident language - ---- - - -{{style_instructions}} - - ---- - -## SLIDE CONTENT - -**Slide {{slide_number}} of {{total_slides}} — Three Columns** -**Filename**: {{slide_number}}-slide-{{name}}.png - -// NARRATIVE GOAL -{{narrative_goal}} - -// KEY CONTENT -Headline: {{headline}} -Column 1: {{column_1_title}} - {{column_1_content}} -Column 2: {{column_2_title}} - {{column_2_content}} -Column 3: {{column_3_title}} - {{column_3_content}} - -// VISUAL -{{visual_description}} - -// LAYOUT -Layout: three-column. Headline at top. Three equal columns (33/33/33) side by side. Each column has a distinct accent color. Generous spacing between columns. Optional connecting element (arrow, flow) between columns. diff --git a/slides-creator/references/prompt-templates/title-hero.md b/slides-creator/references/prompt-templates/title-hero.md deleted file mode 100644 index b0fd9e41..00000000 --- a/slides-creator/references/prompt-templates/title-hero.md +++ /dev/null @@ -1,52 +0,0 @@ -Create a presentation slide image following these guidelines: - -## Image Specifications - -- **Type**: Presentation slide -- **Aspect Ratio**: 16:9 (landscape) -- **Style**: {{style_name}} - -## Core Principles - -- Flat cartoon style throughout - NO realistic or photographic elements -- NO slide numbers, page numbers, footers, headers, or logos -- Clean, uncluttered layouts with clear visual hierarchy -- Each slide conveys ONE clear message - -## Text Style (CRITICAL) - -- **ALL text MUST match the designated style exactly** -- Title text: Large, bold, immediately readable -- Body text: Clear, legible, appropriate sizing -- Max 3-4 text elements per slide - -## Language - -- All text in {{language}} -- Write in direct, confident language - ---- - - -{{style_instructions}} - - ---- - -## SLIDE CONTENT - -**Slide {{slide_number}} of {{total_slides}} — Cover** -**Filename**: {{slide_number}}-slide-cover.png - -// NARRATIVE GOAL -{{narrative_goal}} - -// KEY CONTENT -Headline: {{headline}} -Sub-headline: {{sub_headline}} - -// VISUAL -{{visual_description}} - -// LAYOUT -Layout: title-hero. Headline centered at top. Sub-headline below. Hero visual composition centered in the lower 60% of the slide. diff --git a/slides-creator/references/style-gallery.md b/slides-creator/references/style-gallery.md deleted file mode 100644 index 48e9e310..00000000 --- a/slides-creator/references/style-gallery.md +++ /dev/null @@ -1,65 +0,0 @@ -# Style Gallery - -## flat-cartoon-infographic - -**Best for**: Tech explainers, approachable content, WeChat-style infographics - -**Tokens**: -- White background (#FFFFFF) -- Flat cartoon illustrations (simple rounded shapes) -- Colorful pill/tag shapes for lists -- Bold color contrasts -- 2-3 key points per slide - -**Example**: "龙虾 vs Claude Code" deck - -## corporate-clean - -**Best for**: Investor decks, B2B sales, executive briefings - -**Tokens**: -- Minimal design -- Geometric shapes -- Muted palette (blues, grays) -- Lots of whitespace -- Data-forward - -## chalkboard-edu - -**Best for**: Tutorials, workshops, educational content - -**Tokens**: -- Dark background (blackboard) -- Handwritten-style typography -- Warm tones (yellows, oranges) -- Sketch/doodle aesthetic - -## bold-editorial - -**Best for**: Keynotes, product launches, creative presentations - -**Tokens**: -- High contrast -- Editorial typography (serif headlines) -- Full-bleed images -- Magazine-like layouts - -## scientific - -**Best for**: Research presentations, academic talks, technical deep-dives - -**Tokens**: -- Clean, structured layouts -- Cool color palette (blues, teals) -- Data visualizations -- Citation-ready - -## notion - -**Best for**: Product demos, SaaS presentations, tool tutorials - -**Tokens**: -- Clean, neutral colors -- Geometric icons -- Dense but organized information -- Modern SaaS aesthetic diff --git a/slides-creator/scripts/archive_version.py b/slides-creator/scripts/archive_version.py deleted file mode 100755 index dc41245c..00000000 --- a/slides-creator/scripts/archive_version.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python3 -# /// script -# requires-python = ">=3.10" -# dependencies = [] -# /// -"""Archive current slide version to _archive/v{N}/.""" - -import argparse -import shutil -from pathlib import Path - - -def get_next_version(archive_dir: Path) -> int: - """Find the next version number (v1, v2, ...).""" - if not archive_dir.exists(): - return 1 - versions = [] - for d in archive_dir.iterdir(): - if d.is_dir() and d.name.startswith("v"): - try: - versions.append(int(d.name[1:])) - except ValueError: - pass - return max(versions, default=0) + 1 - - -def archive_version(project_dir: str): - """Archive 02-slides/ and 03-prompts/ to _archive/v{N}/.""" - project_path = Path(project_dir) - slides_dir = project_path / "02-slides" - prompts_dir = project_path / "03-prompts" - - if not slides_dir.exists(): - print(f"No slides to archive: {slides_dir}") - return False - - archive_dir = project_path / "_archive" - next_ver = get_next_version(archive_dir) - target_dir = archive_dir / f"v{next_ver}" - - print(f"Archiving to: {target_dir}") - target_dir.mkdir(parents=True, exist_ok=False) - - # Copy slides - target_slides = target_dir / "02-slides" - shutil.copytree(slides_dir, target_slides) - print(f" Copied slides: {len(list(target_slides.glob('*.png')))} files") - - # Copy prompts if exist - if prompts_dir.exists(): - target_prompts = target_dir / "03-prompts" - shutil.copytree(prompts_dir, target_prompts) - prompt_count = sum(1 for _ in target_prompts.rglob("*.md")) - print(f" Copied prompts: {prompt_count} files") - - print(f"Archive v{next_ver} complete.") - return True - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Archive slide version") - parser.add_argument("--project", required=True, help="Project directory") - args = parser.parse_args() - - archive_version(args.project) diff --git a/slides-creator/scripts/extract_notes.py b/slides-creator/scripts/extract_notes.py deleted file mode 100755 index 92500ec2..00000000 --- a/slides-creator/scripts/extract_notes.py +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/env python3 -# /// script -# requires-python = ">=3.10" -# dependencies = [] -# /// -"""Extract structured speaker notes from slide prompt files.""" - -import argparse -import re -from pathlib import Path - - -def find_prompt_file(slide_name: str, prompts_dir: Path) -> Path | None: - """Find matching prompt .md for a slide name.""" - # Try flat structure first: 03-prompts/01-slide-cover.md - flat = prompts_dir / f"{slide_name}.md" - if flat.exists(): - return flat - - # Try versioned subdirectories: 03-prompts/v6/01-slide-cover.md - for subdir in prompts_dir.iterdir(): - if subdir.is_dir(): - candidate = subdir / f"{slide_name}.md" - if candidate.exists(): - return candidate - - return None - - -def extract_notes(prompt_text: str) -> dict: - """Extract NARRATIVE GOAL and SPEAKER NOTES sections from prompt.""" - result = {} - - ng_match = re.search( - r"// NARRATIVE GOAL\s*\n(.+?)(?=\n// |\n## |\Z)", - prompt_text, - re.DOTALL, - ) - if ng_match: - result["narrative_goal"] = ng_match.group(1).strip() - - sn_match = re.search( - r"// SPEAKER NOTES\s*\n(.+?)(?=\n// |\n## |\Z)", - prompt_text, - re.DOTALL, - ) - if sn_match: - result["speaker_notes"] = sn_match.group(1).strip() - - # Fallback: KEY CONTENT - if not result: - kc_match = re.search( - r"// KEY CONTENT\s*\n(.+?)(?=\n// |\n## |\Z)", - prompt_text, - re.DOTALL, - ) - if kc_match: - result["key_content"] = kc_match.group(1).strip() - - return result - - -def extract_all_notes(prompts_dir: str, output: str | None = None) -> str: - """Extract notes from all prompt files and return as markdown.""" - prompts_path = Path(prompts_dir) - if not prompts_path.exists(): - raise FileNotFoundError(f"Prompts directory not found: {prompts_dir}") - - # Find all slide prompt files - prompt_files = [] - for path in prompts_path.rglob("*.md"): - # Only match files like 01-slide-xxx.md (not README etc.) - if re.match(r"\d+-slide-", path.name): - prompt_files.append(path) - - # Sort by slide number extracted from filename - def sort_key(p: Path) -> int: - match = re.match(r"(\d+)-slide-", p.name) - return int(match.group(1)) if match else 999 - - prompt_files.sort(key=sort_key) - - lines = ["# Speaker Notes\n"] - matched = 0 - - for prompt_file in prompt_files: - slide_name = prompt_file.stem # e.g. "01-slide-cover" - prompt_text = prompt_file.read_text(encoding="utf-8") - notes = extract_notes(prompt_text) - - if notes: - matched += 1 - lines.append(f"## {slide_name}") - if "narrative_goal" in notes: - lines.append(f"**Narrative Goal**: {notes['narrative_goal']}") - if "speaker_notes" in notes: - lines.append(f"**Speaker Notes**: {notes['speaker_notes']}") - if "key_content" in notes: - lines.append(f"**Key Content**: {notes['key_content']}") - lines.append("") - - result = "\n".join(lines) - - if output: - output_path = Path(output) - output_path.write_text(result, encoding="utf-8") - print(f"Wrote speaker notes to: {output}") - print(f"Prompts scanned: {len(prompt_files)}") - print(f"Slides with notes: {matched}") - - return result - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Extract speaker notes from prompts") - parser.add_argument("--prompts", required=True, help="Directory containing per-slide prompt .md files") - parser.add_argument("--output", help="Output markdown file path (default: print to stdout)") - args = parser.parse_args() - - extract_all_notes(args.prompts, args.output) diff --git a/slides-creator/scripts/main.ts b/slides-creator/scripts/main.ts deleted file mode 100755 index 81498893..00000000 --- a/slides-creator/scripts/main.ts +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/env bun -/** - * Post-processing: assemble deliverables from generated slides - * - * After baoyu-slide-deck generates PNGs, this script: - * 1. Validates the slide sequence (aspect ratio, naming, gaps) - * 2. Extracts structured speaker notes from 03-prompts/ - * 3. Generates PDF + PPTX in 01-成品/ - * - * This does NOT generate images — image generation is delegated to baoyu-slide-deck. - * Post-processing handles: validation, notes extraction, and assembly into deliverables. - * - * Usage: - * bun main.ts --project /path/to/slide-deck/project-name - */ - -import { $ } from "bun"; -import { existsSync } from "fs"; -import { resolve, basename } from "path"; - -interface Args { - projectDir: string; -} - -function parseArgs(): Args { - const idx = process.argv.indexOf("--project"); - if (idx === -1 || !process.argv[idx + 1]) { - console.error("Usage: bun main.ts --project /path/to/slide-deck/project-name"); - process.exit(1); - } - return { projectDir: resolve(process.argv[idx + 1]) }; -} - -async function main() { - const { projectDir } = parseArgs(); - const projectName = basename(projectDir); - - const slidesDir = `${projectDir}/02-slides`; - const outputDir = `${projectDir}/01-成品`; - - if (!existsSync(slidesDir)) { - console.error(`Slides directory not found: ${slidesDir}`); - process.exit(1); - } - - if (!existsSync(outputDir)) { - console.log(`Creating output directory: ${outputDir}`); - await $`mkdir -p ${outputDir}`; - } - - // Validate slides - console.log("Validating slides..."); - const { stdout } = await $`uv run ${import.meta.dir}/validate_slides.py --slides ${slidesDir}`; - const result = JSON.parse(stdout.toString()); - - if (result.status === "FAILED") { - console.error("Validation failed:", result.issues); - process.exit(1); - } - if (result.warnings.length > 0) { - console.warn("Warnings:", result.warnings); - } - console.log(`Validation passed: ${result.slide_count} slides`); - - // Extract speaker notes - const promptsDir = `${projectDir}/03-prompts`; - const notesPath = `${projectDir}/speaker-notes.md`; - if (existsSync(promptsDir)) { - console.log(`Extracting speaker notes: ${notesPath}`); - await $`uv run ${import.meta.dir}/extract_notes.py --prompts ${promptsDir} --output ${notesPath}`; - } - - // Generate PDF - const pdfPath = `${outputDir}/${projectName}.pdf`; - console.log(`Generating PDF: ${pdfPath}`); - await $`uv run ${import.meta.dir}/merge_to_pdf.py --slides ${slidesDir} --output ${pdfPath}`; - - // Generate PPTX (with speaker notes from 03-prompts/) - const pptxPath = `${outputDir}/${projectName}.pptx`; - console.log(`Generating PPTX: ${pptxPath}`); - if (existsSync(promptsDir)) { - await $`uv run ${import.meta.dir}/merge_to_pptx.py --slides ${slidesDir} --output ${pptxPath} --prompts ${promptsDir}`; - } else { - await $`uv run ${import.meta.dir}/merge_to_pptx.py --slides ${slidesDir} --output ${pptxPath}`; - } - - console.log("\nPost-processing complete!"); - console.log(`Deliverables in ${outputDir}:`); - console.log(` - ${projectName}.pdf`); - console.log(` - ${projectName}.pptx`); -} - -main().catch((err) => { - console.error(err); - process.exit(1); -}); diff --git a/slides-creator/scripts/merge_to_pdf.py b/slides-creator/scripts/merge_to_pdf.py deleted file mode 100755 index 4bb0c857..00000000 --- a/slides-creator/scripts/merge_to_pdf.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python3 -# /// script -# requires-python = ">=3.10" -# dependencies = ["Pillow"] -# /// -"""Merge slide PNGs into a single PDF.""" - -import argparse -import re -from pathlib import Path -from PIL import Image - - -def parse_slide_number(filename: str) -> int | None: - """Extract slide number from filename like '01-slide-cover.png'.""" - match = re.match(r"(\d+)-slide-", filename) - return int(match.group(1)) if match else None - - -def merge_to_pdf(slides_dir: str, output: str): - """Merge PNG slides into PDF.""" - slides_path = Path(slides_dir) - png_files = sorted( - [f for f in slides_path.glob("*.png") if parse_slide_number(f.name) is not None], - key=lambda f: parse_slide_number(f.name) or 0, - ) - - if not png_files: - print(f"No PNG files found in {slides_dir}") - return False - - images = [] - for png in png_files: - img = Image.open(png) - if img.mode == 'RGBA': - # Convert RGBA to RGB for PDF compatibility - background = Image.new('RGB', img.size, (255, 255, 255)) - background.paste(img, mask=img.split()[3]) - img = background - images.append(img) - - # Save first image, append rest - first_image = images[0] - rest_images = images[1:] if len(images) > 1 else [] - - first_image.save( - output, - save_all=True, - append_images=rest_images, - resolution=150.0, - ) - - print(f"Created PDF: {output}") - print(f"Slides included: {len(images)}") - return True - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Merge slide PNGs to PDF") - parser.add_argument("--slides", required=True, help="Directory containing PNG slides") - parser.add_argument("--output", required=True, help="Output PDF path") - args = parser.parse_args() - - merge_to_pdf(args.slides, args.output) diff --git a/slides-creator/scripts/merge_to_pptx.py b/slides-creator/scripts/merge_to_pptx.py deleted file mode 100755 index ad0cfaeb..00000000 --- a/slides-creator/scripts/merge_to_pptx.py +++ /dev/null @@ -1,146 +0,0 @@ -#!/usr/bin/env python3 -# /// script -# requires-python = ">=3.10" -# dependencies = ["python-pptx", "Pillow"] -# /// -"""Merge slide PNGs into a PowerPoint file with optional speaker notes.""" - -import argparse -import re -from pathlib import Path -from PIL import Image -from pptx import Presentation -from pptx.util import Inches - - -EMUS_PER_INCH = 914400 - - -def parse_slide_number(filename: str) -> int | None: - """Extract slide number from filename like '01-slide-cover.png'.""" - match = re.match(r"(\d+)-slide-", filename) - return int(match.group(1)) if match else None - - -def find_prompt_file(slide_name: str, prompts_dir: Path) -> Path | None: - """Find matching prompt .md for a slide name.""" - # Try flat structure first: 03-prompts/01-slide-cover.md - flat = prompts_dir / f"{slide_name}.md" - if flat.exists(): - return flat - - # Try versioned subdirectories: 03-prompts/v6/01-slide-cover.md - for subdir in prompts_dir.iterdir(): - if subdir.is_dir(): - candidate = subdir / f"{slide_name}.md" - if candidate.exists(): - return candidate - - return None - - -def extract_notes(prompt_text: str) -> str: - """Extract NARRATIVE GOAL and SPEAKER NOTES sections from prompt.""" - notes_parts = [] - - # Extract // NARRATIVE GOAL - ng_match = re.search(r"// NARRATIVE GOAL\s*\n(.+?)(?=\n// |\n## |\Z)", prompt_text, re.DOTALL) - if ng_match: - notes_parts.append(f"NARRATIVE GOAL:\n{ng_match.group(1).strip()}") - - # Extract // SPEAKER NOTES - sn_match = re.search(r"// SPEAKER NOTES\s*\n(.+?)(?=\n// |\n## |\Z)", prompt_text, re.DOTALL) - if sn_match: - notes_parts.append(f"SPEAKER NOTES:\n{sn_match.group(1).strip()}") - - # If neither section found but there's KEY CONTENT, use that as fallback - if not notes_parts: - kc_match = re.search(r"// KEY CONTENT\s*\n(.+?)(?=\n// |\n## |\Z)", prompt_text, re.DOTALL) - if kc_match: - notes_parts.append(f"KEY CONTENT:\n{kc_match.group(1).strip()}") - - return "\n\n".join(notes_parts) if notes_parts else "" - - -def get_image_aspect_ratio(image_path: Path) -> float: - """Return width / height ratio of an image.""" - with Image.open(image_path) as img: - return img.width / img.height - - -def merge_to_pptx( - slides_dir: str, - output: str, - prompts_dir: str | None = None, - title: str | None = None, -): - """Merge PNG slides into PowerPoint with speaker notes.""" - slides_path = Path(slides_dir) - png_files = sorted( - [f for f in slides_path.glob("*.png") if parse_slide_number(f.name) is not None], - key=lambda f: parse_slide_number(f.name) or 0, - ) - - if not png_files: - print(f"No PNG files found in {slides_dir}") - return False - - # Auto-detect prompts directory - if prompts_dir is None: - project_root = slides_path.parent - auto_prompts = project_root / "03-prompts" - if auto_prompts.exists(): - prompts_dir = str(auto_prompts) - prompts_path = Path(prompts_dir) if prompts_dir else None - - # Dynamic slide size from first image - first_ratio = get_image_aspect_ratio(png_files[0]) - # Standard 16:9 is 13.333 x 7.5 inches; scale height to match ratio - target_height = Inches(7.5) - target_width = Inches(7.5 * first_ratio) - - prs = Presentation() - prs.slide_width = int(target_width) - prs.slide_height = int(target_height) - - notes_count = 0 - for png in png_files: - slide_layout = prs.slide_layouts[6] # blank layout - slide = prs.slides.add_slide(slide_layout) - slide.shapes.add_picture( - str(png), - Inches(0), - Inches(0), - width=prs.slide_width, - height=prs.slide_height, - ) - - # Add speaker notes if prompt file found - slide_name = png.stem # e.g. "01-slide-cover" - if prompts_path: - prompt_file = find_prompt_file(slide_name, prompts_path) - if prompt_file: - prompt_text = prompt_file.read_text(encoding="utf-8") - notes = extract_notes(prompt_text) - if notes: - notes_slide = slide.notes_slide - notes_slide.notes_text_frame.text = notes - notes_count += 1 - - prs.save(output) - print(f"Created PPTX: {output}") - print(f"Slides included: {len(png_files)}") - if prompts_path: - print(f"Slides with notes: {notes_count}") - return True - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Merge slide PNGs to PPTX") - parser.add_argument("--slides", required=True, help="Directory containing PNG slides") - parser.add_argument("--output", required=True, help="Output PPTX path") - parser.add_argument("--prompts", help="Directory containing per-slide prompt .md files (default: 03-prompts/ relative to slides parent)") - parser.add_argument("--title", help="Presentation title") - args = parser.parse_args() - - merge_to_pptx(args.slides, args.output, args.prompts, args.title) diff --git a/slides-creator/scripts/validate_slides.py b/slides-creator/scripts/validate_slides.py deleted file mode 100755 index 187ed840..00000000 --- a/slides-creator/scripts/validate_slides.py +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env python3 -# /// script -# requires-python = ">=3.10" -# dependencies = ["Pillow"] -# /// -"""Validate slide deck consistency.""" - -import argparse -import json -import os -from pathlib import Path -from PIL import Image - - -def validate_slides(slides_dir: str, expected_count: int = None): - """Validate slide deck for consistency issues.""" - slides_path = Path(slides_dir) - png_files = sorted(slides_path.glob("*.png")) - - issues = [] - warnings = [] - info = [] - - if not png_files: - issues.append(f"No PNG files found in {slides_dir}") - return {"status": "FAILED", "issues": issues, "warnings": warnings, "info": info} - - info.append(f"Found {len(png_files)} slides") - - # Check expected count - if expected_count and len(png_files) != expected_count: - warnings.append(f"Expected {expected_count} slides, found {len(png_files)}") - - # Check aspect ratios - aspect_ratios = {} - for png in png_files: - img = Image.open(png) - ratio = round(img.width / img.height, 2) - aspect_ratios[ratio] = aspect_ratios.get(ratio, []) + [png.name] - - if len(aspect_ratios) > 1: - issues.append(f"Inconsistent aspect ratios: {aspect_ratios}") - else: - ratio = list(aspect_ratios.keys())[0] - info.append(f"Consistent aspect ratio: {ratio} (16:9 ≈ 1.78)") - if abs(ratio - 1.78) > 0.05: - warnings.append(f"Aspect ratio {ratio} deviates from standard 16:9 (1.78)") - - # Check naming convention - expected_pattern = True - for i, png in enumerate(png_files, 1): - expected_prefix = f"{i:02d}-slide-" - if not png.name.startswith(expected_prefix): - warnings.append(f"Naming convention: {png.name} doesn't start with {expected_prefix}") - expected_pattern = False - - if expected_pattern: - info.append("Naming convention: OK") - - # Check for gaps in numbering - numbers = [] - for png in png_files: - try: - num = int(png.name.split("-")[0]) - numbers.append(num) - except ValueError: - warnings.append(f"Cannot extract number from {png.name}") - - if numbers: - expected_set = set(range(min(numbers), max(numbers) + 1)) - actual_set = set(numbers) - gaps = expected_set - actual_set - if gaps: - warnings.append(f"Missing slide numbers: {sorted(gaps)}") - - # File size check - oversized = [png for png in png_files if png.stat().st_size > 10 * 1024 * 1024] # 10MB - if oversized: - warnings.append(f"Oversized files (>10MB): {[p.name for p in oversized]}") - - status = "FAILED" if issues else "PASSED" if not warnings else "PASSED_WITH_WARNINGS" - - return { - "status": status, - "slide_count": len(png_files), - "issues": issues, - "warnings": warnings, - "info": info - } - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Validate slide deck") - parser.add_argument("--slides", required=True, help="Directory containing PNG slides") - parser.add_argument("--expected-count", type=int, help="Expected number of slides") - args = parser.parse_args() - - result = validate_slides(args.slides, args.expected_count) - print(json.dumps(result, indent=2, ensure_ascii=False)) From e9d52f7e3738bdc1ab2b576c565289b9868f851c Mon Sep 17 00:00:00 2001 From: daymade Date: Fri, 7 Aug 2026 14:09:22 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix(slides-creator):=20=E8=A1=A5=E4=B8=8A?= =?UTF-8?q?=E5=89=8D=E4=B8=80=E4=B8=AA=20commit=20=E8=A2=AB=20scope-guard?= =?UTF-8?q?=20=E6=8B=A6=E6=8E=89=E7=9A=84=E9=80=80=E5=BD=B9=E4=B8=89?= =?UTF-8?q?=E4=BB=B6=E5=A5=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 3ffe8dd 只提交了删除(首次 Bash 调用在 PreToolUse 被拦,heredoc stub 写入、 marketplace bump、changelog 均未执行,retry 只跑了 git commit)。 本 commit 补齐:SKILL.md 退役 stub、marketplace 2.0.0、CHANGELOG 条目。 CI「Touched skills still validate」红的原因。 Co-Authored-By: Claude --- .claude-plugin/marketplace.json | 4 +- CHANGELOG.md | 2 + slides-creator/SKILL.md | 604 ++------------------------------ 3 files changed, 25 insertions(+), 585 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 30479037..cd100ff1 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -676,10 +676,10 @@ }, { "name": "slides-creator", - "description": "Narrative-first slide deck creation. Guides users through structured narrative design (ABCDEFG model), then delegates visual generation to baoyu-slide-deck. Triggers on create slides, make a presentation, generate deck, slide deck, PPT, or when user needs to turn content into visual slides.", + "description": "【DEPRECATED · 已废弃】叙事优先的幻灯片创建方法论已于 2026-08-07 并入 deck-creator(作者私有仓 Route A)。本条目仅为退役通告保留,请勿调用。", "source": "./slides-creator", "strict": false, - "version": "1.0.0", + "version": "2.0.0", "category": "content-creation", "keywords": [ "slides", diff --git a/CHANGELOG.md b/CHANGELOG.md index 8117fbf5..e84221d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added +- **slides-creator** (v2.0.0): **DEPRECATED — skill retired to a stub, no longer maintained.** Same consolidation as ppt-creator (daymade-docs v1.6.0, same release): the PPT toolchain merge of 2026-08-07 folded its methodology — First Law (user's voice is primary), the ABCDEFG narrative-discussion framework, the baoyu-slide-deck delegation protocol, and the four-layer directory governance — into deck-creator's Route A · narrative in the author's private marketplace. For external users: this is the final version, kept for install compatibility, receiving no further updates; physical removal in a future major release. references/ and scripts/ removed here (git history preserves them); SKILL.md is now a deprecation notice. + - **ppt-creator** (`daymade-docs` v1.6.0): **DEPRECATED — skill retired to a stub, no longer maintained.** The PPT toolchain was merged on 2026-08-07: ppt-creator / slides-creator / html-to-ppt / a project-embedded pptx_builder were consolidated into a single entry point (deck-creator, in the author's private marketplace; its Route B absorbed this skill's methodology — INTAKE questionnaire, Pyramid-Principle workflow, assertion-evidence templates, VIS-GUIDE chart selection, STYLE-GUIDE, RUBRIC scoring). Motivation: toolchain fragmentation (5 PPT tools) produced a real routing failure — an agent aware of only 2 candidates recommended an approach a client had previously rejected. For external users: this is the final version, kept for install compatibility; it receives no further updates and will be physically removed in daymade-docs v2.0.0. The scripts/ and references/ content was removed in this release (git history preserves it); SKILL.md is now a deprecation notice. - **transcript-fixer** (`daymade-audio` v1.23.1): **「Stage 1 alone is not the job」契约强化**,针对 2026-08-07 真实失效——meeting-ingest 经 `transcript_fixer.script_path` 配置集成(全程 0 次 Skill 加载)只跑 Stage 1 词典、报「逐字稿干净」,73min 腾讯逐字稿 54 处误识漏网,用户批评「你为什么每次都只跑 stage 1」。根因不是缺规则(SKILL.md 早写着 Native AI 是默认主路径、L121 契约节甚至预言过「run Stage 1, apply almost nothing, and report success」),而是规则不在调用方的上下文里。三处收紧:①frontmatter description 插入「Stage 1 alone is not the job.」;②Quick Start bash 块尾部新增「⚠️ STOP」注释块(扫读找命令的集成方不会错过)+「After Stage 1」段强化(豁免条款:仅人类用户当场限定 scope 或有 native pass 已跑证据有效,「the pipeline ran the script」/「稿子短」/「词典已修 N 处」均不算豁免);③cross-skill invocation contract 节引言扩为两种失败并列 +「TWO MUSTs」路标(防读者在 `--apply-domain` 处带合规自信收工),新增「Stage 1 is the whole script call — it must not be the whole job」段(caller 必须接 skill 而非仅 script path;纯 CI 走 Stage 3 API;script-path-only 集成是本文件无解的诚实边界)。两轮 fresh-context 独立审阅全采纳(第一轮 5 条:契约引言未为新 MUST 让位/豁免无有效性标准/漏 Stage 3 路径/零命中校准偏窄;第二轮 4 条:豁免字面覆盖 caller 常驻接线/相对指针落错位/「dictionary never touched」字面不准/「hand to an agent」误读另派),档案 `~/scripts/skill-reviews/transcript-fixer/independent-review-2026-08-07-stage1-not-the-job.md`。回归审计以 git ref 1809c27 为 baseline 通过(2 candidates 均 intentional_boundary + 用户原话「能不能把那个 transcript-fixer 全跑完呢」作 user_approval)。已知残留:meeting-ingest Step 3.5 措辞仍是「Stage 1 dictionary」(失效的直接位置,另一仓,待配套改写)。 diff --git a/slides-creator/SKILL.md b/slides-creator/SKILL.md index 02561f1d..1a79bd2a 100644 --- a/slides-creator/SKILL.md +++ b/slides-creator/SKILL.md @@ -1,594 +1,32 @@ --- name: slides-creator -description: Narrative-first slide deck creation. Guides users through structured narrative design (ABCDEFG model), then delegates visual generation to baoyu-slide-deck. Triggers on "create slides", "make a presentation", "generate deck", "slide deck", "PPT", or when user needs to turn content into visual slides. -context: fork -agent: general-purpose +description: >- + 【DEPRECATED · 已废弃】本 skill 已于 2026-08-07 停止维护。对作者本机环境:其方法论 + (First Law 用户原话优先 / ABCDEFG 叙事框架 / baoyu-slide-deck 委托协议 / 四层目录治理) + 已整体并入 deck-creator(私有仓 daymade-skills-pro 的 Route A · narrative), + 装有 deck-creator 的环境不要调用本 skill。对外部用户:这是最终版本, + 保留安装兼容,不再接收更新。将在后续大版本中物理移除。 --- -# Slides Creator +# slides-creator —— DEPRECATED(2026-08-07) -**Narrative-first slide deck creation.** +**本 skill 已废弃,停止维护。** 保留此 stub 仅为已安装环境的兼容性通告。 -This skill does what machines can't do — narrative co-design with humans — and delegates everything else to the best tool for the job (`baoyu-slide-deck`). +## 发生了什么 -## First Law: The User's Voice Is Primary +PPT 工具链于 2026-08-07 合并:ppt-creator / slides-creator / html-to-ppt / 项目内嵌 pptx_builder +四个工具合并为单一入口 **deck-creator**。本 skill 的方法论已整体并入 deck-creator 的 +**Route A · narrative**(First Law 用户原话优先 + ABCDEFG 叙事讨论 + baoyu 图像轨委托协议 ++ code 可编辑轨 + 四层目录治理)。 -**This is the highest-priority rule. Nothing overrides it.** +## 不同用户怎么办 -> AI cannot write high-quality content for the user. It can only help the user express their own content better. -> -> **Step 1 is ALWAYS: collect the user's original words.** Their transcripts, their articles, their notes, their voice. AI-generated content without user source material is garbage — polished, plausible, unusable garbage. -> -> **Weight hierarchy**: User's own words > User-approved external material > AI synthesis > AI invention. -> -> The output must sound like the user, at their best. Something they could actually say, confidently, in their own voice. +| 你是谁 | 怎么办 | +|---|---| +| daymade 本机环境 | 用 `deck-creator`(私有仓 daymade-skills-pro,Route A)。不要再调用本 skill | +| 外部用户(公共 marketplace 安装) | 本版本是最终版,可继续用但不再更新;deck-creator 在私有仓不对外分发 | -**Corollary**: If the user has no existing content, your job is to help them articulate their thoughts through structured conversation — NOT to fabricate content for them. +## 为什么合并 -**Corollary**: External materials (articles, references) must be presented to the user for selection and validation. AI does not decide what is relevant. The user does. - -**See**: `references/content-creation-first-law.md` for full principle, application to all content types, and failure modes. - -## Architecture - -``` -slides-creator (this skill) -├── Phase 0: Source Collection ← Gather user's original words -├── Phase 1: Narrative Design ← Human expertise + ABCDEFG discussion -├── Phase 2: Content Structuring ← Convert narrative to machine-readable input -├── Phase 3: Delegate to baoyu-slide-deck -│ ├── --prompts-only → outline + prompts -│ └── --images-only → images + PPTX + PDF -└── Phase 6: Post-processing ← Directory reorg + speaker notes extraction -``` - -**Rule**: If `baoyu-slide-deck` can do it, we call it. We only do what baoyu-slide-deck cannot: narrative discussion, ABCDEFG methodology, and user's preferred directory structure. - ---- - -## Phase 0: Source Material Collection - -**CRITICAL**: Do NOT proceed to Phase 1 until user source materials are collected. - -**Goal**: Gather the user's own words and their approved external references. - -### Step 0.1: Request User's Original Content - -Ask the user for: -- **Transcripts** of their past talks, meetings, or discussions -- **Articles** they have written or approved -- **Notes** or drafts they have prepared -- **Previous decks** they have delivered -- **Voice memos** or any recorded thoughts - -If none exist, proceed to Phase 1 with the understanding that the entire narrative must be extracted from the user's head through structured conversation. - -### Step 0.2: Gather External References (Optional) - -- Search for relevant external materials (articles, reports, references) -- **Present findings to the user for selection** — do not assume relevance -- Only include materials the user explicitly approves - -### Step 0.3: Organize Source Materials - -Save all source materials to `00-上游/`(根目录或 `source-materials/` 子目录均可): -``` -00-上游/ -├── prompt-最初提示词.txt # 用户原始 prompt(如有) -├── narrative-brief.md # Phase 1 输出 -├── content.md # Phase 2 输出(baoyu 输入) -├── style-instructions.md # 视觉设计 SSOT -├── outline.md # 来自 baoyu-slide-deck -├── source-materials/ # (可选子目录) -│ ├── user-transcript-1.md -│ ├── user-article-2.md -│ ├── user-notes-3.md -│ └── external-ref-4.md (user-approved) -``` - -**Note**: 对于已有项目,源文件可直接放在 `00-上游/` 根目录;新建议项目时可用 `source-materials/` 子目录保持整洁。 - -**Self-check**: Do we have the user's own words? If not, are we prepared to extract everything through conversation? Do NOT invent content. - ---- - -## Phase 1: Narrative Structure Discussion - -**CRITICAL**: Do NOT generate any files in this phase. Only discuss. - -**Goal**: Align on the narrative arc, emotional journey, and slide-level logic before any visual work begins. - -**Principle**: "你不要直接去写,你应该跟我讨论" - -**Input**: Phase 0 source materials. Every insight in this discussion must be grounded in the user's own words or their explicitly approved references. - -### Discussion Framework (ABCDEFG Model) - -| Step | Question | Purpose | -|------|----------|---------| -| A | **Attention** | How do we hook in the first 30 seconds? | -| B | **Benefit** | What's the promised takeaway? | -| C | **Credibility** | Why should the audience trust us? | -| D | **Difference** | What's the contrarian or novel angle? | -| E | **Evidence** | What proof, demo, or story backs this? | -| F | **Framework** | What mental model do we leave them with? | -| G | **Go** | What should they do Monday morning? | - -### Required Inputs - -Ask user if missing: -- **Topic**: What's the talk about? (1 sentence) -- **Audience**: Who's listening? (technical level, role, context) -- **Duration**: How long is the talk? -- **Key messages**: What must they remember? (3 max) -- **Tone**: Educational? Persuasive? Provocative? Inspirational? -- **Existing content**: Articles, transcripts, notes, previous decks? -- **Constraints**: Must-use content? Avoid topics? Brand guidelines? - -### Discussion Checklist - -1. **Opening strategy**: Shock? Story? Question? Demo? -2. **The arc**: Where's the tension? Where's the release? -3. **Transition logic**: How does each slide lead to the next? -4. **The "one thing"**: If they forget everything, what's the ONE thing? -5. **Call to action**: What do they do after the talk? - -### Anti-patterns to Flag - -- ❌ Too many slides for the time (crowded, rushed) -- ❌ Jumping into details without setting context -- ❌ No emotional arc (flat, forgettable) -- ❌ Ending without a clear takeaway -- ❌ Trying to teach too many things at once - -### Validation - -Summarize agreed narrative arc in 3-5 bullet points. Get explicit user confirmation before proceeding to Phase 2. - -**Self-check**: Did we discuss? Or did we jump to generation? If the latter, go back. - ---- - -## Phase 2: Content Structuring - -**Goal**: Produce two SSOT files that baoyu-slide-deck can consume. - -### 2.1 Create `narrative-brief.md` - -Store in `00-上游/`: - -```markdown -# Narrative Brief - -**Topic**: [Topic name] -**Audience**: [description] -**Duration**: [N min] -**Language**: [zh/en/etc] -**Tone**: [educational/persuasive/provocative/inspirational] -**Key Messages**: (3 max) -1. ... -2. ... -3. ... - -## ABCDEFG Arc - -| Step | Answer | -|------|--------| -| A - Attention | ... | -| B - Benefit | ... | -| C - Credibility | ... | -| D - Difference | ... | -| E - Evidence | ... | -| F - Framework | ... | -| G - Go | ... | - -## Slide Count Recommendation - -| Duration | Recommended | Max | -|----------|-------------|-----| -| 10-15 min | 8-12 | 12 | -| 20-30 min | 12-18 | 20 | -| 30-45 min | 15-25 | 28 | -| 45-60 min | 20-30 | 35 | - -**Recommended**: [N] slides for [duration] talk - -## Content Sources - -- [ ] Original user prompt saved -- [ ] Existing articles/notes/transcripts -- [ ] Previous decks - -## Style Direction - -[User's style preference or "to be decided in Phase 3"] -``` - -### 2.2 Create `content.md` (for baoyu-slide-deck) - -Convert narrative brief into baoyu-slide-deck input format: - -```markdown -# [Title] - -## Overview - -[2-3 paragraph summary of the talk content] - -## Key Points - -1. [Point 1] -2. [Point 2] -3. [Point 3] - -## Structure - -### Opening ([duration]) -[Hook content] - -### Section 1: [Name] ([duration]) -[Content] - -### Section 2: [Name] ([duration]) -[Content] - -### Closing ([duration]) -[CTA content] - -## Audience -[Same as narrative-brief] - -## Notes -[Any constraints or special requirements] -``` - -### 2.3 Create `style-instructions.md` (Optional) - -If user has strong style preferences, create this SSOT file in `00-上游/`: - -```markdown - -Design Aesthetic: [Description] - -Background: - Texture: [clean/grid/organic/etc] - Base Color: [#HEX] - -Typography: - Headlines: [Style, size, color, weight] - Body: [Style, size, color, weight] - -Color Palette: - Primary Text: [#HEX] - usage - Body Text: [#HEX] - usage - Background: [#HEX] - Accent 1: [#HEX] - usage - Accent 2: [#HEX] - usage - Accent 3: [#HEX] - usage - -Visual Elements: - - [Element 1] - - [Element 2] - -Density Guidelines: - - Max [N] text elements per slide - - [Other rules] - -Style Rules: - Do: [List] - Don't: [List] - -``` - -**Self-check**: Read narrative-brief.md back to user. Confirm it matches the Phase 1 discussion before proceeding. - -**Content Integrity Check**: Every claim, quote, and example in `content.md` must be traceable to: -1. User's own words (from Phase 0 source materials) -2. User-approved external references -3. User's explicit statements during Phase 1 discussion - -AI must NOT invent facts, quotes, or examples. If the user said it, use it. If they didn't, ask them. If they don't have it, mark it as `[TODO: user to provide]`. - ---- - -## Phase 3: Delegate to baoyu-slide-deck (Prompts) - -**Goal**: Generate outline and prompts using baoyu-slide-deck. - -### Step 3.1: Prepare Input - -Ensure `content.md` is ready. If `style-instructions.md` exists, note the style preference for passing to baoyu-slide-deck. - -### Step 3.2: Call baoyu-slide-deck - -在 Claude Code 中调用 baoyu-slide-deck skill(两种等效方式): - -``` -/baoyu-slide-deck 00-上游/content.md --prompts-only [--style ] -``` - -或直接使用 Skill 工具(当 `/` 命令不可用时): -``` -Skill({"skill": "baoyu-slide-deck", "args": "00-上游/content.md --prompts-only [--style ]"}) -``` - -**Pre-call setup**: -1. **Inject narrative-brief**: Append `narrative-brief.md` (or its ABCDEFG arc section) to the top of `content.md` so baoyu receives the narrative structure, not just raw content. -2. **Inject confirmed choices**: Prepend a metadata block to `content.md` with the already-confirmed choices. This acts as a strong signal for baoyu's auto-detect and reduces the chance of style drift during confirmation: - ```markdown - - - Style: [preset name or custom] - - Audience: [audience from Phase 1] - - Slide count: [N slides for X-min talk] - - Language: [zh/en/etc] - - Review preference: [skip outline / skip prompts / none] - ``` -3. **Style selection**: If user specified a baoyu preset → use it; if custom `style-instructions.md` exists → use `--style custom`; otherwise auto-detect. - -**⚠️ Confirmation overlap warning**: baoyu-slide-deck Step 2 will ask the user to confirm style, audience, slide count, outline review, and prompt review. Since these were already discussed in Phase 1, **instruct the user to stick with the choices we just made** rather than reconsidering. This prevents confirmation fatigue and style drift. - -| User's Description | baoyu Preset | -|-------------------|--------------| -| Flat cartoon, tech explainer | `vector-illustration` or `bold-editorial` | -| Hand-drawn edu, infographic, process | `hand-drawn-edu` | -| Chalkboard, workshop | `chalkboard` or `sketch-notes` | -| Corporate, B2B, investor deck | `corporate` or `minimal` | -| Editorial, magazine, product launch | `bold-editorial` | -| Journalism, explainer, science communication | `editorial-infographic` | -| Dark, gaming, atmospheric | `dark-atmospheric` | -| Retro, pixel, developer talk | `pixel-art` | -| Watercolor, lifestyle, travel | `watercolor` | -| Blueprint, technical, architecture | `blueprint` | -| Academic, research, bilingual | `intuition-machine` | -| Notion, SaaS, product demo | `notion` | -| Story, fantasy, animation | `fantasy-animation` | -| Biology, chemistry, medical | `scientific` | -| History, heritage, vintage | `vintage` | - -### Step 3.3: Post-process Prompts - -After baoyu-slide-deck generates prompts in `prompts/`: - -1. **Copy to user's structure**: Move/copy prompts to `03-prompts/` -2. **Inject custom style**: If `style-instructions.md` exists, ensure FULL content is embedded in every prompt file -3. **Add narrative goal**: Append `// NARRATIVE GOAL` section to each prompt based on `narrative-brief.md` - -Prompt template addition: -```markdown ---- - -## NARRATIVE CONTEXT - -// NARRATIVE GOAL -[What this slide achieves in the talk arc] - -// SPEAKER NOTES -[What the speaker says while this slide is shown] -``` - -**Self-check**: All prompts include full style-instructions.md? Narrative goals added? Files in `03-prompts/`? - ---- - -## Phase 4: Prompt Review (Conditional) - -**Goal**: Human review before image generation. - -**If user wants to review** (recommended): -1. Display prompt summary table -2. Ask user: "Ready to generate images?" -3. If edits needed → user edits `03-prompts/*.md` → regenerate specific prompts via baoyu-slide-deck - -**If user skips review**: Proceed to Phase 5. - ---- - -## Phase 5: Delegate to baoyu-slide-deck (Images) - -**Goal**: Generate slide images. - -### Step 5.1: Call baoyu-slide-deck - -``` -/baoyu-slide-deck . --images-only -``` - -Or using Skill tool: -``` -Skill({"skill": "baoyu-slide-deck", "args": ". --images-only"}) -``` - -**Important**: baoyu-slide-deck expects prompts in a flat `prompts/` directory (its native output structure). If you have already reorganized to `03-prompts/` (Phase 6), create a temporary copy before calling: -```bash -# From the project root (where 03-prompts/ exists) -cp -r 03-prompts prompts -/baoyu-slide-deck . --images-only -rm -rf prompts # clean up after -``` - -**Note on deliverables**: baoyu-slide-deck internally generates `.pptx` and `.pdf` via its own `merge-to-pptx.ts` and `merge-to-pdf.ts` scripts (Step 8 of its workflow). These are the **primary** deliverables — they live in baoyu's flat output directory (`slide-deck/{topic-slug}/`). - -The `scripts/merge_to_pptx.py` and `scripts/merge_to_pdf.py` in slides-creator are **not** duplicates. They serve a different purpose: -- **baoyu merge**: for baoyu's flat directory structure (PNG + prompts at same level) -- **slides-creator merge**: for the reorganized directory structure (`02-slides/` + `03-prompts/`) - -Use slides-creator's merge scripts only after Phase 6 reorganization, or if baoyu's merge step fails. - -### Step 5.2: Visual Verification - -After generation: -1. **Test slide**: Read `01-slide-cover.png` (or first generated slide) -2. **Style check**: Compare against `style-instructions.md` -3. **Text check**: Verify Chinese/English text legibility -4. **If issues**: Update affected `03-prompts/*.md` → copy `cp -r 03-prompts prompts` → regenerate via `/baoyu-slide-deck . --regenerate N` (或 `Skill({"skill": "baoyu-slide-deck", "args": ". --regenerate N"})`) → clean up `rm -rf prompts` - -**Self-check**: All slides generated? Style consistent? Text legible? - ---- - -## Phase 6: Post-processing & Delivery - -**Goal**: Reorganize baoyu-slide-deck output into user's preferred structure. - -### 6.1 Directory Reorganization - -baoyu-slide-deck outputs to `slide-deck/{topic-slug}/`: -``` -slide-deck/{topic-slug}/ -├── source-{slug}.md -├── outline.md -├── prompts/ -├── *.png -├── {topic-slug}.pptx -└── {topic-slug}.pdf -``` - -Reorganize to user's structure: -``` -{project-name}/ -├── 00-上游/ # Source materials -│ ├── prompt-最初提示词.txt # Original user prompt (if saved) -│ ├── narrative-brief.md # Phase 1 output -│ ├── content.md # Phase 2 output (baoyu input) -│ ├── style-instructions.md # Visual design SSOT -│ └── outline.md # From baoyu-slide-deck -├── 01-成品/ # Final deliverables -│ ├── {project-name}.pdf -│ └── {project-name}.pptx -├── 02-slides/ # Generated PNGs (当前版本) -│ ├── 01-slide-cover.png -│ └── ... -├── 03-prompts/ # Per-slide prompts (SSOT) -│ ├── v6/ # 支持版本子目录(如 v6, v7...) -│ │ ├── 01-slide-cover.md -│ │ └── ... -│ └── 01-slide-cover.md # 或平铺结构 -├── speaker-notes.md # Auto-extracted from 03-prompts/ via extract_notes.py -├── v6/ # baoyu-slide-deck 临时输出(需搬迁到 02-slides/) -│ └── ... -└── _archive/ # Historical versions - └── v1/ -``` - -**Note on versioning**: -- `03-prompts/` 支持平铺或版本子目录(`v6/`, `v7/`)。当同一项目多次迭代时,用子目录保留历史版本。 -- baoyu-slide-deck 可能直接输出到项目根目录的临时文件夹(如 `v6/`)。Post-processing 时需将这些 PNG 移动到 `02-slides/`。 - -**Archive current version** (before major iteration): -```bash -uv run scripts/archive_version.py --project /path/to/project -``` -Archives `02-slides/` + `03-prompts/` to `_archive/v{N}/` (auto-incremented). - -### 6.2 Extract Speaker Notes - -Use `scripts/extract_notes.py` to extract structured notes from `03-prompts/*.md`: - -```bash -uv run scripts/extract_notes.py --prompts 03-prompts --output speaker-notes.md -``` - -Extracts: -- `// NARRATIVE GOAL` sections -- `// SPEAKER NOTES` sections -- Falls back to `// KEY CONTENT` if neither found - -Output format (`speaker-notes.md`): -```markdown -# Speaker Notes - -## 01-slide-cover -**Narrative Goal**: ... -**Speaker Notes**: ... - -## 02-slide-intro -... -``` - -**Note**: `main.ts` auto-runs this step if `03-prompts/` exists. - -### 6.3 Archive Original Prompt - -If user provided an original prompt (like the 35KB prompt for 龙虾 vs Claude Code): -- Save as `00-上游/prompt-最初提示词.txt` - -### 6.4 Final Verification Checklist - -- [ ] PDF opens and all slides render correctly -- [ ] PPTX opens without errors -- [ ] PNG sequence numbered correctly (01, 02, ...) -- [ ] Speaker notes cover all slides -- [ ] Style consistent across all slides -- [ ] No garbled or missing text -- [ ] `00-上游/` contains all source SSOT files -- [ ] `03-prompts/` contains all prompt files - ---- - -## Iteration Workflow - -### Path A: Content Changes -``` -User feedback → Update narrative-brief.md → Update content.md -→ Regenerate prompts (/baoyu-slide-deck content.md --prompts-only) -→ Regenerate images (/baoyu-slide-deck . --images-only) -→ Reorganize + extract notes -``` - -### Path B: Style Changes -``` -User feedback → Update style-instructions.md -→ Update all prompts (inject new style into 03-prompts/*.md) -→ Regenerate all images (via /baoyu-slide-deck . --images-only) -→ Reorganize + extract notes -``` - -### Path C: Single Slide Fix -``` -User feedback → Update 03-prompts/NN-slide-xxx.md -→ Copy prompts: cp -r 03-prompts prompts -→ /baoyu-slide-deck . --regenerate N -→ Clean up: rm -rf prompts -→ Replace in 02-slides/ -→ Regenerate PPTX/PDF -``` - -**Note on `--regenerate`**: baoyu-slide-deck reads from flat `prompts/` directory. After reorganization to `03-prompts/`, create a temporary copy (`cp -r 03-prompts prompts`) before regenerating. If you haven't reorganized yet (still in baoyu's flat structure), call directly without copying. - ---- - -## Script Reference - -| Script | Purpose | -|--------|---------| -| `scripts/main.ts` | Post-processing: validate + extract notes + generate PDF/PPTX | -| `scripts/merge_to_pptx.py` | Merge PNGs to PPTX with structured speaker notes from `03-prompts/*.md` | -| `scripts/merge_to_pdf.py` | Merge PNGs to PDF (reorganized `02-slides/` structure) | -| `scripts/validate_slides.py` | Check aspect ratio, naming, missing slides | -| `scripts/extract_notes.py` | Extract structured speaker notes from `03-prompts/*.md` to `speaker-notes.md` | -| `scripts/archive_version.py` | Archive `02-slides/` + `03-prompts/` to `_archive/v{N}/` | - ---- - -## Failure Log (Do NOT Repeat) - -| Failure | Root Cause | Prevention | -|---------|-----------|------------| -| **AI wrote content for the user — polished garbage** | Violated First Law: skipped Phase 0, fabricated quotes/examples. See `references/content-creation-first-law.md` | **First Law is absolute**: collect user's words FIRST. No source material = STOP and ask. AI assists expression, never replaces it | -| Generated 30 slides for 20-min talk | Didn't enforce slide count guide | Check duration ÷ 2 = max slides | -| Style drift between versions | Style instructions not in prompts | Paste FULL style-instructions.md into every prompt | -| Text unreadable in images | Model doesn't support Chinese well | Test with Chinese text first | -| Narrative arc flat | Jumped to prompts without Phase 1 | ALWAYS discuss narrative first | -| User unhappy with first draft | Didn't confirm before batch | Generate ONE test slide, get approval | -| Directory mess | Didn't use consistent structure | Always use 00-上游/01-成品/02-slides/03-prompts | -| Redundant work | Tried to replace baoyu-slide-deck | Delegate visual generation, focus on narrative | -| Merge scripts questioned as duplicates | Baoyu merge scripts exist but: (1) path unstable (`~/.claude/plugins/...`); (2) expect flat `prompts/` dir; (3) inject full base prompt as notes noise | Keep own merge scripts for reorganized structure. Validate before deleting — call baoyu merge first if accessible | - ---- - -## References - -- `references/content-creation-first-law.md` — Universal principle: user's voice is primary, applies to all content types (slides, articles, ads, courses) -- `references/narrative-design-guide.md` — ABCDEFG model detailed guide -- `references/prompt-templates/` — Prompt templates for common slide types -- `references/style-gallery.md` — Visual style gallery with examples +碎片化(5 个 PPT 工具)已造成真实路由失败:agent 只知部分候选时给出了被客户否决过的方案。 +本 skill 的 First Law 与目录治理仍是 deck-creator Route A 的核心——能力没有消失,是搬了家。