- let val = 0, min = 0, max = 180;
- let nst = 4, dif = max/nst;

body(style=`--a: ${val}`)
	form.sec
		label(for='a') Start angle:
		input#a(type='range' min=min max=max value=val)
		output(for='a')
		.button
			- for(let i = 0; i <= nst; i++)
				input(type='button' class=i === val ? 'hl' : null value=i*dif)
	section#result
	pre.sec
		span.token--func repeating-conic-gradient
		span.token--punc (
		span.token--args
			span.token--arg.token--ini
				span.token--keyw from
				|  
				span.token--ang
					span.token--num
					span.token--unit deg
			span.token--punc ,
			|  
			span.token--arg.token--stop
				span.token--col.span.token--hex #000
				|  
				span.token--list.token--pos
					span.token--item.token--perc
						span.token--num 0
						span.token--unit %
					|  
					span.token--item.token--perc
						span.token--num 25
						span.token--unit %
			span.token--punc ,
			|  
			span.token--arg.token--stop
				span.token--col.span.token--hex #eee
				|  
				span.token--list.token--pos
					span.token--item.token--perc
						span.token--num 0
						span.token--unit %
					|  
					span.token--item.token--perc
						span.token--num 50
						span.token--unit %
		span.token--punc )
View Compiled
$sec-pad: .5em;
$btn-dim: 2em;
$b-arrow: .75*$sec-pad;

$track-w: 15em;
$track-h: .25em;
$track-r: .5*$track-h;

$thumb-d: 1em;
$thumb-r: .5*$thumb-d;

$mover-w: $track-w - $thumb-d;

$c: #fe7e10 #cc7aff #ff67b0 #ffd401 #87c830;
$s: 9em;
$l: 2px;

@mixin track() {
	border: none;
	width: $track-w; height: $track-h;
	border-radius: $track-r;
	background: currentcolor;
}

@mixin thumb($f: 0) {
	margin-top: $f*($track-r - $thumb-r);
	border: none;
	width: $thumb-d; height: $thumb-d;
	border-radius: 50%;
	background: nth($c, 1);
	transition: all calc(var(--f)*2s)
}

* {
	box-sizing: inherit;
	margin: 0;
	padding: 0;
	background: none;
	color: inherit;
	font: inherit
}

body {
	--i: var(--wide, 1);
	--not-i: calc(1 - var(--i));
	display: grid;
	grid-template-rows: max-content 1fr max-content;
	overflow-x: hidden;
	min-width: 205px; height: 100vh;
	background: #222;
	color: #eee;
	font: 1.25em/ 1.5 consolas, ubuntu mono, monaco, monospace;
	transition: --a calc(var(--f)*2s) ease-out;
	counter-reset: a var(--a);
	
	@media (max-width: 715px) {
		.token--arg:nth-child(3)::before { content: '\A     ' }
	}
	
	@media (max-width: 605px) { --wide: 0 }
	
	@media (max-width: 435px) {
		.token--arg:nth-child(1)::before { content: '\A     ' }
	}
	
	@media (max-width: 340px) { font-size: 1em }
	@media (max-width: 275px) { font-size: .875em }
	@media (max-width: 240px) { font-size: .75em }
}

.sec {
	--focus: 0;
	--not-focus: calc(1 - var(--focus));
	padding: $sec-pad;
}

form {
	display: grid;
	grid-template-columns: 1fr $track-w 1fr;
	grid-gap: $sec-pad;
	filter: grayScale(var(--not-focus));
	
	&:focus-within {
		&, & ~ .sec { --focus: 1 }
	}
}

label {
	grid-column: calc(1 + var(--not-i));
	place-self: center var(--wide, end)
}

input {
	cursor: pointer;
	
	&[type='range'] {
		&, &::-webkit-slider-thumb, 
		&::-webkit-slider-runnable-track { -webkit-appearance: none }
		
		grid-column: 2;
		grid-row: calc(1 + var(--not-i));
		
		&::-webkit-slider-runnable-track {
			@include track()
		}
		
		&::-moz-range-track {
			@include track()
		}
		
		&::-webkit-slider-thumb {
			@include thumb(1)
		}
		
		&::-moz-range-thumb {
			@include thumb()
		}
		
		&:focus { outline: solid 0 transparent }
	}
	
	&[type='button'] {
		--hlight: 0;
		--select: 0;
		border: solid 1px #eee;
		width: $btn-dim;
		border-radius: 5px;
		background: 
			rgba(nth($c, 1), 
					 calc(var(--select) + .875*var(--hlight)));
		color: HSL(0, 0%, calc(100%*(1 - (var(--select) + var(--hlight)))));
				
		&:focus { outline: none }
		&:hover, &:focus { --hlight: 1 }
	}
	
	&.hl { --select: 1 }
}

