| name | site-scaffold |
| description | Generate standardized static site structures. Use when creating new websites, setting up demos, or need consistent site structure with SEO, PWA, and accessibility foundations. |
| allowed-tools | Read, Write, Edit, Glob, Grep |
Site Scaffold Skill
Generate standardized static site structures with all essential files for production deployment.
When to Use
Invoke this skill when:
- Creating a new static website from scratch
- Setting up a demo or prototype site
- Need consistent site structure with SEO, PWA, and accessibility foundations
Skills to Consider Before Using
| Task | Invoke Skill | Why |
|---|---|---|
| Writing HTML content | xhtml-author | XHTML-strict patterns, semantic structure |
| Styling components | css-author | Modular CSS, @layer cascade, design tokens |
| Page metadata | metadata | SEO, Open Graph, Twitter Cards |
| Icons | icons | Use <x-icon> component, Lucide library |
| Forms | forms | <form-field> custom element, validation |
| Patterns/sections | patterns | Hero, features, CTA, cards, navigation |
Standard Site Structure
site-name/
├── index.html # Homepage
├── about/
│ └── index.html # About page (folder-based for clean URLs)
├── contact/
│ └── index.html # Contact page
├── errors/ # Error and fallback pages
│ ├── 404.html # Not found
│ ├── 500.html # Server error (inline CSS, no deps)
│ ├── offline.html # Service worker fallback
│ └── noscript.html # JS-disabled fallback
├── assets/
│ ├── css/
│ │ ├── main.css # @import hub only
│ │ ├── _reset.css # CSS reset
│ │ ├── _tokens.css # Design tokens (colors, spacing, etc.)
│ │ ├── _base.css # Base element styles
│ │ ├── _layout.css # Semantic layout (header, main, footer)
│ │ ├── _utilities.css # Helper classes
│ │ ├── sections/ # Section-specific styles
│ │ │ ├── _header.css
│ │ │ └── _footer.css
│ │ ├── components/ # Reusable component styles
│ │ │ ├── _skip-link.css
│ │ │ └── _buttons.css
│ │ └── pages/ # Page-specific styles
│ │ ├── _home.css
│ │ └── _error.css
│ ├── js/
│ │ ├── main.js # Progressive enhancement script
│ │ └── components/ # Web Components
│ │ └── x-icon/ # Icon component
│ └── images/
│ ├── favicon.svg # Vector favicon (modern browsers)
│ ├── favicon.ico # Legacy favicon (32x32)
│ ├── apple-touch-icon.png # iOS icon (180x180)
│ ├── icon-192.png # PWA icon small
│ ├── icon-512.png # PWA icon large
│ ├── logo.svg # Site logo
│ └── og-image.png # Social sharing (1200x630)
├── .well-known/
│ └── security.txt # Security contact info (RFC 9116)
├── robots.txt # Search engine directives
├── humans.txt # Credits and team info
├── sitemap.xml # XML sitemap for crawlers
├── manifest.json # PWA web app manifest
└── browserconfig.xml # Windows tile configuration
Required Configuration
When scaffolding, collect these values:
| Variable | Example | Description |
|---|---|---|
SITE_NAME |
Acme Corporation | Display name for title, headers |
SITE_URL |
https://acme.example.com | Production URL (no trailing slash) |
SITE_DESCRIPTION |
We make quality widgets | Meta description (max 160 chars) |
SITE_AUTHOR |
Acme Inc | Author or organization |
SITE_EMAIL |
hello@acme.example.com | Contact email |
THEME_COLOR |
#1e40af | Primary brand color (hex) |
BACKGROUND_COLOR |
#ffffff | PWA background (hex) |
CURRENT_YEAR |
2025 | For copyright notices |
HTML Template Structure
All HTML pages must follow XHTML-strict patterns:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<!-- Primary Meta -->
<title>Page Title - {{SITE_NAME}}</title>
<meta name="description" content="{{SITE_DESCRIPTION}}"/>
<meta name="author" content="{{SITE_AUTHOR}}"/>
<meta name="referrer" content="strict-origin-when-cross-origin"/>
<meta name="robots" content="index, follow"/>
<!-- Canonical URL -->
<link rel="canonical" href="{{SITE_URL}}/"/>
<!-- Favicon Set -->
<link rel="icon" href="/assets/images/favicon.svg" type="image/svg+xml"/>
<link rel="icon" href="/assets/images/favicon.ico" sizes="32x32"/>
<link rel="apple-touch-icon" href="/assets/images/apple-touch-icon.png"/>
<!-- PWA -->
<link rel="manifest" href="/manifest.json"/>
<meta name="theme-color" content="{{THEME_COLOR}}"/>
<!-- Open Graph -->
<meta property="og:type" content="website"/>
<meta property="og:url" content="{{SITE_URL}}/"/>
<meta property="og:site_name" content="{{SITE_NAME}}"/>
<meta property="og:title" content="Page Title"/>
<meta property="og:description" content="{{SITE_DESCRIPTION}}"/>
<meta property="og:image" content="{{SITE_URL}}/assets/images/og-image.png"/>
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:title" content="Page Title"/>
<meta name="twitter:description" content="{{SITE_DESCRIPTION}}"/>
<meta name="twitter:image" content="{{SITE_URL}}/assets/images/og-image.png"/>
<!-- Styles -->
<link rel="stylesheet" href="/assets/css/main.css"/>
</head>
<body>
<a href="#main" class="skip-link">Skip to main content</a>
<header>
<!-- Site header with logo and navigation -->
</header>
<main id="main">
<!-- Page content -->
</main>
<footer>
<!-- Site footer -->
</footer>
<script type="module" src="/assets/js/components/x-icon/x-icon.js"></script>
<script src="/assets/js/main.js" defer=""></script>
</body>
</html>
CSS Structure
Use modular @import with @layer for cascade control. The main.css file is an import hub only:
main.css (Hub File)
/**
* {{SITE_NAME}} - Main Stylesheet
* Modular CSS architecture with @layer cascade control
*/
@layer reset, tokens, base, layout, sections, components, pages, utilities;
/* Core */
@import "_reset.css" layer(reset);
@import "_tokens.css" layer(tokens);
@import "_base.css" layer(base);
@import "_layout.css" layer(layout);
/* Sections */
@import "sections/_header.css" layer(sections);
@import "sections/_footer.css" layer(sections);
/* Components */
@import "components/_skip-link.css" layer(components);
@import "components/_buttons.css" layer(components);
/* Pages */
@import "pages/_home.css" layer(pages);
@import "pages/_error.css" layer(pages);
/* Utilities */
@import "_utilities.css" layer(utilities);
Layer Responsibilities
| Layer | Purpose | Examples |
|---|---|---|
| reset | Normalize browser defaults | box-sizing, margin resets |
| tokens | Design tokens | colors, spacing, typography |
| base | Default element styles | body, headings, links |
| layout | Semantic containers | header, main, footer, section |
| sections | Page section styles | hero, features, cta |
| components | Reusable UI patterns | buttons, cards, forms |
| pages | Page-specific overrides | home, about, error |
| utilities | Helper classes | visually-hidden, skip-link |
_tokens.css Example
@layer tokens {
:root {
/* Colors */
--color-primary: {{THEME_COLOR}};
--color-primary-dark: color-mix(in srgb, var(--color-primary) 80%, black);
--color-secondary: #059669;
--color-text: #1f2937;
--color-text-light: #6b7280;
--color-bg: #ffffff;
--color-bg-alt: #f3f4f6;
--color-border: #e5e7eb;
/* Spacing */
--space-xs: 0.25rem;
--space-sm: 0.5rem;
--space-md: 1rem;
--space-lg: 2rem;
--space-xl: 4rem;
/* Typography */
--font-family: system-ui, -apple-system, sans-serif;
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.25rem;
--font-size-xl: 1.5rem;
--font-size-2xl: 2rem;
--font-size-3xl: 2.5rem;
/* Layout */
--max-width: 1200px;
--border-radius: 6px;
}
}
JavaScript Pattern
Use DOMContentLoaded with init function:
/**
* Site initialization
* Progressive enhancement - site works without JS
*/
document.addEventListener('DOMContentLoaded', init);
function init() {
initNavigation();
initForms();
}
function initNavigation() {
// Mobile menu, dropdowns, etc.
}
function initForms() {
// Form validation, submission handling
}
robots.txt Template
# Robots.txt for {{SITE_NAME}}
# {{SITE_URL}}/robots.txt
User-agent: *
Allow: /
# Block error pages
Disallow: /errors/
# Sitemaps
Sitemap: {{SITE_URL}}/sitemap.xml
sitemap.xml Template
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>{{SITE_URL}}/</loc>
<lastmod>{{CURRENT_DATE}}</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>{{SITE_URL}}/about/</loc>
<lastmod>{{CURRENT_DATE}}</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
</urlset>
humans.txt Template
/* TEAM */
Site: {{SITE_NAME}}
Contact: {{SITE_EMAIL}}
/* SITE */
Last update: {{CURRENT_DATE}}
Language: English
Standards: HTML5, CSS3, JavaScript ES6+
manifest.json Template
{
"name": "{{SITE_NAME}}",
"short_name": "{{SITE_SHORT_NAME}}",
"description": "{{SITE_DESCRIPTION}}",
"start_url": "/",
"display": "standalone",
"background_color": "{{BACKGROUND_COLOR}}",
"theme_color": "{{THEME_COLOR}}",
"icons": [
{
"src": "/assets/images/icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/assets/images/icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
browserconfig.xml Template
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/assets/images/icon-192.png"/>
<TileColor>{{THEME_COLOR}}</TileColor>
</tile>
</msapplication>
</browserconfig>
security.txt Template
Place in .well-known/security.txt (RFC 9116):
# Security contact for {{SITE_NAME}}
# {{SITE_URL}}/.well-known/security.txt
Contact: mailto:security@example.com
Expires: 2026-12-31T23:59:00.000Z
Preferred-Languages: en
Canonical: {{SITE_URL}}/.well-known/security.txt
# Optional
Policy: {{SITE_URL}}/security-policy
Acknowledgments: {{SITE_URL}}/security-thanks
Required fields:
Contact:- Email or URL for security reportsExpires:- ISO 8601 date (must be renewed annually)
Error Pages
All error pages go in the errors/ directory.
errors/404.html
- Friendly message explaining page not found
- Link back to homepage
- Same header/footer as main site
- Search functionality (optional)
errors/500.html
- Apologetic message for server error
- Inline critical CSS (no external stylesheet dependency)
- Contact information for support
- No dynamic content
errors/offline.html
Service worker fallback with inline styles:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Offline - {{SITE_NAME}}</title>
<meta name="robots" content="noindex"/>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
max-width: 600px;
margin: 4rem auto;
padding: 1rem;
text-align: center;
color: #1f2937;
}
h1 { color: #4b5563; }
.icon { font-size: 4rem; margin-bottom: 1rem; }
a { color: #2563eb; }
</style>
</head>
<body>
<div class="icon" aria-hidden="true">📡</div>
<h1>You're Offline</h1>
<p>It looks like you've lost your internet connection.</p>
<p>Please check your connection and <a href="/">try again</a>.</p>
</body>
</html>
Register in service worker:
const OFFLINE_PAGE = '/errors/offline.html';
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('offline-v1').then((cache) => cache.add(OFFLINE_PAGE))
);
});
self.addEventListener('fetch', (event) => {
if (event.request.mode === 'navigate') {
event.respondWith(
fetch(event.request).catch(() => caches.match(OFFLINE_PAGE))
);
}
});
errors/noscript.html
Fallback for JavaScript-required applications:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>JavaScript Required - {{SITE_NAME}}</title>
<meta name="robots" content="noindex"/>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
max-width: 600px;
margin: 4rem auto;
padding: 1rem;
text-align: center;
color: #1f2937;
}
h1 { color: #4b5563; }
.icon { font-size: 4rem; margin-bottom: 1rem; }
a { color: #2563eb; }
code { background: #f3f4f6; padding: 0.2em 0.4em; border-radius: 4px; }
</style>
</head>
<body>
<div class="icon" aria-hidden="true">⚙️</div>
<h1>JavaScript Required</h1>
<p>This application requires JavaScript to function properly.</p>
<p>Please enable JavaScript in your browser settings and <a href="/">reload the page</a>.</p>
<details>
<summary>How to enable JavaScript</summary>
<ul style="text-align: left;">
<li><strong>Chrome:</strong> Settings → Privacy and security → Site settings → JavaScript</li>
<li><strong>Firefox:</strong> Type <code>about:config</code> in address bar, search for <code>javascript.enabled</code></li>
<li><strong>Safari:</strong> Preferences → Security → Enable JavaScript</li>
<li><strong>Edge:</strong> Settings → Cookies and site permissions → JavaScript</li>
</ul>
</details>
</body>
</html>
Use with <noscript> redirect:
<head>
<noscript>
<meta http-equiv="refresh" content="0; url=/errors/noscript.html"/>
</noscript>
</head>
Favicon Requirements
| File | Size | Purpose |
|---|---|---|
| favicon.svg | Vector | Modern browsers, scales perfectly |
| favicon.ico | 32x32 | Legacy browser support |
| apple-touch-icon.png | 180x180 | iOS home screen |
| icon-192.png | 192x192 | Android/PWA small |
| icon-512.png | 512x512 | Android/PWA large, splash |
| og-image.png | 1200x630 | Social sharing preview |
Checklist
When scaffolding a new site:
Core Files
- Create directory structure
- Generate index.html with full meta tags
- Create about/index.html and contact/index.html
- Create robots.txt with sitemap reference
- Create sitemap.xml with all pages
- Create humans.txt with team info
- Create manifest.json for PWA
- Create browserconfig.xml for Windows
Error & Fallback Pages
- Generate errors/404.html
- Generate errors/500.html (inline CSS, no external deps)
- Create errors/offline.html for service worker
- Create errors/noscript.html (if app requires JavaScript)
Security
- Create .well-known/security.txt with contact info
Assets
- Set up modular CSS with @layer and @import
- Set up JS with init pattern
- Create/copy favicon set
- Create og-image.png for social sharing
- Copy x-icon component to assets/js/components/
- Copy required Lucide icons to assets/icons/lucide/
- Run
npm run icons:syncto populate icons directory
Validation
- Validate all HTML files pass linters
- Test error pages render correctly
- Verify security.txt is accessible at /.well-known/security.txt
Icons Usage
The scaffold uses the <x-icon> Web Component for icons. Never use inline SVGs for standard icons - always use the x-icon component.
Required x-icon Script
Include in all HTML pages (except 500, offline, noscript):
<script type="module" src="/assets/js/components/x-icon/x-icon.js"></script>
<script src="/assets/js/main.js" defer=""></script>
Common Icons Used
| Icon | Usage | Example |
|---|---|---|
menu |
Mobile navigation toggle | <x-icon name="menu"></x-icon> |
zap |
Feature card (speed/performance) | <x-icon name="zap" size="lg"></x-icon> |
lock |
Feature card (security) | <x-icon name="lock" size="lg"></x-icon> |
info |
Feature card (information) | <x-icon name="info" size="lg"></x-icon> |
mail |
Contact method (email) | <x-icon name="mail"></x-icon> |
map-pin |
Contact method (location) | <x-icon name="map-pin"></x-icon> |
clock |
Contact method (response time) | <x-icon name="clock"></x-icon> |
twitter |
Social link | <x-icon name="twitter"></x-icon> |
github |
Social link | <x-icon name="github"></x-icon> |
linkedin |
Social link | <x-icon name="linkedin"></x-icon> |
frown |
404 error page | <x-icon name="frown" size="2xl"></x-icon> |
Size Presets
| Size | CSS Value | Use Case |
|---|---|---|
xs |
1em | Inline text icons |
sm |
1.25em | Small buttons |
md |
1.5em (default) | Navigation, social links |
lg |
2em | Feature cards |
xl |
2.5em | Section headers |
2xl |
3em | Error page icons |
Icon Exceptions (Use Inline SVGs)
Some pages must use inline SVGs for reliability:
| Page | Reason |
|---|---|
errors/500.html |
No external dependencies (server may be down) |
errors/offline.html |
No network access to load x-icon |
errors/noscript.html |
JavaScript disabled, x-icon won't work |
| Site logo | Brand-specific, not in Lucide library |
Icons Directory Structure
assets/
├── icons/
│ └── lucide/ # Lucide SVG icons (auto-synced)
│ ├── menu.svg
│ ├── zap.svg
│ └── ...
└── js/
└── components/
└── x-icon/
├── x-icon.js
└── x-icon-styles.js
Run npm run icons:sync after scaffolding to populate the icons directory.
Related Skills
- xhtml-author - Write valid XHTML-strict HTML5 markup
- css-author - Modern CSS organization with native @import, @layer cascade
- metadata - HTML metadata and head content
- performance - Write performance-friendly HTML pages
- icons - Lucide icons with
<x-icon>component - patterns - Reusable section and component patterns