[New Release] Whisper Engine v2.0.0

Not Just A Tool - It's Architecture

ghostware.jpg

Whisper Engine - the Emacs-based, Org Mode powered static site engine is in its new evolution.
The 1.x release series powered a lot of internal and some external DeadSwitch sites and homepages.

  • Documentations.
  • Formatted readme collections.
  • Internal articles.
  • The Silent Architect's Whispers site.

The system proved its capabilities in production use.
Like many other tools, it reached critical complexity through iterative development.

In a fast moving and secure environment - complexity can drag back the evolution.

This is the reason for the Whisper Engine v2.0 line.

Whisper Engine v2.0.0

  • It's not an entire, self-contained tool.
  • It skips the long and complex emacs-lisp code and its hooks.
  • I stripped the unnecessary complexity.

The new Whisper Engine is design and architecture around Emacs and Org Mode.

I didn't reinvent the static page generation. I reorganized it with Unix philosophy.

One tool. One task.

Architecture

Whisper Engine v2.0.0 is based on a strict design of directory and file structure.

site.tld/
├── build          <- temporary build files and timestamps
├── public         <- the rendered HTML
│   ├── articles   <- HTML articles in YYYY/MM subdirectories
│   └── static     <- static files simply copied from the source
└── source         <- every edit happens in this directory
    ├── articles   <- org files in YYYY/MM subdirectories
    ├── drafts     <- not rendered or published article and page drafts
    └── static     <- static files like css, images and fonts

The directory structure is handled by an Emacs Lisp script - whisper.el:

;;
;; Whisper Engine v2
;;

(require 'package)
(setq package-enable-at-startup nil)
(package-initialize)

(require 'ox-publish)
(require 'find-lisp)

(defconst ds/root
  (file-name-directory (or load-file-name buffer-file-name)))

(defconst ds/build-directory
  (expand-file-name "build/" ds/root))

(setq org-publish-timestamp-directory
      (expand-file-name ".org-timestamps/" ds/build-directory))

;; HTML Head
(setq org-html-head
      "<link rel=\"stylesheet\" href=\"/static/css/style.css\" type=\"text/css\" />
<link rel=\"icon\" href=\"/static/img/favicon.ico\" type=\"image/x-icon\">
<!-- Generated by Whisper Engine v2.0.0 -->")

;; Navigation
(setq org-html-preamble
      "<nav>
::
<a href=\"/index.html\">Home</a> ::
<a href=\"/static/pages/about.html\">About</a> ::
<a href=\"/static/pages/irc.html\">IRC</a> ::
<a href=\"/articles/archive.html\">Archive</a>
::
</nav>")

;; Footer
(setq org-html-postamble
      "<footer>
<p>© 2025-2026 DeadSwitch | The Silent Architect | All rights reserved.</p>
</footer>")

;; Set HTML Export Defaults
(setq org-html-validation-link nil
      org-html-head-include-scripts nil
      org-html-head-include-default-style nil
      org-export-preserve-breaks t)

;; Project Configuration
(setq org-publish-project-alist
      `(("blog-pages"
         :base-directory "./source"
         :base-extension "org"
         :publishing-directory "./public"
         :recursive nil
         :exclude "articles/"
         :publishing-function org-html-publish-to-html
         :headline-levels 4
         :with-author nil
         :with-creator nil
         :with-toc nil
         :section-numbers nil
         :time-stamp-file nil)

        ("blog-articles"
         :base-directory "./source/articles"
         :base-extension "org"
         :publishing-directory "./public/articles"
         :recursive t
         :publishing-function org-html-publish-to-html
         :with-author nil
         :with-creator nil
         :with-toc nil
         :auto-sitemap t
         :sitemap-filename "archive.org"
         :sitemap-title "Archive"
         :preserve-breaks nil
         :sitemap-style list
         :sitemap-sort-files anti-chronologically)

        ("blog-static-pages"
         :base-directory "./source/static/pages"
         :base-extension "org"
         :publishing-directory "./public/static/pages"
         :recursive t
         :publishing-function org-html-publish-to-html
         :with-author nil
         :with-creator nil
         :with-toc nil
         :preserve-breaks nil
         :sitemap-sort-files anti-chronologically)

        ("blog-2026"
         :base-directory "./source/articles/2026"
         :base-extension "org"
         :publishing-directory "./public/articles/2026"
         :recursive t
         :publishing-function org-html-publish-to-html
         :with-author nil
         :with-creator nil
         :with-toc nil
         :auto-sitemap t
         :sitemap-filename "archive-2026.org"
         :sitemap-title "Whispers From 2026"
         :preserve-breaks nil
         :sitemap-style list
         :sitemap-sort-files anti-chronologically)

         ("blog-2025"
         :base-directory "./source/articles/2025"
         :base-extension "org"
         :publishing-directory "./public/articles/2025"
         :recursive t
         :publishing-function org-html-publish-to-html
         :with-author nil
         :with-creator nil
         :with-toc nil
         :auto-sitemap t
         :sitemap-filename "archive-2025.org"
         :sitemap-title "Whispers From 2025"
         :preserve-breaks nil
         :sitemap-style list
         :sitemap-sort-files anti-chronologically)

        ("blog-static"
         :base-directory "./source/static"
         :base-extension "css\\|js\\|png\\|jpg\\|gif\\|ico\\|ttf"
         :publishing-directory "./public/static"
         :recursive t
         :publishing-function org-publish-attachment)

        ("blog"
         :components ("blog-pages"
                      "blog-articles"
                      "blog-static"
                      "blog-static-pages"
                      "blog-2026"
                      "blog-2025"))))

(provide 'whisper)

The script uses ox-publish to render the Org files into an HTML site.
The :auto-sitemap function does the heavy lifting of generating the archive pages by year.
The index page, index.org is handled manually - for full control.
The visitor experiences a controlled, easy-to-navigate initial page.

The script whisper.el is called from GNU Make.
The make targets handle the site build, full-rebuild and deployment.

.PHONY: build clean rebuild deploy

EMACS ?= emacs

build:
        @echo "Rendering the site..."
        @$(EMACS) --quick --batch --load whisper.el --funcall org-publish-all

clean:
        @echo "Cleaning the public and timestamp cache..."
        @rm -rf public/*
        @rm -rf build/.org-timestamps/*

rebuild: clean build

deploy: build
        @echo "Deploying the site..."
        cd public && git add .
        cd public && git commit -m "Publishing..."
        cd public && git push

The authoring process is simple:

  1. The article is written in /drafts.
  2. When it's ready mv drafts/article.org articles/YYYY/MM/article.org.
  3. The index.org file is modified by hand.
  4. The make build command renders the new article and the index page.
  5. The make deploy command pushes the changes to production.

Final Whisper

In the past, Whisper Engine was a self-contained, monolithic tool to generate websites.
Now, with the new version, the sites are self-contained, independent entities.

Whisper Engine moved from a complex, monolithic tool to an architecture around Emacs, Org Mode ox-publish and GNU Make.

The change builds more on the design than the tools involved in it.

Whisper Engine v2.0.0 is already serving https://silentarchitect.org.