The earliest memory I have of ‘programming’ is in the early/mid 90s when my father brought home a computer from work. We could play games on it … so of course I took the spreadsheet program he used (LOTUS 123, did I date myself with that?) and tried to modify it to print out a helpful message for him. It … halfway worked? At least I could undo it so he could get back to work…

After that, I picked up programming for real in QBASIC (I still have a few of those programs lying around), got my own (junky) Linux desktop from my cousin, tried to learn VBasic (without a Windows machine), and eventually made it to high school… In college, I studied computer science and mathematics, mostly programming in Java/.NET, although with a bit of everything in the mix. A few of my oldest programming posts on this blog are from that time.

After that, on to grad school! Originally, I was going to study computational linguistics, but that fell through. Then programming languages (the school’s specialty). And finally I ended up studying censorship and computer security. That’s about where I am today!

But really, I still have a habit of doing a little bit of everything. Whatever seems interesting at the time!

Popular Github Repos

Posts

A Tabbed View for Hugo

One thing I’ve been using for a lot of my recent posts (such as Backtracking Worms) is a tabbed view of code that can show arbitrarily tabs full of code or other content and render them wonderfully! For example, we can turn: {{< tabs >}} {{< sourcetab ruby "examples/art-station.rune" >}} {{< tab "art-station.svg" >}} {{< include "output/art-station.svg" >}} {{< /tab >}} {{< sourcetab ruby "examples/astrology-and-moons.rune" >}} {{< tab "astrology-and-moons.svg" >}} {{< include "output/astrology-and-moons.

read more...


A DSL for rendering magic circles and runes

Let’s make magic circles/runes!

Turn this:

rune do
    scale 0.9 do 
        circle
        polygon 7
        star 14, 3
        star 7, 2
        children 7, scale: 1/8r, offset: 1 do |i|
            circle
            invert do
                text (0x2641 + i).chr Encoding::UTF_8
            end
        end
    end
    scale 0.15 do
        translate x: -2 do circle; moon 0.45 end
        circle
        translate x: 2 do circle; moon 0.55 end
    end
end

Into this:

read more...


GMail Oldest First

It’s been rather a while since I last worked on a userscript, but there’s been a problem I’ve been trying to solve for some time.

I want to have my GMail in order from oldest to newest. While you can do this for all messages, you can’t do it within a single page.

read more...


Genuary: Triple Nested Loops

The fine people of /r/generative / Genuary2021 have a series of challenges for generative works for the month of January. I don’t think I’m going to do all of them, but pick and choose. For example, the very first prompt is:

// TRIPLE NESTED LOOP

My goal was to draw a grid of circles across the X/Y the image and nest them for the third dimension. To make it a little more interesting, I added a few different color modes. seededRandom is my personal favorite, that was interesting to get working.

read more...


yt-cast: Generating podcasts from YouTube URLs

Today’s goal: Turn a collection of YouTube links into a podcast.

Start with a config.json like this:

{
  "brandon-sanderson": [
    "https://www.youtube.com/watch?v=H4lWbkERlxo&list=PLSH_xM-KC3ZuOZayK68JAAjj5W9ShnFVC",
    "https://www.youtube.com/watch?v=YyaC7NmPsc0&list=PLSH_xM-KC3ZtjKTR2z8rPWxv1pP6bOVzZ",
    "https://www.youtube.com/watch?v=o3V0Zok_kT0&list=PLSH_xM-KC3ZuteHw3G1ZrCDWQrAVgO0ER"
  ]
}

And it will automatically download all referenced YouTube videos, convert them to MP3 (both using youtube-dl), and serve an RSS feed that’s compatible with most podcast programs.

Tested URLs include:

  • Playlist URLs (like the above)
  • Single video URLs
  • Channel URLs

Most youtube URLs should work though.

read more...


Pictogenesis: Stack Transpiling

Much like transpiling register machines, now we have a chance to transpile stack machines. Unfortunately, it doesn’t actually speed up the code nearly so much (the stack is just not as effective of a memory structure in this case), but it’s still an interesting bit of code.

In this case, we turn something like this:

invsub
polT
writeG
id
neg
zero?
sin
invsub
ZERO
inv

Into this:

function(X, Y) {
  this.x = X;
  this.y = Y;

  this.stack = [];
  this.r = undefined;
  this.g = undefined;
  this.b = undefined;

  this.stack.push(X);
  this.stack.push(Y);

  var arg0 = 0;
  var arg1 = 0;
  var arg2 = 0;
  var result = 0;

  // invsub
  arg0 = this.stack.pop() || 0;
  result = 1 - arg0;
  result = result % 1.0;
  this.stack.push(result);

  // polT
  arg0 = this.stack.pop() || 0;
  arg1 = this.stack.pop() || 0;
  result = Math.atan2(arg0, arg1);
  result = result % 1.0;
  this.stack.push(result);

  // writeG
  arg0 = this.stack.pop() || 0;
  this.g = arg0;

  // id
  arg0 = this.stack.pop() || 0;
  result = arg0;
  result = result % 1.0;
  this.stack.push(result);

  // neg
  arg0 = this.stack.pop() || 0;
  result = -arg0;
  result = result % 1.0;
  this.stack.push(result);

  // zero?
  arg0 = this.stack.pop() || 0;
  arg1 = this.stack.pop() || 0;
  arg2 = this.stack.pop() || 0;
  result = arg0 === 0 ? arg1 : arg2;
  result = result % 1.0;
  this.stack.push(result);

  // sin
  arg0 = this.stack.pop() || 0;
  result = Math.sin(arg0);
  result = result % 1.0;
  this.stack.push(result);

  // invsub
  arg0 = this.stack.pop() || 0;
  result = 1 - arg0;
  result = result % 1.0;
  this.stack.push(result);

  // ZERO
  result = 0;
  result = result % 1.0;
  this.stack.push(result);

  // inv
  arg0 = this.stack.pop() || 0;
  result = 1 / arg0;
  result = result % 1.0;
  this.stack.push(result);


  return [
    this.r === undefined ? this.stack.pop() || 0 : this.r,
    this.g === undefined ? this.stack.pop() || 0 : this.g,
    this.b === undefined ? this.stack.pop() || 0 : this.b,
  ];
}

read more...


Pictogenesis: Stack Machine

Okay, enough with register machines. Let’s make something new. This time, a stack based machine!

Rather than keeping it’s memory in a series of memory cells, there will be a single stack of values. All functions can pop values from the top of the stack or push them back on. I will add the ability to read the X/Y value and directly write R/G/B, but you can’t write to the former or read from the latter, so you can’t use them as registers. Let’s see what that looks like!

read more...


Pictogenesis: Transpiling

Okay. That is slow… Let’s make it faster!

So the main problem we have is that we’re interpreting the code. For every single pixel, for every line of code, we’re doing a few housekeeping things and making at least one function call. For a 400x400 image with just 10 lines of code, that’s 1.6M function calls. Like I said, slow.

So let’s make it faster!

My first idea? Transpile it to Javascript!

read more...


Pictogenesis: Wrapping Modes

Now that I’ve got register machines working, one of the next ideas I had was to implement different wrapping modes. Currently, as it stands, X and Y are passed into the machine as floating point numbers from [0, 1] across the image and output is expected to be [0, 1] for each of R, G, and B. Any values that end up outside of that range, we truncate down to that range. But some of our mathematical functions (multiplication, exponentiation, negation, etc) tend to generate numbers way out of this range. But they don’t have to!

read more...


Pictogenesis: Register Machine

Okay. First Pictogeneis machine: a register based machine. Today we’re going to create a very small language with a small number of registers that can read from the outside world, write colors, and act as temporary variables.

Something like this:

gt? t0 b y x r
add g y x
abs b x
inv t0 g
add r g x
sub t0 b r
mul x r b
abs y x

In each case, the first argument is the output and the rest are inputs. So:

# gt? t0 b y x r
if (b > y) {
    t0 = x;
} else {
    t0 = r;
}
 
# add g y x
g = y + x

# abs b x
b = |x|
...

Where x and y are the input point x and y mapped to the range [0, 1]; r, g, b are the output colors in the same range and t{n} are temporary registers just used during the program.

read more...