ThemeForge : un système de thèmes CSS prêt à l’emploi qu’un agent IA installe en une seule étape

Publié
5 octobre 2026
Mis à jour
6 octobre 2026
Par
Jacob Lloyd — rédigé avec l'aide de l'IA, une fois le projet terminé
Temps de lecture
37 min de lecture

En clair : ThemeForge est un dossier gratuit contenant du CSS ainsi qu’un petit script qui ajoute à toute application web un sélecteur de thèmes, dix thèmes colorés et un ensemble complet de boutons, champs, cartes et boîtes de dialogue prêts à l’emploi. Il a été conçu de telle manière qu’un agent de codage IA puisse l’intégrer dans une application en une seule ligne : l’agent suit simplement un fichier présent dans le dépôt, et l’application obtient ainsi un sélecteur fonctionnel, un thème par défaut conforme au système, ainsi que des tokens de conception à utiliser pour le design.

La plupart des applications web finissent par disposer de trois thèmes, définis en trois endroits différents : un bloc :root dans le CSS principal, un second bloc sous @media (prefers-color-scheme: dark), et un troisième inséré manuellement par un développeur pour faire fonctionner le sélecteur de thèmes. Le résultat est toujours le même : un contrôle qui affiche un aspect différent sur la page d’accueil, un autre dans la page des paramètres ; sans oublier les demandes sur les trackers de bugs expliquant pourquoi le thème sombre colore le pied de page en bleu. J’ai créé ThemeForge afin d’éviter ce genre de problèmes. Il s’agit d’un seul dossier, ui-theme/, qui contient le runtime, une couche de base, les classes de composants, les tokens de tous les thèmes, un sélecteur, des adaptateurs optionnels pour Tailwind et Quasar, ainsi qu’un court fichier AGENTS.md destiné à une IA de programmation. Il suffit d’ajouter ce dossier, d’insérer quatre lignes dans l’en-tête de la page, et l’application dispose alors d’un sélecteur fonctionnel ainsi que d’un thème par défaut adapté au système. L’agent chargé de l’installation effectue tout cela via une seule commande ; le reste de cet article s’adresse à ceux qui souhaitent en comprendre le fonctionnement.

Cet article fait office de guide : il décrit le contenu du dossier, les dix thèmes et leurs finalités, la gestion des contrastes, ainsi que les tokens de design et les classes de composants que vous pourrez utiliser comme référence. La seconde partie constitue volontairement un guide consultable : chaque token, chaque composant, chaque méthode publique y sont listés afin qu’une IA de programmation (ou vous-même plus tard) puisse les reprendre tels quels.

Résumé

  • Obtention : github.com/LaserLloyd/ThemeForge — licence MIT, gratuit ; un fichier zip source est également disponible dans la section Téléchargements ci-dessous.
  • Contenu : un seul dossier, ui-theme/, à intégrer dans n’importe quelle application web ; il apporte dix thèmes colorés, un sélecteur, environ 250 tokens de design, une couche élémentaire de base, des standards typographiques et l’ensemble des classes de composants (boutons, champs, interrupteurs, cartes, boîtes de dialogue, notifications, tableaux, shell d’application). Seul du CSS pur et un petit script sont nécessaires. Pas d’étape de compilation, pas de Node, aucune dépendance.
  • Installation en une seule commande (extrait littéralement du README) : python3 -c "import urllib.request as u,sys;sys.argv=['update.py','--dest','static/ui-theme'];exec(u.urlopen('https://raw.githubusercontent.com/LaserLloyd/ThemeForge/main/ui-theme/update.py').read())"
  • En-tête HTML (l’ordre est important) : d’abord ui-theme.js (classique, bloquant, jamais defer ou module) ; ensuite ui-theme-base.css et ui-components.css ; puis le CSS propre à l’application ; enfin ui-theme.css afin que les tokens thématiques priment.
  • Sélecteur : un seul élément : <select class="ui-select" data-ui-theme-picker aria-label="Theme"></select>. Il se remplit automatiquement et reste synchronisé entre les différents onglets.
  • Les dix thèmes : six principaux (Purple, Midnight Gold, Glacier, Forest, Paper, Daylight) plus quatre optionnels (Electric Yellow, LaserLloyd, LaserLloyd Light, Night Red). Chaque thème réussit l’audit de contraste sans aucune défaillance.
  • Contraste : texte principal 7:1, texte secondaire 6:1 ; chaque niveau de texte sur toutes les surfaces atteint 4,5:1 ; les contours des contrôles et leurs états activés/désactivés requièrent un ratio de 3:1. L’état sélectionné ou actif se reconnaît par la forme et le remplissage, pas uniquement par la couleur.
  • Conçu pour les IA : AGENTS.md décrit le script d’installation sous forme de texte — il suffit d’indiquer cette page à une IA pour qu’elle configure le sélecteur en un seul geste. Le CI du dépôt (GitHub Actions, trois tâches) s’exécute correctement sur un clone : audit de contraste, node --check sur chaque fichier JS, et exécution des tests via Chrome sans interface graphique.

Où le trouver

Un unique dépôt sous licence MIT : github.com/LaserLloyd/ThemeForge, contenant AGENTS.md comme script d’installation et le rapport de contraste comme preuve d’audit. Préférez un zip ? La section Téléchargements en bas de page propose le code source complet ; la page Téléchargements du site le liste également. Si votre machine ne dispose pas de Python, le README indique aussi git clone –depth 1, npx degit, ainsi qu’une URL jsDelivr <script> fixée à @v1.0.0 pour les prototypes.

Ce que vous obtenez finalement

En quelques instants, l’application adopte l’apparence souhaitée par l’utilisateur : un en-tête doté d’un sélecteur connaissant tous les thèmes, un mode sombre et un mode clair suivant les préférences du système, et une simple ligne CSS dans le code de l’application qui remplace #1d1d39 par background: var(–surface-2). Choisissez un thème, rechargez la page : aucun effet clignotant n’apparaît. Le script runtime s’exécute de façon synchrone dans <head>, lit ses propres paramètres data-* depuis la balise, puis applique le thème avant même le premier rendu. Ouvrez le sélecteur sur deux onglets, modifiez le thème dans l’un d’eux : l’autre se met à jour automatiquement grâce à un écouteur storage. Lors d’une impression en mode sombre ou OLED, le runtime bascule temporairement vers un thème clair (ou masque la navigation selon la valeur de data-print-theme) afin que le document reste lisible sur papier ; pour un thème clair, l’impression se fait tel quel.

Notes

Boîte de réception

3 notes, 1 non lue

Bilan trimestriel Épinglé

Brouillon du bilan du troisième trimestre — j’attends deux exemples supplémentaires d’ici vendredi.

Liste de préparation du voyage

Passeport, chargeur, la petite lampe torche.

Shell d’application construit à partir de ui-app, ui-card, ui-btn, ui-switch et des tokens --surface-* / --text-* / --accent. Le sélecteur est un simple <select data-ui-theme-picker> — le runtime le remplit et le synchronise.

L’illustration ci-dessus est une démo intégrée à la page, non pas une capture d’écran externe. L’exemple complet — tous les composants dans chaque thème — se trouve dans le dépôt à l’adresse specimen/index.html (à ouvrir via python3 -m http.server puis en se rendant sur /specimen/).

Comment tout s’articule

Le runtime est un petit script, ui-theme.js (environ 23 Ko, 575 lignes) qui effectue trois tâches séquentielles. Il lit d’abord ses attributs data-* depuis la balise <script> où il est inséré (permettant ainsi aux paramètres de voyager avec le fichier), examine ensuite localStorage et les préférences système clair/sombre, puis écrit le thème choisi dans <html data-palette> ainsi que le mode actif dans <html data-theme> (valeurs possibles : amoled, dark, light) avant le premier rendu. Il parcourt ensuite le document à la recherche des éléments <select data-ui-theme-picker> pour les remplir de la liste des thèmes activés (et écoute ceux qui pourraient être ajoutés ultérieurement par un framework). Enfin, il expose window.UITheme et, lorsque ui-components.js est chargé, window.UIComponents, tout en installant un écouteur storage pour maintenir la synchronisation entre plusieurs onglets. Le CSS est tout aussi simple : ui-theme-base.css définit le texte de la page, les liens, l’anneau de focus, les barres de défilement et les réglages de réduction du mouvement ; ui-components.css dessine les boutons, champs, interrupteurs, cartes, boîtes de dialogue, notifications et tableaux ; ui-theme.css est le seul fichier variant selon les thèmes — il définit chaque token (couleur, typographie, espacement, rayon, ombre, animation) pour les dix thèmes via un sélecteur [data-palette=”…”] (le thème Purple correspond à :root, c’est-à-dire l’absence de data-palette). Le runtime sélectionne le thème ; le CSS s’en charge du rendu.

Le suivi du thème du système d’exploitation est ce qui surprend le plus les utilisateurs : data-default=”auto” lit prefers-color-scheme à chaque chargement de page, et le moteur combine cette valeur avec le choix enregistré par l’utilisateur (ou avec data-default-dark et data-default-light) pour déterminer le thème. Changez le thème du système et actualisez la page — elle suit automatiquement. Si l’utilisateur choisit explicitement un thème via le sélecteur, ce choix prévaut jusqu’à ce qu’il soit effacé (ou que UITheme.reset() soit appelé). Le moteur gère également l’événement storage afin que deux onglets ouverts de la même application restent synchronisés sans aucune communication avec le serveur.

Installation

Le fichier AGENTS.md du dépôt contient le guide complet ; voici la version abrégée ainsi que les quatre balises à insérer dans l’en-tête. Depuis la racine de l’application :

python3 -c "import urllib.request as u,sys;sys.argv=['update.py','--dest','static/ui-theme'];exec(u.urlopen('https://raw.githubusercontent.com/LaserLloyd/ThemeForge/main/ui-theme/update.py').read())"

Ce script télécharge l’installateur, qui récupère la dernière version, compare chaque fichier à sa liste SHA-256 dans files.json et écrit le dossier sur le disque. Sur Windows, utilisez python ou py au lieu de python3 ; la commande fonctionne pareillement dans PowerShell, cmd et bash. Les quatre lignes à placer dans l’élément <head> de chaque page :

<script src="/static/ui-theme/ui-theme.js"
        data-themes="purple,midnight-gold,glacier,forest,paper,daylight"
        data-default="auto" data-default-dark="midnight-gold" data-default-light="daylight"
        data-storage-key="myapp.theme"></script>
<link rel="stylesheet" href="/static/ui-theme/ui-theme-base.css">
<link rel="stylesheet" href="/static/ui-theme/ui-components.css">
<!-- vos feuilles de style -->
<link rel="stylesheet" href="/static/ui-theme/ui-theme.css">

Trois règles, chacune pour une raison précise. Le script ui-theme.js est classique et bloquant — jamais type=”module”, defer ou async — car il lit ses paramètres depuis sa propre balise (document.currentScript, qui vaut null pour les scripts module) et définit le thème avant le premier rendu. Les couches de base et de composants se chargent avant la CSS de l’application afin que les règles propres à l’app aient la même spécificité. ui-theme.css vient en dernier, empêchant ainsi toute variable ancienne de l’application de masquer un token de thème. Le sélecteur ne nécessite qu’une seule ligne : <select class=”ui-select” data-ui-theme-picker aria-label=”Theme”></select>. En script, on dispose de UITheme.set(‘glacier’), UITheme.current() et UITheme.onChange(fn). L’installation complète prend environ cinq minutes, comme indiqué dans l’introduction d’AGENTS.md.

L’agent qui a effectué cette installation en une seule étape sur une vraie application ressemblait à ceci : un humain a demandé à un agent de codage IA de mettre en place un mode sombre et un sélecteur de thèmes. L’agent a lu AGENTS.md, exécuté la commande unique dans static/ui-theme/, inséré les quatre balises d’en-tête dans le modèle de base, remplacé deux valeurs de couleur par var(–surface-2) et var(–text-secondary), puis ajouté le sélecteur en haut de page. Six lignes seulement modifiées dans l’application, aucune nouvelle dépendance. L’audit de contraste couvre déjà toutes les paires possibles générées par les composants ; le moteur suit automatiquement le thème du système d’exploitation, et un futur commit qui codifierait une couleur serait immédiatement détecté par l’étape de lint.

Les thèmes

Les six premiers constituent la gamme de base proposée par défaut ; les quatre autres ne s’affichent que si l’application les répertorie explicitement. Chaque thème passe avec succès l’audit de contraste (docs/contrast-report.md) : le texte principal a un ratio de 7:1, le texte secondaire 6:1 sur toute surface, tous les autres niveaux de texte 4,5:1 ; les bords des contrôles et leurs états « on » ou « sélectionné » respectent le ratio de 3:1, et la forme suffit à identifier ces états en plus de la couleur dans chaque thème. Voici la liste complète :

Thème Catégorie Fond Description
Purple de base sombre Accent violet et texte lavande doux sur un indigo profond. C’est le thème de base : ses valeurs correspondent aux paramètres par défaut de :root.
Midnight Gold de base OLED Or chaud sur du noir pur, idéal pour les écrans OLED.
Glacier de base OLED Texte et signature bleu glace sur noir pur, avec un accent turquoise profond.
Forest de base OLED Vert sauge pâle et lichen, avec des bruns d’écorce sur noir pur.
Paper de base clair Parchemin chaleureux, texte brun encre, police serif pour les textes longs et un accent rouge.
Daylight de base clair Blanc épuré avec un accent bleu.
Electric Yellow optionnel sombre Jaune acide sur gris graphite, avec des rayons arrondis et des traits nets.
LaserLloyd optionnel sombre Bleu laser sur un gris graphite presque noir, inspiré du site de l’auteur. Il s’associe à LaserLloyd Light.
LaserLloyd Light optionnel clair Version claire du thème LaserLloyd.
Night Red optionnel OLED Thème nocturne à faible émission de lumière bleue : texte couleur braise sur noir pur, structure rouge, aucune composante bleue dans aucune couleur.

Trois des quatre thèmes optionnels sont volontairement très contrastés. Electric Yellow est celui que j’utilise lorsque je révise du CSS dans le noir et que je veux que la page ressorte davantage que mon éditeur ; LaserLloyd reprend l’aspect bleu-graphite de ce site afin d’assurer la cohérence entre le site et l’application que je développe ; Night Red constitue un « profil nocturne » à part, soumis par l’outil de contraste à une vérification étendue sur 171 lignes (147 standards plus des lignes supplémentaires pour les conditions de faible luminosité) où chaque token du thème comporte zéro valeur bleue (docs/contrast-report.md section « Audit sans bleu » ; README.md §Night Red ; docs/THEMES.md §Night Red).

Pièges à éviter

  • Une couleur codée en dur dans votre CSS est le bug, pas le thème. L’audit ne vérifie que les tokens ; un color: #fff dans le code de l’application reste blanc quel que soit le thème. tools/lint_colors.py (dans le dépôt) ainsi que la commande grep dans AGENTS.md §8 détectent ce problème ; le lint en CI ne lance pas cette étape, donc exécutez-la localement avant de fusionner.
  • ui-theme.js doit être placé en premier dans <head>, en mode classique, et non avec defer ou module. Un script en mode module ne dispose pas de document.currentScript, et le runtime lit ses propres attributs data-* depuis la balise. Le symptôme est un affichage temporaire du mauvais thème, puis du bon thème.
  • ui-theme.css doit se charger après le CSS de l’application, et non avant. L’ordre est : base, composants, application, tokens. Une règle de l’application ayant la même spécificité mais chargée après les tokens est écrasée.
  • data-themes détermine ce que le sélecteur de thèmes affiche. Un thème enregistré dont le slug ne figure pas dans data-themes est ignoré lors du prochain chargement (le runtime revient alors au thème par défaut). Lorsque vous supprimez un thème, ajoutez une fois data-legacy-key et data-legacy-map afin de migrer la valeur enregistrée.
  • Les classes rounded-md et font-sans de Tailwind changent après l’installation. C’est normal : le thème définit les tokens –radius- et –font-, dont les valeurs priment. Ne tentez pas de les modifier.
  • Avertissement d’hydratation de Next.js. Ajoutez suppressHydrationWarning à <html> et désactivez la règle de lint no-sync-scripts pour le bloc : le runtime définit des attributs sur <html> avant que React ne procède à l’hydratation.
  • Une autre bibliothèque lit data-theme sur <html> (daisyUI, Pico). Le runtime écrit alors data-theme=”amoled|dark|light” dans cette balise ; vérifiez que la bibliothèque ne réagit pas à cela. Si c’est le cas, utilisez data-mirror-attr pour lui attribuer un autre attribut.
  • Ne modifiez rien à l’intérieur de ui-theme/. Ce dossier est remplacé lors des mises à jour ; le lint détecte toute modification manuelle et l’installation refusera de surcharger un fichier modifié. Transférez plutôt vos modifications dans le CSS propre à l’application.
  • Les polices mentionnées dans les stacks ne sont pas intégrées par défaut. Chaque stack fait appel aux polices système en cas de besoin ; si vous souhaitez utiliser Inter, JetBrains Mono, Space Grotesk ou Archivo, chargez-les vous-même (le document d’intégration propose un extrait <link> à copier-coller).
  • prefers-contrast: more augmente l’épaisseur des traits et rend plus lisibles les textes les plus clairs. Aucun paramètre de thème n’est nécessaire ; le runtime détecte cette requête et le CSS s’adapte en conséquence. Le groupe de tokens high-contrast constitue l’option héritée pour obtenir le même effet.

Où cela me laisse-t-il ?

Ce que je voulais, c’était un moyen d’offrir à chaque application que je développe un vrai système de thèmes, sans avoir à en écrire un depuis zéro à chaque fois ; ThemeForge est donc la version que je souhaite conserver. Les dossiers que j’intègre dans les applications sont désormais ui-theme/ et un autre dossier correspondant aux fonctionnalités propres à l’application ; les quatre balises head-block ainsi que le sélecteur de thèmes restent identiques quel que soit le framework utilisé. L’agent chargé de l’installation lit le fichier AGENTS.md, et non un message Slack. Les audits de contraste, les tests d’exécution via Chrome headless, ainsi que node –check sur chaque fichier JS distribué me donnent la confiance nécessaire pour continuer à avancer. La version est fixée à 1.0.0 car les tokens constituent l’API publique ; renommer un token équivaut donc à une mise à jour majeure. Chaque version correspond à une balise Git, le dossier VERSION est synchronisé en conséquence, et les fichiers JSON sont signés par la même liste de sommes de contrôle que celle vérifiée par update.py. La CI du dépôt lui-même fonctionne correctement sous Linux, Windows et Python 3.9 ; les mêmes vérifications s’effectuent sans problème sur une nouvelle copie du code sur cette machine.

Référence (pour les agents d’IA)

Le reste de cet article constitue une fiche de référence qu’un agent de codage (ou mon futur moi) peut copier mot pour mot. La première moitié ci-dessus est du texte descriptif ; la seconde moitié est structurée, facile à parcourir et conçue pour être lue par un outil. Chaque token, chaque classe de composant, chaque méthode publique sur window.UITheme et window.UIComponents, chaque thème, chaque paramètre configurable via les balises script, chaque adaptateur, le chemin d’installation complet, les règles de contraste ainsi que les informations de version se trouvent ci-dessous.

Manifeste de fichiers

Le dépôt contient deux arborescences importantes : le bundle que l’application copie, et les outils ainsi que la conception permettant de le créer. Cet article porte sur le bundle.

Paquet d’intégration — ce que l’application copie (ui-theme/):

Fichier Taille Lignes Description
ui-theme.js 23 515 o 575 En temps d’exécution : applique le thème sauvegardé avant le premier affichage, suit les paramètres clair/sombre du système via data-default="auto", remplit les sélecteurs de thèmes, synchronise les onglets, expose window.UITheme
ui-theme-base.css 13 255 o — Valeurs par défaut des éléments : texte du corps, liens, titres, code, anneau de focus, barres de défilement, gestion du mouvement réduit, niveaux de texte, .ui-markdown, couleurs de highlight.js
ui-components.css 51 344 o — Composants : boutons, champs, cases à cocher, boutons radio, commutateurs, cartes, badges, boîtes d’information, onglets, contrôles segmentés, tableaux, boîtes de dialogue, menus, infobulles, notifications, barre de progression, blocs de code, ainsi qu’un shell d’application
ui-theme.css 86 389 o (21 197 o compressé en gzip) — Jetons de tous les dix thèmes (environ 20 Ko compressés en gzip)
ui-components.js 5 441 o 135 Fonctions optionnelles confirm(), alert(), prompt() et toast() adaptées au thème
ui-theme.d.ts 2 841 o — Déclarations TypeScript pour window.UITheme et window.UIComponents
update.py 16 081 o — Installe et met à jour le dossier ; vérifie chaque fichier via son hash SHA-256
themes.json 4 089 o — Liste des thèmes (nom, famille, couleur de fond, jeu de couleurs, échantillons, polices)
files.json 1 401 o — Liste des sommes de contrôle que update.py vérifie
VERSION 30 o — Version du dossier (ThemeForge 1.0.0 3db64d9f574f)
README.md 6 342 o — Notes d’utilisation propres au paquet
adapters/quasar.css 24 997 o — Mappage NiceGUI/Quasar
adapters/quasar.js 1 468 o 40 Pont JavaScript NiceGUI/Quasar
adapters/tailwind.css 4 399 o — Mappage @theme inline pour Tailwind CSS v4
adapters/tailwind-v3.preset.js 2 915 o 54 Préréglage pour Tailwind CSS v3

Le design et les outils utilisés pour créer le bundle (non copiés dans l’application) :

Fichier Taille Description
README.md 6,592 B README du dépôt
AGENTS.md 19,063 B Le script d’installation, présenté sous forme de texte, destiné aux agents IA
CHANGELOG.md 4,425 B Historique des versions (1.0.0 est la première version publiée)
CLAUDE.md 1,498 B Conventions du dépôt pour Claude
CONTRIBUTING.md 4,476 B Comment contribuer au développement des thèmes
LICENSE 1,067 B Licence MIT ; copyright © 2026. Le fichier original cite l’auteur par son nom personnel ; le site utilise une forme de marque ; la chaîne de texte sur disque correspond à celle du fichier LICENSE d’origine. Non inclus dans le fichier zip de téléchargement : la ligne de copyright originale mentionne l’auteur par son nom personnel, et le système de protection du site considère cela comme une divulgation d’identité non vérifiable.
docs/TOKENS.md 15,391 B Liste de tous les tokens, classés par groupe
docs/COMPONENTS.md 13,889 B Description de toutes les classes de composants, avec exemples de code
docs/THEMES.md 8,081 B Présentation des thèmes, notes de conception et procédure pour en ajouter un nouveau
docs/INTEGRATIONS.md 10,604 B Étapes d’installation selon chaque framework
docs/TEXT.md 5,465 B Niveaux de texte et style Markdown utilisé
docs/UPDATING.md 4,134 B Procédure de mise à jour, verrouillage des versions, mise en cache, explication sur la validité des sommes de contrôle
docs/contrast-report.md 124,372 B Rapport d’audit de contraste (10 thèmes × 147 à 171 lignes)
docs/theme-template.css 9,854 B Modèle de thème vide destiné à tools/sync_theme.py
tokens/<theme>.json ~57 Ko chacun Tokens résolus pour chaque thème, au format JSON conforme aux spécifications W3C DTCG
examples/static-html/ 3,731 B (fichier index) Exemple simple en HTML/CSS/JS
examples/fastapi-jinja/ 2,172 B (fichier app.py) Exemple d’utilisation avec FastAPI et Jinja
specimen/index.html 17,721 B Présentation locale de tous les composants dans tous les thèmes
tools/check_contrast.py 43,171 B Script d’audit de contraste (exécuté en CI)
tools/lint_colors.py 22,711 B Vérification des valeurs de couleur dans le CSS de l’application
tools/sync_theme.py 41,671 B Génère à nouveau ui-theme.css, tokens/*.json et docs/contrast-report.md à partir de src/css/*.css
tools/update.py 16,081 B Script d’installation/vérification (équivalent à ui-theme/update.py)
tools/screenshots.py 3,273 B Génération de captures d’écran des thèmes pour docs/images/
tests/test_tools.py 17,606 B Tests unitaires en Python (32 tests dans cette copie ; 1 test est ignoré)
tests/run_browser_tests.py 3,570 B Tests exécutés via Chrome headless sur l’environnement de runtime
tests/runtime.html 24,930 B Script de test pour le navigateur
.github/workflows/ci.yml — Configuration CI : vérification du contraste, node --check, tests unitaires, tests navigateur, vérification des caractères CRLF ; exécuté sur Linux, Windows et Python 3.9

Le CI propre au dépôt exécute trois tâches : checks sur Ubuntu avec Python 3.12, tools-on-windows sur Windows avec Python 3.11, et updater-on-oldest-python sur Ubuntu avec Python 3.9. Le clone local passe le test node --check pour chaque fichier JS distribué ; l’outil de contraste reproduit les dix lignes de l’audit, et tous les tests unitaires réussissent (32 tests réussis, 1 ignoré en 1,212 s sous Linux avec Python 3.14, le 05/10/2026).

Jeton de conception (groupes, rôle, valeur d’exemple)

Chaque thème résout tous les jetons. Les valeurs ci-dessous correspondent à celles de Purple (la base :root) ; les autres thèmes disposent de leurs propres valeurs résolues dans tokens/<theme>.json (format JSON DTCG). Utilisez un jeton via var(--nom). Ne redéclarez jamais un jeton dans le CSS de l’application : attribuez aux variables d’application un préfixe propre à l’application (--myapp-sidebar-w) ou créez un alias pour le jeton (--myapp-brand: var(--accent)). Source : docs/TOKENS.md.

Groupe Token Rôle Exemple (Violet)
Surfaces --surface-void plus foncé que la page (pleine largeur) #08080f
Surfaces --surface-0 la page #0e0e1b
Surfaces --surface-1 barre de navigation #14142a
Surfaces --surface-2 cartes #1d1d39
Surfaces --surface-3 état survol #232342
Surfaces --surface-4 état actif #262648
Surfaces --surface-sunken zones en retrait #0a0a14
Surfaces --surface-overlay menus, popovers #1d1d39
Surfaces --glass-1/2/3 panneaux translucides rgba(29,29,57,.72/.84/.92)
Surfaces --glass-highlight effet de brillance sur le verre rgba(255,255,255,.055)
Surfaces --code-bg arrière-plan du code #0b0b16
Texte --text-primary texte principal #e8e8f0
Texte --text-secondary étiquettes, descriptions #a0a0bd
Texte --text-tertiary indices, horodatages #8d8db0
Texte --text-disabled contrôles désactivés #717195
Texte --text-inverse texte sur un fond clair #0e0e1b
Texte --text-link / --text-link-hover liens et texte d’accentuation #a78bfa / #c4b5fd
Texte --on-accent / --on-danger / --on-success / --on-warning / --on-media / --on-media-muted texte sur un fond d’accentuation #ffffff / #2a0808 / …
Accentuation --accent / --accent-hover / --accent-pressed accent de marque, actions principales #7c3aed / #8250f0 / #6d28d9
Accentuation --accent-subtle / --accent-muted / --accent-glow arrière-plan teinté, remplissage doux, effet de lueur rgba(124,58,237,.16/.26/.35)
Accentuation --accent-rgb permet à le JS de composer rgba(var(--accent-rgb), .2) 124,58,237
Accentuation --accent-2 / --accent-2-subtle accentuation secondaire #5eead4
Appels à l’action --cta / --cta-hover / --cta-pressed / --on-cta zone d’action principale #7c3aed / #8250f0 / #6d28d9 / #ffffff
Appels à l’action --cta-shadow / --cta-shadow-hover ombres portées pour la zone d’action 0 6px 20px rgba(124,58,237,.28) / .38
Appels à l’action --highlight / --highlight-subtle / --on-highlight marqueurs, couleur des infobulles #fcd34d / rgba(252,211,77,.12) / #251a00
Lignes --border-subtle / --border / --border-strong les bords des contrôles de formulaire sont --border-strong avec un ratio de 3:1 #21213b / #292945 / #6f6f9c
Lignes --divider lignes fines #21213b
Lignes --focus-ring / --focus-ring-width / --focus-ring-offset cercle de focus #a78bfa / 2px / 2px
Lignes --glass-stroke / --glass-stroke-strong bordures en verre rgba(255,255,255,.08/.16)
États des contrôles --selected / --on-selected activé / coché / enfoncé / actuel selon le thème
États des contrôles --unselected-border / --unselected-fg contour désactivé, ratio de 3:1 sur toutes les surfaces selon le thème
Statut --success / --warning / --danger / --info points, barres, remplissages selon le thème
Statut --success-text / --warning-text / --danger-text / --info-text couleur du texte pour chaque statut selon le thème
Statut --success-subtle / --warning-subtle / --danger-subtle / --info-subtle arrière-plan teinté pour chaque statut selon le thème
Statut --success-border / --warning-border / --danger-border / --info-border bordures de statut selon le thème
Statut --idle / --idle-text / --idle-subtle / --idle-border / --idle-hover état neutre selon le thème
Statut --live / --live-text / --live-subtle / --live-border / --live-hover indicateur « actif » / « en cours d’exécution » selon le thème
Code / syntaxe --syn-bg / --syn-fg / --syn-comment / --syn-keyword / --syn-string / --syn-number / --syn-function / --syn-attr / --syn-tag / --syn-builtin / --syn-type / --syn-variable / --syn-literal / --syn-operator / --syn-title / --syn-addition palette de mise en évidence syntaxique selon le thème
Code / syntaxe --code-header-bg / --code-stroke bordures des blocs de code (foncées dans tous les thèmes) selon le thème
Graphiques --cat-1 … --cat-12 couleurs des séries, ratio de 3:1 sur --surface-0 selon le thème
Graphiques --seq-1 … --seq-5 palette du plus clair au plus foncé selon le thème
Graphiques --div-1 … --div-5 mauvais, neutre, bon selon le thème
Graphiques --chart-grid / --chart-axis éléments graphiques des graphiques selon le thème
Bulles de dialogue --bubble-user-text / --bubble-assistant-text / --bubble-user-bg / --bubble-assistant-bg bulles de chat selon le thème
Bulles de dialogue --rp-speech / --rp-thought / --rp-shout / --rp-whisper / --rp-ooc / --rp-action / --rp-critical couleurs des bulles de rôle-play selon le thème
Différences --diff-add-bg / --diff-add-text / --diff-remove-bg / --diff-remove-text vue des différences selon le thème
Typographie --fs-xs / --fs-sm / --fs-md / --fs-lg / --fs-xl / --fs-2xl tailles de police selon le thème
Typographie --fw-medium / --fw-semibold / --fw-bold épaisseurs de police selon le thème
Typographie --font-sans / --font-mono / --font-display polices utilisées selon le thème
Espacement --space-1 … --space-8 4 à 64 px selon le thème
Rayons --radius-sm / --radius-md / --radius-lg / --radius-pill formes des contrôles selon le thème
Ombres --shadow-1 / --shadow-2 / --shadow-3 / --shadow-4 niveaux d’ombres portées selon le thème
Couches Z --z-modal / --z-toast / --z-popover / --z-nav ordre de superposition selon le thème
Animation --motion-fast / --motion-med / --motion-slow / --easing-standard durées d’animation (le mode « réduction du mouvement » arrête les boucles) selon le thème
Markdown --md-bold / --md-italic / --md-bolditalic / --md-bolditalic-glow mise en forme Markdown dans l’application selon le thème
Divers --mark-bg / --selection-text / --selection-bg / --media-filter / --quote-bar / --heartbeat-text / --heartbeat-hover / --offline-text / --on-offline / --canvas-handle petites fonctionnalités selon le thème

Source : docs/TOKENS.md (22 groupes, environ 270 tokens — grep -oE '\| \(–[a-zA-Z][a-zA-Z0-9-]*)` |’ docs/TOKENS.md | sort -u | wc -lrenvoie 272 noms de tokens uniques ; 22 groupes## `).

Classes de composants (chaque modificateur, sur une seule ligne)

L’état provient des attributs natifs (disabled, checked, aria-pressed, aria-selected, aria-current, aria-invalid, aria-busy, [open]) — jamais d’une classe supplémentaire. La plupart des sélecteurs ne comportent qu’une seule classe afin qu’une règle ultérieure de même spécificité puisse l’écraser. Les propriétés logiques sont utilisées partout (fonctionnent en écriture de droite à gauche). « On », « coché », « enfoncé » et « actuel » utilisent --selected ; « off » correspond à un contour ; « désactivé » se caractérise par un trait en pointillés et aucun remplissage. Source : docs/COMPONENTS.md.

Classe Modificateurs / parties Description
ui-stack — Colonne, espacement --space-3
ui-row — Ligne à enroulement, centrée, espacement --space-2
ui-grid --ui-grid-min Colonnes auto-générées, min défini sur l’élément
ui-container — Centré, largeur maximale --content-max
ui-spacer — Pousse le reste de la ligne vers la fin
ui-app __header __nav __main Structure d’application (en-tête, navigation latérale, contenu principal) ; la navigation se masque en dessous de 760 px
ui-brand — Titre de l’application dans l’en-tête
ui-nav __label __item Navigation latérale
ui-title / ui-heading / ui-subheading / ui-lead / ui-kicker / ui-small / ui-mono / ui-num / ui-kbd / ui-code / ui-divider — Hiérarchie typographique (<hr> correspond à .ui-divider)
ui-text-primary / -secondary / -tertiary / -disabled / -link — Classes de niveaux de texte (utilisez les tokens pour du nouveau code)
ui-markdown — Conteneur pour le Markdown rendu ; voir docs/TEXT.md
ui-btn --primary --ghost --outline --danger --cta --sm --lg --icon --block Boutons ; fonctionne aussi avec <a> ; s’associe à aria-pressed / aria-busy / disabled
ui-btn-group — Boutons adjacents partagent un bord arrondi
ui-field — Conteneur de champ de formulaire (étiquette + contrôle + aide)
ui-label — Étiquette du champ
ui-input --sm Champ de saisie texte
ui-select — <select> stylisé ; data-ui-theme-picker active le sélecteur de thème
ui-textarea — <textarea> stylisé
ui-help — Texte d’aide du champ (liens vers aria-describedby)
ui-error — Texte d’erreur du champ (liens vers aria-describedby) ; s’affiche lorsque aria-invalid="true"
ui-input-group — Paire champ + bouton (ex. : recherche)
ui-check — Ligne de cases à cocher / boutons radio / interrupteurs
ui-checkbox — <input type="checkbox"> natif stylisé
ui-radio — <input type="radio"> natif stylisé
ui-switch — Case à cocher role="switch" stylisée comme un interrupteur
ui-switch-state data-on data-off Étiquettes « On » / « Off » (masquées aux lecteurs d’écran ; l’interrupteur annonce lui-même son état)
ui-range — Champ de sélection de plage natif coloré avec --slider-color
ui-segmented — Groupe de boutons agissant comme des boutons radio
ui-tabs ui-tab Liste d’onglets (les onglets liens utilisent <a aria-current="page">) ; la gestion au clavier relève de l’application
ui-card __header __title __footer --raised --interactive Carte ; aria-selected / aria-current mettent en évidence une carte sélectionnée
ui-well — Zone en retrait (journaux, prévisualisations, contenu secondaire)
ui-stat __label __value Paire étiquette / valeur
ui-badge --success --warning --danger --info --live --accent --neutral Badge en forme de pilule
ui-dot --success --warning --danger --info --live --neutral Point d’état
ui-count --accent --danger Compteur
ui-callout --info --success --warning --danger __title Zone colorée (utilisez role="alert" pour les erreurs)
ui-table-wrap — Conteneur pour <table class="ui-table"> afin d’avoir des en-têtes collants / défilement
ui-table --hover --compact td.num Styles de tableau
ui-dialog — <dialog> stylisé
ui-drawer — Panneau latéral sur <dialog>
ui-menu __item Liste de menus
[data-ui-tooltip] data-ui-tooltip-side="bottom" Infobulle sur n’importe quel élément
ui-progress — Barre de progression linéaire
ui-spinner — Indicateur de chargement
ui-skeleton — Skeleton de chargement
ui-breadcrumbs — Liste de navigation
ui-pagination — Pagination
ui-avatar — Avatar circulaire
ui-chip __remove Chip supprimable / sélectionnable
ui-details — Accordéon basé sur <details>
ui-fieldset — Ensemble de champs + légende
ui-codeblock __bar <figure> contenant <figcaption class="ui-codeblock__bar"> + <pre>
ui-empty — État vide
ui-bubble --user --assistant Bulle de chat

Méthodes publiques sur window.UITheme et window.UIComponents

Source : ui-theme/ui-theme.d.ts (déclarations TypeScript pour les deux objets globaux).

window.UITheme (UIThemeApi) :

Membre Type Rôle
version string (en lecture seule) La version du dossier, ex. "1.0.0"
config objet (en lecture seule) { themes, default, auto, storageKey, families, printTheme }
current() () => string Le slug du thème actif
theme([slug]) (slug?) => UIThemeInfo \| null Informations sur un thème (ou le thème actif)
list() () => UIThemeInfo[] Tous les thèmes activés
set(slug) (slug) => string Basculer vers un thème ; renvoie le slug
reset() () => string Revenir au thème par défaut ; renvoie le slug
partner([slug]) (slug?) => string \| null Le partenaire clair/sombre d’une famille (ex. laserlloyd ↔ laserlloyd-light)
toggleFamily() () => string \| null Basculer vers le thème partenaire ; renvoie le nouveau slug
onChange(listener) (fn) => () => void S’abonner ; renvoie une fonction pour se désabonner ; detail.print vaut true lors d’un changement lié à l’impression
token(name, [el]) (name, element?) => string Valeur brute du token (ex. "#7c3aed")
tokens(names, [el]) (names, element?) => Record<name, string> Plusieurs tokens à la fois
color(name) (name) => string Couleur au format rgb() pour le canevas
colors(names) (names) => Record<name, string> Plusieurs couleurs au format rgb() pour le canevas
mountPicker(target, [opts]) (elOrSel, options?) => HTMLSelectElement \| null Remplir un sélecteur en tant que sélecteur de thèmes ; les options sont { label, coreLabel, optInLabel, systemLabel }

L’événement ui-theme-change est déclenché sur document avec { slug, theme, previous, print }.

window.UIComponents (UIComponentsApi) : (nécessite ui-components.js)

Méthode Signature Rôle
confirm (opts: UIDialogOptions \| string) => Promise<boolean> confirm() thématisé ; les options sont { title, message, label, confirmLabel, cancelLabel, danger }
alert (opts: UIDialogOptions \| string) => Promise<void> alert() thématisé
prompt (opts: UIPromptOptions \| string) => Promise<string \| null> prompt() thématisé ; renvoie null si l’utilisateur annule ; options supplémentaires : { value, placeholder, type }
toast (message, { kind?, timeout? }) => HTMLElement Toast de type info / success / warning / danger ; renvoie l’élément créé

window.UI_THEME_MANIFEST (optionnel, prioritaire sur les valeurs par défaut définies dans la balise <script>) : { themes, default, defaultDark, defaultLight, storageKey, families, legacy, mirrorAttr, fontsHref, printTheme }. themes accepte un tableau ou une chaîne de caractères séparée par des virgules.

Paramètres via la balise <script> (data-*)

Attribut Valeur par défaut Rôle
data-themes les six thèmes principaux (purple,midnight-gold,glacier,forest,paper,daylight) Liste de thèmes activés, séparés par des virgules ; détermine le contenu du sélecteur et les valeurs stockées. Sans data-themes, ui-theme.js active les six thèmes avec set==="core" (ui-theme.js:147-149).
data-default le premier thème activé (premier slug dans data-themes, ou purple si aucun n’est activé et que auto n’est pas défini) Le slug du thème par défaut ; la valeur littérale auto active le suivi automatique des paramètres système via prefers-color-scheme (ui-theme.js:164) ; un attribut manquant ou vide renvoie au premier thème activé (ui-theme.js:177-179).
data-default-dark le premier thème non clair activé (premier slug dans data-themes où ground !== "light", sinon le premier thème activé, ou purple si rien n’est activé) Correspond à la version sombre du mode auto. ui-theme.js:168-175 l’utilise lorsque le système préfère le mode sombre et qu’aucune valeur explicite n’est définie.
data-default-light le premier thème clair activé (premier slug dans data-themes où ground === "light", sinon le premier thème activé, ou purple si rien n’est activé) Correspond à la version claire du mode auto. Même logique que ci-dessus (ui-theme.js:168-175).
data-storage-key ui-theme Clé utilisée dans localStorage pour stocker le choix de l’utilisateur (ui-theme.js:185). AGENTS.md §3 recommande de la modifier en <nom_app>.theme afin d’éviter les conflits entre plusieurs applications ThemeForge sur la même origine.
data-families false Regrouper les thèmes par famille dans le sélecteur
data-print-theme auto Thème utilisé lors de l’impression : si le thème actif est sombre ou OLED, auto bascule vers le partenaire clair de la famille (ou le premier thème clair activé, ou daylight) ; un slug spécifique force l’utilisation de ce thème ; none empêche tout changement ; si le thème actif est clair, rien ne change (ui-theme.js:474-490).
data-legacy-key — Ancienne clé de stockage à migrer une seule fois (avec data-legacy-map)
data-legacy-map — Correspondance d’ancien vers nouveau pour les valeurs héritées (objet JSON)
data-mirror-attr — Copier le thème actif dans un autre attribut (utile pour les bibliothèques qui s’y réfèrent)
data-fonts-href — URL d’une feuille de style à injecter pour la typographie du thème

Sources : ui-theme.js:147-149, 164, 168-174, 185, 474-490 (valeurs par défaut) et AGENTS.md §3, §12 (recommandations de personnalisation — ex. définir data-themes avec les six thèmes principaux, data-default="auto", data-storage-key="<nom_app>.theme").

Adaptateurs

Adaptateur Fichiers Rôle
NiceGUI / Quasar adapters/quasar.js + adapters/quasar.css Charger adapters/quasar.js juste après ui-theme.js et adapters/quasar.css après ui-theme.css (via ui.add_head_html). Les boutons, cases à cocher et radios de Quasar adoptent le design des contrôles thématisés ; les contrôles désactivés sont affichés en trait discontinu avec une opacité maximale. Supprimer tout appel à ui.dark_mode() — l’adaptateur s’en charge.
Tailwind CSS v4 adapters/tailwind.css @import "./<chemin>/ui-theme/adapters/tailwind.css"; après @import "tailwindcss";. Définit bg-surface-2, text-fg, text-fg-muted, bg-accent, text-on-accent, border-line, etc. Les textes utilisent les classes fg-* car Tailwind gère les tailles via text-*.
Tailwind CSS v3 adapters/tailwind-v3.preset.js presets: [require('./<chemin>/ui-theme/adapters/tailwind-v3.preset.js')]. Mêmes tokens que l’adaptateur v4, mais exprimés sous forme de preset v3.

L’adaptateur Tailwind mappe les tokens du thème ; celui de Quasar mappe les classes des composants. Aucun n’est obligatoire pour le bon fonctionnement du reste du bundle.

Procédure d’installation complète (copier tel quel, extrait d’AGENTS.md)

AGENTS.md est un script d’installation rédigé sous forme de texte, destiné aux agents de programmation IA. Les deux premières sections sont reproduites ci-dessous intégralement ; c’est le prompt auquel l’agent doit être confronté. Les caractères sont échappés conformément à la règle §8 du skill article-forge (un <blockquote> brut interprète le markdown littéralement, donc <, >, & doivent être remplacés par &lt;, &gt;, &amp;).

## 1. Décider une fois

| Question | Réponse par défaut |
|---|---|
| Où placer le dossier ? | Dans le dossier statique de l’application, tel quel : `static/ui-theme/` (Flask, FastAPI, Django), `public/ui-theme/` (Vite, Next.js, Create React App), `app/static/ui-theme/` ou à côté de `index.html` pour un site simple. |
| Quels thèmes activer ? | Les six thèmes principaux : `purple,midnight-gold,glacier,forest,paper,daylight`. Ajouter les thèmes optionnels (`night-red`, `electric-yellow`, `laserlloyd`, `laserlloyd-light`) uniquement si l’utilisateur le demande. |
| Thème par défaut ? | `auto` : le thème suit automatiquement les paramètres clair/sombre du système jusqu’à ce que l’utilisateur fasse un choix (`data-default-dark="midnight-gold"`, `data-default-light="daylight"`). |
| Clé de stockage ? | `<nom_app>.theme`, ex. `notes.theme`. |

## 2. Installer

Exécuter depuis le dossier racine de l’application (Python 3.9 ou supérieur ; remplacer `static/ui-theme` par le chemin choisi) :


python3 -c &quot;import urllib.request as u,sys;sys.argv=['update.py','--dest','static/ui-theme'];exec(u.urlopen('https://raw.githubusercontent.com/LaserLloyd/ThemeForge/main/ui-theme/update.py').read())&quot;
Sur Windows, utiliser `python` (ou `py`) au lieu de `python3` ; la ligne fonctionne de la même manière dans PowerShell, cmd et bash. Elle télécharge l’outil d’installation qui récupère la dernière version sur GitHub, vérifie chaque fichier via ses sommes de contrôle et crée le dossier. Pour les mises à jour ultérieures : `python3 static/ui-theme/update.py`. En mode hors ligne : télécharger un archive `.tar.gz` ailleurs, puis exécuter `python3 update.py --source <archive> --dest static/ui-theme` en utilisant le fichier `update.py` présent dans le dossier `ui-theme/`. Autres méthodes, si Python n’est pas disponible : - **git :** `git clone --depth 1 https://github.com/LaserLloyd/ThemeForge.git ut-tmp`, copier `ut-tmp/ui-theme` dans l’application puis supprimer `ut-tmp`. - **Node :** `npx degit LaserLloyd/ThemeForge/ui-theme#v1.0.0 static/ui-theme`. - **Pas d’installation (prototypes, pages HTML isolées) :** charger les fichiers depuis jsDelivr en pointant sur une version fixe : `https://cdn.jsdelivr.net/gh/LaserLloyd/ThemeForge@v1.0.0/ui-theme/ui-theme.js` (et le même chemin pour chaque fichier CSS). Ne jamais utiliser `@main` car le CDN met en cache les versions jusqu’à 12 heures. Pour mettre à jour une page via le CDN, il suffit de changer la version indiquée ; les étapes 8.5, 9 et 10 ci-dessous ne s’appliquent pas dans ce cas.

Les autres sections d’AGENTS.md (3 à 12) décrivent le bloc <head> à insérer, le sélecteur de thèmes, la génération de tokens, les règles, les graphiques, la vérification, la ligne à ajouter dans le AGENTS.md propre à l’application afin que les agents suivants respectent la convention, la commande de mise à jour, le tableau de dépannage et la liste de référence mentionnée plus haut.

Audit de contraste (résumé, tous les thèmes)

tools/check_contrast.py s’exécute en CI à chaque envoi. Le rapport complet pèse 124 Ko (une section par thème plus un résumé) et se trouve à docs/contrast-report.md ; voici le résumé :

Thème Catégorie Profil Vérifications Échecs
purple principal standard 147 0
midnight-gold principal standard 147 0
glacier principal standard 147 0
forest principal standard 147 0
paper principal standard 147 0
daylight principal standard 147 0
electric-yellow optionnel standard 147 0
laserlloyd optionnel standard 147 0
laserlloyd-light optionnel standard 147 0
night-red optionnel nuit 171 0

Contrat exigé par chaque thème : texte principal 7:1, texte secondaire 6:1 (le rapport de contraste mentionne explicitement « la promesse de 6:1 du contrat » — docs/contrast-report.md indique ainsi chaque ligne text-secondary on surface-2) ; tout niveau de texte sur toute surface doit offrir un ratio de 4,5:1, les éléments désactivés 3:1, le texte sur fonds accentués ou d’état 4,5:1, le texte sur fond teinté d’état 4,5:1, le texte sur sélection 4,5:1, les bordures de sélection/non-sélection et les textes correspondants 3:1, les bordures renforcées, pistes de contrôle et anneaux de focus 3:1, les couleurs syntaxiques sur --syn-bg 4,5:1 (les commentaires 3,5:1), et les séries graphiques (--cat-1 à --cat-12) 3:1 sur --surface-0. Activation/désactivation par forme : un contrôle « activé » est rempli avec --selected ; un contrôle « désactivé » n’est qu’un contour en --unselected-border ; pour les commutateurs, l’état « on » ajoute une barre au bouton, l’état « off » un anneau. États désactivés : les éléments désactivés sont affichés en trait discontinu avec la teinte propre à l’état désactivé, même lorsqu’ils sont activés.

Frameworks

Conformément au schéma de docs/INTEGRATIONS.md : HTML brut · FastAPI, Flask, Starlette (modèles Jinja) · Django · Vite, Vue, Svelte, SvelteKit, Astro · Next.js (routeur d’applications) · NiceGUI (Quasar) · Tailwind CSS · Electron, Tauri, pywebview · Polices · Graphiques · Politique de sécurité du contenu. Pour chaque framework : placer ui-theme/ là où les fichiers statiques sont servis, insérer le bloc <head> dans l’ordre indiqué à AGENTS.md §3, et servir le dossier sans mise en cache (ou versionner les URLs) afin que toute mise à jour soit immédiatement visible. Deux exemples concrets figurent dans le dépôt : examples/static-html/ (une seule page) et examples/fastapi-jinja/ (FastAPI + Jinja, avec un app.py de 2 172 octets).

Impression, contraste et animations

Trois éléments que le runtime surveille et auxquels la feuille de style réagit, sans nécessiter de paramètre propre à chaque thème :

  • Impression — data-print-theme détermine ce qui sera imprimé (ui-theme.js:474-490) : lorsque le thème actif est sombre ou OLED, auto bascule vers le thème clair correspondant à la famille de thèmes (ou le premier thème clair activé, ou daylight) ; un slug permet d’imprimer ce thème ; none ne provoque aucun changement. Lorsque le thème actif est clair, la page s’imprime telle quelle. Le mode impression masque la barre latérale de navigation, les notifications, les menus, les panneaux et les infobulles.

  • prefers-contrast: more — dans chaque thème, l’épaisseur des contours passe au niveau maximal, et le texte tertiaire est rehaussé au niveau du texte secondaire.

  • prefers-reduced-motion — les boucles d’animation s’arrêtent et les animations se raccourcissent ; les variables --motion-* prennent alors la valeur 0.

Versions

À partir du dépôt tel qu’il est au moment de la rédaction de cet article (cloné le 05/10/2026) :

$ git log -1 --format='%h %ci'
56fb665 2026-10-05 21:46:52 +0900        # ThemeForge 1.0.0

$ cat ui-theme/VERSION
ThemeForge 1.0.0 3db64d9f574f

$ wc -c ui-theme/*.js ui-theme/*.css ui-theme/*.ts ui-theme/*.py 2>/dev/null
  23515 ui-theme.js
   5441 ui-components.js
   2841 ui-theme.d.ts
  16081 update.py
  13255 ui-theme-base.css
  51344 ui-components.css
  86389 ui-theme.css

$ node --check ui-theme.js ui-components.js
(node v24.18.0) — Tout est conforme, y compris dans adapters/quasar.js et adapters/tailwind-v3.preset.js

$ python -m unittest discover -s tests
32 tests exécutés en 1,212 s
OK (skipped=1)

$ python tools/check_contrast.py --fail-on any
…
## Résumé
| Thème | Ensemble | Profil | Vérifications | Échecs |
| purple | core | standard | 147 | 0 |
| midnight-gold | core | standard | 147 | 0 |
| glacier | core | standard | 147 | 0 |
| forest | core | standard | 147 | 0 |
| paper | core | standard | 147 | 0 |
| daylight | core | standard | 147 | 0 |
| electric-yellow | opt-in | standard | 147 | 0 |
| laserlloyd | opt-in | standard | 147 | 0 |
| laserlloyd-light | opt-in | standard | 147 | 0 |
| night-red | opt-in | night | 171 | 0 |

Cibles : les versions actuelles de Chrome, Edge, Firefox et Safari (2024 ou ultérieures). Cette couche utilise :has(), color-mix() ainsi que l’API popover ; les navigateurs plus anciens conservent les couleurs, mais certains états de composants et menus se dégradent.

Voir aussi : ChatForge : un assistant IA local utilisant le NPU pour la touche Copilot · StudioForge : un serveur LLM fonctionnant uniquement sur GPU · DisPatch : chat IA auto-hébergé · Mon propre stack d’agents IA locaux · Comment faire en sorte qu’un modèle IA adapte n’importe quel projet à votre système

Téléchargements

Gratuit pour un usage personnel. Si ça vous fait gagner un après-midi, le bouton café n'est pas loin.


← Plus de IA et LLM locaux