MAJOR ACHIEVEMENT: Full working reactive framework! ## What's Working ✅ Python → AST → Ritz IR → LLVM IR → WASM pipeline ✅ Reactive signals stored in WASM memory (@signal_name = global i32) ✅ Event handlers exported from WASM and callable from JS ✅ Clean runtime with RitzLoader and debug tools ✅ Two working examples: HelloWorld and HighFive counter ## Core Components ### Parser (ritz/parser.py) - Uses Python's ast module to parse components - Handles @component decorator, signals, event handlers - Supports yield, with statements, f-strings, augmented assignment (+=) - Clean syntax: from ritz.syntax import * ### LLVM IR Code Generator (ritz/llvm_codegen_signals.py) - Generates LLVM IR directly (not C!) - Signals as global variables in WASM memory - Exports getter/setter functions for each signal - Exports event handler functions for JS to call - UTF-8 string handling ### Build System (ritz/build.py) - Python → AST → IR → LLVM IR → clang --target=wasm32 → WASM - Saves intermediate .ll files for inspection - Debug symbols support (-g flag) ### Runtime (runtime/ritz-runtime.js) - RitzRuntime class: DOM bridge for WASM - RitzLoader class: Simplified component loading - Debug bar with Ctrl+` toggle - Signal updates trigger DOM updates ## Examples ### HelloWorld.py Simple static content - renders <p>Hello World</p> ### HighFive.py Reactive counter with: - Signal in WASM memory (high_fives = signal(0)) - Event handler (increment function) - DOM updates on signal change ## Test Coverage - 4 parser tests (all passing) - 4 LLVM codegen tests (all passing) - 4 signal parsing tests (all passing) - Code formatted with black and ruff ## Next Steps - <script type="text/ritz"> in-browser compilation - Better signal-to-DOM binding tracking - More complex examples (TodoMVC, forms, lists) - Playwright browser tests --- This is a genuinely innovative framework: write Python, compile to WASM, run with reactive signals in WASM memory. No virtual DOM, no transpilation, just compiled Python with fine-grained reactivity. 🎉 Python → WASM → Reactive UI is REAL!
6.1 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Ritz is a WebAssembly UI framework with Python-like syntax that compiles to high-performance WASM while remaining executable in Python for debugging. The framework uses valid Python syntax that can execute in CPython for prototyping/debugging, but is designed to compile to WebAssembly for production.
Current Status: Python prototype stage. The WASM compilation pipeline is conceptual/architectural.
Development Commands
Running the Prototype
# Run example application showing various components
python3 example.py
# Run simple test
python3 test.py
# Test AST parser
python3 ast_parser.py
# View module system concept
python3 module_system.py
# View compilation pipeline concept
python3 compiler.py
# View debugging concept
python3 debug_concept.py
Core Architecture
Component Model
Components are defined using the @component decorator with Python generator syntax (yield-based):
@component
def Counter():
count = signal(0) # Reactive state
def increment():
count += 1
with Div(class_='counter'): # Context managers for element nesting
yield H1('Counter') # Yield elements/strings/components
yield P(f'Count: {count}')
yield Button('Click me', onclick=increment)
Key patterns:
- Generators: Components are generator functions that yield children
- Context managers: Use
with Element():for nested structures - Signals: Reactive state via
signal(initial_value) - Mixed content: Can yield strings, elements, or other components
File Structure
Core Framework Files:
framework.py- Python prototype runtime (Signal, VNode, Element, component decorator)ast_parser.py- Parses Python components using Python'sastmodule to generate IRcompiler.py- Complete compilation pipeline concept (Python → IR → LLVM → WASM)module_system.py- Progressive module loading architecture for code splitting
Conceptual/Research:
debug_concept.py- Python-in-WASM debugging architecture (DWARF symbols, source maps)RESEARCH.md- Complete technical architecture and implementation roadmap
Examples:
example.py- Demonstrates component syntax with various examplestest.py- Simple test for debugging framework behavior
Compilation Pipeline (Conceptual)
The planned compilation flow:
- Parser: Uses Python's
astmodule to parse components (no custom parser needed!) - IR Generation: Transform Python AST → Ritz intermediate representation
- LLVM Codegen: Ritz IR → LLVM IR
- WASM Output: LLVM IR → WebAssembly with debug symbols (DWARF)
- Module Splitting: Split into multiple WASM modules (bootstrap, core, features)
Reactive System
Signals are the primitive reactive unit:
- Store a value and list of subscribers
- When value changes, notify all subscribers
- In Python prototype: simple Python class
- In WASM target: efficient memory layout with direct DOM node references
Key insight: No virtual DOM. Signals map directly to DOM nodes for updates.
Module System Architecture
Apps split into multiple WASM modules for security and performance:
bootstrap.wasm(~50KB) - Login only, no auth required, no business logicapp-core.wasm(~200KB) - Main app, requires authenticationfeatures/*.wasm- Lazy-loaded feature modules
Security benefit: Unauthenticated users never receive app code containing API endpoints or business logic.
Important Implementation Details
AST Parsing
The framework uses Python's own ast module to parse components (not a custom parser). This provides:
- Zero parsing overhead
- Perfect Python compatibility
- Automatic syntax error messages
- Type hints support
See ast_parser.py for the RitzASTTransformer that converts Python AST to Ritz IR.
VNode Structure
Internal representation during Python execution:
VNode(tag, props, children)- Virtual DOM nodeto_html()- Render to HTML stringto_ir()- Convert to intermediate representation for compilation
Context Stack
_context_stack is a global list tracking nested with Element(): blocks. The @component decorator manages this stack to build the component tree.
Debugging Philosophy
Revolutionary concept: Debug Python code running in WASM, not JavaScript!
- DWARF debug symbols embedded in WASM
- Source maps linking WASM instructions → Python source lines
- Chrome DevTools can set breakpoints in Python files
- Inspect Python variables, not mangled JS
See debug_concept.py and RESEARCH.md sections on debugging.
Design Principles
- Python-executable, WASM-compilable: The same code runs in both environments
- Yield-based composition: Natural Python syntax for building component trees
- Fine-grained reactivity: Signals update DOM directly, no virtual DOM diffing
- Progressive loading: Split code into secure, cacheable modules
- Developer experience: Debug in Python, ship as WASM
Performance Targets
Based on SolidJS/Leptos research:
- Bundle size: < 200KB compressed
- Startup time: < 500ms on slow 3G
- Update performance: Within 10% of vanilla JS
- Memory usage: 70% less than React
- DOM mutations: 99% fewer than virtual DOM frameworks
When Modifying Code
- Python prototype (
framework.py): Currently functional, can be tested with Python - Compilation pipeline (
compiler.py,ast_parser.py): Architectural/conceptual code that demonstrates intended design - Module system (
module_system.py): Demonstrates progressive loading strategy - Components must be valid Python and use generator syntax with yield
- All examples should run with
python3 example.py
Key Technical Decisions
- Why yield? Natural Python syntax, composable, clear execution order
- Why compile vs interpret? 10-100x performance, smaller bundle, type safety
- Why LLVM? Mature toolchain, excellent WASM backend, optimization passes
- Why Python's ast module? No custom parser needed, perfect compatibility