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:

  • /gamer route is mounted inside authenticated :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.png rendered 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):

  1. 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.
  2. 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.
  3. 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_name or 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.amount where created_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 UserAchievement records by their Achievement.rarity (legendary > epic > rare > uncommon > common), tie-breaking by requirement_value DESC then unlocked_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 :hover and :focus-within on the zone wrapper, with the card absolutely positioned and pointer-events: auto so it stays open while the cursor moves into it.
  • Touch / no-hover devices: a Stimulus controller (gamer-map-zone) listens for click and toggles an is-open class. A second tap (or a tap outside) navigates / closes.
  • Keyboard: :focus-within matches when the zone link is focused; Escape collapses 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::ProgressCalculator where 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:

  • Player
  • World Map
  • Active Quests
  • Training
  • Finance Vault
  • Goal Temple
  • Achievement Hall
  • Next 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 /gamer page 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.