Skip to footer navigation.

« Oatmeal

Posts tagged js

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

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.

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!

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.

Introducing Guava

I’ve been fascinated by Forth and concatenative programming for a while now. I can’t remember how I initially stumbled in to it, but once I got going I’ve been unable to stop. I’m a wee bit in love with it.

Wanting to play a bit with implementing my own spin on things and having opinions about tooling, I picked up a little scripting language called Ripen, by Felix, and started to extend it. I call the results Guava.

Guava

Guava is a stack-based, concatenative language and editor for the browser intended to be used for scripting and as a DSL for small web projects.

It is a toy for exploring concatenative language design, and the DOM. It could also easily be used as a scripting interface for a larger project. It is likely to change a bit over time, and is by no means done — but I think it is in a pretty decent state for a toy to draw to the DOM.

Guava supports arithmetic, control structures, basic DOM manipulation, object parsing and very simple HTTP requests (GET and POST).

Guava is an unusual language inspired by other unusual languages. While not strictly necessary, being loosely familiar with Forth is helpful when playing with Guava. Guava isn’t a Forth, but it is closer to a Forth than it is to something like JavaScript, C, or Lua.

Here is a good place to start with learning Forth. Or here, and for fun, here, too!

Dictionary

A major goal of Guava is keeping the entire language tiny and easily learnable. With this as a goal, the dictionary is kept relatively limited.

The dictionary is broken into 2 categories — words and sigils.

Words are akin to keywords or in-built functions in other languages while sigils are prefixes that guide the interpreter, switching it into different modes (roughly speaking).

Words

#> ( ) * */ + ++ - -- -eq? -if -rot . .s / /* /mod 
2dup ; <# [ ] abs alert and assert assert:false 
assert:true buffer clear confirm cr dec depth drop 
dup el:a el:append el:b el:clear el:h1 el:h2 el:h3 
el:html el:i el:p el:root emit eq? execute false 
gt? gteq? http:get http:post if inc kv:get kv:remove 
kv:set lt? lteq? max min mod negate not obj:parse 
or over pokedex prompt repeat rot sigils space swap 
times true until while words { }

Sigils

! ' / : ?

Introduction

Like most stack-based languages, Guava relies on reverse Polish notation and a LIFO — “last in, first out” — memory stack.

Most programming languages use infix notation, e.g. 3 + 3. If you’ve used Lisp or Scheme you may be familiar with prefix notation, e.g. + 3 3. Reverse Polish notation is the opposite of prefix notation — 3 3 +.

The stack is how data flows through a stack-based language where data is added and removed from the top,” sort of like a stack of dishes. At first blush it seems like stack manipulation is all that a programmer using a stack-based language would be doing all day long, while in reality most folks using stack-based languages tend to keep the stack pretty shallow — Guava also offers an escape hatch, allowing for easy use of variables outside of the context of the stack…which some may say is cheating, but we don’t need that kinda gate keeping.

For more info on how to use Guava take a look at the cookbook.

Editor

A lot of programming languages are pretty similar to one another — once you learn the core constructs of programming (control flow, data handling and storage, etc.) it becomes relatively easy to pick up new languages…the hiccup, I find, comes from needing to learn new tooling. Tooling can be inscrutable, and it is often assumed that you just sort of know it…but it is rarely really taught. For this reason an editor is provided for Guava.

The editor is comprised for 2 parts, an area to display output and an area to collect input. Full disclosure, the area to display output (e.g. console) has a few quirks to it that I’m still trying to work out. If these are a hindrance, you can open up the console of your browser for a more direct view of what is going down.

Screenshot of the Guava editor in action

Code can be input into the lower textarea, clicking the run” button will interpret the code. Any text entered into the textarea is saved to the browser’s local storage with each keystroke.

The clean” button empties the stack and clears the data from the output area.

The destroy” button completely clears all inputted code and resets the environment.

