Skip to content
gxlselfPublic

About

把屏幕顶端那一条变成工作台:逐字歌词、Claude Code 会话、剪贴板、文件暂存架。macOS 与 Windows 通用。

Resources

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

Bangs

A dynamic notch for macOS and Windows, built with Tauri 2 + React by gxlself (bundle id com.gxlself.bangs). It sits at the top center of the screen, shows live activity next to the notch, and expands on hover.

Download · bangs site — the macOS build is signed with a Developer ID and notarized, so it opens on a double click; the Windows installer is unsigned, so SmartScreen wants "Run anyway" once.

  • Now playing: artwork, progress and play/pause/skip/seek for the current system media session, with timed lyrics — the line being sung shows next to the collapsed notch, two lines with translation in the panel

  • File shelf: drop files on the notch to park them, drag them back out to other apps

  • Dev panel: Claude Code and Codex CLI sessions with busy/waiting/idle status in one list, and the projects VS Code and Cursor have open, grouped per editor with their git branch. Click a row to open that project in the editor. Optional alerts open the panel when a session changes from busy to waiting or idle, and close it again after a few seconds if nobody looks.

  • Clipboard: on macOS the panel mirrors gxlself's own Paste app (gxlself.paste-tool) and offers to install it when it is missing; on Windows, where there is no Paste, Bangs records the history itself. Click an entry to put it back on the clipboard.

  • To-do: a short list you type into — the one place the notch takes the keyboard, and only while the field is focused. Click a line to tick it off: it is struck through and sinks below what is still open, and clicking it again brings it back. Deleting is its own act — the × on a line, or "Clear done" for every done line at once — and a deleted line comes apart and blows off the list. A new line waits beside the collapsed notch for a few minutes unless something is playing.

  • Tabs: drag a tab along the bar to put the panels in the order you use them; the order is kept across restarts. A tab that only shows up sometimes, like the board, keeps its place.

  • Board: anything else on the machine can dock a row — a title, a subtitle, a progress bar and at most a link — by writing a JSON file, or by posting to a loopback endpoint. The newest row shows beside the collapsed notch. See docs/plugins.md.

  • Apple Watch: a watch app (watch/) for the same glance on the wrist — now playing with lyrics and transport controls, the Claude Code / Codex sessions with a tap when one stops working, the to-do list and the board. It reaches Bangs over the local network once the tray's Apple Watch submenu opens the port and the watch pairs with the code shown there. It ships inside the iPhone app. See watch/README.md and docs/watch.md.

  • iPhone & iPad app (ios/): to-dos, the dev panel's Claude Code / Codex status, the clipboard and the shelf on your phone, synced through your own iCloud (CloudKit, like Paste) — no server. To-dos go both ways; the rest is the Mac's mirror, read-only on the phone. Off until you turn it on in the tray menu ("Sync with iPhone (iCloud)"); to-dos, session details, clipboard text and pictures are end-to-end encrypted in CloudKit (shelf files are ordinary CloudKit assets). macOS only; Windows keeps its data local. See docs/sync.md.

Screens with a hardware notch get wings around it; other screens get a virtual notch, which shrinks to a thin bar when nothing is happening (the tray menu can turn that off). Full-screen video, games and presentations get the screen to themselves: the notch collapses to that bar on macOS and hides altogether on Windows — unless the screen has a real cutout, where it was never in the way.

Develop

Requires Node.js (^20.19.0 || >=22.12.0), pnpm and Rust. macOS also needs the Xcode command line tools.

pnpm install
pnpm tauri dev            # run
pnpm tauri build          # .app/.dmg on macOS, .msi/.exe on Windows

Build each platform on that platform (Windows installers cannot be produced on macOS).

iPhone app and sync

Plain pnpm tauri dev has no iCloud entitlements, so it runs with sync switched off (the tray menu says so); everything else works. To develop the iPhone app and the sync itself:

# once: the Apple Developer setup in docs/sync.md ("环境、签名与权限") — iCloud container,
# two App IDs, and a Mac development profile saved as src-tauri/icloud/dev.provisionprofile

