pushinbr / pam-desktop
Build fast native Linux, macOS and Windows applications with PHP and PAM.
Requires
- php: ^8.5
- symfony/polyfill-intl-normalizer: ^1.43
Requires (Dev)
None
Suggests
- bacon/bacon-qr-code: Required by Pam\Desktop\Qr (^3.1.1)
Provides
None
Conflicts
None
Replaces
None
- dev-main
- v2.1.3
- v2.1.2
- v2.1.1
- v2.1.0
- v2.0.1
- v2.0.0
- v1.3.4
- v1.3.3
- v1.3.2
- v1.3.1
- v1.3.0
- v1.2.9
- v1.2.8
- v1.2.7
- v1.2.6
- v1.2.5
- v1.2.4
- v1.2.3
- v1.2.2
- v1.2.1
- v1.2.0
- v1.1.2
- v1.1.1
- v1.1.0
- v1.0.5
- v1.0.4
- v1.0.3
- v1.0.2
- v1.0.1
- dev-feat/css-for-storefront
- dev-docs/remove-desktop-workaround
- dev-brand/pam-mascot
- dev-release/2.1.2
- dev-docs/readme
- dev-fix/parity-2.1.x
- dev-feat/chromium-parity-2.1
- dev-fix/gtk-4-6-baseline
- dev-release/2.0.0
- dev-feat/native-2.0
- dev-release/1.3.3
- dev-fix/accesskit-tokio-runtime
- dev-release/1.3.2
- dev-fix/release-linux-runtime
- dev-release/desktop-1.3.1
- dev-fix/release-clean-room-display
- dev-feat/native-workstation-1.3
- dev-fix/http-status-response
- dev-codex/select-host-1-2-7
- dev-codex/binary-http
- dev-fix/desktop-window-geometry
This package is auto-updated.
Last update: 2026-11-09 19:04:27 UTC
README
Native desktop applications written in PHP.
Components, state and styles in PHP; a Rust host that lays the tree out and drives real platform views.
No Electron, no Node.js, no web view in the rendering path.
Install · Quick example · Platforms · Features · Docs · Issues
Install
Create a project with the PAM CLI and run it:
pam init my-app --template desktop cd my-app && pam desktop dev
pam init --template desktop (PAM 2.2.12 and later) requires pushinbr/pam-desktop ^2.1, installs it and runs pam desktop init, which writes a small application: a router, a home screen as a .pam.php template with scoped CSS, design tokens, a service and a test. pam desktop dev needs no argument (it finds the nearest pam-desktop.json), reloads the window about 0.3 s after a save and keeps #[State] values. Without PHP on the machine, the host installs it (the PAM runtime on Linux and macOS, the official windows.php.net build on Windows).
pam desktop runs the package's launcher, which downloads the native host of the installed version for the current system from the GitHub release (Linux, macOS and Windows, x86_64 and aarch64), verifies its SHA-256 and runs it. PAM_DESKTOP_HOST points the launcher at a host built from source. To build and run from a checkout, see Examples.
PAM Desktop 2.0 is a different product from 1.x. Version 1 rendered a web interface in a Servo web view behind a typed command gateway; version 2 renders a native interface from PHP components. Applications written for 1.x do not run on 2.x. See Migrating from 1.x.
Quick example
examples/counter/index.php:
<?php declare(strict_types=1); use Pam\Desktop\App; use Pam\Desktop\Component; use Pam\Desktop\Attributes\State; use Pam\Desktop\Style; use Pam\Desktop\UI\Button; use Pam\Desktop\UI\Column; use Pam\Desktop\UI\Text; require __DIR__.'/../../vendor/autoload.php'; final class Counter extends Component { #[State] public int $count = 0; public function render(): Column { return Column::make( Text::make('PAM Desktop')->style(new Style(fontSize: 28, fontWeight: 700)), Text::make("Count: {$this->count}")->style(new Style(fontSize: 18)), Button::make('Increment')->onPress(function (): void { $this->count++; }), )->style(new Style(padding: 24, gap: 16)); } } App::run(new Counter());
Assigning to a #[State] property schedules a render. The host receives a patch with the one text that changed.
Platform support
| Platform | Support | Notes |
|---|---|---|
| Linux | GTK 4 (pam-desktop-gtk) |
The reference backend. Every example and every feature was run and checked on Linux. |
| macOS | AppKit (pam-desktop-appkit) |
Run on macOS 26 (x86_64) in a VM without a GPU: core examples, hot reload, input, a real application and a DMG from pam-desktop build. Not run on Apple Silicon; blur, media, web views, notifications, printing and drag and drop not verified. |
| Windows | Win32 + Direct2D/DirectWrite (pam-desktop-win32) |
Type-checked by cross compilation against the same Backend contract. Not run on Windows yet: first runs are expected to need fixes. |
Requirements
| Requirement | Notes |
|---|---|
| PHP 8.5 | The php executable on PATH, or pam (the host then runs pam exec), or the path in PAM_DESKTOP_PHP. On Linux and macOS without any of them, the host installs the PAM runtime, which embeds PHP; on Windows it downloads the official PHP 8.5 build from windows.php.net (not run on Windows yet). |
| Composer | To install the pushinbr/pam-desktop package. |
| Linux, to run a released host | glibc 2.35 or newer, GTK 4.6 or newer and the GStreamer plugins for media (Ubuntu 22.04, Debian 12, Fedora 36 and later). WebKitGTK 6 (libwebkitgtk-6.0-4, Ubuntu 24.04 and later) only for applications that show a WebView. The released host is built on Ubuntu 22.04 and uses the GTK features newer than 4.6 when the installed GTK has them. |
| Rust 1.92 or newer | Only to build the host from a checkout. rust-toolchain.toml selects the stable channel. |
Linux, to build: libgtk-4-dev |
GTK 4.6 or newer. |
The optional features of the host on Linux, tray and hotkeys, need no extra system library. Platforms lists what each feature does.
The host starts the backend of the system it was built for. Two things were not verified on Linux either: the accessibility tree with a real screen reader, and global shortcuts through the Wayland portal (X11 key grabs were verified). Per-feature status: Platforms; first-run checklist: First run on macOS and Windows.
How it works
A PAM Desktop application is a PHP script. It declares components with reactive state and returns a tree of elements (Column, Row, Text, Button, Input, VirtualizedList…), using the same component syntax as PAM Native, the mobile sibling of this project.
The pam-desktop host starts that script in a PHP worker process and talks to it over stdin and stdout in binary frames. For every frame the host lays the tree out, computes the difference from the previous one and updates real platform views:
- GTK 4 on Linux
- AppKit on macOS
- Win32 with Direct2D and DirectWrite on Windows
Rendering never goes through a web view. A WebView element exists for the cases where an application wants to embed a page.
The host does not wait for PHP to animate, scroll, track gestures, play media or edit text. PHP runs when an event needs application logic and sleeps otherwise.
Features
| Area | What you get | Document |
|---|---|---|
| Components | Layout, text with inline boxes, buttons, inputs (masks, currency, decimal), switches, content-sized lists, scroll views, modals with backdrop blur, bottom sheets, stack navigation with a header, tabs | Components |
| Templates | .pam.php single-file components: expressions with enums, constants and value methods, <Slot :content>, per-component error isolation |
Templates |
| Styling | Style and scoped CSS laid out like Chromium (1/64 px LayoutUnits, Blink line heights): state selectors with :focus-within and :focus-visible, @media, CSS tables, inline formatting (inline, inline-block, vertical-align), position: sticky, two-axis scrolling, classic and thin scrollbars with scrollbar-color, ch units, form controls sized like Blink, font stacks and packaged fonts, line breaking, white-space, backdrop-filter and box shadows matching Skia, fractional grid tracks, dark mode, text scale |
Styling, Grid tracks |
| Controls | Select, Autocomplete, MultiSelect, DatePicker, Toast and the window toast service, Checkbox, ProgressButton (pushinbr/pam-desktop-ui) |
DesktopUI |
| Internationalization | Framework defaults in English, Portuguese and Spanish, following the system or I18n::use(), overridable per app and per component |
Internationalization |
| Charts | Line, area, bar, donut, sparkline, progress ring on the native canvas (pushinbr/pam-desktop-charts) |
Charts |
| Desktop shell | Main window control, secondary windows, menu bar, context menus, tray, local and global shortcuts, key capture, file dialogs, notifications, typed drag and drop, clipboard | Desktop shell |
| Media and web | Images with a disk cache, video and audio, embedded web pages, vector and freehand canvases | Media and web |
| Motion | Transitions, presets, animation programs, gesture detectors, drag contracts, swipeable rows, native pan and zoom | Animation and gestures |
| Modules | Key/value storage, file sandbox and save dialog, HTTP, WebSocket, SQLite with guarded transactions, secure storage, printing, timers, device information and status, links and deep links with a single instance, toasts, alerts | Modules |
| Accessibility | Roles, labels, states and actions mapped to AT-SPI, NSAccessibility and UI Automation; announcements; text selection; keyboard navigation | Accessibility |
| Development | Hot reload with state preservation, the error overlay, pam-desktop check (every template/CSS diagnostic without a window), frame dumps compared with Chromium, screenshots on a virtual display, test suites, static analysis, CI |
Development |
| Internals | Processes, the frame protocol, the render core, the Backend contract, threading |
Architecture |
| Compatibility | Host and SDK versions, the property table and what an older host refuses | Compatibility |
| Shipping | Packaging and installers | Distribution |
| Updates | Application updates | Updates |
Capabilities that only exist on phones in PAM Native (location, contacts, sensors, biometrics, SMS…) are not part of PAM Desktop. Their class names are still known: using one throws a PluginException that names the optional package it belongs to.
Examples
Every directory under examples/ is a runnable application that exercises one feature: counter, showcase, controls, lists, chat, navigation, motion, gestures, images, media, webview, canvas, shell, windows, dragdrop, text, modules, links, toast, errors, web-defaults. What each one shows and how to run them from a checkout: docs/examples.md. Crate and package map: docs/repository-layout.md.
Docs
- Getting started
- Components
- Templates
- Styling
- Grid tracks
- DesktopUI
- Charts
- Desktop shell
- Media and web
- Animation and gestures
- Modules
- Accessibility
- Development
- Architecture
- Compatibility
- Platforms
- First run on macOS and Windows
- Distribution
- Updates
- Migrating from 1.x
- Examples
- Repository layout
- Changelog
Part of the PAM ecosystem
PAM runs PHP natively on servers, desktops and phones. This repository is one piece of it.
| PAM | PAM Native | Ecosystem |
|---|---|---|
| the runtime and CLI | native Android and iOS apps in PHP | every official package and plugin |
Docs: push-in.github.io/pam-docs · Issues
MIT License. The reactive PHP component core, the binary wire protocol and the layout and diff engine started as a copy of PAM Native and remain under the Apache License 2.0; NOTICE lists the origin release and the directories that hold the copied code. The two projects do not depend on each other; fixes are ported between them by hand.
Made in Brazil by Pushin