Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save demostanis/10fa408c59e6e9ce7bd5184fb1c22219 to your computer and use it in GitHub Desktop.

Select an option

Save demostanis/10fa408c59e6e9ce7bd5184fb1c22219 to your computer and use it in GitHub Desktop.
fasdfasdff
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>GSAP Pincushion Distortion + Soft Mountain Shadow</title>
<style>
/* Full-page setup allowing scroll */
html, body {
margin: 0;
padding: 0;
width: 100%;
min-height: 100vh;
position: relative;
background: black;
overflow: auto;
font-family: 'Segoe UI', sans-serif;
}
/* Navbar styling */
nav {
position: fixed;
top: 0;
left: 0;
width: 100%;
padding: 1em 2em;
display: flex;
justify-content: space-between; /* Logo left, items right */
align-items: center;
background-color: rgba(0,0,0,0.1); /* Lighter navbar */
backdrop-filter: blur(12px); /* Blur backdrop */
-webkit-backdrop-filter: blur(12px); /* Safari support */
z-index: 10;
}
nav .logo {
color: white;
font-size: 1.2em;
font-weight: 700;
}
nav ul {
list-style: none;
display: flex;
gap: 1.5em;
margin: 0;
padding: 0;
}
nav ul li a {
color: white;
text-decoration: none;
font-weight: 600;
position: relative;
}
nav ul li a::after {
content: '';
position: absolute;
bottom: -4px;
left: 0;
width: 0;
height: 2px;
background: white;
transition: width 0.3s ease;
}
nav ul li a:hover::after {
width: 100%;
}
canvas {
display: block;
}
/* Headline text styling with 3D effect and white shadows */
#headline {
position: absolute;
top: 15%; /* Moved higher */
left: 5%;
font-size: 3em;
font-weight: 900;
z-index: 5;
pointer-events: none;
line-height: 1.2;
background: linear-gradient(45deg, #00e5ff, #ff00d4, #00ff6c);
background-size: 200% 200%;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
animation: gradientShift 5s ease infinite;
text-shadow:
1px 1px 0 rgba(255,255,255,0.6),
2px 2px 0 rgba(255,255,255,0.4),
3px 3px 0 rgba(255,255,255,0.2),
4px 4px 8px rgba(255,255,255,0.8);
transform: translateY(-5%) rotateX(5deg);
transform-origin: left top;
transform-style: preserve-3d;
}
#headline div {
margin-bottom: 0.2em;
}
@keyframes gradientShift {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@studio-freight/lenis@1.0.30/bundled/lenis.min.js"></script>
</head>
<body>
<nav>
<div class="logo">BrandLogo</div>
<ul>
<li><a href="#">Home</a></li>
<li><a href="#features">Features</a></li>
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
<div id="headline">
<div>la technologie</div>
<div>a la hauteur</div>
<div>de vos ambitions</div>
</div>
<canvas id="glCanvas"></canvas>
<script>
const canvas = document.getElementById("glCanvas");
const gl = canvas.getContext("webgl");
if (!gl) console.error("WebGL not supported.");
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
function compileShader(src, type) {
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(vs, fs) {
const vsShader = compileShader(vs, gl.VERTEX_SHADER);
const fsShader = compileShader(fs, gl.FRAGMENT_SHADER);
const p = gl.createProgram();
gl.attachShader(p, vsShader);
gl.attachShader(p, fsShader);
gl.linkProgram(p);
if (!gl.getProgramParameter(p, gl.LINK_STATUS)) {
console.error(gl.getProgramInfoLog(p));
gl.deleteProgram(p);
return null;
}
return p;
}
// Background vertex shader
const bgVS = `attribute vec2 a_position;attribute vec2 a_texCoord;varying vec2 v_texCoord;void main(){gl_Position=vec4(a_position,0,1);v_texCoord=a_texCoord;}`;
// Background fragment shader
const bgFS = `precision mediump float;uniform sampler2D u_image;uniform vec2 u_mouse;uniform float u_strength;varying vec2 v_texCoord;void main(){vec2 uv=v_texCoord;vec2 d=uv-u_mouse;float dist=length(d);uv=u_mouse+d/(1.+u_strength*dist*dist);gl_FragColor=texture2D(u_image,uv);}`;
const bgProg = createProgram(bgVS, bgFS);
const bgPosLoc = gl.getAttribLocation(bgProg, 'a_position');
const bgTexLoc = gl.getAttribLocation(bgProg, 'a_texCoord');
const bgImgLoc = gl.getUniformLocation(bgProg, 'u_image');
const bgMouseLoc = gl.getUniformLocation(bgProg, 'u_mouse');
const bgStrLoc = gl.getUniformLocation(bgProg, 'u_strength');
const quadVerts = new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]);
const quadTCs = new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]);
const quadVBO = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, quadVBO); gl.bufferData(gl.ARRAY_BUFFER, quadVerts, gl.STATIC_DRAW);
const quadTBO = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, quadTBO); gl.bufferData(gl.ARRAY_BUFFER, quadTCs, gl.STATIC_DRAW);
// Load background texture
const bgTex = gl.createTexture();
const bgImg = new Image(); bgImg.crossOrigin = 'anonymous'; bgImg.src = './stars-upscale.png';
let bgLoaded = false;
bgImg.onload = () => {
gl.bindTexture(gl.TEXTURE_2D, bgTex);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, bgImg);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
bgLoaded = true;
resizeCanvas();
};
// Mouse tracking
const uMouse = { x: 0.5, y: 0.5 };
canvas.addEventListener('mousemove', e => {
const mx = e.clientX / canvas.width;
const my = 1 - ((e.clientY + window.pageYOffset) / canvas.height);
gsap.to(uMouse, { duration: 1, x: mx, y: my });
});
// Overlay shaders
const ovVS = `attribute vec2 a_position;attribute vec2 a_texCoord;uniform vec2 u_quadOffset;varying vec2 v_texCoord;void main(){gl_Position=vec4(a_position+u_quadOffset,0,1);v_texCoord=a_texCoord;}`;
const ovFS = `precision mediump float;uniform sampler2D u_image;uniform bool u_isShadow;varying vec2 v_texCoord;void main(){vec4 c=texture2D(u_image,v_texCoord);if(u_isShadow){float s=0.04;float a=0.;for(int x=-2;x<=2;x++)for(int y=-2;y<=2;y++){a+=texture2D(u_image,v_texCoord+vec2(float(x),float(y))*s).a;}a/=25.;gl_FragColor=vec4(0,0,0,a*0.25);}else{gl_FragColor=c;}}`;
const ovProg = createProgram(ovVS, ovFS);
const ovPosLoc = gl.getAttribLocation(ovProg, 'a_position');
const ovTexLoc = gl.getAttribLocation(ovProg, 'a_texCoord');
const ovOffLoc = gl.getUniformLocation(ovProg, 'u_quadOffset');
const ovShLoc = gl.getUniformLocation(ovProg, 'u_isShadow');
const ovImgLoc = gl.getUniformLocation(ovProg, 'u_image');
const ovVBO = gl.createBuffer();
const ovTBO = gl.createBuffer();
const ovTex = gl.createTexture();
const ovImg = new Image(); ovImg.crossOrigin = 'anonymous'; ovImg.src = './mountain.png';
let overlayVerts, ovLoaded = false;
function getVerts(x, y, w, h, cw, ch) {
return new Float32Array([
2 * (x / cw) - 1, 1 - 2 * ((y + h) / ch),
2 * ((x + w) / cw) - 1, 1 - 2 * ((y + h) / ch),
2 * (x / cw) - 1, 1 - 2 * (y / ch),
2 * ((x + w) / cw) - 1, 1 - 2 * (y / ch)
]);
}
ovImg.onload = () => {
gl.bindTexture(gl.TEXTURE_2D, ovTex);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, ovImg);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
ovLoaded = true;
resizeCanvas();
};
function resizeCanvas() {
if (!bgLoaded || !ovLoaded) return;
const scale = window.innerWidth / ovImg.width;
canvas.width = window.innerWidth;
canvas.height = ovImg.height * scale;
gl.viewport(0, 0, canvas.width, canvas.height);
gl.bindBuffer(gl.ARRAY_BUFFER, quadVBO);
gl.bufferData(gl.ARRAY_BUFFER, quadVerts, gl.STATIC_DRAW);
const yOffset = -canvas.height * 0.25;
overlayVerts = getVerts(0, yOffset, canvas.width, canvas.height, canvas.width, canvas.height);
gl.bindBuffer(gl.ARRAY_BUFFER, ovVBO);
gl.bufferData(gl.ARRAY_BUFFER, overlayVerts, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, ovTBO);
gl.bufferData(gl.ARRAY_BUFFER, quadTCs, gl.STATIC_DRAW);
}
function render() {
gl.clear(gl.COLOR_BUFFER_BIT);
if (bgLoaded) {
gl.useProgram(bgProg);
gl.bindBuffer(gl.ARRAY_BUFFER, quadVBO);
gl.enableVertexAttribArray(bgPosLoc);
gl.vertexAttribPointer(bgPosLoc, 2, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, quadTBO);
gl.enableVertexAttribArray(bgTexLoc);
gl.vertexAttribPointer(bgTexLoc, 2, gl.FLOAT, false, 0, 0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, bgTex);
gl.uniform1i(bgImgLoc, 0);
gl.uniform2f(bgMouseLoc, uMouse.x, uMouse.y);
gl.uniform1f(bgStrLoc, 0.05);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}
if (ovLoaded) {
gl.useProgram(ovProg);
gl.bindBuffer(gl.ARRAY_BUFFER, ovVBO);
gl.enableVertexAttribArray(ovPosLoc);
gl.vertexAttribPointer(ovPosLoc, 2, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, ovTBO);
gl.enableVertexAttribArray(ovTexLoc);
gl.vertexAttribPointer(ovTexLoc, 2, gl.FLOAT, false, 0, 0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, ovTex);
gl.uniform1i(ovImgLoc, 0);
const pad = canvas.width * 0.05;
const shVerts = getVerts(-pad, -pad - canvas.height * 0.25, canvas.width + 2 * pad, canvas.height + 2 * pad, canvas.width, canvas.height);
gl.bindBuffer(gl.ARRAY_BUFFER, ovVBO);
gl.bufferData(gl.ARRAY_BUFFER, shVerts, gl.STATIC_DRAW);
gl.uniform1i(ovShLoc, 1);
gl.uniform2f(ovOffLoc, 0, 0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.bindBuffer(gl.ARRAY_BUFFER, ovVBO);
gl.bufferData(gl.ARRAY_BUFFER, overlayVerts, gl.STATIC_DRAW);
gl.uniform1i(ovShLoc, 0);
gl.uniform2f(ovOffLoc, 0, 0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}
requestAnimationFrame(render);
// Lenis smooth scrolling
const lenis = new Lenis({
duration: 1.2,
easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
smooth: true,
});
function rAF(time) {
lenis.raf(time);
requestAnimationFrame(rAF);
}
requestAnimationFrame(rAF);
}
window.addEventListener('resize', resizeCanvas);
requestAnimationFrame(render);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment