Please keep contributions small, verified, and easy to review. This guide explains how to set up the project, change the app, and open a clean pull request.
WaveFlow is a Tauri 2 desktop app with a React/Vite frontend and a Rust backend.
| Requirement | Notes |
|---|---|
| Bun | Package manager and frontend scripts |
| Rust stable | rustc + cargo, through rustup |
| Tauri system dependencies | Required to build the desktop app |
On Linux, also install the native dependencies used by Tauri, WebKitGTK, and audio:
sudo apt install libgtk-3-dev libwebkit2gtk-4.1-dev libsoup-3.0-dev \
libayatana-appindicator3-dev librsvg2-dev libasound2-dev libssl-dev pkg-configgit clone git@github.com:InstaZDLL/WaveFlow.git
cd WaveFlow
bun installFor frontend-only work:
bun run devFor the full desktop app:
bun run tauri devThe first Rust build can take several minutes.
| Command | Effect |
|---|---|
bun run dev |
Starts Vite without the Tauri shell |
bun run tauri dev |
Starts the desktop app in development mode |
bun run lint |
Checks TypeScript/React code with ESLint |
bun run typecheck |
Runs tsc --noEmit |
bun run build |
Compiles TypeScript and creates the Vite build |
bun run format |
Formats the repository with Prettier |
cargo check --manifest-path src-tauri/Cargo.toml --all-targets |
Checks Rust code |
cargo test --manifest-path src-tauri/Cargo.toml |
Runs Rust tests |
| Path | Role |
|---|---|
src/ |
React frontend, components, hooks, Tauri wrappers |
src/i18n/locales/ |
App translation JSON files |
src-tauri/src/ |
Rust backend, Tauri commands, audio, scanning, integrations |
src-tauri/migrations/ |
Global and per-profile SQLite migrations |
docs/ |
Project documentation |
dist/, node_modules/, src-tauri/target/ |
Generated outputs that should not be edited |
- One pull request should cover one topic.
- Use Bun for JavaScript/TypeScript scripts.
- Do not commit secrets:
.env, keys, tokens, certificates, local databases, or user exports. - Do not manually edit
dist/,node_modules/,src-tauri/target/, or files generated by tools. - Keep changes focused on the files needed for the issue.
- For real-time audio code, do not allocate, lock, or log inside the
cpalcallback.
- Use TypeScript for the frontend and Rust for the Tauri backend.
- Follow the existing style: 2-space frontend indentation, double quotes, semicolons, and trailing commas when the file uses them.
- React components use PascalCase, hooks start with
use. - Add comments only when they explain a decision or a non-obvious constraint.
- Preserve accessibility for visible components: ARIA roles, keyboard focus, labels, and interactive states.
App strings live in src/i18n/locales/. WaveFlow ships 17 locales — fr
(source of truth), en, es, de, it, nl, pt, pt-BR, ru, tr,
id, ja, kr, zh-CN, zh-TW, ar, hi. There is no per-key fallback,
so every locale must include every key.
To add a language:
- Create
src/i18n/locales/xx.jsonwith the same structure asfr.json. - Translate every value without renaming keys. Keep brand tokens
(
WaveFlow,Last.fm,Deezer,ReplayGain,LRCLIB,BPM) verbatim and leave i18next{{placeholder}}interpolation untouched. - Import the file in
src/i18n/index.ts. - Add the language to
SUPPORTED_LANGUAGESandresources. If the script is RTL (Arabic, Hebrew…),index.tsalready setsdocumentElement.dirfromi18n.dir(code). - Run
bun run typecheckand test the language selector in Settings.
To add a new string:
- Add the key to every existing locale (all 17 of them).
- Use
t("key.path")in the React component. - If the string has a variable, keep the same name everywhere, for example
{{count}}.
WaveFlow uses SQLite with two migration families:
src-tauri/migrations/app/for the global app database;src-tauri/migrations/profile/for per-profile data.
When changing the schema:
- add a new timestamped migration in the right folder;
- keep existing migrations immutable;
- check the Rust code that reads or writes the changed tables;
- run at least
cargo check --manifest-path src-tauri/Cargo.toml --all-targets.
Run at least:
bun run lint
bun run typecheck
bun run buildIf you change the Rust backend, also run:
cargo check --manifest-path src-tauri/Cargo.toml --all-targets
cargo test --manifest-path src-tauri/Cargo.tomlFor visible UI changes, manually test the affected screen and attach a screenshot to the PR.
A good pull request includes:
- a clear summary of the user-facing impact;
- the verification commands you ran;
- schema or migration changes, if relevant;
- a screenshot for visible frontend changes;
- known limits or untested areas.
Commit messages follow Conventional Commits. The format is enforced locally:
bun install wires up a husky commit-msg hook that runs commitlint
(config in .commitlintrc.cjs, headers capped at 100 characters with
kebab-case scopes), so a malformed subject line is rejected before it lands.
type(scope): short summary
Common types:
| Type | When to use it |
|---|---|
feat |
User-facing feature |
fix |
Bug fix |
perf |
Performance improvement |
refactor |
Internal change without behavior changes |
docs |
Documentation |
chore |
Tooling, dependencies, maintenance |
test |
Test additions or changes |
Examples:
feat(player): add replaygain togglefix(library): keep deleted tracks unavailabledocs: add contributor guide
The release process is documented in RELEASING.md. Do not publish a signed build without following that procedure, especially for the Tauri updater key.
For a security vulnerability, do not create a public issue. Contact the maintainers privately and include enough information to reproduce the problem.