Custom Code Experiment •
WebGL2 Hex Tiles 2
Source Code View HTML / CSS / JavaScript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebGL2 Star Warp Tiles</title>
<style>
html { height: 100%; }
body {
background: #000;
overflow: hidden;
padding: 0;
margin: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
}
canvas { height: 100%; width: 100%; }
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script id="vertexShader" type="x-shader/x-vertex">#version 300 es
precision highp float;
in vec4 position;
void main() {
gl_Position = vec4(position);
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">#version 300 es
precision highp float;
out vec4 fragColor;
uniform vec2 u_resolution;
uniform float u_time;
#define R u_resolution
#define T u_time
#define PI 3.141592653
#define PI2 6.283185307
#define N 7.0
mat2 rot(float a) { return mat2(cos(a), sin(a), -sin(a), cos(a)); }
float hash21(vec2 a) {
a.y = mod(a.y, N);
return fract(sin(dot(a, vec2(27.609, 57.583))) * 43758.5453);
}
float hash11(float a) {
return fract(sin(a * 127.1) * 43758.5453);
}
float starSDF(vec2 p, float r, float innerR) {
float an = PI2 / 5.0;
p *= rot(PI * 0.5);
float bn = mod(atan(p.x, p.y), an) - an * 0.5;
p = length(p) * vec2(cos(bn), abs(sin(bn)));
vec2 w = vec2(-innerR * sin(an * 0.5), innerR * cos(an * 0.5));
vec2 q = p - r * vec2(cos(an * 0.5), sin(an * 0.5));
float h = clamp(dot(q, w) / dot(w, w), 0.0, 1.0);
return length(q - w * h) * sign(q.x * w.y - q.y * w.x);
}
vec4 hexGrid(vec2 uv) {
vec2 s = vec2(1.0, sqrt(3.0));
vec2 p = uv / s;
vec2 a = mod(p, 1.0) - 0.5;
vec2 b = mod(p - 0.5, 1.0) - 0.5;
vec2 gv = (dot(a,a) < dot(b,b)) ? a : b;
vec2 id = uv - gv * s;
return vec4(gv * s, id);
}
vec3 primaryCol(float idx) {
int i = int(mod(idx * 6.0, 6.0));
if (i == 0) return vec3(0.85, 0.06, 0.06);
if (i == 1) return vec3(0.95, 0.80, 0.00);
if (i == 2) return vec3(0.00, 0.20, 0.85);
if (i == 3) return vec3(0.90, 0.40, 0.00);
if (i == 4) return vec3(0.00, 0.65, 0.15);
return vec3(0.45, 0.00, 0.80);
}
float edge(float d) {
return smoothstep(fwidth(d), 0.0, d);
}
void main() {
vec2 F = gl_FragCoord.xy;
vec2 uv = (2.0 * F - R) / max(R.x, R.y);
// Clamp radius away from zero before log-polar to kill centre singularity
float minR = 0.01;
float len = max(length(uv), minR);
uv = uv / length(uv) * len;
uv *= rot(-T * 0.07);
// Safe log-polar: clamp length to avoid log(0)
float r = max(length(uv), minR);
uv = -vec2(log(r), atan(uv.y, uv.x));
uv /= PI;
uv *= N;
uv.x += T * 0.35;
// Solid background — pure flat colour, nothing else
vec3 C = vec3(0.05, 0.05, 0.07);
vec4 hx = hexGrid(uv);
vec2 localP = hx.xy;
vec2 cellID = hx.zw;
float h1 = hash21(cellID);
float h2 = hash11(h1 * 3791.0 + floor(T * 0.25));
float h3 = fract(h1 * 4785.312);
int ci1 = int(mod(h1 * 6.0, 6.0));
int ci2 = int(mod(h1 * 6.0 + 2.0 + h3 * 2.0, 6.0));
vec3 col1 = primaryCol(float(ci1) / 6.0);
vec3 col2 = primaryCol(float(ci2) / 6.0);
vec3 col3 = primaryCol(fract(h3 * 0.5 + 0.17));
// Outer star
float outerR = 0.78;
float d = starSDF(localP, outerR, outerR * 0.42);
C = mix(C, col1, edge(d));
// Inner counter-rotating star
float angle2 = T * (0.3 + h2 * 0.4) * (h1 > 0.5 ? 1.0 : -1.0);
float d2 = starSDF(rot(angle2) * localP, outerR * 0.52, outerR * 0.52 * 0.42);
C = mix(C, col2, edge(d2));
// Accent star
float angle3 = T * (0.6 + h3 * 0.5) * (h1 > 0.5 ? -1.0 : 1.0);
float d3 = starSDF(rot(angle3) * localP, outerR * 0.26, outerR * 0.26 * 0.42);
C = mix(C, col3, edge(d3));
// Hard dark border
float borderW = 0.06;
C = mix(C, vec3(0.0), edge(borderW - d));
// Thin border line
C = mix(C, col1 * 1.3, edge(abs(d + borderW * 0.3) - borderW * 0.15));
C = pow(clamp(C, 0.0, 1.0), vec3(0.4545));
fragColor = vec4(C, 1.0);
}
</script>
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<script>
const glcanvas = document.getElementById("canvas");
const gl = glcanvas.getContext("webgl2");
if (!gl) alert("WebGL2 not supported!");
const programInfo = twgl.createProgramInfo(gl, ["vertexShader", "fragmentShader"]);
const arrays = {
position: [-1,-1,0, 1,-1,0, -1,1,0, -1,1,0, 1,-1,0, 1,1,0]
};
const bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
const render = (time) => {
twgl.resizeCanvasToDisplaySize(gl.canvas, 1.0);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
const uniforms = {
u_time: time * 0.001,
u_resolution: [gl.canvas.width, gl.canvas.height]
};
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
twgl.drawBufferInfo(gl, bufferInfo);
requestAnimationFrame(render);
};
window.addEventListener("DOMContentLoaded", () => {
requestAnimationFrame(render);
});
</script>
</body>
</html>