- 🤖 Introduction
- ⚙️ Tech Stack
- 🔋 Features
- 🤸 Quick Start
- 🕸️ Snippets
- 🔗 Links
This project is a personal 3D portfolio website built to give an overview of my Software developer journey .
- React.js
- Three.js
- React Three Fiber
- React Three Drei
- Email JS
- Vite
- Tailwind CSS
👉 Customizable 3D Hero Section: Includes a 3D desktop model easily customizable to suit specific needs.
👉 Interactive Experience, Projects and Work Sections: Utilizes animations powered by framer motion for engaging user experience.
👉 3D Skills Section: Showcases skills using 3D geometries through three.js and React Three fiber
👉 Animated Projects, Certifications and Testimonials: Features animated sections using framer motion for projects and client testimonials.
👉 Contact Section with 3D Earth Model:Integrates a 3D earth model with email functionality powered by emailjs.
👉 3D Stars: Generate stars progressively at random positions using Three.js for background display.
👉 Consistent Animations: Implements cohesive animations throughout the website using framer motion.
👉 Responsive Design: Ensures optimal display and functionality across all devices.
Follow these steps to set up the project locally on your machine.
Make sure you have the following installed on your machine:
git clone git@github.com:Csasaka19/Portfolio.git
cd Portfolio
Install the project dependencies using npm:
npm install
Create a new file named .env
in the root of your project and add the following content:
REACT_APP_EMAILJS_USERID=your_emailjs_user_id
REACT_APP_EMAILJS_TEMPLATEID=your_emailjs_template_id
REACT_APP_EMAILJS_RECEIVERID=your_emailjs_receiver_id
Replace the placeholder values with your actual EmailJS credentials. You can obtain these credentials by signing up on the EmailJS website.
npm run dev
Open http://localhost:5173 in your browser to view the 3D Website.
constants.js
import {
mobile,
backend,
creator,
web,
javascript,
typescript,
html,
css,
tailwind,
nodejs,
mongodb,
git,
figma,
docker,
bash,
c,
dart,
datadog,
maria,
pythoon,
r,
redis,
trello,
alx,
cs50,
daystar,
udacity,
R,
python,
flutter,
flask,
Credit,
Chatroom,
patient,
roommate,
certificate,
} from "../assets";
export const navLinks = [
{
id: "about",
title: "About",
},
{
id: "work",
title: "Work",
},
{
id: "contact",
title: "Contact",
},
];
const services = [
{
title: "Full Stack Web Developer",
icon: web,
},
{
title: "Flutter Developer",
icon: mobile,
},
{
title: "Backend Developer",
icon: backend,
},
{
title: "Networking and Server management",
icon: creator,
},
];
const technologies = [
{
name: "C",
icon: c,
},
{
name: "JavaScript",
icon: javascript,
},
{
name: "Node JS",
icon: nodejs,
},
{
name: "MongoDB",
icon: mongodb,
},
{
name: "bash",
icon: bash,
},
{
name: "dart",
icon: dart,
},
{
name: "flask",
icon: flask,
},
{
name: "flutter",
icon: flutter,
},
{
name: "python",
icon: pythoon,
},
{
name: "datadog",
icon: datadog,
},
{
name: "redis",
icon: redis,
},
{
name: "maria",
icon: maria,
},
{
name: "trello",
icon: trello,
},
{
name: "git",
icon: git,
},
{
name: "docker",
icon: docker,
},
{
name: "HTML 5",
icon: html,
},
{
name: "CSS 3",
icon: css,
},
{
name: "TypeScript",
icon: typescript,
},
{
name: "Tailwind CSS",
icon: tailwind,
},
{
name: "figma",
icon: figma,
},
];
index.css
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@100;200;300;400;500;600;700;800;900&display=swap");
@tailwind base;
@tailwind components;
@tailwind utilities;
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Poppins", sans-serif;
scroll-behavior: smooth;
color-scheme: dark;
}
.hash-span {
margin-top: -100px;
padding-bottom: 100px;
display: block;
}
.black-gradient {
background: #000000; /* fallback for old browsers */
background: -webkit-linear-gradient(
to right,
#434343,
#000000
); /* Chrome 10-25, Safari 5.1-6 */
background: linear-gradient(
to right,
#434343,
#000000
); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
}
.violet-gradient {
background: #804dee;
background: linear-gradient(-90deg, #804dee 0%, rgba(60, 51, 80, 0) 100%);
background: -webkit-linear-gradient(
-90deg,
#804dee 0%,
rgba(60, 51, 80, 0) 100%
);
}
.green-pink-gradient {
background: "#00cea8";
background: linear-gradient(90.13deg, #00cea8 1.9%, #bf61ff 97.5%);
background: -webkit-linear-gradient(-90.13deg, #00cea8 1.9%, #bf61ff 97.5%);
}
.orange-text-gradient {
background: #f12711; /* fallback for old browsers */
background: -webkit-linear-gradient(
to top,
#f12711,
#f5af19
); /* Chrome 10-25, Safari 5.1-6 */
background: linear-gradient(
to top,
#f12711,
#f5af19
); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.green-text-gradient {
background: #11998e; /* fallback for old browsers */
background: -webkit-linear-gradient(
to top,
#11998e,
#38ef7d
); /* Chrome 10-25, Safari 5.1-6 */
background: linear-gradient(
to top,
#11998e,
#38ef7d
); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.blue-text-gradient {
/* background: -webkit-linear-gradient(#eee, #333); */
background: #56ccf2; /* fallback for old browsers */
background: -webkit-linear-gradient(
to top,
#2f80ed,
#56ccf2
); /* Chrome 10-25, Safari 5.1-6 */
background: linear-gradient(
to top,
#2f80ed,
#56ccf2
); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.pink-text-gradient {
background: #ec008c; /* fallback for old browsers */
background: -webkit-linear-gradient(
to top,
#ec008c,
#fc6767
); /* Chrome 10-25, Safari 5.1-6 */
background: linear-gradient(
to top,
#ec008c,
#fc6767
); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
/* canvas- styles */
.canvas-loader {
font-size: 10px;
width: 1em;
height: 1em;
border-radius: 50%;
position: relative;
text-indent: -9999em;
animation: mulShdSpin 1.1s infinite ease;
transform: translateZ(0);
}
@keyframes mulShdSpin {
0%,
100% {
box-shadow: 0em -2.6em 0em 0em #ffffff,
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
-2.6em 0em 0 0em rgba(255, 255, 255, 0.5),
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7);
}
12.5% {
box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.7),
1.8em -1.8em 0 0em #ffffff, 2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5);
}
25% {
box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.5),
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7), 2.5em 0em 0 0em #ffffff,
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
}
37.5% {
box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5),
2.5em 0em 0 0em rgba(255, 255, 255, 0.7), 1.75em 1.75em 0 0em #ffffff,
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
}
50% {
box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
2.5em 0em 0 0em rgba(255, 255, 255, 0.5),
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.7), 0em 2.5em 0 0em #ffffff,
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
}
62.5% {
box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.5),
0em 2.5em 0 0em rgba(255, 255, 255, 0.7), -1.8em 1.8em 0 0em #ffffff,
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
}
75% {
box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
0em 2.5em 0 0em rgba(255, 255, 255, 0.5),
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.7), -2.6em 0em 0 0em #ffffff,
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
}
87.5% {
box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.5),
-2.6em 0em 0 0em rgba(255, 255, 255, 0.7), -1.8em -1.8em 0 0em #ffffff;
}
}
Motion.js
export const textVariant = (delay) => {
return {
hidden: {
y: -50,
opacity: 0,
},
show: {
y: 0,
opacity: 1,
transition: {
type: "spring",
duration: 1.25,
delay: delay,
},
},
};
};
export const fadeIn = (direction, type, delay, duration) => {
return {
hidden: {
x: direction === "left" ? 100 : direction === "right" ? -100 : 0,
y: direction === "up" ? 100 : direction === "down" ? -100 : 0,
opacity: 0,
},
show: {
x: 0,
y: 0,
opacity: 1,
transition: {
type: type,
delay: delay,
duration: duration,
ease: "easeOut",
},
},
};
};
export const zoomIn = (delay, duration) => {
return {
hidden: {
scale: 0,
opacity: 0,
},
show: {
scale: 1,
opacity: 1,
transition: {
type: "tween",
delay: delay,
duration: duration,
ease: "easeOut",
},
},
};
};
export const slideIn = (direction, type, delay, duration) => {
return {
hidden: {
x: direction === "left" ? "-100%" : direction === "right" ? "100%" : 0,
y: direction === "up" ? "100%" : direction === "down" ? "100%" : 0,
},
show: {
x: 0,
y: 0,
transition: {
type: type,
delay: delay,
duration: duration,
ease: "easeOut",
},
},
};
};
export const staggerContainer = (staggerChildren, delayChildren) => {
return {
hidden: {},
show: {
transition: {
staggerChildren: staggerChildren,
delayChildren: delayChildren || 0,
},
},
};
};
styles.js
const styles = {
paddingX: "sm:px-16 px-6",
paddingY: "sm:py-16 py-6",
padding: "sm:px-16 px-6 sm:py-16 py-10",
heroHeadText:
"font-black text-white lg:text-[80px] sm:text-[60px] xs:text-[50px] text-[40px] lg:leading-[98px] mt-2",
heroSubText:
"text-[#dfd9ff] font-medium lg:text-[30px] sm:text-[26px] xs:text-[20px] text-[16px] lg:leading-[40px]",
sectionHeadText:
"text-white font-black md:text-[60px] sm:text-[50px] xs:text-[40px] text-[30px]",
sectionSubText:
"sm:text-[18px] text-[14px] text-secondary uppercase tracking-wider",
};
export { styles };
tailwind.config.cjs
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{js,jsx}"],
mode: "jit",
theme: {
extend: {
colors: {
primary: "#050816",
secondary: "#aaa6c3",
tertiary: "#151030",
"black-100": "#100d25",
"black-200": "#090325",
"white-100": "#f3f3f3",
},
boxShadow: {
card: "0px 35px 120px -15px #211e35",
},
screens: {
xs: "450px",
},
backgroundImage: {
"hero-pattern": "url('/src/assets/herobg.png')",
},
},
},
plugins: [],
};
I am yet to deploy the web application.