Mozilla

Articles

Sort by:

View:

  1. Generational Garbage Collection in Firefox

    Generational garbage collection (GGC) has now been enabled in the SpiderMonkey JavaScript engine in Firefox 32. GGC is a performance optimization only, and should have no observable effects on script behavior.

    So what is it? What does it do?

    GGC is a way for the JavaScript engine to collect short-lived objects faster. Say you have code similar to:

    function add(point1, point2) {
        return [ point1[0] + point2[0], point1[1] + point2[1] ];
    }

    Without GGC, you will have high overhead for garbage collection (from here on, just “GC”). Each call to add() creates a new Array, and it is likely that the old arrays that you passed in are now garbage. Before too long, enough garbage will pile up that the GC will need to kick in. That means the entire JavaScript heap (the set of all objects ever created) needs to be scanned to find the stuff that is still needed (“live”) so that everything else can be thrown away and the space reused for new objects.

    If your script does not keep very many total objects live, this is totally fine. Sure, you’ll be creating tons of garbage and collecting it constantly, but the scan of the live objects will be fast (since not much is live). However, if your script does create a large number of objects and keep them alive, then the full GC scans will be slow, and the performance of your script will be largely determined by the rate at which it produces temporary objects — even when the older objects aren’t changing, and you’re just re-scanning them over and over again to discover what you already knew. (“Are you dead?” “No.” “Are you dead?” “No.” “Are you dead?”…)

    Generational collector, Nursery & Tenured

    With a generational collector, the penalty for temporary objects is much lower. Most objects will be allocated into a separate memory region called the Nursery. When the Nursery fills up, only the Nursery will be scanned for live objects. The majority of the short-lived temporary objects will be dead, so this scan will be fast. The survivors will be promoted to the Tenured region.

    The Tenured heap will also accumulate garbage, but usually at a far lower rate than the Nursery. It will take much longer to fill up. Eventually, we will still need to do a full GC, but under typical allocation patterns these should be much less common than Nursery GCs. To distinguish the two cases, we refer to Nursery collections as minor GCs and full heap scans as major GCs. Thus, with a generational collector, we split our GCs into two types: mostly fast minor GCs, and fewer slower major GCs.

    GGC Overhead

    While it might seem like we should have always been doing this, it turns out to require quite a bit of infrastructure that we previously did not have, and it also incurs some overhead during normal operation. Consider the question of how to figure out whether some Nursery object is live. It might be pointed to by a live Tenured object — for example, if you create an object and store it into a property of a live Tenured object.

    How do you know which Nursery objects are being kept alive by Tenured objects? One alternative would be to scan the entire Tenured heap to find pointers into the Nursery, but this would defeat the whole point of GGC. So we need a way of answering the question more cheaply.

    Note that these Tenured ⇒ Nursery edges in the heap graph won’t last very long, because the next minor GC will promote all survivors in the Nursery to the Tenured heap. So we only care about the Tenured objects that have been modified since the last minor (or major) GC. That won’t be a huge number of objects, so we make the code that writes into Tenured objects check whether it is writing any Nursery pointers, and if so, record the cross-generational edges in a store buffer.

    In technical terms, this is known as a write barrier. Then, at minor GC time, we walk through the store buffer and mark every target Nursery object as being live. (We actually use the source of the edge at the same time, since we relocate the Nursery object into the Tenured area while marking it live, and thus the Tenured pointer into the Nursery needs to be updated.)

    With a store buffer, the time for a minor GC is dependent on the number of newly-created edges from the Tenured area to the Nursery, not just the number of live objects in the Nursery. Also, keeping track of the store buffer records (or even just the checks to see whether a store buffer record needs to be created) does slow down normal heap access a little, so some code patterns may actually run slower with GGC.

    Allocation Performance

    On the flip side, GGC can speed up object allocation. The pre-GGC heap needs to be fully general. It must track in-use and free areas and avoid fragmentation. The GC needs to be able to iterate over everything in the heap to find live objects. Allocating an object in a general heap like this is surprisingly complex. (GGC’s Tenured heap has pretty much the same set of constraints, and in fact reuses the pre-GGC heap implementation.)

    The Nursery, on the other hand, just grows until it is full. You never need to delete anything, at least until you free up the whole Nursery during a minor GC, so there is no need to track free regions. Consequently, the Nursery is perfect for bump allocation: to allocate N bytes you just check whether there is space available, then increment the current end-of-heap pointer by N bytes and return the previous pointer.

    There are even tricks to optimize away the “space available” check in many cases. As a result, objects with a short lifespan never go through the slower Tenured heap allocation code at all.

    Timings

    I wrote a simple benchmark to demonstrate the various possible gains of GGC. The benchmark is sort of a “vector Fibonacci” calculation, where it computes a Fibonacci sequence for both the x and y components of a two dimensional vector. The script allocates a temporary object on every iteration. It first times the loop with the (Tenured) heap nearly empty, then it constructs a large object graph, intended to be placed into the Tenured portion of the heap, and times the loop again.

    On my laptop, the benchmark shows huge wins from GGC. The average time for an iteration through the loop drops from 15 nanoseconds (ns) to 6ns with an empty heap, demonstrating the faster Nursery allocation. It also shows the independence from the Tenured heap size: without GGC, populating the long-lived heap slows down the mean time from 15ns to 27ns. With GGC, the speed stays flat at 6ns per iteration; the Tenured heap simply doesn’t matter.

    Note that this benchmark is intended to highlight the improvements possible with GGC. The actual benefit depends heavily on the details of a given script. In some scripts, the time to initialize an object is significant and may exceed the time required to allocate the memory. A higher percentage of Nursery objects may get tenured. When running inside the browser, we force enough major GCs (eg, after a redraw) that the benefits of GGC are less noticeable.

    Also, the description above implies that we will pause long enough to collect the entire heap, which is not the case — our incremental garbage collector dramatically reduces pause times on many Web workloads already. (The incremental and generational collectors complement each other — each attacks a different part of the problem.)

    Continued…

  2. Low price smartphones – memory management and optimization on Firefox OS

    We know how to generate memory a footprint to debug memory leaks and to prevent abusing memory resources. Now, we would like to introduce the memory management and optimizations under the limited memory resources on Firefox OS.

    How to get more memory on Firefox OS?

    There are three types of events which can get more memory when there is not enough memory on Firefox OS:

    1. Low memory killer (LMK)
    2. Memory pressure event
    3. Out of memory (OOM)

    Low memory killer (LMK)

    LMK is a policy to obtain memory resources by killing processes in Android; we integrate it into Firefox OS. When cache size or available memory is lower than a specified threshold, the system will trigger LMK to kill the process with oom_adj higher than 0 and to get some memory resources.

    The thresholds are defined in b2g/app/b2g.js. Let’s take the following table as an example:

    • When cache size and available memory are both lower than 20MB, the process with oom_adj as 10 (BACKGROUND) will be killed by LMK
    • When cache size and available memory are both lower than 8MB, the process with oom_adj as 8 (BACKGROUND_HOMESCREEN) will be killed by LMK
    • When cache size and available memory are both lower than 4MB, the process, named b2g with oom_adj as 0 (MASTER) will be killed by LMK

    By the way, LMK kills processes one-by-one, so we can be sure that memory leakage happens once b2g was killed by LMK.

    // The kernel can only accept 6 (OomScoreAdjust, KillUnderKB) pairs. But it is
    // okay, kernel will still kill processes with larger OomScoreAdjust first even
    // its OomScoreAdjust don't have a corresponding KillUnderKB.
     
    pref("hal.processPriorityManager.gonk.MASTER.OomScoreAdjust", 0);
    pref("hal.processPriorityManager.gonk.MASTER.KillUnderKB", 4096);
    pref("hal.processPriorityManager.gonk.MASTER.Nice", 0);
     
    pref("hal.processPriorityManager.gonk.PREALLOC.OomScoreAdjust", 67);
    pref("hal.processPriorityManager.gonk.PREALLOC.Nice", 18);
     
    pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.OomScoreAdjust", 67);
    pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.KillUnderKB", 5120);
    pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.Nice", 0);
     
    pref("hal.processPriorityManager.gonk.FOREGROUND.OomScoreAdjust", 134);
    pref("hal.processPriorityManager.gonk.FOREGROUND.KillUnderKB", 6144);
    pref("hal.processPriorityManager.gonk.FOREGROUND.Nice", 1);
     
    pref("hal.processPriorityManager.gonk.FOREGROUND_KEYBOARD.OomScoreAdjust", 200);
    pref("hal.processPriorityManager.gonk.FOREGROUND_KEYBOARD.Nice", 1);
     
    pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.OomScoreAdjust", 400);
    pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.KillUnderKB", 7168);
    pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.Nice", 7);
     
    pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.OomScoreAdjust", 534);
    pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.KillUnderKB", 8192);
    pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.Nice", 18);
     
    pref("hal.processPriorityManager.gonk.BACKGROUND.OomScoreAdjust", 667);
    pref("hal.processPriorityManager.gonk.BACKGROUND.KillUnderKB", 20480);
    pref("hal.processPriorityManager.gonk.BACKGROUND.Nice", 18);

    Memory pressure event

    When the memory pressure event was triggered, the services that are registered as memory pressure event observers will execute corresponding actions, such as eliminating or minimizing cache (temporary data of b2g). The threshold of the memory pressure event is configured in b2g/app/b2g.js, and the default value (notifyLowMemUnderKB) is 14MB.

    // Fire a memory pressure event when the system has less than Xmb of memory
    // remaining.  You should probably set this just above Y.KillUnderKB for
    // the highest priority class Y that you want to make an effort to keep alive.
    // (For example, we want BACKGROUND_PERCEIVABLE to stay alive.)  If you set
    // this too high, then we'll send out a memory pressure event every Z seconds
    // (see below), even while we have processes that we would happily kill in
    // order to free up memory.
    pref("hal.processPriorityManager.gonk.notifyLowMemUnderKB", 14336);

    Out of memory (OOM)

    The Linux kernel provides the OOM policy. When available memory is lower than a specified threshold, OOM will decide which process to kill through the score which is calculated by memory usage and oom_score_adj. The whole operation will obtain more memory resources to satisfy the demands of system. The default threshold (min_free_kbytes) of free memory to trigger OOM is 1352KB.

    How to make these three memory policies work smoothly and reach excellent performance on Firefox OS?

    Let me introduce some possible problems first. What will happen if there were conflicts among these three policies?

    • Problem 1. The system will be sluggish if LMK thresholds are lower than the expected ones. With the lower threshold, the system cannot kill any process to get more memory when the memory is not enough. Then the performance will be influenced due to triggered kswapd and heavily consumed CPU. If the thresholds are higher than what’s expected, users will feel inconvenient because applications could be killed easily.
    • Problem 2. The activities of eliminating and minimizing cache will be too aggressive if the threshold of the memory pressure event is high. When memory is enough, the relevant activities will waste CPU resources and will make performance poor. If the threshold is low, the system cannot be able to release memory on time.
    • Problem 3. It will cause crashes or fatal errors when OOM is triggered earlier than LMK is. B2g or other system applications will be killed before background/foreground applications if OOM has been triggered first. When memory is not enough, the system should kill background/foreground applications rather than b2g or system applications.

    For the problems mentioned, we need a set of parameters to fix them:

    1. To experience good performance, we allow to kill background for more memory, and it will make foreground applications operate smoothly. So we increase the value of BACKGROUND_HOMESCREEN.KillUnderKB and BACKGROUND.KillUnderKB to kill homescreen and background easily.
    2. We should trigger the memory pressure event before killing perceivable background applications. That is to say, it’s better to set the value of notifyLowMemUnderKB between the ones of BACKGROUND_HOMESCREEN.KillUnderKB and BACKGROUND_PERCEIVABLE.KillUnderKB.
    3. To solve problem 3, LMK must start working before OOM, which means the value of min_free_kbytes should be lower than the one of MASTER.KillUnderKB.

    Let’s take the Tarako (sc6821, 128MB memory device) as an example. The memory settings which were dumped by adb shell b2g-info are:

    Low-memory killer parameters:
     
      notify_trigger 14336 KB
     
      oom_adj min_free
            0  4096 KB
            1  5120 KB
            2  6144 KB
            6  7168 KB
            8 16384 KB
           10 18432 KB

    Tips for quick memory adjustment

    Firefox OS also provides an efficient way to verify your modified memory settings except modifying parameters in b2g/app/b2g.js. Developers can add his/her own modified settings by modifying /system/b2g/defaults/pref/dev-pref.js on the device. The parameters in this file will overwrite the default value in b2g/app/b2g.js.

    Still, there are quite a few ways of optimizing memory for low price smartphones. We have more detailed technique discussions on bugzilla. Let’s join Firefox OS development and rock the world!

  3. Introducing fxpay for in-app payments

    A while ago Mozilla announced navigator.mozPay() for accepting payments on Firefox OS. This was our first step toward helping developers do commerce on the web. It solved the problem of processing payments but what about the rest? Today we’re announcing an early peek at fxpay, a library for the rest of what you need as a developer to sell digital products in your app. This small JavaScript library (11kB minified) gives you some nice additional features on top of payment processing:

    • Work with a catalog of in-app products without hosting your own server
    • Securely verify each payment in one simple JavaScript callback
    • Restore previous purchases from receipts

    The mozPay() API is great if you need to integrate with an existing system but building a product catalog from scratch is a lot of work. If you have an idea for adding revenue to your app, why not quickly toss in some products and see what sells?

    The fxpay library is designed to get you selling as quickly as possible. Because it interacts with the Firefox Marketplace API you don’t need to manage code on your own server — you enter product details on Firefox Marketplace and call some JavaScript functions in your app to sell them.

    First: A Warning

    fxpay is in an early experimental state. We’re looking for your help to make it a concise, intuitive library which means the API might change rapidly. There’s a section below for details about how to get involved.

    Offer Some Products For Sale

    After running bower install fxpay (installation details), show some products for sale within your app using getProducts():

    // First, let's test with some fake products.
    fxpay.configure({fakeProducts: true});
     
    fxpay.getProducts(function(error, products) {
      if (error) {
        console.error(error);
      } else {
        products.forEach(function(product) {
          addBuyButtonForProduct(product);
        });
      }
    });

    The code here would add a buy button for each product so that tapping the button would start a purchase. Here’s a simplistic example:

    function addBuyButtonForProduct(product) {
      var button = document.createElement('button');
      button.textContent = 'Buy ' + product.name;
      button.addEventListener('click', function () {
     
        fxpay.purchase(product.productId, 
                       function(error, product) {
          if (error) {
            console.error(error);
          } else {
            console.log(product.name + ' bought!');
          }
        });
     
      });
      document.body.appendChild(button);
    }

    That’s it. The call to fxpay.purchase() guides the user through payment via mozPay() and verifies the result on the Firefox Marketplace server. If you receive the callback without an error that means the purchase was verified and funds will be transferred to your account upon completion. It is safe to deliver the product.

    Try It Out

    Install an app on the Firefox OS Simulator using the App Manager and tap your custom buy button. Since this is a test with fake products, you’ll see a payment simulation screen. Tap Continue and your purchase callback will fire, allowing you to get your product delivery code working.

    Restoring Purchases

    When a user completes a purchase, a portable receipt is installed on their device behind the scenes. This is a cryptographically signed JSON object that proves ownership of the product. Each time the user returns to your application, you’ll want to check for any receipts so you can restore their purchased products. The fxpay library does the validation for you but you have to define a callback for when each product is restored like this:

    fxpay.init({
      onerror: function(error) {
        console.error('init error:', error);
      },
      onrestore: function(error, product) {
        if (error) {
          console.error('onrestore error:', error);
        } else {
          console.log(product.name + ' restored');
        }
      }
    });

    Just like the purchase callback, if you don’t get an error it means the receipt is valid; the user owns the product so you should make it available. You probably only need to run init() once when your app starts up.

    Publishing Your Application

    Once you get everything working with fake products, the next step is to submit your app to the Firefox Marketplace developer hub so users can install it. The submission process is detailed in the documentation; it includes entering bank account details to receive payouts and submitting real names and prices of the products you wish to sell.

    Once all of your products are in place and your app has been approved, set {fakeProducts: false} and the same code you see here will begin to work with real products. The getProducts() function will use your app’s origin to retrieve the configured products.

    Example App

    The fxpay library ships with an example app that you can install from the App Manager and play around with.

    Get Involved

    Do you have an idea for an app with in-app payments? Try it out. We’re announcing an early version of fxpay so we can make it work well for you, the developer. If something breaks or just feels awkward or if you have an idea to make the library better, get in touch!

    Going Further

    The Payments team at Mozilla is small (but mighty!). This release has a lot of missing features but we wanted to start getting early feedback. Here are a few ideas for features we’d like to add next:

    Support More App Types

    Right now, fxpay is limited to privileged packaged apps on mobile only. See all prerequisites. We’re working to open up access to other app types such as hosted apps and desktop apps.

    Receipt Recovery

    If a user loses their device or deletes the app they will lose their in-app purchase receipts. Those receipts are backed up on the Marketplace server but users don’t have an interface to reinstall them yet. We’re trying to figure out a way to do that in bug 1045228.

    Exact Product Prices

    Price points and currencies vary by mobile network but non-certified apps don’t have a reliable way to detect users’ networks. Currently you can’t display prices next to your custom buy buttons. We’d like to offer some solutions for this even if it’s just a manual currency selector. See bug 1063758.

    Product Assets

    This first release of fxpay is best suited for local content such as unlocking a level in a game. If an app were to distribute remote content such as a MP3 file as a ring tone, there would be no way to securely protect the contents of that file. We’ll be considering how to add support for this in bug 1063059.

    We’re planning lots of other stuff too!

  4. WebIDE, Storage inspector, jQuery events, iframe switcher + more – Firefox Developer Tools Episode 34

    A new set of Firefox Developer Tools features has just been uplifted to the Aurora channel. These features are available right now in Aurora, and will be in the Firefox 34 release in November. This release brings new tools (storage inspector, WebIDE), an updated profiler, and handy enhancements to the existing tools:

    WebIDE

    WebIDE, a new tool for in-browser app development, has been enabled by default in this release. WebIDE lets you create a new Firefox OS app (which is just a web app) from a template, or open up the code for an already created app. From there you can edit the app’s files. It’s one click to run the app in a simulator and one more to debug it with the developer tools. Open WebIDE from Firefox’s “Web Developer” menu. (docs)

    Storage inspector

    There’s a new panel that shows the data your page has stored in cookies, localStorage, sessionStorage, and IndexedDB, which was created mostly by Girish Shama. Enable the Storage panel by checking off Settings > “Default Developer Tools” > “Storage”. The panel is read-only right now, with editing ability planned for a future release. (docs) (development notes) (UserVoice request)

    storage inspector

    jQuery events

    The event listener popup in the Inspector now supports jQuery. This means the popup will display the function you attached with e.g. jQuery.on(), and not the jQuery wrapper function itself. See this post for more info and how to add support for your preferred framework. (development notes)

    JQuery events

    Iframe switcher

    Change the frame you’re debugging using the new frame selection menu. Selecting a frame will switch all of the tools to debug that iframe, including the Inspector, Console, and Debugger. Add the frame selection button by checking off Settings > “Available Toolbox Buttons” > “Select an iframe”. (docs) (development notes)(UserVoice request)

    iframe selection

    Updated profiler

    An updated JavaScript profiler appears in the new “Performance” tab (formerly the “Profiler” tab). New to the profiler are a frame rate timeline and categories for frames like “network” and “graphics”. (docs) (development notes)

    new profiler

    console.table()

    Add a call to console.table() anywhere in your JavaScript to log data to the console using a table-like display. Log any object, array, Map, or Set. Sort a column in the table by clicking on its header. (docs) (development notes)

    console.table

    Selector preview

    Hover over a CSS selector in the Inspector or Style Editor to highlight all the nodes that match that selector on the page. (development notes)

    selector previews

    Other mentions

    • Persistent split console – The split console (opened by pressing ESC) will now open with the tools if you had it open the last time the tools were closed. (development notes)
    • Web audio – AudioParam connections – the Web Audio Editor now displays connections from AudioNodes to AudioParams. (development notes)

    Special thanks to the 41 contributors that added all the features and fixes in this release.

    Comment here, shoot feedback to @FirefoxDevTools on Twitter, or propose changes on the Developer Tools feedback channel. If you’d like to help out, check out the guide to getting involved.

  5. Single Div Drawings with CSS

    Why A Single Div?

    In May of 2013 I attended CSSConf and saw Lea Verou speak about the humble border-radius. It was an eye-opening talk and I realized there was much about CSS behavior I did not fully understand. This reminded me of my time as a fine arts student where I was constantly pushed to become a master of my chosen medium. As a web designer, CSS is my medium and so I challenged myself to learn all I could about it and to explore and experiment with its limits.

    But why a single div?

    When I was learning to paint, my class did these color mixing exercises where we created the many colors of the spectrum from only the three primary colors: red, yellow, and blue. The purpose of the exercise is to learn the behavior of the medium and the constraints show us the power of combination. You can certainly buy green paint, but you can also create green from blue and yellow. Restricting your available options forces you to re-evaluate the tools you already have.

    I decided to start a CSS drawing project, every few days illustrating something new with only CSS. To further challenge and explore what CSS is capable of, I gave myself the constraint of using only a single div in the markup. Instead of buying green paint (or adding another div), I’d need to stretch and combine CSS properties to achieve my goals.

    The Toolkit

    With only a single div and browser-supported CSS properties, it may seem like the tools are too limited. I found it’s not always what you have to work with, but how you look at them.

    Pseudo elements

    With one div in the HTML, I actually have three elements to work with because of CSS pseudo classes. So with div, div:before, and div:after, we can get something like this:

    pseudo elements

      div { background: red; }
      div:before { background: yellow; }
      div:after { background: blue; }

    It helps to think about these three elements as things that can come in sequence and as three stackable layers. So in my mind, it would usually look more like this:

    pseudo elements as layers

    Shapes

    With CSS and one element, we are afforded three basic shape types. We can use width and height properties to create squares/rectangles, border-radius to create circles/ellipses, and border to create triangles/trapezoids.

    css shapes

    There are others we can create with CSS, but most things can be simplified to some combination of these shapes. And these are the easiest to create and manipulate.

    Multiples of the same shape

    With multiple box-shadows, we can create many versions of the same shape in varying size, color, and blur. Offsetting them on the x- and y-axes gives us almost endless multiples.

    multiple box-shadows

    div {
        box-shadow: 170px 0 10px yellow,
                    330px 0 0 -20px blue,
                    330px 5px 5px -20px black;
    }

    We can even give our box-shadows box-shadows. Pay attention to the order they are declared. Again, It’s helpful to think of them as layers.

    Gradients

    Gradients can be used to add shading and depth by implying a light source. This makes the simple, flat shapes feel more realistic. Combining multiple background-images allows us to use many, layered gradients to achieve more complex shading and even more shapes.

    gradients

    div {
        background-image: linear-gradient(to right, gray, white, gray, black);
    }
     
    div:after {
        background-image: radial-gradient(circle, yellow 50%, transparent 50%),
                          linear-gradient(to right, blue, red);
    }

    Visualizing

    The most difficult part is visualizing how to piece these parts into a whole recognizable drawing. As much as I focus on the technical aspects of the drawings, this part of the process is critical. To help with this, I’ll often look at a photograph of the subject and break it up visually into pieces. Everything is a shape and everything is a color. I simplify the overall picture into smaller shapes or blocks of color I know can (or suspect can) be achieved with CSS.

    Demos

    Let’s take a closer look at two drawings and break down some of the pieces that make up the larger pictures. First up is the green crayon.

    A crayon is made up of two primary shapes: the rectangular body and the triangular drawing tip.

    crayon shapes

    I had to guarantee the following things to capture a realistic image:

    • the different color of the paper wrapper
    • the printed graphics and words on the wrapper
    • the shading that shows the roundness of the crayon
    • the glossiness that shows roundness and a light source

    So first, I created the main body of the crayon with the div and a background color, top-to-bottom gradient, and box-shadow to show some dimension:

    crayon body

    (Note, I’m using a mixin of black(a) and white(a) here in place of rgba)

    div {
        background: #237449;
        background-image: linear-gradient(to bottom,
                                      transparent 62%,
                                      black(.3) 100%);
        box-shadow: 2px 2px 3px black(.3);
    }

    Then I added a left-to-right linear-gradient to create the wrapper. It has an alpha value of .6 so some of that previous gradient shows through.

    crayon wrapper

    div {
        background-image: linear-gradient(to right,
                                      transparent 12px,
                                      rgba(41,237,133,.6) 12px,
                                      rgba(41,237,133,.6) 235px,
                                      transparent 235px);
    }

    Next I used the same left-to-right gradient technique to create the printed stripes on the crayon.

    crayon printing

    div {
        background-image: linear-gradient(to right,
                                      transparent 25px,
                                      black(.6) 25px,
                                      black(.6) 30px,
                                      transparent 30px,
                                      transparent 35px,
                                      black(.6) 35px,
                                      black(.6) 40px,
                                      transparent 40px,
                                      transparent 210px,
                                      black(.6) 210px,
                                      black(.6) 215px,
                                      transparent 215px,
                                      transparent 220px,
                                      black(.6) 220px,
                                      black(.6) 225px,
                                      transparent 225px);
    }

    And for the printed ellipse, a radial-gradient works great!

    crayon printing

    div {
        background-image: radial-gradient(ellipse at top,
                                      black(.6) 50px,
                                      transparent 54px);
    }

    I have it broken up to demonstrate each piece, but keep in mind the background-image would actually look like this:

    div {
                          // ellipse printed on wrapper
        background-image: radial-gradient(ellipse at top,
                                      black(.6) 50px,
                                      transparent 54px),
                          // printed stripes
                          linear-gradient(to right,
                                      transparent 25px,
                                      black(.6) 25px,
                                      black(.6) 30px,
                                      transparent 30px,
                                      transparent 35px,
                                      black(.6) 35px,
                                      black(.6) 40px,
                                      transparent 40px,
                                      transparent 210px,
                                      black(.6) 210px,
                                      black(.6) 215px,
                                      transparent 215px,
                                      transparent 220px,
                                      black(.6) 220px,
                                      black(.6) 225px,
                                      transparent 225px),
                          // wrapper
                          linear-gradient(to right,
                                      transparent 12px,
                                      rgba(41,237,133,.6) 12px,
                                      rgba(41,237,133,.6) 235px,
                                      transparent 235px),
                          // crayon body shading
                          linear-gradient(to bottom,
                                      transparent 62%,
                                      black(.3) 100%)
    }

    So after completing the div, I moved on to the :before pseudo element to create the crayon’s triangular tip. Using solid and transparent borders, I made a triangle and positioned it next to the div I just drew.

    triangle crayon tip

    div:before {
        height: 10px;
        border-right: 48px solid #237449;
        border-bottom: 13px solid transparent;
        border-top: 13px solid transparent;
    }

    It looks a little flat next to the crayon’s body, but it will be fixed with the :after pseudo element. With this, I added a top-to-bottom linear-gradient to create a reflective gloss effect that spans the width of the crayon.

    crayon gloss

    div:after {
        background-image: linear-gradient(to bottom,
                                        white(0) 12px,
                                        white(.2) 17px,
                                        white(.2) 19px,
                                        white(0) 24px);
    }

    This adds even more dimension and realism and helps with that flat triangle. As a finishing touch, I added some text content to the :after and positioned it as another printed element on the crayon’s wrapper.

    crayon color label

    div:after {
        content: 'green';
        font-family: Arial, sans-serif;
        font-size: 12px;
        font-weight: bold;
        color: black(.3);
        text-align: right;
        padding-right: 47px;
        padding-top: 17px;
    }

    And that’s it!

    Let’s take a look at another one

    The crayon is a good example of using background-image and gradients to produce realistic results. Here’s an example that shows the power of multiple box-shadows: a single div camera.

    Here’s the body of the camera, created with background-image and border-image.

    camera body

    Here’s a gif illustrating the :before pseudo element (the black rectangle) and the many details created with its box-shadows.

    camera rectangle

    div:before {
        background: #333;
        box-shadow: 0 0 0 2px #eee,
                    -1px -1px 1px 3px #333,
                    -95px 6px 0 0 #ccc,
                    30px 3px 0 12px #ccc,
                    -18px 37px 0 46px #ccc,
     
                    -96px -6px 0 -6px #555,
                    -96px -9px 0 -6px #ddd,
     
                    -155px -10px 1px 3px #888,
                    -165px -10px 1px 3px #999,
                    -170px -10px 1px 3px #666,
                    -162px -8px 0 5px #555,
     
                    85px -4px 1px -3px #ccc,
                    79px -4px 1px -3px #888,
                    82px 1px 0 -4px #555;
    }

    Similarly, here’s the :after (the grey circle) and its several box-shadow details.

    camera circle

    div:after {
        background: linear-gradient(45deg, #ccc 40%, #ddd 100%);
        border-radius: 50%;
        box-shadow: 0 3px 2px #999,
                    1px -2px 0 white,
                    -1px -3px 2px #555,
                    0 0 0 15px #c2c2c2,
                    0 -2px 0 15px white,
                    -2px -5px 1px 17px #666,
                    0 10px 10px 15px black(.3),
     
                    -90px -51px 1px -43px #aaa,
                    -90px -50px 1px -40px #888,
                    -90px -51px 0 -34px #ccc,
                    -90px -50px 0 -30px #aaa,
                    -90px -48px 1px -28px black(.2),
     
                    -124px -73px 1px -48px #eee,
                    -125px -72px 0 -46px #666,
                    -85px -73px 1px -48px #eee,
                    -86px -72px 0 -46px #666,
                    42px -82px 1px -48px #eee,
                    41px -81px 0 -46px #777,
                    67px -73px 1px -48px #eee,
                    66px -72px 0 -46px #666,
     
                    -46px -86px 1px -45px #444,
                    -44px -87px 0 -38px #333,
                    -44px -86px 0 -37px #ccc,
                    -44px -85px 0 -34px #999,
     
                    14px -89px 1px -48px #eee,
                    12px -84px 1px -48px #999,
                    23px -85px 0 -47px #444,
                    23px -87px 0 -46px #888;
    }

    A little crazy, but as you can see, multiple box-shadows can add a lot of detail to a single div drawing.

    Biggest challenges

    Two of the biggest obstacles I came across were limitations around triangle shapes and the natural behavior of gradients.

    The trouble with triangles

    Because triangles are created using borders, it limits how much I can do with them. Adding gradients with border-image apply to all the borders, not just one side. Box-shadows apply to the shape of the box, not the triangle shape the border creates, so creating multiple triangle shapes can be difficult. Here’s an example of what that looks like:

    trouble with triangles

    div {
        border-left: 80px solid transparent;
        border-right: 80px solid transparent;
        border-bottom: 80px solid red;
    }
     
    div:before {
        border-left: 80px solid transparent;
        border-right: 80px solid transparent;
        border-bottom: 80px solid red;
        border-image: linear-gradient(to right, red, blue);
    }
     
    div:after {
        border-left: 80px solid transparent;
        border-right: 80px solid transparent;
        border-bottom: 80px solid red;
        box-shadow: 5px 5px 5px gray;
    }

    Layering gradients

    With gradients, their natural behavior is to fill the entire background. This can get a little tricky when layering multiple gradients on top of each other. It takes some extra time to think through transparency, z-index, and understanding what will and won’t be visible. By using this technique effectively, our drawings can have surprising detail.

    The Tardis is a good example of showing and hiding gradients to create a detailed picture. Here’s the drawing mid-process that shows some of the top-to-bottom gradients that span the entire width of the container.

    single div tardis in-process

    Using left-to-right and right-to-left gradients, I was able to cover parts of the gradient and leave some parts exposed.

    single div tardis in-process

    The resulting drawing appears to have many shapes making up the front facade of the Tardis, but it’s strategically layered linear-gradients. Sometimes you have to fake it.

    See them in action

    One awesome thing that popped up because of this project is a really cool and useful Chrome browser extension by Rafael Carício called CSS Gradient Inspector. It extends the developer tools to inspect and toggle on/off each element’s gradients as if they were layers. (It’s very helpful with everyday projects, too.)

    I’m super excited to see designers and developers experimenting and riffing on these drawings with animations and JavaScript functionality. Check out the site and play around with the CSS yourself at a.singlediv.com or on GitHub!

  6. Firefox Add-on Enables Web Development Across Browsers and Devices

    Developing across multiple browsers and devices is the main issue developers have when building applications. Wouldn’t it be great to debug your app across desktop, Android and iOS with one tool? We believe the Web is powerful enough to offer a Mobile Web development solution that meets these needs!

    Enter an experimental Firefox add-on called the Firefox Tools Adaptor that connects the Firefox Developer Tools to other major browser engines. This add-on is taking the awesome tools we’ve built to debug Firefox OS and Firefox on Android to the other major mobile browsers starting with Chrome on Android and Safari on iOS. So far these tools include our Inspector, Debugger and Console.

    Nothing can replace on-device testing. But developer tools on devices have been cumbersome and vendor-specific. Cross-platform development involved learning and switching between all the different browsers developer tools.

    This add-on allows you to use your desktop environment to work on several small screen devices without using up precious screen space. You simply use the device and find out what is going wrong on your computer – regardless of platform and browser engine on the device.

    How the Add-on Works

    Now Try it Out

    This project is still in the early stages, but we put together a preview for developers who are curious or want to contribute. All it takes is the latest copy of Firefox Nightly and the add-on. Follow the Firefox Tools Adapter instructions to get started.

    This preview works with Chrome 37 on Android, currently available as Chrome Beta, and Safari on iOS. Some parts work pretty well, some parts need some work. Give it a try and let us know what you think!

    So What’s Under the Hood?

    This add-on is a new implementation of the Firefox Developer Tools Protocol. Rather than interfacing directly with content, it speaks to the remote debugging protocol surfaced by Chrome and iOS. This implementation is hosted inside the Firefox process, and used internally by the Firefox Developer Tools.

    When Will It Be Ready?

    What we’re showing today is an early preview release. We’ll be actively developing it in the coming months, directed in large part by your feedback. We’ll keep you posted on new updates when they happen!

    How to Contribute

    The GitHub project page has instructions for getting involved with the code. Your feedback is also helpful: Talk to us on Twitter at @FirefoxDevTools, GitHub issues or UserVoice.

  7. 350 posts on Hacks in 2 years!

    Two years ago, we made a number of changes to the Mozilla Hacks blog. Since then we’ve had over three million unique visitors and 350 quality posts in just less than two years – almost one every second day!

    Part of these changes included:

    • A clear focus on learning about the Open Web & open source – more detail in What Mozilla Hacks is
    • A dedicated Editor, me, working with ensuring consistency, quality & versatility of the articles
    • Articles covering both interesting technologies and possibilities but also learning lessons of how to build exciting solutions and work with a number of different technical opportunities
    • To be a credible and independent go-to resource for developers

    Testimonials

    I’ve gathered a few testimonials from authors behind the most popular articles during this time, with their experiences writing for Mozilla Hacks.

    And you know what? You could write for Hacks too!

    If you have experience with a great solution or idea for the Open Web/open source, just let me know and Mozilla can help you share it with a lot of developers out there! Send an e-mail to robert [at] mozilla [dot] com or talk to me via @robertnyman on Twitter and we’ll talk!

    Here are the thoughts from Peter Cooper of HTML5 Weekly & JavaScript Weekly, Dave Camp, Director of Firefox Developer Tools and Thorben Bochenek from Opera on writing for Mozilla Hacks.

    Austin Hallock from Clay.io:

    My co-founder Zoli and I have both written articles for Mozilla Hacks and we agree that it was a very worthwhile experience. The process of getting our posts on the site was easy and both articles generated more response than we expected. Mozilla has a fantastic mission, and the Mozilla Hacks blog is a great extension of that.

    Their articles:

    Also, thanks to the authors on Mozilla Hacks for their great contributions! And those in that page are only authors with 2 posts and more – in total we have 230 authors all time who have published a post on Hacks!

    Most popular content

    During these two years, these are the most popular posts, written by Mozilla staff:

    The most popular posts, written by 3rd party developers/writers:

    Read & write

    If you like our articles, please spread the word about them! Ask your friends to read too and follow @mozhacks on Twitter for the latest articles and announcements.

    And if you have experiences and learnings to share, let us know and help you with sharing that knowledge!

  8. Enabling Voice Input into the Open Web and Firefox OS

    With the advent of smartphones triggered by iPhone in 2007, Touch became the primary mode of input for interacting with these devices. And now with the advent of wearables (and other hands-free technologies that existed before), Voice is becoming another key method of input. The possibilities of experiences Voice Input enables are huge, to say the least.

    They go beyond just merely interacting with in-vehicle devices, accessories and wearables. Just think of the avenues Voice Input opens up for bringing more technologies to more people. It’s enormous: Accessibility, Literacy, Gaming, VR and the list goes on. There is a social vibe there that definitely resonates with our mission at Mozilla detailed in our Mozilla Manifesto

    How it started

    Both current leading mobile OS/ecosystem providers of today- Apple & Google have their native experiences with Siri and “OK Google” (coupled with Google Now). We really needed an effort to enable Voice Input into the first ecosystem that existed – the open Web. Around MWC 2013 in Barcelona, when Desigan Chinniah introduced me to André Natal – Firefox contributor from Brazil, we had a conversation around this and we instantly agreed to do something about this in whichever way possible. Andre told me about being inspired from a talk by Brendan Eich in BrazilJS, so I did not have much convincing to do. :-)

    First steps

    We had numerous calls and meetings over the past year on the approach and tactics around this. Since “code wins arguments”, the basic work started in parallel with Firefox desktop and FxOS Unagi devices, later switching to Mozilla Flame devices over time. Over a period of the past year, we had several meetings with Mozilla engineering leads on exact approach and decided to break this effort into several smaller phases (“baby steps”).

    The first target was getting Web Speech API implemented, and getting acoustic/language modules integrated with a decoder and giving that a try. Lots of similar minded folks in Mozilla Engineering/QA & community helped along with guidance and code-reviews while Andre moonlighted (on top of his day job) with a very high focus. Things moved fast in past month or so. (Well, to be honest, the only day this effort slowed down was when Team Brazil lost to Germany in FIFA 2014. :-)) Full credit to André for his hard work!

    Where are we?

    Our current thinking is to get a grammar-based (limited commands) app working first and distribute it in our rich & diverse international Mozilla community for accent-based testing and enhancements. Once we have this stablilized, we will get into the phase 2 where we can focus more on natural language processing and get closer to a virtual assistant experience sometime in future that can give users voice based answers. There is lots of work to do there and we are just beginning.

    I will save the rest of the details for later and jump to the current status this month. Where are we so far?

    We now have the Web Speech API ready for testing and we have a couple demos for you to see!

    Desktop: Firefox Nightly on Mac

    Editor’s note: for full effect, start playing the two above videos at the same time.

    Firefox OS demo

    Come, Join us!

    If you want to follow along, please look at the SpeechRTC – Speech enabling the open web wiki and Bug 1032964 – Enabling Voice input in Firefox OS.

    So jump in and help out if you can. We need all of you (and your voices). Remember “Many Voices, One Mozilla”!

  9. Webapplate – Maintainable web app template for Firefox OS and Chrome Apps

    There are many powerful tools and technologies surrounding the Web, and we can reuse them to develop cross platform mobile and desktop apps, especially in light of installable apps appearing on platforms such as Firefox OS. This article looks at the best way to do this, and presents Webapplate, a powerful new template to help facilitate this.

    Why invent the wheel (for the new frontier)

    As is the nature of the whole web, web apps are simple to write but hard to get done right. Even though the Web doesn’t provide an SDK or simple ready-to-use templates like other mobile platforms, you can still come out with a workable web app from candidates like Mozilla Open Web Apps, Chrome Apps, or Apache Cordova. But developers who want to quickly build a web app usually take longer time than say, an iOS developer.

    Here is the state of web app support by those candidates:

    • Firefox (desktop), Firefox OS, Firefox for Android support hosted web apps. Those web apps could be hosted on a static or dynamic web server just like normal web sites. Hosted web apps don’t allow some certified web APIs such as the TCP socket API because of security concerns.
    • Firefox OS and Chrome (desktop) support packaged web apps with different APIs for different purposes, because currently they focus on different types of devices.
    • Cordova provides device adapters for many platforms, including Android, iOS and Firefox OS.
    • Google has its Cordova variant to adapt Chrome App’s specific APIs to run on Android devices.

    In quick summary, the web app concept is not totally unified yet, but powerful enough to compete with native apps. Currently packaged web apps are mainstream because of the security concerns with new web API’s. Mozilla is mainly focusing on exposing new web APIs to mobile devices, Google is developing new web APIs for desktop. Apache Cordova is a good container to expose web APIs to different platforms.

    To make things harder, provided examples are often focused on teaching you how to pick up new web APIs rather than utilizing proper web app concepts with your development process.

    I’ve had the chance to join the development of an evolving web app project called Gaia, the Firefox OS user interface. The Gaia project contains the very first Mozilla installable web app implementation, including apps for music, photo gallery, e-mail, calendar and much more. According to GitHub’s pulse monthly, there are about 850 commits per month to the Gaia web apps. In the Gaia project, Mozilla developers and community members devoted lots of time and effort to bring it from the prototype stage to a shippable product within 2 years, and iteratively make it a competitive option for smartphone consumers. As a living large web app project, there are many lessons that can be learned from it, and applied to general web app development.

    Introducing webapplate

    Like other software projects, there are many things beside commiting code to develop a web app, such as:

    • How to organize the source code
    • How to handle library dependencies
    • How to keep the coding style in convention
    • How to optimize web app load performance
    • How to unit/integrate test your web app
    • How to localize your web app
    • How to automate those processes

    Those are topics that need to be resolved to develop a quality web app. In Gaia we have addressed these issues by utilizing a bunch of build scripts (Makefiles).

    You may wonder why we didn’t use Grunt or gulp for building? The answer: at the time Firefox OS was started, these tools didn’t exist. And the module owner wanted to make the core build process run in a Firefox extension one day.

    For general web app development, we didn’t have to follow those constraints. And we could do some experiments rapidly by reusing 3rd-party tools and libraries. From 2013, I’ve initiated a side project called webapplate, the open-sourced web app template that attempts to make Gaia’s solutions compatible with emerging toolkits like npm, Grunt and Bower. It also tries to transport good practices from Gaia to make new web apps more maintainable.

    How to setup webapplate

    Webapplate utilizes many powerful tools. With node.js, Grunt, Bower, Karma, Mocha and l20n, we come out with a maintainable full stack and self-contained web app template with JavaScript. So you could just copy or download the webapplate from Github, and develop and deploy to a hosting server or correspondent web app store.

    You need to install node.js in your desktop first. With Node.js installed, you’ll have the npm tool to manage Node.js modules. Now run this command:

    $ npm install -g grunt-cli bower karma

    to install the primary tools.

    Grunt is a JavaScript task runner tool (like Make) and grunt-cli is its command interface. Gruntfile.js file is similar to Makefile, but written in Javascript.

    Bower is a management tool for the front-end libraries. It helps developer manage different library versions. In webapplate, Bower will download client side libraries into the public/vendor folder when you run

    $ bower install

    command.

    Karma is the test runner that runs test code for each of the browsers. karma.conf.js defines the detail settings to specify how the test runner goes.

    Next, enter the webapplate folder and run:

    $ npm install

    npm will reference package.json to install all dependent node modules. The command will trigger Bower to install client-side library dependencies as well.

    Then you are all set! What you get is:

    • Pre-commit lint checking
    • Firefox and Chrome web app-compatible templates
    • Library dependency management
    • Client-side localization framework
    • Unit test and mock framework
    • Deployable web server

    If you use Firefox nightly, you could open the webapplate/public folder as a packaged app in the WebIDE developer tool.

    WebIDE allows you to edit, debug or execute your web app in the Simulator or on the device, with your favorite Firefox Developer Tools.

    With the Chrome Apps & Extensions developer tool, you can import the webapplate/public folder as a Chrome App and check the UI on desktop.

    webapplate on Chrome devtool

    Pre-commit lint checking

    The very first good practice that Gaia and webapplate provide is git pre-commit lint checking.

    Since in Gaia every commit needs to get reviewed and verified by the module owner before the code is checked in, we have followed the Google JavaScript style conventions. At that time we used gjslint to test it. It sounds good but actually forcing people to follow the exact same discipline manually is hard; asking the reviewer to pick through those style errors is another waste of time. So some genius introduced a git pre-commit hook to check several kinds of lint errors when the developer tries to commit their code, and provide a whitelist for the code that isn’t fully lint-free but should be allowed. Currently in Gaia we have pre-commit checks for JavaScript, CSS and JSON! This is a big relief.

    Currently webapplate utilizes code quality and style checking for JavaScript, JSON via JSHint, JSCS and JSONLint.

    It has exactly the same settings as Gaia for JSHint and also comes with the whitelist. Gaia is also planning to migrate to jscs to replace gjslint. If you use git for version control, run:

    $ grunt githooks

    to bind the git pre-commit code style check to your development process.

    Firefox OS- and Chrome App- compatible templates

    Webapplate uses HTML5 mobile boilerplate as the template base, and adds web app install helpers, icon links and usemin annotation for web app optimization on top. The main web app source is located in the public/ folder. You could check the webapplate wiki to see the full webapplate structure.

    Currently, Firefox web apps use manifest.webapp and Chrome Apps use manifest.json as the manifest file. The syntaxes are mutually compatible, except the localization part (we’ll address this issue later).

    After you edit one of these files, use:

    # firefox to chrome
    $ grunt f2c

    or

    # chrome to firefox
    $ grunt c2f

    to overwrite manifest.webapp with manifest.json, or viceversa.

    To generate a Firefox OS packaged app or Chrome App, run this command:

    $ grunt pack

    to package your web app to an uploadable zip file. With the default settings, webapplate-generated packaged web apps could be uploaded to the Firefox Marketplace and the Chrome App store.

    Library dependency management

    For Gaia we manage development tools via npm and generally don’t use many 3rd-party client side libraries. We host commonly-used libraries between apps in a shared/ folder, and then copy them in at build time via a build script.

    webapplate defines these libraries in package.json, uses npm to require build tools, and doesn’t assume any app framework (e.g. Backbone or Angular.js, or a UI framework such as Bootstrap.) Client-side libraries could be managed via Bower in bower.json.

    Client side localization framework

    Since web apps might be run without an Internet connection, we can’t count on the server to detect multiple languages. Currently Firefox OS uses navigator.mozL10n and Chrome Apps uses chrome.i18n for localization. Both of them are non-standard.

    In webapplate we take the l20n library to address the client-side localization issue. l20n is crafted by Mozilla and the developers are currently working on enhancing the Firefox OS localization framework as well.

    Check out index.html; the localization syntax looks exactly like what we used in Gaia:

    <h1 data-l10n-id="hello">Hello WebApplate</h1>

    The locale file however is in a different format, locales.en.l20n:

    <projectName "WebApplate">
    <hello "Hello {{ projectName }}">

    Also, check out the Multiple Language Support Framework section for how l20n is integrated with webapplate.

    Unit test and mock framework

    Gaia uses its own test-agent to trigger unit tests on Firefox. Gaia uses the Mocha test framework, Chai assertion library and the Sinon test helper library for unit tests.

    Webapplate uses the above unit test libraries plus the Karma test runner to run unit tests on all mainstream browsers.

    Deployable web server

    For developing Firefox OS hosted web apps, we need a working web server and maybe some dynamic web server support. Now that’s what we call the 21st century: it is possible to write server-side code in JavaScript as well.

    Running the command:

    $ grunt server

    will trigger the Express-powered server with django-like Swig template support. It’s been pre-configured for performance. Measure with YSlow and you’ll get a pretty good grade for your web site.

    Webapplate has been tested on some free dynamic web page hosting providers such as openshift, heroku and appfog. Check the deployment section to find out more details.

    If you like to host your web apps on a static web server, run:

    $ grunt static

    to generate optimized web pages for hosting.

    If you want to deploy your web app on a GitHub page (as a free static hosting server), run:

    $ grunt github

    Start your new web app project with webapplate!

    Webapplate is the web app template that borrows good practices for web app maintenance from the Gaia project. It provides ready-to-use Firefox OS and Chrome App support, an integrated toolbox to optimize your web app and maintain quality, and uses JavaScript through client/server side build/test frameworks. If you are about to make a web app or want to see how to maintain a web app, webapplate is a good start.

    References

  10. Introducing Blast.js

    After releasing Velocity.js, a highly performant web animation engine, I wanted to leverage that power for typographic manipulation. The question soon arose, How could I animate one letter, one word, or one sentence at a time without bloating my HTML with wrapper elements?

    If I could figure this out, I could create beautiful typographic animation sequences (the kind you see in movie titles), and perform real-time textual analysis.

    After researching lower-level DOM methods and polishing my RegEx skills, I built Blast.js: a jQuery/Zepto plugin that breaks apart text to enable hassle-free text manipulation. Follow that link to see a few demos.

    Let’s jump right into a code example. If we were to Blast an element using the following syntax…

    $("div").blast({ delimiter: "word" });

    …and if our element initially looked like this…

    <div>
        Hello World
    </div>

    …our element would now look like this:

    <div class="blast-root">
        <span class="blast">Hello</span>
        <span class="blast">World</span>
    </div>

    The div’s text was broken into individual span elements using the specified word delimiter. We could have used the character, sentence, or element delimiters instead.

    For a breakdown of Blast’s API, refer to its documentation.

    This article serves to explore the technical aspects that went into making Blast versatile and accurate: We’ll learn about very powerful, yet little-known, DOM traversal techniques plus how to maximally leverage RegEx for linguistic accuracy.

    If you’re interested in the technical aspects of how rich motion design works or how to manipulate text, this article is for you.

    Versatility

    Most DOM elements are composed of descendant text nodes. Blast traverses the entirety of the HTML element that it is targeted on, descending recursively until it’s found every descendant text node.

    For example, if you Blast the following HTML:

    <div>Hello <span>World</span></div>

    The containing div is an element node. This element node is composed of two children: 1) a text node (“Hello “) and 2) a span element node. The span element node contains one child: a text node of its own (“World”).

    With each text node Blast finds, it executes the RegEx query associated with the chosen delimiter type (e.g. character, word, or sentence) in order to find submatches. For example, a text node of “World” blasted with the character delimiter will produce five submatches: “w”, “o”, “r”, “l”, and “d”. Blast wraps a new element node of a user-defined type (span is the default) around each of these submatches.

    By traversing the DOM in this way, Blast can be applied safely to the entirety of an element without concern for breaking any of its descendant HTML or its associated event handlers. (Event handlers are never bound to text nodes, but rather to containing element nodes.)

    In fact, let’s try just that — in real-time! Click here to see Blast used on a CodePen page with the word delimiter. Notice how the generated wrapper elements are filtered with alternating colors. Next, click around. You’ll see that the page continues to work perfectly; all buttons, event handlers, and interactions remain fully intact. Nothing has been compromised.

    This versatility is crucial when blasting user-generated content, which, by its nature, is not necessarily predictably structured. It can be dirtied with HTML.

    Reversal

    When Blast generates wrappers around each of text node’s submatches, it assigns each wrapper a “blast” class. This class is later referenced when Blast is reversed.

    Blast reversal is triggered by passing in false as Blast’s sole parameter. The reversal process works as follows: The DOM is traversed, but the elements it’s looking for are element nodes (not text nodes) that have been assigned the “blast” class. Each matched element node is then replaced with its inner HTML.

    For example, reversing Blast on the following HTML…

    <div id="helloWorld" class="blast-root">
        <span class="blast">Hello</span>
        <span class="blast">World</span>
    </div>

    … using the following syntax…

    $("#helloWorld").blast(false);

    …will result in Blast descending into #helloWorld, matching each element node individually, then substituting these element nodes with the text nodes that they contain — “Hello” and “World”, respectively.

    After this process, our DOM is back to exactly where it was before we Blasted it. This ability to cleanly reverse allows us to jump into arbitrarily structured HTML, Blast it apart, run a series of typographic animations, then reverse Blast upon completion so that our markup remains clean and structured as originally intended.

    Let’s do just that:

    See the Pen Blast.js – Command: Reverse by Julian Shapiro (@julianshapiro) on CodePen.

    Accuracy

    We’ve established that Blast preserves HTML by touching only the relevant nodes (text nodes). Now let’s explore how Blast is able to pull off this next trick:

    See the Pen Blast.js TypeKit Article – Accuracy by Julian Shapiro (@julianshapiro) on CodePen.

    Remember, when a descendant text node is found in an element node targeted by Blast, the chosen delimiter’s RegEx is executed against it. Let’s examine each delimiter, starting with the simplest: character.

    (Note that you can follow along with these examples by clicking the demo buttons under the Robustness Gallery section of Blast’s documentation. You can also visit RegEx101.com to test the following RegEx queries against your own bodies of text.)

    The RegEx for the character delimiter is simply /(\S)/, which treats every non-space character as a submatch (a submatch is the part of the text node that gets wrapped by a newly-generated element). Simple enough.

    Next, the word delimiter uses this RegEx: /\s*(\S+)\s*/. This matches any non-space character surrounded by either a space or nothing (nothing is the edge case where a word appears at the beginning or ending of a text node). Specifically, \s* means “optionally match a space character”, and the \S+ in the middle means “match as many non-space characters as possible.” Note that the word delimiter matches will include any punctuation that’s adjoined to the word, e.g. “Hey!” will be a full match. For the vast majority of use cases, this is more desirable than treating every adjoined punctuation as its own word.

    Now things start to get more complex. It’s trivial to match characters and space-delimited words, but it’s tricky to robustly match sentences — especially in a multilingual manner. Blast’s sentence delimiter delimits phrases either 1) ending in Latin alphabet punctuation (linebreaks are not considered punctuation) or 2) located at the end of a body of text. The sentence delimiter’s RegEx looks like this:

    (?=\S)(([.]{2,})?[^!?]+?([.…!?]+|(?=\s+$)|$)(\s*[′’'”″“")»]+)*)

    Below is an expanded view (with spacing) for better legibility:

    (?=\S) ( ([.]{2,})? [^!?]+? ([.…!?]+|(?=\s+$)|$) (\s*[′’'”″“")»]+)* )

    Let’s break that down into its components:

    • (?=\S) The sentence must contain a non-space character.
    • ([.]{2,})? The sentence may begin with a group of periods, e.g. “… that was a bad idea, Tom!”
    • [^!?]+? Grab everything that isn’t an unequivocally-terminating punctuation character, but stop when the following condition is reached…
    • ([.…!?]+|(?=\s+$)|$) …match the last occurrence of sentence-final punctuation or the end of the text (optionally with trailing spaces).
    • (\s*[′’'”″“")»]+)* After the final punctuation is matched, also include any and all pairs of (optionally space-delimited) quotes and parentheses.

    That’s quite a bit to to digest, but if you refer to those RegEx components while revisiting the sentence matching behavior from the top of this section (re-embedded below for convenience), you’ll start to see how the larger pieces come together.

    See the Pen Blast.js TypeKit Article – Accuracy by Julian Shapiro (@julianshapiro) on CodePen.

    (Click on the HTML tab to modify the HTML and see how Blast behaves on different bodies of text.)

    We still haven’t explained why that embedded demo’s errant periods aren’t falsely triggering the end of a sentence match: The trick is to perform a pre-pass on each text node — prior to the primary RegEx execution — in which likely false positives are rendered inert by temporary encoding them into non-matching strings. Then, after the sentence RegEx is executed, the likely false positives are decoded back to their original characters.

    The false positive encoding process consists of replacing a punctuation character with its ASCII equivalent inside double curly brackets. For example, a likely false positive period (e.g. one found in the title “Mr. Johnson”) will be turned into “Mr{{46}} Johnson”. Then, when the sentence delimiter’s RegEx is executed, it skips over the {{46}} block since curly braces aren’t considered Latin alphabet punctuation.

    Here’s the logic behind this process:

    text
    /* Escape the following Latin abbreviations and English
       titles: e.g., i.e., Mr., Mrs., Ms., Dr., Sr., and Jr. */
    .replace(RegEx.abbreviations, function(match) {
        return match.replace(/\./g, "{{46}}");
    })
    /* Escape inner-word (non-space-delimited) periods.
       For example, the period inside "Blast.js". */
    .replace(RegEx.innerWordPeriod, function(match) {
       return match.replace(/\./g, "{{46}}");
    });

    So now you have an overview of Blast’s behavior, but you haven’t learned that much. Not to worry, the next two sections get super technical.

    Deep dive: Regex

    This section is optional. This is a technical deep dive into how Blast’s RegEx queries are designed.

    This is the RegEx code block that you can find at the top of Blast’s source code:

    var characterRanges = {
            latinLetters: "\\u0041-\\u005A\\u0061-\\u007A\\u00C0-\\u017F\\u0100-\\u01FF\\u0180-\\u027F",
        },
        Reg = {
            abbreviations: new RegExp("[^" + characterRanges.latinLetters + "](e\\.g\\.)|(i\\.e\\.)|(mr\\.)|(mrs\\.)|(ms\\.)|(dr\\.)|(prof\\.)|(esq\\.)|(sr\\.)|(jr\\.)[^" + characterRanges.latinLetters + "]", "ig"),
            innerWordPeriod: new RegExp("[" + characterRanges.latinLetters + "]\.[" + characterRanges.latinLetters + "]", "ig"),
        };

    The first step is to define the UTF8 character ranges within which the letters used by all the Latin alphabet languages are contained. If that string looks like total gibberish to you, fear not: Character representation systems associate an ID with each of their displayable characters. RegEx simply allows us to define a range of ID’s (place a “-” between your first character’s ID and the last character’s ID). We take advantange of this by collating a bunch of ID ranges together in order to skip past ranges that contain characters that aren’t used in everyday language (e.g. emoticons, arrow symbols, etc.).

    Once we know what all the acceptable characters are, we can use them to create RegEx queries:

    The abbreviations RegEx looks for case-insensitive whitelisted abbreviations (e.g. Mr., Dr. Jr.) that are not immediately preceded by one of the accepted characters. In other words, it wants to find where these abbreviations are preceded by either nothing, a space, or a non-letter character. For example, we don’t want to match “ms.” in “grams.”, but we want to match “ms.” in “→Ms. Piggy”. Likewise, the RegEx query ensures that the abbreviation is also not immediately followed by a letter. For example, we don’t want to match “e.g.” in a corporation’s name abbreviation such as “E.G.G.S.”. But, we do want to match “e.g.” in “… farm animals, e.g. cows, bigs, etc.”

    The inner-word period RegEx looks for any period that’s sandwiched immediately between a whitelisted Latin alphabet letters on either side. So, the period inside “Blast.js” successfully matches, but the period at the end of “This is is a short sentence.” successfully does not.

    Deep dive: DOM traversal

    This section is optional. This is a deep dive into how text node traversal works.

    Let’s take a look at the recursive DOM traversal code:

    if (node.nodeType === 1 && node.hasChildNodes()
        && !Reg.skippedElements.test(node.tagName)
        && !Reg.hasPluginClass.test(node.className)) {
        /* Note: We don't cache childNodes' length since it's a live nodeList (which changes dynamically with the use of splitText() above). */
        for (var i = 0; i < node.childNodes.length; i++) {
            Element.nodeBeginning = true;
     
            i += traverseDOM(node.childNodes[i], opts);
        }
    }

    Above, we check that the node…

    • Has a nodeType of 1 (which is the ID associated with an element node).
    • Has child nodes for us to crawl.
    • Is not one of the blacklisted element node tags (script, textarea, and select), which contain text nodes, but not that typical kind that users likely want to be blasted.
    • Isn’t already assigned the “blast” class, which Blast uses to keep track of which elements it’s currently being used on.

    If the above conditions aren’t true and if the nodeType is instead returning a value of 3, then we know we’ve hit an actual text node. In this case, we proceed with submatch and element wrapping logic. Refer to the inlined comments for a thorough walkthrough:

    /* Find what position in the text node that our
    delimiter's RegEx returns a match. */
    matchPosition = textNode.data.search(delimiterRegex);
     
    /* If there's a RegEx match in this text node, proceed
       with element wrapping. */
    if (matchPosition !== -1) {
        /* Return the match. */
        var match = node.data.match(delimiterRegex),
            /* Get the node's full text. */
            matchText = match[0],
            /* Get only the match's text. */
            subMatchText = match[1] || false;
     
        /* RegEx queries that can return empty strings (e.g ".*")
           produce an empty matchText which throws the entire
           traversal process into an infinite loop due to the
           position index not incrementing. Thus, we bump up
           the position index manually, resulting in a zero-width
           split at this location followed by the continuation
           of the traversal process. */
        if (matchText === "") {
            matchPosition++;
        /* If a RegEx submatch is produced that is not
           identical to the full string match, use the submatch's
           index position and text. This technique allows us to
           avoid writing multi-part RegEx queries for submatch finding. */
        } else if (subMatchText &amp;&amp; subMatchText !== matchText) {
            matchPosition += matchText.indexOf(subMatchText);
            matchText = subMatchText;
        }
     
        /* Split this text node into two separate nodes at the
           position of the match, returning the node that begins
           after the match position. */
        var middleBit = node.splitText(matchPosition);
     
        /* Split the newly-produced text node at the end of the
           match's text so that middleBit is a text node that
           consists solely of the matched text. The other
           newly-created text node, which begins at the end
           of the match's text, is what will be traversed in
           the subsequent loop (in order to find additional
           matches in the containing text node). */
        middleBit.splitText(matchText.length);
     
        /* Over-increment the loop counter so that we skip
           the extra node (middleBit) that we've just created
           (and already processed). */
        skipNodeBit = 1;
     
        /* Create the wrapped node. Note: wrapNode code
           is not shown, but it simply consists of creating
           a new element and assigning it an innerText value. */
        var wrappedNode = wrapNode(middleBit);
     
        /* Then replace the middleBit text node with its 
           wrapped version. */
        middleBit.parentNode.replaceChild(wrappedNode, middleBit);
    }

    This process isn’t tremendously performant when used on a large bodies of text with a delimiter that produces a lot of small matches (namely, the character delimiter), but it’s phenomenally robust and reliable.

    Wrapping up

    Go forth and blast shit up ;-) If you create something cool, please post it on CodePen and share it in the comments below.

    Follow me on Twitter for tweets about UI manipulation.