BUCKYVERSE

Buckyverse: Elixir Static Site Generator with LaTeX → MathML

Project Overview

Build a static site generator in Elixir that converts Markdown content with LaTeX math into HTML with native MathML. Designed for hosting digitized out-of-print books, specifically R. Buckminster Fuller's works.


Technical Stack


Project Structure

buckyverse/
├── lib/
│   ├── buckyverse/
│   │   ├── application.ex
│   │   ├── library.ex              # Content loading
│   │   ├── library/
│   │   │   ├── book.ex             # Book struct
│   │   │   ├── chapter.ex          # Chapter struct
│   │   │   └── page.ex             # Page struct
│   │   ├── latex/
│   │   │   ├── parser.ex           # NimbleParsec LaTeX parser
│   │   │   ├── mathml.ex           # AST → MathML renderer
│   │   │   └── tex4ht.ex           # Fallback to tex4ht
│   │   ├── markdown/
│   │   │   └── renderer.ex         # MD + LaTeX → HTML
│   │   ├── templates/
│   │   │   ├── layout.ex           # HTML layout
│   │   │   ├── page.ex             # Page template
│   │   │   ├── home.ex             # Home page template
│   │   │   └── components.ex       # Reusable components
│   │   ├── build.ex                # Static site generator
│   │   └── watch.ex                # Dev server with live reload
│   └── buckyverse.ex
├── priv/
│   ├── books/                      # Content directory
│   │   └── synergetics/
│   │       ├── _book.yaml          # Book metadata
│   │       ├── 100-universe/
│   │       │   ├── _chapter.yaml   # Chapter metadata
│   │       │   ├── 00-index.md
│   │       │   └── 01-universe.md
│   │       └── figures/
│   │           └── fig-100.01.svg
│   └── static/
│       ├── css/
│       │   └── style.css
│       └── js/
│           └── app.js
├── _site/                          # Build output
├── mix.exs
└── README.md

Phase 1: Project Setup

1.1 Create new Elixir project

mix new buckyverse --sup
cd buckyverse

1.2 Configure mix.exs

Dependencies:

Mix aliases:

1.3 Create directory structure

Create all directories listed in project structure above.


Phase 2: Data Structures

2.1 Book struct (lib/buckyverse/library/book.ex)

Fields:

2.2 Chapter struct (lib/buckyverse/library/chapter.ex)

Fields:

2.3 Page struct (lib/buckyverse/library/page.ex)

Fields:


Phase 3: LaTeX Parser

3.1 Parser (lib/buckyverse/latex/parser.ex)

Use NimbleParsec to build a LaTeX math parser.

Tokens to support:

Structures to support:

Parser output: AST with tagged tuples like:

3.2 MathML Renderer (lib/buckyverse/latex/mathml.ex)

Convert AST to MathML string.

MathML elements to generate:

Public API:

3.3 High-level LaTeX module (lib/buckyverse/latex.ex)

Public API:

Try pure Elixir parser first, fall back to tex4ht if configured.

3.4 tex4ht fallback (lib/buckyverse/latex/tex4ht.ex)

For complex expressions the parser can't handle:

  1. Build minimal LaTeX document
  2. Run make4ht with mathml option
  3. Extract <math> element from output
  4. Return MathML string

Requires TeX Live with tex4ht installed on system.


Phase 4: Markdown Renderer

4.1 Renderer (lib/buckyverse/markdown/renderer.ex)

Process content in order:

  1. Convert display math - Replace $$...$$ with MathML block div
  2. Convert inline math - Replace $...$ with MathML inline
  3. Convert markdown - Headers, bold, italic, links, images, code blocks, paragraphs
  4. Extract TOC - Find all h2/h3/h4 with IDs, return list of %{level, id, text}

Header conversion:

Paragraph handling:

Return: {html, toc}


Phase 5: Content Loading

5.1 Library module (lib/buckyverse/library.ex)

Public API:

Loading logic:

  1. Scan priv/books/ for directories
  2. For each book directory, load _book.yaml
  3. Scan for chapter directories (matching ^\d+-)
  4. For each chapter, load _chapter.yaml if exists
  5. Scan for .md files in chapter
  6. Parse frontmatter and render content for each page
  7. Build nested struct hierarchy

Frontmatter parsing:

Slug extraction:


Phase 6: HTML Templates

