Docs index: /llms.txt · every page as Markdown: add .md

‹ Platforms

macOS

Render Essence 2 and Expression 2 on a Mac with Apple silicon.

On the deviceApple siliconAPI secretSwift package 2.20.5

The iPhone and iPad Swift package, in a Mac app or from a terminal with swift run.

Before you start

No device, provisioning profile or entitlement is needed to try it from a terminal.

Why render on the device.

You needExpression 2Essence 2
A MacApple silicon, macOS 13 or newerApple silicon M3 or newer, macOS 26 or newer
ToolchainXcode 26 or newer (to build; Xcode 26 needs macOS 15.6 or newer)the same
Credentialan API secret (Creator plan or higher)the same
Diskabout 800 MB for the example: downloads plus the folder the engine unpacks them intoabout 250 MB of downloads

Install

In Xcode choose File → Add Package Dependencies… and paste https://gitlab.com/bithuman/sdk/homebrew-bithuman. In a Package.swift:

.package(url: "https://gitlab.com/bithuman/sdk/homebrew-bithuman", from: "2.20.5")
// then attach the product your target uses:
//   .product(name: "Expression2", package: "homebrew-bithuman")
//   .product(name: "Essence2Kit", package: "homebrew-bithuman")
//   .product(name: "Essence2", package: "homebrew-bithuman")

The products:

ProductImportWhat it isDeployment target
Expression2import Expression2the Expression 2 engine with a Swift APIiOS 16 · macOS 13
Essence2Kitimport Essence2Kitthe Essence 2 engine with a Swift API; it includes Essence2iOS 26 · macOS 26
Essence2import Essence2the Essence 2 engine as a C library, for C, C++ and pluginsiOS 26 · macOS 26

Every product ships ios-arm64, ios-arm64-simulator (arm64 only) and macos-arm64.

Authenticate

The engines check an API secret when a session starts. Set BITHUMAN_API_SECRET in the scheme's environment, or pass it in code before you create an engine: Expression2Credential.set(secret) or Essence2Credential.set(secret) (Your API secret).

The scheme's environment is for local builds. A shipped app fetches its secret from your backend and keeps it in the Keychain (What a shipped app holds).

A Mac app built from Xcode’s App template turns on App Sandbox. Under Signing & Capabilities → App Sandbox, tick Outgoing Connections (Client), or the engines cannot check your secret.

Run your first avatar

The macOS Expression 2 example is one Swift file. Clone it, fetch the sample avatar, and run it:

git clone https://github.com/bithuman-product/bithuman-examples.git
cd bithuman-examples/swift/macos-expression2
./setup.sh                                 # the wise-pup avatar, the shared engine and a speech clip
export BITHUMAN_API_SECRET="<your API secret>"
swift run -c release MacOSExpression2
Expected result
engine ready: 416x720, isReady=true
audio: 325451 samples, 20.34 s
generated 407 frames in … s -> out/first-frame.png

407 frames for 20.34 seconds of audio: one frame per 50 ms of speech. The first run prepares the engine for your Mac; keep Model/staged/ and later runs start faster.

The core of Sources/main.swift:

// excerpt: swift/macos-expression2/Sources/main.swift
let engine = try Expression2Engine.create(
    avatarContainer: model.appendingPathComponent("agent.imx"),
    sharedEngineContainer: model.appendingPathComponent("shared-engine.imx"),
    stagingDir: model.appendingPathComponent("staged"))
// …
let started = Date()
engine.feed(samples)
engine.flushTail()
// …
var frames = 0, idleTicks = 0
while idleTicks < 100 {
    var got = false
    while let (frame, _) = engine.pull() {
        if frames == 0 {
            writePNG(frame, width: engine.width, height: engine.height,
                     to: out.appendingPathComponent("first-frame.png"))
        }
        frames += 1
        got = true
    }
    if got { idleTicks = 0 } else { idleTicks += 1; usleep(50_000) }
}

Essence 2 on a Mac

Essence 2 needs an M3 or newer Mac on macOS 26. The same Essence2Kit calls as on the iPhone render a file from a terminal tool: download the avatar in code, set pacing = .unpaced, and take the frames as fast as they render.

// excerpt: a terminal tool (swift run) with the Essence2Kit product;
// samples is a 16 kHz mono clip as [Float].
import Essence2Kit

Essence2Credential.set(ProcessInfo.processInfo.environment["BITHUMAN_API_SECRET"] ?? "")
let imxURL = try await Essence2Download.identity(agentCode: "A52DHS2219")   // sofia-ramirez
let engine = try await Essence2Engine.create(identity: imxURL)            // waits until the engine is ready
engine.pacing = .unpaced                     // a file render: frames as fast as they render

engine.feed(samples)                         // [Float], 16 kHz mono
engine.flushTail()                           // that is the whole reply
var speech = 0
for await frame in engine.frames() {
    if frame.isSpeech { speech += 1 }        // frame.bgr: B, G, R bytes, width * height * 3
    if frame.endsReply { break }             // the reply is over; idle frames follow
}
print("\(engine.width)x\(engine.height): \(speech) frames for \(Double(samples.count) / 16_000) s of audio")
engine.shutdown()
Expected result

With the 15-second sample clip:

1080x1920: 375 frames for 14.997375 s of audio

25 frames a second at the avatar’s own size. The first create downloads the avatar and the engine’s runtime files, then keeps them in Caches and Application Support. The engine also prints its own diagnostic lines on stderr.

Measured with Swift package 2.14.2
Capture detailsCaptured on an Apple M4 iMac (macOS) · Swift package 2.14.2 · wise-pup (Expression 2) · 2026-09-23.

Performance

ConfigurationEssence 2Expression 2
Apple M4 macOS · Swift package
4.8× real timeApple M4 · Swift package 2.15.0 · measured 2026-09-24
8.8× real timeApple M4 · Swift package 2.15.0 · measured 2026-09-24
Apple M4 macOS · CLI
4.2× real timeApple M4 · CLI 2.8.1 · measured 2026-09-27
8.4× real timeApple M4 · CLI 2.8.1 · measured 2026-09-27
Apple M4 macOS · Python
6.9× real timeApple M4 · bithuman 2.11.12 · measured 2026-09-25
8.4× real timeApple M4 · bithuman 2.11.12 · measured 2026-09-25

Times real time: seconds of avatar video rendered per second. At 1.0× or more, an avatar holds a live conversation. Select a figure for its release and date. All configurations and how we measure.

This section moved: docs.bithuman.ai/platforms/macos#run-your-first-avatar

This section moved: docs.bithuman.ai/platforms/swift/app#integrate-into-your-app

This section moved: docs.bithuman.ai/platforms/swift/app#complete-example

This section moved: docs.bithuman.ai/platforms/swift/app#platform-notes

This section moved: docs.bithuman.ai/platforms/swift/troubleshooting#macos

This section moved: docs.bithuman.ai/platforms/swift/reference