Inicio
Bitácora · revisada el 2026-08-31

Claude diseña a ciegas: las cuatro piezas que le ponen ojos

Claude diseña webs a ciegas. Escribe el HTML, escribe el CSS, y nunca ve el resultado. Por eso salen con olor a plantilla: no es que tenga mal gusto, es que trabaja sin mirar.

Esta guía monta las cuatro piezas que lo arreglan, en el orden que importa. Y empieza por el final, que es lo interesante: los ojos van primero.

01Por qué salen con olor a plantillaNo es mal gusto: es que escribe sin ver el resultado.02Pieza 1 · Playwright, los ojosAbre la página de verdad, la mide, y cuenta lo que ha salido torcido.03El montaje, en ordenLos cuatro comandos y la comprobación de cada uno.04El bucle, que es todo el puntoEscribe, abre, mide, corrige. Sin ti en medio.

01 el problema

Por qué salen con olor a plantilla

Piensa en cómo trabajas tú cuando maquetas algo. Escribes una regla, miras, ajustas. Miras otra vez. Ese bucle —escribir, mirar, corregir— es el noventa por ciento del trabajo, y es exactamente el que Claude no puede hacer.

Sin ojos solo le queda una estrategia: escribir lo que estadísticamente suele funcionar. De ahí sale el aspecto reconocible que todo el mundo identifica ya: la tipografía por defecto, el degradado de moda, las tarjetas con la misma sombra, el mismo espaciado en todo.

Lo que ve hoy sin herramientas
el código que acaba de escribir
Lo que NO ve
si el botón se sale, si el texto no contrasta, si desborda
Cómo se entera de un fallo
porque se lo cuentas tú
Cuántas vueltas cuesta eso
las que tú aguantes

El fallo que lo demuestra, y me pasó montando esta misma web

Al montar la web que estás leyendo, los botones salían con el icono encima del texto en vez de al lado, y las etiquetas de cada entrada ocupaban toda la línea en vez de ir en píldoras. En el código no había nada raro: las clases eran correctas y las reglas también.

La causa era que una segunda hoja de estilos se cargaba después y ganaba por orden de cascada. Eso no se ve leyendo, porque los dos archivos por separado están bien. Se vio al renderizar la página y medir los estilos calculados: el botón resolvía display:block cuando su regla decía inline-flex.

Ése es el trabajo que hacen los ojos, y es el motivo de que Playwright vaya primero y no último.

La reglaLo que se ve leyendo y lo que se ve mirando

Un fallo de diseño casi nunca es «el código está mal». Suele ser «el código está

bien y el resultado no es el que dice el código». Sin renderizar, esa diferencia

es invisible.

02 el método

El orden, que decide el resultado

Las cuatro piezas se pueden instalar en cualquier orden y todas funcionan. Pero el orden en que las instales decide cómo trabaja Claude, y eso sí cambia el resultado.

01 · Los ojos

Playwright. Abre la página en un navegador de verdad y le cuenta qué ha salido. Va primero porque sin esto las otras tres son a ciegas.

playwright
02 · Los ladrillos

El MCP de shadcn. Botones, formularios y tarjetas con el código que tú usarías.

shadcn mcp
03 · El movimiento

El MCP de Magic UI. Animaciones y transiciones. Lo que hace que apetezca mirarla.

magicui mcp
04 · El criterio

La skill frontend-design de Anthropic. Jerarquía, espaciado, tipografía.

frontend-design

Sin el cuatro, los tres primeros son piezas caras mal colocadas. Sin el uno, los otros tres son a ciegas. Ese es todo el argumento del orden.

03 los ojos

Pieza 1 · Playwright, los ojos

Playwright es una herramienta de automatización de navegador. Abre tu página en Chromium, Firefox o WebKit de verdad —no en una simulación— y puede leer cualquier cosa de ella: posiciones, tamaños, colores calculados, si algo desborda.

Hay dos formas de usarlo con Claude y conviene entender la diferencia.

La vía directa: un script que mide

Es la que yo uso y la que menos falla. Un archivo corto que abre la página, mide lo que te interesa e imprime números.

