Dice

An RPG dice rolling app for iOS built with SwiftUI. Originally developed as “DiceRoller,” the project has evolved to include a “Music Mode” with Rest dice features, accessible via a multi-mode navigation interface.

Key Decisions

DecisionRationaleOutcome
SwiftUI only, no UIKitModern framework, cleaner code for new iOS projectsGood — clean declarative UI throughout
iOS 17.0 minimum targetAccess to modern SwiftUI features like @ObservableGood — streamlined development
@MainActor on DiceCollectionThread-safe UI updates for ObservableObjectGood — no concurrency issues
Factory method pattern for DiceRollSeparates data model from roll action via static roll()Good — clean separation of concerns
View component extractionDiceSelectionView, SelectedDiceView, RollResultsView as separate viewsGood — maintainable, reusable
Spring animation (0.3 response, 0.6-0.7 damp)Snappy but smooth feel across all animationsGood — satisfying tactile feedback
Medium impact haptic for roll actionPrimary action gets satisfying physical feedbackGood — enhances UX
AloysiusTheme enum for colorsSingle source of truth for design tokens via hex Color extensionGood — easy visual consistency
Mode-agnostic UniversalRollSupports both standard and music dice results in a shared UIGood — shared UI for roll results
DiceFace protocol for music diceCommon interface for all music dice face types (notes, chords, etc.)Good — extensible music system

Patterns Established

PatternDescriptionReusable
PressableButtonStyleConsistent press feedback on all interactive buttonsYes
Color.init(hex:) extensionHex string to SwiftUI Color conversionYes
AloysiusTheme enum with static colorsCentralized design token systemYes
DiceType CaseIterable enumEnum with computed properties for sides and display nameYes
DiceCollection as ObservableObjectCentralized state for dice selection and rollingYes
Static factory method on DiceRollDiceRoll.roll(_:) creates a roll with random resultYes
MainTabView with AppMode enumTab-based mode switching with Identifiable enumYes

Lessons Learned

LessonContextImpact
DispatchQueue.main.asyncAfter timingState updates while UI shows animationSmooth user experience between action and result
Dashed border for empty state UIVisual invitation for interactivityImproved UX for new users
Conditional bulk-action buttonsOnly show clear-all when 2+ items are presentReduced UI clutter
Gold/accent color for prominent valuesHighlighting primary data points like the total sumBetter visual hierarchy
Legacy color aliases for migrationUsing static aliases to ease theme refactoringSeamless visual transitions during design updates
Repo renames require internal auditRename only affects GitHub; project files and bundle IDs must be updatedPrevents mismatch between repo and app code

Technical Debt

ItemPriorityNotes
Gesture interactions pendingMediumPhase 9 (swipe, long-press, drag) planned but not started
Layout refresh pendingMediumPhase 10 (improved responsiveness) planned but not started
No unit testsLowCodebase growing, may benefit from automated verification
Legacy color aliases in themeLowDeprecated static aliases still present for compatibility