160 lines
3.8 KiB
HTML
160 lines
3.8 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Generic STFX UI</title>
|
|
<style>
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
body {
|
|
display: grid;
|
|
grid-template-areas: "header" "params";
|
|
grid-template-rows: 3em 1fr;
|
|
|
|
margin: 0;
|
|
padding: 0;
|
|
width: 100vw;
|
|
max-width: 100vw;
|
|
height: 100vh;
|
|
max-height: 100vh;
|
|
overflow: hidden;
|
|
|
|
background: linear-gradient(#FFF, #EEE, #CCC);
|
|
color: #000;
|
|
|
|
text-align: center;
|
|
word-wrap: break-word;
|
|
font-family: Bahnschrift, 'DIN Alternate', 'Alte DIN 1451 Mittelschrift', 'D-DIN', 'OpenDin', 'Clear Sans', 'Barlow', 'Abel', 'Franklin Gothic Medium', system-ui, sans-serif;
|
|
|
|
/* no text selectable by default */
|
|
user-select: none;
|
|
}
|
|
output {
|
|
font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace;
|
|
font-weight: normal;
|
|
color: #000;
|
|
}
|
|
|
|
#header {
|
|
grid-area: header;
|
|
display: flex;
|
|
justify-content: center;
|
|
}
|
|
#params {
|
|
grid-area: params;
|
|
display: flex;
|
|
align-content: space-around;
|
|
justify-content: space-evenly;
|
|
flex-wrap: wrap;
|
|
|
|
padding: 1rem;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.param-range {
|
|
display: grid;
|
|
width: 3.5rem;
|
|
grid-template-areas: "dial" "name";
|
|
grid-template-rows: 3.5rem 1fr;
|
|
}
|
|
.param-range-value {
|
|
position: relative;
|
|
grid-area: dial;
|
|
|
|
width: 3.5rem;
|
|
height: 3.5rem;
|
|
}
|
|
.param-range-dial {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
z-index: -1;
|
|
}
|
|
.param-range-text {
|
|
position: absolute;
|
|
top: 30%;
|
|
left: 0;
|
|
width: 100%;
|
|
}
|
|
.param-range-units {
|
|
position: absolute;
|
|
top: 60%;
|
|
left: 0;
|
|
width: 100%;
|
|
|
|
color: #666;
|
|
font-size: 0.85rem;
|
|
}
|
|
.param-range-name {
|
|
grid-area: name;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1 id="header">{name}</h1>
|
|
<section id="params">
|
|
<template @foreach>
|
|
<label class="param-range" @if="${d => d.$type == 'ParamRange'}">
|
|
<div class="param-range-name">{name}</div>
|
|
<script>
|
|
function move(data, dx, dy) {
|
|
data.rangeUnit = Math.min(1, Math.max(0, data.rangeUnit - dy/250));
|
|
}
|
|
function press(data, count) {
|
|
if (count == 2) data.value = data.defaultValue;
|
|
}
|
|
</script>
|
|
<div class="param-range-value" $move="${move}" $press="${press}">
|
|
<canvas class="param-range-dial" $update="${drawDial}"></canvas>
|
|
<output class="param-range-text">{text}</output><br>
|
|
<div class="param-range-units">{textUnits}</div>
|
|
</div>
|
|
</label>
|
|
</template>
|
|
</section>
|
|
<script>
|
|
function drawDial(data, canvas) {
|
|
let scale = window.devicePixelRatio;
|
|
let pixels = canvas.offsetWidth*scale;
|
|
if (canvas.width != pixels) canvas.width = pixels;
|
|
if (canvas.height != pixels) canvas.height = pixels;
|
|
|
|
let context = canvas.getContext('2d');
|
|
context.resetTransform();
|
|
context.clearRect(0, 0, pixels, pixels);
|
|
|
|
context.scale(pixels/2, pixels/2);
|
|
context.translate(1, 1);
|
|
|
|
context.beginPath();
|
|
context.ellipse(0, 0, 1, 1, 0, 0, Math.PI*2);
|
|
context.fillStyle = '#FFF';
|
|
context.fill();
|
|
|
|
context.beginPath();
|
|
context.ellipse(0, 0, 0.9, 0.9, 0, Math.PI*-1.25, Math.PI*(-1.249 + data.rangeUnit*1.499));
|
|
context.strokeStyle = '#000';
|
|
context.lineWidth = 0.2;
|
|
context.lineCap = 'round';
|
|
context.stroke();
|
|
}
|
|
</script>
|
|
|
|
<script src="cbor.min.js"></script>
|
|
<script src="matsui-bundle.min.js"></script>
|
|
<script>
|
|
let state = Matsui.replace(document.body, {name: "..."});
|
|
state.trackMerges(merge => {
|
|
window.parent.postMessage(CBOR.encode(merge), '*');
|
|
});
|
|
addEventListener('message', e => {
|
|
state.merge(CBOR.decode(e.data));
|
|
});
|
|
|
|
window.parent.postMessage(CBOR.encode("ready"), '*');
|
|
</script>
|
|
</body>
|
|
</html>
|