Created
May 16, 2025 15:01
-
-
Save demostanis/10fa408c59e6e9ce7bd5184fb1c22219 to your computer and use it in GitHub Desktop.
fasdfasdff
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!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