Communitygithub.com

bitovi/ai-enablement-prompts

Compara una URL de referencia con una URL de desarrollo o de Storybook tomando capturas de pantalla con Playwright en múltiples puntos de quiebre, realizando una comparación de píxeles y reportando los resultados para guiar correcciones de estilo y HTML. Úsalo al replicar una página o componente existente, verificar precisión visual o comprobar fidelidad responsiva.

¿Qué es ai-enablement-prompts?

Este skill de IA permite la comparación visual automatizada entre dos URLs (por ejemplo, un sitio en producción y una versión local en desarrollo o un componente en Storybook) utilizando Playwright para tomar capturas de pantalla en varios puntos de quiebre (móvil, tableta, escritorio), y luego ejecutar una diferencia de píxeles con pixelmatch. Es ideal para desarrolladores que necesitan replicar fielmente una página o componente existente, verificar que los cambios de CSS/HTML no introduzcan desviaciones visuales, o comprobar la fidelidad responsiva en diferentes tamaños de pantalla. El skill está diseñado para usarse con MCP (Model Context Protocol) en editores como VS Code, y asume que Playwright MCP, pixelmatch y pngjs están configurados. El flujo de trabajo guía al agente paso a paso: capturar la línea base, capturar la versión actual, ejecutar el script de diferencia, visualizar la imagen de diferencias (marcando diferencias en rojo y diferencias de suavizado en amarillo), e interpretar los resultados para aplicar correcciones iterativas hasta alcanzar un umbral de similitud aceptable.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/bitovi/ai-enablement-prompts/tree/HEAD/plugins/playwright/skills/visual-diff

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Skill: Diferencia Visual (Visual Diff)

Compara dos URLs visualmente — una línea base (ej. sitio en producción) y una actual (ej. servidor de desarrollo local o historia de Storybook) — para encontrar diferencias a nivel de píxel y guiar correcciones.


Cuándo usarlo

  • Replicar una página o sección existente en Storybook o el sitio Astro
  • Verificar la precisión visual de un componente contra un diseño de referencia
  • Comprobar fidelidad responsiva en distintos puntos de quiebre después de cambios de estilo
  • Iterar sobre CSS/HTML hasta que un componente coincida con su referencia

Cuándo NO usarlo

  • Cambios solo de contenido (actualizaciones de texto, ediciones de copia) donde el diseño no cambia
  • Comparar diseños de Figma — usa el skill de Figma MCP en su lugar
  • Auditorías de rendimiento o accesibilidad — usa Lighthouse o el addon de accesibilidad

Prerrequisitos

Antes de comenzar, confirma:

  1. Playwright MCP está configurado en .vscode/mcp.json con --caps=vision
  2. pixelmatch y pngjs están instalados: revisa las devDependencias en package.json
  3. La URL de línea base es accesible (sitio externo o servidor en ejecución)
  4. La URL actual es accesible (servidor de desarrollo en :4321, Storybook en :6006, etc.)
  5. El directorio temp/ existe en la raíz del espacio de trabajo (está en gitignore)

Si el servidor de desarrollo o Storybook no está en ejecución, inícialos usando las tareas de VS Code:

  • Servidor de desarrollo: usa la tarea Dev Server
  • Storybook: usa la tarea Storybook

Flujo de trabajo

Paso 1: Recibir entradas

El agente necesita:

EntradaRequeridoEjemplo
URL de línea baseSíhttps://www.bitovi.com/
URL actualSíhttp://localhost:4321/ o http://localhost:6006/?path=/story/card--default
Selector CSSNo#hero-section o .card-grid (para comparación a nivel de elemento)
Puntos de quiebreNoPor defecto: móvil (375×667), tableta (768×1024), escritorio (1280×720)

Paso 2: Capturar la línea base

Comparación a nivel de componente (preferida al comparar un solo componente)

Al comparar un componente específico, especialmente cuando la historia de Storybook renderiza solo ese componente pero la página de línea base tiene una página completa alrededor, recorta al cuadro delimitador del componente para que la diferencia no se contamine con secciones de página no relacionadas (barras de navegación, superposiciones fijas, otros módulos arriba/abajo).

Cómo recortar en la página de línea base:

  1. Navega a la URL de línea base
  2. Cambia el tamaño de la ventana gráfica a { width: 1280, height: 720 }
  3. Desplázate hasta que el elemento objetivo esté visible:
    () => document.querySelector('<selector>').scrollIntoView({ behavior: 'instant', block: 'start' })
    
  4. Mide la altura renderizada del componente:
    () => document.querySelector('<selector>').getBoundingClientRect().height
    
  5. Cambia la altura de la ventana gráfica para que coincida exactamente con esa altura (mantén el ancho constante):
    mcp_playwright_browser_resize → { width: 1280, height: <altura medida> }
    
  6. Toma la captura de pantalla — ahora captura solo el área del componente.

Advertencia de sangrado de fondo: Lo que es visible detrás del componente diferirá entre Storybook (vacío) y la página de línea base (otros módulos). Casos comunes: barras de navegación fijas que se superponen en la parte superior, modales/superposiciones con otro contenido de página visible detrás, y componentes parcialmente transparentes. Estas diferencias residuales se agrupan fuera del contenido propio del componente y no son procesables — ignóralas.

Cómo recortar en la historia de Storybook:

Storybook iframe.html renderiza solo el componente sin ningún marco alrededor — no se necesita cambiar tamaño. Solo navega y captura:

mcp_playwright_browser_navigate → { url: "http://localhost:6006/iframe.html?id=<story-id>&viewMode=story" }
mcp_playwright_browser_resize → { width: 1280, height: <misma altura que el recorte de línea base> }
mcp_playwright_browser_take_screenshot → { filename: "temp/vdiff-current-desktop.png" }

Captura de pantalla de página completa (viewport) (al comparar páginas completas)

1. mcp_playwright_browser_navigate → { url: "<url-linea-base>" }
2. mcp_playwright_browser_resize → { width: 1280, height: 720 }
3. mcp_playwright_browser_wait_for → { time: 2 }       # deja que la página se renderice completamente
4. mcp_playwright_browser_take_screenshot → {
     type: "png",
     filename: "temp/vdiff-baseline-desktop.png"
   }

Repite para cada punto de quiebre:

Punto de quiebreAnchoAltoSufijo de nombre de archivo
Móvil375667-mobile
Tableta7681024-tablet
Escritorio1280720-desktop

Paso 3: Capturar la versión actual

Repite exactamente el mismo proceso para la URL actual, usando nombres de archivo temp/vdiff-current-{breakpoint}.png.

Importante: Usa las mismas dimensiones de ventana gráfica y la misma estrategia de recorte (a nivel de componente o página completa) en ambos lados para que la comparación sea de manzanas con manzanas.

Paso 4: Ejecutar el script de diferencia

Para cada punto de quiebre, ejecuta el script de diferencia visual en la terminal:

node scripts/visual-diff.mjs \
  --baseline temp/vdiff-baseline-desktop.png \
  --current temp/vdiff-current-desktop.png \
  --output temp/vdiff-diff-desktop.png

El script produce JSON en la salida estándar:

{
  "totalPixels": 921600,
  "diffPixels": 4521,
  "diffPercent": 0.49,
  "width": 1280,
  "height": 720,
  "baselineDimensions": { "width": 1280, "height": 720 },
  "currentDimensions": { "width": 1280, "height": 720 },
  "dimensionsMismatch": false,
  "diffImagePath": "/absolute/path/to/temp/vdiff-diff-desktop.png"
}

Si dimensionsMismatch es true, las imágenes tenían tamaños diferentes. El script rellena la imagen más pequeña con píxeles transparentes antes de comparar. Esto a menudo indica un problema de diseño que vale la pena investigar.

Paso 5: Ver la imagen de diferencias

Inicia un servidor HTTP temporal para servir el directorio temp/, luego navega con Playwright a la imagen de diferencias:

# Inicia el servidor en segundo plano (ejecuta una vez por sesión)
npx -y http-server temp/ -p 8787 --cors -c-1 &

Luego navega con Playwright a la imagen de diferencias:

mcp_playwright_browser_navigate → { url: "http://localhost:8787/vdiff-diff-desktop.png" }
mcp_playwright_browser_take_screenshot → {}   # activa visión — el agente ahora puede ver la diferencia

La bandera --caps=vision en Playwright MCP significa que el agente puede ver la imagen directamente en la salida de la captura de pantalla.

Nota: Las URL file:// están bloqueadas por Playwright MCP, por lo que el servidor HTTP es necesario. Inícialo una vez y reutilízalo para todas las imágenes de diferencias en la sesión.

Lectura de la imagen de diferencias:

  • Píxeles rojos = diferencias entre línea base y actual
  • Píxeles amarillos = diferencias de suavizado (generalmente ignorables)
  • Original atenuado = áreas que coinciden (mostradas al 30% de opacidad para contexto)
  • Grandes grupos rojos = problemas estructurales (elementos faltantes, cambios de diseño, tamaño incorrecto)
  • Puntos rojos dispersos = renderizado de subpíxeles, suavizado de fuentes o anti-aliasing (generalmente aceptable)
  • Bordes rojos = discrepancia de dimensiones o diferencias de relleno/margen

