Little Why's

March 1, 2026 · View on GitHub

Little Why's is an interactive curiosity-driven learning app for children, designed as a Swift Student Challenge submission. It presents everyday scientific phenomena as explorable questions, pairing short plain-language explanations with hands-on SwiftUI interactions so children can discover answers by doing rather than reading.


Overview

Children encounter the world through questions. Little Why's turns those questions into structured, playful experiences. Each entry in the app is a "why" question — such as "Why does the sky look blue?" or "Why does ice melt?" — answered through animated interactions that model the underlying physics or natural process.

The app is built entirely in Swift Playgrounds / Xcode using SwiftUI and requires no server, no login, and no external dependencies.


Features

  • Discovery Feed — A scrollable card-based feed that surfaces questions grouped by category. Featured questions appear as hero cards with full-bleed illustrations.
  • Category Browser — Questions are organised into five themes: Sky & Weather, Light & Shadows, Water & Ice, Sound & Vibration, and Movement & Forces.
  • Interactive Explanations — Each question has a dedicated detail view that launches a live SwiftUI interaction illustrating the science. Interactions include rain simulation, cloud movement, shadow casting, sunset colour modelling, ice melt, echo visualisation, drum vibration, leaf and gravity physics, magnet attraction, mirror reflection, and a Newton disk.
  • Parent Notes — Selected questions include a brief note for a parent or caregiver with suggestions for extending the conversation.
  • Saved Questions — Users can bookmark questions and revisit them from a dedicated saved list.
  • Haptic Feedback — Light haptics reinforce interactive moments throughout the app.
  • Intro Experience — An animated introduction eases new users into the app on first launch.

Requirements

RequirementValue
PlatformiOS 26.0 or later, iPadOS 26.0 or later
SwiftSwift 6
XcodeSwift Playgrounds 4+ or Xcode 16+
Bundle identifiercom.anksraw.app

Project Structure

little-whys.swiftpm/
├── Package.swift                  # Swift package manifest
├── Assets.xcassets/               # App icon, accent colours, and per-question illustrations
├── Core/
│   ├── MyApp.swift                # App entry point; configures global navigation bar typography
│   ├── ContentView.swift          # Root view; orchestrates intro, feed, and detail layers
│   └── HapticManager.swift        # Centralised haptic feedback helpers
├── Extensions/
│   └── Extensions.swift           # SwiftUI and Foundation convenience extensions
├── Models/
│   ├── WhyQuestion.swift          # Core data model: WhyQuestion, Category, InteractionType
│   ├── CategoryDataset.swift      # Static dataset of browse-mode questions by category
│   └── StoredDataset.swift        # Persistence helpers for saved/viewed state
├── Views/
│   ├── IntroView.swift            # Animated launch and onboarding screen
│   ├── DiscoveryFeedView.swift    # Main scrollable question feed
│   ├── QuestionDetailView.swift   # Per-question detail with explanation and interaction
│   ├── CategoryDetailView.swift   # Category-filtered question list
│   ├── LearnView.swift            # Extended learning content
│   ├── SavedView.swift            # Bookmarked questions list
│   ├── InteractionRouter.swift    # Routes each InteractionType to the correct interaction view
│   ├── ContextualStripView.swift  # Bottom strip showing contextual category info
│   ├── HighlightedTextView.swift  # Attributed text renderer for bolded keywords
│   ├── ParentNoteView.swift       # Parent / caregiver contextual note overlay
│   ├── LoopingVideoPlayer.swift   # AVPlayer wrapper for seamless looping videos
│   ├── VoiceWaveformView.swift    # Animated waveform used in echo and sound interactions
│   ├── GravityGlobeView.swift     # SpriteKit-backed gravity simulation globe
│   ├── GlassJarView.swift         # Stylised glass jar component used in ice-melt interaction
│   ├── AbacusView.swift           # Abacus counting visual component
│   ├── HexBadge.swift             # Hexagonal category badge component
│   ├── RoundedHexagon.swift       # Reusable rounded hexagon shape
│   ├── PremiumGoldSparkle.swift   # Particle sparkle effect for featured cards
│   └── WfApodCard.swift           # Wide-format card layout component
├── Interactions/
│   ├── RainInteraction.swift      # Animated rain particle interaction
│   ├── CloudsInteraction.swift    # Drifting cloud movement interaction
│   ├── ShadowInteraction.swift    # Drag-to-cast shadow interaction
│   ├── SunsetInteraction.swift    # Sky colour gradient transition interaction
│   ├── IceMeltInteraction.swift   # Time-lapse ice melt simulation
│   ├── EchoInteraction.swift      # Sound wave bounce visualisation
│   ├── DrumInteraction.swift      # Tap-to-vibrate drum skin interaction
│   ├── LeavesInteraction.swift    # Wind-driven leaf physics interaction
│   ├── MagnetismInteraction.swift # Magnet attraction field interaction
│   ├── NewtonDiskInteraction.swift# Spinning Newton disk colour-merge interaction
│   ├── GravityInteraction.swift   # Projectile gravity arc interaction
│   └── Typography.swift           # Shared text styles used across interaction views
├── GameAssets/                    # SpriteKit and game-related asset resources
└── Videos/                        # Looping MP4 assets used by LoopingVideoPlayer

Architecture

The app follows a single-source-of-truth pattern using SwiftUI state.

  • State flowContentView owns selectedQuestion as a @State binding that is passed down the view hierarchy. Selecting a question from the feed sets this binding; dismissing the detail view clears it.
  • ModelsWhyQuestion is a plain Swift struct. Category and InteractionType are enums. There is no external persistence framework; bookmarks and viewed-question tracking are stored in @AppStorage.
  • Interactions — Each interaction is a self-contained SwiftUI view. InteractionRouter acts as a switch that instantiates the correct interaction view from the InteractionType on a given question.
  • Swift 6 concurrency — The package declares swiftLanguageVersions: [.version("6")]. All state mutations that cross actor boundaries are handled via @MainActor or structured concurrency.

Getting Started

  1. Clone the repository.

    git clone https://github.com/savetree-1/little-whys-swift.git
    
  2. Open little-whys.swiftpm in Swift Playgrounds 4 on an iPad or iPhone, or in Xcode 16 on a Mac.

  3. Select an iOS 26 simulator or a connected device running iOS 26.

  4. Run the app. No additional configuration is required.


Downloads

https://github.com/user-attachments/assets/bf18ea47-abbf-42db-a409-771dc754c0e3


License

This project was created as a Swift Student Challenge submission. All source code is provided for educational and portfolio purposes.