À compléter avant l'envoi
[nom du serveur][nom du studio][activité, pour qui][ville, quartier][3 services][e-mail][téléphone][numéro WhatsApp][adresse][domaine][[NAV]
Sur mon serveur d'hébergement Opus Growth [nom du serveur], construis un site portfolio statique et rapide pour [nom du studio], avec le rendu des sites d'agence interactifs réalisés sous Webflow, mais sans utiliser Webflow. Studio : [activité, pour qui], ville et quartier : [ville, quartier]. Services : [3 services]. Projets : [pour chacun : nom, type de travail, année, une phrase sur le problème, une sur la solution, lien de l'image]. Contact : [e-mail], [téléphone], [numéro WhatsApp], [adresse]. Domaine : [domaine].
Pages : accueil (hero, index des réalisations choisies, ce que nous faisons, méthode, FAQ, appel à l'action final), réalisations (/isler/ : galerie, puis pour chaque projet le problème, le travail effectué et une note de livraison), studio (/hakkimizda/), contact (/iletisim/, sans formulaire ; e-mail, WhatsApp avec message prérempli et téléphone), confidentialité (/gizlilik/) et 404.html. Sans données validées par le client, n'écris ni pourcentages ni chiffres de croissance pour les résultats des projets ; décris le résultat avec des mots.
Style : moderne brutaliste. Angles vifs, lignes de grille visibles de 1 px, une grotesque display grasse en majuscules (par exemple Clash Grotesk) et une police de texte posée (par exemple Supreme), un accent fluo utilisé uniquement en fond avec du texte noir dessus. Les états de survol changent la couleur et le fond ; l'anneau de focus est épais et visible sur tous les fonds.
Règles d'interaction (la sensation Webflow IX2, sans bibliothèque) :
1. Ne charge PAS GSAP ni Lenis. Écris les interactions dans un seul petit fichier JS natif (IntersectionObserver et requestAnimationFrame) et charge-le avec defer uniquement sur les pages d'accueil et de réalisations. Aucun script sur les autres pages.
2. Élément signature, l'index « Réalisations choisies » : chaque ligne est un vrai lien vers le projet et porte le chemin de l'image d'aperçu dans un attribut data-img. Par défaut (sans JS ou sur appareil tactile), chaque ligne affiche une petite image dans le flux. Uniquement sur les appareils correspondant à `(hover: hover) and (pointer: fine)` qui ne demandent pas de mouvement réduit, le JS ajoute une classe cursor-fx à `<html>`, masque les images en ligne et affiche une seule boite d'aperçu qui suit le pointeur. Déplace la boite avec des variables CSS et transform: translate3d plutôt que left et top, et arrête la boucle requestAnimationFrame quand le pointeur est immobile. Au focus clavier, le même aperçu s'ouvre en position fixe à côté de la ligne et se ferme quand le focus la quitte.
3. Ajoute l'anneau de curseur personnalisé uniquement dans la même condition ; ne masque jamais le curseur natif, marque l'anneau aria-hidden et fais-le grossir au-dessus des liens.
4. Transitions de section : les titres de section s'ouvrent de gauche à droite avec clip-path au scroll. Le JS n'applique l'état de départ masqué qu'aux titres situés sous l'écran à l'ouverture de la page ; le contenu du premier écran n'est jamais masqué. Nomme l'attribut data-reveal ; design-check reconnait le mouvement à ce nom et avertit « no motion » sinon.
5. Galerie Swiper uniquement sur la page de réalisations. Sans JS, le HTML de la galerie est une bande horizontale CSS scroll-snap, et les boutons précédent et suivant restent masqués jusqu'au démarrage de Swiper. Télécharge le bundle Swiper 14 (js et css) dans `assets/vendor/` avec site_fetch. Charge-le quand le pointeur entre dans la galerie, au toucher, au focus ou au premier scroll de la page. Dans la démo, le charger quand la galerie approchait du viewport a fait grimper le LCP mobile à 3 s à cause du bundle de 150 Ko (Performance 94) ; le charger à la première interaction a donné 99. Active les modules Navigation, Keyboard et A11y avec des messages en turc, et mets la vitesse de transition à 0 en mouvement réduit.
6. Construis les slides avec des div plutôt que ul et li. Swiper donne aux slides role="group" ; sur des li, ce rôle a provoqué des erreurs aria-allowed-role et de liste et fait tomber Accessibility à 96.
Mise en place et pièges connus (chacun a fait baisser un score dans les mesures de la démo, ne les saute pas) :
1. Si un site est déjà en ligne sur le serveur, préviens-moi d'abord, car l'installation écrase index.html et le dossier assets. Prévisualise scaffold_site avec confirm=false et appelle-le avec confirm=true après mon accord. Lis ensuite site_design_guide et site_seo_guide. Avant d'écrire du code, consigne 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 hors du dossier assets et montre-le-moi.
2. Compile Tailwind au lieu de le charger depuis le CDN. Installe-le avec site_run_command et background=true : `npm i -D tailwindcss@3`, puis enchaine avec site_command_status. Les chemins content de `tailwind.config.js` doivent couvrir tous les fichiers HTML, les templates et tout fichier JS qui écrit des noms de classes. `_src/tw.css` contient la 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 de chaque page et ne lie que `/assets/site.css`. Recompile après chaque modification du HTML.
3. Héberge les polices toi-même. Lis le CSS des familles Fontshare choisies, télécharge le fichier woff2 de chaque graisse dans `assets/fonts/` avec site_fetch et écris les règles @font-face avec `font-display: swap` dans `assets/app.css` ; design-check y cherche une police personnalisée. Vérifie le nom font-family dans le CSS téléchargé, car Fontshare peut renvoyer une autre famille quand une graisse n'existe pas. Précharge la police du titre du premier écran et la police de texte sur chaque page avec `<link rel="preload" as="font" type="font/woff2" crossorigin>` ; dans la démo, cela a supprimé le décalage de mise en page du à l'échange de police (CLS 0,024 à 0). La plupart des polices Fontshare n'ont pas de glyphe ₺, donc écris « 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 de site.config.js et estampille `_src/header.tpl` et `_src/footer.tpl` entre les marqueurs `<!-- nav:start --><!-- nav:end -->` et `<!-- footer:start --><!-- footer:end -->` de chaque page, en ajoutant aria-current="page" au lien courant. Ne donne pas d'extension .html aux templates et utilise des espaces réservés comme `[[NAV]]` plutôt que `{{...}}`, sinon design-check et seo-check les lisent comme des pages inachevées. Construis le menu mobile sans JS avec `<details>`. Garde la raison sociale, l'adresse et le téléphone dans le pied de page en texte brut.
5. Convertis les images pendant le téléchargement avec site_fetch : écris la même photo dans des fichiers distincts avec resize="480x", "800x" et "1200x", image_format="webp", quality=65. Donne à chaque `<img>` srcset, sizes, width et height. L'image principale du premier écran reçoit fetchpriority="high" et n'est jamais en lazy ; les autres reçoivent loading="lazy" decoding="async". Si l'image principale remplit l'écran du téléphone, sers un recadrage plus large et plus léger sur mobile avec `<picture>` (dans la démo, le hero mobile est passé de 89 Ko à 43 Ko).
6. Crée un favicon PNG de 48 px à partir du logo avec site_fetch et ajoute `<link rel="icon">` à chaque page. Sans lui, le navigateur enregistre une erreur 404 et Best Practices tombe à 96.
7. Règles du validateur HTML : commence chaque document par un `<!DOCTYPE html>` en majuscules (les fichiers de départ du kit sont en minuscules), utilise ` ` pour les espaces dans le texte visible des liens tel:, n'utilise jamais d'attribut style="" et donne type="button" à chaque bouton.
SEO, AEO et GEO :
1. Utilise des URL de répertoire avec barre oblique finale (/isler/, /hakkimizda/, /iletisim/, /gizlilik/). Remplis le bloc seo de site.config.js et lance `node seo-stamp.mjs`. Écris le schema propre à chaque page (accueil WebPage et FAQPage ; réalisations CollectionPage avec un CreativeWork par projet sous hasPart ; studio AboutPage ; contact ContactPage ; BreadcrumbList sur les pages intérieures. Pour un studio avec bureau physique, utilise businessType ProfessionalService) dans des blocs `<script type="application/ld+json">` séparés et relie-le au graphe de base avec @id. N'enfouis pas BreadcrumbList dans un @graph ; donne-lui son propre bloc, car c'est la seule façon pour seo-check de le voir.
2. Titres de 48 à 60 caractères (seo-check signale comme erreur tout ce qui dépasse 65), descriptions de 145 à 158 caractères, un seul h1 par page. Chaque page exige au moins 150 mots de contenu principal ; les pages de contact et de confidentialité ont tendance à rester en dessous.
3. Le premier paragraphe de chaque page répond directement à la question de la page. Écris une FAQ propre à la page avec `<details>` et balise-la en FAQPage. Affiche l'organisation éditrice et une mention « Dernière mise à jour » avec `<time>`.
4. Dans robots.txt, écris ta décision et sa raison 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. sitemap.xml porte de vraies dates lastmod. llms.txt contient un résumé exact du site en deux phrases et la liste des pages clés.
5. N'invente rien : ni avis, ni notes, ni récompenses, ni nombre de clients, ni certificats, ni horaires, ni coordonnées, ni prix, sauf si je te les donne. Laisse les champs inconnus hors du schema.
Contrôles (dans l'ordre ; ne le déclare pas terminé tant que tous ne passent pas) :
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, view="mobile" et view="desktop". site_preview capture la page avec le mouvement désactivé (reduced-motion) ; si du contenu manque sur cette image, l'état sans mouvement est cassé. Dans les captures pleine page, les images lazy plus bas peuvent apparaitre vides ; ce n'est pas une erreur, mais vérifie leurs chemins.
3. Lance core_web_vitals pour chaque page avec strategy="mobile" et strategy="desktop". Critère de réussite : sur mobile, Performance d'au moins 95 et Accessibility, Best Practices et SEO à 100 ; sur desktop, les quatre à 95 au minimum. Sur une page qui échoue, utilise resources=true pour trouver le fichier qui la freine, corrige-le et mesure à nouveau. Lance ensuite seo_audit sur la page d'accueil avec strategy="mobile" et runs=2. La liste des requêtes réseau ne doit contenir aucun hôte autre que ton propre domaine.
4. Aucun défilement horizontal à 360, 390, 768 et 1440 px de large, cibles tactiles d'au moins 44 px, aucune erreur dans la console.
Contrôle des interactions : site_preview ne peut pas montrer les effets de survol ni de curseur. Explique-moi comment vérifier dans un navigateur de bureau que l'aperçu suit le pointeur sur les lignes de l'index, qu'il s'ouvre à côté de la ligne à la tabulation, qu'un téléphone affiche les images en ligne et que la galerie se fait défiler au doigt.
Après la publication : prévisualise la règle `/assets/* Cache-Control: public, max-age=31536000, immutable` avec site_headers et applique-la après mon accord ; ensuite, renomme les fichiers CSS ou JS quand ils changent (site-v2.css, etc.). Soumets sitemap.xml avec gsc_submit_sitemap et vérifie la page d'accueil avec gsc_url_inspect. Termine par un tableau des scores par page (page, quatre scores mobile, quatre scores desktop, LCP, CLS), les résultats des contrôles et la liste des correctifs appliqués.