Theme
Subscribe

How it started

I’ve fallen in love with a tool called Raycast. It has replaced half a dozen other services & apps for me. Besides the Zen browser, it’s my most used app.

One of the key features of Raycast is its extension store—misleadingly named, because everything on it is free. It allows users or companies to create extensions that let it interact with Raycast or extend its functions.

Some of my favorite extensions allow me to grab an icon or SVG from Raycast, manage GitHub PRs, or join a meeting with one click. After using these tools & being part of the community, I wanted to try my hand at making an extension. The problem? I didn’t have any useful ideas.

So of course, I did the obvious thing: built a game inside my productivity tool.


Turning Tools Into Games

The idea I ended up with was an incremental clicker game—a genre known mainly for being a time waster. While this may not be a “useful” extension, it ticked all the boxes for a good challenge:

  • Test local storage
  • Figure out offline progress
  • Build a fun game UI
  • Work through game flow & updates

I also didn’t realize at the time that it would be a perfect way to learn how to update extensions, thanks to the unavoidable bugs found by early players.

So I started writing a design doc, since I didn’t know quite how to escape Raycast’s constraints or plan out solid game progression.


Finding the game vibe & testing limitations

Inevitable scope creep kicked in, & the project expanded from a clicker to a full blown idle game with achievements & a prestige system. I even dreamed of a side by side panel (Cookie Clicker style).

Naive. While Raycast uses React, it imposes strict limits to keep everything tidy. My first mistake was prototyping the MVP in the browser. I thought this would help me iterate quickly before turning it into an extension.

Instead, it caused headaches & unnecessary PR problems (all of my own making). I ended up with legacy HTML & extra code debt to clean before finalizing the extension.


Finally Creating

One of the best bits about Raycast extensions is that they just use React & TypeScript plus the @raycast/api. This means if you’ve touched web dev in the past five years, you already have a solid base.

So I started scaffolding in web, since that’s what I knew. This kind of worked—but also created way too much code debt for such a small project.

Once I gave in & built in Raycast, for Raycast, everything clicked. Raycast makes creating UIs for extensions surprisingly easy, & I was able to enable features like:

  • Game state: resources, upgrades, & flags live in LocalStorage. A saveVersion key keeps migrations safe.>
  • Offline progress: the extension logs a timestamp on close. On load, it calculates how long you were away & applies capped idle gains. No infinite exponential chaos—just enough to make coming back satisfying.>
  • Commands: one main Game command (panel where you play), plus a Menu Bar Command that ticks in the background.>
  • Updates: defensive coding for save migrations, plus small, reviewable PRs to keep fixes fast.
// Example save structure
type SaveState = {
  resources: number;
  upgrades: string[];
  saveVersion: string;
};

const saveVersion = "1.0.0";
await LocalStorage.setItem("save", JSON.stringify({ resources, upgrades, saveVersion }));

Making the game fun

Once I had the skeleton, I realized I wasn’t having any fun playing or testing it. Which kind of defeats the point of a game. So since this was a learning project, I did what I thought would actually be fun.

Breaking the balance

It’s always baffled me when a developer nerfs parts of their PvE game in the name of balance. Since I wasn’t trying to milk playtime & was mainly in this to learn, I optimized for fun, not balance.

First obvious break: if you hold down the clicker instead of clicking, it acts as an auto clicker. My solution? Add an achievement for it. Everyone who plays these games uses an auto clicker anyway—why not turn it into an Easter egg?

Other fun decisions followed: scaling that goes wild but stays rewarding, pacing that doesn’t steal your entire day, & an optimistic trust in the player’s system clock. Yes, time skipping works just like the old mobile games.


What the game actually became

Here’s the quick rundown:

  • Core loop: click to earn → buy upgrades → unlock idle → prestige → repeat.>
  • Upgrade paths: Active (click power), Idle (auto-gain), & Efficiency (cost reduction).>
  • Events: a random Golden Command gives you a burst of points.>
  • Achievements: tiny celebrations for progress milestones, often inspired by player behavior.>
  • Prestige system: reset with a preview of your next boost, making the game speed up exponentially.

Ray Clicker Screenshot


Process of publishing

Since it’s basically a React app with a few Raycast constraints, once I abandoned my misguided web dev detour the rest was straightforward.

The interesting part was learning how submission & publishing work:

  1. Fork the Raycast extensions repo.
  2. Add your extension.
  3. Open a PR.
  4. Work with maintainers to fix issues & match guidelines.
  5. Get merged, & celebrate when your extension goes live in the store.
  6. Patch bugs as users report them, keeping PRs small & reviewable.

Huge thanks to:

  • Per Nielsen Tikær: helped clean up my PR, pointed out store requirements I’d missed, & merged it. Without Per’s patience, this extension wouldn’t exist.
  • litomore: guided me through forking problems & answered all my newbie questions.

Honestly, this has been one of the most welcoming dev communities I’ve been a part of.


Lessons from the village idiot

Prototype where you ship. Raycast ≠ browser. Design with constraints, not against them. Raycast’s UI limits force clarity. Version your saves early. Migration bugs are worse than game bugs. Keep PRs small. Reviewers are doing you a favor; don’t drown them. Communities ship software. Per, litomore, & the Raycast crew made this project possible.


How to play!


Closing thoughts

This project started as a joke but became one of the most fun, educational, & surprisingly community driven things I’ve built.

The Raycast community is one of the kindest I’ve been a part of. I’ve been lucky enough to work with some of the kindest people in it.


Windows port (in progress)

Raycast is coming to Windows, & I’m working on porting the game, especially since its out on Beta! I just need to find between finals.


Thanks for reading!

If you are lucky, here is a free month of Pro. This code changes every so often: Raycast Pro Referral

Feel free to share this blog or reach out to me on LinkedIn.