Product

Grimoire — A lightweight songwriting App

Grimoire — A lightweight songwriting App

Grimoire — A lightweight songwriting App

Tools

Figma

Cursor

Xcode

Figma

Cursor

Xcode

Figma

Cursor

Xcode

Tech Stack

SwiftUI DSwaveformImage

Lottie

SwiftUI DSwaveformImage

Lottie

SwiftUI

DSwaveformImage

Lottie

Goals

Provide songwriters with a seamless way to write song lyrics on their iPhones.

Provide songwriters with a seamless way to write song lyrics on their iPhones.

Provide songwriters with a seamless way to write song lyrics on their iPhones.

My Role

Designed in Figma and built with Cursor and Xcode. Grimoire is an iOS songwriting app that allows users to attach audio files to a notepad, loop sections of music, and organize songs into folders. This enables a seamless songwriting experience that reduces friction and supports creative flow.

Designed in Figma and built with Cursor and Xcode. Grimoire is an iOS songwriting app that allows users to attach audio files to a notepad, loop sections of music, and organize songs into folders. This enables a seamless songwriting experience that reduces friction and supports creative flow.

Designed in Figma and built with Cursor and Xcode. Grimoire is an iOS songwriting app that allows users to attach audio files to a notepad, loop sections of music, and organize songs into folders. This enables a seamless songwriting experience that reduces friction and supports creative flow.

Building with AI

Building with AI

The initial plan was to build this with React Native and CocaPods, I quickly realized that wasn't ideal an instead switch to a SwiftUI build for more control over audio playback. Together with Figma MCP and Cursor I was able to build a working prototype quickly, the app is now in the process of being deployed to the App store.

The initial plan was to build this with React Native and CocaPods, I quickly realized that wasn't ideal an instead switch to a SwiftUI build for more control over audio playback. Together with Figma MCP and Cursor I was able to build a working prototype quickly, the app is now in the process of being deployed to the App store.

The initial plan was to build this with React Native and CocaPods, I quickly realized that wasn't ideal an instead switch to a SwiftUI build for more control over audio playback.


Together with Figma MCP and Cursor I was able to build a working prototype quickly, the app is now in the process of being deployed to the App store.

Outcomes

Shipped a working beta to 12 early testers, receiving feedback on clarity and usability.

Shipped a working beta to 12 early testers, receiving feedback on clarity and usability.

Shipped a working beta to 12 early testers, receiving feedback on clarity and usability.

92% of users said looping felt “more intuitive” than their current setup.

92% of users said looping felt “more intuitive” than their current setup.

92% of users said looping felt “more intuitive” than their current setup.

Discovered an opportunity to evolve into a full song draft manager, potentially including cloud sync and version history.

Discovered an opportunity to evolve into a full song draft manager, potentially including cloud sync and version history.

Discovered an opportunity to evolve into a full song draft manager, potentially including cloud sync and version history.

Problem Space

Problem Space

When songwriting, many tools outside of pen and paper can be distracting. Many iOS users rely on the native Notepad app, but it lacks key features that would make it ideal for writing with music.

Solutions

Solutions

Import and attach audio directly to a notepad.

Import and attach audio directly to a notepad.

Loop specific audio segments for detailed lyric writing or melody matching.

Loop specific audio segments for detailed lyric writing or melody matching.

Organize songs into folders, enabling structured songwriting sessions across projects.

Organize songs into folders, enabling structured songwriting sessions across projects.

Research & Discovery

To validate the opportunity, I interviewed musicians and songwriters ranging from bedroom producers to professional artists. Key insights:

"I mainly use the native iPhone notepad because you can play music in it."
"The notepad app has an audio player but it doesn't have a looping feature to make writing hooks easier."
"Having a digital version of my song lyrics makes it easier to upload them to website like Genius."

Key Features

Key Features

🎼 Audio + Notepad

Users can attach local and cloud based audio files and playback their music while writing lyrics.

🔁 Looping Engine

Implemented custom loop points users can drag and reset, supporting precise section focus.

🗂 Folder System

Inspired by file managers, users can create folders, move songs, and collapse lists for clean navigation.

Icon

Icon

A simple but eye grabbing icon was chosen for the app, I wanted something that could be easily located when opening up your phone.

A simple but eye grabbing icon was chosen for the app, I wanted something that could be easily located when opening up your phone.

Photo

Adding a Song

Adding a Song

Users can quickly browse local and cloud based files and attach them to song sessions.

Users can quickly browse local and cloud based files and attach them to song sessions.

Photo

Music Player

Music Player

As a key touchpoint of the app I wanted the music player to be easy to use but also subtle.

Considering responsiveness I opted to simply the player from earlier version to ensure screen compatibility.

As a key touchpoint of the app I wanted the music player to be easy to use but also subtle.

Considering responsiveness I opted to simply the player from earlier version to ensure screen compatibility.

Photo
Photo

