Cómo hicimos La Pecera de Píxeles
Un pez que crece, se alimenta y usa accesorios, dibujado enteramente por código. Cero imágenes, cero archivos de audio, todo corre en tu navegador.
How we built the Pixel Fish Tank
A fish that grows, eats and wears accessories, drawn entirely in code. Zero images, zero audio files, all running in your browser.
Un pez sin una sola imagen
Todo el pez —cuerpo, cola, aletas, ojo, sombrero, corona— se dibuja con ctx.fillRect(),
rectángulo por rectángulo, en una cuadrícula invisible. No hay ningún archivo .png ni
.svg involucrado. La ventaja: el pez pesa prácticamente cero, y cambiarle el color por
etapa es literalmente cambiar una variable, no editar una imagen.
El truco central es describir cada parte del cuerpo como un perfil de anchos: un arreglo donde cada número dice cuántas celdas de ancho tiene esa fila. Un óvalo, por ejemplo, es angosto arriba, ancho al medio y angosto abajo:
A fish with not a single image
The entire fish —body, tail, fins, eye, hat, crown— is drawn with ctx.fillRect(),
rectangle by rectangle, on an invisible grid. There is no .png or .svg file
involved. The upshot: the fish weighs practically nothing, and changing its colour per stage is
literally changing a variable, not editing an image.
The central trick is describing each body part as a width profile: an array where each number says how many grid cells wide that row is. An oval, for instance, is narrow at the top, wide in the middle, and narrow at the bottom:
const BODY_WIDTHS = [4, 8, 10, 10, 8, 4]; // celdas de ancho, fila por fila
BODY_WIDTHS.forEach((width, row) => {
const startCol = rightEdge - width; // centrado hacia el mismo borde derecho
ctx.fillRect(startCol * CELL, row * CELL, width * CELL, CELL);
});
La cola bifurcada usa el mismo truco, pero dibujando dos puntas separadas por una fila vacía en el medio, justo donde el cuerpo es más ancho —así se ve como una cola de verdad, no como un bloque pegado al costado—.
The forked tail uses the same trick, but draws two separate tips with an empty row between them, right where the body is widest — so it reads as an actual tail fin, not a block glued to the side.
Cómo crece, sin servidor
El pez evoluciona según cuántas veces lo has alimentado, y desbloquea accesorios según cuánto
tiempo real llevas con la pestaña activa —no importa si es hoy o en tres visitas distintas—. Ambos
números se guardan en localStorage, en el navegador de cada persona. No hay base de
datos ni cuenta de usuario: tu pez es tuyo, vive en tu computador.
El tiempo activo se cuenta con cuidado: solo suma mientras la pestaña está realmente visible
(document.visibilityState), para no premiar a alguien por dejar quince pestañas
abiertas en segundo plano.
How it grows, with no server
The fish evolves based on how many times you've fed it, and unlocks accessories based on how much
real time you've spent with the tab active — whether that's today or across three separate visits.
Both numbers are saved to localStorage, in each person's own browser. There is no
database or user account: your fish is yours, it lives on your computer.
Active time is tracked carefully: it only counts while the tab is genuinely visible
(document.visibilityState), so nobody gets credit for leaving fifteen tabs open in the
background.
El efecto de que "sale de la pantalla"
El marco de la pecera usa perspective y rotateX/rotateY de
CSS, ajustados en tiempo real según la posición del mouse. El resultado es que el tanque parece
inclinarse hacia ti, como si flotara delante de la página en vez de estar pegado a ella. Sumamos un
translateZ pequeño y una sombra de color debajo para reforzar la sensación de
profundidad.
En celular, donde no hay mouse, el efecto se desactiva solo —queda plano, sin inclinación—, porque seguirle el dedo a alguien en una pantalla táctil se siente raro, no elegante.
The "popping out of the screen" effect
The tank's frame uses CSS perspective and rotateX/rotateY,
adjusted in real time based on mouse position. The result is that the tank seems to tilt toward you,
as if floating in front of the page instead of glued to it. We add a small translateZ
and a coloured shadow underneath to reinforce the depth.
On mobile, where there is no mouse, the effect turns itself off — it stays flat, no tilt — because following someone's finger on a touchscreen feels odd, not elegant.
Sonido sin un solo archivo de audio
Los sonidos —el splash al alimentar, el "ñam" al comer, la fanfarria al evolucionar— se generan con
la Web Audio API: osciladores que suben o bajan de frecuencia en unos cien
milisegundos, sin depender de ningún .mp3. Es la misma técnica que enseñamos en nuestro
curso de JavaScript, aplicada aquí para algo real.
Sound without a single audio file
The sounds — the splash when feeding, the "yum" when eating, the fanfare when evolving — are
generated with the Web Audio API: oscillators sweeping frequency up or down over a
hundred milliseconds or so, with no .mp3 involved. It's the same technique we teach in
our JavaScript course, applied here for something real.
¿Quieres algo interactivo así, con tu marca? Lo armamos a medida.
Cotizar un proyectoWant something interactive like this, with your brand? We build it to order.
Get a quote