← back to work
case study · macOS app

Quip: making an invisible action tell the truth.

Quip finds a GIF and copies it in a second. The screen never shows the copy happen, so the design has to prove it did.

A menu-bar GIF picker. Search, click a result, and it lands on the clipboard.
Client A personal project
Sector Software, consumer desktop (a macOS menu-bar utility)
My Role Product and interaction design, usability testing, native build, sole author and maintainer
Team Built solo
Duration July to August 2026 · 17 releases, 16 in the first 11 days
Methods Interaction design, usability feedback (Reddit comments, direct messages, in-person observation), attention to legibility across light/dark and busy backgrounds, native macOS (SwiftUI) build, release engineering
Outputs A shipped, notarized, self-updating macOS app · open source
Permissions Personal project, open source

The two GIF tools I relied on stopped being updated.

Finding a GIF and getting it into a chat is a small job. Two apps used to do it, and both were abandoned.

The two were InaGif and GIPHY’s own macOS app. They still launched; nobody was fixing them.

So I built Quip, a menu-bar app that searches Giphy and copies a GIF to the clipboard in a click. The people who came to test it were mostly refugees from those two dead tools, and they arrived with years of habits and firm opinions. That mattered far more than anything I could have guessed at on my own.

The app’s main action leaves no trace on screen.

Copying to the clipboard is invisible. Nothing moves and nothing confirms, so there is no way to be sure the click landed.

Quip’s whole reason to exist is one move: find a GIF, copy it, paste it somewhere else. The clipboard is a silent place, and the popover gets out of the way the instant a result is clicked.

At first it offered no feedback at all. People clicked, saw nothing, and clicked again, unsure whether to switch apps and paste or keep trying. The rest of the work was giving that unseen click an answer.

I built Quip to fix my own annoyance, then let real use redesign it.

Solo, start to finish: the interaction, the Swift and SwiftUI, and the pipeline that signs and notarizes each release. Personal project, open source, no one else on it.

What I did not do alone was find the problems. Across the first two weeks and 16 releases, a dozen or so people put Quip to use and told me where it broke. Nearly every fix in here began as a person getting stuck in front of me, or a message that opened with is it supposed to.

The move it makes most often had to say whether it worked.

A copy that succeeds shows a mark. More important, a copy that fails now says so.

The mark lands on the thumbnail that was clicked, so the answer arrives where the eye already is.

The harder problem was failure. Early on, when a GIF failed to download, the app still showed “Copied”. People switched to their chat, pasted, and got nothing, then blamed themselves or the chat app, because Quip had just told them the copy worked. A cheerful confirmation that lies is worse than no confirmation at all: it sends someone away confident and wrong.

One failure used to take the whole window with it. Now it stays where it happened, on the one tile, and everything else holds its place.

Copy states A copy now reports success, and a failure just as plainly, without taking the whole window down with it.
The copy mark in the running app 1 clip
Copy in use The mark lands on the copied tile, and a half-shown tile at the edge signals the row scrolls sideways for more.

Dragging a GIF into a collection had to actually file it.

Collections let a favourite go into a named bucket. The gesture looked right long before it worked, which is its own kind of lie.

Collections are named buckets for the GIFs worth keeping. Filing one started as a right-click submenu and became a drag onto the collection’s chip.

Then came the sharpest failure in the app’s short history. For one release, a GIF could be picked up, dragged onto a chip, and dropped as the chip lit up. It looked filed. It was not, and nothing said so, so people believed they had organized their favourites when they had not. An error would have sent them back to try again; this gave them nothing to try.

Three attempts at filing a GIF, and what each one got wrong
the attemptwhat went wronghow it read
right-click, Add to CollectionSlow, hard to discover, and the wrong mental model: a menu is not how a person puts a thing into a bucket.findable, barely
drag onto the chipThe gesture was right and the drop did nothing. macOS carries a dragged item differently than I had assumed, so the GIF was never added and nothing said so.filed, and it was not
drag, routed through a shared contextThe drop now does what the animation promises. The chips moved into a drawer that stays in reach, because the moment a person wants to file a GIF is the moment they have just found it.filed
The gesture that lied The fix in the third row was not to the animation but to what the animation was promising.
The same three attempts, drawn as an arc 1 diagram
Filing arc Filing moved from a buried menu to a drag done mid-search, once the drag did what it looked like.
the drop answers
the chips follow the search
Filing in use The toast answers a drop that changes nothing else on screen, and the chips stay in reach, because the moment someone wants to file a GIF is the moment they have just found it.

