What's this?

The December Adventure is low key. The goal is to write a little bit of code every day in December …doesn’t even really have to be code! Let the December Adventure be for all kinds of creative pursuits.
— eli, December Adventure

IRC: #decadv @ irc.libera.chat:6697
Fediverse tag: #DecemberAdventure

📆 Use the calendar below to jump to an entry

Su Mo Tu We Th Fr Sa
  01 02 03 04 05 06
07 08 09 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      

05

Initial draft of a camera system in Trial: camera.lisp - Only added mouse movement for now. Not really happy with it though. There's something weird happening where if I move the mouse rapidly in circles, the camera will start to pan away. I need to re-read the learnopengl articles on matrices and the camera system they have you implement. That's all for tonight, real life has been pulling me away constantly this week unfortunately.

04

  • Started work on Trial, and added a new page for my ongoing chaotic notes of it: trial — nothing there will be of interest to anyone but myself, so making it public is for my own sake: it strangely keeps me motivated.
  • Mostly spent my time reading over Trial code and figuring out how to interact with the scene graph

Trial is CLOS heavy, so generic functions are everywhere. Keep running into situations where I'm wondering what methods are actually being called in a given function invocation. It's pretty easy to find out actually, I just forgot that compute-applicable-methods exists:

(compute-applicable-methods #'enter (list (make-instance '3d-camera)
                                          (scene +main+)))
;; =>
;; (#<STANDARD-METHOD TRIAL:ENTER (CAMERA SCENE) {1003AA8083}>
;;  #<STANDARD-METHOD TRIAL:ENTER :BEFORE (SCENE-NODE CONTAINER) {10032313A3}>
;;  #<STANDARD-METHOD TRIAL:ENTER :AFTER (SCENE-NODE CONTAINER) {1003231383}>
;;  #<STANDARD-METHOD TRIAL:ENTER (T BAG) {100120D4C3}>)

With Slime in Emacs I can visit the source definition of each by pressing M-. (M-x slime-edit-definition) with the point at the name.

Nice.

02

  • Added a calendar to the log. Idea inspired/stolen from devine's own adventure log. Intent is that it'll be easy for folks regularly checking in to jump to the latest entry while also making chronological sense to anyone reading for the first time.
  • Fiddled with website look and settled on it, so we're moving on to our actual goal of the FPS demo. One thing to note for future logs, decadv or otherwise, is the need to set up the page/site, and any workflow, before we start. Ended up getting extremely distracted by setting it up on a moment's notice but what else can be done? At least the very existence of this log keeps reminding me of what I set out to do. Hoping any future side quests this month will stay related to game programming.

01

Alright, said I was going to focus on the FPS demo, but I sidetracked. I'm using org-publish to build my site, and it's ~okay'ish.

Emphasis on the ish

I do not like Org mode. Ten years of Emacs and I still despise it. All the options, different ways of setting options, hidden precedence of options, how difficult it is to figure out what is calling what; this thing is an ORGanic pile of spaghet. Apologies to all the skilled Emacs hackers that work on Org mode and understand it: I do not, but I do appreciate your work. It's what I fucked around with for the first day of my adventure so I'm a little grumpy but getting over it now since I can finally just write.

write

In order to just write, the yakkin was a bit of a need. The less friction the better. For the rest of the month I won't think about how any of this is getting uploaded.


Using org-publish facilities I define three projects:

  • zyd.lol/org : grab all the org files it can find recursively
  • zyd.lol/data : directory i use for attachments and the like
  • zyd.lol/assets : css etc

And a fourth 'meta' project that just builds each of the above three

  • zyd.lol
(setq org-publish-project-alist
      '(("zyd.lol/org"
         :base-extension "org"
         ;; Include file
         :exclude "base.org"
         :base-directory "~/notes/zyd.lol/"
         :publishing-directory "~/docs/zyd.lol/"
         :publishing-function org-html-publish-to-html
         :recursive t)
        ("zyd.lol/data"
         :base-extension any
         :base-directory "~/notes/zyd.lol/data/"
         :publishing-directory "~/docs/zyd.lol/data/"
         :publishing-function org-publish-attachment
         :recursive t)
        ("zyd.lol/assets"
         :base-extension any
         :base-directory "~/notes/zyd.lol/assets/"
         :publishing-directory "~/docs/zyd.lol/assets/"
         :publishing-function org-publish-attachment
         :recursive t)
        ("zyd.lol" :components ("zyd.lol/org" "zyd.lol/data" "zyd.lol/assets"))))

