Tiling multi-terminal manager for WSL
Find a file
megaproxy e3e23b55ba Pick up Cargo.lock version bump from pnpm tauri build
cargo auto-rewrote the tiletopia entry from 0.0.1 to 0.1.0 during
the M5 release build; manually updating Cargo.toml in M5 didn't
touch the lockfile. Committing so the release tag points at a
clean tree.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 13:46:27 +01:00
scripts M5 ship infrastructure: icon, version, release script, README 2026-05-22 13:38:29 +01:00
src Add vitest + 43 unit tests for tree.ts 2026-05-22 13:28:02 +01:00
src-tauri Pick up Cargo.lock version bump from pnpm tauri build 2026-05-22 13:46:27 +01:00
.gitignore Add src-tauri/gen/ to gitignore 2026-05-22 12:32:35 +01:00
CLAUDE.md Initial scaffold from M1 spike (tiletopia) 2026-05-22 12:31:29 +01:00
index.html Initial scaffold from M1 spike (tiletopia) 2026-05-22 12:31:29 +01:00
memory.md M5 ship infrastructure: icon, version, release script, README 2026-05-22 13:38:29 +01:00
package.json M5 ship infrastructure: icon, version, release script, README 2026-05-22 13:38:29 +01:00
pnpm-lock.yaml Add vitest + 43 unit tests for tree.ts 2026-05-22 13:28:02 +01:00
pnpm-workspace.yaml Initial scaffold from M1 spike (tiletopia) 2026-05-22 12:31:29 +01:00
README.md M5 ship infrastructure: icon, version, release script, README 2026-05-22 13:38:29 +01:00
svelte.config.js Initial scaffold from M1 spike (tiletopia) 2026-05-22 12:31:29 +01:00
tsconfig.json Initial scaffold from M1 spike (tiletopia) 2026-05-22 12:31:29 +01:00
tsconfig.node.json Initial scaffold from M1 spike (tiletopia) 2026-05-22 12:31:29 +01:00
vite.config.ts Add vitest + 43 unit tests for tree.ts 2026-05-22 13:28:02 +01:00

tiletopia

A Windows desktop app for running and arranging many WSL terminals at once. Built primarily for managing multiple claude sessions across projects in parallel; works for any multi-shell workflow.

  • Tiling layout — recursive splits, draggable dividers, preset layouts (single / 2-col / 3-col / 2-row / 2×2)
  • Per-pane distro + cwd + label, persisted across restarts
  • Broadcast input to a group of panes
  • Idle detection toasts when a pane goes quiet
  • Ctrl+K palette to fuzzy-jump between panes

Install

  1. Download the latest tiletopia_<version>_x64-setup.exe from the releases page.
  2. Run it. Windows SmartScreen will warn "unrecognized publisher" — it's not code-signed. More info → Run anyway.
  3. Launch tiletopia from the Start menu. A window opens with one terminal pane bound to your default WSL distro.

Requirements

  • Windows 10/11 with WebView2 Runtime (preinstalled on Windows 11; downloadable on Windows 10).
  • At least one WSL distro registered (wsl -l -v lists them).

Using it

  • Split panes in the pane toolbar splits right, splits down. New pane inherits the parent's distro + cwd.
  • Close pane×. The sibling expands to fill.
  • Rename pane — click the label in the toolbar, type, Enter.
  • Change distro — click the small Ubuntu ▾ chip; pick a distro from the popover. The pane respawns (old shell is killed).
  • Broadcast — toggle 📡 on two or more panes (orange border). Typing in any of them mirrors to all.
  • Preset layouts — titlebar buttons: 1 / 2H / 3H / 2V / 2×2.
  • Active pane — click any pane → blue border + keyboard focus.
  • Jump to paneCtrl+K opens a fuzzy picker over label / distro / cwd. ↑/↓ to navigate, Enter to focus, Esc to close.
  • Idle toasts — top-right notification appears when a pane goes quiet for 5s. Useful for "I started a long task; tell me when it's done."

Layout + per-pane settings auto-save to %APPDATA%\com.megaproxy.tiletopia\workspace.json (debounced 500 ms).

Develop

Develop the Rust + frontend code in WSL; build and run on the Windows host (Tauri targets Windows, Rust toolchain is Windows-side).

Source location matters. The project must live on a Windows-native drive (D:\dev\tiletopia\). Don't run pnpm against the \\wsl.localhost\... UNC path — pnpm 11.x crashes inside isDriveExFat (the actual error gets swallowed by the crashing error-hint formatter). The WSL-side symlink at ~/claude/projects/tiletopia is for editing, not building.

Prereqs (Windows host)

  • Windows 10/11 + WebView2 Runtime
  • MSVC toolchain (VS Build Tools, "C++ build tools" workload)
  • Rust on the Windows host
  • Node 20+ and pnpm (corepack use pnpm@11.2.2)

Build + iterate

cd D:\dev\tiletopia
pnpm install
pnpm tauri dev          # iterate — auto-reloads frontend on save, recompiles Rust on src-tauri changes
pnpm tauri build        # NSIS installer at src-tauri\target\release\bundle\nsis\

Test (WSL)

pnpm test          # vitest, ~43 cases on the layout tree
pnpm test:watch    # rerun on file change
pnpm check         # svelte-check

The test suite covers the pure tree helpers in src/lib/layout/tree.ts. UI behavior, broadcast routing, and Tauri integration are still manually tested.

Release

  1. Bump version in package.json, src-tauri/Cargo.toml, src-tauri/tauri.conf.json. Commit + push.
  2. On Windows: pnpm tauri build (produces src-tauri\target\release\bundle\nsis\tiletopia_<ver>_x64-setup.exe).
  3. From WSL: scripts/release.sh v0.1.0 — sanity-checks, tags v0.1.0, pushes the tag, and uploads the installer to Forgejo as a release via tea.

Regenerate the icon

python3 scripts/make-icon.py
pnpm tauri icon src-tauri/icons/source.png
# Tauri's icon command writes iOS + Android + UWP outputs too; rm them.
rm -rf src-tauri/icons/{ios,android,Square*.png,StoreLogo.png,64x64.png,icon.png}

See src-tauri/icons/README.md for details.

Architecture (quick tour)

  • Backendsrc-tauri/src/pty.rs: PtyManager holding Mutex<HashMap<PaneId, PaneHandle>> of portable-pty children. Each spawned pane gets a background reader thread that emits pane://{id}/data events to the frontend (base64 chunks). Counterparts: write_to_pane / resize_pane / kill_pane. Workspace persistence via save_workspace / load_workspace writing to app.path().app_config_dir() with atomic tmp+rename.
  • Layoutsrc/lib/layout/tree.ts: binary tree of splits. HSplit | VSplit internal nodes with a ratio, Leaf at the bottom. Same model as i3 / tmux / Zellij — adaptive resize falls out of mutating one parent ratio. Pure helpers (splitLeaf, closeLeaf, changeDistro, etc.) live in tree.ts; the rendering chain (Pane.svelteSplitNode.svelte / LeafPane.svelte) is thin.
  • Orchestration — broadcast routing, idle detection, palette, active-pane focus all live in App.svelte and are bundled into a PaneOps interface (src/lib/layout/ops.ts) drilled through the Pane chain.
  • Stack precedent — mirrors ~/claude/projects/claude-usage-widget/: same Tauri 2 + Svelte 5 + Vite + pnpm + NSIS Forgejo-release toolchain.

License

Personal project; no formal license yet.