Wednesday, March 30, 2022

getting over xhtml-ish html

 Write HTML, the HTML Way (Not the XHTML Way).

That article charts the rise of stricter xhtml conventions in the 2000s. As it says:

XHTML became popular when everyone believed XML and XML derivatives were the future. “XML all the things.” For HTML, this had a profound effect: The effect that we learned to write it the XHTML way.

(and like I wrote a while back I think there are some very solid reasons JSON beat out XML that we should learn from - along with recognizing what XML did better.)

My HTML roots are old, old, old, and some "bad" habits - especially not closing <p> tags (treating it as more of a linebreak than a wrapper) and <li> still persist for me when I'm on my own. But here's my hot take: in the 90s there was a style that tended to put tag names in ALL CAPS:

<TABLE>
  <TR>
    <TH COLSPAN="2">Some Header Information</TH>
  </TR>
[...]

My unpopular opinion is, that was a better way to write HTML. It made the content (whether values of attributes, or text content) look more distinct from the tag names and attributes.

(Of course, even in the 90s that was a bit of a 70s-ish throwback look. BUT STILL!)

a more delightful react file structure

Delightful React File/Directory Structure has some good priorities.

Tuesday, March 22, 2022

everything old is new again - animated gifs and variable framerates

On a private (and left-leaning) Slack channel about current events, someone posted about the protest truckers coming down with bad coughs, and I realized I didn't have enough emoji-reactions for Schadenfreude, and that Nelson's taunting "HA-HA!" might cover it... 


I tried to upload it in Slack, but it told me it was too big - and shrinking the size of all the frames didn't fix it. Which is weird, because it seems just like 5 or 6 frames...

You can open up GIFs in Mac Preview, and even delete frames:

Looking at it, the problem becomes clear: lots of repeated frames is probably why the file size was large - 5 .1 second frames is larger than 1 .5 second frame even if the frames are identical. (I am assuming, without investigating too much.)

But even though I can delete frames, it didn't seem like I could modify the time for any given frame...

I fired up the App store and after a few false starts found "GIFQuickMaker" which for a few bucks allows more detailed GIF editing, and I ended up with 

which honestly I think has better timing than the original.

the text is almost too small when used as an emoji:

but it gets the idea across.

GIF of course is an archaic and inefficient form, but I love it - the silent films of the web 1.0, the egalitarian geek flipbook. 

But it was funny thinking about why the original Nelson GIF was so inefficient, and I realized that constant framerate is going to be the default for video clips transferred to GIF form. And, kind of akin to the PNG vs JPG difference, animated GIFs should make different assumptions when capturing simple animations. 

And I see the parallel of how "variable refresh rates" is such a hot thing for phones! Very similar thinking, where for animations quicker framerates allow for silky smooth smaller pixel movements, but slower updates make sense for saving power most of the time.

Heh. Reminds me of my old small gif cinema where I had a lot of fun seeing what 40x30 pixels could do. (And in 2002 I even played with putting those on the old Etcha-A-Sketch animator... 12 frames of 40x30 monochrome. Sigh, that came out in 1986, so my art project is even older than it was then...)

UPDATE: Oh, RIP Steve Wilhite, inventor of the GIF!

Sunday, March 20, 2022

the design of the jerry can, a german secret weapon

Cool video on the original German jerry can. While the history of it (as a superior design then copied by other countries to varying degrees of fidelity and success) was interesting my favorite part of the video is the first part, focused on the design- especially the three handles on top, allowing different configurations like one person carrying 4 empties, or 2 people cooperating to carry one, etc.


(A lot of other cool details in the design as well, an air pocket that would make preventing it from sinking if dropped in water, very durable internal weld, a super clever latch that precluded the need for extra funnels/nozzles...)

Friday, March 18, 2022

i got pac-man fever...

Just finished "Pac-Man: Birth of an Icon", a colorful coffee-table-book masterpiece. Just nice to think about the design of it, and share some of the feelings about making toys and games...

So infamously Pac-Man was originally Puck-Man, the name changed to avoid F'in vandalism, but the original cabinet art was so much better than the one released in the USA.


People aren't quite sure of the origin of the "toy-like" red-eyed, be-legged but armless smirking Pac-Man, though it may have been outsourced to Gordon Morison. The eye-catching yellow sides were probably a great idea, however.

