Components
Callout
A world-object annotation: an anchor + a vertical leader up to an emitted label (no box — just a leader line + emitted type). Project x from relative bearing like Pin (lib/geo). World-anchored, never mirrored.
Installation
npx @glasskit-ui/cli add calloutInstall the SDK (it provides GlassViewport, useDpad and the stylesheet), then copy these files into your project:
npm install @glasskit-ui/react// components/lib/utils.tsexport type ClassValue = string | number | null | undefined | false;/** * Join truthy class names. Dependency-free on purpose: the lens components * style via bespoke semantic classes (no conflicting Tailwind utilities to * de-dupe), so this needs no clsx/tailwind-merge and resolves from anywhere * the registry is vendored. */export function cn(...inputs: ClassValue[]): string { return inputs.filter(Boolean).join(" ");}/** * Accessible name from a free-form `label` prop: the label itself when it's a * plain string, otherwise undefined (a ReactNode can't become an aria-label). */export function stringLabel(label: unknown): string | undefined { return typeof label === "string" ? label : undefined;}// components/glasskit/callout.tsximport type { ReactNode } from "react";import { cn } from "../lib/utils";/** * <Callout> — a world-object annotation: a small anchor at a screen point with a * vertical leader line up to an emitted label (no box — additive translates the * card to line + type). `x`/`y` are 0–100 (% of the lens). * * WORLD-ANCHORED — placed by an SVG `transform="translate()"` *attribute*, so it * never mirrors under RTL. The leader is vertical (no inline-direction), keeping * the annotation tied to its real-world point in any writing direction. * * Projection: same recipe as <Pin> — the platform exposes heading + GPS but no * 3D pose, so derive x from the target's relative bearing (`lib/geo`: * `relativeBearing(bearingBetween(me, target), heading)` mapped across the * FOV) and keep y a fixed band. Hide it once the target leaves the FOV. */export function Callout({ x, y, label, detail, className,}: { /** 0–100, % of the lens width. */ x: number; /** 0–100, % of the lens height. */ y: number; label: ReactNode; detail?: ReactNode; className?: string;}) { const cx = Math.round((x / 100) * 600); const cy = Math.round((y / 100) * 600); return ( <svg viewBox="0 0 600 600" className={cn("gk-worldlayer", className)} role="img" aria-label={typeof label === "string" ? label : "Annotation"} > <g transform={`translate(${cx} ${cy})`}> <circle r={6} className="gk-callout__anchor" /> <line x1={0} y1={0} x2={0} y2={-46} className="gk-callout__leader" /> {detail != null ? ( <text y={-82} className="gk-callout__detail"> {detail} </text> ) : null} <text y={-58} className="gk-callout__label"> {label} </text> </g> </svg> );}Usage
<Callout x={x} y={y} label="Powell St" detail="Muni · 3 min" />Props
Prop
Type
Tabs
A top-level tab strip (the home's quick-controls | home | apps pager). Each tab is D-pad-focusable; the active one gets an accent underline. Controlled via value + onChange.
Compass
A heading rose: North stays world-aligned while a fixed top marker shows where you face. World-anchored — never mirrored under RTL.