Wilson Vargas

Driftcheck: un servidor MCP para comparar tu app móvil con su diseño de Figma (y que tu agente corrija las diferencias)

Driftcheck compara la pantalla del emulador o del simulador de iOS con el frame de Figma y le dice a tu agente de IA qué cambiar, propiedad por propiedad.

Ícono de Driftcheck junto al reporte interactivo que compara el diseño de Figma con la app

¿Cuántas veces te ha pasado que entregas una pantalla, el diseñador la abre en su teléfono y te devuelve una lista: "el título está 4 px más abajo", "ese botón no es ese morado", "falta el ícono de Google"? Y lo peor es que tú la veías igual al Figma… hasta que alguien la pone al lado. 😅

Desde que empecé a escribir sobre Xamarin en 2017, pasar un diseño a código ha sido siempre la parte más artesanal del trabajo: medir, comparar a ojo, ajustar un Margin, volver a compilar. Hoy muchos tenemos un agente de IA que escribe ese XAML por nosotros, pero el agente tiene el mismo problema que nosotros: no ve la app. Escribe el código, compila y te dice "listo", sin saber si el resultado se parece al diseño.

Para eso hice Driftcheck, un servidor MCP local y de código abierto que le da ojos a tu agente: captura la pantalla del emulador de Android o del simulador de iOS, la compara 1:1 con el frame de Figma y le devuelve qué es diferente y cómo corregirlo, con las propiedades de tu framework. Vamos a ver qué hace, cómo instalarlo y cómo usarlo en tu flujo de trabajo.

¿Qué es Driftcheck?

MCP (Model Context Protocol) es el estándar con el que los agentes de IA (Claude Code, GitHub Copilot en VS Code, Cursor y compañía) se conectan a herramientas externas. Un servidor MCP expone tools que el agente puede llamar por su cuenta cuando las necesita.

Driftcheck es uno de esos servidores, escrito en .NET 10, y su trabajo es responder una pregunta: ¿esta pantalla se ve como en Figma? No se queda en un diff de píxeles a ciegas: empareja cada capa del diseño con el elemento de la app y compara:

Con eso calcula un porcentaje de fidelidad y escribe la corrección de cada diferencia usando las propiedades del framework de tu app.

Reporte interactivo de Driftcheck en la vista Slider: diseño de Figma y app bajo un deslizador, 75 % de fidelidad y la lista de diferencias con su corrección

Este es el reporte que genera para la pantalla de registro del kit Paylo de Marvilo (CC BY 4.0) implementada en .NET MAUI. Lo puedes abrir y jugar con él en la demo interactiva.

Plataformas y frameworks

Qué soporta
Dispositivos Emulador o dispositivo Android (vía adb) y simulador de iOS en macOS
Sugerencias para .NET MAUI, vistas de Android (XML), Jetpack Compose, UIKit, SwiftUI y Flutter
Diseño Frames de Figma, con la API REST (token) o con el plugin de exportación (sin token)
Salida Texto para el agente, report.html, report.md, side_by_side.png y diff.png
Importante: la comparación no depende del framework. Driftcheck trabaja con lo que hay en pantalla; el framework solo cambia cómo escribe las sugerencias. En el repo hay la misma pantalla hecha en MAUI, en vistas nativas de Android (Java) y en UIKit (Swift) justamente para comprobarlo.

Cómo instalarlo

Necesitas el SDK de .NET 10 y, según la plataforma, adb (Android SDK) o Xcode con un simulador encendido. No hace falta clonar nada: el paquete está publicado en NuGet como servidor MCP y dotnet dnx lo descarga la primera vez.

Con Claude Code

claude mcp add driftcheck -e FIGMA_TOKEN=<tu token de Figma> -- dotnet dnx Driftcheck --yes

En cualquier cliente MCP

{
  "mcpServers": {
    "driftcheck": {
      "command": "dotnet",
      "args": ["dnx", "Driftcheck", "--yes"],
      "env": { "FIGMA_TOKEN": "<tu token de Figma>" }
    }
  }
}

En el README tienes botones para instalarlo en un clic en VS Code, VS Code Insiders y Cursor. VS Code te pide el token al instalar; si lo dejas vacío, usas el plugin de Figma (más abajo te explico por qué eso es útil).

El token es un Personal Access Token de Figma con el permiso File content: Read-only. Driftcheck también está en el registro oficial de MCP como io.github.wilsonvargas/driftcheck.

Variables opcionales

Variable Para qué sirve Por defecto
FIGMA_TOKEN Leer el frame con la API de Figma (sin token, usa el plugin)
DRIFTCHECK_OUTPUT Carpeta donde deja reportes y capturas driftcheck en la carpeta temporal
DRIFTCHECK_EXPORTS Dónde busca las exportaciones del plugin Descargas
ANDROID_HOME / ANDROID_SDK_ROOT Encontrar adb Rutas por defecto de Windows y macOS

