Compétence : Différence Visuelle
Comparez visuellement deux URLs — une baseline (ex. site de production) et une actuelle (ex. serveur de développement local ou story Storybook) — pour trouver des différences au niveau pixel et guider les corrections.
Quand l'utiliser
- Répliquer une page ou une section existante dans Storybook ou le site Astro
- Vérifier la précision visuelle d'un composant par rapport à un design de référence
- Contrôler la fidélité responsive sur différents points de rupture après des modifications de style
- Itérer sur le CSS/HTML jusqu'à ce qu'un composant corresponde à sa référence
Quand NE PAS l'utiliser
- Modifications de contenu uniquement (mises à jour de texte, corrections éditoriales) lorsque la mise en page est inchangée
- Comparer des designs provenant de Figma — utilisez plutôt la compétence Figma MCP
- Audits de performance ou d'accessibilité — utilisez Lighthouse ou l'addon a11y
Prérequis
Avant de commencer, vérifiez :
- Playwright MCP est configuré dans
.vscode/mcp.jsonavec--caps=vision - pixelmatch et pngjs sont installés : vérifiez les devDependencies dans
package.json - L'URL de la baseline est accessible (site externe ou serveur en cours d'exécution)
- L'URL actuelle est accessible (serveur de développement sur
:4321, Storybook sur:6006, etc.) - Le répertoire
temp/existe à la racine du workspace (il est ignoré par git)
Si le serveur de développement ou Storybook n'est pas en cours d'exécution, démarrez-les via les tâches VS Code :
- Serveur de développement : utilisez la tâche Serveur de développement
- Storybook : utilisez la tâche Storybook
Workflow
Étape 1 : Recevoir les entrées
L'agent a besoin de :
| Entrée | Obligatoire | Exemple |
|---|---|---|
| URL de la baseline | Oui | https://www.bitovi.com/ |
| URL actuelle | Oui | http://localhost:4321/ ou http://localhost:6006/?path=/story/card--default |
| Sélecteur CSS | Non | #hero-section ou .card-grid (pour une comparaison centrée sur un élément) |
| Points de rupture | Non | Par défaut : mobile (375×667), tablette (768×1024), desktop (1280×720) |
Étape 2 : Capturer la baseline
Comparaison centrée sur un composant (recommandée pour comparer un seul composant)
Lorsque vous comparez un composant spécifique — en particulier lorsque la story Storybook ne rend que ce composant alors que la baseline affiche une page entière autour — recadrez dans la boîte englobante du composant afin que la différence ne soit pas polluée par des sections de page non liées (barres de navigation, superpositions persistantes, autres modules au-dessus/en dessous).
Comment recadrer sur la baseline :
- Naviguez vers l'URL de la baseline
- Redimensionnez la fenêtre à
{ width: 1280, height: 720 } - Faites défiler jusqu'au composant cible :
() => document.querySelector('<selector>').scrollIntoView({ behavior: 'instant', block: 'start' }) - Mesurez la hauteur rendue du composant :
() => document.querySelector('<selector>').getBoundingClientRect().height - Redimensionnez la hauteur de la fenêtre à cette valeur exacte (gardez la largeur constante) :
mcp_playwright_browser_resize → { width: 1280, height: <hauteur mesurée> } - Prenez la capture d'écran — elle ne capture désormais que la zone du composant.
Avertissement sur les fuites d'arrière-plan : Ce qui est visible derrière le composant différera entre Storybook (vide) et la baseline (autres modules). Cas courants : barres de navigation locales/globales chevauchant le haut, modales/superpositions avec d'autres contenus visibles derrière, et composants partiellement transparents. Ces différences résiduelles se regroupent en dehors du contenu propre du composant et ne sont pas exploitables — ignorez-les.
Comment recadrer sur la story Storybook :
iframe.html de Storybook ne rend que le composant sans chrome environnant — pas de redimensionnement nécessaire. Naviguez et capturez :
mcp_playwright_browser_navigate → { url: "http://localhost:6006/iframe.html?id=<story-id>&viewMode=story" }
mcp_playwright_browser_resize → { width: 1280, height: <même hauteur que le recadrage baseline> }
mcp_playwright_browser_take_screenshot → { filename: "temp/vdiff-current-desktop.png" }
Capture plein écran fenêtré (pour comparer des pages entières)
1. mcp_playwright_browser_navigate → { url: "<url-baseline>" }
2. mcp_playwright_browser_resize → { width: 1280, height: 720 }
3. mcp_playwright_browser_wait_for → { time: 2 } # laisser la page s'afficher complètement
4. mcp_playwright_browser_take_screenshot → {
type: "png",
filename: "temp/vdiff-baseline-desktop.png"
}
Répéter pour chaque point de rupture :
| Point de rupture | Largeur | Hauteur | Suffixe du fichier |
|---|---|---|---|
| Mobile | 375 | 667 | -mobile |
| Tablette | 768 | 1024 | -tablet |
| Desktop | 1280 | 720 | -desktop |
Étape 3 : Capturer l'actuelle
Répétez exactement le même processus pour l'URL actuelle, en utilisant les noms de fichiers temp/vdiff-current-{breakpoint}.png.
Important : Utilisez les mêmes dimensions de fenêtre et la même stratégie de recadrage (centrée sur le composant ou plein écran) des deux côtés pour que la comparaison soit pertinente.
Étape 4 : Exécuter le script de différence
Pour chaque point de rupture, exécutez le script de différence visuelle dans le terminal :
node scripts/visual-diff.mjs \
--baseline temp/vdiff-baseline-desktop.png \
--current temp/vdiff-current-desktop.png \
--output temp/vdiff-diff-desktop.png
Le script renvoie du JSON sur la sortie standard :
{
"totalPixels": 921600,
"diffPixels": 4521,
"diffPercent": 0.49,
"width": 1280,
"height": 720,
"baselineDimensions": { "width": 1280, "height": 720 },
"currentDimensions": { "width": 1280, "height": 720 },
"dimensionsMismatch": false,
"diffImagePath": "/chemin/absolu/vers/temp/vdiff-diff-desktop.png"
}
Si dimensionsMismatch est vrai, les images avaient des tailles différentes. Le script complète l'image la plus petite avec des pixels transparents avant de comparer. Cela indique souvent un problème de mise en page à investiguer.
Étape 5 : Visualiser l'image de différence
Démarrez un serveur HTTP temporaire pour servir le répertoire temp/, puis naviguez avec Playwright vers l'image de différence :
# Démarrer le serveur en arrière-plan (une fois par session)
npx -y http-server temp/ -p 8787 --cors -c-1 &
Puis naviguez avec Playwright vers l'image de différence :
mcp_playwright_browser_navigate → { url: "http://localhost:8787/vdiff-diff-desktop.png" }
mcp_playwright_browser_take_screenshot → {} # déclenche la vision — l'agent peut maintenant voir la différence
Le drapeau --caps=vision sur Playwright MCP permet à l'agent de voir l'image directement dans le résultat de la capture d'écran.
Remarque : Les URLs file:// sont bloquées par Playwright MCP, donc le serveur HTTP est nécessaire. Démarrez-le une fois et réutilisez-le pour toutes les images de différence de la session.
Lecture de l'image de différence :
- Pixels rouges = différences entre la baseline et l'actuelle
- Pixels jaunes = différences d'anti-aliasing (généralement ignorables)
- Original atténué = zones qui correspondent (affichées à 30 % d'opacité pour le contexte)
- Grosses grappes rouges = problèmes structurels (éléments manquants, décalages de mise en page, mauvais dimensionnement)
- Points rouges éparpillés = rendu sub-pixel, lissage de police ou anti-aliasing (généralement acceptable)
- Bandes rouges sur les bords = décalage de dimensions ou différences de rembourrage/marge
Étape 6 : Interpréter et agir
Combinez les données JSON quantitatives avec l'inspection visuelle de la différence :
| diffPercent | Interprétation | Action |
|---|---|---|
| < 1 % | Visuellement identique | Différences sub-pixel mineures uniquement. Aucune action nécessaire. |
| 1–5 % | Correspondance proche | Inspectez l'image de différence pour les écarts d'espacement, de graisse de police ou de bordure. De petites retouches CSS sont probablement nécessaires. |
| 5–15 % | Différences notables | Décalages de mise en page, écarts de couleur ou éléments manquants. Examinez les grappes rouges dans la différence pour identifier les sections à travailler. |
| > 15 % | Écart significatif | Différences structurelles ou stylistiques majeures. Concentrez-vous d'abord sur les plus grandes régions rouges — elles indiquent les plus gros écarts de mise en page. |
Lors de l'interprétation de l'image de différence, notez :
- Où se trouvent les grappes rouges sur la page ? (haut, milieu, bas, gauche, droite)
- Sont-elles associées à des éléments spécifiques ? (navigation, hero, cartes, pied de page)
- Les grappes suggèrent-elles des problèmes d'espacement, des différences de couleur ou du contenu manquant ?
Étape 7 : Corriger et re-différencier
- Apportez des corrections CSS/HTML basées sur l'analyse de la différence
- Répétez les Étapes 3–6 (recapturez uniquement l'URL actuelle)
- Continuez jusqu'à ce que
diffPercentatteigne un niveau acceptable
Objectifs typiques :
- Réplication exacte : < 2 %
- Correspondance raisonnable : < 5 %
- Correspondance structurelle (contenu différent) : < 15 %
Captures d'écran plein écran
Par défaut, les captures d'écran ne capturent que la fenêtre visible. Pour les longues pages, utilisez l'option fullPage :
mcp_playwright_browser_take_screenshot → {
type: "png",
fullPage: true,
filename: "temp/vdiff-baseline-desktop-full.png"
}
Avertissement : Les captures plein écran produisent de grandes images et des différences plus lentes. Ne les utilisez que pour comparer des mises en page de page entières.
Conseils spécifiques à Storybook
Lors de la capture de stories Storybook :
-
Utilisez l'URL iframe pour des captures plus propres (pas de chrome Storybook) :
http://localhost:6006/iframe.html?id=components-card--default&viewMode=story -
Attendez le rendu — les stories Storybook peuvent prendre un moment pour s'hydrater :
mcp_playwright_browser_wait_for → { time: 3 } -
Les captures d'écran d'élément fonctionnent bien pour isoler le contenu de la story des éventuels padding de Storybook.
Réglage du seuil
Le drapeau --threshold (0 à 1) contrôle la sensibilité de pixelmatch :
| Valeur | Sensibilité | Cas d'utilisation |
|---|---|---|
| 0,05 | Très strict | Correspondance exacte des pixels, détecte tout |
| 0,1 | Par défaut | Bon équilibre, ignore la plupart de l'anti-aliasing |
| 0,2 | Tolérant | Tolère les différences de rendu de police entre systèmes |
| 0,3 | Très tolérant | Ne détecte que les principales différences de couleur/mise en page |
node scripts/visual-diff.mjs \
--baseline temp/vdiff-baseline-desktop.png \
--current temp/vdiff-current-desktop.png \
--output temp/vdiff-diff-desktop.png \
--threshold 0.2
Exemple : Comparer une section hero
# 1. Capturer la baseline (hero du site de production)
mcp_playwright_browser_navigate → { url: "https://www.bitovi.com/" }
mcp_playwright_browser_resize → { width: 1280, height: 720 }
mcp_playwright_browser_wait_for → { time: 2 }
mcp_playwright_browser_snapshot → {}
# Trouver la référence de la section hero, ex. ref="hero-[1]"
mcp_playwright_browser_take_screenshot → {
type: "png",
element: "hero section",
ref: "hero-[1]",
filename: "temp/vdiff-baseline-hero-desktop.png"
}
# 2. Capturer l'actuelle (story Storybook)
mcp_playwright_browser_navigate → { url: "http://localhost:6006/iframe.html?id=components-hero--default" }
mcp_playwright_browser_resize → { width: 1280, height: 720 }
mcp_playwright_browser_wait_for → { time: 3 }
mcp_playwright_browser_take_screenshot → {
type: "png",
filename: "temp/vdiff-current-hero-desktop.png"
}
# 3. Exécuter la différence (dans le terminal)
node scripts/visual-diff.mjs \
--baseline temp/vdiff-baseline-hero-desktop.png \
--current temp/vdiff-current-hero-desktop.png \
--output temp/vdiff-diff-hero-desktop.png
# 4. Démarrer le serveur temporaire (une fois par session, dans un terminal en arrière-plan)
npx -y http-server temp/ -p 8787 --cors -c-1 &
# 5. Visualiser l'image de différence via Playwright
mcp_playwright_browser_navigate → { url: "http://localhost:8787/vdiff-diff-hero-desktop.png" }
mcp_playwright_browser_take_screenshot → {} # déclenche la vision
# 6. Interpréter : lire la sortie JSON + inspecter visuellement la différence
# 7. Corriger les styles, re-capturer l'actuelle, re-différencier
Nettoyage
Tous les fichiers de sortie vont dans temp/, qui est ignoré par git. Pour nettoyer après une session :
rm -f temp/vdiff-*.png