first publish

This commit is contained in:
2026-09-06 17:21:52 +02:00
commit b8e41b4d55
147 changed files with 19367 additions and 0 deletions

View File

@@ -0,0 +1,178 @@
# Anelia Wolf Build-Plan & Komponenten-Vertrag
Stand: 2026-09-02 · Grundlage: `docs/superpowers/specs/2026-09-02-anelia-wolf-website-design.md`
(Abschnitt A = verbindliche Abweichungen, danach die Jury-Synthese). Dieser Plan ist der Vertrag,
nach dem parallel arbeitende Agenten bauen. **Pfade, Exportnamen und Props sind verbindlich.**
## 0. Bereits vorhanden (nicht neu anlegen, nur erweitern)
- `next.config.ts` (static export, trailingSlash), `src/app/globals.css` (Tokens, `.grain`, `.gold-text`,
`.rule-gold`, `[data-theme]`), `src/app/layout.tsx` (Fonts Jost/DM Mono/Bodoni Moda → `--font-jost`,
`--font-mono-face`, `--font-bodoni`; Tailwind `font-sans`/`font-mono`/`font-display`; Skip-Link; `SmoothScroll`).
- `src/lib/site.ts` (`site`, `nav`, `legal`), `src/lib/utils.ts` (`cn`), `src/hooks/usePrefersReducedMotion.ts`,
`src/components/providers/SmoothScroll.tsx` (Lenis + GSAP-Ticker, `window.lenis`).
- `src/components/brand/WolfMark.tsx` (SVG-Näherung des Monogramms; Klassen `.wolfmark-v`, `.wolfmark-wolf`,
Pfade mit `data-draw` + `pathLength="1"`, Gradient-Id `${idPrefix}wolf-gold`; Props `className`, `title`,
`idPrefix`, `strokeWidth`). **Nicht verändern.**
- `public/brand/README.md`, `public/photos/README.md` (Drop-in-Slots), `.claude/launch.json` (`anelia-dev`, Port 3000).
Pakete: next 16.3, react 19.2, tailwindcss 4.3, motion 13 (`motion/react`), gsap 3.15 (`gsap/ScrollTrigger`,
`gsap/SplitText`, `gsap/DrawSVGPlugin` alle frei), lenis 1.3, clsx, tailwind-merge. Nichts weiteres installieren
außer `server-only` (falls gewünscht).
Tailwind v4: Utilities aus den Tokens: `bg-ink bg-ink-2 bg-ivory bg-bone text-gold text-gold-deep text-grey-warm
text-grey-deep border-line-dark border-line-light` und Live-Tokens `bg-bg text-fg text-fg-muted text-accent
border-line bg-surface`. Schrift: `font-sans` (Jost), `font-mono` (DM Mono), `font-display` (Bodoni Moda).
## 1. Globale Regeln für alle Agenten
1. Next 16 App Router, statischer Export: Server-Komponenten standardmäßig; `"use client"` nur wo Hooks/DOM.
Keine `params`/`searchParams`, keine Route Handler, keine `fetch` zur Laufzeit, kein `localStorage`/`sessionStorage`/
`document.cookie`, keine externen Skripte/iframes/Fonts. Externe Links `target="_blank" rel="noopener noreferrer"`.
2. Alle GSAP-Nutzung in `useEffect`/`useLayoutEffect` mit `gsap.context()` + `ctx.revert()` im Cleanup; Plugins
nur über `src/lib/gsap.ts`. `gsap.matchMedia()` mit Bedingungen `reduce: "(prefers-reduced-motion: reduce)"`,
`desktop: "(min-width: 1024px) and (pointer: fine)"`.
3. Reduced motion: Endzustand sofort sichtbar. Ohne JS: Inhalte sichtbar (Initialzustände nur unter `html.js`
setzen `layout.tsx` fügt ein 1-Zeilen-Inline-Script hinzu, das `document.documentElement.classList.add("js")` setzt).
4. Bodoni Moda nie < 28 px; Gold-Text (`text-gold`, `.gold-text`) nur in `data-theme="dark"`; auf hell `text-gold-deep`.
Radius 0 überall, keine Schatten, kein Bold (max. 500), ein Italic-Wort pro Headline (`<em>` in `font-display italic`).
5. Alle Texte kommen aus `src/content/*.ts` kein Copy in JSX. Deutsche Anführungszeichen „…“, Gedankenstrich „–“.
6. Ein `<h1>` pro Seite, Landmarken (`header`, `main#inhalt`, `footer`), Alt-Texte, sichtbarer Fokus.
7. Jeder Agent arbeitet NUR in den ihm zugewiesenen Dateien. Fremde Dateien werden importiert, nicht editiert.
Am Ende `npx tsc --noEmit`; Fehler in eigenen Dateien beheben. Fehlende Module aus dem Vertrag (noch nicht
gebaut) sind der einzige erlaubte Fehlertyp und werden gemeldet.
8. Kein `next dev`/`next build` durch Foundation-/Page-Agenten (nur `tsc`). Build und Browser-QA übernehmen die
Integrations-/QA-Agenten.
## 2. Komponenten-Vertrag
### 2.1 `src/lib/gsap.ts` (F1)
```ts
export { gsap, ScrollTrigger, SplitText, DrawSVGPlugin }; // registriert, SSR-sicher (typeof window guard)
export const EASE = { out: "expo.out", inOut: "power3.inOut", none: "none" } as const;
export const DUR = { micro: 0.3, reveal: 0.6, lines: 0.9, door: 1.1, draw: 1.2, sheen: 0.8, rule: 0.9 } as const;
export const MM = { reduce: "(prefers-reduced-motion: reduce)", desktop: "(min-width: 1024px) and (pointer: fine)", touch: "(pointer: coarse)" } as const;
```
### 2.2 `src/lib/site.ts` (F2 erweitert)
```ts
export const flags = { showPlaceholders: true, showFaq: true, showStimmen: false, showSpeakerPdf: false,
showSecondTalk: false, show24hPromise: false, showIndustry: false, showTwins: true } as const;
export const routes = { home: "/", coaching: "/leistungen/coaching/", trainings: "/leistungen/trainings/",
keynotes: "/leistungen/keynotes/", impressum: "/impressum/", datenschutz: "/datenschutz/" } as const;
export const mailto = { kennenlernen: "mailto:info@anelia-wolf.com?subject=Kennenlerngespr%C3%A4ch",
training: "mailto:info@anelia-wolf.com?subject=Training%20anfragen", keynote: "mailto:info@anelia-wolf.com?subject=Keynote%20anfragen" } as const;
```
### 2.3 `src/lib/assets.ts` (F2, nur in Server-Komponenten importieren)
```ts
export function hasPublicFile(relPath: string): boolean; // fs.existsSync(path.join(process.cwd(), "public", relPath))
export function getPhotos(): { hero: string | null; portrait: string | null; stage: string | null };
export function getLogoSvg(): string | null; // Inhalt von public/brand/logo-mark.svg oder null
```
### 2.4 `src/lib/legal.ts` (F2)
```ts
export const LEGAL_TODO: string[]; // offene Pflichtangaben
export function ph(label: string): string; // liefert "[label]" Platzhalter-Text
```
### 2.5 Content (F2) `src/content/*.ts`, alle `as const`, Typen exportieren
- `home.ts`: `hero`, `positioning`, `services`, `principle`, `about`, `audience`, `contact` (+ `termine`) Copy 1:1 aus Spec §6.
- `coaching.ts`, `trainings.ts`, `keynotes.ts`: `{ meta: {title, description}, masthead, eyebrow, h1: {before, em, after},
subline, cta: {label, href, suffix?, micro?}, facts: {label, value}[], situations: {h2, rows[]}, questions?, modules,
rahmen, ablauf, faq, band: {h2, cta, micro} , ... }` Copy 1:1 aus Spec §7.
- `legal.ts`: Impressum- und Datenschutz-Abschnitte (`{ h2, paragraphs[] }[]`) aus `docs/superpowers/specs/legal-templates.md`,
Platzhalter über `ph()`; kein OS-Plattform-Link; „Bezeichnung WOLF-Prinzip“.
### 2.6 Motion-Primitive (F1) `src/components/motion/`
```tsx
<Rule variant?: "gold" | "line" = "line"; origin?: "left" | "center" | "right" | number /* px vom linken Rand */;
play?: "view" | "load" = "view"; delay?: number; className?: string /> // 1px, scaleX 0→1, once
<Lines as?: "h1"|"h2"|"h3"|"p"|"div"; play?: "view" | "load"; delay?; stagger?; className?>children</Lines>
// SplitText lines + mask; wartet document.fonts.ready (Timeout 1.5s); reduce → statisch; setzt aria-label
<Reveal as?; play?: "view"|"load"; delay?; y?=16; className?>children</Reveal> // motion whileInView, once
<RevealGroup stagger?=0.06 delay? className?><RevealItem as? className?>…</RevealItem></RevealGroup>
<Draw play?: "load" | "view" | "scrub"; delay?; duration?; sheen?: boolean; onComplete?; className?>{svg}</Draw>
// animiert alle [data-draw]-Pfade im Kind (stroke-dasharray/offset, pathLength=1); scrub: ScrollTrigger auf eigenem Element
<Door className? parallax?: boolean; priority?: boolean; src alt width height sizes? /> // <img> in clip-path-Maske, scale 1.06→1, 6% Parallax desktop
<ThemeTween /> // einmal pro Seite (template.tsx): tweent body-Variablen --bg --fg --fg-muted --accent --line --surface an [data-theme]-Grenzen (start "top 70%", end "top 30%", scrub 0.4)
<ScrollProgress /> // 1px --accent Linie unter dem Header
<Magnet strength?=0.3 className?>children</Magnet> // nur desktop+no-preference, ref + ein rAF
<TransitionLink href label? className? …LinkProps /> // Vorhang + router.push; Modifier/extern/Anker → normal
<Curtain /> // einmal in layout.tsx; hört auf transition-store
// src/components/motion/transition-store.ts: startTransition(href, label), subscribe(cb)
```
### 2.7 Brand (F1) `src/components/brand/`
```tsx
<BrandMark className? idPrefix? variant?: "full" | "v-only" /> // Server: getLogoSvg() ? inline SVG (Pfade bekommen data-draw, Klassen wie WolfMark) : <WolfMark/>
<DrawMark play? sheen? handoff?: boolean className?>{<BrandMark/>}</DrawMark> // Client-Hülle um BrandMark: Draw-Sequenz V-links → V-rechts → Wolf → (handoff-Linie nach unten) → Sheen
<Wordmark size?: "nav" | "footer"; href?="/" ; className? /> // HTML-Wordmark ANELIA WOLF + Regel + Unterzeile
```
### 2.8 Layout (F1) `src/components/layout/`
```tsx
<Header /> // Client; fixed; Zeile 1 Masthead (≥1024, kollabiert nach 80px), Zeile 2 Logo | 3 Nav-Links | Kontakt + Button (≥1280) | Menü (<1024)
<Masthead center: string; className? /> // drei Slots (Rolle | center | „Deutsch & Englisch“), Hairlines oben/unten
<OverlayMenu open onClose /> // Fullscreen, nummerierter Ledger, Fokus-Trap, Esc, inert
<Footer /> // Server; identisch auf allen Seiten
<Section id theme: "dark"|"light"; numeral?: string; total?: string; label?: string; className?; as?>children</Section>
// <section data-theme id> mit Container + 12er-Grid; sticky Mono-Ziffer links (≥1024) bzw. Zeile oben (<1024); Kinder im Grid (col-span über className)
<Container className?>children</Container> // max-w-[105rem] px-[clamp(20px,5vw,80px)]
<Folio current total next?: {label, href} className? /> // Hairline + „01 / 06“ + „Positionierung ↓“
```
`src/app/template.tsx` (F1): `motion.main#inhalt` opacity/y-Enter 0.6s, `onAnimationComplete → ScrollTrigger.refresh()`, mountet `<ThemeTween/>`, scrollt Lenis auf 0 bei Pfadwechsel.
`src/app/layout.tsx` (F1 erweitert): Inline-Script `html.js`, `<Header/>`, `{children}`, `<Footer/>`, `<Curtain/>`, `<ScrollProgress/>`, `MotionConfig reducedMotion="user"`.
### 2.9 UI / Editorial (F2) `src/components/ui/`
```tsx
<Eyebrow className?>text</Eyebrow> // Jost 500 caps ls .28em text-accent, 24px-Tick ::before
<Numeral value="01" className? /> // Bodoni 400 opsz 96, .gold-text auf dark / text-gold-700 auf light
<Marginalia items: {label: string; value: string; href?: string}[] className? />
<Ledger variant: "toc"|"werdegang"|"termine"|"situations"|"goals"; rows: LedgerRow[]; className? />
// toc-Row: {numeral, title, oneLiner, keywords[], link:{label, href}}; werdegang: {keyword, text}; termine: {date, format, title, venue, href?};
// situations: {numeral, text}; goals: {text}. toc-Zeile = eine <TransitionLink>; Hover ohne Reflow.
<ModuleTable modules: {title, goal, contents[], audience, meta}[] /> // Kopfzeile + <details> pro Modul, + → × per CSS
<SpecTable blocks: {title, goal, contents, audience, meta, tracks?: string[]}[] />
<Facts items: {label, value}[] className? /> // Mono-Stack mit Goldticks (Hero rechts oben)
<FactsStrip items: {label, value}[] /> // volle Breite, vertikale Hairlines (Speaker-Facts)
<Faq items: {q, a}[] /> // native details/summary
<Steps items: {numeral, title, text}[] />
<ContactLinks /> // Schreib mir / Ruf an / Vernetzen (aus site.ts)
<Columns items: {label, title, lines[], link:{label, href}}[] offsetMiddle? />
<Formula lines: {op?: "+"|"=", text, em?: string, goldEm?: boolean, definition, delivers}[] signoff link /> // WOLF-Prinzip; Pin nur desktop
<Quote text author role? />
<Portrait src alt aspect?: "4/5"|"3/5"|"3/4"|"16/10"; caption? sticky? priority? className? /> // nutzt <Door/>; rendert null bei src null
<Button href label suffix? micro? variant?: "primary"|"ghost" external? className? /> // Outline, Sheen-Hover, Mono-Suffix aus Maske
<TextLink href label external? className? /> // caps + →, Unterstreichung wächst von links
<CtaBand h2: {before, em, after}; cta: ButtonProps; micro? /> // dunkles Band inkl. <ContactLinks/>
<Interruption text mono? /> // 100svh ink, riesige Display-Zeile
```
### 2.10 Services gemeinsam (F2) `src/components/services/`
```tsx
<ServiceHero content={coaching|trainings|keynotes} photo?: string|null /> // Masthead(center), Eyebrow, H1 mit <em>, Subline, Button, Facts rechts, Folio 01/03
<ServiceLayout>{children}</ServiceLayout> // Sektionen hell mit Section-Wrapper; Kontakt-Band separat
```
### 2.11 Seiten (Phase 2)
- `src/app/page.tsx` + `src/components/home/{Hero,Positioning,ServicesIndex}.tsx` (P1)
- `src/components/home/{WolfPrinciple,About,Audience,ProcessContact}.tsx` (P2)
- `src/app/leistungen/coaching/page.tsx` + `src/components/services/coaching/*` (P3)
- `src/app/leistungen/trainings/page.tsx` + `src/components/services/trainings/*` (P4)
- `src/app/leistungen/keynotes/page.tsx` + `src/components/services/keynotes/*` (P5)
- `src/app/impressum/page.tsx`, `src/app/datenschutz/page.tsx`, `src/app/not-found.tsx`, `src/app/sitemap.ts`,
`src/app/robots.ts`, `src/app/icon.svg` (P6)
## 3. Phasen
1. **Foundation** (parallel): F1 = 2.1, 2.6, 2.7, 2.8 + `template.tsx` + `layout.tsx`-Erweiterung.
F2 = 2.22.5, 2.9, 2.10 + `src/hooks/useMediaQuery.ts`.
2. **Integration 1**: `tsc` + Verträge angleichen, `npm run build` grün mit Platzhalter-Startseite.
3. **Pages** (parallel): P1P6.
4. **Integration 2**: `tsc`, `lint`, `build`; alle 7 Routen im `out/`.
5. **Visual QA** (Loop bis trocken, max. 3 Runden): Dev-Server über `.claude/launch.json` (`anelia-dev`),
Screenshots 1440×900 + 390×844, Findings → Fix-Agenten (disjunkte Dateien) → erneut.
6. **Review**: A11y, Performance/Static-Export, Datenschutz (keine externen Requests, kein Storage), Copy-Check
gegen verbotene Phrasen → Fixes → finaler Build.