Skia is a cross-platform 2D graphics library that provides a set of drawing primitives which run on iOS, Android, macOS, Windows, Linux, and the browser. Over the past two years, Shopify Engineering has sponsored development of the @shopify/react-native-skia
library that exposes Skia functionality to React Native.
Another hypnotic animation made entirely with React Native Skia 👇
— Enzo Manuel Mangano (@reactiive_) December 20, 2022
Available tomorrow on Patreon: https://t.co/0sXVm7fZfw pic.twitter.com/t0IEksu6aY
As part of the RN Skia community online, I’ve had the chance to interact with other developers and see what they think of it. Although they are often impressed with what can be built, many are afraid to try it out because they don’t know where to get started. Working with RN Skia is not as difficult as it looks once you know the basics of how to work with it. I wanted to write this article to teach the basics of RN Skia so more React Native developers felt comfortable learning the library and using it in their apps ❤️.
What is the Use-Case for React Native Skia?
Before we start coding, I want to answer a common developer question. Why would one use React Native Skia in the first place? This question arises because many who are familiar with the React Native ecosystem are aware react-native-reanimated
and react-native-svg
can behave similarly to Skia when making some types of user experiences.
Both react-native-svg
and RN Skia can be used for custom drawings. They differ in the fact that react-native-svg
is optimized for static SVGs and targets the native Android and iOS SVG platforms. RN Skia’s drawing functionality on the other hand is built on top of the Skia graphics engine from Google. It gives you great primitives for animating like shaders, path operations and image filters.
You want to use RN Skia whenever you need to build custom user interactions that aren’t covered by your run-of-the-mill React Native component. The View
built into React Native is capable of drawing basic boxes and circles, but isn’t meant to take the form of custom shapes. Skia allows us to not only draw whatever shapes we want, but gives us visual effects our components wouldn’t be able to achieve with View
and StyleSheet
.
Skia is also highly optimized for dynamic user interactions. This means anything we draw on the canvas can be animated in a performant manner with a stable frame rate. With RN Skia we use react-native-reanimated
to be the primary driver of all animations. This means you can animate Skia drawings using an API similar to the one you use to animate the View
component.
How to Draw
For most developers with a background in web, we are comfortable using flex
and grid
systems to build our layouts. These systems are very productive and easy to use because they abstract away a lot of the logic used to position elements on the screen.
In Skia, on the other hand, things work quite differently. Instead of having a system that gives us parameters for how to lay out user interface elements, we are given a canvas. The Skia canvas has a basic 2 dimensional cartesian coordinate system that gives you full control over what is drawn at any given pixel on the screen.
The easiest way to get started is to draw the most basic shapes inside the canvas. The simplest shapes we have available to us are Circle
, Rect
and RoundedRect
. We can give these shapes basic x, y, height and width values to get them to appear on the screen.
Here's an example of these shapes in action:
The code for this drawing would look something like this:
The built-in shapes are great, but there isn’t anything in the previous example we couldn’t have accomplished using React Native’s built-in View
. To create more advanced shapes using RN Skia we can use the Path component. One way to draw Paths is through SVG notation using Skia.Path.MakeFromSVGString
. Here’s an example of how you might make an arc using SVGs.
The code
The result
Skia doesn’t limit you to SVGs for drawing. There are also several imperative commands for drawing such as addCircle
, lineTo
, addPoly
that you can use to modify paths created using Skia.Path.Make
. Here is an example of achieving the same effect as above using the addArc
command.
There are a lot more options for lines and shapes than could possibly be covered in this post. I recommend exploring the documentation for paths and making your own custom shapes to experiment with everything that is possible.
Add Movement with Reanimated
Making static drawings is great and all, but probably not what you came here for. RN Skia really shines when you want to add movement to your drawings. We can add motion to our drawings using the power of react-native-reanimated
similar to how we would do it in other parts of React Native. A cool part about this integration is using methods like createAnimatedComponent
and useAnimatedProps
are unnecessary here. Skia has been optimized to work with reanimated out-of-the-box.
To illustrate how we might add motion to a drawing, let’s create an example. If you are following along, make sure to install react-native-reanimated
and react-native-gesture-handler
into your project as we’ll need them for the coming examples. Once you have those installed, feel free to copy-paste this code into your project.
The animation should look like this:
The first thing to observe about the code above is that we created a shared value for the horizontal position of the circle. Shared values from reanimated have the special privilege of being available to the UI thread. This allows animations to avoid slow re-rendering calculations and stay at a smooth 60-120 Frames Per Second.
Note that I have two other functions here named withRepeat
and withSpring
. These are animations that are built into react-native-reanimated
. withSpring
is an animation that interpolates values from where it starts to a specified end value. As you can see here I use the end of the line for that. withRepeat
is an animation that allows an animation to repeat. The parameters -1
and true
tell withRepeat
to continuously run the animation from the start value to the end value and then reverse it from the end to the start.
Reanimated allows for mixing and matching all kinds of animations and it's helpful to try out a lot of different ones to get the effect you want. For exhaustive explanations of all available animations you can view the reanimated documentation here.
The last thing to notice here is that we can give our shared value directly to a Skia circle to control its position on the screen. Skia and react-native-reanimated
have full interop with each other which is extremely powerful.
Now that you know the basics of movement and positioning, a good challenge is to recreate this animation but with a vertical line instead of a horizontal one.
Add interactivity with React Native Gesture Handler
Another thing you’ll want to know in order to get started with React Native Skia is how to handle gestures. We can do this using react-native-gesture-handler
which is another library from Software Mansion. Let's update the demo above to use gestures instead of an animation. This is really easy, we just need to wrap the canvas with a GestureDetector
component and create a gesture variable. Let’s take a look at the code and then talk about why it works.
If you paste these changes into your app you should be able to now interact with the dot like this:
Pretty cool right? The Gesture Handler from reanimated works together seamlessly with the shared value we used earlier to create animated movement. In this code we built a panning gesture using Gesture.Pan()
and then gave the pan gesture callbacks for the onChange
part of the gesture.
As you drag your finger, the onChange
callback is called several times per second with the position of your finger and assigns it to the shared value. Just like when we use the built-in animations, the gesture is run on the UI thread and outside of React saving us re-renders and allowing for 60-120 frame per second interactions.
Although we only used onChange
here to get the x position of your finger, it’s possible to get much more out of the library. Pan gesture for example also provides callbacks for the beginning of the gesture (onBegin
), the end of the gesture (onEnd
) and many more. You can also get values like the y position and velocity of the movement to make your gestures even more expressive. For a full list of gestures and what’s possible in React Native I recommend looking into the documentation for react-native-gesture-handler
.
For the next challenge I recommend re-doing this interaction to work vertically instead of horizontally.
Applying Simple Visual Effects
Of course the fun of Skia does not stop at motion, we can also apply some effects to our drawings. To go into all possible effects with Shaders, Image Filters and everything else Skia can do would be many articles on their own. Luckily for us, there are some basic ones built into RN Skia that we can use out of the box.
I recommend having a look at the Filters section of the documentation to get an idea of everything that is possible. For now, let’s apply a couple of simple effects to our animation from the gestures section.
As you can see I didn’t add much here. The built-in Blur and DashPathEffect can be placed as children to the circle and the line to change their look and feel. All I did was add a simple blur derived value to figure out how far along the line the circle was positioned.
For the final challenge I recommend just going through the documentation on effects and trying out other fun things that are possible to add to this interaction.
Where to go next - Other great resources
I like to think of learning React Native Skia like I think about learning a musical instrument. One can understand proper technique and scales but there is only so far you can go learning on your own. To get to the next level of skill you have to play with other musicians and learn the different tricks people use to keep the sound interesting.
Visual arts like 2D animations share this property. You can only learn so much on your own. It’s important to learn from the creativity and skills of other developers. Here are some videos I recommend as next steps on your Skia journey that can help get you from a beginner to an advanced practitioner of the library.
Telegram Dark Mode - “Can it be done in React Native?” by: William Candillon (@wcandillon)
This was by far the most requested tutorial since @appjsconf https://t.co/gyNv0QLNfw pic.twitter.com/hqXjCyHt3H
— William Candillon (@wcandillon) September 14, 2023
Metaball Animation in React Native (Skia) by: Enzo Manuel Mangano (@reactiive_)
I just posted on YouTube the Metaball Animation in React Native Skia🎨
— Enzo Manuel Mangano (@reactiive_) May 22, 2023
YouTube tutorial: https://t.co/9rkvZjPD0A
Since the animation was "stolen" from my Patreon, I'll post a bonus animation this week for my patronshttps://t.co/UJLQxVqXgU pic.twitter.com/IDFP1o7yTr
Pixelated Image by: Daehyeon Mun (@DaehyeonMun)
I just released my first tutorial video "Pixelated Image with React Native Skia".
— Daehyeon Mun (@DaehyeonMun) September 5, 2023
You can watch the video on the link below and access the full source code.
Thanks :)
Video: https://t.co/GwAYQangG3
Source code: https://t.co/8e4XJT7yfR pic.twitter.com/oTnfeeE6Hv
Web Support
One more thing I wanted to include as a bonus part of this article that not a lot of people know is that React Native Skia actually has web support! If you have React Native Web set-up you can take full advantage of the power of Skia in your browser.
Final Thoughts
I hope you enjoyed this article and that it gave you a useful starting point to learning React Native Skia. This library has personally brought me hours of joy creating animations I thought were beautiful and interesting. The Shopify Engineering team and I look forward to seeing how you integrate React Native Skia into your apps.🚀.