[Job] Help create the Windows version of Framer – React developer in Amsterdam

TL;DR: Framer are looking for a React developer based in Amsterdam to create the Windows version of the app with help from my team. Apply here.

Framer is only available on OSX

One of the things that annoy me the most is operating system dependence. It is frustrating to see a great new tool you want to use but it isn’t available on your platform. Not everyone can afford Apple hardware or wants to do everything in Windows or Android. I personally use several operating systems and it annoys me that I can’t use the same tool stack. Instead you need to learn different ones for each OS (Keynote/Powerpoint anyone?). It feels like the 90s.

That’s why I was happy when Framer contacted me and asked me to help them find someone to work on the Windows version of their great tool. The great news is that you’re not only going to work for a cool company. You also get to work directly with our team here to ensure that the port is going to be a great product. At Microsoft we have a dedicated team helping people to port apps. This team has deep insight into what to do and what to avoid to create an app that takes advantage of the things Windows 10 offers.

So, if you are:

  • A React Native developer who wants to build a great, well-used app for a big community
  • Have Windows experience and supporting more than Chrome/OSX in your WebView
  • Look for a full-time position in Amsterdam, The Netherlands

Apply now, and we can soon bridge another support gap that that is well over-due.

This is a short time offer, Framer are looking to hire someone ASAP and bring out the Windows version within a few months. The new Framer version is close to Alpha release internally.

View full post on Christian Heilmann

VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

Using mozjpeg to Create Efficient JPEGs

The mozjpeg project recently released version 2.1. It aims to improve the efficiency of JPEG encoding over existing encoders while maintaining compatibility with the vast majority of existing decoders.

I’d like to explain how you can use this software to reduce the size of your JPEGs. Specifically, I’m going to go over usage of mozjpeg’s cjpeg command line utility.

Building mozjpeg

There are no official mozjpeg binaries available, so you’ll have to build the project from source. Do this by downloading the source code for the latest release and following the instructions in the file BUILDING.txt.

Building on Linux and OS X is quite easy. Things are a little more complicated on Windows, but it’s still relatively easy. The mozjpeg project is considering providing binary releases in the future.

When you build mozjpeg you’ll produce a command line tool called cjpeg. This is the encoding program that comes with mozjpeg. The decoder is called djpeg.

Input Image Formats

The cjpeg tool is capable of handling the following input file types: targa, bmp, ppm, and jpg.

The ability to take JPEG files as input is a new feature in mozjpeg which doesn’t yet exists in the cjpeg tools provided by other projects. It was added to make re-compression workflows easier. Instead of converting JPEGs to BMP or something else and then re-encoding them, you can just pass the JPEG directly to the cjpeg encoder.

If you want to create a JPEG from a file type not supported by cjpeg, take a look at the ImageMagick tools. They include a command-line utility called convert that can convert back and forth from many types of images.

Basic Usage of the cjpeg Command Line Tool

Most people who use mozjpeg’s cjpeg use it in its simplest form:

$ cjpeg -quality 80 foo.jpg > bar.jpg

This will create a JPEG called “foo.jpg” from the “foo.bmp” input file at quality level 80. cjpeg directly emits the contents of the resulting JPEG file, so if you want to write it to disk, which you probably do, you’ll need to pipe the results to a file with ‘>‘.

Selecting a Quality Level

Quality can range from 0 at the low end to 100 at the high end. Most people will want to pick quality a value somewhere between 60 and 90. You’ll want to use the lowest value that still produces and image at a quality you’re happy with, because lower values will produce images with smaller file sizes.

The following image shows an original image as well as the same image encoded at five different quality levels with mozjpeg’s cjpeg. Click on it to enlarge.

JPEG Quality Comparison

Here are the image files one-by-one:

(Image courtesy of Soulmatesphotography, via Wikimedia, Creative Commons Attribution-Share Alike 3.0 Unported License)

Do some experimenting here. Lots of people don’t, and they miss out on significant reductions in file size. Their thinking is often something along the lines of “80 seems like a good compromise, and I hear that’s what most people do, so I’ll do that.” If you can’t tell the difference between an image at quality 77 vs 80, and you’re using 80, you’re missing out on significant file size savings at no cost to you in terms of quality.

Progressive vs. Baseline JPEGs

The mozjpeg version of cjpeg produces progressive JPEGs by default because their file sizes tend to be about 4% smaller than baseline JPEGs. Progressive JPEGs can appear at full size but blurry at first, and then progress to full resolution as the image downloads. Baseline JPEGs simply load from top to bottom.


(Image courtesy of Soulmatesphotography, via Wikimedia, Creative Commons Attribution-Share Alike 3.0 Unported License)

If you want to produce a baseline JPEG, you can do so like this:

$ cjpeg -baseline -quality 80 foo.jpg > bar.jpg

Targeting Metrics

A cool feature of mozjpeg’s cjpeg is that you can optimize for any of four specific quality metrics: PSNR, PSNR-HVS-M, SSIM, and MS-SSIM. These metrics are algorithms that calculate the quality of an image compared to the original. More scientifically, this is often referred to as a distortion rate.

