Vor dem Senden ausfüllen
[Servername][Name des Büros oder der Fotografin bzw. des Fotografen][Stadt, Stadtteil][Jahr, Teamgröße, Name der Gründerin bzw. des Gründers][Name, Ort, Jahr, ein Satz][falls vorhanden][E-Mail][Telefon][WhatsApp-Nummer][Adresse][Domain][Projektname]
Baue auf meinem Opus-Growth-Hosting-Server [Servername] eine Portfolio-Website mit horizontalem Scrollen für [Name des Büros oder der Fotografin bzw. des Fotografen]. Was ich mache: [Architektur, Innenarchitektur oder Fotografie; welche Art von Arbeiten], Stadt: [Stadt, Stadtteil], Gründungsjahr und Team: [Jahr, Teamgröße, Name der Gründerin bzw. des Gründers]. Projekte: [für jedes: Name, Ort, Jahr, Status, Fläche oder Art des Shootings, ein Satz Zusammenfassung, Fragestellung, Vorgehen, Prozess, Materialien oder Technik, mindestens zwei Foto-Links]. Laufende Arbeiten: [Name, Ort, Jahr, ein Satz]. Berufliche Registrierung: [falls vorhanden]. Kontakt: [E-Mail], [Telefon], [WhatsApp-Nummer], [Adresse]. Domain: [Domain].
Seiten: Startseite (/: Hero, horizontale Projektgalerie, Vorgehen, FAQ), eine Seite pro Projekt (/projeler/[Projektname]/: Bild in voller Breite, Steckbrief, Fragestellung, Vorgehen, Prozess, Materialien, ein zweites Bild, Link zum nächsten Projekt), Büro und Kontakt (/ofis/, mit dem Kontaktbereich am Anker #iletisim), Datenschutz und KVKK (/gizlilik/) sowie 404.html. Kein Formular; E-Mail, Telefon und ein WhatsApp-Link mit vorausgefüllter Nachricht genügen. Hat ein laufendes Projekt keine Detailseite, darf seine Karte kein Link sein.
Stil: ein ruhiges, galerieartiges Portfolio. Hintergrund in Kalkstein-Ton, dunkler Text, scharfe Ecken und dünne Linien; die Akzentfarbe erscheint nur bei Hover und Fokus. Eine Fontshare-Serifenschrift für Überschriften (zum Beispiel Erode) und eine schlichte Grotesk für den Fließtext (zum Beispiel Archivo). Auf dem Desktop füllt der Hero den Bildschirm, sodass die Galerie unterhalb des ersten sichtbaren Bereichs beginnt.
Regeln für die Bewegung (der schwierigste Teil, bitte buchstabengetreu befolgen):
1. Bibliotheken: GSAP 3.13 Core, ScrollTrigger und Lenis, auf der Startseite und den Projektseiten. SplitText und Swiper werden NICHT geladen; auf den Seiten Büro und Datenschutz gibt es überhaupt keine Skripte.
2. Das Standard-HTML und -CSS ist ein vertikaler Stapel: eine Spalte auf dem Smartphone, ein zweispaltiges Raster auf dem Desktop. Ohne JS, bei reduzierter Bewegung und auf dem Smartphone bleibt die Galerie so.
3. Das horizontale Layout baut CSS, nicht JS: Ab 768 px Breite und wenn die Klasse `.anim` vorhanden ist, ist der Track von der ersten Darstellung an `display:flex`, `width:max-content` und `height:calc(100vh - Header-Höhe)`, und der Wrapper scrollt mit `overflow-x:auto` von selbst. So ändert sich das Layout nicht, wenn JS ankommt (CLS 0), und falls die Bibliothek nie ankommt, lässt sich die Galerie trotzdem seitwärts scrollen.
4. Mit gsap.matchMedia, nur für `(min-width: 768px)`, den Wrapper per ScrollTrigger fixieren (pin), scrub 0.8, end gleich dem Überstand des Tracks ("+=" + (track.scrollWidth - innerWidth)), invalidateOnRefresh aktiviert; eine Klasse hinzufügen, die dem Wrapper `overflow:hidden` gibt. Eine dünne Fortschrittslinie wächst per scaleX.
5. Bildeinblendung: Die Galeriebilder öffnen sich von links nach rechts mit containerAnimation, von clip-path `inset(0 100% 0 0)` zu `inset(0)`. Das Panel im ersten sichtbaren Bereich und das Hero-Bild werden nie versteckt. Auf dem Smartphone und auf Projektseiten öffnen sich nur Bilder, die beim Laden unterhalb des Bildschirms liegen, per clip-path nach oben.
6. Tastatur: Erreicht Tab eine Karte, die im Track außerhalb des Bildschirms liegt, scrollt der Browser den Wrapper intern und die Karte verschwindet. Bei focusin den scrollLeft des Wrappers auf 0 zurücksetzen und die Seite zu der vertikalen Position scrollen, an der die Karte ins Bild kommt (scrollTrigger.start + (end - start) * linker Versatz der Karte / gesamter Überstand). Ohne diesen Schritt blieb im Demo die per Tab erreichte dritte Karte außerhalb des Bildschirms.
7. Lenis nur auf `(pointer: fine)`-Geräten aktivieren und mit ScrollTrigger.update verbinden; bei Links innerhalb der Seite wie #projeler nach dem Scrollen den Fokus auf das Ziel setzen.
Einrichtung und bekannte Fallstricke (jeder einzelne hat im Demo Punkte gekostet oder etwas kaputt gemacht, keinen überspringen):
1. Liegt auf dem Server bereits eine Live-Website, sag mir das zuerst, denn die Einrichtung überschreibt index.html und den Ordner assets. Scaffold_site mit confirm=false in der Vorschau ansehen und nach meiner Freigabe confirm=true aufrufen. Danach site_design_guide und site_seo_guide lesen. Bevor du Code schreibst, halte die Designrichtung (Typografie, Farbe, Raster, Signature-Element, Bewegungssprache und die Bibliotheken, die NICHT geladen werden) in einer kurzen ART.md außerhalb von assets fest und zeig sie mir.
2. Tailwind kompilieren, nicht per CDN laden. Installiere `npm i -D tailwindcss@3` mit site_run_command und background=true und beobachte es mit site_command_status. Die content-Pfade in `tailwind.config.js` müssen jede HTML-Datei, jedes Template und jede JS-Datei abdecken, die Klassen schreibt. `_src/tw.css` enthält eine Zeile `@import "../assets/app.css";` und die drei `@tailwind`-Zeilen; kompiliere sie mit `npx tailwindcss -c tailwind.config.js -i _src/tw.css -o assets/site.css --minify` in eine einzige Datei. Entferne das Skript cdn.tailwindcss.com und die Inline-tailwind.config aus den Seiten und verlinke nur `/assets/site.css`. Nach jeder HTML-Änderung neu kompilieren.
3. Schriften selbst hosten. Prüfe zuerst, ob die gewählte Fontshare-Familie die türkischen Buchstaben hat (ş, ğ, ı, İ, ç, ö, ü): Im Demo fehlte Tanker das punktlose ı und Outfit das ş, ğ und İ, sodass diese Buchstaben in Überschriften auf eine andere Schrift zurückfielen. Lade die woff2-Datei jeder Schriftstärke einzeln mit site_fetch nach `assets/fonts/`, schreibe die @font-face-Regeln mit `font-display: swap` in `assets/app.css` (design-check sucht dort nach der Custom Font) und prüfe den font-family-Namen im heruntergeladenen CSS. Lade die Überschrift- und Fließtextschrift, die oberhalb des Falzes verwendet werden, auf jeder Seite mit `<link rel="preload" as="font" type="font/woff2" crossorigin>` vor, und zwar vor dem Stylesheet; preloade nicht mehr als zwei Dateien, denn das Preloaden einer dritten Schriftstärke verlängerte im Demo den mobilen LCP um 0,2 Sekunden. Den meisten Fontshare-Schriften fehlt das ₺-Zeichen, also schreibe für Preise "TL".
4. Menü und Footer als statisches HTML. Lade chrome.js oder site.config.js nicht auf den Seiten. Schreibe ein kleines `chrome-stamp.mjs`, das die Navigationsliste aus site.config.js liest und `_src/header.tpl` sowie `_src/footer.tpl` auf jeder Seite zwischen die Marker `<!-- nav:start --><!-- nav:end -->` und `<!-- footer:start --><!-- footer:end -->` stempelt und dem aktiven Link aria-current="page" hinzufügt. Templates dürfen nicht auf .html enden und müssen Platzhalter wie `[[NAV]]` statt `{{...}}` verwenden. Baue das mobile Menü ohne JS mit `<details>`. Behalte Organisationsname, Adresse und Telefon als reinen Text im Footer und mache jedes Touch-Ziel mindestens 44x44 px groß, auch Footer- und Breadcrumb-Links.
5. Bilder beim Herunterladen mit site_fetch konvertieren: Schreibe dasselbe Foto mit resize="480x", "800x" und "1200x", image_format="webp", quality=65 in getrennte Dateien. site_fetch schneidet nie zu; braucht ein Unsplash-Foto ein anderes Seitenverhältnis, lade die zugeschnittene Version, indem du Parameter wie `?w=1600&h=1200&fit=crop` an die URL hängst. Gib jedem `<img>` srcset, sizes sowie width und height passend zum echten Seitenverhältnis. Das wichtigste Bild oberhalb des Falzes bekommt fetchpriority="high" und ist nicht lazy; die übrigen bekommen loading="lazy" decoding="async". Füllt das Hauptbild auf dem Smartphone den Bildschirm, liefere über `<picture>` einen kleineren Zuschnitt aus.
6. Schreibe die SVG-Version des Logos mit site_write_file als favicon.svg und füge jeder Seite `<link rel="icon" href="/favicon.svg" type="image/svg+xml">` hinzu. Ohne Favicon protokolliert der Browser einen 404 und Best Practices fällt auf 96.
7. Regeln des HTML-Validators: Beginne mit einem großgeschriebenen `<!DOCTYPE html>`, verwende ` ` für die Leerzeichen im sichtbaren Text von tel:-Links, nutze nie ein style=""-Attribut, gib jedem Button type="button" und setze kein `<details>` nach seiner figcaption in ein `<figure>`.
8. Lade die Bewegungsbibliotheken (GSAP, ScrollTrigger, Lenis) mit site_fetch von jsdelivr nach `assets/vendor/`, fixiere die Version und lade sie nur auf der Startseite und den Projektseiten. Verwende nicht `<script defer>`; setze am Seitenende einen kleinen Loader, der auf das load-Ereignis, zwei requestAnimationFrame-Aufrufe und dann requestIdleCallback wartet und die Skripte der Reihe nach mit async=false anhängt. Ein einzeiliges Skript im `<head>` fügt `<html>` die Klasse `js` hinzu und die Klasse `anim`, außer prefers-reduced-motion ist "reduce"; ohne `anim` lädt der Loader nichts. Definiere versteckte Startzustände nur unter `.anim` und füge als Sicherheitsnetz eine CSS-Animation hinzu, die alle versteckten Elemente nach 2,5 Sekunden einblendet, falls die Bibliothek nie ankommt. In früheren Demos schoben aufgeschobene Bibliotheken den mobilen LCP auf 3,2 Sekunden; mit diesem Loader erreichten die Seiten 99 bis 100. Nenne das Attribut für beim Scrollen eingeblendete Elemente data-reveal; design-check erkennt Bewegung nur unter diesem Namen.
SEO, AEO und GEO:
1. Verwende URLs im Verzeichnisstil mit abschließendem Schrägstrich (/projeler/[Projektname]/, /ofis/, /gizlilik/). Fülle den seo-Block von site.config.js aus und führe `node seo-stamp.mjs` aus. Schreibe das seitenspezifische Schema (Startseite: WebPage und FAQPage; jede Projektseite: eine WebPage mit einem CreativeWork als mainEntity, inklusive dateCreated, locationCreated und image; Büro: AboutPage mit einer Person für die Gründerin bzw. den Gründer; BreadcrumbList auf den Unterseiten. Für ein Architektur- oder Fotostudio mit Büro: businessType ProfessionalService) in getrennte `<script type="application/ld+json">`-Blöcke und verknüpfe sie per @id mit dem Basis-Graphen. Verschachtele BreadcrumbList nicht in @graph; halte sie in einem eigenen Block, denn nur so sieht seo-check sie.
2. Halte Titel bei höchstens 60 Zeichen (seo-check meldet alles über 65 als Fehler), Beschreibungen zwischen 120 und 158 Zeichen, genau ein h1 pro Seite und keine übersprungenen Überschriftenebenen (ein h3 direkt nach dem h1 senkte die Barrierefreiheit auf 98). Jede Seite braucht mindestens 150 Wörter Hauptinhalt; Kontakt- und Datenschutzseiten bleiben oft darunter.
3. Der erste Absatz jeder Seite beantwortet die Frage der Seite direkt. Schreibe seitenspezifische FAQs mit `<details>` und zeichne sie als FAQPage aus. Zeige die veröffentlichende Organisation und ein Datum "Zuletzt aktualisiert" in `<time>`.
4. Schreibe in robots.txt deine Entscheidung für GPTBot, OAI-SearchBot, ChatGPT-User, ClaudeBot, Claude-User, Claude-SearchBot, PerplexityBot, Perplexity-User, Google-Extended, Applebot-Extended, Bingbot und CCBot auf und begründe sie, und verweise auf die Sitemap. Gib sitemap.xml echte lastmod-Daten. llms.txt enthält eine korrekte Zusammenfassung der Website in zwei Sätzen, die wichtigsten Fakten und eine Liste der wichtigen Seiten.
5. Nichts erfinden: Schreibe keine Bewertungen, Ratings, Auszeichnungen, Kundenzahlen, Zertifikate, Öffnungszeiten, Koordinaten oder Preise, ohne mich zu fragen. Lass jedes Feld, das du nicht kennst, komplett aus dem Schema weg.
Prüfschritte (in dieser Reihenfolge; sag nicht "fertig", bevor alle bestanden sind):
1. Führe mit site_run_command `node chrome-stamp.mjs`, den Tailwind-Build, `node seo-stamp.mjs`, `node seo-check.mjs` (0 Fehler, 0 Warnungen), `node design-check.mjs` (0 Fehler; jede verbleibende Warnung begründen) und `npx html-validate "**/*.html"` (0 Fehler) aus.
2. Sieh dir jede Seite mit site_preview mit view="mobile" und view="desktop" an. site_preview erfasst die Seite mit ausgeschalteter Bewegung (reduced-motion); fehlt in dieser Aufnahme Inhalt, ist der bewegungslose Zustand kaputt. Weiter unten liegende Lazy-Bilder können in der Ganzseitenaufnahme leer sein; zähle das nicht als Fehler, prüfe aber ihre Pfade.
3. Führe core_web_vitals für jede Seite mit strategy="mobile" und strategy="desktop" aus. Abnahme: Auf dem Smartphone Performance mindestens 95 und Barrierefreiheit, Best Practices und SEO 100; auf dem Desktop alle vier mindestens 95. Finde bei einer Seite, die das verfehlt, mit resources=true die langsame Datei, behebe sie und miss erneut. Führe danach seo_audit für die Startseite mit strategy="mobile" und runs=2 aus. In der Liste der Netzwerkanfragen darf keine Adresse außerhalb deiner eigenen Domain verbleiben.
4. Kein horizontales Scrollen bei 360, 390, 768 und 1440 px, Touch-Ziele von mindestens 44 px und keine Konsolenfehler. Die Website muss außerdem in einem Rahmen von 390x790 und 1440x898 makellos aussehen, wie auf den Prompt-Seiten.
Bewegungsprüfung: site_preview kann keine Bewegung zeigen, also sag mir, worauf ich in meinem eigenen Browser achten soll. Auf dem Desktop soll die Galerie oben haften bleiben, wenn man den Bereich Projekte erreicht, die Karten sollen beim Herunterscrollen nach links fließen, die Bilder sollen sich von links nach rechts öffnen und die Fortschrittslinie soll sich füllen; nach der letzten Karte kehrt die Seite in den normalen Fluss zurück. Beim Tabben zwischen den Karten muss die fokussierte Karte immer auf dem Bildschirm sein. Auf dem Smartphone und bei aktivierter reduzierter Bewegung ist die Galerie ein Stapel von Karten und nichts bleibt haften.
Nach der Veröffentlichung: Sieh dir die Regel `/assets/* Cache-Control: public, max-age=31536000, immutable` mit site_headers in der Vorschau an und wende sie nach meiner Freigabe an; ab dann versionierst du den Dateinamen, sobald sich CSS oder JS ändert (site-v2.css usw.). Reiche sitemap.xml mit gsc_submit_sitemap ein und prüfe die Startseite mit gsc_url_inspect. Gib mir zum Schluss: eine Punktetabelle pro Seite (Seite, vier mobile Werte, vier Desktop-Werte, LCP, CLS), die Ergebnisse der Prüfschritte, das Ergebnis der im Browser ausprobierten Interaktionen und die Liste der angewendeten Korrekturen.