Size the homepage pet from LCD height instead of width alone, and soften the forgot-password link so it reads secondary to the password label.
Habit Pet
Calgary hackathon app for building habits while caring for a customizable pixel pet.
Stack
- Next.js 16 (App Router)
- Supabase (auth + Postgres)
- Tailwind CSS + shadcn/ui
- Vercel deployment via GitHub Actions
Features
- Auth — email/password sign up and login
- Onboarding — focus-topic quiz, then required avatar customization (DB-gated)
- Avatar — layered sprite pet with per-layer styles and hex colors, naming, equipped shop items
- Habits — catalog + custom habits, streaks, coin rewards
- Daily quiz — wellness sliders and journal that affect pet mood
- Shop — buy and equip items from
shop_items/user_items(hats, glasses, backgrounds) - Profile — focus topic, vibe, and reminder preferences
User flow
- Sign up / sign in
- Step 1: onboarding quiz (focus topic only)
- Step 2: avatar customization (required confirm + pet name)
- Main app via bottom nav: Pet, Habits, Quiz, Shop, Profile
Onboarding progress is stored in the database (profiles.onboarding_quiz_complete, profiles.onboarding_complete, avatar_state.avatar_customized) and mirrored in auth metadata for fast client checks.
On the Pet tab, users rename their pet and switch between Overview and Customize sub-tabs.
Local setup
-
Install dependencies:
npm install -
Create local environment file:
cp .env.example .env.local -
Add Supabase values to
.env.local:NEXT_PUBLIC_SUPABASE_URL= NEXT_PUBLIC_SUPABASE_ANON_KEY= -
Apply migrations locally (Supabase CLI):
supabase db reset -
Start the app:
npm run dev
Avatar customization data
Stored in avatar_state:
| Column | Purpose |
|---|---|
avatar_name |
Pet display name |
skin_color |
Skin layer hex color |
pants_style / pants_color |
Pants variant id + hex |
shoe_style / shoe_color |
Shoes variant id + hex |
torso_style / torso_color |
Torso variant id + hex |
eye_type / eye_color |
Eyes variant id + hex |
head_style / head_color |
Head variant id + hex |
avatar_customized |
True after onboarding confirm |
equipped_items |
Shop item ids currently equipped |
Style columns are validated against allowed variant ids (none, pants-1, …). Shop accessories overlay equipped variants at render time without overwriting saved customization.
Sprite assets are added manually under public/character/{layer}/ (e.g. public/character/head/head-1.png). Paths must match the variant ids in lib/character/presets.ts and supabase/seed.sql.
Shop
- Sells character layer styles from
public/character/(head-1,pants-2, etc.) - Shop item
id= variant id,type= layer id (head,pants,shoes,torso,eyes) - Purchases unlock styles in
user_items; owned styles appear in Customize and can be equipped from the shop - Catalog seeded in
supabase/seed.sql
Supabase
- Migrations:
supabase/migrations/ - Seed:
supabase/seed.sql - Config:
supabase/config.toml
Production deploys on push to main via .github/workflows/deploy.yml (lint, build, supabase db push --include-seed, Vercel).
Routes
| Route | Access |
|---|---|
/ |
Public |
/auth/* |
Public |
/onboarding/quiz |
Authenticated, quiz incomplete |
/onboarding/customize |
Authenticated, quiz complete, avatar not confirmed |
/avatar |
Authenticated, onboarding complete |
/habits, /daily/quiz, /shop, /profile |
Authenticated app |
/character-creator |
Redirects to /avatar?tab=customize |