hela

An expressive resume theme for Zola — each step of one's life adds stones to the stream as it carves gently through the earth.

Live demo

Hela resume homepage with a circular portrait, dark indigo palette, and stone-marked stream layout

Features

Installation

Requires Zola 0.23.4 or later; this demo is validated with 0.23.4.

From your Zola site's root, add the theme as a Git submodule:

git submodule add https://git.colorized.life/demo.helaardstrom.net.git themes/hela

Alternatively, clone it into the same directory:

git clone https://git.colorized.life/demo.helaardstrom.net.git themes/hela

Set the top-level theme = "hela" in your site's zola.toml, as shown below.

The theme repository is also a standalone demo: run zola check, zola build, or zola serve from its root without adding a theme setting.

Minimal configuration

Minimal consumer configuration (zola.toml):

base_url = "https://example.com"
title = "My Site"
theme = "hela"
compile_sass = true
build_search_index = false

[extra]
site_title = "My Site"
copyright_holder = "Your Name"
footer_links = []

[extra.resume]
name = "Your Name"
nav_links = []

Add your portrait as static/profile.jpg. Empty navigation arrays avoid linking to pages you have not created. Theme defaults include sample resume data; override those fields with your own content. Optional routes below require content in your site; theme installation alone does not create those pages. For a blog, create content/blog/_index.md using the front matter shown under Feed below, then add dated Markdown posts. Use template = "links.html" for links pages, "palette.html" for the palette, and "page.html" for ordinary pages.

Full options

Theme defaults

The following block exactly matches the active [extra] defaults in theme.toml. Commented examples in that file are optional customizations, not defaults.

[extra]
site_title = "My Site"
copyright_holder = "Your Name"
footer_links = [{ name = "acknowledgements", path = "/acknowledgements" }]


[extra.resume]
name = "First Last"
contact = [
  { text = "email@example.com", url = "mailto:email@example.com" },
  { text = "example.com", url = "https://example.com" },
]
summary = "Two-line professional impact statement goes here."
skills = ["Skill One", "Skill Two", "Skill Three", "Skill Four"]

nav_links = [
  { name = "blog", path = "/blog" },
  { name = "git", url = "https://example.com" },
  { name = "links", path = "/links" },
]
KeyTheme default / fallbackDescription
site_title"My Site"Homepage heading when resume.name is absent; final template fallback is "My Site"
copyright_holder"Your Name"; config.title if absentFooter copyright link text
copyright_urlUnset; config.base_urlOptional footer copyright URL override
footer_linksAcknowledgements link above{ name, path }; path accepts a local path or an absolute URL, not a url key
feed_pathUnset; no feed buttonFeed directory without a trailing slash; the footer appends /atom.xml
resumeSample data aboveHeader, navigation, summary, skills, experience, and education
colorsUnset; built-in paletteOptional color overrides described under Customization
palette_names, palette_rolesUnset; built-in labelsOptional labels for the five palette keys

Consumer customization example, separate from the theme defaults:

[extra]
copyright_url = "https://example.com"
footer_links = [
  { name = "acknowledgements", path = "/acknowledgements" },
  { name = "sites", path = "/sites" },
]

Branded demo configuration excerpt (the source link stays second in the footer):

[extra]
footer_links = [
  { name = "home", path = "/" },
  { name = "source", path = "https://git.colorized.life/demo.helaardstrom.net/about/" },
  { name = "palette", path = "/palette" },
  { name = "acknowledgements", path = "/acknowledgements" },
  { name = "sites", path = "/sites" },
]

The footer renders path directly, including absolute URLs. The demo source link reaches the repository without a deployment redirect.

Feed

Consumer customization for zola.toml (keep top-level keys before [extra]):

feed_filenames = ["atom.xml"]

[extra]
feed_path = "/blog"

Consumer section front matter for content/blog/_index.md:

+++
title = "Blog"
template = "blog.html"
page_template = "post.html"
sort_by = "date"
paginate_by = 4
generate_feeds = true
+++

feed_path only adds the footer button; section feed generation creates /blog/atom.xml. Omit feed_path when no feed exists.

Pages

RouteTemplateDescription
/index.htmlResume landing page
/blogblog.htmlPaginated blog listing
/blog/*post.htmlIndividual blog post
/linkslinks.htmlExternal links (header nav)
/siteslinks.htmlCross-site family navigation (footer)
/palettepalette.htmlColor palette reference
/acknowledgementspage.htmlFont and tool credits

Resume data

Resume content is driven from [extra.resume] in your zola.toml. The following snippets are consumer customization examples; merge them into the existing table rather than repeating TOML table headers. Fields absent from the effective configuration are skipped, except the name heading, which falls back to site_title. Theme defaults supply the sample values above.

[extra.resume]
name = "First Last"
professional_title = "Software Engineer"
contact = [
  { text = "email@example.com", url = "mailto:email@example.com" },
  { text = "example.com", url = "https://example.com" },
]
summary = "Two-line professional impact statement goes here."
skills = ["Skill One", "Skill Two", "Skill Three", "Skill Four"]
KeyDescription
nameDisplay name, rendered as an <h1> at 700 weight
professional_titleSubtitle displayed under the name in muted color (optional)
contactArray of { text, url } entries, stacked vertically
summaryShort impact statement rendered in the Profile stream section
skillsArray of strings, comma-separated in the Skills stream section

Contact items without a url render as plain text. Items with a url render as links.

[extra.resume]
nav_links = [
  { name = "blog", path = "/blog" },
  { name = "git", url = "https://example.com" },
  { name = "links", path = "/links" },
]

Navigation links support path (local or absolute) and url (external); url takes precedence when supplied. Rendered as the first stream section, capped by a stone at the top of the stream line.

Experience

[[extra.resume.experience]]
company = "Company Name"
positions = [
  { title = "Senior Engineer", start = "2022", end = "Present", items = [
    "Accomplishment one",
    "Accomplishment two",
  ] },
]

Each [[extra.resume.experience]] entry represents a company. Multiple positions within the same company are listed under positions.

KeyDescription
companyCompany name (Syne Mono, muted color)
positionsArray of position objects
titlePosition title (Syne)
startStart date
endEnd date
itemsArray of bullet point strings (optional)

Education

[[extra.resume.education]]
school = "State University"
date = "2016"
degree = "B.S. Computer Science"
KeyDescription
schoolSchool name (Syne Mono, muted)
dateYear or date range (Syne Mono, muted)
degreeDegree name (Syne)

Consumer links-page front matter uses [extra] with url, name, and description:

[[extra.links]]
name = "example.com"
url = "https://example.com"
description = "Description text"

Customization

CSS tuning knobs

The resume stylesheet (sass/_resume.scss) exposes tunable values marked with // knob: comments. All values can be adjusted directly in the file.

Desktop

Variable / SelectorDefaultDescription
$stream-x14remHorizontal position of stream line (label column width)
$label-pad-left5remLeft padding on section headers
$stream-line-w2pxStream line thickness
$stream-gap1.25remGap between stream line and content
$stone-size8pxStone diameter
$stream-overhang1remHow far stream line extends past last section
$label-big-size2.8remBB header big letters font-size
$label-rest-size1.1remBB header rest text font-size
$nav-offset-y-1.2remShifts nav content vertically
.resume-header gap2.5remSpace between photo and text stack
.resume-photo width/height200pxProfile picture size (keep square)
.resume-name font-size4remName size (largest text on page)
.resume-title font-size1.5remProfessional title size
.resume-contact gap0.15remVertical spacing between contact lines

Per-section content vertical offsets ($content-y-*) and per-stone vertical offsets ($stone-y-*) are also available for fine alignment.

Mobile (max-width: 600px)

VariableDefaultDescription
$mobile-stream-x-1remStream line position (into container padding)
$mobile-photo-size140pxMobile photo size
$mobile-name-size2.8remMobile name size
$mobile-label-size1.875remMobile BB header font-size
$mobile-section-gap2remSpace between sections
$mobile-stream-trim-top1remTrims the start of the stream line downward

Colors

Add [extra.colors] to your zola.toml to override any color. Only the keys you specify change. Consumer customization example:

[extra.colors]
bg = "#1a1a2e"
accent = "#e8a0b4"
KeyDefaultRole
bg#1a1a2ePage background
text#f5f5f5Primary text
muted#a090b0Metadata text, nav links
accent#e8a0b4Link hover color
glow#7ec8e8Vertical separator color

Palette labels

The palette page displays five fixed swatches. Consumer customization example for names and roles:

[extra.palette_names]
bg = "Space Indigo"
text = "White Smoke"
muted = "Amethyst Smoke"
accent = "Prism Pink"
glow = "Seagull"

[extra.palette_roles]
bg = "Background"
text = "Foreground"
muted = "Muted text"
accent = "Accent"
glow = "Accent"

Sass variables (sass/_variables.scss)

Built-in Sass defaults:

$font-body: "Syne", sans-serif !default;
$font-mono: "Syne Mono", monospace !default;
$container-max: 860px !default;

License

MIT; see LICENSE.