Friday, January 29, 2021

how the atari 2600 merges time and space

"Man, you must have a deep understanding of TIA. I think for a lot of casual atari devs (funny that that's not a contradiction in terms, quite), everything is just there and kind of arbitrary, but you must have some idea of like... how the player 'tripler' flag change circuits."

"As a matter of fact, all sprites on the VCS are represented as counters that increment with the pixel clock (and wrap at 160). These go into a decode matrix that triggers drawing when certain trip points are reached. Changing the number of copies activates different parts of the decode matrix --- if you have three copies, drawing is triggered for tree different counter values."
Me and Christian Speckner, author of the excellent Stellerator Atari 2600 emulator
We're having a cordial conversation about programming (both Atari and modern web) on the Atari Age forums, a spin off of my recent Sisyphus project.

His point blew my mind a little bit... (especially interesting since he gives props to my early 2600 tutorials helping him when he first started out) I've dabbled a bit in Atari and read "Racing the Beam", but never thought about this particular merge of Time and Space: everything that puts a graphic in the right place is fundamentally based on these timers! (The amazingness of this point probably has a pretty small audience, but still...)

Thursday, January 28, 2021

going without a build process

 I like this guy

human-readable sorting of contents in storybook

Storybook slightly undersells its sorting capability... the array you pass to the exported variable parameters.options.storySort.order can be a mix of strings and arrays of [strings or more such arrays], and empircally it seems to work many levels deep. So for example a hierarchy like 

Documentation
	Overview
	Design System Workflow
	Getting Started Guide
		Intro
		Designer Guide
		Developer Guide
Components

can be described as the following:

[
 "Documentation",
 [
  "Overview",
  "Design System Workflow",
  "Getting Started Guide",
  ["Intro","Designer Guide","Developer Guide"]
],
 "Components"
]

But I admit, I didn't quite like that format - the way the contents of a section (like ["Intro, Designer,Developer Guide"]) were at the same level of its "parent" ("Getting Started Guide") seems odd to me, and I thought maybe it would be easier if the Table of Contents were human readable...

So I don't know if I over-engineered it, but I came up with this:

const toc = `
Documentation
 Overview
 Design System Workflow
 Getting Started Guide
  Intro
  Designer Guide
  Developer Guide
Components`;

const tocParse = (lines, ptr, currentDepth, arrayStack) => {
  if(ptr >= lines.length) return;
  const line = lines[ptr];
  const lineDepth = line.search(/\S/); // how many spaces before nonwhite space?
  if(lineDepth === -1) { // if -1 is empty line, skip and move to next
    return tocParse(lines, ptr + 1, currentDepth, arrayStack);
  }
  const title = line.trimLeft().trimRight();
  const currentArray = arrayStack[currentDepth];
  if(lineDepth === currentDepth) { // at this level, add and look to next one
    currentArray.push(title);
    tocParse(lines, ptr + 1, currentDepth, arrayStack);
  } else {
    if(lineDepth > currentDepth) { // deeper, make child array and re-parse line
      const subArray = [];
      currentArray.push(subArray);
      arrayStack.push(subArray);
      tocParse(lines, ptr, currentDepth + 1, arrayStack);
    } else { // more shallow, go up a level and re-parse line
      arrayStack.pop();
      tocParse(lines, ptr, currentDepth - 1, arrayStack );
    }
  }
};

const order = [];
const tocLines = toc.split('\n');
tocParse(tocLines, 0, 0, [order]);

The toc uses spaces not tabs, and so isn't super robust, but still, I think it does a good job having a string that looks like the end result drive the whole process.

Also, as I was building up that little recursive thing, I wanted to test my work - a convenient way of making sure two arrays (containing strings and other nested arrays only) are equal is to just do JSON.stringify() on 'em - unlike objects you don't have keys that might be in a weird order to worry about.

Wednesday, January 27, 2021

this...is....SISYPHUS! (using stellerator to embed playable atari games right in a web page straight from the files)

 I completed my third game for the Atari 2600 - SISYPHUS



More of a philosophical/existential joke than game, to be honest. You, Sisyphus, are condemned by the gods to roll a massive rock up a hill. 

Every time you fail, the rock gets a point.

(I made a mobile friendly web thing that played with the same idea before)

