diff --git a/.envrc b/.envrc
index e1e411c4a..5a1d8227f 100644
--- a/.envrc
+++ b/.envrc
@@ -1,7 +1,3 @@
-source_url \
- https://omnix.page/om/develop/omnixrc/v1 \
- 'sha256-FBAVRYkaexKeFKQGUxaPHqhBnqA7km7++O77dKiyD0I='
+watch_file nix/modules/flake-parts/*.nix
-watch_file nix/modules/flake-parts/*.nix om.yaml
-
-use omnix .
+use flake .
diff --git a/docs/guide/orgmode.yaml b/docs/guide/orgmode.yaml
index 852f45ca2..c03ee751f 100644
--- a/docs/guide/orgmode.yaml
+++ b/docs/guide/orgmode.yaml
@@ -1,4 +1,3 @@
page:
headHtml: |
-
diff --git a/docs/index.yaml b/docs/index.yaml
index 6212be834..a97dc975e 100644
--- a/docs/index.yaml
+++ b/docs/index.yaml
@@ -4,5 +4,3 @@ template:
page:
siteUrl: https://emanote.srid.ca
siteTitle: Emanote
- headHtml: |
-
diff --git a/docs/start/resources/editors/vim.md b/docs/start/resources/editors/vim.md
index 2019cfa8c..05391a6b4 100644
--- a/docs/start/resources/editors/vim.md
+++ b/docs/start/resources/editors/vim.md
@@ -1,10 +1,4 @@
---
-page:
- headHtml: |
-
-
-
-
slug: vim
---
diff --git a/docs/start/resources/zk.md b/docs/start/resources/zk.md
index 6230ab481..fab351b02 100644
--- a/docs/start/resources/zk.md
+++ b/docs/start/resources/zk.md
@@ -1,9 +1,5 @@
---
slug: zk
-page:
- headHtml: |
-
-
---
# zk
diff --git a/docs/tips/js/math.md b/docs/tips/js/math.md
index edad2702a..a0ec091c6 100644
--- a/docs/tips/js/math.md
+++ b/docs/tips/js/math.md
@@ -2,9 +2,7 @@
slug: math
page:
headHtml: |
-
-
---
# Math
diff --git a/docs/tips/js/mermaid.md b/docs/tips/js/mermaid.md
index cc8fb88c8..57662e947 100644
--- a/docs/tips/js/mermaid.md
+++ b/docs/tips/js/mermaid.md
@@ -1,8 +1,6 @@
---
slug: mermaid
page:
- headHtml: |
-
bodyHtml: |
---
diff --git a/docs/tips/js/syntax-highlighting.md b/docs/tips/js/syntax-highlighting.md
deleted file mode 100644
index e4ac99e7d..000000000
--- a/docs/tips/js/syntax-highlighting.md
+++ /dev/null
@@ -1,65 +0,0 @@
----
-slug: syntax-highlighting
-page:
- headHtml: |
-
----
-
-
-# Syntax Highlighting
-
-In order to enable syntax highlighting, you must use a client-side JavaScript highlighter, such as [highlight.js](https://highlightjs.org/) by adding it to `page.headHtml` of [[yaml-config|YAML configuration]] or Markdown frontmatter. Emanote already provides a snippet, so you may directly include the following in your `index.yaml` (assuming you are enabling it on all routes):
-
-```yaml
-page:
- headHtml: |
-
-```
-
-> [!warning]
-> Bear in mind that when using highlight.js you must manually add language support. The above snippet includes Haskell and [Nix](https://nixos.asia) by default; otherwise, it is normally added as:
->
-> ```yaml
-> page:
-> headHtml: |
->
->
->
->
-> ```
->
-> (The `highlightjs-ver` variable comes from the default [`index.yaml`](https://github.com/srid/emanote/blob/master/emanote/default/index.yaml).)
-
-## Example (highlight.js)
-
-### Python
-
-```python
-def fib(n):
- a, b = 0, 1
- while a < n:
- print(a, end=' ')
- a, b = b, a+b
- print()
-fib(1000)
-```
-
-### Haskell
-
-```haskell
-fib 0 = 0
-fib 1 = 1
-fib n = fib (n-1) + fib (n-2)
-```
-
-## Prism
-
-A predefined snippet also exists for another syntax highlighter called [Prism](https://prismjs.com/). To use it add the following to `page.headHtml` of [[yaml-config|YAML configuration]] or Markdown frontmatter.
-
-```yaml
-page:
- headHtml: |
-
-```
-
-> [!warning] Prism does not cooperate well with Emanote's live preview mode.
\ No newline at end of file
diff --git a/docs/tips/syntax-highlighting.md b/docs/tips/syntax-highlighting.md
new file mode 100644
index 000000000..34b0c1b05
--- /dev/null
+++ b/docs/tips/syntax-highlighting.md
@@ -0,0 +1,77 @@
+---
+slug: syntax-highlighting
+order: -1
+---
+
+# Syntax Highlighting
+
+Emanote includes built-in syntax highlighting powered by [skylighting](https://github.com/jgm/skylighting), the same library used by Pandoc. Code blocks are highlighted at build timeāno JavaScript required.
+
+## How it Works
+
+Code blocks are automatically tokenized during rendering. Each token gets a CSS class (like `kw` for keywords, `st` for strings, `co` for comments) and styled via CSS included in emanote's default theme.
+
+### Example
+
+```haskell
+-- A simple factorial function
+factorial :: Integer -> Integer
+factorial 0 = 1
+factorial n = n * factorial (n - 1)
+```
+
+```python
+def fibonacci(n):
+ """Generate fibonacci sequence up to n"""
+ a, b = 0, 1
+ while a < n:
+ yield a
+ a, b = b, a + b
+```
+
+```nix
+{ pkgs, ... }:
+{
+ environment.systemPackages = with pkgs; [
+ vim
+ git
+ ];
+}
+```
+
+## Supported Languages
+
+Skylighting supports [over 140 languages](https://github.com/jgm/skylighting/tree/master/skylighting-core/xml) including:
+
+- Haskell, Python, JavaScript, TypeScript, Rust, Go
+- Nix, Shell/Bash, YAML, JSON, TOML
+- HTML, CSS, SQL, Markdown
+- And many more...
+
+## Disabling Syntax Highlighting
+
+To disable built-in syntax highlighting (for example, to use a client-side highlighter like highlight.js instead), set in your [[yaml-config|index.yaml]]:
+
+```yaml
+emanote:
+ syntaxHighlighting: false
+```
+
+## Customizing the Theme
+
+The default theme is in `_emanote-static/skylighting.css`. To customize, create your own `_emanote-static/skylighting.css` in your notes directory to override the default.
+
+Alternatively, add custom styles in your [[yaml-config|index.yaml]]:
+
+```yaml
+page:
+ headHtml: |
+
+```
+
+See the [skylighting documentation](https://hackage.haskell.org/package/skylighting-core/docs/Skylighting-Types.html#t:TokenType) for a full list of token classes and their meanings.
diff --git a/emanote/CHANGELOG.md b/emanote/CHANGELOG.md
index 7c67ea24e..7c8e33fdf 100644
--- a/emanote/CHANGELOG.md
+++ b/emanote/CHANGELOG.md
@@ -1,5 +1,9 @@
# Revision history for emanote
+## 1.5.4.0 (2025-12-18)
+
+- Built-in static syntax highlighting using skylighting (replaces client-side JS highlighters)
+
## Unreleased
**Notable features**
diff --git a/emanote/default/_emanote-static/skylighting.css b/emanote/default/_emanote-static/skylighting.css
new file mode 100644
index 000000000..eb3cbf575
--- /dev/null
+++ b/emanote/default/_emanote-static/skylighting.css
@@ -0,0 +1,90 @@
+/* Skylighting syntax highlighting theme */
+/* To override, create your own _emanote-static/skylighting.css */
+
+/* Code block container styling */
+pre {
+ background-color: #f8f8f8;
+ border: 1px solid #e1e4e8;
+ border-radius: 6px;
+ padding: 1rem;
+ overflow-x: auto;
+}
+
+pre code {
+ background: transparent;
+ border: none;
+ padding: 0;
+}
+
+/* Dark mode code block */
+@media (prefers-color-scheme: dark) {
+ pre {
+ background-color: #1e1e1e;
+ border-color: #333;
+ }
+}
+
+/* Token colors */
+
+code span.al { color: #ff0000; font-weight: bold; } /* Alert */
+code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
+code span.at { color: #7d9029; } /* Attribute */
+code span.bn { color: #40a070; } /* BaseN */
+code span.bu { color: #008000; } /* BuiltIn */
+code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
+code span.ch { color: #4070a0; } /* Char */
+code span.cn { color: #880000; } /* Constant */
+code span.co { color: #60a0b0; font-style: italic; } /* Comment */
+code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
+code span.do { color: #ba2121; font-style: italic; } /* Documentation */
+code span.dt { color: #902000; } /* DataType */
+code span.dv { color: #40a070; } /* DecVal */
+code span.er { color: #ff0000; font-weight: bold; } /* Error */
+code span.ex { } /* Extension */
+code span.fl { color: #40a070; } /* Float */
+code span.fu { color: #06287e; } /* Function */
+code span.im { color: #008000; font-weight: bold; } /* Import */
+code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
+code span.kw { color: #007020; font-weight: bold; } /* Keyword */
+code span.op { color: #666666; } /* Operator */
+code span.ot { color: #007020; } /* Other */
+code span.pp { color: #bc7a00; } /* Preprocessor */
+code span.re { } /* RegionMarker */
+code span.sc { color: #4070a0; } /* SpecialChar */
+code span.ss { color: #bb6688; } /* SpecialString */
+code span.st { color: #4070a0; } /* String */
+code span.va { color: #19177c; } /* Variable */
+code span.vs { color: #4070a0; } /* VerbatimString */
+code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
+
+/* Dark mode overrides */
+@media (prefers-color-scheme: dark) {
+ code span.al { color: #ff6b6b; }
+ code span.an { color: #8ec8e8; }
+ code span.at { color: #a9c77d; }
+ code span.bn { color: #87ceab; }
+ code span.bu { color: #66cc99; }
+ code span.cf { color: #66cc99; }
+ code span.ch { color: #79a6d2; }
+ code span.cn { color: #e09090; }
+ code span.co { color: #8ec8e8; }
+ code span.cv { color: #8ec8e8; }
+ code span.do { color: #e08080; }
+ code span.dt { color: #e09090; }
+ code span.dv { color: #87ceab; }
+ code span.er { color: #ff6b6b; }
+ code span.fl { color: #87ceab; }
+ code span.fu { color: #79a6d2; }
+ code span.im { color: #66cc99; }
+ code span.in { color: #8ec8e8; }
+ code span.kw { color: #cc99cc; }
+ code span.op { color: #cccccc; }
+ code span.ot { color: #66cc99; }
+ code span.pp { color: #d7ba7d; }
+ code span.sc { color: #79a6d2; }
+ code span.ss { color: #cc99cc; }
+ code span.st { color: #79a6d2; }
+ code span.va { color: #9cdcfe; }
+ code span.vs { color: #79a6d2; }
+ code span.wa { color: #8ec8e8; }
+}
diff --git a/emanote/default/index.yaml b/emanote/default/index.yaml
index d4216e2ef..715de0079 100644
--- a/emanote/default/index.yaml
+++ b/emanote/default/index.yaml
@@ -107,26 +107,6 @@ page:
# Builtin JS behaviour library. Use them in `page.headHtml` of your .yaml or .md
# frontmatter.
js:
- # Syntax highlighting using prism.js
- prism: |
-
-
-
-
-
- # Syntax highlighting using highlight.js
- highlightjs: |
-
-
-
-
-
-
-
-
-
- highlightjs-ver: 11.6.0 # Ref: https://cdnjs.com/libraries/highlight.js
# Diagrams using mermaid.js
mermaid: |
@@ -176,3 +156,7 @@ emanote:
# Whether to automatically treat folder notes as a folgezettel parent of its contents
# By default, all but top-level folders are treated as folgezettel parents.
# folder-folgezettel: true
+
+ # Enable server-side syntax highlighting using skylighting (default: true)
+ # Set to false to use client-side highlighters like highlight.js instead
+ syntaxHighlighting: true
diff --git a/emanote/default/templates/styles.tpl b/emanote/default/templates/styles.tpl
index 37fafa53a..94b091aea 100644
--- a/emanote/default/templates/styles.tpl
+++ b/emanote/default/templates/styles.tpl
@@ -1,3 +1,5 @@
+
+