remy sharp's b:log http://remysharp.com About [code] and all that jazz Sat, 31 Dec 2011 19:28:19 +0000 http://wordpress.org/?v=2.7.1 en hourly 1 http://creativecommons.org/licenses/by-nc-sa/2.0/uk/ My 2011 http://remysharp.com/2011/12/31/my-2011/ http://remysharp.com/2011/12/31/my-2011/#comments Sat, 31 Dec 2011 17:13:47 +0000 Remy Sharp http://remysharp.com/?p=930
  • A Public MIT License Resource
  • Ellis Tennyson Sharp
  • 2010: The Year I'll Never Forget
  • ]]>
    It's now a bit of a tradition with a year end blog post (almost entirely so I can look back and actually remember myself!), so today I post my summary of 2011 and what's happened for me both in my work and personally.

    In short, this year has still been hard after losing Tia in August 2010 but as painful as that is, happiness arrived as a bundle we decided to call Ellis Tennyson Sharp. Pretty much everything else falls away compared to family, as much as I love my work, I hope it will remain a distant second to those most important around me.

    Professional

    On that note though, I'll start with what I've been up to in the web world.

    Speaking

    I was again fortunate enough to be invited to speak at a real variety of conferences - some micro events like Aral's Geek Ninja to larger events like OSCON.

    I was also asked back to Flash on the Beach (I had to pull out last year) which was a real pleasure. The event is run in Brighton, and John Davey is possibly one of the nicest people I know (whom I'm convinced is actually just a British John Wayne). For a conference that has a strong Flash following the audience were particularly welcoming, and even sang me happy birthday!

    Personally however, my favourite conference of 2011 was Highland Fling. It was organised and run in the same spirit as Full Frontal which left me excited and inspired. I'm a big fan of the indie events and if the organiser is full of passion it stands to reason that it just oozes out in to the day. Highly recommend, and if it's on again in 2012, it's a damn fine excuse to visit Scotland again.

    Remy - Photo by Drew McLellan

    Photo by Drew McLellan

    Workshops

    I'd been considering whether I could pull off a "workshop tour" towards the end of 2010, and early on in the year, Julie helped me pull it off. We ran six workshops in five cities over two weeks: Brighton, Manchester, Bristol, London and Nottingham. Amazingly the project was a success both from the teaching, but the business side too. There's a lot of risk involved in trying to sell multiple workshops at once but in the last weeks leading up to the workshops, they managed to sell out.

    I also ran my first two-dayer on Node for Full Frontal - something I'll be running again a few times this year, so if you're interested in be notified, drop me a message.

    Projects

    When I list out these projects that I've released, more often than not I think: damn, I wish I'd done more. But on the other hand, I could have done a lot less - or kept them to myself. So hopefully these are useful to someone as well as me!

    • Inliner - a tool to "inline the crap" out of web sites, inlining CSS, images, fonts and JavaScript, compressing as much as possible. Also available as a command line tool.
    • responsivepx - a tool for testing and finding breaking points in responsive design.
    • Introducing HTML5 2nd Edition - somehow Bruce and I managed to pull off a 2nd edition, packed with new info and even a new chapter on polyfills.
    • mit-license - a public resource to host your own MIT-License under your own name, eg. rem.mit-license.org (more)
    • jsconsole remote support - I got fed up with the insane debugging techniques and poor console support in mobile smart phones - so I tweaked jsconsole so it could do exactly that!
    • Full Frontal 2011 - another year and (if I don't say so myself) a another huge success. It was an amazing day and to my surprise folks were even telling me that it was the best year yet. So, no pressure for 2012!

    Randomly aside, I was nominated to have my face happy-webbie-fied amongst 60-odd others. Somehow in the voting rounds it end up me, so the kind folks at nGen Works have now immortalised me as a cartoon character - very neat :)

    Remy Sharp's happy webbie

    Personal

    The year was still hard after losing Tia last year. Julie and I decided early that we still wanted to continue with our family, and the new year we would try for our second. Ellis was conceived much quicker than either of us hoped - one of the many blessings we had with Smudge's pregnancy (as we saw Ellis in a 7 week scan, his nickname came from what he resembled most: a smudge!).

    Julie delivered Ellis Tennyson Sharp on 29-September 2011 at 11:14am - safely and happily into the arms of his parents. An absolutely amazing day. As tough as it's been, both a mix of emotions as we never had this with Tia, but also the physical side of things, like dealing with an upset human being whose communication skills are rather limited. As tough as that's been, Ellis is so insanely cute that what he cracks a smile all the stresses are forgotten and I can't help but be amazed.

    Ellis with Tia's bear

    Just a month before Ellis was born was Tia's first birthday. In the year leading up to that date we started a local project in her name to improve a local children's park. We've raised a little over £3,000 for the project and there's more we want to do to improve the area for children (though half the money raised goes to SANDS - a charity for bereaved parents). I also had Tia's hand print tattooed on to me permanently so I can always keep her near.

    Both Julie and I celebrated 15 years of being together and completed our second year of 365 project - which our plan is to create a single canvas print with two years of 365 picture - so that should be epic!

    Utterly unrelated, but I built a Death Star this Christmas too - too cool not to include in my round up - definitely going to be doing more Lego next year!

    2012?

    I'm hoping to build my business up. I always wanted to grow my little agency to around 6 people. Obviously I need the business in place before I go along employing people, so if there's some JavaScript (both client and server side) project that you need an A-team on the case - do get in touch!

    Otherwise, I'm hoping do more of the same, more blogging, more project, continue with our 365 - but more importantly: spend as much time as I can with my family.

    Here's to 2012, cheers!

    Related posts:

    1. A Public MIT License Resource
    2. Ellis Tennyson Sharp
    3. 2010: The Year I'll Never Forget

    ]]>
    http://remysharp.com/2011/12/31/my-2011/feed/ http://creativecommons.org/licenses/by-nc-sa/2.0/uk/
    I like Instagram, but it's not as open as I'd like it to be http://remysharp.com/2011/12/10/i-like-instagram-but-its-not-as-open-as-id-like-it-to-be/ http://remysharp.com/2011/12/10/i-like-instagram-but-its-not-as-open-as-id-like-it-to-be/#comments Sat, 10 Dec 2011 12:35:53 +0000 Remy Sharp http://remysharp.com/?p=915
  • Ellis Tennyson Sharp
  • What is Silverback?
  • Upgraded jQuery Tag Suggestions
  • ]]>
    So here's how I got around that, and how I'm using Instagram today.

    I always held off installing Instagram because I felt it was another black hole to post my pictures to and friends and family viewing my pictures used Flickr.

    When I visited Portland earlier in 2011, Petra showed me indeed it could automatically post to Flickr - so I was quickly convinced. Instagram is indeed a fun app. But...

    It's still a black hole

    When I post using the Instagram, I tick the "twitter" and "flickr" options. The problem I have is the tweet points to Instragram. If you want to comment or favourite the picture: you can't. You need the app.

    This is how I'm experimenting with a service called ifttt (stands for If This, Then That - basically: really visual webhooks).

    Using ifttt to open Instagram

    Here's the process:

    1. I post a picture using Instagram, but I don't tick the "twitter" or "flickr" buttons anymore
    2. ifttt takes newly posted pictures and cross-posts them to Flickr where it uses the title and tags it using "instagram"
    3. Another ifttt recipe looks for Flickr pictures tagged with "instagram" and posts to Twitter for me using the short flickr url.

    These are the two simple recipes I use: remy's recipes

    Now if someone without the Instagram app (which includes most of my family) can comment or favourte the picture. Those users of Instagram still see the picture and can still comment inside the silo system that the Instagram app provides. Aside from the image duplication (and really I see the Instagram picture as the copy) I'm pretty happy with this new process.

    Related posts:

    1. Ellis Tennyson Sharp
    2. What is Silverback?
    3. Upgraded jQuery Tag Suggestions

    ]]>
    http://remysharp.com/2011/12/10/i-like-instagram-but-its-not-as-open-as-id-like-it-to-be/feed/ http://creativecommons.org/licenses/by-nc-sa/2.0/uk/
    A Public MIT License Resource http://remysharp.com/2011/10/18/a-public-mit-license-resource/ http://remysharp.com/2011/10/18/a-public-mit-license-resource/#comments Tue, 18 Oct 2011 12:00:19 +0000 Remy Sharp http://remysharp.com/?p=879
  • Twitpic API for getting pictures out
  • ]]>
    Pretty much every personal project I work on I try to make it publicly available - usually under an MIT license - but I pretty much always forget to include an MIT license file.

    There's an Open Source Initiative with the license, but it doesn't have the date, nor the license holder. So I've released mit-license.org - a public, open source permanent resource for MIT license for you.

    I am now pointing all of my new projects at http://rem.mit-license.org.

    The mit-license project works by looking at the CNAME on the host, and if a matching user JSON file is found, it will serve up the MIT license for that individual.

    For instance, the file users/rem.json contains:

    {
      "copyright": "Remy Sharp, http://remysharp.com",
      "url": "http://remysharp.com"
    }
    

    So http://rem.mit-license.org works and displays the correct information (note that the year shown will always update to the current year too).

    The project is up on GitHub and can be forked to add your own information and to reserve your own host. Just send a pull request along and I'll pull it in and you're sorted - no more remembering to include the MIT file in your projects.

    Version targeting

    If you're worried that the license content might change in future versions, you can also target a specific version committed in the git repository.

    This can either be done directly on the url using the commit SHA or you can include the version in your JSON file (which would probably be easier).

    For example, http://rem.mit-license.org/a526bf7ad1 is the same as having a users/rem.json file that contains:

    {
      "copyright": "Remy Sharp, http://remysharp.com",
      "url": "http://remysharp.com",
      "version": "a526bf7ad1"
    }
    

    Of course without the SHA you'll always be on the latest license file (which I doubt will change).

    Fork and send a pull request

    The project is sitting on GitHub here: https://github.com/remy/mit-license and I'm trying to merge in pull requests as quickly as they come in so your url becomes live right away.

    There's also a few more details on the readme in the GitHub project too.

    Related posts:

    1. Twitpic API for getting pictures out

    ]]>
    http://remysharp.com/2011/10/18/a-public-mit-license-resource/feed/ http://creativecommons.org/licenses/by-nc-sa/2.0/uk/
    Ellis Tennyson Sharp http://remysharp.com/2011/10/17/ellis-tennyson-sharp/ http://remysharp.com/2011/10/17/ellis-tennyson-sharp/#comments Mon, 17 Oct 2011 13:00:58 +0000 Remy Sharp http://remysharp.com/?p=869
  • In memory of Tia
  • My 2011
  • 2010: The Year I'll Never Forget
  • ]]>
    September 29 2011, at 11:14am Ellis Tennyson Sharp graced us with his arrival and said hello to his mummy and daddy.

    Arrival

    Ellis was delivered by elective caesarean section because of losing Tia during labour last year, and in the theatre I was able to hand my camera to a nurse and told her it'll take 2,000 pictures, just point and shoot. That's what she did and she caught some amazing moments.

    I love these two pictures, the first literally seconds after Ellis was born, and the next: mother's hands reaching to hold her son for the first time.

    Ellis being delivered

    Ellis being delivered

    On fatherhood

    Ellis has been eagerly awaited over the last year. After losing his big sister last year he meant a lot to a lot of people - none more so than our family.

    My primary job has been changing nappies, and it's funny because before Ellis (and Tia) was born both Julie and I joked about who should change them. Dealing with poo seems like a crappy job. But as soon as I had the little guy in my arms, changing him is second nature. Moreover, it's my time with him - sometimes we do an F1 nappy change (my best time currently 4 minutes), and other times we spend ages chatting and gurgling (him gurgling more so than me!).

    It's definitely a complicated time emotionally, but I know that Ellis brings us happiness - even if we're utterly clueless as to why he cries sometimes!

    It's all made a lot easier as he's cute as hell:

    Ellis Sharp

    My family

    This is my family now. Below Ellis sleeps on my chest. His hands still smaller than Tia's, who is etched in me permanently. Seeing them like this makes me sad, but also so proud of my family and makes me so thankful of everything they give me in my life.

    I am a very proud man.

    My children

    Related posts:

    1. In memory of Tia
    2. My 2011
    3. 2010: The Year I'll Never Forget

    ]]>
    http://remysharp.com/2011/10/17/ellis-tennyson-sharp/feed/ http://creativecommons.org/licenses/by-nc-sa/2.0/uk/
    Rich text input on iOS http://remysharp.com/2011/10/10/rich-text-input-on-ios/ http://remysharp.com/2011/10/10/rich-text-input-on-ios/#comments Sun, 09 Oct 2011 23:18:53 +0000 Remy Sharp http://remysharp.com/?p=860
  • jQuery tutorial: Text box hints
  • maxlength plugin
  • Auto input grow with CSS (but is it a bug?)
  • ]]>
    Rich text input is difficult on any platform, but I discovered a rather cheeky, but simple trick to give you rich text inputs on iOS.

    The way a number of rich text input libraries work (like CodeMirror and Ace), is that when you're typing, you're typing in to a tiny, almost hidden, textarea. This value is then echoed and rendered using styled spans and the like creating a rich mirror of your input. Of course the editors are much more complicated than that - but our iOS technique follows this idea really closely.

    Basically, in iOS if you set an input or textarea to have an opacity of zero, you can't see it (obviously!). However when you focus the element, the cursor is fully visible.

    Also, selection still work, though it only shows the selection colour and block, not the text.

    Example of rich text selection in iOS

    So what we do is sit a textarea on top of a div, listen for keyup, and take the value in the textarea, run it through a parser to get something syntax highlighting and place the rendered HTML under the textarea. This gives the illusion that we have a rich text input element.

    You could use this trick to allow the user to select and highlight certain parts of a document - just like you can in the mobile version of google docs in edit mode.

    Here's a demo that you can try out on an iOS device, which when you type will syntax highlight the code: example rich text input for iOS

    Finally, if you want to learn more about mobile development, my conference Full Frontal, is running a full 2 day masterclass with the lord of mobile: PPK, so check it out (including ticket to the conference & exclusive dinner with the workshop teachers).

    Related posts:

    1. jQuery tutorial: Text box hints
    2. maxlength plugin
    3. Auto input grow with CSS (but is it a bug?)

    ]]>
    http://remysharp.com/2011/10/10/rich-text-input-on-ios/feed/ http://creativecommons.org/licenses/by-nc-sa/2.0/uk/
    On changing my avatar http://remysharp.com/2011/08/23/on-changing-my-avatar/ http://remysharp.com/2011/08/23/on-changing-my-avatar/#comments Tue, 23 Aug 2011 16:36:01 +0000 Remy Sharp http://remysharp.com/?p=839
  • Twivatar, a Twitter avatar API
  • I like Instagram, but it's not as open as I'd like it to be
  • 2010: The Year I'll Never Forget
  • ]]>
    I joined twitter around early 2007 and during those early months I toyed with a number of different avatars. At some point I settled on the avatar I have now - just a quick snap of me in front of my desktop.

    However, as the years went on, I got chubbier, I usually sport a light beard and I have longer hair. When people meet me in reality they quickly realise I don't look like my avatar.

    So I changed it and it worked badly against me.

    Disclaimer: sorry folks, this is a very me post, I'm not mad on them - but really it's here because I'll forget in another 3 years, and this post will be a reminder of why I don't change my mugshot too often!

    I've tweeted around 14,000 messages. That's not to say it's alot, but people following me have a certain unspoken agreement with me: I'll tweet about tech and a few personal things, and they'll recognise me as the guy in the white tee.

    It doesn't really matter what my avatar looks like, but what I had done, without realising, is create a brand around my own name, and my brand image was my avatar. This is marketing 101 to most people, but I'm just a developer, and I wanted to update my avatar to represent myself a little more honestly.

    It's like salt & vinegar vs. cheese & onion. Walkers, some time ago, used to have salt & vinegar in blue packets and cheese & onion in green. Some point along my life they swapped the colours. Ever since I'd always grab the wrong packet if I didn't carefully read the packaging.

    By changing my avatar to what is mostly white, pink and black, to a mostly dark colours, when I tweeted announcing my new workshop tour project, I couldn't work out why the reception was so poor. Then I realised: most folks didn't spot my tweet because it came from a brand they didn't recognise. My tweet was filtered out as noise via the native RT in twitter because folks didn't recognise me - rightly so.

    So I changed it back within 24 hours of changing my avatar.

    The lesson here is that, even without knowing it, nor actively trying to do it, we're creating a brand, and on twitter our brand is our avatar. That doesn't mean you can't change it - I've heard of some people who constantly change their avatar, but that's their brand - it just means if you use twitter for both personal and business, just be careful to maintain a consistent appearance.

    Almost 6 months later, I've tried again, this time I'm going to try to stick to it. I've purposely tried to keep the position of my head and the shapes in the image the same as the previous image, but it's not easy - old face just ain't the new thing it used to be!

    Remy 2008 Remy 2011

    Related posts:

    1. Twivatar, a Twitter avatar API
    2. I like Instagram, but it's not as open as I'd like it to be
    3. 2010: The Year I'll Never Forget

    ]]>
    http://remysharp.com/2011/08/23/on-changing-my-avatar/feed/ http://creativecommons.org/licenses/by-nc-sa/2.0/uk/
    Antisocial spaces on Twitter http://remysharp.com/2011/08/02/antisocial-spaces-on-twitter/ http://remysharp.com/2011/08/02/antisocial-spaces-on-twitter/#comments Tue, 02 Aug 2011 11:00:53 +0000 Remy Sharp http://remysharp.com/?p=829
  • Linkify + upgrade to twitter plugin
  • Trailing white space in TextMate
  • Autocomplete & even better twitter keys
  • ]]>
    Hopefully this doesn't become a meme instead of what I intend for this blog post. There's a way to consume at @reply timeline in Twitter by just stuffing a shed load of new lines with anything at the end (like a period).

    If you're a twitter app developer, please consider removing multiple white space in row. Twitter web client does this already (apparently so does echofon - so I think it's worth support the consistent tweet structure.

    What I did

    Here's a few screenshots to give you an idea of what I did, and how it looked.

    On Twitter for Mac

    On Tweetbot

    On twitter.com

    The fixes

    twitter.com are simply doing a replace on repeated new lines (in fact they're converted to spaces) and spaces. However, it looks like they're not stripping all types of white space, i.e. em-spaces, and no-breaking spaces still remain.

    Although I know this breaks formatting for new lines - which I know full well some people want to retain - I'd really like to see the twitter app developers removing these multiple white spaces, because I'm sure some folk might start exploiting it.

    Don't say I didn't warn you!

    Related posts:

    1. Linkify + upgrade to twitter plugin
    2. Trailing white space in TextMate
    3. Autocomplete & even better twitter keys

    ]]>
    http://remysharp.com/2011/08/02/antisocial-spaces-on-twitter/feed/ http://creativecommons.org/licenses/by-nc-sa/2.0/uk/
    input range polyfill http://remysharp.com/2011/07/18/input-range-polyfill/ http://remysharp.com/2011/07/18/input-range-polyfill/#comments Mon, 18 Jul 2011 12:00:24 +0000 Remy Sharp http://remysharp.com/?p=811
  • Rich text input on iOS
  • Auto input grow with CSS (but is it a bug?)
  • Auto-populating Select Boxes using jQuery & AJAX
  • ]]>
    During The Highland Fling (an excellent conference by the way - highly recommend), James Edwards aka Brothercake was talking about the graceful degradation of HTML5 Web Form elements, in particular the input range type.

    He points out that degrading to text isn't graceful at all, because with a range, you have predefined options. Much like a select box.

    In the wild

    In the last week I've worked on two small projects of which both needed a slider aka range element. In one the user gives a rating to an item, 1 - 5. In the second, the user slides from a scale from 10 to 3000.

    With <input type=range> the apps looked great. Then I opened them in Firefox 5 and iOS 4.x and there's no range, but a text box. Not useful at all.

    Good thing that during James' Q&A session at The Highland Fling I wrote the solution he was describing :)

    Jack watching me code

    Solution

    Instead of the input range, you use a select with a type attribute of range. In that select you offer the options the user can select (in the case of my problem 10-3000, actually I wanted them to chose device widths, so the options were 10, 320, 340, 420, etc for various device widths).

    For a rating, here's what you'd have without JavaScript:

    <select data-type="range" name="rating"> 
      <option>1</option> 
      <option>2</option> 
      <option>3</option> 
      <option>4</option> 
      <option>5</option> 
    </select>
    

    After the DOM is ready, my range polyfill kicks in, and upgrades our select elements with data-type=range to an input range type only if the browser supports it. My code tries to replicate all the attributes from the select element, class, id, etc. It will read the first and last options and use those as the min and max, and then read the selected value and use that as the initial value.

    The code

    You can download it from here: range.js

    Here's a live example using the range.js code: http://jsbin.com/atocep/11/edit

    I've included the range.js script in my polyfills github repo, so if you find a bug do help yourselves to contributing too.

    I've changed the search for the select to look for data-type="range" instead of type="range" - for those validation junkies out there :)

    Related posts:

    1. Rich text input on iOS
    2. Auto input grow with CSS (but is it a bug?)
    3. Auto-populating Select Boxes using jQuery & AJAX

    ]]>
    http://remysharp.com/2011/07/18/input-range-polyfill/feed/ http://creativecommons.org/licenses/by-nc-sa/2.0/uk/
    link elements block DOM parsing too http://remysharp.com/2011/06/08/link-elements-block-dom-parsing-too/ http://remysharp.com/2011/06/08/link-elements-block-dom-parsing-too/#comments Wed, 08 Jun 2011 08:53:12 +0000 Remy Sharp http://remysharp.com/?p=792
  • Performance profiling JavaScript
  • Wiki to HTML using JavaScript
  • How to detect when an external library has loaded
  • ]]>
    Today we're pretty well versed with how JavaScript works. We know that script elements block rendering (well, actually blocks the parsing, which thus delays the rendering), and we know why8. Sure, so we put the script elements at the end of the document. But did you know that link elements block too?

    * document.write can affect the DOM tree, so the parsing makes sure these happen synchronously

    Sure I did, so what?

    In the past it wasn't likely that you would include an externally linked CSS asset, but that's changed today. Today we have services providing fonts, at that point you're linking to an external service from your head element (because we put CSS in the head, and script at the end of the body).

    If that service hangs for whatever reason, it'll hang your page too. Something we've spent a long time in the JavaScript community working to avoid, and now we risk repeating ourselves.

    Why does this happen?

    What's a little frustrating is that I can completely understand why a script element would block parsing the DOM (and thus block rendering), but I can't see why an external stylesheet would.

    Perhaps it's because we could include dynamic content via CSS - but I doubt it. Dynamic content doesn't actually appear in the DOM tree, so I'd guess that it's not blocking the parsing process. So what else could it be? Suggestions in the comments please!

    Perhaps this is a bug? Safari, Chrome and Firefox suffer from this issue. Opera doesn't (but then, does it also block on JavaScript - I have a feeling it doesn't). I didn't test IE (partly because I was sure it would, partly because I didn't want to start my VM - if someone could confirm, that would be super).

    Right now, I'm not sure what's at the root cause, but I do know it's putting some web sites at risk.

    Updated 12-June 2011 after further investigation by zcorpan (aka Simon Pieters) and Stepan Reznikov (via their comments below), what we're actually seeing is render blocking, and not parsing blocking.

    However, it does, from looking at tests, block JavaScript after the hanging link element from running - which is definitely weird.

    There's two example for you - both need the console open: hang example where content ready fires before CSS has loaded, hang example where script waits for CSS before it can run

    Example

    This url will show the hanging: http://jsbin.com/agumu4/3/ - make sure you have a web console open and refresh to watch the state change.

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset=utf-8 />
    <title>Hang test</title>
    <script>
    // script in head to debug state change
    console.log('doc state: ' + document.readyState);
    
    document.onreadystatechange = function () {
      console.log('doc state change: ' + document.readyState);
    };
    </script>
    <link href="http://hang.nodester.com/hang.css?5000" rel="stylesheet" />
    </head>
    <body>
      <p>Hello World</p>
    </body>
    </html>
    

    Testing

    I've created a simple hanging service that you can reuse yourself. It's running on Node so there's no worry of nuking the machine due to the hang (as opposed to using PHP to test using a sleep - which would nuke a public machine).

    To test include the following url: http://hang.nodester.com/file.type?ms

    i.e. http://hang.nodester.com/foo.css?2000 will return a file with a CSS mime type and hang for 2000 milliseconds.

    The best way to determine when the DOM is loaded (or loading) when you can't see the output is to listen for the readystatechange event (ht). So in my test, I've included some script that tells me where the DOM is up to, and I can visually confirm whether the link element is hanging.

    What about font includes?

    I also tested including hanging fonts via CSS, i.e. if you copied the @font-face declarations, but the font service was down: this does not hang the page. However, you do suffer from the FOUC, but that's a whole different issue.

    The fix

    As per anything that hangs: do it asynchronously to the DOM rendering - or rather after the DOM has done most, if not all of the parsing. That is, to use JavaScript to insert the link element once the DOM - or rather content is ready. Here's a simple example: http://jsbin.com/agumu4/4 - note that the readystate says it's still loading, that's because my DOM doesn't fully load when the JavaScript appends the link element (i.e. it doesn't wait for an event, it's just at the bottom of the document).

    Related posts:

    1. Performance profiling JavaScript
    2. Wiki to HTML using JavaScript
    3. How to detect when an external library has loaded

    ]]>
    http://remysharp.com/2011/06/08/link-elements-block-dom-parsing-too/feed/ http://creativecommons.org/licenses/by-nc-sa/2.0/uk/
    In memory of Tia http://remysharp.com/2011/06/06/in-memory-of-tia/ http://remysharp.com/2011/06/06/in-memory-of-tia/#comments Mon, 06 Jun 2011 12:27:05 +0000 Remy Sharp http://remysharp.com/?p=779
  • 2010: The Year I'll Never Forget
  • Ellis Tennyson Sharp
  • My 2011
  • ]]>
    When Tia was born last year, through the pain of losing her, Julie and I promised ourselves that something good must come of this tragedy. In recent months we have been working on Tia's Trees - a project to improve our local park joined to a children's centre, as a memorial to our baby girl.

    During Phase One, with friends and family, we managed to plant over 100 new trees and shrubs (photos, some just baby trees and some more developed. This phase is now complete, but we hope the work won't stop there.

    As part of Phase Two we aim to install new benches in time for the summer to make the park more accessible and more comfortable for local families. Further phases have been planned with the support of the local council, and we expect this project to last a number of years.

    We have set up a fundraising page where donations go 50% to the Tia's Trees project and 50% to SANDS - the UK charity that provide support to families who have lost their babies.

    If you wished to donate, Julie and I would really appreciate it:

    http://www.virginmoneygiving.com/tiastrees

    It's been the hardest time of our lives, but I know that the support that has come out from family, friends and the web community has been truly overwhelming. We've been touched by messages people have sent us, and the thoughts spared for our family and Tia.

    We'll never get over losing our baby girl, but we get stronger with each day and somehow, with time, we have managed to start our lives again creating a new normal and now almost fully re-entered the real world.

    Thank you for all your support.

    Related posts:

    1. 2010: The Year I'll Never Forget
    2. Ellis Tennyson Sharp
    3. My 2011

    ]]>
    http://remysharp.com/2011/06/06/in-memory-of-tia/feed/ http://creativecommons.org/licenses/by-nc-sa/2.0/uk/
    My Big Workshop Tour http://remysharp.com/2011/04/27/my-big-workshop-tour/ http://remysharp.com/2011/04/27/my-big-workshop-tour/#comments Wed, 27 Apr 2011 14:26:14 +0000 Remy Sharp http://remysharp.com/?p=773
  • Creative HTML5 and JavaScript workshop by @seb_ly
  • Big Three Oh - happy birthday to me!
  • Our London to Brighton bike ride and route
  • ]]>
    Last year, a few months before Julie and I were due with Tia, I thought about running a workshop tour. Something where I could offer the web community training, whilst simultaneously seeing more of our grand postage stamp of a country. Here's why and the plan, and I want your input.

    Aim #1 accessible to the Community

    Phase 1 of the project was to canvas the community, you folks, as to where I should bring my workshops. I knew I could run them in Brighton again (since I live here) and I was pretty confident I could sell the workshops in London, but really, after taking part in events like Speak the Web I wanted to also be able to take the workshops beyond London for a change. Give the northern (and other) communities the chance to not travel so damn far for training.

    Phase 2 was selling the tickets, and I had talked with friends and colleagues about how to price the workshops for some time, and I didn't want to run these workshops for the usual prices (anywhere from £400 upwards for a full day).

    At some point I was considering whether I could run the workshops for free, but that was eventually ruled out because a) it would have devalued the workshops entirely, b) some people would book a ticket, but wouldn't come, c) probably most importantly to me - I simply couldn't afford to do it. I am my business. There's no big corporation behind me, so during the time I'm doing public speaking or training, I'm not drumming up business at home.

    I also looked at sponsorship, but in the end, decided that I could run the workshops for about half price at £200 each, and hopefully this would open these up to the freelancers and much smaller companies.

    The real challenge has actually been getting the word out to freelancers and companies out in those cities you folks suggested I come train in.

    Aim #2 travel around our fair land

    This is where I need a bit of your help. Julie, the star that she is, has planned the route that we'll take when visiting each city. But I wanted to get feedback from you folks as to what we absolutely must see in those cities and on our route. What should we be taking pictures of? Where should we make sure we stop to take in a view? Which places are special to you?

    So with that, here's our route plan with dates and locations:

    • 5-May: Brighton HTML5 Workshop (book now)
    • 7-May: Liverpool
    • 8-May: Manchester
    • 9-May: Manchester HTML5 Workshop (book now)
    • 10-May: Manchester jQuery for Designers Workshop (book now)
    • 11-12-May: Peak district
    • 13-May: Nottingham Node Workshop (book now)
    • 14-May: Much Wenlock via Ashby de la Zouch
    • 15-May: Drive through Shropshire and Herefordshire
    • 16-May: Forest of Dean
    • 17-May: Bristol
    • 18-May: Bristol jQuery for Designers Workshop (book now)
    • 20-May: London Node Workshop (sold out)

    I'd love to hear your feedback on the project idea, if you want to come along - grab a ticket because you're running out of time! Otherwise - what is it that we should absolutely see if we're in your city or passing by?

    Related posts:

    1. Creative HTML5 and JavaScript workshop by @seb_ly
    2. Big Three Oh - happy birthday to me!
    3. Our London to Brighton bike ride and route

    ]]>
    http://remysharp.com/2011/04/27/my-big-workshop-tour/feed/ http://creativecommons.org/licenses/by-nc-sa/2.0/uk/
    Getting CORS Working http://remysharp.com/2011/04/21/getting-cors-working/ http://remysharp.com/2011/04/21/getting-cors-working/#comments Thu, 21 Apr 2011 09:44:47 +0000 Remy Sharp http://remysharp.com/?p=761
  • Stop treating Ajax as something special
  • What is JSONP?
  • How I achieved cross site scripting
  • ]]>
    Recently I ran a workshop where I ran a small section of the workshop on CORS and how to enable it. In the past, I've found it to be very easy but this time around everything backfired and it didn't work. So after the workshop I went about understanding why the CORS demo it didn't work, and how to get it working.

    Disclaimer: other people have explained this before, this post is mostly for me!

    CORS?

    Cross Origin Resource Sharing - i.e. cross domain Ajax. The technical side of getting CORS to work has been explained in a lot more detail by Nicholas C. Zakas in his article Cross-domain Ajax with Cross-Origin Resource Sharing, (i.e. IE8, for reasons beyond most, use XDomainRequest - utterly bespoke - but that's Microsoft for you).

    Simple CORS

    CORS, if you're not doing anything clever is easy. The client side should just be the following code (assuming we're not IE - see link above for IE hoop jumping):

    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'http://different-domain.com');
    xhr.onreadystatechange = function () {
      if (this.status == 200 && this.readyState == 4) {
        console.log('response: ' + this.responseText);
      }
    };
    xhr.send();
    

    So just a simple XHR send - in fact, exactly the same with the exception that the url goes to a domain that's different to the origin.

    The only thing you need to have on your different-domain.com server is an additional header that tells the browser it's okay to go cross domain. In PHP that header looks like this:

    <?php
    header('Access-Control-Allow-Origin: http://www.some-site.com');
    ?>
    

    Equally, if you want to make the API public to anyone to access, you can use:

    <?php
    header('Access-Control-Allow-Origin: *');
    ?>
    

    As simple live example of this can be seen here: jsbin.com/oxiyi4 which makes a request to remysharp.com/demo/cors.php which includes a rule that allows any origin to access the resource.

    This is simple and easy. However, it's the preflight that causes confusion. That's where it all went wrong for me.

    Preflight

    In plain Remy language preflight is an additional request the XHR object makes to make sure it's allowed to actually make the request.

    By default, there's no preflight, so why was this a problem for me?

    Setting custom headers on XHR requests triggers a preflight request.

    Detecting Ajax on the server

    Most JavaScript libraries send a custom header in the XHR request which can be sniffed on the server side to allow us to simple detect an Ajax request:

    <?php
    $ajax = isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 
            $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
    
    if ($ajax) {
      // handle specific Ajax differently...
    }
    ?>
    

    This way my server side code handles regular traffic differently to Ajax traffic.

    When I manually set the x-requested-with header on the XHR object, it triggered the preflight, which is where it all hit the fan.

    Handling the preflight x-requested-with

    The request process, with a preflight, if successful should look like the follow request exchange (note that I've stripped some headers that weren't pertinent to this article, like User-Agent, etc).

    This is a real request from one domain to place an XHR request for http://jsbin.com/canvas/73/source.

    Client sends XHR request with custom header:

    OPTIONS /canvas/73/source HTTP/1.1
    Host: jsbin.com
    Access-Control-Request-Method: GET
    Origin: http://jsconsole.com
    Access-Control-Request-Headers: x-requested-with
    

    Server responds to OPTIONS request (no content served in this case):

    HTTP/1.1 200 OK
    Access-Control-Allow-Origin: *
    Access-Control-Allow-Headers: X-Requested-With
    

    Client sends GET request as it has permission to do so:

    GET /canvas/73/source HTTP/1.1
    Host: jsbin.com
    x-requested-with: XMLHttpRequest
    

    Server responds to GET request with content:

    HTTP/1.1 200 OK
    Access-Control-Allow-Origin: *
    Content-Length: 977
    

    This only works, because my server side is specifically looking out for the OPTIONS request, and handling it as you'll see in my following server code.

    Server code to handle prelight

    The following PHP code simply checks for the OPTIONS request method. If OPTIONS has been used to make the request, and the user is requesting using CORS, my server responds saying that the X-Requested-With header is permitted:

    // respond to preflights
    if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
      // return only the headers and not the content
      // only allow CORS if we're doing a GET - i.e. no saving for now.
      if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']) && $_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'] == 'GET') {
        header('Access-Control-Allow-Origin: *');
        header('Access-Control-Allow-Headers: X-Requested-With');
      }
      exit;
    }
    

    Now the XHR CORS request allows the X-Requested-With header, the rest of my code remain in place, and the flag to indicate it's an Ajax request if the X-Requested-Header is present works as it did before.

    Avoid preflight if possible

    Jumping through these hoops was pretty tricky, and only after I solved this puzzle did I breakout Wireshark for packet sniffing - which might have helped to debug the whole issue in the first place.

    Funnily enough, when making a CORS request using jQuery, the JavaScript library specifically avoids setting the custom header, along with a word of warning to developers:

    // For cross-domain requests, seeing as conditions for a preflight are akin to a jigsaw puzzle, we simply never set it to be sure.

    So possibly the best advice, if possible, is to avoid setting the custom header if you don't want to do the preflight dance. Otherwise good luck my friend, I hope this has helped!

    Related posts:

    1. Stop treating Ajax as something special
    2. What is JSONP?
    3. How I achieved cross site scripting

    ]]>
    http://remysharp.com/2011/04/21/getting-cors-working/feed/ http://creativecommons.org/licenses/by-nc-sa/2.0/uk/
    Broken Offline Support http://remysharp.com/2011/04/19/broken-offline-support/ http://remysharp.com/2011/04/19/broken-offline-support/#comments Tue, 19 Apr 2011 18:07:20 +0000 Remy Sharp http://remysharp.com/?p=748
  • Simple Offline Application
  • jQuery API Update: offline and anywhere
  • Tweet offline & better locations
  • ]]>
    The state of offline detection in desktop browsers is broken and it needs to fixed or at least get better, but I can't see this happening unless we push against the browser vendors to fix this.

    Currently, as of April 2011, offline and online events are broken, as is the navigator.onLine property. The only exception appears to be WebKit/MobileSafari on mobile (though I've only successfully tested Android's 2.3.3 and iOS 4.3). Here's the test url: jsbin.com/otudo5 (source)

    Browsers support these events, don't they?

    All the browsers support these events...in a way. In fact, even IE has good broken support for these events for a long time now (pre-IE7?).

    When the browser goes in to an offline mode, it'll fire the offline event. This is currently supported in Opera, IE and Firefox. When the offline event fires, it switches navigator.onLine to read false.

    So if this is the state of support, what am I getting my knickers in a twist for? How they get in to "offline mode" is the problem.

    Work Offline

    The browsers I've listed to having an offline mode, only trigger the event when the end user decides to hit the "file" menu and then select the "Work Offline" menu item.

    This is not the way this event should work, and it needs to be fixed.

    If I'm sat on a train, with a 3G connection to the web, and I run through a black spot of connectivity, I expect the offline event to fire, indicating to the web app that I'm using to run offline. As a developer, I need to be able to handle this event.

    Do we really need the event?

    Actually, no, but it's misleading to developers to see these events in the HTML5 spec. At the very minimum we need navigator.onLine to work properly.

    There is no situation in Safari & Chrome (i.e. WebKit) that you can get navigator.onLine to return false - that's pretty darn broken.

    Could we do without these events?

    I think so.

    It would seem to be easier to drop these events from the specification and only support navigator.onLine properly. The problem with the events is that they need something to poll, somewhere to check for connectivity. Polling isn't great, and I can understand that. Equally, what do you poll? A service could go down. Sure Google probably isn't ever going to go down...but it might.

    How important is it to suddenly announce to the user of your web app "OMG, YOU DON'T HAVE THE INTERNETS!"? I think it's more appropriate to handle a user initiated activity that requires the Internet with a test against navigator.onLine (where the offline appcache doesn't already handle the process for us).

    It should be straight forward to change navigator.onLine to run a blocking test for connectivity.

    I've managed to write something similar for Chrome that polyfills navigator.onLine:

    navigator.__defineGetter__('onLine', function () {
      // test the connection using try/catch with XHR 
      var onLine = false;
      // make sync-ajax request
      var xhr = new XMLHttpRequest();
      // phone home
      xhr.open('HEAD', '/', false); // async = false
      try {
        xhr.send();
        onLine = true;
      } catch (e) {
        // throws NETWORK_ERR when disconnected
        onLine = false;
      }
    
      return onLine
    });
    

    The reason the polyfill doesn't work with the other browsers is because they either don't throw a NETWORK_ERR on the XHR request when the network is down (This is part of the XHR spec, so that's broken too), or in Safari's case, you can't overload the onLine property.

    If my XHR hack worked in the other browsers, I wouldn't be so frustrated with browser support for these events. But it doesn't fully work, so now the only alternative is to call for browsers to fix their offline event and/or navigator.onLine support.

    If you work for a browser vendor, please can you get some eyes on this issue. We developers want to build apps that work correctly without the web to run on your browser, so help us to make it the best it can be.

    Related posts:

    1. Simple Offline Application
    2. jQuery API Update: offline and anywhere
    3. Tweet offline & better locations

    ]]>
    http://remysharp.com/2011/04/19/broken-offline-support/feed/ http://creativecommons.org/licenses/by-nc-sa/2.0/uk/
    Simple Offline Application http://remysharp.com/2011/01/31/simple-offline-application/ http://remysharp.com/2011/01/31/simple-offline-application/#comments Mon, 31 Jan 2011 15:18:13 +0000 Remy Sharp http://remysharp.com/?p=718
  • Broken Offline Support
  • HTML 5 - what caught my eye
  • TextMate Tagging with Simple Tagging
  • ]]>
    I've written my fair share of single file applications. All the JavaScript and CSS are inline, and if I'm feeling particularly ninja, I'll base64 encode the images, and make them inline too.

    To make the whole thing completely available offline is insanely easy, and reusable to boot.

    The first step is to add the manifest attribute to the html element:

    <html manifest="self.manifest">
    

    In this case we've got a file called self.manifest which is pretty simple. It contains the following:

    CACHE MANIFEST
    

    Yep, that's it. Since the application cache automatically includes the file that references the manifest file, we've now got an offline application cache for our single file app.

    Make sure you're serving the manifest file correctly, if you're not sure, check out the HTML5 Doctor introduction to offline applications, but otherwise, that's it.

    When I went away this last week, I wrote a little Boggle clone, and wanted it work offline on the plane - so I added this technique to the single file app (it's only the board and a countdown, not interactive).

    Dirt simple, but totally reusable!

    Note: the manifest file is subject to the same-origin rule, in that you can't point the manifest attribute to something like http://simpleapp.com/self.manifest. Equally, you can't base64 encode the manifest file as some people have asked in the comments - that would be really awesome!

    Related posts:

    1. Broken Offline Support
    2. HTML 5 - what caught my eye
    3. TextMate Tagging with Simple Tagging

    ]]>
    http://remysharp.com/2011/01/31/simple-offline-application/feed/ http://creativecommons.org/licenses/by-nc-sa/2.0/uk/
    Creative HTML5 and JavaScript workshop by @seb_ly http://remysharp.com/2011/01/12/creative-html5-and-javascript-workshop-by-seb_ly/ http://remysharp.com/2011/01/12/creative-html5-and-javascript-workshop-by-seb_ly/#comments Wed, 12 Jan 2011 16:18:19 +0000 Remy Sharp http://remysharp.com/?p=714
  • How to detect if a font is installed (only using JavaScript)
  • Win a ticket for the Full Frontal JavaScript Conference
  • JavaScript Style - why it's important
  • ]]>
    This week I had the pleasure of attending Seb Lee-Delisle's Creative HTML5 and JavaScript workshop and even as someone who classes themselves as an expert JavaScripter (I hope!), I still learnt tons.

    To me, Seb has gone through it all when he was developing for Flash years ago. Things like building 3D in a 2D environment, optimising methods and getting to know the faking techniques and tricks to make something appear awesome without turning your computer in to a smouldering wreck after the CPU melted the thing to the ground!

    In my humble opinion, the "open web" community are now going through the same process with canvas and other HTML5-esque technologies. So why not learn from what Seb and others have already been through? This is why I wanted to attend Seb's workshop, and if he runs it again, I'd recommend you do the same if you're not familiar with visual programming techniques.

    What we built

    The two day workshop broke in to segments around drawing, vectors, particles, simple 3D and using Three.js.

    By the end of day one we had all the components to build a working Asteroids game. Which I glued together that evening by myself (note that most of these components are Seb's with a few of my own tweaks and glueing) - full screen/iPad version also working online:

    Click the canvas above to focus it and control the ship to play and double click to respawn your ship.

    The second day we upgraded from 2D to 3D and to close the day, we asked Seb to build a 3D version of Asteroids. Clearly he wasn't going to completely finish developing the game, but it was fun (and impressive) to see the building blocks being put together. He got to the point where there we asteroids flying towards him, the ship was controlled by the mouse and had some eased effects to give it a more tactile feel, and he had bullets/laser beams firing at the asteroids - all very cool, and not far off a ready game:

    Seb's 3D asteroids

    Notes from the day

    By way of brain dump, and so that I've got a record of the stuff I need to remember somewhere, here's just list of bits that I picked up throughout the day. Obviously there was tons more, but when you're coding, listening, learning and wrapping your head around trig (something that I'm quite useless at) - less notes are taken ;-)

    Canvas

    • When using colours: HSL's where it's at! Here's some help: http://mothereffinghsl.com
    • Remember subpixels drawing, by default you draw between pixels, Mark Pilgrim explains: http://diveintohtml5.org/canvas.html#pixel-madness
    • When using beginPath, unless you do moveTo the first use of lineTo will actually move, and not draw a line, i.e. if you do a lineTo without a start, it only moves (in fact because there's no starting point).
    • Rotating a canvas rotates around the origin, which by default is top, left. To move the origin of the canvas, use translate.
    • save/restore state the drawing style and affects coordinate system - this useful for rotating the canvas drawing, and then resetting the rotation.

    For an animation the (pseudo) code looks like this:

    var mouseX = 0, mouseY = 0, mouseDown = false, keys = {};
    setup(); // initalisation
    setInterval(loop, 1000 / 60); // 60 fps
    
    function loop() {
      // 1. handle key or mouse states
      // 2. update position of animated objects: particles, etc
      object.update();
      // 3. draw each object
      object.draw();
    }
    
    // capture events, but don't do anything with them
    document.addEventListener('mousemove', function (e) {
      mouseX = e.pageX;
      mouseY = e.pageY;
    }, false);
    

    Vectors

    • Pythagoras can be used to determine whether a point (like a click) is inside an circle drawn on a canvas. However, it requires Math.sqrt which is costly, so instead of using Pythagoras to workout hit testing (for length of vector) - compare the distanced squared:

    Instead of:

    var distance = Math.sqrt((this.diff.x * this.diff.x) + (this.diff.y*this.diff.y));
    return (distance<this.radius);
    

    Use:

    var distanceSq = (this.diff.x * this.diff.x) + (this.diff.y*this.diff.y);
    return (distanceSq < this.radius * this.radius)
    

    3D

    Collision detection in 3D:

    var distanceSq3D = (this.diff.x * this.diff.x) + (this.diff.y*this.diff.y) + (this.diff.z * this.diff.z)
    return (distanceSq3D < this.radius * this.radius)
    
    • To calculate the new x and y in a 3D space, you need to multiply them by a scale which is worked out from: f/(f+z) = newscale (note that f the field of view - like the zoom on a camera)
    • To scale the 3D system properly, the origin must be in the centre of the canvas, this is key to getting the perspective correct: ctx.translate(ctx.canvas.width/2, ctx.canvas.height/2)
    • To rotate the y (the yaw), you rotate the y and z axis, which is exactly the same as the distribution code (below in the optimisation tricks), using sin and cos

    To get the z-order correct (painters algorithm), you need to sort by the z axis, where points is an array of objects with xyz:

    points = points.sort(function (a, b) {
      return a.z >= b.z ? -1 : 1;
    });
    
    • If the z is less than -fov (f, i.e. if f=250, and z=-250) it means the z position is behind you - so it should be removed

    Optimisation tricks

    • When removing an item (or deleted) - like bullets or asteroids, recycle the item: disable it when it's finished with, and add it to an array. Then when you want a new object, try to get it from the pool of spares first, otherwise create a new item.
    • Instead of having the keyboard interactivity interrupt the code and update values, track the key presses and check these in the render cycle process.
    • (Math.random() * 0xff) <<16 generates a random blue colour (0xff == 0x0000ff == blue), then shift 16 bits and we've now got a random red colour. We could equally get a random green using <<8.
    • When placing objects at a random position, if you use x = Math.random() * width (and similarly with y axis) the distribution creates a square shape, which looks odd. This is easy to fix, you create a circular distribution.

    To get a circular distribution, rotate around a circle using:

    x = Math.sin(angle) * speed; // sin for X
    y = Math.cos(angle) * speed; // cos for Y
    

    Related posts:

    1. How to detect if a font is installed (only using JavaScript)
    2. Win a ticket for the Full Frontal JavaScript Conference
    3. JavaScript Style - why it's important

    ]]>
    http://remysharp.com/2011/01/12/creative-html5-and-javascript-workshop-by-seb_ly/feed/ http://creativecommons.org/licenses/by-nc-sa/2.0/uk/
    2010: The Year I'll Never Forget http://remysharp.com/2010/12/31/2010-the-year-ill-never-forget/ http://remysharp.com/2010/12/31/2010-the-year-ill-never-forget/#comments Fri, 31 Dec 2010 12:42:11 +0000 Remy Sharp http://remysharp.com/?p=703
  • Goodnight 2009
  • Ellis Tennyson Sharp
  • My 2011
  • ]]>
    I've only managed to write up my thought on the previous years twice (2009, 2007), but this year was one of, if not the, most important year of my life.

    Professional

    The most important part of 2010 was in my personal life, but for the sake of remembering (this blog is primarily here because I forget stuff), here's what I got up in my professional life during 2010:

    Speaking

    I love speaking at conferences and although I had to pull out of a few this year, Flash on the Beach in particular, I had the honour of spreading the good word about HTML5 at a good number of conferences, giving an overview of JavaScript related APIs. As I look around conferences now, I get the distinct feeling that this talk will be redundant or maybe done to death by other speakers, so the plan is that in 2011 is to ditch this talk and try to go in a completely different direction to the other talks we're seeing. Hopefully this is something I can pull off - that's assuming I'm invited to speak again (yes, I'm just as insecure as everyone else!).

    I also got to run a number of workshops, including running the jQuery for Designers workshop for the mighty Andy Clarke and his For A Beautiful Web and HTML5 for @media and John Allsopp (equally mighty!). All of them so far have been a hit with the delegates, which leaves me chuffed to bits, and has encouraged me to run a special workshop project in 2011 - but more on that later.

    Remy talking - short isn't he?

    Projects

    The biggest (new) project was Introducing HTML5 with Bruce Lawson. What an honour to be asked to co-author the book with Bruce. It was a really good experience (although there were definitely some struggles with the editors ::grrr::) and all in all I'm actually rather proud of the book we put together. When I ask around November time, we had sold a "respectable" number of books so far.

    Covers of Introducing HTML5

    Then there was Full Frontal 2010. The first Full Frontal was such a big success, I was rather worried that this one would be extremely difficult to equal last years. Turns out: we did just fine. The conference was a huge success again, and again, that's no doubt down to the speakers and Julie's smooth running of the event. It's definitely happening again in 2011 - I just have to find seven more awesome speakers!

    Remy and Julie closing Full Frontal 2010

    Left Logic, my business, has also been doing well. This year I've done business with the likes of the BBC and Google - both of which are respectable clients, along with a fistful of other equally respectable clients. Right towards the end of the year I was asked to work on a couple of really exciting small projects. One I'm now sure won't make the light of day (sadly) the other should go live very early in the new year. No doubt I'll tweet about it come release day.

    Finally, I started working on a(nother) personal project called: Förbind. It's a real-time sockets service designed to make adding real-time easy as pie to your application. It's still very early days yet, but what's exciting to me, aside from the socket side, is the fact the entire application is written in JavaScript on top of Node. Something to keep my skills sharpened.

    Screenshot of Forbind

    Personal

    Little Tia Sharp

    This year was all about Tia for me. Julie fell pregnant at the end of 2009, and 2010 we watched together as our lives prepared to change. Except in the last moments, Tia was lost.

    She was born on 31st August 2010, we're both still grieving her loss now 4 months later - and I fully expect we will do for a long time to come. Each day comes with its own highs and lows and I'm seeing life through very different eyes than I did only a short while ago.

    I'm thankful for small mercies and even more so that Julie and I have remained strong together even in light of everything that's happened. I question all the time how people can wander around so oblivious of life, and how incredible fragile it all is. Equally I know that we can't spend our lives focusing on this, and that we need to move forward through life. Like I said, I'm seeing things differently lately.

    Slowly in the last month or so, some kind of new normality has begun. We've been able to leave our fortress (we spent a long time hiding at home in the early months), I've started to resume some work and we even occasionally laugh nowadays.

    I have to also say thank you to everyone who has listened and let us talk about our baby girl. The warmth and well wishes from family, friends and strangers alike has been overwhelming and it's given me a real belief that people are ultimately kind and loving. Something that's hard to notice in the normal day to day grind. I'm truly thankful and honoured that we have been in your thoughts. If I could hug you, I would be right now.

    Without turning this in to a monster post about my views on life and death, I'm still super proud of Julie and my little Tia. I'm still a proud father, even if I don't have Tia in the house, and I've promised myself that I'll be a better man in her name.

    For me, 2010 will always be Tia's year.

    Tia, our sleeping baby

    Related posts:

    1. Goodnight 2009
    2. Ellis Tennyson Sharp
    3. My 2011

    ]]>
    http://remysharp.com/2010/12/31/2010-the-year-ill-never-forget/feed/ http://creativecommons.org/licenses/by-nc-sa/2.0/uk/
    Audio Sprites (and fixes for iOS) http://remysharp.com/2010/12/23/audio-sprites/ http://remysharp.com/2010/12/23/audio-sprites/#comments Thu, 23 Dec 2010 14:03:48 +0000 Remy Sharp http://remysharp.com/?p=698
  • How to detect when an external library has loaded
  • Dynamic favicons
  • Rimshot with HTML5
  • ]]>
    I recently had to work on a project for iOS that required that sound play on particular actions being performed. The problem is that iOS and HTML5 has been seriously oversold by Apple and the devices are pretty poor in comparison to the desktop. Audio and video are particularly poor, so to solve my problem I used an audio sprite, a technique that was similar to CSS sprites, just for audio.

    The Problems

    I'll first explain some of the problems I encountered, because these issues are particular to iOS - but could be common to mobile devices.

    1. iPhones don't like playing too much audio at once, it gets very choppy.
    2. iPads don't play more than one audio stream at once. There's some good info on 24 Ways, in the State of Audio - Early Findings - sadly this was published after I discovered this for myself!
    3. iOS won't download the audio unless the user initiates the action.
    4. There's about a 1/2 second delay before iOS is able to play the audio - this is because the audio object (in iOS, not HTML5) is being created.

    Given some of these problems, multiple audio files wasn't going to solve my problem, so I needed to create a sprite for my audio and work with that in iOS.

    Audio Sprite

    If you think CSS sprite, just with audio, then you'll already know that each playable part of a sprite should be the same size. That said, you could program your app to have variable size sprites - but I just think it's easier to build and develop with if they're the same size.

    So if your audio is 1 second long, and you want 10 audio clips to play, you need a sprite that's 10 seconds long. Not rocket science.

    One thing I did notice: using Audacity to create the sprite, shifted all the audio. This may have been me messing things up, but it's something I consistently noticed, so I adjusted for it in the code using a lead time (something that's included in the final source code). Not ideal though, really you want each sprite to start on the 10s modulus 1s increment.

    Audio Sprite Track

    The concept of playing a sprite is simple. You pass the index of the audio you want to play, and the track moves the playhead to index times sprite length and starts playing. You also need to know when to stop the sprite, so that's the start time + sprite length, and there's a setInterval that's constantly watching for when to stop.

    Here's what the track code would look like (note that we've not fixed all the iOS issues yet):

    function Track(src, spriteLength) {
      var audio = document.createElement('audio');
    
      audio.src = src;
      audio.autobuffer = true;
      audio.load(); // force the audio to start loading...doesn't work in iOS
    
      this.audio = audio;
      this.spriteLength = spriteLength;
    }
    
    Track.prototype.play = function (position) {
      var track = this,
          audio = this.audio, // the audio element with our sprite loaded
          length = this.spriteLength, // the length of the individual audio clip
          time = position * length,
          nextTime = time + length;
    
      audio.pause();
      audio.currentTime = time;
      audio.play();
    
      // clear any stop monitoring that was in place already
      clearInterval(track.timer);
      track.timer = setInterval(function () {
        if (audio.currentTime >= nextTime) {
          audio.pause();
          clearInterval(track.timer);
        }
      }, 10);
    };
    

    Fixing the iOS issues

    The biggest problem with iOS is that the audio hasn't loaded at all. So when we try to set audio.currentTime = time a fatal JavaScript error will be thrown because the audio doesn't have that length loaded and all the code will go to crap.

    So we need to wrap it with a try/catch:

    try {
      audio.pause();
      audio.currentTime = time;
      audio.play();      
    } catch (e) {
      // what now?
    }
    

    But now we've wrapped it in a try/catch, what do we do? We could play the audio and keep try/catching to move the currentTime but the problem is that the audio will start playing in the wrong place.

    What we need to do is try to play the audio, and as soon as it has loaded the data for the audio, pause it, move to the right position and then start playing again. This is the tricky bit.

    From experimenting with iOS, I found that the progress event was the one that told me I had enough data to fast forward before the user heard any sound. I would have expected this to be canplay or canplaythrough - but alas, this is iOS and all is not what you'd expect!

    So if the catch in our code fires, we need to listen for the progress and then try to set the currentTime. So I'm changing the catch to this:

    try {
      audio.currentTime = time;
      audio.play();
    } catch (e) {
      track.updateCallback = function () {
        track.updateCallback = null;
        audio.currentTime = time;
        audio.play();
      };
      audio.play();
    }
    

    Now inside the Track object function, I've also adding the following code:

    var track = this;
    
    var progress = function () {
      audio.removeEventListener('progress', progress, false);
      if (track.updateCallback !== null) track.updateCallback();
    };
    
    audio.addEventListener('progress', progress, false);
    track.updateCallback = null;
    

    This means that we're listening for the progress event, and when it fires for the first time, we remove the handler, and if there's a callback, we'll call it. The progress is triggered by trying to play. So now we've got it jumping to the right point, but we still have the 1/2 second delay.

    That we're going to try to fix by preloading the audio secretly in the background. Since the audio can only be loaded when the user clicks, let's listen for that at the top level of the document and kick off the audio loading. However, the only way you can start the audio loading is by playing it. So that's what we'll do, but once the play event fires, we'll pause it right away to stop the audio from playing back, but forcing it to move on to the progress event.

    Again inside the new track object, we add the code to try to load the audio:

    var force = function () {
      audio.pause();
      audio.removeEventListener('play', force, false);
    };
    audio.addEventListener('play', force, false);
    
    var click = document.ontouchstart === undefined ? 'click' : 'touchstart';
    var kickoff = function () {
      audio.play();
      document.documentElement.removeEventListener(click, kickoff, true);
    };
    document.documentElement.addEventListener(click, kickoff, true);
    

    Now we're try to forcibly load the audio as early as possible, which will trigger the progress event, which in turn will allow us to set the currentTime correctly in our audio sprite.

    The completed code

    I've also implemented a simple player to allow you to utilise multiple tracks (something that works very well on the desktop) or you can use a single track object directly. The completed code, with a few more comments and attempts to mute the audio has been included in a gist: HTML5 audio sprites

    Related posts:

    1. How to detect when an external library has loaded
    2. Dynamic favicons
    3. Rimshot with HTML5

    ]]>
    http://remysharp.com/2010/12/23/audio-sprites/feed/ http://creativecommons.org/licenses/by-nc-sa/2.0/uk/
    Our Christmas Films List http://remysharp.com/2010/11/29/our-christmas-films-list/ http://remysharp.com/2010/11/29/our-christmas-films-list/#comments Mon, 29 Nov 2010 11:56:44 +0000 Remy Sharp http://remysharp.com/?p=694
  • Merry Chrimbo to all!
  • It ain't that Christmasy and there ain't no snow
  • Merry Chrimbo to you and to me
  • ]]>
    Each year, since 2006, Julie and I have planned a Christmas movie day, where we watch a day of Christmas spirited films whilst eating various Christmas type food (basically: volauvents). We have a rule that we can't watch the same film two years in a row, but we're secretly trying to watch different films each year. So here's where I ask you: what films are we missing?

    I'd love to know what one film we should watch, and why it's special to you. Either for memories, or it makes for a good film, or you watch it every year after the turkey's been finished and before the arguments over monopoly start.

    Here are the films we've watched over the years (and our plan for 2010):

    2006

    (And a few others that we forgot to take note of)

    2007

    2008

    2009

    2010

    2011

    We've decided we're allowing repeats this year, so here's the list:

    Future Potentials

    Again, what would you recommend, and why?

    Related posts:

    1. Merry Chrimbo to all!
    2. It ain't that Christmasy and there ain't no snow
    3. Merry Chrimbo to you and to me

    ]]>
    http://remysharp.com/2010/11/29/our-christmas-films-list/feed/ http://creativecommons.org/licenses/by-nc-sa/2.0/uk/
    Full Frontal T-shirts in Tia's name http://remysharp.com/2010/11/16/full-frontal-t-shirts-in-tias-name/ http://remysharp.com/2010/11/16/full-frontal-t-shirts-in-tias-name/#comments Tue, 16 Nov 2010 18:18:38 +0000 Remy Sharp http://remysharp.com/?p=684
  • Win a ticket for the Full Frontal JavaScript Conference
  • Going Full Frontal in one week
  • Full Frontal JavaScript Conference
  • ]]>
    Full Frontal 2010 ran last Friday and (as I secretly hoped) was a huge success. As with last year, we had a good number of people asking how they could get one of the Full Frontal t-shirts (as sported by yours truly). And this year we're giving the opportunity to get your hands on one, and 100% of proceeds will go to charity.

    Remy sporting Full Frontal t-shirtOn August 31st 2010, Julie and I lost our baby Tia and our world was turned upside down. We're far from "over it", so Full Frontal was a huge step for us, one that we had planned to be very different. Running the conference with Tia as a newborn baby was going to be one thing - but running it without her was something completely different.

    When we realised people wanted t-shirts, we twigged that we could auction the t-shirts off and raise money in Tia's name at the same time. So 100% of the proceeds will go to SANDS, a UK charity who both support parents in a similar situation to us but also promote research to reduce the loss of baby's lives.

    The listings end on Tuesday 23rd November around 5:30pm (UK time), and we're posting to both the UK, Europe and the US - so please do get involved with the auction and help raise some money for a good cause.

    The complete listing with current bids can be found here:

    http://shop.ebay.co.uk/remysharp/m.html

    And individual listings are here:

    Note that we've not placed the order for the t-shirts, so you'll be able to specific the sex and size of the t-shirt so that it fits just for you.

    Good luck.

    Related posts:

    1. Win a ticket for the Full Frontal JavaScript Conference
    2. Going Full Frontal in one week
    3. Full Frontal JavaScript Conference

    ]]>
    http://remysharp.com/2010/11/16/full-frontal-t-shirts-in-tias-name/feed/ http://creativecommons.org/licenses/by-nc-sa/2.0/uk/
    node.js rapid development: nodemon http://remysharp.com/2010/10/12/nodejs-rapid-development-nodemon/ http://remysharp.com/2010/10/12/nodejs-rapid-development-nodemon/#comments Tue, 12 Oct 2010 13:00:55 +0000 Remy Sharp http://remysharp.com/?p=661
  • How to setup your Mac web development environment
  • Slicehost, Node.js & WebSockets
  • Can't delete from the trash?
  • ]]>
    node.js is clearly the hottest thing since sliced bread, and recently I've been working on a larger project that runs as a node server.

    The problem I encountered was that, unlike a PHP based web app, whenever I made any changes to the code, I would have to manually stop and start node. This bugged me. So I created nodemon to make rapid dev a little easier.

    Install & usage

    You can install nodemon using npm (a node package manager) via:

    npm install nodemon
    

    Now nodemon will be available on the command line and can run your application, as such:

    nodemon server.js 8000
    

    Where server.js is my application and (in my case) 8000 is an argument to my app. Equally I could be running it with a debugger attached:

    nodemon --debug server.js 8000
    

    nodemon won't hide any of your application output, and doesn't require any changes to your existing application.

    What it does do?

    nodemon wraps your node application and sits quietly looking for file changes in the directory you ran nodemon from. That includes any sub-directories too. It's using the unix find command (so it's not available for Windows users right now, sorry), but this means that it's pretty quick to pick up changes.

    As soon as you save a file in any directory of your application, nodemon will restart your node app.

    What if I don't want it to restart?

    nodemon comes with the ability to ignore file patterns (regex's are supported thanks to @fearphage. So in my application, I've got a public directory used by express. Node doesn't need to be restarted for those static files (images, CSS, .less, etc). So I can tell nodemon to ignore anything in the public directory.

    nodemon will create an empty nodemon-ignore which you can add to (and here's a fuller example). So my nodemon-ignore would look like this:

    # ignore the static directory
    /public/*
    

    What I think it really neat about the ignore file, and has made my dev go pretty quickly, is this:

    At any time, you can edit the nodemon-ignore file, commenting out directories whilst you work on a larger change where lots of files might change. nodemon is watching for any changes to the ignore file, and if it does change, it automatically reloads the list of files and directories to ignore.

    Then you can uncomment the directory back in, nodemon reloads the ignore file and the next change it'll detect, it'll restart your app again - thus preventing lots of unnecessary restarts when you know you'll be breaking your app.

    What about if my app throws and error and breaks?

    nodemon will pause, echoing out the error and stack trace as you'd expect, and the next file change - i.e. when you find the culprit and fix him, nodemon will try to restart your app again.

    Bugs, feedback, etc

    If you've got any suggestions or bugs you spot, let me know via an issue and it should be quick to fix (it's a fairly simple script really).

    I'm already using it on one of my projects and it's let me just ignore the stop/start shenanigans whilst I get on with my coding, so at least it's already helping someone!

    Related posts:

    1. How to setup your Mac web development environment
    2. Slicehost, Node.js & WebSockets
    3. Can't delete from the trash?

    ]]>
    http://remysharp.com/2010/10/12/nodejs-rapid-development-nodemon/feed/ http://creativecommons.org/licenses/by-nc-sa/2.0/uk/