Gamer Dashboard Project Plan
Goal
Create an authenticated /gamer page that presents Lifehub as a pixel RPG dashboard. The page should feel like a game-style command center while remaining useful for daily review across tasks, habits, finances, goals, sports/activity logs, XP, achievements, challenges, and levels.
Implementation Status (2026-05-06)
A first pass of /gamer is live in this branch (commits af25f94 feat: add gamer dashboard snapshot and 91135bf gamer dashboard WIP). What shipped vs. what changes next:
Shipped:
/gamerroute is mounted insideauthenticated :user do(not at the top level) so signed-out users redirect to login through the normal Devise flow.GamerDashboardController,GamerDashboardPolicy,GamerDashboard::Snapshot,GamerDashboardHelper, sidebar/navbar/footer-nav links, en + pt-BR translations.- Pixel character PNGs for all eleven tiers in
app/assets/images/gamer/characters/, normalized to square crops so the avatar renders without distortion. - Pixel-art world map at
app/assets/images/gamer/maps/lifehub-world.pngrendered at the source image's true aspect ratio. - Player panel, Habit Forest panel with inline habit toggles (
button_to toggle_habit_path(habit, return_to: gamer_path)so the user can mark habits done directly from/gamer), Tasks/Goals/Sports/Quest-Feed/Finance/Gamification panels. - 8 clickable map zones positioned over the map image with label + a one-line stat each.
Changing in this update (drives the rest of this plan):
- The four center-column cards beneath the map (Missões Ativas / Quadro de Tarefas / Templo de Metas / Campo de Treino) are removed from the body. Their preview content moves into hover cards that appear on the corresponding map zone.
- Every map zone (all 8) gets a hover card showing up to 4 preview items. Hovering the zone reveals the card; clicking the zone or anywhere on the card navigates to that section's full page.
- The left column gains, beneath the Habit Forest:
- A Weekly Activity panel showing this week's habit completions, tasks done, focus minutes, activity logs, and total XP earned this week.
- An Achievements Row showing only icons of the user's most-difficult unlocked achievements (single row, "see all" link to
/gamification/achievements).
User Experience
The dashboard should resemble the provided GitHub gamer-style reference, adapted to Lifehub instead of GitHub. It will be a dark-first, dense, pixel-inspired dashboard with a player profile, a central world map, quest panels, and progression widgets.
The first screen should answer three questions:
- What should I do next?
- How am I progressing today and this week?
- What level, achievements, and rewards am I working toward?
Route
Mounted inside the existing authenticated block in config/routes.rb:
authenticated :user do
get "gamer", to: "gamer_dashboard#show"
end
Signed-out users hit Devise's standard redirect to new_user_session_path. This is a new dashboard, not a replacement for the existing dashboard, finance_dashboard, tasks, habits, or gamification pages.
Layout
The page uses a 3-column grid on desktop (280px / 1fr / 320px), single-column stacked on mobile. The center column is the map and only the map. Everything that used to live beneath the map has either moved into a map-zone hover card or into the left column.
┌────────────────────┬──────────────────────────────┬────────────────────┐
│ Player Panel │ Lifehub World Map (only) │ Finance Panel │
│ Habit Forest │ → 8 map zones │ Gamification Panel │
│ (inline toggles) │ → each shows a hover card │ │
│ Weekly Activity │ with up to 4 preview │ │
│ Achievements Row │ items │ │
└────────────────────┴──────────────────────────────┴────────────────────┘
Page Sections
Player Panel (left column)
The player card shows the user's RPG identity:
- Current 16x16 pixel character (square-cropped sprite,
image-render-pixel) - User name (from
finance_settings.display_nameor email-derived fallback) - Current level title
- XP progress bar with current/needed XP
- Three mini-stats: unlocked achievements count, active challenges count, today's habit progress
Habit Forest Panel (left column)
The Habit Forest stays interactive — habits completed from this panel count immediately and the page redirects back to /gamer:
- Today's completion progress (count + percentage bar)
- Longest current streak and at-risk count mini-stats
- Up to 6 of today's habits, each with an inline toggle button posting to
toggle_habit_path(habit, return_to: gamer_path) - Reuses
Habit::DashboardAggregator
Weekly Activity Panel (left column, NEW)
A compact weekly summary card beneath the Habit Forest. Shows seven-day totals (Mon–Sun of the current week, in Time.zone):
- Habit completions this week
- Tasks completed this week
- Activity logs / minutes this week
- Total XP earned this week (sum of
XpTransaction.amountwherecreated_at >= current_week.beginning) - A small bar mini-chart showing per-day XP for the last 7 days (DRY: pure DOM divs, no chart library)
Achievements Row (left column, NEW)
A single horizontal row showing icons of the user's most difficult unlocked achievements beneath the Weekly Activity panel:
- Sort
UserAchievementrecords by theirAchievement.rarity(legendary > epic > rare > uncommon > common), tie-breaking byrequirement_value DESCthenunlocked_at DESC. - Render only the icon (32×32) with a tooltip showing achievement name + rarity.
- Show up to 6 icons; the row caps at the column's natural width.
- Trailing "see all" pill linking to
gamification_achievements_path.
Lifehub World Map (center column)
The center column is the map alone. The map image is rendered at its source aspect ratio (so the world doesn't squash or stretch). Eight zones are positioned absolutely over named coordinates:
| Zone | Slug | Hover card preview | Click target |
|---|---|---|---|
| Task Board | tasks |
Active count, overdue count, top 4 active todo cards (title + priority chip) | todo_board_path |
| Habit Forest | habits |
Today's completion %, top 4 habits with checkmark state | habits_path |
| Finance Vault | finance |
Total patrimony, monthly expenses, investments %, monthly growth (4 KPIs) | finance_dashboard_path |
| Goal Temple | goals |
Active goal count, top 4 goals by progress (name + percentage bar) | goals_path |
| Training Grounds | sports |
Activities this week, total minutes, top 4 recent activity logs | sports_path |
| Challenge Arena | challenges |
Active count, top 4 active challenge participations w/ progress | challenges_path |
| Achievement Hall | achievements |
Unlocked count, top 4 most recently unlocked achievements (icon + name) | gamification_achievements_path |
| Level Shrine | levels |
Current level + title, XP progress bar, next-tier character preview, 4 latest XP txs | gamification_path |
A zone is fully clickable (the wrapper is the <a> tag). Hovering the zone reveals its preview card, anchored above or to the side of the zone depending on edge-clamping. Hovering the card itself keeps it open. The card itself is also a click target leading to the same destination.
Map Zone Hover Card (interaction model)
- Desktop: pure CSS hover via
:hoverand:focus-withinon the zone wrapper, with the card absolutely positioned andpointer-events: autoso it stays open while the cursor moves into it. - Touch / no-hover devices: a Stimulus controller (
gamer-map-zone) listens forclickand toggles anis-openclass. A second tap (or a tap outside) navigates / closes. - Keyboard:
:focus-withinmatches when the zone link is focused;Escapecollapses the open card. - Z-index discipline: open cards sit above the map but below the global navbar.
Finance Panel (right column)
Right-column summary; unchanged from the shipped pass:
- Total patrimony in BRL
- Monthly expenses
- Investments value
- Monthly growth
- Active financial goals
Reuses existing finance helpers and Dashboard::DataAggregator.
Gamification Panel (right column)
Right-column summary; unchanged from the shipped pass:
- Current level + title
- XP in current level / XP needed for next level
- Recent XP transactions (top 4)
- Active challenge participations
- Completed challenge count
Reuses Gamification::XpAwarder.find_or_create_profile, Gamification::LevelCalculator, UserAchievement, ChallengeParticipation, XpTransaction.
Pixel Character Strategy
I can implement any of the three sprite approaches without requiring additional assets from the user.
Option 1: Generated PNG Sprites
I can generate 16x16-style pixel character PNGs and place them under:
app/assets/images/gamer/characters/
Recommended because it will look closest to the reference image. This may use the image generation tool during implementation, then the generated assets become normal repository assets.
Option 2: CSS Pixel Characters
I can build the characters using CSS grids or box shadows. This avoids image files and is very controllable, but it usually looks less expressive than true pixel art.
Option 3: Inline SVG Pixel Sprites
I can create SVG sprites that render as crisp pixel art. This is lightweight and version-control-friendly, but still less organic than generated PNGs.
Recommendation
Use Option 1 for the level characters, with a simple fallback path to Option 3 if generated assets are not acceptable during implementation.
Character tiers should change every five levels:
| Levels | Tier | Character Direction |
|---|---|---|
| 1-4 | Rookie | simple starter outfit |
| 5-9 | Scout | cap, small backpack |
| 10-14 | Adventurer | stronger pose, utility gear |
| 15-19 | Specialist | finance/task/habit hybrid gear |
| 20-24 | Master | refined armor and brighter palette |
| 25-29 | Grand Master | cape or ornate accessory |
| 30-34 | Sage | calm magical/strategic look |
| 35-39 | Sage Elite | stronger aura and rare colors |
| 40-44 | Legend | heroic silhouette |
| 45-49 | Mythic Legend | high-tier glow and special gear |
| 50 | Transcendent | final unique character |
The first implementation can ship with one character per tier. Later, each tier could have variants based on the user's strongest XP category.
Architecture
Thin controller + namespaced snapshot facade. After the layout restructure, the file list looks like:
app/controllers/gamer_dashboard_controller.rb # shipped, no changes
app/models/gamer_dashboard/snapshot.rb # extended with weekly + zone-preview readers
app/policies/gamer_dashboard_policy.rb # shipped, no changes
app/helpers/gamer_dashboard_helper.rb # add zone helpers (gamer_zone_path, gamer_zone_preview)
app/views/gamer_dashboard/show.html.erb # restructured: 3-col grid; center is map only
app/views/gamer_dashboard/_player_panel.html.erb # shipped, no changes
app/views/gamer_dashboard/_habits_panel.html.erb # shipped, keeps inline toggles
app/views/gamer_dashboard/_weekly_activity.html.erb # NEW
app/views/gamer_dashboard/_achievements_row.html.erb # NEW
app/views/gamer_dashboard/_world_map.html.erb # rebuilt to render zones with hover cards
app/views/gamer_dashboard/_zone.html.erb # NEW: one zone link + its hover card
app/views/gamer_dashboard/_zone_preview/_tasks.html.erb # NEW
app/views/gamer_dashboard/_zone_preview/_habits.html.erb # NEW
app/views/gamer_dashboard/_zone_preview/_finance.html.erb # NEW
app/views/gamer_dashboard/_zone_preview/_goals.html.erb # NEW
app/views/gamer_dashboard/_zone_preview/_sports.html.erb # NEW
app/views/gamer_dashboard/_zone_preview/_challenges.html.erb # NEW
app/views/gamer_dashboard/_zone_preview/_achievements.html.erb # NEW
app/views/gamer_dashboard/_zone_preview/_levels.html.erb # NEW
app/views/gamer_dashboard/_finance_panel.html.erb # shipped, no changes
app/views/gamer_dashboard/_gamification_panel.html.erb # shipped, no changes
app/javascript/controllers/gamer_map_zone_controller.js # NEW: tap-to-open on touch devices
Removed in the restructure (their content moves into hover cards):
app/views/gamer_dashboard/_quest_feed.html.erb
app/views/gamer_dashboard/_tasks_panel.html.erb
app/views/gamer_dashboard/_goals_panel.html.erb
app/views/gamer_dashboard/_sports_panel.html.erb
GamerDashboardController#show should stay thin:
class GamerDashboardController < ApplicationController
def show
authorize :gamer_dashboard
@snapshot = GamerDashboard::Snapshot.new(current_user)
end
end
GamerDashboard::Snapshot should gather the data required by the page and expose small reader methods for the view. It should reuse existing calculators instead of duplicating business logic.
Authorization
Add a singleton-style policy:
class GamerDashboardPolicy < ApplicationPolicy
def show? = user.present?
end
The dashboard must only use current_user-owned records.
Data Sources
Use existing domain objects and calculators:
- Tasks:
TodoBoard,TodoCard - Habits:
Habit::DashboardAggregator - Finance:
Dashboard::DataAggregator - Goals:
Goal,Goal::ProgressCalculatorwhere useful - Sports:
ActivityLog,Sport - XP and levels:
GamificationProfile,Gamification::LevelCalculator - Achievements:
Achievement,UserAchievement - Challenges:
Challenge,ChallengeParticipation
Visual Style
The page should be dark-first and visually distinct from the regular dashboard:
- Background near
#0d1117 - Compact pixel-inspired panels
- Subtle grid/scanline texture
- Crisp borders, not oversized rounded cards
- Small bitmap or pixel-art sprites
- Bright but balanced accents for task, habit, finance, goal, sports, and gamification zones
- Mobile layout that stacks panels cleanly without overlapping text
The page should avoid decorative-only content. Every panel should either summarize progress or link to a useful next action.
Internationalization
Add translations for new UI text in:
config/locales/en.yml
config/locales/pt-BR.yml
The initial display labels can use RPG language while staying understandable:
PlayerWorld MapActive QuestsTrainingFinance VaultGoal TempleAchievement HallNext Reward
Testing Plan
Add Minitest coverage:
- Authenticated users can access
/gamer - Unauthenticated users are redirected
- The route maps to
gamer_dashboard#show - Snapshot builds with a user that has no optional records
- Snapshot only returns records owned by the current user
- Character tier selection changes at level boundaries
- Key panels render without raising errors
Run targeted tests first, then the local CI pipeline before completion:
bin/rails test test/controllers/gamer_dashboard_controller_test.rb
bin/rails test test/models/gamer_dashboard/snapshot_test.rb
bin/ci
Implementation Phases
Phase 1: Data and Routing
- Add route, controller, policy, and snapshot model.
- Add tests for access and snapshot behavior.
- Keep the page visually minimal until the data contract is stable.
Phase 2: Main Gamer Layout
- Build the
/gamerpage structure. - Add player panel, world map, and primary panels.
- Use existing helper methods for formatting money and dates.
Phase 3: Pixel Characters
- Add level-tier character selection.
- Generate or create tier sprites.
- Render the current tier in the player panel and world map.
Phase 4: Polish and Responsiveness
- Tune dark theme, spacing, and panel density.
- Verify desktop and mobile layouts.
- Ensure text does not overflow in compact panels.
Phase 5: Verification (shipped)
- Targeted tests run and passing.
- Manual inspection in the browser at
http://localhost:3004/gamer.
Phase 6: Hover-Driven Map Zones & Layout Restructure (this update)
This is the work covered by this revision of the plan. It is purely a layout and interaction update on top of the shipped foundation — the controller, policy, route, and snapshot stay; the snapshot grows.
6a — Snapshot extensions. Add weekly_activity, weekly_xp_earned, weekly_xp_by_day, top_difficulty_achievements(limit:), and per-zone preview readers (zone_preview(:tasks), zone_preview(:habits), … one per zone) to GamerDashboard::Snapshot. Each preview reader returns at most 4 items, each pre-shaped for its partial.
6b — World map rebuild. Replace the inline 8-link block in _world_map.html.erb with render "zone", zone: ..., snapshot: @snapshot. The new _zone.html.erb partial renders the zone link and its hover card (the corresponding _zone_preview/*.html.erb) inside the same wrapper so CSS :hover/:focus-within keeps the card open while the cursor is on either.
6c — Center column reduction. Remove _quest_feed, _tasks_panel, _goals_panel, _sports_panel partials and their references in show.html.erb. The center column now contains only the world map.
6d — Left column additions. Add _weekly_activity.html.erb and _achievements_row.html.erb after the Habits panel in the left column.
6e — Stimulus tap behavior. Add gamer_map_zone_controller.js so touch devices can tap-to-open and tap-elsewhere/Escape-to-close. CSS stays the source of truth for hover.
6f — Verification. Update render assertions in gamer_dashboard_controller_test.rb to expect the new partials and not the removed ones. Update snapshot_test.rb with coverage for the new readers.
Open Decisions
The current recommendation is to generate PNG sprites for the character tiers. No user-provided artwork is required. (Done — sprites generated, normalized to square, in repo.)
The initial world map should be built with HTML/CSS plus sprite assets. A fully generated pixel-art map background can be added later if the first version needs more visual richness. (Done — generated map shipped at source aspect ratio.)
For the hover card behavior, we explicitly choose CSS-first with a Stimulus enhancer for touch — no popover library, no JS-driven positioning. Edge clamping is handled with Tailwind's min-w-0 on the column and right-0/left-0 overrides per zone.