Skip to content

Complete examples

These examples demonstrate how to combine Shoji’s building blocks for practical workflows.

Developer setup

A complete configuration for software development with multiple layout options.

-- ~/.hammerspoon/init.lua
hs.loadSpoon("Shoji")
local shoji = spoon.Shoji
-- Access building blocks
local Modifiers = shoji.Modifiers
local Partition = shoji.Combinators.Partition
local Tall = shoji.Layouts.Tall
local Wide = shoji.Layouts.Wide
local Grid = shoji.Layouts.Grid
local BSP = shoji.Layouts.BSP
local Column = shoji.Layouts.Column
local Monocle = shoji.Layouts.Monocle
------------------------------------------------------------------------
-- Modified layouts
------------------------------------------------------------------------
-- Mirrored tall: main area on right instead of left
local TallRight = Modifiers.wrap(
Tall,
Modifiers.Mirror.horizontal(),
{ name = "tall-right", displayName = "Tall (Right)" }
)
-- Centered tall: 80% of screen, centered
local CenteredTall = Modifiers.wrap(
Tall,
Modifiers.Centered.ratio(0.8),
{ name = "tall-centered", displayName = "Tall (Centered)" }
)
------------------------------------------------------------------------
-- Partitioned layouts
------------------------------------------------------------------------
-- Developer: main editor (65%), reference stack (35%)
local Developer = Partition.horizontal({
{ ratio = 0.65, layout = Tall, count = 1 },
{ ratio = 0.35, layout = Column },
}, {
name = "developer",
displayName = "Developer",
})
-- IDE: editor (60%), grid + terminal (40%)
local IDE = Partition.horizontal({
{ ratio = 0.6, layout = Tall, count = 2 },
{ ratio = 0.4, layout = Partition.vertical({
{ ratio = 0.5, layout = Grid, count = 2 },
{ ratio = 0.5, layout = Monocle },
})},
}, {
name = "ide",
displayName = "IDE Layout",
})
-- Presentation: main content (85%), notes strip (15%)
local Presentation = Partition.vertical({
{ ratio = 0.85, layout = Monocle, count = 1 },
{ ratio = 0.15, layout = Column },
}, {
name = "presentation",
displayName = "Presentation",
})
------------------------------------------------------------------------
-- Configuration
------------------------------------------------------------------------
shoji:configure({
layouts = {
TallRight,
CenteredTall,
Developer,
IDE,
Presentation,
},
enabled_layouts = {
"tall",
"tall-right",
"developer",
"ide",
"monocle",
},
gap_outer = 8,
gap_inner = 8,
})
shoji:start()
shoji:bindHotkeys({
-- Layout cycling
cycle_layout_forward = { { "cmd", "ctrl", "alt" }, "space" },
-- Window focus
focus_next = { { "ctrl", "alt" }, "'" },
focus_prev = { { "ctrl", "alt" }, ";" },
-- Window swapping
swap_main = { { "cmd", "ctrl", "alt" }, "return" },
-- Layout adjustments
increase_main_ratio = { { "ctrl", "alt" }, "." },
decrease_main_ratio = { { "ctrl", "alt" }, "," },
-- Float toggle
toggle_float = { { "ctrl", "alt", "shift" }, "t" },
})

Keybindings summary

KeysAction
cmd+ctrl+alt+spaceCycle layouts
ctrl+alt+'Focus next window
ctrl+alt+;Focus previous window
cmd+ctrl+alt+returnSwap with main
ctrl+alt+.Expand main area
ctrl+alt+,Shrink main area
ctrl+alt+shift+tToggle floating

Ultrawide monitor setup

Extra gaps and centered layouts work well on ultrawide displays.

hs.loadSpoon("Shoji")
local shoji = spoon.Shoji
local Modifiers = shoji.Modifiers
local Tall = shoji.Layouts.Tall
local BSP = shoji.Layouts.BSP
-- Centered at 85% with extra gaps
local CenteredTall = Modifiers.chain(Tall, {
Modifiers.Centered.ratio(0.85),
Modifiers.Gaps.create({ outer = 20, inner = 12 }),
}, {
name = "centered-tall",
displayName = "Centered Tall",
})
-- BSP with breathing room
local SpacedBSP = Modifiers.chain(BSP, {
Modifiers.Gaps.create({ outer = 24, inner = 8 }),
}, {
name = "spaced-bsp",
displayName = "Spaced BSP",
preserveActions = true, -- Keep BSP resize actions
})
shoji:configure({
layouts = { CenteredTall, SpacedBSP },
enabled_layouts = { "centered-tall", "spaced-bsp" },
gap_outer = 16,
gap_inner = 8,
})
shoji:start()

Minimal configuration

A simple setup with just the essentials.

hs.loadSpoon("Shoji")
local shoji = spoon.Shoji
local Modifiers = shoji.Modifiers
local Tall = shoji.Layouts.Tall
-- Tall with main area on right
local TallRight = Modifiers.wrap(
Tall,
Modifiers.Mirror.horizontal(),
{ name = "tall-right", displayName = "Tall (Right)" }
)
shoji:configure({
layouts = { TallRight },
enabled_layouts = { "tall", "tall-right", "monocle" },
gap_outer = 8,
gap_inner = 8,
})
shoji:start()
shoji:bindHotkeys({
cycle_layout_forward = { { "cmd", "ctrl", "alt" }, "space" },
swap_main = { { "cmd", "ctrl", "alt" }, "return" },
toggle_float = { { "ctrl", "alt", "shift" }, "t" },
})

Building blocks reference

Modifiers

ModifierPurpose
Mirror.horizontal()Flip left/right
Mirror.vertical()Flip top/bottom
Gaps.create()Extra spacing (uniform or per-edge)
Centered.ratio()Scale and center

Combinators

CombinatorPurpose
Partition.horizontal()Split screen left-to-right
Partition.vertical()Split screen top-to-bottom

Functions

FunctionPurpose
Modifiers.wrap()Apply one modifier
Modifiers.chain()Apply multiple modifiers