Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optimizing smooth tween between svg paths in JavaScript / React Native

I'm currently porting an application to React Native that captures user input as a stroke and animates it to the correct position to match an svg (pictures below). In the web, I use a combination of multiple smoothing libraries & pixijs to achieve perfectly smooth transitions with no artifacts.

With React Native & reanimated I'm limited to functions I can write by hand to handle the interpolation between two paths. Currently what I'm doing is:

  1. Convert the target svg to a fixed number N of points
  2. Smooth the captured input and convert it to a series of N points
  3. Loop over each coordinate and interpolate the value between those two points (linear interpolation)
  4. Run the resulting points array through a Catmull-Rom function
  5. Render the resulting SVG curve

1 & 2 I can cache prior to the animation, but steps 3 4 & 5 need to happen on each render.

Unfortunately, using this method, I'm limited to a value of around 300 N as the maximum amount of points before dropping some frames. I'm also still seeing some artifacts at the end of an animation that I don't know how to fix.

This is sufficient, but given that in the web I can animate tens of thousands of points without dropping frames, I feel like I am missing a key performance optimization here. For example, is there a way to combine steps 3 & 4? Are there more performant algorithms than Catmull-Rom?

Is there a better way to achieve a smooth transition between two vector paths using just pure JavaScript (or dropping into Swift if that is possible)?

Is there something more I can do to remove the artifacts pictured in the last photo? I'm not sure what these are called technically so it's hard for me to research - the catmull-rom spline removed most of them but I still see a few at the tail ends of the animation.

Animation end/start state:

animation starting state

Animation middle state:

animation middle state

Animation start/end state (with artifact):

animation end state with artifact

like image 300
cadlac Avatar asked Jul 03 '26 18:07

cadlac


1 Answers

You might want to have a look at flubber.js

Also why not ditch the catmull-rom for simple linear sections (probably detailed enough with 1000+ points)

If neither helps, or you want to get as fast as possible, you might want to leverage the GPUs power for embarrassingly parallel workflows like the interpolation between to N-sized arrays.


edit:

also consider using the skia renderer which already leverages the gpu and supports stuff perfectly fitting your use-case

import {Canvas, Path, Skia, interpolatePath} from "@shopify/react-native-skia";

//obv. you need to modify this to use your arrays 
const path1 = new Path();
path1.moveTo(0, 0);
path1.lineTo(100, 0);
const path2 = new Path();
path2.moveTo(0, 0);
path2.lineTo(0, 100);

//you have to do this dynamically (maybe using skia animations)
let animationProgress = 0.5; 

//magic already implemented for you
let path = interpolatePath(animationProgress, [0, 1], [path1, path2]);

const PathDemo = () => {
  return (
    <Canvas style={{ flex: 1 }}>
      <Path
        path={path}
        color="lightblue"
      />
    </Canvas>
  );
};
like image 80
HannesH Avatar answered Jul 06 '26 06:07

HannesH



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!