december adventure

table of contents

โ„๏ธ

December Adventure is an online event where people pick a project to work on , and log their progress throughout the month of December . you can see a list of adventure logs written by other people here !

2025

december 9th

today i started the documentation generator for pyra , which i'm also using as an opportunity to refine a representation of Nova rules for structural editors that i've been planning .

here's a screenshot of two rules from the painting example program , run through the docs generator :

the graphical representation of two pyra rules

and here's the original pyra code it corresponds to :

the textual representation of two pyra rules

some notes about the design :

i still need to incorporate representations for variables , strings , strides , and snippets . and possibly differentiate the causes from the effects even more .

finally , here's the compiler code that generates the HTML for this representation ( don't worry , the divs are just placeholders that'll be replaced with more accessible markup later on ) :

function formatPattern(pattern)
  if pattern.stack == ''
  then return format(
    '<div class="fact">_</div>',
    pattern.fact
  ) else return format(
    '<div class="stack">_</div><div class="fact">_</div>',
    pattern.stack, pattern.fact
  ) end
end

for _, rule in ipairs(rules) do
  iLine '<div class="rule">'
  if #rule.causes > 0 then
    iLine '<div class="causes">'
    for _, cause in ipairs(rule.causes) do
      local keep = ''
      if cause.keep then keep = ' keep' end
      local stride = ''
      if cause.stride then stride = ' stride' end
      iLine('<div class="pattern__">_</div>',
        keep, stride, formatPattern(cause))
    end
    iLine '</div>'
  end
  if #rule.effects > 0 then
    iLine '<div class="effects">'
    for i = #rule.effects, 1, -1 do
      iLine('<div class="pattern">_</div>',
        formatPattern(rule.effects[i]))
    end
    iLine '</div>'
  end
  iLine '</div>'
end

๐ŸŽง song of the day :
test & recognise [ Flume re-work ] slowed โ€” Seekae


december 8th

i finished more today than i expected ! it feels like the daily cognitive context-loading of December Adventure allowed me to venture deeper into the flow state than usual . changes :

tomorrow , it'll be time to start writing the library documentation generator , which i've been quite excited for !

๐ŸŽง song of the day :
ใ‚นใƒ†ใƒƒใƒ—ใƒใ‚คใ‚นใƒ†ใƒƒใƒ— โ€” Macroblank


december 7th

today i finished organizing the pyra libraries ! so refreshing . here are the libraries we've got now :

another thing that'll make the imports cleaner is to add a separate import type for standard libraries that lets you omit the path and extension . that means something like this :

~ include file:
  ../../libraries/one.nv
  ../../libraries/two.nv
  ../../libraries/three.nv

can be written like this :

~ use library: one two three

much shorter , and less fragile ! tomorrow i'll update the examples to use the new libraries in this way .

woah woah WOAH . hold up . you're tellin' me that the song of the day was concocted by autumn this time ? that's right :

๐ŸŽง song of the day :
waddle fractal โ€” autumn nebulae


december 6th

today i began restructuring pyra's libraries . i want to get this out of the way first , since it's the only significantly backward-incompatible change on the list .

the libraries that use snippets are currently organized by backend : lua.nv , ruby.nv , and javascript.nv . this results in a lot of duplication , makes it hard to split them up further , and just doesn't really make much sense .

the first step in ameliorating the situation is to merge them all into one , which we can do by allowing rules to have multiple snippets : one for each backend they support . now you'll be able to use the snippet symbol ^ followed by the name of a backend , and the compiler will insert the correct snippet depending on which program is using the rule . here's an example rule with a ^lua and a ^ruby snippet :

* get the current time
  ^lua f('result', {os.clock()})
  ^ruby f 'result', [Time.now.to_f]

i merged the backend-specific libraries using this new capability , so the next step will be to organize the rules based on the function they serve , like logging.nv or iteration.nv . after that , i'll need to update the example projects to use the new library scheme .

another motivation for restructuring the libraries is to prepare for the documentation backend . the compiler now stores which backends a given rule supports , so we can show this information in the documentation !

๐ŸŽง song of the day :
CLOCK โ€” Plaid


december 5th

today's been a quiet day of plotting and scheming ! here's the resulting list of priorities for pyra and beyond :

  1. restructure libraries around use , not compiler backend
  2. fix strings that contain quotes , brackets , and uppercase
  3. HTML docgen backend ร  la Hoogle
  4. self-hosted with Go backend for cross-platform binaries
  5. project creation commands
  6. stack changelog for debugging
  7. documentation on pyra.run
  8. create utopie using pyra with Godot backend
  9. create mooncake using utopie

a while ago i renamed the old version of pyra to "stackless pyra" , and "pyra0" to pyra . today i updated the name of the the repo to reflect this .

