Skip to content

Commit 2580230

Browse files
committed
overhaul 0.1
1 parent 5d5ffd6 commit 2580230

File tree

1 file changed

+211
-23
lines changed

1 file changed

+211
-23
lines changed

index.html

Lines changed: 211 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
}
9090

9191
.cert-card:hover {
92-
transform: translateY(-5px);
92+
transform: translateY(5px);
9393
box-shadow: 0 15px 40px rgba(255, 107, 71, 0.15);
9494
}
9595

@@ -117,6 +117,36 @@
117117
color: white;
118118
}
119119

120+
/* Enhanced project card animations */
121+
.project-card {
122+
transform-style: preserve-3d;
123+
perspective: 1000px;
124+
will-change: transform, opacity;
125+
}
126+
127+
.project-card img {
128+
will-change: transform, scale;
129+
backface-visibility: hidden;
130+
}
131+
132+
.project-card.in-view {
133+
/* Optimized rendering for cards in view */
134+
}
135+
136+
@media (prefers-reduced-motion: reduce) {
137+
.project-card {
138+
transform: none !important;
139+
}
140+
.project-card img {
141+
transform: none !important;
142+
}
143+
}
144+
145+
/* Performance optimizations */
146+
.project-card, .skill-card {
147+
contain: layout style paint;
148+
}
149+
120150
/* Custom scrollbar */
121151
::-webkit-scrollbar {
122152
width: 6px;
@@ -785,13 +815,13 @@ <h4 class="font-medium mb-4">Follow Me</h4>
785815
}
786816

