empezó con frailecillos
Lovund tiene una de las colonias de frailecillos más grandes de Noruega, así que en cuanto tuve la montaña lista se sentía mal no poner un frailecillo cerca. Dibujé un pequeño frailecillo en pixel art, le di una ruta de vuelo lenta cruzando la cabecera, y recargué la página unas treinta veces solo para verlo volar.
Entonces pensé, bueno, un solo pájaro se ve un poco solitario.
y luego no paró
Añadí una gaviota. Luego otra gaviota que vuela distinto. Luego me dejé llevar un poco: un ostrero caminando por lo que básicamente es la orilla, un charrán haciendo movimientos rápidos y bruscos en vez del planeo lento de las gaviotas, un cormorán posado bajo sobre el agua, y un águila marina que es más grande y más rara, aparece mucho menos que el resto.
Cada especie recibió su propio tamaño, velocidad y frecuencia de aparición real. El águila marina en particular la dejé bastante poco común, se sentía justo para un pájaro tan grande.

el tope, porque se volvió una tontería
En un momento lo tenía generando pájaros con bastante libertad, y recargar la página me daba algo como quince pájaros peleando por el espacio aéreo sobre una cabecera pequeña. Parecía más una película de Hitchcock que un blog costero. Le puse un pequeño límite integrado directamente en el propio dibujo:
const guaranteed = CANDIDATES.find((c) => c.guaranteed)!;
const rest = CANDIDATES.filter((c) => !c.guaranteed);
const shuffled = [...rest].sort(() => rand() - 0.5);
const extraCount = 2 + Math.floor(rand() * 3); // 2-4
const chosen = [guaranteed, ...shuffled.slice(0, extraCount)];peces, y una confusión que fue cosa mía
También añadí peces bajo la línea de agua, pequeñas formas de píxeles nadando de un lado a otro por debajo de donde vuelan los pájaros. Al principio tuve un bug donde uno de los "pájaros" en realidad se renderizaba por debajo de la capa de la línea de agua, y pasé unos buenos diez minutos confundido sobre por qué un pájaro parecía estar nadando. Resultó que nunca había fijado cada capa a su propia franja:
// first pass: one shared list, whatever top value felt right per sprite
const sprites = [...birds, ...fish].map((s) => ({ ...s, top: s.top }));Nada impedía que el top de un pájaro cayera por accidente debajo de la línea de agua, ya que todos eran solo números en el mismo montón. Lo arreglé fijando cada capa a su propia franja en vez de confiar en lo que fuera que hubiera escrito:
// row 3's top edge, 60% down the strip's own height, is literally
// "the waterline" in this layer's own geometry. Humans stand in the
// land band (top 0-60%); fish swim in the sea band (top 60-100%).
//
// Caps: fish <= 3 (here: 3), humans <= 2 (here: 2 -- one standing, one
// running).Arreglado ya, los pájaros vuelan, los peces nadan, cada uno se queda en su carril.
También colé un pequeño corredor de píxeles trotando por la orilla. Mitad broma, mitad simplemente ponerme yo mismo en la escena, ya que correr es algo que de verdad hago aquí en la isla.
Cada recarga mezcla qué pájaros aparecen, cuántos peces, dónde está el corredor. Cosa pequeña pero hace que la cabecera se sienta viva en vez de estática, que era todo el punto.