Enable Mac Volume Control for HDMI and DisplayPort Audio Devices

When you hook up an HDMI TV or DisplayPort monitor with built-in audio device, you might discover that you can't change the volume with the Mac software mixer any more. Volume buttons on your keyboard won't work. You're expected to use the TV remote or volume control on the device.

Here's a trick to get around this limitation. Grab Soundflower and switch the output to your HDMI or DisplayPort device as shown here:

Soundflower menu

Then option-click the speaker icon in the menu bar. Switch your Mac audio output device to Soundflower:

Mac audio

Here, 34UM95 is the display with audio device that won't let me adjust volume.

Generate Mac App Icons Photoshop Action

Creating App Icons in all the required sizes for a Mac app can get pretty tedious. Here is a Photoshop action to simplify the task:

Download Mac App Icon actions for Photoshop CS6+

The first thing it does is to paste the clipboard contents into a square document — so it's designed for workflows where you edit your artwork in Illustrator, and simply copy the shapes to the clipboard when you're ready to generate some PNGs. The Photoshop action will generate transparent PNGs at 1024, 512, 256, 128, 64, 32, and 16 pixels square.

Generating App Icons

I use bilinear downsampling from the original 1024 pixel base image to generate each icon. This results in nice crisp edges without ringing (sharpening halos).

Making Sausage: Fixing a Previous Git Commit

Let's say I'm six commits ahead of master on my work branch. I've sent out a review, and find out I need to fix something on the 3rd commit. This is my workflow for fixing up the previous git commit:

  1. Get to a clean state on the work branch. (git stash if needed)
  2. Make the necessary changes and commit. For example, git commit -a -m "Date added fix". This will be a temporary commit.
  3. git rebase -i origin master to do an interactive rebase against remote master (assuming your remote is named origin).
  4. Move the temporary commit after the commit that needs to be amended, and tag it f for fixup. (Or tag it s if you want to combine the new commit message with the old one.)

    Screen Shot 2014-03-31 at 9.24.27 AM

Done!

More philosophy: On Sausage Making.

Shuffle Algorithms for Music

Update, March 7, 2014: Improved shuffling has been rolled out on Spotify. More details at the Spotify Labs post, How to Shuffle Songs.

Lots of users complain that Spotify's shuffle algorithms aren't really random. This can best be explained by a cognitive bias called the clustering illusion.

Users aren't wrong to complain, though. What people want isn't true randomness, but an even distribution with separation of similar tracks.

A random sequence might put 3 Michael Jackson songs in a row, but most users don't want that to happen when shuffle is enabled. We should bear this in mind when designing a shuffle algorithm. A simple notion of similarity based on artist alone should get us pretty far. (We can revisit this when users begin complaining that our primitive shuffle algorithm played four cello sonatas in a row.)

Dithering provides a visual analogy for the problem. Dithering is like a halftone pattern, used to create the illusion of continuous tones in a reduced-color image. Two particular methods of dithering are random diffusion and error diffusion.

noise-vs-diffusion

With random diffusion (top), pixels appear clustered together. Error diffusion algorithms (bottom) take neighboring pixels into account and avoid clusters. In shuffling music, we seek to avoid the clusters in the same way.

By the way, Apple got this right 9 years ago.

Subpixel Letter-Spacing in Webkit

As of sometime in August, Chrome Canary enables subpixel CSS letter-spacing attributes. It's a beautiful thing.

capture_2013-09-14_04.03.48

https://bugs.webkit.org/show_bug.cgi?id=20606

http://src.chromium.org/viewvc/blink?view=revision&revision=153727

Avoid Faux-Bold with Web Fonts

Only the best web fonts have a full complement of bold, italic, and bold-italic faces. Typekit provides lots of great fonts with a fleet of variants, but if you're on a budget or enjoy the freedom of Google Fonts (as I do), you'll find a lot of great fonts that don't have true bold variants.

