- Apple silicon only — release builds are now arm64-only (
ARCHS[sdk=macosx*] = arm64,EXCLUDED_ARCHS[sdk=macosx*] = x86_64inproject.yml). Apple's September 2026 guidance lets apps that require macOS 13+ drop Intel, and macOS 27 runs only on Apple silicon. Intel Macs should stay on v1.4.3.
- DDC on Macs with more than one display port (Mac mini, Mac Studio) — the port a display is attached to is now discovered instead of assumed. Apple silicon publishes one
DCPAVServiceProxyper physical port (HDMI, each Thunderbolt) even when the port is empty; with a single monitor Glint always talked to the first proxy, so a monitor on the "other" port (e.g. a Mac mini driving a DisplayPort monitor over Thunderbolt) saw every read fail and both rows showed Not applicable. Candidate ports are now ordered (last port that answered → EDID UUID match in the IORegistry → positional guess → unclaimed ports) and probed with a real DDC read until one replies; the winner is remembered per display and re-discovered on display reconfiguration. Writes go through the same resolution so they can't land on an empty or neighbouring port. Ports another connected display would claim positionally are skipped unless the EDID says otherwise, so a monitor without DDC can't fall through to its neighbour. - Two compiler warnings cleared — the menu-bar visibility observer now asserts main-actor isolation (
MainActor.assumeIsolated) instead of calling MainActor-isolated methods from a nonisolated closure, and the CoreAudio device-name lookup receives its +1CFStringasUnmanagedinstead of forming a raw pointer to aCFStringvariable.
- Settings → "Support Future Development" (MillerKit 1.2.0): a heart row in the Enjoying Glint? block that opens wemiller.com/support — GitHub Sponsors, Ko-fi, a one-time tip.
- MillerKit pinned at 1.3.0 —
Package.resolvedhad stayed at 1.2.0 afterproject.ymlmoved tofrom: "1.2.2"(structural funding-link gate), so everyxcodebuildre-resolved the package and rewrote the lockfile, leaving the tree dirty after any build. The pin now records what the requirement actually resolves to; 1.3.0 itself only registers Kern in MillerKit's shared suite registry, nothing Glint-visible.
- Support future development — the landing page and README gained a support block with GitHub Sponsors and Ko-fi links (plus a link to every way to support at wemiller.com/support). Glint stays free: no ads, no tracking, no subscription
- Settings no longer duplicates Support — removed the redundant “Open Support in Its Own Window” button; support/feedback stay inline via MillerKit’s
SupportSection. The detachable support window remains available from the menu bar Support… item.
- MillerKit 1.1.0 — real version display, working privacy link, and shared About presentation
- Liquid-glass app icon — the monitor-and-sun glyph is now a transparent Icon Composer layer over a purple manifest fill (taken from the original artwork's gradient), so macOS renders the same glass depth (shadow + translucency) as the rest of the suite. Previously the layer was a fully opaque square that occluded the fill and read as a flat tile.
Scripts/generate-assets.swiftnow emits the transparent glyph layer alongside the .icns and DMG assets
- Fully localized in 8 languages — German, Spanish, French, Italian, Japanese, Korean, Portuguese (Brazil), and Simplified Chinese, across the menu bar UI, settings, and support window
- Dedicated support window — help, feedback, and the rest of the app family in one place (via the shared MillerKit support kit)
- MillerKit now resolves from GitHub (
blaineam/MillerKit1.0.0) instead of a local sibling checkout, so CI builds no longer depend on the machine layout
- App icon background fills the full square — removed pre-baked rounded corners and transparency from icon generation scripts (
generate-assets.swift,generate-web-assets.swift); the design now extends edge-to-edge and macOS applies its own squircle mask, eliminating visible transparent corners in Finder, Dock, and Spotlight
- App icon now sourced from the asset catalog — removed the post-build
.icnsinjection fromScripts/build-dmg.sh; the icon now comes exclusively fromAssets.xcassets/AppIcon.appiconsetas compiled byactool, eliminating a duplicate icon source that could drift from the bundled catalog - project.yml version aligned —
CFBundleShortVersionStringhad drifted to 1.3.8 inproject.ymlwhile shipped builds were 1.3.9; bothproject.ymlandInfo.plistare now in sync
- Refreshed app icon to match Apple's macOS guidelines — removed the 10% inset that was making the squircle float in extra padding, and scaled the monitor-with-glint logo up to fill the icon properly; affects the in-app icon, the DMG installer, and all web/portfolio icons
- Bundle plist version aligned — the Info.plist
CFBundleShortVersionStringhad drifted to 1.3.2 across several releases; now correctly reflects the released version
- Fix Swift 6 strict concurrency errors: Add
@MainActorannotation topromptAccessibility()and wrap the OSD fade-out completion handler withMainActor.assumeIsolatedto satisfy Sendable closure requirements - Runtime API resolution for future macOS resilience: IOAVService (Apple Silicon DDC) and DisplayServices (built-in brightness) are now resolved at runtime via
dlsym/dlopeninstead of link-time binding. If Apple removes or renames these private symbols in a future macOS, Glint still launches and falls back to IOKit APIs instead of crashing on startup - Runtime transport detection: DDC transport selection (IOAVService vs IOFramebuffer) is now based on runtime symbol availability instead of compile-time
#if arch(arm64), making the app resilient to future hardware changes
- Write-only volume mode: New toggle in Settings that skips DDC volume reads entirely — initializes at 50% and tracks volume in memory, sending only DDC writes. Fixes monitors (e.g., some LG displays) where DDC volume reads always fail but writes work fine
- Volume adjustment falls back to write-only automatically when
ddc.adjustfails and the setting is enabled
- Exponential backoff DDC reads: Failed reads now retry up to 3 times with exponential backoff (100ms, 200ms, 400ms), fixing volume reads that fail after brightness reads on rate-limited LG monitors
- Default max volume/brightness to 100: If a monitor reports a current value but a zero or missing max, Glint defaults max to 100 instead of showing broken sliders
- Smart key interception: Brightness and volume keys are only intercepted when DDC successfully detected that capability on startup. If DDC volume reads fail, volume keys pass through to macOS as normal
- Always intercept override: New per-control "Always intercept" toggles in Settings for monitors that respond to DDC writes but not reads
- Serial DDC queue: All I2C operations (reads and writes) now go through a serial
DispatchQueue, preventing concurrent bus access that caused LG monitors to drop commands. Every operation enforces a 100ms cooldown before hitting the bus - Startup reliability: DDC retry loop no longer re-reads values that already succeeded — if brightness reads OK on the first attempt, only volume is retried. Retry delay increased from 100ms to 500ms to give LG monitors more recovery time
- TTL read cache: 2-second read cache avoids hammering DDC reads on rapid key presses. Cache is updated after every successful write so subsequent adjustments stay accurate without extra reads
- TTL read cache for DDC: Adds a 2-second read cache to avoid hammering DDC reads on rate-limited monitors (e.g., LG). Rapid key presses reuse the cached value and write immediately; on cache miss a real DDC read is performed with an I2C settling delay before writing. Cache is updated after every successful write so subsequent adjustments stay accurate without extra reads
- Volume adjust uses ddc.write: Volume adjustment now uses direct
ddc.writecalls with cached reads instead of rawddc.readper keystroke, fixing volume control failures on monitors that rate-limit DDC commands
- Fix volume adjustment: Use
ddc.readthenddc.writefor volume changes instead ofddc.adjustwhich added an unnecessary 50ms delay between read and write
- DDC read retries on startup: Initial display refresh now retries DDC reads up to 3 times with 100ms delays — fixes "N/A" sliders on monitors that need time to respond after connection
- I2C bus settling delay: Added 50ms delay between DDC read and write in adjust commands — fixes monitors (e.g., some LG displays) that drop writes arriving too quickly after a read
- Adjust returns max value: DDC adjust now updates both current and max values in the display state, ensuring sliders and OSD always have correct ranges
- Debug logging: Optional debug log that records DDC commands, audio routing decisions, display detection, and I2C results to
~/Library/Application Support/Glint/debug.log— toggle in Settings with a button to reveal the log in Finder - Better audio/display name matching: Partial word-level matching for audio device names against display names (e.g., "LG HDR" matches "LG HDR 4K (2)")
- USB-C hub audio detection: Volume keys now correctly use DDC for monitors connected through USB-C hubs/docks by matching the audio device name against connected display names
- Fix About version: Settings now reads version from the app bundle instead of a hardcoded string
- Mute OSD: Mute key now shows a muted speaker icon when muting and the volume level when unmuting
- Accessibility restart notice: Alert and settings view now inform users that Glint must be relaunched after enabling Accessibility access
- Smart volume routing: Volume keys now automatically use DDC when audio output is HDMI/DisplayPort, and system volume when using built-in speakers, headphones, USB, or Bluetooth — switches gracefully when you change output devices
- Audio-aware mute: Mute key targets the correct output based on the active audio device
- Cursor-aware brightness: When sync is off, brightness keys now only adjust the display the cursor is on
- Proper display sync: When sync is on, the first brightness key press forces all displays (built-in + externals) to match the cursor display's brightness before adjusting them together
- Menu bar slider sync: Dragging a brightness slider in the menu bar popover now propagates to all displays when sync is enabled
- OSD on correct screen: The brightness overlay now appears on the screen the cursor is on
- Initial release
- DDC/CI brightness and volume control for external displays via keyboard media keys
- Sync mode to keep built-in and external displays in lockstep
- Subtle pill-style OSD overlay
- Invisible mode (hide from menu bar and dock)
- Launch at login
- Menu bar popover with per-display brightness and volume sliders