Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save 0xdevalias/270fe78b2fa536c2c1508d75e8aaff45 to your computer and use it in GitHub Desktop.
Save 0xdevalias/270fe78b2fa536c2c1508d75e8aaff45 to your computer and use it in GitHub Desktop.
Some notes, thoughts, motivations and references related to the idea of creating an open-source clone of the Xnapper screenshot / annotation app.

Xnapper Screenshot App - Open Source Clone Potential

Some notes, thoughts, motivations and references related to the idea of creating an open-source clone of the Xnapper screenshot / annotation app.

Table of Contents

Background Context

Overview and Initial Development

Xnapper is a macOS screenshot app that helps users to create / mark up beautiful screenshots (eg. to share on social media) quickly and easily:

It was originally created/launched by Tony Dinh:

And we can read some of his blog posts related to it here (from inception, through to sale):

  • https://news.tonydinh.com/p/may-2022-7-839-mrr-travel-experiments-and-a-new-app-1165569#%C2%A7im-working-on-a-new-small-app
    • May 2022: $7,839 MRR, travel, experiments, and a new app (2022-06-02)

    • I'm working on a new small app!

      As you may know, I’m pretty obsessed with screenshotting tools. I’ve been looking for a “perfect” app for a while, tried CleanShot, Snipaste, LICECap, Shottr, Skitch, and a bunch of other apps.

      I have never found what I was looking for. So I decided to build one.

      Introducing: Xnapper.com

  • https://news.tonydinh.com/p/jun-2022-updates-100k-arr-reflections-and-a-screenshot-app-1206061
    • Jun 2022 updates, $100K ARR, reflections, and a screenshot app! (2022-07-05)

    • Building a screenshot app in 2022. What?

      In June, I released a beta version of my latest product: Xnapper.

      It has become my 3rd major product after DevUtils and Black Magic.

      I opened it up for early-bird purchase and sold $7,802 worth of licenses.

      And it’s a screenshot app, yeah!

      Revenue from Xnapper so far

      I could have never predicted that I will build a screenshot app in 2022.

      There are already so many screenshots apps out there, why bother to build a new one?

    • Story time…

      If you know me, you know I’m serious about my screenshots on social media.

      Too serious sometimes 😂

      (I wrote an entire thread on how to take good screenshots)

      Since I started doing this, people keep asking about it again and again…

      I could probably find a ton more if I spent the time. But you get the idea.

      The trick: there was no trick.

      Here is how I made these screenshots:

      • Take a screenshot (previously used the CleanShot app)

      • Put it on top of my desktop

      • Take another screenshot 🤷

      It took me ~5 seconds every time, and people seem to like it a lot.

      I get asked about it too much I have a dedicated page on my notion notes (the page has now been replaced with “I use Xnapper” 😂)

      Every time someone asks me about the screenshot, I just share the link.

    • Why I decided to build the app

      One day, after another person asked about the screenshot, I decided to build an app.

      Why build an app instead of keeping sending people the link?

      Well, there are a few problems with the way I was doing those screenshots:

      1. It takes ~5 seconds.** I can reduce it to 1 second**.

      2. There are similar web apps but zero native macOS apps.

      3. I like native macOS apps.

      Besides reducing the time to 1 second, I also have many ideas to improve the overall experience to create a good screenshot, ready to share on social media.

      Things like: redact emails automatically, balance the screenshot automatically, detect background color, and a way to do all of that on mobile!

      Many more crazy ideas in my mind waiting to be executed too.

      In short, it’s the perfect screenshot app for content creators.

      Or at least it is for me 😂

    • I don’t think there is anything like this in the market (yet!)

      I think I’m the first one to conquer this niche:

      “Native screenshot apps focused on social media creators/influencers, to make beautiful screenshots, but macOS only.” – niche enough 😂

      Sure, you can find tons of existing apps to make beautiful screenshots, but none of them is a screenshot app (i.e. can’t take screenshots with a keyboard shortcut).

      They are more like photo editors. Very different.

      In fact, I’ll share it with you now. Here are some alternatives to Xnapper:

      They have mostly similar features. So if you are not on macOS and want something similar to Xnapper, check out the above 😄

      Being first in the niche and having an existing audience on Twitter, I think it could be a good chance that Xnapper will be big!

      Hopefully!

      You can try Xnapper now

      As of now, you can use Xnapper for free.

      Download it here:

      When it’s officially released, the license will cost **$29 **per macOS device.

      There is a 30% early bird discount if you purchase today, but totally optional.

      If you have read this far, you can download the iOS app here (secret link!).

      Product Hunt launch soon! 🥳

  • https://news.tonydinh.com/p/july-2022-after-math-of-a-viral-tweet
    • July 2022: Aftermath of a viral tweet (2022-08-04)

    • Revenue Updates

      By the end of July 2022:

      • ..snip..
      • Xnapper reached $3,555 in revenue
    • Other small updates

  • https://news.tonydinh.com/p/my-new-product-on-product-hunt-today
    • My new product on Product Hunt today (2022-08-23)

    • After a long time in Beta testing, today, I launched Xnapper on Product Hunt!

    • Xnapper is my latest product. It’s a macOS app that helps you capture beautiful screenshots fast and easily!

  • https://news.tonydinh.com/p/aug-2022-one-year-since-i-quit-my
    • Aug 2022: One year since I quit my job (2022-09-07)

    • Reached $10K MRR, launched Xnapper (#1 of the week), went on Indie Hackers podcast (😱), and other updates in Aug 2022...

    • Launched Xnapper on Product Hunt

      On August 25th, I launched Xnapper on Product Hunt. The result:

      • 🥇 #1 Product of the Day
      • 🥇 #1 Product of the Week
      • 🥈 #2 Product of the Month

      If you were there to support the launch, thank you very much! ❤️

      As usual, I wrote a launch report to share everything about the launch.

      The post is available on Indie Hackers below.

    • I’m very excited about Xnapper.

      In August, it made $10K+ in revenue! Half of the revenue came from the launch.

      Compared to Black Magic and DevUtils, Xnapper has a much bigger customer base: almost everyone needs a screenshot app.

      By capturing just a small niche of this huge customer base (macOS users & content creators), I think Xnapper has the potential to become the #1 product in my portfolio, even bigger than Black Magic. Let’s see!

  • https://news.tonydinh.com/p/dec-2022-updates-and-happy-new-year
    • Dec 2022 updates and happy new year! (2023-01-05)

    • Look back at what I shipped in 2022

      A quick look back on what I shipped in 2022:

      • ..snip..
      • Built a new product Xnapper, then released 4 new versions in 2022.
      • Built an iOS app for Xnapper (Beta)
      • ..snip..
    • What’s for 2023?

      ..snip..

      Ideally, I want to release a new major version for DevUtils and Xnapper every 2 or 3 months, I don’t have anyone to delegate the Swift coding part, so I’ll have to do all of it myself.

    • Maybe new products

      ..snip..

      Even when I’m already have 3 products, I feel like none of them provide me a safety net I’m looking for. DevUtils and Xnapper are one-off purchase, tons of competitors and copycats; Black Magic is at $14K MRR now but growth has been slowing down, and it’s heavily dependent on the fate of Twitter.

  • https://news.tonydinh.com/p/help-me-win-the-golden-kitty-awards
    • Help me win the Golden Kitty Awards 2022? (2023-01-19)

    • My product Xnapper is nominated for the Golden Kitty Awards 2022 in the **Design Tools **category! 🥳

      However, to win the prize, I need to get enough votes before 20th January 2023.

      If you like Xnapper or have been using it, please support me with a vote here! 😊 (or click the big button below!)

  • https://news.tonydinh.com/p/july-2023-6k-mrr-getting-back-on
    • July 2023: $6K MRR – getting back on recurring revenue (2023-08-07)

    • All of my ideas are in the “build for myself” category, so in a way, you can say that I validate my ideas on myself.

      Then if I can find more people like me (who have the same pain point), it will likely be a successful product.

      Some of my successful products: DevUtils (3 years old), Xnapper (1 year old), Black Magic (2 years old), and Typing Mind (6 months old). I still use all of them every day.

      For my failed products (see my Twitter banner), I ended up not using them myself. If I don’t even use my own product, who will? 😂

      Remember that this is just one way of validating ideas, not the only way. It’s also not the best way, it just works for me (and maybe for you too).

      I shared more details on an example of how I validate & build products in previous issues: here is the Xnapper one, the Black Magic one, and here is the Typing Mind one.

  • https://news.tonydinh.com/p/500k-milestone-my-reflections-after
    • $500K milestone – my reflections after 1 year of building Typing Mind (2024-02-26)

    • Also in this issue: one-off purchase vs. subscription, selling Xnapper, and other updates from me in Feb 2024

    • Other updates: I’m selling Xnapper

      Last week, I posted on Twitter that I was looking for a buyer for Xnapper. I’ve already found a buyer, and I’m in the process of acquisition.

      The main reason I want to sell Xnapper is that I feel like I’m wasting its potential. I spend all of my time on Typing Mind these days, which brings me the majority of my revenue, so I have little time and motivation left to continue growing Xnapper.

      Of course, I can just leave it on autopilot and take my sweet passive income, but it just feels very “wasteful” to me, considering I know how much potential Xnapper has for growth.

      I love and use Xnapper every day (as you can see from the screenshots in this post), but right now, I don’t have the time to bring it to the next level.

      I’ve evaluated all the potential buyers who reached out and agreed to go forward with a very enthusiastic, energetic buyer who is super interested in growing Xnapper.

      I’ll share more about this acquisition in the next newsletter issue once the acquisition officially closes.

    • I’ll see you next month with more updates and follow-up on the acquisition of Xnapper.

  • https://news.tonydinh.com/p/another-6-figure-exit-and-the-future
    • Another 6-figure exit, and the future (2024-03-19)

    • I sold Xnapper, here is a quick update about the acquisition details

    • If you are a long-time subscriber, you probably know I shared about “a new screenshot app” in my June 2022 newsletter issue. I also shared the building and launching story of Xnapper on the Indie Hackers forum.

      Today, I want to write a short update to keep you all updated about the acquisition and share some more thoughts on the future of my indie journey.

    • Reason for selling

      As shared in my last newsletter’s issue, the main reason I want to sell Xnapper is that I feel like I’m wasting its potential.

      With Typing Mind making $40K+/month, I don’t have much time or motivation left to work on Xnapper, so I decided to clean up my portfolio a bit.

      Normally, I would be fine letting the product run on auto-pilot. Like DevUtils, Xnapper is a one-time purchase macOS app, with very low maintenance effort.

      However, for Xnapper, I think it has much more room to grow, and letting it on auto-pilot is very wasteful.

      There are many screenshot apps on the niche macOS market, but the truly good ones are only a few. Xnapper was lucky to receive so much love and support from its users. I really believe it has a shot of becoming the #2 or even #1 screenshot app for macOS.

      But, as I said, I don’t have much time or motivation. So, I thought selling it was the best path forward.

    • How I find the buyer

      I found Brian (the buyer) on Twitter from my tweet. Having an audience is great for cases like this!

      Via our video calls, I find Brian an enthusiastic and energetic entrepreneur who really believes in the future of Xnapper.

      I also listed Xnapper on Acquire.com around the same time. Later, I received one other offer at a higher price of $169K, but I had already accepted Brian’s offer, so I moved forward with the deal with Brian.

      One thing about Acquire.com I learned is that they now charge you a 4% fee on the total acquisition deal value if you find the buyer via their network, which is not a small number! That would have cost me $6,000 in fees for Xnapper’s acquisition!

      Normally, a transaction via escrow.com is less than 1%.

    • ..snip..
    • The Future

      For Xnapper, I think it’s in good hands. Brian is already making progress on growing the app, which I’m happy to see.

      For me, this marks my second product acquisition. This time the deal is bigger than the Black Magic acquisition ($128K).

      It’s funny that Xnapper, a one-time purchase product with only ~$4K/month revenue, now sold at a higher price than Black Magic, which was making $14K MRR. The solopreneur journey is full of surprises.

    • Note: There is a LOT more Xnapper related content in this post since it is basically dedicated to it, I won't bother copying it all here, but it's worth a closer look.
  • https://www.indiehackers.com/tonydinh

Sale to new owner

As we learned from some of the latter posts above (1, 2), around February 2024, Tony sold Xnapper to Brian Shin:

Motivation

TODO: Include a brief intro + overview of the changelog updates without updated binary releases + link to relevant tweets/etc:

Feedback

This section captures the feedback I have submitted about Xnapper since I purchased it.

2024-12-08 17:21 - Redaction Colour & Shape Picker Improvements

AKA: Feedback for Xnapper version 1.17.1 (65)

I've noticed that the 'draw to redact' feature hasn't seemed to be working lately (or perhaps I changed a setting which is making it not work)

Also, I'm not sure if this is currently a feature or not, but it would be nice if I was able to pick the colour that 'draw to redact' uses. I can see that I can select a colour down in the 'cog settings' menu near the 'redact sensitive data' checkbox. Sometimes I would like to be able to choose a background colour using the colour picker 'eye dropper', and then redact with that so that it more seamlessly 'blends in'.

For the 'draw shape' button, currently it toggles between shapes, but it would be nicer if I was able to see a dropdown menu of all possible shapes and choose from those.

That's all my thoughts for now.

2024-12-28 14:28 - Add Selection / Crop Tool & Open in Preview Option

Feedback for Xnapper version 1.17.1 (65)

A feature I have been finding myself wish that Xnapper had more and more lately is some kind of 'selection' tool so that I could select a region to cut/copy/'trim to'; and/or some kind of manual 'crop' tool so that I can crop/resize the image (eg. if I didn't crop it well enough when I initially took the screenshot, etc).

It could also be cool/useful if there was a button/feature that allowed me to take the image from Xnapper and open it in the standard macOS 'preview' app in editing mode to let me do those sorts of manipulations.

I think these features would be useful both independently, but I could also usecases for both together (eg. maybe basic manual cropping is implemented directly within Xnapper, but then for more advanced things I can 'transfer my context' across to editing in Preview/etc.

2024-12-28 14:31 - Allow Cancelling 'Drag Me' with Escape Key

Feedback for Xnapper version 1.17.1 (65)

When I use the 'Drag Me' button, it would be nice if I was able to press 'escape' or similar to cancel the drag. Currently if I am accidentally dragging and want to cancel, I basically need to find some inert part of my screen to drop it on and then hope I can get the edited screenshot context back again. In that instance where the drag is cancelled, it might be nice for Xnapper to re-open to the main window so that the work wasn't lost.

2025-01-09 13:13 - Add Highlight Text Tool

Feedback for Xnapper version 1.17.1 (65)

Similar to the 'redact text' tool, it would be cool if there was a similar 'highlight text' tool.

2025-01-29 21:32 - Screenshot History Ignoring Setting & Inset Value Bug

Feedback for Xnapper version 1.17.1 (65)

I have 'save screenshot history' disabled in the settings, yet looking at ~/Library/Application Support/Xnapper/Archives/ I can see all a whole bunch of files in Raw/ and Output/

I have 'Inset' set to 0, and yet there is a notably sizeable Inset on my images, that I seemingly have no way of reducing, which implies to me that this setting is broken.

2025-02-10 14:18 - Draw to Redact Feature Intermittently Failing

Feedback for Xnapper version 1.17.1 (65)

The draw to redact feature seems to randomly not work.

2025-04-15 14:27 - Add Emoji 'Stamp' Tool for Visual Marking

Feedback for Xnapper version 1.17.1 (65)

It would be cool if we were able to 'stamp' emoji onto an image; making it easier to tick off items in a list/similar.

2025-05-23 13:23 - Manual Redact Not Working on iPhone Screenshots

Feedback for Xnapper version 1.17.1 (65)

Tried to use the manual redact tool on a screenshot that was originally taken on my iPhone today; and not only did it not detect the automatic 'click to redact' fields over text; but even when I tried to draw a block of redaction manually it still didn't work.

2025-10-02 12:46 - Preserve Annotations When Reopening Closed Screenshots

Feedback for Xnapper version 1.17.1 (65)

Sometimes I accidentally end up closing/saving a screenshot I was annotating when I wasn't finished with it.

Usually this is by pressing Cmd+C / similar as muscle memory when I don't mean to.

If I copied it to the clipboard, then I can use 'Open from clipboard' to get it back (kind of), but then it's like I am starting with a fresh 'base image', and so none of the previous annotations can be edited, and often it makes the rounded corners/padding/etc 'double up' in weird ways.

Usually I end up using 'Reopen closed screenshot'; but this ends up opening the original screenshot without any of the annotations I had added.

It would be nice if 'Reopen closed screenshot' kept track of the annotations I had on it as well, and brought it back with those too; or perhaps a new similar option was added that allowed for this.

2025-10-02 12:54 - Cmd+C Conflict with Alfred Hotkey Ends Editing Session

Feedback for Xnapper version 1.17.1 (65)

Further to my previous feedback, it seems that I probably aren't actually accidentally hitting Cmd+C; but I am actually pressing my global Alfred 'universal action' hotkey trigger (Cmd+Shift+Space) while the Xnapper window is focussed, and i'm guessing that might send a Cmd+C to the active app to 'inspect' what is selected/similar.

Usually that wouldn't cause an impact in most apps, but in Xnapper, since Cmd+C 'destructively' ends the editing session, it ends up getting in the way.

I'm not actually sure if there is anything that can be done to resolve this on Xnapper's side of things; I will probably also look to raise it with Alfred's feedback as well; but wanted to raise it here anyway in case.

2025-10-02 13:02 - Update Check Broken & Homebrew Version Out of Date

Feedback for Xnapper version 1.17.1 (65)

For ages l assumed Xnapper was just barely maintained abandonware: but today I stumbled across the fact that the internal Check for Updates' on my version just seems to be broken; and is incorrectly telling me that l have the newest version available:

I haven't read through the Changelog to see if this has been fixed, and I haven't manually updated yet to confirm it either; but just wanted to point this out in case it's still broken in newer versions; or if you seem to have a lot of users 'stuck' on an older version/etc (not sure if you have built in analytics/etc to see that sort of thing)

--

And it seems that homebrew (https://brew.sh) also has this same problem, as it reports 1.17.1 as being the latest version too:

https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/x/xnapper.rb

https://github.com/Homebrew/homebrew-cask/commits/d412b258b889a4536ea7398ec6e585075006d9ec/Casks/x/xnapper.rb

--

Further context in these 2 twitter threads:

Unsorted

⇒ strings /Applications/Xnapper.app/Contents/MacOS/Xnapper| grep /Users
/Users/tonydinh/Desktop/c2.png
/Users/tonydinh/Code/screenshotapp/screenshotapp/ImageEditor/ImageEditorViewController.swift
/Users/tonydinh/Code/screenshotapp/screenshotapp/Utils/TextWrapper.swift
/Users/tonydinh/Code/screenshotapp/screenshotapp/Utils/Editor.swift
/Users/tonydinh/Code/screenshotapp/screenshotapp/ViewController.swift
/Users/tonydinh/Code/screenshotapp/screenshotapp/Components/CustomWKWebView.swift
/Users/tonydinh/Code/screenshotapp/screenshotapp/Components/DragButton.swift
/Users/tonydinh/Code/screenshotapp/screenshotapp/ImageEditor/ImageEditorWindowController.swift
/Users/tonydinh/Code/screenshotapp/screenshotapp/AppDelegate.swift
/Users/tonydinh/Code/screenshotapp/screenshotapp/Utils/Utils.swift
⇒ rg webkit /Applications/Xnapper.app --glob '*.js'
/Applications/Xnapper.app/Contents/Resources/draw.js
22:        if (window.webkit) {
23:          window.webkit.messageHandlers.events.postMessage({
⇒ strings /Applications/Xnapper.app/Contents/MacOS/Xnapper | grep -E 'https?://'
https://xnapper.com/license-manager
https://xnapper.com/pricing
https://github.com/koher/swift-image
https://github.com/sparkle-project/Sparkle
https://github.com/sindresorhus/LaunchAtLogin
https://github.com/sindresorhus/macos-wallpaper
https://github.com/sochalewski/TextFieldAlert
https://github.com/ivanvorobei/SPConfetti
https://github.com/DevUtilsApp/SwiftyBeaver.git
https://github.com/DevUtilsApp/HotKey
https://github.com/DevUtilsApp/ShortcutRecorder.git
https://github.com/stephencelis/SQLite.swift
https://xnapper.com/api/check-license
" xmlns="http://www.w3.org/2000/svg">
You can unlink devices from anywhere by using the License Manager: https://xnapper.com/license-manager
https://api.swiftybeaver.com/api/entries/
⇒ gstrings /Applications/Xnapper.app/Contents/MacOS/Xnapper | grep -E 'https?://' | awk '!seen[$0]++'
https://xnapper.com/license-manager
https://xnapper.com/pricing
https://github.com/koher/swift-image
https://github.com/sparkle-project/Sparkle
https://github.com/sindresorhus/LaunchAtLogin
https://github.com/sindresorhus/macos-wallpaper
https://github.com/sochalewski/TextFieldAlert
https://github.com/ivanvorobei/SPConfetti
https://github.com/DevUtilsApp/SwiftyBeaver.git
https://github.com/DevUtilsApp/HotKey
https://github.com/DevUtilsApp/ShortcutRecorder.git
https://github.com/stephencelis/SQLite.swift
https://xnapper.com/api/check-license
" xmlns="http://www.w3.org/2000/svg">
You can unlink devices from anywhere by using the License Manager: https://xnapper.com/license-manager
https://api.swiftybeaver.com/api/entries/
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
http://crl.apple.com/root.crl0
https://www.apple.com/appleca/0
$http://ocsp.apple.com/ocsp03-devid060
*http://www.apple.com/certificateauthority/0
http://www.apple.com/appleca0
"http://crl.apple.com/timestamp.crl0
⇒ otool -L /Applications/Xnapper.app/Contents/MacOS/Xnapper
/Applications/Xnapper.app/Contents/MacOS/Xnapper:
	@rpath/Sparkle.framework/Versions/B/Sparkle (compatibility version 1.6.0, current version 2.1.0)
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 2048.1.255)
	/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1336.0.0)
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 2483.0.0)
	/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon (compatibility version 2.0.0, current version 170.0.0)
	/System/Library/Frameworks/Combine.framework/Versions/A/Combine (compatibility version 1.0.0, current version 311.0.0, weak)
	/System/Library/Frameworks/CoreData.framework/Versions/A/CoreData (compatibility version 1.0.0, current version 1327.0.0)
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 2048.1.255)
	/System/Library/Frameworks/CoreGraphics.framework/Versions/A/CoreGraphics (compatibility version 64.0.0, current version 1774.0.4)
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices (compatibility version 1.0.0, current version 1226.0.0)
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0)
	/System/Library/Frameworks/ImageIO.framework/Versions/A/ImageIO (compatibility version 1.0.0, current version 1.0.0)
	/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore (compatibility version 1.2.0, current version 1.11.0)
	/System/Library/Frameworks/ServiceManagement.framework/Versions/A/ServiceManagement (compatibility version 1.0.0, current version 2679.0.25)
	/System/Library/Frameworks/SwiftUI.framework/Versions/A/SwiftUI (compatibility version 1.0.0, current version 5.0.83, weak)
	/System/Library/Frameworks/Vision.framework/Versions/A/Vision (compatibility version 1.0.0, current version 7.0.45)
	/System/Library/Frameworks/WebKit.framework/Versions/A/WebKit (compatibility version 1.0.0, current version 616.1.27)
	/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1600.151.0)
	/usr/lib/libsqlite3.dylib (compatibility version 9.0.0, current version 349.1.0)
	/usr/lib/swift/libswiftCore.dylib (compatibility version 1.0.0, current version 5.9.0)
	/usr/lib/swift/libswiftCoreAudio.dylib (compatibility version 1.0.0, current version 5.0.0, weak)
	/usr/lib/swift/libswiftCoreFoundation.dylib (compatibility version 1.0.0, current version 120.100.0, weak)
	/usr/lib/swift/libswiftCoreGraphics.dylib (compatibility version 1.0.0, current version 15.0.0)
	/usr/lib/swift/libswiftCoreImage.dylib (compatibility version 1.0.0, current version 2.0.0, weak)
	/usr/lib/swift/libswiftCoreML.dylib (compatibility version 1.0.0, current version 1877.0.68, weak)
	/usr/lib/swift/libswiftCoreMedia.dylib (compatibility version 1.0.0, current version 3045.79.1, weak)
	/usr/lib/swift/libswiftDarwin.dylib (compatibility version 1.0.0, current version 0.0.0)
	/usr/lib/swift/libswiftDispatch.dylib (compatibility version 1.0.0, current version 34.0.2)
	/usr/lib/swift/libswiftIOKit.dylib (compatibility version 1.0.0, current version 1.0.0, weak)
	/usr/lib/swift/libswiftMetal.dylib (compatibility version 1.0.0, current version 341.16.1, weak)
	/usr/lib/swift/libswiftOSLog.dylib (compatibility version 1.0.0, current version 4.0.0, weak)
	/usr/lib/swift/libswiftObjectiveC.dylib (compatibility version 1.0.0, current version 8.0.0)
	/usr/lib/swift/libswiftQuartzCore.dylib (compatibility version 1.0.0, current version 3.0.0, weak)
	/usr/lib/swift/libswiftUniformTypeIdentifiers.dylib (compatibility version 1.0.0, current version 790.0.0, weak)
	/usr/lib/swift/libswiftVision.dylib (compatibility version 1.0.0, current version 3.0.3)
	/usr/lib/swift/libswiftWebKit.dylib (compatibility version 1.0.0, current version 0.0.0, weak)
	/usr/lib/swift/libswiftXPC.dylib (compatibility version 1.0.0, current version 29.0.2, weak)
	/usr/lib/swift/libswiftos.dylib (compatibility version 1.0.0, current version 1040.0.0, weak)
	/usr/lib/swift/libswiftsimd.dylib (compatibility version 1.0.0, current version 18.0.0, weak)
	/usr/lib/swift/libswiftFoundation.dylib (compatibility version 1.0.0, current version 1.0.0)
	/usr/lib/swift/libswiftAppKit.dylib (compatibility version 45.0.0, current version 2483.0.0)
  • https://developer.apple.com/documentation/appkit
    • AppKit

    • Construct and manage a graphical, event-driven user interface for your macOS app.

    • AppKit contains the objects you need to build the user interface for a macOS app. In addition to drawing windows, buttons, panels, and text fields, it handles all the event management and interaction between your app, people, and macOS.

  • https://developer.apple.com/documentation/foundation
    • Foundation

    • Access essential data types, collections, and operating-system services to define the base layer of functionality for your app.

    • The Foundation framework provides a base layer of functionality for apps and frameworks, including data storage and persistence, text processing, date and time calculations, sorting and filtering, and networking. The classes, protocols, and data types defined by Foundation are used throughout the macOS, iOS, watchOS, and tvOS SDKs.

  • https://developer.apple.com/documentation/coredata
    • CoreData

    • Persist or cache data on a single device, or sync data to multiple devices with CloudKit.

    • Use Core Data to save your application’s permanent data for offline use, to cache temporary data, and to add undo functionality to your app on a single device. To sync data across multiple devices in a single iCloud account, Core Data automatically mirrors your schema to a CloudKit container.

      Through Core Data’s Data Model editor, you define your data’s types and relationships, and generate respective class definitions. Core Data can then manage object instances at runtime to provide the following features.

  • https://developer.apple.com/documentation/coregraphics
    • CoreGraphics

    • Harness the power of Quartz technology to perform lightweight 2D rendering with high-fidelity output. Handle path-based drawing, antialiased rendering, gradients, images, color management, PDF documents, and more.

    • The Core Graphics framework is based on the Quartz advanced drawing engine. It provides low-level, lightweight 2D rendering with unmatched output fidelity. You use this framework to handle path-based drawing, transformations, color management, offscreen rendering, patterns, gradients and shadings, image data management, image creation, and image masking, as well as PDF document creation, display, and parsing.

      In macOS, Core Graphics also includes services for working with display hardware, low-level user input events, and the windowing system.

  • https://developer.apple.com/documentation/quartzcore
    • Core Animation

    • AKA: QuartzCore
    • Render, compose, and animate visual elements.

    • Core Animation provides high frame rates and smooth animations without burdening the CPU or slowing down your app. Core Animation does most of the work of drawing each frame of an animation for you. You’re responsible for configuring the animation parameters, such as the start and end points, and Core Animation does the rest. It accelerates the rendering by handing over most of the work to dedicated graphics hardware.

  • https://developer.apple.com/documentation/swiftui
    • SwiftUI

    • Declare the user interface and behavior for your app on every platform.

    • SwiftUI provides views, controls, and layout structures for declaring your app’s user interface. The framework provides event handlers for delivering taps, gestures, and other types of input to your app, and tools to manage the flow of data from your app’s models down to the views and controls that users see and interact with.

      Define your app structure using the App protocol, and populate it with scenes that contain the views that make up your app’s user interface. Create your own custom views that conform to the View protocol, and compose them with SwiftUI views for displaying text, images, and custom shapes using stacks, lists, and more. Apply powerful modifiers to built-in views and your own views to customize their rendering and interactivity. Share code between apps on multiple platforms with views and controls that adapt to their context and presentation.

    • You can integrate SwiftUI views with objects from the UIKit, AppKit, and WatchKit frameworks to take further advantage of platform-specific functionality. You can also customize accessibility support in SwiftUI, and localize your app’s interface for different languages, countries, or cultural regions.

  • https://developer.apple.com/documentation/combine
    • Combine

    • Customize handling of asynchronous events by combining event-processing operators.

    • The Combine framework provides a declarative Swift API for processing values over time. These values can represent many kinds of asynchronous events. Combine declares publishers to expose values that can change over time, and subscribers to receive those values from the publishers.

      • The Publisher protocol declares a type that can deliver a sequence of values over time. Publishers have operators to act on the values received from upstream publishers and republish them.
      • At the end of a chain of publishers, a Subscriber acts on elements as it receives them. Publishers only emit values when explicitly requested to do so by subscribers. This puts your subscriber code in control of how fast it receives events from the publishers it’s connected to.
  • https://developer.apple.com/documentation/vision
    • Vision

    • Apply computer vision algorithms to perform a variety of tasks on input images and videos.

    • The Vision framework combines machine learning technologies and Swift’s concurrency features to perform computer vision tasks in your app. Use the Vision framework to analyze images for a variety of purposes:

      • Tracking human and animal body poses or the trajectory of an object
      • Recognizing text in 18 different languages
      • Detecting faces and face landmarks, such as eyes, nose, and mouth
      • Performing hand tracking to enable new device interactions
      • Calculating an aesthetics score to determine how memorable a photo is
  • https://developer.apple.com/documentation/webkit
    • WebKit

    • Integrate web content seamlessly into your app, and customize content interactions to meet your app’s needs.

    • Use the WebKit framework to integrate richly styled web content into your app’s native content. WebKit offers a full browsing experience for your content, offering a platform-native view and supporting classes to:

      • Display rich web content using HTML, CSS, and JavaScript
      • Handle the incremental loading of page content
      • Display multiple MIME types and compound frame elements
      • Navigate between pages of content
      • Manage a forward-back list of recently visited pages
  • https://developer.apple.com/documentation/servicemanagement
    • ServiceManagement

    • Manage startup items, launch agents, and launch daemons from within an app.

    • Use Service Management to install and observe the permission settings of three supplemental helper executables that macOS supports. You can use all three of these to provide additional functionality related to your app, from inside your app’s bundle:

      • LoginItems
        • An app that launchd starts when the user logs in. A LoginItem is an app that continues running until the user logs out or manually quits. Its primary purpose is to enable the system to launch helper executables automatically
      • LaunchAgents
        • Processes that run on behalf of the currently logged-in user. launchd, a system-level process, manages Agents. Agents can communicate with other processes in the same user session and with system-wide daemons in the system context.
      • LaunchDaemons
        • A stand-alone background process that launchd manages on behalf of the user and which runs as root and may run before any users have logged on to the system. A daemon doesn’t interact with a user process directly; it can only respond to requests made by user processes in the form of a low-level request, such as a system request, for example XPC, low-level Interprocess Communications system.
  • https://sparkle-project.org/
    • Sparkle

    • Sparkle is an easy-to-use software update framework for macOS applications.

    • https://github.com/sparkle-project/Sparkle
      • Sparkle 2

      • A software update framework for macOS

      • Secure and reliable software update framework for macOS.


Codex Prompt:

User | 2025-10-04 10:03:53 AEST

Can you explore this macOS application for annotating screenshots. It looks like it uses some javascript/similar, but from a quick skim it doesn't look like its an electron app.

Ideally I'd like to understand how it works, and then how we could build something similar, ideally in a more open-source friendly way.

Codex Response:

Codex Assistant | 2025-10-04 10:09:59 AEST

Observed Architecture

  • Native shell is a conventional AppKit app launched from the Main storyboard with NSApplication as the principal class (Contents/Info.plist:114-117). Sparkle auto‑update endpoints are configured here as well (Contents/Info.plist:118-121).
  • The editing surface ships as a bundle of HTML/JS assets; mode changes are relayed back to the host through window.webkit.messageHandlers.events calls, confirming a WKWebView bridge (Resources/draw.js:22-27).
  • Annotation tools (text, arrows, shapes) are implemented in plain DOM/Canvas logic and manage their own drag/stack state inside the web layer (Resources/draw.js:1-120, Resources/text.js:1-124).
  • Redaction mode draws semi-transparent SVG rectangles over detected text regions, again handled fully in JS (Resources/redact.js:1-158).
  • Hotkey capture relies on the bundled ShortcutRecorder resources (Resources/ShortcutRecorder_ShortcutRecorder.bundle/Contents/Info.plist:5-33), while launch-on-login support comes from Sindre Sorhus’s helper app (Contents/Library/LoginItems/LaunchAtLoginHelper.app/Contents/Info.plist:7-52).
  • Distribution includes a Share Extension for system-wide sharing (Contents/PlugIns/Xnapper Mac Share Extension.appex/Contents/Info.plist:21-59) and the Sparkle framework for updates (Contents/Frameworks/Sparkle.framework/Resources/Info.plist:5-16).

Key Feature Clues

  • JS controllers manage UI states such as crosshair cursors, z-ordering, and preview/edit transitions for annotations, hinting that native Swift code primarily feeds screenshots into the web editor then collects serialized edits (Resources/text.js:8-147).
  • Redaction instructions and event handling point to support for manual and auto redaction overlays, likely paired with Vision framework text detection invoked from Swift (Resources/redact.js:7-158).
  • Resource folders contain large background assets (Resources/data/xnapper-custom-background-desktop), suggesting the app composites captured images onto themed canvases before export.

Open-Source Roadmap

  1. Build a SwiftUI/AppKit shell that mirrors the bundle structure above: capture via ScreenCaptureKit, manage windows, preferences, login item, Sparkle (or another updater), and expose a share extension.
  2. Recreate the editor either by reusing the existing HTML/JS (drop it into a WKWebView with a message handler API similar to the current events channel) or by replacing it with a SwiftUI/Metal canvas while keeping the same tool set (text, arrows, shapes, redaction).
  3. Implement auto-redaction by running Vision text detection plus custom regex passes for emails/IPs/API keys in Swift, piping results to the web editor as initial SVG rectangles.
  4. Wrap configuration around open-source components: LaunchAtLogin (or SMAppService), Sparkle or SoftwareUpdate, ShortcutRecorder or MASShortcut, SwiftyBeaver-equivalent logging, ensuring all licensing suits an OSS release.
  5. Define a modular architecture (Core capture, Editor bridge, Export pipeline) so the JS layer can be swapped for native code later without rewriting capture or licensing logic.

Next steps: decide whether to keep the web-based editor (fastest path) or budget time to craft a native drawing surface; once that’s settled, we can scaffold a public repo with those modules and start extracting/rewriting the JS controllers as needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment