Saturday, December 15, 2018

i'm ping pong king, an analysis

Daring Fireball uncharacteristically recommended a game for mobile called "I'm Ping Pong King" and it is indeed pretty great - incredibly minimalist in both game play and presentation - yet compelling, and very easy to pay in small but satisfying doses. I've been thinking about what it does right, and how it compares to some previous similar games --

It's Ping Pong stripped to an almost absurdist minimum - if the ball lands on the left side of the table hit left, if it lands on the right side, hit right. (There's a visual telltale, a little "X" that emerges from the where the ball strikes) Despite the seeming triviality of that, game play is still compelling - I haven't quite worked out if it's the "body language" of the opponent and the motion of the ball before it hits the table that sometimes fools me or what, but this game finds a great place on the fine line between too easy and too reflex-demandingly hard.

(Of course in my history, I'm a big fan of games with a Ping Pong / Pong mechanic and a minimalistic control scheme - my own Joust Pong for the Atari 2600 (later renamed FlapPing to avoid Atari lawyers who claim to exclusive naming rights involving "Pong") is similar in that regard, using a single button to let the player maneuver into ball-returning position.)

Swinging back to what makes a popular mobile game - the "single button the flap against gravity" mechanic of JoustPong was later reinvented for the infamously difficult Flappy Bird. There the single button lets the player push the bird up through gaps between (or more often, directly into) big pipes. This game was difficult enough to be considered "masocore" (masochist + hardcore) but was still ragingly popular for a time.

The simplified control scheme suits mobile well. The other thing Flappy Bird and I'm Ping Pong King have in common is a demand for focus - if you are not concentrating, you will lose quickly. IPPK is a bit more forgiving, though, since a match is "first to five points", thus offering a chance for redemption.

I'm Ping Pong King has a meta-match structure that Flappy Bird lacked - you work your way through a series of 50 opponents. In theory each one might be a bit harder, but maybe that only matters in the last ten, and even then the game never gets crushingly difficult. (At least for a guy who has spent too much of his life playing games, but might be getting slower in his middleage) That sense of progression adds a lot to the package, along with great aesthetics of the motion of the ball and the character.

Wednesday, December 12, 2018

yearswerve

Lately I've been working on a personal timelines project, experimenting with visualizing the course of my life so far: where I've lived, jobs I've had, people I've been with romantically, etc.

Time for humans is such an odd beast - it marches inexorably forward, yet loops back on itself in the form of days of weeks and seasons in years. In experimenting with visual representations of it, I thought back to my old hooptime illustration, showing the idiosyncratic way I place a week in physical space (like when making simple day-of-week calculations)

Back then I mentioned and illustrated my even stronger sense of the course of a year - again counter-clockwise, with January at the top, and looping back:


Of course a simple loop doesn't display a forward progression of time, so for grins today I stretched out the loop into something that also expresses the movement into the future:


(It's not entirely dissimilar from repeat until death, my attempt to animate Christa Terry's ingrained visualization of an upward spiral of years.)
You can see the full p5 version here.
I'm still very interested in the topic of how different people visualize time, and speculation on what influenced that (clockfaces, calendar pages, whatever) If anyone has an idiosyncratic time-space mapping I'd be delighted to try and make an illustration of it.

Sunday, December 9, 2018

repeatable random colors in javascript

Indiegamer olsn provides a nice function making a repeatable series of "random" numbers:

// the initial seed
Math.seed = 6;

// in order to work 'Math.seed' must NOT be undefined,
// so in any case, you HAVE to provide a Math.seed
Math.seededRandom = function(max, min) {
    max = max || 1;
    min = min || 0;

    Math.seed = (Math.seed * 9301 + 49297) % 233280;
    var rnd = Math.seed / 233280;

    return min + rnd * (max - min);
}

(Of course to quote John von Neumann: "Anyone who attempts to generate random numbers by deterministic means is, of course, living in a state of sin.")

olsn goes on to say
You may ask: Why ‘(seed * 9301 + 49297) % 233280‘ ?!The answer is both simple&complicated: The combination of 9301, 49297 and 233280 provide a very even distributed set of “random” numbers. Please don’t ask WHY – that’s the complicated part, some very smart people figured out those numbers quite some time ago, and I also cannot tell you how they did it. But as allways: Google is your friend ;-)

That bit reminds me John Carmack's Fast inverse square root where a little bit shifting and then subtracting from the magic number 0x5F3759DF gives surprisingly good results for an otherwise very expensive math calculation. 

