<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Holographic Starfield</title>
<style>
body, html { margin: 0; padding: 0; overflow: hidden; }
canvas { display: block; }
</style>
</head>
<body>
<canvas id="shaderCanvas"></canvas>
<script>
const vertexShaderSource = `
attribute vec4 position;
varying vec2 vUv;
void main() {
gl_Position = position;
vUv = position.xy * 0.5 + 0.5;
}
`;
const fragmentShaderSource = `
precision highp float;
uniform float time;
uniform vec2 resolution;
varying vec2 vUv;
#define PI 3.141592653589793
#define TAU (2.0 * PI)
#define STAR_COUNT 100
#define DEPTH_LAYERS 8
// Random function for star positions
float rand(vec2 co) {
return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);
}
// Holographic starfield
vec3 holographicStarfield(vec2 uv, float t) {
vec3 color = vec3(0.0);
// Simulate depth layers
for (int layer = 0; layer < DEPTH_LAYERS; layer++) {
float depth = float(layer + 1) / float(DEPTH_LAYERS);
float scale = 1.0 / depth; // Stars get smaller with depth
// Generate stars
for (int i = 0; i < STAR_COUNT; i++) {
// Random star position
vec2 starPos = vec2(
rand(vec2(float(i), float(layer))),
rand(vec2(float(i) + 1.0, float(layer)))
);
// Star size and brightness
float starSize = 0.005 * scale;
float starBrightness = rand(vec2(float(i), float(layer) + 1.0));
// Distance to star
vec2 delta = uv - starPos;
float dist = length(delta);
// Star glow
float glow = smoothstep(starSize, 0.0, dist);
// Holographic interference
float wave = sin(dist * 100.0 - t * 5.0 * depth);
vec3 starColor = vec3(
0.5 + 0.5 * sin(wave + t * depth), // Red
0.5 + 0.5 * cos(wave + t * 0.7 * depth), // Green
0.5 + 0.5 * sin(wave + t * 1.3 * depth) // Blue
);
// Add star to the color
color += starColor * glow * starBrightness * depth;
}
}
return color;
}
void main() {
vec2 uv = vUv;
uv.x *= resolution.x / resolution.y; // Correct aspect ratio
// Dynamic holographic starfield
float t = time * 0.5;
vec3 holoColor = holographicStarfield(uv, t);
gl_FragColor = vec4(holoColor, 1.0);
}
`;
const canvas = document.getElementById('shaderCanvas');
const gl = canvas.getContext('webgl');
if (!gl) throw new Error('WebGL not supported');
function compileShader(gl, source, type) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error('Shader error:', gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
const vertexShader = compileShader(gl, vertexShaderSource, gl.VERTEX_SHADER);
const fragmentShader = compileShader(gl, fragmentShaderSource, gl.FRAGMENT_SHADER);
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW);
const positionLocation = gl.getAttribLocation(program, 'position');
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
const timeLocation = gl.getUniformLocation(program, 'time');
const resolutionLocation = gl.getUniformLocation(program, 'resolution');
function render(time) {
time *= 0.001;
gl.uniform1f(timeLocation, time);
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
requestAnimationFrame(render);
}
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
gl.viewport(0, 0, canvas.width, canvas.height);
}
window.addEventListener('resize', resize);
resize();
requestAnimationFrame(render);
</script>
</body>
</html>
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.