Build GUI applications for Linux desktop environments using AGS. Use when creating desktop applications, system tray tools, bars, or native Linux UI components.
Use AGS (Aylur's GTK Shell) for all Linux GUI development. AGS provides JavaScript/TypeScript-based development with React-like JSX syntax, GTK/CSS styling, and built-in bindings for system integration.
Create a file anywhere:
// mybar.tsx
import app from "ags/gtk4/app"
import { Astal } from "ags/gtk4"
import { createPoll } from "ags/time"
app.start({
main() {
const { TOP, LEFT, RIGHT } = Astal.WindowAnchor
const clock = createPoll("", 1000, "date")
return (
<window visible anchor={TOP | LEFT | RIGHT}>
<label label={clock} />
</window>
)
},
})
Run it:
ags run ./mybar.tsx
#!/usr/bin/env -S ags run
import app from "ags/gtk4/app"
app.start({
main() {
// entry point
},
})
Make executable:
chmod +x mybar.tsx
./mybar.tsx
ags init -d /path/to/project
Generates a template with TypeScript configuration.
ags types -u -d /path/to/project/root
Generates types from GObject-based libraries. Run after adding dependencies.
ags bundle
Bundles your project into a single executable script.
ags run
Runs without bundling for rapid iteration.
import { createState } from "ags"
import { createPoll } from "ags/time"
function Bar() {
const [counter, setCounter] = createState(0)
const date = createPoll("", 1000, `date "+%H:%M - %A %e."`)
return (
<window visible anchor={TOP | LEFT | RIGHT}>
<centerbox>
<label $type="start" label={date} />
<button $type="end" onClicked={() => setCounter((c) => c + 1)}>
<label label={counter((c) => `clicked ${c} times`)} />
</button>
</centerbox>
</window>
)
}
import { createBinding } from "ags"
import { Battery } from "ags/system"
import { Mpris } from "ags/media"
function BatteryLabel() {
const percentage = createBinding(Battery.get_default(), "percentage")
return <label label={percentage((p) => `${Math.round(p * 100)}%`)} />
}
function MediaPlayers() {
const players = createBinding(Mpris.get_default(), "players")
return (
<For each={players}>
{(player) => (
<button
label={createBinding(player, "title")}
onClicked={() => player.play_pause()}
/>
)}
</For>
)
}
button {
animation: wiggle 2s linear infinite;
}
@keyframes wiggle {
0% { transform: rotateZ(0); }
7% { transform: rotateZ(0); }
15% { transform: rotateZ(-15deg); }
20% { transform: rotateZ(10deg); }
25% { transform: rotateZ(-10deg); }
30% { transform: rotateZ(6deg); }
35% { transform: rotateZ(-4deg); }
40% { transform: rotateZ(0); }
100% { transform: rotateZ(0); }
}
.tsx file with shebang, run with ags run ./file.tsxags init -d /path/to/project for TypeScript environmentags types -u -d /path/to/project/root after adding dependenciesags run for hot reloadags bundle for production deployment