Saturday, February 03, 2024

Moving On

It's time for me to admit I'm not really posting here on Blogger anymore. I'll still keep this blog online (as long as Blogger continues to exist) as a record of nearly 2 decades of writing, but I don't expect to be adding to it.

If you want to see what I'm up to now, come find me on Medium or Substack!

Sunday, January 16, 2022

Goodbye 2021, Hello 2022!

It’s that time again, where we answer the question, “What the heck have I been up to this last year?” Step into my wayback machine all the way to last January and we’ll find out…

2020 was a challenging year for all of us, and part of that in my case was that at some point I just gave up on keeping up with OpenSeadragon stuff, and the issues and pull requests piled up. In January 2021 I finally started digging my way back out of that hole, and within a few months I was caught up again. Things are humming along there now, and we even released version 3.0.0 with a ton of features and fixes! We’ve also joined the modern world and moved our primary chat space over to Discord (Gitter still works, but Discord is where the party’s at). Somehow we ended up making some OpenSeadragon memes as well… That’s how you know that a project has truly arrived, right? That said, we need more, so if you have any meme ideas, get cracking!

We also finally set up an OpenCollective for OpenSeadragon funding. I think OpenCollective is a great service; I love their focus on transparency. Of course Patreon is cool too, but I feel it’s more appropriate for an individual creator like myself than a whole open source project like OpenSeadragon. Things are starting slowly with the OpenCollective… I think there’s a real possibility for the many institutions that rely on OpenSeadragon to each kick in some regular money to keep things rolling. Unfortunately, going to all these folks with the hat out isn’t really my forte, so for now we just wait for people to discover it.

Oh! And I’m also putting together an OpenSeadragon training course with Newline. It’ll take you through the basics and up through advanced techniques, all with real-world projects. I’m looking for beta readers, so if that’s of interest, hit me up!

It hasn’t all been OpenSeadragon… The Living Worlds app continues to find its audience, which is awesome! For my part, I’ve been moving up the learning curve on sound design, putting together sounds for the different scenes. I’ve used monthly social media posts as a way to focus the problem into bite-size chunks. You can see them all on Instagram, but you can also find them on Twitter, Facebook, and TikTok. Oh yeah! I started the Facebook and TikTok for Living Worlds in 2021. I finally feel I’m ready to start rolling those soundscapes out in the app, and the January sounds are in! By continuing to do it one month at a time, I’m keeping it doable (and besides, it’s kind of fun to release things one piece at a time).

Let’s see, early in 2021 I also did a bunch of work improving Driftory in preparation for Stuart McMillen’s new comic project on universal basic income. That’s gone on hold while he finishes up The Town Without Television, but hopefully it will be appearing sometime in 2022.

I’ve also been pursuing 3D art, which has been a very rewarding journey. I’ve fallen in love with Blender and the wonderful community around it! My ArtStation is the best place to see my finished pieces.

Of course there’s client work. I’m blessed to be part of several great teams on exciting projects! The theme right now seems to be “fun telepresence” (if we can’t get together in person, we can get together online, and it might as well be enjoyable): I’m helping build a whimsical 3D/video gathering space with Nowhere and a lighthearted shared doodle space with Scribble Together. I’m also continuing to make pretty data visualizations with Schema Design and keeping things running at Traditions of the Ancestors. There are other things in the works, but they are top-secret still!

What does the future hold? Well, pretty much more of the same, I figure… I feel like I’m in a pretty good groove. I’ll be rolling out new versions of Living Worlds with new sounds for each new month. I’ll continue to facilitate progress on OpenSeadragon. Hopefully Driftory will see new content this year. All of my clients have big plans. I intend to keep doing 3D art and sharing it with the world. We’ll see what surprises the world has in store, but we’ve got to make the best of it as we can.

Thank you for reading this far, and for being part of my journey (in all the ways you are)… May our 2022 be a good one! ❤️


Thursday, June 07, 2018

Wrists & Apprentices

I've been working with apprentices since the early 90s, but I haven't really written about it here; I suppose it's about time!

Every year or so my apprentice graduates and I hire a new one. I recently went through that hiring process, and I'm always a little overwhelmed by all of the interested (and interesting!) people. It's distressing that I can only hire one, especially since I seem to be one of the few people offering this sort of thing in the web development industry.

Anyway, a little history… I started programming when I was 9 and went pro when I was 17. I became obsessed and didn't take care of my body, and by the time I was 20 I had developed a chronic wrist injury that I still have decades later. Maybe I should have walked away from computers, but by then I was hooked! That was a dark time, but eventually I struck upon a solution… I could dictate my code to someone else who could be my hands. Turns out this can be very effective and rewarding (even if it does require some patience).

