Skip to content

Overview

You will learn

  • How to build layouts from scratch
  • How to add configurable features to layouts
  • How to use modifiers and combinators for composition

This section teaches you to build custom layouts for Shoji. By the end, you’ll understand how layouts work and have the skills to create your own.

Which tutorial should I start with?

  • “I want to customize my setup” — You probably don’t need a tutorial. Check the Recipes for copy-paste configurations you can adapt.
  • “I want to build my own layout” — Start with Part 1. It walks you through the layout protocol from scratch.
  • “I want to understand composition” — Jump to Part 3 if you already know the basics and want to learn modifiers and combinators.

Prerequisites

Before starting:

  1. Shoji installed and running (Installation)
  2. Basic Lua knowledge (variables, functions, tables)
  3. A text editor for writing Lua files

The tutorials

Part 1: Your first layout

Build a simple column layout from scratch. You’ll learn the layout protocol and how Shoji uses layouts to position windows.

What you’ll build: A layout that arranges windows in equal vertical columns.

Time: Follow along at your own pace.

Start Part 1 →

Part 2: Making it configurable

Extend your layout to respond to user actions. Add capabilities that let users adjust the main ratio and number of main windows.

What you’ll build: A main-stack layout with adjustable regions.

Prerequisites: Complete Part 1.

Start Part 2 →

Part 3: Modifiers and composition

Transform existing layouts without rewriting them. Use modifiers and combinators to create layout variations.

What you’ll build: Custom modifiers and composed layouts.

Prerequisites: Complete Part 2.

Start Part 3 →

Reference material

After completing the tutorials, use these references (also in this section):

  • Layout protocol — Full protocol specification
  • Modifiers — Built-in modifiers and chaining
  • Partition — Divide the screen into regions with different layouts
  • IfMax — Switch between layouts based on window count

Debugging layouts

When a layout doesn’t behave as expected, these techniques help you find the problem.

Check the Hammerspoon console. Open it from the menu bar (Console) or press Cmd+Alt+C. Error messages appear here with file names and line numbers. Common errors include:

  • attempt to index a nil value — a parameter or table field you expected isn’t there. Check your arrange() function’s params table.
  • attempt to perform arithmetic on a nil value — you’re using a missing number (often mainRatio or mainCount before declaring them as capabilities).

Add print() in arrange(). Temporarily print params and computed frames to verify your geometry math:

function MyLayout.arrange(params)
print("workarea:", hs.inspect(params.workarea))
print("window count:", #params.windowIDs)
-- your layout logic ...
end

Use hooks to observe layout execution. The before_tile and after_tile hooks let you inspect what Shoji sends to your layout and what frames result:

spoon.Shoji:on("before_tile", function(spaceID)
print("tiling space " .. spaceID)
end)

See Part 1 for common errors and Part 3 for a debug modifier pattern that logs frames without changing them.

Testing your work

Throughout these tutorials, you’ll test layouts in Hammerspoon:

  1. Save your layout file
  2. Reload Hammerspoon from the menu bar (Reload config) or run hs.reload() in the Hammerspoon console
  3. Cycle to your layout (Ctrl+Alt+Space)
  4. Check the console for errors (menu bar > Console)

Keep the console open while developing to catch errors early.