Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,27 @@ jobs:

- name: Test
run: swift test

# Prose gate: Vale lints the docs against the Microsoft style guide. A style
# violation fails the build, so it never reaches a reviewer. Runs on Linux
# (no Xcode needed) so it starts fast and in parallel with the build matrix.
prose-lint:
name: Docs prose (Vale)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install Vale
run: |
VALE_VERSION=3.15.1
curl -sfL "https://github.com/errata-ai/vale/releases/download/v${VALE_VERSION}/vale_${VALE_VERSION}_Linux_64-bit.tar.gz" -o vale.tar.gz
tar -xzf vale.tar.gz vale
sudo install vale /usr/local/bin/vale
rm -f vale vale.tar.gz

# Downloads the Microsoft style package declared in .vale.ini.
- name: Sync Vale styles
run: vale sync

- name: Lint docs prose
run: vale guide docs/adr README.md
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ DerivedData/
# MkDocs build output (built by CI, not committed)
/site/

# Vale prose-lint styles are downloaded by `vale sync` (locally and in CI)
.github/styles/

# Amore / Sparkle private signing keys — NEVER commit these
*.private
sparkle_private_key
Expand Down
19 changes: 19 additions & 0 deletions .vale.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Vale configuration for MacDirStat docs.
# Prose is linted with the Microsoft Writing Style Guide, the same voice the
# guide and ADR were already written in (active voice, present tense, "you").
StylesPath = .github/styles

# CI fails on errors (clear-cut style violations). Warnings and suggestions
# still print locally for review but don't block the build.
MinAlertLevel = error

# Vale downloads the Microsoft package into StylesPath (see the CI workflow and
# the `vale sync` step in the docs).
Packages = Microsoft

[*.md]
BasedOnStyles = Vale, Microsoft

# Reference pages quote real API symbols (ByteFormatter, TreemapLayout) and code
# identifiers; don't flag those as spelling errors.
Vale.Spelling = NO
38 changes: 19 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<h1>MacDirStat</h1>

<p><strong>See where your disk space went.</strong><br/>
A fast, beautiful macOS disk usage visualizer built entirely in Swift.</p>
A fast, beautiful macOS disk usage visualizer, built entirely in Swift.</p>

