style in web dev

One of the major threads in the substance of style by Virginia Postrel, which I blogged about on October 31, is about understanding why a rational buyer would invest in purely decorative assets. How can it be that spending more on a black iPod than a white one is a good decision?

The answer comes out to a riff on Maslow’s hierarchy of needs, which oversimplifies to the point of being wrong or at least deceptive. The Maslow perspective on buyer goals is that they are prioritized according to how primitive they are. Breathing is more primitive than friendship, hence it gets more priority.

Maslow’s idea suggests that it’s a bad idea to put money into esthetics before you are completely done attaining more primitive goals. So if you haven’t bought dinner yet, don’t get that shiny red ribbon in the store window.

Postrel’s rebuttal is that (in my words), esthetics are a value like anything else and you will choose to invest when the economics are favorable. You need a new car and you want a red ribbon, but one costs more than you have and the other is pocket change.

She has an illuminating example about the looks of computers. Personal computers got a lot better looking in the past ten years, specifically beginning with the Sony Vaio and Apple iMac. (Tangent: blobjects). At the same time they reached a certain parity with consumer needs: the relentless progress of Moore’s law stopped making a practical difference to buyers. Buyers don’t particularly need further increments in system performance, or at least their need isn’t on par with the cost. On the other hand, they do need more attractive living environments, and the additional cost of a more attractive box on their desk is reasonable.

Consumers started to emphasize shallow looks over meat and potatoes performance because the return on investment in looks started to exceed the return on investment in performance.

What it means to web developers and makers of music products is that you should consider chrome as part of your overall value proposition. Hiring a graphic designer might do more for the user than hiring a database administrator. Visual customization to match their profile page might be a higher priority for the user than functional customization with an API. A fashionable look might matter more to them than a fast load.

You have to weigh the relative importance of looks from the user’s perspective. They may be happy to squint for the sake of a sexier font choice, but then again squinting may drive them away to a site which is more readable. There’s no one answer.

The takeaway for me is that users needs are not a strict hierarchy, and sometimes the best thing for them is to put development time and money into sex appeal.


Microsoft has this “Silverlight” thingie which is more or less but mainly more a clone of Flash. A fair number of pundits hyperbloviated over it, which reverse-impressed me. Somebody is going to land a punch on Flash eventually, but it’s not likely to be Microsoft.

But Silverlight could well have a significant impact by expanding the toolchest of APIs available to AJAX apps. The way this will work is that Silverlight will expose some potent and obscure new features and then Javascript programmers will write wrappers to make these features optional upgrades to the user experience.

A whacky Silverlight-only upgrade might be the ability to use the LAPACK linear algebra package in Javascript; this would speed math up for users who had Silverlight and otherwise leave them going along at a poky but survivable rate. If faster math was useful enough, it would eventually lead to the feature becoming broadly available. Maybe Firefox would start including LAPACK, for example.

This was the adoption curve for XMLHTTPRequest, which started out as an proprietary Internet Explorer feature and ended up being implemented by every browser.

The key thing is that Silverlight-specific abilities have to be optional upgrades to the user experience, so that the system has graceful degradation in the absence of Silverlight.

pure AJAX audio formats now a reality

The best hack I’ve seen since Brad Neuberg did AMASS in 2005: Arek Korbik implements Vorbis in Flash, with no dedicated Vorbis support provided by Adobe as part of Flash. It’s a god-level piece of hacking.

What Arek’s hack means is that new sound formats can now be implemented in pure AJAX and deployed with browser-borne technology. This breaks the logjam at MP3, where new audio formats could never reach wide deployment because the only one that Microsoft, Apple, and Adobe could agree on was MP3. The result of the logjam was that innovation related to audio file formats was over in about 1998.

That innovation can now start up again. We can expect growth of patent-free codecs like Vorbis and FLAC. I’ll bet there will be a JSON-based audio format based on Vorbis. And in the long term, freaky Big Daddy Roth audio files with chromed metadata, embedded blenders, etc.

Upate: I’m getting a little pushback from people who feel that (1) there’s nothing new here because it has been possible to do Vorbis using Java applets for a while and (2) this method doesn’t support video.

Java is not a viable option. Most people don’t have Java installed, and the people who do have it installed won’t tolerate the slow and ugly startup. About the need for video, let’s not get ahead of ourselves. One thing at a time.

attribution and reuse

Play the Web is a blog with the premise of exploring technical hurdles for making chains of derivative works:

On this blog we want to talk about media reuse on the Internet and enabling reuse in a responsible way. Media companies’ reactionary response of restricting all use is throwing the baby out with the bathwater but conversely doing away with copyright on the Internet altogether is no better. There’s a middle way and we need to build tools to facilitate that path. Tools to recognise media and enable reuse.

