Web App / Editorial Storytelling · Colombia · 2025
14 Ceros · Las reconversiones monetarias de Venezuela
SPA de scroll storytelling que cuenta 13 años de hiperinflación venezolana a través de un billete que pierde sus ceros en pantalla. Datos oficiales, cero adjetivos.
Una SPA de scroll storytelling donde el lector recorre las tres reconversiones monetarias de Venezuela (2008, 2018, 2021) a través del mismo personaje: un billete de 1.000.000 Bs. El clímax es una animación que borra sus 6 ceros en pantalla — el millón se convierte en 1. 10 secciones narrativas, calculadora interactiva de equivalencias, comparador regional y "máquina del tiempo" que muestra qué representaría 1 Bs digital de hoy en 2007 (100 billones).
El reto
Contar 13 años de hiperinflación venezolana sin caer en lo editorial, lo político ni lo abstracto. La cifra clave — 14 órdenes de magnitud entre el bolívar de 2007 y el de 2021 — no significa nada como número plano. Necesitaba sentirla.
Lo que construí
SPA de scroll storytelling con un billete-personaje como hilo conductor de las tres reconversiones.
- 10 secciones narrativas que recorren las reconversiones de 2008, 2018 y 2021.
- Billete de 1.000.000 Bs renderizado en SVG inline (~150 elementos: guilloché, retrato, sellos, hilo de seguridad), con float CSS continuo y parallax 3D ligado al scroll.
- Animación clímax: los 6 ceros del billete se borran en pantalla — el millón se convierte en 1.
- Calculadora interactiva de equivalencias entre bolívares de cada época.
- Comparador regional contra otros países latinoamericanos.
- "Máquina del tiempo": qué representaría 1 Bs digital de hoy en 2007 (100 billones), con count-up animado.
- Accesibilidad: prefers-reduced-motion desactiva todas las animaciones y muestra contenido estático.
Stack y arquitectura
Nuxt 3 SSG (preset vercel-static) — build estático, sin servidor. La interactividad vive 100% en cliente.
- Nuxt 3 + Vue 3 Composition API + TypeScript.
- Tailwind v3 con design tokens custom (dark mode, escala 8px).
- GSAP + ScrollTrigger para scrub atado a scroll (parallax del billete, rotación 3D, secuencias complejas).
- D3.js v7 para la gráfica de la caída del Bs.F con scroll-scrubbing.
- IntersectionObserver + CSS transitions para los reveals — probado: más robusto que GSAP para casos simples.
- requestAnimationFrame directo para el count-up dinámico (sin dependencias para algo que es 20 líneas).
- Vercel deploy automático desde push a main.
Decisiones notables
- Paleta dark + tres acentos: gold #f4a261 (la moneda), crisis red #e63946 (Venezuela, énfasis dramático), data cyan #a8dadc (visualizaciones). Tipografía editorial: Playfair Display + Inter + JetBrains Mono.
- Ningún adjetivo editorial en el copy: cada sección presenta la cifra oficial (Gaceta Oficial, BCV, FMI, CEPAL) y deja que el contraste hable. "Tres reconversiones. Catorce ceros borrados del mapa. Los números hablan solos."
- El billete como personaje recurrente — no es un asset decorativo, es el protagonista que evoluciona sección a sección.
- Bug del gsap.context que no se encuentra a sí mismo: los ScrollTrigger con trigger: "#hero" desde dentro de gsap.context(scope=root.value) nunca disparaban porque el selector busca descendientes, no el propio scope. Fix: pasar root.value directamente como trigger.
- Reveals que se congelaban a mitad: gsap.from() con immediateRender: false dejaba elementos en opacity:0 permanentemente cuando HMR o lazy components interrumpían el timeline. Reescritura completa a IntersectionObserver + CSS transitions con unobserve() al primer disparo.
- Count-up dinámico sin GSAP: 100.000.000.000.000 cuenta de 0 al final en 2.5s con requestAnimationFrame directo. Default al valor final + safety timer al doble de la duración. font-variant-numeric: tabular-nums evita el jitter de ancho mientras los dígitos cambian.
- Cada .reveal tiene fallback explícito a opacity: 1 !important bajo prefers-reduced-motion — JS lento nunca deja contenido invisible.
Aprendizajes
- GSAP es excelente para scrub y secuencias complejas, pero los reveals simples viven mejor en IntersectionObserver + CSS. La diferencia: GSAP necesita su ticker (rAF) corriendo y su gsap.context lifecycle bien orquestado con Vue. CSS transitions son atómicas — el compositor del browser las maneja sin depender de nada externo.
- Para piezas de portafolio donde la animación es el mensaje, los defaults importan más que las animaciones. Si algo falla, el contenido tiene que seguir siendo legible.
- Cada animación de este sitio degrada a una versión estática que sigue contando la historia. Reduced motion + opacity fallback + count-up con safety timer no son features extras: son requisitos.
- Datos oficiales (BCV, CEPAL, FMI, Gacetas Oficiales) dan autoridad que ningún adjetivo editorial puede comprar. Citar fuentes al pie convierte un microsite en un documento.