About
parkrun Stopwatch Bingo visualises the unofficial stopwatch bingo challenge on a parkrunner’s all-results page (e.g. parkrunner A4886000).
Challenge rules
Each finish contributes the seconds portion of the finish time (00–59), from MM:SS or HH:MM:SS. Results are read oldest-first; the first hit for each second is kept. The challenge is complete when all 60 seconds are collected.
What you see
A clock-style display of collected seconds. Segment length reflects how often each second appears. Click a segment for finish details.
Save as Image downloads a square tile sized for sharing on social media, including activity sites such as Strava.
Version 1.2.2 Updated
Screenshot
Install
Recommended: userscript. Bookmarklet works where a userscript manager isn’t available.
Userscript (recommended)
Install parkrun Stopwatch Bingo
First time? Userscript basics and installation steps
What is a userscript?
A userscript is a small piece of JavaScript that runs in your browser and enhances specific websites. These scripts work with parkrun event pages, parkrunner profile pages, and results pages, and can be used with any userscript manager including Userscripts, Tampermonkey, Violentmonkey, or any compatible browser extension.
Installation steps
-
Install a userscript manager for your browser:
- Desktop: Userscripts (Safari), Tampermonkey (Chrome, Firefox, Edge, Opera), or Violentmonkey (Orion)
- iOS: Userscripts (Safari) or Violentmonkey (Orion)
- Android: Install Kiwi Browser, then install Tampermonkey or Violentmonkey from the Chrome Web Store.
- Click the Install button above for this script.
- Click “Install” when prompted by your userscript manager.
Bookmarklet
A bookmarklet is a bookmark whose URL is JavaScript. Use it on browsers that support bookmarks but not userscript managers.
Drag this link to your bookmarks bar:
parkrun Stopwatch Bingo bookmarklet
Mobile bookmarklet setup and full code
Mobile bookmarklet
On mobile browsers that let you edit bookmark URLs:
- Copy the JavaScript code below to your clipboard.
- Create a new bookmark for any page.
- Edit the bookmark and replace its URL with the code you copied.
- Navigate to the relevant parkrun page.
- Select the bookmark to run the script.
javascript:(()=>{var k={backgroundColor:"#2b223d",clockBorderColor:"#FFA300",clockFaceColor:"#333",completedColor:"#FFA300",textColor:"#e0e0e0",subtleTextColor:"#cccccc"};function o(){var t=document.querySelectorAll("#results");return t[t.length-1]}function n(t){for(var e={},o={},n=0,l=0,r=null,a=null,t=t.querySelectorAll("tr"),i=[],c=(t.forEach(function(t){t=t.querySelectorAll("td");if(!(t.length<5)){var e=t[0].textContent.trim(),o=t[1].textContent.trim(),n=t[2].textContent.trim(),t=t[4].textContent.trim();if(t&&n&&o&&e){var l,e="".concat(e," # ").concat(n),n=t.match(/(\d+):(\d+):(\d+)/);if(n)l=parseInt(n[3],10);else{n=t.match(/(\d+):(\d+)/);if(!n)return;l=parseInt(n[2],10)}i.push({secondValue:l,date:o,event:e,time:t})}}}),i.reverse()),d=0;d<c.length;d++){var s=c[d],p=s.secondValue,u=s.date,m=s.event,s=s.time;if(l++,!(p in e||(e[p]={date:u,event:m,time:s},60!=++n)||a)){o[p]=[{date:a=u,event:r=m,time:s}];break}o[p]||(o[p]=[]),o[p].push({date:u,event:m,time:s})}return{seconds:e,timeData:o,collectedCount:n,totalParkruns:l,dateOfCompletion:a,firstCompleteEvent:r}}function l(g){t="Stopwatch Bingo Challenge",(o=document.createElement("div")).id||(o.id="stopwatchBingoContainer"),o.className="parkrun-bingo-container",o.style.width="100%",o.style.maxWidth="800px",o.style.margin="20px auto",o.style.padding=window.innerWidth<768?"10px":"20px",o.style.backgroundColor=k.backgroundColor,o.style.borderRadius="8px",o.style.boxShadow="0 2px 4px rgba(0,0,0,0.1)",o.style.textAlign="center",(e=document.createElement("h3")).textContent=t,e.style.marginBottom="15px",e.style.color=k.clockBorderColor,e.style.fontSize=window.innerWidth<768?"1.1em":"1.3em",o.appendChild(e);var t=o,e=window.innerWidth<768,o=document.createElement("div");o.style.marginBottom=e?"10px":"20px",o.style.color=k.textColor;for(var n=e?"0.95em":"1.1em",l='<div style="font-size: '.concat(e?"1em":"1.2em",'; margin-bottom: 10px;"><strong>').concat(g.collectedCount," of 60</strong> seconds collected</div>"),x=(l+='<div style="font-size: '.concat(e?"0.9em":"1em",';">After ').concat(g.totalParkruns," parkruns</div>"),g.dateOfCompletion&&(l+='<div style="margin-top: 10px; font-size: '.concat(n,';">🏆 Bingo completed on ').concat(g.dateOfCompletion," (").concat(g.firstCompleteEvent,")</div>")),o.innerHTML=l,t.appendChild(o),e?Math.min(320,window.innerWidth-40):500),b=x/500,C=document.createElement("div"),f=(C.style.position="relative",C.style.width="".concat(x,"px"),C.style.height="".concat(x,"px"),C.style.margin="0 auto",C.style.borderRadius="50%",C.style.border="".concat(Math.round(10*b),"px solid ").concat(k.clockBorderColor),C.style.backgroundColor=k.clockFaceColor,C.style.boxSizing="content-box",1),r=0;r<60;r++){var a=g.timeData[r]?g.timeData[r].length:0;f<a&&(f=a)}for(var i=function(i){if(!(i in g.seconds))return 1;var t=g.timeData[i]?g.timeData[i].length:0,e=((i-.4)/60*360-90)*(Math.PI/180),o=Math.PI/180*((i+.4)/60*360-90),n=document.createElement("div"),l=(n.style.position="absolute",n.style.top="0",n.style.left="0",n.style.width="100%",n.style.height="100%",n.style.pointerEvents="none",220*b),r=50*b,a=x/2,c=x/2,d=document.createElementNS("http://www.w3.org/2000/svg","svg"),s=(d.setAttribute("width","100%"),d.setAttribute("height","100%"),d.style.position="absolute",d.style.top="0",d.style.left="0",d.style.zIndex="1",document.createElementNS("http://www.w3.org/2000/svg","path")),l=r+Math.max(0,Math.round(t/f*(l-r))),p=a+r*Math.cos(e),u=c+r*Math.sin(e),m=a+l*Math.cos(e),e=c+l*Math.sin(e),y=a+l*Math.cos(o),h=c+l*Math.sin(o),a=a+r*Math.cos(o),c=c+r*Math.sin(o),o=["M ".concat(p,",").concat(u),"L ".concat(m,",").concat(e),"A ".concat(l,",").concat(l," 0 0,1 ").concat(y,",").concat(h),"L ".concat(a,",").concat(c),"A ".concat(r,",").concat(r," 0 0,0 ").concat(p,",").concat(u),"Z"].join(" ");s.setAttribute("d",o),s.setAttribute("fill",k.completedColor),s.setAttribute("opacity","1"),s.setAttribute("title","".concat(i.toString().padStart(2,"0")," Seconds - ").concat(t," ").concat(1===t?"Time":"Times")),s.style.cursor="pointer",s.style.pointerEvents="auto",s.addEventListener("click",function(){var t,e,o,n,l,r,a;t=i,e=g.timeData[i],(o=document.getElementById("second-details-popup"))&&o.remove(),(n=document.createElement("div")).id="second-details-popup",n.style.position="fixed",n.style.top="50%",n.style.left="50%",n.style.transform="translate(-50%, -50%)",n.style.width="400px",n.style.maxHeight="500px",n.style.overflowY="auto",n.style.backgroundColor=k.backgroundColor,n.style.borderRadius="8px",n.style.padding="20px",n.style.boxShadow="0 0 20px rgba(0, 0, 0, 0.5)",n.style.zIndex="1000",n.style.color=k.textColor,(o=document.createElement("div")).textContent="✕",o.style.position="absolute",o.style.top="10px",o.style.right="15px",o.style.fontSize="20px",o.style.cursor="pointer",o.addEventListener("click",function(){return n.remove()}),n.appendChild(o),(o=document.createElement("h3")).textContent="".concat(t.toString().padStart(2,"0")," Seconds - ").concat(e.length," Times"),o.style.marginBottom="15px",o.style.color=k.clockBorderColor,n.appendChild(o),(t=document.createElement("table")).style.width="100%",t.style.borderCollapse="collapse",t.style.marginTop="10px",o=document.createElement("thead"),l=document.createElement("tr"),[{title:"Date",align:"left"},{title:"Event",align:"left"},{title:"Time",align:"left"}].forEach(function(t){var e=document.createElement("th");e.textContent=t.title,e.style.textAlign=t.align,e.style.padding="8px",e.style.borderBottom="1px solid #555",l.appendChild(e)}),o.appendChild(l),t.appendChild(o),r=document.createElement("tbody"),e.forEach(function(t,e){var o=document.createElement("tr"),e=(o.style.backgroundColor=0===e?"rgba(255, 163, 0, 0.2)":"transparent",[{content:t.date},{content:t.event},{content:t.time}].map(function(t){return'<td style="padding: 8px; border-bottom: 1px solid #444;">'.concat(t.content,"</td>")}).join(""));o.innerHTML=e,r.appendChild(o)}),t.appendChild(r),n.appendChild(t),document.body.appendChild(n),(a=document.createElement("div")).style.position="fixed",a.style.top="0",a.style.left="0",a.style.width="100%",a.style.height="100%",a.style.backgroundColor="rgba(0, 0, 0, 0.5)",a.style.zIndex="999",a.addEventListener("click",function(){n.remove(),a.remove()}),document.body.appendChild(a)}),d.appendChild(s),n.appendChild(d),C.appendChild(n)},c=0;c<60;c++)i(c);var d=document.createElementNS("http://www.w3.org/2000/svg","svg");d.setAttribute("width","100%"),d.setAttribute("height","100%"),d.style.position="absolute",d.style.top="0",d.style.left="0",d.style.pointerEvents="none",d.style.zIndex="2";for(var s=0;s<60;s+=5){var p=(s/60*360-90)*(Math.PI/180),u=245*b,m=(s%15==0?210:225)*b,y=x/2,h=x/2,v=document.createElementNS("http://www.w3.org/2000/svg","line"),u=(v.setAttribute("x1",y+m*Math.cos(p)),v.setAttribute("y1",h+m*Math.sin(p)),v.setAttribute("x2",y+u*Math.cos(p)),v.setAttribute("y2",h+u*Math.sin(p)),v.setAttribute("stroke",k.textColor),v.setAttribute("stroke-width",(s%15==0?3:2)*b),d.appendChild(v),m-(s%15==0?25:20)*b),v=y+u*Math.cos(p),m=h+u*Math.sin(p),y=document.createElementNS("http://www.w3.org/2000/svg","text");y.setAttribute("x",v),y.setAttribute("y",m),y.setAttribute("fill",k.textColor),y.setAttribute("font-size","".concat((s%15==0?16:14)*b,"px")),y.setAttribute("font-weight","bold"),y.setAttribute("text-anchor","middle"),y.setAttribute("dominant-baseline","middle"),y.textContent=s.toString(),d.appendChild(y)}C.appendChild(d);var w,E,n=document.createElement("div"),n=(n.style.position="absolute",n.style.top="50%",n.style.left="50%",n.style.transform="translate(-50%, -50%)",n.style.width="".concat(100*b,"px"),n.style.height="".concat(100*b,"px"),n.style.borderRadius="50%",n.style.backgroundColor=k.clockBorderColor,n.style.display="flex",n.style.justifyContent="center",n.style.alignItems="center",n.style.color=k.backgroundColor,n.style.fontWeight="bold",n.style.fontSize="".concat(20*b,"px"),n.style.zIndex="3",n.textContent="".concat(Math.round(g.collectedCount/60*100),"%"),C.appendChild(n),t.appendChild(C),w=t,l=window.innerWidth<768,(o=document.createElement("div")).style.marginTop=l?"10px":"15px",o.id="bingo-download-btn-container",(E=document.createElement("button")).textContent="💾 Save as Image",E.style.padding=l?"6px 12px":"8px 15px",E.style.backgroundColor=k.clockBorderColor,E.style.color=k.backgroundColor,E.style.border="none",E.style.borderRadius="4px",E.style.cursor="pointer",E.style.fontWeight="bold",E.style.fontSize=l?"0.9em":"1em",E.addEventListener("mouseover",function(){this.style.backgroundColor="#e59200"}),E.addEventListener("mouseout",function(){this.style.backgroundColor=k.clockBorderColor}),E.addEventListener("click",function(){E.style.display="none",html2canvas(w,{backgroundColor:k.backgroundColor,scale:2,logging:!1,allowTaint:!0,useCORS:!0}).then(function(t){E.style.display="block";var e=document.createElement("a"),o=(new Date).toISOString().split("T")[0],n=window.location.pathname.split("/")[2]||"parkrunner";e.download="stopwatch-bingo-".concat(n,"-").concat(o,".png"),e.href=t.toDataURL("image/png"),e.click()})}),o.appendChild(E),w.appendChild(o),document.createElement("div"));return n.style.marginTop=e?"10px":"20px",n.style.color=k.subtleTextColor,n.style.fontSize=e?"0.8em":"0.9em",n.style.padding=e?"0 5px":"0",n.innerHTML="Stopwatch Bingo: collect finish times with every second from 00-59.<br>Orange segments show seconds you've collected. Segment length indicates frequency.<br>Click on any segment to see details.",t.appendChild(n),t}function t(){var t,e;document.querySelector("#results")?document.querySelector("h2")&&(t=l(n(o())),t=t,e=document.querySelector("h2"))&&e.parentNode&&(e.nextSibling?e.parentNode.insertBefore(t,e.nextSibling):e.parentNode.appendChild(t)):console.log("Results table not found")}"undefined"!=typeof module&&module.exports?module.exports={findResultsTable:o,extractFinishTimes:n}:t()})();