← all apps

magic-coin

Magic Coin - a floating ring for macOS. MA transcribes, BA reads what is under it.

runs onMactechnologySwift, AssemblyAIrepositoryhttps://github.com/markoboskoauroville/magic-coinlast push2026-08-06
GitHub
# Magic Coin

A ring of white light that floats above every other window. Two faces:
**MA** transcribes what you say, **BA** reads aloud whatever is underneath it.
The middle is a real hole — clicks pass straight through, so it can sit on top
of a document you are still working in.

---

## Three things to know before you build it

**1. This is not a macOS Widget, and it cannot be.**
Widgets (WidgetKit) live in Notification Center or pinned to the desktop. They
cannot be dragged anywhere on screen, cannot float above other applications,
and cannot see what is behind them. Everything you asked for needs a real
window. So Magic Coin is a background agent: no Dock icon, no menu bar item,
one borderless transparent panel. It behaves the way you described; it just is
not the thing Apple calls a widget.

**2. macOS has no vibration.**
There is no vibration motor in a Mac. "Vibrating" here is a visual shudder —
the ring wobbles and a second faint ring pulses inside it — plus a real haptic
tap on Force Touch trackpads, which does nothing on a desktop. That is the
closest honest equivalent.

**3. Reading the screen needs permission, and Croatian OCR is weak.**
The BA side screenshots the area under the coin and runs Apple's Vision OCR on
it. macOS will ask for **Screen Recording** permission the first time.
Vision's language list does not include Croatian, so Croatian text is read with
mistakes on the diacritics. English is accurate. The speech itself handles
Croatian properly — it is only the reading-from-pixels step that is limited.

I could not compile this here; there is no Swift toolchain in the environment I
built it in. The GitHub Actions run is therefore the first real compile. If it
fails, send me the log and I will fix it — the errors will be small and
specific, not structural.

---

## Build it

1. Make a new empty repository on GitHub, e.g. `magic-coin`.
2. Drop these files in and push to `main`.
3. The Actions tab will show a **build** run on a real macOS machine.
4. When it finishes, download **MagicCoin.zip** from the run's Artifacts.

For a permanent download instead of an artifact, push a tag:

```
git tag v1.0
git push origin v1.0
```

That attaches `MagicCoin.zip` to a GitHub Release.

**No personal access token is needed.** Actions gives the job a built-in
`GITHUB_TOKEN` with exactly the rights required. Please do not paste a personal
token into a chat — anything pasted there should be treated as compromised, and
this build does not want one.

---

## First run

Unzip and drag `MagicCoin.app` to `/Applications`.

The build is ad-hoc signed, not notarised, so Gatekeeper will refuse the first
double-click. Right-click the app → **Open** → **Open**. Once only.

The coin appears near the top right of your screen.

---

## Using it

| action | what happens |
|---|---|
| drag the ring | move it anywhere |
| double-click | flip the coin, MA ↔ BA |
| click on **MA** | start recording; click again to send |
| click on **BA** | read what is under the coin; click again to stop |
| right-click | the menu: keys, size, quit |
| click through the hole | nothing — the app below gets it |

**MA** turns the ring red while recording, amber while uploading, and puts the
transcript **on your clipboard** when it is done. A floating coin over another
app exists so you can paste.

**BA** turns amber while it looks and green while it speaks, and shows **one
word at a time inside the ring** as it is said. The words come from
`AVSpeechSynthesizer`, which reports the exact character range it is about to
speak — so the highlighting is measured by the speech engine itself rather than
reconstructed afterwards.

---

## The settings, which are only API keys

Right-click the coin → **Load API keys from a file…**

Pick any text file. The keys are lifted out of it and everything else is
ignored. They are written to:

```
~/Documents/maha_api_keys.txt
```

**This is the same file the Maha web app uses**, with the same format and the
same parser rules. Set the keys up in either place and both find them. Right-click
→ **Show the key file in Finder** to see or delete it.

Only an AssemblyAI key is needed. The BA side speaks with macOS's built-in
voices and needs no key at all, so the coin is useful before you have set
anything up.

Parser rules, unchanged from the web app:

* prefixed keys identify themselves — `sk-ant-`, `AIza`, `gsk_`
* a bare 32-character hex string is AssemblyAI's format, and also an MD5, so it
  is only taken when the file says `assemblyai` above it or on the line, or
  when the file names no provider at all

---

## Files

```
Package.swift                     SwiftPM, macOS 14+
Sources/MagicCoin/App.swift       the panel, the menu, the wiring
Sources/MagicCoin/CoinView.swift  the ring, the hole, the shudder, the word
Sources/MagicCoin/Reader.swift    screen capture, OCR, speech (BA)
Sources/MagicCoin/Transcriber.swift  microphone, AssemblyAI (MA)
Sources/MagicCoin/Keys.swift      the key file and its parser
.github/workflows/build.yml       the macOS build
```

The entry point is in `App.swift`, not `main.swift`, deliberately: Swift treats
a file called `main.swift` as top-level code and then rejects `@main` anywhere
in the module.

The AssemblyAI request sends a **model list**, `["universal-3-5-pro",
"universal-2"]`, not a single name. Universal-3.5 Pro covers 18 languages and
Croatian is not among them, so a single-model request is rejected outright on
Croatian audio. Sending the list lets AssemblyAI route and fall back.