PHP-Controllable macOS Metal + AppKit window, menu, texture, input, and drawing extension

Maintainers

Package info

github.com/php-io-extensions/metal

Language:C

Type:php-ext

Ext name:ext-metal

pkg:composer/php-io-extensions/metal

Transparency log

Statistics

Installs: 7

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

0.7.3 2026-08-09 21:52 UTC

This package is auto-updated.

Last update: 2026-08-09 21:52:36 UTC


README

PHP Metal Built with Zephir Platform License: MIT

PHP extension for Apple Metal + AppKit — built with Zephir, installable via PHP PIE.

metal is a standalone macOS-only binding: open an NSWindow, install a macOS menu bar, draw through a CAMetalLayer with Metal, create offscreen MTLTexture targets (0.7.1+) for headless engines/UIs, and blit those textures into a live window (Window::presentTexture, 0.7.2+). It has no knowledge of other windowing libraries.

PHP API is namespaced under Metal\MTL\… as static classes. Opaque native handles are int values.

Requirements

Component Minimum version Notes
PHP 8.2 ZTS and NTS
OS macOS arm64 + x86_64 (PIE os-families: darwin)
Frameworks system Metal, AppKit, QuartzCore, Foundation
Compiler Apple Clang Objective-C ARC
php-dev / phpize matches PHP Required for non-PIE builds

Installation

Via PHP PIE (recommended)

pie install php-io-extensions/metal

macOS only — configure fails on other platforms.

Platform installer

bash install-macos.sh

Laravel Herd:

bash install-macos-herd.sh

Manual build (maintainers)

bash scripts/prepare-ext.sh
cd ext && phpize && ./configure --enable-metal && make -j1
php -n -d extension=modules/metal.so --ri metal

scripts/prepare-ext.sh regenerates Zephir C, syncs src/ into ext/src/, patches config.m4, installs Makefile.frag for .m sources, and strips phpize junk so the committed ext/ tree stays PIE-ready.

Use make -j1 (or the installer). Parallel make is fine for .c objects; the ObjC fragment is conservative.

Quick start

use Metal\MTL\App;
use Metal\MTL\Device;
use Metal\MTL\Menu;
use Metal\MTL\Window;

App::init();
Menu::installDefault('My App');
Menu::addItem('Demo', 'Quit Demo', 'q', 'quit');

$window = Window::create('Metal', 800, 600);
$device = Device::createSystemDefault();
Window::attachDevice($window, $device);

while (!Window::shouldClose($window) && !App::shouldQuit()) {
    App::poll();
    if (Menu::pollAction() === 'quit') {
        break;
    }
    Window::clear($window, 30, 30, 40, 255);
    usleep(16_000);
}

Window::destroy($window);
Device::release($device);

Demo:

php -d extension=./ext/modules/metal.so examples/proof_window.php
# optional smoke: METAL_DEMO_MAX_FRAMES=90 php -d extension=./ext/modules/metal.so examples/proof_window.php

API surface (0.7)

Class Role
Metal\MTL\App NSApplication init / poll / quit
Metal\MTL\Window NSWindow + CAMetalLayer clear/present
Metal\MTL\Menu Menu bar + custom items / Quit
Metal\MTL\Device MTLDevice / command queue handles

License

MIT — see LICENSE.