Repository navigation
Commit 850bb54
iOS 27 tab bar: measured Liquid Glass motion, vibrancy, lens optics and native geometry (#5906)
* iOS 27 tab bar: measured Liquid Glass motion, vibrancy, lens optics and native geometry
The iOS 27 Tabs (tabsMorphPreset ios27) now reproduces UITabBarController from
measurements taken with an instrumented native probe (motion-probe) rather than
by eye:
- TabGlassMotion / TabGlassGesture: the selection motion as measured 60 Hz
tables, plus held presses, a press on the selected tab, drag scrubbing with
release to the tab under the finger, and the release wobble.
- Graphics.colorMatrixRegion (vibrant tab content, the selection platter) and
Graphics.glassLensRegion (the lifted lens's refraction, outline, rim and
shadow), with core reference implementations, JavaSE, iOS/macOS Metal and
(colorMatrixRegion) JavaScript port support.
- Native bar geometry in points and the native label face.
- iOS Metal: the bar glass runs on the GPU, mutable-image drawing reuses its
stencil, the tab motion is no longer painted twice per frame, and the lens
scratch texture is no longer leaked.
- Tooling: tabmotion.py regenerates every table; record-ios-tabs-side-by-side.sh
records native and Codename One side by side under the same real touches
(docs/videos).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Fix CI: CLDC11 has no Math.exp, prose rule, close files in tabmotion.py
GlassLensBlend uses MathUtil.exp (core compiles against CLDC11 in the Ant
build). tabmotion.py opens every file through a context manager; all
regenerated tables and fixtures are byte-identical.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* VibrancyMatrix: closed forms replace the fitted light-alpha and grey tables
The light alpha is 1 - e - 0.3 (0.5 - e) sum(1-t) / |1-t|^2, the exact value
that maps a white backdrop to the tint; the grey ramp is 5/16 / q and
(19/16 g - 1/4) / q with q = 1 + 0.05 g (1 - g). Every matrix the probe
logged matches to 5e-6 (the table reproduced them to 0.0046).
tabmotion.py vibrancy now checks captures against the forms instead of
fitting tables, and the test asserts native matrix entries to 2e-5.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Tabs: the platter colour matrix is 1.2 I - k * luminance, not 24 literals
UIKit's platter colorMatrix is a 1.2 gain less a share of the Rec. 709
luminance (0.33 dark, 0.07 light) plus an offset; every read-back entry
matches within 1.4e-4, as close as UIKit's own rows agree. A test pins the
formula to the native readback.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* TabGlassMotion: the travel, lift, platter and glow are springs, not tables
On the vsync clock (every captured frame renders at exactly start + n/60 s;
the logged times carry main-thread jitter) seven of the fourteen tables are
UIKit springs, written in closed form with DampedSpring:
- travel: duration 0.4 s, bounce 0.15, ended past the overshoot once less
than 0.195 pt remains
- lift: critically damped 0.25 s rise and fall (fall ends 13.5 frames in)
- platter: critically damped 0.4 s from 1 - rise and its velocity at the
release (ends 28.5 frames in)
- glow: layer critically damped 0.1 s to 0.8445, retargeted to 0 on a 0.5 s
spring at the tap's touch-up; mask = 0.33675 * layer; each hidden under
0.005; scale 1 + 3 * the 0.5 s spring
The deformation (STRETCH_*, LEAD_*) and the whole-bar pulse keep their tables:
no closed form matched the capture as well. tabmotion.py check now holds the
closed forms to the capture and fails beyond tolerance; java only splices the
kept tables; fixture is unchanged.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* TabGlassGesture: the settle after a scrub is the tap's travel spring
The settle is TabGlassMotion's travel spring (POSITION_OMEGA, POSITION_ZETA,
now package-private so both share one definition) started from the position
and velocity the follow spring leaves the lens with when the release reaches
it, one touch lag after the finger lifts. It replaces the SETTLE_V/SETTLE_E
tables and the position-curve correction: scrub centre RMS 0.517 -> 0.346 pt,
worst 7.47 -> 3.44 pt; lift worst 0.42 -> 0.14. Fitted to the releases alone
the spring comes out at 15.5 rad/s, zeta 0.847, against 15.708 / 0.85.
The release wobble and the scrub deformation kernels stay tables; a note
above the kernels records the structure a closed form would have to meet.
The bar press spring uses DampedSpring.
tabmotion.py gesture splices the wobble and deformation tables as before and
replays the settle over the episodes gesture-fixture exports (--settle),
failing beyond tolerance. The fixture and the splice are byte-identical.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* TabGlassMotion: drop the blank lines the removed tables left behind
tabmotion.py java regenerates the remaining tables byte for byte again.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Reseed the 7 TabsGlassMotion frames the spring curves moved
Frames 3, 5, 7 and 17 (lift and glow onset, lift release) drifted 0.5-1.3%
of pixels: the lens outline moves by a sub-pixel and the vibrant edge label
recolours with the glow. The other 29 frames and every fidelity row are
unchanged; strict verification passes on the iOS 27 simulator.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Tabs glass: fix the review findings on ports, placement, RTL and hit testing
- iOS: colour matrix and glass lens need the Metal renderer; GL and watchOS
builds report no support so Tabs paints its regular content.
- The glass motion applies to TOP and BOTTOM tabs only; LEFT and RIGHT keep
the regular rendering.
- An empty glass bar paints its glass without resolving a tab.
- Right to left, the first glass tab sits at the right end.
- The glass tabs overlap (each is as wide as its resting lens), so taps and
scrub releases both pick the tab whose centre is nearest.
- The pointer listeners stay registered with swiping off; they also drive
the lens and skip the swipe themselves.
- Metal (iOS and Mac): a colour-matrix region that runs off a screen edge
keeps its texture coordinates and mask anchored to the full region.
- JavaScript: colorMatrixRegion ignores the user transform, as on the other
ports (Tabs scales its regions itself).
Each new test was checked to fail with its fix reverted.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Metal restarts keep clip and transform; vibrant tabs keep their own tint
- A screen effect (blur, glass, lens, colour matrix) ends the Metal encoder
mid-frame and opens another. That reset the transform to identity and
dropped the rectangular and polygon clips the Java side had already sent,
so the effect and everything after it drew unclipped. CN1Metalcompat now
carries them across the restart (the polygon is re-stamped, as each pass
starts with a cleared stencil) until presentFramebuffer ends the frame;
clips set while drawing into a mutable image are not the screen's.
- The vibrant tab content groups the tabs by their own tint in each state,
one mask and matrix per group, so a tab with its own colour or a disabled
tab keeps it. The usual single tint is still two masks.
- Three TabsGlassMotion frames reseeded: with the transform and clip now
kept, the lens rim and the vibrant edge label move by a few edge pixels.
- The watchOS Core Graphics build is the only one without these ops.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Glass tab titles never scroll; reseed the TabsGlassMotion frames
The first tab could gain focus while it was briefly narrower than its title
(before the glass layout ran), which started a Label ticker that never
stopped: the title showed as a drifting 'ed', and every TabsGlassMotion frame
differed from run to run by 0.15-0.4% of pixels -- the source of the
intermittent iOS 27 frame-golden failures. UITabBar never scrolls a title,
so the glass layout stops and disables the ticker on its tabs.
All 36 frames reseeded with 'Featured' whole and centred; two runs of the
same build now capture them pixel-identical.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Tabs: the iOS 26 drop may bulge past the bar in flight
Mid-flight the iOS 26 selection drop is taller than the bar and bulges past
its edges, as UIKit's does, but tabsContainer's paint is clipped to the bar.
On Metal the bulge only showed because an encoder restart dropped the clip;
with the clip now carried across restarts it was cut at the bar edge. The
drop's lens now widens the clip to the whole Tabs while in flight -- the
morph repaints the whole Tabs every frame then -- and leaves it alone at rest,
when the drop is inside the bar.
The test implementation records lensRegion calls with their clip, and a test
holds the morph mid-flight and checks the clip admits the bulge, up to the
Tabs and no further.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* TabGlassGesture: test the finger state, not a float sentinel
at() tested rel == Float.MAX_VALUE. ParparVM writes that constant as the
double 3.4028235E38, which a C float never equals, so the test was always
false on iOS and Xcode 27 reports it (-Wliteral-range), failing the native
warning census of build-ios-metal-27. releaseS answers the sentinel exactly
when the finger is still down, so test upS < 0 instead.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Tabs glass: presses under overlays, preset switches, style bookkeeping; JavaSE clip
- A press only drives the glass lens when the component that receives it is
the tab bar or one of its tabs, not an overlay (side menu, layered-pane
sheet) covering the bar.
- A theme switch between the ios26 and ios27 presets reinstalls the tab
layout when the glass motion flips, so neither renderer runs over the
other's layout.
- Button's forced glass styles keep Component's isUnselectedStyle
bookkeeping, so Label no longer measures a selected title with the width
it cached for the unselected font.
- JavaSE: lensRegion, glassLensRegion and colorMatrixRegion write back only
inside the graphics clip (mapped into buffer pixels), as the Metal and
JavaScript paths do; a raw setRGB bypassed it.
Each new test was checked to fail with its fix reverted.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* motion-probe: keep only the tint lists the fixture needs; README matches the model
The six other tint lists (adapt, cvw, grid17, lowc, slices, sweep3) densified
the samples the old fitted light-alpha table needed. VibrancyMatrix is closed
form now, and sweep/sweep2 -- which native-vibrancy.csv is captured from --
check it just as well (1382 tints per appearance, worst entry 5e-6).
The README described tables that are now springs and formulas, the old
vibrancy/gesture command lines, and a wobble onset independent of the
gesture; it now states the closed forms, the current commands, and the
measured onset per gesture.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Tabs glass: grow the bar for tab content taller than native
The floating bar was fixed at UITabBar's 62 pt, so a tab with larger icons
than the native ones had its label clipped at the bottom of the pill (the
TabsTheme screenshots on build-ios-metal-27). The bar is now 62 pt or the
tallest tab's preferred height plus the insets, whichever is larger: native
content keeps the native geometry exactly (the iOS 27 fidelity suite is
unchanged), larger content fits.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Reseed the iOS 27 TabsTheme screenshots
The iOS 27 tab bar now renders natively (floating glass pill sized to its
tabs, vibrant content, the selection lens), and grows past UITabBar's 62 pt
for this screen's larger-than-native icons so the labels are no longer
clipped. Captured by build-ios-metal-27 on c60d117 and checked by eye: every
label sits whole inside the pill, light and dark.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>1 parent 6447611 commit 850bb54
133 files changed
Lines changed: 16998 additions & 132 deletions
File tree
- CodenameOne/src/com/codename1
- impl
- ui
- plaf
- Ports
- JavaSE/src/com/codename1/impl/javase
- JavaScriptPort/src/main/java/com/codename1/impl/html5
- graphics
- MacPort/nativeSources
- iOSPort
- nativeSources
- src/com/codename1/impl/ios
- Themes
- docs
- developer-guide
- videos
- maven
- core-unittests/src/test
- java/com/codename1
- testing
- ui
- plaf
- resources/tab-glass-motion
- css-compiler/src
- main/java/com/codename1/designer/css
- test/java/com/codename1/designer/css
- javase/src/test/java/com/codename1/impl/javase
- native-themes/ios-modern
- scripts
- common/java
- fidelity-app
- baseline
- common/src/main
- java/com/codenameone/fidelity
- render
- spec
- resources
- goldens
- ios-27-metal-anim
- ios-27-metal-frames
- ios-native-ref/motion-probe
- App
- UITests
- tints
- tools/tab-motion
- ios/screenshots-metal-27
- vm
- ByteCodeTranslator/src/javascript
- tests/src/test/java/com/codename1/tools/translator
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4100 | 4100 | | |
4101 | 4101 | | |
4102 | 4102 | | |
| 4103 | + | |
| 4104 | + | |
| 4105 | + | |
| 4106 | + | |
| 4107 | + | |
| 4108 | + | |
| 4109 | + | |
| 4110 | + | |
| 4111 | + | |
| 4112 | + | |
| 4113 | + | |
| 4114 | + | |
| 4115 | + | |
| 4116 | + | |
| 4117 | + | |
| 4118 | + | |
| 4119 | + | |
| 4120 | + | |
| 4121 | + | |
| 4122 | + | |
| 4123 | + | |
| 4124 | + | |
| 4125 | + | |
| 4126 | + | |
| 4127 | + | |
| 4128 | + | |
| 4129 | + | |
| 4130 | + | |
| 4131 | + | |
| 4132 | + | |
| 4133 | + | |
| 4134 | + | |
| 4135 | + | |
| 4136 | + | |
| 4137 | + | |
| 4138 | + | |
| 4139 | + | |
| 4140 | + | |
| 4141 | + | |
| 4142 | + | |
| 4143 | + | |
| 4144 | + | |
| 4145 | + | |
| 4146 | + | |
| 4147 | + | |
| 4148 | + | |
| 4149 | + | |
| 4150 | + | |
| 4151 | + | |
| 4152 | + | |
| 4153 | + | |
| 4154 | + | |
| 4155 | + | |
| 4156 | + | |
| 4157 | + | |
| 4158 | + | |
| 4159 | + | |
| 4160 | + | |
| 4161 | + | |
| 4162 | + | |
| 4163 | + | |
| 4164 | + | |
| 4165 | + | |
| 4166 | + | |
| 4167 | + | |
| 4168 | + | |
| 4169 | + | |
| 4170 | + | |
| 4171 | + | |
| 4172 | + | |
| 4173 | + | |
| 4174 | + | |
| 4175 | + | |
| 4176 | + | |
| 4177 | + | |
| 4178 | + | |
| 4179 | + | |
| 4180 | + | |
| 4181 | + | |
| 4182 | + | |
| 4183 | + | |
| 4184 | + | |
| 4185 | + | |
| 4186 | + | |
| 4187 | + | |
4103 | 4188 | | |
4104 | 4189 | | |
4105 | 4190 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
90 | 90 | | |
91 | 91 | | |
92 | 92 | | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
93 | 101 | | |
94 | 102 | | |
95 | 103 | | |
| |||
664 | 672 | | |
665 | 673 | | |
666 | 674 | | |
667 | | - | |
| 675 | + | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
668 | 679 | | |
669 | 680 | | |
670 | 681 | | |
| |||
946 | 957 | | |
947 | 958 | | |
948 | 959 | | |
| 960 | + | |
| 961 | + | |
| 962 | + | |
| 963 | + | |
| 964 | + | |
| 965 | + | |
| 966 | + | |
| 967 | + | |
| 968 | + | |
| 969 | + | |
| 970 | + | |
| 971 | + | |
| 972 | + | |
| 973 | + | |
| 974 | + | |
| 975 | + | |
| 976 | + | |
| 977 | + | |
| 978 | + | |
949 | 979 | | |
950 | 980 | | |
| 981 | + | |
| 982 | + | |
| 983 | + | |
951 | 984 | | |
952 | 985 | | |
953 | 986 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3078 | 3078 | | |
3079 | 3079 | | |
3080 | 3080 | | |
3081 | | - | |
3082 | | - | |
3083 | | - | |
3084 | | - | |
3085 | | - | |
3086 | | - | |
3087 | | - | |
3088 | | - | |
3089 | | - | |
3090 | | - | |
3091 | | - | |
3092 | | - | |
3093 | | - | |
3094 | | - | |
3095 | | - | |
3096 | | - | |
3097 | | - | |
3098 | | - | |
3099 | | - | |
3100 | | - | |
3101 | | - | |
3102 | | - | |
3103 | | - | |
| 3081 | + | |
| 3082 | + | |
| 3083 | + | |
| 3084 | + | |
| 3085 | + | |
| 3086 | + | |
| 3087 | + | |
| 3088 | + | |
| 3089 | + | |
| 3090 | + | |
| 3091 | + | |
| 3092 | + | |
| 3093 | + | |
| 3094 | + | |
| 3095 | + | |
| 3096 | + | |
| 3097 | + | |
| 3098 | + | |
| 3099 | + | |
| 3100 | + | |
| 3101 | + | |
| 3102 | + | |
| 3103 | + | |
| 3104 | + | |
| 3105 | + | |
| 3106 | + | |
| 3107 | + | |
| 3108 | + | |
| 3109 | + | |
| 3110 | + | |
| 3111 | + | |
| 3112 | + | |
| 3113 | + | |
3104 | 3114 | | |
3105 | 3115 | | |
3106 | 3116 | | |
| |||
3143 | 3153 | | |
3144 | 3154 | | |
3145 | 3155 | | |
| 3156 | + | |
| 3157 | + | |
| 3158 | + | |
| 3159 | + | |
| 3160 | + | |
| 3161 | + | |
| 3162 | + | |
| 3163 | + | |
| 3164 | + | |
| 3165 | + | |
| 3166 | + | |
| 3167 | + | |
| 3168 | + | |
| 3169 | + | |
| 3170 | + | |
| 3171 | + | |
| 3172 | + | |
| 3173 | + | |
| 3174 | + | |
| 3175 | + | |
| 3176 | + | |
| 3177 | + | |
| 3178 | + | |
| 3179 | + | |
| 3180 | + | |
| 3181 | + | |
3146 | 3182 | | |
3147 | 3183 | | |
3148 | 3184 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2532 | 2532 | | |
2533 | 2533 | | |
2534 | 2534 | | |
| 2535 | + | |
| 2536 | + | |
| 2537 | + | |
| 2538 | + | |
| 2539 | + | |
| 2540 | + | |
| 2541 | + | |
| 2542 | + | |
| 2543 | + | |
2535 | 2544 | | |
2536 | 2545 | | |
2537 | 2546 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
0 commit comments