Clicking export” prompts to save input code to disk.

At the far right is a choose file” button — this allows you to load data from disk. NOTE the data is read in from the disk, but any edits aren’t saved back to the disk unless you click the export” button.

An instance of Guava is currently accessible at https://txt.eli.li/pb/guava.

License

Ripen was originally released under the ARTISTIC LICENSE 2.0. With permission from Felix, Guava is licensed under the MIT LICENSE.

For more, check out Guava’s git repository.

dice.js 2.0

A little dice rolling class in JavaScript for all your dice rolling needs.

class diceRoller {

  constructor() {
    this.log = [];
  }

  validate(diceNotation) {
    const match = /^(\d+)?d(\d+)([+-]\d+)?$/.exec(diceNotation);
    if (!match) {
      throw "Invalid dice notation: " + diceNotation;
    } else {
      return match;
    }
  }

  parseDice(diceNotation) {
    const match = this.validate(diceNotation);
    if (match) {
      const diceInfo = {
        numberOfDice: typeof match[1] === "undefined" ? 1 : parseInt(match[1]),
        sidesOfDice: parseInt(match[2]),
        diceModifier: typeof match[3] === "undefined" ? 0 : parseInt(match[3])
      };
      return diceInfo;
    }
  }

  tallyRolls(diceData) {
    let total = 0;
    for (let i = 0; i < diceData.numberOfDice; i++) {
      total += Math.floor(Math.random() * diceData.sidesOfDice) + 1;
    }
    total += diceData.diceModifier;
    return total;
  }

  roll(humanInput) {
    const rollResult = this.tallyRolls(this.parseDice(humanInput));
    const rightNow = new Date();
    let logEntry = {
      "timestamp": rightNow.toISOString(),
      "input": humanInput,
      "result": rollResult
    }
    this.log.push(logEntry);
    return rollResult;
  }

};

And a quick example of how to use it,

// instantiate yo' players
const playerSarah = new diceRoller();
const playerEli = new diceRoller();

// play the game
playerSarah.roll('2d10-4');
playerEli.roll('2d12+12');
playerSarah.roll('1d12');
playerEli.roll('1d2');


// check the log!
console.log('==== Sarah\'s log ====');
playerSarah.log.forEach(logEntry => {
  console.log(logEntry.input + " : " + logEntry.result + " : " + logEntry.timestamp);
});

console.log('==== Eli\'s log ====');
playerEli.log.forEach(logEntry => {
  console.log(logEntry.input + " : " + logEntry.result + " : " + logEntry.timestamp);
});

JavaScript help!?

Does anyone know of a way to implement client-side full text search in JavaScript without needing to build an index. I’m ideally looking to use the HTML markup itself as the index. Essentially I’m looking for the browsers cmd+f functionality to an HTML document. (I, unfortunately can’t just say use cmd+f”)


Edited to add: I found a pretty solid solution in markjs.

:whispers: maybe it is a bad sign when your dev ecosystem is so expansive that you need a package manager for package managers?

Volta is a hassle-free way to manage your JavaScript command-line tools.”

https://volta.sh

In reply to: home | p5.js

p5.js is a JavaScript library for creative coding, with a focus on making coding accessible and inclusive for artists, designers, educators, beginners, and anyone else!

When designing developer tools, does one have to choose between making programming easier for programmers vs. making programming more accessible and inclusive to a larger group of folks?

Whenever I work with React I feel like it is an example of a tool that makes programming easier for programmers (read as engineers” perhaps?).

If this is true, what then are the consequences of the ClojureScript community so fully embracing the way React does its thing? Is is alienating folks, or is it making react more approachable?

In reply to: React

Why I have a problem with React the library and spend a lot of time talking to my therapist

Screenshot of a text editor and a browser window. The text editor has jquery as a lisp.

jQuery as a lisp!?

Link logging

You all. A week! Maybe a few. They’ve been something else, for good and ill, fun and waaaha!?” A doozy. So, here is a doozy of a link log!

