Skip to content

Instantly share code, notes, and snippets.

@xlab
Last active February 27, 2025 05:33
Show Gist options
  • Save xlab/1ae0d2f6aca1785b3b004ffc55435829 to your computer and use it in GitHub Desktop.
Save xlab/1ae0d2f6aca1785b3b004ffc55435829 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<title>Starship Shards</title>
<!-- Original code https://x.com/XorDev/status/1880344887033569682 -->
<!-- https://x.com/xlab_gg Asked Claude 3.5 to convert it to GLSL ES -->
<!-- Attribute original code to @XorDev if you reuse this code -->
<!-- Jan 17, 2025 -->
<style>
body {
margin: 0;
overflow: hidden;
background: #fff;
transition: background 0.3s;
}
canvas {
width: 100vw;
height: 100vh;
display: block;
}
#themeToggle {
position: fixed;
top: 20px;
right: 20px;
transform: none;
padding: 8px 16px;
border: none;
border-radius: 4px;
background: rgba(0, 0, 0, 0.1);
color: #000;
cursor: pointer;
font-family: system-ui, -apple-system, sans-serif;
backdrop-filter: blur(8px);
transition: all 0.3s;
}
#themeToggle:hover {
background: rgba(0, 0, 0, 0.2);
}
body.dark #themeToggle {
background: rgba(255, 255, 255, 0.1);
color: #fff;
}
body.dark #themeToggle:hover {
background: rgba(255, 255, 255, 0.2);
}
</style>
</head>
<body>
<button id="themeToggle">Switch Theme</button>
<canvas id="glCanvas"></canvas>
<script>
console.log("CREDITS:")
console.log("Original code https://x.com/XorDev/status/1880344887033569682")
console.log("https://x.com/xlab_gg Asked Claude 3.5 to convert it to GLSL ES")
console.log("Attribute original code to @XorDev if you reuse this code")
console.log("- Jan 17, 2025")
</script>
<script id="vertexShader" type="x-shader/x-vertex">
attribute vec4 aVertexPosition;
void main() {
gl_Position = aVertexPosition;
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
precision highp float;
uniform vec2 r;
uniform float t;
uniform float alpha;
vec4 o;
// Simplex 2D noise
vec3 permute(vec3 x) { return mod(((x*34.0)+1.0)*x, 289.0); }
float snoise2D(vec2 v) {
const vec4 C = vec4(0.211324865405187,
0.366025403784439,
-0.577350269189626,
0.024390243902439);
vec2 i = floor(v + dot(v, C.yy));
vec2 x0 = v - i + dot(i, C.xx);
vec2 i1;
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
i = mod(i, 289.0);
vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0))
+ i.x + vec3(0.0, i1.x, 1.0));
vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy),
dot(x12.zw,x12.zw)), 0.0);
m = m*m;
m = m*m;
vec3 x = 2.0 * fract(p * C.www) - 1.0;
vec3 h = abs(x) - 0.5;
vec3 ox = floor(x + 0.5);
vec3 a0 = x - ox;
m *= 1.79284291400159 - 0.85373472095314 * (a0*a0 + h*h);
vec3 g;
g.x = a0.x * x0.x + h.x * x0.y;
g.yz = a0.yz * x12.xz + h.yz * x12.yw;
return 130.0 * dot(m, g);
}
float tanh_float(float x) {
float exp2x = exp(2.0 * x);
return (exp2x - 1.0) / (exp2x + 1.0);
}
vec4 pow_vec4(vec4 v, float p) {
return vec4(
pow(v.x, p),
pow(v.y, p),
pow(v.z, p),
pow(v.w, p)
);
}
void main() {
vec2 FC = gl_FragCoord.xy;
vec2 p = (FC.xy-r*.5)/r.y*mat2(8,-6,6,8);
vec2 v;
o = vec4(0.0,0.0,0.0,alpha);
for(float i = 0.0; i < 50.0; i++) {
float f = 3.0 + snoise2D(p + vec2(t*7.0, 0.0));
v = p + cos(i*i+(t+p.x*0.1)*0.03+i*vec2(11,9))*5.0;
o += (cos(sin(i)*vec4(1,2,3,1))+1.0)*exp(sin(i*i+t))/length(max(v,vec2(v.x*f*0.02,v.y)));
}
vec4 temp = pow_vec4(o/100.0, 1.5);
gl_FragColor = vec4(
tanh_float(temp.x),
tanh_float(temp.y),
tanh_float(temp.z),
tanh_float(temp.w)
);
}
</script>
<script>
let gl;
let program;
let canvas;
let rLocation;
let tLocation;
let alphaLocation;
let startTime;
let isDark = true;
document.body.classList.toggle('dark');
function toggleTheme() {
isDark = !isDark;
document.body.classList.toggle('dark');
if (gl) {
gl.clearColor(1.0, 1.0, 1.0, isDark ? 255.0 : 0.0);
}
}
function initGL() {
canvas = document.querySelector("#glCanvas");
gl = canvas.getContext("webgl");
gl.clearColor(1.0, 1.0, 1.0, 255.0);
if (!gl) {
alert("Unable to initialize WebGL.");
return;
}
const vsSource = document.querySelector("#vertexShader").text;
const fsSource = document.querySelector("#fragmentShader").text;
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fsSource);
program = createProgram(gl, vertexShader, fragmentShader);
const positions = new Float32Array([
-1.0, -1.0,
1.0, -1.0,
-1.0, 1.0,
1.0, 1.0,
]);
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
const aVertexPosition = gl.getAttribLocation(program, "aVertexPosition");
gl.enableVertexAttribArray(aVertexPosition);
gl.vertexAttribPointer(aVertexPosition, 2, gl.FLOAT, false, 0, 0);
rLocation = gl.getUniformLocation(program, "r");
tLocation = gl.getUniformLocation(program, "t");
alphaLocation = gl.getUniformLocation(program, "alpha");
startTime = Date.now();
resize();
window.addEventListener('resize', resize);
requestAnimationFrame(render);
}
function createShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
function createProgram(gl, vertexShader, fragmentShader) {
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error('Unable to initialize the shader program: ' + gl.getProgramInfoLog(program));
return null;
}
return program;
}
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
gl.viewport(0, 0, canvas.width, canvas.height);
}
function render() {
gl.clear(gl.COLOR_BUFFER_BIT);
gl.useProgram(program);
const time = (Date.now() - startTime) * 0.001;
gl.uniform1f(tLocation, time);
gl.uniform2f(rLocation, canvas.width, canvas.height);
gl.uniform1f(alphaLocation, isDark ? 255.0 : 0.0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
requestAnimationFrame(render);
}
window.onload = function () {
initGL();
document.getElementById('themeToggle').addEventListener('click', toggleTheme);
};
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment