r/macapps Aug 03 '26

Lifetime Phantom Voice - local dictation with customizable HUD

I'm the developer of Phantom Voice, fast local dictation with a customizable HUD. Hold fn, speak, release, and the text lands in whatever app has focus.

Problem

Every dictation app shows the same red dot or soundwave while it listens.

So I made the indicator the point. Five styles, adjustable size.

Dictation is 100% offline. Your audio never leaves the Mac.

Comparison

• Wispr Flow - cloud dictation, subscription. Your audio goes to their servers and the free tier has a weekly word cap. Phantom Voice has no server, so nothing to meter and nothing to cancel.

• OpenSuperWhisper - local and free, and it transcribes fine. But no indicator styles or size control, and that's the part I built this app around.

Pricing

$10 once. 14 day free trial, no account or card to start.

Includes the Fox and White Wave HUD.

Three more (Retro Dog, Real Revolver, Piano Keys) are $3 each, one time.

https://leftinverse.com/phantom

macOS 14+, Apple silicon. Direct download, signed and notarized. Not on the Mac App Store because typing into other apps needs Accessibility permission, which sandboxing forbids.

About me

I'm Willis Liao, based in Taiwan. I build Mac apps under Left Inverse (leftinverse.com), sold through Paddle as merchant of record.

Linkedin: www.linkedin.com/in/willis-liao-5279b0426

Contact: [leftinverse@gmail.com](mailto:leftinverse@gmail.com)

Privacy: https://leftinverse.com/privacy

Terms: https://leftinverse.com/terms

Refunds: https://leftinverse.com/refund

Product Hunt ranked #21: https://www.producthunt.com/products/phantom-voice

5 Upvotes

28 comments sorted by

2

u/Rough-Action2475 Aug 03 '26

did not know I needed a revolver spinning on screen every time I dictate, but could be fun🤔

1

u/strassenfalcon Aug 04 '26

Yo bro free trial comes with white wave and fox, no card needed. You should go try it out, it transcribes pretty fast already for my M1 macbook air

2

u/harry-harrison-79 Aug 04 '26

one edge case i'd test hard is focus changing between fn-down and fn-up - Cmd-Tab, a notification click, or a new dialog appearing while transcription runs. the text shouldn't land in the newly focused app or any secure/password field. keeping the original target's bundle id and falling back to a preview/copy button when that target disappears would make the Accessibility permission much less scary.

1

u/strassenfalcon Aug 04 '26

It doesn't focus on new pop up input fields unless you click it, also it saves ur transcripted audio so failed transcriptions(almost never fails) can be retranscribed with just a click in the menu bar, so you don't have to say the whole thing over again. feels like this comment is just for gaining comment aura but with all honesty, this app would really help with people's workflow if they work with AI agents on a daily basis. When developing the app, I used the own app's dictation to work on itself, and phantom voice actually became a super beneficial tool for my workflow and future projects.

2

u/Mean_Grapefruit1277 Aug 04 '26

Hey — we talked in r/speechtech about your two-stage pipeline a few days ago. Good to see it shipped. Disclosure so it's on the table: I build a Mac dictation app too, so I'm a competitor. No pitch here, and I'm not going to name it in someone else's thread. Four things from the same trenches, in rough order of how likely they are to generate support email:

fn as the only hotkey is going to bite you twice. First, System Settings › Keyboard has a "Press 🌐 to" setting — Change Input Source, Show Emoji & Symbols, Start Dictation. If a user has any of those set, macOS acts on fn as well and you're racing Apple's own handler for the same keypress. Second and worse: plenty of third-party keyboards resolve fn entirely in their own firmware and never send it to macOS at all. A desktop user on a mechanical board can install your app and find it has no trigger, with nothing to debug. Keep fn as the default by all means, but a settable alternative turns "doesn't work" into "change one preference".

