From 3251d5d3ee44d32b6e1eb5b7cd0bac0c84eba755 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 4 Nov 2025 16:55:34 +0000
Subject: [PATCH 1/9] Initial plan
From da9bfbaec3bbd5d455b322f2f394fc45a346b5c9 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 4 Nov 2025 17:02:37 +0000
Subject: [PATCH 2/9] Performance optimizations: Fix redundant loops, add
React.memo, and optimize re-renders
Co-authored-by: Keyyard <84187238+Keyyard@users.noreply.github.com>
---
eslint.config.js | 6 ++----
src/components/layout/Background.tsx | 8 ++++++--
src/components/layout/MyHead.tsx | 20 ++++++++------------
src/components/layout/Nav.tsx | 4 +++-
src/components/sections/Hero.tsx | 21 +++++++++++++--------
src/components/sections/Projects.tsx | 6 +++---
src/components/ui/SafeCarousel.tsx | 8 +++++---
src/components/ui/SafeImage.tsx | 8 +++++---
8 files changed, 45 insertions(+), 36 deletions(-)
diff --git a/eslint.config.js b/eslint.config.js
index 62a6f0a..169cb83 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -5,10 +5,9 @@ import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import typescript from '@typescript-eslint/eslint-plugin'
import parser from '@typescript-eslint/parser'
-import next from 'eslint-plugin-next'
export default [
- { ignores: ['dist', '.next'] },
+ { ignores: ['dist', '.next', 'out', 'node_modules'] },
{
files: ['**/*.{js,jsx,ts,tsx}'],
languageOptions: {
@@ -27,7 +26,6 @@ export default [
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
'@typescript-eslint': typescript,
- next,
},
rules: {
...js.configs.recommended.rules,
@@ -35,8 +33,8 @@ export default [
...react.configs['jsx-runtime'].rules,
...reactHooks.configs.recommended.rules,
...typescript.configs.recommended.rules,
- ...next.configs.recommended.rules,
'react/jsx-no-target-blank': 'off',
+ 'react/prop-types': 'off', // Using TypeScript for prop validation
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
diff --git a/src/components/layout/Background.tsx b/src/components/layout/Background.tsx
index 1835931..86fcbe6 100644
--- a/src/components/layout/Background.tsx
+++ b/src/components/layout/Background.tsx
@@ -1,8 +1,12 @@
-const Bg = () => {
+import { memo } from "react";
+
+const Bg = memo(() => {
return (
);
-};
+});
+
+Bg.displayName = 'Background';
export default Bg;
diff --git a/src/components/layout/MyHead.tsx b/src/components/layout/MyHead.tsx
index c34e20c..3673959 100644
--- a/src/components/layout/MyHead.tsx
+++ b/src/components/layout/MyHead.tsx
@@ -38,16 +38,6 @@ function Model({ onLoaded }: { onLoaded: () => void }) {
};
}, [scene, animations]);
- useEffect(() => {
- const animate = () => {
- requestAnimationFrame(animate);
- if (mixer.current) {
- mixer.current.update(0.01);
- }
- };
- animate();
- }, []);
-
useEffect(() => {
if (head.current) {
head.current.rotation.set(0, Math.PI, 0);
@@ -55,10 +45,16 @@ function Model({ onLoaded }: { onLoaded: () => void }) {
}
}, []);
- useFrame((state, dt) => {
+ useFrame((state, delta) => {
+ // Update animation mixer if active
+ if (mixer.current) {
+ mixer.current.update(delta);
+ }
+
+ // Update head rotation to follow cursor
dummy.lookAt(cursor.x, cursor.y, 1);
dummy.rotation.y += Math.PI;
- easing.dampQ(head.current.quaternion, dummy.quaternion, 0.15, dt);
+ easing.dampQ(head.current.quaternion, dummy.quaternion, 0.15, delta);
});
return ;
diff --git a/src/components/layout/Nav.tsx b/src/components/layout/Nav.tsx
index bb0cda4..e15aeac 100644
--- a/src/components/layout/Nav.tsx
+++ b/src/components/layout/Nav.tsx
@@ -27,7 +27,9 @@ const Nav = () => {
(entries) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) return;
- setActiveSection(entry.target.id);
+ // Only update if the active section has actually changed
+ const newSection = entry.target.id;
+ setActiveSection((prev) => prev !== newSection ? newSection : prev);
});
},
{ threshold: 0.01 },
diff --git a/src/components/sections/Hero.tsx b/src/components/sections/Hero.tsx
index 878d872..5d47615 100644
--- a/src/components/sections/Hero.tsx
+++ b/src/components/sections/Hero.tsx
@@ -1,5 +1,6 @@
import { motion } from "framer-motion";
import dynamic from "next/dynamic";
+import { useCallback } from "react";
import { introductionText } from "../../data";
import Bg from "../layout/Background";
@@ -9,6 +10,16 @@ const HeadRender = dynamic(() => import("../layout/MyHead"), {
});
export function Hero() {
+ const scrollToProjects = useCallback(() => {
+ const projectsSection = document.getElementById("projects");
+ projectsSection?.scrollIntoView({ behavior: "smooth" });
+ }, []);
+
+ const scrollToContact = useCallback(() => {
+ const contactSection = document.getElementById("contact");
+ contactSection?.scrollIntoView({ behavior: "smooth" });
+ }, []);
+
return (
@@ -57,19 +68,13 @@ export function Hero() {
)}
-