I used several community tools to pull this off - it's written in batari Basic (consulting Random Terrain's extensive documentation page)... I used my own PlayPal 2 and PlayfieldPal-bB for the graphics... my "IDE" was the Atari Dev Studio for Visual Studio Code, I used the Atari 2600 Label Maker for a semi-authentic looking frame (for some art I bought from shutterstock) In some ways the newest/most interesting tool was using the emulator Stellerator to put an in-browser version playable online

Christian Speckner, creator of Stellerator, actually uses my first Atari game FlapPing (née JoustPong) as an example embedded demo

Stellerator has detailed instructions, but isn't 100% clear on "how do I just make a simple webpage loading an external .bin ROM". The example demo embeds the ROM as a base64 string, but here is the javascript that includes an XMLHttpRequest to load the byte array from the .bin, my additions in bold.

        <script src="stellerator_embedded.min.js"></script>
        <script>
            {
                
                
                // Shortcut to avoid typing out the namespace
                const Stellerator = $6502.Stellerator;
                // Create the stellerator instance
                const stellerator = new $6502.Stellerator(
                    // The canvas element
                    document.getElementById('stellerator-canvas'),
                    // The URL from which the web worker will be loaded
                    'stellerator_worker.min.js'
                );
                window.addEventListener('resize', () => 
                     stellerator.isFullscreen() || stellerator.resize());
               (async function(){
                    const response = await fetch('../sisyphus.bin');
                    const image = await response.arrayBuffer();
                    const byteArray = new Uint8Array(image);
                    stellerator.run(byteArray, Stellerator.TvMode.ntsc);
               })();
                // Expose the instance for tinkering.
                window.stellerator = stellerator;
            }

                        
        </script>
The .js files are available in a zip file from the github page.
My Sisyphus embed page has minimalist HTML, the FlapPing Demo is a little more robust about resizing and with more instructions.



Monday, January 25, 2021

custom sorting sections in storybook

