Gymboy Gba Rpg Overhaul Spec
Gymboy Gba Rpg Overhaul Spec
Source: gymboy-gba-rpg-overhaul-spec.md (ingested 2026-03-28)
GymBoy Repo — Complete Overhaul Spec
Cursor Agent Instructions: Full Rebuild in GBA RPG Visual Style
MISSION BRIEF
You are performing a complete visual and architectural overhaul of the gymboy.coach repository. The target aesthetic is Game Boy Advance (GBA) RPG style — think Golden Sun, Fire Emblem, Zelda: Minish Cap. Every UI decision, component, animation, and color choice must serve this aesthetic while delivering a fully functional fitness coaching web application.
Do not patch. Do not tweak. Rebuild.
PHASE 1: ESTABLISH THE TECHNICAL FOUNDATION
1.1 — Canvas & Resolution System
Every UI element must respect the GBA pixel grid. Implement a global pixel-perfect rendering system.
- Base design unit: 8px grid (all spacing, sizing, and layout must snap to multiples of 8)
- Treat the viewport as a GBA screen scaled up — use integer scaling only (2x, 3x, 4x, 6x)
- Set the following CSS root variables immediately:
:root {
--pixel-unit: 8px;
--grid-2: 16px;
--grid-4: 32px;
--grid-8: 64px;
--screen-width: 240px; /* GBA native width reference */
--screen-height: 160px; /* GBA native height reference */
--scale-factor: 4; /* Scale everything up by 4x */
--render-width: 960px; /* 240 * 4 */
--render-height: 640px; /* 160 * 4 */
}
- Apply
image-rendering: pixelatedandimage-rendering: crisp-edgesglobally — never allow bilinear smoothing anywhere in the app - All borders must be pixel-aligned — no sub-pixel rendering, no fractional values
1.2 — Font System
Remove all existing fonts. Install and configure the following:
- Primary UI Font:
Press Start 2P(Google Fonts) — used for all headings, stat labels, button text - Body/Narrative Font:
SilkscreenorVT323— used for descriptions, tooltips, long-form text - No system fonts anywhere in the UI
:root {
--font-ui: 'Press Start 2P', monospace;
--font-body: 'VT323', monospace;
--font-size-xs: 8px;
--font-size-sm: 12px;
--font-size-md: 16px;
--font-size-lg: 24px;
--font-size-xl: 32px;
--line-height-pixel: 1.5; /* Must be a whole pixel value at all sizes */
}
1.3 — Image Rendering Global Rules
Add this to your global stylesheet and do not override it anywhere:
*, *::before, *::after {
image-rendering: pixelated;
image-rendering: -moz-crisp-edges;
image-rendering: crisp-edges;
}
img, canvas, svg {
image-rendering: pixelated;
}
PHASE 2: COLOR SYSTEM — THE GBA PALETTE
2.1 — Master Palette
The GBA used 15-bit RGB giving 32,768 possible colors, but artists constrained themselves to ~16 colors per sprite/scene. Do the same. Every color in the app must come from this defined palette. No exceptions.
:root {
/* === BACKGROUNDS === */
--color-bg-deep: #0D0D1A; /* Deep space black — main app background */
--color-bg-dark: #1A1A2E; /* Dark navy — panels, cards */
--color-bg-mid: #16213E; /* Mid navy — secondary panels */
--color-bg-surface: #0F3460; /* Surface blue — elevated elements */
/* === PRIMARY ACTION — GBA GOLD (Golden Sun inspired) === */
--color-gold-bright: #FFD700; /* Bright gold — primary CTA, XP bars */
--color-gold-mid: #FFA500; /* Mid gold — hover states */
--color-gold-dark: #8B6914; /* Dark gold — pressed states, shadows */
--color-gold-glow: #FFD70044; /* Gold with alpha — bloom/glow effect */
/* === HEALTH & VITALITY — RED/GREEN === */
--color-hp-green: #00FF7F; /* HP bar fill — bright spring green */
--color-hp-dark: #005C2E; /* HP bar background */
--color-danger-red: #FF3333; /* Low HP, warnings, rest days */
--color-danger-dark: #8B0000; /* Danger background */
/* === MAGIC / SPECIAL — PURPLE/BLUE (Fire Emblem inspired) === */
--color-magic-bright: #9B59B6; /* Special moves, PRs, achievements */
--color-magic-light: #DDA0DD; /* Magic highlight */
--color-magic-glow: #9B59B644; /* Magic bloom */
/* === UI CHROME === */
--color-outline: #1A1A3E; /* NOT pure black — dark navy for outlines */
--color-outline-light: #2D2D5E; /* Lighter outline for inner elements */
--color-text-primary: #F0F0FF; /* Near-white with slight blue tint */
--color-text-secondary: #A0A0C0; /* Muted text */
--color-text-disabled: #404060; /* Disabled/locked content */
/* === STAT COLORS (RPG Stat Screen inspired) === */
--color-stat-str: #FF6B35; /* Strength — orange/red */
--color-stat-end: #4ECDC4; /* Endurance — teal */
--color-stat-agi: #45B7D1; /* Agility — light blue */
--color-stat-rec: #96CEB4; /* Recovery — sage green */
--color-stat-wil: #FFEAA7; /* Willpower — warm yellow */
}
2.2 — The Outline Rule (Critical)
Never use pure #000000 for outlines. Use --color-outline (#1A1A3E) as your darkest value. This is what separates amateur pixel art from professional GBA-era work. The outline should feel like a very dark version of the dominant local color.
For components that use gold as their primary color, use --color-gold-dark as the outline. For purple elements, use a dark purple. This must be implemented systematically via component-level CSS variables.
PHASE 3: COMPONENT LIBRARY — BUILD FROM SCRATCH
Delete all existing UI components. Rebuild every single one in GBA RPG style.
3.1 — The Pixel Border System
Every panel, card, and dialog in a GBA game uses a specific 9-slice border pattern. Implement this as a reusable CSS utility:
.pixel-border {
border: 4px solid var(--color-outline);
box-shadow:
/* Inner highlight (top-left) */
inset 2px 2px 0px var(--color-outline-light),
/* Inner shadow (bottom-right) */
inset -2px -2px 0px var(--color-bg-deep),
/* Outer glow */
0 0 0 2px var(--color-gold-glow);
image-rendering: pixelated;
}
.pixel-border--gold {
border-color: var(--color-gold-mid);
box-shadow:
inset 2px 2px 0px var(--color-gold-bright),
inset -2px -2px 0px var(--color-gold-dark),
0 0 8px var(--color-gold-glow),
0 0 16px var(--color-gold-glow);
}
.pixel-border--magic {
border-color: var(--color-magic-bright);
box-shadow:
inset 2px 2px 0px var(--color-magic-light),
inset -2px -2px 0px #4A235A,
0 0 8px var(--color-magic-glow),
0 0 20px var(--color-magic-glow);
}
3.2 — Stat Bars (HP/XP/Progress Bars)
Replace every progress bar, streak counter, and completion indicator with GBA-style stat bars.
.stat-bar-container {
display: flex;
align-items: center;
gap: var(--grid-2);
height: var(--grid-2); /* 16px — exactly 2 tiles tall */
}
.stat-bar-label {
font-family: var(--font-ui);
font-size: var(--font-size-xs);
color: var(--color-text-primary);
min-width: 32px;
text-align: right;
letter-spacing: 0;
}
.stat-bar-track {
flex: 1;
height: 12px;
background: var(--color-bg-deep);
border: 2px solid var(--color-outline);
position: relative;
overflow: visible;
}
.stat-bar-fill {
height: 100%;
position: relative;
transition: width 0.4s steps(20, end); /* Stepped animation — feels digital */
}
.stat-bar-fill::after {
content: '';
position: absolute;
top: 0;
right: 0;
width: 2px;
height: 100%;
background: rgba(255, 255, 255, 0.8); /* Leading edge highlight */
}
/* HP variant — Green */
.stat-bar--hp .stat-bar-fill { background: var(--color-hp-green); }
.stat-bar--hp .stat-bar-track { border-color: var(--color-hp-dark); }
/* XP variant — Gold */
.stat-bar--xp .stat-bar-fill { background: var(--color-gold-bright); }
.stat-bar--xp .stat-bar-track { border-color: var(--color-gold-dark); }
/* Danger variant — Red (below 25%) */
.stat-bar--danger .stat-bar-fill {
background: var(--color-danger-red);
animation: hp-critical 0.5s steps(2, end) infinite;
}
@keyframes hp-critical {
0% { opacity: 1; }
50% { opacity: 0.4; }
100% { opacity: 1; }
}
Apply this system to:
- Daily workout completion percentage → HP bar
- Weekly XP progress → XP bar
- Streak counter → converted to a multi-segment bar (one pip per day)
- Personal Record proximity → Magic bar (purple)
3.3 — Buttons
Every interactive button must look and behave like a GBA menu option.
.btn-pixel {
font-family: var(--font-ui);
font-size: var(--font-size-xs);
color: var(--color-text-primary);
background: var(--color-bg-surface);
border: none;
outline: none;
cursor: pointer;
padding: var(--pixel-unit) var(--grid-2);
position: relative;
letter-spacing: 1px;
text-transform: uppercase;
/* The "raised tile" look */
box-shadow:
-2px -2px 0px var(--color-outline-light),
2px 2px 0px var(--color-bg-deep),
0px 4px 0px var(--color-bg-deep); /* Bottom shadow = depth */
transition: none; /* No smooth transitions — this is pixel art */
}
.btn-pixel:hover {
background: var(--color-bg-mid);
color: var(--color-gold-bright);
box-shadow:
-2px -2px 0px var(--color-outline-light),
2px 2px 0px var(--color-bg-deep),
0px 4px 0px var(--color-bg-deep),
0 0 12px var(--color-gold-glow);
}
.btn-pixel:active {
/* Button "presses in" — remove bottom shadow, shift down 4px */
transform: translateY(4px);
box-shadow:
-2px -2px 0px var(--color-outline-light),
2px 2px 0px var(--color-bg-deep);
}
/* Primary CTA — Gold outlined */
.btn-pixel--primary {
background: var(--color-gold-dark);
color: var(--color-gold-bright);
border: 2px solid var(--color-gold-mid);
}
/* Danger — Red (skip workout, rest day) */
.btn-pixel--danger {
background: var(--color-danger-dark);
color: var(--color-danger-red);
border: 2px solid var(--color-danger-red);
}
/* The blinking cursor indicator (GBA menu standard) */
.btn-pixel--selected::before {
content: '▶';
position: absolute;
left: -16px;
color: var(--color-gold-bright);
animation: cursor-blink 0.7s steps(1, end) infinite;
}
@keyframes cursor-blink {
0%, 100% { opacity: 1; }
50% { opacity: 0; }
}
3.4 — Dialog / Menu Windows
All modals, tooltips, and information panels become GBA dialog boxes.
.dialog-box {
background: var(--color-bg-dark);
padding: var(--grid-2);
position: relative;
min-width: 200px;
/* The classic GBA dialog border — double border effect */
border: 4px solid var(--color-outline-light);
outline: 2px solid var(--color-bg-deep);
outline-offset: 2px;
/* Corner "notch" effect using clip-path */
clip-path: polygon(
0% 8px,
8px 0%,
calc(100% - 8px) 0%,
100% 8px,
100% calc(100% - 8px),
calc(100% - 8px) 100%,
8px 100%,
0% calc(100% - 8px)
);
}
.dialog-box__title {
font-family: var(--font-ui);
font-size: var(--font-size-xs);
color: var(--color-gold-bright);
border-bottom: 2px solid var(--color-outline-light);
padding-bottom: var(--pixel-unit);
margin-bottom: var(--pixel-unit);
letter-spacing: 2px;
}
.dialog-box__body {
font-family: var(--font-body);
font-size: var(--font-size-md);
color: var(--color-text-primary);
line-height: 1.6;
}
/* Text reveal animation — typewriter effect, stepped */
.dialog-box__body--animate {
overflow: hidden;
white-space: nowrap;
animation: typewriter 2s steps(40, end);
}
@keyframes typewriter {
from { width: 0; }
to { width: 100%; }
}
3.5 — Character / Avatar Sprite Frame
The user profile and any "coach" character must be displayed in a sprite frame — a bordered box that looks like a GBA character select screen.
.sprite-frame {
width: var(--grid-8); /* 64px — 8 tiles wide */
height: var(--grid-8);
background: var(--color-bg-deep);
border: 4px solid var(--color-outline-light);
display: grid;
place-items: center;
position: relative;
overflow: hidden;
}
.sprite-frame::before {
/* Scanline overlay for authentic handheld feel */
content: '';
position: absolute;
inset: 0;
background: repeating-linear-gradient(
0deg,
transparent,
transparent 1px,
rgba(0, 0, 0, 0.15) 1px,
rgba(0, 0, 0, 0.15) 2px
);
pointer-events: none;
z-index: 1;
}
.sprite-frame img {
image-rendering: pixelated;
width: 100%;
height: 100%;
object-fit: contain;
}
/* Idle breathing animation */
.sprite-frame--idle img {
animation: idle-breathe 2s steps(2, end) infinite;
}
@keyframes idle-breathe {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-2px); } /* 2px = 1 pixel at 2x scale */
}
PHASE 4: PAGE-BY-PAGE REBUILD
4.1 — Dashboard / Home Screen → "WORLD MAP" Screen
Redesign the dashboard as a GBA World Map interface.
Layout:
- Full-screen tiled background using a repeating pixel art grass/dungeon texture (SVG pattern acceptable)
- Floating location nodes representing: Today's Workout, Weekly Quest, Achievement Vault, Stats Screen
- Each node is a pulsing pixel icon with a label beneath it
- Player's avatar sprite walks between nodes (CSS animation, no JS required for basic version)
- Top HUD bar showing:
[HP BAR] [XP BAR] [STREAK: 🔥 X DAYS] [LEVEL: XX]
HUD Bar (top of every screen):
.hud-bar {
width: 100%;
height: 32px; /* 4 tiles tall */
background: var(--color-bg-deep);
border-bottom: 4px solid var(--color-outline-light);
display: flex;
align-items: center;
gap: var(--grid-2);
padding: 0 var(--grid-2);
font-family: var(--font-ui);
font-size: var(--font-size-xs);
color: var(--color-text-primary);
}
4.2 — Workout Logging Screen → "BATTLE" Screen
The workout entry UI becomes a turn-based battle interface.
Layout:
- Top half: The exercise being performed shown as a large "enemy encounter" name plate (the muscle group is the "boss")
- Bottom half: Command menu with 4 options in a 2x2 grid:
▶ LOG SET(primary action)▶ SWAP EXERCISE(secondary action)▶ ADD NOTE(utility)▶ FINISH WORKOUT(end battle)
- Each completed set adds to a "Damage Dealt" counter — visual feedback like
+45 XP!floating up in gold text - Rest timer displayed as a depleting MP bar (blue)
Floating XP Text:
.xp-popup {
font-family: var(--font-ui);
font-size: var(--font-size-sm);
color: var(--color-gold-bright);
position: absolute;
pointer-events: none;
animation: xp-float 1.5s steps(20, end) forwards;
text-shadow: 2px 2px 0px var(--color-gold-dark);
}
@keyframes xp-float {
0% { transform: translateY(0px); opacity: 1; }
70% { transform: translateY(-32px); opacity: 1; }
100% { transform: translateY(-48px); opacity: 0; }
}
4.3 — User Profile / Stats → "CHARACTER SCREEN"
Replace the profile page with a full RPG Character Sheet.
Layout (split into sections):
LEFT COLUMN — Character sprite (large, with idle animation) + Name + Class + Level
CENTER COLUMN — Stat grid:
STR ████████░░ 72
END ██████████ 98
AGI ████░░░░░░ 41
REC ███████░░░ 68
WIL █████████░ 85
RIGHT COLUMN — Equipment slots styled as GBA item boxes:
[PROGRAM]— Current workout program name[GOAL]— Primary fitness goal[STREAK]— Current streak (shown as a rune/badge)[COACH]— GymBoy coach avatar assigned
Each stat must have its own color pulled from --color-stat-* variables defined in Phase 2.
4.4 — Exercise Library → "SKILL TREE / ITEM SHOP"
The exercise browser becomes a Skill Tree or Item Shop screen.
Layout:
- Left panel: Category filter as a scrollable menu list (GBA-style vertical menu with blinking cursor)
- Right panel: Exercise cards displayed as Item Cards with:
- Exercise icon (pixel art — 16x16 sprite)
- Exercise name in
--font-ui - Muscle groups as colored element badges (like elemental affinities in Golden Sun)
- Difficulty as a star rating using pixel star sprites
- "EQUIP" button to add to today's workout
4.5 — Achievements → "TROPHY ROOM / BESTIARY"
Replace the achievements UI with a GBA Trophy Room.
- Locked achievements shown as silhouettes with
???text (exactly like locked Pokédex entries) - Unlocked achievements have a gold glow and a completion date
- Each achievement has a rarity tier with color coding:
- Common:
--color-text-secondary(gray) - Rare:
--color-stat-agi(blue) - Epic:
--color-magic-bright(purple) - Legendary:
--color-gold-bright(gold) + bloom glow effect
- Common:
PHASE 5: ANIMATION SYSTEM
5.1 — The Rules
GBA animations follow specific principles. Enforce all of them:
- No CSS
easeorease-in-out— usesteps()timing function for all UI animations - No smooth fades — use
steps(1, end)for instant cuts orsteps(8, end)for short fades - Squash & Stretch — buttons scale to
scaleY(0.85)on press, return to1on release - Idle animations are mandatory — any character sprite must have a breathing/idle cycle
- Screen transitions use a horizontal wipe (
clip-pathexpanding from left to right in steps)
5.2 — Screen Transition
.page-transition-enter {
animation: screen-wipe-in 0.3s steps(6, end) forwards;
}
.page-transition-exit {
animation: screen-wipe-out 0.3s steps(6, end) forwards;
}
@keyframes screen-wipe-in {
0% { clip-path: inset(0 100% 0 0); }
100% { clip-path: inset(0 0% 0 0); }
}
@keyframes screen-wipe-out {
0% { clip-path: inset(0 0% 0 0); }
100% { clip-path: inset(0 0 0 100%); }
}
5.3 — Level Up Sequence
When a user gains a level, trigger a full-screen level-up sequence:
- Screen flashes white (2 frames,
steps(2, end)) LEVEL UP!text drops from top in gold, with pixel shadow- Stats that increased animate their bars filling up one by one
- Fanfare sound (if audio is enabled)
- Screen wipes back to dashboard
.level-up-overlay {
position: fixed;
inset: 0;
background: var(--color-bg-deep);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 9999;
animation: level-up-enter 0.1s steps(2, end);
}
.level-up-text {
font-family: var(--font-ui);
font-size: var(--font-size-xl);
color: var(--color-gold-bright);
text-shadow:
4px 4px 0px var(--color-gold-dark),
0 0 20px var(--color-gold-glow),
0 0 40px var(--color-gold-glow);
animation: level-up-bounce 0.4s steps(4, end);
}
@keyframes level-up-bounce {
0% { transform: translateY(-64px) scaleY(1.5); }
50% { transform: translateY(8px) scaleY(0.8); }
75% { transform: translateY(-4px) scaleY(1.1); }
100% { transform: translateY(0px) scaleY(1.0); }
}
PHASE 6: GAMIFICATION LAYER — SYSTEM DESIGN
These are the RPG mechanics that must be wired into the existing GymBoy data layer.
6.1 — XP & Leveling Formula
XP per set = weight_kg * reps * 0.1
XP per workout = sum(set_xp) + (100 * consistency_multiplier)
consistency_multiplier = 1.0 + (current_streak * 0.05) /* Max 2.0 at 20-day streak */
Level threshold = 100 * (level ^ 1.5) /* Level 1→2: 100xp, Level 10→11: 3162xp */
6.2 — Stat System (Map to Real Fitness Metrics)
| RPG Stat | Real Metric | How It Increases | |:---------|:------------|:-----------------| | STR (Strength) | Max weight lifted | PRs in compound lifts | | END (Endurance) | Workout duration consistency | Completing full sessions | | AGI (Agility) | Workout frequency | Days per week worked out | | REC (Recovery) | Rest day compliance | Logging rest days properly | | WIL (Willpower) | Streak consistency | Unbroken streaks |
6.3 — Class System
Assign the user a Class based on their dominant training style. Update dynamically.
| Class | Unlock Condition | |:------|:----------------| | Warrior | Strength-focused (>60% compound lifts) | | Ranger | Cardio-focused (>3 cardio sessions/week) | | Monk | Balanced (no single category >50%) | | Berserker | High volume (>20 sets/session average) | | Paladin | Perfect recovery compliance (>90% rest days logged) |
PHASE 7: AUDIO (OPTIONAL BUT RECOMMENDED)
If audio is in scope, implement a chiptune sound system.
- Use the Web Audio API to generate sounds procedurally (no audio files needed for basic SFX)
- Menu navigation: Short 8-bit blip (
220Hz, square wave, 50ms) - Button confirm: Ascending two-note chirp
- XP gain: Coin pickup sound (classic sine wave sweep up)
- Level up: 4-note ascending fanfare
- Achievement unlock: 8-bit fanfare sting
All audio must be opt-in with a [🔊 SFX: ON/OFF] toggle in the HUD bar, styled as a pixel toggle switch.
PHASE 8: IMPLEMENTATION ORDER
Execute in this exact sequence to avoid dependency conflicts:
- CSS Custom Properties — Establish all variables from Phase 2 in a single
tokens.cssfile - Global Resets — Apply
image-rendering, font loading, box model resets - Typography — Install and verify all pixel fonts render correctly at all defined sizes
- Base Components —
pixel-border,stat-bar,dialog-box,btn-pixel - Layout Shells — HUD bar, page containers, World Map layout
- Screen Rebuilds — Dashboard → Workout → Profile → Library → Achievements (in this order)
- Animation Layer — Apply all
@keyframesand transition rules after static layout is confirmed correct - Gamification Wiring — Connect XP/Level/Stat calculations to real data
- Audio Layer — Add last, after all visual systems are confirmed stable
- QA Pass — Check every pixel for blurring, every color for palette compliance, every animation for
steps()usage
HARD RULES — DO NOT VIOLATE
- No
border-radius— GBA art uses sharp, squared corners everywhere. No rounded corners. No pills. No circles. - No
easetransitions — Onlysteps()orlinear(and linear only for scroll/position, never color or opacity) - No pure
#000000— Use--color-outlineor--color-bg-deepas your darkest values - No Google Material, Tailwind defaults, or Bootstrap components — Every component is custom
- No Bilinear scaling —
image-rendering: pixelatedmust be present on every<img>and<canvas> - No fractional pixel values — All sizing must be integers divisible by 2 or 4
- No sans-serif or serif body fonts — Only pixel fonts as specified
DELIVERABLES CHECKLIST
When the overhaul is complete, the following must all be true:
- [ ] Every color in the app exists in the master palette defined in Phase 2
- [ ] Every animation uses
steps()timing - [ ] Every border uses
--color-outlineor a local dark color — never pure black - [ ] Every image renders with
image-rendering: pixelated - [ ] All fonts are pixel fonts (
Press Start 2P,VT323, orSilkscreen) - [ ] Dashboard reads as a World Map screen
- [ ] Workout logger reads as a Battle screen
- [ ] Profile reads as a Character Sheet
- [ ] Exercise library reads as an Item Shop / Skill Tree
- [ ] Achievements read as a Trophy Room with locked silhouettes
- [ ] XP, Level, and all 5 Stats are calculated from real workout data
- [ ] Level-up sequence triggers correctly on threshold crossing
- [ ] All spacing values are multiples of 8px
- [ ] No
border-radiusexists anywhere in the codebase - [ ] Screen transitions use the horizontal pixel wipe