cv-pdf-gen
v0.2.0
Published
**A framework for building 1-page CV PDFs. Edit YAML. Pick a theme. Print to PDF. No React knowledge required.**
Downloads
273
Readme
cv-pdf-gen
A framework for building 1-page CV PDFs. Edit YAML. Pick a theme. Print to PDF. No React knowledge required.
Quick Start
npm create cv-gen my-cv
cd my-cv
npm install
npm run devOpen http://localhost:3000, edit your content, then press Cmd+P (or click Export PDF) to save your CV as a PDF.
How It Works
- Content — edit
content/cv.en.yamlwith your personal info, experience, skills, and education - Theme — choose or customize a CSS theme in
themes/ - Export — use the browser's print dialog to save as PDF
That's it. The framework handles the layout, typography, and print formatting for you.
Project Structure
After running npm create cv-gen, your project looks like this:
my-cv/
├── content/
│ └── cv.en.yaml # Your CV content
├── themes/
│ ├── default.css # Theme colors and fonts
│ └── default.layout.yaml # Column layout and decorations (optional)
├── decorations/ # SVG decoration files
├── plugins/ # Custom plugins (optional)
├── public/
│ └── photo.jpg # Your portrait photo
└── src/
└── main.tsx # Entry point (pre-configured, no need to edit)Content (YAML)
All your CV data lives in content/cv.en.yaml. Here's a full example:
# Section order — rearrange to reorder sections on the page
blocks:
- header
- experience
- technical_skills
- soft_skills
- education
- languages
# Column layout
layout:
columns: 2
left:
- experience
right:
- technical_skills
- soft_skills
- education
- languages
# Section heading labels (customize for any language)
labels:
workExperience: "WORK EXPERIENCE"
technicalSkills: "TECHNICAL SKILLS"
softSkills: "SOFT SKILLS"
education: "EDUCATION"
languages: "LANGUAGES"
responsibilities: "Responsibilities"
achievements: "Achievements/Tasks"
# Personal info
personal:
name: "Jane Smith"
title: "Software Engineer"
photo: "photo.jpg" # Place in public/ — omit if you don't want a photo
summary: "Brief professional summary that appears below your name."
contact:
email: "[email protected]"
phone: "+1 555 000 0000"
location: "Berlin, Germany"
linkedin: "linkedin.com/in/janesmith"
# Work experience
experience:
- role: "Senior Engineer"
company: "Acme Corp"
dates: "01/2022 - Present"
location: "Berlin, Germany (hybrid)"
description: "Short description of the company."
type: "achievements" # "achievements" or "responsibilities"
items:
- "Led migration of monolith to microservices, reducing deploy time by 40%."
- "Mentored a team of 4 junior engineers."
# Technical skills — displayed as category/value pairs
technical_skills:
- category: "Languages"
items: "Python, TypeScript, Go, SQL"
- category: "Frameworks"
items: "FastAPI, React, Django"
- category: "Infrastructure"
items: "Docker, Kubernetes, AWS, GitHub Actions"
# Soft skills — displayed as a comma-separated list
soft_skills:
- "Collaborative"
- "Pragmatic"
- "Curious"
# Education
education:
- title: "MSc Computer Science — University of Berlin"
description: "Thesis: Distributed Systems at Scale"
dates: "2016 - 2018"
# Languages — level is 1 (basic) to 5 (native)
languages:
- name: "English"
level: 5
- name: "German"
level: 4Themes
Three themes are included out of the box:
| Theme | Description |
|-------|-------------|
| default | Clean two-column layout with a teal accent |
| sidebar | Dark sidebar (30/70 split) with accent background |
| minimal | Serif fonts, minimalist black and white |
The dev server shows a tab for each theme so you can compare them side by side.
Customizing a theme
Each theme is a plain CSS file that sets custom properties. Override any of these in your theme file:
:root {
--cv-accent: #2b7a78; /* Primary color */
--cv-accent-light: #e0f2f1; /* Light accent (backgrounds, borders) */
--cv-text: #333333; /* Body text */
--cv-text-light: #666666; /* Secondary text */
--cv-bg: #ffffff; /* Page background */
--cv-font: 'Helvetica Neue', Arial, sans-serif;
--cv-font-size-base: 9pt;
--cv-font-size-name: 28pt;
--cv-font-size-section: 13pt;
--cv-left-column: 58%; /* Left column width (right = remainder) */
}To create a new theme, add a .css file to the themes/ directory — it's picked up automatically.
Theme layout
Themes can have a companion layout YAML file (themes/default.layout.yaml) to override the column layout and add decorations independently of the content YAML:
layout:
columns: 2
left:
- experience
right:
- technical_skills
- education
- languagesDecorations
Drop any SVG into the decorations/ folder and reference it from a layout YAML file:
layout:
columns: 2
left: [experience]
right: [technical_skills, education, languages]
decorations:
- svg: circles-cluster.svg
position: top-right # top-left | top-right | bottom-left | bottom-right
width: 80mm
height: 80mm
opacity: 0.1
color: "#2b7a78" # Replaces currentColor in the SVGDecorations are rendered as background images — they are fully print-safe and won't cause page overflow.
Plugins
Plugins let you extend or replace built-in blocks without touching the framework.
Place a plugin in plugins/my-plugin/index.tsx — it's auto-discovered at startup.
Inject content around items (hooks)
import { hooks } from "../../src/framework/plugin";
import type { Experience } from "../../src/framework/types";
// Extend the Experience type with your custom YAML fields
interface ExperienceWithBadges extends Experience {
badges?: string[];
}
export default hooks<ExperienceWithBadges>("experience", {
afterEach: ({ item }) =>
item.badges?.length ? (
<div className="badges">
{item.badges.map((b) => (
<span key={b} className="badge">{b}</span>
))}
</div>
) : null,
});Available hook points: before, after, beforeEach, afterEach.
Replace a block entirely (replace)
import { replace } from "../../src/framework/plugin";
import type { CVData } from "../../src/framework/types";
export default replace("languages", ({ data }: { data: CVData }) => (
<div className="languages-custom">
{data.languages.map((lang) => (
<div key={lang.name}>
<span>{lang.name}</span>
<meter value={lang.level} min={0} max={5} />
</div>
))}
</div>
));Two example plugins are included in the template: tech-badges (renders skill badges on experience items) and rating-bars (replaces the languages block with visual rating bars).
Multiple Languages
To add a French version of your CV, create content/cv.fr.yaml with translated content. The dev server will automatically show a tab for each language/theme combination.
content/
├── cv.en.yaml
└── cv.fr.yaml ← auto-discoveredExporting to PDF
- Click the Export PDF button in the top bar, or press Cmd+P / Ctrl+P
- In the print dialog, set Destination to "Save as PDF"
- Make sure "Print backgrounds" is enabled to preserve theme colors and decorations
- Set margins to None
A red dashed border appears in the dev preview if your content overflows the A4 page — use it as a guide to trim content before exporting.
License
MIT
