MyNixOS website logo
Description

Data-Driven CVs with 'Quarto' and 'Typst'.

Provides tools for producing data-driven curriculum vitae documents from structured data stored in an Excel workbook. The core workflow reads CV content from a workbook, converts it into 'Typst' layout blocks, and renders a polished PDF via the 'Quarto' publishing system. Includes functions for reading and cleaning CV data, building 'Typst' section headings and entries, rendering CV sections from data frames, and scaffolding new CV projects with a standard folder structure and template workbook. Designed to separate content from layout: CV data lives in the spreadsheet, rendering configuration lives in 'Quarto', and transformation logic lives in small, reusable R functions. See the 'Typst' typesetting system at <https://typst.app> and the 'Quarto' publishing system at <https://quarto.org>. Inspired by the 'vitae' package <https://CRAN.R-project.org/package=vitae> and the 'Awesome CV' LaTeX template <https://github.com/posquit0/Awesome-CV>.

curriculr curriculr package logo

DOI R-CMD-check CRAN status Lifecycle: experimental Codecov test coverage

curriculr is an R package for producing data-driven curriculum vitae documents. You maintain your CV content in an Excel workbook. curriculr reads it, converts it into Typst layout blocks, and renders a polished PDF via Quarto's Typst engine. No LaTeX. No vitae. No custom .cls files.

Installation

You can install curriculr from CRAN:

install.packages("curriculr")

Install the development version from GitHub:

# install.packages("pak")
pak::pak("erwinlares/curriculr")

Requirements

  • R (>= 4.2.0)
  • Quarto 1.4 or later (ships with Typst support built in)

For new users

Step 1 — scaffold your project

Call create_cv() with no arguments. This copies the template workbook and a placeholder profile image into your current working directory:

library(curriculr)
create_cv()

You will see:

v Created cv-data-template.xlsx
v Created placeholder.png
i Next steps:
1. Open cv-data-template.xlsx and fill in the profile sheet.
2. Replace placeholder.png with your own profile photo.
3. Call create_cv(data = 'cv-data-template.xlsx', photo = 'your-photo.png')

Step 2 — fill in the workbook

Open cv-data-template.xlsx. Start with the profile sheet:

fieldvalue
first_nameYour first name
last_nameYour last name
job_titleYour current title
addressYour mailing address
email[email protected]
websiteyourwebsite.com
githubyour-github-username
linkedinin/your-linkedin
profile_statementOne or two sentence professional summary
photoRelative path to your profile image

Then fill in the remaining sheets with your CV content. The readme sheet inside the workbook explains the column schema and date entry conventions in detail.

Step 3 — render

create_cv(
  data  = "cv-data-template.xlsx",
  photo = "your-photo.png"
)

This writes CV.qmd and CV.pdf next to your workbook. Open CV.pdf to review the output. To update your CV, edit the workbook and call create_cv() again with overwrite = TRUE.

To render without a profile photo, omit the photo argument. The header will use a single-column layout with your name, contact line, and profile statement centered on the page:

create_cv(data = "cv-data-template.xlsx")

For existing users updating from v0.2.0

v0.3.0 introduces several workbook schema changes and new arguments. Here is what you need to know.

photo = NULL now means no photo. Previously, omitting photo in render mode fell back to a bundled placeholder image. It now produces a single-column header layout with no image. Supply a path explicitly to restore the two-column layout.

Your workbook needs an include_in_resume column on every section sheet. This is a boolean column (checked/unchecked) that controls which rows appear when rendering in resume variant mode. Add a column named include_in_resume to each section sheet and check the rows you want to include in a focused resume. Rows without this column are always included.

Your workbook can have an optional theme sheet. This sheet controls fonts, colors, and page layout. If absent, built-in defaults are used. Copy the theme sheet from the updated template workbook to gain full control over the visual appearance without editing CV.qmd directly.

readxl is no longer required. curriculr now uses openxlsx2 for all workbook reading. If you have readxl in your own explicit dependencies for curriculr-related code, you can remove it.


For existing users updating from v0.1.0

