Files
novafarma/ACCESSIBILITY_PLAN.md

716 lines
18 KiB
Markdown

# ♿ ACCESSIBILITY OPTIONS - IMPLEMENTATION PLAN
**Game:** Mrtva Dolina / Death Valley
**Date:** January 4, 2026
**Priority:** HIGH (Inclusive Gaming Standard)
---
## 🎯 ACCESSIBILITY FEATURES (From Screenshot)
### **Required Features:**
1.**High Contrast Mode**
2.**Large Text Mode**
3.**Color Blind Mode**
4.**Screen Reader Support**
5.**Reduce Flashing (Epilepsy)**
6.**One-Handed Controls**
7.**Audio Cues**
**Quick Toggle:** Press 1-7 to toggle features
**Full Settings:** ESC → Settings → Accessibility
---
## 📋 DETAILED IMPLEMENTATION
### **1. HIGH CONTRAST MODE** 🎨
**Purpose:** Better visibility for low vision players
**Changes:**
- Background: Pure black (#000000)
- Text: Pure white (#FFFFFF)
- UI borders: Bright yellow (#FFFF00)
- Buttons: High contrast colors
- Dialogue box: Black with white border
- Character portraits: Increased brightness +30%
**Implementation:**
```javascript
// src/systems/AccessibilitySystem.js
class AccessibilitySystem {
toggleHighContrast() {
this.highContrast = !this.highContrast;
if (this.highContrast) {
// Override all colors
this.scene.dialogueBg.setFillStyle(0x000000, 1.0);
this.scene.dialogueBg.setStrokeStyle(4, 0xFFFF00);
this.scene.dialogueText.setColor('#FFFFFF');
this.scene.speakerText.setColor('#FFFF00');
// Apply to all scenes
this.game.scene.scenes.forEach(scene => {
if (scene.applyHighContrast) {
scene.applyHighContrast();
}
});
} else {
// Restore original colors
this.restoreDefaultColors();
}
this.save();
}
}
```
**Keyboard:** Press **1** to toggle
---
### **2. LARGE TEXT MODE** 📝
**Purpose:** Readability for visually impaired
**Changes:**
- All text +50% larger
- Dialogue: 18px → 27px
- UI labels: 16px → 24px
- Buttons: 14px → 21px
- Line spacing: +25%
**Implementation:**
```javascript
toggleLargeText() {
this.largeText = !this.largeText;
const multiplier = this.largeText ? 1.5 : 1.0;
// Update all text objects
this.scene.dialogueText.setFontSize(18 * multiplier);
this.scene.speakerText.setFontSize(22 * multiplier);
// Resize dialogue box to fit
const newHeight = this.largeText ? 240 : 180;
this.scene.dialogueBg.setDisplaySize(
this.scene.dialogueBg.width,
newHeight
);
this.save();
}
```
**Keyboard:** Press **2** to toggle
---
### **3. COLOR BLIND MODE** 🌈
**Purpose:** Support for color blindness (8% of men, 0.5% of women)
**Types Supported:**
- **Deuteranopia** (Red-Green, most common)
- **Protanopia** (Red-Green)
- **Tritanopia** (Blue-Yellow, rare)
**Changes:**
- Health bars: Red → Orange with pattern
- Stamina: Blue → Cyan with stripes
- Quest markers: Color + Icon
- Item rarity: Color + Border style
- Enemy indicators: Color + Shape
**Color Palette Remapping:**
```javascript
const COLOR_BLIND_PALETTES = {
deuteranopia: {
red: 0xFF8C00, // Orange instead of red
green: 0x00CED1, // Dark cyan instead of green
blue: 0x4169E1, // Royal blue (unchanged)
purple: 0xFF00FF // Magenta (more distinct)
},
protanopia: {
red: 0xFFD700, // Gold instead of red
green: 0x1E90FF, // Dodger blue instead of green
blue: 0x8A2BE2, // Blue violet
purple: 0xFF69B4 // Hot pink
},
tritanopia: {
red: 0xFF0000, // Red (unchanged)
green: 0x00FF00, // Green (unchanged)
blue: 0xFF1493, // Deep pink instead of blue
yellow: 0x00FFFF // Cyan instead of yellow
}
};
```
**Implementation:**
```javascript
setColorBlindMode(type) {
this.colorBlindMode = type; // 'none', 'deuteranopia', 'protanopia', 'tritanopia'
if (type !== 'none') {
const palette = COLOR_BLIND_PALETTES[type];
// Remap all color references
this.game.registry.set('palette', palette);
// Add patterns to critical elements
this.addAccessibilityPatterns();
}
this.save();
}
addAccessibilityPatterns() {
// Add stripes to health bar
this.healthBar.setTexture('health_bar_striped');
// Add icons to color-coded elements
this.questMarkers.forEach(marker => {
marker.addIcon(); // Add symbol alongside color
});
}
```
**UI:** Dropdown menu: None / Deuteranopia / Protanopia / Tritanopia
**Keyboard:** Press **3** to cycle modes
---
### **4. SCREEN READER SUPPORT** 🔊
**Purpose:** Blind/low-vision accessibility
**Features:**
- Announce all UI changes
- Read dialogue text aloud
- Describe scene changes
- Navigate menus with keyboard
- Audio feedback for all actions
**Implementation:**
```javascript
class ScreenReaderSystem {
constructor(game) {
this.game = game;
this.enabled = false;
this.speechSynth = window.speechSynthesis;
this.currentUtterance = null;
}
enable() {
this.enabled = true;
this.announce("Screen reader enabled. Use arrow keys to navigate.");
}
announce(text, interrupt = false) {
if (!this.enabled) return;
// Stop current speech if interrupting
if (interrupt && this.speechSynth.speaking) {
this.speechSynth.cancel();
}
const utterance = new SpeechSynthesisUtterance(text);
utterance.lang = this.game.settings.language || 'sl-SI';
utterance.rate = 1.0;
utterance.pitch = 1.0;
utterance.volume = 1.0;
this.speechSynth.speak(utterance);
this.currentUtterance = utterance;
}
announceDialogue(speaker, text) {
const fullText = `${speaker} says: ${text}`;
this.announce(fullText, true);
}
announceSceneChange(sceneName) {
this.announce(`Entering ${sceneName}`, true);
}
announceButton(buttonLabel) {
this.announce(`Button: ${buttonLabel}. Press Enter to activate.`);
}
}
```
**Integration with PrologueScene:**
```javascript
showDialogue(index) {
const dialogue = this.dialogueData[index];
// Screen reader support
if (this.game.accessibility.screenReader.enabled) {
this.game.accessibility.screenReader.announceDialogue(
dialogue.speaker,
dialogue.text
);
}
// ... rest of dialogue logic
}
```
**Keyboard:** Press **4** to toggle
---
### **5. REDUCE FLASHING (EPILEPSY)** ⚡
**Purpose:** Prevent seizures (photosensitive epilepsy affects ~3%)
**Changes:**
- Disable camera shake
- Disable screen flash effects
- Reduce particle effects
- Smooth transitions only
- Warning on startup if disabled
**Removed Effects:**
```javascript
toggleReduceFlashing() {
this.reduceFlashing = !this.reduceFlashing;
if (this.reduceFlashing) {
// Disable dangerous effects
this.game.cameras.main.shake(0); // No shake
this.game.cameras.main.flash(0); // No flash
// Reduce particle systems
this.game.particles.setEmitterRate(0.5); // 50% particles
// Disable lightning
this.weatherSystem.disableLightning = true;
// Smooth transitions only
this.transitionDuration = 2000; // Slower fades
}
this.save();
}
```
**Startup Warning:**
```javascript
create() {
if (!this.game.accessibility.reduceFlashing) {
this.showFlashWarning();
}
}
showFlashWarning() {
const warning = this.add.text(
this.cameras.main.width / 2,
this.cameras.main.height / 2,
'⚠️ WARNING ⚠️\n\n' +
'This game contains flashing lights\n' +
'and rapid scene changes.\n\n' +
'Press 5 to enable Epilepsy Safety Mode\n' +
'Press any other key to continue',
{
fontSize: '24px',
align: 'center',
backgroundColor: '#000000',
padding: { x: 40, y: 40 }
}
);
warning.setOrigin(0.5);
// Wait for input
this.input.keyboard.once('keydown', (event) => {
if (event.key === '5') {
this.game.accessibility.toggleReduceFlashing();
}
warning.destroy();
});
}
```
**Keyboard:** Press **5** to toggle
---
### **6. ONE-HANDED CONTROLS** 🎮
**Purpose:** Physical disability support (one hand, motor impairments)
**Modes:**
- **Left-Hand Mode** (WASD + nearby keys)
- **Right-Hand Mode** (Arrow keys + numpad)
- **Both modes support mouse-only gameplay**
**Left-Hand Layout:**
```
Movement: WASD
Action: Q
Menu: E
Inventory: R
Map: T
Sprint: Shift
Crouch: Ctrl
```
**Right-Hand Layout:**
```
Movement: Arrow Keys
Action: Numpad 0
Menu: Numpad Enter
Inventory: Numpad +
Map: Numpad -
Sprint: Numpad /
Crouch: Numpad *
```
**Implementation:**
```javascript
class OneHandedControls {
setMode(mode) {
this.mode = mode; // 'left', 'right', 'both'
if (mode === 'left') {
this.bindLeftHandKeys();
} else if (mode === 'right') {
this.bindRightHandKeys();
} else {
this.bindBothHands();
}
}
bindLeftHandKeys() {
const keys = {
up: 'W',
down: 'S',
left: 'A',
right: 'D',
action: 'Q',
menu: 'E',
inventory: 'R',
map: 'T',
sprint: 'SHIFT',
crouch: 'CTRL'
};
this.remapKeys(keys);
}
bindRightHandKeys() {
const keys = {
up: 'UP',
down: 'DOWN',
left: 'LEFT',
right: 'RIGHT',
action: 'NUMPAD_ZERO',
menu: 'NUMPAD_ENTER',
inventory: 'NUMPAD_ADD',
map: 'NUMPAD_SUBTRACT',
sprint: 'NUMPAD_DIVIDE',
crouch: 'NUMPAD_MULTIPLY'
};
this.remapKeys(keys);
}
}
```
**UI Toggle:**
- Settings → Accessibility → One-Handed Controls
- Options: Both Hands / Left Hand Only / Right Hand Only
**Keyboard:** Press **6** to cycle modes
---
### **7. AUDIO CUES** 🔔
**Purpose:** Additional feedback for deaf/hard-of-hearing players
**Features:**
- Visual sound indicators
- Subtitles for all dialogue (already done!)
- Direction indicators for off-screen sounds
- Vibration feedback (controller)
**Visual Sound System:**
```javascript
class VisualSoundCueSystem {
constructor(scene) {
this.scene = scene;
this.cues = [];
}
showCue(soundType, direction, distance) {
// Create visual indicator
const cue = this.scene.add.sprite(x, y, 'sound_cue_' + soundType);
cue.setAlpha(0.7);
// Position based on direction
const angle = this.getAngleFromDirection(direction);
const radius = 200; // Distance from player
cue.x = this.scene.player.x + Math.cos(angle) * radius;
cue.y = this.scene.player.y + Math.sin(angle) * radius;
// Add text label
const label = this.scene.add.text(cue.x, cue.y + 30, soundType, {
fontSize: '14px',
backgroundColor: '#000000'
});
// Fade out after 2 seconds
this.scene.tweens.add({
targets: [cue, label],
alpha: 0,
duration: 2000,
onComplete: () => {
cue.destroy();
label.destroy();
}
});
}
// Example usage
onZombieGrowl(zombiePosition) {
const direction = this.getDirectionToPlayer(zombiePosition);
const distance = Phaser.Math.Distance.Between(
this.scene.player.x, this.scene.player.y,
zombiePosition.x, zombiePosition.y
);
this.showCue('Zombie Growl', direction, distance);
}
}
```
**Sound Types with Icons:**
- 🧟 Zombie nearby
- 💥 Explosion
- 🔔 Quest update
- 💬 NPC speaking
- ⚔️ Combat
- 🚪 Door opening/closing
- 📦 Item pickup
**Keyboard:** Press **7** to toggle
---
## 🎨 UI IMPLEMENTATION
### **Accessibility Options Menu**
```javascript
class AccessibilityMenu extends Phaser.Scene {
create() {
// Title
this.add.text(width/2, 50, '♿ ACCESSIBILITY OPTIONS', {
fontSize: '32px',
color: '#FFFFFF'
}).setOrigin(0.5);
// Options list
const options = [
{ id: 1, name: 'High Contrast Mode', key: '1' },
{ id: 2, name: 'Large Text Mode', key: '2' },
{ id: 3, name: 'Color Blind Mode', key: '3' },
{ id: 4, name: 'Screen Reader Support', key: '4' },
{ id: 5, name: 'Reduce Flashing (Epilepsy)', key: '5' },
{ id: 6, name: 'One-Handed Controls', key: '6' },
{ id: 7, name: 'Audio Cues', key: '7' }
];
let y = 150;
options.forEach(option => {
const text = this.add.text(100, y,
`${option.id}. ${option.name}`,
{ fontSize: '20px' }
);
// Toggle indicator
const indicator = this.add.text(width - 100, y,
this.getStatusText(option.id),
{ fontSize: '20px' }
);
y += 50;
});
// Footer
this.add.text(width/2, height - 100,
'Full accessibility settings available\n' +
'in-game (ESC → Settings)\n\n' +
'Tip: Press 1-7 to toggle these features',
{
fontSize: '16px',
align: 'center',
color: '#AAAAAA'
}
).setOrigin(0.5);
// OK button
const okButton = this.add.rectangle(
width/2, height - 40,
200, 50,
0x0066FF
);
this.add.text(width/2, height - 40, 'OK', {
fontSize: '24px'
}).setOrigin(0.5);
okButton.setInteractive();
okButton.on('pointerdown', () => {
this.scene.start('MainMenu');
});
// Keyboard shortcuts
this.input.keyboard.on('keydown', (event) => {
const key = parseInt(event.key);
if (key >= 1 && key <= 7) {
this.toggleOption(key);
}
});
}
toggleOption(id) {
const accessibility = this.game.registry.get('accessibility');
switch(id) {
case 1: accessibility.toggleHighContrast(); break;
case 2: accessibility.toggleLargeText(); break;
case 3: accessibility.cycleColorBlindMode(); break;
case 4: accessibility.toggleScreenReader(); break;
case 5: accessibility.toggleReduceFlashing(); break;
case 6: accessibility.cycleOneHandedMode(); break;
case 7: accessibility.toggleAudioCues(); break;
}
// Refresh UI
this.scene.restart();
}
getStatusText(id) {
const accessibility = this.game.registry.get('accessibility');
const statuses = [
accessibility.highContrast ? 'ON' : 'OFF',
accessibility.largeText ? 'ON' : 'OFF',
accessibility.colorBlindMode || 'None',
accessibility.screenReader ? 'ON' : 'OFF',
accessibility.reduceFlashing ? 'ON' : 'OFF',
accessibility.oneHandedMode || 'Both',
accessibility.audioCues ? 'ON' : 'OFF'
];
return statuses[id - 1];
}
}
```
---
## 💾 PERSISTENCE
```javascript
// Save accessibility settings to localStorage
class AccessibilitySystem {
save() {
const settings = {
highContrast: this.highContrast,
largeText: this.largeText,
colorBlindMode: this.colorBlindMode,
screenReader: this.screenReader,
reduceFlashing: this.reduceFlashing,
oneHandedMode: this.oneHandedMode,
audioCues: this.audioCues
};
localStorage.setItem('accessibility_settings', JSON.stringify(settings));
}
load() {
const saved = localStorage.getItem('accessibility_settings');
if (saved) {
const settings = JSON.parse(saved);
Object.assign(this, settings);
this.applyAll();
}
}
applyAll() {
if (this.highContrast) this.toggleHighContrast();
if (this.largeText) this.toggleLargeText();
if (this.colorBlindMode !== 'none') this.setColorBlindMode(this.colorBlindMode);
if (this.screenReader) this.screenReaderSystem.enable();
if (this.reduceFlashing) this.toggleReduceFlashing();
if (this.oneHandedMode !== 'both') this.controls.setMode(this.oneHandedMode);
if (this.audioCues) this.visualSoundCues.enable();
}
}
```
---
## 📊 IMPLEMENTATION TIMELINE
| Week | Task | Deliverable |
|------|------|-------------|
| **1** | Core System | AccessibilitySystem.js |
| **2** | High Contrast + Large Text | Visual modes |
| **3** | Color Blind Mode | 3 palette variants |
| **4** | Screen Reader | Text-to-speech |
| **5** | Epilepsy Safety | Effect reduction |
| **6** | One-Handed + Audio Cues | Control schemes |
| **7** | UI Integration | Settings menu |
| **8** | Testing | User testing |
**Total Time:** 8 weeks (~2 months)
---
## ✅ SUCCESS CRITERIA
- [ ] All 7 features implemented
- [ ] Keyboard shortcuts (1-7) working
- [ ] Settings persist across sessions
- [ ] No performance impact
- [ ] Screen reader announces all interactions
- [ ] Color blind modes tested with simulators
- [ ] One-handed mode fully playable
- [ ] Epilepsy warning on first launch
---
## 🎯 PRIORITY ORDER
### **Phase 1 (Critical):**
1. **Reduce Flashing** - Safety first!
2. **Large Text Mode** - Easy win
3. **High Contrast Mode** - Visual accessibility
### **Phase 2 (Important):**
4. **Color Blind Mode** - 8% of players
5. **One-Handed Controls** - Physical accessibility
6. **Audio Cues** - Deaf/HoH support
### **Phase 3 (Advanced):**
7. **Screen Reader Support** - Complex but essential
---
## 🏆 INDUSTRY STANDARDS
Following guidelines from:
- **Game Accessibility Guidelines** (gameaccessibilityguidelines.com)
- **Xbox Accessibility** standards
- **PlayStation Accessibility** standards
- **WCAG 2.1** (Web Content Accessibility Guidelines)
**Certification Goal:** Xbox Accessibility Features badge
---
**Last Updated:** January 4, 2026
**Status:** Planning → Implementation Starting Tonight