Sketching in the Browser
Ask any team that works with a design system, and youâll find the benefits are clearâdesigners and developers are more productive, products are more consistent, communication between disciplines is clearer.
However, most design systems still have a fundamental flaw. Designers and developers continue to work in entirely different mediums. As a result, without constant, manual effort to keep them in sync, our code and design assets are constantly drifting further and further apart.
For companies working with design systems, it seems our industry is stuck with design tools that are essentially built for the wrong mediumâcompletely unable to feed our development work back into the next round of design.
Luckily, this is all about to change.
Our design system journey
At SEEK, weâve been working on our living style guide for over a year now, with an ever-growing suite of React components. As you might expect, this has introduced a radical shift in how we think about visual design.
Suddenly, we had a single source of truth, in code, easily installable, defining how our brand appears across dozens of disparate projects.
Naturally, our design system work didnât begin in the browser. Weâd already spent a lot of time trying to formalise our design rules in a more static formâlong before our living style guide ever existed.
What began as a static PDF eventually gave way to a Sketch starter kit. Standardised symbols, colours and text styles could be easily leveraged as the starting point for any new design work.
Some time later, we experimented with Craft, a suite of Sketch plugins from InVision, the most notable being their Library plugin.
This allowed us to share Sketch symbols across both document and team boundaries, building a shared symbol library for the entire organisation.
What became immediately apparent was the sheer amount of work required to keep this library up to date, particularly when new and existing patterns are constantly evolving across our products.
Developers, often pairing with designers, would make changes to the code that could have a dramatic impact on the visual design, but our static design library would remain completely untouchedâunless, of course, someone remembered to manually keep it to date, which usually didnât happen.
Meanwhile, we were experiencing exactly the same consistency problems on the other side of the fence, with developers lacking a clear source of truth for design in their code.
From React to react-sketchapp
It was around this time that we began work on our first React projectâserver-rendered, powered by webpack, and CSS Modules (which we helped co-create along the way)âeventually leading to the creation of our living style guide.
Reactâs singular focus on components made this transition almost inevitable. Itâs no surprise that, since its release, weâve seen similar stories play out at countless other companies around the world.
Once weâd built up a sizeable collection of components, other teams working on new projects were quick to capitalise on our workâbut since our style guide consisted of React components and Less styles, it was of little use to our designers. However, this didnât stand out as an immediate issue to us. The technical disconnect between designers and developers is an age-old problemâone thatâs been with our industry for so long that weâre largely trained to ignore it.
That was, of course, until we saw react-sketchapp.
âIn Sketch, we use symbols and overrides, in React we use components and properties. The concepts are so similar that it seemed silly not to unify them.â
We couldnât believe our eyes. Here we had real React code, rendering directly into Sketch. It seemed that both developers and designers would finally be able to leverage a design systemâs single source of truth.
With our design rules defined centrally in code, weâd not only be able to power our production applicationsâweâd also be able to feed our work back into the tools that our designers were already using. As our design rules continued to evolve, weâd automatically be able to keep our designers up to date, without any manual translation back to Sketch.
Of course, once we dug in a bit further, we discovered that react-sketchapp came with a few requirements.
- Components needed to be built with React (obviously). Luckily, we were already using React, so this wasnât a problem.
- Styles needed to be defined in JavaScript. In our case, since our design system was built with CSS Modules, weâd already hit a bit of a hurdle. Weâre big fans of CSS-in-JS, but we werenât about to overhaul our styling across the entire ecosystemânot in any hurry, at least.
- Components needed to use generic primitives (View, Text, StyleSheet) rather than browser primitives, using something like react-primitives. Essentially, react-sketchapp was closer to React Native than vanilla React. Again, this is something that we could feasibly migrate to, but it would require a lot of workâand possibly a few tradeoffs along the way.
So, while react-sketchapp is an amazing project that we wholeheartedly recommend, its technical requirements unfortunately meant that we wouldnât be able to make use of it in the short-to-medium term.
Even if we decided to migrate our component library, we needed another answer in the meantime.
Bringing design to version control
As you may already know, there are tools available now that allow you to use version control inside of your design toolsâbut this is completely backwards.
We need to bring our design tools to version control, not the other way around. We need design assets to sit side-by-side with any other asset typeânot stored in a design-centric silo, hosted in a proprietary walled garden.
So we tried something different.
Using Kactus and some custom Node scripts, we experimented with committing Sketch files into our style guide repository.
While we were able to achieve this technically, we were disappointed to find that the workflow never worked out the way weâd hopedâfor our use case, at least. Keeping two radically different formats in sync was extremely tedious, error prone, and difficult to review.
Maintaining code and Sketch files in the same location may have helped make the problem clearer, but it didnât help much in actually solving the problem. To make matters worse, it introduced a lot of extra friction for style guide contributors for seemingly little gain. The Sketch files were quickly neglected. For us, it was a failed experiment.
But thenâjust when we felt like weâd lost hope in bringing designers and developers together in the same projectâhtml-sketchapp came along and changed everything.
The emergence of html-sketchapp
It turned out that we werenât the only ones having trouble integrating react-sketchapp into their existing tech stack.
âWe were unable to quickly work around these limitations, so we created html-sketchapp.â
With html-sketchapp, they took a radically different approach.
As the name would suggest, html-sketchapp lets you generate Sketch files from regular HTML contentâbut unlike react-sketchapp, there are no restrictions on the technology choices in your application.
You could build your app with Preact, or Vue, or Angular, or Backbone, or jQueryâor even Ruby or PHP.
You could still use React, of course, but now you could style it however you like, using whatever primitives made sense for your project.
The contract was incredibly straightforwardâas long as you generated HTML, you could import it into Sketch.
Generating Sketch files
At first glance, this seemed like magic, but when we had a look under the hood, we quickly found that itâs actually not that complicated.
To understand how html-sketchapp works, you first need to understand Sketchâs file format. Surprisingly enough, Sketch files are really just Zip files.
Once upzipped, Sketch files are mostly made of JSON files which, of course, can be opened in any regular text editor.
If you have a look at the contents of these files, youâll see that itâs a relatively simple format, essentially made from a small handful of nested classes.
At its lowest level, html-sketchapp allows you to programmatically generate instances of these classes and convert them to JSONâbut it goes much further than that.
The most powerful function in html-sketchapp is ânodeToSketchLayersâ, which gives you the ability to convert a single browser element into an array of Sketch layers. This is where most of the magic happens, since it contains all of the logic for extracting browser styles and converting them into their Sketch equivalents.
What really brings this all together is the âSymbolMasterâ class, which allows you to dynamically generate Sketch symbols. Since symbols form the basis of any Sketch library, this allowed us to selectively expose a set of components to our designers, based directly on the underlying code.
Unfortunately, due to some limitations in the current Sketch format with how text styles are encoded, the generated documents arenât quite valid Sketch filesâhtml-sketchapp refers to them as âAlmost Sketchâ files, or âasketchâ for short. As a result, they need to be manually imported via html-sketchappâs Sketch plugin. Thankfully, this process isnât too difficult.
Wiring all of these steps together sounded somewhat daunting at first, but it turned out that there was already an example project on GitHub showing how to convert an existing style guide into a Sketch document.
As soon as we saw this, it didnât take us long to start experimenting, and it took a surprisingly small amount of time before we started seeing truly startling results.
Experimenting with html-sketchapp
First, to get a feel for what was possible, we pointed it at the home page of our style guideâs website.
Next, we started generating our first symbols from our âButtonâ component, rendering a few different variants.
To achieve this, we came up with a convention of adding a special JavaScript file within each component folder (e.g. Button.sketch.js), defining the symbols that we wanted to export.
Each file would export an object defining the symbol names and their corresponding React elements.
import React from 'react';
import Button from './Button';export const symbols = {
'Button/Pink': <Button color="pink">Button</Button>,
'Button/Blue': <Button color="blue">Button</Button>,
'Button/Transparent': <Button color="transparent">Button</Button>,
};
We then created a special hidden route on our style guide site which imported any file ending in â.sketch.jsâ and rendered the supplied React elements to the screen. Taking this approach, we were able to greatly simplify the conversion process by exposing all Sketch content on a single page.
Each symbol instance was wrapped in a div element with its name defined in a data attribute, which allowed us to easily select and name every symbol on the page.
<div data-sketch-symbol="Button/Pink">
...
</div>
This pattern proved to be very effective, and we soon expanded it to include text styles and document colours.
Since our style guide is responsive, we then automated the process of resizing the browser window and taking symbol snapshots at different screen sizes.
We could now add, remove and rename viewport sizes in a single location, and every single symbol would be regenerated to reflect these new values. In one fell swoop, it seemed that weâd solved one of the most tedious issues with maintaining a responsive Sketch library.
While everything went surprisingly smoothly, we did have to add a few workarounds specifically to support Sketchâin the same way that you might support buggy browser implementationsâbut we managed to localise them to a single file.
From experiment to production
What started as a small-scale experiment had quickly snowballed into something of a mini-framework. At this point, it didnât take much work for us to get it properly integrated into our style guide, running as part of our standard build process.
If you look at the pull request, however, youâll see that it required us to include a lot of extra wiring code and dependencies, even thoughâat a high levelâwe were trying to achieve a single, conceptually simple task.
To generate our Sketch library, we had to perform the following steps:
- Compile a browser script with webpack, containing html-sketchapp and accompanying logic for selecting and converting elements.
- Start a static web server on any available port.
- Open Puppeteer (a headless version of Chromium).
- Navigate to the correct URL.
- Inject the compiled script into the running Puppeteer instance.
- Resize the browser window multiple times, taking snapshots at each configured screen size by calling the functions defined in our compiled script.
- Write the resulting JSON files to disk.
- Shut down the static web server.
- Shut down the headless browser.
It seemed obvious to us that this could easily be streamlined in a single commandâone which would allow us to simply point to a URL and start taking snapshots.
So thatâs what we did.
Unveiling html-sketchapp-cli
Less than a month after we first integrated html-sketchapp into our style guide, we open sourced html-sketchapp-cli, a small command-line utility to take all of this plumbing code off your hands.
Now, we could achieve the same thing with a single dependency and a simple, declarative config file.
module.exports = {
serve: 'docs/dist',
url: '/sketch-exports',
outDir: 'dist/asketch',
viewports: {
'Desktop': '1024x768',
'Mobile Plus': '414x736',
'Mobile': '320x568'
}
};
Not surprisingly, when we used html-sketchapp-cli in our style guide, we were able to delete a lot of code.
Continuous design pipeline
All of this tooling is now part of our standard continuous delivery pipeline, allowing us to expand the reach of our codeâmoving beyond the developer community and supporting our designers in their daily work.
On every successful build of the style guideânot only do we automatically deploy our site to GitHub pages (using gh-pages) and publish the component library to npm (using semantic-release)âwe now automatically generate âAlmost Sketchâ files, ready to be imported and converted into our official Sketch library.
This Sketch library then gets distributed via our design teamâs shared drive, which means that our designers always have an up-to-date copy of the library, syncing in real-time, even while Sketch is open.
Thanks to Sketchâs new built-in library support, designers are immediately able to open up the âSEEK Style Guide Libraryâ menu and start selecting components, knowing that the naming conventions and visual styling match the expectations of the developers on their teams.
Ever since this was introduced, weâve seen changes to our code continuously flowing through into Sketch â sometimes when those making the changes donât even have Sketch installed on their machines. Since the style guide is connected to our production applications, itâs constantly being improved upon from people all over the organisation, and we can now ensure that all of those improvements continue to keep our Sketch library fresh and up to date.
Even if theyâre technically still working in different mediums, weâre working hard to create the illusion of a single unified language.
So, where to from here?
As great as this development has been for us, weâre still only viewing this as an interim solution. Rendering web content into Sketch is incredibly powerful, and a necessary step forward on our journey, but our industry needs to take this even further.
The line between our mediums may be getting blurry, but the design tools of the future need to remove this line altogether. For us to truly deliver on this potential, we need design tools that donât merely imitate the target mediumâwe need them to be actually built on it.
Fortunately, thereâs no shortage of people working on this problem right now. Tools like Compositor, Interplay, Alva, Haiku, Webflow and UXPin are looking to break down the technical walls between design tools and the underlying code, and there are more tools like this on the way.
Who knowsâwe may even start to see more traditional design tools adopt this approach in order to stay relevant, particularly as design systems continue to become a standard part of the modern design toolkit.
In the meantime, while we wait for new design tools that truly embrace the principles driving the design systems era, projects like react-sketchapp and html-sketchapp are doing an astounding job of getting us ready for this new way of thinking today.
Frankly, thereâs never been a better time to start.