Monday, February 18, 2019

is dotAll you got? (frustrations with firefox multiline string matching)

There's growing discontent among developers with Chrome as a browser (and the risk of it becoming a kind of monoculture in the way IE was, albeit not quite as crappily and a bit more standards-compliant) and many are making the leap to Firefox. And recently I was delighted to see that the developer tools were pretty much at parity with Chrome's, and used many of the same UI patterns as well.

But I found Firefox was choking on some regular expressions I put into the backend tooling for my website.
SyntaxError: invalid regular expression flag s
That s flag, letting an expression like /(.*)/s match multiple lines (because it says to treat linebreaks as normal whitespace-ish stuff) was a critical tool going back to my Perl days...

So to quote T.J. Crowser in StackOverflow:
You are looking for the /.../s modifier, also known as the dotall modifier. It forces the dot . to also match newlines, which it does not do by default.
The bad news is that it does not exist in JavaScript (it does as of ES2018, see below). The good news is that you can work around it by using a character class (e.g. \s) and its negation (\S) together, like this:
His examples then show `[\s\S]` replacing good old `.`. I'm happy to have the workaround, but man is that an ugly one!

I wish I knew more about the history here - feels like Firefox was sticking to the spec more righteously than Chrome, which I guess is fair enough, but why was such a critical piece missing from JS/ECMAScript in the first place? It smells a little bit like some religious war fallout, some coders didn't like multiline conceptually, or something...

p5 and figure-ground reversal fun

I have a notebook from when I was 18, the summer before college.

I had designed T-shirts for my high school's jazz band the years previous, and I guess the band was still the focus of tooling around with some design stuff, and so I made this:

I've always enjoyed handcrafting blockletters, and I believe I made these by drawing the 3D extrusion behind the letters and then just filling in the extruded bits on the page in front.

Anyway, I realized I can now have the mojo to get a computer to do most of the work for me, and so I made fgrtext: figure-ground reversal (the fancy word I saw for it on wikipedia's entry for negative space.) It's a little virtual toy to mess around with the words, colors and other factors.

I made it so you can bookmark creations - here are some designs I made for 222 Street Jazz:


and JP Honk:

You can view source on the page to see everything in one file. The core idea is pretty simple - keep drawing the letters repeatedly in the "foreground" color on a diagonal slant, and then switch to the background color and keep drawing the letters a few more times. There were some challenges in the P5 code for it - they have a library for DOM elements and oddly (to me anyway) you set their .parent() after creation of them, otherwise they just end up attached directly to the body of the DOM, which is kind of weird. (Also since they didn't seem to support textareas, it was pretty easy to manually set up the HTML for that and use vanilla JS onkeyup events to call my functions directly, a bit of mix and match.) One drawback to the sliders was I had to only pay attention to mouse moves withing the boundaries of the main canvas - slider adjustments were showing up as background/foreground movements.

Also I made creations in this system bookmarkable by putting all the parameters in a state object and then encoding the JSON stringified version of that as the hash at every draw(), and then reading the hash at start.

Another courtesy I do is using noLoop() to only draw when the state has changed - p5 is great for many things but processor efficiency isn't one of them.

Saturday, February 16, 2019

ripping music the old-fashioned way

In the beginning (well, my beginning anyway) there were LPs and my parents old 33s. Then cameth cassette tapes and behold the radiant wonder of the CD. Upon this time was a golden age of mixtapes, whereupon one might assemble a cherrypicked selection of tunes (and come on - some may disagree but wouldn't you say most albums are a few good songs and a bunch of filler?) for thine only pleasure or to pitcheth a bit of woo... (gettest thou to the High Fidelity if you are ill-informed of this most wond'rous art.)

There was a brief interval when "mix-CDs" were also kind of a thing - an impressive feat to make one in the mid-90s, when blank CDs were like $25 a pop and a "buffer underrun error" would leave your CD as nothing more than a pretty coaster or frisbee...

But then things went digital even before portable MP3 players (most famously the iPod) really took off. And when laptops were still price luxuries... not sure how we listened to our music, maybe with computer desktop speakers? Anyway, "Napster" was the darling of the turn of millennium - a  co-operative venture that would let you nab pretty much any song you could think of. That was amazing! But, it failed to produce a good method of getting money back to artists...and so Napster was crushed, and for a while there was nothing that replaced it - if you read about a tune and wanted to hear a sample of it, you were probably out of luck.

Eventually, things got better. Online music stores emerged (and Apple dropped its DRM), Youtube coverage of esoteric tracks got about as complete as Napster was, and then came the rise of streaming - a trend I still don't really get. (I sort of see the appeal of customized robo-DJs, but man, I just don't want to encounter that much new so-so music all the time. I prefer buying MP3s, listening to my "recently added" playlist to get acclimated to songs, and keeping all my music even if I stop using a service.)

ANYWAY. There are still some songs or amateur-musicaly-things that aren't available for purchase or other legit download. For a a long while Convert2MP3 did a good job of ripping tracks, but with the rise of Youtube's own attempts at subscription music services, this no longer works for most music tracks (I think it still is an option for some other things that Youtube doesn't categorize as music.)

I figure that with my multiple laptops and tablets I would be able to do rips manually - that a stereo wire with a plug on both ends would let one device playback and the other to record. Turns out it wasn't quite that easy? There are some rumors that Macs' lone audio port used to be able to be used as an input device, but maybe later versions of the OS stopped supporting that. An old Windows 8 laptop didn't seem much better about it.

So not wanting to resort to "be in a really quiet room and use the built-in mic for recording", I bought a USB mic and speaker dongle for like $7, and was then able to use Audacity. I have one wire from the headphone jack on an iPad and it goes right into the microphone dongle, so there's no room noise. I wasn't quite sure how to set the levels, but fiddling with the iPad volume while recording some throwaway tracks 'til the visualization showed consistent filling of most but not all off the space seemed to work ok.

I do worry over time this path will be shut down somehow - already it was awkward. I would have needed a dongle to do it from my iPhone, of course, and if my main Macbook was newer I wouldn't have needed a USB-C dongle for that as well ... and that's beyond obscure technologies that will strive to prevent this kind of shenanigans (like if you try to record video from a secure playback source, or for that matter how photocopiers will recognize currency and decline to duplicate it...)

Thursday, February 14, 2019

drawing x1,y1,x2,y2 lines (any angle) with divs

When I was playing with different technologies for my timelines project Timelines project one advantage P5 had over straight DOM-stuff was being able to draw arbitrary lines (I was already using a lot of X/Y coordinate absolute positioning, rather than letting things flow)

Not surprisingly it's pretty easy to do similar in DOM and CSS, using transform rotations and just a bit of geometry.

The core CSS could be
.line {
    background-color: #000;
    position: absolute;
    transform-origin: top left;  
(the container div should be be styled position:relative or similar)

and then the JS something like

function addLine(id,x1,y1,x2,y2) {
  const canvas = document.getElementById(id);
  const newLine = document.createElement("div");

  const length = Math.sqrt(Math.pow(x1-x2,2)+Math.pow(y1-y2,2));
  const ang = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI; = `${x1}px`; = `${y1}px`; = `${length}px`; = `rotate(${ang}deg)`;

I created a codepen proof of concept but didn't make it do anything interesting.

Of course, this doesn't hold a candle to stuff like Diana Adrianne's pure-CSS oilpaintings but it's a start :-D (For that matter, arguably I'm just reinventing svg, badly...)

Tuesday, February 12, 2019

design failure - when numbers confuse

I am one of the organizers for BABAM, a Boston-based alliance of activist musicians. We had some internal debate about whether it was appropriate for us as an activist group to get involved in electoral politics - for example, some of our partner bands are 501(c)(3) organizations who would be prohibited from that kind of activity. Or, there might be some members who might object to implicit endorsement for a particular politician.

I created an online survey, and then decided to have some design fun posting  the results. I came up with the following, where the size of each of the 28 votes was a dot, with the size of the dot reflecting how often the person said they attended events. A comment at the top explained that the numbers were references to numbered comments below the main display...

But I was surprised when the first response back from the mailing list was
I may be reading these results wrong, but it looks like :
6 fully
22 quietly
1 indirectly
17 none
1 dunno
Aargh! I'm not quite sure how they were working the math, but clearly the digits were throwing things off.

My fix was to replace the numbers with letters, and then visually repeat the circle motif at the start of the comment itself:

 Ah well. Maybe the thing was trying to be too clever. I may have been too anxious to cross reference what a person voted from how often they showed up (originally I was going to do a 2 axis graph of "frequency person attends" to "enthusiasm for allowing campaign activity)

Sunday, February 10, 2019

RIP WAP (or don't, we don't care)

Doing some cleanup of my blog, I ran into's rant about WAP - now available only on the Internet Wayback Machine. At the time I linked to the article I wrote
WAP is the underlying protocol that you use when you use "wireless internet" on your cellphone. Although the protocol itself isn't too too bad (except for an odd 1492 character limit in how much a server can send in one gulp), it's associated with WML, a terrible HTML-like language, and also having to use the cellphone keypad to laboriously tap in letters.
I'm impressed at the combination of technical depth and strong feeling of that article. WAP was horrible. And like the article mentions but my summary leaves out, the nickel-and-diming of the usage fees kept people away in droves. While some other phones were creating more-or-less-ok web experiences on phones (I will always love this horribly NSFW rant extolling the Nokia E70 over the iPhone) I am convinced that one absolutely critical factor in the success of the first iPhone was getting Cingular/AT&T to offer it only with "all you can eat" data, so people could just use the thing without hearing the tick tick tick of an invisible meter run.

Around that time I was working on a project making a WAP gateway to your ATM account balance information (which is why I was intimately familiar with the 1492 character limit) -- late stage dot com boom was a weird time

Thursday, February 7, 2019

VS Code jump back to last edit spot

One feature I'd gotten used to in IntelliJ is a "back" button that would take you back to the last place you were editing, even across files. According to stackoverflow on a mac the combo I want is ctrl-minus (or ctrl-shift-minus to go the other way.)

One feature of VS Code I didn't really grok til I did a big React/Redux fix is the "list of currently open files" on the sidebar. At first this seems a little redundant - isn't that what tabs are for? But there's a bit more room there to show the relevant path bits. Depending on your project structure, it can be very useful to be able to see path info (like "containers/"  or "components/" or "reducers/" or what not) to more quickly get back to the file you're thinking of.

Wednesday, February 6, 2019

visual studio code's logo is a disaster

Trying to be one of the hip kids at work, I'm migrating to Visual Studio Code.

I've complained about editor icons before but VS Code's is horrible:
This page talks about its origins - it claims
We iterated on the infinity logo for some time [...] Until we landed on the current "fish", which tested well with admittedly, a small number of developers.
A. That's... not the infinity logo, chief.
B. with current coloring it looks more like "XJ" then "Infinity Corner"... or like it's a sideways "ribbon for cancer awareness" (Esophagal Cancer according to this page )

For people who tend to think phonetically, it's a disaster, and I don't see many othe redeeming factors in terms of meaning.


Just note to future self:
Work buddy Noah used this immutable.js codepen to help me come up with "how can I modify values in particular Map which is the member of a Set":

const set = Immutable.Set([Immutable.Map({a:'1',b:'foo'}), Immutable.Map({a:'2',b:'bar'}), Immutable.Map({a:'3',b:'baz'})]);
const newSet = => 
    value.get('a') === '1' ? value.set('b', 'hello').set('c','woot') : value

confirming argument order with es6 property shorthand

A coworker was helping me with some Immutable.js (blarg) and wasn't sure of the exact order of arguments his callback would be receiving so he did this:
const funk = (foo,bar,baz) => console.log({foo,bar,baz});
and then
would put
{foo: 1, bar: 2, baz: 3}
in the console, and he could make sure foo and bar and baz were in the right places in the argument list. 

Thought that was pretty clever, an easy cut and paste way of adding human readable labels from "mere" variable names via the es6 sweetening.

Thursday, January 31, 2019

finding files on a mac

I find it ironic that the MacOS file management program is called "The Finder" because finding files (like, with a search) is not really one of its strengths.

Here I am trying to find files with "tuba" in the filename:

Besides the clunkiness of having to use an autocomplete-like function to do a filename search rather than also searching file contents, this view is inadequate if you think it would be useful to know WHERE the result was at a glance. (For a while I was thinking you couldn't get the information at all, but if you select the file the path shows up on the bottom.)

Anyway, I prefer the clunky layout of the free app EasyFind:
It's easy to sort by location, which I find useful in many cases.

If you don't mind paying $8 or so some people prefer Find Any File, which offers a hierarchical view.

Heh - one of my first big tech rants was in 2004 when Windows switched to a sidebar integrated search vs the previously perfectly serviceable standalone mini-program. For Mac too, I find the habit of having just the same kind of display for search results as for folder contents as being a bit of a misthink.

Some people (not me in particular, but I was stuck on Windows til 2013) long for the old old days of Mac, where there was only ever one window for a folder, and it would remember its location etc. It added a certain realness and physicality to the file system, I think.

But then again, from Windows "My Documents" to iOS's too little too late "files" app, OSes kind of don't want regular users thinking in terms of filesystems. And to be fair, it probably is simpler for many folks, but as soon as the folks want to level up and, say, back up their files on their own, or in general not be so beholden to a particular cloud service, it's annoying. (In the windows days C:\DATA was always "my stuff", and transferring to a new PC was pretty easy. These days I stuff everything into Dropbox, which is nicely multiplatform and straightforward in its folder->server mapping.)

Monday, January 28, 2019

timelines title image

I wanted to add my recent timelines project to my alienbill portfolio page - recently I redesigned that page to have fancy titles for the main attractions - I thought for timelines I would take a whole-document screenshot (with Fireshot) than copy and paste lines from that into the title "TIMELINE" (Guess I don't need the S, really, which means all the letters are composed of straight segments).

Here was the first result as seen on the page:

It had some legibility problems, so I went it and hand cut the whitespace around each letter:

Not quite perfect, but good enough.

Sunday, January 27, 2019

amazing playful interactive artsy stuff in browsers by david li

A friend linked to choir, an amazing software toy - a bit like my old favorite mobile app Bebot (a "robot synth") but with a choir and fascinating pseudo-photo-realistic visuals and physics.  (On my old Macbook Air, chrome struggled with it but firefox was fine, as was mobile.)

He has some other amazing works as well - "Character Soup" was a lot of fun with some probably relatively simple but well done fluid physics - the combination of that along with characters to make it less abstract is phenomenal.

Besides his git repository being there, he tweets a tiny bit about his methods - he's doing a lot of stuff in low level wasm and crosscompiling from C++.

Man! I wish I had the chops to code up fluids and 3D.

Also kudos to Adult Swim for sponsoring this kind of stuff.

Friday, January 25, 2019

slack strike out and strikethrough

Daringfireball really ripped into the design work for Slack's new logo:

Before and After image from this page that has some more thoughts. I admit I am not a fan of the "squirting rainbow cucumber swastika" aspect, but YMMV.

Anyway, today I learned you can use tilde to surround text in slack and get a cross out effect. This might make sense to remove a top level comment that then turned into a thread, since you can't properly delete it otherwise.

Thursday, January 24, 2019

slightly fancier console logging

Hmm. Dan Abramov's Idiomatic React Video Course mentioned a few tricks for console supported in chrome and some other browsers (but not all, so you might want to look for undefined functions)

You can do and console.groupEnd do give some nice formatting/indenting.

Also, console.log('%c smurf','color:blue','!!!'); gives you a blue smurf. (Heh, the color console logging thing is very similar to the example trojan horse used in I’m harvesting credit card numbers and passwords from your site. Here’s how.)

Sunday, January 20, 2019

#Software10YearChallenge meet #Website20YearChallenge

#Software10YearChallenge isn't really taking off, and I'm not sure website even count, and it's not like my sites have set the world on fire, but anyway, thanks to the Wayback Machine it's pretty easy to get old views of my two most important sites  and  (I'm sure the name changes didn't help my google juice none.... )

Alien Bill was my first domain, with "Alien Bill Productions" being my fake-y company since my teen years. In the late 90s it looked like this:

Oh, man. What's best about this? The animated GIF at top? The Robotech font? The "Imperfect Web Design for an Imperfect World" slogan? The subtle titled background rockets and UFOs? Or the photorealistic icons I was briefly enamored with? Probably that.

I like the running alien bill (the repeating squares behind him are meant to emphasize motion.) And the micro-screenshots are kind of fun too. I took the animation from the old header and broke it out by frames.
Current day. I've been using the oversized hero image for a while now, and kind of love it. Recently I did a redesign to really try to bring people's attention to the stuff that I'm most proud of or that they might find the most interesting, and used the title fonts from my various works when I could, which mixes things up in a kind of fun way.

Then, my blog, coming up on 20 years. This is shortly after I started blogging, vs just having a more personal homepage-
I moved the personal homepage stuff to a sidebar... and hey, remember guestbooks? Those were kind of great. (I remember my websites guestbook served as an emergency contact pad on a day of surprise layoffs at work, useful in those pre-Social Media times.)

Hmm. Went a little nuts. The hand-doodled icons at top are kind of a throwback to the mid-90s stuff, like an even earlier version of alienbill:
But for the sidebar I had these delightful tiny minimalist things. (Also I used to be so weirdly enamored of that shade of turquoise, which I think showed up in Windows 3.1 or 95 a lot)

Also that was when I was changing gears from slightly longer form blogging to stuff I could mirror on twitter, the "...of the Moment" section. Over the years the UI I built for that became my primary way of adding stuff to the site, and eventually I blurred the visual distinction as you can see in the present day:
A few Christmases ago I embraced a kind of minimalism, and had some fun building up a visual language for the icons and the title at top. Also I added a tag system which is sometimes useful to me.

Wednesday, January 16, 2019

operator overload

Watching this Redux Crash Course video, Brad uses
I could guess what that was doing, but had to ask what that syntax was called - "computed keys" or "computed property names"

In terms of JS, there's definitely a drive for conciseness. Which can pay some dividends in terms of letting experienced coders recognize a complex trope quickly, but also comes with potential ambiguity - sometimes i personally wish the language was a bit more verbose, even if function() { }s are ugly,  bar fat arrows or random floating {}s can be so hard to parse.

Anyhoo, a coworker recommended this guide to ES6 features - it's pretty cool in showing the old and busted after the new hotness.

Of all the new syntaxes, one sticks out as clunky, and the other sticks out as just plain bad and confusing.

Custom Interprolation:
new hotness:
get`${bar + baz}&quux=${quux}`
is the same as 
get([ "", "&quux=", "" ],bar + baz, quux);

Dividing a string that way seems very strange.
But Parameter Context Matching seems really ugly when it starts letting you declare a local variable from a totally different argument map entry....
I mean 
function f ([ name, val ]) {
    console.log(name, val)
function h ({ name, val }) {
    console.log(name, val)
make sense and are pretty easy to read, but the renaming that goes on with
function g ({ name: n, val: v }) {
    console.log(n, v)
is bizarre - it feels like it's messing with left / right operands, every else in js land the key / variable name you're changing is on the left...

(Random note: the video made use of which seems pretty hip.)

hungarian notation

I realized I was almost on the verge of forgetting the term "Hungarian Notation" - a now mostly rejected idea of prefixing variable names with the type of the object. It was probably rejected because it was misunderstood and misapplied - like you shouldn't call your incrementer iCounter just because it's an integer, but if you have, say, a screen dimension that might be in pixels or might be in em, it might make sense to have "pxWidth" or "emWidth".

For instance, I'm fooling around with a gimmicky 3D for my timeline data, and some of my dates are objects containing a y and m key for month and year, sometimes I'm using a "count of months" (i.e. y * 12 + m) and sometimes I've normalized it to a value between 0 and 1. Hungarian Notation kind of makes sense here.

(To google up the forgotten term I had to search "notation petzold" - ah, the old Petzold book "Programming Windows", what an artifact of my first programming job...)

UPDATE: My online pal Jeremy Penner of Glorious Trainwrecks and the Fringe Games podcast worked with Charles Simonyi (inventor of "hungarian notation") and told me about his experience with it:
Anyway, the whole system was written from the ground up using Hungarian notation, and it turns out that it's actually a very interesting mental hack with very unintuitive properties

So, for example, the thing everyone complains about, where coming to a new codebase is totally impenetrable? Like "what the fuck is an mpfuidsibst?" It turns out that's a huge tradeoff that absolutely makes sense when you're building something totally new, in that you don't assume anything about what an mpfuidsibst is. You KNOW you don't understand it instead of believing you have a fuzzy understanding that is actually incorrect.
(mpfuidsibst is a name I gave a thing and it is my go-to example of "this name makes complete sense in context but is utterly absurd to outsiders")
The other huge benefit is that it allows you to talk precisely about different things that are similar and would be given similar names
So instead of talking about an "event", and being unsure of whether you meant a win32 API event, or an internal UI event, or a "document modified" event, all of which are dispatched slightly differently and have different properties, you would have a unique short name for each, that you use consistently
The names are cryptic because they're short, and they're short so that you always say the full name out loud and don't abbreviate, so you are always precise in what you're talking about
It's as much a research collaboration tool as anything
And once you've bought in to the system, and you learn what things mean, it's incredibly effective at preventing misunderstandings
Heh, interesting. In some React/Redux tutorials, I've noticed some times when the naming gets a little fuzzy, like "todos" might mean the JSON object map in memory as state, or as the reducers that tell you how to apply a change to the old state to get a new state

Monday, January 14, 2019

timelines: trying to capture four and a half decades on a screen

Everyone who hits middle aged gets shocked at how quickly life seems to pass (maybe because each year is a smaller fraction of the number of years we've already lived through). Also it's easy to lose track of whole years or even longer stretches. I'm hoping a visual timeline that says "here's where you were" will help me reclaim some of those "lost years" - let me connect with my past self of that era, however distant. Also, it might be interesting to compare different timelines - where was I living, vs who was i working for? Which times of my life had more change, and which had more stability?
A lot of the initial design came from Your Life in Weeks. I sort of loved the macabre nature of seeing all the weeks I was likely to get, with a kind of "You Are Here" in the middle of it. (and not on the early side of the middle either).

Quickly I was reminded that a year doesn't go easily into weeks - neither 365 nor 366 is a multiple of seven! So so either you line up the week columns, but they stick out scruffily on the sides, or you let the weeks shift left and right and you lose your nice rows and columns. And as cool as the "here are all your weeks" idea was, I realized it was orthogonal to getting a sense of history. So I threw that code away.
DOM version (2018.12.09)
Built a "city I lived in history" seeing what happens if I keep everything in the DOM - kinda ugly! Realizing what I want to do with captions doesn't really make sense (i.e. it would be hard to put one caption over several blocks etc.) And I was clumsy with my choice of colors - the old school term for that was "angry fruit salad". I think only labeling every multiple of 5 year was the right idea/
blocks version (2018.12.11)
Switched to p5 and canvas where I have a lot more control over finessing how things are positioned. I figure out how to get colors more or less under control. I also put in the raw data for jobs and romances. I both figured out how to center the captions things that took multiple years were only labeled once, reducing clutter. (Also I added little triangles for things that were going on into the future)
I like how the stacked look gives me a sense of time repeating - like how high school and college summers had their own feel, a kind of central column.
I was a little coy with most of the romances, using initials for the most part. At somepoint I will put a disclaimer saying these aren't all romance-romances, some are "its complicated" or mere crushes on my part. But I consider it all a part of my history and want to claim it.
yearserve (2018.12.12)
Kind of a digression -- I was thinking about getting back to a flattened look, but wondering if I could still get that sense of the looping nature of time - 4 years ago I noticed that my sense of a week and a year are both circular, and so here I am trying to balance that loopiness with a sense of the inexorable forward progression of time - and the seasons, as they are in the New England-y bits of the Northern Hemisphere. I am reasonably pleased with the result, but I don't think it's very useful for marking stretches of time on.
flat (2018.12.21)
If I decided to "flatten" time, I wasn't sure if I wanted to go vertical (the way I kind of visualized time going forward, from left to right) or down (which is more natural for webpages and mobile apps, TBH). Decided to start with Horizontal.
Since it gets soooo wide and to the right, I decided to start with it scrunched, and then zoom in on click. Also I put back in the season colors in - that returns a better feel of the years, but kind of looks like a faded out African Flag, which wasn't a reference I was thinking of.
Overall I think the scrolling to the side gets pretty tedious. I suppose an update with embedded, zoomable photos, say, might might be more compelling, but I'm kind of meh about this one.
UPDATE: I just realized some of these weren't working on iPhone. The error is "Canvas area exceeds the maximum limit (width * height > 16777216)" even though I thought I was setting it to 16470 x 280 = 4611600 which is less than that, but I think it's because of Retina pixel scaling.
Bummer. This might influence what I try next. Either vertical, maybe with DOM elements (some of the frustrations I had with DOM bits might be lessened if I have a simpler, "linear" display) or maybe I should stick with the "blocks" style, which was compelling in its own way.
flatplus (2018.12.28)
One last attempt at full horizontal before I give it up.
Here the idea is that if we move the labels out of the line itself, we don't have to ensure that each span of time is as long as its label, and can compress the entire thing and not make it scroll so far to the side.
The routine to make sure label boxes don't overlap (pushing them to new rows as needed) is slightly complex.
I also took some additional care with the endcaps of the time spans, where one picks up where the last left off the circle is split.
I like how the lines are visually more lightweight than the blocks I've been using, but overall the effect is still a bit jumbled. And I'd say I think "blocks" is still winning in terms of taking in the information.
vert (2018.12.30)
Back to DOM. Using the more sophisticated colors was a big help - and since now each column is a simple chronology (vs the earlier DOM version and "blocks" where years went down but months went across) this one was very easy to code - I even added a gradiant fade to black for things going on now to an unknown point in the future.
skinny (2019.01.02)
Pretty much just vert, but making the lines skinner (but with the caption like a sign on a signpost). Also fixed the colors so that if there's a repeated label in a timeline it gets the same color each time.
I'm learning more and more that this doesn't need to be about "exactitude" in terms of dates. I started rounding off to the nearest month for convenience, and that has proven more than precise enough for my requirements. In fact, for reasons of legibility and design I may play even faster and looser with exact dates.
skinnyphoto / skinnybig (2019.01.04)
Adding in images - This is where shtuff gets real - or rather, really emotionally resonate for me. And I think far more visually compelling as well.
Before this, I hadn't given too much thought about where I'd put the thumbnails - but because the time dimension is vertical, putting small thumbnails to the side seemed to make more sense, now that I'm here.
But I realized I could do better, making the entire block a "cover" image. CSS has pretty cool "cover fit" cropping and stretching, and by using an alpha color for the caption background, I was able to make legible overlays for the caption, keeping the colors aligned.
I also added "big trips" as a column - which has the added bonus of providing lots of images. Not sure if they are showing up in all the old prototypes (though all prototypes so far rely on the same data file)
All the images I grabbed were already in galleries I put online, but seeing so many photos from so many contexts really gets me the effect I was looking for, of telling a story of a middle-aged guys life in one place.
I'm digging "skinnybig". I think I may need to add a cheat so you can have bigger minimum heights, even though most "big trips" are less than a month.
I also want to add a "projects and groups" column - I think I want to design so that it can hold different bars simultaneously (i.e. right now the program assumes I can't, say, have lived two places at once or held
beta1 (2019.01.06)
On the home stretch, maybe. I've started making it so each new version doesn't rely on the common dataset, but makes its own copy.
For beta1 I added the idea of "events" - things that occur on a single year/month - in this case, big vacations and trips I took. I refactored some stuff so that each event takes up 3 months worth of space, so you can get a better view of the photograph.
I also punted on complex logic to make sure images don't overlap, instead putting in a "tweakpos" parameter in the data to nudge an event up a bit. Again one of the takeaways of this is that precision doesn't matter that much - as long as most things that happened around the same time appear side by side, that hits the point I want to get across
beta2 (2019.01.08)
Made a new option so that one collection of date ranges can appear in a single column - so a little logic to place the vertical bars in different sub-columns. Used it to show what bands I've been in. (Hm. Maybe this behavior should be the default, so people don't have to be strict about non-overlapping date fields)
As the display is now larger horizontally, I realized my trick for keeping the column labels pinned is broken. For some reason I can't get the CSS property "sticky" (supposedly a mix of relative and fixed) to function at all.
I also added the same "tweakpos" logic to move any photo blocks around so they don't overlap, and then further tweaks so you can change the y-position of a photo in a short block (vs having it centered).
Also: fixed the headers with position:sticky and made code for seeing the full photo when you click on it less idiosyncratic yet stupid.
final (2019.01.14)
I realized that with all the vertical space I'm taking up, and making a viewer scroll through, the sense of proportionality is lost- part of the mission of this display is giving me a sense that a lot of time has passed, I was living life there, even if I don't have the best recollection of it. To help address that, I added a minimap - showing what the current viewport is showing relative to my whole life so far. I then tweaked it by putting the years, which reinforce that, hey, the 2010s were happening. And also a rough age indicator, of how old I was.
I also tweaked the display of the range blocks, putting a faded-out background behind the entire time range. This is to counteract a feeling that the vertical space occupied by a photo was where the time range was, and not where "popsicle stick" stretched to. (Actually I had to remove that effect for the "multibar" columns where I allow overlapping ranges)

So that's it! Again you can see the final result and if you want me to to make a version with your own life story (you have to provide the dates and photos, I can handle much of the rest) let me know!

Friday, January 11, 2019

scrolling minimaps with css and javascript

Remember the old arcade game Defender? And how they had a little minimap scanner at the top, that could show you where aliens were abducting your humanoids even as the screen was scrolling horizontally? For my timelines project, with a big vertical scroll, I wanted something similar - I want a generous amount of space to include images, but I wasn't liking losing the sense of "a whole life", so a small map seemed like the right idea, with a little frame on the map saying "you are here" (Kind of like a modern disappearing relative scrollbar, except it can hold a mini-me version of the whole thing.)

I might have cheated a little bit - I decided everything above the main content will be in a single block with an id of "header". The minimap and the frame moving in it then look like this:
<div id="minimap">
    <div id="frame"></div>

The CSS (fixed to one edge, and using opacity to let you see the real world beneath it)

#minimap {
    border:1px black solid;
    top: 40px;
    z-index: 100;
    overflow: hidden;
#frame {
    position: absolute;
    border:3px red solid;

Then I just call setupMinimap. The code is a little wonky for IE support:

function setupMinimap(){
    if(window.addEventListener) {
        window.addEventListener('scroll', onScrollEventHandler, false);   
        window.addEventListener('resize', onScrollEventHandler, false);   
    else if (window.attachEvent) {
        window.attachEvent('onscroll', onScrollEventHandler); 
        window.attachEvent('onresize', onScrollEventHandler); 

function onScrollEventHandler() { 
    const main = document.getElementById('main');
    const frame = document.getElementById('frame');
    const header = document.getElementById('header'); = (window.innerHeight / main.offsetHeight) * 100.0 +"%";
    let frameTopPercent = (100*((window.scrollY - header.offsetHeight) / (main.offsetHeight))); = frameTopPercent+"%";

    /*if(frameTopPercent < 0) { = 'none';    
    } else { = 'block';    

FOLLOWUP: you can see the end result on my timelines page

Thursday, January 10, 2019

position: sticky not working ?

So, there's a cool position: sticky CSS style - the idea is that it behaves like position:relative; but then once its containing element is scrolled it is like position: fixed --  good for column headers so they're always visible even when the body of the table or whatnot is halfway off the screen.

I was having trouble using it for my timelines project, it was seemingly ignored it - I resolved the problem by making sure its containing element had a height style explicitly set.

Monday, January 7, 2019

pretty css blockquotes

Literally probably a decade ago, a friend's blog had a neat bit of styling for quotes that I've always meant to emulate - it had a big ol' quote mark as background to the right. 10 Simple CSS Snippets for Creating Beautiful Blockquotes linked to this codepen that was in the ballpark of what I was thinking of:

<blockquote> and then a <footer> tag for the citation (some of the examples used a semantically better "cite" attribute on the blockquote but you can't really do more markup, such as links, in that.)

I don't use a CSS preprocessor for my blog, and so the code I ended up with looks like this:

blockquote.quote {
    position: relative;
blockquote.quote::before {
    content: '\201C';
    position: absolute;
    left: -0.3em;
    top: -0.2em;
    font-size: 6em;
    z-index: -1;
blockquote.quote footer {
    font-size: 0.9em;
    padding-left: 1em;
blockquote.quote footer::before {
    content: '\2015';  
So much of my blog is about quoting things, it's nice to have a flexible way of showing that it's not me speaking.

Saturday, January 5, 2019

capturing cmd-s and ctrl-s in browser

The homebrew backend for my personal blog is an ugly, aged, idiosyncratic mix of Perl and PHP
(to paraphrase yoda, "When 6580 days old you reach, look as good, you will not, hmm?") but I have total control and the editor I use has some features I like - 
  • convenience forms for "quick hits" vs longer pieces (the former auto translates linebreaks into <br> tags) along with a simple tab interface with back button support
  • scaling images taking care of iPhone rotation issues - but keeping the fullsize images around as well (wish I had done that years earlier, the blog really is my best archive of cool stuff) 
  • Relatedly, it's not really well integrated into the editor, but my new CSS-only thumbnail gallery system is still pretty keen.
  • a simple but slick way of saving me from typing up <a href> tags - I prefer to be in raw HTML mode rather than markdown, but still, the idea of "linkify this" using the highlighted text as the URL if it starts with "http" or as the clickable text if not works super well and doesn't require any other UI bits.
and now:
  • support for cmd-s to save
The code for that is a bit temperamental to setup: some similar variants don't do the job but this worked for me:

function setupCmdSIntercept(sel,clicksel) {
    jQuery(sel).keydown(function(event) {
            // If Control or Command key is pressed and the S key is pressed
            // run save function. 83 is the key code for S.
            if((event.ctrlKey || event.metaKey) && event.which == 83) {
                // Save Function
                return false;

Code modified from Pascal Bajorat's sample...
(oh the embarrassment - not only is it jQuery, but I can't even use the $ short cut because of the way it's embedded in even older Perl)

Of course the more general "edit any file on any of my subsites" edit system I refreshed last spring is going great (and probably why I longed to put the cmd-S support in the blog system as well.) The UI is idiosyncratic, but it's removed like 85% of my need to use an FTP program or ssh to do work (file upload, file deletion, and making directories are where it goes above and beyond the normal bounds of a browser based text editor)

FOLLOWUP (2019.02.01):
Here is a version that works without jQuery. Tested on modern chrome, safari, firefox, edge, and even old ie.

    if(e.key === "s" && (e.metaKey || e.ctrlKey)) {
        return false;   

Obviously you might want a more specific element than "document" (which I guess might need stopping propagation) but you get the idea.