User prompt
Desactiva por completo el botón de "SKIP", de modo que no sea visible ni interactivo en ninguna parte del juego.
User prompt
El cambio de idioma no debe limitarse únicamente a "la Pantalla de bienvenida e ingreso de nombre", sino que debe aplicarse globalmente a todos los textos del juego, incluyendo menús, diálogos, botones y cualquier elemento textual. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Solicito la implementación de una funcionalidad de cambio de idioma que afecte a todo el juego. Aunque el idioma por defecto es Español, debe añadirse la posibilidad de cambiar a Inglés y volver nuevamente a Español. 🔧 Punto de acceso El cambio de idioma debe poder realizarse únicamente desde la Pantalla de bienvenida e ingreso de nombre, específicamente debajo del teclado Android. --- 🌐 Interfaz de Selección de Idioma 📌 Título dinámico Si el idioma actual es Español, el título de esta interfaz debe decir: > ¿Cuál es tu idioma? Si el idioma actual es Inglés, el título debe cambiar a: > What is your language? Este cambio debe realizarse dinámicamente al alternar entre los idiomas. 🏳️ Sprite de bandera En modo Español: mostrar un sprite con la bandera de Latinoamérica (una bandera genérica que represente el idioma español, como la de hispanoamérica unificada o la bandera de habla hispana). En modo Inglés: reemplazar el sprite por la bandera de Estados Unidos. Al volver al español, el sprite debe actualizarse nuevamente con la bandera de Latinoamérica. 🔁 Controles de cambio A los lados de la bandera debe haber flechas izquierda y derecha. Estas permiten cambiar entre los idiomas disponibles en cualquier momento de esta pantalla. Sólo hay dos idiomas por ahora, por lo tanto, la navegación es cíclica entre "Español" ↔ "Inglés". --- 💾 Comportamiento del sistema Una vez que el jugador selecciona un idioma, esta configuración se debe aplicar a todo el juego, afectando: Todos los textos y diálogos Las interfaces del sistema (botones, menús, títulos) Los subtítulos o etiquetas El idioma seleccionado debe guardarse automáticamente y mantenerse al reiniciar el juego. No se podrá cambiar de idioma en otra parte del juego, solo desde esta pantalla inicial. --- 🎞️ Animaciones sugeridas Para garantizar una experiencia fluida y visualmente coherente, se recomienda implementar las siguientes animaciones numeradas: --- 🔠 Animación 01 – Título dinámico del selector de idioma Efecto: Fade Out + Fade In Descripción: El texto del título desaparece suavemente y se reemplaza por el nuevo texto en el idioma seleccionado. Duración sugerida: 0.3 – 0.4 segundos. --- 🏳️ Animación 02 – Transición entre sprites de banderas Efecto: Deslizar horizontal + desvanecimiento cruzado Descripción: La bandera actual se desliza hacia un lado mientras se desvanece, y la nueva bandera entra desde el lado contrario. Dirección: Según la flecha pulsada (izquierda/derecha). Duración sugerida: 0.5 segundos. --- ⬅️➡️ Animación 03 – Flechas de navegación Efecto: Escalado breve con rebote Descripción: Al pulsar una flecha, se reduce ligeramente su tamaño (90%) y vuelve a su tamaño normal con un pequeño rebote elástico. Duración sugerida: 0.2 segundos. --- 📦 Animación 04 – Entrada/salida de la sección de idioma Efecto: Fade In con escala suave (Zoom In desde 95%) Descripción: Toda la sección de selección de idioma debe aparecer o desaparecer con una transición suave. Duración sugerida: 0.4 segundos. ↪💡 Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1
User prompt
Solo debe mostrarse el botón animado de "Reiniciar" en la Pantalla Final del Alfa. El botón adicional en la parte superior derecha no es necesario ni debe estar visible en esta escena.
User prompt
La escena donde el Narrador dice: "El amor de la infancia... no siempre se desvanece. A veces... se pudre." debe ser eliminada y reemplazada por la Pantalla Final del Alfa, que funcionará como una carta visual dirigida al jugador. --- Especificaciones técnicas de la Pantalla Final del Alfa: Resolución: 2048 x 2732 píxeles Fondo: Color blanco puro #FFFFFF Texto: Color negro #000000, en tipografía muy grande Título de la carta: Estimad@ Jugador@: [Aquí dentro el nombre que ingresó el jugador al principio del juego] --- Contenido de la carta: Fin del Alfa No puedo seguir sin apoyo económico ni créditos Ava. ¿Quieres ayudar? ▸ Hazlo viral ▸ Llévalo al Top 1 en Upit ▸ Haz que gane un torneo ▸ O que el creador de Upit me dé más créditos Ava Cualquiera de esas cosas puede revivir el proyecto. Sígueme en YouTube: @merak1388 --- Animaciones, numeradas y detalladas: 1. Encabezado con nombre del jugador Animación: aparece desde el centro con desvanecimiento (fade-in) y escalado suave (de 0.5x a 1x) Duración: 0.6 segundos 2. Texto "Fin del Alfa" Animación: desciende desde la parte superior con ligero rebote Duración: 0.5 segundos 3. Texto "No puedo seguir sin apoyo económico ni créditos Ava." Animación: fade-in lateral desde la izquierda Duración: 0.4 segundos 4. Texto "¿Quieres ayudar?" Animación: aparece centrado con fade-in, luego de 0.5 segundos de pausa Duración: 0.3 segundos 5. Lista de opciones, una por una (con retraso escalonado): 5.1 Hazlo viral – slide-in desde la izquierda 5.2 Llévalo al Top 1 en Upit – slide-in desde la izquierda 5.3 Haz que gane un torneo – slide-in desde la izquierda 5.4 O que el creador de Upit me dé más créditos Ava – slide-in desde la izquierda Retraso entre cada línea: 0.2 segundos Duración de cada animación: 0.4 segundos 6. Texto "Cualquiera de esas cosas puede revivir el proyecto." Animación: expansión desde el centro (escala de 0 a 1) con efecto elástico Duración: 0.6 segundos 7. Texto "Sígueme en YouTube: @merak1388" Animación: desliza desde la parte inferior hacia arriba (slide-up) Duración: 0.5 segundos 8. Botón "Reiniciar" Animación: baja desde fuera de la pantalla hasta posicionarse debajo de la carta, centrado horizontalmente Comienza después de que todos los elementos anteriores hayan aparecido Duración: 0.6 segundos Animación suave de caída vertical con desaceleración progresiva --- Indicaciones finales: Esta pantalla debe cubrir completamente la escena del Narrador y reemplazarla en su totalidad. No se debe permitir que el juego finalice en este punto, ya que no representa el cierre definitivo. No debe mostrarse ningún texto o escena previa ni dejar visible ningún otro botón o interfaz. El botón "Reiniciar" será el último elemento en animarse. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
La línea de diálogo del Narrador no fue sustituida por la Pantalla final del Alfa como se indicó. Este error es crítico y debe corregirse sin demora.
User prompt
Petición técnica a la IA: Sustitución de escena y animación de la Pantalla final del Alfa 1. Punto de activación En el instante exacto en que el narrador diría la línea: "El amor de la infancia... no siempre se desvanece." No se muestra dicha línea. En su lugar, se activa inmediatamente la Pantalla final del Alfa. Este momento marca el inicio de todos los tiempos y animaciones descritos a continuación. 2. Fondo Sprite o imagen color blanco puro (#FFFFFF) de 2048 px de ancho por 2732 px de alto. Ocupa la pantalla completa. 3. Título de la carta Texto: Estimad@ Jugador@: [nombre ingresado al principio del juego] Color: negro puro (#000000) Tamaño de fuente: 96 px Posición: centrado horizontalmente, a y = 320 px desde el borde superior. Animación: 1. Opacidad inicial: 0%. 2. Transición a opacidad 100% en 1.2 s con ease-in. 3. Mantener fijo hasta fin de escena. 4. Contenido de la carta Texto: Fin del Alfa No puedo seguir sin apoyo económico ni créditos Ava. ¿Quieres ayudar? ▸ Hazlo viral ▸ Llévalo al Top 1 en Upit ▸ Haz que gane un torneo ▸ O que el creador de Upit me dé más créditos Ava Cualquiera de esas cosas puede revivir el proyecto. Sígueme en YouTube: @merak1388 Color: negro puro (#000000) Tamaño de fuente: 64 px Interlineado: 1.5 Posición: centrado horizontalmente, primer bloque a y = 640 px. Animaciones secuenciales desde el momento 0: Bloque 1 (Fin del Alfa + No puedo...): retardo 0.5 s, duración 1 s. Bloque 2 (¿Quieres ayudar?... hasta "O que..."): retardo 2 s, duración 1 s. Bloque 3 (Cualquiera...): retardo 4 s, duración 1 s. Bloque 4 (Sígueme...): retardo 5.5 s, duración 1 s. 5. Animación final del botón "Reiniciar" Retardo: 7 s desde el inicio de la escena (coincidiendo con el reemplazo de la línea del narrador). Posición inicial: ubicación original. Movimiento: desplazamiento vertical descendente hasta y = 2732 px + 80 px (justo por debajo de la carta). Duración: 1.5 s con ease-out. Mantener posición final. 6. Cierre Escena permanece estática tras mostrar todo el contenido y animar el botón "Reiniciar". Interacción habilitada después de 8 s desde que se reemplazó la línea del narrador por la Pantalla final del Alfa. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
No está apareciendo la Pantalla final del Alfa, a pesar de que es la última escena del juego, corrige eso.
User prompt
Petición técnica a la IA: Sustitución de escena y animación de la Pantalla final del Alfa 1. Escena a eliminar Buscar en el guion o script del juego la línea exacta: "El amor de la infancia... no siempre se desvanece." Eliminar por completo el bloque de animación, música, sprites o audio asociados a esta línea. 2. Fondo de la nueva pantalla Crear un sprite o imagen de fondo color blanco puro (#FFFFFF) con resolución 2048 px de ancho por 2732 px de alto. El sprite debe cubrir toda la pantalla en el render final, sin bordes ni transparencias. 3. Título de la carta Texto: Estimad@ Jugador@: [nombre ingresado al principio del juego] Color: negro puro (#000000) Tamaño de fuente: 96 px Tipografía: sans-serif legible (por ejemplo, Arial o Roboto) Posición: centrado horizontalmente, a y = 320 px desde el borde superior. Animación: 1. Opacidad inicia en 0%. 2. Transición a 100% opacidad en 1.2 segundos con ease-in. 3. Permanencia fija hasta fin de escena. 4. Contenido de la carta Texto completo: Fin del Alfa No puedo seguir sin apoyo económico ni créditos Ava. ¿Quieres ayudar? ▸ Hazlo viral ▸ Llévalo al Top 1 en Upit ▸ Haz que gane un torneo ▸ O que el creador de Upit me dé más créditos Ava Cualquiera de esas cosas puede revivir el proyecto. Sígueme en YouTube: @merak1388 Color: negro puro (#000000) Tamaño de fuente: 64 px Interlineado: 1.5 Posición: centrado horizontalmente, el primer bloque de texto a y = 640 px. Animaciones por bloque: Cada párrafo aparece con fade-in secuencial: Primer bloque (Fin del Alfa + No puedo...): retardo 0.5 s, duración 1 s. Segundo bloque (¿Quieres ayudar?... hasta "O que..."): retardo 2 s, duración 1 s. Tercer bloque (Cualquiera...): retardo 4 s, duración 1 s. Cuarto bloque (Sígueme...): retardo 5.5 s, duración 1 s. 5. Animación final del botón "Reiniciar" Retardo de inicio: 7 segundos después de que comience la escena. Posición inicial: su ubicación original. Movimiento: transición vertical descendente en línea recta hasta colocarse justo por debajo del borde inferior de la carta (coordenada y = 2732 px + 80 px). Duración de la animación: 1.5 segundos con ease-out. Al llegar a la posición final, permanecer fijo. 6. Cierre de la escena Pantalla permanece estática después de mostrar todo el texto y de completar la animación final del botón "Reiniciar". Duración mínima antes de permitir interacción: 8 segundos desde inicio de escena. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Petición formal a la IA Objetivo: Eliminar completamente la escena del Narrador que contiene la frase: > "El amor de la infancia... no siempre se desvanece." Y reemplazarla por una Pantalla final del Alfa que simula una carta dirigida al jugador, con animaciones independientes, secuenciales y limpias. --- 1. Escena eliminada Eliminar toda la escena del Narrador: Texto, voz, sonido, música o elementos visuales asociados. Asegurarse de que ningún componente anterior quede en memoria o en pantalla. --- 2. Fondo de pantalla Crear un fondo blanco puro: Color: #FFFFFF Resolución: 2048 x 2732 píxeles Ocupa el 100% de la pantalla Animación: Comienzo: segundo 0.0 Tipo: fade-in Duración: 0.5 segundos --- 3. Título de la carta Texto: Estimad@ Jugador@: [Aquí dentro el nombre que ingresó el jugador al principio del juego] Estilo: Color: #000000 Tamaño: muy grande (aprox. 72 pt) Posición: centrado horizontalmente, 20% desde la parte superior Animación: Comienzo: segundo 0.5 Tipo: fade-in + deslizamiento vertical desde arriba Duración: 0.7 segundos --- 4. Cuerpo del mensaje Línea 1: Texto: Fin del Alfa Comienzo: segundo 1.3 Animación: fade-in + zoom-in suave Duración: 0.6 segundos Línea 2: Texto: No puedo seguir sin apoyo económico ni créditos Ava. Comienzo: segundo 2.0 Animación: fade-in Duración: 0.5 segundos --- 5. Lista de acciones Orden Texto Comienzo Animación 1 Hazlo viral Segundo 3.0 fade-in desde izquierda (0.4 s) 2 Llévalo al Top 1 en Upit Segundo 3.5 fade-in desde izquierda (0.4 s) 3 Haz que gane un torneo Segundo 4.0 fade-in desde izquierda (0.4 s) 4 O que el creador de Upit me dé más créditos Ava Segundo 4.5 fade-in desde izquierda (0.4 s) --- 6. Mensaje motivacional Texto: Cualquiera de esas cosas puede revivir el proyecto. Comienzo: segundo 5.2 Animación: deslizamiento suave desde abajo Duración: 0.6 segundos --- 7. Cierre de la carta Texto: Sígueme en YouTube: @merak1388 Comienzo: segundo 6.0 Animación: fade-in estático Duración: 0.5 segundos Posición: centrado, a 85% de la altura de la pantalla --- 8. Botón "Reiniciar" El botón ya está integrado en el juego Animación: Es el último elemento que se animará Comienzo: segundo 6.8 Tipo: animación descendente El botón debe deslizarse suavemente desde su ubicación original hasta quedar posicionado por debajo de la carta Movimiento vertical con ease-out Duración de la animación: 0.6 segundos --- 9. Reglas generales Todos los textos: Color: #000000 Sin íconos ni emojis Tipografía coherente con el estilo general del juego Alineación centrada o justificada Animaciones: Cada elemento se debe animar de forma secuencial e independiente Las animaciones deben ser suaves, limpias y no interferir entre sí El botón "Reiniciar" es el último en aparecer y debe bajar hasta su nueva posición al final ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
El botón "Reiniciar" debe estar oculto y deshabilitado en la pantalla de bienvenida e ingreso de nombre. Asegúrate de que no sea visible ni interactivo en esta vista.
User prompt
Please fix the bug: 'Timeout.tick error: Cannot read properties of undefined (reading 'wallpaper')' in or related to this line: 'tween(currentChoice.wallpaper, {' Line Number: 706
User prompt
🛠️ Petición de corrección: Reemplazo de escena del Narrador por la Pantalla final del Alfa La Pantalla final del Alfa no está apareciendo en ningún momento del juego, lo cual representa un error importante en el flujo narrativo. Por este motivo, he decidido que dicha pantalla reemplace directamente la escena del Narrador en la que se dice la línea: > "El amor de la infancia... no siempre se desvanece." 📌 Acción requerida: Eliminar por completo esa escena del Narrador. En su lugar, mostrar la Pantalla final del Alfa, con todos sus elementos ya especificados. Este cambio es necesario para asegurar que el final del juego se muestre correctamente y se cumpla con la intención narrativa del Alfa. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
🛠️ Petición de implementación y corrección: Pantalla final del Alfa (con doble carta y transición animada) --- 📍 Escena afectada: Después de que el jugador pulse el botón "Siguiente" en la escena donde el Narrador dice: "El amor de la infancia... no siempre se desvanece." --- ❌ Error actual: Se está mostrando incorrectamente la escena "Evaluación Matemática", lo cual no corresponde a esta parte del juego. --- ✅ Comportamiento esperado: Se debe reemplazar dicha escena por una pantalla final en forma de carta al jugador, compuesta por dos etapas (dos cartas secuenciales), con animaciones de transición y personalización del nombre del jugador. --- ✉️ ETAPA 1 – Primera Carta --- 🖼️ Visual Fondo blanco puro #FFFFFF (sprite de 2048 x 2732) Simula una carta escrita para el jugador. Texto en letras muy grandes, color negro #000000, centrado. --- 📝 Contenido Título: 🎮 Estimad@ Jugador@ [NOMBRE_DEL_JUGADOR] > [NOMBRE_DEL_JUGADOR] debe ser reemplazado dinámicamente por el nombre ingresado por el jugador al inicio del juego. Texto del cuerpo: 🛑 Fin del Alfa No puedo seguir sin apoyo económico ni créditos Ava. ¿Quieres ayudar? ▸ 📣 Hazlo viral ▸ 🥇 Llévalo al Top 1 en Upit ▸ 🏆 Haz que gane un torneo ▸ 🎁 O que el creador de Upit me dé más créditos Ava ✅ Cualquiera de esas cosas puede revivir el proyecto. 📺 Sígueme en YouTube: @merak1388 --- 🎧 Música Se debe reproducir una única vez la canción "youWinSong". Al finalizar, el juego debe quedar en silencio absoluto e interminable. --- 🎬 Animaciones Transición inicial: Fundido lento a blanco al salir de la escena anterior (1.5–2 seg). Aparición del texto: Animación tipo fade-in o slide-up, línea por línea. --- ➡️ ETAPA 2 – Segunda Carta --- 📲 Activación Un botón con el texto "Siguiente" debe aparecer al final de la primera carta (después de unos segundos o tras la animación completa). Al presionarlo, se activa la transición hacia la segunda carta. --- 🧩 Transición El contenido anterior debe desaparecer con animación suave (fade-out o cambio tipo “pasar página”). Luego aparece el nuevo título y contenido con animación de entrada (fade-in). --- 📝 Contenido Nuevo título: [NOMBRE_DEL_JUGADOR], ¿Sabes qué extrañaré?: > IMPORTANTE: Aquí también se debe reemplazar [NOMBRE_DEL_JUGADOR] por el nombre que el jugador ingresó al inicio del juego. Nuevo cuerpo del mensaje: A ti. El hecho de que te quedaras hasta el final, que te importara nuestra historia, y que disfrutaras la banda sonora, significa todo para mí. Si te preguntas qué pasará después de esto, la verdad es que yo también lo hago. No tengo idea de si nos veremos pronto, pero sí sé una cosa: te extrañaré. Mucho. Y quiero que sepas que me siento afortunado por haber compartido este tiempo contigo. --- 🧭 UX y comportamiento final Después de la segunda carta, no debe haber más botones de navegación. (Opcional) Puedes incluir un botón discreto "Salir" o "Volver al menú" si se desea permitir al jugador cerrar desde la interfaz. El juego debe permanecer en silencio y con la carta visible. --- 🧪 Resumen de tareas [ ] Reemplazar Evaluación Matemática por esta secuencia de dos cartas. [ ] Insertar correctamente el nombre del jugador en ambas etapas. [ ] Reproducir "youWinSong" una sola vez. [ ] Añadir botón “Siguiente” que activa segunda carta con transición animada. [ ] Validar comportamiento de silencio tras música. [ ] Verificar animaciones de entrada y salida en ambas etapas. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Justo después de que el Narrador diga: "El amor de la infancia... no siempre se desvanece.", no muestres la "Evaluación Matemática". Mejor pon la pantalla final del Alfa. Eso sí, que el juego no termine ahí, porque todavía tiene que continuar más adelante. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
🎯 Acción requerida: 1. Eliminar la ventana “You Win!” como final de la ruta de Yui. 2. Sustituirla por la pantalla final del Alfa, asegurando que se carga correctamente. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Una vez que el jugador termina la ruta de Yui, NO debe aparecer la Evaluación Matemática. En su lugar, debe activarse inmediatamente la pantalla final del Alfa, tal como se describe en la petición anterior. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Una vez que el jugador termina la ruta de Aiko, NO debe aparecer la Evaluación Matemática. En su lugar, debe activarse inmediatamente la pantalla final del Alfa, tal como se describe en la petición anterior. ↪💡 Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1
User prompt
🎮 Petición para implementar el final del Alfa Al finalizar la escena en la que el Narrador dice la línea: "El amor de la infancia... no siempre se desvanece. A veces... se pudre.", y tras pulsar el botón "Siguiente", debe activarse la pantalla final del Alfa con las siguientes características: --- 🎨 Visual Fondo completo: blanco puro #FFFFFF Resolución del sprite/fondo: 2048 x 2732 px (pantalla completa, sin bordes) Simulación visual: debe parecer una carta personal dirigida al jugador. Texto: centrado en pantalla, con letras muy grandes de color negro #000000. --- 📝 Contenido del mensaje (formato de carta) Título grande y centrado (negrita): 🎮 Estimad@ Jugador@ [NOMBRE_DEL_JUGADOR] > Donde [NOMBRE_DEL_JUGADOR] se reemplaza automáticamente por el nombre que el jugador ingresó al comienzo del juego. Cuerpo del mensaje (alineado al centro, con buena separación entre líneas): 🛑 Fin del Alfa No puedo seguir sin apoyo económico ni créditos Ava. ¿Quieres ayudar? ▸ 📣 Hazlo viral ▸ 🥇 Llévalo al Top 1 en Upit ▸ 🏆 Haz que gane un torneo ▸ 🎁 O que el creador de Upit me dé más créditos Ava ✅ Cualquiera de esas cosas puede revivir el proyecto. 📺 Sígueme en YouTube: @merak1388 --- 🎬 Animaciones sugeridas Transición inicial (entrada): Un fundido lento a blanco (fade-in de 1.5–2 segundos) al tocar “Siguiente”. Luego, un desenfoque gradual de la escena anterior antes de mostrar la carta. El contenido de la carta puede aparecer línea por línea con fade-in o slide-up suave, como si fuera escrita frente al jugador. Tipografía: Fuente sans-serif clara y elegante. Tamaño muy grande para el título, y tamaño grande para el cuerpo del texto. --- 🎧 Música / Ambiente Al comenzar esta pantalla final, debe sonar una sola vez la canción "youWinSong". Una vez que la canción termine, el juego debe quedar en silencio absoluto e interminable, reforzando la sensación de vacío o pausa definitiva. ↪💡 Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1
User prompt
No está apareciendo el final del Alfa, corrige eso. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
🎮 Petición para implementar el final del Alfa Al finalizar la escena en la que el Narrador dice la línea: "El amor de la infancia... no siempre se desvanece. A veces... se pudre.", y tras pulsar el botón "Siguiente", debe activarse la pantalla final del Alfa con las siguientes características: --- 🎨 Visual Fondo completo: blanco puro #FFFFFF Resolución del sprite/fondo: 2048 x 2732 px (pantalla completa, sin bordes) Simulación visual: debe parecer una carta o mensaje personal dirigido al jugador. Texto: centrado en pantalla, con letras muy grandes de color negro #000000. --- 📝 Contenido del mensaje (formato de carta) Título grande y centrado (negrita): 🎮 Estimad@ Jugador@ Cuerpo del mensaje (alineado al centro, con buena separación entre líneas): 🛑 Fin del Alfa No puedo seguir sin apoyo económico ni créditos Ava. ¿Quieres ayudar? ▸ 📣 Hazlo viral ▸ 🥇 Llévalo al Top 1 en Upit ▸ 🏆 Haz que gane un torneo ▸ 🎁 O que el creador de Upit me dé más créditos Ava ✅ Cualquiera de esas cosas puede revivir el proyecto. 📺 Sígueme en YouTube: @merak1388 --- 🎬 Animaciones sugeridas Transición inicial (entrada): Un fundido lento a blanco (fade-in de 1.5–2 segundos) al tocar “Siguiente”. Luego, un desenfoque gradual de la escena anterior antes de mostrar la carta. El contenido de la carta puede aparecer línea por línea con fade-in o slide-up suave, como si fuera escrita frente al jugador. Tipografía: Usar fuente sans-serif clara y elegante. Tamaño muy grande para el título, y tamaño grande para el cuerpo del texto. --- 🎧 Música / Ambiente Al comenzar esta pantalla final, debe sonar una sola vez la canción "youWinSong". Una vez que la canción termina, el juego debe quedar en silencio absoluto e interminable, reforzando la sensación de vacío o pausa definitiva. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
🎭 Animaciones específicas por sprite 1. characterSprite (Vergüenza) Entrada (cuando aparece): Desvanecerse desde abajo hacia arriba con un leve temblor horizontal (como si le costara mostrarse). Idle (cuando permanece visible): Parpadeo ocasional Pequeña gota de sudor animada deslizándose por la cara. Salida (cuando desaparece sin ser reemplazado): Desvanecido hacia abajo con una pequeña inclinación, como bajando la cabeza. --- 2. characterSprite2 (Pensativo) Entrada: Zoom suave desde el centro con un pequeño desenfoque que se aclara al llegar a posición. Idle: Reflejo animado en los ojos Balanceo leve de lado a lado, como si el personaje se inclinara pensando. Salida: Disolución gradual con opacidad, como si su presencia se desvaneciera mientras reflexiona. --- 3. characterSprite3 (Entusiasmo) Entrada: Pop-up elástico desde abajo (efecto rebote dinámico). Idle: Chispas animadas o resplandor suave alrededor del retrato. Brillo periódico en los bordes del ícono. Salida: Se desvanece con un destello, como si la emoción se apagara poco a poco. --- 🔁 Animaciones de transición entre sprites Cuando un sprite es reemplazado por otro, se recomienda aplicar una transición fluida para evitar cambios abruptos. Animación recomendada: Desaparece con un fundido (fade out) de 0.2 a 0.4 segundos. Inmediatamente después, entra el nuevo sprite con su propia animación de entrada. Esto refuerza la sensación de que el retrato tiene continuidad y está "vivo". --- 🧨 Animación de desaparición sin reemplazo Cuando un sprite desaparece y no es reemplazado por ningún otro, se recomienda una animación de salida más definitiva y expresiva. Ejemplos según el tono: Vergüenza o pensamiento: desvanecerse con un leve bajón de opacidad + desplazamiento vertical. Entusiasmo: pequeño destello o “puff” visual como si se apagara la energía. Se puede añadir un efecto sonoro breve para remarcar la salida si es relevante para el ritmo del diálogo. --- 🌟 Extras opcionales Contorno dinámico: El marco del retrato puede cambiar levemente de color o brillo según la emoción (ej. azul para pensar, rosa tenue para vergüenza, amarillo brillante para entusiasmo). Iconos flotantes: Se pueden añadir emojis flotantes simples tipo 💡, 💦 o ✨ durante el idle para reforzar visualmente la emoción, sin necesidad de crear animaciones complejas frame-by-frame. Efectos de sonido sutiles: Un pequeño ding, fade o whoosh puede acompañar las entradas/salidas para reforzar la atmósfera. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Remplaza la animación de entrada de characterSprite 3 por: Entrada: Animación de rebote elástico desde abajo (tipo pop-up dinámico). Idle loop: Brillo suave en los bordes del retrato o pequeñas chispas animadas que aparecen y desaparecen alrededor del borde. Extra opcional: Un leve resplandor o parpadeo cuando se activa, como si irradiara emoción. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Después de que se muestre characterSprite2 por primera vez en el juego, ya no debe volver a aparecer más adelante. Esto es intencional, para evitar que se repita la misma expresión dos veces. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Después de que se muestre characterSprite por primera vez en el juego, ya no debe volver a aparecer más adelante. Esto es intencional, para evitar que se repita la misma expresión dos veces. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Character = Container.expand(function () { var self = Container.call(this); var sprite = self.attachAsset('characterSprite', { anchorX: 0.5, anchorY: 1, x: 280, y: 2732 - 700 }); var sprite2 = self.attachAsset('characterSprite2', { anchorX: 0.5, anchorY: 1, x: 280, y: 2732 - 700 }); sprite2.visible = false; var sprite3 = self.attachAsset('characterSprite3', { anchorX: 0.5, anchorY: 1, x: 280, y: 2732 - 700 }); sprite3.visible = false; // Animation state tracking var currentActiveSprite = null; var idleTimer = null; var blinkTimer = null; var sparkleTimer = null; // Create sweat drop for sprite1 (shame) var sweatDrop = self.attachAsset('sparkle', { anchorX: 0.5, anchorY: 1, x: 300, y: 2732 - 780, scaleX: 0.8, scaleY: 0.8, alpha: 0, visible: false }); // Create sparkles for sprite3 (enthusiasm) var sparkles = []; for (var i = 0; i < 5; i++) { var sparkle = self.attachAsset('sparkle', { anchorX: 0.5, anchorY: 0.5, x: 280 + (Math.random() - 0.5) * 200, y: 2732 - 700 + (Math.random() - 0.5) * 200, scaleX: 0.5, scaleY: 0.5, alpha: 0, visible: false }); sparkles.push(sparkle); } // Entrance animations self.playEntranceAnimation = function (spriteType) { if (spriteType === 'shame') { // characterSprite // Fade in from bottom with horizontal shake sprite.alpha = 0; sprite.y = 2732 - 650; // Start slightly below normal position tween(sprite, { alpha: 1, y: 2732 - 700 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { // Add slight horizontal shake self.addHorizontalShake(sprite); self.startIdleAnimation('shame'); } }); } else if (spriteType === 'thoughtful') { // characterSprite2 // Zoom with blur effect (simulated with scale and alpha) sprite2.scaleX = 1.5; sprite2.scaleY = 1.5; sprite2.alpha = 0.3; tween(sprite2, { scaleX: 1.0, scaleY: 1.0, alpha: 1.0 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { self.startIdleAnimation('thoughtful'); } }); } else if (spriteType === 'enthusiastic') { // characterSprite3 // Elastic pop-up from below sprite3.y = 2732 - 600; sprite3.scaleX = 0.3; sprite3.scaleY = 0.3; tween(sprite3, { y: 2732 - 700, scaleX: 1.0, scaleY: 1.0 }, { duration: 700, easing: tween.elasticOut, onFinish: function onFinish() { self.startIdleAnimation('enthusiastic'); } }); } }; // Idle animations self.startIdleAnimation = function (spriteType) { self.stopIdleAnimation(); // Clear any existing animations if (spriteType === 'shame') { // Occasional blink and sweat drop blinkTimer = LK.setInterval(function () { if (sprite.visible && sprite.alpha > 0.9) { tween(sprite, { alpha: 0.7 }, { duration: 100, onFinish: function onFinish() { tween(sprite, { alpha: 1.0 }, { duration: 100 }); } }); } }, 3000 + Math.random() * 2000); // Sweat drop animation var sweatTimer = LK.setInterval(function () { if (sprite.visible && sweatDrop) { sweatDrop.visible = true; sweatDrop.alpha = 0; sweatDrop.y = 2732 - 780; tween(sweatDrop, { alpha: 0.8, y: 2732 - 720 }, { duration: 1500, easing: tween.easeIn, onFinish: function onFinish() { tween(sweatDrop, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { sweatDrop.visible = false; } }); } }); } }, 5000 + Math.random() * 3000); } else if (spriteType === 'thoughtful') { // Eye reflection and gentle swaying var reflectionTimer = LK.setInterval(function () { if (sprite2.visible) { // Simulate eye reflection with brief brightness tween(sprite2, { tint: 0xffffff }, { duration: 200, onFinish: function onFinish() { tween(sprite2, { tint: 0xf0f0f0 }, { duration: 300, onFinish: function onFinish() { tween(sprite2, { tint: 0xffffff }, { duration: 200 }); } }); } }); } }, 4000 + Math.random() * 2000); // Gentle side-to-side sway idleTimer = LK.setInterval(function () { if (sprite2.visible) { var originalX = 280; tween(sprite2, { x: originalX + 5 }, { duration: 1500, easing: tween.easeInOut, onFinish: function onFinish() { tween(sprite2, { x: originalX - 5 }, { duration: 1500, easing: tween.easeInOut, onFinish: function onFinish() { tween(sprite2, { x: originalX }, { duration: 1500, easing: tween.easeInOut }); } }); } }); } }, 3000); } else if (spriteType === 'enthusiastic') { // Sparkles and periodic glow sparkleTimer = LK.setInterval(function () { if (sprite3.visible) { for (var i = 0; i < sparkles.length; i++) { var sparkle = sparkles[i]; sparkle.visible = true; sparkle.alpha = 0; sparkle.x = 280 + (Math.random() - 0.5) * 150; sparkle.y = 2732 - 700 + (Math.random() - 0.5) * 150; sparkle.scaleX = 0.3 + Math.random() * 0.4; sparkle.scaleY = sparkle.scaleX; tween(sparkle, { alpha: 0.8 + Math.random() * 0.2, scaleX: sparkle.scaleX * 1.5, scaleY: sparkle.scaleY * 1.5 }, { duration: 800 + Math.random() * 400, easing: tween.easeOut, onFinish: function onFinish() { tween(sparkle, { alpha: 0, scaleX: sparkle.scaleX * 0.5, scaleY: sparkle.scaleY * 0.5 }, { duration: 400, onFinish: function onFinish() { sparkle.visible = false; } }); } }); } } }, 2000 + Math.random() * 1000); // Periodic bright glow on borders var glowTimer = LK.setInterval(function () { if (sprite3.visible) { tween(sprite3, { tint: 0xffff99 }, { duration: 300, onFinish: function onFinish() { tween(sprite3, { tint: 0xffffff }, { duration: 500 }); } }); } }, 3500 + Math.random() * 2000); } }; // Exit animations self.playExitAnimation = function (spriteType, onComplete) { self.stopIdleAnimation(); // Stop idle animations if (spriteType === 'shame') { // Fade down with head lowering tween(sprite, { alpha: 0, y: 2732 - 650, scaleY: 0.9 }, { duration: 600, easing: tween.easeIn, onFinish: onComplete || function () {} }); } else if (spriteType === 'thoughtful') { // Gradual dissolution tween(sprite2, { alpha: 0 }, { duration: 800, easing: tween.easeOut, onFinish: onComplete || function () {} }); } else if (spriteType === 'enthusiastic') { // Flash out tween(sprite3, { tint: 0xffff00 }, { duration: 200, onFinish: function onFinish() { tween(sprite3, { alpha: 0, scaleX: 1.2, scaleY: 1.2 }, { duration: 400, easing: tween.easeIn, onFinish: function onFinish() { sprite3.tint = 0xffffff; // Reset tint if (onComplete) onComplete(); } }); } }); } }; // Helper function for horizontal shake self.addHorizontalShake = function (target) { var originalX = target.x; var shakeCount = 0; var maxShakes = 6; function shake() { if (shakeCount < maxShakes) { var offset = (Math.random() - 0.5) * 8; tween(target, { x: originalX + offset }, { duration: 50, onFinish: function onFinish() { shakeCount++; shake(); } }); } else { tween(target, { x: originalX }, { duration: 100 }); } } shake(); }; // Stop all idle animations self.stopIdleAnimation = function () { if (idleTimer) { LK.clearInterval(idleTimer); idleTimer = null; } if (blinkTimer) { LK.clearInterval(blinkTimer); blinkTimer = null; } if (sparkleTimer) { LK.clearInterval(sparkleTimer); sparkleTimer = null; } // Hide all effects sweatDrop.visible = false; for (var i = 0; i < sparkles.length; i++) { sparkles[i].visible = false; } }; self.show = function (isDecisionMoment, isMotivated) { // Stop any current animations self.stopIdleAnimation(); tween.stop(sprite); tween.stop(sprite2); tween.stop(sprite3); sprite.tint = 0xffffff; // Always use white/no tint var newActiveSprite = null; var animationType = ''; if (isMotivated) { // Transition to enthusiastic sprite if (currentActiveSprite !== sprite3) { if (currentActiveSprite) { var oldSpriteType = currentActiveSprite === sprite ? 'shame' : currentActiveSprite === sprite2 ? 'thoughtful' : 'enthusiastic'; self.playExitAnimation(oldSpriteType, function () { sprite.visible = false; sprite2.visible = false; sprite3.visible = true; self.playEntranceAnimation('enthusiastic'); }); } else { sprite.visible = false; sprite2.visible = false; sprite3.visible = true; self.playEntranceAnimation('enthusiastic'); } newActiveSprite = sprite3; } else { self.startIdleAnimation('enthusiastic'); } } else if (isDecisionMoment) { // Transition to thoughtful sprite if (currentActiveSprite !== sprite2) { if (currentActiveSprite) { var oldSpriteType = currentActiveSprite === sprite ? 'shame' : currentActiveSprite === sprite2 ? 'thoughtful' : 'enthusiastic'; self.playExitAnimation(oldSpriteType, function () { sprite.visible = false; sprite2.visible = true; sprite3.visible = false; self.playEntranceAnimation('thoughtful'); }); } else { sprite.visible = false; sprite2.visible = true; sprite3.visible = false; self.playEntranceAnimation('thoughtful'); } newActiveSprite = sprite2; } else { self.startIdleAnimation('thoughtful'); } } else { // Transition to shame sprite if (currentActiveSprite !== sprite) { if (currentActiveSprite) { var oldSpriteType = currentActiveSprite === sprite ? 'shame' : currentActiveSprite === sprite2 ? 'thoughtful' : 'enthusiastic'; self.playExitAnimation(oldSpriteType, function () { sprite.visible = true; sprite2.visible = false; sprite3.visible = false; self.playEntranceAnimation('shame'); }); } else { sprite.visible = true; sprite2.visible = false; sprite3.visible = false; self.playEntranceAnimation('shame'); } newActiveSprite = sprite; } else { self.startIdleAnimation('shame'); } } currentActiveSprite = newActiveSprite; self.visible = true; }; self.hide = function () { if (currentActiveSprite) { var spriteType = currentActiveSprite === sprite ? 'shame' : currentActiveSprite === sprite2 ? 'thoughtful' : 'enthusiastic'; self.playExitAnimation(spriteType, function () { self.visible = false; currentActiveSprite = null; }); } else { self.visible = false; } }; return self; }); var ChoiceSystem = Container.expand(function () { var self = Container.call(this); var choices = []; var interactionBlocker = null; var animationActive = false; self.showChoices = function (choiceOptions) { self.clearChoices(); // Check if this is the first scene with crossroads choices if (currentScene === 0 && choiceOptions.length === 2 && choiceOptions[0].text === 'Contarle todo a mamá' && choiceOptions[1].text === 'Mantenerlo en secreto') { // Play crossroads song for this specific choice moment LK.stopMusic(); LK.playMusic('theCrossroadsSong'); } // Check if this is the school scene with three route choices if (currentScene === 2 && choiceOptions.length === 3 && choiceOptions[0].text === 'Acercarme a Aiko' && choiceOptions[1].text === 'Hablar con Yui' && choiceOptions[2].text === 'Seguir a Hikari') { // Play crossroads song for this specific choice moment LK.stopMusic(); LK.playMusic('theCrossroadsSong'); } // Check if this is Aiko route tutoring choice moment if (currentScene === 3 && choiceOptions.length === 2 && choiceOptions[0].text === 'Pedirle que sea mi tutora' && choiceOptions[1].text === 'Sugerir estudiar juntos como amigos') { // Play crossroads song for this specific choice moment LK.stopMusic(); LK.playMusic('theCrossroadsSong'); } // Update character sprite for decision moment if Satoshi is visible if (selectedRoute && character.visible) { character.show(true); } // Create invisible interaction blocker overlay interactionBlocker = self.attachAsset('choiceButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1100, scaleX: 2, scaleY: 3, alpha: 0 }); interactionBlocker.interactive = true; interactionBlocker.down = function () {}; // Block all interactions animationActive = true; for (var i = 0; i < choiceOptions.length; i++) { var choice = choiceOptions[i]; // Determine slide direction (alternate left/right) var slideDirection = i % 2 === 0 ? -100 : 100; // Choice button wallpaper - positioned and centered with choiceButton within 2048x2048 scene area var choiceButtonWallpaper = self.attachAsset('choiceButtonWallpaper', { anchorX: 0.5, anchorY: 0.5, x: 1024 + slideDirection, y: 900 + i * 400, alpha: 0, scaleX: 0.95, scaleY: 0.95 }); choiceButtonWallpaper.interactive = false; var choiceBtn = self.attachAsset('choiceButton', { anchorX: 0.5, anchorY: 0.5, x: 1024 + slideDirection, y: 900 + i * 400, alpha: 0, scaleX: 0.95, scaleY: 0.95 }); choiceBtn.interactive = false; var choiceText = new Text2(choice.text, { size: 85, fill: 0x000000, wordWrap: true, wordWrapWidth: 750 }); choiceText.anchor.set(0.5, 0.5); choiceText.x = choiceBtn.x; choiceText.y = choiceBtn.y; choiceText.alpha = 0; choiceText.scaleX = 0.95; choiceText.scaleY = 0.95; self.addChild(choiceText); choiceBtn.choiceData = choice; choiceBtn.down = function () { if (!animationActive) { // Stop all currently playing voice lines to prevent overlap LK.getSound('aikoAudioLine1').stop(); LK.getSound('aikoAudioLine2').stop(); LK.getSound('aikoAudioLine3').stop(); LK.getSound('aikoAudioLine4').stop(); LK.getSound('aikoAudioLine5').stop(); LK.getSound('audioAikoLine6').stop(); LK.getSound('aikoAudioLine7').stop(); LK.getSound('aikoAudioLine8').stop(); LK.getSound('aikoAudioLine9').stop(); LK.getSound('aikoAudioLine10').stop(); LK.getSound('yuiAudioLine1').stop(); LK.getSound('yuiAudioLine2').stop(); LK.getSound('yuiAudioLine3').stop(); LK.getSound('yuiAudioLine4').stop(); LK.getSound('yuiAudioLine5').stop(); LK.getSound('yuiAudioLine6').stop(); LK.getSound('yuiAudioLine7').stop(); LK.getSound('Kissonthecheek').stop(); game.makeChoice(this.choiceData); } }; choices.push({ btn: choiceBtn, text: choiceText, wallpaper: choiceButtonWallpaper }); // Animate button with staggered delay var delay = i * 100; // 0.1s delay between buttons var animationDuration = 400; LK.setTimeout(function (buttonIndex) { return function () { var currentChoice = choices[buttonIndex]; // Animate wallpaper tween(currentChoice.wallpaper, { x: 1024, alpha: 1, scaleX: 1.0, scaleY: 1.0 }, { duration: animationDuration, easing: tween.easeOut }); // Animate button tween(currentChoice.btn, { x: 1024, alpha: 1, scaleX: 1.0, scaleY: 1.0 }, { duration: animationDuration, easing: tween.easeOut }); // Animate text tween(currentChoice.text, { x: 1024, alpha: 1, scaleX: 1.0, scaleY: 1.0 }, { duration: animationDuration, easing: tween.easeOut, onFinish: function onFinish() { // Enable interaction only after last button animation completes if (buttonIndex === choiceOptions.length - 1) { // All animations complete - enable interactions animationActive = false; if (interactionBlocker) { interactionBlocker.destroy(); interactionBlocker = null; } for (var j = 0; j < choices.length; j++) { choices[j].btn.interactive = true; choices[j].wallpaper.interactive = true; } } } }); }; }(i), delay); } self.visible = true; }; self.clearChoices = function () { // Immediately disable all interactions animationActive = true; // Create interaction blocker if it doesn't exist if (!interactionBlocker && choices.length > 0) { interactionBlocker = self.attachAsset('choiceButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1100, scaleX: 2, scaleY: 3, alpha: 0 }); interactionBlocker.interactive = true; interactionBlocker.down = function () {}; } for (var i = 0; i < choices.length; i++) { choices[i].btn.interactive = false; if (choices[i].wallpaper) { choices[i].wallpaper.interactive = false; } } if (choices.length > 0) { var animationsRemaining = choices.length * 3; // 3 elements per choice var animationDuration = 300; for (var i = 0; i < choices.length; i++) { // Animate wallpaper out tween(choices[i].wallpaper, { alpha: 0, y: choices[i].wallpaper.y + 40, scaleX: 0.95, scaleY: 0.95 }, { duration: animationDuration, easing: tween.easeIn, onFinish: function onFinish() { animationsRemaining--; if (animationsRemaining === 0) { // All fade animations complete - destroy elements for (var j = 0; j < choices.length; j++) { choices[j].btn.destroy(); choices[j].text.destroy(); if (choices[j].wallpaper) { choices[j].wallpaper.destroy(); } } choices = []; animationActive = false; if (interactionBlocker) { interactionBlocker.destroy(); interactionBlocker = null; } self.visible = false; } } }); // Animate button out tween(choices[i].btn, { alpha: 0, y: choices[i].btn.y + 40, scaleX: 0.95, scaleY: 0.95 }, { duration: animationDuration, easing: tween.easeIn, onFinish: function onFinish() { animationsRemaining--; if (animationsRemaining === 0) { for (var j = 0; j < choices.length; j++) { choices[j].btn.destroy(); choices[j].text.destroy(); if (choices[j].wallpaper) { choices[j].wallpaper.destroy(); } } choices = []; animationActive = false; if (interactionBlocker) { interactionBlocker.destroy(); interactionBlocker = null; } self.visible = false; } } }); // Animate text out tween(choices[i].text, { alpha: 0, y: choices[i].text.y + 40, scaleX: 0.95, scaleY: 0.95 }, { duration: animationDuration, easing: tween.easeIn, onFinish: function onFinish() { animationsRemaining--; if (animationsRemaining === 0) { for (var j = 0; j < choices.length; j++) { choices[j].btn.destroy(); choices[j].text.destroy(); if (choices[j].wallpaper) { choices[j].wallpaper.destroy(); } } choices = []; animationActive = false; if (interactionBlocker) { interactionBlocker.destroy(); interactionBlocker = null; } self.visible = false; } } }); } } else { // No choices to animate - clear immediately choices = []; animationActive = false; if (interactionBlocker) { interactionBlocker.destroy(); interactionBlocker = null; } self.visible = false; } }; return self; }); var DialogSystem = Container.expand(function () { var self = Container.call(this); // Dialog box var dialogBox = self.attachAsset('dialogBox', { anchorX: 0.5, anchorY: 1, x: 1024, y: 2732 - 200 }); // Variables for text acceleration var isDialogPressed = false; var normalTypewriterDelay = 50; var fastTypewriterDelay = 10; // Name box wallpaper - positioned and centered with nameBox var nameBoxWallpaper = self.attachAsset('nameBoxWallpaper', { anchorX: 0.5, anchorY: 0.5, x: 250, // Centered with nameBox x position (50) + nameBox width/2 (200) y: 2732 - 590 // Centered with nameBox y position }); // Name box var nameBox = self.attachAsset('nameBox', { anchorX: 0, anchorY: 1, x: 50, y: 2732 - 550 }); // Texts var nameText = new Text2('', { size: 80, fill: 0x000000 }); nameText.anchor.set(0.5, 0.5); nameText.x = nameBox.x + 200; nameText.y = nameBox.y - 40; self.addChild(nameText); var dialogText = new Text2('', { size: 90, fill: 0x000000, wordWrap: true, wordWrapWidth: 1400 }); dialogText.anchor.set(0, 0); dialogText.x = dialogBox.x - 900; dialogText.y = dialogBox.y - 280; self.addChild(dialogText); // Next button var nextBtn = self.attachAsset('nextButton', { anchorX: 0.5, anchorY: 0.5, x: 1750, y: 2732 - 350 }); var nextText = new Text2('', { size: 85, fill: 0x000000 }); nextText.anchor.set(0.5, 0.5); nextText.x = nextBtn.x; nextText.y = nextBtn.y; self.addChild(nextText); self.showDialog = function (speaker, text) { nameText.setText(speaker); // Clear previous text and hide next button during typing dialogText.setText(''); nextBtn.visible = false; nextText.visible = false; nextBtn.alpha = 0; nextText.alpha = 0; nextBtn.interactive = false; // Show nameBoxWallpaper and nameBox together nameBoxWallpaper.visible = true; nameBox.visible = true; self.visible = true; // Reset acceleration state isDialogPressed = false; // Typewriter effect variables var currentCharIndex = 0; var typewriterDelay = normalTypewriterDelay; // Function to add next character function addNextCharacter() { if (currentCharIndex < text.length) { dialogText.setText(text.substring(0, currentCharIndex + 1)); currentCharIndex++; // Use current delay based on press state typewriterDelay = isDialogPressed ? fastTypewriterDelay : normalTypewriterDelay; // Schedule next character LK.setTimeout(addNextCharacter, typewriterDelay); } else { // Typing complete - show next button unless GAME OVER if (speaker === 'GAME OVER') { nextBtn.visible = false; nextText.visible = false; } else { nextBtn.visible = true; nextText.visible = true; // Entry animation: scale from 0.0x to 1.0x nextBtn.scaleX = 0; nextBtn.scaleY = 0; nextText.scaleX = 0; nextText.scaleY = 0; tween(nextBtn, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { nextBtn.interactive = true; // Start bounce animation after entry self.startBounceAnimation(); } }); tween(nextText, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 300, easing: tween.easeOut }); } } } // Start typewriter effect addNextCharacter(); }; self.hide = function () { // Hide nameBoxWallpaper and nameBox together nameBoxWallpaper.visible = false; nameBox.visible = false; self.visible = false; }; // Dialog box press handlers for text acceleration dialogBox.down = function () { isDialogPressed = true; }; dialogBox.up = function () { isDialogPressed = false; }; nextBtn.down = function () { // Stop all currently playing voice lines to prevent overlap LK.getSound('aikoAudioLine1').stop(); LK.getSound('aikoAudioLine2').stop(); LK.getSound('aikoAudioLine3').stop(); LK.getSound('aikoAudioLine4').stop(); LK.getSound('aikoAudioLine5').stop(); LK.getSound('audioAikoLine6').stop(); LK.getSound('aikoAudioLine7').stop(); LK.getSound('aikoAudioLine8').stop(); LK.getSound('aikoAudioLine9').stop(); LK.getSound('aikoAudioLine10').stop(); LK.getSound('yuiAudioLine1').stop(); LK.getSound('yuiAudioLine2').stop(); LK.getSound('yuiAudioLine3').stop(); LK.getSound('yuiAudioLine4').stop(); LK.getSound('yuiAudioLine5').stop(); LK.getSound('yuiAudioLine6').stop(); LK.getSound('yuiAudioLine7').stop(); LK.getSound('Kissonthecheek').stop(); // Stop bounce animation when pressed self.stopBounceAnimation(); // Disable button interaction immediately nextBtn.interactive = false; // Exit animation: scale from 1.0x to 0.0x tween(nextBtn, { scaleX: 0, scaleY: 0 }, { duration: 200, easing: tween.easeIn, onFinish: function onFinish() { nextBtn.visible = false; // Execute original button logic after animation if (game.currentChoices.length > 0) { game.showChoices(); } else { game.nextDialog(); } } }); tween(nextText, { scaleX: 0, scaleY: 0 }, { duration: 200, easing: tween.easeIn, onFinish: function onFinish() { nextText.visible = false; } }); }; // Bounce animation for next button var bounceTimer = null; var originalNextBtnX = 1750; self.startBounceAnimation = function () { // Clear any existing bounce timer if (bounceTimer) { LK.clearInterval(bounceTimer); } // Start bounce animation every 4 seconds bounceTimer = LK.setInterval(function () { if (!nextBtn.visible || !nextBtn.interactive) return; // First bounce: +8 px tween(nextBtn, { x: originalNextBtnX + 8 }, { duration: 75, easing: tween.easeInOut, onFinish: function onFinish() { // Return to original position tween(nextBtn, { x: originalNextBtnX }, { duration: 75, easing: tween.easeInOut, onFinish: function onFinish() { // Second bounce: +16 px tween(nextBtn, { x: originalNextBtnX + 16 }, { duration: 75, easing: tween.easeInOut, onFinish: function onFinish() { // Return to original position tween(nextBtn, { x: originalNextBtnX }, { duration: 75, easing: tween.easeInOut }); } }); } }); } }); }, 4000); }; self.stopBounceAnimation = function () { if (bounceTimer) { LK.clearInterval(bounceTimer); bounceTimer = null; } }; return self; }); var MathEvaluation = Container.expand(function () { var self = Container.call(this); var currentInputIndex = 0; var answers = ['', '', '', '']; var problems = [{ question: '8 + 5 = ', answer: '13' }, { question: '12 - 4 = ', answer: '8' }, { question: '3 × 6 = ', answer: '18' }, { question: '16 ÷ 4 = ', answer: '4' }]; var inputFields = []; var questionTexts = []; // Background var mathBackground = self.attachAsset('mathEvaluationBackground', { x: 0, y: 0 }); // Grid lines for notebook effect for (var i = 0; i < 50; i++) { var gridLine = self.attachAsset('gridLine', { x: 0, y: i * 50, scaleX: 40 }); } // Aiko character var aikoSprite = self.attachAsset('aikoEvaluation', { anchorX: 0.5, anchorY: 1, x: 1700, y: 1200, scaleX: 0.8, scaleY: 0.8 }); // Title var titleText = new Text2('Evaluación Matemática', { size: 120, fill: 0x000000 }); titleText.anchor.set(0.5, 0); titleText.x = 1024; titleText.y = 200; self.addChild(titleText); // Create problems and input fields for (var i = 0; i < problems.length; i++) { var questionText = new Text2(i + 1 + '. ' + problems[i].question, { size: 100, fill: 0x000000 }); questionText.anchor.set(0, 0.5); questionText.x = 300; questionText.y = 500 + i * 200; self.addChild(questionText); questionTexts.push(questionText); var inputField = self.attachAsset('mathEvaluationInput', { anchorX: 0.5, anchorY: 0.5, x: 900, y: 500 + i * 200 }); var inputText = new Text2('', { size: 80, fill: 0x000000 }); inputText.anchor.set(0.5, 0.5); inputText.x = inputField.x; inputText.y = inputField.y; self.addChild(inputText); inputField.inputText = inputText; inputField.problemIndex = i; inputField.down = function () { currentInputIndex = this.problemIndex; }; inputFields.push({ field: inputField, text: inputText }); } // Number buttons var numberButtons = []; for (var i = 0; i <= 9; i++) { var numBtn = self.attachAsset('mathEvaluationButton', { anchorX: 0.5, anchorY: 0.5, x: 200 + i % 5 * 120, y: 1600 + Math.floor(i / 5) * 100 }); var numText = new Text2(i.toString(), { size: 60, fill: 0xffffff }); numText.anchor.set(0.5, 0.5); numText.x = numBtn.x; numText.y = numBtn.y; self.addChild(numText); numBtn.number = i; numBtn.down = function () { if (answers[currentInputIndex].length < 3) { answers[currentInputIndex] += this.number.toString(); inputFields[currentInputIndex].text.setText(answers[currentInputIndex]); } }; numberButtons.push(numBtn); } // Clear button var clearBtn = self.attachAsset('mathEvaluationButton', { anchorX: 0.5, anchorY: 0.5, x: 800, y: 1600 }); var clearText = new Text2('Borrar', { size: 50, fill: 0xffffff }); clearText.anchor.set(0.5, 0.5); clearText.x = clearBtn.x; clearText.y = clearBtn.y; self.addChild(clearText); clearBtn.down = function () { answers[currentInputIndex] = ''; inputFields[currentInputIndex].text.setText(''); }; // Submit button var submitBtn = self.attachAsset('mathEvaluationButton', { anchorX: 0.5, anchorY: 0.5, x: 1000, y: 1600, scaleX: 1.5 }); var submitText = new Text2('Listo', { size: 60, fill: 0xffffff }); submitText.anchor.set(0.5, 0.5); submitText.x = submitBtn.x; submitText.y = submitBtn.y; self.addChild(submitText); submitBtn.down = function () { var allCorrect = true; for (var i = 0; i < problems.length; i++) { if (answers[i] !== problems[i].answer) { allCorrect = false; break; } } if (allCorrect) { game.startRomanticScene(); } else { // Handle incorrect answers - show failure scene game.startMathEvaluationFailure(); } }; return self; }); var RomanticScene = Container.expand(function () { var self = Container.call(this); var currentRomanticDialog = 0; var romanticDialogs = [{ speaker: 'Aiko', text: '...¿Todas correctas? Hmm... No está mal, para alguien como vos.' }, { speaker: 'Aiko', text: 'Vamos.', action: 'transition' }, { speaker: 'Aiko', text: '¿Sabés algo? No esperaba sentirme así después de enseñarle a alguien como vos.' }, { speaker: 'Aiko', text: 'Pero... hay algo que me gusta de tu esfuerzo. ...Y de tus ojos tontos también.' }, { speaker: 'Aiko', text: 'Eso fue por aprobar mi prueba.', action: 'kiss' }]; // Classroom at sunset background var sunsetBackground = self.attachAsset('aulaAtardecer', { x: 0, y: 0 }); // Aiko character - hidden by default since this is not math evaluation var aikoSprite = self.attachAsset('aikoEvaluation', { anchorX: 0.5, anchorY: 1, x: 1400, y: 2200, visible: false }); self.showRomanticDialog = function () { if (currentRomanticDialog >= romanticDialogs.length) { self.showFinalChoices(); return; } var dialog = romanticDialogs[currentRomanticDialog]; dialogSystem.showDialog(dialog.speaker, dialog.text); // Play aikoAudioLine5 when Aiko says the specific dialog about all correct answers if (dialog.speaker === 'Aiko' && dialog.text === '...¿Todas correctas? Hmm... No está mal, para alguien como vos.') { LK.getSound('aikoAudioLine5').play(); } // Play aikoAudioLine6 when Aiko says "Vamos." if (dialog.speaker === 'Aiko' && dialog.text === 'Vamos.') { LK.getSound('audioAikoLine6').play(); } // Play aikoAudioLine7 when Aiko says the specific dialog about unexpected feelings if (dialog.speaker === 'Aiko' && dialog.text === '¿Sabés algo? No esperaba sentirme así después de enseñarle a alguien como vos.') { LK.getSound('aikoAudioLine7').play(); } // Play aikoAudioLine8 when Aiko says dialog about effort and silly eyes if (dialog.speaker === 'Aiko' && dialog.text === 'Pero... hay algo que me gusta de tu esfuerzo. ...Y de tus ojos tontos también.') { LK.getSound('aikoAudioLine8').play(); } // Play kiss sound effect followed by aikoAudioLine9 when Aiko says kiss dialog if (dialog.speaker === 'Aiko' && dialog.text === 'Eso fue por aprobar mi prueba.') { var kissSound = LK.getSound('Kissonthecheek'); kissSound.play(); // Wait for kiss sound to finish completely before playing voice LK.setTimeout(function () { LK.getSound('aikoAudioLine9').play(); }, 3000); // Further increased timing to create clear separation between sounds } if (dialog.action === 'transition') { // Create cleaning room background with fade transition var cleaningBackground = self.attachAsset('cuartoLimpiezaBackground', { x: 0, y: 0, alpha: 0 }); // Send background to back self.setChildIndex(cleaningBackground, 0); // Fade out sunset background and fade in cleaning background simultaneously tween(sunsetBackground, { alpha: 0 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { sunsetBackground.destroy(); } }); tween(cleaningBackground, { alpha: 1 }, { duration: 800, easing: tween.easeInOut }); // Keep aikoEvaluation hidden during romantic scene self.setChildIndex(aikoSprite, self.children.length - 1); // Ensure dialog system and choice system are visible and in front if (dialogSystem) { game.setChildIndex(dialogSystem, game.children.length - 1); dialogSystem.visible = true; } if (choiceSystem) { game.setChildIndex(choiceSystem, game.children.length - 1); choiceSystem.visible = true; } currentRomanticDialog++; } else if (dialog.text === '¿Sabés algo? No esperaba sentirme así después de enseñarle a alguien como vos.') { // Change background to school corridor for this specific dialog with fade transition var corridorBackground = self.attachAsset('schoolcorridor', { x: 0, y: 0, alpha: 0 }); // Send background to back self.setChildIndex(corridorBackground, 0); // Fade out current background and fade in corridor background if (self.children.length > 1) { var oldBackground = self.children[1]; // Get the previous background (index 1 since corridor is now at 0) if (oldBackground && oldBackground.destroy) { tween(oldBackground, { alpha: 0 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { oldBackground.destroy(); } }); } } tween(corridorBackground, { alpha: 1 }, { duration: 800, easing: tween.easeInOut }); // Keep aikoEvaluation hidden during romantic scene self.setChildIndex(aikoSprite, self.children.length - 1); // Ensure dialog system and choice system are visible and in front if (dialogSystem) { game.setChildIndex(dialogSystem, game.children.length - 1); dialogSystem.visible = true; } if (choiceSystem) { game.setChildIndex(choiceSystem, game.children.length - 1); choiceSystem.visible = true; } currentRomanticDialog++; } else if (dialog.text === 'Eso fue por aprobar mi prueba.') { // Change background to AikoKiss for this specific dialog with fade transition // Store reference to current background before creating new one var oldBackground = null; if (self.children.length > 0) { oldBackground = self.children[0]; } var kissBackground = self.attachAsset('AikoKiss', { x: 0, y: 0, alpha: 0 }); // Send background to back self.setChildIndex(kissBackground, 0); // Fade out current background and fade in kiss background if (oldBackground && oldBackground.destroy) { tween(oldBackground, { alpha: 0 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { oldBackground.destroy(); } }); } tween(kissBackground, { alpha: 1 }, { duration: 800, easing: tween.easeInOut }); // Show kiss effect LK.effects.flashScreen(0xff69b4, 500); var kissText = new Text2('Satoshi ha sido besado por primera vez.', { size: 80, fill: 0xff1493 }); kissText.anchor.set(0.5, 0.5); kissText.x = 1024; kissText.y = 1366; self.addChild(kissText); currentRomanticDialog++; } else if (dialog.action === 'kiss') { // Show kiss effect LK.effects.flashScreen(0xff69b4, 500); var kissText = new Text2('Satoshi ha sido besado por primera vez.', { size: 80, fill: 0xff1493 }); kissText.anchor.set(0.5, 0.5); kissText.x = 1024; kissText.y = 1366; self.addChild(kissText); currentRomanticDialog++; } else { currentRomanticDialog++; } }; self.showFinalChoices = function () { dialogSystem.hide(); // Play crossroads music for the final romantic choice moment LK.stopMusic(); LK.playMusic('theCrossroadsSong'); var finalChoices = [{ text: 'Aiko... quiero más que un beso.', type: 'romantic' }, { text: 'No... no puedo hacer esto contigo.', type: 'reject' }]; choiceSystem.showChoices(finalChoices); }; return self; }); var TitleScreen = Container.expand(function () { var self = Container.call(this); // Background var spaceBackground = self.attachAsset('titleSpaceBackground', { x: 0, y: 0 }); // Stars array for twinkling effect var stars = []; for (var i = 0; i < 50; i++) { var star = self.attachAsset('titleStar', { anchorX: 0.5, anchorY: 0.5, x: Math.random() * 2048, y: Math.random() * 2732 }); stars.push(star); } // Hyperstar setup var hyperStar = self.attachAsset('titleHyperStar', { anchorX: 0.5, anchorY: 0.5, x: Math.random() * 2048, y: Math.random() * 2732, alpha: 0 }); // Logo setup (starts tiny) var logo = self.attachAsset('titleScreenLogo', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 800, scaleX: 0.1, scaleY: 0.1 }); // Start button (starts off screen) var startButton = self.attachAsset('titleStartButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: -500 }); // Earth for transition var earth = self.attachAsset('titleEarth', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 2000, scaleX: 0.3, scaleY: 0.3 }); // Cat setup var catSprites = ['titleCatFloat', 'titleCatJump', 'titleCatMeow', 'titleCatPlay', 'titleCatSleep', 'titleCatEat']; var currentCatSprite = 0; var catTouchCount = 0; var catAngry = false; var catRemoved = false; var cat = self.attachAsset('titleCatFloat', { anchorX: 0.5, anchorY: 0.5, x: 300, y: 1200, scaleX: 1.5, scaleY: 1.5 }); var catVelocityX = 1; var catVelocityY = 0.5; // Cat spaceship (hidden initially) var catSpaceship = self.attachAsset('titleCatSpaceship', { anchorX: 0.5, anchorY: 0.5, x: -300, y: cat.y, scaleX: 1.2, scaleY: 1.2, visible: false }); // Timers var starTwinkleTimer = 0; var hyperStarTimer = 0; var catAnimationTimer = 0; var hyperStarActive = false; // Initialize animations self.initAnimations = function () { // Logo grow animation tween(logo, { scaleX: 1.0, scaleY: 1.0 }, { duration: 2000, easing: tween.elasticOut }); // Start button bounce in tween(startButton, { y: 1800 }, { duration: 1500, easing: tween.bounceOut }); }; self.update = function () { if (catRemoved) return; // Star twinkling starTwinkleTimer++; if (starTwinkleTimer % 60 === 0) { var randomStar = stars[Math.floor(Math.random() * stars.length)]; tween(randomStar, { alpha: 0.3 }, { duration: 300, onFinish: function onFinish() { tween(randomStar, { alpha: 1 }, { duration: 300 }); } }); } // Additional star twinkling for more frequent blinking if (starTwinkleTimer % 30 === 0) { var randomStar2 = stars[Math.floor(Math.random() * stars.length)]; tween(randomStar2, { alpha: 0.1 }, { duration: 200, onFinish: function onFinish() { tween(randomStar2, { alpha: 1 }, { duration: 400 }); } }); } // Continuous gentle twinkling for all stars if (starTwinkleTimer % 15 === 0) { for (var i = 0; i < stars.length; i++) { if (Math.random() < 0.3) { // 30% chance for each star var star = stars[i]; tween(star, { alpha: 0.5 + Math.random() * 0.5 }, { duration: 500 + Math.random() * 1000 }); } } } // Hyperstar movement hyperStarTimer++; if (hyperStarTimer % 900 === 0) { // Every 15 seconds if (!hyperStarActive) { hyperStarActive = true; hyperStar.x = Math.random() * 2048; hyperStar.y = Math.random() * 2732; tween(hyperStar, { alpha: 1 }, { duration: 500, onFinish: function onFinish() { var targetX = Math.random() * 2048; var targetY = Math.random() * 2732; tween(hyperStar, { x: targetX, y: targetY }, { duration: 2000, easing: tween.linear, onFinish: function onFinish() { tween(hyperStar, { alpha: 0 }, { duration: 500, onFinish: function onFinish() { hyperStarActive = false; } }); } }); } }); } } // Cat floating movement if (!catAngry) { cat.x += catVelocityX; cat.y += catVelocityY; // Bounce off edges if (cat.x <= 100 || cat.x >= 1948) { catVelocityX *= -1; } if (cat.y <= 100 || cat.y >= 2632) { catVelocityY *= -1; } // Random sprite change catAnimationTimer++; if (catAnimationTimer % 180 === 0) { currentCatSprite = (currentCatSprite + 1) % catSprites.length; cat.destroy(); cat = self.attachAsset(catSprites[currentCatSprite], { anchorX: 0.5, anchorY: 0.5, x: cat.x, y: cat.y, scaleX: 1.5, scaleY: 1.5 }); // Re-add touch handler cat.down = function () { if (catRemoved) return; catTouchCount++; if (catTouchCount >= 10 && !catAngry) { self.makeCatAngry(); } }; } } }; self.makeCatAngry = function () { catAngry = true; cat.destroy(); cat = self.attachAsset('titleCatAngry', { anchorX: 0.5, anchorY: 0.5, x: cat.x, y: cat.y, scaleX: 1.5, scaleY: 1.5 }); // After 1 second, show spaceship LK.setTimeout(function () { catSpaceship.visible = true; catSpaceship.y = cat.y; // Move spaceship to cat tween(catSpaceship, { x: cat.x - 100 }, { duration: 2000, easing: tween.linear, onFinish: function onFinish() { // Move cat and spaceship to Earth tween(cat, { x: earth.x, y: earth.y, scaleX: 0.3, scaleY: 0.3 }, { duration: 3000, easing: tween.easeInOut }); tween(catSpaceship, { x: earth.x, y: earth.y, scaleX: 0.3, scaleY: 0.3 }, { duration: 3000, easing: tween.easeInOut, onFinish: function onFinish() { cat.visible = false; catSpaceship.visible = false; catRemoved = true; } }); } }); }, 1000); }; // Start button handler startButton.down = function () { // Zoom to Earth transition tween(earth, { scaleX: 50, scaleY: 50 }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { game.startMainGame(); } }); // Zoom cat and move it in random direction if not removed if (!catRemoved) { // Random direction: 0-7 (8 directions: edges and corners) var direction = Math.floor(Math.random() * 8); var targetX, targetY; // Calculate target position based on direction switch (direction) { case 0: // Left edge targetX = -300; targetY = cat.y; break; case 1: // Right edge targetX = 2348; targetY = cat.y; break; case 2: // Top edge targetX = cat.x; targetY = -300; break; case 3: // Bottom edge targetX = cat.x; targetY = 3032; break; case 4: // Top-left corner targetX = -300; targetY = -300; break; case 5: // Top-right corner targetX = 2348; targetY = -300; break; case 6: // Bottom-left corner targetX = -300; targetY = 3032; break; case 7: // Bottom-right corner targetX = 2348; targetY = 3032; break; } // Apply much faster zoom and movement to cat tween(cat, { scaleX: 100, scaleY: 100, x: targetX, y: targetY }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { cat.visible = false; } }); } }; // Cat touch handler cat.down = function () { if (catRemoved) return; catTouchCount++; if (catTouchCount >= 10 && !catAngry) { self.makeCatAngry(); } }; return self; }); var WelcomeScreen = Container.expand(function () { var self = Container.call(this); var playerName = ''; var isCapitalized = false; var keyboardMode = 'letters'; // 'letters', 'symbols1', 'symbols2' // Background var background = self.attachAsset('titleSpaceBackground', { x: 0, y: 0 }); // Welcome text var welcomeText = new Text2('¡BIENVENIDO!', { size: 140, fill: 0xffffff }); welcomeText.anchor.set(0.5, 0.5); welcomeText.x = 1024; welcomeText.y = 500; self.addChild(welcomeText); // Question text var questionText = new Text2('¿Cuál es tu nombre?', { size: 100, fill: 0xffffff }); questionText.anchor.set(0.5, 0.5); questionText.x = 1024; questionText.y = 650; self.addChild(questionText); // Name display box var nameBox = self.attachAsset('inputField', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 800 }); var nameDisplayText = new Text2('', { size: 80, fill: 0x000000 }); nameDisplayText.anchor.set(0.5, 0.5); nameDisplayText.x = nameBox.x; nameDisplayText.y = nameBox.y; self.addChild(nameDisplayText); // Keyboard container var keyboard = new Container(); self.addChild(keyboard); var keys = []; // Letter layouts var letterLayout = [['!#1', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'], ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'Ñ'], ['SHIFT', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '←'], ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'], [',', 'SPACE', '.', 'ENTER']]; var symbols1Layout = [['ABC', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'], ['@', '#', '$', '%', '&', '*', '-', '+', '(', ')'], ['!', '"', "'", ':', ';', '/', '¿', '?', '¡', '=', '←'], ['SPACE', '.', '1/2', 'ENTER']]; var symbols2Layout = [['ABC', '[', ']', '{', '}', '<', '>', '^', '_', '`', '~'], ['|', '\\', '°', '¬', '·', '•', '¶', '§', '×', '÷'], ['€', '£', '¥', '¢', '©', '®', '™', '♡', '♥', '←'], ['SPACE', ',', '2/2', 'ENTER']]; function createKeyboard() { // Clear existing keys for (var i = 0; i < keys.length; i++) { keys[i].btn.destroy(); keys[i].text.destroy(); } keys = []; var layout = keyboardMode === 'letters' ? letterLayout : keyboardMode === 'symbols1' ? symbols1Layout : symbols2Layout; var startY = 1200; var keyWidth = 160; var keyHeight = 120; var keySpacing = 10; for (var row = 0; row < layout.length; row++) { var rowKeys = layout[row]; var totalRowWidth = rowKeys.length * keyWidth + (rowKeys.length - 1) * keySpacing; var startX = (2048 - totalRowWidth) / 2; for (var col = 0; col < rowKeys.length; col++) { var keyText = rowKeys[col]; var keyBtn = keyboard.attachAsset('mathEvaluationButton', { anchorX: 0.5, anchorY: 0.5, x: startX + col * (keyWidth + keySpacing) + keyWidth / 2, y: startY + row * (keyHeight + keySpacing) }); // Adjust special key widths if (keyText === 'SPACE') { keyBtn.scaleX = 3; } else if (keyText === 'SHIFT' || keyText === 'ENTER' || keyText === 'ABC' || keyText === '!#1' || keyText.includes('/') || keyText === '←') { keyBtn.scaleX = 1.2; } var displayText = keyText; if (keyText === 'SPACE') displayText = ' '; if (keyText === '←') displayText = '←'; if (keyText === 'SHIFT') displayText = '↑'; // Show lowercase letters when not in uppercase mode (letters only) if (keyboardMode === 'letters' && keyText.length === 1 && keyText.match(/[A-ZÑ]/)) { if (!isCapitalized && playerName.length > 0) { displayText = keyText.toLowerCase(); } else { displayText = keyText; } } var keyLabel = new Text2(displayText, { size: keyText === 'SPACE' ? 40 : 45, fill: 0xffffff }); keyLabel.anchor.set(0.5, 0.5); keyLabel.x = keyBtn.x; keyLabel.y = keyBtn.y; keyboard.addChild(keyLabel); keyBtn.keyValue = keyText; keyBtn.down = function () { handleKeyPress(this.keyValue); }; keys.push({ btn: keyBtn, text: keyLabel }); } } } function handleKeyPress(key) { if (key === 'ENTER') { if (playerName.length > 0) { storage.playerName = playerName; self.startTitleScreen(); } } else if (key === '←') { if (playerName.length > 0) { playerName = playerName.substring(0, playerName.length - 1); nameDisplayText.setText(playerName); // Reset to uppercase if name becomes empty if (playerName.length === 0) { isCapitalized = false; if (keyboardMode === 'letters') { createKeyboard(); } } } } else if (key === 'SHIFT') { isCapitalized = !isCapitalized; createKeyboard(); } else if (key === 'ABC' || key === '!#1') { if (keyboardMode === 'letters') { keyboardMode = 'symbols1'; } else { keyboardMode = 'letters'; } createKeyboard(); } else if (key === '1/2') { console.log('Switching to symbols2 mode'); keyboardMode = 'symbols2'; createKeyboard(); } else if (key === '2/2') { console.log('Switching back to symbols1 mode'); keyboardMode = 'symbols1'; createKeyboard(); } else if (key === 'SPACE') { if (playerName.length < 20) { playerName += ' '; nameDisplayText.setText(playerName); } } else { // Regular character input if (playerName.length < 20) { var charToAdd = key; if (keyboardMode === 'letters' && key.length === 1 && key.match(/[A-ZÑ]/)) { if (playerName.length === 0 || isCapitalized) { charToAdd = key.toUpperCase(); // Auto-switch to lowercase after first character if (playerName.length === 0) { isCapitalized = false; LK.setTimeout(function () { createKeyboard(); }, 100); } } else { charToAdd = key.toLowerCase(); } } playerName += charToAdd; nameDisplayText.setText(playerName); } } } self.startTitleScreen = function () { // Transition to title screen self.visible = false; game.showTitleScreen(); }; // Initialize with entrance animation self.initAnimations = function () { // Start everything very large (too close to see) welcomeText.scaleX = 20; welcomeText.scaleY = 20; welcomeText.alpha = 0; questionText.scaleX = 15; questionText.scaleY = 15; questionText.alpha = 0; nameBox.scaleX = 10; nameBox.scaleY = 10; nameBox.alpha = 0; nameDisplayText.scaleX = 10; nameDisplayText.scaleY = 10; nameDisplayText.alpha = 0; keyboard.scaleX = 8; keyboard.scaleY = 8; keyboard.alpha = 0; // Animate elements into view with depth effect tween(welcomeText, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 1000, easing: tween.easeOut }); LK.setTimeout(function () { tween(questionText, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 800, easing: tween.easeOut }); }, 300); LK.setTimeout(function () { tween(nameBox, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 600, easing: tween.easeOut }); tween(nameDisplayText, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 600, easing: tween.easeOut }); }, 600); LK.setTimeout(function () { // Position keyboard initially below screen keyboard.y = 2732 + 600; // Start below screen keyboard.scaleX = 1; keyboard.scaleY = 1; keyboard.alpha = 1; // Create keyboard before animation starts createKeyboard(); // Animate keyboard sliding up from bottom tween(keyboard, { y: 0 }, { duration: 800, easing: tween.easeOut }); }, 600); // Start at same time as inputField }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Fondos // Game state var currentScene = 0; var currentDialog = 0; var currentChoices = []; var relationshipPoints = { aiko: 0, yui: 0, hikari: 0, respect: 0, peace: 0, academic: 0 }; var selectedRoute = null; var currentBackground = null; var mathEvaluation = null; var romanticScene = null; var isInMathEvaluation = false; var isInRomanticScene = false; var gameStarted = false; // DialogBox wallpaper - renders behind all backgrounds and dialogBox var dialogBoxWallpaper = game.addChild(LK.getAsset('dialogBoxWallpaper', { x: 0, y: 2048, // Position at bottom area where dialog appears alpha: 1 })); // Send wallpaper to very back (behind all other elements) game.setChildIndex(dialogBoxWallpaper, 0); // Welcome screen (shown first) var welcomeScreen = game.addChild(new WelcomeScreen()); welcomeScreen.initAnimations(); // Title screen (initially hidden) var titleScreen = game.addChild(new TitleScreen()); titleScreen.visible = false; // Do not play title screen music during welcome screen // UI Systems (initially hidden) var dialogSystem = game.addChild(new DialogSystem()); var choiceSystem = game.addChild(new ChoiceSystem()); var character = game.addChild(new Character()); // Hide game elements initially dialogSystem.visible = false; choiceSystem.visible = false; character.visible = false; // Story data var storyScenes = [{ background: 'habitacion', dialogs: [{ speaker: 'Satoshi', text: '¡Ya es mi último año de secundaria! Necesito encontrar novia antes de graduarme.' }, { speaker: 'Satoshi', text: 'Pero primero... mejor hablo con mamá sobre mis planes.' }], choices: [{ text: 'Contarle todo a mamá', effects: { respect: 2, peace: -1 } }, { text: 'Mantenerlo en secreto', effects: { peace: 2, respect: -1 } }] }, { background: 'calle', dialogs: [{ speaker: 'Satoshi', text: 'Camino a la escuela... Hoy conoceré a las chicas que podrían cambiar mi vida.' }] }, { background: 'escuela', dialogs: [{ speaker: 'Satoshi', text: 'Aquí está la escuela. Veo tres chicas que me llaman la atención...' }, { speaker: 'Satoshi', text: 'Aiko, la delegada seria... Yui, mi amiga de la infancia... y Hikari, la misteriosa.' }], choices: [{ text: 'Acercarme a Aiko', route: 'aiko' }, { text: 'Hablar con Yui', route: 'yui' }, { text: 'Seguir a Hikari', route: 'hikari' }] }]; // Route-specific scenes var routeScenes = { aiko: [{ background: 'aula', dialogs: [{ speaker: 'Aiko', text: 'Satoshi-kun, necesitas ser más responsable con tus estudios.' }, { speaker: 'Satoshi', text: 'Tienes razón, Aiko. ¿Me ayudarías a estudiar?' }], choices: [{ text: 'Pedirle que sea mi tutora', effects: { aiko: 3 } }, { text: 'Sugerir estudiar juntos como amigos', effects: { aiko: 1 } }] }, { background: 'Aikosurprised', dialogs: [{ speaker: 'Aiko', text: '...¿Yo? ¿tu tutora?' }, { speaker: 'Aiko', text: 'Está bien. Pero no quiero distracciones. Si no cumplís, se acaba el trato.', backgroundChange: 'aula' }, { speaker: 'Satoshi', text: '¡Lo prometo! Seré el alumno más aplicado que hayas visto.' }] }, { background: 'aula', dialogs: [{ speaker: 'Aiko', text: 'Antes de seguir con estas sesiones, quiero comprobar cuánto sabés.', action: 'startMathEval', backgroundChange: 'Aikosmiling' }, { speaker: 'Aiko', text: 'Nada complicado. Empecemos.' }] }], yui: [{ background: 'patio', dialogs: [{ speaker: 'Yui', text: '¡Satoshi! Como en los viejos tiempos, ¿verdad?' }, { speaker: 'Satoshi', text: 'Sí, Yui... pero ahora te veo diferente.' }], choices: [{ text: 'Confesarle mis sentimientos', effects: { yui: 3 } }, { text: 'Mantener la amistad por ahora', effects: { yui: 1 } }] }], hikari: [{ background: 'aula2', dialogs: [{ speaker: 'Hikari', text: 'Te has dado cuenta de mí... interesante.' }, { speaker: 'Satoshi', text: 'Hay algo especial en ti, Hikari.' }], choices: [{ text: 'Preguntarle sobre su misterio', effects: { hikari: 3 } }, { text: 'Invitarla a caminar', effects: { hikari: 2 } }] }] }; function changeBackground(backgroundType) { // If there's no current background, just create the new one immediately if (!currentBackground) { currentBackground = game.addChild(LK.getAsset(backgroundType, { x: 0, y: 0 })); // Send background to back but after dialogBoxWallpaper game.setChildIndex(currentBackground, 1); // Store background type for future comparison currentBackground.backgroundType = backgroundType; return; } // Check if the new background is the same as the current one if (currentBackground.backgroundType === backgroundType) { // Same background - no transition needed return; } // Create new background with alpha 0 (invisible) var newBackground = game.addChild(LK.getAsset(backgroundType, { x: 0, y: 0, alpha: 0 })); // Send new background to back but after dialogBoxWallpaper game.setChildIndex(newBackground, 1); // Store background type for future comparison newBackground.backgroundType = backgroundType; // Store reference to old background for destruction var oldBackground = currentBackground; currentBackground = newBackground; // Fade out old background and fade in new background simultaneously tween(oldBackground, { alpha: 0 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { oldBackground.destroy(); } }); tween(newBackground, { alpha: 1 }, { duration: 800, easing: tween.easeInOut }); } function showCurrentDialog() { var scene = getCurrentScene(); if (!scene || !scene.dialogs || currentDialog >= scene.dialogs.length) { if (scene && scene.choices) { currentChoices = scene.choices; choiceSystem.showChoices(scene.choices); dialogSystem.hide(); } else { nextScene(); } return; } var dialog = scene.dialogs[currentDialog]; dialogSystem.showDialog(dialog.speaker, dialog.text); // Play aikoAudioLine1 when Aiko says the specific dialog about being responsible if (dialog.speaker === 'Aiko' && dialog.text === 'Satoshi-kun, necesitas ser más responsable con tus estudios.') { LK.getSound('aikoAudioLine1').play(); } // Play aikoAudioLine2 when Aiko says the tutoring dialog if (dialog.speaker === 'Aiko' && dialog.text === '...¿Yo? ¿tu tutora?') { LK.getSound('aikoAudioLine2').play(); } // Play aikoAudioLine3 when Aiko says the deal dialog if (dialog.speaker === 'Aiko' && dialog.text === 'Está bien. Pero no quiero distracciones. Si no cumplís, se acaba el trato.') { LK.getSound('aikoAudioLine3').play(); } // Play aikoAudioLine4 when Aiko says the evaluation dialog if (dialog.speaker === 'Aiko' && dialog.text === 'Antes de seguir con estas sesiones, quiero comprobar cuánto sabés.') { LK.getSound('aikoAudioLine4').play(); } // Play aikoAudioLine5 when Aiko says the specific dialog about all correct answers if (dialog.speaker === 'Aiko' && dialog.text === '...¿Todas correctas? Hmm... No está mal, para alguien como vos.') { LK.getSound('aikoAudioLine5').play(); } // Handle background changes within dialog if (dialog.backgroundChange) { changeBackground(dialog.backgroundChange); } // Before route selection: hide characterSprite, show full Satoshi // After route selection: show characterSprite for Satoshi, hide for others if (!selectedRoute) { // Before route selection - always hide characterSprite character.hide(); } else { // After route selection - show characterSprite for Satoshi, hide for others if (dialog.speaker === 'Satoshi') { // Check if this is the specific promise dialog in Aiko route var isMotivatedMoment = selectedRoute === 'aiko' && currentScene === 4 && currentDialog === 2 && dialog.text === '¡Lo prometo! Seré el alumno más aplicado que hayas visto.'; character.show(false, isMotivatedMoment); } else { character.hide(); } } choiceSystem.clearChoices(); } function getCurrentScene() { if (selectedRoute && routeScenes[selectedRoute]) { var routeIndex = currentScene - storyScenes.length; if (routeIndex >= 0 && routeIndex < routeScenes[selectedRoute].length) { return routeScenes[selectedRoute][routeIndex]; } } if (currentScene < storyScenes.length) { return storyScenes[currentScene]; } return null; } function nextScene() { currentScene++; currentDialog = 0; currentChoices = []; // No auto-save - game resets on refresh var scene = getCurrentScene(); if (scene) { if (scene.background) { changeBackground(scene.background); } showCurrentDialog(); } else { showEnding(); } } function showEnding() { var maxPoints = 0; var winner = null; if (selectedRoute) { maxPoints = relationshipPoints[selectedRoute]; winner = selectedRoute; } var endingText = ''; if (maxPoints >= 3) { endingText = '¡Felicidades! Has encontrado el amor verdadero con ' + (winner === 'aiko' ? 'Aiko' : winner === 'yui' ? 'Yui' : 'Hikari') + '!'; LK.showYouWin(); } else { endingText = 'Aunque no encontraste el amor esta vez, aprendiste mucho sobre ti mismo.'; dialogSystem.showDialog('Narrador', endingText); } } game.nextDialog = function () { // If we're in romantic scene, continue with romantic dialog if (isInRomanticScene && romanticScene) { romanticScene.showRomanticDialog(); return; } var scene = getCurrentScene(); var dialog = scene && scene.dialogs ? scene.dialogs[currentDialog] : null; if (dialog && dialog.action === 'startMathEval' && !isInMathEvaluation) { game.startMathEvaluation(); return; } currentDialog++; // No auto-save for dialog progress showCurrentDialog(); }; game.startMathEvaluation = function () { isInMathEvaluation = true; dialogSystem.hide(); character.hide(); if (currentBackground) { currentBackground.destroy(); } // Play evaluation song during math test LK.playMusic('evaluationSong'); mathEvaluation = game.addChild(new MathEvaluation()); }; game.startMathEvaluationFailure = function () { isInMathEvaluation = false; if (mathEvaluation) { mathEvaluation.destroy(); mathEvaluation = null; } if (currentBackground) { currentBackground.destroy(); } // Stop music when player fails evaluation LK.stopMusic(); // Change to cold, grey classroom changeBackground('aula'); character.hide(); // Show Aiko's disappointed reaction with specific dialogs var failureDialogs = [{ speaker: 'Aiko', text: '...¿En serio?' }, { speaker: 'Aiko', text: 'Pensé que podrías con algo tan simple. Pero está claro que puse expectativas demasiado altas en vos.' }, { speaker: 'Aiko', text: 'Mejor andá a pedirle ayuda a tu mamá. Quizás con dibujos entiendas.' }, { speaker: 'GAME OVER', text: '¡Por eso eres virgen!' }]; var failureDialogIndex = 0; function showFailureDialog() { if (failureDialogIndex < failureDialogs.length) { var dialog = failureDialogs[failureDialogIndex]; dialogSystem.showDialog(dialog.speaker, dialog.text); failureDialogIndex++; if (dialog.speaker === 'GAME OVER') { LK.effects.flashScreen(0xff0000, 1000); // Play game over sound effect when narrator says the virgin line LK.getSound('gameOverEffect').play(); } } } // Override nextDialog temporarily for failure sequence var originalNextDialog = game.nextDialog; game.nextDialog = function () { showFailureDialog(); if (failureDialogIndex >= failureDialogs.length) { // Restore original nextDialog game.nextDialog = originalNextDialog; } }; showFailureDialog(); }; game.startRomanticScene = function () { isInMathEvaluation = false; isInRomanticScene = true; if (mathEvaluation) { mathEvaluation.destroy(); mathEvaluation = null; } if (currentBackground) { currentBackground.destroy(); } // Stop evaluation music and play romantic song when player passes evaluation LK.stopMusic(); LK.playMusic('romanticSong'); romanticScene = game.addChild(new RomanticScene()); romanticScene.showRomanticDialog(); }; game.makeChoice = function (choice) { // Handle romantic scene choices if (isInRomanticScene && choice.type) { choiceSystem.clearChoices(); if (choice.type === 'romantic') { // Resume romantic music for positive choice LK.stopMusic(); LK.playMusic('romanticSong'); // Show positive romantic outcome if (romanticScene) { romanticScene.destroy(); } // Change background to AikoPoseOjou for this specific dialog if (currentBackground) { currentBackground.destroy(); } currentBackground = game.addChild(LK.getAsset('AikoPoseOjou', { x: 0, y: 0 })); // Send background to back but after dialogBoxWallpaper game.setChildIndex(currentBackground, 1); relationshipPoints.aiko += 2; dialogSystem.showDialog('Aiko', '¿Más...? Sos más valiente de lo que pensaba. Pero antes de seguir... prométeme que vas a seguir estudiando conmigo.'); // Play aikoAudioLine10 when Aiko says the romantic choice dialog LK.getSound('aikoAudioLine10').play(); // Override nextDialog to handle Yui's route transition var originalNextDialog = game.nextDialog; game.nextDialog = function () { // Restore original nextDialog game.nextDialog = originalNextDialog; // Start Yui's hidden route game.startYuiHiddenRoute(); }; } else if (choice.type === 'reject') { // Stop music completely for rejection to emphasize gameOverEffect LK.stopMusic(); // Show game over if (romanticScene) { romanticScene.destroy(); } LK.effects.flashScreen(0xff0000, 1000); dialogSystem.showDialog('GAME OVER', '¡Por eso eres virgen!'); // Play game over sound effect with clear musical space LK.getSound('gameOverEffect').play(); } return; } // Check if this is the first scene crossroads choice and restore music if (currentScene === 0 && (choice.text === 'Contarle todo a mamá' || choice.text === 'Mantenerlo en secreto')) { // Resume the beginning song after making the crossroads choice LK.stopMusic(); LK.playMusic('theBeginningSong'); } // Check if this is the school scene route choice and play school song if (currentScene === 2 && (choice.text === 'Acercarme a Aiko' || choice.text === 'Hablar con Yui' || choice.text === 'Seguir a Hikari')) { // Play school song after making route choice LK.stopMusic(); LK.playMusic('theSchoolSong'); } // Check if this is Aiko tutoring choice and resume school song if (currentScene === 3 && (choice.text === 'Pedirle que sea mi tutora' || choice.text === 'Sugerir estudiar juntos como amigos')) { // Resume the school song after making the tutoring choice LK.stopMusic(); LK.playMusic('theSchoolSong'); } // Reset character sprite to normal state if (selectedRoute && character.visible) { character.show(false); } if (choice.effects) { for (var key in choice.effects) { relationshipPoints[key] += choice.effects[key]; } } // Special handling for Aiko route choices if (selectedRoute === 'aiko' && currentScene === 3) { if (choice.text === 'Pedirle que sea mi tutora') { relationshipPoints.academic += 1; } else if (choice.text === 'Sugerir estudiar juntos como amigos') { // Trigger immediate game over dialogSystem.hide(); choiceSystem.clearChoices(); LK.effects.flashScreen(0xff0000, 1000); dialogSystem.showDialog('GAME OVER', '¡Por eso eres virgen!'); return; } } if (choice.route) { selectedRoute = choice.route; } choiceSystem.clearChoices(); currentChoices = []; nextScene(); }; game.showChoices = function () { if (currentChoices.length > 0) { choiceSystem.showChoices(currentChoices); dialogSystem.hide(); } }; game.showTitleScreen = function () { // Hide welcome screen welcomeScreen.visible = false; // Play title screen music without looping when showing title screen LK.playMusic('titleScreenSong', { loop: false }); // Show and initialize title screen titleScreen.visible = true; titleScreen.initAnimations(); }; game.startMainGame = function () { if (gameStarted) return; gameStarted = true; // Stop title screen music LK.stopMusic(); // Start the beginning song for Satoshi's room scene LK.playMusic('theBeginningSong'); // Hide title screen titleScreen.visible = false; // Show game elements dialogSystem.visible = true; choiceSystem.visible = true; character.visible = true; // Restart button text removed - no color changes needed // Initialize game changeBackground('habitacion'); showCurrentDialog(); }; // Don't auto-start the game - wait for title screen // Restart button in top-right corner var restartButton = LK.gui.topRight.addChild(LK.getAsset('restartButton', { anchorX: 1, anchorY: 0, x: -50, y: 20, scaleX: 0.6, scaleY: 0.6 })); // Restart button text removed - sprite is sufficient restartButton.down = function () { // Stop all music immediately for complete reset LK.stopMusic(); // Clear all saved data delete storage.currentScene; delete storage.currentDialog; delete storage.relationshipPoints; delete storage.selectedRoute; delete storage.playerName; // Reset game state variables currentScene = 0; currentDialog = 0; currentChoices = []; relationshipPoints = { aiko: 0, yui: 0, hikari: 0, respect: 0, peace: 0, academic: 0 }; selectedRoute = null; isInMathEvaluation = false; isInRomanticScene = false; gameStarted = false; // Reset the nextDialog function to original state game.nextDialog = function () { // If we're in romantic scene, continue with romantic dialog if (isInRomanticScene && romanticScene) { romanticScene.showRomanticDialog(); return; } var scene = getCurrentScene(); var dialog = scene && scene.dialogs ? scene.dialogs[currentDialog] : null; if (dialog && dialog.action === 'startMathEval' && !isInMathEvaluation) { game.startMathEvaluation(); return; } currentDialog++; // No auto-save for dialog progress showCurrentDialog(); }; // Destroy any active special scenes and all screen elements if (mathEvaluation) { mathEvaluation.destroy(); mathEvaluation = null; } if (romanticScene) { romanticScene.destroy(); romanticScene = null; } if (currentBackground) { currentBackground.destroy(); currentBackground = null; } if (currentYuiBackground) { currentYuiBackground.destroy(); currentYuiBackground = null; } // Clear all UI elements and systems choiceSystem.clearChoices(); if (choiceSystem) { choiceSystem.destroy(); choiceSystem = null; } if (character) { character.destroy(); character = null; } if (dialogSystem) { dialogSystem.destroy(); dialogSystem = null; } // Destroy and clear all screen elements if (titleScreen) { titleScreen.destroy(); titleScreen = null; } if (welcomeScreen) { welcomeScreen.destroy(); welcomeScreen = null; } // Remove all children from game to clear the screen completely while (game.children.length > 0) { var child = game.children[0]; if (child && child.destroy) { child.destroy(); } else { game.removeChild(child); } } // Recreate dialogBoxWallpaper first (always at bottom) dialogBoxWallpaper = game.addChild(LK.getAsset('dialogBoxWallpaper', { x: 0, y: 2048, alpha: 1 })); game.setChildIndex(dialogBoxWallpaper, 0); // Recreate all systems from scratch dialogSystem = game.addChild(new DialogSystem()); choiceSystem = game.addChild(new ChoiceSystem()); character = game.addChild(new Character()); titleScreen = game.addChild(new TitleScreen()); welcomeScreen = game.addChild(new WelcomeScreen()); // Hide all game elements - start fresh at title screen dialogSystem.visible = false; choiceSystem.visible = false; character.visible = false; welcomeScreen.visible = false; // Show title screen and initialize it titleScreen.visible = true; titleScreen.initAnimations(); // Play title screen music for fresh start LK.playMusic('titleScreenSong'); }; // Yui's hidden route scenes var yuiHiddenRoute = [{ background: 'schoolcorridor', dialogs: [{ speaker: 'Narrador', text: 'En un rincón del pasillo, entre casilleros, una figura permanece inmóvil. Sus labios no se mueven. Pero su mirada... lo dice todo.' }] }, { background: 'schoolcorridor', dialogs: [{ speaker: 'Yui', text: '¿Así que ahora sonríes así por ella...?', isThought: true }] }, { background: 'schoolcorridor', dialogs: [{ speaker: 'Yui', text: 'Intenta quitármelo... y sufrirás las graves consecuencias.', isThought: true }] }, { background: 'schoolcorridor', dialogs: [{ speaker: 'Yui', text: 'Si yo no puedo tenerlo...', isThought: true }] }, { background: 'schoolcorridor', dialogs: [{ speaker: 'Yui', text: '...nadie más lo tendrá.', isThought: true }] }, { background: 'schoolcorridor', dialogs: [{ speaker: 'Yui', text: 'Satoshi, te conocí cuando éramos niños...', isThought: true }] }, { background: 'schoolcorridor', dialogs: [{ speaker: 'Yui', text: 'Jugábamos a las carreras, a las escondidas... Y a los novios...', isThought: true }] }, { background: 'schoolcorridor', dialogs: [{ speaker: 'Yui', text: 'Pero jamás pensé... que lo olvidarías.', isThought: true }] }, { background: 'schoolcorridor', dialogs: [{ speaker: 'Narrador', text: 'El amor de la infancia... no siempre se desvanece. A veces... se pudre.' }] }]; var currentYuiBackground = null; var yuiBackgroundFilters = [{ brightness: 1.0, contrast: 1.0, saturation: 1.0, tint: 0xffffff }, // Warm afternoon light { brightness: 0.8, contrast: 1.2, saturation: 0.9, tint: 0xf0f0f0 }, // Longer shadows { brightness: 0.7, contrast: 1.4, saturation: 0.8, tint: 0xff9999 }, // Reddish tint { brightness: 0.6, contrast: 1.1, saturation: 0.4, tint: 0xcccccc }, // Desaturated { brightness: 0.4, contrast: 1.6, saturation: 0.2, tint: 0x999999 }, // Dark and cold { brightness: 0.5, contrast: 1.3, saturation: 0.6, tint: 0xddaa88 }, // Sepia tones { brightness: 0.3, contrast: 1.8, saturation: 0.3, tint: 0x888888 }, // Unstable lighting { brightness: 0.2, contrast: 2.0, saturation: 0.1, tint: 0x666666 } // Almost black and white ]; function changeYuiBackground(backgroundType) { // If there's no current Yui background, just create the new one immediately if (!currentYuiBackground) { currentYuiBackground = game.addChild(LK.getAsset(backgroundType, { x: 0, y: 0 })); // Send background to back but after dialogBoxWallpaper game.setChildIndex(currentYuiBackground, 1); // Store background type for future comparison currentYuiBackground.backgroundType = backgroundType; return; } // Check if the new background is the same as the current one if (currentYuiBackground.backgroundType === backgroundType) { // Same background - no transition needed return; } // Create new background with alpha 0 (invisible) var newYuiBackground = game.addChild(LK.getAsset(backgroundType, { x: 0, y: 0, alpha: 0 })); // Send new background to back but after dialogBoxWallpaper game.setChildIndex(newYuiBackground, 1); // Store background type for future comparison newYuiBackground.backgroundType = backgroundType; // Store reference to old background for destruction var oldYuiBackground = currentYuiBackground; currentYuiBackground = newYuiBackground; // Fade out old background and fade in new background simultaneously tween(oldYuiBackground, { alpha: 0 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { oldYuiBackground.destroy(); } }); tween(newYuiBackground, { alpha: 1 }, { duration: 800, easing: tween.easeInOut }); } game.startYuiHiddenRoute = function () { // Stop romantic music LK.stopMusic(); // Clear any existing scene if (romanticScene) { romanticScene.destroy(); romanticScene = null; } // Store reference to current background before creating new one var oldBackground = null; if (currentBackground) { oldBackground = currentBackground; currentBackground = null; } isInRomanticScene = false; character.hide(); // Create theLocker background with fade transition var newLockerBackground = game.addChild(LK.getAsset('theLocker', { x: 0, y: 0, alpha: 0 })); // Send background to back but after dialogBoxWallpaper game.setChildIndex(newLockerBackground, 1); // Update current background reference currentYuiBackground = newLockerBackground; // Fade out old background and fade in new background simultaneously if (oldBackground && oldBackground.destroy) { tween(oldBackground, { alpha: 0 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { oldBackground.destroy(); } }); } tween(newLockerBackground, { alpha: 1 }, { duration: 800, easing: tween.easeInOut }); // Start Yui's route var yuiSceneIndex = 0; function showYuiScene() { if (yuiSceneIndex >= yuiHiddenRoute.length) { // End of Yui's route - show final message dialogSystem.showDialog('Narrador', 'Inicio de la ruta de Yui desbloqueado'); return; } var scene = yuiHiddenRoute[yuiSceneIndex]; var dialog = scene.dialogs[0]; dialogSystem.showDialog(dialog.speaker, dialog.text); // Play YandereSong when Narrator says the opening line for Yui's hidden route if (dialog.speaker === 'Narrador' && dialog.text === 'En un rincón del pasillo, entre casilleros, una figura permanece inmóvil. Sus labios no se mueven. Pero su mirada... lo dice todo.') { LK.playMusic('yandereSong'); } // Play yuiAudioLine1 when Yui says her first thought dialog if (dialog.speaker === 'Yui' && dialog.text === '¿Así que ahora sonríes así por ella...?') { LK.getSound('yuiAudioLine1').play(); // Change background to theLockerOfYui for this specific scene changeYuiBackground('theLockerOfYui'); } // Play yuiAudioLine2 when Yui says her threatening thought dialog if (dialog.speaker === 'Yui' && dialog.text === 'Intenta quitármelo... y sufrirás las graves consecuencias.') { LK.getSound('yuiAudioLine2').play(); // Change background to threatofYui for this specific scene changeYuiBackground('threatofYui'); } // Play yuiAudioLine3 when Yui says her fourth thought dialog if (dialog.speaker === 'Yui' && dialog.text === 'Si yo no puedo tenerlo...') { LK.getSound('yuiAudioLine3').play(); // Change background to threatofYui for this specific scene changeYuiBackground('threatofYui'); } // Play yuiAudioLine4 when Yui says her fifth thought dialog if (dialog.speaker === 'Yui' && dialog.text === '...nadie más lo tendrá.') { LK.getSound('yuiAudioLine4').play(); // Change background to crazyInTheLocker for this specific scene changeYuiBackground('crazyInTheLocker'); } // Play yuiAudioLine5 when Yui says her sixth thought dialog if (dialog.speaker === 'Yui' && dialog.text === 'Satoshi, te conocí cuando éramos niños...') { LK.getSound('yuiAudioLine5').play(); // Change background to theLoveOfChildren for this specific scene changeYuiBackground('theLoveOfChildren'); } // Play yuiAudioLine6 when Yui says her seventh thought dialog if (dialog.speaker === 'Yui' && dialog.text === 'Jugábamos a las carreras, a las escondidas... Y a los novios...') { LK.getSound('yuiAudioLine6').play(); // Change background to theLoveOfChildren for this specific scene changeYuiBackground('theLoveOfChildren'); } // Play yuiAudioLine7 when Yui says her eighth thought dialog if (dialog.speaker === 'Yui' && dialog.text === 'Pero jamás pensé... que lo olvidarías.') { LK.getSound('yuiAudioLine7').play(); // Change background to cryingInTheLocker for this specific scene changeYuiBackground('cryingInTheLocker'); } // Change background to cryingInTheLocker when Narrator says the final line about childhood love rotting if (dialog.speaker === 'Narrador' && dialog.text === 'El amor de la infancia... no siempre se desvanece. A veces... se pudre.') { changeYuiBackground('cryingInTheLocker'); } yuiSceneIndex++; } // Override nextDialog for Yui's route var originalNextDialog = game.nextDialog; game.nextDialog = function () { // Check if we just showed the final Narrator line about childhood love rotting var currentScene = yuiHiddenRoute[yuiSceneIndex - 1]; if (currentScene && currentScene.dialogs[0].speaker === 'Narrador' && currentScene.dialogs[0].text === 'El amor de la infancia... no siempre se desvanece. A veces... se pudre.') { // Show alpha ending right after this line game.showAlphaEnding(); return; } // Continue with next scene if not the final narrator line showYuiScene(); // Restore original nextDialog after Yui's route ends if (yuiSceneIndex >= yuiHiddenRoute.length) { game.nextDialog = originalNextDialog; } }; // Start Yui's route showYuiScene(); }; game.showAlphaEnding = function () { // Stop all music and play youWinSong once LK.stopMusic(); LK.playMusic('youWinSong', { loop: false }); // Store current elements for restoration later var storedYuiBackground = currentYuiBackground; var storedBackground = currentBackground; // Hide current elements but don't destroy them yet if (currentYuiBackground) { currentYuiBackground.visible = false; } if (currentBackground) { currentBackground.visible = false; } dialogSystem.hide(); choiceSystem.clearChoices(); character.hide(); // Create white background for letter var alphaBackground = game.addChild(LK.getAsset('mathEvaluationBackground', { x: 0, y: 0, tint: 0xffffff })); // Send background to back but after dialogBoxWallpaper game.setChildIndex(alphaBackground, 1); // Get player name from storage or use default var playerName = storage.playerName || 'Jugador'; // Title text var titleText = new Text2('Estimad@ Jugador@ ' + playerName, { size: 120, fill: 0x000000, wordWrap: true, wordWrapWidth: 1800 }); titleText.anchor.set(0.5, 0); titleText.x = 1024; titleText.y = 400; titleText.alpha = 0; game.addChild(titleText); // Body text lines var bodyLines = ['Fin del Alfa', '', 'No puedo seguir sin apoyo económico ni créditos Ava.', '', '¿Quieres ayudar?', '▸ Hazlo viral', '▸ Llévalo al Top 1 en Upit', '▸ Haz que gane un torneo', '▸ O que el creador de Upit me dé más créditos Ava', '', '✅ Cualquiera de esas cosas puede revivir el proyecto.', '', 'Sígueme en YouTube: @merak1388']; var bodyText = new Text2(bodyLines.join('\n'), { size: 80, fill: 0x000000, wordWrap: true, wordWrapWidth: 1600 }); bodyText.anchor.set(0.5, 0); bodyText.x = 1024; bodyText.y = 700; bodyText.alpha = 0; game.addChild(bodyText); // Create continue button that appears after text is shown var continueButton = game.addChild(LK.getAsset('nextButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 2200, alpha: 0, visible: false })); var continueText = new Text2('Continuar', { size: 60, fill: 0x000000 }); continueText.anchor.set(0.5, 0.5); continueText.x = continueButton.x; continueText.y = continueButton.y; continueText.alpha = 0; continueText.visible = false; game.addChild(continueText); // Continue button handler continueButton.down = function () { // Fade out alpha ending elements tween(alphaBackground, { alpha: 0 }, { duration: 800, easing: tween.easeInOut }); tween(titleText, { alpha: 0 }, { duration: 800, easing: tween.easeInOut }); tween(bodyText, { alpha: 0 }, { duration: 800, easing: tween.easeInOut }); tween(continueButton, { alpha: 0 }, { duration: 800, easing: tween.easeInOut }); tween(continueText, { alpha: 0 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { // Clean up alpha ending elements alphaBackground.destroy(); titleText.destroy(); bodyText.destroy(); continueButton.destroy(); continueText.destroy(); // Restore game elements if (storedYuiBackground) { storedYuiBackground.visible = true; currentYuiBackground = storedYuiBackground; } if (storedBackground) { storedBackground.visible = true; currentBackground = storedBackground; } dialogSystem.visible = true; // Resume Yui's route or continue game yuiSceneIndex++; // Move to next scene if (yuiSceneIndex < yuiHiddenRoute.length) { // Continue with rest of Yui's route var nextScene = yuiHiddenRoute[yuiSceneIndex]; var nextDialog = nextScene.dialogs[0]; dialogSystem.showDialog(nextDialog.speaker, nextDialog.text); } else { // End Yui's route dialogSystem.showDialog('Narrador', 'Inicio de la ruta de Yui desbloqueado'); } } }); }; // Fade in white background tween(alphaBackground, { alpha: 1 }, { duration: 1500, easing: tween.easeInOut, onFinish: function onFinish() { // Show title first tween(titleText, { alpha: 1 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { // Show body text after title LK.setTimeout(function () { tween(bodyText, { alpha: 1 }, { duration: 1500, easing: tween.easeOut, onFinish: function onFinish() { // Show continue button after all text is visible LK.setTimeout(function () { continueButton.visible = true; continueText.visible = true; tween(continueButton, { alpha: 1 }, { duration: 500, easing: tween.easeOut }); tween(continueText, { alpha: 1 }, { duration: 500, easing: tween.easeOut }); }, 1000); } }); }, 500); } }); } }); }; // Add game state to global for debugging game.currentChoices = currentChoices; // Admin skip button for instant stage bypass var adminSkipButton = LK.gui.topLeft.addChild(LK.getAsset('titleButton', { anchorX: 0, anchorY: 0, x: 120, // Avoid top-left 100x100 px reserved area y: 20, scaleX: 0.4, scaleY: 0.4, alpha: 0.3 // Semi-transparent to indicate admin function })); var skipText = new Text2('SKIP', { size: 60, fill: 0xffffff }); skipText.anchor.set(0.5, 0.5); skipText.x = adminSkipButton.x + adminSkipButton.width * 0.2; // Center on button skipText.y = adminSkipButton.y + adminSkipButton.height * 0.2; LK.gui.topLeft.addChild(skipText); adminSkipButton.down = function () { // Skip current stage based on game state if (!gameStarted) { // Skip title screen game.startMainGame(); } else if (isInMathEvaluation) { // Skip math evaluation with success game.startRomanticScene(); } else if (isInRomanticScene) { // Skip to Yui's hidden route game.startYuiHiddenRoute(); } else if (currentChoices.length > 0) { // Auto-select first choice to continue if (currentChoices[0]) { game.makeChoice(currentChoices[0]); } } else { // Skip current dialog/scene if (currentScene < storyScenes.length || selectedRoute && routeScenes[selectedRoute] && currentScene - storyScenes.length < routeScenes[selectedRoute].length) { // Skip to end of current scene var scene = getCurrentScene(); if (scene && scene.dialogs) { currentDialog = scene.dialogs.length - 1; } game.nextDialog(); } else { // Skip to ending showEnding(); } } };
===================================================================
--- original.js
+++ change.js
@@ -1999,10 +1999,10 @@
/****
* Game Code
****/
-// Game state
// Fondos
+// Game state
var currentScene = 0;
var currentDialog = 0;
var currentChoices = [];
var relationshipPoints = {
@@ -2322,14 +2322,9 @@
}
var endingText = '';
if (maxPoints >= 3) {
endingText = '¡Felicidades! Has encontrado el amor verdadero con ' + (winner === 'aiko' ? 'Aiko' : winner === 'yui' ? 'Yui' : 'Hikari') + '!';
- // Check if this is Yui route completion - show alpha ending instead of You Win
- if (winner === 'yui') {
- game.showAlphaEnding();
- } else {
- LK.showYouWin();
- }
+ LK.showYouWin();
} else {
endingText = 'Aunque no encontraste el amor esta vez, aprendiste mucho sobre ti mismo.';
dialogSystem.showDialog('Narrador', endingText);
}
@@ -2962,25 +2957,17 @@
}
// Override nextDialog for Yui's route
var originalNextDialog = game.nextDialog;
game.nextDialog = function () {
- // Check if we just finished the final Narrator line about childhood love rotting
- if (yuiSceneIndex > 0) {
- var previousScene = yuiHiddenRoute[yuiSceneIndex - 1];
- if (previousScene && previousScene.dialogs[0].speaker === 'Narrador' && previousScene.dialogs[0].text === 'El amor de la infancia... no siempre se desvanece. A veces... se pudre.') {
- // Show alpha ending instead of math evaluation
- game.showAlphaEnding();
- return;
- }
- }
- // Continue with Yui scenes if not at the end
- if (yuiSceneIndex < yuiHiddenRoute.length) {
- showYuiScene();
- } else {
- // End of Yui's route - show alpha ending directly
+ // Check if we just showed the final Narrator line about childhood love rotting
+ var currentScene = yuiHiddenRoute[yuiSceneIndex - 1];
+ if (currentScene && currentScene.dialogs[0].speaker === 'Narrador' && currentScene.dialogs[0].text === 'El amor de la infancia... no siempre se desvanece. A veces... se pudre.') {
+ // Show alpha ending right after this line
game.showAlphaEnding();
return;
}
+ // Continue with next scene if not the final narrator line
+ showYuiScene();
// Restore original nextDialog after Yui's route ends
if (yuiSceneIndex >= yuiHiddenRoute.length) {
game.nextDialog = originalNextDialog;
}
@@ -2993,16 +2980,17 @@
LK.stopMusic();
LK.playMusic('youWinSong', {
loop: false
});
- // Clear all current elements
+ // Store current elements for restoration later
+ var storedYuiBackground = currentYuiBackground;
+ var storedBackground = currentBackground;
+ // Hide current elements but don't destroy them yet
if (currentYuiBackground) {
- currentYuiBackground.destroy();
- currentYuiBackground = null;
+ currentYuiBackground.visible = false;
}
if (currentBackground) {
- currentBackground.destroy();
- currentBackground = null;
+ currentBackground.visible = false;
}
dialogSystem.hide();
choiceSystem.clearChoices();
character.hide();
@@ -3040,8 +3028,90 @@
bodyText.x = 1024;
bodyText.y = 700;
bodyText.alpha = 0;
game.addChild(bodyText);
+ // Create continue button that appears after text is shown
+ var continueButton = game.addChild(LK.getAsset('nextButton', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 1024,
+ y: 2200,
+ alpha: 0,
+ visible: false
+ }));
+ var continueText = new Text2('Continuar', {
+ size: 60,
+ fill: 0x000000
+ });
+ continueText.anchor.set(0.5, 0.5);
+ continueText.x = continueButton.x;
+ continueText.y = continueButton.y;
+ continueText.alpha = 0;
+ continueText.visible = false;
+ game.addChild(continueText);
+ // Continue button handler
+ continueButton.down = function () {
+ // Fade out alpha ending elements
+ tween(alphaBackground, {
+ alpha: 0
+ }, {
+ duration: 800,
+ easing: tween.easeInOut
+ });
+ tween(titleText, {
+ alpha: 0
+ }, {
+ duration: 800,
+ easing: tween.easeInOut
+ });
+ tween(bodyText, {
+ alpha: 0
+ }, {
+ duration: 800,
+ easing: tween.easeInOut
+ });
+ tween(continueButton, {
+ alpha: 0
+ }, {
+ duration: 800,
+ easing: tween.easeInOut
+ });
+ tween(continueText, {
+ alpha: 0
+ }, {
+ duration: 800,
+ easing: tween.easeInOut,
+ onFinish: function onFinish() {
+ // Clean up alpha ending elements
+ alphaBackground.destroy();
+ titleText.destroy();
+ bodyText.destroy();
+ continueButton.destroy();
+ continueText.destroy();
+ // Restore game elements
+ if (storedYuiBackground) {
+ storedYuiBackground.visible = true;
+ currentYuiBackground = storedYuiBackground;
+ }
+ if (storedBackground) {
+ storedBackground.visible = true;
+ currentBackground = storedBackground;
+ }
+ dialogSystem.visible = true;
+ // Resume Yui's route or continue game
+ yuiSceneIndex++; // Move to next scene
+ if (yuiSceneIndex < yuiHiddenRoute.length) {
+ // Continue with rest of Yui's route
+ var nextScene = yuiHiddenRoute[yuiSceneIndex];
+ var nextDialog = nextScene.dialogs[0];
+ dialogSystem.showDialog(nextDialog.speaker, nextDialog.text);
+ } else {
+ // End Yui's route
+ dialogSystem.showDialog('Narrador', 'Inicio de la ruta de Yui desbloqueado');
+ }
+ }
+ });
+ };
// Fade in white background
tween(alphaBackground, {
alpha: 1
}, {
@@ -3060,9 +3130,28 @@
tween(bodyText, {
alpha: 1
}, {
duration: 1500,
- easing: tween.easeOut
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ // Show continue button after all text is visible
+ LK.setTimeout(function () {
+ continueButton.visible = true;
+ continueText.visible = true;
+ tween(continueButton, {
+ alpha: 1
+ }, {
+ duration: 500,
+ easing: tween.easeOut
+ });
+ tween(continueText, {
+ alpha: 1
+ }, {
+ duration: 500,
+ easing: tween.easeOut
+ });
+ }, 1000);
+ }
});
}, 500);
}
});
A cute 15-year-old red-haired boy with intense red eyes, wearing a traditional Japanese school uniform (gakuran). He's running down the street with a serious and confident expression. Despite his determined look, his appearance remains sweet and endearing. His gaze is focused straight ahead, with the wind gently lifting his hair and school jacket. The scene is illustrated in Pixel Art style.. In-Game asset. 2d. High contrast. No shadows
A cute 15-year-old red-haired boy with red eyes, wearing a traditional Japanese school uniform (gakuran). He has a big closed-mouth smile, shining eyes, and clenched fists held forward, as if encouraging himself. Behind him, other Japanese students can be seen. The scene is illustrated in Pixel Art style.. In-Game asset. 2d. High contrast. No shadows
A cute anime-style girl in pixel art, with an emo aesthetic and striking purple eyes. She wears a classic Japanese school uniform (sailor fuku) and is often shown with a slightly grumpy expression, reflecting a bit of a tsundere personality. She stands confidently with her hands on her hips and a slight tilt to her posture. Behind her is a typical Japanese classroom, enhancing the school-themed atmosphere.. In-Game asset. 2d. High contrast. No shadows
She’s a cute anime girl with a free-spirited and rebellious vibe. Her hair is pink, and she’s wearing a traditional Japanese school uniform (sailor fuku). She sports dark sunglasses and holds a skateboard in one hand while pointing with the other. Her face lights up with a big smile and mischievous pink eyes that match her hair. In the background, there's a Japanese classroom, and the entire artwork is done in Pixel Art style.. In-Game asset. 2d. High contrast. No shadows
Stella is a sweet and very kawaii 15-year-old anime girl with short, soft blue-gray hair (HEX: #b0b9d8) and black eyes. She wears a traditional Japanese school uniform called a sailor fuku. Stella is extremely shy—she blushes easily, avoids eye contact, and often covers herself when she feels nervous. In this Pixel Art scene, she’s gently touching the tips of her index fingers together, a classic gesture of shyness seen in anime. Behind her is the courtyard of a Japanese middle school, completing the charming school setting.. In-Game asset. 2d. High contrast. No shadows
A kawaii anime boy with intense red eyes, each containing shining stars. He raises his fist forward with determination, wearing a wide, open smile full of enthusiasm. Sparkles and glimmers float around him, symbolizing hope. The entire scene is rendered in Pixel Art style.
A kawaii anime boy with red eyes and a serious expression stands with his eyes closed, resting a hand under his chin in a thoughtful pose. He’s wearing a traditional Japanese school uniform called a gakuran. Suddenly, a lightbulb appears above his head—the classic symbol of a brilliant idea. He opens his eyes with determination, a confident smile forming on his face. It's Pixel Art.
Remove the sparkles from the background.
Pure white. 2d
A cute anime-style girl in pixel art, with an emo aesthetic, striking purple eyes, and a classic Japanese school uniform (sailor fuku), is studying with furrowed brows and a confident smile. She sits next to a shy red-haired boy with red eyes, also in pixel art style. Their desks are pushed together, and on the boy’s desk lies an open notebook, which he nervously stares at while holding a graphite pencil. The girl looks at him with a mix of sternness and confidence, convinced he won’t pass the exam. The background depicts a typical Japanese classroom.
A cute anime-style girl rendered in pixel art, with an emo aesthetic and striking purple eyes, is wearing a high school cheerleader uniform and holding pom-poms in both hands. With her arms and legs extended in a dynamic pose, she winks playfully while cheering. The background is an American football field.
A cute anime-style girl depicted in pixel art, with an emo aesthetic and striking purple eyes. She's wearing a classic Japanese school uniform (sailor fuku). She has a shy expression, with blushing cheeks and an averted gaze. Her left hand is playing with her hair, while her right hand rests on her chest. In the background, there's a typical anime-style classroom.
In pixel art style, a cute anime-style girl with an emo aesthetic, striking purple eyes, and a Japanese school uniform (sailor fuku) suddenly pulls the hand of a shy red-haired boy with red eyes, who is wearing a gakuran and sitting in front of a rectangular desk. She smiles brightly with her eyes closed as she yanks him toward her, pulling him out of his seat. The boy looks confused and nervous, flustered by the sudden physical contact. In the background, a typical Japanese classroom can be seen.
The camera focuses only on their hands. The girl, wearing a traditional Japanese sailor fuku uniform, firmly grabs the hand of the boy, who is dressed in a classic gakuran. She pulls him forward with energy and excitement. His hand follows with slight tension, expressing surprise. Nothing else is shown—just the gesture: a meaningful connection captured in the simple act of their hands intertwined. Behind them stretches a Japanese school hallway, all rendered in a charming Pixel Art style.
A cute anime-style girl with an emo aesthetic, striking purple eyes, and dressed in a traditional Japanese school uniform (sailor fuku), suddenly gives an unexpected kiss on the lips to a sweet red-haired boy with deep crimson eyes, wearing a classic gakuran school uniform. As she kisses him, her cheeks are deeply flushed, while he, also blushing, wears a look of shock and disbelief — not only was the kiss completely unprompted, but it’s also the very first time anyone has ever kissed him. Behind them stretches a Japanese school hallway, all rendered in a charming Pixel Art style.
A charming anime-style girl rendered in delightful Pixel Art, featuring an emo aesthetic, striking purple eyes, and a classic Japanese school uniform (sailor fuku). She confidently strikes the iconic “Ojou-sama pose”: Her left hand is elegantly lifted near her face, fingers gracefully splayed like a fan, perfectly framing her smug expression. Her face bears a tilted, self-assured smile, the kind that practically echoes a soft, aristocratic “Ohoho~” laugh. One eyebrow arches subtly, radiating playful confidence and a touch of superiority. Her right hand rests casually near her waist, loosely clenched into a relaxed fist — an anchor for her graceful yet dominant posture. Behind her stretches the polished hallway of a Japanese school, complete with sliding doors and sunlit windows, completing the scene with a nostalgic, everyday charm — all captured in the cozy, detailed charm of Pixel Art.
A cute gray chibi-style anime kitten, dressed in an astronaut suit and drifting through the universe, rendered in Pixel Art.
A cute gray kitten, drawn in an adorable chibi anime style and wearing an astronaut suit, floats in outer space with its little paws outstretched as if reaching out for a hug. It meows sweetly, and the entire scene is illustrated in charming Pixel Art style.
A cute chibi-style anime kitten, dressed in an astronaut suit and drifting through the universe, rendered in Pixel Art.
White star of the universe in Pixel Art style
Planet Earth of the universe in Pixel Art style
Create a title screen logo with the following text: "Corazón de Estudiante - Novela Visual" Behind the text, the Andromeda Galaxy (M31) stretches across the background, creating a dreamy, cosmic atmosphere that evokes mystery and romance.
A cute kitten, illustrated in an adorable chibi anime style and wearing an astronaut suit, is playfully tangled in a ball of yarn, floating through space with overwhelming joy. Its eyes are shut tight in pure happiness, and its movements are full of energetic delight.
Three-quarter view pixel art jetpack
Transparent, colorless glass button that says "Empezar" (Spanish for "Start"), featuring an adventure video game font and Pixel Art style.
Advertencia que dice: "Sin usar"
A realistic yellow star from the universe, in pixel art style.
Pure white
A cute, red-haired anime boy, 15 years old, with red eyes. He's in pajamas, looking sleepy, rubbing one eye with his hand. He's in his otaku-style bedroom. The scene is illustrated in Pixel Art style.
Blue button with two yellow chevrons in a row, pixel art style.
A green circular button featuring a fuchsia-colored refresh icon, designed in Pixel Art style.
Stella is a 15-year-old anime girl—sweet and incredibly kawaii—with short, soft hair in a bluish-gray tone (HEX: #b0b9d8) and deep black eyes. She wears a traditional Japanese school uniform, the classic sailor-style fuku. In her right hand, she holds a butcher knife. Her expression is serious, and her eyes, now glowing with an intense yandere red, reflect jealousy and obsession. Dark under-eye circles emphasize her unsettling gaze. She is inside a high school locker in a Japanese school. Her right hand is slightly raised, gripping the knife, while her left hand gently touches the blade with her index finger, mimicking the motion of a clock hand—adding to the eerie atmosphere. To emphasize the feeling of being inside the locker, soft light shines through the ventilation slits, casting dramatic shadows across her face. The entire scene is rendered in detailed Pixel Art style, enhancing both the cuteness and the unsettling atmosphere of the character and setting.
Yui y un niño anime, ambos de 5 o 6 años, corren por un parque soleado en una carrera infantil. Yui tiene el cabello corto, suave, azul grisáceo (HEX: #b0b9d8) y ojos negros. Lleva un vestido lavanda claro con volantes blancos y zapatillas blancas con detalles rosa pastel. Sonríe tímidamente con mejillas sonrojadas mientras corre con pasos pequeños. El niño tiene cabello pelirrojo alborotado y ojos rojos intensos. Lleva una camiseta amarilla brillante con una estrella blanca, pantalones cortos azul claro y zapatillas rojas. Corre con energía, sonriendo ampliamente, mirando a Yui con entusiasmo. La escena está en Pixel Art, con césped verde, árboles y pétalos flotando. Ambos se ven felices, reflejando un momento puro de infancia.
Yui is a cute 15-year-old anime girl with big black eyes and short, soft blue-gray hair (HEX: #b0b9d8). She wears a traditional Japanese school uniform called a sailor fuku. In this Pixel Art scene, Yui looks clearly upset—she has very noticeable dark circles under her eyes, her eyebrows are tense, and her teeth are pressed together in frustration. Her arms are relaxed and down at her sides, showing no physical aggression, just quiet tension. She’s inside a school locker, looking out through a metal grate with a serious, focused expression. The entire scene is viewed from inside the locker, with soft light coming through the vents, casting gentle shadows across her face and creating a slightly tense but family-friendly atmosphere.
Pixel art. A red-haired 15-year-old anime-style boy with red eyes and a girl with purple eyes in Japanese school uniforms, both with large, expressive eyes and oversized irises to look super kawaii, are talking cheerfully while looking into each other’s eyes and gesturing with their hands. They are standing very close to a row of school lockers. In the center locker, a pair of glowing red eyes peer through the slats. The eyes belong to a hidden yandere—obsessed, crazy, and jealous—whose face and body remain completely obscured in the darkness inside the locker. The mood is lighthearted between the boy and girl, contrasting with the eerie presence watching them from the shadows.
Stella, a 15-year-old anime girl with short, soft hair in a bluish-gray tone (HEX: #b0b9d8), and large black eyes with oversized irises (super kawaii style), glowing with intense yandere red. She wears a traditional Japanese school uniform (classic sailor fuku). She is inside a Japanese school locker, with soft light coming through the ventilation slits, casting dramatic shadows on her face. Her eyebrows are furrowed in extreme anger, but she has a wide, creepy smile, like someone completely insane. Dark under-eye circles highlight her unhinged expression. Her right hand holds a butcher knife slightly raised, while her left hand gently touches the blade with her index finger, mimicking a clock hand motion. Visual style: highly detailed Pixel Art.
Yui is a cute 15-year-old anime girl with big black eyes and short, soft blue-gray hair (HEX: #b0b9d8). She wears a traditional Japanese school uniform called a sailor fuku. In this Pixel Art scene, Yui is clearly devastated—she’s hunched over in a slouched, defeated posture, crying intensely. Many visible tears stream down her cheeks, slipping past her fingers as she covers her face with both hands. Her entire body language screams sadness; it’s raw, heavy, and impossible to ignore. She’s inside a school locker, and although she’s looking outward through the metal grate, her face is mostly hidden behind her trembling hands. The entire scene is viewed from inside the locker, with soft light coming through the vents, casting delicate shadows across her curled-up figure and highlighting the depth of her heartbreak. The atmosphere is heavy, emotional, and quietly heartbreaking—yet still family-friendly in tone.
Diseña exclusivamente un cuadro de diálogo de color blanco de 2048 x 684 píxeles y esquinas en ángulo recto, evocando la estética romántica y juvenil de una novela ligera escolar, todo en estilo pixel art. No debe incluir ninguna otra funcionalidad. Detrás hay un fondo de color verde croma.
Ilustración en Pixel Art de un Name Box blanco, característico de una novela visual romántica, con detalles en colores pastel. El cuadro no contiene texto.
Ilustración en Pixel Art de un Name Box blanco, característico de una novela visual romántica, con detalles en colores pastel. El cuadro no contiene texto.
LoveTime
Music
Music1
Music
titleScreenSong
Music
theBeginningSong
Music
theCrossroadsSong
Music
theSchoolSong
Music
romanticSong
Music
youWinSong
Music
gameOverSong
Music
gameOverEffect
Sound effect
evaluationSong
Music
aikoAudioLine2
Sound effect
aikoAudioLine1
Sound effect
aikoAudioLine3
Sound effect
aikoAudioLine4
Sound effect
aikoAudioLine5
Sound effect
audioAikoLine6
Sound effect
aikoAudioLine7
Sound effect
aikoAudioLine8
Sound effect
Kissonthecheek
Sound effect
aikoAudioLine9
Sound effect
aikoAudioLine10
Sound effect
yuiAudioLine1
Sound effect
yuiAudioLine2
Sound effect
yuiAudioLine3
Sound effect
yuiAudioLine4
Sound effect
yuiAudioLine5
Sound effect
yuiAudioLine6
Sound effect
yuiAudioLine7
Sound effect
yandereSong
Music