{
  "schemaVersion": 1,
  "id": "liquid-glass",
  "version": "1.1.0",
  "status": "published",
  "kind": "material",
  "title": "Liquid Glass",
  "summary": "A thick slab of clear glass glides over your backdrop, bending what is behind it with a faint rainbow fringe, and morphs from pill to circle to rounded square. The look from every 2026 interface.",
  "description": "The liquid glass look that spread from Apple’s interfaces into motion design and the web: a rounded, bevelled slab of clear glass that refracts whatever sits behind it, splits light into a subtle colour fringe at its edges (dispersion), catches a bright specular rim from the studio lights and morphs between shapes as it moves. Put it over colour bands, a word, a logo or a photo plane; set the glass thickness, how much it bends light, the frosting and the colour fringe; choose whether it morphs and how far it glides.",
  "role": "Foreground glass element (Three.js) that refracts an opaque backdrop.",
  "collections": [
    "chrome-glass",
    "product-reveals",
    "backgrounds"
  ],
  "tags": [
    "liquid glass",
    "glass",
    "refraction",
    "dispersion",
    "glassmorphism",
    "frosted",
    "pill",
    "morph",
    "apple",
    "ui",
    "3d",
    "three.js",
    "transmission",
    "chromatic"
  ],
  "synonyms": [
    "liquid glass effect",
    "glass pill",
    "glass button",
    "glassmorphism animation",
    "refracting glass",
    "apple liquid glass",
    "glass morph",
    "lens",
    "magnifier",
    "glass overlay"
  ],
  "useCases": [
    "Product or app launch visual",
    "Logo or word under moving glass",
    "Background element for a UI showcase",
    "Transition element over a photo"
  ],
  "featured": 1,
  "publishedAt": "2026-10-03",
  "implementation": {
    "target": "three",
    "runtime": "browser",
    "language": "javascript",
    "module": "esm",
    "entry": "src/liquid-glass.js",
    "exports": [
      {
        "name": "createLiquidGlassMaterial",
        "signature": "createLiquidGlassMaterial({ tint?, ior?, thickness?, roughness?, dispersion?, clearcoat?, envMapIntensity? }) => THREE.MeshPhysicalMaterial",
        "description": "Thick clear glass with transmission, dispersion and a clear coat."
      },
      {
        "name": "createSlabGeometry",
        "signature": "createSlabGeometry({ width?, height?, depth?, radius?, bevel?, segments?, smooth? }) => THREE.BufferGeometry",
        "description": "A rounded-rectangle slab with a bevelled edge and smooth normals; the same vertex count for every shape."
      },
      {
        "name": "createLiquidGlass",
        "signature": "createLiquidGlass({ shapes?, depth?, bevel?, material?, hover?, drift?, tiltAmount?, cycles? }) => { mesh, update(progress), setPhase(phase), shapeAt(phase), setShape(w, h, r), dispose() }",
        "description": "A slab that morphs through shape keyframes with GPU morph targets, hovers and tilts as a pure function of progress (exact loop). setPhase(phase) morphs on its own so you can drive the glass yourself."
      },
      {
        "name": "smoothNormals",
        "signature": "smoothNormals(geometry, creaseDegrees?) => BufferGeometry",
        "description": "Smooths the normals of a non-indexed geometry, keeping edges sharper than the crease angle."
      }
    ],
    "reusable": [
      "src/liquid-glass.js"
    ],
    "demo": "demo.js",
    "harness": "index.html"
  },
  "dependencies": [
    {
      "id": "three",
      "version": "0.185.1",
      "reason": "WebGL rendering (MeshPhysicalMaterial transmission and dispersion)."
    },
    {
      "id": "chrome-material",
      "version": "1.1.0",
      "scope": "demo",
      "reason": "Demo uses the studio environment, cove and floor. Any environment map works with the glass."
    },
    {
      "id": "apw-runtime",
      "version": "1.0.0",
      "scope": "demo",
      "reason": "Demo harness."
    }
  ],
  "params": [
    {
      "key": "backdrop",
      "label": "Behind the glass",
      "type": "select",
      "default": "bands",
      "options": [
        {
          "value": "bands",
          "label": "Colour bands"
        },
        {
          "value": "dots",
          "label": "Dot grid"
        },
        {
          "value": "gradient",
          "label": "Gradient"
        }
      ]
    },
    {
      "key": "text",
      "label": "Word on the backdrop",
      "type": "text",
      "default": "LIQUID",
      "maxLength": 16,
      "sensitive": true
    },
    {
      "key": "morph",
      "label": "Morph between shapes",
      "type": "boolean",
      "default": true
    },
    {
      "key": "cycles",
      "label": "Morph cycles per clip",
      "type": "integer",
      "min": 1,
      "max": 2,
      "step": 1,
      "default": 1
    },
    {
      "key": "thickness",
      "label": "Glass thickness",
      "help": "Thicker glass bends the backdrop more.",
      "type": "number",
      "min": 0.2,
      "max": 0.9,
      "step": 0.01,
      "default": 0.5
    },
    {
      "key": "ior",
      "label": "Bend of light (IOR)",
      "help": "1.5 is window glass, 1.33 water, 2.4 diamond.",
      "type": "number",
      "min": 1.1,
      "max": 2.4,
      "step": 0.01,
      "default": 1.5
    },
    {
      "key": "dispersion",
      "label": "Colour fringe",
      "help": "The rainbow split at the edges. 0 is none.",
      "type": "number",
      "min": 0,
      "max": 0.4,
      "step": 0.01,
      "default": 0.14
    },
    {
      "key": "frost",
      "label": "Frosting",
      "type": "number",
      "min": 0,
      "max": 0.3,
      "step": 0.01,
      "default": 0.02
    },
    {
      "key": "glide",
      "label": "Glide distance",
      "type": "number",
      "min": 0,
      "max": 1.2,
      "step": 0.05,
      "default": 0.55
    },
    {
      "key": "tilt",
      "label": "Tilt",
      "type": "number",
      "min": 0,
      "max": 0.4,
      "step": 0.01,
      "default": 0.16
    },
    {
      "key": "tint",
      "label": "Glass tint",
      "type": "color",
      "default": "#ffffff"
    },
    {
      "key": "colorA",
      "label": "Backdrop colour 1",
      "type": "color",
      "default": "#ff4f3d"
    },
    {
      "key": "colorB",
      "label": "Backdrop colour 2",
      "type": "color",
      "default": "#1e3cff"
    },
    {
      "key": "colorC",
      "label": "Backdrop colour 3",
      "type": "color",
      "default": "#ffd23f"
    },
    {
      "key": "textColor",
      "label": "Word colour",
      "type": "color",
      "default": "#ffffff"
    },
    {
      "key": "background",
      "label": "Background",
      "type": "color",
      "default": "#0f1117"
    }
  ],
  "presets": [
    {
      "id": "default",
      "label": "Bands",
      "params": {}
    },
    {
      "id": "frosted",
      "label": "Frosted pill",
      "params": {
        "frost": 0.09,
        "dispersion": 0.04,
        "morph": false,
        "backdrop": "gradient",
        "colorA": "#2b1c6b",
        "colorB": "#8a3cff",
        "colorC": "#ff6fb5"
      }
    },
    {
      "id": "lens",
      "label": "Thick lens",
      "params": {
        "thickness": 0.9,
        "ior": 1.9,
        "dispersion": 0.3,
        "backdrop": "dots",
        "colorA": "#f1e9d6",
        "colorB": "#1b1e27",
        "colorC": "#d84a2c",
        "background": "#f1f2f4",
        "textColor": "#1b1e27"
      }
    }
  ],
  "output": {
    "width": 1080,
    "height": 1080,
    "fps": 30,
    "durationSeconds": 8,
    "posterSeconds": 1.2,
    "alpha": false,
    "motion": "procedural",
    "loop": {
      "seamless": true,
      "cycleSeconds": 8,
      "method": "Shape keyframes, glide, hover and tilt are periodic in clip progress; the clip returns exactly to its start."
    },
    "seed": null
  },
  "composition": {
    "inputs": "Clip progress (frame / durationFrames). A material and shape keyframes.",
    "outputs": "A THREE.Mesh placed at the origin; update(progress) moves and morphs it.",
    "coordinates": "Y-up, centred on the origin, facing +Z. Default slab about 2.6 × 1.15 × 0.5 units; put the backdrop at z ≈ −1.5.",
    "lighting": "Needs scene.environment for highlights. The studio from Chrome Material works well.",
    "timing": "Pure function of progress. Whole cycles loop exactly.",
    "compatibleWith": [
      "chrome-material",
      "orbit-camera",
      "kinetic-title",
      "gradient-background",
      "glass-container"
    ],
    "notes": [
      "Transmission sees only opaque objects: put a photo, text or colour on an opaque plane behind the glass, not a transparent one.",
      "Morphing uses GPU morph targets (shapes share one vertex count), so it costs nothing per frame; setShape() still rebuilds the geometry and turns morphing off.",
      "To drive the glass yourself (for example from the pointer) call setPhase(phase) and move mesh.position; use mesh.scale for a stretch."
    ]
  },
  "reuse": [
    "Put a logo or product name on the backdrop plane and let the glass glide across it for a launch bumper.",
    "Use it as a lens: a thick, high-IOR slab over a photo plane, driven by Orbit Camera for a slow pass.",
    "Layer Kinetic Title underneath on an opaque canvas texture so the letters refract as they rise."
  ],
  "integration": {
    "newProject": "Create the studio (chrome-material), an opaque backdrop plane at z = −1.6, then createLiquidGlass() and call update(progress) each frame.",
    "existingProject": "Copy src/liquid-glass.js. Add the mesh to your scene with an environment map; call update(progress) or setShape() yourself."
  },
  "performance": {
    "notes": "One transmission pass per frame; dispersion adds three samples. Fine at 1080p on a GPU.",
    "limits": "Software WebGL renders slowly (about 1–3 s per 1080p frame)."
  },
  "limitations": [
    "Glass behind glass is not visible through the front face (a Three.js transmission limit).",
    "The slab is a flat extrusion; it does not deform like a true liquid, it morphs between rounded shapes."
  ],
  "license": {
    "spdx": "MIT",
    "notice": "Copyright (c) 2026 AI Pixel Wizard. Released under the MIT License. See LICENSE in this folder.",
    "thirdParty": []
  },
  "provenance": "Original code written for AI Pixel Wizard on 3 October 2026 by an automated agent, inspired by the liquid glass trend (Apple’s interface material, Webflow’s Three.js refraction showcase, open-source Liquid Glass web implementations on X). No code, images or shaders were copied; the technique is Three.js MeshPhysicalMaterial transmission with dispersion. Version 1.1.0 (4 October 2026) adds smoothed normals and morph targets.",
  "changelog": [
    {
      "version": "1.1.0",
      "date": "2026-10-04",
      "notes": "Smooth normals across the bevel (the refracted backdrop no longer breaks into horizontal bands at the glass edge) and GPU morph targets for shape morphing instead of rebuilding the geometry each frame. New setPhase(phase) and smoothNormals(geometry). Same parameters and look otherwise; the Colour fringe and Bend of light controls now read cleaner."
    },
    {
      "version": "1.0.0",
      "date": "2026-10-03",
      "notes": "Initial release."
    }
  ]
}
