Skip to footer navigation.

« Oatmeal

Posts tagged javascript

Follow this tag's bespoke rss feed or return to the list of all tags.

...but I can do that with regex?

The other day a co-worker showed me a project that seemed genuinely useful, but I didn’t love some bits of how complicated and resource intensive its architecture were, so, I made my own version of it! Check out diff heatmap.

As an aside, I put this one on github which I don’t generally choose to use for personal projects, but I’d love to see folks contribute rules to this project, and this seemed like the most straight forward way to enable that…maybe.

JavaScript Notebook

Kartik recently reminded me of my own project playground that I do use from time to time, but that I’ve always been a little frustrated with.

That reminder paired with that frustration lead me to revisit something similar that I’d started a while ago, but hadn’t finished. Notebook is kinda my take on Jupyter Notebooks minus a ton of features and capabilities.

Here is a little video demo of it in action that I put together over my lunch break today.

There are likely some bugs still left to be ironed out! Sharing scrappy fiddles and what not.

leibovitz

Folks what that haunt me (positive) on the Fediverse may have seen me sharing progress shots from this, but here I am, and I have made another camera application for the web. Leibovitz combines a lot that I learned making my other camera applications into one, hopefully less clunky package.

With leibovitz you can either take new photos, or upload any image file and apply filters to it. The UX to toggle between the two modes is a bit clunky, but I’ve tried to be sparing with the UI to leave as much room as possible for the image preview. That meant dropping some buttons and making heavier use of a floating pallet than I’d normally like.

You can apply blur, adjust color contrast, fiddle with the white balance, setup chromatic tinting,” and select between a few different dithering modes! On browser and device combos that support it you can also change the focus — but I’ll caveat that I don’t actually have a device that supports this feature, so the implementation is mostly there on a hope and a prayer after reading the docs for it all. It should also work offline after initial load, but no promises about how well that’ll work across browser and device combos since the whole service worker api thing seems to be weird weird weird in how it is actually implemented and supported across the various browsers.

Styrofoam cups and awk

I like writing these posts for my website, but I’ve sat down to write this one like 11 times and it either takes on a tone of totally encompassing dread and dystopian navel gazing or I feel like I’m burying my head in the sand and ignoring reality as it happens around me.

…I finished reading Victor LaValle’s The Changeling. It was engaging, and I was interested in where it was going, but I found that where it went wasn’t interesting. The dialogue and prose were lively and contemporary, which is what really kept me going with the book. I’ve started The Phoenix Keeper by S.A. MacLean as well as Jiro Taniguchi’s The Walking Man — that one as part of a bookclub!

The Walking Man had me from the jump because it opens up with some birding. The Phoenix Keeper is a bit more YA than I usually lean, but I’m enjoying it — I think it’d make a really great animated series.

I’ve been poking at two programming projects — one was thoroughly and totally ill-advised. The fun one: I’ve been fiddling with making a sort of generic starting point that I could use to make card games. I was inspired to do this when I came across Cuttle, which is sorta like MTG or Netrunner but with a normal deck of cards.

What I’ve got so far is pretty basic. Here’s a demo with 4 decks of cards. Each deck is shuffled, and I’m tracking which card belongs to what deck. I am modeling a few different layers of abstraction, but I think I need to add in a box” or something, so that you can move an entire deck around more easily. Click and drag to move the cards around. Right click to flip the cards over. It currently doesn’t play nicely with touchscreens, but I can add that in someday soon!

The ill-advised project: inspired by John Earnest’s implementation of lil in awk, Lila, I set out to make a non-trivially sized program using awk. Enter f.awk! It is a really basic implementation of forth in awk. It is missing conditional branching, It sort of supports conditional branching, but does have support for user-defined words!

I learned a lot of awk doing this…and I guess I feel more comfortable using awk, but I also find myself reeling from the lack of any useful developer tooling. JavaScript and the browser have me spoiled, I guess? If I was clever I wouldn’t implement forth directly in awk, instead I’d implement a simple virtual machine using awk, and then implement the forth using the virtual machine’s byte code…but there is only so much brain power I can exert on such a silly project.

