Saturday, September 26, 2020

Fail Faster. Follow the Fun.

Marc "MAHK" LeBlanc on game design: 

"Fail Faster. Follow the Fun."

That quote via this video:

I'm proud of the little games I've made but sometimes I wish I had fleshed out more of them... most are just barely enough wrappers for playing with a lovely little mechanic.

awesome modern css layout tropes

Excellent video, "10 modern layouts in 1 line of CSS"


I think the name is mildly misleading (the 1 line is the core idea but you'll still have other layout work to do) but it's great stuff! It has an accompanying website with CodePens.

Thursday, September 24, 2020

the importance of rapid iteration and proximate feedback

A couple things I've been experiencing (reading, listening to, and programming) are having some synchronicity:

Daniel Kahneman, talking with Sam Harris on what it takes to develop intuition - to impress knowledge into your immediate, System 1 processing vs your slower, rational System 2:

Now, in order to recognize patterns in reality, which is what true intuitions are, the world has to be regular enough so that there are regularities to be picked up. Then you have to have enough exposure to those regularities to have a chance to learn them. And third, it turns out that intuition depends critically on the time between when you're making a guess and a judgement, and when you get feedback about it. The feedback has to be rapid. And if those three conditions are satisfied, then eventually people develop intuition. 

Maddy Myers talking on the podcast Triple Click on Which Games Do We Wish We Were Better At? - specifically at around 16:00, on playing at local competitions for fighting games

And then hearing from people, in person, feedback on what I was doing wrong and then using that immediately to improve...you really can't beat that [...] because you're getting that hands-on lesson constantly... and matches are short enough that you can get actually quickly implement that! Which I feel is another reason why I could more immediately see improvements there then at something like Starcraft, where I feel like I did 600 things wrong, and the next match is going to be completely different than this, so who frickin' knows! - But at least in fighting games you can change one thing and see a big difference and that always worked better for my learning style.

And I'm back on my own, why does my System 1 have a such a dislike of unit tests and disinterest in locking down javascript via typescript, when so many other smart developers love both so much? 

I think I answered this question on this blog in 2016:

I've found SOME parallels in the way I write code relative to the Proper Unit Tester (PUTter). I'm a ridiculously incremental coder; I hate being "wrong", and kind of scared of making a block of code so big that when I'm finally ready to run it I don't what part might be going wrong, and so I've always relied on tight code/run/eval loops... lots of manual inspection and testing of assumptions at each little baby step. Often I'd even write little homebrew test functions for the various edge cases. The difference between old me and a true PUTter, then, is I would then throw away those little functions and logging statements in the same way a building site takes down the scaffolding once the building is standing. But PUTing says - look, that's how you know this code still works in the future, nurture that scaffolding, keep it around... make it survive any refactoring, fix all the mocks when the endpont input or output gets added to, etc etc.  That's a huge cost, and I'm still trying to convince my self it's worth it.

TypeScript is a bit of friction on that kind of iterating axel... it tends to violate DRY; if you are messing with the interface of a function, and especially if your typescript system is a bit hair trigger (like yelling at you for unused values) you might have to make changes 3 or 4 places. Yeah, it's better than undocumented "oh we assumed this random key was in the props object but forgot to tell you", but it's also not much of a replacement for updated real documentation. 

Unit tests can be similar, especially for UI. I'm not sure if I've just never landed in a place that was doing it right, but every place I've been at, the correct response to "oh the unit tests broke!" is not "time to fix the code!" but "time to update the unit tests!" In general, basic developer testing confirms the new feature is working, and the old functionality isn't blatantly busted - and unit tests are often awkward enough to set up (in terms of mocking an environment for the code to run in) that they are almost always more fragile that the core code... they are canaries in the coal mine that keel over if a miner passes wind.

The other thing about UI is that dependencies often aren't well described. Today we ran into one where a change to the CSS line-height property of a container label was making our checkboxes break. There wasn't really a way to capture in that in a unit test, unless you were doing screenshot-y ones. (We use text-based snapshots... a few years back I interviewed at one place that was using graphical screenshots which might be more revealing) 

A Unit Test is setting up a fragile glass ant farm to make sure a few little ants are still toiling away - but that's no way to test the health of the colony, and I don't see why so many developers don't see the costs of them in terms of developer time, both at the outset and as the codebase extends. 

The errors that do show up as a codebase extends are emergent... most well sized units are too small to fail, the trouble happens at higher levels. And yadda yadda, what if you have to refactor the unit, and want to make sure it works? Again, the number of subtle problems I've seen introduced with that kind of unit refactoring in real life I could count on one hand.

typescript and style components gotchas

Sometimes typescript + style components make a hot mess of build errors as you pass around various interface-y objects. This article outlines some good practices, like how you can define the props your styled component is using:

type ButtonProps = {

  primary: boolean;

};

const Button = styled.TouchableOpacity<ButtonProps>`

  opacity: ${(props) => (props.primary ? 0.5 : 1)};

`;

Monday, September 21, 2020

understanding package-lock.json

A coworker recommended this article when I was trying to figure out why package-lock.json should be checked in.

I could see the appeal of package-lock.json as a snapshot thing, so you could trace back and recreate an environment in production or whatever. But the idea of pulling down another dev's updates that might have changed both it was and good old package.json was weird... like the latter is "what the versions should be" and the former "what the versions actually are", so until you run npm install, you're kind of living a lie?

In short I was trying to reconcile other documentation that made clear 

One key detail about package-lock.json is that it cannot be published

with this newfound passage:

The idea then becomes that instead of using package.json to resolve and install modules, npm will use the package-lock.json. 

I guess npm using package-lock.json to tell it what to install is the weird/new bit for me... so npm says "I will install what's in package-lock.json, knowing what needs to be installed by comparing it to what's actually in node_modules... unless package.json needs something newer, in which case I will install that newness and update package-lock.json accordingly"...

I guess it makes sense but it feels a little weird, like there's not quite a single source of truth for stuff.


Friday, September 18, 2020

mocking fetch

Had a rough week with unit test. The status quo of unit testing in React seems a little rough; the fake-y environment you set up to fake being a browser seems at least at delicate as the actual code you want to test...

I had almost forgotten discovering react-testing-library which seems to be the future, and a little closer to unit tests that simulate users rather than Enzyme's way of getting lost in a see of props. There was some learning curve though; the finders like screen.getByLabelText() and screen.getByRole() seem designed to help get devs thinking in terms of a11y issues (like making sure aria roles are accounted for etc) so if you're used to thinking "oh I'll just grab it via the element id".... it kind of discourages that sort of thinking.

I had a surprising amount of aggravation faking the client/server response. I was hoping code like this would set up Mock Service Worker as a nice little endpoint:

import { rest } from 'msw'
import { setupServer } from 'msw/node'

//... later in the test: 

const server = setupServer(
  rest.get('/endpoint*',  (req, res, ctx) => {
    return res(ctx.json({ results: ['abc','def','ghi'] }))
  })
)  
beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())

Though I'd also have use a polyfill for fetch

const {Response, Request, Headers, fetch} = require('whatwg-fetch');
global.Response = Response;
global.Request = Request;
global.Headers = Headers;
global.fetch = fetch;

But I couldn't get it to work; somehow the fetch().then would never resolve. It's still easy to get trapped up on this asynch stuff!

So after banging my head against it I went with the less recommended practice of handrolling a stubbed out fetch:

const mockSuccessResponse = {results: ['abc','def','ghi']};
const mockJsonPromise = Promise.resolve(mockSuccessResponse);
const mockFetchPromise = Promise.resolve({
  json: () => mockJsonPromise,
});
global.fetch = jest.fn().mockImplementation(() => {
  return mockFetchPromise;
});

//..and later
global.fetch.mockClear();
delete global.fetch;

Blargh! Good enough for the moment I guess.

Tuesday, September 15, 2020

Saturday, September 12, 2020

the ux of scroll direction: natural and y-axis: inverted

I recently reconfigured my work-from-home desk to have my laptop on a stand - it raises the webcam to a more flattering level, makes its screen easier to glance at (next to my main monitor, rather than beneath), and keeps my wrists from the unpleasant heat of a warm machine.

I switched to a plain old mouse after a failed attempt to use a "magic trackpad" in a laptop-like configuration. Macs are frustrating though because they have a single "scroll direction: natural" setting that applies to both mice and touchpads - but I want exactly opposite behaviors for the two.

The "Natural" setting makes the touchable surface of the trackpad act like the surface of an iPad: if the image on the screen were of a piece of paper, it's like you're dragging the paper with your two fingers - so to see the lower part of the paper in the glass of the screen, you drag up. 

But historically, mice scroll by dragging a little marker in the scrollbar, and in the 90s mice added a physical scrollwheel (it's so nice to have that physicality back with my cheap bluetooth mouse - though occasionally frustrating since I can't easily scroll left and right with it.) Anyway, with that scroll marker, moving up moves the viewport up... so if you want to see the "lower part of the paper in the glass of the screen" you drag down.

But Apple treats this as one setting! (I'm not sure what it feels like to use Apple's "magic mouse" that has a trackpad-ish surface...) There are programs that allow you set the two differently, but the hack I installed long ago has noticeable lag where a scroll starts moving the wrong way and then corrects.

There's an interesting parallel to life in video games, especially 3D run around and shoot games. The "standard" controls for aiming the crosshairs make a certain amount of intuitive sense: if the target is above where you are aiming, press up on the controller to aim at it. But for a certain population of gamers they will immediately head to settings to reverse that y-axis - they want to press down to aim at the higher target.

This diagram attempts my best guess as to why:


The first example, "normal", shows how the controller (represented as a compass rose) is mapped to the tip of the gun. So to aim at the higher target, you press up (and the character in the viewport moves down).

Gamers who prefer inverted controls do a different mapping... it's to the viewpoint, or you could say the top of the avatars head. To hit a higher target you pull down - or rather, back, and the viewport slides up.

The third sketch shows how this is akin to how flight simulators or flying games in general work - a pilot pulls back on the flight stick (which corresponds to down on a more humble controller) and the plane tips back and ascends. 