Each individual org file #+INCLUDE's base.org to set up some nonsense

#+OPTIONS: title:nil toc:nil html-style:nil ^:nil num:nil html5-fancy:t
#+OPTIONS: author:nil html-postamble:nil
#+HTML_DOCTYPE: html5
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="/assets/style.css"/>
#+HTML_HEAD: <link rel="icon" type="image/x-icon" href="/assets/favicon.jpg" />

To build all these files and test out path resolving as if its on an actual web server, I'm using simple-httpd.

M-x zyd/build-site and point my browser @ localhost:8080

(defun zyd/publishing-directory (project)
  (org-publish-property
   :publishing-directory
   (assoc project org-publish-project-alist)))

(defun zyd/build-site (&optional stop-server)
  (interactive "P")
  (let ((org-html-prefer-user-labels t)
        (org-export-with-broken-links t)
        (org-html-self-link-headlines t)
        (dir (zyd/publishing-directory "zyd.lol/org")))
    (org-publish "zyd.lol")
    (if stop-server (httpd-stop)
      (httpd-serve-directory dir))
    dir))

And to actually upload I'm using Sourcehut:

(defun zyd/push-site ()
  (interactive)
  (let* ((inhibit-message t)
         (site (zyd/build-site t))
         (tarball (format "%ssite.tar.gz" site)))
    (shell-command
     (format "cd %s && \
              rm -f %s && \
              tar -cvz * > %s"
             site
             tarball
             tarball))
    (async-shell-command
     (format "hut pages publish -d zyd.lol %s" tarball))))

One frustrating thing about Org that I haven't been able to 'fix' is when linking local .org files, in the HTML export they end up being transformed into anchor tags with hrefs that use the file:// protocol. I tried figuring out how I was expected to configure this but ended up just monkey patching org-html-link which is responsible for transforming org links.

(defun string-replace-> (replacements in-string)
  "Return a string after a list of string replacements '((from-string
to-string)) have been applied to IN-STRING."
  (let ((%in-string (copy-sequence in-string)))
    (pcase-dolist (`(,from-string ,to-string) replacements)
      (setq %in-string (string-replace from-string to-string %in-string)))
    %in-string))

(defun zyd/filter-org-html-links (fn &rest args)
  "Hack to replace file:// protocol links and index.html"
  (string-replace->
   '(("file://" "")
     ("/index.html" "/"))
   (apply fn args)))

(advice-add 'org-html-link :around 'zyd/filter-org-html-links)

pcase is cute and all my homies love destructuring

So that's all I wrote today. Not a lot but it took way longer than I'd care to admit, specifically figuring out how to deal with org links. It's 7PM now, maybe I can find another burst of executive function and start working on the FPS demo. Who knows.

Start!

A december adventure seems perfect for me: do something, anything, whatever amount, every day, and make note of it. My goal this month is to use Trial, a game engine written in Common Lisp, to re-implement this basic FPS demo from Raylib:

2025-12-01__00-07-58.png
Figure 1: examples/core/core_3d_camera_fps.c

It's a simple demo too. I'm basically recreating the FPS camera from my nohgl project, grounding it to the xz plane, and adding a couple of fields to simulate quake-like movement. The difficult part is figuring out the Trial-provided mechanisms to glue it all together. Once I get the ball rolling (heh), collision and other stuff can be built on top of it. Eventually, we can have an actual FPS demo that could qualify as a game.