This morning I read a blog post, Keeping the seat warm between peaks of cephalopod civilisation. I liked this quote:

Birds are just little Napoleons, exiled on their St. Helena of deep time, before they make their vengeful return. Octopus patiently biding their time until the fish clear off again. And here we are, just keeping the seat warm.

While I never really used the phrase deep time” in grad school doing the Art History thing, I was trying to write something about landscape paintings that included major geological features, and how they relate to Timothy Morton’s thinking around hyper objects…things so humongously distributed in time that we struggle to really even perceive them, like climate change and a styrofoam cup.

Also, check out my blogroll. It slaps. Well, it is just a list of links…but those links are rad.

Bouncing off of books

After playing a few hours in Fields of Mistria I decided to put it down for a bit. I’m really really enjoying it. The farming is low key, and feels more like grinding for resources so far (positive), the relationship sim stuff is fun and the quests and tasks are really approachable (and there is, my favorite thing in the world, an in-game quest log!). All in all it’s a supremely, deliciously, snackable game. If I had to level critique against it, it’d be that the day/night cycle feels a bit too fast. I regularly end up trying to finish tasks in the middle of the night, which doesn’t always work out. Even an additional five minutes per day would be good. I put it down, though, because it’s in early access and I wanna let it bake some more. I’ll be revisiting it regularly.

Pining for a pixel art fix, though, I started playing Cassette Beasts. Pokémon games are hands down my favorite games, especially the Gameboy Color and Gameboy Advanced era ones. Cassette Beasts’ formula is similar to Pokémon, but so much more jrpg…which I guess is to say weird?” or maybe goes really hard, really fast?” The story is a lot more front and center than the story of any Pokemon game which are all basically deliver this package (3 - 10 minutes) draw the rest of the owl (20 - ∞ hours).” Whereas Cassette Beasts is all angels, a demons, and there are lurking vampire folks around, clicky cassette decks, and even voice acting! Fun stuff. It also has co-op and online multiplayer, which I’m actually curious about — usually I’m not so into multiplayer, but this could be groovy.

I actually gasped when I first started the game and saw the Godot splash screen. I should learn Godot, and stop pretending I can use JavaScript in the browser for absolutely everything imaginable…but…

…since making plains, I gave some love to my neglected pixel art editor, pixel pixel pixel pixel pixel pixel. It is a lot more functional now!

I updated it to work better on touch screens since my kids like to play with it on a tablet. I also added the ability to add more than 1 canvas, so you can more easily work on multiple sprites at the same size all at one go. I stopped short of adding real onion skinning, and figure folks (me) can stitch frames together either in code or some other tool. Probably, most importantly, though, I added the ability to export and import projects so that you don’t have to exclusively rely on the browser’s local storage any more. I’ve been using it to make some pixel art for another game, but have become a wee bit side tracked fiddling with isometric transforms.

Whenever you use the <canvas> tag in the browser you set a context for it like canvas.getContext('2d'); — I, a simpleton, naively took this to mean that to do 3d things I’d have to set that context to…you know…3d and that documentation is a lot. NAY! NO! This is not so! At least not for the 3d I would ever dream of using. It is always just pixels on a screen! So, I’ve had some fun making silly little bouncy guys and experimenting with how to make vaguely performant 3d-ish things for the browser…but also…I should really learn to use Godot. Maybe that’ll be a thing to do in the new year.

I’ve also continued to think about week notes, which I nearly always typo as weak notes” the first time, and I wonder if that is my subconscious telling me something…but what? I like the format, but also want something more conversational. I don’t wanna always list read this, didn’t watch anything, had some feelings about the weather.” That said, I’ve watched a lot of Gundam over the holiday break, have been enjoying the new Star Wars thing, Skeleton Crew, with my oldest kid, and will likely not finish reading The Overstory before the turn of the year…or maybe ever. I usually force myself to power through books regardless of how I feel about them, but, maybe it is a sign of personal growth that I wanna put this book down and totally walk away from it. It isn’t bad, or even not good. I’m just not feeling it.

