fad4006f60
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
179 lines
6.1 KiB
Markdown
179 lines
6.1 KiB
Markdown
---
|
|
id: "0031"
|
|
title: "C++ animation curves (timeline + bezier_editor + tween_curves)"
|
|
status: completado
|
|
type: feature
|
|
domain:
|
|
- cpp-stack
|
|
scope: multi-app
|
|
priority: media
|
|
depends: []
|
|
blocks: []
|
|
related: []
|
|
created: 2026-05-17
|
|
updated: 2026-05-17
|
|
tags: []
|
|
---
|
|
# 0031 — C++ animation curves (timeline + bezier_editor + tween_curves)
|
|
|
|
## APP Metadata
|
|
|
|
| Campo | Valor |
|
|
|-------|-------|
|
|
| **ID** | 0031 |
|
|
| **Estado** | pendiente |
|
|
| **Prioridad** | media |
|
|
| **Tipo** | feature — C++ core (cpp/functions/core) |
|
|
|
|
## Dependencias
|
|
|
|
`tokens_cpp_core`. Independiente de los demas issues.
|
|
|
|
**Desbloquea:** animar uniforms en `shaders_lab` con keyframes; easing reusable en transiciones de UI; control fino sobre animaciones procedurales.
|
|
|
|
---
|
|
|
|
## Objetivo
|
|
|
|
Tres primitivos:
|
|
|
|
1. **`tween_curves_cpp_core`** — set de funciones de easing puras (Penner): linear, ease_in/out_quad/cubic/expo, elastic, bounce. Header-only.
|
|
2. **`bezier_editor_cpp_core`** — editor visual de una curva cubica Bezier (4 puntos de control), evaluacion `f(t)` para t∈[0,1]. Estado puro + render en ImGui canvas.
|
|
3. **`timeline_cpp_core`** — widget tipo DAW: tracks horizontales con keyframes draggable, scrub, play/pause, evaluacion `track_value_at(time)` con interp lineal o curve por keyframe.
|
|
|
|
Demo en `primitives_gallery` con un slider animado por timeline + curva bezier para ease.
|
|
|
|
## Contexto
|
|
|
|
`shaders_lab` tiene sliders manuales para uniforms. No hay forma de:
|
|
- Animar un uniform con curva temporal.
|
|
- Disenar transiciones suaves reusables.
|
|
|
|
Las funciones de easing son utiles tambien fuera de animacion (interpolacion de colores, rampas).
|
|
|
|
## Arquitectura
|
|
|
|
```
|
|
cpp/functions/core/
|
|
├── tween_curves.h # NEW (header-only ok)
|
|
├── tween_curves.cpp # NEW (si hace falta .cpp)
|
|
├── tween_curves.md # NEW
|
|
├── bezier_editor.h # NEW
|
|
├── bezier_editor.cpp # NEW
|
|
├── bezier_editor.md # NEW
|
|
├── timeline.h # NEW
|
|
├── timeline.cpp # NEW
|
|
└── timeline.md # NEW
|
|
cpp/apps/primitives_gallery/
|
|
├── demos_animation.cpp # NEW
|
|
├── demos.h # MOD
|
|
├── main.cpp # MOD
|
|
└── CMakeLists.txt # MOD
|
|
```
|
|
|
|
### API propuesta
|
|
|
|
```cpp
|
|
namespace fn {
|
|
|
|
// --- tween_curves (puro, header-only ok) ---
|
|
namespace tween {
|
|
inline float linear(float t) { return t; }
|
|
inline float in_quad(float t) { return t*t; }
|
|
inline float out_quad(float t) { return 1 - (1-t)*(1-t); }
|
|
inline float in_out_cubic(float t) { /* Penner */ }
|
|
inline float in_expo(float t);
|
|
inline float out_expo(float t);
|
|
inline float in_elastic(float t);
|
|
inline float out_elastic(float t);
|
|
inline float out_bounce(float t);
|
|
// ... ~15 easing funcs
|
|
|
|
enum class Ease { Linear, InQuad, OutQuad, InOutQuad, InCubic, OutCubic, /*...*/ };
|
|
float apply(Ease e, float t);
|
|
}
|
|
|
|
// --- bezier_editor (puro estado) ---
|
|
struct BezierCurve { ImVec2 p0{0,0}, p1{0.25f,0.0f}, p2{0.75f,1.0f}, p3{1,1}; };
|
|
float bezier_eval(const BezierCurve&, float t); // y at x=t
|
|
bool bezier_editor(const char* id, BezierCurve&, ImVec2 size = {200, 200}); // returns true if changed
|
|
|
|
// --- timeline ---
|
|
struct Keyframe { float time; float value; tween::Ease ease = tween::Ease::Linear; };
|
|
struct Track { std::string name; std::vector<Keyframe> keys; };
|
|
struct TimelineState {
|
|
std::vector<Track> tracks;
|
|
float current_time = 0.0f;
|
|
float duration = 5.0f;
|
|
bool playing = false;
|
|
};
|
|
float track_value_at(const Track&, float t); // interp puro
|
|
void timeline_update(TimelineState&, float dt); // avanza si playing
|
|
bool timeline_widget(const char* id, TimelineState&, ImVec2 size = {-1, 200}); // returns true if changed
|
|
}
|
|
```
|
|
|
|
## Tareas
|
|
|
|
### Fase 1 — tween_curves
|
|
|
|
- 1.1 Implementar las funciones Penner (referencia: easings.net). Header-only inline para que el compilador inline en hot paths.
|
|
- 1.2 `tween::apply(Ease, t)` con switch.
|
|
- 1.3 Tests: cada curva en t=0 y t=1 da 0 y 1 respectivamente (excepto elastic/bounce).
|
|
- 1.4 `.md`.
|
|
|
|
### Fase 2 — bezier_editor
|
|
|
|
- 2.1 `bezier_eval`: De Casteljau o forma polinomial. Implementacion puramente algebraica.
|
|
- 2.2 `bezier_editor`: canvas ImGui con 4 puntos draggable (p0/p3 fijos en {0,0}/{1,1} para easing). Dibuja la curva con `AddBezierCubic`.
|
|
- 2.3 Tests para `bezier_eval`.
|
|
- 2.4 `.md`.
|
|
|
|
### Fase 3 — timeline
|
|
|
|
- 3.1 `track_value_at`: encuentra el segmento (k_i, k_{i+1}), normaliza t, aplica `tween::apply(ease)`.
|
|
- 3.2 `timeline_update`: si `playing`, avanza `current_time += dt`; loop al llegar a duration.
|
|
- 3.3 `timeline_widget`: barra con tracks horizontales, keyframes como diamantes draggable, scrub time con click en barra superior, botones play/pause. Estilo basado en `tokens`.
|
|
- 3.4 Tests para `track_value_at` (linear).
|
|
- 3.5 `.md`.
|
|
|
|
### Fase 4 — Gallery demo
|
|
|
|
- 4.1 `demos_animation.cpp`:
|
|
- `demo_tween()`: dropdown de Ease + curva animandose contra el tiempo.
|
|
- `demo_bezier_editor()`: editor + plot de la curva resultante.
|
|
- `demo_timeline()`: timeline con 2 tracks ("hue", "amp") + slider que muestra `track_value_at(now)` para cada uno.
|
|
- 4.2 Registrar en gallery (3 entradas).
|
|
|
|
### Fase 5 — Tests + docs
|
|
|
|
- 5.1 Tests de easing y track_value_at.
|
|
- 5.2 `./fn index` + `./fn show` de los 3.
|
|
|
|
## Ejemplo de uso
|
|
|
|
```cpp
|
|
fn::TimelineState tl{};
|
|
tl.tracks.push_back({"hue", {{0, 0}, {2, 1}, {4, 0}}});
|
|
tl.duration = 4.0f;
|
|
tl.playing = true;
|
|
|
|
fn::run_app("anim", [&](float dt){
|
|
fn::timeline_update(tl, dt);
|
|
float h = fn::track_value_at(tl.tracks[0], tl.current_time);
|
|
ImGui::Text("hue = %.3f", h);
|
|
fn::timeline_widget("##tl", tl);
|
|
});
|
|
```
|
|
|
|
## Decisiones de diseño
|
|
|
|
- **Tween header-only**: codigo pequeño, alto uso → inline.
|
|
- **Bezier solo para easing (p0=0, p3=1)** en MVP. Generalizable si hace falta.
|
|
- **Timeline simple, no jerarquico**: tracks planos. Si hace falta layering en el futuro, otro issue.
|
|
|
|
## Riesgos
|
|
|
|
- **UX del bezier_editor**: precision de drag con mouse en canvas pequeño. Documentar tamaño minimo recomendado (180+).
|
|
- **Timeline drag race**: keyframe drag debe respetar orden temporal. Reordenar al soltar.
|