v0.2.0 changes how create_cv() works and adds a sections sheet to the workbook schema. Here is what you need to know.

create_cv() now has two modes:

  • Scaffold mode (no arguments) — copies template files to your current directory. Use this once to get started or to reset.
  • Render mode (with arguments) — reads your workbook and renders the PDF. Use this every time you update your CV.

Your workbook needs a sections sheet. This sheet controls which sections appear in the rendered PDF and in what order. Add it manually or copy it from the updated template workbook. The schema is:

sectionlabeltitle_colorg_coldetail_coldate_funwhere_col
educationEducationtitleinstitutiondetailyearwhere
experienceExperiencetitleunitdetaildatewhere

Row order is render order. Delete a row to exclude a section. Add a row for any sheet that follows the standard column schema and it will render automatically without any R code changes.

The date_fun column accepts five tokens:

tokenproduces
dateJan 2018 - Dec 2022
year2018 - 2022
month_yearJan 2018
year_only2021
none(no date)

Rendering a resume

When you want a shorter, focused version of your CV, use variant = "resume". curriculr will include only the rows you have checked in the include_in_resume column of each section sheet:

create_cv(
  data        = "cv-data-template.xlsx",
  photo       = "your-photo.png",
  variant     = "resume",
  output_file = "resume.pdf"
)

Check and uncheck rows directly in the workbook. No R code changes are needed to switch between CV and resume variants.


Customizing the rendered PDF

Changing colors, fonts, and page layout

Open your workbook and edit the theme sheet. Each key maps to a visual setting:

keywhat it controls
font_familyBody font (e.g. Lato, Arial)
font_sizeBase font size (e.g. 8.8pt)
body_colorMain text color (hex code)
accent_colorSection headings, dates, and rules (hex code)
dark_colorEntry titles and name in the header (hex code)
papersizePage size (us-letter or a4)
margin_xLeft and right margins (e.g. 0.62in)
margin_yTop and bottom margins (e.g. 0.58in)

Re-render after editing the theme sheet with overwrite = TRUE to see the changes.

Changing section order or content

Edit the sections sheet in your workbook. Reorder rows to reorder sections. Delete a row to remove a section.

Adding a new section

Use add_section() to add a new sheet and register it in the sections control sheet in one step:

add_section(
  "cv-data-template.xlsx",
  section  = "patents",
  label    = "Patents",
  date_fun = "year_only"
)

The new sheet is pre-populated with the standard column spine. Open the workbook, add your data, and re-render.


Functions

create_cv()

The main entry point. No arguments triggers scaffold mode. With data triggers render mode.

# Scaffold mode
create_cv()

# Render mode — full CV with Font Awesome icons in the contact line
create_cv(
  data        = "~/my_cv/cv-data.xlsx",
  photo       = "~/my_cv/me.jpeg",
  output_file = "erwin-lares-cv.pdf"
)

# Render mode — resume variant, plain text contact line
create_cv(
  data        = "~/my_cv/cv-data.xlsx",
  photo       = "~/my_cv/me.jpeg",
  variant     = "resume",
  use_icons   = "none",
  output_file = "erwin-lares-resume.pdf"
)

Arguments:

  • data — path to the workbook. NULL triggers scaffold mode.
  • photo — path to the profile image. NULL renders without a photo.
  • output_file — PDF filename. Defaults to "CV.pdf".
  • overwrite — whether to overwrite existing files. Defaults to FALSE.
  • variant"cv" (all rows) or "resume" (checked rows only).
  • use_icons"fontawesome" (default) or "none".

add_section()

Adds a new sheet to an existing workbook and registers it in the sections control sheet.

add_section(
  "cv-data-template.xlsx",
  section   = "invited_talks",
  label     = "Invited Talks",
  date_fun  = "month_year",
  where_col = "where"
)

read_cv_data()

Reads all sheets from the workbook into a named list. The profile and theme sheets become named character vectors; section sheets become data frames; the sections sheet is returned in row order.

cv <- read_cv_data("cv-data-template.xlsx")
cv <- read_cv_data("cv-data-template.xlsx", variant = "resume")

cv$experience           # a data frame
cv$sections             # the sections control sheet
cv$profile[["email"]]  # a scalar string
cv$theme[["accent_color"]]  # a scalar string

cv_contact_line()

Assembles the contact line from a profile vector. Useful when building custom Quarto templates.

cv_contact_line(cv$profile, use_icons = "fontawesome")
cv_contact_line(cv$profile, use_icons = "none")

cv_render_section()

Iterates over a CV data frame and writes each row as a formatted Typst entry. Called inside CV.qmd — you will not normally call this directly.

typst_escape()

Escapes Typst-sensitive characters in a string. Useful when building custom Quarto templates.

cv_section()

Returns a raw Typst string for a section heading. Useful when building custom Quarto templates.

resolve_date_fun()

Maps a date_fun token string to an R date formatting function. Useful when building custom rendering logic outside the standard template.


Workbook schema

Every section sheet shares a common column spine:

title | unit | startMonth | startYear | endMonth | endYear | where | detail | include_in_resume

title is always the primary entry label. unit is the secondary line. include_in_resume is a boolean checkbox column — check a row to include it when rendering with variant = "resume". Leave cells blank rather than typing NA.

Date conventions

SituationstartMonthstartYearendMonthendYear
Ongoing roleJan2018present(blank)
Completed roleMar2015Dec2022
Single-year event(blank)2021(blank)(blank)
No date(blank)(blank)(blank)(blank)

Related packages

curriculr is one of three sibling packages:

  • toolero — research workflow toolkit
  • containr — Docker containerization
  • curriculr — data-driven CV generation with Quarto and Typst

Acknowledgements

curriculr was inspired by two prior projects:

  • vitae by Mitchell O'Hara-Wild, Rob Hyndman, and contributors
  • Awesome CV by Byungjin Park (posquit0)

License

MIT (c) Erwin Lares.

Metadata

Version

0.3.0

License

Unknown

Platforms (80)

    Darwin
    FreeBSD
    Genode
    GHCJS
    Linux
    MMIXware
    NetBSD
    none
    OpenBSD
    Redox
    Solaris
    uefi
    WASI
    Windows
Show all
  • aarch64-darwin
  • aarch64-freebsd
  • aarch64-genode
  • aarch64-linux
  • aarch64-netbsd
  • aarch64-none
  • aarch64-uefi
  • aarch64-windows
  • aarch64_be-none
  • arc-linux
  • arm-none
  • armv5tel-linux
  • armv6l-linux
  • armv6l-netbsd
  • armv6l-none
  • armv7a-linux
  • armv7a-netbsd
  • armv7l-linux
  • armv7l-netbsd
  • avr-none
  • i686-cygwin
  • i686-freebsd
  • i686-genode
  • i686-linux
  • i686-netbsd
  • i686-none
  • i686-openbsd
  • i686-windows
  • javascript-ghcjs
  • loongarch64-linux
  • m68k-linux
  • m68k-netbsd
  • m68k-none
  • microblaze-linux
  • microblaze-none
  • microblazeel-linux
  • microblazeel-none
  • mips-linux
  • mips-none
  • mips64-linux
  • mips64-none
  • mips64el-linux
  • mipsel-linux
  • mipsel-netbsd
  • mmix-mmixware
  • msp430-none
  • or1k-none
  • powerpc-linux
  • powerpc-netbsd
  • powerpc-none
  • powerpc64-linux
  • powerpc64le-linux
  • powerpcle-none
  • riscv32-linux
  • riscv32-netbsd
  • riscv32-none
  • riscv64-linux
  • riscv64-netbsd
  • riscv64-none
  • rx-none
  • s390-linux
  • s390-none
  • s390x-linux
  • s390x-none
  • sh4-linux
  • vc4-none
  • wasm32-wasi
  • wasm64-wasi
  • x86_64-cygwin
  • x86_64-darwin
  • x86_64-freebsd
  • x86_64-genode
  • x86_64-linux
  • x86_64-netbsd
  • x86_64-none
  • x86_64-openbsd
  • x86_64-redox
  • x86_64-solaris
  • x86_64-uefi
  • x86_64-windows