Build this mobile app now based on the specification below.
The app must be mobile-first and responsive.
Set the HTML <title> element (and any document.title assignments) to exactly: "Made with App Studio".
Name: Memory game
Specification:
PRD: Memory Game (Memorama)
Overview
Aplicación móvil de juego de memoria (Memorama) en español. Un solo jugador voltea cartas en un tablero 4×4 para encontrar pares iguales. El juego termina cuando todas las cartas están emparejadas. Ideal para pasar el rato y ejercitar la memoria.
Core Features
Tablero de juego
- Tablero de 4×4 (8 pares de cartas).
- Las cartas se distribuyen aleatoriamente al inicio de cada partida.
- Temas variados en las cartas: animales, frutas, emojis, banderas, números, etc. — cada partida puede usar un tema diferente, seleccionado aleatoriamente o por elección del usuario.
Mecánica de juego
- El jugador toca una carta para voltearla y revelar su contenido.
- Luego toca una segunda carta para intentar formar un par.
- Si las dos cartas son iguales, permanecen descubiertas (boca arriba).
- Si son diferentes, ambas se voltean de nuevo tras un breve momento.
- El juego continúa hasta que todos los pares han sido encontrados.
Contadores y finalización
- Contador de movimientos: muestra el número total de intentos (pares volteados) realizados.
- Cronómetro: tiempo transcurrido desde el inicio de la partida.
- Cuando se completan todos los pares, se muestra una pantalla de victoria con el resumen (movimientos y tiempo).
Selección de tema
- Opción para elegir el tema de las cartas antes de empezar (animales, frutas, emojis, etc.).
- Si no se selecciona, se asigna un tema aleatorio.
Content
Textos
- Todo el texto de la interfaz (botones, instrucciones, mensajes de victoria, etiquetas) está en español.
- Ejemplos: "Voltear", "Pares encontrados", "Movimientos", "Tiempo", "¡Ganaste!", "Nueva partida", "Elegir tema".
Temas de cartas
Cada tema contiene 8 imágenes o íconos distintos (uno por cada par). Los temas incluidos son:
- Animales (perro, gato, elefante, león, etc.)
- Frutas (manzana, banana, uva, fresa, etc.)
- Emojis (😀, 🐱, 🚀, ⭐, etc.)
- Banderas (🇲🇽, 🇪🇸, 🇺🇸, 🇧🇷, etc.)
- Números (1, 2, 3, 4, 5, 6, 7, 8)
Visual Style
- Diseño colorido y amigable, adecuado para móviles.
- Las cartas tienen un dorso atractivo (ej. patrón o color sólido) y un frente con el contenido del tema elegido.
- Animación suave al voltear las cartas (efecto de giro).
- Botones grandes y fáciles de tocar en pantalla táctil.
- Fondo limpio y alegre, con colores que contrasten bien con las cartas.
Non-Features (explícitamente no incluidos)
- No hay multijugador ni modo contra reloj.
- No hay guardado de partidas ni progreso entre sesiones.
- No hay puntuaciones altas ni historial de partidas.
Look good — should I start building this Memory Game for you?
The specification above is final and approved. Implement the app now in code. Do not ask for confirmation, do not summarize what you will build, do not ask follow-up questions.
CRITICAL: Do not modify, remove, or bypass the Pi Network SDK and authentication integration that ships with this template. The app must always initialize the Pi SDK and authenticate the user via Pi on startup. Do not add code that disables, mocks, or skips Pi authentication.
AUDIENCE: The creator reading your chat messages is non-technical. Use the technical details in these instructions only to write the code — never repeat them to the creator. In your messages do NOT mention code, function, hook, API, package, or file names (for example usePiAuth, sdk.state, sdk.userState, lib/pi.ts) or any SDK internals. Describe what you did in plain, general language — e.g. "I'll save the player's progress to their Pi account so it's there next time", not the function or API used.
DATA PERSISTENCE: Store any per-user data that must survive a page reload or a new session (game progress, scores, settings, preferences, saved state of any kind) using the Pi user-state storage that ships with this template. Do NOT use localStorage, sessionStorage, IndexedDB, or cookies for persistent user data — those are per-device and are not durable for Pi users.
Use the Pi SDK instance this template already provides — auth and the backend are already wired, so never create a new SDK or set a backend URL. Obtain the instance whichever way this project exposes it:
- If the app loads SDKLite, the instance is: const sdk = await window.SDKLite.init();
- If the app uses the @pi-sdk packages, import the configured instance: import { pi as sdk } from "@/lib/pi";
The user-state API is identical on either instance:
await sdk.userState.set("save", { level: 4, coins: 120 }); // upsert a JSON object under a key
const record = await sdk.userState.get("save"); // -> { blob, updatedAt, version } | null
await sdk.userState.delete("save"); // remove a key
Design around the limits the storage backend enforces:
- Keys: lowercase letters, digits, ".", "_", "-" only; max 64 characters. Use one key per logical slice of state.
- Each value is a JSON object up to 64 KB, nested at most 4 levels deep.
- Up to 64 keys per user, and 128 KB total per user.
- Writes are rate limited (about 1 write / 5s per key, and 1 write / 2s across all keys): debounce and batch saves; never write on every keystroke, drag, or animation frame.
- get() resolves to null when a key has never been written — treat that as a fresh start with sensible defaults.
- A save can be rejected — handle it WITHOUT losing the player's progress: keep the last good state in memory, show a brief non-blocking notice (never wipe the UI or reset progress), and let them keep playing. Retry rate-limited saves with backoff. If the user's own storage is full, let them free space by removing old keys with sdk.userState.delete(...) (list them with sdk.userState.keys()).
- Treat loaded state as untrusted input: render values as text (never via dangerouslySetInnerHTML) and don't merge stored keys into objects/prototypes.