Las herramientas que recibe tu agente

Una vez instalado, tu agente tiene cinco herramientas nuevas. No tienes que llamarlas tú: el agente decide cuándo usar cada una según lo que le pidas.

Herramienta Para qué la usa el agente
list_devices Ver los dispositivos Android conectados y los simuladores de iOS encendidos
get_design_specs Leer tamaños, colores, textos y fuentes del frame antes de escribir la UI
capture_screen Capturar la pantalla y listar los elementos con su AutomationId
compare_screen Comparar diseño contra app: fidelidad, diferencias, correcciones y report.html
import_design Importar un .driftcheck.json del plugin que quedó fuera de Descargas

compare_screen acepta algunos parámetros que vale la pena conocer:

Un ciclo completo, paso a paso

Así se ve el flujo con una app .NET MAUI en el emulador de Android:

  1. En Figma, selecciona el frame de la pantalla y usa Copy link to selection. El enlace debe llevar ?node-id=.
  2. Ejecuta tu app en el emulador y navega a esa pantalla.
  3. Pídele a tu agente algo como esto:
Compara la app del emulador con https://www.figma.com/design/…?node-id=… y corrige las diferencias.
  1. El agente llama a compare_screen y recibe un reporte como este (extracto de la demo):
**Fidelity: 75 %** — 15 of 20 elements as in Figma

| Element                    | Property   | Figma   | App     |
|----------------------------|------------|---------|---------|
| Nice to meet you           | height     | 31.5    | 25.5    |
| Text "Sign up with Google" | x          | 131.9   | 125     |
| Shape "Sign up"            | background | #DBC6F8 | #BAD1BB |

## How to fix it

- **Nice to meet you**
  - The glyphs don't measure the same as in Figma; check the font: in Figma it is Inter 32 weight 600.
    `FontFamily="Inter"`, `FontSize="32"`, `CharacterSpacing`