A tool summoned for two seconds must never interrupt.

Quip is anti-modal by design. It interrupts once, on first launch, and never again.

Quip is the kind of tool a person calls up for two seconds and dismisses, so it holds a firm rule: it does not interrupt. An update found in the background never throws a window that steals focus mid-task.

The rule has one deliberate exception. Quip keeps no Dock icon and opens no window when it launches, so a new user could install it and see nothing but a small icon they might not notice. On the very first launch, and only then, the popover opens itself once. It breaks the no-interrupt rule to serve the reason the rule is there.

the rule

No window steals focus. An update found in the background marks the menu-bar icon with a dot and offers Install Update on right-click. That is the whole of it.

the one exception

On first launch only, the popover opens itself once, anchored to its menu-bar home. Quip keeps no Dock icon and opens no window, so without this a new user installs it and sees nothing.

Anti-modal, once The exception breaks the rule to serve the reason the rule exists: a tool summoned for two seconds has to be findable in the first place.

Grouped by cause instead of by release, one bug turned out to be three.

17 releases, 16 of them in the first 11 days, and because Quip updates itself a fix reached people the same day.

What I did not expect was the shape of it: a success signal outlasting the thing it reported, in three mechanisms I had been thinking about separately.

None of this is a large study, and the numbers stay small and honest: a dozen or so testers, three weeks, one person building. Still, the people who came over from the two dead tools stayed on it. For something that lives in the corner of the screen, that is enough.

What use surfaced across 17 releases, grouped by cause
what use foundhow ofteneach time it happened
A success mark that outlived the truth three times, over three and a half weeks
  • 1.1.1 · 13 JulA failed copy replaced the whole window with an error, so the one tile that failed was the one thing it did not tell you about.
  • 1.1.5 · 18 JulA GIF that never finished downloading still got a “Copied!” mark.
  • 1.1.15 · 6 AugA copy that failed straight after one that worked inherited the first one’s mark, which sat there asserting success over a failure.
An action that looked done and was not once, closed the same day
  • 1.1.7 → 1.1.8 · 19 JulDragging a GIF onto a collection looked like it worked. The GIF was never added.
A stale view left standing after the thing behind it changed in three releases, all found in use
  • 1.1.5 · 18 JulSwitching stickers or the content rating left the results already on screen untouched.
  • 1.1.11 · 22 JulThe same switch left a search that had failed or found nothing standing, and trending briefly showed the previous kind of result.
  • 1.1.15 · 6 AugMaking a collection mid-search filtered the favourites down to it afterwards, and switching kinds while trending loaded left the old grid up.
Something that read as an error and was not once
  • 1.1.5 · 18 JulA search with no matches looked like a failure. It now says there are no GIFs, which is a different sentence.
One class, three times Every row is a public changelog entry, so the count is checkable. The third instance landed on 6 August, three weeks after I had written up the first two as a lesson learned.

I should have tested the failures before shipping the successes.

Both trust bugs shipped before use caught them, and writing the lesson down did not stop a third.

The two failures I am least proud of both shipped. I had tested that copying worked and that filing worked. I had not tested what either one does when it fails, and failure is exactly where a hidden action does its damage, because there is nothing on screen to contradict it.

Writing it down was not enough either. Three weeks after I had filed the first two as understood, a third arrived: a stale success mark from one copy sat over the failure of the next. So the rule I would keep is narrower than the one I first wrote: test what the previous action is still saying while this one fails.

A few of these lessons outlast the GIF app.

The specific fixes were about GIFs. The habits underneath them are not.

an invisible action needs an honest answer

Copy and file both change nothing on screen, and both needed a signal that tells the truth when the action fails. Success was never the hard case.

direct manipulation beats a menu

For putting a thing somewhere. Dragging onto a chip was the single biggest gain in collections, once the drop landed.

the chrome must not fight the content

Scroll bars kept covering the stars people were reaching for. The fix was removing the chrome rather than tuning it; a half-shown row now does its job without sitting on top.

a control has to hold on any background

A group of Light-mode users once got dark text on a dark panel. The copy icon and the star kept vanishing on bright thumbnails until a darker outline let them read on anything.

What outlasts the GIF app Four habits, each one bought with a shipped mistake.