Created: February 9, 2019

Last modified: May 29, 2023

Configuration for this Website

This is the entire configuration for this website including the css styling and org-publish configuration. The features this website supports can be seen here. Ideas for features I’d like to implement in the future can be found here.


Doom One Dark Theme

@media (prefers-color-scheme: dark) {
    :root {
        --bg        : #282c34;
        --fg        : #bbc2cf;
        --bg-alt    : #21242b;
        --fg-alt    : #5B6268;
        --base0     : #1B2229;
        --base1     : #1c1f24;
        --base2     : #202328;
        --base3     : #23272e;
        --base4     : #3f444a;
        --base5     : #5B6268;
        --base6     : #73797e;
        --base7     : #9ca0a4;
        --base8     : #DFDFDF;
        --grey      : #3f444a;
        --red       : #ff6c6b;
        --i-red     : #ce537a;
        --orange    : #da8548;
        --green     : #98be65;
        --i-green   : #2d9574;
        --teal      : #4db5bd;
        --yellow    : #ECBE7B;
        --blue      : #51afef;
        --dark-blue : #2257A0;
        --magenta   : #c678dd;
        --violet    : #a9a1e1;
        --cyan      : #46D9FF;
        --dark-cyan : #5699AF;

Doom One Light Theme

@media (prefers-color-scheme: light) {
    :root {
        --bg        : #fafafa;
        --fg        : #383a42;
        --bg-alt    : #f0f0f0;
        --fg-alt    : #c6c7c7;
        --base0     : #f0f0f0;
        --base1     : #e7e7e7;
        --base2     : #dfdfdf;
        --base3     : #c6c7c7;
        --base4     : #9ca0a4;
        --base5     : #383a42;
        --base6     : #202328;
        --base7     : #1c1f24;
        --base8     : #1b2229;
        --grey      : #9ca0a4;
        --red       : #e45649;
        --i-red     : #e45649;
        --orange    : #da8548;
        --green     : #50a14f;
        --i-green   : #50a14f;
        --teal      : #4db5bd;
        --yellow    : #986801;
        --blue      : #4078f2;
        --dark-blue : #a0bcf8;
        --magenta   : #a626a4;
        --violet    : #b751b6;
        --cyan      : #0184bc;
        --dark-cyan : #005478;


Much of this is from org-html-style-default

body {
  font-family: "Helvetica Neue", Helvetica, sans-serif;
  color: var(--fg);
  background-color: var(--bg);
  max-width: 42em;
  margin: auto;

#preamble {
  text-align: center;
#postamble {
  text-align: center;
  margin: 2em;
.menu {
  display: inline-block;
  padding: 0.2em;
  position: relative;
  background-color: var(--base0);
  border-radius: 0.2em;
button {
  border: none;
  background-color: inherit;
  font-size: inherit;
  font: inherit;
  cursor: pointer;
  color: var(--blue);
button:hover {
  text-decoration: underline;

.menu-btn {
  display: inline-block;
  width: 6em;
  transition: all 0.2s ease;
  color: var(--fg);
  padding: 0.3em;
  margin: 0.2em;
  border-radius: 0.2em;
  border: 2px solid var(--magenta);
  fill: var(--fg);
.menu-btn:hover {
  background-color: var(--magenta);
  color: var(--base0);
  fill: var(--base0);

a {
  color: var(--blue);
  background-color: inherit;
  font: inherit;
  text-decoration: inherit;
a:hover {
  text-decoration: underline;
.title  { text-align: center;
          margin-bottom: .2em; }
.subtitle { text-align: center;
            font-size: medium;
            font-weight: bold;
            margin-top:0; }
.todo   { font-family: monospace; color: red; }
.done   { font-family: monospace; color: green; }
.priority { font-family: monospace; color: orange; }
.tag    { background-color: #eee; font-family: monospace;
          padding: 2px; font-size: 80%; font-weight: normal; }
.timestamp { color: var(--fg-alt); }
.timestamp-kwd { color: var(--dark-cyan); }
.org-right  { margin-left: auto; margin-right: 0px;  text-align: right; }
.org-left   { margin-left: 0px;  margin-right: auto; text-align: left; }
.org-center { margin-left: auto; margin-right: auto; text-align: center; }
.underline { text-decoration: underline; }
#postamble p, #preamble p { font-size: 90%; margin: .2em; }
p.verse { margin-left: 3%; }

table { border-collapse:collapse; }
caption.t-above { caption-side: top; }
caption.t-bottom { caption-side: bottom; }
td, th { vertical-align:top;  }  { text-align: center;  }   { text-align: center;   } { text-align: center; }  { text-align: right;  }   { text-align: left;   } { text-align: center; }
dt { font-weight: bold; }
.footpara { display: inline; }
.footdef  { margin-bottom: 1em; }
.figure { padding: 1em; }
.figure p { text-align: center; }
.equation-container {
  display: table;
  text-align: center;
  width: 100%;
.equation {
  vertical-align: middle;
.equation-label {
  display: table-cell;
  text-align: right;
  vertical-align: middle;
.inlinetask {
  padding: 10px;
  border: 2px solid gray;
  margin: 10px;
  background: #ffffcc;
{ text-align: right; font-size: 70%; white-space: nowrap; }
textarea { overflow-x: auto; }
.linenr { font-size: smaller }
.code-highlighted { background-color: #ffff00; }
.org-info-js_info-navigation { border-style: none; }
{ font-size: 10px; font-weight: bold; white-space: nowrap; }
{ background-color: #ffff00; color: #000000; font-weight: bold; }
.org-svg { width: 90%; }
.org-src-container { }
.org-ul {}

org classes

.org-builtin {color: var(--magenta);}
.org-comment {color: var(--fg-alt);}
.org-comment-delimiter {color: var(--fg-alt);}
.org-constant {color: var(--violet);}
.org-css-property {color: var(--green);}
.org-css-selector {color: var(--blue);}
.org-doc {color: #83898d;}
.org-font-latex-bold {font-weight: bold;}
.org-font-latex-math {color: var(--green);}
.org-font-latex-script-char {color: var(--dark-blue);}
.org-font-latex-sedate {color: #d3d3d3;}
.org-function-name {color: var(--magenta);}
.org-keyword {color: var(--blue);}
.org-operator {}
.org-whitespace-line {
  color: var(--red);
  background-color: var(--base0);
  font-weight: bold;
.org-negation-char {
  color: var(--blue);
  font-weight: bold;
.org-org-block {
  background-color: var(--base3);
.org-org-block-begin-line {
  color: var(--fg-alt);
  background-color: var(--base3);
.org-org-block-end-line {
  color: var(--fg-alt);
  background-color: var(--base3);
.org-org-meta-line {color: #83898d;}
.org-org-target {text-decoration: underline;}
.org-rainbow-delimiters-depth-1 {color: var(--blue);}
.org-rainbow-delimiters-depth-2 {color: var(--magenta);}
.org-rainbow-delimiters-depth-3 {color: var(--green);}
.org-rainbow-delimiters-depth-4 {color: var(--violet);}
.org-rainbow-delimiters-depth-5 {color: var(--teal);}
.org-rainbow-delimiters-depth-6 {color: var(--blue);}
.org-rainbow-delimiters-depth-7 {color: var(--magenta);}
.org-rainbow-delimiters-depth-8 {color: var(--green);}
.org-rainbow-delimiters-depth-9 {color: var(--violet);}
.org-regexp-grouping-backslash {
  color: var(--blue);
  font-weight: bold;
.org-regexp-grouping-construct {
  color: var(--blue);
  font-weight: bold;
.org-sh-heredoc {color: var(--green);}
.org-sh-quoted-exec {
  color: var(--blue);
  font-weight: bold;
.org-string {color: var(--green);}
.org-type {color: var(--yellow);}
.org-variable-name {color: #dcaeea;}
.org-warning {color: var(--yellow);}
.org-diff-added {
  color: var(--green);
  background-color: var(--bg-alt);
.org-diff-changed {
  color: var(--violet);
.org-diff-changed-unspecified {
  color: var(--violet);
  background-color: #333333;
.org-diff-context {}
.org-diff-error {
  color: #ff0000;
  background-color: #000000;
  font-weight: bold;
.org-diff-file-header {color: var(--blue);}
.org-diff-function {color: var(--cyan);}
.org-diff-header {color: var(--cyan);}
.org-diff-hunk-header {color: var(--violet);}
.org-diff-index {color: var(--blue);}
.org-diff-indicator-added {
  color: #22aa22;
  background-color: var(--bg-alt);
.org-diff-indicator-changed {color: #aaaa22;}
.org-diff-indicator-removed {
  color: #aa2222;
  background-color: var(--base3);
.org-diff-nonexistent {color: var(--blue);}
.org-diff-refine-added {
  color: var(--green);
  background-color: var(--bg-alt);
.org-diff-refine-changed {color: var(--violet);}
.org-diff-refine-removed {
  color: var(--red);
  background-color: var(--base3);
.org-diff-removed {
  color: var(--red);
  background-color: var(--base3);

Source Code

pre {
  border: 1px solid #e6e6e6;
  border-radius: 3px;
  padding: 8pt;
  font-family: monospace;
  overflow: auto;
  margin: 1.2em;
pre.src {
  position: relative;
  overflow: auto;
pre.src:before {
  display: none;
  position: absolute;
  top: -8px;
  right: 12px;
  padding: 3px;
  color: #555;
  background-color: #f2f2f299;
pre.src:hover:before { display: inline; margin-top: 14px;}
pre.src-C:before { content: 'C'; }
pre.src-css:before { content: 'CSS'; }
pre.src-dot:before { content: 'Graphviz'; }
pre.src-calc:before { content: 'Emacs Calc'; }
pre.src-emacs-lisp:before { content: 'Emacs Lisp'; }
pre.src-elisp:before { content: 'Emacs Lisp'; }
pre.src-fortran:before { content: 'Fortran'; }
pre.src-haskell:before { content: 'Haskell'; }
pre.src-js:before { content: 'Javascript'; }
pre.src-latex:before { content: 'LaTeX'; }
pre.src-lisp:before { content: 'Lisp'; }
pre.src-lua:before { content: 'Lua'; }
pre.src-org:before { content: 'Org mode'; }
pre.src-python:before { content: 'Python'; }
pre.src-jupyter-python:before { content: 'Jupyter Python'; }
pre.src-jupyter-julia:before { content: 'Jupyter Julia'; }
pre.src-ruby:before { content: 'Ruby'; }
pre.src-scheme:before { content: 'Scheme'; }
pre.src-sed:before { content: 'Sed'; }
pre.src-sh:before { content: 'shell'; }
pre.src-makefile:before { content: 'Makefile'; }
pre.src-perl:before { content: 'Perl'; }
pre.src-shell:before { content: 'Shell Script'; }
pre.src-cpp:before  { content: 'C++'; }
pre.src-bash:before  { content: 'bash'; }
pre.src-html:before { content: 'HTML'; }
pre.src-prolog:before { content: 'Prolog'; }
pre.src-tex:before { content: 'TeX'; }
pre.src-plain-tex:before { content: 'Plain TeX'; }
pre.src-conf:before { content: 'Configuration File'; }


@licstart  The following is the entire license notice for the
JavaScript code in this tag.

Copyright (C) 2012-2019 Free Software Foundation, Inc.

The JavaScript code in this tag is free software: you can
redistribute it and/or modify it under the terms of the GNU
General Public License (GNU GPL) as published by the Free Software
Foundation, either version 3 of the License, or (at your option)
any later version.  The code is distributed WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the GNU GPL for more details.

As additional permission under GNU GPL version 3 section 7, you
may distribute non-source (e.g., minimized or compacted) forms of
that code without the copy of the GNU GPL normally required by
section 4, provided you include this license notice and a URL
through which recipients can access the Corresponding Source.

@licend  The above is the entire license notice
for the JavaScript code in this tag.
 function CodeHighlightOn(elem, id)
   var target = document.getElementById(id);
   if(null != target) {
     elem.cacheClassElem = elem.className;
     elem.cacheClassTarget = target.className;
     target.className = "code-highlighted";
     elem.className   = "code-highlighted";
 function CodeHighlightOff(elem, id)
   var target = document.getElementById(id);
     elem.className = elem.cacheClassElem;
     target.className = elem.cacheClassTarget;


<script src="/scripts.js" type="text/javascript"></script>
<link href="/styles.css" rel="stylesheet" type="text/css">
<link href="/favicon.svg" rel="icon" type="image/svg+xml">
<div class="menu">
<a class="menu-btn" href="/">Akira Kyle</a>
<span style="color: var(--func);">|</span>
<a class="menu-btn" href="/blog">Blogoroam</a>
MathJax = {
  chtml: {
    displayAlign: "center",
    displayIndent: "0em",
    scale: 1
  svg: {
    scale: 1
  tex: {
    tags: "ams",
    multlineWidth: "85%",
    tagSide: "right",
    tagIndent: ".8em",
    autoload: {
      color: [],
      colorV2: ['color']
    packages: {'[+]': ['physics']}
  options: {
    ignoreHtmlClass: 'tex2jax_ignore',
    processHtmlClass: 'tex2jax_process'
  loader: {
    load: ['[tex]/physics']
<script type="text/javascript" id="MathJax-script" async

Emacs Lisp org-publish

See How I publish my wiki with org-publish for another take on exporting org-roam using org-publish.

(setq my-org-dir (file-name-as-directory "~/org"))
(setq my-org-publish-dir (file-name-as-directory "~/www/org"))
(setq my-website-publish-dir (file-name-as-directory "~/www/"))

List of notes/pages

(setq my-notes-dir (file-name-as-directory (concat my-org-dir "notes")))

(defun my-org-get-env-key (post-filename key)
  "Extract the value of `#+title:`, `#+author:`, `#+date:`, or `#+filetags:`
from post-filename."
  (with-temp-buffer (insert-file-contents post-filename)
                    (cadar (org-collect-keywords (list key)))))

(defun my-notes-filenames ()
  "Returns a list of all files sorted approprately."
   (directory-files my-notes-dir t ".*\\.org$" nil)
   (lambda (a b)
     (org-time-string-to-seconds (my-org-get-env-key a "date"))
     (org-time-string-to-seconds (my-org-get-env-key b "date"))))))

(defun my-filenames-to-org-list (post-filenames)
   (lambda (acc el) (concat acc "\n- " el))
   (seq-map (lambda (fname)
                `(:date ,(org-element-parse-secondary-string
                          (my-org-get-env-key fname "date")
                          (org-element-restriction 'keyword))) "%Y-%m-%d")
               ": "
                (concat "file:" (file-relative-name fname))
                (my-org-get-env-key fname "title"))))

org roam export backlinks and reflinks and citations

  • insert-bibliography eliminates the need for #+print_bibliography: at the end of every file
    • my-filter-citations makes org citations link to the corresponding org-roam nodes
      • I didn’t end up trying to use the csl formatter to get the nice, configurable inline style, but rather just make the org-roam title close to what the csl formatter would do (yeah this is hacky).
;; TODO: Still need to fix spacing
(defun my-filter-citations (data backend info)
  (let* ((cite-to-id
          (lambda (el)
            (let* ((key (concat "@" (org-element-property :key el)))
                   (node (org-roam-node-from-ref key))
                   (_ (and (not node) (error "No org roam node for key %s" key)))
                   (id (org-roam-node-id node))
                   (title (org-roam-node-title node)))
              (org-link-make-string (concat "id:" id) title))))
          (lambda (elts)
                (insert (concat " (" (mapconcat cite-to-id elts "; ") ") "))
                (car (org-element-map (org-element-parse-buffer) 'paragraph
          (lambda (el)
            (unless (org-element-property :style el)
              (mapc (lambda (l) (org-element-insert-before l el))
                    (funcall cites-to-ids (org-element-contents el)))
              (org-element-extract-element el)))))
    (org-element-map data 'citation map-citation info nil nil t)

(defun insert-bibliography (backend)
  "Insert reflinks into the end of the org file before parsing it."
  (when (eq backend 'html)
    (goto-char (point-min))
    (when (re-search-forward "\\[cite:.*\\]" nil t)
      (goto-char (point-max))
      (insert "\n\n* References:\n")
      (insert "#+print_bibliography: :title \"References\""))))

(defun collect-backlinks-string (backend)
  "Insert backlinks into the end of the org file before parsing it."
  (when (and (or (eq backend 'html) (eq backend 'html-with-cite-filter))
    (let* ((backlinks (org-roam-backlinks-get (org-roam-node-at-point))))
      (when backlinks
        (goto-char (point-max))
        (insert "\n\n* Backlinks:\n")
        (dolist (backlink backlinks)
          (let* ((source-node (org-roam-backlink-source-node backlink))
                 (point (org-roam-backlink-point backlink)))
             (format "- [[id:%s][%s]]\n"
                     (file-name-nondirectory (org-roam-node-id source-node))
                     (org-roam-node-title source-node)))))))))

(defun collect-reflinks-string (backend)
  "Insert reflinks into the end of the org file before parsing it."
  (when (and (or (eq backend 'html) (eq backend 'html-with-cite-filter))
    (let* ((reflinks (org-roam-reflinks-get (org-roam-node-at-point))))
      (when reflinks
        (goto-char (point-max))
        (insert "\n\n* Reflinks:\n")
        (dolist (reflink reflinks)
          (let* ((source-node (org-roam-reflink-source-node reflink))
                 (point (org-roam-reflink-point reflink)))
            (unless (string= (org-roam-node-id source-node)
                             (org-roam-node-id (org-roam-node-at-point)))
               (format "- [[id:%s][%s]]\n"
                       (file-name-nondirectory (org-roam-node-id source-node))
                       (org-roam-node-title source-node))))))))))

publish config

(let* ((named-element (org-element-map (org-element-parse-buffer) org-element-all-elements
                        (lambda (element)
                          (when (string= (org-element-property :name element) name)
                        nil t))
       (result (org-element-property :value named-element)))
  (format "\"%s\"" (replace-regexp-in-string "\\\"" "\\\\\"" result))) ;; escape quote
;; I use the ~#+modified:~ property rather than org's default of using the
;; file's modification time, since my org files are in git
(defun my-org-html-build-preamble (info)
  (let* ((spec (org-html-format-spec info))
         (date (cdr (assq ?d spec)))
         (timestamp-format (plist-get info :html-metadata-timestamp-format))
         (modified-str (cadar (org-collect-keywords '("modified"))))
         (modified-parsed (org-element-parse-secondary-string
                           modified-str (org-element-restriction 'keyword)))
         (modified (org-export-get-date `(:date ,modified-parsed)
     (and (plist-get info :with-date)
          (org-string-nw-p date)
          (format "<p class=\"date\">Created: %s</p>\n" date))
     (and (plist-get info :with-date)
          (org-string-nw-p modified)
          (format "<p class=\"date\">Last modified: %s</p>\n" modified)))))

;;(setq org-export-async-init-file (expand-file-name "~/notebook/setup.el")
;;      org-export-in-background t)
(setq org-html-metadata-timestamp-format "%B %e, %Y")
(setq org-html-htmlize-output-type 'css)
(setq org-html-html5-fancy t)
(setq org-html-doctype "html5")
(setq org-export-with-toc nil)
(setq org-export-with-section-numbers nil)
(setq org-export-time-stamp-file nil)
(setq org-html-head-include-default-style nil)
(setq org-html-head-include-scripts nil)
(setq org-html-head
(setq org-html-preamble 'my-org-html-build-preamble)
(setq org-html-postamble nil)
(setq org-html-mathjax-template

;; for org-html-link to omit .html from a href links
(setq org-html-extension "")

(org-export-define-derived-backend 'html-with-cite-filter 'html)

(defun my-org-html-publish-to-html (plist filename pub-dir)
  (org-publish-org-to 'html filename ".html" plist pub-dir))

(defun my-org-html-publish-to-html-with-cite-filter (plist filename pub-dir)
  (let ((org-export-filter-parse-tree-functions '(my-filter-citations)))
    (org-publish-org-to 'html-with-cite-filter filename ".html" plist pub-dir)))

(add-hook 'org-export-before-processing-functions 'insert-bibliography)
(add-hook 'org-export-before-processing-functions 'collect-backlinks-string)
(add-hook 'org-export-before-processing-functions 'collect-reflinks-string)

(setq collab-url "collab/")

(defun my-publish-dir-with-cite-filter (dir)
    :base-directory ,(concat my-org-dir dir)
    :publishing-directory ,(concat my-website-publish-dir collab-url dir)
    :publishing-function my-org-html-publish-to-html-with-cite-filter))

(defun my-publish-dir (dir)
    :base-directory ,(concat my-org-dir dir)
    :publishing-directory ,(concat my-website-publish-dir dir)
    :publishing-function my-org-html-publish-to-html))
    ;;:html-postamble "Insert comments here..."))

(setq org-publish-project-alist
        ,(cons "top" (cdr (my-publish-dir "")))
        ,(my-publish-dir "config")
        ,(my-publish-dir "notes")
        ,(my-publish-dir "present")
        ,(my-publish-dir-with-cite-filter "ref-notes")
        ,(my-publish-dir-with-cite-filter "notebook")
        ,(my-publish-dir-with-cite-filter "rough")
        ; :exclude "info/.*\\|rough/.*\\|notebook/.*\\|ref-notes/.*"
        ; :recursive t)
         :base-directory ,my-org-dir
         :publishing-directory ,my-website-publish-dir
         :base-extension "svg"
         :publishing-function org-publish-attachment)
        ("website" :components ("top" "config" "notes" "present" "resources"))

(defun my-tangle-website-js-css ()
  (org-babel-tangle-file (concat my-org-dir "config/")
                         (concat my-website-publish-dir "styles.css")
  (org-babel-tangle-file (concat my-org-dir "config/")
                         (concat my-website-publish-dir "scripts.js")
(org-publish "website" t)

Need to run org-id-update-id-locations and org-roam-update-org-id-locations when exporting and get “org-export-data: Unable to resolve link”

Preview with simple-httpd

(require 'simple-httpd)

(defun httpd-gen-path (path &optional root)
  "Translate GET to secure path in ROOT (`httpd-root')."
  (let ((clean (expand-file-name (httpd-clean-path path) (or root httpd-root))))
    (if (file-directory-p clean)
        (let* ((dir (file-name-as-directory clean))
               (indexes (cl-mapcar (apply-partially 'concat dir) httpd-indexes))
               (existing (cl-remove-if-not 'file-exists-p indexes)))
          (or (car existing) dir))
      (if (file-exists-p clean)
        (concat clean ".html")))))

(setq httpd-root my-website-publish-dir)
(setq httpd-listings t)
(setq httpd-host "")