Build native OpenGL Applications with HTML, CSS, and JavaScript
Project description
███╗ ███╗ ██████╗ ██████╗ ██████╗ ██╗ ██╗
████╗ █████║██╔═══██╗██╔══██╗██╔══██╗██║ ██║
██╔████╔██║██║ ██║██████╔╝██████╔╝███████║
██║╚██╔╝██║██║ ██║██╔══██╗██╔═══╝ ██╔══██║
██║ ╚═╝ ██║╚██████╔╝██║ ██║██║ ██║ ██║
╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝
Build native OpenGL Applications with HTML, CSS, and JavaScript.
No browser. No Electron. No WebView. Just a lightweight native binary.
What is Morph?
Morph is a UI framework that compiles .mx files (JSX-like syntax with CSS and JavaScript) directly into native OpenGL binaries. You write familiar web syntax — Morph produces a lean, native binary with zero browser overhead.
<!-- src/App.mx -->
<morph-window title="My App" width="800" height="600">
<div style="height: 48px; background: #1a1a2e;">
<button morph-open="settings">Settings</button>
</div>
<h1 style="color: #e0e0e0;">Hello from Morph</h1>
</morph-window>
morph dev # live window, hot reload via Unix socket
morph build # optimized native binary
Why Morph?
| Electron | Qt | Morph | |
|---|---|---|---|
| Write UI in | HTML/CSS/JS | C++ / QML | HTML/CSS/JS |
| Runtime | Chromium (~150MB) | Qt libs | Zero |
| Binary size | ~80MB+ | ~20MB+ | <1MB |
| Native OpenGL access | ✗ | ✓ | ✓ |
| Hot reload | ✓ | ✗ | ✓ |
| Custom C++ nodes | ✗ | ✓ | ✓ |
Quick Start
1. Install
pip install levizr-morph
morph doctor # verify system dependencies
2. Create a project
morph init my-app
cd my-app
3. Start dev mode
morph dev
A native window opens. Edit src/App.mx — the window updates instantly without restarting.
4. Ship
morph build
# builds native binary
How It Works
Morph is a compiler, not an interpreter. Your source files never ship — only the compiled binary does.
src/App.mx ──► MorphParser ──► JSXWalker ──► IRBuilder ──► LayoutEngine ──► IR dict ──► C++ Codegen ──► g++ ──► native binary
│
[Dev: Unix Socket]
Python handles the entire toolchain — .mx parsing via tree-sitter, IR building, layout math, and Jinja2-based C++ code generation. C++ handles the runtime — OpenGL rendering, window management, and event handling. The final binary contains zero Python and zero Node.
In dev mode, the pipeline produces an IR dict that is sent over a Unix socket to a pre-compiled renderer (morph_devrt) on every file save. The window never closes — only the node tree swaps.
Current State (v0.0.5 — Early Development)
✅ Working
| Component | Status |
|---|---|
.mx file parsing — tree-sitter-based JSX, imports, props |
Complete |
| CSS parsing — local files, remote URLs, MD5-cached | Complete |
| Tailwind CSS — 500 common utility classes + arbitrary values | Complete |
| IRBuilder — walked AST → IR with inline CSS, Tailwind, color/unit conversion | Complete |
CLI — init (interactive wizard), dev, build, pkg, doctor, cache |
Complete |
Config — morph.config.json load/save |
Complete |
IR data models — IRNode, IRWindow, IRPage, IRViewport, IRStyle, IREvent |
Complete |
| IR serializer/deserializer — JSON-safe dict for dev socket | Complete |
| Layout engine — box model (margin, padding), vertical stacking, gap, flexbox | Complete |
| Dev file watcher — watchdog-based with debounce | Complete |
| Unix socket IPC — sends IR to dev runtime | Complete |
| C++ node emitter — IR → C++ instantiation code from Jinja2 templates | Complete |
| Build compiler — g++ invocation with conditional FreeType/GLFW/OpenGL flags | Complete |
| Package registry client — fetch, install, manifest parsing | Complete |
| OpenGL 3.3 batch renderer — instanced VAO/VBO/IBO, uniform color + rounded rect SDF | Complete |
| FreeType text rendering — per-size glyph atlas, batch text with kerning | Complete |
| Rounded rectangles — SDF-based border-radius in fragment shader | Complete |
Font weight support — bold/normal font selection, font-weight CSS property |
Complete |
Style inheritance — color, font-size, font-weight, text-align cascade from parent |
Complete |
Transparent backgrounds — only render when background-color set |
Complete |
Event system — onClick, MouseDown, MouseUp, MouseMove events |
Complete |
| Scrollbar — browser-like drag, wheel, track-click, nested containers | Complete |
| Viewport culling — skip off-screen children in draw + event dispatch | Complete |
Feature-based compilation — #define MORPH_FEATURE_* guards, linker GC |
Complete |
Flexbox — justify-content, align-items, two-pass layout, content-based sizing |
Complete |
text-align — left, center, right with correct container-relative centering |
Complete |
max-width — layout constraint for responsive sizing |
Complete |
Margin/padding side properties — margin-top, padding-left, etc. |
Complete |
Cursor support — cursor: pointer (hand), cursor: text (I-beam) |
Complete |
morph_devrt binary — dev mode C++ renderer, Unix socket IPC, hot reload |
Complete |
Border rendering — border-width, border-color, border-style with SDF shader on all elements (div, button, img); border ring batch on top of everything |
Complete |
Image rendering — stb_image-backed: PNG, JPEG, WebP, GIF, BMP, TGA, PSD, HDR, PNM, PIC; per-texture batching, border-radius clipping |
Complete |
Box-sizing — content-box and border-box CSS property |
Complete |
| Dev mode auto-build — CMake integration, automatic binary rebuild on missing | Complete |
| Window config hot reload — title update on save, node tree swap without restart | Complete |
| DevTools panel — F12 toggle, element inspect (F2/click), box-model overlay (margin/border/padding/content), element info panel | Complete |
🚧 In Progress
| Component | Status | Notes |
|---|---|---|
| Style resolver — CSS cascade, specificity, selector matching | Stub | Only inline + Tailwind work via IRBuilder |
| JS interpreter — JS event handler → C++ lambdas | Stub | Only console.log works |
Flexbox flex-wrap — row overflow wrapping |
Partial | Content-based sizing works, wrap still in progress |
position: relative/fixed — offset positioning, sticky |
Stub | Not yet implemented |
Features
CSS Properties (resolved from inline styles, CSS rules, and Tailwind classes)
width,height,max-widthmargin,padding+ individual side properties (margin-top,padding-left, etc.)background-color,color(hex, rgb, named)border-radius,border-width,border-color,border-stylebox-sizing—content-box,border-boxdisplay: flex,flex-direction,justify-content,align-items,flex-wrap,gapposition,left,right,top,bottomoverflow,cursorfont-size(px, %, em, bare numbers),font-weight,text-aligncolor,font-size,font-weight,text-aligncascade from parent to children
HTML Elements
div,span,h1–h6,p,button<img>— supports PNG, JPEG, WebP, GIF, BMP, TGA, PSD, HDR, PNM, PIC via stb_image; intrinsic aspect ratio;width/heightattributes;border-radiusclipping<morph-window>— declares a native window
C++ Runtime
- OpenGL 3.3 core profile batch renderer (instanced VAO/VBO/IBO)
- Rounded rectangles via SDF fragment shader (radius auto-clamped)
- Border rendering —
border-width,border-color,border-stylevia SDF shader on all elements (div,button,img, etc.); border ring batch flushed on top of everything box-sizing: content-box/border-boxlayout modes- FreeType text rendering with per-size glyph atlas and word-wrap
- Font weight support (bold / normal with
DejaVuSans-Bold.ttf) - Style inheritance cascade (
color,font-size,font-weight,text-align) - Transparent backgrounds by default
onClick,MouseDown,MouseUp,MouseMoveevent dispatch- Scrollbar with drag, wheel, track-click; nested scroll containers
- Viewport culling for draw + events
- Feature-based dead code elimination
- Image rendering — stb_image-backed texture loading (PNG/JPEG/WebP/GIF/BMP/TGA/PSD/HDR/PNM/PIC); per-texture-ID batched draw calls;
border-radiusstencil clipping on images cursor: pointerandcursor: textvia GLFW standard cursors
DevTools (morph_devrt only)
F12— Toggle DevTools panelF2or click "Inspect Element" — Toggle inspect mode- Box-model overlay: margin (orange), border (yellow), padding (green), content (blue)
- Element info panel: tag name, size, position, margin, padding, display, overflow, box-sizing, color (hex swatch), background (hex swatch), font size, font weight, text align
- Hot reload preserves DevTools state
Project Structure
my-app/
├── src/
│ ├── App.mx ← entry point (JSX + CSS + JS)
│ └── components/ ← reusable .mx components
├── cpp/ ← optional custom C++ nodes
│ └── my_widget.h
├── assets/ ← fonts, textures, etc.
├── morph.config.json ← project config + dependencies
└── dist/
└── app ← compiled binary (gitignored)
morph.config.json:
{
"name": "my-app",
"entry": "src/App.mx",
"window": {
"width": 1024,
"height": 768,
"title": "My App"
},
"dependencies": {},
"cpp_sources": []
}
System Requirements
| Linux | macOS | Windows | |
|---|---|---|---|
| Python | 3.10+ | 3.10+ | 3.10+ |
| Compiler | g++ 11+ | clang++ 13+ | MSVC / MinGW |
| OpenGL | 3.3+ | 3.3+ | 3.3+ |
| GLFW | apt install libglfw3-dev |
brew install glfw |
bundled |
Run morph doctor after installing to verify your environment.
Roadmap
v0.1.0 (Next Up)
- CSS style resolver — Selector matching, cascade, specificity
- JS interpreter — Full JS expression handling (CallExpression, BinaryExpression)
-
flex-wrap— Row overflow wrapping -
position: relative/fixed— Offset and viewport-relative positioning -
margincollapse — Collapsing vertical margins between siblings
Future
- Multi-window & navigation system
-
<morph-viewport>embedded OpenGL canvas - Custom C++ node integration
- morph-icons (first-party package)
- morph-animate
- Windows support
- VSCode extension (syntax highlighting for
.mxfiles)
Contributing
Morph is in early development. Contributions, ideas, and feedback are very welcome.
git clone https://github.com/levizr/morph
cd morph
pip install -e ".[dev]"
morph doctor
The most impactful areas right now are the CSS style resolver, morph_devrt binary, and JS interpreter. See the Current State section for a full breakdown.
Open an issue before starting on large features so we can align on design.
License
APACHE — see LICENSE.
Built with C++ and Python · Rendered with OpenGL · No browser required
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file levizr_morph-0.0.5.tar.gz.
File metadata
- Download URL: levizr_morph-0.0.5.tar.gz
- Upload date:
- Size: 203.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a52aa6af99a3e1eeca506ea0364923900cebee3e02f86e0686430745623754f0
|
|
| MD5 |
155991f33b8204a17bf9c8234b7ae429
|
|
| BLAKE2b-256 |
52f130cb0626e49eeb23c79b5b3199274ce4ac44056798d8c0287090c00d7ada
|
File details
Details for the file levizr_morph-0.0.5-py3-none-any.whl.
File metadata
- Download URL: levizr_morph-0.0.5-py3-none-any.whl
- Upload date:
- Size: 232.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4fd584596c4717b697079bee80d748acfa9ea853209ca45af46c41692b42dc90
|
|
| MD5 |
b9949f377f0b6bf91be0dff67cfd8dac
|
|
| BLAKE2b-256 |
558f0f10a3e9f629235b4bf1e40d509090ecb12c5e64de43c8822665c5929663
|