What you end up with is "faux bold," a glyph fattened procedurally by the OS. Here's Poly, with a synthetic bold word:

Screen Shot 2013-05-30 at 12.39.17 AM

It's showing the symptoms of a faux bold: the glyphs are puffed up and letter spacing is widened to accommodate the extra fatness. Yuck. A nice alternative is to find a stand-in that closely matches your ill-equipped font family. The bold word here is provided by Alegreya:

Screen Shot 2013-05-30 at 2.21.57 AM

For me, this is accomplished with a simple CSS rule that overrides font-family for bold elements: b, strong, th { font-family: Alegreya }

Converting to Retina

These are my personal recommendations for making the switch to a high-DPI website.

1. Step one: stop working at 72 DPI

This one is for the designers: get into the practice of doing everything at high-DPI. If you are working in Photoshop, get to know and love shape layers and the path tool, even for the single-pixel details. Any low-res PSD is a PSD you'll have to trash and redo when it gets converted to high-DPI, so don't create any more low-DPI art in the first place.

2. Avoid generating low-res assets when possible

Creating two sets of assets is not always necessary. Distinct low- and high-DPI assets, commonly applied using an '@2x' filename suffix and the min-device-pixel-ratio CSS media query, are only necessary for elements that need precise pixel rendering, such as icons or line art with pixel boundaries that need to be precisely controlled.  (Or when designers see fit to use completely different artwork for low- and high-DPI interface elements.)

It's often sufficient to render a single 2x resolution asset inside an <img> tag with height and width constrained to exactly 1/2 the actual image dimensions, and let the browser handle the scaling on low-DPI devices.  This also works for assets used as background images, if the background-size CSS property is used to constrain the image to the containing element. You'll be relying on the browser to resample the image for low-DPI screens, and this would normally be a deal-breaker in IE9, but results are acceptable when resizing to exactly half original size.

3. Image alternatives?

I don't use vector formats like SVG or web font dingbats because these assets are more difficult to generate and less maintainable than simple PNG or JPEG assets. The tools are not quite there yet. They also yield unpredictable pixel grid alignment at small sizes, which will be ugly on low-DPI displays.

Rendering icons with CSS is a parlor trick not suitable for "real-world" sites, in my opinion.  These hacks don't achieve pixel precision and don't handle browser zoom well.

4. Prioritize your assets

Asset classes should be prioritized for conversion to high-DPI, based on their prevalence in the user interface and their robustness to scaling. From most important to least important:

  1. Your logo
  2. Icons, pictographs, and other symbols
  3. Image-based interface elements: scrollbar caps, buttons, checkboxes, etc.
  4. Small photographic elements
  5. Large photographs

Some assets don't need to be converted to high DPI:

  1. Smooth gradient images
  2. Drop shadow images
  3. Any image that remains virtually unchanged by a 2-pixel Gaussian blur

5. File size is not a concern

Image size over the wire should generally not be a concern.  By decreasing JPEG compression quality, high-DPI images can be saved at the same size on disk as low-DPI images, and won't lose detail.  Check out these informative posts for examples:

Likewise, the compression scheme used in PNG images means file sizes don't scale linearly with number of pixels.

Google Analytics for Backbone Apps

When you build a single-page web app with something like Backbone driving routes and managing browser history, the page load event is only going to happen once at the beginning of the session.

The standard Google Analytics javascript snippet doesn't work so well for these single-page apps. You should trigger an Analytics event when the user changes routes or otherwise causes a meaningful content change in your app.

This can be accomplished with a simple call to _gaq.push(['_trackPageview']) with an optional second argument for the URL path/fragment/route of your current page. To tell Google that a user just searched for Nicki Minaj on my music site, I'd just call _gaq.push(['_trackPageview'], '/search/Nicki-Minaj') for example.

You can get fancy if you are using Backbone, and override the Backbone.history.loadURL function to do this for you: https://github.com/kendagriff/backbone.analytics.