Checkpoint current interactive fiction state

This commit is contained in:
2026-05-14 21:17:43 +02:00
parent c745efd1d2
commit 873049f7e6
183 changed files with 13755 additions and 1459 deletions
+83 -13
View File
@@ -13,10 +13,15 @@ class TextBufferModule extends BaseModule {
this.processingLock = false;
this.processingQueue = [];
this.isProcessingActive = false;
this.paragraphCounter = 0;
this.currentTextBlockId = 0;
this.markupParser = null;
this.dependencies = ['markup-parser'];
// Bind methods using parent's bindMethods utility
this.bindMethods([
'addText',
'splitIntoParagraphs',
'processNextFromQueue',
'processSentences',
'processNextSentence',
@@ -33,6 +38,11 @@ class TextBufferModule extends BaseModule {
*/
async initialize() {
try {
this.markupParser = this.getModule('markup-parser');
if (!this.markupParser) {
console.warn("TextBuffer: Markup parser not found, using plain paragraph splitting");
}
// Use parent's addEventListener for automatic cleanup
this.addEventListener(document, 'ui:paragraph:complete', (event) => {
if (this.processingQueue.length > 0 && !this.isProcessingActive) {
@@ -83,9 +93,39 @@ class TextBufferModule extends BaseModule {
if (!text) return;
console.log(`TextBuffer: Adding text: "${text.substring(0, 50)}${text.length > 50 ? '...' : ''}"`);
// Add to processing queue instead of directly to buffer
this.processingQueue.push(text);
const blocks = this.markupParser && typeof this.markupParser.parse === 'function'
? this.markupParser.parse(text)
: this.splitIntoParagraphs(text).map(paragraphText => ({
type: 'paragraph',
text: paragraphText,
layoutText: paragraphText,
cueMarkers: [],
role: 'body',
isFirstParagraphInChapter: false
}));
blocks.forEach(block => {
if (block.type === 'paragraph') {
const paragraphId = `paragraph-${this.paragraphCounter + 1}`;
this.processingQueue.push({
...block,
id: paragraphId,
paragraphIndex: this.paragraphCounter,
textBlockId: this.currentTextBlockId
});
this.paragraphCounter += 1;
} else {
this.processingQueue.push({
...block,
id: `${block.type}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
});
if (block.type === 'image') {
this.currentTextBlockId += 1;
}
}
});
// Process the queue if not already processing
if (!this.isProcessingActive && this.onSentenceReadyCallback) {
@@ -94,6 +134,20 @@ class TextBufferModule extends BaseModule {
console.log('TextBuffer: Text queued for processing');
}
}
/**
* Split an incoming narrative fragment into book paragraphs.
* Single newlines inside a paragraph are normalized to spaces; blank lines
* mark distinct paragraphs.
* @param {string} text - Raw text fragment
* @returns {Array<string>} - Normalized paragraph strings
*/
splitIntoParagraphs(text) {
return String(text)
.split(/\n\s*\n/g)
.map(paragraph => paragraph.replace(/\s*\n\s*/g, ' ').trim())
.filter(Boolean);
}
/**
* Process the next text fragment from the queue
@@ -104,18 +158,32 @@ class TextBufferModule extends BaseModule {
}
this.isProcessingActive = true;
const text = this.processingQueue.shift();
const paragraph = this.processingQueue.shift();
console.log(`TextBuffer: Processing next fragment from queue, remaining: ${this.processingQueue.length}`);
// Add text to buffer
this.buffer += text;
// If we have a trailing newline as a complete sentence, add a period
this.buffer = this.buffer.replace(/\n$/g, '.\n');
// Process sentences
this.processSentences();
this.buffer = paragraph.text;
super.dispatchEvent('buffer:sentence', {
sentence: paragraph.text,
paragraph,
remaining: this.processingQueue.length
});
if (this.onSentenceReadyCallback) {
this.onSentenceReadyCallback(paragraph, () => {});
this.buffer = '';
this.isProcessingActive = false;
this.processingLock = false;
if (this.processingQueue.length > 0) {
queueMicrotask(() => this.processNextFromQueue());
} else {
super.dispatchEvent('buffer:empty', {});
}
} else {
this.isProcessingActive = false;
}
}
/**
@@ -238,6 +306,8 @@ class TextBufferModule extends BaseModule {
this.processingQueue = [];
this.isProcessingActive = false;
this.processingLock = false;
this.paragraphCounter = 0;
this.currentTextBlockId = 0;
}
/**