À compléter avant l'envoi
[nom du serveur][nom de l'agence ou du photographe][ville, quartier][année, effectif, nom du fondateur][nom, lieu, année, une phrase][le cas échéant][e-mail][téléphone][numéro WhatsApp][adresse][domaine][nom-du-projet]
Sur mon serveur d'hébergement Opus Growth [nom du serveur], crée un site portfolio à défilement horizontal pour [nom de l'agence ou du photographe]. Mon activité : [architecture, architecture d'intérieur ou photographie ; quel type de travaux], ville : [ville, quartier], année de création et équipe : [année, effectif, nom du fondateur]. Projets : [pour chacun, nom, lieu, année, statut, surface ou type de prise de vue, résumé en une phrase, problématique, approche, processus, matériaux ou technique, au moins deux liens vers des photos]. Projets en cours : [nom, lieu, année, une phrase]. Inscription professionnelle : [le cas échéant]. Contact : [e-mail], [téléphone], [numéro WhatsApp], [adresse]. Domaine : [domaine].
Pages : accueil (/ : hero, galerie de projets horizontale, approche, FAQ), une page par projet (/projeler/[nom-du-projet]/ : image pleine largeur, fiche technique, problématique, approche, processus, matériaux, une seconde image, lien vers le projet suivant), agence et contact (/ofis/, avec la section contact à l'ancre #iletisim), confidentialité et KVKK (/gizlilik/) et 404.html. Pas de formulaire ; un e-mail, un téléphone et un lien WhatsApp avec message prérempli suffisent. Si un projet en cours n'a pas de page détail, ne transforme pas sa carte en lien.
Style : un portfolio calme, à l'esprit galerie. Fond pierre calcaire, texte sombre, angles vifs et filets fins ; la couleur d'accent n'apparait qu'au survol et au focus. Une police d'affichage à empattements de Fontshare (par exemple Erode) et une police de texte grotesque sobre (par exemple Archivo). Sur ordinateur, le hero remplit l'écran, de sorte que la galerie commence sous la première vue.
Règles d'animation (la partie la plus difficile, à suivre à la lettre) :
1. Bibliothèques : GSAP 3.13 core, ScrollTrigger et Lenis, sur la page d'accueil et les pages projet. SplitText et Swiper ne sont PAS chargés ; aucun script du tout sur les pages agence et confidentialité.
2. Le HTML et le CSS par défaut forment une pile verticale : une colonne sur mobile, une grille à deux colonnes sur ordinateur. Sans JS, avec animations réduites et sur mobile, la galerie reste ainsi.
3. Le CSS, et non le JS, construit la mise en page horizontale : à partir de 768 px de large et quand la classe `.anim` est présente, la piste est en `display:flex`, `width:max-content` et `height:calc(100vh - hauteur de l'en-tête)` dès le premier rendu, et le conteneur défile de lui-même avec `overflow-x:auto`. Ainsi la mise en page ne change pas à l'arrivée du JS (CLS 0), et si la bibliothèque n'arrive jamais, la galerie reste défilable latéralement.
4. Avec gsap.matchMedia, uniquement pour `(min-width: 768px)`, épingle le conteneur avec ScrollTrigger, scrub 0.8, un end égal au débordement de la piste ("+=" + (track.scrollWidth - innerWidth)) et invalidateOnRefresh activé ; ajoute une classe qui donne `overflow:hidden` au conteneur. Une fine ligne de progression avance avec scaleX.
5. Révélation des images : les images de la galerie s'ouvrent de gauche à droite avec containerAnimation, de clip-path `inset(0 100% 0 0)` à `inset(0)`. Ne masque jamais le panneau visible dans la première vue ni l'image du hero. Sur mobile et sur les pages projet, seules les images situées sous l'écran au chargement s'ouvrent vers le haut avec clip-path.
6. Clavier : quand Tab atteint une carte hors écran dans la piste, le navigateur fait défiler le conteneur en interne et la carte disparait. Au focusin, remets le scrollLeft du conteneur à 0 et fais défiler la page jusqu'à la position verticale où la carte apparait (scrollTrigger.start + (end - start) * le décalage gauche de la carte / le débordement total). Sans cette étape, la troisième carte atteinte avec Tab restait hors écran dans la démo.
7. Active Lenis uniquement sur les appareils `(pointer: fine)` et connecte-le à ScrollTrigger.update ; pour les liens internes comme #projeler, déplace le focus vers la cible après le défilement.
Mise en place et pièges connus (chacun a couté des points ou cassé quelque chose lors de la mesure de la démo, n'en saute aucun) :
1. Si un site en ligne existe déjà sur le serveur, dis-le-moi d'abord, car l'installation écrase index.html et le dossier assets. Prévisualise scaffold_site avec confirm=false et appelle confirm=true après mon accord. Lis ensuite site_design_guide et site_seo_guide. Avant d'écrire du code, place la direction de design (typographie, couleur, grille, élément signature, langage de mouvement et bibliothèques qui ne seront PAS chargées) dans un court ART.md en dehors d'assets et montre-le-moi.
2. Compile Tailwind, ne le charge pas depuis le CDN. Installe `npm i -D tailwindcss@3` avec site_run_command et background=true, et surveille avec site_command_status. Les chemins content de `tailwind.config.js` doivent couvrir tous les fichiers HTML, tous les templates et tous les fichiers JS qui écrivent des classes. `_src/tw.css` contient une ligne `@import "../assets/app.css";` et les trois lignes `@tailwind` ; compile-le en un seul fichier avec `npx tailwindcss -c tailwind.config.js -i _src/tw.css -o assets/site.css --minify`. Retire le script cdn.tailwindcss.com et le tailwind.config en ligne des pages et ne lie que `/assets/site.css`. Recompile après chaque modification du HTML.
3. Héberge les polices toi-même. Vérifie d'abord que la famille Fontshare choisie contient les lettres turques (ş, ğ, ı, İ, ç, ö, ü) : dans la démo, Tanker n'avait pas de ı sans point et Outfit n'avait ni ş, ni ğ, ni İ, si bien que ces lettres retombaient sur une autre police dans les titres. Télécharge chaque graisse en woff2 séparément avec site_fetch dans `assets/fonts/`, écris les règles @font-face avec `font-display: swap` dans `assets/app.css` (design-check y cherche la police personnalisée) et vérifie le nom font-family dans le CSS téléchargé. Précharge les polices de titre et de texte utilisées au-dessus de la ligne de flottaison sur chaque page avec `<link rel="preload" as="font" type="font/woff2" crossorigin>`, avant la feuille de style ; ne précharge pas plus de deux fichiers, car précharger une troisième graisse dans la démo a allongé le LCP mobile de 0,2 seconde. La plupart des polices Fontshare n'ont pas le signe ₺, écris donc « TL » pour les prix.
4. Rends le menu et le pied de page en HTML statique. Ne charge ni chrome.js ni site.config.js sur les pages. Écris un petit `chrome-stamp.mjs` qui lit la liste de navigation depuis site.config.js et estampille `_src/header.tpl` et `_src/footer.tpl` entre les marqueurs `<!-- nav:start --><!-- nav:end -->` et `<!-- footer:start --><!-- footer:end -->` sur chaque page, en ajoutant aria-current="page" au lien actif. Les templates ne doivent pas se terminer par .html et doivent utiliser des espaces réservés comme `[[NAV]]` au lieu de `{{...}}`. Construis le menu mobile sans JS avec `<details>`. Garde le nom de l'organisation, l'adresse et le téléphone en texte brut dans le pied de page, et donne à chaque zone tactile au moins 44x44 px, y compris les liens du pied de page et du fil d'Ariane.
5. Convertis les images pendant leur téléchargement avec site_fetch : écris la même photo avec resize="480x", "800x" et "1200x", image_format="webp", quality=65 dans des fichiers séparés. site_fetch ne recadre jamais ; quand une photo Unsplash demande un autre ratio, télécharge la version recadrée en ajoutant des paramètres comme `?w=1600&h=1200&fit=crop` à son URL. Donne à chaque `<img>` srcset, sizes ainsi qu'une width et une height correspondant au ratio réel. L'image principale au-dessus de la ligne de flottaison reçoit fetchpriority="high" et n'est pas lazy ; les autres reçoivent loading="lazy" decoding="async". Si l'image principale remplit l'écran sur mobile, sers un recadrage plus petit avec `<picture>`.
6. Écris la version SVG du logo dans favicon.svg avec site_write_file et ajoute `<link rel="icon" href="/favicon.svg" type="image/svg+xml">` à chaque page. Sans favicon, le navigateur journalise une 404 et les Bonnes pratiques tombent à 96.
7. Règles du validateur HTML : commence par un `<!DOCTYPE html>` en majuscules, utilise ` ` pour les espaces dans le texte visible des liens tel:, n'utilise jamais d'attribut style="", donne à chaque bouton type="button", et ne place pas de `<details>` dans une `<figure>` après son figcaption.
8. Télécharge les bibliothèques d'animation (GSAP, ScrollTrigger, Lenis) depuis jsdelivr dans `assets/vendor/` avec site_fetch, fige la version et ne les charge que sur la page d'accueil et les pages projet. N'utilise pas `<script defer>` ; place un petit chargeur à la fin de la page qui attend l'événement load, deux appels requestAnimationFrame puis requestIdleCallback, et ajoute les scripts dans l'ordre avec async=false. Un script d'une ligne dans `<head>` ajoute la classe `js` à `<html>` et la classe `anim` sauf si prefers-reduced-motion vaut « reduce » ; sans `anim`, le chargeur ne télécharge rien. Définis les états de départ masqués uniquement sous `.anim`, et ajoute une animation CSS de sécurité qui révèle tous les éléments masqués après 2,5 secondes au cas où la bibliothèque n'arriverait jamais. Dans les démos précédentes, les bibliothèques en defer ont poussé le LCP mobile à 3,2 secondes ; avec ce chargeur, les pages ont mesuré entre 99 et 100. Nomme data-reveal l'attribut des éléments révélés au défilement ; design-check ne reconnait le mouvement que par ce nom.
SEO, AEO et GEO :
1. Utilise des URL de type répertoire avec une barre oblique finale (/projeler/[nom-du-projet]/, /ofis/, /gizlilik/). Renseigne le bloc seo de site.config.js et lance `node seo-stamp.mjs`. Écris le schema propre à chaque page (accueil : WebPage et FAQPage ; chaque page projet : une WebPage avec une CreativeWork comme mainEntity, incluant dateCreated, locationCreated et image ; agence : AboutPage avec une Person pour le fondateur ; BreadcrumbList sur les pages intérieures. Pour une agence d'architecture ou de photographie avec bureau, businessType ProfessionalService) dans des blocs `<script type="application/ld+json">` séparés et relie-les au graphe de base par @id. N'imbrique pas BreadcrumbList dans @graph ; garde-le dans son propre bloc, car c'est la seule façon pour seo-check de le voir.
2. Garde les titres à 60 caractères ou moins (seo-check signale comme erreur tout ce qui dépasse 65), les descriptions entre 120 et 158 caractères, un seul h1 par page et aucun niveau de titre sauté (un h3 juste après le h1 a fait tomber l'accessibilité à 98). Chaque page a besoin d'au moins 150 mots de contenu principal ; les pages contact et confidentialité ont tendance à être trop courtes.
3. Le premier paragraphe de chaque page répond directement à la question de la page. Rédige des FAQ propres à chaque page avec `<details>` et balise-les en FAQPage. Affiche l'organisation éditrice et une date de « Dernière mise à jour » dans `<time>`.
4. Dans robots.txt, note et justifie ta décision pour GPTBot, OAI-SearchBot, ChatGPT-User, ClaudeBot, Claude-User, Claude-SearchBot, PerplexityBot, Perplexity-User, Google-Extended, Applebot-Extended, Bingbot et CCBot, et indique le sitemap. Donne à sitemap.xml de vraies dates lastmod. llms.txt contient un résumé exact du site en deux phrases, les faits clés et la liste des pages importantes.
5. Pas d'invention : n'écris ni avis, ni notes, ni récompenses, ni nombre de clients, ni certificats, ni horaires d'ouverture, ni coordonnées, ni prix sans me demander. Laisse totalement hors du schema tout champ que tu ne connais pas.
Contrôles (dans l'ordre ; ne dis pas « terminé » tant que tous ne sont pas passés) :
1. Avec site_run_command, lance `node chrome-stamp.mjs`, la compilation Tailwind, `node seo-stamp.mjs`, `node seo-check.mjs` (0 erreur, 0 avertissement), `node design-check.mjs` (0 erreur ; justifie tout avertissement restant) et `npx html-validate "**/*.html"` (0 erreur).
2. Visualise chaque page avec site_preview en view="mobile" et view="desktop". site_preview capture la page avec les animations désactivées (reduced-motion) ; si du contenu manque dans cette capture, l'état sans animation est cassé. Les images lazy situées plus bas peuvent être vides dans la capture pleine page ; ne le compte pas comme une erreur, mais vérifie leurs chemins.
3. Lance core_web_vitals avec strategy="mobile" et strategy="desktop" pour chaque page. Critères d'acceptation : sur mobile, Performance d'au moins 95 et Accessibilité, Bonnes pratiques et SEO à 100 ; sur ordinateur, les quatre scores à 95 minimum. Pour une page qui échoue, trouve le fichier lent avec resources=true, corrige-le et mesure à nouveau. Lance ensuite seo_audit sur la page d'accueil avec strategy="mobile" et runs=2. Aucune adresse extérieure à ton propre domaine ne doit rester dans la liste des requêtes réseau.
4. Aucun défilement horizontal à 360, 390, 768 et 1440 px, des zones tactiles d'au moins 44 px et aucune erreur de console. Le site doit aussi être impeccable dans un cadre de 390x790 et un cadre de 1440x898, comme sur les pages de prompts.
Contrôle du mouvement : site_preview ne peut pas montrer le mouvement ; dis-moi donc quoi observer dans mon propre navigateur. Sur ordinateur, la galerie doit se coller en haut quand on atteint la section Projets, les cartes doivent défiler vers la gauche quand on descend, les images doivent s'ouvrir de gauche à droite et la ligne de progression doit se remplir ; après la dernière carte, la page reprend son flux normal. Quand on navigue entre les cartes avec Tab, la carte focalisée doit toujours être à l'écran. Sur mobile et avec la réduction des animations activée, la galerie est une pile de cartes et rien ne reste collé.
Après publication : prévisualise la règle `/assets/* Cache-Control: public, max-age=31536000, immutable` avec site_headers et applique-la après mon accord ; à partir de là, versionne le nom de fichier à chaque modification du CSS ou du JS (site-v2.css, etc.). Soumets sitemap.xml avec gsc_submit_sitemap et vérifie la page d'accueil avec gsc_url_inspect. Pour finir, donne-moi : un tableau des scores par page (page, quatre scores mobile, quatre scores ordinateur, LCP, CLS), les résultats des contrôles, le résultat des interactions testées dans un navigateur et la liste des corrections appliquées.