Broughlike dev log

I’ve been working on the broughlike pretty steadily since my last update. The gameplay loop is pretty much unchanged, but I’ve added a fair bit of polish, and fixed a lot of bugs. I think it is honestly sort of boring to play, but I am excited to have this as the starting point for future projects…can you smell the roguelike!? I can!

The major fixes and improvements that I’ve made since my last update include:

  • better way finding used during level generation helps to make sure that items and enemies are always reachable by the player and not trapped in little rooms all on their own
  • 4 different wall generators that are used at random! I was previously only using a naïve flood fill algorithm, now, alongside that I also have RSP Tree, Cellular Automata, and Drunkard’s Walk algorithms for generating walls
  • enhanced enemy logic means the enemies are a lot more clever — they’re set up to move straight to the exit unless the player is within 4 grid cells of their current location, at which point they switch to pursuing the player, this combo means that they often end up swarming the player as they get closer to the exit
  • bosses now appear every 10 levels…if you defeat one your health is boosted a little bit
  • a whole bunch of optimizations and code clean up

An interesting side-effect of working on a 6x6 grid is that it is about as small as any of my algorithms can support — if I go smaller to 4x4 they get wicked slow or totally crash. If I go bigger they stay about as useful, without any noticeable lag (though I haven’t tested for an upper limit to this).

I’ve also been experimenting with an auto-play algorithm, that, similar to the logic which controls the enemies, would have the player automatically navigate toward the exit, able to move around walls, engage enemies and collect items. So far that isn’t really working, though, so I’ll save that for the code-spelunkers among you dear readers.

Here’s the code I’m using to make sure that the player can always reach the exit, other enemies, and items.

// Checks to see if there's a path between any two points on the level
function isReachable(startX, startY, targetX, targetY) {
    const visited = Array(CONFIG.GRID_SIZE).fill().map(() => Array(CONFIG.GRID_SIZE).fill(false)); // Initialize a 2D array of false values
    function dfs(x, y) {
        if (x < 0 || x >= CONFIG.GRID_SIZE || y < 0 || y >= CONFIG.GRID_SIZE) return false; // Are the coordinates in bounds?
        if (visited[x][y]) return false;                                                    // Have we already visited this cell?
        if (walls.some(wall => wall.x === x && wall.y === y)) return false;                 // Is there a wall here?
        visited[x][y] = true;                                                               // Mark this cell as visited
        if (x === targetX && y === targetY) return true;                                    // Have we reached the target?
        return dfs(x + 1, y) || dfs(x - 1, y) || dfs(x, y + 1) || dfs(x, y - 1);            // Recursively check neighbors
    }
    return dfs(startX, startY);
}

Beyond little bits of game development here and there I’ve switched projects at work, been reading a bunch and generally enjoying the fall-flavored actives that happen this time of year…which is a little bit to say I’ve been playing ostrich.”

Guitar driven development

I’ve found myself in possession of a guitar. Actually, the guitar that I had in middle school has come back to me after a decade’s long jaunt with someone else. I don’t really play guitar, but, I figured I should restring it and tune it.

I’m really very bad at tuning, so, rather than get good at that, or use any of the existing tools within reach of the internet to help me with that I made a thing. Tuner is a little web app that does 2 things: using a device’s microphone it listens for a primary frequency and displays what note that is, and it can play some reference tones, starting from middle C.

The most interesting bit of tuner is the code that detects the dominate frequency being input, and then maps that to a note. I script-monkeyed most of this together.

// Detect the dominant frequency and map it to a musical note
// <https://webaudio.github.io/web-audio-api/#the-analysernode-interface>
// <https://en.wikipedia.org/wiki/Autocorrelation>
function detectNote() {
    const freqArray = new Float32Array(analyzer.frequencyBinCount);
    analyzer.getFloatFrequencyData(freqArray);

    let maxAmp = -Infinity;
    let maxIndex = 0;

    for (let i = 0; i < freqArray.length; i++) {
        if (freqArray[i] > maxAmp) {
            maxAmp = freqArray[i];
            maxIndex = i;
        }
    }

    // Nyquist frequency is half the sample rate of a signal
    // <https://en.wikipedia.org/wiki/Nyquist_frequency>
    const nyquist = audioContext.sampleRate / 2;
    const frequency = maxIndex * nyquist / freqArray.length;

    const note = getNoteFromFrequency(frequency);
    noteDisplay.textContent = `Note: ${note}`;
}