They’re assuming that the end result of their work will be part of The Initiative:

Our immediate challenge is discovering what licensing and ownership attributes are associated with a given piece of media. There are millions of discrete pieces of media on the Internet, how can software tell which are reusable, which are licensed, which are public domain, etc.? A simple solution to this problem is offered by microformats. By embedding meta-data with media in a standardised, machine-readable way we open the door to all kinds of applications that rely on this knowledge.

And they already have an excellent post on how to do attribution for a reused photograph:

I’m now kind of concerned with what to call “Attribution”. In the Creative Commons attribution is a legal term, but what I really want to relate is:

  1. From where did I find the content: Miss 604’s blog. (The Copied Source)
  2. From where did the original content come from: Squeaky Marmot (The Original Source or at least the source Miss 604 found)

Do you reuse content? Do others reuse your content? If so, what do you think? How would you like to see the “attribution”?

I have a couple data points to offer.

One, non-commercial users don’t care about copyright. They know zero about it, they don’t know of any reason to care, and they aren’t going to change. (Software developers, who deal with free and open source software, are an exception to this rule). Commercial users may care, but can’t use content under a non-commercial license. So in practice the issue of attribution only has a real-world impact for derived works created by commercial entities. Source works which are licensed to allow both derivative works and commercial use are the ones we’re talking about.

Two, in XSPF there is an element for giving attribution to the sources of derived works. The idea is that one person would incorporate another person’s playlist into their own, and would use this element to give credit. It is defined as a chronologically-ordered stack:

An ordered list of URIs. The purpose is to satisfy licenses allowing modification but requiring attribution. If you modify such a playlist, move its //playlist/location or //playlist/identifier element to the top of the items in the //playlist/attribution element. xspf:playlist elements MAY contain exactly one xspf:attribution element.

Such a list can grow without limit, so as a practical matter we suggest deleting ancestors more than ten generations back.


The stack framework is a pretty elegant tool for handling this requirement, and I’m happy about how we did it. However this element is rarely if ever used because no current playlist sharing sites that I know of both expect playlists to cross site boundaries and expect users to make new playlists out of old ones.

O’Reilly on goose

Over on the O’Reilly Digital Media site, David Battino has published a piece called Three Free & Easy Web Audio Players which covers Delicious Playtagger, Goose aka Yahoo Media Player, and a new player of his own design.

Want to play MP3s on your site? I did. The unpredictable behavior of audio links annoyed me so much that I finally broke down and wrote my own player. And then I wrote several more. An enterprising bloke in Australia even copied my code and started selling it as his own. But web audio is a treacherous world, and we both learned that what worked well on our own browsers often sputtered horribly on other people’s. … In this article, I’ll look at two free players you can add to your own site with a single line of code. … Inspired by Play Tagger and YMP, I revisited my JavaScript-based web audio player.

In David’s own Batmosphere Multiplayer player he introduces some cool new ideas. Media links that have been made playable launch the player when you click on them without affecting the link itself, so a user can still do right-click+save-as. Also, in the popout window for the player he scales the window to the size of any album art specified by the user, which is pretty damn slick.

A cool accident of the layout of this article is that it captures a sort of threaded conversation among developers of web audio players. Playtagger came first, goose came second, the Batmosphere player came third, and each was an iteration of shared ideas. They all add small play buttons to plain vanilla media links in HTML documents — that was a delicious innovation which goose copied and batmosphere picked up in turn. Goose extended the concept by allowing publishers to customize the player using various fields of the anchor; for example, you can set the song title by using the standard “title” attribute of an HTML anchor element. Batmosphere picks up on these features and adds to the pool by letting you use the “id” attribute to specify a caption.

One subtle, important, and usually overlooked aspect of the goose anchor syntax is that it doesn’t rely on file extensions. Playtagger, for example, requires you to have a URL that ends in “.mp3”, like this:

<a href="example.mp3">my song</a>

But what if your URL doesn’t end in “.mp3”?

<a href="getmp3.php">my song</a>

What if it ends in .mp3 but redirects to an HTML page?

<a href="getphp.mp3">my web page</a>

The design of the web explicitly rules out using the extension to tell the browser what kind of file is on the other end of a link. This is to allow tools designed specifically for the job to be used — MIME types and HTTP content negotiation. And goose supports both of them.

Goose allows you to set the MIME type by using the “type” attribute, so that this *will* get picked up:

<a href="getmp3.php" type="audio/mpeg">my song</a>

And this *won’t* get picked up:

<a href="getphp.mp3" type="text/html">my web page</a>

It allows you to use content negotiation by setting the link class to “htrack”:

<a href="getaudiofile.php" class="htrack">this might be AAC or WMA</a>