I find this difference in expectation among gamers fascinating (and frustrating; some games, like "Luigi's Mansion 3", don't bother to put in a control scheme to accommodate the "inverted" preference.) I think gamers who grew up with keyboard controls, mouse aiming will hardly ever long for inverted-Y controls

And there's that parallel with the mouse/trackpad scrolling: my girlfriend thinks I'm weird for ever using "natural" scroll for my Mac trackpad - I'm guessing her model of it is based on the scroll position and/or the viewport, rather than the content.

And they say there's a similar ambiguity in how people map space and time - does "we had to push the meeting forward 2 days" mean the meeting is now earlier or later than it was planned? Your answer may have to do with if you see yourself as fixed, and time heading towards you, or time is fixed and you are travelling through it... and some cultures have entirely different ways of mapping the two.

Fun stuff in UX! Don't assume your audience maps space the same way you do...

Friday, September 11, 2020

ui and testability: the ant farm, the GOTO statement

I have never been a true aficionado of unit testing; 

  • I've seen too many that test implementation and not true functionality and that break even though the underlying code is fine after a refactor
  • as a form of "documentation" they aren't particularly easy for a human to read and glean information from (though I admit they are more constrained to be updated along with the code, unlike external documentation)
  • when written by the same coder who wrote the code under test, they assuredly won't test much that the coder didn't think of when doing the implementation, and most true small units should - frankly - be "too small to fail".
  • when implemented and providing high code coverage, they're sometimes cited to give a false sense of security

But mostly, especially for UI, the bugs I've seen that make it to production all depend on context; they're an emergent property of interacting parts that don't properly understand each other enough to play well; 

  • the unexpected format of the response from the server - (oh yeah, the format in the db and endpoint updated 2 sprints ago but we forgot to update the code and the tests!)
  • the odd browser incompatibility for a CSS or even Javascript syntax
  • the surrounding DOM of the page leaking into the embedded unit and doing odd things
  • the text value from the server (or the user input) was much longer than the happy path examples on the designers happy-path mockup and things look weird
  • a surprising race condition or other sequence-based context-y problem
None of these issues are particularly amenable to being caught early by the isolated confines of a unit test. (And half of them aren't easy to see if your test runner output is based on a command line and not human inspectable UI.)

When you make up a unit test, it's like you set up a tiny 2 or 3 ant ant farm and carefully observe your ants correctly doing their own thing in those glass walls, and sure, it's important to make sure your ants are basically healthy - but there's only a small chance that that's how you're going to catch the problem with all the ants of the colony ahead of time.

The sweet spots for unit tests are in functional programming: ALL relevant input is known / there is no other reliance context to botch things up, a manipulation of that input  - complex enough to be worth testing! - is performed, and the results can be inspected in their entirety. And one reason why declarative programming for UI has gained so much popularity is that of all styles of UI code it has the highest chances of meeting that criteria... but even then the tools for making a component, faking an interaction with it, and seeing the result are just so-so at best. 

Anyway, I didn't mean this to be quite this long of a ramble - mostly I wanted to set up this quote I snagged in 1998:

"Menu items are the modern programmer's way -- even that of the Java programmer, who is too pure of heart to use pointers -- of putting an obscene number of unpredictable GOTO statements everywhere in his code." -- jhayward@imsa.edu via Usenet's "rec.humor.funny"

 Very old school in both tech and gendered language, but I think about that in the context of UI a lot.

Tuesday, September 8, 2020

safely unpacking nested key/values in javascript/ECMAscript - the mess of the null propagation operator

 So if you have an object like 

const foo = {
  bar: {
    val: 'got this!'  
  },
  apple:{
    banana:{
      cherry: 'fruit'
    }
  }
};

and you want to safely get foo.bar.val or check on foo.baz.val without getting errors... there's a good syntax for it based on question marks - but isn't yet part of the the standard: foo?.bar?.val or foo?.baz?.val - it's scary, because it seems to work in some browsers, but isn't considered standard.

I made up a code pen that says something like this function might be an ok substitute, if less clean:

function getNested(obj,...keys){
  keys.forEach((key)=>{
    if(obj === undefined || obj === null) {
      return;
    }
      obj = obj[key]; 
  });
  return obj;
}

Then you can call getNested(foo,'baz','val')

Sunday, September 6, 2020

the return of the obhack

Back in the 90s I was often on Usenet - a distributed set of conversational message boards. The level of discourse was generally pretty high, maybe because of the system's academic routes and relative lack of anonymity, and you could use whatever newsreader you liked and your single account to interact with all kinds of topic-based groups - kind of like Reddit, but more geared to writing in paragraphs rather than sentences.

Besides "rec.games.video.classic" and "alt.fan.cecil-adams" my favorite group was "alt.hackers" - hackers in in the sense of "making cheap and cheerful kludges" vs "hacking into computer systems". (Or the MIT sense of "grand stunts") It was "self-moderated" - there was a specific technical trick you had to pull in order to post there. The "netiquette" of the group suggested you post an "obligatory hack" or "ObHack" if your post would otherwise be off-topic.

I kept a list of my own ObHacks for future use, and there's still a part of my brain that thinks "oh, that was a clever little thing I came up with, I should file that away for an ObHack!" So here's two of those about the lockscreen wallpaper for my phone.

One is for band: I take a snapshot or screenshot of the setlist and then post it as my lockscreen, so I can quickly see what songs are coming up without fiddling with my phone too much. It's not quite as classic as taping a list to the floor but it's a lot less work.




(Plus then afterwards I have a nice memento of the concert until I remember to put my wallpaper back...)

Anyway, I noticed that changing wallpaper and case is a nice way to make a phone feel refreshed and new, so I got this bright yellow case to replace the blue silicone one that was starting to wear. I decided to lean into how "bumblebee" like it made my phone look and made up this wallpaper:

The slight ObHack cleverness was using a screenshot to layout where the bee appeared - I wanted it so that even if a song or podcast was playing, I could still see the bee, so I took a screenshot and used it as a layer to get the placement right:


Then I hid the layer and saved. (In practice, the bee was a smidge lower than where I thought it would show up, but I decided on a new shade of blue so I had to redo it anyway.)

Incidentally, Piskel was a lot better at making the pixel art bee (I stole the design by googling "pixelated bumblebee" and seeing these cool Etsy earrings)
 




Friday, September 4, 2020

jmespath - query syntax for json

I hadn't heard of jmespath before this slack msg:
Haha my coworker said she is naming her first child Jmes, in honor of Jmespath lol

but I dig it, I've sometimes thought I needed something like that. 

the spatial ux of thinking about time itself

I've always been interested in how humans visualize and put metaphors to time ("life's like an hourglass glued to the table" I've been told) Some of my interest was sparked by recognizing how idiosyncratic my own way of spatializing the course of a year and the course of a week as counterclockwise circles (I made visualization of those timehoops a while back)

All of these are akin to synaesthesia - time isn't inherently spatial, but we find the metaphors for it useful.

This Anthropology.net article discusses a few of those metaphors that were less familiar to me
  • I knew of the Aymara of the Andes, who reverse the more common view of marching into the future with the past at our backs - "the past is known and has been seen, and thus lies in front. The future remains unknown and unseen, and is relinquished to be behind the ego".
  • For many speakers of Mandarin, "the past is referred as above the speaker. And the future referred to as below the speaker." (I'm not sure if the metaphor is that of plummeting? That's almost as morbid as the hourglass glued to the table!)
  • For the the Pormpuraawans of Australia "time always flows from east or the past to west or the future" regardless of the current location and orientation of the speaker.
  • For the Yupno peoples of Papua New Guinea, "time is a topographical concept, time winds its way up and downhill." (The article points to speculation on how this might relate to the group's literally uphill migratory history.)
If you dig this topic, you might like the book "Einstein's Dreams" by Alan Lightman, that posits the great thinker dreaming of different ways times might behave, and how humans might respond. (If time slowed down noticeably with velocity, would people attempt to live their life always in motion in order to have more time, put their houses on wheels and go go go? Or in a universe where time slowed based on proximity to a central point, would adults with young children or old people journey to be nearer that point, while people trying to flee bad memories would head as far away from it as possible?)

Thursday, September 3, 2020

Tuesday, September 1, 2020

workspace noodling: laptop in front vs old school keyboard and mouse

 Random self-indulgent first world nerdery: for a long time I've really liked having a second monitor up above my laptop, using the laptop as the keyboard and trackpad and secondary monitor. It seemed like such a no-brainer, I almost had pity on my coworkers who put the laptop on a stand and needed a separate mouse and keyboard. I loved how the trackpad is right there beneath your thumbs, none of that reach over for the mouse, and just how efficient it seemed in general - and also the elegance of having the same arrangement when on the go or at the desk, so never having to retrain my hands...

Well... I've been having second thoughts. Honestly it's mostly because I was tired of warm wrists from overheated laptops, but also I realized I was using the laptop screen less because it was so low, plus I knew I would get a better webcam angle with the laptop riding higher.

Sadly, I don't think anyone makes a good "keyboard with trackpad integrated in front" (honestly, if I could somehow adapt the new iPad Pro magic keyboard/trackpad combo for use on a Mac, that would be ideal...)

So I bought a laptop stand, grabbed an old Apple Apple "magic" keyboard Melissa wasn't using much, and bought a "Magic Trackpad" to place right in front of- recreating the laptop w/ trackpad-at-the-thumbs experience. But, it was uncomfortable, and prone to accidental hits... even after several revisions of lego-constructed wrist rests:

So I guess I'm back to keyboard plus mouse... I still find myself reaching my thumbs down but there are some advantages to the mouse: the cheap bluetooth mouse I got has a scrollwheel, which is a tactile pleasantness I had forgotten, and a distinct button for right clicks, which Mac still supports, albeit grudgingly. Still, it feels so oldschool to need a mousepad (for my white IKEA desktop) -- it's like I'm back in the AOL generation... 

Sunday, August 30, 2020

the apple family

The Lost in Mobile blog (and its watch-based spinoffs) has be reformed as McGST, a very enjoyable read. In a recent post about his family, Shaun noticed how Apple-centric they all were.

I too am Apple-centric with most of my gear. I wrote:

Yeah, seems like it’s a mix of:
– loyalty / other competitive products decent but not having benefits worth re-learning (phone)
– anemic competition in the category (watch, tablet, laptop (at least if you like Unix-y things))
– prestige and/or superior design (wireless earpods)
– familiarity w/ and cohesion of the product line landscape

Alan Kay said “People who are really serious about software should make their own hardware.” – Apple has been doing that in a more cohesive way for longer than anyone. Samsung doesn’t do much in terms of software (tho their smart TV UIs had made tremendous strides, I’ve lived through) — Microsoft was late to hardware and never got the hang of mobile, Google has chromebooks and seems to not be excited about pixel….


Saturday, August 29, 2020

laws of ux

 The Laws of UX has one of my favorite maxims that I learned from Larry Wall who invented Perl:


Postel's Law: Be liberal in what you accept, 

and conservative in what you send.

minimal react

 Kind of a nice intro to minimal React, with as few libraries as possible

Thursday, August 27, 2020

the new hotness: design tokens

At work we've decided our next generation work for designers and developers will be based on Figma vs Sketch. Using Figma is a bit like using Google Docs instead of Office, in the sense of everything is browser-based and shared in real time, rather than passing files around (or using a supplemental program such as Invision)

I'm a little surprised that both programs are still fundamentally vector based, vs being grounded in like DOM elements or what not... though I guess this has a lot more flexibility, especially since it's not like web is the only target medium. 

Anyway, "Design Tokens" are the new hotness - in atomic design thinking, these are almost like the "subatomic particles", the consistent properties like color and padding that you'd expect to see applied across many different atomic units.

(Which really... is just designers discovering the power of key-value pairs. Some of my shtick is when I think what Perl showed me in the mid-90s, having only used C prior to that (along with some BASIC and LOGO) -- key-value pairs (associative arrays), duck typing, not having to manage memory obsessively, strings as first-class objects, and regular expressions - maybe key/value pairs was the most important...)

Anyway, this article goes pretty in-depth into the whole process of setting up design tokens in Figma and then the kind of js you would need to pull them out for use elsewhere, such as your CSS.

Tuesday, August 25, 2020

Friday, August 21, 2020

programming dbs for the people!

Paul Ford on how setting up little database systems is a very egalitarian form of programming:

 I've always loved that moment when someone shows you the thing they built for tracking books they've read or for their jewelry business. Amateur software is magical because you can see the seams and how people wrestled the computer. Like outsider art. So much of the tech industry today is about making things look professional, maybe convincing Apple to let you into the App Store to join the great undifferentiated mass of other apps. That's software. When people build their own Airtable to feed the neighborhood, that's culture.

[...]

I get asked a lot about learning to code. Sure, if you can. It's fun. But the real action, the crux of things, is there in the database. Grab a tiny, free database like SQLite. Import a few million rows of data. Make them searchable. It's one of the most soothing activities known to humankind, taking big piles of messy data and massaging them into the rigid structure required of a relational database. It's true power. Or mess around with Airtable or its no-code ilk. If you do it long enough and work with friends, you can do wonderful things. You can build data models that work well enough to feed people who need the help. That's real programming.

I think about something I heard about how in the 90s you could make a decent little business setting up little MS Access databases with custom Visual Basic front ends for small companies.

I've seen some of this with people using Google Docs and Google's survey tool - also I've seen some neat homebrew efforts for various Porchfests that often rival the results I've put into my sites for 'em, but took a lot less background knowledge.

I know I've gotten great utility out of a little Perl DB (later PHP, and overdue for a front end makeover) I made - just rows and columns and a customizable form, like a less-fancy, more functional Excel. I've made dozens of tables in it but mostly I use it record media I consume, coworkers I want to keep in touch with, and lately to assemble my monthly playlists.

Thursday, August 20, 2020

css woulda coulda... shouldas?

The Languages Which Almost Became CSS - fascinating glimpse of alternate universes.

I think CSS ended up in a pretty good spot. I like the nesting you get with SASS+LESS, and variables, but selectors are a pretty solid idea. IMO. 

Pity it took so many years for flexbox + grid to get established! Those "no we musn't use tables for display! Here us this wacky hack" days were terrible.

Wednesday, August 19, 2020

a11y irony

 This was an entry on my LinkedIn feed. Can you spot the irony?

It's a pretty decent article by a buddy of mine.

Tuesday, August 18, 2020

we remember less taking in life through the damn zoom screen

The Covid-19 lockdown, after all, was full of new experiences. Some were grim: I lost a friend to the disease; I smashed my face up in an accident; we had to wear masks and avoid physical contact and worry about where the next roll of toilet paper was coming from. Some were more positive: the discovery of new pleasures, the honing of new skills, the overcoming of new challenges.

But I doubt I am alone in finding that my memory of the lockdown months is rather thin. No matter how many new people or old friends you talk to on Zoom or Skype, they all start to smear together because the physical context is monotonous: the conversations take place while one sits in the same chair, in the same room, staring at the same computer screen.

The psychologist Barbara Tversky, author of Mind in Motion, argues that our minds are built on a foundation of cognition about place, space and movement. That creeps into our language with phrases such as "built on a foundation" and "creeps into". Our brains started by helping us process our surroundings and the threats and opportunities they presented. Abstract thinking is an adaptation of those basic spatial capacities.

Tim Harford on how  We won't remember much of what we did in the pandemic.

A few thoughts: one is thinking about how I have already been oddly obsessed with daily notes - aiming for a daily blog entry (which I try to make less about me and more about stuff I find), a "mundane" journal entry, and for 7 or 8 years now a "One Second Everyday" video snippet. I guess I dislike that feeling of lost time.

The other is a tangent - I think the ambient details of surroundings is one of the reasons why RSS and other tools to retrieve "pure" content but with the same visual context each time never worked for me- the visual details surrounding an article give it a flavor that helps it land in my mind.

Finally - I wonder if there's a lesson in artificial intelligence like this. Tversky writes about how the human path to thinking about the world so often depends on the physicality of it all, of being an actor in a space and learning the principles of cause and effect (with ever present considerations like gravity and mass and texture) I read her book last year and actually corresponded briefly with her, very good stuff.

Saturday, August 15, 2020

binary clocks (weird ways of showing time, and recreational programming)

Years ago I bought my Uncle Bill one of those geeky binary clocks... just for fun this weekend I made up a virtual version of that, along with a few variations...


I love both playing with different ideas of representing time and just being able to do recreational programming in general, take a few hours and make an idea like this a reality.

P5.js is such a good choice for that, for stuff you want to be able to run in a browser, and with maximum flexibility.

Because I knew I'd want multiple instances of clocks on a page with explanatory text in between, I had to use p5's "instance" mode. The structure got a little wonky but was kind of fun to see what code could be shared among the variants - I wanted to make sure both that things were efficient (and so not needlessly refreshing each clock at 20/30 FPS or whatever) but also that all the clocks were well in synch...

Friday, August 14, 2020

MacOS minimize paradigm

Almost 10 years ago I wrote how the Windows task bar was better than the OSX Dock but since then I've come around... Windows' alt-tab is between running windows only, regardless of app, while back divides it between cmd-tab for apps and then cmd-` within apps. I now think that double wheel nature is superior.

Another difference in behavior only now makes sense to me: what happens when you minimize a window. On Windows, it just gets the Window out of the way, but on Mac it tucks in the Dock - and it is no longer in the cmd-` cycle of windows, which contrasts with Windows where it's still in the loop.

It also doesn't popup when you close out all the other open windows in the app.

Now I use why it's like that- instead of just being a screenspace management thing, it's like a little safe storage box. You can put some a browser tab you want to get back later there without worrying about accidentally closing it, or you can have a long run terminal process there, stuff like that.

It's how long it takes me to realize little things like that that make me hesitate before trying Linux fulltime, since I'm sure there are dozens and dozens of little behaviors I expect that Linux may or may not support out of the box - or if there's a setting to control it, I'm not sure how to describe what I'm looking for to find it in settings...

Thursday, August 13, 2020

history of the web

 Nice piece on Tim Berners-Lee, inventor of the web. My Kevin Bacon number for him is 2, my team lead was working with him a bit around SOLID, trying to think of the next generation of user-controlled information and connection.

Wednesday, August 12, 2020

random gripe - why are html checkboxes so 1997?

 In an HTML/CSS world that has grown into flexbox and grids and typeahead and disclosures (details/summary element) it is really bizarre that stuff like checkboxes don't have CSS styling, and if you want something pretty you have to build it up from div scratch (hiding the actual element but leaving it there for screenreaders)

Thursday, August 6, 2020

typescript-y factoids

I need to up my typescript game so I've been reading the full docs.

I know a lot of people complain about about JS's loosey-goosey ducktype nature, but didn't realize til I read the TS docs that
1 < x < 4
is true no matter what numeric value x is.

Also, I was wondering if typescriptlang.org was the canonical site, with a name like that - guess so. Seems like Typescript is a 2007-2010 era CMS that grabbed the better domain...

Also I'm sort of glad to see that according to the excellent typescript playground, this kind of shenanigans will produce an error:

interface Person {
  name: string;
}

interface Teacher extends Person {
  id: string;
}

interface Student extends Person {
  id: number;
}

interface StudentTeacher extends Teacher, Student {
    catchphrase: string;
}

I remember an old compsci teacher, back when C++ was sort of new, warning us about diamond-shaped inheritance trees. Maybe more problematic when those members were functions vs variables? But still. 

turn.js for a highly skeuomorphic magazine page turn effect

Years ago I had a side project to make the web version of the WhiteWave Foods Company Annual Report - they request I use turn.js which makes an intensely skeuomorphic page flip effect, using the mouse or pointer to drag the page over:


A bit gimmicky but rather satisfying! It was pretty easy to setup if memory serves (it has been a while)

Tuesday, August 4, 2020

conventionally committing

My current team has adopted the Conventional Commits standard, a way of bringing some of the chaos and messiness to heel.

The format is:
<type>[optional scope]: <description>

[optional body]

[optional footer(s)]
where type is fix: feat: build: chore:, ci:, docs:, style:, refactor:, perf:, test:, etc. And I think description is meant to be imperative, "do ___". So the example on that page:

feat(parser): add ability to parse arrays

(I'm mostly making this entry to remind myself of the name, "Conventional" has poor mental stickiness for me, and by putting something on my blog I have easy access to both the term and then the example...)

Monday, August 3, 2020

typeahead in html5 (datalist)

I was surprised to find out out html5 now has suport for "typeahead" - where you start typing and then get suggestions that match in a dropdown.


w3schools has a pretty good example:
<form action="/action_page.php" method="get">
  <label for="browser">Choose your browser from the list:</label>
  <input list="browsers" name="browser" id="browser">
  <datalist id="browsers">
    <option value="Edge">
    <option value="Firefox">
    <option value="Chrome">
    <option value="Opera">
    <option value="Safari">
  </datalist>
  <input type="submit">
</form>



gettin' old

Ctrl-Alt-Delete: The Planned Obsolescence of Old Coders - as a 46 year old, I think I'm lucky because I kind of "pass" younger, in outlook, life circumstance, and appearance. And I haven't had much drive to go into middle management. 

Sunday, August 2, 2020

make the whole parent td clickable for a radio button (without jQuery)

TL;DR: if you have a radio button (possibly with a caption) inside of a table cell, and you click in anywhere on the cell to change the button, put it (and maybe the caption) in a label but use CSS to make the label "display: block;"

Making a simple "what songs should we play" survey tool for my band, something like:


I had put a label around the caption and the radio button in the table, something like 

<td><label>Yah!<br /><input type='radio' name='songname' value='1'></label></td>

Using label like that is the simplest way to make both the button and the caption clickable, but I noticed the empty space to the left and right of the radio button wasn't clickable... bad UX!

I Googled around for a solution, but most of the answers were jQuery. Bleh!

Eventually I realized, making the label display:block; would effectively have it take up the whole width of the table cell, and resolve my issue.

It took me a bit to get there - I mean, I knew this was a pretty decent case for a table (it is pretty much tabular data, after all) but I decided to try fixing it with a css-grid - that way I could make the label the equivalent of the table cells, and so the whole cell would be clickable.

It worked ok, I guess, but definitely reinforced that css-grid isn't a good replacement for a <table>... not having the equivalent of <tr> is pretty unforgiving if you leave out an item! It seems very strange to be relying on modulus arithmetic to make sure your columns are consistent...

(Of course, some of this all goes back to the allergic reaction against using tables for layout that made life kind of stupid when we had CSS to style things but  flex-box wasn't widely available...)

Wednesday, July 29, 2020

the good ol' gadgets

Gizmodo's I Miss series is pretty fun.

clumping and the pleasure of recreational computing

Interactive version at toys.alienbill.com/ahaclumps
I'm rereading Martin Gardner's book "aha! Gotcha: Paradoxes to puzzle and delight" I found this book in my Aunt and Uncle's library and it left an impact on me, teaching me things like the "liar's paradox" ("this sentence is true!") and the weirdness of the Hotel Infinity, where the seemingly full hotel can make space for any finite number of new guests by having all the current guests move up that many rooms, or even an infinite number of new guests by having everyone take a room that's their current room number x 2.

In the section on Statistics Gardner talks about statistical "clumping". I remember this passage:
A striking experiment in clumping was discovered by A. D. Moore, an engineer at the University of Michigan. Moore calls it the "nonpareil mosaic" because it uses large quantities of nonpareils, a sugar candy manufactured in the shape of tiny colored spheres. Obtain enough red and green nonpareils so that you can fill a glass bottle with equal amounts of each. Shake the bottle until the two colors are thoroughly mixed.

Inspect the sides of the bottle. You would expect to a see a homogenous mix of colors, but instead you see a beautiful mosaic made up of irregular large red clumps interspersed with equally large green clumps. The pattern is so unexpected that even mathematicians, when they first see it, believe that some sort of electrostatic effect is causing spheres of like color to stick to one another. Actually, nothing but chance is operating. The mosaic is the normal result of random clumping.

If this seems hard to believe, try this simple experiment. On a sheet of graph paper, outline a 20-by-20 square. Take each cell in turn and color it red or green, choosing the color by flipping a coin. When the 400-cell square is fully colored, you will see the same kind of mosaic that appeared on the sides of the bottle.
But being in a page of relatively plentiful computer power, I made a digital version of this this morning and saved myself the 400 coin flips... see it yourself at ahaclumps

I made it so if you click higher or lower you get more or fewer colors (up to 8) and if you click left or right the number of squares in the grid changes. With small squares, I feel the clumping effect is a bit less pronounced, so I'm not quite sure I believe the original jar-of-nonpareils effect is well demonstrated here.

It is nice to be able to whip something like this up in an hour or so... two minor bits of cleverness, one is I do love p5's random() function that will return a random member of an array that you pass into (or an ordinary bounded random number  if you pass in numbers). Also if you look in the code there's a good excuse to use a little curry function (so I can put x,y into a single-ly dimensioned array) and then the code to show the current settings and then remove them with a timeout was some decent UX (IMO).

Tuesday, July 28, 2020

Saturday, July 25, 2020

the internet's first shareholder proxy voting system

Back in the mid-90s I was tasked with making "vote-by-net.com", the Internet's first Shareholder Proxy Voting system.


It even got a brief mention on the first page of the Wall Street Journal! (I'll make a scan if I run across the sheet again.) 

It was a bunch of Perl scripts, with a bit of JS flavoring. Had some weird bits like translating into IBM's old punchcard-based encoding EBCDIC as well.

Cleaning up old files I ran into this set of handoff documents (including servers and directories and passwords, oh my - but long since defunct.) 

Friday, July 24, 2020

good react-testing-library tutorial

I've never had an intuitive love of unit tests, preferring to test at higher levels -- but because many smart people disagree with me, and because unit tests give the warm fuzzies to so many manager-types, I don't make much of a stink about it.

My favorite low-key slogans expressing my view, which all revolve around the same core:
  • Unit Testing like testing 100 trees and assuming you have a forest
  • Bugs are usually an emergent property from connecting parts. 
  • A well-scoped component will usually be "too small to fail", internal errors should be pretty visible on inspection without much place to hide.
But I am of course compelled to make the best of the state of the world which considers unit test coverage to be table stakes for professional development. (And there are some advantages - a good set of tests can act as a form of communication to future developers.)

One positive development is the move towards React Testing Library over, say, Enzyme. The emphasis is on using the component more like a user would. I would suggest Robin Wieruch's How to use React Testing Library Tutorial.

A few thoughts I jotted on it:
  • love the whole "screen" element of it, and screen.debug() for high visibility
  • getByRole() seems pretty brilliant, especially the way you can leave it blank and the output of running it will make suggestions about what roles are available in the component - a clunky (but useful!) form of auto-complete.
  • the await stuff is interesting. (I admit I don't yet 100% deeply grok the "await" syntax at times :-D )
So, good tutorial for a good tool.

Thursday, July 23, 2020

adding minification via terser or uglify

I've never been much of a build engineer; in fact up until this year I was always more of a "<script src='..." kinda dude.

My lead asked me to add in some minification to our rollup-based build system, but luckily he'd already done most of the hard work, and trying different plugins was pretty easy! (Kind of one of those ones where it was going to be really easy or really hard.)

Uglify vs. Babel-minify vs. Terser: A mini battle royale provided some comparison, I decided just to go for uglify (which seems like it used to be the favorite) and Terser (which the article seemed to like.) I tried both but settled on Terser (looking back now in writing this I see that npmjs.com/package/rollup-plugin-uglify says "Note: uglify-js is able to transpile only es5 syntax. If you want to transpile es6+ syntax use terser instead" so it feels like the future is with Terser.

Both were easy to setup for Terser it was
npm i rollup-plugin-terser --save-dev
then adding
import { terser } from "rollup-plugin-terser";
and
terser()
in the plugins array of rollup.config.js

(Also adding typescript support with declaration files was pretty easy, see this stackoverflow.)

good newsletter for UI

Frontend Focus is a better than average newsletter on UI-ish things, very well-curated.

This post on CSS Grid was great. CSS Grid sometimes gets ignored because it's a bit fiddly and flexbox solves SO many design problems, but grid is pretty hip, and the article presents a nice answer for "content mostly constrained to a middle column but with some full width hero-ish images"

Wednesday, July 22, 2020

best options for shared screens on code interviews...

https://codesandbox.io/ seems pretty good for interviewing a candidate but.I think they need a github account? And the old fiddle https://jsfiddle.net/ seems less real-time share-y.

For codesandbox.io the trick seems to be doing "create workspace", a button in the lower left corner, and then maybe sending the link at top after creating a pen. But they do seem to need a github account.

On both sides of the interviewing table I've definitely had some frustrations with glitches in these.

ux ux ux

t's a little heavy handed but MS's medium post on their upcoming UI is pushing things in UX ways

Thursday, July 16, 2020

stating the obvious about the need for "mobile first"

Folks at my current company had to trace down a bug that occurred on specific phones with people uploading resumes... it made me write up the following:

[One take away for me is ...] it's just how people who have been a "techie" for over a decade or two might not fully get just how "mobile first" many folks' lives are! If you are half the time on your laptop anyway, stuff like applying for a job or deeply searching for a good used car - I would never start with my phone, a phone feels like a more casual thing. But - and I know this isn't a news flash- for a wide swath of folks, smartphones are THE way to the Internet. Like, every day the Apple App Store gets more new games than the entire decade run of the Nintendo Entertainment System (not double checking that factoid but it's at least roughly right) Tech's egalitarian nature has kind of exploded, and developers and designers - even the moderately hip ones - need to keep in mind that not everyone is as intimate with tech that sits on a tabletop as they are... :-D

Tuesday, July 14, 2020

a lerna learner, standing up a monorepo from existing repo/packages

Earlier I talked about our use of verdaccio so each developer can trivially stand up their own npm repo. At work we are heading towards a "monorepo" model, with one overarching project and github repository. This should not be confused with a "monolithic architecture": each project is about as standalone (or dependent on others as an npm package as always) as always, but lerna makes it easier to manage versioning 0 and to update a library and quickly start using the changes in a dependent package without the old version update tango... as I put it to one coworker:
w/o monorepo, a dev making a change in a library and seeing it work in the app using it was:
  • update the code in the library
  • update the version of the library
  • publish library to npm
  • update the app so it knows of the new version of the library
  • rebuild the app
But now that's like:
  • update code in library
  • run lerna command to rebuild
and that's it!
For my first example, I went to make a new monorepo called "one-love" to encompass two previously existing packages - ux-poc-stylish-app and the component library prototype it depends on, ux-poc-stylish-components.

Things were pretty well set out at lerna.js.org-
npm install --global lerna
is the obvious first step

Next steps:

git init one-love
cd one-love
lerna init

At this point I had to set up the git repo - I'm not positive you have to stand up the remote on github, but it seemed to help (It's funny how often I turn back to my git 101 notes - it's not like the steps are that hard...) Without standing up the repo, you get somewhat obscure errors like 

lerna publish:Error: Command failed: git rev-parse --abbrev-ref HEAD fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree

With the basic git repository I could use lerna import, bring in repos from my local file system:

cd packages
lerna import ../../ux-stylish/ux-poc-stylish-app 
lerna import ../../ux-stylish/ux-poc-stylish-components 
cd ..
lerna bootstrap --hoist

The "--hoist" argument was crucial, but not mentioned much in the main lerna docs.

So then in one terminal window I went to ux-poc-stylish-app and ran npm start. (It had been set up from create-react-app so changes to the core app were instantly visible) 

I updated a component in ux-poc-stylish-components, and then back in main one-love directory I ran "lerna run build" which replaced running "npm run build" in the library. ux-poc-stylish-app then noticed the change in the underlying library and rebuilt and reloaded itself.

UPDATE: javascript-monorepo-with-lerna is another decent overview, but starting packages/from scratch not importing.

UPDATE 2: fair warning, if you're using verdaccio and npm, your package-lock.json might be full of localhost:4873 ... they say npm is now agnostic about which registry you used to generate the package-lock.json but I'm not sure if that means the hosts in the URL don't matter??

Sunday, July 12, 2020

play a sound now if you want to play a sound later (challenges with sound playback on mobile devices)

(Shh, don't tell, I plan to get lots of mileage reusing this virtual card this year 'til July 4th next year, but I figure no one I want to reuse this for actually reads this blog... actually, I don't think anyone reads this blog.)

I had an idea for a fireworks-with-drum-sounds for a July 4th virtual toy (see also this one for loveblender and this one from 2009) but didn't make it in time, but my friend Johnny's birthday was a week after... and he is a drummer! So I made it for him since it was so on-topic and I miss his bass drum with my tuba.

It came together pretty well, you can see it here: toys.alienbill.com/johnny2020 , but sound wasn't working on mobile. Debugging can be such a pain in the butt, I tried like half a dozen things (MP3s not WAVs, make sure there was a touch even before loading the sounds, switching libraries, etc) because I know browsers and especially mobile are fussy about not playing a sound 'til after an interaction... turns out all my sounds were triggered by setTimeout()s, but if I played a sound immediately after click, even "the sound of silence", all the other sounds worked as well.

I also did the CSS `user-select: none;` to stop text from autoselecting with inadvertant doubletaps. I hoped "touch-action: manipulation; " would similarly stop the zoom in/out but less luck there... but I've spent enough time on this today.

Saturday, July 11, 2020

regularly updating in react with pure functional components

I think it's fair to say that playing nicely with setTimeout() and setInterval() is not React's sweetspot, especially when using pure functional components. I feel like I might be missing something (but even Dan Abramov seems to agree) but either something's inside the render (using useState, but being reset all the time in render) or it's outside, and it can't easily hit the state, or you do a mishmash and get an infinite loop of rerenders...

Making things a bit trickier was I needed to instances of these things (I might not have noticed how tricky this was if I was accidentally only using it in a singleton kind of way)

I think this works ok, for a little timer bar that sweeps across its parent...

import React, { useState } from 'react';
import styles from './RiffGrid.module.css';
import { millis2pixels } from '../Utils.js';

const CurrentTimePointer = ({ startTime, isPlaying }) => {
    const [nowish, setNowish] = useState(0);
    let timerRef = null;

    if (isPlaying) {
        timerRef = setTimeout(() => setNowish(Date.now()), 100);
    }
    if (!isPlaying) {
        clearTimeout(timerRef);
        return null;
    }

    return <div className={styles.timePointer} style={{ left: `${millis2pixels(nowish - startTime)}px` }}></div>;
};
export default CurrentTimePointer;

The trick seemed to be setting state with something from outside the system, in this case Date.now(); trying to pull from state for a simple increment gets all confused.

Friday, July 10, 2020

the bad ux of a microwave timer

So here is a bad photo of our serviceable little microwave:

It has a timer function on it, which is convenient, but I really wonder about the design choice to switch back to displaying the clock time after about 5 seconds. Even if you press the "timer" button to go back to looking at the countdown, after about 5 seconds it bounces back to the current time.

Not such a big deal, but I really wonder what went through the mind of the person who set it up that way. It's not like people are gonna set timers all the time, but when they do, isn't that "obviously" the most important thing they're using the microwave and its display for?

Sunday, July 5, 2020

refactoring to more idiomatic react keeping argument names with the spread operator

I'm making my first large React-based personal project, and I caught myself putting too many plain old function calls in my JSX, stuff where I might have a function like

const renderRowLabels = (soundSet, keyCurrentlyPressed) => {

being called by code in (in JSX) like

{renderRowLabels(soundSet, keyCurrentlyPressed)}

it's more idiomatic in React to make such DOM-element corresponding things look more like a tag... so the function becomes

const RowLabels = ({soundSet, keyCurrentlyPressed})  => {

since those two arguments will be passed as keys inside a props object, but we can destructure them on the fly so we don't have to refactor any code below.

Then we change the call to something like
<RowLabels soundSet={soundSet} keyCurrentlyPressed={keyCurrentlyPressed} />

But that's a little ugly, right? Redundant. With ECMAScript hotness, we can take advantage of how we are using the same names for variables in both places, and packup a nice properties bit again with the ... operator:

<RowLabels {...{ soundSet, keyCurrentlyPressed }} />

A little weird looking the first time you see it, but more true to how React sort of wants to be written...

(Note this assumes you are using the same variables names in the parent and the child. Otherwise feel free to mashup this use of the spread operator with regular properties, like
<RowLabels {...{ soundSet}} key={keyCurrentlyPressed} />)

I remember a few months ago when I first "got" the spread operator - how it feels like letting things bust out from serial to parallel, somehow...

Sunday, June 28, 2020

the joy of craft

My friend linked to Craft is Culture which had a big emphasis on Working From Home as standard practice. (Oddly I think that's what is using the term "Digital by Default" for, which is a rather misleading way of putting it, IMHO.)

Danco writes
There are many reasons why the west coast won, but one of the most widely agreed-upon was the fact that California state law forbids non-compete clauses.
I only agree with the part of that before the comma. For my career since the mid 90s at least, they've always been thought of as probably not-enforceable and generally ignored, though obviously the same explicit-IP-protections apply.

I'm not sure of all the reasons for the coast migration. MIT + Harvard and then military contracts like Lincoln Labs and Raytheon were early anchors. But other companies like Intel, Microsoft, Atari, Apple, those were all West Coast, and the new anchors.

I think that there's a limited time when a techie is likely to make a big move to follow a job (though I guess I can think of more examples than I first realized if I try). But there's a big anchoring effect... you go to college, then you either stay in that area, return to your hometown, or maybe land a new job someplace new to you. Then there's about one period in your late 20s where you might relocate again.

The thing about follow your craft is... I think the majority of techies are rather bad at monetizing their craft. They really rely on businesses to make money. Many coders are as stupid about the very basics of how a business can scale up to afford salaries (and health care) and rent - as stupid about those basics as the non-techies are about a full website works. So the 40 hour grinds continue.

It follow from that that I think most techies are fairly risk averse. They might takes some swings w/ a low salary but uncertain high reward in a startup, but that's about it. Entrepreneurial crafters are not so common.

Danco brings up the Cathedral and the Bazaar - and indeed, Linux is amazingly impressive. But I think projects like that work by programmers "scratching itches" as they say. I think Linux was an usually fortuitous mix of some folks who wanted to take on the "big itch" of a whole damn OS, and a legion of people happy to work a bit smaller. Going back to my earlier point, folks coding for the love of craft are usually not working on something that will be as universally useful as Linux has been - or anything that they have a real hope of making a living off of.

easy set of radio buttons in react

It's funny, a few basic elements are a bit tricky in pure-function React - but then again checkboxes  and radio buttons and select/options could be a bit of a semantic pain in JQuery too.

(One real pain was using setInterval - I can use the approach outlined here but it's kind of brittle, like it needs to be inside the render...)

Anyway, here is some quick and dirty code for making a set of radio buttons:
const RadioSet = ({ selectedVal, setter, valToCaptions }) => {
    return Object.keys(valToCaptions).map((val) => {
        const caption = valToCaptions[val];
        return (
            <label key={val}>
                <input onChange={() => setter(val)} type="radio" checked={val == selectedVal} />
                {caption}
            </label>
        );
    });
};
In my case selectedVal and setter are what I get from useState(), and valToCaptions is a just a simple object of key/val pairs. Nothing fancy but I stopped violating DRY with so many radio buttons...

Friday, June 26, 2020

simple checkbox in react using hooks / useState

One of those, oh right duh --
const [thereminMode, setThereminMode] = React.useState(true);
and then the checkbox:
<input checked={thereminMode} type="checkbox" onChange={() => setThereminMode(!thereminMode)} />
It took me a second to realize, we don't have to read anything from the event or the checkbox itself, the verb "change" is enough to do the toggle ourself...

preventing nativeEvent offsetX / offsetY from being blocked by child

"Last night Wes Bos saved my life"...

Well, it was this morning, not last night. And maybe "my life" is overstating it...

But Wes Bos (his React for Beginners class is stellar, and I need to get back to his Javascript 30 - seems like serious playful fun) had a tweet that was hugely useful.

For yesterday's bad react paint program turning into a music tracker, I added a large row hilight div, but it became obvious as the hilight kept jumping that it was blocking the handleMouseMove logic that was getting
const { offsetX: x, offsetY: y, buttons } = e.nativeEvent;

(The offsets were wrong, I guess because the "target" was changed)

That tweet thread suggested some weird updated math when the event target wasn't the current thing (but how to get the "current thing" in React is a little weird?) but luckily there's a trivial (and oddly CSS-based!) solution: on the child element, putting

pointer-events: none;

lets the parent div do all the math.

(That explains why some of the pixels in my bad paint program show up in the top left corner...)

Thursday, June 25, 2020

loading extra files (libraries and binary/sound files) in a parcel app

This is Parcel 101 (or maybe 102) but as I make version 2 of a vanilla js app in React using Parcel, sometimes I forget how things work in this kind of bundled app... you can't just refer to external js libraries in a script tag, and you can't just load a sound file via URL.

The library in question is pizzicato.js, and I put a bunch of files in "src/wav/sound_##_##.wav" where the ##s are two digit numbers.

The lines of code then are:

import Pizzicato from './js/Pizzicato.min.js';
import bundledFiles from './wav/*.wav';

Using Pizzicato is then straight forward (new Pizzicato.Sound() or whatever).

The sound files are a little weirder, you get a js object where the keys are what was put in the wildcard, so sound_06_27 was the key used for the ./sound_06_27.c7ca9f08.wav which was a path I could pass to Pizzicato.

Mischnic's answer on this page was helpful in figuring out the syntax.

Oh, and luckily I remembered Parcel's weirdness in assuming it is serving from the root URL of a site, I overcame that with this line in package.json:
 "scripts": {
        "build-prod": "parcel build src/index.html --public-url ."
The "--public-url" makes it happy to go where it is put.

building a bad paint program in react with parcel

I've had some success making the Atari Sound Forger, a webapp that lets you play with sound files representing noises an Atari 2600 can make by treating the computer keyboard like a specialized piano keyboard. It can even record the loops as you bang them out and play them back in browser or generate a small batari Basic program to listen on a real Atari or emulator!

One user ("Random Terrain", gatekeeper of the batari Basic command list suggested it would be more fun/useful if you could paint on the "piano roll" display ala Mario Paint or what not) - and damn it he's right.

The Sound Forger uses some semi-clever techniques with setInterval and setTimeout to let the browser do a fair job of pretending to be an Atari, but I kind of painted myself in a corner... fundamentally it's recording sound start and stop times in milliseconds (i.e. rather native to Javascript) and then extrapolating to the "frames" (60 per second) the Atari uses. (The sound engine is a pair of single voice/single timers that switches between notes and periods of silence) The algorithm screws up when you overlap sounds though... also while it worked pretty well for "sound on, sound off" approach, more complicated ADSR/sound envelope technique (i.e. hitting the note then reducing volume, like a piano striking a note) was going to be clunky at best.

So I decided to start from scratch, but grabbing tricks and techniques from my old code. Also I thought it would be good practice to switch into React, rather than doing yet another Vanilla JS project.

(Actually, it might make more sense to switch to P5.js, like I did for my playfield graphic editor playfieldpal-bB-DPC  - or maybe at least use a canvas-in-react approach which I would have to study up on, vs the "lets just throw DOM elements at it" approach I'm starting with)

I'm also a little burnt out on the "ALL THE THINGS!" approach of create-react-app, so I decided to fire up parcel. During that process, I (think I) had to update node and even download xcode on my new machine because of some js dependencies.) Also, the one bell-and-or-whistle I wanted was using CSS modules, so I had to follow a few more steps, running
npm add postcss-modules autoprefixer
and then making a .postcssrc file with
{
  "modules": true,
  "plugins": {
    "autoprefixer": {
      "grid": true
    }
  }
}
after that importing a "Widget.module.css" worked as expected and I had nice bundling of components with the CSS that applies to them only.

I decided to start with a simple Proof of Concept paint program... cutting to the chase I ended up the stuff I put in this codesandbox.io. (Out of laziness I punted and went back to normal CSS inclusion for the sandbox)

I used the useState hook, and to keep it simple I collapsed what might have been a 2D array into a map-like object by having the key be x + (y * width) (old programmer trick).

I'm plucking things out of the nativeEvent property of the event object my handleMouseMove function gets:
const { offsetX: x, offsetY: y, buttons } = e.nativeEvent;
I'm not quite sure what e.nativeEvent is... I could dump it out to console.log() ok, and pull out the stuff I need (offset values so the mouse position relative to the top left corner)  but if you go over the keys or call JSON.stringify on it it claims the only key is "isTrusted" (set to true).

So, it's a pretty lousy paint program, missing a lot of dots! (when I made a simpler editor, I used a trick of treating the previous mouse position and current as line endpoints to get all the dots inbetween). But for the app I have in mind, the grid is much less "fine" (it may even use clicks instead of drawing for the most part) and I think this technique (of putting small pixel-y <div>s  over the parent space for the dots) should work ok.

Wednesday, June 24, 2020

remembering AOL instant messenger

Nice tribute to AOL Instant Messenger. I feel like my friends and I were funnier on AIM than we are on the current chat options. Maybe it's the setting? Like it's easier to think of something clever typing on a normal computer with a keyboard and a big screen than tip-tapping on a mobile device?

The article mentions the art of the away message... I think that tends to be a youth thing. Like in college, we had ".plan" files, what people would see when they ran the "finger" command on your account (and yes, the jokes about that verb were plentiful and rarely subtle). It shared that youthful romance energy as mentioned in the article, wistfully seeing if your crush had logged in and checked your email and not bothered to reply, and leaving a message that you hoped they might see but might never know if they did.

(Not even sure if there's a social media equivalent of "away messages" and .plans - maybe avatar photos and what the banner image on your FB profile page?)

gmail feeling like an old car

A piece going over some of the features of the Hey e-mail service, and how they cleverly borrowed interface patterns from other things like social media and the MacOS dock to make a better e-mail experience.

It makes me realize that I've been using gmail for about as long as I've had my current car, about 16 years. Besides the value of 16 years of mail archive (and my hesitation to use an email service where I assume I'd lose my account if I stopped paying - "free" is a dangerous and addictive drug!) the gmail feature I'd miss if it wasn't well-replicated is sorting my inbox into "Important and Unread" vs "Everything Else" (with a little section of starred items to get back to.) That separation of the sheep from the goats works better for me than more fine-grained categories.