Quest-Forge

An interactive dark fantasy narrative adventure for iOS 17+ with choice-based gameplay, character selection, branching storylines, procedural audio, and session persistence. Pure SwiftUI with zero third-party dependencies. v1.4 shipped — maintenance mode.

Overview

Quest-Forge is a choice-based narrative game where players select characters and navigate branching story scenarios in a dark fantasy setting. The game engine uses a dictionary-based scene graph ([String: StoryScene]) for O(1) lookups with human-readable snake_case scene IDs, making content authoring natural. The app shipped through phases 1–15 across milestones v1.0–v1.4, adding character-specific branching (v1.0), typewriter text animation via Combine Timer (v1.1), achievements and persistence (v1.3), and procedural audio soundscapes via AVAudioEngine (v1.4).

GitHub: irishrocker1125/Quest-Forge

Tech Stack

TechnologyVersionPurpose
Swift5.9+Primary language — @MainActor, modern concurrency
SwiftUIiOS 17+Declarative UI, navigation, animations
CombineSystemTimer.publish for typewriter animation
AVFoundationSystemAVAudioEngine for procedural soundscapes and SFX
FoundationSystemCodable models, JSON persistence to Documents directory
Xcode15+Build system / IDE

No external packages. Zero third-party dependencies.

Architecture

MVVM with GameState as central @MainActor ObservableObject. All screens use fullScreenCover for immersive chrome-free presentation. Services (HapticManager, AudioManager, PersistenceManager) use singleton pattern with lazy initialization.

Key Decisions

DecisionRationaleOutcome
SwiftUI nativeClean stack matches iOS-only scopeGood
Choice-based input onlyReduces complexity, maintains narrative flowGood
No save states in v1Simplifies architecture, sessions are short by designGood (revisiting in v1.1)
Dark fantasy primary toneSets atmospheric foundation, can expand laterGood
StoryScene namingAvoid SwiftUI Scene collisionGood
Theme-prefixed colorsAvoid Xcode asset symbol conflictsGood
fullScreenCover for game/selectionImmersive experience without nav chromeGood
String IDs for scenesHuman-readable story authoringGood
Combine Timer.publishSwiftUI-compatible animations without retain cyclesGood
0.25s fade timingQuick but visible scene transitionsGood
SampleStory.all patternEnables iteration over all scenariosGood
requiredCharacterIds on ChoiceCharacter-specific content without fragmenting storiesGood
Optional discoveries (pendant)Rewards exploration, affects later pathsGood
Named NPCs (Lyra Shadowmend)Emotional weight to backstory revealsGood
Genre-bending scenariosHeist + cosmic horror differentiates contentGood

Patterns Established

PatternDescriptionReusable
String scene IDsHuman-readable story graph navigationYes
Choice-based branchingSimple but effective narrative structureYes
Theme-prefixed assetsAvoid Xcode symbol conflictsYes
fullScreenCover for immersionModal presentation for game screensYes
Timer-based animationsCombine for SwiftUI-compatible timingYes

Lessons Learned

LessonImpactRecommendation
String IDs are human-friendlyStory authoring is more naturalUse strings over UUIDs for narrative content
Prefix theme colorsXcode assets can conflictAlways namespace asset names
Short sessions justify no savesReduced scope significantlyScope to session length early