mel.rocks

org-mode html publishing reference

Introduction

This post documents various org-mode snippets and processes for producing the html you see on this screen.

Why org-mode?

org-mode is a great way to organize text documents in emacs.

The editor makes interacting with the elements and organizing them very simple.
The text output is also easily consumable and parseable.

It’s just text, but its annotated in such a way that interacting with it programmatically becomes fairly trivial.

org elements

org documents are made up of “elements”.

Major elements
  • Headings

    Headings are used to define structures and sections.

    All of the headings in this document are annotated this way.

     * Level 1
     ** Level 2
     *** Level 3
    

    The more *’s you add the further your hierarchy will nest.

  • Lists

    Lists can be ordered

    1. One
    2. Two
    3. Three
    

    Unordered

     One Two Three
    
  • Tables

    Tables are just data structured with pipes

    | Column A | Column B | Column C |
    | row 1 a  | row 2 a  | row 3 c  |
    | row 2 a  | row 2 a  | row 2 c  |
    

    When exporting to html they get rendered like regular <table> elements

    Column A Column B Column C
    row 1 a row 2 a row 3 c
    row 2 a row 2 a row 2 c
  • Blocks
  • Keywords & Properties
  • Timestamps
  • TODO items
Objects

The Setup

The basic structure is simple:

mel.rocks/
├── org/          # Source files
│   ├── posts/    # Blog posts
│   └── pages/    # Static pages
├── public/       # Generated HTML
└── publish.el    # Configuration

Writing Posts

Creating a new post is as simple as:

#<buffer 2025-12-10-my-new-post.org>

Then add the metadata:

TITLE: My New Post
AUTHOR: Your Name
DATE:  2025-12-10 Tue 
DESCRIPTION: A brief description

Your content goes here...

Publishing Workflow

The entire publishing process is handled by a single command:

make build  # Generate HTML
make serve  # Preview locally
make deploy # Push to Cloudflare

Code Examples

Org-mode handles code blocks beautifully. Here’s a Python example:

def hello_world():
    """A simple greeting function."""
    return "Hello from org-mode!"

print(hello_world())

And some JavaScript:

const greet = (name) => {
    return `Hello, ${name}!`;
};

console.log(greet("World"));

Tables

org-mode tables are cool. you define them as plain text like so

| Feature     | Markdown | Org-Mode  |
|-------------+----------+-----------|
| Tables      | Limited  | Excellent |
| Code Blocks | Good     | Excellent |
| Linking     | Basic    | Advanced  |
| Export      | HTML     | Multiple  |

Seems simple enough but when you interact with them in emacs it balances everything for you and allows for excel like functionality.

When you input the same table as part of the doc the publishing tool renders it like so as html:

Feature Markdown Org-Mode
Tables Limited Excellent
Code Blocks Good Excellent
Linking Basic Advanced
Export HTML Multiple

Images and Media

Files

Adding images is straightforward:

[[file:../img/screenshot.png]]

You can also add captions and attributes:

#+CAPTION: My awesome screenshot
#+ATTR_HTML: :width 600px :alt Screenshot description
[[file:../img/screenshot.png]]

URLs

I added a special rule where instead of specifying file: in the tag you specify img: to treat a URL as an image tag.

#+CAPTION: A keyboard, I think.
#+ATTR_HTML: :width 600px
[[img:https://upload.internetz.club/cxd6nToc]]
cxd6nToc
A keyboard, I think.

Deployment to Cloudflare Pages

Cloudflare Pages makes hosting simple and free:

  1. Push your code to GitHub
  2. Connect Cloudflare Pages to your repository
  3. Set build command: emacs --batch -q --load publish.el
  4. Set output directory: public

Every push to main triggers a new deployment automatically.

Tips and Tricks

Use Snippets

Create yasnippet templates for common post formats:

# -*- mode: snippet -*-
# name: blogpost
# key: blog
# --
#+TITLE: ${1:Title}
#+AUTHOR: Mel Gray
#+DATE: `(format-time-string "<%Y-%m-%d %a>")`
#+DESCRIPTION: ${2:Description}
#+KEYWORDS: ${3:keywords}

$0

Preview While Writing

Use org-preview-html-mode or run a local server:

make serve &  # Run in background
make watch    # Auto-rebuild on changes

Organize with Tags

Use tags for categorization:

**My Post Title : emacs : programming : tutorial :

Conclusion

This setup gives me everything I need:

  • Simple writing experience in Emacs
  • Version control with Git
  • Complete control over the output