Files
komorebi/docs/common-workflows/layout-ratios.md
Csaba 24c0ce0b1d feat(wm): add global layout_defaults for per-layout default options
Adds a top-level layout_defaults setting that defines default
layout_options and layout_options_rules per layout. Workspaces without
their own layout_options or layout_options_rules automatically inherit
the global defaults. If a workspace defines either setting, all global
defaults for that layout are fully replaced.
2026-05-03 10:16:20 -07:00

10 KiB

Layout Ratios

With komorebi you can customize the split ratios for various layouts using column_ratios and row_ratios in the layout_options configuration.

Before and After

BSP layout example:

Before (default 50/50 splits):

Before layout ratios

After (with column_ratios: [0.7] and row_ratios: [0.6]):

After layout ratios

Configuration

{
  "monitors": [
    {
      "workspaces": [
        {
          "name": "main",
          "layout_options": {
            "column_ratios": [0.3, 0.4],
            "row_ratios": [0.4, 0.3]
          }
        }
      ]
    }
  ]
}

You can specify up to 5 ratio values (defined by MAX_RATIOS constant). Each value should be between 0.1 and 0.9 (defined by MIN_RATIO and MAX_RATIO constants). Values outside this range are automatically clamped. Columns or rows without a specified ratio will share the remaining space equally.

Usage by Layout

Layout column_ratios row_ratios
Columns Width of each column -
Rows - Height of each row
Grid Width of each column (rows are equal height) -
BSP [0] as horizontal split ratio [0] as vertical split ratio
VerticalStack [0] as primary column width Stack row heights
RightMainVerticalStack [0] as primary column width Stack row heights
HorizontalStack Stack column widths [0] as primary row height
UltrawideVerticalStack [0] center, [1] left column Tertiary stack row heights

Examples

Columns Layout with Custom Widths

Create 3 columns with 30%, 40%, and 30% widths:

{
  "layout_options": {
    "column_ratios": [0.3, 0.4]
  }
}

Note: The third column automatically gets the remaining 30%.

Rows Layout with Custom Heights

Create 3 rows with 20%, 50%, and 30% heights:

{
  "layout_options": {
    "row_ratios": [0.2, 0.5]
  }
}

Note: The third row automatically gets the remaining 30%.

Grid Layout with Custom Column Widths

Grid with custom column widths (rows within each column are always equal height):

{
  "layout_options": {
    "column_ratios": [0.4, 0.6]
  }
}

Note: The Grid layout only supports column_ratios. Rows within each column are always divided equally because the number of rows per column varies dynamically based on window count.

VerticalStack with Custom Ratios

Primary column takes 60% width, and the stack rows are split 30%/70%:

{
  "layout_options": {
    "column_ratios": [0.6],
    "row_ratios": [0.3]
  }
}

Note: The second row automatically gets the remaining 70%.

HorizontalStack with Custom Ratios

Primary row takes 70% height, and the stack columns are split 40%/60%:

{
  "layout_options": {
    "row_ratios": [0.7],
    "column_ratios": [0.4]
  }
}

Note: The second column automatically gets the remaining 60%.

UltrawideVerticalStack with Custom Ratios

Center column at 50%, left column at 25% (remaining 25% goes to tertiary stack), with tertiary rows split 40%/60%:

{
  "layout_options": {
    "column_ratios": [0.5, 0.25],
    "row_ratios": [0.4]
  }
}

Note: The second row automatically gets the remaining 60%.

BSP Layout with Custom Split Ratios

Use separate ratios for horizontal (left/right) and vertical (top/bottom) splits:

{
  "layout_options": {
    "column_ratios": [0.6],
    "row_ratios": [0.3]
  }
}
  • column_ratios[0]: Controls all horizontal splits (left window gets 60%, right gets 40%)
  • row_ratios[0]: Controls all vertical splits (top window gets 30%, bottom gets 70%)

Note: BSP only uses the first value ([0]) from each ratio array. This single ratio is applied consistently to all splits of that type throughout the layout. Additional values in the arrays are ignored.

Notes

  • Ratios are clamped between 0.1 and 0.9 (prevents zero-sized windows and ensures space for other windows)
  • Default ratio is 0.5 (50%) when not specified, except for UltrawideVerticalStack secondary column which defaults to 0.25 (25%)
  • Ratios are applied progressively - a ratio is only used when there are more windows to place after the current one
  • The last window always takes the remaining space, regardless of defined ratios
  • Ratios that would sum to 100% or more are automatically truncated at config load time to ensure there's always space for additional windows
  • Unspecified ratios default to sharing the remaining space equally
  • You only need to specify the ratios you want to customize; trailing values can be omitted

Layout Options Rules

You can dynamically change layout_options based on the number of containers on a workspace using layout_options_rules. This uses the same threshold-based logic as layout_rules: when the container count is greater than or equal to a threshold, the highest matching threshold's options are used.

