Morph is a compiler, not an interpreter. Your source files never ship — only the compiled binary does.
src/App.mx ──► Oxc Parser ──► lightningcss ──► IRBuilder ──► LayoutEngine ──► IRSerializer
│
┌────────────────────────┴──────────────┐
▼ ▼
[Dev: IPC loopback TCP] [Build: C++ Codegen]
morph_devrt binary node_emitter → g++ → binary
+ logic.so (dlopen) TS→C++ (logic) → g++ → logic.mx / .tsx / .ts file using the TypeScript grammar into an AST (3× faster than SWC, arena-allocated)From here, the pipeline splits:
morph_devrt renderer. Your JS logic is compiled to a logic.so shared library loaded via dlopen.app.cpp which is compiled with g++/clang++ into a standalone binary.Rust (morph) handles the toolchain:
.mx/.tsx/.ts parsing (Oxc)C++ handles the runtime:
The final binary contains zero Rust (compiler only), zero Python, and zero Node.js.
An .mx file is a single file containing JSX markup with TypeScript/JavaScript logic and CSS imports:
import { morphState } from 'morph'
import { compute } from './math.cpp' // C++ import
import "./style.css"
export const windowConfig = { title: "App", width: 800, height: 600 }
export default function App() {
const [value, setValue] = morphState(0)
return (
<body>
<div>Result: {compute(value)}</div>
<button onClick={() => setValue(value + 1)}>Add</button>
</body>
)
}Morph scans the IR tree and detects which features your app actually uses. Only the required C++ code is compiled in — everything else is stripped by the linker:
text — text rendering (adds FreeType)button — button widgetscroll — scroll containersflex — flexbox layouthover — hover pseudo-classanimation — CSS animationstransform — CSS transformsimage — image rendering (adds stb_image)This is why Morph binaries are so small — a simple "Hello World" app doesn't include image loading, animation, or scroll code.
One mode — intent-based codegen is the default (morph file.ts): escape analysis → stack/unique_ptr/shared_ptr, native types (int32_t, std::string, std::vector), type widening only when needed. --type strict respects annotations, --type infer (default) infers from code.
See Intent-Based Codegen for the full memory management strategy.
┌──────────────┐ Unix Socket ┌──────────────────┐
│ morph │ ◄──────────────────► │ morph_devrt │
│ (watcher) │ JSON IR + │ (always running)│
│ │ logic.so path │ │
└──────┬───────┘ └────────┬─────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────────┐
│ Rebuild │ │ Hot Reload │
│ logic.so │ │ - dlopen new │
│ (g++ -shared) │ logic.so │
└──────────────┘ │ - Rewire signals│
│ - Re-run effects│
└──────────────────┘morph_devrt is a pre-compiled renderer binary (shipped with runtime).mx source
│
▼
┌──────────────────────────────────────┐
│ Feature Detection (FeatureSet) │
│ - Scans IR nodes for used features │
│ - Emits only required #defines │
└──────────────┬───────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ Tera Templates (app_main.cpp.tera) │
│ - window_code + keyframe_code │
│ - list_factory_code │
│ - headers + defines │
│ - premain_functions │
│ - state_decls │
└──────────────┬───────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ g++ -std=c++20 -O2 │
│ -ffunction-sections │
│ -fdata-sections │
│ -Wl,--gc-sections │
└──────────────┬───────────────────────┘
│
▼
native binary (~200-800 KB)Dead code elimination: Linker GC sections removes unused runtime code. A hello-world with only <div> + <button> includes ~15 KB of runtime; adding <img> pulls in stb_image (~50 KB).
~/.morph/
├── cache/
│ └── runtimes/
│ └── cpp/
│ ├── v0.1.0/ # Runtime source (symlinked to .morph/runtime/)
│ ├── v0.2.0/
│ └── v0.3.0/
└── index.json # Metadata
Project:
.morph/
├── runtime/ → ~/.morph/cache/runtimes/cpp/v0.2.0/ (symlink or copy)
├── build/ # Object files, fingerprints, logic.so
└── cache/
├── css/ # Remote CSS + @font-face files (MD5 keyed)
└── *.fingerprint # Content hashes for incremental buildsmorph.config.json + entry source + runtime tree + imported files)| Artifact | How It's Built |
|---|---|
morph binary |
cargo install --locked → static musl on Linux, native on macOS/Windows |
| C++ runtime | GitHub Actions: g++-14 build → tar.gz → GitHub Release (tagged by versions/runtime/cpp.json) |
| Version files | versions/{morph,version.json} + versions/runtime/cpp.json — push to main = auto-release |
Security: CODEOWNERS protects versions/**, semver validation in CI, sha256 verified on download, only main branch triggers releases.