Quiero armar "la personita": una mascota virtual en pixel art para mi M5StickC Plus2 que hay que cuidar (comida, agua, energía y ánimo) y que además me avisa en la pantalla cuando termina una sesión de Claude Code, con el nombre de la carpeta del proyecto. No sé programar: guíame en español, explícame en 2 o 3 líneas qué vas a hacer en cada paso antes de hacerlo, y avanza de a un paso. - Trabaja SOLO dentro de la carpeta `~/personita` (créala). La única excepción son los pasos 5 y 6, que guardan la clave de los avisos y el aviso de Claude Code en `~/.claude`. - Haz SOLO lo que pide este documento. No agregues funciones, librerías, archivos ni servicios extra. - NUNCA me pidas que escriba la clave de mi WiFi en el chat. Yo la escribo directamente en `secretos.h`. - NUNCA abras puertos del router ni uses servicios en internet para los avisos: todo pasa dentro de mi red de la casa. - Detén el trabajo y pregúntame antes de: instalar algo que no esté en este documento, reemplazar o borrar un archivo fuera de `~/personita`, o subir un programa al M5 por primera vez (reemplaza el programa de fábrica). - Al terminar cada paso, escribe "✅ Paso N: [qué quedó hecho y cómo lo verificaste]" y espera a que yo diga "sigue". - Si un mismo error se repite 3 veces, detente, explícame qué intentaste y pregúntame cómo seguir. - Detecta mi sistema operativo. Con el M5 conectado por USB, encuentra su puerto serial (`arduino-cli board list` o `ls /dev/cu.*` en Mac). Si no aparece en Windows, dime que instale el driver CH9102 desde la página oficial de M5Stack y espera. - Instala `arduino-cli` (Mac: Homebrew; Windows: winget). - Agrega el catálogo de placas `https://static-cdn.m5stack.com/resource/arduino/package_m5stack_index.json`, instala la plataforma `m5stack:esp32` y la librería oficial `M5StickCPlus2` (autor M5Stack). La placa es `m5stack:esp32:m5stack_stickc_plus2`. - Solo en Mac con chip Apple: el `ctags` que trae Arduino es para Intel y pediría Rosetta. Pregúntame antes, y si acepto, instala `universal-ctags` con Homebrew, respalda el original como `ctags.intel-original` y reemplázalo por un enlace al nativo. - Verificación: `arduino-cli board listall` muestra `M5StickCPlus2`. Cada letra es un píxel. Colores: K #1b1630 contorno · H #4b2a6b pelo · h #7a4aa8 brillo del pelo · P #2f2f3d audífonos · p #ee6c4d detalle coral (también el elástico del moño) · S #f4c7a1 piel · s #e2a882 sombra de piel · E #1b1630 ojos · W #ffffff brillo de ojos · M #c0504d boca · C #ee6c4d polerón · c #c9553b sombra del polerón · N #2e4460 pantalón · B #f2f2f2 zapatillas · G #c9dfae piel enferma · g #a9c78c sombra enferma · D #5ab0e6 gota y lágrima · Z #ffffff zetas de sueño. El punto es transparente. Dibujo base (24 × 33): ``` ..........KKKK.......... .........KHhhHK......... ........KHHhHHHK........ ........KHhHHHHK........ ........KHHHHHHK........ ........KppppppK........ ......KKHHHHHHHHKK...... .....KHHhhHHHHHHHHK..... ....KHHhhHHHHHHHHHHK.... ...KPKHHHHHHHHHHHHKPK... ..KPpKHHSSSSSSSSHHKpPK.. ..KPpKHSSSSSSSSSSHKpPK.. ..KPpKSSEESSSSEESSKpPK.. ..KPpKSSEWSSSSEWSSKpPK.. ..KPPKSsSSSSSSSSsSKPPK.. ...KKKSSSSSMMSSSSSKKK... .....KSSSSSSSSSSSSK.KSK. ......KKSSSSSSSSKK..KSSK ........KKSSSSKK....KSSK ..........KSSK......KCCK ........KKCCCCKK...KCCK. .......KCCCCCCCCK.KCCK.. ......KCCCCCCCCCCKCCK... .....KCCKCCCCCCCCCCK.... .....KCCKCCCCCCCCK...... .....KCCKCCCCCCCCK...... .....KSSKccccccccK...... ......KK.KNNNNNNK....... .........KNNKKNNK....... .........KNNK.KNNK...... .........KNNK.KNNK...... ........KBBBK.KBBBK..... ........KKKKK.KKKKK..... ``` Las 7 caras cambian las columnas 6 a 17 de algunas filas (fila: texto nuevo): - Normal: el dibujo base. - Feliz: 15 `SSSSMSSMSSSS`, 16 `SSSSSMMSSSSS`. - Hambre: 15 `SSSSSMMSSSSS`, 16 `SSSSSMMSSSSS`. - Sed: 15 `SSSSSSSSSSSS`, 16 `SSSSSMMSSSSS`, y una gota D arriba a la derecha (fila 1 col 20; filas 2 y 3 cols 19–21; fila 4 col 20). - Sueño: 12 `SSSSSSSSSSSS`, 13 `SSEESSSSEESS`, 15 `SSSSSSSSSSSS`, 16 `SSSSSMSSSSSS`, y una Z (fila 0 cols 19–23; fila 1 col 22; fila 2 col 21; fila 3 col 20; fila 4 cols 19–23). - Triste: 14 `SDSSSSSSSSsS`, 15 `SSSSSMMSSSSS`, 16 `SSSSMSSMSSSS`. - Enferma: 12 `SSSSSSSSSSSS`, 13 `SSEESSSSEESS`, 15 `SSSSMSMSSSSS`, 16 `SSSSSMSMSSSS`, y en las filas 10 a 18, columnas 6 a 17, S pasa a G y s pasa a g. Escribe un script en Python que convierta esto a `firmware/personita/sprites.h` (paleta en RGB565 con índice 0 transparente, y una matriz por cara) y otro que genere una imagen PNG con las 7 caras para que yo la revise. Verificación: muéstrame la imagen y espera mi visto bueno. Si quiero otros colores, cambia solo la paleta. Programa que muestre a la personita (escala 3) sobre fondo #0d1b2a y que el botón grande (A) cambie de cara. Pon todo el código en `app.cpp` y deja `personita.ino` vacío con un comentario (así no depende de ctags). Compila, pídeme permiso para subirlo y súbelo. Verificación: te confirmo que veo las 7 caras. - Pantalla horizontal (240 × 135). Dibuja todo en un `M5Canvas` y mándalo de una vez, sin parpadeo. Personita a la izquierda; debajo, una pila chica con el porcentaje de batería (verde > 50, amarillo 20–50, rojo < 20). A la derecha, 4 barras: Comida, Agua, Energía, Ánimo. Abajo, el menú `< Comer >`. Usa la fuente `efontJA_12/16` para que salgan tildes y ñ. - Vive con los horarios de una persona, según la hora local: - **Almuerzo de 13:00 a 14:00 y cena de 18:00 a 19:00.** Comer solo funciona dentro de esos horarios y deja la comida en 100. Fuera de horario, Comer muestra "Todavía no es hora" y no hace nada. Si se salta una comida, sigue con hambre hasta la siguiente. - **Se acuesta entre 21:00 y 22:00 y despierta sola a las 7:00.** En ese horario, Dormir la acuesta. Si a las 22:00 sigue despierta, se duerme sola, pero baja el ánimo 20 por acostarse tarde. - **Siesta**: de día solo puede dormir si la energía está bajo 25, y despierta sola cuando llega a 100 o cuando la despiertas. - Si no hay hora válida (sin reloj ni internet), no aplica los horarios y deja comer y dormir en cualquier momento. - Cada necesidad va de 100 a 0 y baja con el tiempo: - Comida: se vacía en 17 h despierta y a la mitad de velocidad durmiendo. Así, después de cenar a las 19:00 llega con hambre al almuerzo del día siguiente, sin quedar en 0. - Agua: se vacía en 6 h despierta, a la mitad durmiendo. Se puede beber a cualquier hora. - Energía: baja de 100 a 0 en 16 h despierta. **Durmiendo SUBE de 0 a 100 en 6 h**: súmala en cada actualización mientras duerme, nunca la restes, y guárdala. - Ánimo: se vacía en 10 h despierta y no baja durmiendo. - Mientras duerme, la pantalla baja el brillo pero muestra "Durmiendo" y el porcentaje de energía subiendo, para que se vea que está cargando. Al despertar a las 7:00, vuelve el brillo normal. - Botón lateral (B): recorre Comer, Beber, Dormir/Despertar, Jugar. Botón A: ejecuta. Beber +50. Al comer o beber queda feliz 1 minuto. Jugar: muestra "¡Agítame!" 8 segundos. Agitar el M5 (aceleración > 2 g, máximo una vez cada 10 segundos, solo despierta) sube ánimo +25 y baja energía −5. Si una acción no está permitida por el horario, explícalo en la línea del menú por 3 segundos. - Cerca de cada comida y de la hora de dormir, te avisa con un pitido corto al empezar el horario (13:00, 18:00 y 21:00). - La cara muestra lo más urgente: enferma, después durmiendo, después feliz, y si algo baja de 25, la cara de esa necesidad. - Se enferma si dos necesidades quedan en 0 por 3 horas; se mejora cuando todas superan 50. Enferma no puede jugar. - Te llama con 3 pitidos si algo está urgente: máximo una vez por hora y NUNCA entre las 22:00 y las 8:00. - Guarda el estado con `Preferences` cada minuto y después de cada acción. Al encender, descuenta el tiempo que estuvo apagado (máximo 7 días) usando el reloj interno (RTC, guardado en UTC) y la hora de internet (NTP); cuando llega la hora de internet, corrige el RTC. Pregúntame mi zona horaria y usa su cadena POSIX (Chile continental: `<-04>4<-03>,M9.1.6/24,M4.1.6/24`). - Antes de subirlo, prueba la lógica de los horarios y de la energía con un modo de prueba que acelere el tiempo (1 minuto real = 1 hora) y una hora simulada: comer a las 12:00 no funciona, a las 13:30 sí; acostarla a las 21:30 y ver que la energía sube hasta 100 y despierta a las 7:00. Después quita el modo de prueba. - Verificación: compila, súbelo y yo te confirmo que las barras y el menú funcionan. - Crea `firmware/personita/secretos.h` con `WIFI_NOMBRE`, `WIFI_CLAVE` y `CLAVE_AVISOS`, más un `secretos.h.ejemplo` y un `.gitignore` que excluya `secretos.h`. Genera `CLAVE_AVISOS` al azar (24 bytes, base64 url) sin mostrarla en el chat, y guárdala también en `~/.claude/personita-clave` con permisos solo para mi usuario. - Pídeme que escriba yo mi WiFi en `secretos.h` y avísame que el M5 solo usa redes de 2,4 GHz. Revisa que ya no tenga los datos de ejemplo, sin mostrar su contenido. - En el M5: conectar al WiFi sin bloquear la pantalla, reintentar cada 30 segundos y anunciarse como `personita.local` (mDNS) cada vez que conecta. Servidor HTTP en el puerto 80 con una sola ruta, `POST /aviso`, con parámetro `proyecto` y cabecera `X-Clave`: - clave comparada en tiempo constante; si no calza, 401; - máximo 20 avisos por minuto (si se pasa, 429); - nombre limpiado: solo letras, números, `- _ .` y espacio, máximo 24 caracteres; si queda vacío, 400; - fila de máximo 5 avisos, sin repetir un proyecto que ya está esperando. - Mientras haya avisos, tapan las barras: nombre del proyecto en coral (cortado con ".." si no cabe), "terminó", "+N más" y "A: visto"; suena un doble pitido y el botón A marca el primero como visto. - Verificación: prueba con `curl -4` (sin el -4 se cuelga por IPv6) sin clave (401), con clave mala (401), con la clave buena (200) y con un nombre con `