(Un experimento entre código, navidad y un poquito de IA)
Hay proyectos que nacen porque “se necesitan”… y hay otros que nacen porque ya urge sentir vacaciones, porque ya estamos marcando los días con rayitas en la pared y porque ver caer nieve (aunque sea digital) nos sube el ánimo con la ilusión de un chocolate caliente imaginario.
Así nació este pequeño experimento:
🎉 un contador regresivo animado,
❄️ con nieve de verdad (bueno, de CSS),
🎄 emojis que brotan cuando pasas el dedo,
📱 y una experiencia que funciona perfecto en móvil.
Y sí: lo hice con HTML, CSS, JS… y una ayudadita estratégica de IA.
Porque si la tecnología está para jugar, se juega.
❄️ ¿Qué es este contador y por qué está tan divertido?
Es un contador regresivo que te dice cuántos días, horas, minutos y segundos faltan para las vacaciones.
Hasta ahí normal…
Pero:
✨ Tiene un fondo invernal con copos de nieve cayendo suavemente.
✨ Cuando mueves el mouse o pasas el dedo, brotan emojis navideños como si estuvieras lanzando magia.
✨ Funciona perfecto en celular, porque el contenedor se hace más pequeño y te deja jugar más con el efecto.
✨ No usa librerías externas. Todo es HTML, CSS y JS puro.
✨ Y sí, me apoyé en IA para pulir animaciones y hacerlo más interactivo.
Es un proyecto simple pero con vibes de mini-juego navideño.
Los alumnos lo aman, mis amigos lo quieren en sus páginas, y yo… bueno, yo ya ingreso diario a ver cuánta nieve cae.
🎯 HTML: la estructura del show
El HTML es casi minimalista: un contenedor visible (para mostrar el tiempo) y un contenedor invisible que sirve de escenario para la nieve y los emojis.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cuenta Regresiva para Vacaciones</title>
<!-- Vinculando el archivo CSS -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h1>🌴 ¡Cuenta regresiva para las vacaciones! 🎉</h1>
<p id="days">Cargando...</p>
</div>
<!-- Fondo con emojis -->
<div id="emoji-container"></div>
<!-- Vinculando el archivo JS -->
<script src="script.js"></script>
</body>
</html>
🎨 CSS: donde ocurre la magia visual
El CSS es la parte que da vida al proyecto:
🌫️ un degradado azul estilo “cielo frío”
🌨️ animación de los copos de nieve cayendo
🎉 animación de los emojis que explotan y se desvanecen
📱 reglas responsivas para que en móvil todo se vea tierno y compacto
/* Importar la fuente personalizada */
@font-face {
font-family: "Last";
src: url("last.otf") format("opentype");
}
/* Estilos generales */
body {
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
/* Cielo invernal en degradado */
background: linear-gradient(to bottom, #4a90e2, #87ceeb);
overflow: hidden;
}
/* Contenedor principal */
.container {
text-align: center;
background: rgba(255, 255, 255, 0.95);
padding: 40px 50px;
border-radius: 24px;
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.25);
z-index: 1;
position: relative;
}
/* Título */
.container h1 {
font-family: "Last", "Comic Sans MS", cursive, sans-serif;
font-size: 2.6rem;
color: #ff4500; /* Naranja vibrante */
margin-bottom: 20px;
}
/* Días restantes */
#days {
font-size: 2.2rem;
font-weight: bold;
color: #2e8b57; /* Verde bosque */
}
/* Fondo para nieve y emojis de trail */
#emoji-container {
position: fixed;
inset: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 0;
overflow: hidden;
}
/* Copos de nieve que caen */
.snowflake {
position: absolute;
top: -10vh;
animation-name: snow-fall;
animation-timing-function: linear;
animation-iteration-count: 1;
opacity: 0.9;
filter: drop-shadow(0 0 4px rgba(255, 255, 255, 0.9));
}
@keyframes snow-fall {
0% {
transform: translateY(-10vh) translateX(0);
opacity: 0;
}
20% {
opacity: 1;
}
100% {
transform: translateY(110vh) translateX(10vw);
opacity: 0;
}
}
/* Emojis que brotan al pasar el dedo */
.emoji-trail {
position: absolute;
transform: translate(-50%, -50%);
opacity: 0;
animation: emoji-pop 1.8s ease-out forwards;
pointer-events: none;
}
@keyframes emoji-pop {
0% {
transform: translate(-50%, -50%) scale(0.2);
opacity: 0;
}
40% {
transform: translate(-50%, -70%) scale(1);
opacity: 1;
}
100% {
transform: translate(-50%, -90%) scale(0.6);
opacity: 0;
}
}
/* ==============================
AJUSTES PARA MÓVIL
============================== */
@media (max-width: 768px) {
.container {
width: 80%;
padding: 20px 25px;
border-radius: 16px;
transform: scale(0.85); /* La hace más pequeña */
}
.container h1 {
font-size: 1.8rem;
}
#days {
font-size: 1.5rem;
font-family: Verdana, Geneva, Tahoma, sans-serif;
}
body {
padding-top: 30px;
}
}
/* Para móviles MUY pequeños */
@media (max-width: 430px) {
.container {
width: 75%;
padding: 18px 20px;
transform: scale(0.75); /* aún más chica */
}
.container h1 {
font-size: 1.4rem;
}
#days {
font-size: 1.2rem;
}
}
⚙️ JavaScript: el cerebro del contador
El JS controla tres cosas:
1️⃣ El contador regresivo
Cada segundo calcula la diferencia entre ahora y una fecha objetivo (en mi caso, 19 de diciembre a las 3:00 p.m.):
countdownElement.textContent =
`Faltan ${days}d ${hours}h ${minutes}m ${seconds}s para las vacaciones 🎉`;
2️⃣ La nieve animada
Cada 250 ms se crea un copo ❄️ con posición, tamaño y velocidad aleatoria:
setInterval(createSnowflake, 250);
3️⃣ Los emojis que aparecen cuando pasas el dedo o mouse
Aquí viene lo divertido: se detecta tu movimiento y se generan pequeños “estallidos” de emojis.
document.addEventListener("pointermove", handlePointerMove, { passive: true });
Y sí, funcionan perfectamente en celular, que es donde este efecto se siente más juguetón.
Cada estallido genera varios emojis aleatoriamente que flotan y se desvanecen, como si activaras un hechizo navideño cada vez que tocas la pantalla.
// =========================
// COUNTDOWN A VACACIONES
// =========================
// Función para calcular el tiempo restante hasta una fecha y hora específicas
function calculateTimeUntil(targetDateTime) {
const now = new Date();
const target = new Date(targetDateTime);
const timeDiff = target - now;
return timeDiff;
}
// Actualizar el contador en pantalla
function updateCountdown() {
// Fecha objetivo: 19 de diciembre a las 3:00 p.m.
const targetDateTime = new Date("2025-12-19T15:00:00");
const countdownElement = document.getElementById("days");
const timeLeft = calculateTimeUntil(targetDateTime);
if (timeLeft > 0) {
const days = Math.floor(timeLeft / (1000 * 60 * 60 * 24));
const hours = Math.floor(
(timeLeft % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)
);
const minutes = Math.floor(
(timeLeft % (1000 * 60 * 60)) / (1000 * 60)
);
const seconds = Math.floor((timeLeft % (1000 * 60)) / 1000);
countdownElement.textContent =
`Faltan ${days}d ${hours}h ${minutes}m ${seconds}s para las vacaciones 🎉`;
} else {
countdownElement.textContent =
"¡Las vacaciones ya comenzaron! 🌴☀️🏖️";
}
}
// =========================
// NIEVE (SOLO COPOS ❄️)
// =========================
function createSnowflake() {
const emojiContainer = document.getElementById("emoji-container");
if (!emojiContainer) return;
const snowflake = document.createElement("div");
snowflake.textContent = "❄️";
snowflake.classList.add("snowflake");
// Posición aleatoria horizontal
snowflake.style.left = Math.random() * 100 + "vw";
// Duración de la caída (un poco aleatoria)
const duration = Math.random() * 5 + 5; // 5s a 10s
snowflake.style.animationDuration = duration + "s";
// Tamaño aleatorio
const size = Math.random() * 1.3 + 1; // 1rem - 2.3rem aprox
snowflake.style.fontSize = size + "rem";
emojiContainer.appendChild(snowflake);
setTimeout(() => {
snowflake.remove();
}, duration * 1000 + 500);
}
function startSnow() {
// Nieva suavecito
setInterval(createSnowflake, 250);
}
// =========================
// EMOJIS AL PASAR EL DEDO
// =========================
const trailEmojis = [
"🎄", "🎅", "🤶", "🦌", "☃️", "⛄", "🎁",
"🌟", "🕯️", "🧤", "🧣", "🍪", "☕", "🍫", "🎀"
];
let lastEmojiTime = 0;
// Crea un solo emoji en la posición indicada
function createTrailEmoji(x, y) {
const emojiContainer = document.getElementById("emoji-container");
if (!emojiContainer) return;
const emoji = document.createElement("div");
emoji.textContent =
trailEmojis[Math.floor(Math.random() * trailEmojis.length)];
emoji.classList.add("emoji-trail");
// Posición absoluta según el dedo / mouse
emoji.style.left = x + "px";
emoji.style.top = y + "px";
// Tamaño aleatorio para que se vea más vivo
const size = Math.random() * 0.8 + 1.2; // 1.2rem - 2rem
emoji.style.fontSize = size + "rem";
emojiContainer.appendChild(emoji);
// Se quedan más tiempo en pantalla
setTimeout(() => {
emoji.remove();
}, 3500);
}
// CREA VARIOS EMOJIS CERCA DEL PUNTO
function spawnEmojiBurst(x, y) {
const count = 4 + Math.floor(Math.random() * 3); // entre 4 y 6 emojis
for (let i = 0; i < count; i++) {
const offsetX = (Math.random() - 0.5) * 60; // -30px a +30px
const offsetY = (Math.random() - 0.5) * 60;
createTrailEmoji(x + offsetX, y + offsetY);
}
}
// Maneja el movimiento del mouse / dedo con throttle
function handlePointerMove(e) {
const now = Date.now();
// Más frecuente para que salgan más emojis
if (now - lastEmojiTime < 30) return;
lastEmojiTime = now;
let x, y;
if (e.touches && e.touches.length > 0) {
x = e.touches[0].clientX;
y = e.touches[0].clientY;
} else {
x = e.clientX;
y = e.clientY;
}
if (x == null || y == null) return;
spawnEmojiBurst(x, y);
}
// =========================
// INICIO
// =========================
document.addEventListener("DOMContentLoaded", () => {
// Inicia el contador
updateCountdown();
setInterval(updateCountdown, 1000);
// Inicia la nieve
startSnow();
// Para mouse / pointer
document.addEventListener("pointermove", handlePointerMove, {
passive: true,
});
// Fallback por si algún navegador usa solo touchmove
document.addEventListener("touchmove", handlePointerMove, {
passive: true,
});
});
🤖 ¿Y la IA en todo esto?
Yo escribí la mayor parte del código y la estructura, pero le pedí a la IA que:
✔ me sugiriera animaciones más suaves
✔ ajustara tiempos y movimientos para hacerlo más mágico
✔ me ayudara con la parte responsiva
✔ aportara ideas para el efecto de estallido de emojis
Fue un muy buen experimento:
yo puse la idea, la lógica y el diseño…
la IA aportó finesse ✨.
🎁 PROMPT: así puedes pedirle a otra IA que te genere algo similar
Quiero que me generes una mini aplicación web navideña con HTML, CSS y JavaScript.
Debe tener un contador regresivo a una fecha específica, un fondo con nieve animada
(copos ❄️), y un efecto donde al mover el mouse o el dedo aparezcan emojis navideños
en pequeños estallidos con animación.
La app debe ser responsiva, con un contenedor central más pequeño en móvil, estilo
navideño agradable y animaciones suaves.
No uses librerías externas.
Explica el código paso a paso.
