GlassKit UI
Components

Viewfinder

Camera-POV chrome: bold corner brackets, optional zoom and REC badges. Web apps have no camera access — this is presentation scaffolding for a camera-style UI; recording is app state you set.

Standby

600 × 600 · live

Platform wishlist — built and waiting on camera access (getUserMedia or a capture API). The UI ships today; the day Meta exposes the API, it plugs in. See the wishlist →

Installation

npx @glasskit-ui/cli add viewfinder

Install 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/viewfinder.tsximport type { ReactNode } from "react";import { cn } from "../lib/utils";/** * <Viewfinder> — camera-POV chrome: corner brackets framing the shot, an * optional zoom badge and a REC indicator. `children` overlays (e.g. a focus * reticle). World-anchored framing — corners use physical positioning, never * mirrored. * * Platform note (2026-06): web apps on the Display have NO camera access — * no getUserMedia, no capture API. This is presentation scaffolding for a * camera-style UI (the lens shows the real world through the brackets), not * a working viewfinder. `recording` is app state you set; nothing records. */export function Viewfinder({  zoom,  recording = false,  children,  className,}: {  /** Zoom badge text, e.g. "1×" / "3×". */  zoom?: ReactNode;  recording?: boolean;  children?: ReactNode;  className?: string;}) {  return (    <div      className={cn("gk-viewfinder", className)}      role="img"      aria-label="Camera viewfinder"    >      <span className="gk-viewfinder__c gk-viewfinder__c--tl" />      <span className="gk-viewfinder__c gk-viewfinder__c--tr" />      <span className="gk-viewfinder__c gk-viewfinder__c--bl" />      <span className="gk-viewfinder__c gk-viewfinder__c--br" />      {zoom != null ? (        <span className="gk-viewfinder__zoom t-caption">{zoom}</span>      ) : null}      {recording ? (        <span className="gk-viewfinder__rec t-caption">          <span className="gk-viewfinder__dot" aria-hidden="true" />          REC        </span>      ) : null}      {children}    </div>  );}

Usage

<Viewfinder zoom="3×" recording>  <Reticle active /></Viewfinder>

Props

Prop

Type