Files
Aaron Sinclair 635d466874 Implement Python → LLVM IR → WASM reactive framework
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!
2025-11-15 01:50:40 -08:00

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's ast module to generate IR
  • compiler.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 examples
  • test.py - Simple test for debugging framework behavior

Compilation Pipeline (Conceptual)

The planned compilation flow:

  1. Parser: Uses Python's ast module to parse components (no custom parser needed!)
  2. IR Generation: Transform Python AST → Ritz intermediate representation
  3. LLVM Codegen: Ritz IR → LLVM IR
  4. WASM Output: LLVM IR → WebAssembly with debug symbols (DWARF)
  5. 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 logic
  • app-core.wasm (~200KB) - Main app, requires authentication
  • features/*.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 node
  • to_html() - Render to HTML string
  • to_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

  1. Python-executable, WASM-compilable: The same code runs in both environments
  2. Yield-based composition: Natural Python syntax for building component trees
  3. Fine-grained reactivity: Signals update DOM directly, no virtual DOM diffing
  4. Progressive loading: Split code into secure, cacheable modules
  5. 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

  1. Python prototype (framework.py): Currently functional, can be tested with Python
  2. Compilation pipeline (compiler.py, ast_parser.py): Architectural/conceptual code that demonstrates intended design
  3. Module system (module_system.py): Demonstrates progressive loading strategy
  4. Components must be valid Python and use generator syntax with yield
  5. 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