El detector: 44 reglas deterministas
El detector: 44 reglas deterministas
En el capítulo anterior montamos el contexto de diseño con init, PRODUCT.md y DESIGN.md. Ese contexto le dice al agente qué clase de interfaz queremos. Pero hay un problema que ningún archivo de contexto resuelve por sí solo: incluso con buenas instrucciones, un agente de IA tiende a producir interfaces con un “acento” reconocible. Bordes gruesos de color a un lado de las tarjetas, glows oscuros, gradientes morados, la misma tipografía de siempre. A ese conjunto de tics visuales lo llamamos AI slop, y es justo lo que el detector de Impeccable existe para cazar.
Lo interesante es que el detector no es un comando del agente: es una herramienta aparte. Mientras que comandos como /impeccable audit o /impeccable critique razonan con un modelo, el detector es un CLI determinista que aplica 44 reglas mecánicas sobre tu código o sobre una URL. No interpreta, no opina: mide. Y eso le da dos superpoderes que veremos en este capítulo.
El detector es determinista y no necesita API key
La primera característica clave del detector es que no requiere clave de API ni harness de IA. No habla con ningún modelo. Es un linter visual y estructural escrito en JavaScript que puedes correr en cualquier máquina, incluso en CI, sin gastar tokens ni exponer secretos.
La segunda es que es determinista: las mismas 44 reglas, con los mismos umbrales, producen el mismo resultado cada vez. Esto contrasta con los comandos basados en modelo, que pueden variar entre ejecuciones. El detector es el suelo firme sobre el que se apoyan los comandos más creativos.
Se invoca directamente con npx, sin instalación previa obligatoria:
npx impeccable detect src/ # escanea un directorio
npx impeccable detect index.html # escanea un archivo HTML
npx impeccable detect https://example.com # escanea una URL (con Puppeteer)
npx impeccable detect --json . # salida JSON, ideal para CI
npx impeccable detect --no-config src/ # escaneo crudo, ignora la config
Cuando le pasas una URL, el detector levanta un navegador headless (Puppeteer) para renderizar la página y poder medir colores efectivos, contraste real y geometría de los elementos tal como los ve el usuario. Cuando le pasas archivos locales, analiza el HTML y el CSS estáticos, y para reglas visuales también puede renderizar.
Recuerda: el detector vive en el repo de Paul Bakaus (pbakaus), se publica en npm como
impeccabley es Apache 2.0. El CLIdetectes independiente del agente, así que puedes adoptarlo aunque todavía no uses los comandos/impeccable.
Los cuatro motores del detector
No todas las reglas se evalúan igual. Algunas miran el texto del código fuente, otras necesitan ver los píxeles renderizados. El detector organiza esto en cuatro motores, y cada regla declara cuál usa:
- Estático (static): analiza el HTML y el CSS como texto estructurado. Sirve para reglas que dependen de declaraciones explícitas, como gradientes de rayas repetidas o transiciones sobre propiedades de layout.
- Regex (regex): aplica expresiones regulares sobre el texto crudo. Lo usan reglas de copy y de patrones textuales, como el abuso de em-dashes o frases tipo “innovation theater”.
- Visual (visual): mide el resultado renderizado: contraste real, luminancia, tamaños computados, geometría de cajas. Es el motor más potente y el que sustenta la mayoría de reglas de calidad.
- Browser (browser): usa el navegador headless completo (Puppeteer) para inspeccionar estilos computados y estructura del DOM en una URL viva. Es el que se activa cuando apuntas el detector a
https://....
flowchart TD
A[npx impeccable detect TARGET] --> B{Tipo de target}
B -->|archivo o directorio| C[Motor estático HTML/CSS]
B -->|texto crudo| D[Motor regex]
B -->|URL https| E[Motor browser Puppeteer]
C --> F[Motor visual: render y medición]
E --> F
D --> G[Colección de hallazgos]
F --> G
G --> H{Modo de salida}
H -->|por defecto| I[Reporte legible en terminal]
H -->|--json| J[JSON para CI / hooks]
La idea es que cada regla elija el motor mínimo necesario. Una regla de copy no necesita renderizar nada (le basta regex), mientras que detectar un glow oscuro requiere medir la luminancia del fondo y el blur de la sombra (visual/browser).
Qué detecta: dos grandes familias
Las 44 reglas se reparten en dos familias conceptuales:
- AI slop: tics visuales y de copy que delatan una interfaz generada por IA sin curaduría humana.
- Calidad general de diseño: problemas atemporales de legibilidad, espaciado, accesibilidad y estructura que existirían igual sin IA.
Veamos las categorías concretas, con reglas representativas extraídas de los archivos checks.mjs y antipatterns.mjs del detector. No hace falta memorizar las 44; lo valioso es entender los grupos y reconocer el patrón.
Bordes y sombras (el sello del AI slop)
Esta categoría agrupa los tells más reconocibles de una UI generada por IA.
side-tab: borde de color grueso (≥2px) a un lado de una tarjeta redondeada. La descripción del registro lo llama “el tell más reconocible de las UIs generadas por IA”. Motor visual; excluye tags seguros comoformoinput.border-accent-on-rounded: bordes de acento arriba o abajo (≥2px) que chocan con las esquinas redondeadas.dark-glow:box-shadowcromático (blur >4px) sobre fondos oscuros (luminancia <0.1). Es “el look cool por defecto” del AI slop. Motor visual.
Tipografía
overused-font: tipografía primaria usada por ≥15% del texto cuando pertenece a la lista de fuentes sobreusadas (Inter, Roboto, Fraunces, Geist, Plus Jakarta Sans, Space Grotesk). Motor browser sobre estilos computados.single-font: una sola familia tipográfica no genérica en ≥20 elementos de texto.flat-type-hierarchy: ratio de tamaños <2.0 entre ≥3 tamaños distintos; no hay jerarquía visual clara.gradient-text:background-clip: text+ gradiente, decoración sin significado.italic-serif-display: serif itálica enorme (Fraunces, Recoleta, Playfair) como titular del hero.hero-eyebrow-chipyrepeated-section-kickers: las etiquetas diminutas, en mayúsculas y con tracking, justo encima de un h1 o repetidas sobre los h2/h3.oversized-h1: h1 ≥72px con ≥40 caracteres que domina ≥28% del alto del viewport.tiny-text(texto <12px),all-caps-body(mayúsculas en >30 caracteres de cuerpo),wide-tracking(>0.05em) yextreme-negative-tracking(≤-0.05em).
Color y contraste
ai-color-palette: texto morado/violeta en encabezados o colores cian/neón sobre fondos oscuros. Híbrido estático/visual que escanea hex y gradientes parseados.cream-palette: fondos de página crema o beige cálido, “la superficie con buen gusto por defecto” del AI slop. Motor visual.gray-on-color: texto gris neutro sobre fondos cromáticos; se ve lavado.low-contrast: fallo de contraste WCAG AA (4.5:1 para texto normal, 3:1 para texto grande). Motor visual comparando color de texto contra fondo efectivo o stops de gradiente.
Espaciado y layout
line-length: cuerpo de texto que excede ~80 caracteres por línea.cramped-padding: padding insuficiente en contenedores con borde o color; umbrales relativos al tamaño de fuente (verticalmax(4px, fontSize × 0.3), horizontalmax(8px, fontSize × 0.5)).body-text-viewport-edge:<p>o<li>pegado al borde del viewport (<16px de margen) sin padding del contenedor.tight-leading:line-height<1.3 en cuerpo de texto.justified-text:text-align: justifysinhyphens: auto.nested-cards: tarjetas dentro de tarjetas, que generan ruido visual y profundidad excesiva.monotonous-spacing: un único valor de espaciado domina >60% de los paddings/margins/gaps recogidos.
Componentes y estructura
icon-tile-stack: el cuadradito redondeado con un icono encima de un encabezado, “la plantilla universal de feature-card de la IA”. Motor visual; aspect ratio 0.7–1.4.skipped-heading: saltos en la jerarquía de encabezados (por ejemplo h2 → h4) que rompen la estructura del documento. Motor browser/estático.broken-image: atributossrcvacíos o ausentes.text-overflowyclipped-overflow-container: contenido que desborda o queda cortado por overflow.- Objetivos táctiles: los objetivos táctiles demasiado pequeños (por debajo de ~44×44 px) se evalúan dentro de la dimensión responsive del comando
audit, no como una regla determinista con id propio del detector.
Movimiento
bounce-easing: animaciones cuyo nombre coincide con bounce/elastic/wobble/jiggle/spring, o cubic-bezier con valores fuera de[0,1](overshoot). “Se sienten anticuadas y de mal gusto”. Motor estático/visual.layout-transition:transitionsobre propiedades de layout (width, height, padding, margin) que provocan layout thrash. Motor regex.image-hover-transform: escalar o rotar imágenes en hover (hover:scale,hover:rotate).
Copy (texto y cadencia)
em-dash-overuse: más de dos em-dashes en el cuerpo; una cadencia típica de IA.marketing-buzzword: frases SaaS genéricas (streamline, empower, supercharge, world-class).aphoristic-cadence: tres o más secciones que cierran con una frase corta de remate.numbered-section-markers: marcadores numéricos (01, 02, 03) como etiquetas de sección.theater-slop-phrase: el patrón “[palabra] theater” (por ejemplo “innovation theater”). Motor regex.
Gradientes y efectos
repeating-stripes-gradient:repeating-linear-gradient/repeating-radial-gradientdecorativos. Motor regex estático.
Reglas del design system (consultan tu DESIGN.md)
Cuando activas detector.designSystem.enabled, el detector cruza tu código contra los tokens documentados en DESIGN.md:
design-system-font: tipografías fuera de las documentadas.design-system-color: colores fuera de la paleta declarada (consejo).design-system-radius: radios de borde fuera de los tokens del sistema (consejo).
Aquí se cierra el círculo con el capítulo 3: el DESIGN.md que escribiste deja de ser documentación pasiva y se convierte en reglas verificables.
Reglas gated por proveedor
Algunas reglas solo se activan según el proveedor de IA que generó el código, porque son tics específicos de un modelo:
gpt-thin-border-wide-shadow(GPT): bordes finísimos con sombras difusas.repeating-stripes-gradientytheater-slop-phrase(GPT-gated): patrones de copy y gradiente recurrentes en salidas de GPT.image-hover-transform(Gemini-gated): transformaciones de imagen en hover típicas de Gemini.
El sistema de ignores inline
Ninguna regla mecánica acierta el 100% de las veces. A veces ese overused-font: Inter es deliberado porque Inter es tu fuente de marca. Para esos casos, el detector ofrece waivers inline: comentarios en el propio archivo que silencian una regla, con un motivo opcional que documenta la decisión.
<!-- impeccable-disable overused-font: documento de marca exportado -->
<div class="brand-doc">...</div>
Hay tres variantes, igual que en un linter clásico:
<!-- impeccable-disable overused-font: motivo -->
<!-- impeccable-disable-line overused-font -->
<!-- impeccable-disable-next-line overused-font -->
impeccable-disablesilencia la regla en el bloque o archivo.impeccable-disable-linela silencia en la línea del propio comentario.impeccable-disable-next-linela silencia en la línea siguiente.
El motivo tras los dos puntos es texto libre y queda como rastro de la decisión: cuando alguien revise el código dentro de seis meses sabrá por qué se ignoró. Buena higiene de equipo.
Si quieres ver el resultado crudo, sin honrar los ignores, hay dos flags:
npx impeccable detect --no-inline-ignores src/ # ignora los comentarios de waiver
npx impeccable detect --no-config src/ # ignora toda la configuracion
Configuración del detector
Además de los waivers inline, el detector lee su configuración de .impeccable/config.json (y de .impeccable/config.local.json para overrides locales que no se commitean). Las tres claves clave para controlar el ruido son:
{
"detector": {
"ignoreRules": ["bounce-easing", "cream-palette"],
"ignoreFiles": ["src/legacy/**", "vendor/**"],
"ignoreValues": {
"overused-font": [
{ "value": "Inter", "reason": "Fuente oficial de marca" }
]
},
"designSystem": { "enabled": true }
}
}
detector.ignoreRules: desactiva reglas completas por su id. Útil cuando una regla no encaja con tu producto.detector.ignoreFiles: excluye rutas (con globs). Perfecto para carpetas legacy o de terceros.detector.ignoreValues: suprime un hallazgo concreto de una regla (por ejemplo, permiteInterparaoverused-font) con un motivo opcional.
Estas mismas operaciones tienen atajos en el CLI, sin editar el JSON a mano:
npx impeccable ignores list # muestra los ignores activos
npx impeccable ignores add-file "src/legacy/**" # agrega un archivo/glob
npx impeccable ignores add-value overused-font Inter --reason "Brand font"
La diferencia entre ignore inline e ignore de config es de alcance y de intención: el inline documenta una excepción puntual junto al código que la justifica; el de config aplica una política transversal a todo el proyecto. Usa inline para lo local y excepcional, y config para lo global y estructural.
Cómo integrar el detector en tu flujo
Hay dos formas de poner el detector a trabajar, y conviene usar ambas.
Manual: como linter bajo demanda
La forma más simple es correrlo tú mismo antes de dar por terminada una pantalla:
npx impeccable detect src/components/PricingCard.tsx
Lo lees, decides qué arreglar y qué silenciar con un waiver, y vuelves a correrlo. En CI lo encadenas con --json para fallar el pipeline cuando aparecen hallazgos nuevos:
npx impeccable detect --json . > impeccable-report.json
Automático: vía hooks del agente
La integración más potente es la que conecta el detector con tu agente de coding. Al instalar Impeccable, el instalador configura hooks nativos del proveedor (Claude Code, GitHub Copilot, Codex, Cursor) que corren el detector automáticamente cuando el agente edita archivos de UI directamente, y le devuelven los hallazgos al agente para que se autocorrija en el momento.
Así, el detector deja de ser un paso manual y se convierte en un guardarraíl permanente: el agente escribe una tarjeta con un side-tab, el hook lo detecta, y el propio agente la corrige antes de que tú la veas. Estos hooks respetan tu .impeccable/config.json y honran los waivers inline por defecto, de modo que el comportamiento automático es coherente con el manual.
sequenceDiagram
participant A as Agente de coding
participant H as Hook nativo
participant D as Detector (CLI)
participant U as Usuario
A->>A: Edita archivo de UI
A->>H: Dispara hook on-edit
H->>D: npx impeccable detect (respeta config + waivers)
D-->>H: Hallazgos (JSON)
H-->>A: Devuelve hallazgos al agente
A->>A: Autocorrige el AI slop
A->>U: Entrega UI ya saneada
La configuración fina de estos hooks (hook.enabled, hook.auditLog para logging NDJSON, y el resto del workflow de equipo) la cubrimos en el capítulo 12. Por ahora basta con saber que el detector es la pieza que esos hooks ejecutan.
Resumen
El detector es el corazón determinista de Impeccable: un CLI independiente, sin API key, que aplica 44 reglas mecánicas sobre archivos, directorios o URLs mediante npx impeccable detect. Sus cuatro motores —estático, regex, visual y browser— cubren desde el texto del código hasta los píxeles renderizados con Puppeteer. Las reglas se reparten en dos familias: AI slop (side-tab, dark-glow, ai-color-palette, cream-palette, overused-font, icon-tile-stack, bounce-easing, gradient-text y los tells de copy) y calidad general (line-length, cramped-padding, low-contrast, skipped-heading, tiny-text y más), con reglas extra que validan tu propio DESIGN.md. Cuando una regla se equivoca o la excepción es deliberada, la silencias con ignores inline (impeccable-disable, -line, -next-line) o con la configuración de .impeccable/config.json (ignoreRules, ignoreFiles, ignoreValues). Y lo integras a tu flujo de dos maneras: manualmente como linter en CI, o automáticamente vía los hooks del agente que le devuelven los hallazgos para que se autocorrija.
Con el detector dominado, ya tienes el suelo firme. En el próximo capítulo subimos un nivel: los comandos que sí razonan con un modelo para planificar diseño antes de escribir código.
Siguiente: Comandos de planificación: craft, shape, document, extract