Perfect layouts.
First try.
Finestry arranges your windows into exact layouts with the same gap everywhere, remembers where each one goes, and saves them as scenes you bring back with one shortcut.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// One solver for every path
struct Board {
let gap: CGFloat = 12
var frames: [CGRect]
}
func solveLayout(_ windows: [Window],
in screen: CGRect) -> Board {
let sizes = probe(windows)
let board = reconcile(sizes, screen)
return board.snappedToGrid()
}
// Quantized apps snap to anchor + n × step
func gridSnapDown(_ v: CGFloat,
anchor: CGFloat, step: CGFloat) -> CGFloat {
anchor + ((v - anchor) / step).rounded(.down) * step
}
Compiling Finestry TilingEngine.swift
Build complete! (2.31s)
~/finestry ❯ swift test
Executed 150 tests, with 0 failures
~/finestry ❯ ▍
Beta checklist
Every pixel put to work. Your windows move like pieces on a magnetic board.
Everything in its place.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// One solver for every path
struct Board {
let gap: CGFloat = 12
var frames: [CGRect]
}
func solveLayout(_ windows: [Window],
in screen: CGRect) -> Board {
let sizes = probe(windows)
let board = reconcile(sizes, screen)
return board.snappedToGrid()
}
// Quantized apps snap to anchor + n × step
func gridSnapDown(_ v: CGFloat,
anchor: CGFloat, step: CGFloat) -> CGFloat {
anchor + ((v - anchor) / step).rounded(.down) * step
}
Compiling Finestry TilingEngine.swift
Build complete! (2.31s)
~/finestry ❯ swift test
Executed 150 tests, with 0 failures
~/finestry ❯ ▍
Beta checklist
Auto-tiling
Open a second window and Finestry splits the screen between the two, with no shortcut and no menu. Close one and the other takes the whole screen back.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// One solver for every path
struct Board {
let gap: CGFloat = 12
var frames: [CGRect]
}
func solveLayout(_ windows: [Window],
in screen: CGRect) -> Board {
let sizes = probe(windows)
let board = reconcile(sizes, screen)
return board.snappedToGrid()
}
// Quantized apps snap to anchor + n × step
func gridSnapDown(_ v: CGFloat,
anchor: CGFloat, step: CGFloat) -> CGFloat {
anchor + ((v - anchor) / step).rounded(.down) * step
}
Compiling Finestry TilingEngine.swift
Build complete! (2.31s)
~/finestry ❯ swift test
Executed 150 tests, with 0 failures
~/finestry ❯ ▍
Beta checklist
Drag to reorder
Open the HUD and drag any window card, the master included, to a new slot. Every window moves to its new place in one go.
⌥A2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// One solver for every path
struct Board {
let gap: CGFloat = 12
var frames: [CGRect]
}
func solveLayout(_ windows: [Window],
in screen: CGRect) -> Board {
let sizes = probe(windows)
let board = reconcile(sizes, screen)
return board.snappedToGrid()
}
// Quantized apps snap to anchor + n × step
func gridSnapDown(_ v: CGFloat,
anchor: CGFloat, step: CGFloat) -> CGFloat {
anchor + ((v - anchor) / step).rounded(.down) * step
}
Compiling Finestry TilingEngine.swift
Build complete! (2.31s)
~/finestry ❯ swift test
Executed 150 tests, with 0 failures
~/finestry ❯ ▍
Beta checklist
Magnetic resize
Drag the edge between two windows. When you let go, the neighbours adjust to fill the space and keep the gap exact, never below each app's minimum.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// One solver for every path
struct Board {
let gap: CGFloat = 12
var frames: [CGRect]
}
func solveLayout(_ windows: [Window],
in screen: CGRect) -> Board {
let sizes = probe(windows)
let board = reconcile(sizes, screen)
return board.snappedToGrid()
}
// Quantized apps snap to anchor + n × step
func gridSnapDown(_ v: CGFloat,
anchor: CGFloat, step: CGFloat) -> CGFloat {
anchor + ((v - anchor) / step).rounded(.down) * step
}
Compiling Finestry TilingEngine.swift
Build complete! (2.31s)
~/finestry ❯ swift test
Executed 150 tests, with 0 failures
~/finestry ❯ ▍
Beta checklist
It remembers where everything goes
Minimize a window and the rest fill the space. Bring it back and it returns to the exact slot it left. Finestry remembers your arrangements, even after a restart.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// One solver for every path
struct Board {
let gap: CGFloat = 12
var frames: [CGRect]
}
func solveLayout(_ windows: [Window],
in screen: CGRect) -> Board {
let sizes = probe(windows)
let board = reconcile(sizes, screen)
return board.snappedToGrid()
}
// Quantized apps snap to anchor + n × step
func gridSnapDown(_ v: CGFloat,
anchor: CGFloat, step: CGFloat) -> CGFloat {
anchor + ((v - anchor) / step).rounded(.down) * step
}
Compiling Finestry TilingEngine.swift
Build complete! (2.31s)
~/finestry ❯ swift test
Executed 150 tests, with 0 failures
~/finestry ❯ ▍
Beta checklist
Scenes
Save a layout as a named scene, like Development or Meetings. Finestry marks it when something changes and restores it from the menu bar or a shortcut.
⌥S2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// One solver for every path
struct Board {
let gap: CGFloat = 12
var frames: [CGRect]
}
func solveLayout(_ windows: [Window],
in screen: CGRect) -> Board {
let sizes = probe(windows)
let board = reconcile(sizes, screen)
return board.snappedToGrid()
}
// Quantized apps snap to anchor + n × step
func gridSnapDown(_ v: CGFloat,
anchor: CGFloat, step: CGFloat) -> CGFloat {
anchor + ((v - anchor) / step).rounded(.down) * step
}
Compiling Finestry TilingEngine.swift
Build complete! (2.31s)
~/finestry ❯ swift test
Executed 150 tests, with 0 failures
~/finestry ❯ ▍
Beta checklist
Every display at once
A scene remembers each monitor. Restore it and every display falls into place together, on the right desktop.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// One solver for every path
struct Board {
let gap: CGFloat = 12
var frames: [CGRect]
}
func solveLayout(_ windows: [Window],
in screen: CGRect) -> Board {
let sizes = probe(windows)
let board = reconcile(sizes, screen)
return board.snappedToGrid()
}
// Quantized apps snap to anchor + n × step
func gridSnapDown(_ v: CGFloat,
anchor: CGFloat, step: CGFloat) -> CGFloat {
anchor + ((v - anchor) / step).rounded(.down) * step
}
Compiling Finestry TilingEngine.swift
Build complete! (2.31s)
~/finestry ❯ swift test
Executed 150 tests, with 0 failures
~/finestry ❯ ▍
Beta checklist
Set a window aside
Float one window out of the layout with a shortcut and the rest close the gap. Press it again and the window returns to its original slot.
⌥⇧W- Your own shortcutsSet shortcuts for every action, and for jumping straight to a saved scene.
- Desktops and monitorsWorks across different macOS desktops and across different monitors.
- Unlimited scenesCreate as many scenes as you want.
- Auto-saveOptionally save every move you make, so you never have to save by hand.
Other tools guess the size. Apps refuse it.
Terminal snaps to its character grid. Some apps won't shrink below a minimum. Ask for a size an app won't take and you get crooked gaps and overlapping edges.
Finestry measures each app first: its real minimum and the steps it resizes in. Then it plans the whole layout around those numbers, so the first result is already right.
Measure once. Place once.
Probe
One quick probe per window finds the sizes each app really accepts. The result is cached per app and version.
Reconcile
Plain arithmetic on the real sizes: snap to each app's grid, fill the screen and keep every gap identical.
Apply
A final check covers minimums, screen edges, overlaps and gaps. Then only the windows that change are moved, once.
Hi, I'm Vicent.
I build Finestry on my own, from Spain, in my spare time. I wanted my windows to line up perfectly every time, so I started making the tool myself.
There is no company and no support team. I read and answer every message myself, so a reply can take a few days.
A note on English: my first language is Spanish and I often use a translator. If something I write sounds a bit odd, that's why. Messages in Spanish are always welcome.
Contact email coming with the beta.
Pay once. Keep it.
- Layouts for up to 4 windows
- HUD with drag to reorder
- Arrange windows with ⌥A
- Magnetic resize
- One display
- Everything in Free
- Named scenes
- Scenes across multiple displays
- Set a window aside
- Configurable shortcuts
- Auto-save scenes
Plans and prices may change before launch.
Questions, answered.
Which Macs does it run on?
Any Mac running macOS 14 Sonoma or later.
Why does it ask for Accessibility access?
macOS only lets an app move and resize other apps' windows through the Accessibility permission. Finestry needs it to place your windows.
What do crash reports include?
Reports are only sent with your consent. Logs never include window titles, and you can also send a report yourself from the menu.
Is it a subscription?
No. Finestry is a one-time purchase, and it is free while in beta.
Who answers my messages?
I do. Finestry is a one-person project, so please be patient if a reply takes a few days.
Your windows, in order.
Try the beta and tell me what breaks. Every feature is unlocked while I test it.