Back to Komorebi

Layout Ratios

docs/common-workflows/layout-ratios.md

0.1.4110.3 KB
Original Source

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):

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

Configuration

json
{
  "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

Layoutcolumn_ratiosrow_ratios
ColumnsWidth of each column-
Rows-Height of each row
GridWidth of each column (rows are equal height)-
BSP[0] as horizontal split ratio[0] as vertical split ratio
VerticalStack[0] as primary column widthStack row heights
RightMainVerticalStack[0] as primary column widthStack row heights
HorizontalStackStack column widths[0] as primary row height
UltrawideVerticalStack[0] center, [1] left columnTertiary stack row heights

Examples

Columns Layout with Custom Widths

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

json
{
  "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:

json
{
  "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):

json
{
  "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%:

json
{
  "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%:

json
{
  "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%:

json
{
  "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:

json
{
  "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

json
{
  "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 CountEffective layout_options
1-2Base: column_ratios: [0.6], row_ratios: [0.4]
3-4Rule "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

json
{
  "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

json
{
  "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 ConfigGlobal ConfigEffective Behavior
No layout_options, no ruleslayout_defaults has bothUses global base + global rules
Has layout_options onlylayout_defaults has bothWorkspace base only (all globals ignored)
Has layout_options_rules onlylayout_defaults has bothWorkspace rules only (all globals ignored)
Has bothlayout_defaults has bothAll 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 StackRow Heights
1100%
230%, 70% (remainder)
330%, 50%, 20% (remainder)
430%, 50%, 10%, 10% (remainder split equally)
530%, 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 RatiosEffective RatiosReason
[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.