From c4ed8d8705583df295ede84c029ea6128f59e839 Mon Sep 17 00:00:00 2001 From: Jason Date: Sun, 1 Mar 2026 16:44:49 +0800 Subject: [PATCH] Initial commit: homepage code --- index.html | 276 +++++++++++++++++++++++++++++++++++++++++++++++++ script.js | 93 +++++++++++++++++ style.css | 295 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 664 insertions(+) create mode 100644 index.html create mode 100644 script.js create mode 100644 style.css diff --git a/index.html b/index.html new file mode 100644 index 0000000..cce8bac --- /dev/null +++ b/index.html @@ -0,0 +1,276 @@ + + + + + + + zzs'homepage + + + + + + +
+
+

zzs'homepage

+
+ + +
+ + + + + \ No newline at end of file diff --git a/script.js b/script.js new file mode 100644 index 0000000..8196ff1 --- /dev/null +++ b/script.js @@ -0,0 +1,93 @@ +// Particle background effect +const canvas = document.createElement('canvas'); +canvas.style.position = 'fixed'; +canvas.style.top = '0'; +canvas.style.left = '0'; +canvas.style.width = '100vw'; +canvas.style.height = '100vh'; +canvas.style.zIndex = '-2'; +canvas.style.pointerEvents = 'none'; +document.body.appendChild(canvas); + +const ctx = canvas.getContext('2d'); +let particles = []; + +function resize() { + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; +} + +window.addEventListener('resize', resize); +resize(); + +class Particle { + constructor() { + this.x = Math.random() * canvas.width; + this.y = Math.random() * canvas.height; + this.size = Math.random() * 2; + this.speedX = Math.random() * 1 - 0.5; + this.speedY = Math.random() * 1 - 0.5; + this.opacity = Math.random() * 0.5 + 0.1; + } + update() { + this.x += this.speedX; + this.y += this.speedY; + if (this.x > canvas.width) this.x = 0; + if (this.x < 0) this.x = canvas.width; + if (this.y > canvas.height) this.y = 0; + if (this.y < 0) this.y = canvas.height; + } + draw() { + ctx.fillStyle = `rgba(255, 255, 255, ${this.opacity})`; + ctx.beginPath(); + ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); + ctx.fill(); + } +} + +function init() { + for (let i = 0; i < 80; i++) { + particles.push(new Particle()); + } +} + +function animate() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + for (let i = 0; i < particles.length; i++) { + particles[i].update(); + particles[i].draw(); + } + requestAnimationFrame(animate); +} + +init(); +animate(); + +// 3D Tilt effect on cards +const cards = document.querySelectorAll('.nav-group'); +cards.forEach(card => { + card.addEventListener('mousemove', e => { + const rect = card.getBoundingClientRect(); + const x = e.clientX - rect.left; + const y = e.clientY - rect.top; + + const centerX = rect.width / 2; + const centerY = rect.height / 2; + + const rotateX = ((y - centerY) / centerY) * -4; + const rotateY = ((x - centerX) / centerX) * 4; + + // Apply inline styles. Combine with CSS transform if needed. + card.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) translateY(-8px)`; + card.style.transition = 'none'; + }); + + card.addEventListener('mouseleave', () => { + card.style.transition = 'all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275)'; + card.style.transform = 'perspective(1000px) rotateX(0) rotateY(0) translateY(0)'; + }); + + card.addEventListener('mouseenter', () => { + card.style.transition = 'all 0.1s ease'; + }); +}); diff --git a/style.css b/style.css new file mode 100644 index 0000000..4da9426 --- /dev/null +++ b/style.css @@ -0,0 +1,295 @@ +:root { + --bg-color: #0b0f19; + --card-bg: rgba(25, 30, 45, 0.4); + --card-border: rgba(255, 255, 255, 0.08); + --text-primary: #f8fafc; + --text-secondary: #94a3b8; + --accent-1: #3b82f6; + --accent-2: #8b5cf6; + --accent-3: #10b981; +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + font-family: 'Outfit', sans-serif; + background-color: var(--bg-color); + color: var(--text-primary); + min-height: 100vh; + display: flex; + justify-content: center; + align-items: center; + overflow-x: hidden; + position: relative; + /* Reduced padding to keep things tighter */ + padding: 2rem 1rem; +} + +/* Background Gradients */ +body::before, +body::after { + content: ''; + position: absolute; + width: 600px; + height: 600px; + border-radius: 50%; + filter: blur(120px); + z-index: -1; + opacity: 0.4; + animation: float 20s infinite ease-in-out alternate; +} + +body::before { + background: radial-gradient(circle, var(--accent-1) 0%, rgba(0, 0, 0, 0) 70%); + top: -100px; + left: -100px; +} + +body::after { + background: radial-gradient(circle, var(--accent-2) 0%, rgba(0, 0, 0, 0) 70%); + bottom: -100px; + right: -100px; + animation-delay: -10s; +} + +@keyframes float { + 0% { + transform: translate(0, 0) scale(1); + } + + 50% { + transform: translate(5%, 5%) scale(1.1); + } + + 100% { + transform: translate(-5%, -5%) scale(1); + } +} + +.container { + /* Scaled down width */ + max-width: 1000px; + width: 100%; +} + +header { + text-align: center; + /* Scaled down margin */ + margin-bottom: 3rem; +} + +h1 { + /* Scaled down font */ + font-size: 2.8rem; + font-weight: 600; + letter-spacing: -1px; + background: linear-gradient(135deg, #ffffff 0%, #cbd5e1 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + margin-bottom: 0; +} + +.nav-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + /* Scaled down gap */ + gap: 1.5rem; +} + +@media (max-width: 1024px) { + .nav-grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 768px) { + h1 { + font-size: 2.2rem; + } + + .nav-grid { + grid-template-columns: 1fr; + } +} + +.nav-group { + background: var(--card-bg); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + border: 1px solid var(--card-border); + /* Scaled down radius and padding */ + border-radius: 20px; + padding: 1.5rem; + transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); + display: flex; + flex-direction: column; +} + +.nav-group:hover { + transform: translateY(-6px); + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3); + background: rgba(30, 36, 54, 0.5); + border-color: rgba(255, 255, 255, 0.15); +} + +.group-title { + /* Scaled down font and margin */ + font-size: 1.25rem; + font-weight: 500; + margin-bottom: 1.2rem; + display: flex; + align-items: center; + gap: 0.75rem; +} + +.group-title::before { + content: ''; + display: inline-block; + width: 12px; + height: 12px; + border-radius: 50%; + box-shadow: 0 0 12px currentColor; +} + +.nav-group:nth-child(1) .group-title { + color: #60a5fa; +} + +.nav-group:nth-child(1) .group-title::before { + background: #60a5fa; +} + +.nav-group:nth-child(2) .group-title { + color: #c084fc; +} + +.nav-group:nth-child(2) .group-title::before { + background: #c084fc; +} + +.nav-group:nth-child(3) .group-title { + color: #34d399; +} + +.nav-group:nth-child(3) .group-title::before { + background: #34d399; +} + +.links { + display: flex; + flex-direction: column; + /* Scaled down gap */ + gap: 0.8rem; +} + +.link-item { + display: flex; + justify-content: space-between; + align-items: center; + /* Scaled down padding */ + padding: 0.8rem 1rem; + background: rgba(255, 255, 255, 0.03); + border-radius: 12px; + text-decoration: none; + color: var(--text-primary); + font-weight: 400; + border: 1px solid rgba(255, 255, 255, 0.02); + transition: all 0.3s ease; + position: relative; + overflow: hidden; +} + +.link-content { + display: flex; + align-items: center; + gap: 0.75rem; + position: relative; + z-index: 1; +} + +.icon-wrapper { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + border-radius: 8px; + background: rgba(255, 255, 255, 0.05); + color: var(--text-secondary); + transition: all 0.3s ease; +} + +.icon-wrapper svg { + width: 16px; + height: 16px; +} + +.link-item::after { + content: '↗'; + font-family: sans-serif; + font-size: 1.1rem; + opacity: 0.4; + transition: opacity 0.3s, transform 0.3s; + z-index: 1; +} + +.link-item::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.06), transparent); + transform: translateX(-100%); + transition: transform 0.6s ease; + z-index: 0; +} + +.link-item:hover { + background: rgba(255, 255, 255, 0.07); + border-color: rgba(255, 255, 255, 0.1); + transform: translateX(4px); + color: #fff; +} + +/* Specific hover colors for icon wrapper and item border */ +.nav-group:nth-child(1) .link-item:hover { + box-shadow: -3px 0 0 #60a5fa; +} + +.nav-group:nth-child(1) .link-item:hover .icon-wrapper { + background: rgba(96, 165, 250, 0.2); + color: #60a5fa; +} + +.nav-group:nth-child(2) .link-item:hover { + box-shadow: -3px 0 0 #c084fc; +} + +.nav-group:nth-child(2) .link-item:hover .icon-wrapper { + background: rgba(192, 132, 252, 0.2); + color: #c084fc; +} + +.nav-group:nth-child(3) .link-item:hover { + box-shadow: -3px 0 0 #34d399; +} + +.nav-group:nth-child(3) .link-item:hover .icon-wrapper { + background: rgba(52, 211, 153, 0.2); + color: #34d399; +} + +.link-item:hover::before { + transform: translateX(100%); +} + +.link-item:hover::after { + opacity: 1; + transform: translateX(2px) translateY(-2px); +} \ No newline at end of file