47fac22230
- .claude/CLAUDE.md - .claude/commands/subagentes.md - .claude/rules/INDEX.md - .mcp.json - bash/functions/cybersecurity/analyze_dns.md - bash/functions/cybersecurity/audit_http_headers.md - bash/functions/cybersecurity/audit_ssh_config.md - bash/functions/cybersecurity/check_firewall.md - bash/functions/cybersecurity/detect_suspicious_users.md - bash/functions/cybersecurity/encrypt_file.md - ... Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4.9 KiB
4.9 KiB
name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, tested, tests, test_file_path, file_path, framework, params, output
| name | kind | lang | domain | version | purity | signature | description | tags | uses_functions | uses_types | returns | returns_optional | error_type | imports | tested | tests | test_file_path | file_path | framework | params | output | |||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| timeline | component | cpp | core | 1.0.0 | pure | bool fn::timeline_widget(const char* id, fn::TimelineState&, ImVec2 size = {-1,200}) + float fn::track_value_at(const Track&, float t) + void fn::timeline_update(TimelineState&, float dt) | Widget tipo DAW: tracks horizontales con keyframes draggable, scrub, play/pause/loop, evaluacion track_value_at(time) interpolando entre keyframes con la Ease de cada keyframe destino. Estado puro (TimelineState) + render con tokens. |
|
|
false |
|
false | cpp/functions/core/timeline.cpp | imgui |
|
true en el frame en que el usuario interactua (drag de keyframe, scrub, play/pause/reset, cambio de duration o loop) |
timeline
Widget de timeline tipo DAW para animar valores escalares en el tiempo. Cada Track es un canal con keyframes (time, value, ease); track_value_at(time) interpola entre keyframes consecutivos aplicando la Ease de la keyframe destino.
Tipos
struct fn::Keyframe {
float time;
float value;
fn::tween::Ease ease = fn::tween::Ease::Linear;
};
struct fn::Track {
std::string name;
std::vector<Keyframe> keys; // ordenadas por time
};
struct fn::TimelineState {
std::vector<Track> tracks;
float current_time = 0.0f;
float duration = 5.0f;
bool playing = false;
bool loop = true;
};
API
// Pure: interp del valor del track en t
float fn::track_value_at(const Track&, float t);
// Avanza current_time si playing; loop o satura segun flag
void fn::timeline_update(TimelineState&, float dt);
// Render del widget. Devuelve true si hubo interaccion del usuario.
bool fn::timeline_widget(const char* id, TimelineState&, ImVec2 size = {-1, 200});
Ejemplo
static fn::TimelineState tl;
if (tl.tracks.empty()) {
tl.tracks.push_back({"hue", {{0, 0.0f}, {2.0f, 1.0f, fn::tween::Ease::OutCubic}, {4.0f, 0.0f}}});
tl.tracks.push_back({"amp", {{0, 0.2f}, {3.0f, 1.0f, fn::tween::Ease::InOutQuad}}});
tl.duration = 4.0f;
}
float dt = ImGui::GetIO().DeltaTime;
fn::timeline_update(tl, dt);
float hue = fn::track_value_at(tl.tracks[0], tl.current_time);
float amp = fn::track_value_at(tl.tracks[1], tl.current_time);
ImGui::Text("hue=%.3f amp=%.3f", hue, amp);
fn::timeline_widget("##my_tl", tl);
Comportamiento de track_value_at
- 0 keys → devuelve 0.0
- 1 key → devuelve siempre
keys[0].value - t antes de la primera key →
keys.front().value(clamp izq) - t despues de la ultima key →
keys.back().value(clamp der) - Entre dos keys
ayb:u = (t - a.time) / (b.time - a.time)k = tween::apply(b.ease, u)(la ease es la "curva entrante" hasta b)- resultado =
a.value + (b.value - a.value) * k
Smoke tests (linear)
Track con 2 keys {(0,0), (1,1)} con ease=Linear:
track_value_at(t, 0.0) == 0.0track_value_at(t, 0.5) == 0.5track_value_at(t, 1.0) == 1.0
Render
- Header: Play/Pause + Reset + DragFloat de duration + indicador
t=...s+ checkbox loop. - Ruler: ticks cada 0.5s, etiqueta cada segundo, scrub con click+drag.
- Tracks: filas horizontales con nombre a la izquierda (k_label_w=80px) y keyframes como diamantes draggable.
- Playhead: linea vertical
primary_lightcon triangulo en la cabeza del ruler. - Colores via
fn_tokens(surface bg, border, primary keys, text labels).
Interaccion
- Drag horizontal de un diamante: cambia
key.time. Al soltar (o cualquier frame conchanged), las keys se reordenan por tiempo. - Scrub: click + drag en el ruler mueve
current_time. - Play/Pause/Reset: cambian
playingycurrent_time. - Duration drag: clampada >= 0.1s.
Decisiones
- Ease en la keyframe destino: convencion comun en animation toolings (Maya, AfterEffects). La curva define como llegamos a esa key.
- Sin edicion vertical (value drag): para mantener el widget simple. Si hace falta editar
valuecon la UI, el caller puede mostrar un campo numerico al lado o dentro de un popup. - Sort en cada cambio: O(n log n) por track no es problema para timelines tipicas (<100 keys); evita estado intermedio "drag in progress".
Limitaciones / TODO
- No hay editor de
easepor keyframe en el MVP (queda enLinearsalvo que el caller lo configure). - No hay seleccion multiple ni copy/paste de keyframes.
- No hay zoom horizontal: la timeline siempre encaja
durationcompleta al ancho del widget.