PHP 8.5 first
PAM Native
PAM Native turns typed PHP components into real Android Views and UIKit controls. Rust owns validation, reconciliation, diffing, and layout; Kotlin and Swift apply compact mutation batches. There is no WebView, JavaScript runtime, or browser CSS engine.
Native by construction
One style compiler
Explainable speed
Start here
Section titled “Start here”-
Install PAM and verify the machine.
Terminal window curl --proto '=https' --proto-redir '=https' --tlsv1.2 \--connect-timeout 15 --max-time 60 --max-filesize 1048576 \-fsSL https://github.com/push-in/pam/releases/latest/download/install.sh | shpam doctor -
Create a complete mobile project. Android and iOS hosts come by default.
Terminal window pam init my-app --template nativecd my-apppam composer require pushinbr/pam-nativepam doctor --fix -
Launch it.
Terminal window pam dev# or: pam run android / pam run ios
Builds are project-clean by contract: PAM preserves declared APK/AAB/IPA/app outputs and evidence, then removes regenerable Gradle, Xcode, SwiftPM, Rust, and generated-host intermediates even when the command fails. Read the mandatory build hygiene contract for the exact retention boundary.
pam doctor --fix handles SDK licenses and installs required, checksum-verified runtime artifacts. Production builds do not require a local Rust toolchain.
The first run is a release contract
Section titled “The first run is a release contract”Every PAM and PAM Native release is blocked until CI creates a disposable
project with pam init --template mobile and successfully completes pam dev
on a clean Android emulator. The same release gate covers the official Native
UI starter and the server, HTTP, and Laravel templates. It verifies automatic
Composer/Gradle/SDK/NDK/runtime setup, installation, process liveness, Logcat,
and a captured frame. This is the exact public workflow, not a preassembled
fixture.
If PAM can safely repair a missing tool or license, it does so. If the host
cannot satisfy a requirement, pam doctor --fix reports the exact prerequisite
and verification command; publication remains blocked.
Native component, familiar syntax
Section titled “Native component, familiar syntax”<?phpdeclare(strict_types=1);
use Pam\Native\Attributes\Action;use Pam\Native\Attributes\Prop;
final class ProductCard{ public function __construct( #[Prop] public readonly Product $product, #[Prop] public bool $favorite = false, ) {}
#[Action] public function toggleFavorite(): void { $this->favorite = !$this->favorite; }}?>
<template language="2"> <Card class="product-card"> <Image :source="$product.cover" decorative="true" /> <Heading>{{ $product.name }}</Heading> <Button on:press="toggleFavorite">Favorite</Button> </Card></template>
<style scoped>@tokens { color.surface: #10131a; space.card: 20px; }
.product-card { gap: 12px; padding: var(--space-card); background: var(--color-surface); border-radius: 20px;}
.product-card > Button:pressed { opacity: 72%; transform: scale(0.98);}</style>Use {{ }} for text, :property="$path" for native properties, and p-model for two-way input/toggle binding. PHP attributes remain the typed prop/action contract.
Everything PAM Native gives you
Section titled “Everything PAM Native gives you”PAM Native is more than a renderer. It is a retained-native application platform: PHP describes typed intent, Rust validates and reconciles it, and Kotlin/Swift keep interaction, scrolling, media, animation, and platform work on the native side. The following catalog covers the complete supported surface.
Choose your syntax: tree or tags
Section titled “Choose your syntax: tree or tags”Every core visual component has two first-class authoring forms. The typed tree is ideal for builders, libraries, generated UI, and explicit refactoring. Tags are ideal for application screens and keep PHP state/actions beside a concise template. They compile to the same retained tree, native node kinds, properties, events, style IR, and performance path; mixing both forms is supported.
Layout and text
Section titled “Layout and text”use Pam\Native\Style;use Pam\Native\UI\{Column, Row, SafeAreaView, Screen, Text, View};
return Screen::make( SafeAreaView::make( Column::make( Text::make('Dashboard')->style(new Style(fontSize: 28)), Row::make( View::make(Text::make('Revenue'))->key('revenue'), View::make(Text::make('Orders'))->key('orders'), )->style(new Style(gap: 12)), )->style(new Style(flexGrow: 1, padding: 24, gap: 16)), ),);<Screen> <SafeAreaView> <Column class="flex-1 p-6 gap-4"> <Text fontSize="28">Dashboard</Text> <Row class="gap-3"> <View key="revenue"><Text>Revenue</Text></View> <View key="orders"><Text>Orders</Text></View> </Row> </Column> </SafeAreaView></Screen>Input, binding, buttons, and toggles
Section titled “Input, binding, buttons, and toggles”use Pam\Native\KeyboardType;use Pam\Native\UI\{Button, Column, Input, Toggle};
return Column::make( Input::make($this->email) ->placeholder('you@example.com') ->keyboard(KeyboardType::Email) ->onChange(fn (string $value) => $this->email = $value), Toggle::make($this->newsletter) ->onToggle(fn (bool $value) => $this->newsletter = $value), Button::make('Continue')->onPress(fn () => $this->submit()),);<Column> <Input p-model="$email" keyboardType="email" placeholder="you@example.com" /> <Toggle p-model="$newsletter" /> <Button on:press="submit">Continue</Button></Column>Images and cached media
Section titled “Images and cached media”use Pam\Native\ImageFit;use Pam\Native\MediaCachePolicy;use Pam\Native\UI\Image;
return Image::make($this->user->avatarUrl) ->fit(ImageFit::Cover) ->defaultSource('asset://avatar-placeholder.png') ->cache(MediaCachePolicy::StaleWhileRevalidate) ->cacheKey("avatar:{$this->user->id}") ->pinOffline() ->onError(fn ($event) => $this->report($event->error));<Image :source="$user->avatarUrl" fit="cover" defaultSource="asset://avatar-placeholder.png" cache="stale-while-revalidate" :cacheKey="'avatar:' . $user->id" pin-offline on:imageError="imageFailed"/>Recycled lists and rich cells
Section titled “Recycled lists and rich cells”use Pam\Native\UI\VirtualizedList;
return VirtualizedList::make( ...array_map( fn (Post $post) => PostCard::make($post)->key("post:{$post->id}"), $this->posts, ),) ->estimatedRowHeight(604) ->prefetch(6) ->onEndReached(fn () => $this->loadNextPage());<VirtualizedList estimatedRowHeight="604" prefetch="6" on:endReached="loadNextPage"> <PostCard p-for="$post in $posts" :key="'post:' . $post->id" :post="$post" /></VirtualizedList>Gestures and compositor motion
Section titled “Gestures and compositor motion”use Pam\Native\GestureDirection;use Pam\Native\GestureType;use Pam\Native\UI\GestureDetector;
return GestureDetector::make(GestureType::Pan, $card) ->direction(GestureDirection::Horizontal) ->minimumDistance(12) ->onUpdate(fn ($event) => $this->dragX = $event->translationX) ->onEnd(fn ($event) => $this->finishDrag($event->velocityX));<GestureDetector gestureType="pan" gestureDirection="horizontal" gestureMinDistance="12" on:gestureUpdate="drag" on:gestureEnd="finishDrag"> <Card :style="{ translationX: $dragX }" /></GestureDetector>Modals, sheets, and system UI
Section titled “Modals, sheets, and system UI”use App\UI\Filters;use Pam\Native\BottomSheetKeyboardBehavior;use Pam\Native\UI\BottomSheet;
return BottomSheet::make( Filters::make(), snapPoints: [0.35, 0.7, 1.0], index: $this->sheetIndex,) ->dismissible() ->keyboardBehavior(BottomSheetKeyboardBehavior::Interactive) ->onDismiss(fn () => $this->filtersOpen = false);<BottomSheet :snapPoints="[0.35, 0.7, 1.0]" :index="$sheetIndex" keyboardBehavior="interactive" on:sheetDismiss="closeFilters"> <Filters /></BottomSheet>Video and audio
Section titled “Video and audio”use Pam\Native\MediaCachePolicy;use Pam\Native\MediaType;use Pam\Native\UI\MediaPlayer;
return MediaPlayer::make($this->episodeUrl, MediaType::Video) ->controls() ->streamingCache() ->cache(MediaCachePolicy::Disk) ->onProgress(fn ($current, $duration) => $this->progress($current, $duration)) ->onEnd(fn () => $this->playNext());<Video :source="$episodeUrl" controls streaming-cache cache="disk" on:mediaProgress="progress" on:end="playNext"/>Controlled web content
Section titled “Controlled web content”use Pam\Native\UI\WebView;
return WebView::make('https://app.example.com/embedded') ->allowedHosts(['app.example.com']) ->javaScriptEnabled() ->onMessage(fn (string $json) => $this->handleMessage($json));<WebView source="https://app.example.com/embedded" allowedHosts="app.example.com" javaScriptEnabled on:message="handleMessage"/>Visual plugin surfaces
Section titled “Visual plugin surfaces”Official visual packages provide a high-level typed Renderable. Templates can
mount the same registered host view through the built-in CustomView tag. Keep
the typed wrapper when you want package enums and decoded events; use the tag
when the property map already belongs to declarative component state.
use Pam\Native\Camera\{CameraEventKind, CameraFacing, CameraMode, CameraView};
return CameraView::make() ->facing(CameraFacing::Back) ->mode(CameraMode::PhotoAndVideo) ->fps(60) ->pinchToZoom() ->onEvent(function ($event): void { if ($event->kind === CameraEventKind::PhotoCaptured) { $this->savePhoto($event->capture); } });// Typed state consumed by the template; enum values remain integers.public array $cameraProperties = [ 'active' => true, 'facing' => CameraFacing::Back->value, 'mode' => CameraMode::PhotoAndVideo->value, 'fps' => 60, 'pinchToZoom' => true,];<CustomView name="camera.preview" :properties="$cameraProperties" on:event="cameraEvent"/>The same tag boundary mounts media.camera, video.player, scanner.camera,
canvas.view, gpu.surface, three-d.scene, and maps.map. Their package
wrappers remain the preferred typed tree API because they validate limits and
decode native events before application code receives them.
Authoring and component model
Section titled “Authoring and component model”| Capability | What you can build | Complete reference |
|---|---|---|
| Three authoring styles | Typed PHP trees, class components with templates, or single-file .pam components |
Components |
| Vue-like templates | {{ expression }}, :prop, @event, on:event, p-model, conditionals, loops, slots, refs, and safe expressions |
Template syntax |
| Typed contracts | #[Prop], #[State], #[Action], #[Computed], #[Watch], #[Effect], #[Expose], lifecycle hooks, context, and error boundaries |
Component runtime |
| Retained rendering | Stable native identity, keyed reconciliation, compact mutation batches, and subtree invalidation | State and lifecycle |
| Visual DOM | Typed selectors, traversal, classList, attributes, dataset, inline/computed styles, atomic mutations, observers, focus, measurement, and motion |
Visual DOM |
| Scoped styling | Scoped/module/global styles, imports, cascade, selectors, variables, tokens, recipes, responsive queries, keyframes, and strict diagnostics | PAM Style Language |
| Responsive UI | Flex, native grid, twelve-column layouts, breakpoints, safe areas, fold posture, TV/remote input, and container queries | Responsive layout |
| Forms | Typed fields, validation attributes, touched/dirty state, server errors, submission state, drafts, reset, and p-model |
Forms and validation |
Native UI surface
Section titled “Native UI surface”These are retained Android Views and UIKit controls—not HTML elements painted in a WebView.
| Family | Included surface | Complete reference |
|---|---|---|
| Layout | Screen, View, rows, columns, grids, safe areas, spacers, wrapping, clipping, and custom chrome |
Layout and views |
| Text and input | Text, headings, rich text, packaged fonts, inputs, text areas, buttons, pressables, switches, checkboxes, radio controls, sliders, keyboard events, and accessories | Text, input, and controls |
| Images and drawing | Packaged/remote/authenticated images, resize modes, progressive loading, cache policy, prefetch, offline pinning, backgrounds, thumbnails, and drawing canvas | Images and cache |
| Scrolling and large data | Scroll views, recycled/virtualized lists, sections, grids, pagination, snapping, restoration, pull-to-refresh, and imperative jumps | Scroll and lists |
| Interaction and motion | Press feedback, taps, long press, pan, pinch, rotation, drag/drop, context menus, native-state selectors, and compositor animation | Interaction and motion |
| Overlays and system UI | Modals, bottom sheets, drawers, progress indicators, status/navigation bars, safe keyboard handling, and input accessories | Overlays and system UI |
| Audio and video | Native playback, controls, lifecycle events, streaming cache, bounded downloads, and offline pinning | Video and audio |
| Web content | Host-allowlisted WebView, bounded JavaScript injection, inline media, navigation policy, and native message bridge | WebView |
| Design system | Retained-native Material 3 components, themes, typed facades, directives, accessibility, and Android/iOS parity | PAM Native UI · complete component catalog |
| App-owned controls | Register application-owned Android Views and generated custom views without leaving the retained tree | Custom native views |
Application architecture
Section titled “Application architecture”| Capability | Included surface | Complete reference |
|---|---|---|
| Local and scoped state | Typed local state, computed values, effects, watchers, context, persistence, memoization, and render control | State and lifecycle |
| Global store | Vuex-style actions, selectors, computed values, transactions, persistence/migrations, optimistic updates, undo, middleware, replicas, and DevTools | Global store |
| Navigation | Named stacks, tabs, top tabs, drawers, nested navigators, typed parameters, groups, deep links, notifications, shared content, persistence, transitions, shared elements, and predictive back | Navigation |
| Networking | Bounded GET/POST/PUT/PATCH/DELETE and JSON requests, typed responses, headers, cancellation, timeouts, and explicit transport failures | HTTP networking |
| Files and galleries | File, image, video, audio, and filtered mixed-gallery pickers | Files and media picker |
| Platform runtime | Typed IDL bridge, priority lanes, async work, native worklets, virtualization, background jobs, offline sync, Canvas, and bounded server-driven UI | Platform runtime |
| Device capabilities | Permissions, contacts, location, recording, files, links, notifications, background work, SQLite, sensors, and device state | Platform capabilities |
Official capability packages
Section titled “Official capability packages”Install only what an application needs. Every package below is independently versioned, usable without a bundle such as “feed” or “social”, and talks to PAM Native through the same typed plugin contract.
pam composer require pushinbr/pam-native-camera# Replace camera with any capability listed below.Camera, media, graphics, and immersive UI
Section titled “Camera, media, graphics, and immersive UI”| Package | Capability | Reference |
|---|---|---|
pushinbr/pam-native-camera |
Low-latency professional capture, devices, formats, focus, exposure, zoom, flash/torch, frame processors, photo, and video | Camera |
pushinbr/pam-native-media |
Sandboxed media probing, correctly oriented thumbnails, and lifecycle-aware photo/video capture | Media |
pushinbr/pam-native-video |
Adaptive HLS/DASH and local playback with Media3/AVPlayer, tracks, controls, seek, and progress | Video |
pushinbr/pam-native-media-editor |
Typed photo/video timelines, transforms, filters, audio, composition, progress, and native export | Media Editor |
pushinbr/pam-native-scanner |
Realtime QR/barcode scanning through CameraX/ML Kit and AVFoundation/Vision | Scanner |
pushinbr/pam-native-canvas |
Retained-mode native 2D scene graphs with bounded PHP commands | Canvas |
pushinbr/pam-native-gpu |
Programmable OpenGL ES 3 and Metal fragment rendering without a JavaScript bridge | GPU |
pushinbr/pam-native-3d |
GLB and USDZ scenes through Filament and RealityKit | 3D |
Device, proximity, health, and system surfaces
Section titled “Device, proximity, health, and system surfaces”| Package | Capability | Reference |
|---|---|---|
pushinbr/pam-native-bluetooth |
BLE scan, connect, discovery, read, write, subscribe, opaque IDs, and lifecycle-safe events | Bluetooth |
pushinbr/pam-native-nfc |
Bounded NDEF read/write with Android reader mode and iOS system sessions | NFC |
pushinbr/pam-native-health |
Health Connect/HealthKit permissions and typed steps, heart rate, weight, calories, and sleep | Health |
pushinbr/pam-native-maps |
Google Maps/MapKit camera, styles, user location, gestures, markers, overlays, and events | Maps |
pushinbr/pam-native-intents |
Android Dynamic Shortcuts and Apple App Intents mapped to named PAM routes | Intents |
pushinbr/pam-native-live-activities |
ActivityKit Live Activities and Android ongoing notifications | Live Activities |
pushinbr/pam-native-widgets |
Android App Widgets and WidgetKit timelines with stable IDs and deep links | Widgets |
pushinbr/pam-native-share-extension |
Text, URL, and sandboxed-file intake from Android shares and iOS Share Extensions | Share Extension |
Identity, commerce, cloud, and realtime
Section titled “Identity, commerce, cloud, and realtime”| Package | Capability | Reference |
|---|---|---|
pushinbr/pam-native-auth |
Keystore/Keychain encrypted credentials and OAuth 2.1 PKCE material | Auth |
pushinbr/pam-native-payments |
Stripe PaymentSheet, native wallets, and SCA/3DS with server-owned secrets | Payments |
pushinbr/pam-native-subscriptions |
StoreKit 2 and Play Billing products, purchase, restore, verification, acknowledgement, and entitlement safety | Subscriptions |
pushinbr/pam-native-firebase |
Firebase apps, Analytics, Remote Config, Messaging tokens, Installations, Crashlytics, and flag adapters | Firebase |
pushinbr/pam-native-realtime |
Native-owned RFC 6455 WebSockets that survive PHP renders/reloads with bounded queues | Realtime |
pushinbr/pam-native-background-transfer |
OS-scheduled durable HTTPS upload/download with constraints, progress, and relaunch recovery | Background Transfer |
Offline data, delivery, quality, and operations
Section titled “Offline data, delivery, quality, and operations”| Package | Capability | Reference |
|---|---|---|
pushinbr/pam-native-nitro |
Model-driven, offline-first data flows on native SQLite workers | Nitro |
pushinbr/pam-native-sync |
Idempotent outbox, ordered batches, cursors, tombstones, retries, and deterministic conflicts | Sync |
pushinbr/pam-native-sync-laravel |
Authenticated Laravel push/pull API with signed cursors, idempotency, conflicts, and retention | Laravel Sync |
pushinbr/pam-native-feature-flags |
Typed targeting, deterministic rollouts, overrides, exposure events, and offline snapshots | Feature Flags |
pushinbr/pam-native-observability |
Vendor-neutral traces, logs, metrics, crash context, sampling, batching, and exporters | Observability |
pushinbr/pam-native-devtools |
Redacted snapshots, performance measures, errors, network recording, and deterministic diagnostics | DevTools package |
pushinbr/pam-native-testing |
Strict deterministic native-module fakes, deferred responses, recorded calls, and completion assertions | Testing |
pushinbr/pam-native-plugin-kit |
Package scaffolding, manifest validation, and IDL generation for PHP, Kotlin, and Swift | Plugin Kit |
Tooling and development experience
Section titled “Tooling and development experience”| Capability | What it does | Complete reference |
|---|---|---|
| One project console | pam init, contextual Composer, pam dev, pam run android, pam run ios, tests, diagnostics, builds, and releases |
CLI and project console |
| Zero-setup doctor | Detects and safely repairs PHP, Composer, Android SDK/NDK/licenses, Gradle, runtime artifacts, and project requirements | Start here |
| Hot reload | Atomic PHP source reload without frozen UI, stale processes, or duplicate server bindings | Hot reload |
| Editor intelligence | Formatting, completion, hover, diagnostics, go-to-definition, and navigation for .pam in LSP editors |
Editor setup |
| Runtime DevTools | FPS, render/commit cost, native nodes, batches, heap, and device profiling | DevTools |
| Style diagnostics | Strict compiler, source maps, compatibility/render-cost reports, token generation, and machine-readable manifests | Inspect and explain |
| Production certification | Tests source/protocol, PHP 8.5, Rust, UIKit, Android API 26/36, official packages, clean starters, artifacts, and checksums | Platform and verification |
| Automatic cleanup | Preserves declared products/evidence and removes regenerable Gradle, Xcode, SwiftPM, Rust, and host intermediates | Build hygiene |
Extension and compatibility boundaries
Section titled “Extension and compatibility boundaries”| Surface | Contract | Complete reference |
|---|---|---|
| Composer-first plugins | PHP components plus Android modules/views/resources/AAR/JNI/Maven and Swift packages through one manifest | Plugin SDK |
| Typed cross-platform IDL | One bounded schema generates deterministic PHP, Kotlin, and Swift contracts | Plugin Kit |
| Wire protocol | Versioned PNT1/PNP1 frames, compatibility negotiation, hard bounds, and fail-closed validation | Protocol and limits |
| Public PHP surface | Namespace-by-namespace index of runtime, rendering, state, navigation, capabilities, bridge, and style APIs | PHP API index |
| Android | Real Views, API 26–36 contract, generated Gradle host, emulator/device testing, APK and AAB | Components |
| iOS | UIKit controls, generated Xcode host, extensions, simulator/device diagnostics, signed IPA | iOS runtime and host |
PAM Style Language 1.0
Section titled “PAM Style Language 1.0”PAM accepts familiar CSS spelling and compiles it into versioned PAMS bytecode and typed IR. Unsupported syntax is a build error—not a silent guess.
The compiler emits stable property IDs, scope ownership, cascade winners, query ASTs, granular invalidation dependencies, source maps, compatibility/render-cost data, UI-thread keyframes, and typed PHP/Kotlin/Swift token APIs.
Scope and imports
Section titled “Scope and imports”<style scoped>/* default: this component subtree */</style><style module>/* stable hashed module scope */</style><style global>/* application design system */</style>@import accepts relative .css files inside the Composer project root. Imports are cycle checked, depth limited, and size capped.
Selectors and cascade
Section titled “Selectors and cascade”| Feature | Syntax | Contract |
|---|---|---|
| Basic | Button, *, .card, #checkout |
Compiled matcher; no runtime parsing |
| Compound | Button.primary[disabled] |
All terms match one native node |
| Relationship | .screen .title, .toolbar > Button |
Descendant and direct child |
| Attributes | [role], [type="email"], ~=, ` |
=, ^=, $=, *=` |
| Lists | .title, .subtitle |
Independent cascade entries |
| States | :pressed, :focus, :focus-visible, :hover, :disabled, :checked, :selected, :active, :loading, :error, :empty |
See the exact state contract below |
| Priority | specificity, source order, !important |
Deterministic per-property winner |
| Layers | @layer components { … } |
Declared layer order |
Inherited text properties are color, font family/size/style/weight, letter spacing, line height, alignment, decoration, and transformation. Geometry never inherits accidentally.
State selectors without a PHP round trip
Section titled “State selectors without a PHP round trip”:pressed, :focus, :focus-visible, and :hover lower to a compact native state map. Opacity, scale, translation, background color, text color, and border color are applied by Android Views or UIKit; PHP is not called between pointer/focus frames. :disabled, :checked, :selected, :active, :loading, :error, and :empty are reconciled from typed component properties. :focus-visible follows the native focus system rather than browser keyboard heuristics.
Touch devices may never enter :hover. Android mouse/stylus/TV pointer events and the iOS pointer interaction do. Always keep the unqualified rule usable.
Units, functions, variables, environment
Section titled “Units, functions, variables, environment”| Family | Supported |
|---|---|
| Native/absolute | number, px, dp, sp, pt |
| Relative | %, rem, vw, vh, vmin, vmax |
| Math | calc(), min(), max(), clamp(), +, -, *, / |
| Variables | --token, var(--token), fallback values |
| Environment | env(safe-area-inset-top), -right, -bottom, -left |
Expressions compile once to a typed tree. Only nodes depending on a changed variable, state, container, viewport, theme, or environment value invalidate.
Application variables can change without recompiling unrelated rules:
use Pam\Native\Style\StyleVariables;
StyleVariables::set('space-card', '24dp');StyleVariables::set('color-surface', '#10131a');Only declarations containing the changed var() binding are recompiled. A revision change requests one reconciler render; unchanged declarations keep their compiled representation.
Complete property surface
Section titled “Complete property surface”| Group | Properties and shorthands |
|---|---|
| Size | width, height, min-width, min-height, max-width, max-height, aspect-ratio |
| Spacing | padding, padding-{top,right,bottom,left}, padding-inline, padding-block, the same margin forms, gap, row-gap, column-gap |
| Flex | display: flex, flex, flex-grow, flex-shrink, flex-direction, flex-wrap, align-items, align-self, justify-content |
| Grid | display: grid, grid-template-columns, grid-column: span N, place-items; 1–64 tracks |
| Position | `position: relative |
| Surface | background, background-color, opacity, elevation, box-shadow |
| Border | border, border-{top,right,bottom,left}, per-edge width/color, `border-style: solid |
| Text | color, font family/size/style/weight, letter spacing, line height, align, decoration, transform |
| Image | `object-fit: contain |
| Transform | transform with translateX, translateY, scale, scaleX, scaleY, rotate; direct translation-x and translation-y |
| Visibility | `display: flex |
| Native colors | -pam-native-background-color, -pam-native-text-color, -pam-native-border-color |
Grid is native, not nested-view emulation. repeat(N, …) or explicit fr, auto, intrinsic, and minmax() tracks choose the column count; children use grid-column: span N.
@font-face accepts safe packaged asset:// TTF/OTF files, weights 100–900, and normal/italic faces.
All dimensions use native border-box geometry; box-sizing: border-box is accepted as an explicit assertion. content-box, floats, fixed/sticky positioning, subgrid, multiple/inset shadows, gradients, filters, CSS transitions, and browser-generated content are rejected. They are not silently approximated.
Android resources and iOS named colors
Section titled “Android resources and iOS named colors”.surface { background: #10131a; /* portable fallback */ -pam-native-background-color: colorSurface; -pam-native-text-color: labelPrimary; -pam-native-border-color: colorAccent;}On Android each name resolves from the application package’s R.color; night-qualified and theme-aware resources therefore follow the current configuration. On iOS the same name resolves with UIColor(named:in:compatibleWith:), including light/dark and high-contrast Asset Catalog variants. If a named resource is unavailable, keep a portable color declaration as the cross-platform fallback.
Responsive native queries
Section titled “Responsive native queries”@media (width >= 840dp) {}@media (orientation: landscape) {}@media (prefers-color-scheme: dark) {}@media (prefers-reduced-motion: reduce) {}@media (pointer: coarse) {}@media (device-type: tv) {}@media (refresh-rate >= 90) {}@media (dynamic-range: high) {}@media (display-mode: standalone) {}@media (fold-posture: half-opened) {}@media (input-mode: remote) {}@media (memory-class >= 256) {}@media (performance-tier >= 2) {}
@container player (width >= 560dp) { .controls { grid-template-columns: repeat(6, 1fr); }}Legacy min/max-width and min/max-height spelling remains valid. Media queries observe the native window; container queries observe the nearest measured container. Kinds, operators, and features are stable sequential integer enums in the public IR.
Tokens and recipes
Section titled “Tokens and recipes”@tokens { color.brand: #7c5cff; radius.card: 20px; space.md: 16px; }
@recipe button { base { padding: 12px 18px; border-radius: var(--radius-card); } variant tone=primary { background: var(--color-brand); color: white; } variant tone=quiet { background: transparent; color: var(--color-brand); }}<Button recipe="button" variant:tone="primary">Continue</Button>Generate identical token constants for app PHP and custom native modules:
pam style tokens resources/styles/tokens.css generated/style# Tokens.php · Tokens.kt · Tokens.swiftUI-thread animation
Section titled “UI-thread animation”@keyframes enter { from { opacity: 0; transform: translateY(12px) scale(0.98); } to { opacity: 1; transform: translateY(0) scale(1); }}Opacity, translation, scale, and rotation keyframes are compile-time validated and played by Android/iOS compositor APIs. PHP is not consulted between frames. Reduced-motion queries can replace motion declaratively.
Utilities use the same engine
Section titled “Utilities use the same engine”PAM utility classes are optional compiler input, not a JavaScript dependency. Utilities, recipes, component CSS, and typed styles lower to the same IR, cascade, property IDs, invalidation graph, and cost diagnostics.
The built-in, versioned utility grammar is deliberately small:
| Family | Syntax |
|---|---|
| Layout | flex-1, w-full, h-full, items-start, items-center, items-end, items-stretch, items-baseline |
| Color | bg-white, bg-black, text-white, text-black |
| Spacing/surface | p-N, px-N, py-N, m-N, mx-N, my-N, gap-N, rounded-N, elevation-N; N × 4dp |
| Composition | opacity-0 through opacity-100 |
| Grid | grid-N, col-N, col-{sm,md,lg,xl}-N, responsive offset-*, order-*, gutter-x-N, gutter-y-N |
PAM does not claim the complete Tailwind browser catalog. Unknown utilities are ignored as ordinary component class names; supported utility grammar is visible in pam style manifest and produces the same PAMS IR as an equivalent CSS declaration.
Inspect and explain
Section titled “Inspect and explain”pam style inspect resources/styles/app.csspam style manifestinspect reports strict validity, fingerprint, rule/query/keyframe counts, invalidation dependencies, source map, compatibility, and render cost. manifest prints the machine-readable property catalog used by tooling.
Strict mode rejects unknown properties, invalid values/units, unsafe imports, malformed selectors, circular variables, invalid keyframes, and ambiguous grid tracks with an actionable source location.
Performance contract
Section titled “Performance contract”| Cost | Examples | Behavior |
|---|---|---|
| Compose | opacity, transform, z-order | UI-thread/compositor; ideal for 60/90/120 Hz |
| Paint | colors, border, shadow | Redraws without relayout |
| Layout | dimensions, spacing, flex/grid, typography | Smallest affected subtree only |
Production rendering consumes fingerprinted IR/bytecode; it does not parse CSS strings per frame.
Platform and verification boundary
Section titled “Platform and verification boundary”| Requirement | Contract |
|---|---|
| PHP | 8.5.x default |
| Android | API 26–36, emulator and physical devices |
| iOS | UIKit host, simulator, signed IPA, device diagnostics |
| Protocol | PNT1/PNP1 v1; PAMS Style IR v1 |
| Target | Native Views/UIKit, never WebView |
The shared surface includes layout, text, images, inputs, pressables, scrolling/recycled lists, grid, modals, bottom sheets, status/safe-area/keyboard behavior, refresh, gestures, animation, media, storage, HTTP, system APIs, accessibility, and generated custom views.
pam format --check resourcespam style inspect resources/styles/app.csspam doctorpam testpam production:certifypam releaseUse the editor setup for completion, hover, diagnostics, formatting, and navigation.