# ♿ ACCESSIBILITY FEATURES - IMPLEMENTATION PLAN **Datum:** 12. December 2025 **Prioriteta:** HIGH **Estimated Time:** 2-3 ure --- ## 🎯 **CILJI:** Implementirati celovit accessibility sistem za: - High Contrast Modes - Color Blind Support - Photosensitivity Protection --- ## 📋 **FAZA 1: HIGH CONTRAST MODES** (30 min) ### **1.1 Black & White Mode** **Datoteka:** `src/systems/AccessibilitySystem.js` (nova) ```javascript class AccessibilitySystem { constructor(scene) { this.scene = scene; this.settings = { highContrast: 'none', // 'none', 'bw', 'yellow_black' largeUI: false, boldOutlines: false, colorBlindMode: 'none', photosensitivity: false }; this.loadSettings(); } enableBlackWhite() { // Apply grayscale filter to entire game this.scene.cameras.main.setPostPipeline('GrayscalePipeline'); // Increase contrast this.scene.cameras.main.setAlpha(1.2); console.log('🎨 Black & White mode enabled'); } disableBlackWhite() { this.scene.cameras.main.clearPostPipeline(); this.scene.cameras.main.setAlpha(1.0); } } ``` ### **1.2 Yellow on Black Mode** ```javascript enableYellowOnBlack() { // Create color replacement pipeline const pipeline = this.scene.game.renderer.pipelines.add('YellowBlackPipeline', { fragShader: ` precision mediump float; uniform sampler2D uMainSampler; varying vec2 outTexCoord; void main(void) { vec4 color = texture2D(uMainSampler, outTexCoord); float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114)); // Yellow on black vec3 yellow = vec3(1.0, 1.0, 0.0); vec3 result = yellow * gray; gl_FragColor = vec4(result, color.a); } ` }); this.scene.cameras.main.setPostPipeline(pipeline); } ``` ### **1.3 Large UI (150%-200%)** ```javascript enableLargeUI(scale = 1.5) { const uiScene = this.scene.scene.get('UIScene'); if (!uiScene) return; // Scale all UI elements uiScene.children.list.forEach(child => { if (child.setScale) { child.setScale(child.scaleX * scale, child.scaleY * scale); } }); // Adjust positions this.repositionUIElements(scale); console.log(`🔍 Large UI enabled: ${scale * 100}%`); } ``` ### **1.4 Bold Outlines** ```javascript enableBoldOutlines() { // Increase stroke thickness on all text const uiScene = this.scene.scene.get('UIScene'); if (!uiScene) return; uiScene.children.list.forEach(child => { if (child.type === 'Text') { child.setStroke('#000000', 6); // Thicker stroke child.setShadow(2, 2, '#000000', 2, true, true); } }); } ``` --- ## 📋 **FAZA 2: COLOR BLIND SUPPORT** (45 min) ### **2.1 Protanopia Mode (Red-Blind)** ```javascript enableProtanopia() { const pipeline = this.createColorBlindPipeline('protanopia', ` // Protanopia simulation mat3 protanopia = mat3( 0.567, 0.433, 0.0, 0.558, 0.442, 0.0, 0.0, 0.242, 0.758 ); vec3 result = protanopia * color.rgb; `); this.scene.cameras.main.setPostPipeline(pipeline); } ``` ### **2.2 Deuteranopia Mode (Green-Blind)** ```javascript enableDeuteranopia() { const pipeline = this.createColorBlindPipeline('deuteranopia', ` mat3 deuteranopia = mat3( 0.625, 0.375, 0.0, 0.7, 0.3, 0.0, 0.0, 0.3, 0.7 ); vec3 result = deuteranopia * color.rgb; `); this.scene.cameras.main.setPostPipeline(pipeline); } ``` ### **2.3 Tritanopia Mode (Blue-Blind)** ```javascript enableTritanopia() { const pipeline = this.createColorBlindPipeline('tritanopia', ` mat3 tritanopia = mat3( 0.95, 0.05, 0.0, 0.0, 0.433, 0.567, 0.0, 0.475, 0.525 ); vec3 result = tritanopia * color.rgb; `); this.scene.cameras.main.setPostPipeline(pipeline); } ``` ### **2.4 Achromatopsia Mode (Total Color Blind)** ```javascript enableAchromatopsia() { // Full grayscale this.enableBlackWhite(); // Add high contrast this.scene.cameras.main.setContrast(1.5); } ``` ### **2.5 Shape Coding** ```javascript addShapeCoding() { // Replace color-only indicators with shapes // Example: HP bar = ❤️, Hunger = 🍖, Thirst = 💧 const uiScene = this.scene.scene.get('UIScene'); if (!uiScene) return; // Add icons to bars if (uiScene.healthBar) { const icon = uiScene.add.text( uiScene.healthBar.x - 20, uiScene.healthBar.y, '❤️', { fontSize: '16px' } ); icon.setScrollFactor(0); } } ``` ### **2.6 Pattern Overlays** ```javascript addPatternOverlays() { // Add patterns to differentiate elements // Example: HP = solid, Hunger = stripes, Thirst = dots const createPattern = (type) => { const graphics = this.scene.add.graphics(); if (type === 'stripes') { for (let i = 0; i < 10; i++) { graphics.lineStyle(2, 0xffffff, 0.3); graphics.lineBetween(i * 10, 0, i * 10, 100); } } else if (type === 'dots') { for (let i = 0; i < 5; i++) { for (let j = 0; j < 5; j++) { graphics.fillStyle(0xffffff, 0.3); graphics.fillCircle(i * 20, j * 20, 3); } } } return graphics; }; } ``` --- ## 📋 **FAZA 3: PHOTOSENSITIVITY PROTECTION** (45 min) ### **3.1 Flash Limiter** ```javascript class FlashLimiter { constructor(scene) { this.scene = scene; this.flashCount = 0; this.flashWindow = 1000; // 1 second this.maxFlashes = 3; // Max 3 flashes per second this.lastFlashTime = 0; } canFlash() { const now = Date.now(); // Reset counter if window passed if (now - this.lastFlashTime > this.flashWindow) { this.flashCount = 0; this.lastFlashTime = now; } // Check limit if (this.flashCount >= this.maxFlashes) { console.warn('⚠️ Flash limit reached - skipping flash'); return false; } this.flashCount++; return true; } } ``` ### **3.2 Disable Lightning Effects** ```javascript disableLightning() { if (this.scene.weatherSystem) { this.scene.weatherSystem.lightningEnabled = false; } // Remove existing lightning effects this.scene.children.list.forEach(child => { if (child.name === 'lightning') { child.destroy(); } }); } ``` ### **3.3 Reduce Particles** ```javascript reduceParticles(level = 0.5) { // Reduce particle emission rate this.scene.children.list.forEach(child => { if (child.type === 'ParticleEmitter') { child.setFrequency(child.frequency / level); child.setQuantity(Math.floor(child.quantity * level)); } }); } ``` ### **3.4 Epilepsy Warning Screen** ```javascript showEpilepsyWarning() { const warning = this.scene.add.container( this.scene.cameras.main.centerX, this.scene.cameras.main.centerY ); warning.setDepth(10000); const bg = this.scene.add.rectangle(0, 0, 600, 400, 0x000000, 0.95); const title = this.scene.add.text(0, -150, '⚠️ EPILEPSY WARNING', { fontSize: '32px', color: '#ff0000', fontStyle: 'bold' }).setOrigin(0.5); const text = this.scene.add.text(0, -50, 'This game contains flashing lights and patterns\n' + 'that may trigger seizures in people with\n' + 'photosensitive epilepsy.\n\n' + 'Player discretion is advised.', { fontSize: '18px', color: '#ffffff', align: 'center', wordWrap: { width: 500 } } ).setOrigin(0.5); const enableBtn = this.scene.add.text(0, 120, '[ ENABLE PHOTOSENSITIVITY MODE ]', { fontSize: '20px', color: '#00ff00', backgroundColor: '#003300', padding: { x: 20, y: 10 } }).setOrigin(0.5); enableBtn.setInteractive({ useHandCursor: true }); enableBtn.on('pointerdown', () => { this.enablePhotosensitivityMode(); warning.destroy(); }); const continueBtn = this.scene.add.text(0, 170, '[ CONTINUE WITHOUT ]', { fontSize: '16px', color: '#888888' }).setOrigin(0.5); continueBtn.setInteractive({ useHandCursor: true }); continueBtn.on('pointerdown', () => { warning.destroy(); }); warning.add([bg, title, text, enableBtn, continueBtn]); } ``` ### **3.5 Motion Sickness Options** ```javascript enableMotionSicknessMode() { // Reduce camera shake this.scene.cameras.main.shake = () => {}; // Reduce screen transitions this.scene.cameras.main.fadeEffect.duration = 100; // Faster fades // Disable parallax if (this.scene.parallaxSystem) { this.scene.parallaxSystem.enabled = false; } // Reduce zoom changes this.scene.cameras.main.zoomTo = (zoom, duration) => { this.scene.cameras.main.setZoom(zoom); // Instant }; } ``` ### **3.6 Brightness Limiter** ```javascript enableBrightnessLimiter(maxBrightness = 0.8) { // Limit maximum brightness const overlay = this.scene.add.graphics(); overlay.fillStyle(0x000000, 1 - maxBrightness); overlay.fillRect(0, 0, this.scene.cameras.main.width, this.scene.cameras.main.height); overlay.setScrollFactor(0); overlay.setDepth(9999); this.brightnessOverlay = overlay; } ``` --- ## 📋 **FAZA 4: SETTINGS MENU INTEGRATION** (30 min) ### **4.1 Accessibility Settings Menu** ```javascript createAccessibilityMenu() { const menu = this.scene.add.container( this.scene.cameras.main.centerX, this.scene.cameras.main.centerY ); // Title const title = this.scene.add.text(0, -200, '♿ ACCESSIBILITY', { fontSize: '32px', fontStyle: 'bold' }).setOrigin(0.5); // High Contrast this.addToggle(menu, 0, -150, 'High Contrast', [ 'None', 'Black & White', 'Yellow on Black' ], (value) => this.setHighContrast(value)); // Large UI this.addToggle(menu, 0, -100, 'UI Size', [ '100%', '150%', '200%' ], (value) => this.setUISize(value)); // Color Blind Mode this.addToggle(menu, 0, -50, 'Color Blind Mode', [ 'None', 'Protanopia', 'Deuteranopia', 'Tritanopia', 'Achromatopsia' ], (value) => this.setColorBlindMode(value)); // Photosensitivity this.addCheckbox(menu, 0, 0, 'Photosensitivity Protection', (checked) => this.setPhotosensitivity(checked)); // Motion Sickness this.addCheckbox(menu, 0, 50, 'Motion Sickness Mode', (checked) => this.setMotionSickness(checked)); menu.add(title); return menu; } ``` --- ## 📝 **IMPLEMENTATION STEPS:** 1. **Ustvari AccessibilitySystem.js** (30 min) 2. **Implementiraj High Contrast Modes** (30 min) 3. **Implementiraj Color Blind Support** (45 min) 4. **Implementiraj Photosensitivity Protection** (45 min) 5. **Ustvari Settings Menu** (30 min) 6. **Integracija v GameScene** (15 min) 7. **Testing** (30 min) **Total:** 3h 45min --- ## 🔧 **DATOTEKE:** **Nove:** - `src/systems/AccessibilitySystem.js` (~500 vrstic) - `src/pipelines/ColorBlindPipeline.js` (~200 vrstic) - `src/pipelines/GrayscalePipeline.js` (~50 vrstic) **Posodobljene:** - `src/scenes/GameScene.js` - Initialize AccessibilitySystem - `src/scenes/UIScene.js` - Accessibility menu - `index.html` - Dodaj nove skripte --- ## 🎯 **PRIORITETA:** **HIGH** - Accessibility je pomemben za: - Večjo dostopnost - Širše občinstvo - Boljšo uporabniško izkušnjo - Compliance s standardi --- **Status:** ⏳ **PLAN PRIPRAVLJEN - ČAKA NA IMPLEMENTACIJO** **Priporočam:** Implementacija v naslednji seji (jutri) **Razlog:** Seja že traja 2h 14min, accessibility zahteva 3-4 ure dela. Želite začeti zdaj ali pustim za jutri? 🎮