memory-cards
borradorJuego 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.
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()"conx-init="deal()"; un pequeño script de fábrica exponewindow.memoryGame()con solo la lógica del juego, mientras que toda la interfaz son bindings de Alpine — mazox-for, estadísticasx-text, superposición/alternativa de victoriax-show, controlesx-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 capacontainer-type: size— así que JS no calcula ninguna imagen de fondo, cuadrícula ni medición. Las mejores puntuaciones se guardan con la magia$persistde 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
$persistde Alpine (clave de localStoragememory-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@propertycomo 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.
@propertyanima el barrido de color (tono); cambiar entre diseños cambiabackground-imageal 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>conaria-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éaselang/es.json); las estadísticas reactivas (movimientos/parejas/mejor/victoria) leen un bloquewindow.mgI18nemitido 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
- Pegue el marcado renderizado de
resources/views/prototypes/memory-cards.blade.phpen un componente Blade enresources/views/components/games/memory-game.blade.php(ajustecopy-tocomo desee), o pegue el HTML interno directamente en cualquier plantilla. - 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 componentex-data). Las aplicaciones Livewire 3 ya incluyen Alpine. - 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.comestá 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 (definewindow.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 globalwindow.memoryGamedisponible 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
$persistde Alpine, que recurre con elegancia al almacenamiento temporal (en memoria) cuandolocalStorageno está disponible (navegación privada) — sin mejor puntuación, sin fallo. $persistdebe crearse en una expresión de Alpine, no dentro de la fábrica. Las magias de Alpine solo se resuelven dentro del evaluadorwith (scope)de atributos comox-data; el cuerpo de una función normal (comowindow.memoryGame) se crea en el ámbito global del script, así que referenciar$persistallí lanzaReferenceError: $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 leex-data="memoryGame($persist({...}).as('memory-cards-best'))"y la fábrica no tiene magia:memoryGame = (best) => ({ best, ... })— elinitInterceptorsde Alpine inicializa la propiedad interceptor del objeto devuelto por usted.
Vista previa
🧠 Parejas de cartas
Voltea dos cartas y encuentra cada pareja.
¡Ganaste!
Todas las parejas encontradas en .
- Imágenes cortesía de picsum.photos desde Picsum