feat: Puente Mayúscula-Minúscula + TTS SpeechSynthesis + E2E fixes
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
import type { Exercise, Stage, TopicCurriculum } from "./types"
|
||||
|
||||
const lecturaModules: Record<string, Stage> = {}
|
||||
const numerosModules: Record<string, Stage> = {}
|
||||
|
||||
async function loadStages(
|
||||
topic: string,
|
||||
modules: Record<string, Stage>,
|
||||
stageFiles: number[],
|
||||
) {
|
||||
for (const s of stageFiles) {
|
||||
try {
|
||||
const mod = await import(`./${topic}/etapa-${s}`)
|
||||
modules[s] = mod.default
|
||||
} catch {
|
||||
// stage not yet implemented
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let lecturaLoaded = false
|
||||
let numerosLoaded = false
|
||||
|
||||
export function getAllLecturaExercises(): Exercise[] {
|
||||
const stages = Object.values(getLecturaStages())
|
||||
return stages.flatMap((s) => s.exercises || [])
|
||||
}
|
||||
|
||||
export function getLecturaStages(): Record<string, Stage> {
|
||||
return lecturaModules as Record<string, Stage>
|
||||
}
|
||||
|
||||
export function getNumerosStages(): Record<string, Stage> {
|
||||
return numerosModules as Record<string, Stage>
|
||||
}
|
||||
|
||||
export async function initCurriculum() {
|
||||
if (!lecturaLoaded) {
|
||||
await loadStages("lectura", lecturaModules, [1, 2, 3, 4, 5, 6, 7, 8, 9])
|
||||
lecturaLoaded = true
|
||||
}
|
||||
if (!numerosLoaded) {
|
||||
await loadStages("numeros", numerosModules, [1, 2, 3, 4, 5, 6, 7, 8])
|
||||
numerosLoaded = true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
import type { Stage } from '../types'
|
||||
|
||||
const stage: Stage = {
|
||||
id: 1,
|
||||
name: 'Sensibilización al lenguaje escrito',
|
||||
description: 'Explorar sonidos del entorno, onomatopeyas, ritmo y conciencia de que el lenguaje se puede representar.',
|
||||
exercises: [
|
||||
// --- Sonidos del entorno ---
|
||||
{
|
||||
id: 'lec1-sonido-perro',
|
||||
stage: 1,
|
||||
skillCode: 'sensibilizacion-sonidos',
|
||||
type: 'sensibilizacion',
|
||||
prerequisites: [],
|
||||
content: {
|
||||
instruction: 'Escuchá este sonido. ¿Qué animal hace así?',
|
||||
audioText: '¡El perro hace guau guau!',
|
||||
options: [
|
||||
{ label: '🐱 Gato', correct: false },
|
||||
{ label: '🐕 Perro', correct: true },
|
||||
{ label: '🐄 Vaca', correct: false },
|
||||
],
|
||||
emoji: '🐕',
|
||||
},
|
||||
functionalContext: 'Identificar sonidos cotidianos del entorno.',
|
||||
},
|
||||
{
|
||||
id: 'lec1-sonido-gato',
|
||||
stage: 1,
|
||||
skillCode: 'sensibilizacion-sonidos',
|
||||
type: 'sensibilizacion',
|
||||
prerequisites: [],
|
||||
content: {
|
||||
instruction: '¿Quién hace miau?',
|
||||
audioText: 'El gato hace miau miau',
|
||||
options: [
|
||||
{ label: '🐕 Perro', correct: false },
|
||||
{ label: '🐄 Vaca', correct: false },
|
||||
{ label: '🐱 Gato', correct: true },
|
||||
],
|
||||
emoji: '🐱',
|
||||
},
|
||||
functionalContext: 'Asociar sonidos con animales.',
|
||||
},
|
||||
{
|
||||
id: 'lec1-sonido-vaca',
|
||||
stage: 1,
|
||||
skillCode: 'sensibilizacion-sonidos',
|
||||
type: 'sensibilizacion',
|
||||
prerequisites: [],
|
||||
content: {
|
||||
instruction: '¿Cuál hace muuuu?',
|
||||
audioText: 'La vaca hace muuu',
|
||||
options: [
|
||||
{ label: '🐄 Vaca', correct: true },
|
||||
{ label: '🐔 Gallina', correct: false },
|
||||
{ label: '🐑 Oveja', correct: false },
|
||||
],
|
||||
emoji: '🐄',
|
||||
},
|
||||
functionalContext: 'Reconocer sonidos de animales.',
|
||||
},
|
||||
{
|
||||
id: 'lec1-sonido-auto',
|
||||
stage: 1,
|
||||
skillCode: 'sensibilizacion-sonidos',
|
||||
type: 'sensibilizacion',
|
||||
prerequisites: [],
|
||||
content: {
|
||||
instruction: '¿Qué hace run run?',
|
||||
audioText: 'El auto hace run run',
|
||||
options: [
|
||||
{ label: '🚲 Bici', correct: false },
|
||||
{ label: '🚗 Auto', correct: true },
|
||||
{ label: '✈️ Avión', correct: false },
|
||||
],
|
||||
emoji: '🚗',
|
||||
},
|
||||
functionalContext: 'Identificar sonidos de transporte.',
|
||||
},
|
||||
{
|
||||
id: 'lec1-sonido-lluvia',
|
||||
stage: 1,
|
||||
skillCode: 'sensibilizacion-sonidos',
|
||||
type: 'sensibilizacion',
|
||||
prerequisites: [],
|
||||
content: {
|
||||
instruction: '¿Qué hace pío pío?',
|
||||
audioText: 'El pajarito hace pío pío',
|
||||
options: [
|
||||
{ label: '🐟 Pez', correct: false },
|
||||
{ label: '🐔 Gallina', correct: false },
|
||||
{ label: '🐤 Pájaro', correct: true },
|
||||
],
|
||||
emoji: '🐤',
|
||||
},
|
||||
functionalContext: 'Asociar onomatopeyas con animales.',
|
||||
},
|
||||
// --- Sonidos de la naturaleza ---
|
||||
{
|
||||
id: 'lec1-sonido-abeja',
|
||||
stage: 1,
|
||||
skillCode: 'sensibilizacion-sonidos',
|
||||
type: 'sensibilizacion',
|
||||
prerequisites: [],
|
||||
content: {
|
||||
instruction: '¿Quién hace zzzzz?',
|
||||
audioText: 'La abeja hace zzzz',
|
||||
options: [
|
||||
{ label: '🐝 Abeja', correct: true },
|
||||
{ label: '🦋 Mariposa', correct: false },
|
||||
{ label: '🐞 Mariquita', correct: false },
|
||||
],
|
||||
emoji: '🐝',
|
||||
},
|
||||
functionalContext: 'Discriminar sonidos de insectos.',
|
||||
},
|
||||
{
|
||||
id: 'lec1-sonido-agua',
|
||||
stage: 1,
|
||||
skillCode: 'sensibilizacion-sonidos',
|
||||
type: 'sensibilizacion',
|
||||
prerequisites: [],
|
||||
content: {
|
||||
instruction: '¿Qué suena así: glu glu glu?',
|
||||
audioText: 'El agua hace glu glu',
|
||||
options: [
|
||||
{ label: '💧 Agua', correct: true },
|
||||
{ label: '🔥 Fuego', correct: false },
|
||||
{ label: '💨 Viento', correct: false },
|
||||
],
|
||||
emoji: '💧',
|
||||
},
|
||||
functionalContext: 'Reconocer sonidos del agua.',
|
||||
},
|
||||
// --- Ritmo y rimas ---
|
||||
{
|
||||
id: 'lec1-ritmo-palmas',
|
||||
stage: 1,
|
||||
skillCode: 'sensibilizacion-ritmo',
|
||||
type: 'sensibilizacion',
|
||||
prerequisites: [],
|
||||
content: {
|
||||
instruction: '¡Vamos a aplaudir! ¿Podés seguir el ritmo? DA-da-da, DA-da-da',
|
||||
audioText: 'Vamos a aplaudir juntos',
|
||||
emoji: '👏',
|
||||
},
|
||||
functionalContext: 'Desarrollar conciencia rítmica.',
|
||||
},
|
||||
{
|
||||
id: 'lec1-cancion-infantil',
|
||||
stage: 1,
|
||||
skillCode: 'sensibilizacion-ritmo',
|
||||
type: 'sensibilizacion',
|
||||
prerequisites: [],
|
||||
content: {
|
||||
instruction: 'Cantemos juntos: "Estrellita, ¿dónde estás?"',
|
||||
audioText: 'Estrellita, ¿dónde estás? Me pregunto quién serás',
|
||||
emoji: '⭐',
|
||||
},
|
||||
functionalContext: 'Explorar ritmo y melodía del lenguaje.',
|
||||
},
|
||||
{
|
||||
id: 'lec1-silencio-ruido',
|
||||
stage: 1,
|
||||
skillCode: 'sensibilizacion-discriminacion',
|
||||
type: 'sensibilizacion',
|
||||
prerequisites: [],
|
||||
content: {
|
||||
instruction: 'A veces hay silencio, a veces hay ruido. ¿Cuándo escuchamos silencio?',
|
||||
audioText: 'El silencio es cuando no hay sonido',
|
||||
options: [
|
||||
{ label: '🔊 Música fuerte', correct: false },
|
||||
{ label: '🤫 Todos callados', correct: true },
|
||||
{ label: '📢 Gritos', correct: false },
|
||||
],
|
||||
emoji: '🤫',
|
||||
},
|
||||
functionalContext: 'Discriminar presencia y ausencia de sonido.',
|
||||
},
|
||||
{
|
||||
id: 'lec1-eco',
|
||||
stage: 1,
|
||||
skillCode: 'sensibilizacion-eco',
|
||||
type: 'sensibilizacion',
|
||||
prerequisites: [],
|
||||
content: {
|
||||
instruction: 'Vamos a hacer eco. Decí después de mí: PA... PA... PA',
|
||||
audioText: 'PA... PA... PA... repetí después de mí',
|
||||
options: [
|
||||
{ label: '¡Lo hice!', correct: true },
|
||||
],
|
||||
emoji: '🔊',
|
||||
},
|
||||
functionalContext: 'Tomar conciencia de la propia producción de sonidos.',
|
||||
},
|
||||
{
|
||||
id: 'lec1-onomatopeya-coco',
|
||||
stage: 1,
|
||||
skillCode: 'sensibilizacion-onomatopeya',
|
||||
type: 'sensibilizacion',
|
||||
prerequisites: [],
|
||||
content: {
|
||||
instruction: 'El reloj hace: tic-tac, tic-tac. ¿Cuál es el reloj?',
|
||||
audioText: 'El reloj hace tic tac',
|
||||
options: [
|
||||
{ label: '🕐 Reloj', correct: true },
|
||||
{ label: '📞 Teléfono', correct: false },
|
||||
{ label: '🚪 Puerta', correct: false },
|
||||
],
|
||||
emoji: '🕐',
|
||||
},
|
||||
functionalContext: 'Asociar objetos a sus sonidos.',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export default stage
|
||||
@@ -0,0 +1,345 @@
|
||||
import type { Stage } from '../types'
|
||||
|
||||
const stage: Stage = {
|
||||
id: 2,
|
||||
name: 'Conciencia fonológica',
|
||||
description: 'Rimas, conteo de sílabas, identificar sonidos iniciales y segmentación de palabras.',
|
||||
exercises: [
|
||||
// --- Rimas ---
|
||||
{
|
||||
id: 'lec2-rima-sol',
|
||||
stage: 2,
|
||||
skillCode: 'conciencia-rimas',
|
||||
type: 'conciencia',
|
||||
prerequisites: ['lec1-sonido-perro', 'lec1-ritmo-palmas'],
|
||||
content: {
|
||||
instruction: '¿Cuál palabra rima con SOL?',
|
||||
text: 'SOL',
|
||||
audioText: 'Sol rima con...',
|
||||
options: [
|
||||
{ label: 'SOL', correct: false },
|
||||
{ label: 'CARACOL', correct: true },
|
||||
{ label: 'LUNA', correct: false },
|
||||
],
|
||||
emoji: '☀️',
|
||||
},
|
||||
functionalContext: 'Identificar palabras que terminan igual.',
|
||||
errorType: 'discriminacion-auditiva',
|
||||
},
|
||||
{
|
||||
id: 'lec2-rima-pan',
|
||||
stage: 2,
|
||||
skillCode: 'conciencia-rimas',
|
||||
type: 'conciencia',
|
||||
prerequisites: ['lec1-sonido-perro'],
|
||||
content: {
|
||||
instruction: '¿Qué rima con PAN?',
|
||||
text: 'PAN',
|
||||
audioText: 'Pan rima con...',
|
||||
options: [
|
||||
{ label: 'MANO', correct: false },
|
||||
{ label: 'PAN', correct: false },
|
||||
{ label: 'CHAPAN', correct: true },
|
||||
],
|
||||
emoji: '🍞',
|
||||
},
|
||||
functionalContext: 'Reconocer terminaciones comunes.',
|
||||
errorType: 'discriminacion-auditiva',
|
||||
},
|
||||
{
|
||||
id: 'lec2-rima-flor',
|
||||
stage: 2,
|
||||
skillCode: 'conciencia-rimas',
|
||||
type: 'conciencia',
|
||||
prerequisites: ['lec1-sonido-perro'],
|
||||
content: {
|
||||
instruction: 'Buscá la palabra que rima con FLOR',
|
||||
text: 'FLOR',
|
||||
audioText: 'Flor rima con...',
|
||||
options: [
|
||||
{ label: 'COLOR', correct: true },
|
||||
{ label: 'HOJA', correct: false },
|
||||
{ label: 'FLOR', correct: false },
|
||||
],
|
||||
emoji: '🌸',
|
||||
},
|
||||
functionalContext: 'Identificar rimas en palabras conocidas.',
|
||||
errorType: 'discriminacion-auditiva',
|
||||
},
|
||||
{
|
||||
id: 'lec2-rima-miel',
|
||||
stage: 2,
|
||||
skillCode: 'conciencia-rimas',
|
||||
type: 'conciencia',
|
||||
prerequisites: ['lec1-sonido-abeja'],
|
||||
content: {
|
||||
instruction: '¿Cuál rima con MIEL?',
|
||||
text: 'MIEL',
|
||||
audioText: 'Miel rima con...',
|
||||
options: [
|
||||
{ label: 'MIEL', correct: false },
|
||||
{ label: 'PAN', correct: false },
|
||||
{ label: 'PINCEL', correct: true },
|
||||
],
|
||||
emoji: '🍯',
|
||||
},
|
||||
functionalContext: 'Reconocer patrones sonoros finales.',
|
||||
errorType: 'discriminacion-auditiva',
|
||||
},
|
||||
// --- Conteo de sílabas ---
|
||||
{
|
||||
id: 'lec2-silabas-2',
|
||||
stage: 2,
|
||||
skillCode: 'conciencia-silabas',
|
||||
type: 'conciencia',
|
||||
prerequisites: ['lec1-eco'],
|
||||
content: {
|
||||
instruction: 'Vamos a contar: ¿cuántas palmadas tiene MANO? (MA-NO)',
|
||||
text: 'MANO',
|
||||
audioText: 'MA-NO, dos palmadas',
|
||||
options: [
|
||||
{ label: '👏 Una', correct: false },
|
||||
{ label: '👏👏 Dos', correct: true },
|
||||
{ label: '👏👏👏 Tres', correct: false },
|
||||
],
|
||||
emoji: '✋',
|
||||
},
|
||||
functionalContext: 'Desarrollar conciencia de segmentación silábica.',
|
||||
errorType: 'discriminacion-auditiva',
|
||||
},
|
||||
{
|
||||
id: 'lec2-silabas-3',
|
||||
stage: 2,
|
||||
skillCode: 'conciencia-silabas',
|
||||
type: 'conciencia',
|
||||
prerequisites: ['lec2-silabas-2'],
|
||||
content: {
|
||||
instruction: '¿Cuántas partes tiene VENTANA? (VEN-TA-NA)',
|
||||
text: 'VENTANA',
|
||||
audioText: 'VEN-TA-NA, tres partes',
|
||||
options: [
|
||||
{ label: '👏 Dos', correct: false },
|
||||
{ label: '👏👏👏 Tres', correct: true },
|
||||
{ label: '👏👏👏👏 Cuatro', correct: false },
|
||||
],
|
||||
emoji: '🪟',
|
||||
},
|
||||
functionalContext: 'Segmentar palabras en sílabas.',
|
||||
errorType: 'discriminacion-auditiva',
|
||||
},
|
||||
{
|
||||
id: 'lec2-silabas-1',
|
||||
stage: 2,
|
||||
skillCode: 'conciencia-silabas',
|
||||
type: 'conciencia',
|
||||
prerequisites: ['lec2-silabas-2'],
|
||||
content: {
|
||||
instruction: '¿Cuántas palmadas para SOL? (SOL)',
|
||||
text: 'SOL',
|
||||
audioText: 'SOL, una sola palmada',
|
||||
options: [
|
||||
{ label: '👏 Una', correct: true },
|
||||
{ label: '👏👏 Dos', correct: false },
|
||||
{ label: '👏👏👏 Tres', correct: false },
|
||||
],
|
||||
emoji: '☀️',
|
||||
},
|
||||
functionalContext: 'Reconocer palabras monosílabas.',
|
||||
errorType: 'discriminacion-auditiva',
|
||||
},
|
||||
{
|
||||
id: 'lec2-silabas-4',
|
||||
stage: 2,
|
||||
skillCode: 'conciencia-silabas',
|
||||
type: 'conciencia',
|
||||
prerequisites: ['lec2-silabas-3'],
|
||||
content: {
|
||||
instruction: '¿Cuántas palmadas para MARIPOSA? (MA-RI-PO-SA)',
|
||||
text: 'MARIPOSA',
|
||||
audioText: 'MA-RI-PO-SA, cuatro partes',
|
||||
options: [
|
||||
{ label: '👏 Dos', correct: false },
|
||||
{ label: '👏👏👏 Tres', correct: false },
|
||||
{ label: '👏👏👏👏 Cuatro', correct: true },
|
||||
],
|
||||
emoji: '🦋',
|
||||
},
|
||||
functionalContext: 'Segmentar palabras de 4 sílabas.',
|
||||
errorType: 'discriminacion-auditiva',
|
||||
},
|
||||
// --- Sílaba inicial ---
|
||||
{
|
||||
id: 'lec2-inicial-ma',
|
||||
stage: 2,
|
||||
skillCode: 'conciencia-inicial',
|
||||
type: 'conciencia',
|
||||
prerequisites: ['lec2-silabas-2'],
|
||||
content: {
|
||||
instruction: '¿Cuál empieza como MAMÁ? (MA-MÁ, MA-NO)',
|
||||
text: 'MAMÁ → MA...',
|
||||
audioText: 'Mamá empieza con MA',
|
||||
options: [
|
||||
{ label: 'MANO', correct: true },
|
||||
{ label: 'PATO', correct: false },
|
||||
{ label: 'SAPO', correct: false },
|
||||
],
|
||||
emoji: '👩',
|
||||
},
|
||||
functionalContext: 'Identificar el sonido inicial de las palabras.',
|
||||
errorType: 'discriminacion-auditiva',
|
||||
},
|
||||
{
|
||||
id: 'lec2-inicial-pa',
|
||||
stage: 2,
|
||||
skillCode: 'conciencia-inicial',
|
||||
type: 'conciencia',
|
||||
prerequisites: ['lec2-inicial-ma'],
|
||||
content: {
|
||||
instruction: '¿Cuál empieza como PAPÁ? (PA-PÁ, PA-TO)',
|
||||
text: 'PAPÁ → PA...',
|
||||
audioText: 'Papá empieza con PA',
|
||||
options: [
|
||||
{ label: 'PERRO', correct: false },
|
||||
{ label: 'PATO', correct: true },
|
||||
{ label: 'CASA', correct: false },
|
||||
],
|
||||
emoji: '👨',
|
||||
},
|
||||
functionalContext: 'Generalizar identificación de sílaba inicial.',
|
||||
errorType: 'discriminacion-auditiva',
|
||||
},
|
||||
{
|
||||
id: 'lec2-inicial-ta',
|
||||
stage: 2,
|
||||
skillCode: 'conciencia-inicial',
|
||||
type: 'conciencia',
|
||||
prerequisites: ['lec2-inicial-pa'],
|
||||
content: {
|
||||
instruction: 'Buscá la que empieza como TAZA (TA-ZA, TA-BLA)',
|
||||
text: 'TAZA → TA...',
|
||||
audioText: 'Taza empieza con TA',
|
||||
options: [
|
||||
{ label: 'MESA', correct: false },
|
||||
{ label: 'TAMBOR', correct: true },
|
||||
{ label: 'LÁPIZ', correct: false },
|
||||
],
|
||||
emoji: '☕',
|
||||
},
|
||||
functionalContext: 'Reconocer sílaba TA al inicio.',
|
||||
errorType: 'discriminacion-auditiva',
|
||||
},
|
||||
{
|
||||
id: 'lec2-inicial-sa',
|
||||
stage: 2,
|
||||
skillCode: 'conciencia-inicial',
|
||||
type: 'conciencia',
|
||||
prerequisites: ['lec2-inicial-ta'],
|
||||
content: {
|
||||
instruction: '¿Cuál empieza como SAPO? (SA-PO, SA-LTA)',
|
||||
text: 'SAPO → SA...',
|
||||
audioText: 'Sapo empieza con SA',
|
||||
options: [
|
||||
{ label: 'SAPO', correct: false },
|
||||
{ label: 'SALTA', correct: true },
|
||||
{ label: 'RANA', correct: false },
|
||||
],
|
||||
emoji: '🐸',
|
||||
},
|
||||
functionalContext: 'Identificar sonido SA al inicio.',
|
||||
errorType: 'discriminacion-auditiva',
|
||||
},
|
||||
// --- Segmentación ---
|
||||
{
|
||||
id: 'lec2-segmentar-casa',
|
||||
stage: 2,
|
||||
skillCode: 'conciencia-segmentacion',
|
||||
type: 'conciencia',
|
||||
prerequisites: ['lec2-silabas-2', 'lec2-inicial-ma'],
|
||||
content: {
|
||||
instruction: 'Separala en partes: CA-SA. ¿Cuál tiene dos partes?',
|
||||
text: 'CA-SA',
|
||||
audioText: 'CA-SA',
|
||||
options: [
|
||||
{ label: 'SOL', correct: false },
|
||||
{ label: 'CASA', correct: true },
|
||||
{ label: 'MARIPOSA', correct: false },
|
||||
],
|
||||
emoji: '🏠',
|
||||
},
|
||||
functionalContext: 'Segmentar palabras en sílabas.',
|
||||
errorType: 'omision-letra',
|
||||
},
|
||||
{
|
||||
id: 'lec2-segmentar-mesa',
|
||||
stage: 2,
|
||||
skillCode: 'conciencia-segmentacion',
|
||||
type: 'conciencia',
|
||||
prerequisites: ['lec2-segmentar-casa'],
|
||||
content: {
|
||||
instruction: 'ME-SA. ¿Cuál es?',
|
||||
text: 'ME-SA',
|
||||
audioText: 'ME-SA',
|
||||
options: [
|
||||
{ label: 'MESA', correct: true },
|
||||
{ label: 'MELÓN', correct: false },
|
||||
{ label: 'SAPO', correct: false },
|
||||
],
|
||||
emoji: '🪑',
|
||||
},
|
||||
functionalContext: 'Unir segmentos para formar palabras.',
|
||||
errorType: 'omision-letra',
|
||||
},
|
||||
{
|
||||
id: 'lec2-segmentar-pato',
|
||||
stage: 2,
|
||||
skillCode: 'conciencia-segmentacion',
|
||||
type: 'conciencia',
|
||||
prerequisites: ['lec2-segmentar-mesa'],
|
||||
content: {
|
||||
instruction: 'PA-TO. ¿Qué palabra formamos?',
|
||||
text: 'PA-TO',
|
||||
audioText: 'PA-TO',
|
||||
options: [
|
||||
{ label: 'PATO', correct: true },
|
||||
{ label: 'PERRO', correct: false },
|
||||
{ label: 'GATO', correct: false },
|
||||
],
|
||||
emoji: '🦆',
|
||||
},
|
||||
functionalContext: 'Sintetizar sílabas para formar palabras.',
|
||||
errorType: 'omision-letra',
|
||||
},
|
||||
{
|
||||
id: 'lec2-ordenar-silabas',
|
||||
stage: 2,
|
||||
skillCode: 'conciencia-orden',
|
||||
type: 'secuencia',
|
||||
prerequisites: ['lec2-segmentar-pato'],
|
||||
content: {
|
||||
instruction: 'Ordená las sílabas para formar una palabra',
|
||||
audioText: 'Ordená las sílabas',
|
||||
sequence: ['TO', 'PA'],
|
||||
emoji: '🧩',
|
||||
},
|
||||
functionalContext: 'Desarrollar habilidad de ordenamiento fonológico.',
|
||||
errorType: 'inversion-letra',
|
||||
},
|
||||
{
|
||||
id: 'lec2-ordenar-silabas-2',
|
||||
stage: 2,
|
||||
skillCode: 'conciencia-orden',
|
||||
type: 'secuencia',
|
||||
prerequisites: ['lec2-ordenar-silabas'],
|
||||
content: {
|
||||
instruction: 'Armá la palabra',
|
||||
audioText: 'Ordená estas sílabas',
|
||||
sequence: ['SA', 'CA'],
|
||||
emoji: '🧩',
|
||||
},
|
||||
functionalContext: 'Ordenar sílabas para formar palabras.',
|
||||
errorType: 'inversion-letra',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export default stage
|
||||
@@ -0,0 +1,269 @@
|
||||
import type { Stage } from '../types'
|
||||
|
||||
function vocalChoice(vocal: string, correctLabel: string, distractors: string[], emoji: string, instruction: string, audioText?: string) {
|
||||
const options = [
|
||||
{ label: correctLabel, correct: true, id: vocal },
|
||||
...distractors.map((d) => ({ label: d, correct: false, id: d })),
|
||||
].sort(() => Math.random() - 0.5)
|
||||
|
||||
return {
|
||||
stage: 3,
|
||||
skillCode: `vocal-${vocal}`,
|
||||
type: 'eleccion' as const,
|
||||
prerequisites: getVocalPrereqs(vocal),
|
||||
content: {
|
||||
instruction,
|
||||
text: correctLabel,
|
||||
options,
|
||||
audioText: audioText || `${correctLabel}`,
|
||||
emoji,
|
||||
color: getVocalColor(vocal),
|
||||
},
|
||||
functionalContext: `Identificar la vocal ${vocal.toUpperCase()} en diferentes contextos.`,
|
||||
errorType: 'confusion-letra' as const,
|
||||
}
|
||||
}
|
||||
|
||||
function getVocalColor(vocal: string): string {
|
||||
const colors: Record<string, string> = { a: '#FF6B6B', o: '#4ECDC4', i: '#45B7D1', e: '#96CEB4', u: '#DDA0DD' }
|
||||
return colors[vocal] || '#FF6B6B'
|
||||
}
|
||||
|
||||
function getVocalPrereqs(vocal: string): string[] {
|
||||
const order = ['a', 'o', 'i', 'e', 'u']
|
||||
const idx = order.indexOf(vocal)
|
||||
if (idx === 0) return ['lec2-segmentar-pato']
|
||||
return [`vocal-${order[idx - 1]}-completa`]
|
||||
}
|
||||
|
||||
const gestos: Record<string, { gesto: string, palabra: string, fonema: string, emoji: string }> = {
|
||||
a: { gesto: 'Abrí la mano como una boca grande', palabra: 'ÁRBOL', fonema: 'AAA', emoji: '🌳' },
|
||||
o: { gesto: 'Redondeá la mano como una O', palabra: 'OJO', fonema: 'OOO', emoji: '👁️' },
|
||||
i: { gesto: 'Señalá el cielo con el dedo', palabra: 'INDIO', fonema: 'III', emoji: '🪶' },
|
||||
e: { gesto: 'Estirá la mano como una trompa de elefante', palabra: 'ELEFANTE', fonema: 'EEE', emoji: '🐘' },
|
||||
u: { gesto: 'Señalá el suelo con la mano', palabra: 'UNO', fonema: 'UUU', emoji: '1️⃣' },
|
||||
}
|
||||
|
||||
function buildVocalExercises(vocal: string, index: number): any[] {
|
||||
const g = gestos[vocal]
|
||||
const exs: any[] = []
|
||||
|
||||
// Ejercicio de gesto (sensibilizacion)
|
||||
exs.push({
|
||||
id: `lec3-${vocal}-gesto`,
|
||||
stage: 3,
|
||||
skillCode: `vocal-${vocal}`,
|
||||
type: 'sensibilizacion',
|
||||
prerequisites: getVocalPrereqs(vocal),
|
||||
content: {
|
||||
instruction: `Hacé así para la ${vocal.toUpperCase()}: ${g.gesto}`,
|
||||
audioText: `Esta es la letra ${vocal.toUpperCase()}. ${g.palabra}. ${g.fonema}`,
|
||||
emoji: g.emoji,
|
||||
color: getVocalColor(vocal),
|
||||
},
|
||||
functionalContext: `Aprender el gesto Borel-Maisonny para la vocal ${vocal.toUpperCase()}.`,
|
||||
})
|
||||
|
||||
// Reconocer la vocal entre otras
|
||||
exs.push(vocalChoice(
|
||||
vocal, vocal.toUpperCase(),
|
||||
['A', 'O', 'I', 'E', 'U'].filter((v) => v !== vocal.toUpperCase()),
|
||||
g.emoji,
|
||||
`Señalá la letra ${vocal.toUpperCase()}`,
|
||||
))
|
||||
|
||||
// ¿Con qué vocal empieza?
|
||||
exs.push({
|
||||
id: `lec3-${vocal}-inicial`,
|
||||
stage: 3,
|
||||
skillCode: `vocal-${vocal}`,
|
||||
type: 'eleccion',
|
||||
prerequisites: [`lec3-${vocal}-gesto`],
|
||||
content: {
|
||||
instruction: `¿Con qué vocal empieza ${g.palabra}?`,
|
||||
text: g.palabra,
|
||||
audioText: `${g.palabra} empieza con ${vocal.toUpperCase()}`,
|
||||
options: [
|
||||
{ label: vocal.toUpperCase(), correct: true, id: vocal },
|
||||
...['A', 'O', 'I', 'E', 'U'].filter((v) => v !== vocal.toUpperCase()).slice(0, 2).map((v) => ({ label: v, correct: false, id: v })),
|
||||
],
|
||||
emoji: g.emoji,
|
||||
},
|
||||
functionalContext: `Reconocer la vocal inicial en palabras.`,
|
||||
errorType: 'discriminacion-auditiva',
|
||||
})
|
||||
|
||||
// Emparejar imagen con vocal
|
||||
exs.push({
|
||||
id: `lec3-${vocal}-emparejar`,
|
||||
stage: 3,
|
||||
skillCode: `vocal-${vocal}`,
|
||||
type: 'conciencia',
|
||||
prerequisites: [`lec3-${vocal}-inicial`],
|
||||
content: {
|
||||
instruction: `¿Cuál empieza con ${vocal.toUpperCase()}?`,
|
||||
audioText: `¿Qué empieza con ${vocal.toUpperCase()}?`,
|
||||
options: [
|
||||
{ label: g.emoji, correct: true, id: vocal },
|
||||
...Object.entries(gestos)
|
||||
.filter(([k]) => k !== vocal)
|
||||
.slice(0, 2)
|
||||
.map(([k, v]) => ({ label: v.emoji, correct: false, id: k })),
|
||||
],
|
||||
},
|
||||
functionalContext: `Asociar la vocal con imágenes que empiezan con ella.`,
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
|
||||
// Discriminación auditiva
|
||||
exs.push({
|
||||
id: `lec3-${vocal}-auditiva`,
|
||||
stage: 3,
|
||||
skillCode: `vocal-${vocal}`,
|
||||
type: 'conciencia',
|
||||
prerequisites: [`lec3-${vocal}-emparejar`],
|
||||
content: {
|
||||
instruction: `Escuchá bien. ¿Cuál suena como ${vocal.toUpperCase()}?`,
|
||||
audioText: `${g.fonema}... ${g.fonema}... como ${g.palabra}`,
|
||||
options: [
|
||||
{ label: vocal.toUpperCase(), correct: true, id: vocal },
|
||||
...['A', 'O', 'I', 'E', 'U'].filter((v) => v !== vocal.toUpperCase()).slice(0, 2).map((v) => ({ label: v, correct: false, id: v })),
|
||||
],
|
||||
emoji: '👂',
|
||||
},
|
||||
functionalContext: `Discriminar auditivamente la vocal ${vocal.toUpperCase()}.`,
|
||||
errorType: 'discriminacion-auditiva',
|
||||
})
|
||||
|
||||
// Escribir con el dedo (trazo)
|
||||
exs.push({
|
||||
id: `lec3-${vocal}-trazo`,
|
||||
stage: 3,
|
||||
skillCode: `vocal-${vocal}`,
|
||||
type: 'trazo',
|
||||
prerequisites: [`lec3-${vocal}-auditiva`],
|
||||
content: {
|
||||
instruction: `Trazá la letra ${vocal.toUpperCase()} con tu dedo`,
|
||||
text: vocal.toUpperCase(),
|
||||
audioText: `Trazá la ${vocal.toUpperCase()}`,
|
||||
color: getVocalColor(vocal),
|
||||
emoji: g.emoji,
|
||||
},
|
||||
functionalContext: `Desarrollar memoria motriz de la vocal ${vocal.toUpperCase()}.`,
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
|
||||
// Repaso final
|
||||
exs.push({
|
||||
id: `lec3-${vocal}-completa`,
|
||||
stage: 3,
|
||||
skillCode: `vocal-${vocal}`,
|
||||
type: 'eleccion',
|
||||
prerequisites: [`lec3-${vocal}-trazo`],
|
||||
content: {
|
||||
instruction: `¡Repaso! Señalá la letra ${vocal.toUpperCase()}`,
|
||||
audioText: `Buscá la ${vocal.toUpperCase()}`,
|
||||
options: [
|
||||
{ label: vocal.toUpperCase(), correct: true, id: vocal },
|
||||
...['A', 'O', 'I', 'E', 'U'].filter((v) => v !== vocal.toUpperCase()).map((v) => ({ label: v, correct: false, id: v })),
|
||||
],
|
||||
emoji: g.emoji,
|
||||
color: getVocalColor(vocal),
|
||||
},
|
||||
functionalContext: `Consolidar reconocimiento de la vocal ${vocal.toUpperCase()}.`,
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
|
||||
return exs
|
||||
}
|
||||
|
||||
// Additional cross-vowel discrimination exercises
|
||||
const mixedExercises: any[] = [
|
||||
{
|
||||
id: 'lec3-mix-ae',
|
||||
stage: 3,
|
||||
skillCode: 'vocal-discriminacion',
|
||||
type: 'eleccion',
|
||||
prerequisites: ['lec3-a-completa', 'lec3-e-completa'],
|
||||
content: {
|
||||
instruction: '¿Cuál es la A y cuál es la E? Señalá la A',
|
||||
options: [
|
||||
{ label: 'A', correct: true, id: 'a' },
|
||||
{ label: 'E', correct: false, id: 'e' },
|
||||
{ label: 'O', correct: false, id: 'o' },
|
||||
],
|
||||
emoji: '🔤',
|
||||
},
|
||||
functionalContext: 'Discriminar entre A y E.',
|
||||
errorType: 'confusion-letra',
|
||||
},
|
||||
{
|
||||
id: 'lec3-mix-iu',
|
||||
stage: 3,
|
||||
skillCode: 'vocal-discriminacion',
|
||||
type: 'eleccion',
|
||||
prerequisites: ['lec3-i-completa', 'lec3-u-completa'],
|
||||
content: {
|
||||
instruction: '¿Cuál es la I y cuál es la U? Señalá la I',
|
||||
options: [
|
||||
{ label: 'I', correct: true, id: 'i' },
|
||||
{ label: 'U', correct: false, id: 'u' },
|
||||
{ label: 'A', correct: false, id: 'a' },
|
||||
],
|
||||
emoji: '🔤',
|
||||
},
|
||||
functionalContext: 'Discriminar entre I y U.',
|
||||
errorType: 'confusion-letra',
|
||||
},
|
||||
{
|
||||
id: 'lec3-mix-ao',
|
||||
stage: 3,
|
||||
skillCode: 'vocal-discriminacion',
|
||||
type: 'eleccion',
|
||||
prerequisites: ['lec3-a-completa', 'lec3-o-completa'],
|
||||
content: {
|
||||
instruction: 'Señalá la letra O',
|
||||
options: [
|
||||
{ label: 'A', correct: false, id: 'a' },
|
||||
{ label: 'O', correct: true, id: 'o' },
|
||||
{ label: 'U', correct: false, id: 'u' },
|
||||
],
|
||||
emoji: '🔤',
|
||||
},
|
||||
functionalContext: 'Discriminar entre A y O.',
|
||||
errorType: 'confusion-letra',
|
||||
},
|
||||
{
|
||||
id: 'lec3-mix-ei',
|
||||
stage: 3,
|
||||
skillCode: 'vocal-discriminacion',
|
||||
type: 'eleccion',
|
||||
prerequisites: ['lec3-e-completa', 'lec3-i-completa'],
|
||||
content: {
|
||||
instruction: 'Señalá la E',
|
||||
options: [
|
||||
{ label: 'I', correct: false, id: 'i' },
|
||||
{ label: 'E', correct: true, id: 'e' },
|
||||
{ label: 'U', correct: false, id: 'u' },
|
||||
],
|
||||
emoji: '🔤',
|
||||
},
|
||||
functionalContext: 'Discriminar entre E e I.',
|
||||
errorType: 'confusion-letra',
|
||||
},
|
||||
]
|
||||
|
||||
const exercises: any[] = []
|
||||
for (const [i, vocal] of ['a', 'o', 'i', 'e', 'u'].entries()) {
|
||||
exercises.push(...buildVocalExercises(vocal, i))
|
||||
}
|
||||
exercises.push(...mixedExercises)
|
||||
|
||||
const stage: Stage = {
|
||||
id: 3,
|
||||
name: 'Vocales A-O-I-E-U',
|
||||
description: 'Aprender las 5 vocales con gestos Borel-Maisonny, discriminación auditiva y visual, trazo y reconocimiento.',
|
||||
exercises,
|
||||
}
|
||||
|
||||
export default stage
|
||||
@@ -0,0 +1,235 @@
|
||||
import type { Stage } from '../types'
|
||||
|
||||
type ConInfo = {
|
||||
letra: string
|
||||
palabra: string
|
||||
emoji: string
|
||||
silabas: string[]
|
||||
gesto: string
|
||||
}
|
||||
|
||||
const consonantes: ConInfo[] = [
|
||||
{ letra: 'M', palabra: 'MAMÁ', emoji: '👩', silabas: ['MA', 'ME', 'MI', 'MO', 'MU'], gesto: 'Manos en la boca como mmm' },
|
||||
{ letra: 'P', palabra: 'PAPÁ', emoji: '👨', silabas: ['PA', 'PE', 'PI', 'PO', 'PU'], gesto: 'Manos que abren y cierran como pompa' },
|
||||
{ letra: 'L', palabra: 'LUNA', emoji: '🌙', silabas: ['LA', 'LE', 'LI', 'LO', 'LU'], gesto: 'Lengua arriba como lámpara' },
|
||||
{ letra: 'S', palabra: 'SOL', emoji: '☀️', silabas: ['SA', 'SE', 'SI', 'SO', 'SU'], gesto: 'Dedos como serpiente sss' },
|
||||
{ letra: 'T', palabra: 'TASA', emoji: '☕', silabas: ['TA', 'TE', 'TI', 'TO', 'TU'], gesto: 'Golpecito con la mano' },
|
||||
{ letra: 'N', palabra: 'NIDO', emoji: '🪺', silabas: ['NA', 'NE', 'NI', 'NO', 'NU'], gesto: 'Nariz como nido' },
|
||||
{ letra: 'D', palabra: 'DEDO', emoji: '👉', silabas: ['DA', 'DE', 'DI', 'DO', 'DU'], gesto: 'Dedo señalando' },
|
||||
{ letra: 'R', palabra: 'RATÓN', emoji: '🐭', silabas: ['RA', 'RE', 'RI', 'RO', 'RU'], gesto: 'Lengua que vibra como rrr' },
|
||||
]
|
||||
|
||||
const exercises: any[] = []
|
||||
|
||||
for (const con of consonantes) {
|
||||
// 1. Presentación con gesto
|
||||
exercises.push({
|
||||
id: `lec4-${con.letra.toLowerCase()}-gesto`,
|
||||
stage: 4,
|
||||
skillCode: `consonante-${con.letra.toLowerCase()}`,
|
||||
type: 'sensibilizacion',
|
||||
prerequisites: con.letra === 'M' ? ['lec3-u-completa'] : [`lec4-${consonantes[consonantes.indexOf(con) - 1].letra.toLowerCase()}-completa`],
|
||||
content: {
|
||||
instruction: `Hacé así para la ${con.letra}: ${con.gesto}`,
|
||||
audioText: `Esta es la letra ${con.letra}. ${con.palabra}. ${con.silabas[0].toLowerCase()}`,
|
||||
emoji: con.emoji,
|
||||
},
|
||||
functionalContext: `Conocer el gesto asociado a la consonante ${con.letra}.`,
|
||||
})
|
||||
|
||||
// 2. Reconocer la consonante
|
||||
exercises.push({
|
||||
id: `lec4-${con.letra.toLowerCase()}-reconocer`,
|
||||
stage: 4,
|
||||
skillCode: `consonante-${con.letra.toLowerCase()}`,
|
||||
type: 'eleccion',
|
||||
prerequisites: [`lec4-${con.letra.toLowerCase()}-gesto`],
|
||||
content: {
|
||||
instruction: `Señalá la letra ${con.letra}`,
|
||||
text: `Buscá la ${con.letra}`,
|
||||
audioText: `¿Dónde está la ${con.letra}?`,
|
||||
options: [
|
||||
{ label: con.letra, correct: true, id: con.letra.toLowerCase() },
|
||||
...consonantes.filter(c => c.letra !== con.letra).slice(0, 3).map(c => ({ label: c.letra, correct: false, id: c.letra.toLowerCase() })),
|
||||
],
|
||||
emoji: con.emoji,
|
||||
},
|
||||
functionalContext: `Reconocer visualmente la consonante ${con.letra}.`,
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
|
||||
// 3. Discriminación auditiva de la sílaba
|
||||
exercises.push({
|
||||
id: `lec4-${con.letra.toLowerCase()}-auditiva`,
|
||||
stage: 4,
|
||||
skillCode: `consonante-${con.letra.toLowerCase()}`,
|
||||
type: 'conciencia',
|
||||
prerequisites: [`lec4-${con.letra.toLowerCase()}-reconocer`],
|
||||
content: {
|
||||
instruction: `Escuchá. ¿Cuál suena como ${con.silabas[0]}?`,
|
||||
audioText: `${con.silabas[0]}... ${con.silabas[0]}... como ${con.palabra}`,
|
||||
options: [
|
||||
{ label: con.silabas[0], correct: true, id: con.silabas[0].toLowerCase() },
|
||||
...consonantes.filter(c => c.letra !== con.letra).slice(0, 2).map(c => ({ label: c.silabas[0], correct: false, id: c.silabas[0].toLowerCase() })),
|
||||
],
|
||||
emoji: '👂',
|
||||
},
|
||||
functionalContext: `Discriminar auditivamente la sílaba ${con.silabas[0]}.`,
|
||||
errorType: 'discriminacion-auditiva',
|
||||
})
|
||||
|
||||
// 4. Emparejar sílaba con vocal
|
||||
for (let vi = 1; vi < con.silabas.length; vi++) {
|
||||
const sil = con.silabas[vi]
|
||||
const vocal = sil[1]
|
||||
const vocales = ['A', 'E', 'I', 'O', 'U'].filter(v => v !== vocal)
|
||||
exercises.push({
|
||||
id: `lec4-${con.letra.toLowerCase()}-silaba-${sil.toLowerCase()}`,
|
||||
stage: 4,
|
||||
skillCode: `consonante-${con.letra.toLowerCase()}-silabas`,
|
||||
type: 'eleccion',
|
||||
prerequisites: [`lec4-${con.letra.toLowerCase()}-auditiva`, `lec4-${con.letra.toLowerCase()}-silaba-${con.silabas[vi - 1].toLowerCase()}`],
|
||||
content: {
|
||||
instruction: `¿Cuál es ${sil}?`,
|
||||
text: sil,
|
||||
audioText: `${sil}... como ${con.palabra.toLowerCase()}`,
|
||||
options: [
|
||||
{ label: sil, correct: true, id: sil.toLowerCase() },
|
||||
{ label: `${con.letra}${vocales[0]}`, correct: false, id: `${con.letra}${vocales[0]}`.toLowerCase() },
|
||||
{ label: `${con.letra}${vocales[1]}`, correct: false, id: `${con.letra}${vocales[1]}`.toLowerCase() },
|
||||
],
|
||||
emoji: con.emoji,
|
||||
},
|
||||
functionalContext: `Leer la sílaba ${sil}.`,
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
}
|
||||
|
||||
// 5. Palabra con la consonante
|
||||
exercises.push({
|
||||
id: `lec4-${con.letra.toLowerCase()}-palabra`,
|
||||
stage: 4,
|
||||
skillCode: `consonante-${con.letra.toLowerCase()}`,
|
||||
type: 'palabra',
|
||||
prerequisites: [`lec4-${con.letra.toLowerCase()}-silaba-${con.silabas[con.silabas.length - 1].toLowerCase()}`],
|
||||
content: {
|
||||
instruction: `¿Cuál palabra empieza con ${con.letra}?`,
|
||||
audioText: `${con.palabra} empieza con ${con.letra}`,
|
||||
imageEmoji: con.emoji,
|
||||
options: [
|
||||
{ label: con.palabra, correct: true, id: con.palabra.toLowerCase() },
|
||||
{ label: 'CASA', correct: false, id: 'casa' },
|
||||
{ label: 'GATO', correct: false, id: 'gato' },
|
||||
{ label: 'Escuchar 👂', correct: false, id: 'escuchar' },
|
||||
],
|
||||
},
|
||||
functionalContext: `Asociar la consonante ${con.letra} con una palabra significativa.`,
|
||||
errorType: 'discriminacion-auditiva',
|
||||
})
|
||||
|
||||
// 6. Final: repaso completo
|
||||
exercises.push({
|
||||
id: `lec4-${con.letra.toLowerCase()}-completa`,
|
||||
stage: 4,
|
||||
skillCode: `consonante-${con.letra.toLowerCase()}`,
|
||||
type: 'eleccion',
|
||||
prerequisites: [`lec4-${con.letra.toLowerCase()}-palabra`],
|
||||
content: {
|
||||
instruction: `¡Repaso! Señalá la letra ${con.letra}`,
|
||||
audioText: `Buscá la ${con.letra}`,
|
||||
options: [
|
||||
{ label: con.letra, correct: true, id: con.letra.toLowerCase() },
|
||||
...consonantes.filter(c => c.letra !== con.letra).slice(0, 3).map(c => ({ label: c.letra, correct: false, id: c.letra.toLowerCase() })),
|
||||
],
|
||||
emoji: con.emoji,
|
||||
},
|
||||
functionalContext: `Consolidar reconocimiento de la consonante ${con.letra}.`,
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
}
|
||||
|
||||
// Cross-consonant discrimination exercises
|
||||
exercises.push({
|
||||
id: 'lec4-mix-mp',
|
||||
stage: 4,
|
||||
skillCode: 'consonante-discriminacion',
|
||||
type: 'eleccion',
|
||||
prerequisites: ['lec4-m-completa', 'lec4-p-completa'],
|
||||
content: {
|
||||
instruction: 'Señalá la M',
|
||||
options: [
|
||||
{ label: 'M', correct: true, id: 'm' },
|
||||
{ label: 'P', correct: false, id: 'p' },
|
||||
{ label: 'L', correct: false, id: 'l' },
|
||||
],
|
||||
emoji: '🔤',
|
||||
},
|
||||
functionalContext: 'Discriminar entre M y P.',
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
|
||||
exercises.push({
|
||||
id: 'lec4-mix-st',
|
||||
stage: 4,
|
||||
skillCode: 'consonante-discriminacion',
|
||||
type: 'eleccion',
|
||||
prerequisites: ['lec4-s-completa', 'lec4-t-completa'],
|
||||
content: {
|
||||
instruction: 'Señalá la T',
|
||||
options: [
|
||||
{ label: 'S', correct: false, id: 's' },
|
||||
{ label: 'T', correct: true, id: 't' },
|
||||
{ label: 'N', correct: false, id: 'n' },
|
||||
],
|
||||
emoji: '🔤',
|
||||
},
|
||||
functionalContext: 'Discriminar entre S y T.',
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
|
||||
exercises.push({
|
||||
id: 'lec4-mix-ld',
|
||||
stage: 4,
|
||||
skillCode: 'consonante-discriminacion',
|
||||
type: 'eleccion',
|
||||
prerequisites: ['lec4-l-completa', 'lec4-d-completa'],
|
||||
content: {
|
||||
instruction: 'Señalá la D',
|
||||
options: [
|
||||
{ label: 'L', correct: false, id: 'l' },
|
||||
{ label: 'D', correct: true, id: 'd' },
|
||||
{ label: 'R', correct: false, id: 'r' },
|
||||
],
|
||||
emoji: '🔤',
|
||||
},
|
||||
functionalContext: 'Discriminar entre L y D.',
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
|
||||
exercises.push({
|
||||
id: 'lec4-mix-nr',
|
||||
stage: 4,
|
||||
skillCode: 'consonante-discriminacion',
|
||||
type: 'eleccion',
|
||||
prerequisites: ['lec4-n-completa', 'lec4-r-completa'],
|
||||
content: {
|
||||
instruction: 'Señalá la R',
|
||||
options: [
|
||||
{ label: 'N', correct: false, id: 'n' },
|
||||
{ label: 'R', correct: true, id: 'r' },
|
||||
{ label: 'M', correct: false, id: 'm' },
|
||||
],
|
||||
emoji: '🔤',
|
||||
},
|
||||
functionalContext: 'Discriminar entre N y R.',
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
|
||||
const stage: Stage = {
|
||||
id: 4,
|
||||
name: 'Consonantes M-P-L-S-T-N-D-R',
|
||||
description: 'Aprender las consonantes M, P, L, S, T, N, D, R con gestos, sílabas, y palabras significativas.',
|
||||
exercises,
|
||||
}
|
||||
|
||||
export default stage
|
||||
@@ -0,0 +1,293 @@
|
||||
import type { Stage, Exercise } from '../types'
|
||||
|
||||
type Info = {
|
||||
letra: string
|
||||
palabra: string
|
||||
emoji: string
|
||||
gesto: string
|
||||
silaba: string
|
||||
palabraLower: string
|
||||
}
|
||||
|
||||
const moduleA: Info[] = [
|
||||
{ letra: 'A', palabra: 'ÁRBOL', emoji: '🌳', gesto: 'Abrí la mano como una boca grande', silaba: 'a', palabraLower: 'árbol' },
|
||||
{ letra: 'E', palabra: 'ELEFANTE', emoji: '🐘', gesto: 'Estirá la mano como una trompa', silaba: 'e', palabraLower: 'elefante' },
|
||||
{ letra: 'I', palabra: 'INDIO', emoji: '🪶', gesto: 'Señalá el cielo con el dedo', silaba: 'i', palabraLower: 'indio' },
|
||||
{ letra: 'O', palabra: 'OJO', emoji: '👁️', gesto: 'Redondeá la mano como una O', silaba: 'o', palabraLower: 'ojo' },
|
||||
{ letra: 'U', palabra: 'UNO', emoji: '1️⃣', gesto: 'Señalá el suelo con la mano', silaba: 'u', palabraLower: 'uno' },
|
||||
]
|
||||
|
||||
const moduleB: Info[] = [
|
||||
{ letra: 'M', palabra: 'MAMÁ', emoji: '👩', gesto: 'Manos en la boca como mmm', silaba: 'ma', palabraLower: 'mamá' },
|
||||
{ letra: 'P', palabra: 'PAPÁ', emoji: '👨', gesto: 'Manos que abren y cierran como pompa', silaba: 'pa', palabraLower: 'papá' },
|
||||
{ letra: 'L', palabra: 'LUNA', emoji: '🌙', gesto: 'Lengua arriba como lámpara', silaba: 'la', palabraLower: 'luna' },
|
||||
{ letra: 'S', palabra: 'SOL', emoji: '☀️', gesto: 'Dedos como serpiente sss', silaba: 'sa', palabraLower: 'sol' },
|
||||
]
|
||||
|
||||
const moduleC: Info[] = [
|
||||
{ letra: 'T', palabra: 'TASA', emoji: '☕', gesto: 'Golpecito con la mano', silaba: 'ta', palabraLower: 'tasa' },
|
||||
{ letra: 'N', palabra: 'NIDO', emoji: '🪺', gesto: 'Nariz como nido', silaba: 'na', palabraLower: 'nido' },
|
||||
{ letra: 'D', palabra: 'DEDO', emoji: '👉', gesto: 'Dedo señalando', silaba: 'da', palabraLower: 'dedo' },
|
||||
{ letra: 'R', palabra: 'RATÓN', emoji: '🐭', gesto: 'Lengua que vibra como rrr', silaba: 'ra', palabraLower: 'ratón' },
|
||||
]
|
||||
|
||||
const allModules = [moduleA, moduleB, moduleC]
|
||||
|
||||
function getDistractors(pool: Info[], current: Info, count: number): Info[] {
|
||||
return pool.filter((x) => x.letra !== current.letra).slice(0, count)
|
||||
}
|
||||
|
||||
function getPoolIndex(info: Info): number {
|
||||
for (let i = 0; i < allModules.length; i++) {
|
||||
if (allModules[i].find((x) => x.letra === info.letra)) return i
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
function buildExercises(): Exercise[] {
|
||||
const all: Exercise[] = []
|
||||
let prevId: string | null = 'lec4-r-completa'
|
||||
|
||||
for (const pool of allModules) {
|
||||
for (const info of pool) {
|
||||
const MIN = info.letra.toLowerCase()
|
||||
const dist = getDistractors(pool, info, 3)
|
||||
|
||||
// 1. Descubrimiento del par
|
||||
all.push({
|
||||
id: `lec5-${MIN}-descubre`,
|
||||
stage: 5,
|
||||
skillCode: `puente-${MIN}`,
|
||||
type: 'sensibilizacion',
|
||||
prerequisites: prevId ? [prevId] : [],
|
||||
content: {
|
||||
instruction: `${info.letra} y ${MIN} suenan igual`,
|
||||
audioText: `${info.letra} grande y ${MIN} chica suenan igual: ${gestoKey(info.gesto)}`,
|
||||
emoji: info.emoji,
|
||||
},
|
||||
functionalContext: `Descubrir que ${info.letra} y ${MIN} son la misma letra.`,
|
||||
})
|
||||
prevId = `lec5-${MIN}-descubre`
|
||||
|
||||
// 2. Práctica emparejada: Tocá Mm
|
||||
const pairOptions = [
|
||||
{ label: `${info.letra}${MIN}`, correct: true, id: MIN },
|
||||
...dist.map((d) => ({
|
||||
label: `${d.letra}${d.letra.toLowerCase()}`,
|
||||
correct: false,
|
||||
id: d.letra.toLowerCase(),
|
||||
})),
|
||||
].sort(() => Math.random() - 0.5)
|
||||
|
||||
all.push({
|
||||
id: `lec5-${MIN}-pareja`,
|
||||
stage: 5,
|
||||
skillCode: `puente-${MIN}`,
|
||||
type: 'eleccion',
|
||||
prerequisites: [prevId],
|
||||
content: {
|
||||
instruction: `Tocá la ${info.letra}${MIN}`,
|
||||
audioText: `¿Dónde está ${info.letra}${MIN}?`,
|
||||
options: pairOptions,
|
||||
emoji: info.emoji,
|
||||
},
|
||||
functionalContext: `Asociar el par ${info.letra}${MIN}.`,
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
prevId = `lec5-${MIN}-pareja`
|
||||
|
||||
// 3. Buscar mayúscula entre minúsculas: Tocá la M
|
||||
const mayusOptions = [
|
||||
{ label: info.letra, correct: true, id: MIN },
|
||||
...dist.map((d) => ({
|
||||
label: d.letra.toLowerCase(),
|
||||
correct: false,
|
||||
id: `${d.letra.toLowerCase()}-may`,
|
||||
})),
|
||||
].sort(() => Math.random() - 0.5)
|
||||
|
||||
all.push({
|
||||
id: `lec5-${MIN}-busca-mayus`,
|
||||
stage: 5,
|
||||
skillCode: `puente-${MIN}`,
|
||||
type: 'eleccion',
|
||||
prerequisites: [prevId],
|
||||
content: {
|
||||
instruction: `Tocá la ${info.letra} grande`,
|
||||
audioText: `¿Dónde está la ${info.letra} grande?`,
|
||||
options: mayusOptions,
|
||||
emoji: info.emoji,
|
||||
},
|
||||
functionalContext: `Reconocer ${info.letra} mayúscula entre minúsculas.`,
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
prevId = `lec5-${MIN}-busca-mayus`
|
||||
|
||||
// 4. Buscar minúscula entre mayúsculas: Tocá la m (CLAVE)
|
||||
const minusOptions = [
|
||||
{ label: MIN, correct: true, id: MIN },
|
||||
...dist.map((d) => ({
|
||||
label: d.letra,
|
||||
correct: false,
|
||||
id: `${d.letra.toLowerCase()}-min`,
|
||||
})),
|
||||
].sort(() => Math.random() - 0.5)
|
||||
|
||||
all.push({
|
||||
id: `lec5-${MIN}-busca-minus`,
|
||||
stage: 5,
|
||||
skillCode: `puente-${MIN}`,
|
||||
type: 'eleccion',
|
||||
prerequisites: [prevId],
|
||||
content: {
|
||||
instruction: `Tocá la ${MIN} chica`,
|
||||
audioText: `¿Dónde está la ${MIN} chica?`,
|
||||
options: minusOptions,
|
||||
emoji: info.emoji,
|
||||
},
|
||||
functionalContext: `Reconocer ${MIN} minúscula entre mayúsculas — discriminación clave para dislexia.`,
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
prevId = `lec5-${MIN}-busca-minus`
|
||||
|
||||
// 5. Pareja inversa: ¿Cuál es la pareja de M? → m
|
||||
const parejaMayusOptions = [
|
||||
{ label: MIN, correct: true, id: `${MIN}-pm` },
|
||||
...dist.map((d) => ({
|
||||
label: d.letra.toLowerCase(),
|
||||
correct: false,
|
||||
id: `${d.letra.toLowerCase()}-pm`,
|
||||
})),
|
||||
].sort(() => Math.random() - 0.5)
|
||||
|
||||
all.push({
|
||||
id: `lec5-${MIN}-pareja-mayus`,
|
||||
stage: 5,
|
||||
skillCode: `puente-${MIN}`,
|
||||
type: 'eleccion',
|
||||
prerequisites: [prevId],
|
||||
content: {
|
||||
instruction: `¿Cuál es la pareja de ${info.letra}?`,
|
||||
audioText: `Buscá la ${MIN} chica, pareja de la ${info.letra} grande`,
|
||||
options: parejaMayusOptions,
|
||||
emoji: info.emoji,
|
||||
},
|
||||
functionalContext: `Asociar la mayúscula ${info.letra} con su minúscula ${MIN}.`,
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
prevId = `lec5-${MIN}-pareja-mayus`
|
||||
|
||||
// 6. Pareja inversa 2: ¿Cuál es la pareja de m? → M
|
||||
const parejaMinusOptions = [
|
||||
{ label: info.letra, correct: true, id: `${MIN}-pm2` },
|
||||
...dist.map((d) => ({
|
||||
label: d.letra,
|
||||
correct: false,
|
||||
id: `${d.letra.toLowerCase()}-pm2`,
|
||||
})),
|
||||
].sort(() => Math.random() - 0.5)
|
||||
|
||||
all.push({
|
||||
id: `lec5-${MIN}-pareja-minus`,
|
||||
stage: 5,
|
||||
skillCode: `puente-${MIN}`,
|
||||
type: 'eleccion',
|
||||
prerequisites: [prevId],
|
||||
content: {
|
||||
instruction: `¿Cuál es la pareja de ${MIN}?`,
|
||||
audioText: `Buscá la ${info.letra} grande, pareja de la ${MIN} chica`,
|
||||
options: parejaMinusOptions,
|
||||
emoji: info.emoji,
|
||||
},
|
||||
functionalContext: `Asociar la minúscula ${MIN} con su mayúscula ${info.letra}.`,
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
prevId = `lec5-${MIN}-pareja-minus`
|
||||
|
||||
// 7. Sílabas en minúscula: Tocá ma
|
||||
const silabaOptions = [
|
||||
{ label: info.silaba, correct: true, id: `${MIN}-sil` },
|
||||
...dist.map((d) => ({
|
||||
label: d.silaba,
|
||||
correct: false,
|
||||
id: `${d.letra.toLowerCase()}-sil`,
|
||||
})),
|
||||
].sort(() => Math.random() - 0.5)
|
||||
|
||||
all.push({
|
||||
id: `lec5-${MIN}-silaba`,
|
||||
stage: 5,
|
||||
skillCode: `puente-${MIN}`,
|
||||
type: 'eleccion',
|
||||
prerequisites: [prevId],
|
||||
content: {
|
||||
instruction: `Tocá ${info.silaba}`,
|
||||
audioText: `¿Dónde está ${info.silaba}?`,
|
||||
options: silabaOptions,
|
||||
emoji: info.emoji,
|
||||
},
|
||||
functionalContext: `Leer la sílaba ${info.silaba} en minúscula.`,
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
prevId = `lec5-${MIN}-silaba`
|
||||
|
||||
// 8. Palabra en minúscula: Tocá mamá
|
||||
const palabraOptions = [
|
||||
{ label: info.palabraLower, correct: true, id: `${MIN}-pal` },
|
||||
...dist.map((d) => ({
|
||||
label: d.palabraLower,
|
||||
correct: false,
|
||||
id: `${d.letra.toLowerCase()}-pal`,
|
||||
})),
|
||||
].sort(() => Math.random() - 0.5)
|
||||
|
||||
all.push({
|
||||
id: `lec5-${MIN}-palabra`,
|
||||
stage: 5,
|
||||
skillCode: `puente-${MIN}`,
|
||||
type: 'eleccion',
|
||||
prerequisites: [prevId],
|
||||
content: {
|
||||
instruction: `Tocá ${info.palabraLower}`,
|
||||
audioText: `¿Dónde dice ${info.palabraLower}?`,
|
||||
options: palabraOptions,
|
||||
emoji: info.emoji,
|
||||
},
|
||||
functionalContext: `Leer la palabra ${info.palabraLower} en minúscula.`,
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
prevId = `lec5-${MIN}-palabra`
|
||||
}
|
||||
}
|
||||
|
||||
return all
|
||||
}
|
||||
|
||||
function gestoKey(gesto: string): string {
|
||||
const map: Record<string, string> = {
|
||||
'Abrí': 'a-a-a',
|
||||
'Estirá': 'e-e-e',
|
||||
'Señalá el cielo': 'i-i-i',
|
||||
'Redondeá': 'o-o-o',
|
||||
'Señalá el suelo': 'u-u-u',
|
||||
'Manos en la boca': 'mmm',
|
||||
'Manos que abren': 'p-p-p',
|
||||
'Dedos como serpiente': 'sss',
|
||||
'Lengua arriba': 'l-l-l',
|
||||
'Golpecito': 't-t-t',
|
||||
'Nariz como nido': 'n-n-n',
|
||||
'Dedo señalando': 'd-d-d',
|
||||
'Lengua que vibra': 'rrr',
|
||||
}
|
||||
const key = Object.keys(map).find((k) => gesto.startsWith(k))
|
||||
return key ? map[key] : gesto
|
||||
}
|
||||
|
||||
const stage: Stage = {
|
||||
id: 5,
|
||||
name: 'Puente Mayúscula-Minúscula',
|
||||
description: 'Asociar letras mayúsculas con sus correspondientes minúsculas. 8 ejercicios por letra — 104 en total.',
|
||||
exercises: buildExercises(),
|
||||
}
|
||||
|
||||
export default stage
|
||||
@@ -0,0 +1,119 @@
|
||||
import type { Stage } from '../types'
|
||||
|
||||
const palabras2silabas = [
|
||||
{ palabra: 'MAPA', silabas: ['MA', 'PA'], emoji: '🗺️' },
|
||||
{ palabra: 'PASA', silabas: ['PA', 'SA'], emoji: '🔄' },
|
||||
{ palabra: 'SALA', silabas: ['SA', 'LA'], emoji: '🏠' },
|
||||
{ palabra: 'TAPA', silabas: ['TA', 'PA'], emoji: '📦' },
|
||||
{ palabra: 'LATA', silabas: ['LA', 'TA'], emoji: '🥫' },
|
||||
{ palabra: 'NIDO', silabas: ['NI', 'DO'], emoji: '🪺' },
|
||||
{ palabra: 'DEDO', silabas: ['DE', 'DO'], emoji: '👉' },
|
||||
{ palabra: 'RATO', silabas: ['RA', 'TO'], emoji: '⏰' },
|
||||
{ palabra: 'MESA', silabas: ['ME', 'SA'], emoji: '🪑' },
|
||||
{ palabra: 'PATO', silabas: ['PA', 'TO'], emoji: '🦆' },
|
||||
{ palabra: 'LIMA', silabas: ['LI', 'MA'], emoji: '🍋' },
|
||||
{ palabra: 'SOPA', silabas: ['SO', 'PA'], emoji: '🥣' },
|
||||
{ palabra: 'TINA', silabas: ['TI', 'NA'], emoji: '🛁' },
|
||||
{ palabra: 'MONO', silabas: ['MO', 'NO'], emoji: '🐵' },
|
||||
{ palabra: 'PINO', silabas: ['PI', 'NO'], emoji: '🌲' },
|
||||
{ palabra: 'LUNES', silabas: ['LU', 'NES'], emoji: '📅' },
|
||||
{ palabra: 'SAPO', silabas: ['SA', 'PO'], emoji: '🐸' },
|
||||
{ palabra: 'TELO', silabas: ['TE', 'LO'], emoji: '🧶' },
|
||||
{ palabra: 'DAMA', silabas: ['DA', 'MA'], emoji: '👩' },
|
||||
{ palabra: 'RAMA', silabas: ['RA', 'MA'], emoji: '🌿' },
|
||||
]
|
||||
|
||||
const exercises: any[] = []
|
||||
|
||||
for (const { palabra, silabas, emoji } of palabras2silabas) {
|
||||
const lowerPalabra = palabra.toLowerCase().replace(/[^a-z]/g, '')
|
||||
const id = `lec6-palabra-${lowerPalabra}`
|
||||
const letras = palabra.split('')
|
||||
const conLetras = letras[0]?.toLowerCase()
|
||||
const consonantDep = conLetras && ['m', 'p', 'l', 's', 't', 'n', 'd', 'r'].includes(conLetras)
|
||||
? `lec4-${conLetras}-completa`
|
||||
: 'lec3-u-completa'
|
||||
|
||||
// Leer la palabra (ver las sílabas separadas)
|
||||
exercises.push({
|
||||
id: `${id}-leer`,
|
||||
stage: 6,
|
||||
skillCode: `silabas-${lowerPalabra}`,
|
||||
type: 'eleccion',
|
||||
prerequisites: [consonantDep],
|
||||
content: {
|
||||
instruction: `Leé esta palabra: ${silabas.join('-')}`,
|
||||
text: `${silabas.join(' ')}`,
|
||||
audioText: `${palabra}: ${silabas.join(', ')}`,
|
||||
emoji,
|
||||
options: [
|
||||
{ label: palabra, correct: true, id: lowerPalabra },
|
||||
...palabras2silabas
|
||||
.filter(p => p.palabra !== palabra)
|
||||
.slice(0, 2)
|
||||
.map(p => ({ label: p.palabra, correct: false, id: p.palabra.toLowerCase() })),
|
||||
],
|
||||
},
|
||||
functionalContext: `Leer la palabra ${palabra} combinando sílabas.`,
|
||||
errorType: 'silaba-dificil',
|
||||
})
|
||||
|
||||
// Emparejar con imagen
|
||||
exercises.push({
|
||||
id: `${id}-imagen`,
|
||||
stage: 6,
|
||||
skillCode: `silabas-${lowerPalabra}`,
|
||||
type: 'palabra',
|
||||
prerequisites: [`${id}-leer`],
|
||||
content: {
|
||||
instruction: `¿Cuál palabra es esta?`,
|
||||
imageEmoji: emoji,
|
||||
audioText: `¿Qué palabra es?`,
|
||||
options: [
|
||||
...palabras2silabas
|
||||
.filter(p => p.palabra !== palabra)
|
||||
.slice(0, 2)
|
||||
.map(p => ({ label: p.palabra, correct: false, id: p.palabra.toLowerCase() })),
|
||||
{ label: palabra, correct: true, id: lowerPalabra },
|
||||
{ label: 'Escuchar 👂', correct: false, id: 'escuchar' },
|
||||
],
|
||||
},
|
||||
functionalContext: `Asociar la palabra ${palabra} con su imagen.`,
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
}
|
||||
|
||||
// Silaba order exercises
|
||||
const secuencias = [
|
||||
{ palabra: 'MAPA', silabas: ['PA', 'MA'], emoji: '🗺️' },
|
||||
{ palabra: 'PATO', silabas: ['TO', 'PA'], emoji: '🦆' },
|
||||
{ palabra: 'SAPO', silabas: ['PO', 'SA'], emoji: '🐸' },
|
||||
]
|
||||
|
||||
for (const { palabra, silabas, emoji } of secuencias) {
|
||||
const lower = palabra.toLowerCase()
|
||||
exercises.push({
|
||||
id: `lec6-ordenar-${lower}`,
|
||||
stage: 6,
|
||||
skillCode: `silabas-orden-${lower}`,
|
||||
type: 'secuencia',
|
||||
prerequisites: [`lec6-palabra-${lower}-leer`],
|
||||
content: {
|
||||
instruction: `Ordená las sílabas para formar ${palabra}`,
|
||||
audioText: `Ordená para formar ${palabra}`,
|
||||
sequence: silabas,
|
||||
emoji,
|
||||
},
|
||||
functionalContext: `Ordenar sílabas para formar ${palabra}.`,
|
||||
errorType: 'inversion-letra',
|
||||
})
|
||||
}
|
||||
|
||||
const stage: Stage = {
|
||||
id: 6,
|
||||
name: 'Sílabas y palabras de 2 sílabas',
|
||||
description: 'Combinar consonantes + vocales para formar y leer palabras de 2 sílabas.',
|
||||
exercises,
|
||||
}
|
||||
|
||||
export default stage
|
||||
@@ -0,0 +1,109 @@
|
||||
import type { Stage } from '../types'
|
||||
|
||||
const palabras3silabas = [
|
||||
{ palabra: 'MALETA', silabas: ['MA', 'LE', 'TA'], emoji: '🧳' },
|
||||
{ palabra: 'PALETA', silabas: ['PA', 'LE', 'TA'], emoji: '🎨' },
|
||||
{ palabra: 'SALIDA', silabas: ['SA', 'LI', 'DA'], emoji: '🚪' },
|
||||
{ palabra: 'TELÉFONO', silabas: ['TE', 'LÉ', 'FO', 'NO'], emoji: '📞' },
|
||||
{ palabra: 'MARIPOSA', silabas: ['MA', 'RI', 'PO', 'SA'], emoji: '🦋' },
|
||||
{ palabra: 'MUSICA', silabas: ['MU', 'SI', 'CA'], emoji: '🎵' },
|
||||
{ palabra: 'PLATO', silabas: ['PLA', 'TO'], emoji: '🍽️' },
|
||||
{ palabra: 'TRISTE', silabas: ['TRIS', 'TE'], emoji: '😢' },
|
||||
{ palabra: 'PLUMA', silabas: ['PLU', 'MA'], emoji: '🪶' },
|
||||
{ palabra: 'PANTALLA', silabas: ['PAN', 'TA', 'LLA'], emoji: '📺' },
|
||||
{ palabra: 'PRIMAVERA', silabas: ['PRI', 'MA', 'VE', 'RA'], emoji: '🌸' },
|
||||
{ palabra: 'MELÓN', silabas: ['ME', 'LÓN'], emoji: '🍈' },
|
||||
{ palabra: 'SILLA', silabas: ['SI', 'LLA'], emoji: '🪑' },
|
||||
{ palabra: 'TORTUGA', silabas: ['TOR', 'TU', 'GA'], emoji: '🐢' },
|
||||
{ palabra: 'DORMIR', silabas: ['DOR', 'MIR'], emoji: '😴' },
|
||||
{ palabra: 'RATÓN', silabas: ['RA', 'TÓN'], emoji: '🐭' },
|
||||
{ palabra: 'NARIZ', silabas: ['NA', 'RIZ'], emoji: '👃' },
|
||||
{ palabra: 'LÁPIZ', silabas: ['LÁ', 'PIZ'], emoji: '✏️' },
|
||||
{ palabra: 'DINOSAURIO', silabas: ['DI', 'NO', 'SAU', 'RIO'], emoji: '🦕' },
|
||||
{ palabra: 'ELEFANTE', silabas: ['E', 'LE', 'FAN', 'TE'], emoji: '🐘' },
|
||||
]
|
||||
|
||||
const exercises: any[] = []
|
||||
|
||||
for (const { palabra, silabas, emoji } of palabras3silabas) {
|
||||
const lowerPalabra = palabra.toLowerCase().replace(/[^a-záéíóú]/g, '')
|
||||
|
||||
// Read the word
|
||||
exercises.push({
|
||||
id: `lec7-${lowerPalabra}-leer`,
|
||||
stage: 7,
|
||||
skillCode: `palabra-${lowerPalabra}`,
|
||||
type: 'eleccion',
|
||||
prerequisites: ['lec6-palabra-mapa-leer'],
|
||||
content: {
|
||||
instruction: `Leé esta palabra: ${palabra}`,
|
||||
text: palabra,
|
||||
audioText: `${palabra}`,
|
||||
emoji,
|
||||
options: [
|
||||
{ label: palabra, correct: true, id: lowerPalabra },
|
||||
...palabras3silabas
|
||||
.filter(p => p.palabra !== palabra)
|
||||
.slice(0, 2)
|
||||
.map(p => ({ label: p.palabra, correct: false, id: p.palabra.toLowerCase().replace(/[^a-záéíóú]/g, '') })),
|
||||
],
|
||||
},
|
||||
functionalContext: `Leer la palabra ${palabra}.`,
|
||||
errorType: 'silaba-dificil',
|
||||
})
|
||||
|
||||
// Count syllables
|
||||
exercises.push({
|
||||
id: `lec7-${lowerPalabra}-silabas`,
|
||||
stage: 7,
|
||||
skillCode: `palabra-${lowerPalabra}`,
|
||||
type: 'conciencia',
|
||||
prerequisites: [`lec7-${lowerPalabra}-leer`],
|
||||
content: {
|
||||
instruction: `¿Cuántas sílabas tiene ${palabra}?`,
|
||||
text: palabra,
|
||||
audioText: `¿Cuántas sílabas?`,
|
||||
options: [
|
||||
{ label: `${'👏'.repeat(silabas.length)} ${silabas.length}`, correct: true, id: `${silabas.length}` },
|
||||
{ label: `${'👏'.repeat(Math.max(1, silabas.length - 1))} ${silabas.length - 1}`, correct: false, id: `${silabas.length - 1}` },
|
||||
{ label: `${'👏'.repeat(silabas.length + 1)} ${silabas.length + 1}`, correct: false, id: `${silabas.length + 1}` },
|
||||
],
|
||||
emoji,
|
||||
},
|
||||
functionalContext: `Contar sílabas en ${palabra}.`,
|
||||
errorType: 'discriminacion-auditiva',
|
||||
})
|
||||
|
||||
// Match image
|
||||
exercises.push({
|
||||
id: `lec7-${lowerPalabra}-imagen`,
|
||||
stage: 7,
|
||||
skillCode: `palabra-${lowerPalabra}`,
|
||||
type: 'palabra',
|
||||
prerequisites: [`lec7-${lowerPalabra}-silabas`],
|
||||
content: {
|
||||
instruction: `¿Qué palabra es?`,
|
||||
imageEmoji: emoji,
|
||||
audioText: `¿Cuál es?`,
|
||||
options: [
|
||||
...palabras3silabas
|
||||
.filter(p => p.palabra !== palabra)
|
||||
.slice(0, 2)
|
||||
.map(p => ({ label: p.palabra, correct: false, id: p.palabra.toLowerCase().replace(/[^a-záéíóú]/g, '') })),
|
||||
{ label: palabra, correct: true, id: lowerPalabra },
|
||||
{ label: 'Escuchar 👂', correct: false, id: 'escuchar' },
|
||||
],
|
||||
},
|
||||
functionalContext: `Asociar la palabra ${palabra} con su imagen.`,
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
}
|
||||
|
||||
const stage: Stage = {
|
||||
id: 7,
|
||||
name: 'Palabras de 3+ sílabas',
|
||||
description: 'Leer y comprender palabras de 3 o más sílabas con sílabas compuestas.',
|
||||
exercises,
|
||||
}
|
||||
|
||||
export default stage
|
||||
@@ -0,0 +1,147 @@
|
||||
import type { Stage } from '../types'
|
||||
|
||||
const frases = [
|
||||
{
|
||||
frase: 'Mi mamá me ama.',
|
||||
opciones: ['Mi papá me ama.', 'Mi mamá me ama.', 'Mi mamá me mima.'],
|
||||
correcta: 'Mi mamá me ama.',
|
||||
emoji: '💕',
|
||||
},
|
||||
{
|
||||
frase: 'El sol sale temprano.',
|
||||
opciones: ['La luna sale tarde.', 'El sol sale temprano.', 'El sol se esconde.'],
|
||||
correcta: 'El sol sale temprano.',
|
||||
emoji: '☀️',
|
||||
},
|
||||
{
|
||||
frase: 'La luna está en el cielo.',
|
||||
opciones: ['El sol está en el mar.', 'La luna está en el cielo.', 'La luna es redonda.'],
|
||||
correcta: 'La luna está en el cielo.',
|
||||
emoji: '🌙',
|
||||
},
|
||||
{
|
||||
frase: 'El pato nada en el lago.',
|
||||
opciones: ['El pato vuela alto.', 'El pato nada en el lago.', 'El gato nada en el lago.'],
|
||||
correcta: 'El pato nada en el lago.',
|
||||
emoji: '🦆',
|
||||
},
|
||||
{
|
||||
frase: 'Mi gato es muy lindo.',
|
||||
opciones: ['Mi perro es grande.', 'Mi gato es muy lindo.', 'Mi gato salta alto.'],
|
||||
correcta: 'Mi gato es muy lindo.',
|
||||
emoji: '🐱',
|
||||
},
|
||||
{
|
||||
frase: 'La mariposa vuela entre las flores.',
|
||||
opciones: ['La mariposa está dormida.', 'La mariposa vuela entre las flores.', 'La abeja hace miel.'],
|
||||
correcta: 'La mariposa vuela entre las flores.',
|
||||
emoji: '🦋',
|
||||
},
|
||||
{
|
||||
frase: 'Tomo leche con galletitas.',
|
||||
opciones: ['Tomo agua con hielo.', 'Tomo leche con galletitas.', 'Como sopa caliente.'],
|
||||
correcta: 'Tomo leche con galletitas.',
|
||||
emoji: '🥛',
|
||||
},
|
||||
{
|
||||
frase: 'El perro corre en el parque.',
|
||||
opciones: ['El perro duerme en casa.', 'El perro corre en el parque.', 'El gato corre en el parque.'],
|
||||
correcta: 'El perro corre en el parque.',
|
||||
emoji: '🐕',
|
||||
},
|
||||
{
|
||||
frase: 'Mi hermana tiene un lápiz rojo.',
|
||||
opciones: ['Mi mamá tiene una mesa.', 'Mi hermana tiene un lápiz rojo.', 'Mi hermana tiene un libro.'],
|
||||
correcta: 'Mi hermana tiene un lápiz rojo.',
|
||||
emoji: '✏️',
|
||||
},
|
||||
{
|
||||
frase: 'La tortuga camina despacio.',
|
||||
opciones: ['La liebre salta rápido.', 'La tortuga camina despacio.', 'El pez nada veloz.'],
|
||||
correcta: 'La tortuga camina despacio.',
|
||||
emoji: '🐢',
|
||||
},
|
||||
{
|
||||
frase: 'El elefante es muy grande.',
|
||||
opciones: ['El ratón es chiquito.', 'El elefante es muy grande.', 'El perro es mediano.'],
|
||||
correcta: 'El elefante es muy grande.',
|
||||
emoji: '🐘',
|
||||
},
|
||||
{
|
||||
frase: 'Me gusta pintar con mis dedos.',
|
||||
opciones: ['Me gusta cantar canciones.', 'Me gusta pintar con mis dedos.', 'Me gusta mirar tele.'],
|
||||
correcta: 'Me gusta pintar con mis dedos.',
|
||||
emoji: '🎨',
|
||||
},
|
||||
{
|
||||
frase: 'El sol es amarillo.',
|
||||
opciones: ['La luna es blanca.', 'El sol es amarillo.', 'El cielo es azul.'],
|
||||
correcta: 'El sol es amarillo.',
|
||||
emoji: '🟡',
|
||||
},
|
||||
{
|
||||
frase: 'Mi papá me lee un cuento.',
|
||||
opciones: ['Mi mamá me canta.', 'Mi papá me lee un cuento.', 'Mi papá cocina rico.'],
|
||||
correcta: 'Mi papá me lee un cuento.',
|
||||
emoji: '📖',
|
||||
},
|
||||
{
|
||||
frase: 'La mesa está en la sala.',
|
||||
opciones: ['La silla está en la cocina.', 'La mesa está en la sala.', 'La cama está en mi pieza.'],
|
||||
correcta: 'La mesa está en la sala.',
|
||||
emoji: '🪑',
|
||||
},
|
||||
]
|
||||
|
||||
const exercises: any[] = []
|
||||
|
||||
for (const { frase, opciones, correcta, emoji } of frases) {
|
||||
const id = `lec8-${frase.toLowerCase().replace(/[^a-záéíóú]/g, '').slice(0, 20)}`
|
||||
|
||||
exercises.push({
|
||||
id: `${id}-leer`,
|
||||
stage: 8,
|
||||
skillCode: 'frases',
|
||||
type: 'lectura',
|
||||
prerequisites: ['lec7-maleta-leer'],
|
||||
content: {
|
||||
instruction: 'Leé esta oración en voz alta',
|
||||
text: frase,
|
||||
audioText: frase,
|
||||
emoji,
|
||||
options: [
|
||||
{ label: '¡Leída!', correct: true, id: 'leida' },
|
||||
],
|
||||
},
|
||||
functionalContext: 'Leer oraciones simples.',
|
||||
})
|
||||
|
||||
exercises.push({
|
||||
id: `${id}-comprender`,
|
||||
stage: 8,
|
||||
skillCode: 'frases',
|
||||
type: 'lectura',
|
||||
prerequisites: [`${id}-leer`],
|
||||
content: {
|
||||
instruction: `¿Cuál oración es la correcta?`,
|
||||
emoji,
|
||||
audioText: `¿Cuál es correcta?`,
|
||||
options: opciones.map(o => ({
|
||||
label: o,
|
||||
correct: o === correcta,
|
||||
id: o.toLowerCase().replace(/[^a-záéíóú]/g, '').slice(0, 15),
|
||||
})),
|
||||
},
|
||||
functionalContext: 'Comprender la oración leída.',
|
||||
errorType: 'omision-letra',
|
||||
})
|
||||
}
|
||||
|
||||
const stage: Stage = {
|
||||
id: 8,
|
||||
name: 'Frases y oraciones',
|
||||
description: 'Leer oraciones simples y comprender su significado.',
|
||||
exercises,
|
||||
}
|
||||
|
||||
export default stage
|
||||
@@ -0,0 +1,176 @@
|
||||
import type { Stage } from '../types'
|
||||
|
||||
const lecturas = [
|
||||
{
|
||||
texto: 'El sol sale por la mañana. Las flores se abren. Los pájaros cantan. Es un lindo día.',
|
||||
pregunta: '¿Qué pasa por la mañana?',
|
||||
opciones: [
|
||||
{ label: 'La luna sale', correct: false },
|
||||
{ label: 'El sol sale', correct: true },
|
||||
{ label: 'Las estrellas brillan', correct: false },
|
||||
],
|
||||
emoji: '🌄',
|
||||
},
|
||||
{
|
||||
texto: 'Mamá prepara la mesa. Papá sirve la sopa. Todos comen juntos. Después lavan los platos.',
|
||||
pregunta: '¿Qué hace papá?',
|
||||
opciones: [
|
||||
{ label: 'Lava los platos', correct: false },
|
||||
{ label: 'Prepara la mesa', correct: false },
|
||||
{ label: 'Sirve la sopa', correct: true },
|
||||
],
|
||||
emoji: '🍲',
|
||||
},
|
||||
{
|
||||
texto: 'El gato de mi casa es negro. Le gusta dormir al sol. Por la noche sale a pasear.',
|
||||
pregunta: '¿De qué color es el gato?',
|
||||
opciones: [
|
||||
{ label: 'Blanco', correct: false },
|
||||
{ label: 'Negro', correct: true },
|
||||
{ label: 'Gris', correct: false },
|
||||
],
|
||||
emoji: '🐈⬛',
|
||||
},
|
||||
{
|
||||
texto: 'La nena juega en el parque. Sube al tobogán. Baja rápido y se ríe. Después juega en la arena.',
|
||||
pregunta: '¿Dónde juega la nena?',
|
||||
opciones: [
|
||||
{ label: 'En su casa', correct: false },
|
||||
{ label: 'En la escuela', correct: false },
|
||||
{ label: 'En el parque', correct: true },
|
||||
],
|
||||
emoji: '🛝',
|
||||
},
|
||||
{
|
||||
texto: 'En la granja hay vacas, ovejas y gallinas. Las vacas dan leche. Las gallinas ponen huevos.',
|
||||
pregunta: '¿Qué dan las vacas?',
|
||||
opciones: [
|
||||
{ label: 'Huevos', correct: false },
|
||||
{ label: 'Leche', correct: true },
|
||||
{ label: 'Lana', correct: false },
|
||||
],
|
||||
emoji: '🐄',
|
||||
},
|
||||
{
|
||||
texto: 'Luna tiene cuatro patas, dos orejas largas y una cola corta. Come zanahorias. Es una coneja.',
|
||||
pregunta: '¿Qué es Luna?',
|
||||
opciones: [
|
||||
{ label: 'Un perro', correct: false },
|
||||
{ label: 'Un gato', correct: false },
|
||||
{ label: 'Una coneja', correct: true },
|
||||
],
|
||||
emoji: '🐰',
|
||||
},
|
||||
{
|
||||
texto: 'El libro de cuentos tiene dibujos lindos. La nena lo mira todas las noches. Su mamá le lee antes de dormir.',
|
||||
pregunta: '¿Cuándo lee mamá?',
|
||||
opciones: [
|
||||
{ label: 'Por la mañana', correct: false },
|
||||
{ label: 'Antes de dormir', correct: true },
|
||||
{ label: 'A la tarde', correct: false },
|
||||
],
|
||||
emoji: '📚',
|
||||
},
|
||||
{
|
||||
texto: 'La tortuga Tula vive en un estanque. Le gusta nadar y tomar sol en una piedra. Es muy tranquila.',
|
||||
pregunta: '¿Dónde vive Tula?',
|
||||
opciones: [
|
||||
{ label: 'En el mar', correct: false },
|
||||
{ label: 'En un estanque', correct: true },
|
||||
{ label: 'En una casa', correct: false },
|
||||
],
|
||||
emoji: '🐢',
|
||||
},
|
||||
{
|
||||
texto: 'Tomás tiene tres años. Juega con bloques de colores. Arma una torre muy alta. Después la derriba. ¡Plaf!',
|
||||
pregunta: '¿Qué arma Tomás?',
|
||||
opciones: [
|
||||
{ label: 'Un castillo', correct: false },
|
||||
{ label: 'Una torre', correct: true },
|
||||
{ label: 'Un puente', correct: false },
|
||||
],
|
||||
emoji: '🧱',
|
||||
},
|
||||
{
|
||||
texto: 'La abuela teje una bufanda roja para el invierno. Usa lana suave y dos agujas. La bufanda queda muy linda.',
|
||||
pregunta: '¿Qué teje la abuela?',
|
||||
opciones: [
|
||||
{ label: 'Un gorro', correct: false },
|
||||
{ label: 'Una bufanda', correct: true },
|
||||
{ label: 'Un guante', correct: false },
|
||||
],
|
||||
emoji: '🧣',
|
||||
},
|
||||
{
|
||||
texto: 'En la plaza hay un árbol grande. Tiene hojas verdes y flores rosadas. Los pájaros hacen nidos allí.',
|
||||
pregunta: '¿De qué color son las flores?',
|
||||
opciones: [
|
||||
{ label: 'Rosadas', correct: true },
|
||||
{ label: 'Amarillas', correct: false },
|
||||
{ label: 'Blancas', correct: false },
|
||||
],
|
||||
emoji: '🌳',
|
||||
},
|
||||
{
|
||||
texto: 'El niño se pone las botas de lluvia. Abre el paraguas azul. Salta en los charcos. ¡Qué divertido!',
|
||||
pregunta: '¿Qué se pone el niño?',
|
||||
opciones: [
|
||||
{ label: 'Un abrigo', correct: false },
|
||||
{ label: 'Botas de lluvia', correct: true },
|
||||
{ label: 'Un sombrero', correct: false },
|
||||
],
|
||||
emoji: '☂️',
|
||||
},
|
||||
]
|
||||
|
||||
const exercises: any[] = []
|
||||
|
||||
for (const { texto, pregunta, opciones, emoji } of lecturas) {
|
||||
const id = `lec9-${texto.toLowerCase().replace(/[^a-záéíóú]/g, '').slice(0, 15)}`
|
||||
|
||||
exercises.push({
|
||||
id: `${id}-texto`,
|
||||
stage: 9,
|
||||
skillCode: 'comprension',
|
||||
type: 'lectura',
|
||||
prerequisites: ['lec8-frase-mimamameama-leer'],
|
||||
content: {
|
||||
instruction: 'Leé este texto',
|
||||
text: texto,
|
||||
audioText: texto,
|
||||
emoji,
|
||||
options: [
|
||||
{ label: '¡Leído!', correct: true, id: 'leido' },
|
||||
],
|
||||
},
|
||||
functionalContext: 'Leer un texto corto.',
|
||||
})
|
||||
|
||||
exercises.push({
|
||||
id: `${id}-pregunta`,
|
||||
stage: 9,
|
||||
skillCode: 'comprension',
|
||||
type: 'lectura',
|
||||
prerequisites: [`${id}-texto`],
|
||||
content: {
|
||||
instruction: `Respondé: ${pregunta}`,
|
||||
text: texto,
|
||||
audioText: pregunta,
|
||||
emoji,
|
||||
options: [
|
||||
...opciones.map(o => ({ label: o.label, correct: o.correct, id: o.label.toLowerCase().replace(/[^a-záéíóú]/g, '') })),
|
||||
],
|
||||
},
|
||||
functionalContext: 'Comprender y responder preguntas sobre el texto.',
|
||||
errorType: 'omision-letra',
|
||||
})
|
||||
}
|
||||
|
||||
const stage: Stage = {
|
||||
id: 9,
|
||||
name: 'Comprensión lectora',
|
||||
description: 'Leer textos cortos y responder preguntas de comprensión.',
|
||||
exercises,
|
||||
}
|
||||
|
||||
export default stage
|
||||
@@ -0,0 +1,82 @@
|
||||
import type { Stage } from '../types'
|
||||
|
||||
const exercises: any[] = []
|
||||
|
||||
// Count 1-5
|
||||
for (let n = 1; n <= 5; n++) {
|
||||
const emojis = '⭐'.repeat(n)
|
||||
exercises.push({
|
||||
id: `num1-contar-${n}`,
|
||||
stage: 1,
|
||||
skillCode: `contar-${n}`,
|
||||
type: 'sensibilizacion',
|
||||
prerequisites: n === 1 ? [] : [`num1-contar-${n - 1}`],
|
||||
content: {
|
||||
instruction: `Contá. ¿Cuántas estrellas hay?`,
|
||||
audioText: `Uno, dos, tres...`,
|
||||
emoji: emojis,
|
||||
options: [
|
||||
...Array.from({ length: 5 }, (_, i) => i + 1)
|
||||
.filter(j => j !== n)
|
||||
.slice(0, 2)
|
||||
.map(j => ({ label: String(j), correct: false, id: String(j) })),
|
||||
{ label: String(n), correct: true, id: String(n) },
|
||||
].sort(() => Math.random() - 0.5),
|
||||
},
|
||||
functionalContext: `Contar hasta ${n} elementos.`,
|
||||
errorType: 'discriminacion-auditiva',
|
||||
})
|
||||
}
|
||||
|
||||
// Recognize written digits 1-5
|
||||
for (let n = 1; n <= 5; n++) {
|
||||
exercises.push({
|
||||
id: `num1-digito-${n}`,
|
||||
stage: 1,
|
||||
skillCode: `digito-${n}`,
|
||||
type: 'eleccion',
|
||||
prerequisites: [`num1-contar-${n}`],
|
||||
content: {
|
||||
instruction: `Señalá el número ${n}`,
|
||||
audioText: `Buscá el número ${n}`,
|
||||
options: [
|
||||
...Array.from({ length: 5 }, (_, i) => i + 1)
|
||||
.filter(j => j !== n)
|
||||
.slice(0, 2)
|
||||
.map(j => ({ label: String(j), correct: false, id: String(j) })),
|
||||
{ label: String(n), correct: true, id: String(n) },
|
||||
].sort(() => Math.random() - 0.5),
|
||||
emoji: String(n),
|
||||
},
|
||||
functionalContext: `Reconocer el dígito ${n}.`,
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
}
|
||||
|
||||
// Trace with finger
|
||||
for (let n = 1; n <= 5; n++) {
|
||||
exercises.push({
|
||||
id: `num1-trazo-${n}`,
|
||||
stage: 1,
|
||||
skillCode: `digito-${n}`,
|
||||
type: 'trazo',
|
||||
prerequisites: [`num1-digito-${n}`],
|
||||
content: {
|
||||
instruction: `Trazá el número ${n} con tu dedo`,
|
||||
text: String(n),
|
||||
audioText: `Trazá el número ${n}`,
|
||||
emoji: '✍️',
|
||||
},
|
||||
functionalContext: `Aprender a trazar el número ${n}.`,
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
}
|
||||
|
||||
const stage: Stage = {
|
||||
id: 1,
|
||||
name: 'Conteo del 1 al 5',
|
||||
description: 'Contar objetos, reconocer dígitos y trazar números del 1 al 5.',
|
||||
exercises,
|
||||
}
|
||||
|
||||
export default stage
|
||||
@@ -0,0 +1,99 @@
|
||||
import type { Stage } from '../types'
|
||||
|
||||
const exercises: any[] = []
|
||||
|
||||
// Count 6-10
|
||||
for (let n = 6; n <= 10; n++) {
|
||||
const emojis = '🟢'.repeat(n)
|
||||
exercises.push({
|
||||
id: `num2-contar-${n}`,
|
||||
stage: 2,
|
||||
skillCode: `contar-${n}`,
|
||||
prerequisites: n === 6 ? ['num1-trazo-5'] : [`num2-contar-${n - 1}`],
|
||||
type: 'sensibilizacion',
|
||||
content: {
|
||||
instruction: `¿Cuántos círculos verdes hay?`,
|
||||
audioText: `Contá los círculos`,
|
||||
emoji: emojis,
|
||||
options: [
|
||||
...Array.from({ length: 5 }, (_, i) => i + 6)
|
||||
.filter(j => j !== n)
|
||||
.slice(0, 2)
|
||||
.map(j => ({ label: String(j), correct: false, id: String(j) })),
|
||||
{ label: String(n), correct: true, id: String(n) },
|
||||
].sort(() => Math.random() - 0.5),
|
||||
},
|
||||
functionalContext: `Contar hasta ${n} elementos.`,
|
||||
errorType: 'discriminacion-auditiva',
|
||||
})
|
||||
}
|
||||
|
||||
// Recognize written digits 6-10
|
||||
for (let n = 6; n <= 10; n++) {
|
||||
exercises.push({
|
||||
id: `num2-digito-${n}`,
|
||||
stage: 2,
|
||||
skillCode: `digito-${n}`,
|
||||
type: 'eleccion',
|
||||
prerequisites: [`num2-contar-${n}`],
|
||||
content: {
|
||||
instruction: `Señalá el número ${n}`,
|
||||
audioText: `Buscá el ${n}`,
|
||||
options: [
|
||||
...Array.from({ length: 5 }, (_, i) => i + 6)
|
||||
.filter(j => j !== n)
|
||||
.slice(0, 2)
|
||||
.map(j => ({ label: String(j), correct: false, id: String(j) })),
|
||||
{ label: String(n), correct: true, id: String(n) },
|
||||
].sort(() => Math.random() - 0.5),
|
||||
emoji: String(n),
|
||||
},
|
||||
functionalContext: `Reconocer el dígito ${n}.`,
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
}
|
||||
|
||||
// Order sequence 1-10
|
||||
exercises.push({
|
||||
id: 'num2-secuencia-1-10',
|
||||
stage: 2,
|
||||
skillCode: 'secuencia-1-10',
|
||||
type: 'secuencia',
|
||||
prerequisites: ['num2-digito-10'],
|
||||
content: {
|
||||
instruction: 'Ordená los números del 1 al 10',
|
||||
audioText: 'Ordená del 1 al 10',
|
||||
sequence: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'],
|
||||
emoji: '🔢',
|
||||
},
|
||||
functionalContext: 'Conocer la secuencia numérica del 1 al 10.',
|
||||
errorType: 'inversion-letra',
|
||||
})
|
||||
|
||||
// Trace 6-10
|
||||
for (let n = 6; n <= 10; n++) {
|
||||
exercises.push({
|
||||
id: `num2-trazo-${n}`,
|
||||
stage: 2,
|
||||
skillCode: `digito-${n}`,
|
||||
type: 'trazo',
|
||||
prerequisites: [`num2-digito-${n}`, ...(n > 6 ? [`num2-trazo-${n - 1}`] : [])],
|
||||
content: {
|
||||
instruction: `Trazá el número ${n} con tu dedo`,
|
||||
text: String(n),
|
||||
audioText: `Trazá el ${n}`,
|
||||
emoji: '✍️',
|
||||
},
|
||||
functionalContext: `Aprender a trazar el número ${n}.`,
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
}
|
||||
|
||||
const stage: Stage = {
|
||||
id: 2,
|
||||
name: 'Conteo del 6 al 10',
|
||||
description: 'Contar objetos, reconocer dígitos y trazar números del 6 al 10, y ordenar del 1 al 10.',
|
||||
exercises,
|
||||
}
|
||||
|
||||
export default stage
|
||||
@@ -0,0 +1,107 @@
|
||||
import type { Stage } from '../types'
|
||||
|
||||
const exercises: any[] = []
|
||||
|
||||
// Pair number with quantity
|
||||
for (let n = 1; n <= 10; n++) {
|
||||
const emojis = ['🐶', '🐱', '🐰', '🐸', '🐵', '🐼', '🐨', '🦊', '🐻', '🐯']
|
||||
const animal = emojis[n - 1]
|
||||
const howMany = animal.repeat(Math.min(n, 5)) + (n > 5 ? ` (${n})` : '')
|
||||
|
||||
exercises.push({
|
||||
id: `num3-cantidad-${n}`,
|
||||
stage: 3,
|
||||
skillCode: `correspondencia-${n}`,
|
||||
type: 'conciencia',
|
||||
prerequisites: n === 1 ? ['num2-trazo-10'] : [`num3-cantidad-${n - 1}`],
|
||||
content: {
|
||||
instruction: `¿Cuántos ${animal} hay?`,
|
||||
audioText: `Contá los animalitos`,
|
||||
text: n <= 5 ? animal.repeat(n) : `${animal.repeat(5)}... +${n - 5}`,
|
||||
options: [
|
||||
...Array.from({ length: 10 }, (_, i) => i + 1)
|
||||
.filter(j => j !== n)
|
||||
.slice(0, 2)
|
||||
.map(j => ({ label: String(j), correct: false, id: String(j) })),
|
||||
{ label: String(n), correct: true, id: String(n) },
|
||||
].sort(() => Math.random() - 0.5),
|
||||
emoji: animal,
|
||||
},
|
||||
functionalContext: 'Asociar cantidad con número.',
|
||||
errorType: 'discriminacion-auditiva',
|
||||
})
|
||||
}
|
||||
|
||||
// Match groups that are equal
|
||||
const pares = [
|
||||
{ a: '🐶🐶🐶', b: '3️⃣', num: 3 },
|
||||
{ a: '🐱🐱🐱🐱', b: '4️⃣', num: 4 },
|
||||
{ a: '🐰🐰🐰🐰🐰', b: '5️⃣', num: 5 },
|
||||
{ a: '🐸🐸', b: '2️⃣', num: 2 },
|
||||
{ a: '🐵🐵🐵🐵🐵🐵', b: '6️⃣', num: 6 },
|
||||
]
|
||||
|
||||
for (const { a, b, num } of pares) {
|
||||
exercises.push({
|
||||
id: `num3-emparejar-${num}`,
|
||||
stage: 3,
|
||||
skillCode: 'correspondencia',
|
||||
type: 'conciencia',
|
||||
prerequisites: [`num3-cantidad-${num}`],
|
||||
content: {
|
||||
instruction: `¿Cuál número le corresponde a ${a}?`,
|
||||
audioText: `¿Qué número es?`,
|
||||
text: a,
|
||||
options: [
|
||||
...pares.filter(p => p.num !== num).slice(0, 2).map(p => ({ label: p.b, correct: false, id: String(p.num) })),
|
||||
{ label: b, correct: true, id: String(num) },
|
||||
].sort(() => Math.random() - 0.5),
|
||||
emoji: '🔄',
|
||||
},
|
||||
functionalContext: 'Emparejar grupos con su número.',
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
}
|
||||
|
||||
// More/less comparison
|
||||
const comparaciones = [
|
||||
{ a: 3, b: 5, mas: 5, menos: 3 },
|
||||
{ a: 2, b: 7, mas: 7, menos: 2 },
|
||||
{ a: 4, b: 4, mas: 4, menos: 4 },
|
||||
{ a: 6, b: 3, mas: 6, menos: 3 },
|
||||
{ a: 1, b: 9, mas: 9, menos: 1 },
|
||||
]
|
||||
|
||||
for (const { a, b, mas, menos } of comparaciones) {
|
||||
const idA = '⭐'.repeat(a)
|
||||
const idB = '⭐'.repeat(b)
|
||||
exercises.push({
|
||||
id: `num3-mas-${a}-${b}`,
|
||||
stage: 3,
|
||||
skillCode: 'comparacion',
|
||||
type: 'conciencia',
|
||||
prerequisites: [`num3-cantidad-${Math.max(a, b)}`],
|
||||
content: {
|
||||
instruction: `¿Dónde hay MÁS?`,
|
||||
text: `${idA} vs ${idB}`,
|
||||
audioText: `¿Cuál tiene más?`,
|
||||
options: [
|
||||
{ label: `👈 ${a}`, correct: mas === a, id: `izq-${a}` },
|
||||
{ label: `👉 ${b}`, correct: mas === b, id: `der-${b}` },
|
||||
{ label: '😐 Igual', correct: a === b, id: 'igual' },
|
||||
],
|
||||
emoji: '⚖️',
|
||||
},
|
||||
functionalContext: 'Comparar cantidades (más/menos).',
|
||||
errorType: 'discriminacion-auditiva',
|
||||
})
|
||||
}
|
||||
|
||||
const stage: Stage = {
|
||||
id: 3,
|
||||
name: 'Correspondencia uno a uno',
|
||||
description: 'Asociar cantidades con números, emparejar grupos iguales, comparar más y menos.',
|
||||
exercises,
|
||||
}
|
||||
|
||||
export default stage
|
||||
@@ -0,0 +1,83 @@
|
||||
import type { Stage } from '../types'
|
||||
|
||||
const exercises: any[] = []
|
||||
|
||||
for (let n = 11; n <= 20; n++) {
|
||||
exercises.push({
|
||||
id: `num4-contar-${n}`,
|
||||
stage: 4,
|
||||
skillCode: `contar-${n}`,
|
||||
type: 'conciencia',
|
||||
prerequisites: n === 11 ? ['num3-cantidad-10'] : [`num4-contar-${n - 1}`],
|
||||
content: {
|
||||
instruction: `Contá. ¿Cuántos hay? (${n})`,
|
||||
audioText: `Son ${n}`,
|
||||
text: `🔵🔵🔵🔵🔵 🟣🟣🟣🟣🟣 ${n > 10 ? `+${n - 10}` : ''}`,
|
||||
options: [
|
||||
...Array.from({ length: 5 }, (_, i) => n - 2 + i)
|
||||
.filter(j => j >= 10 && j <= 20 && j !== n)
|
||||
.slice(0, 2)
|
||||
.map(j => ({ label: String(j), correct: false, id: String(j) })),
|
||||
{ label: String(n), correct: true, id: String(n) },
|
||||
].sort(() => Math.random() - 0.5),
|
||||
emoji: String(n),
|
||||
},
|
||||
functionalContext: `Reconocer el número ${n}.`,
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
}
|
||||
|
||||
// Decenas y unidades visual
|
||||
for (let n = 10; n <= 20; n++) {
|
||||
const decenas = Math.floor(n / 10)
|
||||
const unidades = n % 10
|
||||
exercises.push({
|
||||
id: `num4-descomponer-${n}`,
|
||||
stage: 4,
|
||||
skillCode: 'decenas-unidades',
|
||||
type: 'eleccion',
|
||||
prerequisites: [`num4-contar-${n}`],
|
||||
content: {
|
||||
instruction: `${n} son ${decenas} decena${decenas > 1 ? 's' : ''} y ${unidades} unidades`,
|
||||
text: `🔟🔟${'●'.repeat(unidades)} = ${n}`,
|
||||
audioText: `${n} es ${decenas} decenas y ${unidades} unidades`,
|
||||
options: [
|
||||
{ label: '🔟 Decenas', correct: false, id: `decenas-${n}` },
|
||||
{ label: String(n), correct: true, id: String(n) },
|
||||
...Array.from({ length: 3 }, (_, i) => n + i - 1)
|
||||
.filter(j => j >= 10 && j <= 20 && j !== n)
|
||||
.slice(0, 1)
|
||||
.map(j => ({ label: String(j), correct: false, id: String(j) })),
|
||||
].sort(() => Math.random() - 0.5),
|
||||
emoji: '🔟',
|
||||
},
|
||||
functionalContext: 'Introducir decenas y unidades.',
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
}
|
||||
|
||||
// Secuencia 11-20
|
||||
exercises.push({
|
||||
id: 'num4-secuencia-11-20',
|
||||
stage: 4,
|
||||
skillCode: 'secuencia-11-20',
|
||||
type: 'secuencia',
|
||||
prerequisites: ['num4-descomponer-20'],
|
||||
content: {
|
||||
instruction: 'Ordená los números del 11 al 20',
|
||||
audioText: 'Ordená del 11 al 20',
|
||||
sequence: ['11', '12', '13', '14', '15', '16', '17', '18', '19', '20'],
|
||||
emoji: '🔢',
|
||||
},
|
||||
functionalContext: 'Conocer la secuencia del 11 al 20.',
|
||||
errorType: 'inversion-letra',
|
||||
})
|
||||
|
||||
const stage: Stage = {
|
||||
id: 4,
|
||||
name: 'Números del 11 al 20',
|
||||
description: 'Aprender los números del 11 al 20. Introducir decenas y unidades.',
|
||||
exercises,
|
||||
}
|
||||
|
||||
export default stage
|
||||
@@ -0,0 +1,90 @@
|
||||
import type { Stage } from '../types'
|
||||
|
||||
const sumas = [
|
||||
{ a: 1, b: 1, r: 2, emoji: '🐶+🐶' },
|
||||
{ a: 2, b: 1, r: 3, emoji: '🐱+🐶' },
|
||||
{ a: 2, b: 2, r: 4, emoji: '🐱+🐱' },
|
||||
{ a: 3, b: 1, r: 5, emoji: '🐰+🐶' },
|
||||
{ a: 3, b: 2, r: 5, emoji: '🐰+🐱' },
|
||||
{ a: 4, b: 1, r: 5, emoji: '🐸+🐶' },
|
||||
{ a: 5, b: 1, r: 6, emoji: '🐵+🐶' },
|
||||
{ a: 3, b: 3, r: 6, emoji: '🐰+🐰' },
|
||||
{ a: 5, b: 2, r: 7, emoji: '🐵+🐱' },
|
||||
{ a: 4, b: 3, r: 7, emoji: '🐸+🐰' },
|
||||
{ a: 5, b: 3, r: 8, emoji: '🐵+🐰' },
|
||||
{ a: 4, b: 4, r: 8, emoji: '🐸+🐸' },
|
||||
{ a: 5, b: 4, r: 9, emoji: '🐵+🐸' },
|
||||
{ a: 5, b: 5, r: 10, emoji: '🐵+🐵' },
|
||||
{ a: 6, b: 1, r: 7, emoji: '🐼+🐶' },
|
||||
{ a: 6, b: 2, r: 8, emoji: '🐼+🐱' },
|
||||
{ a: 7, b: 1, r: 8, emoji: '🐨+🐶' },
|
||||
{ a: 7, b: 2, r: 9, emoji: '🐨+🐱' },
|
||||
{ a: 8, b: 1, r: 9, emoji: '🦊+🐶' },
|
||||
{ a: 8, b: 2, r: 10, emoji: '🦊+🐱' },
|
||||
{ a: 9, b: 1, r: 10, emoji: '🐻+🐶' },
|
||||
{ a: 3, b: 4, r: 7, emoji: '🐰+🐸' },
|
||||
{ a: 4, b: 5, r: 9, emoji: '🐸+🐵' },
|
||||
{ a: 6, b: 3, r: 9, emoji: '🐼+🐰' },
|
||||
{ a: 7, b: 3, r: 10, emoji: '🐨+🐰' },
|
||||
]
|
||||
|
||||
const exercises: any[] = []
|
||||
|
||||
for (const { a, b, r, emoji } of sumas) {
|
||||
const id = `num5-suma-${a}-${b}`
|
||||
exercises.push({
|
||||
id,
|
||||
stage: 5,
|
||||
skillCode: 'suma',
|
||||
type: 'problema',
|
||||
prerequisites: a <= 5 && b <= 5 ? ['num4-secuencia-11-20'] : [`num5-suma-${a}-${b - 1}`],
|
||||
content: {
|
||||
instruction: `¿Cuánto es ${a} + ${b}?`,
|
||||
text: `${a} + ${b} = ?`,
|
||||
audioText: `${a} más ${b}`,
|
||||
emoji,
|
||||
options: [
|
||||
...Array.from({ length: 4 }, (_, i) => r - 2 + i + (i >= 2 ? 2 : 0))
|
||||
.filter(j => j >= 1 && j <= 12 && j !== r)
|
||||
.slice(0, 2)
|
||||
.map(j => ({ label: String(j), correct: false, id: String(j) })),
|
||||
{ label: String(r), correct: true, id: String(r) },
|
||||
].sort(() => Math.random() - 0.5),
|
||||
},
|
||||
functionalContext: 'Sumar dos números pequeños.',
|
||||
errorType: 'discriminacion-auditiva',
|
||||
})
|
||||
}
|
||||
|
||||
// Represent sum with objects
|
||||
for (const { a, b, r } of sumas.slice(0, 8)) {
|
||||
exercises.push({
|
||||
id: `num5-suma-visual-${a}-${b}`,
|
||||
stage: 5,
|
||||
skillCode: 'suma-visual',
|
||||
type: 'conciencia',
|
||||
prerequisites: [`num5-suma-${a}-${b}`],
|
||||
content: {
|
||||
instruction: `${a} + ${b} es lo mismo que...`,
|
||||
text: `${'●'.repeat(a)} + ${'●'.repeat(b)}`,
|
||||
audioText: `Juntamos ${a} y ${b}, tenemos ${r}`,
|
||||
options: [
|
||||
{ label: '●'.repeat(r), correct: true, id: String(r) },
|
||||
{ label: '●'.repeat(r + 1), correct: false, id: String(r + 1) },
|
||||
{ label: '●'.repeat(Math.max(1, r - 1)), correct: false, id: String(r - 1) },
|
||||
],
|
||||
emoji: '➕',
|
||||
},
|
||||
functionalContext: 'Visualizar la suma como unión de conjuntos.',
|
||||
errorType: 'discriminacion-auditiva',
|
||||
})
|
||||
}
|
||||
|
||||
const stage: Stage = {
|
||||
id: 5,
|
||||
name: 'Sumas simples (1-10)',
|
||||
description: 'Sumar números del 1 al 10 con ayudas visuales y ejercicios progresivos.',
|
||||
exercises,
|
||||
}
|
||||
|
||||
export default stage
|
||||
@@ -0,0 +1,95 @@
|
||||
import type { Stage } from '../types'
|
||||
|
||||
const restas = [
|
||||
{ a: 2, b: 1, r: 1, emoji: '🍎-🍎' },
|
||||
{ a: 3, b: 1, r: 2, emoji: '🍎🍎-🍎' },
|
||||
{ a: 3, b: 2, r: 1, emoji: '🍎🍎-🍎🍎' },
|
||||
{ a: 4, b: 1, r: 3, emoji: '🍪🍪🍪🍪-🍪' },
|
||||
{ a: 4, b: 2, r: 2, emoji: '🍪🍪🍪🍪-🍪🍪' },
|
||||
{ a: 5, b: 1, r: 4, emoji: '⭐-⭐' },
|
||||
{ a: 5, b: 2, r: 3, emoji: '⭐⭐-⭐⭐' },
|
||||
{ a: 5, b: 3, r: 2, emoji: '⭐⭐⭐-⭐⭐⭐' },
|
||||
{ a: 5, b: 4, r: 1, emoji: '⭐⭐⭐⭐-⭐⭐⭐⭐' },
|
||||
{ a: 6, b: 1, r: 5, emoji: '🌸-🌸' },
|
||||
{ a: 6, b: 2, r: 4, emoji: '🌸🌸-🌸🌸' },
|
||||
{ a: 6, b: 3, r: 3, emoji: '🌸🌸🌸-🌸🌸🌸' },
|
||||
{ a: 7, b: 2, r: 5, emoji: '🌻🌻-🌻🌻' },
|
||||
{ a: 7, b: 3, r: 4, emoji: '🌻🌻🌻-🌻🌻🌻' },
|
||||
{ a: 8, b: 3, r: 5, emoji: '🍄🍄🍄-🍄🍄🍄' },
|
||||
{ a: 8, b: 4, r: 4, emoji: '🍄🍄🍄🍄-🍄🍄🍄🍄' },
|
||||
{ a: 9, b: 4, r: 5, emoji: '🍂🍂🍂🍂-🍂🍂🍂🍂' },
|
||||
{ a: 9, b: 5, r: 4, emoji: '🍂🍂🍂🍂🍂-🍂🍂🍂🍂🍂' },
|
||||
{ a: 10, b: 1, r: 9, emoji: '💎-💎' },
|
||||
{ a: 10, b: 2, r: 8, emoji: '💎💎-💎💎' },
|
||||
{ a: 10, b: 3, r: 7, emoji: '💎💎💎-💎💎💎' },
|
||||
{ a: 10, b: 4, r: 6, emoji: '💎💎💎💎-💎💎💎💎' },
|
||||
{ a: 10, b: 5, r: 5, emoji: '💎💎💎💎💎-💎💎💎💎💎' },
|
||||
{ a: 8, b: 5, r: 3, emoji: '🍀🍀🍀🍀🍀-🍀🍀🍀🍀🍀' },
|
||||
{ a: 7, b: 5, r: 2, emoji: '🌺🌺🌺🌺🌺-🌺🌺🌺🌺🌺' },
|
||||
{ a: 6, b: 5, r: 1, emoji: '🌷🌷🌷🌷🌷-🌷🌷🌷🌷🌷' },
|
||||
]
|
||||
|
||||
const exercises: any[] = []
|
||||
|
||||
for (const { a, b, r, emoji } of restas) {
|
||||
exercises.push({
|
||||
id: `num6-resta-${a}-${b}`,
|
||||
stage: 6,
|
||||
skillCode: 'resta',
|
||||
type: 'problema',
|
||||
prerequisites: a <= 5 ? ['num5-suma-visual-1-1'] : [`num6-resta-${a - 1}-${Math.max(1, b - 1)}` || 'num5-suma-10-1'],
|
||||
content: {
|
||||
instruction: `¿Cuánto es ${a} - ${b}?`,
|
||||
text: `${a} - ${b} = ?`,
|
||||
audioText: `${a} menos ${b}`,
|
||||
emoji,
|
||||
options: [
|
||||
...Array.from({ length: 4 }, (_, i) => r - 2 + i + (i >= 2 ? 2 : 0))
|
||||
.filter(j => j >= 0 && j <= 10 && j !== r)
|
||||
.slice(0, 2)
|
||||
.map(j => ({ label: String(j), correct: false, id: String(j) })),
|
||||
{ label: String(r), correct: true, id: String(r) },
|
||||
].sort(() => Math.random() - 0.5),
|
||||
},
|
||||
functionalContext: 'Restar números pequeños.',
|
||||
errorType: 'discriminacion-auditiva',
|
||||
})
|
||||
}
|
||||
|
||||
// Visual subtraction: take away
|
||||
const visuales = [
|
||||
{ a: 3, b: 1, r: 2 },
|
||||
{ a: 4, b: 2, r: 2 },
|
||||
{ a: 5, b: 3, r: 2 },
|
||||
]
|
||||
for (const { a, b, r } of visuales) {
|
||||
exercises.push({
|
||||
id: `num6-resta-visual-${a}-${b}`,
|
||||
stage: 6,
|
||||
skillCode: 'resta-visual',
|
||||
type: 'conciencia',
|
||||
prerequisites: [`num6-resta-${a}-${b}`],
|
||||
content: {
|
||||
instruction: `${a} - ${b} = ? Sacamos ${b}`,
|
||||
text: `${'🟢'.repeat(a)}\nSacamos ${'🔴'.repeat(b)}\nQuedan...`,
|
||||
audioText: `Sacamos ${b}, quedan ${r}`,
|
||||
options: [
|
||||
{ label: '🟢'.repeat(r), correct: true, id: String(r) },
|
||||
{ label: '🟢'.repeat(r + 2), correct: false, id: String(r + 2) },
|
||||
{ label: '🟢'.repeat(Math.max(1, r + 1)), correct: false, id: String(r + 1) },
|
||||
],
|
||||
emoji: '➖',
|
||||
},
|
||||
functionalContext: 'Visualizar la resta como quitar elementos.',
|
||||
errorType: 'discriminacion-auditiva',
|
||||
})
|
||||
}
|
||||
|
||||
const stage: Stage = {
|
||||
id: 6,
|
||||
name: 'Restas simples (1-10)',
|
||||
description: 'Restar números del 1 al 10 con ayudas visuales.',
|
||||
exercises,
|
||||
}
|
||||
|
||||
export default stage
|
||||
@@ -0,0 +1,103 @@
|
||||
import type { Stage } from '../types'
|
||||
|
||||
const numeros2d = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 30, 33, 40, 44, 50]
|
||||
|
||||
const exercises: any[] = []
|
||||
|
||||
for (const n of numeros2d) {
|
||||
const dec = Math.floor(n / 10)
|
||||
const uni = n % 10
|
||||
const decStr = '🔟'.repeat(dec)
|
||||
const uniStr = '●'.repeat(uni)
|
||||
|
||||
exercises.push({
|
||||
id: `num7-componer-${n}`,
|
||||
stage: 7,
|
||||
skillCode: 'valor-posicional',
|
||||
type: 'eleccion',
|
||||
prerequisites: n <= 15 ? ['num6-resta-visual-3-1'] : [`num7-componer-${numeros2d[numeros2d.indexOf(n) - 1]}`],
|
||||
content: {
|
||||
instruction: `${dec} decenas + ${uni} unidades = ?`,
|
||||
text: `${dec}×10 + ${uni}×1 = ?`,
|
||||
audioText: `${n}: ${dec} decenas y ${uni} unidades`,
|
||||
options: [
|
||||
...Array.from({ length: 4 }, (_, i) => n - 2 + i + (i >= 2 ? 2 : 0))
|
||||
.filter(j => j >= 10 && j <= 55 && j !== n)
|
||||
.slice(0, 2)
|
||||
.map(j => ({ label: String(j), correct: false, id: String(j) })),
|
||||
{ label: String(n), correct: true, id: String(n) },
|
||||
].sort(() => Math.random() - 0.5),
|
||||
emoji: decStr,
|
||||
},
|
||||
functionalContext: 'Componer números de 2 dígitos en decenas y unidades.',
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
}
|
||||
|
||||
// Write the number of tens and units
|
||||
for (const n of [15, 23, 30, 47, 50]) {
|
||||
const dec = Math.floor(n / 10)
|
||||
const uni = n % 10
|
||||
exercises.push({
|
||||
id: `num7-descomponer-${n}`,
|
||||
stage: 7,
|
||||
skillCode: 'valor-posicional',
|
||||
type: 'conciencia',
|
||||
prerequisites: [`num7-componer-${n}`],
|
||||
content: {
|
||||
instruction: `¿Cuántas decenas y unidades tiene ${n}?`,
|
||||
text: `${n} = ? decenas + ? unidades`,
|
||||
audioText: `${n} tiene ${dec} decenas y ${uni} unidades`,
|
||||
options: [
|
||||
{ label: `${dec} dec, ${uni} uni`, correct: true, id: `d${dec}u${uni}` },
|
||||
{ label: `${uni} dec, ${dec} uni`, correct: false, id: `d${uni}u${dec}` },
|
||||
{ label: `${dec + 1} dec, ${Math.max(0, uni - 1)} uni`, correct: false, id: `d${dec + 1}u${Math.max(0, uni - 1)}` },
|
||||
],
|
||||
emoji: '🔟',
|
||||
},
|
||||
functionalContext: 'Descomponer números en decenas y unidades.',
|
||||
errorType: 'inversion-letra',
|
||||
})
|
||||
}
|
||||
|
||||
// Compare 2-digit numbers
|
||||
const comparaciones = [
|
||||
{ a: 15, b: 20 },
|
||||
{ a: 23, b: 18 },
|
||||
{ a: 30, b: 25 },
|
||||
{ a: 42, b: 39 },
|
||||
{ a: 50, b: 49 },
|
||||
]
|
||||
|
||||
for (const { a, b } of comparaciones) {
|
||||
const mayor = a > b ? a : b
|
||||
const menor = a < b ? a : b
|
||||
exercises.push({
|
||||
id: `num7-comparar-${a}-${b}`,
|
||||
stage: 7,
|
||||
skillCode: 'comparacion-2d',
|
||||
type: 'eleccion',
|
||||
prerequisites: [`num7-descomponer-${mayor}`],
|
||||
content: {
|
||||
instruction: `¿Cuál número es más grande?`,
|
||||
text: `${a} vs ${b}`,
|
||||
audioText: `¿Cuál es más grande?`,
|
||||
options: [
|
||||
{ label: String(a), correct: a === mayor, id: String(a) },
|
||||
{ label: String(b), correct: b === mayor, id: String(b) },
|
||||
],
|
||||
emoji: '📏',
|
||||
},
|
||||
functionalContext: 'Comparar números de 2 dígitos.',
|
||||
errorType: 'confusion-letra',
|
||||
})
|
||||
}
|
||||
|
||||
const stage: Stage = {
|
||||
id: 7,
|
||||
name: 'Decenas y unidades',
|
||||
description: 'Componer y descomponer números de 2 dígitos en decenas y unidades. Comparar números.',
|
||||
exercises,
|
||||
}
|
||||
|
||||
export default stage
|
||||
@@ -0,0 +1,214 @@
|
||||
import type { Stage } from '../types'
|
||||
|
||||
const problemas = [
|
||||
{
|
||||
text: 'Tenés 2 manzanas. Mamá te da 1 más. ¿Cuántas manzanas tenés?',
|
||||
respuesta: 3,
|
||||
opciones: [2, 3, 4],
|
||||
emoji: '🍎',
|
||||
op: 'suma',
|
||||
},
|
||||
{
|
||||
text: 'Hay 3 pájaros en el árbol. 1 se va volando. ¿Cuántos quedan?',
|
||||
respuesta: 2,
|
||||
opciones: [1, 2, 4],
|
||||
emoji: '🐦',
|
||||
op: 'resta',
|
||||
},
|
||||
{
|
||||
text: 'Tenés 4 galletitas. Te comés 1. ¿Cuántas te quedan?',
|
||||
respuesta: 3,
|
||||
opciones: [2, 3, 5],
|
||||
emoji: '🍪',
|
||||
op: 'resta',
|
||||
},
|
||||
{
|
||||
text: 'En el patio hay 2 perros y 3 gatos. ¿Cuántos animales hay?',
|
||||
respuesta: 5,
|
||||
opciones: [3, 4, 5],
|
||||
emoji: '🐕',
|
||||
op: 'suma',
|
||||
},
|
||||
{
|
||||
text: 'Tenés 5 lápices. Tu amiga te presta 2 más. ¿Cuántos lápices tenés ahora?',
|
||||
respuesta: 7,
|
||||
opciones: [5, 7, 8],
|
||||
emoji: '✏️',
|
||||
op: 'suma',
|
||||
},
|
||||
{
|
||||
text: 'Hay 6 flores en el jardín. Cortás 2 para mamá. ¿Cuántas quedan?',
|
||||
respuesta: 4,
|
||||
opciones: [3, 4, 8],
|
||||
emoji: '🌸',
|
||||
op: 'resta',
|
||||
},
|
||||
{
|
||||
text: 'En la mesa hay 3 platos y 3 vasos. ¿Cuántas cosas hay?',
|
||||
respuesta: 6,
|
||||
opciones: [5, 6, 9],
|
||||
emoji: '🍽️',
|
||||
op: 'suma',
|
||||
},
|
||||
{
|
||||
text: 'Tenés 7 stickers. Le das 2 a tu hermana. ¿Cuántos te quedan?',
|
||||
respuesta: 5,
|
||||
opciones: [4, 5, 9],
|
||||
emoji: '⭐',
|
||||
op: 'resta',
|
||||
},
|
||||
{
|
||||
text: 'Compraste 8 globos. 3 se explotan. ¿Cuántos globos quedan?',
|
||||
respuesta: 5,
|
||||
opciones: [3, 5, 11],
|
||||
emoji: '🎈',
|
||||
op: 'resta',
|
||||
},
|
||||
{
|
||||
text: 'En la pecera hay 4 peces naranjas y 2 azules. ¿Cuántos peces hay?',
|
||||
respuesta: 6,
|
||||
opciones: [4, 6, 8],
|
||||
emoji: '🐠',
|
||||
op: 'suma',
|
||||
},
|
||||
{
|
||||
text: 'Tenés 9 bloques. Usás 4 para hacer una torre. ¿Cuántos sobran?',
|
||||
respuesta: 5,
|
||||
opciones: [4, 5, 13],
|
||||
emoji: '🧱',
|
||||
op: 'resta',
|
||||
},
|
||||
{
|
||||
text: 'En tu plato hay 5 frutillas y 3 uvas. ¿Cuántas frutas tenés?',
|
||||
respuesta: 8,
|
||||
opciones: [5, 8, 15],
|
||||
emoji: '🍓',
|
||||
op: 'suma',
|
||||
},
|
||||
{
|
||||
text: 'Hay 10 libros en el estante. Sacás 4 para leer. ¿Cuántos quedan?',
|
||||
respuesta: 6,
|
||||
opciones: [4, 6, 14],
|
||||
emoji: '📚',
|
||||
op: 'resta',
|
||||
},
|
||||
{
|
||||
text: 'Tenés 2 manos. Cada mano tiene 5 dedos. ¿Cuántos dedos tenés en total?',
|
||||
respuesta: 10,
|
||||
opciones: [5, 7, 10],
|
||||
emoji: '🖐️',
|
||||
op: 'suma',
|
||||
},
|
||||
{
|
||||
text: 'Compartís 6 caramelos con tu amiga. Le das la mitad. ¿Cuántos te quedan?',
|
||||
respuesta: 3,
|
||||
opciones: [2, 3, 6],
|
||||
emoji: '🍬',
|
||||
op: 'resta',
|
||||
},
|
||||
{
|
||||
text: 'Hay 7 días en la semana. Ya pasaron 3. ¿Cuántos días quedan?',
|
||||
respuesta: 4,
|
||||
opciones: [3, 4, 10],
|
||||
emoji: '📅',
|
||||
op: 'resta',
|
||||
},
|
||||
{
|
||||
text: 'Viste 3 mariquitas en una hoja y 2 en otra. ¿Cuántas viste?',
|
||||
respuesta: 5,
|
||||
opciones: [3, 5, 6],
|
||||
emoji: '🐞',
|
||||
op: 'suma',
|
||||
},
|
||||
{
|
||||
text: 'Tenés 4 monedas. Encontrás 3 más en tu bolsillo. ¿Cuántas tenés?',
|
||||
respuesta: 7,
|
||||
opciones: [4, 7, 12],
|
||||
emoji: '🪙',
|
||||
op: 'suma',
|
||||
},
|
||||
{
|
||||
text: 'Son las 3 de la tarde. Pasaron 2 horas. ¿Qué hora es?',
|
||||
respuesta: 5,
|
||||
opciones: [1, 5, 6],
|
||||
emoji: '🕐',
|
||||
op: 'suma',
|
||||
},
|
||||
{
|
||||
text: 'El nene tiene 8 años. La nena tiene 3 años menos. ¿Cuántos años tiene la nena?',
|
||||
respuesta: 5,
|
||||
opciones: [3, 5, 11],
|
||||
emoji: '👶',
|
||||
op: 'resta',
|
||||
},
|
||||
{
|
||||
text: 'En la granja hay 2 caballos, 3 vacas y 1 cerdo. ¿Cuántos animales?',
|
||||
respuesta: 6,
|
||||
opciones: [4, 6, 7],
|
||||
emoji: '🐴',
|
||||
op: 'suma',
|
||||
},
|
||||
{
|
||||
text: 'Papá horneó 12 galletitas. Te comiste 2. ¿Cuántas quedan?',
|
||||
respuesta: 10,
|
||||
opciones: [8, 10, 14],
|
||||
emoji: '🍪',
|
||||
op: 'resta',
|
||||
},
|
||||
{
|
||||
text: 'Un tren tiene 4 vagones rojos y 4 azules. ¿Cuántos vagones tiene?',
|
||||
respuesta: 8,
|
||||
opciones: [4, 8, 16],
|
||||
emoji: '🚂',
|
||||
op: 'suma',
|
||||
},
|
||||
{
|
||||
text: 'Tenés 5 años. Cuando cumplas 5 más, ¿cuántos vas a tener?',
|
||||
respuesta: 10,
|
||||
opciones: [5, 10, 15],
|
||||
emoji: '🎂',
|
||||
op: 'suma',
|
||||
},
|
||||
{
|
||||
text: 'El árbol tiene 10 manzanas. Caen 3. ¿Cuántas manzanas quedan en el árbol?',
|
||||
respuesta: 7,
|
||||
opciones: [3, 7, 13],
|
||||
emoji: '🍎',
|
||||
op: 'resta',
|
||||
},
|
||||
]
|
||||
|
||||
const exercises: any[] = []
|
||||
|
||||
for (let i = 0; i < problemas.length; i++) {
|
||||
const p = problemas[i]
|
||||
exercises.push({
|
||||
id: `num8-problema-${i + 1}`,
|
||||
stage: 8,
|
||||
skillCode: 'problemas-cotidianos',
|
||||
type: 'problema',
|
||||
prerequisites: i === 0 ? ['num7-comparar-15-20'] : [`num8-problema-${i}`],
|
||||
content: {
|
||||
instruction: 'Escuchá bien el problema',
|
||||
text: p.text,
|
||||
audioText: p.text,
|
||||
emoji: p.emoji,
|
||||
options: p.opciones.map(o => ({
|
||||
label: String(o),
|
||||
correct: o === p.respuesta,
|
||||
id: String(o),
|
||||
})).sort(() => Math.random() - 0.5),
|
||||
},
|
||||
functionalContext: 'Resolver problemas matemáticos de la vida cotidiana.',
|
||||
errorType: p.op === 'resta' ? 'inversion-letra' : 'discriminacion-auditiva',
|
||||
})
|
||||
}
|
||||
|
||||
const stage: Stage = {
|
||||
id: 8,
|
||||
name: 'Problemas de la vida cotidiana',
|
||||
description: 'Resolver problemas cotidianos que requieren sumar y restar números hasta 12.',
|
||||
exercises,
|
||||
}
|
||||
|
||||
export default stage
|
||||
@@ -0,0 +1,54 @@
|
||||
export type ExerciseType =
|
||||
| "sensibilizacion"
|
||||
| "conciencia"
|
||||
| "trazo"
|
||||
| "eleccion"
|
||||
| "emparejar"
|
||||
| "secuencia"
|
||||
| "palabra"
|
||||
| "problema"
|
||||
| "lectura"
|
||||
|
||||
export type ErrorType =
|
||||
| "discriminacion-auditiva"
|
||||
| "confusion-letra"
|
||||
| "silaba-dificil"
|
||||
| "omision-letra"
|
||||
| "inversion-letra"
|
||||
| null
|
||||
|
||||
export interface ExerciseContent {
|
||||
instruction: string
|
||||
text?: string
|
||||
options?: { label: string; correct: boolean; id?: string }[]
|
||||
pairs?: { left: string; right: string; id: string }[]
|
||||
sequence?: string[]
|
||||
emoji?: string
|
||||
color?: string
|
||||
audioText?: string
|
||||
imageEmoji?: string
|
||||
}
|
||||
|
||||
export interface Exercise {
|
||||
id: string
|
||||
stage: number
|
||||
skillCode: string
|
||||
type: ExerciseType
|
||||
content: ExerciseContent
|
||||
prerequisites: string[]
|
||||
errorType?: ErrorType
|
||||
functionalContext?: string
|
||||
}
|
||||
|
||||
export interface Stage {
|
||||
id: number
|
||||
name: string
|
||||
description: string
|
||||
exercises: Exercise[]
|
||||
}
|
||||
|
||||
export interface TopicCurriculum {
|
||||
topic: string
|
||||
name: string
|
||||
stages: Stage[]
|
||||
}
|
||||
Reference in New Issue
Block a user