El problema
Un portafolio de junior suele ser una lista de bullets o un template comprado. Yo quería otra cosa: un sitio que demuestre el oficio en vez de describirlo — que se note que controlo el DOM, el CSS y la animación sin esconderme detrás de un framework — y que, de paso, le enseñe algo a quien entra.
La decisión
Lo dividí en dos productos bajo la misma marca:
- micro.lab — una galería de 22 microinteracciones con mini-explicación: ves el efecto, lees el porqué y te llevas el código.
- Portafolio — trayectoria (Teletón, Automatismos Lau…), proyectos, CV descargable y contacto.
Y una regla incómoda a propósito: cero frameworks de UI. HTML, CSS y JavaScript modular. Si algo se mueve, es porque yo escribí cómo se mueve.
Tres retos técnicos (con código)
En vez de listar tecnologías, prefiero mostrarte tres problemas reales que tuve que resolver — con el código de verdad y la lección que me dejó cada uno.
Un contador que cobra vida
Los números del portafolio (22 demos, etc.) no aparecen de golpe: suben desde cero y desaceleran al final, justo cuando entran en pantalla. Se siente vivo, pero son solo tres piezas trabajando juntas:
// 1) una curva que desacelera al final (easing)
const easeOut = t => 1 - Math.pow(1 - t, 3);
// 2) requestAnimationFrame: animar cuadro a cuadro
function subir(el, fin, dur = 1400) {
const ini = performance.now();
(function paso(ahora) {
const t = Math.min((ahora - ini) / dur, 1);
el.textContent = Math.round(easeOut(t) * fin);
if (t < 1) requestAnimationFrame(paso);
})(ini);
}
// 3) IntersectionObserver: arranca cuando el número se ve
new IntersectionObserver(([e], obs) => {
if (!e.isIntersecting) return;
subir(e.target, +e.target.dataset.cuenta);
obs.unobserve(e.target);
}).observe(numero);La lección: una animación que se siente bien casi nunca es azar: es easing (para que no sea lineal y robótico) + el momento correcto (que arranque cuando se ve, no antes).
“Cambié el código y no se veía”
El bug más frustrante del proyecto no fue de lógica: subía un cambio, recargaba… y seguía viendo la versión vieja. Solo en incógnito aparecía lo nuevo. El culpable era la caché — el navegador y el service worker guardaban el CSS/JS viejo. La solución fue pedir el código primero a la red:
// Para mi propio código voy primero a la red, saltándome
// la caché del navegador (cache: 'reload'). Si hay internet
// muestro lo nuevo y guardo copia; si no, caigo al caché.
function redPrimero(req) {
return fetch(req, { cache: 'reload' })
.then(res => { guardarCopia(req, res); return res; })
.catch(() => caches.match(req));
}
// Y en las cabeceras del hosting, para el código:
// Cache-Control: max-age=0, must-revalidateLa lección: en una PWA tu peor enemigo no es un bug, es la caché vieja pegada. “Network-first” para tu propio código = el deploy se ve al primer refresh, no al tercero.
Un solo truco para casi todo el movimiento
El cursor personalizado, el búho mascota y los “seguidores” que persiguen al mouse comparten una sola línea de matemática — interpolación lineal (lerp): en cada cuadro, acércate un porcentaje a la meta.
// lerp: muévete un 15% de lo que te falta, cada frame.
pos.x += (destino.x - pos.x) * 0.15;
pos.y += (destino.y - pos.y) * 0.15;
// 0.15 = qué tan suave se siente. Más bajo = más lento y elegante.La lección: no necesitas una librería de física para que algo se sienta vivo. Una primitiva pequeña y buena (lerp), bien reutilizada, rinde más que una dependencia de 100 KB.
El resultado
El proyecto vive en pabloaravena.com: HTTPS, deploy continuo desde GitHub a Cloudflare Pages, PWA (manifest + service worker), tema claro/oscuro con transición, bilingüe ES/EN y formulario de contacto. Es a la vez mi carta de presentación y un laboratorio público de frontend — 22 demos que cualquiera puede abrir, leer y copiar.
Lo que aprendí
Hubo días en que tiraba código y no lograba lo que tenía en la cabeza. Pero construir cada pieza a mano me hizo entender por qué funciona, no solo que funciona. Ese es el punto de todo esto: nunca fue un proyecto para lucrar — era para mostrar lo que me gusta hacer y, ojalá, enseñarle algo a alguien que recién parte.