Skip to content

Instantly share code, notes, and snippets.

@oivoodoo
Created February 3, 2025 09:17
Show Gist options
  • Save oivoodoo/8479c562af435eeeed008c4a42c483f7 to your computer and use it in GitHub Desktop.
Save oivoodoo/8479c562af435eeeed008c4a42c483f7 to your computer and use it in GitHub Desktop.
import React from "react";
import { Dimensions } from "react-native";
import { GLView } from "expo-gl";
const ANIMATION_SPEED = 0.08;
const vertexShaderSource = `
attribute vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0, 1);
}
`;
const fragmentShaderSource = `
precision highp float;
uniform float u_time;
uniform vec2 u_resolution;
float random(vec2 st) {
return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453);
}
void main() {
vec2 uv = gl_FragCoord.xy / u_resolution.xy;
uv.x *= u_resolution.x / u_resolution.y;
float starValue = 0.0;
for (int i = 0; i < 100; i++) {
vec2 starPos = vec2(random(vec2(float(i), 0.0)), random(vec2(0.0, float(i))));
float starSize = random(vec2(float(i), 1.0)) * 0.025;
float starBrightness = random(vec2(float(i), 2.0));
float dist = distance(uv, starPos);
starValue += smoothstep(starSize, 0.0, dist) * starBrightness;
}
float twinkle = sin(u_time * 5.0 + uv.x * 10.0) * 0.5 + 0.5;
starValue *= twinkle;
gl_FragColor = vec4(vec3(starValue), 1.0);
}
`;
const StarryBackground = () => {
const onContextCreate = (gl: WebGLRenderingContext) => {
// Compile vertex shader
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
if (!vertexShader) {
throw new Error("Failed to create vertex shader");
}
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);
// Compile fragment shader
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
if (!fragmentShader) {
throw new Error("Failed to create fragment shader");
}
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);
// Create and link program
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
// Set up geometry
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
const positions = [-1, -1, 1, -1, -1, 1, 1, 1]; // Full-screen quad
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
// Set up attributes
const positionLocation = gl.getAttribLocation(program, "a_position");
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
// Set up uniforms
const resolutionLocation = gl.getUniformLocation(program, "u_resolution");
const timeLocation = gl.getUniformLocation(program, "u_time");
const render = (time: number) => {
gl.uniform2f(resolutionLocation, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.uniform1f(timeLocation, (time * ANIMATION_SPEED) / 1000);
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.flush();
gl.endFrameEXP();
requestAnimationFrame(render);
};
requestAnimationFrame(render);
};
return (
<GLView
style={{
zIndex: -1,
position: "absolute",
width: Dimensions.get("window").width,
height: Dimensions.get("window").height,
top: 0,
left: 0,
backgroundColor: "white",
}}
onContextCreate={onContextCreate}
/>
);
};
export default StarryBackground;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment