Skip to content

Commit e86ec38

Browse files
committed
Fluid bg
1 parent f05ff6a commit e86ec38

3 files changed

Lines changed: 73 additions & 106 deletions

File tree

src/components/InteractiveBackground.tsx

Lines changed: 55 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,6 @@
22

33
import { useEffect, useRef } from 'react'
44

5-
interface Particle {
6-
x: number
7-
y: number
8-
vx: number
9-
vy: number
10-
radius: number
11-
}
12-
135
const InteractiveBackground = () => {
146
const canvasRef = useRef<HTMLCanvasElement>(null)
157

@@ -32,99 +24,69 @@ const InteractiveBackground = () => {
3224
}
3325
window.addEventListener('resize', resize)
3426

35-
// Configuration
36-
const particleCount = Math.floor((width * height) / 15000)
37-
const connectionDistance = 150
38-
const particles: Particle[] = []
27+
// Vibrant Aurora Orbs
28+
const orbs = [
29+
{ x: width * 0.2, y: height * 0.2, vx: 0.5, vy: 0.3, radius: width * 0.4, color: 'rgba(0, 229, 255, 0.4)' }, // Cyan
30+
{ x: width * 0.8, y: height * 0.8, vx: -0.4, vy: -0.5, radius: width * 0.5, color: 'rgba(139, 92, 246, 0.4)' }, // Violet
31+
{ x: width * 0.5, y: height * 0.5, vx: 0.3, vy: -0.4, radius: width * 0.6, color: 'rgba(217, 70, 239, 0.3)' }, // Fuchsia
32+
{ x: width * 0.8, y: height * 0.2, vx: -0.6, vy: 0.4, radius: width * 0.4, color: 'rgba(56, 189, 248, 0.4)' }, // Light Blue
33+
]
34+
35+
let mouseX = width / 2
36+
let mouseY = height / 2
3937

40-
// Mouse interaction
41-
let mouse = { x: -1000, y: -1000 }
4238
const handleMouseMove = (e: MouseEvent) => {
43-
mouse.x = e.clientX
44-
mouse.y = e.clientY
45-
}
46-
const handleMouseLeave = () => {
47-
mouse.x = -1000
48-
mouse.y = -1000
39+
mouseX = e.clientX
40+
mouseY = e.clientY
4941
}
5042
window.addEventListener('mousemove', handleMouseMove)
51-
document.addEventListener('mouseleave', handleMouseLeave)
52-
53-
// Init particles
54-
for (let i = 0; i < particleCount; i++) {
55-
particles.push({
56-
x: Math.random() * width,
57-
y: Math.random() * height,
58-
vx: (Math.random() - 0.5) * 0.5,
59-
vy: (Math.random() - 0.5) * 0.5,
60-
radius: Math.random() * 1.5 + 0.5
61-
})
62-
}
6343

6444
const animate = () => {
65-
ctx.clearRect(0, 0, width, height)
66-
67-
// Draw a subtle gradient background
68-
const bgGradient = ctx.createRadialGradient(width / 2, height / 2, 0, width / 2, height / 2, width)
69-
bgGradient.addColorStop(0, '#0a0a0f')
70-
bgGradient.addColorStop(1, '#000000')
71-
ctx.fillStyle = bgGradient
45+
ctx.fillStyle = '#05050A' // Very dark violet/black base
7246
ctx.fillRect(0, 0, width, height)
7347

74-
// Update and draw particles
75-
for (let i = 0; i < particles.length; i++) {
76-
const p = particles[i]
77-
48+
// Draw and move orbs
49+
orbs.forEach((orb, index) => {
7850
// Move
79-
p.x += p.vx
80-
p.y += p.vy
81-
82-
// Bounce off edges
83-
if (p.x < 0 || p.x > width) p.vx *= -1
84-
if (p.y < 0 || p.y > height) p.vy *= -1
85-
86-
// Mouse repulsion
87-
const dx = mouse.x - p.x
88-
const dy = mouse.y - p.y
89-
const dist = Math.sqrt(dx * dx + dy * dy)
90-
if (dist < 100) {
91-
const force = (100 - dist) / 100
92-
p.x -= (dx / dist) * force * 2
93-
p.y -= (dy / dist) * force * 2
51+
orb.x += orb.vx
52+
orb.y += orb.vy
53+
54+
// Bounce gently off boundaries (with massive padding so they can go off-screen)
55+
if (orb.x < -orb.radius || orb.x > width + orb.radius) orb.vx *= -1
56+
if (orb.y < -orb.radius || orb.y > height + orb.radius) orb.vy *= -1
57+
58+
// Add subtle mouse attraction to the first orb (Cyan)
59+
if (index === 0) {
60+
orb.x += (mouseX - orb.x) * 0.005
61+
orb.y += (mouseY - orb.y) * 0.005
9462
}
9563

96-
// Draw particle
64+
// Draw gradient orb
65+
const gradient = ctx.createRadialGradient(orb.x, orb.y, 0, orb.x, orb.y, orb.radius)
66+
gradient.addColorStop(0, orb.color)
67+
gradient.addColorStop(1, 'transparent')
68+
9769
ctx.beginPath()
98-
ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2)
99-
ctx.fillStyle = 'rgba(0, 229, 255, 0.8)'
70+
ctx.arc(orb.x, orb.y, orb.radius, 0, Math.PI * 2)
71+
ctx.fillStyle = gradient
10072
ctx.fill()
73+
})
10174

102-
// Connect particles
103-
for (let j = i + 1; j < particles.length; j++) {
104-
const p2 = particles[j]
105-
const dx2 = p.x - p2.x
106-
const dy2 = p.y - p2.y
107-
const dist2 = Math.sqrt(dx2 * dx2 + dy2 * dy2)
108-
109-
if (dist2 < connectionDistance) {
110-
ctx.beginPath()
111-
ctx.moveTo(p.x, p.y)
112-
ctx.lineTo(p2.x, p2.y)
113-
const opacity = 1 - (dist2 / connectionDistance)
114-
ctx.strokeStyle = `rgba(0, 229, 255, ${opacity * 0.2})`
115-
ctx.lineWidth = 1
116-
ctx.stroke()
117-
}
118-
}
75+
// Add a subtle grid overlay for a high-tech feel
76+
ctx.strokeStyle = 'rgba(255, 255, 255, 0.03)'
77+
ctx.lineWidth = 1
78+
const gridSize = 50
79+
for (let x = 0; x < width; x += gridSize) {
80+
ctx.beginPath()
81+
ctx.moveTo(x, 0)
82+
ctx.lineTo(x, height)
83+
ctx.stroke()
11984
}
120-
121-
// Add a large glowing aura around the mouse
122-
if (mouse.x !== -1000) {
123-
const mouseGlow = ctx.createRadialGradient(mouse.x, mouse.y, 0, mouse.x, mouse.y, 200)
124-
mouseGlow.addColorStop(0, 'rgba(0, 229, 255, 0.05)')
125-
mouseGlow.addColorStop(1, 'transparent')
126-
ctx.fillStyle = mouseGlow
127-
ctx.fillRect(0, 0, width, height)
85+
for (let y = 0; y < height; y += gridSize) {
86+
ctx.beginPath()
87+
ctx.moveTo(0, y)
88+
ctx.lineTo(width, y)
89+
ctx.stroke()
12890
}
12991

13092
requestAnimationFrame(animate)
@@ -135,15 +97,17 @@ const InteractiveBackground = () => {
13597
return () => {
13698
window.removeEventListener('resize', resize)
13799
window.removeEventListener('mousemove', handleMouseMove)
138-
document.removeEventListener('mouseleave', handleMouseLeave)
139100
}
140101
}, [])
141102

142103
return (
143-
<canvas
144-
ref={canvasRef}
145-
className="fixed inset-0 -z-10 pointer-events-none"
146-
/>
104+
<div className="fixed inset-0 -z-10 bg-[#05050A]">
105+
<canvas
106+
ref={canvasRef}
107+
className="w-full h-full object-cover"
108+
style={{ filter: 'blur(60px) saturate(150%)' }}
109+
/>
110+
</div>
147111
)
148112
}
149113

src/components/ProjectsSection.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -123,27 +123,27 @@ const ProjectsSection = () => {
123123
{projects.map((project, index) => (
124124
<motion.div
125125
key={index}
126-
className={`bento-card p-8 flex flex-col justify-between group ${project.colSpan} ${project.rowSpan}`}
126+
className={`bento-card p-6 md:p-8 flex flex-col justify-between group ${project.colSpan} ${project.rowSpan}`}
127127
variants={itemVariants}
128128
>
129-
<div className="flex justify-between items-start mb-6">
130-
<div>
131-
<span className="inline-block px-3 py-1 bg-white/5 border border-white/10 rounded-full text-xs text-white/60 mb-4 font-mono">
129+
<div className="flex justify-between items-start mb-6 gap-4">
130+
<div className="flex-1">
131+
<span className="inline-block px-3 py-1 bg-primary/20 border border-primary/30 rounded-full text-xs text-primary mb-4 font-mono font-bold tracking-wide">
132132
{project.device}
133133
</span>
134-
<h3 className="text-xl md:text-2xl font-bold group-hover:text-primary transition-colors duration-300">
134+
<h3 className="text-xl md:text-2xl font-bold text-white group-hover:text-primary transition-colors duration-300">
135135
{project.title}
136136
</h3>
137137
</div>
138-
<ArrowUpRight className="text-white/20 group-hover:text-primary transition-colors duration-300" size={24} />
138+
<ArrowUpRight className="text-white/40 group-hover:text-primary transition-colors duration-300 flex-shrink-0" size={28} />
139139
</div>
140140

141-
<div>
142-
<p className="text-white/60 text-sm mb-6 line-clamp-3 leading-relaxed">
141+
<div className="mt-auto">
142+
<p className="text-white/80 text-sm md:text-base mb-6 leading-relaxed">
143143
{project.description}
144144
</p>
145145

146-
<div className="flex flex-wrap gap-3">
146+
<div className="flex flex-wrap gap-3 mt-4">
147147
{project.links.map((link, linkIndex) => {
148148
const IconComponent = link.icon
149149
return (
@@ -152,9 +152,9 @@ const ProjectsSection = () => {
152152
href={link.href}
153153
target="_blank"
154154
rel="noopener noreferrer"
155-
className="inline-flex items-center gap-2 px-4 py-2 bg-white/5 hover:bg-primary/20 hover:text-primary border border-white/10 hover:border-primary/50 text-white/80 text-xs rounded-full transition-all duration-300 backdrop-blur-sm"
155+
className="inline-flex items-center gap-2 px-4 py-2 bg-white/10 hover:bg-primary hover:text-black border border-white/20 hover:border-primary text-white font-medium text-sm rounded-full transition-all duration-300"
156156
>
157-
<IconComponent size={14} />
157+
<IconComponent size={16} />
158158
{link.label}
159159
</a>
160160
)

src/styles/globals.css

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,15 @@ h1, h2, h3, h4, h5, h6 {
5151

5252
/* Bento Box Utilities */
5353
.bento-card {
54-
@apply bg-bento border border-white/5 rounded-3xl overflow-hidden relative backdrop-blur-md transition-all duration-500;
54+
@apply bg-black/60 border border-white/10 rounded-3xl overflow-hidden relative transition-all duration-500;
55+
backdrop-filter: blur(20px);
56+
-webkit-backdrop-filter: blur(20px);
57+
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.5);
5558
}
5659
.bento-card:hover {
57-
@apply border-white/20;
58-
box-shadow: 0 0 40px rgba(0, 229, 255, 0.05);
59-
transform: translateY(-2px);
60+
@apply border-white/30 bg-black/70;
61+
box-shadow: 0 10px 40px rgba(0, 229, 255, 0.15);
62+
transform: translateY(-4px);
6063
}
6164

6265
/* Typography animations */

0 commit comments

Comments
 (0)