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