// Convert frequency to musical note
function getNoteFromFrequency(frequency) {
    const notes = [
        'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'
    ];
    const A4 = 440;
    const semitoneRatio = Math.pow(2, 1 / 12);
    const noteIndex = Math.round(12 * Math.log2(frequency / A4));
    const note = notes[(noteIndex % 12 + 12) % 12];

    return frequency ? note : 'N/A';
}

Once the guitar was tuned, I figured I may as well make a metronome because while I am really very bad at tuning I’m even worse at keeping time. BP-sand is a metronome — you can enter a beats per minute count and it’ll beep at an appropriate interval. With each beep a grain of sand rains from the top of the screen. The sand piles up into sticky, branching stacks.

Next, I have to relearn how to play the guitar, I guess…

Other than these musically inclined adventures, autumn has come to Maine — we’ve been enjoying fall vibes, and soaking it all in before the Winter Drearies set in. Recent reading includes The Way of Kings by Brandon Sanderson (an author that I’m honestly ready to call it quits on…page turners for sure, but not for me these days) and The Algebraist by Iain M. Banks. Since finishing Arranger I haven’t picked up another video game, but I have fallen back in love with Puzzmo — pile up poker is 10/10. I think this winter me and Caves of Qud are gonna spend some quality time together. I’m really weirdly excited for it’s 1.0 release. I’m especially excited to explore Qud’s tutorial…I’ve played it for years, but haven’t ever really felt that I’ve actually known how to play it.

A playground for sharing scrappy fiddles

I shared some snippets of JavaScript in a recent blog post and was wicked irked that I didn’t have an easy way to share interactive code on my own thing…so…I made a totally static JavaScript playground for running little experiments and sharing scrappy fiddles!

It is pretty simple — it allows folks to enter and run JavaScript, includes a console so you can easily log things out without folks needing to open developer tools, and lets you share your code in two different ways. First, you can append the contents of the code editor (just a textarea) as a hash to the URL. If you share a URL that includes hashed contents those will automatically load when anyone visits that hash. Because that makes some wickedly long URLs, though, I also added the capability to download the entire website (a single html page) plus the contents of the textarea — this way you can either directly host your own version or share the entire html file with someone else.

I’m really pleased with how this turned out, and I’m excited to use this little playground a lot more. The piece I’m most pleased with is how I handle console.log; I didn’t want anyone to have to write a custom logging function, I wanted folks to be able to reliably use whatever the browser offers, so, I hijacked the in-built console.log function that we all know and love and then return it to you after the code has been run!

To learn about the playground’s secrets run the help function from the editor.


After the fact updates!

I updated the playground a bit since the initial post!

It now includes a few pre-made functions that make creating things a bit easier, including clear and mount functions. For more info, check out the newly improved help command. Here is a demo that shows off how to use the mount function

If you use this playground for anything, I’d love to see what you make!

Constants, variable assignment, and pointers

After reading my last post, a friend asked an interesting question that I thought would also be fun to write about!

They noted that in the reshape function I declared the variable result as a constant. They asked if this was a mistake, because I was resigning the value iteratively, shouldn’t it be declared using let?

What is happening there is that the constant is being declared as an array, so the reference to the array is constant…meaning that you can’t resign that variable to a new array or object. You can, however, fiddle with the contents of that array. Here, const makes the reference immutable, but the contents of the referenced array can be modified.

This is different than, say, C++, where if you declare an array as a constant with the keyword const, you cannot modify the contents.

const int arr[] = {1, 2, 3};
arr[0] = 5;  // Womp, womp, compilation error!

