com um clique
site-scaffold
Generate standardized static site structures. Use when creating new websites, setting up demos, or need consistent site structure with SEO, PWA, and accessibility foundations.
Menu
Generate standardized static site structures. Use when creating new websites, setting up demos, or need consistent site structure with SEO, PWA, and accessibility foundations.
Write Node.js CLI tools with zero dependencies. Use when creating command-line tools, argument parsing, colored output, or interactive prompts.
Modern CSS organization with native @import, @layer cascade control, CSS nesting, design tokens, and element-focused selectors. AUTO-INVOKED when editing .css files.
Define and use custom HTML elements. Use when creating new components, defining custom tags, or using project-specific elements beyond standard HTML5.
Umbrella coordinator for image handling. Coordinates responsive-images, placeholder-images, and automation scripts. Use when adding images to any page, optimizing existing images, or setting up image pipelines.
Generate SVG placeholder images for prototypes. Use when adding placeholder images for layouts, mockups, or development. Supports simple, labeled, and brand-aware types.
Modern responsive image techniques using picture element, srcset, sizes, and modern formats. Use when adding images that need to adapt to different screen sizes, resolutions, or support modern image formats.
| 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 |
Generate standardized static site structures with all essential files for production deployment.
Invoke this skill when:
| 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 |
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
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 |
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>
Use modular @import with @layer for cascade control. The main.css file is an import hub only:
/**
* {{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 | 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 |
@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;
}
}
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 for {{SITE_NAME}}
# {{SITE_URL}}/robots.txt
User-agent: *
Allow: /
# Block error pages
Disallow: /errors/
# Sitemaps
Sitemap: {{SITE_URL}}/sitemap.xml
<?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>
/* TEAM */
Site: {{SITE_NAME}}
Contact: {{SITE_EMAIL}}
/* SITE */
Last update: {{CURRENT_DATE}}
Language: English
Standards: HTML5, CSS3, JavaScript ES6+
{
"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"
}
]
}
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/assets/images/icon-192.png"/>
<TileColor>{{THEME_COLOR}}</TileColor>
</tile>
</msapplication>
</browserconfig>
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)All error pages go in the errors/ directory.
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))
);
}
});
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>
| 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 |
When scaffolding a new site:
npm run icons:sync to populate icons directoryThe scaffold uses the <x-icon> Web Component for icons. Never use inline SVGs for standard icons - always use the x-icon component.
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>
| 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 | 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 |
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 |
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.
<x-icon> component