Skip to content

Support Bezier curve - #2781

Open
MarkYav wants to merge 4 commits into
google:mainfrom
MarkYav:support-bezier-curve
Open

Support Bezier curve#2781
MarkYav wants to merge 4 commits into
google:mainfrom
MarkYav:support-bezier-curve

Conversation

@MarkYav

@MarkYav MarkYav commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

WHAT

Adds full Remote Compose Bezier spline animation support by replacing static path translations with dynamic expression tree RemoteFloat evaluations. Furthermore, completely restructures the underlying Keyframe/Bezier rendering classes into single-responsibility, SLAP-enforced modular files.

WHY

Previously, bezier path lookups used static cubic easing arrays parsed from Lottie keyframes. To correctly enable state-driven multi-node spline paths (i.e. morphing Lottie vector geometries dynamically through variables on wear targets), Remote Compose paths required fully-typed RemoteFloat chained logic translating easing tangents seamlessly. The structural refactor addresses code density rules, moving monolithic handlers into dry helpers (less than 25 lines/method) which keeps the interpolation math legible and sustainable long-term.

HOW

  • Interpolation Engine: Migrates RemoteLottiePath generation strictly onto RemoteFloat evaluations relying heavily on native cubicEasing operations instead of simple interpolated float arrays.
  • Node Chaining: Built chainBezierAnimation, enabling deep array segments to execute Remote Compose property conditional cascades cleanly over timeline boundaries.
  • Topology Resiliency: Closed the rendering loops gracefully inside gatherShapes parsing vectors rather than singular objects, stopping runtime open path geometry boundary failures (IndexOutOfBoundsException) inherently.
  • Decoupled Architecture: Replaced the monolithic Animation.kt core with 4 explicitly-scoped responsibilities (AnimationUtils.kt, PositionAnimation.kt, VectorAnimation.kt, BezierAnimation.kt) all abiding strictly by SLAP paradigms (< 25-line ceilings by isolating low-level initialization routines in cleanly named builder methods).
  • Encapsulated inner iterative draw segments into an extension block via RemotePathScope.drawSplinePaths.

Checklist 📋

  • Add explicit visibility modifier and explicit return types for public declarations
  • Run spotless check
  • Run tests
  • Update metalava's signature text files

…zier paths.

- Refactors RemoteBezierValue mapping to store fully-typed RemoteFloat matrix values, ensuring AST constraints are tracked per parameter inside drawScope.remotePath.
- Translates dynamic segments recursively with chainBezierAnimation, enabling sequence looping across multi-keyframe structures.
- Parses and renders multiple path splines synchronously within gatherShapes.
- Fixes an IndexOutOfBoundsException edge case when evaluating rendering geometries for open paths.
- Disassembled monolithic Animation.kt core into granular, single-responsibility domain scopes (AnimationUtils.kt, PositionAnimation.kt, VectorAnimation.kt, BezierAnimation.kt).
- Centralized repetitive keyframe tangent mathematics into a universal evaluateKeyframeProgress helper strictly tracking AST interpolation durations.
- Encapsulated loop allocations into declarative sequence builders, shrinking all evaluation methods below 25 lines to prevent mental parsing overhead (SLAP).
- Abstracted canvas spline drawing iteration logic securely into explicit RemotePathScope.drawSplinePaths extensions.

@yschimke yschimke left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm unclear if it's passing tests because it produces identical output, or because we don't have good existing coverage of these tests.

Can you add a screenshot test covering this.

Also, are there any other unit tests we should consider for various cases.

val p2 = listOf(p4[0] + inTangent[0], p4[1] + inTangent[1])

rcPath.cubicTo(p1[0], p1[1], p2[0], p2[1], p4[0], p4[1])
private fun path(lottiePath: Path, animationSettings: LottieSettings): List<RemoteLottiePath> {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If we are splitting to a List of paths, what happens with any effects like caps on the start or the ends? do we treat these differently after this?

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.

2 participants