Resident Profiles

Resident Profiles

Data is key for proper resident management, this page serves as the center for internal users. I made sure to present data in a manageable way for the users.

Data is key for proper resident management, this page serves as the center for internal users. I made sure to present data in a manageable way for the users.

Photo

Design Tokens

Design Tokens

As a key touchpoint of the app I wanted the music player to be easy to use but also subtle.

Photo

Font Tokens

struct DesignTokens {
    // Brand color - stays consistent across themes
    static let brandColor = Color(red: 0.941, green: 0.408, blue: 0.220) // #F06838
    
    // Typography - Dynamic Type support using text styles
    // These automatically scale with user's preferred text size
    static let headingFont = Font.system(.largeTitle, design: .rounded).weight(.bold)
    static let bodyFont = Font.system(.body, design: .rounded).weight(.regular)
    static let subheadingFont = Font.headline.weight(.semibold)
    static let songTitleFont = Font.headline.weight(.semibold)
    static let songSnippetFont = Font.subheadline.weight(.regular)
    
    // Additional Dynamic Type fonts for specific UI elements
    static let headerTitleFont = Font.system(.headline, design: .rounded).weight(.semibold)
    static let buttonFont = Font.body.weight(.semibold)
    static let captionFont = Font.caption.weight(.regular)
    static let footnoteFont = Font.footnote.weight(.regular)
    static let settingsTitleFont = Font.subheadline.weight(.semibold)
    static let settingsSubtitleFont = Font.footnote.weight(.regular)
    static let settingsSectionFont = Font.caption.weight(.medium)
    static let upgradeButtonFont = Font.body.weight(.semibold)
    static let featureTitleFont = Font.subheadline.weight(.medium)
    static let featureSubtitleFont = Font.subheadline.weight(.regular)
    static let timeDisplayFont = Font.caption.weight(.medium).monospaced()
    static let musicPlayerTitleFont = Font.system(.caption, design: .default).weight(.medium)
    static let lyricEditorFont = Font.body.weight(.regular)
    static let placeholderFont = Font.body.weight(.regular)
    static let errorFont = Font.caption2.weight(.regular)
    
    // For cases where we need custom sizing with Dynamic Type support
    static func customFont(style: Font.TextStyle, weight: Font.Weight = .regular, design: Font.Design = .default) -> Font {
        Font.system(style, design: design).weight(weight)
struct DesignTokens {
    // Brand color - stays consistent across themes
    static let brandColor = Color(red: 0.941, green: 0.408, blue: 0.220) // #F06838
    
    // Typography - Dynamic Type support using text styles
    // These automatically scale with user's preferred text size
    static let headingFont = Font.system(.largeTitle, design: .rounded).weight(.bold)
    static let bodyFont = Font.system(.body, design: .rounded).weight(.regular)
    static let subheadingFont = Font.headline.weight(.semibold)
    static let songTitleFont = Font.headline.weight(.semibold)
    static let songSnippetFont = Font.subheadline.weight(.regular)
    
    // Additional Dynamic Type fonts for specific UI elements
    static let headerTitleFont = Font.system(.headline, design: .rounded).weight(.semibold)
    static let buttonFont = Font.body.weight(.semibold)
    static let captionFont = Font.caption.weight(.regular)
    static let footnoteFont = Font.footnote.weight(.regular)
    static let settingsTitleFont = Font.subheadline.weight(.semibold)
    static let settingsSubtitleFont = Font.footnote.weight(.regular)
    static let settingsSectionFont = Font.caption.weight(.medium)
    static let upgradeButtonFont = Font.body.weight(.semibold)
    static let featureTitleFont = Font.subheadline.weight(.medium)
    static let featureSubtitleFont = Font.subheadline.weight(.regular)
    static let timeDisplayFont = Font.caption.weight(.medium).monospaced()
    static let musicPlayerTitleFont = Font.system(.caption, design: .default).weight(.medium)
    static let lyricEditorFont = Font.body.weight(.regular)
    static let placeholderFont = Font.body.weight(.regular)
    static let errorFont = Font.caption2.weight(.regular)
    
    // For cases where we need custom sizing with Dynamic Type support
    static func customFont(style: Font.TextStyle, weight: Font.Weight = .regular, design: Font.Design = .default) -> Font {
        Font.system(style, design: design).weight(weight)

Looping in Action

Looping in Action

Keeping the timestamps while customizing the loop was a top ask from beta testers.

Keeping the timestamps while customizing the loop was a top ask from beta testers.

Photo

Next Steps

Launch on app store in Q3.

Launch on app store in Q3.

Launch on app store in Q3.

Build backend structure and

Build backend structure and

Build backend structure and

Expand notepad features with annotations, and maybe add social aspect if userbase allows for it.

Expand notepad features with annotations, and maybe add social aspect if userbase allows for it.

Expand notepad features with annotations, and maybe add social aspect if userbase allows for it.