In C++, the const keyword sorta goes deeper,” and applies to the contents of the array, too, not only the reference, so the entire kit-and-caboodle is immutable. To achieve something like what I did in JavaScript in C++ with const you’d want a pointer to an array. This will allow you to modify the contents of the array, but keep the pointer immutable.

int arr[] = {1, 2, 3};
int* const p = arr;
p[0] = 5;  // Success! No compilation error! 

In this example, the pointer, p, is a constant, and immutable, but the contents it points to can change. Sorta like having a box bolted to the floor — you can’t move or change the box, but you can put all kinds of different stuff into the box as long as they fit!

Reshape, in JavaScript and APL

In APL the rho, , called reshape is used to both construct arrays of a given shape (dimensionality), and to reconfigure arrays into new shapes.

Sometimes I wish I had reshape in JavaScript…so I wrote it!

Here are two functions that, when combined, a la Captain Planet, can stand in for APLs reshape in JavaScript.

Ravel is the simpler of the two, it takes an array of any dimension and returns a new, one-dimensional array of the same data. Sorta like flatten from functional libraries like Ramda.js.

function ravel(array) {
  if (!Array.isArray(array)) return [array];
  return array.reduce((acc, val) => acc.concat(ravel(val)), []);
}

Reshape takes a vector describing the desired shape of a new array and an array to reformulate into that shape. The function will produce a new array with the specified shape and fill it by cycling through the elements of the input array. I think that this mimics APLs reshape, allowing you to reshape arrays with fill and cycling behavior.

function reshape(shape, array) {
  const totalSize = shape.reduce((acc, val) => acc * val, 1);
  const ravelledArray = ravel(array);
  const filledArray = [];

  for (let i = 0; i < totalSize; i++) {
    filledArray.push(ravelledArray[i % ravelledArray.length]);
  }

  function constructArray(shape, data, offset = 0) {
    if (shape.length === 1) {
      return data.slice(offset, offset + shape[0]);
    }

    const size = shape[0];
    const subShape = shape.slice(1);
    const subArraySize = subShape.reduce((acc, val) => acc * val, 1);

    const result = [];
    for (let i = 0; i < size; i++) {
      result.push(constructArray(subShape, data, offset + i * subArraySize));
    }
    
    return result;
  }

  return constructArray(shape, filledArray);
}

Here are some side-by-side tests of my JS and the same maneuvers in APL.

First, we reshape an array into an array of two nested arrays:

const array = [1, 2, 3, 4, 5];
const shape = [2, 3];
const reshapedArray = reshape(shape, array);
console.log(reshapedArray);
// [[1, 2, 3], [4, 5, 1]]

In APL:

2 3 ⍴ 1 2 3 4 5

Returns

1 2 3
4 5 1

Next a test case where we need to fill in a larger shape with repeating:

const array = [1, 2, 3];
const shape = [3, 3];
const reshapedArray = reshape(shape, array);
console.log(reshapedArray);
// [[1, 2, 3], [1, 2, 3], [1, 2, 3]]

In APL:

3 3 ⍴ 1 2 3

Returns

1 2 3
1 2 3
1 2 3

You, and me, and the HTML5 canvas, pixel art, and quest logs

As we start to round out the summer I haven’t been reading as much, so I don’t have much to report on that front, but I have been keeping busy!

I made yet another pixel art drawing tool, pixel pixel pixel pixel pixel pixel allows folks to draw chonky pixel art creations on pretty much any sized canvas. This was fun to make. I’ve spent so much time with the HTML5 canvas lately that I’m really starting to feel like I get it, which is a fun realization! If you draw anything with pixel I’d love to see what you make!

Having made a fancy little menagerie of web things lately, I’ve been wondering if I can do anything more to unify their aesthetic — I have some subtle and secret rules that I use when designing them to help keep things consistent, but that is more to save me from having to make choices than it is to make them all feel related.

…but also, why would I need them to feel related when they almost all already live at the same URL?

My family recently started to play a game called SCHiM — I’ve been watching, mostly, and I’m really struck by it. A few things I am appreciating about the game:

  • it includes an accessibility setting to increase the contrast
  • the sound design is gorgeous, and supports the visual aesthetic. A lot of the world building and wayfinding is audio-driven
  • there’s a totally subtle, yet effective mechanism for helping you to find your next waypoint, like a nonverbal/textual hint system

That sort of quest log stuff has really been on my mind; after noticing how good the quest log is in Arranger in a previous post, being forever struck by how bad the Pokémon games handle this, and picking up Dragon Quest VI on the Gameboy after like…an eon? a millennium? a full epoch? away and being able to slip right back in I decided to make my own quest log…which isn’t in any way a todo list. I’ve been using it at work.

Evidently I've become a guy what that makes camera apps?

I really like the unpredictable depth of field and color handling of single-use cameras. The day before we left for a little vacation to down east Maine I wrote another weird little camera app, lut cam. Lut cam attempts to simulate some of the aspects of a single-use camera by allowing you to apply color profiles to the raw image produced by a device’s camera.

I now have a collection of weird vacation photos that sorta look like they came from 1994.

Because I did this using JavaScript and browser APIs, I didn’t have guaranteed access to the device’s focusing mechanisms which means the images are pretty much whatever the sensor picks up — distorted lens, graininess, and wonky focus included. It was a fun follow up project to my dithering stuff because it really makes apparent how much computational work phone cameras do to make up for their physically diminutive optics.

All my recent projects have been made within pretty short periods of time — typically a weekend, or, in the case of lut cam a few hours…I enjoy working under those sorts of constraints because it encourages me to work off of previous work rather than jump down new deep, dark, rabbit holes where I’ll likely get lost. A feature I’d like to add to both pico cam, and lut cam is a level — I think I can use the device orientation and device motion events to accomplish this, but haven’t tried, yet…because we were on vacation, which was lovely!

We visited our old stomping grounds, met up with fiends friends, made new ones, and spent almost enough time on the best rope swing this side of the Atlantic. It was a good way to send up the summer!

One trip to the beach inspired me to make two programs this weekend

This weekend we traveled 20 minutes to a sort of secret beach. It was a grey, overcast day, and we timed our trip to line up with low tide so that we could walk waaaaaaay far out into the ocean all the way to some little islands. It was fun, and we saw some neat birds, including an Oyster Catcher. While on this adventure I took a picture. Later at home I thought it’d be nice to dither this!” I usually reach for Dither me this for such tasks, but for some reason I tried to do it from the command line. That quickly became frustrating. Not because it didn’t work but because it was wickedly clunkier than I remembered it being…so I got to thinking, maybe I can make my own tool to do this!?”

A bit of noodling, a pile of JavaScript and a few hours later I was done! Dither it is a small website where you can select an image from your local device and it’ll automatically be transformed using a Floyd-Steinberg dithering algorithm. Then you can save it. Nothing ever leaves your browser, no settings or knobs to fiddle with (for both good and ill).

I expected the dithering algorithm to be the most difficult bit. It wasn’t because it was pretty easy to find a whole lot of great example implementations. In the end the most difficult bit I ran into was figuring out how to turn the contents of an html canvas into a downloadable image file. Once that nut was cracked it all seemed to be done and dusted…

…until then some time passed and I began to wonder why am I processing images, why not take dithered photos to start with!?”

I slid down a rabbit hole researching the Gameboy camera and noodling if I should get a used one to use with an Analogue Pocket?

That seems like a wild setup to carry around and like it takes a bit of planning to effectively use. I’m not much of a planner. You know what doesn’t involve any planning for me? Taking photos with my phone! It is honestly the only camera I use.

Enter a new project! Pico cam is a small web application that lets you take dithered photos. The images it produces are the same dimensions as the Gameboy camera’s. It was an interesting project, and I’m pleased with the results. I expected this project to be more challenging than it ended up being. I quickly learned that contemporary browsers can do a lot of the heavy lifting for you, so most of what I assumed would be difficult I was able to handle using in-built browser APIs. As is my habit, I was able to pull this project off using only JavaScript in the browser, no external packages, or build step or anything like that.