I use the term apprentice because they're never just a typist… It's impossible to be the conduit for all of that code without picking up a lot of things along the way. I liken it to learning a foreign language by going to a foreign country and hearing people speak it all day long. As we work, I try to explain things along the way, and encourage my apprentice to ask questions. At the beginning I may have to spell everything out, but over time the apprentice picks up the patterns and I can speak at a more high level. The more they understand of what we're doing, the more powerful a team we become!

When I started doing this in the early 90s, pair programming wasn't a widely known practice, but nowadays it's much more common. What I'm doing with my apprentice is much like pair programming, except that the experience gap between my apprentice and me is wider than for most pairs (sometimes my apprentices start out knowing nothing about programming, though that's rarer these days with all the online code learning resources), and we never swap who's typing. Many of the benefits to pair programming still apply:
  • Two pairs of eyes on the code means fewer mistakes
  • We are focused on the job all day long; having someone else there makes it harder to procrastinate
  • Knowledge exchange; my apprentice is learning from me, and I'm learning from talking things through with them
  • We are able to discuss design challenges and alternatives to come up with better solutions
You might think all of this communication must slow us down, but quite the contrary… When we get rolling we really fly! Two minds are better than one.
It's a very close working relationship… We sit just a few feet apart and talk constantly together all day long, week after week. Many of my former apprentices have become lifelong friends of mine. It's also very satisfying to see their careers develop after they move on to the next thing.

Often people ask me about my "apprenticeship program" and how they can replicate it at their company or in their region. First off: yes, you should! There are tons of promising novice programmers out there who just need a bit of guidance and an opportunity to grow. There seems to be no shortage of software jobs, but it's difficult for someone new to break in. Anyone who can tap into that budding talent gets a competitive advantage. Meanwhile, the apprentices get a head start with invaluable learning by being directly involved with real projects. Better training and knowledge exchange means better developers, which means a better industry. For more thoughts on why (and how), see Software Training Sucks: Why We Need to Roll it Back 1,000 Years from Rob Walling. I've also written about the benefits of apprenticeship culture before.

I think what I've been doing gives pretty good results, but of course it's also tuned to my situation… After all, the driving need here is for me to be able to get my work done. If I didn't need them to type for me, I would want the apprentice to move to greater levels of individual contribution gradually over time. As it is, I do recommend my apprentice use their off time to focus on their own projects and bring them in to discuss with me, to help cement their learning.

Anyway, my recommendations:
  • Pick someone who shows promise and passion but doesn't have a lot of experience. Don't just go for college students on break (like many internship programs), or you'll miss out on all the folks coming out of boot camps or who've learned with online resources. 
  • Get them working on real projects right away (whether this be in a company setting or on open source). Real projects are the only way to turn theory into skill. The sooner they get started, the sooner all of the lessons and exercises they've done will actually make sense. Besides, this way they're being productive from the beginning.
  • Start them out pairing with someone who's already established. Make sure the mentor/apprentice relationship is explicit and that both sides understand what's expected. I think it's good for the less experienced programmer to do the typing, because otherwise it's easy for them to zone out while the more experienced programmer whizzes around, but your mileage may vary. It may feel slow at first, but you're sharing valuable information, and things will speed up as your shared experience grows. 
  • Next step would be to have them make their own pull requests and have the experienced programmer critique them. This exercises different parts of the brain than the pair programming, and helps them move into the driver seat. Actually, I suppose you could do this step live, with the more experienced programmer doing the typing based entirely on dictation from the apprentice, but giving feedback along the way. Either way, you'll already have a rich shared understanding to build on.
  • Move them gradually up to more levels of autonomy, until one day they become the mentor for the next apprentice!
So that's my story, and some thoughts on bringing apprenticeship to your neck of the woods. I know it's already happening in some parts of the industry (within companies and at places like Apprenti), but I think it would be great for there to be more of it! Any skilled trade with a complex set of tools and a rich culture can benefit from the kind of cross-pollination and dialogue engendered by apprenticeship, and I'd say software development certainly fits the bill.

What do you think? I'm sure I've just scratched the surface… Hit me up with questions if you've got 'em!


Thursday, February 08, 2018


Wow, I guess I haven't been posting here much lately (though I've been posting regular updates on Patreon). Maybe it's time to change that… How about I start with a little 2017 wrap-up?

