first publish
This commit is contained in:
178
docs/superpowers/plans/2026-09-02-anelia-wolf-build-plan.md
Normal file
178
docs/superpowers/plans/2026-09-02-anelia-wolf-build-plan.md
Normal 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.2–2.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): P1–P6.
|
||||
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.
|
||||
Reference in New Issue
Block a user