about summary refs log tree commit diff stats
path: root/js/baba-yaga/scratch/docs/GAME-ENGINE.md
diff options
context:
space:
mode:
Diffstat (limited to 'js/baba-yaga/scratch/docs/GAME-ENGINE.md')
-rw-r--r--js/baba-yaga/scratch/docs/GAME-ENGINE.md1748
1 files changed, 1748 insertions, 0 deletions
diff --git a/js/baba-yaga/scratch/docs/GAME-ENGINE.md b/js/baba-yaga/scratch/docs/GAME-ENGINE.md
new file mode 100644
index 0000000..2844540
--- /dev/null
+++ b/js/baba-yaga/scratch/docs/GAME-ENGINE.md
@@ -0,0 +1,1748 @@
+## Baba Yaga Text Adventure Game Engine - Project Plan
+
+### Phase 1: Understanding Baba Yaga
+*(Completed)*
+
+*   **Reviewed Baba Yaga Language Features:**
+    *   Data Structures: Immutable lists and tables, `append`, `set`, `merge`, `shape`.
+    *   Functional Programming: Immutability, first-class functions, currying, partial application, higher-order functions (`map`, `filter`, `reduce`), typed functions, combinators.
+    *   Pattern Matching: `when` expressions (literals, wildcards, types, results, lists, tables).
+    *   Recursion and Composition: Simple, tail-recursive, mutual recursion, functional composition.
+    *   Types: Optional types, runtime type inference, validation, numeric lattices, `Result` type.
+*   **Analyzed Core Implementation:**
+    *   `interpreter.js`: Execution, scope, native functions (`io`, math, list/table ops), type validation, function calls (closures, partial application).
+    *   `runner.js`: Lexing, parsing, interpretation pipeline, error handling.
+
+### Phase 2: Game Engine Architecture Design
+*(In Progress)*
+
+*   **Goal:** To create a text adventure game engine using the Baba Yaga language, enabling users to implement games using only Baba Yaga. The games will be playable in the terminal or the browser, with identical core functionality (except for visual enhancements in the browser).
+
+*   **Core Components:**
+    *   **JavaScript Host Components:**
+        *   **Game Loop Manager:** Orchestrates the flow of the game.
+        *   **Input/Output Abstraction:** Leverages Baba Yaga's `io` functions (`io.in`, `io.listen`, `io.out`, `io.emit`) to handle player input and game output across different environments.
+        *   **Game State Management:** Implemented using the Elm Architecture (TEA) principles in JavaScript. Manages a serializable state object that represents the current game world, player status, available actions, and visual elements. Supports snapshotting, rewinding, and state restoration (save/load functionality).
+        *   **Command Parser/Input Handler:** Presents players with predefined lists of verbs and nouns for interaction. In the terminal, this will be a numbered list or a richer TUI interface. In the browser, this will be clickable links/buttons. These selections are passed to the Baba Yaga script via the IO abstraction.
+        *   **Rendering Abstraction:** Provides a unified way to render the game state, abstracting differences between terminal (TUI) and browser (HTML/CSS) output. Browser versions will support optional visual-novel style background images that can change based on game state.
+    *   **Baba Yaga Game Script (`.baba` files):**
+        *   Monolithic files initially, defining game logic, world, items, narrative, puzzles, and player interaction using Baba Yaga's features.
+        *   Will define and mutate the game state through function composition.
+        *   Will reference image assets in a structured directory alongside the `.baba` file for browser-based visual enhancements.
+
+*   **Integration & Execution:**
+    *   The JavaScript engine will use the existing Baba Yaga interpreter to execute game scripts.
+    *   Player selections from the JS host are passed as messages/inputs to the Baba Yaga interpreter via its `io` words.
+    *   Baba Yaga scripts, through function composition, will mutate the game state.
+    *   The JS engine will manage the serialization and deserialization of the full state object for saving/loading.
+
+*   **State Object (`Model`) Structure:**
+    *   `current_scene`: Represents the player's current location. This could be a scene ID or a detailed scene object.
+    *   `scenes`: A collection (e.g., map/dictionary) of all scenes in the game, mapping scene identifiers to scene objects. Each scene object will contain:
+        *   Description text.
+        *   Available actions and nouns relevant to the scene.
+        *   Connections to other scenes (e.g., mapping directions to scene identifiers).
+        *   Optional visual elements (e.g., background image paths) for browser rendering.
+    *   The entire state object will be serializable (e.g., to JSON) for persistence.
+
+*   **Example Implementation:**
+    *   Create a simple `example.baba` to demonstrate basic game loop, scene navigation, item interaction, and state saving/loading.
+
+### Phase 3: Detailed Technical Specifications
+
+#### 3.1 Core Data Structures and Types
+
+**Game State Model (Baba Yaga Table Structure):**
+```baba
+// Core game state structure - simplified and focused
+GameState : {
+  current_scene_id: String,
+  player: Player,
+  inventory: List,
+  flags: Table,
+  history: List,
+  messages: List  // Recent game messages for UI
+};
+
+// Player state
+Player : {
+  name: String,
+  health: Int,
+  max_health: Int,
+  location: String,
+  attributes: Table
+};
+
+// Scene definition - returned by scene functions
+Scene : {
+  id: String,
+  title: String,
+  description: String,
+  exits: Table,  // direction -> scene_id
+  items: List,   // item_ids
+  npcs: List,    // npc_ids
+  actions: List, // available action_ids
+  background: String, // optional image path
+  visited: Bool
+};
+
+// Action definition
+Action : {
+  id: String,
+  name: String,
+  description: String,
+  verbs: List,   // ["take", "pick up", "grab"]
+  nouns: List,   // ["key", "sword", "book"]
+  conditions: Function, // (state, args) -> Bool
+  effect: Function,     // (state, args) -> GameState
+  available: Function   // (state) -> Bool
+};
+
+// Item definition
+Item : {
+  id: String,
+  name: String,
+  description: String,
+  portable: Bool,
+  usable: Bool,
+  actions: List, // action_ids
+  properties: Table
+};
+```
+
+**Scene Management Architecture - State as Functions:**
+
+```baba
+// Scene functions that take game state and return scene data
+// This allows scenes to be dynamic and responsive to game state
+
+entrance_scene : state -> {
+  id: "entrance",
+  title: "Cave Entrance",
+  description: when state.flags.torch_lit is
+    true then "The cave entrance is illuminated by your torch, revealing ancient markings on the walls..."
+    false then "You stand at the entrance to a dark cave. The shadows seem to swallow all light...",
+  exits: when state.flags.cave_unlocked is
+    true then { "north": "main_cavern", "east": "side_tunnel" }
+    false then { "north": "main_cavern" },
+  items: when state.flags.torch_taken is
+    true then []
+    false then ["torch"],
+  npcs: when state.flags.old_man_met is
+    true then []
+    false then ["old_man"],
+  actions: ["take", "look", "move", "talk"],
+  background: when state.flags.torch_lit is
+    true then "cave_entrance_lit.jpg"
+    false then "cave_entrance_dark.jpg",
+  visited: state.flags.entrance_visited
+};
+
+main_cavern_scene : state -> {
+  id: "main_cavern",
+  title: "Main Cavern",
+  description: when state.flags.torch_lit is
+    true then "A vast cavern stretches before you, stalactites glistening in the torchlight..."
+    false then "Complete darkness. You can hear water dripping somewhere in the distance...",
+  exits: { "south": "entrance", "east": "treasure_room", "west": "chasm" },
+  items: when state.flags.sword_found is
+    true then []
+    false then ["ancient_sword"],
+  actions: ["take", "look", "move", "listen"],
+  background: "main_cavern.jpg",
+  visited: state.flags.main_cavern_visited
+};
+
+// Scene registry function
+scene_registry : scene_id ->
+  when scene_id is
+    "entrance" then entrance_scene
+    "main_cavern" then main_cavern_scene
+    "treasure_room" then treasure_room_scene
+    "side_tunnel" then side_tunnel_scene
+    "chasm" then chasm_scene
+    _ then error_scene;
+
+// Scene resolver - gets current scene data
+get_current_scene : state ->
+  (scene_registry state.current_scene_id) state;
+
+// Scene state management
+mark_scene_visited : state scene_id ->
+  { state with flags: set state.flags (scene_id .. "_visited") true };
+
+update_scene_flag : state scene_id flag_name value ->
+  { state with flags: set state.flags (scene_id .. "_" .. flag_name) value };
+```
+
+**Scene Composition Utilities:**
+
+```baba
+// Scene building blocks for composition
+base_scene : id title description -> {
+  id: id,
+  title: title,
+  description: description,
+  exits: {},
+  items: [],
+  npcs: [],
+  actions: ["look"],
+  background: "",
+  visited: false
+};
+
+with_exits : scene exits -> { scene with exits: exits };
+with_items : scene items -> { scene with items: items };
+with_npcs : scene npcs -> { scene with npcs: npcs };
+with_actions : scene actions -> { scene with actions: actions };
+with_background : scene bg -> { scene with background: bg };
+
+// Conditional scene modifiers
+with_conditional_exits : scene condition exits ->
+  when condition is
+    true then with_exits scene exits
+    false then scene;
+
+with_conditional_items : scene condition items ->
+  when condition is
+    true then with_items scene items
+    false then scene;
+
+// Example of composed scene
+simple_entrance : state ->
+  pipe
+    (base_scene "entrance" "Cave Entrance" "You stand at the entrance...")
+    (with_exits { "north": "main_cavern" })
+    (with_conditional_items (not state.flags.torch_taken) ["torch"])
+    (with_actions ["take", "look", "move"])
+    (with_background "cave_entrance.jpg");
+```
+
+#### 3.2 JavaScript Host API Interface
+
+**Game Engine Class Structure:**
+```javascript
+class BabaYagaGameEngine {
+  constructor(gameScript, options = {}) {
+    this.gameScript = gameScript;
+    this.interpreter = null;
+    this.currentState = null;
+    this.history = [];
+    this.maxHistory = options.maxHistory || 50;
+    this.assetPath = options.assetPath || './assets';
+    this.eventListeners = new Map();
+    this.memoizedScenes = new Map();
+    
+    // IO abstraction for Baba Yaga
+    this.host = {
+      io: {
+        out: this.handleOutput.bind(this),
+        in: this.handleInput.bind(this),
+        emit: this.handleEmit.bind(this),
+        listen: this.handleListen.bind(this)
+      }
+    };
+  }
+
+  // Core game loop methods
+  async initialize() { 
+    try {
+      // Initialize Baba Yaga interpreter
+      const result = await this.evaluateBabaYaga('init_game()');
+      if (result.ok) {
+        this.currentState = result.value;
+        this.pushToHistory(this.currentState);
+        return { ok: true, state: this.currentState };
+      } else {
+        throw new GameError('Failed to initialize game', 'runtime', result.error);
+      }
+    } catch (error) {
+      throw new GameError('Initialization failed', 'runtime', error);
+    }
+  }
+
+  async processCommand(verb, noun) {
+    try {
+      // Validate input
+      if (!verb || typeof verb !== 'string') {
+        throw new GameError('Invalid verb', 'input', { verb, noun });
+      }
+
+      // Process action through Baba Yaga
+      const actionCall = `process_action(${JSON.stringify(this.currentState)}, "${verb}", "${noun || ''}")`;
+      const result = await this.evaluateBabaYaga(actionCall);
+      
+      if (result.ok) {
+        const newState = result.value;
+        this.setState(newState);
+        this.pushToHistory(newState);
+        
+        // Mark scene as visited
+        const sceneCall = `mark_scene_visited(${JSON.stringify(newState)}, "${newState.current_scene_id}")`;
+        const sceneResult = await this.evaluateBabaYaga(sceneCall);
+        if (sceneResult.ok) {
+          this.setState(sceneResult.value);
+        }
+        
+        return { ok: true, state: this.currentState };
+      } else {
+        throw new GameError('Action processing failed', 'runtime', result.error);
+      }
+    } catch (error) {
+      throw new GameError('Command processing failed', 'runtime', error);
+    }
+  }
+
+  async saveGame(slot) {
+    try {
+      const saveCall = `save_game(${JSON.stringify(this.currentState)})`;
+      const result = await this.evaluateBabaYaga(saveCall);
+      
+      if (result.ok) {
+        const serializedState = result.value;
+        // Store in localStorage or file system
+        if (typeof localStorage !== 'undefined') {
+          localStorage.setItem(`baba_yaga_save_${slot}`, serializedState);
+        }
+        return { ok: true, slot };
+      } else {
+        throw new GameError('Save failed', 'runtime', result.error);
+      }
+    } catch (error) {
+      throw new GameError('Save operation failed', 'runtime', error);
+    }
+  }
+
+  async loadGame(slot) {
+    try {
+      let serializedState;
+      if (typeof localStorage !== 'undefined') {
+        serializedState = localStorage.getItem(`baba_yaga_save_${slot}`);
+      }
+      
+      if (!serializedState) {
+        throw new GameError('Save file not found', 'state', { slot });
+      }
+
+      const loadCall = `load_game("${serializedState}")`;
+      const result = await this.evaluateBabaYaga(loadCall);
+      
+      if (result.ok) {
+        this.setState(result.value);
+        this.pushToHistory(result.value);
+        return { ok: true, state: this.currentState };
+      } else {
+        throw new GameError('Load failed', 'runtime', result.error);
+      }
+    } catch (error) {
+      throw new GameError('Load operation failed', 'runtime', error);
+    }
+  }
+
+  async undo() {
+    if (this.history.length > 1) {
+      this.history.pop(); // Remove current state
+      const previousState = this.history[this.history.length - 1];
+      this.setState(previousState);
+      return { ok: true, state: this.currentState };
+    }
+    return { ok: false, error: 'No history to undo' };
+  }
+  
+  // State management
+  getCurrentState() { 
+    return this.currentState; 
+  }
+
+  setState(newState) { 
+    this.currentState = newState;
+    // Clear memoized scenes when state changes
+    this.memoizedScenes.clear();
+    // Emit state change event
+    this.emit('stateChanged', newState);
+  }
+
+  pushToHistory(state) { 
+    this.history.push(JSON.parse(JSON.stringify(state))); // Deep clone
+    if (this.history.length > this.maxHistory) {
+      this.history.shift();
+    }
+  }
+
+  // Baba Yaga evaluation
+  async evaluateBabaYaga(code) {
+    try {
+      // Combine game script with evaluation code
+      const fullCode = this.gameScript + '\n' + code;
+      const result = await evaluate(fullCode, this.host);
+      return result;
+    } catch (error) {
+      return { ok: false, error };
+    }
+  }
+
+  // Scene management
+  async getCurrentScene() {
+    if (!this.currentState) return null;
+    
+    // Check memoization
+    const memoKey = `${this.currentState.current_scene_id}_${JSON.stringify(this.currentState.flags)}`;
+    if (this.memoizedScenes.has(memoKey)) {
+      return this.memoizedScenes.get(memoKey);
+    }
+
+    try {
+      const sceneCall = `get_current_scene(${JSON.stringify(this.currentState)})`;
+      const result = await this.evaluateBabaYaga(sceneCall);
+      
+      if (result.ok) {
+        this.memoizedScenes.set(memoKey, result.value);
+        return result.value;
+      } else {
+        throw new GameError('Failed to get scene', 'runtime', result.error);
+      }
+    } catch (error) {
+      throw new GameError('Scene retrieval failed', 'runtime', error);
+    }
+  }
+
+  async getAvailableActions() {
+    try {
+      const actionsCall = `get_available_actions(${JSON.stringify(this.currentState)})`;
+      const result = await this.evaluateBabaYaga(actionsCall);
+      
+      if (result.ok) {
+        return result.value;
+      } else {
+        throw new GameError('Failed to get actions', 'runtime', result.error);
+      }
+    } catch (error) {
+      throw new GameError('Action retrieval failed', 'runtime', error);
+    }
+  }
+
+  // Event handling
+  handleOutput(...args) {
+    const message = args.map(arg => String(arg)).join(' ');
+    this.emit('output', message);
+  }
+
+  handleInput() {
+    // This would be implemented by the UI layer
+    return '';
+  }
+
+  handleEmit(topic, data) {
+    this.emit(topic, data);
+  }
+
+  handleListen(topic, handler) {
+    if (!this.eventListeners.has(topic)) {
+      this.eventListeners.set(topic, []);
+    }
+    this.eventListeners.get(topic).push(handler);
+    
+    // Return unsubscribe function
+    return () => {
+      const listeners = this.eventListeners.get(topic);
+      const index = listeners.indexOf(handler);
+      if (index > -1) {
+        listeners.splice(index, 1);
+      }
+    };
+  }
+
+  emit(event, data) {
+    const listeners = this.eventListeners.get(event) || [];
+    listeners.forEach(listener => {
+      try {
+        listener(data);
+      } catch (error) {
+        console.error('Event listener error:', error);
+      }
+    });
+  }
+
+  // Rendering
+  async render() { 
+    const scene = await this.getCurrentScene();
+    const actions = await this.getAvailableActions();
+    return { scene, actions, state: this.currentState };
+  }
+}
+
+// Game error class
+class GameError extends Error {
+  constructor(message, type, details) {
+    super(message);
+    this.name = 'GameError';
+    this.type = type; // 'parse', 'runtime', 'state', 'asset', 'input'
+    this.details = details;
+  }
+}
+```
+
+**Game Loop Implementation:**
+```javascript
+class GameLoop {
+  constructor(engine, interface) {
+    this.engine = engine;
+    this.interface = interface;
+    this.isRunning = false;
+    this.pendingInput = null;
+    this.inputResolver = null;
+  }
+
+  async start() {
+    this.isRunning = true;
+    
+    try {
+      // Initialize game
+      await this.engine.initialize();
+      
+      // Initial render
+      await this.render();
+      
+      // Start input loop
+      await this.inputLoop();
+    } catch (error) {
+      this.interface.handleError(error);
+    }
+  }
+
+  async inputLoop() {
+    while (this.isRunning) {
+      try {
+        // Wait for input
+        const input = await this.waitForInput();
+        
+        if (input.type === 'command') {
+          await this.processCommand(input.verb, input.noun);
+        } else if (input.type === 'system') {
+          await this.processSystemCommand(input.command);
+        }
+        
+        // Render updated state
+        await this.render();
+      } catch (error) {
+        this.interface.handleError(error);
+      }
+    }
+  }
+
+  async waitForInput() {
+    return new Promise((resolve) => {
+      this.inputResolver = resolve;
+    });
+  }
+
+  async processCommand(verb, noun) {
+    const result = await this.engine.processCommand(verb, noun);
+    if (!result.ok) {
+      throw new GameError('Command failed', 'runtime', result.error);
+    }
+  }
+
+  async processSystemCommand(command) {
+    switch (command) {
+      case 'save':
+        await this.engine.saveGame('auto');
+        break;
+      case 'load':
+        await this.engine.loadGame('auto');
+        break;
+      case 'undo':
+        await this.engine.undo();
+        break;
+      case 'quit':
+        this.isRunning = false;
+        break;
+      default:
+        throw new GameError(`Unknown system command: ${command}`, 'input');
+    }
+  }
+
+  async render() {
+    const renderData = await this.engine.render();
+    this.interface.render(renderData);
+  }
+
+  provideInput(input) {
+    if (this.inputResolver) {
+      this.inputResolver(input);
+      this.inputResolver = null;
+    }
+  }
+
+  stop() {
+    this.isRunning = false;
+  }
+}
+```
+
+**Terminal Interface:**
+```javascript
+class TerminalGameInterface {
+  constructor(engine) {
+    this.engine = engine;
+    this.gameLoop = new GameLoop(engine, this);
+    this.inputBuffer = '';
+    this.isInputMode = false;
+  }
+
+  async start() {
+    // Set up terminal input handling
+    process.stdin.setRawMode(true);
+    process.stdin.resume();
+    process.stdin.setEncoding('utf8');
+    
+    process.stdin.on('data', (key) => {
+      this.handleKeyPress(key);
+    });
+
+    // Start game loop
+    await this.gameLoop.start();
+  }
+
+  handleKeyPress(key) {
+    if (key === '\u0003') { // Ctrl+C
+      this.quit();
+      return;
+    }
+
+    if (this.isInputMode) {
+      if (key === '\r' || key === '\n') { // Enter
+        this.submitInput();
+      } else if (key === '\u007f') { // Backspace
+        this.inputBuffer = this.inputBuffer.slice(0, -1);
+        this.redrawInput();
+      } else {
+        this.inputBuffer += key;
+        this.redrawInput();
+      }
+    } else {
+      // Handle menu navigation
+      this.handleMenuKey(key);
+    }
+  }
+
+  async render(renderData) {
+    const { scene, actions, state } = renderData;
+    
+    // Clear screen
+    process.stdout.write('\x1B[2J\x1B[0f');
+    
+    // Render scene
+    this.renderScene(scene);
+    
+    // Render actions
+    this.renderActions(actions);
+    
+    // Render status
+    this.renderStatus(state);
+    
+    // Show input prompt
+    this.showInputPrompt();
+  }
+
+  renderScene(scene) {
+    console.log(`\n${scene.title}`);
+    console.log('='.repeat(scene.title.length));
+    console.log(scene.description);
+    
+    if (scene.items.length > 0) {
+      console.log('\nItems here:');
+      scene.items.forEach(item => console.log(`  - ${item}`));
+    }
+    
+    if (Object.keys(scene.exits).length > 0) {
+      console.log('\nExits:');
+      Object.entries(scene.exits).forEach(([direction, target]) => {
+        console.log(`  ${direction}: ${target}`);
+      });
+    }
+  }
+
+  renderActions(actions) {
+    console.log('\nAvailable actions:');
+    actions.forEach((action, index) => {
+      console.log(`  ${index + 1}. ${action}`);
+    });
+  }
+
+  renderStatus(state) {
+    console.log('\nStatus:');
+    console.log(`  Location: ${state.current_scene_id}`);
+    console.log(`  Health: ${state.player.health}/${state.player.max_health}`);
+    console.log(`  Inventory: ${state.inventory.length} items`);
+  }
+
+  showInputPrompt() {
+    console.log('\n> ');
+    this.isInputMode = true;
+  }
+
+  submitInput() {
+    const input = this.inputBuffer.trim();
+    this.inputBuffer = '';
+    this.isInputMode = false;
+    
+    if (input.startsWith('/')) {
+      this.gameLoop.provideInput({ type: 'system', command: input.slice(1) });
+    } else {
+      // Parse verb/noun from input
+      const parts = input.split(' ');
+      const verb = parts[0];
+      const noun = parts.slice(1).join(' ');
+      this.gameLoop.provideInput({ type: 'command', verb, noun });
+    }
+  }
+
+  redrawInput() {
+    process.stdout.write(`\r> ${this.inputBuffer}`);
+  }
+
+  handleError(error) {
+    console.error(`\nError: ${error.message}`);
+    if (error.details) {
+      console.error('Details:', error.details);
+    }
+  }
+
+  quit() {
+    process.exit(0);
+  }
+}
+```
+
+**Browser Interface:**
+```javascript
+class BrowserGameInterface {
+  constructor(engine, container) {
+    this.engine = engine;
+    this.container = container;
+    this.gameLoop = new GameLoop(engine, this);
+    this.actionButtons = new Map();
+    this.messageQueue = [];
+    
+    this.setupEventListeners();
+  }
+
+  setupEventListeners() {
+    // Listen for engine events
+    this.engine.on('output', (message) => {
+      this.addMessage(message, 'output');
+    });
+
+    this.engine.on('stateChanged', (state) => {
+      this.updateUI(state);
+    });
+  }
+
+  async start() {
+    await this.gameLoop.start();
+  }
+
+  async render(renderData) {
+    const { scene, actions, state } = renderData;
+    
+    // Clear container
+    this.container.innerHTML = '';
+    
+    // Render scene
+    this.renderScene(scene);
+    
+    // Render actions
+    this.renderActions(actions);
+    
+    // Render status
+    this.renderStatus(state);
+    
+    // Render messages
+    this.renderMessages();
+    
+    // Render controls
+    this.renderControls();
+  }
+
+  renderScene(scene) {
+    const sceneEl = document.createElement('div');
+    sceneEl.className = 'game-scene';
+    
+    // Background image
+    if (scene.background) {
+      sceneEl.style.backgroundImage = `url(${this.engine.assetPath}/images/${scene.background})`;
+    }
+    
+    // Scene content
+    const titleEl = document.createElement('h2');
+    titleEl.textContent = scene.title;
+    sceneEl.appendChild(titleEl);
+    
+    const descEl = document.createElement('p');
+    descEl.textContent = scene.description;
+    sceneEl.appendChild(descEl);
+    
+    // Items
+    if (scene.items.length > 0) {
+      const itemsEl = document.createElement('div');
+      itemsEl.className = 'scene-items';
+      itemsEl.innerHTML = '<h3>Items here:</h3>';
+      scene.items.forEach(item => {
+        const itemEl = document.createElement('div');
+        itemEl.textContent = `- ${item}`;
+        itemsEl.appendChild(itemEl);
+      });
+      sceneEl.appendChild(itemsEl);
+    }
+    
+    // Exits
+    if (Object.keys(scene.exits).length > 0) {
+      const exitsEl = document.createElement('div');
+      exitsEl.className = 'scene-exits';
+      exitsEl.innerHTML = '<h3>Exits:</h3>';
+      Object.entries(scene.exits).forEach(([direction, target]) => {
+        const exitEl = document.createElement('div');
+        exitEl.textContent = `${direction}: ${target}`;
+        exitsEl.appendChild(exitEl);
+      });
+      sceneEl.appendChild(exitsEl);
+    }
+    
+    this.container.appendChild(sceneEl);
+  }
+
+  renderActions(actions) {
+    const actionsEl = document.createElement('div');
+    actionsEl.className = 'game-actions';
+    
+    actionsEl.innerHTML = '<h3>Available actions:</h3>';
+    
+    actions.forEach((action, index) => {
+      const button = document.createElement('button');
+      button.textContent = action;
+      button.className = 'action-button';
+      button.onclick = () => this.handleAction(action);
+      actionsEl.appendChild(button);
+    });
+    
+    this.container.appendChild(actionsEl);
+  }
+
+  renderStatus(state) {
+    const statusEl = document.createElement('div');
+    statusEl.className = 'game-status';
+    
+    statusEl.innerHTML = `
+      <h3>Status:</h3>
+      <p>Location: ${state.current_scene_id}</p>
+      <p>Health: ${state.player.health}/${state.player.max_health}</p>
+      <p>Inventory: ${state.inventory.length} items</p>
+    `;
+    
+    this.container.appendChild(statusEl);
+  }
+
+  renderMessages() {
+    if (this.messageQueue.length > 0) {
+      const messagesEl = document.createElement('div');
+      messagesEl.className = 'game-messages';
+      
+      this.messageQueue.forEach(message => {
+        const messageEl = document.createElement('div');
+        messageEl.className = `message message-${message.type}`;
+        messageEl.textContent = message.text;
+        messagesEl.appendChild(messageEl);
+      });
+      
+      this.container.appendChild(messagesEl);
+      this.messageQueue = [];
+    }
+  }
+
+  renderControls() {
+    const controlsEl = document.createElement('div');
+    controlsEl.className = 'game-controls';
+    
+    const saveBtn = document.createElement('button');
+    saveBtn.textContent = 'Save';
+    saveBtn.onclick = () => this.gameLoop.provideInput({ type: 'system', command: 'save' });
+    
+    const loadBtn = document.createElement('button');
+    loadBtn.textContent = 'Load';
+    loadBtn.onclick = () => this.gameLoop.provideInput({ type: 'system', command: 'load' });
+    
+    const undoBtn = document.createElement('button');
+    undoBtn.textContent = 'Undo';
+    undoBtn.onclick = () => this.gameLoop.provideInput({ type: 'system', command: 'undo' });
+    
+    controlsEl.appendChild(saveBtn);
+    controlsEl.appendChild(loadBtn);
+    controlsEl.appendChild(undoBtn);
+    
+    this.container.appendChild(controlsEl);
+  }
+
+  handleAction(action) {
+    // Parse action into verb/noun
+    const parts = action.split(' ');
+    const verb = parts[0];
+    const noun = parts.slice(1).join(' ');
+    
+    this.gameLoop.provideInput({ type: 'command', verb, noun });
+  }
+
+  addMessage(text, type = 'output') {
+    this.messageQueue.push({ text, type });
+  }
+
+  updateUI(state) {
+    // Update any UI elements that depend on state
+    // This could include updating inventory display, health bars, etc.
+  }
+
+  handleError(error) {
+    this.addMessage(`Error: ${error.message}`, 'error');
+    if (error.details) {
+      console.error('Game error details:', error.details);
+    }
+  }
+}
+```
+
+#### 3.3 Baba Yaga Game Script API
+
+**Required Game Functions:**
+```baba
+// Game initialization
+init_game : () -> GameState;
+
+// Core game loop functions
+process_action : (state: GameState, verb: String, noun: String) -> GameState;
+get_available_actions : (state: GameState) -> List;
+render_scene : (state: GameState) -> String;
+
+// State management
+save_game : (state: GameState) -> String; // Returns serialized state
+load_game : (serialized: String) -> GameState;
+
+// Utility functions
+is_action_available : (state: GameState, action_id: String) -> Bool;
+get_item_by_id : (items: List, item_id: String) -> Maybe Item;
+get_scene_by_id : (scenes: Table, scene_id: String) -> Maybe Scene;
+```
+
+**Example Game Script Structure:**
+```baba
+// Game data definitions
+scenes : {
+  "entrance": {
+    id: "entrance",
+    title: "Cave Entrance",
+    description: "You stand at the entrance to a dark cave...",
+    exits: { "north": "main_cavern" },
+    items: ["torch"],
+    npcs: [],
+    actions: ["take", "look", "move"],
+    background: "cave_entrance.jpg",
+    visited: false
+  }
+};
+
+items : {
+  "torch": {
+    id: "torch",
+    name: "Wooden Torch",
+    description: "A simple wooden torch...",
+    portable: true,
+    usable: true,
+    actions: ["light", "extinguish"],
+    properties: { "lit": false }
+  }
+};
+
+// Game logic functions
+init_game : () -> {
+  current_scene: "entrance",
+  scenes: scenes,
+  player: {
+    name: "Adventurer",
+    health: 100,
+    max_health: 100,
+    location: "entrance",
+    attributes: { "strength": 10, "intelligence": 8 }
+  },
+  inventory: [],
+  flags: { "torch_lit": false },
+  history: []
+};
+
+process_action : state verb noun ->
+  when verb noun is
+    "take" "torch" then take_torch state
+    "move" "north" then move_north state
+    "look" _ then look_around state
+    _ _ then state; // Unknown action, return unchanged state
+
+take_torch : state ->
+  when is_item_in_scene state "torch" is
+    true then {
+      state with
+      inventory: append state.inventory ["torch"],
+      scenes: update_scene_items state.scenes state.current_scene (remove_item "torch")
+    }
+    false then state;
+
+move_north : state ->
+  when get_scene_exit state.current_scene "north" is
+    Just scene_id then {
+      state with
+      current_scene: scene_id,
+      player: { state.player with location: scene_id }
+    }
+    Nothing then state;
+```
+
+#### 3.4 File Structure and Asset Management
+
+**Project Structure:**
+```
+game-name/
+├── game.baba              # Main game script
+├── assets/                # Game assets
+│   ├── images/            # Background images
+│   │   ├── cave_entrance.jpg
+│   │   ├── main_cavern.jpg
+│   │   └── ...
+│   ├── sounds/           # Audio files (future)
+│   └── data/             # Additional game data
+├── saves/                # Save game files
+│   ├── save1.json
+│   ├── save2.json
+│   └── ...
+└── README.md             # Game documentation
+```
+
+**Asset Loading Strategy:**
+- Browser: Assets loaded via HTTP requests, cached for performance
+- Terminal: Asset paths stored but not loaded (text-only mode)
+- Fallback: Graceful degradation when assets missing
+
+#### 3.5 Integration Patterns and Usage Examples
+
+**Basic Game Setup:**
+```javascript
+// Browser usage
+import { BabaYagaGameEngine, BrowserGameInterface } from './game-engine.js';
+
+async function startGame() {
+  const gameScript = await fetch('./game.baba').then(r => r.text());
+  const engine = new BabaYagaGameEngine(gameScript, {
+    assetPath: './assets',
+    maxHistory: 100
+  });
+  
+  const container = document.getElementById('game-container');
+  const interface = new BrowserGameInterface(engine, container);
+  
+  await interface.start();
+}
+
+// Terminal usage
+import { BabaYagaGameEngine, TerminalGameInterface } from './game-engine.js';
+import { readFileSync } from 'fs';
+
+async function startTerminalGame() {
+  const gameScript = readFileSync('./game.baba', 'utf8');
+  const engine = new BabaYagaGameEngine(gameScript);
+  const interface = new TerminalGameInterface(engine);
+  
+  await interface.start();
+}
+```
+
+**Custom Game Interface:**
+```javascript
+class CustomGameInterface {
+  constructor(engine) {
+    this.engine = engine;
+    this.gameLoop = new GameLoop(engine, this);
+  }
+
+  async render(renderData) {
+    const { scene, actions, state } = renderData;
+    
+    // Custom rendering logic
+    this.updateSceneDisplay(scene);
+    this.updateActionButtons(actions);
+    this.updateStatusBar(state);
+  }
+
+  updateSceneDisplay(scene) {
+    // Custom scene rendering
+    const sceneEl = document.getElementById('scene');
+    sceneEl.innerHTML = `
+      <h1>${scene.title}</h1>
+      <p>${scene.description}</p>
+      ${this.renderItems(scene.items)}
+      ${this.renderExits(scene.exits)}
+    `;
+  }
+
+  updateActionButtons(actions) {
+    const actionsEl = document.getElementById('actions');
+    actionsEl.innerHTML = actions.map(action => 
+      `<button onclick="handleAction('${action}')">${action}</button>`
+    ).join('');
+  }
+
+  updateStatusBar(state) {
+    const statusEl = document.getElementById('status');
+    statusEl.innerHTML = `
+      Location: ${state.current_scene_id} | 
+      Health: ${state.player.health}/${state.player.max_health} | 
+      Items: ${state.inventory.length}
+    `;
+  }
+
+  handleError(error) {
+    console.error('Game error:', error);
+    // Custom error handling
+  }
+}
+```
+
+**Event-Driven Game Logic:**
+```javascript
+// Listen for game events
+engine.on('stateChanged', (newState) => {
+  console.log('Game state updated:', newState.current_scene_id);
+  updateUI(newState);
+});
+
+engine.on('output', (message) => {
+  addToMessageLog(message);
+});
+
+// Custom event handling
+engine.on('itemPickedUp', (item) => {
+  playSound('pickup');
+  showNotification(`Picked up ${item}`);
+});
+
+engine.on('sceneEntered', (scene) => {
+  if (scene.background) {
+    preloadImage(scene.background);
+  }
+});
+```
+
+**Advanced State Management:**
+```javascript
+class AdvancedGameEngine extends BabaYagaGameEngine {
+  constructor(gameScript, options = {}) {
+    super(gameScript, options);
+    this.stateObservers = new Set();
+    this.stateMiddleware = [];
+  }
+
+  addStateObserver(observer) {
+    this.stateObservers.add(observer);
+  }
+
+  addStateMiddleware(middleware) {
+    this.stateMiddleware.push(middleware);
+  }
+
+  setState(newState) {
+    // Apply middleware
+    let processedState = newState;
+    for (const middleware of this.stateMiddleware) {
+      processedState = middleware(processedState, this.currentState);
+    }
+
+    // Update state
+    super.setState(processedState);
+
+    // Notify observers
+    for (const observer of this.stateObservers) {
+      observer(processedState, this.currentState);
+    }
+  }
+
+  // Custom state validation
+  validateState(state) {
+    const errors = [];
+    
+    if (!state.current_scene_id) {
+      errors.push('Missing current_scene_id');
+    }
+    
+    if (!state.player) {
+      errors.push('Missing player data');
+    }
+    
+    if (state.player.health < 0) {
+      errors.push('Player health cannot be negative');
+    }
+    
+    return errors.length === 0 ? null : errors;
+  }
+}
+```
+
+**Performance Optimizations:**
+```javascript
+class OptimizedGameEngine extends BabaYagaGameEngine {
+  constructor(gameScript, options = {}) {
+    super(gameScript, options);
+    this.sceneCache = new Map();
+    this.actionCache = new Map();
+    this.cacheTimeout = options.cacheTimeout || 5000; // 5 seconds
+  }
+
+  async getCurrentScene() {
+    const cacheKey = this.getCacheKey();
+    const cached = this.sceneCache.get(cacheKey);
+    
+    if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
+      return cached.data;
+    }
+
+    const scene = await super.getCurrentScene();
+    this.sceneCache.set(cacheKey, {
+      data: scene,
+      timestamp: Date.now()
+    });
+
+    return scene;
+  }
+
+  getCacheKey() {
+    return `${this.currentState.current_scene_id}_${JSON.stringify(this.currentState.flags)}`;
+  }
+
+  // Batch state updates
+  batchUpdate(updates) {
+    let currentState = this.currentState;
+    
+    for (const update of updates) {
+      currentState = update(currentState);
+    }
+    
+    this.setState(currentState);
+  }
+
+  // Debounced rendering
+  debouncedRender = debounce(async () => {
+    const renderData = await this.render();
+    this.emit('render', renderData);
+  }, 16); // ~60fps
+}
+
+function debounce(func, wait) {
+  let timeout;
+  return function executedFunction(...args) {
+    const later = () => {
+      clearTimeout(timeout);
+      func(...args);
+    };
+    clearTimeout(timeout);
+    timeout = setTimeout(later, wait);
+  };
+}
+```
+
+**Testing Integration:**
+```javascript
+class TestableGameEngine extends BabaYagaGameEngine {
+  constructor(gameScript, options = {}) {
+    super(gameScript, options);
+    this.testMode = options.testMode || false;
+    this.mockIO = options.mockIO || null;
+  }
+
+  async evaluateBabaYaga(code) {
+    if (this.testMode && this.mockIO) {
+      // Use mock IO for testing
+      const testHost = { ...this.host, io: this.mockIO };
+      return await evaluate(this.gameScript + '\n' + code, testHost);
+    }
+    return await super.evaluateBabaYaga(code);
+  }
+
+  // Test utilities
+  setTestState(state) {
+    this.currentState = state;
+  }
+
+  getTestState() {
+    return this.currentState;
+  }
+
+  simulateAction(verb, noun) {
+    return this.processCommand(verb, noun);
+  }
+}
+
+// Test example
+describe('Game Engine Tests', () => {
+  let engine;
+  let mockIO;
+
+  beforeEach(() => {
+    mockIO = {
+      out: jest.fn(),
+      in: jest.fn(() => 'test input'),
+      emit: jest.fn(),
+      listen: jest.fn()
+    };
+
+    engine = new TestableGameEngine(gameScript, {
+      testMode: true,
+      mockIO
+    });
+  });
+
+  it('should process take torch action', async () => {
+    const initialState = createTestState('entrance', { torch_taken: false });
+    engine.setTestState(initialState);
+
+    const result = await engine.simulateAction('take', 'torch');
+    
+    expect(result.ok).toBe(true);
+    expect(result.state.inventory).toContain('torch');
+    expect(result.state.flags.torch_taken).toBe(true);
+  });
+});
+```
+
+#### 3.6 Error Handling and Validation
+
+**Baba Yaga Error Handling:**
+```baba
+// Use Result type for error handling
+validate_action : state verb noun ->
+  when is_valid_verb verb is
+    true then when is_valid_noun noun is
+      true then Ok (verb, noun)
+      false then Err "Invalid noun"
+    false then Err "Invalid verb";
+
+safe_process_action : state verb noun ->
+  when validate_action state verb noun is
+    Ok (v, n) then process_action state v n
+    Err msg then {
+      state with
+      messages: append state.messages [msg]
+    };
+
+// Scene validation
+validate_scene_state : state scene_id ->
+  when scene_id is
+    "entrance" then validate_entrance_state state
+    "main_cavern" then validate_cavern_state state
+    _ then Ok state;
+
+// State validation utilities
+validate_game_state : state ->
+  when state is
+    { current_scene_id: scene_id, player: player, inventory: inv, flags: flags } then
+      when validate_scene_id scene_id is
+        Ok _ then when validate_player player is
+          Ok _ then when validate_inventory inv is
+            Ok _ then Ok state
+            Err msg then Err ("Inventory error: " .. msg)
+          Err msg then Err ("Player error: " .. msg)
+        Err msg then Err ("Scene error: " .. msg)
+    _ then Err "Invalid state structure";
+```
+
+**JavaScript Error Handling:**
+```javascript
+class GameError extends Error {
+  constructor(message, type, details) {
+    super(message);
+    this.name = 'GameError';
+    this.type = type; // 'parse', 'runtime', 'state', 'asset', 'input'
+    this.details = details;
+  }
+}
+
+// Error recovery strategies
+async handleGameError(error) {
+  switch (error.type) {
+    case 'parse':
+      return this.handleParseError(error);
+    case 'runtime':
+      return this.handleRuntimeError(error);
+    case 'state':
+      return this.handleStateError(error);
+    case 'asset':
+      return this.handleAssetError(error);
+    case 'input':
+      return this.handleInputError(error);
+    default:
+      return this.handleUnknownError(error);
+  }
+}
+
+// Specific error handlers
+handleParseError(error) {
+  console.error('Parse error:', error.message);
+  // Could attempt to recover by re-parsing or showing syntax help
+  return { ok: false, error: 'Game script has syntax errors' };
+}
+
+handleRuntimeError(error) {
+  console.error('Runtime error:', error.message);
+  // Could attempt to rollback to previous state
+  return { ok: false, error: 'Game encountered a runtime error' };
+}
+
+handleStateError(error) {
+  console.error('State error:', error.message);
+  // Could attempt to restore from last known good state
+  return { ok: false, error: 'Game state is invalid' };
+}
+
+handleAssetError(error) {
+  console.error('Asset error:', error.message);
+  // Could fall back to text-only mode
+  return { ok: true, warning: 'Some assets could not be loaded' };
+}
+
+handleInputError(error) {
+  console.error('Input error:', error.message);
+  // Could show input help or suggestions
+  return { ok: false, error: 'Invalid input provided' };
+}
+```
+
+#### 3.7 Performance Considerations
+
+**State Management Optimization:**
+- Immutable state updates using structural sharing
+- Lazy evaluation of expensive computations
+- State history with configurable depth
+- Efficient serialization/deserialization
+- Memoization of scene functions
+- Batch state updates to reduce re-renders
+
+**Rendering Optimization:**
+- Incremental UI updates
+- Debounced action processing
+- Asset preloading for browser interface
+- Virtual scrolling for long text output
+- Scene caching with TTL
+- Event batching for multiple state changes
+
+**Memory Management:**
+```javascript
+class MemoryOptimizedEngine extends BabaYagaGameEngine {
+  constructor(gameScript, options = {}) {
+    super(gameScript, options);
+    this.weakRefs = new WeakMap();
+    this.gcThreshold = options.gcThreshold || 1000;
+    this.operationCount = 0;
+  }
+
+  setState(newState) {
+    super.setState(newState);
+    this.operationCount++;
+    
+    if (this.operationCount > this.gcThreshold) {
+      this.performGarbageCollection();
+    }
+  }
+
+  performGarbageCollection() {
+    // Clear caches
+    this.memoizedScenes.clear();
+    this.sceneCache.clear();
+    this.actionCache.clear();
+    
+    // Trim history if too long
+    if (this.history.length > this.maxHistory * 2) {
+      this.history = this.history.slice(-this.maxHistory);
+    }
+    
+    this.operationCount = 0;
+  }
+}
+```
+
+#### 3.8 Testing Strategy
+
+**Unit Tests:**
+- Baba Yaga game logic functions
+- JavaScript engine components
+- State management operations
+- Error handling scenarios
+- Scene function validation
+- Action processing logic
+
+**Integration Tests:**
+- Full game loop execution
+- Save/load functionality
+- Cross-platform compatibility
+- Asset loading and rendering
+- Event system integration
+- State persistence
+
+**Example Test Structure:**
+```javascript
+describe('Game Engine', () => {
+  it('should initialize game state correctly', async () => {
+    const engine = new BabaYagaGameEngine(gameScript);
+    await engine.initialize();
+    const state = engine.getCurrentState();
+    expect(state.current_scene_id).toBe('entrance');
+  });
+
+  it('should process valid actions', async () => {
+    const engine = new BabaYagaGameEngine(gameScript);
+    await engine.initialize();
+    
+    const result = await engine.processCommand('take', 'torch');
+    expect(result.ok).toBe(true);
+    expect(result.state.inventory).toContain('torch');
+  });
+
+  it('should handle invalid actions gracefully', async () => {
+    const engine = new BabaYagaGameEngine(gameScript);
+    await engine.initialize();
+    
+    const result = await engine.processCommand('invalid', 'action');
+    expect(result.ok).toBe(true); // Should not crash, just return unchanged state
+  });
+
+  it('should maintain state history', async () => {
+    const engine = new BabaYagaGameEngine(gameScript);
+    await engine.initialize();
+    
+    const initialState = engine.getCurrentState();
+    await engine.processCommand('take', 'torch');
+    
+    expect(engine.history.length).toBe(2);
+    expect(engine.history[0]).toEqual(initialState);
+  });
+});
+
+describe('Scene Functions', () => {
+  it('should return different descriptions based on state', async () => {
+    const engine = new BabaYagaGameEngine(gameScript);
+    await engine.initialize();
+    
+    const scene1 = await engine.getCurrentScene();
+    expect(scene1.description).toContain('dark cave');
+    
+    // Update state to light torch
+    engine.setState({
+      ...engine.getCurrentState(),
+      flags: { ...engine.getCurrentState().flags, torch_lit: true }
+    });
+    
+    const scene2 = await engine.getCurrentScene();
+    expect(scene2.description).toContain('illuminated');
+  });
+});
+
+describe('Save/Load System', () => {
+  it('should save and restore game state', async () => {
+    const engine = new BabaYagaGameEngine(gameScript);
+    await engine.initialize();
+    
+    await engine.processCommand('take', 'torch');
+    const stateBeforeSave = engine.getCurrentState();
+    
+    await engine.saveGame('test');
+    
+    // Reset engine
+    await engine.initialize();
+    expect(engine.getCurrentState().inventory).toEqual([]);
+    
+    await engine.loadGame('test');
+    expect(engine.getCurrentState()).toEqual(stateBeforeSave);
+  });
+});
+```
+
+**Performance Tests:**
+```javascript
+describe('Performance', () => {
+  it('should handle rapid state changes efficiently', async () => {
+    const engine = new BabaYagaGameEngine(gameScript);
+    await engine.initialize();
+    
+    const startTime = performance.now();
+    
+    for (let i = 0; i < 100; i++) {
+      await engine.processCommand('look', 'around');
+    }
+    
+    const endTime = performance.now();
+    expect(endTime - startTime).toBeLessThan(1000); // Should complete in under 1 second
+  });
+
+  it('should cache scene data appropriately', async () => {
+    const engine = new BabaYagaGameEngine(gameScript);
+    await engine.initialize();
+    
+    // First call should populate cache
+    const scene1 = await engine.getCurrentScene();
+    expect(engine.memoizedScenes.size).toBe(1);
+    
+    // Second call should use cache
+    const scene2 = await engine.getCurrentScene();
+    expect(scene1).toBe(scene2); // Should be the same object reference
+  });
+});
+```
+
+#### 3.8 Architectural Choices Emerging from Scene State as Functions
+
+**Choice 1: Dynamic Scene Content**
+*Decision:* Scenes are functions that take game state and return scene data
+*Benefits:*
+- Scenes can react to player actions and game flags
+- Content changes based on story progression
+- No need to pre-compute all possible scene variations
+- Natural fit for Baba Yaga's functional paradigm
+
+*Consequences:*
+- Scene functions must be pure and predictable
+- Game state becomes the single source of truth
+- Scene testing requires state fixtures
+
+**Choice 2: Lazy Scene Loading**
+*Decision:* Only load scene data when needed via function calls
+*Benefits:*
+- Memory efficient for large games
+- Scenes can be defined in separate modules
+- Easy to add new scenes without modifying existing code
+- Natural code splitting and organization
+
+*Consequences:*
+- Scene registry must be maintained
+- Error handling for missing scenes
+- Potential performance cost of function calls
+
+**Choice 3: State-Driven Rendering**
+*Decision:* All scene content (descriptions, exits, items) depends on game state
+*Benefits:*
+- Consistent state management
+- Easy to implement story branches
+- Natural progression tracking
+- Simplified save/load (only state, not scene data)
+
+*Consequences:*
+- Scene functions must handle all state combinations
+- More complex scene logic
+- Need for state validation
+
+**Choice 4: Composition Over Inheritance**
+*Decision:* Use function composition to build complex scenes from simple parts
+*Benefits:*
+- Reusable scene components
+- Easy to test individual parts
+- Clear separation of concerns
+- Leverages Baba Yaga's functional strengths
+
+*Consequences:*
+- Need for composition utilities
+- Potential for over-abstraction
+- Learning curve for composition patterns
+
+**Choice 5: Immutable Scene Updates**
+*Decision:* Scene functions return new scene data, never modify existing state
+*Benefits:*
+- Predictable behavior
+- Easy debugging and testing
+- Natural fit with Baba Yaga's immutability
+- Enables time-travel debugging
+
+*Consequences:*
+- More memory usage for large scenes
+- Need for efficient update patterns
+- All state changes must be explicit
+
+**Choice 6: Flag-Based State Management**
+*Decision:* Use a flat flag structure for tracking game progress
+*Benefits:*
+- Simple and predictable
+- Easy to serialize/deserialize
+- Clear naming conventions
+- Easy to debug and inspect
+
+*Consequences:*
+- Potential for flag explosion
+- Need for flag organization strategy
+- Manual flag management
+
+**Emerging Patterns and Utilities:**
+
+```baba
+// State validation utilities
+validate_scene_state : state scene_id ->
+  when scene_id is
+    "entrance" then validate_entrance_state state
+    "main_cavern" then validate_cavern_state state
+    _ then Ok state;
+
+// Scene transition utilities
+can_transition_to : state from_scene to_scene ->
+  when from_scene is
+    "entrance" then when to_scene is
+      "main_cavern" then true
+      "side_tunnel" then state.flags.cave_unlocked
+      _ then false
+    _ then false;
+
+// Scene content utilities
+get_scene_description : state scene_id ->
+  when scene_id is
+    "entrance" then entrance_scene state.description
+    "main_cavern" then main_cavern_scene state.description
+    _ then "You are in an unknown location.";
+
+// State update utilities
+update_scene_state : state scene_id updates ->
+  fold (state, update) -> update state state updates;
+
+// Scene testing utilities
+create_test_state : scene_id flags ->
+  {
+    current_scene_id: scene_id,
+    player: default_player,
+    inventory: [],
+    flags: flags,
+    history: [],
+    messages: []
+  };
+```
+
+**Performance Considerations:**
+- Scene functions should be memoized for repeated calls
+- State updates should be batched when possible
+- Scene composition should be optimized for common patterns
+- Flag access should be efficient (consider using a more structured approach for large games)
+
+**Scalability Patterns:**
+- Scene modules for different game areas
+- Shared state utilities across scenes
+- Scene templates for common patterns
+- State validation at scene boundaries
+
+### Next Steps:
+
+1.  **Implement Core Engine:** Start with the `BabaYagaGameEngine` class and basic state management using the scene state as functions approach.
+2.  **Create Scene Function Framework:** Implement the scene registry, composition utilities, and state management functions.
+3.  **Build Sample Game:** Develop a simple 2-3 room adventure using the new scene architecture to validate the design.
+4.  **Implement State-Driven Rendering:** Create the rendering system that uses scene functions to generate UI content.
+5.  **Add Scene Composition Utilities:** Build the `base_scene`, `with_exits`, `with_items` etc. utilities for easy scene creation.
+6.  **Enhance Browser Interface:** Extend the existing web app with game-specific UI components that work with dynamic scene content.
+7.  **Implement Save/Load:** Add persistence functionality that serializes only the game state (not scene data).
+8.  **Add Performance Optimizations:** Implement memoization for scene functions and efficient state updates.
+9.  **Create Scene Testing Framework:** Build utilities for testing scene functions with different state configurations.
+10. **Documentation and Examples:** Create comprehensive documentation and sample games demonstrating the scene architecture.