Update CSS file paths and enhance tutorial system

- Changed CSS file paths in index.html and show.html.erb to reflect new directory structure under public/break_escape.
- Added a new tutorial.css file with styles tailored for the tutorial system, ensuring a cohesive pixel-art aesthetic.
- Enhanced the tutorial manager to track player interactions, including clicks to move and inventory item usage, improving the tutorial experience for new players.
- Updated tutorial steps to dynamically include objectives based on the current scenario.

Files modified:
- index.html: Updated CSS links.
- show.html.erb: Updated CSS links.
- tutorial.css: New styles for the tutorial system.
- player.js: Added notifications for player actions.
- tutorial-manager.js: Enhanced logic for tracking tutorial progress and objectives.
- interactions.js: Added notifications for inventory interactions.
This commit is contained in:
Z. Cliffe Schreuders
2026-01-19 09:54:15 +00:00
parent b7223af010
commit 5c28743144
13 changed files with 1174 additions and 104 deletions

View File

@@ -52,6 +52,7 @@
<link rel="stylesheet" href="/break_escape/css/text-file-minigame.css">
<link rel="stylesheet" href="/break_escape/css/npc-barks.css">
<link rel="stylesheet" href="/break_escape/css/objectives.css">
<link rel="stylesheet" href="/break_escape/css/tutorial.css">
<link rel="stylesheet" href="/break_escape/css/vm-launcher-minigame.css">
<link rel="stylesheet" href="/break_escape/css/flag-station-minigame.css">
</head>

View File

@@ -18,3 +18,4 @@ class RemoveUniqueGameConstraint < ActiveRecord::Migration[7.0]
end

View File

@@ -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

View File

@@ -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.

View File

@@ -26,29 +26,29 @@
</script>
<!-- CSS Files -->
<link rel="stylesheet" href="css/main.css">
<link rel="stylesheet" href="css/utilities.css">
<link rel="stylesheet" href="css/notifications.css">
<link rel="stylesheet" href="css/panels.css">
<link rel="stylesheet" href="css/hud.css">
<link rel="stylesheet" href="css/minigames-framework.css">
<link rel="stylesheet" href="css/dusting.css">
<link rel="stylesheet" href="css/lockpicking.css">
<link rel="stylesheet" href="css/modals.css">
<link rel="stylesheet" href="css/notes.css">
<link rel="stylesheet" href="css/bluetooth-scanner.css">
<link rel="stylesheet" href="css/biometrics-minigame.css">
<link rel="stylesheet" href="css/container-minigame.css">
<link rel="stylesheet" href="css/phone-chat-minigame.css">
<link rel="stylesheet" href="css/person-chat-minigame.css">
<link rel="stylesheet" href="css/rfid-minigame.css">
<link rel="stylesheet" href="css/npc-interactions.css">
<link rel="stylesheet" href="css/pin.css">
<link rel="stylesheet" href="css/minigames-framework.css">
<link rel="stylesheet" href="css/password-minigame.css">
<link rel="stylesheet" href="css/text-file-minigame.css">
<link rel="stylesheet" href="css/npc-barks.css">
<link rel="stylesheet" href="css/tutorial.css">
<link rel="stylesheet" href="public/break_escape/css/main.css">
<link rel="stylesheet" href="public/break_escape/css/utilities.css">
<link rel="stylesheet" href="public/break_escape/css/notifications.css">
<link rel="stylesheet" href="public/break_escape/css/panels.css">
<link rel="stylesheet" href="public/break_escape/css/hud.css">
<link rel="stylesheet" href="public/break_escape/css/objectives.css">
<link rel="stylesheet" href="public/break_escape/css/minigames-framework.css">
<link rel="stylesheet" href="public/break_escape/css/dusting.css">
<link rel="stylesheet" href="public/break_escape/css/lockpicking.css">
<link rel="stylesheet" href="public/break_escape/css/modals.css">
<link rel="stylesheet" href="public/break_escape/css/notes.css">
<link rel="stylesheet" href="public/break_escape/css/bluetooth-scanner.css">
<link rel="stylesheet" href="public/break_escape/css/biometrics-minigame.css">
<link rel="stylesheet" href="public/break_escape/css/container-minigame.css">
<link rel="stylesheet" href="public/break_escape/css/phone-chat-minigame.css">
<link rel="stylesheet" href="public/break_escape/css/person-chat-minigame.css">
<link rel="stylesheet" href="public/break_escape/css/rfid-minigame.css">
<link rel="stylesheet" href="public/break_escape/css/npc-interactions.css">
<link rel="stylesheet" href="public/break_escape/css/pin.css">
<link rel="stylesheet" href="public/break_escape/css/password-minigame.css">
<link rel="stylesheet" href="public/break_escape/css/text-file-minigame.css">
<link rel="stylesheet" href="public/break_escape/css/npc-barks.css">
<link rel="stylesheet" href="public/break_escape/css/tutorial.css">
<!-- External JavaScript libraries -->
<script src="https://cdn.jsdelivr.net/npm/phaser@3.60.0/dist/phaser.min.js"></script>

