Files
bot/ui/public/skills.html
zooqueenandHanzo Dev 2a2d582eac feat: add Skills Hub with 51 SEO-optimized detail pages + Web3 credits
- Build script (scripts/build-skills-catalog.ts) parses all SKILL.md
  files, outputs JSON catalog and individual detail HTML pages
- Skills Hub list page (/skills) with search, category filters, card grid
- Individual skill pages (/skills/github, etc.) with pre-rendered README,
  metadata sidebar, install commands, GitHub API integration
- Full SEO: unique title, meta description, Open Graph, Twitter Card,
  JSON-LD structured data on every page
- Web3 native messaging: DID identities, wallets, on-chain payments,
  prepaid credit balance model
- Fix stale chat widget system prompt pricing (Pro $5 → actual tiers)
- Add skills:catalog script to package.json

Co-authored-by: Hanzo Dev <[email protected]>
2026-02-13 17:26:25 -08:00

1082 lines
34 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Skills Hub — Hanzo Bot</title>
<meta
name="description"
content="Browse 52+ autonomous AI skills for Hanzo Bot. GitHub, Discord, Notion, Slack, and more. Web3-native with DID identities, wallets, and on-chain payments."
/>
<meta
name="keywords"
content="Hanzo Bot, AI skills, autonomous agents, GitHub, Discord, Slack, Notion, Web3, DID, crypto payments"
/>
<link rel="canonical" href="https://hanzo.bot/skills" />
<!-- Open Graph -->
<meta property="og:title" content="Skills Hub — Hanzo Bot" />
<meta
property="og:description"
content="Browse 52+ autonomous AI skills. Development, Communication, Productivity, Content, Search, and Utilities."
/>
<meta property="og:type" content="website" />
<meta property="og:url" content="https://hanzo.bot/skills" />
<meta property="og:site_name" content="Hanzo Bot" />
<meta property="og:image" content="https://hanzo.bot/og-skills.png" />
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@hanaborteam" />
<meta name="twitter:title" content="Skills Hub — Hanzo Bot" />
<meta
name="twitter:description"
content="Browse 52+ autonomous AI skills for Hanzo Bot. Web3-native with DID, wallets, and on-chain payments."
/>
<!-- JSON-LD -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "CollectionPage",
"name": "Skills Hub — Hanzo Bot",
"description": "Browse and install 52+ autonomous AI skills for Hanzo Bot",
"url": "https://hanzo.bot/skills",
"isPartOf": {
"@type": "WebSite",
"name": "Hanzo Bot",
"url": "https://hanzo.bot"
},
"publisher": {
"@type": "Organization",
"name": "Hanzo AI",
"url": "https://hanzo.ai"
}
}
</script>
<link
rel="icon"
href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🥷</text></svg>"
/>
<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@400;500;600;700&display=swap"
rel="stylesheet"
/>
<style>
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--brand: #fd4444;
--brand-secondary: #ff6b6b;
--bg: #000000;
--bg-card: rgba(255, 255, 255, 0.04);
--bg-hover: #1a1a1a;
--border: rgba(255, 255, 255, 0.08);
--border-hover: rgba(255, 255, 255, 0.16);
--text: #fff;
--muted: #888;
--subtle: #555;
--max-w: 1200px;
--ease: cubic-bezier(0.4, 0, 0.2, 1);
--ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
--font:
"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
sans-serif;
--font-mono: "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
}
html {
scroll-behavior: smooth;
}
body {
font-family: var(--font);
background: var(--bg);
color: var(--text);
line-height: 1.6;
-webkit-font-smoothing: antialiased;
position: relative;
}
body::before {
content: "";
position: fixed;
inset: 0;
background-image:
linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
background-size: 64px 64px;
pointer-events: none;
z-index: 0;
}
body::after {
content: "";
position: fixed;
inset: 0;
opacity: 0.035;
pointer-events: none;
z-index: 0;
background: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
body > * {
position: relative;
z-index: 1;
}
a {
color: inherit;
text-decoration: none;
}
button {
font-family: inherit;
cursor: pointer;
border: none;
background: none;
color: inherit;
}
/* ===== HEADER ===== */
.header {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
background: rgba(0, 0, 0, 0.85);
backdrop-filter: blur(12px);
border-bottom: 1px solid var(--border);
}
.header-inner {
max-width: var(--max-w);
margin: 0 auto;
padding: 0 24px;
height: 56px;
display: flex;
align-items: center;
justify-content: space-between;
}
.header-left {
display: flex;
align-items: center;
gap: 32px;
}
.logo {
display: flex;
align-items: center;
gap: 8px;
}
.logo-mark {
width: 24px;
height: 24px;
}
.logo-mark svg {
width: 100%;
height: 100%;
display: block;
}
.logo-text {
font-size: 15px;
font-weight: 600;
letter-spacing: -0.03em;
}
.nav-links {
display: flex;
gap: 4px;
}
.nav-link {
position: relative;
padding: 8px 12px;
font-size: 13px;
font-weight: 500;
color: var(--muted);
border-radius: 6px;
transition:
color 0.15s,
background 0.15s;
}
.nav-link:hover {
color: var(--text);
background: var(--bg-hover);
}
.nav-link.active {
color: var(--brand);
}
.header-right {
display: flex;
align-items: center;
gap: 8px;
}
.btn-ghost {
padding: 8px 16px;
font-size: 13px;
font-weight: 500;
color: var(--muted);
border-radius: 8px;
transition:
color 0.15s,
background 0.15s;
}
.btn-ghost:hover {
color: var(--text);
background: var(--bg-hover);
}
.btn-primary {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 8px 20px;
font-size: 13px;
font-weight: 600;
color: #fff;
background: var(--brand);
border-radius: 9999px;
transition:
opacity 0.15s,
box-shadow 0.15s;
}
.btn-primary:hover {
opacity: 0.9;
box-shadow: 0 0 24px rgba(253, 68, 68, 0.3);
}
.btn-outline {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 8px 20px;
font-size: 13px;
font-weight: 500;
color: var(--text);
border: 1px solid var(--border);
border-radius: 9999px;
transition:
border-color 0.15s,
background 0.15s,
box-shadow 0.15s;
}
.btn-outline:hover {
border-color: rgba(253, 68, 68, 0.3);
background: rgba(253, 68, 68, 0.06);
}
/* ===== HERO ===== */
.skills-hero {
max-width: var(--max-w);
margin: 0 auto;
padding: 120px 24px 40px;
text-align: center;
position: relative;
}
.skills-hero::before {
content: "";
position: absolute;
top: -100px;
left: 50%;
transform: translateX(-50%);
width: 600px;
height: 600px;
background: radial-gradient(circle, rgba(253, 68, 68, 0.05) 0%, transparent 70%);
pointer-events: none;
}
.hero-badge {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 6px 16px;
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(253, 68, 68, 0.2);
border-radius: 100px;
font-size: 12px;
color: var(--muted);
margin-bottom: 24px;
}
.hero-badge strong {
color: var(--brand);
}
.skills-hero h1 {
font-size: clamp(32px, 5vw, 52px);
font-weight: 700;
letter-spacing: -0.04em;
line-height: 1.1;
margin-bottom: 16px;
}
.gradient-text {
background: linear-gradient(135deg, var(--brand) 0%, #ff8a65 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.skills-hero p {
font-size: 16px;
color: var(--muted);
max-width: 560px;
margin: 0 auto 16px;
line-height: 1.6;
}
.web3-banner {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 6px 14px;
background: rgba(99, 102, 241, 0.08);
border: 1px solid rgba(99, 102, 241, 0.2);
border-radius: 100px;
font-size: 12px;
color: #818cf8;
margin-bottom: 8px;
}
.web3-banner strong {
color: #a5b4fc;
}
.skill-count {
font-size: 13px;
color: var(--subtle);
}
/* ===== FILTER BAR ===== */
.filter-bar {
position: sticky;
top: 56px;
z-index: 50;
background: rgba(0, 0, 0, 0.9);
backdrop-filter: blur(12px);
border-bottom: 1px solid var(--border);
padding: 12px 0;
}
.filter-inner {
max-width: var(--max-w);
margin: 0 auto;
padding: 0 24px;
display: flex;
align-items: center;
gap: 16px;
flex-wrap: wrap;
}
.search-wrap {
position: relative;
flex: 0 0 280px;
}
.search-icon {
position: absolute;
left: 12px;
top: 50%;
transform: translateY(-50%);
width: 16px;
height: 16px;
color: var(--subtle);
pointer-events: none;
}
.search-input {
width: 100%;
padding: 8px 12px 8px 36px;
font-family: var(--font);
font-size: 13px;
color: var(--text);
background: rgba(255, 255, 255, 0.04);
border: 1px solid var(--border);
border-radius: 8px;
outline: none;
transition: border-color 0.15s;
}
.search-input::placeholder {
color: var(--subtle);
}
.search-input:focus {
border-color: rgba(253, 68, 68, 0.3);
}
.category-pills {
display: flex;
gap: 6px;
flex-wrap: wrap;
flex: 1;
}
.pill {
padding: 6px 14px;
font-size: 12px;
font-weight: 500;
color: var(--muted);
background: rgba(255, 255, 255, 0.04);
border: 1px solid var(--border);
border-radius: 100px;
transition: all 0.15s;
white-space: nowrap;
}
.pill:hover {
color: var(--text);
border-color: var(--border-hover);
}
.pill.active {
color: #fff;
background: var(--brand);
border-color: var(--brand);
}
.result-count {
font-size: 12px;
color: var(--subtle);
white-space: nowrap;
}
/* ===== SKILLS GRID ===== */
.skills-grid-wrap {
max-width: var(--max-w);
margin: 0 auto;
padding: 32px 24px 80px;
}
.skills-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 16px;
}
.skill-card {
display: flex;
flex-direction: column;
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 12px;
padding: 20px;
backdrop-filter: blur(16px);
transition:
border-color 0.2s var(--ease),
box-shadow 0.2s var(--ease),
transform 0.2s var(--ease);
cursor: pointer;
}
.skill-card:hover {
border-color: rgba(253, 68, 68, 0.2);
box-shadow: 0 0 40px rgba(253, 68, 68, 0.06);
transform: translateY(-2px);
}
.card-top {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 10px;
}
.card-emoji {
font-size: 28px;
line-height: 1;
flex-shrink: 0;
}
.card-title {
font-size: 15px;
font-weight: 600;
letter-spacing: -0.01em;
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.card-desc {
font-size: 13px;
color: var(--muted);
line-height: 1.5;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
flex: 1;
margin-bottom: 12px;
}
.card-footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.card-category {
display: inline-block;
padding: 2px 8px;
border-radius: 100px;
font-size: 10px;
font-weight: 500;
background: rgba(253, 68, 68, 0.08);
color: var(--brand-secondary);
border: 1px solid rgba(253, 68, 68, 0.15);
}
.card-requires {
font-size: 11px;
color: var(--subtle);
font-family: var(--font-mono);
}
.no-results {
grid-column: 1 / -1;
text-align: center;
padding: 80px 24px;
color: var(--muted);
}
.no-results h3 {
font-size: 20px;
margin-bottom: 8px;
color: var(--text);
}
/* ===== WEB3 SECTION ===== */
.web3-section {
max-width: var(--max-w);
margin: 0 auto;
padding: 0 24px 64px;
}
.web3-card {
background: linear-gradient(
135deg,
rgba(99, 102, 241, 0.06) 0%,
rgba(253, 68, 68, 0.04) 100%
);
border: 1px solid rgba(99, 102, 241, 0.15);
border-radius: 16px;
padding: 40px;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 40px;
align-items: center;
}
.web3-card h2 {
font-size: clamp(24px, 3vw, 32px);
font-weight: 700;
letter-spacing: -0.03em;
margin-bottom: 12px;
}
.web3-card p {
font-size: 14px;
color: var(--muted);
line-height: 1.7;
margin-bottom: 20px;
}
.web3-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
}
.web3-feature {
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(99, 102, 241, 0.12);
border-radius: 10px;
padding: 16px;
}
.web3-feature-icon {
font-size: 20px;
margin-bottom: 8px;
}
.web3-feature h4 {
font-size: 13px;
font-weight: 600;
margin-bottom: 4px;
}
.web3-feature p {
font-size: 12px;
color: var(--subtle);
line-height: 1.5;
margin: 0;
}
/* ===== FOOTER ===== */
.footer {
border-top: 1px solid var(--border);
padding: 64px 24px 32px;
}
.footer-inner {
max-width: var(--max-w);
margin: 0 auto;
}
.footer-grid {
display: grid;
grid-template-columns: 240px repeat(4, 1fr);
gap: 40px;
margin-bottom: 48px;
}
.footer-brand .footer-logo {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 16px;
}
.footer-brand .footer-logo svg {
width: 20px;
height: 20px;
}
.footer-brand .footer-logo span {
font-size: 14px;
font-weight: 600;
}
.footer-brand p {
font-size: 13px;
color: var(--muted);
line-height: 1.6;
margin-bottom: 16px;
}
.footer-social {
display: flex;
gap: 12px;
}
.footer-social a {
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid var(--border);
border-radius: 8px;
color: var(--muted);
transition:
color 0.15s,
border-color 0.15s;
}
.footer-social a:hover {
color: var(--text);
border-color: var(--border-hover);
}
.footer-social svg {
width: 14px;
height: 14px;
}
.footer-col h4 {
font-size: 12px;
font-weight: 500;
letter-spacing: 0.05em;
text-transform: uppercase;
color: var(--subtle);
margin-bottom: 16px;
}
.footer-col a {
display: block;
font-size: 13px;
color: var(--muted);
padding: 3px 0;
transition: color 0.15s;
}
.footer-col a:hover {
color: var(--text);
}
.footer-bottom {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 24px;
border-top: 1px solid var(--border);
font-size: 12px;
color: var(--subtle);
}
/* ===== ANIMATIONS ===== */
@keyframes fade-up {
from {
opacity: 0;
transform: translateY(16px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.fade-in {
animation: fade-up 0.5s var(--ease) both;
}
.fade-in-1 {
animation-delay: 0.1s;
}
.fade-in-2 {
animation-delay: 0.2s;
}
.fade-in-3 {
animation-delay: 0.3s;
}
/* ===== RESPONSIVE ===== */
@media (max-width: 1024px) {
.nav-links {
display: none;
}
.footer-grid {
grid-template-columns: repeat(3, 1fr);
}
.footer-brand {
grid-column: 1 / -1;
}
.web3-card {
grid-template-columns: 1fr;
}
.filter-inner {
flex-direction: column;
align-items: stretch;
}
.search-wrap {
flex: 1 1 auto;
}
}
@media (max-width: 768px) {
.skills-grid {
grid-template-columns: 1fr;
}
.footer-grid {
grid-template-columns: repeat(2, 1fr);
}
.web3-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 480px) {
.skills-hero h1 {
font-size: 28px;
}
.skills-hero {
padding: 100px 16px 32px;
}
.skills-grid-wrap {
padding: 24px 16px 60px;
}
}
</style>
</head>
<body>
<!-- HEADER -->
<header class="header">
<div class="header-inner">
<div class="header-left">
<a href="/" class="logo">
<div class="logo-mark">
<svg viewBox="0 0 67 67" xmlns="http://www.w3.org/2000/svg">
<path d="M22.21 67V44.6369H0V67H22.21Z" fill="#fff" />
<path d="M0 44.6369L22.21 46.8285V44.6369H0Z" fill="#fff" />
<path
d="M66.7038 22.3184H22.2534L0.0878906 44.6367H44.4634L66.7038 22.3184Z"
fill="#fff"
/>
<path d="M22.21 0H0V22.3184H22.21V0Z" fill="#fff" />
<path d="M66.7198 0H44.5098V22.3184H66.7198V0Z" fill="#fff" />
<path d="M66.6753 22.3185L44.5098 20.0822V22.3185H66.6753Z" fill="#fff" />
<path d="M66.7198 67V44.6369H44.5098V67H66.7198Z" fill="#fff" />
</svg>
</div>
<span class="logo-text">Bot</span>
</a>
<nav class="nav-links">
<a href="https://hanzo.ai" class="nav-link">AI</a>
<a href="/" class="nav-link">Home</a>
<a href="/skills" class="nav-link active">Skills</a>
<a href="/book" class="nav-link">Book</a>
<a href="https://docs.hanzo.bot" class="nav-link">Docs</a>
<a href="https://github.com/hanzoai/bot" class="nav-link">GitHub</a>
</nav>
</div>
<div class="header-right">
<a href="https://hanzo.ai/contact" class="btn-ghost">Contact Sales</a>
<a href="/chat" class="btn-primary">Sign In</a>
</div>
</div>
</header>
<!-- HERO -->
<section class="skills-hero">
<div class="web3-banner fade-in">
&#9670; <strong>Web3 Native</strong> &middot; DID identities &middot; Wallets &middot;
On-chain payments
</div>
<h1 class="fade-in fade-in-1"><span class="gradient-text">Skills</span> Hub</h1>
<p class="fade-in fade-in-2">
Browse and install autonomous AI skills for Hanzo Bot. Prefund your account balance and we
draw against your credits as you spend. Every bot ships with a DID identity, integrated
wallet, and crypto payment rails built in.
</p>
<div class="skill-count fade-in fade-in-3" id="skillCount">Loading skills...</div>
</section>
<!-- FILTER BAR -->
<div class="filter-bar">
<div class="filter-inner">
<div class="search-wrap">
<svg
class="search-icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="11" cy="11" r="8" />
<path d="m21 21-4.3-4.3" />
</svg>
<input
type="text"
class="search-input"
id="searchInput"
placeholder="Search skills..."
autocomplete="off"
/>
</div>
<div class="category-pills" id="categoryPills">
<button class="pill active" data-category="all">All</button>
<button class="pill" data-category="Development">Development</button>
<button class="pill" data-category="Communication">Communication</button>
<button class="pill" data-category="Productivity">Productivity</button>
<button class="pill" data-category="Content & Media">Content &amp; Media</button>
<button class="pill" data-category="Search & Info">Search &amp; Info</button>
<button class="pill" data-category="Utilities">Utilities</button>
</div>
<span class="result-count" id="resultCount"></span>
</div>
</div>
<!-- SKILLS GRID -->
<div class="skills-grid-wrap">
<div class="skills-grid" id="skillsGrid">
<!-- Cards injected by JS -->
</div>
</div>
<!-- WEB3 SECTION -->
<section class="web3-section">
<div class="web3-card">
<div>
<h2>Every Bot is <span class="gradient-text">Web3 Native</span></h2>
<p>
Hanzo bots ship with decentralized identities, integrated wallets, and full crypto
payment rails. Prefund your account balance and we draw against your credits as you
spend &mdash; pay with fiat or crypto. Send funds directly to your bots, let them manage
assets, and accept on-chain payments across multiple networks.
</p>
<a href="https://docs.hanzo.bot/web3" class="btn-outline">Learn More</a>
</div>
<div class="web3-grid">
<div class="web3-feature">
<div class="web3-feature-icon">&#128273;</div>
<h4>DID Identity</h4>
<p>Decentralized identifiers for every bot. Verifiable, portable, self-sovereign.</p>
</div>
<div class="web3-feature">
<div class="web3-feature-icon">&#128176;</div>
<h4>Integrated Wallets</h4>
<p>Built-in multi-chain wallets. Send, receive, and manage crypto assets.</p>
</div>
<div class="web3-feature">
<div class="web3-feature-icon">&#9918;</div>
<h4>On-Chain Payments</h4>
<p>Accept and process payments on Ethereum, Solana, and more.</p>
</div>
<div class="web3-feature">
<div class="web3-feature-icon">&#128179;</div>
<h4>Prepaid Credits</h4>
<p>Prefund your balance with fiat or crypto. We draw against credits as you spend.</p>
</div>
</div>
</div>
</section>
<!-- FOOTER -->
<footer class="footer">
<div class="footer-inner">
<div class="footer-grid">
<div class="footer-brand">
<div class="footer-logo">
<svg viewBox="0 0 67 67" xmlns="http://www.w3.org/2000/svg">
<path d="M22.21 67V44.6369H0V67H22.21Z" fill="#fff" />
<path d="M0 44.6369L22.21 46.8285V44.6369H0Z" fill="#fff" />
<path
d="M66.7038 22.3184H22.2534L0.0878906 44.6367H44.4634L66.7038 22.3184Z"
fill="#fff"
/>
<path d="M22.21 0H0V22.3184H22.21V0Z" fill="#fff" />
<path d="M66.7198 0H44.5098V22.3184H66.7198V0Z" fill="#fff" />
<path d="M66.6753 22.3185L44.5098 20.0822V22.3185H66.6753Z" fill="#fff" />
<path d="M66.7198 67V44.6369H44.5098V67H66.7198Z" fill="#fff" />
</svg>
<span>Hanzo</span>
</div>
<p>Build, deploy, and manage autonomous AI agents across every platform.</p>
<div class="footer-social">
<a href="https://x.com/hanaborteam" aria-label="X"
><svg viewBox="0 0 24 24" fill="currentColor">
<path
d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"
/></svg
></a>
<a href="https://linkedin.com/company/hanzo-ai" aria-label="LinkedIn"
><svg viewBox="0 0 24 24" fill="currentColor">
<path
d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"
/></svg
></a>
<a href="https://discord.gg/XthHQQj" aria-label="Discord"
><svg viewBox="0 0 24 24" fill="currentColor">
<path
d="M20.317 4.37a19.791 19.791 0 00-4.885-1.515.074.074 0 00-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 00-5.487 0 12.64 12.64 0 00-.617-1.25.077.077 0 00-.079-.037A19.736 19.736 0 003.677 4.37a.07.07 0 00-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 00.031.057 19.9 19.9 0 005.993 3.03.078.078 0 00.084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 00-.041-.106 13.107 13.107 0 01-1.872-.892.077.077 0 01-.008-.128 10.2 10.2 0 00.372-.292.074.074 0 01.077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 01.078.01c.12.098.246.198.373.292a.077.077 0 01-.006.127 12.299 12.299 0 01-1.873.892.077.077 0 00-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 00.084.028 19.839 19.839 0 006.002-3.03.077.077 0 00.032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 00-.031-.03z"
/></svg
></a>
</div>
</div>
<div class="footer-col">
<h4>Products</h4>
<a href="https://hanzo.ai">Hanzo AI</a>
<a href="https://hanzo.app">Hanzo App</a>
<a href="https://hanzo.bot">Hanzo Bot</a>
<a href="https://hanzo.ai/dev">Hanzo Dev</a>
<a href="https://hanzo.ai/cloud">Hanzo Cloud</a>
<a href="https://hanzo.app/download">Desktop App</a>
<a href="/book">The Hanzo Book</a>
</div>
<div class="footer-col">
<h4>Developers</h4>
<a href="https://docs.hanzo.bot">Documentation</a>
<a href="https://github.com/hanzoai/bot">GitHub</a>
<a href="https://docs.hanzo.bot/api">API Reference</a>
<a href="/skills">Skills Hub</a>
<a href="https://docs.hanzo.bot/cli">CLI Reference</a>
</div>
<div class="footer-col">
<h4>Solutions</h4>
<a href="#">Customer Support</a>
<a href="#">Developer Operations</a>
<a href="#">Marketing</a>
<a href="#">Finance</a>
<a href="#">Security</a>
<a href="#">Enterprise</a>
</div>
<div class="footer-col">
<h4>Company</h4>
<a href="https://hanzo.ai/about">About</a>
<a href="https://hanzo.ai/blog">Blog</a>
<a href="https://hanzo.ai/careers">Careers</a>
<a href="https://hanzo.ai/contact">Contact</a>
<a href="https://hanzo.ai/privacy">Privacy</a>
<a href="https://hanzo.ai/terms">Terms</a>
<a href="https://status.hanzo.ai">Status</a>
</div>
</div>
<div class="footer-bottom">
<span>&copy; 2016&ndash;2026 Hanzo Industries. All rights reserved.</span>
<span>hanzo.ai</span>
</div>
</div>
</footer>
<script>
(function () {
"use strict";
var skills = [];
var activeCategory = "all";
var searchQuery = "";
var grid = document.getElementById("skillsGrid");
var searchInput = document.getElementById("searchInput");
var resultCount = document.getElementById("resultCount");
var skillCount = document.getElementById("skillCount");
var pills = document.querySelectorAll(".pill[data-category]");
// Load catalog
fetch("./skills-catalog.json")
.then(function (r) {
return r.json();
})
.then(function (data) {
skills = data;
skillCount.textContent = skills.length + " skills available";
render();
})
.catch(function () {
grid.innerHTML =
'<div class="no-results"><h3>Could not load skills</h3><p>Try refreshing the page.</p></div>';
skillCount.textContent = "";
});
// Escape HTML for safe insertion
function esc(s) {
var d = document.createElement("div");
d.textContent = s;
return d.innerHTML;
}
// Filter skills
function filtered() {
var q = searchQuery.toLowerCase();
return skills.filter(function (s) {
var matchCat = activeCategory === "all" || s.category === activeCategory;
var matchSearch =
!q ||
s.name.toLowerCase().includes(q) ||
s.slug.toLowerCase().includes(q) ||
s.description.toLowerCase().includes(q);
return matchCat && matchSearch;
});
}
// Render grid
function render() {
var items = filtered();
resultCount.textContent = items.length + " skill" + (items.length !== 1 ? "s" : "");
if (!items.length) {
grid.innerHTML =
'<div class="no-results"><h3>No skills found</h3><p>Try a different search or category.</p></div>';
return;
}
var html = items
.map(function (s) {
var reqs = [];
if (s.requires.bins) reqs = reqs.concat(s.requires.bins);
if (s.requires.anyBins) reqs = reqs.concat(s.requires.anyBins);
if (s.requires.env) reqs = reqs.concat(s.requires.env);
if (s.requires.config) reqs = reqs.concat(s.requires.config);
var reqText = reqs.length ? reqs.slice(0, 2).join(", ") : "";
return (
'<a href="/skills/' +
esc(s.slug) +
'" class="skill-card">' +
'<div class="card-top">' +
'<span class="card-emoji">' +
s.emoji +
"</span>" +
'<span class="card-title">' +
esc(s.name) +
"</span>" +
"</div>" +
'<div class="card-desc">' +
esc(s.description) +
"</div>" +
'<div class="card-footer">' +
'<span class="card-category">' +
esc(s.category) +
"</span>" +
(reqText ? '<span class="card-requires">' + esc(reqText) + "</span>" : "") +
"</div>" +
"</a>"
);
})
.join("");
grid.innerHTML = html;
}
// Search
searchInput.addEventListener("input", function () {
searchQuery = this.value;
render();
});
// Category pills
pills.forEach(function (pill) {
pill.addEventListener("click", function () {
activeCategory = this.getAttribute("data-category");
pills.forEach(function (p) {
p.classList.remove("active");
});
this.classList.add("active");
render();
});
});
// Keyboard shortcut: / to focus search
document.addEventListener("keydown", function (e) {
if (e.key === "/" && document.activeElement !== searchInput) {
e.preventDefault();
searchInput.focus();
}
if (e.key === "Escape" && document.activeElement === searchInput) {
searchInput.blur();
}
});
})();
</script>
</body>
</html>