PTENES
MÓDULO 4.3

📈 Data-Story

Los datos por sí solos son aburridos. Los datos contados como una historia son memorables. Este módulo crea un video que guía al espectador por una narrativa de números: gráficos animados, contadores, comparaciones y texto destacado, todo orquestado con Series y transiciones cross-dissolve.

6
Temas
45
Minutos
Avanzado
Nivel
Proyecto
Tipo
datos JSON/props chart-animation donut-chart stat-counter comparison-chart Data-Story narrativa coherente con los datos
1

📖 Estructura narrativa — el arco del dato

Un Data-Story eficaz no empieza con el gráfico — empieza con el problema. El espectador necesita entender qué está en juego antes de ver el número. La secuencia de escenas crea automáticamente ese arco narrativo cuando ordenas bien el Series.

📈 El arco de 5 escenas

1.Contexto — una frase que define el problema. Ej.: "En 2025, el 68% de los videos se vieron sin sonido."
2.Dato central — el número más importante, animado con un stat-counter grande.
3.Proporción — donut chart que muestra cómo se divide ese número.
4.Tendencia — line-chart que muestra la evolución a lo largo del tiempo.
5.Conclusión — texto destacado con el mensaje central + llamado a la acción.

💡 Regla de 5–8 segundos por escena

Cada escena de datos debe durar entre 5 y 8 segundos. Menos de 5 s: el espectador no procesa el dato. Más de 8 s: el ritmo decae y parece una presentación de PowerPoint. Las transiciones cross-dissolve de 10–15 frames cubren el cambio sin interrumpir el flujo.

5 escenas
Arco completo
5–8 s
Por escena de datos
Contexto
Siempre primero
Total
~30–45 s
2

📊 Gráfico de barras animado — chart-animation

O chart-animation.tsx usa un array de valores y anima cada barra creciendo de 0 hasta su altura proporcional. El stagger entre barras hace que el gráfico parezca "llenarse": el ojo del espectador sigue la barra más alta, que normalmente representa el dato más importante.

Barras con stagger chart-animation.tsx
const data = [42, 68, 55, 91, 37]; // valores %
const maxH = 200;        // px de altura máxima

{data.map((val, i) => {
  const delay = i * 6;  // stagger de 6 frames
  const barHeight = interpolate(
    frame, [delay, delay + 45],
    [0, (val / 100) * maxH],
    { extrapolateRight: "clamp", easing: Easing.out(Easing.quad) }
  );
  // rótulo aparece quando barra chega ao topo
  const labelOpacity = interpolate(
    frame, [delay + 40, delay + 55], [0, 1],
    { extrapolateRight: "clamp" }
  );
  return <div key={i} style={{ height: `${barHeight}px`, opacity: 1 }}>
    <span style={{ opacity: labelOpacity }}>{val}%</span>
  </div>;
})}

✓ Barras que funcionan

  • ✓Stagger de 4–8 frames entre barras: perceptible sin ser lento.
  • ✓La etiqueta aparece cuando termina la barra: 15 frames después del retraso de la barra.
  • ✓Easing.out para crecer: empieza rápido y desacelera al llegar a la cima.

✗ Errores de gráficos

  • ✗Todas las barras crecen al mismo tiempo: se pierde el efecto de revelación.
  • ✗La etiqueta aparece antes de que termine la barra: parece un error.
  • ✗Easing.in para crecer: empieza demasiado lento y parece trabado.
Stagger
delay = i * 6
Altura
(val/100) * maxH
Easing
out(quad)
Etiqueta
+15f después de la barra
3

🍩 Gráfico de dona de proporción

O donut-chart.tsx usa SVG con stroke-dasharray e stroke-dashoffset animados. Cada segmento es un <circle> con la longitud del arco calculada a partir del porcentaje. El reveal progresivo sigue la misma lógica de las barras: Easing.out, revelación de cada porción con un pequeño stagger.

1

Calcular la circunferencia y los offsets

const c = 2 * Math.PI * r — circunferencia del círculo. Para una porción del 42%, la longitud del arco es c * 0.42. O strokeDasharray é "arco restante" y el offset se rota para posicionarlo correctamente.

2

Animación de strokeDashoffset

Empieza con dashoffset = c (sector invisible) y anima hasta dashoffset = c - arco (sector completo). El resultado es el sector "dibujándose" en sentido horario.

3

El subtítulo aparece después del reveal

Cada color del gráfico de dona tiene una leyenda que aparece gradualmente cuando termina de aparecer la porción correspondiente. La leyenda y la porción quedan asociadas visualmente.

strokeDasharray
arco + resto
strokeDashoffset
c → c-arco
Rotación
-90° para iniciar desde arriba
Subtítulo
fade después de reveal
4

🔢 stat-counter y text-highlight combinados

La escena del dato central combina dos plantillas: stat-counter.tsx con el número animándose de 0 hasta el valor, y text-highlight.tsx que destaca una frase contextual con un background colorido que crece del 0% al 100% del width. Ambos entran en stagger: primero el número y luego el texto.

Counter + highlight en secuencia DataScene.tsx
const frame = useCurrentFrame();

// número conta de 0 → 68% em 60 frames
const pct = Math.round(interpolate(
  frame, [0, 60], [0, 68],
  { easing: Easing.out(Easing.cubic), extrapolateRight: "clamp" }
));

// highlight cresce de 0 → 100% a partir do frame 50
const hlWidth = interpolate(
  frame, [50, 80], [0, 100],
  { extrapolateLeft: "clamp", extrapolateRight: "clamp" }
);

return <AbsoluteFill style={{ display:"flex", flexDirection:"column", alignItems:"center", justifyContent:"center" }}>
  <span style={{ fontSize: 120, fontWeight: 800, color: "#fbbf24" }}>{pct}%</span>
  <div style={{ position: "relative" }}>
    <div style={{ position:"absolute", inset:0, background:"rgba(251,191,36,0.25)", width:`${hlWidth}%` }}/>
    <span>dos vídeos são assistidos sem som</span>
  </div>
</AbsoluteFill>;
Counter
0 → valor en 60f
Destacado
width 0 → 100%
Stagger
Counter primero
Fuente
120px+ para generar impacto
5

⚔️ Gráfico de comparación — comparison-chart

O comparison-chart.tsx muestra dos barras lado a lado que crecen de forma diferente: el argumento visual más poderoso para mostrar una diferencia. La regla de oro: la barra «mala» aparece primero, crece un poco y, entonces, la barra «buena» la supera de forma dramática.

✓ Comparación impactante

  • ✓La barra negativa (roja) aparece primero: ancla baja.
  • ✓La barra positiva (ámbar/verde) crece después y la supera: drama visual.
  • ✓La etiqueta de diferencia porcentual aparece con spring en la parte superior de la barra más alta.

✗ Comparación débil

  • ✗Ambas barras crecen al mismo tiempo: se pierde el efecto de «adelantamiento».
  • ✗Colores similares en ambos lados: la comparación no queda clara.
  • ✗Sin una etiqueta de diferencia, el espectador tiene que calcularla mentalmente.
Orden
Malo → bueno
Delay
+15f para la 2.ª barra
Colores
Rojo vs. ámbar
Δ%
Spring en la parte superior
6

🔀 Transiciones cross-dissolve entre escenas

El cross-dissolve es la transición ideal para Data-Story: lo bastante fluida para no interrumpir el razonamiento, pero marca claramente el cambio de escena. Se implementa superponiendo dos Sequence con overlap y animando las opacidades en sentidos opuestos durante los frames de superposición.

Fundido cruzado manual con superposición DataStory.tsx
// Cena A: frames 0–90 | Cena B: frames 78–168 | overlap: 78–90
const DISSOLVE = 12; // frames de sobreposição

return (
  <AbsoluteFill>
    <Sequence from={0} durationInFrames={90}>
      <div style={{ opacity: interpolate(frame,
        [90 - DISSOLVE, 90], [1, 0], { extrapolateLeft: "clamp", extrapolateRight: "clamp" }) }}>
        <CenaA />
      </div>
    </Sequence>
    <Sequence from={90 - DISSOLVE}>
      <div style={{ opacity: interpolate(frame,
        [90 - DISSOLVE, 90], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" }) }}>
        <CenaB />
      </div>
    </Sequence>
  </AbsoluteFill>
);

💡 10–15 fotogramas de disolución

Una disolvencia de 10 fotogramas (0.33 s a 30fps) casi no se percibe, pero suaviza el corte. Una disolvencia de 15 fotogramas (0.5 s) se nota y es más elegante. Por encima de 20 fotogramas empieza a parecer intencionalmente dramática; úsala solo si quieres ese efecto.

Overlap
10–15 fotogramas
Escena A
opacity 1 → 0
Escena B
opacity 0 → 1
extrapolate
clamp en ambos

🏁 Resumen del módulo

✓
Arco de 5 escenas — contexto → dato → proporción → tendencia → conclusión.
✓
Barras con stagger — delay = i * 6, etiqueta +15f después de la barra, Easing.out(quad).
✓
Dona mediante SVG — strokeDashoffset animado de c a c-arco con rotación de -90°.
✓
Counter + highlight — número grande con width animada debajo del texto contextual.
✓
Comparación dramática — la barra mala aparece primero; la buena la supera con un delay de 15 fotogramas.
✓
Fundido cruzado — 12 frames de superposición, opacidades inversas entre escenas consecutivas.

Próximo módulo:

4.4 — Reels / Shorts: video vertical 9:16, typewriter, glitch, sound-wave, bokeh y recordatorio para suscribirse.