Academic Presentation Generation
SkillDocs & knowledgeGenerate academic PowerPoint presentations (.pptx) using python-pptx. Use this skill for making PPT, slides, presentations, 生成PPT, 做PPT, 写PPT, 幻灯片. Provides complete helper functions and templates. Preferred over scientific-slides and frontend-slides for all PPTX generation.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Academic Presentation Generation skill
What this skill tells your AI
The instructions your AI receives, as published by zaoqu-liu/scienceclaw in skills/pptx-generation/SKILL.md and read by ahel’s review.
Overview
Create publication-quality academic presentations (.pptx) for group meetings, thesis defenses, conference talks, and product introductions.
Templates
Group Meeting (10-15 slides)
- Title slide (project name, date, presenter)
- Background / Context (1-2 slides)
- This Week's Progress (3-5 slides)
- Results & Figures (2-3 slides)
- Challenges / Questions (1 slide)
- Next Steps (1 slide)
Thesis Defense (30-50 slides)
- Title → 2. Outline → 3. Background (5-8) → 4. Aims (1-2) → 5-7. Aim chapters (8-12 each) → 8. Discussion (2-3) → 9. Conclusions (1-2) → 10. Future → 11. Acknowledgments → 12. Backup
Conference Talk (12-20 slides, 10-15 min)
- Title → 2. Problem → 3. Key Question → 4. Approach → 5-9. Results → 10. Implications → 11. Acknowledgments
Product / Project Introduction (10-15 slides)
- Title → 2. Problem → 3. Solution → 4. Architecture → 5-8. Core features → 9-10. Case studies → 11. Comparison → 12. Quick start → 13. Roadmap → 14. Summary
Design Principles
- One message per slide: two messages → two slides
- Visual hierarchy: title → key message → supporting data → source
- Minimal text: bullet points, not paragraphs
- Figure-first: lead with figures, explain verbally
- Consistent styling: same fonts, colors, layout throughout
Technical Implementation
Dependencies
pip install -q python-pptx Pillow
CRITICAL: Execution Pattern
ALWAYS write the ENTIRE script FIRST, then run it. NEVER send text before running the script.
The script MUST be self-contained. Install deps, define helpers, build slides, save — all in ONE bash call:
pip install -q python-pptx Pillow 2>/dev/null && python3 << 'PPTXEOF'
# === FULL SCRIPT HERE (see template below) ===
PPTXEOF
Color Themes
Academic palettes — pick ONE and use consistently:
THEMES = {
"lancet": {
"primary": (0x00, 0x46, 0x8B),
"accent": (0xED, 0x00, 0x00),
"accent2": (0x42, 0xB5, 0x40),
"light": (0xE8, 0xEE, 0xF4),
"text": (0x33, 0x33, 0x33),
"muted": (0x88, 0x88, 0x88),
},
"npg": {
"primary": (0x3C, 0x54, 0x88),
"accent": (0xE6, 0x4B, 0x35),
"accent2": (0x00, 0xA0, 0x87),
"light": (0xEE, 0xF0, 0xF5),
"text": (0x33, 0x33, 0x33),
"muted": (0x84, 0x91, 0xB4),
},
"nejm": {
"primary": (0x00, 0x72, 0xB5),
"accent": (0xBC, 0x3C, 0x29),
"accent2": (0x20, 0x85, 0x4E),
"light": (0xE6, 0xF0, 0xF8),
"text": (0x33, 0x33, 0x33),
"muted": (0x6F, 0x99, 0xAD),
},
}
Complete Template Script
Copy this entire template. Fill in the SLIDES list with actual content. Do not restructure the helpers — just fill in content.
from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.dml.color import RGBColor
import os
# --- CONFIG ---
OUTPUT_DIR = os.path.expanduser("~/.scienceclaw/workspace")
os.makedirs(OUTPUT_DIR, exist_ok=True)
FILENAME = "presentation.pptx" # <-- change this
OUTPUT_PATH = os.path.join(OUTPUT_DIR, FILENAME)
THEME = "lancet" # lancet | npg | nejm
T = {
"lancet": {"p":(0,70,139),"a":(237,0,0),"a2":(66,181,64),"l":(232,238,244),"t":(51,51,51),"m":(136,136,136)},
"npg": {"p":(60,84,136),"a":(230,75,53),"a2":(0,160,135),"l":(238,240,245),"t":(51,51,51),"m":(132,145,180)},
"nejm": {"p":(0,114,181),"a":(188,60,41),"a2":(32,133,78),"l":(230,240,248),"t":(51,51,51),"m":(111,153,173)},
}[THEME]
def rgb(key): return RGBColor(*T[key])
prs = Presentation()
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)
W, H = prs.slide_width, prs.slide_height
def add_shape(slide, left, top, w, h, fill=None):
s = slide.shapes.add_shape(1, left, top, w, h)
s.line.fill.background()
if fill: s.fill.solid(); s.fill.fore_color.rgb = RGBColor(*fill)
else: s.fill.background()
return s
def add_text(slide, left, top, w, h, text, size=18, bold=False, color="t", align=PP_ALIGN.LEFT, anchor=MSO_ANCHOR.TOP):
box = slide.shapes.add_textbox(left, top, w, h)
box.text_frame.word_wrap = True
p = box.text_frame.paragraphs[0]
p.text = text
p.font.size = Pt(size)
p.font.bold = bold
p.font.color.rgb = rgb(color)
p.alignment = align
box.text_frame.paragraphs[0].space_after = Pt(4)
return box
def add_bullets(slide, left, top, w, h, items, size=16, color="t"):
box = slide.shapes.add_textbox(left, top, w, h)
tf = box.text_frame
tf.word_wrap = True
for i, item in enumerate(items):
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
p.text = item
p.font.size = Pt(size)
p.font.color.rgb = rgb(color)
p.space_after = Pt(8)
p.level = 0
return box
def title_slide(title, subtitle="", presenter=""):
s = prs.slides.add_slide(prs.slide_layouts[6])
add_shape(s, 0, 0, W, H, fill=T["p"])
add_shape(s, 0, Inches(5.2), W, Inches(2.3), fill=(max(0,T["p"][0]-20), max(0,T["p"][1]-20), max(0,T["p"][2]-20)))
add_text(s, Inches(1), Inches(1.8), Inches(11), Inches(2), title, size=40, bold=True, color="l", align=PP_ALIGN.LEFT)
if subtitle:
add_text(s, Inches(1), Inches(3.8), Inches(11), Inches(1), subtitle, size=22, color="l")
if presenter:
add_text(s, Inches(1), Inches(5.6), Inches(11), Inches(0.8), presenter, size=16, color="l")
return s
def section_slide(title):
s = prs.slides.add_slide(prs.slide_layouts[6])
add_shape(s, 0, 0, W, H, fill=T["l"])
add_shape(s, Inches(0.8), Inches(3.2), Inches(2), Pt(4), fill=T["p"])
add_text(s, Inches(0.8), Inches(1.8), Inches(11), Inches(1.5), title, size=36, bold=True, color="p")
return s
def content_slide(title, bullets, note=""):
s = prs.slides.add_slide(prs.slide_layouts[6])
add_shape(s, 0, 0, W, Inches(0.06), fill=T["p"])
add_text(s, Inches(0.8), Inches(0.4), Inches(11), Inches(1), title, size=28, bold=True, color="p")
add_shape(s, Inches(0.8), Inches(1.3), Inches(2), Pt(3), fill=T["a"])
add_bullets(s, Inches(0.8), Inches(1.6), Inches(11), Inches(4.8), bullets, size=18)
if note:
add_text(s, Inches(0.8), Inches(6.5), Inches(11), Inches(0.6), note, size=12, color="m")
return s
def two_col_slide(title, left_items, right_items, left_title="", right_title=""):
s = prs.slides.add_slide(prs.slide_layouts[6])
add_shape(s, 0, 0, W, Inches(0.06), fill=T["p"])
add_text(s, Inches(0.8), Inches(0.4), Inches(11), Inches(1), title, size=28, bold=True, color="p")
add_shape(s, Inches(0.8), Inches(1.3), Inches(2), Pt(3), fill=T["a"])
if left_title:
add_text(s, Inches(0.8), Inches(1.6), Inches(5.2), Inches(0.5), left_title, size=20, bold=True, color="p")
add_bullets(s, Inches(0.8), Inches(2.2), Inches(5.2), Inches(4.2), left_items, size=16)
if right_title:
add_text(s, Inches(7), Inches(1.6), Inches(5.2), Inches(0.5), right_title, size=20, bold=True, color="p")
add_bullets(s, Inches(7), Inches(2.2), Inches(5.2), Inches(4.2), right_items, size=16)
return s
def table_slide(title, headers, rows):
s = prs.slides.add_slide(prs.slide_layouts[6])
add_shape(s, 0, 0, W, Inches(0.06), fill=T["p"])
add_text(s, Inches(0.8), Inches(0.4), Inches(11), Inches(1), title, size=28, bold=True, color="p")
add_shape(s, Inches(0.8), Inches(1.3), Inches(2), Pt(3), fill=T["a"])
cols = len(headers)
tbl = s.shapes.add_table(len(rows)+1, cols, Inches(0.8), Inches(1.8), Inches(11.5), Inches(4.5)).table
for j, h in enumerate(headers):
c = tbl.cell(0, j); c.text = h
for p in c.text_frame.paragraphs:
p.font.size = Pt(14); p.font.bold = True; p.font.color.rgb = RGBColor(255,255,255)
c.fill.solid(); c.fill.fore_color.rgb = rgb("p")
for i, row in enumerate(rows):
for j, val in enumerate(row):
c = tbl.cell(i+1, j); c.text = str(val)
for p in c.text_frame.paragraphs:
p.font.size = Pt(13); p.font.color.rgb = rgb("t")
c.fill.solid(); c.fill.fore_color.rgb = RGBColor(*(T["l"] if i%2==0 else (255,255,255)))
return s
def end_slide(title, items=None):
s = prs.slides.add_slide(prs.slide_layouts[6])
add_shape(s, 0, 0, W, H, fill=T["p"])
add_text(s, Inches(1), Inches(2.5), Inches(11), Inches(2), title, size=36, bold=True, color="l", align=PP_ALIGN.CENTER)
if items:
add_bullets(s, Inches(2), Inches(4.2), Inches(9), Inches(2), items, size=18, color="l")
return s
# ============================================================
# FILL IN SLIDES BELOW — use the helpers above
# ============================================================
title_slide(
"Your Title Here",
subtitle="Subtitle line",
presenter="Author · Institution · Date",
)
content_slide("Slide Title", [
"• Bullet point one",
"• Bullet point two",
"• Bullet point three",
])
# ... add more slides using the helpers ...
end_slide("Thank You", ["contact@example.com"])
# ============================================================
# SAVE
# ============================================================
prs.save(OUTPUT_PATH)
print(f"DONE: {OUTPUT_PATH} ({len(prs.slides)} slides)")
Output Convention
- Save to
~/.scienceclaw/workspace/<descriptive-name>.pptx - Print the absolute path and slide count on success
- If the script fails, print the traceback — do NOT silently swallow errors
Error Handling
- If
python-pptxfails to install: tell the user to runpip install python-pptxon the host - If script errors: read traceback, fix, re-run (max 3 attempts)
- After success: verify the file exists and has non-zero size before telling the user
Language & Content Rules
- Match the user's language. If user writes in Chinese, all slide content must be Chinese.
- Keep bullet points to 3-5 per slide, 6-10 words per bullet.
- Use the academic palette consistently.
- The model decides which helper to use for each slide (title_slide, content_slide, two_col_slide, table_slide, section_slide, end_slide).
Signals
- GitHub stars
- 60
- Forks
- 14
- Last commit
- Mar 2026
ahel review
K1binfo
installs-packages
Automated review, not a security audit. Ruleset v1+k2.
Advanced
- Catalog kind
- skill
- Gateway key
pptx-generation- Source
- github.com/zaoqu-liu/scienceclaw