noe.sh/dollseq/index.html
2024-10-18 22:43:21 -07:00

207 lines
4.9 KiB
HTML

<!DOCTYPE html>
<link rel="preconnect" href="https://fonts.bunny.net" />
<link
href="https://fonts.bunny.net/css?family=atkinson-hyperlegible:400,400i,700,700i"
rel="stylesheet"
/>
<link rel="stylesheet" href="/libs/shocktools.css" />
<style>
.drawer {
display: flex;
background-color: #2f382f;
max-width: 960px;
flex-wrap: wrap;
padding: 20px;
}
.seqItem {
/* allow for 16 seqments before wrapping */
flex: 1 8 100px;
max-width: 100px;
min-width: 20px;
height: 100px;
background-color: #6f916f;
margin: 10px;
border-radius: 3px;
overflow: hidden;
position: relative;
.seqItemInput {
transform: rotate(-90deg);
appearance: none;
background-color: transparent;
width: 100%;
height: 95%;
position: relative;
left: -2px;
}
.seqItemValue {
top: 0;
left: 0;
right: 0;
bottom: 0;
position: absolute;
pointer-events: none;
user-select: none;
z-index: 2;
display: flex;
justify-content: center;
align-items: center;
color: #42424288;
font-size: 45px;
font-weight: bold;
}
--progress-color: #e2d34a;
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
}
input[type="range"]::-moz-range-thumb,
input[type="range"]::-moz-range-track {
background-color: transparent;
appearance: none;
opacity: 0;
border: 0;
}
input[type="range"]::-webkit-slider-runnable-track {
background-color: var(--progress-color);
height: 100px;
}
input[type="range"]::-moz-range-progress {
background-color: var(--progress-color);
appearance: none;
height: 100px;
}
}
</style>
<main>
<section id="safetysection">
<div>
<label for="safety">SAFETY LOCK</label>
<input type="checkbox" name="safety" id="safety" value="true" />
</div>
<div>
<label for="arm">ARM DOLL CONTROL</label>
<input type="checkbox" name="arm" id="arm" />
</div>
<div>
<label for="intensity"
>Intensity Limit: <span id="intensity-readout">3</span></label
><br />
<input id="intensity" type="range" min="1" max="9" value="3" />
<button id="pair">Pair</button>
</div>
<div>
<div id="dot"></div>
<span id="dotText">Not Armed</span>
</div>
<div>
<div id="safetyDot"></div>
<span id="safetyDotText">Safety ON (commands will not be sent)</span>
</div>
</section>
<section id="app">
<div id="drawer" class="drawer">
<div class="seqItem">
<input
type="range"
min="0"
max="9"
step="1"
class="seqItemInput"
value="0"
oninput="handleNoteChange"
onchange="handleNoteChange"
/>
<div class="seqItemValue"></div>
</div>
</div>
</section>
<section id="logsection">
<h2>log</h2>
<pre id="log"></pre>
</section>
</main>
<script src="/libs/shock.js"></script>
<script defer async>
window.shockInit();
const safeLevel = (input, userMax, rangeMax = 9) =>
Math.min(Math.round((input / rangeMax) * userMax), userMax);
const handleNoteChange = (event) => {
const value = event.target.value;
const parent = event.target.parentNode;
const display = parent.querySelector(".seqItemValue");
const safeValue = safeLevel(value, window.getIntensity());
console.log({ value, safeValue });
if (safeValue === 0) {
display.innerHTML = "";
return;
}
display.innerHTML = `${safeValue}`;
location.hash = generateURLSequence();
};
const setupSequencerDrawer = (sequenceItems, urlSeed) => {
const seqItem = document.querySelector(".seqItem");
const drawer = document.querySelector("#drawer");
seqItem.value = 0;
drawer.innerHTML = "";
if (urlSeed !== null) {
sequenceItems = urlSeed.length;
}
for (let i = 0; i < sequenceItems; i++) {
drawer.innerHTML += seqItem.outerHTML;
}
forEachInput((input, _, idx) => {
input.addEventListener("input", handleNoteChange);
input.addEventListener("change", handleNoteChange);
input.value = urlSeed[idx] || 0;
handleNoteChange({ target: input });
});
};
const forEachInput = (predicate) => {
const allInputs = drawer.querySelectorAll(".seqItemInput");
allInputs.forEach((input, idx) => predicate(input, input.value, idx));
};
const generateURLSequence = () => {
let seq = "";
forEachInput((_, value) => (seq += value));
return seq;
};
let urlSeed = null;
if (location.hash) {
urlSeed = location.hash.split("").slice(1);
}
setupSequencerDrawer(16, urlSeed);
document.querySelector("#intensity").addEventListener("input", (event) => {
const value = event.target.value;
forEachInput((input) => {
handleNoteChange({ target: input });
});
});
</script>