# the iPhone app (needs Xcode 15+ and `brew install xcodegen`)
cd ios && xcodegen generate && open Bangs.xcodeproj    # pick your iPhone, Run

# the Mac side, signed for the CloudKit Development environment, same as the app from Xcode
scripts/dev-icloud.sh                                  # then tray menu → "Sync with iPhone (iCloud)"

# the merge rules, which both sides test against docs/sync-vectors.json
(cd src-tauri && cargo test -- sync:: todos::)           # Rust
(cd packages/BangsCloud && swift test)                 # Swift

scripts/sync-preflight.sh lists whatever this Mac is still missing (Xcode, XcodeGen, the profile, the certificate, iCloud), and docs/sync-testing.md walks through testing it end to end.

pnpm tauri dev --features icloud also works for checking that the Swift bridge builds and links: the binary is unsigned there, so it reports "no iCloud entitlement" and never touches CloudKit. A release that can sync is BANGS_ICLOUD=1 scripts/build-release.sh --mac; see docs/sync.md for what the Developer ID profile needs and why the CloudKit schema has to be deployed to Production first.

The tray menu — the menu bar icon on macOS, the notification area icon on Windows — controls show/hide, expand on hover, idle bar, lyrics, lyric translations, Claude alerts, display, language, the Apple Watch connection and launch at login.

Bangs speaks Chinese and English, following the system language unless the Language submenu pins it to one (src-tauri/src/i18n.rs, src/lib/i18n.ts). WKWebView reports the app's own language rather than the system's, so the native side resolves it and hands it to the webview. Its last entry is the version: it asks GitHub for the newest release at start-up and every six hours, says "有新版本 vX.Y.Z" when this build is behind, and opens the release page when clicked (src-tauri/src/update.rs). Nothing is ever downloaded or replaced without the user.

Release

scripts/version.sh 0.2.0        # one version across package.json, tauri.conf.json and Cargo.toml
scripts/build-release.sh        # .dmg + .app.zip here, .exe + .msi over ssh on the Windows box
scripts/publish-site.sh         # site/ to the gh-pages branch

scripts/publish-release.md has the full checklist: the asset names both the site and the in-app version check depend on, and the one command that stores the notarization credentials (BANGS_NOTARY_PROFILE). Signing happens automatically from the keychain's Developer ID; the hardened runtime needs src-tauri/entitlements.plist, whose Apple Events entitlement is what keeps the Spotify panel working in a notarized build.

Lyrics query QQ Music and NetEase concurrently, rank candidates by title, artist, album, duration and version, then prefer word-timed results with well-aligned translations. Reliable translations can be merged across providers after a global timeline offset is verified. Only track metadata is sent; results use expiring on-disk caches, can be refreshed from the music panel, and the tray menu can turn lookup off.

The clipboard panel asks Paste for its panel with open pasteg://panel, which Paste answers in AppDelegate.application(_:open:); older Paste builds only get activated instead.

How it works

macOS Windows
Window NSPanel (tauri-nspanel), non-activating, status level above the menu bar Topmost, focusable: false (WS_EX_NOACTIVATE), no taskbar entry; hides during full-screen apps
Now playing MediaRemote, loaded into /usr/bin/perl (see below) GlobalSystemMediaTransportControlsSessionManager
Notch size NSScreen.safeAreaInsets / auxiliaryTop*Area Virtual only
Dev panel Claude Code / Codex session state and VS Code / Cursor state Same, using Windows application-data paths
Clipboard Paste's Core Data store, read-only Bangs' own history
Full screen A layer-0 window covering the display (CGWindowListCopyWindowInfo) SHQueryUserNotificationState
Keyboard The panel is made key while the to-do field is focused, and resigns it after WS_EX_NOACTIVATE comes off for as long, then focus goes back
Lyrics QQ Music and NetEase, cached on disk Same

The host window is a fixed 640 x 280 transparent window in logical pixels. The visible notch animates inside it, and a native thread polls the cursor every 33 ms (src-tauri/src/geometry.rs) to:

  • make the window click-through everywhere except the current notch rect,
  • emit hover and outside-click events,
  • stream the pointer position, because WKWebView ignores mouse moves in a panel that is not key. CSS therefore uses [data-hover] (set by src/lib/hover.ts) instead of :hover.

