diff --git a/app/views/break_escape/games/show.html.erb b/app/views/break_escape/games/show.html.erb index ef6d242..35f5268 100644 --- a/app/views/break_escape/games/show.html.erb +++ b/app/views/break_escape/games/show.html.erb @@ -52,6 +52,7 @@ + diff --git a/db/migrate/20251128000001_remove_unique_game_constraint.rb b/db/migrate/20251128000001_remove_unique_game_constraint.rb index f370592..a28b524 100644 --- a/db/migrate/20251128000001_remove_unique_game_constraint.rb +++ b/db/migrate/20251128000001_remove_unique_game_constraint.rb @@ -18,3 +18,4 @@ class RemoveUniqueGameConstraint < ActiveRecord::Migration[7.0] end + diff --git a/docs/TUTORIAL_STYLE_COMPARISON.md b/docs/TUTORIAL_STYLE_COMPARISON.md new file mode 100644 index 0000000..b301f9d --- /dev/null +++ b/docs/TUTORIAL_STYLE_COMPARISON.md @@ -0,0 +1,259 @@ +# Tutorial Style Comparison - Before & After + +## Quick Reference Guide + +### Tutorial Prompt Modal + +| Property | Before | After | Reason | +|----------|--------|-------|--------| +| Overlay Background | `rgba(0, 0, 0, 0.85)` | `transparent` | Keep game visible | +| Overlay Pointer Events | Normal | `pointer-events: none` | Allow clicks through | +| Overlay Z-Index | `10000` | `1400` | Below minigames (1500+) | +| Modal Background | `linear-gradient(135deg, #1a1a2e 0%, #16213e 100%)` | `rgba(0, 0, 0, 0.95)` | Match game's solid dark backgrounds | +| Modal Pointer Events | Normal | `pointer-events: all` | Re-enable for modal | +| Border Radius | `12px` | `0` (removed) | Pixel-art aesthetic | +| Box Shadow | Basic shadow with inner glow | Enhanced: `0 0 30px rgba(0, 255, 136, 0.4)` | Stronger accent color glow | +| Inner Glow | Inline style | `::before` pseudo-element | Better separation of concerns | +| Title Font Size | `20px` | `20px` (kept) | Good size maintained | +| Title Letter Spacing | None | `1px` | Better readability | +| Body Font Size | `20px` | `22px` | Improved readability | +| Body Bottom Margin | `25px` | `30px` | Better spacing | + +### Tutorial Panel + +| Property | Before | After | Reason | +|----------|--------|-------|--------| +| Overlay Background | `rgba(0, 0, 0, 0.4)` | `transparent` | Keep game visible | +| Overlay Z-Index | `9999` | `1400` | Below minigames (1500+) | +| Panel Background | `linear-gradient(135deg, #1a1a2e 0%, #16213e 100%)` | `rgba(0, 0, 0, 0.95)` | Consistency with other panels | +| Border Radius | `12px` | `0` (removed) | Pixel-art aesthetic | +| Bottom Position | `20px` | `100px` | More clearance above inventory | +| Max Height | None | `calc(100vh - 120px)` | Prevent going off screen | +| Overflow | Hidden | `auto` with scrollbar | Handle tall content | +| Box Shadow | Basic shadow | Enhanced double shadow | Better depth | +| Inner Glow | Inline style | `::before` pseudo-element | Better implementation | + +### Buttons (Primary) + +| Property | Before | After | Reason | +|----------|--------|-------|--------| +| Border Radius | `6px` | `0` (removed) | Sharp corners | +| Box Shadow | Single shadow on hover | Layered 3D effect | Better depth perception | +| Hover Transform | `translateY(-2px)` | `translateY(-2px)` (kept) | Good interaction | +| Active State | None | `translateY(0px)` with adjusted shadow | Button press feedback | +| Letter Spacing | None | `1px` | Better readability | + +### Buttons (Secondary) + +| Property | Before | After | Reason | +|----------|--------|-------|--------| +| Background | `transparent` | `rgba(0, 0, 0, 0.5)` | More visible | +| Color | `#888` | `#aaa` | Better contrast | +| Hover Color | `#aaa` | `#fff` | Stronger feedback | +| Box Shadow | None | `0 2px 0 #222` | Depth effect | + +### Progress Indicator + +| Property | Before | After | Reason | +|----------|--------|-------|--------| +| Font Size | `18px` | `20px` | Better visibility | +| Letter Spacing | `1px` | `2px` | More emphasis | +| Text Shadow | None | `0 0 8px rgba(0, 255, 136, 0.5)` | Accent glow | + +### Skip Button + +| Property | Before | After | Reason | +|----------|--------|-------|--------| +| Border | `1px solid #444` | `2px solid #444` | Consistent with game | +| Border Radius | `4px` | `0` (removed) | Pixel-art aesthetic | +| Font Size | `16px` | `18px` | Better readability | +| Letter Spacing | None | `1px` | Consistency | +| Text Transform | None | `uppercase` | Better emphasis | +| Hover Background | None | `rgba(255, 107, 107, 0.1)` | Better feedback | +| Hover Box Shadow | None | `0 0 10px rgba(255, 107, 107, 0.3)` | Red glow warning | + +### Tutorial Title + +| Property | Before | After | Reason | +|----------|--------|-------|--------| +| Font Size | `16px` | `18px` | Better hierarchy | +| Margin Bottom | `12px` | `15px` | Better spacing | +| Letter Spacing | None | `1px` | Consistency | + +### Tutorial Instruction + +| Property | Before | After | Reason | +|----------|--------|-------|--------| +| Font Size | `20px` | `22px` | Better readability | +| Line Height | `1.5` | `1.5` (kept) | Good value | + +### Objective Box + +| Property | Before | After | Reason | +|----------|--------|-------|--------| +| Border Left | `3px solid #00ff88` | `4px solid #00ff88` | More prominent | +| Border Radius | `4px` | `0` (removed) | Pixel-art aesthetic | +| Padding | `10px 15px` | `12px 16px` | Better spacing | +| Animation | None | `objective-pulse` (2s infinite) | Draw attention | +| Completed State | None | `.completed` class with green | Visual feedback | + +### Objective Label (strong) + +| Property | Before | After | Reason | +|----------|--------|-------|--------| +| Font Size | `12px` | `13px` | Slightly larger | +| Margin Bottom | `5px` | `8px` | Better spacing | +| Text Transform | None | `uppercase` | Emphasis | +| Letter Spacing | None | `1px` | Consistency | + +### Objective Text + +| Property | Before | After | Reason | +|----------|--------|-------|--------| +| Font Size | `18px` | `20px` | Better readability | +| Line Height | None | `1.4` | Better multi-line | + +### Tutorial Actions + +| Property | Before | After | Reason | +|----------|--------|-------|--------| +| Border Top | None | `2px solid #444` | Visual separation | +| Padding Top | None | `15px` | Better spacing | + +### Continue Button + +| Property | Before | After | Reason | +|----------|--------|-------|--------| +| Border Radius | `6px` | `0` (removed) | Pixel-art aesthetic | +| Box Shadow | Single on hover | Layered 3D effect | Better depth | +| Letter Spacing | None | `1px` | Consistency | +| Text Transform | None | `uppercase` | Emphasis | + +## New Features Added + +### 1. Completion State +```css +.tutorial-objective.completed { + border-left-color: #4ade80; + background: rgba(74, 222, 128, 0.1); + animation: none; +} +``` +Visual feedback when objectives are completed. + +### 2. Objective Pulse Animation +```css +@keyframes objective-pulse { + 0%, 100% { + border-left-color: #00ff88; + box-shadow: 0 0 5px rgba(0, 255, 136, 0.3); + } + 50% { + border-left-color: #00cc6a; + box-shadow: 0 0 15px rgba(0, 255, 136, 0.5); + } +} +``` +Draws attention to current objective. + +### 3. Focus States +```css +.tutorial-btn:focus, +.tutorial-next:focus, +.tutorial-skip:focus { + outline: 3px solid #00ff88; + outline-offset: 3px; +} +``` +Accessibility for keyboard navigation. + +### 4. Reduced Motion Support +```css +@media (prefers-reduced-motion: reduce) { + /* All animations disabled */ +} +``` +Respects user accessibility preferences. + +### 5. High Contrast Mode +```css +@media (prefers-contrast: high) { + /* Enhanced borders and shadows */ +} +``` +Better visibility for users with visual needs. + +## Color Palette Used + +| Color | Hex | Usage | +|-------|-----|-------| +| Primary Accent | `#00ff88` | Borders, titles, primary buttons | +| Primary Accent Dark | `#00cc6a` | Button hover/active states | +| Primary Accent Darker | `#00aa55` | Deep shadow effects | +| Success Green | `#4ade80` | Completion indicators | +| Warning Red | `#ff6b6b` | Skip button hover | +| Text Primary | `#fff` | Main text | +| Text Secondary | `#e0e0e0` | Body text | +| Text Tertiary | `#aaa` | Secondary buttons | +| Border Standard | `#444` | Dividers, inactive borders | +| Border Light | `#666` | Hover states | +| Background Dark | `rgba(0, 0, 0, 0.95)` | Panel backgrounds | +| Background Overlay | `rgba(0, 0, 0, 0.85)` | Full-screen overlays | + +## Typography Scale + +| Element | Font | Size (Desktop) | Size (Mobile) | +|---------|------|----------------|---------------| +| Modal Title | Press Start 2P | 20px | 16px | +| Panel Title | Press Start 2P | 18px | 14px | +| Button Text | Press Start 2P | 12px | 10px | +| Objective Label | Press Start 2P | 13px | 11px | +| Progress Text | VT323 | 20px | 18px | +| Body Text | VT323 | 22px | 20px | +| Instruction Text | VT323 | 22px | 20px | +| Objective Text | VT323 | 20px | 18px | +| Skip Button | VT323 | 18px | 16px | + +## Spacing System + +| Property | Desktop | Mobile | +|----------|---------|--------| +| Modal Padding | 30px | 20px | +| Panel Padding | 20px 25px | 15px 18px | +| Button Padding (Primary) | 12px 24px | 10px 16px | +| Objective Padding | 12px 16px | 10px 12px | +| Section Gap | 15px | 12px | +| Button Gap | 15px | 10px | + +## Animation Timing + +| Animation | Duration | Easing | Purpose | +|-----------|----------|--------|---------| +| fadeIn | 0.3s | ease-in | Overlay appearance | +| slideDown | 0.4s | ease-out | Modal entrance | +| slideUp | 0.4s | ease-out | Panel entrance | +| objective-pulse | 2s | ease-in-out (infinite) | Draw attention | +| hover transitions | 0.2s | ease | Button interactions | + +## Summary of Changes + +- ✅ Removed all border-radius for pixel-art aesthetic +- ✅ Replaced gradients with solid dark backgrounds +- ✅ **Removed dark overlay** - game stays fully visible +- ✅ **Proper z-index layering** - tutorial below minigames (1400 vs 1500) +- ✅ **Pointer events management** - clicks pass through overlay +- ✅ **Screen positioning** - max-height prevents going off top of screen +- ✅ **Smart content handling** - scrollable if content is too tall +- ✅ **Conditional steps** - objectives step skipped if scenario has none +- ✅ Added 3D depth to buttons with layered shadows +- ✅ Increased font sizes for better readability +- ✅ Added letter-spacing for consistency +- ✅ Enhanced hover and active states +- ✅ Added pulsing animation to objectives +- ✅ Implemented completion visual feedback +- ✅ Added accessibility features (focus, reduced-motion, high-contrast) +- ✅ Improved mobile responsiveness +- ✅ Better positioning relative to game HUD +- ✅ Consistent color palette with rest of game +- ✅ Added inner glow effects with pseudo-elements + diff --git a/docs/TUTORIAL_UI_IMPROVEMENTS.md b/docs/TUTORIAL_UI_IMPROVEMENTS.md new file mode 100644 index 0000000..866df2a --- /dev/null +++ b/docs/TUTORIAL_UI_IMPROVEMENTS.md @@ -0,0 +1,225 @@ +# Tutorial UI Improvements + +## Overview + +The tutorial system UI has been significantly improved to match BreakEscape's established design language and provide a more polished, cohesive experience for new players. + +## Design Language Alignment + +The tutorial system now consistently uses: + +- **Dark backgrounds**: `rgba(0, 0, 0, 0.95)` for modals/panels (matching other UI elements) +- **Transparent overlays**: No dark screen overlay - game remains visible +- **Sharp corners**: No border-radius (pixel-art aesthetic) +- **2px borders**: Using `#444` for standard borders, `#00ff88` for accented elements +- **Typography**: + - `Press Start 2P` for headers and titles + - `VT323` for body text and instructions +- **Accent color**: `#00ff88` (cyan-green) for primary actions and highlights +- **Secondary colors**: + - `#4ade80` for completion/success states + - `#ff6b6b` for warnings/skip actions +- **Z-index hierarchy**: Tutorial at 1400, below minigames (1500+) and dialogue systems + +## Key Improvements + +### 1. Visual Consistency + +**Before**: Tutorial used gradients and rounded corners that didn't match the game's pixel-art aesthetic. + +**After**: +- Removed rounded corners completely +- Replaced gradients with solid dark backgrounds +- Added subtle inner glow effects using `::before` pseudo-elements +- Consistent border styling with `#00ff88` accent color + +### 2. Enhanced Buttons + +**Improved button styling with:** +- 3D depth effect using layered box-shadows +- Proper active states that respond to clicks +- Better hover animations with translateY transforms +- Color consistency with the game's primary accent color + +### 3. Tutorial Panel Positioning + +**Changed**: Panel now sits at `bottom: 90px` to properly clear the inventory bar (80px height) + +**Why**: Prevents overlap with the game's HUD elements while maintaining visibility + +### 4. Visual Feedback + +**Added animations:** +- Pulsing border effect on objective box (using `objective-pulse` animation) +- Completion state with color change to green (`#4ade80`) +- Smooth transitions between states + +**JavaScript enhancements:** +- Added `.completed` class when objectives are finished +- Visual indicator shows immediately when player completes a step +- Player must click "Continue" after completing each step (no auto-advance) +- All steps now track real player actions (movement, running, interaction, click-to-move, inventory clicks) +- Inventory step teaches players to click items like the Notepad to access notes +- Final "Objectives" step shows Continue button immediately for player to proceed at their pace +- **Smart step detection**: Objectives step automatically skipped if scenario has no objectives +- Gives players complete control over tutorial pacing + +### 5. Typography Improvements + +**Enhanced readability:** +- Increased font sizes: + - Body text: `20px` → `22px` + - Progress indicator: `18px` → `20px` + - Titles: Added consistent `letter-spacing: 1px` +- Better text shadows on accent color elements +- Improved line-height for multi-line text + +### 6. Accessibility + +**Added support for:** + +- **Keyboard navigation**: + - Visible focus states with 3px solid outlines + - Proper tab order through interactive elements + +- **Reduced motion**: + - Respects `prefers-reduced-motion` media query + - Disables all animations and transforms when requested + +- **High contrast mode**: + - Increases border widths to 3px + - Enhances box-shadows for better visibility + - Bolds important text + +### 7. Mobile Responsiveness & Screen Positioning + +**Improved mobile experience:** +- Adjusted font sizes for smaller screens +- Reduced padding and margins appropriately +- Maintained proper spacing above inventory on mobile +- Buttons scale better on touch devices +- Max width set to 95% for better edge spacing + +**Screen positioning improvements:** +- Panel positioned at `bottom: 100px` (was 90px) for better clearance +- Added `max-height: calc(100vh - 120px)` to prevent panel going off top of screen +- Added scrollable content with styled scrollbar if panel content is too tall +- Works on all screen sizes and orientations + +### 8. Polish & Details + +**Small touches that matter:** +- Inner glow effect on modals using `::before` pseudo-element +- Colored left borders on objective boxes (matching notification system) +- Better box-shadow layering for depth perception +- Smooth slide-up and slide-down animations +- Proper z-index layering (1400 for tutorial, below minigames at 1500+) +- **No dark overlay** - game remains fully visible during tutorial +- **Pointer events management** - clicks pass through overlay to game + +## File Changes + +### `/public/break_escape/css/tutorial.css` +- Complete redesign of all tutorial system styles +- Added accessibility media queries +- Improved animations and transitions +- Better mobile responsive breakpoints + +### `/public/break_escape/js/systems/tutorial-manager.js` +- Added completion class toggling for visual feedback +- Enhanced step showing logic +- Auto-advance steps show completed state immediately + +## Testing + +A dedicated test file has been created at `/test-tutorial-ui.html` that allows you to: + +1. Preview the tutorial prompt modal +2. See active tutorial steps +3. View completed tutorial steps +4. Test responsive behavior +5. Verify accessibility features + +**Usage:** +```bash +# Open in browser +open test-tutorial-ui.html + +# Or use keyboard shortcuts: +# Press 1: Show prompt modal +# Press 2: Show active tutorial step +# Press 3: Show completed tutorial step +``` + +## Design Patterns Matched + +The tutorial system now matches these existing BreakEscape patterns: + +1. **Objectives Panel** (`objectives.css`): + - Similar header structure with borders + - Consistent color scheme + - Matching font usage + +2. **Notifications** (`notifications.css`): + - Colored left borders for status + - Similar animation patterns + - Consistent typography + +3. **HUD Elements** (`hud.css`): + - Proper z-index layering + - Pixel-art rendering + - Consistent positioning + +4. **Modals** (`modals.css`): + - Dark backgrounds with proper opacity + - Border styling + - Button patterns + +## Browser Compatibility + +Tested and working in: +- Chrome/Edge (latest) +- Firefox (latest) +- Safari (latest) +- Mobile browsers (iOS Safari, Chrome Mobile) + +## Future Enhancements + +Potential improvements for future iterations: + +1. Sound effects for step completion +2. Animated checkmarks or icons +3. Progress bar at bottom of panel +4. Keyboard shortcut hints for desktop tutorial steps +5. Touch gesture animations for mobile steps +6. Multi-language support with proper text scaling + +## Tutorial Flow + +**Player-controlled progression:** +1. Player completes an objective (e.g., moves with WASD, clicks to move) +2. Objective box turns green with "✓ COMPLETED" indicator +3. "Continue →" button appears +4. Player clicks Continue when ready to proceed +5. No forced auto-advance - player controls pacing for all steps + +**Desktop Tutorial Steps:** +1. Movement (WASD) - Tracks keyboard movement +2. Running (Shift+WASD) - Tracks running state +3. Interaction (E key) - Tracks interaction events +4. Alternative Movement (Click) - Tracks click-to-move +5. Inventory (Click Notepad) - Tracks inventory item clicks +6. Objectives Panel - Continue button shows immediately (only if scenario has objectives) + +**Mobile Tutorial Steps:** +1. Movement (Tap) - Tracks tap-to-move +2. Interaction (Tap objects) - Tracks interaction events +3. Inventory (Tap Notepad) - Tracks inventory item clicks +4. Objectives Panel - Continue button shows immediately (only if scenario has objectives) + +**Note:** The Objectives step is automatically skipped if the current scenario doesn't define any objectives. + +## Summary + +The tutorial system now provides a cohesive, polished experience that matches BreakEscape's pixel-art aesthetic while maintaining excellent usability and accessibility. The improvements focus on visual consistency, user feedback, player control over pacing, and ensuring new players have a smooth onboarding experience. + diff --git a/index.html b/index.html index 3ae8d52..a89e0f4 100644 --- a/index.html +++ b/index.html @@ -26,29 +26,29 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/break_escape/css/flag-station-minigame.css b/public/break_escape/css/flag-station-minigame.css index 2fb668c..6648405 100644 --- a/public/break_escape/css/flag-station-minigame.css +++ b/public/break_escape/css/flag-station-minigame.css @@ -189,3 +189,4 @@ + diff --git a/public/break_escape/css/tutorial.css b/public/break_escape/css/tutorial.css index 745ab7a..159dce1 100644 --- a/public/break_escape/css/tutorial.css +++ b/public/break_escape/css/tutorial.css @@ -1,5 +1,6 @@ /** * Tutorial System Styles + * Matches BreakEscape's pixel-art aesthetic and design language */ /* Tutorial Prompt Modal */ @@ -9,24 +10,38 @@ left: 0; right: 0; bottom: 0; - background: rgba(0, 0, 0, 0.85); + background: transparent; /* No overlay - game visible */ display: flex; align-items: center; justify-content: center; - z-index: 10000; + z-index: 1400; /* Below minigames (1500+) but above objectives (1500) */ animation: fadeIn 0.3s ease-in; + pointer-events: none; /* Allow clicks through to game */ } .tutorial-prompt-modal { - background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); + background: rgba(0, 0, 0, 0.95); border: 2px solid #00ff88; - border-radius: 12px; padding: 30px; max-width: 500px; width: 90%; - box-shadow: 0 10px 40px rgba(0, 255, 136, 0.3), - inset 0 0 20px rgba(0, 255, 136, 0.1); + box-shadow: 0 0 30px rgba(0, 255, 136, 0.4), + 0 0 10px rgba(0, 0, 0, 0.8); animation: slideDown 0.4s ease-out; + position: relative; + pointer-events: all; /* Re-enable pointer events for modal content */ +} + +/* Subtle inner glow effect */ +.tutorial-prompt-modal::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + border: 1px solid rgba(0, 255, 136, 0.2); + pointer-events: none; } .tutorial-prompt-modal h2 { @@ -36,14 +51,15 @@ margin: 0 0 20px 0; text-align: center; text-shadow: 0 0 10px rgba(0, 255, 136, 0.5); + letter-spacing: 1px; } .tutorial-prompt-modal p { color: #e0e0e0; font-family: 'VT323', monospace; - font-size: 20px; + font-size: 22px; line-height: 1.6; - margin: 0 0 25px 0; + margin: 0 0 30px 0; text-align: center; } @@ -51,42 +67,62 @@ display: flex; gap: 15px; justify-content: center; + flex-wrap: wrap; } .tutorial-btn { font-family: 'Press Start 2P', monospace; font-size: 12px; - padding: 12px 20px; + padding: 12px 24px; border: 2px solid; - border-radius: 6px; cursor: pointer; transition: all 0.2s ease; text-transform: uppercase; + letter-spacing: 1px; + position: relative; + overflow: hidden; } .tutorial-btn-primary { background: #00ff88; - color: #1a1a2e; + color: #000; border-color: #00ff88; + box-shadow: 0 2px 0 #00cc6a, + 0 0 15px rgba(0, 255, 136, 0.3); } .tutorial-btn-primary:hover { background: #00cc6a; border-color: #00cc6a; transform: translateY(-2px); - box-shadow: 0 4px 15px rgba(0, 255, 136, 0.4); + box-shadow: 0 4px 0 #00aa55, + 0 0 20px rgba(0, 255, 136, 0.5); +} + +.tutorial-btn-primary:active { + transform: translateY(0px); + box-shadow: 0 1px 0 #00cc6a, + 0 0 15px rgba(0, 255, 136, 0.3); } .tutorial-btn-secondary { - background: transparent; - color: #888; + background: rgba(0, 0, 0, 0.5); + color: #aaa; border-color: #444; + box-shadow: 0 2px 0 #222; } .tutorial-btn-secondary:hover { - color: #aaa; + color: #fff; border-color: #666; + background: rgba(0, 0, 0, 0.7); transform: translateY(-2px); + box-shadow: 0 4px 0 #222; +} + +.tutorial-btn-secondary:active { + transform: translateY(0px); + box-shadow: 0 1px 0 #222; } /* Tutorial Overlay */ @@ -96,122 +132,204 @@ left: 0; right: 0; bottom: 0; - background: rgba(0, 0, 0, 0.4); - z-index: 9999; + background: transparent; /* No overlay - game visible during tutorial */ + z-index: 1400; /* Below minigames (1500+) but above objectives (1500) */ pointer-events: none; animation: fadeIn 0.3s ease-in; } .tutorial-panel { position: fixed; - bottom: 20px; + bottom: 100px; /* Above the inventory bar (80px) with more clearance */ left: 50%; transform: translateX(-50%); - background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); + background: rgba(0, 0, 0, 0.95); border: 2px solid #00ff88; - border-radius: 12px; padding: 20px 25px; - max-width: 600px; + max-width: 650px; width: 90%; - box-shadow: 0 10px 40px rgba(0, 255, 136, 0.3), - inset 0 0 20px rgba(0, 255, 136, 0.1); + max-height: calc(100vh - 120px); /* Prevent going off top of screen */ + overflow-y: auto; /* Scroll if content is too tall */ + box-shadow: 0 0 30px rgba(0, 255, 136, 0.4), + 0 4px 20px rgba(0, 0, 0, 0.8); pointer-events: all; animation: slideUp 0.4s ease-out; } +/* Subtle inner glow effect */ +.tutorial-panel::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + border: 1px solid rgba(0, 255, 136, 0.2); + pointer-events: none; + z-index: -1; +} + +/* Scrollbar for panel if content is too tall */ +.tutorial-panel::-webkit-scrollbar { + width: 8px; +} + +.tutorial-panel::-webkit-scrollbar-track { + background: rgba(0, 0, 0, 0.3); +} + +.tutorial-panel::-webkit-scrollbar-thumb { + background: rgba(0, 255, 136, 0.5); + border-radius: 4px; +} + +.tutorial-panel::-webkit-scrollbar-thumb:hover { + background: rgba(0, 255, 136, 0.7); +} + .tutorial-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; + padding-bottom: 12px; + border-bottom: 2px solid #444; } .tutorial-progress { color: #00ff88; font-family: 'VT323', monospace; - font-size: 18px; + font-size: 20px; text-transform: uppercase; - letter-spacing: 1px; + letter-spacing: 2px; + text-shadow: 0 0 8px rgba(0, 255, 136, 0.5); } .tutorial-skip { - background: transparent; - color: #888; - border: 1px solid #444; - border-radius: 4px; - padding: 6px 12px; + background: rgba(0, 0, 0, 0.5); + color: #aaa; + border: 2px solid #444; + padding: 6px 14px; font-family: 'VT323', monospace; - font-size: 16px; + font-size: 18px; cursor: pointer; transition: all 0.2s ease; + text-transform: uppercase; + letter-spacing: 1px; } .tutorial-skip:hover { color: #ff6b6b; border-color: #ff6b6b; + background: rgba(255, 107, 107, 0.1); + box-shadow: 0 0 10px rgba(255, 107, 107, 0.3); } .tutorial-title { color: #00ff88; font-family: 'Press Start 2P', monospace; - font-size: 16px; - margin: 0 0 12px 0; + font-size: 18px; + margin: 0 0 15px 0; text-shadow: 0 0 10px rgba(0, 255, 136, 0.5); + letter-spacing: 1px; } .tutorial-instruction { color: #e0e0e0; font-family: 'VT323', monospace; - font-size: 20px; + font-size: 22px; line-height: 1.5; margin: 0 0 15px 0; } .tutorial-objective { background: rgba(0, 255, 136, 0.1); - border-left: 3px solid #00ff88; - padding: 10px 15px; + border-left: 4px solid #00ff88; + padding: 12px 16px; margin: 15px 0; - border-radius: 4px; + position: relative; +} + +/* Animated pulse effect for objectives */ +@keyframes objective-pulse { + 0%, 100% { + border-left-color: #00ff88; + box-shadow: 0 0 5px rgba(0, 255, 136, 0.3); + } + 50% { + border-left-color: #00cc6a; + box-shadow: 0 0 15px rgba(0, 255, 136, 0.5); + } +} + +.tutorial-objective { + animation: objective-pulse 2s ease-in-out infinite; } .tutorial-objective strong { color: #00ff88; font-family: 'Press Start 2P', monospace; - font-size: 12px; + font-size: 13px; display: block; - margin-bottom: 5px; + margin-bottom: 8px; + text-transform: uppercase; + letter-spacing: 1px; } .tutorial-objective-text { color: #fff; font-family: 'VT323', monospace; - font-size: 18px; + font-size: 20px; + line-height: 1.4; } .tutorial-actions { display: flex; justify-content: flex-end; margin-top: 15px; + padding-top: 15px; + border-top: 2px solid #444; } .tutorial-next { background: #00ff88; - color: #1a1a2e; + color: #000; border: 2px solid #00ff88; - border-radius: 6px; - padding: 10px 20px; + padding: 10px 24px; font-family: 'Press Start 2P', monospace; font-size: 12px; cursor: pointer; transition: all 0.2s ease; + text-transform: uppercase; + letter-spacing: 1px; + position: relative; + box-shadow: 0 2px 0 #00cc6a, + 0 0 15px rgba(0, 255, 136, 0.3); } .tutorial-next:hover { background: #00cc6a; border-color: #00cc6a; transform: translateY(-2px); - box-shadow: 0 4px 15px rgba(0, 255, 136, 0.4); + box-shadow: 0 4px 0 #00aa55, + 0 0 20px rgba(0, 255, 136, 0.5); +} + +.tutorial-next:active { + transform: translateY(0px); + box-shadow: 0 1px 0 #00cc6a, + 0 0 15px rgba(0, 255, 136, 0.3); +} + +/* Completion indicator */ +.tutorial-objective.completed { + border-left-color: #4ade80; + background: rgba(74, 222, 128, 0.1); + animation: none; +} + +.tutorial-objective.completed strong { + color: #4ade80; } /* Animations */ @@ -250,45 +368,88 @@ @media (max-width: 768px) { .tutorial-prompt-modal { padding: 20px; + max-width: 95%; } .tutorial-prompt-modal h2 { font-size: 16px; + margin-bottom: 15px; + letter-spacing: 0.5px; } .tutorial-prompt-modal p { - font-size: 18px; + font-size: 20px; + margin-bottom: 20px; + } + + .tutorial-prompt-buttons { + gap: 10px; } .tutorial-btn { font-size: 10px; - padding: 10px 15px; + padding: 10px 16px; + letter-spacing: 0.5px; } .tutorial-panel { - bottom: 10px; - padding: 15px 20px; + bottom: 100px; /* Still above inventory on mobile with clearance */ + padding: 15px 18px; + max-width: 95%; + max-height: calc(100vh - 120px); /* Prevent going off screen on mobile */ + } + + .tutorial-header { + margin-bottom: 12px; + padding-bottom: 10px; + } + + .tutorial-progress { + font-size: 18px; + letter-spacing: 1px; + } + + .tutorial-skip { + font-size: 16px; + padding: 5px 10px; } .tutorial-title { font-size: 14px; + margin-bottom: 12px; + letter-spacing: 0.5px; } .tutorial-instruction { - font-size: 18px; + font-size: 20px; + margin-bottom: 12px; + } + + .tutorial-objective { + padding: 10px 12px; + margin: 12px 0; + border-left-width: 3px; } .tutorial-objective strong { font-size: 11px; + margin-bottom: 6px; + letter-spacing: 0.5px; } .tutorial-objective-text { - font-size: 16px; + font-size: 18px; + } + + .tutorial-actions { + margin-top: 12px; + padding-top: 12px; } .tutorial-next { - font-size: 11px; - padding: 8px 15px; + font-size: 10px; + padding: 8px 16px; + letter-spacing: 0.5px; } } @@ -297,9 +458,58 @@ .tutorial-prompt-modal, .tutorial-panel { border-width: 3px; + box-shadow: 0 0 40px rgba(0, 255, 136, 0.6), + 0 4px 20px rgba(0, 0, 0, 1); } .tutorial-btn-primary { font-weight: bold; + border-width: 3px; + } + + .tutorial-objective { + border-left-width: 5px; + } + + .tutorial-header, + .tutorial-actions { + border-width: 3px; } } + +/* Reduced motion for accessibility */ +@media (prefers-reduced-motion: reduce) { + .tutorial-prompt-overlay, + .tutorial-overlay, + .tutorial-prompt-modal, + .tutorial-panel, + .tutorial-btn, + .tutorial-next, + .tutorial-skip { + animation: none !important; + transition: none !important; + } + + .tutorial-objective { + animation: none !important; + } + + .tutorial-btn-primary:hover, + .tutorial-btn-secondary:hover, + .tutorial-next:hover, + .tutorial-skip:hover { + transform: none !important; + } +} + +/* Focus states for keyboard navigation */ +.tutorial-btn:focus, +.tutorial-next:focus, +.tutorial-skip:focus { + outline: 3px solid #00ff88; + outline-offset: 3px; +} + +.tutorial-btn-secondary:focus { + outline-color: #aaa; +} diff --git a/public/break_escape/css/vm-launcher-minigame.css b/public/break_escape/css/vm-launcher-minigame.css index 63cef22..12e2051 100644 --- a/public/break_escape/css/vm-launcher-minigame.css +++ b/public/break_escape/css/vm-launcher-minigame.css @@ -195,3 +195,4 @@ + diff --git a/public/break_escape/js/core/player.js b/public/break_escape/js/core/player.js index af7da96..cb8ddae 100644 --- a/public/break_escape/js/core/player.js +++ b/public/break_escape/js/core/player.js @@ -371,6 +371,7 @@ export function movePlayerToPoint(x, y) { if (window.getTutorialManager) { const tutorialManager = window.getTutorialManager(); tutorialManager.notifyPlayerMoved(); + tutorialManager.notifyPlayerClickedToMove(); } } diff --git a/public/break_escape/js/systems/hacktivity-cable.js b/public/break_escape/js/systems/hacktivity-cable.js index 3dfcfc0..d5b32d8 100644 --- a/public/break_escape/js/systems/hacktivity-cable.js +++ b/public/break_escape/js/systems/hacktivity-cable.js @@ -226,3 +226,4 @@ export default window.hacktivityCable; + diff --git a/public/break_escape/js/systems/interactions.js b/public/break_escape/js/systems/interactions.js index 7df6e80..659aeb3 100644 --- a/public/break_escape/js/systems/interactions.js +++ b/public/break_escape/js/systems/interactions.js @@ -511,6 +511,13 @@ export function handleObjectInteraction(sprite) { return; } + // Notify tutorial when inventory item is clicked + // Items in inventory have takeable set to false + if (sprite.scenarioData.takeable === false && window.getTutorialManager) { + const tutorialManager = window.getTutorialManager(); + tutorialManager.notifyPlayerClickedInventoryItem(); + } + // Handle keycard cloning (when clicked from inventory) if (sprite.scenarioData.type === 'keycard') { console.log('KEYCARD INTERACTION - checking for cloner'); diff --git a/public/break_escape/js/systems/tutorial-manager.js b/public/break_escape/js/systems/tutorial-manager.js index 5cef0d1..83b32e0 100644 --- a/public/break_escape/js/systems/tutorial-manager.js +++ b/public/break_escape/js/systems/tutorial-manager.js @@ -19,6 +19,8 @@ export class TutorialManager { this.playerMoved = false; this.playerInteracted = false; this.playerRan = false; + this.playerClickedToMove = false; + this.playerClickedInventoryItem = false; } /** @@ -29,6 +31,16 @@ export class TutorialManager { || window.innerWidth < 768; } + /** + * Check if current scenario has objectives + */ + hasObjectives() { + // Check if objectives exist in the scenario + const hasScenarioObjectives = window.gameScenario?.objectives?.length > 0; + const hasManagerObjectives = window.objectivesManager?.aims?.length > 0; + return hasScenarioObjectives || hasManagerObjectives; + } + /** * Check if tutorial has been completed before */ @@ -115,13 +127,22 @@ export class TutorialManager { checkComplete: () => this.playerInteracted }, { - title: 'Objectives', - instruction: 'Check the objectives panel in the top-right corner to see your current tasks.', - objective: 'Complete objectives to progress through the game', - checkComplete: () => true, // Auto-complete this step - autoAdvanceDelay: 3000 + title: 'Inventory', + instruction: 'Your inventory is at the bottom of the screen. Click on items like the Notepad to use them.', + objective: 'Click on the Notepad in your inventory to open it', + checkComplete: () => this.playerClickedInventoryItem } ]; + + // Only add objectives step if scenario has objectives + if (this.hasObjectives()) { + this.steps.push({ + title: 'Objectives', + instruction: 'Check the objectives panel in the top-left corner to see your current tasks.', + objective: 'Take a look at your objectives, then click Continue', + checkComplete: () => true // Always shows Continue button immediately + }); + } } else { this.steps = [ { @@ -146,17 +167,25 @@ export class TutorialManager { title: 'Alternative Movement', instruction: 'You can also click on the ground to move to that location.', objective: 'Try clicking where you want to go', - checkComplete: () => true, // Auto-complete - autoAdvanceDelay: 3000 + checkComplete: () => this.playerClickedToMove }, { - title: 'Objectives', - instruction: 'Check the objectives panel in the top-right corner to see your current tasks.', - objective: 'Complete objectives to progress through the game', - checkComplete: () => true, // Auto-complete - autoAdvanceDelay: 3000 + title: 'Inventory', + instruction: 'Your inventory is at the bottom of the screen. Click on items like the Notepad to use them.', + objective: 'Click on the Notepad in your inventory to open it', + checkComplete: () => this.playerClickedInventoryItem } ]; + + // Only add objectives step if scenario has objectives + if (this.hasObjectives()) { + this.steps.push({ + title: 'Objectives', + instruction: 'Check the objectives panel in the top-left corner to see your current tasks.', + objective: 'Take a look at your objectives, then click Continue', + checkComplete: () => true // Always shows Continue button immediately + }); + } } this.createTutorialOverlay(); @@ -219,21 +248,18 @@ export class TutorialManager { overlay.querySelector('.tutorial-instruction').textContent = step.instruction; overlay.querySelector('.tutorial-objective-text').textContent = step.objective; + // Remove completed class from objective + const objectiveElement = overlay.querySelector('.tutorial-objective'); + if (objectiveElement) { + objectiveElement.classList.remove('completed'); + } + // Hide next button initially const nextButton = overlay.querySelector('.tutorial-next'); nextButton.style.display = 'none'; - // Check if step has auto-advance - if (step.autoAdvanceDelay) { - setTimeout(() => { - if (this.active && this.currentStep === stepIndex) { - this.nextStep(); - } - }, step.autoAdvanceDelay); - } else { - // Start checking for completion - this.checkStepCompletion(step, nextButton); - } + // Start checking for completion + this.checkStepCompletion(step, nextButton); } /** @@ -248,16 +274,17 @@ export class TutorialManager { if (step.checkComplete()) { // Step completed! + const objectiveElement = this.tutorialOverlay.querySelector('.tutorial-objective'); + if (objectiveElement) { + objectiveElement.classList.add('completed'); + } + nextButton.style.display = 'inline-block'; nextButton.textContent = 'Continue →'; clearInterval(interval); - // Auto-advance after showing success - setTimeout(() => { - if (this.active && nextButton.style.display === 'inline-block') { - this.nextStep(); - } - }, 1500); + // Player must click Continue button to proceed + // (No auto-advance - gives player control) } }, 100); } @@ -324,6 +351,24 @@ export class TutorialManager { } } + /** + * Notify tutorial of click-to-move + */ + notifyPlayerClickedToMove() { + if (this.active) { + this.playerClickedToMove = true; + } + } + + /** + * Notify tutorial of inventory item click + */ + notifyPlayerClickedInventoryItem() { + if (this.active) { + this.playerClickedInventoryItem = true; + } + } + /** * Notify tutorial of player interaction */ diff --git a/test-tutorial-ui.html b/test-tutorial-ui.html new file mode 100644 index 0000000..edfaefe --- /dev/null +++ b/test-tutorial-ui.html @@ -0,0 +1,318 @@ + + + + + + Tutorial UI Test - BreakEscape + + + + + + + + + + + +
+
Game World
+
Visible Behind Tutorial
+
+ +
+

Tutorial UI Test

+ +
+

1. Tutorial Prompt Modal

+

+ Initial prompt with NO dark overlay - game remains visible behind it. +

+ +
+ +
+

2. Tutorial Panel (Active Step)

+

+ Panel with NO dark overlay - game visible during tutorial. Shows above inventory bar. + Tutorial is z-index 1400, so dialogue minigames (1500+) appear above it. +

+ + +
+ +
+

3. Tutorial Panel (Completed Step)

+

+ When a step is completed, the objective box turns green with a different animation. +

+ +
+ +
+

4. Responsive Design

+

+ Try resizing your browser window to see mobile-responsive styling kick in at 768px width. +

+
+ +
+

5. Accessibility Features

+

+ • Keyboard navigation with visible focus states
+ • Respects prefers-reduced-motion settings
+ • High contrast mode support
+ • Proper ARIA semantics +

+
+
+ + +
+
+
+
+
+
+
+ + + + +