Rules fully replace the base layout_options when they match. If no rule matches, the base layout_options is used.

Configuration

{
  "monitors": [
    {
      "workspaces": [
        {
          "name": "main",
          "layout": "VerticalStack",
          "layout_options": {
            "column_ratios": [0.6],
            "row_ratios": [0.4]
          },
          "layout_options_rules": {
            "3": { "column_ratios": [0.55] },
            "5": { "column_ratios": [0.3, 0.3, 0.3], "row_ratios": [0.5] }
          }
        }
      ]
    }
  ]
}

In the example above:

Container Count Effective layout_options
1-2 Base: column_ratios: [0.6], row_ratios: [0.4]
3-4 Rule "3": column_ratios: [0.55] (no row_ratios, no scrolling, no grid)
5+ Rule "5": column_ratios: [0.3, 0.3, 0.3], row_ratios: [0.5]

Rules can include any field that layout_options supports: column_ratios, row_ratios, scrolling, and grid. When a rule matches, it completely replaces the base options. Fields not specified in the matching rule default to their standard defaults (not the base layout_options values).

Example: Scrolling Layout with Dynamic Columns

{
  "layout": "Scrolling",
  "layout_options": {
    "scrolling": { "columns": 2 }
  },
  "layout_options_rules": {
    "4": { "scrolling": { "columns": 3 } },
    "7": { "scrolling": { "columns": 4 } }
  }
}

This increases the visible scrolling columns as more windows are added.

Layout Defaults

You can define global per-layout default layout_options and layout_options_rules using the top-level layout_defaults setting. This avoids repeating the same configuration across every workspace that uses the same layout.

Configuration

{
  "layout_defaults": {
    "VerticalStack": {
      "layout_options": { "column_ratios": [0.7] },
      "layout_options_rules": {
        "2": { "column_ratios": [0.7] },
        "3": { "column_ratios": [0.55] },
        "5": { "column_ratios": [0.4] }
      }
    },
    "Columns": {
      "layout_options": { "column_ratios": [0.3, 0.4] },
      "layout_options_rules": {
        "4": { "column_ratios": [0.2, 0.3, 0.3] }
      }
    },
    "HorizontalStack": {
      "layout_options": { "row_ratios": [0.6] }
    }
  },
  "monitors": [
    {
      "workspaces": [
        {
          "name": "main",
          "layout": "VerticalStack"
        }
      ]
    }
  ]
}

In this example, every workspace using VerticalStack, Columns, or HorizontalStack automatically gets the global layout_options and layout_options_rules without needing to specify them per-workspace. Note that VerticalStack only has 2 columns (main + stack), so only a single column_ratios value is meaningful, while Columns distributes windows across multiple columns where additional ratios control each column's width.

Resolution Cascade

Global defaults act as a fallback. If a workspace defines either layout_options or layout_options_rules, it completely replaces all global layout_defaults for that layout. Global defaults are only used when the workspace has neither setting.

Within the effective source (workspace or global):

  1. Try threshold match from the rules (highest matching threshold wins)
  2. If a rule matches → use it (full replacement of base options)
  3. Otherwise → use the base layout_options

Override Examples

Workspace Config Global Config Effective Behavior
No layout_options, no rules layout_defaults has both Uses global base + global rules
Has layout_options only layout_defaults has both Workspace base only (all globals ignored)
Has layout_options_rules only layout_defaults has both Workspace rules only (all globals ignored)
Has both layout_defaults has both All workspace (all globals ignored)

This "complete replacement" semantic means you never get a mix of workspace and global settings for the same layout. If you override anything at the workspace level, you take full control of that layout's options for that workspace.

Progressive Ratio Behavior

Ratios are applied progressively as windows are added. For example, with row_ratios: [0.3, 0.5] in a VerticalStack:

Windows in Stack Row Heights
1 100%
2 30%, 70% (remainder)
3 30%, 50%, 20% (remainder)
4 30%, 50%, 10%, 10% (remainder split equally)
5 30%, 50%, 6.67%, 6.67%, 6.67%

Automatic Ratio Truncation

When ratios sum to 100% (or more), they are automatically truncated at config load time.

For example, if you configure column_ratios: [0.4, 0.3, 0.3] (sums to 100%), the last ratio (0.3) is automatically removed, resulting in effectively [0.4, 0.3]. This ensures there's always remaining space for the last window.

Configured Ratios Effective Ratios Reason
[0.3, 0.4] [0.3, 0.4] Sum is 0.7, below 1.0
[0.4, 0.3, 0.3] [0.4, 0.3] Sum would be 1.0, last ratio truncated
[0.5, 0.5] [0.5] Sum would be 1.0, last ratio truncated
[0.6, 0.5] [0.6] Sum would exceed 1.0, last ratio truncated

This ensures the layout always fills 100% of the available space and new windows are never placed outside the visible area.