Skip to content

Replace AnimationCurve curve value inputs during preprocessing#4290

Draft
Gavin-Niederman wants to merge 8 commits into
GraphiteEditor:masterfrom
Gavin-Niederman:add/animation-curve-preprocessing
Draft

Replace AnimationCurve curve value inputs during preprocessing#4290
Gavin-Niederman wants to merge 8 commits into
GraphiteEditor:masterfrom
Gavin-Niederman:add/animation-curve-preprocessing

Conversation

@Gavin-Niederman

Copy link
Copy Markdown

This PR adds a replace_animation_curve_inputs method to the preprocessor that replaces any TaggedValue::AnimationCurve(curve) value inputs in the network new eval_curve nodes. It also refactors out some of the logic in replace_resource_inputs into visit_* 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

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +51 to 58
for node in network.nodes.values_mut() {
if let DocumentNodeImplementation::Network(nested) = &mut node.implementation {
inner(nested, visitor)?;
continue;
}

visitor(node, &mut inserts)?;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

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)?;
			}

Comment on lines +91 to +94
InterpolationBehavior::Bezier { right_handle } => {
let start = segment_start.knot;
let end = segment_end.knot;
let left_handle = segment_end.left_handle.unwrap_or(end);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
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);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant