Playing Hisorty

On <2026-04-23 Thu> I saw Hisorty website and played it.

Other similar quizes:

Hisorty [2026-05-03 Sun]
260503--hisorty__screenshot.png
Hisorty [2026-05-02 Sat]

Topic: computers 260502--hisorty__screenshot.png

Hisorty [2026-04-26 Sun]
260426--hisorty__screenshot.png
Hisorty [2026-04-23 Thu]
260423--hisorty__screenshot.jpg
NYT Flashback [2026-04-25 Sat]

25 points 🟥🟩🟩🟩🟩🟩🟩🟩

NYT Flashback [2026-04-18 Sat]

25 points 🟩🟩🟩🟩🟩🟩🟥🟩

TIMDLE [2026-04-26 Sun]
260426--timdle__screenshot.png
TIMDLE [2026-04-23 Thu]
260423--timdle__screenshot.jpg

Hosting static HTMLs

While I'm on vacation and Mac Mini 2024 (my home server) is turned off, I wanted to host HackerNews legible frontend (html file) on the Internet with minimum setup as possible.

Obvious choices like Cloudflare Workers, Github Pages and all their variants were ruled out as they require accounts, backed by big corps while I wanted something indy.

Playing with Surge, made me realise it's a nice way to host static html artifacts created with AI, so here it is: https://hotter.surge.sh.

Operations
(let ((default-directory "~/Developer/src/github.com/velppa/hotter.surge.sh"))
  (async-shell-command
    ;; "surge --help"
    ;; "surge files hotter.surge.sh"
    ;; "surge . hotter.surge.sh" ;; deploy
    "make deploy"
    "*hotter.surge.sh*"))

(setq surge-server (ws-file-server :dir "~/Developer/src/github.com/velppa/hotter.surge.sh" :port 9004))
(ws-stop surge-server)

Window configuration on m4pro

MacBook Pro M4 Pro has larger screen and windows in Emacs behave differently, often ending up with 6 windows at once. That's not what I want.

Time to learn Window management in Emacs.

On <2026-04-21 Tue> I switched to ace-window from other-window and keeping track of what has changed.

Keybindings:

Good:

Bad:

Things to try:

textpod.el v0.3.0

Another round of improvements of textpod.el, a companion Emacs package to Textpod.

Custom ID format - attribute name and prefix

Added two defcustom options in textpod.el:

  • textpod-id-property (default "TEXTPOD_ID") - name of the Org property used to store the note id.
  • textpod-id-prefix (default "") - prefix prepended to ids when stored, stripped before sending requests to the server.

Introduced textpod--strip-prefix helper and updated all id call sites (textpod-open-current-note, textpod-org-heading-to-note, textpod-org-region-to-note) to respect these configs.

textpod-set-id sets ID without creating a node

I need a function to create texpod id property without sending note to the server. This is needed to submit old notes so they have proper timestamp.

Added textpod-set-id: an interactive command that sets textpod-id-property on the current heading (with textpod-id-prefix) derived from a time as YYYYMMDDhhmmss, without making any HTTP request.

  • No prefix arg → uses (current-time).
  • With prefix arg → prompts via org-read-date, so the note can be back-dated before later uploading with textpod-org-heading-to-note.
Quickly getting to Textpod notes

Using Ack is possible, placing point on a file-name and pressing {H-RET} will call visit-source and go directly to the line.

ack ":ID:\s*textpod_" *.org | grep -v 2026-04-22 | head -n 20

2026-04-12.org:226::ID: textpod_20260412124048
2026-04-13.org:10::ID: textpod_20260414214110
2026-04-13.org:237::ID: textpod_20260414212612
2026-04-13.org:247::ID: textpod_20260414224720
2026-04-13.org:263::ID: textpod_20260414210103
2026-04-13.org:314::ID: textpod_20260414224944
2026-04-16.org:12::ID: textpod_20260416100352
2026-04-16.org:97::ID: textpod_20260417092822
2026-04-21.org:205::ID: textpod_20260421120000

Since I made my Textpod notes to be Org-roam notes, I can query them directly from SQLite DB.

  • (sqlite-mode-open-file "~/.config/emacs/org-roam.db")

    select id, file, title from nodes n where n.id like '"textpod_%"';