I had a strong concept about what a game designer is- someone who designs projects to make people happy.
--Toru Iwatani, creator of Pac-Man

Making a game combines everything that's hard about building a bridge with everything that's hard about composing an opera. Games are basically operas made out of bridges.
--Frank Lantz, Directory of the New York University Game Center

Also I do love the art for the earlier Namco game "Gee Bee"...



Tuesday, March 15, 2022

axe-con accessibility conference online

 D'ohh, forgot to mention axe-con, an online accessibility conference. Sir Tim Berners-Lee was the keynote!

I suspect you can still sign up for free, and then catch up with recordings of the sessions. (It's not clear why watching something recorded feels less cool than live, but there you are.)

Saturday, March 12, 2022

making videos in react

Oh, this is pretty cool... making videos in React!

Interesting how declarative and "purely functional" this is... really gets you to think about "where is this thing positioned as a function of the current frame". 

(I think if I really needed to make a video I'd be more tempted to stick with something that works with p5 because it provides more canvas-y primitives than fiddling w/ SVG, but still.)

Wednesday, March 9, 2022

get "cover fit" with plain old img objects

One little tidbit from my image gallery viewer in January: it seems like many developers know of "cover" and "contain" values for the "background-size" property for elements with background images - "cover" in particular is great for "make as much as possible of this image fit in the space, crop whatever edge is hanging off after your resize - but fewer realize you can do the same thing on an img itself, with the object-fit property - it also has "cover" and "contain" values. 

Admittedly it's a little weirder to think about the img kind of resizing itself rather than just scaling a background image, but it can be a better option, especially if you use want to use the <picture> element to declare multiple sources.

radix-ui

 radix-ui looks pretty keen!

Tuesday, March 8, 2022

ken kocienda's lessons from apple

The Talk Show (of Daring Fireball) had an episode with Ken Kocienda, who did pioneering work on the Safari browser and the iPhone and who recently wrote the book Creative Selection about his work at Apple and the culture their during Steve Jobs' return.

Getting the onscreen keyboard right (and thus refuting the "Crackberry"-wielding naysayers who loved their physical keyboard, as well as avoiding a repeat of the Egg Freckles perception issue that hastened Newton's demise) was a huge challenge, and at one point the entire iPhone (then codenamed "Purple") engineering team pivoted to solving it, having a "Keyboard Derby" to demonstrate different approaches. 

Here was Kocienda's winning entry:

You'll notice it won the derby, but the launch product returned to a more normal one-key-per-letter layout. This layout was a bridge from earlier attempts at predictive text on phone keypads to the autocorrect we rely on today. (It's odd how when they pivoted back to one letter per key - needed for typing in names and purposeful misspelling that the dictionary wouldn't know about - the end result looked an awful lot like PalmPilots had been doing over along.)

One detail that doesn't get mentioned in the book but they talk about on the podcast is the iOS checkerboard that would appear when the iPhone scrolled past what it could render, until the true content could catch up. (You don't see it much these days but apparently the code is still there.) It was a great example of how keeping up the feeling of true physicality was so crucial on the early iPhone, and was more important than being "honest" about what could be rendered.

That need for speed predates the iPhone and goes back to when it was a significant goal of Safari - he cites Don Melton's mantra of "our browser will become faster by never going slower", that is, every check-in of new code had to run a speed performance test and find some way to compensate for any speed loss before it could become part of the product. (This was the PLT, or "Page Load Test" - I think that tests final results - rendering page speeds in this case - are holistic and therefore superior to superficially similar tests-on-checkin, such as unit test coverage.)

The book has a lot of other great stories of bits of advice - like how Richard Williamson's 2 day "hack Konqueror to run on Mac" blew away Kocienda's much longer effort to get Mozilla compiled and running, and thus became the root branch of nearly all browser platforms, which led to Kocienda musing:

Over time, Don and I began to understand and absorb the model Richard showed us. Look for ways to make quick progress. Watch for project stalls that might indicate a lack of potential. Cut corners to skip unnecessary effort. Remove distractions to focus attention where it needs to be. Start approximating your end goal as soon as possible. Maximize the impact of your most difficult effort. Combine inspiration, decisiveness, and craft to make demos. 
We learned all this from Richard. He changed the way we worked. 

 Another great point was algorithms vs heuristics... for things like the PLT, you can take a persnickety algorithmic approach, but for many other things you can and should rely on the heuristics of taste and feel - 

We used algorithms and heuristics like they were the left and right sides of our collective product development brain. Employing each involved an interplay of craft and taste, and we always tried to strike the correct balance. Algorithms and heuristics must coordinate to make a great high-tech product. Fast web page loads, correct insertion point movement, efficient code, lovely animations, intuitive gestures, and well-considered built-in behaviors are all essential in a product like the iPhone. Our goal was comfortable technology and computer-enabled liberal arts, a combination of both. 
However, it’s crucial to make the right call about whether to use an algorithm or a heuristic in a specific situation. This is why the Google experiment with forty-one shades of blue seems so foreign to me, accustomed as I am to the Apple approach. Google used an A/B test to make a color choice. It used a single predetermined value criterion and defined it like so: The best shade of blue is the one that people clicked most often in the test. This is an algorithm. 
At Apple, we never considered the notion of an algorithmically correct color. We used demos to pick colors and animation timings, and we put our faith in our sense of taste.

That was the part of the path to get to the legendary accomplishments of mid-2000s Apple:

A small group of people built a work culture based on applying the seven essential elements through an ongoing process of creative selection. 
Expanded out, it reads like this: 
A small group of passionate, talented, imaginative, ingenious, ever-curious people built a work culture based on applying their inspiration and collaboration with diligence, craft, decisiveness, taste, and empathy and, through a lengthy progression of demo-feedback sessions, repeatedly tuned and optimized heuristics and algorithms, persisted through doubts and setbacks, selected the most promising bits of progress at every step, all with the goal of creating the best products possible.

Anyway, the book is a great read that doesn't overstay its welcome. 

Monday, March 7, 2022

optional chaining for safely calling a possibly non-existent function

So optional chaining is relatively new in Javascript, so you can get deeply nested values from a stricture, even if the "branches" above the leaf are missing - like

user?.preferences?.colors

is safe to. call, even if user.preferences doesn't exist, and you don't have to write

user && user.preferences && user.preferences.colors

(or the kind of syntactic ugliness of

const key = 'preferences';
users?.[key]?.colors

 part of my brain says... what's the dot doing there before the square brackets...)

Anyway, turns out you can use that for functions as well - useful even if you aren't chaining per se - you can write

someFunction?.();

And it is safe, even if someFunction is not defined.

As always, I'm not crazy about how new syntaxes increase the cross-section of what folks have to know to read code, and `?.` is a bit ugly but it is definitely more DRY (Don't Repeat Yourself) than 

someFunction && someFunction();

Here's a little codepen I made:

const bar = () => {
  console.log('bar!!');   
}
const baz = undefined;
const foo = () => {
  baz?.();
  bar?.();
}
<button onclick="foo()">foo</button>

You can see, bar is still called even though we try to call baz before, which is undefined.

Tuesday, March 1, 2022

ssr - window.location.href with Gatsby Server Side Rendering can be dangerous!

For work I was asked to make a component with a "copy current page URL into clipboard" share button. (if they didn't pass in 'copyText' explicitly because they wanted other information there....)

My first pass had 

  const textToCopy = copyText ?  copyText : window?.location?.href;

above, and 
<button aria-label='copy' onClick={()=>navigator.clipboard.writeText(textToCopy);}>
    Caption
</button>

below. One coworker pointed out that might blow up if the component is rendered serverside, even with the ? marks, just talking about "window" might be an issue . So I change that line to 

  const textToCopy = copyText ?  copyText : ((typeof window !== 'undefined' && window?.location?.href) || '');

but I realized that might not blow up but, since it happened before the render, maybe on SSR it would try and (safely) fail to look up the location, get the blank, and then render an onClick that just copied the blank in.

I think it's safer to make sure all the dynamic work happens in whatever function the onClick calls, so I ended up with


// we make sure the window.location lookup happens onClick, so we don't get caught on the SSR...
const copyTextOrLocation = (copyText: string | undefined) => {
  const textToCopy = copyText ?  copyText : ((typeof window !== 'undefined' && window?.location?.href) || '');
  navigator.clipboard.writeText(textToCopy);
}

and then
<button aria-label='copy' onClick={()=> copyTextOrLocation(copyText)}>
    Caption
</button>