- **Shape "Sign up"**
  - `BackgroundColor="#9E56FF"` (it renders as #DBC6F8 in the design: the layer or a container has opacity)
  1. Con eso edita el XAML, recompila, reinstala y vuelve a comparar. El reporte muestra la fidelidad anterior al lado de la nueva (por ejemplo before 72 % (+16)), así que el agente sabe si va mejorando.

Fíjate en el detalle del botón Sign up: en el render de Figma se ve #DBC6F8, pero Driftcheck sugiere #9E56FF, que es el color real de la capa, porque el diseño le aplica opacidad. Ese tipo de cosas son las que a ojo se escapan siempre.

Y lo que más me gusta: el reporte viene en el idioma de tu framework. Para MAUI habla de Margin, FontSize o StrokeShape="RoundRectangle 8"; para Android de android:layout_marginTop; para Compose de Modifier.padding; para SwiftUI de .frame; para Flutter de EdgeInsets.

El reporte interactivo

Además del texto para el agente, cada comparación genera un report.html de un solo archivo (con las imágenes embebidas), para que lo abras tú o se lo pases a tu diseñador. Tiene cuatro vistas, que cambias con las teclas 1 a 4:

A la derecha está la lista de diferencias, filtrable por Differ, Missing y Match; al seleccionar una, se resalta en la imagen.

Vista Side by side del reporte de Driftcheck: a la izquierda el diseño de Figma y a la derecha la app con cajas verdes y naranjas sobre cada elemento

El código de colores de las cajas es simple: verde = coincide, naranja = difiere y azul punteado = dónde dice Figma que debería estar. En la captura se ve claro que el título y el ícono de Google están corridos, y que el botón Sign up tiene otro color.

Vista Diff del reporte de Driftcheck: los píxeles diferentes entre el diseño y la app marcados en magenta, con el botón Sign up completamente resaltado

La vista Diff es la más honesta 😄. Para que no se llene de ruido, cada elemento emparejado se superpone en su posición en la app si coincide, así que el magenta marca solo diferencias reales de forma o color. Un desplazamiento de un píxel no cuenta.

¿Cómo empareja Figma con la app?

Vale la pena entender esta parte para sacarle provecho. Driftcheck empareja capas con elementos en tres pasadas:

  1. Nombre de la capa = AutomationId (ignora espacios y mayúsculas: Login Button ↔ LoginButton), solo si el nombre es único en el diseño.
  2. Texto visible: la capa "Sign up" con el botón que dice "Sign up". Esto es lo que funciona con kits reales, donde las capas se llaman Text o Auto Layout.
  3. Posición: una capa de texto sobre un elemento con otro texto se empareja igual, para que reporte el texto diferente.

En Android el AutomationId es el resource-id (lo lee con uiautomator dump), y en iOS es el accessibilityIdentifier (lo lee un helper de XCUITest con el árbol de accesibilidad). En .NET MAUI ponerlo es una línea:

<!-- El AutomationId coincide con el nombre de la capa en Figma -->
<Image
    AutomationId="Image"
    Source="paylo_logo.png"
    WidthRequest="81"
    HeightRequest="81"
    HorizontalOptions="Center" />

<Border
    AutomationId="Social button"
    BackgroundColor="White"
    Stroke="#EBE7F1"
    StrokeThickness="1"
    StrokeShape="RoundRectangle 24"
    HeightRequest="48">
    <!-- … -->
</Border>
Ojo: los botones, campos, líneas e íconos no aparecen en el árbol de accesibilidad, así que Driftcheck los busca en la captura por cómo se ven: mide cada capa en el PNG del diseño y en la captura, y compara caja, relleno, radio, borde y contenido. Por eso encuentra el ícono de Google que falta aunque la capa se llame Icon.

Algunos detalles más que hacen que la comparación sea útil en la vida real:

El recorrido completo está en How Driftcheck compares.

Sin token de Figma: el plugin de exportación

Aquí hay algo que conviene saber: la API de Figma limita cuántas llamadas puede hacer un token, y en algunos tipos de asiento la cuota es muy baja. Cuando se acaba, responde 429 con esperas de días. Por eso Driftcheck:

Con el plugin el flujo cambia muy poco:

  1. En Figma de escritorio, importa el plugin desde su manifest.json (Plugins → Development → Import plugin from manifest…).
  2. Selecciona el frame y ejecuta Driftcheck Export.
  3. Deja el archivo en Descargas.
  4. Pídele al agente que compare con el enlace del frame, como siempre. Driftcheck encuentra la exportación por el node-id y no llama a la API.

✅ Usa el plugin si no tienes token, si tu cuota es baja o si no quieres darle acceso de lectura a tus archivos. ❌ Evítalo si el diseño cambia a cada rato y prefieres que refresh=true traiga la última versión sin exportar a mano.

Un detalle que me parece importante: el plugin tiene networkAccess en none, no se conecta a ningún servidor. Todo queda en el archivo que descargas.

Del reporte al 100 %

Después de comparar, corregir y recompilar, así queda la pantalla de ejemplo frente a su diseño:

Resultado de Driftcheck: la pantalla de registro en Figma y en la app lado a lado, con el título 100 % igual al diseño

A mi parecer, aquí está el valor real: no es que el agente "adivine" mejor, es que ahora tiene un criterio objetivo para saber cuándo terminó. El porcentaje de fidelidad sube con cada corrección y el agente deja de decir "listo" cuando todavía faltan 6 dp.

Limitaciones actuales

Para que no te lleves sorpresas, esto es lo que todavía no hace:

Limitación Detalle
iOS solo en simulador No funciona con iPhone físico
Solo el área visible No hace scroll; compara lo que se ve en pantalla
Tamaño de fuente en la app uiautomator y XCUITest no lo exponen; get_design_specs lo da como referencia
Sugerencias como pistas La misma diferencia puede venir del elemento o de su contenedor

Checklist

✅ Tienes el SDK de .NET 10 y adb o Xcode con un simulador encendido. ✅ Registraste el servidor con dotnet dnx Driftcheck --yes en tu cliente MCP. ✅ Configuraste FIGMA_TOKEN o instalaste el plugin de exportación. ✅ Copiaste el enlace del frame con ?node-id=. ✅ Le pusiste AutomationId a los elementos clave con el mismo nombre que la capa en Figma. ✅ Pasas framework (maui, compose, swiftui…) para recibir sugerencias con las propiedades correctas. ✅ Pasas projectPath para que te avise si la app instalada está desactualizada.

Conclusión

Ya viste:

Mi recomendación: empieza llamando a get_design_specs antes de escribir la pantalla y deja compare_screen para cerrar el ciclo. Si ya trabajas con un agente, es la forma más directa de que deje de decirte "listo" a ciegas. Y si te interesa ver otro proyecto open source que hice para .NET MAUI, te dejo el post de Avizoro.

El proyecto es MIT y está en GitHub: los issues y pull requests son bienvenidos. ¿Con qué framework lo vas a probar primero? Escríbeme en X (Twitter) y cuéntame qué tal te fue.

Nos leemos pronto 😊


Referencias:

Compartir
Wilson Vargas
Escrito por

Wilson Vargas

Programador .NET con 8 años de experiencia, apasionado por la tecnología. Con habilidades en el desarrollo de aplicaciones utilizando tecnologías de la plataforma .NET.

Posts relacionados

Comentarios