Skip to content

Commit aa88821

Browse files
committed
Update documentation
1 parent 1204be6 commit aa88821

File tree

4 files changed

+84
-80
lines changed

4 files changed

+84
-80
lines changed

docs/docs/animations/hooks.md

Lines changed: 79 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,77 @@ sidebar_label: Hooks
55
slug: /animations/hooks
66
---
77

8+
## usePathInterpolation
9+
10+
This hook interpolates between different path values based on a progress value, providing smooth transitions between the provided paths.
11+
12+
Paths need to be interpolatable, meaning they must contain the same number and types of commands. If the paths have different commands or different numbers of commands, the interpolation may not behave as expected. Ensure that all paths in the `outputRange` array are structured similarly for proper interpolation.
13+
14+
```tsx twoslash
15+
import React, { useEffect } from 'react';
16+
import { useSharedValue, withTiming } from 'react-native-reanimated';
17+
import { Skia, usePathInterpolation, Canvas, Path } from '@shopify/react-native-skia';
18+
19+
const angryPath = Skia.Path.MakeFromSVGString("M 16 25 C 32 27 43 28 49 28 C 54 28 62 28 73 26 C 66 54 60 70 55 74 C 51 77 40 75 27 55 C 25 50 21 40 27 55 L 16 25 Z")!;
20+
const normalPath = Skia.Path.MakeFromSVGString("M 21 31 C 31 32 39 32 43 33 C 67 35 80 36 81 38 C 84 42 74 57 66 60 C 62 61 46 59 32 50 C 24 44 20 37 21 31 Z")!;
21+
const goodPath = Skia.Path.MakeFromSVGString("M 21 45 C 21 37 24 29 29 25 C 34 20 38 18 45 18 C 58 18 69 30 69 45 C 69 60 58 72 45 72 C 32 72 21 60 21 45 Z")!;
22+
23+
const Demo = () => {
24+
const progress = useSharedValue(0);
25+
useEffect(() => {
26+
progress.value = withTiming(1, { duration: 1000 });
27+
}, []);
28+
29+
const path = usePathInterpolation(progress, [0, 0.5, 1], [angryPath, normalPath, goodPath]);
30+
return (
31+
<Canvas style={{ flex: 1 }}>
32+
<Path path={path} style="stroke" strokeWidth={5} strokeCap="round" strokeJoin="round" />
33+
</Canvas>
34+
);
35+
};
36+
```
37+
38+
## usePathValue
39+
40+
This hooks offers an easy way to animate paths.
41+
Behind the scene, it make sure that everything is done as efficiently as possible.
42+
43+
```tsx twoslash
44+
import {useSharedValue, withSpring} from "react-native-reanimated";
45+
import {Gesture, GestureDetector} from "react-native-gesture-handler";
46+
import {usePathValue, Canvas, Path, processTransform3d, Skia} from "@shopify/react-native-skia";
47+
48+
const rrct = Skia.RRectXY(Skia.XYWHRect(0, 0, 100, 100), 10, 10);
49+
50+
export const FrostedCard = () => {
51+
const rotateY = useSharedValue(0);
52+
53+
const gesture = Gesture.Pan().onChange((event) => {
54+
rotateY.value -= event.changeX / 300;
55+
});
56+
57+
const clip = usePathValue((path) => {
58+
"worklet";
59+
path.addRRect(rrct);
60+
path.transform(
61+
processTransform3d([
62+
{ translate: [50, 50] },
63+
{ perspective: 300 },
64+
{ rotateY: rotateY.value },
65+
{ translate: [-50, -50] },
66+
])
67+
);
68+
});
69+
return (
70+
<GestureDetector gesture={gesture}>
71+
<Canvas style={{ flex: 1 }}>
72+
<Path path={clip} />
73+
</Canvas>
74+
</GestureDetector>
75+
);
76+
};
77+
```
78+
879
## useClock
980

1081
This hook returns a number indicating the time in milliseconds since the hook was activated.
@@ -32,31 +103,20 @@ export default function App() {
32103
}
33104
```
34105

35-
## usePathInterpolation
36-
37-
This hook interpolates between different path values based on a progress value, providing smooth transitions between the provided paths.
106+
## Canvas Size
38107

39-
Paths need to be interpolatable, meaning they must contain the same number and types of commands. If the paths have different commands or different numbers of commands, the interpolation may not behave as expected. Ensure that all paths in the `outputRange` array are structured similarly for proper interpolation.
108+
The Canvas element has an `onSize` property that can receive a shared value, which will be updated whenever the canvas size changes.
40109

41110
```tsx twoslash
42-
import React, { useEffect } from 'react';
43-
import { useSharedValue, withTiming } from 'react-native-reanimated';
44-
import { Skia, usePathInterpolation, Canvas, Path } from '@shopify/react-native-skia';
45-
46-
const angryPath = Skia.Path.MakeFromSVGString("M 16 25 C 32 27 43 28 49 28 C 54 28 62 28 73 26 C 66 54 60 70 55 74 C 51 77 40 75 27 55 C 25 50 21 40 27 55 L 16 25 Z")!;
47-
const normalPath = Skia.Path.MakeFromSVGString("M 21 31 C 31 32 39 32 43 33 C 67 35 80 36 81 38 C 84 42 74 57 66 60 C 62 61 46 59 32 50 C 24 44 20 37 21 31 Z")!;
48-
const goodPath = Skia.Path.MakeFromSVGString("M 21 45 C 21 37 24 29 29 25 C 34 20 38 18 45 18 C 58 18 69 30 69 45 C 69 60 58 72 45 72 C 32 72 21 60 21 45 Z")!;
111+
import {useSharedValue} from "react-native-reanimated";
112+
import {Fill, Canvas} from "@shopify/react-native-skia";
49113

