Classic Wallpapers

    Overcome by a wave of nostalgia, I recently booted up my SheepSaver Mac OS 9 installation and put together a collection of all the system wallpapers.

    Download

    If you're looking for something a little higher resolution, Louie Mantia has a fantastic re-render of the 'Mac OS Default' pattern on his wallpapers page.

    JavaScript Clocks

    Earlier this year, I created a JavaScript analogue clock for a side-project. The clock never made it into shipping code, so I thought I'd share it here for posterity.

    The HTML is more complex than I might like:

    <div class="clock-container">
        <div class="clock-body">
            <div class="clock-hours"></div>
            <div class="clock-center-shadow"></div>
            <div class="clock-minutes"></div>
            <div class="clock-center"></div>
            <div class="clock-seconds"></div>
            <div class="clock-center-seconds"></div>
        </div>
    </div>
    

    And, as always, the CSS is incredibly verbose:

    .clock-container {
        background: #324B72;
        padding: 32px 0;
        margin: 0;
        border-radius: 6px;
        text-align: center;
    }
    
    .clock-body {
        display: inline-block;
        position: relative;
        height: 200px;
        width: 200px;
        border: 8px solid #fff;
        border-radius: 50%;
        box-shadow:
            0 0 5px rgba(0, 0, 0, 0.3),
            inset 0 0 5px rgba(0, 0, 0, 0.3);
        margin: 8px;
    }
    
    .clock-type-night {
        background-color: rgba(0, 0, 0, 0.3);
    }
    
    .clock-type-day {
        background-color: rgba(255, 255, 255, 0.3);
    }
    
    .clock-hours {
        box-sizing: border-box;
        background-color: #fff;
        position: absolute;
        width: 8px;
        height: 50px;
        border-radius: 4px;
        bottom: 96px;
        left: 96px;
        transform-origin: 4px 46px;
        box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
    }
    
    .clock-minutes {
        box-sizing: border-box;
        background-color: #fff;
        position: absolute;
        width: 6px;
        height: 80px;
        border-radius: 4px;
        bottom: 97px;
        left: 97px;
        transform-origin: 3px 77px;
        box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
    }
    
    .clock-center-shadow {
        position: absolute;
        width: 18px;
        height: 18px;
        background-color: #fff;
        border-radius: 50%;
        left: 91px;
        top: 91px;
        box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);    
    }
    
    .clock-center {
        position: absolute;
        width: 18px;
        height: 18px;
        background-color: #fff;
        border-radius: 50%;
        left: 91px;
        top: 91px;
    }
    
    .clock-seconds {
        box-sizing: border-box;
        background-color: #aaa;
        position: absolute;
        width: 2px;
        height: 100px;
        border-radius: 4px;
        bottom: 89px;
        left: 99px;
        transform-origin: 1px 89px;
        box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
    }
    
    .clock-center-seconds {
        position: absolute;
        width: 8px;
        height: 8px;
        background-color: #aaa;
        border-radius: 50%;
        left: 96px;
        top: 96px;
    }
    

    But at least the JavaScript is fairly simple:

    $(document).ready(function() {
    
        var transform = function(degrees) {
            return "rotate(" + degrees + "deg)";
        }
    
        var updateTime = function() {
    
            var now = new Date();
            var hours = now.getHours();
            var minutes = now.getMinutes();
            var seconds = now.getSeconds();
    
            var hourDegrees = (hours * 30) + (minutes * 0.5);
            var minuteDegrees = ((minutes * 60) + seconds) * 0.1;
            var secondDegrees = (seconds * 6);
    
            $('.clock-hours').css("transform", transform(hourDegrees));
            $('.clock-minutes').css("transform", transform(minuteDegrees));
            $('.clock-seconds').css("transform", transform(secondDegrees));
    
        };
    
        setInterval(updateTime, 1000);
        updateTime();
    });
    

    On-Demand 3D-Printed Parts

    We often hear the promise that advances in 3D printing will provide a new supply chain model, giving us access to products for which there is otherwise insufficient demand; that, amongst other things, this is set to revolutionise the spare parts market, allowing companies to provide parts for any item on-demand.

    Unfortunately, although companies such as Shapeways offer comprehensive marketplaces for makers to sell their designs, these are flooded with novelty items (and gadget cases): items of which there is already a glut in traditional retail channels.

    You can imagine my excitement then when I recently had an opportunity to purchase a vaguely practical 3D-printed item which would not have otherwise been available:

    3DS Cartridge Blank Thin

    Having switched to all digital downloads, my Nintendo 3DS now has an empty cartridge slot: ideal for collecting dust and a perfect point of structural weakness. Thanks to 3D printing, it's possible to purchase a blank 3DS cartridge from Shapeways. I opted for the 'Black Strong & Flexible' material – a matte textured plastic – and an very pleased with the result.

    Game Boy Cartridge

    In the interests of restoring to Game Play Color some of the original Game Play design that didn't make the first-cut, I've been gradually converting these elements over to pure HTML and CSS.

    One piece I found particularly daunting was the rendering of the original Game Boy cartridge used in the game library. The current version of Game Play Color sports a much simpler game library for this very reason.

    On the left you can see the more skeuomorphic Game Play game library; on the right, the simpler Game Play Color game library.

    This has always felt like the lazy approach (and I'm not a fan of exclusively flat design) so, a few days ago, I set about rectifying the situation:

    Super Mario Land
    This Side Out

    The HTML for this is fairly simple, though I'm disappointed by the number of elements required, especially for the embossed bars across the top of the cartridge:

    <div class="cartridge">
        <div class="top"></div>
        <div class="logo"></div>
        <div class="lines">
            <div class="bar left one"></div>
            <div class="bar left two"></div>
            <div class="bar left three"></div>
            <div class="bar left four"></div>
            <div class="bar right one"></div>
            <div class="bar right two"></div>
            <div class="bar right three"></div>
            <div class="bar right four"></div>
        </div>
        <div class="inset">
            <div class="label">
                <div class="title right">Super Mario Land</div>
                <div class="title left">This Side Out</div>
                <img src="/assets/2016/03/mario.jpg" />
            </div>
        </div>
        <div class="edge left"></div>
        <div class="edge right"></div>
        <div class="arrow"></div>
    </div>
    

    Unfortunately, the CSS proves a little more complex, with many special cases and absolute dimensions:

    .cartridge {
        width: 140px;
        height: 152px;
        background-color: #848086;
        position: relative;
        box-shadow:
            0 0 5px rgba(0, 0, 0, 0.6),
            inset 0 1px 1px rgba(255, 255, 255, 0.6);
        margin-top: 8px;
        margin: auto;
    }
    
    .cartridge > .logo {
        box-sizing: border-box;
        position: absolute;
        top: 4px;
        left: 15px;
        width: 110px;
        height: 28px;
        z-index: 10;
        border-radius: 100px;
        background: linear-gradient(top,
                                    rgba(0, 0, 0, 0.2),
                                    rgba(255, 255, 255, 0.2));
        background: -moz-linear-gradient(top,
                                         rgba(0, 0, 0, 0.2),
                                         rgba(255, 255, 255, 0.2));
        background: -webkit-linear-gradient(top,
                                            rgba(0, 0, 0, 0.2),
                                            rgba(255, 255, 255, 0.2));
        box-shadow:
            0 1px 1px rgba(255, 255, 255, 0.5),
            inset 0 1px 1px rgba(0, 0, 0, 0.5);
    }
    
    .cartridge > .top {
        box-sizing: border-box;
        position: absolute;
        content: "";
        top: -8px;
        left: 0;
        background-color: #848086;
        height: 10px;
        box-shadow:
            inset 0 1px 1px rgba(255, 255, 255, 0.6);
        width: 90%;
    }
    
    .cartridge > .arrow {
        box-sizing: border-box;
        content: "";
        position: absolute;
        left: 60px;
        bottom: 4px;
        width: 19px;
        height: 12px;
        border-top: 1px solid rgba(0, 0, 0, 0.3);
    }
    
    .cartridge > .arrow:before, .cartridge > .arrow:after {
        content: "";
        width: 14px;
        height: 0;
        border-top: 1px solid rgba(255, 255, 255, 0.3);
        position: absolute;
        top: 4px;
    }
    
    .cartridge > .arrow:before {
        transform: rotate(45deg);
        -webkit-transform: rotate(45deg);
        left: -2px;
    }
    
    .cartridge > .arrow:after {
        transform: rotate(-45deg);
        -webkit-transform: rotate(-45deg);
        left: 7px;
    }
    
    .cartridge > .inset {
        content: "";
        position: absolute;
        bottom: 20px;
        left: 15px;
        height: 92px;
        width: 110px;
        box-sizing: border-box;
        border-radius: 3px;
        box-shadow:
            0 1px 1px rgba(255, 255, 255, 0.5),
            inset 0 1px 1px rgba(0, 0, 0, 0.5);
        padding: 2px;
    }
    
    .cartridge > .inset > .label {
        width: 100%;
        height: 100%;
        background: linear-gradient(top,
                                    rgba(200, 200, 200, 1.0),
                                    rgba(170, 170, 170, 1.0));
        background: -moz-linear-gradient(top,
                                         rgba(200, 200, 200, 1.0),
                                         rgba(170, 170, 170, 1.0));
        background: -webkit-linear-gradient(top,
                                            rgba(200, 200, 200, 1.0),
                                            rgba(170, 170, 170, 1.0));
        text-align: center;
        border-radius: 1px;
        box-shadow: inset 0 0 2px rgba(255, 255, 255, 0.4);
        position: relative;
    }
    
    .cartridge > .inset > .label > .title {
        position: absolute;
        top: 40px;
        font-size: 6px;
        text-transform: uppercase;
        font-family: Helvetica;
        width: 106px;
        text-align: center;
    }
    
    .cartridge > .inset > .label > .title.left {
        transform: rotate(-90deg);
        -webkit-transform: rotate(-90deg);
        left: 45%;
    }
    
    .cartridge > .inset > .label > .title.right {
        transform: rotate(90deg);
        -webkit-transform: rotate(90deg);
        left: -45%;
    }
    
    .cartridge > .inset > .label > img {
        height: 100%;
    }
    
    .cartridge > .edge {
        box-sizing: border-box;
        position: absolute;
        bottom: 0;
        width: 4px;
        height: 86px;
        border-top: 1px solid rgba(255, 255, 255, 0.3);
    }
    
    .cartridge > .edge.left {
        left: 0;
        background: linear-gradient(left,
                                    rgba(0, 0, 0, 0.4),
                                    rgba(0, 0, 0, 0.2));
        background: -moz-linear-gradient(left,
                                         rgba(0, 0, 0, 0.4),
                                         rgba(0, 0, 0, 0.2));
        background: -webkit-linear-gradient(left,
                                            rgba(0, 0, 0, 0.4),
                                            rgba(0, 0, 0, 0.2));
    }
    
    .cartridge > .edge.right {
        right: 0;
        background: linear-gradient(right,
                                    rgba(0, 0, 0, 0.4),
                                    rgba(0, 0, 0, 0.2));
        background: -moz-linear-gradient(right,
                                         rgba(0, 0, 0, 0.4),
                                         rgba(0, 0, 0, 0.2));
        background: -webkit-linear-gradient(right,
                                            rgba(0, 0, 0, 0.4),
                                            rgba(0, 0, 0, 0.2));
    }
    
    .cartridge > .lines {
        box-sizing: border-box;
        position: absolute;
        width: 100%;
        height: 30px;
        top: 6px;
        left: 0;
        overflow: hidden;
    }
    
    .cartridge > .lines > .bar {
        box-sizing: border-box;
        position: absolute;
        width: 20px;
        height: 4px;
        box-shadow:
            0 1px 1px rgba(255, 255, 255, 0.5),
            inset 0 1px 1px rgba(0, 0, 0, 0.5);
    }
    
    .cartridge > .lines > .bar.left {
        left: -4px;
    }
    
    .cartridge > .lines > .bar.right {
        right: -4px;
    }
    
    .cartridge > .lines > .bar.one {
        top: 0;
    }
    
    .cartridge > .lines > .bar.two {
        top: 7px;
        width: 16px;
    }
    
    .cartridge > .lines > .bar.three {
        top: 14px;
        width: 16px;
    }
    
    .cartridge > .lines > .bar.four {
        top: 21px;
    }
    
    .cartridge > .lines > .bar.left.one,
    .cartridge > .lines > .bar.right.four {
        transform: skew(-55deg);
    }
    
    .cartridge > .lines > .bar.left.two,
    .cartridge > .lines > .bar.right.three {
         transform: skew(-12deg);   
    }
    
    .cartridge > .lines > .bar.left.three,
    .cartridge > .lines > .bar.right.two {
        transform: skew(12deg);
    }
    
    .cartridge > .lines > .bar.left.four,
    .cartridge > .lines > .bar.right.one {
        transform: skew(55deg);
    }
    

    Generally, I find the overall result fairly pleasing and, adding a few tweaks for Game Boy Color cartridges games helps keep things playful:

    Charging The Dash

    I recently acquired The Dash from Bragi. They're a great pair of headphones and a fantastic first product from Bragi, modulo all the usual Kickstarter caveats1.

    One of the many features of The Dash is the ability to load music directly onto the headphones themselves – they mount as a USB mass storage device when plugged into a computer and adding music is simply a matter of dragging-and-dropping unencrypted music files.

    As useful as this is, it's far more common that I simply wish to charge my headphones when plugging them into MacBook Pro. Since OS X helpfully auto-mounts USB mass storage volumes, I find myself with many of these when I'm done charging:

    Fortunately, it's possible to disable auto-mounting in OS X on a per-disk basis by tweaking your fstab; Wolf Paulus has a great post describing the basics of how to do this. The technique described relies on using the Volume UUID to identify the device but, since The Dash don't appear to have a Volume UUID, it's necessary to filter using the Volume Label instead2:

    #                                                                                      
    # Warning - this file should only be modified with vifs(8)                             
    #                                                                                      
    # Failure to do so is unsupported and may be destructive.                              
    #                                                                                      
    LABEL=THE\040DASH none msdos rw,noauto 0 0
    

    Remember to use vifs to modify your fstab, instead of editing it directly:

    $ sudo vifs
    

    1. Over-promise and under-deliver. In the case of The Dash, some of the additional functionality such as fitness tracking (and even voice calling) doesn't yet work as advertised.
    2. Thanks to Johannes WeiƟ for his suggestion and guidance.