Void Presence Release Schedule
Track current and past releases, prereleases, and published builds.
Track current and past releases, prereleases, and published builds.
Latest GitHub release appears at the top.
Prereleases and nightly builds are ordered by release date.
View downloads analyticsIf your Rich Presence buttons are not visible in Discord, see the status page for details.
Read setup & troubleshootingstopDiscordRich() now awaits savePersistOffsetIfNeeded() — config file always updated before exit.updatePersistOffsetIfNeeded() fire-and-forget → awaited in stopDiscordRich() — Promise always resolves before shutdown.setTimestampConfig() Promise hangs → Emergency save on stop with await guarantee.reattachDnDForProfiles rebinds DnD for all profile‑related lists after applying a config.createListManager, but wired it to the shared DnD helper so newly rendered rows automatically participate in sorting.applyStateToUIAndLists.······) on the left side of all list rows:
······ rotated 90° so they appear vertical on the left.draggable attribute now lives only on .drag-handle, not on the whole row.drag‑handle across all list‑rendering helpers:
createRow generic helper now includes .drag-handle.renderRecentApps now includes .drag-handle for recent app entries.dragstart was triggered somewhere other than the handle.Connecting RPC Client ID: <id>).App not found or Fetch failed) and are visually dimmed./applications/{ID}/rpc endpointoverflow: hidden from config panels — long data lists (cycles, buttons, recent apps) now properly scroll instead of clipping contentpersist timestamp offset reset on app restart after a power loss — persistOffsetSec is now preserved in the config and no longer gets overwritten by renderer state.length > 18) before saving to client-config.json.clientId: null after restart — empty strings from inputs no longer overwrite valid IDs.client-config.json, settings.json, image-cycles.json, party-config.json, timestamp-config.json, etc.) are now written via temporary file + rename when possible.tmp‑file cleanup.live-set-party, live-set-images, and related IPC handlers now safely recover from ENOENT / EPERM filesystem errors during config writes.(optional) placeholder text:
{ placeholder: 'State (optional)', value: entry.state || '' }.state values are represented with a clear, optional‑labelled placeholder instead of leaving misleading empty labels.now / range / persist and nowMode.EPERM: operation not permitted and ENOENT: no such file or directory errors when saving:
image-cycles.jsonclient-config.jsonparty-config.jsonvoidpresence://auth?authorId=....authorId is saved into localStorage and the config-author-input field;authorId copy‑paste is required — the profile is pre‑connected.Guaranteed First Activity Push
Discord RPC now always pushes config cycles activity immediately on ready via pushActivity(null).
Fixed complete index reset (cycleIndex=imageIndex=buttonIndex=partyIndex=0) — first cycle guaranteed on startup.
Session State Consistency
Proper initialization of currentTitle, lastSmTcStatus/Position, and lastJsonSignature for seamless pollJsonLoop() transitions.
attachDnD<T> generic with precise drop zones (drop-target-top/drop-target-bottom), stable hover states via dragenter/dragleave, and TypeScript-safe dataset handling.
Smoother dragging, no flickering, accurate drop positioning — fully reliable across all list types.Unified List Management
All user-editable lists (buttons, cycles, images, party, time blocks) now share a common createListManager<T> helper.
This reduces duplicated DOM-rendering and localStorage-saving code, making the config UI modules much more DRY and maintainable.
Reusable Row-Creation Helpers
Each config row (createButtonPairRow, createCycleRow, createTimeRow, etc.) is now built on top of a central createRow helper.
Row-related DOM creation, event listeners, onUpdate and onRemove hooks are now centralized, improving consistency across features and reducing boilerplate.
Config Module Organization The config-related logic has been split into clearly separated modules:
list-renderers – common list-handling and createListManager;rows – row-creation helpers;clientId-controls – clientId, intervals, toasts, drag-and-drop setup;mode-controls – timestamp and “now mode” logic;time-controls – time-cycles handling.
This makes it easier to locate, update, and test specific pieces of the UI.Helper-Driven Architecture Many duplicated patterns (DOM-element creation, localStorage I/O, drag-and-drop wiring) have been moved into reusable helpers instead of being scattered inline across multiple functions. This improves type-safety, testability, and makes future UI changes less error-prone.
Type-Safe Attachment Layer DnD-attaching and list-rendering now use a generic-style pattern, so the same logic can be applied to different list types without manual code duplication. TypeScript errors are easier to catch upfront, and the structure is more predictable for contributors.
No UI Behavior Changes From the user’s perspective, nothing has changed:
>= 1) instead of raw JavaScript milliseconds.
This fixes validation errors such as:
child "activity" fails because [child "timestamps" fails because [child "start" fails because ["start" must be larger than or equal to 1]]]
when updating activity via SET_ACTIVITY.Consistent Time Format for Discord
All internal time calculations still use JavaScript milliseconds (from Date.now()), but before sending data to Discord, they are converted to Unix seconds using a small helper function.
This ensures that the activity.timestamps.start and activity.timestamps.end fields always match Discord’s expected format and range.
Safe Timestamp Conversion Layer A dedicated conversion helper now:
Math.floor(ms / 1000).< 1), so Discord never receives zero or negative timestamps.activity.timestamps object right before the SET_ACTIVITY request is sent.No Behavior Changes for Existing Features All existing behaviors (such as “now”, “range”, “persist” timestamp modes and playback progress from the media session) remain the same from the user’s point of view. Only the way timestamps are formatted for Discord has changed, making the integration more stable and standards‑compliant.
dotenv Dependency
The project no longer depends on the dotenv package for loading environment variables.ready Handler Adjusted
The localClient.on('ready') handler now:
NowPlaying snapshot from SMTC.pushActivity(np) once and only then sets sendStatus('ACTIVE').lastJsonSignature based on the initial snapshot so that the polling loop does not immediately re‑send the same payload.live-set-timestamp IPC handler so that switching timestamp modes (now, range, persist) no longer forces a Discord Rich Presence restart. Mode, range, and display settings now apply live without interrupting the active RPC session, making timestamp experimentation feel more responsive in the UI.mode, rangeMin, rangeMax, persistOffsetSec, nowMode, timeCycles) now flows through the shared setTimestampConfig helper, ensuring consistent validation, rounding, and safety checks across both regular and live update paths.persistOffsetSec timestamp configuration so that large jumps are ignored. Incoming persistOffsetSec values are still rounded to the nearest 5 seconds, but if a new value is more than 10 seconds higher than the currently stored offset, the change is discarded and the existing value is preserved. This prevents accidental or noisy updates from causing sudden, unrealistic jumps in the persisted timestamp.uploadBtn.innerHTML) to better match the rest of the UI, improving visual consistency and making the upload action more noticeable without changing its behavior.Centralized Main Config Module
All JSON config read/write logic (client-config, buttons, cycles, image-cycles, party, timestamp, settings) has been consolidated into a single main/config.ts module, using a generic Validator<T> and safe helpers readJsonWithSchema / writeJsonSafe for consistent validation and error handling.
Async Settings API
Legacy synchronous loadSettings / saveSettings have been replaced with asynchronous readSettings / writeSettings, and readFiltersState can now rely on the shared Settings validator, reducing duplication and improving code clarity.
tag: broken
UpdateInfo shape for updates, including changelogMd for the inline changelog.UpdateInfo shape for updates, including changelogMd for the inline changelog.Lighter Gray Theme Refresh: Switched from dark theme to a softer gray palette for reduced eye strain and modern feel — lighter, more comfortable for long sessions.
New Tutorials: Added guided tutorials on the main screen and config pages for easier onboarding.
Overall UI Lightness: Streamlined layouts, smoother animations, and better readability across all modes.
tag: stable
basic, while exports always include the current mode for clearer sharing and backup behavior.basic across the app (UI state, local config and Electron settings) to avoid mismatched behavior on fresh installs.fade-in, translateY) for all views and modals.TypeError: Cannot read properties of undefined (reading 'state') that occurred when reducing the number of entries in Cycles or Image Cycles while the app was running.cycleIndex against the current array length. If the configuration is saved with fewer entries, the index automatically resets to 0 instead of crashing the update loop.cycleIndex management across both Basic and Advanced RPC modules.v2.3.4 - Fix Ipc Modules & SMTC Worker
Basic / Advanced RPC modes
Added switchable RPC mode: Basic (classic Rich Presence without SMTC) and Advanced (Advanced Rich Presence with media player and SMTC worker support).
The mode is saved in the settings and automatically applied the next time the app is launched.
Safe RPC restart without duplicate sessions
Restarting Discord Rich Presence now correctly stops an active session before starting a new one, reusing the single path and the startDiscordRich callback.
This prevents the accumulation of background RPC connections and eliminates duplicate activity updates.
The SMTC worker is enabled only in Advanced mode
The SMTC worker now starts only in Advanced mode and stops automatically when switching to Basic.
This reduces overhead costs in scenarios where media integration is not needed.
Consistent activity interval handling
Activity update intervals are now redirected via the common function setActivityInterval, which takes into account the selected RPC mode.
This ensures predictable timing behavior in both Basic and Advanced modes.
basic/advanced) and delegates the start/stop calls and interval settings to the appropriate modules.startDiscordRich helper, which minimizes duplicate logic and simplifies RPC lifecycle management.SMTC_USER_DATA and polls the media status at a fixed interval, publishing only current changes.Reduced CPU usage for SMTC worker
The SMTC worker now caches the media session status and updates the now-playing' file.json only for actual track changes or playback status.
This reduces the number of accesses to the system API and writes to disk, reducing the load in the background.
Optimized now-playing.json polling in RPC
The Discord RPC module reads now-playing.json uses a single secure method and reuses the received data instead of re-reading and parsing the file in several places.
Unnecessary accesses to the file system are removed, which reduces peak CPU consumption.
Smarter Rich Presence updates
Discord activity updates are now performed only when the track signature (name, status, position) changes, and not on every tick of the timer.
This reduces the number of SET_ACTIVITY requests and helps you avoid hitting Discord's update frequency limits.
Track cover caching with size limit
A limited cache of track covers has been added to avoid requesting iTunes, TheAudioDB, and MusicBrainz during each update cycle.
The cache is automatically cleared when the limit is reached, keeping memory usage under control.
NowPlaying publishing path, which minimizes duplicate work.readNowPlayingSafe) and transmits the result directly to pushActivity, eliminating repeated parsing of JSON.Correct timestamp persistence
Saving settings via SAVE and RESTART PRESENCE no longer resets persistOffsetSec to 0.
The current offset value (for example, 110 seconds) is now saved until the user explicitly resets.
Reset saved timestamp is working correctly
The reset saved timestamp button now:
resets only the saved timestamp (the persistOffsetSec field),
does not touch mode, rangeMin, RangeMax, nowMode and timeCycles,
Secure saving of time configuration
The updated logic of setTimestampConfig now:
merges with the current config (readTimestampConfig),
does not overwrite persistOffsetSec if it is not passed from renderer,
now uses the currentpersistOffsetSec' if the field was not passed from the UI.setTimestampConfig from renderer during SAVE and RESTART PRESENCE no longer resets the internal 'saved time'.resetPersistTimestamp + overwrite only `persistOffsetSec').Basic vs Music and Youtube) with seamless switching — Music and Youtube now intelligently detects and displays music activity (Spotify) and YouTube playback alongside custom presence data.sendLog integration for critical events like SMTC worker lifecycle.RPC Mode now shows real music and YouTube activity in Discord status!
now), randomized ranges (range), or a persistent start point (persist) for your activity timer.Save and Restart RPC now only adds a new history entry for a client ID if it does not already exist, avoiding overwriting names or timestamps of existing entries.autoHideOnStart enabled — createMainWindow now always called on app launchstartDiscordRich call, preventing conflicts and double updatesapp.whenReady(), hide only if autoHideOnStart=truegetMainWindow() + show() instead of createMainWindow() on clickUpload Current button in profile cards so it now uploads the full state of the selected profile instead of the current in-memory UI state.cfg.state.config-page.ts to add a dedicated handler for per-profile cloud upload that mirrors the global Upload Currentblur event handling.Removed the built-in auto-update helper due to unstable behavior and unnecessary complexity in production. The app now falls back to a simple version check and a link to the latest GitHub release, letting users decide when to download updates manually.
app-update.yml errors and other side effects caused by the auto-update setup in Windows builds.Expanded the version system with optional auto‑update flow and refined cloud config UX, building on top of the 1.4.x version check and warnings.
info / warn levels for update flow eventsLogLevel (info, warn, error, success) and consistent renderer stylingmain/, ipc/, logging/, cloud/, and updates/ modules for better maintainabilityAdded GitHub version check on startup with in‑app warning logs and status indicator when a newer Void Presence build is available.
app.getVersion()OUTDATED_VERSION RPC status with orange status chip and dot, indicating that an update is availableinfo, warn, error, success) from the main process, with colored indicators in the rendererwarn level (border, background, dot color) matching existing error/success semanticsrenderer/ folder for UI logic, state handling, and view wiringbridge/ and ipc/ modules for safer main–renderer communicationconfig/ (load/save, validation) and profiles/ (profiles list, active profile, cloud payload)Full TypeScript renderer and improved cloud config upload stability.
renderer.js to TypeScript with strict typing for Window, electronAPI, VoidPresenceCtx, cycles, and buttonsFileList → File, nullable fields for cycles and images)localStorage usage for configs, intervals, and auto-start/auto-hide flagsCloud config upload – users can now upload and share their Discord presence configurations directly to the cloud.
upload-config)push() for unique config IDselectronAPI.uploadConfigDownload the latest version "v1.4.0" and extract it to any location.
Your existing configurations from v1.3.2+ will continue working seamlessly. Local configs auto-sync with cloud on first launch.
Tray behavior fix – the window now correctly moves to the tray only when closing, while the minimize button keeps it visible in the taskbar.
Improvements:
Bug Fixes:
Download the latest version "v1.3.2" and extract it to any location. Your existing configurations and profiles will not work if you upgrade from v1.3.1 or lower.
Smarter profiles workflow – importing and managing presets is now simpler and more transparent directly from the config view.
Improvements:
.json file anywhere on the app, with dashed borders around the edges when the drop zone is activeNew Features:
Bug Fixes:
Richer session controls – managing Void Presence is now more convenient and transparent directly from the main view.
Improvements:
DISABLED, RESTARTING, DISCONNECTED, etc., reflected in both the status chip and logsNew Features:
Bug Fixes:
Not respondingDownload the latest v1.3.0 release and extract it to any location.
Your existing configurations and profiles will keep working as before, with the new session controls and profile details available right away after updating.
New pages and config tools – Void Presence is now easier to configure and maintain without touching your existing setups.
Improvements:
.json configs onto the +Config area.jsonNew Features:
Bug Fixes:
Download the latest v1.2.0 release and extract it to any location. Your existing configurations will continue to work as before, but you can now manage them through the new Config page.
Discord buttons are now optional – you no longer need to add button pairs to use Void Presence. Configure just your Client ID and status cycles, and the app will work perfectly without buttons.
Improvements:
Bug Fixes:
Download the latest release and extract to any location. No changes needed to existing configurations – existing button setups will continue to work as before.
v1.0.0-alpha Void Presence
Advanced Discord Rich Presence manager with customizable button pairs, text cycles, and image rotation. Status updates every 30 seconds with full control over your Discord activity display.
Easy Setup: Download the ZIP file from GitHub, extract it, run Void Presence.exe, and configure your Discord status in seconds.
Code button → Download ZIPVoid Presence.exeSAVE buttonGet your Application ID from Discord Developer Portal:
Ctrl+, – Show/hide windowCtrl+R – Restart Rich PresenceCtrl+Q – Quit applicationMade with ❤️ by Devollox
Void Presence – Control your Discord presence. Own your story.