├── .env.example
├── .eslintrc.json
├── .github
└── FUNDING.yml
├── .gitignore
├── Image Prompts.txt
├── LICENSE.md
├── README.md
├── jsconfig.json
├── next.config.mjs
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
├── audio
│ └── birds39-forest-20772.mp3
├── background
│ ├── about-background.png
│ ├── contact-background.png
│ ├── home-background.png
│ └── projects-background.png
├── models
│ ├── hat-transformed.glb
│ ├── staff-transformed.glb
│ └── wizard-transformed.glb
├── next.svg
├── resume.pdf
└── vercel.svg
├── src
├── app
│ ├── (sub pages)
│ │ ├── about
│ │ │ └── page.js
│ │ ├── contact
│ │ │ └── page.js
│ │ ├── layout.js
│ │ └── projects
│ │ │ └── page.js
│ ├── data.js
│ ├── favicon.ico
│ ├── globals.css
│ ├── layout.js
│ └── page.js
└── components
│ ├── FireFliesBackground.jsx
│ ├── HomeBtn.jsx
│ ├── RenderModel.jsx
│ ├── ResponsiveComponent.jsx
│ ├── Sound.jsx
│ ├── about
│ ├── ItemLayout.jsx
│ └── index.jsx
│ ├── contact
│ └── Form.jsx
│ ├── hooks
│ └── useScreenSize.jsx
│ ├── models
│ ├── HatModel.jsx
│ ├── Staff.jsx
│ └── Wizard.jsx
│ ├── navigation
│ ├── NavButton.jsx
│ └── index.jsx
│ └── projects
│ ├── ProjectLayout.jsx
│ └── index.jsx
└── tailwind.config.js
/.env.example:
--------------------------------------------------------------------------------
1 | NEXT_PUBLIC_SERVICE_ID="Enter your service id here"
2 | NEXT_PUBLIC_TEMPLATE_ID="Enter your template id here"
3 | NEXT_PUBLIC_PUBLIC_KEY="Enter your public key here"
4 |
5 | # Following env variables should be replaced with your own hosted github stats
6 |
7 | NEXT_PUBLIC_GITHUB_STATS_URL="https://github-readme-stats.vercel.app"
8 | NEXT_PUBLIC_GITHUB_STREAK_STATS_URL="https://github-readme-streak-stats.herokuapp.com"
9 |
10 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [codebucks27] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
12 | polar: # Replace with a single Polar username
13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
14 | thanks_dev: # Replace with a single thanks.dev username
15 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 | .yarn/install-state.gz
8 |
9 | # testing
10 | /coverage
11 |
12 | # next.js
13 | /.next/
14 | /out/
15 |
16 | # production
17 | /build
18 |
19 | # misc
20 | .DS_Store
21 | *.pem
22 |
23 | # debug
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/Image Prompts.txt:
--------------------------------------------------------------------------------
1 | Site: https://playground.com/
2 |
3 | Default Configuration:
4 |
5 | - Model: Stable Diffusion XL
6 |
7 | - Filter: RealVis XL
8 |
9 | - Image Dimentions: 1024*576 (16:9)
10 |
11 | - Quality & Details: 30 steps
12 |
13 | --------------------------------------------------
14 |
15 | Home Page Background
16 |
17 | - Prompt: "An enchanted forest at night, under a starlit sky. The scene is dark by mystical glows from luminescent flowers, exotic mushrooms, and arcane symbols on ancient trees. The atmosphere is serene, with a magical aura conveyed through ethereal particles and soft glimmers of light floating in the air. The color scheme should focus on dark tones with highlights in mild yellow and gold, creating a magical and inviting scene that blends the beauty of an astral night with the mystery of a magical forest."
18 |
19 | - Seed: 656140970
20 |
21 |
22 | --------------------------------------------------
23 |
24 | About Page Background
25 |
26 | - Prompt: "mystical forest, dawn, luminescent plants, mist, ancient trees, tranquil, magical ambiance."
27 |
28 | - Seed: 568754894
29 |
30 |
31 | --------------------------------------------------
32 |
33 | Projects Page Background
34 |
35 | - Prompt: "An enchanted workshop at night, nestled within a forest clearing. The workshop is illuminated by glowing crystals and lanterns, casting soft lights on intricate machinery and floating spellbooks. Workbenches are cluttered with magical tools, potions, and ancient maps. The backdrop is a blend of natural forest elements and magical innovation, suggesting a space where magical projects and creations come to life."
36 |
37 | - Seed: 949988405
38 |
39 |
40 | --------------------------------------------------
41 |
42 | Contact Page Background
43 |
44 | - Prompt: "Twilight forest, ancient stone archway, glowing runes, magical flora, shimmering leaves, ethereal wisps, ambient light."
45 |
46 | - Seed: 225378614
47 |
48 |
49 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024-present CODEBUCKS.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Next.js Creative Portfolio Tutorial: Build Amazing Portfolio Website with Next.js, Three.js, and Tailwind CSS 🔥
2 |
3 | 
4 | 
5 | 
6 |
7 | This repository contains **final code** for Next.js Creative Portfolio website built using Next.js and Three.js.
8 |
9 | For Demo checkout following link👇:
10 | [Nextjs Creative Portfolio Website Demo](https://next-js-creative-portfolio-website.vercel.app/)
11 |
12 | Starter Code Files👇:
13 | ➡ Link 💚: [Nextjs Creative Portfolio Website Starter Code](https://github.com/codebucks27/Nextjs-Creative-Portfolio-Starter-Code-Files)
14 |
15 |
16 | If you want to learn how to create it please follow below tutorial👇:
17 | ➡ Tutorial Link 💚: [Personal Portfolio Website with Next.js, Three.js & Tailwind CSS Tutorial](https://youtu.be/T5t46vuW8fo)
18 | [](https://youtu.be/T5t46vuW8fo)
20 |
21 | 💚 Checkout my personal website [DevDreaming](https://devdreaming.com)
22 |
23 | ---
24 | # ⭐DO NOT FORGET TO STAR THIS REPO⭐
25 | ---
26 |
27 | ## Images of The Portfolio Website:
28 |
29 | #### Home
30 | 
31 |
32 | #### About
33 | 
34 |
35 | #### Projects
36 | 
37 |
38 | #### Contact
39 | 
40 |
41 | #### Mobile Version
42 | 
43 | 
44 | 
45 | 
46 |
47 | ## Resources Used in This Project
48 |
49 | #### 3D Models
50 |
51 | - ["Tim Mckee - Boy Wizard"](https://skfb.ly/6YATu) by [elbertwithane is licensed under Creative Commons Attribution ](http://creativecommons.org/licenses/by/4.0/).
52 | - ["Stylized wizard hat"](https://skfb.ly/ozxOQ) by [Enkarra is licensed under Creative Commons Attribution](http://creativecommons.org/licenses/by/4.0/).
53 | - ["Wizard Staff"](https://skfb.ly/6QYZw) by [Toymancer Studio is licensed under Creative Commons Attribution](http://creativecommons.org/licenses/by/4.0/).
54 |
55 | #### AI Images
56 |
57 | - Created with the help of [Playground AI](https://playgroundai.com/)
58 |
59 | #### Github Stats & Details
60 |
61 | - [Github ReadMe Stats](https://github.com/anuraghazra/github-readme-stats)
62 | - [Skills Icons](https://github.com/tandpfun/skill-icons)
63 | - [Github Readme Streak Stats](https://github.com/denvercoder1/github-readme-streak-stats)
64 |
65 | #### Development Resources
66 |
67 | - Fonts from [Google Fonts](https://fonts.google.com/)
68 | - Icons from [Lucide Icons](https://lucide.dev/)
69 | - Notifications from [Sonner](https://sonner.emilkowal.ski/)
70 | - Form created using [react-hook-form](https://react-hook-form.com/)
71 | - Animations using [framer-motion](https://www.framer.com/motion/)
72 | - Emails using [Emailjs](https://www.emailjs.com/)
73 | - Convert 3d models to JSX using [Gltf JSX](https://github.com/pmndrs/gltfjsx)
74 |
75 | #### Audio
76 |
77 | - Music by Shiden Beats Music from Pixabay
78 |
79 | ---
80 |
81 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
82 |
83 | ## Getting Started
84 |
85 | First, install the dependencies and run the development server:
86 |
87 | ```bash
88 | npm run install # to install all dependencies
89 |
90 | npm run dev
91 | # or
92 | yarn dev
93 | # or
94 | pnpm dev
95 | # or
96 | bun dev
97 | ```
98 |
99 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
100 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "paths": {
4 | "@/*": ["./src/*"]
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/next.config.mjs:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {};
3 |
4 | export default nextConfig;
5 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nextjs-creative-portfolio",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@emailjs/browser": "^4.2.0",
13 | "@react-three/drei": "^9.99.5",
14 | "@react-three/fiber": "^8.15.16",
15 | "clsx": "^2.1.0",
16 | "framer-motion": "^11.0.8",
17 | "lucide-react": "^0.344.0",
18 | "next": "14.2.10",
19 | "react": "^18",
20 | "react-dom": "^18",
21 | "react-hook-form": "^7.51.0",
22 | "sharp": "^0.33.2",
23 | "sonner": "^1.4.3",
24 | "three": "^0.162.0"
25 | },
26 | "devDependencies": {
27 | "autoprefixer": "^10.0.1",
28 | "eslint": "^8",
29 | "eslint-config-next": "14.1.1",
30 | "postcss": "^8",
31 | "tailwindcss": "^3.3.0"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/public/audio/birds39-forest-20772.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codebucks27/Next.js-Creative-Portfolio-Website/cff35d71760fe35797e675a15073d17307d81e72/public/audio/birds39-forest-20772.mp3
--------------------------------------------------------------------------------
/public/background/about-background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codebucks27/Next.js-Creative-Portfolio-Website/cff35d71760fe35797e675a15073d17307d81e72/public/background/about-background.png
--------------------------------------------------------------------------------
/public/background/contact-background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codebucks27/Next.js-Creative-Portfolio-Website/cff35d71760fe35797e675a15073d17307d81e72/public/background/contact-background.png
--------------------------------------------------------------------------------
/public/background/home-background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codebucks27/Next.js-Creative-Portfolio-Website/cff35d71760fe35797e675a15073d17307d81e72/public/background/home-background.png
--------------------------------------------------------------------------------
/public/background/projects-background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codebucks27/Next.js-Creative-Portfolio-Website/cff35d71760fe35797e675a15073d17307d81e72/public/background/projects-background.png
--------------------------------------------------------------------------------
/public/models/hat-transformed.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codebucks27/Next.js-Creative-Portfolio-Website/cff35d71760fe35797e675a15073d17307d81e72/public/models/hat-transformed.glb
--------------------------------------------------------------------------------
/public/models/staff-transformed.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codebucks27/Next.js-Creative-Portfolio-Website/cff35d71760fe35797e675a15073d17307d81e72/public/models/staff-transformed.glb
--------------------------------------------------------------------------------
/public/models/wizard-transformed.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codebucks27/Next.js-Creative-Portfolio-Website/cff35d71760fe35797e675a15073d17307d81e72/public/models/wizard-transformed.glb
--------------------------------------------------------------------------------
/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/resume.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codebucks27/Next.js-Creative-Portfolio-Website/cff35d71760fe35797e675a15073d17307d81e72/public/resume.pdf
--------------------------------------------------------------------------------
/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/(sub pages)/about/page.js:
--------------------------------------------------------------------------------
1 | import Image from "next/image";
2 | import bg from "../../../../public/background/about-background.png";
3 | import RenderModel from "@/components/RenderModel";
4 | // import HatModel from "@/components/models/HatModel";
5 | import AboutDetails from "@/components/about";
6 | import dynamic from "next/dynamic";
7 | const HatModel = dynamic(() => import("@/components/models/HatModel"), {
8 | ssr: false,
9 | });
10 |
11 | export const metadata = {
12 | title: "About",
13 | };
14 |
15 | export default function Home() {
16 | return (
17 | <>
18 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | CodeBucks
36 |
37 |
38 | Meet the wizard behind this portfolio
39 |
40 |
41 |
42 |
43 |
44 | >
45 | );
46 | }
47 |
--------------------------------------------------------------------------------
/src/app/(sub pages)/contact/page.js:
--------------------------------------------------------------------------------
1 | import Image from "next/image";
2 | import bg from "../../../../public/background/contact-background.png";
3 | import Form from "@/components/contact/Form";
4 |
5 | export const metadata = {
6 | title: "Contact",
7 | };
8 |
9 | export default function Contact() {
10 | return (
11 | <>
12 |
19 |
20 |
21 |
22 |
23 | summon the wizard
24 |
25 |
26 | Step into the circle of enchantment and weave your words into the
27 | fabric of the cosmos. Whether you seek to conjure collaborations,
28 | unlock mysteries, or simply share tales of adventure, your messages
29 | are treasured scrolls within this realm. Use the form below to send
30 | your missives through the ethereal network, and await the whisper of
31 | magic in response.
32 |
33 |
34 |
35 |
36 | >
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/src/app/(sub pages)/layout.js:
--------------------------------------------------------------------------------
1 | import HomeBtn from "@/components/HomeBtn";
2 |
3 | export default function SubPagesLayout({ children }) {
4 | return (
5 |
6 |
7 | {children}
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/src/app/(sub pages)/projects/page.js:
--------------------------------------------------------------------------------
1 | import Image from "next/image";
2 | import bg from "../../../../public/background/projects-background.png";
3 | import ProjectList from "@/components/projects";
4 | import { projectsData } from "../../data";
5 | import RenderModel from "@/components/RenderModel";
6 | // import Staff from "@/components/models/Staff";
7 | import dynamic from "next/dynamic";
8 |
9 | const Staff = dynamic(() => import("@/components/models/Staff"), {
10 | ssr: false,
11 | });
12 |
13 | export const metadata = {
14 | title: "Projects",
15 | };
16 |
17 | export default function Home() {
18 | return (
19 | <>
20 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | >
36 | );
37 | }
38 |
--------------------------------------------------------------------------------
/src/app/data.js:
--------------------------------------------------------------------------------
1 | /*
2 | Websites:
3 |
4 | - https://github.com/pmndrs/gltfjsx (GLTF JSX for 3D Models)
5 | - https://lucide.dev/icons/ (Lucide Icons)
6 | - https://github.com/anuraghazra/github-readme-stats (Github Readme Stats)
7 | - https://skillicons.dev (Skill Icons to show skills)
8 | - https://github-readme-streak-stats.herokuapp.com (Github Readme Streak Stats)
9 |
10 | :root {
11 | --background: 27 27 27;
12 | --foreground: 225 225 225;
13 | --muted: 115 115 115;
14 | --accent: 254 254 91; #FEFE5B
15 | }
16 |
17 | */
18 |
19 | export const projectsData = [
20 | {
21 | id: 1,
22 | name: "EcoTracker",
23 | description: "Track your carbon footprint",
24 | date: "2022-08-15",
25 | demoLink: "https://ecotracker.example.com",
26 | },
27 | {
28 | id: 2,
29 | name: "ArtGallery Online",
30 | description: "Digital art showcase platform",
31 | date: "2022-06-20",
32 | demoLink: "https://artgalleryonline.example.com",
33 | },
34 | {
35 | id: 3,
36 | name: "BudgetPlanner",
37 | description: "Plan and track expenses",
38 | date: "2022-09-10",
39 | demoLink: "https://budgetplanner.example.com",
40 | },
41 | {
42 | id: 4,
43 | name: "HealthBeat",
44 | description: "Monitor heart rate zones",
45 | date: "2022-05-30",
46 | demoLink: "https://healthbeat.example.com",
47 | },
48 | {
49 | id: 5,
50 | name: "RecipeFinder",
51 | description: "Discover new recipes",
52 | date: "2022-07-12",
53 | demoLink: "https://recipefinder.example.com",
54 | },
55 | {
56 | id: 6,
57 | name: "JourneyLogger",
58 | description: "Log your travels",
59 | date: "2022-10-01",
60 | demoLink: "https://journeylogger.example.com",
61 | },
62 | {
63 | id: 7,
64 | name: "StudyBuddy",
65 | description: "Collaborative learning platform",
66 | date: "2022-04-18",
67 | demoLink: "https://studybuddy.example.com",
68 | },
69 | {
70 | id: 8,
71 | name: "TechTalk",
72 | description: "Tech news aggregator",
73 | date: "2022-11-05",
74 | demoLink: "https://techtalk.example.com",
75 | },
76 | {
77 | id: 9,
78 | name: "FitTrack",
79 | description: "Fitness and workout tracker",
80 | date: "2022-03-22",
81 | demoLink: "https://fittrack.example.com",
82 | },
83 | {
84 | id: 10,
85 | name: "MindfulMoments",
86 | description: "Meditation and mindfulness app",
87 | date: "2022-02-14",
88 | demoLink: "https://mindfulmoments.example.com",
89 | },
90 | ];
91 |
92 | export const BtnList = [
93 | { label: "Home", link: "/", icon: "home", newTab: false },
94 | { label: "About", link: "/about", icon: "about", newTab: false },
95 | { label: "Projects", link: "/projects", icon: "projects", newTab: false },
96 | { label: "Contact", link: "/contact", icon: "contact", newTab: false },
97 | {
98 | label: "Github",
99 | link: "https://www.github.com/codebucks27",
100 | icon: "github",
101 | newTab: true,
102 | },
103 | {
104 | label: "LinkedIn",
105 | link: "https://www.linkedin.com/in/codebucks",
106 | icon: "linkedin",
107 | newTab: true,
108 | },
109 | {
110 | label: "X",
111 | link: "https://www.x.com/code_bucks",
112 | icon: "twitter",
113 | newTab: true,
114 | },
115 | {
116 | label: "Resume",
117 | link: "/resume.pdf",
118 | icon: "resume",
119 | newTab: true,
120 | },
121 | ];
122 |
123 |
124 |
--------------------------------------------------------------------------------
/src/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codebucks27/Next.js-Creative-Portfolio-Website/cff35d71760fe35797e675a15073d17307d81e72/src/app/favicon.ico
--------------------------------------------------------------------------------
/src/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | @layer base {
6 | :root {
7 | --background: 27 27 27;
8 | --foreground: 225 225 225;
9 | --muted: 115 115 115;
10 | --accent: 254 254 91;
11 | /* hex value of rgb(254,254,91) color is #FEFE5B */
12 | }
13 | }
14 |
15 | @layer utilities {
16 | .pause {
17 | animation-play-state: paused;
18 | }
19 |
20 | .custom-bg {
21 | @apply bg-background/20 border border-accent/30 border-solid backdrop-blur-[6px] shadow-glass-inset hover:shadow-glass-sm;
22 | }
23 | }
24 |
25 | @keyframes move {
26 | 0% {
27 | transform: translate(0, 0);
28 | }
29 | 100% {
30 | transform: translate(100px, 100px);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/app/layout.js:
--------------------------------------------------------------------------------
1 | import { Inter } from "next/font/google";
2 | import "./globals.css";
3 | import clsx from "clsx";
4 | import FireFliesBackground from "@/components/FireFliesBackground";
5 | import Sound from "@/components/Sound";
6 |
7 | const inter = Inter({
8 | subsets: ["latin"],
9 | variable: "--font-inter",
10 | });
11 |
12 | export const metadata = {
13 | title: {
14 | template:
15 | "Next.js Portfolio Created with Three.js and Tailwind CSS | %s | CodeBucks",
16 | default:
17 | "Next.js Portfolio Created with Three.js and Tailwind CSS by CodeBucks",
18 | },
19 | description:
20 | "A unique creative portfolio designed by CodeBucks with cutting-edge technologies like Next.js, Tailwind CSS, Three.js, and Framer Motion. Experience the art of modern web development firsthand. Checkout CodeBucks on youtube.",
21 | };
22 |
23 | export default function RootLayout({ children }) {
24 | return (
25 |
26 |
32 | {children}
33 |
34 |
35 |
36 |
37 |
38 | );
39 | }
40 |
--------------------------------------------------------------------------------
/src/app/page.js:
--------------------------------------------------------------------------------
1 | import Image from "next/image";
2 | import bg from "../../public/background/home-background.png";
3 | import RenderModel from "@/components/RenderModel";
4 | // import Wizard from "@/components/models/Wizard";
5 | import Navigation from "@/components/navigation";
6 |
7 | import dynamic from "next/dynamic";
8 | const Wizard = dynamic(() => import("@/components/models/Wizard"), {
9 | ssr: false,
10 | });
11 |
12 | export default function Home() {
13 | return (
14 |
15 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | );
32 | }
33 |
--------------------------------------------------------------------------------
/src/components/FireFliesBackground.jsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import React, { useEffect, useState } from "react";
3 |
4 | const createFirefly = () => ({
5 | id: Math.random(),
6 | top: `${Math.random() * 100}%`,
7 | left: `${Math.random() * 100}%`,
8 | animationDuration: `${Math.random() * 5 + 5}s`,
9 | });
10 |
11 | const FireFliesBackground = () => {
12 | const [fireflies, setFireflies] = useState([]);
13 |
14 | useEffect(() => {
15 | const addFireflyPeriodically = () => {
16 | const newFirefly = createFirefly();
17 | setFireflies((currentFireflies) => [
18 | ...currentFireflies.slice(-14),
19 | newFirefly,
20 | ]);
21 | };
22 |
23 | const interval = setInterval(addFireflyPeriodically, 1000);
24 |
25 | return () => clearInterval(interval);
26 | }, []);
27 |
28 | return (
29 |
30 | {fireflies.map((firefly) => {
31 | return (
32 |
41 | );
42 | })}
43 |
44 | );
45 | };
46 |
47 | export default FireFliesBackground;
48 |
--------------------------------------------------------------------------------
/src/components/HomeBtn.jsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import { motion } from "framer-motion";
3 | import { Home } from "lucide-react";
4 | import Link from "next/link";
5 |
6 | const NavLink = motion(Link);
7 | const HomeBtn = () => {
8 | return (
9 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | Home
29 |
30 |
31 | Go to Home Page
32 |
33 | );
34 | };
35 |
36 | export default HomeBtn;
37 |
--------------------------------------------------------------------------------
/src/components/RenderModel.jsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import { Environment } from "@react-three/drei";
3 | import { Canvas } from "@react-three/fiber";
4 | import clsx from "clsx";
5 | import React, { Suspense } from "react";
6 |
7 | const RenderModel = ({ children, className }) => {
8 | return (
9 |
15 | {children}
16 |
17 |
18 | );
19 | };
20 |
21 | export default RenderModel;
22 |
--------------------------------------------------------------------------------
/src/components/ResponsiveComponent.jsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import React from "react";
4 | import useScreenSize from "./hooks/useScreenSize";
5 |
6 | const ResponsiveComponent = ({ children }) => {
7 | const size = useScreenSize();
8 |
9 | return <>{children({ size })}>;
10 | };
11 |
12 | export default ResponsiveComponent;
13 |
--------------------------------------------------------------------------------
/src/components/Sound.jsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import { motion } from "framer-motion";
3 | import { Volume2, VolumeX } from "lucide-react";
4 | import React, { useEffect, useRef, useState } from "react";
5 | import { createPortal } from "react-dom";
6 |
7 | const Modal = ({ onClose, toggle }) => {
8 | return createPortal(
9 |
10 |
15 |
Do you like to play the background music?
16 |
17 |
21 | Yes
22 |
23 |
27 | No
28 |
29 |
30 |
31 |
,
32 |
33 | document.getElementById("my-modal")
34 | );
35 | };
36 |
37 | const Sound = () => {
38 | const audioRef = useRef(null);
39 | const [isPlaying, setIsPlaying] = useState(false);
40 | const [showModal, setShowModal] = useState(false);
41 |
42 | const handleFirstUserInteraction = () => {
43 | const musicConsent = localStorage.getItem("musicConsent");
44 | if (musicConsent === "true" && !isPlaying) {
45 | audioRef.current.play();
46 | setIsPlaying(true);
47 | }
48 |
49 | ["click", "keydown", "touchstart"].forEach((event) =>
50 | document.removeEventListener(event, handleFirstUserInteraction)
51 | );
52 | };
53 |
54 | useEffect(() => {
55 | const consent = localStorage.getItem("musicConsent");
56 | const consentTime = localStorage.getItem("consentTime");
57 |
58 | if (
59 | consent &&
60 | consentTime &&
61 | new Date(consentTime).getTime() + 3 * 24 * 60 * 60 * 1000 > new Date()
62 | ) {
63 | setIsPlaying(consent === "true");
64 |
65 | if (consent === "true") {
66 | ["click", "keydown", "touchstart"].forEach((event) =>
67 | document.addEventListener(event, handleFirstUserInteraction)
68 | );
69 | }
70 | } else {
71 | setShowModal(true);
72 | }
73 | }, []);
74 |
75 | const toggle = () => {
76 | const newState = !isPlaying;
77 | setIsPlaying(!isPlaying);
78 | newState ? audioRef.current.play() : audioRef.current.pause();
79 | localStorage.setItem("musicConsent", String(newState));
80 | localStorage.setItem("consentTime", new Date().toISOString());
81 | setShowModal(false);
82 | };
83 | return (
84 |
85 | {showModal && (
86 |
setShowModal(false)} toggle={toggle} />
87 | )}
88 |
89 |
90 |
91 | your browser does not support the audio element.
92 |
93 |
102 | {isPlaying ? (
103 |
107 | ) : (
108 |
112 | )}
113 |
114 |
115 | );
116 | };
117 |
118 | export default Sound;
119 |
--------------------------------------------------------------------------------
/src/components/about/ItemLayout.jsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import { motion } from "framer-motion";
3 | import clsx from "clsx";
4 |
5 | const ItemLayout = ({ children, className }) => {
6 | return (
7 |
17 | {children}
18 |
19 | );
20 | };
21 |
22 | export default ItemLayout;
23 |
--------------------------------------------------------------------------------
/src/components/about/index.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ItemLayout from "./ItemLayout";
3 | import Link from "next/link";
4 |
5 | const AboutDetails = () => {
6 | return (
7 |
8 |
9 |
14 |
15 | Architect of Enchantment
16 |
17 |
18 | My journey in web development is powered by an array of mystical
19 | tools and languages, with JavaScript casting the core of my
20 | enchantments. I wield frameworks like React.js and Next.js with
21 | precision, crafting seamless portals (websites) that connect realms
22 | (users) across the digital universe. The ancient arts of the
23 | Jamstack empower me to create fast, secure, and dynamic experiences,
24 | while my design skills ensure every creation is not only functional
25 | but visually captivating. Join me as I continue to explore new
26 | spells and technologies to shape the future of the web.
27 |
28 |
29 |
30 |
33 |
34 | 25+ clients
35 |
36 |
37 |
38 |
41 |
42 | 4+{" "}
43 | years of experience
44 |
45 |
46 |
47 |
50 |
56 |
57 |
58 |
59 |
65 |
66 |
67 |
68 |
74 |
75 |
76 |
77 |
83 |
84 |
85 |
86 |
91 |
97 |
98 |
99 |
100 |
101 | );
102 | };
103 |
104 | export default AboutDetails;
105 |
--------------------------------------------------------------------------------
/src/components/contact/Form.jsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import React from "react";
3 | import { useForm } from "react-hook-form";
4 | import emailjs from "@emailjs/browser";
5 | import { Toaster, toast } from "sonner";
6 | import { motion } from "framer-motion";
7 |
8 | const container = {
9 | hidden: { opacity: 0 },
10 | show: {
11 | opacity: 1,
12 | transition: {
13 | staggerChildren: 0.3,
14 | delayChildren: 0.2,
15 | },
16 | },
17 | };
18 |
19 | const item = {
20 | hidden: { scale: 0 },
21 | show: { scale: 1 },
22 | };
23 |
24 | export default function Form() {
25 | const {
26 | register,
27 | handleSubmit,
28 | formState: { errors },
29 | } = useForm();
30 |
31 | const sendEmail = (params) => {
32 | const toastId = toast.loading("Sending your message, please wait...");
33 |
34 | toast.info(
35 | "Form submissions are demo-only here. Please checkout the final code repo to enable it. If you want to connect you can reach out to me via codebucks27@gmail.com.",
36 | {
37 | id: toastId,
38 | }
39 | );
40 |
41 | // comment out the above toast.info and uncomment the below code to enable emailjs
42 |
43 | // emailjs
44 | // .send(
45 | // process.env.NEXT_PUBLIC_SERVICE_ID,
46 | // process.env.NEXT_PUBLIC_TEMPLATE_ID,
47 | // params,
48 | // {
49 | // publicKey: process.env.NEXT_PUBLIC_PUBLIC_KEY,
50 | // limitRate: {
51 | // throttle: 5000, // you can not send more then 1 email per 5 seconds
52 | // },
53 | // }
54 | // )
55 | // .then(
56 | // () => {
57 | // toast.success(
58 | // "I have received your message, I will get back to you soon!",
59 | // {
60 | // id: toastId,
61 | // }
62 | // );
63 | // },
64 | // (error) => {
65 | // // console.log("FAILED...", error.text);
66 | // toast.error(
67 | // "There was an error sending your message, please try again later!",
68 | // {
69 | // id: toastId,
70 | // }
71 | // );
72 | // }
73 | // );
74 | };
75 |
76 | const onSubmit = (data) => {
77 | const templateParams = {
78 | to_name: "CodeBucks",
79 | from_name: data.name,
80 | reply_to: data.email,
81 | message: data.message,
82 | };
83 |
84 | sendEmail(templateParams);
85 | };
86 |
87 | return (
88 | <>
89 |
90 |
97 |
110 | {errors.name && (
111 |
112 | {errors.name.message}
113 |
114 | )}
115 |
122 | {errors.email && (
123 |
124 | {errors.email.message}
125 |
126 | )}
127 |
143 | {errors.message && (
144 |
145 | {errors.message.message}
146 |
147 | )}
148 |
149 |
157 |
158 | >
159 | );
160 | }
161 |
--------------------------------------------------------------------------------
/src/components/hooks/useScreenSize.jsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { useEffect, useState } from "react";
4 |
5 | const useScreenSize = () => {
6 | const [screenSize, setScreenSize] = useState();
7 |
8 | useEffect(() => {
9 | function getScreenSize() {
10 | return window.innerWidth;
11 | }
12 |
13 | function handleResize() {
14 | setScreenSize(getScreenSize());
15 | }
16 |
17 | handleResize();
18 |
19 | window.addEventListener("resize", handleResize);
20 |
21 | return () => window.removeEventListener("resize", handleResize);
22 | }, []);
23 |
24 | return screenSize;
25 | };
26 |
27 | export default useScreenSize;
28 |
--------------------------------------------------------------------------------
/src/components/models/HatModel.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | Auto-generated by: https://github.com/pmndrs/gltfjsx
3 | */
4 | "use client";
5 | import React, { useRef } from "react";
6 | import { useGLTF } from "@react-three/drei";
7 | import { useFrame } from "@react-three/fiber";
8 |
9 | const HatModel = React.memo(function HatModel(props) {
10 | // Use React.memo for performance optimization
11 | const { nodes, materials } = useGLTF("/models/hat-transformed.glb");
12 |
13 | const modelRef = useRef();
14 |
15 | useFrame(() => {
16 | modelRef.current.rotation.y += 0.007;
17 | });
18 | return (
19 |
27 |
35 |
36 | );
37 | });
38 |
39 | export default HatModel;
40 | useGLTF.preload("/models/hat-transformed.glb");
41 |
--------------------------------------------------------------------------------
/src/components/models/Staff.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | Auto-generated by: https://github.com/pmndrs/gltfjsx
3 | */
4 | "use client";
5 | import React, { useRef } from "react";
6 | import { useGLTF } from "@react-three/drei";
7 | import { useFrame } from "@react-three/fiber";
8 |
9 | const Staff = React.memo(function Staff(props) {
10 | // Use React.memo for performance optimization
11 | const { nodes, materials } = useGLTF("/models/staff-transformed.glb");
12 | const modelRef = useRef();
13 |
14 | useFrame(() => {
15 | modelRef.current.rotation.y += 0.007;
16 | });
17 |
18 | return (
19 |
26 |
35 |
44 |
53 |
62 |
71 |
72 | );
73 | });
74 |
75 | export default Staff;
76 | useGLTF.preload("/models/staff-transformed.glb");
77 |
--------------------------------------------------------------------------------
/src/components/models/Wizard.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | Auto-generated by: https://github.com/pmndrs/gltfjsx
3 | */
4 | "use client";
5 | import React, { useRef } from "react";
6 | import { useGLTF } from "@react-three/drei";
7 | import { useFrame } from "@react-three/fiber";
8 |
9 | const Wizard = React.memo(function Wizard(props) {
10 | // Use React.memo for performance optimization
11 | const { nodes, materials } = useGLTF("/models/wizard-transformed.glb");
12 |
13 | const modelRef = useRef();
14 |
15 | useFrame((state) => {
16 | modelRef.current.position.y =
17 | -1.5 + Math.sin(state.clock.elapsedTime) * 0.15;
18 | });
19 |
20 | return (
21 |
29 |
38 |
47 |
56 |
65 |
74 |
83 |
92 |
101 |
110 |
119 |
128 |
137 |
146 |
155 |
164 |
173 |
182 |
191 |
200 |
209 |
210 | );
211 | });
212 |
213 | export default Wizard;
214 | useGLTF.preload("/models/wizard-transformed.glb");
215 |
--------------------------------------------------------------------------------
/src/components/navigation/NavButton.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | Github,
3 | Home,
4 | Linkedin,
5 | NotebookText,
6 | Palette,
7 | Phone,
8 | Twitter,
9 | User,
10 | } from "lucide-react";
11 | import Link from "next/link";
12 | import React from "react";
13 | import ResponsiveComponent from "../ResponsiveComponent";
14 | import clsx from "clsx";
15 | import { motion } from "framer-motion";
16 |
17 | const getIcon = (icon) => {
18 | switch (icon) {
19 | case "home":
20 | return ;
21 | case "about":
22 | return ;
23 | case "projects":
24 | return ;
25 | case "contact":
26 | return ;
27 | case "github":
28 | return ;
29 | case "linkedin":
30 | return ;
31 | case "twitter":
32 | return ;
33 | case "resume":
34 | return ;
35 |
36 | default:
37 | return ;
38 | }
39 | };
40 |
41 | const item = {
42 | hidden: { scale: 0 },
43 | show: { scale: 1 },
44 | };
45 |
46 | const NavLink = motion(Link);
47 |
48 | const NavButton = ({
49 | x,
50 | y,
51 | label,
52 | link,
53 | icon,
54 | newTab,
55 | labelDirection = "right",
56 | }) => {
57 | return (
58 |
59 | {({ size }) => {
60 | return size && size >= 480 ? (
61 |
65 |
77 |
78 | {getIcon(icon)}
79 |
80 |
81 |
82 |
83 | {label}
84 |
85 |
86 |
87 |
88 | ) : (
89 |
90 |
102 |
103 | {getIcon(icon)}
104 |
105 |
106 |
107 |
113 | {label}
114 |
115 |
116 |
117 |
118 | );
119 | }}
120 |
121 | );
122 | };
123 |
124 | export default NavButton;
125 |
--------------------------------------------------------------------------------
/src/components/navigation/index.jsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import { BtnList } from "@/app/data";
3 | import React from "react";
4 | import NavButton from "./NavButton";
5 | import useScreenSize from "../hooks/useScreenSize";
6 | import ResponsiveComponent from "../ResponsiveComponent";
7 | import { motion } from "framer-motion";
8 |
9 | const container = {
10 | hidden: { opacity: 0 },
11 | show: {
12 | opacity: 1,
13 | transition: {
14 | staggerChildren: 0.3,
15 | },
16 | },
17 | };
18 |
19 | const Navigation = () => {
20 | const angleIncrement = 360 / BtnList.length;
21 | const size = useScreenSize();
22 | const isLarge = size >= 1024;
23 | const isMedium = size >= 768;
24 |
25 | return (
26 |
27 |
28 | {({ size }) => {
29 | return size && size >= 480 ? (
30 |
36 | {BtnList.map((btn, index) => {
37 | const angleRad = (index * angleIncrement * Math.PI) / 180;
38 | const radius = isLarge
39 | ? "calc(20vw - 1rem)"
40 | : isMedium
41 | ? "calc(30vw - 1rem)"
42 | : "calc(40vw - 1rem)";
43 | const x = `calc(${radius}*${Math.cos(angleRad)})`;
44 | const y = `calc(${radius}*${Math.sin(angleRad)})`;
45 |
46 | return ;
47 | })}
48 |
49 | ) : (
50 | <>
51 |
57 | {BtnList.slice(0, BtnList.length / 2).map((btn) => {
58 | return ;
59 | })}
60 |
61 |
62 |
68 | {BtnList.slice(BtnList.length / 2, BtnList.length).map(
69 | (btn) => {
70 | return (
71 |
78 | );
79 | }
80 | )}
81 |
82 | >
83 | );
84 | }}
85 |
86 |
87 | );
88 | };
89 |
90 | export default Navigation;
91 |
--------------------------------------------------------------------------------
/src/components/projects/ProjectLayout.jsx:
--------------------------------------------------------------------------------
1 | import { motion } from "framer-motion";
2 | import Link from "next/link";
3 |
4 | const item = {
5 | hidden: { opacity: 0, y: 100 },
6 | show: { opacity: 1, y: 0 },
7 | };
8 |
9 | const ProjectLink = motion(Link);
10 | const ProjectLayout = ({ name, description, date, demoLink }) => {
11 | return (
12 |
18 |
19 |
{name}
20 |
{description}
21 |
22 |
23 |
24 | {new Date(date).toDateString()}
25 |
26 |
27 | );
28 | };
29 |
30 | export default ProjectLayout;
31 |
--------------------------------------------------------------------------------
/src/components/projects/index.jsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import { motion } from "framer-motion";
3 | import ProjectLayout from "./ProjectLayout";
4 |
5 | const container = {
6 | hidden: { opacity: 0 },
7 | show: {
8 | opacity: 1,
9 | transition: {
10 | staggerChildren: 0.3,
11 | delayChildren: 1.5,
12 | },
13 | },
14 | };
15 |
16 | const ProjectList = ({ projects }) => {
17 | return (
18 |
24 | {projects.map((project, index) => {
25 | return ;
26 | })}
27 |
28 | );
29 | };
30 |
31 | export default ProjectList;
32 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
5 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
6 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
7 | ],
8 | theme: {
9 | extend: {
10 | fontFamily:{
11 | inter: ['var(--font-inter)']
12 | },
13 | colors:{
14 | background: 'rgb(var(--background))',
15 | foreground: 'rgb(var(--foreground))',
16 | muted: 'rgb(var(--muted))',
17 | accent: 'rgb(var(--accent))',
18 | },
19 | backgroundImage:{
20 | 'firefly-radial': "radial-gradient(50% 50% at 50% 50%, rgba(253, 255, 80, 0.5) 0%, rgba(217,217,217, 0) 100%)"
21 | },
22 | boxShadow:{
23 | 'glass-inset': 'inset 0 17px 5px -9px rgba(254,254,91, 0.05)',
24 | 'glass-sm': '5px 5px 20px 0px rgba(254,254,91, 0.3)',
25 | },
26 | keyframes:{
27 | 'spin-reverse':{
28 | '0%': {transform: 'rotate(0deg)'},
29 | '100%': {transform: 'rotate(-360deg)'}
30 | }
31 | },
32 | animation:{
33 | 'spin-slow': 'spin 40s linear infinite',
34 | 'spin-slow-reverse': 'spin-reverse 40s linear infinite',
35 | },
36 | screens:{
37 | xs: '480px',
38 | }
39 | },
40 | },
41 | plugins: [],
42 | };
43 |
--------------------------------------------------------------------------------