Fifty Narrative Engine
A sentence processing engine for Flutter games and interactive applications. Part of Fifty Flutter Kit.
| Sentence Queue | Dialogue Choices | Narration |
|---|---|---|
![]() |
![]() |
![]() |
Features
- NarrativeEngine - Core processor for in-game sentence execution
- NarrativeInterpreter - Instruction parsing and handler delegation
- NarrativeQueue - Optimized queue with order-based sorting
- SafeNarrativeWriter - Deduplication for idempotent sentence rendering
- BaseNarrativeModel - Abstract interface for custom sentence models
- Complete sentence processing system - Enables narration, player interaction, and navigation control in visual novels, interactive fiction, and narrative games
Installation
Add to your pubspec.yaml:
dependencies:
fifty_narrative_engine: ^0.1.0
Or for local development in the monorepo:
dependencies:
fifty_narrative_engine:
path: ../fifty_narrative_engine
Quick Start
1. Create a Sentence Model
Implement BaseNarrativeModel for your application:
class GameSentence implements BaseNarrativeModel {
@override
final int? order;
@override
final String text;
@override
final String instruction;
@override
final bool waitForUserInput;
@override
final String? phase;
@override
final List<dynamic> choices;
GameSentence({
this.order,
required this.text,
this.instruction = 'write',
this.waitForUserInput = false,
this.phase,
this.choices = const [],
});
}
2. Initialize the Engine
final engine = NarrativeEngine(
onStatusChange: (status) {
print('Engine status: $status');
},
onSentencesChanged: (sentences) {
// Update UI with processed sentences
setState(() {
_displayedSentences = sentences;
});
},
);
3. Create an Interpreter
final interpreter = NarrativeInterpreter(
engine: engine,
onRead: (text) async {
// Text-to-speech
await ttsService.speak(text);
},
onWrite: (sentence) async {
// Add to chat display
engine.addSentenceToWritten(sentence);
},
onAsk: (sentence) async {
// Show question with choices
await showChoiceDialog(sentence);
},
onWait: (sentence) async {
// Wait for user tap
await engine.pauseUntilUserContinues();
},
onNavigate: (sentence) async {
// Navigate to new screen/phase
await navigateToPhase(sentence.phase!);
},
);
engine.registerInterpreter(interpreter);
4. Process Sentences
// Create sentences
final sentences = [
GameSentence(
order: 1,
text: 'Welcome to the adventure!',
instruction: 'read + write',
),
GameSentence(
order: 2,
text: 'Choose your path:',
instruction: 'write',
choices: ['Forest', 'Mountain', 'Sea'],
),
];
// Enqueue and process
engine.enqueue(sentences);
await engine.process(
onComplete: () => print('All sentences processed!'),
onInterrupted: () => print('Processing was interrupted'),
);
Architecture
NarrativeEngine
|
+-- NarrativeQueue
| Order-based sorting, push/pop operations
|
+-- NarrativeInterpreter
| Instruction parsing, handler delegation
|
+-- SafeNarrativeWriter
| Deduplication for idempotent rendering
|
+-- ProcessingStatus
State machine: idle → processing → completed
Core Components
| Component | Description |
|---|---|
NarrativeEngine |
Core processor managing sentence execution flow |
NarrativeInterpreter |
Instruction parser and handler delegator |
NarrativeQueue |
Optimized queue with order-based sorting |
SafeNarrativeWriter |
Deduplication for idempotent sentence rendering |
BaseNarrativeModel |
Abstract interface for custom sentence models |
API Reference
NarrativeEngine
Core processor managing sentence execution flow.
class NarrativeEngine {
// Constructor
NarrativeEngine({
ValueChanged<ProcessingStatus>? onStatusChange,
ValueChanged<List<BaseNarrativeModel>>? onSentencesChanged,
ValueChanged<int>? onProcessingIndexChanged,
NarrativeInterpreter? interpreter,
});
// Getters
List<BaseNarrativeModel> get sentences;
int get processingIndex;
ProcessingStatus get status;
Stream<ProcessingStatus> get onStatusChanged;
// Core Methods
void enqueue(List<BaseNarrativeModel> newSentences);
Future<void> process({VoidCallback? onComplete, VoidCallback? onInterrupted});
// Flow Control
void pause();
void resume();
void cancel();
void reset();
// User Interaction
Future<void> pauseUntilUserContinues();
void continueAfterUserInput();
// Sentence Management
void addSentenceToWritten(BaseNarrativeModel sentence);
void clearProcessedSentences();
// Registration
void registerInterpreter(NarrativeInterpreter interpreter);
// Cleanup
void dispose();
}
ProcessingStatus
Engine state enumeration:
enum ProcessingStatus {
idle, // Not processing
processing, // Actively processing
paused, // Temporarily paused
cancelled, // Cancelled before completion
completed, // All sentences processed
}
NarrativeInterpreter
Instruction parser and handler delegator:
class NarrativeInterpreter {
NarrativeInterpreter({
required NarrativeEngine engine,
Future<void> Function(String text)? onRead,
Future<void> Function(BaseNarrativeModel sentence)? onWrite,
Future<void> Function(BaseNarrativeModel sentence)? onAsk,
Future<void> Function(BaseNarrativeModel sentence)? onNavigate,
Future<void> Function(BaseNarrativeModel sentence)? onWait,
Future<void> Function(BaseNarrativeModel sentence)? onUnhandled,
});
Future<void> interpret(BaseNarrativeModel sentence);
}
Supported Instructions:
| Instruction | Handler | Purpose |
|---|---|---|
read |
onRead |
Text-to-speech output |
write |
onWrite |
Display text on screen |
ask |
onAsk |
Show choices, wait for selection |
wait |
onWait |
Pause until user tap |
navigate |
onNavigate |
Phase-based navigation |
Instructions can be combined: read + write
NarrativeQueue
Optimized queue for large-scale sentence processing:
class NarrativeQueue {
// Push operations
void pushBack(BaseNarrativeModel item);
void pushBackAll(Iterable<BaseNarrativeModel> items);
void pushFront(BaseNarrativeModel item);
void pushFrontAll(Iterable<BaseNarrativeModel> items);
void pushOrdered(BaseNarrativeModel item);
void pushOrderedAll(Iterable<BaseNarrativeModel> items);
// Access
BaseNarrativeModel pop();
BaseNarrativeModel peek();
List<BaseNarrativeModel> toList();
// Management
void clear();
void sortByOrder();
void remove(BaseNarrativeModel item);
void removeWhere(bool Function(BaseNarrativeModel) test);
// Properties
int get length;
bool get isEmpty;
bool get isNotEmpty;
bool contains(BaseNarrativeModel item);
}
SafeNarrativeWriter
Prevents duplicate sentence rendering:
class SafeNarrativeWriter {
SafeNarrativeWriter(Future<void> Function(BaseNarrativeModel) delegate);
Future<void> write(BaseNarrativeModel sentence);
void reset();
}
BaseNarrativeModel
Abstract interface for sentence models:
abstract class BaseNarrativeModel {
int? get order; // Queue sorting order
String get text; // Sentence content
String get instruction; // Processing directive
bool get waitForUserInput;// Pause after processing
String? get phase; // Navigation phase
List<dynamic> get choices;// Choice options
}
Usage Patterns
Tap to Continue
final interpreter = NarrativeInterpreter(
engine: engine,
onWrite: (sentence) async {
engine.addSentenceToWritten(sentence);
},
onWait: (sentence) async {
// Engine will pause until user taps
await engine.pauseUntilUserContinues();
},
);
// In UI
GestureDetector(
onTap: () => engine.continueAfterUserInput(),
child: ChatDisplay(sentences: engine.sentences),
)
Choice System
final interpreter = NarrativeInterpreter(
engine: engine,
onAsk: (sentence) async {
engine.pause();
final choice = await showDialog<String>(
context: context,
builder: (_) => ChoiceDialog(choices: sentence.choices),
);
handleChoice(choice);
engine.resume();
},
);
Phase Navigation
final interpreter = NarrativeInterpreter(
engine: engine,
onNavigate: (sentence) async {
await Navigator.pushNamed(
context,
'/game/${sentence.phase}',
);
},
);
// Sentences with phases
GameSentence(
text: 'You enter the forest...',
instruction: 'write',
phase: 'forest', // Will trigger navigation
)
With TTS Integration
// Using fifty_speech_engine
final speechEngine = FiftySpeechEngine();
final interpreter = NarrativeInterpreter(
engine: engine,
onRead: (text) async {
await speechEngine.speak(text);
},
onWrite: (sentence) async {
engine.addSentenceToWritten(sentence);
},
);
With Audio Engine
import 'package:fifty_audio_engine/fifty_audio_engine.dart';
final interpreter = NarrativeInterpreter(
engine: engine,
onNavigate: (sentence) async {
// Play transition sound
await audioEngine.playSfx('transition.mp3');
// Change BGM for new phase
await audioEngine.playBgm('${sentence.phase}_theme.mp3');
},
);
Order-Based Processing
final queue = NarrativeQueue();
// Sentences added out of order
queue.pushOrdered(GameSentence(text: 'Third', order: 3));
queue.pushOrdered(GameSentence(text: 'First', order: 1));
queue.pushOrdered(GameSentence(text: 'Second', order: 2));
// Will process: First, Second, Third
while (queue.isNotEmpty) {
final sentence = queue.pop();
print(sentence.text);
}
Platform Support
| Platform | Support |
|---|---|
| Android | Yes |
| iOS | Yes |
| macOS | Yes |
| Linux | Yes |
| Windows | Yes |
| Web | Yes |
Fifty Design Language Integration
This package is part of Fifty Flutter Kit:
- Consistent naming - All classes follow Fifty Flutter Kit patterns
- fifty_speech_engine - TTS integration for read instructions
- fifty_audio_engine - Sound effects for navigation transitions
- Compatible packages - Works alongside all Fifty Flutter Kit packages
Migration from erune_narrative_engine
If migrating from the original package:
-
Update import:
// Before import 'package:erune_narrative_engine/erune_narrative_engine.dart'; // After import 'package:fifty_narrative_engine/fifty_narrative_engine.dart'; -
Replace class names:
EruneSentencesEngine->FiftyNarrativeEngine
-
GetX Removal: The
NarrativeEngineno longer extendsGetxController. Use the callback parameters instead:// Before (with GetX) final engine = Get.put(NarrativeEngine()); engine.sentences; // RxList // After (callbacks) final engine = NarrativeEngine( onSentencesChanged: (sentences) => setState(() {}), ); engine.sentences; // Regular List
Version
0.1.0
License
MIT License - see LICENSE for details.
Part of Fifty Flutter Kit.
Libraries
- data/base_sentence
- data/sentence_queue
- engine/narrative_engine
- engine/sentence_interpreter
- engine/sentence_writer
- fifty_narrative_engine
- Fifty Narrative Engine - A sentence processing engine for games and interactive applications.
- fifty_narrative_engine_method_channel
- fifty_narrative_engine_platform_interface
- fifty_narrative_engine_web