For a deeper explanation of the relationship between content negotiation, MIME types, and file extensions in URLs, check out Content Negotiation: why it is useful, and how to make it work. For more details on how goose interprets link syntax, see how to link in the goose wiki.

relative paths in playlists

There is a new version of libSpiff, the XSPF library, with support for relative paths using the xml:base attribute. Up until now relative paths have never worked in playlists as far as I know, so whereas in an HTML document you could do…

<a href="my.mp3">my song</a>

In a playlist you always had to spell it out, like:

<a href="">my song</a>

The long-term story here is about the maturation of playlists as an internet media type. They have rarely gotten enough respect to be implemented well, according to the same high standards as other media types, and as a result they could rarely be shared across different systems. Any application that did bother to support relative paths in M3U had to guess at how that should work, so no two apps would support it the same way and a different M3U file would have to be created for each app. That’s like having one kind of HTML for Internet Explorer and another for Firefox, which is how we did do things in the bad old days before internet developers aggressively moved to web standards.

A plug for libSpiff: it has this kind of sophistication in many other ways as well. Unlike most playlist implementations it does a stellar job with the little details (like character sets outside of US-ASCII) that tell a user whether or not to trust your software. If you’re making an app that uses playlists, you can have that quality level just by using libSpiff.

I know that many developers consider playlisting too trivial to even have this kind of detail. But then again, most app developers don’t do a competitive job on playlist support. Playlists are one of the three atomic multimedia types, along with audio and video. Considering playlists less important is like giving red and green more respect than blue: Light blue and dark blue are finicky colors. Sky blue is pretty much all you need.

Relative paths are a baseline part of the web. If playlists are web documents, they need to support relative paths. This release of libSpiff makes it so.

foo_xspf is a plugin for the foobar2000 audio software that adds XSPF support. XSPF is an open, XML based playlist format developed by the Xiph.Org Foundation. It uses the open library libspiff to parse the files.

license claims in HTML

When you put a Creative Commons license in a web page, it usually applies to that page. For example, if you generated HTML for the Attribution-ShareAlike license using the license chooser at and put that claim into a web page at, it would mean that the page at could be freely shared as long as there was attribution and the sharer applies the same license to their copy.

By using the “about” attribute specified in RDFa, you can modify that claim HTML so that it applies to a different URL and not the page in which the HTML is embedded.

Let’s say you have a media file “my.mp3” (which may or may not have embedded license info), it is online at, and you have a web page at Let’s also say you have a chunk of HTML for saying that the current web page is under an Attribution-Sharealike license.

Your web page containing that chunk would normally have HTML along these lines:

      [the HTML for the license claim]

The modified HTML would look like this:

      <div about="">
      [the HTML for the license claim]

This is a new way to publish a license claim for a media file. The existing way is to embed the claims into the file using a tool like liblicense. The reason you would use the new method is that the benefits and drawbacks are a better match for your needs.

Pros of embedding within media files:

  1. A license claim inside a file travels with the file, so that the license claims on the copy are still identifiable. If you use the external HTML method, the only way to tell that a copy at a different URL is under the same license is to do a byte-for-byte comparison of the files.
  2. A license claim inside a media file is instantly accessible to any program which is already accessing the file and only slightly less accessible to a program which already has a copy of the file. A license claim in external HTML requires the HTML page to be found, fetched, and parsed.

Pros of using an external HTML file:

  1. A license claim embedded in a media file can only be recognized by fetching the file and parsing it. AJAX techniques usually can’t be used to parse a binary file. Bandwidth and latency limits may also prevent this. In contrast, an HTML file can be parsed by JavaScript, and is often small enough that bandwidth and latency are not a problem.
  2. A license claim inside a media file is hard for web spiders to see, and most search engines won’t index it. In contrast, a license claim in HTML is easy for a spider to see and all search engines will index it.
  3. A license claim inside a media file requires a dedicated program like liblicense on the client side to edit. A license claim in HTML can be generated using a simple web application like the license chooser at, and any decent content management system (like Drupal or WordPress) could easily do it.

You don’t have to choose between these methods. There is no reason why these two methods can’t be used together, which would give you the good parts of both.

As with all implementation proposals, this method may not work. It may be that the RDFa “about” element isn’t widely available enough, given that it is specific to XHTML 2 as far as I know. It may be that the rel-license microformat can’t be extended like this.

There’s one improvement to this method that I don’t know how to do — making it work in existing search engines with no changes on their part. If it’s possible to tweak the HTML syntax so that existing search APIs or query arguments could be used to find Creative Commons works, the entire open media ecosystem would benefit.

hAudio in Yahoo! Media Player

This blog post is for techies.

It’s natural for Yahoo! Media Player to support hAudio. hAudio has valuable functionality and is generally well thought out.

