Aurora

A Skia-based animated aurora effect that renders flowing light waves over a soft sky gradient

Last updated on

Edit on GitHub

Manual

Install the following dependencies:

npm install react-native-reanimated @shopify/react-native-skia

Copy and paste the following code into your project. component/molecules/aurora.tsx

// @ts-ignoreimport React, { memo, useMemo } from "react";import { Canvas, Shader, Fill, Skia } from "@shopify/react-native-skia";import {  useSharedValue,  useFrameCallback,  useDerivedValue,  type FrameInfo,} from "react-native-reanimated";import { DEFAULT_AURORA_COLORS, DEFAULT_SKY_COLORS } from "./const";import { AURORA_VERTEX_SHADER } from "./conf";import { hexToRgb } from "./helper";import type { IAurora } from "./types";import { useWindowDimensions } from "react-native";const SHADER = Skia.RuntimeEffect.Make(AURORA_VERTEX_SHADER)!;export const Aurora: React.FC<IAurora> & React.FunctionComponent<IAurora> =  memo<IAurora>(    ({      width: paramsWidth,      height: paramsHeight,      auroraColors = DEFAULT_AURORA_COLORS as string[],      skyColors = DEFAULT_SKY_COLORS,      speed = 0.5,      intensity = 1,      waveDirection = [9, -9],    }: React.ComponentProps<typeof Aurora>):      | (React.JSX.Element & React.ReactNode & React.ReactElement)      | null => {      const time = useSharedValue<number>(0);      useFrameCallback((frameInfo: FrameInfo) => {        if (frameInfo.timeSincePreviousFrame != null) {          time.value += frameInfo.timeSincePreviousFrame / 1000;        }      });      const color1 = useMemo(        () => hexToRgb<string>(auroraColors[0] ?? DEFAULT_AURORA_COLORS[0]),        [auroraColors],      );      const color2 = useMemo(        () => hexToRgb<string>(auroraColors[1] ?? DEFAULT_AURORA_COLORS[1]),        [auroraColors],      );      const color3 = useMemo(        () => hexToRgb<string>(auroraColors[2] ?? DEFAULT_AURORA_COLORS[2]),        [auroraColors],      );      const skyTop = useMemo(() => hexToRgb<string>(skyColors[0]), [skyColors]);      const skyBottom = useMemo(        () => hexToRgb<string>(skyColors[1]),        [skyColors],      );      const { width: screenWidth, height: screenHeight } =        useWindowDimensions();      const width = paramsWidth ?? screenWidth;      const height = paramsHeight ?? screenHeight * 0.25;      const uniforms = useDerivedValue(() => {        "worklet";        return {          resolution: [width, height] as [number, number],          time: time.value,          color1: color1 as [number, number, number],          color2: color2 as [number, number, number],          color3: color3 as [number, number, number],          skyTop: skyTop as [number, number, number],          skyBottom: skyBottom as [number, number, number],          speed: speed,          intensity: intensity,          waveDirection: waveDirection as [number, number],        } as const;      }, [        width,        height,        color1,        color2,        color3,        skyTop,        skyBottom,        speed,        intensity,        waveDirection,      ]);      return (        <Canvas style={{ width, height: height + 100 }}>          <Fill>            <Shader source={SHADER} uniforms={uniforms} />          </Fill>        </Canvas>      );    },  );export default memo<React.FC<IAurora> & React.FunctionComponent<IAurora>>(  Aurora,);

Usage

import Aurora from "@/components/molecules/aurora";import React from "react";import { StyleSheet, View } from "react-native";export default function App(): React.ReactNode &  React.JSX.Element &  React.ReactElement {  return (    <View style={stylez.container}>      <Aurora />    </View>  );}const stylez = StyleSheet.create({  container: {    flex: 1,  },  row: {    flexDirection: "row",    alignItems: "center",    justifyContent: "center",    gap: 10,    marginTop: 50,  },  text: {    fontSize: 34,  },});

Props

React Native Reanimated
React Native Skia

On this page