diff --git a/docs/developer-guide/img/backend-build-pipeline.svg b/docs/developer-guide/img/backend-build-pipeline.svg
index 96e48244585..ab3a307fb35 100644
--- a/docs/developer-guide/img/backend-build-pipeline.svg
+++ b/docs/developer-guide/img/backend-build-pipeline.svg
@@ -9,7 +9,7 @@
@RestControllercontrollers
- @Service @Component
+ @Componentbeans@Configuration + @Bean
diff --git a/docs/website/content/blog/browser-desktop-theme.md b/docs/website/content/blog/browser-desktop-theme.md
new file mode 100644
index 00000000000..87a58ef6d53
--- /dev/null
+++ b/docs/website/content/blog/browser-desktop-theme.md
@@ -0,0 +1,100 @@
+---
+title: "Do You Want Your Web App to Feel Like a Native App?"
+slug: browser-desktop-theme
+url: /blog/browser-desktop-theme/
+date: '2026-10-07'
+author: Shai Almog
+description: "Use macOS, Windows or Linux desktop styling in the JavaScript port, with an optional HTML menu bar, and see how the same theme work reaches the Certificate Wizard."
+feed_html: ' Use macOS, Windows or Linux desktop styling in the JavaScript port, with an optional HTML menu bar, and see how the same theme work reaches the Certificate Wizard.'
+series: ["release-2026-10-02"]
+---
+
+
+
+You can give your Codename One web app the same desktop theme family as your users' operating system: Aqua on macOS, Fluent on Windows, or Adwaita on Linux. Menus can sit above the app in HTML, with commands such as File and View visible instead of tucked into a mobile overflow menu.
+
+That gives you a browser version of your app that fits more comfortably on a desktop. The JavaScript port now supports both choices, and the same theme work reaches the Certificate Wizard you use to sign your apps.
+
+## Follow the operating system, or choose a theme
+
+Set these in the Settings app's **Build Hints**:
+
+```properties
+nativeTheme=native
+javascript.titleBar=html
+```
+
+In `codenameone_settings.properties`, use `codename1.arg.nativeTheme` and `codename1.arg.javascript.titleBar` instead. Desktop browsers select Fluent for Windows, Aqua for macOS, and Adwaita for Linux and the remaining desktop systems. Phones and tablets keep the mobile theme selection. The browser detection treats an iPad as a tablet even when it reports a Mac browser.
+
+These are Codename One themes drawing the controls. They are not the operating system's native widget toolkit embedded in the page.
+
+[](/blog/desktop-theme-collage.jpg)
+
+*The Settings app demonstrates the three desktop theme families now available to browser apps. Click to compare the controls at full size.*
+
+You can pin a desktop theme when the application's design calls for it:
+
+```properties
+javascript.desktopTheme=fluent
+```
+
+The other explicit choices are `aqua`, `adwaita` and `none`. `none` keeps mobile themes on desktop browsers. Leave the value at `auto` to follow the operating system. The broader `nativeTheme=modern` setting has different behavior: it selects the modern mobile families, including on desktop browsers. Use `native` when desktop family selection is what you want.
+
+## Put commands above the app
+
+The default `javascript.titleBar=toolbar` keeps the themed Toolbar inside the app. With `html`, the page supplies title and menu bars instead. The title follows the current form; commands group into menus using the same `Command.setDesktopMenu()` hint used on the desktop ports.
+
+For example, inside an initialized app:
+
+```java
+com.codename1.ui.Form form = new com.codename1.ui.Form("Notes");
+com.codename1.ui.Command refresh = new com.codename1.ui.Command("Refresh") {
+ public void actionPerformed(com.codename1.ui.events.ActionEvent event) {
+ form.setTitle("Notes refreshed");
+ }
+};
+refresh.setDesktopMenu("View");
+form.getToolbar().addCommandToOverflowMenu(refresh);
+form.show();
+```
+
+Commands without a menu hint go into a **Commands** menu. The HTML bars follow the selected appearance and the browser's light or dark preference. They do not have fake minimize, maximize or close buttons: the page does not own the browser window. The browser tab title remains the application's display name.
+
+{{< mermaid >}}
+flowchart TD
+ Commands[Toolbar commands and menu hints] --> Mode{Title bar setting}
+ Mode -->|toolbar| Inside[Themed Toolbar inside the app]
+ Mode -->|html| Outside[HTML title and menu above the app]
+ Outside --> Action[Dispatch to the same Command]
+ Inside --> Action
+{{< /mermaid >}}
+
+The source is in [JavaScriptDesktopChrome](https://github.com/codenameone/CodenameOne/blob/master/Ports/JavaScriptPort/src/main/java/com/codename1/impl/html5/JavaScriptDesktopChrome.java), with build-hint and page behavior documented in the [JavaScript guide](/developer-guide/working-with-javascript/).
+
+## Keep navigation inside your browser app
+
+We do not support additional native `Window` surfaces in the JavaScript port. Popup blockers and the browser's window ownership make that a different promise from drawing a menu inside the current page. **Windows browsers are supported; extra OS windows are the unsupported feature.** Dialogs and navigation within the app remain the appropriate model.
+
+There are renderer limits too. For example, the full lifted-lens optics from [Sunday's iOS article](/blog/ios27-glass-from-measurements/) are not implemented in the browser. Try the actual controls and effects your app uses rather than assuming a theme name proves complete renderer parity.
+
+The build prunes theme resources it can prove the app will not reach. If your code constructs resource names dynamically, set `javascript.pruneThemes=false`; otherwise a theme loaded only through that constructed name may be missing.
+
+## Use the same desktop styling when you sign your app
+
+A gallery of buttons cannot tell us whether an application works comfortably with a desktop theme. The Certificate Wizard has longer forms, tables, dialogs and instructions that people must actually read to finish a task.
+
+[PR #5916](https://github.com/codenameone/CodenameOne/pull/5916) adopts the native desktop themes there, continuing the work we did in Settings. Its current source uses `@DesktopBuild(themeMode = "native", titleBar = DesktopTitleBar.NATIVE, ...)`, with interactive scrollbars. Fluent, Aqua and Adwaita now provide the surrounding control styles instead of a separate wizard-specific desktop imitation.
+
+The same change fixes handling of an App ID's team prefix. That is a separate functional repair, not a consequence of adopting a theme. The wizard's [current source](https://github.com/codenameone/CodenameOne/tree/master/scripts/certificatewizard) keeps both changes visible.
+
+Try the browser theme with a form that has real commands and enough content to scroll. Switch appearances, open its menus and check keyboard navigation. That will teach you more than another screenshot of an isolated button.
+
+The [weekly overview](/blog/java-server-work-before-startup/) links the rest of the release. It also includes this week's smaller map-label improvement.
+
+---
+
+## Discussion
+
+_For a browser version of a desktop app, which commands deserve a visible menu?_
+
+{{< giscus >}}
diff --git a/docs/website/content/blog/friday-release-better-gates.md b/docs/website/content/blog/friday-release-better-gates.md
new file mode 100644
index 00000000000..f54857f37d4
--- /dev/null
+++ b/docs/website/content/blog/friday-release-better-gates.md
@@ -0,0 +1,113 @@
+---
+title: "Don't Order Fish on Monday. Don't Release on Friday"
+slug: friday-release-better-gates
+url: /blog/friday-release-better-gates/
+date: '2026-10-08'
+author: Shai Almog
+description: "A difficult release week exposed an Apple API failure that passed device tests, leading to source and binary checks for undeclared SDK imports."
+feed_html: ' A difficult release week exposed an Apple API failure that passed device tests, leading to source and binary checks for undeclared SDK imports.'
+series: ["release-2026-10-02"]
+---
+
+
+
+Anthony Bourdain's famous warning about Monday fish was a warning about the supply chain behind the menu. In his [1999 essay](https://www.newyorker.com/magazine/1999/04/19/dont-eat-before-reading-this), he described seafood bought for the weekend still being served on Monday. Knowing how the kitchen worked changed what he would order.
+
+Developers have a similar rule: never release on Friday. If something breaks, you have just made plans for everyone's weekend. It is excellent advice that we have ignored for years.
+
+We settled on Friday releases to avoid dropping a framework update into the middle of our customers' release week. The idea was to use the quieter window to test and repair our release before it collided with theirs. That assumes a lot about when other people ship. It has also cost me plenty of weekends.
+
+This time the problems consumed much of the week. There were regressions around the optional Xcode 27 path, push, and windows. Some overlapped, so a fix could make the original symptom disappear while the underlying problem resurfaced elsewhere. That is exhausting for us, and it is worse for the customer trying to finish an app.
+
+## Catch a rejection your device tests can miss
+
+One failure was especially instructive. Apps using particular crypto APIs could compile, link and run, then fail App Store Connect submission because the binary imported non-public symbols. Most apps did not enable the affected code, so most users and our usual tests never encountered it:
+
+```text
+_CCCryptorGCMAddAAD
+_CCCryptorGCMAddIV
+_CCCryptorGCMFinal
+```
+
+The SDK's libraries exported these symbols. The linker could resolve them. But they were not declared in the public headers. A successful link did not establish that they were public APIs suitable for submission.
+
+Our tests had another blind spot: the calls sat behind an optional feature gate that the sample app did not normally enable. Testing the same sample more often would not make that branch appear.
+
+The [new checker source](https://github.com/codenameone/CodenameOne/blob/master/scripts/check-ios-private-api.py) preserves the rejection and the causal chain. It is a more useful record than a claim that we “added more tests.”
+
+## How your build could enable a feature you never requested
+
+The builder enabled a feature by replacing a preprocessor definition. A plain string replacement for one name also matched the start of a longer name:
+
+```c
+#define CN1_INCLUDE_CRYPTO
+#define CN1_INCLUDE_CRYPTO_GCM
+```
+
+Enabling general crypto could therefore enable the GCM path too. The customer did not have to request that optional path to compile its imports.
+
+The fix makes the builder match the whole definition name. A focused regression test guards that behavior. The GCM implementation itself was rewritten using public CommonCrypto operations and a C implementation of GHASH, the authentication calculation. The authenticated-decryption path verifies the tag before releasing decrypted output.
+
+A separate sweep found `sqlite3_key` and `sqlite3_rekey` imports that were valid for the bundled cipher engine but not public declarations in Apple's SQLite headers. Those imports now depend on the bundled engine defining them. One rejected upload exposed more than one place where “the symbol links” had stood in for “the symbol is public.”
+
+## How we will catch this class of failure before it reaches you
+
+A regression test for the three names would catch those three names returning. We also need a check for the broader mistake: importing an SDK symbol that has no public declaration.
+
+The new gate asks that question in two ways:
+
+| Check | What it sees | Why it is needed |
+| --- | --- | --- |
+| Source mode | Native port sources with feature gates enabled and optional-engine variants | The ordinary sample does not exercise every feature combination |
+| Binary mode | Imports in a linked Release device app and the covered bundled components | The final link can contain code beyond the port source sweep |
+
+{{< mermaid >}}
+flowchart TD
+ Source[Native sources and feature variants] --> Compile[Compile the covered configurations]
+ Compile --> Imports[Collect SDK imports]
+ Binary[Linked Release device app] --> Imports
+ SDK[Public SDK headers] --> Compare[Compare exported names with declarations]
+ Imports --> Compare
+ Compare --> Fail[Fail on undeclared imported symbols]
+ Probe[Known private and public control symbols] --> Verify[Verify the checker can distinguish them]
+ Verify --> Compare
+{{< /mermaid >}}
+
+The checker uses SDK export information to identify the library symbols and scans public headers with comments removed. A name mentioned in a comment is not accepted as a declaration. It also exercises known private and public controls before trusting a clean result. A check that can never report a failure is a very comforting way to learn nothing.
+
+For a local inspection of a linked app, the script exposes a binary mode:
+
+```bash
+python3 scripts/check-ios-private-api.py \
+ --binary /path/to/Release-iphoneos/MyApp.app --sdk iphoneos
+```
+
+Replace the example path with your Release device artifact; use `--developer-dir` if the SDK belongs to a different Xcode installation. The repository wires source mode and Release binary mode into its iOS checks. [PR #5923](https://github.com/codenameone/CodenameOne/pull/5923) contains the implementation and the builder repair.
+
+## Know what your submission check covers
+
+This is an imported-symbol check for the covered C and Objective-C surface. It skips Swift and C++ mangled names that cannot be matched by this header scan, and it does not inspect private Objective-C selectors. The binary check in the repository runs against the covered sample and bundled components, not every arbitrary dependency a customer might add.
+
+It also cannot predict every App Store review decision. Entitlements, privacy declarations and application behavior are different questions. Checking imports catches one specific reason for rejection before you upload.
+
+Review those remaining checks separately when preparing your submission.
+
+## We owe you more reliable releases
+
+This week was hard. I spent too much of it chasing regressions, and some of you spent time proving to us that a fix had not really fixed your problem. That is time you should have been able to spend on your own apps. Our release process needs to do better.
+
+Changing the day we ship would not repair the gaps that let these failures through. Our plan is to strengthen the gates around the things we deliver: exercise optional configurations, check the final artifacts, and test rules that cover a whole class of mistakes. We still need the small regression test for each bug. We also need to ask why that bug could reach a customer while the checks were green.
+
+The private API gate is one concrete step in that plan. It checks feature combinations our regular sample missed, examines a linked Release app, and uses known control symbols to verify that the checker can actually fail. The wider work is ongoing; one new gate does not solve every regression involving Xcode, push, or windows.
+
+I cannot promise next week will be quiet. I can promise that a difficult week should leave us with stronger release checks, not just a longer list of closed bugs. As that coverage grows, fewer failures should depend on a customer finding the right combination of APIs for us.
+
+This closes the [weekly series](/blog/java-server-work-before-startup/). I am excited about the backend and the UI improvements, but you should be able to try them without wondering what else an update will break. That is the release quality we need to earn.
+
+---
+
+## Discussion
+
+_Which green check has given your team the most misleading confidence before a release?_
+
+{{< giscus >}}
diff --git a/docs/website/content/blog/gradle-smaller-projects.md b/docs/website/content/blog/gradle-smaller-projects.md
new file mode 100644
index 00000000000..1c46e378397
--- /dev/null
+++ b/docs/website/content/blog/gradle-smaller-projects.md
@@ -0,0 +1,182 @@
+---
+title: "Do You Prefer Gradle?"
+slug: gradle-smaller-projects
+url: /blog/gradle-smaller-projects/
+date: '2026-10-05'
+author: Shai Almog
+description: "Optional Gradle projects remove empty platform modules, support standalone backends, and use the same build engine as Maven."
+feed_html: ' Optional Gradle projects remove empty platform modules, support standalone backends, and use the same build engine as Maven.'
+series: ["release-2026-10-02"]
+---
+
+
+
+You can now choose Gradle for a Codename One project. Start with fewer files, add platform directories when you need native code, or create a standalone backend without a mobile app attached. A smaller project is easier to browse and leaves less scaffolding competing for space in an LLM's context.
+
+I like Maven XML. I know it is verbose. I also spent enough time at Sun Microsystems staring at deeply scripted, heavily patched `make` files to develop a lasting suspicion of clever build systems.
+
+Someone starts with a reasonable shortcut. Someone else needs one more condition. A few years later the build has its own undocumented programming language and nobody wants to touch it. I would rather a build system be strict and limited. Give people enough power and, with the best intentions, they build a Frankenstein build.
+
+That is a personal preference. Plenty of developers I respect love Gradle, or at least appreciate what it lets them do. This week we added [optional Gradle support](https://github.com/codenameone/CodenameOne/pull/5922) because it lets us offer something useful: a smaller Codename One project, including a standalone backend with no client scaffolding.
+
+## Start with fewer files
+
+The Maven app layout has a root POM and platform modules ready for native code. That makes the structure explicit, but a new app often has no code in most of those places.
+
+A Gradle app starts with the sources and configuration it needs. Native directories appear when you generate native interfaces. A backend subproject appears when you add a backend.
+
+For a concrete example, we converted the checked-in HelloCodenameOne sample with the current converter:
+
+| Project files | Maven sample | Converted Gradle sample |
+| --- | ---: | ---: |
+| Total files, including app sources and resources | 358 | 305 |
+| Maven POMs | 9 | 0 |
+| Gradle Kotlin configuration files | 0 | 2 |
+
+That removes **53 files, about 15% of the tree**. We counted the tracked sample before conversion and all files in the converter's new directory afterward, excluding build output and caches. This is the existing demonstration app, with its resources and Kotlin source, rather than a comparison of two different Hello World programs.
+
+The generated `settings.gradle.kts` is small enough to show in full, with its explanatory comments removed:
+
+```kotlin
+pluginManagement {
+ repositories {
+ maven("https://repo.codenameone.com/maven2")
+ gradlePluginPortal()
+ }
+}
+plugins {
+ id("com.codenameone") version "7.0.274"
+}
+rootProject.name = "HelloCodenameOne"
+```
+
+The example selects release `7.0.274`, which includes Gradle support. The app's own dependencies and Kotlin plugin go in `build.gradle.kts`; the framework's platform builders come from the Codename One plugin.
+
+
+```text
+MyApp/
+ settings.gradle.kts
+ gradle.properties
+ gradlew
+ gradle/wrapper/
+ codenameone_settings.properties
+ icon.png
+ src/main/java/
+ src/main/css/theme.css
+ src/main/resources/
+```
+
+Add `build.gradle.kts` when you have dependencies or build configuration of your own. Kotlin source belongs in `src/main/kotlin` when the project applies the Kotlin plugin.
+
+That smaller tree helps a human understand an unfamiliar project. It can also reduce the irrelevant files an agent sees when building its context. The file reduction is measurable; the context saved depends on which files your agent reads.
+
+## Keep the same builds when you switch
+
+We did not implement a second set of platform builders. The Gradle plugin calls the shared engine used by Maven. That includes upload staging, local builders, CSS compilation and bytecode compliance checks.
+
+{{< mermaid >}}
+flowchart TD
+ Maven[Maven plugin] --> Engine[Shared Codename One build engine]
+ Gradle[Gradle plugin] --> Engine
+ Engine --> CSS[Compile CSS and check bytecode]
+ Engine --> Local[Generate local platform projects]
+ Engine --> Upload[Stage cloud build upload]
+{{< /mermaid >}}
+
+From a generated Gradle app:
+
+```bash
+./gradlew run
+./gradlew cn1Test
+./gradlew buildJavascriptLocal
+./gradlew buildIosXcodeProject -Popen=false
+```
+
+`run` starts the simulator. `cn1Test` uses the simulator test runner. The last two commands build the JavaScript port locally and generate an Xcode project. Tasks that submit cloud builds are available too, with the same service requirements as Maven.
+
+There are limits. Running Gradle requires JDK 17 or newer and Gradle 8.5 or newer; the generated wrapper supplies Gradle. These projects target Java 17. They do not support legacy `.cn1lib` files or the old resource Designer task. The OpenAPI, gRPC and GraphQL generators and on-device debugging helpers still have Maven goals without equivalent Gradle tasks. The [workflow chapter](/developer-guide/gradle-project-workflow/) lists the supported surface.
+
+## Build a standalone Java backend
+
+In the [Initializr](/initializr/), choose **Gradle** as the build tool and **Backend only** as the project type. The server lives at the root, with its Java source and application properties. There is no client theme, simulator module or collection of empty native directories.
+
+For a generated project named `MyService`:
+
+```bash
+CN1_PROFILE=dev ./gradlew runBackend
+```
+
+That runs the development server on the JVM. Stop it before changing the backend code; this is a restart workflow, not hot reload. To build and run the native executable:
+
+```bash
+./gradlew backendPackage
+CN1_PROFILE=dev PORT=9000 ./build/MyService
+```
+
+The development profile uses the generated in-memory SQLite configuration. Without it, the starter reads its production settings and expects `DATABASE_URL`. The executable's name follows the project name.
+
+An existing Gradle app can gain a server with:
+
+```bash
+./gradlew addBackend
+CN1_PROFILE=dev ./gradlew :backend:runBackend
+./gradlew :backend:backendPackage
+```
+
+I hope people will try the backend on its own. It is still experimental, but a small independent service can reveal useful constraints without requiring a mobile application first. The [weekly overview](/blog/java-server-work-before-startup/) shows the Spring-style programming model it now supports.
+
+## Try Gradle alongside your Maven project
+
+The converter leaves the original project in place and writes a sibling project. Replace `VERSION` with the Codename One plugin release containing this feature:
+
+```bash
+mvn com.codenameone:codenameone-maven-plugin:VERSION:convert-to-gradle \
+ -Dcn1.sourceProject=/path/to/MyApp \
+ -Dcn1.outputDir=/path/to/MyApp-gradle
+```
+
+The destination must be empty or absent. The conversion carries sources, resources, CSS and platform implementations into the new layout, and raises the application's bytecode target to Java 17. A customized backend comes across; the untouched backend skeleton is optional. Legacy `.cn1lib` dependencies stop conversion with their names rather than silently disappearing.
+
+Open the converted project and run its tests before switching the team's build. Your old checkout remains available for comparison.
+
+## Find the API for the code you are writing
+
+Last week we split the Developer Guide into chapters. Before that, we rebuilt the Javadocs. A backend-only project made the next problem obvious: a client API page is the wrong answer when you are writing a server.
+
+[PR #5918](https://github.com/codenameone/CodenameOne/pull/5918) separates the [client API](/javadoc/) from the [backend API](/backend/javadoc/). The references label their audience and link shared classes to their counterpart. Backend classes belong in the backend reference; a UI implementation package does not belong there just because it exists in the repository.
+
+| What you are writing | Reference to start with |
+| --- | --- |
+| A form, component or device integration | [Client Javadocs](/javadoc/) |
+| A controller, database service or scheduled job | [Backend Javadocs](/backend/javadoc/) |
+| Shared models and mapping code | The shared class page, with its counterpart link |
+
+The distinction helps readers and code-generation tools for the same reason: it reduces the chance of choosing an API that exists in the wrong runtime. Both references are checked with `doclint`, so malformed documentation has a build-time consequence too.
+
+## Try Gradle 9 for your Android build
+
+The optional Gradle project layout and the Gradle version used inside a generated Android project are different choices. You can keep your Codename One app on Maven and still test the newer Android builder.
+
+In Settings, under **Build Hints**:
+
+```properties
+android.gradleVersion=9
+```
+
+Or in `codenameone_settings.properties`:
+
+```properties
+codename1.arg.android.gradleVersion=9
+```
+
+The current builder pairs Gradle 9.8.0 with Android Gradle Plugin 9.4.1. It adjusts the generated project for removed DSL elements and AGP's built-in Kotlin support. This selects the experimental Gradle 9 / Android Gradle Plugin 9 path from [PR #5919](https://github.com/codenameone/CodenameOne/pull/5919). It is opt-in. Much of the surrounding tooling and library configuration still assumes Gradle 8. Test your actual native dependencies and generated Android project before adopting it; a successful empty app is not the same test.
+
+I expect to keep using Maven for plenty of projects. Supporting Gradle gives teams another way into the same build machinery, and gives a small server a project tree that looks like a small server.
+
+---
+
+## Discussion
+
+_How much freedom do you want a build system to give the next person maintaining it?_
+
+{{< giscus >}}
diff --git a/docs/website/content/blog/ios27-glass-from-measurements.md b/docs/website/content/blog/ios27-glass-from-measurements.md
new file mode 100644
index 00000000000..c2db974cdbd
--- /dev/null
+++ b/docs/website/content/blog/ios27-glass-from-measurements.md
@@ -0,0 +1,137 @@
+---
+title: "Can You Tell the Difference Between These iOS Tab Bars?"
+slug: ios27-glass-from-measurements
+url: /blog/ios27-glass-from-measurements/
+date: '2026-10-04'
+author: Shai Almog
+description: "Reconstructing iOS 27 tab motion from real touches, spring equations, color matrices and a side-by-side simulator comparison."
+feed_html: ' Reconstructing iOS 27 tab motion from real touches, spring equations, color matrices and a side-by-side simulator comparison.'
+series: ["release-2026-10-02"]
+---
+
+
+
+Watch how the two tab bars respond to the recorded taps, holds, drags and changes of direction. Can you tell which one is UIKit and which one is drawn by Codename One?
+
+That is a more useful test than a still image. Your users feel the delay before a selection moves, the way the glass follows a finger and the settling motion after release. A tab bar can have the right colors and still feel wrong in your hand.
+
+[Last week's iOS 27 theme](/blog/ios-27-glass-you-can-test/) was close, but I still wasn't happy with those interactions. Getting closer meant recording UIKit's presentation layers during real touches, fitting the motion to spring equations and reconstructing the glass effects. Here is the result, followed by the measurements and formulas behind it.
+
+## Watch the same gestures twice
+
+{{< guide-block >}}
+
+{{< /guide-block >}}
+
+*UIKit is on top and Codename One below. These committed iOS 27 simulator recordings use the same touch sequence: six taps, a held press, a tap on the selected tab, a slow drag and a flick. Each gesture occupies a 4.2-second slot aligned on the touch.*
+
+{{< guide-block >}}
+
+{{< /guide-block >}}
+
+*The dark appearance exposes the edge, vibrancy and refraction differences more clearly. UIKit is above Codename One in both simulator recordings.*
+
+The [recording script](https://github.com/codenameone/CodenameOne/blob/master/scripts/record-ios-tabs-side-by-side.sh) and [video notes](https://github.com/codenameone/CodenameOne/blob/master/docs/videos/README.md) make the provenance inspectable. The remaining differences are part of the comparison: the lifted lens, its rounded ends and the saturation still deserve work.
+
+## Why your tab bar can look right and feel wrong
+
+Setting the selected tab in code did not produce the complete native interaction. UIKit performs that motion for genuine touches on a controller-managed bar. The probe therefore uses XCUITest taps, holds, and drags.
+
+There was another complication: UIKit did not attach a simple `CAAnimation` containing the whole trajectory. It updated layer values frame by frame. The useful record was the presentation geometry at each display refresh: position, bounds, transform, opacity and the touch timestamps that explained them.
+
+{{< mermaid >}}
+flowchart LR
+ Touch[Real XCUITest gesture] --> UIKit[Native tab controller]
+ UIKit --> Log[Per-frame presentation geometry]
+ Log --> Fit[Fit springs and retained curves]
+ Fit --> Java[Java motion model]
+ Log --> Fixture[Recorded fixtures]
+ Java --> Check[Replay and compare]
+ Fixture --> Check
+{{< /mermaid >}}
+
+Capturing an image on every frame changes the timing enough to contaminate the measurement. The probe separates geometry logging from optional frame snapshots. Snapshot runs are useful for comparing the lens at the same motion state, not for fitting its timing. Likewise, lossless screenshots over known backdrops reveal the blur; compressed video smears the very edges we need to inspect.
+
+Those constraints are documented in the [native probe](https://github.com/codenameone/CodenameOne/tree/master/scripts/fidelity-app/ios-native-ref/motion-probe). They explain why “looks close in a recording” was not enough.
+
+## Make taps, holds and drags respond differently
+
+For a fixed target, a damped spring follows this equation:
+
+
+
+Here `x` is position, `xₜ` is the target, `ω` controls the natural frequency and `ζ` the damping. Dots denote derivatives with respect to time. A critically damped spring has `zeta = 1`; lower damping allows an overshoot. The implementation uses the measured constants rather than retuning the entire animation by eye:
+
+| Channel | Model in the current source |
+| --- | --- |
+| Selection travel | `omega = 2*pi/0.4`, `zeta = 0.85` |
+| Lens lift | Critical damping, `omega = 2*pi/0.25` |
+| Platter return | Critical damping, `omega = 2*pi/0.4` |
+| Whole-bar press growth | `omega = 17.6`, `zeta = 0.59` |
+| Lens following a drag | `omega = 32`, `zeta = 0.90` |
+
+The travel stops once the remaining distance after the overshoot is below about 0.195 points. The drag and press models include a measured 20 ms touch lag. These small details are visible because your finger gives the animation a moving reference point.
+
+The current [TabGlassMotion](https://github.com/codenameone/CodenameOne/blob/master/CodenameOne/src/com/codename1/ui/TabGlassMotion.java) and [TabGlassGesture](https://github.com/codenameone/CodenameOne/blob/master/CodenameOne/src/com/codename1/ui/TabGlassGesture.java) contain the formulas, retained tables and stopping rules. The regeneration tool checks the closed forms against captures and rewrites the channels that remain tabulated.
+
+## Let users drag across tabs without selecting each one
+
+During a drag the lens follows the finger on its own spring, so it can lag behind. On release, UIKit selects the tab under the finger, not the one nearest the lagging lens. The lens then settles toward that tab from its current position and velocity.
+
+Resetting velocity at that handoff creates a visible interruption. Snapping to the nearest lens position after a fast flick creates another discontinuity. A press on the already selected tab must also lift and pulse without inventing travel to another tab. A held press has to keep its lifted state until release rather than play a fixed-duration tap and finish underneath your finger.
+
+The release adds a small wobble. Our model uses a common starting point for it even though the captures show slightly different onset times across gesture types. That approximation is one reason to keep the full gesture suite alongside the short demo.
+
+## Keep icons legible as the backdrop changes
+
+A vibrant tab icon is not simply painted with an alpha color. Its result depends on the glass behind it. The probe reads UIKit's color matrices across tint sweeps, and `VibrancyMatrix` reconstructs the transform.
+
+For a non-gray dark tint vector `t`, the measured form is:
+
+```text
+e = 0.5 * min(t) / max(t)
+M = e*I + (0.5 - e) * (ones * transpose(t)) / dot(t,t)
+offset = t
+output = M * backdrop + offset
+```
+
+`I` is the identity matrix and `ones` is a column of three ones. Gray tints have their own formula, so this expression is not a universal branch to paste over the implementation. Light appearance uses a different form. The [vibrancy source](https://github.com/codenameone/CodenameOne/blob/master/CodenameOne/src/com/codename1/ui/plaf/VibrancyMatrix.java) and recorded fixture hold those cases together.
+
+The selection platter also transforms the bar's existing glass. `Graphics.colorMatrixRegion` applies that operation within a shape and optional mask. The lifted lens needs a separate operation: refraction around a circular bevel, color dispersion, an outline, rim light and shadow. `glassLensRegion` supplies that rendering path.
+
+This is why adjusting the opacity of a rounded rectangle could only take us so far. The effect changes the content underneath it.
+
+## Keep the glass animation on the GPU
+
+A more accurate motion model is wasted if the renderer misses the frames that distinguish it. The iOS bar glass now runs on the GPU instead of passing through a CPU blur with GPU synchronization around it. Mutable images reuse their stencil texture. The tab animation avoids asking for a second whole-component repaint, and the lens scratch texture is released after use.
+
+The portable color-matrix operation reaches the JavaScript port too. The browser lens still lacks the full optics implementation. A shared API does not mean every rendering backend implements every effect today.
+
+## Choose the appearance, then test your screen
+
+In the Settings app's **Build Hints**, select:
+
+```properties
+ios.themeMode=modern
+ios.themeGeneration=27
+```
+
+For the cloud toolchain, `ios.xcode_version=27` is a separate setting. In `codenameone_settings.properties`, prefix build-hint keys with `codename1.arg.`. A local Xcode build uses the Xcode installation selected on your Mac.
+
+Codename One draws these controls itself. The theme and its motion ship with the app, so adopting this appearance remains your decision. That control also gives us the responsibility to measure the behavior we reproduce.
+
+Try the animation over a photograph, a scrolling list and a plain dark background. Hold it. Drag past the middle and release. The [implementation in PR #5906](https://github.com/codenameone/CodenameOne/pull/5906) and the fixtures behind it make those interactions repeatable instead of leaving fidelity to memory.
+
+---
+
+## Discussion
+
+_Which gesture exposes an animation that looked right in a screenshot?_
+
+{{< giscus >}}
diff --git a/docs/website/content/blog/java-server-work-before-startup.md b/docs/website/content/blog/java-server-work-before-startup.md
new file mode 100644
index 00000000000..f1be08479c2
--- /dev/null
+++ b/docs/website/content/blog/java-server-work-before-startup.md
@@ -0,0 +1,426 @@
+---
+title: "A Smaller, Faster Java Server with a Spring-Style API"
+slug: java-server-work-before-startup
+url: /blog/java-server-work-before-startup/
+date: '2026-10-02'
+author: Shai Almog
+description: "Build a smaller native Java service with Spring-style transactions and dependency injection. Inspect the generated code and compare local Linux startup, memory, throughput, binary size and build time."
+feed_html: ' Build a smaller native Java service with Spring-style transactions and dependency injection. Inspect the generated code and compare local Linux startup, memory, throughput, binary size and build time.'
+series: ["release-2026-10-02"]
+---
+
+
+
+What do you pay for Spring and Java's dynamic architecture? Can you deliver the same API without the same runtime cost?
+
+For a small service, you might want dependency injection, transactions and scheduled jobs without a long startup or a large deployment. That is the case our native Java backend is trying to make. Write a controller and a service, compile their wiring into the application, then deploy a native executable.
+
+The HTTP runtime underneath that API is small. In the two-core Linux test below, its lower-level `Bench` handler occupies `5.17 MiB` and reaches its first verified response in `14.8 ms`. The same two endpoints in Spring/GraalVM occupy `88.31 MiB` and respond in `43.6 ms`. This handler uses no controller annotations or generated wiring, so those numbers measure the HTTP stacks, not the cost of the Spring-style API.
+
+This week's Spring-style API adds the parts that make that approach useful beyond a greeting endpoint: transaction propagation, scoped beans, background tasks, sessions, metrics and MCP tools. ParparVM supplies the native runtime, including virtual threads that can park while a handler waits for PostgreSQL, MySQL or another HTTP service.
+
+**This is a Spring-style API, not a drop-in Spring implementation.** Its annotations live in `com.codename1.backend.annotations`. Spring itself supports AOT processing and GraalVM Native Image. Our proposition is a smaller supported surface with direct generated calls, a native runtime shared with our app framework, and code you can inspect when you want to know what an annotation costs.
+
+The backend is still a work in progress. It sits on ParparVM, the runtime behind our native iOS apps, and is maturing rapidly. The local measurements below show where it earns the “smaller, faster” description. They also define the narrow workload being compared.
+
+## Coming This Week
+
+Today's article covers the backend API, generated code and local server comparison. The follow-ups explore what you can do with the rest of the release:
+
+- **Saturday, October 3:** {{< post-link path="/blog/parparvm-four-byte-header" text="Honey, I Shrunk Java" >}}. How object headers, compiler optimizations and garbage collection affect the memory and CPU your application needs.
+- **Sunday, October 4:** {{< post-link path="/blog/ios27-glass-from-measurements" text="Can You Tell the Difference Between These iOS Tab Bars?" >}}. Compare the videos, then see how measured motion and glass formulas make your UI feel closer to UIKit.
+- **Monday, October 5:** {{< post-link path="/blog/gradle-smaller-projects" text="Do You Prefer Gradle?" >}}. Start with fewer files, build a standalone backend, find the right Javadocs, and try the separate Android Gradle 9 option.
+- **Tuesday, October 6:** {{< post-link path="/blog/native-backend-observability" text="Connect Your App to Your Enterprise Traces" >}}. Connect your client app and native backend to traces across your enterprise services, with metrics and MCP alongside them.
+- **Wednesday, October 7:** {{< post-link path="/blog/browser-desktop-theme" text="Do You Want Your Web App to Feel Like a Native App?" >}}. Use desktop themes and visible menus in the browser. The Certificate Wizard gets the same theme families.
+- **Thursday, October 8:** {{< post-link path="/blog/friday-release-better-gates" text="Don't Order Fish on Monday. Don't Release on Friday" >}}. Catch private API imports before submission, and what a difficult Friday release taught us about gaps in testing.
+
+## Compare startup, memory, throughput and build time
+
+The measurements use CN1 revision [`60c4f310`](https://github.com/codenameone/CodenameOne/tree/60c4f310bddcfc51e5acc75c63a57c43c73430d3). For the comparison, we ran two small HTTP handlers on the Linux deployment target: a 13-byte plaintext response and a JSON object containing one `message` field. The CN1 executable uses the repository's lower-level `Bench` handler. Spring Boot 4.1.1 uses Spring MVC and embedded Tomcat, running either on Temurin JDK 25 or as a GraalVM 25 native executable.
+
+**This compares the selected HTTP stacks, not equivalent framework features.** The CN1 handler does not exercise the annotation-generated application shown below. There is no database, TLS, authentication, or telemetry in either application. Both JSON handlers create a map per request; CN1 also allocates a fresh response object.
+
+The host is an Apple M4 Max with 16 logical CPUs and `64 GiB` RAM. The local Linux ARM64 VM has four virtual CPUs and `8 GiB`. Linux CPU affinity restricts the server to 1, 2, or 4 CPUs. At 1 and 2, the load generator runs on the remaining CPUs; at 4, it shares them with the server. These are actual scheduling restrictions, not just a reported processor count.
+
+### Start quickly and ship a smaller executable
+
+The two-core configuration gives the server and load generator separate CPUs. Here are medians from three fresh processes, with the startup range in parentheses:
+
+| Application | First response, ms: median (range), lower is better | Native executable, MiB, lower is better |
+| --- | ---: | ---: |
+| CN1 native | 14.8 (5.3-15.1) | 5.17 |
+| Spring Boot / JDK 25 | 1,501.1 (1,407.6-1,617.8) | N/A |
+| Spring Boot / GraalVM 25 | 43.6 (32.5-45.6) | 88.31 |
+
+[](/blog/native-http-charts/startup.png)
+
+Startup includes spawning the process and receiving a verified HTTP response. File system caches are left warm; this is not a cold-machine or serverless measurement. The polling loop and `taskset` launcher also contribute to the short native times. The JVM run uses its default runtime settings without an AOT cache.
+
+[](/blog/native-http-charts/binary-size.png)
+
+The CN1 executable is `5.17 MiB`, compared with `88.31 MiB` for this Spring native build. These are uncompressed executable files from the default build outputs. Both files were unchanged by an additional pass that strips symbols. Both builds use shared system libraries, which are excluded here. This is not a container-size or complete-deployment comparison. The JVM column is N/A because its JAR is not a standalone native executable.
+
+### Leave more memory for the work your service does
+
+A server's memory use changes after it starts accepting traffic. We recorded all three stages using the same windows for each runtime:
+
+| Application, 2 allowed CPUs | Idle before load, MiB | Peak through load, MiB | Idle after load, MiB |
+| --- | ---: | ---: | ---: |
+| CN1 native | 10.0 | 57.8 | 29.8 |
+| Spring Boot / JDK 25 | 163.0 | 282.2 | 282.3 |
+| Spring Boot / GraalVM 25 | 78.1 | 117.0 | 79.6 |
+
+[](/blog/native-http-charts/memory.png)
+
+*Lower is better in all three memory columns. Idle before load is sampled three seconds after the first verified response. Peak is the kernel's resident-memory high-water mark through startup and both routes. Idle after load is sampled five seconds after traffic ends, without forcing collection. Each table entry is the median of the three process measurements.*
+
+CN1 uses less resident memory in both the idle and loaded measurements here. Four-byte object metadata is only one part of that cost. RSS also includes code, stacks, allocator pages and library state; it is not the live Java heap. This Linux build uses native virtual threads, so its connection costs differ from a platform-thread pool.
+
+### Serve requests with 1, 2 or 4 CPUs
+
+| Allowed server CPUs | Application | Plaintext requests/s | JSON requests/s |
+| --- | --- | ---: | ---: |
+| 1 | CN1 native | 164,542 | 138,555 |
+| 1 | Spring Boot / JDK 25 | 34,721 | 64,068 |
+| 1 | Spring Boot / GraalVM 25 | 40,286 | 39,167 |
+| 2 | CN1 native | 287,997 | 261,121 |
+| 2 | Spring Boot / JDK 25 | 69,953 | 70,491 |
+| 2 | Spring Boot / GraalVM 25 | 51,729 | 49,000 |
+| 4 | CN1 native | 245,608 | 251,435 |
+| 4 | Spring Boot / JDK 25 | 116,491 | 110,530 |
+| 4 | Spring Boot / GraalVM 25 | 80,053 | 61,873 |
+
+[](/blog/native-http-charts/throughput.png)
+
+*Higher is better. Points are medians; whiskers show the three-run range. Each route has ten seconds of warmup and ten seconds of measurement, using two `wrk` threads and 32 connections. Plaintext precedes JSON. Four-core points include load-generator contention, so this is not a clean four-core scaling curve.*
+
+### Does HotSpot catch up after warmup?
+
+CN1 still leads after a minute of warmup per endpoint: **3.9 times the plaintext throughput and 3.4 times the JSON throughput** of Spring/JDK 25 in the matched two-core follow-up. Both servers received the same longer warmup, followed by three consecutive ten-second measurement windows for each route.
+
+| Application, 2 allowed CPUs | Plaintext requests/s | JSON requests/s |
+| --- | ---: | ---: |
+| CN1 native, 60 s warmup per route | 296,928 | 250,268 |
+| Spring Boot / JDK 25, 60 s warmup per route | 75,721 | 73,613 |
+
+[](/blog/native-http-charts/warmed-throughput.png)
+
+*Higher is better. These are medians of three windows within one fresh process per runtime, separate from the three-process matrix above. The server uses CPUs 0 and 1; `wrk` uses CPUs 2 and 3, with 32 connections. Both routes completed without socket or non-2xx errors.*
+
+We checked HotSpot's compiled-method list during warmup: Spring's request dispatcher and handler adapter had reached tier-4 compilation. The snapshot is included in the reproduction bundle. The extra warmup does not close the gap for these two handlers. More complex application code, dependencies and different concurrency levels can change that comparison.
+
+The matrix rotates runtime order and reverses CPU order in its middle round. Every response body is checked before load; any socket or non-2xx error during warmup or measurement rejects the run. All 27 process runs completed without those errors. Keep-alive request limits are raised or disabled on both servers; other runtime settings use their defaults.
+
+### How long do you wait for a build?
+
+Native compilation moves work out of startup and into the build. You do not need to pay that cost after every edit: CN1's debug/development mode runs on the JVM, while the native build produces the deployment executable.
+
+| Build | Median elapsed, seconds | Three-run range, seconds |
+| --- | ---: | ---: |
+| Spring Boot / JDK 25 | 2.07 | 1.54-2.57 |
+| CN1 debug / JVM | 1.67 | 1.57-2.49 |
+| CN1 native | 95.34 | 75.43-107.08 |
+| Spring Boot / GraalVM 25 | 200.89 | 174.80-214.39 |
+
+[](/blog/native-http-charts/build-time.png)
+
+*Lower is better. Three builds per configuration, with runtime order rotated, on the same four-vCPU, `8 GiB` Linux VM. Application outputs are rebuilt each time; dependencies and toolchains are cached. Downloads, tests and server startup are excluded.*
+
+For this example, the CN1 native build takes **53% less elapsed time** than Spring/GraalVM. The JVM builds take seconds. That keeps the edit-and-debug loop short while letting you check the native artifact before deployment.
+
+The CN1 development measurement compiles the repository's `Bench` handler, JavaSE backend runtime and shared sources with JDK 25. The native path compiles Java with JDK 8, translates it, then compiles and links the generated C with Clang at `-O3`; the translator and Java API dependencies are prebuilt. Spring uses Maven `clean package` on JDK 25; its native build adds Spring AOT processing and GraalVM `native:compile`. These are build-path timings for the HTTP examples, including their different build tools, rather than isolated `javac` or incremental-build timings.
+
+The [reproduction bundle](/blog/native-http-comparison.zip) includes sources, commands, artifact hashes, every raw sample, the matched longer-warmup comparison, clean-output build timings, and the controller and transaction examples. The results make a small native backend worth trying for services with these constraints. Measure your own handlers and dependencies before using them to choose deployment capacity.
+
+## Start your service with less runtime setup
+
+Here is a complete controller for a backend module:
+
+```java
+package example;
+
+import com.codename1.backend.annotations.GetMapping;
+import com.codename1.backend.annotations.RestController;
+
+@RestController
+public class GreetingApi {
+ @GetMapping("/hello")
+ public String hello() {
+ return "Hello, World!";
+ }
+}
+```
+
+After `javac` compiles your sources, the build reads the annotations and generates Java classes for routing, dependency injection and method instrumentation. ParparVM translates the resulting bytecode to C, then the native compiler builds the executable.
+
+[](/developer-guide/img/backend-build-pipeline.svg)
+
+*From the current Backend guide. The generated classes are ordinary input to the translator and its dead-code analysis.*
+
+A generated `Router` holds the route as bytes and binds parameters according to their declared types. `BackendWiring` creates beans in dependency order. Missing dependencies, ambiguous candidates, constructor cycles and duplicate routes fail the build with the relevant class or injection point.
+
+The wiring constructs this controller and the `Notes` service in the next section with direct calls like these:
+
+```java
+b_greetingApi = new example.GreetingApi();
+b_notes = new example.Notes(
+ com.codename1.backend.Backend.requireDataSource(
+ dataSource, "constructor parameter 1 of example.Notes"));
+```
+
+There is no runtime search for a `Notes` constructor or a matching database bean. The call is in the generated program. With more dependencies, the build orders the constructor calls and emits field or setter injection afterward. A private `@Autowired` field gets a generated setter so the assignment can still be a direct call.
+
+This gives you a useful debugging option: follow the call into the generated code and see exactly what it constructs. It also lets the native linker remove unreferenced classes. You exchange some of Spring's runtime flexibility for a build that can resolve more of the application before deployment.
+
+## Keep your transaction when you call another method
+
+If you use Spring's usual proxy-based transactions, a call through `this` bypasses the proxy. That can make a refactor change transactional behavior even though the annotation is still on the method. Spring documents both the limitation and its bytecode-weaving alternative in the [proxying guide](https://docs.spring.io/spring-framework/reference/core/aop/proxying.html).
+
+Our build rewrites the annotated method itself. `@Transactional`, `@Async`, `@Timed` and `@Counted` therefore apply when another method on the same object calls it. They also apply to private methods and project classes you construct with `new`.
+
+For example, this service writes a note and an audit row in one transaction. Assume migrations have created `note(body)` and `audit(message)` in the configured database:
+
+```java
+package example;
+
+import com.codename1.backend.DataSource;
+import com.codename1.backend.annotations.Component;
+import com.codename1.backend.annotations.Transactional;
+import java.io.IOException;
+
+@Component
+public class Notes {
+ private final DataSource db;
+
+ public Notes(DataSource db) {
+ this.db = db;
+ }
+
+ @Transactional(rollbackFor = IOException.class)
+ public void add(String body) throws IOException {
+ db.execute("INSERT INTO note (body) VALUES (?)", new Object[] {body});
+ db.execute("INSERT INTO audit (message) VALUES (?)",
+ new Object[] {"note created"});
+ }
+}
+```
+
+What does the annotation become? The build moves the original method body into a separate method and wraps its call in transaction handling. This pseudocode shows the control flow for `Notes.add`; helper names and generated class layouts are implementation details:
+
+```text
+transaction = begin(REQUIRED, readOnly = false, timeout = none)
+try:
+ call original add(body)
+catch error:
+ rollback = error is IOException
+ or error is RuntimeException
+ or error is Error
+ or error is DataAccessException
+ completeAfterFailure(transaction, rollback)
+ rethrow error
+commit(transaction)
+```
+
+The body runs inside a transaction boundary regardless of how you reached `add`. On failure, the wrapper applies the rollback rule to that boundary and rethrows the error. Completing a joined transaction can mark the outer transaction for rollback; it does not necessarily commit or roll back the connection immediately. There is no runtime annotation lookup or proxy dispatch for this method. The [processor source](https://github.com/codenameone/CodenameOne/blob/master/maven/build-engine/src/main/java/com/codename1/maven/processors/BackendSources.java) and [bytecode weaver](https://github.com/codenameone/CodenameOne/blob/master/maven/build-engine/src/main/java/com/codename1/maven/processors/BackendWeaver.java) show how this is implemented.
+
+The database connection is borrowed lazily, at the first database operation. The method can return without touching the pool if it never accesses the database. `DataSource`, generated DAOs and managed ORM sessions join the transaction associated with the executing thread.
+
+[](/developer-guide/img/backend-transaction-propagation.svg)
+
+You can choose all seven propagation modes: `REQUIRED`, `REQUIRES_NEW`, `NESTED`, `SUPPORTS`, `MANDATORY`, `NOT_SUPPORTED` and `NEVER`. The important choices are what you want to happen when a transaction exists, and whether an inner failure should undo the outer work. `REQUIRES_NEW` needs another connection; `NESTED` uses a savepoint on the current one.
+
+Read-only declarations, timeouts and explicit rollback rules are supported. Isolation-level selection is not. An asynchronous task does not inherit its caller's transaction, and a database transaction cannot undo an email or an HTTP request. The [data chapter](/developer-guide/backend-data/) spells out these boundaries, including what happens when code touches more than one connection pool.
+
+## Handle more waiting requests without a thread per connection
+
+If your handler spends most of its time waiting for another server, an OS thread per connection is expensive. You want straightforward blocking code without making each wait occupy a host thread.
+
+On the Linux native HTTP path, each connection has a ParparVM virtual thread: a stack retained for the life of that connection. Host threads run those stacks. A host owns its connections and their `epoll` registrations; a virtual thread stays with that host. When the handler needs bytes that have not arrived, the runtime parks its stack and lets the host run another connection.
+
+[](/developer-guide/img/backend-architecture.svg)
+
+That applies beyond the incoming socket. PostgreSQL and MySQL queries use the same parking mechanism. Outbound HTTP, including its TLS handshake, can park too. Your service can wait for a query in ordinary sequential Java while other connections continue on the same host.
+
+{{< mermaid >}}
+sequenceDiagram
+ participant A as Request A
+ participant H as Host thread
+ participant DB as Database socket
+ participant B as Request B
+ H->>A: Resume handler
+ A->>DB: Send query
+ A-->>H: Park until socket is ready
+ H->>B: Run another handler
+ B-->>H: Finish response or park
+ DB-->>H: epoll reports readable socket
+ H->>A: Resume at the waiting call
+{{< /mermaid >}}
+
+Background tasks now participate in this model too. A virtual task has no incoming connection descriptor, so the host uses a wake pipe to notice newly submitted work. `Future.get()` on a virtual thread yields cooperatively while waiting for the task. Blocking the host there could otherwise stall the very task whose result the handler needs.
+
+This work also fixed a subtle scheduler failure: each yield site must report whether it is runnable or waiting for I/O. A stale reason could leave a handler stuck after `yieldNow()` or send an I/O wait back through the runnable path after garbage-collector backpressure. A virtual-thread API is only useful when those transitions remain correct under load.
+
+You still need to choose the right executor for your work:
+
+| Your operation | Native virtual-thread behavior | Practical choice |
+| --- | --- | --- |
+| Wait for PostgreSQL, MySQL or outbound HTTP | Parks at supported socket waits | Virtual threads suit this work |
+| Wait on an asynchronous task's `Future` | Yields cooperatively | A virtual handler can await virtual work |
+| SQLite, file access, DNS resolution or `Object.wait()` | Can block the host thread | Put blocking local work on a platform executor |
+| Incoming TLS server connection | Uses the platform-thread pool | Account for pool capacity |
+| JVM development run | Uses platform threads, including `VIRTUAL` tasks | Test native concurrency before deployment |
+
+These are ParparVM's virtual threads, not the JDK implementation. `ThreadKind.PLATFORM` remains the default for `@Async` and `@Scheduled`; `VIRTUAL` requests the native facility where available, and `AUTO` selects it when the server has virtual hosts. The [scheduling chapter](/developer-guide/backend-scheduling/) documents fallback behavior and named executors.
+
+## Schedule work without accidental duplicate runs
+
+A scheduled method runs outside the request thread. Use a fixed rate when you want starts at regular intervals, or a fixed delay when you want a pause after the previous run finishes. The distinction becomes visible as soon as the job takes longer than expected:
+
+[](/developer-guide/img/backend-schedule-timelines.svg)
+
+One job does not overlap itself within a process. If a fixed-rate job is still running at its next start, that start is skipped. The build validates the method signature and six-field cron expressions; configuration can supply the actual schedule.
+
+When you deploy several server instances, each instance has a scheduler. A database lock lets them coordinate one job across replicas. For example, `@Scheduled(fixedDelay = 60000, lock = "purge")` requests a shared lock. The lease must exceed the job's maximum runtime, since expiry permits another instance to claim it. You can inspect job state and skipped runs through the management endpoints.
+
+## Keep configuration and state explicit as your service grows
+
+The Spring-style surface extends beyond the three annotations in a demo:
+
+| What you need | API and behavior |
+| --- | --- |
+| Select an implementation | `@Primary` and `@Qualifier` resolve competing dependencies |
+| Bind deployment settings | `@Value` and `@ConfigurationProperties` bind configuration |
+| Enable an environment-specific bean | `@Profile` and `@ConditionalOnProperty` control activation |
+| Construct a library object | A `@Bean` factory supplies it explicitly |
+| Keep state for one request or session | `@Scope("request")` and `@Scope("session")` locate the current instance through generated stand-ins |
+| Initialize and shut down resources | `@PostConstruct` and `@PreDestroy` hooks participate in lifecycle management |
+| Measure or manage a service method | `@Timed`, `@Counted`, `@ManagedResource` and related annotations generate adapters |
+
+The build catches unresolved wiring, but runtime configuration can still deactivate a required bean or omit a necessary value. Request, session and lazy stand-ins need a non-final class and an accessible no-argument constructor. That constructor runs for the stand-in too. The [beans chapter](/developer-guide/backend-beans/) explains the supported combinations and their restrictions.
+
+Sessions use an in-memory or database store. They are created on demand, so an API that never asks for a session does not set a session cookie. Rotate the identifier at sign-in with `changeSessionId()`, and use the database store when multiple instances need to share session state. Session beans run their `@PreDestroy` or configured destroy method when the session is invalidated, found expired or closed at server shutdown. Expiry cleanup happens when a request encounters the expired session or triggers the periodic purge, rather than at the exact timeout instant.
+
+[](/developer-guide/img/backend-session-lifecycle.svg)
+
+There is no general `ApplicationContext` lookup, and an arbitrary JAR on the classpath does not become a compatible Spring bean library. Native backend sources currently use Java 8 language level against the supported runtime library. Packaged deployment targets Linux. Those boundaries help you decide whether a small service fits this backend before attempting a migration.
+
+## Keep your service visible across your enterprise
+
+An order can cross a client app, your native backend and several existing services. The backend can continue the incoming trace and propagate it on outbound HTTP calls so your operations team can follow that work in its existing observability system. Optional OpenTelemetry tracing and metrics are compiled into the executable, alongside management endpoints for health, jobs and application resources.
+
+The generated server has a defined request chain. Its own endpoints run before application routes, and static files come last. A wrapper handles request scope, session persistence and request metrics:
+
+[](/developer-guide/img/backend-request-lifecycle.svg)
+
+MCP gives your development tools a way to inspect the running service. An agent can list routes and beans, call an endpoint, inspect recent requests, and query database state through the development tools. You can publish application tools with `@McpTool`; the build generates their argument schemas and direct dispatch.
+
+Development tools are excluded from packaged servers by default. A production MCP endpoint requires a token. Tuesday's article connects the client and backend to an enterprise trace, then covers metrics and the MCP development workflow.
+
+To try the backend, start with the [backend guide](/developer-guide/backend/) and a small endpoint, then add a database operation and verify its rollback behavior. The implementation behind [PR #5908](https://github.com/codenameone/CodenameOne/pull/5908) is the basis for this week's expanded API.
+
+---
+
+## More This Week
+
+That is the backend story. The rest of the release reaches your app's UI, project structure and submission process. Here is a closer look at each upcoming post, plus a small maps improvement.
+
+### How your Java server uses less RAM
+
+**Saturday: {{< post-link path="/blog/parparvm-four-byte-header" text="Honey, I Shrunk Java" >}}**
+
+The server comparison above puts CN1's peak RSS at **`57.8 MiB`**, against **`117.0 MiB`** for Spring/GraalVM. Saturday explains the runtime work behind that smaller footprint: four-byte object headers, tighter fields, fewer temporary objects and changes to garbage collection. We will also look at the compiler translating itself faster than JDK 25, and explain how ParparVM's layout differs from HotSpot's compact headers and Leyden's AOT work. Headers are part of the saving; the whole server measurement includes code, stacks and libraries too.
+
+### Can your users spot the custom-rendered tab bar?
+
+**Sunday: {{< post-link path="/blog/ios27-glass-from-measurements" text="Can You Tell the Difference Between These iOS Tab Bars?" >}}**
+
+[Last week's iOS 27 theme](/blog/ios-27-glass-you-can-test/) still had motion I wasn't happy with. This comparison shows the refinement under taps, holds, and drags. Watch the original video; the small changes in timing and glass detail are the point.
+
+{{< guide-block >}}
+
+{{< /guide-block >}}
+
+*UIKit is above Codename One in this side-by-side simulator recording.*
+
+Sunday's post follows the reverse engineering from frame measurements to spring equations, vibrancy and lens rendering. You can judge the remaining differences and choose when to adopt the theme in your app.
+
+### Choose Gradle and start with fewer files
+
+**Monday: {{< post-link path="/blog/gradle-smaller-projects" text="Do You Prefer Gradle?" >}}**
+
+You can now start a smaller Gradle project and add platform directories when needed. A standalone backend no longer requires a client project alongside it. That makes the tree easier to navigate and leaves less boilerplate in an LLM's context. I still prefer Maven XML, for reasons involving the `make` files I lived with at Sun, but your preference should not block either project shape.
+
+
+We converted the repository's HelloCodenameOne sample: **358 files became 305**, and **nine POMs became two Gradle Kotlin files**. That is 53 fewer files around the same application. The count includes sources and resources, excludes generated build output, and comes from the actual converter.
+
+The generated `settings.gradle.kts` selects the build plugin:
+
+```kotlin
+plugins {
+ id("com.codenameone") version "8.0-SNAPSHOT"
+}
+rootProject.name = "HelloCodenameOne"
+```
+
+This is an excerpt; the generated file also configures plugin repositories. Use the release version containing Gradle support when it is published. Monday shows the full setup and conversion commands.
+
+The new [backend Javadocs](/backend/javadoc/) also separate server APIs from the [client reference](/javadoc/), with shared classes identified between them. Monday covers that split and the separate, experimental Gradle 9 Android build option. Choosing Gradle for your project and changing the Android builder's Gradle version are independent choices.
+
+### Bring your app into your enterprise traces
+
+**Tuesday: {{< post-link path="/blog/native-backend-observability" text="Connect Your App to Your Enterprise Traces" >}}**
+
+Your mobile or web app can be the start of a trace that crosses a native CN1 backend, existing Java services and a database. The client and server propagate the same trace context, so compiling the backend to native code need not leave a gap in your enterprise observability. You can use your existing OTel collector and tracing system, with collector credentials kept on the server.
+
+{{< mermaid >}}
+flowchart LR
+ App[CN1 client app] -->|traceparent| Native[CN1 native backend]
+ Native -->|traceparent| Java[Existing Java service]
+ Java --> DB[(Database)]
+ App -. app spans via relay .-> Collector[Enterprise OTel collector]
+ Native -. spans and metrics .-> Collector
+ Java -. service telemetry .-> Collector
+{{< /mermaid >}}
+
+Tuesday explains the setup, sampling and metric labels that keep telemetry manageable as traffic grows, plus MCP tools for checking the service during development. Downstream services must participate in trace propagation too.
+
+### Make your browser app feel like a native desktop app
+
+**Wednesday: {{< post-link path="/blog/browser-desktop-theme" text="Do You Want Your Web App to Feel Like a Native App?" >}}**
+
+Your web app can now use native desktop OS styling: macOS (Aqua), Windows (Fluent) or Linux (Adwaita). An optional HTML title and menu bar puts commands above the application. Additional OS windows remain unsupported in the JavaScript port because of browser popup restrictions; that does not exclude Windows browsers. The Certificate Wizard adopts the same desktop theme families, continuing last week's Settings work.
+
+[](/blog/desktop-theme-collage.jpg)
+
+*The Settings app shows the three desktop theme families now available in the JavaScript port.*
+
+### Read street names along the road
+
+There is a smaller maps improvement too: names now follow the road geometry, with curved glyph placement on bends and upright text along straighter sections. Labels remain above route overlays, so the route does not hide the street you need to follow.
+
+
+
+*From the Maps guide. The renderer rejects placements that bend too sharply or collide with other labels.*
+
+This is part of the continuing vector-map work in [PR #5902](https://github.com/codenameone/CodenameOne/pull/5902). The [Maps guide](/developer-guide/maps/) covers the renderer and deeper zooming without stretching raster tiles.
+
+### Your release also has to survive submission
+
+**Thursday: {{< post-link path="/blog/friday-release-better-gates" text="Don't Order Fish on Monday. Don't Release on Friday" >}}**
+
+A working simulator or device build can still import an API that Apple rejects at submission. In this case, the unwanted imports appeared only when particular optional APIs were enabled, so most apps and our usual test configuration missed them. The new check looks for imported SDK symbols without public declarations, exercises optional feature combinations and inspects a linked Release device app. It catches a class of mistake that another happy-path test would miss.
+
+This was a rough week of regressions around the optional Xcode 27 path, push, and windows. Some overlapped, so we thought we had fixed a bug only to discover its symptoms had moved. Thursday's post explains one of those failures, why we release on Friday despite the obvious cost to our weekends, and how better gates can protect your release from ours. The Apple check has a defined scope; it cannot guarantee App Store acceptance.
+
+There is a lot to try this week. There is also work to do on the reliability of getting it into your hands. I would like you to spend the next release testing something useful in your app, rather than helping us untangle a regression. That is why the gate work matters as much as the new features.
+
+---
+
+## Discussion
+
+_What would you need to see before trying a smaller native Java backend for one of your services?_
+
+{{< giscus >}}
diff --git a/docs/website/content/blog/native-backend-observability.md b/docs/website/content/blog/native-backend-observability.md
new file mode 100644
index 00000000000..745bec2fb71
--- /dev/null
+++ b/docs/website/content/blog/native-backend-observability.md
@@ -0,0 +1,211 @@
+---
+title: "Connect Your App to Your Enterprise Traces"
+slug: native-backend-observability
+url: /blog/native-backend-observability/
+date: '2026-10-06'
+author: Shai Almog
+description: "Connect your client app and native Java backend to distributed enterprise traces, export metrics through OpenTelemetry, and keep collector credentials on the server."
+feed_html: ' Connect your client app and native Java backend to distributed enterprise traces, export metrics through OpenTelemetry, and keep collector credentials on the server.'
+series: ["release-2026-10-02"]
+---
+
+
+
+Your customer taps “Place order.” The request crosses your app, an API gateway, a native backend, a payment service and a database. Your operations team needs to see that path in the same tracing system it uses for the rest of the company. Neither the client app nor a compiled Java server should disappear from that picture.
+
+I wrote a book on debugging, so I am probably more opinionated about this than most people: in 2026, production diagnosis should not depend on somebody searching a pile of logs with `grep` and guessing which lines belong together.
+
+Logs still matter. At enterprise scale, though, you need to connect work across machines, teams and runtimes, then see whether a failure is isolated or spreading. On a JVM, Java agents can instrument much of that work for us. Once our backend is translated to C and compiled into a native executable, the usual JVM instrumentation hook is gone.
+
+We have to carry that visibility into the binary. [OpenTelemetry support](/blog/follow-a-tap-with-opentelemetry/) started that work last week. The [expanded backend API](https://github.com/codenameone/CodenameOne/pull/5908) adds metrics and management alongside it. This article follows what happens after you turn them on.
+
+## Follow an operation across your systems
+
+Observability is the ability to understand a system's internal behavior from the evidence it emits. OpenTelemetry, usually shortened to OTel, defines APIs, data conventions and transport for producing that evidence. It is not itself the screen where you investigate an incident; a collector and an observability backend handle that part. The [OTel primer](https://opentelemetry.io/docs/concepts/observability-primer/) provides the broader model.
+
+| Question | Useful evidence |
+| --- | --- |
+| Why did this request take two seconds? | A trace connecting its operations |
+| Is database waiting increasing across the service? | Metrics over time |
+| What did the application decide at the failure? | Logs and events with context |
+
+A span records one timed operation. Related spans form a trace. Metrics aggregate behavior across operations: a count, a current value or a distribution such as request duration. Neither replaces the other. A single trace can explain a slow query without telling you how often it occurs.
+
+Our integration exports traces and metrics. It does not turn every application log into an OTLP log record.
+
+## Add tracing to your native executable
+
+Put this in the backend's `application.properties` before building:
+
+```properties
+cn1.otel.enabled=true
+```
+
+Or use the backend's `@OpenTelemetry` annotation. The generator installs the tracer, making its implementation reachable to the translator. Without that build-time opt-in, the unused tracing code can be left out. Setting an environment variable after deploying a binary that omitted the tracer cannot add it back.
+
+Once enabled, the runtime records an incoming request span named for its route template. A `Web` call creates a client span and propagates W3C trace headers. A database statement creates another client span. Incoming `traceparent` connects the request to its caller.
+
+{{< mermaid >}}
+sequenceDiagram
+ participant App as CN1 client app
+ participant Native as CN1 native backend
+ participant Service as Existing enterprise service
+ participant DB as Database
+ participant Collector as Enterprise OTel collector
+ App->>Native: Order request + traceparent
+ Native->>Service: HTTP call + traceparent
+ Service->>DB: SQL span under the same trace
+ DB-->>Service: Result
+ Service-->>Native: Result
+ Native-->>App: Response
+ App->>Native: Batched client spans via relay
+ Native->>Collector: Client spans + server spans + metrics
+ Service->>Collector: Existing service telemetry
+{{< /mermaid >}}
+
+The native backend propagates context on outbound `Web` calls. Each receiving service must accept and continue that context. OTel-compatible instrumentation lets those services participate regardless of their implementation language.
+
+## Include the client, not just the servers
+
+The client annotation belongs on your app's main class:
+
+```java
+import com.codename1.annotations.OpenTelemetry;
+import com.codename1.system.Lifecycle;
+
+@OpenTelemetry(
+ relay = "https://api.example.com",
+ relayToken = "replace-with-your-relay-token",
+ serviceName = "orders-app",
+ sampleRatio = 0.2,
+ requireAnalyticsConsent = true)
+public class OrdersApp extends Lifecycle {
+}
+```
+
+Replace the URL with your backend and the token placeholder with your relay token. Set the backend's `RELAY_TOKEN` environment variable to that same value. Enable its relay as shown below, and wire the app's analytics-consent flow before collecting telemetry. The client instruments supported app operations and `ConnectionRequest` calls, including outgoing trace context. It sends its recorded spans through the backend rather than carrying your collector credentials.
+
+For browser apps, context propagation is limited to the relay host and configured `propagateTo` hosts. A cross-origin service must allow the tracing headers in CORS. The [client tracing walkthrough](/blog/follow-a-tap-with-opentelemetry/) covers consent, propagation and the supported span types.
+
+That connects the experience on the device to the work behind it. A server-only trace cannot show the client work before the request or after the response. You can investigate that larger path in your enterprise tracing system instead of keeping a separate, disconnected account of what the app did.
+
+
+Database spans record SQL as supplied, with placeholders intact; bound parameters are not recorded. If an application concatenates a secret into SQL, the resulting text already contains it. `cn1.otel.attributes.exclude=db.query.text` can exclude that attribute. Parameterized SQL remains the better habit.
+
+WebSocket lifetime is outside this automatic request-span model. An hours-long connection with thousands of messages is not one useful HTTP request duration, and its upgrade is handled before this tracing path.
+
+## Send it to the system your team already uses
+
+For an enabled build, configure a collector at runtime:
+
+```bash
+export OTEL_SERVICE_NAME=orders-native
+export OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318
+export OTEL_TRACES_SAMPLER=parentbased_traceidratio
+export OTEL_TRACES_SAMPLER_ARG=0.1
+./build/Orders
+```
+
+Here `Orders` is the packaged application's executable. The ratio samples a tenth of newly rooted traces; the parent-based policy respects an upstream sampling decision.
+
+The exporter uses OTLP over HTTP, with protobuf by default and JSON as an option. It does not implement OTLP/gRPC. It appends `/v1/traces` or `/v1/metrics` to the base endpoint unless you supply a signal-specific endpoint.
+
+Dynatrace can receive that OTLP data. For traces, its [documented ingest endpoint](https://docs.dynatrace.com/docs/ingest-from/opentelemetry/otlp-api) is configured through `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`, with an ingest credential in `OTEL_EXPORTER_OTLP_HEADERS`. This uses explicit telemetry export; the translated server no longer has the JVM hooks used by Java instrumentation agents.
+
+A dedicated exporter thread batches spans. If the collector is slow or unavailable, request handling does not wait indefinitely for it. A bounded queue eventually drops spans and records the drops. That preserves the service at the cost of incomplete telemetry, which is itself a condition to monitor.
+
+## Track latency without a metric for every URL
+
+The server records request duration, active requests, open connections, database pool counts and task queue depth. Scheduled jobs report duration and outcome. The default metric export interval is one minute, using cumulative temporality.
+
+Route labels use `/orders/{id}`, not `/orders/81379`. Putting each order ID into a metric label would create a new time series for every order. Templates keep the series count bounded by the API's shape.
+
+The application can instrument a method too:
+
+```java
+package example;
+
+import com.codename1.backend.annotations.Counted;
+import com.codename1.backend.annotations.Component;
+import com.codename1.backend.annotations.Timed;
+
+@Component
+public class QuoteService {
+ @Timed
+ @Counted
+ public int quoteCents(int quantity) {
+ if (quantity < 1) {
+ throw new IllegalArgumentException("quantity must be positive");
+ }
+ return quantity * 250;
+ }
+}
+```
+
+This deliberately small example creates a duration histogram and call counters, including a failure counter. The default instrument names derive from the class and method. The build weaves the measurement into the method, so a call through `this` is measured too. For a real quote service, validate upper bounds and apply the application's monetary rules.
+
+`@ManagedResource`, `@ManagedAttribute` and `@ManagedOperation` offer a JMX-inspired model for current values and operator actions. Numeric managed getters become gauges. The management transport is the backend's own HTTP API; this is not a JVM JMX server hidden inside the native executable. Follow the [management configuration](/developer-guide/backend-observability/) before exposing operational actions.
+
+## Let an agent check the running application
+
+MCP, the Model Context Protocol, gives a development tool a structured way to ask the server questions. The backend serves tools for listing routes, inspecting beans, reading recent requests and querying the database. After editing a handler, you can call it and inspect the row it wrote from your development tool.
+
+A practical loop is:
+
+1. Start the backend on its development profile.
+2. Inspect `backend_routes`, `backend_beans` and `backend_schema`.
+3. Make the edit, then stop and restart the server. There is no hot reload.
+4. Exercise the handler with `backend_call`.
+5. Check `backend_requests`, `backend_sql` and `backend_metrics`.
+
+The default SQL tool uses a database-enforced read-only transaction unless its caller explicitly requests write access. An application can publish its own methods with `@McpTool`; the build derives JSON Schema from their supported parameter types and calls them directly.
+
+For a tool of your own, here is a complete bean using the generated dispatch:
+
+```java
+package example;
+
+import com.codename1.backend.annotations.McpParam;
+import com.codename1.backend.annotations.McpTool;
+import com.codename1.backend.annotations.Component;
+
+@Component
+public class QuoteTools {
+ private final QuoteService quotes;
+
+ public QuoteTools(QuoteService quotes) {
+ this.quotes = quotes;
+ }
+
+ @McpTool(description = "Returns a quote in cents for a positive quantity.")
+ public int quote(@McpParam("quantity") int quantity) {
+ return quotes.quoteCents(quantity);
+ }
+}
+```
+
+It reuses `QuoteService` above. The description tells an agent when the tool is relevant, and `@McpParam` supplies a stable argument name independent of compiler parameter metadata. Runtime authentication still has to be configured before serving it outside development.
+
+Development tools are omitted by `backendPackage` / `cn1:backend-package` unless deliberately enabled. Outside development, the MCP endpoint requires a bearer token. A tokenless development server is restricted to loopback. Origin checks also matter when a browser can reach that machine. The [MCP chapter](/developer-guide/backend-mcp/) spells out these boundaries.
+
+## Keep collector credentials off the phone
+
+An app can send its own spans through the backend relay. The relay validates the OTLP/JSON payload, applies size and span-count limits, then queues it for export using credentials held by the server.
+
+```properties
+cn1.otel.relay=true
+cn1.otel.relay.token=${RELAY_TOKEN}
+cn1.otel.relay.corsOrigin=https://app.example.com
+```
+
+The relay requires the client's `relayToken` to match `RELAY_TOKEN`; a missing or different token returns HTTP 401. The CORS setting is for a web app on another origin. An app-carried relay token is not an unextractable secret; the collector's ingest credentials should remain on the backend. A full queue returns 503 so the client can back off.
+
+Start with one real app action that crosses the native backend and an existing enterprise service. Verify that its spans share a trace ID in your collector, then check consent, sampling, queue drops and access to the relay before expanding collection. The goal is to make the app and its native server observable parts of the system your operations team already runs.
+
+---
+
+## Discussion
+
+_Which part of your application is hardest to connect to an end-to-end trace?_
+
+{{< giscus >}}
diff --git a/docs/website/content/blog/parparvm-four-byte-header.md b/docs/website/content/blog/parparvm-four-byte-header.md
new file mode 100644
index 00000000000..bdefddcda0c
--- /dev/null
+++ b/docs/website/content/blog/parparvm-four-byte-header.md
@@ -0,0 +1,177 @@
+---
+title: "Honey, I Shrunk Java"
+slug: parparvm-four-byte-header
+url: /blog/parparvm-four-byte-header/
+date: '2026-10-03'
+author: Shai Almog
+description: "ParparVM translates its compiler with 37.5% less time and 45.8% less peak memory in the Linux ARM64 baseline. See the object, compiler and GC changes behind it."
+feed_html: ' ParparVM translates its compiler with 37.5% less time and 45.8% less peak memory in the Linux ARM64 baseline. See the object, compiler and GC changes behind it.'
+series: ["release-2026-10-02"]
+---
+
+
+
+The current Linux ARM64 performance baseline has ParparVM translating its own compiler in **37.5% less elapsed time and 45.8% less peak memory than JDK 25**. Across all 16 recorded machine configurations, self-translation takes **22.5% to 56.6% less elapsed time**. The gains vary by OS and processor; the chart and table include every configuration. Your Java source does not need to change to benefit from a smaller runtime and a compiler that removes more work.
+
+[](/blog/runtime-diagrams/translation-baselines.png)
+
+These are the repository's [checked-in performance baselines](https://github.com/codenameone/CodenameOne/blob/60c4f310bddcfc51e5acc75c63a57c43c73430d3/vm/selfhost/perf-baseline.json), read on October 1. They are recorded reference results used to detect regressions, not new measurements made for this article. Each comparison runs the same translator classes on the two runtimes and verifies the generated files byte for byte.
+
+| Self-translation baseline | Elapsed time, ParparVM / JDK 25 | Peak memory, ParparVM / JDK 25 | Recorded calibration runs |
+| --- | ---: | ---: | ---: |
+| Linux ARM64, Neoverse N2 | 0.625 | 0.542 | 7 |
+| Linux x64, EPYC 7763 | 0.484 | 0.519 | 3 |
+| Linux x64, EPYC 9V45 | 0.495 | 0.539 | 1 |
+| Linux x64, EPYC 9V74 | 0.516 | 0.522 | 2 |
+| Linux x64, Xeon 6973P-C | 0.537 | 0.520 | 1 |
+| Linux x64, Xeon Platinum 8370C | 0.434 | 0.509 | 3 |
+| Linux x64, Xeon Platinum 8573C | 0.505 | 0.517 | 1 |
+| macOS ARM64 | 0.539 | 0.739 | 1 |
+| Windows ARM64, model D49 | 0.751 | 0.539 | 7 |
+| Windows ARM64, model D84 | 0.775 | 0.570 | 1 |
+| Windows x64, AMD family 25/model 1 | 0.606 | 0.542 | 7 |
+| Windows x64, AMD family 25/model 17 | 0.636 | 0.551 | 2 |
+| Windows x64, AMD family 26/model 2 | 0.611 | 0.546 | 1 |
+| Windows x64, Intel family 6/model 106 | 0.627 | 0.536 | 1 |
+| Windows x64, Intel family 6/model 173 | 0.677 | 0.549 | 1 |
+| Windows x64, Intel family 6/model 207 | 0.602 | 0.526 | 1 |
+
+*Lower is better in both columns. JDK 25 is 1.0. Each baseline is the median of the recorded runs' median ratios, with each platform using its available CPUs and runtime defaults. Translation time includes the whole process; Linux and macOS memory is peak RSS; Windows memory is peak working set. Some configurations have only one calibration run, as shown. They are separate machines, not a core-count scaling test.*
+
+A couple of weeks ago I wrote about [making ParparVM compile itself](/blog/parparvm-compiles-itself/). HotSpot beat us on elapsed time. That was disappointing, though hardly surprising. Since then we have worked on object layout, collections, generated C and garbage collection. The results above are a much better place to be.
+
+The smaller objects matter beyond the compiler benchmark. In [Friday's server comparison](/blog/java-server-work-before-startup/), CN1's native backend peaks at **`57.8 MiB` RSS**, against **`117.0 MiB`** for Spring/GraalVM, and rests at **`29.8 MiB`** after load against **`79.6 MiB`**. That compares complete HTTP stacks. Here we will look at the runtime changes that help make a smaller Java process possible.
+
+## What gets faster, and what still needs work?
+
+Self-translation is a substantial Java workload: allocating objects, walking collections, resolving methods and writing generated C. It is also our own compiler, so we should check other workloads before treating it as a verdict on Java performance.
+
+The complete Linux ARM64 baseline contains 13 workloads. ParparVM uses less peak memory in all 13 and less elapsed time in eight. Sequential array access takes 0.362 times the JDK's measured time; hash-map churn uses 0.121 times its peak process memory. Allocation remains an important weakness: that workload takes 3.043 times the JDK's time, even while using 0.239 times its peak memory.
+
+[](/blog/runtime-diagrams/arm64-baselines.png)
+
+*Each row combines seven calibration runs; each run compares the two runtimes in alternating order. Translation rows measure the complete process. The smaller workloads time repetitions inside the process after their own warmup, so JVM startup does not count against HotSpot. Memory is whole-process peak RSS in every row, not live heap.*
+
+The [performance harness](https://github.com/codenameone/CodenameOne/blob/master/vm/selfhost/perf-gate.py) checks workload results as well as time and memory. The original self-hosting post measured 1.56 seconds for HotSpot against 1.84 seconds for ParparVM. The opening charts show the later checked-in baselines after the optimization work; they are separate measurements, not a reinterpretation of that earlier result.
+
+Elapsed time and CPU time also answer different questions. Parallel JIT compilation and collection can reduce the wait while consuming more CPU across threads. That distinction helped guide the investigation, but it does not establish a battery saving: energy depends on the machine's power use over time. The current baseline records elapsed time and peak memory, so those are the claims we can make from it.
+
+## Why a tiny Java object needs a header
+
+An object header is runtime metadata stored alongside your fields. It lets the runtime identify the object's class and track information needed for collection and other operations. On a typical 64-bit HotSpot configuration, the header occupies 12 bytes; without compressed class pointers it can occupy 16. JDK 25's optional compact object headers reduce that to 8 bytes. [Oracle's JDK 25 GC guide](https://docs.oracle.com/en/java/javase/25/gctuning/other-considerations.html) documents the sizes and the `-XX:+UseCompactObjectHeaders` switch.
+
+This is the work associated with **Project Lilliput**. **Project Leyden** addresses startup, warmup and footprint through ahead-of-time work, including AOT caches. The names are easy to mix up, but shrinking each object's header and caching class-loading work solve different problems. See the [Leyden project](https://openjdk.org/projects/leyden/) for that distinction.
+
+| Runtime layout | Object header metadata | What the number excludes |
+| --- | ---: | --- |
+| HotSpot, compressed class pointers | 12 bytes | Fields, alignment and backing storage |
+| HotSpot, JDK 25 compact headers enabled | 8 bytes | Fields, alignment and backing storage |
+| ParparVM release layout | 4 bytes | Fields, alignment, side tables and backing storage |
+
+These are layout sizes, not a prediction of process memory. A small HTTP server can spend more of its resident memory on stacks, code, allocator pages and library state than on live Java object headers. The [server comparison](/blog/java-server-work-before-startup/) measures the whole process separately.
+
+The release object header carries a 16-bit class index, an 8-bit collection epoch and an 8-bit heap state. The class index addresses a closed-world class table instead of storing a pointer in every object. Objects requiring a legacy heap index use a side table keyed by address.
+
+[](/blog/runtime-diagrams/object-header.svg)
+
+The [runtime header](https://github.com/codenameone/CodenameOne/blob/master/vm/ByteCodeTranslator/src/cn1_globals.h) is explicit about the distinction between metadata and allocation. The C header struct remains eight-byte aligned. Small objects live in allocator size classes, and fields need alignment too. A four-byte header does not make an empty object a four-byte allocation.
+
+The translator packs eligible fields into the gap after the metadata. It stores fields at their real widths and orders them to reduce padding. A subclass must preserve its superclass layout as a prefix, so it cannot arbitrarily reach back and fill a hole belonging to an ancestor. That restriction sharply reduced the savings predicted by an early census.
+
+| Object in the experiment | Before | After four-byte header and root-field packing |
+| --- | ---: | ---: |
+| `VarOp` | 32 bytes | 24 bytes |
+| `ArrayList` | 32 bytes | 24 bytes |
+| `ByteCodeMethodArg` | 32 bytes | 24 bytes |
+| `BasicInstruction` | 40 bytes | 32 bytes |
+
+*Object sizes from the layout experiment. Backing storage is additional.*
+
+The [header-layout experiment](https://github.com/codenameone/CodenameOne/blob/60c4f310bddcfc51e5acc75c63a57c43c73430d3/vm/selfhost/experiments/REGISTRY.md#round-49-the-4-byte-header-and-why-it-is-worth-much-less-than-the-8-byte-one) measured one-core container RSS moving from 618 MB to 605 MB across five interleaved runs. That is useful, but much smaller than “we halved the header” might suggest. The page allocator and native collection buffers still occupy memory.
+
+There was a second trap. A static class table that named every class also kept those classes reachable to the native linker. The current implementation registers most entries as classes are used. Shrinking object metadata should not accidentally force otherwise unused classes into the executable.
+
+## Get less overhead from the same Java loop
+
+ParparVM translates bytecode to C. “Lowering” is the step that turns a higher-level operation into a representation the native compiler can optimize directly. We do not get that benefit merely by giving Clang a large pile of C functions.
+
+Consider a collection traversal. The ordinary implementation has an iterator object and virtual calls for `hasNext()` and `next()`. When the translator proves the exact collection layout, it can emit a native cursor loop. When it cannot prove the receiver, it can check the exact class once and retain the ordinary iterator as a fallback.
+
+{{< mermaid >}}
+flowchart TD
+ Loop[Collection traversal] --> Proof{Exact supported layout?}
+ Proof -->|Proved locally| Cursor[Native cursor loop]
+ Proof -->|Unknown receiver| Guard[Check exact class once]
+ Guard -->|Matches| Cursor
+ Guard -->|Other class| Iterator[Ordinary iterator]
+ Cursor --> Rules[Keep owner alive and preserve modification checks]
+{{< /mermaid >}}
+
+The owner must remain a GC root until the final native-buffer access. A raw pointer into a `malloc` block does not keep the Java owner alive. The emitted lifetime fence is therefore part of correctness, not optional bookkeeping to strip from a fast loop.
+
+Several related changes attack allocation and dispatch:
+
+- **Collection storage:** hash tables combine key, value and metadata slices into one native allocation. Reference slices still need tracing and write barriers. Moving them outside the managed heap does not make their Java references invisible to the collector.
+- **Strings and builders:** `StringBuilder` keeps Latin-1 bytes until it needs UTF-16. Proven temporary builders can use native storage while preserving ownership across helper calls and exceptions. `StringBuffer` retains its synchronization.
+- **Short string equality:** bounded loads compare short strings without an ordinary Java method call. Longer ranges still use `memcmp`; mixed encodings preserve their own comparison rules. The implementation must not read past the logical range just because a wide load would be convenient.
+- **Immediate array streams:** supported `Stream.of(array)` pipelines with known lambda callbacks can become one C loop. Escaping streams, unknown callbacks, `sorted`, `distinct` and unsupported terminals keep the lazy implementation.
+
+For example, this shape is eligible for the stream work when the surrounding method satisfies the proof:
+
+```java
+long count = java.util.stream.Stream.of(names)
+ .filter(name -> name.length() > 3)
+ .count();
+```
+
+Here `names` is a `String[]`. Eligibility is narrower than “streams allocate nothing.” Nor does seeing a loop in emitted C prove that the linked binary vectorizes it. The lowering audit checks generated code and linked instructions separately from elapsed-time measurements.
+
+## Keep your program correct when removing work
+
+A declared `List` type does not prove an `ArrayList` layout. `LocalReceiverTypes` tracks allocation provenance, and unknown parameters or factory results retain guards. Analysis is restricted to methods that need it, and the compiler drops the temporary frame information after capturing the proof. Optimizing the translated program should not require keeping an unnecessary analysis graph alive throughout translation.
+
+Direct calls also gain small C intrinsics for operations such as list access, string length, hashing and builder appends. They apply to calls whose target is resolved statically, with the ordinary implementation available off the fast path. Together with traversal lowering, this lets the C compiler see useful operations inside a loop instead of opaque calls at every step.
+
+Another pass removes instance fields the closed program never reads. It checks native-source references and conservatively keeps runtime fields and unresolved cases. Removing a dead reference field can save both its storage and the object it would otherwise retain. This pass is disabled for JavaScript output and on-device debugging.
+
+There is a semantic edge worth stating: the current [dead-field pass](https://github.com/codenameone/CodenameOne/blob/master/vm/ByteCodeTranslator/src/com/codename1/tools/translator/DeadFieldElimination.java) documents that assigning to a removed field on a null receiver no longer produces the JVM's `NullPointerException`. Its treatment of an unused store is therefore not a claim of identical behavior for every Java program. An application depending on that exception needs to account for this difference.
+
+## Fit the collector to the cores you have
+
+The small-object allocator groups objects into pages by size, often called BiBOP, short for “big bag of pages.” A nonmoving collector cannot return a page while one live object still occupies it. Free slots inside a partial page can be reusable capacity without being releasable memory.
+
+The experiments found 50 to 60 MB of free slots inside partial pages around one peak. Those slots were reused before new pages were allocated. Calling all of that a leak would send the investigation in the wrong direction.
+
+On one core, the generational collector can stop application work and collect young objects. With spare cores, the concurrent collector overlaps tracing with the application. The concurrent path needs grace for allocations that appear after a snapshot. That can retain dead objects longer, and shortening that lifetime requires preserving everything the snapshot could not yet see.
+
+We tried reclaiming dead large objects every single-core cycle. The first attempts were unsound. A growing output buffer could be allocated after the extent snapshot and remain live only in a thread's local state. If the collector could not resolve that pointer, it could free a live buffer.
+
+The fix registers those large objects from allocation and rebuilds the relevant snapshot at each thread's pause in that mode. The concurrent collector keeps its different grace rules. Applying one mode's shortcut to the other added locking to a hot path without providing a benefit.
+
+| One-core translation, five interleaved rounds | Minimum elapsed | Maximum RSS |
+| --- | ---: | ---: |
+| JDK 25 | 13.74 s | 557 MB |
+| Four-byte header before reclamation change | 10.29 s | 608 MB |
+| With large-object reclamation change | 9.84 s | 503 MB |
+
+*A separate Linux container experiment isolating the reclamation change: minimum elapsed and maximum RSS from five interleaved runs. Lower is better. Its four-byte-header control peaked at 608 MB; the header-layout experiment reported 605 MB in a different set of runs. The [reclamation experiment record](https://github.com/codenameone/CodenameOne/blob/60c4f310bddcfc51e5acc75c63a57c43c73430d3/vm/selfhost/experiments/REGISTRY.md#L6605-L6652) describes this later comparison. The opening charts show the current baseline.*
+
+We then reduced work in minor collections: skip an already-old page object before expensive conservative resolution, and consult the monitor table only for pages that have had monitors. The experiment record includes the unsuccessful alternatives too. Fewer object bytes help memory use. Avoiding thousands of unnecessary collector operations helps execution time too.
+
+## What changes for your app?
+
+If your application creates large graphs of small objects, the smaller headers and field packing can reduce their cost without a source rewrite. Proven collection traversals and stream pipelines can avoid temporary objects and dispatch. These are compiler and runtime changes, so you get them by rebuilding with a release that includes this work.
+
+The benefit depends on what your app spends time and memory doing. A form with a large model, an importer that walks collections, and a service that allocates objects continuously stress different parts of the runtime. The allocation result above is a reason to check a busy handler before assuming it will behave like the compiler benchmark.
+
+For an existing Codename One app, rebuild and compare a real interaction on your target device: startup, a large list or model load, and a sustained operation that creates objects. For a backend, compare resident memory at rest and under representative traffic, plus throughput and latency. Keep the input and build settings the same between releases. The [backend guide](/developer-guide/backend/) covers packaging a small service you can test this way.
+
+There is more room to improve. Our measurements point toward shorter-lived garbage in the concurrent collector and less overhead in small native collection buffers. A stop-the-world strategy saves memory on one core, but forcing it everywhere can lose too much execution time. The next step is to reduce that retention while preserving useful concurrency. That is an optimization direction, not a promise that one collector will win on every application.
+
+---
+
+## Discussion
+
+_When you compare runtimes, do you record CPU time as well as the time you waited?_
+
+{{< giscus >}}
diff --git a/docs/website/static/blog/browser-desktop-theme.jpg b/docs/website/static/blog/browser-desktop-theme.jpg
new file mode 100644
index 00000000000..eafe827bf2a
Binary files /dev/null and b/docs/website/static/blog/browser-desktop-theme.jpg differ
diff --git a/docs/website/static/blog/desktop-theme-collage.jpg b/docs/website/static/blog/desktop-theme-collage.jpg
new file mode 100644
index 00000000000..b6dcca3b4c9
Binary files /dev/null and b/docs/website/static/blog/desktop-theme-collage.jpg differ
diff --git a/docs/website/static/blog/friday-release-better-gates.jpg b/docs/website/static/blog/friday-release-better-gates.jpg
new file mode 100644
index 00000000000..257cd7f7a2a
Binary files /dev/null and b/docs/website/static/blog/friday-release-better-gates.jpg differ
diff --git a/docs/website/static/blog/gradle-smaller-projects.jpg b/docs/website/static/blog/gradle-smaller-projects.jpg
new file mode 100644
index 00000000000..1fe8ffdb6e0
Binary files /dev/null and b/docs/website/static/blog/gradle-smaller-projects.jpg differ
diff --git a/docs/website/static/blog/ios27-glass-from-measurements.jpg b/docs/website/static/blog/ios27-glass-from-measurements.jpg
new file mode 100644
index 00000000000..8b6e1b3ecf4
Binary files /dev/null and b/docs/website/static/blog/ios27-glass-from-measurements.jpg differ
diff --git a/docs/website/static/blog/ios27-measured-glass/dark-poster.jpg b/docs/website/static/blog/ios27-measured-glass/dark-poster.jpg
new file mode 100644
index 00000000000..509b35f0ae2
Binary files /dev/null and b/docs/website/static/blog/ios27-measured-glass/dark-poster.jpg differ
diff --git a/docs/website/static/blog/ios27-measured-glass/dark-tabs.mp4 b/docs/website/static/blog/ios27-measured-glass/dark-tabs.mp4
new file mode 100644
index 00000000000..b5cd30019f2
Binary files /dev/null and b/docs/website/static/blog/ios27-measured-glass/dark-tabs.mp4 differ
diff --git a/docs/website/static/blog/ios27-measured-glass/light-poster.jpg b/docs/website/static/blog/ios27-measured-glass/light-poster.jpg
new file mode 100644
index 00000000000..d478c147cd1
Binary files /dev/null and b/docs/website/static/blog/ios27-measured-glass/light-poster.jpg differ
diff --git a/docs/website/static/blog/ios27-measured-glass/light.mp4 b/docs/website/static/blog/ios27-measured-glass/light.mp4
new file mode 100644
index 00000000000..7bf753180ef
Binary files /dev/null and b/docs/website/static/blog/ios27-measured-glass/light.mp4 differ
diff --git a/docs/website/static/blog/java-server-work-before-startup.jpg b/docs/website/static/blog/java-server-work-before-startup.jpg
new file mode 100644
index 00000000000..d0a7a8904d9
Binary files /dev/null and b/docs/website/static/blog/java-server-work-before-startup.jpg differ
diff --git a/docs/website/static/blog/native-backend-observability.jpg b/docs/website/static/blog/native-backend-observability.jpg
new file mode 100644
index 00000000000..e4309d8b21e
Binary files /dev/null and b/docs/website/static/blog/native-backend-observability.jpg differ
diff --git a/docs/website/static/blog/native-http-charts/binary-size.png b/docs/website/static/blog/native-http-charts/binary-size.png
new file mode 100644
index 00000000000..03a604126f7
Binary files /dev/null and b/docs/website/static/blog/native-http-charts/binary-size.png differ
diff --git a/docs/website/static/blog/native-http-charts/build-time.png b/docs/website/static/blog/native-http-charts/build-time.png
new file mode 100644
index 00000000000..9b1084a380c
Binary files /dev/null and b/docs/website/static/blog/native-http-charts/build-time.png differ
diff --git a/docs/website/static/blog/native-http-charts/memory.png b/docs/website/static/blog/native-http-charts/memory.png
new file mode 100644
index 00000000000..79431d5928c
Binary files /dev/null and b/docs/website/static/blog/native-http-charts/memory.png differ
diff --git a/docs/website/static/blog/native-http-charts/startup.png b/docs/website/static/blog/native-http-charts/startup.png
new file mode 100644
index 00000000000..b458aec5d2b
Binary files /dev/null and b/docs/website/static/blog/native-http-charts/startup.png differ
diff --git a/docs/website/static/blog/native-http-charts/throughput.png b/docs/website/static/blog/native-http-charts/throughput.png
new file mode 100644
index 00000000000..7e39ae8d57e
Binary files /dev/null and b/docs/website/static/blog/native-http-charts/throughput.png differ
diff --git a/docs/website/static/blog/native-http-charts/warmed-throughput.png b/docs/website/static/blog/native-http-charts/warmed-throughput.png
new file mode 100644
index 00000000000..503dd8bc0b3
Binary files /dev/null and b/docs/website/static/blog/native-http-charts/warmed-throughput.png differ
diff --git a/docs/website/static/blog/native-http-comparison.zip b/docs/website/static/blog/native-http-comparison.zip
new file mode 100644
index 00000000000..dceae3229e7
Binary files /dev/null and b/docs/website/static/blog/native-http-comparison.zip differ
diff --git a/docs/website/static/blog/parparvm-four-byte-header.jpg b/docs/website/static/blog/parparvm-four-byte-header.jpg
new file mode 100644
index 00000000000..d656b8dae62
Binary files /dev/null and b/docs/website/static/blog/parparvm-four-byte-header.jpg differ
diff --git a/docs/website/static/blog/runtime-diagrams/arm64-baselines.png b/docs/website/static/blog/runtime-diagrams/arm64-baselines.png
new file mode 100644
index 00000000000..6305f1a6612
Binary files /dev/null and b/docs/website/static/blog/runtime-diagrams/arm64-baselines.png differ
diff --git a/docs/website/static/blog/runtime-diagrams/damped-spring.svg b/docs/website/static/blog/runtime-diagrams/damped-spring.svg
new file mode 100644
index 00000000000..5bf5326ff2f
--- /dev/null
+++ b/docs/website/static/blog/runtime-diagrams/damped-spring.svg
@@ -0,0 +1,268 @@
+
+
+
diff --git a/docs/website/static/blog/runtime-diagrams/object-header.svg b/docs/website/static/blog/runtime-diagrams/object-header.svg
new file mode 100644
index 00000000000..e4a64673bab
--- /dev/null
+++ b/docs/website/static/blog/runtime-diagrams/object-header.svg
@@ -0,0 +1 @@
+
diff --git a/docs/website/static/blog/runtime-diagrams/translation-baselines.png b/docs/website/static/blog/runtime-diagrams/translation-baselines.png
new file mode 100644
index 00000000000..e01448284e3
Binary files /dev/null and b/docs/website/static/blog/runtime-diagrams/translation-baselines.png differ