These algorithms differ in how they define quality, so optimizing for one metric can hurt performance on another. See the July 2014 lossy compressed images study from Mozilla for many example of what this looks like.

mozjpeg tunes for PSNR-HVS-M by default, because tuning for this does pretty well on all metrics.

If you or your organization have decided that you trust a particular metric more than the others, you can tell mozjpeg’s cjpeg tool about your preference and it will tune for that metric.


Hopefully at this point you know enough to confidently start making use of mozjpeg to optimize your JPEGs. If you run into any issues, please report them on mozjpeg’s github issue tracker.

View full post on Mozilla Hacks – the Web developer blog

VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

Create Add-ons for Australis to Win a Firefox OS Phone

Firefox 29 (“Australis”) includes significant design and customization improvements, and we’re challenging you to create add-ons that look and feel great in it.

Between March 11 – April 15, 2014, create add-ons that take full advantage of the new design, which opens up new customization opportunities and streamlines the add-on experience in your browser. A panel of judges will pick one winner and two runners-up from each prize category.

All winners will receive Firefox OS phones, and the first-prize winners in each category will also receive a collection of Mozilla gear.

The Categories

  • Best overall add-on – an add-on that best makes use of the new Australis features, like the new toolbar widgets and tab appearance.
  • Best complete theme – a complete theme that most creatively alters the look and feel of Australis.
  • Best bookmark add-on – an innovative bookmarking add-on that works well with the Australis theme.

Add-ons in Australis

In order to create great entries for this contest you will need to know what’s new in Australis. Following is a quick summary of what we’ve been publishing in the Add-ons Blog.


The toolbars have changed significantly in Australis. The Add-on Bar at the bottom has been removed, and instead there is a new menu panel that extends the toolbar with buttons and widgets. It is activated by clicking on the button at the right end of the main toolbar. All the items in this new menu are customizable and it’s possible to add add-on buttons and widgets to it as well.

The icons in the main toolbar are 18×18 pixels. However, a 1px padding is expected, so the 16×16 pixel icons you should be using for the main toolbar in modern versions of Firefox will work without any changes. Icons are 32×32 pixels in the menu panel and also during customization. So, if you have an add-on that adds a toolbar button to the main toolbar using the usual guidelines of overlaying the button to the palette and then adding it to the toolbar using JS on first run, everything should work the same and you should only change your CSS to something like this:

/* Original CSS */
#my-button {
  list-style-image: url(“chrome://my-extension/skin/icon16.png”);
/* Added for Australis support */
  toolbarpaletteitem[place="palette"] > #my-button {
  list-style-image: url(“chrome://my-extension/skin/icon32.png”);

Note that buttons in the Australis theme have the cui-areatype attribute set when placed in in the UI. The possible values are menu-panel and toolbar. You can use the toolbar value to have different style for the button in Australis and non-Australis themes.

Australis for Add-on Developers: Part 1 contains more details.

New Customization API

Another exciting addition to Australis is the ability to create toolbar widgets using the CustomizableUI module. You will be able to easily create simple buttons and more interesting widgets with very little code, both for restartless and more conventional add-ons. Here’s a sample:

    id : "aus-hello-button",
    defaultArea : CustomizableUI.AREA_NAVBAR,
    label : "Hello Button",
    tooltiptext : "Hello!",
    onCommand : function(aEvent) {
      let win =;

Australis for Add-on Developers: Part 2 demonstrates how to leverage this API with two demos and plenty of code to play with.

Get Started!

View full post on Mozilla Hacks – the Web developer blog

VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

This developer wanted to create a language selector and asked for help on Twitter. You won’t believe what happened next!

Hey, it works for Upworthy, right?

Yesterday in a weak moment Dhananjay Garg asked me on Twitter to help him with a coding issue and I had some time to do that. Here’s a quick write-up of what I created and why.

Dhananjay had posted his problem on StackOverflow and promptly got an answer that wasn’t really solving or explaining the issue, but at least linked to W3Schools to make matters worse (no, I am not bitter about the success of either resource).

The problem was solved, yes (assignment instead of comparison – = instead of === ) but the code was still far from efficient or easily maintainable which was something he asked about.

The thing Dhananjay wanted to achieve was to have a language selector for a web site that would redirect to documents in different languages and store the currently selected one in localStorage to redirect automatically on subsequent visits. The example posted has lots and lots of repetition in it:

function english()
function french()
  window.location.href = "french.html";
window.onload = function() {
if (localStorage.language === "Language")
   window.location.href = "language.html";
else if (localStorage.language === "English")
   window.location.href = "eng.html";
else if (localStorage.language === "French")
  window.location.href = "french.html";
else if (localStorage.language === "Spanish")
  window.location.href = "spanish.html";

This would be done for 12 languages, meaning you’ll have 12 functions all doing the same with different values assigned to the same property. That’s the first issue here, we have parameters on functions to avoid this. Instead of having a function for each language, you write a generic one:

function setLanguage(language, url) {
 	localStorage.language = language;
 	window.location.href = url;

Then you could call for example setLanguage(‘French’, ‘french.html’) to set the language to French and do a redirect. However, it seems dangerous to clear the whole of localStorage every time when you simply redefine one of its properties.

The onload handler reading from localStorage and redirecting accordingly is again riddled with repetition. The main issue I see here is that both the language values and the URLs to redirect to are hard-coded and a repetition of what has been defined in the functions setting the respective languages. This would make it easy to make a mistake as you repeat values.

A proposed solution

Assuming we really want to do this in JavaScript (I’d probably do a .htaccess re-write on a GET parameter and use a cookie) here’s the solution I came up with.

First of all, text links to set a language seem odd as a choice and do take up a lot of space. This is why I decided to go with a select box instead. As our functionality is dependent on JavaScript to work, I do not create any static HTML at all but just use a placeholder form in the document to add our language selector to:

<form id="languageselect"></form>

Instead of repeating the same information in the part of setting the language and reading out which one has been set onload, I store the information in one singular object:

var locales = {
    'us': {label: 'English',location:'english.html'},
    'de': {label: 'German',location: 'german.html'},
    'fr': {label: 'Français',location: 'french.html'},
    'nl': {label: 'Nederlands',location: 'dutch.html'}       

I also create locale strings instead of using the name of the language as the condition. This makes it much easier to later on change the label of the language.

This is generally always a good plan. If you find yourself doing lots of “if – else if” in your code use an object instead. That way to get to the information all you need to do is test if the property exists in your object. In this case:

if (locales['de']) { // or - the bracket allows for spaces
	console.log( // -> "German"

The rest is then all about using that data to populate the select box options and to create an accessible form. I explained in the comments what is going on:

// let's not leave globals
  // when the browser knows about local storage…
  if ('localStorage' in window) {
    // Define a single object to hold all the locale 
    // information - notice that it is a good idea 
    // to go for a language code as the key instead of
    // the text that is displayed to allow for spaces
    // and all kind of special characters
    var locales = {
        'us': {label: 'English',location:'english.html'},
        'de': {label: 'German',location: 'german.html'},
        'fr': {label: 'Français',location: 'french.html'},
        'nl': {label: 'Nederlands',location: 'dutch.html'}       
    // get the current locale. If nothing is stored in 
    // localStorage, preset it to 'en'
    var currentlocale = window.localStorage.locale || 'en';
    // Grab the form element
    var selectorContainer = document.querySelector('#languageselect');
    // Add a label for the select box - this is important 
    // for accessibility
    selectorContainer.innerHTML = '<label for="languageselectdd">'+
                                  'Select Language</label>';
    // Create a select box 
    var selector = document.createElement('select'); = 'language'; = 'languageselectdd';
    var html = '';
    // Loop over all the locales and put the right data into 
    // the options. If the locale matches the current one,
    // add a selected attribute to the option
    for (var i in locales) {
      var selected = (i === currentlocale) ? 'selected' : '';
        html += '<option value="'+i+'" '+selected+'>'+
    // Set the options of the select box and add it to the
    // form
    selector.innerHTML = html;
    // Finish the form HTML with a submit button
    selectorContainer.innerHTML += '<input type="submit" value="go">';
    // When the form gets submitted…
    selectorContainer.addEventListener('submit', function(ev) {
      // grab the currently selected option's value
      var currentlocale = this.querySelector('select').value;
      // Store it in local storage as 'locale'
      window.localStorage.locale = currentlocale;
      // …and redirect to the document defined in the locale object
      alert('Redirect to: '+locales[currentlocale].location);
      //window.location = locales[currentlocale].location;
      // don't send the form
    }, false);

Surely there are different ways to achieve the same, but the important part here is that an object is a great way to store information like this and simplify the whole process. If you want to add a language now, all you need to do is to modify the locales object. Everything is maintained in one place.

View full post on Christian Heilmann

VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

Lightning talk: Five tools to create visuals for presentations

I am currently in Toronto, Canada at a work-week of the websites and developer engagement team in Mozilla. We’re organising a lot of things, plan and also share. In the lightning talk round I got up to share five tools I use to create visuals for presentations.
The tool guitar

The screencast is available on YouTube.

The tools in detail are:

  • LiceCap is a very simple tool to create animated GIFs from parts of the screen simply by selecting it and hitting a record button.
  • Showterm is a recording tool for the command line
  • YouTube Download is a script to download YouTube videos on the command line. This can be used to download creative commons videos for editing later. There are quite a few Browser add-ons available, that do the same but these are more dodgy as many of them inject ads into the YouTube page.
  • Miro Converter is a video converter allowing you to create videos optimised for several platforms and devices
  • MPEG Streamclip is a simple video editing tool.
  • Droid@Screen allows you to connect an Android phone via USB and show it on screen or take screencasts of it. It is good to show things but bad for showing performance as it is low-FPS.

These are just a few tools that make my life easier, all of them are free to use, so hopefully they are useful for you, too.

View full post on Christian Heilmann

VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)