A SwiftUI implementation of Peblo's AI Story Buddy & Quiz Component challenge. The application narrates a short story using native iOS Text-to-Speech and then presents a data-driven interactive quiz in a child-friendly interface.
I chose SwiftUI because it provides declarative UI development, reactive state management, smooth animations, and seamless integration with AVFoundation. The project follows a lightweight MVVM architecture to keep UI, business logic, and services separated.
The application follows a state-driven flow:
Idle
↓
Preparing
↓
Playing Story
↓
Story Completed
↓
Quiz Appears
↓
Success State
AVSpeechSynthesizerDelegate is used to detect when narration finishes. Once the completion callback is received, the ViewModel updates the state and reveals the quiz with animation. The interface automatically scrolls to the quiz section, helping guide the user through the experience.
The quiz is generated from JSON instead of hardcoded UI.
Example JSON:
{
"question": "What colour was Pip the Robot's lost gear?",
"options": ["Red", "Green", "Blue", "Yellow"],
"answer": "Blue"
}The options are rendered dynamically using:
ForEach(quiz.options, id: \.self)This allows the application to support future questions with different text and different option counts (3, 4, 5, or more) without requiring any UI changes.
The current implementation uses Apple's native AVSpeechSynthesizer, which generates speech locally on the device. Since no audio files are downloaded, explicit audio caching is not required.
If a remote TTS service such as ElevenLabs were used, generated audio files would be cached locally using the file system and reused when available. This would reduce network requests, loading times, and repeated API usage.
Before narration begins, the application enters a preparing state and displays:
🤖 Pip is preparing your story...
This provides immediate feedback and prevents the interface from feeling unresponsive.
A dedicated error state is implemented in the ViewModel:
case error(String)If narration fails, the user is shown a friendly error message along with a Try Again button. This allows the user to recover without restarting the application.
Performance was reviewed using Xcode Instruments (Time Profiler) while testing the complete user flow:
- Story narration
- Quiz appearance
- Wrong answer feedback
- Success state transition
The UI remained smooth and responsive throughout testing. Animations, scrolling, and state transitions showed no noticeable frame drops or stutters. A performance screenshot has been included with the submission.
The application was designed to remain lightweight and responsive:
- Native Text-to-Speech instead of remote audio generation
- Minimal view hierarchy
- State-driven UI updates
- Lightweight animations
- Dynamic JSON rendering
- No unnecessary network requests
- Small asset footprint
These decisions help keep memory usage and processing overhead low while maintaining a smooth user experience.
AI assistance was used for:
- SwiftUI implementation guidance
- Architecture discussions
- Debugging support
- UI refinement ideas
- Documentation assistance
One suggestion was to hardcode the quiz UI for the provided question. This approach was rejected because the challenge explicitly required a data-driven solution capable of supporting future questions with different option counts and content.
Initially, the quiz appeared before the storytelling flow felt complete. This was resolved by revealing the quiz only after receiving the Text-to-Speech completion callback and improving the experience with automatic scrolling and delayed success transitions.
Arjun