chore: outils preview, mesure, design system et Dockerfile
This commit is contained in:
@@ -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.
|
||||||
@@ -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"""
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">{lid}</span>
|
||||||
|
<span class="lmode" style="background:{mode_badge[1]};color:{mode_badge[2]}">{mode_badge[0]}</span>
|
||||||
|
</div>
|
||||||
|
<h3>{name}</h3>
|
||||||
|
<p class="hint">{hint}</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>{champs}</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">{requis}</code></div>
|
||||||
|
</div>
|
||||||
|
</div>"""
|
||||||
|
|
||||||
|
sections = ""
|
||||||
|
for fam, items in families.items():
|
||||||
|
cards = "\n".join(card(n, c) for n, c in items)
|
||||||
|
sections += f"""
|
||||||
|
<section class="family">
|
||||||
|
<div class="fh">
|
||||||
|
<div>
|
||||||
|
<div class="se">{len(items)} layout{'s' if len(items)>1 else ''}</div>
|
||||||
|
<h2 class="st">{fam}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lg">{cards}</div>
|
||||||
|
</section>"""
|
||||||
|
|
||||||
|
palette = "".join(
|
||||||
|
f'<div class="cc"><div class="cs" style="background:{hexv}"></div>'
|
||||||
|
f'<div class="cm"><div class="cn">{label}</div>'
|
||||||
|
f'<div class="chx">{hexv}</div></div></div>'
|
||||||
|
for label, hexv in [
|
||||||
|
("Navy", NAVY), ("Navy light", NAVY2), ("Coral", CORAL),
|
||||||
|
("Glacier", GLACIER), ("Slate", SLATE), ("Card", CARD)])
|
||||||
|
|
||||||
|
html = f"""<!DOCTYPE html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<title>Sliding Design System v2 — Pernod Ricard</title>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Cambria&family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
:root{{--navy:{NAVY};--navy2:{NAVY2};--coral:{CORAL};--glacier:{GLACIER};--slate:{SLATE};--card:{CARD};--bg:#faf8f4;--bo:#e8e2d6;--t1:#1a1a1a;--t2:#6b6b6b;--t3:#9a9a9a}}
|
||||||
|
*{{margin:0;padding:0;box-sizing:border-box}}
|
||||||
|
body{{font-family:Inter,sans-serif;background:var(--bg);color:var(--t1);font-weight:300;-webkit-font-smoothing:antialiased}}
|
||||||
|
header{{background:var(--navy);color:#fff;padding:80px 60px 60px;position:relative;overflow:hidden}}
|
||||||
|
header::after{{content:"";position:absolute;right:-80px;top:-80px;width:340px;height:340px;border-radius:50%;background:var(--navy2);opacity:.5}}
|
||||||
|
header::before{{content:"";position:absolute;right:120px;bottom:-60px;width:160px;height:160px;border-radius:50%;background:var(--coral);opacity:.85}}
|
||||||
|
.eyebrow{{font-size:11px;letter-spacing:.3em;text-transform:uppercase;color:var(--glacier);margin-bottom:24px;font-weight:500;position:relative;z-index:2}}
|
||||||
|
h1{{font-family:Cambria,serif;font-size:60px;font-weight:700;line-height:1.05;letter-spacing:-.02em;margin-bottom:24px;position:relative;z-index:2}}
|
||||||
|
.lead{{font-size:17px;line-height:1.6;color:rgba(255,255,255,.75);max-width:680px;position:relative;z-index:2}}
|
||||||
|
.hmeta{{display:flex;gap:60px;margin-top:50px;padding-top:30px;border-top:1px solid rgba(255,255,255,.15);position:relative;z-index:2}}
|
||||||
|
.mi{{display:flex;flex-direction:column;gap:4px}}
|
||||||
|
.ml{{font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--glacier)}}
|
||||||
|
.mv{{font-family:Cambria,serif;font-size:28px;font-weight:700}}
|
||||||
|
.charte{{padding:70px 60px;background:#fff;border-bottom:1px solid var(--bo)}}
|
||||||
|
.se{{font-size:11px;letter-spacing:.3em;text-transform:uppercase;color:var(--coral);font-weight:600;margin-bottom:14px}}
|
||||||
|
.st{{font-family:Cambria,serif;font-size:40px;font-weight:700;line-height:1.1;color:var(--navy);margin-bottom:30px}}
|
||||||
|
.cr{{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px;max-width:900px}}
|
||||||
|
.cc{{border-radius:8px;overflow:hidden;border:1px solid var(--bo)}}
|
||||||
|
.cs{{height:60px}}
|
||||||
|
.cm{{padding:8px 12px;background:#fff}}
|
||||||
|
.cn{{font-size:12px;font-weight:500}}
|
||||||
|
.chx{{font-size:10px;color:var(--t3);font-family:monospace;margin-top:2px}}
|
||||||
|
.family{{padding:60px}}
|
||||||
|
.family:nth-child(even){{background:#fff}}
|
||||||
|
.fh{{margin-bottom:36px}}
|
||||||
|
.lg{{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:24px}}
|
||||||
|
.lc{{background:#fff;border:1px solid var(--bo);border-radius:10px;padding:24px;transition:all .25s;display:flex;flex-direction:column;box-shadow:0 1px 3px rgba(6,16,51,.04)}}
|
||||||
|
.lc:hover{{transform:translateY(-3px);box-shadow:0 12px 36px rgba(6,16,51,.10);border-color:var(--coral)}}
|
||||||
|
.lc-head{{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px}}
|
||||||
|
.lcode{{background:var(--navy);color:#fff;font-size:10px;font-weight:600;padding:3px 9px;border-radius:4px;letter-spacing:.1em;font-family:monospace}}
|
||||||
|
.lmode{{font-size:10px;font-weight:600;padding:3px 10px;border-radius:20px;letter-spacing:.05em}}
|
||||||
|
.lc h3{{font-family:Cambria,serif;font-size:23px;font-weight:700;color:var(--navy);margin-bottom:10px}}
|
||||||
|
.hint{{font-size:13.5px;line-height:1.55;color:var(--t2);margin-bottom:18px;flex:1}}
|
||||||
|
.fields{{border-top:1px solid var(--bo);padding-top:14px;display:flex;flex-direction:column;gap:8px}}
|
||||||
|
.frow{{display:flex;gap:10px;align-items:baseline}}
|
||||||
|
.flab{{font-size:9px;letter-spacing:.15em;text-transform:uppercase;color:var(--t3);min-width:48px;font-weight:600}}
|
||||||
|
.frow code{{font-size:11.5px;font-family:monospace;color:var(--slate);line-height:1.4}}
|
||||||
|
.frow code.req{{color:var(--coral)}}
|
||||||
|
footer{{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-size:13px;text-align:center}}
|
||||||
|
@media(max-width:640px){{header,.charte,.family{{padding:40px 24px}}h1{{font-size:40px}}.lg{{grid-template-columns:1fr}}}}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="eyebrow">Pernod Ricard · Data Governance</div>
|
||||||
|
<h1>Sliding Design System v2</h1>
|
||||||
|
<p class="lead">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.</p>
|
||||||
|
<div class="hmeta">
|
||||||
|
<div class="mi"><span class="ml">Layouts</span><span class="mv">{n_layouts}</span></div>
|
||||||
|
<div class="mi"><span class="ml">Familles</span><span class="mv">{n_families}</span></div>
|
||||||
|
<div class="mi"><span class="ml">Version</span><span class="mv">2.0</span></div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<section class="charte">
|
||||||
|
<div class="se">Palette</div>
|
||||||
|
<h2 class="st">Charte chromatique</h2>
|
||||||
|
<div class="cr">{palette}</div>
|
||||||
|
</section>
|
||||||
|
{sections}
|
||||||
|
<footer>
|
||||||
|
Généré automatiquement depuis layouts_v2.yaml · {datetime.now().strftime('%d/%m/%Y')} · {n_layouts} layouts
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>"""
|
||||||
|
|
||||||
|
Path("index.html").write_text(html, encoding="utf-8")
|
||||||
|
print(f"index.html généré — {n_layouts} layouts, {n_families} familles")
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# Dockerfile — conteneur sliding-preview · Chantier C2
|
||||||
|
# PPTX → PDF → PNG par slide, sur GrosseBertha (ARM64, DSM 7.3.2).
|
||||||
|
# Polices : Carlito/Caladea (métriquement compatibles Calibri/Cambria)
|
||||||
|
# installées dans l'image ; les TTF PR réelles peuvent être montées en
|
||||||
|
# volume sur /fonts (prioritaires, voir preview_inner.sh).
|
||||||
|
#
|
||||||
|
# Build (dossier docker/preview/, single-line) :
|
||||||
|
# docker build -t sliding-preview .
|
||||||
|
|
||||||
|
FROM ubuntu:24.04
|
||||||
|
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
libreoffice-impress \
|
||||||
|
poppler-utils \
|
||||||
|
fontconfig \
|
||||||
|
fonts-crosextra-carlito \
|
||||||
|
fonts-crosextra-caladea \
|
||||||
|
fonts-liberation \
|
||||||
|
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY preview_inner.sh /usr/local/bin/preview_inner.sh
|
||||||
|
RUN chmod +x /usr/local/bin/preview_inner.sh
|
||||||
|
|
||||||
|
ENTRYPOINT ["/usr/local/bin/preview_inner.sh"]
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# preview_inner.sh — exécuté DANS le conteneur sliding-preview · Chantier C2
|
||||||
|
# Usage : preview_inner.sh /work/chemin/deck.pptx [dpi]
|
||||||
|
# Produit : <dossier du pptx>/<nom>_previews/slide-NN.png + index.html
|
||||||
|
set -e
|
||||||
|
|
||||||
|
PPTX="$1"
|
||||||
|
DPI="${2:-110}"
|
||||||
|
|
||||||
|
if [ -z "$PPTX" ] || [ ! -f "$PPTX" ]; then
|
||||||
|
echo "preview_inner: fichier introuvable: $PPTX" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Polices PR réelles montées en volume (prioritaires sur Carlito/Caladea)
|
||||||
|
if [ -d /fonts ]; then
|
||||||
|
mkdir -p /usr/local/share/fonts/custom
|
||||||
|
cp -f /fonts/*.ttf /fonts/*.TTF /fonts/*.otf \
|
||||||
|
/usr/local/share/fonts/custom/ 2>/dev/null || true
|
||||||
|
fc-cache -f >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
BASE=$(basename "$PPTX" .pptx)
|
||||||
|
DIR=$(dirname "$PPTX")
|
||||||
|
OUT="$DIR/${BASE}_previews"
|
||||||
|
TMP=/tmp/lo
|
||||||
|
mkdir -p "$OUT" "$TMP"
|
||||||
|
rm -f "$OUT"/slide-*.png "$OUT/index.html"
|
||||||
|
|
||||||
|
# 1. PPTX → PDF (profil LibreOffice jetable : pas de lock, RAM contenue)
|
||||||
|
echo "preview_inner: conversion PDF ($BASE)..."
|
||||||
|
soffice --headless --norestore \
|
||||||
|
-env:UserInstallation=file:///tmp/louser \
|
||||||
|
--convert-to pdf --outdir "$TMP" "$PPTX" >/dev/null
|
||||||
|
|
||||||
|
PDF="$TMP/$BASE.pdf"
|
||||||
|
if [ ! -f "$PDF" ]; then
|
||||||
|
echo "preview_inner: la conversion PDF a échoué." >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2. PDF → PNG par page
|
||||||
|
echo "preview_inner: rasterisation PNG (${DPI} dpi)..."
|
||||||
|
pdftoppm -png -r "$DPI" "$PDF" "$OUT/slide"
|
||||||
|
|
||||||
|
# 3. Normalisation slide-N.png → slide-0N.png (decks < 10 slides)
|
||||||
|
for f in "$OUT"/slide-?.png; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
n=$(basename "$f")
|
||||||
|
mv "$f" "$OUT/slide-0${n#slide-}"
|
||||||
|
done
|
||||||
|
|
||||||
|
# 4. Galerie index.html (consultable via File Station ou partage web)
|
||||||
|
{
|
||||||
|
printf '%s\n' '<!doctype html><html><head><meta charset="utf-8">'
|
||||||
|
printf '<title>%s</title>\n' "$BASE"
|
||||||
|
printf '%s\n' '<style>body{font-family:Calibri,Carlito,sans-serif;background:#F4F1EC;margin:20px;color:#2B3440}h1{color:#061033;font-size:22px}div.g{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:14px}figure{margin:0;background:#fff;padding:8px;border-radius:6px;box-shadow:0 1px 4px rgba(6,16,51,.15)}img{width:100%;display:block}figcaption{text-align:center;color:#46505A;font-size:13px;padding-top:6px}</style></head><body>'
|
||||||
|
printf '<h1>%s</h1><div class=g>\n' "$BASE"
|
||||||
|
for f in "$OUT"/slide-*.png; do
|
||||||
|
n=$(basename "$f")
|
||||||
|
printf '<figure><img src="%s" loading="lazy"><figcaption>%s</figcaption></figure>\n' "$n" "$n"
|
||||||
|
done
|
||||||
|
printf '%s\n' '</div></body></html>'
|
||||||
|
} > "$OUT/index.html"
|
||||||
|
|
||||||
|
rm -f "$PDF"
|
||||||
|
NB=$(ls "$OUT"/slide-*.png 2>/dev/null | wc -l | tr -d ' ')
|
||||||
|
echo "preview_inner: $NB slides -> $OUT"
|
||||||
+620
@@ -0,0 +1,620 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<title>Sliding Design System v2 — Pernod Ricard</title>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Cambria&family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
:root{--navy:#061033;--navy2:#10204D;--coral:#F4795B;--glacier:#8FA9D0;--slate:#46505A;--card:#F4F1EC;--bg:#faf8f4;--bo:#e8e2d6;--t1:#1a1a1a;--t2:#6b6b6b;--t3:#9a9a9a}
|
||||||
|
*{margin:0;padding:0;box-sizing:border-box}
|
||||||
|
body{font-family:Inter,sans-serif;background:var(--bg);color:var(--t1);font-weight:300;-webkit-font-smoothing:antialiased}
|
||||||
|
header{background:var(--navy);color:#fff;padding:80px 60px 60px;position:relative;overflow:hidden}
|
||||||
|
header::after{content:"";position:absolute;right:-80px;top:-80px;width:340px;height:340px;border-radius:50%;background:var(--navy2);opacity:.5}
|
||||||
|
header::before{content:"";position:absolute;right:120px;bottom:-60px;width:160px;height:160px;border-radius:50%;background:var(--coral);opacity:.85}
|
||||||
|
.eyebrow{font-size:11px;letter-spacing:.3em;text-transform:uppercase;color:var(--glacier);margin-bottom:24px;font-weight:500;position:relative;z-index:2}
|
||||||
|
h1{font-family:Cambria,serif;font-size:60px;font-weight:700;line-height:1.05;letter-spacing:-.02em;margin-bottom:24px;position:relative;z-index:2}
|
||||||
|
.lead{font-size:17px;line-height:1.6;color:rgba(255,255,255,.75);max-width:680px;position:relative;z-index:2}
|
||||||
|
.hmeta{display:flex;gap:60px;margin-top:50px;padding-top:30px;border-top:1px solid rgba(255,255,255,.15);position:relative;z-index:2}
|
||||||
|
.mi{display:flex;flex-direction:column;gap:4px}
|
||||||
|
.ml{font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--glacier)}
|
||||||
|
.mv{font-family:Cambria,serif;font-size:28px;font-weight:700}
|
||||||
|
.charte{padding:70px 60px;background:#fff;border-bottom:1px solid var(--bo)}
|
||||||
|
.se{font-size:11px;letter-spacing:.3em;text-transform:uppercase;color:var(--coral);font-weight:600;margin-bottom:14px}
|
||||||
|
.st{font-family:Cambria,serif;font-size:40px;font-weight:700;line-height:1.1;color:var(--navy);margin-bottom:30px}
|
||||||
|
.cr{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px;max-width:900px}
|
||||||
|
.cc{border-radius:8px;overflow:hidden;border:1px solid var(--bo)}
|
||||||
|
.cs{height:60px}
|
||||||
|
.cm{padding:8px 12px;background:#fff}
|
||||||
|
.cn{font-size:12px;font-weight:500}
|
||||||
|
.chx{font-size:10px;color:var(--t3);font-family:monospace;margin-top:2px}
|
||||||
|
.family{padding:60px}
|
||||||
|
.family:nth-child(even){background:#fff}
|
||||||
|
.fh{margin-bottom:36px}
|
||||||
|
.lg{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:24px}
|
||||||
|
.lc{background:#fff;border:1px solid var(--bo);border-radius:10px;padding:24px;transition:all .25s;display:flex;flex-direction:column;box-shadow:0 1px 3px rgba(6,16,51,.04)}
|
||||||
|
.lc:hover{transform:translateY(-3px);box-shadow:0 12px 36px rgba(6,16,51,.10);border-color:var(--coral)}
|
||||||
|
.lc-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px}
|
||||||
|
.lcode{background:var(--navy);color:#fff;font-size:10px;font-weight:600;padding:3px 9px;border-radius:4px;letter-spacing:.1em;font-family:monospace}
|
||||||
|
.lmode{font-size:10px;font-weight:600;padding:3px 10px;border-radius:20px;letter-spacing:.05em}
|
||||||
|
.lc h3{font-family:Cambria,serif;font-size:23px;font-weight:700;color:var(--navy);margin-bottom:10px}
|
||||||
|
.hint{font-size:13.5px;line-height:1.55;color:var(--t2);margin-bottom:18px;flex:1}
|
||||||
|
.fields{border-top:1px solid var(--bo);padding-top:14px;display:flex;flex-direction:column;gap:8px}
|
||||||
|
.frow{display:flex;gap:10px;align-items:baseline}
|
||||||
|
.flab{font-size:9px;letter-spacing:.15em;text-transform:uppercase;color:var(--t3);min-width:48px;font-weight:600}
|
||||||
|
.frow code{font-size:11.5px;font-family:monospace;color:var(--slate);line-height:1.4}
|
||||||
|
.frow code.req{color:var(--coral)}
|
||||||
|
footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-size:13px;text-align:center}
|
||||||
|
@media(max-width:640px){header,.charte,.family{padding:40px 24px}h1{font-size:40px}.lg{grid-template-columns:1fr}}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="eyebrow">Pernod Ricard · Data Governance</div>
|
||||||
|
<h1>Sliding Design System v2</h1>
|
||||||
|
<p class="lead">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.</p>
|
||||||
|
<div class="hmeta">
|
||||||
|
<div class="mi"><span class="ml">Layouts</span><span class="mv">31</span></div>
|
||||||
|
<div class="mi"><span class="ml">Familles</span><span class="mv">18</span></div>
|
||||||
|
<div class="mi"><span class="ml">Version</span><span class="mv">2.0</span></div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<section class="charte">
|
||||||
|
<div class="se">Palette</div>
|
||||||
|
<h2 class="st">Charte chromatique</h2>
|
||||||
|
<div class="cr"><div class="cc"><div class="cs" style="background:#061033"></div><div class="cm"><div class="cn">Navy</div><div class="chx">#061033</div></div></div><div class="cc"><div class="cs" style="background:#10204D"></div><div class="cm"><div class="cn">Navy light</div><div class="chx">#10204D</div></div></div><div class="cc"><div class="cs" style="background:#F4795B"></div><div class="cm"><div class="cn">Coral</div><div class="chx">#F4795B</div></div></div><div class="cc"><div class="cs" style="background:#8FA9D0"></div><div class="cm"><div class="cn">Glacier</div><div class="chx">#8FA9D0</div></div></div><div class="cc"><div class="cs" style="background:#46505A"></div><div class="cm"><div class="cn">Slate</div><div class="chx">#46505A</div></div></div><div class="cc"><div class="cs" style="background:#F4F1EC"></div><div class="cm"><div class="cn">Card</div><div class="chx">#F4F1EC</div></div></div></div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="family">
|
||||||
|
<div class="fh">
|
||||||
|
<div>
|
||||||
|
<div class="se">1 layout</div>
|
||||||
|
<h2 class="st">Ouverture</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lg">
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L01</span>
|
||||||
|
<span class="lmode" style="background:#061033;color:#ffffff">Sombre</span>
|
||||||
|
</div>
|
||||||
|
<h3>cover_split</h3>
|
||||||
|
<p class="hint">Slide de couverture. titre = titre de la présentation, sous_titre = tagline en une phrase.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, sous_titre</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre</code></div>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
</section>
|
||||||
|
<section class="family">
|
||||||
|
<div class="fh">
|
||||||
|
<div>
|
||||||
|
<div class="se">1 layout</div>
|
||||||
|
<h2 class="st">Synthèse</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lg">
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L05</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>executive_summary</h3>
|
||||||
|
<p class="hint">Synthèse SCR. Titre = So What. 3 cartes pleine largeur : situation, complication, resolution (1-2 phrases chacune).</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, situation, complication, resolution</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, situation, complication, resolution</code></div>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
</section>
|
||||||
|
<section class="family">
|
||||||
|
<div class="fh">
|
||||||
|
<div>
|
||||||
|
<div class="se">2 layouts</div>
|
||||||
|
<h2 class="st">Structure</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lg">
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L03</span>
|
||||||
|
<span class="lmode" style="background:#061033;color:#ffffff">Sombre</span>
|
||||||
|
</div>
|
||||||
|
<h3>section_divider</h3>
|
||||||
|
<p class="hint">Transition de section. titre = nom de la section. Le numéro est incrémenté automatiquement par le moteur.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre</code></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L40</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>agenda</h3>
|
||||||
|
<p class="hint">Sommaire 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.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, sections</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, sections</code></div>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
</section>
|
||||||
|
<section class="family">
|
||||||
|
<div class="fh">
|
||||||
|
<div>
|
||||||
|
<div class="se">6 layouts</div>
|
||||||
|
<h2 class="st">Données</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lg">
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L10</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>big_stat</h3>
|
||||||
|
<p class="hint">Un chiffre héro plein écran. valeur = le chiffre (ex "78%"), description = ce qu'il signifie, source = référence.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, valeur, description, source</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, valeur</code></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L09</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>kpi_grid</h3>
|
||||||
|
<p class="hint">2 à 6 cartes KPI. items = [{label, valeur, description}]. valeur en grand corail, label en en-tête, description en source.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, items</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, items</code></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L42</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>bar_chart</h3>
|
||||||
|
<p class="hint">Comparaison 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.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, categories, series, unite, source, horizontal</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, categories, series</code></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L43</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>line_chart</h3>
|
||||||
|
<p class="hint">É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).</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, points_x, series, unite, source</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, points_x, series</code></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L44</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>donut_split</h3>
|
||||||
|
<p class="hint">Ré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é.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, segments, valeur_centrale, source</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, segments</code></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L45</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>waterfall</h3>
|
||||||
|
<p class="hint">Pont 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.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, depart, marches, arrivee, unite, source</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, depart, marches, arrivee</code></div>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
</section>
|
||||||
|
<section class="family">
|
||||||
|
<div class="fh">
|
||||||
|
<div>
|
||||||
|
<div class="se">3 layouts</div>
|
||||||
|
<h2 class="st">Comparaison</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lg">
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L07</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>two_cols_text</h3>
|
||||||
|
<p class="hint">Deux colonnes en cartes avec en-tête coloré. left/right = {titre, bullets[]}. Gauche = navy, droite = corail.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, left, right</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, left, right</code></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L34</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>comparison_table</h3>
|
||||||
|
<p class="hint">Tableau structuré multi-critères. headers = liste de colonnes (1ère = critères). rows = [{label, values: []}] ou listes plates. Max 5 colonnes, 8 lignes.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, headers, rows</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, headers, rows</code></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L46</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>heatmap_table</h3>
|
||||||
|
<p class="hint">Tableau à 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.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, headers, rows, legende</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, headers, rows</code></div>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
</section>
|
||||||
|
<section class="family">
|
||||||
|
<div class="fh">
|
||||||
|
<div>
|
||||||
|
<div class="se">1 layout</div>
|
||||||
|
<h2 class="st">Message</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lg">
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L08</span>
|
||||||
|
<span class="lmode" style="background:#061033;color:#ffffff">Sombre</span>
|
||||||
|
</div>
|
||||||
|
<h3>key_message</h3>
|
||||||
|
<p class="hint">Message clé en citation plein écran. message = la phrase forte, detail = sous-texte optionnel.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>message, detail</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">message</code></div>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
</section>
|
||||||
|
<section class="family">
|
||||||
|
<div class="fh">
|
||||||
|
<div>
|
||||||
|
<div class="se">2 layouts</div>
|
||||||
|
<h2 class="st">Concept</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lg">
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L17</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>circular_diagram</h3>
|
||||||
|
<p class="hint">3 à 6 valeurs en cercles + légende à droite. segments = [{label, description, couleur?}].</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, segments</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, segments</code></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L41</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>pyramid</h3>
|
||||||
|
<p class="hint">Argumentation 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.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, niveaux</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, niveaux</code></div>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
</section>
|
||||||
|
<section class="family">
|
||||||
|
<div class="fh">
|
||||||
|
<div>
|
||||||
|
<div class="se">1 layout</div>
|
||||||
|
<h2 class="st">Texte structuré</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lg">
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L06</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>default_bullets</h3>
|
||||||
|
<p class="hint">Liste de points clés. Si texte au format "Mot : explication", le moteur met le mot en gras navy. Max 5 bullets. bullets = [{niveau, texte}].</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, bullets</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, bullets</code></div>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
</section>
|
||||||
|
<section class="family">
|
||||||
|
<div class="fh">
|
||||||
|
<div>
|
||||||
|
<div class="se">3 layouts</div>
|
||||||
|
<h2 class="st">Process</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lg">
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L19</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>numbered_steps</h3>
|
||||||
|
<p class="hint">Étapes en cartes pleine largeur avec badge rond numéroté. steps = [{numero, titre, description}].</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, steps</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, steps</code></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L36</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>process_arrow</h3>
|
||||||
|
<p class="hint">Flux horizontal de 3 à 6 étapes. steps = [{titre, description}]. Badges numérotés corail, couleurs cycle alternées. Max 6 étapes.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, steps</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, steps</code></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L47</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>funnel</h3>
|
||||||
|
<p class="hint">Entonnoir 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.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, etapes, source</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, etapes</code></div>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
</section>
|
||||||
|
<section class="family">
|
||||||
|
<div class="fh">
|
||||||
|
<div>
|
||||||
|
<div class="se">2 layouts</div>
|
||||||
|
<h2 class="st">Planning</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lg">
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L23</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>phases_timeline</h3>
|
||||||
|
<p class="hint">Phases reliées par une ligne pointillée. phases = [{label, periode}]. Couleurs du cycle theme.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, phases</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, phases</code></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L32</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>gantt_timeline</h3>
|
||||||
|
<p class="hint">Gantt 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.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, periods, workstreams</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, periods, workstreams</code></div>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
</section>
|
||||||
|
<section class="family">
|
||||||
|
<div class="fh">
|
||||||
|
<div>
|
||||||
|
<div class="se">1 layout</div>
|
||||||
|
<h2 class="st">Acteurs & décision</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lg">
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L28</span>
|
||||||
|
<span class="lmode" style="background:#8FA9D0;color:#061033">Panel</span>
|
||||||
|
</div>
|
||||||
|
<h3>recommendation_card</h3>
|
||||||
|
<p class="hint">Carte de recommandation. Sidebar = numero + titre + cta. Corps = headline + bullets.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>numero, titre, cta, headline, bullets</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, headline, bullets</code></div>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
</section>
|
||||||
|
<section class="family">
|
||||||
|
<div class="fh">
|
||||||
|
<div>
|
||||||
|
<div class="se">1 layout</div>
|
||||||
|
<h2 class="st">Clôture</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lg">
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L30</span>
|
||||||
|
<span class="lmode" style="background:#061033;color:#ffffff">Sombre</span>
|
||||||
|
</div>
|
||||||
|
<h3>end_slide</h3>
|
||||||
|
<p class="hint">Slide de fin. message = phrase de conclusion.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>message</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">message</code></div>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
</section>
|
||||||
|
<section class="family">
|
||||||
|
<div class="fh">
|
||||||
|
<div>
|
||||||
|
<div class="se">1 layout</div>
|
||||||
|
<h2 class="st">Transformation</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lg">
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L31</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>from_to_pairs</h3>
|
||||||
|
<p class="hint">Transformation 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.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, pairs, label_from, label_to</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, pairs</code></div>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
</section>
|
||||||
|
<section class="family">
|
||||||
|
<div class="fh">
|
||||||
|
<div>
|
||||||
|
<div class="se">1 layout</div>
|
||||||
|
<h2 class="st">Historique</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lg">
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L33</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>yearly_timeline</h3>
|
||||||
|
<p class="hint">Frise chronologique horizontale. milestones = [{annee, label, actif?}]. actif = true pour le jalon courant (corail). Labels alternent haut/bas. Max 6 jalons.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, milestones</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, milestones</code></div>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
</section>
|
||||||
|
<section class="family">
|
||||||
|
<div class="fh">
|
||||||
|
<div>
|
||||||
|
<div class="se">1 layout</div>
|
||||||
|
<h2 class="st">Gouvernance</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lg">
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L35</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>raci_table</h3>
|
||||||
|
<p class="hint">Matrice 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.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, roles, tasks</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, roles, tasks</code></div>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
</section>
|
||||||
|
<section class="family">
|
||||||
|
<div class="fh">
|
||||||
|
<div>
|
||||||
|
<div class="se">1 layout</div>
|
||||||
|
<h2 class="st">Organisation</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lg">
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L37</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>org_chart</h3>
|
||||||
|
<p class="hint">Organigramme hiérarchique max 3 niveaux. root = {label, children: [{label, children?: [{label}]}]}. Max 4 enfants directs, 3 petits-enfants par enfant.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, root</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, root</code></div>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
</section>
|
||||||
|
<section class="family">
|
||||||
|
<div class="fh">
|
||||||
|
<div>
|
||||||
|
<div class="se">1 layout</div>
|
||||||
|
<h2 class="st">Priorisation</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lg">
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L38</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>matrix_2x2</h3>
|
||||||
|
<p class="hint">Matrice 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.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, axis_x, axis_y, quadrants, items</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, items</code></div>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
</section>
|
||||||
|
<section class="family">
|
||||||
|
<div class="fh">
|
||||||
|
<div>
|
||||||
|
<div class="se">2 layouts</div>
|
||||||
|
<h2 class="st">Visuel</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lg">
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L50</span>
|
||||||
|
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||||
|
</div>
|
||||||
|
<h3>image_split</h3>
|
||||||
|
<p class="hint">Image 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.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, image, bullets, side, legende</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, image, bullets</code></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lc">
|
||||||
|
<div class="lc-head">
|
||||||
|
<span class="lcode">L51</span>
|
||||||
|
<span class="lmode" style="background:#061033;color:#ffffff">Sombre</span>
|
||||||
|
</div>
|
||||||
|
<h3>image_full</h3>
|
||||||
|
<p class="hint">Ouverture 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/.</p>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="frow"><span class="flab">Champs</span><code>titre, image, sous_titre</code></div>
|
||||||
|
<div class="frow"><span class="flab">Requis</span><code class="req">titre, image</code></div>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
</section>
|
||||||
|
<footer>
|
||||||
|
Généré automatiquement depuis layouts_v2.yaml · 09/07/2026 · 31 layouts
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
+53
@@ -0,0 +1,53 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# preview.sh — wrapper hôte GrosseBertha · Chantier C2
|
||||||
|
# Usage : ./preview.sh <chemin/vers/deck.pptx> [dpi]
|
||||||
|
# Convertit le deck en PNG par slide via le conteneur sliding-preview.
|
||||||
|
# Sortie : <dossier du pptx>/<nom>_previews/ (slide-NN.png + index.html)
|
||||||
|
#
|
||||||
|
# Prérequis : image construite (cd docker/preview && docker build -t
|
||||||
|
# sliding-preview .) et droits docker pour l'utilisateur (voir notes C2).
|
||||||
|
#
|
||||||
|
# Env optionnels :
|
||||||
|
# FONTS_DIR — dossier des TTF PR (défaut ./assets/fonts s'il existe)
|
||||||
|
# DOCKER_BIN — binaire docker (défaut docker)
|
||||||
|
# PREVIEW_MEM — limite RAM du conteneur (défaut 1200m — DS218 2 Go)
|
||||||
|
|
||||||
|
PPTX="$1"
|
||||||
|
DPI="${2:-110}"
|
||||||
|
DOCKER_BIN="${DOCKER_BIN:-docker}"
|
||||||
|
PREVIEW_MEM="${PREVIEW_MEM:-1200m}"
|
||||||
|
|
||||||
|
# Docker exige root sur ce NAS : s'auto-élever si besoin (C2)
|
||||||
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
|
exec sudo "$0" "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$PPTX" ]; then
|
||||||
|
echo "usage: preview.sh <deck.pptx> [dpi]" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ ! -f "$PPTX" ]; then
|
||||||
|
echo "preview: fichier introuvable: $PPTX" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Chemins absolus (le dossier du pptx est monté sur /work)
|
||||||
|
WORK=$(cd "$(dirname "$PPTX")" && pwd)
|
||||||
|
NAME=$(basename "$PPTX")
|
||||||
|
|
||||||
|
# Polices PR : défaut ./assets/fonts relatif au dossier de ce script
|
||||||
|
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
|
||||||
|
if [ -z "$FONTS_DIR" ] && [ -d "$SCRIPT_DIR/assets/fonts" ]; then
|
||||||
|
FONTS_DIR="$SCRIPT_DIR/assets/fonts"
|
||||||
|
fi
|
||||||
|
|
||||||
|
FONT_MOUNT=""
|
||||||
|
if [ -n "$FONTS_DIR" ] && [ -d "$FONTS_DIR" ]; then
|
||||||
|
FONT_MOUNT="-v $FONTS_DIR:/fonts:ro"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$DOCKER_BIN" run --rm \
|
||||||
|
--memory "$PREVIEW_MEM" --memory-swap "$PREVIEW_MEM" \
|
||||||
|
-v "$WORK:/work" \
|
||||||
|
$FONT_MOUNT \
|
||||||
|
sliding-preview "/work/$NAME" "$DPI"
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
# THE DESIGNER (mode annotation)
|
||||||
|
# Sliding Pipeline v3 — Pernod Ricard · Design System "PR Editorial"
|
||||||
|
# Mistral Large · Temperature 0.4 · Format : Markdown annoté
|
||||||
|
|
||||||
|
## RÔLE
|
||||||
|
|
||||||
|
Tu es The Designer. Tu reçois le Markdown narratif approuvé par Bastien et tu
|
||||||
|
le **réécris à l'identique en y ajoutant, sous chaque slide, une annotation
|
||||||
|
de layout**. Tu ne produis PAS un plan séparé : tu enrichis le Markdown lui-même.
|
||||||
|
|
||||||
|
L'objectif : Bastien voit son contenu ET la structure visuelle proposée dans une
|
||||||
|
seule vue, et peut te donner du feedback dessus (« slide 4 plutôt en big_stat »,
|
||||||
|
« regroupe 6 et 7 »). Une fois validé, ce Markdown annoté est transmis à
|
||||||
|
l'Encoder.
|
||||||
|
|
||||||
|
Tu prends des décisions éditoriales : quel layout rend ce contenu le plus
|
||||||
|
lisible ? L'enchaînement est-il fluide ? Trop de slides texte d'affilée ?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CE QUE TU REÇOIS
|
||||||
|
|
||||||
|
Un Markdown narratif :
|
||||||
|
- `#` = titre de la présentation
|
||||||
|
- `##` = sections
|
||||||
|
- `###` = slides avec leur contenu brut
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CE QUE TU PRODUIS
|
||||||
|
|
||||||
|
**Le même Markdown, repris intégralement, avec une ligne `@layout` ajoutée
|
||||||
|
juste sous chaque titre `###`** (et sous le `#` pour la couverture).
|
||||||
|
|
||||||
|
Format de l'annotation :
|
||||||
|
|
||||||
|
```
|
||||||
|
### [Titre du slide — inchangé]
|
||||||
|
@layout: nom_du_layout
|
||||||
|
@note: justification courte du choix (1 phrase)
|
||||||
|
[contenu original du slide, inchangé]
|
||||||
|
```
|
||||||
|
|
||||||
|
Pour la couverture et la clôture, annote aussi :
|
||||||
|
|
||||||
|
```
|
||||||
|
# [Titre de la présentation]
|
||||||
|
@layout: cover_split
|
||||||
|
*[sous-titre original]*
|
||||||
|
```
|
||||||
|
|
||||||
|
À la toute fin, ajoute une ligne de clôture si elle manque :
|
||||||
|
|
||||||
|
```
|
||||||
|
## Clôture
|
||||||
|
### [Message de fin]
|
||||||
|
@layout: end_slide
|
||||||
|
```
|
||||||
|
|
||||||
|
**Règles :**
|
||||||
|
- Tu NE modifies PAS le texte narratif. Tu ajoutes seulement les lignes `@layout` et `@note`.
|
||||||
|
- Tu n'inventes pas de contenu. Si une slide manque d'un champ requis par le
|
||||||
|
layout choisi, tu l'indiques dans `@note` (ex : « @note: valeur chiffrée à fournir »).
|
||||||
|
- Le premier bloc est TOUJOURS `cover_split`, le dernier `end_slide`.
|
||||||
|
- Les `##` deviennent des `section_divider` si la présentation fait plus de 6 slides.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## LES 21 LAYOUTS DISPONIBLES
|
||||||
|
|
||||||
|
[CE BLOC EST GÉNÉRÉ AUTOMATIQUEMENT PAR prompt_injection_v2.py]
|
||||||
|
[NE PAS MODIFIER MANUELLEMENT]
|
||||||
|
|
||||||
|
{{LAYOUTS_CATALOGUE}}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## RÈGLES DE SÉQUENÇAGE
|
||||||
|
|
||||||
|
[CE BLOC EST GÉNÉRÉ AUTOMATIQUEMENT PAR prompt_injection_v2.py]
|
||||||
|
[NE PAS MODIFIER MANUELLEMENT]
|
||||||
|
|
||||||
|
{{SEQUENCING_RULES}}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PATTERNS NARRATIFS
|
||||||
|
|
||||||
|
[CE BLOC EST GÉNÉRÉ AUTOMATIQUEMENT PAR prompt_injection_v2.py]
|
||||||
|
[NE PAS MODIFIER MANUELLEMENT]
|
||||||
|
|
||||||
|
{{NARRATIVE_PATTERNS}}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## GESTION DU FEEDBACK
|
||||||
|
|
||||||
|
Quand Bastien te donne du feedback sur le Markdown annoté (« slide 5 en
|
||||||
|
two_cols_text », « ajoute un big_stat après la 3 »), tu renvoies le Markdown
|
||||||
|
annoté complet mis à jour, pas seulement la partie modifiée.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## RÈGLES ABSOLUES
|
||||||
|
|
||||||
|
- Tu utilises UNIQUEMENT les 21 layouts du catalogue.
|
||||||
|
- Tu reprends le Markdown INTÉGRALEMENT — aucune perte de contenu.
|
||||||
|
- Tu ajoutes UNIQUEMENT les lignes `@layout:` et `@note:`.
|
||||||
|
- Tu ne produis ni YAML, ni plan séparé, ni JSON.
|
||||||
|
- `cover_split` en premier, `end_slide` en dernier, toujours.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## EXEMPLE
|
||||||
|
|
||||||
|
**Entrée :**
|
||||||
|
```markdown
|
||||||
|
# Le télétravail chez Pernod Ricard
|
||||||
|
*Intégrer durablement le télétravail*
|
||||||
|
|
||||||
|
## Pourquoi agir
|
||||||
|
|
||||||
|
### Le télétravail est devenu un critère de choix décisif
|
||||||
|
78% des salariés en Europe le considèrent comme non négociable. Source à valider.
|
||||||
|
|
||||||
|
### Nos concurrents ont déjà agi
|
||||||
|
Diageo et Bacardi ont lancé leurs programmes il y a 2 ans.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Sortie :**
|
||||||
|
```markdown
|
||||||
|
# Le télétravail chez Pernod Ricard
|
||||||
|
@layout: cover_split
|
||||||
|
*Intégrer durablement le télétravail*
|
||||||
|
|
||||||
|
## Pourquoi agir
|
||||||
|
|
||||||
|
### Le télétravail est devenu un critère de choix décisif
|
||||||
|
@layout: big_stat
|
||||||
|
@note: un seul chiffre fort (78%) → big_stat plutôt que bullets
|
||||||
|
78% des salariés en Europe le considèrent comme non négociable. Source à valider.
|
||||||
|
|
||||||
|
### Nos concurrents ont déjà agi
|
||||||
|
@layout: two_cols_text
|
||||||
|
@note: opposition Diageo / Bacardi → deux colonnes
|
||||||
|
Diageo et Bacardi ont lancé leurs programmes il y a 2 ans.
|
||||||
|
|
||||||
|
## Clôture
|
||||||
|
### Le télétravail, une opportunité à saisir
|
||||||
|
@layout: end_slide
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user