787817
// Certificate filtering
788-
function filterCertificates(category) {
789-
const cards = document.querySelectorAll('.cert-card');
818+
function filterCertificates(category, buttonElement) {
819+
const cards = document.querySelectorAll('[data-categories]');
790820
const filterButtons = document.querySelectorAll('.filter-btn');
791821

792822
// Update active filter button
793823
filterButtons.forEach(btn => btn.classList.remove('active'));
794-
event.target.classList.add('active');
824+
buttonElement.classList.add('active');
795825

796826
cards.forEach(card => {
797827
const cardCategory = card.dataset.categories;
@@ -835,15 +865,15 @@ <h4 class="font-medium mb-4">Follow Me</h4>
835865
function createCertificateCard(cert, index) {
836866
return new Promise((resolve) => {
837867
const card = document.createElement('div');
838-
card.className = 'cert-card opacity-0 transform translate-y-4 transition-all duration-300 ease-in-out';
868+
card.className = 'opacity-0 transform translate-y-4 transition-all duration-300 ease-in-out cert-card';
839869
card.dataset.categories = cert.category;
840870

841871
card.innerHTML = `
842872
<div class="card rounded-lg overflow-hidden">
843873
<div class="relative h-64 overflow-hidden">
844874
<iframe class="cert-iframe" src="${cert.path}"></iframe>
845875
<div class="absolute inset-0 bg-gradient-to-t from-black/70 via-black/0 to-transparent transform translate-y-full transition-transform duration-300 p-4 flex flex-col justify-end">
846-
<div class="text-emerald-500 font-medium text-sm">${cert.title}</div>
876+
<div class="text-black font-medium text-sm">${cert.title}</div>
847877
</div>
848878
</div>
849879
<div class="p-4">
@@ -900,7 +930,8 @@ <h4 class="font-medium mb-4">Follow Me</h4>
900930
// Filter button event listeners
901931
document.querySelectorAll('.filter-btn').forEach(btn => {
902932
btn.addEventListener('click', (e) => {
903-
filterCertificates(e.target.dataset.filter);
933+
const category = e.target.dataset.filter;
934+
filterCertificates(category, e.target);
904935
});
905936
});
906937
});
@@ -1000,34 +1031,181 @@ <h4 class="font-medium mb-4">Follow Me</h4>
10001031
});
10011032
});
10021033

1003-
// Projects section animations
1034+
// Optimized Projects section animations
1035+
1036+
// Enhanced title animation with text reveal effect
1037+
gsap.set('#projects-title', { opacity: 0, y: 50 });
10041038
gsap.to('#projects-title', {
10051039
scrollTrigger: {
10061040
trigger: '#projects',
10071041
start: 'top 80%',
1042+
end: 'top 50%',
10081043
toggleActions: 'play none none reset'
10091044
},
10101045
opacity: 1,
10111046
y: 0,
1012-
duration: 0.8,
1013-
ease: 'power2.out'
1047+
duration: 1,
1048+
ease: 'power3.out'
10141049
});
10151050

1016-
gsap.utils.toArray('.project-card').forEach((card, i) => {
1017-
gsap.to(card, {
1018-
scrollTrigger: {
1019-
trigger: card,
1020-
start: 'top 90%',
1021-
toggleActions: 'play none none reset'
1022-
},
1051+
// Advanced project cards animation with improved performance
1052+
gsap.set('.project-card', {
1053+
opacity: 0,
1054+
y: 80,
1055+
scale: 0.8,
1056+
rotationX: 15
1057+
});
1058+
1059+
// Create timeline for better performance and control
1060+
const projectTimeline = gsap.timeline({
1061+
scrollTrigger: {
1062+
trigger: '#projects .grid',
1063+
start: 'top 85%',
1064+
end: 'bottom 20%',
1065+
toggleActions: 'play none none reset'
1066+
}
1067+
});
1068+
1069+
// Animate project cards in batches for better performance
1070+
const projectCards = gsap.utils.toArray('.project-card');
1071+
const batchSize = 3; // Animate 3 cards at a time
1072+
1073+
for (let i = 0; i < projectCards.length; i += batchSize) {
1074+
const batch = projectCards.slice(i, i + batchSize);
1075+
1076+
projectTimeline.to(batch, {
10231077
opacity: 1,
10241078
y: 0,
1079+
scale: 1,
1080+
rotationX: 0,
10251081
duration: 0.8,
1026-
delay: i * 0.2,
1027-
ease: 'power2.out'
1082+
ease: 'power3.out',
1083+
stagger: {
1084+
amount: 0.3,
1085+
from: 'start',
1086+
ease: 'power2.out'
1087+
}
1088+
}, i === 0 ? 0 : '-=0.4'); // Overlap batches slightly
1089+
}
1090+
1091+
// Enhanced individual card hover animations with better performance
1092+
projectCards.forEach((card, index) => {
1093+
const image = card.querySelector('img');
1094+
const techTags = card.querySelectorAll('.tech-tag');
1095+
1096+
// Create hover timeline for each card
1097+
const hoverTl = gsap.timeline({ paused: true });
1098+
1099+
hoverTl
1100+
.to(card, {
1101+
scale: 1.05,
1102+
rotationX: -2,
1103+
rotationY: 2,
1104+
z: 50,
1105+
duration: 0.4,
1106+
ease: 'power2.out'
1107+
}, 0)
1108+
.to(image, {
1109+
scale: 1.1,
1110+
duration: 0.4,
1111+
ease: 'power2.out'
1112+
}, 0)
1113+
.to(techTags, {
1114+
y: -5,
1115+
duration: 0.3,
1116+
ease: 'back.out(1.7)',
1117+
stagger: 0.05
1118+
}, 0.1);
1119+
1120+
// Mouse events with debouncing for performance
1121+
let hoverTimeout;
1122+
1123+
card.addEventListener('mouseenter', () => {
1124+
clearTimeout(hoverTimeout);
1125+
hoverTl.play();
1126+
});
1127+
1128+
card.addEventListener('mouseleave', () => {
1129+
hoverTimeout = setTimeout(() => {
1130+
hoverTl.reverse();
1131+
}, 50);
1132+
});
1133+
1134+
// Add parallax effect on mouse move
1135+
card.addEventListener('mousemove', (e) => {
1136+
const rect = card.getBoundingClientRect();
1137+
const centerX = rect.left + rect.width / 2;
1138+
const centerY = rect.top + rect.height / 2;
1139+
1140+
const deltaX = (e.clientX - centerX) / rect.width;
1141+
const deltaY = (e.clientY - centerY) / rect.height;
1142+
1143+
gsap.to(card, {
1144+
rotationX: deltaY * -10,
1145+
rotationY: deltaX * 10,
1146+
duration: 0.3,
1147+
ease: 'power2.out',
1148+
overwrite: 'auto'
1149+
});
1150+
});
1151+
1152+
card.addEventListener('mouseleave', () => {
1153+
gsap.to(card, {
1154+
rotationX: 0,
1155+
rotationY: 0,
1156+
duration: 0.5,
1157+
ease: 'power2.out'
1158+
});
10281159
});
10291160
});
10301161

1162+
// Add intersection observer for performance optimization
1163+
const observerOptions = {
1164+
root: null,
1165+
rootMargin: '100px',
1166+
threshold: 0.1
1167+
};
1168+
1169+
const projectObserver = new IntersectionObserver((entries) => {
1170+
entries.forEach(entry => {
1171+
if (entry.isIntersecting) {
1172+
entry.target.classList.add('in-view');
1173+
} else {
1174+
entry.target.classList.remove('in-view');
1175+
}
1176+
});
1177+
}, observerOptions);
1178+
1179+
// Observe all project cards
1180+
projectCards.forEach(card => {
1181+
projectObserver.observe(card);
1182+
});
1183+
1184+
// Add scroll-triggered parallax for project images
1185+
projectCards.forEach((card, index) => {
1186+
const image = card.querySelector('img');
1187+
if (image) {
1188+
gsap.to(image, {
1189+
scrollTrigger: {
1190+
trigger: card,
1191+
start: 'top bottom',
1192+
end: 'bottom top',
1193+
scrub: 1,
1194+
onUpdate: self => {
1195+
// Only animate if card is in view for performance
1196+
if (card.classList.contains('in-view')) {
1197+
const progress = self.progress;
1198+
gsap.set(image, {
1199+
y: (progress - 0.5) * 20,
1200+
scale: 1 + (Math.sin(progress * Math.PI) * 0.05)
1201+
});
1202+
}
1203+
}
1204+
}
1205+
});
1206+
}
1207+
});
1208+
10311209
// Certificates section animations
10321210
gsap.to('#certificates-title', {
10331211
scrollTrigger: {
@@ -1071,13 +1249,23 @@ <h4 class="font-medium mb-4">Follow Me</h4>
10711249
});
10721250
});
10731251

1074-
// Enhanced hover animations
1075-
document.querySelectorAll('.card').forEach(card => {
1252+
// Enhanced hover animations for non-project cards
1253+
document.querySelectorAll('.card:not(.project-card)').forEach(card => {
10761254
card.addEventListener('mouseenter', () => {
1077-
gsap.to(card, { scale: 1.02, duration: 0.3, ease: 'power2.out' });
1255+
gsap.to(card, {
1256+
scale: 1.02,
1257+
y: -5,
1258+
duration: 0.3,
1259+
ease: 'power2.out'
1260+
});
10781261
});
10791262
card.addEventListener('mouseleave', () => {
1080-
gsap.to(card, { scale: 1, duration: 0.3, ease: 'power2.out' });
1263+
gsap.to(card, {
1264+
scale: 1,
1265+
y: 0,
1266+
duration: 0.3,
1267+
ease: 'power2.out'
1268+
});
10811269
});
10821270
});
10831271

0 commit comments

Comments
 (0)