[![CI](https://github.com/Ti-03/MacDirStat/actions/workflows/ci.yml/badge.svg)](https://github.com/Ti-03/MacDirStat/actions/workflows/ci.yml)
[![App Store](https://img.shields.io/badge/Mac_App_Store-Download-0D96F6?style=flat-square&logo=apple)](https://apps.apple.com/app/dirstat/id6766033292?mt=12)
Expand All @@ -23,21 +23,21 @@ A fast, beautiful macOS disk usage visualizer — built entirely in Swift.</p>

## What it does

MacDirStat scans any folder and turns your filesystem into an interactive sunburst chart every ring is a depth level, every arc is a file or folder, sized by disk usage. Hover to inspect. Click to drill in. Right-click to delete.
MacDirStat scans any folder and turns your filesystem into an interactive sunburst chart: every ring is a depth level, every arc is a file or folder, sized by disk usage. Hover to inspect. Click to drill in. Right-click to delete.

## Features

- **Sunburst visualization** depth rings, color-coded by file type (video, code, images, archives…)
- **Spotlight hover** everything else fades when you hover; selected files pulse with a glow
- **Force Touch haptics** soft tap for small files, triple thud for multi-GB ones
- **Drill navigation** click any folder to zoom in, click back to go up
- **Duplicate detection** finds identical files by content hash, shows wasted space per group
- **One-click cleanup**keep one copy, trash the rest or delete file by file
- **File list panel** sortable tree view beside the chart, toggle to give the chart full width
- **File type breakdown** top file types with a searchable list of all types
- **Move to Trash** right-click any arc or row to trash it, chart refreshes instantly
- **CSV export** dump the full scan as a spreadsheet
- **Settings** toggle haptic feedback on/off
- **Sunburst visualization**: depth rings, color-coded by file type (video, code, images, archives…)
- **Spotlight hover**: everything else fades when you hover; selected files pulse with a glow
- **Force Touch haptics**: soft tap for small files, triple thud for multi-GB ones
- **Drill navigation**: click any folder to zoom in, click back to go up
- **Duplicate detection**: finds identical files by content hash, shows wasted space per group
- **One-click cleanup**: keep one copy, trash the rest, or delete file by file
- **File list panel**: sortable tree view beside the chart, toggle to give the chart full width
- **File type breakdown**: top file types with a searchable list of all types
- **Move to Trash**: right-click any arc or row to trash it, chart refreshes instantly
- **CSV export**: dump the full scan as a spreadsheet
- **Settings**: toggle haptic feedback on/off

## Screenshots

Expand All @@ -47,9 +47,9 @@ MacDirStat scans any folder and turns your filesystem into an interactive sunbur

## Install

**[Download on the Mac App Store](https://apps.apple.com/app/dirstat/id6766033292?mt=12)** published as **DirStat**.
**[Download on the Mac App Store](https://apps.apple.com/app/dirstat/id6766033292?mt=12)**, published as **DirStat**.

Or grab the DMG directly from **[Releases](https://github.com/Ti-03/MacDirStat/releases)** — open it and drag the app to your Applications folder. It updates itself automatically via the Help menu once installed.
Or grab the DMG directly from **[Releases](https://github.com/Ti-03/MacDirStat/releases)**. Open it and drag the app to your Applications folder. It updates itself automatically via the Help menu once installed.

**Build from source**

Expand All @@ -63,14 +63,14 @@ Requires macOS 14+ and Xcode 15+.

## Tech

Pure Swift + SwiftUI no Electron, no web views, no dependencies.
Pure Swift + SwiftUI: no Electron, no web views, no dependencies.

| Layer | What |
|---|---|
| Scanner | POSIX `opendir`/`fstatat` with async task groups parallel, cancellable |
| Scanner | POSIX `opendir`/`fstatat` with async task groups: parallel, cancellable |
| Layout | Custom sunburst partition algorithm (band-width from view size) |
| Renderer | SwiftUI `Canvas` draws 1,000+ arcs at 30 fps |
| Haptics | `NSHapticFeedbackManager` intensity scales with file size |
| Renderer | SwiftUI `Canvas`: draws 1,000+ arcs at 30 fps |
| Haptics | `NSHapticFeedbackManager`: intensity scales with file size |
| Duplicates | SHA-256 content hashing on a background actor |

## Documentation
Expand Down
8 changes: 4 additions & 4 deletions docs/adr/0001-compile-time-guard-for-liquid-glass.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ alone type-checked. The runtime `#available` check stays inside the
compile-time branch, so a build made with Xcode 26 still back-deploys
correctly to macOS 14/15 at runtime.

We also dropped `macos-14` from the CI matrix: its SDK predates both
`glassEffect` and the `ContentUnavailableView` backport check, so it cannot
I also dropped `macos-14` from the CI matrix: its SDK predates both
`glassEffect` and the `ContentUnavailableView` backport check, so it can't
build this project at all regardless of guards, and keeping it would only
produce a permanently red, unfixable job.

Expand All @@ -72,9 +72,9 @@ produce a permanently red, unfixable job.
`#available` alone. A future contributor who copies an existing
`#available`-only pattern from elsewhere in SwiftUI code will reintroduce
this bug; there is no compiler warning for it.
- The CI matrix (`macos-15`, `macos-26`) is now load-bearing: it is the
- The CI matrix (`macos-15`, `macos-26`) is now load-bearing: it's the
only thing that would have caught this before it shipped, since a
single-SDK local build cannot reproduce the failure.
single-SDK local build can't reproduce the failure.
- Slightly more boilerplate per call site (two nested conditionals instead
of one), in exchange for the app actually compiling on the SDK most
users' Macs currently have.
6 changes: 3 additions & 3 deletions guide/how-to/read-the-treemap.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ extension:
| Pink | Fonts | `ttf`, `otf`, `woff` |
| Lime | 3D / models | `obj`, `fbx`, `gltf` |

An extension MacDirStat does not recognize gets a stable color derived from
An extension MacDirStat doesn't recognize gets a stable color derived from
its name, so the same unknown extension is always the same color across a
scan. Folders are colored separately from files: each folder gets a muted,
scan. Folders and files use different color schemes: each folder gets a muted,
low-saturation tint based on its name, so folders never compete visually
with the files inside them. Files also darken slightly with depth, so you
can tell a top-level file from one buried five folders down at a glance.
Expand All @@ -55,7 +55,7 @@ can tell a top-level file from one buried five folders down at a glance.

## See also

- [Scan your first folder](../tutorial/first-scan.md) if you have not run a
- [Scan your first folder](../tutorial/first-scan.md) if you haven't run a
scan yet.
- [TreemapLayout reference](../reference/treemap-layout.md) for exactly how
angles and colors are computed.
4 changes: 2 additions & 2 deletions guide/index.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# MacDirStat

MacDirStat is a native macOS app that scans a folder and shows what is taking up
MacDirStat is a native macOS app that scans a folder and shows what's taking up
disk space, as an interactive radial treemap.

This guide is for **macOS users who have MacDirStat installed** (or built it
from source) and want to scan a folder, read the resulting chart, or look up
what a specific API does. You do not need any Swift experience to follow the
what a specific API does. You don't need any Swift experience to follow the
tutorial or how-to guide; the reference section assumes you are reading the
Swift source.

Expand Down
6 changes: 3 additions & 3 deletions guide/reference/treemap-layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ let arcAngle = fraction * totalAngle

An arc smaller than `minArcAngle` (about 1 degree) is skipped entirely
rather than drawn as an unreadable sliver. Folders recurse into their own
children at the next radius band; files do not.
children at the next radius band; files don't.

## `TreemapCell`

Expand All @@ -61,9 +61,9 @@ One cell per arc. `startAngle`/`endAngle` are in radians; `innerRadius`/

## Color assignment

Colors are not assigned by `TreemapLayout` directly; it delegates to
Colors aren't assigned by `TreemapLayout` directly; it delegates to
`ExtensionColorMap.color(for:)` for files and computes a muted per-folder
tint by hashing the folder's name for directories. Files also darken by a
fixed amount per depth (from 0% at depth 0 up to 38% at depth 5+), so a
`.mp4` five folders deep is visibly darker than one at the top level, even
though both are "orange".
though both are "orange."
2 changes: 1 addition & 1 deletion guide/tutorial/first-scan.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ proportional to how much disk space it uses.

## Next step

The colors are not random. Continue to
The colors aren't random. Continue to
[How to read the treemap](../how-to/read-the-treemap.md) to learn what each
color means and how to change the color scheme.
Loading