A sample image taken with pico cam shows some trees growing over a suburban street lined with houses.

My approach was to first dump a live stream from a connected camera into a <video> tag, then to sort of stream” frames from that video to a <canvas> element, at which point I’m essentially running the code from Dither it! Easy! Next up was a button to save individual frames from the canvas to the device and bip, bop, boop, a bit of css and markup re-arranging I have a totally passable Gameboy camera web app!

Another sample image taken with pico cam shows a heavily dithered image of a pine tree and some clouds at dusk.

If you end up using either Dither it or Pico cam I’d love to see the pictures you make!

Books, the end of winter, video games and JavaScript

Since my last update I’ve read a handful of books. Some standout reads include Tales from Earthsea, The Other Wind and The Left Hand of Darkness, all by Ursula K. Le Guin. I’d read them all before, accepted for The Other Wind. I thought I’d read The Other Wind, but hadn’t! Chaos: Making a New Science by James Gleick was also a fun read. I liked it for the rabbit holes it invited me down; I’ve been thinking a lot about an anecdote in the book about how the measured length of a coastline is dependent on what precision you are measuring it at.

The weather has slowly turned from winter to spring, though we’ve had an ice storm, a significant blizzard and spent about a week total without power between various power outages from the wind and ice. Now things seem to be springing up, though. Our garden is drying out and I’m trying to figure out what to do with the plots this year. A squirrel purloined our potatoes last year. I’d like to try potatoes again.

Inspired by a friend’s noodling with love2d and yuescript I threw together a little sand simulation in javascript this weekend. I’ve hidden a little playable guy in it, and have some ideas about using the sand simulation to build the environment of a platforming game. I enjoy making these tiny sketchy games. It is lovely to write code with no dependencies outside of what the browser provides and no build step. I know I could use something like p5.js to do this, too, but it seems like another thing to learn and figure out — I’ve already invested a mountain of time learning browser APIs a nuances so until I run into limitations I’ll keep on this simple path…the biggest downside to which is that I haven’t kept up with modern build tooling outside of what I have to know for work.

Lately I’ve been making time to play a handful of video games, namely Balatro and Pokémon Prism. Balatro is a roguelike deck builder, loosely built around the rules of poker, but you collect joker’s that modify or multiply how the scoring works. The most exciting bit of it for me, though, is that it is implemented with love2d. There’s some pretty wild shader code in it. I’ve probably spent equal time playing it as I have noodling its code. Pokémon Prism is a ROM hack of Pokémon Crystal. I’ve never played Crystal, but I am enjoying Prism a lot. The best Pokémon games I’ve played are easily the ROM hacks like Prism and Radical Red. I’ve found Prism to be a nearly perfect balance of challenging, while not demanding tons of tedious grinding to level up to move past certain areas. From what I’ve played of it, Radical Red requires a lot more grinding and I’ve never finished it because of that.

For my birthday a few weeks ago my in-laws gifted me a set of bike tools. I’ve never actually owned my own bike tools. On the island I either worked at bike shops or was friendly enough with folks at the shops to borrow the tools I needed. Since moving off the island I haven’t done as much bike maintenance. Having my own tools has been fun! I may try to scrounge a bike to restore over the summer.

Arkady Martine and Virginia Woolf

As an undergrad and a grad student I was obsessed with Virginia Woolf. Woolf’s writings appeared in my citations pretty much regardless of the class or subject area I was writing on.

I have recently finished reading an engaging and lovely novel by Arkady Martine, A Memory Called Empire.” Of course, I was excited to pick up the sequel, but, also, I had this feeling, this Woolf’s scent — I’ve always felt that Woolf’s nonfiction was more lucid and powerful than her fiction…it cuts different, sharper, more directly, it stings and is beautiful in its knife-likeness.

I had a sense that Arkady Martine’s writing would be similar, so I looked around for nonfiction she’s authored. I think I was right:

Why cities, when I could have chosen anything to preserve? To devote my life to keeping out of the sea? I cannot help but think that cities are our best and our most inevitable future.

I made another small toy in javascript, this time a note taking application. Ink n switch is a simple note pad for typing in text, that you can also draw on top of. There are two layers, a text layer and a drawing layer. They’re always right on top of each other. There aren’t heaps of features, and it doesn’t work on mobile (yet) (it works on mobile now!), but I find it pretty pleasant for little notes and sketches.

I think I’ve come to terms with the fact that, while I claim to be a polyglot programmer, and while I do love to explore different programming systems, javascript and the browser are like home when it comes to actually making a thing — for turning an idea into reality. Especially since, the way I tend to write javascript is easy, no dependencies, no build system, just javascript in the browser.

Over the last few days, what was previously a frighteningly mild winter has turned wet, exceedingly so, here in Maine. There have been a series of super high tides at the same time has heavy rains and snow melt, leading to massive flooding along coastal areas. We are thankfully above grade and far from the ocean, but, just like this summer felt like a very different summer, so too does this winter feel different. Changed.

I stumbled across a small vestige of the old internet. The human-hand-made-curated thing.

A scrappy fiddle

A screen recording of a teeny tiny browser window. The window starts by displaying a grey surface with a subtle white grid on top of it. A computer cursor moves around, occasionally it clicks to open a context menu that lists 3 choices, “circle, square, triangle.” When the cursor selects a shape that shape is inscribed within that grid cell.

I’ve had fun playing at implementing a very basic visual programming system over the last few days. I like the direction I’ve started down, but realize I’ve made a few oversights that are gonna necessitate my starting over, which is part of the fun.

I’ve implemented toy interpreted languages before — usually lisps. Architecturally, a graphical programming system smells similar, especially when I think about the repl 🤝 event-loop as being mostly the same thing plus or minus a person tapping the return key to trigger evaluation.

I’ve leaned in to the playful possibilities of javascript, the browser’s inbuilt abilities and the HTML canvas element. And, you know what? It is rad and I have zero regrets. These are little corners of a space that I’m otherwise fairly familiar with through work, but that I haven’t really spent any time with.

It snowed a lot today — we all had fun playing in it this morning, afterwards I cleared the walk and driveway for the first time. I did that three more times throughout the day, but, to be totally honest, I love shoveling almost as much as I love going on walks, so, all in all, pretty rad.

I’m nearing the end of A memory called empire by Arkady Martine. Unless the ending gets wickedly flubbed, I’ll most certainly be reading the next book in the series.

A post-publish-edit because I forgot to link to the inspiration for this things title!

New year

The last weeks of 2023 have been very enjoyable. Other than having to deal with a cascade of car issues, there’s been a lot of time to hang out with the partner and kids, wander around outside, and poke at fun personal projects…and I mean, work, too, but…you know.

The other evening I pulled together a fun Markov chain toy. It isn’t anything fancy, but I wanted the ability to feed a madlib style script to the program and have it use that as a template to fill in. The resulting program is beak and you can take a look at it if that sort of thing interests you. I want to figure out how to build a game around it about history and discovering the past’s fragmented stories.

Then, last night, I made what is probably the most minimal, worst version of Alto’s Odyssey (one of my favorite games) imaginable. My version is called hill, and you can play it online. I haven’t put the code into a repository, yet, but it is just plain-old, boring-old, no-dependencies-on-anything-but-the-browser, JavaScript, so, view source will reveal all that it contains. I made this as a fidget-toy to play with during meetings.

I’ve struggled for a long time to pick up personal projects like this, but someone recently gave me the advice to focus on smaller points of curiosity — e.g., rather than dive right into trying to make an entire game that needs to generate vast histories, make the generator and then figure out how to layer more game bits on around it. That advice has proven wicked powerful, and I’ve enjoyed building more stuff more quickly lately. I think my attention span is also less impacted by brain stuff these days, which is helping me feel more confident when taking on any kind of project — I was even able to do some car repairs (shout out to Isaac for the encouragement)!

…I don’t enjoy doing car repairs.

Supposedly it’ll snow soon. The winter has been mild and exceedingly damp.

I’m about one third of the way into Arkady Martine’s A memory called empire and loving it.