Skip to content

Instantly share code, notes, and snippets.

@KoljaL
Created January 22, 2026 12:03
Show Gist options
  • Select an option

  • Save KoljaL/af7bf982e658024359446db2923d67d4 to your computer and use it in GitHub Desktop.

Select an option

Save KoljaL/af7bf982e658024359446db2923d67d4 to your computer and use it in GitHub Desktop.
The bookmarklet allows users to quickly access speed reading functionality directly from their web browser
javascript:(function(){const DEFAULT_WPM=300,RAMP_ENABLED=!0,RAMP_START_WPM=120,RAMP_DURATION=2e3;let words=[],index=0,wpm=DEFAULT_WPM,rampStartTime=null,state="PAUSED",timer=null,overlay=document.createElement("div");overlay.id="rsvpOverlay",Object.assign(overlay.style,{position:"fixed",top:0,left:0,width:"100%",height:"100%",background:"rgba(0,0,0,0.9)",display:"flex",justifyContent:"space-around",alignItems:"center",flexDirection:"column",zIndex:9999,color:"#fff",fontSize:"3em",textAlign:"center"}),document.body.appendChild(overlay);const wordEl=document.createElement("div");overlay.appendChild(wordEl);const controls=document.createElement("div");controls.style.marginTop="20px",controls.style.display="flex",controls.style.alignItems="center",controls.style.flexDirection="column",controls.style.gap="10px",overlay.appendChild(controls);const speedInput=document.createElement("input");speedInput.type="range",speedInput.min=100,speedInput.max=1e3,speedInput.value=DEFAULT_WPM,speedInput.style.margin="0 10px",controls.appendChild(speedInput);const playBtn=document.createElement("button");playBtn.textContent="Play",playBtn.style.fontSize="1em",playBtn.style.color="hsl(0, 3.1%, 38.4%)",playBtn.style.background="hsl(0, 0%, 16.9%)",playBtn.style.border="none",controls.appendChild(playBtn);const closeBtn=document.createElement("button");closeBtn.textContent="Close",closeBtn.style.fontSize="1em",playBtn.style.color="hsl(0, 3.1%, 38.4%)",playBtn.style.background="hsl(0, 0%, 16.9%)",playBtn.style.border="none",controls.appendChild(closeBtn);const selection=window.getSelection().toString().trim();if(!selection)return alert("Please select some text first!"),void document.body.removeChild(overlay);words=selection.replace(/\s+/g," ").split(" ").filter(w=>w.length>0),wordEl.textContent=words[0];function showNextWord(t){if("PLAYING"!==state)return;let e=6e4/wpm;if(RAMP_ENABLED&&rampStartTime){const n=t-rampStartTime,a=Math.min(n/RAMP_DURATION,1),o=RAMP_START_WPM+a*(DEFAULT_WPM-RAMP_START_WPM);e=6e4/o}wordEl.textContent=words[index],index++,index>=words.length?(state="FINISHED",playBtn.textContent="Play"):timer=setTimeout(()=>requestAnimationFrame(showNextWord),e)}playBtn.onclick=()=>{"PAUSED"!==state&&"FINISHED"!==state?(state="PAUSED",playBtn.textContent="Play",clearTimeout(timer)):(state="PLAYING",playBtn.textContent="Pause",rampStartTime=performance.now(),showNextWord(rampStartTime))},speedInput.oninput=()=>{wpm=parseInt(speedInput.value)},closeBtn.onclick=()=>{clearTimeout(timer),document.body.removeChild(overlay)}})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment