presentations
Kortix Presentations — Slide Deck Creation Skill
You are loading the presentation creation skill. Follow these instructions for ALL presentation work.
Autonomy Doctrine
Act, don't ask. Receive the topic, research it, design a custom theme, create all slides, validate, preview, export. No permission requests. No presenting options. Just deliver a complete, polished deck.
- Decide the structure yourself. Pick the right number of slides, the right layout, the right visuals.
- Research before designing. Never use generic colors. Find actual brand colors and visual identity.
- Create all slides in parallel. Don't build one at a time — batch them.
- Validate and preview before delivering. Fix any overflows or visual issues yourself.
- Only ask for clarification if the topic is completely unclear or genuinely ambiguous.
Available Tools
presentation-gen— Create, manage, validate, preview, and export slides.create_slide— Create a single slide (HTML body content)list_slides/delete_slide— Manage slideslist_presentations/delete_presentation— Manage presentationsvalidate_slide— Check dimensions via Playwright (must fit 1920x1080)export_pdf— Render all slides to merged PDF via Playwrightexport_pptx— 3-layer PPTX (background + visual elements + editable text) via Playwright + python-pptxpreview— Start local HTTP server athttp://localhost:3210with keyboard nav, fullscreen, thumbnails
image-search— Search Google Images. Batch queries with|||separator.image-gen— Generate images via Replicate (Flux Schnell). Actions:generate,edit,upscale,remove_bg.web-search— Search the web via Tavily. Batch queries with|||separator.scrape-webpage— Fetch and extract content from URLs via Firecrawl.
CRITICAL: ALWAYS use presentation-gen with action: "create_slide" to build slides. NEVER create slide HTML files manually.
Folder Structure
presentations/
images/ ← shared images (downloaded BEFORE slides)
hero.jpg
logo.png
[presentation-name]/ ← created automatically by create_slide
metadata.json
slide_01.html
slide_02.html
viewer.html ← auto-generated on every create/delete
Images go to presentations/images/ BEFORE the presentation folder exists. Reference images as ../images/[filename] from slides.
Efficiency Rules
- Batch searches — Multiple queries in ONE call using
|||separator - Chain shell commands — ALL folder creation + image downloads in ONE bash command
- Parallel slide creation — Create ALL slides simultaneously (multiple
create_slidecalls at once)
Creation Workflow
Phase 1: Topic Confirmation
- Extract the topic from the user's message
- If clear enough to act on, proceed immediately with defaults:
- Target audience: "General public" unless specified
- Goals: "Informative overview" unless specified
- Only ask for clarification if the topic is completely unclear
Phase 2: Theme Design
-
Batch web search for brand identity — ALL in one call:
[topic] brand colors[topic] visual identity[topic] official website design[topic] brand guidelines
-
Define custom color scheme based on research:
- USE ACTUAL brand colors found in research
- FORBIDDEN: "blue for tech", "red for speed", "green for innovation" without research backing
- For companies: use their official brand colors
- For people: find their associated visual identity
- Document WHERE you found the color information
- Define: primary, secondary, accent, text color, font choices, layout patterns
Phase 3: Research and Content Planning
Complete ALL steps including ALL image downloads before Phase 4.
-
Batch content research — ALL in one call:
[topic] history background[topic] key features[topic] statistics data facts[topic] significance impact- Scrape key pages for detail
-
Create content outline — one main idea per slide. Note a TOPIC-SPECIFIC image query for each slide (always include the actual topic name/brand/person — never generic category queries).
-
Batch image search — ALL queries in one call with
num_results: 2 -
Select images based on:
- Topic specificity (actual brand/person images, not generic stock)
- Dimensions (landscape for backgrounds, portrait for side panels)
- Visual quality and relevance
-
Download ALL images in one command:
mkdir -p presentations/images && \ curl -L "URL1" -o presentations/images/slide1_hero.jpg && \ curl -L "URL2" -o presentations/images/slide2_detail.jpg && \ ls -lh presentations/images/Verify ALL expected files exist. Retry any failures.
-
Document image mapping: slide number -> filename, dimensions, orientation, placement
Phase 4: Slide Creation
Only start after Phase 3 is complete with all images downloaded and verified.
-
Create ALL slides in parallel — multiple
create_slidecalls simultaneously:presentation-gen( action: "create_slide", presentation_name: "my_pres", slide_number: 1, slide_title: "Introduction", content: "<div>...</div>", presentation_title: "My Presentation" ) -
Use downloaded images — Reference as
../images/filenamein<img>tags:- Landscape → full-width backgrounds, hero images
- Portrait → side panels, accent images
- Square → centered focal points, logos
Phase 5: Validate, Preview, Export
-
Validate —
presentation-genwithaction: "validate_slide"on each slide. Fix any overflows (content exceeding 1920x1080). -
Preview —
presentation-genwithaction: "preview"to launch viewer athttp://localhost:3210. -
Export — both formats:
action: "export_pdf"— merged PDF via Playwrightaction: "export_pptx"— 3-layer PPTX (background + visuals + editable text)
Both require
presentation_name. Output saved in the presentation folder.
Phase 6: Deliver
Review all slides for visual consistency, then report:
- What was created (topic, slide count, theme)
- Viewer URL:
http://localhost:3210 - Paths to exported PDF and PPTX files
Slide Content Rules
HTML Rules
- HTML body content ONLY — no
<!DOCTYPE>,<html>,<head>,<body>tags (added automatically) - Inter font is pre-loaded — use it directly
- Use emoji for icons — no Font Awesome or icon libraries
- Design for FIXED 1920x1080 pixels — NOT responsive
box-sizing: border-boxon all containers- Max 40px container padding
overflow: hiddenon all containers
Typography
| Element | Size | Weight |
|---|---|---|
| Titles | 48-72px | 700-900 |
| Subtitles | 32-42px | 600-700 |
| Headings | 28-36px | 600 |
| Body | 20-24px | 400-500 |
| Small/captions | 16-18px | 300-400 |
Line height: 1.5-1.8 for all text.
Layout — PRESENTATION, NOT WEBSITE
FORBIDDEN:
- Multi-column card grids
- Responsive patterns,
vw/vhunits, media queries - Scrolling content
- More than 5 bullet points per slide
- More than 2 ideas per slide
REQUIRED:
- Centered, focused content
- Large titles with visual impact
- Fixed pixel dimensions only
- 1-2 ideas per slide max
- 3-5 bullet points max
- Think PowerPoint: large title, centered content, minimal elements
Color Usage
- Primary — backgrounds, main elements
- Secondary — subtle backgrounds, section dividers
- Accent — highlights, CTAs, key numbers
- Text — all text content
- Consistent scheme across ALL slides — no slide should look like it belongs to a different deck
Image Placement Patterns
Full-bleed background
<div style="position:absolute;inset:0;background:url('../images/hero.jpg') center/cover;"></div>
<div style="position:absolute;inset:0;background:rgba(0,0,0,0.5);"></div>
<div style="position:relative;z-index:1;padding:60px;">
<!-- content over darkened image -->
</div>
Side panel (40/60 split)
<div style="display:flex;width:1920px;height:1080px;">
<div style="width:40%;background:url('../images/photo.jpg') center/cover;"></div>
<div style="width:60%;padding:60px;display:flex;flex-direction:column;justify-content:center;">
<!-- content -->
</div>
</div>
Centered accent image
<div style="text-align:center;padding:40px;">
<img src="../images/logo.png" style="max-height:300px;margin:0 auto 30px;">
<!-- content below -->
</div>
Data Visualization
D3.js and Chart.js are pre-loaded. Use them for charts, graphs, and data visualizations directly in slide HTML.
<canvas id="myChart" width="800" height="400"></canvas>
<script>
new Chart(document.getElementById('myChart'), {
type: 'bar',
data: {
labels: ['Q1', 'Q2', 'Q3', 'Q4'],
datasets: [{
label: 'Revenue ($M)',
data: [12, 19, 8, 15],
backgroundColor: '#1F4E79'
}]
},
options: { responsive: false }
});
</script>
Slide Templates
Title Slide
<div style="width:1920px;height:1080px;display:flex;flex-direction:column;justify-content:center;align-items:center;background:linear-gradient(135deg,PRIMARY,SECONDARY);padding:80px;box-sizing:border-box;">
<h1 style="font-size:64px;font-weight:800;color:#fff;text-align:center;margin:0 0 20px;">
Presentation Title
</h1>
<p style="font-size:28px;font-weight:400;color:rgba(255,255,255,0.8);text-align:center;">
Subtitle or tagline
</p>
</div>
Content Slide (title + bullets)
<div style="width:1920px;height:1080px;padding:60px 80px;box-sizing:border-box;background:#fff;display:flex;flex-direction:column;">
<h2 style="font-size:48px;font-weight:700;color:PRIMARY;margin:0 0 40px;">
Section Title
</h2>
<ul style="font-size:24px;line-height:1.8;color:#333;list-style:none;padding:0;">
<li style="margin-bottom:20px;">• First key point with supporting detail</li>
<li style="margin-bottom:20px;">• Second key point with supporting detail</li>
<li style="margin-bottom:20px;">• Third key point with supporting detail</li>
</ul>
</div>
Stats/Numbers Slide
<div style="width:1920px;height:1080px;padding:60px 80px;box-sizing:border-box;background:PRIMARY;display:flex;flex-direction:column;justify-content:center;">
<h2 style="font-size:42px;font-weight:700;color:#fff;margin:0 0 60px;text-align:center;">
Key Numbers
</h2>
<div style="display:flex;justify-content:space-around;">
<div style="text-align:center;">
<div style="font-size:72px;font-weight:900;color:ACCENT;">$2.5B</div>
<div style="font-size:20px;color:rgba(255,255,255,0.8);margin-top:10px;">Revenue</div>
</div>
<div style="text-align:center;">
<div style="font-size:72px;font-weight:900;color:ACCENT;">150K+</div>
<div style="font-size:20px;color:rgba(255,255,255,0.8);margin-top:10px;">Customers</div>
</div>
<div style="text-align:center;">
<div style="font-size:72px;font-weight:900;color:ACCENT;">98%</div>
<div style="font-size:20px;color:rgba(255,255,255,0.8);margin-top:10px;">Satisfaction</div>
</div>
</div>
</div>
Quote Slide
<div style="width:1920px;height:1080px;display:flex;align-items:center;justify-content:center;background:SECONDARY;padding:120px;box-sizing:border-box;">
<div style="max-width:1200px;text-align:center;">
<div style="font-size:120px;color:ACCENT;line-height:1;margin-bottom:20px;">"</div>
<p style="font-size:36px;font-weight:500;color:PRIMARY;line-height:1.6;font-style:italic;">
The quote text goes here, keeping it impactful and concise.
</p>
<p style="font-size:20px;color:#666;margin-top:30px;">— Attribution Name, Title</p>
</div>
</div>
Closing/CTA Slide
<div style="width:1920px;height:1080px;display:flex;flex-direction:column;justify-content:center;align-items:center;background:linear-gradient(135deg,PRIMARY,SECONDARY);padding:80px;box-sizing:border-box;">
<h2 style="font-size:56px;font-weight:800;color:#fff;text-align:center;margin:0 0 30px;">
Thank You
</h2>
<p style="font-size:24px;color:rgba(255,255,255,0.8);text-align:center;">
Contact info or call to action
</p>
</div>
Presentation Viewer
A polished slide viewer and preview server for HTML presentations (1920x1080).
Architecture
The viewer consists of two parts:
viewer.html— a self-contained HTML template that renders slides in scaled iframes with keyboard navigation, fullscreen, and a thumbnail strip.serve.ts— a lightweight Bun HTTP server that serves the presentation folder and injects the viewer at/.
Both files live in skills/presentations/ alongside this SKILL.md.
Why a Server (Not Just a Static HTML File)?
Standalone 1920x1080 HTML slides opened directly in a browser are an unscaled, scrollable mess. The viewer fixes this by loading slides into iframes and CSS-scaling them to fit any viewport.
The problem: loading <iframe src="slide_XX.html"> does not work reliably over file://. Browsers enforce CORS/sandboxing restrictions on file:// origins. An HTTP server on localhost eliminates all of this.
In the Sandbox (Container)
The viewer is already running as a service inside the sandbox container. It starts automatically on boot via s6-overlay and listens on port 3210.
- The service watches
/workspace/presentations/for any presentation with ametadata.json - It serves the most recently created/updated presentation at
http://localhost:3210 - Port 3210 is exposed in docker-compose and mapped to the host
The agent does not need to start the server manually. After creating slides, tell the user to open http://localhost:3210.
| Item | Value |
|---|---|
| Service location | /etc/s6-overlay/s6-rc.d/svc-presentation-viewer/run |
| Viewer files | /opt/opencode/skills/presentations/ |
| Port | 3210 (mapped to host) |
| Presentations dir | /workspace/presentations/ |
| Managed by | s6-overlay (auto-restart on crash) |
Local Development (Outside Container)
bun run .opencode/skills/presentations/serve.ts presentations/my-deck
Or via the presentation-gen tool:
presentation-gen(action: "preview", presentation_name: "my-deck")
Viewer Controls
| Key | Action |
|---|---|
→ / Space / ↓ |
Next slide |
← / ↑ |
Previous slide |
Home |
First slide |
End |
Last slide |
F |
Toggle fullscreen |
T |
Toggle thumbnail strip |
? |
Toggle keyboard shortcuts |
Esc |
Exit fullscreen / close panels |
| Swipe left/right | Navigate (touch) |
How Scaling Works
Each slide is a 1920x1080 iframe. The viewer measures the stage area, computes min(availWidth / 1920, availHeight / 1080), sets the wrapper to displayed pixel size, and applies transform: scale(factor) with transform-origin: 0 0. The 16:9 aspect ratio is maintained at any viewport size.