output {
	grid-column: calc(3 - var(--not-i));
	grid-row: calc(1 + var(--not-i));
	place-self: start;
	transform: 
		translate(calc(var(--not-i)*(#{$thumb-r} + var(--a)/180*#{$mover-w} - 50%)), 
							calc(var(--not-i)*(#{1.5*$b-arrow} - 100%)));
	
	&::after {
		display: block;
		border: solid $b-arrow transparent;
		padding: 0 .25em;
		border-radius: calc(#{$b-arrow} + 3px);
		transform-origin: 50% 100%;
		transform: scale(calc(var(--i) + var(--not-i)*var(--focus)));
		background: nth($c, 1) border-box;
		color: #222;
		text-align: center;
		--xy: calc(var(--not-i)*50%) calc(50%*(1 + var(--not-i)));
		--mask:
			linear-gradient(red, red) padding-box, 
			conic-gradient(
					from calc(45deg - var(--not-i)*90deg) 
					at var(--xy), 
					red 0% 25%, transparent 0%) 
				var(--xy)/ 50% 50% no-repeat border-box;
		-webkit-mask: var(--mask);
						mask: var(--mask);
		transition: transform .3s, filter .3s;
		content: counter(a)'°'
	}
}

.button {
	grid-column: 2;
	display: flex;
	justify-content: space-between;
	margin: 0 calc(#{$thumb-r} - #{.5*$btn-dim})
}

#result {
	--line: #{nth($c, 1)} 0 #{.5*$l}, 
					transparent 0 calc(100% - #{.5*$l}), 
					#{nth($c, 1)};
	background: 
		linear-gradient(var(--line)), 
		linear-gradient(90deg, var(--line)), 
		repeating-conic-gradient(from calc(var(--a)*1deg), 
				#000 0% 25%, #eee 0% 50%);
	background-position: 50%;
	background-size: $s $s
}

.token {
	&--func { color: nth($c, 1) }
	
	&--keyw { color: nth($c, 2) }
	
	&--ang {
		display: inline-block;
		position: relative;
		padding: 0 .25em;
		vertical-align: bottom;
		color: nth($c, 3);
		
		&::before {
			position: absolute;
			top: 1px; right: 0; bottom: 0; left: 0;
			background: currentcolor;
			--rect: inset(0 calc(var(--not-focus)*100%) 0 0 round 5px);
			-webkit-clip-path: var(--rect);
							clip-path: var(--rect);
			mix-blend-mode: difference;
			transition: .5s 
				cubic-bezier(calc(var(--focus)*.42), 0, calc(var(--not-focus)*.58), 1);
			content: ''
		}
	}
	
	&--hex { color: nth($c, 4) }
	
	&--perc { color: nth($c, 5) }
	
	&--ang &--num::after { content: counter(a) }
	
	&--arg::before { white-space: pre }
}
View Compiled
const _B = document.body, 
			_A = document.getElementById('a'), 
			MX = +_A.max, 
			COND = CSS.registerProperty;

let _hl = _B.querySelector('.hl'), 
		prv = +_A.value, rID = null, 
		pressed = false, updating = false;

function update() {
	_A.value = +getComputedStyle(_B).getPropertyValue('--a');
	rID = requestAnimationFrame(update)
};

_A.addEventListener('input', e => {
	let val = +_A.value, 
			_eq = _B.querySelector(`[type='button'][value='${val}']`);
	
	_B.style.setProperty('--f', +(Math.abs(prv - val)/MX).toFixed(2));
	_B.style.setProperty('--a', prv = val);
	
	if(_eq) {
		_hl = _eq;
		_hl.classList.add('hl')
	}
	else if(_hl) {
		_hl.classList.remove('hl');
		_hl = null
	}
}, false);

addEventListener('click', e => {
	let _tg = e.target;
	
	if(_tg.type && _tg.type === 'button') {
		let val = +_tg.value;
		
		_B.style.setProperty('--f', +(Math.abs(prv - val)/MX).toFixed(2));
		_B.style.setProperty('--a', prv = val);
		
		if(_hl) _hl.classList.remove('hl');
		_hl = _tg;
		_hl.classList.add('hl');
		
		if(!COND || pressed) _A.value = val
	}
}, false);

_A.addEventListener('mousedown', e => { pressed = true }, false);
_A.addEventListener('mouseup', e => {
	pressed = false;
	if(updating) update();
}, false);

addEventListener('transitionstart', e => {
	updating = true;
	if(!pressed) update()
}, false);

addEventListener('transitionend', e => {
	updating = false;
	cancelAnimationFrame(rID);
	rID = null
}, false);

if(COND) {
	CSS.registerProperty({
		name: '--a', 
		syntax: '<integer>',
		initialValue: +_A.value, 
		inherits: true
	})
}
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.