View File

@@ -189,3 +189,4 @@

View File

@@ -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;
}

View File

@@ -195,3 +195,4 @@

View File

@@ -371,6 +371,7 @@ export function movePlayerToPoint(x, y) {
if (window.getTutorialManager) {
const tutorialManager = window.getTutorialManager();
tutorialManager.notifyPlayerMoved();
tutorialManager.notifyPlayerClickedToMove();
}
}

View File

@@ -226,3 +226,4 @@ export default window.hacktivityCable;

View File

@@ -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');

View File

@@ -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
*/

318
test-tutorial-ui.html Normal file
View File

@@ -0,0 +1,318 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tutorial UI Test - BreakEscape</title>
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&family=VT323&display=swap" rel="stylesheet">
<!-- Tutorial CSS -->
<link rel="stylesheet" href="public/break_escape/css/tutorial.css">
<style>
body {
margin: 0;
padding: 20px;
background: #1a1a2e;
font-family: 'VT323', monospace;
color: #fff;
/* Add some animated elements to simulate the game */
background-image:
linear-gradient(45deg, transparent 40%, rgba(0, 255, 136, 0.05) 50%, transparent 60%),
linear-gradient(-45deg, transparent 40%, rgba(0, 255, 136, 0.05) 50%, transparent 60%);
background-size: 200px 200px;
animation: gameBackground 20s linear infinite;
}
@keyframes gameBackground {
0% { background-position: 0 0, 100px 100px; }
100% { background-position: 200px 200px, 300px 300px; }
}
.test-container {
max-width: 1200px;
margin: 0 auto;
}
h1 {
font-family: 'Press Start 2P', monospace;
color: #00ff88;
text-align: center;
margin-bottom: 40px;
font-size: 24px;
text-shadow: 0 0 10px rgba(0, 255, 136, 0.5);
}
.test-section {
margin-bottom: 40px;
background: rgba(0, 0, 0, 0.5);
padding: 20px;
border: 2px solid #444;
}
.test-section h2 {
font-family: 'Press Start 2P', monospace;
color: #00ff88;
font-size: 16px;
margin-bottom: 20px;
}
button {
font-family: 'Press Start 2P', monospace;
font-size: 12px;
padding: 12px 24px;
margin: 10px;
cursor: pointer;
border: 2px solid #00ff88;
background: #00ff88;
color: #000;
transition: all 0.2s ease;
}
button:hover {
background: #00cc6a;
transform: translateY(-2px);
}
.description {
font-size: 20px;
margin-bottom: 20px;
line-height: 1.6;
}
/* Simulate game elements visible behind tutorial */
.game-simulation {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-family: 'Press Start 2P', monospace;
font-size: 14px;
color: rgba(0, 255, 136, 0.3);
text-align: center;
z-index: 1;
pointer-events: none;
}
/* Mock game elements */
.mock-inventory {
position: fixed;
bottom: 0;
left: 50%;
transform: translateX(-50%);
height: 80px;
width: 100%;
background: rgba(149, 157, 216, 0.8);
border-top: 2px solid #444;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
}
.mock-slot {
width: 60px;
height: 60px;
border: 1px solid rgba(255, 255, 255, 0.3);
background: rgba(255, 255, 255, 0.1);
}
</style>
</head>
<body>
<!-- Simulated game background -->
<div class="game-simulation">
<div>Game World</div>
<div style="margin-top: 20px;">Visible Behind Tutorial</div>
</div>
<div class="test-container">
<h1>Tutorial UI Test</h1>
<div class="test-section">
<h2>1. Tutorial Prompt Modal</h2>
<p class="description">
Initial prompt with NO dark overlay - game remains visible behind it.
</p>
<button onclick="showPromptModal()">Show Prompt Modal</button>
</div>
<div class="test-section">
<h2>2. Tutorial Panel (Active Step)</h2>
<p class="description">
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.
</p>
<button onclick="showTutorialPanel(false, 'movement')">Show Movement Step</button>
<button onclick="showTutorialPanel(false, 'inventory')">Show Inventory Step</button>
</div>
<div class="test-section">
<h2>3. Tutorial Panel (Completed Step)</h2>
<p class="description">
When a step is completed, the objective box turns green with a different animation.
</p>
<button onclick="showTutorialPanel(true)">Show Completed Tutorial Step</button>
</div>
<div class="test-section">
<h2>4. Responsive Design</h2>
<p class="description">
Try resizing your browser window to see mobile-responsive styling kick in at 768px width.
</p>
</div>
<div class="test-section">
<h2>5. Accessibility Features</h2>
<p class="description">
• Keyboard navigation with visible focus states<br>
• Respects prefers-reduced-motion settings<br>
• High contrast mode support<br>
• Proper ARIA semantics
</p>
</div>
</div>
<!-- Mock inventory bar -->
<div class="mock-inventory">
<div class="mock-slot"></div>
<div class="mock-slot"></div>
<div class="mock-slot"></div>
<div class="mock-slot"></div>
<div class="mock-slot"></div>
</div>
<script>
function showPromptModal() {
// Remove any existing modal
const existing = document.querySelector('.tutorial-prompt-overlay');
if (existing) existing.remove();
// Create modal overlay
const overlay = document.createElement('div');
overlay.className = 'tutorial-prompt-overlay';
overlay.innerHTML = `
<div class="tutorial-prompt-modal">
<h2>Welcome to BreakEscape!</h2>
<p>Would you like to go through a quick tutorial to learn the basic controls?</p>
<div class="tutorial-prompt-buttons">
<button id="tutorial-yes" class="tutorial-btn tutorial-btn-primary">Yes, show me</button>
<button id="tutorial-no" class="tutorial-btn tutorial-btn-secondary">No, I'll figure it out</button>
</div>
</div>
`;
document.body.appendChild(overlay);
// Add click handlers
document.getElementById('tutorial-yes').addEventListener('click', () => {
document.body.removeChild(overlay);
showTutorialPanel(false);
});
document.getElementById('tutorial-no').addEventListener('click', () => {
document.body.removeChild(overlay);
});
// Click outside to close
overlay.addEventListener('click', (e) => {
if (e.target === overlay) {
document.body.removeChild(overlay);
}
});
}
function showTutorialPanel(completed = false, stepType = 'movement') {
// Remove any existing panel
const existing = document.querySelector('.tutorial-overlay');
if (existing) existing.remove();
// Define step content
const steps = {
movement: {
progress: 'Step 1 of 6',
title: 'Movement',
instruction: 'Use W, A, S, D keys to move your character around.',
objective: 'Try moving in different directions'
},
inventory: {
progress: 'Step 5 of 6',
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'
}
};
const step = steps[stepType] || steps.movement;
// Create tutorial overlay
const overlay = document.createElement('div');
overlay.className = 'tutorial-overlay';
overlay.innerHTML = `
<div class="tutorial-panel">
<div class="tutorial-header">
<span class="tutorial-progress">${step.progress}</span>
<button class="tutorial-skip" title="Skip Tutorial">Skip Tutorial</button>
</div>
<h3 class="tutorial-title">${step.title}</h3>
<p class="tutorial-instruction">${step.instruction}</p>
<div class="tutorial-objective ${completed ? 'completed' : ''}">
<strong>Objective:</strong>
<span class="tutorial-objective-text">${step.objective}</span>
</div>
<div class="tutorial-actions">
<button class="tutorial-next" style="display: ${completed ? 'inline-block' : 'none'};">Continue →</button>
</div>
</div>
`;
document.body.appendChild(overlay);
// Add click handler for skip button
overlay.querySelector('.tutorial-skip').addEventListener('click', () => {
if (confirm('Are you sure you want to skip the tutorial?')) {
document.body.removeChild(overlay);
}
});
// Add click handler for next button
overlay.querySelector('.tutorial-next').addEventListener('click', () => {
document.body.removeChild(overlay);
});
// If not completed, simulate completion after 3 seconds
// Player must click Continue to proceed (no auto-advance)
if (!completed) {
setTimeout(() => {
const objectiveElement = overlay.querySelector('.tutorial-objective');
const nextButton = overlay.querySelector('.tutorial-next');
if (objectiveElement && nextButton) {
objectiveElement.classList.add('completed');
nextButton.style.display = 'inline-block';
// Note: Button appears but doesn't auto-advance
}
}, 3000);
}
}
// Keyboard shortcuts for testing
document.addEventListener('keydown', (e) => {
if (e.key === '1') showPromptModal();
if (e.key === '2') showTutorialPanel(false, 'movement');
if (e.key === '3') showTutorialPanel(true, 'movement');
if (e.key === '4') showTutorialPanel(false, 'inventory');
if (e.key === '5') showTutorialPanel(true, 'inventory');
});
console.log('Tutorial UI Test Ready!');
console.log('Press 1 to show prompt modal');
console.log('Press 2 to show movement step (active)');
console.log('Press 3 to show movement step (completed)');
console.log('Press 4 to show inventory step (active)');
console.log('Press 5 to show inventory step (completed)');
</script>
</body>
</html>