diff --git a/SKILL_sliding_design_system.md b/SKILL_sliding_design_system.md new file mode 100644 index 0000000..662007c --- /dev/null +++ b/SKILL_sliding_design_system.md @@ -0,0 +1,469 @@ +# SKILL — Sliding Design System (Pernod Ricard) + +Ce skill décrit le **design system « PR Editorial »** et le format de données +que consomme le moteur de rendu `render_engine_v2.py` pour produire des +présentations PowerPoint au format Pernod Ricard. + +**Périmètre de ce skill : design et production uniquement.** Il ne traite pas +de la structuration narrative, de la rédaction ou de la rhétorique. Il répond +à une seule question : *comment produire un fichier YAML valide qui, passé au +moteur, génère un PPTX conforme à la charte Pernod Ricard.* + +--- + +## 1. Principe de fonctionnement + +Le moteur prend en entrée un fichier **YAML** décrivant une liste de slides. +Chaque slide déclare un `layout` (parmi 21) et les champs de contenu de ce +layout. Le moteur applique automatiquement la charte (couleurs, polices, +grille, centrage vertical). Tu n'as jamais à spécifier de couleur, de police +ou de position en mode standard : tu fournis le contenu, le moteur compose. + +Commande de rendu : +```bash +python3 render_engine_v2.py presentation.yaml sortie.pptx \ + --theme theme_v2.yaml --components components_v2.yaml --layouts layouts_v2.yaml +``` + +Structure générale du YAML : +```yaml +slides: + - layout: cover_split + titre: "..." + - layout: kpi_grid + titre: "..." + items: [...] +``` + +--- + +## 2. La charte (appliquée automatiquement) + +Tu n'écris jamais ces valeurs en mode standard ; elles sont là pour information. + +**Couleurs** +| Token | Hex | Usage | +|---|---|---| +| navy | `#061033` | dominant — fonds sombres, titres | +| navy_light | `#10204D` | cercles décoratifs sur fond sombre | +| coral | `#F4795B` | accent UNIQUE — chiffres, badges, lignes | +| glacier | `#8FA9D0` | sous-titres sur fond sombre, 3e couleur | +| slate | `#46505A` | 2e couleur de cycle | +| card | `#F4F1EC` | fond des cartes (gris chaud) | +| card_alt | `#EAF0F8` | variante froide | +| body | `#2B3440` | texte courant sur fond clair | +| muted | `#8A93A0` | légendes, sources | + +**Polices** : Cambria (titres, chiffres) / Calibri (corps). +**Format slide** : 33,87 × 19,05 cm (16:9). +**Règle d'accent** : le corail est rare. Un seul élément corail dominant par slide ; le navy domine. +**Rythme sandwich** : ouverture, transitions et clôture sur fond sombre (navy) ; contenu sur fond clair. + +--- + +## 3. Les 21 layouts standards + +Chaque layout liste ses champs **requis** (obligatoires) et **optionnels**. +`titre` doit être une formulation affirmative (le message du slide), pas un label. + +### Ouverture / Clôture / Structure + +**cover_split** — couverture (fond sombre) +Requis : `titre` · Optionnel : `sous_titre` +```yaml +- layout: cover_split + titre: "Titre de la présentation" + sous_titre: "Tagline en une phrase" +``` + +**section_divider** — transition de section (fond sombre, numéro auto) +Requis : `titre` +```yaml +- layout: section_divider + titre: "Nom de la section" +``` + +**end_slide** — clôture (fond sombre) +Requis : `message` +```yaml +- layout: end_slide + message: "Phrase de conclusion" +``` + +### Synthèse / Message + +**executive_summary** — synthèse situation/complication/résolution +Requis : `titre, situation, complication, resolution` +```yaml +- layout: executive_summary + titre: "Le So What en une phrase affirmative" + situation: "État des lieux factuel" + complication: "Le problème ou la tension" + resolution: "La réponse proposée" +``` + +**key_message** — citation/message fort (fond sombre) +Requis : `message` · Optionnel : `detail` +```yaml +- layout: key_message + message: "Le message clé en une phrase forte." + detail: "Sous-texte optionnel." +``` + +### Données + +**big_stat** — un chiffre héro plein écran +Requis : `titre, valeur` · Optionnel : `description, source` +```yaml +- layout: big_stat + titre: "Titre affirmatif" + valeur: "78%" + description: "ce que le chiffre signifie" + source: "Référence — 2026" +``` + +**kpi_grid** — 2 à 6 cartes KPI +Requis : `titre, items` +```yaml +- layout: kpi_grid + titre: "Titre affirmatif" + items: + - label: "Indicateur 1" + valeur: "+13%" + description: "Source ou contexte" + - label: "Indicateur 2" + valeur: "85%" + description: "Source ou contexte" +``` +Note : `valeur` est une chaîne. Les valeurs courtes (≤6 car.) s'affichent en +très grand, les valeurs longues sont réduites automatiquement. + +### Comparaison + +**two_cols_text** — deux colonnes en cartes (gauche navy, droite corail) +Requis : `titre, left, right` +```yaml +- layout: two_cols_text + titre: "Titre affirmatif" + left: + titre: "Titre colonne gauche" + bullets: + - texte: "Premier point" + - texte: "Deuxième point" + right: + titre: "Titre colonne droite" + bullets: + - texte: "Premier point" +``` + +**comparison_table** — tableau comparatif multi-critères +Requis : `titre, headers, rows` (max ~5 colonnes, 8 lignes) +```yaml +- layout: comparison_table + titre: "Titre affirmatif" + headers: ["Critère", "Option A", "Option B"] + rows: + - label: "Premier critère" + values: ["Valeur A", "Valeur B"] + - label: "Deuxième critère" + values: ["Valeur A", "Valeur B"] +``` + +**from_to_pairs** — transformation avant/après +Requis : `titre, pairs` · Optionnel : `label_from, label_to` (max 5 paires) +```yaml +- layout: from_to_pairs + titre: "Titre affirmatif" + label_from: "SITUATION ACTUELLE" + label_to: "SITUATION CIBLE" + pairs: + - from: "État de départ" + to: "État cible" + - from: "Autre point" + to: "Autre cible" +``` + +### Concept / Texte + +**circular_diagram** — 3 à 6 cercles + légende +Requis : `titre, segments` +```yaml +- layout: circular_diagram + titre: "Titre affirmatif" + segments: + - label: "Concept 1" + description: "Description courte" + - label: "Concept 2" + description: "Description courte" + - label: "Concept 3" + description: "Description courte" +``` + +**default_bullets** — liste de points (max 5) +Requis : `titre, bullets` +Le format « Mot-clé : explication » met le mot-clé en gras navy. +```yaml +- layout: default_bullets + titre: "Titre affirmatif" + bullets: + - texte: "Mot-clé : explication du point" + niveau: 1 + - texte: "Autre mot-clé : explication" + niveau: 1 +``` + +### Process / Planning + +**numbered_steps** — étapes en cartes avec badge numéroté (2 à 5) +Requis : `titre, steps` +```yaml +- layout: numbered_steps + titre: "Titre affirmatif" + steps: + - numero: 1 + titre: "Première étape" + description: "Ce que ça implique" + - numero: 2 + titre: "Deuxième étape" + description: "Ce que ça implique" +``` + +**process_arrow** — flux horizontal de 3 à 6 étapes (sans dates) +Requis : `titre, steps` +```yaml +- layout: process_arrow + titre: "Titre affirmatif" + steps: + - titre: "Étape 1" + description: "Ce qui se passe" + - titre: "Étape 2" + description: "Ce qui se passe" + - titre: "Étape 3" + description: "Ce qui se passe" +``` + +**phases_timeline** — phases avec périodes +Requis : `titre, phases` +```yaml +- layout: phases_timeline + titre: "Titre affirmatif" + phases: + - label: "Mois 1-2" + periode: "Ce qui se passe" + - label: "Mois 3-8" + periode: "Ce qui se passe" +``` + +**gantt_timeline** — Gantt par workstreams +Requis : `titre, periods, workstreams` (max 3 workstreams, 4 tâches chacun) +`start`/`end` = index dans `periods` (0-based). +```yaml +- layout: gantt_timeline + titre: "Titre affirmatif" + periods: ["Juin", "Juil", "Août", "Sept"] + workstreams: + - label: "Workstream 1" + tasks: + - label: "Tâche A" + start: 0 + end: 2 + - label: "Workstream 2" + tasks: + - label: "Tâche B" + start: 1 + end: 3 +``` + +**yearly_timeline** — frise chronologique +Requis : `titre, milestones` (max 6, `actif: true` met le jalon en corail) +```yaml +- layout: yearly_timeline + titre: "Titre affirmatif" + milestones: + - annee: "2024" + label: "Premier jalon" + - annee: "2025" + label: "Deuxième jalon" + - annee: "2026" + label: "Jalon courant" + actif: true +``` + +### Gouvernance / Organisation / Décision + +**raci_table** — matrice RACI +Requis : `titre, roles, tasks` (max 4 rôles, 8 tâches) +Lettres : R (Responsable, corail), A (Autorité, navy), C (Consulté, slate), I (Informé, muted). +```yaml +- layout: raci_table + titre: "Titre affirmatif" + roles: ["Rôle 1", "Rôle 2", "Rôle 3"] + tasks: + - label: "Première activité" + raci: ["A", "R", "C"] + - label: "Deuxième activité" + raci: ["A", "I", "R"] +``` + +**org_chart** — organigramme (max 3 niveaux) +Requis : `titre, root` +Les `children` peuvent être des objets `{label, children}` OU de simples +chaînes. Max 4 enfants directs, 3 petits-enfants par enfant (au-delà, ça serre). +```yaml +- layout: org_chart + titre: "Titre affirmatif" + root: + label: "Responsable racine" + children: + - label: "Manager 1" + children: + - "Équipe A" + - "Équipe B" + - label: "Manager 2" + children: + - "Équipe C" +``` + +**matrix_2x2** — matrice effort/impact +Requis : `titre, items` · Optionnel : `axis_x, axis_y, quadrants` (max 8 items) +`x` et `y` vont de 0 à 100. +```yaml +- layout: matrix_2x2 + titre: "Titre affirmatif" + axis_x: + label: "Effort" + low: "Faible" + high: "Élevé" + axis_y: + label: "Impact" + low: "Faible" + high: "Élevé" + quadrants: + top_left: "Gains rapides" + top_right: "Projets stratégiques" + bottom_left: "Déprioritiser" + bottom_right: "À planifier" + items: + - label: "Initiative A" + x: 30 + y: 80 + - label: "Initiative B" + x: 70 + y: 75 +``` + +**recommendation_card** — carte de recommandation (sidebar navy) +Requis : `titre, headline, bullets` · Optionnel : `numero, cta` +```yaml +- layout: recommendation_card + numero: 1 + titre: "Nom court de la recommandation" + headline: "TROIS DÉCISIONS À PRENDRE MAINTENANT" + cta: "Décider en réunion du 30 juin" + bullets: + - texte: "Première décision précise" + - texte: "Deuxième décision précise" +``` + +--- + +## 4. Le flux libre (freeform) — composition sur mesure + +Pour les slides qui ne rentrent dans aucun layout standard, utilise +`layout: freeform`. La slide est composée de **blocs positionnés sur une +grille 12 × 12** (colonnes 0-12, lignes 0-12). La charte reste **imposée** : +les couleurs ne peuvent être que des tokens nommés (jamais de hex). + +Règles de la grille : +- `col` (0-12) = colonne de départ, `row` (0-12) = ligne de départ +- `w` = largeur en colonnes, `h` = hauteur en lignes +- Contraintes : `col + w ≤ 12` et `row + h ≤ 12` +- Maximum 8 blocs par slide +- `mode: light` (fond blanc) ou `mode: dark` (fond navy) +- `footer: false` pour masquer le pied de page (affiché par défaut, même sur fond sombre) + +Note : `freeform` est géré directement par le moteur de rendu et ne figure pas +dans `layouts_v2.yaml`. Un validateur basé sur ce fichier peut donc le signaler +comme « layout inconnu » — c'est sans effet, le rendu fonctionne normalement. + +Types de blocs disponibles : +| type | description | champs spécifiques | +|---|---|---| +| `title` / `heading` | titre serif | `size` (déf. 28), `align`, `color` | +| `text` | texte courant (Calibri) | `size`, `bold`, `italic`, `serif`, `align`, `color` | +| `stat` | grand chiffre serif corail | `size` (déf. 72), `align`, `color` | +| `circle` | cercle plein (motif charte) | `color` (diamètre = min(w,h)) | +| `badge` | cercle numéroté, texte blanc centré | `text`, `color` | +| `card` | carte arrondie avec ombre | `color` (déf. card) | +| `rect` | rectangle plein | `color`, `rounded` | +| `line` | ligne / séparateur | `color`, `weight` (h:0 = horizontale) | + +Tokens couleur autorisés : `navy, navy_light, coral, glacier, slate, card, +white, body, muted`. Aucun hex. + +Exemple — slide manifeste (fond sombre, grand chiffre + titre + accent) : +```yaml +- layout: freeform + mode: dark + blocks: + - type: stat + text: "3" + col: 0.5 + row: 1 + w: 3 + h: 4 + size: 150 + color: coral + align: center + - type: title + text: "trois convictions structurantes" + col: 4 + row: 1.5 + w: 7.5 + h: 3 + size: 30 + color: white + - type: line + col: 4 + row: 4.5 + w: 7 + h: 0 + color: coral + weight: 2 + - type: text + text: "Le sous-texte en glacier, italique." + col: 4 + row: 5 + w: 7.5 + h: 2 + size: 18 + italic: true + color: glacier +``` + +--- + +## 5. Règles de production (à respecter pour un YAML valide) + +1. **Layouts** : utiliser uniquement les 21 noms listés (+ `freeform`). +2. **Champs requis** : chaque layout doit avoir tous ses champs requis, non vides. +3. **Chaînes** : toujours entre guillemets. Échapper les guillemets internes. +4. **Chiffres de contenu** (`valeur`, `stat`) : toujours des chaînes (`"78%"`). +5. **Entiers de structure** (`numero`, `niveau`, `start`, `end`, `x`, `y`) : sans guillemets. +6. **`titre`** : formulation affirmative (le message), jamais un label thématique. +7. **Pas de syntaxe Markdown** dans les valeurs : pas de `**gras**`, pas de `#`. + Le formatage est géré par le moteur, pas par le texte. +8. **Champ optionnel absent** : l'omettre (ne pas mettre `null`). +9. **Freeform** : respecter `col+w ≤ 12`, `row+h ≤ 12`, max 8 blocs, tokens charte uniquement. +10. **Densité** : respecter les maxima par layout (ex. kpi_grid ≤ 6, bullets ≤ 5, + org_chart ≤ 4 branches). Au-delà, le rendu se dégrade. + +--- + +## 6. Sortie attendue + +Quand on te demande de produire une présentation au format Pernod Ricard, +tu produis **uniquement le YAML** décrit ci-dessus — rien d'autre. Ce YAML +est destiné à être passé tel quel à `render_engine_v2.py`. Pas de texte +d'introduction, pas de commentaire, pas de Markdown autour : le YAML brut, +directement exploitable. diff --git a/build_gallery.py b/build_gallery.py new file mode 100644 index 0000000..17bb738 --- /dev/null +++ b/build_gallery.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +build_gallery.py — Génère la galerie HTML du design system v2 +depuis layouts_v2.yaml. Relancer après tout ajout de layout. +Usage : python3 build_gallery.py → produit index.html +""" +import yaml +from pathlib import Path +from datetime import datetime + +LAYOUTS = yaml.safe_load(open("layouts_v2.yaml", encoding="utf-8"))["layouts"] +THEME = yaml.safe_load(open("theme_v2.yaml", encoding="utf-8")) + +C = THEME["colors"] +NAVY = C["primary"]["navy"] +NAVY2 = C["primary"]["navy_light"] +CORAL = C["accent"]["coral"] +GLACIER = C["secondary"]["glacier"] +SLATE = C["secondary"]["slate"] +CARD = C["backgrounds"]["card"] + +# Familles regroupées dans l'ordre d'apparition +families = {} +for name, cfg in LAYOUTS.items(): + fam = cfg.get("famille", "Autres") + families.setdefault(fam, []).append((name, cfg)) + +n_layouts = len(LAYOUTS) +n_families = len(families) + +def card(name, cfg): + lid = cfg.get("id", "") + mode = cfg.get("mode", "light") + hint = " ".join(cfg.get("agent_hint", "").split()) + champs = ", ".join(cfg.get("champs", [])) + requis = ", ".join(cfg.get("champs_requis", [])) + mode_badge = { + "light": ("Clair", "#f4f1ec", NAVY), + "dark": ("Sombre", NAVY, "#ffffff"), + "panel": ("Panel", GLACIER, NAVY), + }.get(mode, ("Clair", "#f4f1ec", NAVY)) + return f""" +
{hint}
+{champs}{requis}Catalogue des layouts disponibles dans le pipeline de génération automatique de présentations. Design system « PR Editorial » : navy dominant, accent corail, grille fixe et centrage vertical systématique.
+ +Catalogue des layouts disponibles dans le pipeline de génération automatique de présentations. Design system « PR Editorial » : navy dominant, accent corail, grille fixe et centrage vertical systématique.
+ +Slide de couverture. titre = titre de la présentation, sous_titre = tagline en une phrase.
+titre, sous_titretitreSynthèse SCR. Titre = So What. 3 cartes pleine largeur : situation, complication, resolution (1-2 phrases chacune).
+titre, situation, complication, resolutiontitre, situation, complication, resolutionTransition de section. titre = nom de la section. Le numéro est incrémenté automatiquement par le moteur.
+titretitreSommaire du deck : à placer en slide 2 pour toute présentation de plus de 15 minutes. sections = liste de {label, numero?, duree?, actif?}, 2 à 8 entrées. actif: true met la section en corail (utile pour les rappels d'agenda en cours de deck). duree (ex "10 min") s'affiche à droite en discret.
+titre, sectionstitre, sectionsUn chiffre héro plein écran. valeur = le chiffre (ex "78%"), description = ce qu'il signifie, source = référence.
+titre, valeur, description, sourcetitre, valeur2 à 6 cartes KPI. items = [{label, valeur, description}]. valeur en grand corail, label en en-tête, description en source.
+titre, itemstitre, itemsComparaison de valeurs par catégories — graphique NATIF éditable. Max 8 catégories × 3 séries. series = liste de {label, values} ; values = nombres SANS guillemets, alignés sur categories. horizontal: true pour des barres (libellés longs). unite (ex M€) et source optionnels. Couleurs imposées : navy, coral, glacier.
+titre, categories, series, unite, source, horizontaltitre, categories, seriesÉvolution temporelle — graphique NATIF éditable. Max 12 points × 3 séries. points_x = libellés d'axe (mois, années...) ; series = {label, values}, nombres sans guillemets. Le dernier point de la première série est automatiquement mis en valeur (corail).
+titre, points_x, series, unite, sourcetitre, points_x, seriesRépartition d'un tout : anneau à gauche + légende détaillée à droite. 2 à 6 segments = {label, valeur} (nombres sans guillemets). valeur_centrale (optionnelle) s'affiche au centre de l'anneau (ex : total « 120 M€ »). Couleurs = cycle PR imposé.
+titre, segments, valeur_centrale, sourcetitre, segmentsPont de valeur (waterfall) : expliquer un écart entre deux montants par des variations successives. depart et arrivee = {label, valeur} ; marches = liste de {label, delta} SIGNÉ (positif ou négatif, max 8). Le moteur calcule les cumuls — ne jamais fournir de cumul. Idéal pour : évolution de budget, pont d'effectifs, décomposition d'un résultat.
+titre, depart, marches, arrivee, unite, sourcetitre, depart, marches, arriveeDeux colonnes en cartes avec en-tête coloré. left/right = {titre, bullets[]}. Gauche = navy, droite = corail.
+titre, left, righttitre, left, rightTableau structuré multi-critères. headers = liste de colonnes (1ère = critères). rows = [{label, values: []}] ou listes plates. Max 5 colonnes, 8 lignes.
+titre, headers, rowstitre, headers, rowsTableau à intensité : évaluer plusieurs items sur plusieurs critères. headers = colonnes (max 6) ; rows = {label, scores} avec score ENTIER de 0 (faible) à 4 (fort), max 8 lignes. Le moteur traduit chaque score en teinte de navy — aucune autre donnée. Idéal pour : maturité, couverture fonctionnelle, cartographie de risques.
+titre, headers, rows, legendetitre, headers, rowsMessage clé en citation plein écran. message = la phrase forte, detail = sous-texte optionnel.
+message, detailmessage3 à 6 valeurs en cercles + légende à droite. segments = [{label, description, couleur?}].
+titre, segmentstitre, segmentsArgumentation pyramidale : la conclusion au sommet, les fondations à la base. niveaux = liste de {label, description?}, EXACTEMENT 3 ou 4 niveaux, du sommet vers la base. Largeurs d'étages fixes gérées par le moteur. Idéal pour : message clé et ses appuis, hiérarchie stratégie/tactiques/moyens.
+titre, niveauxtitre, niveauxListe de points clés. Si texte au format "Mot : explication", le moteur met le mot en gras navy. Max 5 bullets. bullets = [{niveau, texte}].
+titre, bulletstitre, bulletsÉtapes en cartes pleine largeur avec badge rond numéroté. steps = [{numero, titre, description}].
+titre, stepstitre, stepsFlux horizontal de 3 à 6 étapes. steps = [{titre, description}]. Badges numérotés corail, couleurs cycle alternées. Max 6 étapes.
+titre, stepstitre, stepsEntonnoir de conversion : volumes décroissants d'étape en étape. etapes = {label, valeur, description?} du haut vers le bas, 3 à 5 étages. Largeurs proportionnelles aux valeurs (plancher de lisibilité), dernier étage corail. Idéal pour : pipeline commercial, adoption, qualification progressive.
+titre, etapes, sourcetitre, etapesPhases reliées par une ligne pointillée. phases = [{label, periode}]. Couleurs du cycle theme.
+titre, phasestitre, phasesGantt par workstreams. periods = liste de labels (ex ["Juin","Juil"]). workstreams = [{label, tasks: [{label, start, end}]}]. start/end = index dans periods (0-based). Max 3 workstreams, 4 tâches chacun.
+titre, periods, workstreamstitre, periods, workstreamsCarte de recommandation. Sidebar = numero + titre + cta. Corps = headline + bullets.
+numero, titre, cta, headline, bulletstitre, headline, bulletsSlide de fin. message = phrase de conclusion.
+messagemessageTransformation avant/après en paires alignées. pairs = [{from, to}]. label_from/label_to = en-têtes colonnes. Max 5 paires. Idéal pour tangibiliser un changement.
+titre, pairs, label_from, label_totitre, pairsFrise chronologique horizontale. milestones = [{annee, label, actif?}]. actif = true pour le jalon courant (corail). Labels alternent haut/bas. Max 6 jalons.
+titre, milestonestitre, milestonesMatrice RACI. roles = liste de rôles. tasks = [{label, raci: [R/A/C/I]}]. R=Responsable(corail), A=Autorité(navy), C=Consulté(slate), I=Informé(muted). Max 4 rôles, 8 tâches.
+titre, roles, taskstitre, roles, tasksOrganigramme hiérarchique max 3 niveaux. root = {label, children: [{label, children?: [{label}]}]}. Max 4 enfants directs, 3 petits-enfants par enfant.
+titre, roottitre, rootMatrice effort/impact. axis_x/axis_y = {label, low, high}. quadrants = {top_left, top_right, bottom_left, bottom_right}. items = [{label, x, y}] avec x/y de 0 à 100. Max 8 items.
+titre, axis_x, axis_y, quadrants, itemstitre, itemsImage d'appui sur 40 % de la slide (side: left par défaut, right possible) + titre et points clés (max 4 bullets). À utiliser quand une image du dossier assets/ du projet illustre le propos ; image = nom de fichier exact tel que listé par /lire. legende (optionnelle) s'affiche sur un bandeau navy sous l'image.
+titre, image, bullets, side, legendetitre, image, bulletsOuverture de chapitre visuelle : image plein cadre + voile navy + titre display blanc. Alternative à section_divider quand un asset du projet s'y prête. image = nom de fichier exact de assets/.
+titre, image, sous_titretitre, image