Pronounced /ˈkɐ̃tʃi/ ("KAHN-chee") — Portuguese for "sing!" (imperative of cantar).
Cante shows the current lyric line from Spotify or macOS Now Playing in a floating macOS desktop overlay, with the next line underneath.
Cante is published as a Homebrew tap. Apple Silicon only.
brew install squiter/cante/canteUpgrade later with brew upgrade cante. Tap source: squiter/homebrew-cante.
Cante also ships as a macOS command-line bundle on GitHub Releases.
- Open the Releases page.
- Download the latest
cante-...-macos-...tar.gzarchive. - Download the matching
.sha256file if you want to verify the archive. - Unpack the archive.
tar -xzf cante-*-macos-*.tar.gz
cd cante-*-macos-*Keep the included binaries together in the same folder:
cante
cante-overlay
cante-spotify
cante-now-playing
cante-lyrics
The manual-download binaries are not notarized, so macOS Gatekeeper blocks them by default with a "cannot be opened because the developer cannot be verified" message. Remove the quarantine flag once after unpacking:
xattr -dr com.apple.quarantine cante cante-overlay cante-spotify cante-now-playing cante-lyricsRun this from inside the unpacked release folder. After that the binaries launch normally. Homebrew installs do not need this step.
Start Spotify or a browser player that appears in macOS Now Playing, then run:
cante runBy default Cante auto-selects the active source. Spotify is preferred when it is actively playing; otherwise Cante tries macOS Now Playing for browser-based players such as music.youtube.com.
When using Spotify for the first time, macOS may ask for permission to let Cante control Spotify. Allow it so Cante can read the current track and playback position.
To force browser-based YouTube Music through macOS Now Playing, run:
cante run --source now-playingTo force Spotify, run:
cante run --source spotify(If you installed manually, run ./cante run from the unpacked folder.)
By default cante run detaches into the background, returns your terminal, and writes output to ~/Library/Logs/cante.log. The overlay supervisor pid is recorded in /tmp/cante.pid.
The overlay can be dragged around the screen. Close it with the x button, or from a terminal:
cante stopPass --foreground (or -f) to keep cante attached to the current terminal — useful for debugging, since output goes to the terminal and Ctrl-C stops everything:
cante run --foreground --debugClear cached lyrics:
cante clear-cacheCheck the installed version:
cante --versionRun with debug logs:
cante run --debugRun in click-through mode:
cante run --click-throughIn click-through mode, the overlay ignores mouse events, so the close button and dragging are disabled. Use cante stop to close it.
A few overlay options let you adjust readability, size, and density:
--text-shadowadds a dark halo around the lyric text so it stays legible over light wallpapers and white windows.--opaqueswaps the translucent backdrop for a solid dark panel, removing the blend with whatever is behind the overlay.--size small|medium|largescales the whole overlay — fonts, padding, and box dimensions — together. Default ismedium.--single-linehides the second (next-lyric) line for a more compact box; loading and missing-lyrics status are folded into the main line.
All toggles default to off and can be forced off with the --no-* variant (--no-text-shadow, --no-opaque, --no-single-line):
cante run --text-shadow --opaque --size small --single-lineTo make the choices persistent, create ~/.config/cante/config.json:
{
"overlay": {
"textShadow": true,
"opaqueBackground": false,
"size": "medium",
"singleLine": false
}
}CLI flags override the config file, so you can keep persistent defaults and still flip them per-run.
- Shows the current lyric line and the next lyric line.
- Shows the current track while lyrics are loading.
- Fades down when synced lyrics are not available for a song.
- Caches LRCLIB synced lyrics locally so repeated songs load faster.
- Auto-selects Spotify when it is actively playing, otherwise tries macOS Now Playing.
- Floats above other windows and joins all Spaces.
For development:
swift build
.build/debug/cante runRelease changes are tracked in CHANGELOG.md.
To cut a new release, add a ## [x.y.z] section to CHANGELOG.md, commit it, then run:
make release VERSION=x.y.zThis tags vx.y.z, waits for the GitHub Actions release workflow to publish the arm64 tarball, and then updates the formula in squiter/homebrew-cante (path overridable via HOMEBREW_CANTE_DIR, defaults to ../homebrew-cante).
GitHub Actions handles the actual build: it produces a .tar.gz archive plus a SHA-256 checksum and attaches both to the GitHub Release.
The overlay reads from standard input, so you can drive it with your own scripts.
Run it with:
swift run cante-overlayThen type a line and press Return. Each new line replaces the overlay text.
Stop a running overlay from another terminal with:
.build/debug/cante stopCtrl-C also works when the overlay is attached to your current terminal session.
You can also pipe timed text into it:
while true; do
echo "You want people to love you"
sleep 2
echo "It's encoded in your greed"
sleep 2
done | swift run cante-overlayCante can also work as a lightweight teleprompter because the overlay reads from standard input. The simplest format is one prompt line per line:
Welcome everyone, and thanks for joining.
Today I want to show what Cante can do.
Let's start with the live desktop overlay.
Save that as prompt.txt, then stream it at your own pace:
while IFS= read -r line; do
echo "$line"
sleep 4
done < prompt.txt | .build/debug/cante-overlayIf you want the smaller second line to show what comes next, use JSON Lines. Each line should be one JSON object:
{"current":"Welcome everyone, and thanks for joining.","next":"Today I want to show what Cante can do."}
{"current":"Today I want to show what Cante can do.","next":"Let's start with the live desktop overlay."}
{"current":"Let's start with the live desktop overlay.","next":null}Then stream the file the same way:
while IFS= read -r line; do
echo "$line"
sleep 4
done < prompt.jsonl | .build/debug/cante-overlayPlain text updates only the main line. JSON Lines can update both the main line and the smaller next line.
cante-lyrics fetches synced lyrics from LRCLIB and prints each line according to its LRC timestamp:
swift run cante-lyrics --track "ERROR" --artist "The Warning"Pipe it into the overlay:
swift build
swift run cante-lyrics --track "ERROR" --artist "The Warning" | .build/debug/cante-overlayThis does not know any player playback position. It treats command start as song start, which is enough to validate timestamp parsing and overlay updates. For faster visual testing, skip directly to the first lyric:
swift run cante-lyrics --track "ERROR" --artist "The Warning" --skip-intro true | .build/debug/cante-overlayIf lyrics are visible in the terminal but not in the overlay, run the overlay with stdin logging:
swift run cante-lyrics --track "ERROR" --artist "The Warning" --skip-intro true | .build/debug/cante-overlay --debug-stdincante-spotify reads the current Spotify desktop playback through macOS scripting, fetches synced lyrics from LRCLIB when the track changes, and prints the lyric line that matches Spotify's playback position.
swift build
.build/debug/cante-spotify | .build/debug/cante-overlayFor troubleshooting:
.build/debug/cante-spotify --debug | .build/debug/cante-overlay --debug-stdinThis requires the Spotify desktop app to be running. macOS may ask for permission to let Cante control Spotify.
You can also check whether Cante sees Spotify as actively playing:
.build/debug/cante-spotify --probecante-now-playing reads the current macOS Now Playing item through the private MediaRemote framework. This can work with browser-based players such as YouTube Music when the browser publishes media metadata to macOS Control Center.
swift build
.build/debug/cante-now-playing | .build/debug/cante-overlayOr through the top-level CLI, forcing this source:
.build/debug/cante run --source now-playing --foreground --debugBecause this uses a private macOS framework, it may break on future macOS releases or behave differently across browsers. If macOS reports only generic video metadata, Cante will not be able to fetch matched LRCLIB lyrics.
To inspect the raw metadata Cante can see from macOS Now Playing:
.build/debug/cante-now-playing --dumpYou can also check whether Cante sees macOS Now Playing as actively playing:
.build/debug/cante-now-playing --probeThe overlay shows a loading state while lyrics are being fetched or the selected source is not actively playing. Once lyrics are available, it shows the current line and the next line underneath.
Fetched LRCLIB results are cached locally in the user cache directory, so repeated tracks avoid another network request.
Clear the lyrics cache with:
.build/debug/cante clear-cache