Durvald

Local-first music player with a shared Rust core and native interfaces

2025

Product and current stage

Durvald is a local-first music player evolving from a SolidJS/Tauri interface to native applications with a shared Rust core. Its purpose is to organize and play the listener's collection on their own device.

The macOS implementation is the most advanced. Windows is part of the migration to native interfaces, and an initial GTK4 implementation exists for Linux. These clients are at different stages; feature parity across platforms is not claimed.

Native Durvald interface on macOS, showing library navigation, the Switched-On Bach album and playback controls.Native macOS version: album details, track list and persistent player.

Authorship and learning

I developed the entire project, from its logo and visual identity to the interfaces and Rust core, with assistance from different AI models. Durvald is a personal development and learning project.

From Tauri to native interfaces

The Tauri version was still incomplete, roughly halfway through development, when I chose native interfaces as an opportunity to learn SwiftUI and GTK4. Much of the Rust core was already used in Tauri, limiting the impact of the change through reuse. The migration took place while building the product, rather than replacing an established production system.

The first implementation combined SolidJS presentation, Tauri commands and events for communication, and Rust processing. Its source remains public in durvald-tauri, documenting the earlier stage of the same product.

The current architecture concentrates shared responsibilities in the UI-independent durvald-core. The product's purpose remains the same, while native clients replace the shared presentation layer. This choice requires maintaining platform-specific integrations and interface behavior. The memory section records a local observation of both versions; controlled benchmarks are outside the current scope.

Interface of the earlier Durvald implementation using SolidJS and Tauri.Screenshot of the SolidJS/Tauri version; it does not show the current native interface.

Visual consistency across systems

The move toward platform-native interfaces also addressed a problem the author observed on Windows: transparency and blur effects using backdrop-filter failed in overlapping components of the Tauri interface. The author associated this behavior with Chromium issue #40835530, supplied as a technical reference for the investigation.

This experience increased the visual compatibility work required by the shared interface and contributed to the decision to adopt native clients. The reference identifies the investigated problem; its current resolution status was not confirmed in this review.

Tauri context menu on Windows, with a rectangular background extending beyond its rounded corners.Windows defect captured by the author. According to his experience, the same problem did not occur on Linux.

Linux distribution and maintenance cost

Beyond the goal of native interfaces, the project's Linux workflow depended on an Ubuntu environment according to the author's experience. External reports provide context: discussion #12960 records a linuxdeploy failure on Arch after compilation, involving an incompatible strip tool and maintainer comments on glibc portability. Issues #15106 and #11701 also report AppImage generation failures on Arch.

These reports reinforce the need to control packaging environments and distribution dependencies. They do not establish a universal Ubuntu requirement or a controlled comparison between distributions. Moving to GTK4 removes the Linux client's WebView, but system libraries, packaging and compatibility across distributions still require validation.

Shared core and contracts

The Rust core owns library indexing, SQLite persistence, local playback, history, settings and Last.fm integration. SwiftUI and other FFI clients use its UniFFI surface; the GTK4 client, also written in Rust, consumes the public Rust API directly without UniFFI bindings.

This boundary keeps shared rules outside the interfaces. The documentation defines contracts for paths and managed artwork, scanning and cancellation, audio formats and public errors. Clients should branch on CoreError variants rather than interpret diagnostic messages as contracts.

Consistency and long-running operations

Only one library scan may run at a time. Cancellation is cooperative: work stops at safe boundaries and cancelled results are not persisted. A complete scan reconciles removed files; a partial or cancelled scan preserves existing records.

In the GTK4 client, widgets remain on the GTK/GLib thread and core operations are dispatched to a Tokio runtime. This separates blocking work from the interface thread and requires coordinating asynchronous results with the window lifecycle.

Implementation by platform

  • macOS: native SwiftUI client integrated through the UniFFI surface; the most advanced development track.
  • Windows: under development as part of the move to a native implementation. This case does not yet provide a demonstration or validated feature list for this version.
  • Linux: a Rust/GTK4 foundation that opens a window, initializes the core and reads the number of persisted tracks. Import, track lists and playback controls remain next steps. Refreshing the library rereads the database; it does not start a scan.

Observed idle memory

In a local Activity Monitor capture, with both versions idle according to the author, the native process (Durvald) shows 73.5 MB. The four processes identified by the author as belonging to Tauri total 176.9 MB: http://localhost:1420 (95.7 MB), durvald (53.2 MB), durvald Graphics and Media (17.3 MB), and durvald Networking (10.7 MB).

ImplementationDisplayed memory
Tauri — sum of the four identified processes176.9 MB
Native macOS — identified process73.5 MB
Difference in this capture103.4 MB (approximately 58% lower)

Activity Monitor showing the native and Tauri Durvald processes and their memory values.Local observation supplied by the author, who confirmed the process identification.

The comparison sums the values displayed by Activity Monitor, not exclusive physical memory. This is a single observation: hardware, macOS version, commits, build mode, library size and idle duration have not been recorded in this case. The localhost address indicates locally served content in the Tauri version. These values do not establish a general reduction in memory, CPU usage or startup time; a reproducible comparison requires equivalent conditions and multiple runs.

Evidence and limits

This case brings together public code, interface screenshots and a local memory observation. Its focus is learning native interface development and reusing the Rust core while building the product. Comparative benchmarks are outside the current scope; the memory capture remains a single observation rather than a general performance claim.

Current source

Earlier version — Tauri

Rust core contracts

Linux client status and execution