From 77268b4589abded72f50a30fdb6bd302104ee326 Mon Sep 17 00:00:00 2001 From: Shane Rosenthal Date: Wed, 2 Sep 2026 21:18:48 -0400 Subject: [PATCH 1/3] Mobile v4 docs: tighten SuperNative introduction copy Rewrite the SuperNative Introduction page to read more plainly: replace em dashes with commas and periods, turn the bold-header bullet lists in "How it works" and "Why SuperNative?" into prose, drop hype wording like "blistering speeds" and "fully leverage", match the plugin heading to the sentence case used elsewhere on the page, and fix a typo in the web view opt-out section. No technical claims were added or removed. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_0112bxu7tWLuSwy1NLdV3xwA --- .../mobile/4/architecture/super-native.md | 117 +++++++++--------- 1 file changed, 57 insertions(+), 60 deletions(-) diff --git a/resources/views/docs/mobile/4/architecture/super-native.md b/resources/views/docs/mobile/4/architecture/super-native.md index 0b622f5b7..cb0b0b893 100644 --- a/resources/views/docs/mobile/4/architecture/super-native.md +++ b/resources/views/docs/mobile/4/architecture/super-native.md @@ -5,50 +5,47 @@ order: 5 ## What is SuperNative? -SuperNative is our name for a combination of technologies that enable PHP to produce platform-native UI at -blistering speeds. +SuperNative is our name for the set of technologies that let PHP produce platform-native UI. Your Blade +templates become SwiftUI views on iOS and Jetpack Compose views on Android, built and updated directly by +your PHP code. -While SuperNative uses HTML-like syntax, **there is no need for a web view**. Your apps built with Blade -can fully leverage the native components and performance of each platform's UI tools, directly from PHP — SwiftUI -on iOS and Jetpack Compose on Android. +The syntax looks like HTML, but **there is no web view**. Each screen is a real, platform-native view. +Same Laravel app, same Blade templates, two native UIs. -Your app's screens are not web views rendering HTML. They are real, platform-native views, built and -updated by your PHP code. Same Laravel app, same Blade templates, two genuine native UIs. +You write EDGE components once. There is no separate syntax for Android and iOS. -You don't need to think about the right syntax for Android vs iOS, just use EDGE. - -SuperNative is **the default**. New apps render native screens from the very first route — no configuration -required. +SuperNative is **the default**. New apps render native screens from the very first route, with no +configuration required. ## What SuperNative is not -SuperNative is not a fully custom renderer, like Skia or Impeller. It does not attempt to create pixel-perfect -cross-platform user interfaces. Instead it *embraces* the differences and simply smooths over them with a single -consistent syntax. +SuperNative is not a custom renderer like Skia or Impeller, and it does not try to draw pixel-identical +interfaces on both platforms. Each platform keeps its own look and behaviour. SuperNative gives you one +syntax for describing a screen and lets SwiftUI and Compose render it their own way. -It's not another virtual machine on top of or adjacent to PHP trying to convert *all* instructions to/from native -equivalents. It's explicitly focused on turning PHP objects that conform to a known interface into a fixed-length -byte array that can be processed by an explicit native-side interpreter. +It is not a virtual machine that translates every PHP instruction into a native equivalent. Its job is +narrower: take PHP objects that conform to a known interface and turn them into a fixed-length byte array +that a native-side interpreter can read. -Neither is it a transpiler or HTML-to-native converter. We've built our own Blade engine that converts real Blade -components into a simple binary representation instead of HTML ([The Renderer](renderer)). This gets passed immediately -to the native shell — no other serialization, no bridge function calls — and Swift and Kotlin can pick it up and parse -it immediately into a native UI tree. +It is not a transpiler or an HTML-to-native converter either. We built our own Blade engine, +[The Renderer](renderer), that compiles real Blade components into a simple binary representation instead +of HTML. That representation goes straight to the native shell with no further serialization and no bridge +function calls, and Swift or Kotlin parse it into a native UI tree. ## Try it now The fastest way to see SuperNative is to run the demo app, [`nativephp/super-native`](https://github.com/nativephp/super-native), on a simulator or device. -You'll need a working NativePHP for Mobile [development environment](../getting-started/environment-setup) first -(Xcode for iOS, Android Studio for Android). Then clone the demo, install it, and run it: +You'll need a working NativePHP for Mobile [development environment](../getting-started/environment-setup) +first (Xcode for iOS, Android Studio for Android). Then clone the demo, install it, and run it: ```shell git clone https://github.com/nativephp/super-native @@ -58,52 +55,54 @@ php artisan native:install php artisan native:run ``` -`native:run` builds the app and launches it on your connected device or simulator. Explore the source to see how -the screens are built, then start swapping in your own. +`native:run` builds the app and launches it on your connected device or simulator. Explore the source to +see how the screens are built, then start swapping in your own. ## How it works -SuperNative builds on three ideas working together: +SuperNative rests on three ideas. + +The native layer and your PHP application share memory directly. There is no network round-trip and no +web view bridge in between, so a state change in PHP reaches the native UI almost instantly. + +Each screen is driven by a PHP component class that holds its state and behaviour, much like a Livewire +component. User interactions call your methods, your properties update, and the UI re-renders to match. -- **Shared memory with PHP** — the native layer and your PHP application share memory directly, so there's no - network round-trip, no serialization overhead, and no waiting on a web view bridge. State changes flow between - PHP and the native UI almost instantly. -- **Livewire-like components** — each screen is driven by a PHP component class that holds its state and behavior, - just like a Livewire component. User interactions call your methods, your properties update, and the UI - re-renders to match. -- **Blade components for DX** — you define your UI with the same [EDGE component](../edge-components/introduction) - syntax you already know. Familiar, expressive Blade templates compile down to native SwiftUI and Compose views. +You describe the UI with the [EDGE component](../edge-components/introduction) syntax you already know +from Blade. Those templates compile to SwiftUI and Compose views. If you've built anything with Livewire, you already know how to build with SuperNative. -For a look under the hood — how Blade becomes SwiftUI and Compose, how state flows across the shared-memory -boundary, and the threading model behind it — see the rest of the [Architecture](about-the-new-architecture) section. +The rest of the [Architecture](about-the-new-architecture) section covers how Blade becomes SwiftUI and +Compose, how state crosses the shared-memory boundary, and the threading model behind it. ## Why SuperNative? -Two reasons above all: +Two reasons above all. -- **Performance** — native views render and animate at full platform speed. No web view startup cost, no DOM, no - JavaScript bridge. Scrolling, transitions and gestures feel exactly the way users expect because they're powered - by the same UI frameworks every other native app uses. -- **Accessibility** — SwiftUI and Jetpack Compose come with the platform's accessibility support built in. - Screen readers, dynamic type, contrast settings and assistive controls work with your app out of the box, - rather than being approximated through a browser. +Performance. Native views render and animate at full platform speed. There is no web view to start up and +no JavaScript bridge to cross. Scrolling and transitions feel the way users expect because the same UI +frameworks every other native app uses are doing the work. + +Accessibility. SwiftUI and Jetpack Compose ship with the platform's accessibility support. Screen readers, +dynamic type, contrast settings and assistive controls work with your app out of the box instead of being +approximated through a browser. There's more detail [in this blog article](/blog/supernative). ## Is the web view still an option? -Yes, but instead of being the default, it's now a component that you add to a native view. To make your app behave -the same way that NativePHP for Mobile versions before v4 did, you can do something like this: +Yes. It is no longer the default, but it is available as a component you add to a native view. To make +your app behave the way NativePHP for Mobile did before v4: ```php // routes/mobile.php @@ -116,17 +115,15 @@ Route::native('/home', WebViewScreen::class); Route::view('/', 'welcome'); ``` -Then just set `NATIVEPHP_START_URL=/home` in your `.env`. - -This way your existing web view-based app can keep on working and you can start adopt SuperNative one screen at a time -whenever you're ready — or not at all. +Then set `NATIVEPHP_START_URL=/home` in your `.env`. -## For Plugin Developers +Your existing web view app keeps working, and you can adopt SuperNative one screen at a time whenever +you're ready, or never. -SuperNative contains **no breaking changes** to our plugin architecture. +## For plugin developers -It actually expands what your plugins are capable of by giving you a standardized target for UI elements. That means your -plugins can ship fully native EDGE components that you know will work consistently for developers using your plugin. +SuperNative introduces **no breaking changes** to the plugin architecture. -No need to make your plugins UI-less abstractions or support multiple flavors of front-end tooling; simply create and ship -EDGE components and every consumer of your plugin will see the UI you intended. +It gives your plugin a standard target for UI. Your plugin can ship native EDGE components and know they +will render the same way for every developer who installs it. You no longer have to keep plugins UI-less +or support several front-end toolchains. From 7fce3c1e097769936c69e0257899fdd7e0b73a8a Mon Sep 17 00:00:00 2001 From: Shane Rosenthal Date: Thu, 3 Sep 2026 14:37:56 -0400 Subject: [PATCH 2/3] Mobile v4 docs: tighten copy across the rest of the Architecture section Apply the same copy pass to the remaining eight Architecture pages: replace em dashes with commas, periods and parentheses, turn bold-header bullet lists into prose or subheadings, trim forced triplets and negate-then-assert phrasing, and drop hype wording. All linked heading anchors are preserved. No technical claims were added or removed. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_0112bxu7tWLuSwy1NLdV3xwA --- .../about-the-new-architecture.md | 65 ++++++++------- .../cross-platform-implementation.md | 31 ++++--- .../mobile/4/architecture/embedded-php.md | 28 +++---- .../docs/mobile/4/architecture/glossary.md | 20 ++--- .../4/architecture/render-publish-mount.md | 32 ++++---- .../docs/mobile/4/architecture/renderer.md | 80 +++++++++---------- .../mobile/4/architecture/subtree-reuse.md | 44 +++++----- .../mobile/4/architecture/threading-model.md | 58 ++++++++------ 8 files changed, 182 insertions(+), 176 deletions(-) diff --git a/resources/views/docs/mobile/4/architecture/about-the-new-architecture.md b/resources/views/docs/mobile/4/architecture/about-the-new-architecture.md index 79708bac5..b0e9a1dd9 100644 --- a/resources/views/docs/mobile/4/architecture/about-the-new-architecture.md +++ b/resources/views/docs/mobile/4/architecture/about-the-new-architecture.md @@ -3,73 +3,72 @@ title: About the New Architecture order: 10 --- -NativePHP for Mobile runs your Laravel app on the device itself — no server, no network round-trip. Traditionally, -your app's UI rendered as HTML inside a web view. That model is productive and familiar, and it's +NativePHP for Mobile runs your Laravel app on the device itself. There is no server and no network round-trip. +Until now, your app's UI rendered as HTML inside a web view. That model is productive and familiar, and it's [still fully supported](../architecture/super-native#is-the-web-view-still-an-option). But it puts a browser between -your app and the platform, and some things can only feel truly native when they *are* native. +your app and the platform, and some things only feel native when they *are* native. -The new architecture — [SuperNative](../architecture/super-native) — removes that layer entirely. Your screens are -real SwiftUI and Jetpack Compose views, created and updated directly by your PHP code. Here's why we built it, and -what it changes. +The new architecture, [SuperNative](../architecture/super-native), removes that layer. Your screens are real SwiftUI +and Jetpack Compose views, created and updated directly by your PHP code. Here's why we built it and what it +changes. ## Why a new architecture? ### Truly native rendering A web view is a remarkable piece of engineering, but users can tell. Scroll physics, text rendering, transitions, -context menus, dark mode, dynamic type, screen readers — every one of these is approximated in a browser and -effortless in the platform's own UI framework. +context menus, dark mode, dynamic type, screen readers. Every one of these is approximated in a browser and comes +for free in the platform's own UI framework. -With the new architecture, an EDGE component like `` isn't a styled `
` — it's the same button -every other native app on that device uses. Accessibility, theming and platform conventions come along for free, +With the new architecture, an EDGE component like `` is the same button every other native app on +that device uses, rather than a styled `
`. Accessibility, theming and platform conventions come along with it, because there's nothing between your UI and the operating system. -### Shared memory, not serialization +### Shared memory instead of serialization -Frameworks that drive native UI from another language usually pay a toll at the border: state gets serialized to -JSON, shipped across a bridge, and parsed on the other side — for every update. +Frameworks that drive native UI from another language usually pay a toll at the border. State gets serialized to +JSON, shipped across a bridge, and parsed on the other side, on every update. NativePHP doesn't have that border. Your PHP runtime is [embedded inside the app process](embedded-php), and the rendering layer communicates through **shared memory**. When your component re-renders, PHP writes a compact binary -description of the screen directly into a buffer the native side reads from — no JSON, no sockets, no copies across -a bridge. The native layer walks your PHP data structures directly, in the same process, in native code. +description of the screen directly into a buffer the native side reads from. There is no JSON and no bridge to +cross. The native layer walks your PHP data structures directly, in the same process, in native code. -The result: a state change in PHP reaches the screen in well under a frame. +A state change in PHP reaches the screen in well under a frame. ### Native-speed interaction -Some things should never wait for application code — a drag should track your finger, an animation should never -drop a frame. The new architecture has a dedicated lane for these: -SharedValues live on the native side and are updated on the UI thread by gestures and animations at the display's -full frame rate. PHP holds a handle and hears about the outcome; the -per-frame work never crosses into PHP at all. +Some things should never wait for application code. A drag should track your finger, and an animation should never +drop a frame. The new architecture has a dedicated lane for these. SharedValues live on the native side and are +updated on the UI thread by gestures and animations at the display's full frame rate. PHP holds a handle and hears +about the outcome. The per-frame work never crosses into PHP at all. -You get Reanimated-style, gesture-driven motion — written in Blade. +You get Reanimated-style, gesture-driven motion, written in Blade. ## What can you expect? -Practically, the same development experience you already have, with a different result on screen: +Practically, the same development experience you already have, with a different result on screen. -- **Same Laravel app.** Routes, controllers, Eloquent, validation, queues — nothing about your backend changes. - Screens are registered with `Route::native()` and driven by PHP component classes, Livewire-style. -- **Same Blade.** You compose screens from [EDGE components](../edge-components/introduction) — declarative Blade - tags with Tailwind-style utility classes — and the framework turns them into SwiftUI and Compose. -- **Native output.** Navigation stacks, tab bars, sheets, lists and gestures are the platform's own, in light and +- Your Laravel app stays the same. Routes, controllers, Eloquent, validation and queues are untouched. Screens are + registered with `Route::native()` and driven by PHP component classes, Livewire-style. +- Your Blade stays the same. You compose screens from [EDGE components](../edge-components/introduction), + declarative Blade tags with Tailwind-style utility classes, and the framework turns them into SwiftUI and Compose. +- The output is native. Navigation stacks, tab bars, sheets, lists and gestures are the platform's own, in light and dark mode, with the platform's accessibility support built in. -- **Adopt at your pace.** The web view is still available as a component, so you can go all-native, all-web, or +- You adopt at your own pace. The web view is still available as a component, so you can go all-native, all-web, or migrate screen by screen. ## Should you use it today? -SuperNative is **the default**: new apps render native screens from the very first route. It's in beta, so -expect rapid iteration — and if you'd rather wait, [opting out](../architecture/super-native#is-the-web-view-still-an-option) -is one route and one component. +SuperNative is **the default**. New apps render native screens from the very first route. It's in beta, so expect +rapid iteration. If you'd rather wait, +[opting out](../architecture/super-native#is-the-web-view-still-an-option) is one route and one component. Ready to go deeper? Start with [The Renderer](renderer). diff --git a/resources/views/docs/mobile/4/architecture/cross-platform-implementation.md b/resources/views/docs/mobile/4/architecture/cross-platform-implementation.md index e5b13455b..f50af9a05 100644 --- a/resources/views/docs/mobile/4/architecture/cross-platform-implementation.md +++ b/resources/views/docs/mobile/4/architecture/cross-platform-implementation.md @@ -3,9 +3,8 @@ title: Cross-Platform Implementation order: 40 --- -NativePHP renders with each platform's own UI framework — SwiftUI on iOS, Jetpack Compose on Android — yet one -Blade template produces the same screen on both. That consistency isn't achieved by testing hard; it's achieved by -sharing the core. +NativePHP renders with each platform's own UI framework, SwiftUI on iOS and Jetpack Compose on Android, yet one +Blade template produces the same screen on both. One shared core is what makes that possible. ## One core, two thin shells @@ -13,25 +12,25 @@ Everything that defines *what* gets rendered lives in a single shared implementa [compiled directly into the PHP runtime](embedded-php) that ships on both platforms: - walking your PHP element trees and encoding them into [frames](glossary#frame), -- the binary [node](glossary#node) format itself — every field, in the same order, with the same meaning, +- the binary [node](glossary#node) format itself, every field in the same order with the same meaning, - the skip-and-reuse logic described in [Subtree Reuse](subtree-reuse), - and the [event channel](glossary#wire-events) that carries interactions back to PHP. What remains per platform is deliberately thin: a reader that decodes frames and diffs trees, and a renderer that -maps each node type to a SwiftUI view or a composable. Even those two layers are written as mirrors of each other -— the same diffing rules, the same frame-coalescing behavior, the same enums for flexbox values, so +maps each node type to a SwiftUI view or a composable. Even those two layers are written as mirrors of each other, +with the same diffing rules, the same frame-coalescing behavior and the same enums for flexbox values, so `justify-content: center` is the identical byte on the wire and the identical concept on both screens. -The practical consequence: when we fix a bug or land a performance improvement in the pipeline, both platforms get -it simultaneously, because there's only one pipeline. +In practice, when we fix a bug or land a performance improvement in the pipeline, both platforms get it at the same +time, because there's only one pipeline. ## Native layout on both platforms Layout follows the same philosophy. Each node carries flexbox-style layout values, and each platform implements -flexbox *inside its own layout system* — a pure-Swift `Layout` on iOS and a Compose `Layout` on Android, built to -the same semantics. There's no shared C++ layout engine sitting apart from the UI framework: your components -measure and place like any other SwiftUI or Compose view, which is exactly why safe areas, dynamic type and -platform navigation transitions work naturally with them. +flexbox *inside its own layout system*, a pure-Swift `Layout` on iOS and a Compose `Layout` on Android, built to +the same semantics. There's no shared C++ layout engine sitting apart from the UI framework. Your components +measure and place like any other SwiftUI or Compose view, which is why safe areas, dynamic type and platform +navigation transitions work naturally with them. iOS is the reference implementation for visual behavior; Android is held to it. Where the platforms disagree by default (text padding, stretch behavior, pixel-versus-point units), the Android renderer adapts so the same @@ -39,13 +38,13 @@ classes produce the same result. ## Two seams, one boundary -Rendering isn't the only traffic between PHP and native. Device features — camera, biometrics, geolocation, -secure storage and everything the [plugin system](../plugins/introduction) exposes — travel over a separate, +Rendering isn't the only traffic between PHP and native. Device features (camera, biometrics, geolocation, +secure storage and everything the [plugin system](../plugins/introduction) exposes) travel over a separate, simpler seam: [bridge functions](../plugins/bridge-functions), a registry of named native functions PHP can call with JSON in and JSON out. The two seams are independent by design. The rendering path is a hot loop measured in microseconds, so it gets the -binary shared-memory treatment; device APIs are occasional calls where clarity and extensibility matter more, so +binary shared-memory treatment. Device APIs are occasional calls where clarity and extensibility matter more, so they get a friendly, pluggable interface. Plugin authors only ever touch the second one. ## Failing loud, not weird @@ -53,5 +52,5 @@ they get a friendly, pluggable interface. Plugin authors only ever touch the sec A shared binary format is only safe if both sides agree on it, so the format carries an explicit **version number**. At startup, each native reader checks the version reported by the Element Runtime against the one it was compiled for; on mismatch it refuses to render rather than misinterpret bytes. Because the PHP runtime and the -native shells [ship together in lockstep](embedded-php), the check should never fire in a real app — it exists so +native shells [ship together in lockstep](embedded-php), the check should never fire in a real app. It exists so that if the impossible happens, you get one clear error instead of a subtly broken UI. diff --git a/resources/views/docs/mobile/4/architecture/embedded-php.md b/resources/views/docs/mobile/4/architecture/embedded-php.md index ab99edcc7..c2a98165a 100644 --- a/resources/views/docs/mobile/4/architecture/embedded-php.md +++ b/resources/views/docs/mobile/4/architecture/embedded-php.md @@ -3,20 +3,20 @@ title: Embedded PHP order: 70 --- -There's no server in a NativePHP app — and no separate PHP process either. PHP ships *inside* your app as a +There's no server in a NativePHP app, and no separate PHP process either. PHP ships *inside* your app as a library, compiled specifically for mobile devices and linked into the native application itself. This page explains what that build is, why we produce it ourselves, and how it reaches your project. ## PHP as a library -Standard PHP is built to sit behind a web server. Mobile PHP is built with the **embed SAPI**: instead of a -`php` binary, the build produces a C library (`libphp`) that the Swift and Kotlin shells link against and call -directly. When your app boots, it initializes the PHP engine in-process, loads your Laravel app from the bundled +Standard PHP is built to sit behind a web server. Mobile PHP is built with the **embed SAPI**. Instead of a `php` +binary, the build produces a C library (`libphp`) that the Swift and Kotlin shells link against and call directly. +When your app boots, it initializes the PHP engine in-process, loads your Laravel app from the bundled [app package](../getting-started/introduction), and keeps it resident as the [persistent runtime](threading-model#lifecycle-booted-once-kept-warm). Running in-process is what makes the rest of the architecture possible: shared memory only works when both sides -share a process. It's also simply fast — there's no FastCGI, no sockets, no per-request process to spawn. +share a process. It's also fast, since there's no FastCGI layer and no per-request process to spawn. NativePHP for Mobile currently bundles **PHP 8.4**, cross-compiled for iOS (device and simulator) and Android (ARM64), thread-safe, and tuned for embedding. @@ -24,28 +24,28 @@ NativePHP for Mobile currently bundles **PHP 8.4**, cross-compiled for iOS (devi ## Built in lockstep with the framework The renderer's [wire format](glossary#frame) has two sides: the [Element Runtime](glossary#element-runtime) that -writes it, and the native readers that decode it. The Element Runtime is a PHP **extension** — native code +writes it, and the native readers that decode it. The Element Runtime is a PHP **extension**, native code compiled into `libphp` itself, alongside the engine. -That's why we build PHP ourselves, and why every release of `nativephp/mobile` pins exact binary builds: the PHP +That's why we build PHP ourselves, and why every release of `nativephp/mobile` pins exact binary builds. The PHP engine, the NativePHP extension inside it, and the Swift/Kotlin readers around it are produced and shipped -**together**, from matching sources. Both sides of every boundary are always the same version — there is no +**together**, from matching sources. Both sides of every boundary are always the same version, so there is no "which PHP works with which framework release" matrix to manage. The wire format's [version handshake](cross-platform-implementation#failing-loud-not-weird) exists as a backstop, but lockstep shipping is what makes it a formality. The same extension also provides the [bridge functions](../plugins/bridge-functions) seam that device APIs and -plugins are built on — one native extension, both boundaries. +plugins are built on. One native extension, both boundaries. ## What's inside The builds include the extensions a Laravel app expects, statically compiled along with their dependencies: bcmath, ctype, curl, dom, fileinfo, filter, intl, mbstring, openssl, pdo_sqlite, phar, session, simplexml, -sockets, sodium, sqlite3, tokenizer, xml, xmlreader, xmlwriter, zip and zlib — plus the `nativephp` extension +sockets, sodium, sqlite3, tokenizer, xml, xmlreader, xmlwriter, zip and zlib, plus the `nativephp` extension described above. SQLite is the bundled database, a CA certificate bundle is included so HTTPS works out of the box, and ICU is included so localization and `intl`-powered formatting behave properly on device. -Everything is compiled from source for each platform — including OpenSSL, libxml2, SQLite and friends — so the +Everything is compiled from source for each platform, including OpenSSL, libxml2, SQLite and friends, so the builds have no dependencies on whatever libraries happen to exist on a given device. ## How it reaches your app @@ -57,12 +57,12 @@ php artisan native:install ``` the framework downloads the prebuilt PHP bundles matching your `nativephp/mobile` version and places them into the -platform projects — static libraries for iOS, shared libraries for Android. `native:run` then compiles your app -with PHP inside it, exactly like any other native dependency. +platform projects, as static libraries for iOS and shared libraries for Android. `native:run` then compiles your +app with PHP inside it, exactly like any other native dependency.