50114
const Demo = () => {
51-
const progress = useSharedValue(0);
52-
useEffect(() => {
53-
progress.value = withTiming(1, { duration: 1000 });
54-
}, []);
55-
56-
const path = usePathInterpolation(progress, [0, 0.5, 1], [angryPath, normalPath, goodPath]);
115+
// size will be updated as the canvas size changes
116+
const size = useSharedValue({ width: 0, height: 0 });
57117
return (
58-
<Canvas style={{ flex: 1 }}>
59-
<Path path={path} style="stroke" strokeWidth={5} strokeCap="round" strokeJoin="round" />
118+
<Canvas style={{ flex: 1 }} onSize={size}>
119+
<Fill color="white" />
60120
</Canvas>
61121
);
62122
};

docs/docs/animations/reanimated3.md

Lines changed: 1 addition & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -45,60 +45,4 @@ export const HelloWorld = () => {
4545
};
4646
```
4747

48-
## Performance
49-
50-
When animating with React Native Skia, we recommend avoiding new JSI allocations on each frame. Instead of creating a new value on each frame to notify Reanimated that the value has changed, directly mutate the value and notify Reanimated. Below are examples illustrating this pattern:
51-
52-
```tsx twoslash
53-
import {Gesture} from "react-native-gesture-handler";
54-
import {useSharedValue} from "react-native-reanimated";
55-
import {Skia, notifyChange} from "@shopify/react-native-skia";
56-
57-
const matrix = useSharedValue(Skia.Matrix());
58-
const path = useSharedValue(Skia.Path.Make().moveTo(0, 0));
59-
60-
const pan = Gesture.Pan().onChange((e) => {
61-
// ❌ Avoid creating a new path on every frame
62-
const newPath = path.value.copy();
63-
path.value = newPath.lineTo(e.changeX, e.changeY);
64-
});
65-
66-
const pan2 = Gesture.Pan().onChange((e) => {
67-
// ✅ Instead, mutate the value directly and notify Reanimated
68-
path.value.lineTo(e.changeX, e.changeY);
69-
notifyChange(path);
70-
});
71-
72-
const pinch = Gesture.Pinch().onChange((e) => {
73-
// ❌ Avoid creating a new matrix on every frame
74-
const newMatrix = Skia.Matrix(matrix.value.get());
75-
matrix.value = newMatrix.scale(e.scale);
76-
});
77-
78-
const pinch2 = Gesture.Pinch().onChange((e) => {
79-
// ✅ Mutate the value and notify Reanimated
80-
matrix.value.scale(e.scale);
81-
notifyChange(matrix);
82-
});
83-
```
84-
85-
`path.interpolate` now has an extra parameter to interpolate paths without allocating new paths. We provide a [usePathInterpolation](/docs/animations/hooks#usepathinterpolation) hook that will do all the heavy lifting for you.
86-
87-
## Canvas Size
88-
89-
The Canvas element has an `onSize` property that can receive a shared value, which will be updated whenever the canvas size changes.
90-
91-
```tsx twoslash
92-
import {useSharedValue} from "react-native-reanimated";
93-
import {Fill, Canvas} from "@shopify/react-native-skia";
94-
95-
const Demo = () => {
96-
// size will be updated as the canvas size changes
97-
const size = useSharedValue({ width: 0, height: 0 });
98-
return (
99-
<Canvas style={{ flex: 1 }} onSize={size}>
100-
<Fill color="white" />
101-
</Canvas>
102-
);
103-
};
104-
```
48+
We offer some [Skia specific animation hooks](/docs/animations/hooks), especially for paths.

example/src/Examples/FrostedCard/FrostedCard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export const FrostedCard = () => {
5555
});
5656

5757
const clip = usePathValue((path) => {
58+
"worklet";
5859
path.addRRect(rrct);
5960
path.transform(
6061
processTransform3d([
@@ -66,7 +67,6 @@ export const FrostedCard = () => {
6667
])
6768
);
6869
});
69-
7070
return (
7171
<View style={{ flex: 1 }}>
7272
<GestureDetector gesture={gesture}>

package/src/external/reanimated/interpolators.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type {
33
FrameInfo,
44
SharedValue,
55
} from "react-native-reanimated";
6-
import { useMemo, useRef } from "react";
6+
import { useCallback, useMemo, useRef } from "react";
77

88
import type { SkPath, SkPoint } from "../../skia/types";
99
import { interpolatePaths, interpolateVector } from "../../animation";
@@ -37,10 +37,10 @@ export const usePathValue = (cb: (path: SkPath) => void) => {
3737

3838
export const useClock = () => {
3939
const clock = useSharedValue(0);
40-
const callback = useRef((info: FrameInfo) => {
40+
const callback = useCallback((info: FrameInfo) => {
4141
"worklet";
4242
clock.value = info.timeSinceFirstFrame;
43-
}).current;
43+
}, []);
4444
useFrameCallback(callback);
4545
return clock;
4646
};

0 commit comments

Comments
 (0)