When only the closing block moved to page 2, the page-1 deficit was shared across every gap, including the closing block's own gaps, which cannot help page 1. Page 1 then came out a few points short and the totals spilled over with the closing block. Monolith and Cobalt Stripe now squeeze only the page-1 gaps in that case, as Marble and Highlighter already do. Monolith's flow notes block could start in the last few points of a page and be cut into zero-height lines. It now holds 70 pt of room under its label first, as Marble does. Adds tests for both cases (they failed before the fix) and notes in the template specs. Fingerprint goldens and thumbnails are unchanged.
Voiced
An offline-first desktop invoicing app for Arun P, built by Bongbetic.
Voiced turns a few details into a clean, GST-ready PDF invoice. It keeps a running invoice-number series in a local database, remembers your vendor and bank details, and exports print-ready PDFs — no account, no network required.
Features
- Automatic invoice numbering — a persistent series (e.g.
AP/2026-001) that keeps counting up, with a one-click "start a new series" that resets the counter. - Guided first-run setup — your name, address, contact, PAN, GSTIN, logo, signature and bank details, pre-filled from your existing invoice and editable at any time.
- Two line-item modes — a fixed amount, or a rate × quantity where the unit can be per second / minute / hour / session / unit (e.g. 10 sessions × ₹2,500).
- GST support — toggle taxes on/off and split as CGST + SGST (within state) or IGST (inter-state), with live totals and Indian amount-in-words.
- Signatures — attach a PNG/JPEG per invoice, or omit it and the invoice notes that it is computer-generated and needs no signature.
- PDF export — a print-ready A4 invoice styled to match the original
format.pdf. - Saved clients, invoice history with re-export, and light/dark (Carbon g10/g100) themes.
- Input validation for PAN, IFSC, GSTIN, email and phone.
Tech stack
| Layer | Choice |
|---|---|
| Shell | Tauri v2 (Rust core, WebView2 on Windows) |
| UI | React + TypeScript + IBM Carbon Design System (@carbon/react) |
| Fonts | IBM Plex, self-hosted (works offline) |
| Storage | SQLite via rusqlite (bundled) |
@react-pdf/renderer with bundled IBM Plex |
Prerequisites
- Node.js 20+ and npm
- Rust (stable) via rustup
- Linux dev only: WebKitGTK 4.1, libsoup3, GTK3, librsvg,
pkg-config,clang/llvm/lld
Development
npm install
npm run app:dev # launches the desktop app with hot reload
Other scripts:
npm run build # type-check + build the web frontend
npm run app:build # package the app for the current platform
Building for Windows (cross-compile from Linux/macOS)
Tauri only supports the MSVC target. Cross-compiling uses cargo-xwin
and produces an NSIS installer plus a portable .exe. A .msi still requires a real
Windows host.
# one-time setup
rustup target add x86_64-pc-windows-msvc
cargo install --locked cargo-xwin
# plus NSIS (makensis), LLVM/LLD and clang on the host
npm run app:build:windows
Output lands in src-tauri/target/x86_64-pc-windows-msvc/release/bundle/nsis/ and the
portable binary in the sibling release/ folder.
Notes for Linux hosts without an nsis package
makensis is required for the installer, and Tauri also fetches a small NSIS plugin. On
distributions that don't package NSIS (e.g. Void Linux):
-
Provide
makensis(e.g. extract it from your distribution's or an upstream package) and put it onPATH. -
Point
makensisat a full NSIS data directory (3.11 recommended, forWin/RestartManager.nsh); it looks in the directory compiled into the binary unlessNSISDIRis set. -
Pre-seed Tauri's plugin cache so it does not have to download it:
mkdir -p ~/.cache/tauri/NSIS/Plugins/x86-unicode/additional # nsis_tauri_utils.dll (SHA1 75197fee3c6a814fe035788d1c34ead39349b860) # from https://github.com/tauri-apps/nsis-tauri-utils/releases
With those in place, npm run app:build:windows produces the NSIS -setup.exe and the
portable voiced.exe.
Installing on Void Linux
Two ways to get a native .xbps package.
Prebuilt binary package (no xbps-src needed)
./packaging/void/build-xbps.sh # -> build/void/repo/voiced-<version>_1.<arch>.xbps
echo "repository=$(pwd)/build/void/repo" | sudo tee /etc/xbps.d/99-voiced-local.conf
sudo xbps-install -Sy voiced
Launch Voiced from the application menu, or run voiced. Remove it with
sudo xbps-remove voiced.
The package installs /usr/bin/voiced, a desktop entry and hicolor icons, and depends on
libwebkit2gtk41.
Fonts on Void. The package also installs the bundled TTF fonts under
/usr/share/fonts/voiced/<family>/ and each family's OFL licence under
/usr/share/licenses/voiced/. The voiced/ subdirectory avoids file conflicts with Void's own
font-ibm-plex-ttf and noto-fonts-ttf. The INSTALL and REMOVE scripts in packaging/void/
run fc-cache -f /usr/share/fonts/voiced after install and removal. xbps-create packs them from
the destdir root (checked with xbps 0.60.7).
Building through xbps-src
Copy packaging/void/template into a void-packages checkout and build it the standard way:
mkdir -p void-packages/srcpkgs/voiced
cp packaging/void/template packaging/void/INSTALL packaging/void/REMOVE void-packages/srcpkgs/voiced/
cd void-packages && ./xbps-src pkg voiced
See the comments at the top of the template about the private source archive and checksums.
Where data lives
| What | Location |
|---|---|
| Database | <app-data>/voiced.db — on Windows %APPDATA%\com.bongbetic.voiced\ |
| Logos & signatures | <app-data>/assets/ |
Project layout
src/ React + Carbon frontend
views/ Onboarding · NewInvoice · InvoiceHistory · SeriesSettings · AppSettings
components/ AppShell · InvoicePreview · ImagePicker
pdf/ InvoiceDocument (react-pdf template)
lib/ api · types · invoice · numberToWords · validators · format · pdf
src-tauri/ Rust backend (Tauri commands, SQLite schema, asset store)
public/brand/ Bongbetic + vendor brand assets
public/fonts/ IBM Plex (woff/woff2)
packaging/void/ Void Linux packaging (xbps-src template + build script + desktop entry)
Ownership
© Bongbetic. All rights reserved. This is a private application.