The bridge
The bridge is the layer between the JavaScript runtime and native code. Yolk's bridge is a true zero-copy, high-performance interface designed for shared memory access and end-to-end type safety.
True Zero-Copy Architecture
Unlike traditional bridges that copy data at the boundary, Yolk shares the same raw memory between Swift and JavaScript.
How it works
- JS to Swift: When JS passes an
ArrayBuffer, Yolk extracts its C-pointer and wraps it in a SwiftDataobject usingData(bytesNoCopy:...). We manage memory lifetime by capturing theJSValuein theDatadeallocator, preventing garbage collection until Swift releases the buffer. - Swift to JS: When Swift passes
Datato JS, we bridge it toNSDataand pass its raw bytes toJSObjectMakeArrayBufferWithBytesNoCopy. JS sees this as a standardArrayBufferpointing directly to Swift's memory.
Why this matters
- Zero Serialization: Eliminates
JSON.stringifyandJSON.parseentirely. - Shared Memory: Perfect for high-bandwidth tasks like image processing, audio streaming, or real-time physics logic.
- Safe Value Semantics: Swift
Datauses Copy-on-Write (CoW). If Swift tries to mutate JS-owned memory, it automatically creates a local copy, ensuring thread safety and preventing memory corruption on the JS heap.
How a call works
Arguments are packed into a binary buffer using the YolkBin protocol and passed via shared memory:
TypeScript Bridge Swift
────────── ────── ─────
playground.increment(1)
│
├─▶ YolkBin.encode([1]) ──▶ ArrayBuffer (Shared Ptr)
│ │
└─▶ __yolk_native_Playground("increment", buffer)
│ │
├─▶ Create JS Promise │
│ │
└─▶ Task { ▼
// args is raw Data pointing to JS memory
await module.handle("increment", args)
│
├─▶ YolkBin.decode(args) ──▶ [1.0]
│
└─▶ actor PlaygroundModule
│
└─▶ increment(step: 1.0) ──▶ PlaygroundState(...)
}
│
├─▶ YolkBin.encode(state) ──▶ Data (Shared Ptr)
│ │
└─▶ jsQueue.async { ▼
// result is ArrayBuffer pointing to Swift memory
__yolk.resolve(42, result)
drainMicrotasks() ──▶ Promise resolves
}
The YolkBin Protocol
Yolk implements a custom Type-Length-Value (TLV) protocol for binary serialization. It handles primitives, objects, and zero-copy raw buffers:
- 0x03 (Number): Native Float64 (8 bytes).
- 0x04 (String): UTF-8 bytes with a length prefix.
- 0x07 (Buffer): Direct pointer sharing for
ArrayBufferandData.
Single Source of Truth (SSOT)
Yolk follows a reactive state model. The application state lives in JavaScript. Whenever the state mutates, the JS logic pushes the new state as a binary buffer to a native Observer:
// JS notifies native of state change via zero-copy buffer
const buffer = YolkBin.encode([state]);
globalThis.__yolk_native_Observer("onStateChanged", buffer);On the native side, the generated PlaygroundState struct is automatically updated, triggering a reactive UI refresh.