diff --git a/bun.lock b/bun.lock
index 3c9236b9..e7cb532e 100644
--- a/bun.lock
+++ b/bun.lock
@@ -22,7 +22,6 @@
"react-native-screens": "^4.19.0",
"react-native-video": "^6.18.0",
"react-native-worklets": "^0.7.1",
- "react-native-worklets-core": "^1.6.2",
"shared": "workspace:^",
},
"devDependencies": {
@@ -66,7 +65,6 @@
"react-native-screens": "~4.16.0",
"react-native-video": "^6.18.0",
"react-native-worklets": "0.5.1",
- "react-native-worklets-core": "^1.6.2",
"shared": "workspace:^",
},
"devDependencies": {
@@ -92,6 +90,7 @@
"react": "19.2.0",
"react-native": "0.83.1",
"react-native-builder-bob": "^0.40.17",
+ "react-native-worklets": "^0.7.1",
"react-native-worklets-core": "^1.6.2",
"release-it": "^15.0.0",
"typescript": "^5.8.3",
@@ -99,7 +98,8 @@
"peerDependencies": {
"react": "*",
"react-native": "*",
- "react-native-worklets-core": ">=1.3.2",
+ "react-native-reanimated": ">=4.0.0",
+ "react-native-worklets": "*",
},
},
},
diff --git a/examples/AppExampleFabric/index.js b/examples/AppExampleFabric/index.js
index 0e41963a..e9b4e1f7 100644
--- a/examples/AppExampleFabric/index.js
+++ b/examples/AppExampleFabric/index.js
@@ -3,9 +3,6 @@ import App from 'shared/src/App'
import { name as appName } from './app.json'
import { StrictMode } from 'react'
-import { version } from 'react-native-worklets-core/package.json'
-console.log(`Using react-native-worklets-core@${version}`)
-
// Setup a logger for filament
import { setLogger } from 'react-native-filament'
// A function that can wrap a console log call to add a prefix
diff --git a/examples/AppExampleFabric/package.json b/examples/AppExampleFabric/package.json
index c1c47e0f..100c7c8b 100644
--- a/examples/AppExampleFabric/package.json
+++ b/examples/AppExampleFabric/package.json
@@ -27,7 +27,6 @@
"react-native-screens": "^4.19.0",
"react-native-video": "^6.18.0",
"react-native-worklets": "^0.7.1",
- "react-native-worklets-core": "^1.6.2",
"shared": "workspace:^"
},
"devDependencies": {
diff --git a/examples/ExpoExample/package.json b/examples/ExpoExample/package.json
index d74164bc..f769905a 100644
--- a/examples/ExpoExample/package.json
+++ b/examples/ExpoExample/package.json
@@ -23,7 +23,6 @@
"react-native-screens": "~4.16.0",
"react-native-video": "^6.18.0",
"react-native-worklets": "0.5.1",
- "react-native-worklets-core": "^1.6.2",
"shared": "workspace:^"
},
"devDependencies": {
diff --git a/examples/Shared/src/App.tsx b/examples/Shared/src/App.tsx
index 523b50bd..d327f0ed 100644
--- a/examples/Shared/src/App.tsx
+++ b/examples/Shared/src/App.tsx
@@ -3,6 +3,7 @@ import { StyleSheet, Pressable, Text, View, ScrollView } from 'react-native'
import { NavigationContainer, useNavigation } from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import { GestureHandlerRootView } from 'react-native-gesture-handler'
+import {SafeAreaView} from 'react-native-safe-area-context'
import { AnimationTransitions } from './AnimationTransitions'
import { AnimationTransitionsRecording } from './AnimationTransitionsRecording'
@@ -50,6 +51,7 @@ function NavigationItem(props: { name: string; route: string }) {
function HomeScreen() {
return (
+
@@ -69,6 +71,7 @@ function HomeScreen() {
+
)
}
@@ -88,30 +91,30 @@ function App() {
-
-
-
-
-
-
+ /> */}
+ {/* */}
+ {/* */}
+ {/* */}
+ {/* */}
+ {/* */}
-
-
-
-
-
-
-
-
+ {/* */}
+ {/* */}
+ {/* */}
+ {/* */}
+ {/* */}
+ {/* */}
+ {/* */}
+ {/* */}
-
+ {/* */}
diff --git a/package.json b/package.json
index 5b6f05ec..a02e14de 100644
--- a/package.json
+++ b/package.json
@@ -13,7 +13,6 @@
}
],
"scripts": {
- "postinstall": "bunx patch-package"
},
"license": "MIT",
"bugs": {
diff --git a/package/android/CMakeLists.txt b/package/android/CMakeLists.txt
index a7e1ec71..88304458 100644
--- a/package/android/CMakeLists.txt
+++ b/package/android/CMakeLists.txt
@@ -38,6 +38,7 @@ add_library(
../cpp/RNFChoreographer.cpp
../cpp/RNFChoreographerWrapper.cpp
../cpp/RNFListener.cpp
+ ../cpp/jsi/RNFBoxedHybridObject.cpp
../cpp/jsi/RNFHybridObject.cpp
../cpp/jsi/RNFPromise.cpp
../cpp/jsi/RNFPromiseFactory.cpp
@@ -141,16 +142,15 @@ else()
)
endif()
-# Link with RNWC:
-find_package(react-native-worklets-core REQUIRED CONFIG)
-message("RN Filament: react-native-worklets core found! Enabling Worklets support...")
-message("RN Filament: react-native-worklets-core found in ${react-native-worklets-core_DIR}")
+
+find_package(react-native-worklets REQUIRED) # <-- for Worklets
target_link_libraries(
${PACKAGE_NAME}
- react-native-worklets-core::rnworklets
+ react-native-worklets::worklets
)
add_definitions(-DHAS_WORKLETS=1)
+
# Filament (local CMake project as a git submodule)
message("RN Filament: Adding pre-compiled libraries in ${FILAMENT_DIR}...")
file(GLOB FILAMENT_LIBRARIES "${FILAMENT_DIR}/lib/${ANDROID_ABI}/*.a")
diff --git a/package/android/build.gradle b/package/android/build.gradle
index 0ce7ec38..a67718fa 100644
--- a/package/android/build.gradle
+++ b/package/android/build.gradle
@@ -189,7 +189,7 @@ dependencies {
// For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+"
- implementation project(":react-native-worklets-core")
+ implementation project(":react-native-worklets")
}
if (isNewArchitectureEnabled()) {
diff --git a/package/cpp/RNFFilamentProxy.cpp b/package/cpp/RNFFilamentProxy.cpp
index c881994d..9444308f 100644
--- a/package/cpp/RNFFilamentProxy.cpp
+++ b/package/cpp/RNFFilamentProxy.cpp
@@ -10,6 +10,7 @@
#include "core/RNFEngineConfigHelper.h"
#include "jsi/RNFPromise.h"
#include "threading/RNFDispatcher.h"
+#include "threading/RNFAsyncQueueImpl.h"
#include
#include
@@ -31,7 +32,10 @@ void FilamentProxy::loadHybridMethods() {
registerHybridMethod("getCurrentDispatcher", &FilamentProxy::getCurrentDispatcher, this);
registerHybridGetter("hasWorklets", &FilamentProxy::getHasWorklets, this);
#if HAS_WORKLETS
- registerHybridMethod("createWorkletContext", &FilamentProxy::createWorkletContext, this);
+ // Newly added APIs:
+ registerHybridMethod("createWorkletAsyncQueue", &FilamentProxy::createWorkletAsyncQueue, this);
+ registerHybridMethod("installDispatcher", &FilamentProxy::installDispatcher, this);
+ registerHybridMethod("box", &FilamentProxy::box, this);
#endif
}
@@ -44,23 +48,29 @@ bool FilamentProxy::getHasWorklets() {
}
#if HAS_WORKLETS
-std::shared_ptr FilamentProxy::createWorkletContext() {
- Logger::log(TAG, "Creating Worklet Context...");
- auto jsDispatcher = getJSDispatcher();
- auto runOnJS = [=](std::function&& function) { jsDispatcher->runAsync(std::move(function)); };
- auto renderThreadDispatcher = getRenderThreadDispatcher();
- auto runOnWorklet = [=](std::function&& function) { renderThreadDispatcher->runAsync(std::move(function)); };
- auto& runtime = getMainJSRuntime();
- auto workletContext = std::make_shared("FilamentRenderer", &runtime, runOnJS, runOnWorklet);
- Logger::log(TAG, "Successfully created WorkletContext! Installing global Dispatcher...");
-
- workletContext->invokeOnWorkletThread([=](RNWorklet::JsiWorkletContext*, jsi::Runtime& runtime) {
+std::shared_ptr FilamentProxy::createWorkletAsyncQueue() {
+ Logger::log(TAG, "Creating Worklet AsyncQueue...");
+ auto renderThreadDispatcher = getRenderThreadDispatcher();
+// auto runOnWorklet = [=](std::function&& function) { renderThreadDispatcher->runAsync(std::move(function)); };
+ // TODO: i am pretty sure i should hold this dispatcher somewhere? or will the JS engine keep it alive as its NativeState?
+ auto asyncQueue = std::make_shared(renderThreadDispatcher);
+
+ return asyncQueue;
+}
+
+
+jsi::Value FilamentProxy::installDispatcher(jsi::Runtime& runtime, const jsi::Value&, const jsi::Value*, size_t) {
+ auto renderThreadDispatcher = getRenderThreadDispatcher(); // todo: return dispatcher, and pass it here is cleaner i guess
+ // Note: one thing that is odd, is that this is called with the correct runtime, but on the "wrong" thread.
+ // this will still be called from the JS thread, but the runtime is the worklet runtime.
Dispatcher::installRuntimeGlobalDispatcher(runtime, renderThreadDispatcher);
- Logger::log(TAG, "Successfully installed global Dispatcher in WorkletContext!");
- });
+ return jsi::Value::undefined();
+}
- return workletContext;
+std::shared_ptr FilamentProxy::box(const std::shared_ptr& hybridObject) {
+ return std::make_shared(hybridObject);
}
+
#endif
jsi::Value FilamentProxy::getCurrentDispatcher(jsi::Runtime& runtime, const jsi::Value&, const jsi::Value*, size_t) {
diff --git a/package/cpp/RNFFilamentProxy.h b/package/cpp/RNFFilamentProxy.h
index 6cf84b00..d731579f 100644
--- a/package/cpp/RNFFilamentProxy.h
+++ b/package/cpp/RNFFilamentProxy.h
@@ -18,21 +18,13 @@
#include "bullet/RNFBulletWrapper.h"
#include "core/RNFEngineWrapper.h"
#include "jsi/RNFHybridObject.h"
+#include "jsi/RNFBoxedHybridObject.h"
#include "test/RNFTestHybridObject.h"
#include "threading/RNFDispatcher.h"
+#include "threading/RNFAsyncQueueImpl.h"
#include
-#ifdef HAS_WORKLETS
-#if __has_include()
-// Old arch & CocoaPod headers on apple
-#include
-#else
-// New arch android, where RNWC and RNF c++ modules are build inside the app's project
-#include "WKTJsiWorkletContext.h"
-#endif
-#endif // HAS_WORKLETS
-
namespace margelo {
using namespace facebook;
@@ -93,6 +85,7 @@ class FilamentProxy : public HybridObject {
#if HAS_WORKLETS
/**
+ * TODO: update this comment
* Create a new Worklet Context that runs on the Filament Renderer Thread.
*
* The FilamentProxy does not hold a strong reference to the Worklet Context,
@@ -100,7 +93,9 @@ class FilamentProxy : public HybridObject {
*
* The caller (JS) is responsible for keeping the returned reference strong.
*/
- std::shared_ptr createWorkletContext();
+ std::shared_ptr createWorkletAsyncQueue();
+ jsi::Value installDispatcher(jsi::Runtime& runtime, const jsi::Value&, const jsi::Value*, size_t);
+ std::shared_ptr box(const std::shared_ptr& hybridObject);
#endif
public:
diff --git a/package/cpp/jsi/RNFBoxedHybridObject.cpp b/package/cpp/jsi/RNFBoxedHybridObject.cpp
new file mode 100644
index 00000000..aafbd51f
--- /dev/null
+++ b/package/cpp/jsi/RNFBoxedHybridObject.cpp
@@ -0,0 +1,31 @@
+//
+// BoxedHybridObject.cpp
+// NitroModules
+//
+// Created by Marc Rousavy on 17.09.24.
+//
+
+#include "RNFBoxedHybridObject.h"
+
+namespace margelo {
+
+ std::vector RNFBoxedHybridObject::getPropertyNames(facebook::jsi::Runtime& runtime) {
+ return jsi::PropNameID::names(runtime, "unbox");
+ }
+
+ jsi::Value RNFBoxedHybridObject::get(jsi::Runtime& runtime, const jsi::PropNameID& propName) {
+ std::string name = propName.utf8(runtime);
+
+ if (name == "unbox") {
+ return jsi::Function::createFromHostFunction(
+ runtime, jsi::PropNameID::forUtf8(runtime, "unbox"), 0,
+ [hybridObject = _hybridObject](jsi::Runtime& runtime, const jsi::Value&, const jsi::Value*, size_t) -> jsi::Value {
+ return JSIConverter>::toJSI(runtime, hybridObject);
+// return jsi::Object::createFromHostObject(runtime, hybridObject);
+ });
+ }
+
+ return jsi::Value::undefined();
+ }
+
+} // namespace margelo::nitro
diff --git a/package/cpp/jsi/RNFBoxedHybridObject.h b/package/cpp/jsi/RNFBoxedHybridObject.h
new file mode 100644
index 00000000..5dcd686e
--- /dev/null
+++ b/package/cpp/jsi/RNFBoxedHybridObject.h
@@ -0,0 +1,39 @@
+//
+// Created by Hanno Gödecke on 11.01.26.
+// From https://github.com/mrousavy/nitro/blob/afa41bae947ecf738c33569ead42eaf0825cc6d5/packages/react-native-nitro-modules/cpp/core/BoxedHybridObject.hpp
+// TODO: should be removable once migrated to nitro modules + RNW supporting nitro HybridObjects
+//
+
+#pragma once
+
+#include "RNFHybridObject.h"
+#include
+#include
+
+namespace margelo {
+
+ using namespace facebook;
+
+/**
+ * Represents a `HybridObject` that has been boxed into a `jsi::HostObject`.
+ *
+ * While `HybridObject`s are runtime agnostic, some threading/worklet libraries do not support copying over objects
+ * with `jsi::NativeState` and a prototype chain (which is what a `HybridObject` is), so Nitro offers support for
+ * boxing those `HybridObject`s into a type that those libraries support - which is a `jsi::HostObject`.
+ *
+ * Simply call `unbox()` on this `jsi::HostObject` from the new Runtime/context to get the `HybridObject` again.
+ */
+ class RNFBoxedHybridObject final : public jsi::HostObject {
+ public:
+ explicit RNFBoxedHybridObject(const std::shared_ptr& hybridObject) : _hybridObject(hybridObject) {}
+
+ public:
+ jsi::Value get(jsi::Runtime& runtime, const jsi::PropNameID& propName) override;
+ std::vector getPropertyNames(jsi::Runtime& runtime) override;
+
+ private:
+ std::shared_ptr _hybridObject;
+ };
+
+} // namespace margelo::nitro
+
diff --git a/package/cpp/threading/RNFAsyncQueueImpl.h b/package/cpp/threading/RNFAsyncQueueImpl.h
new file mode 100644
index 00000000..239dc3f2
--- /dev/null
+++ b/package/cpp/threading/RNFAsyncQueueImpl.h
@@ -0,0 +1,27 @@
+//
+// Created by Hanno Gödecke on 11.01.26.
+//
+
+#if __has_include()
+#include
+#elif __has_include()
+#include
+#else
+#error react-native-worklets Prefab not found!
+#endif
+
+#pragma once
+
+namespace margelo {
+ class RNFAsyncQueueImpl : public worklets::AsyncQueue {
+ public:
+ explicit RNFAsyncQueueImpl(std::shared_ptr dispatcher) : _dispatcher(std::move(dispatcher)) {}
+
+ void push(std::function &&job) override {
+ _dispatcher->runAsync(std::move(job));
+ }
+
+ private:
+ std::shared_ptr _dispatcher;
+ };
+} // namespace margelo
diff --git a/package/cpp/threading/RNFDispatcher.cpp b/package/cpp/threading/RNFDispatcher.cpp
index 41e3c80d..9e7a2ece 100644
--- a/package/cpp/threading/RNFDispatcher.cpp
+++ b/package/cpp/threading/RNFDispatcher.cpp
@@ -1,6 +1,5 @@
#include "RNFDispatcher.h"
#include "RNFLogger.h"
-#include "jsi/RNFWorkletRuntimeCollector.h"
namespace margelo {
@@ -9,10 +8,7 @@ using namespace facebook;
static constexpr auto GLOBAL_DISPATCHER_HOLDER_NAME = "__globalDispatcher";
void Dispatcher::installRuntimeGlobalDispatcher(jsi::Runtime& runtime, std::shared_ptr dispatcher) {
- Logger::log(TAG, "Installing global Dispatcher Holder...");
-
- // Track the runtime's lifetime
- WorkletRuntimeCollector::install(runtime);
+ Logger::log(TAG, "Installing global Dispatcher Holder on runtime ptr: " + std::to_string(reinterpret_cast(&runtime)) + " desc: " + runtime.description());
jsi::Object dispatcherHolder(runtime);
dispatcherHolder.setNativeState(runtime, dispatcher);
diff --git a/package/package.json b/package/package.json
index 0968dafe..fde08cd0 100644
--- a/package/package.json
+++ b/package/package.json
@@ -94,6 +94,7 @@
"react": "19.2.0",
"react-native": "0.83.1",
"react-native-builder-bob": "^0.40.17",
+ "react-native-worklets": "^0.7.1",
"react-native-worklets-core": "^1.6.2",
"release-it": "^15.0.0",
"typescript": "^5.8.3"
@@ -101,7 +102,8 @@
"peerDependencies": {
"react": "*",
"react-native": "*",
- "react-native-worklets-core": ">=1.3.2"
+ "react-native-reanimated": ">=4.0.0",
+ "react-native-worklets": "*"
},
"release-it": {
"git": {
diff --git a/package/scripts/build-filament.sh b/package/scripts/build-filament.sh
index f6a007f7..346e1f34 100755
--- a/package/scripts/build-filament.sh
+++ b/package/scripts/build-filament.sh
@@ -120,7 +120,20 @@ if [ "$BUILD_ANDROID" = "true" ]; then
# TODO(Marc): Use Filament from the Maven/Gradle library, to avoid shipping this huge dependency over npm.
echo "[Filament] Building Filament for Android ($target)"
# -v = Exclude Vulkan support
- ./build.sh -p android "$target"
+ if [ "$CI" = "true" ]; then
+ # In CI, pipe through tail to keep only last 1000 lines (prevents disk space issues)
+ ./build.sh -p android "$target" 2>&1 | tail -n 1000 > filament-android-build.log
+ # Check the exit code of build.sh (first command in pipe)
+ if [ "${PIPESTATUS[0]}" -ne 0 ]; then
+ echo "Build failed! Last 1000 lines of output:"
+ cat filament-android-build.log
+ rm filament-android-build.log
+ exit 1
+ fi
+ rm filament-android-build.log
+ else
+ ./build.sh -p android "$target"
+ fi
# echo "Building Android .aar ($target)..."
# cd android
diff --git a/package/src/ErrorUtils.ts b/package/src/ErrorUtils.ts
index d361ce06..970d6f77 100644
--- a/package/src/ErrorUtils.ts
+++ b/package/src/ErrorUtils.ts
@@ -1,4 +1,4 @@
-import { Worklets } from 'react-native-worklets-core'
+import { runOnJS } from 'react-native-worklets'
/**
* Report an error to react native's `ErrorUtils` if available, or log to console otherwise.
@@ -18,7 +18,7 @@ export function reportError(error: unknown, fatal: boolean): void {
}
}
-const throwErrorOnJS = Worklets.createRunOnJS((message: string, stack: string | undefined, fatal: boolean) => {
+const throwErrorOnJS = runOnJS((message: string, stack: string | undefined, fatal: boolean) => {
const error = new Error()
error.message = message
error.stack = stack
diff --git a/package/src/hooks/internal/useApplyTransformations.tsx b/package/src/hooks/internal/useApplyTransformations.tsx
index e59a8942..17e53c06 100644
--- a/package/src/hooks/internal/useApplyTransformations.tsx
+++ b/package/src/hooks/internal/useApplyTransformations.tsx
@@ -4,7 +4,7 @@ import { useFilamentContext } from '../useFilamentContext'
import { AABB, Entity, Float3 } from '../../types'
import { areFloat3Equal, isWorkletSharedValue } from '../../utilities/helper'
import { useWorkletEffect } from '../useWorkletEffect'
-import { ISharedValue, Worklets } from 'react-native-worklets-core'
+import { makeMutable, type SharedValue } from 'react-native-reanimated'
type Params = {
// If null it will not take the entity from the context, as it indicates that it will be provided through the param
@@ -76,9 +76,9 @@ export function useApplyTransformations({ to: entity, transformProps, aabb }: Pa
transformToUnitCube,
])
- const prevScaleShared = useRef(isWorkletSharedValue(scale) ? Worklets.createSharedValue(null) : null)
- const prevRotateShared = useRef(isWorkletSharedValue(rotate) ? Worklets.createSharedValue(null) : null)
- const prevPositionShared = useRef(isWorkletSharedValue(position) ? Worklets.createSharedValue(null) : null)
+ const prevScaleShared = useRef(isWorkletSharedValue(scale) ? makeMutable(null) : null)
+ const prevRotateShared = useRef(isWorkletSharedValue(rotate) ? makeMutable(null) : null)
+ const prevPositionShared = useRef(isWorkletSharedValue(position) ? makeMutable(null) : null)
// Effects for when a transform option is a shared value (SRT)
useWorkletEffect(() => {
@@ -86,18 +86,19 @@ export function useApplyTransformations({ to: entity, transformProps, aabb }: Pa
if (entity == null) return
- const unsubscribers: (() => void)[] = []
+ const unsubscribers: [SharedValue, number][] = []
// Generic handler for worklet transform values
const createTransformHandler = (
value: any,
- prevValueShared: ISharedValue | null,
+ prevValueShared: SharedValue | null,
updater: (newValue: Float3) => void
) => {
'worklet'
if (value == null || !isWorkletSharedValue(value) || Array.isArray(value)) return null
- const unsubscribe = value.addListener(() => {
+ const randomNumericId = Number(Math.random().toString().substring(12))
+ value.addListener(randomNumericId, () => {
'worklet'
// Check if value has changed to avoid duplicate applications in strict mode
@@ -113,7 +114,7 @@ export function useApplyTransformations({ to: entity, transformProps, aabb }: Pa
}
})
- unsubscribers.push(unsubscribe)
+ unsubscribers.push([value, randomNumericId])
return value
}
@@ -148,9 +149,10 @@ export function useApplyTransformations({ to: entity, transformProps, aabb }: Pa
positionHandler.value = [positionHandler.value[0], positionHandler.value[1], positionHandler.value[2]]
}
- return () => {
- 'worklet'
- unsubscribers.forEach((unsubscribe) => unsubscribe())
- }
+ // TODO: bring back, currently crashes?
+ // return () => {
+ // 'worklet'
+ // unsubscribers.forEach(([value, id]) => value.removeListener(id))
+ // }
})
}
diff --git a/package/src/hooks/useEngine.ts b/package/src/hooks/useEngine.ts
index 8d9ede6c..29236d42 100644
--- a/package/src/hooks/useEngine.ts
+++ b/package/src/hooks/useEngine.ts
@@ -1,7 +1,9 @@
import type { Engine, EngineBackend, EngineConfig } from '../types'
import { FilamentProxy } from '../native/FilamentProxy'
-import { IWorkletContext, useWorklet } from 'react-native-worklets-core'
import { useDisposableResource } from './useDisposableResource'
+import { type WorkletRuntime } from 'react-native-worklets'
+import { useCallback } from 'react'
+import { scheduleOnRuntimeAsync } from '../utilities/scheduleOnRuntimeAsync'
export interface EngineProps {
/**
@@ -15,15 +17,17 @@ export interface EngineProps {
*/
config?: EngineConfig
- context: IWorkletContext
+ runtime: WorkletRuntime
}
-export function useEngine({ backend, config, context }: EngineProps): Engine | undefined {
+export function useEngine({ backend, config, runtime }: EngineProps): Engine | undefined {
// Important: create the engine on the worklet thread, so its owned by the worklet thread
- const createEngine = useWorklet(context, () => {
- 'worklet'
- return FilamentProxy.createEngine(backend ?? undefined, config ?? undefined)
- })
+ const createEngine = useCallback(() => {
+ return scheduleOnRuntimeAsync(runtime, () => {
+ 'worklet'
+ return FilamentProxy.createEngine(backend ?? undefined, config ?? undefined)
+ })
+ }, [backend, config, runtime])
const engine = useDisposableResource(createEngine)
return engine
diff --git a/package/src/hooks/useFilamentContext.ts b/package/src/hooks/useFilamentContext.ts
index 12dace35..1d3ebb9f 100644
--- a/package/src/hooks/useFilamentContext.ts
+++ b/package/src/hooks/useFilamentContext.ts
@@ -11,7 +11,7 @@ import {
TransformManager,
View,
} from '../types'
-import { IWorkletContext } from 'react-native-worklets-core'
+import { WorkletRuntime } from 'react-native-worklets'
export type FilamentContextType = {
engine: Engine
@@ -23,7 +23,7 @@ export type FilamentContextType = {
camera: RNFCamera
renderer: Renderer
nameComponentManager: NameComponentManager
- workletContext: IWorkletContext
+ workletRuntime: WorkletRuntime
/**
* This is a private API, do not use this.
diff --git a/package/src/hooks/useLightEntity.ts b/package/src/hooks/useLightEntity.ts
index 06740b2b..34ff3579 100644
--- a/package/src/hooks/useLightEntity.ts
+++ b/package/src/hooks/useLightEntity.ts
@@ -1,15 +1,14 @@
import { useMemo } from 'react'
import { LightConfig, LightManager } from '../types'
-import { ISharedValue } from 'react-native-worklets-core'
-import { useFilamentContext } from './useFilamentContext'
import { useWorkletEffect } from './useWorkletEffect'
import convertKelvinToLinearSRGB from '../utilities/convertKelvinToLinearSRGB'
+import { type SharedValue } from 'react-native-reanimated'
export type UseLightEntityProps =
| LightConfig
| (Omit & {
- intensity?: number | ISharedValue
- colorKelvin?: number | ISharedValue
+ intensity?: number | SharedValue
+ colorKelvin?: number | SharedValue
})
/**
@@ -60,7 +59,6 @@ export function useLightEntity(lightManager: LightManager, config: UseLightEntit
])
// Subscribe to the intensity shared value
- const { workletContext } = useFilamentContext()
useWorkletEffect(() => {
'worklet'
const intensity = config.intensity
@@ -69,12 +67,21 @@ export function useLightEntity(lightManager: LightManager, config: UseLightEntit
const setIntensity = lightManager.setIntensity
- return intensity.addListener(
- workletContext.createRunAsync(() => {
+ const randomNumericId = Number(Math.random().toString().substring(12))
+ intensity.addListener(
+ randomNumericId,
+ // TODO: do we need to wrap this in createRunAsync?
+ () => {
'worklet'
setIntensity(entity, intensity.value)
- })
+ }
)
+
+ // TODO: i believe this is causing crashes rn
+ // return () => {
+ // 'worklet'
+ // intensity.removeListener(randomNumericId)
+ // }
})
// Subscribe to the colorKelvin shared value
@@ -86,12 +93,17 @@ export function useLightEntity(lightManager: LightManager, config: UseLightEntit
const setColor = lightManager.setColor
- return colorKelvin.addListener(
- workletContext.createRunAsync(() => {
- 'worklet'
- setColor(entity, convertKelvinToLinearSRGB(colorKelvin.value))
- })
- )
+ const randomNumericId = Number(Math.random().toString().substring(12))
+ colorKelvin.addListener(randomNumericId, () => {
+ 'worklet'
+ setColor(entity, convertKelvinToLinearSRGB(colorKelvin.value))
+ })
+
+ // TODO: i believe this is causing crashes rn
+ // return () => {
+ // 'worklet'
+ // colorKelvin.removeListener(randomNumericId)
+ // }
})
return entity
diff --git a/package/src/hooks/useModel.ts b/package/src/hooks/useModel.ts
index c9244554..de19d1a3 100644
--- a/package/src/hooks/useModel.ts
+++ b/package/src/hooks/useModel.ts
@@ -6,6 +6,7 @@ import usePrevious from './usePrevious'
import { useWorkletEffect } from './useWorkletEffect'
import { AABB, Entity } from '../types'
import { useMemo } from 'react'
+import { scheduleOnRuntimeAsync } from '../utilities/scheduleOnRuntimeAsync'
export interface UseModelConfigParams {
/**
@@ -59,7 +60,7 @@ export type FilamentModel =
*/
export function useModel(source: BufferSource, props?: UseModelConfigParams): FilamentModel {
const { shouldReleaseSourceData = true, addToScene = true, instanceCount } = props ?? {}
- const { engine, scene, workletContext } = useFilamentContext()
+ const { engine, scene, workletRuntime } = useFilamentContext()
const assetBuffer = useBuffer({ source: source, releaseOnUnmount: false })
// Note: the native cleanup of the asset will remove it automatically from the scene
@@ -69,7 +70,7 @@ export function useModel(source: BufferSource, props?: UseModelConfigParams): Fi
throw new Error('instanceCount must be greater than 0')
}
- return workletContext.runAsync(() => {
+ return scheduleOnRuntimeAsync(workletRuntime, () => {
'worklet'
let loadedAsset: FilamentAsset
@@ -84,7 +85,7 @@ export function useModel(source: BufferSource, props?: UseModelConfigParams): Fi
return loadedAsset
})
- }, [assetBuffer, workletContext, engine, instanceCount])
+ }, [assetBuffer, instanceCount, workletRuntime, engine])
useWorkletEffect(() => {
'worklet'
diff --git a/package/src/hooks/useWorkletCallback.ts b/package/src/hooks/useWorkletCallback.ts
index 88c5d591..5793d075 100644
--- a/package/src/hooks/useWorkletCallback.ts
+++ b/package/src/hooks/useWorkletCallback.ts
@@ -1,27 +1,14 @@
-import { getWorkletDependencies } from 'react-native-worklets-core'
import { useFilamentContext } from './useFilamentContext'
-import { wrapWithErrorHandler } from '../ErrorUtils'
-import { useMemo } from 'react'
+import { useCallback } from 'react'
+import { scheduleOnRuntimeAsync } from '../utilities/scheduleOnRuntimeAsync'
/**
* Creates a callback that can be executed in he separate worklet thread of the engine.
*/
export function useWorkletCallback any>(callback: T): (...args: Parameters) => Promise> {
- const { workletContext } = useFilamentContext()
+ const { workletRuntime } = useFilamentContext()
- // Note: from react-native-worklets-core/useWorklet
- // As we want to wrap using `wrapWithErrorHandler` the dependencies must be captured from the
- // callback, not from the wrapper.
-
- // As a dependency for this use-memo we use all of the values captured inside the worklet,
- // as well as the unique context name.
- const dependencies = [...getWorkletDependencies(callback)]
-
- return useMemo(
- () => {
- return workletContext.createRunAsync(wrapWithErrorHandler(callback))
- },
- // eslint-disable-next-line react-hooks/exhaustive-deps
- dependencies
- )
+ return useCallback(() => {
+ return scheduleOnRuntimeAsync(workletRuntime, callback)
+ }, [callback, workletRuntime])
}
diff --git a/package/src/hooks/useWorkletEffect.ts b/package/src/hooks/useWorkletEffect.ts
index 0b1573c5..ac7e1922 100644
--- a/package/src/hooks/useWorkletEffect.ts
+++ b/package/src/hooks/useWorkletEffect.ts
@@ -1,30 +1,23 @@
import { useEffect } from 'react'
import { useFilamentContext } from './useFilamentContext'
-import { getWorkletDependencies, isWorklet } from 'react-native-worklets-core'
-import { wrapWithErrorHandler } from '../ErrorUtils'
+import { scheduleOnRuntime } from 'react-native-worklets'
+import { scheduleOnRuntimeAsync } from '../utilities/scheduleOnRuntimeAsync'
type CleanupFn = () => void
export function useWorkletEffect(workletFunction: () => CleanupFn | void) {
- const { workletContext } = useFilamentContext()
+ const { workletRuntime } = useFilamentContext()
useEffect(() => {
- const cleanupPromise = workletContext.runAsync(wrapWithErrorHandler(workletFunction))
+ const cleanupPromise = scheduleOnRuntimeAsync(workletRuntime, workletFunction)
return () => {
cleanupPromise.then((cleanup): void => {
if (cleanup == null || typeof cleanup !== 'function') {
// no cleanup function was returned, do nothing.
return
}
- if (isWorklet(cleanup)) {
- // call cleanup function on Worklet context
- workletContext.runAsync(cleanup)
- } else {
- // call normal cleanup JS function on normal context
- cleanup()
- }
+ scheduleOnRuntime(workletRuntime, cleanup)
})
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, getWorkletDependencies(workletFunction))
+ }, [workletFunction, workletRuntime])
}
diff --git a/package/src/native/FilamentProxy.ts b/package/src/native/FilamentProxy.ts
index f05162a8..2e647760 100644
--- a/package/src/native/FilamentProxy.ts
+++ b/package/src/native/FilamentProxy.ts
@@ -2,13 +2,12 @@ import { FilamentBuffer } from './FilamentBuffer'
import type { Engine } from '../types/Engine'
import { FilamentView } from './FilamentViewTypes'
import type { BulletAPI } from '../bullet/types/api'
-import type { IWorkletContext } from 'react-native-worklets-core'
import { EngineBackend, EngineConfig } from '../types'
import { TFilamentRecorder } from '../types/FilamentRecorder'
import { Choreographer } from '../types/Choreographer'
import { Dispatcher } from './Dispatcher'
import { FilamentModule } from './FilamentModule'
-import { Worklets } from 'react-native-worklets-core'
+import { createWorkletRuntime } from 'react-native-worklets'
interface TestHybridObject {
int: number
@@ -74,7 +73,10 @@ export interface TFilamentProxy {
*/
readonly hasWorklets: boolean
+ createChoreographer(): Choreographer
+
/**
+ * TODO: update content
* Create a Worklet context used for Rendering to Filament.
*
* This should only be called once, and the returned value should be kept strong.
@@ -91,9 +93,12 @@ export interface TFilamentProxy {
* })
* ```
*/
- createWorkletContext: () => IWorkletContext
-
- createChoreographer(): Choreographer
+ // New APIs i added:
+ createWorkletAsyncQueue: () => object
+ installDispatcher: () => void
+ box: (hybridObject: T) => {
+ unbox: () => T
+ }
}
const successful = FilamentModule.install()
@@ -114,15 +119,20 @@ if (proxy == null) {
if (!proxy.hasWorklets) {
throw new Error(
- 'Failed to initialize react-native-filament - Worklets are not available (HAS_WORKLETS=false), did you install react-native-worklets-core?'
+ 'Failed to initialize react-native-filament - Worklets are not available (HAS_WORKLETS=false), did you install react-native-worklets & react-native-reanimated?'
)
}
export const FilamentProxy = proxy
-// We must make sure that the Worklets API (module) is initialized (as its possible a lazy-loaded CxxTurboModule),
-// to initialize we must only call any property of the module:
-Worklets.defaultContext
-
-// Create our custom RNF worklet context:
-export const FilamentWorkletContext = proxy.createWorkletContext()
+const FilamentWorkletQueue = proxy.createWorkletAsyncQueue()
+export const FilamentWorkletRuntime = createWorkletRuntime({
+ name: 'FilamentWorkletRuntime',
+ useDefaultQueue: false,
+ customQueue: FilamentWorkletQueue,
+ initializer: () => {
+ 'worklet'
+ // Note: this will still be called from the JS thread, weird
+ proxy.installDispatcher()
+ },
+})
diff --git a/package/src/react/Animator.tsx b/package/src/react/Animator.tsx
index e5dd65b5..cfa247b6 100644
--- a/package/src/react/Animator.tsx
+++ b/package/src/react/Animator.tsx
@@ -2,9 +2,9 @@ import React, { useEffect } from 'react'
import { FilamentInstance } from '../types'
import { RenderCallbackContext } from './RenderCallbackContext'
import { useAnimator } from '../hooks/useAnimator'
-import { ISharedValue, useSharedValue } from 'react-native-worklets-core'
import usePrevious from '../hooks/usePrevious'
import { ParentInstancesContext } from './ParentInstancesContext'
+import { useSharedValue, type SharedValue } from 'react-native-reanimated'
export type AnimationItem = {
index: number
@@ -17,7 +17,7 @@ export type AnimatorProps = {
* The index of the animation to play. To find out the index for the animation you want to play, you can use the `onAnimationsLoaded` callback.
* @default 0
**/
- animationIndex?: number | ISharedValue
+ animationIndex?: number | SharedValue
/**
* Returns a list of all animations for the model.
@@ -117,12 +117,13 @@ function AnimatorImpl({ instance, animationIndex: animationIndexProp = 0, transi
// Update previous index if the prop is a shared value:
let value = animationIndexProp.value
- const removeListener = animationIndexProp.addListener(() => {
+ const listenerId = Date.now()
+ animationIndexProp.addListener(listenerId, () => {
prevAnimationIndex.value = value
value = animationIndexProp.value
})
return () => {
- removeListener()
+ animationIndexProp.removeListener(listenerId)
}
}, [animationIndexProp, prevAnimationIndex, previousAnimationIndexProp])
diff --git a/package/src/react/Camera.tsx b/package/src/react/Camera.tsx
index cea9e35c..11f9d960 100644
--- a/package/src/react/Camera.tsx
+++ b/package/src/react/Camera.tsx
@@ -1,4 +1,4 @@
-import { useSharedValue } from 'react-native-worklets-core'
+import { useSharedValue } from 'react-native-reanimated'
import { CameraManipulator, Float3 } from '../types'
import { useFilamentContext } from '../hooks/useFilamentContext'
import { RenderCallbackContext } from './RenderCallbackContext'
diff --git a/package/src/react/FilamentScene.tsx b/package/src/react/FilamentScene.tsx
index 8fd8c9d4..aa137512 100644
--- a/package/src/react/FilamentScene.tsx
+++ b/package/src/react/FilamentScene.tsx
@@ -1,15 +1,16 @@
-import { PropsWithChildren, useMemo } from 'react'
-import { FilamentProxy, FilamentWorkletContext } from '../native/FilamentProxy'
+import { PropsWithChildren, useCallback, useMemo } from 'react'
+import { FilamentProxy, FilamentWorkletRuntime } from '../native/FilamentProxy'
import { EngineProps, useEngine } from '../hooks/useEngine'
import { useDisposableResource } from '../hooks/useDisposableResource'
-import { useWorklet } from 'react-native-worklets-core'
import React from 'react'
import { Configurator, RendererConfigProps, ViewConfigProps } from './Configurator'
import { FilamentContext, FilamentContextType } from '../hooks/useFilamentContext'
import { RenderCallbackContext } from './RenderCallbackContext'
+import { runOnJS, scheduleOnRuntime } from 'react-native-worklets'
+import { Choreographer } from '../types'
export type FilamentProviderProps = PropsWithChildren<
- Omit &
+ Omit &
ViewConfigProps &
RendererConfigProps & {
fallback?: React.ReactElement
@@ -47,7 +48,7 @@ export type FilamentProviderProps = PropsWithChildren<
*/
export function FilamentScene({ children, fallback, config, backend, frameRateOptions, ...viewProps }: FilamentProviderProps) {
// First create the engine, which we need to create (almost) all other filament APIs
- const engine = useEngine({ config, backend, context: FilamentWorkletContext })
+ const engine = useEngine({ config, backend, runtime: FilamentWorkletRuntime })
// Create all Filament APIs using the engine
const transformManager = useDisposableResource(() => Promise.resolve(engine?.createTransformManager()), [engine])
@@ -61,10 +62,19 @@ export function FilamentScene({ children, fallback, config, backend, frameRateOp
// Create a choreographer for this context tree
const choreographer = useDisposableResource(
- useWorklet(FilamentWorkletContext, () => {
- 'worklet'
- return FilamentProxy.createChoreographer()
- })
+ useCallback(() => {
+ // TODO: DRY this pattern?
+ let resolve: (engine: Choreographer) => void
+ const promise = new Promise((res) => {
+ resolve = res
+ })
+ scheduleOnRuntime(FilamentWorkletRuntime, () => {
+ 'worklet'
+ const choreographerImpl = FilamentProxy.createChoreographer()
+ runOnJS(resolve)(choreographerImpl)
+ })
+ return promise
+ }, [])
)
// Construct the context object value:
@@ -94,7 +104,7 @@ export function FilamentScene({ children, fallback, config, backend, frameRateOp
camera,
renderer,
nameComponentManager,
- workletContext: FilamentWorkletContext,
+ workletRuntime: FilamentWorkletRuntime,
choreographer: choreographer,
}
}, [engine, transformManager, renderableManager, scene, lightManager, view, camera, renderer, nameComponentManager, choreographer])
diff --git a/package/src/react/FilamentView.tsx b/package/src/react/FilamentView.tsx
index 69e85f3c..61aafe48 100644
--- a/package/src/react/FilamentView.tsx
+++ b/package/src/react/FilamentView.tsx
@@ -1,15 +1,16 @@
import React from 'react'
import { FilamentProxy } from '../native/FilamentProxy'
import FilamentNativeView, { type FilamentViewNativeType, type NativeProps } from '../native/specs/FilamentViewNativeComponent'
-import { reportWorkletError, wrapWithErrorHandler } from '../ErrorUtils'
import { FilamentContext } from '../hooks/useFilamentContext'
import { RenderCallback, SwapChain } from 'react-native-filament'
import type { SurfaceProvider, FilamentView as RNFFilamentView } from '../native/FilamentViewTypes'
import { Listener } from '../types/Listener'
import { findNodeHandle, GestureResponderEvent } from 'react-native'
-import { Worklets } from 'react-native-worklets-core'
import { getLogger } from '../utilities/logger/Logger'
import { getTouchHandlers } from './TouchHandlerContext'
+import { scheduleOnRuntimeAsync } from '../utilities/scheduleOnRuntimeAsync'
+import { makeMutable } from 'react-native-reanimated'
+import { reportWorkletError } from '../ErrorUtils'
const Logger = getLogger()
@@ -40,7 +41,7 @@ export class FilamentView extends React.PureComponent {
private view: RNFFilamentView | undefined
// There is a race condition where the surface might be destroyed before the swapchain is created.
// For this we keep track of the surface state:
- private isSurfaceAlive = Worklets.createSharedValue(true)
+ private isSurfaceAlive = makeMutable(true)
private isComponentMounted = false
private viewId: number
@@ -75,7 +76,7 @@ export class FilamentView extends React.PureComponent {
private latestToken = 0
private updateRenderCallback = async (callback: RenderCallback, swapChain: SwapChain) => {
const currentToken = ++this.latestToken
- const { renderer, view, workletContext, choreographer } = this.getContext()
+ const { renderer, view, workletRuntime, choreographer } = this.getContext()
// When requesting to update the render callback we have to assume that the previous one is not valid anymore
// ie. its pointing to already released resources from useDisposableResource:
@@ -83,39 +84,30 @@ export class FilamentView extends React.PureComponent {
// Adding a new render callback listener is an async operation
Logger.debug('Setting render callback')
- const listener = await workletContext.runAsync(
- wrapWithErrorHandler(() => {
+ const listener = await scheduleOnRuntimeAsync(workletRuntime, () => {
+ 'worklet'
+
+ // We need to create the function we pass to addFrameCallbackListener on the worklet thread, so that the
+ // underlying JSI function is owned by that thread. Only then can we call it on the worklet thread when
+ // the choreographer is calling its listeners.
+ return choreographer.addFrameCallbackListener((frameInfo) => {
'worklet'
- // We need to create the function we pass to addFrameCallbackListener on the worklet thread, so that the
- // underlying JSI function is owned by that thread. Only then can we call it on the worklet thread when
- // the choreographer is calling its listeners.
- return choreographer.addFrameCallbackListener((frameInfo) => {
- 'worklet'
-
- if (!swapChain.isValid) {
- // TODO: Supposedly fixed in https://github.com/margelo/react-native-filament/pull/210, remove this once proven
- reportWorkletError(
- new Error(
- '[react-native-filament] SwapChain is invalid, cannot render frame.\nThis should never happen, please report an issue with reproduction steps.'
- )
- )
- return
- }
-
- try {
- callback(frameInfo)
-
- if (renderer.beginFrame(swapChain, frameInfo.timestamp)) {
- renderer.render(view)
- renderer.endFrame()
- }
- } catch (error) {
- reportWorkletError(error)
- }
- })
+ if (!swapChain.isValid) {
+ // TODO: Supposedly fixed in https://github.com/margelo/react-native-filament/pull/210, remove this once proven
+ throw new Error(
+ '[react-native-filament] SwapChain is invalid, cannot render frame.\nThis should never happen, please report an issue with reproduction steps.'
+ )
+ }
+
+ callback(frameInfo)
+
+ if (renderer.beginFrame(swapChain, frameInfo.timestamp)) {
+ renderer.render(view)
+ renderer.endFrame()
+ }
})
- )
+ })
// It can happen that after the listener was set the surface got destroyed already:
if (!this.isComponentMounted || !this.isSurfaceAlive.value) {
@@ -137,6 +129,7 @@ export class FilamentView extends React.PureComponent {
// Calling this here ensures that only after the latest successful call for attaching a listener, the choreographer is started.
Logger.debug('Starting choreographer')
choreographer.start()
+ Logger.debug('Choreographer started!')
}
private getContext = () => {
@@ -238,11 +231,11 @@ export class FilamentView extends React.PureComponent {
Logger.debug('Surface created!')
const isSurfaceAlive = this.isSurfaceAlive
isSurfaceAlive.value = true
- const { engine, workletContext } = this.getContext()
+ const { engine, workletRuntime } = this.getContext()
// Create a swap chain …
const enableTransparentRendering = this.props.enableTransparentRendering ?? true
Logger.debug('Creating swap chain')
- const swapChain = await workletContext.runAsync(() => {
+ const swapChain = await scheduleOnRuntimeAsync(workletRuntime, () => {
'worklet'
if (!isSurfaceAlive.value) {
diff --git a/package/src/react/RenderCallbackContext.tsx b/package/src/react/RenderCallbackContext.tsx
index df5a4a3c..9fbf0aa6 100644
--- a/package/src/react/RenderCallbackContext.tsx
+++ b/package/src/react/RenderCallbackContext.tsx
@@ -1,6 +1,6 @@
import React, { createContext, DependencyList, PropsWithChildren, useCallback, useContext, useEffect, useMemo } from 'react'
import { RenderCallback } from 'react-native-filament'
-import { ISharedValue, useSharedValue } from 'react-native-worklets-core'
+import { SharedValue, useSharedValue } from 'react-native-reanimated'
type RenderCallbackList = {
callback: RenderCallback
@@ -12,22 +12,12 @@ type RenderCallbackList = {
* This context allows us to have multiple render callbacks, as we call them in the render callback.
*/
export type RenderContextType = {
- renderCallbacks: ISharedValue
+ renderCallbacks: SharedValue
addRenderCallback: (callback: RenderCallback) => () => void
}
export const makeRenderContext = () => {
- const RenderContext = createContext({
- renderCallbacks: {
- value: [],
- addListener: () => {
- throw new Error('RenderContextProvider not found')
- },
- },
- addRenderCallback: () => {
- throw new Error('RenderContextProvider not found')
- },
- })
+ const RenderContext = createContext(null!)
const RenderContextProvider = ({ children }: PropsWithChildren) => {
const renderCallbacks = useSharedValue([])
@@ -35,9 +25,9 @@ export const makeRenderContext = () => {
(callback: RenderCallback) => {
const id = Math.random().toString(36).substring(7)
const entry = { callback, id }
- renderCallbacks.value.push(entry)
+ renderCallbacks.set((prev) => [...prev, entry])
return () => {
- renderCallbacks.value = renderCallbacks.value.filter((e) => e.id !== id)
+ renderCallbacks.set((prev) => prev.filter((e) => e.id !== id))
}
},
[renderCallbacks]
diff --git a/package/src/types/TransformProps.ts b/package/src/types/TransformProps.ts
index 8238dedd..bec8f2ab 100644
--- a/package/src/types/TransformProps.ts
+++ b/package/src/types/TransformProps.ts
@@ -1,5 +1,5 @@
import { Float3 } from '.'
-import { ISharedValue } from 'react-native-worklets-core'
+import { type SharedValue } from 'react-native-reanimated'
// TODO: WithAnimatedProps ?
@@ -11,17 +11,17 @@ export type TransformationProps = {
* Position in meters. Unit is in meters.
* @default [0, 0, 0]
*/
- translate?: Float3 | ISharedValue
+ translate?: Float3 | SharedValue
/**
* Scale for each axis. Unit is in meters.
*/
- scale?: Float3 | ISharedValue
+ scale?: Float3 | SharedValue
/**
* Rotation for each axis in radians.
*/
- rotate?: Float3 | ISharedValue
+ rotate?: Float3 | SharedValue
/**
* If true, the current transformation of the entity will be multiplied with the new transformation.
diff --git a/package/src/utilities/helper.ts b/package/src/utilities/helper.ts
index dfefe589..b6088ca0 100644
--- a/package/src/utilities/helper.ts
+++ b/package/src/utilities/helper.ts
@@ -1,4 +1,4 @@
-import { ISharedValue } from 'react-native-worklets-core'
+import { type SharedValue } from 'react-native-reanimated'
import { Float3 } from '../types'
export const areFloat3Equal = (a: Float3, b?: Float3): boolean => {
@@ -6,7 +6,7 @@ export const areFloat3Equal = (a: Float3, b?: Float3): boolean => {
return a[0] === b?.[0] && a[1] === b?.[1] && a[2] === b?.[2]
}
-export const isWorkletSharedValue = (value: any): value is ISharedValue => {
+export const isWorkletSharedValue = (value: any): value is SharedValue => {
'worklet'
return typeof value === 'object' && value != null && 'addListener' in value && typeof value.addListener === 'function'
}
diff --git a/package/src/utilities/scheduleOnRuntimeAsync.ts b/package/src/utilities/scheduleOnRuntimeAsync.ts
new file mode 100644
index 00000000..f2d5494f
--- /dev/null
+++ b/package/src/utilities/scheduleOnRuntimeAsync.ts
@@ -0,0 +1,14 @@
+import { runOnJS, scheduleOnRuntime, WorkletRuntime } from 'react-native-worklets'
+
+export function scheduleOnRuntimeAsync(runtime: WorkletRuntime, worklet: () => T): Promise {
+ let resolve: (result: T) => void
+ const promise = new Promise((res) => {
+ resolve = res
+ })
+ scheduleOnRuntime(runtime, () => {
+ 'worklet'
+ const result = worklet()
+ runOnJS(resolve)(result)
+ })
+ return promise
+}
diff --git a/patches/react-native-worklets-core+1.6.2.patch b/patches/react-native-worklets-core+1.6.2.patch
deleted file mode 100644
index 54612060..00000000
--- a/patches/react-native-worklets-core+1.6.2.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-diff --git a/node_modules/react-native-worklets-core/android/CMakeLists.txt b/node_modules/react-native-worklets-core/android/CMakeLists.txt
-index cc4cbfe..66f81c1 100644
---- a/node_modules/react-native-worklets-core/android/CMakeLists.txt
-+++ b/node_modules/react-native-worklets-core/android/CMakeLists.txt
-@@ -79,10 +79,17 @@ if(${JS_RUNTIME} STREQUAL "hermes")
-
- string(APPEND CMAKE_CXX_FLAGS " -DJS_RUNTIME_HERMES=1")
-
-- target_link_libraries(
-- ${PACKAGE_NAME}
-- hermes-engine::libhermes
-+ if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 82)
-+ target_link_libraries(
-+ ${PACKAGE_NAME}
-+ hermes-engine::hermesvm
-+ )
-+ else()
-+ target_link_libraries(
-+ ${PACKAGE_NAME}
-+ hermes-engine::libhermes
- )
-+ endif()
-
- if(${HERMES_ENABLE_DEBUGGER})
- if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 76)