Good Night Tales™

App website | iOS App Store


Starting with zero iOS or Swift experience, Good Night Tales was developed by myself over the course of 16 months. It features a domain-specific video compression scheme, able to store 20 minutes of video in only 140 MB. It includes a fully custom video player that supports highly dynamic playback, including personalization through customizable elements and randomizing elements of videos to increase variety during replays.


Nearly every aspect of the UI is animated in some way or another. Whether that’s the fluid motion of the custom book list view, seamlessly sliding a book from the story selector to the detail screen, or sliding controls onto or off of the screen, they all serve to give the app a character of its own.


The app features an entirely custom video player, with controls that are invoked by a swipe-up gesture from the bottom of the screen, keeping a child’s idle fingers from accidentally opening them. The player can toggle both subtitles and the narration track, allowing parents the option to read along with their children.


The video player has analytics out the wazoo, including but not limited to:

  • The local time when the story was played
  • The amount of time the story took to load
  • The amount of battery charge that was drained while playing
  • The brightness of the screen during playback
  • A heatmap of how many times parts of the video were viewed
  • A heatmap of the app memory usage while playing the video

Due to the limitations of the analytics frameworks we used, the largest amount of data a property can have is a 100-character string, so all heatmaps are stored as strings where each character stores a value corresponding to a portion of the video.



One thing many people who have built apps will know is how annoying resizing master assets to the required 1x/2x/3x resolutions can be. After having it nag me for a while I realized an easy solution that required very little logic at all. After using the asset name to find the respective master image file, the script would read the sizes of all the existing images, scale the master to those sizes, then replace them. XCAssetMaster is the implementation of this idea.