generate-resume
Resume Generator
<when_to_activate> Activate when the user:
- Asks to generate, create, or update their resume
- Says "create my resume", "make a resume", "export resume PDF"
- Wants to refresh the resume after updating portfolio content
- Asks about resume format or PDF generation
Trigger phrases: "resume", "generate resume", "PDF", "export resume", "make resume" </when_to_activate>
Critical Files
| File | Purpose |
|---|---|
src/pages/ResumePage.tsx |
React component for print-optimized layout |
src/pages/ResumePage.css |
Print/screen styles with theme isolation |
scripts/generate-resume.ts |
Puppeteer PDF generation script |
content/profile.yaml |
Name, email, location, tagline, stats |
content/experience/index.yaml |
Jobs with highlights |
content/skills/index.yaml |
Categorized skills |
public/resume.pdf |
Default output file |
Design Principles
1. Never Cut Experience
Critical: Include ALL jobs from content/experience/index.yaml. Missing experience (especially major companies) damages credibility more than a slightly longer resume.
- If page is too long → reduce highlights per job, NOT number of jobs
- Set
MAX_JOBSto match total jobs in experience file - Every role adds signal; cutting roles removes career trajectory
2. Metrics Over Descriptions
Highlights should follow Action → Outcome format with quantified results:
❌ "Managed product development"
✅ "Shipped Advanced API from 0→1: 17 methods serving 1M+ daily requests"
3. ATS-First Design
- Plain text (no images, icons, or complex layouts)
- Standard fonts: Georgia, Times New Roman (serif) or Arial, Helvetica (sans)
- Clear section headers: Header, Summary, Experience, Skills
- All text must be selectable/copyable
4. Single Page Target
One-page resumes get 2x more callbacks. Fit content by:
- Reducing highlights per job (2-3 is sufficient)
- Tightening typography (9-10pt base)
- Never by cutting jobs
Format Guidelines
Layout Constants (ResumePage.tsx)
const RESUME_CONFIG = {
SUMMARY_SKILL_CATEGORIES: 2, // Categories in impact summary
SKILLS_PER_CATEGORY: 3, // Skills per category in summary
SUMMARY_COMPANIES: 4, // Companies to list in summary
MAX_JOBS: 6, // Include ALL jobs - adjust to match your experience
MAX_HIGHLIGHTS_PER_JOB: 3, // Bullets per job (action → outcome format)
};
Adjust MAX_JOBS to match the total number of jobs in your experience file.
Resume Structure
- Header: Name / Current Role + contact info (email, location)
- Impact Summary: One-liner tagline + top skills + notable companies + key stats
- Professional Experience: Each job with company, role, period, location, and bullets
- Skills: 2-column grid organized by category
Skills Section Layout
Skills are displayed in a 2-column grid with category names in bold:
Category A: skill1, skill2, skill3... | Category B: skill1, skill2...
Category C: skill1, skill2, skill3... | Category D: skill1, skill2...
Categories are pulled from content/skills/index.yaml. Common category structures:
For Engineers:
- Languages & Frameworks, Infrastructure, Databases, Tools
For Product Managers:
- Domain Expertise, Product Leadership, Technical Execution, Tools
For Designers:
- Design Tools, Research Methods, Platforms, Collaboration
Typography (ResumePage.css)
- Font: Georgia / Times New Roman (ATS-safe serif)
- Base size: 9.5pt
- Line height: 1.35
- Page: Letter size (8.5in × 11in)
- Margins: 0.4in top/bottom, 0.5in left/right
Known Issues & Fixes
1. Black Box at Bottom of PDF
Cause: ThemeProvider applies dark background (#08080a) to body/#root, which bleeds into the PDF outside the .resume-page container.
Fix: CSS must override parent elements in @media print:
@media print {
html,
body,
#root {
background: white !important;
min-height: auto !important;
padding: 0 !important;
margin: 0 !important;
}
}
2. PDF Exceeds One Page
Fix: Reduce MAX_HIGHLIGHTS_PER_JOB in ResumePage.tsx. Do NOT reduce MAX_JOBS - missing experience is worse than a slightly longer resume.
3. Missing Experience/Jobs
Cause: MAX_JOBS was set too low, cutting off important companies.
Fix: Always set MAX_JOBS to the total number of jobs in content/experience/index.yaml. Count your jobs and update the config.
4. Yellow/Colored Underline on Role Title
Fix: Ensure .resume-role-highlight has no border-bottom or background-color.
5. Theme Colors Bleeding Through
Fix: Reset all children with:
.resume-page * {
background: transparent;
color: inherit;
}
6. Fonts Not Loading in PDF
Fix: The script waits for document.fonts.ready + 500ms buffer. If fonts still don't load, increase POST_FONT_BUFFER_MS in generate-resume.ts.
Generation Workflow
Prerequisites
- Dev server running:
npm run dev - Content files populated:
content/profile.yaml(name, email, location, tagline, stats)content/experience/index.yaml(jobs with highlights)content/skills/index.yaml(categorized skills)
Steps
- Validate content:
npm run validate - Preview at http://localhost:5173/resume
- Verify single-page fit (no vertical scrollbar)
- Check all experience is included
- Generate:
npm run generate:resume
- Verify output at
public/resume.pdf
Custom Filename
npm run generate:resume -- --name "Jane Smith"
# Output: public/jane-smith.pdf
Custom URL
npm run generate:resume -- --url http://localhost:3000
# Uses different dev server port
Troubleshooting
| Issue | Solution |
|---|---|
| "net::ERR_CONNECTION_REFUSED" | Start dev server: npm run dev |
| PDF is blank | Check browser console at /resume for React errors |
| Wrong content displayed | Verify YAML files, run npm run validate |
| Fonts look wrong | Increase POST_FONT_BUFFER_MS in script |
| Two pages instead of one | Reduce MAX_HIGHLIGHTS_PER_JOB, NOT MAX_JOBS |
| Dark background in PDF | Verify print CSS overrides html/body/#root |
| Jobs missing | Increase MAX_JOBS to match total in experience file |
| Skills look cramped | Reduce number of skills per category or categories |
After Generation
Update hero CTA in content/profile.yaml to link to the resume:
hero:
cta:
secondary:
label: "Download Resume"
href: "/resume.pdf"
Technical Details
Puppeteer Configuration (generate-resume.ts)
const PAGE_DIMENSIONS = {
LETTER: {
WIDTH_PX: 816, // 8.5" at 96dpi
HEIGHT_PX: 1056, // 11" at 96dpi
},
};
const TIMING = {
POST_FONT_BUFFER_MS: 500, // Wait after fonts.ready
PAGE_LOAD_TIMEOUT_MS: 30000, // Navigation timeout
};
PDF Export Settings
await page.pdf({
path: output,
format: 'letter',
printBackground: true,
margin: {
top: '0.4in',
right: '0.5in',
bottom: '0.4in',
left: '0.5in',
},
preferCSSPageSize: true,
});
Content Sources
The resume pulls data from these content files:
| Data | Source | Field |
|---|---|---|
| Name | profile.yaml |
name |
profile.yaml |
email |
|
| Location | profile.yaml |
location |
| Tagline | profile.yaml |
about.tagline |
| Stats | profile.yaml |
about.stats[] |
| Jobs | experience/index.yaml |
jobs[] |
| Skills | skills/index.yaml |
categories[].skills[] |
Quality Checklist
Before Generating
- Content YAML files pass validation (
npm run validate) - Preview at /resume shows correct info
- ALL jobs are included (count them!)
- Resume fits on single page (no scrollbar)
- All highlights follow "Action → Outcome" format
- Metrics are quantified (%, $, numbers)
After Generating
- Open PDF and verify visual appearance
- Check all text is selectable (ATS-friendly)
- Verify no dark backgrounds or visual artifacts
- Confirm all companies/roles are present
- Test PDF in an ATS simulator if available
More from fotescodev/portfolio
run-tests
Run the test suite and identify new tests needed for recent code changes. Use when verifying changes work correctly or when asked to run tests.
2dmitrii-writing-style
Captures Dmitrii's distinctive writing voice and preferences for all written outputs. Use when creating case studies, blog posts, articles, documents, emails, proposals, PRDs, specifications, messages, or any written content on Dmitrii's behalf. MUST be invoked for any mid-to-long form content creation.
2cv-knowledge-query
Query the CV knowledge base to find achievements, stories, and metrics by theme, skill, company, or keyword. Use when user asks about experience, wants to find specific accomplishments, or needs data for content generation.
2cv-data-ingestion
Ingest and organize raw career data from Obsidian notes, CSV files, zip archives, and markdown documents into the Universal CV portfolio system. Use when processing career history, work experience, testimonials, case studies, or resume data from multiple sources. Outputs structured YAML/Markdown validated against Zod schemas.
2