TL;DR

The problem we were trying to solve

The requirements

Sketch and sketchtool

{ "_class": "sharedStyle", "do_objectID": "49BA4E98-8D63-435C-81D9-E2F6CDB63136", "name": "name-of/the-style", "value": { "_class": "style", "endMarkerType": 0, "fills": [ { "_class": "fill", "isEnabled": true, "color": { "_class": "color", "alpha": 1, "blue": 0.7176470588235294, "green": 0.4627450980392159, "red": 0 }, "fillType": 0, "noiseIndex": 0, "noiseIntensity": 0, "patternFillType": 1, "patternTileScale": 1 } ], "miterLimit": 10, "startMarkerType": 0, "windingRule": 1 } }

Sketchtool

… is a command line utility that’s bundled with Sketch, that allows you to perform some operations with Sketch documents, like inspecting them or exporting assets. It also lets you control Sketch from the command line to perform some actions (like running plugins, for example).

Sketch.app/Contents/Resources/sketchtool/

$ /Applications/Sketch.app/Contents/Resources/sketchtool/bin/sketchtool

Usage: sketchtool <command> [<args>] [--formats=<string>] [--use-id-for-name{=YES|NO}] [--export-page-as-fallback{=YES|NO}] [--serial{=YES|NO}] [--context=<string>] [--application=<path>] [--without-activating{=YES|NO}] [--item=<string>] [--items=<string>] [--safemode{=YES|NO} | --no-safemode | -S {<YES|NO>}] [--max-size=<float> | -m <float>] [--background=<string> | -g <string>] [--compression=<float> | -c <float>] [--new-instance{=YES|NO}] [--reveal{=YES|NO}] [--timeout=<float>] [--include-symbols{=YES|NO}] [--bounds=<rectangle>] [--outputJSON=<path>] [--filename=<string>] [--wait-for-exit{=YES|NO}] [--scales=<path>] [--overwriting{=YES|NO}] [--group-contents-only{=YES|NO}] [--trimmed{=YES|NO}] [--help] [--progressive{=YES|NO}] [--save-for-web{=YES|NO}] [--output=<path>] Commands: dump Dump out the structure of a document as JSON. export artboards Export one or more artboards export layers Export one or more layers export pages Export an area from one or more pages export preview Export a preview image for a document export slices Export one or more slices help Show this help message. list artboards List information on the document's artboards. list formats List the supported export formats. list layers List information on all of the document's layers. list pages List information on the document's pages. list slices List information on the document's slices. metadata List the metadata for a document. run Run a command from a plugin, inside Sketch. show Show the location of the various sketch folders. See ‘sketchtool help <command>’ for more information on a specific command.

The Sketch file(s)

Dynamic colouring the icons with Shared Styles (and Design Tokens)

Pages and artboard names used for AB testing

Multiple files for multiple brands

