Arc Picker
Option list laid out along a curved arc with a bracketed selection. Switch the arc side, then scroll, click or use arrow keys.
Preview and code
index.html
<div class="ap" tabindex="0"><div class="sd"><button data-s="top" type="button">Top</button><button data-s="bottom" type="button">Bottom</button><button data-s="left" type="button">Left</button><button data-s="right" class="on" type="button">Right</button></div><div class="st"></div></div>
styles.css
.ap{position:relative;width:100%;height:100%;min-height:380px;overflow:hidden;outline:0;font-family:system-ui,-apple-system,sans-serif;color:#eee;}.sd{position:absolute;top:14px;left:50%;transform:translateX(-50%);display:flex;gap:2px;background:#161616;border:1px solid #2a2a2a;border-radius:99px;padding:3px;z-index:2}.sd button{border:0;background:none;color:#888;font:500 11px system-ui;padding:6px 10px;border-radius:99px;cursor:pointer}.sd .on{background:#262626;color:#fff}.st{position:absolute;left:50%;top:55%}.ai{position:absolute;left:0;top:0;white-space:nowrap;font-size:15px;color:#999;cursor:pointer;transition:transform .45s cubic-bezier(.3,1.2,.5,1),opacity .3s,color .2s;padding:3px 6px}.ai.on{color:#0a84ff}.ai.on:before{content:"[ ";opacity:.8}.ai.on:after{content:" ]";opacity:.8}
script.js
(function(){var R=document.querySelector(".ap"),st=R.querySelector(".st"),W=["Early","Sunrise","Morning","Midday","Noon","Afternoon","Golden hour","Sunset","Dusk","Evening","Night"],a=6,side="right",Rr=260;var els=W.map(function(w,i){var e=document.createElement("div");e.className="ai";e.textContent=w;e.onclick=function(){a=i;lay()};st.appendChild(e);return e});function lay(){els.forEach(function(e,i){var k=i-a,d=k*34,g=Math.asin(Math.max(-.97,Math.min(.97,d/Rr))),cr=Rr*(1-Math.cos(g)),dg=g*180/Math.PI,x,y,rot,an,org;if(side==="right"){x=cr-60;y=d;rot=dg;an="translate(0,-50%)";org="0 50%"}else if(side==="left"){x=-cr+60;y=d;rot=-dg;an="translate(-100%,-50%)";org="100% 50%"}else if(side==="top"){x=d;y=cr-90;rot=dg;an="translate(-50%,-50%)";org="50% 50%"}else{x=d;y=-cr+90;rot=-dg;an="translate(-50%,-50%)";org="50% 50%"}e.style.transformOrigin=org;e.style.transform="translate("+x+"px,"+y+"px) "+an+" rotate("+rot+"deg)";e.style.opacity=Math.abs(k)>5?0:Math.max(.15,1-Math.abs(k)*.16);e.classList.toggle("on",k===0)})}[].forEach.call(R.querySelectorAll(".sd button"),function(b){b.onclick=function(){side=b.getAttribute("data-s");[].forEach.call(R.querySelectorAll(".sd button"),function(x){x.classList.toggle("on",x===b)});lay()}});var t=0;R.onwheel=function(e){e.preventDefault();if(Date.now()-t<80)return;t=Date.now();a=Math.max(0,Math.min(W.length-1,a+(e.deltaY>0?1:-1)));lay()};R.onkeydown=function(e){if(e.key==="ArrowDown"||e.key==="ArrowRight")a=Math.min(W.length-1,a+1);else if(e.key==="ArrowUp"||e.key==="ArrowLeft")a=Math.max(0,a-1);else return;e.preventDefault();lay()};lay()})();