Your desktop,
under version control.
Gailan runs widgets on your macOS desktop. They are TypeScript files in a folder: save one and it is on screen before you have switched windows.
A folder of files, on your wallpaper
There is no widget store and no editor to learn. Gailan watches a directory, compiles what it finds, and draws it behind your windows. Delete the file and the widget is gone.
Widgets are TypeScript
A widget is a module exporting a command, a refresh interval and a render. Types are stripped when it bundles, so annotate as much or as little as suits you.
esbuild, not Babel
Save a file and it rebuilds in single-digit milliseconds, then pushes over a socket. No dev server to start, no watcher to configure.
Glass drawn by macOS
A widget marks a rectangle and the system frosts your wallpaper behind it. Real Liquid Glass on macOS 26, a vibrancy material before that.
Shortcuts and AppleScript
Refresh a widget, reload one, hide it, choose its screens. From the Shortcuts app with a widget picker, from a script, or from Siri.
Locked to your machine
The server binds to localhost, checks the origin, and takes a per-launch token handed over on stdin. Nothing else on your network can reach it.
Übersicht widgets still run
The classic object-literal API is intact, and importing uebersicht still resolves. Rename the file to .js and it works.
Three exports and you are done
A command to run, how often to run it, and what to draw with the output. Everything else is optional.
import { styled } from "gailan"
export const command = "date '+%H:%M'"
export const refreshFrequency = 10000
const Time = styled("div")`
font-variant-numeric: tabular-nums;
`
// the desktop is frosted behind this one
export const render = ({ output }) => (
<Time data-gailan-desktop-glass={12}>
{output.trim()}
</Time>
)What you get for free
Emotion's css and styled are exported from the gailan module, and generated class names carry the component they came from, so the inspector reads css-1a2b3c-Time rather than a hash on its own.
Widgets see the system appearance through prefers-color-scheme and an attribute on the document, so light and dark are a media query rather than a setting to read.
When a widget fails, the error appears where the widget was, with the line from your source and the column marked. The stack is mapped back through the bundle, so it points at the file you wrote.
Glass the system draws
A page cannot see what is behind its own window, which is why CSS has never been able to frost a wallpaper. So the widget marks a rectangle and the app asks macOS to put its material there.
One attribute
Add data-gailan-desktop-glass to an element with the radius you want. Give it an id and the same pane of glass follows it as the widget re-renders.
On macOS 26 this is Liquid Glass, with a style and a tint in Preferences. Before that it is the closest vibrancy material. Keep your own background thin or it covers the glass it asked for.
Specifications
Widgets, by pull request
GailanHub is one repository of widgets. Every one is a folder with a manifest, a readme saying what it runs, and a screenshot. Adding yours means opening a pull request; CI compiles it before anyone looks.