Skip to content
Header image for Shipping a Studio Tool: What We Learned Building Gradient Galore
Engineering

March 23, 2026

4 min read

Shipping a Studio Tool: What We Learned Building Gradient Galore

B

Blue Monkey Makes

We shipped Gradient Galore in a few weeks. Not because we rushed it, but because we made a series of deliberate choices that kept scope tight and momentum high. Here's what we learned.

Start with the thing that doesn't exist

Every gradient generator we tried handled linear and radial gradients well. Some handled conic. None of them handled aura gradients — layered radial blobs with independent controls per layer. That was the gap. That was our starting point.

We didn't set out to build "the ultimate gradient tool." We set out to build the aura gradient editor we needed for a client project. Everything else grew from there — but always in service of the original use case.

If you're building a studio tool, start with the thing you actually need that doesn't exist. Not the thing that would be cool. Not the thing that has the best market opportunity. The thing you'll use tomorrow.

The stack decisions

React Router 7 was the framework choice. We already use it for client projects, so there was zero ramp-up time. SSR by default meant the gallery pages load fast, and the route-based loaders/actions pattern kept server logic clean.

Tailwind CSS 4 for styling. We have a strict rule: no arbitrary bracket values. Everything uses named sizes and design tokens. This keeps the codebase scannable and prevents the kind of one-off values that make maintenance painful.

Jotai for client-side state. The gradient editor has a lot of interactive state — colour stops, aura points, mesh points, easing curves, noise settings. Jotai's atomic model meant we could share state between the preview, the controls sidebar, and the palette strip without prop drilling or context overhead. The state also persists to localStorage automatically, so your work survives a page refresh.

Drizzle ORM with PostgreSQL for the gallery and palettes. We wanted persistence without the overhead of a full backend. Drizzle gives us type-safe queries with minimal boilerplate. PostgreSQL runs in Docker for local dev and deploys anywhere.

No external colour libraries. The OKLCH conversion, shade generation, harmony calculations, and contrast checking are all written from scratch. The entire colour engine is about 400 lines of TypeScript. We didn't want to depend on a library for something this central to the tool — and writing it ourselves meant we understood every edge case.

Things that worked

Building the palette creator as an immersive full-viewport experience. Early versions had the palette creator as a card inside the palettes list page. It was functional but forgettable. Moving it to a dedicated route with full-height colour columns, Coolors-style spacebar randomisation, and a slide-out tool drawer transformed it from a form into an experience. Users spend more time in it. They experiment more. That's the point.

OKLCH everywhere. Every colour operation — shade generation, harmony, adjustments, contrast — runs through the same OKLCH pipeline. This means everything is consistent. A colour you pick in the harmony generator looks the same in the shade scale and behaves the same in the contrast checker. No surprises.

Per-layer visibility toggles on aura and mesh gradients. This was a late addition but immediately became essential. When you're building a complex layered gradient, being able to hide individual layers to see what's underneath is the kind of small feature that makes a tool feel professional.

Smart point placement. When you add a new aura or mesh point, the tool finds the position on the canvas that's furthest from all existing points. No more new points spawning on top of existing ones.

Things we'd do differently

Gallery filtering should have been database-level from the start. We initially loaded all gallery items and filtered in JavaScript. It worked fine with a handful of items, but it's the kind of shortcut that scales poorly. We moved it to database queries before launch, but it would have been cleaner to start there.

The old palette editor route is still in the codebase. When we built the new immersive creator, we redirected all edit links to it but didn't remove the old route. It's dead code. We should clean it up. We haven't yet.

We underestimated how much people would want to reorder colours. Move left/right buttons were a late addition to the palette creator. In hindsight, drag-to-reorder would be even better. That's on the list.

The agency question

People sometimes ask whether it makes sense for an agency to build and release tools like this. Isn't it a distraction from client work?

We think it's the opposite. Building tools forces you to solve problems completely — not just well enough for one project, but well enough to be generally useful. That discipline makes our client work better. And releasing tools publicly shows potential clients how we think and what we care about.

Gradient Galore started as something we needed. It became something we're proud of. And it's already saved us time on two subsequent projects.

If you're running a studio and you keep solving the same problem on different projects, consider building the tool. Not as a product. Not as a business. As a studio tool that you share because someone else probably needs it too.

Try it

Gradient Galore is free at gradientgalore.com. The source is available on GitHub. If you build something cool with it, we'd love to see it.

React RouterTailwindside projectsstudio tools