← Todos los prototipos

memory-cards

borrador

Juego de memoria tipo concentración con cartas clásicas de 5:7: empareja fotos de Picsum, con dorsos CSS nítidos o repetidos, aleatorizador de dorso compartido y modo psicodélico. Creado como componente de Alpine.js.

Tipo: alpine copia

Configuración y uso (desde ABOUT.md)

Cartas de memoria

Un juego de emparejamiento de cartas (concentración) autocontenido sobre clásicas cartas verticales de 5:7: voltea dos cartas por turno y encuentra cada pareja de fotos antes de que se acabe el tiempo. Los dorsos son CSS puro — patrones repetidos nítidos (ajedrezado, rayas, diagonales, zigzag, cuadrícula de puntos, cuadrícula de líneas cruzadas) junto con degradados suaves (aurora, mándala, olas) — pintados desde la propiedad personalizada --mg-back-hue y controlados por un número registrado con @property para que los cambios de color se animen. Uniformes en todo el tablero, realeatorizados en cada reparto, o repartidos como un mosaico psicodélico por carta.

Qué incluye

  • Un componente Alpine.js, sin paso de compilación. La raíz es x-data="memoryGame()" con x-init="deal()"; un pequeño script de fábrica expone window.memoryGame() con solo la lógica del juego, mientras que toda la interfaz son bindings de Alpine — mazo x-for, estadísticas x-text, superposición/alternativa de victoria x-show, controles x-model, estados de volteo :class. Todo lo visual es CSS: los dorsos son reglas .mg-back--* basadas en --mg-back-hue, la cuadrícula del tablero es una clase .mg-board--hard, y el confeti cae mediante una capa container-type: size — así que JS no calcula ninguna imagen de fondo, cuadrícula ni medición. Las mejores puntuaciones se guardan con la magia $persist de Alpine. La página anfitriona solo necesita Alpine.js cargado (las aplicaciones Livewire, que incluyen Alpine y el plugin persist, ya lo tienen).
  • Tres dificultades — Fácil (4×3, 6 parejas), Media (4×4, 8 parejas), Difícil (6×4, 12 parejas).
  • Estadísticas — movimientos, parejas encontradas, cronómetro en vivo. El mejor tiempo por dificultad se guarda con $persist de Alpine (clave de localStorage memory-cards-best, que contiene un mapa por dificultad).
  • Patrones de dorso — un selector Backs (Aleatorio / Aurora / Mándala / Olas / Ajedrezado / Rayas / Diagonales / Zigzag / Puntos / Cuadrícula). Cada diseño es una regla CSS (.mg-back--*) pintada desde la variable --mg-back-hue; el tono se registra con @property como un <number>, por lo que cada barajado/reparto desliza los colores hacia la nueva paleta durante 600 ms en lugar de saltar. En modo compartido, Aleatorio elige un diseño + tono nuevos para todo el tablero en cada reparto, y el botón 🎲 Barajar dorsos realeatoriza el dorso compartido sin reiniciar una partida en curso. El conmutador Dorsos psicodélicos reparte en cambio un mosaico de diseño + tono aleatorios por carta (congelado en el momento del reparto para que Alpine nunca vuelva a ejecutar la aleatoriedad al re-renderizar).
  • Los cambios de diseño son discretos. @property anima el barrido de color (tono); cambiar entre diseños cambia background-image al instante, ya que las distintas pilas de degradados no son interpolables. El deslizamiento de color disimula bien el salto, pero no espere que los patrones se transformen.
  • Origen de las imágenes — solo Picsum (picsum.photos/seed/memory-<id>/240/336). La semilla es determinista, así que las dos cartas de una pareja siempre resuelven a la misma foto; 240×336 coincide con la proporción 5:7 de la carta. Si una imagen de carta no carga, se recurre a un emoji de marcador de posición — las parejas nunca se rompen.
  • Cartas accesibles — cada carta es un <button> con aria-pressed, y un bloque de crédito visible acredita el servicio de imágenes (regla del proyecto).
  • Cadenas traducidas — las etiquetas estáticas usan __() del sistema de locale de la aplicación anfitriona (véase lang/es.json); las estadísticas reactivas (movimientos/parejas/mejor/victoria) leen un bloque window.mgI18n emitido por el Blade antes del script del juego, de modo que todo el juego se renderiza en el locale de la aplicación y recurre al inglés si el bloque no existe.