Let's see… I'd say it's been a pretty good year for me, both personally and professionally (politics notwithstanding), but I don't have anything really dramatic to report… It's mostly been a continuation of threads from previous years.

I'm working on a variety of projects professionally, as well as my various side projects. For the latter, my year-end wrap-up on Patreon is a good summary, and for the former, you can see a few new entries on my projects page, but a bunch of them are still under wraps.

We didn't go on any big trips, beyond going down to Oregon for the solar eclipse (which was amazing; highly recommended!). Caitlyn is continuing with her homeschool, and continuing to develop her skills in art (traditional and digital; 2D and 3D; still and animated). Christina is continuing to pursue her many pursuits and still somehow finding time to keep the rest of us organized.

Meanwhile, I read books, watched movies, and listened to music.

All in all it's been a fine year. What do I hope for from 2018? Well, probably more of the same. We've found a nice groove. Still, if I could have some wishes:
  • I'd like to do more writing. Maybe here, maybe on Patreon, maybe somewhere else… There are too many options these days, and it's not clear how best to find the right audience.
  • I'd like to get more people involved in my passion projects… Things like Arty Widget, Clockwork Goldfish, and Driftory are all made for people to build with; I need to encourage more people to do so.
  • I'd like to get involved in building VR experiences. Caitlyn and I have been playing in VR, there's a ton of VR stuff happening in this area, and I've been learning a lot about 3D programming, so I figure the time is right.
We shall see… May 2018 be a good year, for all of us!

Sunday, July 16, 2017

OpenSeadragon 2.3.0

We've just released version 2.3.0 of OpenSeadragon!

