diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/App.tsx b/App.tsx new file mode 100644 index 0000000..1fcd6c3 --- /dev/null +++ b/App.tsx @@ -0,0 +1,29 @@ +import React, { useState } from 'react'; +import Navbar from './components/Navbar'; +import Hero from './components/Hero'; +import Projects from './components/Projects'; +import About from './components/About'; +import Footer from './components/Footer'; +import LoadingScreen from './components/LoadingScreen'; + +const App: React.FC = () => { + const [isLoading, setIsLoading] = useState(true); + + return ( + <> + {isLoading && setIsLoading(false)} />} + +
+ {}} isDark={false} /> +
+ + + +
+
+
+ + ); +}; + +export default App; \ No newline at end of file diff --git a/README.md b/README.md index 2241000..5affe33 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,20 @@
- GHBanner - -

Built with AI Studio

- -

The fastest path from prompt to production with Gemini.

- - Start building -
+ +# Run and deploy your AI Studio app + +This contains everything you need to run your app locally. + +View your app in AI Studio: https://ai.studio/apps/drive/1TiMFoAG3MlNJvKqVz68y71I_K1ca--la + +## Run Locally + +**Prerequisites:** Node.js + + +1. Install dependencies: + `npm install` +2. Set the `GEMINI_API_KEY` in [.env.local](.env.local) to your Gemini API key +3. Run the app: + `npm run dev` diff --git a/components/About.tsx b/components/About.tsx new file mode 100644 index 0000000..d63296c --- /dev/null +++ b/components/About.tsx @@ -0,0 +1,84 @@ +import React from 'react'; +import { FileCode2, Terminal, Database, Server, GitBranch, Layout } from 'lucide-react'; + +const TECH_STACKS = [ + { + name: 'TypeScript', + desc: 'Strict syntactical superset of JavaScript', + icon: FileCode2 + }, + { + name: 'Python', + desc: 'Data structures, scripting & automation', + icon: Terminal + }, + { + name: 'MySQL', + desc: 'Relational database management', + icon: Database + }, + { + name: 'Node.js', + desc: 'Server-side JavaScript runtime', + icon: Server + }, + { + name: 'Git', + desc: 'Version control & collaboration', + icon: GitBranch + }, + { + name: 'HTML5', + desc: 'Semantic web markup & accessibility', + icon: Layout + } +]; + +const About: React.FC = () => { + return ( +
+
+ + {/* Left Column: Bio - Vertically Centered */} +
+

+ Why m5rcel? +

+
+ m4rcel-lol Avatar +
+

+ It’s not just about writing code. It’s about creating an experience that feels magical. From the moment the page loads, everything should feel responsive, fluid, and intuitive. +

+

+ I specialize in creating pixel-perfect interfaces that pay homage to the golden era of design while utilizing the raw power of modern web technologies. +

+
+
+
+ + {/* Right Column: Skills (Sidebar style) */} +
+

Tech Stacks

+ +
    + {TECH_STACKS.map((tech, i) => ( +
  • +
    + +
    +
    +
    {tech.name}
    +
    {tech.desc}
    +
    +
  • + ))} +
+
+ +
+
+ ); +}; + +export default About; \ No newline at end of file diff --git a/components/Footer.tsx b/components/Footer.tsx new file mode 100644 index 0000000..c7f0b7d --- /dev/null +++ b/components/Footer.tsx @@ -0,0 +1,17 @@ +import React from 'react'; + +const Footer: React.FC = () => { + return ( + + ); +}; + +export default Footer; \ No newline at end of file diff --git a/components/Hero.tsx b/components/Hero.tsx new file mode 100644 index 0000000..ec1a379 --- /dev/null +++ b/components/Hero.tsx @@ -0,0 +1,77 @@ +import React from 'react'; +import { motion } from 'framer-motion'; + +const Hero: React.FC = () => { + return ( +
+ {/* 2009 Layout: Fixed width centered */} +
+ + {/* Main Headline - Myriad Pro style */} + + m5rcel. + + + {/* Subheadline */} + + The developer that likes to do stuff out of boredom. + + + {/* Product Hero Image with Reflection */} + +
+ Hero Product +
+
+ + {/* The Classic "Aqua" Buttons */} +
+ + {/* Glossy Button Container */} +
+ + Contact Me + +
+
+ + + {/* Silver Button Container */} +
+ + See GitHub + +
+
+
+ + {/* Small legal text typical of ads */} +

+ Requires an internet connection. Battery life varies by use and configuration. +

+ +
+
+ ); +}; + +export default Hero; \ No newline at end of file diff --git a/components/LoadingScreen.tsx b/components/LoadingScreen.tsx new file mode 100644 index 0000000..2f1e21a --- /dev/null +++ b/components/LoadingScreen.tsx @@ -0,0 +1,32 @@ +import React, { useEffect } from 'react'; +import { Apple } from 'lucide-react'; + +interface LoadingScreenProps { + onComplete: () => void; +} + +const LoadingScreen: React.FC = ({ onComplete }) => { + useEffect(() => { + // Simulate classic boot time + const timer = setTimeout(() => { + onComplete(); + }, 2000); + return () => clearTimeout(timer); + }, [onComplete]); + + return ( +
+ {/* Mac OS X Boot Logo */} +
+ +
+ + {/* Classic Mac Spinner */} +
+
+
+
+ ); +}; + +export default LoadingScreen; \ No newline at end of file diff --git a/components/Navbar.tsx b/components/Navbar.tsx new file mode 100644 index 0000000..05670f0 --- /dev/null +++ b/components/Navbar.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { Apple } from 'lucide-react'; + +interface NavbarProps { + toggleTheme: () => void; + isDark: boolean; +} + +const Navbar: React.FC = () => { + return ( + + ); +}; + +export default Navbar; \ No newline at end of file diff --git a/components/Projects.tsx b/components/Projects.tsx new file mode 100644 index 0000000..d12dbf5 --- /dev/null +++ b/components/Projects.tsx @@ -0,0 +1,84 @@ +import React from 'react'; +import { PROJECTS } from '../constants'; + +const Projects: React.FC = () => { + return ( +
+
+ + {/* Section Header */} +
+

+ Built for performance. +

+

+ Thousands of lines of code. Zero compromise. +

+
+ + {/* 2009 Grid Layout */} +
+ {PROJECTS.map((project) => ( +
+ {/* Image Box */} +
+ {project.title} + {/* Gloss Overlay */} +
+
+ + {/* Content */} +

+ {project.title} + + {/* Fedora SVG */} + {project.id === 'fedora-bytebeat' && ( + + + + )} + + {/* Python SVG */} + {['m5rcode', 'bytebeat-win', 'fedora-bytebeat'].includes(project.id) && ( + + + + + + )} + + {/* Vercel SVG */} + {project.id === 'geminicord' && ( + + + + )} +

+

+ {project.description} +

+ + + Learn more + +
+ ))} +
+
+
+ ); +}; + +export default Projects; \ No newline at end of file diff --git a/constants.ts b/constants.ts new file mode 100644 index 0000000..8f48118 --- /dev/null +++ b/constants.ts @@ -0,0 +1,84 @@ +import { Project, TimelineItem } from './types'; + +// Apple's "Emphasized" easing +export const EASE_APPLE = [0.2, 0, 0, 1]; + +export const PROJECTS: Project[] = [ + { + id: 'm5rcode', + title: 'm5rcode', + category: 'Language Design', + description: 'Experimental polyglot programming language written with a blend of Python, JavaScript, PHP, C#, and C++.', + image: 'https://picsum.photos/seed/m5rcode/800/600', + tags: ['C++', 'Python', 'Compiler'], + githubUrl: 'https://github.com/m4rcel-lol/m5rcode', + featured: true, + }, + { + id: 'geminicord', + title: 'Geminicord', + category: 'AI Web Application', + description: "Pixel-perfect recreation of the modern Discord UI, powered by Google's Gemini AI.", + image: 'https://picsum.photos/seed/geminicord/800/600', + tags: ['React', 'Gemini API', 'UI Clone'], + githubUrl: 'https://github.com/m4rcel-lol/custom-discord-ai-chatbot-site', + featured: true, + }, + { + id: 'bytebeat-win', + title: 'Python Bytebeat Player', + category: 'Audio Software', + description: 'Play Bytebeat sequences on PC using Python.', + image: 'https://picsum.photos/seed/bytebeat1/800/600', + tags: ['Python', 'Audio Synthesis'], + githubUrl: 'https://github.com/m4rcel-lol/python-bytebeat-player', + }, + { + id: 'fedora-bytebeat', + title: 'Python Bytebeat Player', + category: 'Linux Audio', + description: 'Play Bytebeat sequences on PC using Python, but on linux.', + image: 'https://picsum.photos/seed/fedora/800/600', + tags: ['Python', 'Linux', 'Fedora'], + githubUrl: 'https://github.com/m4rcel-lol/fedora-bytebeat-player', + }, +]; + +export const TIMELINE: TimelineItem[] = [ + { + year: '2024', + title: 'Senior Frontend Engineer', + description: 'Leading UI architecture for next-gen consumer products.', + }, + { + year: '2022', + title: 'Creative Developer', + description: 'Bridging the gap between design and engineering with motion-heavy interfaces.', + }, + { + year: '2020', + title: 'Open Source Contributor', + description: 'Started journey contributing to major UI libraries.', + }, +]; + +// Animation Variants +export const fadeInUp = { + hidden: { opacity: 0, y: 40 }, + visible: { + opacity: 1, + y: 0, + transition: { duration: 0.8, ease: EASE_APPLE } + } +}; + +export const staggerContainer = { + hidden: { opacity: 0 }, + visible: { + opacity: 1, + transition: { + staggerChildren: 0.1, + delayChildren: 0.2 + } + } +}; \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..6228702 --- /dev/null +++ b/index.html @@ -0,0 +1,97 @@ + + + + + + m5rcel - Developer & Designer + + + + + + + +
+ + \ No newline at end of file diff --git a/index.tsx b/index.tsx new file mode 100644 index 0000000..39e1012 --- /dev/null +++ b/index.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App'; + +const rootElement = document.getElementById('root'); +if (!rootElement) { + throw new Error("Could not find root element to mount to"); +} + +const root = ReactDOM.createRoot(rootElement); +root.render( + + + +); diff --git a/metadata.json b/metadata.json new file mode 100644 index 0000000..bd39d02 --- /dev/null +++ b/metadata.json @@ -0,0 +1,5 @@ +{ + "name": "m5rcel Portfolio", + "description": "A premium, Apple-styled personal portfolio website for m5rcel, featuring cinematic animations and clean typography.", + "requestFramePermissions": [] +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..3625c5d --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "m5rcel-portfolio", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "react": "^19.2.1", + "react-dom": "^19.2.1", + "framer-motion": "^12.23.25", + "lucide-react": "^0.556.0" + }, + "devDependencies": { + "@types/node": "^22.14.0", + "@vitejs/plugin-react": "^5.0.0", + "typescript": "~5.8.2", + "vite": "^6.2.0" + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..2c6eed5 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "ES2022", + "experimentalDecorators": true, + "useDefineForClassFields": false, + "module": "ESNext", + "lib": [ + "ES2022", + "DOM", + "DOM.Iterable" + ], + "skipLibCheck": true, + "types": [ + "node" + ], + "moduleResolution": "bundler", + "isolatedModules": true, + "moduleDetection": "force", + "allowJs": true, + "jsx": "react-jsx", + "paths": { + "@/*": [ + "./*" + ] + }, + "allowImportingTsExtensions": true, + "noEmit": true + } +} \ No newline at end of file diff --git a/types.ts b/types.ts new file mode 100644 index 0000000..52369d9 --- /dev/null +++ b/types.ts @@ -0,0 +1,22 @@ +export interface Project { + id: string; + title: string; + category: string; + description: string; + image: string; + tags: string[]; + githubUrl: string; + demoUrl?: string; + featured?: boolean; +} + +export interface Skill { + name: string; + icon: string; +} + +export interface TimelineItem { + year: string; + title: string; + description: string; +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..ee5fb8d --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,23 @@ +import path from 'path'; +import { defineConfig, loadEnv } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig(({ mode }) => { + const env = loadEnv(mode, '.', ''); + return { + server: { + port: 3000, + host: '0.0.0.0', + }, + plugins: [react()], + define: { + 'process.env.API_KEY': JSON.stringify(env.GEMINI_API_KEY), + 'process.env.GEMINI_API_KEY': JSON.stringify(env.GEMINI_API_KEY) + }, + resolve: { + alias: { + '@': path.resolve(__dirname, '.'), + } + } + }; +});