Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: skottie #657

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions example/src/Examples/API/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ const examples = [
screen: "Images",
title: "🏞 Images",
},
{
screen: "Skottie",
title: "▶️ Skottie",
},
{
screen: "Clipping",
title: "✂️ & 🎭 Clipping & Masking",
Expand Down
1 change: 1 addition & 0 deletions example/src/Examples/API/Routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ export type Routes = {
Freeze: undefined;
UseCanvas: undefined;
Reanimated: undefined;
Skottie: undefined;
};
47 changes: 47 additions & 0 deletions example/src/Examples/API/SkottieAnimations.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React, { useMemo } from "react";
import { ScrollView, useWindowDimensions } from "react-native";
import {
Canvas,
Skia,
SkottieAnimation,
useTiming,
Easing,
} from "@shopify/react-native-skia";

import _LottieAnim from "../../assets/material_wave_loading.json";

const LottieAnim = JSON.stringify(_LottieAnim);

export const SkottieAnimations = () => {
const { width, height } = useWindowDimensions();

// TODO: build a hook that abstracts this logic
const skottieAnimation = useMemo(() => Skia.SkottieAnimation(LottieAnim), []);

const progress = useTiming(
{
from: 0,
to: 1,
loop: true,
},
{
duration: skottieAnimation.duration * 1000,
easing: Easing.linear,
}
);

return (
<ScrollView>
<Canvas style={{ width, height }}>
<SkottieAnimation
x={0}
y={0}
width={width}
height={height}
progress={progress}
anim={skottieAnimation}
/>
</Canvas>
</ScrollView>
);
};
8 changes: 8 additions & 0 deletions example/src/Examples/API/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { UseCanvas } from "./UseCanvas";
import { FreezeExample } from "./Freeze";
import { Touch } from "./Touch";
import { Reanimated } from "./Reanimated";
import { SkottieAnimations } from "./SkottieAnimations";

const Stack = createNativeStackNavigator<Routes>();
export const API = () => {
Expand All @@ -40,6 +41,13 @@ export const API = () => {
title: "🔺 Shapes",
}}
/>
<Stack.Screen
name="Skottie"
component={SkottieAnimations}
options={{
title: "▶️ Skottie (lottie animations)",
}}
/>
<Stack.Screen
name="Images"
component={Images}
Expand Down
1 change: 1 addition & 0 deletions example/src/assets/material_wave_loading.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"assets":[],"ddd":0,"fr":29.9700012207031,"h":256,"ip":0,"layers":[{"ao":0,"bm":0,"ddd":0,"ind":1,"ip":0,"ks":{"a":{"a":0,"k":[-70,-0.5,0]},"o":{"a":0,"k":100},"p":{"a":1,"k":[{"e":[208.6,88,0],"i":{"x":0.667,"y":1},"n":"0p667_1_0p333_0","o":{"x":0.333,"y":0},"s":[208.6,127.969,0],"t":20,"ti":[0,-0.00520833348855,0],"to":[0,-6.66145849227905,0]},{"e":[208.6,128,0],"i":{"x":0.667,"y":1},"n":"0p667_1_0p333_0","o":{"x":0.333,"y":0},"s":[208.6,88,0],"t":30,"ti":[0,-6.66666650772095,0],"to":[0,0.00520833348855,0]},{"t":40.0000016292334}]},"r":{"a":0,"k":0},"s":{"a":0,"k":[75,75,100]}},"nm":"Shape Layer 3","op":300.00001221925,"shapes":[{"cix":2,"it":[{"d":1,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","p":{"a":0,"k":[0,0]},"s":{"a":0,"k":[33.75,34.5]},"ty":"el"},{"c":{"a":0,"k":[0.9843137,0.5490196,0,1]},"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","o":{"a":0,"k":100},"r":1,"ty":"fl"},{"a":{"a":0,"ix":1,"k":[0,0]},"nm":"Transform","o":{"a":0,"ix":7,"k":100},"p":{"a":0,"ix":2,"k":[-70.125,-0.5]},"r":{"a":0,"ix":6,"k":0},"s":{"a":0,"ix":3,"k":[100,100]},"sa":{"a":0,"ix":5,"k":0},"sk":{"a":0,"ix":4,"k":0},"ty":"tr"}],"ix":1,"mn":"ADBE Vector Group","nm":"Ellipse 1","np":3,"ty":"gr"}],"sr":1,"st":0,"ty":4},{"ao":0,"bm":0,"ddd":0,"ind":2,"ip":0,"ks":{"a":{"a":0,"k":[-70,-0.5,0]},"o":{"a":0,"k":100},"p":{"a":1,"k":[{"e":[168.6,88,0],"i":{"x":0.667,"y":1},"n":"0p667_1_0p333_0","o":{"x":0.333,"y":0},"s":[168.6,128,0],"t":15,"ti":[0,0,0],"to":[0,-6.66666650772095,0]},{"e":[168.6,128,0],"i":{"x":0.667,"y":1},"n":"0p667_1_0p333_0","o":{"x":0.333,"y":0},"s":[168.6,88,0],"t":25,"ti":[0,-6.66666650772095,0],"to":[0,0,0]},{"t":35.0000014255792}]},"r":{"a":0,"k":0},"s":{"a":0,"k":[75,75,100]}},"nm":"Shape Layer 2","op":300.00001221925,"shapes":[{"cix":2,"it":[{"d":1,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","p":{"a":0,"k":[0,0]},"s":{"a":0,"k":[33.75,34.5]},"ty":"el"},{"c":{"a":0,"k":[0.9921569,0.8470588,0.2078431,1]},"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","o":{"a":0,"k":100},"r":1,"ty":"fl"},{"a":{"a":0,"ix":1,"k":[0,0]},"nm":"Transform","o":{"a":0,"ix":7,"k":100},"p":{"a":0,"ix":2,"k":[-70.125,-0.5]},"r":{"a":0,"ix":6,"k":0},"s":{"a":0,"ix":3,"k":[100,100]},"sa":{"a":0,"ix":5,"k":0},"sk":{"a":0,"ix":4,"k":0},"ty":"tr"}],"ix":1,"mn":"ADBE Vector Group","nm":"Ellipse 1","np":3,"ty":"gr"}],"sr":1,"st":0,"ty":4},{"ao":0,"bm":0,"ddd":0,"ind":3,"ip":0,"ks":{"a":{"a":0,"k":[-70,-0.5,0]},"o":{"a":0,"k":100},"p":{"a":1,"k":[{"e":[128.594,88,0],"i":{"x":0.667,"y":1},"n":"0p667_1_0p333_0","o":{"x":0.333,"y":0},"s":[128.594,127.969,0],"t":10,"ti":[0,-0.00520833348855,0],"to":[0,-6.66145849227905,0]},{"e":[128.594,128,0],"i":{"x":0.667,"y":1},"n":"0p667_1_0p333_0","o":{"x":0.333,"y":0},"s":[128.594,88,0],"t":20,"ti":[0,-6.66666650772095,0],"to":[0,0.00520833348855,0]},{"t":30.0000012219251}]},"r":{"a":0,"k":0},"s":{"a":0,"k":[75,75,100]}},"nm":"Shape Layer 1","op":300.00001221925,"shapes":[{"cix":2,"it":[{"d":1,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","p":{"a":0,"k":[0,0]},"s":{"a":0,"k":[33.75,34.5]},"ty":"el"},{"c":{"a":0,"k":[0.2627451,0.627451,0.2784314,1]},"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","o":{"a":0,"k":100},"r":1,"ty":"fl"},{"a":{"a":0,"ix":1,"k":[0,0]},"nm":"Transform","o":{"a":0,"ix":7,"k":100},"p":{"a":0,"ix":2,"k":[-70.125,-0.5]},"r":{"a":0,"ix":6,"k":0},"s":{"a":0,"ix":3,"k":[100,100]},"sa":{"a":0,"ix":5,"k":0},"sk":{"a":0,"ix":4,"k":0},"ty":"tr"}],"ix":1,"mn":"ADBE Vector Group","nm":"Ellipse 1","np":3,"ty":"gr"}],"sr":1,"st":0,"ty":4},{"ao":0,"bm":0,"ddd":0,"ind":4,"ip":0,"ks":{"a":{"a":0,"k":[-70,-0.5,0]},"o":{"a":0,"k":100},"p":{"a":1,"k":[{"e":[88.6,88,0],"i":{"x":0.667,"y":1},"n":"0p667_1_0p333_0","o":{"x":0.333,"y":0},"s":[88.6,127.969,0],"t":5,"ti":[0,-0.00520833348855,0],"to":[0,-6.66145849227905,0]},{"e":[88.6,128,0],"i":{"x":0.667,"y":1},"n":"0p667_1_0p333_0","o":{"x":0.333,"y":0},"s":[88.6,88,0],"t":15,"ti":[0,-6.66666650772095,0],"to":[0,0.00520833348855,0]},{"t":25.0000010182709}]},"r":{"a":0,"k":0},"s":{"a":0,"k":[75,75,100]}},"nm":"Shape Layer 4","op":300.00001221925,"shapes":[{"cix":2,"it":[{"d":1,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","p":{"a":0,"k":[0,0]},"s":{"a":0,"k":[33.75,34.5]},"ty":"el"},{"c":{"a":0,"k":[0.1176471,0.5333334,0.8980392,1]},"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","o":{"a":0,"k":100},"r":1,"ty":"fl"},{"a":{"a":0,"ix":1,"k":[0,0]},"nm":"Transform","o":{"a":0,"ix":7,"k":100},"p":{"a":0,"ix":2,"k":[-70.125,-0.5]},"r":{"a":0,"ix":6,"k":0},"s":{"a":0,"ix":3,"k":[100,100]},"sa":{"a":0,"ix":5,"k":0},"sk":{"a":0,"ix":4,"k":0},"ty":"tr"}],"ix":1,"mn":"ADBE Vector Group","nm":"Ellipse 1","np":3,"ty":"gr"}],"sr":1,"st":0,"ty":4},{"ao":0,"bm":0,"ddd":0,"ind":5,"ip":0,"ks":{"a":{"a":0,"k":[-70,-0.5,0]},"o":{"a":0,"k":100},"p":{"a":1,"k":[{"e":[48.6,88,0],"i":{"x":0.667,"y":1},"n":"0p667_1_0p333_0","o":{"x":0.333,"y":0},"s":[48.6,127.969,0],"t":0,"ti":[0,-0.00520833348855,0],"to":[0,-6.66145849227905,0]},{"e":[48.6,128,0],"i":{"x":0.667,"y":1},"n":"0p667_1_0p333_0","o":{"x":0.333,"y":0},"s":[48.6,88,0],"t":10,"ti":[0,-6.66666650772095,0],"to":[0,0.00520833348855,0]},{"t":20.0000008146167}]},"r":{"a":0,"k":0},"s":{"a":0,"k":[75,75,100]}},"nm":"Shape Layer 5","op":300.00001221925,"shapes":[{"cix":2,"it":[{"d":1,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","p":{"a":0,"k":[0,0]},"s":{"a":0,"k":[33.75,34.5]},"ty":"el"},{"c":{"a":0,"k":[0.8980392,0.2235294,0.2078431,1]},"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","o":{"a":0,"k":100},"r":1,"ty":"fl"},{"a":{"a":0,"ix":1,"k":[0,0]},"nm":"Transform","o":{"a":0,"ix":7,"k":100},"p":{"a":0,"ix":2,"k":[-70.125,-0.5]},"r":{"a":0,"ix":6,"k":0},"s":{"a":0,"ix":3,"k":[100,100]},"sa":{"a":0,"ix":5,"k":0},"sk":{"a":0,"ix":4,"k":0},"ty":"tr"}],"ix":1,"mn":"ADBE Vector Group","nm":"Ellipse 1","np":3,"ty":"gr"}],"sr":1,"st":0,"ty":4}],"nm":"Comp 1","op":40.0000016292334,"v":"4.6.8","w":256}
1 change: 1 addition & 0 deletions example/src/assets/techno_penguin.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"build-skia": "yarn build-skia-ios && yarn build-skia-android",
"clean-skia": "yarn rimraf ./package/libs && yarn rimraf ./externals/skia/out",
"copy-skia-include-headers": "yarn rimraf ./package/cpp/skia/include/ && cp -a ./externals/skia/include/. ./package/cpp/skia/include",
"copy-skia-module-headers": "yarn rimraf ./package/cpp/skia/modules/ && mkdir -p ./package/cpp/skia/modules/svg/include && mkdir -p ./package/cpp/skia/modules/skresources/include && cp -a ./externals/skia/modules/svg/include/. ./package/cpp/skia/modules/svg/include && cp -a ./externals/skia/modules/skresources/include/. ./package/cpp/skia/modules/skresources/include",
"copy-skia-module-headers": "yarn rimraf ./package/cpp/skia/modules/ && mkdir -p ./package/cpp/skia/modules/svg/include && mkdir -p ./package/cpp/skia/modules/skresources/include && mkdir -p ./package/cpp/skia/modules/skottie/include && mkdir -p ./package/cpp/skia/modules/skottie/src/text && cp -a ./externals/skia/modules/svg/include/. ./package/cpp/skia/modules/svg/include && cp -a ./externals/skia/modules/skresources/include/. ./package/cpp/skia/modules/skresources/include && cp -a ./externals/skia/modules/skottie/include/. ./package/cpp/skia/modules/skottie/include && cp ./externals/skia/modules/skottie/src/text/SkottieShaper.h ./package/cpp/skia/modules/skottie/src/text/SkottieShaper.h",
"copy-skia-headers": "yarn copy-skia-module-headers && yarn copy-skia-include-headers",
"build-npm": "yarn ts-node ./scripts/build-npm-package.ts",
"get-filename-npm": "yarn ts-node ./scripts/get-npm-filename.ts",
Expand Down
9 changes: 9 additions & 0 deletions package/android/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ set (PACKAGE_NAME "reactskia")
set (SKIA_LIB "skia")
set (SKIA_SVG_LIB "svg")
set (SKIA_SKSHAPER_LIB "skshaper")
set (SKIA_SKSG_LIB "sksg")
set (SKIA_SKOTTIE_LIB "skottie")

set(build_DIR ${CMAKE_SOURCE_DIR}/build)
file(GLOB LIBRN_DIR "${PREBUILT_DIR}/${ANDROID_ABI}")
Expand Down Expand Up @@ -91,6 +93,11 @@ set_property(TARGET svg PROPERTY IMPORTED_LOCATION "${SKIA_LIBS_PATH}/libsvg.a")
add_library(skshaper STATIC IMPORTED)
set_property(TARGET skshaper PROPERTY IMPORTED_LOCATION "${SKIA_LIBS_PATH}/libskshaper.a")

add_library(sksg STATIC IMPORTED)
set_property(TARGET sksg PROPERTY IMPORTED_LOCATION "${SKIA_LIBS_PATH}/libsksg.a")

add_library(skottie STATIC IMPORTED)
set_property(TARGET skottie PROPERTY IMPORTED_LOCATION "${SKIA_LIBS_PATH}/libskottie.a")

find_library(
LOG_LIB
Expand Down Expand Up @@ -147,6 +154,8 @@ target_link_libraries(
${TURBOMODULES_LIB}
${SKIA_SVG_LIB}
${SKIA_SKSHAPER_LIB}
${SKIA_SKOTTIE_LIB}
${SKIA_SKSG_LIB}
${SKIA_LIB}
-ljnigraphics
-lGLESv2
Expand Down
2 changes: 2 additions & 0 deletions package/cpp/api/JsiSkApi.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "JsiSkPictureFactory.h"
#include "JsiSkRuntimeShaderBuilder.h"
#include "JsiSkColor.h"
#include "JsiSkSkottieAnimation.h"

namespace RNSkia
{
Expand Down Expand Up @@ -70,6 +71,7 @@ namespace RNSkia
installFunction("MakeVertices", JsiSkVertices::createCtor(context));
installFunction("PictureRecorder", JsiSkPictureRecorder::createCtor(context));
installFunction("Color", JsiSkColor::createCtor());
installFunction("SkottieAnimation", JsiSkSkottieAnimation::createCtor(context));

installReadonlyProperty("SVG",
std::make_shared<JsiSkSVGFactory>(context));
Expand Down
11 changes: 11 additions & 0 deletions package/cpp/api/JsiSkCanvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,17 @@ class JsiSkCanvas : public JsiSkHostObject {
void setCanvas(SkCanvas *canvas) { _canvas = canvas; }
SkCanvas *getCanvas() { return _canvas; }

/**
Returns the underlying object from a host object of this type
*/
static SkCanvas *fromValue(jsi::Runtime &runtime,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As the API design is to call animation.render(canvas, progress) I needed to get the canvas as parameter when called from JS

const jsi::Value &obj)
{
return obj.asObject(runtime)
.asHostObject<JsiSkCanvas>(runtime)
->getCanvas();
}

private:
SkCanvas *_canvas;
};
Expand Down
85 changes: 85 additions & 0 deletions package/cpp/api/JsiSkSkottieAnimation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#pragma once

#include <JsiSkHostObjects.h>

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdocumentation"

#include <modules/skottie/include/Skottie.h>

#pragma clang diagnostic pop

#include <jsi/jsi.h>

// TODO: we probably also want to turn that into a factory.
namespace RNSkia {
using namespace facebook;

class JsiSkSkottieAnimation : public JsiSkWrappingSkPtrHostObject<skottie::Animation>
{
public:
//#region Properties
JSI_PROPERTY_GET(duration) { return static_cast<double>(getObject()->duration()); }
JSI_PROPERTY_GET(fps) { return static_cast<double>(getObject()->fps()); }

JSI_EXPORT_PROPERTY_GETTERS(JSI_EXPORT_PROP_GET(JsiSkSkottieAnimation, duration),
JSI_EXPORT_PROP_GET(JsiSkSkottieAnimation, fps))
//#endregion


//#region Methods
JSI_HOST_FUNCTION(seek) {
getObject()->seek(arguments[0].asNumber());
return jsi::Value::undefined();
}

JSI_HOST_FUNCTION(render) {
auto canvas = JsiSkCanvas::fromValue(runtime, arguments[0]);
auto rect = JsiSkRect::fromValue(runtime, arguments[1]);
if (canvas != nullptr && rect != nullptr)
getObject()->render(canvas, rect.get());

return jsi::Value::undefined();
}

JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkSkottieAnimation, seek),
JSI_EXPORT_FUNC(JsiSkSkottieAnimation, render), )
//#endregion

/**
Constructor
*/
JsiSkSkottieAnimation(std::shared_ptr<RNSkPlatformContext> context,
const sk_sp<skottie::Animation> animation)
: JsiSkWrappingSkPtrHostObject<skottie::Animation>(std::move(context), std::move(animation)){}

/**
Returns the jsi object from a host object of this type
*/
static sk_sp<skottie::Animation> fromValue(jsi::Runtime &runtime, const jsi::Value &obj) {
return obj.asObject(runtime)
.asHostObject<JsiSkSkottieAnimation>(runtime)
->getObject();
}

/**
* Creates the function for contructing a new instance of the
* JsiSkSkottieAnimation class.
*
* @param context platform context
* @return A function for creating a new host object wrapper for the JsiSkSkottieAnimation class.
*/
static const jsi::HostFunctionType
createCtor(std::shared_ptr<RNSkPlatformContext> context) {
return JSI_HOST_FUNCTION_LAMBDA {
auto jsonStr = arguments[0].asString(runtime).utf8(runtime);
auto animation = skottie::Animation::Builder()
.make(jsonStr.c_str(), jsonStr.size());

// Return the newly constructed object
return jsi::Object::createFromHostObject(
runtime, std::make_shared<JsiSkSkottieAnimation>(std::move(context), std::move(animation)));
};
}
};
}
2 changes: 2 additions & 0 deletions package/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
"libs/ios/libskia.xcframework",
"libs/ios/libskshaper.xcframework",
"libs/ios/libsvg.xcframework",
"libs/ios/libskottie.xcframework",
"libs/ios/libsksg.xcframework",
"react-native-skia.podspec",
"scripts/install-npm.js",
"scripts/setup-canvaskit.js",
Expand Down
4 changes: 3 additions & 1 deletion package/react-native-skia.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ Pod::Spec.new do |s|
s.ios.vendored_frameworks = [
'libs/ios/libskia.xcframework',
'libs/ios/libsvg.xcframework',
'libs/ios/libskshaper.xcframework'
'libs/ios/libskshaper.xcframework',
'libs/ios/libskottie.xcframework',
'libs/ios/libsksg.xcframework'
]

# All iOS cpp/h files
Expand Down
1 change: 1 addition & 0 deletions package/src/renderer/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export * from "./imageFilters";
export * from "./pathEffects";
export * from "../processors";
export * from "./Picture";
export * from "./skottie";

export * from "./Group";
export * from "./Mask";
Expand Down
24 changes: 24 additions & 0 deletions package/src/renderer/components/skottie/SkottieAnimation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from "react";

import type { AnimatedProps } from "../../processors";
import type { RectProps } from "../shapes";
import { processRect } from "../../processors";
import { createDrawing } from "../../nodes/Drawing";
import type { SkSkottieAnimation } from "../../../skia/types/SkottieAnimation";

export type SkottieProps = RectProps & {
anim: SkSkottieAnimation;
// value from 0 - 1 (or negative as well?)
progress: number;
};

const onDraw = createDrawing<SkottieProps>(
({ canvas, Skia }, { anim, progress, ...rectProps }) => {
const rect = processRect(Skia, rectProps);
anim.seek(progress);
anim.render(canvas, rect);
}
);
export const SkottieAnimation = (props: AnimatedProps<SkottieProps>) => {
return <skDrawing onDraw={onDraw} {...props} />;
};
1 change: 1 addition & 0 deletions package/src/renderer/components/skottie/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./SkottieAnimation";
2 changes: 2 additions & 0 deletions package/src/skia/types/Skia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import type { SkPath } from "./Path/Path";
import type { SkContourMeasureIter } from "./ContourMeasure";
import type { PictureFactory, SkPictureRecorder } from "./Picture";
import type { Color, SkColor } from "./Color";
import type { SkSkottieAnimation } from "./SkottieAnimation";

/**
* Declares the interface for the native Skia API
Expand All @@ -45,6 +46,7 @@ export interface Skia {
) => SkContourMeasureIter;
Paint: () => SkPaint;
PictureRecorder: () => SkPictureRecorder;
SkottieAnimation: (jsonString: string) => SkSkottieAnimation;
Picture: PictureFactory;
Path: PathFactory;
Matrix: (matrix?: readonly number[]) => SkMatrix;
Expand Down
9 changes: 9 additions & 0 deletions package/src/skia/types/SkottieAnimation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { SkCanvas } from "./Canvas";
import type { SkRect } from "./Rect";

export interface SkSkottieAnimation {
readonly duration: number;
readonly fps: number;
readonly seek: (time: number) => void;
readonly render: (canvas: SkCanvas, rect: SkRect) => void;
}
3 changes: 3 additions & 0 deletions package/src/skia/web/JsiSkia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,7 @@ export const JsiSkApi = (CanvasKit: CanvasKit): Skia => ({
return new JsiSkRect(CanvasKit, CanvasKit.XYWHRect(x, y, width, height));
},
Surface: new JsiSkSurfaceFactory(CanvasKit),
SkottieAnimation: (_jsonString) => {
throw new Error("Not implemented yet on React Native Web");
},
});
4 changes: 3 additions & 1 deletion scripts/build-npm-package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ if (process.env.GITHUB_RUN_NUMBER === undefined) {

// Check that Android Skia libs are built
["armeabi-v7a", "arm64-v8a", "x86", "x86_64"].forEach((cpu) => {
["libskia.a", "libskshaper.a", "libsvg.a"].forEach((target) => {
["libskia.a", "libskshaper.a", "libsvg.a", "libskottie.a", "libsksg.a"].forEach((target) => {
const path = `./package/libs/android/${cpu}/${target}`;
checkFileExists(
path,
Expand All @@ -56,6 +56,8 @@ if (process.env.GITHUB_RUN_NUMBER === undefined) {
"libskia.xcframework",
"libskshaper.xcframework",
"libsvg.xcframework",
"libskottie.xcframework",
"libsksg.xcframework"
].forEach((lib) => {
checkFileExists(
`./package/libs/ios/${lib}`,
Expand Down
6 changes: 3 additions & 3 deletions scripts/skia-configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const commonArgs = [
["skia_use_system_zlib", false],
["skia_enable_tools", false],
["is_official_build", true],
["skia_enable_skottie", false],
["skia_enable_skottie", true],
["is_debug", false],
["skia_enable_pdf", false],
["skia_enable_flutter_defines", true],
Expand Down Expand Up @@ -84,7 +84,7 @@ export const configurations: Configuration = {
],
],
outputRoot: "package/libs/android",
outputNames: ["libskia.a", "libskshaper.a", "libsvg.a"],
outputNames: ["libskia.a", "libskshaper.a", "libsvg.a", "libskottie.a", "libsksg.a"],
},
ios: {
targets: {
Expand Down Expand Up @@ -143,6 +143,6 @@ export const configurations: Configuration = {
["cxx", '"clang++"'],
],
outputRoot: "package/libs/ios",
outputNames: ["libskia.a", "libskshaper.a", "libsvg.a"],
outputNames: ["libskia.a", "libskshaper.a", "libsvg.a", "libskottie.a", "libsksg.a"],
},
};
4 changes: 3 additions & 1 deletion scripts/workflow-copy-libs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ const sources = [

const destinations = ["armeabi-v7a", "arm64-v8a", "x86", "x86_64"];

const androidFiles = ["libskia.a", "libskshaper.a", "libsvg.a"];
const androidFiles = ["libskia.a", "libskshaper.a", "libsvg.a", "libskottie.a", "libsksg.a"];
const iosFiles = [
"libskia.xcframework",
"libskshaper.xcframework",
"libsvg.xcframework",
"libskottie.xcframework",
"libsksg.xcframework"
];

const copyFiles = (from: string, to: string, files: string[]) => {
Expand Down