Replace AnimationCurve curve value inputs during preprocessing#4290
Replace AnimationCurve curve value inputs during preprocessing#4290Gavin-Niederman wants to merge 8 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces the graphene-animation crate, which implements animation primitives like Keyframe, InterpolationBehavior, and AnimationCurve for the Graphene node system. It integrates these curves into the node registry, adds an eval_curve node, and updates the preprocessor to replace AnimationCurve inputs with eval_curve nodes. The feedback highlights two critical issues: first, the preprocessor's node visitor skips preprocessing inputs on nested Network nodes due to an early continue; second, evaluating bezier curves with non-finite handle coordinates can lead to panics or infinite loops, requiring sanitization of the handles.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| for node in network.nodes.values_mut() { | ||
| if let DocumentNodeImplementation::Network(nested) = &mut node.implementation { | ||
| inner(nested, visitor)?; | ||
| continue; | ||
| } | ||
|
|
||
| visitor(node, &mut inserts)?; | ||
| } |
There was a problem hiding this comment.
By using continue when encountering a Network node, the preprocessor skips visiting the inputs of the Network node itself. If a nested network (group) has constant inputs (like an AnimationCurve or Resource), they will not be preprocessed, leading to runtime type mismatches or evaluation errors. Removing the continue allows the preprocessor to correctly visit and replace inputs on Network nodes in the parent network context.
for node in network.nodes.values_mut() {
if let DocumentNodeImplementation::Network(nested) = &mut node.implementation {
inner(nested, visitor)?;
}
visitor(node, &mut inserts)?;
}| InterpolationBehavior::Bezier { right_handle } => { | ||
| let start = segment_start.knot; | ||
| let end = segment_end.knot; | ||
| let left_handle = segment_end.left_handle.unwrap_or(end); |
There was a problem hiding this comment.
If right_handle or left_handle contains non-finite values (such as NaN or Infinity), the clamp or solve_itp operations can panic or loop infinitely. Sanitizing these handles to ensure they are finite before processing prevents these robustness issues.
| InterpolationBehavior::Bezier { right_handle } => { | |
| let start = segment_start.knot; | |
| let end = segment_end.knot; | |
| let left_handle = segment_end.left_handle.unwrap_or(end); | |
| InterpolationBehavior::Bezier { right_handle } => { | |
| let start = segment_start.knot; | |
| let end = segment_end.knot; | |
| let right_handle = if right_handle.is_finite() { right_handle } else { start }; | |
| let left_handle = segment_end.left_handle.filter(|h| h.is_finite()).unwrap_or(end); |
This PR adds a
replace_animation_curve_inputsmethod to the preprocessor that replaces anyTaggedValue::AnimationCurve(curve)value inputs in the network neweval_curvenodes. It also refactors out some of the logic inreplace_resource_inputsintovisit_*functions to reduce code duplication.In the future, this will be used in the expose dialog to allow exposing inputs to the timeline.
This PR is a follow-up to #4164. Until that PR is merged, this one will include its commits.
Demo
untitled.mp4