Panneau des jeux publiés sur les domaines de Léo Deroin. Quatre pages, quatre
langues, entièrement statique : elle ne fait que pointer vers
reflow.leoderoin.fr, anguille.page, azimut.page, pushyourluck.net
et loupsgarous.net, elle ne les héberge pas.
C'est délibéré. Servir un jeu à deux adresses le ferait entrer en concurrence
avec lui-même dans les résultats de recherche, et aucun hreflang ne rattrape
ça.
npm install
npm run dev # http://localhost:3003Ou dans Docker, pour retrouver la version de Node de la production :
docker compose -p jeux -f docker-compose.dev.yml up -d --buildAvant de pousser :
npm run check # typecheck + lint + build| Sujet | Choix |
|---|---|
| Rendu | Next.js 16 en output: 'export' — du HTML complet par langue, aucun Node en production |
| Langues | fr sur /, puis /en/, /es/, /de/ — slugs traduits (/a-propos/, /en/about/) |
| Icônes | lucide-react, aucun emoji dans l'interface |
| Vignettes | des SVG en ligne écrits à la main, un par jeu (components/GameArt.tsx) |
| Typographie | Fredoka (titres) et Outfit (texte), variables et auto-hébergées |
| Thèmes | système, clair forcé, sombre forcé |
| Production | une image nginx sans privilèges, en lecture seule, 28 Mo |
src/
app/(default)/ les pages françaises : /, /a-propos/, /mentions-legales/…
app/(prefixed)/ les autres langues, sur /xx/ et /xx/<slug traduit>/
app/sitemap.ts une entrée par langue ET par page, avec ses alternatives
i18n/routes.ts LA table des chemins — toute URL interne passe par path()
components/ en-tête, pied de page, carte de jeu, sélecteurs
components/GameArt les illustrations de couverture, en SVG
data/games.ts LA liste des jeux — donnée pure, sans React
fonts/ les .woff2 auto-hébergés et leurs licences OFL
i18n/dictionaries/ fr.ts fait référence, les autres en sont typées
lib/seo.ts métadonnées et JSON-LD
views/ le corps des pages, partagé par les deux racines
nginx/ configuration de production, figée à la construction
(redirects.conf est GÉNÉRÉ, ne pas l'éditer)
scripts/export-og.mts rasterise les SVG de public/ en PNG
- Une entrée dans
src/data/games.ts(URL, dépôt, statut, accent, icône). - La copie dans les quatre dictionnaires —
npm run typecheckrefuse de compiler tant qu'il en manque une. - Une paire de variables
--card-accentdansglobals.csssi la couleur du jeu n'existe pas encore, et sa clé dans[data-accent='…']. - La clé d'icône dans
components/GameIcon.tsx. - Une illustration dans
components/GameArt.tsx. C'est la moitié haute de la tuile, donc la première chose qu'on voit — c'est aussi le plus long à faire. Compte plusieurs allers-retours : dessine, construis, regarde la capture, recommence. Les couleurs de la vignette sont FIXES, elles ne changent pas avec le thème.
Le sitemap, le JSON-LD et le compteur de la page suivent tout seuls.
- Hébergeur — LordHosting, SASU au capital de 1 000 €, 5 square
Frédéric Vallois, 75015 Paris, 06 01 21 24 27, SIREN 105 383 988 (RCS
Paris). Relevé sur leurs mentions légales et recoupé avec le registre
officiel le 20 août 2026.
⚠️ Un PDF « LORDHOSTING ASSOCIATION » de 2022 circule encore avec une adresse à Vitry-sur-Seine : c'est l'ancienne structure, ne pas la reprendre. -
NEXT_PUBLIC_MATOMO_SITE_ID=7— confirmé le 20 août 2026 en sondant le serveur :idsite=7répond 200, un identifiant inexistant répond 400. Le 400 observé pendant un audit antérieur ne se reproduit pas. - Jeton Search Console posé dans
src/lib/site.ts. Il reste à ajouter la propriété dans Search Console, cliquer « Vérifier », puis soumettrehttps://jeux.leoderoin.fr/sitemap.xml. - Relire les mentions légales et la page de confidentialité : elles
décrivent une configuration Matomo sans cookie
(
_paq.push(['disableCookies']), posé danssrc/components/Matomo.tsx). Si cette configuration change, le texte devient faux.
- Sa clé et ses quatre slugs dans
SLUGS(src/i18n/routes.ts). - Sa copie dans les quatre dictionnaires, avec au minimum
titleTagetdescription. - Sa clé dans
CONTENT_KEYSsi c'est une page de texte — elle réutilise alorsTextPageViewsans une ligne de plus. - Un dossier de route français, dont le nom EST le slug : il doit rester
identique à
SLUGS.<clé>.fr, rien ne le vérifie. Les autres langues sont servies par[locale]/[slug], qui se génère depuis la table. - Son entrée dans
PAGES(src/app/sitemap.ts).
Les redirections nginx, elles, se régénèrent seules : npm run nginx dérive
nginx/redirects.conf de la table des routes, et npm run build l'appelle.
- Le code dans
LOCALES(src/i18n/config.ts), plus son endonyme et son abréviation. - Un dictionnaire dans
src/i18n/dictionaries/, typéDictionary. - Son
og:localedansOG_LOCALES(src/lib/seo.ts). - Son slug pour chaque page dans
SLUGS(src/i18n/routes.ts).
Ce qui est en place, et qu'il ne faut pas casser :
- une balise
canonicalpar langue, barre finale comprise ; hreflangréciproques entre les quatre langues, plusx-default;sitemap.xmlaveclastmod,changefreqetprioritysur chaque URL — et sansxhtml:link: ces éléments désactivent le visualiseur XML du navigateur, et leshreflangsont déjà dans le<head>des seize pages ;- JSON-LD
WebSite+ItemListdeVideoGame, prix zéro déclaré ; - Open Graph et Twitter Card avec une image 1200×630 par langue ;
/fr/redirigé en 301 vers/, pour ne jamais avoir deux fois la même page.
Vérifier après un changement :
npm run build
grep -o '<link rel="alternate"[^>]*>' out/index.html
head -20 out/sitemap.xmlLes SVG de public/ sont la source des icônes. Les PNG en sont des
rasterisations, versionnées, régénérées par :
npm run og # 4 images de partage (une par langue) + les icônes
npm run fonts # recopie les .woff2 depuis @fontsource-variableL'image de partage n'a pas de fichier source : elle est décrite dans le script, parce qu'elle est paramétrée par langue et que ses textes viennent des dictionnaires.
La construction Docker ne fait que copier les PNG : elle n'a ni sharp ni
polices système, et un rendu de texte y donnerait un résultat différent de
celui vérifié à l'œil.
docker compose -p jeux up -d --buildLe conteneur écoute sur 127.0.0.1:${JEUX_HOST_PORT:-3006} — jamais sur une
interface publique : le proxy inverse de la machine porte le TLS, la limitation
de débit et les journaux.
NEXT_PUBLIC_SITE_URL doit être posée dans le .env du serveur avant
la construction : elle est inlinée dans les fichiers produits, et c'est elle
qui écrit les canoniques, les hreflang et le sitemap. La passer au démarrage
n'a aucun effet.
Voir .env.example pour la liste complète, dont
NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION, qui pose la balise de propriété Google
Search Console. Vide, aucune balise n'est émise.
Mesuré sur l'image de production, Lighthouse 12, sans Matomo :
| Mobile | Desktop | |
|---|---|---|
| Performance | 97 | 100 |
| Accessibilité | 100 | 100 |
| Bonnes pratiques | 100 | 100 |
| SEO | 100 | 100 |
CLS 0, TBT 10 ms, 328 Ko au total. La page « à propos » est à 98 en mobile.
Voir docs/seo.md pour l'audit complet.
Le lien retour depuis Push Your Luck et Loups-Garous vers cette page. Azimut et Reflow le portent déjà, dans leur pied de page. Sans lui, l'annuaire ne reçoit aucun trafic et ne sert qu'à son auteur — c'est le maillage entre les jeux qui justifie le projet, pas la page elle-même.