One of the first decisions I made after getting my MacBook Air was that I would try running it without Adobe’s Flash player installed for a while and see how it would do. After all, Apple wasn’t even installing Flash on its computers anymore, so the open web must be doing pretty well, right? I ran with this setup for a couple of reasons other than Apple’s refusal to install it on my system. First, I’m a fan of performance and all evidence points to Flash taking performance out back, putting a shotgun to its head, and going all Old Yeller on it’s ass (err, head). Second, I was curious to see how much of the web had moved over to using HTML5-compatible video standards now that the iPad had been out for almost 18 months.

The experiment worked pretty well, actually. With Vimeo videos, since we released the Universal Embed Code and Desktop HTML5 Player last year, the vast majority of new videos played fine. YouTube, however, was a different story. They also have an embeddable HTML5 player, but they’re certainly in no rush to promote it, so most YouTube embeds are of the Flash <object> embed variety. To get around this, there’s a neat Safari extension called YouTube5 that replaces YouTube Flash video players with a nice, simple HTML5 player that plays great on the desktop. Life was good.

Then, a couple of days ago, YouTube changed something on their end and inadvertently (or not so inadvertently) broke YouTube5. I’m sure the extension author will get around to fixing the extension at some point, but what’s to stop it from breaking again in the future? There has to be a better way.

As it turns out there is a better way, and I actually wrote it myself when we originally announced our Universal Embed player at Vimeo. When the Universal Embed first came out, we had deal with the fact that while all future embedded videos would be able to display HTML5 or Flash video players, we still had millions and millions of embedded videos that were embedded the old-fashioned way with Flash (which is true to this day). The solution was a snippet of JavaScript I wrote that would search the page for any old Flash embed code, grab all of the important information we needed from it, and replace it with the updated Universal Embed. The original intention was for site authors to use on their own websites, but there’s no reason this couldn’t be (quite easily) turned into a browser extension.

So, without further ado, I give you the Embedinator. It’ll scan the page for embeds and update them where necessary. By default it automatically runs every time you load a page in your browser, but you can turn that off and run it manually by clicking on the button in the toolbar. It of course supports Vimeo videos, but I’ve also added support for our friends over at YouTube, using their own iframe embed player to replace all of their old embeds. As well as supporting YouTube, I’ve structured the extension so that it’s easy to add more services, so if you think of any other video players that have an HTML5-compatible version, feel free to contact me with the details and I’ll try and add support for it.

Like all of my projects here on Reusable Bits, Embedinator is open source and available on GitHub. Feel free to check out the source, give suggestions, or fix any bugs for me :-). If you’re just interested in downloading and installing the extension itself, you can find it below.


Download Embedinator for Safari.

Update: Latest version (Embedinator 1.1) works with (most) videos on YouTube.com. Unfortunately, since it’s using embed code, any video whose settings don’t allow the video to be embedded won’t be playable. Such is life.

Drawing Resolution Less-Dependent Graphics

One of the great recent additions to modern browsers is the <canvas> element. The <canvas> element enables a whole new world of client-side scripting awesomeness by allowing you to draw graphics into an HTML element via JavaScript.

That’s awesome!

However, a popular misconception1 exists with the <canvas> element: <canvas> graphics are not vector graphics, they’re raster. What does this mean? It means if you’re viewing your beautiful <canvas> artwork on a device that supports zooming, once you zoom past 100%, your artwork will get pixelated.

That sucks!

So, how do we solve this? As it so happens, this issue was solved several years ago before these zoomable devices were even on the market by none other than the Webkit team:

The img element already supports specifying explicit sizes, and so today you can specify a width and height and if an image is larger it will be downscaled. In a high DPI system where 1 CSS pixel != 1 device pixel, more detail can then be rendered.

In other words how you scale an image is based off comparing device pixels and not CSS pixels. For example, if you have a zoom factor of 2, an img tag that specifies a width and height of 100 CSS pixels, and an image whose intrinsic size is 200×200 device pixels, then that image is not scaled, since 100×2 = 200. However on a lower DPI display that might not have any zoom factor set, the 200×200 image would be properly downscaled to 100×100.

The basic strategy here is two-fold. First, we provide a graphic whose dimensions are greater than the dimension we intend on displaying them at. This means if we want to display a 50x50 pixel image we use a 100x100 or 200x200 pixel image instead. Then, we resize our nice large image back down to 50x50 pixels (using either CSS or the width and height attributes). The net effect here is that when you zoom in on your image, the High DPI display will show all that extra pixel information, while normal displays will be none the wiser.

What does this <img> magic have to do with our friendly <canvas> element? As it so happens, we can apply this same exact strategy. If we draw out our <canvas> larger than we need it to be, then resize it back down, we get nice, crisp artwork even when you right up in its grill. So instead of drawing your 50x50 pixel canvas artwork at 50x50 pixels, try drawing a 100x100 pixel (200x200, 800x800, whatever you please) <canvas> element and then shrinking it back down to 50x50 pixels in CSS.

You can actually see this at work in the Vimeo video player:

Awesome: Awesome

Not so Awesome: Not so Awesome

What’s really great about using this technique with the <canvas> element versus simply linking to a larger image within the <img> tag is that since graphics are being drawn client-side you’re not loading extra bytes over the network that are potentially 2-4 times larger than you really need2.

Script on!

Further reading:

  1. I think some of the confusion stems from how the word vector is used in relation to <canvas>. The <canvas> API is “vector” in the mathematical/physical sense, meaning a line is drawn by defining a direction, and a magnitude. It is not vector in the sense that the graphics are re-drawn each time the view updates (ie. when you zoom in). Once <canvas> graphics are drawn, they exists as rasterized pixels and cannot be manipulated as separate objects, unlike SVG

  2. Ah yes, there’s always a footnote next to a sentence saying there’s no downside. While it’s true you’re not loading in extra-large artwork, saving you the cost of transferring that over the network, you still are drawing 2-4 times as many pixels on the screen. This can potentially have an effect on drawing speed, memory usage, and animation performance. So just be aware of these caveats and test often. 

Simple Class-based Function Pattern for JavaScript

Some sample code and an overview of a neat, simple pattern Brad and I used when we wrote the HTML Player over at Vimeo:

When your JavaScript code gets loaded tens of thousands of times a minute, every little byte counts. Therefore, right at the outset we wanted to come up with a simple pattern around which we could structure our code that would allow us great flexibility (we’d be developing 3 players, afterall: Desktop, Mobile, and Touch) but would also lend itself to good compression before deployment (in our case via Google’s Closure Compiler).

Now, there are many, many, many things that we did to bring our video player source code to its svelte ~25k, but one of the techniques was to be extremely precise in scope for our class methods. Above you can see some stubbed-out code that illustrates the three different types of class methods we used: Private, Privileged, and Public.

Click through to see the sample code as well as explanations for the three method types.

Say Hello to Snipe

Over the past few weeks I’ve taken it upon myself to learn Python. Learning a new programming language is fun and all, but it requires a ton of work and a ton of research. All of this research has left me with a lot of open tabs and windows that look a bit like this:

Or if you’re a crazy Chrome user, like this:

Finding a specific tab in that mess is no fun, especially when you have multiple tabs open from the same site, leaving all your tabs looking the exact same, starting with the same words. I thought there must be a better way to handle this when it occurred to me that the same problem exists on your operating system when looking for Apps, and OS makers have come up with some great solutions.

Since this solution is so natural and intuitive, I thought it would be a perfect fit to apply the same idea to searching your browser tabs and windows, and Snipe is the product of that:

To bring up Snipe, you simply press Ctrl + Alt + Space 1 on any open tab2, and up pops the input field. Begin typing and, automagically, results from your open tabs (in any window!) start appearing. Use your keyboard to select which tab you’d like, and Snipe will switch you to that tab and get out of your way. Snipe searches both the title and the url of your tabs, so fear not if you’re looking for your Facebook tab but don’t remember what page it’s on. Also, searching is “fuzzy”, meaning you don’t have to get the content exactly right to get a result, and the results are smartly sorted by which one Snipe thinks is the most relevant based on your key words.

