Billie
Finance.
A dark-mode personal finance companion for mobile web — combining multi-card management, Gemini AI coaching, and social spending competitions in a single conversational interface designed to make credit health feel winnable.
01 · Overview
Project at a Glance
A social-first personal finance app that reframes credit health as a competitive sport — combining a physics-driven card wallet, Gemini AI coaching, and peer leaderboards in a single mobile web interface.
🎯 The Problem
Young adults managing multiple credit cards struggle to act on financial data that feels abstract and punitive — existing apps frame credit health as a deficit rather than a skill to develop.
💡 The Solution
A single-screen mobile app that makes credit health competitive and rewarding — with animated card management, Gemini AI coaching, and peer groups (Cartels) that gamify financial discipline.
⚙️ Design Principle
Finance should feel like a game you can win, not an audit you're failing. Every screen rewards progress and socialises the habit.
📐 Scope
Single-file React application. Frontend-only with mock data — Gemini 2.5 Flash API powers AI features. DiceBear Personas API renders member avatars. localStorage persists onboarding state.
02 · Process
Double Diamond Method
The Double Diamond structured Billie's design across two diverge-converge cycles — first to diagnose why personal finance apps fail to stick, then to build the right social-first intervention.
Phase 01
Discover
Competitive audit of Mint, YNAB, Copilot, and Revolut revealed all four frame finance as deficit management. User sentiment patterns across App Store reviews surfaced guilt and anxiety as dominant themes — confirming a motivational gap, not an informational one.
Phase 02
Define
Defined the core problem as: users know they overspend — they lack a mechanism that makes improvement feel rewarding and visible. The goal shifted from 'help users understand their finances' to 'make credit health feel like a streak worth maintaining.'
Phase 03
Develop
Explored three directions: solo gamified challenges (low retention without social proof), a finance social network (privacy concerns at scale), and embedded peer groups within a card management app. The third path combined utility with accountability.
Phase 04
Deliver
Converged on Billie: a mobile card wallet with Cartels for social competition, a Gemini AI coach (the Vault) for contextual education, and a gamified XP system that rewards on-time payments and low utilisation — not just app opens.
Research Methods Used
Competitive Audit
Systematic review of Mint, YNAB, Copilot, and Revolut across six dimensions: onboarding friction, emotional tone, social features, retention hooks, notification strategy, and error framing. Identified the universal absence of peer accountability as the structural gap.
Sentiment Analysis
Analysis of App Store reviews across leading fintech apps for recurring emotional language. Guilt, anxiety, and feeling overwhelmed emerged as dominant themes in negative reviews — validating the hypothesis that emotional design, not missing features, drives abandonment.
Concept Testing
Three interaction prototypes tested across the solo gamified model, a finance social feed, and the Cartel group model. The Cartel structure showed the strongest stated intent to return and lowest reported financial anxiety — validating the social accountability mechanic.
03 · User Flow
App Walkthrough
Seven screens from first launch to AI-powered coaching. Tap any card to reveal the design rationale behind each screen.
Welcome to Billie
Track spending, join Cartels to compete, and learn from the Vault.
Get Started
Brand introduction presented as a modal overlay on first launch. Dismisses on 'Get Started' and writes a localStorage flag to suppress on all subsequent visits.
localStorage prevents re-showing the overlay, matching native app first-run behaviour without requiring a backend session model.
Dismissal sets React state immediately and persists asynchronously — the transition feels instant with zero perceived lag.
The Billie logomark SVG uses stroke-based paths on a black background, remaining crisp at all sizes without font or icon dependencies.
Good Morning,
Alex
Total Balance
$36,398
Send
Request
Recent Spending
Netflix
Today
-$14.99
Whole Foods
Today
-$124.50
"Do not save what is left after spending..."
— WARREN BUFFETT
Consolidated view of total balance across all five cards, Send and Request quick actions, three recent transactions, nearby offers preview, and live Cartel activity feed.
Balance masking via the Eye toggle uses a single boolean state — no data is cleared, only the rendering path changes.
Tapping the balance card navigates directly to the Spendings tab — the most-used analytical feature is one tap from the home screen.
The XP badge is visible on the profile avatar without opening the profile screen, surfacing the gamification layer passively on every home visit.
Analysis
Spending & Offers
Limit
$102K
Spent
$36K
Left
$65K
Spendings
Offers
All
Dining
Groceries
Travel
Netflix
Entertainment-$14.99
Whole Foods
Groceries-$124.50
Starbucks
Dining-$6.45
Dual-tab view of filterable transaction history and location-aware merchant offers. Limit, Spent, and Left statistics surface the utilisation rate with a contextual 'ideal' anchor.
useMemo gates category extraction so the filter set never recomputes on unrelated state changes — the feed remains responsive at any transaction volume.
The Offers tab gates behind a geolocation permission request, providing a clear value proposition before asking for sensitive browser access.
Utilisation is shown with 'Ideal: under 30%' inline — users get the benchmark without navigating to a separate education screen.
Alpha Spenders
Smart Leaderboard · 8 Members
Your Rank
#1
Top 5% Smart Spender
A
Alex
98
↑
S
Sarah
95
↑
M
Mike
88
↓
Inside a Cartel, members are ranked by a composite credit score combining utilisation, payment timing, and trend direction. The sort runs client-side on the members array.
DiceBear Personas are seeded by member name, ensuring each avatar is visually consistent across sessions without storing or serving image assets.
The rank sort is a pure client-side array sort — no API call required, no loading state, instant rank updates within a session.
Trend indicators use distinct SVG icons (up arrow, down arrow, flat line) alongside colour — satisfying WCAG 1.4.1 for non-colour differentiation of state.
The Vault
Where smart spenders get an edge
💡 Today's Intel
✦ Analyze
Paying minimum on Card B costs extra interest. Prioritize it.
2 more on-time payments and your score could jump a band.
Ask Vault anything…
Credit Utilisation
2 minMinimum Payments
3 min🎯 Missions
Drop utilisation below 40%
+50 XPGemini 2.5 Flash analyses the current transaction feed and returns three personalised coaching tips. The Ask Vault input accepts any free-form financial question.
The Gemini prompt includes an explicit instruction — 'supportive coaching tips, not roasts' — making encouragement framing a prompt constraint, not a UI choice.
JSON parsing is wrapped in try/catch; on failure the previous intel cards are preserved, so the Vault never shows a blank state on API error.
Ask Vault fires on both Enter key and tap, ensuring the interaction is equally efficient for keyboard and touch users.
Total Balance
$36,398
Utilization
35.7%
Platinum
$4,250
Business
$12,800
Travel
$3,100
Press to Eject Cards
An animated card stack ejects on press to reveal five payment cards. Selecting a card opens a full-screen detail view with balance, quick actions, and transaction history.
The eject mechanic uses CSS translateY driven by a single React boolean — no animation library is imported, keeping the dependency surface minimal.
Each card's gradient is defined in the cards data array rather than hardcoded in JSX, making the palette trivial to retheme per institution or brand.
The wallet overlay blurs and scales the background to 90% using CSS, signalling modal context without a route change or navigation stack push.
Send Money
Amount
$
0.00
Recent Contacts
M
Mom
M
Mike
S
Sarah
E
Elon
Send Now
SENDING FROM
Platinum Card
A bottom-sheet overlay for initiating peer transfers. Recent contacts are surfaced as scrollable avatar chips above a full-width amount input field.
The overlay uses absolute positioning with a blurred backdrop — no route change, no navigation stack push, no URL mutation.
Contact avatars use the first letter of each name as a fallback glyph, eliminating all image asset requests for the contact row.
Both Send and Request flows share one overlay component with the action type as a prop, halving the JSX surface for two near-identical screens.
05 · Accessibility
WCAG 2.2 Compliance
Accessibility was evaluated against WCAG 2.2 AA throughout development. The dark palette, full-width touch targets, and semantic button elements meet most criteria — documented gaps below carry implementation specifications for the next iteration.
1.4.3 Contrast (AA)
Colour Contrast
Primary text (#F0EEE9) on Billie's zinc-950 background exceeds 15:1. Secondary text (zinc-400 / #A8A49D) on dark surfaces meets the 4.5:1 AA threshold. Category colour chips always include a text label — colour never encodes state alone.
#F0EEE9 on zinc-950 — exceeds 15:1
2.5.3 Touch Target
Touch Targets
All primary action buttons span the full container width with p-4 padding, far exceeding the 44×44px requirement. Icon-only controls (Send, Freeze, More on card detail) use w-14 h-14 — 56px — matching the enhanced WCAG 2.5.3 target size.
Full-width CTAs · 56px icon buttons
2.4.7 Focus Visible
Focus & Labels
Key icon-only buttons carry explicit aria-label attributes — aria-label='Eject Cards' on the wallet trigger and aria-label='Open Profile' on the avatar button. Tailwind's focus:ring utilities provide visible focus indicators on all interactive elements.
aria-label on wallet eject · profile button
1.4.1 Use of Colour
Non-Colour Cues
Transaction amounts pair positive/negative icons with colour. Cartel trend indicators combine SVG direction icons (TrendingUp, TrendingDown, Activity) with emerald/red/gray colour — colour is never the sole differentiator for any state change throughout the app.
Icon + colour on all status states
2.1.1 Keyboard Access
Keyboard Operation
Every interactive element in Billie uses a semantic <button> element — there are no div-based click handlers across the entire codebase. The Ask Vault input fires on Enter key press as well as button tap, serving keyboard users equally.
All interactions on semantic <button>
4.1.3 Status Messages
Live Regions
The Vault's AI answer panel animates in via Tailwind animate-in. A specification gap exists: the answer container does not yet carry aria-live='polite', meaning screen reader users must navigate to the element to hear the response. This is the priority fix for the next iteration.
Spec: aria-live on Vault AI answer panel
Full Criteria Review
| Criterion | Requirement | Implementation |
|---|---|---|
| 1.1.1 Non-text Content | Alt text for images | DiceBear avatar <img> tags carry alt={memberName}; decorative SVG icons use aria-hidden |
| 1.4.11 Non-text Contrast | UI component contrast ≥ 3:1 | Button borders (rgba 0.12 white) against dark bg meet the 3:1 minimum; active states use full-opacity borders |
| 2.4.4 Link Purpose | Descriptive link text | Nav labels are descriptive nouns (Home, Vault, Cartel, Spendings, Wallet) — no 'click here' patterns exist |
| 3.2.2 On Input | No unexpected context change | Tab switching requires explicit taps; no auto-navigation triggered by input field changes anywhere in the app |
| 3.3.1 Error Identification | Error messages present | Geolocation denial surfaces an inline fallback state with a clear prompt; there are no silent failure states |
| 2.4.11 Focus Appearance (2.2) | Focus indicator ≥ 2px | Specification gap: explicit focus ring dimensions are not enforced. Next iteration to add focus-visible:ring-2 ring-offset-2 globally via Tailwind config. |
06 · Inclusivity
Designed for Financial Anxiety
Financial anxiety disproportionately affects young adults, first-generation credit card holders, and people navigating debt cycles. Billie was designed to serve these users first — assuming limited financial literacy, high emotional stakes, and varied device capability.
Physical & Motor
Full-Width Touch Targets Throughout
All primary action buttons span the full container width. Icon-only controls (Send, Freeze, More) use w-14 h-14 — 56px — exceeding WCAG 2.5.3. The card eject trigger is a 56px-wide full-height button at the bottom of the wallet, impossible to miss.
Visual
High Contrast Dark Mode Throughout
Primary text on zinc-950 background exceeds 15:1 contrast. All status states (positive, negative, warning, neutral) use icon plus colour plus text label. The app is dark-first with no light mode toggle — eliminating contrast inconsistency at the cost of system preference support.
Cognitive
Encouragement, Not Deficit Framing
The Gemini prompt is explicitly constrained to 'supportive coaching tips, not roasts.' Mission XP rewards any improvement, not only perfection. Transaction category labels are neutral descriptors — Dining, Entertainment, Travel — without moral judgement attached.
Screen Readers
Semantic Markup and Explicit Labels
All icon-only interactives carry descriptive aria-label attributes. The full flow uses semantic <button> elements throughout — no div-based click handlers in the entire codebase. A specification gap exists for the Vault answer panel: aria-live='polite' is the planned fix for the next iteration.
Keyboard & Switch Access
Fully Tab-Navigable Flow
Every interaction is reachable and activatable via Tab and Enter alone. Focus order follows visual reading sequence top-to-bottom. The Ask Vault input fires on Enter key — keyboard users can complete the full AI coaching flow without touching the mouse.
Financial Literacy
Plain Language and In-Context Education
Navigation labels are plain nouns — Vault, Cartel, Spendings. The Vault section provides short 'Decode' articles on credit concepts. The Gemini prompt instructs the model to 'answer clearly and simply (ELI5)', targeting accessibility for users without financial education backgrounds.
Error Recovery
No Dead Ends in the Flow
Geolocation denial shows a clear 'permission required' state rather than an empty offers list. Gemini API failures preserve the previous intel cards — the Vault never renders a blank state. All async operations are wrapped in try/catch with non-destructive error handling.
Device & Connection
Mobile-First, Minimal Network Dependency
Billie makes no background API calls — Gemini is triggered only on explicit user actions. DiceBear avatars are fetched on demand per member view. The app loads from a single bundled file with no lazy-loaded chunks, making it resilient to slow connections.
Design Principle
"Design for the most financially anxious user first. If the interface adds shame, it will drive avoidance. If the improvement doesn't feel winnable, users will never return."
Traditional finance apps optimise for users who are already disciplined. Billie optimises for users who want to be. The gamification layer, the AI encouragement constraint, and the social accountability mechanic all serve this one design principle — make improvement feel possible for someone who has been failing so far.
07 · Technology
Technology
A deliberately lean stack — chosen to maximise demonstrability in a sandboxed environment and keep the entire codebase explorable in a single read.
React 18
useState · useEffect · useRef · useMemo
Tailwind CSS
zinc-950 palette · animate-in · opacity modifiers
lucide-react
20+ icons · consistent 24px stroke weight
Gemini 2.5 Flash
generateContent endpoint · JSON output · ELI5 prompts
DiceBear Personas
Seed-based SVG avatars · name-consistent across sessions
localStorage
First-run onboarding flag · single boolean key
Why Gemini over the OpenAI API?
Gemini 2.5 Flash offers a generous free tier with fast response times — critical for a demo that calls the API live on user interaction.
Why Tailwind for a complex dark mobile UI?
Tailwind's zinc-950/900/800 scale maps directly to Billie's layered dark palette, reducing custom CSS to near-zero while enabling fine-grained visual hierarchy.
Why localStorage for onboarding state?
Billie has no backend authentication layer. localStorage provides the simplest persistent first-run detection without introducing a session model.
08 · Trade-offs
Considered Trade-offs
Three product decisions that shaped the character and constraints of Billie.
01 —
Social Layer as Primary Motivator
Cartels make credit health a shared competitive activity — the social obligation sustains the habit where personal discipline alone fails.
02 —
AI Coach, Not AI Judge
The Gemini prompt explicitly requests 'supportive coaching tips, not roasts.' The encouragement instruction lives in the prompt, not the interface.
03 —
Single-File Architecture
All state, UI, and AI calls live in one React file — sacrificing modularity for legibility. For a portfolio artefact, reviewability outweighs conventional separation of concerns.
| Attribute | Decision Made | Alternative Considered |
|---|---|---|
| AI provider | Gemini 2.5 Flash via REST fetch | OpenAI GPT-4o-mini (costlier, requires SDK or same pattern) |
| Transaction data | useMemo-generated mock array | CSV import / real bank API (out of scope for demo) |
| Avatar rendering | DiceBear Personas via CDN img src | Initials-based SVG avatars (consistent without network dependency) |
| Wallet animation | CSS translateY via React boolean | Framer Motion (adds ~40KB, no additional expressiveness here) |
| Cartel scoring | Client-side composite sort on member array | Backend aggregate score with server persistence (no backend in scope) |