1/* Fullscreen screen tests â dead pixel and colour. 2 One engine, driven by the slide set declared on the page container. */ 3(function () { 4 'use strict'; 5 6 var stage = document.getElementById('test-stage'); 7 if (!stage) return; 8 9 var mode = stage.dataset.mode || 'pixel'; 10 11 var SETS = { 12 pixel: [ 13 { css: '#000000', name: 'Black', hint: 'Bright dots here are stuck or hot pixels.' }, 14 { css: '#ffffff', name: 'White', hint: 'Dark dots here are dead pixels or dust.' }, 15 { css: '#ff0000', name: 'Red', hint: 'A pixel missing red shows as cyan-ish.' }, 16 { css: '#00ff00', name: 'Green', hint: 'Green drives most of perceived brightness.' }, 17 { css: '#0000ff', name: 'Blue', hint: 'Blue faults are the hardest to spot â look closely.' }, 18 { css: '#00ffff', name: 'Cyan', hint: 'Green + blue only.' }, 19 { css: '#ff00ff', name: 'Magenta', hint: 'Red + blue only.' }, 20 { css: '#ffff00', name: 'Yellow', hint: 'Red + green only.' }, 21 { css: '#808080', name: 'Grey 50%', hint: 'Uneven patches here mean poor uniformity.' } 22 ], 23 colour: [ 24 { css: 'linear-gradient(90deg,#000,#fff)', name: 'Greyscale ramp', hint: 'Look for banding â steps instead of a smooth fade.' }, 25 { css: 'linear-gradient(90deg,#000,#f00)', name: 'Red ramp', hint: 'Should fade evenly with no blotches.' }, 26 { css: 'linear-gradient(90deg,#000,#0f0)', name: 'Green ramp', hint: 'Should fade evenly with no blotches.' }, 27 { css: 'linear-gradient(90deg,#000,#00f)', name: 'Blue ramp', hint: 'Blue banding is the most common.' }, 28 { css: 'linear-gradient(90deg,#f00,#ff0,#0f0,#0ff,#00f,#f0f,#f00)', name: 'Hue sweep', hint: 'Every hue should be distinct, none crushed.' }, 29 { css: '#ffffff', name: 'White field', hint: 'Check for tint, clouding or brighter edges.' }, 30 { css: '#808080', name: 'Grey field', hint: 'The honest test of panel uniformity.' }, 31 { css: '#000000', name: 'Black field', hint: 'Check backlight bleed at the corners.' } 32 ], 33 burnin: [ 34 { css: '#ffffff', name: 'Full white', hint: 'A faint ghost of a previous image shows most clearly here.' }, 35 { css: '#808080', name: 'Grey 50%', hint: 'The most revealing field for image retention.' }, 36 { css: '#ff0000', name: 'Red', hint: 'Retention often shows in one channel before the others.' }, 37 { css: '#00ff00', name: 'Green', hint: 'Green wears fastest on OLED â check for dull patches.' }, 38 { css: '#0000ff', name: 'Blue', hint: 'Blue subpixels age quickest of all.' }, 39 { css: '#000000', name: 'Black', hint: 'Look for uneven glow or lingering shapes.' } 40 ], 41 full: [ 42 { css: '#ffffff', name: 'White', hint: 'Step 1 of 10 â dark dots are dead pixels or dust.' }, 43 { css: '#000000', name: 'Black', hint: 'Step 2 â bright dots are stuck pixels; glow at the edges is backlight bleed.' }, 44 { css: '#ff0000', name: 'Red', hint: 'Step 3 â checking the red subpixels.' }, 45 { css: '#00ff00', name: 'Green', hint: 'Step 4 â green carries most of the perceived brightness.' }, 46 { css: '#0000ff', name: 'Blue', hint: 'Step 5 â blue faults are the hardest to spot.' }, 47 { css: '#808080', name: 'Grey 50%', hint: 'Step 6 â the most revealing field for uniformity and retention.' }, 48 { css: 'linear-gradient(90deg,#000,#fff)', name: 'Greyscale ramp', hint: 'Step 7 â look for banding: steps instead of a smooth fade.' }, 49 { css: 'linear-gradient(90deg,#000,#00f)', name: 'Blue ramp', hint: 'Step 8 â blue bands most easily of the three channels.' }, 50 { css: 'linear-gradient(90deg,#f00,#ff0,#0f0,#0ff,#00f,#f0f,#f00)', name: 'Hue sweep', hint: 'Step 9 â every hue should be distinct.' }, 51 { css: '#050505', name: 'Near black', hint: 'Step 10 â lift the black slightly to expose clouding.' } 52 ], 53 bleed: [ 54 { css: '#000000', name: 'Pure black', hint: 'Light leaking at the edges or corners is backlight bleed.' }, 55 { css: '#050505', name: 'Near black', hint: 'Slightly lifted black makes clouding easier to see.' }, 56 { css: '#101010', name: 'Very dark grey', hint: 'Uneven patches here are clouding rather than bleed.' }, 57 { css: '#000000', name: 'Pure black again', hint: 'Move your head: bleed stays put, reflections move.' } 58 ] 59 }; 60 61 var slides = SETS[mode] || SETS.pixel; 62 var i = 0; 63 64 var surface = document.getElementById('test-surface'); 65 var nameEl = document.getElementById('test-name'); 66 var hintEl = document.getElementById('test-hint'); 67 var posEl = document.getElementById('test-pos'); 68 var hud = document.getElementById('test-hud'); 69 70 function paint() { 71 var s = slides[i]; 72 var isGradient = s.css.indexOf('gradient') !== -1; 73 surface.style.background = s.css; 74 // Keep the HUD readable whatever is behind it. 75 surface.classList.toggle('on-light', !isGradient && isLight(s.css)); 76 if (nameEl) nameEl.textContent = s.name; 77 if (hintEl) hintEl.textContent = s.hint; 78 if (posEl) posEl.textContent = (i + 1) + ' / ' + slides.length; 79 } 80 81 function isLight(hex) { 82 if (hex.charAt(0) !== '#') return false;
83 var n = parseInt(hex.slice(1), 16); 84 var r = (n >> 16) & 255, g = (n >> 8) & 255, b = n & 255; 85 return (0.2126 * r + 0.7152 * g + 0.0722 * b) > 140; 86 } 87 88 function go(d) { i = (i + d + slides.length) % slides.length; paint(); } 89 90 // ââ burn-in fixer âââââââââââââââââââââââââââââââââââââââââââââââ 91 // Rapidly cycling colours exercises every subpixel, which can shift mild 92 // image retention. It cannot repair a truly burned-in OLED. 93 var fixer = null; 94 var FIX_COLOURS = ['#ff0000', '#00ff00', '#0000ff', '#ffffff', '#000000']; 95 function startFixer() { 96 if (fixer) return; 97 var n = 0; // local counter; must not shadow the slide index 98 var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches; 99 var every = reduce ? 400 : 90; 100 fixer = setInterval(function () { 101 surface.style.background = FIX_COLOURS[n++ % FIX_COLOURS.length]; 102 }, every); 103 if (nameEl) nameEl.textContent = 'Fixer running'; 104 if (hintEl) hintEl.textContent = 'Leave this running for 10-30 minutes. Press Esc to stop.'; 105 } 106 function stopFixer() { 107 if (!fixer) return; 108 clearInterval(fixer); fixer = null; paint(); 109 } 110 var fixBtn = document.getElementById('test-fixer'); 111 if (fixBtn) fixBtn.addEventListener('click', function (ev) { 112 ev.stopPropagation(); 113 if (fixer) { stopFixer(); fixBtn.textContent = 'Run burn-in fixer'; } 114 else { enter(); startFixer(); fixBtn.textContent = 'Stop fixer'; } 115 }); 116 117 // ââ fullscreen ââââââââââââââââââââââââââââââââââââââââââââââââââ 118 function enter() { 119 var el = stage; 120 var fn = el.requestFullscreen || el.webkitRequestFullscreen || el.msRequestFullscreen; 121 if (fn) { try { fn.call(el); } catch (e) {} } 122 stage.classList.add('running'); 123 document.body.classList.add('test-running');
124 paint(); 125 } 126 function exit() { 127 stopFixer(); 128 if (document.fullscreenElement || document.webkitFullscreenElement) { 129 var fn = document.exitFullscreen || document.webkitExitFullscreen; 130 if (fn) { try { fn.call(document); } catch (e) {} } 131 } 132 stage.classList.remove('running'); 133 document.body.classList.remove('test-running'); 134 } 135 136 var startBtn = document.getElementById('test-start'); 137 if (startBtn) startBtn.addEventListener('click', enter); 138 139 var exitBtn = document.getElementById('test-exit'); 140 if (exitBtn) exitBtn.addEventListener('click', function (ev) { ev.stopPropagation(); exit(); }); 141 142 document.querySelectorAll('[data-test-nav]').forEach(function (b) { 143 b.addEventListener('click', function (ev) { 144 ev.stopPropagation(); 145 go(b.dataset.testNav === 'prev' ? -1 : 1); 146 }); 147 }); 148 149 // Click / tap anywhere advances â the whole point is not hunting for a button. 150 if (surface) { 151 surface.addEventListener('click', function () { if (stage.classList.contains('running') && !fixer) go(1); }); 152 } 153 154 document.addEventListener('keydown', function (ev) { 155 if (!stage.classList.contains('running')) return; 156 if (ev.key === 'ArrowRight' || ev.key === ' ' || ev.key === 'Enter') { ev.preventDefault(); go(1); } 157 else if (ev.key === 'ArrowLeft') { ev.preventDefault(); go(-1); } 158 else if (ev.key === 'Escape') exit(); 159 else if (ev.key === 'h' || ev.key === 'H') hud && hud.classList.toggle('hidden'); 160 }); 161 162 ['fullscreenchange', 'webkitfullscreenchange'].forEach(function (evt) { 163 document.addEventListener(evt, function () { 164 if (!document.fullscreenElement && !document.webkitFullscreenElement) { 165 stage.classList.remove('running'); 166 document.body.classList.remove('test-running'); 167 } 168 }); 169 }); 170 171 // Build the swatch strip on the intro card so the page is not empty before you start. 172 var strip = document.getElementById('test-strip'); 173 if (strip) { 174 strip.innerHTML = slides.map(function (s, n) { 175 return '<button type="button" class="sw" data-i="' + n + '" title="' + s.name + 176 '" style="background:' + s.css + '"><span>' + s.name + '</span></button>'; 177 }).join(''); 178 strip.addEventListener('click', function (ev) { 179 var b = ev.target.closest('.sw'); 180 if (!b) return; 181 i = parseInt(b.dataset.i, 10) || 0; 182 enter(); 183 }); 184 } 185 186 paint(); 187})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.