textpod_20260329123259 ~/Notes/2026-03.org Standalone HTML Galleries
textpod_20260315124829 ~/Notes/2026-03.org Build HackerNews Legible Frontend
textpod_20260415130636 ~/Notes/2026-04.org Improve public notes
textpod_20260415205822 ~/Notes/2026-04.org “Why Kim Wexler Was The Real Villain of Better Call Saul” by BreakingHub (19 min)
textpod_20260415210948 ~/Notes/2026-04.org “Linus Lays down the Law” – The PrimeTime (ThePrimeagen), 13 min
textpod_20260412124048 ~/Notes/daily/2026-04-12.org Improve HackerNews Legible Frontend
textpod_20260414214110 ~/Notes/daily/2026-04-13.org Interview about k8s setup in Amazon
textpod_20260414212612 ~/Notes/daily/2026-04-13.org kumo – local AWS emulator in Go
textpod_20260414224720 ~/Notes/daily/2026-04-13.org Snowflake MCP server
textpod_20260414210103 ~/Notes/daily/2026-04-13.org Claude Code quota exhausted / degraded quality
textpod_20260414224944 ~/Notes/daily/2026-04-13.org Trying Textpod once again
textpod_20250612070826 ~/Notes/html.org I'm betting on HTML
textpod_20260421120000 ~/Notes/daily/2026-04-21.org Rewrite Textpod to Go
textpod_20260416100352 ~/Notes/daily/2026-04-16.org Advice to org-roam-dailies-goto-today
textpod_20260417092822 ~/Notes/daily/2026-04-16.org Links <2026-04-16 Thu>
textpod_20260422124810 ~/Notes/daily/2026-04-22.org textpod.el v0.3.0

[TK: :colnames yes got broken for some reason].

My textpod.el config

The config automatically makes notes published to Textpod as Org-roam nodes.

(use-package textpod
  :config
  (setq textpod-id-property "ID"
        textpod-id-prefix "textpod_"
        textpod-token (cadr (auth-source-user-and-password "finita.myaddr.dev" "textpod"))
        ;;textpod-url "/notes"
        textpod-url "http://localhost:3000/notes"
        )
  :bind (("C-c b x" . textpod-set-id)
         ("C-c b b" . textpod-org-heading-to-note)
         ("C-c b o" . textpod-open-current-note)))

Updates:

  • <2026-04-23 Thu>: add keybindings

I'm on vacation, in free time setting up new MacBook Pro machine.

20260423T173752--m4pro-on-vacation__life-1.jpg

Rewrite Textpod to Go

On <2026-04-21 Tue> I rewritten Textpod from Rust to Go.

While I'm on vacation with the new MacBook Pro M4 Pro and I have installed only bare minimum on it, I don't have Rust toolchain but do have Go. So, asked Claude to do rewrite. The only external dependency is goldmark package to render Markdown as HTMLs.

Updated Elisp helpers:

(use-package textpod
  :config
  (setq textpod-token (cadr (auth-source-user-and-password "finita.myaddr.dev" "textpod"))
        ;;textpod-url "/notes"
        textpod-url "http://localhost:3000/notes"
        ))

(let ((default-directory "~/Developer/src/github.com/velppa/textpod"))
  (async-shell-command "go build -o ~/.local/bin/textpod ." "*textpod-build*"))

(let ((default-directory "~/Developer/src/github.com/velppa/finita-la-comedia/textpod")
      (buffer-name "*textpod-server*"))
  (when (get-buffer buffer-name)
    (kill-buffer buffer-name))
  (async-shell-command (format "textpod --token %s --base-path notes" textpod-token) buffer-name))

(browse-url (format "%s?token=%s" textpod-url textpod-token))

Links <2026-04-16 Thu>

Advice to org-roam-dailies-goto-today

Currently, when calling org-roam-dailies-goto-today, {C-c n d} for me, Emacs switches to the daily note buffer, but moves point to (point-min). I want to advice to first check if the buffer with "YYYY-MM-DD.org" (for today) already exists, and if so, switch to this buffer. Related to Org-roam.

Here's an advice function to achieve that:

(defun my-org-roam-dailies-goto-today-advice (orig-fun &rest args)
  "Switch to today's daily note buffer/window if it exists, otherwise create it.
Preserves point position if buffer already exists."
  (let* ((today (format-time-string "%Y-%m-%d"))
         (daily-buffer-name (concat today ".org"))
         (existing-buffer (get-buffer daily-buffer-name))
         (existing-window (and existing-buffer
                               (get-buffer-window existing-buffer t))))
    (cond
     ;; Buffer is already displayed in a window - switch to that window
     (existing-window
      (select-window existing-window))
     ;; Buffer exists but not displayed - switch to it in current window
     (existing-buffer
      (switch-to-buffer existing-buffer))
     ;; Buffer doesn't exist - create it
     (t
      (apply orig-fun args)))))

(advice-add 'org-roam-dailies-goto-today
            :around #'my-org-roam-dailies-goto-today-advice)

This advice:

  1. Checks for buffer by name (not file path)
  2. If the buffer is displayed in any window (even in another frame), selects that window
  3. If the buffer exists but isn't displayed, switches to it in the current window
  4. Otherwise calls the original function

To remove the advice later:

(advice-remove 'org-roam-dailies-goto-today
               #'my-org-roam-dailies-goto-today-advice)

Improve public notes

Next round of improving Textpod on <2026-04-15 Wed>.

Deploy publicly –

Introduced --base-path flag, to serve notes under sub-path.

To start Textpod with sub-path, use:

textpod --token $TEXTPOD_TOKEN --base-path notes
Publish textpod.el to the repository

textpod.el is a companion Emacs package for quick publishing notes from Org Mode documents.

Install it like this:

(use-package textpod
  :config
  (setq textpod-token (cadr (auth-source-user-and-password "finita.myaddr.dev" "textpod")))
  (setq textpod-url "/notes"))

Then these helper functions do the heavy-lifting:

  • textpod-org-region-to-note: Convert the Org region between BEG and END to Markdown and send to Textpod.
  • textpod-org-heading-to-note: Send the current heading’s subtree to Textpod.
  • textpod-open-current-note: Open the current heading’s Textpod note in a browser.

When creating a note, textpod.el sets TEXTPOD_ID property that's equal to node'id.

Change separator in notes.md to ^L

Default separator \n\n---\n\n is fragile as it requires exactly two newlines before / after the note. I often messed up notes when editing notes.md file manually. To fix that, I replaced it with ^L character (insert in Emacs via C-q C-l) which usually represents new pages.

Fix attachments links

Attachement links need to respect --base-path flag.

Handling attachments

My current workflow:

  • Assets are stored next to Notes under assets/ directory

  • I can quickly search for them, then open in Emacs/qView:

    find ../assets -name "*prefix-in-emacs*"
    
    ../assets/m-g-prefix-in-emacs.png
    ../assets/m-s-prefix-in-emacs.png
    
  • I can reference an asset as an image: img

  • An image is a link to an image file that does not have a description part (Images (The Org Manual)).

  • Textpod already support images. What happens when I drag-n-drop an image file to the textarea? Textpod copies them under attachments directory.

What I want:

  • When creating a public note containing an image via API (using textpod.el), copy the asset to assets/ directory, mimicing the directory structure in the notes.
  • I need another API endpoint - POST /notes/assets/<name>, accepting binary as payload.

Okay, I implemented it, let's test.

textpod-org-heading-to-note

Prompt: Implement textpod-org-heading-to-note function, it should select current (top) heading - the one that has TEXTPOD_ID parameter, and call textpod-org-region-to-note on it.

The command {M-x textpod-org-heading-to-note} works!

Should the textpod id be just id?

Currently I use TEXTPOD_ID property. If using ID property, notes will automatically become Org-roam nodes. Currently IDs are generated as timestamps via (setq org-id-method 'ts) with nanoseconds precision. Then it will come with seconds precision. I will need to a prefix, to be able to quickly find them (e.g. with {M-x deadgrep}).

Wrap h3 into details on index page

To declutter the index page, h3 markdown headings (h2 Org headings) are wrapped into <details> tag. The note page renders normally, showing table of contents on the left sidebar.