about summary refs log tree commit diff stats
path: root/js/baba-yaga/web
diff options
context:
space:
mode:
Diffstat (limited to 'js/baba-yaga/web')
-rw-r--r--js/baba-yaga/web/app.js497
-rw-r--r--js/baba-yaga/web/editor/README.md210
-rw-r--r--js/baba-yaga/web/editor/debug-modules.html107
-rw-r--r--js/baba-yaga/web/editor/index.html577
-rw-r--r--js/baba-yaga/web/editor/js/ast-synchronizer.js463
-rw-r--r--js/baba-yaga/web/editor/js/baba-yaga-mode.js191
-rw-r--r--js/baba-yaga/web/editor/js/baba-yaga-runner.js564
-rw-r--r--js/baba-yaga/web/editor/js/editor.js1004
-rw-r--r--js/baba-yaga/web/editor/js/formatter.js621
-rw-r--r--js/baba-yaga/web/editor/js/main.js225
-rw-r--r--js/baba-yaga/web/editor/js/structural-editors.js501
-rw-r--r--js/baba-yaga/web/editor/js/tree-sitter-baba-yaga.js79
-rw-r--r--js/baba-yaga/web/editor/structural.html101
-rw-r--r--js/baba-yaga/web/editor/styles.css755
-rw-r--r--js/baba-yaga/web/editor/test-formatter.html155
-rw-r--r--js/baba-yaga/web/editor/test-integration.html109
-rw-r--r--js/baba-yaga/web/index.html355
17 files changed, 6514 insertions, 0 deletions
diff --git a/js/baba-yaga/web/app.js b/js/baba-yaga/web/app.js
new file mode 100644
index 0000000..ad92716
--- /dev/null
+++ b/js/baba-yaga/web/app.js
@@ -0,0 +1,497 @@
+import { createLexer } from '../lexer.js';
+import { createParser } from '../parser.js';
+import { createInterpreter } from '../interpreter.js';
+
+/**
+ * Baba Yaga REPL Application
+ * A mobile-first, accessible CLI-style REPL for the Baba Yaga language
+ */
+
+class BabaYagaREPL {
+  constructor() {
+    this.history = [];
+    this.historyIndex = -1;
+    this.sessionCode = '';
+    
+    // DOM elements
+    this.messagesEl = document.getElementById('messages');
+    this.inputEl = document.getElementById('input');
+    this.sendBtn = document.getElementById('send');
+    this.clearBtn = document.getElementById('clear');
+    this.loadBtn = document.getElementById('load');
+    this.fileInputEl = document.getElementById('fileInput');
+    this.examplesBtn = document.getElementById('examples');
+    this.helpBtn = document.getElementById('help');
+    
+    this.setupEventListeners();
+    this.showWelcome();
+  }
+
+  setupEventListeners() {
+    // Execute code
+    this.sendBtn.addEventListener('click', () => this.executeCode());
+    this.inputEl.addEventListener('keydown', (e) => {
+      if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {
+        e.preventDefault();
+        this.executeCode();
+      } else if (e.key === 'ArrowUp') {
+        e.preventDefault();
+        this.navigateHistory(-1);
+      } else if (e.key === 'ArrowDown') {
+        e.preventDefault();
+        this.navigateHistory(1);
+      }
+    });
+
+    // Auto-resize textarea
+    this.inputEl.addEventListener('input', () => this.autoResize());
+
+    // Clear output
+    this.clearBtn.addEventListener('click', () => this.clearOutput());
+
+    // Load file
+    this.loadBtn.addEventListener('click', () => this.fileInputEl.click());
+    this.fileInputEl.addEventListener('change', (e) => this.handleFileLoad(e));
+
+    // Load examples
+    this.examplesBtn.addEventListener('click', () => this.loadExamples());
+
+    // Help
+    this.helpBtn.addEventListener('click', () => this.showHelp());
+
+    // Focus management
+    this.inputEl.focus();
+  }
+
+  showWelcome() {
+    this.addMessage('Baba Yaga REPL', 'info');
+    this.addMessage('Type /help for available commands', 'info');
+  }
+
+  executeCode() {
+    const code = this.inputEl.value.trim();
+    if (!code) return;
+
+    // Add to history
+    this.addToHistory(code);
+    
+    // Display input
+    this.addInputMessage(code);
+
+    try {
+      // Check for slash commands
+      if (code.startsWith('/')) {
+        this.handleSlashCommand(code);
+        this.clearInput();
+        return;
+      }
+
+      // Execute Baba Yaga code with session persistence
+      const result = this.evaluateWithSession(code);
+      
+      if (result.ok) {
+        if (result.value !== undefined) {
+          this.addMessage(this.formatValue(result.value), 'output');
+        }
+      } else {
+        this.addMessage(`Error: ${result.error.message}`, 'error');
+        if (result.error.codeFrame) {
+          this.addMessage(result.error.codeFrame, 'error');
+        }
+      }
+    } catch (error) {
+      this.addMessage(`Unexpected error: ${error.message}`, 'error');
+    }
+
+    this.clearInput();
+  }
+
+  evaluate(source) {
+    try {
+      const lexer = createLexer(source);
+      const tokens = lexer.allTokens();
+      const parser = createParser(tokens);
+      const ast = parser.parse();
+      
+      const host = {
+        io: {
+          out: (...args) => {
+            const text = args.map(arg => this.formatValue(arg)).join(' ');
+            this.addMessage(text, 'output');
+          },
+          in: () => {
+            // For now, return empty string - could be enhanced with stdin
+            return '';
+          }
+        }
+      };
+
+      const interpreter = createInterpreter(ast, host);
+      const value = interpreter.interpret();
+      
+      return { ok: true, value };
+    } catch (error) {
+      const message = error?.message || String(error);
+      const lineMatch = / at (\d+):(\d+)/.exec(message);
+      const line = lineMatch ? Number(lineMatch[1]) : null;
+      const column = lineMatch ? Number(lineMatch[2]) : null;
+      const codeFrame = this.makeCodeFrame(source, line, column);
+      
+      return { 
+        ok: false, 
+        error: { 
+          message, 
+          line, 
+          column, 
+          codeFrame 
+        } 
+      };
+    }
+  }
+
+  evaluateWithSession(source) {
+    try {
+      // Combine session code with new code
+      const fullSource = this.sessionCode + source;
+      
+      const lexer = createLexer(fullSource);
+      const tokens = lexer.allTokens();
+      const parser = createParser(tokens);
+      const ast = parser.parse();
+      
+      const host = {
+        io: {
+          out: (...args) => {
+            const text = args.map(arg => this.formatValue(arg)).join(' ');
+            this.addMessage(text, 'output');
+          },
+          in: () => {
+            // For now, return empty string - could be enhanced with stdin
+            return '';
+          }
+        }
+      };
+
+      const interpreter = createInterpreter(ast, host);
+      const value = interpreter.interpret();
+      
+      // If successful, add to session code
+      this.sessionCode += source + '\n';
+      
+      return { ok: true, value };
+    } catch (error) {
+      const message = error?.message || String(error);
+      const lineMatch = / at (\d+):(\d+)/.exec(message);
+      const line = lineMatch ? Number(lineMatch[1]) : null;
+      const column = lineMatch ? Number(lineMatch[2]) : null;
+      const codeFrame = this.makeCodeFrame(source, line, column);
+      
+      return { 
+        ok: false, 
+        error: { 
+          message, 
+          line, 
+          column, 
+          codeFrame 
+        } 
+      };
+    }
+  }
+
+  formatValue(value) {
+    if (value === null || value === undefined) {
+      return 'null';
+    }
+    
+    if (typeof value === 'number') {
+      return value.toString();
+    }
+    
+    if (typeof value === 'string') {
+      return value;
+    }
+    
+    if (Array.isArray(value)) {
+      return JSON.stringify(value);
+    }
+    
+    if (value && typeof value === 'object') {
+      if (value.type === 'Object' && value.properties) {
+        const obj = {};
+        for (const [key, val] of value.properties.entries()) {
+          obj[key] = this.formatValue(val);
+        }
+        return JSON.stringify(obj, null, 2);
+      }
+      
+      if (value.value !== undefined) {
+        return value.value.toString();
+      }
+      
+      // Handle native functions - don't show the function object
+      if (value.type === 'NativeFunction') {
+        return ''; // Return empty string for native functions
+      }
+      
+      // Handle function objects - don't show the function definition
+      if (value.type === 'Function') {
+        return ''; // Return empty string for function objects
+      }
+    }
+    
+    return JSON.stringify(value, null, 2);
+  }
+
+  makeCodeFrame(source, line, column) {
+    if (!line || !column) return '';
+    
+    const lines = source.split(/\r?\n/);
+    const idx = line - 1;
+    const context = [idx - 1, idx, idx + 1].filter(i => i >= 0 && i < lines.length);
+    const pad = n => String(n + 1).padStart(4, ' ');
+    const caret = ' '.repeat(column - 1) + '^';
+    const rows = context.map(i => `${pad(i)} | ${lines[i]}`);
+    rows.splice(context.indexOf(idx) + 1, 0, `     | ${caret}`);
+    return rows.join('\n');
+  }
+
+  addMessage(text, type = 'output') {
+    const messageDiv = document.createElement('div');
+    messageDiv.className = 'message';
+    
+    const contentDiv = document.createElement('div');
+    contentDiv.className = `message-${type}`;
+    contentDiv.innerHTML = text.replace(/\n/g, '<br>');
+    
+    messageDiv.appendChild(contentDiv);
+    this.messagesEl.appendChild(messageDiv);
+    
+    // Auto-scroll to bottom after adding message
+    this.scrollToBottom();
+  }
+
+  addInputMessage(code) {
+    const messageDiv = document.createElement('div');
+    messageDiv.className = 'message';
+    
+    const inputDiv = document.createElement('div');
+    inputDiv.className = 'message-input';
+    
+    const promptDiv = document.createElement('div');
+    promptDiv.className = 'prompt';
+    promptDiv.textContent = '>';
+    
+    const codeDiv = document.createElement('div');
+    codeDiv.className = 'code';
+    codeDiv.textContent = code;
+    
+    inputDiv.appendChild(promptDiv);
+    inputDiv.appendChild(codeDiv);
+    messageDiv.appendChild(inputDiv);
+    
+    this.messagesEl.appendChild(messageDiv);
+    
+    // Auto-scroll to bottom after adding input message
+    this.scrollToBottom();
+  }
+
+  clearInput() {
+    this.inputEl.value = '';
+    this.autoResize();
+  }
+
+  clearOutput() {
+    this.messagesEl.innerHTML = '';
+    this.sessionCode = '';
+    this.showWelcome();
+  }
+
+  autoResize() {
+    this.inputEl.style.height = 'auto';
+    this.inputEl.style.height = Math.min(this.inputEl.scrollHeight, 120) + 'px';
+  }
+
+  scrollToBottom() {
+    this.messagesEl.scrollTop = this.messagesEl.scrollHeight;
+  }
+
+  addToHistory(code) {
+    this.history.push(code);
+    this.historyIndex = this.history.length;
+  }
+
+  navigateHistory(direction) {
+    if (this.history.length === 0) return;
+    
+    this.historyIndex += direction;
+    
+    if (this.historyIndex < 0) {
+      this.historyIndex = 0;
+    } else if (this.historyIndex >= this.history.length) {
+      this.historyIndex = this.history.length;
+      this.inputEl.value = '';
+    } else {
+      this.inputEl.value = this.history[this.historyIndex];
+    }
+    
+    this.autoResize();
+  }
+
+  handleSlashCommand(command) {
+    const cmd = command.toLowerCase();
+    
+    switch (cmd) {
+      case '/help':
+        this.showHelp();
+        break;
+      case '/clear':
+        this.clearOutput();
+        break;
+      case '/examples':
+        this.loadExamples();
+        break;
+      case '/run':
+        this.runSession();
+        break;
+      case '/load':
+        this.fileInputEl.click();
+        break;
+      default:
+        this.addMessage(`Unknown command: ${command}. Type /help for available commands.`, 'error');
+    }
+  }
+
+  runSession() {
+    if (!this.sessionCode.trim()) {
+      this.addMessage('No code in session to run. Load a file or type some code first.', 'info');
+      return;
+    }
+
+    this.addMessage('Running session code...', 'info');
+    
+    try {
+      const result = this.evaluate(this.sessionCode);
+      
+      if (result.ok) {
+        if (result.value !== undefined) {
+          this.addMessage(this.formatValue(result.value), 'output');
+        }
+        this.addMessage('Session executed successfully.', 'info');
+      } else {
+        this.addMessage(`Error: ${result.error.message}`, 'error');
+        if (result.error.codeFrame) {
+          this.addMessage(result.error.codeFrame, 'error');
+        }
+      }
+    } catch (error) {
+      this.addMessage(`Unexpected error: ${error.message}`, 'error');
+    }
+  }
+
+  showHelp() {
+    const helpText = `Available slash commands:
+  /help     - Show this help message
+  /clear    - Clear the output
+  /examples - Load example code
+  /load     - Load a .baba file
+  /run      - Execute all code in session
+
+Keyboard shortcuts:
+  Cmd/Ctrl + Enter - Execute code
+  ↑/↓              - Navigate history
+
+Baba Yaga language features:
+  - Immutable variables: name : value;
+  - Functions: name : params -> body;
+  - Pattern matching: when expr is pattern then result;
+  - Lists: [1, 2, 3]
+  - Tables: {key: value}
+  - String concatenation: str1 .. str2
+  - IO: io.out "Hello"; io.in
+
+Example function definition:
+  add : x y -> x + y;
+  result : add 3 4;`;
+
+    this.addMessage(helpText, 'info');
+  }
+
+  async handleFileLoad(event) {
+    const file = event.target.files?.[0];
+    if (!file) return;
+
+    try {
+      const text = await file.text();
+      
+      // Validate the file content by trying to parse it
+      const lexer = createLexer(text);
+      const tokens = lexer.allTokens();
+      const parser = createParser(tokens);
+      parser.parse();
+      
+      // If parsing succeeds, add to session and display
+      this.sessionCode += text + '\n';
+      
+      this.addMessage(`Loaded ${file.name}`, 'info');
+      this.addInputMessage(text);
+      this.addMessage('File loaded successfully. Click "Run" to execute or add more code.', 'info');
+      
+    } catch (error) {
+      const message = error?.message || String(error);
+      this.addMessage(`Failed to load ${file.name}: ${message}`, 'error');
+    } finally {
+      // Reset the input so the same file can be selected again
+      event.target.value = '';
+    }
+  }
+
+  loadExamples() {
+    const examples = [
+      {
+        title: 'Basic arithmetic',
+        code: `result : 2 + 3 * 4;
+io.out result;`
+      },
+      {
+        title: 'Simple function',
+        code: `add : x y -> x + y;
+result : add 5 3;
+io.out result;`
+      },
+      {
+        title: 'Variables and expressions',
+        code: `a : 10;
+b : 20;
+sum : a + b;
+io.out sum;`
+      },
+      {
+        title: 'String operations',
+        code: `greeting : "Hello";
+name : "World";
+message : greeting .. " " .. name;
+io.out message;`
+      },
+      {
+        title: 'String functions',
+        code: `io.out str.substring "hello world" 0 5;
+io.out str.replace "hello hello" "hello" "hi";`
+      }
+    ];
+
+    this.addMessage('Available examples:', 'info');
+    
+    examples.forEach(example => {
+      this.addMessage(`// ${example.title}`, 'output');
+      this.addInputMessage(example.code);
+    });
+    
+    this.addMessage('Copy and paste any example above to try it out!', 'info');
+  }
+}
+
+// Initialize the REPL when the page loads
+document.addEventListener('DOMContentLoaded', () => {
+  new BabaYagaREPL();
+});
+
diff --git a/js/baba-yaga/web/editor/README.md b/js/baba-yaga/web/editor/README.md
new file mode 100644
index 0000000..3cf7c5c
--- /dev/null
+++ b/js/baba-yaga/web/editor/README.md
@@ -0,0 +1,210 @@
+# Baba Yaga Inline AST Editor
+
+A web-based structural editor for the Baba Yaga programming language, featuring real-time AST visualization and **inline tree editing** capabilities.
+
+## **Core Concept**
+
+This editor allows you to edit code structure directly through the Abstract Syntax Tree (AST) view. Instead of traditional forms, you can **double-click any element** in the tree to edit it inline, making structural editing intuitive and powerful.
+
+## **Key Features**
+
+### **Inline AST Editing**
+- **Double-click to Edit**: Any node type, name, value, or parameter
+- **Real-time Updates**: Changes sync immediately between AST and code editor
+- **Action Buttons**: + (add child) and × (delete) for each node
+- **Smart Scaffolding**: Add Function, When, or With expressions with one click
+
+### **Layout & UX**
+- **Side-by-side Layout**: Code editor (50%) + AST tree editor (50%)
+- **Output Panel**: Below both panels for execution results
+- **Mobile Responsive**: Stacks vertically on smaller screens
+- **Auto-parsing**: Code updates in real-time as you edit
+
+### **Bidirectional Synchronization**
+- **AST ↔ Code Editor**: Always in sync
+- **Real-time Parsing**: 500ms debounced parsing as you type
+- **Visual Feedback**: Parse status indicators and error highlighting
+
+## **Architecture**
+
+The editor consists of several key components:
+
+- **Code Editor**: Text-based input for Baba Yaga code
+- **AST Tree Editor**: Interactive tree view with inline editing
+- **AST Synchronizer**: Manages bidirectional synchronization
+- **Baba Yaga Parser**: Real language parser integration
+- **Code Generator**: Converts modified AST back to code
+
+## **How to Use**
+
+### **Basic Workflow**
+1. **Type Code** → See AST tree automatically generated
+2. **Double-click** any node element to edit inline
+3. **Click +** to add child nodes
+4. **Click ×** to delete nodes
+5. **Use + Function/When/With** buttons for quick scaffolding
+
+### **Inline Editing**
+- **Node Types**: Double-click the type (e.g., "FunctionDeclaration")
+- **Names & Values**: Double-click any name or value field
+- **Parameters**: Double-click parameter names or types
+- **Keyboard**: Enter to save, Escape to cancel
+
+### **Quick Add Elements**
+- **+ Function**: Creates `newFunction : -> expression`
+- **+ When**: Creates empty when expression structure  
+- **+ With**: Creates empty with header structure
+
+## **Development**
+
+### **Setup**
+1. Ensure you have a web server running (e.g., `python3 -m http.server 8000`)
+2. Open `index.html` in your browser
+3. The editor will automatically load and parse any existing code
+
+### **Key Components**
+- `editor.js`: Main editor class with inline editing logic
+- `ast-synchronizer.js`: AST synchronization and code generation
+- `main.js`: Application initialization and global utilities
+
+### **Adding New Features**
+To extend the inline editing capabilities:
+
+1. **New Node Types**: Add to `createDefaultChildNode()` method
+2. **Custom Editors**: Extend the inline editing methods
+3. **Validation**: Add input validation in `finishEdit*` methods
+4. **Code Generation**: Update the code generation logic
+
+## **Future Enhancements**
+
+- **Syntax Highlighting**: ✅ Baba Yaga language support (implemented!)
+- **Advanced Pattern Matching**: Enhanced when expression editing
+- **Type System Integration**: Better type inference and validation
+- **Code Suggestions**: Intelligent autocomplete and suggestions
+- **Refactoring Tools**: Automated code restructuring
+- **Export/Import**: Save and load AST structures
+- **Undo/Redo**: Track editing history
+- **Drag & Drop**: Visual AST manipulation
+
+## **Technical Details**
+
+### **Inline Editing Implementation**
+- **Event Delegation**: Handles all editing through centralized methods
+- **Dynamic Input Fields**: Replace text with input boxes on interaction
+- **AST Manipulation**: Direct tree structure modification
+- **Real-time Sync**: Immediate updates between views
+
+### **Performance Optimizations**
+- **Debounced Parsing**: 500ms delay to avoid excessive parsing
+- **Selective Updates**: Only re-render changed sections
+- **Memory Management**: Efficient AST node tracking
+
+### **Syntax Highlighting Features**
+- **Custom Language Mode**: Full Baba Yaga syntax support
+- **Token Recognition**: Keywords, types, functions, operators, numbers, strings
+- **Smart Indentation**: Auto-indent for function bodies, when expressions, with headers
+- **Theme Integration**: Monokai dark theme with custom Baba Yaga colors
+- **Code Folding**: Collapsible code blocks for better organization
+
+## 🌟 **Why Inline Editing?**
+
+Traditional structural editors require switching between different forms and panels, which can be cumbersome. This inline approach:
+
+- **Reduces Context Switching**: Edit directly where you see the structure
+- **Improves Workflow**: Faster iteration and experimentation
+- **Enhances Understanding**: Visual connection between structure and code
+- **Increases Productivity**: More intuitive editing experience
+
+## 📁 **File Structure**
+
+```
+web/editor/
+├── index.html              # Main HTML with inline editor layout
+├── styles.css              # CSS with inline editing styles
+├── js/
+│   ├── editor.js           # Main editor with inline editing logic
+│   ├── ast-synchronizer.js # AST sync and code generation
+│   ├── baba-yaga-mode.js   # Custom CodeMirror language mode
+│   ├── main.js             # Application initialization
+│   └── tree-sitter-baba-yaga.js # Future grammar integration
+└── README.md               # This documentation
+```
+
+## 🎨 **Syntax Highlighting Colors**
+
+The editor provides rich syntax highlighting with a carefully chosen color scheme:
+
+- **Keywords** (`when`, `with`, `rec`, `in`): Purple (#c586c0)
+- **Types** (`Int`, `String`, `Result`): Teal (#4ec9b0) 
+- **Functions** (function names): Yellow (#dcdcaa)
+- **Builtins** (`map`, `filter`, `reduce`): Orange (#d7ba7d)
+- **Operators** (`->`, `:`, `+`, `*`): White (#d4d4d4)
+- **Numbers**: Green (#b5cea8)
+- **Strings**: Red (#ce9178)
+- **Comments**: Green (#6a9955)
+- **Variables**: Blue (#9cdcfe)
+
+## **Development Commands**
+
+The editor provides several console commands for development:
+
+```javascript
+// Get current AST
+window.babaYagaEditorCommands.getAST()
+
+// Get current code
+window.babaYagaEditorCommands.getCode()
+
+// Parse current code
+window.babaYagaEditorCommands.parse()
+
+// Format current code
+window.babaYagaEditorCommands.format()
+
+// Show AST in console
+window.babaYagaEditorCommands.showAST()
+
+// Show code in console
+window.babaYagaEditorCommands.showCode()
+```
+
+## 🔧 **Baba Yaga Language Support**
+
+### **Supported Constructs**
+- **Function Declarations**: `name : params -> body`
+- **Variable Declarations**: `name : value`
+- **Basic Expressions**: Arithmetic, comparison, logical operators
+- **Pattern Matching**: `when` expressions (basic support)
+- **Local Bindings**: `with` headers (basic support)
+
+### **Language Features**
+- **Currying**: Multiple arrow functions
+- **Type Annotations**: Optional type declarations
+- **Pattern Matching**: `when` expressions with multiple cases
+- **Recursion**: `with rec` for mutually recursive functions
+- **Immutability**: All data structures are immutable
+
+## 🚀 **Getting Started**
+
+1. **Clone the repository** and navigate to `web/editor/`
+2. **Start a web server**: `python3 -m http.server 8000`
+3. **Open in browser**: Navigate to `http://localhost:8000/web/editor/`
+4. **Start editing**: Type Baba Yaga code or use the inline AST editor
+
+## 🤝 **Contributing**
+
+1. Fork the repository
+2. Create a feature branch
+3. Make your changes
+4. Test thoroughly
+5. Submit a pull request
+
+## 📄 **License**
+
+This project is part of the Baba Yaga language implementation. See the main project license for details.
+
+## 🙏 **Acknowledgments**
+
+- Inspired by functional programming language editors
+- Built on modern web technologies
+- Designed for educational and development use
diff --git a/js/baba-yaga/web/editor/debug-modules.html b/js/baba-yaga/web/editor/debug-modules.html
new file mode 100644
index 0000000..549b984
--- /dev/null
+++ b/js/baba-yaga/web/editor/debug-modules.html
@@ -0,0 +1,107 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Module Loading Debug</title>
+</head>
+<body>
+    <h1>Module Loading Debug</h1>
+    
+    <div id="status">Loading...</div>
+    
+    <div id="results"></div>
+    
+    <!-- Baba Yaga Language Components -->
+    <script src="../../lexer.js" type="module"></script>
+    <script src="../../parser.js" type="module"></script>
+    <script src="../../interpreter.js" type="module"></script>
+    
+    <script type="module">
+        const statusDiv = document.getElementById('status');
+        const resultsDiv = document.getElementById('results');
+        
+        function log(message, type = 'info') {
+            const color = type === 'error' ? 'red' : type === 'success' ? 'green' : 'black';
+            resultsDiv.innerHTML += `<p style="color: ${color}">${message}</p>`;
+        }
+        
+        async function debugModules() {
+            try {
+                statusDiv.textContent = 'Checking module loading...';
+                
+                // Wait a bit for modules to load
+                await new Promise(resolve => setTimeout(resolve, 100));
+                
+                log('=== Module Loading Debug ===');
+                
+                // Check global scope
+                log('Global scope check:');
+                log(`- window.createLexer: ${typeof window.createLexer}`);
+                log(`- window.createParser: ${typeof window.createParser}`);
+                log(`- window.createInterpreter: ${typeof window.createInterpreter}`);
+                
+                // Check if functions are available
+                log('Function availability check:');
+                log(`- createLexer: ${typeof createLexer}`);
+                log(`- createParser: ${typeof createParser}`);
+                log(`- createInterpreter: ${typeof createInterpreter}`);
+                
+                if (typeof createLexer === 'undefined') {
+                    log('❌ createLexer is not defined', 'error');
+                } else {
+                    log('✅ createLexer is available', 'success');
+                }
+                
+                if (typeof createParser === 'undefined') {
+                    log('❌ createParser is not defined', 'error');
+                } else {
+                    log('✅ createParser is available', 'success');
+                }
+                
+                if (typeof createInterpreter === 'undefined') {
+                    log('❌ createInterpreter is not defined', 'error');
+                } else {
+                    log('✅ createInterpreter is available', 'success');
+                }
+                
+                // Try to use them if available
+                if (typeof createLexer !== 'undefined' && typeof createParser !== 'undefined') {
+                    log('Testing basic functionality...');
+                    
+                    try {
+                        const testCode = 'add : x y -> x + y;';
+                        const lexer = createLexer(testCode);
+                        const tokens = lexer.allTokens();
+                        log(`✅ Lexer test passed: ${tokens.length} tokens`);
+                        
+                        const parser = createParser(tokens);
+                        const ast = parser.parse();
+                        log(`✅ Parser test passed: AST type = ${ast.type}`);
+                        
+                        statusDiv.textContent = 'All tests passed! 🎉';
+                        statusDiv.style.color = 'green';
+                        
+                    } catch (error) {
+                        log(`❌ Functionality test failed: ${error.message}`, 'error');
+                        statusDiv.textContent = 'Tests failed! ❌';
+                        statusDiv.style.color = 'red';
+                    }
+                } else {
+                    log('❌ Cannot test functionality - modules not loaded', 'error');
+                    statusDiv.textContent = 'Modules not loaded! ❌';
+                    statusDiv.style.color = 'red';
+                }
+                
+            } catch (error) {
+                log(`❌ Debug failed: ${error.message}`, 'error');
+                statusDiv.textContent = 'Debug failed! ❌';
+                statusDiv.style.color = 'red';
+            }
+        }
+        
+        // Run debug when page loads
+        document.addEventListener('DOMContentLoaded', debugModules);
+    </script>
+</body>
+</html>
diff --git a/js/baba-yaga/web/editor/index.html b/js/baba-yaga/web/editor/index.html
new file mode 100644
index 0000000..6344cee
--- /dev/null
+++ b/js/baba-yaga/web/editor/index.html
@@ -0,0 +1,577 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
+    <title>Baba Yaga Code Runner</title>
+    <link rel="stylesheet" href="../../node_modules/codemirror/lib/codemirror.css">
+    <link rel="stylesheet" href="../../node_modules/codemirror/theme/monokai.css">
+    <script src="../../node_modules/codemirror/lib/codemirror.js"></script>
+    <script src="../../node_modules/codemirror/addon/edit/closebrackets.js"></script>
+    <script src="../../node_modules/codemirror/addon/edit/matchbrackets.js"></script>
+    <script src="../../node_modules/codemirror/addon/fold/foldcode.js"></script>
+    <script src="../../node_modules/codemirror/addon/fold/foldgutter.js"></script>
+    <script src="../../node_modules/codemirror/addon/fold/brace-fold.js"></script>
+    <script src="../../node_modules/codemirror/addon/fold/indent-fold.js"></script>
+    
+    <!-- Baba Yaga Language Components -->
+    <script type="module">
+        // Import Baba Yaga components and make them globally available
+        import { createLexer, tokenTypes } from '../../lexer.js';
+        import { createParser } from '../../parser.js';
+        import { createInterpreter } from '../../interpreter.js';
+        
+        // Make them globally available
+        window.createLexer = createLexer;
+        window.createParser = createParser;
+        window.createInterpreter = createInterpreter;
+        window.tokenTypes = tokenTypes;
+        
+        console.log('Baba Yaga modules loaded and made globally available');
+    </script>
+    
+    <!-- Baba Yaga Language Mode -->
+    <script src="js/baba-yaga-mode.js"></script>
+    
+    <!-- Baba Yaga Formatter -->
+    <script src="js/formatter.js"></script>
+    
+    <style>
+        * {
+            margin: 0;
+            padding: 0;
+            box-sizing: border-box;
+        }
+
+        html, body {
+            height: 100%;
+            overflow: hidden;
+        }
+
+        body {
+            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif;
+            background-color: #1e1e1e;
+            color: #d4d4d4;
+        }
+
+        .container {
+            display: flex;
+            flex-direction: column;
+            height: 100vh;
+            overflow: hidden;
+        }
+
+        .header {
+            background-color: #2d2d30;
+            border-bottom: 1px solid #3e3e42;
+            padding: 1rem;
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+        }
+
+        .header h1 {
+            color: #569cd6;
+            font-size: 1.5rem;
+            font-weight: 600;
+        }
+
+        .header-controls {
+            display: flex;
+            gap: 0.5rem;
+        }
+
+        .btn {
+            background-color: #007acc;
+            color: white;
+            border: none;
+            padding: 0.5rem 1rem;
+            border-radius: 4px;
+            cursor: pointer;
+            font-size: 0.9rem;
+            transition: background-color 0.2s;
+        }
+
+        .btn:hover {
+            background-color: #005a9e;
+        }
+
+        .btn.success {
+            background-color: #4ec9b0;
+        }
+
+        .btn.error {
+            background-color: #f14c4c;
+        }
+
+        .main-content {
+            display: flex;
+            flex: 1;
+            overflow: hidden;
+        }
+
+        .editor-section {
+            flex: 1;
+            display: flex;
+            flex-direction: column;
+            border-right: 1px solid #3e3e42;
+        }
+
+        .editor-header {
+            padding: 1rem;
+            background-color: #2d2d30;
+            border-bottom: 1px solid #3e3e42;
+            color: #d4d4d4;
+        }
+
+        .editor-container {
+            flex: 1;
+            overflow: hidden;
+            display: flex;
+            flex-direction: column;
+            min-height: 0;
+        }
+
+        .CodeMirror {
+            height: 100% !important;
+            min-height: 300px;
+            flex: 1;
+        }
+
+        .CodeMirror-scroll {
+            min-height: 100%;
+        }
+
+        .output-section {
+            width: 400px;
+            display: flex;
+            flex-direction: column;
+            background-color: #252526;
+        }
+
+        .output-header {
+            padding: 1rem;
+            background-color: #2d2d30;
+            border-bottom: 1px solid #3e3e42;
+            color: #d4d4d4;
+        }
+
+        .output-content {
+            flex: 1;
+            overflow: auto;
+            padding: 1rem;
+        }
+
+        .output-tabs {
+            display: flex;
+            background-color: #2d2d30;
+            border-bottom: 1px solid #3e3e42;
+        }
+
+        .tab-btn {
+            background-color: transparent;
+            color: #d4d4d4;
+            border: none;
+            padding: 0.75rem 1rem;
+            cursor: pointer;
+            border-bottom: 2px solid transparent;
+            transition: all 0.2s;
+        }
+
+        .tab-btn:hover {
+            background-color: #3e3e42;
+        }
+
+        .tab-btn.active {
+            background-color: #007acc;
+            color: white;
+            border-bottom-color: #007acc;
+        }
+
+        .tab-pane {
+            display: none;
+        }
+
+        .tab-pane.active {
+            display: block;
+        }
+
+        .output-text {
+            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
+            font-size: 14px;
+            line-height: 1.5;
+            white-space: normal;
+            word-wrap: break-word;
+        }
+
+        .error-message {
+            color: #f14c4c;
+            background-color: rgba(241, 76, 76, 0.1);
+            border-left: 3px solid #f14c4c;
+            padding: 0.75rem;
+            margin: 0.5rem 0;
+            border-radius: 4px;
+        }
+
+        .success-message {
+            color: #4ec9b0;
+            background-color: rgba(78, 201, 176, 0.1);
+            border-left: 3px solid #4ec9b0;
+            border-radius: 4px;
+            padding: 0.75rem;
+            margin: 0.5rem 0;
+        }
+
+        .info-message {
+            color: #569cd6;
+            background-color: rgba(86, 156, 214, 0.1);
+            border-left: 3px solid #569cd6;
+            padding: 0.75rem;
+            margin: 0.5rem 0;
+            border-radius: 4px;
+        }
+
+        .sample-code-btn {
+            background-color: #6a9955;
+            margin-left: 0.5rem;
+        }
+
+        .sample-code-btn:hover {
+            background-color: #5a8a45;
+        }
+
+        .format-btn {
+            background-color: #ff9500;
+        }
+
+        .format-btn:hover {
+            background-color: #e6850e;
+        }
+
+        .structural-editor-btn {
+            background-color: #8b5cf6;
+        }
+
+        .structural-editor-btn:hover {
+            background-color: #7c3aed;
+        }
+
+        /* Custom token colors for Baba Yaga - override monokai theme */
+        .cm-s-monokai .cm-keyword {
+            color: #c586c0 !important;
+            font-weight: bold;
+        }
+
+        .cm-s-monokai .cm-type {
+            color: #4ec9b0 !important;
+            font-weight: bold;
+        }
+
+        .cm-s-monokai .cm-function {
+            color: #dcdcaa !important;
+            font-weight: bold;
+        }
+
+        .cm-s-monokai .cm-builtin {
+            color: #d7ba7d !important;
+        }
+
+        .cm-s-monokai .cm-operator {
+            color: #d4d4d4 !important;
+        }
+
+        .cm-s-monokai .cm-number {
+            color: #b5cea8 !important;
+        }
+
+        .cm-s-monokai .cm-string {
+            color: #ce9178 !important;
+        }
+
+        .cm-s-monokai .cm-comment {
+            color: #6a9955 !important;
+            font-style: italic;
+        }
+
+        .cm-s-monokai .cm-variable {
+            color: #9cdcfe !important;
+        }
+
+        /* Dark theme adjustments for monokai */
+        .cm-s-monokai.CodeMirror {
+            background-color: #1e1e1e;
+            color: #d4d4d4;
+        }
+
+        .cm-s-monokai .CodeMirror-gutters {
+            background-color: #2d2d30;
+            border-right: 1px solid #3e3e42;
+        }
+
+        .cm-s-monokai .CodeMirror-linenumber {
+            color: #858585;
+        }
+
+        .CodeMirror-focused .CodeMirror-cursor {
+            border-left: 2px solid #007acc;
+        }
+
+        .CodeMirror-selected {
+            background-color: #264f78 !important;
+        }
+
+        .CodeMirror-activeline-background {
+            background-color: #2d2d30;
+        }
+        
+        /* Touch-friendly improvements */
+        .btn {
+            touch-action: manipulation;
+            -webkit-tap-highlight-color: transparent;
+        }
+        
+        .tab-btn {
+            touch-action: manipulation;
+            -webkit-tap-highlight-color: transparent;
+        }
+        
+        /* Ensure CodeMirror is mobile-friendly */
+        .CodeMirror {
+            touch-action: manipulation;
+            -webkit-overflow-scrolling: touch;
+        }
+        
+        /* Mobile scrollbar improvements */
+        .output-content::-webkit-scrollbar {
+            width: 6px;
+        }
+        
+        .output-content::-webkit-scrollbar-track {
+            background: #2d2d30;
+        }
+        
+        .output-content::-webkit-scrollbar-thumb {
+            background: #3e3e42;
+            border-radius: 3px;
+        }
+        
+        .output-content::-webkit-scrollbar-thumb:hover {
+            background: #4e4e52;
+        }
+        
+        /* Improved output layout */
+        .output-content {
+            padding: 1rem;
+        }
+        
+        .output-content .success-message,
+        .output-content .info-message,
+        .output-content .error-message {
+            margin: 0.75rem 0;
+        }
+        
+        .output-content .info-message:first-child {
+            margin-top: 0;
+        }
+        
+        /* IO output items */
+        .io-output-item {
+            margin: 0.25rem 0;
+            padding: 0.5rem;
+            background: rgba(86, 156, 214, 0.1);
+            border-radius: 4px;
+            border-left: 2px solid #569cd6;
+            font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+            font-size: 13px;
+        }
+        
+        /* Mobile Responsive Design */
+        @media (max-width: 768px) {
+            .header {
+                flex-direction: column;
+                gap: 1rem;
+                padding: 1rem 0.5rem;
+            }
+            
+            .header h1 {
+                font-size: 1.25rem;
+                text-align: center;
+            }
+            
+            .header-controls {
+                justify-content: center;
+                flex-wrap: wrap;
+                gap: 0.5rem;
+            }
+            
+            .btn {
+                padding: 0.5rem 0.75rem;
+                font-size: 0.85rem;
+                min-width: 80px;
+            }
+            
+            .main-content {
+                flex-direction: column;
+            }
+            
+            .editor-section {
+                border-right: none;
+                border-bottom: 1px solid #3e3e42;
+                min-height: 300px;
+            }
+            
+            .output-section {
+                width: 100%;
+                min-height: 250px;
+            }
+            
+            .editor-header,
+            .output-header {
+                padding: 0.75rem;
+            }
+            
+            .editor-header h3,
+            .output-header h3 {
+                font-size: 1rem;
+            }
+            
+            .output-tabs {
+                flex-wrap: wrap;
+            }
+            
+            .tab-btn {
+                padding: 0.5rem 0.75rem;
+                font-size: 0.85rem;
+                flex: 1;
+                min-width: 80px;
+                text-align: center;
+            }
+            
+            .output-content {
+                padding: 0.75rem;
+            }
+            
+            .success-message,
+            .info-message,
+            .error-message {
+                padding: 0.5rem;
+                margin: 0.5rem 0;
+                font-size: 0.9rem;
+            }
+            
+            .io-output-item {
+                padding: 0.4rem;
+                font-size: 12px;
+            }
+            
+            .CodeMirror {
+                min-height: 250px;
+            }
+        }
+        
+        /* Small mobile devices */
+        @media (max-width: 480px) {
+            .header h1 {
+                font-size: 1.1rem;
+            }
+            
+            .btn {
+                padding: 0.4rem 0.6rem;
+                font-size: 0.8rem;
+                min-width: 70px;
+            }
+            
+            .editor-header,
+            .output-header {
+                padding: 0.5rem;
+            }
+            
+            .output-content {
+                padding: 0.5rem;
+            }
+            
+            .success-message,
+            .info-message,
+            .error-message {
+                padding: 0.4rem;
+                font-size: 0.85rem;
+            }
+            
+            .io-output-item {
+                padding: 0.3rem;
+                font-size: 11px;
+            }
+        }
+        
+        /* Landscape mobile optimization */
+        @media (max-width: 768px) and (orientation: landscape) {
+            .main-content {
+                flex-direction: row;
+            }
+            
+            .editor-section {
+                border-right: 1px solid #3e3e42;
+                border-bottom: none;
+                min-height: 200px;
+            }
+            
+            .output-section {
+                width: 300px;
+                min-height: 200px;
+            }
+        }
+    </style>
+</head>
+<body>
+    <div class="container">
+        <!-- Header -->
+        <header class="header">
+            <h1>Baba Yaga Code Runner</h1>
+            <div class="header-controls">
+                <button id="run-btn" class="btn">▶ Run Code</button>
+                <button id="format-btn" class="btn format-btn">📝 Format</button>
+                <button id="sample-btn" class="btn sample-code-btn">Load Sample</button>
+            </div>
+        </header>
+
+        <!-- Main content -->
+        <div class="main-content">
+            <!-- Code Editor Section -->
+            <div class="editor-section">
+                <div class="editor-header">
+                    <h3>Code Editor</h3>
+                </div>
+                <div class="editor-container">
+                    <textarea id="code-editor" placeholder="Enter your Baba Yaga code here..."></textarea>
+                </div>
+            </div>
+
+            <!-- Output Section -->
+            <div class="output-section">
+                <div class="output-header">
+                    <h3>Output</h3>
+                </div>
+                <div class="output-tabs">
+                    <button class="tab-btn active" data-tab="output">Output</button>
+                    <button class="tab-btn" data-tab="errors">Errors</button>
+                    <button class="tab-btn" data-tab="ast">AST</button>
+                </div>
+                <div class="output-content">
+                    <div id="output-tab" class="tab-pane active">
+                        <div class="output-text" id="output-text">Ready to run Baba Yaga code...</div>
+                    </div>
+                    <div id="errors-tab" class="tab-pane">
+                        <div class="output-text" id="errors-text">No errors yet.</div>
+                    </div>
+                    <div id="ast-tab" class="tab-pane">
+                        <div class="output-text" id="ast-text">AST will appear here after parsing.</div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!-- Scripts -->
+    <script src="js/baba-yaga-runner.js"></script>
+</body>
+</html>
diff --git a/js/baba-yaga/web/editor/js/ast-synchronizer.js b/js/baba-yaga/web/editor/js/ast-synchronizer.js
new file mode 100644
index 0000000..f404c0c
--- /dev/null
+++ b/js/baba-yaga/web/editor/js/ast-synchronizer.js
@@ -0,0 +1,463 @@
+/**
+ * ASTSynchronizer - Manages bidirectional synchronization between text and structural views
+ * This is the core component that keeps the AST, text editor, and structural editors in sync
+ */
+class ASTSynchronizer {
+    constructor(editor, structuralEditors) {
+        this.editor = editor;
+        this.structuralEditors = structuralEditors;
+        this.ast = null;
+        this.isUpdating = false; // Prevent infinite loops during updates
+        
+        this.init();
+    }
+    
+    init() {
+        // Set up change listeners
+        this.setupChangeListeners();
+    }
+    
+    setupChangeListeners() {
+        // Listen for AST changes from the editor
+        if (this.editor && this.editor.editor) {
+            this.editor.editor.on('change', () => {
+                if (!this.isUpdating) {
+                    this.updateAST();
+                }
+            });
+        }
+        
+        // Listen for structural editor changes
+        if (this.structuralEditors) {
+            this.structuralEditors.onChange((changes) => {
+                if (!this.isUpdating) {
+                    this.updateASTFromStructural(changes);
+                }
+            });
+        }
+    }
+    
+    updateAST() {
+        try {
+            this.isUpdating = true;
+            
+            // Show parsing status
+            this.showParseStatus('parsing');
+            
+            const code = this.editor.getCode();
+            if (!code.trim()) {
+                this.ast = { type: 'Program', body: [] };
+                this.showParseStatus('parsed');
+                return;
+            }
+            
+            // Parse the code to get new AST
+            const newAST = this.parseCode(code);
+            this.ast = newAST;
+            
+            // Update structural editors with new AST (but don't trigger changes)
+            if (this.structuralEditors) {
+                this.structuralEditors.updateFromAST(newAST, true); // true = silent update
+            }
+            
+            // Update tree view
+            this.updateTreeView(newAST);
+            
+            // Show success status
+            this.showParseStatus('parsed');
+            
+        } catch (error) {
+            console.error('Error updating AST:', error);
+            this.showParseError(error);
+            this.showParseStatus('error');
+        } finally {
+            this.isUpdating = false;
+        }
+    }
+    
+    updateASTFromStructural(changes) {
+        try {
+            this.isUpdating = true;
+            
+            // Apply changes to the current AST
+            const updatedAST = this.applyStructuralChanges(this.ast, changes);
+            this.ast = updatedAST;
+            
+            // Generate code from updated AST
+            const newCode = this.generateCode(updatedAST);
+            
+            // Only update text editor if we have actual structural changes
+            if (changes && changes.length > 0) {
+                // Update text editor
+                this.editor.editor.setValue(newCode);
+            }
+            
+            // Update tree view
+            this.updateTreeView(updatedAST);
+            
+        } catch (error) {
+            console.error('Error updating AST from structural changes:', error);
+            this.showStructuralError(error);
+        } finally {
+            this.isUpdating = false;
+        }
+    }
+    
+    parseCode(code) {
+        // Use the real Baba Yaga parser
+        if (this.editor.parseWithBabaYaga) {
+            return this.editor.parseWithBabaYaga(code);
+        }
+        
+        // Fallback parsing
+        return this.fallbackParse(code);
+    }
+    
+    fallbackParse(code) {
+        const lines = code.split('\n').filter(line => line.trim());
+        const ast = {
+            type: 'Program',
+            body: []
+        };
+        
+        lines.forEach((line, index) => {
+            const trimmed = line.trim();
+            if (trimmed && !trimmed.startsWith('//')) {
+                if (trimmed.includes(':')) {
+                    const [name, ...rest] = trimmed.split(':');
+                    const value = rest.join(':').trim();
+                    
+                    if (value.includes('->')) {
+                        // Function declaration
+                        ast.body.push({
+                            type: 'FunctionDeclaration',
+                            name: name.trim(),
+                            params: this.parseFunctionParams(value),
+                            body: this.parseFunctionBody(value),
+                            returnType: null,
+                            line: index + 1
+                        });
+                    } else {
+                        // Variable declaration
+                        ast.body.push({
+                            type: 'VariableDeclaration',
+                            name: name.trim(),
+                            value: value,
+                            line: index + 1
+                        });
+                    }
+                }
+            }
+        });
+        
+        return ast;
+    }
+    
+    parseFunctionParams(value) {
+        const arrowIndex = value.indexOf('->');
+        if (arrowIndex === -1) return [];
+        
+        const beforeArrow = value.substring(0, arrowIndex).trim();
+        if (!beforeArrow) return [];
+        
+        // Check if this is a typed function signature
+        if (beforeArrow.startsWith('(') && beforeArrow.endsWith(')')) {
+            return this.parseTypedParameters(beforeArrow);
+        }
+        
+        // Simple space-separated parameter parsing
+        return beforeArrow.split(/\s+/).filter(p => p.trim());
+    }
+    
+    parseTypedParameters(paramString) {
+        // Parse (x: Int, y: String) format
+        const content = paramString.slice(1, -1); // Remove parentheses
+        if (!content.trim()) return [];
+        
+        const params = [];
+        const parts = content.split(',').map(p => p.trim());
+        
+        parts.forEach(part => {
+            if (part.includes(':')) {
+                const [name, type] = part.split(':').map(p => p.trim());
+                params.push({ name, type });
+            } else {
+                params.push({ name: part, type: null });
+            }
+        });
+        
+        return params;
+    }
+    
+    parseFunctionBody(value) {
+        const arrowIndex = value.indexOf('->');
+        if (arrowIndex === -1) return '';
+        
+        const afterArrow = value.substring(arrowIndex + 2).trim();
+        
+        // Check if this is a when expression
+        if (afterArrow.startsWith('when')) {
+            return this.parseWhenExpression(afterArrow);
+        }
+        
+        // Check if this is a with header
+        if (afterArrow.startsWith('with')) {
+            return this.parseWithHeader(afterArrow);
+        }
+        
+        return afterArrow;
+    }
+    
+    parseWhenExpression(whenCode) {
+        // Basic when expression parsing
+        return {
+            type: 'WhenExpression',
+            raw: whenCode
+        };
+    }
+    
+    parseWithHeader(withCode) {
+        // Basic with header parsing
+        return {
+            type: 'WithHeader',
+            raw: withCode
+        };
+    }
+    
+    applyStructuralChanges(ast, changes) {
+        if (!ast) return ast;
+        
+        const updatedAST = JSON.parse(JSON.stringify(ast)); // Deep clone
+        
+        changes.forEach(change => {
+            switch (change.type) {
+                case 'function_update':
+                    this.updateFunctionInAST(updatedAST, change);
+                    break;
+                case 'when_update':
+                    this.updateWhenInAST(updatedAST, change);
+                    break;
+                case 'with_update':
+                    this.updateWithInAST(updatedAST, change);
+                    break;
+                case 'add_function':
+                    this.addFunctionToAST(updatedAST, change);
+                    break;
+                case 'remove_function':
+                    this.removeFunctionFromAST(updatedAST, change);
+                    break;
+                default:
+                    console.warn('Unknown change type:', change.type);
+            }
+        });
+        
+        return updatedAST;
+    }
+    
+    updateFunctionInAST(ast, change) {
+        const functionIndex = ast.body.findIndex(node => 
+            node.type === 'FunctionDeclaration' && node.name === change.oldName
+        );
+        
+        if (functionIndex !== -1) {
+            ast.body[functionIndex] = {
+                type: 'FunctionDeclaration',
+                name: change.newName || change.oldName,
+                params: change.params || ast.body[functionIndex].params,
+                body: change.body || ast.body[functionIndex].body,
+                returnType: change.returnType || ast.body[functionIndex].returnType,
+                line: ast.body[functionIndex].line
+            };
+        }
+    }
+    
+    updateWhenInAST(ast, change) {
+        // Find and update when expressions in function bodies
+        this.updateWhenInNode(ast, change);
+    }
+    
+    updateWhenInNode(node, change) {
+        if (node.type === 'WhenExpression') {
+            // Update the when expression
+            Object.assign(node, change);
+        } else if (node.body && typeof node.body === 'object') {
+            this.updateWhenInNode(node.body, change);
+        } else if (Array.isArray(node.body)) {
+            node.body.forEach(child => this.updateWhenInNode(child, change));
+        }
+    }
+    
+    updateWithInAST(ast, change) {
+        // Find and update with headers in function bodies
+        this.updateWithInNode(ast, change);
+    }
+    
+    updateWithInNode(node, change) {
+        if (node.type === 'WithHeader') {
+            // Update the with header
+            Object.assign(node, change);
+        } else if (node.body && typeof node.body === 'object') {
+            this.updateWithInNode(node.body, change);
+        } else if (Array.isArray(node.body)) {
+            node.body.forEach(child => this.updateWithInNode(child, change));
+        }
+    }
+    
+    addFunctionToAST(ast, change) {
+        const newFunction = {
+            type: 'FunctionDeclaration',
+            name: change.name,
+            params: change.params || [],
+            body: change.body || '',
+            returnType: change.returnType || null,
+            line: ast.body.length + 1
+        };
+        
+        ast.body.push(newFunction);
+    }
+    
+    removeFunctionFromAST(ast, change) {
+        const functionIndex = ast.body.findIndex(node => 
+            node.type === 'FunctionDeclaration' && node.name === change.name
+        );
+        
+        if (functionIndex !== -1) {
+            ast.body.splice(functionIndex, 1);
+        }
+    }
+    
+    generateCode(ast) {
+        if (!ast || ast.type !== 'Program') return '';
+        
+        const lines = [];
+        
+        ast.body.forEach(node => {
+            switch (node.type) {
+                case 'FunctionDeclaration':
+                    lines.push(this.generateFunctionCode(node));
+                    break;
+                case 'VariableDeclaration':
+                    lines.push(this.generateVariableCode(node));
+                    break;
+                default:
+                    lines.push(`// Unknown node type: ${node.type}`);
+            }
+        });
+        
+        return lines.join('\n');
+    }
+    
+    generateFunctionCode(node) {
+        let code = `${node.name} : `;
+        
+        // Generate parameter list
+        if (node.params && node.params.length > 0) {
+            if (typeof node.params[0] === 'string') {
+                // Untyped parameters
+                code += node.params.join(' ');
+            } else {
+                // Typed parameters
+                const paramStrings = node.params.map(param => 
+                    param.type ? `${param.name}: ${param.type}` : param.name
+                );
+                code += `(${paramStrings.join(', ')})`;
+            }
+        }
+        
+        // Add return type if specified
+        if (node.returnType) {
+            code += ` -> ${node.returnType}`;
+        }
+        
+        code += ' -> ';
+        
+        // Generate body
+        if (node.body && typeof node.body === 'object') {
+            if (node.body.type === 'WhenExpression') {
+                code += this.generateWhenCode(node.body);
+            } else if (node.body.type === 'WithHeader') {
+                code += this.generateWithCode(node.body);
+            } else {
+                code += node.body.raw || JSON.stringify(node.body);
+            }
+        } else {
+            code += node.body || '';
+        }
+        
+        return code;
+    }
+    
+    generateVariableCode(node) {
+        return `${node.name} : ${node.value};`;
+    }
+    
+    generateWhenCode(whenNode) {
+        // Basic when expression code generation
+        return whenNode.raw || 'when expression';
+    }
+    
+    generateWithCode(withNode) {
+        // Basic with header code generation
+        return withNode.raw || 'with header';
+    }
+    
+    updateTreeView(ast) {
+        if (this.editor.updateTreeView && ast) {
+            try {
+                this.editor.updateTreeView(ast);
+            } catch (error) {
+                console.error('Error updating tree view:', error);
+            }
+        }
+    }
+    
+    showParseError(error) {
+        if (this.editor.showError) {
+            this.editor.showError('Parse error: ' + error.message);
+        }
+    }
+    
+    showStructuralError(error) {
+        if (this.editor.showError) {
+            this.editor.showError('Structural edit error: ' + error.message);
+        }
+    }
+    
+    getAST() {
+        return this.ast;
+    }
+    
+    setAST(ast) {
+        this.ast = ast;
+        this.updateTreeView(ast);
+    }
+    
+    showParseStatus(status) {
+        const statusElement = document.getElementById('parse-status');
+        if (statusElement) {
+            statusElement.className = `parse-status ${status}`;
+            
+            switch (status) {
+                case 'parsing':
+                    statusElement.textContent = '⏳ Parsing...';
+                    break;
+                case 'parsed':
+                    statusElement.textContent = '✅ Parsed';
+                    // Clear status after 2 seconds
+                    setTimeout(() => {
+                        statusElement.textContent = '';
+                        statusElement.className = 'parse-status';
+                    }, 2000);
+                    break;
+                case 'error':
+                    statusElement.textContent = '❌ Parse Error';
+                    // Clear status after 3 seconds
+                    setTimeout(() => {
+                        statusElement.textContent = '';
+                        statusElement.className = 'parse-status';
+                    }, 3000);
+                    break;
+            }
+        }
+    }
+}
diff --git a/js/baba-yaga/web/editor/js/baba-yaga-mode.js b/js/baba-yaga/web/editor/js/baba-yaga-mode.js
new file mode 100644
index 0000000..32b5421
--- /dev/null
+++ b/js/baba-yaga/web/editor/js/baba-yaga-mode.js
@@ -0,0 +1,191 @@
+/**
+ * Baba Yaga Language Mode for CodeMirror
+ * Provides syntax highlighting for the Baba Yaga functional programming language
+ */
+
+// Global function to initialize the Baba Yaga language mode
+window.initBabaYagaMode = function() {
+    // Check if CodeMirror is available
+    if (typeof CodeMirror === 'undefined') {
+        console.log('CodeMirror not available yet, will retry...');
+        setTimeout(window.initBabaYagaMode, 100);
+        return;
+    }
+
+    console.log('Initializing Baba Yaga language mode...');
+
+    // Baba Yaga language keywords
+    const keywords = [
+        'when', 'is', 'then', 'else', 'with', 'rec', 'in',
+        'Ok', 'Err', 'true', 'false', 'PI', 'INFINITY',
+        'and', 'or', 'xor', 'not', 'if'
+    ];
+
+    // Baba Yaga type system
+    const types = [
+        'Int', 'String', 'Result', 'Float', 'Number', 
+        'List', 'Table', 'Bool', 'Unit', 'Maybe'
+    ];
+
+    // Function names that are commonly used
+    const builtins = [
+        'map', 'filter', 'reduce', 'fold', 'head', 'tail',
+        'length', 'append', 'concat', 'reverse', 'sort'
+    ];
+
+    // Main tokenizer function
+    function tokenize(stream, state) {
+        // Handle comments
+        if (stream.match(/\/\/.*/)) {
+            return 'comment';
+        }
+
+        // Handle multi-line comments
+        if (stream.match(/\/\*/)) {
+            state.inComment = true;
+            return 'comment';
+        }
+
+        if (state.inComment) {
+            if (stream.match(/\*\//)) {
+                state.inComment = false;
+            } else {
+                stream.next();
+            }
+            return 'comment';
+        }
+
+        // Handle whitespace
+        if (stream.eatSpace()) {
+            return null;
+        }
+
+        // Handle numbers (integers and floats)
+        if (stream.match(/^-?\d+\.\d+/)) {
+            return 'number';
+        }
+        if (stream.match(/^-?\d+/)) {
+            return 'number';
+        }
+
+        // Handle strings
+        if (stream.match(/^"[^"]*"/)) {
+            return 'string';
+        }
+
+        // Handle identifiers and keywords
+        if (stream.match(/^[a-zA-Z_][a-zA-Z0-9_]*/)) {
+            const word = stream.current();
+            
+            if (keywords.includes(word)) {
+                return 'keyword';
+            }
+            
+            if (types.includes(word)) {
+                return 'type';
+            }
+            
+            if (builtins.includes(word)) {
+                return 'builtin';
+            }
+            
+            // Check if it's a function declaration (followed by :)
+            const nextChar = stream.peek();
+            if (nextChar === ':') {
+                return 'function';
+            }
+            
+            return 'variable';
+        }
+
+        // Handle operators and symbols
+        if (stream.match(/^->/)) {
+            return 'operator';
+        }
+        
+        if (stream.match(/^[=!<>]=/)) {
+            return 'operator';
+        }
+        
+        if (stream.match(/^[+\-*/%=<>!&|^,;:()[\]{}]/)) {
+            return 'operator';
+        }
+        
+        // Handle dots for member access
+        if (stream.match(/^\./)) {
+            return 'operator';
+        }
+
+        // Handle unknown characters
+        stream.next();
+        return null;
+    }
+
+    // Define the Baba Yaga language mode
+    CodeMirror.defineMode("baba-yaga", function() {
+        return {
+            startState: function() {
+                return {
+                    inComment: false,
+                    inString: false,
+                    indentLevel: 0
+                };
+            },
+
+            token: function(stream, state) {
+                return tokenize(stream, state);
+            },
+
+            // Indentation rules
+            indent: function(state, textAfter) {
+                const baseIndent = state.indentLevel * 2;
+                
+                // Increase indent after certain patterns
+                if (textAfter.match(/^[a-zA-Z_][a-zA-Z0-9_]*\s*:/)) {
+                    return baseIndent + 2;
+                }
+                
+                if (textAfter.match(/^->/)) {
+                    return baseIndent + 2;
+                }
+                
+                if (textAfter.match(/^when/)) {
+                    return baseIndent + 2;
+                }
+                
+                if (textAfter.match(/^with/)) {
+                    return baseIndent + 2;
+                }
+                
+                return baseIndent;
+            },
+
+            // Line comment character
+            lineComment: "//",
+
+            // Auto-indent on certain characters
+            electricChars: "{}:->",
+
+            // Fold code blocks
+            fold: "indent"
+        };
+    });
+
+    // Note: CodeMirror 5 doesn't have defineTheme, we use CSS instead
+    // The theme is defined in the CSS with .cm-s-baba-yaga classes
+    
+    // Also register MIME types
+    CodeMirror.defineMIME("text/x-baba-yaga", "baba-yaga");
+    CodeMirror.defineMIME("text/baba-yaga", "baba-yaga");
+    CodeMirror.defineMIME("application/x-baba-yaga", "baba-yaga");
+
+    console.log('Baba Yaga language mode loaded successfully!');
+    console.log('Available modes:', Object.keys(CodeMirror.modes));
+    
+    // Dispatch a custom event to notify that the mode is ready
+    window.dispatchEvent(new CustomEvent('baba-yaga-mode-ready'));
+};
+
+// Start initialization
+console.log('Baba Yaga mode script loaded, waiting for CodeMirror...');
+window.initBabaYagaMode();
diff --git a/js/baba-yaga/web/editor/js/baba-yaga-runner.js b/js/baba-yaga/web/editor/js/baba-yaga-runner.js
new file mode 100644
index 0000000..6dd0312
--- /dev/null
+++ b/js/baba-yaga/web/editor/js/baba-yaga-runner.js
@@ -0,0 +1,564 @@
+class BabaYagaRunner {
+    constructor() {
+        this.editor = null;
+        this.container = document.querySelector('.container');
+        this.currentIOOutput = [];
+        this.init();
+    }
+
+    async init() {
+        try {
+            // Wait for Baba Yaga language mode to be ready
+            await this.waitForLanguageMode();
+            
+            // Initialize CodeMirror editor
+            this.initEditor();
+            
+            // Set up event listeners
+            this.setupEventListeners();
+            
+            // Load sample code
+            this.loadSampleCode();
+            
+            console.log('Baba Yaga Code Runner initialized successfully');
+        } catch (error) {
+            console.error('Failed to initialize Baba Yaga Code Runner:', error);
+            this.showError('Initialization failed: ' + error.message);
+        }
+    }
+
+    async waitForLanguageMode() {
+        return new Promise((resolve) => {
+            if (window.CodeMirror && window.CodeMirror.modes['baba-yaga']) {
+                resolve();
+            } else {
+                window.addEventListener('baba-yaga-mode-ready', resolve);
+            }
+        });
+    }
+
+    initEditor() {
+        const textarea = document.getElementById('code-editor');
+        
+        if (typeof CodeMirror === 'undefined') {
+            console.warn('CodeMirror not available, using basic textarea');
+            return;
+        }
+
+                    // Check if Baba Yaga language mode found, initializing with syntax highlighting
+            if (CodeMirror.modes['baba-yaga']) {
+                console.log('Baba Yaga language mode found, initializing with syntax highlighting');
+                            this.editor = CodeMirror.fromTextArea(textarea, {
+                mode: 'baba-yaga',
+                theme: 'monokai',
+                lineNumbers: true,
+                autoCloseBrackets: true,
+                matchBrackets: true,
+                indentUnit: 2,
+                tabSize: 2,
+                indentWithTabs: false,
+                lineWrapping: true,
+                foldGutter: true,
+                gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
+                // Mobile-friendly settings
+                lineWiseCopyCut: false,
+                dragDrop: false,
+                extraKeys: {
+                    'Tab': 'indentMore',
+                    'Shift-Tab': 'indentLess',
+                    'Enter': 'newlineAndIndent',
+                    'Ctrl-Enter': () => this.runCode(),
+                    'Cmd-Enter': () => this.runCode()
+                }
+            });
+            
+            // Ensure CodeMirror fills the container properly
+            setTimeout(() => {
+                this.editor.refresh();
+            }, 100);
+        } else {
+            console.warn('Baba Yaga language mode not found, using plain text mode');
+            this.editor = CodeMirror.fromTextArea(textarea, {
+                mode: 'text',
+                theme: 'monokai',
+                lineNumbers: true,
+                autoCloseBrackets: true,
+                matchBrackets: true,
+                indentUnit: 2,
+                tabSize: 2,
+                indentWithTabs: false,
+                lineWrapping: true,
+                foldGutter: true,
+                gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
+                // Mobile-friendly settings
+                lineWiseCopyCut: false,
+                dragDrop: false,
+                extraKeys: {
+                    'Tab': 'indentMore',
+                    'Shift-Tab': 'indentLess',
+                    'Enter': 'newlineAndIndent',
+                    'Ctrl-Enter': () => this.runCode(),
+                    'Cmd-Enter': () => this.runCode()
+                }
+            });
+        }
+    }
+
+    setupEventListeners() {
+        // Run button
+        const runBtn = document.getElementById('run-btn');
+        if (runBtn) {
+            runBtn.addEventListener('click', () => this.runCode());
+            // Add touch event for mobile
+            runBtn.addEventListener('touchend', (e) => {
+                e.preventDefault();
+                this.runCode();
+            });
+        }
+
+        // Format button
+        const formatBtn = document.getElementById('format-btn');
+        if (formatBtn) {
+            formatBtn.addEventListener('click', () => this.formatCode());
+            // Add touch event for mobile
+            formatBtn.addEventListener('touchend', (e) => {
+                e.preventDefault();
+                this.formatCode();
+            });
+        }
+
+        // Sample code button
+        const sampleBtn = document.getElementById('sample-btn');
+        if (sampleBtn) {
+            sampleBtn.addEventListener('click', () => this.loadSampleCode());
+            // Add touch event for mobile
+            sampleBtn.addEventListener('touchend', (e) => {
+                e.preventDefault();
+                this.loadSampleCode();
+            });
+        }
+
+        // Tab switching
+        const tabBtns = document.querySelectorAll('.output-tabs .tab-btn');
+        tabBtns.forEach(btn => {
+            btn.addEventListener('click', () => this.switchTab(btn.dataset.tab));
+            // Add touch event for mobile
+            btn.addEventListener('touchend', (e) => {
+                e.preventDefault();
+                this.switchTab(btn.dataset.tab);
+            });
+        });
+        
+        // Handle mobile keyboard events
+        this.setupMobileKeyboardHandling();
+    }
+    
+    setupMobileKeyboardHandling() {
+        // Handle mobile virtual keyboard events
+        if (this.editor) {
+            // Ensure CodeMirror handles mobile input properly
+            this.editor.on('focus', () => {
+                // Scroll into view on mobile when focusing
+                if (window.innerWidth <= 768) {
+                    setTimeout(() => {
+                        this.editor.refresh();
+                    }, 100);
+                }
+            });
+            
+            // Handle mobile viewport changes
+            window.addEventListener('resize', () => {
+                if (this.editor && this.editor.refresh) {
+                    setTimeout(() => {
+                        this.editor.refresh();
+                    }, 100);
+                }
+            });
+        }
+    }
+
+    switchTab(tabName) {
+        // Hide all tab panes
+        const tabPanes = document.querySelectorAll('.tab-pane');
+        tabPanes.forEach(pane => pane.classList.remove('active'));
+        
+        // Remove active class from all tab buttons
+        const tabBtns = document.querySelectorAll('.output-tabs .tab-btn');
+        tabBtns.forEach(btn => btn.classList.remove('active'));
+        
+        // Show selected tab pane
+        const selectedPane = document.getElementById(`${tabName}-tab`);
+        if (selectedPane) {
+            selectedPane.classList.add('active');
+        }
+        
+        // Activate selected tab button
+        const selectedBtn = document.querySelector(`[data-tab="${tabName}"]`);
+        if (selectedBtn) {
+            selectedBtn.classList.add('active');
+        }
+    }
+
+    async runCode() {
+        const runBtn = document.getElementById('run-btn');
+        const originalText = runBtn.textContent;
+        
+        try {
+            // Update button state
+            runBtn.textContent = 'Running...';
+            runBtn.className = 'btn';
+            runBtn.disabled = true;
+            
+            // Clear previous output
+            this.clearOutput();
+            
+            // Clear IO output tracking
+            this.currentIOOutput = [];
+            
+            // Get code from editor
+            const code = this.getCode();
+            if (!code.trim()) {
+                this.showError('No code to run. Please enter some Baba Yaga code.');
+                return;
+            }
+
+            // Parse and execute
+            const result = await this.executeCode(code);
+            
+            // Display results
+            this.displayResults(result);
+            
+            // Update button state
+            runBtn.textContent = 'Success!';
+            runBtn.className = 'btn success';
+            
+        } catch (error) {
+            console.error('Code execution error:', error);
+            this.showError('Execution failed: ' + error.message);
+            
+            // Update button state
+            runBtn.textContent = 'Error';
+            runBtn.className = 'btn error';
+        } finally {
+            // Reset button after delay
+            setTimeout(() => {
+                runBtn.textContent = originalText;
+                runBtn.className = 'btn';
+                runBtn.disabled = false;
+            }, 2000);
+        }
+    }
+
+    async executeCode(code) {
+        const result = {
+            code: code,
+            ast: null,
+            output: null,
+            errors: [],
+            executionTime: 0,
+            ioOutput: [] // Track IO output
+        };
+
+        try {
+            // Step 1: Lexical Analysis
+            this.showInfo('Analyzing code...');
+            const lexer = createLexer(code);
+            const tokens = lexer.allTokens();
+            this.showInfo(`Generated ${tokens.length} tokens`);
+            
+            // Step 2: Parsing
+            this.showInfo('Building AST...');
+            const parser = createParser(tokens);
+            const ast = parser.parse();
+            result.ast = ast;
+            this.showInfo('AST built successfully');
+            
+            // Step 3: Execution
+            this.showInfo('Executing code...');
+            const startTime = performance.now();
+            console.log('Creating interpreter with AST:', ast);
+            
+            // Create a custom IO host that captures output
+            const ioHost = {
+                io: {
+                    out: (...args) => {
+                        // Capture output and display it in real-time
+                        const outputText = args.map(arg => 
+                            typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)
+                        ).join(' ');
+                        
+                        // Store in result for later display
+                        result.ioOutput.push(outputText);
+                        
+                        // Also store in instance for real-time display
+                        this.currentIOOutput.push(outputText);
+                        
+                        // Show real-time output in a cleaner format
+                        this.showInfo(`${outputText}`);
+                        console.log('Baba Yaga output:', ...args);
+                    },
+                    in: () => '', // No input for now
+                    emit: () => {}, // No events for now
+                    listen: () => () => {} // No listeners for now
+                }
+            };
+            
+            const interpreter = createInterpreter(ast, ioHost);
+            console.log('Interpreter created:', interpreter);
+            console.log('Interpreter methods:', Object.getOwnPropertyNames(interpreter));
+            const output = interpreter.interpret();
+            console.log('Execution output:', output);
+            result.executionTime = performance.now() - startTime;
+            result.output = output;
+            
+            this.showInfo(`⚡ Execution completed in ${result.executionTime.toFixed(2)}ms`);
+            
+        } catch (error) {
+            // Enhanced error handling with helpful messages
+            const errorInfo = this.enhanceErrorMessage(error, code);
+            result.errors.push(errorInfo);
+            throw new Error(errorInfo.message);
+        }
+
+        return result;
+    }
+
+    enhanceErrorMessage(error, code) {
+        let enhancedError = {
+            message: error.message,
+            line: null,
+            column: null,
+            suggestion: '',
+            context: ''
+        };
+
+        // Extract line and column information from error message
+        const lineMatch = error.message.match(/at (\d+):(\d+)/);
+        if (lineMatch) {
+            enhancedError.line = parseInt(lineMatch[1]);
+            enhancedError.column = parseInt(lineMatch[2]);
+            
+            // Get the problematic line
+            const lines = code.split('\n');
+            if (enhancedError.line <= lines.length) {
+                const problemLine = lines[enhancedError.line - 1];
+                enhancedError.context = problemLine;
+                
+                // Add helpful suggestions based on error type
+                if (error.message.includes('Unexpected token')) {
+                    enhancedError.suggestion = 'Check for missing operators, parentheses, or semicolons.';
+                } else if (error.message.includes('Expected')) {
+                    enhancedError.suggestion = 'Check for missing required syntax elements.';
+                } else if (error.message.includes('ARROW')) {
+                    enhancedError.suggestion = 'Make sure arrow functions use the correct syntax: `params -> body`.';
+                } else if (error.message.includes('COLON')) {
+                    enhancedError.suggestion = 'Function declarations need a colon: `name : params -> body`.';
+                }
+            }
+        }
+
+        return enhancedError;
+    }
+
+    displayResults(result) {
+        // Display AST
+        const astText = document.getElementById('ast-text');
+        if (astText) {
+            astText.innerHTML = `<pre>${JSON.stringify(result.ast, null, 2)}</pre>`;
+        }
+
+        // Display output
+        const outputText = document.getElementById('output-text');
+        if (outputText) {
+            let outputHtml = '';
+            
+            // Show execution status
+            if (result.output !== null && result.output !== undefined) {
+                outputHtml += `
+                    <div class="success-message">
+                        <strong>Execution successful!</strong><br>
+                        <strong>Return value:</strong> ${typeof result.output === 'object' ? JSON.stringify(result.output, null, 2) : result.output}<br>
+                        <strong>Execution time:</strong> ${result.executionTime.toFixed(2)}ms
+                    </div>
+                `;
+            } else {
+                outputHtml += `
+                    <div class="info-message">
+                        <strong>Code executed successfully</strong><br>
+                        <strong>Execution time:</strong> ${result.executionTime.toFixed(2)}ms<br>
+                        <em>No return value (this is normal for some programs)</em>
+                    </div>
+                `;
+            }
+            
+            // Show IO output if any
+            if (result.ioOutput && result.ioOutput.length > 0) {
+                outputHtml += `
+                    <div class="info-message" style="margin-top: 1rem;">
+                        <strong>IO Output:</strong>
+                        ${result.ioOutput.map(output => `<div class="io-output-item">${output}</div>`).join('')}
+                    </div>
+                `;
+            }
+            
+            outputText.innerHTML = outputHtml;
+        }
+
+        // Switch to output tab
+        this.switchTab('output');
+    }
+
+    showError(message) {
+        const errorsText = document.getElementById('errors-text');
+        if (errorsText) {
+            errorsText.innerHTML = `
+                <div class="error-message">
+                    <strong>Error:</strong><br>
+                    ${message}
+                </div>
+            `;
+        }
+        
+        // Switch to errors tab
+        this.switchTab('errors');
+    }
+
+    showInfo(message) {
+        const outputText = document.getElementById('output-text');
+        if (outputText) {
+            outputText.innerHTML = message;
+        }
+    }
+
+    clearOutput() {
+        const outputText = document.getElementById('output-text');
+        const errorsText = document.getElementById('errors-text');
+        const astText = document.getElementById('ast-text');
+        
+        if (outputText) outputText.textContent = '';
+        if (errorsText) errorsText.textContent = 'No errors yet.';
+        if (astText) astText.textContent = 'AST will appear here after parsing.';
+    }
+
+    async formatCode() {
+        const formatBtn = document.getElementById('format-btn');
+        const originalText = formatBtn.textContent;
+        
+        try {
+            // Update button state
+            formatBtn.textContent = 'Formatting...';
+            formatBtn.className = 'btn format-btn';
+            formatBtn.disabled = true;
+            
+            // Get code from editor
+            const code = this.getCode();
+            if (!code.trim()) {
+                this.showError('No code to format. Please enter some Baba Yaga code.');
+                return;
+            }
+
+            // Check if formatter is available
+            if (typeof BabaYagaFormatter === 'undefined') {
+                this.showError('Formatter not available. Please refresh the page.');
+                return;
+            }
+
+            // Format the code
+            const formatter = new BabaYagaFormatter({
+                indentSize: 2,
+                maxLineLength: 100
+            });
+            
+            const formattedCode = formatter.format(code);
+            
+            // Update the editor with formatted code
+            if (this.editor) {
+                this.editor.setValue(formattedCode);
+            } else {
+                document.getElementById('code-editor').value = formattedCode;
+            }
+            
+            // Show success message
+            this.showInfo('Code formatted successfully!');
+            this.switchTab('output');
+            
+            // Update button state
+            formatBtn.textContent = 'Formatted!';
+            formatBtn.className = 'btn format-btn success';
+            
+        } catch (error) {
+            console.error('Code formatting error:', error);
+            this.showError('Formatting failed: ' + error.message);
+            
+            // Update button state
+            formatBtn.textContent = 'Error';
+            formatBtn.className = 'btn format-btn error';
+        } finally {
+            // Reset button after delay
+            setTimeout(() => {
+                formatBtn.textContent = originalText;
+                formatBtn.className = 'btn format-btn';
+                formatBtn.disabled = false;
+            }, 2000);
+        }
+    }
+
+    getCode() {
+        if (this.editor) {
+            return this.editor.getValue();
+        }
+        return document.getElementById('code-editor').value;
+    }
+
+    loadSampleCode() {
+        const sampleCode = `// Sample Baba Yaga code - try running this!
+// Notice the inconsistent formatting - use the Format button to clean it up!
+add:x y->x+y;
+
+multiply : x y->x*y;
+
+// Calculate factorial with inconsistent spacing
+factorial:n-> 
+    when n is
+        0 then 1
+        1    then 1
+        _  then n*factorial(n-1);
+
+// Test the functions
+result1:add 5 3;
+result2:multiply 4 6;
+result3:factorial 5;
+
+// Use io.out to display results
+io.out"Results:";
+io.out"add 5 3 = "result1;
+io.out "multiply 4 6 = " result2;
+io.out"factorial 5 = "result3;
+
+// Return the factorial result
+result3`;
+
+        if (this.editor) {
+            this.editor.setValue(sampleCode);
+        } else {
+            document.getElementById('code-editor').value = sampleCode;
+        }
+
+        this.showInfo('Sample code loaded! Click "Run Code" to execute it.');
+        this.switchTab('output');
+    }
+}
+
+// Initialize the runner when the page loads
+document.addEventListener('DOMContentLoaded', () => {
+    window.babaYagaRunner = new BabaYagaRunner();
+});
+
+// Add some helpful console commands
+window.babaYagaRunnerCommands = {
+    run: () => window.babaYagaRunner?.runCode(),
+    format: () => window.babaYagaRunner?.formatCode(),
+    getCode: () => window.babaYagaRunner?.getCode(),
+    loadSample: () => window.babaYagaRunner?.loadSampleCode(),
+    clearOutput: () => window.babaYagaRunner?.clearOutput()
+};
diff --git a/js/baba-yaga/web/editor/js/editor.js b/js/baba-yaga/web/editor/js/editor.js
new file mode 100644
index 0000000..37ab24f
--- /dev/null
+++ b/js/baba-yaga/web/editor/js/editor.js
@@ -0,0 +1,1004 @@
+/**
+ * BabaYagaEditor - Main editor class for the structural editor
+ * Manages the text editor, structural editor, and AST synchronization
+ */
+class BabaYagaEditor {
+    constructor(container) {
+        this.container = container;
+        this.parser = null;
+        this.tree = null;
+        this.editor = null;
+        this.astSynchronizer = null;
+        this.checkLanguageModeInterval = null;
+        
+        this.init();
+    }
+    
+    async init() {
+        try {
+            await this.initTreeSitter();
+            this.initEditor();
+            this.initASTSynchronizer();
+            this.bindEvents();
+            this.loadSampleCode();
+        } catch (error) {
+            console.error('Failed to initialize editor:', error);
+            this.showError('Failed to initialize editor: ' + error.message);
+        }
+    }
+    
+    async initTreeSitter() {
+        // Initialize tree-sitter parser (optional for now)
+        if (typeof TreeSitter !== 'undefined') {
+            this.parser = new TreeSitter();
+            try {
+                const JavaScript = await TreeSitter.Language.load('tree-sitter-javascript.wasm');
+                this.parser.setLanguage(JavaScript);
+            } catch (error) {
+                console.warn('Could not load JavaScript grammar, tree-sitter parsing disabled');
+            }
+        } else {
+            console.warn('Tree-sitter not loaded, using Baba Yaga parser instead');
+        }
+    }
+    
+    initEditor() {
+        // Initialize CodeMirror editor
+        const textarea = this.container.querySelector('#code-editor');
+        if (!textarea) {
+            throw new Error('Code editor textarea not found');
+        }
+        
+        // Check if CodeMirror is available
+        if (typeof CodeMirror !== 'undefined') {
+            console.log('CodeMirror is available, checking for Baba Yaga language mode...');
+            console.log('Available modes:', Object.keys(CodeMirror.modes));
+            
+            // Check if Baba Yaga language mode is available (CodeMirror 5)
+            const mode = CodeMirror.modes['baba-yaga'];
+            
+            if (mode) {
+                console.log('Baba Yaga language mode found, initializing with syntax highlighting');
+                // Initialize CodeMirror with Baba Yaga language mode
+                this.editor = CodeMirror.fromTextArea(textarea, {
+                    mode: 'baba-yaga',
+                    theme: 'baba-yaga', // Use our custom theme
+                    lineNumbers: true,
+                    autoCloseBrackets: true,
+                    matchBrackets: true,
+                    indentUnit: 2,
+                    tabSize: 2,
+                    indentWithTabs: false,
+                    lineWrapping: true,
+                    foldGutter: true,
+                    gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
+                    extraKeys: {
+                        'Tab': 'indentMore',
+                        'Shift-Tab': 'indentLess',
+                        'Enter': 'newlineAndIndent'
+                    }
+                });
+                
+                // Ensure CodeMirror fills the container properly
+                setTimeout(() => {
+                    this.editor.refresh();
+                    this.forceRefreshEditor();
+                }, 100);
+            } else {
+                console.warn('Baba Yaga language mode not found, using plain text mode');
+                console.log('Will retry when language mode becomes available...');
+                
+                // Initialize CodeMirror with plain text mode
+                this.editor = CodeMirror.fromTextArea(textarea, {
+                    mode: 'text',
+                    theme: 'monokai',
+                    lineNumbers: true,
+                    autoCloseBrackets: true,
+                    matchBrackets: true,
+                    indentUnit: 2,
+                    tabSize: 2,
+                    indentWithTabs: false,
+                    lineWrapping: true,
+                    foldGutter: true,
+                    gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
+                    extraKeys: {
+                        'Tab': 'indentMore',
+                        'Shift-Tab': 'indentLess',
+                        'Enter': 'newlineAndIndent'
+                    }
+                });
+                
+                // Listen for the language mode to become available
+                window.addEventListener('baba-yaga-mode-ready', () => {
+                    console.log('Baba Yaga language mode ready event received!');
+                    this.retryLanguageMode();
+                });
+            }
+            
+            // Set up change listener with debouncing for auto-parsing
+            let parseTimeout;
+            this.editor.on('change', () => {
+                // Clear previous timeout
+                if (parseTimeout) {
+                    clearTimeout(parseTimeout);
+                }
+                
+                // Set new timeout for auto-parsing (500ms delay)
+                parseTimeout = setTimeout(() => {
+                    if (this.astSynchronizer) {
+                        this.astSynchronizer.updateAST();
+                    }
+                }, 500);
+            });
+            
+        } else {
+            // Fallback to basic textarea if CodeMirror is not available
+            console.warn('CodeMirror not available, using basic textarea');
+            this.editor = {
+                getValue: () => textarea.value,
+                setValue: (value) => { textarea.value = value; },
+                on: (event, callback) => {
+                    if (event === 'change') {
+                        textarea.addEventListener('input', callback);
+                    }
+                }
+            };
+            
+            // Set up change listener with debouncing for auto-parsing
+            let parseTimeout;
+            this.editor.on('change', () => {
+                // Clear previous timeout
+                if (parseTimeout) {
+                    clearTimeout(parseTimeout);
+                }
+                
+                // Set new timeout for auto-parsing (500ms delay)
+                parseTimeout = setTimeout(() => {
+                    if (this.astSynchronizer) {
+                        this.astSynchronizer.updateAST();
+                    }
+                }, 500);
+            });
+        }
+        
+        // Set up add button event handlers
+        this.setupAddButtons();
+        
+        // Set up retry syntax highlighting button
+        this.setupRetryButton();
+        
+        // Set up window resize handler for CodeMirror
+        this.setupResizeHandler();
+        
+        // Periodically check if Baba Yaga language mode becomes available
+        if (typeof CodeMirror !== 'undefined') {
+            this.checkLanguageModeInterval = setInterval(() => {
+                if (this.retryLanguageMode()) {
+                    clearInterval(this.checkLanguageModeInterval);
+                }
+            }, 1000); // Check every second
+        }
+    }
+    
+    initASTSynchronizer() {
+        this.astSynchronizer = new ASTSynchronizer(this, null);
+    }
+    
+    bindEvents() {
+        // Parse button
+        const parseBtn = this.container.querySelector('#parse-btn');
+        if (parseBtn) {
+            parseBtn.addEventListener('click', () => this.parseCode());
+        }
+        
+        // Format button
+        const formatBtn = this.container.querySelector('#format-btn');
+        if (formatBtn) {
+            formatBtn.addEventListener('click', () => this.formatCode());
+        }
+        
+        // Run button
+        const runBtn = this.container.querySelector('#run-btn');
+        if (runBtn) {
+            runBtn.addEventListener('click', () => this.runCode());
+        }
+        
+        // Tab switching
+        const tabBtns = this.container.querySelectorAll('.structural-tabs .tab-btn');
+        tabBtns.forEach(btn => {
+            btn.addEventListener('click', () => this.switchTab(btn.dataset.tab));
+        });
+        
+        // Output tab switching
+        const outputTabBtns = this.container.querySelectorAll('.output-tabs .tab-btn');
+        outputTabBtns.forEach(btn => {
+            btn.addEventListener('click', () => this.switchOutputTab(btn.dataset.tab));
+        });
+    }
+    
+    switchTab(tabName) {
+        // Hide all tab panes
+        const tabPanes = this.container.querySelectorAll('.tab-pane');
+        tabPanes.forEach(pane => pane.classList.remove('active'));
+        
+        // Remove active class from all tab buttons
+        const tabBtns = this.container.querySelectorAll('.structural-tabs .tab-btn');
+        tabBtns.forEach(btn => btn.classList.remove('active'));
+        
+        // Show selected tab pane
+        const selectedPane = this.container.querySelector(`#${tabName}-tab`);
+        if (selectedPane) {
+            selectedPane.classList.add('active');
+        }
+        
+        // Activate selected tab button
+        const selectedBtn = this.container.querySelector(`[data-tab="${tabName}"]`);
+        if (selectedBtn) {
+            selectedBtn.classList.add('active');
+        }
+    }
+    
+    switchOutputTab(tabName) {
+        // Hide all output tab panes
+        const outputTabPanes = this.container.querySelectorAll('.output-content .tab-pane');
+        outputTabPanes.forEach(pane => pane.classList.remove('active'));
+        
+        // Remove active class from all output tab buttons
+        const outputTabBtns = this.container.querySelectorAll('.output-tabs .tab-btn');
+        outputTabBtns.forEach(btn => btn.classList.remove('active'));
+        
+        // Show selected output tab pane
+        const selectedPane = this.container.querySelector(`#${tabName}-tab`);
+        if (selectedPane) {
+            selectedPane.classList.add('active');
+        }
+        
+        // Activate selected output tab button
+        const selectedBtn = this.container.querySelector(`[data-tab="${tabName}"]`);
+        if (selectedBtn) {
+            selectedBtn.classList.add('active');
+        }
+    }
+    
+    parseCode() {
+        try {
+            const code = this.editor.getValue();
+            if (!code.trim()) {
+                this.showError('No code to parse');
+                return;
+            }
+            
+            let ast;
+            try {
+                // Try to use the real Baba Yaga parser
+                ast = this.parseWithBabaYaga(code);
+            } catch (parserError) {
+                console.warn('Real parser failed, falling back to basic parsing:', parserError);
+                // Fallback to basic parsing
+                ast = this.basicParse(code);
+            }
+            
+            this.tree = ast;
+            
+            // Update the tree view
+            this.updateTreeView(ast);
+            
+            // No longer using structural editors
+            
+            this.showSuccess('Code parsed successfully');
+            this.showASTJSON(ast);
+            
+        } catch (error) {
+            this.showError('Parse error: ' + error.message);
+            console.error('Parse error:', error);
+        }
+    }
+    
+    parseWithBabaYaga(code) {
+        try {
+            // Check if Baba Yaga components are available
+            console.log('Checking Baba Yaga components...');
+            console.log('createLexer:', typeof createLexer);
+            console.log('createParser:', typeof createParser);
+            console.log('createInterpreter:', typeof createInterpreter);
+            
+            if (typeof createLexer === 'undefined' || typeof createParser === 'undefined') {
+                throw new Error('Baba Yaga language components not loaded');
+            }
+            
+            // Use the real Baba Yaga lexer and parser
+            const lexer = createLexer(code);
+            const tokens = lexer.allTokens();
+            console.log('Tokens generated:', tokens.length);
+            
+            const parser = createParser(tokens);
+            const ast = parser.parse();
+            console.log('AST generated:', ast);
+            
+            return ast;
+        } catch (error) {
+            console.error('Baba Yaga parsing error:', error);
+            throw new Error(`Parsing failed: ${error.message}`);
+        }
+    }
+    
+    basicParse(code) {
+        // Basic parsing for demonstration purposes
+        // This will be replaced with proper tree-sitter parsing
+        const lines = code.split('\n').filter(line => line.trim());
+        const ast = {
+            type: 'Program',
+            body: []
+        };
+        
+        lines.forEach((line, index) => {
+            const trimmed = line.trim();
+            if (trimmed && !trimmed.startsWith('//')) {
+                if (trimmed.includes(':')) {
+                    const [name, ...rest] = trimmed.split(':');
+                    const value = rest.join(':').trim();
+                    
+                    if (value.includes('->')) {
+                        // Function declaration
+                        ast.body.push({
+                            type: 'FunctionDeclaration',
+                            name: name.trim(),
+                            params: this.parseFunctionParams(value),
+                            body: this.parseFunctionBody(value),
+                            line: index + 1
+                        });
+                    } else {
+                        // Variable declaration
+                        ast.body.push({
+                            type: 'VariableDeclaration',
+                            name: name.trim(),
+                            value: value,
+                            line: index + 1
+                        });
+                    }
+                }
+            }
+        });
+        
+        return ast;
+    }
+    
+    parseFunctionParams(value) {
+        // Basic function parameter parsing
+        const arrowIndex = value.indexOf('->');
+        if (arrowIndex === -1) return [];
+        
+        const beforeArrow = value.substring(0, arrowIndex).trim();
+        if (!beforeArrow) return [];
+        
+        // Simple space-separated parameter parsing
+        return beforeArrow.split(/\s+/).filter(p => p.trim());
+    }
+    
+    parseFunctionBody(value) {
+        // Basic function body parsing
+        const arrowIndex = value.indexOf('->');
+        if (arrowIndex === -1) return '';
+        
+        return value.substring(arrowIndex + 2).trim();
+    }
+    
+    updateTreeView(ast) {
+        const treeView = this.container.querySelector('#tree-view');
+        if (!treeView) return;
+        
+        treeView.innerHTML = this.renderTree(ast);
+    }
+    
+    renderTree(node, depth = 0) {
+        const indent = '  '.repeat(depth);
+        let html = '';
+        
+        if (!node || !node.type) {
+            return html;
+        }
+        
+        // Create a unique ID for this node
+        const nodeId = `node-${Math.random().toString(36).substr(2, 9)}`;
+        
+        html += `${indent}<div class="tree-node" data-node-id="${nodeId}" data-node-type="${node.type}">`;
+        html += `<div class="tree-node-content">`;
+        
+        // Node type (always editable)
+        html += `<span class="tree-node-type tree-node-editable" ondblclick="window.babaYagaEditor?.editNodeType('${nodeId}', '${node.type}')">${node.type}</span>`;
+        
+        // Node name (if exists)
+        if (node.name !== undefined) {
+            html += `<span class="tree-node-value tree-node-editable" ondblclick="window.babaYagaEditor?.editNodeValue('${nodeId}', 'name', '${node.name}')">${node.name}</span>`;
+        }
+        
+        // Node value (if exists)
+        if (node.value !== undefined) {
+            html += `<span class="tree-node-value tree-node-editable" ondblclick="window.babaYagaEditor?.editNodeValue('${nodeId}', 'value', '${JSON.stringify(node.value)}')">: ${JSON.stringify(node.value)}</span>`;
+        }
+        
+        // Handle different node types
+        if (node.params && Array.isArray(node.params)) {
+            html += `<span class="tree-node-value"> (${node.params.length} params)</span>`;
+        }
+        
+        if (node.returnType) {
+            html += `<span class="tree-node-value tree-node-editable" ondblclick="window.babaYagaEditor?.editNodeValue('${nodeId}', 'value', 'returnType', '${node.returnType}')"> -> ${node.returnType}</span>`;
+        }
+        
+        // Action buttons
+        html += `<div class="tree-node-actions">`;
+        html += `<button class="tree-node-action-btn" onclick="window.babaYagaEditor?.addChildNode('${nodeId}', '${node.type}')">+</button>`;
+        html += `<button class="tree-node-action-btn delete" onclick="window.babaYagaEditor?.deleteNode('${nodeId}')">×</button>`;
+        html += `</div>`;
+        
+        html += `</div>`;
+        
+        // Render children
+        if (node.body && Array.isArray(node.body)) {
+            html += `<div class="tree-node-children">`;
+            node.body.forEach(child => {
+                html += this.renderTree(child, depth + 1);
+            });
+            html += `</div>`;
+        } else if (node.body && typeof node.body === 'object') {
+            html += `<div class="tree-node-children">`;
+            html += this.renderTree(node.body, depth + 1);
+            html += `</div>`;
+        }
+        
+        // Handle other child properties
+        if (node.params && Array.isArray(node.params)) {
+            html += `<div class="tree-node-children">`;
+            html += `<div class="tree-node"><span class="tree-node-type">params</span></div>`;
+            node.params.forEach((param, index) => {
+                if (typeof param === 'string') {
+                    html += `<div class="tree-node-children"><div class="tree-node"><span class="tree-node-value tree-node-editable" ondblclick="window.babaYagaEditor?.editParamValue('${nodeId}', ${index}, '${param}')">${param}</span></div></div>`;
+                } else if (param.name) {
+                    html += `<div class="tree-node-children"><div class="tree-node"><span class="tree-node-value tree-node-editable" ondblclick="window.babaYagaEditor?.editParamValue('${nodeId}', ${index}, '${param.name}', '${param.type || ''}')">${param.name}${param.type ? ': ' + param.type : ''}</span></div></div>`;
+        }
+            });
+            html += `</div>`;
+        }
+        
+        html += `</div>`;
+        
+        return html;
+    }
+    
+    formatCode() {
+        try {
+            const code = this.editor.getValue();
+            if (!code.trim()) {
+                this.showError('No code to format');
+                return;
+            }
+            
+            // Basic formatting - in the future this will be more sophisticated
+            const formatted = this.basicFormat(code);
+            this.editor.setValue(formatted);
+            
+            this.showSuccess('Code formatted successfully');
+            
+        } catch (error) {
+            this.showError('Format error: ' + error.message);
+        }
+    }
+    
+    basicFormat(code) {
+        // Basic code formatting
+        const lines = code.split('\n');
+        const formatted = [];
+        let indentLevel = 0;
+        
+        lines.forEach(line => {
+            const trimmed = line.trim();
+            if (!trimmed) {
+                formatted.push('');
+                return;
+            }
+            
+            // Decrease indent for closing braces
+            if (trimmed === '}' || trimmed === ']' || trimmed === ')') {
+                indentLevel = Math.max(0, indentLevel - 1);
+            }
+            
+            // Add indentation
+            const indent = '  '.repeat(indentLevel);
+            formatted.push(indent + trimmed);
+            
+            // Increase indent for opening braces
+            if (trimmed === '{' || trimmed === '[' || trimmed === '(') {
+                indentLevel++;
+            }
+        });
+        
+        return formatted.join('\n');
+    }
+    
+    async runCode() {
+        try {
+            const code = this.editor.getValue();
+            if (!code.trim()) {
+                this.showError('No code to run');
+                return;
+            }
+            
+            // Parse the code first
+            let ast;
+            try {
+                ast = this.parseWithBabaYaga(code);
+            } catch (parserError) {
+                ast = this.basicParse(code);
+            }
+            
+            // Check if interpreter is available
+            if (typeof createInterpreter === 'undefined') {
+                this.showOutput('Interpreter not available. Code parsed successfully:\n' + JSON.stringify(ast, null, 2));
+                return;
+            }
+            
+            // Execute using the Baba Yaga interpreter
+            const interpreter = createInterpreter(ast);
+            const result = interpreter.interpret();
+            
+            // Display the result
+            this.showOutput(`Code executed successfully!\nResult: ${JSON.stringify(result, null, 2)}`);
+            
+        } catch (error) {
+            this.showError('Execution error: ' + error.message);
+            console.error('Execution error:', error);
+        }
+    }
+    
+        loadSampleCode() {
+        const sampleCode = `// Sample Baba Yaga code - demonstrating syntax highlighting
+add : x y -> x + y;
+
+multiply : x y -> x * y;
+
+// Simple function
+double : x -> x * 2;
+
+// Basic arithmetic
+calculate : x y -> (x + y) * 2;`;
+        
+        if (this.editor && this.editor.setValue) {
+            this.editor.setValue(sampleCode);
+        }
+    }
+    
+    showOutput(message) {
+        const outputText = this.container.querySelector('#output-text');
+        if (outputText) {
+            outputText.textContent = message;
+        }
+    }
+    
+    showError(message) {
+        const errorsText = this.container.querySelector('#errors-text');
+        if (errorsText) {
+            errorsText.textContent = message;
+            errorsText.className = 'error';
+        }
+    }
+    
+    showSuccess(message) {
+        const outputText = this.container.querySelector('#output-text');
+        if (outputText) {
+            outputText.textContent = message;
+            outputText.className = 'success';
+        }
+    }
+    
+    showASTJSON(ast) {
+        const astJsonText = this.container.querySelector('#ast-json-text');
+        if (astJsonText) {
+            astJsonText.textContent = JSON.stringify(ast, null, 2);
+        }
+    }
+    
+    getAST() {
+        return this.tree;
+    }
+    
+    getCode() {
+        return this.editor.getValue();
+    }
+    
+    selectASTNode(nodeId, nodeData) {
+        console.log('Selected AST node:', nodeId, nodeData);
+        
+        // Highlight the selected node
+        this.highlightSelectedNode(nodeId);
+        
+        // Populate the structural editor based on node type
+        this.populateStructuralEditor(nodeData);
+        
+        // Switch to the appropriate tab
+        this.switchToStructuralTab(nodeData.type);
+    }
+    
+    highlightSelectedNode(nodeId) {
+        // Remove previous highlights
+        document.querySelectorAll('.tree-node.selected').forEach(node => {
+            node.classList.remove('selected');
+        });
+        
+        // Add highlight to selected node
+        const selectedNode = document.querySelector(`[data-node-id="${nodeId}"]`);
+        if (selectedNode) {
+            selectedNode.classList.add('selected');
+        }
+    }
+    
+    populateStructuralEditor(nodeData) {
+        // No longer using structural editors - inline editing is handled directly
+        console.log('Selected node for inline editing:', nodeData);
+    }
+    
+    switchToStructuralTab(nodeType) {
+        let tabName = 'function'; // default
+        
+        switch (nodeType) {
+            case 'FunctionDeclaration':
+                tabName = 'function';
+                break;
+            case 'WhenExpression':
+                tabName = 'when';
+                break;
+            case 'WithHeader':
+                tabName = 'with';
+                break;
+        }
+        
+        this.switchTab(tabName);
+    }
+    
+    // Inline AST editing methods
+    editNodeType(nodeId, currentType) {
+        const nodeElement = document.querySelector(`[data-node-id="${nodeId}"]`);
+        if (!nodeElement) return;
+        
+        const typeElement = nodeElement.querySelector('.tree-node-type');
+        const input = document.createElement('input');
+        input.type = 'text';
+        input.value = currentType;
+        input.className = 'tree-node-editing';
+        
+        input.onblur = () => this.finishEditNodeType(nodeId, input.value);
+        input.onkeydown = (e) => {
+            if (e.key === 'Enter') {
+                this.finishEditNodeType(nodeId, input.value);
+            } else if (e.key === 'Escape') {
+                this.cancelEdit(nodeElement, typeElement);
+            }
+        };
+        
+        typeElement.innerHTML = '';
+        typeElement.appendChild(input);
+        input.focus();
+    }
+    
+    editNodeValue(nodeId, property, currentValue) {
+        const nodeElement = document.querySelector(`[data-node-id="${nodeId}"]`);
+        if (!nodeElement) return;
+        
+        const valueElement = nodeElement.querySelector(`[ondblclick*="${property}"]`);
+        if (!valueElement) return;
+        
+        const input = document.createElement('input');
+        input.type = 'text';
+        input.value = currentValue;
+        input.className = 'tree-node-editing';
+        
+        input.onblur = () => this.finishEditNodeValue(nodeId, property, input.value);
+        input.onkeydown = (e) => {
+            if (e.key === 'Enter') {
+                this.finishEditNodeValue(nodeId, property, input.value);
+            } else if (e.key === 'Escape') {
+                this.cancelEdit(nodeElement, valueElement);
+            }
+        };
+        
+        valueElement.innerHTML = '';
+        valueElement.appendChild(input);
+        input.focus();
+    }
+    
+    editParamValue(nodeId, paramIndex, currentName, currentType = '') {
+        const nodeElement = document.querySelector(`[data-node-id="${nodeId}"]`);
+        if (!nodeElement) return;
+        
+        const paramElements = nodeElement.querySelectorAll('.tree-node-children .tree-node-value');
+        const paramElement = paramElements[paramIndex];
+        if (!paramElement) return;
+        
+        const input = document.createElement('input');
+        input.type = 'text';
+        input.value = currentType ? `${currentName}: ${currentType}` : currentName;
+        input.className = 'tree-node-editing';
+        
+        input.onblur = () => this.finishEditParamValue(nodeId, paramIndex, input.value);
+        input.onkeydown = (e) => {
+            if (e.key === 'Enter') {
+                this.finishEditParamValue(nodeId, paramIndex, input.value);
+            } else if (e.key === 'Escape') {
+                this.cancelEdit(nodeElement, paramElement);
+            }
+        };
+        
+        paramElement.innerHTML = '';
+        paramElement.appendChild(input);
+        input.focus();
+    }
+    
+    finishEditNodeType(nodeId, newType) {
+        // Find the node in the AST and update it
+        this.updateASTNodeProperty(nodeId, 'type', newType);
+        this.refreshTreeView();
+    }
+    
+    finishEditNodeValue(nodeId, property, newValue) {
+        // Find the node in the AST and update it
+        this.updateASTNodeProperty(nodeId, property, newValue);
+        this.refreshTreeView();
+    }
+    
+    finishEditParamValue(nodeId, paramIndex, newValue) {
+        // Parse the new parameter value
+        let name, type;
+        if (newValue.includes(':')) {
+            [name, type] = newValue.split(':').map(s => s.trim());
+        } else {
+            name = newValue;
+            type = null;
+        }
+        
+        // Find the node in the AST and update the parameter
+        this.updateASTNodeParam(nodeId, paramIndex, name, type);
+        this.refreshTreeView();
+    }
+    
+    cancelEdit(nodeElement, originalElement) {
+        // Restore the original content
+        this.refreshTreeView();
+    }
+    
+    addChildNode(nodeId, parentType) {
+        // Add a new child node based on parent type
+        const newNode = this.createDefaultChildNode(parentType);
+        this.addChildToASTNode(nodeId, newNode);
+        this.refreshTreeView();
+    }
+    
+    deleteNode(nodeId) {
+        // Remove the node from the AST
+        this.removeASTNode(nodeId);
+        this.refreshTreeView();
+    }
+    
+    createDefaultChildNode(parentType) {
+        switch (parentType) {
+            case 'Program':
+                return { type: 'FunctionDeclaration', name: 'newFunction', params: [], body: 'expression' };
+            case 'FunctionDeclaration':
+                return { type: 'WhenExpression', discriminants: [], cases: [] };
+            case 'WithHeader':
+                return { type: 'WithHeader', recursive: false, entries: [], body: 'expression' };
+            default:
+                return { type: 'Expression', value: 'newValue' };
+        }
+    }
+    
+    updateASTNodeProperty(nodeId, property, value) {
+        // This is a simplified implementation
+        // In a real implementation, you'd traverse the AST to find and update the node
+        console.log(`Updating node ${nodeId} property ${property} to ${value}`);
+        
+        // Update the code editor to reflect changes
+        this.syncASTToCode();
+    }
+    
+    updateASTNodeParam(nodeId, paramIndex, name, type) {
+        console.log(`Updating node ${nodeId} parameter ${paramIndex} to ${name}: ${type}`);
+        this.syncASTToCode();
+    }
+    
+    addChildToASTNode(nodeId, childNode) {
+        console.log(`Adding child to node ${nodeId}:`, childNode);
+        this.syncASTToCode();
+    }
+    
+    removeASTNode(nodeId) {
+        console.log(`Removing node ${nodeId}`);
+        this.syncASTToCode();
+    }
+    
+    syncASTToCode() {
+        // Generate code from the current AST and update the code editor
+        if (this.astSynchronizer) {
+            const newCode = this.astSynchronizer.generateCode(this.tree);
+            this.editor.setValue(newCode);
+        }
+    }
+    
+    refreshTreeView() {
+        // Re-render the tree view with the updated AST
+        if (this.tree) {
+            this.updateTreeView(this.tree);
+        }
+    }
+    
+    refreshEditor() {
+        // Refresh CodeMirror editor if it's available
+        if (this.editor && this.editor.refresh) {
+            this.editor.refresh();
+        }
+    }
+    
+    // Force refresh the editor layout
+    forceRefreshEditor() {
+        if (this.editor) {
+            // Force a complete refresh
+            this.editor.refresh();
+            
+            // Also trigger a resize event to ensure proper layout
+            setTimeout(() => {
+                if (this.editor.refresh) {
+                    this.editor.refresh();
+                }
+            }, 50);
+        }
+    }
+    
+    retryLanguageMode() {
+        // Try to reload the Baba Yaga language mode
+        if (typeof CodeMirror !== 'undefined' && this.editor) {
+            // For CodeMirror 5, we can directly check if the mode is available
+            if (CodeMirror.modes['baba-yaga']) {
+                console.log('Baba Yaga language mode now available, switching to it');
+                this.editor.setOption('mode', 'baba-yaga');
+                // Force refresh after mode change
+                setTimeout(() => {
+                    this.forceRefreshEditor();
+                }, 50);
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    cleanup() {
+        // Clean up intervals
+        if (this.checkLanguageModeInterval) {
+            clearInterval(this.checkLanguageModeInterval);
+            this.checkLanguageModeInterval = null;
+        }
+    }
+    
+    setupAddButtons() {
+        // Add Function button
+        const addFunctionBtn = document.getElementById('add-function-btn');
+        if (addFunctionBtn) {
+            addFunctionBtn.addEventListener('click', () => {
+                this.addNewFunction();
+            });
+        }
+        
+        // Add When button
+        const addWhenBtn = document.getElementById('add-when-btn');
+        if (addWhenBtn) {
+            addWhenBtn.addEventListener('click', () => {
+                this.addNewWhen();
+            });
+        }
+        
+        // Add With button
+        const addWithBtn = document.getElementById('add-with-btn');
+        if (addWithBtn) {
+            addWithBtn.addEventListener('click', () => {
+                this.addNewWith();
+            });
+        }
+    }
+    
+    setupRetryButton() {
+        const retryBtn = document.getElementById('retry-syntax-btn');
+        if (retryBtn) {
+            retryBtn.addEventListener('click', () => {
+                console.log('Manual retry of syntax highlighting...');
+                if (this.retryLanguageMode()) {
+                    retryBtn.textContent = '✅';
+                    retryBtn.style.backgroundColor = '#4ec9b0';
+                    setTimeout(() => {
+                        retryBtn.textContent = '🔄';
+                        retryBtn.style.backgroundColor = '#6a9955';
+                    }, 2000);
+                } else {
+                    retryBtn.textContent = '❌';
+                    retryBtn.style.backgroundColor = '#f14c4c';
+                    setTimeout(() => {
+                        retryBtn.textContent = '🔄';
+                        retryBtn.style.backgroundColor = '#6a9955';
+                    }, 2000);
+                }
+            });
+        }
+    }
+    
+    setupResizeHandler() {
+        // Handle window resize to ensure CodeMirror fills container
+        window.addEventListener('resize', () => {
+            if (this.editor && this.editor.refresh) {
+                setTimeout(() => {
+                    this.editor.refresh();
+                }, 100);
+            }
+        });
+        
+        // Also handle when the container becomes visible
+        const observer = new ResizeObserver(() => {
+            if (this.editor && this.editor.refresh) {
+                setTimeout(() => {
+                    this.editor.refresh();
+                }, 100);
+            }
+        });
+        
+        if (this.container) {
+            observer.observe(this.container);
+        }
+    }
+    
+    addNewFunction() {
+        const newFunction = {
+            type: 'FunctionDeclaration',
+            name: 'newFunction',
+            params: [],
+            body: 'expression',
+            returnType: null
+        };
+        
+        if (!this.tree) {
+            this.tree = { type: 'Program', body: [] };
+        }
+        
+        this.tree.body.push(newFunction);
+        this.refreshTreeView();
+        this.syncASTToCode();
+    }
+    
+    addNewWhen() {
+        const newWhen = {
+            type: 'WhenExpression',
+            discriminants: [],
+            cases: []
+        };
+        
+        if (!this.tree) {
+            this.tree = { type: 'Program', body: [] };
+        }
+        
+        this.tree.body.push(newWhen);
+        this.refreshTreeView();
+        this.syncASTToCode();
+    }
+    
+    addNewWith() {
+        const newWith = {
+            type: 'WithHeader',
+            recursive: false,
+            entries: [],
+            body: 'expression'
+        };
+        
+        if (!this.tree) {
+            this.tree = { type: 'Program', body: [] };
+        }
+        
+        this.tree.body.push(newWith);
+        this.refreshTreeView();
+        this.syncASTToCode();
+    }
+}
diff --git a/js/baba-yaga/web/editor/js/formatter.js b/js/baba-yaga/web/editor/js/formatter.js
new file mode 100644
index 0000000..b0485d6
--- /dev/null
+++ b/js/baba-yaga/web/editor/js/formatter.js
@@ -0,0 +1,621 @@
+/**
+ * Browser-compatible Baba Yaga code formatter
+ * Adapted from fmt.js for use in the web editor
+ */
+
+class BabaYagaFormatter {
+  constructor(options = {}) {
+    this.indentSize = options.indentSize || 2;
+    this.maxLineLength = options.maxLineLength || 100;
+    this.preserveComments = options.preserveComments !== false;
+  }
+
+  /**
+   * Format source code string
+   */
+  format(source) {
+    try {
+      if (typeof createLexer === 'undefined' || typeof createParser === 'undefined') {
+        throw new Error('Baba Yaga language components not loaded');
+      }
+
+      const lexer = createLexer(source);
+      const tokens = lexer.allTokens();
+      
+      // Extract comments before parsing
+      const comments = this.extractComments(source);
+      
+      const parser = createParser(tokens);
+      const ast = parser.parse();
+      
+      return this.formatAST(ast, comments, source);
+    } catch (error) {
+      throw new Error(`Formatting failed: ${error.message}`);
+    }
+  }
+
+  /**
+   * Extract comments from source with their positions
+   */
+  extractComments(source) {
+    const comments = [];
+    const lines = source.split('\n');
+    
+    lines.forEach((line, lineIndex) => {
+      const commentMatch = line.match(/\/\/(.*)$/);
+      if (commentMatch) {
+        const column = line.indexOf('//');
+        comments.push({
+          line: lineIndex + 1,
+          column: column,
+          text: commentMatch[0],
+          content: commentMatch[1].trim()
+        });
+      }
+    });
+    
+    return comments;
+  }
+
+  /**
+   * Format AST node
+   */
+  formatAST(ast, comments = [], originalSource = '') {
+    return this.visitNode(ast, 0, comments);
+  }
+
+  /**
+   * Visit and format a node
+   */
+  visitNode(node, depth = 0, comments = []) {
+    if (!node) return '';
+
+    switch (node.type) {
+      case 'Program':
+        return this.formatProgram(node, depth, comments);
+      case 'TypeDeclaration':
+        return this.formatTypeDeclaration(node, depth);
+      case 'VariableDeclaration':
+        return this.formatVariableDeclaration(node, depth, comments);
+      case 'FunctionDeclaration':
+        return this.formatFunctionDeclaration(node, depth, comments);
+      case 'CurriedFunctionDeclaration':
+        return this.formatCurriedFunctionDeclaration(node, depth, comments);
+      case 'WithHeader':
+        return this.formatWithHeader(node, depth, comments);
+      case 'WhenExpression':
+        return this.formatWhenExpression(node, depth, comments);
+      case 'BinaryExpression':
+        return this.formatBinaryExpression(node, depth, comments);
+      case 'UnaryExpression':
+        return this.formatUnaryExpression(node, depth, comments);
+      case 'FunctionCall':
+        return this.formatFunctionCall(node, depth, comments);
+      case 'AnonymousFunction':
+        return this.formatAnonymousFunction(node, depth, comments);
+      case 'ListLiteral':
+        return this.formatListLiteral(node, depth, comments);
+      case 'TableLiteral':
+        return this.formatTableLiteral(node, depth, comments);
+      case 'MemberExpression':
+        return this.formatMemberExpression(node, depth, comments);
+      case 'ResultExpression':
+        return this.formatResultExpression(node, depth, comments);
+      case 'NumberLiteral':
+        return this.formatNumberLiteral(node);
+      case 'StringLiteral':
+        return this.formatStringLiteral(node);
+      case 'BooleanLiteral':
+        return this.formatBooleanLiteral(node);
+      case 'Identifier':
+        return this.formatIdentifier(node);
+      default:
+        // Fallback for unknown node types - avoid infinite recursion
+        if (typeof node === 'string') {
+          return node;
+        }
+        if (typeof node === 'number') {
+          return node.toString();
+        }
+        if (typeof node === 'boolean') {
+          return node.toString();
+        }
+        if (node && typeof node === 'object') {
+          // Try to handle as a literal value
+          if (node.value !== undefined) {
+            return node.value.toString();
+          }
+          if (node.name !== undefined) {
+            return node.name;
+          }
+        }
+        return JSON.stringify(node);
+    }
+  }
+
+  /**
+   * Format program (top level)
+   */
+  formatProgram(node, depth, comments) {
+    const statements = [];
+    let lastWasFunction = false;
+
+    node.body.forEach((stmt, index) => {
+      const formatted = this.visitNode(stmt, depth, comments);
+      const isFunction = stmt.type === 'FunctionDeclaration' || 
+                        stmt.type === 'CurriedFunctionDeclaration';
+      
+      // Add extra spacing between functions and other statements
+      if (index > 0 && (isFunction || lastWasFunction)) {
+        statements.push('');
+      }
+      
+      statements.push(formatted);
+      lastWasFunction = isFunction;
+    });
+
+    return statements.join('\n') + (statements.length > 0 ? '\n' : '');
+  }
+
+  /**
+   * Format type declaration
+   */
+  formatTypeDeclaration(node, depth) {
+    const indent = this.getIndent(depth);
+    return `${indent}${node.name} ${node.typeAnnotation};`;
+  }
+
+  /**
+   * Format variable declaration
+   */
+  formatVariableDeclaration(node, depth, comments) {
+    const indent = this.getIndent(depth);
+    
+    // Check if the value is a complex expression that should be on its own line
+    if (node.value.type === 'WhenExpression' || node.value.type === 'WithHeader') {
+      const value = this.visitNode(node.value, depth + 1, comments);
+      return `${indent}${node.name} :\n${value};`;
+    } else {
+      const value = this.visitNode(node.value, depth, comments);
+      return `${indent}${node.name} : ${value};`;
+    }
+  }
+
+  /**
+   * Format function declaration
+   */
+  formatFunctionDeclaration(node, depth, comments) {
+    const indent = this.getIndent(depth);
+    let result = `${indent}${node.name} : `;
+    
+    // Format parameters
+    if (node.params && node.params.length > 0) {
+      if (this.hasTypedParams(node.params)) {
+        result += this.formatTypedParameters(node.params);
+      } else {
+        result += node.params.map(p => typeof p === 'string' ? p : p.name).join(' ');
+      }
+    }
+    
+    // Add return type if present
+    if (node.returnType) {
+      result += ` -> ${this.formatType(node.returnType)}`;
+    }
+    
+    result += ' ->\n';
+    
+    // Format body with proper indentation
+    const body = this.visitNode(node.body, depth + 1, comments);
+    // If the body doesn't start with indentation, add it
+    if (body && !body.startsWith(this.getIndent(depth + 1))) {
+      result += this.getIndent(depth + 1) + body;
+    } else {
+      result += body;
+    }
+    
+    result += ';';
+    return result;
+  }
+
+  /**
+   * Format curried function declaration
+   */
+  formatCurriedFunctionDeclaration(node, depth, comments) {
+    const indent = this.getIndent(depth);
+    let result = `${indent}${node.name} : `;
+    
+    // Format first typed parameter
+    result += `(${node.param.name}: ${this.formatType(node.param.type)})`;
+    
+    // Format return type
+    if (node.returnType) {
+      result += ` -> ${this.formatType(node.returnType)}`;
+    }
+    
+    result += ' ->\n';
+    
+    // Format body with proper indentation
+    const body = this.visitNode(node.body, depth + 1, comments);
+    result += body + ';';
+    
+    return result;
+  }
+
+  /**
+   * Format with header
+   */
+  formatWithHeader(node, depth, comments) {
+    const indent = this.getIndent(depth);
+    let result = `${indent}with`;
+    
+    if (node.recursive) {
+      result += ' rec';
+    }
+    
+    result += ' (\n';
+    
+    // Format entries
+    node.entries.forEach((entry, index) => {
+      const entryIndent = this.getIndent(depth + 1);
+      if (entry.type === 'WithTypeDecl') {
+        result += `${entryIndent}${entry.name} ${this.formatType(entry.typeAnnotation)};`;
+      } else if (entry.type === 'WithAssign') {
+        const value = this.visitNode(entry.value, depth + 1, comments);
+        result += `${entryIndent}${entry.name} : ${value};`;
+      }
+      
+      if (index < node.entries.length - 1) {
+        result += '\n';
+      }
+    });
+    
+    result += `\n${indent}) ->\n`;
+    const body = this.visitNode(node.body, depth + 1, comments);
+    // Ensure the body is properly indented
+    if (body && !body.startsWith(this.getIndent(depth + 1))) {
+      result += this.getIndent(depth + 1) + body;
+    } else {
+      result += body;
+    }
+    
+    return result;
+  }
+
+  /**
+   * Format when expression
+   */
+  formatWhenExpression(node, depth, comments) {
+    const indent = this.getIndent(depth);
+    let result = `${indent}when `;
+    
+    // Format discriminants
+    const discriminants = node.discriminants.map(d => 
+      this.visitNode(d, 0, comments)
+    ).join(' ');
+    result += `${discriminants} is\n`;
+    
+    // Calculate the maximum pattern width to align 'then' keywords
+    const caseIndent = this.getIndent(depth + 1);
+    const formattedCases = node.cases.map(caseNode => {
+      const patterns = caseNode.patterns.map(p => 
+        this.formatPattern(p, depth + 1, comments)
+      ).join(' ');
+      return {
+        patterns,
+        consequent: caseNode.consequent,
+        originalCase: caseNode
+      };
+    });
+    
+    // Find the maximum pattern length for alignment
+    const maxPatternLength = Math.max(
+      ...formattedCases.map(c => c.patterns.length)
+    );
+    
+    // Format cases with aligned 'then' keywords
+    formattedCases.forEach((formattedCase, index) => {
+      const { patterns, consequent } = formattedCase;
+      
+      // Pad patterns to align 'then' keywords
+      const paddedPatterns = patterns.padEnd(maxPatternLength);
+      result += `${caseIndent}${paddedPatterns} then `;
+      
+      // Format consequent - handle nested when expressions specially
+      if (consequent.type === 'WhenExpression') {
+        // For nested when expressions, add newline and proper indentation
+        result += '\n' + this.visitNode(consequent, depth + 2, comments);
+      } else {
+        // For simple consequents, add inline
+        const consequentFormatted = this.visitNode(consequent, 0, comments);
+        result += consequentFormatted;
+      }
+      
+      // Add newline between cases (but not after the last one)
+      if (index < formattedCases.length - 1) {
+        result += '\n';
+      }
+    });
+    
+    return result;
+  }
+
+  /**
+   * Format pattern
+   */
+  formatPattern(pattern, depth, comments) {
+    if (!pattern) return '';
+    
+    switch (pattern.type) {
+      case 'WildcardPattern':
+        return '_';
+      case 'TypePattern':
+        return pattern.name;
+      case 'ResultPattern':
+        return `${pattern.variant} ${pattern.identifier.name}`;
+      case 'ListPattern':
+        const elements = pattern.elements.map(e => 
+          this.formatPattern(e, depth, comments)
+        ).join(', ');
+        return `[${elements}]`;
+      case 'TablePattern':
+        const properties = pattern.properties.map(prop => 
+          `${prop.key}: ${this.formatPattern(prop.value, depth, comments)}`
+        ).join(', ');
+        return `{${properties}}`;
+      case 'NumberLiteral':
+        return pattern.value.toString();
+      case 'StringLiteral':
+        return `"${pattern.value}"`;
+      case 'BooleanLiteral':
+        return pattern.value.toString();
+      case 'Identifier':
+        return pattern.name;
+      default:
+        // For literal patterns, try to format them directly
+        if (typeof pattern === 'string') {
+          return pattern;
+        }
+        if (typeof pattern === 'number') {
+          return pattern.toString();
+        }
+        return this.visitNode(pattern, depth, comments);
+    }
+  }
+
+  /**
+   * Format binary expression
+   */
+  formatBinaryExpression(node, depth, comments) {
+    const left = this.visitNode(node.left, depth, comments);
+    const right = this.visitNode(node.right, depth, comments);
+    
+    // Add spaces around operators
+    const needsSpaces = !['.', '..'].includes(node.operator);
+    if (needsSpaces) {
+      return `${left} ${node.operator} ${right}`;
+    } else {
+      return `${left}${node.operator}${right}`;
+    }
+  }
+
+  /**
+   * Format unary expression
+   */
+  formatUnaryExpression(node, depth, comments) {
+    const operand = this.visitNode(node.operand, depth, comments);
+    return `${node.operator}${operand}`;
+  }
+
+  /**
+   * Format function call
+   */
+  formatFunctionCall(node, depth, comments) {
+    const callee = this.visitNode(node.callee, depth, comments);
+    const args = node.arguments.map(arg => 
+      this.visitNode(arg, depth, comments)
+    );
+    
+    if (args.length === 0) {
+      return callee;
+    }
+    
+    // Handle parentheses for complex expressions
+    const formattedArgs = args.map(arg => {
+      // If argument contains operators or is complex, wrap in parentheses
+      if (arg.includes(' -> ') || (arg.includes(' ') && !arg.startsWith('"') && !arg.startsWith('['))) {
+        return `(${arg})`;
+      }
+      return arg;
+    });
+    
+    return `${callee} ${formattedArgs.join(' ')}`;
+  }
+
+  /**
+   * Format anonymous function
+   */
+  formatAnonymousFunction(node, depth, comments) {
+    // Handle both string parameters and object parameters
+    const params = node.params.map(param => {
+      if (typeof param === 'string') {
+        return param;
+      } else if (param && typeof param === 'object' && param.name) {
+        return param.name;
+      } else if (param && typeof param === 'object' && param.type === 'Identifier') {
+        return param.name;
+      } else {
+        return String(param);
+      }
+    }).join(' ');
+    const body = this.visitNode(node.body, depth, comments);
+    return `${params} -> ${body}`;
+  }
+
+  /**
+   * Format list literal
+   */
+  formatListLiteral(node, depth, comments) {
+    if (node.elements.length === 0) {
+      return '[]';
+    }
+    
+    const elements = node.elements.map(el => 
+      this.visitNode(el, depth, comments)
+    );
+    
+    // Single line if short, multi-line if long
+    const singleLine = `[${elements.join(', ')}]`;
+    if (singleLine.length <= 50) {
+      return singleLine;
+    }
+    
+    const indent = this.getIndent(depth);
+    const elementIndent = this.getIndent(depth + 1);
+    let result = '[\n';
+    elements.forEach((el, index) => {
+      result += `${elementIndent}${el}`;
+      if (index < elements.length - 1) {
+        result += ',';
+      }
+      result += '\n';
+    });
+    result += `${indent}]`;
+    return result;
+  }
+
+  /**
+   * Format table literal
+   */
+  formatTableLiteral(node, depth, comments) {
+    if (node.properties.length === 0) {
+      return '{}';
+    }
+    
+    const properties = node.properties.map(prop => {
+      const value = this.visitNode(prop.value, depth + 1, comments);
+      return `${prop.key}: ${value}`;
+    });
+    
+    // Single line if short, multi-line if long
+    const singleLine = `{${properties.join(', ')}}`;
+    if (singleLine.length <= 50 && !properties.some(p => p.includes('\n'))) {
+      return singleLine;
+    }
+    
+    const indent = this.getIndent(depth);
+    const propIndent = this.getIndent(depth + 1);
+    let result = '{\n';
+    properties.forEach((prop, index) => {
+      result += `${propIndent}${prop}`;
+      if (index < properties.length - 1) {
+        result += ',';
+      }
+      result += '\n';
+    });
+    result += `${indent}}`;
+    return result;
+  }
+
+  /**
+   * Format member expression
+   */
+  formatMemberExpression(node, depth, comments) {
+    const object = this.visitNode(node.object, depth, comments);
+    const property = this.visitNode(node.property, depth, comments);
+    return `${object}.${property}`;
+  }
+
+  /**
+   * Format result expression
+   */
+  formatResultExpression(node, depth, comments) {
+    const value = this.visitNode(node.value, depth, comments);
+    return `${node.variant} ${value}`;
+  }
+
+  /**
+   * Format number literal
+   */
+  formatNumberLiteral(node) {
+    return node.value.toString();
+  }
+
+  /**
+   * Format string literal
+   */
+  formatStringLiteral(node) {
+    return `"${node.value}"`;
+  }
+
+  /**
+   * Format boolean literal
+   */
+  formatBooleanLiteral(node) {
+    return node.value.toString();
+  }
+
+  /**
+   * Format identifier
+   */
+  formatIdentifier(node) {
+    return node.name;
+  }
+
+  // Helper methods
+
+  /**
+   * Get indentation string
+   */
+  getIndent(depth) {
+    return ' '.repeat(depth * this.indentSize);
+  }
+
+  /**
+   * Check if parameters have type annotations
+   */
+  hasTypedParams(params) {
+    return params.some(p => 
+      typeof p === 'object' && p.type && p.type !== 'Identifier'
+    );
+  }
+
+  /**
+   * Format typed parameters
+   */
+  formatTypedParameters(params) {
+    const formatted = params.map(p => {
+      if (typeof p === 'string') {
+        return p;
+      } else if (p.type && p.type !== 'Identifier') {
+        return `${p.name}: ${this.formatType(p.type)}`;
+      } else {
+        return p.name;
+      }
+    });
+    return `(${formatted.join(', ')})`;
+  }
+
+  /**
+   * Format type annotation
+   */
+  formatType(type) {
+    if (typeof type === 'string') {
+      return type;
+    }
+    
+    if (type.type === 'PrimitiveType') {
+      return type.name;
+    }
+    
+    if (type.type === 'FunctionType') {
+      const paramTypes = type.paramTypes.map(t => this.formatType(t)).join(', ');
+      const returnType = this.formatType(type.returnType);
+      return `(${paramTypes}) -> ${returnType}`;
+    }
+    
+    return 'Unknown';
+  }
+}
+
+// Make formatter available globally
+window.BabaYagaFormatter = BabaYagaFormatter;
diff --git a/js/baba-yaga/web/editor/js/main.js b/js/baba-yaga/web/editor/js/main.js
new file mode 100644
index 0000000..29dda7c
--- /dev/null
+++ b/js/baba-yaga/web/editor/js/main.js
@@ -0,0 +1,225 @@
+/**
+ * main.js - Main entry point for the Baba Yaga Structural Editor
+ * Initializes the editor when the page loads
+ */
+
+// Wait for DOM to be ready
+document.addEventListener('DOMContentLoaded', () => {
+    console.log('Baba Yaga Structural Editor initializing...');
+    
+    try {
+        // Initialize the main editor
+        const container = document.querySelector('.editor-container');
+        if (!container) {
+            throw new Error('Editor container not found');
+        }
+        
+        // Create and initialize the editor
+        const editor = new BabaYagaEditor(container);
+        
+        // Store reference globally for debugging
+        window.babaYagaEditor = editor;
+        
+        console.log('Baba Yaga Structural Editor initialized successfully');
+        
+        // Add some helpful console commands for development
+        window.babaYagaEditorCommands = {
+            getAST: () => editor.getAST(),
+            getCode: () => editor.getCode(),
+            parse: () => editor.parseCode(),
+            format: () => editor.formatCode(),
+            run: () => editor.runCode(),
+            retryLanguageMode: () => editor.retryLanguageMode(),
+            initLanguageMode: () => window.initBabaYagaMode(),
+            forceRefresh: () => editor.forceRefreshEditor(),
+            refresh: () => editor.refreshEditor(),
+            showAST: () => {
+                const ast = editor.getAST();
+                console.log('Current AST:', ast);
+                return ast;
+            },
+            showCode: () => {
+                const code = editor.getCode();
+                console.log('Current Code:', code);
+                return code;
+            }
+        };
+        
+        console.log('Development commands available: window.babaYagaEditorCommands');
+        
+    } catch (error) {
+        console.error('Failed to initialize Baba Yaga Structural Editor:', error);
+        
+        // Show error message to user
+        const errorDiv = document.createElement('div');
+        errorDiv.style.cssText = `
+            position: fixed;
+            top: 50%;
+            left: 50%;
+            transform: translate(-50%, -50%);
+            background: #d73a49;
+            color: white;
+            padding: 2rem;
+            border-radius: 8px;
+            font-family: monospace;
+            max-width: 80%;
+            text-align: center;
+            z-index: 10000;
+        `;
+        errorDiv.innerHTML = `
+            <h2>Initialization Error</h2>
+            <p>${error.message}</p>
+            <p>Check the console for more details.</p>
+            <button onclick="this.parentElement.remove()" style="margin-top: 1rem; padding: 0.5rem 1rem; border: none; border-radius: 4px; cursor: pointer;">Close</button>
+        `;
+        document.body.appendChild(errorDiv);
+    }
+});
+
+// Add some global error handling
+window.addEventListener('error', (event) => {
+    console.error('Global error:', event.error);
+});
+
+window.addEventListener('unhandledrejection', (event) => {
+    console.error('Unhandled promise rejection:', event.reason);
+});
+
+// Add some helpful utility functions
+window.babaYagaUtils = {
+    // Parse Baba Yaga code manually
+    parseCode: (code) => {
+        try {
+            // Try to use the real Baba Yaga parser if available
+            if (typeof createLexer !== 'undefined' && typeof createParser !== 'undefined') {
+                try {
+                    const lexer = createLexer(code);
+                    const tokens = lexer.allTokens();
+                    const parser = createParser(tokens);
+                    return parser.parse();
+                } catch (parserError) {
+                    console.warn('Real parser failed, falling back to basic parsing:', parserError);
+                }
+            }
+            
+            // Basic parsing for demonstration
+            const lines = code.split('\n').filter(line => line.trim());
+            const ast = {
+                type: 'Program',
+                body: []
+            };
+            
+            lines.forEach((line, index) => {
+                const trimmed = line.trim();
+                if (trimmed && !trimmed.startsWith('//')) {
+                    if (trimmed.includes(':')) {
+                        const [name, ...rest] = trimmed.split(':');
+                        const value = rest.join(':').trim();
+                        
+                        if (value.includes('->')) {
+                            ast.body.push({
+                                type: 'FunctionDeclaration',
+                                name: name.trim(),
+                                params: window.babaYagaUtils.parseFunctionParams(value),
+                                body: window.babaYagaUtils.parseFunctionBody(value),
+                                line: index + 1
+                            });
+                        } else {
+                            ast.body.push({
+                                type: 'VariableDeclaration',
+                                name: name.trim(),
+                                value: value,
+                                line: index + 1
+                            });
+                        }
+                    }
+                }
+            });
+            
+            return ast;
+        } catch (error) {
+            console.error('Parse error:', error);
+            throw error;
+        }
+    },
+    
+    parseFunctionParams: (value) => {
+        const arrowIndex = value.indexOf('->');
+        if (arrowIndex === -1) return [];
+        
+        const beforeArrow = value.substring(0, arrowIndex).trim();
+        if (!beforeArrow) return [];
+        
+        return beforeArrow.split(/\s+/).filter(p => p.trim());
+    },
+    
+    parseFunctionBody: (value) => {
+        const arrowIndex = value.indexOf('->');
+        if (arrowIndex === -1) return '';
+        
+        return value.substring(arrowIndex + 2).trim();
+    },
+    
+    // Generate code from AST
+    generateCode: (ast) => {
+        if (!ast || ast.type !== 'Program') return '';
+        
+        const lines = [];
+        
+        ast.body.forEach(node => {
+            switch (node.type) {
+                case 'FunctionDeclaration':
+                    lines.push(window.babaYagaUtils.generateFunctionCode(node));
+                    break;
+                case 'VariableDeclaration':
+                    lines.push(window.babaYagaUtils.generateVariableCode(node));
+                    break;
+                default:
+                    lines.push(`// Unknown node type: ${node.type}`);
+            }
+        });
+        
+        return lines.join('\n');
+    },
+    
+    generateFunctionCode: (node) => {
+        let code = `${node.name} : `;
+        
+        if (node.params && node.params.length > 0) {
+            code += node.params.join(' ');
+        }
+        
+        code += ' -> ';
+        code += node.body || '';
+        
+        return code;
+    },
+    
+    generateVariableCode: (node) => {
+        return `${node.name} : ${node.value};`;
+    },
+    
+    // Validate Baba Yaga syntax
+    validateSyntax: (code) => {
+        try {
+            const ast = window.babaYagaUtils.parseCode(code);
+            return { valid: true, ast };
+        } catch (error) {
+            return { valid: false, error: error.message };
+        }
+    },
+    
+    // Format Baba Yaga code
+    formatCode: (code) => {
+        try {
+            const ast = window.babaYagaUtils.parseCode(code);
+            return window.babaYagaUtils.generateCode(ast);
+        } catch (error) {
+            console.error('Format error:', error);
+            return code; // Return original code if formatting fails
+        }
+    }
+};
+
+console.log('Baba Yaga utilities available: window.babaYagaUtils');
+console.log('Try: window.babaYagaUtils.parseCode("add : x y -> x + y;")');
diff --git a/js/baba-yaga/web/editor/js/structural-editors.js b/js/baba-yaga/web/editor/js/structural-editors.js
new file mode 100644
index 0000000..3203d19
--- /dev/null
+++ b/js/baba-yaga/web/editor/js/structural-editors.js
@@ -0,0 +1,501 @@
+/**
+ * StructuralEditors - Manages all structural editing panels
+ * Provides interfaces for editing functions, when expressions, and with headers
+ */
+class StructuralEditors {
+    constructor(container) {
+        this.container = container;
+        this.changeCallbacks = [];
+        this.currentAST = null;
+        this.silentUpdate = false;
+        
+        this.init();
+    }
+    
+    init() {
+        this.initFunctionEditor();
+        this.initWhenEditor();
+        this.initWithEditor();
+        this.bindEvents();
+    }
+    
+    initFunctionEditor() {
+        this.functionEditor = {
+            name: this.container.querySelector('#func-name'),
+            params: this.container.querySelector('#func-params'),
+            returnType: this.container.querySelector('#func-return-type'),
+            body: this.container.querySelector('#func-body'),
+            addParamBtn: this.container.querySelector('#add-param-btn')
+        };
+    }
+    
+    initWhenEditor() {
+        this.whenEditor = {
+            discriminants: this.container.querySelector('#when-discriminants'),
+            cases: this.container.querySelector('#when-cases'),
+            addDiscriminantBtn: this.container.querySelector('#add-discriminant-btn'),
+            addCaseBtn: this.container.querySelector('#add-case-btn')
+        };
+    }
+    
+    initWithEditor() {
+        this.withEditor = {
+            recursive: this.container.querySelector('#with-recursive'),
+            entries: this.container.querySelector('#with-entries'),
+            body: this.container.querySelector('#with-body'),
+            addEntryBtn: this.container.querySelector('#add-entry-btn')
+        };
+    }
+    
+    bindEvents() {
+        // Function editor events
+        if (this.functionEditor.addParamBtn) {
+            this.functionEditor.addParamBtn.addEventListener('click', () => {
+                this.addFunctionParameter();
+            });
+        }
+        
+        if (this.functionEditor.name) {
+            this.functionEditor.name.addEventListener('input', () => {
+                this.onFunctionChange();
+            });
+        }
+        
+        if (this.functionEditor.returnType) {
+            this.functionEditor.returnType.addEventListener('change', () => {
+                this.onFunctionChange();
+            });
+        }
+        
+        // When editor events
+        if (this.whenEditor.addDiscriminantBtn) {
+            this.whenEditor.addDiscriminantBtn.addEventListener('click', () => {
+                this.addWhenDiscriminant();
+            });
+        }
+        
+        if (this.whenEditor.addCaseBtn) {
+            this.whenEditor.addCaseBtn.addEventListener('click', () => {
+                this.addWhenCase();
+            });
+        }
+        
+        // With editor events
+        if (this.withEditor.addEntryBtn) {
+            this.withEditor.addEntryBtn.addEventListener('click', () => {
+                this.addWithEntry();
+            });
+        }
+        
+        if (this.withEditor.recursive) {
+            this.withEditor.recursive.addEventListener('change', () => {
+                this.onWithChange();
+            });
+        }
+    }
+    
+    // Function Editor Methods
+    
+    addFunctionParameter() {
+        const paramItem = document.createElement('div');
+        paramItem.className = 'parameter-item';
+        paramItem.innerHTML = `
+            <input type="text" class="param-name" placeholder="parameterName" />
+            <select class="param-type">
+                <option value="">Infer</option>
+                <option value="Int">Int</option>
+                <option value="Float">Float</option>
+                <option value="String">String</option>
+                <option value="Bool">Bool</option>
+                <option value="List">List</option>
+                <option value="Table">Table</option>
+            </select>
+            <button class="remove-param-btn" onclick="this.parentElement.remove()">Remove</button>
+        `;
+        
+        // Add event listeners for the new parameter
+        const nameInput = paramItem.querySelector('.param-name');
+        const typeSelect = paramItem.querySelector('.param-type');
+        
+        nameInput.addEventListener('input', () => this.onFunctionChange());
+        typeSelect.addEventListener('change', () => this.onFunctionChange());
+        
+        this.functionEditor.params.appendChild(paramItem);
+        this.onFunctionChange();
+    }
+    
+    onFunctionChange() {
+        // Don't notify changes during silent updates
+        if (this.silentUpdate) {
+            return;
+        }
+        
+        const changes = [{
+            type: 'function_update',
+            oldName: this.getCurrentFunctionName(),
+            newName: this.functionEditor.name.value,
+            params: this.getFunctionParameters(),
+            returnType: this.functionEditor.returnType.value || null,
+            body: this.getFunctionBody()
+        }];
+        
+        this.notifyChanges(changes);
+    }
+    
+    getCurrentFunctionName() {
+        // Try to get the name from the current AST selection
+        // For now, return a default
+        return 'currentFunction';
+    }
+    
+    getFunctionParameters() {
+        const params = [];
+        const paramItems = this.functionEditor.params.querySelectorAll('.parameter-item');
+        
+        paramItems.forEach(item => {
+            const name = item.querySelector('.param-name').value;
+            const type = item.querySelector('.param-type').value;
+            
+            if (name.trim()) {
+                params.push({
+                    name: name.trim(),
+                    type: type || null
+                });
+            }
+        });
+        
+        return params;
+    }
+    
+    getFunctionBody() {
+        // For now, return a simple expression
+        // In the future, this will be a more sophisticated expression builder
+        return 'expression';
+    }
+    
+    // When Editor Methods
+    
+    addWhenDiscriminant() {
+        const discriminantItem = document.createElement('div');
+        discriminantItem.className = 'expression-item';
+        discriminantItem.innerHTML = `
+            <input type="text" class="discriminant-expr" placeholder="expression" />
+            <button class="remove-discriminant-btn" onclick="this.parentElement.remove()">Remove</button>
+        `;
+        
+        const exprInput = discriminantItem.querySelector('.discriminant-expr');
+        exprInput.addEventListener('input', () => this.onWhenChange());
+        
+        this.whenEditor.discriminants.appendChild(discriminantItem);
+        this.onWhenChange();
+    }
+    
+    addWhenCase() {
+        const caseItem = document.createElement('div');
+        caseItem.className = 'case-item';
+        caseItem.innerHTML = `
+            <div class="case-header">
+                <h4>Case</h4>
+                <button class="remove-case-btn" onclick="this.closest('.case-item').remove()">Remove</button>
+            </div>
+            <div class="case-patterns">
+                <div class="pattern-item">
+                    <select class="pattern-type">
+                        <option value="literal">Literal</option>
+                        <option value="type">Type</option>
+                        <option value="wildcard">Wildcard</option>
+                        <option value="list">List</option>
+                        <option value="table">Table</option>
+                    </select>
+                    <input type="text" class="pattern-value" placeholder="pattern value" />
+                    <button class="add-pattern-btn" onclick="this.parentElement.parentElement.appendChild(this.parentElement.cloneNode(true))">Add Pattern</button>
+                </div>
+            </div>
+            <div class="case-consequent">
+                <label>Consequent:</label>
+                <input type="text" class="consequent-expr" placeholder="expression" />
+            </div>
+        `;
+        
+        // Add event listeners
+        const patternType = caseItem.querySelector('.pattern-type');
+        const patternValue = caseItem.querySelector('.pattern-value');
+        const consequentExpr = caseItem.querySelector('.consequent-expr');
+        
+        patternType.addEventListener('change', () => this.onWhenChange());
+        patternValue.addEventListener('input', () => this.onWhenChange());
+        consequentExpr.addEventListener('input', () => this.onWhenChange());
+        
+        this.whenEditor.cases.appendChild(caseItem);
+        this.onWhenChange();
+    }
+    
+    onWhenChange() {
+        // Don't notify changes during silent updates
+        if (this.silentUpdate) {
+            return;
+        }
+        
+        const changes = [{
+            type: 'when_update',
+            discriminants: this.getWhenDiscriminants(),
+            cases: this.getWhenCases()
+        }];
+        
+        this.notifyChanges(changes);
+    }
+    
+    getWhenDiscriminants() {
+        const discriminants = [];
+        const discriminantItems = this.whenEditor.discriminants.querySelectorAll('.discriminant-expr');
+        
+        discriminantItems.forEach(item => {
+            const value = item.value.trim();
+            if (value) {
+                discriminants.push(value);
+            }
+        });
+        
+        return discriminants;
+    }
+    
+    getWhenCases() {
+        const cases = [];
+        const caseItems = this.whenEditor.cases.querySelectorAll('.case-item');
+        
+        caseItems.forEach(item => {
+            const patterns = [];
+            const patternItems = item.querySelectorAll('.pattern-item');
+            
+            patternItems.forEach(patternItem => {
+                const type = patternItem.querySelector('.pattern-type').value;
+                const value = patternItem.querySelector('.pattern-value').value.trim();
+                
+                if (value) {
+                    patterns.push({ type, value });
+                }
+            });
+            
+            const consequent = item.querySelector('.consequent-expr').value.trim();
+            
+            if (patterns.length > 0 && consequent) {
+                cases.push({ patterns, consequent });
+            }
+        });
+        
+        return cases;
+    }
+    
+    // With Editor Methods
+    
+    addWithEntry() {
+        const entryItem = document.createElement('div');
+        entryItem.className = 'entry-item';
+        entryItem.innerHTML = `
+            <div class="entry-header">
+                <h4>Entry</h4>
+                <button class="remove-entry-btn" onclick="this.closest('.entry-item').remove()">Remove</button>
+            </div>
+            <div class="entry-content">
+                <div class="form-group">
+                    <label>Type:</label>
+                    <select class="entry-type-selector">
+                        <option value="assignment">Assignment</option>
+                        <option value="type-decl">Type Declaration</option>
+                    </select>
+                </div>
+                <div class="form-group">
+                    <label>Name:</label>
+                    <input type="text" class="entry-name" placeholder="variableName" />
+                </div>
+                <div class="form-group entry-value-group">
+                    <label>Value:</label>
+                    <input type="text" class="entry-value" placeholder="value or type" />
+                </div>
+            </div>
+        `;
+        
+        // Add event listeners
+        const typeSelector = entryItem.querySelector('.entry-type-selector');
+        const nameInput = entryItem.querySelector('.entry-name');
+        const valueInput = entryItem.querySelector('.entry-value');
+        
+        typeSelector.addEventListener('change', () => this.onWithChange());
+        nameInput.addEventListener('input', () => this.onWithChange());
+        valueInput.addEventListener('input', () => this.onWithChange());
+        
+        this.withEditor.entries.appendChild(entryItem);
+        this.onWithChange();
+    }
+    
+    onWithChange() {
+        // Don't notify changes during silent updates
+        if (this.silentUpdate) {
+            return;
+        }
+        
+        const changes = [{
+            type: 'with_update',
+            recursive: this.withEditor.recursive.checked,
+            entries: this.getWithEntries(),
+            body: this.getWithBody()
+        }];
+        
+        this.notifyChanges(changes);
+    }
+    
+    getWithEntries() {
+        const entries = [];
+        const entryItems = this.withEditor.entries.querySelectorAll('.entry-item');
+        
+        entryItems.forEach(item => {
+            const type = item.querySelector('.entry-type-selector').value;
+            const name = item.querySelector('.entry-name').value.trim();
+            const value = item.querySelector('.entry-value').value.trim();
+            
+            if (name && value) {
+                entries.push({ type, name, value });
+            }
+        });
+        
+        return entries;
+    }
+    
+    getWithBody() {
+        // For now, return a simple expression
+        // In the future, this will be a more sophisticated expression builder
+        return 'expression';
+    }
+    
+    // AST Integration Methods
+    
+    updateFromAST(ast, silent = false) {
+        this.currentAST = ast;
+        
+        // If this is a silent update, don't trigger change notifications
+        if (silent) {
+            this.silentUpdate = true;
+        }
+        
+        // Find the first function declaration to populate the function editor
+        if (ast && ast.body) {
+            const firstFunction = ast.body.find(node => node.type === 'FunctionDeclaration');
+            if (firstFunction) {
+                this.populateFunctionEditor(firstFunction);
+            }
+            
+            // Find when expressions and with headers in function bodies
+            this.populateWhenAndWithEditors(ast);
+        }
+        
+        // Reset silent flag
+        if (silent) {
+            this.silentUpdate = false;
+        }
+    }
+    
+    populateFunctionEditor(functionNode) {
+        if (!this.functionEditor.name) return;
+        
+        this.functionEditor.name.value = functionNode.name || '';
+        
+        // Clear existing parameters
+        this.functionEditor.params.innerHTML = '';
+        
+        // Add parameters
+        if (functionNode.params) {
+            functionNode.params.forEach(param => {
+                this.addFunctionParameter();
+                const lastParam = this.functionEditor.params.lastElementChild;
+                if (lastParam) {
+                    const nameInput = lastParam.querySelector('.param-name');
+                    const typeSelect = lastParam.querySelector('.param-type');
+                    
+                    if (typeof param === 'string') {
+                        nameInput.value = param;
+                    } else if (param.name) {
+                        nameInput.value = param.name;
+                        typeSelect.value = param.type || '';
+                    } else if (param.value) {
+                        // Handle case where param might be an Identifier node
+                        nameInput.value = param.value || '';
+                    }
+                }
+            });
+        }
+        
+        // Set return type
+        if (this.functionEditor.returnType) {
+            this.functionEditor.returnType.value = functionNode.returnType || '';
+        }
+    }
+    
+    populateWhenAndWithEditors(ast) {
+        // This is a simplified implementation
+        // In the future, this will properly parse and populate when expressions and with headers
+        console.log('Populating when and with editors from AST:', ast);
+    }
+    
+    populateWhenEditor(whenNode) {
+        if (!this.whenEditor.discriminants) return;
+        
+        // Clear existing content
+        this.whenEditor.discriminants.innerHTML = '';
+        this.whenEditor.cases.innerHTML = '';
+        
+        // TODO: Parse when expression and populate discriminants and cases
+        console.log('Populating when editor with:', whenNode);
+    }
+    
+    populateWithEditor(withNode) {
+        if (!this.withEditor.entries) return;
+        
+        // Clear existing content
+        this.withEditor.entries.innerHTML = '';
+        
+        // Set recursive flag
+        if (this.withEditor.recursive) {
+            this.withEditor.recursive.checked = withNode.recursive || false;
+        }
+        
+        // TODO: Parse with header and populate entries
+        console.log('Populating with editor with:', withNode);
+    }
+    
+    // Change Notification
+    
+    onChange(callback) {
+        this.changeCallbacks.push(callback);
+    }
+    
+    notifyChanges(changes) {
+        this.changeCallbacks.forEach(callback => {
+            try {
+                callback(changes);
+            } catch (error) {
+                console.error('Error in change callback:', error);
+            }
+        });
+    }
+    
+    // Utility Methods
+    
+    clearEditors() {
+        // Clear function editor
+        if (this.functionEditor.name) this.functionEditor.name.value = '';
+        if (this.functionEditor.params) this.functionEditor.params.innerHTML = '';
+        if (this.functionEditor.returnType) this.functionEditor.returnType.value = '';
+        
+        // Clear when editor
+        if (this.whenEditor.discriminants) this.whenEditor.discriminants.innerHTML = '';
+        if (this.whenEditor.cases) this.whenEditor.cases.innerHTML = '';
+        
+        // Clear with editor
+        if (this.withEditor.entries) this.withEditor.entries.innerHTML = '';
+        if (this.withEditor.recursive) this.withEditor.recursive.checked = false;
+    }
+    
+    getCurrentAST() {
+        return this.currentAST;
+    }
+}
diff --git a/js/baba-yaga/web/editor/js/tree-sitter-baba-yaga.js b/js/baba-yaga/web/editor/js/tree-sitter-baba-yaga.js
new file mode 100644
index 0000000..8a2757d
--- /dev/null
+++ b/js/baba-yaga/web/editor/js/tree-sitter-baba-yaga.js
@@ -0,0 +1,79 @@
+/**
+ * Tree-sitter Baba Yaga Grammar (Placeholder)
+ * 
+ * This is a placeholder file that will be replaced with the actual tree-sitter grammar
+ * once we develop it. For now, it provides a basic structure that the editor can work with.
+ * 
+ * The actual grammar will be generated from a .js file using tree-sitter-cli
+ */
+
+// Placeholder grammar - this will be replaced with the actual compiled grammar
+console.log('Tree-sitter Baba Yaga grammar placeholder loaded');
+console.log('This will be replaced with the actual grammar file');
+
+// For now, we'll use basic parsing in the editor
+// The actual tree-sitter integration will happen when we:
+// 1. Create the grammar file (baba-yaga.js)
+// 2. Compile it to WASM
+// 3. Load it in the editor
+
+// Example of what the actual grammar might look like:
+/*
+module.exports = grammar({
+  name: 'baba_yaga',
+  
+  rules: {
+    program: $ => repeat($.statement),
+    
+    statement: $ => choice(
+      $.type_declaration,
+      $.variable_declaration,
+      $.function_declaration,
+      $.expression_statement
+    ),
+    
+    function_declaration: $ => seq(
+      field('name', $.identifier),
+      ':',
+      choice(
+        $.typed_function_signature,
+        $.untyped_function_signature
+      ),
+      '->',
+      field('body', $.expression)
+    ),
+    
+    typed_function_signature: $ => seq(
+      '(',
+      commaSep($.typed_parameter),
+      ')',
+      optional(seq('->', $.type_annotation))
+    ),
+    
+    when_expression: $ => seq(
+      'when',
+      field('discriminants', commaSep($.expression)),
+      'is',
+      repeat($.when_case)
+    ),
+    
+    with_header: $ => seq(
+      'with',
+      optional('rec'),
+      '(',
+      repeat($.with_entry),
+      ')',
+      '->',
+      field('body', $.expression)
+    )
+  }
+});
+*/
+
+// Export a placeholder object so the editor doesn't crash
+if (typeof module !== 'undefined' && module.exports) {
+    module.exports = {
+        name: 'baba_yaga_placeholder',
+        rules: {}
+    };
+}
diff --git a/js/baba-yaga/web/editor/structural.html b/js/baba-yaga/web/editor/structural.html
new file mode 100644
index 0000000..169e696
--- /dev/null
+++ b/js/baba-yaga/web/editor/structural.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Baba Yaga Structural Editor - Advanced AST Editing</title>
+    <link rel="stylesheet" href="styles.css">
+    <!-- CodeMirror for text editing -->
+    <link rel="stylesheet" href="../../node_modules/codemirror/lib/codemirror.css">
+    <link rel="stylesheet" href="../../node_modules/codemirror/theme/monokai.css">
+    <script src="../../node_modules/codemirror/lib/codemirror.js"></script>
+    <script src="../../node_modules/codemirror/addon/edit/closebrackets.js"></script>
+    <script src="../../node_modules/codemirror/addon/edit/matchbrackets.js"></script>
+    <script src="../../node_modules/codemirror/addon/fold/foldcode.js"></script>
+    <script src="../../node_modules/codemirror/addon/fold/foldgutter.js"></script>
+    <script src="../../node_modules/codemirror/addon/fold/brace-fold.js"></script>
+    <script src="../../node_modules/codemirror/addon/fold/indent-fold.js"></script>
+    <!-- Baba Yaga Language Components -->
+    <script type="module">
+        // Import Baba Yaga components and make them globally available
+        import { createLexer, tokenTypes } from '../../lexer.js';
+        import { createParser } from '../../parser.js';
+        import { createInterpreter } from '../../interpreter.js';
+        
+        // Make them globally available
+        window.createLexer = createLexer;
+        window.createParser = createParser;
+        window.createInterpreter = createInterpreter;
+        window.tokenTypes = tokenTypes;
+        
+        console.log('Baba Yaga modules loaded and made globally available');
+    </script>
+    <!-- Baba Yaga Language Mode - Load after CodeMirror -->
+    <script src="js/baba-yaga-mode.js"></script>
+    <!-- Tree-sitter for parsing (optional for now) -->
+    <script src="https://unpkg.com/tree-sitter@0.20.6/dist/tree-sitter.js"></script>
+</head>
+<body>
+    <div class="editor-container">
+        <!-- Header -->
+        <header class="editor-header">
+            <h1>Baba Yaga Structural Editor</h1>
+            <div class="header-controls">
+                <button id="parse-btn">Parse</button>
+                <button id="format-btn">Format</button>
+                <button id="run-btn">Run</button>
+                <a href="index.html" style="text-decoration: none; display: inline-block; background-color: #8b5cf6; color: white; padding: 0.5rem 1rem; border-radius: 4px; cursor: pointer; font-size: 0.9rem; transition: background-color 0.2s;" onmouseover="this.style.backgroundColor='#7c3aed'" onmouseout="this.style.backgroundColor='#8b5cf6'">▶ Code Runner</a>
+            </div>
+        </header>
+
+        <!-- Main editor area -->
+        <div class="editor-main">
+            <!-- Top row: Code editor and AST tree view side by side -->
+            <div class="top-row">
+                <!-- Code editor (50% width) -->
+                <div class="code-editor-panel">
+                    <h3>Code Editor <span id="parse-status" class="parse-status"></span><button id="retry-syntax-btn" class="retry-btn" title="Retry loading syntax highlighting">🔄</button></h3>
+                    <div class="code-editor-container">
+                        <textarea id="code-editor" placeholder="Enter your Baba Yaga code here..."></textarea>
+                    </div>
+                </div>
+
+                <!-- AST Tree View/Editor (50% width) -->
+                <div class="ast-editor-panel">
+                    <h3>AST Tree Editor <button id="add-function-btn" class="add-btn">+ Function</button><button id="add-when-btn" class="add-btn">+ When</button><button id="add-with-btn" class="add-btn">+ With</button></h3>
+                    <div class="tree-editor-container">
+                        <div id="tree-view"></div>
+                    </div>
+                </div>
+            </div>
+
+            <!-- Bottom row: Output panel -->
+            <div class="output-panel">
+                <h3>Output</h3>
+                <div class="output-tabs">
+                    <button class="tab-btn active" data-tab="output">Output</button>
+                    <button class="tab-btn" data-tab="errors">Errors</button>
+                    <button class="tab-btn" data-tab="ast-json">AST JSON</button>
+                </div>
+                <div class="output-content">
+                    <div id="output-tab" class="tab-pane active">
+                        <pre id="output-text"></pre>
+                    </div>
+                    <div id="errors-tab" class="tab-pane">
+                        <pre id="errors-text"></pre>
+                    </div>
+                    <div id="ast-json-tab" class="tab-pane">
+                        <pre id="ast-json-text"></pre>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!-- Scripts -->
+    <script src="js/tree-sitter-baba-yaga.js"></script>
+    <script src="js/editor.js"></script>
+    <script src="js/ast-synchronizer.js"></script>
+    <script src="js/main.js"></script>
+</body>
+</html>
diff --git a/js/baba-yaga/web/editor/styles.css b/js/baba-yaga/web/editor/styles.css
new file mode 100644
index 0000000..51983b9
--- /dev/null
+++ b/js/baba-yaga/web/editor/styles.css
@@ -0,0 +1,755 @@
+/* Reset and base styles */
+* {
+    margin: 0;
+    padding: 0;
+    box-sizing: border-box;
+}
+
+body {
+    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+    background-color: #1e1e1e;
+    color: #d4d4d4;
+    line-height: 1.6;
+}
+
+/* Editor container */
+.editor-container {
+    display: flex;
+    flex-direction: column;
+    height: 100vh;
+    overflow: hidden;
+}
+
+/* Header */
+.editor-header {
+    background-color: #2d2d30;
+    border-bottom: 1px solid #3e3e42;
+    padding: 1rem;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+}
+
+.editor-header h1 {
+    color: #569cd6;
+    font-size: 1.5rem;
+    font-weight: 600;
+}
+
+.header-controls {
+    display: flex;
+    gap: 0.5rem;
+}
+
+.header-controls button {
+    background-color: #007acc;
+    color: white;
+    border: none;
+    padding: 0.5rem 1rem;
+    border-radius: 4px;
+    cursor: pointer;
+    font-size: 0.9rem;
+    transition: background-color 0.2s;
+}
+
+.header-controls button:hover {
+    background-color: #005a9e;
+}
+
+/* Main editor area */
+.editor-main {
+    display: flex;
+    flex-direction: column;
+    flex: 1;
+    overflow: hidden;
+}
+
+/* Top row: Code editor and AST tree view side by side */
+.top-row {
+    display: flex;
+    flex: 1;
+    overflow: hidden;
+}
+
+/* Code editor panel (50% width) */
+.code-editor-panel {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    border-right: 1px solid #3e3e42;
+    background-color: #1e1e1e;
+}
+
+.code-editor-panel h3 {
+    padding: 1rem;
+    background-color: #2d2d30;
+    border-bottom: 1px solid #3e3e42;
+    color: #d4d4d4;
+}
+
+.code-editor-container {
+    flex: 1;
+    overflow: hidden;
+    display: flex;
+    flex-direction: column;
+    min-height: 0; /* Important for flexbox to work properly */
+}
+
+#code-editor {
+    width: 100%;
+    height: 100%;
+    border: none;
+    outline: none;
+    background-color: #1e1e1e;
+    color: #d4d4d4;
+    font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
+    font-size: 14px;
+    line-height: 1.5;
+    padding: 1rem;
+    resize: none;
+}
+
+/* CodeMirror editor height fixes */
+.CodeMirror {
+    height: 100% !important;
+    min-height: 300px;
+    flex: 1;
+}
+
+.CodeMirror-scroll {
+    min-height: 100%;
+}
+
+
+
+/* AST Tree Editor panel (50% width) */
+.ast-editor-panel {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    background-color: #252526;
+    border-left: 1px solid #3e3e42;
+}
+
+.ast-editor-panel h3 {
+    padding: 1rem;
+    background-color: #2d2d30;
+    border-bottom: 1px solid #3e3e42;
+    color: #d4d4d4;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+}
+
+.tree-editor-container {
+    flex: 1;
+    overflow: auto;
+    padding: 1rem;
+}
+
+/* Bottom row: Output panel */
+.output-panel {
+    height: 200px;
+    display: flex;
+    flex-direction: column;
+    background-color: #1e1e1e;
+    border-top: 1px solid #3e3e42;
+}
+
+/* Tabs */
+.structural-tabs {
+    display: flex;
+    background-color: #2d2d30;
+    border-bottom: 1px solid #3e3e42;
+}
+
+.tab-btn {
+    background-color: transparent;
+    color: #d4d4d4;
+    border: none;
+    padding: 0.75rem 1rem;
+    cursor: pointer;
+    border-bottom: 2px solid transparent;
+    transition: all 0.2s;
+}
+
+.tab-btn:hover {
+    background-color: #3e3e42;
+}
+
+.tab-btn.active {
+    background-color: #007acc;
+    color: white;
+    border-bottom-color: #007acc;
+}
+
+/* Tab content */
+.tab-content {
+    flex: 1;
+    overflow: auto;
+    padding: 1rem;
+}
+
+.tab-pane {
+    display: none;
+}
+
+.tab-pane.active {
+    display: block;
+}
+
+/* Tree view */
+.tree-view-container {
+    height: 100%;
+    overflow: auto;
+}
+
+#tree-view {
+    font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
+    font-size: 12px;
+    line-height: 1.4;
+}
+
+.tree-node {
+    margin: 2px 0;
+    padding: 2px 0;
+}
+
+.tree-node-content {
+    display: flex;
+    align-items: center;
+    cursor: pointer;
+    padding: 2px 4px;
+    border-radius: 3px;
+    transition: background-color 0.2s;
+}
+
+.tree-node-content:hover {
+    background-color: #3e3e42;
+}
+
+.tree-node-content.clickable {
+    cursor: pointer;
+}
+
+.tree-node.selected .tree-node-content {
+    background-color: #007acc;
+    color: white;
+}
+
+.tree-node.selected .tree-node-type {
+    color: white;
+}
+
+.tree-node.selected .tree-node-value {
+    color: white;
+}
+
+.tree-node-toggle {
+    margin-right: 8px;
+    color: #569cd6;
+    font-weight: bold;
+    width: 16px;
+    text-align: center;
+}
+
+.tree-node-type {
+    color: #4ec9b0;
+    margin-right: 8px;
+    font-weight: 600;
+}
+
+.tree-node-value {
+    color: #d4d4d4;
+}
+
+.tree-node-children {
+    margin-left: 20px;
+    border-left: 1px solid #3e3e42;
+    padding-left: 10px;
+}
+
+/* Form styles */
+.form-group {
+    margin-bottom: 1rem;
+}
+
+.form-group label {
+    display: block;
+    margin-bottom: 0.5rem;
+    color: #d4d4d4;
+    font-weight: 500;
+}
+
+.form-group input,
+.form-group select {
+    width: 100%;
+    padding: 0.5rem;
+    border: 1px solid #3e3e42;
+    border-radius: 4px;
+    background-color: #1e1e1e;
+    color: #d4d4d4;
+    font-size: 14px;
+}
+
+.form-group input:focus,
+.form-group select:focus {
+    outline: none;
+    border-color: #007acc;
+    box-shadow: 0 0 0 2px rgba(0, 122, 204, 0.2);
+}
+
+/* Parameter list */
+.parameter-list {
+    margin-bottom: 0.5rem;
+}
+
+.parameter-item {
+    display: flex;
+    gap: 0.5rem;
+    margin-bottom: 0.5rem;
+    align-items: center;
+}
+
+.parameter-item input {
+    flex: 1;
+}
+
+.parameter-item select {
+    width: 120px;
+}
+
+.remove-param-btn {
+    background-color: #d73a49;
+    color: white;
+    border: none;
+    padding: 0.25rem 0.5rem;
+    border-radius: 3px;
+    cursor: pointer;
+    font-size: 12px;
+}
+
+.remove-param-btn:hover {
+    background-color: #b31d28;
+}
+
+/* Expression builder */
+.expression-builder {
+    border: 1px solid #3e3e42;
+    border-radius: 4px;
+    padding: 1rem;
+    background-color: #1e1e1e;
+    min-height: 100px;
+}
+
+.expression-item {
+    display: flex;
+    gap: 0.5rem;
+    margin-bottom: 0.5rem;
+    align-items: center;
+}
+
+.expression-type-selector {
+    width: 120px;
+}
+
+.expression-value {
+    flex: 1;
+}
+
+/* When expression editor */
+.when-editor {
+    height: 100%;
+    overflow: auto;
+}
+
+.expression-list,
+.case-list {
+    margin-bottom: 1rem;
+}
+
+.case-item {
+    border: 1px solid #3e3e42;
+    border-radius: 4px;
+    padding: 1rem;
+    margin-bottom: 1rem;
+    background-color: #1e1e1e;
+}
+
+.case-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 1rem;
+}
+
+.case-patterns {
+    margin-bottom: 1rem;
+}
+
+.pattern-item {
+    display: flex;
+    gap: 0.5rem;
+    margin-bottom: 0.5rem;
+    align-items: center;
+}
+
+.remove-case-btn {
+    background-color: #d73a49;
+    color: white;
+    border: none;
+    padding: 0.25rem 0.5rem;
+    border-radius: 3px;
+    cursor: pointer;
+    font-size: 12px;
+}
+
+/* With header editor */
+.with-editor {
+    height: 100%;
+    overflow: auto;
+}
+
+.entry-list {
+    margin-bottom: 1rem;
+}
+
+.entry-item {
+    border: 1px solid #3e3e42;
+    border-radius: 4px;
+    padding: 1rem;
+    margin-bottom: 1rem;
+    background-color: #1e1e1e;
+}
+
+.entry-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 1rem;
+}
+
+.entry-type-selector {
+    width: 120px;
+}
+
+.entry-name {
+    flex: 1;
+    margin-right: 0.5rem;
+}
+
+.remove-entry-btn {
+    background-color: #d73a49;
+    color: white;
+    border: none;
+    padding: 0.25rem 0.5rem;
+    border-radius: 3px;
+    cursor: pointer;
+    font-size: 12px;
+}
+
+/* Output panel */
+.output-panel {
+    height: 200px;
+    background-color: #252526;
+    border-top: 1px solid #3e3e42;
+}
+
+.output-panel h3 {
+    padding: 1rem;
+    background-color: #2d2d30;
+    border-bottom: 1px solid #3e3e42;
+    color: #d4d4d4;
+}
+
+.output-tabs {
+    display: flex;
+    background-color: #2d2d30;
+    border-bottom: 1px solid #3e3e42;
+}
+
+.output-content {
+    flex: 1;
+    overflow: auto;
+    padding: 1rem;
+}
+
+.output-content pre {
+    font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
+    font-size: 12px;
+    line-height: 1.4;
+    color: #d4d4d4;
+    white-space: pre-wrap;
+    word-wrap: break-word;
+}
+
+/* Buttons */
+button {
+    background-color: #007acc;
+    color: white;
+    border: none;
+    padding: 0.5rem 1rem;
+    border-radius: 4px;
+    cursor: pointer;
+    font-size: 0.9rem;
+    transition: background-color 0.2s;
+}
+
+button:hover {
+    background-color: #005a9e;
+}
+
+button:disabled {
+    background-color: #3e3e42;
+    color: #6a6a6a;
+    cursor: not-allowed;
+}
+
+/* Utility classes */
+.hidden {
+    display: none !important;
+}
+
+.error {
+    color: #f14c4c;
+}
+
+.success {
+    color: #4ec9b0;
+}
+
+.warning {
+    color: #dcdcaa;
+}
+
+/* Responsive design */
+@media (max-width: 1200px) {
+    .top-row {
+        flex-direction: column;
+    }
+    
+    .code-editor-panel,
+    .ast-editor-panel {
+        flex: none;
+        height: 50%;
+    }
+}
+
+@media (max-width: 768px) {
+    .editor-header {
+        flex-direction: column;
+        gap: 1rem;
+        align-items: stretch;
+    }
+    
+    .header-controls {
+        justify-content: center;
+    }
+    
+    .structural-tabs {
+        flex-wrap: wrap;
+    }
+    
+    .tab-btn {
+        flex: 1;
+        min-width: 80px;
+    }
+}
+
+/* Parse status indicator */
+.parse-status {
+    font-size: 0.8rem;
+    font-weight: normal;
+    margin-left: 0.5rem;
+}
+
+.parse-status.parsing {
+    color: #dcdcaa;
+}
+
+.parse-status.parsed {
+    color: #4ec9b0;
+}
+
+.parse-status.error {
+    color: #f14c4c;
+}
+
+/* Baba Yaga Syntax Highlighting Enhancements */
+.CodeMirror {
+    font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
+    font-size: 14px;
+    line-height: 1.5;
+}
+
+/* Custom token colors for Baba Yaga - More specific selectors */
+.CodeMirror.cm-s-baba-yaga .cm-keyword,
+.cm-s-baba-yaga .cm-keyword {
+    color: #c586c0 !important; /* Purple for keywords */
+    font-weight: bold;
+}
+
+.CodeMirror.cm-s-baba-yaga .cm-type,
+.cm-s-baba-yaga .cm-type {
+    color: #4ec9b0 !important; /* Teal for types */
+    font-weight: bold;
+}
+
+.CodeMirror.cm-s-baba-yaga .cm-function,
+.cm-s-baba-yaga .cm-function {
+    color: #dcdcaa !important; /* Yellow for functions */
+    font-weight: bold;
+}
+
+.CodeMirror.cm-s-baba-yaga .cm-builtin,
+.cm-s-baba-yaga .cm-builtin {
+    color: #d7ba7d !important; /* Orange for builtins */
+}
+
+.CodeMirror.cm-s-baba-yaga .cm-operator,
+.cm-s-baba-yaga .cm-operator {
+    color: #d4d4d4 !important; /* White for operators */
+}
+
+.CodeMirror.cm-s-baba-yaga .cm-number,
+.cm-s-baba-yaga .cm-number {
+    color: #b5cea8 !important; /* Green for numbers */
+}
+
+.CodeMirror.cm-s-baba-yaga .cm-string,
+.cm-s-baba-yaga .cm-string {
+    color: #ce9178 !important; /* Red for strings */
+}
+
+.CodeMirror.cm-s-baba-yaga .cm-comment,
+.cm-s-baba-yaga .cm-comment {
+    color: #6a9955 !important; /* Green for comments */
+    font-style: italic;
+}
+
+.CodeMirror.cm-s-baba-yaga .cm-variable,
+.cm-s-baba-yaga .cm-variable {
+    color: #9cdcfe !important; /* Blue for variables */
+}
+
+/* Dark theme adjustments for better contrast */
+.cm-s-baba-yaga.CodeMirror {
+    background-color: #1e1e1e;
+    color: #d4d4d4;
+}
+
+.cm-s-baba-yaga .CodeMirror-gutters {
+    background-color: #2d2d30;
+    border-right: 1px solid #3e3e42;
+}
+
+.cm-s-baba-yaga .CodeMirror-linenumber {
+    color: #858585;
+}
+
+/* Focus state */
+.CodeMirror-focused .CodeMirror-cursor {
+    border-left: 2px solid #007acc;
+}
+
+/* Selection */
+.CodeMirror-selected {
+    background-color: #264f78 !important;
+}
+
+/* Active line highlighting */
+.CodeMirror-activeline-background {
+    background-color: #2d2d30;
+}
+
+/* Add buttons */
+.add-btn {
+    background-color: #007acc;
+    color: white;
+    border: none;
+    padding: 0.25rem 0.5rem;
+    margin-left: 0.5rem;
+    border-radius: 3px;
+    cursor: pointer;
+    font-size: 0.8rem;
+    transition: background-color 0.2s;
+}
+
+.add-btn:hover {
+    background-color: #005a9e;
+}
+
+/* Retry button */
+.retry-btn {
+    background-color: #6a9955;
+    color: white;
+    border: none;
+    padding: 0.25rem 0.5rem;
+    margin-left: 0.5rem;
+    border-radius: 3px;
+    cursor: pointer;
+    font-size: 0.8rem;
+    transition: background-color 0.2s;
+}
+
+.retry-btn:hover {
+    background-color: #4a7a35;
+}
+
+.retry-btn:active {
+    transform: scale(0.95);
+}
+
+/* Inline editing */
+.tree-node-editable {
+    cursor: pointer;
+    padding: 2px 4px;
+    border-radius: 3px;
+    transition: background-color 0.2s;
+}
+
+.tree-node-editable:hover {
+    background-color: #3e3e42;
+}
+
+.tree-node-editing {
+    background-color: #007acc;
+    color: white;
+}
+
+.tree-node-editing input {
+    background: transparent;
+    border: none;
+    color: white;
+    outline: none;
+    font-family: inherit;
+    font-size: inherit;
+    width: 100%;
+}
+
+.tree-node-actions {
+    display: inline-flex;
+    margin-left: 0.5rem;
+    gap: 0.25rem;
+}
+
+.tree-node-action-btn {
+    background-color: #3e3e42;
+    color: #d4d4d4;
+    border: none;
+    padding: 1px 4px;
+    border-radius: 2px;
+    cursor: pointer;
+    font-size: 0.7rem;
+    transition: background-color 0.2s;
+}
+
+.tree-node-action-btn:hover {
+    background-color: #007acc;
+    color: white;
+}
+
+.tree-node-action-btn.delete:hover {
+    background-color: #f14c4c;
+}
+
diff --git a/js/baba-yaga/web/editor/test-formatter.html b/js/baba-yaga/web/editor/test-formatter.html
new file mode 100644
index 0000000..616afe2
--- /dev/null
+++ b/js/baba-yaga/web/editor/test-formatter.html
@@ -0,0 +1,155 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Test Baba Yaga Formatter</title>
+    <style>
+        body {
+            font-family: monospace;
+            padding: 20px;
+            background: #1e1e1e;
+            color: #d4d4d4;
+        }
+        .test-section {
+            margin: 20px 0;
+            padding: 20px;
+            border: 1px solid #3e3e42;
+            border-radius: 8px;
+        }
+        .code-block {
+            background: #2d2d30;
+            padding: 10px;
+            border-radius: 4px;
+            white-space: pre-wrap;
+            margin: 10px 0;
+        }
+        .success { color: #4ec9b0; }
+        .error { color: #f14c4c; }
+        button {
+            background: #007acc;
+            color: white;
+            border: none;
+            padding: 10px 20px;
+            border-radius: 4px;
+            cursor: pointer;
+            margin: 10px 0;
+        }
+        button:hover {
+            background: #005a9e;
+        }
+    </style>
+</head>
+<body>
+    <h1>Baba Yaga Formatter Test</h1>
+    
+    <div class="test-section">
+        <h2>Test 1: Basic Function Formatting</h2>
+        <div class="code-block" id="input1">add:x y->x+y;</div>
+        <button onclick="testFormat1()">Format Test 1</button>
+        <div class="code-block" id="output1"></div>
+        <div id="result1"></div>
+    </div>
+
+    <div class="test-section">
+        <h2>Test 2: Complex Code Formatting</h2>
+        <div class="code-block" id="input2">factorial:n->when n is 0 then 1 1 then 1 _ then n*factorial(n-1);</div>
+        <button onclick="testFormat2()">Format Test 2</button>
+        <div class="code-block" id="output2"></div>
+        <div id="result2"></div>
+    </div>
+
+    <div class="test-section">
+        <h2>Test 3: Multiple Functions</h2>
+        <div class="code-block" id="input3">add:x y->x+y;
+multiply:x y->x*y;
+result:add 5 3;</div>
+        <button onclick="testFormat3()">Format Test 3</button>
+        <div class="code-block" id="output3"></div>
+        <div id="result3"></div>
+    </div>
+
+    <!-- Load Baba Yaga components -->
+    <script type="module">
+        import { createLexer, tokenTypes } from '../../lexer.js';
+        import { createParser } from '../../parser.js';
+        
+        // Make them globally available
+        window.createLexer = createLexer;
+        window.createParser = createParser;
+        window.tokenTypes = tokenTypes;
+        
+        console.log('Baba Yaga modules loaded');
+    </script>
+
+    <!-- Load formatter -->
+    <script src="js/formatter.js"></script>
+
+    <script>
+        function testFormat1() {
+            const input = document.getElementById('input1').textContent;
+            const output = document.getElementById('output1');
+            const result = document.getElementById('result1');
+            
+            try {
+                const formatter = new BabaYagaFormatter();
+                const formatted = formatter.format(input);
+                output.textContent = formatted;
+                result.innerHTML = '<span class="success">✓ Formatting successful!</span>';
+            } catch (error) {
+                output.textContent = 'Error: ' + error.message;
+                result.innerHTML = '<span class="error">✗ Formatting failed: ' + error.message + '</span>';
+            }
+        }
+
+        function testFormat2() {
+            const input = document.getElementById('input2').textContent;
+            const output = document.getElementById('output2');
+            const result = document.getElementById('result2');
+            
+            try {
+                const formatter = new BabaYagaFormatter();
+                const formatted = formatter.format(input);
+                output.textContent = formatted;
+                result.innerHTML = '<span class="success">✓ Formatting successful!</span>';
+            } catch (error) {
+                output.textContent = 'Error: ' + error.message;
+                result.innerHTML = '<span class="error">✗ Formatting failed: ' + error.message + '</span>';
+            }
+        }
+
+        function testFormat3() {
+            const input = document.getElementById('input3').textContent;
+            const output = document.getElementById('output3');
+            const result = document.getElementById('result3');
+            
+            try {
+                const formatter = new BabaYagaFormatter();
+                const formatted = formatter.format(input);
+                output.textContent = formatted;
+                result.innerHTML = '<span class="success">✓ Formatting successful!</span>';
+            } catch (error) {
+                output.textContent = 'Error: ' + error.message;
+                result.innerHTML = '<span class="error">✗ Formatting failed: ' + error.message + '</span>';
+            }
+        }
+
+        // Test formatter availability on load
+        window.addEventListener('load', () => {
+            setTimeout(() => {
+                if (typeof BabaYagaFormatter !== 'undefined') {
+                    console.log('✓ BabaYagaFormatter is available');
+                } else {
+                    console.error('✗ BabaYagaFormatter is not available');
+                }
+                
+                if (typeof createLexer !== 'undefined' && typeof createParser !== 'undefined') {
+                    console.log('✓ Baba Yaga language components are available');
+                } else {
+                    console.error('✗ Baba Yaga language components are not available');
+                }
+            }, 1000);
+        });
+    </script>
+</body>
+</html>
diff --git a/js/baba-yaga/web/editor/test-integration.html b/js/baba-yaga/web/editor/test-integration.html
new file mode 100644
index 0000000..356b8cd
--- /dev/null
+++ b/js/baba-yaga/web/editor/test-integration.html
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Baba Yaga Integration Test</title>
+</head>
+<body>
+    <h1>Baba Yaga Integration Test</h1>
+    
+    <div id="status">Loading...</div>
+    
+    <div id="test-results"></div>
+    
+    <!-- Baba Yaga Language Components -->
+    <script type="module">
+        // Import Baba Yaga components and make them globally available
+        import { createLexer, tokenTypes } from '../../lexer.js';
+        import { createParser } from '../../parser.js';
+        import { createInterpreter } from '../../interpreter.js';
+        
+        // Make them globally available
+        window.createLexer = createLexer;
+        window.createParser = createParser;
+        window.createInterpreter = createInterpreter;
+        window.tokenTypes = tokenTypes;
+        
+        console.log('Baba Yaga modules loaded and made globally available');
+    </script>
+    
+    <script type="module">
+        // Test the integration
+        async function testIntegration() {
+            const statusDiv = document.getElementById('status');
+            const resultsDiv = document.getElementById('test-results');
+            
+            try {
+                // Test 1: Check if modules are loaded
+                statusDiv.textContent = 'Testing module loading...';
+                
+                if (typeof createLexer === 'undefined') {
+                    throw new Error('createLexer not found');
+                }
+                if (typeof createParser === 'undefined') {
+                    throw new Error('createParser not found');
+                }
+                if (typeof createInterpreter === 'undefined') {
+                    throw new Error('createInterpreter not found');
+                }
+                
+                resultsDiv.innerHTML += '<p>✅ All modules loaded successfully</p>';
+                
+                // Test 2: Test lexer
+                statusDiv.textContent = 'Testing lexer...';
+                const testCode = 'add : x y -> x + y;';
+                const lexer = createLexer(testCode);
+                const tokens = lexer.allTokens();
+                
+                resultsDiv.innerHTML += `<p>✅ Lexer working: ${tokens.length} tokens generated</p>`;
+                
+                // Test 3: Test parser
+                statusDiv.textContent = 'Testing parser...';
+                const parser = createParser(tokens);
+                const ast = parser.parse();
+                
+                resultsDiv.innerHTML += `<p>✅ Parser working: AST generated with ${ast.body.length} statements</p>`;
+                
+                // Test 4: Test interpreter
+                statusDiv.textContent = 'Testing interpreter...';
+                const interpreter = createInterpreter(ast);
+                const result = interpreter.interpret();
+                
+                resultsDiv.innerHTML += `<p>✅ Interpreter working: Result = ${JSON.stringify(result)}</p>`;
+                
+                // Test 5: Test more complex code
+                statusDiv.textContent = 'Testing complex code...';
+                const complexCode = `
+factorial : n ->
+  when n is
+    0 then 1
+    _ then n * (factorial (n - 1));
+
+result : factorial 5;`;
+                
+                const complexLexer = createLexer(complexCode);
+                const complexTokens = complexLexer.allTokens();
+                const complexParser = createParser(complexTokens);
+                const complexAST = complexParser.parse();
+                const complexInterpreter = createInterpreter(complexAST);
+                const complexResult = complexInterpreter.interpret();
+                
+                resultsDiv.innerHTML += `<p>✅ Complex code working: Result = ${JSON.stringify(complexResult)}</p>`;
+                
+                statusDiv.textContent = 'All tests passed! 🎉';
+                statusDiv.style.color = 'green';
+                
+            } catch (error) {
+                statusDiv.textContent = 'Test failed! ❌';
+                statusDiv.style.color = 'red';
+                resultsDiv.innerHTML += `<p style="color: red;">❌ Error: ${error.message}</p>`;
+                console.error('Integration test failed:', error);
+            }
+        }
+        
+        // Run tests when page loads
+        document.addEventListener('DOMContentLoaded', testIntegration);
+    </script>
+</body>
+</html>
diff --git a/js/baba-yaga/web/index.html b/js/baba-yaga/web/index.html
new file mode 100644
index 0000000..fd20d11
--- /dev/null
+++ b/js/baba-yaga/web/index.html
@@ -0,0 +1,355 @@
+<!doctype html>
+<html lang="en">
+<head>
+  <meta charset="utf-8" />
+  <meta name="viewport" content="width=device-width, initial-scale=1" />
+  <title>Baba Yaga REPL</title>
+  <style>
+    body {
+      --color-bg: #f8f8ff;
+      --color-text: #222;
+      --color-main-bg: #fff;
+      --color-main-border: #222;
+      --color-shadow: #0001;
+      --color-label: #222;
+      --color-input-border: #222;
+      --color-button-bg: #222;
+      --color-button-text: #fff;
+      --color-button-disabled-bg: #888;
+      --color-result-border: #aaa;
+      --color-result-bg: #f6f6fa;
+      --color-error: #b30000;
+      --color-success: #006600;
+      --color-info: #0066cc;
+      --color-code-bg: #f0f0f0;
+      --color-code-border: #ccc;
+
+      font-family: system-ui, sans-serif;
+      background: var(--color-bg);
+      color: var(--color-text);
+      margin: 0;
+      padding: 0;
+      height: 100vh;
+      overflow: hidden;
+    }
+
+    * {
+      box-sizing: border-box;
+    }
+
+    /* Focus styles for accessibility */
+    *:focus {
+      outline: 2px solid var(--color-button-bg);
+      outline-offset: 2px;
+    }
+
+    /* Main layout */
+    .app {
+      display: flex;
+      flex-direction: column;
+      height: 100vh;
+    }
+
+    /* Chat container */
+    .chat-container {
+      flex: 1;
+      display: flex;
+      flex-direction: column;
+      overflow: hidden;
+      max-width: 100%;
+      margin: 0 auto;
+      width: 100%;
+    }
+
+    /* Messages area */
+    .messages {
+      flex: 1;
+      overflow-y: auto;
+      padding: 1rem;
+      background: var(--color-main-bg);
+    }
+
+    .message {
+      margin-bottom: 1rem;
+    }
+
+    .message-input {
+      background: var(--color-code-bg);
+      border: 1.5px solid var(--color-code-border);
+      border-radius: 4px;
+      padding: 0.8rem;
+      margin-bottom: 0.5rem;
+    }
+
+    .message-input .prompt {
+      color: var(--color-text);
+      font-family: monospace;
+      font-weight: bold;
+      font-size: 1em;
+      margin-bottom: 0.3em;
+    }
+
+    .message-input .code {
+      font-family: monospace;
+      font-size: 1.25em;
+      color: var(--color-text);
+      white-space: pre-wrap;
+      word-wrap: break-word;
+    }
+
+    .message-output {
+      background: var(--color-result-bg);
+      color: var(--color-text);
+      border: 1.75px solid var(--color-result-border);
+      border-radius: 4px;
+      padding: 0.8rem;
+      font-family: monospace;
+      font-size: 0.9em;
+      white-space: pre-wrap;
+      word-wrap: break-word;
+    }
+
+    .message-error {
+      background: #fff0f0;
+      color: var(--color-error);
+      border: 1.75px solid var(--color-error);
+      border-radius: 4px;
+      padding: 0.8rem;
+      font-family: monospace;
+      font-size: 0.9em;
+      white-space: pre-wrap;
+      word-wrap: break-word;
+    }
+
+    .message-info {
+      background: #f0f8ff;
+      color: var(--color-info);
+      border: 1.75px solid var(--color-info);
+      border-radius: 4px;
+      padding: 0.8rem;
+      font-size: 0.9em;
+    }
+
+    /* Input area */
+    .input-area {
+      background: var(--color-main-bg);
+      border-top: 2px solid var(--color-main-border);
+      padding: 1rem 1.5rem;
+      flex-shrink: 0;
+    }
+
+    .input-container {
+      display: flex;
+      gap: 0.5rem;
+      align-items: flex-end;
+      margin-bottom: 0.5rem;
+    }
+
+    .input-wrapper {
+      flex: 1;
+    }
+
+    .input-textarea {
+      width: 100%;
+      background: var(--color-code-bg);
+      color: var(--color-text);
+      border: 2px solid var(--color-input-border);
+      border-radius: 4px;
+      padding: 0.6em;
+      font-family: monospace;
+      font-size: 1.25em;
+      line-height: 1.4;
+      resize: none;
+      outline: none;
+      min-height: 44px;
+      max-height: 120px;
+      overflow-y: auto;
+    }
+
+    .input-textarea:focus {
+      border-color: var(--color-button-bg);
+    }
+
+    .send-button {
+      background: var(--color-button-bg);
+      color: var(--color-button-text);
+      border: none;
+      border-radius: 4px;
+      padding: 0.6em 1.2em;
+      font-weight: bold;
+      text-transform: uppercase;
+      cursor: pointer;
+      font-size: 0.9em;
+      min-height: 44px;
+      min-width: 44px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+    }
+
+    .send-button:hover {
+      opacity: 0.9;
+    }
+
+    .send-button:active {
+      transform: translateY(1px);
+    }
+
+    .send-button:disabled {
+      background: var(--color-button-disabled-bg);
+      cursor: not-allowed;
+    }
+
+    /* Controls */
+    .controls {
+      display: flex;
+      gap: 0.5rem;
+      flex-wrap: wrap;
+    }
+
+    .button {
+      background: var(--color-button-bg);
+      color: var(--color-button-text);
+      border: none;
+      border-radius: 4px;
+      padding: 0.6em 1.2em;
+      font-weight: bold;
+      text-transform: uppercase;
+      cursor: pointer;
+      font-size: 0.8em;
+      min-height: 44px;
+      text-decoration: none;
+      display: inline-flex;
+      align-items: center;
+      justify-content: center;
+    }
+
+    .button:hover {
+      opacity: 0.9;
+    }
+
+    .button:active {
+      transform: translateY(1px);
+    }
+
+    /* Mobile optimizations */
+    @media (max-width: 768px) {
+      .header {
+        padding: 0.8rem 1rem;
+      }
+
+      .header h1 {
+        font-size: 1.25rem;
+      }
+
+      .messages {
+        padding: 0.8rem;
+      }
+
+      .input-area {
+        padding: 0.8rem 1rem;
+      }
+
+      .controls {
+        flex-direction: column;
+      }
+
+      .button {
+        width: 100%;
+      }
+    }
+
+    /* Dark mode support */
+    @media (prefers-color-scheme: dark) {
+      body {
+        --color-bg: #0a0a0a;
+        --color-text: #ffffff;
+        --color-main-bg: #1a1a1a;
+        --color-main-border: #ffffff;
+        --color-shadow: #0003;
+        --color-label: #ffffff;
+        --color-input-border: #ffffff;
+        --color-button-bg: #ffffff;
+        --color-button-text: #000000;
+        --color-button-disabled-bg: #666666;
+        --color-result-border: #444444;
+        --color-result-bg: #2a2a2a;
+        --color-code-bg: #2a2a2a;
+        --color-code-border: #444444;
+      }
+    }
+
+    /* High contrast mode */
+    @media (prefers-contrast: high) {
+      body {
+        --color-bg: #000;
+        --color-text: #fff;
+        --color-main-bg: #000;
+        --color-main-border: #fff;
+        --color-button-bg: #fff;
+        --color-button-text: #000;
+      }
+    }
+
+    /* Reduced motion */
+    @media (prefers-reduced-motion: reduce) {
+      * {
+        animation-duration: 0.01ms !important;
+        animation-iteration-count: 1 !important;
+        transition-duration: 0.01ms !important;
+      }
+    }
+  </style>
+</head>
+<body>
+  
+  <div class="app">
+  
+    <main id="main" class="chat-container" role="main">
+      <div class="messages" id="messages" role="log" aria-live="polite" aria-label="REPL conversation"></div>
+      
+      <div class="input-area">
+        <div class="input-container">
+          <div class="input-wrapper">
+            <textarea 
+              class="input-textarea" 
+              id="input" 
+              placeholder="Enter Baba Yaga code..."
+              aria-label="Code input"
+              rows="1"
+            ></textarea>
+          </div>
+          <button 
+            class="send-button" 
+            id="send" 
+            type="button"
+            aria-label="Execute code"
+          >
+            Run
+          </button>
+        </div>
+
+        <div class="controls">
+          <button class="button" id="clear" type="button">
+            Clear
+          </button>
+          <button class="button" id="load" type="button">
+            Load
+          </button>
+          <button class="button" id="examples" type="button">
+            Examples
+          </button>
+          <button class="button" id="help" type="button">
+            Help
+          </button>
+        </div>
+        
+        <input id="fileInput" type="file" accept=".baba" style="display: none;" />
+      </div>
+    </main>
+  </div>
+
+  <script type="module" src="./app.js"></script>
+</body>
+</html>
+