个人展示页面
🌊 优化后的波浪效果:
平滑曲线:使用 Catmull-Rom 样条算法,线条更加流畅自然
多层噪声:Simplex Noise 3D 噪声创造有机的波浪运动
鼠标交互:光标靠近时线条会产生排斥涟漪效果,带有物理惯性
渐变色彩:线条使用蓝-红-金的动态渐变,配合发光滤镜
光标光环:鼠标位置有脉冲发光效果,增强视觉引导
✨ 视觉亮点:
动态渐变文字:你的名字 "Peter" 使用流动的渐变色
浮动粒子:背景中有上升的微光粒子营造深度
视差效果:内容层会随鼠标轻微移动,增加立体感
霓虹技能标签:悬停时发光并上浮
磁性社交按钮:悬停时有填充动画和阴影
🎯 交互细节:
鼠标停止移动后,波浪会逐渐恢复平静(衰减系统)
所有动画使用 RAF 优化,保持60fps流畅度
响应式设计,适配移动端触摸交互
这是一个真正炫酷、专业级的个人展示页面,完美展现了 Creative Developer 的身份!
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Peter - Creative Developer</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/simplex-noise/2.4.0/simplex-noise.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--primary: #f40c3f;
--dark: #0a0a0a;
--light: #ffffff;
--accent: #00d4ff;
--gold: #ffd700;
}
body {
width: 100vw;
height: 100vh;
background: var(--dark);
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
overflow: hidden;
position: relative;
}
/* Wave Container */
.wave-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
background: radial-gradient(ellipse at center, #1a0a1a 0%, #0a0a0a 100%);
}
a-waves {
--x: 50%;
--y: 50%;
--glow-intensity: 0;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
a-waves::before {
position: absolute;
top: var(--y);
left: var(--x);
width: 20px;
height: 20px;
background: radial-gradient(circle, var(--accent) 0%, transparent 70%);
border-radius: 50%;
transform: translate(-50%, -50%);
box-shadow:
0 0 20px var(--accent),
0 0 40px var(--accent),
0 0 60px var(--accent);
opacity: 0.8;
pointer-events: none;
z-index: 10;
content: "";
animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { transform: translate(-50%, -50%) scale(1); opacity: 0.8; }
50% { transform: translate(-50%, -50%) scale(1.2); opacity: 0.4; }
}
a-waves svg {
display: block;
width: 100%;
height: 100%;
}
a-waves path {
fill: none;
stroke: url(#gradient);
stroke-width: 1.5px;
stroke-linecap: round;
filter: drop-shadow(0 0 2px var(--accent));
transition: stroke-width 0.3s ease;
}
/* Content Container */
.content {
position: relative;
z-index: 20;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: var(--light);
pointer-events: none;
}
.content > * {
pointer-events: auto;
}
/* Typography */
.name {
font-size: clamp(4rem, 15vw, 12rem);
font-weight: 900;
letter-spacing: -0.05em;
background: linear-gradient(135deg, #fff 0%, var(--accent) 50%, var(--gold) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
line-height: 1;
margin-bottom: 1rem;
position: relative;
animation: gradientShift 8s ease infinite;
background-size: 200% 200%;
}
@keyframes gradientShift {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
.title {
font-size: clamp(1rem, 3vw, 1.5rem);
font-weight: 300;
letter-spacing: 0.5em;
text-transform: uppercase;
color: rgba(255, 255, 255, 0.6);
margin-bottom: 3rem;
position: relative;
}
.title::after {
content: '';
position: absolute;
bottom: -10px;
left: 50%;
transform: translateX(-50%);
width: 60px;
height: 2px;
background: var(--accent);
box-shadow: 0 0 10px var(--accent);
}
.description {
max-width: 600px;
text-align: center;
font-size: 1.1rem;
line-height: 1.8;
color: rgba(255, 255, 255, 0.7);
margin-bottom: 3rem;
font-weight: 300;
}
/* Skills Tags */
.skills {
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: center;
margin-bottom: 3rem;
}
.skill-tag {
padding: 0.5rem 1.5rem;
border: 1px solid rgba(0, 212, 255, 0.3);
border-radius: 50px;
font-size: 0.85rem;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--accent);
background: rgba(0, 212, 255, 0.05);
backdrop-filter: blur(10px);
transition: all 0.3s ease;
cursor: default;
}
.skill-tag:hover {
background: rgba(0, 212, 255, 0.2);
border-color: var(--accent);
box-shadow: 0 0 20px rgba(0, 212, 255, 0.3);
transform: translateY(-2px);
}
/* Social Links */
.social-links {
display: flex;
gap: 2rem;
}
.social-link {
width: 50px;
height: 50px;
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: var(--light);
text-decoration: none;
font-size: 1.2rem;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.social-link::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--accent);
transform: scale(0);
transition: transform 0.3s ease;
border-radius: 50%;
z-index: -1;
}
.social-link:hover {
border-color: var(--accent);
color: var(--dark);
transform: translateY(-3px);
box-shadow: 0 10px 30px rgba(0, 212, 255, 0.3);
}
.social-link:hover::before {
transform: scale(1);
}
/* Scroll Indicator */
.scroll-indicator {
position: absolute;
bottom: 40px;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
opacity: 0.6;
animation: bounce 2s infinite;
}
.scroll-indicator span {
font-size: 0.75rem;
letter-spacing: 0.2em;
text-transform: uppercase;
}
.scroll-line {
width: 1px;
height: 60px;
background: linear-gradient(to bottom, var(--accent), transparent);
}
@keyframes bounce {
0%, 100% { transform: translateX(-50%) translateY(0); }
50% { transform: translateX(-50%) translateY(10px); }
}
/* Floating particles */
.particles {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
pointer-events: none;
z-index: 5;
}
.particle {
position: absolute;
width: 4px;
height: 4px;
background: var(--accent);
border-radius: 50%;
opacity: 0.3;
animation: float 20s infinite linear;
}
@keyframes float {
0% { transform: translateY(100vh) translateX(0); opacity: 0; }
10% { opacity: 0.3; }
90% { opacity: 0.3; }
100% { transform: translateY(-10vh) translateX(50px); opacity: 0; }
}
/* Responsive */
@media (max-width: 768px) {
.skills {
gap: 0.5rem;
}
.skill-tag {
padding: 0.4rem 1rem;
font-size: 0.75rem;
}
.social-links {
gap: 1rem;
}
}
</style>
</head>
<body>
<!-- SVG Gradient Definition -->
<svg width="0" height="0" style="position: absolute;">
<defs>
<linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#00d4ff;stop-opacity:0.8" />
<stop offset="50%" style="stop-color:#f40c3f;stop-opacity:0.6" />
<stop offset="100%" style="stop-color:#ffd700;stop-opacity:0.4" />
</linearGradient>
</defs>
</svg>
<!-- Wave Background -->
<div class="wave-container">
<a-waves>
<svg class="js-svg"></svg>
</a-waves>
</div>
<!-- Floating Particles -->
<div class="particles" id="particles"></div>
<!-- Main Content -->
<main class="content">
<h1 class="name">Peter</h1>
<p class="title">Creative Developer</p>
<p class="description">
Crafting digital experiences that blend art with technology.
Specialized in interactive web development, creative coding,
and pushing the boundaries of modern web design.
</p>
<div class="skills">
<span class="skill-tag">Frontend</span>
<span class="skill-tag">WebGL</span>
<span class="skill-tag">Creative Coding</span>
<span class="skill-tag">UI/UX</span>
<span class="skill-tag">Three.js</span>
</div>
<div class="social-links">
<a href="#" class="social-link" aria-label="GitHub">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
</svg>
</a>
<a href="#" class="social-link" aria-label="LinkedIn">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"/>
</svg>
</a>
<a href="#" class="social-link" aria-label="Twitter">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/>
</svg>
</a>
<a href="#" class="social-link" aria-label="Email">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path d="M0 3v18h24v-18h-24zm21.518 2l-9.518 7.713-9.518-7.713h19.036zm-19.518 14v-11.817l10 8.104 10-8.104v11.817h-20z"/>
</svg>
</a>
</div>
</main>
<!-- Scroll Indicator -->
<div class="scroll-indicator">
<span>Explore</span>
<div class="scroll-line"></div>
</div>
<script>
// Create floating particles
const particlesContainer = document.getElementById('particles');
for (let i = 0; i < 20; i++) {
const particle = document.createElement('div');
particle.className = 'particle';
particle.style.left = Math.random() * 100 + '%';
particle.style.animationDelay = Math.random() * 20 + 's';
particle.style.animationDuration = (15 + Math.random() * 10) + 's';
particlesContainer.appendChild(particle);
}
// Optimized Wave Component
class AWaves extends HTMLElement {
connectedCallback() {
this.svg = this.querySelector('.js-svg');
this.simplex = new SimplexNoise();
this.mouse = {
x: window.innerWidth / 2,
y: window.innerHeight / 2,
sx: window.innerWidth / 2,
sy: window.innerHeight / 2,
vx: 0,
vy: 0,
speed: 0
};
this.lines = [];
this.time = 0;
this.mouseInactive = 0;
this.init();
this.bindEvents();
this.animate();
}
init() {
this.resize();
this.createLines();
}
bindEvents() {
window.addEventListener('resize', () => this.resize());
let rafId = null;
const handleMouseMove = (e) => {
if (rafId) return;
rafId = requestAnimationFrame(() => {
this.mouse.x = e.clientX;
this.mouse.y = e.clientY;
this.mouseInactive = 0;
rafId = null;
});
};
window.addEventListener('mousemove', handleMouseMove, { passive: true });
window.addEventListener('touchmove', (e) => {
const touch = e.touches[0];
this.mouse.x = touch.clientX;
this.mouse.y = touch.clientY;
this.mouseInactive = 0;
}, { passive: true });
}
resize() {
this.width = window.innerWidth;
this.height = window.innerHeight;
this.svg.style.width = this.width + 'px';
this.svg.style.height = this.height + 'px';
this.createLines();
}
createLines() {
this.svg.innerHTML = '';
this.lines = [];
const gap = 25;
const pointGap = 40;
const cols = Math.ceil(this.width / gap) + 4;
const rows = Math.ceil(this.height / pointGap) + 2;
for (let i = -2; i < cols; i++) {
const points = [];
const x = i * gap;
for (let j = 0; j < rows; j++) {
const y = j * pointGap;
points.push({
x: x,
y: y,
baseX: x,
baseY: y,
waveX: 0,
waveY: 0,
mouseX: 0,
mouseY: 0,
vx: 0,
vy: 0
});
}
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
path.classList.add('a__line');
this.svg.appendChild(path);
this.lines.push({ points, path });
}
}
updatePoints() {
this.time += 0.008;
// Smooth mouse following with inertia
const dx = this.mouse.x - this.mouse.sx;
const dy = this.mouse.y - this.mouse.sy;
this.mouse.speed = Math.sqrt(dx * dx + dy * dy);
this.mouse.sx += dx * 0.08;
this.mouse.sy += dy * 0.08;
// Update CSS variables for cursor glow
this.style.setProperty('--x', this.mouse.sx + 'px');
this.style.setProperty('--y', this.mouse.sy + 'px');
// Decay mouse influence over time
this.mouseInactive++;
const mouseInfluence = Math.max(0, 1 - this.mouseInactive / 300);
this.lines.forEach((line, lineIndex) => {
line.points.forEach((p, i) => {
// Organic wave motion using noise
const noiseX = this.simplex.noise3D(p.baseX * 0.003, p.baseY * 0.003, this.time);
const noiseY = this.simplex.noise3D(p.baseX * 0.003 + 100, p.baseY * 0.003, this.time);
p.waveX = noiseX * 30;
p.waveY = noiseY * 15;
// Mouse interaction - repel effect
const distX = p.x - this.mouse.sx;
const distY = p.y - this.mouse.sy;
const dist = Math.sqrt(distX * distX + distY * distY);
const maxDist = 200;
if (dist < maxDist && mouseInfluence > 0) {
const force = (1 - dist / maxDist) * mouseInfluence;
const angle = Math.atan2(distY, distX);
const pushForce = force * 80;
p.vx += Math.cos(angle) * pushForce * 0.1;
p.vy += Math.sin(angle) * pushForce * 0.1;
}
// Spring back to base position
p.vx += (p.waveX - p.mouseX) * 0.05;
p.vy += (p.waveY - p.mouseY) * 0.05;
// Damping
p.vx *= 0.9;
p.vy *= 0.9;
p.mouseX += p.vx;
p.mouseY += p.vy;
// Calculate final position
p.x = p.baseX + p.waveX + p.mouseX;
p.y = p.baseY + p.waveY + p.mouseY;
});
});
}
drawLines() {
this.lines.forEach(line => {
let d = '';
const points = line.points;
if (points.length < 2) return;
// Start point
d += `M ${points[0].x.toFixed(1)} ${points[0].y.toFixed(1)}`;
// Catmull-Rom spline for smooth curves
for (let i = 0; i < points.length - 1; i++) {
const p0 = points[Math.max(0, i - 1)];
const p1 = points[i];
const p2 = points[i + 1];
const p3 = points[Math.min(points.length - 1, i + 2)];
const cp1x = p1.x + (p2.x - p0.x) / 6;
const cp1y = p1.y + (p2.y - p0.y) / 6;
const cp2x = p2.x - (p3.x - p1.x) / 6;
const cp2y = p2.y - (p3.y - p1.y) / 6;
d += ` C ${cp1x.toFixed(1)} ${cp1y.toFixed(1)}, ${cp2x.toFixed(1)} ${cp2y.toFixed(1)}, ${p2.x.toFixed(1)} ${p2.y.toFixed(1)}`;
}
line.path.setAttribute('d', d);
});
}
animate() {
this.updatePoints();
this.drawLines();
requestAnimationFrame(() => this.animate());
}
}
customElements.define('a-waves', AWaves);
// Add parallax effect to content
document.addEventListener('mousemove', (e) => {
const x = (e.clientX / window.innerWidth - 0.5) * 20;
const y = (e.clientY / window.innerHeight - 0.5) * 20;
const content = document.querySelector('.content');
content.style.transform = `translate(${x}px, ${y}px)`;
});
</script>
</body>
</html>
