three+gsap实现webgl波浪涟漪全屏图片幻灯片过渡动画效果代码
代码语言:html
所属分类:幻灯片
代码描述:three+gsap实现webgl波浪涟漪全屏图片幻灯片过渡动画效果代码,可按h键进行更高级的参数设置。
代码标签: three gsap webgl 波浪 涟漪 全屏 图片 幻灯片 过渡 动画
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <style> @import url("https://fonts.cdnfonts.com/css/pp-neue-montreal"); @font-face { font-family: "PPSupplyMono"; src: url("//repo.bfw.wiki/bfwrepo/font/PPSupplyMono-Regular.ttf") format("truetype"); font-weight: normal; font-style: normal; font-display: swap; } :root { --font-mono: "PPSupplyMono", monospace; --font-sans: "PP Neue Montreal", sans-serif; --color-bg: #000; --color-text: #fff; --color-text-muted: rgba(255, 255, 255, 0.8); --color-text-light: rgba(255, 255, 255, 0.6); --color-accent: #fff; --font-size-mono: clamp(10px, 1.2vw, 12px); --spacing-sm: 1rem; --spacing-md: 2rem; } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: var(--font-sans); background: var(--color-bg); overflow: hidden; color: var(--color-text); cursor: pointer; } .slider-wrapper { position: relative; width: 100vw; height: 100vh; overflow: hidden; } .webgl-canvas { display: block; width: 100%; height: 100%; } /* Current slide number at middle left - UPDATED: 12px uppercase */ .slide-number { position: absolute; top: 50%; left: var(--spacing-md); transform: translateY(-50%); font-family: var(--font-mono); font-size: 12px; font-weight: 600; color: var(--color-text); z-index: 3; letter-spacing: 1px; text-transform: uppercase; } /* Total slides at middle right - UPDATED: 12px uppercase */ .slide-total { position: absolute; top: 50%; right: var(--spacing-md); transform: translateY(-50%); font-family: var(--font-mono); font-size: 12px; font-weight: 600; color: var(--color-text); z-index: 3; letter-spacing: 1px; text-transform: uppercase; } .slides-navigation { position: absolute; bottom: var(--spacing-md); left: var(--spacing-md); right: var(--spacing-md); display: flex; gap: 0; z-index: 3; pointer-events: all; } .slide-nav-item { display: flex; flex-direction: column; cursor: pointer; padding: var(--spacing-sm); flex: 1; border: none; background: none; } .slide-progress-line { width: 100%; height: 2px; background: rgba(255, 255, 255, 0.2); margin-bottom: 8px; border-radius: 1px; overflow: hidden; } .slide-progress-fill { height: 100%; width: 0%; background: var(--color-accent); transition: width 0.1s ease, opacity 0.3s ease; border-radius: 1px; } .slide-nav-title { font-family: var(--font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--color-text-muted); font-weight: 600; transition: color 0.3s ease; } .slide-nav-item.active .slide-nav-title { color: var(--color-text); } .help-text { position: absolute; top: var(--spacing-md); left: var(--spacing-md); font-family: var(--font-mono); font-size: 11px; text-transform: uppercase; color: var(--color-text-muted); z-index: 3; } /* Tweakpane Styling */ .tp-dfwv { position: fixed !important; top: 20px !important; right: 20px !important; z-index: 1000 !important; max-width: 320px !important; background: rgba(0, 0, 0, 0.9) !important; -webkit-backdrop-filter: blur(20px) !important; backdrop-filter: blur(20px) !important; border: 1px solid rgba(255, 255, 255, 0.1) !important; border-radius: 8px !important; } .tp-dfwv .tp-btnv_b { background: rgba(255, 255, 255, 0.1) !important; border: 1px solid rgba(255, 255, 255, 0.2) !important; color: #ffffff !important; font-family: var(--font-mono) !important; border-radius: 4px !important; } .tp-dfwv .tp-btnv_b:hover { background: rgba(255, 255, 255, 0.2) !important; } @media (max-width: 600px) { .slides-navigation { bottom: var(--spacing-sm); left: var(--spacing-sm); right: var(--spacing-sm); } .slide-nav-item { padding: 0.75rem; } .help-text { top: var(--spacing-sm); left: var(--spacing-sm); } .slide-number { left: var(--spacing-sm); } .slide-total { right: var(--spacing-sm); } .tp-dfwv { top: 10px !important; right: 10px !important; max-width: 280px !important; } } /* Preloader styles */ .slider-wrapper { opacity: 0; transition: opacity 1.5s ease-in; pointer-events: none; } .slider-wrapper.loaded { opacity: 1; pointer-events: auto; } </style> </head> <body translate="no"> <main class="slider-wrapper"> <canvas class="webgl-canvas"></canvas> <span class="slide-number" id="slideNumber">01</span> <span class="slide-total" id="slideTotal">06</span> <span class="help-text"> H: Toggle Settings • Space/→: Next • ←: Previous • Click to Advance </span> <nav class="slides-navigation" id="slidesNav"> </nav> </main> <script type="importmap"> { "imports":{ "three":"//repo.bfw.wiki/bfwrepo/js/module/three/build/165/three.module.js" } } </script> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/gsap.3.13.0.js"></script> <script type="module"> // ======================================== // PRELOADER // ======================================== class SliderLoadingManager { constructor() { this.overlay = null; this.canvas = null; this.ctx = null; this.animationId = null; this.startTime = null; this.duration = 3000; this.createLoadingScreen(); } createLoadingScreen() { this.overlay = document.createElement("div"); this.overlay.style.cssText = ` position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: #000000; display: flex; justify-content: center; align-items: center; z-index: 10000; `; this.canvas = document.createElement("canvas"); this.canvas.width = 300; this.canvas.height = 300; this.ctx = this.canvas.getContext("2d"); this.overlay.appendChild(this.canvas); document.body.appendChild(this.overlay); this.startAnimation(); } startAnimation() { const centerX = this.canvas.width / 2; const centerY = this.canvas.height / 2; let time = 0; let lastTime = 0; const dotRings = [ { radius: 20, count: 8 }, { radius: 35, count: 12 }, { radius: 50, count: 16 }, { radius: 65, count: 20 }, { radius: 80, count: 24 }]; const colors = { primary: "#ffffff", accent: "#dddddd" }; const easeInOutSine = t => { return -(Math.cos(Math.PI * t) - 1) / 2; }; const easeInOutCubic = t => { return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2; }; const smoothstep = (edge0, edge1, x) => { const t = Math.max(0, Math.min(1, (x - edge0) / (edge1 - edge0))); return t * t * (3 - 2 * t); }; const hexToRgb = hex => { if (hex.startsWith("#")) { return [ parseInt(hex.slice(1, 3), 16), parseInt(hex.slice(3, 5), 16), parseInt(hex.slice(5, 7), 16)]; } const match = hex.match(/\d+/g); return match ? [parseInt(match[0]), parseInt(match[1]), parseInt(match[2])] : [255, 255, 255]; }; const interpolateColor = (color1, color2, t, opacity = 1) => { const rgb1 = hexToRgb(color1); const rgb2 = hexToRgb(color2); const r = Math.round(rgb1[0] + (rgb2[0] - rgb1[0]) * t); const g = Math.round(rgb1[1] + (rgb2[1] - rgb1[1]) * t); const b = Math.round(rgb1[2] + (rgb2[2] - rgb1[2]) * t); return `rgba(${r}, ${g}, ${b}, ${opacity})`; }; const animate = timestamp => { if (!this.startTime) this.startTime = timestamp; if (!lastTime) lastTime = timestamp; const deltaTime = timestamp - lastTime; lastTime = timestamp; time += deltaTime * 0.001; this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); this.ctx.beginPath(); this.ctx.arc(centerX, centerY, 3, 0, Math.PI * 2); const rgb = hexToRgb(colors.primary); this.ctx.fillStyle = `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]}, 0.9)`; this.ctx.fill(); dotRings.forEach((ring, ringIndex) => { for (let i = 0; i < ring.count; i++) { const angle = i / ring.count * Math.PI * 2; const pulseTime = time * 2 - ringIndex * 0.4; const radiusPulse = easeInOutSine((Math.sin(pulseTime) + 1) / 2) * 6 - 3; const x = centerX + Math.cos(angle) * (ring.radius + radiusPulse); const y = centerY + Math.sin(angle) * (ring.radius + radiusPulse); const opacityPhase = (Math.sin(pulseTime + i * 0.2) + 1) / 2; const opacityBase = 0.3 + easeInOutSine(opacityPhase) * 0.7; const highlightPhase = (Math.sin(pulseTime) + 1) / 2; const highlightIntensity = easeInOutCubic(highlightPhase); this.ctx.beginPath(); this.ctx.arc(x, y, 2, 0, Math.PI * 2); const colorBlend = smoothstep(0.2, 0.8, highlightIntensity); this.ctx.fillStyle = interpolateColor( colors.primary, colors.accent, colorBlend, opacityBase); this.ctx.fill(); } }); if (timestamp - this.startTime >= this.duration) { this.complete(); return; } this.animationId = requestAnimationFrame(animate); }; this.animationId = requestAnimationFrame(animate); } complete() { if (this.animationId) { cancelAnimationFrame(this.animationId); } if (this.overlay) { this.overlay.style.opacity = "0"; this.overlay.style.transition = "opacity 0.8s ease"; setTimeout(() => { this.overlay?.remove(); setTimeout(() => { const sliderWrapper = document.querySelector(".slider-wrapper"); if (sliderWrapper) { sliderWrapper.classList.add("loaded"); } }, 500); }, 800); } }} // Initialize preloader document.addEventListener("DOMContentLoaded", function () { const loadingManager = new SliderLoadingManager(); }); // ======================================== // VISUAL EFFECTS SLIDER CONFIGURATION // ======================================== const SLIDER_CONFIG = { // Core settings settings: { // Timing settings transitionDuration: 2.5, autoSlideSpeed: 5000, // Current state currentEffect: "glass", currentEffectPreset: "Default", // Global settings that affect all effects globalIntensity: 1.0, speedMultiplier: 1.0, distortionStrength: 1.0, colorEnhancement: 1.0, // Effect-specific settings (will be overridden by presets) glassRefractionStrength: 1.0, glassChromaticAberration: 1.0, glassBubbleClarity: 1.0, glassEdgeGlow: 1.0, glassLiquidFlow: 1.0, frostIntensity: 1.5, frostCrystalSize: 1.0, frostIceCoverage: 1.0, frostTemperature: 1.0, frostTexture: 1.0, rippleFrequency: 25.0, rippleAmplitude: 0.08, rippleWaveSpeed: 1.0, rippleRippleCount: 1.0, rippleDecay: 1.0, plasmaIntensity: 1.2, plasmaSpeed: 0.8, plasmaEnergyIntensity: 0.4, plasmaContrastBoost: 0.3, plasmaTurbulence: 1.0, timeshiftDistortion: 1.6, timeshiftBlur: 1.5, timeshiftFlow: 1.4, timeshiftChromatic: 1.5, timeshiftTurbulence: 1.4 }, // Effect-specific presets effectPresets: { glass: { Subtle: { glassRefractionStrength: 0.6, glassChromaticAberration: .........完整代码请登录后点击上方下载按钮下载查看
网友评论0