Capability Gate
A true gate: renders children only when the device meets a stated requirement (e.g. WebGPU), otherwise a themed fallback with guidance.
Capability Gate
The Capability Gate renders its children only when the device meets a stated requirement (e.g. requires="webgpu"), and otherwise renders a fallback slot with guidance. Local models have hard device requirements — LiteRT Gemma is WebGPU-only — so gating prevents a broken experience and gives a clear, themeable explanation instead. The capability check uses useCapabilities.
Preview
Installation
pnpm dlx shadcn@latest add @localmode/ui/local-first/capability-gatenpx shadcn@latest add @localmode/ui/local-first/capability-gateyarn dlx shadcn@latest add @localmode/ui/local-first/capability-gatebunx --bun shadcn@latest add @localmode/ui/local-first/capability-gateData source & dependencies
Data source: detects device capabilities via the bundled useCapabilities navigator hook — self-contained, works in any React app, no backend required. (It mirrors the detection useCapabilities from @localmode/react performs, plus copy-owned camera/microphone media-input availability entries via enumerateDevices() — never prompting.)
@localmode/ui/lib/use-environment— the bundleduseCapabilitiesnavigator hook (installed automatically as a registry dependency)clsx+tailwind-merge— via the sharedcn()util (installed automatically as a registry dependency)
Files installed
capability-gate.tsx— theCapabilityGatecomponentlib/use-environment.ts— the bundleduseCapabilitiesnavigator hooklib/utils.ts— thecn()helper (if not already present)
Props
CapabilityGate
Prop
Type
Examples
Gate a WebGPU-only model
<CapabilityGate
requires="webgpu"
fallback={<p>This model needs WebGPU. Try Chrome 113+.</p>}
>
<FastWebGPUModel />
</CapabilityGate>Gate a media surface (camera / microphone)
The camera and microphone capabilities gate on media-input availability — a secure context, navigator.mediaDevices.getUserMedia present, and enumerateDevices() reporting at least one device of that kind. The detection never prompts the user. Runtime permission denial is deliberately not gated: request permission from your own start action and surface a getUserMedia rejection as a recoverable error with retry.
<CapabilityGate
requires="camera"
fallback={<p>No camera detected on this device.</p>}
>
<WebcamHandTracking /> {/* calls getUserMedia on its own Start action */}
</CapabilityGate>
<CapabilityGate requires="microphone">
<RecordAndClassify />
</CapabilityGate>Customization
The default fallback and pending slots are themed amber/muted notices — pass your own fallback/pending nodes for full control. The requires union covers webgpu, wasm, webnn, simd, threads, indexeddb, webworkers, sharedarraybuffer, and the media-availability entries camera and microphone; add more by extending the LABELS map. Styled entirely with shadcn/ui CSS-variable utilities so it inherits your theme — because you own the copied file, every class and threshold is yours to change.
Model Loading Panel
A full-height "waiting for model" splash combining metadata, a progress bar, and a first-download-vs-cache-load help message.
Device Capability Grid
A full device-capability diagnostic card — the expanded sibling of Device Badge — with a stats bar, feature-flag grid, storage, and browser/OS footer.