7.7 KiB
🎡 Ruleta Interactiva — SCORM 1.2
Actividad e-learning interactiva basada en una ruleta con preguntas de cultura general, construida con React, TypeScript, Tailwind CSS y empaquetada como contenido SCORM 1.2.
🛠️ Stack Tecnológico
| Tecnología | Versión | Uso |
|---|---|---|
| React | 19 | UI y manejo de estado |
| TypeScript | 5 | Tipado estático |
| Tailwind CSS | 4 | Estilos utilitarios |
| Vite | 6 | Bundler y dev server |
| Howler.js | 2 | Manejo de audio |
| scorm-again | 3 | Simulador SCORM en desarrollo |
📁 Estructura del Proyecto
src/
├── audio/
│ ├── ExtendedHowl.ts # Clase que extiende Howl con eventos de timeupdate (250ms)
│ ├── AudioController.ts # Controlador global de audio + sonidos precargados
│ └── audios.ts # Constantes con rutas de archivos de audio
│
├── components/
│ ├── ui/
│ │ └── Button.tsx # Botón reutilizable (variantes: primary, secondary, outline, danger)
│ ├── layout/
│ │ ├── Header.tsx # Cabecera de la aplicación
│ │ └── Footer.tsx # Pie de página
│ ├── screens/
│ │ ├── Cover.tsx # Pantalla de portada con introducción y botón comenzar
│ │ ├── Game.tsx # Pantalla principal del juego
│ │ └── Result.tsx # Pantalla de cierre (3 estados)
│ └── game/
│ ├── Ruleta/
│ │ └── RuletaSVG.tsx # Ruleta SVG con 4 secciones de colores
│ ├── QuestionModal.tsx # Modal de pregunta con temporizador y feedback
│ └── ResultModal.tsx # Modal interno (reservado)
│
├── data/
│ └── preguntas.json # 4 categorías × 8 preguntas + banco genérico
│
├── hooks/
│ ├── useAudio.ts # Hook para consumir el AudioController
│ ├── useIntentos.ts # Manejo de intentos con persistencia en sessionStorage
│ ├── useRuleta.ts # Lógica completa del juego
│ ├── useSCORM.ts # Hook para inicializar y usar SCORM 1.2
│ └── useScale.ts # Escalado adaptativo 1920×1080
│
├── layouts/
│ └── MainLayout.tsx # Template principal con escalado adaptativo
│
├── scorm/
│ └── scorm.ts # Funciones SCORM 1.2 con fallback a sessionStorage
│
├── types/
│ └── index.ts # Interfaces TypeScript (Pregunta, Categoria, PreguntasData)
│
├── App.tsx # Manejo de pantallas y flujo de intentos
└── main.tsx # Entry point con simulador SCORM en desarrollo
public/
├── audios/
│ ├── click.mp3 # Sonido de clic en botones
│ ├── wheel-spin.mp3 # Sonido al girar la ruleta
│ ├── feedback-correct.mpeg # Sonido de respuesta correcta
│ └── feedback-incorrect.mpeg # Sonido de respuesta incorrecta
├── img/
│ ├── ruleta.png # Imagen de ruleta (respaldo)
│ └── indicador.png # Imagen de indicador (respaldo)
└── imsmanifest.xml # Manifiesto SCORM 1.2 requerido por el LMS
🎮 Flujo de la Actividad
Portada (Cover)
│
│ clic en "Comenzar" → consume 1 intento + sonido click
▼
Juego (Game)
│
│ clic en la ruleta → gira + sonido wheel-spin (4s)
▼
Detecta sección (4 categorías × 90°)
│
▼
Modal de Pregunta (temporizador 30s)
├── Respuesta correcta → sonido correct → feedback → círculo de progreso
├── Respuesta incorrecta → sonido incorrect → feedback → círculo de progreso
└── Tiempo agotado → cuenta como incorrecta → feedback
│
│ 10 preguntas respondidas
▼
Pantalla de Resultado
├── ≥ 8 correctas → ¡Felicidades! (sin botón)
├── < 8 correctas + intentos disponibles → "Casi" + botón Reintentar
└── Sin intentos → Mensaje final (persiste al recargar)
🎯 Categorías de Preguntas
| # | Categoría | Color | Preguntas |
|---|---|---|---|
| 1 | 🏛️ Historia | Morado #7C3AED |
8 |
| 2 | 🌍 Geografía | Verde #059669 |
8 |
| 3 | 🔬 Ciencia | Rojo #DC2626 |
8 |
| 4 | 🎨 Arte y Literatura | Naranja #D97706 |
8 |
Las preguntas se seleccionan aleatoriamente sin repetir dentro de cada categoría. Si se agotan las preguntas de una categoría, se usa el banco genérico (5 preguntas).
🏆 Criterios de Aprobación
| Criterio | Valor |
|---|---|
| Preguntas por actividad | 10 |
| Mínimo para aprobar | 8 correctas |
| Intentos totales | 3 |
| Tiempo por pregunta | 30 segundos |
| Tiempo agotado | Cuenta como incorrecta |
🔄 Sistema de Intentos
- El intento se consume al hacer clic en "Comenzar"
- Se persiste en
sessionStorage, por lo que recargar la página no recupera el intento - Al agotar los 3 intentos, la pantalla de cierre final persiste aunque se recargue
📐 Escalado Adaptativo
El hook useScale escala toda la actividad a una resolución base de 1920×1080 manteniendo proporciones en cualquier pantalla:
const BASE_WIDTH = 1920
const BASE_HEIGHT = 1080
const scale = Math.min(window.innerWidth / BASE_WIDTH, window.innerHeight / BASE_HEIGHT)
Solo orientación horizontal. No aplica diseño para pantallas verticales.
🔊 Audio
Los audios se precargan al iniciar la aplicación mediante AudioController:
sounds.click?.play() // Botones de navegación
sounds.wheelSpin?.play() // Al girar la ruleta
sounds.correct?.play() // Respuesta correcta
sounds.incorrect?.play() // Respuesta incorrecta
📡 SCORM 1.2
El módulo SCORM (src/scorm/scorm.ts) implementa todas las funciones estándar con fallback automático a sessionStorage cuando no hay LMS disponible:
| Función | CMI Key |
|---|---|
initSCORM() |
Inicializa y establece status incomplete |
getStudentName() |
cmi.core.student_name |
getLessonStatus() / setLessonStatus() |
cmi.core.lesson_status |
getLessonLocation() / setLessonLocation() |
cmi.core.lesson_location |
getScore() / setScore() |
cmi.core.score.raw/max/min |
getSuspendData() / setSuspendData() |
cmi.suspend_data |
getScormData() / setScormData() |
Cualquier clave CMI |
finishSCORM() |
Calcula session_time en HH:MM:SS y cierra |
completeLesson() |
Establece status completed |
En desarrollo,
scorm-againsimula elwindow.APIdel LMS automáticamente.
🧩 Componente Button
<Button variant="primary" size="lg" onClick={fn}>Texto</Button>
<Button variant="secondary" size="md">Texto</Button>
<Button variant="outline" size="sm">Texto</Button>
<Button variant="danger" disabled>Texto</Button>
🚀 Comandos
# Instalar dependencias
npm install
# Desarrollo
npm run dev
# Build para producción
npm run build
# Verificar TypeScript
npx tsc --noEmit
📦 Empaquetado SCORM
Para publicar en un LMS (Moodle, Cornerstone, etc.):
- Ejecutar
npm run build - Abrir la carpeta
dist/— elimsmanifest.xmlse copia automáticamente - Seleccionar todo el contenido de
dist/y comprimir en un.zip - Subir el
.zipal LMS como paquete SCORM 1.2
El
masteryscoreestá configurado en 80 en elimsmanifest.xml.
📋 Pendientes
- Reemplazar categorías y preguntas de cultura general por el contenido real del cliente
- Integrar
setScoreycompleteLessoncon SCORM al finalizar la actividad - Pruebas en LMS real (Moodle)
- Definir diseño visual final (colores, logo, imágenes del cliente)