Skip to content

Instantly share code, notes, and snippets.

@aranda-adapptor
Created February 24, 2021 03:54
Show Gist options
  • Save aranda-adapptor/02eada872338589667d5eb2baff61a13 to your computer and use it in GitHub Desktop.
Save aranda-adapptor/02eada872338589667d5eb2baff61a13 to your computer and use it in GitHub Desktop.
The final App.tsx code
import React, { useEffect } from "react";
import { View, Dimensions } from "react-native";
import Animated, {
useSharedValue,
withRepeat,
withTiming,
useAnimatedStyle,
Easing,
} from "react-native-reanimated";
interface StarData {
id: number;
x: number;
y: number;
}
interface StarProps extends StarData {
time: Animated.SharedValue<number>;
}
const stars: StarData[] = [];
const starCount = 50;
const windowWidth = Dimensions.get("window").width;
const windowHeight = Dimensions.get("window").height;
// Stars should be spread evenly between -0.5 and 0.5.
// We apply the screen width/height adjustment in the animated style function.
for (var i = 0; i < starCount; i++) {
stars.push({
id: i,
x: Math.random() - 0.5,
y: Math.random() - 0.5,
});
}
const Star: React.FC<StarProps> = (props) => {
const animatedStyle = useAnimatedStyle(() => {
const t = props.time.value;
const { x, y } = props;
// For the 3D effect, we can use the star's id as the Z value
const z = props.id / starCount;
// Animate the Z value by adding time
// Modulo 1 resets stars back to the start when they reach 1
const depth = (z + t) % 1;
// Calculate the perspective effect.
// The x and y value are divided by the star's depth
const invZp = 0.4 / (1 - depth);
return {
transform: [
// Apply window size and perspective to x and y
{ translateX: windowWidth * (0.5 + x * invZp) },
{ translateY: windowHeight * (0.5 + y * invZp) },
// Scale the star based on it's depth
{ scaleX: depth },
{ scaleY: depth },
],
};
});
return (
<Animated.View
style={[
{
position: "absolute",
backgroundColor: "white",
width: 10,
height: 10,
},
animatedStyle,
]}
/>
);
};
const Starfield: React.FC<{}> = () => {
const timeVal = useSharedValue(0);
useEffect(() => {
timeVal.value = 0;
timeVal.value = withRepeat(
withTiming(1, { duration: 1000, easing: Easing.linear }),
0,
false
);
}, []);
return (
<View
style={{
flex: 1,
backgroundColor: "black",
}}
>
{stars.map((s) => (
<Star key={s.id} time={timeVal} {...s} />
))}
</View>
);
};
export default Starfield;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment