Ten self-contained presentation tasks that probe how well a model creates and edits .pptx files β from a simple title slide to multi-slide decks with tables, charts, images, icons, custom layouts, speaker notes, and XML-based slide editing. Each task has a copy-paste prompt, a verify command, and clear pass criteria.
These tasks test the pptx skill β the model's ability to produce well-structured, visually coherent presentations using PptxGenJS. Tasks 1β4 cover basic slides (title, bullets, tables, images). Tasks 5β10 add charts, shapes, icons, speaker notes, and the unpack-edit-repack workflow. All tasks produce Node.js scripts using pptxgenjs. Start at Task 1 and work up.
These tasks use PptxGenJS for creating presentations from scratch and the project's PPTX scripts for unpacking, editing, and verifying. Knowing these conventions helps you evaluate whether the model followed the skill correctly.
| Concept | Rule | Why |
|---|---|---|
| No "#" in colors | Use "FF0000", not "#FF0000" | Hash prefix corrupts the file |
| No 8-char hex | Never encode opacity in color strings | Use opacity property instead |
| Bullets | Use bullet: true in rich text array | Unicode bullets create double bullets |
| breakLine | Required between rich text array items | Last item doesn't need it |
| Layout | Set explicitly: LAYOUT_16x9 (default) | Consistent aspect ratio |
| Icons | react-icons β sharp rasterize β base64 PNG | Universal compatibility |
| Charts | slide.addChart(pres.charts.BAR, ...) | Built-in PptxGenJS chart types |
| Images | path, data (base64), or url | Use sizing for fit/cover/crop |
| Verify | node scripts/verify.js output.pptx | Checks structure, slides, placeholders |
| Read | node scripts/read.js output.pptx | Extracts text for content review |
| Editing | unpack β edit XML β clean β pack | Use add_slide.js to duplicate |
You need one terminal with the Aperio server running on your preferred AI provider. Paste each task prompt into the chat (web UI or CLI).
npm run start:local # or any AI_PROVIDER, port 31337
Paste each task's prompt into the chat. Use a fresh conversation per task when possible. The model will write a PptxGenJS script and run it to produce the .pptx file. After it completes, run the Verify command.
The verify commands use the project's own skills/pptx/scripts/verify.js for structural validation and Python 3 (stdlib zipfile) for XML inspection. PptxGenJS scripts run as Node.js scripts inside the session workspace and trash/ directory.
If you want to re-run tasks against a different model, clean up the output files first:
rm -f trash/test-*.pptx
rm -f trash/create-*.js
Ordered by complexity: simple slides first (title, bullets, tables, images), then multi-slide decks, charts, shapes, icons, speaker notes, and finally the unpack-edit-repack XML editing workflow. Each task lists difficulty, what to look for, the prompt to paste, and the verify command.
Probes: PptxGenJS script structure, text positioning, layout setting
Files:1 script + 1 output (trash/create-title.js β trash/test-title.pptx)
trash/create-title.js that creates trash/test-title.pptx with a single title slide:
- Layout: 16x9
- Title: "Aperio β Personal Memory Layer for AI Agents" (centered, bold, 36pt, dark navy color "1A2744")
- Subtitle: "One brain. Every agent. Nothing forgotten." (centered, 18pt, gray "64748B")
- A thin accent line (a RECTANGLE shape, 2" wide, 0.04" tall, color "7C3AED") centered below the title
- Background: white ("FFFFFF")
Use require("pptxgenjs") (CommonJS). Save with writeFile. Print the output path to console. No "#" in hex colors.node skills/pptx/scripts/verify.js trash/test-title.pptxnode -e "require('skills/pptx/scripts/read')('trash/test-title.pptx').then(t=>{const hasAperio=t.toLowerCase().includes('aperio');const hasMemory=t.toLowerCase().includes('memory');console.log('Contains Aperio:',hasAperio,'Contains Memory:',hasMemory);process.exit(hasAperio&&hasMemory?0:1)})"Probes: rich text arrays, bullet: true, breakLine, no unicode bullets
Files:1 script + 1 output (trash/create-bullets.js β trash/test-bullets.pptx)
trash/create-bullets.js that creates trash/test-bullets.pptx with 3 slides:
Slide 1 β "Why Memory Matters"
- Title at top: "Why Memory Matters" (24pt, bold)
- 5 bullet points about AI memory (Context window limits, Session isolation, Knowledge persistence, Cross-agent sharing, Personalization)
- Use bullet: true and breakLine: true in a rich text array β do NOT use unicode bullet characters
- Title font: Arial, body: Arial 16pt, dark gray "374151"
Slide 2 β "Key Features"
- Title: "Key Features" (same style)
- 4 bullet points (MCP Integration, Multi-Provider, Code Graph, Vector Search)
- Same bullet style
Slide 3 β "Getting Started"
- Title: "Getting Started"
- A numbered list (use bullet: { type: "number" }) with 4 setup steps
- Body font: Arial 16pt
Layout: 16x9. Background: white. No "#" in colors. Use require("pptxgenjs").bullet: true, not unicode characters?node skills/pptx/scripts/verify.js trash/test-bullets.pptxpython3 -c "from zipfile import ZipFile; z=ZipFile('trash/test-bullets.pptx'); xml=z.read('ppt/slides/slide1.xml').decode(); import re; bullet_refs=len(re.findall(r'Probes: addTable, header styling, cell formatting
Files:1 script + 1 output (trash/create-table.js β trash/test-table.pptx)
trash/create-table.js that creates trash/test-table.pptx with:
Slide 1 β Title: "Q4 Performance Metrics" (bold, 24pt, centered)
Slide 2 β Data table:
- A table with 4 columns: Product, Revenue ($), Growth (%), Market Share (%)
- 6 data rows with realistic SaaS metrics
- Header row: dark blue fill ("1E3A5F"), white bold text
- Data rows: alternating light gray ("F8F9FA") and white fills
- Font: Arial 14pt body, 16pt header
- Table positioned centered on the slide with appropriate width (~8")
- Border style: thin gray lines
Slide 3 β Key Takeaways
- Title: "Key Takeaways"
- 3 bullet points summarizing the data (highest growth product, market leader, etc.)
Layout: 16x9. No "#" in colors. Use require("pptxgenjs").node skills/pptx/scripts/verify.js trash/test-table.pptxpython3 -c "from zipfile import ZipFile; z=ZipFile('trash/test-table.pptx'); xml=z.read('ppt/slides/slide2.xml').decode(); tbl=xml.count('=1 and rows>=6, 'Need table with >=6 rows'; print('OK β table with 6+ rows')" Probes: addImage, file path loading, sizing, alt text
Files:1 script + 1 output (trash/create-image.js β trash/test-image.pptx)
trash/create-image.js that creates trash/test-image.pptx with:
Slide 1 β Title: "Our Technology Stack" (centered, 28pt, bold)
Slide 2 β Image showcase:
- Load public/assets/aperio-logo.png (or any PNG in public/assets/) using fs.readFileSync
- Display it centered on the slide with addImage using sizing: { type: 'contain', w: 6, h: 3 }
- Below the image: caption text "Reference Architecture" in italic, 12pt, centered, gray "6B7280"
- Use altText on the image for accessibility
Slide 3 β "Image Details"
- 2 bullet points: the image source path and its format
- Smaller inset version of the same image in the bottom-right corner (2" Γ 1.5")
Layout: 16x9. Arial font. No "#" in colors. Use require("pptxgenjs").altText specified on the image?node skills/pptx/scripts/verify.js trash/test-image.pptxpython3 -c "from zipfile import ZipFile; z=ZipFile('trash/test-image.pptx'); files=z.namelist(); media=[f for f in files if 'media' in f]; rels=z.read('ppt/slides/_rels/slide2.xml.rels').decode(); has_image='image/' in rels; print('Media files:',len(media),'Image rel:',has_image); assert len(media)>=1 and has_image, 'Need media and image rel'; print('OK β image embedded')"Probes: multi-slide structure, varied layouts, theme application
Files:1 script + 1 output (trash/create-pitch.js β trash/test-pitch.pptx)
trash/create-pitch.js that creates a 5-slide pitch deck at trash/test-pitch.pptx. Use a consistent color theme: dark navy ("1A2744") for headers, purple ("7C3AED") for accents, dark gray ("374151") for body text.
Slide 1 β Title: "Aperio" (36pt, bold, centered) + subtitle "The Memory Layer for AI Agents" + a thin purple accent line
Slide 2 β "The Problem": title (24pt, bold) + 4 bullet points about AI session isolation and context limits
Slide 3 β "Our Solution": title + 3 content blocks laid out horizontally (use RECTANGLE shapes as cards with text inside each): "Persistent Memory", "MCP Integration", "Multi-Provider". Each card should have a light purple fill ("EDE9FE"), 16pt dark text, and be positioned side by side.
Slide 4 β "Architecture": title + text explaining the stack (SQLite/Postgres + Embeddings + AI Providers) + a simple visual: 3 rectangles stacked vertically with connecting text
Slide 5 β "Get Started": title + 4 numbered steps (git clone, npm install, configure, run) + footer text "aperio.dev" in italic
Layout: 16x9. Background: white. No "#" in colors. Use require("pptxgenjs").node skills/pptx/scripts/verify.js trash/test-pitch.pptxnode -e "require('skills/pptx/scripts/read')('trash/test-pitch.pptx').then(t=>{const slides=t.split('Slide').length-1;console.log('Slides:',slides);process.exit(slides>=5?0:1)})"Probes: addChart, chart options, data series, modern styling
Files:1 script + 1 output (trash/create-chart.js β trash/test-chart.pptx)
trash/create-chart.js that creates trash/test-chart.pptx with:
Slide 1 β "Q1 2026 Performance" (title)
Slide 2 β Bar chart:
- Use pres.charts.BAR with barDir "col"
- 3 series: Revenue, Costs, Profit over 4 quarters
- Modern styling: custom chart colors ("7C3AED", "10B981", "F59E0B"), white chart area, rounded corners, muted axis labels, subtle grid lines, data labels on bars, no legend for single-series, show title "Quarterly Performance ($K)"
- Position: covering most of the slide area
Slide 3 β Pie chart:
- Use pres.charts.PIE showing expense breakdown (4 categories)
- Show percentages with showPercent: true
- Custom colors matching the theme
Slide 4 β Key insights as bullet points
Layout: 16x9. No "#" in colors. Use require("pptxgenjs").node skills/pptx/scripts/verify.js trash/test-chart.pptxpython3 -c "from zipfile import ZipFile; z=ZipFile('trash/test-chart.pptx'); charts=[f for f in z.namelist() if 'chart' in f.lower()]; print('Chart XML files:',charts); assert len(charts)>=2, 'Need >=2 chart definitions'; print('OK β charts present')"Probes: addShape, rectangles, ovals, lines, alignment, visual composition
Files:1 script + 1 output (trash/create-shapes.js β trash/test-shapes.pptx)
trash/create-shapes.js that creates trash/test-shapes.pptx with a visual process diagram using shapes:
Slide 1 β "How Aperio Works" (title, 28pt)
Slide 2 β Process flow diagram:
- 3 rounded rectangles (use ROUNDED_RECTANGLE with rectRadius 0.15) arranged horizontally: "Input" β "Process" β "Store"
- Each rectangle: 2.5" wide, 1.5" tall, purple fill ("7C3AED") with white bold text
- Arrows between them: use LINE shapes (triangle arrow or just small right-pointing triangles / chevrons)
- Below: 3 OVAL shapes as bullet markers, each with a short label text below
- A horizontal LINE separator (full width, thin, gray "D1D5DB") between the top diagram and bottom section
Slide 3 β "Architecture Layers"
- 4 stacked RECTANGLE shapes representing layers: UI Layer, API Layer, Memory Store, Vector Index
- Different subtle fill colors for each layer ("EDE9FE", "DBEAFE", "D1FAE5", "FEF3C7")
- Each has white bold text with the layer name
- All same width (7") with small gaps between them
Layout: 16x9. No "#" in colors. Use require("pptxgenjs").node skills/pptx/scripts/verify.js trash/test-shapes.pptxpython3 -c "from zipfile import ZipFile; z=ZipFile('trash/test-shapes.pptx'); s2=z.read('ppt/slides/slide2.xml').decode(); s3=z.read('ppt/slides/slide3.xml').decode(); shapes2=s2.count(''); shapes3=s3.count(''); print('Shapes slide2:',shapes2,'slide3:',shapes3); assert shapes2>=6 and shapes3>=4, 'Need shapes on both slides'; print('OK β shapes present')" Probes: react-icons, sharp rasterization, base64 PNG embedding
Files:1 script + 1 output (trash/create-icons.js β trash/test-icons.pptx)
trash/create-icons.js that creates trash/test-icons.pptx with icon-enhanced slides:
Slide 1 β "Key Capabilities" (title, 28pt, bold)
Slide 2 β Feature grid with icons:
Create 4 feature cards arranged in a 2Γ2 grid. Each card is a RECTANGLE shape (light gray fill "F9FAFB") containing:
- An icon from react-icons (use react-icons/fi or react-icons/fa) rasterized to a base64 PNG via sharp
- A bold label below the icon
- A short description text
- Icon-to-PNG: renderIconSvg(IconComponent, color, size) β sharp β base64 PNG β addImage(data)
Suggested icons and features:
- FiDatabase β "Persistent Memory"
- FiLink β "MCP Integration"
- FiCode β "Code Graph"
- FiSearch β "Vector Search"
Slide 3 β Summary: Title "Built for Extensibility" with 3 bullet points
Layout: 16x9. Icon color: purple "7C3AED". Icon size: 0.5" Γ 0.5". Cards evenly spaced. No "#" in colors.node skills/pptx/scripts/verify.js trash/test-icons.pptxpython3 -c "from zipfile import ZipFile; z=ZipFile('trash/test-icons.pptx'); media=[f for f in z.namelist() if 'media' in f]; s2=z.read('ppt/slides/slide2.xml').decode(); images=s2.count('=4 and images>=4, 'Need >=4 images and blipFills'; print('OK β embedded icons' )" Probes: addNotes, notes XML structure, per-slide notes content
Files:1 script + 1 output (trash/create-notes.js β trash/test-notes.pptx)
trash/create-notes.js that creates trash/test-notes.pptx β a 3-slide deck where each slide has speaker notes:
Slide 1 β "Introduction" (title slide)
- Bold title "Aperio Overview", subtitle "Personal Memory for AI"
- Speaker note: "Start by asking the audience how many have experienced losing context with their AI assistant. This sets up the pain point."
Slide 2 β "Core Architecture"
- Title: "Core Architecture"
- 3 bullet points about the tech stack
- Speaker note: "Emphasize the pluggable backend β SQLite for single users, Postgres for teams. Mention the MCP integration point."
Slide 3 β "Roadmap"
- Title: "Roadmap & Next Steps"
- 4 bullet points (Q1-Q4 milestones)
- Speaker note: "For Q3, the focus is on multi-agent memory sync. We're also exploring a hosted option. Open for questions at the end."
Use slide.addNotes("...") to attach notes to each slide. Layout: 16x9. No "#" in colors.node skills/pptx/scripts/verify.js trash/test-notes.pptxpython3 -c "from zipfile import ZipFile; z=ZipFile('trash/test-notes.pptx'); notes=[f for f in z.namelist() if 'notesSlide' in f]; print('Notes files:',notes); assert len(notes)>=3, 'Need >=3 notes slides'; for n in notes: xml=z.read(n).decode(); assert 'context' in xml.lower() or 'slide' in xml.lower() or len(xml)>500, f'{n} seems empty'; print('OK β speaker notes present on all slides')"Probes: unpack workflow, XML editing, slide manipulation, pack workflow
Files:Source + output (create trash/test-source.pptx first β edit β trash/test-edited.pptx)
trash/test-source.pptx with 4 slides:
- Slide 1: Title "Quarterly Review" + subtitle "Q4 2025"
- Slide 2: "Financial Summary" with a table (3 columns Γ 4 rows)
- Slide 3: "Key Metrics" with 4 bullet points
- Slide 4: "Next Steps" with 3 bullet points
Step 2 β Unpack
Run: node skills/pptx/scripts/unpack.js trash/test-source.pptx trash/test-unpacked
Step 3 β Edit XML
Edit trash/test-unpacked/ppt/slides/slide1.xml to change the title from "Quarterly Review" to "Annual Review 2025" (find and replace the text content).
Step 4 β Reorder slides
Edit trash/test-unpacked/ppt/presentation.xml to move the last slide (Next Steps) to the second position. Adjust the order in <p:sldIdLst>.
Step 5 β Clean & Pack
Run: node skills/pptx/scripts/clean.js trash/test-unpacked
Then: node skills/pptx/scripts/pack.js trash/test-unpacked trash/test-edited.pptx
Verify with node skills/pptx/scripts/verify.js trash/test-edited.pptx and node skills/pptx/scripts/read.js trash/test-edited.pptx to confirm the title change and reorder.verify.js pass on the output?node skills/pptx/scripts/verify.js trash/test-edited.pptxnode -e "require('skills/pptx/scripts/read')('trash/test-edited.pptx').then(t=>{const hasAnnual=t.includes('Annual');const slide2=t.split('Slide')[3]||'';const hasNextSteps=slide2.includes('Next Steps');console.log('Contains Annual:',hasAnnual,'Slide 2 is Next Steps:',hasNextSteps);process.exit(hasAnnual&&hasNextSteps?0:1)})"Apply these five signals to each task after running the verify command. They measure not just "does the file exist" but also "did the model follow the skill's conventions and verify its own work".
| Signal | 0 = fail | 1 = pass |
|---|---|---|
| File created at correct path | wrong path / wrong format / script error | correct trash/test-*.pptx |
| Verify command passes | verify.js reports errors, placeholders > 0, or missing file | green with expected slide count |
| Follows PPTX conventions | "#" in hex colors, unicode bullets, 8-char hex with opacity | clean colors, proper bullets, correct opacity |
| Uses correct API for the task | wrong chart type, no ImageRun type, missing breakLine | correct PptxGenJS API per task |
| Model verified its own work | claimed "looks good" without verify.js | ran verify.js and fixed issues found |
Results fill in automatically as you click the buttons above.
| Test | Result | Notes |
|---|---|---|
| 1. Title Slide | β | |
| 2. Bulleted Content Slides | β | |
| 3. Data Table Slide | β | |
| 4. Image Slide | β | |
| 5. Multi-Slide Pitch Deck | β | |
| 6. Charts (Bar + Pie) | β | |
| 7. Visual Layout with Shapes | β | |
| 8. Rendered Icons (react-icons) | β | |
| 9. Speaker Notes | β | |
| 10. XML Editing (UnpackβEditβRepack) | β | |
| TOTAL: ____ / 10 passed | ||
react-icons, react, react-dom, sharp. Install with npm install react-icons react react-dom sharp..pptx files.The task order traces a curve from shallow to deep presentation-creation understanding:
title slide (1) β bulleted content (2) β data tables (3) β embedded images (4) β multi-slide deck (5) β charts (6) β shapes & layout (7) β react-icons rasterization (8) β speaker notes (9) β XML editing pipeline (10)
A model that drops off after Task 4 can create basic slides but not multi-slide structure. One that drops off after Task 7 can build visual decks but not icons or editing. A model that passes all 10 understands the full presentation-creation stack.