Time off between jobs

On August 20th, 2021 I left my job at Tempus for a job at AWS working on the AWS Rust SDK. In the between, I took 24 days for leisure time and personal projects. This page is a chronicle of that period.

August 17th

I rate my own discipline as pretty low, and my attention span isn't much better. I'm compelled to create things because I crave the validation of others. I'm going into this time off with a desire to create something neat and better myself.

I hope to achieve three things:

How to build a Gunpey

I think this task will be the most difficult because I've never used druid before and the instructional book is incomplete. I'm counting on my past experience with creating GUIs for the web and the work I've done with conrod for my plotter art generators. If I run into too much trouble, I can switch over to a more familiar framework like ggez, nannou, or even pixels. This project is also a good opportunity to work on graph traversal algorithms. The object of the game is to build an unbroken line from the left of the screen to the right. An individual segment of the line is valid if it's connected on both sides to either another line or a screen edge. Building that solver will be the first thing that I tackle.

August 23rd

I was right to guess that learning Druid would be difficult but that's only been true for some aspects of it. My past experience making websites with React has been helpful overall but I've still made a few mistakes that I could have avoided. Just like React, Druid UI are declarative. The "view" that users see and interact with is constructed from a central blob of "state". Druid tracks what state each widget (component in React) relies on and re-renders widgets when state is changed. Just like React, it's easy to misunderstand what constitutes a change and what doesn't.

State changes in React

(This part applies to older Class-style React components. The new method of using hooks to manage state has it's own set of footguns)

If you've used React, you may have been bitten by this because of how JavaScript handles equality comparisons between objects. When comparing objects, JS only compares the pointers for those objects and disregards the values they contain.

e.g.

let objA = {
  bestKaiju: "Biolante",
};
let objB = {
  bestKaiju: "Biolante",
};

console.assert(objA === objA, "This is true");
console.assert(objA.bestKaiju === objB.bestKaiju, "This is true");
console.assert(objA === objB, "This is false");

What this means in React is that if you directly modify the object where you store your state, React will think that nothing has changed because JavaScript says that the pointer to the object is still the same:

class Foo extends React.Component {
  constructor(props) {
    super(props);
    this.state = { name: "world" };
  }

  handleNameChange() {
    // Modifying the state object like this is a no-no.
    // React will never notice that this was changed.
    this.state.name = "Zelda";
  }

  render() {
    return (
      <div>
        <h1>Hello, {this.state.name}!</h1>
        <button onClick={handleNameChange}>change name</button>
      </div>
    );
  }
}

In order to make the change noticeable, a new object has to be created to replace the old one:

  handleNameChange() {
    // Creating a new object like this is a noticeable change
    this.state = { name: "Zelda"};
    // React also provides a nice function to call to make state changes
    // this.setState({ name: "Zelda"});
  }

(for more info on React state, see here)

Druid works in much the same way.

State changes in Druid

In Druid, the Data trait is responsible for defining how state containers should be compared. One of the default impls of Data is for Arc which ends up working exactly like the JavaScript object pointer comparison mentioned earlier. Whatever is defined as state is cloned often and it's up to the user to either make sure that your state itself is cheap-to-clone or that your expensive-to-clone state is behind a cheap-to-clone Arc. Before I had internalized this, I ran into some roadblocks with widgets that didn't want to update even though I thought that I had changed their state.

Where I'm currently at

I made a good amount of progress over the weekend and have actually taken a liking to Druid in spite of my confusion.

Gunpey game dev progress example depicting results of a partially-correct graph algorithm

The graph algorithm is having some trouble


I've added a start screen and a game screen to the app. The game screen has a few buttons for testing the score meter and adding rows to the game board. Grid cells can be swapped and connections are usually calculated correctly although it also misses a few valid connections in the above screenshot. The tests pass so I'm wondering if it's an issue with the Druid widget I created to represent the game grid. This has definitely been one of the most difficult projects I've attempted and I'm definitely planning on turning this experience into a tutorial for aspiring Rust game developers. I'm going to continue on with Druid for the next few days but I'm still considering the option of switching it out for a framework that I'm more experienced with.

August 30th

I spent most of the past week working on music and playing videogames. I've been putting effort into learning the Octatrack and it's starting to pay off although the device feels no less arcane. I have another piece I started in Ableton that needs polish but it's also a candidate for my "write a song" goal. More on this to come.

September 8th

It's almost the end of my time between jobs. I have spent a large amount of the time just chillin and I've beaten a few adventure games:

Gunpey graph algorithm progress

The graph algorithm for determining connection is now fully working and correct:

Gunpey game dev progress example depicting results of a correct graph algorithm

(compare this screenshot to the previous update)


The breakthrough that made this possible was focusing on the grid as a bunch of corners. Focusing on the cells alone made it easy to reason about cells that formed a chain between the left and right sides but it made considering how the cells were actually connected difficult. Changing the focus to the corners of cells made it possible to focus on that important missing piece.

Gunpey graph explainer

in the corner-wise diagram, it's easy to see the unconnected end at (3,2)

My friend Tess was instrumental in creating the final algorithm based on this method. I'll write about exactly how it works as part of a separate tutorial article.

Music

I put some more polish on the song I was working on but I want to add a second part to it based on a suggestion from my piano teacher. I swear I'm actually going to share it at some point.

September 10th

I created a new plotling called Line Noise and made a print with it:

A photograph of a plotter print depicting the results of the Line Noise art generator

September 12th

This is the end, friends. Here's a review of the original goals and my thoughts on how I did

Goal One: Learn the druid UI framework and build a game

This was a very tough and time-consuming goal. I didn't fully succeed in either of the two parts but I got pretty far.

Goal Two: Create a new plotling

This task was completed and I even made a print (see the Sept. 10th entry). This was definitely the easiest goal and I was able to complete it start-to-finish in the space of one morning. My plotlings framework that I've set up is easy to use and I could see it becoming a library of some sort. The ideal would be to make a "nannou draw calls" to SVG converter.

Goal Three: Create and publish a 3-5 minute original song to YouTube

This goal was tied for difficulty with my first one, but I was able to fully complete it. I'm not completely happy with the song but I think it's ok and I can always go back and re-record it at a later date if I really want. I've uploaded it to YouTube so give it a listen and let me know what you think.