MediaRemote on macOS 15.4+ requires an Apple-entitled process. src-tauri/native/macos/media_bridge.m is built by src-tauri/build.rs into src-tauri/resources/libbangs_media.dylib, loaded into /usr/bin/perl, and talks to the app over stdio (JSON lines out, commands in). This relies on system behavior Apple could change in a future release.

The dev integration polls every two seconds, reading ~/.claude/sessions/*.json, the newest ~/.codex/sessions rollout logs (a session counts as running while its log has an unfinished task_started), the editors' User/globalStorage/storage.json, and project .git/HEAD read-only. It checks running processes to ignore stale sessions and closed editors. Opening a project uses the editor on macOS or its code / cursor CLI on Windows, with a folder-reveal fallback.

On macOS the clipboard panel opens Paste's local Core Data store (PasteTool.sqlite) read-only and polls the latest 24 entries every three seconds, checking Paste's sandbox container first. Bangs never writes to that database; picking an entry writes to the system clipboard — a picture goes on as PNG and TIFF, so it pastes anywhere — while file entries hand over to Paste's own panel (pasteg://panel), which is what holds them.

On Windows there is no Paste, so Bangs keeps the history: it polls GetClipboardSequenceNumber, stores what changed (text and dropped file paths, up to 200 entries) in the app data directory, and writes an entry back when it is picked. Content that apps mark private with ExcludeClipboardContentFromMonitorProcessing or CanIncludeInClipboardHistory — password managers do — is skipped, and the tray menu can stop the recording altogether.

src/                       React UI
  App.tsx                  native events, drag/drop and agent alerts
  components/              Notch shell, compact/expanded views, music and shelf panels
    DevPanel.tsx           agent sessions and per-editor project rows
    ClipboardPanel.tsx     clipboard history, copy, clear and install actions
  store/                   zustand stores: notch state machine, media, shelf
    dev.ts                 agent sessions, workspaces and busy-to-idle/waiting detection
    clipboard.ts           clipboard history, copy feedback and platform actions
    TodoPanel.tsx          the to-do list and the field that takes the keyboard
  lib/layout.ts            notch sizes per mode (keep WINDOW in sync with geometry.rs)
  lib/hover.ts             pointer-driven [data-hover] workaround
    lyrics.ts              current lines and the line-at-time lookup
src-tauri/src/
  lib.rs                   app setup, bootstrap and commands
  geometry.rs              window placement, hit rect, cursor tracker, display watcher
  platform/{mac,win}.rs     window setup, cursor, notch metrics, editor launch, full-screen handling
  media/{mod,mac,win}.rs    shared media state and platform now-playing providers
  dev.rs                   read-only Claude/Codex/editor polling and project opening
  lyrics/mod.rs            lyric lookup, LRC/QRC parsing and the on-disk cache
  lyrics/qrc.rs            vendored QRC decrypter (per-character timings)
  media/spotify.rs         Spotify over AppleScript, for what the session leaves out
  update.rs                the newest GitHub release, for the tray
  clipboard/mod.rs         shared clipboard panel state and commands
  clipboard/mac.rs         read-only Paste store, copy and panel hand-off
  clipboard/win.rs         Bangs' own clipboard history
  todos.rs                 the to-do list, saved in <config>/todos.json
  remote.rs                the Apple Watch API on the local network, pairing and paired watches
  http.rs                  the bit of HTTP both local APIs share
  shelf.rs                 file metadata, open/reveal, drag preview
  tray.rs, settings.rs      tray menu and persisted settings
site/                      the landing page published to gh-pages
watch/                     the Apple Watch app (SwiftUI, watchOS 10+), a target in ios/project.yml
scripts/generate-icons.swift  app/tray/drag icons (then `pnpm tauri icon src-tauri/icons/app-icon.png`)
scripts/version.sh, build-release.sh, publish-site.sh, windows-build.ps1  release plumbing

About

把屏幕顶端那一条变成工作台:逐字歌词、Claude Code 会话、剪贴板、文件暂存架。macOS 与 Windows 通用。

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages