From e7ccc3c7aec05372d162924bfe3416c9a89cc7a9 Mon Sep 17 00:00:00 2001 From: Mikalai Silivonik Date: Thu, 26 Mar 2026 17:28:02 -0400 Subject: [PATCH] Rewrite README with comprehensive API documentation Replace the minimal README with full documentation covering all components (CameraKitProvider, LensPlayer, LiveCanvas/CaptureCanvas), hooks (useCameraKit, useApplyLens, useApplySource, usePlaybackOptions), media sources, error handling patterns, and a complete Lens switcher example. Co-Authored-By: Claude Opus 4.6 (1M context) --- README.md | 368 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 304 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index 073aa7e..b5fa8cb 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # @snap/react-camera-kit -React Camera Kit for web applications. +The official React wrapper for the [Camera Kit Web SDK](https://developers.snap.com/camera-kit/integrate-sdk/web/web-configuration). It provides declarative components and hooks that handle SDK bootstrapping, session lifecycle, media sources, and Lens management — so you can integrate Snap AR into React apps with minimal boilerplate. -**[Live Demo](https://snapchat.github.io/react-camera-kit/)** +**[Live Demo](https://snapchat.github.io/react-camera-kit/)** · **[Camera Kit Docs](https://developers.snap.com/camera-kit/integrate-sdk/web/guides/react-camera-kit)** ## Installation @@ -10,107 +10,347 @@ React Camera Kit for web applications. npm install @snap/react-camera-kit @snap/camera-kit ``` -## Prerequisites +### Requirements -Before using this package, complete Camera Kit Web setup and obtain: +- `@snap/camera-kit` `^1.13.0` (peer dependency) +- `react` `>=16.8.0` and `react-dom` `>=16.8.0` +- `rxjs` `>=7` +- `https://` for deployed apps (`http://localhost` works for local development) -- `apiToken` -- `lensId` -- `lensGroupId` -- `https://` for deployed apps (`http://localhost` should works for local dev) +You'll need a Camera Kit API token, Lens ID, and Lens Group ID from the [Snap Developer Portal](https://kit.snapchat.com/manage). See [Setting Up Accounts](https://developers.snap.com/camera-kit/getting-started/setting-up-accounts) if you're new to Camera Kit. -Full setup guides: +## Quick start -- Camera Kit Web configuration: https://developers.snap.com/camera-kit/integrate-sdk/web/web-configuration -- `@snap/camera-kit` docs: https://www.npmjs.com/package/@snap/camera-kit +```tsx +import { CameraKitProvider, LensPlayer } from "@snap/react-camera-kit"; -## Compatibility +function App() { + return ( + + + + ); +} +``` -- Requires `@snap/camera-kit` `^1.13.0`, because `1.13.0+` includes the SDK-side font bootstrap behavior needed by this package. +That's it — `CameraKitProvider` initializes the SDK, and `LensPlayer` sets up the camera, applies the Lens, and renders the output canvas. -## Usage +## Components -This package provides a simple API for integrating Camera Kit into React applications. +### CameraKitProvider -The simplest use case is: +The root provider that initializes the Camera Kit SDK. All other components and hooks must be descendants of this provider. ```tsx - - - +import { CameraKitProvider, createConsoleLogger } from "@snap/react-camera-kit"; + + + {children} +; ``` -if you need to render specific canvas with custom layout: +| Prop | Type | Default | Description | +| ----------------------------- | ---------------------------------------- | ------------ | ------------------------------------------------------------- | +| `apiToken` | `string` | **required** | Camera Kit API token | +| `logger` | `CameraKitLogger` | `noopLogger` | Logger instance — use `createConsoleLogger()` for development | +| `logLevel` | `"debug" \| "info" \| "warn" \| "error"` | `"info"` | Log verbosity | +| `renderWhileTabHidden` | `boolean` | `false` | Continue rendering when the browser tab is hidden | +| `stabilityKey` | `string \| number` | auto | Manual control over when the SDK re-initializes | +| `extendContainer` | `(container) => container` | — | Customize the SDK's DI container | +| `createBootstrapEventHandler` | `MetricEventHandlerFactory` | — | Factory for tracking bootstrap success/failure | + +### LensPlayer + +All-in-one component that handles source setup, Lens application, and playback. Defaults to the user's camera if no `source` is provided. ```tsx - - -
- -
-
- -
-
-
+ ``` -if you need to access lens status (assuming `CameraKitProvider` context): +| Prop | Type | Default | Description | +| ---------------- | ----------------------- | -------------------- | ------------------------------------------------------------------------------------------------ | +| `lensId` | `string` | — | Lens to apply | +| `lensGroupId` | `string` | — | Lens Group containing the Lens | +| `source` | `SourceInput` | `{ kind: "camera" }` | Media source (camera, video, or image) | +| `outputSize` | `OutputSize` | — | Rendering canvas size | +| `lensLaunchData` | `LensLaunchData` | — | Launch parameters passed to the Lens | +| `lensReadyGuard` | `() => Promise` | — | Async guard called while Lens is loading (2s timeout) | +| `refreshTrigger` | `unknown` | — | When this value changes, the Lens is removed and reapplied | +| `canvasType` | `"live" \| "capture"` | `"live"` | Which canvas to render. For custom layouts, use `LiveCanvas`/`CaptureCanvas` as children instead | +| `fpsLimit` | `number` | — | Maximum rendering framerate | +| `muted` | `boolean` | `false` | Mute audio output | +| `screenRegions` | `ScreenRegions` | — | Screen regions for Lens-aware UI layout | +| `onError` | `(error, lens) => void` | — | Callback for playback errors | +| `className` | `string` | — | CSS class name | +| `style` | `CSSProperties` | — | Inline styles | +| `children` | `ReactNode` | — | Custom children (use with `LiveCanvas`/`CaptureCanvas`) | + +### LiveCanvas / CaptureCanvas + +Render the live preview or capture canvas as children of `LensPlayer`: ```tsx -function Preview() { - const { lens } = useCameraKit(); + +
+ +
+
+ +
+
+``` + +Both accept `className` and `style` props. + +## Hooks + +### useCameraKit + +Access the full Camera Kit context — SDK status, source/Lens state, and imperative methods. Must be called within a `CameraKitProvider`. + +```tsx +import { useCameraKit } from "@snap/react-camera-kit"; + +function Controls() { + const { sdkStatus, lens, lenses, isMuted, toggleMuted, applyLens, removeLens, fetchLenses } = useCameraKit(); + + if (sdkStatus !== "ready") return

Loading SDK...

; + return ( - - {lens.status !== "ready" && lens.status !== "error" && } - {lens.status === "error" && } - {lens.status === "ready" && } - +
+

Lens: {lens.lensId ?? "None"}

+ + +
); } ``` -When you need full control (assuming `CameraKitProvider` context): +**State properties:** + +| Property | Type | Description | +| --------------- | --------------------------------------------------------- | --------------------------------------- | +| `sdkStatus` | `"uninitialized" \| "initializing" \| "ready" \| "error"` | SDK initialization status | +| `sdkError` | `Error \| undefined` | Error from SDK initialization | +| `source` | `CurrentSource` | Current source status, input, and error | +| `lens` | `CurrentLens` | Current Lens status, IDs, and error | +| `lenses` | `Lens[]` | Array of loaded Lens objects | +| `liveCanvas` | `HTMLCanvasElement \| undefined` | Live preview canvas element | +| `captureCanvas` | `HTMLCanvasElement \| undefined` | Capture canvas element | +| `keyboard` | `Keyboard \| undefined` | Keyboard API for Lens keyboard requests | +| `isMuted` | `boolean` | Whether audio is muted | +| `fpsLimit` | `number \| undefined` | Current FPS limit | +| `screenRegions` | `ScreenRegions \| undefined` | Current screen regions | + +**Methods:** + +| Method | Description | +| ------------------------------------------------------ | ------------------------------------------------------- | +| `applySource(input, size?)` | Apply a media source (camera, video, or image) | +| `removeSource()` | Remove the current source | +| `fetchLens(lensId, groupId)` | Load a single Lens (returns cached if already loaded) | +| `fetchLenses(groupId)` | Load all Lenses in a group (accepts string or string[]) | +| `applyLens(lensId, groupId, launchData?, readyGuard?)` | Apply a Lens by ID | +| `removeLens()` | Remove the current Lens | +| `refreshLens()` | Remove and reapply the current Lens | +| `reinitialize()` | Re-bootstrap the SDK (useful after errors) | +| `setMuted(muted)` | Set the muted state | +| `toggleMuted()` | Toggle audio mute | +| `setFPSLimit(fps)` | Set maximum rendering FPS | +| `setScreenRegions(regions)` | Set screen regions for Lens-aware layout | + +### useApplyLens + +Declaratively apply a Lens — it updates automatically when parameters change. + +```tsx +import { useApplyLens } from "@snap/react-camera-kit"; + +useApplyLens("YOUR_LENS_ID", "YOUR_LENS_GROUP_ID"); +``` + +| Parameter | Type | Description | +| ---------------- | --------------------- | ------------------------------------ | +| `lensId` | `string \| undefined` | Lens ID — pass `undefined` to remove | +| `lensGroupId` | `string \| undefined` | Lens Group ID | +| `lensLaunchData` | `LensLaunchData` | Optional launch parameters | +| `lensReadyGuard` | `() => Promise` | Optional async ready guard | + +### useApplySource + +Declaratively apply a media source. Defaults to camera if no source is provided. + +```tsx +import { useApplySource } from "@snap/react-camera-kit"; + +// Video source with fixed output size +useApplySource({ kind: "video", url: "/demo.mp4", autoplay: true }, { mode: "fixed", width: 720, height: 1280 }); +``` + +| Parameter | Type | Default | Description | +| ------------ | ------------- | -------------------- | -------------- | +| `source` | `SourceInput` | `{ kind: "camera" }` | Media source | +| `outputSize` | `OutputSize` | — | Rendering size | + +### usePlaybackOptions + +Declaratively set playback options. + +```tsx +import { usePlaybackOptions } from "@snap/react-camera-kit"; + +usePlaybackOptions({ + fpsLimit: 30, + muted: false, + onError: (error) => console.error("Playback error:", error), +}); +``` + +| Option | Type | Description | +| --------------- | ----------------------- | ------------------------------ | +| `fpsLimit` | `number` | Maximum rendering FPS | +| `muted` | `boolean` | Mute audio | +| `screenRegions` | `ScreenRegions` | Screen regions for Lens layout | +| `onError` | `(error, lens) => void` | Playback error callback | + +## Media sources + +Pass a `SourceInput` to `LensPlayer`'s `source` prop or to `useApplySource`: + +```tsx +// Camera (default) +{ kind: "camera" } +{ kind: "camera", deviceId: "abc123", options: { cameraFacing: "environment" } } + +// Video +{ kind: "video", url: "/demo.mp4", autoplay: true } + +// Image +{ kind: "image", url: "/photo.jpg" } +``` + +### Camera source options + +| Option | Type | Default | Description | +| ------------------- | ------------------------- | ------------------------------ | ----------------------------- | +| `cameraFacing` | `"user" \| "environment"` | `"user"` | Front or back camera | +| `cameraConstraints` | `MediaTrackConstraints` | `{ width: 1280, height: 720 }` | Camera resolution constraints | +| `cameraRotation` | `0 \| -90 \| 90 \| 180` | `0` | Camera rotation | +| `fpsLimit` | `number` | — | Max FPS for the source | +| `outputSize` | `OutputSize` | — | Rendering canvas size | + +### Output size + +```tsx +// Fixed resolution +{ mode: "fixed", width: 720, height: 1280 } + +// Match input source resolution +{ mode: "match-input" } +``` + +## Handling loading and error states + +Use `useCameraKit()` to track the status of the SDK, source, and Lens. Each progresses through `"none" → "loading" → "ready"` (or `"error"`): ```tsx function Preview() { - const { sdkStatus, source, lens } = useCameraKit(); - useApplySource({ kind: "video", url: "/demo.mp4" }, { mode: "fixed", width: 720, height: 1280 }); - useApplyLens("123", "abc", launchData); - usePlaybackOptions({ onError: (error) => console.error(error) }); + const { sdkStatus, sdkError, source, lens } = useCameraKit(); - if (sdkStatus !== "ready" || source.status !== "ready" || lens.status !== "ready") { - return ; - } - return ; + if (sdkStatus === "error") return

SDK failed: {sdkError?.message}

; + if (sdkStatus !== "ready") return

Initializing...

; + if (source.status === "loading") return

Setting up camera...

; + if (lens.status === "error") return

Lens error: {lens.error?.message}

; + + return ( + + {lens.status !== "ready" &&
} + + + ); } ``` -## Development +## Full example: Lens switcher -```bash -# Install dependencies -npm install +```tsx +import { CameraKitProvider, LensPlayer, LiveCanvas, useCameraKit } from "@snap/react-camera-kit"; +import { useEffect } from "react"; + +const LENS_GROUP_ID = "YOUR_LENS_GROUP_ID"; + +function LensSwitcher() { + const { sdkStatus, lenses, lens, fetchLenses, applyLens, isMuted, toggleMuted, reinitialize, sdkError } = + useCameraKit(); + + useEffect(() => { + if (sdkStatus === "ready") fetchLenses(LENS_GROUP_ID); + }, [sdkStatus]); + + if (sdkStatus === "error") { + return ( +
+

SDK error: {sdkError?.message}

+ +
+ ); + } -# Build the package (ESM + CJS) -npm run build + return ( +
+ + + + + + +
+ ); +} + +export default function App() { + return ( + + + + ); +} +``` -# Build in watch mode (for development) -npm run watch +## Utilities -# Type checking -npm run typecheck +| Export | Description | +| ------------------------ | --------------------------------------------------- | +| `createConsoleLogger()` | Returns a logger that prints to the browser console | +| `createNoopLogger()` | Returns a silent logger (default) | +| `isCameraSource(source)` | Type guard for `CameraSourceInput` | +| `isVideoSource(source)` | Type guard for `VideoSourceInput` | +| `isImageSource(source)` | Type guard for `ImageSourceInput` | +| `CameraRotationOptions` | Valid rotation values: `[0, -90, 90, 180]` | -# Run tests -npm test +## Development -# Clean dist folder -npm run clean +```bash +npm install # Install dependencies +npm run build # Build ESM + CJS +npm run watch # Build in watch mode +npm run typecheck # Type checking +npm test # Run tests +npm run clean # Clean dist folder ``` -## Demo App +### Demo app -A Vite demo app is available at `demo`. +A Vite demo app is available in `demo/`: ```bash npm run demo:install @@ -120,7 +360,7 @@ npm run demo:dev ## Contributing -We welcome contributions! Please see our [Contributing Guidelines](CONTRIBUTING.md) for details on how to get started. +We welcome contributions! Please see our [Contributing Guidelines](CONTRIBUTING.md) for details. - [Code of Conduct](CODE_OF_CONDUCT.md) - [Security Policy](SECURITY.md)