Skip to footer navigation.

Oatmeal

A digital pillow fort

A photograph of silhouetted trees in front of the northern lights. A large gravestone is barely visible in one corner of the image.

A photograph of silhouetted trees in front of the northern lights.

A photograph of silhouetted trees in front of the northern lights. They’re visible as sheets of pinks and reds.

A blurry photograph of a child in colorful overalls holding a mini golf club high over their head standing in front of a “life size” brachiosaurus.

Dinosaur golf before it shuts for the season.

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 photograph of a sleepy cat lounging in a sunny patch on a bed covered in a grey blanket.

Solar powered.

A relatively close up photograph of many yellow and white flowers in a meadow. The sky is blue and the image is processed to have a warmer hue. It is out of focus.

I had time to take a walk before running some errands and getting a flu shot and a Covid booster this morning.

Two kids in shorts and sweaters standing on a lumpy rock looking out over some Rosa Rugosa at the sea.

It is starting to smell like fall!

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

September summer

I finished reading Robin Sloan’s Moonbound today. It was fun, and light. The blurb likens it to Narnia, and, while a bold claim, I think that was a correct assertion, but more about the intended audience than the book’s subject matter. If a sequel is ever written I’d most certainly give it a look. It seems like a great gift book for a kid between like 8 and 15…or you know, perhaps, anyone who likes fun stories that aren’t scared of being joyful.

The book did do a thing that I don’t often like, which is write a story about the power of a story…it didn’t really lean too hard into that, so I will forgive that…this time.

Next up, following the theme of talking animals…Redwall? Or maybe The Mountain in the Sea, by Ray Nayler! I haven’t read that yet, so don’t really know what it is about, but lets assume a giant talking octopus for the time being!

After some biking about, and playground time with the kids today, I played some more Arranger. This game is becoming the star of this blog, it seems. The game recently started to signal that we’re nearing the final boss!? I may actually finish this game! I’m shocked and excited. Being able to play in bite-sized chunks has a huge breath of fresh air. I rarely have the attention span, nor eyeball powers to play a video game much longer than 45 - 60 minutes in a go.

I’ve also been playing a narrative game in the evenings before bed when I’d typically read a book or stare, listless, at the ceiling. Specifically, I’ve been playing The Ghost and the Golem. I’m still pretty early in, I think, but I’m reminded now of how much I enjoy playing narrative games, and this one seems especially tailored for me. If you have any recommendations for narrative games, I’d be really interested to learn about them.

A new page, still in progress, has appeared on the wiki. This one is being used to catalogue the parts of lil that I find particularly exciting.

Here are some drawings I made with the pixel art thing I mentioned in my last post.

A pixel art portrait, this one of a green guy with green hair and red eyes. The face exudes smugness.

A pixel art portrait of a person with grey skin and a pink nose wearing a black shirt, dark grey pants, and a black hat. They’re set in front of a rather blocky tree, and a purple background.

A pixel art portrait of a large-eyed, pointy-eared green fellow in a dark red shirt.

A pixel art portrait of a purple person with yellow eyes and shoulder-length green hair. They’re in a blue shirt, and in front of a red and light blue checked background.

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:

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.

Two young children in swim things are next to each other in the surface. They’re jumping over a small, crashing wave. Above them an overcast sky stretches waaaaaay out to sea. There’s some sea weed out on the drying sand, because the tied is going out.

Home beach. Last day of vacation for me.

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!

Two young children in sweaters and shorts, each with reddish hair and white skin sit on a large granite rock by the Atlantic Ocean. They’re looking out to sea. It is fairly foggy.

Summer vibing, fog horn whooping.

A photograph of a rocky coastline leading to the Atlantic Ocean. Beyond a large stretch of water is a point of land. There are some big fluffy clouds above it all.

Rocky shore.

« Future Page 1 of 211 Past »