diff --git a/src/components/animation/AnimationCanvas.tsx b/src/components/animation/AnimationCanvas.tsx new file mode 100644 index 0000000..e30611f --- /dev/null +++ b/src/components/animation/AnimationCanvas.tsx @@ -0,0 +1,82 @@ +import React, { useMemo } from "react"; +import { StyleSheet, ViewStyle } from "react-native"; +import { + Canvas, + Image as SkImage, + Shader, + Fill, + useImage, +} from "@shopify/react-native-skia"; +import { useSharedValue, useFrameCallback } from "react-native-reanimated"; +import { shaders } from "@/shaders"; +import type { AnimationType, AnimationUniforms } from "@/types/wallpaper"; + +interface AnimationCanvasProps { + sourceUri: string; + animation: AnimationType; + uniforms: AnimationUniforms; + width: number; + height: number; + fps?: number; + style?: ViewStyle; +} + +/** + * Standalone animated preview canvas. + * Used in wallpaper cards on the home screen (mini previews at reduced FPS). + */ +export function AnimationCanvas({ + sourceUri, + animation, + uniforms, + width, + height, + fps = 15, + style, +}: AnimationCanvasProps) { + const image = useImage(sourceUri); + const shader = useMemo(() => shaders[animation], [animation]); + const time = useSharedValue(0); + + const frameInterval = 1000 / fps; + let lastFrame = 0; + + useFrameCallback((info) => { + const now = info.timeSinceFirstFrame ?? 0; + if (now - lastFrame >= frameInterval) { + time.value = now / 1000; + lastFrame = now; + } + }); + + if (!image || !shader) return null; + + return ( + + + + + + + + ); +} diff --git a/src/components/animation/index.ts b/src/components/animation/index.ts new file mode 100644 index 0000000..c23668e --- /dev/null +++ b/src/components/animation/index.ts @@ -0,0 +1 @@ +export { AnimationCanvas } from "./AnimationCanvas";