Using a custom build script in Node JS, it is possible to manipulate a series of Sketch files, and then, using an internal Sketch tool, automatically export their assets, to generate multiple icon libraries, for multiple platforms and different brands, that support dynamic colourisation of the assets via design tokens, and also AB testing of the assets via naming convention. Easy peasy :)Well, actually it’s not that easy, but it can certainly be done. This post is a detailed explanation of how we did it, and what we discovered along the way.At Badoo we build a dating app. Actually, multiple dating apps. For multiple platforms ( iOS Desktop Web ), across multiple teams We use hundreds of icons in our apps. Some of them are the same across different apps, some are very specific to the brands the apps reflect. The icons are continuously evolving, in sync with the evolution of the design. Sometimes completely new icons are added, while others get updated, and still others get dropped (although, they often remain in the codebase).Our design team designs and maintains the icons, and until now the only way for them to provide the correct assets to the different teams, platforms and apps, was to send them via email, chat or dropbox. This is not only time-consuming, but but it’s almost always prone to error. In fact, we found that errors occurred every time (we’re human!): icons would be updated on one platform but not on another; or icons would be missing or in the wrong format or size. So, there was a constant back and forth between designers and developers; developers would export icons directly from the Sketch file, and the icons would get added to the codebase but with no check to see if similar icons already existed (and were available for reuse). I’m sure you know what I am talking about.At Badoo we have a Design System, called Cosmos , and recently we introduced a library of Design Tokens across multiple platforms (Mobile Web, Android and iOS) both for our main app and its white-labels. Essentially, we are now able to communicate design decisions (like the border of a button, the background colour of a particular feature page, the font size of the Heading 1, or the duration of an animation for a popup) using elementary design values, all processed and delivered automatically to all the apps, and all the platforms consuming these design tokens in their apps.How we are now able to transform a design idea, like for example a change of a colour, to real code in production, in just a few clicks and hardly any time at all, has really impressed product managers and designers alike.So, their next question (and request) was: can you do something similar for the assets? And our answer was: yes, we (probably) can!It was quite a leap of faith at the time, I have to admit. We had some ideas of how to do it, but we were not at all sure if it was technically doable, with all the restrictions we operate under. We agreed to start with an MVP project, but by the end everything had gone so well that it became our final product, with all the necessary features.The requirements for the MVP were very clear: create a pipeline that could take a Sketch file and export all the icons included in the file, in different formats, for different platforms, with each icon suitable for use in AB testing.This is complicated because, in our products, one icon can have many different colours and/or different shapes for different brands/white-labels (although the codebase of the app is the same, as well as, the name of the icon).Look at some of the icons used in our applications and you will notice that some are identical, some are very similar to each other but for a few details, while others are quite different, both in their shapes and colours:Now, the colours used in the icons are not just plain colours, but match the exact colours stated in the design tokens for that brand and its specific features:So, our aim with this new assets pipeline was not only to automate the process of generation and delivery of the icons, for all the different platforms and brands, but rather to be able to «dynamically» colour the icons according to the brand/white-label. Sketch is the main design tool that our design team uses. Even though we did consider other options ( Figma , mainly), we knew that Sketch was the format of the source files we were going to be using for this project (simply because it’s the tool our designers are more proficient in, and it’s the format of the files where the existing icons/assets are used, among other reasons).The fact is that, at the beginning of the project we were not even sure what final formats the platforms were expecting. In our minds, the process was going to be pretty basic like this: export the icons in SVG format from the Sketch file and then consume the SVG files in Mobile Web and Android, and for iOS find a library that can convert SVGs to PDFs. And that’s it. That was the plan when we started, although we had no idea if it would work, or about the unknown unknowns we might encounter (hence, the MVP to see if it was even feasible, and, if so, how much effort it might entail).I don’t know if you have ever worked with «PDF converters» but in my experience they are generally a pain. They «almost» do the job, but never to the 100% you really need. So, in the back of my mind, I felt we were treading a dangerous path.Sketch has a way of exporting assets that is pretty much perfect, I’ve never had a problem with it (be it SVG, PDF, or other formats). So I wanted to see if there were any other ways to interact with Sketch, to use its engine to export assets directly via Sketch, possibly in a programmatic way (I was also wondering if a custom plugin could be built, although that would have meant a lot of work for me, not only because I have zero experience in that field!).I knew that internally Sketch is no more than a zip file (if you rename afile to, double-click to uncompress it, and open the resulting folder, you see a list of JSON files, and a bitmap used as preview):So, I started to explore the different JSON files, trying to understand the connections and dependencies between them.I realised that somehow, despite the JSON files being deeply nested (and quite large!), the relations between the different entities inside their objects is not too complicated: you have pages, artboards and layers; inside the layers you have the paths, and you can have shared styles between them; each one of these entities has a unique ID that is used to keep a reference between the different files; and all the «page» objects are saved in JSON files, stored in a sub-folder called, with the ID of the page used as name of the file.One significant discovery I made, during this exploration, was thatThe thing that matters is the unique ID assigned to them, and this is never exposed to the end user (although, can be read and referenced inside the JSON files). Here is an example of how the unique ID of a style looks like:This gave me an idea: that maybe we could use specific conventions on the names of the artboards and of the pages, to declare some kind of meta-information about the relations between the different assets, and use them programmatically at build time.At this point, by the end of the initial explorations, the plan had changed fromto. But even then, the plan was still very blurred (and the technical feasibility was still uncertain).It was while I was looking at existing plugins, specially at their source code, to see if and how they might interact with the Sketch export APIs, that I came across a tool that I’d never heard of before: Sketchtool.Sketchtool is an official Sketch tool (official as in: developed by Bohemian Coding), which according to the documentation Hang on… ato perform operations like? Just, what I was looking for! Also, being an official tool, there wouldn’t be any problems of versions, obsolescence, maintenance, etc.I started to look into it immediately, and read the documentation, which amounted to just a single page on the Sketch website (I’ve found hardly any other resources or pages about it out there, so it’s understandable that I’d never heard of it)Sketchtool is bundled directly with Sketch, and you can find it inside Sketch at this path:When you launch it in your CLI with the command:this is the output you see on your terminal (I have simplified it a little):As you can see, the tool has four main functions: tothe metadata of the internal JSON files; tothe entities inside a file; tothese entities; and toa command exposed by a plugin. In addition, each command has a lot ofavailable. In the case of the export command, almost all the options you find in theare also available via Sketchtool’s command line:This means that Sketch can be used directly as export «engine» via, without the need for external converters (from SVG to PNG or PDF, for example). Big deal!A quick test usingand a simple Sketch file with a few icons inside, confirmed all the initial suppositions: just by using this simple tool, we can avoid both using third-party exporters and building our own custom exporters: Sketch does it all!Once we knew that Sketch was the tool we were going to use, for both storing and exporting the icons, it was time to actually collect the icons used in our applications into a Sketch file.Initially, we only planned to work with a limited set of icons, those for the MVP project, but we quickly realised that it would have been better to collected them all at once, to be able to immediately spot duplicates, inconsistencies, any omissions, etc.Our designers did an incredible job and in just a couple of days a large part of the assets used in their Sketch files has been collected and organised into a single file. At this point, the Sketch file looked like this:In the file, each icon has its own artboard, named with the desired name of the icon (later to be used by Sketch as file name when exporting the assets).All the paths are converted to outlines, and the combined paths (generally asor) are flattened to a single shape. This ensures that the generated assets maintain the perfect visual appearance they have in the source file, and optimum compatibility with the various platforms.Once we had collected the icons, the next step was to apply the right colours to them. What we did was create a set of pre-defined Shared Styles in Sketch , with names that matched those of the design tokens used in our design system, and then use them to apply colours to the icons.This is how a style is applied to a layer:And this is how the styles are declared and then applied to an element:The naming convention is very important here. The designers can organise the styles in any sub-folders, providing the name of the style itself matches the name of the corresponding design token for that colour. This is, so it can be referenced programmatically by the build script later on.At this point, it was time to understand how to ensure the designers would be able to carry out AB testing on the icons. Once again, in the end we decided to rely on naming conventions (big fan of K.I.S.S. here).In this case, we used theto detect when a set of icons was an AB test/experiment (using "as prefix) and theto detect which asset the AB test was referring to, and its different variants (enclosed within square brackets).:)The names used for the tests and the variants are not generic names: they must match theassigned to the experiments/variants in our internal user-split tool. In this way, the assets can later be correctly associated with the correct AB test user group.The last piece of the puzzle was: how do we support different shapes of the same icon, for different brands?This was, and we had various options available to use. At first, we thought of using different pages in the same Sketch file, with different page names for each brand; but soon we realised it would made it much more complex and more difficult for the designers to keep the icons in sync between the different brands. So we concluded that the solution was to have multiple files: a, where we stored all the icons that were identical for the different brands, andfor icons that werethe «base» icons in the common file.At this point the Sketch files were ready. We were ready to start writing code.