A mindful learning platform theme for Hugo that prioritizes content as the sole visual figure. Designed for creating reading-centered digital interfaces with a focus on lectures, slides, and notes using an "invisible interface" philosophy.
- Two Content Modes: Presentations (horizontal slides) and Documents (vertical reading)
- PDF & Jupyter Notebook Support: Embed and display PDFs and notebooks with automatic page generation
- Custom Markdown Syntax: Slide delimiters, column splits, and slide types
- Mathematical Expressions: Full LaTeX support via MathJax
- Enhanced Code Blocks: Syntax highlighting with line numbers and language indicators
- Smart Navigation: Keyboard, scroll, and touch gesture support
- Automatic Heading Anchors: Click-to-copy URLs for document sections
- Colorblind-Friendly: Carefully chosen color palette for accessibility
- Typography Optimized: Merriweather font optimized for sustained reading
- Hugo Extended v0.112.0 or higher
- Git (for theme installation)
Add to your config.toml:
[module]
[[module.imports]]
path = "github.com/FabioSol/Lykeion"
[markup]
[markup.highlight]
noClasses = false
lineNos = true
lineNumbersInTable = true
[markup.goldmark]
[markup.goldmark.extensions]
[markup.goldmark.extensions.passthrough]
enable = true
[markup.goldmark.extensions.passthrough.delimiters]
block = [['\[', '\]'], ['$$', '$$']]
inline = [['\(', '\)'], ['$', '$']]Then run:
hugo mod init github.com/FabioSol/{your repo}
hugo mod get -ucreate a content directory.
follow the structure:
content/
├── _index.md # front page
└── lectures/
├── _index.md # type lecture
└── {your lectures}/
├── _index.md # type lecture
└── file.md # type document or presentation
-
[markup.highlight] noClasses = false: This is required for proper syntax highlighting with the theme's color scheme. Without this, code blocks will not be styled correctly. -
[markup.goldmark.extensions.passthrough]: This enables LaTeX math rendering via MathJax. Without this configuration, mathematical expressions will not render properly — Markdown will parse LaTeX syntax (e.g., underscores_as emphasis) before MathJax can process it.
Lykeion provides two distinct content types optimized for different use cases:
Horizontal slide-based layout perfect for lectures, talks, and presentations.
Create a new presentation:
hugo new content/lectures/my-lecture/presentation.mdExample frontmatter:
---
title: "Introduction to Hugo"
date: 2025-01-08
draft: false
type: "presentation"
description: "A comprehensive introduction to static site generation"
showTitleSlide: true
weight: 1
math: true
---Vertical scrolling layout optimized for long-form reading and documentation.
Create a new document:
hugo new content/lectures/my-lecture/document.mdExample frontmatter:
---
title: "Hugo Documentation"
date: 2025-01-08
draft: false
type: "document"
description: "Complete guide to using Hugo"
showDescription: true
weight: 2
math: false
---Lykeion provides first-class support for embedding PDF documents and Jupyter notebooks directly into your site.
The theme includes a content generation script that automatically creates Hugo pages for PDFs and Jupyter notebooks found in your content directory.
Quick Setup:
-
Install the content generator:
hugo mod get -u github.com/FabioSol/Lykeion bash -c "$(curl -fsSL https://raw.githubusercontent.com/FabioSol/Lykeion/main/scripts/install-hooks.sh)" -
Add PDFs or Jupyter notebooks to your content:
content/ └── lectures/ └── 01-introduction/ ├── slides.pdf └── analysis.ipynb -
Run the generator:
./generate-content.sh
This will automatically create .gen.md files (e.g., slides.gen.md, analysis.gen.md) with the proper frontmatter and shortcodes.
Integration Options:
Add to your Makefile:
generate:
./generate-content.sh
serve: generate
hugo serve
build: generate
hugo buildOr add to package.json:
{
"scripts": {
"generate": "./generate-content.sh",
"dev": "npm run generate && hugo serve",
"build": "npm run generate && hugo build"
}
}Or add to GitHub Actions (before Hugo build):
- name: Generate content for PDFs and Notebooks
run: |
chmod +x ./generate-content.sh
./generate-content.shImportant: Add *.gen.md to your .gitignore since these files are auto-generated.
You can also manually embed PDFs and notebooks using shortcodes:
PDF Shortcode:
---
title: "Course Slides"
type: embedded
embedded_type: pdf
---
{{< pdf "lectures/01-introduction/slides.pdf" >}}Notebook Shortcode:
---
title: "Data Analysis"
type: embedded
embedded_type: notebook
---
{{< notebook "lectures/01-introduction/analysis.ipynb" >}}The paths are relative to your content directory.
- PDFs: Embedded in responsive iframes with full viewport support
- Jupyter Notebooks: Client-side rendering with interactive outputs preserved
- Automatic Navigation: PDF and notebook pages integrate with the theme's navigation system
- Custom Titles: Auto-generated from filenames, or manually specified in frontmatter
Use three hyphens on a new line to create a new slide:
# First Slide
Content for the first slide
---
# Second Slide
Content for the second slideTo display literal --- without creating a slide break, escape it:
\---Define slide layouts by adding [type] immediately after the delimiter:
---[title]
# Section Title
Brief description or subtitle
---[content]
## Regular Content Slide
Standard layout with content
---[title-content]
# Title at Top
%%%
## Column 1
Content here
%%%
## Column 2
More content hereAvailable slide types:
[content]- Standard full-width slide (default)[title]- Large, centered title slide for section breaks[title-content]- Title at top with multi-column grid below
Use three percent signs to create columns within a slide:
---[title-content]
# Multi-Column Slide
%%%
## Left Column
- Point 1
- Point 2
%%%
## Middle Column
- Point 3
- Point 4
%%%
## Right Column
- Point 5
- Point 6To display literal %%%, escape it:
\%%%The grid automatically adapts to the number of columns (2, 3, or more).
Lykeion supports full LaTeX math syntax via MathJax.
Use single dollar signs or \( \):
Einstein's famous equation is $E = mc^2$.
Alternatively: \(E = mc^2\)Use double dollar signs or \[ \]:
$$
f(x) = \int_{-\infty}^{\infty} \hat{f}(\xi) e^{2\pi i \xi x} d\xi
$$Or:
\[
\frac{d}{dx} \left( \int_{a}^{x} f(t) dt \right) = f(x)
\]$$
\begin{aligned}
\nabla \times \vec{\mathbf{B}} - \frac{1}{c} \frac{\partial\vec{\mathbf{E}}}{\partial t} &= \frac{4\pi}{c}\vec{\mathbf{j}} \\
\nabla \cdot \vec{\mathbf{E}} &= 4 \pi \rho \\
\nabla \times \vec{\mathbf{E}} + \frac{1}{c} \frac{\partial\vec{\mathbf{B}}}{\partial t} &= \vec{\mathbf{0}} \\
\nabla \cdot \vec{\mathbf{B}} &= 0
\end{aligned}
$$All GitHub-flavored markdown is fully supported:
# Heading 1
## Heading 2
### Heading 3
#### Heading 4
##### Heading 5
###### Heading 6**Bold text**
*Italic text*
~~Strikethrough~~
`Inline code`Unordered list:
- Item 1
- Item 2
- Nested item
- Another nested item
Ordered list:
1. First item
2. Second item
1. Nested item
2. Another nested item- [x] Completed task
- [ ] Pending task
- [ ] Another pending task> This is a blockquote.
> It can span multiple lines.
>
> And multiple paragraphs.Use triple backticks with language identifier:
```python
def hello_world():
print("Hello, World!")
```
```javascript
function helloWorld() {
console.log("Hello, World!");
}
```
```bash
echo "Hello, World!"
```Code blocks automatically include:
- Line numbers
- Language indicator header
- Syntax highlighting (100+ languages supported)
| Left Aligned | Center Aligned | Right Aligned |
|:-------------|:--------------:|--------------:|
| Cell 1 | Cell 2 | Cell 3 |
| Cell 4 | Cell 5 | Cell 6 |[Link text](https://example.com)
[Link with title](https://example.com "Link title")
Images are automatically responsive and sized appropriately.
---Note: In presentations, --- creates a new slide. Use \--- to display a horizontal rule.
In document-type content, every heading automatically gets:
- A unique anchor ID
- A clickable hyperlink icon on hover
- Click-to-copy URL functionality
- Smooth scroll navigation
Hover over any heading to reveal the link icon, then click to copy the full URL and jump to that section.
←/→- Navigate between slides (presentations) or sibling pages↑/↓- Navigate to parent/child or previous/next pagesSpace- Next slide (presentations)Home- First slide (presentations)End- Last slide (presentations)
- Scroll/Swipe - Navigate through slides or sections with overscroll detection
- Touch Swipe - Horizontal swipes change slides in presentations
- Mouse Wheel - Overscroll triggers navigation to adjacent content
The navigation system uses intelligent direction detection:
- Requires 5x ratio for wheel events (prevents accidental triggers)
- Requires 2x ratio for touch events
- 500ms debounce to prevent false navigation
A bottom indicator shows dots for each slide:
- Current slide highlighted
- Click any dot to jump to that slide
- Updates automatically as you navigate
A side navigation panel shows all headings:
- Hierarchical display with proper nesting
- Click to jump to any section
- Hover to reveal heading text
- Visual size variations by heading level
Documents automatically calculate bottom padding to ensure:
- The last section can be scrolled to viewport center
- No content is cut off by the bottom edge
- Responsive to window resizing
content/
└── lectures/
├── _index.md
├── 01-introduction/
│ ├── _index.md
│ ├── presentation.md
│ ├── features-document.md
│ ├── slides.pdf # Auto-generates slides.gen.md
│ └── notebook-demo.ipynb # Auto-generates notebook-demo.gen.md
├── 02-advanced/
│ ├── _index.md
│ ├── presentation.md
│ └── reference.md
└── 03-examples/
├── _index.md
└── demo.md
Each section can contain:
- Multiple presentations
- Multiple documents
- PDF files (auto-converted to pages)
- Jupyter notebooks (auto-converted to pages)
- Nested subsections
- Any combination of content types
Use the weight parameter in frontmatter to control ordering:
---
title: "First Lecture"
weight: 1
---The theme uses Merriweather, a serif typeface optimized for sustained reading on screens. It provides:
- Excellent readability at various sizes
- Multiple weights (300-900) with italic variants
- Proper optical sizing for different contexts
- High legibility in low-light conditions
Font files are included in WOFF2 format for optimal performance.
Lykeion uses an OKLCH-based color system that is:
- Perceptually uniform - Equal changes in values result in equal perceptual changes
- Colorblind-friendly - Colors chosen for maximum accessibility
- High contrast - Ensures readability in various lighting conditions
The syntax highlighting palette is specifically designed to be distinguishable by users with various types of color vision deficiency.
The theme is built on 9 evidence-based design principles:
- Content as Sole Visual Figure - Interface recedes, content dominates
- Clear Visual Hierarchy - Typography guides structure
- Cognitive Chunking - Content in manageable units
- Spatial Rhythm - Consistent whitespace creates flow
- Typography for Reading - Font selection prioritizes legibility
- Saccadic Efficiency - Line length optimized for eye movement
- Minimal Interaction Cost - Navigation requires minimal effort
- Effortless Orientation - Consistent navigation patterns
- Progressive Disclosure - Complexity revealed gradually
The theme works in all modern browsers that support:
- CSS Grid
- ES6 Modules
- CSS Custom Properties
- WOFF2 fonts
- MathJax 4
Tested on:
- Chrome/Edge 90+
- Firefox 88+
- Safari 14+
Ensure you have added the math passthrough configuration to your config.toml. This is required to prevent Markdown from parsing LaTeX syntax — without it, underscores in equations like $x_1 + y_2$ will be rendered as italic text instead of subscripts.
[markup.goldmark.extensions.passthrough]
enable = true
[markup.goldmark.extensions.passthrough.delimiters]
block = [['\[', '\]'], ['$$', '$$']]
inline = [['\(', '\)'], ['$', '$']]Also ensure math: true is set either globally in [params] or in the page frontmatter.
Make sure you have set:
[markup.highlight]
noClasses = falseThis is critical for the theme's syntax highlighting to work properly.
Verify you are using exactly three hyphens on a new line with blank lines before and after:
Content before
---
Content afterCheck that:
- JavaScript is enabled in your browser
- Content files have proper
weightvalues in frontmatter - Content is organized in sections with
_index.mdfiles
To work on the theme locally:
git clone https://github.com/fabiosolorzano/Lykeion.git
cd Lykeion
hugo server --source exampleSiteThe example site demonstrates all theme features.
MIT License - see LICENSE file for details.
Created by Fabio Solorzano
Built with Hugo, the world's fastest static site generator.
Typography powered by Merriweather by Sorkin Type.
Math rendering by MathJax.
- GitHub Issues: https://github.com/fabiosolorzano/Lykeion/issues
- Documentation: See the example site in
/exampleSite
Contributions are welcome! Please feel free to submit a Pull Request.