aerc; The world’s best email client

I haven’t given this a go, yet, but it looks pretty solid, and like a great/easier to use alternative to mutt or alpine.

Why I’m still using jQuery in 2019

I use jQuery just about every day, and, you know what…I really like it. 😬

Why You Should Buy Into the Emacs Platform

The title of this post is a we bit deceive-ious, it is more of a list of awesome emacs resources than a manifesto/proclamation on why you should” use emacs.

Welcome to Linux From Scratch!

Linux From Scratch (LFS) is a project that provides you with step-by-step instructions for building your own custom Linux system, entirely from source code.

Why Don’t Americans Use Their Parks At Night?

However cities want to encourage more park use at night, he stresses that they need to consult the community anchors” to ensure that it meets the needs of the entire neighborhood.

Animal Crossing: New Horizons will have skin tone customization, gender-neutral hairstyles for Villagers

This piece serves as a great follow up to this previously linked post from Austin Walker, Me, On The Screen: Race in Animal Crossing: New Leaf

Instant Pot Baked Potatoes Recipe

How to cook potatoes in an instant pot.

Is Robert’s Rules too Restrictive? Consider Martha’s Rules of Order for Meetings

See also, Martha’s Rules

Borough mayor is knitting to prove men speak too much at meetings

Montgomery said she is unfazed by criticism and will continue knitting until Christmas.

Knitting as both protest, and social signal.

Don’t slow that bus down, we’ve got places to be

But there’s a clear difference between Die Hard and Speed, […] Die Hard is about the individual — the lone wolf John McClaine, shooting his way through the terrorists — but Speed isn’t really about Reeves. It’s about the collective. It’s not just one of Keanu’s best movies; it’s one of the best movies about public transportation. Speed refutes one of the most pervasive myths about metropolitan transit systems in the U.S. — that no one rides the bus in Los Angeles — with its economically and racially diverse ensemble of riders, who must work together and with Jack Traven to keep the bus going until the bomb is dismantled.

Help For Werewolf

Werewolf! is a free-form social roleplaying game (kinda):

Be your own curator. Archivist.

Question: what is to be done with the stuff after it has been cataloged and stored? Are we pinning butterflies for the sake of pinning them, or is there a moment of beholding, and re-use/re-mix down the line?

Save and make? Transform?

I like to think of what I do with these link logs as part curation, part compost.

IBM and the Holocaust — why wasn’t this on my radar?

Juxtaposed: Wayfair workers plan walkout in protest of company’s bed sales to migrant camps.

Slight correction to CNNs title, though — migration camps” should be concentration camps.”

Atlanta’s Food Forest Will Provide Fresh Fruit, Nuts, and Herbs to Forage

Most of the trees in the forest are still too young to bear fruit. But once they become productive, about five years from now, McCord expects literal tons of fruit.”

Before you were here

[…] Needing to build your own website, setting up your own webservers, and using non-user friendly applications to transfer data not only meant that most early users had a better core understanding of the technology and what its future might bring, it also meant that users had a sense of ownership. They were shaping the medium they were consuming.

screenshots of despair

A catalog of little despair.

Fans Are Better Than Tech at Organizing Information Online

The first step to recovery is admitting that you have a problem. I, as exemplified by this very post, have a tagging problem.

Interesting also in the context of digital minimalism,” see Walking Alone: On Digital Minimalism”.

on dat://

@kicks offering the most cogent explanation of what the heck date:// actually is that I’ve found!

Ok, so how does Dat work exactly? It is simply a unique address attached to a folder of files (kind of like a ZIP file.) You then share that folder on the network and others can sync it to their system when they visit the unique address.

SwiftUI, Privacy, macOS, and the Web

A long, but worthwhile read.

The Future of Interaction, Part II

The most important part of this announcement is the abstraction they’re working with, not the view surface being used for rendering.

Wherein the abstraction becomes a tool for focusing on interaction, rather than specific implementation.

Adversarial Interoperability: Reviving an Elegant Weapon From a More Civilized Age to Slay Today’s Monopolies

What made iWork a success—and helped re-launch Apple—was the fact that Pages could open and save most Word files […]

[…] Apple didn’t just make an interoperable” product that worked with an existing product in the market: they made an adversarially interoperable product whose compatibility was wrested from the incumbent, through diligent reverse-engineering and reimplementation.

The New Wilderness

The need to regulate online privacy is a truth so universally acknowledged that even Facebook and Google have joined the chorus of voices crying for change […] No two companies have done more to drag private life into the algorithmic eye than Google and Facebook.

So why have the gravediggers of online privacy suddenly grown so worried about the health of the patient?

Part of the answer is a defect in the language we use to talk about privacy. That language, especially as it is codified in law, is not adequate for the new reality of ubiquitous, mechanized surveillance.

Continuing later,

The question we need to ask is not whether our data is safe, but why there is suddenly so much of it that needs protecting. The problem with the dragon, after all, is not its stockpile stewardship, but its appetite.

That Web Dev Thing Where Everybody Says Something Clever Involving Toast

Twitter is designed to escalate responses and keep people engaged. This has the effect of polarising discussions online which in turn has, in my mind, made it completely useless as a venue for discussing web development issues.

airtext

A decentralized blogging…thing…platform…service?

Link logging

WebAuthn; A better alternative for securing our sensitive information online

I’ve mixed feelings about this — but tbh, I am not in the lease qualified to opine one way or the other. That being said, I’m really digging the .guide TLD.

Video of a Japanese Space Probe Touching Down on an Asteroid

While I was struggling get some react and an API to cooperate other people were landing a probe on an asteroid.

Grainy image of the probe’s landing zone

The Geography of America’s Mobile and Stuck,’ Mapped

The United States is facing a new class distinction: those who are mobile across state lines, and those who are stuck.

I catch myself (panicked) thinking about this a lot in the context of climate change, wondering where we should live if we are going to be stuck there.

Technical communication is particularly hard for newcomers

One of the key components to good technical communication is the right amount of context.

Cache-Control for Civilians

One of the most common and effective ways to manage the caching of your assets is via the Cache-Control HTTP header. This header applies to individual assets, meaning everything on our pages can have a very bespoke and granular cache policy. The amount of control we’re granted makes for very intricate and powerful caching strategies.

Handy dandy skip to point link

The Growing Complexity Of Developing Websites and the Growing Ease Of Using Site Builders

Developers like to develop. They like code and development tools and they’re bringing more of those things to the design and development of websites. Instead of writing HTML and CSS directly, now we’re told to write both inside Javascript.

Continuing,

The downside of this change is that it’s becoming more difficult for someone new (particular on the design side) to enter the field. The barrier for entry is increasing as the requirements are growing more complex.

I think this is spot on — something that I believe is missing from this conversation, however, is that raising the barrier for entry also runs the risk of making the community even more homogenous.

The Great Divide

Very much in-line with the previous entry:

The divide is between people who self-identify as a (or have the job title of) front-end developer, yet have divergent skill sets.

This article is nice in that it spells out a solution, and offers some guidance for how best to talk about the work of front-end development…and points out that front-end development can mean a lot of different things to a different people.

An exercise in progressive enhancement

A recent project I’ve been tinkering with was a good use case for me to familiarise myself with the actual implementation of a site that works without Javascript, but is enhanced by Javascript when it is available.

Making Things Better: Redefining the Technical Possibilities of CSS by Rachel Andrew

A CSS tech-talk liveblog,

CSS tries to avoid data loss.

Writing in Emacs

A nice little assortment of packages for writing words inside of emacs. I’ll also take this as an opportunity to plug my homespun config that I’m still really digging: tilde.el

