Skip to content
spaxe-devPublic

About

A local-first infinite whiteboard that lives on your Windows desktop.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Underlay icon

Underlay

A local-first infinite whiteboard that lives on your Windows desktop.

Notes, sketches, and diagrams behind your desktop icons — without replacing Explorer or switching to a separate editor.

Status: early preview (0.1.0). The whiteboard, persistence, window modes, and browser fallback are tested. The behind-the-icons desktop canvas is implemented and manually exercised, but remains experimental — see Known limitations. No signed installer or binary release is published yet; build from source.

Underlay embeds the MIT-licensed Excalidraw engine in a Tauri 2 desktop shell, adds local persistence and recovery, and can reparent its own WebView2 window behind the desktop icons. The same engine and the same board are used in every presentation mode; there is no second canvas and no wallpaper screenshot.

Features

  • Infinite canvas with pan/zoom, freehand pen, a highlighter action, shapes, lines, and arrows bound to elements.
  • Sticky notes and direct text editing, selection, move, resize, rotate, group, duplicate, and delete.
  • Undo/redo, clipboard text/image paste, Excalidraw scene import/export, Underlay board import/export, and PNG export.
  • Multiple boards with rename, duplicate, delete-to-trash, and a board library.
  • Local autosave with atomic writes, previous-version backups, rotating snapshots, interrupted-save recovery, and corrupt-file fallback.
  • Dark bluish-black default canvas with light/dark UI themes, five board backgrounds, and five muted sticky palettes.
  • Windows presentation modes: experimental desktop canvas behind icons, a normal window, and a legacy always-on-bottom mode.
  • Desktop integration: tray menu, single instance, opt-in launch at login, global shortcuts, and a --safe-mode fallback.
  • Browser preview over localStorage for frontend development.

Desktop canvas

Choose Canvas under Settings → “When Underlay starts”, or press Ctrl+Alt+W. The Tauri window and its WebView2 child are reparented under the desktop WorkerW, below SHELLDLL_DefView and therefore below the icons.

  • Click notes and empty canvas to select, drag, draw, and type. Desktop icons, the taskbar, Start, and ordinary apps stay usable above the canvas.
  • Right-click empty canvas for the Underlay menu. Alt+right-click opens the real Windows desktop menu. Right-clicking an element shows Excalidraw's element menu.
  • Ctrl+Alt+X pauses canvas input so every click reaches the shell or an app.
  • Ctrl+Alt+B returns to the normal window.
  • If shell icon geometry cannot be read, input passes through in the icon area rather than guessing positions.
  • --safe-mode (or UNDERLAY_SAFE_MODE) disables the desktop canvas.

The desktop canvas currently targets the primary monitor. The legacy always-on-bottom window mode remains available as a fallback.

Requirements

  • Windows 10/11. Development and verification used Windows 11 build 26300; Windows 10 is untested.
  • Microsoft Edge WebView2 Runtime (normally present on Windows).
  • Node.js 22+ and npm.
  • Rust stable with the MSVC toolchain and Visual Studio C++ build tools.
  • Git Bash for scripts/env.sh and the test harnesses.

Quick start

git clone https://github.com/spaxe-dev/underlay.git
cd underlay
source scripts/env.sh   # Git Bash: keeps caches and build output inside the repo
npm ci
npm run desktop:dev     # Vite + the native Tauri window

For a browser-only preview (localStorage instead of disk storage):

source scripts/env.sh
npm run dev

scripts/env.sh is optional. It redirects TEMP, the npm cache, CARGO_HOME, CARGO_TARGET_DIR, the WebView2 profile, and development data to gitignored folders inside the repository. Without it, npm and Cargo use their normal locations.

Keyboard shortcuts

Shortcut Action
Ctrl+S Save now and show confirmation
Ctrl+, Open settings
Ctrl+Alt+B Show/hide the canvas, or return from the desktop canvas (global)
Ctrl+Alt+W Toggle the desktop canvas behind icons (global)
Ctrl+Alt+X Pause/resume canvas input, or toggle legacy click-through (global)
Ctrl+Alt+D Toggle legacy always-on-bottom desktop mode (global)

The highlighter button in the top bar (also in the app menu) selects a wide, translucent yellow freehand stroke.

How it works

flowchart TB
  subgraph Web["React + TypeScript"]
    UI["Underlay UI and board library"]
    Engine["Excalidraw 0.18.1 engine"]
  end
  subgraph Native["Tauri 2 / Rust"]
    Store["Board store: JSON, backups, trash, settings"]
    Surface["Desktop surface host: WorkerW + WebView2"]
    Input["Scoped input bridge and focus proxy"]
  end
  UI --> Engine
  UI --> Store
  UI --> Surface
  Surface --> Input
Loading
  • The frontend owns the single Excalidraw engine and the application shell.
  • The Rust store validates paths and names, writes boards atomically, keeps previous-version backups and snapshots, and falls back to the last good file.
  • The desktop surface saves the window's parent/style/rectangle, reparents the existing Tauri window under WorkerW, routes only desktop-level mouse input, reads icon geometry through the shell, and restores everything on detach.
  • The normal window and legacy always-on-bottom mode bypass the desktop surface entirely.

There is no Explorer injection, no global keyboard hook, and no permanent low-level mouse hook: mouse routing is scoped to the desktop surface and removed when it detaches.

More detail: docs/ARCHITECTURE.md and docs/DESKTOP_SURFACE_POC.md.

Data and privacy

Underlay is local-only. It has no telemetry, accounts, or runtime network services; Excalidraw fonts and locales are served from local files.

Packaged builds resolve the data folder in this order:

  1. UNDERLAY_DATA_DIR, if set.
  2. D:\Underlay, if D: exists. An existing pre-rename D:\Vanvas folder is reused in place.
  3. %LOCALAPPDATA%\Underlay, or an existing %LOCALAPPDATA%\Vanvas.

Development uses <repo>/userdata when scripts/env.sh is sourced. Boards are versioned JSON named <id>.underlay.json under boards/, with backups/, trash/, logs/, exports/, and settings beside them. Deletes go to trash/; nothing is silently erased.

Underlay was previously prototyped as Vanvas. Existing Vanvas boards (.vanvas.json), previous-version backups, browser localStorage keys, and VANVAS_* environment variables are still read, and legacy boards are saved in place.

Build and test

source scripts/env.sh

npm run typecheck
npm run lint
npm test                # 35 Vitest tests
npm run test:rust       # 15 Rust store tests
npm run build           # production frontend
npm run desktop:build   # release executable + unsigned NSIS installer

End-to-end harnesses:

# Browser: requires `npm run dev` in another terminal.
npm run e2e

# Desktop: requires an unlocked interactive Windows session.
npm run desktop:e2e
npm run desktop:surface

The current tree passes typecheck, lint, 35 unit tests, 15 Rust tests, 47 browser checks, and the production frontend build. The desktop harnesses drive the real WebView2 through CDP and verify Win32 window styles; their last complete run predates the Underlay rename. Release smoke and the opt-in Explorer-restart phase are not yet run against the renamed build.

Build outputs live under build/ (gitignored). The NSIS installer is unsigned and has not been installed on a clean machine.

Compatibility

  • Board format: versioned JSON (schemaVersion: 1).
  • Import accepts .underlay, legacy .vanvas, .json, and .excalidraw files.
  • Existing settings, backups, trash, and browser preview data are read across the rename.
  • UNDERLAY_SAFE_MODE and the legacy VANVAS_SAFE_MODE both disable the desktop canvas.

Known limitations

  • Windows only, with the desktop canvas on the primary monitor. Mixed-DPI, monitor removal, sleep/lock, IME, touch, and pen behavior are unverified.
  • Explorer restart and wallpaper conflicts are implemented or documented but not verified live. On builds with no WorkerW host, Underlay sends the undocumented 0x052C message to Progman once per attach; that path has not been exercised by a real Explorer restart.
  • No published binary or signed installer. Build from source; the installer is unsigned and untested on a clean machine.
  • Excalidraw font notices must be collected before distributing built binaries. The fonts are copied from npm at build time and are not stored here.
  • Packaged CSP is still Tauri's default and needs hardening.
  • Rotation, clipboard paste, and image insertion come from Excalidraw but are not individually automated in this repository's tests.
  • No auto-updater.

Contributing

Issues and pull requests are welcome. Keep the app local-first (no telemetry or required network services), run the checks above before opening a PR, and avoid vendoring GPL-licensed code. See THIRD_PARTY_NOTICES.md for dependency obligations.

License

MIT © 2026 Aadit (spaxe-dev)

Underlay builds on MIT/Apache-2.0 dependencies; see THIRD_PARTY_NOTICES.md and docs/DEPENDENCY_AUDIT.md. Excalidraw is MIT-licensed and remains the copyright of its contributors.

About

A local-first infinite whiteboard that lives on your Windows desktop.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages