Building internal tools with AI
One way that our digital experience platform, LifeHub, works to build products is that it defines a set of components once, and can then reuse them across multiple products. When a component gets an upgrade, all products get that upgrade.
The styling of components works similarly. We’re a web-based platform, so the styling is all based on CSS variables.
To manage this, around 5 years ago I set up an internal tool I’ve come to refer to as ‘Styler’. It began as a single database table and a single piece of javascript.
- The table holds a column of variables, and multiple columns of values - one for each product style that LifeHub needs to emulate.
- The script concatenates the variable names with any one product and generates a css file that can be uploaded to the server.
It’s a homegrown solution, and not the most common approach. Most people in the design system world base their variables in Figma, and maybe a DTMS (Design Tokens Management System). LifeHub requires something more unique.
Software that does everything we need, and nothing we don’t
Figma is clearly a valuable tool for businesses worldwide with the features it provides: multiplayer for collaboration, an intuitive component system, the ease of making prototypes.
But one specific area falls short for our needs: Its styling options.
Figma’s right-hand sidebar offers just enough control over each layer to mock up drawings, but the options there are a subset of what CSS can achieve to style web apps. And that subset is far too limited.
Styler can make use of the full CSS grid capability, dynamic units like dvh, calc() functions, iOS safe-areas… the whole mixed bag of CSS is available. And we do use it. Figma just cannot create a frame with enough layout logic to keep up.
If we were to use the most common tooling approach, Figma variables and Token Studio, we’d be limiting our styling capabilities to only what Figma have decided to offer. We’d have a fast handoff to developers, but be at the mercy of what Figma’s Product Managers decide to ship.
Styler is my attempt at giving us enough styling capability, even at the cost of a slower styling process as Figma is decoupled from our front end.
Problems after years of use
Speed of operations is a critical factor for all product teams. And while I’ve managed to maintain enough pace working with Styler for a good few years, as our business has grown and our work has become more complex the Styling process has become more of a bottleneck.
After analysing the Styler system in more detail, and examining whether other off-the-shelf SaaS products could cover the functionality we need, I concluded that custom software was still the way to go. With AI as a coding assistant, it’s entirely possible to now build software that does everything we need, and nothing we don’t.
Given that Styler was such a bare-bones and simple implementation, the real problems to solve were in how we work with it. Designers were spending too much time:
- Getting CSS files into the server
- Assigning values to the thousands of variables now in the table
- Figuring out which variables to modify
- Tracking down typos that cause invalid code
It’s tempting to imagine a world where AI can do all of this for us. I have some epic plans brewing around this notion, but I wanted some fairly immediate results so opted to use AI to help me build features to the Styler system and speed up the manual work.
Publishing CSS files into the server
This was the first problem I tackled as the publishing is a high frequency action, plus the solution seemed simple: Write a script that takes data from the raw table & publishes CSS to the server using the least manual effort possible. I had one of our developers build me an API endpoint for this specific case. My Rapid Publishing script packages up the CSS and sends it to the API which uploads the file to the correct server folder and clears the front end cache.
Publishing CSS had grown in complexity over the years until it required logging into 5 separate admin tools, having numerous browser windows open, 23 clicks and about 3 mins of elapsed time per publish. This was a process we did many times per styling session, and those clicks, windows and minutes all add up. The problem is not only total amount of time spent, but also cognitive load and a risk of making mistakes each time.
Today, designers can publish their CSS with 2 clicks, in only 14 seconds.
Much better. Now, onto the second problem…
Assigning values to variables
This forms the bulk of our styling process. Because we’re not connecting Figma variables to our front end, modifying variable values required uploading the CSS file to see if the changes made were what we intended. We were styling product while essentially blind to what those values would actually do. The new Rapid Publishing feature helped here, but I had an idea to go one step further.
I built a feature I call Live Preview. Imagine the server styles as a painting, those styles are baked into the actual canvas. Live Preview is like a sheet of glass on top, with some parts painted over to cover the canvas beneath. Designers make a change to a value in the table, which gets instantly pushed to the front end as an override to the existing styles.
To enable this I built a custom Chrome extension which can modify anything on the current webpage. It takes roughly 2 seconds (the absolute speed limit of such a system as it requires an API call in the backend) to push value changes through to the front end, giving designers a much faster feedback loop, and with no extra clicks, thus solving the blind styling problem.
Today, once happy with what Live Preview is showing them on the front end, designers can publish their work in in 2 clicks and 14s, which then clears all the Live Preview overrides to keep the table styles & server styles neatly in sync.
There are more heavy-hitting AI approaches to this part of the styling process, but the setup will be equally as heavy so those are coming in a future phase of DesignOps engineering work.
On to the next problem…
Which variables to modify?
Styler’s table is well structured and fairly well organised. But, over the years, the way some variables have been named by different designers and the way components have been coded by different developers has introduced some oddities.
To tackle this, we’ve been using Chrome Dev Tools to inspect elements and check what variables are applied to them. It works, but it’s a slow approach as it requires clicking through variables that reference variables that reference variables… until you get to the final value. Somewhere in that chain of variables is the variable we want to modify. And it could be in the default styles, or in some page-level override.
To improve our approach, I added functionality to our Styler Chrome extension to instantly reveal the entire variable chain for all properties of a selected element in a way that’s faster to digest. I call it Styler Inspect.
Today, designers can use Styler Inspect to examine any element on the web page and answer the questions they have in their minds: What variables are available to affect this element? Which are having an impact right now? Where do I find them in the Styler table?
Styler Inspect cuts out all the visual distraction and interaction steps of using Chrome’s native dev tools. Everything is laid out in one flat, scrollable view. It even supports dark mode for those prone to screen-induced migraines.
Diagnosing & fixing bugs
The new features I’d built so far were all fine & dandy assuming the CSS code actually worked. But with such a large table of manually edited values, it’s inevitable that bugs creep in due to typos that break the CSS syntax & make it invalid.
We used to catch these when manually saving a CSS file into VScode, but Rapid Publishing skips this step. This left us unaware of errors and in no position to fix them.
In the original script that generated CSS I’d added some logic to look for common typo errors & fix them automatically - missing colons & semi-colons. But there are many other ways in which code can become invalid and we can’t predict them all. Plus, years of the script fixing our errors upon generating the code had left those errors peppered throughout the table. I’d carried this approach through to the Rapid Publishing feature too.
However, I felt it was a better approach to remove this silent-patch logic from Rapid Publishing in favour of a new feature to check for issues throughout the table, and list them in a sidebar so we can see how many times we’ve made errors. Then we could run an auto-fix function to clean up the table properly.
This results in designers becoming more educated on what errors are most commonly made, enables us to catch a wider array of error types, doesn’t add significantly to the time it takes to fix them, and leaves us with a cleaner table of data that will be more friendly to future AI processing.
Peeking under the hood
Throughout the two weeks it took me to build these features, I learned some interesting approaches for AI assisted coding.
With the right process I found AI to be not just efficient but consistent at helping me understand technical concepts and boundaries, consider edge cases, debate best practice, ensure code is secure, diagnose bugs, and test everything is working as intended.
I learnt about SPDD (Structured Prompt Driven Development), which led me to an even more interesting methodology that I’ve begun using to build systems that can help in other areas of our design operations.
There’s a lot of detail to explain here, and so I’ll go deep on that subject matter in a separate article soon.

About the author
Hi, I'm Rob
I make digital products that help improve people's lives.
After working my way up to the top of the design function in my earlier years, I began a broader role with a new startup - Life Moments - in 2018.
I've been a pivotal force in shaping and operating the business from its inception to profitability and beyond.
Find out more about my career.