个人展示页面(html 线条交互)

个人展示页面

🌊 优化后的波浪效果:

  • 平滑曲线:使用 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>
相关推荐
笨蛋不要掉眼泪1 小时前
Spring Cloud Gateway 核心实战:断言(Predicate)的长短写法与自定义工厂详解
java·前端·微服务·架构
RichardLau_Cx1 小时前
零依赖!纯前端 AI 辅助病例管理系统 aiCaseManage:无后端也能实现诊疗行为核验
前端·人工智能·前端开发·localstorage·医疗科技·ai辅助开发·零依赖项目
Never_Satisfied2 小时前
在HTML & CSS中,CSS选中第二个指定类型的子元素的方法
前端·css·html
木斯佳2 小时前
前端八股文面经大全:字节跳动前端一面(2025-10-09)·面经深度解析
前端·状态模式
Never_Satisfied2 小时前
在HTML & CSS中,图片嵌入文字方法
前端·css·html
huohaiyu8 小时前
从URL到页面的完整解析流程
前端·网络·chrome·url
Lethehong8 小时前
国产GLM-5开源模型炸裂发布!编程能力超越Gemini逼近Claude!
开源·蓝耘元生代·蓝耘maas·glm-5
阿星AI工作室10 小时前
一个简单Demo彻底理解前后端怎么连的丨Figma + Supabase + Vercel
前端·人工智能
aircrushin10 小时前
一拍即传的平替,完全免费的实时照片墙!
前端