This Hyper-Drive speed reading widget leverages Rapid Serial Visual Presentation (RSVP) to eliminate the mechanical latency of eye movements during traditional scanning.
By displaying text sequentially at a single focal point, it eliminates saccades: the involuntary micro jumps the eyes make when moving between words, and suppresses sub vocalisation, which is the internal habit of speaking words silently.
This allows users to consume content at speeds upwards of 500 words per minute without sacrificing core narrative comprehension, transforming longform blog entries into highly digestible streams of information.
At the heart of its performance is the strict adherence to the Optimal Recognition Point (ORP) formula, which dictates that the human brain processes a word most efficiently when the eye targets a specific offset just left of the true center.
The widget achieves this through a structured three part alignment matrix. By pinning the left component to a fixed width percentage and coloring the focal character a vivid red, the layout guarantees that the primary processing anchor never drifts horizontally.
The reader's focus remains locked onto a static vertical axis, removing the cognitive fatigue associated with tracking words of varying lengths.
Engineered for seamless crossplatform utility, the script functions autonomously without reliance on external frameworks or platform specific APIs.
Its content discovery algorithm evaluates the structural hierarchy of the host page, scanning for universal semantic markers like blog body wrappers before defaulting to text density heuristics to filter out tracking scripts, headers, and sidebars.
Whether embedded into a legacy Blogger layout or a contemporary WordPress environment, the code deploys an isolated user interface that handles its own state, rendering it an ideal, plug and play enhancement for any content management system.
Speed Reading Widget
Copy Code
<div id="speed-reader-widget-container">
<!-- Floating Hover Button -->
<button id="sr-launcher" title="Launch Speed Reader">
<span>⚡</span>
<span class="sr-launch-text">Speed Read</span>
</button>
<!-- Reader Overlay Interface -->
<div id="sr-overlay" class="sr-hidden">
<div class="sr-modal">
<button id="sr-close" title="Close">×</button>
<!-- RSVP Display Box -->
<div class="sr-display-container">
<div id="sr-word-box">
<span class="sr-part sr-left"></span><span class="sr-part sr-center"></span><span class="sr-part sr-right"></span>
</div>
<!-- Alignment guides to aid visual focus -->
<div class="sr-guide top-guide"></div>
<div class="sr-guide bottom-guide"></div>
</div>
<!-- Controls Panel -->
<div class="sr-controls">
<button id="sr-play-btn">Play</button>
<div class="sr-wpm-container">
<label for="sr-wpm-input">WPM:</label>
<input type="number" id="sr-wpm-input" value="350" min="100" max="1000" step="25">
</div>
</div>
</div>
</div>
</div>
<style>
/* Launcher Button Styling */
#sr-launcher {
position: fixed;
right: 0;
top: 50%;
transform: translateY(-50%);
z-index: 99999;
background-color: #222;
color: #fff;
border: 1px solid #444;
border-right: none;
border-radius: 8px 0 0 8px;
padding: 12px 8px;
cursor: pointer;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
font-size: 14px;
display: flex;
align-items: center;
gap: 6px;
transition: all 0.3s ease;
box-shadow: -2px 2px 10px rgba(0,0,0,0.2);
}
#sr-launcher .sr-launch-text {
max-width: 0;
overflow: hidden;
white-space: nowrap;
transition: max-width 0.3s ease, opacity 0.2s ease;
opacity: 0;
font-weight: 500;
}
#sr-launcher:hover {
padding: 12px 16px;
background-color: #000;
}
#sr-launcher:hover .sr-launch-text {
max-width: 100px;
opacity: 1;
}
/* Overlay and Modal Canvas */
#sr-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.9);
z-index: 100000;
display: flex;
justify-content: center;
align-items: center;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
.sr-hidden {
display: none !important;
}
.sr-modal {
background-color: #1a1a1a;
color: #fff;
padding: 30px 20px;
border-radius: 12px;
width: 95%;
max-width: 500px;
position: relative;
box-shadow: 0 10px 30px rgba(0,0,0,0.7);
border: 1px solid #333;
box-sizing: border-box;
}
#sr-close {
position: absolute;
top: 10px;
right: 15px;
background: none;
border: none;
color: #888;
font-size: 24px;
cursor: pointer;
transition: color 0.2s;
}
#sr-close:hover {
color: #fff;
}
/* RSVP Text Window Engine Styles */
.sr-display-container {
position: relative;
height: 100px;
margin: 30px 0;
background-color: #0a0a0a;
border-radius: 8px;
border: 1px solid #222;
overflow: hidden;
}
/* Alignment markers */
.sr-guide {
position: absolute;
left: 40%;
width: 2px;
height: 12px;
background-color: #444;
transform: translateX(-50%);
z-index: 10;
}
.top-guide { top: 0; }
.bottom-guide { bottom: 0; }
/* Rigid letter alignment system */
#sr-word-box {
width: 100%;
height: 100%;
display: flex;
align-items: center;
font-size: 26px;
font-family: "Courier New", Courier, monospace;
font-weight: bold;
white-space: nowrap;
}
.sr-part {
display: inline-block;
white-space: pre;
}
.sr-left {
width: 40%;
text-align: right;
overflow: visible;
}
.sr-center {
color: #ff3b30;
width: auto;
text-align: center;
}
.sr-right {
width: 55%;
text-align: left;
overflow: visible;
}
/* Control Panel Layout */
.sr-controls {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #333;
padding-top: 15px;
}
#sr-play-btn {
background-color: #007bff;
color: white;
border: none;
padding: 8px 20px;
border-radius: 6px;
font-size: 15px;
cursor: pointer;
font-weight: 600;
min-width: 80px;
}
#sr-play-btn:hover {
background-color: #0056b3;
}
.sr-wpm-container {
display: flex;
align-items: center;
gap: 8px;
color: #ccc;
font-size: 14px;
}
#sr-wpm-input {
background-color: #222;
border: 1px solid #444;
color: #fff;
padding: 6px;
border-radius: 6px;
width: 70px;
font-size: 14px;
text-align: center;
}
</style>
<script>
(function() {
const CONTENT_SELECTORS = [
'.post-body',
'.entry-content',
'article',
'[itemprop="articleBody"]',
'main',
'.main-content'
];
let wordsArray = [];
let currentIndex = 0;
let isPlaying = false;
let speedTimeout = null;
const launcher = document.getElementById('sr-launcher');
const overlay = document.getElementById("sr-overlay");
const closeBtn = document.getElementById('sr-close');
const playBtn = document.getElementById('sr-play-btn');
const wpmInput = document.getElementById('sr-wpm-input');
const partLeft = overlay.querySelector('.sr-left');
const partCenter = overlay.querySelector('.sr-center');
const partRight = overlay.querySelector('.sr-right');
function extractMainText() {
let targetElement = null;
for (const selector of CONTENT_SELECTORS) {
const element = document.querySelector(selector);
if (element && element.innerText.trim().length > 150) {
targetElement = element;
break;
}
}
if (!targetElement) {
const paragraphs = document.getElementsByTagName('p');
if (paragraphs.length > 0) {
let bestContainer = null;
let maxTextLength = 0;
for (let p of paragraphs) {
const parent = p.parentElement;
if (parent) {
const length = parent.innerText.trim().length;
if (length > maxTextLength) {
maxTextLength = length;
bestContainer = parent;
}
}
}
targetElement = bestContainer || document.body;
} else {
targetElement = document.body;
}
}
const clone = targetElement.cloneNode(true);
// Remove the widget itself
const widgetInsideClone = clone.querySelector('#speed-reader-widget-container');
if (widgetInsideClone) {
widgetInsideClone.remove();
}
// Aggressively strips styles, scripts, UI elements, code blocks, and headings safely
const badElements = clone.querySelectorAll('style, script, noscript, iframe, button, input, textarea, select, pre, code, h1, h2, h3, h4, h5, h6, span, .tr-caption, figcaption');
badElements.forEach(block => block.remove());
// Inject trailing spaces into block boundaries to avoid word collision on extraction
const blockElements = clone.querySelectorAll('p, li, div, br');
blockElements.forEach(el => {
el.appendChild(document.createTextNode(' '));
});
const text = clone.innerText || clone.textContent || "";
// Strip common punctuation marks upfront now that boundaries are clean
const cleanText = text.replace(/[.,!?:;-]/g, "");
return cleanText
.replace(/\s+/g, ' ')
.trim()
.split(' ')
.filter(word => word.length > 0);
}
function renderWord(word) {
if (!word) {
partLeft.textContent = '';
partCenter.textContent = '';
partRight.textContent = '';
return;
}
const len = word.length;
let midIndex = 0;
if (len <= 1) {
midIndex = 0;
} else if (len <= 5) {
midIndex = 1;
} else if (len <= 9) {
midIndex = 2;
} else if (len <= 13) {
midIndex = 3;
} else {
midIndex = 4;
}
partLeft.textContent = word.substring(0, midIndex);
partCenter.textContent = word.charAt(midIndex);
partRight.textContent = word.substring(midIndex + 1);
}
function getDelay() {
const wpm = parseInt(wpmInput.value, 10) || 350;
return 60000 / wpm;
}
function tick() {
if (!isPlaying) return;
if (currentIndex >= wordsArray.length) {
pauseReader();
currentIndex = 0;
return;
}
renderWord(wordsArray[currentIndex]);
currentIndex++;
speedTimeout = setTimeout(tick, getDelay());
}
function playReader() {
if (wordsArray.length === 0) return;
isPlaying = true;
playBtn.textContent = 'Pause';
tick();
}
function pauseReader() {
isPlaying = false;
playBtn.textContent = 'Play';
if (speedTimeout) clearTimeout(speedTimeout);
}
launcher.addEventListener('click', () => {
wordsArray = extractMainText();
if (wordsArray.length === 0) {
alert('Could not parse text content from this page.');
return;
}
overlay.classList.remove('sr-hidden');
renderWord(wordsArray[currentIndex]);
});
closeBtn.addEventListener('click', () => {
pauseReader();
overlay.classList.add('sr-hidden');
});
playBtn.addEventListener('click', () => {
if (isPlaying) {
pauseReader();
} else {
playReader();
}
});
window.addEventListener('keydown', (e) => {
if (overlay.classList.contains('sr-hidden')) return;
if (e.key === ' ') {
e.preventDefault();
playBtn.click();
} else if (e.key === 'Escape') {
closeBtn.click();
}
});
})();
</script>
Notice:
Comments are moderated and may not appear immediately. Please keep your comments respectful, and relevant to the post. Spam will not be tolerated. My site. My rules.