--- name: generate-resume description: Generate a print-optimized, ATS-friendly single-page resume PDF from portfolio content. Use when user wants to create or regenerate their resume. (project) --- # Resume Generator Generate a single-page PDF resume using Puppeteer to render the `/resume` React page. Optimized for ATS (Applicant Tracking Systems) and print. 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" ## 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_JOBS` to 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: 1. Reducing highlights per job (2-3 is sufficient) 2. Tightening typography (9-10pt base) 3. Never by cutting jobs --- ## Format Guidelines ### Layout Constants (ResumePage.tsx) ```typescript 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 1. **Header**: Name / Current Role + contact info (email, location) 2. **Impact Summary**: One-liner tagline + top skills + notable companies + key stats 3. **Professional Experience**: Each job with company, role, period, location, and bullets 4. **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`: ```css @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: ```css .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 1. **Dev server running**: `npm run dev` 2. **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 1. **Validate content**: `npm run validate` 2. **Preview** at http://localhost:5173/resume 3. **Verify** single-page fit (no vertical scrollbar) 4. **Check** all experience is included 5. **Generate**: ```bash npm run generate:resume ``` 6. **Verify** output at `public/resume.pdf` ### Custom Filename ```bash npm run generate:resume -- --name "Jane Smith" # Output: public/jane-smith.pdf ``` ### Custom URL ```bash 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: ```yaml hero: cta: secondary: label: "Download Resume" href: "/resume.pdf" ``` --- ## Technical Details ### Puppeteer Configuration (generate-resume.ts) ```typescript 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 ```typescript 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` | | Email | `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