<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Wordle en Español</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: #121213;
color: #fff;
font-family: 'Helvetica Neue', Arial, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
}
header {
width: 100%;
max-width: 500px;
padding: 14px;
text-align: center;
border-bottom: 1px solid #3a3a3c;
margin-bottom: 20px;
}
h1 { font-size: 1.8rem; letter-spacing: 4px; text-transform: uppercase; }
#mensaje {
height: 28px;
font-size: 0.9rem;
font-weight: bold;
color: #fff;
background: rgba(255,255,255,0.1);
border-radius: 4px;
padding: 4px 14px;
margin-bottom: 16px;
transition: opacity 0.3s;
display: flex;
align-items: center;
justify-content: center;
min-width: 200px;
}
/* ?? Tablero ?? */
#tablero {
display: grid;
grid-template-rows: repeat(6, 62px);
gap: 5px;
margin-bottom: 20px;
}
.fila {
display: grid;
grid-template-columns: repeat(5, 62px);
gap: 5px;
}
.celda {
border: 2px solid #3a3a3c;
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
font-weight: bold;
text-transform: uppercase;
transition: border-color 0.1s;
user-select: none;
}
.celda.activa { border-color: #565758; }
.celda.pop { animation: pop 0.1s ease; }
@keyframes pop { 0%{transform:scale(1)} 50%{transform:scale(1.12)} 100%{transform:scale(1)} }
.celda.flip { animation: flip 0.5s ease forwards; }
@keyframes flip {
0% { transform: rotateX(0); }
49% { transform: rotateX(90deg);}
50% { transform: rotateX(90deg);}
100% { transform: rotateX(0); }
}
.correcta { background: #538d4e; border-color: #538d4e; }
.presente { background: #b59f3b; border-color: #b59f3b; }
.ausente { background: #3a3a3c; border-color: #3a3a3c; }
/* ?? Teclado ?? */
#teclado { display: flex; flex-direction: column; gap: 8px; align-items: center; }
.fila-teclado { display: flex; gap: 6px; }
.tecla {
height: 58px;
min-width: 43px;
padding: 0 6px;
background: #818384;
border: none;
border-radius: 4px;
color: #fff;
font-size: 0.85rem;
font-weight: bold;
text-transform: uppercase;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.3s;
}
.tecla.wide { min-width: 65px; font-size: 0.75rem; }
.tecla:hover { filter: brightness(1.15); }
.tecla.correcta { background: #538d4e; }
.tecla.presente { background: #b59f3b; }
.tecla.ausente { background: #3a3a3c; }
/* ?? Modal victoria/derrota ?? */
#modal-overlay {
display: none;
position: fixed; inset: 0;
background: rgba(0,0,0,0.7);
align-items: center;
justify-content: center;
z-index: 10;
}
#modal {
background: #1a1a1b;
border: 1px solid #3a3a3c;
border-radius: 10px;
padding: 32px 40px;
text-align: center;
max-width: 320px;
width: 90%;
}
#modal h2 { font-size: 1.4rem; margin-bottom: 10px; }
#modal p { color: #aaa; margin-bottom: 6px; font-size: 0.9rem; }
#modal .palabra-reveal {
font-size: 1.6rem;
font-weight: bold;
letter-spacing: 4px;
color: #538d4e;
margin: 10px 0 20px;
}
#btn-nuevo {
background: #538d4e;
color: #fff;
border: none;
border-radius: 4px;
padding: 12px 28px;
font-size: 1rem;
font-weight: bold;
cursor: pointer;
width: 100%;
}
#btn-nuevo:hover { background: #6aaf64; }
</style>
</head>
<body>
<header><h1>Wordle</h1></header>
<div id="mensaje"></div>
<div id="tablero"></div>
<div id="teclado">
<div class="fila-teclado" id="fila-q"></div>
<div class="fila-teclado" id="fila-a"></div>
<div class="fila-teclado" id="fila-z"></div>
</div>
<div id="modal-overlay">
<div id="modal">
<h2 id="modal-titulo"></h2>
<p id="modal-subtitulo"></p>
<div class="palabra-reveal" id="modal-palabra"></div>
<button id="btn-nuevo">Nueva partida</button>
</div>
</div>
<script>
// ?? Lista de palabras en español de 5 letras ??????????????????
const PALABRAS = [
'ACERO','AGUJA','AIREN','ALCEN','ALDEA','ALELO','ALERO','ALIFE','ALISO',
'ALMUD','ALOJA','ALOSA','ALUDA','ALURA','ALZAN','AMADA','AMAGO','AMARA',
'AMARO','AMIBA','AMIGO','AMINA','AMOCO','AMOLA','AMONA','AMPLA','ANGEL',
'ANIMA','ANION','ANISO','ANITO','ANODE','ANOLA','ANONA','BALDE','BANCO',
'BANDA','BELGA','BELLO','BESAR','BIELA','BIRRA','BOLSA','BOMBA','BORDE',
'BRISA','BURRO','CACAO','CACHO','CALOR','CAMPO','CANAL','CANAS','CANTO',
'CARNE','CARTA','CASCO','CAUSA','CAZAR','CELOS','CERDO','CERIO','CIELO',
'CINCO','CIRCO','CLASE','CLAVE','CLAVO','COBRO','COCER','COCIO','COFIA',
'COIMA','COJAN','COJOS','COLON','COLOR','COLZA','COMER','COMIC','COMUN',
'CORAL','CORTE','COSMO','COSTE','CREAR','CREDO','CREMA','CRIME','CRIOS',
'CRUCE','CRUDA','CRUEL','CUERO','CULPA','DANZA','DEBUT','DECIR','DELTA',
'DENSE','DEPEN','DESDE','DICHA','DISCO','DOLOR','DOMBO','DONAR','DUDAR',
'DUELO','DULCE','EBRIO','EDEMA','EGYPT','EJIDO','ELEVA','ELIXIR','ENERO',
'ENLACE','ENOJO','ENTRE','ENVIO','EPOCA','ESCALA','ESTRO','ETAPA','ETNIA',
'FACIL','FALDA','FALSO','FANGO','FARDA','FERIA','FEROZ','FINCA','FLOTA',
'FOBIA','FOGON','FORMA','FOTON','FRENO','FRESA','FUEGO','FUERZA','FUMAR',
'GALLO','GARZA','GASTO','GEMIR','GENIO','GENOMA','GLOBO','GLOSA','GORDO',
'GOTAS','GRAMO','GRANO','GRASA','GRAVE','GRITA','GRUTA','GUAPA','GUION',
'GUSTO','HEROE','HERTZ','HIELO','HIGOS','HONOR','HOTEL','HULLA','HUMUS',
'IDEAL','IDOLO','INDIO','INODO','JAMON','JARDIN','JAULA','JUGAR','JUNTO',
'KARMA','KILOS','LASER','LATIR','LECHE','LEDGE','LENTE','LEONA','LIBRE',
'LIMON','LINEA','LIRIO','LITRO','LLANO','LLENO','LLORO','LONJA','LUNES',
'LUCHA','LUGAR','LUMBA','MADRE','MALVA','MANGO','MANOR','MARCO','MARES',
'MAGIA','MARSH','MATAR','MEDIA','MEDIO','MELON','MENOS','MENTA','MENUS',
'METAL','MIEDO','MIMAR','MINGO','MIRAR','MIXTO','MODELO','MODIO','MOJAR',
'MOLDE','MONTE','MORAL','MOTOR','MOVER','MUCHO','MUNDO','NEGRO','NIEVE',
'NIVEL','NOBLE','NOCHE','NORMA','NOVIO','NUBLA','NUEVO','OBESO','OBRAR',
'ODIAR','OLEAJE','OLIVO','OLIVE','OPACO','OPERA','ORDEN','OREIA','ORION',
'PAGAR','PALMA','PANDA','PANEL','PAPEL','PARED','PARIR','PARVO','PASTA',
'PAUSA','PECHO','PEDAL','PEDIR','PENAL','PERLA','PESAR','PIANO','PICAR',
'PILOTO','PIOJO','PISTA','PIXEL','PIZZA','PLANO','PLATA','PLAZA','PLENA',
'PLUMA','PODER','POEMA','POLLO','POMPA','PONER','PORTA','PRISA','PROBAR',
'PROSA','PUBIS','PUNTA','PUNTO','QUESO','RADIO','RAION','RAJAS','RANGO',
'RASGO','RATON','REBUS','REGLA','REINA','REINO','RELOJ','REPAS','REUMA',
'RIGOR','RINDE','RITMO','RIVAL','ROBLE','ROBOT','RONDA','ROPER','ROSTO',
'ROTAR','RUBIO','RUEDA','RUINA','SABIO','SAGAZ','SALIR','SALON','SALUD',
'SALVO','SAUCE','SECTA','SERIO','SIGLO','SIGMA','SIRVA','SOBRE','SOLAR',
'SOMBA','SONAR','SOPLA','SORDO','SUAVE','SUCIO','SUELO','SUMAR','SUPER',
'TABACO','TABLA','TACTO','TALON','TARDE','TAREA','TECLA','TEXTO','TIBIA',
'TIRAR','TITAN','TOCAR','TOMAR','TONER','TORNO','TORPE','TOTAL','TRAMA',
'TRAMO','TRIBU','TRIGO','TRONO','TROZO','TURBO','TUTOR','UMBRA','UNION',
'UNTAR','URANO','URBAN','USADA','USTED','VALOR','VAPOR','VARIAR','VASCO',
'VECINO','VELOZ','VENDA','VENIR','VENTA','VERDE','VERJA','VERSO','VIAJE',
'VIDEO','VIGOR','VIRAL','VISOR','VISTA','VIVIR','VOTAR','VUELO','YERBA',
'YERMO','YOGUR','ZURDO'
].filter(w => w.length === 5);
// ?? Estado global ??????????????????????????????????????????????
let palabraActual, intentoActual, letraActual, terminado;
let filas, estadoTeclado;
function elegirPalabra() {
return PALABRAS[Math.floor(Math.random() * PALABRAS.length)];
}
function iniciar() {
palabraActual = elegirPalabra();
intentoActual = 0;
letraActual = 0;
terminado = false;
estadoTeclado = {};
construirTablero();
construirTeclado();
document.getElementById('modal-overlay').style.display = 'none';
mostrarMensaje('');
}
function construirTablero() {
const tablero = document.getElementById('tablero');
tablero.innerHTML = '';
filas = [];
for (let i = 0; i < 6; i++) {
const fila = document.createElement('div');
fila.className = 'fila';
const celdas = [];
for (let j = 0; j < 5; j++) {
const c = document.createElement('div');
c.className = 'celda';
fila.appendChild(c);
celdas.push(c);
}
tablero.appendChild(fila);
filas.push(celdas);
}
}
const FILAS_TECLADO = [
['Q','W','E','R','T','Y','U','I','O','P'],
['A','S','D','F','G','H','J','K','L','Ñ'],
['?','Z','X','C','V','B','N','M','?']
];
const IDS_FILAS = ['fila-q','fila-a','fila-z'];
function construirTeclado() {
FILAS_TECLADO.forEach((letras, i) => {
const fila = document.getElementById(IDS_FILAS[i]);
fila.innerHTML = '';
letras.forEach(l => {
const btn = document.createElement('button');
btn.className = 'tecla' + (l === '?' || l === '?' ? ' wide' : '');
btn.textContent = l;
btn.dataset.letra = l;
btn.addEventListener('click', () => manejarLetra(l));
fila.appendChild(btn);
});
});
}
function manejarLetra(l) {
if (terminado) return;
if (l === '?') {
borrar(); return;
}
if (l === '?') {
confirmar(); return;
}
if (letraActual < 5) {
const celda = filas[intentoActual][letraActual];
celda.textContent = l;
celda.classList.add('activa', 'pop');
setTimeout(() => celda.classList.remove('pop'), 150);
letraActual++;
}
}
function borrar() {
if (letraActual > 0) {
letraActual--;
filas[intentoActual][letraActual].textContent = '';
filas[intentoActual][letraActual].classList.remove('activa');
}
}
function confirmar() {
if (letraActual < 5) {
mostrarMensaje('Faltan letras'); return;
}
const intento = filas[intentoActual].map(c => c.textContent).join('');
const resultado = evaluar(intento, palabraActual);
// Animar con delay por celda
resultado.forEach((estado, i) => {
setTimeout(() => {
const celda = filas[intentoActual][i];
celda.classList.add('flip');
setTimeout(() => {
celda.classList.remove('activa');
celda.classList.add(estado);
}, 250);
}, i * 100);
});
// Actualizar teclado después de la animación
setTimeout(() => {
resultado.forEach((estado, i) => {
const letra = intento[i];
const prioridad = {correcta:3, presente:2, ausente:1};
if ((prioridad[estado] || 0) > (prioridad[estadoTeclado[letra]] || 0)) {
estadoTeclado[letra] = estado;
const btn = document.querySelector(`.tecla[data-letra="${letra}"]`);
if (btn) { btn.classList.remove('correcta','presente','ausente'); btn.classList.add(estado); }
}
});
intentoActual++;
letraActual = 0;
if (intento === palabraActual) {
terminado = true;
const mensajes = ['¡Perfecto!','¡Brillante!','¡Excelente!','¡Muy bien!','¡Bien!','¡Uf, por poco!'];
setTimeout(() => mostrarModal(true, mensajes[intentoActual - 1] || '¡Conseguido!'), 300);
} else if (intentoActual === 6) {
terminado = true;
setTimeout(() => mostrarModal(false), 300);
}
}, 600);
}
function evaluar(intento, objetivo) {
const resultado = Array(5).fill('ausente');
const conteo = {};
// Contar letras del objetivo
for (const l of objetivo) conteo[l] = (conteo[l] || 0) + 1;
// Primero las correctas
for (let i = 0; i < 5; i++) {
if (intento[i] === objetivo[i]) {
resultado[i] = 'correcta';
conteo[intento[i]]--;
}
}
// Luego las presentes
for (let i = 0; i < 5; i++) {
if (resultado[i] === 'correcta') continue;
if (conteo[intento[i]] > 0) {
resultado[i] = 'presente';
conteo[intento[i]]--;
}
}
return resultado;
}
function mostrarMensaje(msg) {
const el = document.getElementById('mensaje');
el.textContent = msg;
el.style.opacity = msg ? '1' : '0';
if (msg) setTimeout(() => { el.style.opacity = '0'; }, 2000);
}
function mostrarModal(victoria, titulo = '') {
document.getElementById('modal-titulo').textContent = victoria ? titulo : '¡Oh no!';
document.getElementById('modal-subtitulo').textContent = victoria
? `Lo resolviste en ${intentoActual} ${intentoActual === 1 ? 'intento' : 'intentos'}`
: 'La palabra era:';
document.getElementById('modal-palabra').textContent = palabraActual;
document.getElementById('modal-overlay').style.display = 'flex';
}
// Teclado físico
document.addEventListener('keydown', e => {
if (e.ctrlKey || e.altKey || e.metaKey) return;
if (e.key === 'Enter') { manejarLetra('?'); return; }
if (e.key === 'Backspace') { manejarLetra('?'); return; }
const l = e.key.toUpperCase();
if (/^[A-ZÁÉÍÓÚÑ]$/.test(l)) manejarLetra(l);
});
document.getElementById('btn-nuevo').addEventListener('click', iniciar);
iniciar();
</script>
</body>
</html>
Wordle en JavaScript: clon completo en español
Clon del juego Wordle en JavaScript puro con palabras en español. Tablero 6×5, teclado virtual, colores verde/amarillo/gris, animación de flip y detección de victoria y derrota. Todo en un único fichero HTML sin dependencias externas.
Descargar adjuntos
COMPARTE ESTE TUTORIAL
COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP