Skip to content

Instantly share code, notes, and snippets.


Tab Atkins Jr. tabatkins

View GitHub Profile
tabatkins /
Last active Sep 3, 2022
Results of the discussion between Tab and Yulia

On Sep 1 2022, Yulia and I had a VC to get past our misunderstandings/disagreements about pattern matching in a high-bandwidth fashion.

The high-level summary is that Yulia has three requests, all of which I think are reasonable. In order of complexity:

Allowing plain functions as custom matchers

Right now, custom matchers have to be done via an object with a Symbol.matcher key. The matcher function can be written as a plain boolean function now, but you still need that object wrapper, which is annoying as it prevents existing boolean functions from being easily used. Ideally you'd be able to write when(${someFunc}) and have it work exactly like when(${{[Symbol.matcher]: someFunc}}) does in today's spec.

The blocker for this is that we currently define Function.prototype[Symbol.matcher] to essentially do an instanceof check, so JS classes can be used by default: when(${MyClass}) will match if the matchable is an instance of MyClass or a subclass, wi

tabatkins /
Last active Aug 26, 2022
Various ARIA component patterns, and how they'd be naively built using toggle


<div class=checkbox></div>

.checkbox {
	toggle: checked;
.checkbox:toggle(checked)::before {
tabatkins /
Last active Jun 1, 2022
Chester comic script


Beachside, camera facing away from the ocean.

A FIRBOLG and a DWARF relax in beach chairs, sipping pina coladas, with halos above their head. A skinny human man is building a sand castle at their feet.

DWARF: Gotta say, didn't expect to find myself enjoying this sorta afterlife.

tabatkins / option.js
Last active Jan 31, 2022
ADT, Decorators, Pattern Matching
View option.js
// This is a decorated version of <>
// A predefined ADT decorator.
// Use it on static "constructor" methods only.
// Pass an extractor function, to produce a pattern-matching value.
// The instance must have an [ADT.kind] property
// set to the constructor method used.
const ADT = (valExtractor=()=>null) => (_, {methodName, isStatic, kind, addInitializer}) => {
if(kind == "method" && isStatic) {
tabatkins /
Last active Jan 24, 2022
Obscurdle rules
  1. Vowels are green, y is yellow.

  2. Doubled letters in a word are yellow, tripled letters are green.

  3. ???? My first guess gave me a yellow T and green A, and I just made words putting those lettes where they needed to be and solved all the challenges. Surely it's not that simple???

    (Edited to add: It's not that simple - the first letter in alphabetical order in your guess is green, the last is yellow. My first guess (and all subsequent) just happened to use A and T as the first/last letters.)

  4. If you use the same letter in the same position as the immediately preceding guess, it's yellow. If a letter is used in the same position three guesses in a row, it's green. Good luck with the GGBGG pattern.

import io
# Gets my list of words taken from wordle source
# (91k raw, 33k compressed)
# down to 32k raw, 16k compressed.
# Squashing characters into 6 bits, and the separator into 4,
# would reduce the raw size ~30% more,
# at the cost of a more complex decoder.
separator = "\n"
tabatkins /
Last active Jan 6, 2022
Integrating the dataflow proposals

There's currently five "linear dataflow" proposals bouncing around TC39: the pipe operator |>, the bind-this :: operator, the partial function application foo~() operator, the Extension operator ::/:, and the pipe()/flow() functions. @js-choi put together a wonderful diagram comparing and contrasting their functionality overlaps, along with an accompanying blogpost going over things in more detail.

My personal thoughts on the matter are that we need the Pipe operator, could use PFA and the pipe()/flow() methods, and don't need the other two.

Pipe Operator

As the diagram helpfully illustrates, the pipe operator nearly subsumes every other proposal

tabatkins /
Last active Oct 14, 2021
Weapon Construction

D&D 5e Weapon Construction Rules

Way back in D&D 3rd edition, I noticed that the weapons table seemed very regular. There were certain patterns that were maintained almost completely across the board. I documented these and wrote them up (still on my very very old pbwiki), to help other people create new balanced weapons.

(Later, one of the 3e designers, Sean K Reynolds, confirmed for me that, while they hadn't quite formalized the rules in the form that I was presenting, my rules were accurate.)

Later, when 5th edition came out, I looked over the weapons again and attempted to extract a similar set of rules. They were a bit more complex, surprisingly, and not quite as regular - 5e seems to have embraced sometimes giving less-effective options for flavor or lower cost (look at the armor table, for instance, phew).

But if you look at the reasonably optimal weapons, the following rules will construct weapon


XML-in-KDL (XiK)

This specification describes a canonical way to losslessly encode XML in KDL. While this isn't a very useful thing to want to do on its own, it's occasionally useful when using a KDL toolchain while speaking with an XML-consuming or -emitting service.

This is version 1.0.0 of XiK.

XML-in-KDL (XiK from now on) is a kdl microsyntax for losslessly encoding XML into a KDL document. XML and KDL, luckily, have very similar data models (KDL is almost a superset of XML), so it's quite straightforward to encode most XML documents into KDL.

XML has four types of nodes, corresponding to certain KDL constructs:

tabatkins /
Last active Jul 18, 2021
JSON-in-KDL specification


This specification describes a canonical way to losslessly encode JSON in KDL. While this isn't a very useful thing to want to do on its own, it's occasionally useful when using a KDL toolchain while speaking with a JSON-consuming or -emitting service.

JSON-in-KDL (JiK from now on) is a kdl microsyntax consisting of three types of nodes:

  • literal nodes, with _ as the nodename
  • array nodes, with array as the nodename
  • dict nodes, with dict as the nodename