Class GlassRecipe

java.lang.Object
com.codename1.ui.plaf.GlassRecipe

public final class GlassRecipe extends Object

A typed, named recipe for the "Liquid Glass" backdrop materials (iOS 26).

A glass surface is described by its material INTENT -- which named recipe it uses -- rather than by loose per-parameter theme constants. Each recipe bundles the bounded, measured parameters of one native material (the colour transform the real UIVisualEffectView / UIGlassEffect applies to the blurred backdrop, plus the edge optics), so similar glass surfaces cannot silently diverge and a theme cannot tune itself into an incoherent material. The available recipes:

  • blur -- GlassRecipe.Kind.PLAIN_BLUR: backdrop blur only, no material colour transform (a plain CSS backdrop-filter).
  • chrome -- GlassRecipe.Kind.LIQUID_CHROME: the rectangular chrome bars anchored at a screen edge (navigation / title bars). Very transparent; the backdrop reads through at near-full saturation.
  • pill -- GlassRecipe.Kind.LIQUID_PILL: the floating pill chrome (the iOS 26 tab bar). Frostier than the edge bars -- in light mode it washes strongly toward white while boosting saturation.
  • panel -- GlassRecipe.Kind.LIQUID_PANEL: a bare glass panel or button capsule (UIGlassEffect). The strongest material: heavy wash, plus edge refraction and a specular rim so the glass reads as a layer on top of the content rather than a flat hole.
  • chrome27, pill27, panel27 -- the same three materials as iOS 27 retuned them. Light is measured as unchanged in chrome and pill; dark moved in all three, and dark chrome and pill are the only materials that are not affine: they carry a luminance curve (see getCurve()). See liquidPanel27(boolean) for how the constants were measured.

A theme assigns a recipe per UIID with the theme constant <UIID>GlassRecipe (for example ToolbarGlassRecipe: chrome), with glassRecipeDefault as the theme-wide default (panel when unset). The recipe is resolved at paint time by Component.internalPaintImpl and its parameters are passed to the port through Graphics.glassRegion; ports never read material constants themselves.

The travelling tab-selection lens is the remaining glass surface; it is an optics-over-content effect bound to the morph motion, so its typed parameters live with the motion model (TabSelectionMorph) rather than here.

  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static enum 
    The material kind a GlassRecipe renders.
  • Method Summary

    Modifier and Type
    Method
    Description
    float
    The strength of the material's luminance CURVE, in levels per unit of squared normalised luma distance from getCurveMid().
    float
    The normalised luma (0..1) at which the curve term is zero -- the vertex of the parabola.
    The material kind this recipe renders.
    float
    The colour offset (wash floor) of the material's affine colour transform, in 0..255 channel units.
    float
    The strength (0..1) of the thin dark outline iOS 27 draws around the sides of its glass; 0 for none, which is every recipe but the iOS 27 panel and pill.
    float
    The edge refraction (lensing) strength -- bends the backdrop toward the edges so the glass reads as a layer on top rather than a flat hole.
    float
    The saturation boost applied to the blurred backdrop.
    float
    The colour scale multiplier of the material's affine colour transform.
    float
    The brightness of the specular edge rim (the bright glint).
    liquidChrome(boolean dark)
    The rectangular edge-anchored chrome bar material (navigation/title bars).
    liquidChrome27(boolean dark)
    The iOS 27 chrome-bar material.
    liquidPanel(boolean dark)
    The bare glass panel / button capsule material (UIGlassEffect).
    liquidPanel27(boolean dark)
    The iOS 27 glass-panel material, and the recipe that carries the method these three were measured with.
    liquidPill(boolean dark)
    The floating pill chrome material (the iOS 26 tab bar).
    liquidPill27(boolean dark)
    The iOS 27 floating-pill material.
    named(String name, boolean dark)
    Looks up a recipe by its theme name: blur, chrome, pill, panel, or their iOS 27 variants chrome27, pill27 and panel27.
    Plain backdrop blur with no material transform.
    resolve(UIManager manager, String uiid, boolean dark)
    Resolves the recipe for a UIID from the theme: the per-UIID <UIID>GlassRecipe constant wins, then the theme-wide glassRecipeDefault, then the panel recipe.

    Methods inherited from class Object

    clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Method Details

    • plainBlur

      public static GlassRecipe plainBlur()
      Plain backdrop blur with no material transform.
      Returns:
      the plain-blur recipe
    • liquidChrome

      public static GlassRecipe liquidChrome(boolean dark)
      The rectangular edge-anchored chrome bar material (navigation/title bars). Measured against the iOS 26 UINavigationBar glass: the backdrop passes through at near-full strength with only a light wash.
      Parameters:
      dark - true for the dark appearance
      Returns:
      the chrome-bar recipe
    • liquidPill

      public static GlassRecipe liquidPill(boolean dark)
      The floating pill chrome material (the iOS 26 tab bar). Frostier than the edge bars: light mode washes strongly toward white while boosting saturation, and a faint specular rim keeps the pill edge legible.
      Parameters:
      dark - true for the dark appearance
      Returns:
      the floating-pill recipe
    • liquidPanel

      public static GlassRecipe liquidPanel(boolean dark)
      The bare glass panel / button capsule material (UIGlassEffect). The strongest material: a heavy wash plus edge refraction (lensing) and a specular rim, so a free-standing glass element reads as a layer on top of the content.
      Parameters:
      dark - true for the dark appearance
      Returns:
      the glass-panel recipe
    • liquidChrome27

      public static GlassRecipe liquidChrome27(boolean dark)

      The iOS 27 chrome-bar material.

      LIGHT IS DELIBERATELY IDENTICAL to liquidChrome(boolean). Fitting the transform against the iOS 27 capture returned sat 1.09, scale 0.860, offset 18.9 where iOS 26 is 1.10 / 0.850 / 20.0 -- inside 1.3% on every parameter, at an rms of 1.27/255. That is a measurement saying "unchanged", so the iOS 26 numbers are reused verbatim rather than replaced by a near-identical duplicate that would read as a real difference.

      DARK carries the luminance curve. The best affine fit left rms 14.6/255 with a systematic bend in the residual; the curved material halves that, to 8.0/255. Chrome bends hardest of the three (curve 1.65) because the bar sits over the full range of content luma. See liquidPanel27(boolean) for the method.

      Unlike the pill, this one is fitted but NOT verified on device: the fidelity suite's Toolbar tile paints a Toolbar-styled container rather than a form toolbar, so no glass material reaches it and its score does not move with these constants (it was byte-identical across the change).

      Parameters:
      dark - true for the dark appearance
      Returns:
      the iOS 27 chrome-bar recipe
    • liquidPill27

      public static GlassRecipe liquidPill27(boolean dark)

      The iOS 27 floating-pill material.

      LIGHT is again measured as unchanged -- the fit returned 1.86 / 0.984 / 111.4 against iOS 26's 1.80 / 1.000 / 108.0 -- so the iOS 26 values are reused as the MATERIAL. DARK carries the luminance curve, which takes the fit from rms 11.4/255 to 4.4/255.

      Both appearances carry the iOS 27 edge outline (see getOutline()), softer on the pill than on the panel: a 127 backdrop falls to about 85 on the capsule's boundary pixel in both light and dark, hence 0.55.

      Parameters:
      dark - true for the dark appearance
      Returns:
      the iOS 27 floating-pill recipe
    • liquidPanel27

      public static GlassRecipe liquidPanel27(boolean dark)

      The iOS 27 glass-panel material, and the recipe that carries the method these three were measured with.

      HOW THE NUMBERS WERE OBTAINED. The material is the documented affine transform c' = clamp((lum + (c - lum) * sat) * scale + offset). The iOS 26 constants are known, so every interior pixel of a committed goldens/ios-26-metal tile can be inverted back to the backdrop that produced it, and the matching goldens/ios-27-metal pixel then fitted against that same backdrop. Nothing about the backdrop has to be assumed, and because the transform is linear it commutes with the Gaussian blur, so the blur does not bias the fit. Clipping does NOT commute, so a pixel is used only when nothing within the blur's reach clipped -- without that erosion the photo-backdrop tile fitted at rms 14 against rms 1 for the flat ones, and it dragged every parameter with it.

      The method self-checks: run against the iOS 26 set it recovers the iOS 26 chrome constants it was never told, to within 1.3%.

      WHY DARK CHROME AND PILL HAVE A CURVE. After the best affine fit, the light residual is flat across the whole backdrop-luma range (within +/-0.9/255). The dark residual is not: on the chrome bar it runs +8.9 at low luma, -9.3 through the middle and +10.3 at high luma -- a systematic parabola, not noise. iOS 27's dark glass applies a NON-LINEAR luminance response that no choice of sat/scale/offset can express, so the dark chrome and pill recipes add curve * 255 * (lum / 255 - curveMid)^2 to every channel (see getCurve()). The fit is the same inversion as above, with the vertex gridded and the rest solved by least squares: rms 14.6 to 8.0 on chrome, 11.4 to 4.4 on the pill. On device the pill tiles moved with it -- Tabs dark 68.75% to 73.53%, TabsGeom dark 87.73% to 90.81%.

      THIS PANEL STAYS AFFINE, ON MEASUREMENT. Its residual bends far less, and the curve only took the fit from rms 3.59 to 3.18. On device that did not survive: GlassPanelGrey, GlassText and GlassIcon in dark each lost about 0.3 points and none gained, so the affine constants stand.

      Saturation and scale trade off along a flat valley once the curve is free: with the vertex and the linear terms re-solved at each saturation, chrome fits at rms 8.03 at sat 3.0, 8.02 at 4.5 and 8.02 at 8.5. The captures therefore barely constrain saturation, and it is the constant most likely to be wrong on a strongly coloured backdrop the fidelity tiles do not cover.

      THE OUTLINE, AND WHY IT IS WHAT MAKES THE DARK PANEL VISIBLE. Over a flat mid-grey the dark material gives 128.18, which the renderer emits as 128 -- the backdrop exactly -- so the material alone draws no silhouette, and no offset changes that (80.3 was tried). The native silhouette is not made by the material at all. iOS 27 draws a thin dark line around the sides of the glass, in both appearances and over every backdrop, which iOS 26 does not: on its boundary pixel each channel of the backdrop b becomes max(b - 76, 0.22 * b) to within a few levels -- grey 126 to 54, red 251/58/47 to 179/17/12, the blue gradient 35/148/165 to 7/71/85 -- and it fades out toward the top and bottom edges. getOutline() carries that line; this panel's is 0.95, the strength that reproduces the grey boundary pixel.

      Raising the specular rim instead was tried first, and rejected on measurement: a rim bright enough to show over grey (1.2) overshot the native rim over the red, photo and gradient backdrops by about two to one and cost every other dark panel tile 0.1 to 0.9 points.

      Parameters:
      dark - true for the dark appearance
      Returns:
      the iOS 27 glass-panel recipe
    • named

      public static GlassRecipe named(String name, boolean dark)
      Looks up a recipe by its theme name: blur, chrome, pill, panel, or their iOS 27 variants chrome27, pill27 and panel27. Unknown names fall back to the panel recipe -- the safest default for a free-standing glass surface.
      Parameters:
      name - the recipe name from the theme
      dark - true for the dark appearance
      Returns:
      the named recipe, never null
    • resolve

      public static GlassRecipe resolve(UIManager manager, String uiid, boolean dark)
      Resolves the recipe for a UIID from the theme: the per-UIID <UIID>GlassRecipe constant wins, then the theme-wide glassRecipeDefault, then the panel recipe.
      Parameters:
      manager - the UI manager holding the theme
      uiid - the component's UIID
      dark - true for the dark appearance
      Returns:
      the resolved recipe, never null
    • getKind

      public GlassRecipe.Kind getKind()
      The material kind this recipe renders.
      Returns:
      the kind, never null
    • getSaturation

      public float getSaturation()
      The saturation boost applied to the blurred backdrop.
      Returns:
      the saturation multiplier
    • getScale

      public float getScale()
      The colour scale multiplier of the material's affine colour transform.
      Returns:
      the scale factor
    • getOffset

      public float getOffset()
      The colour offset (wash floor) of the material's affine colour transform, in 0..255 channel units.
      Returns:
      the offset
    • getRefraction

      public float getRefraction()
      The edge refraction (lensing) strength -- bends the backdrop toward the edges so the glass reads as a layer on top rather than a flat hole.
      Returns:
      the refraction strength, 0 = none
    • getSpecular

      public float getSpecular()
      The brightness of the specular edge rim (the bright glint).
      Returns:
      the specular strength, 0 = none
    • getCurve

      public float getCurve()

      The strength of the material's luminance CURVE, in levels per unit of squared normalised luma distance from getCurveMid(). Zero for every recipe whose platform material is affine, which is all of them except the iOS 27 dark variants.

      The full per-pixel material is c' = clamp((lum + (c - lum) * sat) * scale + offset + curve * 255 * (lum / 255 - curveMid)^2), with lum the Rec. 709 luma of the backdrop pixel before the transform. A port that does not implement the term reproduces the affine material exactly, because the term vanishes when curve is zero.

      Returns

      the curve strength; 0 for an affine material

    • getOutline

      public float getOutline()

      The strength (0..1) of the thin dark outline iOS 27 draws around the sides of its glass; 0 for none, which is every recipe but the iOS 27 panel and pill.

      On the outermost pixel of the glass, each channel of the backdrop b under it is darkened by min(76 * w, 0.78 * w * b) after the glass is composited over it, where w is this strength times the horizontal component of the edge normal: full on the vertical sides, fading around the corners, none along the top and bottom. At full strength that is the max(b - 76, 0.22 * b) measured on the native boundary pixel.

      UIKit draws the line just OUTSIDE the view's bounds. A component cannot paint outside its own bounds on every port, so it lands on the outermost pixel inside instead -- one pixel inward of the native line.

      Returns

      the outline strength; 0 for none

    • getCurveMid

      public float getCurveMid()

      The normalised luma (0..1) at which the curve term is zero -- the vertex of the parabola. Meaningless when getCurve() is zero.

      Returns

      the curve's vertex, as a fraction of full-scale luma