Skip to content

Repository files navigation

tilescript

tilescript is a layout runtime designed for Wayland compositors and tiling window managers.

It lets you define workspace layouts in JSX/TSX, Lua, or Fennel together with CSS, then evaluates those layouts in Rust and hands the resulting placement decisions to a window manager or compositor adapter.

Current adapter target: Hyprland

Playground: https://akisarou.github.io/tilescript/

Features

  • JSX/TSX, Lua, and Fennel layouts
  • CSS-driven layout
  • runtime layout selection by workspace index, workspace name, and monitor
  • flex-inferred resize behavior with configurable resize step and minimum pane size
  • Hyprland plugin integration
  • CSS language server crates and a VS Code client package

Examples

layouts/master-stack/index.tsx
import type { LayoutContext } from "@tilescript/sdk/layout";

import "./index.css";

export default function layout(ctx: LayoutContext) {
  return (
    <workspace>
      <slot take={1} class="master-slot" />

      {ctx.windows.length > 1 ? (
        <group class="stack-group">
          <slot class="stack-slot" />
        </group>
      ) : null}
    </workspace>
  );
}
layouts/master-stack/index.lua
local h = require("tilescript")

---@param ctx Tilescript.LayoutContext
return function(ctx)
  return h.workspace() {
    h.slot({
      take = 1,
      class = "master-slot",
    }),

    h.when(#ctx.windows > 1) {
      h.group({ class = "stack-group" }) {
        h.slot({
          class = "stack-slot",
        }),
      },
    },
  }
end
layouts/master-stack/index.fnl
(local h (require "tilescript"))

(fn [ctx]
  ((h.workspace)
   [(h.slot {:take 1
             :class "master-slot"})
    ((h.when (> (# ctx.windows) 1))
     [((h.group {:class "stack-group"})
       [(h.slot {:class "stack-slot"})])])]))

layouts/master-stack/index.css

workspace {
  display: flex;
  flex-direction: row;
  gap: 6px;
  padding: 6px;
  width: 100%;
  height: 100%;

  .master-slot {
    flex-basis: 0;
    flex-grow: 3;
    min-width: 0;
    min-height: 0;
  }

  .stack-group {
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex-basis: 0;
    flex-grow: 2;
    min-width: 0;

    .stack-slot {
      flex-basis: 0;
      flex-grow: 1;
      min-height: 0;
    }
  }
}

Config Layout

tilescript loads a config root directory.

If config_path is omitted, the default config root is ~/.config/tilescript.

At minimum, that directory contains:

  • a config entry such as config.{ts, tsx, js, jsx, lua, fnl}.
  • one or more layouts under layouts/<name>/
  • optional root index.css for shared stylesheet rules

For starter layouts and config skeletons, see examples/.

Typical project layout:

config.ts
index.css
layouts/
  master-stack/
    index.tsx
    index.css
  dwindle/
    index.lua
    index.css

Hyprland

To use tilescript with Hyprland:

  1. Build the plugin with make hypr-plugin.
  2. Run make hypr-plugin-snippet and paste the printed plugin block into your Hyprland config.
  3. Set config_path to your config root directory.
  4. Reload Hyprland or reload the plugin after changing layouts or config.

Example Hyprland config:

plugin = /absolute/path/to/tilescript-hypr.so

plugin {
  tilescript-hypr {
    config_path = /absolute/path/to/your/tilescript-config/
  }
}


general {
    # disable gaps. those should be better configured via CSS
    gaps_in = 0
    gaps_out = 0

    layout = tilescript
}

Related keybindings:

$mainMod = ALT

bind = $mainMod, h, tilescript-hypr, focus, l
bind = $mainMod, j, tilescript-hypr, focus, d
bind = $mainMod, k, tilescript-hypr, focus, u
bind = $mainMod, l, tilescript-hypr, focus, r

bind = $mainMod CTRL, h, tilescript-hypr, resize, l
bind = $mainMod CTRL, j, tilescript-hypr, resize, d
bind = $mainMod CTRL, k, tilescript-hypr, resize, u
bind = $mainMod CTRL, l, tilescript-hypr, resize, r

bind = $mainMod SHIFT, h, tilescript-hypr, move, l
bind = $mainMod SHIFT, j, tilescript-hypr, move, d
bind = $mainMod SHIFT, k, tilescript-hypr, move, u
bind = $mainMod SHIFT, l, tilescript-hypr, move, r

bind = $mainMod, 1, tilescript-hypr, workspace, 1
bind = $mainMod, 2, tilescript-hypr, workspace, 2
bind = $mainMod, 3, tilescript-hypr, workspace, 3
bind = $mainMod, 4, tilescript-hypr, workspace, 4
bind = $mainMod, 5, tilescript-hypr, workspace, 5
bind = $mainMod, 6, tilescript-hypr, workspace, 6
bind = $mainMod, 7, tilescript-hypr, workspace, 7
bind = $mainMod, 8, tilescript-hypr, workspace, 8
bind = $mainMod, 9, tilescript-hypr, workspace, 9
bind = $mainMod, 0, tilescript-hypr, workspace, 10

bind = $mainMod SHIFT, 1, tilescript-hypr, movetoworkspace, 1
bind = $mainMod SHIFT, 2, tilescript-hypr, movetoworkspace, 2
bind = $mainMod SHIFT, 3, tilescript-hypr, movetoworkspace, 3
bind = $mainMod SHIFT, 4, tilescript-hypr, movetoworkspace, 4
bind = $mainMod SHIFT, 5, tilescript-hypr, movetoworkspace, 5
bind = $mainMod SHIFT, 6, tilescript-hypr, movetoworkspace, 6
bind = $mainMod SHIFT, 7, tilescript-hypr, movetoworkspace, 7
bind = $mainMod SHIFT, 8, tilescript-hypr, movetoworkspace, 8
bind = $mainMod SHIFT, 9, tilescript-hypr, movetoworkspace, 9
bind = $mainMod SHIFT, 0, tilescript-hypr, movetoworkspace, 10

bind = $mainMod, q, tilescript-hypr, closewindow
bind = $mainMod, f, tilescript-hypr, fullscreen

Docs

Core Dependencies

tilescript builds on a small set of foundational libraries:

About

JSX+CSS window manager layout runtime

Resources

Stars

8 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages