VibeCoderzVibeCoderz
Telegram
All Prompts
WebGL Light Rays Animated Background preview
backgroundanimatedwebglcanvasinteractiveresponsivecss

WebGL Light Rays Animated Background

Анимированный фон WebGL с лучами света. Настраиваемый, интерактивный, идеален для динамических заголовков и секций.

by davidhdevLive Preview

Prompt

<div class="light-rays-container" id="lightRaysWrap"></div>

<style>
.light-rays-container {
  position: absolute;
  top: 0; left: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  pointer-events: none; /* så att den inte stör klick */
  z-index: -1; /* bakgrund */
}

canvas#light-rays-canvas {
  width: 100%;
  height: 100%;
  display: block;
}
</style>

<script>
(function(){
  const container = document.getElementById('lightRaysWrap');
  const canvas = document.createElement('canvas');
  canvas.id = 'light-rays-canvas';
  container.appendChild(canvas);

  const gl = canvas.getContext('webgl', { alpha: true, antialias: true });
  if (!gl) { console.error('WebGL not supported'); return; }

  // --- Shader helpers ---
  function compileShader(gl,type,src){const s=gl.createShader(type);gl.shaderSource(s,src);gl.compileShader(s);if(!gl.getShaderParameter(s,gl.COMPILE_STATUS)){console.error(gl.getShaderInfoLog(s));gl.deleteShader(s);return null;}return s;}
  function createProgram(gl,vs,fs){const v=compileShader(gl,gl.VERTEX_SHADER,vs),f=compileShader(gl,gl.FRAGMENT_SHADER,fs);if(!v||!f)return null;const p=gl.createProgram();gl.attachShader(p,v);gl.attachShader(p,f);gl.linkProgram(p);if(!gl.getProgramParameter(p,gl.LINK_STATUS)){console.error(gl.getProgramInfoLog(p));gl.deleteProgram(p);return null;}return p;}

  const vertexSrc = `attribute vec2 a_position; varying vec2 vUv; void main(){vUv=a_position*0.5+0.5; gl_Position=vec4(a_position,0.0,1.0);}`;
  const fragmentSrc = `precision highp float;
uniform float iTime;
uniform vec2 iResolution;
uniform vec2 rayPos;
uniform vec2 rayDir;
uniform vec3 raysColor;
uniform float raysSpeed;
uniform float lightSpread;
uniform float rayLength;
uniform float pulsating;
uniform float fadeDistance;
uniform float saturation;
uniform vec2 mousePos;
uniform float mouseInfluence;
uniform float noiseAmount;
uniform float distortion;
varying vec2 vUv;
float noise(vec2 st){return fract(sin(dot(st.xy,vec2(12.9898,78.233)))*43758.5453123);}
float rayStrength(vec2 raySource,vec2 rayRefDirection,vec2 coord,float seedA,float seedB,float speed){
  vec2 sourceToCoord=coord-raySource;
  vec2 dirNorm=normalize(sourceToCoord);
  float cosAngle=dot(dirNorm,rayRefDirection);
  float distortedAngle=cosAngle+distortion*sin(iTime*2.0+length(sourceToCoord)*0.01)*0.2;
  float spreadFactor=pow(max(distortedAngle,0.0),1.0/max(lightSpread,0.001));
  float distance=length(sourceToCoord);
  float maxDistance=iResolution.x*rayLength;
  float lengthFalloff=clamp((maxDistance-distance)/maxDistance,0.0,1.0);
  float fadeFalloff=clamp((iResolution.x*fadeDistance-distance)/(iResolution.x*fadeDistance),0.5,1.0);
  float pulse=pulsating>0.5?(0.8+0.2*sin(iTime*speed*3.0)):1.0;
  float baseStrength=clamp((0.45+0.15*sin(distortedAngle*seedA+iTime*speed))+(0.3+0.2*cos(-distortedAngle*seedB+iTime*speed)),0.0,1.0);
  return baseStrength*lengthFalloff*fadeFalloff*spreadFactor*pulse;
}
void mainImage(out vec4 fragColor,in vec2 fragCoord){
  vec2 coord=vec2(fragCoord.x,iResolution.y-fragCoord.y);
  vec2 finalRayDir=rayDir;
  if(mouseInfluence>0.0){vec2 mouseScreenPos=mousePos*iResolution.xy;vec2 mouseDirection=normalize(mouseScreenPos-rayPos);finalRayDir=normalize(mix(rayDir,mouseDirection,mouseInfluence));}
  vec4 rays1=vec4(1.0)*rayStrength(rayPos,finalRayDir,coord,36.2214,21.11349,1.5*raysSpeed);
  vec4 rays2=vec4(1.0)*rayStrength(rayPos,finalRayDir,coord,22.3991,18.0234,1.1*raysSpeed);
  fragColor=rays1*0.5+rays2*0.4;
  if(noiseAmount>0.0){float n=noise(coord*0.01+iTime*0.1);fragColor.rgb*=(1.0-noiseAmount+noiseAmount*n);}
  float brightness=1.0-(coord.y/iResolution.y);
  fragColor.x*=(0.1+brightness*0.8);
  fragColor.y*=(0.3+brightness*0.6);
  fragColor.z*=(0.5+brightness*0.5);
  if(saturation!=1.0){float gray=dot(fragColor.rgb,vec3(0.299,0.587,0.114));fragColor.rgb=mix(vec3(gray),fragColor.rgb,saturation);}
  fragColor.rgb*=raysColor;
}
void main(){vec4 color; mainImage(color,gl_FragCoord.xy); gl_FragColor=color;}`;

  const program = createProgram(gl, vertexSrc, fragmentSrc);
  gl.useProgram(program);

  const posLoc = gl.getAttribLocation(program,'a_position');
  const posBuf = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER,posBuf);
  gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]),gl.STATIC_DRAW);
  gl.enableVertexAttribArray(posLoc);
  gl.vertexAttribPointer(posLoc,2,gl.FLOAT,false,0,0);

  const uni = {};
  ['iTime','iResolution','rayPos','rayDir','raysColor','raysSpeed','lightSpread','rayLength','pulsating','fadeDistance','saturation','mousePos','mouseInfluence','noiseAmount','distortion'].forEach(n=>uni[n]=gl.getUniformLocation(program,n));

  // --- Component state (uppdaterade värden) ---
  const state = {
    raysColor:'#dc143c',
    raysOrigin:'top',
    raysSpeed:2.2,
    lightSpread:3.0,
    rayLength:4.9,
    pulsating:false,
    fadeDistance:2.0,
    saturation:0.6,
    mouseInfluence:0.12,
    noiseAmount:0,
    distortion:0
  };

  function hexToRgb(hex){const m=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);return m?[parseInt(m[1],16)/255,parseInt(m[2],16)/255,parseInt(m[3],16)/255]:[1,1,1];}
  function getAnchorAndDir(origin,w,h){const o=0.2;switch(origin){case'top-left':return{anchor:[0,-o*h],dir:[0,1]};case'top-right':return{anchor:[w,-o*h],dir:[0,1]};case'left':return{anchor:[-o*w,0.5*h],dir:[1,0]};case'right':return{anchor:[(1+o)*w,0.5*h],dir:[-1,0]};case'bottom-left':return{anchor:[0,(1+o)*h],dir:[0,-1]};case'bottom-center':return{anchor:[0.5*w,(1+o)*h],dir:[0,-1]};case'bottom-right':return{anchor:[w,(1+o)*h],dir:[0,-1]};default:return{anchor:[0.5*w,-o*h],dir:[0,1]};}}

  const mouse={x:0.5,y:0.5},smoothMouse={x:0.5,y:0.5};
  window.addEventListener('mousemove',e=>{const r=canvas.getBoundingClientRect();mouse.x=(e.clientX-r.left)/r.width;mouse.y=(e.clientY-r.top)/r.height;});

  function resize(){const dpr=Math.min(window.devicePixelRatio||1,2);const w=Math.floor(container.clientWidth*dpr);const h=Math.floor(container.clientHeight*dpr);canvas.width=w;canvas.height=h;gl.viewport(0,0,w,h);}
  window.addEventListener('resize',resize); resize();

  function setUniforms(t){
    gl.uniform1f(uni.iTime,t*0.001);
    gl.uniform2f(uni.iResolution,canvas.width,canvas.height);
    const {anchor,dir} = getAnchorAndDir(state.raysOrigin,canvas.width,canvas.height);
    gl.uniform2f(uni.rayPos,anchor[0],anchor[1]);
    gl.uniform2f(uni.rayDir,dir[0],dir[1]);
    const c = hexToRgb(state.raysColor);
    gl.uniform3f(uni.raysColor,c[0],c[1],c[2]);
    gl.uniform1f(uni.raysSpeed,state.raysSpeed);
    gl.uniform1f(uni.lightSpread,state.lightSpread);
    gl.uniform1f(uni.rayLength,state.rayLength);
    gl.uniform1f(uni.pulsating,state.pulsating?1:0);
    gl.uniform1f(uni.fadeDistance,state.fadeDistance);
    gl.uniform1f(uni.saturation,state.saturation);
    gl.uniform2f(uni.mousePos,smoothMouse.x,smoothMouse.y);
    gl.uniform1f(uni.mouseInfluence,state.mouseInfluence);
    gl.uniform1f(uni.noiseAmount,state.noiseAmount);
    gl.uniform1f(uni.distortion,state.distortion);
  }

  function frame(t){
    const s=0.92;
    smoothMouse.x=smoothMouse.x*s+(1-s)*mouse.x;
    smoothMouse.y=smoothMouse.y*s+(1-s)*mouse.y;
    setUniforms(t);
    gl.clearColor(0,0,0,0); gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(gl.TRIANGLES,0,6);
    requestAnimationFrame(frame);
  }
  requestAnimationFrame(frame);

})();
</script>

All Prompts