import { z } from "zod/v4"; import { defineApp, defineTool, ui } from "@colineapp/sdk/v2"; import { GROUPS, INSTALL, PACKAGE, RULES, SITE_URL, SUMMARY, VERSION } from "./site/api"; import { reactSnippet, vanillaSnippet } from "./site/snippet"; // The @colineapp/liquid-glass playground and docs, a Coline site at // https://liquid-glass.coline.space. `site/main.tsx` is the page. It keeps no // data. Its two tools answer agents in the visitor's browser (WebMCP) with the // same reference and snippets the page shows. const lookup = defineTool({ name: "liquid-glass.reference", description: "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.", input: z.object({ name: z.string().trim().max(80).optional() }), effect: "read", execute: async ({ name }) => { // `tabs.glass`, `glass` and `magnify(factor)` all find their entries. const wanted = name?.toLowerCase().replace(/^.*\./, "").replace(/\(.*$/, ""); const matches = wanted ? GROUPS.flatMap(group => group.entries .filter(entry => entry.name.toLowerCase().replace(/[<>/\s]/g, "").replace(/\(.*$/, "") === wanted) .map(entry => ({ group: group.title, ...entry })), ) : []; return { output: { package: PACKAGE, version: VERSION, install: INSTALL, summary: SUMMARY, rules: RULES, matches, names: GROUPS.flatMap(group => group.entries.map(entry => `${group.id}.${entry.name}`)), docs: `${SITE_URL}/llms.txt`, }, }; }, }); const snippet = defineTool({ name: "liquid-glass.snippet", description: "Code for a Liquid Glass surface with the given options, in React or plain TypeScript.", input: z.object({ flavor: z.enum(["react", "vanilla"]).default("react"), shape: z.enum(["capsule", "card", "circle"]).optional(), variant: z.enum(["regular", "clear"]).optional(), floating: z.union([z.boolean(), z.literal("dialog")]).optional(), interactive: z.boolean().optional(), swell: z.boolean().optional(), hue: z.string().max(40).nullable().optional(), hueStrength: z.number().min(0).max(1).optional(), refraction: z.boolean().optional(), samples: z.union([z.literal(1), z.literal(4)]).optional(), geometry: z .object({ maxFall: z.number().min(0).max(0.95).optional(), bezel: z.number().min(0).max(80).optional(), thickness: z.number().min(0).max(120).optional(), edge: z.number().min(0).max(4).optional(), glint: z.number().min(0).max(1).optional(), }) .optional(), }), effect: "read", execute: async ({ flavor, ...options }) => ({ output: { code: flavor === "vanilla" ? vanillaSnippet(options) : reactSnippet(options), install: INSTALL }, }), }); export default defineApp({ key: "liquid-glass", name: "Liquid Glass", description: SUMMARY, permissions: ["site.serve", "ai.tools"], hosting: { default: "coline" }, surfaces: { home: { tier: "tree" }, site: { entry: "site/main.tsx", assets: "site/public", title: "Liquid Glass for the web", description: SUMMARY, routes: [ { path: "/", head: { title: "Liquid Glass for the web ยท @colineapp/liquid-glass", image: "/og.png", description: SUMMARY, }, }, ], tools: ["liquid-glass.reference", "liquid-glass.snippet"], // Agents in the visitor's browser can look up the API and get code. agentTools: true, }, }, tools: [lookup, snippet], handlers: { renderHome: async () => ui.stack([ ui.heading("Liquid Glass", { level: 1 }), ui.text(SUMMARY, { tone: "muted" }), ui.text(`The playground is at ${SITE_URL}. Install with ${INSTALL}.`), ]), }, });