Imagen del inicio de sesión de la web

Juego - 2026

HEART­SWEEPER


¿De qué trata?

HeartSweeper es una reinterpretación del clásico buscaminas: en vez de minas, corazones ocultos. El objetivo, descubrir todo el tablero sin destaparlos.

No es solo un ejercicio de UI. Es un proyecto que ha vivido dos vidas: nació en JavaScript vanilla como ejercicio de lógica de juego, evolucionó hacia una aplicación full-stack con ranking global persistente, y más tarde lo reconstruí por completo en React para consolidar fundamentos del framework diseñando y desplegando, de nuevo desde cero, su propia API serverless independiente.


  1. Lógica de juego no trivial.El revelado en cascada de celdas vacías exige un algoritmo de flood fill recursivo que calcule en tiempo real los corazones vecinos y determine cuándo se cumplen las condiciones de victoria o derrota.
  2. Persistencia real, no local.Un ranking en localStorage se pierde al cambiar de dispositivo. Quería puntuaciones globales, siempre disponibles, sin montar un backend tradicional con servidor y base de datos gestionados.

v1 - JS vanilla (Buscacorazones)

La primera versión nació como ejercicio de lógica pura: generación de tablero, colocación aleatoria según dificultad, apretura en cascada, detección de victoria/derrota. Con el tiempo creció hacia una app full-stack real:

Por qué migrar a React

No fue por necesidad técnica del proyecto, la versión JS ya funcionaba en producción con su propia API. Fue una decisión de aprendizaje deliberada: quería consolidar fundamentos de React (gestión de estado, lifting state, separación de lógica pura y efectos secundarios) construyendo desde cero, sin plantillas, y aplicando de nuevo lo aprendido sobre backends serverless para diseñar y desplegar una segunda API independiente, propia de esta versión.

v1 vs v2 - Comparativa

v1 - JS vanilla v2 - React 19
Renderizado Manipulación directa del DOM Componentes declarativos + estado
Gestión de estado Variables globales / closures Lifting state hacia Game como fuente de verdad
Estilos Sass Sass (SCSS) + CSS custom properties inyectadas desde JSX
UX feedback SweetAlert2 Modal propio + animación de corazones al ganar
Backend Supabase migrado a Cloudflare Workers + D1 (API propia) Cloudflare Workers (segunda API propia, independiente de la de v1)
Punto fuerte Control total, cero dependencias de framework, demuestra fundamentos puros de JS Código más mantenible y escalable, lógica de juego desacoplada de la UI
Punto débil Lógica y renderizado más entrelazados, refactors más costosos Curva de configuración inicial de React/JSX/build tooling

Prueba las dos versiones


Frontend (React19 + Vite)

Backend (Cloudflare Workers)


Tecnologías utilizadas.

v2 - React

v1 - JS


Lo que aprendí.

El proyecto no llegó a implantarse en el hotel real porque la dirección descartó la inversión, pero el proceso de desarrollo generó aprendizajes técnicos concretos que puedo defender en cualquier entrevista:

01

Estado compartido sin caos: lifting state bien pensado

En una app de tamaño mediano es fácil caer en prop drilling excesivo o en estado duplicado entre componentes. Elevé el estado compartido (celdas abiertas, cronómetro, fin de partida, ranking) al componente Game, que actúa como única fuente de verdad. El resultado: un flujo de datos predecible y componentes hijos que reciben solo lo que necesitan, sin acoplarse entre sí.

02

Separar lógica pura de efectos secundarios

El flood fill del tablero vive en una función pura expandirCelda completamente aislada de React; la actualización de estado vive en revealCell. Esta separación no es un detalle estético: significa que la lógica de juego se puede razonar, testear y depurar sin necesidad de montar componentes ni simular el ciclo de vida de React, algo que se nota especialmente cuando hay que localizar un bug de cálculo en el tablero.

03

Diseñar una API REST propia, no solo consumirla

Más allá de hacer fetch a un endpoint, diseñé el esquema de datos, los endpoints POST/GET /api/scores y las reglas de vvalidación de una API ligera desplegada en Cloudflare Workers. Desacoplé además la lógica de red del resto de la app en un módulo dedicado scoresApi.js, de forma que cambiar de backend en el futuro no debería tocar ni un componente de la interfaz.

04

Migrar arquitectura en producción sin romper nada

En la versión anterior del proyecto, sustituí un backend basado en Supabase por una API propia sobre Cloudflare Workers + D1, sin que el frontend que la consumía dejara de funcionar en ningún momento. No fue un simple cambio de proveedor: implicó rediseñar el esquema de datos, versionar migraciones SQL y justificar la decisión más allá de "hacer que funcione" evaluando trade-offs realies entre un BaaS y una solución serverless propia.

05

Algoritmia de juego aplicada a un problema real

Destrás de un juego aparentemente sencillo hay un algoritmo de flood fill recursivo que calcula en tiempo real los corazones vecinos de cada celda, genera el tablero de forma procedural según la dificultar elegida, y determina con precisión cuándo se cumplen las condiciones de victoria o derrota. Un buen ejemplo de cómo un problema clásico de algoritmia se traduce en código de producción.

06

Despliegue continuo, no solo código en un repositorio

El proyecto está desplegado en Vercel con integración directa desde el repositorio: cada git push actualiza la app en producción. Tener el hábito de desplegar desde el primer commit, en lugar de dejarlo para el final, permitió detectar problemas de producción pronto y tratar el despliegue como parte del desarrollo, no como un paso posterios.