6.1 Layout template (lib/buckyverse/templates/layout.ex)

Full HTML document with:

6.2 Page template (lib/buckyverse/templates/page.ex)

Three-column layout:

6.3 Components (lib/buckyverse/templates/components.ex)

sidebar(book, nav_tree, current_page):

page_nav(book, prev_page, next_page):

toc(items):

6.4 Home template (lib/buckyverse/templates/home.ex)

6.5 Book index template


Phase 7: Static Site Builder

7.1 Build module (lib/buckyverse/build.ex)

run() function:

  1. Delete _site/ if exists
  2. Create _site/
  3. Build all books (pages as nested directories)
  4. Build home page
  5. Copy static assets
  6. Build search index JSON

For each book:

  1. Create _site/{book_slug}/
  2. Write index.html (book index)
  3. For each page:
    • Create _site/{book_slug}/{chapter_slug}/{page_slug}/
    • Calculate prev/next pages
    • Render page template
    • Wrap in layout
    • Write index.html
  4. Copy figures/ directory if exists

Search index:


Phase 8: Development Server

8.1 Watch module (lib/buckyverse/watch.ex)

  1. Run initial build
  2. Start FileSystem watcher on priv/books/ and priv/static/
  3. Start simple HTTP server on port 4000 serving _site/
  4. On file change events, rebuild affected content
  5. Log rebuild activity

Use :inets httpd or :plug_cowboy for HTTP server.


Phase 9: Styling

9.1 CSS (priv/static/css/style.css)

Layout:

Sidebar styling:

Content styling:

Math styling:

Navigation:

Responsive:


Phase 10: Sample Content

10.1 Book metadata (priv/books/synergetics/_book.yaml)

title: "Synergetics"
subtitle: "Explorations in the Geometry of Thinking"
author: "R. Buckminster Fuller"
year: 1975
description: |
  Fuller's comprehensive exploration of geometric thinking
  and the coordinate system of nature.

10.2 Chapter metadata (priv/books/synergetics/100-universe/_chapter.yaml)

title: "Universe"
section: "100"

10.3 Sample page (priv/books/synergetics/100-universe/01-universe.md)

---
title: Universe
section: "100.00"
---

## 100.00 Universe

**100.01** Universe is the aggregate of all humanity's consciously 
apprehended and communicated experience.

**100.02** The fundamental equation relating energy and mass is:

$$E = mc^2$$

where $m$ represents mass and $c$ the speed of light.

**100.03** Consider the quadratic formula:

$$\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$$

**100.04** A matrix example:

$$\begin{pmatrix} a & b \\ c & d \end{pmatrix}$$

Build & Run Commands

# Install dependencies
mix deps.get

# Build static site
mix bucky.build

# Development server with watch
mix bucky.watch

# Preview built site
cd _site && python3 -m http.server 8000

# Test math parser in IEx
iex -S mix

IEx testing:

alias Buckyverse.LaTeX
alias Buckyverse.LaTeX.{Parser, MathML}

# Parse and render
{:ok, ast} = Parser.parse("E = mc^2")
MathML.render(ast)

# High-level API
LaTeX.to_mathml!("\\frac{a}{b}", display: true)

Deployment

Static output in _site/ can be deployed to:


Future Enhancements

  1. Full-text search - Client-side with Lunr.js or server-side with Haystack
  2. PDF generation - Use tex4ht or Tectonic for downloadable PDFs
  3. Phoenix LiveView - Dynamic version with instant navigation
  4. Ash Framework - Structured domain layer for content
  5. Cross-references - Parse \ref{} and \label{} for internal linking
  6. Bibliography - BibTeX support with citations
  7. Figures - Enhanced figure handling with captions and numbering
  8. Comments/Annotations - User annotations with persistence

Key Implementation Notes

LaTeX Parser Tips

MathML Tips

Content Loading Tips


Estimated Timeline

Phase Description Effort
1 Project setup 1 hour
2 Data structures 30 min
3 LaTeX parser + MathML 4-6 hours
4 Markdown renderer 2 hours
5 Content loading 2 hours
6 HTML templates 2 hours
7 Static builder 1 hour
8 Dev server 1 hour
9 CSS styling 2 hours
10 Sample content 30 min

Total: ~16-20 hours


This plan is self-contained and can be executed in a new chat session. Start with Phase 1 and work through sequentially. Each phase builds on the previous ones.