Skip to content

@remotion/paths: Fix getTangentAtLength() direction on arcs - #12868

Merged
samohovets merged 2 commits into
remotion-dev:mainfrom
b84330808:fix-arc-tangent-direction
Nov 3, 2026
Merged

samohovets merged 2 commits into
remotion-dev:mainfrom
b84330808:fix-arc-tangent-direction

Conversation

@b84330808

@b84330808 b84330808 commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

getTangentAtLength() returns a unit vector pointing along the path for lines and Bézier curves (getTangentAtLength("M 50 50 L 150 50", 50) → {x: 1, y: 0}), but for A/a segments it pointed backwards. Both branches of the finite-difference code in helpers/arc.ts had their signs swapped.

Half circle M 0 0 A 50 50 0 0 1 100 0:

length before after same arc after reduceInstructions()
0 (0, 1) (0, -1) (0, -1)
78.5 (-1, 0.01) (1, -0.01) (1, -0.01)
157 (0, -1) (0, 1) (0, 1)

Gated for v5

Projects that compensate for the reversed direction would break if the fix shipped in v4, so the fix is gated behind ENABLE_V5_BREAKING_CHANGES. With the flag off (v4), getTangentAtLength() returns exactly the same values as before. The new direction takes effect when the v5 flag is flipped.

  • helpers/arc.ts: the sign of the tangent depends on the v5 flag.
  • packages/example React logo: the electron's tail offset depends on the flag, so it renders correctly in both v4 and v5.
  • Test: expects the legacy direction with the flag off and the direction of travel with it on.
  • 5-0-migration.mdx: new entry "getTangentAtLength() points in the direction of travel on arcs".

Until v5, users who need the correct direction can run the path through reduceInstructions() first, which converts arcs to cubic curves.

I used Claude Code to write this change.

The tangent of an `A` segment pointed against the direction of travel,
while lines and Bézier curves point along it. Flip the sign so arcs
match the other segment types.

The React logo example drew the electron's tail along the old, reversed
tangent, so it now subtracts the tangent to keep the tail behind.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@vercel

vercel Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
bugs Ready Ready Preview Nov 3, 2026 3:45pm UTC
remotion Ready Ready Preview Nov 3, 2026 3:45pm UTC

Request Review

@pullfrog pullfrog 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.

Important

The direction fix itself is correct and well-tested, but it changes the public output of getTangentAtLength() for every A/a segment unconditionally on the v4/main line. Please resolve the gating/documentation question raised in the PR body before merging.

Reviewed changes

  • Fix arc tangent direction — swaps the two finite-difference return branches in packages/paths/src/helpers/arc.ts so the returned unit vector points along the direction of travel, matching lines, Béziers and the reduceInstructions() output.
  • Example compensation — negates x/y in Arc.tsx's move() so the electron-tail arrow keeps rendering as before given the now-flipped tangent.
  • Regression test — adds a half-circle arc assertion for the start, middle and end tangents in get-tangent-at-length.test.ts.

I independently confirmed the corrected behavior: for M 0 0 A 50 50 0 0 1 100 0, the arc tangents now agree with the same path after reduceInstructions() (arc → cubic), and all 107 tests in @remotion/paths pass.

Pullfrog  | Fix it ➔ | View workflow run | Using deepseek-v4.1-flash | 𝕏

@samohovets

Copy link
Copy Markdown
Member

Thanks! To avoid breaking projects that already compensate for the reversed direction, I pushed 92e6737, which gates the fix behind the v5 flag. v4 output is unchanged. The fix takes effect in 5.0 and is listed in the migration guide. I updated the description to match.

@b84330808

Copy link
Copy Markdown
Contributor Author

Thanks, gating it behind v5 makes sense!

@samohovets
samohovets merged commit cd1bb77 into remotion-dev:main Nov 3, 2026
18 checks passed

This branch was successfully deployed

2 active deployments
Preview – remotion — 92e67374 Deployed Nov 3, 2026 by vercel[bot]
Preview – bugs — 92e67374 Deployed Nov 3, 2026 by vercel[bot]
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