Code hidden in Stone Age art may be the root of human writing

🤯

Climate crisis and a betrayed generation

Leading to ⤵️

The Servant Economy

West Marches: Running Your Own

Zelda Breath of the Wild meets table top gaming! An open world, sandbox style RP is something I’ve always wanted to try…maybe set on the high seas! 🏴‍☠️

Check out all these historical Jolly Roger flags from wikipedia

Shout out to the best from the collection, Jacquotte Delahaye’s Back From the Dead Red” flag

Shout out to this, the greatest flag — a lady pirate dancing with a very jolly looking skeleton holding a spear.

Link logging

Explaining Code using ASCII Art

People tend to be visual: we use pictures to understand problems. Mainstream programming languages, on the other hand, operate in an almost completely different kind of abstract space, leaving a big gap between programs and pictures.

Cyberfeminism ~1990s - present, Cyberfeminist Index by Mindy Seu

I’m currently working on a printed publication, a la the Whole Earth Catalog and the New Woman’s Survival Catalog, that will provide an overview of cyberfeminism and its evolution into networked feminism (like social media activism), xenofeminism (gender-abolition), and posthumanism/bio-hacktivism. It will be a resource guide: a sampling of books, essays, collectives, online communities, hackerspaces, etc.”

This article does a bonkers good job laying out how quickly and how much China’s urban and suburban areas are growing.

Networking - 🚂 Choo Documentation

I’ve been exploring alternatives to React lately, and keep coming back to Choo. I very much like this bit from its documentation:

A fun way to think about browsers, is as a standardized Virtual Machine (VM) that includes high-level APIs to do networking, sandboxed code execution and disk access. It runs on almost every platform, behaves similarly everywhere, and is always kept backwards compatible.

What if JavaScript Wins?

Technology has always existed in a social context, and evaluations of the risk or reliability of a tech platform have always relied on social indicators. But the acceleration of these patterns, and the extending of the social networks around code to include the majority of working coders, means that institutional indicators (like which company funds its development?”) now come second to community-based signals.

Similarly, top-down indications of technical maturity like documentation (often an artifact of outside investment in making a technology accessible to a new audience) are complemented, or even eclipsed, by bottoms-up indicators like how many people have bookmarked a framework, or how many people answer comments about a toolkit.

Tbh, I wasn’t all that interested in this pieces discussion of the pros and cons of JavaScript, but the author, Anil Dash of Glitch does an excellent job articulating the squishier side of why this and such system prevails over that and which thing-a-ma-bob that may be technically” better.

The piece reminds me of something I recently heard John Siracusa talk about on a podcast — he speculated that software may be the most complicated non-biological thing that humans have ever built. At first I thought it was hubris, but then, as he continued to make his point and draw a line from software to hardware to physics and the physicality of computing I was swayed.

What we often think of as being ethereal and digital” is, at the end of the day, still in meatspace…

See also Being Popular” by Paul Graham.

Why I Write CSS in JavaScript

I’m skeptical of CSS in JS for a few reasons, but this article softened my views. I still don’t love it, but my reasons for not loving it aren’t technical, really.

Pragmatic rules of web accessibility that will stick to your mind

Good high-level intro. I could see this being valuable for someone trying to convince management” of accessibilities value.”

Time to Panic. The planet is getting warmer in catastrophic ways. And fear may be the only thing that saves us.

Our little brown rat’: first climate change-caused mammal extinction

RIP. Expecting more news of this sort in the coming years is terrifying, but also, hopefully, key to catalyzing change.

A Journey Into the Animal Mind

Crows are among the most sophisticated avian technologists.

That is a solid sentence. I read it allowed to myself a few times when I came across it.

Cisco Trash Map, On railroads, oil rigs, uranium mines, 7-11 pizzas, Thelma and Louise, ruination, salvage, and the limits of the garbage gaze.

