---
title: Camera Feed in Swift
description: Start a live camera feed app on WendyOS using the Swift camera template
language: swift
---

## Live Camera Feed with Swift

Use the Wendy camera template when you want a browser-viewable camera stream without wiring the project from scratch. The template includes `wendy.json`, camera entitlements, a Dockerfile, Swift backend code, and the browser UI.

### Prerequisites

- Wendy CLI installed on your development machine
- Swift 6.2 or later installed **via [swiftly](https://www.swift.org/install/)**
- A WendyOS device with a USB camera connected

## Setting Up Your Project

<Steps>
  <Step>
    ### Initialize the Project

    ```bash
    wendy init swift-camera --target wendyos --language swift --template camera-feed --var APP_ID=swift-camera --var PORT=6003 --var SWIFT_VERSION=6.3 --assistant skip --git-init no
    cd swift-camera
    ```

    <CliShot flow="init" step="wizard" alt="wendy init scaffolding the Swift camera-feed project" />

    The generated project is ready to run. After the first run, use the sections below as a code breakdown when you want to understand or customize camera handling, routes, or UI behavior.
  </Step>

  <Step>
    ### Run on WendyOS

    ```bash
    wendy run
    ```

    <CliShot flow="run" step="deploy" alt="wendy run deploying the Swift camera-feed container" />

    Wendy will build the app, ask you to select a device if one is not already configured, deploy the container, and print the app URL.
  </Step>
</Steps>

## Code Breakdown

Open the app URL (`http://${WENDY_HOSTNAME}:6003`) from the Wendy run output to view the stream. The `postStart` hook in `wendy.json` opens it for you automatically once the server is ready.

### Project Structure

The generated project looks like this:

```
swift-camera/
├── Package.swift
├── Dockerfile
├── wendy.json
├── .swift-version
├── index.html
├── assets/
│   └── wendy-logo.svg
└── Sources/
    └── swift-camera/
        ├── App.swift
        ├── MJPEGCamera.swift
        ├── CameraDiscovery.swift
        ├── JPEGFrameParser.swift
        └── StaticFileMiddleware.swift
```

### Generated wendy.json

The template requests host networking, camera, and GPU entitlements, and registers a readiness probe plus a browser hook on port `6003`:

```json
{
    "appId": "swift-camera",
    "platform": "linux",
    "version": "0.1.0",
    "entitlements": [
        {
            "type": "network",
            "mode": "host"
        },
        {
            "type": "camera"
        },
        {
            "type": "gpu"
        }
    ],
    "readiness": {
        "tcpSocket": { "port": 6003 },
        "timeoutSeconds": 30
    },
    "hooks": {
        "postStart": {
            "cli": "wendy utils open-browser http://${WENDY_HOSTNAME}:6003"
        }
    }
}
```

### Generated Server Routes

`Sources/swift-camera/App.swift` builds a Hummingbird server with WebSocket support and exposes:

- `GET /health` — returns `200 OK`
- `GET /cameras` — lists detected cameras as JSON
- `WS /stream` — streams MJPEG frames over a WebSocket; send `{"switch_camera": "<device>"}` to change the source camera
- `GET /` and `GET {path+}` — serve the bundled `index.html` single-page UI

The camera is captured via GStreamer/V4L2 in `MJPEGCamera.swift`, with device enumeration in `CameraDiscovery.swift` and JPEG frame extraction in `JPEGFrameParser.swift`.

### Generated Dockerfile

The multi-stage Dockerfile builds the binary with `swift:6.3-bookworm` and runs it on `swift:6.3-bookworm-slim` with GStreamer and V4L2 installed:

```dockerfile
# Stage 1: Build the Swift application
FROM swift:6.3-bookworm AS builder
WORKDIR /app
COPY Package.swift ./
COPY Sources Sources
RUN swift build -c release

# Stage 2: Runtime image with GStreamer and V4L2
FROM swift:6.3-bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
    gstreamer1.0-tools \
    gstreamer1.0-plugins-base \
    gstreamer1.0-plugins-good \
    gstreamer1.0-plugins-bad \
    gstreamer1.0-plugins-ugly \
    v4l-utils \
    ca-certificates \
    && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/.build/release/swift-camera /usr/local/bin/swift-camera
COPY index.html ./index.html
COPY assets/ ./assets/
EXPOSE 6003
CMD ["swift-camera"]
```
