Energy Orb
Energy ORB made using Skia's Shader
Last updated on
Manual
Install the following dependencies:
npm install react-native-reanimated @shopify/react-native-skiaCopy and paste the following code into your project.
component/organisms/energy-orb
// @ts-checkimport React, { useMemo, memo } from "react";import { StyleSheet } from "react-native";import { Canvas, Fill, Skia, Shader, type Uniforms,} from "@shopify/react-native-skia";import { useSharedValue, useFrameCallback, useDerivedValue,} from "react-native-reanimated";import { SHADER_SOURCE, DEFAULT_COLORS, DEFAULT_SPEED, DEFAULT_INTENSITY, DEFAULT_GLOW_RADIUS, DEFAULT_SIZE,} from "./conf";import { parseColor } from "./helper";import type { IEnergyOrb, RGB } from "./types";const source = Skia.RuntimeEffect.Make(SHADER_SOURCE);export const EnergyOrb: React.FC<IEnergyOrb> & React.FunctionComponent<IEnergyOrb> = memo<IEnergyOrb>( ({ width = DEFAULT_SIZE, height = DEFAULT_SIZE, speed = DEFAULT_SPEED, intensity = DEFAULT_INTENSITY, colors = DEFAULT_COLORS, glowRadius = DEFAULT_GLOW_RADIUS, }: IEnergyOrb): | (React.ReactNode & React.ReactElement & React.JSX.Element) | null => { const time = useSharedValue<number>(0); useFrameCallback(() => { time.value += 0.016 * speed; }); const [c0r, c0g, c0b] = useMemo<RGB>( () => parseColor(colors[0] || DEFAULT_COLORS[0]), [colors], ); const [c1r, c1g, c1b] = useMemo<RGB>( () => parseColor(colors[1] || colors[0] || DEFAULT_COLORS[1]), [colors], ); const [c2r, c2g, c2b] = useMemo<RGB>( () => parseColor(colors[2] || colors[0] || DEFAULT_COLORS[2]), [colors], ); const uniforms = useDerivedValue<Uniforms>(() => ({ iTime: time.value, iResolution: [width, height], uSpeed: speed, uIntensity: intensity, uColor0: [c0r, c0g, c0b], uColor1: [c1r, c1g, c1b], uColor2: [c2r, c2g, c2b], uGlowRadius: glowRadius, })); if (!source) return null; return ( <Canvas style={[styles.canvas, { width, height }]}> <Fill> <Shader source={source} uniforms={uniforms} /> </Fill> </Canvas> ); },);const styles = StyleSheet.create({ canvas: { backgroundColor: "transparent", },});export default memo<React.FC<IEnergyOrb> & React.FunctionComponent<IEnergyOrb>>( EnergyOrb,);Usage
import { View, Text, StyleSheet } from "react-native";import { GestureHandlerRootView } from "react-native-gesture-handler";import { StatusBar } from "expo-status-bar";import { Ionicons } from "@expo/vector-icons";import Dropdown from "@/components/organisms/dropdown";import { useFonts } from "expo-font";import EnergyOrb from "@/components/organisms/energy-orb";export default function App(): React.JSX.Element { const [fontLoaded] = useFonts({ SfProRounded: require("@/assets/fonts/sf-pro-rounded.ttf"), HelveticaNowDisplay: require("@/assets/fonts/HelveticaNowDisplayMedium.ttf"), Coolvetica: require("@/assets/fonts/Coolvetica-Rg.otf"), }); return ( <GestureHandlerRootView style={styles.container}> <StatusBar style="light" /> <View style={{ justifyContent: "center", alignItems: "center", marginTop: 100, }} > <EnergyOrb glowRadius={0.5} width={300} height={300} /> </View> </GestureHandlerRootView> );}const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#000", paddingHorizontal: 24, }, card: { backgroundColor: "rgba(255,255,255,0.08)", borderRadius: 20, padding: 20, top: 120, }, header: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", }, title: { color: "#fff", fontSize: 17, fontWeight: "600", }, subtitle: { color: "rgba(255,255,255,0.6)", fontSize: 13, marginTop: 2, }, body: { marginTop: 12, color: "rgba(255,255,255,0.75)", fontSize: 14, lineHeight: 20, }, trigger: { width: 36, height: 36, borderRadius: 10, backgroundColor: "rgba(255,255,255,0.12)", justifyContent: "center", alignItems: "center", }, menu: { backgroundColor: "#fff", }, itemText: { fontSize: 15, color: "#111", }, destructive: { color: "#dc2626", },});Props
React Native Reanimated
React Native Skia
