Skip to content

fosterdill/ansel

Ansel

OpenSSF Scorecard Tests Release License: MIT

A disk usage visualizer for macOS (and friends), built with Tauri + React. Think Disk Inventory X, but with an explicit "I'm here to free up space" workflow built in.

Scans a volume, renders the contents as a squarified treemap, sunburst diagram, or flat table — colored by file type (or by modification age or last-access time, as a heatmap) — and lets you mark suspect files into a cleanup queue that can be moved to Trash or deleted forever.

Visit the project landing page at fosterdill.github.io/ansel-web.

Ansel scanning the system volume — explorer on the left, squarified treemap in the middle, inspector on the right

Features

  • Treemap, sunburst, and table views — squarified treemap, Daisy Disk-style sunburst, and flat sortable table. Canvas-rendered at native DPR with spatial-grid hit-testing.
  • Four color modes — by file type (14 categories), by modification age (cool→warm heatmap), by last-access time, or by folder (treemap-only).
  • Cleanup queue — mark files for review, then move to Trash or delete permanently with a two-step confirmation.
  • Multi-select⌘-click across all views; shared state with the inspector panel.
  • Search — case-insensitive search over the entire scan tree, results sorted by size with keyboard navigation.
  • Cross-platform — macOS, Linux, and Windows. Platform-appropriate file manager reveal, keyboard shortcuts, and Trash/recycle-bin integration.
  • On-disk size — files sized by allocated blocks (stat.blocks × 512 on Unix), so sparse files show their real footprint.

Keyboard / mouse cheatsheet

Action Result
Click Select (replaces current selection)
⌘-click (Ctrl-click) Toggle in multi-selection
⌥-click (Alt-click) Toggle in cleanup queue
Double-click on a folder Zoom in
Right-click on a folder segment (sunburst) Zoom into that directory
Click center circle (sunburst) Zoom out to parent directory
Shift+click on a folder rect Zoom into that folder (treemap)
Right-click on a folder rect Zoom into that folder (treemap)
Shift+⌘-click (Shift+Ctrl-click) Select all items in the folder group
Shift+⌥-click (Shift+Alt-click) Mark all items in the folder group
Hold Shift Highlight the current folder group under the cursor (treemap dimming)
Click a breadcrumb Zoom back out to any ancestor
Cmd+↑ (Ctrl+↑) Zoom out to parent directory
Shift+↑/↓ Adjust folder grouping depth
Drag-to-select (treemap) Marquee-select multiple rects
Drag sidebar gutter Resize the file tree sidebar
Esc Clear selection / close modal

Caveats

Space accounting

The toolbar shows three numbers:

  • Total — the volume's capacity, as reported by the filesystem (statvfs on Unix, GetDiskFreeSpaceExW on Windows). Definitive.
  • Scanned — the sum of on-disk allocation (st_blocks × 512 on Unix, GetCompressedFileSizeW on Windows) for every file the scanner reached. Also definitive, but a different measurement.
  • Free — derived as total − scanned. Represents everything the scanner didn't attribute to individual files: filesystem metadata, allocation slack between file boundaries, APFS snapshots, directories skipped due to permissions (see TCC below), and sparse-file holes.

These three will not match Finder's Used/Free numbers, for good reason:

  • Ansel's "scanned" will be higher than Finder's "Used" because on-disk allocation counts partial blocks per file, while Finder reports logical usage.
  • Ansel's derived "free" will be lower than Finder's "Available" because Finder includes purgeable space (Time Machine local snapshots, caches) that statvfs does not count as free.
  • On macOS, the totals will differ by ~7% from Finder's decimal GB display because Finder uses base-10 while Ansel uses base-2 on non-macOS platforms. On macOS itself, Ansel matches Finder's base-10 convention.

Every disk scanner faces the same reconciliation problem. The scanned file count and per-file sizes are the authoritative numbers; the bar exists to show you roughly where the volume stands.

macOS Gatekeeper

Apple has become increasingly aggressive with unsigned apps. Right-click → Open no longer suffices for recent macOS versions. To launch Ansel for the first time:

  1. Download and attempt to open the .app (Gatekeeper will block it).
  2. Open System Settings → Privacy & Security.
  3. Scroll to the bottom — you'll see a message that Ansel was blocked. Click Open Anyway.
  4. Confirm the second dialog that appears.

Subsequent launches work normally.

macOS Full Disk Access

Parts of ~/Library, /private/var, and other user homes are hidden behind TCC. Without Full Disk Access granted to whatever launched the app (or to the built binary), those subtrees come back as 0 bytes. The scan succeeds — it just under-counts.

APFS clones

Cloned files (copy-on-write duplicates) share blocks on disk, but each clone is counted with its own block tally by stat(2). This can inflate the scanned total when many clones exist.

Development

Requires Rust (stable), Node 20+, pnpm.

pnpm install
pnpm tauri dev

The first pnpm tauri dev cold-compiles the Rust backend (~30–60s on Apple Silicon); subsequent runs hot-reload the frontend in milliseconds and incrementally rebuild Rust changes.

Project layout

src/                     React frontend
  App.tsx                Layout shell — toolbar, three-column layout, side effects (Tauri events, keyboard shortcuts, transitions, sidebar resize)
  components/
    WelcomeScreen.tsx    Volume picker, scanning animation, error/retry
    Treemap.tsx          Canvas-rendered squarified treemap, DPR-aware, grid hittest, dimming
    Sunburst.tsx         Canvas-rendered concentric-ring sunburst, polar hittest, zoom-in/out
    SearchBar.tsx        Search over in-memory scan tree, results sorted by size with keyboard navigation
    TreeView.tsx         Lazy-loaded file tree sidebar
    LargestFiles.tsx     Flat sortable table of biggest files
    InfoPanel.tsx        Inspector (single + multi-select views)
    Breadcrumbs.tsx      Clickable path breadcrumbs
    CleanupQueue.tsx     Marked-items review modal with batch actions
    DeleteConfirm.tsx    Two-step permanent deletion confirmation
  lib/
    store.ts             Zustand store — all application state and actions (scan, navigation, selection, UI, cleanup)
    api.ts               Typed Tauri IPC wrappers, shared types
    treemap.ts           Squarified layout algorithm (Bruls-Huizing-van Wijk)
    color.ts             FNV-1a hash, HSL jitter, age heatmap, folder coloring
    fileTypes.ts         14 file categories, ~120 extension mappings
    format.ts            Platform-aware byte formatting (decimal on macOS, binary elsewhere)
src-tauri/
  src/lib.rs             Tauri commands, AppState, volume discovery, subtree builder
  src/scanner.rs         Parallel rayon scanner, tree mutation, top-files, extension breakdown
  src/main.rs            Entry point
  tauri.conf.json        Bundle identifier, window config
  Cargo.toml             Rust dependencies (tauri, rayon, serde, trash, windows-sys)
  capabilities/         Tauri v2 permissions (core + opener)

Building a release locally

pnpm tauri build

Artifacts land under src-tauri/target/release/bundle/ (.dmg on macOS, .AppImage/.deb on Linux, .msi on Windows).

Contributing

See CONTRIBUTING.md for setup instructions and workflow details. main is protected — all changes land via feature branch → pull request → squash merge.

License

MIT

Security

Report vulnerabilities by opening a GitHub issue or emailing fosterdill@gmail.com. See SECURITY.md for the full policy.

About

Disk Inventory X-style file system visualizer built with Tauri + React. Treemap, age heatmap, largest-files view, trash-or-delete cleanup workflow.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors