píxeles de cerca, suave de lejos

8 de septiembre de 2026 meta designpixelart

Hay dos tipos de dibujo en este sitio y nunca se les permite tocarse entre sí. Esa regla suena pretenciosa cuando la escribo así, pero es lo que realmente hizo que la cabecera y el fondo dejaran de pelear por la atención.

el problema que resuelve

Al principio, todo en la página se dibujaba de la misma manera: sprites en cuadrícula de píxeles, bordes duros, un <rect> de SVG por celda. La montaña de la cabecera, los pájaros, todo. Se veía bien de cerca y completamente plano en cuanto añadías algo pensado para quedar más atrás, como una silueta de fondo detrás de la columna de texto. Los píxeles gruesos que se supone leen como "montaña lejana entre la bruma" no funcionan, la distancia en la visión real es suave, no tosca. Pero ir todo suave en todas partes mataba lo que de verdad me gustaba del pixel art para empezar, que es que se lee como deliberado y hecho a mano en vez de una ilustración vectorial de stock.

El arreglo no fue elegir un solo estilo. Fue decidir, a propósito, qué elementos podían ser nítidos y cuáles podían ser suaves, y no dejar nunca que un elemento se repartiera entre ambos.

cerca: todo lo que miras directamente

Las franjas de horizonte de cabecera y pie de página, los pequeños glifos de navegación junto a cada enlace de sección, la marca de montaña del monograma BMK, el frailecillo del 404, los iconos de luna/sol del interruptor de tema, y cada pájaro y pez que de verdad vuela o nada por el cielo y la orilla. Todo cuadrícula de píxeles. Todo construido de la misma manera: primero esbozo la forma como una cuadrícula ASCII en un comentario al principio del componente, un carácter por celda, antes de escribir una sola línea de SVG:

//   ......................RRR.MM.....................
//   .....................RRRRRMM.....................
//   .....................RRRRRR.....................
//   ....................RRRRRRRR.....................

Esa es la parte de arriba real del horizonte alto de la cabecera, R de roca, . de cielo abierto, M de la luna que solo aparece en modo oscuro. Una vez que la cuadrícula se lee bien como ASCII, la convierto en tramos de <rect> fusionados (las celdas adyacentes del mismo color en una fila se colapsan en un solo rect más ancho en vez de uno por celda, lo que evita que el DOM se hinche en una cuadrícula de 48 columnas) con preserveAspectRatio="none" para que toda la franja se estire y llene su contenedor de borde a borde sin desbordarse nunca en un ancho de ventana raro.

Cerca: el horizonte nítido de la cabecera en cuadrícula de píxeles

lejos: todo lo que debe quedarse atrás

La silueta de la isla de fondo es lo opuesto de todo eso. Es una única forma continua, calcada con curvas Bézier cúbicas a partir de una foto de referencia real que tomé de Lovundfjellet, no esbozada celda por celda:

const MOUNTAIN_PATH =
	'M145,300' +
	'C160,250 175,210 195,180' +
	'C210,158 225,140 240,133' +
	'C258,140 275,155 290,170' +
	'C305,195 320,225 335,260' +
	...

La misma montaña real, el mismo perfil real de dos picos (de hecho calqué primero la versión en píxeles, en las mismas coordenadas exactas de columna y fila, y luego convertí esos puntos de anclaje en curvas suaves para esta pasada en vez de empezar de cero) pero renderizada como una única masa suave en vez de un contorno escalonado. Sentada detrás de la columna de contenido a baja opacidad, se lee como atmósfera, de la forma en que una montaña real se lee cuando hay un pueblo y un tramo de agua entre tú y ella. La capa de constelaciones nocturnas funciona igual, posiciones estelares reales, pero dibujadas como círculos suaves rellenos en vez de cuadrados de píxeles, porque un campo de estrellas "lejano" hecho de puntos de píxel duros se vería como un bug, no como un cielo.