But it’s too big a project. The syntax is very complex. Writing a parser and accurately supporting the features is a large job which is out of scope for the media player team. The verbosity of the syntax will turn off many users. And using the syntax is too complex to do by hand; users absolutely can’t write hAudio without a dedicated hAudio editor.

What my team needs is an open source library for parsing the syntax and managing the feature set. This library would have to be small — we have strict limits on code size that are already hard to manage. The library would have to be fast — we already have a long lag time to parse big pages, and our metadata syntax can be parsed much more quickly than hAudio. The library would have to be under a license that we could incorporate into a commercial project; this probably means a BSD license.

What users need is a user interface for authoring hAudio integrated into their working enviroment. For example, editors within Drupal, WordPress, Moveable Type, and social networking sites.

I appreciate the good work of the hAudio creators. They took on a difficult and practical goal and had both the persistence and skill to pull it off. So I’m sorry to say that their project is not yet at the point where my team can take advantage of it.

Webjay playlist popularity metric

Someone asked me recently about the Webjay popularity metric. It was a good metric — simple and reliable — so I thought I’d pass it along here. I do this with confidence that Yahoo doesn’t mind because its metrics are much more sophisticated.

The metric was based on playlist plays, so if somebody played a playlist this was used as input. A “play” was defined as fetching a playlist in a playable format like XSPF, M3U, SMIL, or ASX.

Who it was that fetched the playlist was recorded, so that we could filter out plays according to various reputation metrics. The reputation metric that ended up the winner was how old an account was. I tried others that were more exclusive, but they ended up filtering out so much data that there wasn’t enough left for the statistics to be reliable. By sticking to plays by people who had been around a while, we got rid of plays by people who were just looking around for the first time. New people invariable play the most popular items, so filtering out their activity fixed a feedback loop. (Note to old Webjay hands: feedback loops like this were the reason why the same few playlists would get stuck to the top of the listings).

At this point we had a set of play data that covered the entire lifespan of the project. If we counted each play as a single point, the sum would give the relative popularity of a playlist within all playlists. It would be a hall of fame with playlists from different time periods competing. (Though the point scores would have had to be normalized against the changing popularity of the site by dividing against the total points within a given time period). Given the amount of data and the number of competing playlists for such a large time period, the results would probably have been an accurate indicator of playlist quality.

However, we needed a sense of freshness, because regular visitors want to know what’s happening on an ongoing basis. To make this work the timestamps of the plays were recorded, and plays were given more value if they were more recent. Timestamps were used because they happen to ascend perfectly, which makes them monotonic. The ranking of a playlist was the sum of the timestamps.

However, there was again a feedback loop. The most popular playlists of all time still had an advantage in the popularity listing on the home page, and thus still got stuck to the top of the listing. There was a need to allow playlists to compete within different time windows, so that they could be on even footing. New candidates should be competing with other new candidates.

To set the time window of the ranking, the plays were filtered according to different time periods. I think the time periods were a day, a week, two weeks and a month. This gave us popularity contests among peers. The best playlist today, the best playlist this month, etc. Note that the filtering didn’t rely on when a playlist was created, so sometimes an old one would be rediscovered and rise to the top.

So which time window to use? There could have been pages dedicated to each one, but traffic off the home page was always going to dominate. Also, it is inconvenient to make users click around. The solution was for the different popularity contests to share the home page. This was done by choosing a random time window within the four possible time windows each time the popularity rankings were calculated. On a user level what this meant was that the home page would be showing one of four different rankings depending on when you viewed it.

This constantly shifting ranking set worked to sift playlists up through the ranks. A promising new playlist would get exposure by appearing on the home page in the “today’s most popular” set. It would compete with the other brand new playlists for enough popularity to advance to the “this week’s most popular” set. If it made the cut, it would then be on a footing to advance to the two-week set, and from there to the 1-month set. At each step a bit of popularity gave the playlist opportunity to compete for more.

A bit of good luck was that this metric captured the attention span of the community. A good playlist would be discovered, rise to the top, be tried out by all the regulars, and sink down as the regulars got bored with it.

A deliberate strength of this metric was that it was based on actual behavior rather than on vote counts, so was not as gameable as systems using the Digg approach. This also provided more input data, which improves the quality of statistics.

A weakness of this method was that it relied on a single home page, and a single ranking can never be representative of all the different interest groups. A project that I never got to do was to filter according to similarity with an input set of playlists or playlisters, so that you’d have the world according to Jim (who likes punk and modern classical) or according to Chromegat (who likes hip hop).

So that’s the metric. It developed over many sessions of trying to manage feedback loops and turn user behaviors into meaningful data, and took a lot of tweaking to get right. I hope this is useful to others.