init
This commit is contained in:
+24
@@ -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?
|
||||
@@ -0,0 +1,215 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Language } from './types';
|
||||
import { RESUME_DATA } from './constants';
|
||||
import LanguageToggle from './components/LanguageToggle';
|
||||
import Section from './components/Section';
|
||||
import ExperienceList from './components/ExperienceList';
|
||||
import ProjectCard from './components/ProjectCard';
|
||||
import { Mail, Phone, MessageSquare, Download, Linkedin, GraduationCap, Code2, ChevronDown, Award, Globe2 } from 'lucide-react';
|
||||
|
||||
const App: React.FC = () => {
|
||||
const [lang, setLang] = useState<Language>('zh');
|
||||
|
||||
const { name, title, summary, contact, skills, experience, projects, education } = RESUME_DATA;
|
||||
|
||||
// Background images from Unsplash
|
||||
const heroBgImage = "https://images.unsplash.com/photo-1519389950473-47ba0277781c?q=80&w=2670&auto=format&fit=crop";
|
||||
const footerBgImage = "https://images.unsplash.com/photo-1451187580459-43490279c0fa?q=80&w=2000&auto=format&fit=crop";
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex flex-col font-sans bg-slate-50 text-slate-900 selection:bg-indigo-100 selection:text-indigo-900">
|
||||
{/* Navigation / Header */}
|
||||
<header className="fixed top-0 w-full z-50 bg-white/80 backdrop-blur-md border-b border-white/20 shadow-sm transition-all supports-[backdrop-filter]:bg-white/60">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 h-16 flex items-center justify-between">
|
||||
<div className="font-bold text-xl tracking-tight text-slate-900 flex items-center gap-2">
|
||||
<div className="w-9 h-9 bg-gradient-to-br from-indigo-600 to-blue-500 rounded-lg flex items-center justify-center text-white font-bold text-sm shadow-lg shadow-indigo-200">
|
||||
{name['en'].split(' ')[0][0]}
|
||||
</div>
|
||||
<span className="hidden sm:block">{lang === 'en' ? 'Resume' : '个人简历'}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-3 sm:gap-6">
|
||||
<nav className="hidden md:flex gap-8 text-sm font-semibold text-slate-600">
|
||||
<a href="#about" className="hover:text-indigo-600 transition-colors">{lang === 'en' ? 'About' : '简介'}</a>
|
||||
<a href="#experience" className="hover:text-indigo-600 transition-colors">{lang === 'en' ? 'Experience' : '经历'}</a>
|
||||
<a href="#projects" className="hover:text-indigo-600 transition-colors">{lang === 'en' ? 'Projects' : '项目'}</a>
|
||||
</nav>
|
||||
<div className="h-5 w-px bg-slate-300 hidden md:block"></div>
|
||||
|
||||
<button className="hidden sm:flex items-center gap-2 px-4 py-2 text-sm font-medium text-white bg-slate-900 rounded-full hover:bg-slate-800 transition-colors shadow-md">
|
||||
<Download size={14} />
|
||||
<span>{lang === 'en' ? 'Download PDF' : '下载简历'}</span>
|
||||
</button>
|
||||
<LanguageToggle lang={lang} setLang={setLang} />
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Hero Section with Rich Background Image */}
|
||||
<main className="flex-grow pt-16">
|
||||
<div id="about" className="relative h-[85vh] min-h-[600px] flex items-center justify-center overflow-hidden">
|
||||
{/* Background Image */}
|
||||
<div
|
||||
className="absolute inset-0 z-0 bg-cover bg-center bg-no-repeat bg-fixed"
|
||||
style={{ backgroundImage: `url(${heroBgImage})` }}
|
||||
></div>
|
||||
|
||||
{/* Overlay - White gradient for clean text readability */}
|
||||
<div className="absolute inset-0 z-10 bg-gradient-to-b from-white/95 via-white/80 to-slate-50/95"></div>
|
||||
|
||||
<div className="relative z-20 max-w-4xl mx-auto text-center px-4">
|
||||
<div className="animate-fade-in-up">
|
||||
<div className="inline-flex items-center gap-2 px-4 py-1.5 rounded-full bg-white/50 backdrop-blur-md text-indigo-700 text-sm font-bold mb-8 border border-indigo-100 shadow-sm ring-1 ring-indigo-50">
|
||||
<span className="relative flex h-2 w-2">
|
||||
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-indigo-400 opacity-75"></span>
|
||||
<span className="relative inline-flex rounded-full h-2 w-2 bg-indigo-500"></span>
|
||||
</span>
|
||||
<span>{lang === 'en' ? 'Available for new opportunities' : '正在寻找新机会'}</span>
|
||||
</div>
|
||||
|
||||
<h1 className="text-5xl md:text-7xl lg:text-8xl font-black text-slate-900 tracking-tight mb-6 leading-[1.1]">
|
||||
{name[lang]}
|
||||
</h1>
|
||||
|
||||
<p className="text-xl md:text-3xl text-transparent bg-clip-text bg-gradient-to-r from-indigo-600 to-blue-500 font-bold mb-8">
|
||||
{title[lang]}
|
||||
</p>
|
||||
|
||||
<p className="text-lg md:text-xl text-slate-600 max-w-2xl mx-auto leading-relaxed mb-10 font-medium">
|
||||
{summary[lang]}
|
||||
</p>
|
||||
|
||||
{/* Contact Buttons */}
|
||||
<div className="flex flex-wrap justify-center gap-4">
|
||||
<a href={`tel:${contact.mobile}`} className="flex items-center gap-3 bg-slate-900 text-white px-8 py-4 rounded-full shadow-lg shadow-indigo-200 hover:shadow-xl hover:-translate-y-1 transition-all font-semibold">
|
||||
<Phone size={18} />
|
||||
<span>{contact.mobile}</span>
|
||||
</a>
|
||||
<a href={`mailto:${contact.email}`} className="flex items-center gap-3 bg-white text-slate-700 px-8 py-4 rounded-full shadow-md border border-slate-100 hover:border-indigo-200 hover:shadow-lg hover:-translate-y-1 transition-all font-semibold">
|
||||
<Mail size={18} />
|
||||
<span>{contact.email}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Scroll Indicator */}
|
||||
<div className="absolute bottom-10 left-1/2 -translate-x-1/2 animate-bounce text-slate-400 z-20">
|
||||
<ChevronDown size={32} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Skills Section (Dark Band) */}
|
||||
<div className="bg-slate-900 text-white py-20 relative overflow-hidden">
|
||||
{/* Abstract BG pattern */}
|
||||
<div className="absolute inset-0 opacity-10" style={{ backgroundImage: "radial-gradient(#4f46e5 1px, transparent 1px)", backgroundSize: "32px 32px" }}></div>
|
||||
|
||||
<div className="max-w-6xl mx-auto px-4 sm:px-6 relative z-10">
|
||||
<div className="text-center mb-12">
|
||||
<h3 className="text-indigo-400 font-bold uppercase tracking-widest text-sm mb-3">
|
||||
{lang === 'en' ? 'Technical Expertise' : '技能特长'}
|
||||
</h3>
|
||||
<h2 className="text-3xl md:text-4xl font-bold text-white">
|
||||
{lang === 'en' ? 'Core Competencies' : '核心技术栈'}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap justify-center gap-3 md:gap-5">
|
||||
{skills.map((skill, idx) => (
|
||||
<div key={idx} className="group px-6 py-3 bg-white/5 hover:bg-white/10 rounded-xl border border-white/10 hover:border-indigo-500/50 backdrop-blur-sm transition-all cursor-default flex items-center gap-3">
|
||||
<div className="w-1.5 h-1.5 rounded-full bg-indigo-500 group-hover:bg-indigo-400 transition-colors"></div>
|
||||
<span className="text-slate-200 font-medium text-base md:text-lg">{skill[lang]}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Experience Section */}
|
||||
<Section id="experience" title={lang === 'en' ? 'Work Experience' : '工作经历'} className="bg-slate-50">
|
||||
<ExperienceList experience={experience} lang={lang} />
|
||||
</Section>
|
||||
|
||||
{/* Projects Section */}
|
||||
<Section id="projects" title={lang === 'en' ? 'Featured Projects' : '个人作品'} className="bg-white">
|
||||
<div className="grid md:grid-cols-2 gap-8 lg:gap-12">
|
||||
{projects.map((project, index) => (
|
||||
<ProjectCard key={index} project={project} lang={lang} />
|
||||
))}
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
{/* Education Section */}
|
||||
<Section id="education" title={lang === 'en' ? 'Education' : '教育经历'} className="bg-slate-50">
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
{education.map((edu, index) => (
|
||||
<div key={index} className="bg-white p-8 rounded-2xl shadow-sm border border-slate-100 flex items-start gap-6 hover:shadow-md transition-all group">
|
||||
<div className="w-14 h-14 bg-indigo-50 rounded-2xl flex items-center justify-center text-indigo-600 shrink-0 group-hover:scale-110 group-hover:bg-indigo-600 group-hover:text-white transition-all duration-300">
|
||||
<GraduationCap size={32} />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-bold text-xl text-slate-900">{edu.school[lang]}</h3>
|
||||
<p className="text-indigo-600 font-semibold mb-2 text-lg">{edu.major[lang]}</p>
|
||||
<div className="flex flex-wrap items-center gap-3 text-sm text-slate-500 font-medium">
|
||||
<span className="bg-slate-100 px-3 py-1 rounded-full text-slate-600">{edu.degree[lang]}</span>
|
||||
<span className="hidden sm:inline text-slate-300">•</span>
|
||||
<span>{edu.period}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
{/* Contact / Footer CTA Area */}
|
||||
<div className="relative py-24 flex items-center justify-center bg-slate-900 overflow-hidden">
|
||||
<div
|
||||
className="absolute inset-0 z-0 bg-cover bg-center opacity-20"
|
||||
style={{ backgroundImage: `url(${footerBgImage})` }}
|
||||
></div>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-slate-900 via-slate-900/80 to-transparent"></div>
|
||||
|
||||
<div className="relative z-10 text-center px-4 max-w-3xl mx-auto">
|
||||
<h2 className="text-3xl md:text-5xl font-bold text-white mb-6">
|
||||
{lang === 'en' ? 'Let\'s work together' : '期待与您的合作'}
|
||||
</h2>
|
||||
<p className="text-slate-300 text-lg mb-10 leading-relaxed">
|
||||
{lang === 'en'
|
||||
? 'I am currently open to new opportunities in autonomous driving, simulation, and game development.'
|
||||
: '我目前正在寻找自动驾驶、仿真及游戏开发领域的新机会。'}
|
||||
</p>
|
||||
<div className="flex flex-col sm:flex-row items-center justify-center gap-4">
|
||||
<a href={`mailto:${contact.email}`} className="w-full sm:w-auto px-8 py-4 bg-indigo-600 hover:bg-indigo-500 text-white rounded-full font-bold text-lg transition-all shadow-lg shadow-indigo-900/50 flex items-center justify-center gap-2">
|
||||
<Mail size={20} />
|
||||
{lang === 'en' ? 'Email Me' : '发送邮件'}
|
||||
</a>
|
||||
<div className="w-full sm:w-auto px-8 py-4 bg-white/10 hover:bg-white/20 backdrop-blur-md text-white rounded-full font-bold text-lg transition-all flex items-center justify-center gap-2 cursor-pointer">
|
||||
<MessageSquare size={20} />
|
||||
WeChat: {contact.wechat}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="bg-slate-950 border-t border-white/5 py-12">
|
||||
<div className="max-w-6xl mx-auto px-4 flex flex-col md:flex-row items-center justify-between gap-6">
|
||||
<div className="flex flex-col items-center md:items-start">
|
||||
<h2 className="text-xl font-bold text-white mb-2">{name[lang]}</h2>
|
||||
<p className="text-slate-500 text-sm">
|
||||
© {new Date().getFullYear()} All rights reserved.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-6">
|
||||
<a href={`mailto:${contact.email}`} className="text-slate-400 hover:text-white transition-colors p-2 bg-white/5 rounded-full hover:bg-indigo-600"><Mail size={20}/></a>
|
||||
<a href="#" className="text-slate-400 hover:text-white transition-colors p-2 bg-white/5 rounded-full hover:bg-blue-600"><Linkedin size={20}/></a>
|
||||
<a href="#" className="text-slate-400 hover:text-white transition-colors p-2 bg-white/5 rounded-full hover:bg-emerald-600"><Globe2 size={20}/></a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,20 @@
|
||||
<div align="center">
|
||||
<img width="1200" height="475" alt="GHBanner" src="https://github.com/user-attachments/assets/0aa67016-6eaf-458a-adb2-6e31a0763ed6" />
|
||||
</div>
|
||||
|
||||
# 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/1WUmEnnlP32ZAV4EvpNu8RLOKs9siv2ez
|
||||
|
||||
## 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`
|
||||
@@ -0,0 +1,63 @@
|
||||
import React from 'react';
|
||||
import { ExperienceItem, Language } from '../types';
|
||||
import { Calendar } from 'lucide-react';
|
||||
|
||||
interface Props {
|
||||
experience: ExperienceItem[];
|
||||
lang: Language;
|
||||
}
|
||||
|
||||
const ExperienceList: React.FC<Props> = ({ experience, lang }) => {
|
||||
return (
|
||||
<div className="relative space-y-12">
|
||||
{/* Central Line */}
|
||||
<div className="absolute left-4 top-4 bottom-4 w-0.5 bg-slate-200 md:left-1/2 md:-ml-[1px]"></div>
|
||||
|
||||
{experience.map((job, index) => (
|
||||
<div key={index} className={`relative flex flex-col md:flex-row gap-8 ${index % 2 === 0 ? 'md:flex-row-reverse' : ''} group`}>
|
||||
|
||||
{/* Timeline Dot */}
|
||||
<div className="absolute left-4 -translate-x-1/2 top-6 w-4 h-4 rounded-full border-4 border-white bg-indigo-500 shadow-md z-10 md:left-1/2 transition-transform group-hover:scale-125 group-hover:bg-indigo-600"></div>
|
||||
|
||||
{/* Date for Desktop (Opposite side) */}
|
||||
<div className="hidden md:block w-1/2 pt-4 px-8 text-right group-hover:text-indigo-600 transition-colors">
|
||||
<div className={`flex items-center gap-2 text-sm font-bold tracking-wider text-slate-400 uppercase ${index % 2 === 0 ? 'justify-start' : 'justify-end'}`}>
|
||||
{index % 2 !== 0 && <span>{job.period}</span>}
|
||||
<Calendar size={14} />
|
||||
{index % 2 === 0 && <span>{job.period}</span>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content Card */}
|
||||
<div className="ml-12 md:ml-0 md:w-1/2 md:px-8">
|
||||
<div className="bg-white p-6 rounded-2xl shadow-sm border border-slate-100 group-hover:shadow-lg group-hover:border-indigo-100 transition-all duration-300 relative">
|
||||
{/* Mobile Date */}
|
||||
<div className="md:hidden text-xs font-bold text-indigo-500 mb-2 uppercase tracking-wide flex items-center gap-1">
|
||||
<Calendar size={12} />
|
||||
{job.period}
|
||||
</div>
|
||||
|
||||
<h3 className="text-lg font-bold text-slate-900 group-hover:text-indigo-700 transition-colors">
|
||||
{job.company[lang]}
|
||||
</h3>
|
||||
<div className="text-sm font-semibold text-slate-500 mb-4">
|
||||
{job.role[lang]}
|
||||
</div>
|
||||
|
||||
<ul className="space-y-3">
|
||||
{job.description.map((desc, i) => (
|
||||
<li key={i} className="text-sm text-slate-600 leading-relaxed flex items-start gap-3">
|
||||
<span className="mt-1.5 w-1.5 h-1.5 bg-indigo-400 rounded-full shrink-0"></span>
|
||||
<span>{desc[lang]}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ExperienceList;
|
||||
@@ -0,0 +1,23 @@
|
||||
import React from 'react';
|
||||
import { Language } from '../types';
|
||||
import { Globe } from 'lucide-react';
|
||||
|
||||
interface Props {
|
||||
lang: Language;
|
||||
setLang: (lang: Language) => void;
|
||||
}
|
||||
|
||||
const LanguageToggle: React.FC<Props> = ({ lang, setLang }) => {
|
||||
return (
|
||||
<button
|
||||
onClick={() => setLang(lang === 'en' ? 'zh' : 'en')}
|
||||
className="flex items-center gap-2 px-4 py-2 rounded-full bg-slate-100 hover:bg-slate-200 transition-colors text-slate-700 font-medium"
|
||||
aria-label="Toggle Language"
|
||||
>
|
||||
<Globe size={18} />
|
||||
<span>{lang === 'en' ? '中文' : 'English'}</span>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default LanguageToggle;
|
||||
@@ -0,0 +1,83 @@
|
||||
import React from 'react';
|
||||
import { ProjectItem, Language } from '../types';
|
||||
import { ExternalLink, Code, Gamepad2, Car, BarChart3 } from 'lucide-react';
|
||||
|
||||
interface Props {
|
||||
project: ProjectItem;
|
||||
lang: Language;
|
||||
}
|
||||
|
||||
const ProjectCard: React.FC<Props> = ({ project, lang }) => {
|
||||
// Select a placeholder icon fallback
|
||||
const getIcon = () => {
|
||||
switch (project.imageType) {
|
||||
case 'car': return <Car size={32} className="text-white opacity-80" />;
|
||||
case 'game': return <Gamepad2 size={32} className="text-white opacity-80" />;
|
||||
case 'chart': return <BarChart3 size={32} className="text-white opacity-80" />;
|
||||
default: return <Code size={32} className="text-white opacity-80" />;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="group bg-white rounded-2xl overflow-hidden shadow-md hover:shadow-2xl transition-all duration-300 border border-slate-100 flex flex-col h-full transform hover:-translate-y-1">
|
||||
{/* Image Area - Increased height for "Rich" feel */}
|
||||
<div className="relative h-64 w-full overflow-hidden bg-slate-900">
|
||||
{project.imageUrl ? (
|
||||
<img
|
||||
src={project.imageUrl}
|
||||
alt={project.title[lang]}
|
||||
className="w-full h-full object-cover transform group-hover:scale-110 transition-transform duration-700 ease-out"
|
||||
loading="lazy"
|
||||
/>
|
||||
) : (
|
||||
<div className="w-full h-full flex items-center justify-center bg-gradient-to-br from-slate-800 to-indigo-900">
|
||||
{getIcon()}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Dark Gradient Overlay for text readability at bottom */}
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-slate-900/80 via-transparent to-transparent opacity-60"></div>
|
||||
|
||||
{/* Type badge */}
|
||||
<div className="absolute top-4 right-4 bg-white/10 backdrop-blur-md px-3 py-1 rounded-full border border-white/20 shadow-sm">
|
||||
<span className="text-xs font-bold text-white tracking-wide uppercase">
|
||||
{project.imageType || 'Dev'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content Area */}
|
||||
<div className="p-6 md:p-8 flex-1 flex flex-col">
|
||||
<h3 className="text-xl md:text-2xl font-bold text-slate-800 mb-3 group-hover:text-indigo-600 transition-colors">
|
||||
{project.title[lang]}
|
||||
</h3>
|
||||
<p className="text-base text-slate-600 leading-relaxed mb-6 flex-1">
|
||||
{project.description[lang]}
|
||||
</p>
|
||||
|
||||
<div className="mt-auto pt-6 border-t border-slate-100 flex items-center justify-between">
|
||||
<div className="flex gap-2">
|
||||
{/* Decorative dots representing tech stack */}
|
||||
<div className="h-2 w-2 rounded-full bg-indigo-500"></div>
|
||||
<div className="h-2 w-2 rounded-full bg-blue-400"></div>
|
||||
<div className="h-2 w-2 rounded-full bg-purple-400"></div>
|
||||
</div>
|
||||
|
||||
{project.link && (
|
||||
<a
|
||||
href={project.link}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex items-center gap-2 text-sm font-bold text-indigo-600 hover:text-indigo-800 transition-colors bg-indigo-50 px-4 py-2 rounded-lg hover:bg-indigo-100"
|
||||
>
|
||||
{project.linkText ? project.linkText[lang] : (lang === 'en' ? 'View details' : '查看详情')}
|
||||
<ExternalLink size={16} />
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectCard;
|
||||
@@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
const Section: React.FC<Props> = ({ title, children, className = "", id }) => {
|
||||
return (
|
||||
<section id={id} className={`py-20 ${className}`}>
|
||||
<div className="max-w-6xl mx-auto px-4 sm:px-6">
|
||||
<div className="flex flex-col items-center mb-16">
|
||||
<h2 className="text-3xl md:text-4xl font-extrabold text-slate-900 mb-4 tracking-tight">
|
||||
{title}
|
||||
</h2>
|
||||
<div className="h-1 w-20 bg-indigo-600 rounded-full"></div>
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Section;
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
import { ResumeData } from './types';
|
||||
|
||||
export const RESUME_DATA: ResumeData = {
|
||||
name: {
|
||||
en: "Xiang, Silian",
|
||||
zh: "项思炼"
|
||||
},
|
||||
title: {
|
||||
en: "Senior Developer / Simulation Expert",
|
||||
zh: "高级开发工程师 / 仿真专家"
|
||||
},
|
||||
summary: {
|
||||
en: "10+ years of experience. 4 years in autonomous driving simulation engine development and management. 6 years in mobile game development (Unity, Cocos2d, 3D graphics). 2 years in data visualization using React. Master of Engineering.",
|
||||
zh: "10年以上工作经验。4年自动驾驶HMI、仿真开发管理经验。6年Unity、Cocos2d游戏开发管理经验。3年Linux后端开发及大数据Docker部署经验。"
|
||||
},
|
||||
contact: {
|
||||
mobile: "13810215419",
|
||||
email: "youmiss@163.com",
|
||||
wechat: "13810215419"
|
||||
},
|
||||
skills: [
|
||||
{ en: "Autonomous Driving Simulation (LGSVL, World Sim)", zh: "自动驾驶仿真 (LGSVL, World Sim)" },
|
||||
{ en: "Unity 3D / Cocos2d Development", zh: "Unity 3D / Cocos2d 开发" },
|
||||
{ en: "HMI Development (Android/PC)", zh: "HMI 开发 (Android/PC)" },
|
||||
{ en: "Backend (C++, Java, Python, WebRTC)", zh: "后端 (C++, Java, Python, WebRTC)" },
|
||||
{ en: "Graphics Programming (OpenGL, Shaders)", zh: "图形编程 (OpenGL, Shaders)" },
|
||||
{ en: "Frontend (React, TypeScript)", zh: "前端 (React, TypeScript)" }
|
||||
],
|
||||
experience: [
|
||||
{
|
||||
company: { en: "Yi Hai Lan", zh: "亿海蓝" },
|
||||
role: { en: "Software Development Engineer", zh: "软件开发工程师" },
|
||||
period: "2024/05 - Present",
|
||||
description: [
|
||||
{
|
||||
en: "Ship Autonomous Driving HMI System: Frontend using Unity (PC/Android), Backend on Orin using C++.",
|
||||
zh: "轮船自动驾驶HMI系统开发:前端采用Unity(支持PC和Android),后端为Orin采用C++开发。"
|
||||
},
|
||||
{
|
||||
en: "Remote Driving System Development: WebRTC low-latency video, KCP protocol control integration, multi-platform server architecture.",
|
||||
zh: "远程驾驶系统开发:WebRTC低延时视频,KCP协议控制指令集成,多端服务器架构设计。"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
company: { en: "He Duo Technology (HoloMatic)", zh: "禾多科技" },
|
||||
role: { en: "Lead Developer of Simulation Engine", zh: "可视化、仿真开发负责人" },
|
||||
period: "2020/10 - 2024/04",
|
||||
description: [
|
||||
{
|
||||
en: "LGSVL Secondary Development: Built initial sim engine supporting ground truth perception testing and Python-based PNC scenarios.",
|
||||
zh: "基于LGSVL进行二次开发,完成仿真引擎初版。支持感知结果真值的自动驾驶仿真测试,通过Python搭建测试场景进行PNC测试。"
|
||||
},
|
||||
{
|
||||
en: "Sim Engine 2.0 Refactor: Implemented Unity real-time rendering for raw camera input simulation (closed-loop). Full data recording for replay. Decoupled logic from game engine (white-box testing). RL for NPC motion.",
|
||||
zh: "重构仿真引擎升级到2.0:Unity实时渲染仿真摄像头原始图像(闭环测试);全数据记录与重放;逻辑纯代码实现(白盒化);强化学习控制NPC运动。"
|
||||
},
|
||||
{
|
||||
en: "Developed in-house OpenScenario parsing engine.",
|
||||
zh: "自研OpenScenario解析引擎,支持标准化的仿真测试。"
|
||||
},
|
||||
{
|
||||
en: "Log Sim & World Sim: HIL bench testing, Perception CI/CD, Cloud Docker large-scale concurrency testing.",
|
||||
zh: "Log Sim回灌测试(Hil台架,感知CI/CD);World Sim仿真测试(云端Docker大规模并发测试)。"
|
||||
},
|
||||
{
|
||||
en: "HMI Rendering: Optimization for TDA4 platform, proprietary UI framework on 8155 chip.",
|
||||
zh: "HMI渲染开发:TDA4平台3D实时流畅渲染,自研交互框架在8155芯片实现高清渲染。"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
company: { en: "Independent Game", zh: "独立游戏开发" },
|
||||
role: { en: "Game Producer", zh: "独立游戏制作人" },
|
||||
period: "2019/11 - 2020/09",
|
||||
description: [
|
||||
{
|
||||
en: "Smart TV Game: 'Soldier vs. Monster' (Unity). Optimized for low-end hardware.",
|
||||
zh: "智能电视游戏:《士兵打怪兽》(体感游戏,山寨健身环大冒险),硬件软件全栈开发。"
|
||||
},
|
||||
{
|
||||
en: "Mobile Education: 'Solid Geometry' AR teaching software.",
|
||||
zh: "手机教育软件:《立体几何》AR增强现实教学软件。"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
company: { en: "HappyElement (Beijing)", zh: "乐元互动(北京)" },
|
||||
role: { en: "AI Engineer", zh: "AI工程师" },
|
||||
period: "2018/01 - 2019/04",
|
||||
description: [
|
||||
{
|
||||
en: "Full stack development, Big Data Analysis & Visualization using React and Druid.",
|
||||
zh: "全栈开发,大数据分析&可视化(React)。AI驱动游戏运营。"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
company: { en: "Beijing Youyi Mr. Technology", zh: "北京游艺先生科技" },
|
||||
role: { en: "Technical Manager / Partner", zh: "技术合伙人" },
|
||||
period: "2014/05 - 2017/12",
|
||||
description: [
|
||||
{
|
||||
en: "Built tech team from scratch. Developed 'Ice and Fire Fantasy' (Cocos2dx + Lua, Java/Redis/MySQL).",
|
||||
zh: "从零开始搭建技术团队。开发手机游戏《冰火幻想》(客户端Cocos2dx+Lua,服务器Java+Redis+MySQL)。"
|
||||
},
|
||||
{
|
||||
en: "Virtual Idol Development (UE4 + Motion Capture).",
|
||||
zh: "虚拟偶像开发(UE4 + 洛伊滕动捕),数值人直播。"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
company: { en: "HappyElement (Beijing)", zh: "乐元互动(北京)" },
|
||||
role: { en: "Technical Manager / Main Programmer", zh: "主程序" },
|
||||
period: "2011/03 - 2014/05",
|
||||
description: [
|
||||
{
|
||||
en: "Participated in 'Aquarium', 'Happy Fish'. Main programmer for 'Dragon Legend', 'Warrior World'.",
|
||||
zh: "参与《开心水族馆》《开心消消乐》开发。《巨龙传说》《指尖英雄》《战姬天下》前后端开发。"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
company: { en: "Tencent", zh: "腾讯" },
|
||||
role: { en: "Game Developer (C++)", zh: "C++ 程序" },
|
||||
period: "2010/03 - 2011/03",
|
||||
description: [
|
||||
{
|
||||
en: "Participated in 'Happy Landlord'. Main programmer for 'QQ Matching'.",
|
||||
zh: "参与《欢乐斗地主》开发,《QQ连连看》主程序。"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
company: { en: "Gameloft", zh: "Gameloft" },
|
||||
role: { en: "Lead Mobile Game Programmer", zh: "手机游戏主程序" },
|
||||
period: "2008/08 - 2010/03",
|
||||
description: [
|
||||
{
|
||||
en: "Programmed 'Real Football' and 'Chess' games (Java/Lua).",
|
||||
zh: "《脑白金》主机游戏Lua,《真实足球》Java,《棒球》C++。"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
education: [
|
||||
{
|
||||
school: { en: "Guizhou University", zh: "贵州大学 (211)" },
|
||||
degree: { en: "Master of Engineering", zh: "硕士" },
|
||||
major: { en: "Computer Application Technology", zh: "计算机应用技术" },
|
||||
period: "2005/09 - 2008/07"
|
||||
},
|
||||
{
|
||||
school: { en: "Guizhou University", zh: "贵州大学 (211)" },
|
||||
degree: { en: "Bachelor of Engineering", zh: "本科" },
|
||||
major: { en: "Automation", zh: "自动化" },
|
||||
period: "1999/09 - 2003/07"
|
||||
}
|
||||
],
|
||||
projects: [
|
||||
{
|
||||
title: { en: "U3D Software Rendering Engine", zh: "U3D 软渲染引擎" },
|
||||
description: {
|
||||
en: "Deep dive into Unity rendering pipeline. Implemented Simple_lit and Physically Based Rendering (PBR) shaders in pure C++.",
|
||||
zh: "深入理解Unity引擎渲染细节。复刻Unity URP Shader效果,实现simple_lit及物理渲染Lit shader。"
|
||||
},
|
||||
link: "https://zhuanlan.zhihu.com/p/688850501",
|
||||
linkText: { en: "View Article (Zhihu)", zh: "知乎专栏" },
|
||||
imageType: "code",
|
||||
imageUrl: "https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe?q=80&w=2564&auto=format&fit=crop" // Abstract 3D
|
||||
},
|
||||
{
|
||||
title: { en: "Surround View Camera Simulation", zh: "环视摄像头仿真" },
|
||||
description: {
|
||||
en: "Solved 180+ degree FOV rendering issues using spherical projection instead of pinhole models, improving efficiency by 6x. High fidelity fisheye simulation.",
|
||||
zh: "环视全景相机实时渲染。弃用传统视锥体投影,采用球视体模型统一处理坐标变换和畸变,效率提升6倍。"
|
||||
},
|
||||
link: "https://www.bilibili.com/video/BV16z421f7xH",
|
||||
linkText: { en: "View Video (Bilibili)", zh: "B站视频" },
|
||||
imageType: "car",
|
||||
imageUrl: "https://images.unsplash.com/photo-1492144534655-ae79c964c9d7?q=80&w=2304&auto=format&fit=crop" // Car
|
||||
},
|
||||
{
|
||||
title: { en: "LiDAR Point Cloud Visualization", zh: "激光雷达点云数据可视化" },
|
||||
description: {
|
||||
en: "Unity URP pipeline. Encoded point cloud data to GPU via texture. Used Compute Shaders for vertex transformation and coloring, supporting 10M+ points on integrated graphics.",
|
||||
zh: "采用Unity URP管线。编写Computer shader进行点云可视化,支持集成显卡上千万级点云实时渲染。"
|
||||
},
|
||||
imageType: "chart",
|
||||
imageUrl: "https://images.unsplash.com/photo-1558494949-ef526b0042a0?q=80&w=2600&auto=format&fit=crop" // Tech/Data
|
||||
},
|
||||
{
|
||||
title: { en: "AR Solid Geometry", zh: "AR 立体几何" },
|
||||
description: {
|
||||
en: "Augmented Reality teaching software using physical object visual features (no markers required). Occlusion rendering for realistic 3D geometry.",
|
||||
zh: "不用特定特征图片,直接采用实物视觉效果。采用空间透明遮挡渲染模型来渲染立体几何效果。"
|
||||
},
|
||||
link: "http://www.bilibili.com/video/BV1jW421A7mM",
|
||||
linkText: { en: "View Video", zh: "B站视频" },
|
||||
imageType: "code",
|
||||
imageUrl: "https://images.unsplash.com/photo-1531297461136-82lwDe43q5DL?q=80&w=2600&auto=format&fit=crop" // AR/Geometry
|
||||
}
|
||||
]
|
||||
};
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Xiang Silian - Resume</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<style>
|
||||
/* Smooth scrolling for anchor links */
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
</style>
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"lucide-react": "https://aistudiocdn.com/lucide-react@^0.555.0",
|
||||
"react/": "https://aistudiocdn.com/react@^19.2.0/",
|
||||
"react": "https://aistudiocdn.com/react@^19.2.0",
|
||||
"react-dom/": "https://aistudiocdn.com/react-dom@^19.2.0/"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<link rel="stylesheet" href="/index.css">
|
||||
</head>
|
||||
<body class="bg-slate-50 text-slate-900 antialiased">
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/index.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "Xiang Silian Resume",
|
||||
"description": "Interactive bilingual resume for Xiang Silian featuring work experience, skills, and portfolio.",
|
||||
"requestFramePermissions": []
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "xiang-silian-resume",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"lucide-react": "^0.555.0",
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.14.0",
|
||||
"@vitejs/plugin-react": "^5.0.0",
|
||||
"typescript": "~5.8.2",
|
||||
"vite": "^6.2.0"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
export type Language = 'en' | 'zh';
|
||||
|
||||
export interface LocalizedString {
|
||||
en: string;
|
||||
zh: string;
|
||||
}
|
||||
|
||||
export interface ExperienceItem {
|
||||
company: LocalizedString;
|
||||
role: LocalizedString;
|
||||
period: string;
|
||||
description: LocalizedString[];
|
||||
location?: LocalizedString;
|
||||
}
|
||||
|
||||
export interface ProjectItem {
|
||||
title: LocalizedString;
|
||||
description: LocalizedString;
|
||||
link?: string;
|
||||
linkText?: LocalizedString;
|
||||
techStack?: string[];
|
||||
imageUrl?: string; // Added field for project images
|
||||
imageType?: 'code' | 'car' | 'game' | 'chart'; // For placeholder selection fallback
|
||||
}
|
||||
|
||||
export interface EducationItem {
|
||||
school: LocalizedString;
|
||||
degree: LocalizedString;
|
||||
period: string;
|
||||
major: LocalizedString;
|
||||
}
|
||||
|
||||
export interface ContactInfo {
|
||||
mobile: string;
|
||||
email: string;
|
||||
wechat: string;
|
||||
}
|
||||
|
||||
export interface ResumeData {
|
||||
name: LocalizedString;
|
||||
title: LocalizedString;
|
||||
summary: LocalizedString;
|
||||
contact: ContactInfo;
|
||||
skills: LocalizedString[];
|
||||
experience: ExperienceItem[];
|
||||
projects: ProjectItem[];
|
||||
education: EducationItem[];
|
||||
}
|
||||
@@ -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, '.'),
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user