diff --git a/SVG_CONTENT_ARCHITECTURE.md b/SVG_CONTENT_ARCHITECTURE.md new file mode 100644 index 0000000..180150b --- /dev/null +++ b/SVG_CONTENT_ARCHITECTURE.md @@ -0,0 +1,98 @@ +# Architecture des contenus SVG pédagogiques + +## Diagnostic + +Le problème des traits de fraction n'est pas un simple défaut ponctuel de mise en page. +Les retours du 2026-05-07 montrent le même motif sur plusieurs supports fractions : + +- traits obliques à proscrire pour les élèves de CM1 ; +- barres horizontales qui recouvrent le numérateur ou le dénominateur ; +- expressions de fractions qui se chevauchent dans les équations ; +- corrections faites directement dans les SVG finaux. + +L'architecture actuelle sait charger, servir, recadrer et relire des SVG. Elle ne sait pas garantir que les objets mathématiques dessinés à l'intérieur du SVG sont corrects. + +## État actuel + +- Les contenus sont stockés comme fichiers SVG finaux dans `backend/contenus_pedagogiques`. +- Le backend expose les SVG tels quels via `/program/assets/{asset_token}`. +- Le découpage en cards est fait par détection de grands groupes `` dans `backend/app/program_content.py`. +- Les retours de validation sont stockés séparément dans `review_updates`. +- Les SVG fractions récents utilisent déjà une convention locale : `math-expression` et `fraction-g`. + +Cette convention est utile, mais elle arrive trop tard : elle est écrite dans le SVG produit, sans source structurée, sans composant unique et sans validation automatique. + +## Décision recommandée + +Garder SVG comme format de sortie, mais ne plus considérer le SVG final comme la source principale pour les objets mathématiques sensibles. + +Pour les prochaines générations, il faut ajouter une couche intermédiaire : + +1. Une source structurée décrivant les cards et les objets pédagogiques. +2. Une petite bibliothèque de primitives SVG contrôlées. +3. Un validateur automatique lancé après génération. +4. Une revue humaine uniquement sur les points que l'automatique ne peut pas juger. + +## Primitive prioritaire : fraction verticale + +Une fraction ne doit plus être écrite à la main dans un SVG. + +La primitive `fraction(numerateur, denominateur, options)` doit produire : + +- un groupe `` ; +- deux textes centrés ; +- une barre horizontale ; +- des espacements calculés depuis la taille de police ; +- une largeur calculée depuis le plus long texte ; +- aucun trait oblique pour les fractions CM1 ; +- une boîte logique exportable, pour éviter les collisions dans les équations. + +Règle de rendu CM1 : + +- fraction verticale obligatoire ; +- barre horizontale visible et séparée des chiffres ; +- pas de notation `3/4` dans les SVG destinés à l'élève, sauf dans les notes Markdown ou les contextes de card. + +## Validation automatique minimale + +Le validateur doit refuser ou signaler : + +- texte SVG contenant une fraction oblique du type `3/4` ; +- groupe `fraction-g` sans numérateur, barre et dénominateur ; +- barre qui n'est pas située entre les deux textes ; +- espacement vertical trop faible autour de la barre ; +- barre trop courte par rapport aux chiffres ; +- SVG sans `viewBox` ou dimensions incohérentes ; +- card sans grand rectangle détectable, quand elle doit être découpée. + +Le premier filet de sécurité est disponible dans `backend/tools/validate_svg_quality.py`. + +## Architecture cible courte + +À court terme : + +- continuer à servir les SVG existants ; +- imposer `fraction-g` pour toutes les fractions verticales ; +- lancer `python backend/tools/validate_svg_quality.py backend/contenus_pedagogiques` après chaque génération ; +- corriger les fichiers signalés avant revue utilisateur. + +À moyen terme : + +- générer les SVG depuis des descriptions structurées, par exemple `*.content.json` ou `*.content.yaml` ; +- centraliser les primitives dans un module de génération ; +- faire produire aux agents du contenu structuré plutôt que du SVG brut ; +- rendre le SVG final reproductible à partir de la source. + +À long terme : + +- ajouter une capture raster automatique en CI pour détecter les chevauchements visuels réels ; +- comparer certains rendus à des snapshots de référence ; +- étendre les primitives aux droites graduées, bandes partagées, tableaux de nombres, zones de réponse et schémas en barres. + +## Évaluation + +L'architecture actuelle est acceptable pour afficher et relire des supports déjà produits. +Elle n'est pas suffisante pour produire régulièrement des contenus mathématiques propres. + +La bonne direction n'est pas de remplacer SVG, mais de déplacer l'intelligence avant le SVG final : composants mathématiques, contraintes géométriques, validation automatique, puis rendu. + diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/01_lire_ecrire_fraction_simple.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/01_lire_ecrire_fraction_simple.svg index 0d2a9b1..d849f63 100644 --- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/01_lire_ecrire_fraction_simple.svg +++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/01_lire_ecrire_fraction_simple.svg @@ -1,10 +1,85 @@ - - - + + + + + Exercices - Lire et écrire une fraction - 1. Lis les fractions123458710 - 2. Haut et bas254967Numérateur :Dénominateur :Recommence pour les autres. - 3. Écris en chiffresdeux tierstrois cinquièmesneuf dixièmesExplique avec unité et parts. + + + 1. Lis les fractions + + + 1 + + 2 + + + + + 3 + + 4 + + + + + 5 + + 8 + + + + + 7 + + 10 + + + + + + + + + + 2. Haut et bas + + + 2 + + 5 + + + + + 4 + + 9 + + + + + 6 + + 7 + + + Numérateur : + + Dénominateur : + + Recommence pour les autres. + + + + 3. Écris en chiffres + deux tiers + + trois cinquièmes + + neuf dixièmes + + Explique avec unité et parts. + - diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/02_representer_fraction_partage.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/02_representer_fraction_partage.svg index de626e6..514bc2f 100644 --- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/02_representer_fraction_partage.svg +++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/02_representer_fraction_partage.svg @@ -1,9 +1,64 @@ - - + + + + + Exercices - Représenter une fraction - 1. Quelle fraction ?2 parts sur 34 parts sur 56 parts sur 10 - 2. Colorie 36Puis explique :Dénominateur =Numérateur = - 3. Collection12 jetons, 5 rougesFraction rouge :Les parts doivent etre égales. + + + 1. Quelle fraction ? + 2 parts sur 3 + + 4 parts sur 5 + + 6 parts sur 10 + + + + + + 2. Colorie + + 3 + + 6 + + + + + + + + + + + Puis explique : + Dénominateur = + + Numérateur = + + + + + 3. Collection + 12 jetons, 5 rouges + + + + + + + + + + + + + + + Fraction rouge : + + Les parts doivent etre égales. + - diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/03_fraction_sur_demi_droite_graduee.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/03_fraction_sur_demi_droite_graduee.svg index c9eb6bc..e01fb39 100644 --- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/03_fraction_sur_demi_droite_graduee.svg +++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/03_fraction_sur_demi_droite_graduee.svg @@ -1,7 +1,53 @@ - - Exercices - Fraction sur demi-droite - 1. Place 3401Unité partagée en 4 parts.Avance de combien de parts ? - 2. Lis le point01L'unité est en 5 parts.Le point indique : + + + + + + Exercices - Fraction sur demi-droite + + + + 1. Place + + 3 + + 4 + + + + + + + 0 + + + + + 1 + + Unité partagée en 4 parts. + Avance de combien de parts ? + + + + + 2. Lis le point + + + + + 0 + + + + + + + 1 + + L'unité est en 5 parts. + Le point indique : + + - diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/04_fraction_superieure_a_un.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/04_fraction_superieure_a_un.svg index bfd8b90..92bb1fc 100644 --- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/04_fraction_superieure_a_un.svg +++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/04_fraction_superieure_a_un.svg @@ -1,8 +1,124 @@ - - Exercices - Fraction supérieure à 1 - 1. Entoure > 12555759438Attention : égal à 1 n'est pas > 1. - 2. Complète54 = 44 +73 = 63 +92 = 82 + - 3. Représente 74Colorie le reste. + + + + + + Exercices - Fraction supérieure à 1 + + + 1. Entoure > 1 + + + 2 + + 5 + + + + + 5 + + 5 + + + + + 7 + + 5 + + + + + 9 + + 4 + + + + + 3 + + 8 + + + Attention : égal à 1 n'est pas > 1. + + + + 2. Complète + + + 5 + + 4 + + = + + 4 + + 4 + + + + + + + + 7 + + 3 + + = + + 6 + + 3 + + + + + + + + 9 + + 2 + + = + + 8 + + 2 + + + + + + + + + + 3. Représente + + 7 + + 4 + + + + + + + + + + + + + + + + + Colorie le reste. + + - diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/05_comparer_fractions_simples.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/05_comparer_fractions_simples.svg index c65217f..9e10d45 100644 --- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/05_comparer_fractions_simples.svg +++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/05_comparer_fractions_simples.svg @@ -1,8 +1,135 @@ - - Exercices - Comparer des fractions - 1. Complète275768384949 - 2. Choisis la plus grande12 ou 1423 ou 2536 ou 310 - 3. Compare avec 1561661861Justifie un choix. + + + + + + Exercices - Comparer des fractions + + + 1. Complète + + + 2 + + 7 + + + + + + 5 + + 7 + + + + + 6 + + 8 + + + + + + 3 + + 8 + + + + + 4 + + 9 + + + + + + 4 + + 9 + + + + + + 2. Choisis la plus grande + + + 1 + + 2 + + ou + + 1 + + 4 + + + + + + 2 + + 3 + + ou + + 2 + + 5 + + + + + + 3 + + 6 + + ou + + 3 + + 10 + + + + + + + 3. Compare avec 1 + + + 5 + + 6 + + + + 1 + + + 6 + + 6 + + + + 1 + + + 8 + + 6 + + + + 1 + Justifie un choix. + - diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/06_encadrer_fraction_entre_entiers.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/06_encadrer_fraction_entre_entiers.svg index 8560c5f..94dd59e 100644 --- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/06_encadrer_fraction_entre_entiers.svg +++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/06_encadrer_fraction_entre_entiers.svg @@ -1,8 +1,78 @@ - - Exercices - Ençadrer une fraction - 1. Entiers en fractions1 =/42 =/4Puis recommence en tiers. - 2. Complète< 54 << 83 << 115 < - 3. Place 136123Ençadrement : + + + + + + Exercices - Encadrer une fraction + + + 1. Entiers en fractions + 1 = + + /4 + 2 = + + /4 + Puis recommence en tiers. + + + + 2. Complète + + + < + + 5 + + 4 + + < + + + + + < + + 8 + + 3 + + < + + + + + < + + 11 + + 5 + + < + + + + + + + 3. Place + + 13 + + 6 + + + + + + 1 + + 2 + + 3 + + Ençadrement : + + - diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/07_additionner_soustraire_fractions_simples.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/07_additionner_soustraire_fractions_simples.svg index b144581..dbdf4d1 100644 --- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/07_additionner_soustraire_fractions_simples.svg +++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/07_additionner_soustraire_fractions_simples.svg @@ -1,8 +1,141 @@ - - Exercices - Additionner et soustraire des fractions - 1. Additionne15 + 25 =27 + 37 =410 + 510 = - 2. Soustrais68 - 28 =79 - 39 =1012 - 412 = - 3. Dessine 27 + 37Résultat :Le dénominateur reste : + + + + + + Exercices - Additionner et soustraire des fractions + + + 1. Additionne + + + 1 + + 5 + + + + + 2 + + 5 + + = + + + + + 2 + + 7 + + + + + 3 + + 7 + + = + + + + + 4 + + 10 + + + + + 5 + + 10 + + = + + + + + + 2. Soustrais + + + 6 + + 8 + + - + + 2 + + 8 + + = + + + + + 7 + + 9 + + - + + 3 + + 9 + + = + + + + + 10 + + 12 + + - + + 4 + + 12 + + = + + + + + + + 3. Dessine + + 2 + + 7 + + + + + 3 + + 7 + + + + + + + + + + + + + + + + + Résultat : + + Le dénominateur reste : + + - diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/08_fraction_d_une_quantite.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/08_fraction_d_une_quantite.svg index 7e97b3b..2917960 100644 --- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/08_fraction_d_une_quantite.svg +++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices_svg/08_fraction_d_une_quantite.svg @@ -1,8 +1,79 @@ - - Exercices - Fraction d'une quantité - 1. Une part12 de 18 =13 de 24 =15 de 40 = - 2. Partage puis prends34 de 2020 ÷ 4 =Puis x 3 = - 3. Problème28 élèves.34 participent.Combien ?Deux gestes :1. partager2. prendre + + + + + + Exercices - Fraction d'une quantité + + + 1. Une part + + + 1 + + 2 + + de 18 = + + + + + 1 + + 3 + + de 24 = + + + + + 1 + + 5 + + de 40 = + + + + + + 2. Partage puis prends + + + 3 + + 4 + + de 20 + + 20 ÷ 4 = + + Puis x 3 = + + + + + + + + + + + 3. Problème + 28 élèves. + + + 3 + + 4 + + participent. + + Combien ? + + Deux gestes : + 1. partager + 2. prendre + - diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/kit_adaptatif/svg/parcours_fraction_support.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/kit_adaptatif/svg/parcours_fraction_support.svg index 1df1b71..bd0b460 100644 --- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/kit_adaptatif/svg/parcours_fraction_support.svg +++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/kit_adaptatif/svg/parcours_fraction_support.svg @@ -1,35 +1,32 @@ - - + + Aide fractions Une unité, des parts égales, des parts prises. - - + 3 4 3 parts prises 4 parts égales - - - - - - - - + + + + + + + 3 parts sur 4 - - - - - - - - - + + + + + + + + 0 1 3 - + 4 diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/kit_adaptatif/svg/test_diagnostic_fraction.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/kit_adaptatif/svg/test_diagnostic_fraction.svg index dcaabf6..848ed53 100644 --- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/kit_adaptatif/svg/test_diagnostic_fraction.svg +++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/kit_adaptatif/svg/test_diagnostic_fraction.svg @@ -1,43 +1,38 @@ - - + + Diagnostic fractions Lis, dessine, place, puis compare. - - + 1. Lire 3 - + 4 - - + 2. Partager - - - - - - - + + + + + + 3. Placer - - - - + + + + 0 1 - - + 4. Comparer 2 - + 5 ? 4 - + 5 - - + Observer surtout les erreurs, les hésitations et les mots utilisés. Le diagnostic choisit une aide. Il ne note pas l'élève. diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/01_lire_ecrire_fraction_simple.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/01_lire_ecrire_fraction_simple.svg index 5330ccd..fd1c28b 100644 --- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/01_lire_ecrire_fraction_simple.svg +++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/01_lire_ecrire_fraction_simple.svg @@ -1,43 +1,54 @@ - + - - + + Lire et écrire une fraction Maths CM1 - Numérateur, dénominateur, unité - + - + La fraction 3 - + 4 - + Ce que ça dit - 3 parts prises - 4 parts égales - 34 se lit : + + 3 parts prises + + 4 parts égales + + + 3 + + 4 + + se lit : + trois quarts - + L'unité partagée - - - - - + + + + + + + L'unité est coupée en 4 parts égales. - + À retenir Le dénominateur indique le partage. Le numérateur indique les parts prises. diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/02_representer_fraction_partage.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/02_representer_fraction_partage.svg index 2278b69..9cca738 100644 --- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/02_representer_fraction_partage.svg +++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/02_representer_fraction_partage.svg @@ -1,17 +1,77 @@ - - - + + + + + + Représenter une fraction Je partage l'unité en parts égales, puis je colorie - - Bande : 35 - - 5 parts égales, 3 parts coloriées - Disque : 14 - - 4 parts égales, 1 part coloriée - Collection : 610 - - 10 objets, 6 sont choisis - À retenirUne fraction n'a de sens que si l'unité et les parts égales sont claires. + + + + + Bande : + + 3 + + 5 + + + + + + + + + + + + + 5 parts égales, 3 parts coloriées + + + + + Disque : + + 1 + + 4 + + + + + + + 4 parts égales, 1 part coloriée + + + + + Collection : + + 6 + + 10 + + + + + + + + + + + + + + + 10 objets, 6 sont choisis + + + + À retenir + Une fraction n'a de sens que si l'unité et les parts égales sont claires. + diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/03_fraction_sur_demi_droite_graduee.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/03_fraction_sur_demi_droite_graduee.svg index 1032b0c..3c61147 100644 --- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/03_fraction_sur_demi_droite_graduee.svg +++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/03_fraction_sur_demi_droite_graduee.svg @@ -1,19 +1,60 @@ - - - + + + + + + Placer une fraction sur une demi-droite Je partage chaque unité selon le dénominateur - - Exemple : placer 54 - - - 0 - 1 - 2 - - 54 + + + + + Exemple : placer + + 5 + + 4 + + + + + + + 0 + + 1 + + 2 + + + + + + + + + + 5 + + 4 + + + + Dénominateur 4 : + chaque unité a 4 parts. + + + 5 + + 4 + + est juste après 1. - Dénominateur 4 :chaque unité a 4 parts.54 est juste après 1. - À retenirL'intervalle de 0 à 1 est l'unité. Je le partage en parts égales. + + + À retenir + L'intervalle de 0 à 1 est l'unité. Je le partage en parts égales. + diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/04_fraction_superieure_a_un.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/04_fraction_superieure_a_un.svg index 7fe0182..166cd53 100644 --- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/04_fraction_superieure_a_un.svg +++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/04_fraction_superieure_a_un.svg @@ -1,4 +1,4 @@ - + - - + + Fraction supérieure à 1 Quand le numérateur dépasse le dénominateur - - + - + Exemple : - - 7 - - 4 + + 7 + + 4 - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + - - + Je décompose - - - 7 - - 4 + + 7 + + 4 = - - 4 - - 4 + + 4 + + 4 + - - 3 - - 4 + + 3 + + 4 - - - 7 - - 4 + + 7 + + 4 = 1 + - - 3 - - 4 + + 3 + + 4 - La première unité est complète. Il reste encore trois quarts. - - + À retenir Une fraction peut être plus grande que 1 : il faut alors utiliser plusieurs unités. diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/05_comparer_fractions_simples.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/05_comparer_fractions_simples.svg index 020dac3..24387ee 100644 --- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/05_comparer_fractions_simples.svg +++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/05_comparer_fractions_simples.svg @@ -1,16 +1,73 @@ - - - + + + + + + Comparer des fractions simples Même unité, parts égales, puis je compare - - Même dénominateur - 35 < 45 - - + + + + Même dénominateur + + + 3 + + 5 + + < + + 4 + + 5 + + + + + + + + + + + + + + + + + + + + + + + - Même numérateur - 12 > 14Quand on partage en plus de parts,chaque part est plus petite.Toujours comparer la même unité. + + + Même numérateur + + + 1 + + 2 + + > + + 1 + + 4 + + + Quand on partage en plus de parts, + chaque part est plus petite. + Toujours comparer la même unité. + + + + À retenir + À dénominateur égal, le plus grand numérateur donne la plus grande fraction. - À retenirÀ dénominateur égal, le plus grand numérateur donne la plus grande fraction. diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/06_encadrer_fraction_entre_entiers.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/06_encadrer_fraction_entre_entiers.svg index 6a7c96e..17562c2 100644 --- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/06_encadrer_fraction_entre_entiers.svg +++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/06_encadrer_fraction_entre_entiers.svg @@ -1,13 +1,72 @@ - - - - Ençadrer une fraction + + + + + + + Encadrer une fraction Je cherche entre quels entiers elle se trouve - - Exemple : 73 - 63 = 293 = 32 < 73 < 3 - - 012373 + + + + + Exemple : + + 7 + + 3 + + + + + 6 + + 3 + + = 2 + + + + 9 + + 3 + + = 3 + + + 2 < + + 7 + + 3 + + < 3 + + + + + + 0 + + 1 + + 2 + + 3 + + + + + 7 + + 3 + + + + + + + À retenir + Je compare la fraction aux fractions qui valent les entiers voisins. - À retenirJe compare la fraction aux fractions qui valent les entiers voisins. diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/07_additionner_soustraire_fractions_simples.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/07_additionner_soustraire_fractions_simples.svg index 51f656f..2c15940 100644 --- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/07_additionner_soustraire_fractions_simples.svg +++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/07_additionner_soustraire_fractions_simples.svg @@ -1,12 +1,78 @@ - - - + + + + + + Additionner des fractions simples Si les dénominateurs sont les mêmes, les parts ont la même taille - - Exemple27 + 37 = 57 - + + + + Exemple + + + 2 + + 7 + + + + + 3 + + 7 + + = + + 5 + + 7 + + + + + + + + + + + + + + + + + + + + La règle + Je garde le dénominateur. + J'ajoute ou je retire + seulement les numérateurs. + + + 6 + + 8 + + - + + 2 + + 8 + + = + + 4 + + 8 + + + + + + À retenir + Avant de calculer, je vérifie que les dénominateurs sont identiques. - La règleJe garde le dénominateur.J'ajoute ou je retireseulement les numérateurs.68 - 28 = 48 - À retenirAvant de calculer, je vérifie que les dénominateurs sont identiques. diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/08_fraction_d_une_quantite.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/08_fraction_d_une_quantite.svg index 4e51eee..af3551c 100644 --- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/08_fraction_d_une_quantite.svg +++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/svg/08_fraction_d_une_quantite.svg @@ -1,13 +1,54 @@ - - - + + + + + + Trouver une fraction d'une quantité Je partage, puis je prends les parts demandées - - Exemple : 34 de 20 - - 20 partage en 4 parts : chaque part vaut 5.Je prends 3 parts : 15. + + + + + Exemple : + + 3 + + 4 + + de 20 + + + + + + + + + + + 20 partage en 4 parts : chaque part vaut 5. + Je prends 3 parts : 15. + + + + La méthode + 20 ÷ 4 = 5 + 5 x 3 = 15 + Le dénominateur partage. + Le numérateur dit combien prendre. + + + + À retenir + + Pour trouver + + 3 + + 4 + + d'une quantité : je divise par 4, puis je multiplie par 3. + - La méthode20 ÷ 4 = 55 x 3 = 15Le dénominateur partage.Le numérateur dit combien prendre. - À retenirPour trouver 34 d'une quantité : je divise par 4, puis je multiplie par 3. diff --git a/backend/tools/validate_svg_quality.py b/backend/tools/validate_svg_quality.py new file mode 100644 index 0000000..c60c16a --- /dev/null +++ b/backend/tools/validate_svg_quality.py @@ -0,0 +1,260 @@ +from __future__ import annotations + +import argparse +import re +import sys +import xml.etree.ElementTree as ET +from dataclasses import dataclass +from pathlib import Path + + +SLASH_FRACTION_RE = re.compile(r"(? str: + return tag.rsplit("}", 1)[-1] + + +def parse_number(value: str | None, default: float = 0.0) -> float: + if not value: + return default + try: + return float(value) + except ValueError: + return default + + +def node_text(node: ET.Element) -> str: + return "".join(node.itertext()).strip() + + +def class_names(node: ET.Element) -> set[str]: + return set((node.attrib.get("class") or "").split()) + + +def has_class(node: ET.Element, name: str) -> bool: + return name in class_names(node) + + +def parse_styles(root: ET.Element) -> dict[str, dict[str, str]]: + styles: dict[str, dict[str, str]] = {} + for node in root.iter(): + if local_name(node.tag) != "style": + continue + text = node.text or "" + for match in CLASS_STYLE_RE.finditer(text): + declarations: dict[str, str] = {} + for declaration in match.group(2).split(";"): + if ":" not in declaration: + continue + key, value = declaration.split(":", 1) + declarations[key.strip()] = value.strip() + styles[match.group(1)] = declarations + return styles + + +def font_size(node: ET.Element, styles: dict[str, dict[str, str]], default: float = 24.0) -> float: + direct = parse_number(node.attrib.get("font-size"), 0) + if direct: + return direct + + style_attr = node.attrib.get("style") or "" + style_match = FONT_SIZE_RE.search(style_attr) + if style_match: + return parse_number(style_match.group(1), default) + + for class_name in class_names(node): + value = styles.get(class_name, {}).get("font-size") + if value: + return parse_number(value.replace("px", ""), default) + return default + + +def line_width(node: ET.Element) -> float: + return abs(parse_number(node.attrib.get("x2")) - parse_number(node.attrib.get("x1"))) + + +def line_y(node: ET.Element) -> float: + return (parse_number(node.attrib.get("y1")) + parse_number(node.attrib.get("y2"))) / 2 + + +def text_x(node: ET.Element) -> float: + return parse_number(node.attrib.get("x")) + + +def text_y(node: ET.Element) -> float: + return parse_number(node.attrib.get("y")) + + +def estimated_text_width(text: str, size: float) -> float: + # Chiffres scolaires en police sans-serif : estimation volontairement prudente. + return max(1, len(text.strip())) * size * 0.62 + + +def validate_fraction_group(path: Path, group: ET.Element, styles: dict[str, dict[str, str]]) -> list[Issue]: + issues: list[Issue] = [] + texts = [node for node in group if local_name(node.tag) == "text"] + lines = [node for node in group if local_name(node.tag) == "line"] + + if len(texts) < 2 or not lines: + return [ + Issue( + "error", + path, + "Un groupe fraction-g doit contenir au moins deux textes et une barre horizontale.", + ) + ] + + numerator = texts[0] + denominator = texts[-1] + bar = lines[0] + num_y = text_y(numerator) + den_y = text_y(denominator) + bar_y = line_y(bar) + + if not num_y < bar_y < den_y: + issues.append(Issue("error", path, "La barre d'une fraction-g n'est pas entre le numérateur et le dénominateur.")) + + num_size = font_size(numerator, styles) + den_size = font_size(denominator, styles) + min_top_gap = max(8.0, num_size * 0.30) + min_bottom_gap = max(8.0, den_size * 0.30) + + if bar_y - num_y < min_top_gap: + issues.append( + Issue( + "warning", + path, + f"Espace faible entre numérateur et barre ({bar_y - num_y:.1f}px, attendu >= {min_top_gap:.1f}px).", + ) + ) + if den_y - bar_y < min_bottom_gap: + issues.append( + Issue( + "warning", + path, + f"Espace faible entre barre et dénominateur ({den_y - bar_y:.1f}px, attendu >= {min_bottom_gap:.1f}px).", + ) + ) + + expected_width = max( + estimated_text_width(node_text(numerator), num_size), + estimated_text_width(node_text(denominator), den_size), + ) + if line_width(bar) < expected_width * 0.95: + issues.append( + Issue( + "warning", + path, + f"Barre de fraction possiblement trop courte ({line_width(bar):.1f}px pour ~{expected_width:.1f}px de texte).", + ) + ) + + center = (parse_number(bar.attrib.get("x1")) + parse_number(bar.attrib.get("x2"))) / 2 + if abs(text_x(numerator) - center) > 4 or abs(text_x(denominator) - center) > 4: + issues.append(Issue("warning", path, "Numérateur ou dénominateur non centré sur la barre de fraction.")) + + return issues + + +def validate_svg(path: Path) -> list[Issue]: + issues: list[Issue] = [] + try: + text = path.read_text(encoding="utf-8") + root = ET.fromstring(text) + except Exception as exc: + return [Issue("error", path, f"SVG illisible: {exc}")] + + if local_name(root.tag) != "svg": + issues.append(Issue("error", path, "Le fichier n'a pas de racine .")) + return issues + + if not root.attrib.get("viewBox"): + issues.append(Issue("warning", path, "SVG sans viewBox : recadrage et responsive moins fiables.")) + + styles = parse_styles(root) + + for node in root.iter(): + if local_name(node.tag) == "text": + content = node_text(node) + for forbidden, expected in FORBIDDEN_TEXT.items(): + if forbidden in content: + issues.append( + Issue( + "error", + path, + f"Texte incorrect détecté: {forbidden!r}. Utiliser {expected!r}.", + ) + ) + if MOJIBAKE_RE.search(content): + issues.append( + Issue( + "error", + path, + f"Encodage texte suspect dans le SVG: {content!r}.", + ) + ) + if SLASH_FRACTION_RE.search(content): + issues.append( + Issue( + "error", + path, + f"Fraction oblique détectée dans un texte SVG: {content!r}. Utiliser une fraction verticale.", + ) + ) + + if local_name(node.tag) == "g" and has_class(node, "fraction-g"): + issues.extend(validate_fraction_group(path, node, styles)) + + return issues + + +def iter_svg_paths(paths: list[Path]) -> list[Path]: + files: list[Path] = [] + for path in paths: + if path.is_file() and path.suffix.lower() == ".svg": + files.append(path) + elif path.is_dir(): + files.extend(sorted(path.rglob("*.svg"))) + return sorted(set(files)) + + +def main() -> int: + parser = argparse.ArgumentParser(description="Valide les SVG pédagogiques sensibles.") + parser.add_argument("paths", nargs="+", type=Path, help="Fichiers ou dossiers SVG à contrôler.") + parser.add_argument("--warnings-as-errors", action="store_true", help="Retourne une erreur si des warnings existent.") + args = parser.parse_args() + + all_issues: list[Issue] = [] + files = iter_svg_paths(args.paths) + for path in files: + all_issues.extend(validate_svg(path)) + + for issue in all_issues: + print(f"{issue.severity.upper()} {issue.path}: {issue.message}") + + errors = [issue for issue in all_issues if issue.severity == "error"] + warnings = [issue for issue in all_issues if issue.severity == "warning"] + print(f"SVG contrôlés: {len(files)} | erreurs: {len(errors)} | warnings: {len(warnings)}") + + if errors or (args.warnings_as_errors and warnings): + return 1 + return 0 + + +if __name__ == "__main__": + sys.exit(main())