La Forja (emoji → personaje): fuentes de datos, arquitectura y decisiones
Contexto: 2026-08-13, sesión 2 del proyecto ~//Documents/emoji. MVP funcionando: index.html + styles.css + app.js + data.js (estático, sin backend).
## Fuentes de datos (verificadas y descargadas)
- Datos reales de Emoji Kitchen: repo xsalazar/emoji-kitchen-backend, archivo app/metadata.json
(~99 MB). x0-github/emojikitchen ya no existe; el sitio actual es xsalazar/emoji-kitchen (emojikitchen.dev).
- Números reales del catálogo actual: 619 emojis base · C(619,2)=191.271 pares posibles ·
147.000 combinaciones válidas (76,9%). No 2.121 (esa cifra era de otra versión).
- Imágenes: hotlink directo a gstatic, sin CORS, sin backend:
https://www.gstatic.com/android/keyboard/emojikitchen/{YYYYMMDD}/u{cp}/u{cp}_u{cp2}.png
La dirección importa (u1f600_u2615 != u2615_u1f600); en data.js pairs se guarda "l_r" -> fecha
con el orden real de la imagen.
- Nombres en español: CLDR annotations/es/annotations.json (key = caracter emoji, campo tts).
469/619 con nombre ES; el resto cae a alt en inglés.
## Generación de data.js (por si hay que regenerar con catálogo nuevo)
1. curl metadata.json (99MB) del repo backend.
2. Por cada emoji, de combinations tomar solo la versión isLatest (max date) y su left/right real.
3. Claves canónicas "l_r" -> date. 619 emojis, ~147k pares.
4. Unir con CLDR es para name/kws. Sort por gBoardOrder.
5. window.EMOJI_DATA = {emojis:[{cp,ch,name,kws,cat}], pairs:{"l_r":date}} (~3,8 MB)
## Decisiones de diseño del MVP
- Sin framework, sin build: python3 -m http.server (fetch de data.js como script funciona incluso con file://).
- Ejercicio de combinatoria visible: elegir A filtra la parrilla a sus parejas válidas y muestra el % del grupo.
- Storytelling South Park: cada escena conecta con «Por lo tanto,» o «Pero» (nunca «y luego»).
Apertura sin conector, 4 beats más, botón «Continuar» agrega beats infinitamente.
- Slots fijos por historia: nombre, A, B, lugar, enemigo, tesoro, accion, pool. {giro} es POR BEAT
(pickSlot con key 'giro' evita repetición inmediata; bug conocido: usar ?? no || para el índice 0).
- Enemigos siempre en singular (colectivos: "la cofradía de los monjes ciegos") para que los
verbos de las plantillas concuerden.
- fill() aplica contracciones post-reemplazo: "a el"->al, "de el"->del.
- Azar = base aleatoria + extras de AZAR mezclados (se congela por historia en state.currentData).
- Debug en consola: window.__FORJA = {state, forge, startStory, continueStory, pairInfo, imgUrl, partnersOf, renderAll}.
## Siguientes pasos pensados (no construidos)
- Guardar personajes forjados en localStorage (lista de fichas + historias) para "seguir el desarrollo del personaje".
- Semilla reproducible para historias (URL hash ?semilla=...).
- Reintentar combos 404 con fechas viejas (fallback a versiones no-latest) — hoy solo se usa la última fecha.
## Paso "Ahonda en el personaje" (añadido 2026-08-13, pulido)
- Flujo: elegir A → parrilla filtrada → elegir B → forge (avatar + ficha, SIN historia) → panel
profundizar con 3 inputs (poderes/objetivo/rasgos) prellenados por autogeneración → «A la historia».
- Autogeneración: poder = "aliento/mirada/voz/... de {nombre A|B}" (75%) o "don de {B}";
objetivo = plantilla resuelta con fill (recuperar {tesoro} / escapar de {lugar} / sobrevivir a {enemigo}...);
rasgos = 2 adjetivos distintos del pool (bug corregido: pickSlot devuelve valor, no índice).
- El objetivo del personaje persiste entre historias ("Otra historia" cambia mundo, no personaje).
- «Editar personaje» reabre el panel desde la historia; «A la historia» regenera con lo escrito.
- Slots nuevos en plantillas: {poder}, {objetivo}, {rasgo}. Aperturas ahora usan {objetivo},
no {tesoro} (tesoro queda como MacGuffin en beats genéricos). Beats nuevos:
"cambia de plan: invoca {poder} para {accion}", "el secreto de {AE} vive en {poder}",
"ser {rasgo} le juega en contra", "recuerda la promesa: {objetivo}".