diff --git a/PROTOTYPE_ANALYSIS.md b/PROTOTYPE_ANALYSIS.md deleted file mode 100644 index d02de86..0000000 --- a/PROTOTYPE_ANALYSIS.md +++ /dev/null @@ -1,311 +0,0 @@ -# Prototype Text Pipeline Analysis - -## Overview -The prototype uses a sophisticated text processing pipeline that achieves professional typography through: -1. SmartyPants (typographic punctuation) -2. Hyphenopoly (hyphenation with pipe markers) -3. Knuth-Plass algorithm (optimal line breaking) -4. Precise character-by-character width measurement -5. Justification ratio application - -## Complete Text Flow (Prototype) - -``` -User Text - ↓ -SmartyPants.smartypantsu(text, 1) - ↓ [Converts quotes, dashes to typographic characters] -hyphenator_en(..., '.hyphenatePipe') - ↓ [Inserts | at hyphenation points] -kap(..., measureText, measure.toReversed(), true) - ↓ [Knuth-Plass line breaking] -typesetParagraph(paragraph_data, delay, measure) - ↓ [DOM creation with justification] -Rendered paragraph with proper spacing -``` - -## Key Components - -### 1. Text Preprocessing (game.js:698) - -```javascript -var preview_data = kap( - hyphenator_en( - SmartyPants.smartypantsu(text, 1), - '.hyphenatePipe' // ← CRITICAL: Uses pipe character - ), - measureText, - measure.toReversed(), - true // ← hyphenation enabled -); -``` - -**Purpose**: Creates nodes with accurate widths and hyphenation points - -### 2. Character Width Measurement (game.js:380-406) - -```javascript -function measureText(str) { - // Special cases - if(str.substr(0, 2) == '') { ... } // Closing tag - if(str.substr(0, 1) == '<') { ... } // Opening tag - if(str === '|') return 0; // ← Hyphen point has ZERO width - if (str === ' ') str = '\u00A0'; // Non-breaking space - - // Actual measurement - ruler = rstack[rstack.length-1]; - let textNode = document.createTextNode(str); - ruler.appendChild(textNode); - let width = ruler.getClientRects()[0].width; // ← REAL CSS width - ruler.removeChild(textNode); - return width; -} -``` - -**Key Insight**: Uses a hidden `#ruler` element to measure actual rendered widths with the exact font/size from CSS. - -### 3. Measure Array (game.js:656-696) - -The measure array defines different line widths: - -**Chapter beginning (with drop cap)**: -```javascript -measure.push(containerWidth); // Full width -measure.push(containerWidth - indentWidth); // Indented -measure.push(containerWidth - indentWidth * 0.9); // More indented -``` - -**Regular paragraph (indented first line)**: -```javascript -measure.push(containerWidth); // Full width -measure.push(containerWidth - indentWidth * 0.5); // Half indent -``` - -**Important**: Array is reversed before passing to `kap()`: `measure.toReversed()` - -### 4. Knuth-Plass Algorithm (knuth-and-plass.js:1-60) - -```javascript -function kap(text, measureText, measure, hyphenation) { - // Strip pipes if hyphenation disabled - if (!hyphenation) { - text = text.replace(/\|/g, ''); - } - - // Split on: punctuation, spaces, pipes, tags - text.split(/([.,:;!?] |\s|\||<.*?>)/u).forEach(function (fragment) { - if (fragment === ' ') { - // Create glue with stretch/shrink - nodes.push(linebreak.glue(spaceWidth, stretch, shrink)); - } else if (fragment === '|') { - // Create penalty node for hyphenation point - nodes.push(linebreak.penalty(hyphenWidth * 0.25, 100, 1)); - } else { - // Create box node for word - nodes.push(linebreak.box(fragmentWidth, fragment)); - } - }); - - // Run Knuth-Plass algorithm - let breaks = linebreak(nodes, measure, { tolerance: 3, demerits }); - - return { nodes, breaks }; -} -``` - -**Node Types**: -- **box**: Word with fixed width (cannot break) -- **glue**: Space with stretch/shrink (for justification) -- **penalty**: Potential break point (like hyphen) with cost - -### 5. Rendering with Justification (game.js:295-378) - -```javascript -function typesetParagraph(paragraph_data, delay = 0, measure = []) { - // Create paragraph container - let p = document.createElement("p"); - p.style.position = 'relative'; - p.style.height = lineHeight * (paragraph_data.breaks.length - 1) + 'px'; - - // Iterate through lines - for(let i = 1; i < paragraph_data.breaks.length; i++) { - let left = 0; - let ratio = paragraph_data.breaks[i].ratio; // ← JUSTIFICATION RATIO - - // Iterate through nodes on this line - for(let j = paragraph_data.breaks[i-1].position; j <= paragraph_data.breaks[i].position; j++) { - let node = paragraph_data.nodes[j]; - - if(node.type === 'box') { - // Handle hyphenated syllables (lines 316-320) - if(j > paragraph_data.breaks[i-1].position + 1 && - paragraph_data.nodes[j-1].type === 'penalty' && lastChild) { - // Combine with previous syllable - syllable += '\u200c' + node.value; // Zero-width non-joiner - lastChild.innerHTML = syllable; - left += node.width; - } else { - // Create new word span - let word = document.createElement("span"); - word.style.position = 'absolute'; - word.style.top = lineHeight * (i - 1) * 100 / paragraph_height + '%'; - word.style.left = left * 100 / line_width + '%'; - word.innerHTML = node.value; - p.appendChild(word); - left += node.width; - } - } - else if(node.type === 'glue') { - // ← CRITICAL: Apply justification ratio to glue - if(ratio > 0) { - left += node.width + ratio * node.stretch; - } else { - left += node.width + ratio * node.shrink; - } - } - else if(node.type === 'penalty' && node.penalty === 100 && j === breaks[i].position) { - // Add hyphen at line break - let word = document.createElement("span"); - word.innerHTML = "-"; - p.appendChild(word); - } - } - } - - return [p, delay]; -} -``` - -**Key Points**: -1. **Justification**: Glue widths are adjusted by `ratio * stretch` or `ratio * shrink` -2. **Hyphenation**: Syllables after penalty nodes are combined with previous word using zero-width non-joiner -3. **Positioning**: All words use `position: absolute` with percentage-based coordinates - -## Current Implementation Issues - -### Issue 1: Text Processing Pipeline - -**Current** (sentence-queue-module.js:266): -```javascript -const processedText = textProcessor ? await textProcessor.process(text) : text; -``` - -**Problem**: -- `textProcessor.process()` may not pass the correct selector to Hyphenopoly -- Hyphenopoly needs `.hyphenatePipe` selector to use pipe characters - -**Fix Needed**: -```javascript -const processedText = textProcessor ? - await textProcessor.hyphenate( - textProcessor.smartyPants(text), - '.hyphenatePipe' - ) : text; -``` - -### Issue 2: Hyphenation with Pipe Character - -**Current** (text-processor-module.js:275-286): -```javascript -hyphenate(text) { - if (!this.isHyphenationAvailable()) return text; - try { - return this.hyphenator(text); // ← No selector parameter - } catch (error) { - console.error("Error hyphenating text:", error); - return text; - } -} -``` - -**Fix Needed**: Add selector parameter -```javascript -hyphenate(text, selector = null) { - if (!this.isHyphenationAvailable()) return text; - try { - return selector ? - this.hyphenator(text, selector) : - this.hyphenator(text); - } catch (error) { - console.error("Error hyphenating text:", error); - return text; - } -} -``` - -### Issue 3: Knuth-Plass Not Using Pipe Characters - -**Current** (public/js/knuth-and-plass.js): -- May not properly split on pipe characters -- May not create penalty nodes - -**Fix Needed**: Ensure knuth-and-plass.js matches prototype implementation - -### Issue 4: Syllable Combination in Rendering - -**Current** (layout-renderer-module.js): -- Does NOT combine hyphenated syllables -- Missing logic for `if(nodes[j-1].type === 'penalty' && lastChild)` - -**Fix Needed**: Add syllable combination logic when rendering box nodes after penalty nodes - -### Issue 5: Missing #ruler Element - -**Current**: No `#ruler` element for text measurement - -**Fix Needed**: -1. Add `
` to HTML -2. Use ruler for character width measurement in paragraph-layout-module.js - -## Implementation Plan - -### Phase 1: Fix Text Processing Pipeline - -1. **Update text-processor-module.js**: - - Add `selector` parameter to `hyphenate()` method - - Update `process()` to pass `.hyphenatePipe` selector - -2. **Update sentence-queue-module.js**: - - Pass `.hyphenatePipe` selector when calling text processor - - Ensure processedText includes pipe characters - -### Phase 2: Fix Knuth-Plass Integration - -1. **Verify knuth-and-plass.js**: - - Ensure it splits on `\|` character - - Creates `penalty` nodes with cost 100 - - Handles HTML tags properly - -2. **Update paragraph-layout-module.js**: - - Ensure `measureText()` returns 0 for `|` character - - Use `#ruler` element for measurement - - Handle HTML tag stack properly - -### Phase 3: Fix Rendering with Justification - -1. **Update layout-renderer-module.js**: - - Add syllable combination logic for hyphenated words - - Apply justification ratios to glue widths correctly - - Add hyphens at line breaks when penalty node is at break position - -2. **Fix spacing issues**: - - Create space spans with adjusted widths - - Use zero-width non-joiner for syllable combination - -### Phase 4: Testing & Refinement - -1. **Test with simple text**: "This is a test." -2. **Test with hyphenation**: Long words that span lines -3. **Test with justification**: Full paragraphs -4. **Test with special characters**: Quotes, dashes, etc. - -## Success Criteria - -✅ SmartyPants converts quotes correctly -✅ Hyphenopoly inserts pipe characters -✅ Knuth-Plass creates proper breaks with hyphenation -✅ Words don't overlap -✅ Words have proper spacing (not smushed) -✅ Justification works (even spacing across line width) -✅ Hyphens appear at line breaks -✅ Drop caps and indentation work diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 4fff76b..0000000 --- a/TODO.md +++ /dev/null @@ -1,106 +0,0 @@ -# Module System Refactoring TODO - -## High Priority (Critical Architectural Issues) - -### 1. Asynchronous Flow Control Improvements -- [ ] Remove all `setTimeout` calls used for synchronization in modules - - [X] Replace timeout in `browser-tts-handler.js` with proper Promise handling for voice loading - - [X] Eliminate race condition in `tts-player.js` that uses a hard-coded 1000ms timeout - - [ ] Remove all `setTimeout` calls in `ui-controller.js` for UI updates -- [ ] Implement proper Promise-based flow control in all modules - - [ ] Update `kokoro-handler.js` to correctly handle loading events - - [ ] Ensure all `async/await` patterns follow best practices - - [ ] Fix race conditions in module loading sequences - -### 2. Module State Management -- [ ] Fix premature reporting of `FINISHED` state - - [ ] Ensure `tts-player.js` properly waits for Kokoro loading before reporting FINISHED - - [ ] Add proper state checks in all modules before reporting FINISHED -- [ ] Implement proper state transition reporting - - [ ] Update modules to use event system for reporting state transitions - - [ ] Add better error handling during module initialization - -### 3. Module Dependencies & Loading -- [ ] Fix missing dependency declarations - - [ ] Update `ui-controller.js` to properly declare its TTS dependency - - [ ] Ensure all modules correctly specify all dependencies -- [ ] Remove dependency availability checks within modules - - [ ] Remove conditional checks like `if (!this.ttsHandler)` in `ui-controller.js` - - [ ] Rely on the module loader for dependency management - -## Medium Priority (Functionality & Implementation Issues) - -### 4. TTS Handler Implementation -- [ ] Implement missing `tts-handler.js` file content - - [ ] Create proper implementation with consistent interface - - [ ] Ensure it uses proper event-based communication -- [ ] Fix inconsistent event usage across TTS handlers - - [ ] Replace direct callbacks with event system - - [ ] Standardize event names and parameters - -### 5. Animation Queue Enhancements -- [ ] Implement proper queue control mechanisms - - [ ] Add pause/resume functionality - - [ ] Implement more robust animation timing - - [ ] Add priority management for animations - -### 6. UI Controller Cleanup -- [ ] Fix duplicate methods in UI Controller - - [ ] Deduplicate code for creating UI elements - - [ ] Consolidate event handling functions -- [ ] Remove redundant `ModuleEvent` class implementation - - [ ] Use the shared implementation from `base-module.js` - -### 7. Kokoro Loading Implementation -- [ ] Implement proper `requestIdleCallback` for Kokoro loading - - [ ] Follow the pattern described in the specification - - [ ] Add progress reporting during Kokoro loading -- [ ] Fix event handling for loading completion - -## Lower Priority (Refinements & Optimizations) - -### 8. Code Quality & Consistency -- [ ] Standardize module registration pattern - - [ ] Ensure all modules follow the same pattern - - [ ] Fix inconsistencies in export approaches -- [ ] Improve module progress reporting - - [ ] Make progress reporting more granular - - [ ] Add more descriptive status messages - -### 9. Error Handling Improvements -- [ ] Add better error recovery mechanisms - - [ ] Implement fallbacks for critical failures - - [ ] Add user-friendly error messages -- [ ] Improve error logging - - [ ] Add structured error reporting - - [ ] Implement debugging tools - -### 10. Performance Optimizations -- [ ] Optimize module loading sequence - - [ ] Prioritize critical modules - - [ ] Defer non-essential loading -- [ ] Improve resource utilization - - [ ] Minimize memory footprint - - [ ] Reduce CPU usage during animations - -## Documentation & Testing - -### 11. Documentation -- [ ] Add JSDoc comments to all public methods -- [ ] Create architectural documentation - - [ ] Document module dependencies - - [ ] Explain event system -- [ ] Add example usage for modules - -### 12. Testing -- [ ] Create unit tests for modules -- [ ] Implement integration tests for module system -- [ ] Add browser compatibility tests - -## Future Enhancements - -### 13. New Features -- [ ] Add module versioning support -- [ ] Implement module hot-reloading -- [ ] Create plugin system for extending modules -- [ ] Add internationalization support for UI \ No newline at end of file diff --git a/references/CLIENT_TODO_v1.md b/references/CLIENT_TODO_v1.md deleted file mode 100644 index 730a564..0000000 --- a/references/CLIENT_TODO_v1.md +++ /dev/null @@ -1,145 +0,0 @@ -# Client Architecture Refactoring TODO List - -## Enhanced SentenceQueueModule Implementation - -### Phase 1: Core Structure and Design - -1. **Design the Sentence Object Structure** - - [ ] Define comprehensive sentence object with fields for: - - Unique ID - - Original text - - Processed text (hyphenated, typeset) - - Layout information (breaks, nodes, typography) - - Audio component (player, duration, data, type) - - Status tracking (pending, processing, ready, playing, complete) - -2. **Implement Basic Queue Management** - - [ ] Create methods for adding sentences to the queue - - [ ] Implement queue processing logic that maintains order - - [ ] Add status tracking for each sentence in the queue - - [ ] Implement priority handling for urgent sentences - -### Phase 2: Text Processing Integration - -1. **Integrate with Paragraph Layout** - - [ ] Connect to ParagraphLayoutModule for text processing - - [ ] Implement hyphenation and typesetting in the queue - - [ ] Store layout information in the sentence object - - [ ] Ensure layout processing happens in parallel with audio - -2. **Text Animation Preparation** - - [ ] Calculate animation timing based on text length and settings - - [ ] Prepare animation data for each word in the sentence - - [ ] Store animation timing in the sentence object - - [ ] Create animation player function for the sentence - -### Phase 3: Audio Processing Integration - -1. **TTS System Integration** - - [ ] Implement audio generation for Kokoro TTS - - [ ] Implement browser TTS handling with duration estimation - - [ ] Implement "none" TTS option with duration calculation - - [ ] Create consistent player interface for all TTS types - -2. **Audio Data Management** - - [ ] Implement audio data storage in sentence objects - - [ ] Connect with TTSFactoryModule's IndexedDB for persistent caching - - [ ] Add audio preloading capabilities - - [ ] Implement audio resource cleanup - -### Phase 4: Playback Coordination - -1. **Synchronized Playback** - - [ ] Implement coordinated text animation and audio playback - - [ ] Create timing adjustment based on speed settings - - [ ] Add event handling for playback states (start, pause, resume, complete) - - [ ] Implement sentence transition handling - -2. **User Interaction Handling** - - [ ] Add support for fast-forwarding text/audio - - [ ] Implement pause/resume functionality - - [ ] Handle user interruptions gracefully - - [ ] Support skipping to next sentence - -## Component Consolidation - -### Phase 1: Identify and Remove Redundancies - -1. **TTSPlayerModule Refactoring** - - [ ] Remove preloadedAudio Map (replaced by sentence objects) - - [ ] Remove preloadQueue (replaced by SentenceQueue) - - [ ] Update speak method to use SentenceQueue - - [ ] Refactor to be a thin wrapper around SentenceQueue - -2. **UIDisplayHandlerModule Refactoring** - - [ ] Remove pendingParagraphs queue (replaced by SentenceQueue) - - [ ] Update displayText to use SentenceQueue - - [ ] Modify processNextParagraph to work with sentence objects - - [ ] Update event handling to work with the new architecture - -3. **KokoroTTSModule Refactoring** - - [ ] Replace pendingGenerations Map with SentenceQueue integration - - [ ] Update generateSpeech to work with sentence objects - - [ ] Modify iframe communication to support the new structure - - [ ] Ensure backward compatibility during transition - -4. **TextBufferModule Refactoring** - - [ ] Move sentence preparation logic to SentenceQueue - - [ ] Update text handling to work with the new architecture - - [ ] Ensure proper integration with SentenceQueue - - [ ] Maintain high-level text management responsibilities - -### Phase 2: Interface Updates - -1. **Update Module Interfaces** - - [ ] Create consistent interfaces for interacting with SentenceQueue - - [ ] Update event system to work with sentence objects - - [ ] Implement progress reporting for sentence processing - - [ ] Add debugging and monitoring capabilities - -2. **Documentation and Examples** - - [ ] Document the new architecture and interfaces - - [ ] Create usage examples for common scenarios - - [ ] Update developer guidelines - - [ ] Add migration guide for existing code - -## Testing and Validation - -1. **Unit Testing** - - [ ] Create tests for SentenceQueue core functionality - - [ ] Test text processing integration - - [ ] Test audio processing integration - - [ ] Test playback coordination - -2. **Integration Testing** - - [ ] Test interaction between SentenceQueue and other modules - - [ ] Validate timing and synchronization - - [ ] Test error handling and recovery - - [ ] Verify performance under load - -3. **User Experience Testing** - - [ ] Validate text animation quality - - [ ] Test audio playback quality - - [ ] Verify synchronization from user perspective - - [ ] Test accessibility features - -## Implementation Strategy - -1. **Phased Rollout** - - [ ] Implement SentenceQueue core structure - - [ ] Add text processing integration - - [ ] Add audio processing integration - - [ ] Implement playback coordination - - [ ] Gradually replace existing components - -2. **Backward Compatibility** - - [ ] Maintain support for existing interfaces during transition - - [ ] Implement adapter patterns where needed - - [ ] Add feature flags for enabling/disabling new architecture - - [ ] Create fallback mechanisms for error recovery - -3. **Performance Optimization** - - [ ] Implement parallel processing where possible - - [ ] Optimize memory usage for sentence objects - - [ ] Add resource management for audio data - - [ ] Implement efficient queue processing algorithms \ No newline at end of file diff --git a/references/Documentation.md b/references/Documentation.md deleted file mode 100644 index dbcf6ef..0000000 --- a/references/Documentation.md +++ /dev/null @@ -1,441 +0,0 @@ -# AI Interactive Fiction Engine - Technical Documentation - -## 1. Overview - -This document provides a comprehensive technical explanation of the AI Interactive Fiction Engine implemented in `game.js`. The engine leverages inkjs for narrative management and incorporates advanced text rendering features, including custom animations, sophisticated typography using SmartyPants and Hyphenopoly, and optimal line breaking via the Knuth and Plass algorithm, to create rich, dynamic interactive fiction experiences. - -## 2. Core Technologies - -The engine is built upon several key technologies: - -* **inkjs**: Manages the core interactive fiction logic, including story state, branching narrative, choices, and variables. -* **Knuth and Plass Line Breaking Algorithm**: Adapted implementation for optimal paragraph justification and line breaking, ensuring high-quality text layout. (Based on Bram Stein's "typeset" library). -* **Hyphenopoly**: Provides high-quality, language-aware text hyphenation, crucial for justified text layout. -* **SmartyPants**: Enhances typography by converting plain text elements (quotes, dashes) into their typographically correct equivalents. -* **Custom Animation System**: A queue-based system handles the precise timing and visual reveal of text elements. -* **JavaScript (ES6+)**: The primary implementation language. -* **HTML/CSS**: Used for structuring the UI and styling the visual presentation. - -## 3. Engine Architecture and Flow - -The engine follows a well-defined process from initialization to interactive playback. - -### 3.1. Initialization (`window.onload`) - -Execution begins when the window loads: - -1. **Initial State Setup**: Global state variables (`running`, `fastForwardingAll`, `speech`, `speed`, `delay`) are initialized. -2. **Background Effects**: Lighting animations for background visuals are configured. -3. **Text Libraries**: Hyphenopoly is initialized for hyphenation support. -4. **Story Loading**: The compiled Ink story (JSON format) is fetched and loaded. -5. **Event Listeners**: Listeners for user interactions (keyboard input, clicks, slider changes) are attached. -6. **Playback Start**: The `continueStory()` function is called to begin rendering the narrative. - -### 3.2. The Main Playback Loop (`continueStory()`) - -The `continueStory()` function is the engine's core, orchestrating the display of narrative content and handling user choices. - -**Step-by-step Process:** - -1. **Setup**: Animation state variables (`fade_in`, `running`, `fastForwardingAll`) are reset for the current turn. -2. **Story Content Iteration**: - ```javascript - while(story.canContinue) { - // Fetch next paragraph & associated tags from inkjs - var paragraphText = story.Continue(); - var tags = story.currentTags; - - // Process tags (Section 3.3) - // ... - - // Process and render text (Section 4) - // ... - } - ``` - The loop continues as long as inkjs indicates more content is available for the current narrative sequence. - -3. **Choice Handling**: After exhausting the `story.canContinue` content, the engine checks for available choices: - ```javascript - story.currentChoices.forEach(function(choice) { - // Create interactive DOM elements for each choice - // Attach event listeners to handle choice selection - // Apply appropriate styling - }); - ``` - When a user selects a choice, an event handler calls `story.ChooseChoiceIndex(choice.index)` and then triggers `continueStory()` again to display the subsequent narrative branch. - -4. **End of Story**: If `story.canContinue` is false and there are no choices, the story concludes or reaches a waiting point. - -### 3.3. Tag Processing - -Ink tags are used to control various non-textual aspects of the presentation: - -* `AUDIO ...
-
- // Iterate through lines defined by paragraph_data.breaks
- for(let i = 1; i < paragraph_data.breaks.length; i++) {
- // Iterate through nodes (words, spaces, hyphens, tags) within the line
- for(let j = paragraph_data.breaks[i-1].position; j <= paragraph_data.breaks[i].position; j++) {
- const node = paragraph_data.nodes[j];
- // Create appropriate DOM element (e.g., for words/tags)
- // Set absolute position (left, top) based on calculated widths and line height
- // Apply styles (opacity: 0 initially)
- // Schedule fade-in animation using scheduleTimeout() (Section 5)
- // Update the running 'delay' total for the next element
- }
- // Handle line breaks, adjusting vertical position
- }
-
- return [p, delay]; // Return the populated element and the final delay value
-}
-```
-
-* Each word, space, or preserved tag becomes a separate, absolutely positioned DOM element (typically a ``).
-* Positions are determined precisely based on the widths calculated during the line-breaking phase.
-* Initial opacity is set to 0, and fade-in animations are scheduled sequentially.
-
-## 5. Animation System
-
-The engine features a sophisticated animation system for revealing text dynamically.
-
-### 5.1. Animation Queue (`timeoutQueue`)
-
-* A central array `timeoutQueue = []` tracks all pending `setTimeout` calls.
-* Each entry is an object storing the function to execute, its arguments, and the `timeoutId`.
-
-### 5.2. Scheduling Animations (`scheduleTimeout`)
-
-```javascript
-function scheduleTimeout(func, delay, ...args) {
- // Creates timeoutObject with execute method and null timeoutId
- // Uses setTimeout to schedule execution after 'delay'
- // Inside setTimeout callback: executes func, removes object from timeoutQueue
- // Pushes timeoutObject onto timeoutQueue
- // Returns the timeoutId
-}
-```
-* Provides a managed way to schedule functions, ensuring they are tracked.
-* Enables batch operations like fast-forwarding or cancellation.
-
-### 5.3. Timing and Delay (`window.delay`, `window.speed`)
-
-* `window.delay`: Accumulates the total delay time as elements are scheduled. Each new element's animation starts after the previous one finishes.
-* `window.speed`: Controls the duration of each word's fade-in, typically adjusted by a UI slider. The delay increment for a word is often calculated like `delay += window.speed * word.length;`.
-* Speed Adjustment: The UI slider uses a non-linear function (`Math.pow(100.0 - value, 3) / 10000 * 10 + 0.01`) for finer control at slower speeds.
-
-### 5.4. Fast Forwarding (`fastForward`, `fastForwardingAll`)
-
-* The `fastForward()` function:
- 1. Iterates through `timeoutQueue`.
- 2. Calls `clearTimeout()` for each pending animation.
- 3. Immediately executes the scheduled function (`timeoutObject.execute()`).
- 4. Clears the `timeoutQueue`.
- 5. Resets `window.delay` to 0.
-* Triggered by user actions (spacebar, click) or programmatically.
-* `window.fastForwardingAll` flag indicates if fast-forward is continuously active (e.g., holding space).
-* Visual Feedback: The page border changes color (e.g., red) when `fastForwardingAll` is true.
-
-### 5.5. Animation Interruption (`stopAllTimeouts`)
-
-* The `stopAllTimeouts()` function:
- 1. Iterates through `timeoutQueue`.
- 2. Calls `clearTimeout()` for each pending animation.
- 3. Clears the `timeoutQueue`.
-* Used during navigation, loading saves, or story resets to prevent outdated animations from playing.
-
-## 6. Additional Features
-
-### 6.1. Text-to-Speech (TTS)
-
-* Integrates with an external TTS service (e.g., ElevenLabs API).
-* A UI button toggles speech playback.
-* Attempts to synchronize audio playback with text animation reveal (implementation details not fully specified in the source document).
-* Playback can be interrupted by user interactions or fast-forwarding.
-
-### 6.2. State Management and Persistence
-
-* **Ink State**: The core narrative state (current position, variable values, etc.) is managed by inkjs and can be serialized using `story.state.toJson()`.
-* **Local Storage**: Used to persist the serialized Ink state and potentially other UI/game states (like rendered history) across browser sessions.
-* **Save/Load**: Functionality allows users to explicitly save the current state and reload it later. This involves restoring the Ink state via `story.state.loadJson()` and potentially re-rendering the story history up to that point.
-
-## 7. External Libraries & Credits
-
-The engine relies on the following external libraries:
-
-* **inkjs**
- * **Author**: Yannick Lohse (y-lohse)
- * **Source**: [https://github.com/y-lohse/inkjs](https://github.com/y-lohse/inkjs)
- * **Description**: JavaScript port of Inkle's Ink narrative scripting language.
-* **Hyphenopoly**
- * **Author**: Hermann Monnich (mnater)
- * **Source**: [https://github.com/mnater/Hyphenopoly](https://github.com/mnater/Hyphenopoly)
- * **Website**: [https://mnater.github.io/Hyphenopoly/](https://mnater.github.io/Hyphenopoly/)
- * **Description**: High-quality JavaScript hyphenation library.
-* **SmartyPants**
- * **Original Author**: John Gruber
- * **JavaScript Port Author**: Example: Othree (othree)
- * **Source (Example Port)**: [https://github.com/othree/smartypants.js](https://github.com/othree/smartypants.js)
- * **Description**: Typography prettifier for quotes, dashes, etc.
-* **typeset (Basis for Knuth & Plass / LinkedList)**
- * **Author**: Bram Stein (bramstein)
- * **Source**: [https://github.com/bramstein/typeset](https://github.com/bramstein/typeset)
- * **Description**: Original JavaScript implementation of the Knuth-Plass line breaking algorithm, adapted for this engine.
-
-## 8. Practical Refactoring Recommendations (Updated)
-
-Based on the detailed analysis of the engine's functionality and the goal of optimizing for **modularity, separation of concerns, and reusability**, the following refined refactoring strategy is recommended. This approach breaks the system into highly focused, potentially reusable components, moving away from reliance on global state and tightly coupled logic.
-
-### Core Component Modules:
-
-1. **`AnimationQueue` (`animation-queue.js`)**
- * **Responsibility**: Solely manage the timing and execution queue for all scheduled animations (primarily text reveal).
- * **Core Functions**: `schedule(func, delay, ...args)`, `fastForward()`, `stop()`, `setSpeed(value)`.
- * **State**: Manages the internal `queue` array, the current `delay` accumulator, and the animation `speed`.
- * **Reusability**: Highly reusable for any system requiring sequenced, timed execution with speed control and interruption.
-
-2. **`TextProcessor` (`text-processor.js`)**
- * **Responsibility**: Encapsulate text pre-processing steps required before layout calculation.
- * **Core Functions**: `process(text)` method that applies typographic enhancements (SmartyPants) and hyphenation (Hyphenopoly).
- * **Dependencies**: Takes instances or functions of the SmartyPants and Hyphenopoly libraries during construction.
- * **Reusability**: Reusable wherever this specific text processing pipeline (SmartyPants + Hyphenopoly) is needed.
-
-3. **`ParagraphLayout` (`paragraph-layout.js`)**
- * **Responsibility**: Interface with the Knuth-Plass line breaking algorithm (`kap` function) to calculate optimal line breaks.
- * **Core Functions**: `calculateLayout(processedText, measures)` method.
- * **Dependencies**: Takes the `kap` function and a `measureText` function (capable of measuring text widths in the target rendering context) during construction.
- * **Reusability**: Reusable in any system needing high-quality paragraph line breaking, provided the `kap` algorithm and a text measurement function are supplied.
-
-4. **`LayoutRenderer` (`layout-renderer.js`)**
- * **Responsibility**: Translate the abstract layout data (from `ParagraphLayout`) into concrete visual elements (DOM nodes in this case). Handle visual tag rendering.
- * **Core Functions**: `renderParagraph(layoutData, measures)` creates positioned DOM elements (e.g., `` for words/tags), applies styles (initial opacity 0), and *uses* `AnimationQueue.schedule` to initiate fade-in animations. `renderVisualTag(tagType, tagData)` handles rendering for `IMAGE`, `BACKGROUND`, `CHAPTER`, `SEPARATOR`, and applying CSS classes.
- * **Dependencies**: Takes an `AnimationQueue` instance and potentially configuration for visual elements.
- * **Reusability**: Moderately reusable. The core logic of translating layout data is reusable, but the specific DOM creation part is tied to HTML/DOM rendering. Could be adapted for other rendering targets (e.g., Canvas).
-
-5. **`AudioManager` (`audio-manager.js`)**
- * **Responsibility**: Manage loading and playback of non-TTS audio effects triggered by tags (e.g., `AUDIO