mirror of
https://github.com/cliffe/BreakEscape.git
synced 2026-02-20 13:50:46 +00:00
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:
@@ -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>
|
||||
|
||||
@@ -18,3 +18,4 @@ class RemoveUniqueGameConstraint < ActiveRecord::Migration[7.0]
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
259
docs/TUTORIAL_STYLE_COMPARISON.md
Normal file
259
docs/TUTORIAL_STYLE_COMPARISON.md
Normal 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
|
||||
|
||||
225
docs/TUTORIAL_UI_IMPROVEMENTS.md
Normal file
225
docs/TUTORIAL_UI_IMPROVEMENTS.md
Normal 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.
|
||||
|
||||
46
index.html
46
index.html
@@ -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>
|
||||
|
||||
@@ -189,3 +189,4 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -195,3 +195,4 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -371,6 +371,7 @@ export function movePlayerToPoint(x, y) {
|
||||
if (window.getTutorialManager) {
|
||||
const tutorialManager = window.getTutorialManager();
|
||||
tutorialManager.notifyPlayerMoved();
|
||||
tutorialManager.notifyPlayerClickedToMove();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -226,3 +226,4 @@ export default window.hacktivityCable;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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
318
test-tutorial-ui.html
Normal 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>
|
||||
|
||||
Reference in New Issue
Block a user