Hey notJust Developers,
Exciting news in the world of React Native Animation: The Skia team recently published React Native Skia version 1.0, a significant milestone achieved just 3 weeks ago. In this first-ever stable release, they’ve unveiled 5 super exciting features and enhancements.
- Rich Text Layouts using the New Paragraph API
- New Animation Hooks
- The Atlas API for rendering multiple instances of the same texture or image
- Efficient Lottie Animations with RN Skottie and RN Skia
- Canvaskit-js - 20kb RN Skia for web
Let’s explore these features individually, create code examples, and showcase their functionality along with the expected output, as demonstrated below.
In-app subscriptions are a pain. The code can be hard to write, time-consuming to maintain, and full of edge cases. RevenueCat makes it simple, plus provides analytics, integrations, and tools to grow so you can get back to building your app.
Get started with RevenueCat for free, and save weeks of development time integrating In-app subscriptions.
Before diving into the details of each feature & enhancement, let’s understand some basics about Skia & React Native Skia.
The Skia Library
Skia is an open-source 2D graphics library that provides common APIs that work across a variety of hardware and software platforms. It serves as the graphics engine for Google Chrome and ChromeOS, Android, Flutter, and many other products.
Skia is now in React Native
React Native Skia brings the Skia Graphics Library to React Native. It has been built by the Shopify team and William Candillon, on top of the Skia Library.
One of the main differences between Flutter & React Native is that Flutter has control over pixels but the big downside is Flutter doesn’t have control over Native Views. On the other hand, React Native has control over Native Views but it loses control over Pixel.
What “React Native Skia” did here is that it gives React Native control over Pixels too now. Besides this, by “React Native Skia” you can apply effects on Native Views and capture the pixels of Native views too.
Unveiling the Potency of React Native Skia
There is tremendous potential in React Native Skia. Let’s explore some common but very crucial capabilities of React Native Skia.
- “React Native Skia” is using JSI. JSI (Javascript Interface) is written in C++ & it is the new architecture model in React Native which dropped the old “Bridge” architecture from React Native. JSI brought a direct, native interface to JavaScript objects and functions. As “React Native Skia” uses JSI it can expose C++ objects to Javascript & which makes React Native Skia very faster.
- “React Native Skia” also uses “Reanimated”, which was created by Software Mansion. “Reanimated” enables developers to create smooth animations and interactions that run natively on the UI thread. In React Native, there are two threads specifically used: 1) JS thread and 2) UI (Native) thread. When animations can run on the UI thread, they become very speedy due to native performance. Since “Reanimated” can run animations on the UI thread and “React Native Skia” uses Reanimated, so “React Native Skia” can run animations on the UI (Native) thread which makes it super fast.
Install React Native Skia
To add React Native Skia to your project, simply run:
npm install @shopify/react-native-skia
Let’s dive into new features & enhancements
Rich Text Layouts with the New Paragraph API
From day one, React Native Skia was able to display text, but it was not possible to automatically break lines, apply layouts, or mix and match system fonts with custom app fonts. And this is what the Paragraph API now does.
The Paragraph API in React Native Skia allows you to create sophisticated text layouts with ease. Whether you’re building a chat app, a document viewer, or any other text-heavy interface, this feature will come in handy.
Let’s start by creating the below paragraph using custom fonts.
To do this you have to add one or two custom fonts in your React Native app. For your information, we will use “Roboto” & “BungeeSpice” fonts for this example.
import {
Paragraph,
Skia,
useFonts,
TextAlign,
Canvas,
} from "@shopify/react-native-skia";
Now load your custom fonts.
export default function RichText() {
const customFontMgr = useFonts({
Roboto: [
require("../../assets/fonts/roboto/Roboto-Regular.ttf"),
require("../../assets/fonts/roboto/Roboto-Medium.ttf"),
],
Bungee: [require("../../assets/fonts/bungee/BungeeSpice-Regular.ttf")],
});
}
Then build the paragraph using “Skia.ParagraphBuilder” with the above custom fonts that we loaded.
export default function RichText() {
return Skia.ParagraphBuilder.Make(paragraphStyle, customFontMgr)
.pushStyle(textStyle)
.addText("Welcome to RN")
.pushStyle({ ...textStyle, fontStyle: { weight: 500 } })
.addText(" Skia V1.0. 🚀")
.pushStyle({ ...textStyleBungee })
.addText(" #NotJustDev")
.pushStyle({ ...textStyle })
.addText(" is presenting ")
.pushStyle({ ...textStyle, fontStyle: { weight: 500 } })
.addText("Skia.")
.pop()
.build();
}
You see we added styles “paragraphStyle”, “textStyle” & “textStyleBungee”. Now let’s see how we added those styles inside <RichText> the component.
export default function RichText() {
const paragraphStyle = {
textAlign: TextAlign.Center,
};
const textStyle = {
color: Skia.Color("black"),
fontFamilies: ["Roboto"],
fontSize: 50,
};
const textStyleBungee = {
color: Skia.Color("black"),
fontFamilies: ["Bungee"],
fontSize: 45,
};
}
Finally return the Paragraph we built using custom fonts
export default function RichText() {
return (
<Canvas style={{ width: 256, height: 256 }}>
<Paragraph paragraph={paragraph} x={0} y={0} width={wp(90)} />
</Canvas>
);
}
Now call this <RichText /> component from anywhere in the app. You will see an output like below.
Let’s get a review of other new features & enhancements of React Native Skia V1.0.
New Animation Hooks
These hooks provide the easiest and fastest way to build animations in Skia. Below are animation hooks that RN SKIA provided when using React Native Skia with Reanimated.
- usePathInterpolation: This hook smoothly interpolates between different path values based on a progress value. Imagine you have two different shapes (paths), and you want to transition smoothly from one to the other. usePathInterpolation makes this happen seamlessly.
- usePathValue: This hook offers an easy way to animate paths. Behind the scenes, it optimizes everything for efficiency. Imagine you’re creating a weather app, and you want to animate a raindrop falling from the sky. usePathValue ensures that raindrop glides down gracefully, without any hiccups.
- useClock: This hook returns a time value in milliseconds since it was activated. Let’s think of it as a digital stopwatch that starts ticking when your component mounts. You can use this time value for various purposes, such as creating time-based animations or scheduling events.
- useRectBuffer: This hook creates an array of rectangles to be animated. If your component needs to handle multiple rectangles (maybe for a game grid or UI layout), useRectBuffer simplifies the process. It’s like having a stack of virtual sticky notes you can move around.
The Atlas API
The Atlas component in React Native Skia is like a magical backpack for textures or images. It helps you efficiently render multiple instances of the same texture (think: sprites) with varying transformations.
Imagine you’re drawing a bunch of similar objects, like game characters or UI elements, and you want them to move, rotate, or scale smoothly. The Atlas API has your back!
The Atlas component has 3 major attributes.
- Image: You load an image (your texture) into the Atlas. This could be anything — a cute cat, a spaceship, or even a slice of pizza (because why not? 🍕).
- Sprites: Next, you define where these sprites (pieces of your image) are located within the Atlas. Each sprite corresponds to a specific part of your texture.
- Transforms: You apply transformations (like rotation, scaling, or translation) to each sprite. These transformations make your sprites dance, fly, or do whatever you need them to do.
Let’s create an Atlas component like below & understand each of its parts.
First of all, import all the dependencies.
import React from "react";
import {
Skia,
drawAsImage,
Group,
Rect,
Canvas,
Atlas,
rect,
} from "@shopify/react-native-skia";
Now, we’re creating an image (a rectangle shape) that contains two rectangles by using <Rect /> — one cyan-filled and the other blue-bordered.
const size = { width: 25, height: 11.25 };
const strokeWidth = 2;
const imageSize = {
width: size.width + strokeWidth,
height: size.height + strokeWidth,
};
const image = drawAsImage(
<Group>
<Rect
rect={rect(strokeWidth / 2, strokeWidth / 2, size.width, size.height)}
color="cyan"
/>
<Rect
rect={rect(strokeWidth / 2, strokeWidth / 2, size.width, size.height)}
color="blue"
style="stroke"
strokeWidth={strokeWidth}
/>
</Group>,
imageSize,
);
Then below, we’re creating an array called sprites. The array will have numberOfBoxes elements (in this case, 350). Each element represents a sprite, which is like a cutout from our image (those rectangles or circles we want to animate). The rect(0, 0, imageSize.width, imageSize.height) function creates a sprite with a specific size (width and height).
export default ImageWithAtlas = () => {
const numberOfBoxes = 350;
const sprites = new Array(numberOfBoxes)
.fill(0)
.map(() => rect(0, 0, imageSize.width, imageSize.height));
};
After that, now we’re creating another array called transforms. Each element in this array represents a transformation for a corresponding sprite.
export default ImageWithAtlas = () => {
const pos = { x: 190, y: 258 };
const width = 400;
const transforms = new Array(numberOfBoxes).fill(0).map((_, i) => {
const tx = 5 + ((i * size.width) % width);
const ty = 25 + Math.floor(i / (width / size.width)) * size.width;
const r = Math.atan2(pos.y - ty, pos.x - tx);
return Skia.RSXform(Math.cos(r), Math.sin(r), tx, ty);
});
};
In the above transformation code, we used some calculations. Let’s try to understand them a bit.
- The pos is the center point, and sprites (rectangles) will circulate this center point.
- The tx and ty values determine the position (translation) of each sprite (each rectangle in this case).
- The r value calculates the rotation angle based on the sprite’s position relative to the center point (pos).
Now bringing It all together through <Atlas /> API.
export default ImageWithAtlas = () => {
return (
<Canvas
style={{
width: wp(100),
height: hp(60),
}}
>
<Atlas image={image} sprites={sprites} transforms={transforms} />
</Canvas>
);
};
Now you can call the <ImageWithAtlas /> component from anywhere in your app & you will see an output like below.
Efficient Lottie Animations with RN Skottie and RN Skia
For scripted (Guided Movements) animations, React Native Skia serves as the foundation for React NativeSkottie by providing the necessary infrastructure for rendering graphics. React NativeSkottie has been created by Margelo.
When you use react-native-skottie in your React Native app, it internally relies on @shopify/react-native-skia. When you load a Lottie animation (either from a JSON file or a DotLottie file), @shopify/react-native-skia processes it and hands it over to Skottie. Skottie then takes care of rendering the animation efficiently using Skia’s GPU acceleration. The result is incredibly smooth and performant animations within your React Native app!
It is very simple to use Skottie in your React Native App.
import { Skottie } from "react-native-skottie";
import LottieAnimationFile from "./animation.json";
export default function App() {
return (
<Skottie
style={styles.flex1}
source={LottieAnimationFile}
autoPlay={true}
/>
);
}
Canvaskit-js: Skia in Web
The React Native Skia team is excited to announce the release of Canvaskit-js, an open-source library designed for web development. This lightweight yet powerful library enables you to create rich web experiences using React Native Skia, all while keeping your bundle size impressively small — just 20 kilobytes!
That’s it 🙌
In a nutshell, React Native Skia V1.0 brings five fresh features to the table. Get ready for an exciting ride!
🔴 Join me live
This Friday we will continue the Trello Clone with React Native. It's going to be a tutorial packed with value, so set a reminder and don't miss it out 👇
🔁 In case you missed it
Build a Local First Trello Clone with React Native & RealmThis video is perfect to learn the ins and outs of React Native using Realm, including the Atlas Device SDK. | | In-app Subscriptions & Paywalls with RevenueCat We'll guide you through the essential steps to seamlessly integrate in-app subscriptions into your mobile application. |
🔥 Press worthy
📦 Marc is pushing the boundaries of React Native with a sneak peak of a new 3D Library
🆕 Check if your app is ready for the New Architecture with NewArch Helper
🎫 App.js tickets are selling fast. Get a 10% discount with code “notjustdevs”
Did you learn something new today?
If you found this email valuable, forward it to one friend or coworker that can benefit from it as well. That would be much appreciated 🙏
The newsletter was written by Anis and edited by Vadim Savin.
| | Vadim SavinHelping you become a better developer together with the notJust.dev team |