Fix JavaScript glass tab lens rendering#5388
Conversation
Cloudflare Preview
|
|
Compared 176 screenshots: 176 matched. |
✅ ByteCodeTranslator Quality ReportTest & Coverage
Benchmark Results
Static Analysis
Generated automatically by the PR CI workflow. |
✅ Continuous Quality ReportTest & Coverage
Static Analysis
Generated automatically by the PR CI workflow. |
|
Compared 145 screenshots: 145 matched. Benchmark ResultsDetailed Performance Metrics
|
|
Compared 145 screenshots: 145 matched. Benchmark ResultsDetailed Performance Metrics
|
|
Compared 145 screenshots: 145 matched. Benchmark ResultsDetailed Performance Metrics
|
|
Compared 146 screenshots: 146 matched. |
|
Compared 146 screenshots: 146 matched. |
|
Compared 148 screenshots: 148 matched. Benchmark Results
Build and Run Timing
Detailed Performance Metrics
|
|
Compared 143 screenshots: 143 matched. |
|
Compared 147 screenshots: 147 matched. Benchmark Results
Detailed Performance Metrics
|
|
Compared 142 screenshots: 142 matched. Benchmark Results
Build and Run Timing
Detailed Performance Metrics
|
|
Compared 216 screenshots: 216 matched. |
Native fidelity (Android, Material 3)54 pairs compared -- median 95.6%, worst 91.3% ( Distribution --
Geometry vs native (bbox offset / size ratio / center offset / corner radius) -- gated separately from the visual score
Side-by-side comparisons (worst first)
|
|
Compared 12 screenshots: 12 matched. |
|
Compared 149 screenshots: 149 matched. Native Android coverage
✅ Native Android screenshot tests passed. Native Android coverage
Benchmark ResultsDetailed Performance Metrics
|
…Region) The previous commits re-derived the whole material+motion model from the committed grey-backdrop phone recording, which flattened the effect on every port including iOS -- diverging from the doc-blessed fidelity target and the committed ios-26-metal-frames goldens. Revert the shared model (TabSelectionMorph tokens/curve), Tabs paint behaviour, the Metal shader and CPU reference constants, and the iOS-modern theme back to master's tuning. The actual reason the simulator looked wrong was never the model: JavaSE had NO glassRegion implementation, so the bar's Liquid Glass material fell back to a plain blur. The lens then sampled a flat grey bar instead of the bright frost, and every in-flight frame read as a murky smudge. Implement JavaSEPort.glassRegion as a step-for-step mirror of IOSImplementation's offscreen branch (padded edge-replicated backdrop, affine colour material, Gaussian blur, SDF optics: edge refraction + specular rim + AA mask). With it the JavaSE render of TabsMorph_t050 matches the committed Metal golden to ~1 LSB at matched anatomy (bar 240/240/240, bubble interior within 2). Keep the good parts of this PR: the JavaScript port's real per-pixel lens and full glass recipe (replacing the uniform-zoom fallback), re-pinned to master's constants and bit-identical to JavaSE at all seven probe points; the four-backend constant/CRC parity script (regenerated against JavaSEPort.applyLensBuffer); the deterministic JavaSE frame probe; and the opt-in cn1.javase.pixelMilliRatio density override for reference-resolution captures. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Re-record native-tabs-{light,dark}.mov from the live UITabBar on the current
iOS 26.3 simulator runtime. The fresh recordings confirm the old video was not
stale: Apple toned the Liquid Glass tab drop down in later 26.x updates, so
current UIKit shows a flat compact drop -- the frosted refracting bubble from
the original iOS 26 design (the developer-guide fidelity image and the
committed TabsMorph frame goldens) can no longer be captured natively.
Codename One deliberately keeps the original frosted-bubble design, so add
cn1-tabs-{light,dark}.mov: the shipped morph in motion, rendered
deterministically from the JavaSE simulator at the reference density (60fps,
the theme's 480ms timeline, 1088x290 tile) with the restored model and the new
glassRegion material. A README in the anim goldens dir now states which video
is authoritative for what: natives for timing/travel, the CN1 baseline and the
frame goldens for material -- never tune against the flat native material.
Also note in verify-javascript-lens-parity.mjs that the glass material/optics
CRC pins are shared by three CPU implementations (iOS, JavaSE, browser bridge);
JavaSE's new glassMaterialInPlace/applyGlassOptics reproduce them bit-exactly.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s interaction-only
The flat drop in the previous native-tabs recordings was a recording artifact,
not Apple toning the effect down: UIKit plays the full Liquid Glass selection
morph (the frosted refracting bubble with chromatic rims that bulges past the
bar) only for genuine touch-driven selection on a UITabBarController.
Programmatic selectedIndex changes play a flat simplified platter slide, and
the old bare-UITabBar + custom-appearance path never showed the effect at all.
Verified by XCUITest-tapping both the Files app and a plain UITabBarController
on the same iOS 26.3 runtime over the same grey backdrop -- both show the full
bubble that the committed Metal frame goldens and the developer-guide fidelity
image depict.
- NativeRef animate mode now hosts a real UITabBarController (the bare bar
also crashed under a controller: selectedItem writes are forbidden)
- add the tap-driver XCUITest harness (xcodegen project, like the
input-validation iOS driver); record-ios-native-anim.sh drives real taps
through it for the tabs recording (build-for-testing, then record during
test-without-building) and keeps the self-animating path for the switch
- re-record native-tabs-{light,dark}.mov: they now show the true frosted
morph, matching the CN1 baseline instead of contradicting it
- rewrite the anim-goldens README accordingly (the earlier toned-down claim
was wrong)
- Playground: the Tabs sample now uses addTab(title, materialIcon, size,
content) so tab icons are theme-driven and recolor with selection; the old
manual FontImage.createMaterial icons stayed one colour
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Merge origin/master (#5387 Liquid Glass theme fidelity) into the branch. Refine the RaisedButton gradient stroke: the ring was painted as an outer gradient fill with the background filled over an inset contour, and at the theme's 0.1mm hairline width the two independently-rasterized edges misregistered -- the stroke read as broken segments and muddy grey arcs that mixed with the backdrop (clearly visible in the ButtonTheme goldens). The ring is now a single two-contour shape (inner contour programmatically reversed so the default non-zero winding leaves a ring -- even-odd is not plumbed through the JavaScript port's canvas fill) painted OVER the background fill, giving a uniform, luminous rim: white glint at the top-left flowing to the cyan tint at the bottom-right, on every port from the same shared code. Add the Codename One copyright header to the tap-driver sources, NativeRef and PlaygroundExamples (check-copyright-headers CI failure). Screenshot goldens that include the dark/light RaisedButton hairline stroke will need a refresh cycle; the JavaScript ones are regenerated in the next commit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The JavaScript port now renders the genuine Liquid Glass material and selection lens (and the refined gradient stroke), so the iOS-theme screenshots legitimately changed. Goldens are taken from the javascript-ui-tests artifact of CI run 29512910274 (commit 5131184) -- the runner's own Chromium rendering -- because locally-rendered pixels do not match the CI environment. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…inding ring The multi-contour non-zero ring rendered correctly on JavaSE and the JavaScript port but the iOS/Metal clip rasterizer unions subpaths, so on Mac/iOS the whole pill filled with the stroke gradient (caught by the build-mac-native screenshot diff). Replace it with three passes that hold on every port: the background fills the full shape, the translucent gradient paints over it clipped to the same shape, and the interior is restored through a solid Paint clipped to the inset shape. The two clipped passes share one rasterizer, so the leftover hairline ring keeps registration-stable edges (the original defect), and the background beneath keeps it luminous. JavaSE render verified identical to the ring construction at 4x zoom. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ortable stroke Taken from the javascript-ui-tests artifact of CI run 29531928085 (commit 1cf9e06) -- the three-pass gradient stroke shifts the raised-button rim by a few pixels relative to the ring-construction renders these goldens froze. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Taken from the ios-ui-tests / watch-ui-tests artifacts of CI run 29536263092 (commit df3d40a): the RaisedButton/FlatButton hairline rim now renders as a clean uniform ring on the device pipeline instead of the broken segments the old goldens froze. Metal and tvOS jobs passed against their existing goldens. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>












































































































Summary
glassRegionin the JavaSE port — a step-for-step mirror ofIOSImplementation's offscreen Liquid Glass branch (padded edge-replicated backdrop read, affine colour material, Gaussian blur, SDF optics: edge refraction + specular rim + AA shape mask)JavaSEPort.applyLensBufferat all seven probe pointscn1.javase.pixelMilliRatiodensity override for reference-resolution capturesios-26-metal-framesgoldens and the developer-guide fidelity image)RoundBordergradient stroke: the hairline ring is now three clip-registered passes (background, gradient over it, interior restored) that render a uniform luminous rim on every port -- the old two-fill construction read as broken muddy segments, and a multi-contour winding ring broke on the iOS/Metal clip rasterizerRoot cause
The simulator and JavaScript port looked wrong for two independent reasons, neither of which was the shared morph model:
glassRegionimplementation. The tab bar's Liquid Glass material silently fell back to a plain blur, leaving the bar a flat grey (156) where the device renders a bright frost (240). The selection lens then magnified that grey substrate, so every in-flight frame read as a murky smudge regardless of tuning.glassRegionto a plain blur.An earlier iteration of this PR instead re-tuned the shared model against the grey-backdrop phone recording (
goldens/ios-26-metal-anim/native-tabs-light.mov), which flattened the effect on every port including iOS and diverged from the committed Metal goldens. That re-tuning is reverted; the recording and the fidelity capture disagree about the material and the goldens are the canonical target.Validation
TabsMorph_t050_lightnow matches the committed Metal golden at matched anatomy to ~1 LSB: bar(240,240,240)vs(240,240,240), bubble interior(234,236,240)vs(235,237,240); settled and dark frames match equivalentlynode scripts/verify-javascript-lens-parity.mjs: 14 constants pinned across 4 backends; JS lens CRCs bit-identical to JavaSE at t=0/10/25/50/75/90/100; glass material + optics CRCs passgit diff --check