Browser the Cat
Browser the Cat is BookWish's friendly bookstore cat mascot who helps users discover features and provides contextual guidance throughout the app.
Character Overview
Browser is a helpful, warm, and friendly cat who lives in the BookWish bookstore. He appears at key moments to offer tips, celebrate achievements, and make the app experience more delightful and human.
Personality Traits:
- Helpful but not intrusive
- Warm and encouraging
- Playful but professional
- Book-loving and knowledgeable
Visual Design
Appearance
Browser appears as a Lottie animation positioned in the bottom-left corner of the screen, accompanied by a speech bubble containing his message.
Visual Properties:
- Animation size: 80x80 pixels
- Position: Bottom-left (100px from bottom, 16px padding)
- Speech bubble: Dark blue (inkBlue) with white text
- Speech bubble radius: 16px
- Shadow: Subtle drop shadow for depth
Animation States
Browser has five distinct animation states that convey different moods and contexts:
| Animation | Usage | Context |
|---|---|---|
idle | Default resting state | When no specific emotion needed |
speaking | Providing hints or information | Default for most messages |
thinking | Loading or processing | Error states, awaiting response |
waving | Greeting users | Onboarding, first visits |
sleeping | Passive presence | Unused currently |
Animation Files:
/app/assets/lottie/browser_idle.json/app/assets/lottie/browser_speaking.json/app/assets/lottie/browser_thinking.json/app/assets/lottie/browser_waving.json/app/assets/lottie/browser_sleeping.json
Implementation
Widget Structure
Browser is implemented as a persistent overlay widget (BrowserOverlay) that appears above the main content.
File: /app/lib/ui/widgets/browser_overlay.dart
// Browser appears when enabled, visible, and has a message
if (!browserState.isEnabled || !browserState.isVisible || browserState.message == null) {
return const SizedBox.shrink();
}
Browser State
File: /app/lib/state/browser_state.dart
class BrowserState {
final bool isVisible; // Currently showing
final bool isEnabled; // User preference (can be disabled)
final String? message; // Current message text
final BrowserAnimation animation; // Animation state
final BrowserContext context; // Usage context
final Duration? autoDismissAfter; // Auto-hide timer
}
Browser Properties
| Property | Type | Description |
|---|---|---|
isVisible | bool | Whether Browser is currently displayed |
isEnabled | bool | User preference setting (persisted) |
message | String? | Text to display in speech bubble |
animation | BrowserAnimation | Current animation state |
context | BrowserContext | Usage context for analytics |
autoDismissAfter | Duration? | Optional auto-hide delay |
Display Sizes
| Size Type | Dimensions | Usage |
|---|---|---|
| Standard | 80x80px | Main overlay appearance |
| Error State | 100x100px | Larger size in BwErrorState widget |
Context Appearances
Onboarding
When: First launch of the app
Animation: waving
Message: "Hi, I'm Browser. I'm the BookWish bookstore cat."
Duration: 5 seconds auto-dismiss
Implementation: /app/lib/ui/pages/auth/onboarding_page.dart
ref.read(browserNotifierProvider.notifier).show(
message: "Hi, I'm Browser. I'm the BookWish bookstore cat.",
context: BrowserContext.onboarding,
animation: BrowserAnimation.waving,
autoDismiss: const Duration(seconds: 5),
);
Tab Hints
Browser appears on first visit to major tabs to introduce functionality.
Contexts:
wish_tab_first- First visit to Wish tabshare_tab_first- First visit to Share tabread_tab_first- First visit to Read tab
Animation: speaking
Duration: 5 seconds auto-dismiss
Behavior: Shows once per hint key, tracked in local storage
Empty States
Browser can appear in error states to provide a friendlier experience.
When: Data loading fails
Animation: thinking
Message: "Let me help you try that again!"
Implementation: Optional in BwErrorState widget
BwErrorState(
title: 'Something went wrong',
subtitle: 'Check your connection',
onRetry: _handleRetry,
showBrowser: true,
)
Achievements & Celebrations
When: User completes significant actions
Animation: speaking (could use waving for extra enthusiasm)
Context: BrowserContext.celebration
Example: "Great job adding your first book to your wishlist!"
Confirmations
When: Pre-purchase or important actions
Animation: speaking
Context: BrowserContext.confirmation
Purpose: Provide helpful context before checkout
Loading States
When: Waiting for operations to complete
Animation: thinking
Context: BrowserContext.loading
Purpose: Indicate processing with friendly presence
Settings Integration
Users can control Browser's appearance through the Preferences tab in Settings.
File: /app/lib/ui/overlays/settings_overlay.dart
SwitchListTile(
title: Text('Show Browser'),
subtitle: Text('Browser the cat helps you discover features'),
value: browserState.isEnabled,
onChanged: (value) {
ref.read(browserNotifierProvider.notifier).setEnabled(value);
},
)
User Control:
- Users can disable Browser entirely
- Preference is persisted in local storage (Hive)
- When disabled, Browser never appears
- Setting is accessible under Settings > Preferences > Helper
Animation Guidelines
When to Use Each Animation
-
Waving - First impressions, warm welcomes
- Onboarding
- After long absence
- Special celebrations
-
Speaking - Default for communication
- Feature hints
- Confirmations
- General guidance
- Celebrations
-
Thinking - Processing or uncertainty
- Error states
- Loading operations
- Complex decisions
-
Idle - Passive presence
- Default fallback
- Minimal distraction needed
-
Sleeping - Reserved for future use
- Night mode?
- Inactive periods?
Animation Best Practices
- Keep animations smooth and brief (under 3 seconds loop)
- Ensure animations work well at 80x80px size
- Test animations on various devices and screen densities
- Maintain consistent character design across all animations
- Ensure animations don't interfere with touch targets
Writing Browser's Voice
Tone Guidelines
Browser speaks in first person and maintains a consistent, helpful tone:
- Friendly but professional - "Hi, I'm Browser" not "Hey there!"
- Brief and clear - Short sentences, under 20 words when possible
- Action-oriented - Focus on what users can do
- Encouraging not demanding - Suggest, don't command
- Bookish references welcome - Cat and book puns are on-brand
Example Phrases
Good Examples:
- "Hi, I'm Browser. I'm the BookWish bookstore cat."
- "Tap here to add books to your wishlist."
- "Great job adding your first book!"
- "This is where you'll find your reading communities."
- "Let me help you try that again!"
Avoid:
- "YOU MUST DO THIS NOW!" (Too demanding)
- "This is the wishlist tab where you can add books..." (Too verbose)
- "OMG AMAZING!!!" (Too informal)
- Technical jargon or complex language
- Negative or discouraging language
Message Length
- Optimal: 10-15 words
- Maximum: 25 words
- Longer messages should be split or simplified
Hint Best Practices
- Show once - Use
showOnceHint()for feature introductions - Time wisely - 5 seconds auto-dismiss for hints
- Context matters - Show hints when users need them, not randomly
- Allow dismissal - Always let users tap to dismiss
- Respect preferences - Honor the disabled setting
Technical Implementation
Showing Browser
// Simple show
ref.read(browserNotifierProvider.notifier).show(
message: 'Your message here',
context: BrowserContext.tabHint,
animation: BrowserAnimation.speaking,
autoDismiss: const Duration(seconds: 5),
);
// Show once (tracked hint)
await ref.read(browserNotifierProvider.notifier).showOnceHint(
hintKey: BrowserHints.wishTabFirstVisit,
message: 'Create wishlists for books you want to read!',
context: BrowserContext.tabHint,
animation: BrowserAnimation.speaking,
);
Hiding Browser
// Manual hide
ref.read(browserNotifierProvider.notifier).hide();
// Auto-dismiss (specify when showing)
autoDismiss: const Duration(seconds: 5)
Hint Tracking
Hints are tracked in local storage to prevent repeat displays.
File: /app/lib/utils/browser_hints.dart
Predefined Hint Keys:
wish_tab_first- Wish tab introductionshare_tab_first- Share tab introductionread_tab_first- Read tab introductionfirst_wishlist_add- First wishlist item addedpre_purchase- Pre-checkout confirmation
Error Handling
Browser includes fallback UI if Lottie animations fail to load:
errorBuilder: (context, error, stackTrace) {
return Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: AppColors.tealEdge,
borderRadius: BorderRadius.circular(40),
),
child: const Icon(
CupertinoIcons.paw,
color: Colors.white,
size: 40,
),
);
}
Displays a paw icon in a teal circle if animation files are missing or corrupt.
Accessibility Considerations
Browser is primarily a visual enhancement and should not be required for app functionality.
- Browser can be disabled entirely by users
- All information conveyed by Browser should also be available through standard UI
- Browser messages are readable text (not embedded in animations)
- Tappable to dismiss (meets minimum touch target size)
- Consider adding semantic labels for screen readers in future updates
Future Enhancements
Potential improvements to the Browser system:
- Sleeping animation usage - Activate during inactive periods or night mode
- More animations - Reading, jumping, playing for more contexts
- Screen reader support - Add semantic labels and announcements
- Customization - Allow users to choose different mascots
- Context awareness - More intelligent hint timing based on user behavior
- Achievement system - Special Browser appearances for milestones
- Accessibility improvements - Reduced motion alternative animations