feat(skills): add create-website skill for zero-build responsive SPAs and showcases

This commit is contained in:
Moritz Graf
2026-09-28 07:37:36 +02:00
parent 7336f7bfff
commit 2bde04617f
7 changed files with 681 additions and 0 deletions
@@ -0,0 +1,210 @@
# Alpine.js Core Patterns for Single-Page Applications ⚡
These zero-build Alpine.js patterns provide reactive state management directly in HTML. Use these snippets to make your single-page websites snappy, interactive, and responsive.
---
## 1. Dark/Light Mode Switcher with Persistence
Place this in `<html x-data="{ darkMode: localStorage.getItem('theme') === 'dark' }" :class="{ 'dark': darkMode }">`:
```html
<button
@click="darkMode = !darkMode; localStorage.setItem('theme', darkMode ? 'dark' : 'light')"
class="p-2.5 rounded-xl border border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-900 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-all cursor-pointer"
title="Toggle Theme">
<i x-show="!darkMode" data-lucide="moon" class="w-5 h-5"></i>
<i x-show="darkMode" data-lucide="sun" class="w-5 h-5"></i>
</button>
```
---
## 2. Dynamic Tab Navigation
Switch between multiple views without page reloads:
```html
<div x-data="{ activeTab: 'overview' }" class="w-full">
<!-- Tab Bar -->
<div class="flex gap-2 p-1.5 bg-zinc-100 dark:bg-zinc-900 rounded-xl max-w-md mx-auto mb-8 border border-zinc-200 dark:border-zinc-800">
<button
@click="activeTab = 'overview'"
:class="activeTab === 'overview' ? 'bg-white dark:bg-zinc-800 text-zinc-900 dark:text-white shadow-sm' : 'text-zinc-500 hover:text-zinc-900 dark:hover:text-white'"
class="flex-1 py-2 px-4 rounded-lg font-medium text-sm transition-all flex items-center justify-center gap-2">
<i data-lucide="layout-grid" class="w-4 h-4"></i> Overview
</button>
<button
@click="activeTab = 'calculator'"
:class="activeTab === 'calculator' ? 'bg-white dark:bg-zinc-800 text-zinc-900 dark:text-white shadow-sm' : 'text-zinc-500 hover:text-zinc-900 dark:hover:text-white'"
class="flex-1 py-2 px-4 rounded-lg font-medium text-sm transition-all flex items-center justify-center gap-2">
<i data-lucide="calculator" class="w-4 h-4"></i> Calculator
</button>
</div>
<!-- Tab Contents with Transitions -->
<div x-show="activeTab === 'overview'" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0 translate-y-2" x-transition:enter-end="opacity-100 translate-y-0">
<!-- Overview View Content -->
</div>
<div x-show="activeTab === 'calculator'" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0 translate-y-2" x-transition:enter-end="opacity-100 translate-y-0">
<!-- Calculator View Content -->
</div>
</div>
```
---
## 3. Instant Search & Category Filter
Real-time filtering of cards or list items:
```html
<div x-data="{
search: '',
activeCategory: 'all',
items: [
{ title: 'Pistazien Gelato', category: 'creami', protein: '28g', calories: 340, desc: 'Reichhaltiges Gelato mit echter sizilianischer Pistazienpaste.' },
{ title: 'Protein Erdbeer Sorbet', category: 'protein', protein: '35g', calories: 210, desc: 'Frisches Erdbeersorbet mit Clear Whey Isolat.' },
{ title: 'Mango Maracuja Slush', category: 'fruit', protein: '2g', calories: 140, desc: 'Perfekte Sommererfrischung mit Mango-Chunks.' }
],
get filteredItems() {
return this.items.filter(item => {
const matchesSearch = item.title.toLowerCase().includes(this.search.toLowerCase()) || item.desc.toLowerCase().includes(this.search.toLowerCase());
const matchesCategory = this.activeCategory === 'all' || item.category === this.activeCategory;
return matchesSearch && matchesCategory;
});
}
}">
<!-- Search & Pills -->
<div class="flex flex-col sm:flex-row gap-4 mb-8">
<div class="relative flex-1">
<i data-lucide="search" class="w-4 h-4 absolute left-3.5 top-3.5 text-zinc-400"></i>
<input
x-model="search"
type="text"
placeholder="Rezepte durchsuchen..."
class="w-full pl-10 pr-4 py-2.5 rounded-xl border border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-900 text-zinc-900 dark:text-white placeholder-zinc-400 focus:outline-none focus:ring-2 focus:ring-cyan-500 text-sm">
</div>
<div class="flex gap-2 overflow-x-auto pb-1">
<template x-for="cat in ['all', 'creami', 'protein', 'fruit']" :key="cat">
<button
@click="activeCategory = cat"
:class="activeCategory === cat ? 'bg-cyan-500 text-white font-semibold' : 'bg-zinc-100 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-400 hover:bg-zinc-200'"
class="px-4 py-2 rounded-xl text-xs uppercase tracking-wider capitalize whitespace-nowrap transition-all cursor-pointer"
x-text="cat === 'all' ? 'Alle Rezepte' : cat">
</button>
</template>
</div>
</div>
<!-- Cards Grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<template x-for="item in filteredItems" :key="item.title">
<div class="p-6 rounded-2xl bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 hover:border-cyan-500/50 shadow-sm hover:shadow-xl transition-all">
<h3 class="text-lg font-bold text-zinc-900 dark:text-white mb-2" x-text="item.title"></h3>
<p class="text-sm text-zinc-500 dark:text-zinc-400 mb-4" x-text="item.desc"></p>
<div class="flex justify-between items-center text-xs font-semibold text-cyan-600 dark:text-cyan-400">
<span x-text="item.protein + ' Protein'"></span>
<span x-text="item.calories + ' kcal'"></span>
</div>
</div>
</template>
</div>
</div>
```
---
## 4. Live Reactive Slider & Calculator
Instant calculations with automatic UI updates:
```html
<div x-data="{
pints: 1,
baseMilk: 300,
baseWhey: 35,
basePistachio: 30,
get milk() { return this.baseMilk * this.pints; },
get whey() { return this.baseWhey * this.pints; },
get pistachio() { return this.basePistachio * this.pints; },
get proteinTotal() { return Math.round(this.whey * 0.8 + (this.milk * 0.034)); },
celebrate() {
if (typeof confetti === 'function') {
confetti({ particleCount: 75, spread: 60, origin: { y: 0.8 } });
}
}
}" class="p-6 rounded-2xl bg-zinc-900 border border-white/10 text-white">
<div class="flex justify-between items-center mb-6">
<h3 class="text-xl font-bold font-heading">Portions-Rechner</h3>
<span class="px-3 py-1 bg-cyan-500/20 text-cyan-400 rounded-full text-xs font-semibold" x-text="pints + (pints === 1 ? ' Pint' : ' Pints')"></span>
</div>
<div class="mb-6">
<label class="block text-xs uppercase tracking-wider text-zinc-400 mb-2">Anzahl Ninja CREAMi Deluxe Pints (680ml)</label>
<input type="range" min="1" max="4" step="1" x-model.number="pints" class="w-full accent-cyan-400 cursor-pointer">
</div>
<!-- Computed Ingredients -->
<div class="space-y-3 mb-6">
<div class="flex justify-between py-2 border-b border-white/5 text-sm">
<span class="text-zinc-400">Milch 1.5% oder Hafermilch</span>
<span class="font-bold text-white" x-text="milk + ' ml'"></span>
</div>
<div class="flex justify-between py-2 border-b border-white/5 text-sm">
<span class="text-zinc-400">Proteinpulver (Whey/Casein)</span>
<span class="font-bold text-cyan-400" x-text="whey + ' g'"></span>
</div>
<div class="flex justify-between py-2 border-b border-white/5 text-sm">
<span class="text-zinc-400">Pistazienmus (100%)</span>
<span class="font-bold text-emerald-400" x-text="pistachio + ' g'"></span>
</div>
</div>
<button @click="celebrate()" class="w-full py-3 bg-gradient-to-r from-cyan-500 to-blue-600 rounded-xl font-bold text-sm hover:brightness-110 active:scale-95 transition-all">
Zutaten vorbereitet! 🎉
</button>
</div>
```
---
## 5. Modal Dialog with Escape & Backdrop Blur
Accessible modal overlay:
```html
<div x-data="{ open: false }">
<button @click="open = true" class="px-4 py-2 bg-zinc-900 text-white rounded-xl text-sm font-medium">
Details öffnen
</button>
<div
x-show="open"
@keydown.escape.window="open = false"
class="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/60 backdrop-blur-sm"
x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
style="display: none;">
<div
@click.outside="open = false"
class="bg-white dark:bg-zinc-900 rounded-2xl max-w-lg w-full p-6 border border-zinc-200 dark:border-zinc-800 shadow-2xl"
x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0 scale-95"
x-transition:enter-end="opacity-100 scale-100">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-bold text-zinc-900 dark:text-white">Modal Titel</h3>
<button @click="open = false" class="text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-200">
<i data-lucide="x" class="w-5 h-5"></i>
</button>
</div>
<p class="text-sm text-zinc-600 dark:text-zinc-400 mb-6">
Hier befindet sich detaillierter Inhalt mit Reaktivität oder Formularen.
</p>
<div class="flex justify-end gap-3">
<button @click="open = false" class="px-4 py-2 text-sm text-zinc-500 hover:text-zinc-800 dark:hover:text-white">Schließen</button>
<button @click="open = false" class="px-4 py-2 text-sm font-medium bg-cyan-500 text-white rounded-xl">Bestätigen</button>
</div>
</div>
</div>
</div>
```
@@ -0,0 +1,38 @@
# Anti-AI-Slop Quality Checklist 🛡️
Before finalizing and publishing any website or HTML artifact, verify every item on this checklist. This ensures the output feels designed by a human senior product designer rather than a generic LLM.
---
## ❌ Forbidden Trappings of "AI Slop"
1. **Never use generic default fonts**:
* 🚫 No raw Inter, Roboto, Arial, or unstyled system-ui.
* ✅ Always import characterful fonts (e.g. *Syne*, *Cabinet Grotesk*, *Fraunces*, *Space Grotesk*, *Plus Jakarta Sans*).
2. **Never use the generic purple-to-indigo gradient**:
* 🚫 `bg-gradient-to-r from-purple-600 to-indigo-600` on white background.
* ✅ Use intentional palettes: deep obsidian with electric cyan accents, warm ivory with terracotta, neo-brutalist yellow with black borders, or slate with emerald glow.
3. **Never generate static, boring centered 3-card rows**:
* 🚫 Three identical white boxes with light gray text centered on a plain gray canvas.
* ✅ Vary card sizes, emphasize a primary card with a border glow or badge, use grid spans (`md:col-span-2`), or add asymmetry.
4. **Never forget interactive micro-interactions**:
* 🚫 Dead buttons that don't react to hover or click.
* ✅ Always add `hover:-translate-y-0.5 hover:shadow-lg transition-all duration-200` and `active:scale-95`.
5. **Never rely on broken external images**:
* 🚫 Using fake URLs like `https://example.com/image.jpg` or placeholder services that fail.
* ✅ Use SVG patterns, Lucide icons, gradient mesh backgrounds, or reliable Unsplash source links with explicit fallback styling.
---
## ✅ Mandatory Pre-Flight Verification
| Check | Requirement | Verified? |
|---|---|:---:|
| **Viewport & Encoding** | `<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">` | [ ] |
| **Tailwind CDN** | `<script src="https://cdn.tailwindcss.com"></script>` included in `<head>` | [ ] |
| **Alpine.js CDN** | `<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>` in `<head>` | [ ] |
| **Lucide Icons** | `<script src="https://unpkg.com/lucide@latest"></script>` + `lucide.createIcons()` at bottom of `<body>` | [ ] |
| **Google Fonts** | Preconnect + Google Font `<link>` + custom `<style>` setting `font-family` | [ ] |
| **Touch Targets** | Buttons and clickable elements have at least `py-2.5 px-4` and `cursor-pointer` | [ ] |
| **Dark Mode Consistency** | If dark mode is supported, all cards, borders, text, and inputs have `dark:` variants | [ ] |
| **Mobile Responsiveness** | Layout uses `grid-cols-1 md:grid-cols-2 lg:grid-cols-3` and responsive paddings (`p-4 md:p-8`) | [ ] |
| **Content Richness** | Real, realistic domain content (no repeated "Lorem Ipsum" filler) | [ ] |
@@ -0,0 +1,122 @@
# Design Archetypes & Visual Systems 🎨
This document defines the 4 core design archetypes used by the `create-website` skill. Every generated website or single-page application must commit fully to one of these visual directions to ensure high aesthetic distinction and eliminate generic AI aesthetics.
---
## 1. Dark Obsidian & Cyber-Luxury 🌌
*Best for: Tech products, developer tools, AI showcases, crypto/finance, dark-mode dashboards, interactive apps.*
### Google Fonts Embed
```html
<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=Plus+Jakarta+Sans:wght@300;400;500;600;700&family=Syne:wght@600;700;800&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
body { font-family: 'Plus Jakarta Sans', sans-serif; }
h1, h2, h3, .font-heading { font-family: 'Syne', sans-serif; }
code, pre, .font-mono { font-family: 'JetBrains Mono', monospace; }
</style>
```
### Color Palette & Classes
* **Canvas Background**: `bg-[#090A0F]` with subtle radial gradients:
`bg-[radial-gradient(ellipse_80%_80%_at_50%_-20%,rgba(120,119,198,0.15),rgba(255,255,255,0))]`
* **Card Surface (Glassmorphism)**: `bg-white/[0.03] backdrop-blur-xl border border-white/10 hover:border-white/20 transition-all`
* **Secondary Surface**: `bg-[#12151E] border border-white/5`
* **Text Hierarchy**: Headings `text-white font-bold tracking-tight`, Body `text-zinc-400`, Subtle `text-zinc-500`
* **Accent Highlights**:
* Electric Cyan: `text-cyan-400 bg-cyan-500/10 border-cyan-500/20 shadow-[0_0_20px_rgba(6,182,212,0.15)]`
* Neon Violet: `text-purple-400 bg-purple-500/10 border-purple-500/20`
* Emerald Glow: `text-emerald-400 bg-emerald-500/10 border-emerald-500/20`
* **Buttons**:
* Primary: `bg-gradient-to-r from-cyan-500 to-blue-600 hover:from-cyan-400 hover:to-blue-500 text-white font-medium px-5 py-2.5 rounded-xl shadow-lg shadow-cyan-500/20 active:scale-95 transition-all`
* Secondary: `bg-white/5 hover:bg-white/10 text-white border border-white/10 px-5 py-2.5 rounded-xl active:scale-95 transition-all`
---
## 2. Editorial Warmth & Swiss Typographic 📰
*Best for: In-depth research dossiers, long-form journalism, recipe collections, personal manifestos, architectural notes, knowledge collections.*
### Google Fonts Embed
```html
<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=Fraunces:ital,opsz,wght@0,9..144,300..700;1,9..144,300..700&family=Instrument+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
body { font-family: 'Instrument Sans', sans-serif; }
h1, h2, h3, .font-heading { font-family: 'Fraunces', serif; }
</style>
```
### Color Palette & Classes
* **Canvas Background**: Warm Ivory `bg-[#FDFBF7]` or Linen `bg-[#F7F4EE]`
* **Card Surface**: Paper White `bg-white border border-stone-200/80 shadow-sm rounded-2xl`
* **Text Hierarchy**: Headings `text-stone-900 font-semibold tracking-tight`, Body `text-stone-600 leading-relaxed`, Captions `text-stone-500 text-sm`
* **Accent Highlights**:
* Heritage Rust / Terracotta: `text-[#C2410C] bg-[#FFF7ED] border-[#FDBA74]`
* Deep Forest: `text-[#166534] bg-[#F0FDF4] border-[#BBF7D0]`
* Warm Amber: `text-[#B45309] bg-[#FEF3C7] border-[#FDE68A]`
* **Styling Rules**:
* Generous margins and breathing room (`py-16 md:py-24 max-w-4xl mx-auto`).
* Elegant divider rules (`border-t border-stone-200`).
* Dropcaps or serif quotes with subtle italic styling (`italic text-stone-700`).
---
## 3. Neo-Brutalism & High-Energy ⚡
*Best for: Interactive party invites, festival schedules, fitness challenges, hackathon pitches, playful calculators, game companions.*
### Google Fonts Embed
```html
<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=Space+Grotesk:wght@500;700&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
<style>
body { font-family: 'Space Grotesk', sans-serif; }
code, pre, .font-mono { font-family: 'JetBrains Mono', monospace; }
</style>
```
### Color Palette & Classes
* **Canvas Background**: High-contrast Pale Pastel `bg-[#FAF8F5]` or Off-Yellow `bg-[#FEFCE8]`
* **Borders & Shadows**:
* Signature Shadow: `border-2 border-black shadow-[4px_4px_0px_0px_#000] hover:shadow-[2px_2px_0px_0px_#000] hover:translate-x-[2px] hover:translate-y-[2px] transition-all`
* Card: `bg-white border-2 border-black shadow-[5px_5px_0px_0px_#000] rounded-xl p-6`
* **Color Accents**:
* Electric Canary: `bg-[#FDE047]`
* Acid Lime: `bg-[#A3E635]`
* Bright Coral: `bg-[#FB7185]`
* Cyan Pill: `bg-[#38BDF8]`
* **Interactive Elements**:
* Badges: `inline-block px-3 py-1 text-xs font-bold uppercase tracking-wider bg-black text-white rounded-md`
* Buttons: `bg-[#FDE047] hover:bg-[#FACC15] text-black font-bold px-6 py-3 border-2 border-black shadow-[4px_4px_0px_0px_#000] active:translate-x-[4px] active:translate-y-[4px] active:shadow-none transition-all rounded-xl cursor-pointer`
---
## 4. Modern Clean SaaS & Dynamic Dashboard 📊
*Best for: Multi-tab trackers, data analytics, KPI summaries, filterable catalogues, interactive calculators, recipe managers.*
### Google Fonts Embed
```html
<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=Outfit:wght@400;500;600;700&family=Plus+Jakarta+Sans:wght@400;500;600&display=swap" rel="stylesheet">
<style>
body { font-family: 'Plus Jakarta Sans', sans-serif; }
h1, h2, h3, .font-heading { font-family: 'Outfit', sans-serif; }
</style>
```
### Color Palette & Classes
* **Canvas Background**: Adaptive Light/Dark:
`bg-slate-50 text-slate-900 dark:bg-slate-950 dark:text-slate-100 transition-colors duration-200`
* **Card Surface**:
`bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl shadow-sm hover:shadow-md transition-all`
* **KPI Metrics**:
* Value: `text-3xl md:text-4xl font-bold font-heading tracking-tight text-slate-900 dark:text-white`
* Label: `text-xs font-medium uppercase tracking-wider text-slate-500 dark:text-slate-400 mt-1`
* **Interactive Controls**:
* Inputs: `bg-slate-100 dark:bg-slate-800 border-none rounded-xl px-4 py-2 text-sm focus:ring-2 focus:ring-indigo-500`
* Active Tabs: `bg-indigo-600 text-white rounded-lg px-4 py-2 font-medium shadow-sm`
* Inactive Tabs: `text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white px-4 py-2 rounded-lg`