Aargh, one of those silly "didn't read far enough in the documentation" -- Storybook DOES easily cover 2 levels of hierarchy, so you can have your main Documentation before your per-Component documentation, and then sorted Documentation sections (but if you need finer grained control than that, you're going to have to work harder.)

Assuming you already have a `export const parameters` object, just add this:

  options: {
    storySort: {
      order: ['Documentation', 
               ['Overview','Design System Workflow'], 
             'Components'],    
    },
  },

But before I read low enough on the page to see the previous example, I had the "roll your own sort function" on my mind., even for the simpler sort one level of sections version. This was the code I came up with... I kind of like sorting one array by the contents of another:

const knownSectionsForSorting = ['Documentation', 'Components'];

const positionOfContainingSection = (titlePath: string) => {
  const section = titlePath.substring(0, titlePath.indexOf('/'));
  return knownSectionsForSorting.indexOf(section);
};

export const parameters = {
  options: {
    storySort: (a, b) => {
      // story titles are the "kind" parameter of the second item of the info array
      const diffInSection =
        positionOfContainingSection(a[1].kind) -
        positionOfContainingSection(b[1].kind);
      return diffInSection || a[1].kind.localeCompare(b[1].kind);
    },
  },
};

You'd have to build something like that but more advanced if you need to sort individual files with a subsection of your Documentation section, for example.

And the documentation for doing that is a little light... odd that you have to look at "a[1].kind" to find the Title to sort on...

Saturday, January 23, 2021

problems playing multiplayer with friends in minecraft for switch

 (This is one of those, who knows, maybe it will help someone's google search results)

Online Minecraft on Nintendo Switch seems a little flakey, but even before that there are a few steps you can get wrong, especially if you haven't done much with the online play modes with friend in general...

1. The accounts on the two switches have to be friends (you can youtube up pretty easy instructions to exchange friends codes, it's on each accounts page not general settings)

2. One player creates the world, and they have to make sure multiplayer is turned on for that world

There's still a lot I don't understand (creating realms, which I think means you don't have to have a separate "host" machine so either player can work on the realm when the other is online) and this cross-account thing with Microsoft accounts, but the above were the toughest steps in getting it going. 

(I have both Switches in my posession, which made thing easier... trying to troubleshoot remotely when the other person is not so techie would have been tough!)

Friday, January 22, 2021

super tiny pixel font

For my current Atari 2600 project I may try making a digital clock using big, clunky playfield pixels. Luckily, for an old site I LOVED called Pixel Time (RIP,  here's my loving fan page) I made a font that could make words even on its absurdly limited 45x45 canvas:

(I think Nick had made an All-Caps version that I cribbed from a bit.)

Heh. I think I got my start with hyper-minimal fonts on the old Etcha-a-Sketch Animator, an early digital toy that let you make animations of 12 frames of 40x30 pixels (arranged in longer sequences)

Thursday, January 21, 2021

on the naming of shapes

Minor argument at work, we were thinking of a new property "shape" for buttons, with values corresponding to the first 4 items listed here. Personally I strongly disliked "oval" to mean "rectangular but with half circles for the sides" since in geometry, that's not what an oval is...

Some of my coworkers didn't like "capsule" or "pill" (maybe because it means something else in other systems, like where a "pill" is a type of "tag".) Stadium and Obrund are pretty correctly but not widely understood.
 

I made a CSS webpage , shown above, to make the discussion more clear. Turns out you can get true ovals with something like `border-radius: 100px / 40px`...

Monday, January 18, 2021

on ai and problem solving

I've been participating in a FB thread about AI starting with the question, is there a definition of human level intelligence - interestingly half the participants started talking about AI and the other half about animals.

I learned about MuZero, the successor to AlphaZero and AlphaGo. I knew they've been using Atari 2600 programs as readily available programs for evolving and evaluating virtual player / learning algorithms, but it does my heart good to see the phrase "a standard suite of Atari games" (here's one example virtual gameplayer including how it stacks up to humans.)

The thread introduced me to the Specification gaming examples in AI Google Doc, where various programs have found solutions that are "technically correct" (the best, or maybe worst, kind of correct) but exploit bugs in the virtual environment or success criteria.

That doc reminded me of this set of humans thinking outside the box with clever solutions to problems... the fitted sheets with labels specifying top/bottom vs sides was good, also the shovel with small holes to avoid suction for digging in mud. Also "wake me for meals / do not disturb" sleep masks for planes...

And I thought of the thread when I saw this quote:
In a way, human's are the only species to have "evolved backwards". By developing such a complex mind, we create our own problems.
--u/mkemp2804 on r/showerthoughts
Obviously a little tongue in cheek, but it covered the domains of animal intelligence and humans looking for AI assistance in their own problem solving pretty well.

Wednesday, January 13, 2021

regular expressions to make (and test) prepod URLs

Javascript regular expression that slightly smartly puts back a preprod version of random site URLs, but is smart enough to only do it for "mycompany" sites...("mycompany. mycompanyboard.nl, and othercompanysite...)

const preprodUrlSubstring = 'www.mycompanyprepod.';

const exp = [
 'https://mycompany.com/profile/',
 'https://www.mycompany.com/profile/',
  'https://www.mycompany.co.uk/profile/',
  'https://mycompany.co.uk/profile/',
  'https://www.mycompany.co.uk',  
  'https://www.mycompany.co.uk/profile/',
  'https://mycompanyboard.nl/profile/',  
  'https://www.mycompanyboard.nl/profile/',  
  'https://othercompanysite.com',
 'https://www.twitter.com/mycompany/',
  'https://facebook.com/othercompanysite.com/',
 'https://www.mycompanyprepod.mycompany.com/profile/',
];

const fix = (currentUrl) => {
  const pattern = /^(https?:\/\/)(www\.)?(mycompany\.| othercompanysite\.com| mycompanyboard\.nl)(.*?)$/i;
  return currentUrl.replace(pattern, `$1${preprodUrlSubstring}$3$4`);
}

exp.map((thing)=>{
  console.log(`expect(convertUrlToPreproductionVersion('${thing}')).toBe('${fix(thing)}');`)

});

I like how I then had it make the jest test lines for the cases I came up with..

Oh and jsitor proved its value, it seems less fiddly then some of the other jsfiddle type sandboxes (sill don't understand the detail of autocomplete quotes and parens and what not though!)

Tuesday, January 12, 2021

the flex

 I'm still tempted by the poster for CSS-Trick's awesome reference page for flexbox...

It's funny. A lot of design problems can be solved by flexbox - and often css-grid feels like overkill... but often, you don't actually want that "pinterest" like effect of things flowing to the next line. More often than not it's a 1-axis kind of thing.

But sometimes doing sizescreen break-point type stuff, you have to choose the lesser of two evils to stop stuff from hopping up or down a row: either non-(or less-)semantic divs representing your row boundaries, or a heap of "flex-basis" settings for the various sizes. Neither option is quite ideal...

a new burger king logo

Burger King is doing a rebrand! Here is some work they did before settling on the version at the top left. So clever!

 


I really think Burger King is superior in every way to McDonalds, though I know some fry aficionados disagree.

emoji snobbery

Historically, I find myself being a bit of a snob about emojis and other decorations for electronic communication. Which is weird, I like to think of myself as an egalitarian! Chat and email, to a lesser extent) are casual mediums, yet typed text is a bit "cold" - lacking cues of gesture and tone, so I should appreciate ways to warm it up. And in my head, I do.

Way back when, closer to my English Major days (I was a double major in that and computer science) maybe I thought "literate folks should be able to express via words, damn it" - and that stance seems to be where my heart is too often stuck. In practice, I'll shun a casual form of expressing, then come around to it, eventually - and I think finally even use it more than most. (I seem to use laughing emojis to end my phrases a lot, even if somethings not being funny. )

I'm not sure if I was ever against punctuation "emoticons"/smilies when they were typographical jokes:
:) :-/ :D etc. I definitely rebelled when AOL messenger start popularizing cartoon versions of the same idea... now I see that the current palette is far more expressive - with a little room for trouble as some emoji read differently on different devices. 

Then for the longest time, I was against "LOL". I started using it strictly sardonically, now kind of a mix. "Ha!" is still better.

My current "I sort of hate it now but might come around" is per-message emoji decoration. (Heh, and I know there's a blue bubble/green bubble thing, where the decorating is handled more gracefully on iPhones than on Android devices) 

Especially during work Slack convos, if it's an argument or general discussion with some disagreement... adding a "+1" to one side seems to be piling on a bit, maybe?

One friend is really free with per-comment hearts and smile decorations in FB messenger. And again, my head can see it as the logical equivalent to nodding and other non-verbal feedback in conversations, but my gut is slow to warm up to it.


Tuesday, January 5, 2021

style components - can swap the actual element

I still have my doubts about styled components, but lots of folks love 'em.

For technical reasons we had to have links in a navigation sometimes be a button.

My first pass, I had some code that was like 

      {!isButton ? (
        <a {...(id && { id })} href={url}>
          {label}
        </a>
      ) : (
        <button {...(id && { id })} }>
          {label}
        </button>
      )}

(the shtick with the "id"... I'm not sure if there's a better way to conditionally include an object propery as a component attribute...)

Anyway, by using "as" which overrides the underlying DOM element for a styled component, we can make the conditional a little more focused:

      <VerticalNavigationItemContent
        {...(id && { id })}
        as={isButton ? 'button' : 'a'}
        {...(!isButton && { href: url })}
      >
        {label}
      </VerticalNavigationItemContent>

So as for the definition of VerticalNavigationItemContent, it doesn't matter if it's a "a" or a "button" to start, like in the definition:

export const VerticalNavigationItemContent = styled.a`

Which seems a little weird to me? Kind of shades of calling everything a div :-D But it works ok. 

Monday, January 4, 2021

"natural" scroll direction and keyboards

A few months ago I wrote about the ux of scroll direction, in part to complain that I thought it was foolish Mac conflated the scroll direction for touchpads and for scroll features on a mouse. This maybe makes sense for the "Magic" mouse with its touchpad like top, but for a scrollwheel, historically it wasn't the way things were done - moving the wheel was moving the scroll pointer - moving the viewport rather than virtually moving the document.

For a silly New Year's Resolution I decided to get used to "natural" scroll direction for the cheap bluetooth mice I prefer, so I could stop dipping into Preferences to change it (the plug in software was too unresponsive) It's gone a little better than I expected.

But now I'm wondering... as I scroll through a webpage with arrow keys, they're also opposite "natural" scroll direction! You press down,  and the document "moves" up, because down is applying to the cursor / viewport and not to the document itself - even though there's no cursor. Hmm. I wonder if they will ever try to change that...