I’ve shared this extension with some people around the office and they really seem to like it. I know I’ve found myself using it constantly throughout the day, so I’m excited to see if other people find Snipe as useful as I do. Check out the download links below to install the extension (Chrome and Safari only) and, like all the projects I post on Reusable Bits, Snipe is also available for you to fork on Github to make your own additions and contributions. I’d love to hear about any feature ideas you have on the extension (there’s already a couple ideas I have in a todo on the Github page) so feel free to leave any brainstorms in the comments.

Snipe for Safari | Snipe for Chrome (Web Store) (Direct Download) | Source on Github

  1. For Chrome users of Snipe, you have a couple other options as well. Snipe will work as a popup window with the regular Ctrl + Alt + Space shortcut, but it also shows up as a button in your toolbar and clicking that button will invoke the Snipe UI. Also, for the super-savy Chrome users, you can take advantage of Chrome’s Omnibox. Simple type “tabs” into the Omnibox and then hit the TAB key, and begin searching for your tabs as normal. You’ll see your Snipe results show up built right in to Chrome. 

  2. After you first install the extension you’ll have to either refresh all of your open tabs or restart your browser to get the keyboard shortcut to work. Sorry, but I don’t think there’s a way around this! 

Clamp.js v0.2: Explanations and Performance Updates

A couple of weeks ago I released a cool little utility called Clamp.js that helps with clamping (ie. adding ellipsis to) long pieces of html text. I was pretty excited about its release, though I stated that one downside was that performance improvements could be made on it since it loops character-by-character through a piece of text, checking to see if it fits each time.

After some really constructive conversations with people on twitter and on this blog, I made some updates to how Clamp.js loops through text looking for a good fit. However, before I go into that, it’s probably constructive to visualize how Clamp.js used to work.

Read More

Introducing Clamp.js

Recently, while working on some last-minute fixes for the Vimeo HTML player, I ran into a limitation of current-gen browsers that really frustrated me. It seems that there is no standardized, supported way to clamp an HTML element. What do I mean by clamp? If you have a design which limits your text to be only 2 or 3 lines long, but the text is dynamic and so can be any length it damn well pleases, clamping will ensure the text gets chopped off at the appropriate height and will add ellipsis at the end to denote that the content has been interrupted.

I did some research and found Dave DeSandro’s entry about -webkit-line-clamp which, through applying some seemingly unrelated and random CSS styles, does achieve this effect… sort of… most of the time. Here’s an example of some properly clamped text in our wonderful video player:

Great! That works! Well… sort of. Here’s what happens if your HTML element just happens to have a link as the last node of the element:

Whoops. It’s actually inserting the link from the very end of the paragraph even though it should be getting cut off. As Dave explained to me, -webkit-line-clamp is not only vendor-specific, it’s completely undocumented and experimental, so it can’t really be used reliably.

Instead of admitting defeat I decided to write my own solution (I mean how hard can it be, right?). Well, it turns out it wasn’t that difficult at all, and the results are hosted over on Github. You can give it how many number of lines you want your content to be, how many pixels high you want it to be, or a setting of “auto” where it’ll fit as much as it can in a given area and then automatically clamp itself. If you’re using a browser that supports the wonderful -webkit-line-clamp it’ll attempt to use it (though you can force to turn it off as well), otherwise it’ll fall back to a JavaScript-based solution.

There are, of course, some caveats with using it. First, it can be a little expensive performance-wise if used incorrectly. Clamp.js works by removing one character at a time from the end of the content until it fits inside a designated area. That means that if your content is 30 lines long and it needs to get down to 2 lines, it’s going to loop hundreds and hundres of times until it gets from 30 to 2 lines. This is something I want to improve on at some point, but for now just be aware of this. Second, I haven’t done too much extensive testing (that’s what you guys are for!) so there are bound to be bugs. Don’t use this in mission critical projects just yet.

Other than that feel free to use the heck out of it and give me some feedback. I would love to know what you think!

Update: Performance updates released with v0.2.