diff --git a/apps/example/ios/Podfile.lock b/apps/example/ios/Podfile.lock
index 7a048fa41..1931bcb69 100644
--- a/apps/example/ios/Podfile.lock
+++ b/apps/example/ios/Podfile.lock
@@ -1865,7 +1865,7 @@ PODS:
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- - react-native-wgpu (0.5.0):
+ - react-native-wgpu (0.5.2):
- boost
- DoubleConversion
- fast_float
@@ -2903,81 +2903,81 @@ SPEC CHECKSUMS:
fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd
glog: 5683914934d5b6e4240e497e0f4a3b42d1854183
hermes-engine: 35c763d57c9832d0eef764316ca1c4d043581394
- RCT-Folly: 846fda9475e61ec7bcbf8a3fe81edfcaeb090669
+ RCT-Folly: 59ec0ac1f2f39672a0c6e6cecdd39383b764646f
RCTDeprecation: c0ed3249a97243002615517dff789bf4666cf585
RCTRequired: 58719f5124f9267b5f9649c08bf23d9aea845b23
RCTTypeSafety: 4aefa8328ab1f86da273f08517f1f6b343f6c2cc
React: 2073376f47c71b7e9a0af7535986a77522ce1049
React-callinvoker: 751b6f2c83347a0486391c3f266f291f0f53b27e
- React-Core: dff5d29973349b11dd6631c9498456d75f846d5e
- React-CoreModules: c0ae04452e4c5d30e06f8e94692a49107657f537
- React-cxxreact: 376fd672c95dfb64ad5cc246e6a1e9edb78dec4c
+ React-Core: 7195661f0b48e7ea46c3360ccb575288a20c932c
+ React-CoreModules: 14f0054ab46000dd3b816d6528af3bd600d82073
+ React-cxxreact: 7f602425c63096c398dac13cd7a300efd7c281ae
React-debug: 7b56a0a7da432353287d2eedac727903e35278f5
- React-defaultsnativemodule: 393b81aaa6211408f50a6ef00a277847256dd881
- React-domnativemodule: 5fb5829baa7a7a0f217019cbad1eb226d94f7062
- React-Fabric: a17c4ae35503673b57b91c2d1388429e7cbee452
- React-FabricComponents: a76572ddeba78ebe4ec58615291e9db4a55cd46a
- React-FabricImage: d806eb2695d7ef355ec28d1a21f5a14ac26b1cae
- React-featureflags: 1690ec3c453920b6308e23a4e24eb9c3632f9c75
- React-featureflagsnativemodule: 7b7e8483fc671c5a33aefd699b7c7a3c0bdfdfec
- React-graphics: ea146ee799dc816524a3a0922fc7be0b5a52dcc1
- React-hermes: fcbdc45ecf38259fe3b12642bd0757c52270a107
- React-idlecallbacksnativemodule: a353f9162eaa7ad787e68aba9f52a1cfa8154098
- React-ImageManager: ec5cf55ce9cc81719eb5f1f51d23d04db851c86c
- React-jserrorhandler: 594c593f3d60f527be081e2cace7710c2bd9f524
- React-jsi: 59ec3190dd364cca86a58869e7755477d2468948
- React-jsiexecutor: b87d78a2e8dd7a6f56e9cdac038da45de98c944f
- React-jsinspector: b9204adf1af622c98e78af96ec1bca615c2ce2bd
- React-jsinspectorcdp: 4a356fa69e412d35d3a38c44d4a6cc555c5931e8
- React-jsinspectornetwork: 7820056773178f321cbf18689e1ffcd38276a878
- React-jsinspectortracing: b341c5ef6e031a33e0bd462d67fd397e8e9cd612
- React-jsitooling: 401655e05cb966b0081225c5201d90734a567cb9
- React-jsitracing: 67eff6dea0cb58a1e7bd8b49243012d88c0f511e
- React-logger: a3cb5b29c32b8e447b5a96919340e89334062b48
- React-Mapbuffer: 9d2434a42701d6144ca18f0ca1c4507808ca7696
- React-microtasksnativemodule: 75b6604b667d297292345302cc5bfb6b6aeccc1b
- react-native-safe-area-context: c00143b4823773bba23f2f19f85663ae89ceb460
- react-native-skia: 5bf2b2107cd7f2d806fd364f5e16b1c7554ed3cd
- react-native-wgpu: e54fcee5946cc2cee4814f63f425be358f097b14
- React-NativeModulesApple: 879fbdc5dcff7136abceb7880fe8a2022a1bd7c3
+ React-defaultsnativemodule: 695d8a0b40f735edb3c4031e0f049e567fdac47a
+ React-domnativemodule: 6d66c1f61f277d008d98cae650ce2c025b89d3b9
+ React-Fabric: 997d4115d688f483cb409a1290171bff3c93dab4
+ React-FabricComponents: 8167e5e363ca3a3fe394d8afee355e4072bea1db
+ React-FabricImage: f8f9f2c97657116702acc670e3f4357bc842bed3
+ React-featureflags: dfb4d0d527d55dd968231370f6832b9197ee653d
+ React-featureflagsnativemodule: c63cfd8fe95cd98f12ebb37daa919c4544810a45
+ React-graphics: fd795f1c2a1133a08dde31725b20949edd545dca
+ React-hermes: 0a167bbb02c242664745e82154578c64e90a88e5
+ React-idlecallbacksnativemodule: 1798c6aa33ddc7c2e9fa3c3d67729728639889e9
+ React-ImageManager: c498ee6945dffacc82bfa175aa3264212f27c70b
+ React-jserrorhandler: 216951fea62fc26c600f4c96f0dc4fd53d1e7a9b
+ React-jsi: 9c27d27d3007b73c702ad3fd5a6166557c741020
+ React-jsiexecutor: 2b24f4ed4026344a27f717bf947a434cbbeeff7a
+ React-jsinspector: 02394b059c48805780f7d977366317a24168d00e
+ React-jsinspectorcdp: f4b6d5c5c9db05ef44d082716714f90cfeed96bb
+ React-jsinspectornetwork: e7c77d01b5f0664e24c0bec1aea27d5e3d7fb746
+ React-jsinspectortracing: aaa96a4e53abb88dc6d47da3b5744c710652fef9
+ React-jsitooling: 226e5f4147c7b6f1ae1954a8406ffa713f3da828
+ React-jsitracing: 8a2fbeaa9c53c3f0b23904ccffefc890eae48d71
+ React-logger: 1767babce2d28c3251039ce05556714a2c8c6ded
+ React-Mapbuffer: 33f678ee25b6c0ee2b01b1ecec08e3e02424cefe
+ React-microtasksnativemodule: 44b44a4d3cd6ffb85d928abf741acdc26722de2e
+ react-native-safe-area-context: 54d812805f3c4e08a4580ad086cbde1d8780c2e4
+ react-native-skia: 4df548eb44d05ce5e35679b15a9d765e5724126e
+ react-native-wgpu: b4dc1b3af4fb7e6169f504ad28a60508d530d06a
+ React-NativeModulesApple: b5d18bc109c45c9a1c6b71664991b5cc3adc4e48
React-oscompat: 93b5535ea7f7dff46aaee4f78309a70979bdde9d
- React-perflogger: 5536d2df3d18fe0920263466f7b46a56351c0510
- React-performancetimeline: 9041c53efa07f537164dcfe7670a36642352f4c2
+ React-perflogger: a03d913e3205b00aee4128082abe42fd45ce0c98
+ React-performancetimeline: 9b5986cc15afafb9bf246d7dd55bdd138df94451
React-RCTActionSheet: 42195ae666e6d79b4af2346770f765b7c29435b9
- React-RCTAnimation: fa103ccc3503b1ed8dedca7e62e7823937748843
- React-RCTAppDelegate: 665d4baf19424cef08276e9ac0d8771eec4519f9
- React-RCTBlob: 0fa9530c255644db095f2c4fd8d89738d9d9ecc0
- React-RCTFabric: 1fcd8af6e25f92532f56b4ba092e58662c14d156
- React-RCTFBReactNativeSpec: db171247585774f9f0a30f75109cc51568686213
- React-RCTImage: ba824e61ce2e920a239a65d130b83c3a1d426dff
- React-RCTLinking: d2dc199c37e71e6f505d9eca3e5c33be930014d4
- React-RCTNetwork: 87137d4b9bd77e5068f854dd5c1f30d4b072faf6
- React-RCTRuntime: 137fafaa808a8b7e76a510e8be45f9f827899daa
- React-RCTSettings: 71f5c7fd7b5f4e725a4e2114a4b4373d0e46048f
- React-RCTText: b94d4699b49285bee22b8ebf768924d607eccee3
- React-RCTVibration: 6e3993c4f6c36a3899059f9a9ead560ddaf5a7d7
+ React-RCTAnimation: 5c10527683128c56ff2c09297fb080f7c35bd293
+ React-RCTAppDelegate: c616bd5b0d12f0b21dfacee9cd2d512c6df013aa
+ React-RCTBlob: 6e3757bdd7dce6fd9788c0dd675fd6b6c432db9d
+ React-RCTFabric: e8f3b9da97477710bf0904a62eb5b5209c964694
+ React-RCTFBReactNativeSpec: c042f8d60d44ad9e2c722da89323c0bdab7a37af
+ React-RCTImage: a3482fe1ae562d1bab08b42d4670a7c9a21813cd
+ React-RCTLinking: d82b9adb141aef9d2b38d446b837ae7017ab60aa
+ React-RCTNetwork: fa9350dd99354c5695964f589bd4790bdd4f6a85
+ React-RCTRuntime: be99a38cd23388c08921d8969c82a1997a11ec90
+ React-RCTSettings: b7f4a03f44dba1d3a4dc6770843547b203ca9129
+ React-RCTText: 91dc597a5f6b27fd1048bb287c41ea05eeca9333
+ React-RCTVibration: 27b09ddf74bddfa30a58d20e48f885ea6ed6c9d9
React-rendererconsistency: b4785e5ed837dc7c242bbc5fdd464b33ef5bfae7
- React-renderercss: e6fb0ba387b389c595ffa86b8b628716d31f58dc
- React-rendererdebug: 60a03de5c7ea59bf2d39791eb43c4c0f5d8b24e3
- React-RuntimeApple: 3df6788cd9b938bb8cb28298d80b5fbd98a4d852
- React-RuntimeCore: fad8adb4172c414c00ff6980250caf35601a0f5d
- React-runtimeexecutor: d2db7e72d97751855ea0bf5273d2ac84e5ea390c
- React-RuntimeHermes: 04faa4cf9a285136a6d73738787fe36020170613
- React-runtimescheduler: f6a1c9555e7131b4a8b64cce01489ad0405f6e8d
- React-timing: 1e6a8acb66e2b7ac9d418956617fd1fdb19322fd
- React-utils: 52bbb03f130319ef82e4c3bc7a85eaacdb1fec87
- ReactAppDependencyProvider: 433ddfb4536948630aadd5bd925aff8a632d2fe3
- ReactCodegen: 7042ec4a7316b59e8f247b8fa312891179d24f5a
- ReactCommon: 394c6b92765cf6d211c2c3f7f6bc601dffb316a6
- ReactNativeHost: f5e054387e917216a2a021a3f7fdc4f9f158e7e4
- ReactTestApp-DevSupport: 9b7bbba5e8fed998e763809171d9906a1375f9d3
+ React-renderercss: cef3f26df2ddec558ce3c0790fc574b4fb62ce67
+ React-rendererdebug: e68433ae67738caeb672a6c8cc993e9276b298a9
+ React-RuntimeApple: dc1d4709bf847bc695dbe6e8aaf3e22ef25aef02
+ React-RuntimeCore: ca3473c8b6578693fa3bad4d44240098d49d6723
+ React-runtimeexecutor: 0db3ca0b09cd72489cef3a3729349b3c2cf13320
+ React-RuntimeHermes: f92cabaf97ef2546a74360eddfc1c74a34cb9ff8
+ React-runtimescheduler: 06aea75069e0d556a75d258bfc89eb0ebd5d557e
+ React-timing: 1a90df9a04d8e7fd165ff7fa0918b9595c776373
+ React-utils: 92115441fb55ce01ded4abfb5e9336a74cd93e9c
+ ReactAppDependencyProvider: b20fba6c3d091a393925890009999472c8f94d95
+ ReactCodegen: cf03d376a26d393f818d511240b026fc8c95313c
+ ReactCommon: 00df7b9f859c9d02181844255bb89a8bca544374
+ ReactNativeHost: b63ce830e7c5b4e3adcf556b2ef41665da189da0
+ ReactTestApp-DevSupport: c7bff1aee7663f2fb1eefcf60c41573f02916c41
ReactTestApp-Resources: 1bd9ff10e4c24f2ad87101a32023721ae923bccf
- RNGestureHandler: e37bdb684df1ac17c7e1d8f71a3311b2793c186b
- RNReanimated: 464375ff2caa801358547c44eca894ff0bf68e74
- RNWorklets: ee58e869ea579800ec5f2f1cb6ae195fd3537546
+ RNGestureHandler: 92ad734ef0da16d69d0a325b7e1e9ae80bdce1f9
+ RNReanimated: 52dad96755e908e80b403c5ccdd7e24451f0c42a
+ RNWorklets: 95eb4f990dd495be6bf35a2567b0351a6d7f73cf
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
- Yoga: a3ed390a19db0459bd6839823a6ac6d9c6db198d
+ Yoga: 922d794dce2af9c437f864bf4093abfa7a131adb
PODFILE CHECKSUM: b4c1d70c599aba416a49b6bad5eea5084b4e43d0
-COCOAPODS: 1.16.2
+COCOAPODS: 1.15.2
diff --git a/apps/example/src/App.tsx b/apps/example/src/App.tsx
index c1f2037d7..69685abd8 100644
--- a/apps/example/src/App.tsx
+++ b/apps/example/src/App.tsx
@@ -35,6 +35,7 @@ import { ComputeToys } from "./ComputeToys";
import { Reanimated } from "./Reanimated";
import { AsyncStarvation } from "./Diagnostics/AsyncStarvation";
import { DeviceLostHang } from "./Diagnostics/DeviceLostHang";
+import { ViewTransform } from "./ViewTransform";
// The two lines below are needed by three.js
import "fast-text-encoding";
@@ -91,6 +92,7 @@ function App() {
+
diff --git a/apps/example/src/Home.tsx b/apps/example/src/Home.tsx
index 711978821..68e653557 100644
--- a/apps/example/src/Home.tsx
+++ b/apps/example/src/Home.tsx
@@ -123,6 +123,10 @@ export const examples = [
screen: "DeviceLostHang",
title: "⚠️ Device Lost Hang",
},
+ {
+ screen: "ViewTransform",
+ title: "🔄 View Transform",
+ },
];
const styles = StyleSheet.create({
diff --git a/apps/example/src/Route.ts b/apps/example/src/Route.ts
index 67d82ad22..b5298a7b2 100644
--- a/apps/example/src/Route.ts
+++ b/apps/example/src/Route.ts
@@ -28,4 +28,5 @@ export type Routes = {
Reanimated: undefined;
AsyncStarvation: undefined;
DeviceLostHang: undefined;
+ ViewTransform: undefined;
};
diff --git a/apps/example/src/ViewTransform/ViewTransform.tsx b/apps/example/src/ViewTransform/ViewTransform.tsx
new file mode 100644
index 000000000..23c39a8f6
--- /dev/null
+++ b/apps/example/src/ViewTransform/ViewTransform.tsx
@@ -0,0 +1,150 @@
+import React, { useEffect, useRef } from "react";
+import { StyleSheet, View, PixelRatio, Text } from "react-native";
+import Animated, {
+ useAnimatedStyle,
+ useSharedValue,
+} from "react-native-reanimated";
+import type { CanvasRef } from "react-native-wgpu";
+import { Canvas } from "react-native-wgpu";
+
+import { redFragWGSL, triangleVertWGSL } from "../Triangle/triangle";
+
+export function ViewTransform() {
+ const ref = useRef(null);
+
+ const rotation = useSharedValue(0);
+ const id = useRef | null>(null);
+
+ useEffect(() => {
+ const _id = setInterval(() => {
+ rotation.value += 0.05 % (Math.PI * 2);
+ }, 30);
+ id.current = _id;
+
+ return () => {
+ if (id.current) {
+ clearInterval(id.current);
+ }
+ };
+ }, [rotation]);
+
+ const animatedStyle = useAnimatedStyle(() => {
+ const angle = rotation.value * 10;
+ return {
+ transform: [{ perspective: 1000 }, { rotateY: `${angle}deg` }],
+ };
+ });
+
+ useEffect(() => {
+ (async () => {
+ const adapter = await navigator.gpu.requestAdapter();
+ if (!adapter) {
+ throw new Error("No adapter");
+ }
+
+ const device = await adapter.requestDevice();
+ const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
+
+ const context = ref.current!.getContext("webgpu")!;
+ const canvas = context.canvas as HTMLCanvasElement;
+ canvas.width = canvas.clientWidth * PixelRatio.get();
+ canvas.height = canvas.clientHeight * PixelRatio.get();
+
+ if (!context) {
+ throw new Error("No context");
+ }
+
+ context.configure({
+ device,
+ format: presentationFormat,
+ alphaMode: "premultiplied",
+ });
+
+ const pipeline = device.createRenderPipeline({
+ layout: "auto",
+ vertex: {
+ module: device.createShaderModule({
+ code: triangleVertWGSL,
+ }),
+ entryPoint: "main",
+ },
+ fragment: {
+ module: device.createShaderModule({
+ code: redFragWGSL,
+ }),
+ entryPoint: "main",
+ targets: [
+ {
+ format: presentationFormat,
+ },
+ ],
+ },
+ primitive: {
+ topology: "triangle-list",
+ },
+ });
+
+ const commandEncoder = device.createCommandEncoder();
+
+ const textureView = context.getCurrentTexture().createView();
+
+ const renderPassDescriptor: GPURenderPassDescriptor = {
+ colorAttachments: [
+ {
+ view: textureView,
+ clearValue: [0, 0, 0, 0],
+ loadOp: "clear",
+ storeOp: "store",
+ },
+ ],
+ };
+
+ const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
+ passEncoder.setPipeline(pipeline);
+ passEncoder.draw(3);
+ passEncoder.end();
+
+ device.queue.submit([commandEncoder.finish()]);
+
+ context.present();
+ })();
+ }, [ref]);
+
+ return (
+
+ {/* @ts-expect-error React 19 + Reanimated typing issue */}
+
+
+ AAAAAAAAAAAAAAAABBBBBBBBBBBBB
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ alignItems: "center",
+ justifyContent: "center",
+ backgroundColor: "#2c2c2cCC",
+ },
+ canvasContainer: {
+ width: 300,
+ height: 300,
+ },
+ canvas: {
+ width: 300,
+ height: 300,
+ },
+ redBackground: {
+ position: "absolute",
+ width: 300,
+ height: 300,
+ backgroundColor: "#ff0000cc",
+ },
+ text: {
+ color: "#FFFFFF",
+ fontSize: 20,
+ },
+});
diff --git a/apps/example/src/ViewTransform/index.ts b/apps/example/src/ViewTransform/index.ts
new file mode 100644
index 000000000..174d7c82b
--- /dev/null
+++ b/apps/example/src/ViewTransform/index.ts
@@ -0,0 +1 @@
+export * from "./ViewTransform";