¿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:
- Posición y tamaño.
- Textos y tipografía (midiendo los glifos visibles, no las cajas).
- Color de fondo y de texto, radios de las esquinas y bordes.
- Íconos e imágenes que faltan, incluso capas sin texto que se llaman
FrameoVector.
Con eso calcula un porcentaje de fidelidad y escribe la corrección de cada diferencia usando las propiedades del framework de tu app.

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:
framework:maui,android,compose,uikit,swiftuioflutter. Sin él, las sugerencias van en términos generales.projectPath: la carpeta de tu proyecto. Si tiene archivos más nuevos que la app instalada, el reporte te avisa que falta recompilar (te ahorra comparar contra una versión vieja 🙃).toleranceycolorTolerance: tolerancia de posición/tamaño (2 dp o pt por defecto) y de color (distancia RGB, 24 por defecto).refresh: vuelve a descargar el frame de Figma en lugar de usar la caché local.
Un ciclo completo, paso a paso
Así se ve el flujo con una app .NET MAUI en el emulador de Android:
- En Figma, selecciona el frame de la pantalla y usa Copy link to selection. El enlace debe llevar
?node-id=. - Ejecuta tu app en el emulador y navega a esa pantalla.
- 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.
- El agente llama a
compare_screeny 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)
- 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:
- Slider: Figma y la app encimados con un deslizador.
- Opacity: una sobre la otra con transparencia.
- Diff: los píxeles diferentes en magenta.
- Side by side: lado a lado.
A la derecha está la lista de diferencias, filtrable por Differ, Missing y Match; al seleccionar una, se resalta en la imagen.

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.

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:
- Nombre de la capa =
AutomationId(ignora espacios y mayúsculas:Login Button↔LoginButton), solo si el nombre es único en el diseño. - 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
TextoAuto Layout. - 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:
- Auto layout de Figma recalculado: dentro de instancias de componentes, Figma puede devolver cajas desactualizadas (por ejemplo, capas ocultas que "siguen ocupando espacio"). Driftcheck recalcula dirección, padding, spacing y alineación con las reglas de cada frame.
- Pantallas de distinto ancho: compara en dp o pt (1 unidad de Figma = 1 dp en Android = 1 pt en iOS). Si el dispositivo es un poco más ancho o angosto que el frame (411 contra 430), ancla cada elemento a la izquierda, derecha, centro o estirado, lo que encaje mejor.
- Splash de .NET: si la captura no se parece al diseño, casi siempre es la pantalla de carga. Espera y vuelve a capturar hasta 3 veces.
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:
- Guarda el JSON y el PNG de cada frame en una caché local y los reutiliza en cada comparación. Solo vuelve a descargar con
refresh=true. - Si Figma responde
429, el error te dice cuánto esperar. - Incluye un plugin de Figma (
tools/figma-export-plugin) que exporta el frame a un archivo.driftcheck.jsonsin usar la API REST.
Con el plugin el flujo cambia muy poco:
- En Figma de escritorio, importa el plugin desde su
manifest.json(Plugins → Development → Import plugin from manifest…). - Selecciona el frame y ejecuta Driftcheck Export.
- Deja el archivo en Descargas.
- Pídele al agente que compare con el enlace del frame, como siempre. Driftcheck encuentra la exportación por el
node-idy 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:

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:
- Qué es Driftcheck y qué compara: posición, tamaño, texto, fuente, colores, radios, bordes e íconos.
- Cómo instalarlo con
dotnet dnxen Claude Code, VS Code, Cursor o cualquier cliente MCP. - Las cinco herramientas que recibe tu agente y los parámetros de
compare_screen. - Cómo leer el reporte interactivo y sus vistas Slider, Diff y Side by side.
- Cómo empareja capas con elementos y por qué conviene usar
AutomationId. - Cómo trabajar sin token con el plugin de Figma.
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:
