UI Specification: Photo Capture & Entry Creation Flow
Date: 2025-11-10 Version: 1.0 Author: Product Designer Status: Phase 2 - Awaiting Approval Platform: iOS-native feel (Flutter implementation) Devices: iPhone 15/16/17 (390-430pt width)Overview
This document specifies the complete UI design for the Photo Capture & Entry Creation Flow - the core 60-second user experience that defines the product. This flow is triggered when users want to create a new journal entry and guides them from photo selection through to saving a completed memory. Design Principles for Entry Creation:- Effortless: 80% of entries completed in under 60 seconds
- AI-Guided: Intelligent suggestions reduce cognitive load
- Delightful: Micro-animations and celebrations make journaling feel rewarding
- Forgiving: Clear error states, easy recovery, no data loss
- Accessible: WCAG 2.1 AA compliant, Dynamic Type support, VoiceOver ready
- Photo capture/selection: 10 seconds
- AI prompts load: 10 seconds (with engaging loading state)
- Select prompt + write text: 30 seconds
- Tag emotions: 5 seconds
- Save: 5 seconds
Screen 1: Entry Creation (Choose Photo Source)
Purpose
Present users with a clear choice between taking a new photo or selecting from their library. This is a decision point, not a complex screen.User Journey
- Entry Point:
- Timeline → Tap FAB (+ button)
- Timeline Empty State → Tap “Create Your First Memory”
- Tab Bar → Tap center ”+” tab
- Exit Point:
- Tap “Take Photo” → In-App Camera (Screen 2)
- Tap “Choose from Library” → Photo Picker (Screen 4)
- Swipe down or tap “Cancel” → Return to Timeline
Layout Structure (Light Mode)
Components Used
1. Bottom Sheet Container
- Component: iOS native bottom sheet (UIModalPresentationFormSheet style in Flutter)
- Presentation: Slide up from bottom with backdrop dim
- Backdrop: 40% black overlay (#000000 at 0.4 opacity)
- Height: Auto (content-driven, approximately 360pt)
- Background:
- Light Mode: Off-White (#F9FAFB)
- Dark Mode: Elevated Surface (#2C3135)
- Border Radius: 16pt (top corners only)
- Shadow: Level 2 (raised)
- Light Mode: rgba(0, 0, 0, 0.12), offset (0, 2pt), blur 8pt
- Dark Mode: rgba(0, 0, 0, 0.06), offset (0, 2pt), blur 8pt
- Padding: 24pt internal padding (all sides)
- Safe Area: Respects bottom home indicator
2. Drag Handle
- Component: Visual indicator for swipe-to-dismiss
- Dimensions: 36×4pt
- Position: Centered horizontally, 12pt from top of sheet
- Color:
- Light Mode: Light Gray (#DFE6E9)
- Dark Mode: Dark Gray (#3C4347)
- Border Radius: 2pt (pill shape)
- Accessibility: VoiceOver “Drag to dismiss” hint
- Interaction: Swipe down to dismiss sheet
3. Title
- Component: Text (Title 2 style)
- Text: “Add a Photo”
- Typography:
- Font: SF Pro Display, 22pt Bold
- Line Height: 28pt
- Letter Spacing: 0.35pt
- Alignment: Center
- Color:
- Light Mode: Charcoal (#2D3436)
- Dark Mode: Off-White (#F5F6FA)
- Position: 32pt from top of sheet (below handle)
- Accessibility: VoiceOver “Add a Photo, heading”
4. Option Card 1: Take Photo
Card Container:- Dimensions: Full-width minus padding (342pt on iPhone 15)
- Height: 100pt
- Border Radius: 12pt
- Background:
- Light Mode: White (#FFFFFF)
- Dark Mode: Elevated Surface (#2C3135)
- Border: 1pt solid
- Light Mode: Light Gray (#DFE6E9)
- Dark Mode: Dark Gray (#3C4347)
- Shadow: None (flat in bottom sheet)
- Position: 24pt below title
- Layout: Horizontal (icon on left, text on right)
- Icon: SF Symbol
camera.fillor custom camera icon - Size: 48×48pt
- Color: Primary Coral (#FF6B6B in Light, #FF8787 in Dark)
- Position: 16pt from leading edge, vertically centered
- Background: Circular container
- Dimensions: 64×64pt circle
- Background: Primary Coral at 10% opacity
- Border Radius: 32pt
- Text: “Take Photo”
- Typography: SF Pro Text, 17pt Semibold
- Color: Charcoal (Light) / Off-White (Dark)
- Position: 16pt to the right of icon, vertically centered
- Text: “Capture a new moment”
- Typography: SF Pro Text, 15pt Regular
- Color: Slate Gray (Light) / Light Gray (Dark)
- Position: Below label, 4pt gap
- Default: White background, border visible
- Hover (iPad): Background 5% darker
- Pressed: Background 10% darker, scale 0.98 (100ms ease-in-out)
- Focus: 2pt blue focus ring
- VoiceOver: “Take Photo, Capture a new moment, button”
- Touch Target: Full card (100pt height)
5. Option Card 2: Choose from Library
Same specifications as Option Card 1, with differences: Library Icon:- Icon: SF Symbol
photo.on.rectangle.fillor custom library icon - Color: Deep Teal (#4ECDC4 in Light, #6FE0D8 in Dark)
- Background: Deep Teal at 10% opacity
- Text: “Choose from Library”
- Text: “Select an existing photo”
- VoiceOver: “Choose from Library, Select an existing photo, button”
6. Cancel Button
- Component: Text Button
- Text: “Cancel”
- Typography: SF Pro Text, 16pt Regular
- Color: Primary Coral (#FF6B6B in Light, #FF8787 in Dark)
- Position: 24pt below Option Card 2, centered
- Touch Target: Full width, 44pt height
- States:
- Default: Coral text
- Pressed: 20% darker coral, 0.8 opacity (100ms)
- Action: Dismiss bottom sheet, return to Timeline
- Accessibility: VoiceOver “Cancel, button”
Responsive Behavior
iPhone SE (320pt width):- Cards: Full-width minus 32pt margins (16pt each side)
- Icon size: 40×40pt
- Icon container: 56×56pt
- Adjust padding to 16pt
- Layout as shown
- Cards: Max-width 400pt (centered in sheet)
- More generous padding (28pt)
Interactive States & Animations
Bottom Sheet Appear Animation
Duration: 300ms Curve: ease-out Sequence:- Backdrop fades in (0 → 0.4 opacity)
- Sheet slides up from bottom (translateY: +100% → 0)
- Content fades in with slight delay (50ms)
Bottom Sheet Dismiss Animation
Duration: 250ms Curve: ease-in Triggers:- Swipe down on drag handle
- Tap Cancel
- Tap backdrop
- Tap an option (dismiss after navigation)
Card Press Animation
Duration: 100ms Curve: ease-in-out Behavior: Scale 0.98, background darkens 10%Option Selected
Duration: 250ms Sequence:- Card press animation completes
- Sheet dismisses
- Navigate to next screen (camera or photo picker)
Accessibility
WCAG 2.1 AA Compliance:- ✅ Color Contrast: All text meets 4.5:1 minimum
- ✅ Touch Targets: Cards 100pt height, Cancel button 44pt
- ✅ Focus Indicators: 2pt blue ring on cards when focused
- ✅ Dynamic Type: All text scales appropriately
- “Add a Photo, heading”
- “Take Photo, Capture a new moment, button”
- “Choose from Library, Select an existing photo, button”
- “Cancel, button”
- Swipe down: Dismiss sheet
- Tap backdrop: Dismiss sheet
- VoiceOver magic tap: Dismiss sheet
Content Guidelines
Title:- Short, clear action (2-4 words)
- “Add” not “Upload” (warmer language)
- 20-30 characters
- Action-oriented (verb + noun)
- “Take” not “Capture” for camera (more casual)
- 40-60 characters
- Benefit-focused, not feature-focused
Edge Cases
Camera Permission Denied:- Tapping “Take Photo” shows alert:
- Title: “Camera Access Required”
- Message: “To capture photos, please enable camera access in Settings.”
- Actions: “Open Settings” (opens iOS Settings), “Cancel”
- Alert uses iOS native style
- Tapping “Choose from Library” shows alert:
- Title: “Photo Library Access Required”
- Message: “To select photos, please enable photo library access in Settings.”
- Actions: “Open Settings”, “Cancel”
- Both options are still visible (don’t hide)
- Tapping shows appropriate permission dialog
- “Choose from Library” works but only shows selected photos
- Show hint in library picker: “You’ve granted limited access. Tap to select more photos.”
Design Tokens Used
Colors:colors.primary.coral(#FF6B6B / #FF8787)colors.accent.teal(#4ECDC4 / #6FE0D8)colors.neutral.background.surface(Off-White / Elevated Surface)colors.neutral.background.primary(White / Elevated Surface)colors.neutral.text.primary(Charcoal / Off-White)colors.neutral.text.secondary(Slate Gray / Light Gray)
typography.title2(22pt bold)typography.headline(17pt semibold)typography.subheadline(15pt regular)
spacing.md(16pt)spacing.lg(24pt)spacing.xl(32pt)
shadows.level2(raised)
borderRadius.md(12pt)borderRadius.lg(16pt)
Screen 2: In-App Camera
Purpose
Allow users to capture photos directly within the app with a native iOS camera feel.User Journey
- Entry Point: Screen 1 → Tap “Take Photo”
- Exit Point:
- Capture photo → Photo Review (Screen 3)
- Tap “Close” → Return to Timeline
- Tap “Gallery” → Photo Picker (Screen 4)
Layout Structure (Full-Screen)
Components Used
1. Camera Preview
- Component: Native iOS camera feed (AVCaptureVideoPreviewLayer in Flutter)
- Dimensions: Full screen (edge-to-edge)
- Aspect Ratio: Native device aspect ratio (e.g., 16:9, 19.5:9)
- Background: Black (#000000)
- Focus: Tap-to-focus supported
- Tap anywhere on preview → Yellow focus square appears (80×80pt)
- Square fades out after 1 second
- Haptic feedback on focus lock
- Exposure: Auto-exposure enabled
- Quality: High quality (1080p minimum)
- Performance: 30fps minimum, 60fps target
- Dimensions: 80×80pt square
- Border: 2pt yellow stroke
- Animation: Fade in + scale from 1.2 → 1.0 (200ms), fade out after 1s
- Position: Centered on tap location
2. Close Button
- Component: Icon Button
- Icon: SF Symbol
xmark(X) - Size: 24×24pt icon
- Touch Target: 44×44pt
- Position: Top-left, 16pt from leading and top Safe Area edges
- Background: 50% black blur (iOS native blur effect)
- Dimensions: 44×44pt circle
- Background: rgba(0, 0, 0, 0.5) with backdrop filter blur
- Icon Color: White (#FFFFFF)
- States:
- Default: White icon, blur background
- Pressed: Icon at 0.6 opacity, scale 0.95 (100ms)
- Action: Dismiss camera, return to Timeline
- Accessibility: VoiceOver “Close camera, button”
3. Flash Control
- Component: Icon Button (toggle)
- Icons:
- Auto: SF Symbol
bolt.badge.a(default) - On: SF Symbol
bolt.fill - Off: SF Symbol
bolt.slash
- Auto: SF Symbol
- Size: 24×24pt icon
- Touch Target: 44×44pt
- Position: Bottom-left, 24pt from leading edge, 32pt from bottom Safe Area
- Background: 50% black blur (44×44pt circle)
- Icon Color:
- Auto: White
- On: Yellow (#FDCB6E)
- Off: White with 0.6 opacity
- States: Cycles through Auto → On → Off → Auto
- Animation: Icon change with cross-fade (200ms)
- Accessibility: VoiceOver “Flash mode: [auto/on/off], button”
4. Flip Camera Button
- Component: Icon Button
- Icon: SF Symbol
arrow.triangle.2.circlepath.camera(camera flip) - Size: 24×24pt icon
- Touch Target: 44×44pt
- Position: To the right of Flash, 88pt from leading edge, 32pt from bottom
- Background: 50% black blur (44×44pt circle)
- Icon Color: White
- States:
- Default: White icon
- Pressed: Icon at 0.6 opacity
- Flipping: Icon rotates 180° (300ms)
- Action: Toggle between rear and front camera
- Animation: Icon rotates + camera feed crossfades (300ms)
- Accessibility: VoiceOver “Flip camera, button”
5. Shutter Button
- Component: Large circular button (primary action)
- Dimensions: 70×70pt
- Position: Center-bottom, 32pt from bottom Safe Area
- Design:
- Outer Circle: 70×70pt, white border (4pt stroke), transparent fill
- Inner Circle: 58×58pt, white fill, centered
- Gap: 6pt between outer and inner circles
- States:
- Default: White circles, no fill in outer ring
- Pressed: Inner circle scales to 0.9 (100ms)
- Capturing: White screen flash (200ms), inner circle scales to 0.7 then bounces back
- Action: Capture photo → Navigate to Photo Review (Screen 3)
- Accessibility:
- VoiceOver: “Capture photo, button”
- Hint: “Double-tap to take a photo”
- User taps shutter (0ms)
- Inner circle scales to 0.7 (100ms)
- White screen flash (full-screen white overlay, 0 → 1 → 0 opacity, 200ms)
- Camera shutter sound plays (native iOS sound)
- Haptic feedback (heavy impact)
- Inner circle bounces back to 1.0 (100ms, spring curve)
- Navigate to Photo Review with captured image
6. Gallery Button
- Component: Icon Button with thumbnail
- Dimensions: 44×44pt
- Position: Bottom-right, 24pt from trailing edge, 32pt from bottom Safe Area
- Content:
- Thumbnail of most recent photo in library (if available)
- If no photos: SF Symbol
photo.on.rectangle(24×24pt)
- Border: 2pt white stroke
- Border Radius: 8pt
- Background:
- With thumbnail: Photo thumbnail (cropped to fill)
- Without thumbnail: 50% black blur
- States:
- Default: Thumbnail visible
- Pressed: Scale 0.95 (100ms)
- Action: Navigate to Photo Picker (Screen 4)
- Accessibility: VoiceOver “Photo library, button”
Responsive Behavior
iPhone SE (320pt width):- Shutter button: 64×64pt (slightly smaller)
- Control buttons: 40×40pt touch targets
- Adjust bottom spacing to 24pt
- Layout as shown
- Shutter button: 76×76pt (slightly larger)
- More generous spacing
- Portrait: Layout as shown
- Landscape: Shutter button moves to right edge, controls rotate to right side
Interactive States & Animations
Camera Open Animation
Duration: 300ms Curve: ease-out Behavior: Fade in from black (camera feed appears)Capture Animation (Detailed)
Total Duration: 500ms Sequence:- Tap shutter (0ms)
- Shutter button inner circle scales to 0.7 (0-100ms, ease-in)
- White flash overlay appears (100ms, fade in)
- Camera captures still image (100ms)
- White flash fades out (100-300ms, fade out)
- Shutter button bounces back (100-200ms, spring)
- Haptic heavy impact (100ms)
- Camera shutter sound (100ms)
- Freeze frame of captured photo (300-500ms)
- Transition to Photo Review (500ms)
Focus Lock Animation
Duration: 200ms Behavior: Yellow square appears at tap location, scales from 1.2 → 1.0, fades out after 1sFlip Camera Animation
Duration: 300ms Behavior: Camera feed crossfades, flip icon rotates 180°Accessibility
WCAG 2.1 AA Compliance:- ✅ Touch Targets: All buttons 44×44pt minimum (shutter 70×70pt)
- ✅ Color Contrast: White on black meets AAA (high contrast)
- ✅ Focus Indicators: All buttons have visible pressed states
- ✅ VoiceOver: All controls clearly labeled
- “Close camera, button”
- “Flash mode: auto, button”
- “Flip camera, button”
- “Capture photo, button”
- “Photo library, button”
- Users who can’t use camera can tap “Gallery” to select existing photos
- Camera permission denied: Show alert with “Open Settings” option
Content Guidelines
No text content on this screen - all icon-based UI for visual clarity.Edge Cases
Camera Permission Denied (First Time):- Camera opens → iOS system permission dialog appears immediately
- Dialog: “App would like to access the camera”
- If Allow: Camera feed starts
- If Don’t Allow: Alert appears
- Title: “Camera Access Required”
- Message: “To capture photos, enable camera access in Settings.”
- Actions: “Open Settings”, “Cancel”
- Tapping “Take Photo” on Screen 1 shows alert before opening camera
- User must manually enable in Settings
- Show error overlay on black screen:
- Icon: SF Symbol
exclamationmark.triangle(48×48pt, white) - Message: “Camera unavailable. Please try again.”
- Button: “Close” (returns to Timeline)
- Icon: SF Symbol
- Flash control automatically disabled (grayed out) when front camera active
- Accessibility hint: “Flash not available with front camera”
- iOS Night Mode activates automatically if available (iPhone 11+)
- No manual control in MVP
- After capture, if device storage full:
- Alert: “Not enough storage to save photo. Free up space and try again.”
- Action: “OK” (returns to camera, photo discarded)
Design Tokens Used
Colors:colors.system.white(#FFFFFF)colors.system.black(#000000)colors.system.yellow(#FDCB6E) - Flash on state
spacing.md(16pt)spacing.lg(24pt)spacing.xl(32pt)
- Custom: 50% black blur for controls
- Native iOS camera (AVCaptureSession)
- Custom shutter button design
Screen 3: Photo Review
Purpose
Show the captured photo and allow users to accept it or retake.User Journey
- Entry Point: Screen 2 → Capture photo
- Exit Point:
- Tap “Use Photo” → Journal Entry Screen (Screen 6)
- Tap “Retake” → Return to Camera (Screen 2)
Layout Structure (Full-Screen)
Components Used
1. Photo Preview
- Component: Full-screen image view
- Dimensions: Full screen, aspect-fill (photo fills entire screen)
- Aspect Ratio: Original photo aspect ratio maintained, cropped to fit screen
- Background: Black (#000000) for letterboxing if needed
- Quality: High resolution (not thumbnail)
- Zoom: Pinch-to-zoom enabled
- Min scale: 1.0 (fit screen)
- Max scale: 3.0 (3x zoom)
- Double-tap to zoom in/out
- Performance: Smooth pinch gestures, 60fps
- No visible zoom UI (native iOS behavior)
- Scale automatically resets to 1.0 when navigating away
2. Retake Button
- Component: Secondary Button
- Text: “Retake”
- Dimensions:
- Width: 140pt
- Height: 50pt
- Border Radius: 12pt
- Position: Bottom-left, 24pt from leading edge, 32pt from bottom Safe Area
- Typography: SF Pro Text, 17pt Semibold
- Colors:
- Background: 50% black blur (iOS native)
- Text: White (#FFFFFF)
- Border: 1pt white stroke
- Shadow: None (blur provides depth)
- States:
- Default: Blur background, white text
- Hover: Background 10% brighter
- Pressed: Background 20% brighter, scale 0.98 (100ms)
- Focus: 2pt blue ring
- Action: Discard photo, return to Camera (Screen 2)
- Accessibility:
- VoiceOver: “Retake photo, button”
- Hint: “Double-tap to retake the photo”
3. Use Photo Button
- Component: Primary Button
- Text: “Use Photo”
- Dimensions:
- Width: 140pt
- Height: 50pt
- Border Radius: 12pt
- Position: Bottom-right, 24pt from trailing edge, 32pt from bottom Safe Area
- Typography: SF Pro Text, 17pt Semibold
- Colors:
- Background: Primary Coral (#FF6B6B in Light, #FF8787 in Dark)
- Text: White (#FFFFFF)
- Shadow: Level 2 (raised)
- Shadow: rgba(0, 0, 0, 0.16), offset (0, 4pt), blur 16pt
- States:
- Default: Coral background, shadow visible
- Hover: 10% darker coral
- Pressed: 20% darker coral, scale 0.98 (100ms)
- Focus: 2pt blue ring
- Action: Accept photo, navigate to Journal Entry Screen (Screen 6)
- Accessibility:
- VoiceOver: “Use Photo, button”
- Hint: “Double-tap to use this photo for your journal entry”
Responsive Behavior
iPhone SE (320pt width):- Button widths: 120pt each
- Buttons may stack vertically if needed (edge case)
- Spacing: 16pt from edges
- Layout as shown
- Button widths: 160pt each
- More generous spacing (32pt from edges)
- Portrait: Buttons at bottom as shown
- Landscape: Buttons may move to right edge vertically stacked
Interactive States & Animations
Photo Review Appear Animation
Duration: 300ms Curve: ease-out Behavior:- Photo fades in from black (camera view)
- Buttons slide up from bottom (translateY: +50pt → 0)
- Buttons fade in (0 → 1 opacity)
Button Press Animation
Duration: 100ms Curve: ease-in-out Behavior: Scale 0.98, background darkensUse Photo Transition
Duration: 300ms Curve: ease-out Behavior:- Photo zooms out slightly (scale 1.0 → 0.95)
- Fade to white
- Journal Entry Screen fades in
Retake Transition
Duration: 250ms Curve: ease-in Behavior: Fade to black, camera reopensAccessibility
WCAG 2.1 AA Compliance:- ✅ Touch Targets: Both buttons 50pt height, 140pt width
- ✅ Color Contrast: White text on black/coral backgrounds (high contrast)
- ✅ Focus Indicators: 2pt blue ring on buttons
- “Photo preview, image”
- “Retake photo, button”
- “Use Photo, button”
- “Recently captured photo” (generic)
- Future: AI-generated alt text
Content Guidelines
Button Text:- “Retake” not “Redo” or “Try Again” (concise)
- “Use Photo” not “Accept” or “Continue” (clear intent)
Edge Cases
Photo Capture Failed (Rare):- If camera capture fails technically:
- Show alert: “Photo capture failed. Please try again.”
- Action: “OK” (returns to camera)
- Compress photo automatically (max 25MB)
- No user-visible error unless compression fails
- Graceful degradation: Show lower resolution preview
- Alert if unable to process: “Photo is too large. Please try a different photo.”
Design Tokens Used
Colors:colors.system.black(#000000)colors.system.white(#FFFFFF)colors.primary.coral(#FF6B6B / #FF8787)
typography.headline(17pt semibold)
spacing.lg(24pt)spacing.xl(32pt)
shadows.level2(raised)
borderRadius.md(12pt)
Screen 4: Photo Picker (Library)
Purpose
Allow users to select existing photos from their device library using the native iOS photo picker.User Journey
- Entry Point:
- Screen 1 → Tap “Choose from Library”
- Screen 2 → Tap “Gallery” button
- Exit Point:
- Select photo → Journal Entry Screen (Screen 6)
- Tap “Cancel” → Return to previous screen
Layout Structure (Native iOS)
Implementation
Native iOS Photo Picker:- Component: PHPickerViewController (iOS 14+)
- Presentation: Modal sheet (slide up from bottom)
- Configuration:
- Selection limit: 1 photo (single selection only in MVP)
- Media types: Images only (no videos, no Live Photos)
- Filter: All photos and screenshots
- Suggested selections: Show “Recents” album by default
- Grid: 4 columns on portrait, 5 columns on landscape
- Gutter: 2pt between thumbnails
- Thumbnail Quality: Standard iOS quality (optimized for speed)
- Best performance and UX (Apple-designed)
- Handles permissions automatically
- Users are familiar with the interface
- Respects iOS 14+ Limited Photo Access
- No custom UI needed (saves development time)
Components Used
1. Navigation Bar (iOS Native)
- Component: iOS native navigation bar
- Title: “Photos”
- Title Style: Headline (17pt semibold)
- Left Button: None
- Right Button: “Cancel”
- Text: “Cancel”
- Color: Primary Coral
- Action: Dismiss picker, return to previous screen
- Background: iOS system background (blur effect)
- Height: 44pt
2. Photo Grid (iOS Native)
- Component: iOS native grid view (collectionView)
- Layout: 4 columns (portrait), 5 columns (landscape)
- Gutter: 2pt between items
- Margins: 0pt (edge-to-edge)
- Thumbnail Size: Square, dynamic based on screen width
- iPhone SE: ~78pt per thumbnail
- iPhone 15: ~95pt per thumbnail
- iPhone 15 Pro Max: ~105pt per thumbnail
- Thumbnail Crop: Center crop (aspect fill)
- Scroll: Vertical infinite scroll
- Performance: Smooth 60fps scrolling, image caching
- Component: iOS native checkmark overlay
- Position: Bottom-right corner of thumbnail
- Checkmark: White checkmark in Primary Coral circle
- Circle Size: 28×28pt
- Border: 2pt white stroke
- Animation: Scale in (0.8 → 1.0, 150ms, spring curve)
3. Album Selector (iOS Native)
- Component: iOS native album picker (dropdown from title)
- Access: Tap “Photos” title to see album list
- Albums Shown: Recents, Favorites, All Photos, + user albums
- Default: Recents album
- Presentation: Sheet from top
Responsive Behavior
iPhone SE (320pt width):- Grid: 4 columns, ~76pt per thumbnail
- Gutter: 1pt
- Grid: 4 columns, ~95pt per thumbnail
- Gutter: 2pt
- Grid: 4 columns, ~105pt per thumbnail
- Gutter: 2pt
- Portrait: 4 columns
- Landscape: 5 columns
Interactive States & Animations
Photo Picker Appear Animation
Duration: 300ms (iOS standard) Curve: ease-out Behavior: Modal sheet slides up from bottomPhoto Selection
Duration: 150ms Behavior:- User taps photo
- Checkmark scales in (0.8 → 1.0, spring)
- Haptic feedback (light impact)
- Photo highlight border appears (Primary Coral, 3pt)
Photo Deselection (If User Taps Selected Photo)
Duration: 150ms Behavior: Checkmark scales out (1.0 → 0.8), fade outPicker Dismiss (After Selection)
Duration: 300ms Behavior:- Sheet slides down
- Selected photo transitions to Journal Entry Screen
- Photo zooms from thumbnail position to full-screen
Accessibility
WCAG 2.1 AA Compliance:- ✅ Touch Targets: Each thumbnail is tappable (dynamic size, minimum 44×44pt)
- ✅ VoiceOver: All photos have VoiceOver labels
- ✅ Keyboard Navigation: Support for external keyboard (iPad, future)
- Photo Labels: “Photo, [Date], [Time]” or “Screenshot, [Date], [Time]”
- Selected Photo: “Photo, selected, [Date], [Time]”
- Navigation: “Photos, heading, button” (tapping opens album selector)
- Cancel: “Cancel, button”
- If user previously selected “Select Photos” (not “Allow All”):
- Picker only shows selected photos
- Banner at top: “You’ve granted limited access. Tap to select more photos.”
- Tapping banner opens iOS Settings to add more photos
Content Guidelines
No custom content - all native iOS strings.Edge Cases
Photo Library Permission Denied:- PHPickerViewController handles this automatically
- If denied previously: Alert shown before picker opens (see Screen 1 edge cases)
- Picker shows only selected photos
- Banner prompts user to select more
- User can manage in iOS Settings
- iOS shows empty state: “No Photos”
- Unlikely edge case (most users have photos)
- If import fails (rare):
- Alert: “Couldn’t import photo. Please try again.”
- User remains in picker
- Picker imports photo at lower resolution automatically
- iOS handles compression
- Photos not downloaded yet show cloud icon
- Tapping downloads automatically (progress indicator)
- User waits for download, then selection completes
Design Tokens Used
Colors:colors.primary.coral(#FF6B6B / #FF8787) - Checkmark, Cancel button- iOS system colors for everything else
- iOS system typography (native picker)
- PHPickerViewController (iOS 14+)
Screen 5: Photo Edit (Optional)
Purpose
Allow users to crop and rotate photos before journaling. This screen is optional - users can skip to Journal Entry Screen.User Journey
- Entry Point:
- Screen 3 → Tap “Edit” icon (added to Photo Review screen)
- Screen 4 → After selecting photo, tap “Edit” (optional)
- Screen 6 → Tap photo, tap “Edit”
- Exit Point:
- Tap “Done” → Return to Journal Entry Screen (Screen 6) with edited photo
- Tap “Cancel” → Discard edits, return to previous screen
Layout Structure (Full-Screen)
Components Used
1. Navigation Bar
- Component: iOS native navigation bar
- Height: 44pt
- Background: iOS system background (blur)
- Left Button: “Cancel”
- Text: “Cancel”
- Color: Primary Coral
- Action: Discard edits, return to previous screen
- Right Button: “Done”
- Text: “Done”
- Color: Primary Coral
- Action: Apply edits, return to Journal Entry Screen
- Accessibility:
- Cancel: VoiceOver “Cancel, button, discards changes”
- Done: VoiceOver “Done, button, applies changes”
2. Photo Editor (Crop View)
- Component: Interactive crop view (CropViewController in Flutter/iOS)
- Dimensions: Full-width, maintains aspect ratio
- Photo: Centered, fit to screen with margins
- Crop Grid:
- 3×3 grid overlay (rule of thirds)
- Grid lines: 1pt white stroke at 50% opacity
- Corner handles: 8×8pt circles, white fill
- Edge handles: 6pt wide, white fill
- Behavior:
- Pinch to zoom in/out
- Drag photo to reposition within crop area
- Drag handles to adjust crop region
- Double-tap to reset to original
- Constraints: Crop area cannot be smaller than 200×200pt
- Always visible while editing
- Fades to 30% opacity when not interacting (2s delay)
- Reappears at 100% opacity when user touches screen
- Area outside crop: 40% black overlay (shows what will be cropped out)
3. Aspect Ratio Tools (Bottom Toolbar)
Toolbar Container:- Height: 88pt (includes safe area)
- Background: iOS blur (light blur in Light Mode, dark blur in Dark Mode)
- Padding: 16pt horizontal
- Layout: Horizontal row, evenly spaced
- Free Crop (default selected)
- 1:1 Square
- 4:3 Standard
- 16:9 Widescreen
- Rotate (separate from aspect ratios)
- Touch Target: 60×60pt
- Icon Container: 48×48pt
- Icon: 24×24pt
- Label: Below icon, 11pt regular
- Spacing: Evenly distributed across toolbar width
- Icon: SF Symbol
rectangle.dashed(free-form) - Label: “Free”
- Action: Allow any aspect ratio (default)
- Icon: SF Symbol
square(square) - Label: “Square”
- Action: Lock crop to 1:1 aspect ratio
- Icon: Custom rectangle icon (4:3 ratio)
- Label: “4:3”
- Action: Lock crop to 4:3 aspect ratio
- Icon: Custom rectangle icon (16:9 ratio)
- Label: “16:9”
- Action: Lock crop to 16:9 aspect ratio
- Icon: SF Symbol
rotate.right(clockwise arrow) - Label: “Rotate”
- Action: Rotate photo 90° clockwise
- Position: Separated from aspect ratio buttons (right side)
- Background: Primary Coral at 15% opacity
- Icon Color: Primary Coral
- Label Color: Primary Coral
- Border: 2pt Primary Coral stroke
- Border Radius: 8pt
- Background: Transparent
- Icon Color: Charcoal (Light) / Off-White (Dark)
- Label Color: Charcoal (Light) / Off-White (Dark)
- Scale: 0.95 (100ms)
- Background: 10% gray
Responsive Behavior
iPhone SE (320pt width):- Photo editor: Smaller margins (12pt)
- Tool buttons: 52×52pt touch targets
- Labels: 10pt font size
- Layout as shown
- Photo editor: More generous margins (24pt)
- Tool buttons: 64×64pt touch targets
- Portrait: Layout as shown
- Landscape: Toolbar moves to right edge (vertical), photo editor left
Interactive States & Animations
Edit Screen Appear
Duration: 300ms Curve: ease-out Behavior: Fade in from previous screenAspect Ratio Change
Duration: 300ms Curve: spring (response: 0.3, dampingFraction: 0.7) Behavior:- User taps aspect ratio button
- Selected state animates in (background + icon color change)
- Crop grid animates to new aspect ratio
- Photo scales/repositions to fit new crop area
- Haptic feedback (medium impact)
Rotate Animation
Duration: 400ms Curve: spring (response: 0.4, dampingFraction: 0.75) Behavior:- User taps Rotate button
- Photo rotates 90° clockwise (smooth rotation)
- Crop grid adjusts to rotated dimensions
- Haptic feedback (medium impact)
Done (Apply Edits)
Duration: 300ms Behavior:- Crop view fades out
- Edited photo transitions to Journal Entry Screen
- Loading indicator if processing takes >500ms
Cancel (Discard Edits)
Duration: 250ms Behavior: Fade out, return to previous screenAccessibility
WCAG 2.1 AA Compliance:- ✅ Touch Targets: All tool buttons 60×60pt
- ✅ Color Contrast: Labels and icons meet 4.5:1 minimum
- ✅ Focus Indicators: Selected state is clearly visible
- ✅ VoiceOver: All tools clearly labeled
- “Cancel, button”
- “Done, button”
- “Photo editor, image, adjust crop by dragging”
- “Free crop, button”
- “Square crop, button”
- “4:3 crop, button”
- “16:9 crop, button”
- “Rotate photo, button”
- Photo editor: “Swipe to adjust crop. Double-tap to reset.”
- Aspect ratio buttons: “Double-tap to change aspect ratio”
- Rotate: “Double-tap to rotate photo 90 degrees”
Content Guidelines
Button Labels:- Short, clear (1-2 words)
- “Free” not “Free Crop” (concise)
- “Rotate” not “Rotate 90°” (implied)
Edge Cases
Photo Too Large to Edit:- Downscale photo temporarily for editing (use preview resolution)
- Apply edits to full-resolution photo on save
- Show loading indicator if processing >1s
- Alert: “Photo is too large to edit. Please try a different photo.”
- Action: “OK” (returns to previous screen)
- Minimum crop area: 200×200pt
- Handles resist shrinking below minimum
- Haptic feedback (error vibration) if user tries to crop smaller
- Rotation still works (even though visually appears the same)
- Crop grid rotates, photo maintains orientation
- User can rotate multiple times (0°, 90°, 180°, 270°)
- Edits are applied cumulatively on save
Design Tokens Used
Colors:colors.primary.coral(#FF6B6B / #FF8787)colors.neutral.text.primary(Charcoal / Off-White)colors.system.white(#FFFFFF)colors.system.black(#000000)
typography.caption1(11pt regular) - Tool labelstypography.callout(16pt regular) - Navigation buttons
spacing.md(16pt)spacing.lg(24pt)
- Custom crop view (or library like TOCropViewController)
Screen 6: Journal Entry Screen (MOST CRITICAL)
Purpose
The core screen where users create a journal entry: view their photo, receive AI-generated prompts, write text, and tag emotions. This is the heart of the 60-second experience.User Journey
- Entry Point:
- Screen 3 → Tap “Use Photo”
- Screen 4 → Select photo
- Screen 5 → Tap “Done” (if edited)
- Exit Point:
- Tap “Save Entry” → Entry Saved Confirmation (Screen 7)
- Tap “Cancel” → Confirmation dialog, return to Timeline
Layout Structure (Light Mode, Scrollable)
Components Used
1. Navigation Bar
- Component: iOS navigation bar
- Height: 44pt
- Background: iOS system background (blur)
- Left Button: Close (×)
- Icon: SF Symbol
xmark, 20×20pt - Color: Charcoal (Light) / Off-White (Dark)
- Touch Target: 44×44pt
- Action: Show confirmation dialog → Return to Timeline
- Icon: SF Symbol
- Right Button: “Save” (text button)
- Text: “Save”
- Color: Primary Coral (enabled), Light Gray (disabled)
- Touch Target: 60×44pt
- Action: Save entry → Screen 7
- States: Disabled until photo + text/emotion added
- Accessibility:
- Close: VoiceOver “Close, button, shows confirmation dialog”
- Save: VoiceOver “Save entry, button, [disabled/enabled]“
2. Photo Display
- Component: Image view (tappable)
- Dimensions: Full-width, 300pt fixed height
- Aspect Ratio: Original aspect ratio maintained, cropped to fit (aspect-fill)
- Border Radius: 0pt (full-bleed)
- Background: Black for letterboxing
- Quality: High resolution (not thumbnail)
- Tap Action: Expand to full-screen view (pinch-to-zoom enabled)
- Edit Button: Small “Edit” icon button overlaid on top-right corner
- Icon: SF Symbol
crop.rotate, 16×16pt - Background: 50% black blur, 32×32pt circle
- Position: 8pt from top-right corner
- Action: Navigate to Photo Edit screen (Screen 5)
- Accessibility: VoiceOver “Edit photo, button”
- Icon: SF Symbol
- Background: Black
- Photo: Centered, pinch-to-zoom (1x to 3x)
- Close: Tap photo or swipe down to dismiss
- Duration: 300ms fade in/out
3. AI Loading State (8-15 seconds)
Loading Header:- Component: Text with animated icon
- Icon: SF Symbol
arrow.clockwise.circle(spinner), 20×20pt, rotating - Text: “Thinking about your photo…”
- Typography: SF Pro Text, 16pt Regular
- Color: Slate Gray (Light) / Light Gray (Dark)
- Position: 24pt below photo
- Animation: Icon rotates continuously (360° every 1s, linear)
- Component: Skeleton loading cards
- Dimensions: Full-width minus 32pt margins, 80pt height
- Border Radius: 12pt
- Background: Light Gray (#E0E0E0) with shimmer gradient overlay
- Spacing: 12pt vertical gap between cards
- Shimmer Animation:
- Gradient: Linear, 45° angle, white highlight (0 → 100% → 0 opacity)
- Duration: 1.5s continuous loop
- Direction: Left to right
- Message: “Taking longer than expected. Try manual entry?”
- Text Link: “Skip AI prompts” (Primary Coral)
- Action: Hide loading state, show empty prompt cards with “Write your own entry” message
- Message: “AI couldn’t generate prompts. Write your own entry.”
- Icon: SF Symbol
exclamationmark.circle, Warning Amber - Action: Show empty prompt cards (user writes freely)
- Fallback Prompts: Show 3 generic fallback prompts:
- “What happened in this moment?”
- “How did this make you feel?”
- “What do you want to remember about today?“
4. AI Prompt Cards (After Loading)
Success State (3 prompt cards): Prompt Card Specifications (each):- Dimensions: Full-width minus 32pt margins, variable height (60-80pt)
- Border Radius: 12pt
- Background:
- Light Mode: Off-White (#F9FAFB)
- Dark Mode: Elevated Surface (#2C3135)
- Border: 1pt solid
- Light Mode: Light Gray (#DFE6E9)
- Dark Mode: Dark Gray (#3C4347)
- Selected: 2pt Primary Coral
- Padding: 16pt internal padding
- Typography: SF Pro Text, 17pt Regular
- Color: Charcoal (Light) / Off-White (Dark)
- Max Length: 15 words (approximately 60-90 characters)
- Spacing: 12pt vertical gap between cards
- Default: Light background, thin border
- Hover (iPad): Background 5% darker
- Pressed: Scale 0.98 (100ms)
- Selected: 2pt Primary Coral border, coral text color
- Focus: 2pt blue ring
- Tap: Select prompt → Insert into text field
- Long Press: Show options: “Use this prompt”, “Copy”, “Refresh prompts”
- “What made this moment special?”
- “Who were you with and what did you talk about?”
- “How did this moment make you feel?”
- VoiceOver: “[Prompt text], button, tap to use this prompt”
5. Refresh Prompts Button
- Component: Text link button
- Icon: SF Symbol
arrow.clockwise, 16×16pt (leading icon) - Text: “Refresh prompts”
- Typography: SF Pro Text, 16pt Regular
- Color: Primary Coral
- Position: 16pt below last prompt card, leading-aligned
- Touch Target: Full width, 44pt height
- Action: Request 3 new AI prompts (show loading state again)
- Limit: Maximum 5 refreshes per session (prevent API abuse)
- Accessibility: VoiceOver “Refresh prompts, button”
6. Emotion Selector Section
Section Header:- Text: “How did you feel?”
- Typography: SF Pro Text, 17pt Semibold
- Color: Charcoal (Light) / Off-White (Dark)
- Position: 32pt below Refresh button
- Accessibility: VoiceOver “How did you feel, heading”
- Layout: 4 columns × 3 rows = 12 emotions
- Spacing: 8pt horizontal gap, 12pt vertical gap
- Margins: 16pt horizontal
- Dimensions: Variable width (flex), 44pt height
- Border Radius: 22pt (pill shape)
- Padding: 10pt horizontal
- Layout: Horizontal (icon + label)
- Icon Size: 24×24pt emoji
- Gap: 6pt between icon and label
- Font: SF Pro Text, 14pt Regular
- Label: Abbreviated (e.g., “Happy” → “Hpy”, “Grateful” → “Grt”)
- Color:
- Unselected: Emotion color at 100%
- Selected: White (#FFFFFF)
- Positive Emotions:
- Happy: Warm Coral (#FF6B6B)
- Grateful: Soft Pink (#FF8FA3)
- Excited: Bright Yellow (#FDCB6E)
- Peaceful: Light Teal (#81ECEC)
- Reflective Emotions:
- Thoughtful: Cool Blue (#74B9FF)
- Nostalgic: Muted Purple (#A29BFE)
- Proud: Golden Orange (#FAB1A0)
- Loving: Rose Pink (#FD79A8)
- Challenging Emotions:
- Sad: Muted Blue (#6C5CE7)
- Anxious: Gray-Blue (#636E72)
- Frustrated: Muted Red (#E17055)
- Hopeful: Soft Teal (#55EFC4)
- Background: Emotion color at 100%
- Text: White
- Icon: White
- Checkmark: SF Symbol
checkmark, 16×16pt, white, trailing
- Unselected: Light background (15% opacity), colored text
- Selected: Full color background, white text + checkmark
- Pressed: Scale 0.98 (100ms), haptic feedback (light impact)
- Hover (iPad): Background opacity 25%
- Users can select 0 to 12 emotions (no limit)
- Encourage 1-3 emotions (show hint if >5 selected)
- Hint (if >5): “Focusing on your strongest feelings makes your entries more meaningful.”
- VoiceOver: “[Emotion name], [category], [selected/unselected], button”
- Example: “Happy, positive emotion, selected, button”
7. Text Entry Field
Field Label:- Text: “What do you want to remember?”
- Typography: SF Pro Text, 17pt Semibold
- Color: Charcoal (Light) / Off-White (Dark)
- Position: 32pt below emotion grid
- Accessibility: VoiceOver “What do you want to remember, label”
- Component: Multi-line text area (iOS UITextView / Flutter TextField)
- Dimensions: Full-width minus 32pt margins, min 120pt height (3 lines)
- Max Height: 300pt (scrollable if text exceeds)
- Border Radius: 12pt
- Padding: 16pt internal padding
- Background:
- Light Mode: Off-White (#F9FAFB)
- Dark Mode: Elevated Surface (#2C3135)
- Border: 1pt solid
- Light Mode: Light Gray (#DFE6E9)
- Dark Mode: Dark Gray (#3C4347)
- Focus: 2pt Primary Coral
- Typography: SF Pro Text, 17pt Regular
- Line Height: 22pt
- Color: Charcoal (Light) / Off-White (Dark)
- Placeholder: “Tap an AI prompt above or write freely…”
- Placeholder Color: Light Gray at 60% opacity
- Position: Bottom-right corner of text field (inside padding)
- Typography: SF Pro Text, 13pt Regular
- Color:
- 0-450 chars: Light Gray (not visible)
- 451-500 chars: Slate Gray (visible)
- 500 chars: Error Red (limit reached)
- Format: “450 / 500” or “500 / 500” (free tier limit)
- Limit: 500 characters per entry
- Behavior: Text field becomes non-editable at 500 chars
- Upgrade CTA: “Upgrade to Premium for unlimited characters” (appears below field at limit)
- Limit: Unlimited characters
- Character count: Not shown (or shows “No limit”)
- Default: Light background, thin border
- Focus: Coral border, keyboard opens
- Typing: Character count updates in real-time
- At Limit: Error red count, slight red tint to border
- Error: Red border if invalid (edge case)
- Drafts auto-save every 10 seconds
- Draft preserved on app backgrounding
- Draft cleared on successful save
- VoiceOver: “Journal entry text, text area, [X] characters”
- Dynamic Type: Text size scales appropriately
8. Save Entry Button
- Component: Primary Button
- Text: “Save Entry”
- Dimensions: Full-width minus 32pt margins, 56pt height (taller for emphasis)
- Border Radius: 12pt
- Typography: SF Pro Text, 17pt Semibold
- Position: 32pt below text field, 32pt above bottom Safe Area
- Background:
- Enabled: Primary Coral (#FF6B6B / #FF8787)
- Disabled: Light Gray (#DFE6E9 in Light, #3C4347 in Dark)
- Text Color: White
- Shadow: Level 2 (when enabled)
- States:
- Disabled: Gray background, no shadow, no interaction
- Enabled: Coral background, shadow visible
- Hover: 10% darker coral
- Pressed: 20% darker coral, scale 0.98 (100ms)
- Saving: Loading spinner replaces text (white spinner)
- Entry is valid if:
- Photo is attached AND
- (Text is not empty OR at least 1 emotion is selected)
- Button is disabled until both conditions met
- Validate entry (photo + text/emotion)
- Show loading spinner on button
- Upload photo (if not already uploaded)
- Save entry to database
- Navigate to Screen 7 (Entry Saved Confirmation)
- VoiceOver: “Save Entry, button, [enabled/disabled]”
- Hint: “Double-tap to save your journal entry”
Responsive Behavior
iPhone SE (320pt width):- Photo height: 240pt
- Margins: 24pt (reduced from 32pt)
- Emotion chips: 3 columns (instead of 4)
- Text field: Min height 100pt
- Layout as shown
- Photo height: 320pt
- Margins: 32pt
- Emotion chips: 4 columns (as shown)
- Text field: Min height 140pt
- Entire screen scrollable (except navigation bar)
- Scroll-to-top on tapping photo
- Keyboard pushes text field into view when focused
Interactive States & Animations
Screen Appear Animation
Duration: 300ms Curve: ease-out Sequence:- Photo fades in (0s)
- AI loading state appears (100ms delay)
- Emotion section fades in (200ms delay)
- Text field fades in (300ms delay)
- Save button fades in (400ms delay)
AI Prompts Loading → Loaded Transition
Duration: 500ms Curve: spring (response: 0.3, dampingFraction: 0.7) Sequence:- Loading header fades out
- Shimmer placeholders fade out
- Actual prompt cards fade in + slide up 10pt
- Stagger each prompt by 100ms (1, 2, 3)
- Refresh button fades in
- Subtle scale pulse on each prompt card (1.0 → 1.02 → 1.0, 300ms)
- Haptic feedback (light impact)
Prompt Selection Animation
Duration: 200ms Behavior:- User taps prompt card
- Card border changes to coral (2pt)
- Card text changes to coral
- Prompt text copies to clipboard
- Text field focuses (keyboard opens)
- Prompt text appears in field with typing animation (optional)
- Haptic feedback (medium impact)
- Prompt text appears letter-by-letter in text field
- Duration: 1s (fast enough to not annoy)
- Skippable: User can start typing immediately to interrupt
Emotion Selection Animation
Duration: 150ms Behavior:- User taps emotion chip
- Background color fills (15% → 100% opacity, 150ms)
- Text color changes to white
- Checkmark scales in (0.8 → 1.0, spring)
- Haptic feedback (light impact)
- Toast notification appears: “Focusing on your strongest feelings makes your entries more meaningful.”
- Duration: 3s, auto-dismiss
- Position: Top of screen (below nav bar)
- Dismiss: Swipe up or auto-dismiss
Text Field Focus Animation
Duration: 200ms Behavior:- User taps text field
- Border color changes to coral (1pt → 2pt, 200ms)
- Keyboard slides up from bottom (iOS native animation)
- Field scrolls into view (if needed)
Save Entry Animation
Duration: Variable (depends on upload speed) Sequence:- User taps Save Entry
- Button text fades out (100ms)
- Loading spinner fades in (100ms)
- Button background pulses subtly (0.95 → 1.0 scale, 1s loop)
- Upload progress (if photo not uploaded yet)
- On success: Checkmark replaces spinner (200ms)
- Navigate to Screen 7
- Small progress indicator below Save button
- Text: “Uploading photo… 45%”
- Linear progress bar (coral color)
Cancel / Close Confirmation
Trigger: User taps Close (×) button with unsaved changes Confirmation Dialog:- Title: “Discard Entry?”
- Message: “Your entry will be lost if you don’t save it.”
- Actions:
- “Discard” (destructive, red text)
- “Keep Editing” (default, bold)
- Behavior: If user has unsaved changes, show dialog. If no changes, dismiss immediately.
- Photo added OR
- Text field not empty OR
- At least 1 emotion selected
Accessibility
WCAG 2.1 AA Compliance:- ✅ Color Contrast: All text meets 4.5:1 minimum
- ✅ Touch Targets: All interactive elements 44×44pt minimum (Save button 56pt)
- ✅ Focus Indicators: Coral border on focused elements
- ✅ Dynamic Type: All text scales appropriately
- ✅ VoiceOver: Logical reading order, clear labels
- “Close, button”
- “Save, button, disabled”
- “Photo, image, tap to view full-screen”
- “Edit photo, button”
- “Thinking about your photo, loading”
- [After loading] “AI prompt 1: [text], button”
- “AI prompt 2: [text], button”
- “AI prompt 3: [text], button”
- “Refresh prompts, button”
- “How did you feel, heading”
- [For each emotion] “[Emotion name], [category], [selected/unselected], button”
- “What do you want to remember, label”
- “Journal entry text, text area”
- “Save Entry, button”
- Photo: “Double-tap to view full-screen”
- Prompt cards: “Double-tap to use this prompt in your entry”
- Emotion chips: “Double-tap to select this emotion”
- Save button: “Double-tap to save your journal entry”
- At AX5 (largest size):
- Photo height: 240pt (reduced)
- Prompt cards: Line breaks allowed, variable height
- Emotion chips: Stack vertically if needed (2 columns)
- Text field: Min height 160pt
- All content scrollable
Content Guidelines
AI Prompt Quality:- Length: 8-15 words (approximately 40-75 characters)
- Tone: Thoughtful, reflective questions
- Specificity: Reference photo content when possible
- Examples:
- Good: “What made this sunset moment special?”
- Bad: “Write about this.” (too generic)
- Good: “Who were you with and what were you celebrating?”
- Bad: “Describe the people in the photo.” (too clinical)
- “What happened in this moment?”
- “How did this make you feel?”
- “What do you want to remember about today?”
- “Tap an AI prompt above or write freely…”
- Clear, helpful, not prescriptive
- Short, conversational questions
- “How did you feel?” not “Select Emotions” (warmer)
Edge Cases
AI Generation Timeout (>15s):- Show message: “Taking longer than expected. Try manual entry?”
- Show “Skip AI prompts” link
- User can write freely without AI
- Show error message: “AI couldn’t generate prompts. Write your own entry.”
- Icon: Warning amber
- Show 3 generic fallback prompts
- Log error for debugging (no user-facing technical details)
- Queue entry for retry
- Show toast: “Entry saved locally. Will sync when online.”
- Entry appears in timeline immediately (optimistic UI)
- Background sync when network available
- Retry upload 3 times
- If all retries fail:
- Alert: “Photo upload failed. Entry saved without photo.”
- Options: “Retry Upload”, “Save Without Photo”, “Cancel”
- Entry with photo placeholder + text/emotions saved
- Character count turns red
- Border tints red slightly
- Keyboard continues working but no new characters accepted
- Show upgrade CTA: “Upgrade to Premium for unlimited characters”
- Save button remains disabled
- No error message (implied by disabled button)
- User must add either text or emotions to save
- Draft auto-saves
- On app relaunch: “You have an unsaved entry. Continue editing?”
- Options: “Continue”, “Discard”
- “Refresh prompts” button becomes disabled
- Message: “You’ve reached the refresh limit. Write freely!”
- Prevents API abuse
- Fully supported (no character encoding issues)
- Emoji count as 2 characters for free tier limit
- Supported via iOS keyboard
- No character limit applied during dictation (applies after user stops)
Design Tokens Used
Colors:colors.primary.coral(#FF6B6B / #FF8787)colors.neutral.text.primary(Charcoal / Off-White)colors.neutral.text.secondary(Slate Gray / Light Gray)colors.neutral.background.surface(Off-White / Elevated Surface)colors.neutral.background.primary(White / Elevated Surface)colors.neutral.border(Light Gray / Dark Gray)colors.system.error(#D63031)colors.system.success(#00B894)- All 12 emotion colors
typography.headline(17pt semibold) - Section headerstypography.body(17pt regular) - Prompt cards, text fieldtypography.subheadline(15pt regular) - AI loading messagetypography.footnote(13pt regular) - Character counttypography.caption1(12pt regular) - Hints
spacing.xs(8pt)spacing.sm(12pt)spacing.md(16pt)spacing.lg(24pt)spacing.xl(32pt)
shadows.level2(raised)
borderRadius.md(12pt)borderRadius.full(22pt for emotion chips)
Screen 7: Entry Saved Confirmation
Purpose
Celebrate the user’s entry creation and confirm success. Brief moment of delight before returning to timeline.User Journey
- Entry Point: Screen 6 → Tap “Save Entry” (successful save)
- Exit Point:
- Auto-dismiss to Timeline after 3 seconds
- Tap “View Entry” → Entry Detail View
- Swipe down → Timeline (early dismiss)
Layout Structure (Full-Screen Overlay)
Components Used
1. Background Overlay
- Component: Full-screen overlay
- Background:
- Light Mode: White (#FFFFFF) at 95% opacity
- Dark Mode: Background Black (#1A1D1F) at 95% opacity
- Backdrop Blur: iOS native blur effect (light/dark)
- Dismissible: Swipe down to dismiss early
2. Success Checkmark Icon
- Component: Animated icon
- Icon: SF Symbol
checkmark.circle.fill - Size: 120×120pt
- Color: Success Green (#00B894)
- Position: Centered horizontally, 30% from top
- Animation (on appear):
- Duration: 600ms
- Sequence:
- Icon scales from 0 → 1.2 (300ms, ease-out)
- Icon bounces to 1.0 (300ms, spring curve)
- Subtle rotation wiggle: -5° → +5° → 0° (200ms)
- Haptic: Success haptic feedback (notification type)
- Reduce Motion: Fade in only, no scale/bounce
- Particle effect: Small colored dots burst from checkmark
- Duration: 1s (fades out)
- Colors: Primary Coral, Deep Teal, Soft Peach
- Reduce Motion: Skip confetti entirely
3. Success Message (Headline)
- Component: Text (Title 2 style)
- Text: “Entry saved!”
- Typography: SF Pro Display, 28pt Bold
- Color: Charcoal (Light) / Off-White (Dark)
- Position: 32pt below checkmark icon
- Alignment: Center
- Accessibility: VoiceOver “Entry saved! heading”
4. Subtext
- Component: Text (Body style)
- Text: “Your memory has been added to your timeline.”
- Typography: SF Pro Text, 17pt Regular
- Color: Slate Gray (Light) / Light Gray (Dark)
- Position: 12pt below headline
- Alignment: Center
- Max Width: 300pt
- Accessibility: VoiceOver reads after headline
5. View Entry Button
- Component: Primary Button
- Text: “View Entry”
- Dimensions: Full-width minus 48pt margins, 50pt height
- Border Radius: 12pt
- Typography: SF Pro Text, 17pt Semibold
- Background: Primary Coral (#FF6B6B / #FF8787)
- Text Color: White
- Shadow: Level 2 (raised)
- Position: 48pt below subtext
- Action: Navigate to Entry Detail View (full view of saved entry)
- States:
- Default: Coral background
- Hover: 10% darker
- Pressed: 20% darker, scale 0.98 (100ms)
- Accessibility: VoiceOver “View Entry, button”
6. Auto-Dismiss Countdown
- Component: Text (Footnote style)
- Text: “Returning to timeline in 3s…”
- Typography: SF Pro Text, 13pt Regular
- Color: Slate Gray (Light) / Light Gray (Dark)
- Position: 24pt below View Entry button, centered
- Animation:
- Countdown: “3s” → “2s” → “1s” (updates every second)
- Fade out when dismissed
- Accessibility: VoiceOver “Returning to timeline in 3 seconds”
- Timer starts on screen appear
- Pauses if user taps View Entry (prevents early dismiss)
- User can swipe down to dismiss early
Responsive Behavior
iPhone SE (320pt width):- Checkmark: 100×100pt
- Headline: 24pt
- Margins: 32pt horizontal
- Layout as shown
- Checkmark: 140×140pt
- More generous vertical spacing
Interactive States & Animations
Success Screen Appear Animation
Duration: 600ms Curve: spring (response: 0.4, dampingFraction: 0.7) Sequence:- Backdrop fades in (0-200ms)
- Checkmark animates in (200-800ms):
- Scale from 0 → 1.2 (200-500ms, ease-out)
- Bounce to 1.0 (500-800ms, spring)
- Rotate wiggle: -5° → +5° → 0° (600-800ms)
- Confetti burst (if enabled) (500ms)
- Headline fades in + slide up 10pt (400ms delay)
- Subtext fades in + slide up 10pt (500ms delay)
- View Entry button fades in + slide up 10pt (600ms delay)
- Countdown fades in (700ms delay)
- Haptic feedback: Success notification (at 500ms)
Auto-Dismiss Transition
Duration: 300ms Trigger: 3-second countdown completes Behavior:- Entire success screen fades out
- Timeline fades in with newly saved entry at top
- New entry has subtle highlight pulse (1.0 → 1.02 → 1.0 scale, 500ms)
View Entry Button Press
Duration: 300ms Behavior:- Button press animation (scale 0.98)
- Success screen fades out
- Entry Detail View fades in (full entry with photo, text, emotions)
Early Dismiss (Swipe Down)
Duration: 250ms Trigger: User swipes down on overlay Behavior: Success screen slides down + fades out, return to TimelineAccessibility
WCAG 2.1 AA Compliance:- ✅ Color Contrast: All text meets 4.5:1 minimum
- ✅ Touch Targets: View Entry button 50pt height
- ✅ VoiceOver: Clear success announcement
- ✅ Reduce Motion: Animations simplified or skipped
- “Entry saved! heading”
- “Your memory has been added to your timeline”
- “View Entry, button”
- “Returning to timeline in 3 seconds”
- Immediate announcement: “Entry saved successfully”
- Interrupts current reading (high priority)
- Skip checkmark bounce/wiggle
- Skip confetti
- Fade in only, no slides/scales
Content Guidelines
Headline:- Celebratory, concise (1-3 words)
- “Entry saved!” > “Success” (more personal)
- Exclamation point adds warmth
- 100-150 characters
- Explains what happened
- “Your memory” not “Your entry” (warmer language)
- Action-oriented (verb + noun)
- “View Entry” > “See Entry” (clearer)
- Clear timing (“3s” not “3 seconds”)
- Non-intrusive color (gray, not bold)
Edge Cases
Save Succeeded, But Entry Not Immediately Visible:- Rare: Database write delay
- Timeline shows entry after 1-2s (acceptable)
- No error shown (optimistic UI)
- This screen only shows if save succeeded
- If save failed, user sees error on Screen 6 (not Screen 7)
- Countdown pauses
- On foreground: Resume countdown
- If countdown expired: Dismiss and return to Timeline
- Success screen dismisses immediately
- Entry creation flow starts fresh
Design Tokens Used
Colors:colors.system.success(#00B894) - Checkmarkcolors.primary.coral(#FF6B6B / #FF8787) - View Entry buttoncolors.neutral.text.primary(Charcoal / Off-White)colors.neutral.text.secondary(Slate Gray / Light Gray)colors.neutral.background.primary(White / Black) - Overlay
typography.title2(28pt bold) - Headlinetypography.body(17pt regular) - Subtexttypography.headline(17pt semibold) - Buttontypography.footnote(13pt regular) - Countdown
spacing.sm(12pt)spacing.lg(24pt)spacing.xl(32pt)spacing.xxl(48pt)
shadows.level2(raised) - Button
borderRadius.md(12pt)
Dark Mode Specifications
All 7 screens have full Dark Mode variants. Key adjustments from Light Mode:Color Adjustments
Backgrounds:- Light Mode: White (#FFFFFF) / Off-White (#F9FAFB)
- Dark Mode: Background Black (#1A1D1F) / Elevated Surface (#2C3135)
- Primary: Charcoal (#2D3436) → Off-White (#F5F6FA)
- Secondary: Slate Gray (#636E72) → Light Gray (#B2BEC3)
- Light Mode: #FF6B6B
- Dark Mode: #FF8787 (10% brighter for dark background legibility)
- Light Mode: Light Gray (#DFE6E9)
- Dark Mode: Dark Gray (#3C4347)
- Light Mode: Full opacity (rgba(0, 0, 0, 0.08-0.16))
- Dark Mode: 50% reduced opacity (rgba(0, 0, 0, 0.04-0.08))
- All emotion colors slightly adjusted (5-10% brighter) for dark mode legibility
- Maintain same relative differences between colors
Animation Specifications Summary
Global Animation Principles
- Respect Reduce Motion: All animations have fade-only fallbacks
- Timing: Use iOS-standard spring curves for organic feel (response: 0.3, dampingFraction: 0.7)
- Performance: 60fps minimum (120fps on ProMotion devices)
- Purpose: Every animation guides, informs, or delights (never decorative)
- Haptics: Pair animations with appropriate haptic feedback
Spring Curve (Default for Most Animations)
Durations
- Instant: 100ms (button press)
- Fast: 150-200ms (micro-interactions, selection feedback)
- Standard: 300ms (page transitions, modals)
- Deliberate: 500-600ms (celebration animations)
- Continuous: 1-1.5s (loading states, shimmers)
Common Animations
Modal/Bottom Sheet Appear:- Duration: 300ms
- Transform: Slide up from bottom (translateY: +100% → 0)
- Opacity: 0 → 1
- Backdrop: Fade in 40% black (0 → 0.4)
- Curve: ease-out
- Duration: 100ms
- Scale: 1.0 → 0.98 → 1.0
- Curve: ease-in-out
- Haptic: Light impact
- Duration: 150ms
- Border: 1pt → 2pt, color change
- Scale: 1.0 → 0.98 (press)
- Haptic: Light impact
- Duration: 1.5s continuous loop
- Gradient: White highlight sweeps left to right
- Curve: linear (continuous)
- Duration: 600ms
- Checkmark: Scale 0 → 1.2 → 1.0 (bounce)
- Rotate: -5° → +5° → 0° (wiggle)
- Confetti: Particle burst (optional)
- Haptic: Success notification
Flutter Implementation Notes
Design System Compatibility
All components designed for Flutter with Cupertino widgets (iOS-native feel): Key Flutter Widgets Used:- CupertinoButton: Primary/Secondary buttons
- CupertinoNavigationBar: Navigation bar
- CupertinoTabBar: Not used in this flow (Timeline uses it)
- CupertinoTextField: Text input fields
- CupertinoActionSheet: Bottom sheets (Screen 1)
- CupertinoAlertDialog: Confirmation dialogs
- CupertinoActivityIndicator: Loading spinners
- PageView: Not used in this flow (but available for swipe gestures)
- Emotion Chips: Custom Flutter widgets (circular badges with icons)
- Prompt Cards: Custom Container with BoxDecoration
- Photo Editor: Use plugin like
image_cropperorcrop_your_image - Camera: Use
cameraplugin for native camera integration - Photo Picker: Use
image_pickerplugin (native PHPickerViewController on iOS)
Camera Implementation (Screen 2)
Photo Picker Implementation (Screen 4)
AI Prompt Loading Animation (Screen 6)
Design Tokens in Dart
Responsive Layout in Flutter
Dark Mode in Flutter
Asset Export Requirements
For @frontend-developer
Illustrations:- None required (using native camera, photo picker)
- Use SF Symbols where possible (Flutter plugin:
cupertino_iconsorflutter_icons) - Custom icons: Export as SVG or icon font
- Sizes needed: 16×16pt, 20×20pt, 24×24pt, 32×32pt, 48×48pt
- Format: Emoji (built-in Unicode) OR custom SVG
- Recommendation: Use emoji for simplicity (😊❤️🎉😌🤔😢😊😍😔😰😤😌)
- Sizes: 20×20pt, 24×24pt, 32×32pt
- Files (if custom):
emotion-happy.svg,emotion-grateful.svg, etc.
- Use SF Symbols:
camera.fill,photo.on.rectangle.fill - Flutter:
CupertinoIcons.camera_fill,CupertinoIcons.photo_fill_on_rectangle_fill
- This flow uses native components (camera, photo picker)
- Success checkmark uses SF Symbol
checkmark.circle.fill
Design Handoff Checklist
Deliverables for Approval
- ✅ This document: Complete UI specifications for 7 screens
- Figma file: High-fidelity mockups (14 artboards: 7 screens × Light/Dark)
- Interactive prototype: Clickable flow (Figma Prototype mode)
- Animation specs: Detailed timing and easing curves (included above)
- Flutter design tokens: Dart file with colors, typography, spacing
- Edge case documentation: All error states designed
Review Checklist
- All 7 screens designed for iPhone 15/16/17 (390-430pt width)
- Light and Dark mode variants for all screens
- iOS-native feel maintained (Cupertino widgets, iOS patterns)
- 60-second target achievable (verified in prototype)
- AI loading states engaging (shimmer, progress indicators)
- Emotion selector intuitive (12 emotions, multi-select)
- Accessibility: VoiceOver labels, Dynamic Type support, WCAG AA contrast
- Responsive behavior documented for all breakpoints
- Edge cases handled (permissions denied, AI failure, network errors)
- Animations specified with timing and easing curves
- Flutter implementation notes provided
- Design tokens exported in Dart format
Next Steps After Approval
Phase 3: Timeline & Entry Detail View
After approval of Photo Capture & Entry Creation Flow, design remaining screens: Screens to design (5-6 screens):- Timeline (Grid View) - Main browsing experience
- Timeline (Empty State) - First-time user guidance
- Entry Detail View - Full entry with photo, text, emotions, metadata
- Entry Edit Mode - Edit existing entries
- Search & Filter - Keyword search, date filter, emotion filter
- Settings - Account, notifications, privacy, help
Appendix: Design System Cross-Reference
This UI specification uses the following components from/docs/design/ux/design-system.md:
Navigation Components:
- 1.2 Navigation Bar (Top Bar) - Screen 6
- 2.1 Text Field (Journal Entry) - Screen 6
- 2.2 Camera Capture - Screen 2
- 2.3 Photo Picker (Library) - Screen 4
- 2.4 Emotion Selector - Screen 6
- 3.1 Primary Button - All screens
- 3.2 Secondary Button - Screen 3
- 3.3 Text Button (Link) - Screen 6 (Refresh prompts)
- 4.3 AI Prompt Card - Screen 6
- 4.4 Loading State (Skeleton Screen) - Screen 6
- 4.6 Error State - Screen 6 (AI failure)
- 5.1 Toast Notification - Screen 6 (multi-select hint)
- 5.3 Progress Indicator - Screen 6 (AI loading, photo upload)
- Bottom Sheet (Screen 1) - Entry Creation source selector
- Photo Review (Screen 3) - Full-screen photo with action buttons
- Photo Editor (Screen 5) - Crop and rotate tools
- Success Celebration (Screen 7) - Animated checkmark with confetti
Approval
Stakeholders:- Product Designer (self) - Design completeness, quality
- UX Designer - Style guide adherence, accessibility
- Senior Product Manager - PRD alignment, user stories coverage (Stories 1.1-2.4, 3.2-3.4)
- Frontend Developer (iOS/Flutter) - Technical feasibility, implementability
- Backend Developer - API requirements (AI prompts, photo upload)
- Chief Product Officer - Brand alignment, strategic fit
Revision History
| Version | Date | Changes | Author |
|---|---|---|---|
| 1.0 | 2025-11-10 | Initial UI specification for Photo Capture & Entry Creation Flow (Phase 2: 7 screens) | Product Designer |
END OF PHOTO CAPTURE & ENTRY CREATION FLOW UI SPECIFICATION Related Documents: Next Phase: After approval, proceed to Phase 3: Timeline & Entry Detail View (5-6 screens) This is the most important flow in the app - it makes or breaks the 60-second target and the entire product experience. Every detail has been designed to feel effortless and delightful.