Paso 6: Interpretar y actuar

Combina los datos cuantitativos del JSON con la inspección visual de la diferencia:

diffPercentInterpretaciónAcción
< 1%Visualmente idénticoSolo diferencias menores de subpíxeles. No se necesita acción.
1–5%Coincidencia cercanaInspecciona la imagen de diferencias en busca de diferencias de espaciado, peso de fuente o bordes. Probablemente se necesiten pequeños ajustes CSS.
5–15%Diferencias notablesCambios de diseño, discrepancias de color o elementos faltantes. Revisa los grupos rojos en la diferencia para identificar qué secciones necesitan trabajo.
> 15%Brecha significativaGrandes diferencias estructurales o de estilo. Concéntrate primero en las regiones rojas más grandes — estas indican las mayores discrepancias de diseño.

Al interpretar la imagen de diferencias, nota:

  • ¿Dónde en la página están los grupos rojos? (arriba, medio, abajo, izquierda, derecha)
  • ¿Están asociados con elementos específicos? (navegación, héroe, tarjetas, pie de página)
  • ¿Los grupos sugieren problemas de espaciado, diferencias de color o contenido faltante?

Paso 7: Corregir y volver a comparar

  1. Realiza correcciones CSS/HTML basadas en el análisis de diferencias
  2. Repite los Pasos 3–6 (solo vuelve a capturar la URL actual)
  3. Continúa hasta que diffPercent alcance un nivel aceptable

Objetivos típicos:

  • Replicación exacta: < 2%
  • Coincidencia razonable: < 5%
  • Coincidencia estructural (contenido diferente): < 15%

Capturas de pantalla de página completa

Por defecto, las capturas de pantalla solo capturan la ventana gráfica visible. Para páginas largas, usa la opción fullPage:

mcp_playwright_browser_take_screenshot → {
  type: "png",
  fullPage: true,
  filename: "temp/vdiff-baseline-desktop-full.png"
}

Advertencia: Las capturas de pantalla de página completa producen imágenes grandes y diferencias más lentas. Úsalas solo al comparar diseños de página completos.


Consejos específicos de Storybook

Al capturar historias de Storybook:

  1. Usa la URL de iframe para capturas más limpias (sin el marco de Storybook):

    http://localhost:6006/iframe.html?id=components-card--default&viewMode=story
    
  2. Espera a que se renderice — las historias de Storybook pueden tardar un momento en hidratarse:

    mcp_playwright_browser_wait_for → { time: 3 }
    
  3. Las capturas de elementos funcionan bien para aislar el contenido de la historia de cualquier relleno de Storybook.


Ajuste del umbral

La bandera --threshold (0 a 1) controla la sensibilidad de pixelmatch:

ValorSensibilidadCaso de uso
0.05Muy estrictoCoincidencia exacta de píxeles, captura todo
0.1PredeterminadoBuen equilibrio, ignora la mayoría del suavizado
0.2ToleranteTolerante a diferencias de renderizado de fuentes entre sistemas
0.3Muy toleranteSolo captura grandes diferencias de color/diseño
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

Ejemplo: Comparar una sección héroe

# 1. Capturar línea base (héroe del sitio de producción)
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 → {}
# Encontrar ref para la sección héroe, ej. ref="hero-[1]"
mcp_playwright_browser_take_screenshot → {
  type: "png",
  element: "hero section",
  ref: "hero-[1]",
  filename: "temp/vdiff-baseline-hero-desktop.png"
}

# 2. Capturar actual (historia de 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. Ejecutar diferencia (en 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. Iniciar servidor temporal (una vez por sesión, en terminal en segundo plano)
npx -y http-server temp/ -p 8787 --cors -c-1 &

# 5. Ver imagen de diferencias a través de Playwright
mcp_playwright_browser_navigate → { url: "http://localhost:8787/vdiff-diff-hero-desktop.png" }
mcp_playwright_browser_take_screenshot → {}   # activa visión

# 6. Interpretar: leer salida JSON + inspeccionar visualmente la diferencia
# 7. Corregir estilos, volver a capturar actual, volver a diferenciar

Limpieza

Todos los archivos de salida van a temp/, que está en gitignore. Para limpiar después de una sesión:

rm -f temp/vdiff-*.png

Skills relacionados