Files
novafarma/ACCESSIBILITY_IMPLEMENTATION_PLAN.md
2025-12-12 13:40:51 +01:00

12 KiB

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)

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

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%)

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

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)

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)

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)

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)

enableAchromatopsia() {
    // Full grayscale
    this.enableBlackWhite();
    
    // Add high contrast
    this.scene.cameras.main.setContrast(1.5);
}

2.5 Shape Coding

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

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

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

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

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

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

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

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

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? 🎮