medir.mjs · los cuatro números, medidos

import { chromium } from '@playwright/test'

const URL = process.argv[2] ?? 'http://localhost:3000'
const ANCHO = Number(process.argv[3] ?? 390)

const nav = await chromium.launch()
const ctx = await nav.newContext({ viewport: { width: ANCHO, height: 844 } })
const p = await ctx.newPage()
await p.goto(URL, { waitUntil: 'domcontentloaded' })
await p.waitForSelector('main, body > *')

const d = await p.evaluate(() => {
  const cs = e => getComputedStyle(e)
  const visible = e => {
    const r = e.getBoundingClientRect()
    return r.width > 0 && r.height > 0 && cs(e).visibility !== 'hidden'
  }

  // ── color: rgb(a) -> [r,g,b,a] ────────────────────────────────────────────
  const rgba = s => (s.match(/[\d.]+/g) || [0, 0, 0, 0]).map(Number)

  // Pinta `frente` (que puede llevar alfa) encima de `detras`.
  const mezcla = (frente, detras) => {
    const a = frente[3] === undefined ? 1 : frente[3]
    return [0, 1, 2].map(i => Math.round(frente[i] * a + detras[i] * (1 - a)))
  }

  // El fondo REAL. getComputedStyle devuelve rgba(0,0,0,0) cuando es
  // transparente, que es el caso normal, así que hay que subir por los
  // ancestros. Pero NO basta con quedarse con el primero que tenga alfa:
  // una capa a rgba(15,12,8,0.04) sobre blanco es casi blanca, y tratarla
  // como negra da ratio 1,0 sobre texto perfectamente legible. Se apilan
  // las translúcidas y se componen sobre el primer opaco.
  const fondo = e => {
    const capas = []
    let base = [255, 255, 255]
    for (let n = e; n; n = n.parentElement) {
      const c = rgba(cs(n).backgroundColor)
      const a = c[3] === undefined ? 1 : c[3]
      if (a === 0) continue
      if (a === 1) { base = c.slice(0, 3); break }
      capas.push(c)
    }
    return capas.reverse().reduce((acc, c) => mezcla(c, acc), base)
  }

  // Luminancia relativa y ratio, según WCAG 2.2
  const lum = ([r, g, b]) => {
    const f = v => (v /= 255) <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4
    return 0.2126 * f(r) + 0.7152 * f(g) + 0.0722 * f(b)
  }
  const ratio = (a, b) => {
    const [x, y] = [lum(a), lum(b)].sort((m, n) => n - m)
    return (x + 0.05) / (y + 0.05)
  }

  // ── 1 · ¿se sale la página por el lado? ───────────────────────────────────
  const desborda = document.documentElement.scrollWidth
                 - document.documentElement.clientWidth

  // ── 2 · objetivos pulsables por debajo de 44 px en el lado corto ──────────
  const pulsables = [...document.querySelectorAll(
    'a, button, [role="button"], input, select, textarea, summary')]
    .filter(visible)
    .map(e => ({ e, r: e.getBoundingClientRect() }))
    .filter(({ r }) => Math.min(r.width, r.height) < 44)
    .map(({ e, r }) => ({
      que: e.tagName.toLowerCase() + (e.className ? '.' + String(e.className).split(' ')[0] : ''),
      texto: (e.textContent || '').trim().slice(0, 24),
      w: Math.round(r.width), h: Math.round(r.height),
    }))

  // ── 3 · contraste del texto contra su fondo ───────────────────────────────
  const bajos = []
  for (const e of document.querySelectorAll('p, li, a, span, h1, h2, h3, td, th, button')) {
    if (!visible(e)) continue
    const propio = [...e.childNodes].some(n => n.nodeType === 3 && n.textContent.trim())
    if (!propio) continue
    const est = cs(e)
    const px = parseFloat(est.fontSize)
    const grande = px >= 24 || (px >= 18.66 && Number(est.fontWeight) >= 700)
    const min = grande ? 3 : 4.5
    const bg = fondo(e)
    const r = ratio(mezcla(rgba(est.color), bg), bg)
    if (r < min) bajos.push({
      que: e.tagName.toLowerCase(), texto: (e.textContent || '').trim().slice(0, 24),
      ratio: Number(r.toFixed(2)), exige: min,
    })
  }

  // ── 4 · caracteres por línea ──────────────────────────────────────────────
  const anchos = []
  for (const e of document.querySelectorAll('p, li')) {
    if (!visible(e)) continue
    const t = (e.textContent || '').trim()
    if (t.length < 40) continue
    const r = e.getBoundingClientRect()
    const alto = parseFloat(cs(e).lineHeight) || parseFloat(cs(e).fontSize) * 1.2
    const lineas = Math.max(1, Math.round(r.height / alto))
    const cpl = Math.round(t.length / lineas)
    if (cpl > 70) anchos.push({ cpl, texto: t.slice(0, 30) })
  }

  return {
    desborda,
    pulsables_pequenos: pulsables.length, pulsables,
    contraste_bajo: bajos.length, bajos,
    lineas_largas: anchos.length, anchos,
  }
})

// Un informe corto y pegable, no un volcado: si la salida no cabe en la
// pantalla, nadie la lee y el bucle deja de tener freno.
const linea = (rotulo, n, ok) => `${ok ? '✓' : '✗'} ${rotulo.padEnd(26)} ${n}`
console.log(`── ${URL}  @${ANCHO}px ─────────────────────`)
console.log(linea('desborda a lo ancho', d.desborda + 'px', d.desborda === 0))
console.log(linea('pulsables < 44px', d.pulsables_pequenos, d.pulsables_pequenos === 0))
for (const x of d.pulsables.slice(0, 3)) console.log(`    ${x.que} ${x.w}×${x.h} «${x.texto}»`)
console.log(linea('contraste bajo', d.contraste_bajo, d.contraste_bajo === 0))
for (const x of d.bajos.slice(0, 3)) console.log(`    ${x.ratio}:1 exige ${x.exige} «${x.texto}»`)
console.log(linea('líneas > 70 caracteres', d.lineas_largas, d.lineas_largas === 0))
for (const x of d.anchos.slice(0, 3)) console.log(`    ${x.cpl} car «${x.texto}»`)
await p.screenshot({ path: 'pantalla.png', fullPage: true })
await nav.close()

Se lo das a Claude y le pides que lo ejecute y lea la salida. La captura, además, la puede mirar.

Si prefieres no descargar nada y ya tienes Google Chrome instalado, cambia chromium.launch() por chromium.launch({ channel: 'chrome' }) y usa el que tienes. Pero que quede claro lo que exige: Chrome, no vale Chromium ni Brave, y en WSL —que es lo que recomiendo a quien va con Windows— normalmente no hay ninguno de los dos. Por eso el script de arriba no trae channel: la versión que funciona en más máquinas es la que se baja su propio navegador.

npm install -D @playwright/test && npx playwright install chromium
node medir.mjs http://localhost:3000 390

Y esto es lo que imprime. No es un ejemplo inventado: es la salida de apuntarlo a la portada de esta misma bitácora el 31/08/2026, con sus fallos dentro.

Lo que sale de verdad
── https://javivillegas-ai.cp.c2developers.com/bitacora/  @390px ─────────────────────
✓ desborda a lo ancho        0px
✗ pulsables < 44px           21
    input.buscador 185×21 «»
    a.pil 57×36 «Todo»
    a.pil 54×36 «guia»
✗ contraste bajo             2
    4.4:1 exige 4.5 «.»
    4.4:1 exige 4.5 «javiergarcia@c2developer»
✓ líneas > 70 caracteres     0

Veintiuno y dos. En mi propia web, publicada, después de mirarla mucho. Ése es justo el argumento de la guía: a ojo no se ve, y con números aparece en dos segundos.

La trampa del contraste, que casi me cuela un número falso

La primera versión de este medidor subía por los ancestros hasta encontrar un fondo opaco y se quedaba con el primero que tuviera algo de color. Con una capa a rgba(15,12,8,0.04) —un tinte del 4 % sobre blanco— la trataba como casi negra, y reportaba 1,0:1 sobre un texto que se lee perfectamente.

Un medidor que da falsos positivos es peor que no tenerlo: mandas a Claude a arreglar algo que no está roto. Por eso fondo() compone las capas translúcidas en vez de quedarse con una, y el color del texto también se compone sobre el resultado, porque también puede llevar alfa.

La vía del MCP

Microsoft publica un servidor MCP oficial de Playwright que le da a Claude control del navegador directamente, leyendo la página como árbol de accesibilidad en vez de por capturas. Es más cómodo para explorar y navegar.

claude mcp add playwright -- npx -y @playwright/mcp@latest
OjoCuál de las dos vías usar

Cuál usar: el MCP para explorar y hacer clic; el script para medir. Un

script que imprime números es reproducible y lo puedes meter en un examen

automático. Una sesión de navegador conversacional, no.

La trampa de node_modules, que cuesta media hora

Node resuelve los paquetes desde la ruta del archivo, no desde donde lo ejecutas. Un script de Playwright guardado en /tmp no encuentra la librería aunque la tengas instalada, y el error no lo dice claro.

El error que vas a ver
Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@playwright/test'
    imported from /tmp/medir.mjs

El script vive dentro del proyecto. Siempre.

04 los ladrillos

Pieza 2 · shadcn, los ladrillos

Botones, formularios, tarjetas, diálogos. Claude los pide, se los instala él solo, y salen con el código que tú ya usarías: no una librería que importas, sino archivos que entran en tu proyecto y que puedes editar.

El MCP no es un paquete aparte: viene dentro de la propia herramienta de línea de comandos. Esto conviene saberlo porque hay forks de la comunidad que aparecen antes en las búsquedas.

npx shadcn@latest mcp init --client claude

Qué cambia teniéndolo

Sin el MCP, le pides un botón y te escribe un botón: HTML y CSS inventados sobre la marcha, que se parecen a los del proyecto pero no son los del proyecto. Con el MCP, busca en el registro, instala el componente real y lo usa.

La diferencia se nota a la tercera pantalla, cuando todos los botones son el mismo botón en vez de cinco primos lejanos.

Pedirle componentes de verdad

Necesito una pantalla de alta de cliente.

Antes de escribir nada:

1. Lista qué componentes hay disponibles en el registro para formularios.
2. Dime cuáles vas a usar y por qué ésos.
3. Instálalos.

Y después móntala. No escribas ningún componente a mano si existe en el
registro: quiero que todos vengan del mismo sitio, para que en la pantalla
siguiente sean idénticos.

La última frase es la que evita el problema real. Sin ella mezcla componentes instalados con componentes escritos a mano y a las tres pantallas tienes dos sistemas de diseño conviviendo.

05 el movimiento

Pieza 3 · Magic UI, lo que se mueve

Magic UI pone lo que se mueve: animaciones, degradados, transiciones. Es la diferencia entre una web que funciona y una que apetece mirar. Está pensada como complemento de shadcn, así que las dos conviven sin pelearse.

npx shadcn@latest add "https://magicui.design/r/shimmer-button"

Y su servidor MCP, que hace los componentes buscables desde el editor:

claude mcp add magicui -- npx -y @magicuidesign/mcp@latest
OjoLa pieza más floja de las cuatro

Ésta es la pieza más floja de las cuatro y hay que decirlo. Comprobado el

31/08/2026: la librería está viva, pero su servidor MCP llevaba meses sin un

solo cambio y sin publicar versión nueva. Funciona, pero no está en desarrollo

activo. Si te falla, usa la librería directamente sin el MCP — se pierde la

comodidad de buscar desde el editor, no los componentes.

Cuánto movimiento es demasiado

Casi siempre, menos del que apetece poner. Tres reglas que aplico:

gana el movimiento.

provoca mareo, y desactivarlo son tres líneas.

La regla de movimiento, para el proyecto

Añade esto a las instrucciones del proyecto:

- Como mucho UN elemento animado por pantalla, y es el que dirige la mirada.
- Nada en bucle infinito a menos de 200px de un bloque de texto largo.
- Todo lo que se mueva va dentro de una consulta que respete
  prefers-reduced-motion: reduce, sin excepciones.
- Las transiciones de interfaz, por debajo de 200ms. Por encima se percibe
  como lentitud, no como elegancia.

06 el criterio

Pieza 4 · frontend-design, el criterio

Y debajo de todo va frontend-design, una skill publicada por Anthropic. Le pone criterio: jerarquía, espaciado, tipografía, cuándo una decisión visual es intencionada y cuándo es la de siempre.

Las skills son carpetas con instrucciones que Claude carga cuando le hacen falta.

git clone --depth 1 https://github.com/anthropics/skills.git /tmp/sk && cp -r /tmp/sk/skills/frontend-design ~/.claude/skills/
ls ~/.claude/skills/frontend-design

Qué aporta que no aporten las otras tres

Las otras tres te dan material. Ésta te da criterio sobre el material, y es la diferencia entre una página con componentes buenos y una página bien compuesta.

En concreto es la que hace que no salga el aspecto genérico: te empuja a elegir una paleta que venga del tema, a emparejar dos tipografías con intención, y a que la estructura de la página diga algo sobre el contenido en vez de ser la retícula por defecto.

Con las tres primeras

Componentes correctos, animaciones bonitas, y una página que se parece a otras cincuenta. Nada está mal y nada es memorable.

Con las cuatro

Las mismas piezas, colocadas con una intención que se puede explicar. Se nota sobre todo en el espaciado y en la tipografía, que es donde vive el oficio.

La regla

Una nota sobre licencias, porque se generaliza y no toca: en ese repositorio la

licencia va por skill, no en la raíz. frontend-design es Apache-2.0. Otras

del mismo repositorio no son código abierto. Si esto va a una empresa,

compruébalo skill a skill.

07 manos a la obra

El montaje, en orden

  1. Los ojos

    Instala Playwright en el proyecto y escribe el medidor. Compruébalo ejecutándolo contra tu página: si imprime números, ya tienes ojos.

  2. Los ladrillos

    Arranca el MCP de shadcn. Comprueba pidiéndole que liste los componentes disponibles: si te los enumera, está conectado.

  3. El movimiento

    Añade Magic UI. Si el MCP no responde, sigue con la librería directamente y no pierdas la tarde: es la pieza más prescindible de las cuatro.

  4. El criterio

    Copia la skill a tu carpeta de Claude y comprueba con ls que está. Sin comprobarlo no hay error: simplemente no se carga y tú no te enteras.

  5. La prueba de que funciona

    Pídele una pantalla y NO le digas qué está mal. Que la escriba, la abra, la mida y la corrija solo. Si hace ese bucle sin ti, el montaje está bien.

claude mcp list

Aquí hay una arruga que despista, y prefiero avisarte antes de que la veas. Los tres no salen en la misma lista. Los dos que has añadido con claude mcp add van a tu ámbito de usuario y aparecen siempre. El de shadcn no: shadcn mcp init --client claude escribe en el .mcp.json del proyecto, y los servidores de proyecto Claude Code te los pregunta al arrancar la sesión en esa carpeta antes de conectarlos.

Así que si shadcn no aparece, mira dos cosas antes de tocar nada: que estás ejecutando el comando dentro de la carpeta del proyecto, y que aceptaste el aviso de aprobación cuando abriste la sesión. No es que esté mal instalado, es que vive en otro sitio.

Nota

No te copio aquí la salida

La lista depende de lo que tengas montado tú, y he decidido que en esta bitácora

no se publica ninguna salida de terminal que yo no haya ejecutado. Escribir

tres palomitas de memoria es exactamente la forma de que alguien dé por buena

una instalación rota. Lo que tienes que ver es tu propia lista con playwright

y magicui conectados; shadcn, por lo de arriba, puede que no esté ahí.

08 cómo se usa

El bucle, que es todo el punto

Con las cuatro montadas, el trabajo cambia de forma. Ya no le dices «el botón está pegado al borde». Él escribe, abre la página, ve que el botón está pegado al borde y lo mueve. Y repite hasta que aquello se ve bien.

El prompt que enciende el bucle

Monta la pantalla que te he descrito. Y después, sin que yo te diga nada:

1. Abre la página con el medidor de Playwright a 390 y a 1440.
2. Comprueba, con números y no de vista:
   - que la página no desborda a lo ancho en ninguno de los dos tamaños
   - que ningún objetivo pulsable baja de 44px en el lado corto
   - que el texto principal contrasta 4,5:1 o más contra su fondo
   - que ningún bloque de texto pasa de 70 caracteres por línea
3. Si algo falla, arréglalo y vuelve a medir. **Máximo tres pasadas.** Si a la
   tercera queda algún número sin cumplir, PARA y dime cuál es, qué valor da y
   qué has intentado. No sigas dando vueltas.
4. Cuando esté, enséñame la captura y la tabla de medidas. No me cuentes lo
   que has hecho: enséñame los números.

Si algo no se puede medir con el script, dímelo en vez de darlo por bueno.

Por qué el punto 4 importa tanto

Porque «ya está arreglado» no es una comprobación. Lo he visto fallar de las dos maneras: dar por corregido algo que no lo estaba, y corregir una cosa rompiendo otra que ya no volvió a mirar. Pedir la tabla de medidas cierra las dos puertas.

Las cuatro medidas que cazan casi todo

Qué se mideUmbralDe dónde saleQué caza
Desbordamiento horizontal0 pxNo hay norma: o desborda o noEl fallo más común en móvil
Objetivo pulsable44 px de ladoApple, guías de interfaz humanaBotones e iconos demasiado pequeños
Contraste de texto4,5:1WCAG 2.2, nivel AAGris sobre gris, que se ve bien en tu pantalla
Ancho de línea70 caracteresTipografía clásica, no una normaPárrafos imposibles de leer en escritorio

Los umbrales llevan fuente a propósito, porque dos de los cuatro son una elección mía y conviene que lo sepas. Los 44 px son de Apple; Android pide 48 y WCAG solo los exige en nivel AAA —su AA de la 2.2 se conforma con 24×24—. Y los 70 caracteres no son de ninguna norma: son tipografía de toda la vida. El único que es una regla de accesibilidad de verdad, y el que yo no negociaría, es el 4,5:1.

Con esas cuatro y el bucle corriendo solo, el noventa por ciento de lo que se enseña en una revisión de diseño ya está resuelto antes de que tú mires.

09 honestidad

Lo que sigue saliendo mal

El gusto no se instala. Estas cuatro piezas evitan los fallos y dan coherencia. No van a producir una identidad visual que emocione a nadie. Eso sigue siendo trabajo de diseñador, y decir lo contrario sería vender humo.

El contraste sobre una imagen no se puede medir así. El medidor lee el color de fondo declarado y compone las capas translúcidas, y con eso acierta en fondos planos. Pero si el texto va encima de una foto, de un degradado o de un vídeo, no hay color de fondo que leer: el número que salga no significa nada. Ahí se mira a ojo, y con el peor fotograma de la imagen, no con el mejor.

Los estilos calculados no lo cuentan todo. Un :hover no se dispara solo, y el foco por tabulación tampoco. Lo que está declarado se puede leer; lo que solo existe mientras interactúas, hay que provocarlo a propósito.

La zona segura del móvil no se puede medir en un navegador sin cabeza. El espacio del indicador de inicio del iPhone resuelve a cero, y ahí no se puede distinguir «funciona» de «vale cero». Eso hay que mirarlo en un teléfono real, y no hay vuelta.

La tipografía real cambia por plataforma. Lo que mides con la fuente del sistema en un equipo no es lo que verá alguien en otro. Los anchos de texto medidos son orientativos, no exactos.

OjoNinguna herramienta sustituye un móvil de verdad

Si una guía te promete que con esto ya no necesitas mirar la web en un móvil de

verdad, esa guía no ha probado nada en un móvil de verdad.

10 qué esperar

Qué esperar la primera semana

