diff --git a/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/01_lire_ecrire_fraction_simple/exercices.svg b/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/01_lire_ecrire_fraction_simple/exercices.svg
index 0d2a9b1..28041c6 100644
--- a/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/01_lire_ecrire_fraction_simple/exercices.svg
+++ b/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/01_lire_ecrire_fraction_simple/exercices.svg
@@ -1,10 +1,21 @@
-
diff --git a/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/02_representer_fraction_partage/exercices.svg b/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/02_representer_fraction_partage/exercices.svg
index de626e6..151766d 100644
--- a/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/02_representer_fraction_partage/exercices.svg
+++ b/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/02_representer_fraction_partage/exercices.svg
@@ -1,9 +1,21 @@
-
diff --git a/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/03_fraction_sur_demi_droite_graduee/exercices.svg b/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/03_fraction_sur_demi_droite_graduee/exercices.svg
index c9eb6bc..68a41b3 100644
--- a/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/03_fraction_sur_demi_droite_graduee/exercices.svg
+++ b/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/03_fraction_sur_demi_droite_graduee/exercices.svg
@@ -1,7 +1,21 @@
-
diff --git a/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/04_fraction_superieure_a_un/exercices.svg b/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/04_fraction_superieure_a_un/exercices.svg
index bfd8b90..afd9ae8 100644
--- a/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/04_fraction_superieure_a_un/exercices.svg
+++ b/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/04_fraction_superieure_a_un/exercices.svg
@@ -1,8 +1,21 @@
-
diff --git a/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/05_comparer_fractions_simples/exercices.svg b/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/05_comparer_fractions_simples/exercices.svg
index c65217f..859ff4a 100644
--- a/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/05_comparer_fractions_simples/exercices.svg
+++ b/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/05_comparer_fractions_simples/exercices.svg
@@ -1,8 +1,21 @@
-
diff --git a/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/06_encadrer_fraction_entre_entiers/exercices.svg b/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/06_encadrer_fraction_entre_entiers/exercices.svg
index 8560c5f..57493f2 100644
--- a/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/06_encadrer_fraction_entre_entiers/exercices.svg
+++ b/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/06_encadrer_fraction_entre_entiers/exercices.svg
@@ -1,8 +1,21 @@
-
diff --git a/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/07_additionner_soustraire_fractions_simples/exercices.svg b/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/07_additionner_soustraire_fractions_simples/exercices.svg
index b144581..28e969c 100644
--- a/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/07_additionner_soustraire_fractions_simples/exercices.svg
+++ b/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/07_additionner_soustraire_fractions_simples/exercices.svg
@@ -1,8 +1,21 @@
-
diff --git a/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/08_fraction_d_une_quantite/exercices.svg b/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/08_fraction_d_une_quantite/exercices.svg
index 7e97b3b..49bc455 100644
--- a/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/08_fraction_d_une_quantite/exercices.svg
+++ b/Programme/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/08_fraction_d_une_quantite/exercices.svg
@@ -1,8 +1,21 @@
-
diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/01_lire_ecrire_fraction_simple/exercices.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/01_lire_ecrire_fraction_simple/exercices.svg
index d849f63..28041c6 100644
--- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/01_lire_ecrire_fraction_simple/exercices.svg
+++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/01_lire_ecrire_fraction_simple/exercices.svg
@@ -1,85 +1,21 @@
diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/02_representer_fraction_partage/exercices.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/02_representer_fraction_partage/exercices.svg
index 514bc2f..151766d 100644
--- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/02_representer_fraction_partage/exercices.svg
+++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/02_representer_fraction_partage/exercices.svg
@@ -1,64 +1,21 @@
diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/03_fraction_sur_demi_droite_graduee/exercices.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/03_fraction_sur_demi_droite_graduee/exercices.svg
index e01fb39..68a41b3 100644
--- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/03_fraction_sur_demi_droite_graduee/exercices.svg
+++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/03_fraction_sur_demi_droite_graduee/exercices.svg
@@ -1,53 +1,21 @@
diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/04_fraction_superieure_a_un/exercices.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/04_fraction_superieure_a_un/exercices.svg
index 92bb1fc..afd9ae8 100644
--- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/04_fraction_superieure_a_un/exercices.svg
+++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/04_fraction_superieure_a_un/exercices.svg
@@ -1,124 +1,21 @@
diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/05_comparer_fractions_simples/exercices.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/05_comparer_fractions_simples/exercices.svg
index 9e10d45..859ff4a 100644
--- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/05_comparer_fractions_simples/exercices.svg
+++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/05_comparer_fractions_simples/exercices.svg
@@ -1,135 +1,21 @@
diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/06_encadrer_fraction_entre_entiers/exercices.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/06_encadrer_fraction_entre_entiers/exercices.svg
index 94dd59e..57493f2 100644
--- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/06_encadrer_fraction_entre_entiers/exercices.svg
+++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/06_encadrer_fraction_entre_entiers/exercices.svg
@@ -1,78 +1,21 @@
diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/07_additionner_soustraire_fractions_simples/exercices.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/07_additionner_soustraire_fractions_simples/exercices.svg
index dbdf4d1..28e969c 100644
--- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/07_additionner_soustraire_fractions_simples/exercices.svg
+++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/07_additionner_soustraire_fractions_simples/exercices.svg
@@ -1,141 +1,21 @@
diff --git a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/08_fraction_d_une_quantite/exercices.svg b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/08_fraction_d_une_quantite/exercices.svg
index 2917960..49bc455 100644
--- a/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/08_fraction_d_une_quantite/exercices.svg
+++ b/backend/contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices/08_fraction_d_une_quantite/exercices.svg
@@ -1,79 +1,21 @@
diff --git a/backend/tools/regenerate_fraction_exercise_svgs.py b/backend/tools/regenerate_fraction_exercise_svgs.py
new file mode 100644
index 0000000..00e3577
--- /dev/null
+++ b/backend/tools/regenerate_fraction_exercise_svgs.py
@@ -0,0 +1,293 @@
+from __future__ import annotations
+
+from pathlib import Path
+from xml.sax.saxutils import escape
+
+
+ROOT = Path(__file__).resolve().parents[2]
+RELATIVE = Path("contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices")
+TARGET_ROOTS = [ROOT / "backend" / RELATIVE, ROOT / "Programme" / RELATIVE]
+
+
+STYLE = """
+.bg{fill:#f6f5ef}
+.panel{fill:#fff;stroke:#d9e7e1;stroke-width:3}
+.card{fill:#eef7f4;stroke:#c9dfd8;stroke-width:3}
+.white{fill:#fff;stroke:#c9dfd8;stroke-width:3}
+.title{font-family:"Trebuchet MS",Verdana,sans-serif;font-size:48px;font-weight:800;fill:#074f4b}
+.h2{font-family:"Trebuchet MS",Verdana,sans-serif;font-size:28px;font-weight:800;fill:#074f4b}
+.body{font-family:"Trebuchet MS",Verdana,sans-serif;font-size:24px;fill:#1d3038}
+.small{font-family:"Trebuchet MS",Verdana,sans-serif;font-size:20px;fill:#2d4148}
+.frac{font-family:"Trebuchet MS",Verdana,sans-serif;font-size:52px;font-weight:800;fill:#074f4b}
+.op{font-family:"Trebuchet MS",Verdana,sans-serif;font-size:34px;font-weight:800;fill:#074f4b}
+.blank{stroke:#7fa79d;stroke-width:3;stroke-dasharray:10 10}
+.axis{stroke:#26383d;stroke-width:4;stroke-linecap:round}
+.tick{stroke:#26383d;stroke-width:3;stroke-linecap:round}
+.shade{fill:#5ab7a8}
+.empty{fill:#fff}
+""".strip()
+
+
+def text(x: int, y: int, value: str, klass: str = "body", anchor: str | None = None) -> str:
+ anchor_attr = f' text-anchor="{anchor}"' if anchor else ""
+ return f'{escape(value)}'
+
+
+def line(x1: int, y1: int, x2: int, y2: int, klass: str = "blank") -> str:
+ return f''
+
+
+def fraction(x: int, y: int, n: str | int, d: str | int, size: int = 52) -> str:
+ n_text = str(n)
+ d_text = str(d)
+ width = max(58, int(max(len(n_text), len(d_text)) * size * 0.62) + 22)
+ cx = width / 2
+ return (
+ f''
+ f'{escape(n_text)}'
+ f''
+ f'{escape(d_text)}'
+ ""
+ )
+
+
+def card(x: int, y: int, w: int, h: int, title: str, body: str, soft: bool = True) -> str:
+ klass = "card" if soft else "white"
+ return (
+ f''
+ f''
+ f'{text(32, 58, title, "h2")}'
+ f'{body}'
+ ""
+ )
+
+
+def sheet(title: str, cards: list[str]) -> str:
+ return (
+ '\n'
+ )
+
+
+def band(x: int, y: int, parts: int, shaded: int, width: int = 250, height: int = 44) -> str:
+ cell = width / parts
+ rects = []
+ for index in range(parts):
+ fill = "shade" if index < shaded else "empty"
+ rects.append(
+ f''
+ )
+ return "".join(rects)
+
+
+def number_line(x: int, y: int, parts: int, point: int | None = None, width: int = 320) -> str:
+ items = [line(x, y, x + width, y, "axis")]
+ for index in range(parts + 1):
+ px = x + int(width * index / parts)
+ items.append(line(px, y - 14, px, y + 14, "tick"))
+ items.append(text(x, y + 48, "0", "small", "middle"))
+ items.append(text(x + width, y + 48, "1", "small", "middle"))
+ if point is not None:
+ px = x + int(width * point / parts)
+ items.append(f'')
+ return "".join(items)
+
+
+def svg_01() -> str:
+ c1 = "".join(
+ fraction(58, y, n, d) + line(190, y + 8, 360, y + 8)
+ for y, (n, d) in zip([145, 255, 365, 475], [(1, 2), (3, 4), (5, 8), (7, 10)])
+ )
+ c2 = "".join(
+ fraction(58, y, n, d) + text(175, y - 22, "Numerateur :", "small") + line(320, y - 22, 385, y - 22)
+ + text(175, y + 42, "Denominateur :", "small") + line(330, y + 42, 385, y + 42)
+ for y, (n, d) in zip([145, 305, 465], [(2, 5), (4, 9), (6, 7)])
+ )
+ c3 = (
+ text(45, 140, "deux tiers", "body") + line(45, 180, 340, 180)
+ + text(45, 260, "trois cinquiemes", "body") + line(45, 300, 340, 300)
+ + text(45, 380, "neuf dixiemes", "body") + line(45, 420, 340, 420)
+ + text(45, 510, "Ecris avec une barre horizontale.", "small")
+ )
+ return sheet("Exercices - Lire et ecrire une fraction", [
+ card(110, 190, 430, 560, "1. Lis", c1),
+ card(590, 190, 430, 560, "2. Haut et bas", c2, False),
+ card(1070, 190, 420, 560, "3. Ecris", c3),
+ ])
+
+
+def svg_02() -> str:
+ c1 = (
+ text(38, 120, "Quelle fraction est coloriee ?", "body")
+ + band(45, 160, 3, 2) + line(330, 185, 430, 185)
+ + band(45, 260, 5, 4) + line(330, 285, 430, 285)
+ + band(45, 360, 10, 6) + line(330, 385, 430, 385)
+ )
+ c2 = "".join(
+ fraction(52, y, n, d) + text(160, y + 18, "Dessine une bande.", "small") + line(345, y + 18, 470, y + 18)
+ for y, (n, d) in zip([145, 285, 425], [(1, 4), (3, 6), (5, 8)])
+ )
+ c3 = (
+ text(40, 130, "Verifie toujours :", "body")
+ + text(55, 200, "1. une seule unite", "body")
+ + text(55, 270, "2. des parts egales", "body")
+ + text(55, 340, "3. les parts prises", "body")
+ + text(55, 450, "Explique ton choix a l'oral.", "small")
+ )
+ return sheet("Exercices - Representer une fraction partagee", [
+ card(95, 190, 460, 560, "1. Fraction coloriee", c1),
+ card(590, 190, 500, 560, "2. Dessine", c2, False),
+ card(1125, 190, 360, 560, "3. Verifie", c3),
+ ])
+
+
+def svg_03() -> str:
+ c1 = number_line(55, 190, 4) + text(55, 115, "L'unite est partagee en 4.", "body") + line(55, 330, 350, 330)
+ c2 = number_line(55, 210, 4, 3) + text(55, 115, "Avance de 3 petites parts.", "body") + fraction(360, 330, 3, 4)
+ c3 = number_line(55, 210, 5, 2) + text(55, 115, "Lis le point orange.", "body") + line(55, 330, 350, 330)
+ return sheet("Exercices - Fraction sur demi-droite", [
+ card(95, 190, 450, 500, "1. L'unite", c1),
+ card(575, 190, 450, 500, "2. Placer", c2, False),
+ card(1055, 190, 450, 500, "3. Lire", c3),
+ ])
+
+
+def svg_04() -> str:
+ c1 = "".join(fraction(x, 170, n, d) for x, (n, d) in zip([45, 150, 255, 360, 465], [(2, 5), (5, 5), (7, 5), (9, 4), (3, 8)]))
+ c1 += text(45, 330, "Entoure seulement celles qui sont > 1.", "small")
+ c2 = (
+ fraction(45, 150, 5, 4) + text(145, 170, "=", "op") + fraction(205, 150, 4, 4) + text(305, 170, "+", "op") + line(365, 170, 500, 170)
+ + fraction(45, 330, 7, 3) + text(145, 350, "=", "op") + fraction(205, 330, 6, 3) + text(305, 350, "+", "op") + line(365, 350, 500, 350)
+ )
+ c3 = (
+ text(35, 135, "Numerateur", "small")
+ + text(35, 180, "plus grand", "small")
+ + text(35, 225, "que le bas :", "small")
+ + text(35, 285, "souvent > 1.", "small")
+ + text(35, 380, "Egal veut = 1.", "small")
+ )
+ return sheet("Exercices - Fractions superieures a 1", [
+ card(80, 190, 560, 500, "1. Reconnaitre", c1),
+ card(670, 190, 560, 500, "2. Decomposer", c2, False),
+ card(1260, 190, 260, 500, "3. Attention", c3),
+ ])
+
+
+def svg_05() -> str:
+ rows = [(2, 7, "<", 5, 7), (6, 8, ">", 3, 8), (4, 9, "=", 4, 9)]
+ c1 = "".join(
+ fraction(45, y, a, b) + text(155, y + 22, "...", "op") + fraction(235, y, c, d)
+ for y, (a, b, _, c, d) in zip([135, 285, 435], rows)
+ )
+ c2 = "".join(
+ fraction(45, y, a, b) + text(155, y + 22, "ou", "op") + fraction(245, y, c, d) + line(360, y + 22, 500, y + 22)
+ for y, (a, b, c, d) in zip([135, 285, 435], [(1, 2, 1, 4), (2, 3, 2, 5), (3, 6, 3, 10)])
+ )
+ c3 = (
+ text(45, 130, "Meme denominateur :", "body")
+ + text(45, 190, "compare les numerateurs.", "small")
+ + text(45, 290, "Meme numerateur :", "body")
+ + text(45, 350, "les parts grandes", "small")
+ + text(45, 390, "ont un bas plus petit.", "small")
+ )
+ return sheet("Exercices - Comparer des fractions", [
+ card(80, 190, 520, 560, "1. Complete", c1),
+ card(630, 190, 520, 560, "2. Choisis", c2, False),
+ card(1180, 190, 330, 560, "3. Strategie", c3),
+ ])
+
+
+def svg_06() -> str:
+ c1 = (
+ text(45, 125, "Avec des quarts :", "body") + text(45, 185, "1 =", "op") + line(120, 185, 220, 185) + text(235, 185, "et 2 =", "op") + line(340, 185, 440, 185)
+ + text(45, 300, "Avec des tiers :", "body") + text(45, 360, "2 =", "op") + line(120, 360, 220, 360) + text(235, 360, "et 3 =", "op") + line(340, 360, 440, 360)
+ )
+ c2 = (
+ text(45, 177, "... <", "op") + fraction(180, 155, 5, 4) + text(290, 177, "< ...", "op")
+ + text(45, 327, "... <", "op") + fraction(180, 305, 8, 3) + text(290, 327, "< ...", "op")
+ + text(45, 477, "... <", "op") + fraction(180, 455, 11, 5) + text(305, 477, "< ...", "op")
+ )
+ c3 = number_line(45, 220, 4, 5, 320) + text(45, 120, "Repere l'entier juste avant", "body") + text(45, 345, "puis l'entier juste apres.", "small")
+ return sheet("Exercices - Encadrer une fraction", [
+ card(90, 190, 470, 540, "1. Entiers", c1),
+ card(595, 190, 410, 540, "2. Encadrer", c2, False),
+ card(1040, 190, 470, 540, "3. Droite", c3),
+ ])
+
+
+def svg_07() -> str:
+ c1 = "".join(
+ fraction(45, y, a, b) + text(145, y + 22, "+", "op") + fraction(205, y, c, d) + text(310, y + 22, "=", "op") + line(370, y + 22, 510, y + 22)
+ for y, (a, b, c, d) in zip([125, 275, 425], [(1, 5, 2, 5), (2, 7, 3, 7), (4, 10, 5, 10)])
+ )
+ c2 = "".join(
+ fraction(45, y, a, b) + text(145, y + 22, "-", "op") + fraction(205, y, c, d) + text(310, y + 22, "=", "op") + line(370, y + 22, 510, y + 22)
+ for y, (a, b, c, d) in zip([125, 275, 425], [(6, 8, 2, 8), (7, 9, 3, 9), (10, 12, 4, 12)])
+ )
+ c3 = (
+ text(35, 130, "On garde", "small")
+ + text(35, 175, "le denominateur.", "small")
+ + text(35, 260, "On calcule", "small")
+ + text(35, 305, "les numerateurs.", "small")
+ + line(45, 380, 330, 380)
+ )
+ return sheet("Exercices - Additionner et soustraire", [
+ card(75, 190, 560, 560, "1. Additionner", c1),
+ card(665, 190, 560, 560, "2. Soustraire", c2, False),
+ card(1255, 190, 270, 560, "3. Regle", c3),
+ ])
+
+
+def svg_08() -> str:
+ c1 = "".join(
+ fraction(45, y, n, d) + text(145, y + 22, f"de {q} =", "op") + line(285, y + 22, 440, y + 22)
+ for y, (n, d, q) in zip([135, 285, 435], [(1, 2, 18), (1, 3, 24), (1, 5, 40)])
+ )
+ c2 = "".join(
+ fraction(45, y, n, d) + text(145, y + 22, f"de {q} =", "op") + line(285, y + 22, 440, y + 22)
+ for y, (n, d, q) in zip([135, 285, 435], [(3, 4, 20), (2, 5, 30), (3, 6, 42)])
+ )
+ c3 = (
+ text(45, 130, "1. Je partage par le bas.", "body")
+ + text(45, 210, "2. Je prends le haut.", "body")
+ + text(45, 310, "Exemple :", "body")
+ + fraction(45, 390, 3, 4)
+ + text(145, 412, "de 20", "op")
+ )
+ return sheet("Exercices - Fraction d'une quantite", [
+ card(80, 190, 490, 560, "1. Une part", c1),
+ card(610, 190, 490, 560, "2. Plusieurs parts", c2, False),
+ card(1140, 190, 370, 560, "3. Methode", c3),
+ ])
+
+
+SVG_BY_DIR = {
+ "01_lire_ecrire_fraction_simple": svg_01,
+ "02_representer_fraction_partage": svg_02,
+ "03_fraction_sur_demi_droite_graduee": svg_03,
+ "04_fraction_superieure_a_un": svg_04,
+ "05_comparer_fractions_simples": svg_05,
+ "06_encadrer_fraction_entre_entiers": svg_06,
+ "07_additionner_soustraire_fractions_simples": svg_07,
+ "08_fraction_d_une_quantite": svg_08,
+}
+
+
+def main() -> None:
+ for root in TARGET_ROOTS:
+ for folder, builder in SVG_BY_DIR.items():
+ target = root / folder / "exercices.svg"
+ target.parent.mkdir(parents=True, exist_ok=True)
+ target.write_text(builder(), encoding="utf-8")
+ print(f"updated {target}")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/frontend/src/styles.css b/frontend/src/styles.css
index 1bb090a..b618866 100644
--- a/frontend/src/styles.css
+++ b/frontend/src/styles.css
@@ -339,21 +339,26 @@ button:disabled { opacity: 0.5; cursor: not-allowed; }
.validation-main-preview {
min-height: 0;
flex: 1;
- display: grid;
- place-items: center;
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ gap: 1rem;
border: 1px solid #e2e8f0;
border-radius: 16px;
background: #f8fafc;
- overflow: hidden;
+ overflow: auto;
padding: 1rem;
}
.validation-main-preview img {
width: 100%;
- height: 100%;
- max-height: calc(100vh - 310px);
+ height: auto;
+ max-height: min(58vh, 620px);
object-fit: contain;
display: block;
+ flex: 0 0 auto;
+ border-radius: 10px;
+ background: white;
}
.empty-preview {
@@ -796,6 +801,14 @@ button:disabled { opacity: 0.5; cursor: not-allowed; }
background: white;
padding: 1rem;
}
+
+.validation-main-preview .validation-text-preview {
+ width: min(100%, 980px);
+ min-height: 220px;
+ max-height: 32vh;
+ align-self: center;
+ flex: 0 0 auto;
+}
.program-node-text-preview pre,
.validation-text-preview {
margin: 0;