My favorite use of finding a great random seed is in classic video games - both Pitfall! and River Raid on the Atari 2600 use it to generate huge amounts of content (for River Raid, see this page on an amazing 'bot that was taught to play it amazing well and explore The River of No Return) but I thought I might use something similar to generate a series of colors for a project I'm on - I wanted to make a series of colors that kind of harmonized but were still distinct - one trick I learned is to constrain each r g and b value to a medium-size range (or if you alternate between #ff and #cc you get some nice pastels, which is how my loveblender site got its look in the 90s which given the era, wasn't half bad)

For each part of the rgb I generate a number from 100-200:
Math.round(Math.seededRandom(100,200)).toString(16);
and that makes a series like this:




(If the inline version doesn't work you can see it in action here.)

(Note to self, Indiegamer's book From Zero to the App Store looks interesting)

Tuesday, December 4, 2018

shape detection

Daring Fireball on The Iconfactory's Linea app update - you can scroll down to the ZipShades video there - as DF quotes:
Simply draw a rough circle, square, rectangle, oval, or polygon and hold at the end. After a configurable delay, ZipShape will activate and transform your rough version into a clean, precise shape. It works with all of Linea’s drawing tools — including the new fill tool.
You don’t have to be perfect — after the shape is generated, there are transform handles you can use to tweak its final position and appearance. No rulers or stencils required!
Gruber calls that "a real standout". Which is fair enough - not many programs support that kind of interaction. But it's not a new idea -
 
that video shows a mid-90s Newton running with the concept.

But you know, it's a lot older than that - here's Ivan Sutherland and Alan Kay showing the way:

That's Sketchpad (a.k.a. Robot Draftsman) all the way back from 1963!

While Steve Jobs was right that HAVING to use a stylus on a phone-sized device was terrible, it's probably not great that it took 5 years into the life of the iPad to introduce a precision stylus, the Apple Pencil.

I'm sure CAD-software has been doing this all along, so I'm not being snarky about this being touted as revolutionary, because it's not, just conceptually cool.

Wednesday, November 28, 2018

&& short-circuiting considered harmful... or at least, a little weird

I've never adored the && short-circuit operator, where if you write
A && B
and then A is false, B is never evaluated (or if a function, never called)

To me the short circut always felt like a weird, overloading side effect of "parsing this in left to right order", even though it's just such a cute and concise thing to do its become a standard. But when I think about parallelization, it seems like && reduces parallelization, like you can't run the second part in parallel (at least if there are any side effects) since you might end up not having to do so if the left part succeeds. (Of course if you are in a heavenly pure functional program wonderland, you have nothing to fear!)

My discomfort might come from how it breaks with other forms of boolean logic - like in logic, there's kind of a commutative property -
A AND B
is the same as
B AND A
but that is absolutely not the case in this style of programming.

Thinking about it more, I wish there was something that looked more like the ternary operator, like
shouldDoSomething && doSomething()
is less clear in its intent than
shoudDoSomething ? doSomething() : null;

Still, I'm kicking against the sticks. The hip kids really dig things that are that cute and concise and it's a pretty well-established pattern.

Tuesday, November 27, 2018

quick and dirty javascript stacktrace

As I've bemoaned, debugging declarative javascript code, fixing things when you don't get the results you expect, is tough. Sometimes it's handy to take a peek at the stacktrace and try to guess at what's calling what and why, and to get a stacktrace:

var e = new Error("at some function"); 
console.log(e.stack);

seems to work ok.

Wednesday, November 21, 2018

the tag

This tweet mentions the <meter> element and shows how it can easily be used for a Amazon-like star display - hadn't seen it before. (And like all good things it might not work on IE)

Here's the meter tag with defaults:


<meter high="66" id="fuel" low="33" max="100" min="0" name="fuel" optimum="80" value="60"></meter>


 Interesting that it has concepts of "low" and "high" for like warning values...

Thursday, November 15, 2018

touch tablet paint program ui thoughts

I do daydream about making an expanded version of my self-published comic on coping with mortality, something that captures the best of my thinking not just on death but on the best way to get through life. 

I continue to look for the best app to do that with, experimenting with various paint programs (over the year I've spent so much money on devices with touch sensitive screens, each time thinking "maybe THIS will be the one that lets my doodle skills blossom") Apple iPad's "Notes" program probably can't be it (if only because it doesn't deal with layers) but it really has some interesting UI decisions: coloring with the marker is more or less two-toned, paint once then start painting on the same spot to get a darker shade. And the eraser tool is kind of wild: it's like using the "Undo" button (that might erase a set of lines squiggles you made without lifting the stylus all at once) but instead of removing the last thing you did, it removes what ever you poke with the eraser tool. It's disconcerting at first, but kind of encourages a "well if you mess up you can do that whole thing over" approach.

I'm appropriately humble about my doodle skills, but looking at the sesame street characters I drew from memory during a meeting, I wonder if some of the lack of depth most of my stuff has comes from my preferences for using flat flood fill to color with... it's interesting to let go of a kind of "coloring perfectionism". 


Tuesday, November 13, 2018

grep / search for multiple terms across files in php

"Hey, what's the matter?" 
"I'm sad because you're going to die." 
"Yeah, that bugs me sometimes too. But not so much as you think... ...When you get as old as I am, you start to realize that you've told most of the good stuff you know to other people anyway." 
--Richard Feynman and Danny Hillis. 

After blogging for almost two decades my site kirk.is is an increasingly important supplement to my memory - it's great to have an archive for the full text of half-remembered quotes and excerpts.

A long while back I wrote a simple "grep" in Perl to find stuff - it could only find one exact string match across all the files, but often that was enough, and unlike Google, results were in chronological order, which was often useful. And its sense of usefulness (albeit mostly just to me) has increased over the years, so I decided to make it a little smarter and able to search for multiple terms and sentence snippets.

The logic turned out to be slightly trickier than I bargained for - the logic I finally realized I wanted was, for each file, go through each query term. Then go through the lines in the file. If for any query term none of the lines match, bail on this file, otherwise remember which lines matched. If we get to the end of all the terms, every term has at least one match - so for all lines that matched any term, sort 'em (having already made sure they were dedup'd), escape the HTML, bold the matching terms, and then return the lines as an array.

Here's the code for that:
function getLinesMatchingQueryStringInFile($file,$query) {
    $linesInFile = file($file);
    #break up query, using CSV (split on spaces after collapsing whitespace)
    $query = preg_replace('/\s+/',' ',$query);
    $queryterms = str_getcsv(trim($query), ' ');

    $matchingLineNumbers = array();
    
    foreach ($queryterms as $queryterm) {
        $lineNumbersMatchingThisTerm = array();
        foreach ($linesInFile as $linenum => $line) {            
            if (preg_match("/$queryterm/i",$line)) {
                $lineNumbersMatchingThisTerm[] = $linenum;
            }
        }
        #if any query term doesn't match we bail!
        if (count($lineNumbersMatchingThisTerm) == 0) { 
            return array();    
        } else {
             foreach($lineNumbersMatchingThisTerm as $linenum) {
                if (! in_array($linenum,$matchingLineNumbers)) {   
                    $matchingLineNumbers[] = $linenum;
                }
             }
        }
    }
    asort($matchingLineNumbers);
    $res = array();
    foreach ($matchingLineNumbers as $linenum) {
        $matchline = htmlspecialchars($linesInFile[$linenum]);
        foreach ($queryterms as $queryterm) {
            $matchline = preg_replace("/($queryterm)/i","<b>$1</b>",$matchline);
        }
        $res[] = $matchline;
    }
    return $res;
}
A slightly clever bit (i.e. slightly deeper in the StackedOverflow) was trimming the query expression, and then using str_getcsv(), which does a good job of breaking something like 
find "something good"
into 
find
and 
something good
which is what I'd want to search on.

Friday, November 9, 2018

grumble grumble

Trying to follow a piece of data get mangled in a relatively declarative-style code base is a pain.

(FOLLOWUP: More specifically, the code in question was implicitly manipulating a lot of data for a financial estimation calculator - there was the display format (and my task was internationalizing that), the internal format used to do the math, and then the format for editing (i.e. you might want to display a money value with a currency symbol and a thousand place separator, but you remove it when the user is editing that value) It was frustrating when the "to" and "from" functions used in the reducer were each called like 2 or 3 times for every field. The correct solution turned out to be doing a "typeof" in the "toNumber()" routine, and if the argument was a string call the locale-aware number parsing function, and if it was a number just returning the number.  Now I'm not the biggest fanboy either of declarative styles (I still think event-driven code be a bit more sane- or at least easy to figure out what's messing up when things go awry) or of strict typing in javascript, but this experience made me thing the two might go well together.)

Thursday, November 1, 2018

git-r-done ux

Once upon a time, the comments section on my regular blog kirk.is made it a social place, with regular commentators, only about half of whom I knew IRL.

Social media has moved on, alas. And adding injury to insult, my homebrew comment system got invaded by dirty rotten link spammers. These guys are the biggest jerks in the world. I have about 4,000 days with comments on them (!) but I'd say at least 3/4 of those will turn out to be nothing but comment spam.

Even after eliminating the ability for people (and bots) to post links, they kept on coming, and I decided not to give up, rather than invest more deeply into a fix.

But, being nostalgic and wanting to shake my fist against the onslaught, I'm going back and eliminating the spam while preserving the conversations. So I built a tool to efficiently drive through each entry and with a click, determine where the good comments started and the bots began, showing the actual entry to the right.

If there's no good comments, I click "KILL ALL" and the thing is removed. Other wise, I click a link that says "truncate the comments section here". (In the screenshot you get the idea of my crude but functional system: the first line is a count of how many comments in the file (for efficient "See X Comments" labeling when building the blog entry page), then each comment is followed by special lines in brackets "[[]]", with key/values for their name, and the time they posted.

To improve the UI, I make use of the fact that most of the 'bot entries seem to be posted 3000 or so days (i.e. 8 years) after the original entry date - so anything over 1000 days old gets labeled in gray, with a red highlight on the day differential. Anything older than 10 days still gets a light gray treatment.

I could probably just write a script to discard any comment coming 1000 days or more after, but besides the fact it would throw out some good stuff and keep some bad stuff, I kind of like the nostalgia of the old conversations. Right now I'm up to 2003, as we move into Iraq.

UPDATE: write after I wrote this I realized I could it one better - 98% of the time I just click on either "KILL ALL" (where there's nothing) or at the transition point from "good" to "bad" comments. So I really git-r-done'd a javascript thing (long story short I wanted to keep things one pass in my PHP) to add a css style to the id of the "cut here" link and turn it bright yellow, and then another button that says "DO THE YELLOW" if I accept the verdict - that button is plunked at the top of the page so I don't have to find it with the mouse.

So, it's cruft-y as hell, but very efficient, and transparent: make it easy for the user (me) but "show your work" at all time, along with being clear what action you are going to do...

Dang, I wish "Git-R-Done" wasn't so Larry-the-Cable-Guy-ish!

minimalist css callout/tooltips

http://cssdeck.com/labs/bv45bh6p has a pretty good, minimalist CSS callout. I got rid of the fixed height and shadows and just use the one direction I needed:

div.callout {
  width: 200px;
  display: none;
}

div.callout {
  background-color: #444;
  background-image: -moz-linear-gradient(top, #444, #444);
  position: absolute;
  top: 0.5em;
  left: 8em;
  color: #ccc;
  padding: 10px;
  border-radius: 3px;
  margin: 25px;
  min-height: 50px;
  border: 1px solid #333;
  z-index: 100;
}

.callout::before {
  content: "";
  width: 0px;
  height: 0px;
  border: 0.8em solid transparent;
  position: absolute;
}

.callout.bottom::before {
  left: 45%;
  top: -20px;
  border-bottom: 10px solid #444;
}

After whipping up a version of that (and having to have the onmouseover/onmouseout for both the triggering text and the callout itself it was pointed out to me that the bootstrap we use has a decent library for what it calls tooltips - it can be "onclick" ( the code is like 
$('[data-toggle="tooltip"]').tooltip({trigger:'click'});
) , it can be made to not escape  HTML,
data-html="true"
and you can style it with CSS - selector is
 .tooltip .tooltip-inner
And also it's pretty good that it fallsback gracefully using the html5 default "title" tooltip behavior

Tuesday, October 30, 2018

BASIC and the joy of little improvisational programs

Daring Fireball just posted a link to a 2014 article, TIME Magazine's Fifty Years of BASIC, the Programming Language That Made Computers Personal. As Gruber puts it
For those of us of a certain age, a BASIC prompt was what you’d expect to see when you turned any computer on.
This article is the best I've read on the subject (marred slightly by the amount of ads on the page) In particular, I hadn't realized how important it was as computers moved from the batch process punchcard era to the expectations of real-time interaction we enjoy today - and of getting students to realize that programming was something that mere mortals could do.

That was in the 60s - in the 80s, BASIC was the bedrock of home computers - and most kids were given a chisel and some other basic tools so that if they were motivated, they could get the computer to do whatever they wanted.

The article briefly touches on BASIC's detractors. But as my friend Jeremy Penner (founder of everyone-can-and-should-make-games celebration site Glorious Trainwrecks ) mentioned to me, line numbers, while limiting in many ways, are a super intuitive way to get a kid making that first step of "computer programs tend to go step by tedious step". I think Dijkstra infamous complaint "It is practically impossible to teach good programming to students that have had a prior exposure to BASIC" is way out of line; understanding simple step by step flow does not preclude later learning of modularity and other more sophisticated topics.

As Harry McCracken writes:
BASIC was so approachable that you could toss off little improvisational programs with barely any effort at all. I probably wrote hundreds of them in my high school’s computer lab—games, utilities, practical jokes to play on my classmates. Most were meant to be disposable, and unless any of them show up on forgotten floppy disks at my parents’ house, almost all of them are long gone.
That hit home for me. In the 2000s, that's sometimes my style for stuff in Processing and P5.js (though I'm a bit of self-absorbed nerd so I archive "the good stuff" at toys.alienbill.com.) Other people I know, like Anna Anthropy write books about writing your own games in Twine, Puzzlescript, and Scratch.

But it's still a long way from the "booting into BASIC" days - Mac/Windows/Phone environments are great program launchers, but don't have that ramp into "you type things and computer stuff happens!" Also, the gap between "real" programs and what an amateur can write is MUCH bigger than it was in 1980s - especially for games. "Casual" games are a welcome exception to that, but a beginner programmer usually isn't using a toolset for 3D stuff.

(An upcoming thing I'll be keeping an eye on is Dreams for PS4 - "a space where you go to play and experience the dreams of Media Molecule and our community. It’s also a space in which to create your own dreams, whether they’re games, art, films, music or anything in-between and beyond." That's the same folks who made LittleBigPlanet which had a pretty rich online maker community too, so it'll be neat to see what comes of it.)

Thursday, October 25, 2018

wator and recreational computing

I've implemented a version of A.K. Dewdney's Wa-Tor from Scientific American's "Computer Recreations" column - it's a simplistic Cellular Automata-kind of thing, a simulation of sharks eating fish on a donut-shaped world (generally mapped onto a simple grid) You can see my version here. Kind of hypnotic!



I was partially inspired to get back to this by my UI Book Club where we just finished Edward Tufte's "Envisioning Information". It reminded me of a Windows 3.1 Version I messed with in college... in particular, it had a population graph that's always stuck with me, something like this:
I can't think of many graphs with a time element where time isn't just slapped on the X-axis - it's kind of cool how you can follow "time" as it makes its curvy path. It turns out this basically a "phase diagram" corresponding to Lotka-Volterra equations, the math that predicts predator-prey relations.

"Computer Recreations" was a big influence on me as a kid. The whole concept of recreational computing, programming for fun, is something that's been lost a bit. The home computers then were slow and with almost no memory and generally primitive, but you had full access to the machine. For kids in the era, even if you just used the computer to play games, you entered a BASIC command to load the game, and you probably learned a smattering of BASIC in school, and learned that you could make these computers follow your instructions and make original stuff.

Anyway, I wrote it in P5, and the code could serve as an example of having 2 P5 apps communicate a bit, even though the whole thing is a bit quick-and-dirty.

Tuesday, October 23, 2018

Wednesday, October 17, 2018

javascript: generations

I updated my photo mini-gallery maker so that clicking on a thumbnail will scroll to that image - I didn't realize el.scrollIntoView({behavior:'smooth'}); was now part of vanilla javascript. 

The code on the page is probably a hybrid of old and new style js - something like to be more prevalent in stackoverflow-based js culture :-D

Monday, October 15, 2018

the stupid-idea-buddies buddy

My favorite Slack channel at work is #stupid-idea-buddies, where people can pitch product ideas and other concepts, free of fear from a negative response. (Inspired by Was Twitter a Stupid Idea)

I'd recommend a channel like this as a way of brainstorming (as well as venting passive-aggressive complaints) for any organization.

To give you a flavor of it, here are a few I posted and were particularly fond of:
#321 formation of a committee to determine the plausibility of "aggressive passive" behavior; for example, furiously hammering water
and
#1593 Make years start on March 1. This will have 3 big advantages:
1. meteorological seasons now line up year - starting with March/April/May spring, June/July/August summer, the school year starts with Sep/Oct/Nov Fall, and then Dec/Jan/Feb Winter
2. September and October now fall on their appropriate Latin numbers (7 and 8)
3. NFL season is no longer this weird ambiguity springing from regular seasons and playoffs of one "season" being in different years
and
#2718 Luggage with face detection that is also delighted to see you as it swings around the baggage carousel and can express that- makes you feel loved after a rough flight and helps you locate your bag. The name of this wonder-product? "emotional baggage" 
Anyway, I made up SIBB, the stupid-idea-buddies buddy! It comes up with very stupid and formulaic original ideas: 
#2720 eights, but for teams [SIBB]
#2721 shops, but for rheumatisms [SIBB]
#2722 buns, but for lawyers [SIBB]
Minutes of entertainment!

Sunday, October 14, 2018

stackoverflow - if you're smart enough to ask the questions, it has the answers (e.g. putting breaks in <pre> tags)

I'm revamping my ancient loveblender site. One thing I use there is Ye Olde <pre> Tags - offering my authors precisely finessed spacing control. (And back in the day, giving my site a kind of fun typewritten look.)

Honestly, I think some users use it who don't need to - in particular one author who wrote very long lines that would break the now-shared page. So I figured there might be a way of getting most of the benefits of a <pre> tag but still breaking super-long lines, and sure enough stackoverflow had the answer:

pre {
    white-space: pre-wrap; /* CSS3 */
    white-space: -moz-pre-wrap; /* Mozilla, post millennium */
    white-space: -pre-wrap; /* Opera 4-6 */
    white-space: -o-pre-wrap; /* Opera 7 */
    word-wrap: break-word; /* Internet Explorer 5.5+ */
}

Stackoverflow has so many answers - in many cases, the problem is just knowing the question. I think this is true in general, for languages you're not using every day, it's ok just to know the concepts, and make good guesses as to what commands are likely available already. Sometimes it seems embarrassing how I write all my personal sites in PHP (as I've said before, not as dumb as it sounds) but how few commands there are that I don't end up looking up. (Then again, I had my own cheatsheet for tropes in Perl...)

Friday, October 12, 2018

13 games under 13k

Some results from a Javascript 13K Game Jam. It's kind of amazing what's built into browsers these days!

Wednesday, October 10, 2018

photo albums, macros, perl regex, browser regex, terminal clipboard, and photo galleries

Middle School was not kind to me.
A long time ago I scanned the photo album I assembled shortly after college and put the photos online. (For a weird time in the late 90s too many websearches for old friends just pointed back to that dang site) The thing is I scanned things at too low of a resolution, so I decided to redo the effort at 600 dpi and post them on my blog.

Over the year I've hacked up my blog system to be pretty friendly to post photos, especially with resizing images for web display, but keeping the fullsize images there as a link (since I finally realized it really was my canonical personal data warehouse.)

(I'm still enamored of my CSS hacky photo gallery system, which easily makes a nice compact display of the album with a minimum of setup)

Anyway, I reused all the file names from my original scans, which include a lot of metadata about people and places in the photos, so I wanted to go from the html my blog system generates for me, for example
<a href="/m/2018/10/10/049.c.mrs mclaughlin at prom toasting camera.jpg"><img src="/m/2018/10/10/049_560.c.mrs mclaughlin at prom toasting camera.jpg" border="0" width="560" height="441"></a>
<br><br>
and copy the filename as the caption underneath, ala:
<a href="/m/2018/10/10/049.c.mrs mclaughlin at prom toasting camera.jpg"><img src="/m/2018/10/10/049_560.c.mrs mclaughlin at prom toasting camera.jpg" border="0" width="560" height="441"></a> mrs mclaughlin at prom toasting camera<br> 
<br><br>

Once upon a time, I would have done this in a macro in a text editor - I feel like I used to care A LOT about how well an editor supported macros (it can get tricky, especially how you record a macro that uses a dynamic "find") but now it doesn't come up so much.

So my fallback plan was writing a perl script:
while($line = <STDIN>){
    chomp $line;
    print "$line\n";
    if($line =~ /^.*?\.\w\.(.*?)\.jpg/){
        print "$1<br>\n";
    }
}

The trick was being a bit lazy about putting things in temporary files - one thing that helped was the pbcopy command in MacOS Terminal, which can pipe stuff into clipboard.

So that would have got the job done, but then I remembered I had made a tool to help me do that in the browser: regexcellent which I write about here. In this case, the matcher was
^(.*?\.\w\.)(.*?)(\.jpg.*)$
and the output was
$1$2$3 $2<br> 
(the one thing I couldn't figure out was putting in \n's for line breaks, but not such a big loss)

Anyway, I'll be posting the results starting tomorrow.

Hope any of this was useful to someone! If only as notes to my future self...

Friday, October 5, 2018

es6 re-review

Decent re-review of ES6 new(ish) hotness(also ish).

Its notes from the Wes Bos lectures- currently I'm taking his video React intro course. A lot of it is review but there's a lot that hasn't yet cemented for me with my intermittent use of it.

I admit I'm not in love with all the new concise syntax - it used to be much easier to take a guess at what a { meant in javascript code, now everything is heavily overloaded.

Saturday, September 29, 2018

fb wants your group page to have the last word


While I can applaud FB encouraging page maintainers to respond promptly to folks contacting the page, this alert - coming after a successful dialogue (my band will likely march with the 15th anniversary JP Canine Costume Parade) worries me that they will clumsily ding the page's response rate because I let Brad have the last word ("great")

The subtle encouragement to have the page runner post the last reply seems like damaging bad UX. When I wrote a post kvetching about this on FB, a friend said that's why he tends to end with the thumbs up, as a kind of punctuation. Good idea, if a bit of a hack.

Friday, September 28, 2018

on the iphone x and ios 12 gestures

I upgraded to an iPhone Xs, mostly seduced by tales of the superior lowlight camera.

Seeing people adapt pretty easily to "no home button" over the previous year had allayed my fears about the transition and learning the new gestures - I'd always been a fan of physical home buttons; to quote Gruber writing skeptically about removal of the home button (admittedly it was 2011)
The physical Home button is impossible to miss. That it is the one and only button on the faces of these devices is a big part of why normal people are able to pick them up, start playing with them, and figure out how to get around with no help.
The PalmPilot had a prominent silkscreen button for "home", and I've always thought it was similar to the convention that clicking on a website's name at the top right will bring you back to the top of the site.

In practice, the iPhone X's Face ID has a simplifying effect - since unlocking is passive and automatic, there is now one gesture predominant, the upward swipe. This movement is identical when opening the phone from the lock screen or from any app - not quite the case with Touch ID, where the "rest and wait for fingerprint" felt a bit different from clicking from with an app.

UPDATE: my sweetie Melissa points out I'm missing a crucial gesture - swiping right or left on the "Home indicator" bar - this is a fast task switcher, a way of getting to apps you've recently been using without going to the whole card-app carousel. From a UX perspective, it's an interesting choice: always returning to the homepage, then letting muscle memory telling you where to go for the app you have in mind, vs keeping in mind what apps you've recently been using (and/or rolling the dice that the app you want is recent- an interesting attention span challenge)

Conceptually, I still miss the home button a bit - there was something nice about how it was "out of band" from every app-interaction  - it was kind of reassuring that to know you were communicating directly with the device, and unlike a gesture it was tough to do accidentally. Also, the home button was always trivial to locate, no matter how you were holding the phone - if an app has switched into landscape mode, even though there's that marker line, the direction to swipe might not be instantly clear.

One additional improvement: the lock screen quick camera access is now a virtual button (See the screenshot below for an example) - it requires a "hard press" but is MUCH more reliable than the "swipe to the side" gesture. (That gesture is still supported on iPhones with Face ID - and the swipe seems to be the only option for iPhones with home buttons, for some reason.)

Anyway.

Over the years I've become rather vain about making my own cases via Zazzle - I figure the silver lining to phones becoming so thin, even at the cost of durability and battery life, is that you can kind of think of the case as a form of customization rather than mere external protection.

I think illustration is a much better bet than photography, and so I go to the work of my artist friend James Harvey (who did the illustrations for my self-help-about-mortality comic So, You're Going to Die) -

In retrospect, I think the wood cases were a mistake - they had a nice warmth (and I could knock wood no matter where I was) but lacked durability.

Also I think my James Harvey lock screen also rocks:

Sunday, September 23, 2018

hand wavey gestures

I use HyperDock on Mac, my favorite feature is using option-cmd-arrow to toss around windows, make them either full-screen or half-screen, an easy way to neaten up the workspace plus I realize it feels a bit like a keyboard based version of all those hand-wavey gestures Tom Cruise uses in Minority Report or Tony Stark in Iron Man movies.

(That said I don't think I'd like actual hand wavey gestures all that much. It's easy enough to make mistakes and get startling behavior just with plain old touchpad gestures.)

My friend Ari recommends SizeUp - I like it because HyperDock didn't really have an option for "bottom half of the screen" (which was unfortunate since I run one of my monitors in "portrait mode". I kind of preferred HyperDock's method of toggling between the moved state and the previous position, but still SizeUp is not bad for $12, and I like how it had a little transparent indicator in the center of the screen telling you what just happened.

Friday, September 14, 2018

using cgi for good

Fantastic use of greenscreen to warn people about why storm surges are not to be trifled with, and behind the scenes....

jawdropper - every id'd DOM element is a variable?



I had no idea, or had utterly forgotten, that every DOM element with an id attribute is available as a variable, seemingly plucked from global space and I guess rendering document.getElementById() almost useless- here's the jsbin link from that tweet.

I forget just how "scripty" Javascript is sometimes, and understand its detractors a bit more (though I am not one of them)

Monday, September 3, 2018

kirk's ui-gripe/hall of shame

It is completely daft that Apple does not let you "nickname" cards or pick alternate looks for for a card that is added to the Apple Pay Wallet. "oh, but doesn't everybody just memorize the last 4 digits of all their credit cards?" is the new "you're holding it wrong".

happy tenth birthday chrome

Google's Chrome browser turned 10 the other day.

This Gizmodo piece mentions that, and about how it's kind of weirdly hard to switch, even when other browsers have caught up on most fronts, and it so clearly puts you in a part of Google's fiefdom.

Some of it's just UI laziness. I've been using Safari more often, trying to push just a bit beyond the monoculture, and because it's said to be easier on the laptop battery, but even the way it does UI tabs feels off. And Chrome's developer tools are even tougher to give up; I don't know if they are better or I'm just extremely used to them.

I remember when IE3 + 4 came out, how much better they felt than Netscape of the time, but it's hard to say exactly why. And Chrome still feels a bit like that now, there's a tough to poinpoint "roundness" in its UI.

Still, the popularity of the browser combined with how "chromebooks" and not tablets have supplanted netbooks or whatever came before for low-cost computing, especially in schools, is a troubling monoculture even without Google's sense of tracking you for the sake of its advertisers.

Thursday, August 30, 2018

lifehack: browser or mac voice synth as PT coach timer

Giving computers a voice has been since the 80s - I remember S.A.M. (Software Automatic Mouth) on my Commodore 64, SBTalker on PCs, and Macs have had it for a while - in OSX you can open up a terminal and type "say whatever".  (Plus there's a variety of voices and accents you can download and have fun with)

It turns out most browsers, including on iPhone, have the same ability:





I thought of this when thinking I'd like a soundtrack to do some Physical Therapy exercises against - a simple, flexible, countdown timer, so I can do the simple reps of "do this, hold for ten seconds, repeat" and not lose track.

I started developing this idea on the Mac using the "say" command - that had the option to insert "[[slnc 1000]]" commands to pause for one second (1000 ms), but it turns out that special command wasn't universal across browsers on different OSes, so I ended up having to build a better UI and managing the time gaps manually - you can see the results here at my Customizable PT Reps Vocalizer

Tuesday, August 21, 2018

organic "is this what you were looking for?" by google lyrics

It's a little sketchy (in a "is this a monopoly abusing its power" kind of way) that Google made song lyric lookup a built-in, don't-have-to-go-the-site-providing-the-information. One thing I noticed as a little irritating is that it always shows you like a lot of lyrics, 1/3 to 1/2 but makes you click to see it all. I guess this has two advantages: one is you can still see the actual web results beneath when the page loads, but more importantly, if someone expands the preview it is a confirmation that the result was a good hit for the search terms used. (I understand this is UI/UX/SEO 101 stuff, but still I hadn't framed it that way for myself before.)

Monday, August 20, 2018

10:1 rule

I've often wondered why programmers are so bad at estimating the time and effort needed for a task. (An old Product Manager friend of mine used to say "ask a programmer for a pessimistic estimate and then multiply that time by two.) Yevgeniy Brikman offers one possible explanation: The 10:1 rule of writing and programming. Looking at git checkins for both his books and some popular software projects, he sees each line being rewritten at least 10 times, statistically speaking! And an update at the bottom of the article points out forum talk saying similar guesstimates of 10:1 apply in film, journalism, music, and photography.

Tuesday, August 7, 2018

manipulating pdf files (and playing jr. sysadmin)

I've never been much of a sysadmin, despite being my own webmaster for decades.

For a sheet music library sideproject I've been on, I've wanted to do three things with PDF sheet music files: split (for when the user uploaded a single file with different pages for all instruments), merge (to put them back when a page might overrun it) and extract contents as text (to try and take a guess what instrument the page is for)

The first thing I found was PDFtk Server. To download it, I had to figure out which linux version I needed; Red Hat or CentOS, Linux 5 or 6, 32-bit or 64-bit. The first two were answered with
cat /etc/redhat-release
(CentOS 6) and the last with
uname -m
(64 bit unsurprisingly)

At that point I could follow the install instructions using a lot of "yum".

The man pages for pdftk indicate the syntax is a bit un-Unix-y. The call splitting "burst", and the syntax is
pdftk BIGFILE.PDF burst
which by default makes pg_0001.pdf etc.

Merging is called concatenation but that's sort of the default behavior for pdftk, so combining page 1 and 2 for example would be
pdftk pg_0001.pdf pg_0002.pdf output COMBINEDFILE.PDF

You can try using a regex to extract text data, but I wanted a proper command. I turned to
pdftotext which is part of poppler-utils -
yum install poppler-utils

That gave me pdftotext and I could do
pdftotext WHATEVERFILE.PDF
which would make WHATEVERFILE.txt, or I could do
pdftotext WHATEVERFILE.txt  -
which would dump to STDOUT.

So, one weird thing is I thought poppler-utils was supposed to come with pdfunite and pdfseparate which mean I could have skipped the pdftk stuff, but for some reason those weren't included, and since I already could do what I needed with pdftk, I decided to give it a miss.

Sunday, August 5, 2018

idiosyncratic css hacks for idiosyncratic blogs (photogallery previews)

I've been running my blog for almost two decades. It's a good example of the old DIY web, powered by a bunch of flatfiles in folders and with a mix of Perl (later PHP) to keep it all together. I love the control handcoding everything offers me and what a deep archive of my life online and off it represents (it's awfully cool to be able to dredge up a photo or half-remembered quote from any browser at any time) but I have to build all its features more or less from scratch, including image uploads, its by-month archive, its tag cloud, and its "On This Day" view.

I've grown to like having my photo galleries in-line as blog content, vs making up special pages for them - for instance I did a series of best digital photos of the year going all the way back to 1996. (One lesson I learned too late is that since its emerged as my main archive, I should have always been putting fullsize versions of photos as links behind the resized-for-web versions. I do that now but stuff from the old days is often hard to find in its full pixel glory...)

So I have these pages, but sometimes when a big gallery page shows up in an archive view, it's disruptive, you have to scroll and scroll and scroll to get through it all and onto the next thing.

I didn't want to have to do a lot of work to update the existing galleries, so I made up the following HTML to paste into each set of photos (followed by the closing div)
  <h2 style="cursor:pointer;" class="hidden-gallery-clicker" onclick="var gal = this.nextElementSibling; gal.style.display = gal.style.display == '' ? 'none' : '';">Click for Photo Gallery</h2>
<div class="hidden-gallery" style="display:none;">

That should be pretty clear to any web coder, the gallery was hidden, and then there was a "Click for Photo Gallery" header that would toggle the visibility of the Gallery.

But... that kind of stinks from a UX standpoint, and general visible appeal. Having a little <h2> tag is not much of an affordance at all the terrific photo content awaits.

I realized I'd prefer tiny thumbnails of all the photos, hiding any extra caption information, but when you open the gallery, all the images show up at their browsable size.

And like I said, I didn't want to have to go hand edit a lot of HTML to do this, so whatever trick I used needed to be pure CSS and maybe a smidge of JS that could live in a single place. But my HTML for the photos was sloppy, I had lots of text nodes outside of separate divs or span tags.

Here's the CSS I came up:
.minishot-gallery {
  font-size:0px;
  border:1px dashed #999;
  cursor:pointer;
  padding:8px;
}
.minishot-gallery * {
  display:none;
}

.minishot-gallery a, .minishot-gallery figure { {
  display:inline;
}
.minishot-gallery img {
  display: inline-block;
  width:auto;
  height:100px;
  margin:4px;
}
.minishot-gallery .minishot-gallery-caption {
  display: block;
  font-size:20px;
}

.minishot-gallery-caption {
    display: none;   
}
.minishot-gallery .minishot-gallery-caption {
    display: block;   

}

The "display:none" for * was the first step, and changing the font size to zero does a good job of hiding the freefloating text. Images are loaded but displayed at 100px high with width to match. I had to let <a> tags display since most of my images are wrapped in those (the link to the true fullsize versions) and then I was also messing around with using the oddball <figure> tag.

The HTML snippet is then:
<div class="minishot-gallery" onclick="if(this.classList.contains('minishot-gallery')) { this.classList.remove('minishot-gallery'); return false; }">
<h2 class="minishot-gallery-caption">Open Photo Gallery</h2>

That's just a bit of JS saying to remove the minishot-gallery class (which in a neat step gets rid of all the weirdness) I had to be careful with the return value so the first click would open it, but clicks on the images afterwards wouldn't be eaten. There were a lot of nooks and crannies to this kind of hackery, but I'm pleased with the end result.


Of course, I'm mighty pleased with my "best of" photo galleries anyway! Maybe it's too bad I now spend most of my photographic creativity on "One Second Everyday"...

UPDATE: I realized for large galleries this was poor UI - if you click on an image later in the set, you expect to see the image you just clicked on, not the top of the gallery.  So the script now is:
<div class="minishot-gallery" onclick="if(this.classList.contains('minishot-gallery')) { this.classList.remove('minishot-gallery'); return false; }">
<h2 class="minishot-gallery-caption">Open Photo Gallery</h2>
<script>
document.addEventListener("DOMContentLoaded", function(event) { 
    var elements = document.querySelectorAll(".minishot-gallery img");
    Array.prototype.forEach.call(elements, function(el, i){
        el.addEventListener("click", function(event) {
            let gallery = el.closest('.minishot-gallery');
            if (gallery) {
                el.closest('.minishot-gallery').classList.remove('minishot-gallery');
                el.scrollIntoView({behavior:'smooth'});
                event.preventDefault();
            }
        });
    });
});
</script>
And obviously you might consider putting that script tag somewhere so it's just called once, even if there are multiple galleries open.

the economic transitions of putting stuff on the web

Two related pieces: one is Alex Singh's tweethread on the transition of the web from independent hangouts to the walled-gardens most of us hang out in today:
Over the past 25 years, the web appears to have transitioned from a primarily nomadic culture to a mostly agrarian one, mirroring the Neolithic Revolution 10,000 years ago.
(The whole thing is just like five tweets)
The second is Nick Heer on The Bullshit Web, where a 1998 modem-based system might download a basic news article in ten to twenty seconds, and a 2018 article over a blazing fast connection might take about the same amount of time - and how Google is offering AMP as a system, but it's getting a huge benefit of keeping eyeballs in Googlespace merely by offering a forced respite form the extraneous file crap.
I take pride in keeping up my idiosyncratic blog over almost two decades, and how the side projects I'm on are largely clear of the BS. I know I tend to build too much from scratch, and other developers get some amazing results using Ruby-on-Rails-style packages, but that is kind of the path to the BS Web as well... the people who are on the "Buy, Always" side of "Make vs Buy" may or may not have good understanding of the tech they employ... I'm too uptight about being left stranded if I make a bug in the infrastructure and don't really get how the magic is working to diagnose it well.

(UPDATED: a more backend look at the Bullshit Web in The Cost of Javascript and some techniques to diminish the impact)

Friday, August 3, 2018

the crushing equalizing of modern social mediums

Mike Monteiro writing on dealing with his depression and social media:
Like a ton of people, I have to deal with it [...] One of the warning signs for me is when I can’t tell the difference between a big problem and a small problem. My brain stops prioritizing. Every problem comes at me at exactly the same size. This is depression taking away a major coping mechanism. And that’s exactly what was happening on Twitter. Every outrage was becoming the exact same size. Whether it was a US president declaring war on a foreign nation, or an actor not wearing the proper shade of a designated color to an awards ceremony. On Twitter those problems become exactly the same size. They receive the same amount of outrage. They’re presented identically. They’re just as big as one another. Twitter works like a giant depressed brain. It can’t tell right from wrong, and it can’t tell big from small. It needs help.
I was struck with the parallels to this criticism of Facebook:
The problem, says Lanier, is that there is nothing special about humans in this information system. Every data point is treated equally, irrespective of how humans experience it. “Jew haters” is just as much an ad category as “Moms who jog.” It’s all data. If Group A has a bigger presence on Facebook than Group B, so be it, even if Group A is trying to demean or organize violence against the Bs. Of course, the reality is that humans are all different, and cannot be reduced to data.
Or as it also says, "To Facebook, the world is not made up of individuals, but of connections between them."

Tremendous problems. I'm not sure what a way of addressing the problem of scale (this is a minor thing, this a large thing) or morality would look like without being censorship. If there's any piece of UX that could help this.

Tuesday, July 24, 2018

bad ux is a misdemeanor against humanity redux - ios settings search and calendar

I generally like Apple's UI, but here are two long-standing problems in iOS.

One is, while the idea of a search box in Settings is great (since the hierarchy can be tough to remember and navigate) the implementation is so poor it's almost useless.

My use case: iOS Calendar sometimes gets confused if someone cancels or moves an Exchange meeting you've just accepted - frequent popups would recur saying it can't accept it. The only way I've found of fixing that is to disconnect the phone from the Exchange Calendar service (doable via a simple toggle switch, once you find it) then reconnecting it.

But where in Settings to do that? A search for "Outlook" or even "Exchange" comes up with nothing, even though "Exchange" is one of the panels under "Accounts & Password". So what if I look up Calendar? I get this result:
I don't think any of those are what I'm looking for. Using the magic word "Accounts" gets you there, sort of, but even then it's a redundant mess.

Another issue with the Calendar is that it's way too easy to put something on the wrong day - I've seen many people make the same mistake I do all the dang time. Why?

If you're using the list view (far and away the best way of seeing a week if you have a schedule that isn't jampacked) and hit "+" to add a new event, it's a bit hit or miss what day the dialog will default too - the day that's pressed up against the top of the scrolling view, and quite possibly not the one you're actually looking at. But once the dialog opens, the "Starts" field just lists the date, not the day of the week.

When you edit the field, the tumbler has the day of the week listed, but as you can see here above the tumbler (they highlight it in red) they didn't think it was important enough to put in the form field itself:

Having the day of the week listed in the field would be much more useful than the year. Because the day of the week isn't listed, many people quickly adding an event might assume the day they were focused on in the list view is where the event landed, and forget to check.

Four years ago I complained about the weird "statefulness" of the iOS Calendar views. I've internalized that so it's no longer a problem, but still - not having the day of the week always visible is just plain bad UX.



Thursday, July 12, 2018

the non-euclidean geometry of boston

At work, we've started a UI reading group and our first book is Edward R. Tufte's (pronounced so it fits the rhyme of Humpty Dance") Envisioning Information.

Unrelatedly, I live in Boston. I always claimed the geometry of the streets was "non-Euclidean", since at the end of Route 2, you can decide to turn left and drive to Harvard Square, or you can decide to turn right and drive to Harvard Square. (I said it jokingly, but someone pointed out, if you define "non-Euclidean" as "the shortest path between two locations ISN'T a straight line" I'm not wrong!)

(Also only semi-relatedly; I used to live in Euclid, Ohio.)

Anyway, Geoff Boeing made this lovely infographic showing the cardinal orientation of streets in major cities:
So good. You can see what a mess Boston and Charlotte have made of themselves.

add ".json" onto the end of most reddit URLs turns it into a mini-API

trojan horses ahoy

A while back I wrote up NPM and New Cities for Trojan Horses, mostly linking to this hypothetical how-to on putting in a credit card swiping bit of javascript in innocent looking code.

Something along those lines seems to be happening now, in the wild, for eslint-scope where some code seems to looking to grab .npmrc files and send them off, via pastebin. YIKES!