Configuración

  1. Pegue el marcado renderizado de resources/views/prototypes/memory-cards.blade.php en un componente Blade en resources/views/components/games/memory-game.blade.php (ajuste copy-to como desee), o pegue el HTML interno directamente en cualquier plantilla.
  2. La aplicación anfitriona debe tener Tailwind CSS v4, daisyUI 5 y Alpine.js cargados (clases de diseño, tokens de tema como btn, card, badge, base-*, y Alpine para el componente x-data). Las aplicaciones Livewire 3 ya incluyen Alpine.
  3. Listo — sin paquetes, sin entrada de Vite, sin bundle JS.

Advertencias

  • Alpine es obligatorio. A diferencia de un widget de JS puro, el juego necesita Alpine.js en la página — el mismo requisito que el prototipo Flat Card. Si falta Alpine, el marcado se renderiza inerte.
  • Compatibilidad con @property. El barrido de color animado necesita navegadores con CSS @property (Chrome 85+, Safari 16.4+, Firefox 128+). Los navegadores antiguos siguen renderizando cada dorso correctamente — el tono simplemente cambia al instante en lugar de transicionar.
  • Unsplash. El antiguo endpoint gratuito source.unsplash.com está obsoleto y muerto desde 2023 — no lo use. Para fotos reales de Unsplash, use la API de Photos oficial (necesita una clave de acceso); conéctela a la expresión de plantilla :src (picsum.photos/seed/memory-<id>/240/336) si la quiere como origen adicional.
  • Protección contra hotlinking. Picsum es fiable, pero fije las imágenes con referrerpolicy="no-referrer" (ya está configurado) para que los proxies que bloquean hotlinks no puedan rechazarlas, y mantenga el emoji alternativo para casos extremos (sin conexión, 5xx transitorios).
  • Script/style en línea. El juego depende de un <script> en línea (define window.memoryGame) + un <style> con ámbito. Si la página anfitriona establece una Content-Security-Policy estricta que bloquea scripts o estilos en línea, mueva los dos bloques a su build y mantenga el global window.memoryGame disponible antes de que Alpine se inicialice.
  • Re-renderizados de Livewire/SPA. Como el juego es un componente Alpine real, Alpine lo reinicializa automáticamente siempre que [data-memory-game] entra en el DOM — no hace falta reenlazar manualmente. La protección contra el doble arranque está integrada en el ciclo de vida de los componentes de Alpine.
  • El almacenamiento de la mejor puntuación usa $persist de Alpine, que recurre con elegancia al almacenamiento temporal (en memoria) cuando localStorage no está disponible (navegación privada) — sin mejor puntuación, sin fallo.
  • $persist debe crearse en una expresión de Alpine, no dentro de la fábrica. Las magias de Alpine solo se resuelven dentro del evaluador with (scope) de atributos como x-data; el cuerpo de una función normal (como window.memoryGame) se crea en el ámbito global del script, así que referenciar $persist allí lanza ReferenceError: $persist is not defined, memoryGame() falla, y cada binding cae en cascada a "is not defined" — el tablero se renderiza vacío mientras el marcado estático sigue visible. Por eso la raíz lee x-data="memoryGame($persist({...}).as('memory-cards-best'))" y la fábrica no tiene magia: memoryGame = (best) => ({ best, ... }) — el initInterceptors de Alpine inicializa la propiedad interceptor del objeto devuelto por usted.

Vista previa

🧠 Parejas de cartas

Voltea dos cartas y encuentra cada pareja.

0 movimientos 0 / 0 parejas 00:00
🎉

¡Ganaste!

Todas las parejas encontradas en .