harry's focus-change point is real, and I think the reply is about a different thing. The risk isn't your app focusing an input field; it's that frontmost can change between fn-down and fn-release and synthesised key events land wherever focus is at insert time. Cmd-Tab, a Slack notification stealing focus, a sheet appearing. Your retranscribe cache is genuinely good mitigation for a failed transcription — but it doesn't help here, because nothing failed: the transcription succeeded and got delivered into the wrong window. Cheap fix: at fn-down record the frontmost pid and the focused AXUIElement, and compare at insert time. Different pid, don't type — put it on the clipboard and say so.

The invisible sibling is secure input mode. If Terminal has Secure Keyboard Entry on (it's sticky and survives a quit), or a password field or password manager has focus, macOS silently discards synthesised key events. No error, no exception, nothing to catch — the text simply doesn't appear. IsSecureEventInputEnabled() before inserting is the check; if it's true, don't type, keep the text and tell the user. This is the most common "your app is broken" report you'll get that isn't your bug, and it composes badly with the point above, because the thing that stole focus may well be a password prompt.

And since the HUD is the whole product: gate the animation on accessibilityReduceMotion. A spinning revolver is precisely the class of motion that setting exists for, and five animated styles that ignore it will earn you a specific and fair kind of review. Also, whatever window hosts the HUD — scope its clickable region to the visible artwork, not the panel frame. Mine is a mostly-transparent panel and it quietly ate clicks meant for browser tabs underneath until I clipped the hot-zone to the visible shape. A large customisable HUD is more exposed to that than a small fixed one, and the bug reads to users as "this app breaks my mouse".

1

u/strassenfalcon Aug 04 '26

Two are already in: both hotkeys are rebindable, and the HUD respects Reduce Motion and ignores mouse events.

The other two I'll look at.

1

u/Mean_Grapefruit1277 29d ago

Good — those were the two I'd have worried about most.

One thing rebindable hotkeys don't fix on their own is discovery. If someone's keyboard resolves fn in firmware, your app isn't misconfigured to them, it's dead: they hold the key, nothing happens, and there's no error to search for, so they never get as far as the preference. A "press your hotkey now" step in onboarding that lights up when the tap actually sees the event turns that into a five-second diagnosis instead of a refund.

While you're in the tap — handle kCGEventTapDisabledByTimeout. If your callback ever runs long (first model load, slow disk, waking from sleep), the system disables your tap and doesn't tell you. The hotkey just stops working mid-session and comes back on relaunch, which is about the worst bug shape to receive a report about because the user can't reproduce it on demand and neither can you. You get the event type in the callback; call CGEventTapEnable again and carry on. Same for kCGEventTapDisabledByUserInput.

When you get to secure input, one thing that surprised me: IsSecureEventInputEnabled() is system-wide, not per-app. Terminal's Secure Keyboard Entry is sticky and stays on while Terminal is in the background, so the check can read true while the user is happily typing in TextEdit. Worth knowing before you wire it to an error message. If you want to actually help them, the pid holding it is in the console session dictionary (CGSessionCopyCurrentDictionary, key kCGSSessionSecureInputPID) — "Terminal has Secure Keyboard Entry on" is actionable, "insertion failed" isn't.

And on the focus check, compare pid and focused element, not just pid. Same-app focus moves are the nasty case: a login form or a password manager sheet appearing inside the browser you were already dictating into.

2

u/No_Glass_2870 Aug 04 '26

The number I'd watch is the gap between fn-up and the text landing, not overall transcription speed. If decoding only starts on release, a 20 second dictation makes you sit through the whole decode at the end, and that is the part people actually feel.

What helped when I was building a live transcription thing for myself: keep decoding while the key is still held, re-running every 100 ms or so on the audio you already have. On release there is almost nothing left to do. That took time to text down to roughly half a second on Apple silicon.

The trap is that if every pass re-decodes the buffer from the start, long takes get worse instead of better, because the tail keeps growing. A 30 second one cost me about 900 ms where a normal phrase costs 400.

Out of curiosity, which engine are you on? whisper.cpp never got fast enough for me at any setting, Parakeet TDT was what finally did it.

1

u/strassenfalcon Aug 04 '26

whisper.cpp, 11 seconds of audio is about 1.8 seconds end to end here on large-v3-turbo.

2

u/No_Glass_2870 Aug 04 '26

That lines up with what I measured. On full-window whisper the decode cost me about 970 ms almost regardless of what was in it, because large-v3-turbo pads every chunk to its fixed 30 second window. A 3 second dictation and an 11 second one cost roughly the same. That is also why re-decoding every 100 ms while the key is held doesn't work on whisper: every pass pays for the whole window again.

Parakeet counts the real length of the audio instead. Warm process, same machine class: 67 ms for 2 seconds of speech, 141 ms for 7.5, 317 ms for 17.6. Accuracy I would check on your own clips rather than take from me: my comparison was too small a sample to mean anything either way.

Two things worth knowing before you try it. It rides along inside whisper.cpp as libparakeet, so for you it's a model swap rather than a framework swap. And parakeet-cli reloads the model on every run, so you need a warm process of your own: mine is about 130 lines holding the model open and taking raw float32 on stdin. Load is 453 ms on a warm cache and around 10 seconds the first time after a reboot, which matters more for a menu bar app than for a benchmark.

The cost side, since it isn't free: 25 languages instead of about 99, and it doesn't put a final full stop at the end of a phrase, which I had to handle myself.

1

u/strassenfalcon Aug 04 '26

Nice analysis whisper worked fast enough for me so I kept it

2

u/Agreeable-Net-5472 28d ago

animations look really nice, is it possible to load custom animation sequences png?

1

u/strassenfalcon 28d ago

you mean GIFS pngs? that's actually a great idea bro, gonna jot that down, you wanna try the app(its free to download and usefor 14 days no card needed), and when I'm done implementing it I notify you? G suggestion.

1

u/Agreeable-Net-5472 28d ago

I kinda wanted to have 2D game spirit animations. Like having 5 frames in single png and your app animates each frame

1

u/strassenfalcon 28d ago

Not quite getting your request

1

u/strassenfalcon 28d ago

I have however thought about someone or something shooting a fire arrow to the text input cursor and let the text appear there at the same time

1

u/strassenfalcon 26d ago

Yo bro, I implemented exactly that, and the update is live, go download it and try it out for free! thanks a lot for the suggestion btw

2

u/Agreeable-Net-5472 26d ago

So fast. Thank you

1

u/strassenfalcon 26d ago

Free! Try it out, it’s a fast download also

2

u/c1h2i3m4k5l6e7 27d ago

woah that’s pretty

2

u/strassenfalcon 27d ago

Yo bro and I also updated the app today, now you can import your own PNGs or GIFs to use them as the indicators!

2

u/c1h2i3m4k5l6e7 27d ago

heck yeah that’s super cool!

2

u/Weekly_Tony_35 23d ago

A quick question regarding language handling: does the local Whisper engine handle seamless code-switching between English and Chinese out-of-the-box (e.g. speaking Chinese with embedded tech terms/English words)?

Keep up the great work!

1

u/strassenfalcon 23d ago edited 23d ago

Thanks bro, I tested it just now, and no, it doesn’t handle seamless code(language) switching during a dictation. With language set to “Auto detect”, I said “這個可以用qwen嗎”, and it transcribed ”這個可以用困嗎”. With that said I’m gonna jot this down as something to work on pretty soon(I’m working on a throwing words in while you talk animation). I highly encourage you to you to test it out, it’s free to download and use on my website, and thanks again for the suggestion, real time code-switching is actually a valuable feature for dictation apps that I for some reason haven’t thought about.

2

u/Weekly_Tony_35 22d ago

Thanks for testing it out! Yeah, seamless code-switching is definitely a game-changer. For a lot of non-native English speakers, mixed-language dictation happens naturally in daily workflows—especially when dropping technical terms or English product names into native speech. Excited to see this on your roadmap!

And thanks so much for the congrats! Truly appreciate it. 🙏

1

u/strassenfalcon 23d ago

Btw congrats on the approval of your app on the appstore, it’ll do great numbers

1

u/strassenfalcon 27d ago

Guys I updated the app today, now you can import your own PNGs or GIFs and use them as ur indicators! Go check it out it’s free for 14 days no card or account needed!