返回 Skill 列表
extension
分类: 开发与工程无需 API Key

site-scaffold

生成标准化的静态网站结构。在创建新网站、设置演示或需要具有SEO、PWA和可访问性基础的一致站点结构时使用。

person作者: jakexiaohubgithub

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 reports
  • Expires: - 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:sync to 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