diff --git a/docs/website/content/blog/ar-vr-support-simulation.md b/docs/website/content/blog/ar-vr-support-simulation.md
new file mode 100644
index 00000000000..887d5ea38d3
--- /dev/null
+++ b/docs/website/content/blog/ar-vr-support-simulation.md
@@ -0,0 +1,97 @@
+---
+title: "AR And VR In Java: ARKit, ARCore, And A Virtual Room You Can Debug"
+slug: ar-vr-support-simulation
+url: /blog/ar-vr-support-simulation/
+date: '2026-07-12'
+author: Shai Almog
+description: "The new com.codename1.ar and com.codename1.vr packages bring world tracking, plane detection, anchors, stereo rendering and 360 panoramas to Codename One, with a simulated AR room so the whole loop is debuggable in the simulator."
+feed_html: ' World tracking, plane detection, anchors, stereo rendering and 360 panoramas, with a simulated AR room so the whole loop is debuggable in the simulator.'
+series: ["release-2026-07-10"]
+---
+
+
+
+This week's [release post](/blog/beating-hotspot-performance/) was about making the VM fast. Today's post is about pointing that VM at the real world. [PR #5335](https://github.com/codenameone/CodenameOne/pull/5335) adds two new core packages: `com.codename1.ar` for augmented reality on ARKit and ARCore, and `com.codename1.vr` for stereo rendering and 360 media on our portable GPU pipeline.
+
+## The Problem With Writing AR Code
+
+AR development has a miserable inner loop. The code only runs on a device, the interesting states are the ones you can't reproduce on demand (tracking loss, a plane that merges into another, a reference image entering the frame), and every debug cycle involves standing up and pointing a phone at your floor. Add a second platform SDK with different classes and coordinate conventions, and simple ideas become week-long jobs.
+
+So this feature has two halves that matter equally: a portable API over ARKit and ARCore, and a simulated AR backend so you can debug the whole loop sitting down.
+
+## The AR Package
+
+The API follows the same shape as the camera package: check support, open a session with options, get one view. World tracking, plane detection (horizontal and vertical), hit testing, anchors, light estimation, image tracking, and face tracking are all in. Placing a glTF model on a tapped surface looks like this:
+
+```java
+if (!AR.isSupported()) {
+ ToastBar.showInfoMessage("AR is not supported on this device");
+ return;
+}
+final ARSession session = AR.open(new ARSessionOptions());
+final ARView view = session.createView();
+
+Form f = new Form("AR", new BorderLayout());
+f.add(BorderLayout.CENTER, view);
+f.show();
+
+// modelBytes is a .glb asset, e.g. loaded from getResourceAsStream
+view.addPointerReleasedListener(e -> {
+ float xn = (e.getX() - view.getAbsoluteX()) / (float) view.getWidth();
+ float yn = (e.getY() - view.getAbsoluteY()) / (float) view.getHeight();
+ session.hitTest(xn, yn).ready(hits -> {
+ if (hits.length > 0) {
+ ARAnchor anchor = hits[0].createAnchor();
+ anchor.setNode(new ARNode(ARModel.fromGltf(modelBytes)));
+ }
+ });
+});
+```
+
+That code is identical on iOS and Android. Underneath, iOS composites an ARKit session through SceneKit and Android runs typed ARCore code, but the port never sees your glTF bytes: the core parses the model with a device-free loader and hands raw geometry buffers to the backend. That last detail is also insurance. Because the API exposes no SceneKit or ARCore types, the iOS backend can migrate to RealityKit later without breaking a line of your code.
+
+Threading follows normal Codename One rules. Every listener fires on the EDT, and high-frequency refinements (anchor updates, plane growth, camera pose, light estimates) are coalesced so a busy EDT sees the latest state rather than a backlog. You write ordinary event-driven code, no synchronization rituals.
+
+## The Simulated Room
+
+The simulator ships a full AR backend modeled on the Android emulator's virtual scene. Open a session and the simulator "detects" the floor of a virtual room after a realistic delay, the same way real plane detection takes a moment. Drag the mouse to look around, move with WASD, and hit test against the detected planes at mathematically exact points. Set a breakpoint inside your plane listener. It works, because it's all Java running in the same process.
+
+
+
+The Simulate menu gains an AR Simulation window for the states you can't summon on hardware: force degraded tracking with a chosen failure reason, change the light estimate, re-run plane detection, trigger recognition of a registered reference image, and toggle a simulated face anchor. The nastiest AR bugs live in exactly these transitions, and now they're a checkbox.
+
+## The VR Package
+
+`com.codename1.vr` takes the opposite approach: no platform SDK at all. It's pure core code built on the existing `com.codename1.gpu` pipeline and the motion sensors API from [last week](/blog/motion-input-form-factors/), so it runs anywhere `isGpuSupported()` is true, including the simulator.
+
+`VRView` renders your scene twice per frame, once per eye, with cameras offset by a configurable interpupillary distance; the offset is the depth cue. `HeadTracker` fuses the gyroscope, accelerometer, and magnetometer into a head orientation through a deterministic complementary filter, which means the fusion math is unit tested rather than eyeballed.
+
+
+
+The piece most apps will actually use is `Media360View`, an equirectangular panorama viewer with drag and gyroscope look-around, in mono or cardboard-style stereo:
+
+```java
+Media360View pano = new Media360View();
+pano.setImage(EncodedImage.create("/panorama.jpg"));
+f.add(BorderLayout.CENTER, pano);
+```
+
+
+
+## What It Costs Your Build: Nothing, Unless You Use It
+
+The build pipeline treats AR like the camera and car APIs: referencing `com.codename1.ar` is what injects the camera permission, the ARCore Gradle dependency, and the manifest entries, and marks ARCore as optional so your app still installs on devices without it (flip `android.ar.required=true` for an AR-only app). On iOS, ARKit is linked only for apps that use the API and compiled out on tvOS and watchOS. Apps that never touch the package pay no size, permission, or store-visibility cost.
+
+## Scoped Out, On Purpose
+
+Two things are deliberately missing rather than stubbed: 360 video and lens distortion correction. Video needs a media-to-texture path and distortion needs render-to-texture, and we'd rather ship no API than a placeholder that changes shape later. `Media360View.setTextureSource()` is the documented extension point that dynamic content, including future video, will arrive through. Also worth knowing: face tracking regions differ per platform (ARCore gives you the nose and forehead, ARKit the eyes), so region lookups can return null and your code must expect that.
+
+Tomorrow closes the week with the other end of the pipeline: once the app is built and signed, getting it into the App Store, Google Play and Huawei AppGallery automatically, with your store listing checked into git.
+
+---
+
+## Discussion
+
+_Join the conversation via GitHub Discussions._
+
+{{< giscus >}}
diff --git a/docs/website/content/blog/automated-store-submissions.md b/docs/website/content/blog/automated-store-submissions.md
new file mode 100644
index 00000000000..36fa3648857
--- /dev/null
+++ b/docs/website/content/blog/automated-store-submissions.md
@@ -0,0 +1,105 @@
+---
+title: "Store Submissions As Code: App Store, Google Play, And Huawei AppGallery"
+slug: automated-store-submissions
+url: /blog/automated-store-submissions/
+date: '2026-07-13'
+author: Shai Almog
+description: "Automated store submissions ship this week: one-click delivery to the App Store, Mac App Store, Google Play, and Huawei AppGallery, with your listing text and screenshots versioned in git and pushed with mvn cn1:metadata-push. Plus organization accounts and self service account deletion."
+feed_html: ' One-click delivery to the App Store, Google Play, and Huawei AppGallery, with your listing versioned in git and pushed with mvn cn1:metadata-push.'
+series: ["release-2026-07-10"]
+---
+
+
+
+This closes out [the release week](/blog/beating-hotspot-performance/). Saturday's [certificate wizard](/blog/standalone-certificate-wizard/) got your app signed. Today's feature handles what comes after the build finishes: uploading the binary, filling in the release notes, updating the listing, and doing it on every store where your users are. [PR #5353](https://github.com/codenameone/CodenameOne/pull/5353) covers the client tooling; the heavy lifting lives in the build cloud.
+
+## After The Build Turns Green
+
+A release isn't done when the build turns green. Someone still uploads the `.ipa` to App Store Connect, pastes the what's-new text into two or three web consoles, re-uploads screenshots because the store flagged one, and repeats the ritual per locale. For a single app it's an annoying hour. For a team maintaining ten apps across App Store, Google Play and AppGallery, it's a part-time job that produces nothing except copy-paste errors.
+
+The obvious prior art is fastlane, which has automated this for years and works well if you maintain a Ruby toolchain and per-store lane configs. Ours is built into the pipeline that already builds and signs your binary, reuses the credentials you already stored, and covers AppGallery.
+
+The build console now has a Submit action on every successful build: to the App Store for an iOS `.ipa`, the Mac App Store for a `.pkg`, and Google Play or Huawei AppGallery for Android. Pick Beta or Production, add release notes, and the binary is delivered. For an Apple production submission the console tracks the review state (processing, in review, approved or rejected) and can email you when it changes.
+
+The boundary, stated plainly: automated submission delivers binaries and metadata to an existing app record. Creating the app record and answering the privacy and content-rating questionnaires are one-time manual steps in each store's console, and our pipeline deliberately stays out of pricing and in-app purchase setup. After that one-time setup, every release's binary and listing ship automatically.
+
+## Your Listing Is Code Now
+
+The part I like most is `cn1:metadata-push`. Your store listing, the description, subtitle, keywords, what's-new text and screenshots, becomes a folder of plain files in your repo:
+
+```
+cn1-metadata/
+ apple/
+ en-US/
+ name.txt (max 30 chars)
+ subtitle.txt (max 30 chars)
+ description.txt (max 4000 chars)
+ keywords.txt (comma separated)
+ whats_new.txt
+ screenshots/
+ APP_IPHONE_67/1.png 2.png ...
+ google/
+ en-US/
+ name.txt
+ subtitle.txt (short description, max 80 chars)
+ description.txt
+ whats_new.txt
+ screenshots/
+ phoneScreenshots/1.png 2.png ...
+```
+
+The file names are neutral and map to each store's fields: `subtitle.txt` becomes the App Store subtitle and the Google Play short description. A file you don't include leaves the store's current value alone. `mvn cn1:metadata-init` scaffolds the whole layout, and pushing is one command:
+
+```bash
+mvn cn1:metadata-push # both stores from cn1-metadata/
+mvn cn1:metadata-push -Dstore=apple # or just one
+```
+
+Every field is validated against the store's limits before it's stored, so an over-long name fails fast on your machine instead of mid-submission. The pushed metadata is applied the next time you submit a build for that package, and applying is best-effort by design: the binary is delivered first, so a rejected field never blocks a release, it just shows as a warning in the console.
+
+Because the listing lives in git and pushes from the command line, it fits CI: generate `whats_new.txt` from your changelog, push, submit. Ten apps stop being ten consoles.
+
+{{< mermaid >}}
+flowchart LR
+ A["cn1-metadata/ in git"] -->|mvn cn1:metadata-push| B["Build cloud"]
+ C["Successful build"] -->|Submit| B
+ B --> D["App Store"]
+ B --> E["Google Play"]
+ B --> F["Huawei AppGallery"]
+{{< /mermaid >}}
+
+## Beyond Google Play
+
+Here's the narrative part, and we might as well say it directly. Google ships an app store and an app framework, and its tooling naturally treats Play as the finish line. We don't have a store, so we have no stake in which one wins. Our job is maximum audience with minimum friction, whatever the store.
+
+That matters because a large share of Android users can't install from Google Play at all: most of the market in China, plus many Huawei devices elsewhere. AppGallery is therefore a first-class submission target, exactly like the App Store and Play. For the long tail of Android markets (Xiaomi, OPPO, VIVO, Tencent MyApp, and the rest), the build can produce distribution-channel packages: your same signed release APK stamped with a per-store channel id, which your app reads back at runtime with `Display.getInstance().getProperty("DistributionChannel", "")` for install-source reporting, no third-party SDK involved. Play itself always receives the standard, unmodified App Bundle, so none of this touches your Play compliance.
+
+Credentials are per store and configured once in the console: the same App Store Connect API key the certificate wizard stored on Saturday, a Google Play service account, and a Huawei API client id and secret.
+
+
+
+On pricing: manual submission, downloading your build and uploading it yourself, stays unlimited and free on every tier, as it always was. The plan limits apply only to the automated pipeline.
+
+## Organization Accounts
+
+Two smaller build cloud changes shipped alongside this, and they fit the same theme of teams shipping many apps.
+
+Build cloud accounts can now belong to an organization. Members share visibility into the apps the team builds, the analytics and crash reports around them, and common data like the submission credentials above, while builds and quotas remain individual. Seats and the subscription are billed to the organization instead of a personal card.
+
+
+
+And accounts now have self service deletion. No support ticket, no email exchange: a danger zone section in account settings permanently removes your account and all of its data, including signing certificates, builds, crash and analytics data, and billing records. If you leave, you shouldn't have to ask permission to take your data with you.
+
+
+
+## Wrapping The Week
+
+That's the release: a VM that [trades blows with warmed HotSpot](/blog/beating-hotspot-performance/), a [certificate wizard that stopped impersonating you](/blog/standalone-certificate-wizard/), [AR you can debug at your desk](/blog/ar-vr-support-simulation/), and a release pipeline that ends in the stores instead of at the binary. The submission flow is documented end to end in the developer guide's new App Store Submission chapter. Try it on your next release, and tell us where it creaks.
+
+---
+
+## Discussion
+
+_Join the conversation via GitHub Discussions._
+
+{{< giscus >}}
diff --git a/docs/website/content/blog/beating-hotspot-performance.md b/docs/website/content/blog/beating-hotspot-performance.md
new file mode 100644
index 00000000000..63ce7825de4
--- /dev/null
+++ b/docs/website/content/blog/beating-hotspot-performance.md
@@ -0,0 +1,301 @@
+---
+title: "How We Beat HotSpot Performance (By Cheating, But Not Like That)"
+slug: beating-hotspot-performance
+url: /blog/beating-hotspot-performance/
+date: '2026-07-10'
+author: Shai Almog
+description: "ParparVM went from 4.21x slower than warmed Java 25 to geomean parity, with six of ten benchmarks at or below HotSpot and peak memory below the JVM's. The architecture behind it: frameless C codegen, a BiBOP page heap, and a poor man's Valhalla."
+feed_html: ' ParparVM went from 4.21x slower than warmed Java 25 to geomean parity, with peak memory below the JVM''s. The architecture behind it, in C terms.'
+series: ["release-2026-07-10"]
+---
+
+
+
+No, we didn't cheat in the benchmark. At least I hope we didn't. Every optimization in this story was gated on bit identical output checksums against HotSpot, and the harness refuses to print a ratio when a checksum differs. If anything, this post is about how good HotSpot actually is. We tilted the table in our favor in every way we could, we hand tuned C code, and we still only beat it on some benchmarks. Getting there was a genuine struggle. If you want to understand the nuts and bolts of what your Java code costs, and the tradeoffs each runtime picks, I hope this is a good read.
+
+The short version: [PR #5327](https://github.com/codenameone/CodenameOne/pull/5327) takes ParparVM, the AOT VM that compiles your Java bytecode to C for iOS and other targets, from 4.21x slower than warmed Java 25 to geomean 1.00x parity across a ten benchmark suite, with six of the ten at or below HotSpot. Along the way you'll meet a new page based heap, a poor man's Project Valhalla, code generation that finally lets clang do its job, and two places where HotSpot beat our hand written C anyway. The memory story ends even better than the speed story.
+
+But before we get to that, a few announcements.
+
+## Before You Update
+
+The optimizations below landed this week. Performance was gated on bit identical output vs HotSpot on every commit. Correctness went further: 63 test pipelines ran across the ports, with torture suites for maps, string builders, threads, and GC stress, in both cooperative and forced signal stop modes, and we squashed every bug we found along the way, several of them in ports far from the VM. But this is a deep change to code generation, allocation, and collection. Like any change of this scale, there's risk.
+
+If a build misbehaves, pin to the previous release with [versioned builds](https://www.codenameone.com/blog/versioned-builds-master/) and let us know through the usual channels. That's exactly the case versioned builds exist for.
+
+There's a lot more shipping this week beyond the VM work; the bottom of this post links to the daily posts covering it.
+
+## The Starting Point
+
+Client VMs are a different beast. The joke around here is that I built ParparVM in two weeks and Steve spent the next three years fixing bugs. When I built it, throughput wasn't a priority at all. I was aiming for simplicity, reliability, and consistency. What actually matters for client performance is startup time, memory footprint, low latency, and fast native access. 90% of client code time should be spent in rendering and IO, and in Codename One those paths are handcrafted native code on each platform, already tuned to the metal.
+
+Occasionally a customer would complain about performance, we'd add an optimization for that specific case, and we'd move along. We profiled common use cases, they were fine, and we never treated VM throughput as a problem. Comparing against HotSpot wasn't even on the table. You can't out-optimize a JIT, and we didn't run on the same platforms anyway. Now that we have desktop ports, people are porting heavier workloads and running direct comparisons on the same hardware. I assumed we were 2x or 3x slower than warmed HotSpot, ignoring startup.
+
+I was really, really off. Measuring it took some surgery: ParparVM normally exists to run Codename One, so we hacked it to run standalone, without the framework, and the suite measures the VM alone rather than the framework on top of it. The reference is OpenJDK 25 with full warmup, and warmed is the fair way to measure it: Java 25 ships ahead of time class loading and method profiles, so a deployed app can reach that warmed state quickly rather than earning it over thousands of iterations. Here's the starting point on an Apple M2, identical checksums on both runtimes:
+
+| Benchmark | What it stresses | ParparVM vs Java 25 |
+|---|---|---:|
+| hashMapChurn | HashMap put/get with autoboxing | **36.2x slower** |
+| stringBuilding | StringBuilder append and hash | **22.7x slower** |
+| objectAllocation | Allocation and GC churn | **19.6x slower** |
+| recursion | Deep call chains (fib) | **7.6x slower** |
+| arraySequential | Fill and reduce | **3.7x slower** |
+| quicksort | Compare, swap, recurse | **1.8x slower** |
+| longArithmetic | 64-bit ALU chain | **1.5x slower** |
+| intArithmetic | 32-bit ALU chain | **1.3x slower** |
+| mathTranscendental | sqrt/sin/cos | **1.1x slower** |
+| arrayRandom | Cache-miss gather | **1.0x** |
+
+Geomean: 4.21x slower. This was really bad.
+
+Spoiler: after everything below, this is where the same suite landed.
+
+| Benchmark | Final ratio | | Benchmark | Final ratio |
+|---|---:|---|---|---:|
+| stringBuilding | **0.67x** | | arrayRandom | 0.96x |
+| arraySequential | **0.82x** | | intArithmetic | 1.07x |
+| quicksort | **0.92x** | | longArithmetic | 1.12x |
+| hashMapChurn | **0.95x** | | objectAllocation | 1.19x |
+| mathTranscendental | **0.96x** | | recursion | 1.60x |
+
+Geomean 1.00x. Below 1.0 means we beat warmed HotSpot C2. Same Java source, same checksums, best of 5 interleaved runs. The interleaving isn't decoration: early on, sequential A-then-B timing on the M2 carried a 10 to 15% thermal bias that made one change look 1.5x faster when it was worth 3%, so the harness alternates the two VMs within a run.
+
+One methodology note before you ask: the comparison runs on macOS because HotSpot doesn't run on iOS. The same generated C ships to every Apple target, so the codegen wins carry over to devices where the JIT can't follow.
+
+{{< mermaid >}}
+xychart-beta
+ title "Final time ratio vs warmed Java 25"
+ x-axis [stringB, arrSeq, qsort, hashMap, mathT, arrRand, intA, longA, objAlloc, recurse]
+ y-axis "ParparVM time / HotSpot time" 0 --> 1.8
+ bar [0.67, 0.82, 0.92, 0.95, 0.96, 0.96, 1.07, 1.12, 1.19, 1.6]
+{{< /mermaid >}}
+
+Lower is better and 1.0 is HotSpot; everything left of intArithmetic finishes ahead of it. The starting ratios wouldn't fit on this chart. hashMapChurn began at 36.
+
+### The Memory Story
+
+Speed is only half the report, and for client apps it's the less important half. RAM is where this release moves the most:
+
+| Metric | master | this PR | Java 25 |
+|---|---:|---:|---:|
+| Binary size (bench app) | 434 KB | 451 KB (+3.8%) | n/a |
+| Memory floor (no-op app) | 2.2 MB | 2.4 MB | ~40 MB |
+| Peak memory (allocation churn) | 1.4 to 2.1 GB | **290 to 390 MB** | 508 MB |
+
+{{< mermaid >}}
+xychart-beta
+ title "Peak memory under allocation churn (MB)"
+ x-axis ["master (trigger bug)", "this PR", "Java 25"]
+ y-axis "MB" 0 --> 2200
+ bar [2100, 390, 508]
+{{< /mermaid >}}
+
+Master's gigabyte peaks were a real GC bug this work exposed: the allocated-since-last-collection counter was a 32-bit int counting bytes. Workloads that allocate gigabytes per cycle wrapped it negative, the "am I allocating fast?" check answered no, and the collector slept through the storm while dead pages piled up. With the trigger fixed, heavy churn peaks *below* the JVM on the same workload, and the idle floor stays where a phone wants it: 2.4 MB. Sit with that pair for a second, because it's the whole thesis of this VM. Trading blows with warmed HotSpot on speed while holding a 2.4 MB floor against its ~40 MB.
+
+## How Did We "Cheat"?
+
+The one advantage we have over HotSpot is that we're not Java. Not really. We bill ourselves as a tool that lets Java developers ship their Java apps to mobile devices. See what we did there? You write Java code, so it's a Java app. But we're not really Java in some major ways, and that gives us freedom HotSpot doesn't have.
+
+We compile a closed world. There's no dynamic class loading, so we know every class that will ever exist. There's no reflection (`Class.forName()` exists in a limited form, and that's roughly the extent of it), so a method nobody calls is a method we can delete, and a virtual call with exactly one reachable implementation is a direct call. The API is smaller, so there's less legacy behavior to preserve. And we can play fast and loose with some nuanced VM behaviors that HotSpot must keep exactly (more on `Integer` identity below).
+
+Without this cheating we would have lost every benchmark in the group. HotSpot carries a quarter century of engineering, and we wouldn't be able to come close playing "fair". Even with these structural advantages, we had to spit blood to get to a competitive point.
+
+## What The C Compiler Actually Sees
+
+ParparVM translates bytecode to C and lets clang optimize it. So the whole game is: how much does the generated C look like the C a human would write? The answer, at the start, was "not at all". Every Java method pushed a GC visible frame of type tagged slots and routed every intermediate value through it:
+
+```c
+/* BEFORE: one heap-visible frame per call, every value tagged and in memory */
+JAVA_LONG fib(CODENAME_ONE_THREAD_STATE, JAVA_INT n) {
+ stack = pushFrameOnThreadStack(threadStateData, locals=2, stack=4);
+ memset(stack, 0, 6 * sizeof(elementStruct)); /* on EVERY call */
+ locals[0].type = CN1_TYPE_INT; locals[0].data.i = n;
+ (*SP).type = CN1_TYPE_INT; (*SP).data.i = 2; SP++;
+ if (locals[0].data.i < SP[-1].data.i) ... /* compare via memory */
+ releaseForReturn(threadStateData, ...);
+}
+```
+
+That frame is how the GC finds live objects. It's also why clang couldn't keep anything in a register. Methods the translator can now prove safe (no try/catch, no synchronization, object roots covered by the native stack scan) compile to the C you'd write by hand:
+
+```c
+/* AFTER: locals are C locals, so they become registers */
+JAVA_LONG fib(CODENAME_ONE_THREAD_STATE, JAVA_INT n) {
+ JAVA_INT ilocals_0_ = n;
+ CN1_FRAMELESS_SOE_GUARD(0); /* stack-overflow check, nothing else */
+ if (ilocals_0_ < 2) return ilocals_0_;
+ return fib(threadStateData, ilocals_0_ - 1) + fib(threadStateData, ilocals_0_ - 2);
+}
+```
+
+Between this and its follow-ups, recursion went from 7.6x to 1.6x. More importantly, frameless codegen feeds every other optimization, because once values live in registers the rest of clang's optimizer wakes up.
+
+### Why We Still Lose Recursion
+
+The remaining 1.6x on recursion is HotSpot's speculative inlining, and we accepted it. A JIT watches the program run, notices that `fib` calls `fib`, inlines it into itself several levels deep, and keeps a deoptimization escape hatch in case its bet goes wrong. An ahead-of-time compiler doesn't get to gamble. It has to emit code that's correct for every possible execution, so a real call remains a real call. This is the structural advantage of a JIT and no amount of hand tuning closes it. If your workload is deep recursive call chains, HotSpot is simply the better machine for it.
+
+### The Bounds Check That Poisoned Every Loop
+
+Java requires an index check on every array access. The check itself is cheap. What killed us was the shape of the failure path. Our bounds check helper threw the exception and then returned a dummy value, so the "failed" path rejoined the loop. That means every loop iteration contained a reachable function call, and clang must assume a call can modify any memory. So it reloaded the array pointer and the array length from memory on every single pass:
+
+```c
+/* BEFORE: while (a[i] < pivot) i++; -- quicksort's scan loop */
+label_scan:
+ if (cn1_array_element_int(ts, locals[0].data.o, i) >= pivot) goto done;
+ /* on bounds failure: throwException(...); return 0; ...and REJOIN.
+ A call is reachable on every iteration, so clang reloads
+ array->data AND array->length every pass: 3 loads per element. */
+ i++;
+ goto label_scan;
+```
+
+The fix is to make the failure path diverge. Throw and return from the method, the same way the stack overflow guard works. Now no cycle of the loop contains a call, and clang hoists the loads out of the loop:
+
+```c
+/* AFTER: the throw path leaves the function; the loop is load/compare/branch */
+label_scan:
+ { JAVA_OBJECT a = locals[0].data.o; JAVA_INT idx = i;
+ CN1_ARRAY_CHECK_DIVERGE(a, idx, ); /* null/oob -> throw; return */
+ if (((JAVA_ARRAY_INT*)(*(JAVA_ARRAY)a).data)[idx] >= pivot) goto done; }
+ i++;
+ goto label_scan;
+```
+
+We measured the check itself against a pure C control at identical flags: raw C runs the sort in 91ms, C with diverging bounds checks in 98ms. So the safety Java mandates costs about 8% when the surrounding code is right. With the fix, the benchmark sort dropped from 216ms to 164ms, vs HotSpot's 197ms. Quicksort ended at 0.92x, below HotSpot, while keeping every check.
+
+### Where HotSpot Beat Our Hand-Tuned C
+
+On intArithmetic and longArithmetic we wrote plain C controls, no VM, no GC, just the loop, compiled with the same clang flags. The generated ParparVM code ran at exact parity with the hand written C: 94.0ms vs 93.7ms, and 59.7ms vs 59.3ms. Zero VM overhead.
+
+HotSpot still won, 1.07x and 1.12x. The residual is C2 reassociating the loop-carried dependency chain better than clang schedules it. On a tight arithmetic loop, HotSpot C2 generates better machine code than clang -O3 given identical semantics. The JIT sees the actual hot loop and its actual dependency graph and optimizes exactly that. We declared those benchmarks done, because when the gap between you and HotSpot is the same as the gap between clang and HotSpot, the VM is no longer the story.
+
+There's one footnote worth stealing for any C-generating project: Java integer semantics require `-fwrapv -fno-strict-aliasing`. Without `-fwrapv`, clang -O3 provably miscompiles overflowing accumulation loops. Our checksum gate caught it, off by exactly 2^32 per overflow.
+
+## Memory: Two Philosophies
+
+The worst starting numbers, the 20x to 36x ones, weren't about code generation at all. They were about memory, and to understand them you need to see how differently the two VMs think about it.
+
+HotSpot asks the OS for one large block up front and manages everything inside it. That buys enormous speed. Allocation is a pointer bump into a thread-local slab, and because HotSpot owns the entire address range, a single address comparison can tell it which region or generation an object belongs to. Owning the addresses simplifies reasoning across the whole VM: barriers, card tables, generation checks, all of it gets cheaper when "where is this object?" is arithmetic.
+
+ParparVM went the other way: we allocate through the OS's own malloc, calloc, and free. For years that looked like the slow, naive choice, and parts of it were slow. We keep it anyway, because it buys three things a client VM cares about more than benchmark points:
+
+- **Direct native access.** Native code and the GPU see our objects as ordinary memory, no pinning, no copying at a heap boundary. That's what makes fast SIMD and rendering paths practical.
+- **Real tooling.** Native profilers and leak detectors (Instruments, Valgrind, and friends) understand our memory, because it is ordinary memory, not a black-box block they can't see into.
+- **A true footprint.** The process holds only what the app actually uses. On constrained devices that's smaller, and what the OS reports for your app is what your app really costs.
+
+### A Big Bag Of Pages
+
+The 19.6x objectAllocation gap was the bill for taking that philosophy too literally. Every `new` was a malloc, a full memset to zero, and an O(n) search for a tracking slot under a lock.
+
+The new allocator is a BiBOP heap, short for "big bag of pages," and it's the largest single architectural change in the PR. The heap is organized as pages, each holding objects of a single size class. The size class of your object is known at compile time, so the allocation the C compiler sees is a pointer bump:
+
+```c
+/* Inlined at the allocation site */
+CN1BibopPage* p = bibopCurrent[SIZE_CLASS]; /* compile-time size class */
+o = page_slot(p, p->bumpIndex++); /* pointer bump */
+o->field1 = arg1; o->field2 = arg2; /* ctor writes every field */
+o->parentCls = &class__Foo; /* class pointer LAST */
+```
+
+There's no zeroing, because the constructor writes every field anyway, and the class pointer is stored last, so the concurrent collector can never trace a half-built object. When every slot in a page turns out to be garbage, the page flips back to bump-from-zero in one step instead of being swept slot by slot. And the pages themselves still come from the OS allocator, so everything in the section above stays true. objectAllocation went from 19.6x to 1.19x.
+
+This is where the two philosophies meet in the middle. We borrowed the part of HotSpot's design that makes allocation fast, pages we bump into, without borrowing the part we don't want, a giant pre-reserved heap the OS can't see into.
+
+## The GC, In Plain Terms
+
+ParparVM's GC never stops the world. Your app's threads keep running while a background collector thread walks the object graph and marks everything reachable, then sweeps what wasn't marked. The threads cooperate: each thread either checks in at safe points, or the collector briefly interrupts it with a signal, captures its registers and stack for scanning, and lets it continue.
+
+{{< mermaid >}}
+sequenceDiagram
+ participant UI as App thread (EDT)
+ participant GC as Collector thread
+ UI->>UI: allocate, render, respond
+ GC->>GC: mark reachable objects (concurrent)
+ GC-->>UI: brief signal: snapshot registers + stack
+ UI->>UI: keeps running
+ GC->>GC: sweep unmarked objects
+ Note over UI,GC: no stop-the-world pause, no frame drop
+{{< /mermaid >}}
+
+Why build it this way? Because on a client, pause time is the only GC metric users can feel. A 30ms collection pause during a scroll animation is two dropped frames, and users see it. A concurrent collector trades throughput for the guarantee that the animation never stutters.
+
+### Why We Don't Want A Generational GC
+
+The standard server answer is a generational collector: allocate new objects in a nursery, collect it often, copy the survivors out. It's a throughput machine, and for servers it's the right call. We tried a nursery on this branch. objectAllocation improved, and hashMapChurn got worse, 32x to 43x. Copying collectors pay for survivors, and a map that holds its entries makes everything survive. UI workloads look like that constantly: the object graph behind a form mostly survives, frame after frame.
+
+Generational collectors also move objects, which is a problem for us in two ways. Native code holds pointers into our heap, and a compacting collector would need to fix those up or pin everything native can see, which would surrender the direct native access we just listed as a core advantage. And copying needs headroom, roughly double the live set during collection, which is exactly the memory a 2.4 MB footprint client doesn't have. Our collector never moves an object. The BiBOP page recycling gives us the cheap-reclamation benefit a nursery promises, without copying anything.
+
+## A Poor Man's Valhalla
+
+The hashMapChurn benchmark spends its life autoboxing, `map.put(i, i * 2)` style code that allocates an `Integer` per call on a standard JVM (outside the -128 to 127 cache). Project Valhalla is Java's decade-long effort to make such values cheap. We don't have to wait for it, because we control the whole stack.
+
+On 64-bit targets, `Integer.valueOf()` no longer allocates anything. It returns a tagged pointer: the low bit is 1, the integer value lives in the high bits. Real object pointers are aligned, so their low bit is always 0, and the two can never collide:
+
+```
+real object: 0x0000600001a2c3f0 (low bit 0, points at a header)
+tagged Integer: 0x000000000000001f (low bit 1, value = 0xf = 15)
+```
+
+The GC ignores tagged values entirely, dispatch substitutes `Integer`'s class when it sees one, and unboxing is a shift. Boxing became free: the PR's A/B measures hashMapChurn at 2.8x with tagging disabled vs 0.97x with it on. It's on by default for 64-bit targets, with `-DCN1_DISABLE_TAGGED_INT` as the escape hatch.
+
+There's a semantic price, and it's the same one Valhalla asks: `Integer` loses identity. Two boxes holding the same value are now literally the same value, so `==` on boxes behaves like the JDK's small-value cache extended to the whole range, and `synchronized (someInteger)` cannot mean anything. The JDK itself has deprecated wrapper constructors and warns against locking on value-based classes for years. Rather than let that fail silently at runtime, [PR #5338](https://github.com/codenameone/CodenameOne/pull/5338) makes the build reject `synchronized` on a primitive wrapper at compile time, with a pointer toward a dedicated lock object. If your code locks on an `Integer`, it was already broken on modern JDKs in spirit. Now it's broken loudly, before it ships.
+
+## Objects That Stopped Existing
+
+Two more changes share a theme with the tagged integers: the fastest object is the one you never allocate.
+
+**Fused objects.** `new String(...)` used to be two heap objects, the `String` and its `char[]`. They're now one block, one allocation, one GC slot, no pointer hop between them:
+
+```
+BEFORE [ String header | fields ] --> [ char[] header | c0 c1 c2 ... ]
+AFTER [ String header | fields | char[] header | c0 c1 c2 ... ]
+```
+
+This ships as `@Fused`, applied internally to `String` and `StringBuilder`, and usable on your own classes that wrap a primitive buffer.
+
+**Escape analysis.** javac compiles `"item-" + i + "/" + n` into a `StringBuilder` chain. A control flow walk proves the builder never escapes the expression, so the builder and its buffer now live on the C stack. The only heap allocation in the whole concatenation is the final `String`. Combined with the rest, stringBuilding landed at 0.67x, finishing in two thirds of HotSpot's time, and this benchmark was rebuilt to be fair to HotSpot first (the original shape let HotSpot's own escape analysis delete the String entirely, so we made both VMs materialize every string).
+
+## Going Deeper
+
+Optimization is a rabbit hole with no bottom. Every fix exposes the next lever, and part of the discipline is deciding where to stop. We're stopping here for now, because at geomean parity the VM is no longer the bottleneck for real apps. The map of the next levels is already drawn, and if a workload shows up that needs them, we'll keep digging:
+
+- **Recursion sits at 1.6x** and will stay roughly there. Speculative inlining is the JIT's home turf.
+- **Tight arithmetic is 1.07x to 1.12x**, and that's clang vs C2, not us vs HotSpot.
+- **Cross-file inlining is the next big lever.** We deliberately generate one readable C file per class. You can open the output, read it, and debug it in Xcode, and we're not willing to trade that for one huge merged source file. The cost shows up in call-chain-heavy code: a real map rendering workload still trails warmed HotSpot because of a per-byte `readByte()` chain that HotSpot inlines across class boundaries. ThinLTO already recovers part of the gap. The rest waits until something real needs it.
+
+The machinery has a price small enough to state exactly: the benchmark app's binary grew from 434 KB to 451 KB. Those 17 KB buy the inlined fast paths, the compact HashMap, and the escape analysis.
+
+The whole suite ships in the repo under `vm/benchmarks`, including the torture tests and the checksum gate:
+
+```bash
+export JDK_8_HOME=/path/to/jdk8
+export BENCH_JAVA=/path/to/jdk25/bin/java
+vm/benchmarks/run-benchmark.sh # interleaved best-of-5, ratio table + geomean
+vm/benchmarks/run-gauntlet.sh # correctness: byte-identical output + GC stress
+```
+
+## TL;DR
+
+- ParparVM went from 4.21x slower than warmed Java 25 to geomean 1.00x, with six of ten benchmarks at or below HotSpot, verified by bit identical output checksums.
+- Peak memory under heavy allocation now lands below the JVM's (290 to 390 MB vs 508 MB), from a 2.4 MB floor vs HotSpot's ~40 MB.
+- The architecture behind it: frameless C code generation, diverging bounds checks, a BiBOP page heap over the OS allocator, stack-allocated string building, and tagged Integers.
+- Tagged Integers change `Integer` identity, and the build now rejects `synchronized` on primitive wrappers ([PR #5338](https://github.com/codenameone/CodenameOne/pull/5338)).
+- The cost: 17 KB of binary. If anything misbehaves, pin with [versioned builds](https://www.codenameone.com/blog/versioned-builds-master/) and tell us.
+
+## The Rest Of This Week
+
+The performance work is the headline, but the week is bigger than one PR:
+
+- **Saturday.** {{< post-link path="/blog/standalone-certificate-wizard" text="The certificate wizard is now a standalone tool with a different approach to Apple login" >}}. It should end the login breakage of the old wizard. PR [#5339](https://github.com/codenameone/CodenameOne/pull/5339).
+- **Sunday.** {{< post-link path="/blog/ar-vr-support-simulation" text="AR and VR support, including a simulated AR room you can debug in the simulator" >}}. PR [#5335](https://github.com/codenameone/CodenameOne/pull/5335).
+- **Monday.** {{< post-link path="/blog/automated-store-submissions" text="Automated store submissions with your listing as code, including Huawei AppGallery" >}}. The same post covers organization accounts and self service account deletion in the build cloud. PR [#5353](https://github.com/codenameone/CodenameOne/pull/5353).
+
+One more note on the week itself. Most of our recent time went into two very large PRs, and the one in this post is the much smaller of the two. So this is a relatively slow week by feature count, but every change in it is tectonic, and there's a lot more moving through the pipeline. More on that soon.
+
+---
+
+## Discussion
+
+_Join the conversation via GitHub Discussions._
+
+{{< giscus >}}
diff --git a/docs/website/content/blog/standalone-certificate-wizard.md b/docs/website/content/blog/standalone-certificate-wizard.md
new file mode 100644
index 00000000000..ab540995b1a
--- /dev/null
+++ b/docs/website/content/blog/standalone-certificate-wizard.md
@@ -0,0 +1,68 @@
+---
+title: "The Certificate Wizard Is Now A Standalone App, And It Stopped Impersonating You"
+slug: standalone-certificate-wizard
+url: /blog/standalone-certificate-wizard/
+date: '2026-07-11'
+author: Shai Almog
+description: "The iOS certificate wizard is now a standalone desktop app launched with mvn cn1:certificatewizard. It authenticates with an App Store Connect API key instead of your Apple ID login, which removes the 2FA and login-flow breakage of the old wizard."
+feed_html: ' The certificate wizard is now a standalone desktop app that authenticates with an App Store Connect API key instead of your Apple ID login.'
+series: ["release-2026-07-10"]
+---
+
+
+
+Yesterday's release post covered the [ParparVM performance work](/blog/beating-hotspot-performance/). Today's post is about the tool most iOS developers meet before they ever see their app on a device: the certificate wizard. [PR #5339](https://github.com/codenameone/CodenameOne/pull/5339) rewrites it as a standalone desktop app with a different way of talking to Apple.
+
+## Why The Old Wizard Kept Breaking
+
+Apple signing needs a pile of interlocking assets: a signing certificate, a bundle ID, registered devices, a provisioning profile that ties the three together, and a push key if you use notifications. The wizard's job has always been to create all of that so you don't spend an afternoon in the Apple developer portal.
+
+The old wizard did it by logging in as you. You typed your Apple ID and password, and the wizard drove Apple's developer services the way a browser would. That approach has an expiry date built in. Apple changes its login flow regularly, added and then kept tightening two-factor authentication, and none of those changes arrive with a heads-up for tools like ours. Every change meant a broken wizard and a scramble on our side. If you ever hit "verification code" loops or a login that silently failed, that was this.
+
+## The New Approach: A Key, Not A Login
+
+The new wizard never sees your Apple ID or password. It uses an App Store Connect API key, which is Apple's official machine-to-machine credential: a `.p8` private key plus a Key ID and an Issuer ID, created once in App Store Connect under Users and Access, Integrations. The key authorizes certificate, bundle ID, device, profile, and push key management through Apple's documented API, the same one Apple's own tooling uses.
+
+There's no password to store, no 2FA prompt to intercept, and no login flow to chase. When Apple redesigns their sign-in page next year, nothing on this path breaks.
+
+
+
+Setup is one page: paste the Key ID and Issuer ID, import the `.p8` file with the native file chooser, done. Apple only lets you download the `.p8` once, so keep a backup somewhere safe.
+
+
+
+## Auto Setup
+
+With the key stored, the toolbar shows Auto Setup. It reads your project's `codenameone_settings.properties`, takes the package name as the bundle ID, and creates or reuses everything a normal project needs: the bundle ID, development and distribution certificates, development and App Store provisioning profiles, and push enablement. It then installs the downloaded `.p12` and `.mobileprovision` files straight into the project's debug and release signing settings.
+
+If no development device is registered yet, it defers the development profile, finishes the App Store assets, and picks up where it left off after you add a device. Mac App Store and Developer ID signing use the same key through the same flow.
+
+
+
+## A Standalone Tool, Bound To Your Project
+
+The wizard used to live inside the Codename One Settings app. It's now its own application, launched from any Codename One Maven project:
+
+```bash
+mvn cn1:certificatewizard
+```
+
+The goal resolves the wizard from Maven, launches it against the current project, and writes results back into that project's settings. It behaves like a real desktop citizen: dark mode, native file dialogs, and it shows up as "Certificate Wizard" in the macOS dock and task switchers rather than as an anonymous Java process.
+
+One detail we enjoy: the wizard is itself a Codename One app. Same framework, same UI toolkit, running as a desktop tool. We keep saying one codebase reaches desktop too, so the signing tool seemed like a reasonable place to prove it.
+
+Android is handled locally, no cloud involved: the wizard generates a self-signed keystore with the JDK's `keytool` and writes the keystore path, alias, and password into the project. Back that keystore up. A published Android app can never change its signing key. Windows code signing certificates must come from a certificate authority, so the wizard documents the settings rather than pretending it can issue them.
+
+## The Tradeoff
+
+The cost of the new model: the `.p8` key is sent to the Codename One cloud signing service, which performs the Apple API calls on your behalf and doesn't return the key afterward. That's the same trust you already extend to the build cloud that signs your binaries, but it is trust, and you should know about it. If you revoke the key in App Store Connect, everything stops cleanly and you can issue a new one in two minutes. Use Admin access for the key; the lower App Store Connect roles can't create certificates and profiles.
+
+Tomorrow's post covers something entirely different: AR and VR support, including a simulated AR room you can walk through in the simulator with WASD keys. And the same API key you just configured comes back on Monday, when it powers automated App Store submissions.
+
+---
+
+## Discussion
+
+_Join the conversation via GitHub Discussions._
+
+{{< giscus >}}
diff --git a/docs/website/static/blog/ar-vr-support-simulation.jpg b/docs/website/static/blog/ar-vr-support-simulation.jpg
new file mode 100644
index 00000000000..50e8db709be
Binary files /dev/null and b/docs/website/static/blog/ar-vr-support-simulation.jpg differ
diff --git a/docs/website/static/blog/ar-vr-support-simulation/ar-simulator-model.png b/docs/website/static/blog/ar-vr-support-simulation/ar-simulator-model.png
new file mode 100644
index 00000000000..681da01a674
Binary files /dev/null and b/docs/website/static/blog/ar-vr-support-simulation/ar-simulator-model.png differ
diff --git a/docs/website/static/blog/ar-vr-support-simulation/vr-360-panorama.png b/docs/website/static/blog/ar-vr-support-simulation/vr-360-panorama.png
new file mode 100644
index 00000000000..baa1cfc9928
Binary files /dev/null and b/docs/website/static/blog/ar-vr-support-simulation/vr-360-panorama.png differ
diff --git a/docs/website/static/blog/ar-vr-support-simulation/vr-stereo-scene.png b/docs/website/static/blog/ar-vr-support-simulation/vr-stereo-scene.png
new file mode 100644
index 00000000000..4f628fe49b4
Binary files /dev/null and b/docs/website/static/blog/ar-vr-support-simulation/vr-stereo-scene.png differ
diff --git a/docs/website/static/blog/automated-store-submissions.jpg b/docs/website/static/blog/automated-store-submissions.jpg
new file mode 100644
index 00000000000..526145f0529
Binary files /dev/null and b/docs/website/static/blog/automated-store-submissions.jpg differ
diff --git a/docs/website/static/blog/automated-store-submissions/delete.png b/docs/website/static/blog/automated-store-submissions/delete.png
new file mode 100644
index 00000000000..fad442df8e9
Binary files /dev/null and b/docs/website/static/blog/automated-store-submissions/delete.png differ
diff --git a/docs/website/static/blog/automated-store-submissions/org.png b/docs/website/static/blog/automated-store-submissions/org.png
new file mode 100644
index 00000000000..f98658d9269
Binary files /dev/null and b/docs/website/static/blog/automated-store-submissions/org.png differ
diff --git a/docs/website/static/blog/automated-store-submissions/submission-store-credentials.png b/docs/website/static/blog/automated-store-submissions/submission-store-credentials.png
new file mode 100644
index 00000000000..9c9609332fb
Binary files /dev/null and b/docs/website/static/blog/automated-store-submissions/submission-store-credentials.png differ
diff --git a/docs/website/static/blog/beating-hotspot-performance.jpg b/docs/website/static/blog/beating-hotspot-performance.jpg
new file mode 100644
index 00000000000..ee3f664b828
Binary files /dev/null and b/docs/website/static/blog/beating-hotspot-performance.jpg differ
diff --git a/docs/website/static/blog/standalone-certificate-wizard.jpg b/docs/website/static/blog/standalone-certificate-wizard.jpg
new file mode 100644
index 00000000000..e9dd1f50a26
Binary files /dev/null and b/docs/website/static/blog/standalone-certificate-wizard.jpg differ
diff --git a/docs/website/static/blog/standalone-certificate-wizard/certificate-wizard-api-key-mock.svg b/docs/website/static/blog/standalone-certificate-wizard/certificate-wizard-api-key-mock.svg
new file mode 100644
index 00000000000..efb1d6abf18
--- /dev/null
+++ b/docs/website/static/blog/standalone-certificate-wizard/certificate-wizard-api-key-mock.svg
@@ -0,0 +1,36 @@
+
diff --git a/docs/website/static/blog/standalone-certificate-wizard/certificate-wizard-overview-mock.svg b/docs/website/static/blog/standalone-certificate-wizard/certificate-wizard-overview-mock.svg
new file mode 100644
index 00000000000..85f9a85b734
--- /dev/null
+++ b/docs/website/static/blog/standalone-certificate-wizard/certificate-wizard-overview-mock.svg
@@ -0,0 +1,63 @@
+
diff --git a/docs/website/static/blog/standalone-certificate-wizard/certificate-wizard-profiles-mock.svg b/docs/website/static/blog/standalone-certificate-wizard/certificate-wizard-profiles-mock.svg
new file mode 100644
index 00000000000..df3f9be9b3c
--- /dev/null
+++ b/docs/website/static/blog/standalone-certificate-wizard/certificate-wizard-profiles-mock.svg
@@ -0,0 +1,49 @@
+
diff --git a/scripts/website/languagetool-accept-blog.txt b/scripts/website/languagetool-accept-blog.txt
index fe60bd8b937..361050d600a 100644
--- a/scripts/website/languagetool-accept-blog.txt
+++ b/scripts/website/languagetool-accept-blog.txt
@@ -94,3 +94,21 @@ Classpath
# Media tool names used in the JavaSE media backend.
ffmpeg
ffprobe
+
+# VM / compiler / performance terminology (the 2026-07-10 ParparVM
+# performance release post and future perf deep dives).
+[Gg]eomean
+gcc
+[Ii]nlin(es?|ing|ed)( it)?
+[Dd]eoptimizations?
+[Qq]uicksort
+[Rr]eassociat(es|ing|ion)
+[Mm]iscompil(es|ed|ations?)
+[Bb]ackpressure
+[Aa]utobox(es|ing)?
+memset
+
+# The store submission tool, officially lowercase.
+fastlane
+calloc
+Valgrind