Enseguida: desaparecen los fallos tontos. Nada desborda, los botones se pueden pulsar, el contraste se cumple. Eso se nota en la primera pantalla.

A los pocos días: la coherencia. Como los componentes salen del mismo sitio, la tercera pantalla se parece a la primera sin que nadie lo haya vigilado.

Nunca: la sorpresa. Una web montada así queda correcta, limpia y sin errores. Para que además tenga personalidad hace falta una decisión que ninguna de las cuatro herramientas va a tomar por ti: elegir una dirección y sostenerla aunque sea incómoda.

Y ahí, otra vez, la ventaja es tener escrito por qué elegiste lo que elegiste. Lo cual es exactamente lo que monta la guía hermana de esta bitácora.

11 el catálogo

Los seis fallos que caza el bucle, uno a uno

Esto no es teoría: son los que aparecen una y otra vez, con el motivo por el que son invisibles leyendo el código.

1 · La página desborda a lo ancho en móvil

El más común con diferencia. Una tabla, un bloque de comando o una imagen que no cabe empuja el documento entero y aparece una barra horizontal que nadie quiere.

Por qué no se ve leyendo: el elemento culpable no tiene nada raro. El problema es la suma, y la suma solo existe al renderizar.

Cómo se arregla mal: poniendo overflow-x:hidden en el cuerpo. Eso no lo arregla, lo esconde: el contenido se sigue saliendo, solo que ya no se ve ni se puede alcanzar. Un desbordamiento invisible es peor que uno visible, porque nadie lo reporta.

Cómo se arregla bien: el scroll va en el contenedor acotado, y el hijo lleva width:max-content para tener qué arrastrar.

La regla del scroll acotado

Cuando algo no quepa a lo ancho —una tabla, un bloque de código, un diagrama—:

- El contenedor lleva overflow-x:auto y min-width:0.
- El hijo lleva width:max-content y min-width:100%.
- NUNCA overflow-x:hidden en html, body ni en el contenedor de la página.

Y compruébalo con dos números, no de vista:
- que el CONTENEDOR desborda por dentro (scrollWidth > clientWidth)
- que la PÁGINA no desborda (documentElement.scrollWidth === clientWidth)

Si solo compruebas el segundo, esconder el problema pasa el examen.

2 · El objetivo pulsable mide bien de alto y mal de ancho

Un icono de 44 de alto y 29 de ancho pasa cualquier revisión que solo mire una dimensión. Se mide el lado corto, siempre.

3 · Un svg sin tamaño se come a su padre

Un <svg> sin width ni height se estira hasta el tamaño del contenedor. En una tarjeta puede ocupar doscientos píxeles y no da ningún error. Todo icono lleva tamaño, sin excepción.

4 · El texto gris sobre fondo gris

Se ve perfectamente en tu pantalla buena, en una habitación con buena luz. No se ve en un móvil al sol. Por eso el contraste se mide con un número y no con la vista: 4,5:1 para texto normal, 3:1 para texto grande y para gráficos que significan algo.

5 · La segunda hoja de estilos

La que me tocó a mí. Dos archivos de CSS correctos por separado, cargados en un orden que hace que uno pise al otro. El código está bien y el resultado está mal, que es la definición exacta de lo que solo se ve renderizando.

6 · El componente usado a medias

Un componente diseñado para llevar su contenido dentro de un elemento concreto, usado sin ese elemento. Las clases están, la regla está, y el color no aplica porque vive un nivel más abajo. Es el fallo más frustrante porque el código parece correcto y lo es: lo que está mal es el marcado, no el estilo.

OjoLo que comparten los seis fallos

Los seis tienen algo en común: ninguno produce un error. La página carga, la

consola está limpia y todo parece bien. Por eso hace falta medir, y por eso los

ojos van primero.

12 el criterio propio

Cómo se le dan instrucciones de diseño que sí se cumplen

La skill de Anthropic pone criterio general. Lo que no puede poner es tu criterio: tus colores, tu tipografía, tus decisiones. Eso va en las instrucciones del proyecto, y hay una forma de escribirlas que funciona y otra que no.

Lo que no funciona

Veinte reglas de estilo, muchas de gusto y algunas contradictorias entre sí. Se cumplen las tres primeras y las demás se diluyen sin que nadie avise.

Lo que sí funciona

Cuatro o cinco reglas, cada una con su POR QUÉ y con un número cuando se pueda. Un número no se interpreta.

El bloque de diseño para tu proyecto

## Diseño

Cada regla lleva su motivo. Si una regla choca con otra, gana la que esté
antes en esta lista.

1. UN SOLO acento por pantalla. El acento es <tu color>. Si aparece dos
   veces compitiendo, deja de señalar y pasa a decorar.

2. La prosa se lee a 65 caracteres por línea como máximo. En una columna
   ancha, el texto se estrecha DENTRO; no se ensancha la columna.

3. Los radios son tres y solo tres: 6px campos y botones, 8px tarjetas,
   12px contenedores grandes. Cualquier otro valor es un descuido.

4. El anillo de 1px va como box-shadow, no como border. Un border cambia
   la caja y desplaza el contenido; un box-shadow no.

5. Nada se declara solo dentro de una consulta de medios ni de un tema.
   Todo color se define primero en la raíz y se REDEFINE después. Un color
   que solo existe en modo oscuro deja la página ilegible en claro, y no
   da ningún error.

Antes de dar una pantalla por terminada, mídela y enséñame los números.

La regla 5 merece un párrafo aparte

Es la que produce el fallo más caro y menos evidente: una página que se ve perfecta en tu equipo y completamente ilegible en el de otro, porque el color del texto solo estaba definido en un tema y el fondo en el otro.

La comprobación es de diez segundos: busca en tu hoja cualquier color cuya única definición esté dentro de un bloque de tema o de una consulta de medios. Si hay alguno, ése es tu próximo error.

13 dudas

Preguntas que salen siempre

¿Hace falta instalar las cuatro?

No. Playwright y la skill de criterio son las dos que cambian el resultado; las otras dos son comodidad. Si solo vas a poner dos, pon ésas.

¿Sirve esto si no uso React?

Playwright y la skill, sí: son agnósticas. shadcn y Magic UI están hechos para React con Tailwind. Con otro montaje, el bucle de medir y corregir funciona exactamente igual; lo que cambia es de dónde salen los componentes.

¿Puedo usarlo sobre una web que ya existe?

Es donde más rinde. Apunta el medidor a tu web actual a 390 y a 1440 y mira los cuatro números. Casi nadie pasa los cuatro a la primera, y las correcciones suelen ser pequeñas.

¿Me va a rediseñar la web entera sin permiso?

Solo si se lo pides así. En el prompt del bucle, la instrucción de enseñar la tabla antes de dar nada por bueno es la que mantiene el control. Un bucle que corrige solo necesita un punto donde te enseñe qué ha hecho, o acabas revisando cincuenta cambios de golpe.

¿Y si el MCP de Magic UI no arranca?

Sigue sin él. Es la pieza más prescindible de las cuatro y llevaba meses parada la última vez que se comprobó. La librería funciona igual instalando los componentes a mano.

Las fuentes, para que lo compruebes tú

Nada de esta guía se cita de memoria. Cada enlace se abrió y se comprobó el día que se escribió: qué es, qué licencia tiene y si sigue mantenido. Si algo de aquí ya no cuadra, gana la fuente.

¿Y esto en tu empresa?

Esto que acabas de leer es formación y herramientas, y en tu empresa tendrá otra forma. Si quieres, lo miramos sobre tu proceso: media hora basta para saber si hay algo que automatizar o si se arregla ordenando lo que ya tienes.

Ver las sesiones
Fuentes

Revisada el 2026-08-31. Publicada el 2026-08-31.

De esto hablo en mi Instagram, donde lo cuento en un minuto.

Sigue por aquí

Claude no se olvida: Obsidian como su memoria

Montar una bóveda que Claude lee y escribe solo, para dejar de contarle tu proyecto cada mañana.

Cinco repos que valen más que el curso de IA

Cinco repositorios abiertos, el orden para instalarlos en una tarde y qué sabrás hacer al final.