For those unfamiliar, OpenSeadragon is a web-based zooming library, used all over the world to share high-resolution imagery (classic paintings, ancient manuscripts, medical imaging, etc.). I wrote the original version back in 2007 (holy cow, that's 10 years ago!) when I worked on the Seadragon team at Microsoft. We later open sourced it, and it's been picking up steam ever since then.

This new version brings lots of little improvements along with new features like:
  • Zoomify format support. This is useful for moving over from legacy Zoomify installations, but it also gives us access to Zoomify's tileset creation tools, such as the Photoshop export plug-in, which may mean an easier on-ramp for folks new to zooming technology.
  • The ability to rotate individual images. You've already been able to rotate the entire viewport, but now you can rotate each image within individually.
  • Events to let you know when the current view has fully resolved; as the user zooms deep into your image it can take a moment for all the pixels to load, and knowing exactly when can be useful for certain effects.
  • The ability to preload images before showing them, for smoother transitions from image to image.
  • CommonJS support.
… and much more!

OpenSeadragon is truly a group effort, with 89 contributors so far, not to mention the folks creating plug-ins for it. I'm still kind of stunned at how the OpenSeadragon community has grown!

I oversee the project, but my role is more facilitator than lead. Whenever someone reports an issue, I help them get to the bottom of it, and I review their patches, but I don't do the actual coding for them. This allows me to have a greater impact with the limited time I have for the project, and it empowers more people to become actively involved in shaping the code. I think if I'd personally taken on fixing every bug and adding every feature as they are posted, I would have burned out long ago, and none of the great contributors would have joined.

So, if you're new to OpenSeadragon, come check it out and see all the cool stuff people have made with it! Also, if you appreciate my part in the project, please consider pledging to my Patreon to support my work there.

Congratulations to everyone who's made this release possible! Here's to many more years of awesome zooming!

Sunday, November 06, 2016

Getting to the Bottom of It

In today's world we have many large controversial topics that we keep going around and around on, instead of just getting to the bottom of. I'm sure there are many reasons for this, many of which don't have anything to do with rational discourse, but let's pretend for a moment that a little rational discourse can at least make a small improvement.

Part of the problem with these big topics is that they are so multifaceted, it's hard to hold it all in your head at once. What we need is a big map starting from a simple premise and going down, down, down through all the pros and cons, twists and turns, branching into every subtopic, to fully cover every facet. I'm confident this information is already available; it just needs to be organized.

I'm imagining a website for this. Anyone can start a new topic, e.g. "is global warming real?" Then anyone can add pro or con posts, and anyone can add rebuttals to each, and rebut the rebuttals and so on. Once a topic is in place, you can navigate it by expanding the areas that interest you, until you get to the bottom of it.

In order for this to work, a lot of care needs to go into making sure the structure is clean… No circular arguments, no logical fallacies. All of the misinformation needs to be debunked (not just buried). Wherever possible there should be links to primary sources. Each answer needs to cover a single point. This means there needs to be as much energy and facility directed toward structural work as there is toward content contribution.

So, for instance, redundant answers need to be able to be merged; answers covering multiple points need to be split; points that have been covered elsewhere need to be linked; logical fallacies need to be flagged; etc. Of course each of these actions need to be vettable, so improperly merged, split, or flagged items can be undone. All of this activity needs to be transparent.

Even if a thing like this won't resolve these arguments directly, it would be an invaluable resource for those working to do so.


Saturday, April 30, 2016

Captain America and the Planetary Era

The upcoming Captain America movie has reminded me of a thing I wrote up about Winter Soldier back when it came out but never got around to posting, about the way Planetary Era themes popped up in that seemingly unlikely place.

If you're not familiar with the Planetary Era concept, I highly recommend watching my father's talk: What Time Is It? The basic idea is that various global trends are moving us into a new societal state that is fundamentally different than the empire-driven societies of the last few millennia. Due to our now globally interconnected nature we need to start thinking and working together as one planetary family, with all of the opportunities and challenges that entails. As with any major shift, some folks are already way ahead on this front, while others lag behind.

So anyway, here are my thoughts. If you haven't already seen Winter Soldier, you need to re-examine your priorities, but also be warned spoilers lie below:

So I saw Captain America: Winter Soldier, and I was struck by a couple of Planetary Era themes. I know, you'd think a movie featuring a hero named after a country would be all about Empire Era thinking, and there was plenty that too, but you could see the Planetary Era peeking through.

One thing that really stuck out for me was the way in which the conflict was repeatedly framed as one between order and chaos. That's not unusual in movies of this sort, but what is unusual is that it was pretty clearly stated that order was the side of the villains, not the good guys. Now, of course any healthy society has a balance between order and chaos, but balance isn't a static thing; it's always moving to match the needs of the time. While the Planetary Era may in fact be more orderly in some ways, I'd say it's pretty clear that the Planetary Era themes of diversity, self-organization, and even our increasingly small-world connectivity will certainly look and feel more chaotic to many observers. Rather than clinging to the illusion of order the Empire Era thinking provided, we will be better served by stepping into the apparent chaos of a vibrant interconnected world.

The other thing that struck me was how one of the key aspects of the good guys winning was the public sharing of all of SHIELD's secrets. This too seems more in tune with the Planetary Era's themes of connectivity and self-organization than the Empire Era's rigid hierarchies and us-versus-them thinking.

Perhaps it's a bit much to say that Captain America is leading the charge into the Planetary Era, but it's good to see that even in this unlikely place, ideas that resonate with the new era are taking hold. I'm looking forward to the upcoming movie… We'll see if it continues the trend, or if Winter Soldier was just a comic book outlier.

Labels: ,

Sunday, November 29, 2015

The Importance of Being Ironic

Hipsters and their irony, amirite? What even is the deal?

In the 20th century, the world got way smaller than ever before, but now in the 21st we've taken it to a whole new level with almost instant access from anyone to anyone on the planet. 100 years ago you could easily go months or even years without your worldview being challenged. Not so much anymore, even with the filter bubble effect.

This is actually a good thing… The world has been filled with different ideas and viewpoints for all of history, and it's about time we as a species get around to accepting this fact. It's about time we learned to use our differences to the benefit of all. Just as in natural ecosystems, diversity creates strength, but it also has its challenges.

One of these challenges is holding conflicting ideas in mind simultaneously without feeling the need to pick sides. Sometimes the only way through a complex situation lies on the road to seeming paradox. Becoming comfortable with this cognitive dissonance, so you can freely navigate the multilayered thoughtspace of the world, is a key skill of the 21st century.

And irony, our old friend, is a handy steppingstone to mastery of that skill. What is irony, after all, but the binding together of conflicting ideas? Whether they know it or not, irony aficionados are doing exactly what they must in order to thrive in the hyper-connected world of today and tomorrow.


Wednesday, May 27, 2015

OpenSeadragon 2.0: Forest-to-Tree Zooming

Today we cross a major threshold!

OpenSeadragon turns 2.0 and brings with it full support for zooming multiple high-resolution images in the same scene. Imagine all the pages of an ancient manuscript laid out on your screen and being able to seamlessly zoom in to the smallest detail on any page.

Back in 2008 when OpenSeadragon (then called Seadragon Ajax) was first released — when IE 7 was Microsoft's top browser and woolly mammoths wandered the frozen steppes — smoothly zooming a single image in pure JavaScript was quite the feat! We could only dream about the sort of cool multi-image scenarios Blaise demoed using a native app with GPU-accelerated code in his famous TED talk.

OpenSeadragon doesn't yet do everything shown in that video, but multi-image opens up some exciting new possibilities! Check out these demos for some inspiration:

OpenSeadragon + Rdio: swim across a sea of high-resolution album artwork, discovering new music as you go.

OpenSeadragon + Flickr: hop from image to tag to image on Flickr's most interesting photos of the day.

Chris Jordan Infinite Zoom: kick back and fill your screen with Chris Jordan's giant photo montages.

If you're new to OpenSeadragon, you should also check out all the great work people have done with the single-image version, such as this gigantic panorama of Mont Blanc and this amazingly detailed story-map of Central America.

Now what are you waiting for? Make some cool multi-image OpenSeadragon things!

Labels: ,

Tuesday, February 03, 2015

self = this

I teach JavaScript, and one of the things I've found most confuses people is the self = this pattern (some people even go to great lengths to avoid learning about it). I haven't been able to find a good post on it, so here's my attempt. If you're not interested in JavaScript, feel free to skip this and read some of my other fine posts.

Okay, I'll start with a concise definition and then explain in depth.

Use the self = this pattern whenever you have a function nested inside of an object's method, and you want to access the object's properties.

Assign self in the object's method and use it inside the nested function. Here's how it looks:

var myObject = {
  aMethod: function() {
    var self = this;

    this.aProperty = 'foo';

    setTimeout(function() {
      console.log(self.aProperty); // outputs 'foo'
    }, 1);

So, let's explain further.

Objects with Functions

While you can certainly write plenty of JavaScript without ever attaching a function to an object, I find that organizing my code into objects makes things a lot cleaner. To avoid junking up the global namespace, I usually define a single global object (named "App" or some such) that all of my variables and functions are attached to. To further organize, I'll group related functions and variables into sub-objects attached to the main object.

Most objects will have a mix of variables (called properties when they are part of an object) and functions (called methods when they are part of an object). Here's a simple object with one of each:

var myObject = {
  aProperty: 'foo', 
  aMethod: function() {

Inside an object's methods, there's a special variable, named this, that is a reference to that object. If the method wants to access any of the object's properties or other methods, it does so through that variable, like so:

var myObject = {
  aProperty: 'foo', 
  aMethod: function() {
    console.log(this.aProperty); // outputs 'foo'

This special variable is managed by JavaScript; you don't have to assign it, and in fact you can't. It's assigned automatically for every function. If it's an object method, this is a reference to the object. For any other object, this is a reference to the global variable namespace.

Nested Functions

In JavaScript, you can nest functions inside of other functions, including object methods. This is a common practice when working with user events, network requests, timers, etc.

var myObject = {
  aMethod: function() {
    setTimeout(function() {
    }, 1);

One handy feature of nested functions is that the inner function has access to all of the variables defined in the outer function. This is called closure.

var myObject = {
  aMethod: function() {
    var a = 'foo';

    setTimeout(function() {
      console.log(a); // outputs 'foo'
    }, 1);

The one exception is the special this variable; since the nested function is just a regular function, not an object method, its this is a reference to the global namespace.

var aProperty = 'global';

var myObject = {
  aMethod: function() {
    this.aProperty = 'local';
    setTimeout(function() {
      console.log(this.aProperty); // outputs 'global'
    }, 1);

Putting It All Together

So, we need a way to get a reference to the object to be available inside the nested function. Closure to the rescue! We assign another (non-special) variable, e.g. self, with the object from this. Since this variable isn't overwritten for each function (unlike this), we can use it inside the inner function.

var myObject = {
  aMethod: function() {
    var self = this;

    this.aProperty = 'foo';

    setTimeout(function() {
      console.log(self.aProperty); // outputs 'foo'
    }, 1);


  • There's nothing magic about the word self; you can use whatever variable name you want. However, self is the most commonly used variable name for this pattern, so it's a good choice for clarity's sake.
  • If a method needs a var self = this; line, I always put it at the very top of the method. Putting it at the top isn't absolutely necessary, but I think it's a good convention; that way you don't have to go hunting to see if it's defined.
  • this is only set up properly if you call the method via the object, like myObject.aMethod(). If you instead call the method indirectly, such as when you pass it to another function (e.g. setTimeout(myObject.aMethod, 1)), this won't be set up. To deal with this, we use closures again, like so: setTimeout(function() { myObject.aMethod(); }, 1).
  • It's actually possible in certain cases for this to not be the object or the global namespace. By using JavaScript's apply or call features, you can set this to whatever you want when you're calling a function. jQuery uses this in its event handlers, for instance.