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/
- 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
layouts/master-stack/index.tsx
importtype{LayoutContext}from"@tilescript/sdk/layout";import"./index.css";exportdefaultfunctionlayout(ctx: LayoutContext){return(<workspace><slottake={1}class="master-slot"/>{ctx.windows.length>1 ? (<groupclass="stack-group"><slotclass="stack-slot"/></group>) : null}</workspace>);}layouts/master-stack/index.lua
localh=require("tilescript")
---@paramctxTilescript.LayoutContextreturnfunction(ctx)
returnh.workspace() {
h.slot({
take=1,
class="master-slot",
}),
h.when(#ctx.windows>1) {
h.group({ class="stack-group" }) {
h.slot({
class="stack-slot",
}),
},
},
}
endlayouts/master-stack/index.fnl
(localh (require"tilescript"))
(fn [ctx]
((h.workspace)
[(h.slot {:take1: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;
}
}
}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.cssfor 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
To use tilescript with Hyprland:
- Build the plugin with
make hypr-plugin. - Run
make hypr-plugin-snippetand paste the printedpluginblock into your Hyprland config. - Set
config_pathto your config root directory. - 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 CSSgaps_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, fullscreendocs/config.mddocs/hyprland.mddocs/jsx.mddocs/css.mddocs/css-lsp.mddocs/development.mddocs/playground.md
tilescript builds on a small set of foundational libraries:
stylo,cssparser, andselectorsfor CSS parsing and selector machinerytaffyfor layout computationoxcandoxc_resolverfor JS/TS/TSX parsing and module graph analysisrquickjsfor the native JS runtimemluafor the native Lua runtimeleptosandleptos_routerfor the browser playground UIwasm-bindgenandweb-sysfor browser/WASM interopmonaco-editor,monaco-vim, andwasmoonfor the playground editor and browser Lua execution