๐ŸŽง song of the day :
Hive โ€” Mobster


december 4th

i'm done working on my site for now , so it's finally .......

PYRA TIME !!! MUAHAHAHAHA

we're startin' off by gently vaporizing a terribly nettlesome quality of the pyra compiler : it doesn't produce deterministic output ! this becomes a hassle when you have a git repo with a pyra program , and the generated code changes randomly every time you recompile .

the code changes because Lua doesn't ensure an iteration order for tables , and i use Lua tables a lot in the compiler . today i fixed this by introducing a lovely little function by Rici Lake that lets you create ordered tables ! it stores the order that you add keys to the table in a linked list , and overrides the __pairs() iteration function to take that order into account :

local function Ordered()
  local key2val, nextkey, firstkey = {}, {}, {}
  nextkey[nextkey] = firstkey
  local function onext(self, key)
    while key ~= nil do
      key = nextkey[key]
      local val = self[key]
      if val ~= nil then return key, val end
    end
  end
  local selfmeta = firstkey
  selfmeta.__nextkey = nextkey
  function selfmeta:__newindex(key, val)
    rawset(self, key, val)
    if nextkey[key] == nil then
      nextkey[nextkey[nextkey]] = key
      nextkey[nextkey] = key
    end
  end
  function selfmeta:__pairs()
    return onext, self, firstkey
  end
  return setmetatable(key2val, selfmeta)
end

after adding this function , i only needed to swap out three tables in the compiler with ordered tables , et voilร  , deterministic output ! this also prepares me for making pyra self-hosted , because i can now use the example programs to conveniently verify that updates to the compiler don't change the output by running git diff .

on another note , i made few style fixes on a new website i'm helping to design for the Nouveau Community . Safari has always been the bane of my existence as a web designer . it seems like i'm always discovering new snippets of CSS the WebKit engine can't handle . this time it was text underlines ! (แ—’แ—ฃแ—•)

i still want to support WebKit browsers for websites i design , in spite of this . i had been using an old Apple device for testing , but today i realized i can install a browser for Linux that uses WebKit instead ! i'm on Fedora , so i installed GNOME Web using the command sudo dnf install epiphany . it worked splendidly for testing the design ; i should've done this a long time ago !

๐ŸŽง song of the day :
CHEAT CODES โ€” TOKYO MACHINE


december 3rd

the managing N24 post is finally complete ! today's portion dives into the VLiDACMel therapy , zeitgebers , and DSPD . it was difficult to include all of the information i wanted without teetering into overwhelming territory . hopefully i struck a good enough balance for people who are new to the subject .

i've been trying out a more casual and playful tone than i usually use in my "serious" informational posts . i noticed how much i've been holding back a more relaxed , and in my opinion , more authentic side of myself . the shift may not be apparent from the exterior , but it feels more nourishing . a small step toward the unfolding of the internet i long to inhabit .

finally , i sent an email to the creator of VLiDACMel , to thank them for how much they've helped .

๐ŸŽง song of the day :
81 Special [Slowed + Reverb] โ€” Caravan Palace


december 2nd

today i collected , ordered and structured all of the scattered notes i've taken about N24 into a friendly article-like shape . the first section is now live on the managing N24 page . i'm planning to edit and post the remaining sections tomorrow !

many of my notes were copied directly from written conversations i've had with friends , which has been a fun source to harvest from !


december 1st

the main project i'd like to work on this month is my programming language , pyra ! however , there's one page on my website that i want to finish first .

i have a rare circadian rhythm disorder called N24 . i recently learned how to manage the condition using a protocol called VLiDACMel , and have been writing an article about my experiences .

something i want to include is an actogram of the sleep data i captured between October of 2023 and November of 2024 . i used a sleep tracker called Plees Tracker , which is a great app , but there's no built-in way to create a visualization how i want . thankfully , it exports data as a CSV that looks like this :

12,1696711105697,1696744567977,4,
13,1696806609732,1696836850079,3,
14,1696902967015,1696940138010,2,
15,1697001200047,1697033781756,0,
...

the second and third columns are the important bit , and store the start and end times of each recorded rest period , encoded in milliseconds elapsed since the Unix epoch . not wanting to create a visualizer from scratch , i found a project that was close to what i needed and looked simple to modify . from there , i made a few modifications to the CSV parsing code and graph styling . the resulting script is available here !

processing my sleep data with the script results in the following graph ( click here to view larger ) :

a graph of my sleep data

this is actually the first time i've seen this data laid out so clearly , and it's interesting how chaotic it looks ! it almost resembles ISWRD , but i'm pretty sure that's an effect of having an unusually long phase delay and frequent interruptions .

today i also added an updates page , to list all of the other changes i've been making to my site recently !