18 KiB
♿ ACCESSIBILITY OPTIONS - IMPLEMENTATION PLAN
Game: Mrtva Dolina / Death Valley
Date: January 4, 2026
Priority: HIGH (Inclusive Gaming Standard)
🎯 ACCESSIBILITY FEATURES (From Screenshot)
Required Features:
- ✅ High Contrast Mode
- ✅ Large Text Mode
- ✅ Color Blind Mode
- ✅ Screen Reader Support
- ✅ Reduce Flashing (Epilepsy)
- ✅ One-Handed Controls
- ✅ 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:
// 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:
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:
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:
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:
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:
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:
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:
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:
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:
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
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
// 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):
- Reduce Flashing - Safety first!
- Large Text Mode - Easy win
- High Contrast Mode - Visual accessibility
Phase 2 (Important):
- Color Blind Mode - 8% of players
- One-Handed Controls - Physical accessibility
- Audio Cues - Deaf/HoH support
Phase 3 (Advanced):
- 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