Lejos: la misma montaña como silueta suave detrás de la columna de contenido

por qué importa la línea

La regla a la que me atengo es que nada se reparte entre los dos registros. Un sprite de pájaro es o bien un pájaro de celda de píxel volando por la capa cercana o una silueta suave sobrevolando la isla de fondo, nunca mitad de cada cosa. En el momento en que los mezclas dentro de un elemento, tu ojo no puede decidir a qué distancia se supone que está la cosa, y toda la ilusión de profundidad se derrumba. Es un truco barato una vez que lo ves: las cosas nítidas se leen cerca, las cosas suaves se leen lejos, y no necesitas paralaje real ni filtros de desenfoque para vender la "distancia," solo necesitas un tratamiento consistente por elemento y no romper nunca tu propia regla a medio camino.

La rompí exactamente una vez, al principio del rediseño, dibujando un pájaro de fondo suave con un par de acentos duros de píxel en la punta del ala porque pensé que "anclaría" un poco la silueta.

<!-- what I tried: smooth silhouette body, pixel-square wingtip accents -->
<path d={SILHOUETTE_PATH} class="soft-fill" />
<rect x="34" y="12" width="2" height="2" class="pixel-accent" />
<rect x="36" y="12" width="2" height="2" class="pixel-accent" />

Simplemente parecía un bug de renderizado, como un recurso que no había cargado bien. Quité los acentos en la misma sesión al volver a mirarlo la mañana siguiente con ojos frescos, de vuelta a una única ruta continua de relleno suave y nada más tocándola.

la parte que no esperaba

Entré en esto pensándolo como un truco puramente visual, cerca contra lejos, primer plano contra fondo. Lo que de verdad me convenció de mantener la regla estricta es que también coincide con cómo funciona la atención en la página. Los elementos del registro cercano son todos cosas que quiero que el ojo de un lector registre de verdad como detalle cercano al contenido, los glifos de navegación que te dicen en qué sección estás, los pájaros que le dan vida a la página. El material del registro lejano es explícitamente decorativo, aria-hidden, pointer-events: none, pensado para sentirse en vez de para mirarse. Mantener los dos visualmente distintos resultó también mantenerlos funcionalmente distintos, cosa que no planeé pero me alegra que haya pasado de todos modos.

el contraste tampoco puede ignorar el fondo

Tener una silueta suave sentada justo detrás del cuerpo de texto más abajo en la página creó una pregunta de accesibilidad real que no había pensado del todo hasta que llegué a comprobarla como es debido: contra qué exactamente se está midiendo el contraste del texto. El fondo de la página aquí es un lavado en gradiente cerca de arriba que se desvanece hacia un tono plano, y la propia sombra de la isla se sienta detrás de texto legible más abajo en la página, así que comprobar el contraste solo contra el color de fondo plano habría sido comprobar completamente la cosa equivocada. Terminé midiendo contra los tonos compuestos reales sobre los que puede renderizarse el texto, el punto más claro del lavado y el color de la sombra de la isla específicamente, usando el cálculo real de luminancia relativa en vez de a ojo, y manteniendo ambos por encima de los mínimos normales de WCAG AA, 4.5 a 1 para el cuerpo de texto, 3 a 1 para texto grande y elementos interactivos. Los tokens puramente decorativos, los marcadores de mes, el color de la roca, la luna, están explícitamente exentos de ese requisito, ya que ninguno de ellos lleva información que no esté ya en texto legible en algún otro sitio de la misma página. La distancia como truco visual es una cosa. La distancia como excusa para dejar que una silueta de fondo destroce la capacidad de un lector de leer de verdad las palabras que tiene delante es otra cosa distinta, y no estaba dispuesto a dejar que la idea de los dos registros fuera la razón de que eso pasara.

0 comentarios

Inicia sesión para comentar.

Iniciar sesión

¿No tienes cuenta?