← TinyGPT · docs · devlog · roadmap · speedup
source: docs/archive/shared_vs_native.md · view on GitHub ↗

Shared vs. native — how the browser and macOS paths relate

TinyGPT will ship as two binaries: a browser playground (Chromium + M-series targeted) and a native macOS app (M-series only). They are separate implementations of the same model, optimized for different ceilings. They deliberately share what’s cheap to share (data + UX + words) and don’t share what’s expensive to share (kernels + runtime).

The browser is the focus right now. The native app is on the roadmap; this document exists so that when we start it, the boundary is already drawn.


Shared (must stay in lockstep)

1. .tinygpt file format (v2)

One binary format for trained models. Both paths read and write it.

A .tinygpt file written in the browser must train-continue cleanly in the Mac app, and vice versa. This is the only hard cross-path contract.

2. UI patterns + copy

The macOS app uses SwiftUI, not HTML, so no literal code reuse — but the design language is shared verbatim:

Anything user-visible that exists on both sides reads identically. New copy ships in both places or in neither.

3. Docs + brand

4. Python reference

python_ref/ stays authoritative. Any disagreement in numerics between the browser, the Mac app, and python_ref/ is resolved by trusting python_ref/. It exists to keep both ports honest.


Distinct (do not try to share)

Kernels + runtime

SurfaceBrowserNative macOS
CPU kernelsC++ → WASM (SIMD + pthreads)MLX-Swift (Apple Accelerate)
GPU kernelsWGSL via WebGPUMetal via MLX-Swift (uses MPS)
Memory modelMemory64 WASM heap, ~16 GB capUnified memory, machine RAM cap
ThreadingWeb Workers + SharedArrayBufferGrand Central Dispatch + MLX async
AttentionCustom WGSL Flash Attention 2mx.fast.scaled_dot_product_attn
Mixed precisionWebGPU shader-f16 extensionMLX fp16 / bf16 paths
QuantizationCustom int4 sample-only pathMLX quantize utilities
File I/OFile / Blob / OPFSFoundation + native disk

Trying to share kernel code across these stacks is a dead end — the abstraction overhead eats the perf benefit on both sides. Each path uses the most native-feeling tools for its platform.

Build + distribution

SurfaceBrowserNative macOS
BuildEmscripten + ViteSwift Package Manager
DistributionCloudflare Pages (a URL)Direct DMG download (notarized)
UpdateRefresh the tabSparkle auto-update
TelemetryOpt-in PostHogOpt-in only (TBD)

What each path is for

The split is intentional. The browser is “show me,” the native app is “now let me actually do it.”


Working rule

When adding a feature, the first question is: which path does this live on?