Le design system de la classe — le socle commun à toutes les classes (police de l'élève, contrastes, papier, mécanique des périodes) et le thème propre à la classe, qui fait de son site un MINI-SITE à son image (gabarits de l'en-tête et du menu, de l'accueil, des documents et des pages de période ; images libres créditées ; mouvement ; couleurs, polices, habillage, couverture), contrôlé par scripts/verifier-theme.py et verifier-gabarits.js. À utiliser dès qu'on touche à l'apparence de quoi que ce soit : site/charte/ (socle.css, composants.css, themes/ : theme.yml, theme.css, habillage.css, gabarits.js), site/gabarits.js, site/modele.js, site/app.css, site/index.html, l'accueil, fiches.css, imagier.css, cartes-corpus.css, impression.css, la couverture des cahiers, une nouvelle page ou un nouveau composant, une icône, une couleur, une police — et pour créer ou faire évoluer le style d'une classe avec son enseignant. Se déclenche aussi sans nom de fichier : « c'est moche », « je voudrais un style à nous », « rends l'accueil plus gai », « la couleur de l'Asie ne va pas », « je voudrais un mode sombre », « ajoute un bouton pour… », « le titre est trop gros sur téléphone », « on peut avoir une vraie couverture ? », « je voudrais que le site ressemble à notre projet », « fais-nous un vrai site », « construis le thème de la maquette retenue ». Ne concerne pas le choix d'une image de fiche (fiches-illustrations) ni d'une photographie de l'imagier (imagier-photos).
Install
npx skillscat add encrine-ai/moteur/charte-graphique Install via the SkillsCat registry.
Le design system de la classe
Chaque classe a son propre style, fait sur mesure avec son enseignant,
pour que la galerie « Les classes » montre des classes vraiment différentes
(décision du propriétaire, 18 octobre 2026). Mais toutes les classes
partagent ce qui sert l'enfant et le papier. D'où trois couches :
| Couche | Où | Qui la change |
|---|---|---|
| le socle | site/charte/socle.css (+ Andika dans site/charte/polices/) |
le moteur seul ; aucun thème ne le défait |
| les composants du moteur | site/app.css, site/fiches/fiches.css, site/imagier/imagier.css, site/cartes-corpus/cartes-corpus.css, site/charte/composants.css (la couverture) — tous dans @layer moteur ; site/impression.css et site/marque/ (les documents de l'enseignant) sont hors thème, au style de la marque |
le moteur ; ils n'emploient que des jetons |
| le thème de la classe | site/charte/themes/<thème>/ : theme.yml, theme.css, habillage.css, gabarits.js, polices/, motifs/, images/ |
la classe, avec son enseignant |
python3 scripts/classe.py generer assemble socle.css, composants.css,
puis theme.css et habillage.css du thème que nomme theme: dansclasse.yml, dans site/charte/charte.css, le seul fichier que chargent
les pages (jamais à éditer à la main ; classe.py verifier le refuse périmé).
Une page ne nomme jamais le dossier d'un thème.
Pourquoi une couche CSS. Les feuilles du moteur sont dans @layer moteur ;
le thème, hors couche, l'emporte donc sur elles sans surenchère de
sélecteurs, et un style écrit dans une fiche (une fiche resserrée à la
main) l'emporte sur les deux. Le socle est hors couche lui aussi : c'est le
contrôle qui empêche le thème d'y toucher.
Deux supports, deux règles. À l'écran, le thème fait un mini-site :
ses gabarits dessinent l'en-tête et le menu, l'accueil, la page de document
et la page de chaque période, avec ses images et son mouvement — « comme un
site différent, à son image » (décision du propriétaire, 18 octobre 2026).
Sur le papier du matériel des élèves (fiches, imagier, cartes-corpus), le thème
habille, il ne restructure pas : couleurs, polices de l'adulte,
ornements, couverture, jamais la géométrie. C'est ce qui permet à une classe
de recevoir les nouvelles versions du moteur (skill synchroniser-moteur)
sans perdre son style : le moteur garde ses accroches et le contrat des
gabarits ; tout le reste lui est interne et peut changer.
La marque sur le papier — les documents de l'enseignant
Décision du propriétaire : les documents de l'enseignant (projet annuel,
programmation, progressions et leurs extraits, mode d'emploi, livret,
évaluations — imprimer.html, donc tous les pdf/<doc>.pdf) sont au
style de la marque Encrine (https://encrine.ai/design/), uniforme pour
toutes les classes, indépendant du thème : imprimer.html ne charge pascharte.css, aucun thème ne les habille (verifier-theme.py refuse les
anciennes racines bandeau-imprime, document-imprime).
| Fichier | Rôle |
|---|---|
site/marque/marque.css |
les polices (Unbounded, Figtree, Marelle, OFL, dans site/marque/polices/ avec leurs LICENCE-*.txt, copiées du site d'Encrine — jamais appelées sur le réseau) et les jetons --m-* (craie, ardoise, cases) ; la couleur d'une période vient de sa famille (periodes[].couleur) rendue dans la case d'Encrine ([data-couleur]) |
site/marque/logo-encrine.svg |
le logo, discret, au pied de la première page |
site/impression.css |
la mise en page : première page, titres, tableaux, en-tête et pied |
site/imprimer.html |
construit la première page, l'en-tête courant, les cases des périodes, le paysage |
Ce qu'on y trouve, et pourquoi :
- une première page pour un document complet (les évaluations de période
en sont :eval-pN) (.premiere, hauteur fixe 258 mm, 171 en paysage) :
le groupe du document en Marelle (la seule cursive), le titre en
Unbounded, le titre du Markdown en sous-titre (leh1quitte le corps),
le projet, « La classe de » sienseignant.signature, puis
niveau, année, zone, et les dates — de la période (extrait, évaluation de
période) ou des cinq périodes. Rien qui imite une couverture d'éditeur ; - un extrait de période n'a PAS de première page (décision du
propriétaire : c'est une feuille d'affichage) : un bandeau compact en
tête de sa page 1 (.bandeau-extrait) — le document, la période avec sa
case et son nom, ses dates (et la précision du titre de période, « 3
unités »), la classe ; leh2de la période s'efface. En-tête et pied
courants dès la page 1 ; - les polices demandées dès la première mise en page (
.precharge
d'imprimer.html) : chargées après le Markdown, elles arrivaient parfois
après l'impression, et Chromium imprimait une page sans aucun texte
(font-display: block) — huit extraits sur trente-cinq lors d'un essai ; - en-tête et pied en boîtes de marge
@page(Chromium ≥ 131) : à
gauche la classe, à droite le document ; en bas « Conçu avec Encrine ·
encrine.ai » et « page X / Y ».imprimer.htmlécrit l'en-tête dans<style id="pages">, avec le:firstqui les retire de la première page
d'un document complet — écrit après l'en-tête, sinon la règle injectée
l'emporte et la première page porte l'en-tête ; - tableaux à filets fins,
theadrépété à chaque page,trinsécable,
première colonne en demi-gras ; une colonne de période (« P1 — Europe »)
reçoit sa case et un filet de sa couleur. Un tableau d'au moins six
colonnes de texte dense (≥ 30 signes par case : la programmation) met
tout le document en paysage ; - pas d'émoji (drapeaux, globes) : retirés au rendu ; la période se
repère par sa case de couleur, toujours avec son nom ; - peu d'encre : aucun aplat, aucun fond de ligne ; tout se lit en noir et
blanc. L'italique d'un titre passe en romain Figtree (Unbounded n'a pas
d'italique ; un faux penché fait amateur).
Essayé et écarté : commencer chaque période d'une progression sur une
nouvelle page (+1 à +4 pages par progression, pour un trou d'un tiers de
page à un seul endroit).
Le matériel des élèves garde sa charte, et ne reçoit de la marque qu'une
ligne : « Conçu avec Encrine · encrine.ai », 6,8 pt, Figtree, #4a5566, dans
la marge basse (@page { @bottom-center } du socle, à 8 mm du bord) —
elle ne prend rien au contenu, donc aucune fiche ne déborde et le nombre de
pages ne bouge pas. Piège : une boîte de marge ne fait pas charger sa
police, et sans elle Chromium n'y imprime rien ; le socle porte donc unhtml::before invisible à la même police — hors @media print, où elle
arrive trop tard. verifier-pagination.py cherche la mention sur chaque page.
Le socle — non négociable
- La police de l'élève. Andika (
--police-enfant) pour tout mot qu'un
enfant lit : cartes, étiquettes, étiquettes de tri, mots sous les images,
lettres, tableaux, défis, le nom du milieu sur la couverture. La règle et
sa liste de sélecteurs sont danssocle.css. Le thème ne touche ni à la
police, ni au corps, ni à l'espacement, ni à la casse de ces mots, et leur
couleur reste l'encre ou la période. La consigne, l'en-tête et le pied
d'une fiche s'adressent à l'adulte : police du texte. - La lisibilité. Tout texte tient 4,5:1 sur le fond que nomme son usage,
3:1 pour un bord de contrôle, dans les trois blocs (clair, sombre,
impression). Le bloc d'impression est celui de la photocopie en noir et
blanc : le rapport de luminance est tout ce qui y reste. La mention de
rangement des cartes a un corps et une encre minimaux
(--repere-taille: 6.5pt,--repere-encre) : à 5,5 pt en gris pâle,
elle ne se lisait plus. - Le papier. A4, une page par fiche et par planche (les
@pagesont du
moteur, le thème n'en écrit pas), aucun saut de page dans un thème. Peu
d'encre sur ce que la classe photocopie : les fonds du papier restent
clairs (luminance ≥ 0,70), un aplat sombre ne va qu'à l'écran et sur la
couverture. Sur le papier, l'habillage ne change que l'apparence, jamais
la géométrie ; un ornement y est toujours en position absolue. - La mécanique des périodes.
data-periode="N"pose--periode,--periode-trait,--periode-paleà partir des--pNdu thème. Les
espacements (--esp-*) sont du socle aussi.
Le contrat du thème — ce qu'il habille
Les jetons (theme.css)
Trois blocs, chacun complet (un jeton oublié retombe sur rien) : :root
(clair), le sombre (@media (prefers-color-scheme: dark) sur:root:not([data-theme="light"]), et :root[data-theme="dark"]), et@media print (le papier reste clair).
| Jetons | Rôle |
|---|---|
--papier, --feuille, --feuille-creuse, --trait, --trait-fort |
fonds et traits |
--encre, --encre-douce |
texte, légendes |
--sapin, --sapin-pale, --sur-sapin |
la couleur de la maison (le nom est historique) : titres, action principale, état actif |
--bouton-dor, --sur-bouton-dor |
la mise en avant (aujourd'hui, le défi) — jamais de texte posé dessus sur fond clair |
--coquelicot, --anneau |
l'alerte, l'anneau de focus |
--p1…--p5 avec -trait et -pale, --sur-periode |
une couleur par période |
--police-titre, --police-texte (obligatoires), --police-etiquette (facultative : numéros, tampons, étiquettes ; par défaut celle des titres) |
les polices de l'adulte, auto-hébergées |
--rayon-s, --rayon-m, --rayon-l, --rayon-pilule |
les arrondis — du thème, plus du socle |
--ombre-flotte |
ce qui flotte |
--consigne-fond/-bord/-encre/-accent, --sous-objectif-fond/-bord/-encre, --defi-fond/-bord/-accent, --fiche-cadre, --trait-coupe, --entete-planche-encre |
accroches du papier : le moteur les lit avec une valeur par défaut tirée de la charte (la consigne sur --feuille-creuse, le sous-objectif à la couleur de la période, le défi bordé de --bouton-dor) |
--t-… |
les variables propres au thème (--t-kraft) |
Les couleurs de période gardent une famille que l'enseignant peut dire
(« le filet bleu ») : elle est notée dans periodes[].couleur declasse.yml, et les modes d'emploi imprimés la citent. On peut foncer ou
nuancer une teinte, pas en changer la famille.
Les composants (habillage.css)
Chaque règle part d'une racine que le moteur garantit et ne nomme que
les parties listées. scripts/verifier-theme.py tient le même registre
(COMPOSANTS) : une racine ou une partie qui n'y est pas est refusée.
Les six premières lignes (bandeau, menu, barre, accueil, bloc, frise) et
les cartes du matériel et des documents sont les composants des gabarits
par défaut (site/gabarits.js) : un thème sans gabarits les habille ici ;
un thème qui a ses gabarits dessine les siens (« Le mini-site », plus bas).
| Composant | Racine | Parties | Ornements | Support |
|---|---|---|---|---|
| Bandeau | [data-composant="bandeau"] |
.marque, .marque-frise (.m1….m5), .marque-texte, .marque-titre, .marque-sous, .menu-toggle, .ic |
bandeau |
écran |
| Menu | [data-composant="menu"] |
.menu-groupe, .groupe, .actif, .pastille, .ic |
écran | |
| Barre d'outils | [data-composant="barre"] |
.fil, .boutons, .btn, .btn-principal |
écran | |
| Accueil (la page) | [data-composant="accueil"] |
écran | ||
| En-tête de l'accueil | [data-composant="accueil-tete"] |
.surtitre, .chapo, h1 |
accueil |
écran |
| Bloc de l'accueil | [data-composant="bloc"] (+ `[data-bloc="annee |
materiel | documents"]`) | .bloc-tete, .zone-badge, .note, .vacances, .reprise, .materiels, .frise-total |
| Frise des périodes | [data-composant="frise"] |
.frise-periode, .en-cours, .frise-bande, .frise-num, .frise-milieu, .frise-dates, .frise-sem, .frise-ici |
frise (dans chaque bande) |
écran |
| Carte d'un cahier à imprimer | [data-composant="materiel"] |
.materiel-tete, .materiel-num, .materiel-liste, .en-cours |
materiel |
écran |
| Cartes des documents | [data-composant="documents"] |
.docs-groupe, .docs |
écran | |
| Document rendu | [data-composant="document"] |
.contenu, .zone-badge |
écran | |
| Invitation à installer l'appli | [data-composant="invitation"] |
.invitation-icone, .invitation-texte, .invitation-fermer, .btn, .btn-principal, .ic |
écran | |
| Pied, pastille, bouton | [data-composant="pied"], .pastille, .btn |
.btn-principal |
écran | |
| Couverture d'un cahier | [data-composant="couverture"] (+ data-periode, data-cle) |
.couverture-tete, -classe, -annee, -centre, -cahier, -titre (mot de l'enfant), -sous, -pied, -periode, -num, -projet |
couverture-fond, couverture-embleme, couverture-tampon |
papier |
| Page de garde | [data-composant="garde"] |
.sous-titre, .encadre, .titre-encadre, .trois-temps, .temps, .usages, .quand, .listes, .savant, .pied-garde, .note |
garde |
papier |
| En-tête de planche | [data-composant="entete-planche"] |
.milieu |
papier | |
| Carte d'imagier | [data-composant="carte-imagier"] |
.photo, .mot, .vide, .repere |
::before, ::after |
papier |
| Carte-corpus | [data-composant="carte-corpus"] |
.visuel, .photo, .dessin, .mot, .vide, .repere |
::before, ::after |
papier |
| Étiquette-mot, étiquette de tri | [data-composant="etiquette"], [data-composant="etiquette-tri"] |
.mot, .repere ; .mot-tri |
::before, ::after |
papier |
| Crédits | [data-composant="credits"] |
papier | ||
| Fiche élève (écrite à la main) | .fiche |
le cadre seulement : .entete, .idext, .champ, .trait, .cartouche, .ref, .dom, .titre, .niveau, .n1, .n2, .sous-objectif, .consigne, .exo, .num, .enonce, .defi, .etoile, .pied-fiche, .codage, .paysage — jamais le matériel de l'exercice |
::before, ::after |
papier |
Les étiquettes de période sont la .pastille (écran), le .cartouche
de la fiche, l'en-tête de planche et le .repere des cartes ; les motifs
décoratifs sont les fonds (body[data-support="ecran"] pour le fond de
l'écran, background-image), les filets et les ornements.
Attributs de contexte permis partout : data-periode (un motif par
continent), data-support="ecran|papier" (sur <body>), data-cahier
(imagier, cartes-corpus), data-bloc, data-cle (la clé du milieu, sur
la couverture), data-theme.
Les ornements sont des éléments vides (<span class="orne" data-orne="…">) que le moteur pose et que le socle cache (display: none).
Un thème les montre et les remplit (display: block; position: absolute;
un motif en mask ou background). Leur hôte est déjà positionné et isolé
(position: relative; isolation: isolate), si bien qu'un z-index: -1 les
passe sous le texte. Les ::before/::after des parties servent
d'ornements supplémentaires.
Ce que vérifie scripts/verifier-theme.py (code 1 s'il reste une anomalie)
Lancé par python3 scripts/classe.py verifier (donc par le déploiement), ou
seul : python3 scripts/verifier-theme.py [thème…].
les fichiers :
theme.ymldéclare chaque police et chaque motif, avec
sa licence (OFL-1.1, CC0-1.0, PDM, CC-BY, CC-BY-SA) et son auteur ; chaque
fichier déclaré existe et sert, chaque fichier du dossier est déclaré,
chaqueurl()pointe sur un fichier déclaré, aucune ne sort sur le réseau
(les PDF se fabriquent sans lui) ; un motif SVG ne contient ni script, ni
image, ni texte, ni lien externe ;les jetons : complets dans les trois blocs ;
--police-titre,--police-texte,--police-etiquettecommencent par une police
auto-hébergée (un@font-facedu thème) ;le contraste : les paires d'usage (encre sur papier et sur feuille,
période sur sa teinte pâle, texte sur la couleur de la maison, accroches
de la fiche…, plus lescontrastes:detheme.yml) dans les trois
blocs ; au bloc d'impression, des fonds de papier clairs ;le socle : ni
--police-enfant, ni--esp-*, ni--periode*, ni--repere-*redéfinis ; aucune règle de police, de corps, d'espacement ou
de casse sur un mot de l'enfant ; ni@page, ni@import, ni saut de
page, ni!important; unefont-familypasse toujours par un jeton ;les composants : racine connue, parties documentées, attributs de
contexte ; sur le papier, des propriétés d'apparence seulement (couleurs,
fonds, styles et couleurs de bordure, arrondis, polices de l'adulte,
graisse, casse, soulignement), un ornement en position absolue, pas
d'aplat sombre hors de la couverture — dont l'intérieur, à hauteur fixe,
se compose librement ; à l'écran, tout, sauf un corps sous 12 px.l'icône de l'appli (
icone:, ci-dessous « L'icône de l'appli ») :
tracé sûr et crédité, image déclarée, recadrage dans ses bornes ;le mini-site : les images de
theme.yml(licence, auteur, source,
fichier, usage) ;gabarits.jssans logique du moteur, et essayé parscripts/verifier-gabarits.js(Node) sur chaque page de la vraie classe —
chaque gabarit rend du texte sans erreur, l'en-tête a son<nav>et son
menu de téléphone, chaquearia-controlsnomme un élément, chaque
document montre son texte et ses PDF, chaque période ses cahiers et ses
documents, chaque image a unalt, chaque bouton untype, le pied la
signature, et chaque entrée du menu a un lien ; sansgabarits.js, ce
sont les gabarits par défaut qu'il essaie ; l'habillage d'écran dans@media screen(ci-dessous) ; toute animation sousprefers-reduced-motion: no-preference.
Il ne dit pas qu'un style est beau ni que la pagination tient : cela se
regarde, aux captures et au PDF (skill imprimer-pdf).
Le mini-site : les gabarits du thème
Le moteur calcule, le thème dessine. site/index.html n'a plus que
trois emplacements — #entete, #contenu (<main>), #pied — et le lien
d'évitement ; à chaque page, site/app.js les fait remplir par les
gabarits, puis donne vie au menu. Il n'y a plus de bandeau (nom de la
classe, année, logo, burger) : le menu est dans l'en-tête, et le pied
porte la signature « Conçu avec Encrine », liée à https://encrine.ai.
| Fichier | Rôle |
|---|---|
site/modele.js |
GS.modele() : le modèle que reçoivent les gabarits (ci-dessous) |
site/gabarits.js |
les gabarits par défaut, sobres ; GS.theme({…}), que le thème appelle |
themes/<thème>/gabarits.js |
les gabarits du thème : tout ou partie des fonctions ; classe.py generer le copie dans site/charte/gabarits.js (fabriqué, chargé après ceux du moteur) |
site/app.js |
la logique : routes, lecture et rendu du Markdown, extraits par période, menu, focus, crédits — un thème n'y touche pas |
scripts/verifier-gabarits.js |
essaie les gabarits sur la vraie classe, avec Node (lancé par verifier-theme.py) |
L'API des gabarits
Un gabarit est une fonction (m, page) → HTML (une chaîne), sans cadriciel.
- Attendus :
entete,accueil,document,periode,pied;
facultatifs :introuvable, etmonter(racine, m, page), appelé après
chaque rendu (le mouvement, une interaction de pure forme). Le thème ne
fournit que ce qu'il change :GS.theme({ accueil: …, periode: … }); le
reste vient des gabarits par défaut, qu'il peut aussi appeler
(GS.gabarits.defaut.boutons(m, page),.extraits(m, page)). page:{type: 'accueil'};{type: 'document', doc, periode, titre, corps, html, sections}—htmlest le Markdown rendu,corpsle
même sans son titre,sectionslesh2(id,titre,periode), les
badges de dates de la zone déjà posés ;{type: 'periode', periode};{type: 'credits', …}et{type: 'mentions', …}(les mentions légales
fabriquées par le moteur), tous deux rendus pardocument— unmonter
qui traite les crédits comme un document traite aussimentions;{type: 'introuvable'}.m, le modèle :m.classe(nom, projet, niveau, annee, accroche,
zone, periodes_nom, origine, enseignant : signature, mot) ;m.periodes[](n, cle, milieu, icone, romain, lien#/periode/<cle>,
debut, fin, sem,dates.court|long|badge, statutpassee|en-cours|a-venir,
prochaine, cahiers avechrefetnomde leur PDF, documents de
la période, extraits des progressions, projet, embleme,
imagier{faune, flore}, corpus, theme — les données propres
au thème, prete) ;m.ici(statutperiode|vacances|avant|apres,
periode, vacances, prochaine, titre « Nous y sommes », texte) ;m.vacances[](nom, libelle, dates, reprise, enCours) ;m.ponts,m.annee(semaines, texte) ;m.menu[](groupes et entrées, avec le
groupe des périodes) ;m.documents,m.groupes(chaque document avecpdfetextraits) ;m.sortes,m.materielNote;m.projet;m.images,m.image(fichier)(chemin, crédit) ;m.signature;m.mentions(texte,lien,source, toujours là :encrinepour une
classe servie par Encrine — l'exemple ou une copie relue de la galerie —,
lien vers https://encrine.ai/mentions-legales/ ;classepour les pages
de la classe,mentions_legales; sinonpage,#/mentions-legales) ;m.pied(conformite, calendrier, credits) ;m.mouvement(faux siprefers-reduced-motion) ;m.outils(esc, texte, icone, pastille,
romain, nombre, jourLong, jourCourt). Un gabarit échappe tout texte
(esc, outextequi ne permet que*italique*et**gras**).- Les accroches du menu, que
app.jsanime :[data-sous-menu]+aria-controls(un sous-menu,hidden; un seul ouvert ; Échap, un clic
ailleurs ou le focus qui part le ferment) ;[data-menu-ouvrir]+aria-controlsvers[data-menu-panneau](le menu du téléphone, un
dialoguerole="dialog" aria-modal="true": le focus y entre et y reste,
Échap le ferme et rend le focus au bouton) ;[data-menu-fermer]. Le
moteur posearia-current="page"sur chaque lien de la page affichée etdata-actifsur le bouton du sous-menu qui la contient. Une ancrehref="#id"(sommaire, renvoi) défile sans changer de page. - Le moteur garantit : le lien d'évitement, le focus sur
<main>à
chaque page, le titre de l'onglet, la signature « Conçu avec Encrine »,
le lien des crédits (#/credits), le crédit de la classe d'origine
(CC BY), le lien « Mentions légales » (m.mentions: celles d'Encrine
pour une classe qu'elle sert, sinon la page que le moteur fabrique depuisclasse.yml, skill site-et-calendrier, « Les mentions légales ») — un
pied qui les oublie les reçoit sous leur forme sobre, juste après le lien
des crédits —, et
l'invitation à installer l'appli (appli.js, composantinvitation). - Interdit à un gabarit (refusé par
verifier-theme.py) : lire
(fetch,import), stocker (localStorage…), changer la route, écouter
le clavier, écrire<script>ouon…=, nommer une adresse extérieure.
Animer (requestAnimationFrame,setInterval,.animate) seulement en
lisantm.mouvement.
Les gabarits par défaut — ceux du thème neutre demo — font un site
sobre : en-tête avec le nom du projet et un sous-menu par groupe
(ordinateur), un bouton « Menu » qui ouvre le même menu en plein écran
(téléphone) ; l'accueil (projet, signature et mot de l'enseignant, frise de
l'année, vacances avec « Nous y sommes », cahiers à imprimer, documents) ;
le document (PDF, cahiers de la période, extraits, texte) ; la période (ce
qu'on y fait, fil rouge, cahiers, documents, projet, imagier, mots des
corpus) ; le pied (signature de la classe, conformité, crédits, « Conçu
avec Encrine »).
La page de période
#/periode/<clé> existe pour chaque période, prête ou non : dates de la
zone, statut, ses cahiers et leurs PDF, ses documents (l'évaluation,
l'extrait de chaque progression), et les données du projet que porteclasse/projet.yml (contenu: projet: dans classe.yml) : resume (ce
qu'on y fait), fil_rouge ou mascotte, albums, documentaires,textes, oeuvres, musique, sorties, spectacle, embleme (une image
déclarée, ou {imagier: <slug>}), et theme: — les données propres au
thème (pour un atlas : la position du continent sur la carte, ses repères).
L'imagier (espèces, photographie, crédit) et les mots des corpus viennent
des manifestes de la classe. classe.py verifier contrôle la forme du
fichier ; on n'y met que ce que le projet annuel dit déjà — une période
en esquisse a une page en esquisse.
Les images du thème
theme.yml, section images: — une entrée par fichier de images/ :
images:
- fichier: images/carte-du-monde.jpg
titre: Mappemonde à l'usage du roi
auteur: Guillaume Delisle
date: vers 1750
institution: Rijksmuseum
source: https://id.rijksmuseum.nl/200450285
licence: PDM # CC0-1.0, PDM, CC-BY-x.0, CC-BY-SA-x.0 — jamais NC ni ND
recadrage: cartouche allégorique effacé, recadré sur le traitverifier-theme.py refuse une licence hors de ces quatre familles, un
auteur ou une source qui manque, Wikimedia, un fichier déclaré absent, un
fichier non déclaré, une image dont aucune feuille ni aucun gabarit ne se
sert. Les images de contenu (une œuvre étudiée, la gravure de la
mascotte) vont dans classe/projet.yml (images:, fichiers soussite/projet/), avec les mêmes champs. Les crédits s'affichent tout
seuls : la page #/credits les liste (thème, projet, photographies de
l'imagier, polices), et le pied y renvoie.
Sources : Openverse en énumérant license=cc0,pdm,by,by-sa (jamais le
filtre commercial, qui laisse passer ND) ; Rijksmuseum
(data.rijksmuseum.nl/search/collection, puis l'objet Linked Art → shows
→ digitally_shown_by → access_point, une adresse IIIF micr.io :/full/1600,/0/default.jpg ; un User-Agent de navigateur ou curl) ;
The Met Open Access (collectionapi.metmuseum.org/public/collection/v1.1/search,isPublicDomain) ; Biodiversity Heritage Library. Jamais Wikimedia.
À regarder à l'œil, toujours : les cartes et gravures anciennes portent
des allégories (les continents en figures dénudées, des putti, l'enlèvement
d'Europe). Le site est pour des enfants de cinq ans : aucune figure
dénudée ni violente. Effacer le cartouche (papier nu, de la couleur du
papier voisin) et le dire dans recadrage, ou choisir une autre image —
la carte de Blaeu et l'Europe de Schenk, retenues en maquette pour l'atlas
de la démo, ont été écartées ainsi. Et aucune illustration de contenu
dessinée : une image vient d'une source libre, ou n'est pas.
L'icône de l'appli (icone: de theme.yml)
L'icône de l'écran d'accueil fait partie du design system de la
classe : l'enseignant installe le site comme une appli, et c'est l'image
qu'il voit tous les jours. Le thème la dessine ; le moteur
(scripts/icone_du_theme.py, appelé par appli.py dans classe.py generer) en tire toutes les tailles : 192 et 512 (coins arrondis),
maskable 512 (Android), apple-touch 180 (le carré plein, iOS arrondit
lui-même), favicon 32, favicon.ico (16, 32, 48) et icones/appli.svg.
Sans icone:, l'icône reste celle du moteur — les bandes des périodes et
l'initiale —, un repli : jugée « pas très jolie » sur l'atlas de la
démonstration, elle ne doit pas rester l'icône d'une classe qui a son thème.
Deux manières, combinables :
icone: # un tracé du thème
svg: icone/rose.svg # viewBox carré, pensé à 512 px
licence: CC0-1.0
auteur: tracé pour le thème
fond: --feuille # couleur ou jeton clair du thème (défaut --feuille)
marge_maskable: 0.1 # 0 à 0.25 : le motif réduit dans la zone sûre d'Android
petite: icone/rose-32.svg # facultatif : une version simplifiée pour ≤ 48 px
icone: # une image libre déjà déclarée dans `images:`
image: images/carte-monde-delisle.jpg
recadrage: {x: 1200, y: 290, cote: 680} # un carré, en pixels de l'image
retouche: {saturation: 2.4, contraste: 1.3} # facultatif (0.5 à 3)
svg: icone/medaillon.svg # facultatif : le cadre, avec sa place vide
# <image id="image" x= y= width= height= clip-path=…/>
licence: CC0-1.0 # (celle du cadre)
auteur: tracé pour le thème- Le SVG est un tracé, contrôlé comme un motif : ni script, ni texte
(une lettre se trace en chemin, tirée de la police du thème avec
fontTools), ni lien ouurl()externe ; sa seule<image>est la place
videid="image"que le moteur remplit avec le recadrage. id="fond"sur le fond du carré (le parchemin, la mer) : dans la
version maskable, le fond couvre tout et le reste est réduit demarge_maskablede chaque bord. Android découpe l'icône en disque, en
goutte ou en carré, et ne garantit que le disque des 80 % centraux.- Remplir le carré : pas de marge blanche autour du motif, pas de coins
arrondis dessinés (le système les fait). Une lettre au plus. - Lisible à 60 px et à 32 px : un motif franc, contrasté, sans
filigrane qui disparaît. Une gravure entière devient une tache à 32 px :
la serrer (recadrage), la raviver (retouche), ou donner unepetite. - Aucune illustration de contenu dessinée : ornements géométriques
(rose des vents, sceau, cadre, tampon) tracés ici ; un animal ou un
personnage ne vient que d'une image libre déclarée dansimages:(la
mascotte d'une gravure doit alors y être déclarée, pas seulement dansclasse/projet.yml). - Le rendu demande Chromium (celui des PDF :
CHROME_BIN,google-chrome, ou celui de Playwright). Sans lui,genererle dit et
garde les icônes existantes ;verifierrelit l'empreinte inscrite dans
chaque PNG et signale une icône périmée. - Se choisit en situation : des propositions montrées sur une planche
d'écran d'accueil d'iPhone (clair et sombre), et à 180, 60 et 32 px ;
l'enseignant tranche (skill nouvelle-classe, étape 5). Pour fabriquer
les candidates, les passer par le moteur lui-même dans une copie de la
classe (hors du dépôt) : la planche montre alors les vrais PNG.
verifier-theme.py contrôle la déclaration : clés connues, fichiers
présents et sûrs, image déclarée dans images: (donc sa licence),
recadrage dans les bornes de l'image et d'au moins 512 px, licence et
auteur du tracé, fond lisible, marge entre 0 et 25 %.
L'habillage du mini-site (habillage.css, @media screen)
Le HTML des gabarits du thème s'habille dans habillage.css, dans un
bloc @media screen { … } : il ne peut pas toucher le papier. Ses classes
y sont libres, sauf : jamais un composant du papier, jamais un élément nu à
la racine du sélecteur (il toucherait les fiches ouvertes à l'écran ; partir
d'une classe ou de body[data-support="ecran"]), font-family par les
jetons (--police-titre|texte|etiquette|enfant), 12 px au moins, et les
mots de l'enfant (.mot-enfant : un nom d'espèce, un mot de corpus) en
Andika — le thème en règle la taille, pas la police. Les règles hors de
ce bloc gardent le contrat des composants (ci-dessus).
Le mouvement : toute animation sous@media (prefers-reduced-motion: no-preference), tout script parm.mouvement ; le moteur coupe de toute façon transitions et animations
quand l'enseignant l'a demandé.
L'accessibilité se vérifie, elle ne se suppose pas : tout au clavier
(lien d'évitement, sous-menus, menu du téléphone ouvert, parcouru, refermé
par Échap), 4,5:1 pour tout texte (les jetons privés aussi : les déclarer
dans contrastes: de theme.yml, par paires [texte, fond]), un alt à
chaque image (vide si elle est décorative), les mots de l'enfant en Andika.
Construire le mini-site d'une classe à partir d'une maquette
La maquette retenue (skill nouvelle-classe, « Le style ») est du HTML
statique : on la traduit en thème, sans rien perdre des rubriques.
- Lire la maquette, ses
NOTES.mdetCREDITS.md. Lister ses écrans
(accueil, menu, document, période) et ce que chacun montre. - Écrire
classe/projet.ymlavec les données réelles (le projet annuel
les porte) ; les données propres au thème sousperiodes.<clé>.theme. themes/<nom>/theme.yml(polices, images, icônes demandées, contrastes,
l'icône de l'appli),theme.css(jetons ; les couleurs de période gardent leur famille,
celle que citent les modes d'emploi imprimés),gabarits.js(une
fonction par écran, à partir du HTML de la maquette, les données venant
du modèle),habillage.css(le CSS de la maquette dans@media screen,
les couleurs passées en jetons).- Toutes les rubriques, pas seulement les pages de la maquette : chaque
progression, le projet, la programmation, les évaluations, chaque
période (même en esquisse), les crédits, une page introuvable. - Le papier reste sobre : un thème peut ne rien habiller du papier (les
gabarits n'y touchent jamais), ou reprendre l'habillage d'avant. - Contrôles :
classe.py genereretverifier(dontverifier-theme.py
et l'essai des gabarits), un parcours Playwright de chaque lien du menu
à 390 et 1280 px dans un sous-dossier comme en production (aucune
erreur, aucun 404, aucun débordement, menu au clavier), puis le PDF
(generer-pdf.sh,verifier-pagination.py: même nombre de PDF et de
pages qu'avant). Vider les caches du service worker entre deux essais
(serviceWorkers: 'block'dans Playwright). - Relire les captures avec l'œil de l'enseignant : le niveau visé est
celui de la maquette, ou mieux.
Créer le design system d'une classe
C'est l'étape « Le style » du skill nouvelle-classe, qui en tient la marche
complète : trois maquettes de mini-site radicalement différentes, quatre
écrans chacune, sur le vrai contenu de la classe, une planche comparative,
le choix de l'enseignant — et seulement ensuite le thème choisi se
construit (« Construire le mini-site… », ci-dessus). La même marche sert à
faire évoluer un style.
Une fois le thème construit : theme: <nom> dans classe.yml,python3 scripts/classe.py generer puis verifier, les icônes
(periodes[].icone et icones: de theme.yml, puisscripts/generer-icones.py, qui demande le réseau), l'icône de l'appli
(proposée dans l'univers du thème, choisie par l'enseignant, déclarée dansicone: ; generer en tire toutes les tailles), et le PDF (skill imprimer-pdf). Le verdict de l'enseignant s'écrit
dans le message de commit et dans theme.yml (description,retenu_le) ; les directions écartées ne restent pas dans le dépôt.
Polices : Fontsource (cdn.jsdelivr.net/npm/@fontsource/<nom>/…, ou@fontsource-variable/<nom> pour un fichier par sous-ensemble) ; lire la
licence dans son package.json (OFL-1.1) ; télécharger les sous-ensembleslatin et latin-ext en woff2 dans polices/, les déclarer avec leurunicode-range. Jamais Andika dans un thème : elle est du socle.
Motifs : des tracés simples (filet, tampon, onde, perforation, coin,
ficelle) tracés soi-même en SVG (CC0, « tracé pour le thème »), ou des
motifs libres déclarés avec leur auteur. Aucune illustration de contenu
(animal, objet reconnaissable) : elles viennent des pictogrammes et des
photographies, selon leurs skills. Un motif en mask prend la couleur du
jeton qu'on lui donne (background: var(--periode)) : un seul fichier sert
les cinq périodes.
Faire évoluer le style
- Une retouche de l'enseignant (« la couverture est trop chargée ») se fait
dans le thème, jamais dans une feuille du moteur. - Il manque une accroche (un composant, une partie, un ornement) : l'ajouter
au moteur, de façon générique — l'attribut dans le HTML fabriqué, la
partie dansCOMPOSANTSdeverifier-theme.py, la ligne du tableau
ci-dessus — puis la remonter (skill remonter-au-moteur). Ne jamais
renommer une accroche existante : les thèmes des classes en dépendent. - Une couleur écrite en dur dans une feuille du moteur est un défaut : elle
ne suit ni le thème, ni la période. La remplacer par un jeton, ou une
accroche dont la valeur par défaut vient de la charte.
La couverture des cahiers
L'imagier et les cartes-corpus s'ouvrent sur une couverture
(classe.couverture() dans scripts/classe.py) : une page de plus par
cahier ; couverture: false sur le cahier, dans materiel de classe.yml,
la retire. Les fiches élève, photocopiées une à une, n'en ont pas. Sa
structure est fixe ; sans thème elle est sobre (un cadre à la couleur de la
période, le milieu en grand, en Andika) ; un thème en fait une vraie
couverture. Hauteur 271 mm : 6 mm de tolérance, sinon elle pousse le cahier
d'une page.
Les règles, et d'où elles viennent
- Une couleur par période, et jamais seule. Le nom du milieu ou « P2 »
l'accompagne toujours : les fiches se photocopient en noir et blanc. - Pas d'émoji dans l'interface. Les icônes de l'écran sont des Lucide
(ISC), inscrites dansICONESdescripts/generer-icones.py. Sur le
papier, jamais d'icône Lucide : des pictogrammes (skill
fiches-illustrations), ou les ornements du thème. - Une mise en page imprimée se juge au PDF. Après toute retouche du
thème, defiches.css,imagier.css,cartes-corpus.css,impression.css,composants.cssou du socle : skill imprimer-pdf,verifier-pagination.pyà 0 anomalie, puis regarder les pages.
Vérifier une retouche de l'écran
Assembler le site (skill imprimer-pdf, étape 1), le servir dans un
sous-dossier (/<dépôt>/, comme GitHub Pages), puis une capture
Playwright (Node : require('playwright'), le Chromium est dans/opt/pw-browsers, --no-proxy-server pour le serveur local,serviceWorkers: 'block' pour ne pas voir une vieille page) à 1280 et à
390 px, en colorScheme: 'light' et 'dark' : l'accueil, le menu du
téléphone ouvert, une progression, une évaluation, une page de période, le
pied. ?date=AAAA-MM-JJ dans l'adresse simule un jour (une période en
cours, des vacances). Gouttière de 16 px au moins, aucun défilement
horizontal, jamais une carte seule sur sa rangée. Regarder les captures
avant de commiter.
Le miroir publié
Si la classe a publié son design system comme artefact de claude.ai (propre
à Claude), il reprend les jetons du thème, les règles ci-dessus et les
composants ; quand une valeur change ici, le mettre à jour (dans Claude
Code : outil Artifact, read puis publish sur son URL ; un agent qui n'a
pas cet outil le signale à l'enseignant). Le dépôt fait foi en cas d'écart.