Upload files to "/"
This commit is contained in:
469
background.js
Normal file
469
background.js
Normal file
@@ -0,0 +1,469 @@
|
||||
(() => {
|
||||
const vertexShaderSource = `#version 300 es
|
||||
in vec2 a_position;
|
||||
out vec2 v_position;
|
||||
|
||||
void main() {
|
||||
v_position = a_position;
|
||||
gl_Position = vec4(a_position, 0.0, 1.0);
|
||||
}
|
||||
`;
|
||||
|
||||
const fragmentShaderSource = `#version 300 es
|
||||
precision highp float;
|
||||
|
||||
uniform vec2 u_viewportSize;
|
||||
uniform vec3 u_color1;
|
||||
uniform vec3 u_color2;
|
||||
uniform vec3 u_color3;
|
||||
uniform vec3 u_color4;
|
||||
uniform float u_colorSize;
|
||||
uniform float u_colorSpacing;
|
||||
uniform float u_colorRotation;
|
||||
uniform float u_colorSpread;
|
||||
uniform vec2 u_colorOffset;
|
||||
uniform float u_displacement;
|
||||
uniform float u_zoom;
|
||||
uniform float u_spacing;
|
||||
uniform float u_seed;
|
||||
uniform vec2 u_transformPosition;
|
||||
uniform float u_time;
|
||||
|
||||
in vec2 v_position;
|
||||
out vec4 outColor;
|
||||
|
||||
vec4 permute(vec4 x) {
|
||||
return mod(((x * 34.0) + 1.0) * x, 289.0);
|
||||
}
|
||||
|
||||
vec4 taylorInvSqrt(vec4 r) {
|
||||
return 1.79284291400159 - 0.85373472095314 * r;
|
||||
}
|
||||
|
||||
float snoise(vec3 v) {
|
||||
const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0);
|
||||
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
|
||||
|
||||
vec3 i = floor(v + dot(v, C.yyy));
|
||||
vec3 x0 = v - i + dot(i, C.xxx);
|
||||
|
||||
vec3 g = step(x0.yzx, x0.xyz);
|
||||
vec3 l = 1.0 - g;
|
||||
vec3 i1 = min(g.xyz, l.zxy);
|
||||
vec3 i2 = max(g.xyz, l.zxy);
|
||||
|
||||
vec3 x1 = x0 - i1 + C.xxx;
|
||||
vec3 x2 = x0 - i2 + C.yyy;
|
||||
vec3 x3 = x0 - D.yyy;
|
||||
|
||||
i = mod(i, 289.0);
|
||||
vec4 p = permute(permute(permute(
|
||||
i.z + vec4(0.0, i1.z, i2.z, 1.0))
|
||||
+ i.y + vec4(0.0, i1.y, i2.y, 1.0))
|
||||
+ i.x + vec4(0.0, i1.x, i2.x, 1.0));
|
||||
|
||||
float n_ = 0.142857142857;
|
||||
vec3 ns = n_ * D.wyz - D.xzx;
|
||||
|
||||
vec4 j = p - 49.0 * floor(p * ns.z * ns.z);
|
||||
vec4 x_ = floor(j * ns.z);
|
||||
vec4 y_ = floor(j - 7.0 * x_);
|
||||
|
||||
vec4 x = x_ * ns.x + ns.yyyy;
|
||||
vec4 y = y_ * ns.x + ns.yyyy;
|
||||
vec4 h = 1.0 - abs(x) - abs(y);
|
||||
|
||||
vec4 b0 = vec4(x.xy, y.xy);
|
||||
vec4 b1 = vec4(x.zw, y.zw);
|
||||
|
||||
vec4 s0 = floor(b0) * 2.0 + 1.0;
|
||||
vec4 s1 = floor(b1) * 2.0 + 1.0;
|
||||
vec4 sh = -step(h, vec4(0.0));
|
||||
|
||||
vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;
|
||||
vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;
|
||||
|
||||
vec3 p0 = vec3(a0.xy, h.x);
|
||||
vec3 p1 = vec3(a0.zw, h.y);
|
||||
vec3 p2 = vec3(a1.xy, h.z);
|
||||
vec3 p3 = vec3(a1.zw, h.w);
|
||||
|
||||
vec4 norm = taylorInvSqrt(vec4(
|
||||
dot(p0, p0),
|
||||
dot(p1, p1),
|
||||
dot(p2, p2),
|
||||
dot(p3, p3)
|
||||
));
|
||||
p0 *= norm.x;
|
||||
p1 *= norm.y;
|
||||
p2 *= norm.z;
|
||||
p3 *= norm.w;
|
||||
|
||||
vec4 m = max(0.6 - vec4(
|
||||
dot(x0, x0),
|
||||
dot(x1, x1),
|
||||
dot(x2, x2),
|
||||
dot(x3, x3)
|
||||
), 0.0);
|
||||
m = m * m;
|
||||
return 42.0 * dot(m * m, vec4(
|
||||
dot(p0, x0),
|
||||
dot(p1, x1),
|
||||
dot(p2, x2),
|
||||
dot(p3, x3)
|
||||
));
|
||||
}
|
||||
|
||||
vec3 noiseDerivatives(vec3 p) {
|
||||
float e = 0.035;
|
||||
float n = snoise(p);
|
||||
float dx = snoise(p + vec3(e, 0.0, 0.0)) - n;
|
||||
float dy = snoise(p + vec3(0.0, e, 0.0)) - n;
|
||||
float dz = snoise(p + vec3(0.0, 0.0, e)) - n;
|
||||
return vec3(dx, dy, dz) / e;
|
||||
}
|
||||
|
||||
float grain(vec2 p) {
|
||||
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
|
||||
}
|
||||
|
||||
mat2 rotate2d(float angle) {
|
||||
float s = sin(angle);
|
||||
float c = cos(angle);
|
||||
return mat2(c, -s, s, c);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 position = v_position;
|
||||
position.x *= min(1.0, u_viewportSize.x / u_viewportSize.y);
|
||||
position.y *= min(1.0, u_viewportSize.y / u_viewportSize.x);
|
||||
position /= u_zoom;
|
||||
position += u_transformPosition;
|
||||
|
||||
vec2 noisePosition = position * 0.5 + 0.5;
|
||||
vec3 displacementNoise = noiseDerivatives(vec3(noisePosition, u_seed + u_time * 0.015));
|
||||
position += displacementNoise.xz * u_displacement * 0.12;
|
||||
|
||||
vec2 offsetPosition = position;
|
||||
offsetPosition -= u_colorOffset;
|
||||
offsetPosition = mod(offsetPosition - u_spacing, vec2(u_spacing * 2.0)) - u_spacing;
|
||||
offsetPosition = rotate2d(offsetPosition.x * 0.04 - u_colorRotation) * offsetPosition;
|
||||
offsetPosition /= vec2(max(u_colorSize, 0.001));
|
||||
offsetPosition *= vec2(1.0 / max(u_colorSpread, 0.001), 1.0);
|
||||
|
||||
vec3 color = vec3(0.0);
|
||||
color = mix(u_color1, color, smoothstep(0.0, 1.0, distance(offsetPosition, vec2(0.0, u_colorSpacing * 1.5))));
|
||||
color = mix(u_color2, color, smoothstep(0.0, 1.0, distance(offsetPosition, vec2(0.0, u_colorSpacing * 0.5))));
|
||||
color = mix(u_color3, color, smoothstep(0.0, 1.0, distance(offsetPosition, vec2(0.0, -u_colorSpacing * 0.5))));
|
||||
color = mix(u_color4, color, smoothstep(0.0, 1.0, distance(offsetPosition, vec2(0.0, -u_colorSpacing * 1.5))));
|
||||
|
||||
float textureNoise = grain(v_position * u_viewportSize * 0.5 + u_time * 12.0);
|
||||
float vignette = smoothstep(1.1, 0.16, length(v_position * vec2(0.82, 1.0)));
|
||||
color += (textureNoise - 0.5) * 0.055;
|
||||
color *= 0.74 + vignette * 0.42;
|
||||
color = clamp(color, 0.0, 1.0);
|
||||
|
||||
outColor = vec4(color, 1.0);
|
||||
}
|
||||
`;
|
||||
|
||||
const defaultOptions = {
|
||||
color1: "#16254b",
|
||||
color2: "#23418a",
|
||||
color3: "#aadfd9",
|
||||
color4: "#e64f0f",
|
||||
colorSize: 0.75,
|
||||
colorSpacing: 0.52,
|
||||
colorRotation: -0.381592653589793,
|
||||
colorSpread: 4.52,
|
||||
colorOffset: [-0.7741174697875977, -0.20644775390624992],
|
||||
displacement: 5,
|
||||
seed: 0.18,
|
||||
position: [-0.2816110610961914, -0.43914794921875],
|
||||
zoom: 0.72,
|
||||
spacing: 4.27
|
||||
};
|
||||
|
||||
function compileShader(gl, type, source) {
|
||||
const shader = gl.createShader(type);
|
||||
gl.shaderSource(shader, source);
|
||||
gl.compileShader(shader);
|
||||
|
||||
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
||||
const message = gl.getShaderInfoLog(shader);
|
||||
gl.deleteShader(shader);
|
||||
throw new Error(message || "Shader compile failed");
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
function createProgram(gl) {
|
||||
const vertexShader = compileShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
|
||||
const fragmentShader = compileShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
|
||||
const program = gl.createProgram();
|
||||
|
||||
gl.attachShader(program, vertexShader);
|
||||
gl.attachShader(program, fragmentShader);
|
||||
gl.linkProgram(program);
|
||||
|
||||
gl.deleteShader(vertexShader);
|
||||
gl.deleteShader(fragmentShader);
|
||||
|
||||
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
||||
const message = gl.getProgramInfoLog(program);
|
||||
gl.deleteProgram(program);
|
||||
throw new Error(message || "Program link failed");
|
||||
}
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
function parseHexColor(value) {
|
||||
const hex = String(value || "").trim().replace("#", "");
|
||||
const normalized = hex.length === 3
|
||||
? hex.split("").map((char) => char + char).join("")
|
||||
: hex.padEnd(6, "0").slice(0, 6);
|
||||
const int = Number.parseInt(normalized, 16);
|
||||
|
||||
if (!Number.isFinite(int)) return [0, 0, 0];
|
||||
|
||||
return [
|
||||
((int >> 16) & 255) / 255,
|
||||
((int >> 8) & 255) / 255,
|
||||
(int & 255) / 255
|
||||
];
|
||||
}
|
||||
|
||||
function parseNumber(value, fallback) {
|
||||
const number = Number.parseFloat(value);
|
||||
return Number.isFinite(number) ? number : fallback;
|
||||
}
|
||||
|
||||
function parseVector(value, fallback) {
|
||||
if (!value) return fallback;
|
||||
const parts = String(value).split(",").map((part) => Number.parseFloat(part.trim()));
|
||||
return parts.length >= 2 && parts.every(Number.isFinite) ? [parts[0], parts[1]] : fallback;
|
||||
}
|
||||
|
||||
class FluidGradient extends HTMLElement {
|
||||
static get observedAttributes() {
|
||||
return [
|
||||
"color1",
|
||||
"color2",
|
||||
"color3",
|
||||
"color4",
|
||||
"colorsize",
|
||||
"colorspacing",
|
||||
"colorrotation",
|
||||
"colorspread",
|
||||
"coloroffset",
|
||||
"displacement",
|
||||
"seed",
|
||||
"position",
|
||||
"zoom",
|
||||
"spacing"
|
||||
];
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.canvas = document.createElement("canvas");
|
||||
this.shadow = this.attachShadow({ mode: "open" });
|
||||
this.shadow.innerHTML = `
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
contain: content;
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
canvas {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
this.shadow.append(this.canvas);
|
||||
|
||||
this.options = structuredClone(defaultOptions);
|
||||
this.pointer = {
|
||||
x: 0.5,
|
||||
y: 0.5,
|
||||
targetX: 0.5,
|
||||
targetY: 0.5,
|
||||
displacement: defaultOptions.displacement,
|
||||
seed: defaultOptions.seed
|
||||
};
|
||||
this.bounds = { width: 1, height: 1, dpr: 1 };
|
||||
this.frame = 0;
|
||||
this.start = performance.now();
|
||||
this.resizeObserver = new ResizeObserver(() => this.resize());
|
||||
this.handlePointerMove = this.handlePointerMove.bind(this);
|
||||
this.render = this.render.bind(this);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.gl = this.canvas.getContext("webgl2", {
|
||||
alpha: false,
|
||||
antialias: true,
|
||||
depth: false,
|
||||
preserveDrawingBuffer: false
|
||||
});
|
||||
|
||||
if (!this.gl) {
|
||||
this.style.background = "radial-gradient(circle at 30% 15%, #aadfd9, transparent 28%), radial-gradient(circle at 24% 78%, #e64f0f, transparent 38%), radial-gradient(circle at 70% 60%, #23418a, transparent 42%), #05090a";
|
||||
return;
|
||||
}
|
||||
|
||||
this.program = createProgram(this.gl);
|
||||
this.createGeometry();
|
||||
this.collectUniforms();
|
||||
this.readAttributes();
|
||||
this.resizeObserver.observe(this);
|
||||
this.addEventListener("pointermove", this.handlePointerMove, { passive: true });
|
||||
this.resize();
|
||||
this.play();
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
cancelAnimationFrame(this.frame);
|
||||
this.resizeObserver.disconnect();
|
||||
this.removeEventListener("pointermove", this.handlePointerMove);
|
||||
}
|
||||
|
||||
attributeChangedCallback() {
|
||||
this.readAttributes();
|
||||
}
|
||||
|
||||
createGeometry() {
|
||||
const gl = this.gl;
|
||||
const positions = new Float32Array([
|
||||
-1, -1,
|
||||
1, -1,
|
||||
-1, 1,
|
||||
-1, 1,
|
||||
1, -1,
|
||||
1, 1
|
||||
]);
|
||||
|
||||
this.buffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
|
||||
|
||||
const positionLocation = gl.getAttribLocation(this.program, "a_position");
|
||||
gl.enableVertexAttribArray(positionLocation);
|
||||
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
|
||||
}
|
||||
|
||||
collectUniforms() {
|
||||
const gl = this.gl;
|
||||
this.uniforms = {
|
||||
viewportSize: gl.getUniformLocation(this.program, "u_viewportSize"),
|
||||
color1: gl.getUniformLocation(this.program, "u_color1"),
|
||||
color2: gl.getUniformLocation(this.program, "u_color2"),
|
||||
color3: gl.getUniformLocation(this.program, "u_color3"),
|
||||
color4: gl.getUniformLocation(this.program, "u_color4"),
|
||||
colorSize: gl.getUniformLocation(this.program, "u_colorSize"),
|
||||
colorSpacing: gl.getUniformLocation(this.program, "u_colorSpacing"),
|
||||
colorRotation: gl.getUniformLocation(this.program, "u_colorRotation"),
|
||||
colorSpread: gl.getUniformLocation(this.program, "u_colorSpread"),
|
||||
colorOffset: gl.getUniformLocation(this.program, "u_colorOffset"),
|
||||
displacement: gl.getUniformLocation(this.program, "u_displacement"),
|
||||
seed: gl.getUniformLocation(this.program, "u_seed"),
|
||||
transformPosition: gl.getUniformLocation(this.program, "u_transformPosition"),
|
||||
zoom: gl.getUniformLocation(this.program, "u_zoom"),
|
||||
spacing: gl.getUniformLocation(this.program, "u_spacing"),
|
||||
time: gl.getUniformLocation(this.program, "u_time")
|
||||
};
|
||||
}
|
||||
|
||||
readAttributes() {
|
||||
this.options.color1 = parseHexColor(this.getAttribute("color1") || defaultOptions.color1);
|
||||
this.options.color2 = parseHexColor(this.getAttribute("color2") || defaultOptions.color2);
|
||||
this.options.color3 = parseHexColor(this.getAttribute("color3") || defaultOptions.color3);
|
||||
this.options.color4 = parseHexColor(this.getAttribute("color4") || defaultOptions.color4);
|
||||
this.options.colorSize = parseNumber(this.getAttribute("colorsize"), defaultOptions.colorSize);
|
||||
this.options.colorSpacing = parseNumber(this.getAttribute("colorspacing"), defaultOptions.colorSpacing);
|
||||
this.options.colorRotation = parseNumber(this.getAttribute("colorrotation"), defaultOptions.colorRotation);
|
||||
this.options.colorSpread = parseNumber(this.getAttribute("colorspread"), defaultOptions.colorSpread);
|
||||
this.options.colorOffset = parseVector(this.getAttribute("coloroffset"), defaultOptions.colorOffset);
|
||||
this.options.displacement = parseNumber(this.getAttribute("displacement"), defaultOptions.displacement);
|
||||
this.options.seed = parseNumber(this.getAttribute("seed"), defaultOptions.seed);
|
||||
this.options.position = parseVector(this.getAttribute("position"), defaultOptions.position);
|
||||
this.options.zoom = parseNumber(this.getAttribute("zoom"), defaultOptions.zoom);
|
||||
this.options.spacing = parseNumber(this.getAttribute("spacing"), defaultOptions.spacing);
|
||||
}
|
||||
|
||||
resize() {
|
||||
if (!this.gl) return;
|
||||
const rect = this.getBoundingClientRect();
|
||||
const dpr = Math.min(window.devicePixelRatio || 1, 2);
|
||||
const width = Math.max(1, Math.floor(rect.width * dpr));
|
||||
const height = Math.max(1, Math.floor(rect.height * dpr));
|
||||
|
||||
if (this.canvas.width !== width || this.canvas.height !== height) {
|
||||
this.canvas.width = width;
|
||||
this.canvas.height = height;
|
||||
this.bounds = { width, height, dpr };
|
||||
this.gl.viewport(0, 0, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
handlePointerMove(event) {
|
||||
const rect = this.getBoundingClientRect();
|
||||
const x = rect.width > 0 ? (event.clientX - rect.left) / rect.width : 0.5;
|
||||
const y = rect.height > 0 ? (event.clientY - rect.top) / rect.height : 0.5;
|
||||
|
||||
this.pointer.targetX = Math.min(1, Math.max(0, x));
|
||||
this.pointer.targetY = Math.min(1, Math.max(0, y));
|
||||
}
|
||||
|
||||
play() {
|
||||
if (this.frame) return;
|
||||
this.frame = requestAnimationFrame(this.render);
|
||||
}
|
||||
|
||||
render(now) {
|
||||
const gl = this.gl;
|
||||
const pointer = this.pointer;
|
||||
const options = this.options;
|
||||
|
||||
pointer.x += (pointer.targetX - pointer.x) * 0.1;
|
||||
pointer.y += (pointer.targetY - pointer.y) * 0.1;
|
||||
pointer.displacement += ((pointer.x * 5) - pointer.displacement) * 0.1;
|
||||
pointer.seed += (((pointer.y * 2) - 1) - pointer.seed) * 0.1;
|
||||
|
||||
gl.clearColor(0, 0, 0, 1);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
gl.useProgram(this.program);
|
||||
|
||||
gl.uniform2f(this.uniforms.viewportSize, this.bounds.width, this.bounds.height);
|
||||
gl.uniform3fv(this.uniforms.color1, options.color1);
|
||||
gl.uniform3fv(this.uniforms.color2, options.color2);
|
||||
gl.uniform3fv(this.uniforms.color3, options.color3);
|
||||
gl.uniform3fv(this.uniforms.color4, options.color4);
|
||||
gl.uniform1f(this.uniforms.colorSize, options.colorSize);
|
||||
gl.uniform1f(this.uniforms.colorSpacing, options.colorSpacing);
|
||||
gl.uniform1f(this.uniforms.colorRotation, options.colorRotation);
|
||||
gl.uniform1f(this.uniforms.colorSpread, options.colorSpread);
|
||||
gl.uniform2fv(this.uniforms.colorOffset, options.colorOffset);
|
||||
gl.uniform1f(this.uniforms.displacement, pointer.displacement);
|
||||
gl.uniform1f(this.uniforms.seed, pointer.seed);
|
||||
gl.uniform2fv(this.uniforms.transformPosition, options.position);
|
||||
gl.uniform1f(this.uniforms.zoom, options.zoom);
|
||||
gl.uniform1f(this.uniforms.spacing, options.spacing);
|
||||
gl.uniform1f(this.uniforms.time, (now - this.start) / 1000);
|
||||
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||
|
||||
this.frame = requestAnimationFrame(this.render);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("fluid-gradient", FluidGradient);
|
||||
})();
|
||||
Reference in New Issue
Block a user