Créer un thème avec votre agent
Une référence pour un agent IA qui crée un thème d’aperçu MarsDawn. L’agent écrit un seul theme.json, le vérifie et le rend avec l’outil en ligne de commande marsdawn, puis vous remet un lien. Vous l’ajustez à l’œil sur la page Créer un thème et vous le soumettez. Les tableaux de champs ci-dessous sont lus dans le code source du kit, et une vérification les maintient identiques.
Écrivez un theme.json, lancez marsdawn theme validate theme.json --require-complete --json jusqu’à obtenir le code de sortie 0, rendez-le avec marsdawn theme preview en clair et en sombre, puis donnez un lien à la personne. Un thème n’est fait que de paramètres. Il ne contient jamais de CSS.
Ce qu’est un thème
- Des couleurs pour le clair et pour le sombre : une palette de base, et des couleurs de syntaxe et de diagramme facultatives. Chacune est de la forme
#RRGGBB. - Un style de police :
sans,serifourounded. - Un ensemble fermé d’options de style : des nombres dans des plages fixes et des choix dans des listes fixes. Une couleur dans une option de style est toujours un rôle de palette comme
accent, jamais une couleur littérale. - Des textes affichés : un nom et un résumé, et éventuellement un auteur et une licence.
Une clé absente des tableaux ci-dessous est une erreur, tout comme une clé écrite deux fois. Le fichier fait au plus 16 384 octets.
Vérifier et rendre
Lancez ces commandes dans le dossier qui contient theme.json. Elles demandent l’outil marsdawn : voir marsdawn pour les agents.
marsdawn theme validate theme.json --require-complete --json
marsdawn theme css theme.json --json
marsdawn theme preview theme.json --appearance light -o light.png
marsdawn theme preview theme.json --appearance dark -o dark.png
- Codes de sortie : 0 valide, 1 invalide avec des identifiants de règle, 2 fichier introuvable, 64 erreur d’usage.
previewajoute 4 quand le PNG existe déjà (passez--forceou choisissez un autre nom) et 5 quand le rendu échoue. - Avec
--json, un thème invalide énumère ses problèmes sousissues, chacun avec un identifiantrule, unpathet unmessage. Corrigez-les et relancez la commande. --require-completeest la vérification d’un thème destiné à être publié : elle exige aussi les couleurssyntaxetdiagramdans les deux palettes.cssaffiche le CSS que sert l’aperçu.previewrend un document d’exemple en PNG. Les deux valident d’abord : un thème invalide ne produit aucun rendu.- Regardez le PNG clair et le PNG sombre avant de remettre le thème.
Partir d’un thème intégré
Copiez l’un des quatre thèmes intégrés et modifiez-le. Chacun est un fichier complet et valide :
/assets/theme-sim/kit/themes/dawn.json: le thème par défaut, et l’exemple ci-dessous/assets/theme-sim/kit/themes/classic.json: une palette plus sobre, proche d’un document/assets/theme-sim/kit/themes/modern.json: une palette plus froide et plus contemporaine/assets/theme-sim/kit/themes/vivid.json: une palette plus vive et plus contrastée
Exemple : Dawn
Voici dawn.json, octet pour octet. Sa seule option de style est un fin filet de couleur d’accent pour hr.
{
"schemaVersion": 1,
"id": "dawn",
"version": "1.0.0",
"name": { "en": "Dawn" },
"summary": { "en": "Warm Martian sunrise" },
"fontDesign": "sans",
"scenarios": ["agent-review"],
"light": {
"background": "#FFFDFB", "surface": "#F6F0EC", "text": "#26211F", "muted": "#6F6660",
"border": "#EADFD8", "heading": "#26211F", "accent": "#C8471B", "link": "#B03C0C", "quote": "#D97A4A",
"syntax": { "keyword": "#B03C0C", "string": "#2F6F5E", "comment": "#746B66", "number": "#9A5B00", "function": "#5B3E8C", "type": "#1F6FB2" },
"diagram": { "node": "#FBE9E0", "nodeBorder": "#CA6C3C", "text": "#26211F", "line": "#8A6A5C", "secondary": "#E6F1EE", "tertiary": "#FFF6F1", "note": "#FFF1D6" }
},
"dark": {
"background": "#1C1A1F", "surface": "#262229", "text": "#EBE4DF", "muted": "#A39992",
"border": "#3A343A", "heading": "#F4EEEA", "accent": "#FF8A50", "link": "#FF9E6B", "quote": "#E08A5C",
"syntax": { "keyword": "#FF9E6B", "string": "#7FD1B9", "comment": "#938A84", "number": "#F2C572", "function": "#C7A6F5", "type": "#6CB6FF" },
"diagram": { "node": "#3A2A26", "nodeBorder": "#E08A5C", "text": "#EBE4DF", "line": "#B8A69C", "secondary": "#23332F", "tertiary": "#2B2427", "note": "#3D3322" }
},
"style": {
"hr": { "style": { "type": "line", "color": "accent", "thickness": 1 } }
}
}
Champs
Chaque objet ci-dessous est lu de la même façon. required signifie que la clé doit être présente, et une clé qui n’est pas listée est une erreur.
Types : string, integer, number, boolean, map (balise de langue vers texte), enum (l’une des valeurs listées), role (un rôle de palette) et object (le tableau vers lequel il renvoie). Un [] après un type signifie une liste.
theme.json
| Champ | Type | Présence | Valeurs et remarques |
|---|---|---|---|
schemaVersion | integer | required | Toujours 1. |
id | string | required | De 1 à 32 caractères : lettres minuscules et chiffres, en blocs reliés par des tirets simples, par exemple calm-green. |
version | string | required | MAJOR.MINOR.PATCH, par exemple 1.0.0. |
name | map | required | Balise de langue vers texte. en est obligatoire ; les autres clés sont des balises de langue comme zh-Hant. Chaque texte compte au plus 48 caractères, sans lien ni saut de ligne. |
summary | map | required | Même forme que name, au plus 120 caractères par texte. |
fontDesign | enum | required | sans, serif, rounded |
scenarios | enum[] | required | agent-review, technical-docs, formal-output, notes-sharing — Un ou deux, sans répétition. Ils fixent le contraste que le thème doit atteindre. |
author | object | optional | author |
license | string | optional | Un identifiant SPDX, par exemple Apache-2.0. Les thèmes soumis sont publiés sous Apache-2.0. |
light | object | required | light, dark |
dark | object | required | light, dark |
style | object | optional | style |
author
| Champ | Type | Présence | Valeurs et remarques |
|---|---|---|---|
name | string | required | Au plus 64 caractères, sans lien. |
github | string | optional | Un identifiant GitHub. Pour une soumission, indiquez celui de la personne qui soumet. |
light, dark
| Champ | Type | Présence | Valeurs et remarques |
|---|---|---|---|
background | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
surface | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
text | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
muted | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
border | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
heading | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
accent | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
link | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
quote | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
syntax | object | optional (requis pour publier, avec --require-complete) | syntax |
diagram | object | optional (requis pour publier, avec --require-complete) | diagram |
syntax
| Champ | Type | Présence | Valeurs et remarques |
|---|---|---|---|
keyword | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
string | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
comment | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
number | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
function | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
type | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
diagram
| Champ | Type | Présence | Valeurs et remarques |
|---|---|---|---|
node | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
nodeBorder | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
text | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
line | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
secondary | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
tertiary | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
note | string | required | # suivi de six chiffres hexadécimaux, par exemple #1C1C1C. |
style
| Champ | Type | Présence | Valeurs et remarques |
|---|---|---|---|
bodySize | number | optional | plage |
lineHeight | number | optional | plage |
headingWeight | number | optional | plage |
radius | number | optional | plage |
maxWidth | number | optional | plage |
h1 | object | optional | style.h1 |
h2 | object | optional | style.h2 |
blockquote | object | optional | style.blockquote |
hr | object | optional | style.hr |
table | object | optional | style.table |
listMarker | role | optional | un rôle de palette |
inlineCode | role | optional | un rôle de palette — Seulement text ou un rôle de syntaxe : keyword, string, comment, number, function ou type. |
link | object | optional | style.link |
syntax | object | optional | style.syntax |
style.h1
| Champ | Type | Présence | Valeurs et remarques |
|---|---|---|---|
size | number | optional | plage |
letterSpacing | number | optional | plage |
align | enum | optional | left, center |
decoration | object | optional | type |
style.h2
| Champ | Type | Présence | Valeurs et remarques |
|---|---|---|---|
letterSpacing | number | optional | plage |
decoration | object | optional | type |
italic | boolean | optional | true, false |
style.blockquote
| Champ | Type | Présence | Valeurs et remarques |
|---|---|---|---|
style | object | optional | type |
italic | boolean | optional | true, false |
style.hr
| Champ | Type | Présence | Valeurs et remarques |
|---|---|---|---|
style | object | optional | type |
style.table
| Champ | Type | Présence | Valeurs et remarques |
|---|---|---|---|
header | object | optional | type |
verticalRules | boolean | optional | true, false |
rounded | boolean | optional | true, false |
style.link
| Champ | Type | Présence | Valeurs et remarques |
|---|---|---|---|
underline | boolean | optional | true, false |
style.syntax
| Champ | Type | Présence | Valeurs et remarques |
|---|---|---|---|
boldKeywords | boolean | optional | true, false |
Options à type
Ces options de style sont des objets avec un type. Chaque type accepte les champs listés pour lui, et aucun autre.
| Option | type | Champ | Présence | Type |
|---|---|---|---|---|
style.h1.decoration | rule | — | — | — |
style.h1.decoration | none | — | — | — |
style.h1.decoration | shortRule | color | required | role |
style.h1.decoration | gradientBar | from | required | role |
style.h1.decoration | gradientBar | to | required | role |
style.h2.decoration | rule | — | — | — |
style.h2.decoration | none | — | — | — |
style.h2.decoration | dot | color | required | role |
style.blockquote.style | bar | width | optional | number plage |
style.blockquote.style | panel | — | — | — |
style.hr.style | line | color | optional | role |
style.hr.style | line | thickness | optional | number plage |
style.hr.style | shortCentered | color | required | role |
style.hr.style | gradient | colors | required | role[] Deux ou trois rôles. |
style.table.header | surface | — | — | — |
style.table.header | accentRule | color | required | role |
style.table.header | filled | background | required | role |
style.table.header | filled | text | required | role |
style.table.header | filled | border | optional | role |
Rôles de palette
Un rôle de palette est l’un de ces noms :
background, surface, text, muted, border, heading, accent, link, quote, keyword, string, comment, number, function, type
Nombres
Un nombre est arrondi au multiple le plus proche de son pas, puis doit se trouver entre le min et le max. Sinon la règle est number.range.
| Champ | Min | Max | Pas |
|---|---|---|---|
style.bodySize | 14 | 18 | 1 |
style.lineHeight | 1.4 | 1.9 | 0.05 |
style.headingWeight | 400 | 900 | 50 |
style.radius | 0 | 16 | 1 |
style.maxWidth | 600 | 1000 | 1 |
style.h1.size | 1.8 | 2.4 | 0.1 |
style.h1.letterSpacing | -0.03 | 0.03 | 0.005 |
style.h2.letterSpacing | -0.03 | 0.03 | 0.005 |
style.blockquote.style.width | 2 | 4 | 1 |
style.hr.style.thickness | 1 | 4 | 1 |
Ce qui est vérifié d’autre
- Contraste. Chaque paire de couleurs que dessine l’aperçu, comme
textsurbackground, doit atteindre 4,5:1 pour le texte et 3:1 pour les traits et le reste du non-texte. Les scénarios que vous indiquez portent certaines couleurs à 4,5:1. Le message nomme la paire, son rapport et celui qu’il faut. - Textes. Un nom, un résumé ou un nom d’auteur vide, trop long, ou contenant un lien, un caractère de contrôle ou un caractère de format invisible ou bidirectionnel est refusé.
- Identifiants de règle. Chaque problème en porte un, par exemple
contrast.pair,color.hex,number.range,id.pattern,schema.unknownKeyoupalette.incomplete. Corrigez le fichier d’après ce que disent l’identifiant et lepath.
Le remettre sous forme de lien
La page Créer un thème ouvre un thème à partir d’un lien, pour que la personne puisse l’ajuster à l’œil. Le lien est l’adresse de la page, puis #theme=, puis les octets du fichier en base64url sans remplissage. Le fichier fait au plus 16 384 octets. Cette seule ligne construit le lien sous zsh et sous bash, sur macOS et sur Linux :
printf 'https://marsdawn.southern-light.dev/fr/themes/new/#theme=%s\n' "$(base64 < theme.json | tr -d '\n=' | tr '+/' '-_')"
Le thème voyage après un #, que le navigateur n’envoie pas au site, et le site ne le transmet nulle part. Le lien reste toutefois dans l’historique de votre shell et du navigateur, et toute personne à qui vous le collez peut lire le thème.
Le soumettre
L’agent prépare le fichier et le lien. La personne soumet. Les deux voies demandent le Developer Certificate of Origin et la publication sous Apache-2.0, et c’est la personne qui fait cette attestation : l’agent ne coche pas la case et ne signe pas à sa place.
- Issue. La personne ouvre le lien et appuie sur Submit dans la page « Créer un thème », ou ouvre le formulaire d’issue et colle le JSON dans Theme. Un workflow vérifie le thème et répond.
- Pull request. Ne modifiez que
themes/<id>/theme.json, mettez dansauthor.githubl’identifiant de l’auteur de la pull request et signez chaque commit avecgit commit -s. Les règles sont dans CONTRIBUTING.md.
Le nom d’auteur, le nom, le résumé et l’identifiant GitHub d’un thème soumis deviennent publics de façon permanente : mettez dans author.name un nom que la personne accepte de publier.
Thèmes publiés
Pour voir à quoi ressemblent les thèmes publiés, parcourez la galerie de thèmes.