Files
davila7__claude-code-templates/docs/blog/heygen-best-practices-skill/index.html
Daniel Avila c7397fe493 Blog standardization, worktree commands, and .gitignore fix (#341)
* fix: improve Chats Mobile security, CSS quality, and desktop layout

- Sanitize error.message with escapeHtml() to prevent XSS in innerHTML
- Replace !important overrides in .back-btn with proper specificity (.header-btn.back-btn)
- Add desktop side-by-side layout at 769px+ (360px sidebar + flexible chat view)
- Extract 100+ inline styles from analytics modal into reusable CSS classes

https://claude.ai/code/session_01Cfg7GGRKxgJoWiNj1EjWSb

* chore: standardize all 15 blog posts for consistency

Apply unified style guide across all local blog posts:
- Fix copyright year 2025 -> 2026 in all footers
- Remove inline styles from explore-components-banner (use CSS classes)
- Standardize CTA text to "800+" and relative links
- Fix OG tag prefix og:article: -> article: (code-reviewer)
- Fix www.aitmpl.com -> aitmpl.com in OG/Twitter/structured data
- Fix cover image absolute URLs to relative paths (e2b, nextjs)
- Standardize Mermaid theme to orange #F97316 (heygen)
- Fix author name to "Claude Code Templates" (neon-complete)
- Add missing explore-components-banner (security-hooks, vercel-monitor, hackathon)
- Add missing callout boxes (info-box, success-box) where absent
- Standardize CodeCopy JS and MarkdownCopier across posts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add worktree commands and blog post for parallel development

Add 4 worktree slash commands for git worktree lifecycle management:
- /worktree-init: create parallel worktrees from task descriptions
- /worktree-check: show current worktree status and task
- /worktree-deliver: commit, push, and create PR
- /worktree-cleanup: remove merged worktrees and branches

Add blog post explaining the Skill + Commands architecture pattern
where a discoverable Skill (worktree-guide) orchestrates manual
Commands for execution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: ignore settings.local.json in all subdirectories

Change .claude/settings.local.json to **/settings.local.json
to cover nested paths like docs/.claude/settings.local.json.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add missing allowed-tools to worktree commands

- worktree-cleanup: add Bash(grep:*) for merge check commands
- worktree-init: add Bash(sed:*) for branch name detection

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-07 20:11:17 -05:00

896 lines
40 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HeyGen Best Practices Skill for Claude Code: AI Avatar Video Creation Guide</title>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-YWW6FV2SGN"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-YWW6FV2SGN');
</script>
<!-- Favicon -->
<link rel="icon" type="image/x-icon" href="../../static/favicon/favicon.ico">
<link rel="icon" type="image/png" sizes="16x16" href="../../static/favicon/favicon-16x16.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../static/favicon/favicon-32x32.png">
<link rel="apple-touch-icon" sizes="180x180" href="../../static/favicon/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="192x192" href="../../static/favicon/android-chrome-192x192.png">
<link rel="icon" type="image/png" sizes="512x512" href="../../static/favicon/android-chrome-512x512.png">
<meta name="description" content="Master HeyGen API integration with 18+ best practice rules. Learn to create AI avatar videos, manage voices, handle video generation workflows, and implement streaming avatars with Claude Code.">
<!-- Open Graph / Facebook -->
<meta property="og:type" content="article">
<meta property="og:url" content="https://aitmpl.com/blog/heygen-best-practices-skill/">
<meta property="og:title" content="HeyGen Best Practices Skill: AI Avatar Video Creation Guide">
<meta property="og:description" content="Master HeyGen API integration with 18+ best practice rules. Learn to create AI avatar videos, manage voices, and handle video generation workflows.">
<meta property="og:image" content="https://aitmpl.com/blog/assets/heygen-best-practices-skill-cover.svg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="article:author" content="Claude Code Templates">
<meta property="article:section" content="Skills">
<meta property="article:tag" content="HeyGen">
<meta property="article:tag" content="AI Video">
<meta property="article:tag" content="Avatar">
<meta property="article:tag" content="Text-to-Video">
<meta property="article:tag" content="API Integration">
<meta property="article:tag" content="Video Generation">
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:url" content="https://aitmpl.com/blog/heygen-best-practices-skill/">
<meta name="twitter:title" content="HeyGen Best Practices Skill: AI Avatar Video Creation Guide">
<meta name="twitter:description" content="Master HeyGen API integration with 18+ best practice rules. Learn to create AI avatar videos, manage voices, and handle video generation workflows.">
<meta name="twitter:image" content="https://aitmpl.com/blog/assets/heygen-best-practices-skill-cover.svg">
<!-- Additional SEO -->
<meta name="keywords" content="HeyGen API, AI avatar, video generation, text-to-video, avatar video, Claude Code, HeyGen skill, video automation, AI presenter, talking head video, streaming avatar, video translation, webhook integration">
<meta name="author" content="Claude Code Templates">
<link rel="canonical" href="https://aitmpl.com/blog/heygen-best-practices-skill/">
<link rel="stylesheet" href="../../css/styles.css">
<link rel="stylesheet" href="../../css/blog.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<!-- Hotjar Tracking Code for https://aitmpl.com -->
<script>
(function(h,o,t,j,a,r){
h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
h._hjSettings={hjid:6519181,hjsv:6};
a=o.getElementsByTagName('head')[0];
r=o.createElement('script');r.async=1;
r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
a.appendChild(r);
})(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');
</script>
<!-- Structured Data -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": "HeyGen Best Practices Skill for Claude Code: AI Avatar Video Creation Guide",
"description": "Master HeyGen API integration with 18+ best practice rules. Learn to create AI avatar videos, manage voices, and handle video generation workflows.",
"image": "https://aitmpl.com/blog/assets/heygen-best-practices-skill-cover.svg",
"author": {
"@type": "Organization",
"name": "Claude Code Templates"
},
"publisher": {
"@type": "Organization",
"name": "Claude Code Templates",
"logo": {
"@type": "ImageObject",
"url": "https://aitmpl.com/static/img/logo.svg"
}
},
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://aitmpl.com/blog/heygen-best-practices-skill/"
},
"keywords": "HeyGen API, AI avatar, video generation, text-to-video, Claude Code, avatar video, streaming avatar",
"wordCount": "1800",
"articleSection": "Claude Code Skills",
"about": [
{
"@type": "Thing",
"name": "HeyGen API Integration"
},
{
"@type": "Thing",
"name": "AI Video Generation"
},
{
"@type": "Thing",
"name": "Avatar Technology"
},
{
"@type": "SoftwareApplication",
"name": "Claude Code",
"applicationCategory": "DeveloperApplication"
}
]
}
</script>
</head>
<body>
<header class="header">
<div class="container">
<div class="header-content">
<div class="terminal-header">
<div class="ascii-title">
<pre class="ascii-art">
██████╗ ██╗ ██████╗ ██████╗
██╔══██╗██║ ██╔═══██╗██╔════╝
██████╔╝██║ ██║ ██║██║ ███╗
██╔══██╗██║ ██║ ██║██║ ██║
██████╔╝███████╗╚██████╔╝╚██████╔╝
╚═════╝ ╚══════╝ ╚═════╝ ╚═════╝</pre>
</div>
</div>
<div class="header-actions">
<a href="../../index.html" class="header-btn">
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
<path d="M10,20V14H14V20H19V12H22L12,3L2,12H5V20H10Z"/>
</svg>
Home
</a>
<a href="../index.html" class="header-btn">
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
<path d="M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z"/>
</svg>
Blog
</a>
<a href="https://github.com/davila7/claude-code-templates" target="_blank" class="header-btn">
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.30 3.297-1.30.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
</svg>
GitHub
</a>
</div>
</div>
</div>
</header>
<main class="terminal">
<header class="article-header">
<div class="container">
<!-- Copy Markdown Button -->
<button id="copy-markdown-btn" class="copy-markdown-button" title="Copy post as Markdown">
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/>
</svg>
Copy as Markdown
</button>
<h1 class="article-title">HeyGen Best Practices Skill: AI Avatar Video Creation Guide</h1>
<p class="article-subtitle">Master HeyGen API integration with 18+ comprehensive rules for creating AI avatar videos, managing voices, handling video generation workflows, and implementing advanced features like streaming avatars and video translation.</p>
<div class="article-meta-full">
<span class="read-time">10 min read</span>
<div class="article-tags">
<span class="tag">Claude Code</span>
<span class="tag">Skill</span>
<span class="tag">HeyGen</span>
<span class="tag">AI Video</span>
<span class="tag">Avatar</span>
<span class="tag">API</span>
</div>
</div>
</div>
</header>
<article class="article-body">
<img src="../assets/heygen-best-practices-skill-cover.svg" alt="HeyGen Best Practices Skill for Claude Code" class="article-cover" loading="lazy">
<div class="article-content-full">
<h2>What is the HeyGen Best Practices Skill?</h2>
<p>The HeyGen Best Practices skill is a comprehensive guide for integrating with HeyGen's AI avatar video creation API. It provides Claude Code with 18+ actionable rules organized by functionality, helping you create professional AI presenter videos, manage avatars and voices, handle video generation workflows, and implement advanced features.</p>
<p>This skill was created by the HeyGen community and includes real-world examples, TypeScript/Python code samples, and best practices for every aspect of the HeyGen API.</p>
<!-- Mermaid Diagram -->
<div class="mermaid-diagram" style="background: #1a1a1a; border: 1px solid #333; border-radius: 8px; padding: 2rem; margin: 2rem 0; text-align: center;">
<pre class="mermaid">
graph TD
A[Video Request] --> B[Claude + HeyGen Skill]
B --> C[Select Avatar]
B --> D[Choose Voice]
B --> E[Write Script]
C --> F[POST /v2/video/generate]
D --> F
E --> F
F --> G[Poll Status]
G --> H{Completed?}
H -->|Yes| I[Download Video URL]
H -->|No| G
style B fill:#F97316,stroke:#fff,color:#000
style I fill:#00ff41,stroke:#fff,color:#000
</pre>
</div>
<h2>Why You Need This Skill</h2>
<p>Creating AI avatar videos programmatically requires understanding multiple API endpoints, matching avatars with voices, handling asynchronous video generation, and implementing proper error handling. This skill simplifies everything by:</p>
<ul>
<li><strong>Organizing knowledge by function</strong> - Rules are grouped into Foundation, Core Video Creation, Customization, and Advanced Features</li>
<li><strong>Providing production-ready code</strong> - Each rule includes TypeScript and Python examples you can use directly</li>
<li><strong>Teaching best practices</strong> - Learn to use avatar's default voice, implement proper polling, and handle rate limits</li>
<li><strong>Progressive context loading</strong> - The skill loads detailed guidelines on-demand to minimize token usage</li>
</ul>
<h2>Key Feature Categories</h2>
<h3>1. Foundation (Required)</h3>
<p>Essential knowledge for any HeyGen integration:</p>
<ul>
<li><strong>Authentication</strong> - API key setup, X-Api-Key header patterns</li>
<li><strong>Quota Management</strong> - Credit system, usage limits, checking remaining quota</li>
<li><strong>Video Status</strong> - Polling patterns, status types, retrieving download URLs</li>
<li><strong>Assets</strong> - Uploading images, videos, and audio for use in videos</li>
</ul>
<pre><code class="language-typescript">// Authenticated request example
const response = await fetch("https://api.heygen.com/v2/avatars", {
headers: {
"X-Api-Key": process.env.HEYGEN_API_KEY!,
},
});
const { data } = await response.json();</code></pre>
<h3>2. Core Video Creation</h3>
<p>The main workflow for generating AI avatar videos:</p>
<ul>
<li><strong>Avatars</strong> - Listing avatars, styles (normal, closeUp, circle), avatar_id selection</li>
<li><strong>Voices</strong> - Listing voices, locales, speed/pitch configuration</li>
<li><strong>Scripts</strong> - Writing scripts, pauses/breaks, pacing, structure templates</li>
<li><strong>Video Generation</strong> - POST /v2/video/generate workflow, multi-scene videos</li>
<li><strong>Dimensions</strong> - Resolution options (720p/1080p) and aspect ratios</li>
</ul>
<pre><code class="language-typescript">// Basic video generation
const videoId = await generateVideo({
video_inputs: [{
character: {
type: "avatar",
avatar_id: "josh_lite3_20230714",
avatar_style: "normal",
},
voice: {
type: "text",
input_text: "Hello! Welcome to our product demo.",
voice_id: avatar.default_voice_id, // Use avatar's default voice
speed: 1.0,
},
background: {
type: "color",
value: "#1a1a2e",
},
}],
dimension: { width: 1920, height: 1080 },
});</code></pre>
<h3>3. Video Customization</h3>
<p>Make your videos visually appealing:</p>
<ul>
<li><strong>Backgrounds</strong> - Solid colors, images, and video backgrounds</li>
<li><strong>Text Overlays</strong> - Adding text with fonts and positioning</li>
<li><strong>Captions</strong> - Auto-generated captions and subtitle options</li>
</ul>
<h3>4. Advanced Features</h3>
<p>Take your integration to the next level:</p>
<ul>
<li><strong>Templates</strong> - Template listing and variable replacement</li>
<li><strong>Video Translation</strong> - Translating videos, quality/fast modes, dubbing</li>
<li><strong>Streaming Avatars</strong> - Real-time interactive avatar sessions</li>
<li><strong>Photo Avatars</strong> - Creating avatars from photos (talking photos)</li>
<li><strong>Webhooks</strong> - Registering webhook endpoints for async notifications</li>
<li><strong>Remotion Integration</strong> - Using HeyGen videos in Remotion compositions</li>
</ul>
<h2>Installation</h2>
<p>Install the HeyGen Best Practices skill using the Claude Code Templates CLI:</p>
<pre><code class="language-bash">npx claude-code-templates@latest --skill=development/heygen-best-practices --yes</code></pre>
<p><strong>Where is the skill installed?</strong></p>
<p>The skill is saved in <code>.claude/skills/heygen-best-practices/</code> in your project directory:</p>
<pre><code class="language-bash">your-project/
├── .claude/
│ └── skills/
│ └── heygen-best-practices/ # Skill installed here
│ ├── SKILL.md
│ └── rules/
│ ├── authentication.md
│ ├── avatars.md
│ ├── voices.md
│ ├── video-generation.md
│ ├── video-status.md
│ └── ... (18+ rule files)
├── src/
├── package.json
└── README.md</code></pre>
<h2>How to Use the Skill</h2>
<p>The skill uses progressive context loading - it provides a quick reference first, then loads detailed guidelines only when needed. This approach minimizes token usage while giving you access to comprehensive information.</p>
<h3>Basic Usage</h3>
<pre><code class="language-bash"># Start Claude Code
claude
# Request HeyGen help
> Use the heygen-best-practices skill to create a video with an AI avatar presenting our product</code></pre>
<p>Claude will:</p>
<ol>
<li>Load the skill's quick reference</li>
<li>Identify the relevant rules (avatars, voices, video-generation)</li>
<li>Load detailed guidelines for those specific areas</li>
<li>Generate production-ready code with proper error handling</li>
</ol>
<h2>Usage Examples</h2>
<h3>Example 1: Create a Simple Avatar Video</h3>
<pre><code class="language-bash">claude
> Use the heygen-best-practices skill to create a 30-second product demo video with a professional male avatar</code></pre>
<p><strong>Result:</strong> Claude loads the avatars, voices, and video-generation rules, then generates code that lists available avatars, selects a professional one, uses its default voice, and creates the video with proper status polling.</p>
<h3>Example 2: Multi-Scene Video with Different Backgrounds</h3>
<pre><code class="language-bash">claude
> Use the heygen-best-practices skill to create a video with 3 scenes: intro, features, and conclusion. Each scene should have a different background color.</code></pre>
<p><strong>Result:</strong> Claude generates multi-scene video configuration with proper scene transitions and background customization.</p>
<h3>Example 3: Implement Webhook Notifications</h3>
<pre><code class="language-bash">claude
> Use the heygen-best-practices skill to set up webhooks so I get notified when my video is ready</code></pre>
<p><strong>Result:</strong> Claude loads the webhooks rule and provides code for registering webhook endpoints and handling completion events.</p>
<h2>Best Practices Highlights</h2>
<h3>Always Use Avatar's Default Voice</h3>
<p>Most avatars have a pre-matched <code>default_voice_id</code> that provides the best lip-sync quality:</p>
<pre><code class="language-typescript">// Get avatar details to find default voice
const details = await getAvatarDetails(avatarId);
// Use the default voice for best results
const voiceId = details.default_voice_id;</code></pre>
<h3>Implement Proper Status Polling</h3>
<p>Video generation is asynchronous and can take 5-15 minutes:</p>
<pre><code class="language-typescript">async function waitForVideo(videoId: string): Promise<string> {
const maxAttempts = 60;
const pollInterval = 10000; // 10 seconds
for (let i = 0; i < maxAttempts; i++) {
const response = await fetch(
`https://api.heygen.com/v1/video_status.get?video_id=${videoId}`,
{ headers: { "X-Api-Key": process.env.HEYGEN_API_KEY! } }
);
const { data } = await response.json();
if (data.status === "completed") {
return data.video_url;
} else if (data.status === "failed") {
throw new Error(data.error || "Video generation failed");
}
await new Promise(r => setTimeout(r, pollInterval));
}
throw new Error("Video generation timed out");
}</code></pre>
<h3>Add Natural Pauses to Scripts</h3>
<p>Use SSML-style break tags for more natural speech:</p>
<pre><code class="language-typescript">const script = `
Welcome to our demo. &lt;break time="1s"/&gt;
Today I'll show you three key features. &lt;break time="0.5s"/&gt;
First, let's look at the dashboard.
`;</code></pre>
<h2>Common Pitfalls Avoided</h2>
<p>The skill helps you avoid these common HeyGen integration mistakes:</p>
<ul>
<li>Mismatching avatar and voice genders</li>
<li>Not polling for video completion (expecting synchronous generation)</li>
<li>Hardcoding API keys instead of using environment variables</li>
<li>Not handling rate limits with exponential backoff</li>
<li>Using the wrong endpoint for transparent background videos</li>
<li>Setting insufficient timeouts for video generation</li>
</ul>
<h2>Skill Structure</h2>
<p>The skill is organized into logical categories with 18+ rule files:</p>
<table class="components-table">
<thead>
<tr>
<th>Category</th>
<th>Rules</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Foundation</strong></td>
<td>authentication, quota, video-status, assets</td>
</tr>
<tr>
<td><strong>Core Video</strong></td>
<td>avatars, voices, scripts, video-generation, video-agent, dimensions</td>
</tr>
<tr>
<td><strong>Customization</strong></td>
<td>backgrounds, text-overlays, captions</td>
</tr>
<tr>
<td><strong>Advanced</strong></td>
<td>templates, video-translation, streaming-avatars, photo-avatars, webhooks, remotion-integration</td>
</tr>
</tbody>
</table>
<h2>Official Documentation</h2>
<p>For more information about skills in Claude Code, see the <a href="https://code.claude.com/docs/en/skills?utm_source=aitmpl&utm_medium=referral&utm_campaign=blog" target="_blank">official skills documentation</a>.</p>
<p>For HeyGen API documentation, visit <a href="https://docs.heygen.com" target="_blank">docs.heygen.com</a>.</p>
<!-- Explore Components Banner -->
<div class="explore-components-banner">
<h3>Explore 800+ Claude Code Components</h3>
<p>Discover agents, commands, MCPs, settings, hooks, skills and templates to supercharge your Claude Code workflow</p>
<a href="../../index.html">Browse All Components</a>
</div>
</div>
<div class="article-nav">
<a href="../index.html" class="back-to-blog">
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
<path d="M20,11V13H8L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11H20Z"/>
</svg>
Back to Blog
</a>
</div>
</article>
</main>
<footer class="footer">
<div class="container">
<div class="footer-content">
<div class="footer-left">
<div class="footer-ascii">
<pre class="footer-ascii-art"> █████╗ ██╗████████╗███╗ ███╗██████╗ ██╗
██╔══██╗██║╚══██╔══╝████╗ ████║██╔══██╗██║
███████║██║ ██║ ██╔████╔██║██████╔╝██║
██╔══██║██║ ██║ ██║╚██╔╝██║██╔═══╝ ██║
██║ ██║██║ ██║ ██║ ╚═╝ ██║██║ ███████╗
╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚══════╝</pre>
<p class="footer-tagline">Supercharge Anthropic's Claude Code</p>
</div>
</div>
<div class="footer-right">
<p class="footer-copyright">&copy; 2026 Claude Code Templates. Open source project.</p>
<div class="footer-links">
<a href="../../trending.html" class="footer-link">
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
<path d="M16,6L18.29,8.29L13.41,13.17L9.41,9.17L2,16.59L3.41,18L9.41,12L13.41,16L19.71,9.71L22,12V6H16Z"/>
</svg>
Trending
</a>
<a href="https://docs.aitmpl.com/" target="_blank" class="footer-link">
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
<path d="M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z"/>
</svg>
Documentation
</a>
<a href="https://github.com/davila7/claude-code-templates" target="_blank" class="footer-link">
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.30.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.30 3.297-1.30.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
</svg>
GitHub
</a>
</div>
</div>
</div>
</div>
</footer>
<!-- Mermaid for diagrams -->
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
mermaid.initialize({
startOnLoad: true,
theme: 'dark',
themeVariables: {
primaryColor: '#F97316',
primaryTextColor: '#fff',
primaryBorderColor: '#F97316',
lineColor: '#00ff41',
secondaryColor: '#1a1a1a',
tertiaryColor: '#2d2d2d'
}
});
</script>
<!-- Code Copy Functionality -->
<script>
// Code Copy Functionality for Blog Articles
class CodeCopy {
constructor() {
this.initCodeBlocks();
this.setupCopyFunctionality();
}
initCodeBlocks() {
// Convert existing pre elements to new code-block structure
const preElements = document.querySelectorAll('.article-content-full pre:not(.converted)');
preElements.forEach(pre => {
const code = pre.querySelector('code');
if (!code) return;
// Detect language from class or content
const language = this.detectLanguage(code);
const isTerminal = language === 'bash' || language === 'terminal';
// Create new code block structure
const codeBlock = document.createElement('div');
codeBlock.className = isTerminal ? 'code-block terminal-block' : 'code-block';
// Create header
const header = document.createElement('div');
header.className = 'code-header';
const languageSpan = document.createElement('span');
languageSpan.className = 'code-language';
languageSpan.textContent = language;
const copyButton = document.createElement('button');
copyButton.className = 'copy-button';
copyButton.innerHTML = `
<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/>
</svg>
Copy
`;
header.appendChild(languageSpan);
header.appendChild(copyButton);
// Clone and prepare the pre element
const newPre = pre.cloneNode(true);
newPre.classList.add('converted');
// Assemble new structure
codeBlock.appendChild(header);
codeBlock.appendChild(newPre);
// Replace original pre
pre.parentNode.replaceChild(codeBlock, pre);
});
}
detectLanguage(codeElement) {
// Check for class-based language detection
const className = codeElement.className;
if (className.includes('language-')) {
return className.match(/language-(\w+)/)[1];
}
// Check content patterns
const content = codeElement.textContent;
if (content.includes('npm ') || content.includes('$ ') || content.includes('claude-code ')) {
return 'bash';
}
if (content.includes('import ') && content.includes('from ')) {
return 'javascript';
}
if (content.includes('CREATE TABLE') || content.includes('SELECT ')) {
return 'sql';
}
if (content.includes('{') && content.includes('"')) {
return 'json';
}
if (content.includes('def ') || content.includes('import ')) {
return 'python';
}
return 'text';
}
setupCopyFunctionality() {
document.addEventListener('click', async (e) => {
if (!e.target.closest('.copy-button')) return;
const button = e.target.closest('.copy-button');
const codeBlock = button.closest('.code-block');
const pre = codeBlock.querySelector('pre');
const code = pre.querySelector('code');
if (!code) return;
try {
// Get clean text content
let textToCopy = code.textContent;
// Clean up terminal prompts if it's a terminal block
if (codeBlock.classList.contains('terminal-block')) {
textToCopy = this.cleanTerminalOutput(textToCopy);
}
await navigator.clipboard.writeText(textToCopy);
// Update button state
const originalContent = button.innerHTML;
button.innerHTML = `
<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>
</svg>
Copied!
`;
button.classList.add('copied');
// Reset after 2 seconds
setTimeout(() => {
button.innerHTML = originalContent;
button.classList.remove('copied');
}, 2000);
} catch (err) {
console.error('Failed to copy code:', err);
// Fallback: select text
const selection = window.getSelection();
const range = document.createRange();
range.selectNodeContents(code);
selection.removeAllRanges();
selection.addRange(range);
}
});
}
cleanTerminalOutput(text) {
// Remove common terminal prompts and clean output
return text
.split('\n')
.map(line => {
// Remove prompts like "$ ", "❯ ", "claude-code> "
line = line.replace(/^[\$❯]\s*/, '').replace(/^claude-code>\s*/, '');
// Remove output/result comments (lines starting with # ✓)
if (line.trim().startsWith('# ✓') ||
line.trim().startsWith('# Start using') ||
line.trim().startsWith('# Your .claude') ||
line.trim().startsWith('# This will') ||
line.includes('Components will be installed') ||
line.includes('directory now contains')) {
return '';
}
return line;
})
.filter(line => line.trim() !== '') // Remove empty lines
.join('\n')
.trim();
}
}
// Initialize when DOM is loaded
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => new CodeCopy());
} else {
new CodeCopy();
}
// Explore components banner hover effect
document.addEventListener('DOMContentLoaded', () => {
const banner = document.querySelector('.explore-components-banner a');
if (banner) {
banner.addEventListener('mouseenter', () => {
banner.style.background = '#00cc33';
banner.style.transform = 'translateY(-2px)';
});
banner.addEventListener('mouseleave', () => {
banner.style.background = '#00ff41';
banner.style.transform = 'translateY(0)';
});
}
});
// Copy Markdown functionality
class MarkdownCopier {
constructor() {
this.setupButton();
}
setupButton() {
const button = document.getElementById('copy-markdown-btn');
if (!button) return;
button.addEventListener('click', async () => {
const markdown = this.extractMarkdown();
try {
await navigator.clipboard.writeText(markdown);
// Update button state
const originalContent = button.innerHTML;
button.innerHTML = `
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>
</svg>
Copied!
`;
button.classList.add('copied');
// Reset after 2 seconds
setTimeout(() => {
button.innerHTML = originalContent;
button.classList.remove('copied');
}, 2000);
} catch (err) {
console.error('Failed to copy markdown:', err);
}
});
}
extractMarkdown() {
const title = document.querySelector('.article-title')?.textContent || '';
const subtitle = document.querySelector('.article-subtitle')?.textContent || '';
const date = document.querySelector('time')?.textContent || '';
const content = document.querySelector('.article-content-full');
let markdown = `# ${title}\n\n`;
if (subtitle) {
markdown += `${subtitle}\n\n`;
}
if (date) {
markdown += `*${date}*\n\n`;
}
if (!content) return markdown;
// Process content elements
const elements = content.children;
for (const element of elements) {
markdown += this.processElement(element) + '\n\n';
}
return markdown.trim();
}
processElement(element) {
const tagName = element.tagName.toLowerCase();
switch (tagName) {
case 'h2':
return `## ${element.textContent}`;
case 'h3':
return `### ${element.textContent}`;
case 'h4':
return `#### ${element.textContent}`;
case 'p':
return element.textContent;
case 'ul':
return this.processList(element, '-');
case 'ol':
return this.processList(element, '1.');
case 'pre':
return this.processCodeBlock(element);
case 'div':
if (element.classList.contains('code-block')) {
return this.processCodeBlock(element.querySelector('pre'));
}
// Skip newsletter CTAs and other divs
if (element.classList.contains('newsletter-cta')) {
return '';
}
return element.textContent || '';
case 'img':
const alt = element.getAttribute('alt') || '';
const src = element.getAttribute('src') || '';
return `![${alt}](${src})`;
default:
return element.textContent || '';
}
}
processList(listElement, marker) {
const items = listElement.querySelectorAll('li');
return Array.from(items)
.map(item => `${marker} ${item.textContent}`)
.join('\n');
}
processTable(table) {
const rows = table.querySelectorAll('tr');
if (rows.length === 0) return '';
let markdown = '';
// Process header
const headerRow = rows[0];
const headers = headerRow.querySelectorAll('th, td');
const headerText = Array.from(headers).map(h => h.textContent.trim()).join(' | ');
markdown += `| ${headerText} |\n`;
// Add separator
const separator = Array.from(headers).map(() => '---').join(' | ');
markdown += `| ${separator} |\n`;
// Process body rows
for (let i = 1; i < rows.length; i++) {
const row = rows[i];
const cells = row.querySelectorAll('td, th');
const cellText = Array.from(cells).map(c => c.textContent.trim()).join(' | ');
markdown += `| ${cellText} |\n`;
}
return markdown;
}
processCodeBlock(preElement) {
if (!preElement) return '';
const code = preElement.querySelector('code');
const codeText = code ? code.textContent : preElement.textContent;
// Detect language from parent code-block or code element classes
const codeBlock = preElement.closest('.code-block');
let language = '';
if (codeBlock) {
const languageSpan = codeBlock.querySelector('.code-language');
if (languageSpan) {
language = languageSpan.textContent.toLowerCase();
}
} else if (code && code.className.includes('language-')) {
language = code.className.match(/language-(\w+)/)?.[1] || '';
}
return `\`\`\`${language}\n${codeText}\n\`\`\``;
}
}
// Initialize markdown copier
document.addEventListener('DOMContentLoaded', () => {
new MarkdownCopier();
});
</script>
</body>
</html>