…I absorbed the common critique of ruin porn — that it tends to erase history and inspire myth. It’s true that as a high schooler I had a pretty vague sense of the politics that made Milwaukee’s ruins. But mythmaking has always shaped the U.S. landscape…

…Ruins are the idealized structures of a vaguely defined past; rubble is the aftermath of specific events that people live in, reuse, and form material relationships to…

Medieval trade networks v.4

A map of ancient trade networks

A detailed map of medieval trade routes. I always find this sort of thing fascinating and, in my experience lacking from contemporary historical education in the U.S. History is often presented as vignettes, as specific narratives, that are disjointed from a large context. I love how a map like this helps to contextualize the ecology, or maybe society? of history.

Five Lessons From Seven Years of Research Into Buttons

The first point is interesting, and click bait-y 1. Buttons Aren’t Actually Easy to Use”

I think it may be better presented as buttons require context.”

Or, perhaps The value of a good label.”

Link logging

Mark’s bookmarklets

I like bookmarklets. I like that these are bookmarklets made by Mark. See also Mark’s Learn2JS.

Pixaki for iPad

This is an app that I have not tried, but that looks groovy if you are into creating pixel art.

Bad ethernet cable

Reminding us that it is important to remember that the medium is the message…especially when the message relies on a medium for transference.

SQL: One of the Most Valuable Skills

Leave your ORM at the door. SQL fo’ lyfe!

Opportunity did not answer NASAs final call, and it’s now lost to us

RIP. You were the best robot adventurer. You will be missed.

I’ve gone full Apocalypse Dad

I read this. It caused me to panic. Living in blissful ignorance and being busy with work and not having the money to actually really stockpile anything of usefulness is what keeps me from being a full on doomsday hoarder.

But responding to the possibility of the worst, by pursuing mere survival, seems a bit limited — even to the point of being paradoxical. Survival is conservative by nature: however bad the world might be, my best chances of surviving in it are by learning and respecting its rules. My best hopes at riding out any given disaster are if things, as far as possible, continue to follow laws and norms I already understand. And yet, the possibility of disaster is inherent to the world as it presently exists, as long as the world remains the same, that possibility will be there. In a way, then, the best thing to do would be to throw caution to the wind, to forget [mere] survival and embrace — as far as possible — radical change. Only then might we achieve a world in which we are genuinely safe, without ever needing to rely on mere survivalism again.

Hello. By the Way. Whatever.

Nora Ephron on blogging.

…one of the most delicious things about the profoundly parasitical world of blogs is that you don’t have to have anything much to say. Or you just have to have a little tiny thing to say. You just might want to say hello. I’m here. And by the way. On the other hand. Nevertheless. Did you see this? Whatever. A blog is sort of like an exhale.

Virginia Woolf on a similar topic:

Of all forms of literature, however, the essay is the one which least calls for the use of long words. The principle which controls it is simply that it should give pleasure; the desire which impels us when we take it from the shelf is simply to receive pleasure. Everything in an essay must be subdued to that end. It should lay us under a spell with its first word, and we should only wake, refreshed, with its last.

SPUDwrite is a DIY E Ink typewriter… with a printer… and an LCD display

An E Ink typewriter.

O Uommibatto”: How the Pre-Raphaelites Became Obsessed with the Wombat

I had no idea that wombats were so beloved by the Pre-Raphaelites!?

Wombat sketch by Edward Burne-Jones featured in Memorials of Edward Burne-Jones (1904) by Georgiana Burne-Jones

TYPE DESIGN, TYPOGRAPHY, TYPEFACES AND FONTS: An encyclopedic treatment of type design, typefaces and fonts. This site is also known as on snot and fonts.

Need I say more than this title?

SCRIPT-8 is pretty much just like PICO-8, but implemented in JavaScript instead of Lua.

All (by which I mean most) of the websites I maintain for work now run a-okay under IE 11! 🕺

Hi, my name is Eli and today Javascript devoured me whole 🦖