Liquid Glass for the web: the rim refraction, light and motion of iOS 27 glass on any rounded element. React bindings and pill tabs. MIT.
| 5 |
| 6 | // The @colineapp/liquid-glass playground and docs, a Coline site at |
| 7 | // https://liquid-glass.coline.space. `site/main.tsx` is the page. It keeps no |
| 8 | // data. Its two tools answer agents in the visitor's browser (WebMCP) with the |
| 9 | // same reference and snippets the page shows. |
| 10 |
| 11 | const lookup = defineTool({ |
| 12 | name: "liquid-glass.reference", |
| 13 | description: |
| 14 | "Look up @colineapp/liquid-glass's API: an option (variant, floating, swell, hue, samples...), a geometry field (maxFall, edge, glint...), a method (magnify, materialize...) or a tabs option. Leave `name` out for the rules and every name.", |
| 15 | input: z.object({ name: z.string().trim().max(80).optional() }), |
| 16 | effect: "read", |
| 17 | execute: async ({ name }) => { |
| 18 | // `tabs.glass`, `glass` and `magnify(factor)` all find their entries. |
| 19 | const wanted = name?.toLowerCase().replace(/^.*\./, "").replace(/\(.*$/, ""); |
| 20 | const matches = wanted |
| 21 | ? GROUPS.flatMap(group => |
| 22 | group.entries |
| 23 | .filter(entry => entry.name.toLowerCase().replace(/[<>/\s]/g, "").replace(/\(.*$/, "") === wanted) |
| 24 | .map(entry => ({ group: group.title, ...entry })), |
| 25 | ) |
| 26 | : []; |
| 27 | return { |
| 28 | output: { |
| 29 | package: PACKAGE, |
| 30 | version: VERSION, |
| 31 | install: INSTALL, |
| 32 | summary: SUMMARY, |
| 33 | rules: RULES, |
| 34 | matches, |
| 35 | names: GROUPS.flatMap(group => group.entries.map(entry => `${group.id}.${entry.name}`)), |
| 36 | docs: `${SITE_URL}/llms.txt`, |
| 37 | }, |
| 38 | }; |
| 39 | }, |
| 40 | }); |
| 41 |
| 42 | const snippet = defineTool({ |
| 43 | name: "liquid-glass.snippet", |
| 44 | description: "Code for a Liquid Glass surface with the given options, in React or plain TypeScript.", |
| 45 | input: z.object({ |
| 46 | flavor: z.enum(["react", "vanilla"]).default("react"), |
| 47 | shape: z.enum(["capsule", "card", "circle"]).optional(), |
| 48 | variant: z.enum(["regular", "clear"]).optional(), |
| 49 | floating: z.union([z.boolean(), z.literal("dialog")]).optional(), |
| 50 | interactive: z.boolean().optional(), |
| 51 | swell: z.boolean().optional(), |
| 52 | hue: z.string().max(40).nullable().optional(), |
| 53 | hueStrength: z.number().min(0).max(1).optional(), |
| 54 | refraction: z.boolean().optional(), |
| 55 | samples: z.union([z.literal(1), z.literal(4)]).optional(), |
| 56 | geometry: z |
| 57 | .object({ |
| 58 | maxFall: z.number().min(0).max(0.95).optional(), |
| 59 | bezel: z.number().min(0).max(80).optional(), |
| 60 | thickness: z.number().min(0).max(120).optional(), |
| 61 | edge: z.number().min(0).max(4).optional(), |
| 62 | glint: z.number().min(0).max(1).optional(), |
| 63 | }) |
| 64 | .optional(), |
| 65 | }), |
| 66 | effect: "read", |
| 67 | execute: async ({ flavor, ...options }) => ({ |
| 68 | output: { code: flavor === "vanilla" ? vanillaSnippet(options) : reactSnippet(options), install: INSTALL }, |
| 69 | }), |
| 70 | }); |
| 71 |
| 72 | export default defineApp({ |
| 73 | key: "liquid-glass", |
| 74 | name: "Liquid Glass", |
| 75 | description: SUMMARY, |
| 76 | permissions: ["site.serve", "ai.tools"], |
| 77 | hosting: { default: "coline" }, |
| 78 | surfaces: { |
| 79 | home: { tier: "tree" }, |
| 80 | site: { |
| 81 | entry: "site/main.tsx", |
| 82 | assets: "site/public", |
| 83 | title: "Liquid Glass for the web", |
| 84 | description: SUMMARY, |
| 85 | routes: [ |
| 86 | { |
| 87 | path: "/", |
| 88 | head: { |
| 89 | title: "Liquid Glass for the web · @colineapp/liquid-glass", |
| 90 | image: "/og.png", |
| 91 | description: SUMMARY, |
| 92 | }, |
| 93 | }, |
| 94 | ], |
| 95 | tools: ["liquid-glass.reference", "liquid-glass.snippet"], |
| 96 | // Agents in the visitor's browser can look up the API and get code. |
| 97 | agentTools: true, |
| 98 | }, |
| 99 | }, |
| 100 | tools: [lookup, snippet], |
| 101 | handlers: { |
| 102 | renderHome: async () => |
| 103 | ui.stack([ |
| 104 | ui.heading("Liquid Glass", { level: 1 }), |
| 105 | ui.text(SUMMARY, { tone: "muted" }), |
| 106 | ui.text(`The playground is at ${SITE_URL}. Install with ${INSTALL}.`), |
| 107 | ]), |
| 108 | }, |
| 109 | }); |
| 110 |