From utils
This skill should be used when creating technical presentation web pages with multiple slides, bilingual support, code examples, or complex visual requirements. Ideal for conference talks, team presentations, or technical documentation requiring slide-based navigation. Also triggered when a user asks to "make slides fill the screen", "resize for projector", "auto-scale to resolution", or "full-viewport presentation".
How this skill is triggered — by the user, by Claude, or both
Slash command
/utils:technical-presentation-generatorThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Generate self-contained HTML presentation files with professional styling, bilingual support, and technical content optimizations. Avoid external dependencies, create cohesive visual themes, and structure content for maximum clarity.
Generate self-contained HTML presentation files with professional styling, bilingual support, and technical content optimizations. Avoid external dependencies, create cohesive visual themes, and structure content for maximum clarity.
Use this skill when:
Don't use when:
❌ Use reveal.js or similar framework
❌ Default themes and colors
❌ External dependencies for fonts/styles
❌ Limited customization
❌ No bilingual strategy
✅ Pure HTML/CSS/JavaScript (no external frameworks)
✅ Custom theme matching content aesthetic
✅ Inline styles and fonts (or self-hosted)
✅ Full control over layout and transitions
✅ Built-in language toggle with proper architecture
✅ Full-viewport snap layout — each slide fills the screen exactly
✅ Fluid typography via clamp() — auto-scales to any resolution
ALWAYS ask these questions upfront:
Before I create the presentation, I need to clarify:
1. **Slide Count**: How many slides total? (Helps plan structure)
2. **Languages**: Which language pair? (Chinese/English, other?)
3. **Visual Theme**: Any preference? (cyberpunk, minimal, corporate, tech-focused)
4. **Code Examples**: What languages will appear? (Go, Python, YAML, etc.)
5. **Content Ratio**: The default ratios per slide section are:
- Introduction slides: 60% text, 40% charts/visuals
- Core content: 30% text, 70% charts/visuals
- Summary slides: 50% text, 50% charts/visuals
Would you like to keep these defaults, or adjust any of them?
6. **Key Topics**: What are the main sections/topics?
Why ask: Different presentations need different structures. Conference talks differ from internal documentation. Getting this right saves rework.
Content Ratio guidance:
Base HTML structure:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>[Title] :: [Subtitle]</title>
<!-- Inline Google Fonts or custom fonts -->
<style>
/* CSS variables for theming */
:root {
--primary-color: #color;
--secondary-color: #color;
--bg-color: #color;
--text-color: #color;
/* ... more theme variables */
}
/* Base styles */
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'YourFont', monospace;
background: var(--bg-color);
color: var(--text-color);
}
/* Language toggle system */
.zh { display: none; }
.en { display: block; }
body.lang-zh .zh { display: block; }
body.lang-zh .en { display: none; }
/* Full-viewport snap layout */
html { height: 100%; overflow: hidden; }
body {
height: 100%;
overflow-y: scroll;
scroll-snap-type: y mandatory;
scroll-behavior: smooth;
}
.slide {
height: 100vh; /* exactly one screen */
scroll-snap-align: start;
scroll-snap-stop: always; /* never skip slides */
padding: 80px 7vw 60px;
display: flex;
flex-direction: column;
justify-content: center;
overflow: hidden; /* clip overflowing content */
}
.slide > * { flex-shrink: 1; min-height: 0; }
/* Dividers: zero-height, invisible */
.divider { height: 0; border: none; margin: 0; }
/* Fluid typography — scales with viewport width */
h1 { font-size: clamp(32px, 4vw, 62px); }
h2 { font-size: clamp(22px, 2.6vw, 40px); }
h3 { font-size: clamp(15px, 1.5vw, 24px); }
p, li { font-size: clamp(13px, 1.15vw, 19px); }
.subtitle { font-size: clamp(14px, 1.4vw, 22px); }
/* Navigation */
.slide-counter { /* ... */ }
/* Stack to single column on narrow screens */
@media (max-width: 900px) {
.slide { padding: 70px 5vw 40px; }
.grid-2, .grid-3, .chart-heavy { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<header>
<button id="langToggle">
<span class="zh">EN</span>
<span class="en">中文</span>
</button>
<div class="slide-counter" id="slideCounter">01/XX</div>
</header>
<main>
<!-- Slides go here -->
</main>
<script>
// Language toggle
// Snap-aware slide navigation (see references/responsive-layout.md)
</script>
</body>
</html>
Correct pattern for language switching:
<!-- Use span wrappers with language classes -->
<h2 class="zh">中文标题</h2>
<h2 class="en">ENGLISH TITLE</h2>
<p class="zh">中文段落内容...</p>
<p class="en">English paragraph content...</p>
<!-- For inline mixed content -->
<p>
<span class="zh">中文部分</span>
<span class="en">English part</span>
</p>
JavaScript toggle:
function toggleLang() {
const body = document.body;
const currentLang = body.classList.contains('lang-zh') ? 'en' : 'zh';
if (currentLang === 'zh') {
body.classList.add('lang-zh');
} else {
body.classList.remove('lang-zh');
}
}
document.getElementById('langToggle').addEventListener('click', toggleLang);
CSS:
/* IMPORTANT: Default language is ENGLISH */
/* English visible by default, Chinese hidden */
.zh { display: none; }
.en { display: block; }
/* When Chinese toggle clicked, add 'lang-zh' class to body */
body.lang-zh .zh { display: block; }
body.lang-zh .en { display: none; }
Key Point: English is the default language. Chinese appears only when user clicks the language toggle button.
Title Slide:
<div class="slide" id="slide-1">
<div class="slide-label">SLIDE 01 // TITLE</div>
<div style="text-align: center; padding: 80px 0;">
<h1 class="zh">主标题</h1>
<h1 class="en">MAIN TITLE</h1>
<div class="divider"></div>
<h2 class="zh">副标题</h2>
<h2 class="en">SUBTITLE</h2>
<div style="margin-top: 60px;">
<span class="tag">TAG 1</span>
<span class="tag">TAG 2</span>
</div>
<div style="margin-top: 80px;">
<p style="color: var(--accent-color);">YYYY/MM</p>
<p>Presenter: Name | [email protected]</p>
</div>
</div>
</div>
<div class="divider"></div>
Content Slide with Charts (30% text, 70% visuals):
<div class="slide" id="slide-X">
<div class="slide-label">SLIDE XX // CATEGORY</div>
<h2 class="zh">幻灯片标题</h2>
<h2 class="en">SLIDE TITLE</h2>
<div class="chart-heavy">
<div>
<!-- 30% text content -->
<h3 class="zh">小节标题</h3>
<h3 class="en">SECTION TITLE</h3>
<ul class="zh">
<li>要点一</li>
<li>要点二</li>
</ul>
<ul class="en">
<li>Point one</li>
<li>Point two</li>
</ul>
</div>
<div class="chart">
<!-- 70% charts/visuals/code -->
<div class="code-block">
<pre>/* code example */</pre>
</div>
</div>
</div>
</div>
<div class="divider"></div>
Alert Boxes:
<div class="alert alert-success">
<h4 class="zh">✓ 成功信息</h4>
<h4 class="en">✓ SUCCESS</h4>
<p class="zh">内容...</p>
<p class="en">Content...</p>
</div>
<div class="alert alert-warning">
<h4 class="zh">⚠ 警告信息</h4>
<h4 class="en">⚠ WARNING</h4>
<!-- ... -->
</div>
<div class="alert alert-danger">
<h4 class="zh">✗ 错误信息</h4>
<h4 class="en">✗ ERROR</h4>
<!-- ... -->
</div>
<div class="alert alert-info">
<h4 class="zh">ℹ 提示信息</h4>
<h4 class="en">ℹ INFO</h4>
<!-- ... -->
</div>
Pure CSS approach (no external libraries):
.code-block {
background: rgba(0, 0, 0, 0.3);
border-left: 4px solid var(--accent-color);
padding: 20px;
border-radius: 4px;
font-family: 'Courier New', monospace;
overflow-x: auto;
}
.code-block pre {
margin: 0;
color: var(--text-color);
}
/* Syntax highlighting */
.keyword { color: #ff79c6; font-weight: 700; }
.string { color: #50fa7b; }
.comment { color: #6272a4; font-style: italic; }
.function { color: #8be9fd; }
HTML usage:
<div class="code-block">
<pre><span class="keyword">package</span> main
<span class="keyword">import</span> (
<span class="string">"context"</span>
)
<span class="keyword">func</span> <span class="function">Reconcile</span>() {
<span class="comment">// Reconciliation logic</span>
}
</pre>
</div>
IMPORTANT: When using the full-viewport snap layout (recommended), body is the scroll container — not window. Use body.scrollTo() and listen on body, not window.
const slides = document.querySelectorAll('.slide');
const scroller = document.body; // snap container
let currentSlide = 0;
function updateSlideCounter() {
const num = String(currentSlide + 1).padStart(2, '0');
slideCounter.textContent = `${num}/${slides.length}`;
}
function scrollToSlide(index) {
if (index < 0 || index >= slides.length) return;
currentSlide = index;
scroller.scrollTo({ top: slides[index].offsetTop, behavior: 'smooth' });
updateSlideCounter();
}
// Keyboard: arrows, space, Home, End, F (fullscreen)
document.addEventListener('keydown', function(e) {
switch(e.key) {
case 'ArrowRight': case 'ArrowDown': case ' ':
e.preventDefault(); scrollToSlide(currentSlide + 1); break;
case 'ArrowLeft': case 'ArrowUp':
e.preventDefault(); scrollToSlide(currentSlide - 1); break;
case 'Home': e.preventDefault(); scrollToSlide(0); break;
case 'End': e.preventDefault(); scrollToSlide(slides.length - 1); break;
case 'f': case 'F':
document.fullscreenElement
? document.exitFullscreen()
: document.documentElement.requestFullscreen();
break;
}
});
// Scroll tracking — read body.scrollTop, not window.scrollY
let scrollTimer;
scroller.addEventListener('scroll', function() {
clearTimeout(scrollTimer);
scrollTimer = setTimeout(function() {
const top = scroller.scrollTop;
let closest = 0, minDist = Infinity;
slides.forEach(function(slide, i) {
const dist = Math.abs(slide.offsetTop - top);
if (dist < minDist) { minDist = dist; closest = i; }
});
currentSlide = closest;
updateSlideCounter();
}, 80);
});
updateSlideCounter();
For full details including touch swipe support, see references/responsive-layout.md.
Choose theme based on content:
| Content Type | Suggested Theme | Colors |
|---|---|---|
| DevOps/Cloud | Cyberpunk | Cyan, Magenta, Dark BG |
| OpenShift/Red Hat | Red Hat Brand | #cc0000 red, #1d6f8a teal, white |
| Corporate | Minimal | Navy, White, Light Gray |
| Data/Analytics | Tech | Blue, Green, Dark |
| Security | Matrix | Green, Black |
| General Tech | Modern | Varied, Clean |
Use this for any Red Hat, OpenShift, or internal company presentations. The title slide design (teal background + decorative circles + official logotype) is the canonical OpenShift template — topic, date, and presenter are the only things to change per presentation.
CSS to add (inside <style>):
:root {
--rh-red: #ee0000;
--rh-orange: #f96d00;
}
/* Red Hat title slide */
.rh-title-slide {
background: #1d6f8a;
position: relative;
overflow: hidden;
}
.rh-circle-tl {
position: absolute;
top: -80px; left: -80px;
width: 340px; height: 340px;
border-radius: 50%;
background: var(--rh-orange);
opacity: 0.85;
}
.rh-circle-tr {
position: absolute;
top: -100px; right: -100px;
width: 280px; height: 280px;
border-radius: 50%;
background: var(--rh-red);
opacity: 0.9;
}
.rh-circle-br {
position: absolute;
bottom: -100px; right: -60px;
width: 260px; height: 260px;
border-radius: 50%;
background: #6dbfcf;
opacity: 0.7;
}
.rh-circle-inner {
position: absolute;
top: -40px; left: -40px;
width: 280px; height: 280px;
border-radius: 50%;
border: 40px solid rgba(255,255,255,0.15);
}
.rh-title-content {
position: relative;
z-index: 10;
padding: 5vh 7vw;
display: flex;
flex-direction: column;
justify-content: center;
height: 100%;
}
.rh-logo {
display: flex;
align-items: center;
margin-bottom: clamp(30px, 6vh, 80px);
}
.rh-logo-icon {
display: flex;
align-items: center;
}
.rh-main-title {
font-size: clamp(36px, 4.5vw, 68px);
font-weight: 700;
color: white;
line-height: 1.15;
margin-bottom: clamp(24px, 4vh, 60px);
}
.rh-meta { color: rgba(255,255,255,0.85); }
.rh-meta p { font-size: clamp(16px, 1.5vw, 24px); margin-bottom: 6px; }
HTML for the title slide — customize TOPIC, DATE, NAME, TEAM:
<div class="slide rh-title-slide" id="slide-1" style="padding:0; overflow:hidden;">
<div class="rh-circle-tl"></div>
<div class="rh-circle-inner"></div>
<div class="rh-circle-tr"></div>
<div class="rh-circle-br"></div>
<div class="rh-title-content">
<div class="rh-logo">
<div class="rh-logo-icon">
<!-- Official OpenShift logotype — icon + wordmark combined, no inline SVG -->
<img src="https://upload.wikimedia.org/wikipedia/commons/3/3a/OpenShift-LogoType.svg"
height="120" alt="OpenShift Logo" style="width:auto;">
</div>
</div>
<div class="rh-main-title">
<span class="en">TOPIC (English)</span>
<span class="zh">TOPIC(中文)</span>
</div>
<div class="rh-meta">
<p class="mono en" style="font-size:20px; margin-bottom:12px;">DATE (e.g. March 2026)</p>
<p class="mono zh" style="font-size:20px; margin-bottom:12px;">DATE (e.g. 2026年3月)</p>
<p>NAME</p>
<p>TEAM / ROLE</p>
</div>
</div>
</div>
<div class="divider"></div>
Critical rules for this template:
.slide itself uses padding:0; overflow:hidden — padding lives inside .rh-title-content (5vh 7vw) to avoid double-inset with the global .slide paddingheight="120" with width:auto — the logotype SVG is wide, never constrain its widthoverflow:hidden, border-radius, or fixed width — these clip the wide logotype into a tiny circle<svg><path> — always use the official URLExample cyberpunk theme:
:root {
--cyber-bg: #0a0e1a;
--cyber-surface: #151b2e;
--cyber-primary: #00f0ff;
--cyber-secondary: #ff00f7;
--cyber-accent: #39ff14;
--cyber-text: #e4e8f0;
--cyber-gray: #6b7280;
}
/* Animated grid background */
.cyber-grid {
position: fixed;
background-image:
linear-gradient(rgba(0, 240, 255, 0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(0, 240, 255, 0.03) 1px, transparent 1px);
background-size: 50px 50px;
}
/* Scan line effect */
.scanlines {
position: fixed;
background: linear-gradient(
transparent 50%,
rgba(0, 240, 255, 0.03) 50%
);
background-size: 100% 4px;
animation: scan 8s linear infinite;
}
Problem: Dependencies on CDNs (reveal.js, impress.js) that may fail or change.
Solution: Build custom HTML/CSS/JS. It's simpler than it seems and gives full control.
Problem:
slideCounter.textContent = slideNum + '/30'; // Hardcoded!
Solution:
const total = slides.length; // Dynamic
slideCounter.textContent = `${slideNum}/${total}`;
Problem:
<!-- Mixing languages in same element -->
<h2>Title / 标题</h2>
Solution:
<h2 class="zh">标题</h2>
<h2 class="en">Title</h2>
Problem: No date on title slide.
Solution: Always add date in YYYY/MM format on first slide.
Problem: Setting Chinese as default instead of English.
Solution:
/* CORRECT: English default */
.zh { display: none; }
.en { display: block; }
/* WRONG: Chinese default */
.zh { display: block; } /* ❌ Don't do this! */
.en { display: none; }
English should ALWAYS be the default language for international accessibility.
Problem: Some links or small text without language wrappers show wrong language.
Solution: Wrap ALL content in language classes, even single words.
<!-- Wrong -->
<a href="...">GitHub PR #123</a> - 详细说明
<!-- Right -->
<a href="...">GitHub PR #123</a> - <span class="zh">详细说明</span><span class="en">Details</span>
body as scroll-snap container, height: 100vh per slide)clamp(min, vw, max)body.scrollTop)presentation.html # Single self-contained file
├─ <head>
│ ├─ <style> # All CSS inline
│ └─ Google Fonts # Or inline base64 fonts
├─ <body>
│ ├─ <header> # Lang toggle + counter
│ ├─ <main>
│ │ └─ .slide × N # All slides
│ └─ <script> # All JS inline
/* Two columns */
.chart-heavy {
display: grid;
grid-template-columns: 30fr 70fr;
gap: 40px;
}
/* Three columns */
.grid-3 {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
/* Two equal columns */
.grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
}
The "Unified Automation Strategy for Control Plane" presentation (33 slides):
User: "Create presentation about Kubernetes Operators, 15 slides"
You: "Before I create the presentation, I need to clarify:
1. Slide count: 15 slides (confirmed)
2. Languages: Chinese/English bilingual?
3. Visual theme: Technical/corporate/cyberpunk?
4. Code examples: Go, YAML?
5. Content ratio — the defaults are:
- Introduction slides: 60% text, 40% charts/visuals
- Core content: 30% text, 70% charts/visuals
- Summary slides: 50% text, 50% charts/visuals
Would you like to keep these, or adjust any of them?
6. Key topics to cover?"
[User responds]
You: [Create single HTML file with]:
- Custom theme matching preferences
- Bilingual architecture
- 15 slides structured as requested
- Code examples with syntax highlighting
- Navigation system
- All inline, self-contained
Before delivery:
firefox presentation.htmlChecklist:
<span> for keywords, not complex librariesvw, vh, clamp() — never fixed px for layout/typographyUse external frameworks if:
Always inform user of trade-offs.
references/responsive-layout.md — Complete full-viewport snap layout pattern: CSS snap container setup, fluid clamp() typography table, viewport-relative spacing, snap-aware JS navigation, touch swipe, common mistakes, and a full checklist. Consult this whenever implementing or debugging responsive/viewport behavior.npx claudepluginhub wangke19/my-claude-skills --plugin utilsGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.