This guide takes you from an empty folder to a running RageKit app. It covers what to install, how to add RageKit to an app, a minimal app, and the commands you use every day.
RageKit is experimental. Expect rough edges and breaking changes.
| Linux (x86_64) | Windows (x86_64) | macOS | |
|---|---|---|---|
| Status | tested | less tested | not supported yet |
| PHP | 8.4 or 8.5 | 8.4 or 8.5 | |
| Composer, git, tar | yes | yes | |
| C++ compiler | g++ (build-essential) |
Visual Studio 2022 Build Tools, "Desktop development with C++" (install-build-tools.ps1 installs them) |
|
| Other | Slint's system libraries (below) | 7-Zip on PATH (unpacks Slint) |
On Windows, RageKit's install-build-tools.ps1 installs the Build Tools with only what's needed
(Windows asks for administrator rights; a few GB, 5-20 minutes). In an app it's at
vendor\ragekit\ragekit\install-build-tools.ps1:
powershell -ExecutionPolicy Bypass -File vendor\ragekit\ragekit\install-build-tools.ps1It does nothing when they're already installed, and adds the C++ workload to an existing Build
Tools install that lacks it. You rarely need to run it yourself: composer create-project ragekit/starter and ragekit setup ask whether to install the Build Tools when they're missing.
The ragekit command itself runs on PHP 8.2+, but TypePHP (the compiler) needs PHP 8.4 or 8.5, so
in practice you need 8.4+.
On Debian or Ubuntu:
sudo apt install php8.4-cli composer git build-essential \
libfontconfig1 libfreetype6 libxkbcommon0 libinput10 libgbm1 libudev1 \
php8.4-dev libphp8.4-embed cmake libgmp-dev libmpfr-devThe second line is what Slint's library links against. A desktop install already has them; a
minimal or server install may not, and then linking fails with "undefined reference to
libinput_…". Apps you ship need them on the user's machine too.
The third line is optional: with PHP's embed library, normal builds link your PHP and take seconds. Without it, the first normal build compiles a private PHP (~10 minutes, once). Nano builds need neither; see toolchain.md.
RageKit downloads everything else (TypePHP and Slint) itself with ragekit setup; see
toolchain.md.
The quickest way: create an app from ragekit/starter, which also runs ragekit setup:
composer create-project ragekit/starter myapp
cd myapp
composer start # build and run; also: composer build, composer devThe rest of this guide does the same by hand: add RageKit to a project, install the toolchain and write a minimal app.
RageKit is a Composer package, ragekit/ragekit:
composer require ragekit/ragekit:^0.8Your classes need an autoloader entry in composer.json, for example:
{
"autoload": {
"psr-4": { "Demo\\": "src/" }
}
}To work on RageKit itself and use your checkout in an app, add it as a path repository
("repositories": [{ "type": "path", "url": "../ragekit" }]) and require "ragekit/ragekit": "*@dev".
Always run the command as vendor/bin/ragekit from the app's folder (the folder with
project.yml). Composer's wrapper passes the app's autoloader, which the build needs to read your
classes.
vendor/bin/ragekit setup
vendor/bin/ragekit doctorsetup installs the TypePHP and Slint versions this RageKit version was tested with. They go to
a folder shared by all your apps (~/.local/share/ragekit/ on Linux), so the second app doesn't
download them again. doctor checks everything a build needs and tells you how to
fix what's missing. When you update RageKit and its pinned versions change, builds stop and ask
you to run setup again. Details: toolchain.md.
myapp/
project.yml
main.php
src/CounterApp.php
src/CounterScreen.php
templates/CounterScreen.rk
project.yml holds TypePHP's settings plus a ragekit: section:
name: myapp
sources:
- main.php
- src
ragekit:
backend: slint
renderer: softwareThe app is a class that extends RageKit\App. It names the screen the main window starts with,
and the main window's title and size:
<?php
namespace Demo;
use RageKit\App;
use RageKit\Screen;
final class CounterApp extends App
{
protected function firstScreen(): Screen
{
return new CounterScreen();
}
protected function title(): string
{
return 'Counter';
}
protected function width(): int
{
return 360;
}
protected function height(): int
{
return 200;
}
}main.php defines main(), the program's entry point. It runs the app: the main window opens,
and the event loop runs until the main window closes:
<?php
use Demo\CounterApp;
function main(): void
{
(new CounterApp())->run();
}A screen is a class with public properties (the state) and public methods (the handlers).
template() says where its .rk template is, relative to the project folder:
<?php
namespace Demo;
use RageKit\Screen;
final class CounterScreen extends Screen
{
public int $count = 0;
public static function template(): string
{
return 'templates/CounterScreen.rk';
}
public function increment(): void
{
$this->count++;
}
}The template describes the window. {count} shows the property, onClick="increment" calls the
method, and after every event the window shows the new values:
<VStack>
<Label text="Count: {count}" />
<Button text="+" onClick="increment" />
</VStack>More on templates, elements and child components: templates.md. For a custom title
bar (a frameless window drawn by your own Window subclass), see
Windows; for state the whole app shares
(who is signed in), state.md.
Bigger apps keep screens, windows, stores and services in their own folders under src/, with
templates in matching folders under templates/. ragekit make:screen Login and friends create
them in the right place; see make.md. The starter (composer create-project ragekit/starter) is laid out that way.
vendor/bin/ragekit build # compile into build/slint/
vendor/bin/ragekit run # build, then start the app
vendor/bin/ragekit dev # hot reload while you workbuildis the default command, so plainvendor/bin/ragekitbuilds too.build --runis the same asrun.--kit=<name>builds with another kit than the one inproject.yml;--backend=<name>overrides the backend (onlyslintexists).-vshows the compilers' output live. Without it, output only appears when a step fails.- Arguments after
--go to TypePHP's compiler unchanged, e.g.vendor/bin/ragekit build -- -f(-fforces a full rebuild). devruns your PHP on plainphpinside a prebuilt shell: saving a template reloads the UI, saving PHP restarts only PHP and keeps the state. Options:--kit=<name>,--on-top. See dev-mode.md.devruns full PHP, so runbuildfrom time to time to check that TypePHP still compiles your code.
TypePHP compiles a subset of PHP. Code that works in dev can fail to compile in build; the
build error says what to change.
Everything ends up in build/slint/ (build/<backend>/ in general):
| File (Linux / Windows) | What it is |
|---|---|
myapp / myapp.exe |
the app |
libragekit_slint.so / ragekit_slint.dll |
RageKit's bridge to Slint (built from your templates) |
libslint_cpp.so / slint_cpp.dll |
Slint's library |
librk_module_<name>.so / rk_module_<name>.dll |
one per enabled module (loaded at runtime) |
your assets: |
copied with their folder structure |
icon.png (with icon:) |
the app's icon; on Windows also app.ico for the executable |
tpc.yml, generated/, cache/ |
build files, not needed to run |
To ship the app, ragekit package puts those files into dist/ (below), or copy the executable
together with the libraries and assets next to it yourself. On
Windows, a normal (non-Nano) build also needs PHP's DLLs from the TypePHP release
(php8ts.dll, phpx.dll, …); ragekit doesn't copy those yet, so ragekit run finds them on
PATH but a copied app won't. Nano builds don't need them.
ragekit package builds the app (same options as build: --nano, --kit), then makes a file to
hand to people in dist/:
--format=tar(the default):<name>-<version>-linux-<arch>.tar.gz, a folder with the runtime files only. Unpack it anywhere and run the executable inside: it finds its libraries next to it.--format=deb:<name>_<version>_<arch>.debfor Debian and Ubuntu. It installs the app into/opt/<name>, a/usr/bin/<name>link, and a menu entry (a.desktopfile with the app's icon, and its link schemes, so an installed app handles its links withoutLinks::register()).Depends:lists the system libraries the binaries link (fromdpkg-shlibdeps);Recommends:the ones modules load at run time (libsecret forkeyring, GLib fornotifications/tray). Needsdpkg-devandfakeroot.
ragekit:
icon: assets/icon.png
package:
version: 1.0.0 # default 0.0.0
description: | # the first line is the summary
A desktop client for example.com.
More about it on the following lines.
maintainer: Ann <ann@example.com>
homepage: https://example.comNormal builds on Linux contain PHP's runtime (statically, or the system's libphp next to the
executable); Nano builds are smaller. Not yet: AppImage, Windows installers and zips, macOS bundles.
The ragekit: section:
| Key | Values | What it does |
|---|---|---|
backend |
slint (default) |
the UI toolkit |
kit |
material (default), shadcn, or your own |
how elements look; see kits.md |
renderer |
software, femtovg, skia |
how Slint draws (see below) |
nano |
true / false (default) |
build with TypePHP's Nano runtime; see toolchain.md |
modules |
list, e.g. [audio] |
native modules the app uses; see modules.md |
assets |
list of files or folders, e.g. [assets/] |
copied next to the executable; read them with App::resolve('assets/…') |
icon |
a .png (or .svg) file, e.g. assets/icon.png |
the app's icon: every window shows it, it's copied next to the executable as icon.png, and the .desktop file Links::register() writes names it. On Windows a png also becomes the .exe's icon (not yet tested there) |
package |
{ version, description, maintainer, homepage } |
what ragekit package writes into the package (see above) |
links |
list of URL schemes, e.g. [myapp] |
the app handles myapp://… links and runs as a single instance; see links.md |
dev |
{ on-top: true } |
ragekit dev keeps the windows above others (same as --on-top) |
Renderers:
softwaredraws on the CPU. It uses the least memory (around 20–30 MB for a small app) and starts fastest, but doesn't draw drop shadows.femtovgandskiadraw on the GPU and draw shadows. They use much more memory (often 100–200 MB, mostly the graphics driver).skiais Slint's default whenrendererisn't set.
The environment variable SLINT_BACKEND (e.g. winit-skia) overrides renderer at run time.
Unknown keys print "ignored" during the build. Everything outside ragekit: is passed to TypePHP
(name, sources, cxx-flags, defines, …).
From a checkout of RageKit:
./setup.sh # Linux; setup.ps1 on Windows
cd demo/counter-slint && ../../bin/ragekit run| Demo | Shows |
|---|---|
demo/calculator |
logic in plain PHP, a keypad from a constant with each |
demo/counter-slint |
state, handlers, a child component, a second window |
demo/kitchen-sink |
every core element, with the shadcn kit (--kit=material to compare) |
demo/kit-demo |
an app's own kit (kits/icons) with SVG icons embedded at build time |
demo/player |
the audio module and assets; RAGEKIT_AUDIO_NULL=1 plays silently without speakers |
The demos use the toolchain setup.sh installed: the shared one, or a .ragekit/ folder in the
repository root if you created one (builds look for .ragekit/ in the app's folder and each
parent folder first).