Horizon is a lightweight, framework‑agnostic Vanllia JavaScript component library that converts input fields into fully‑interactive multi‑touch slider surface. The component is built around a minimal slider‑engine with no dependencies that provides immediate visual feedback.
- supports multiple data types
- RAF‑based rendering
- throttled updates
- debounced persistence
- reactive one‑way or two‑way bindings to external state
- optional persistence via localStorage.
- Demo examples MIDI output, Web Audio, and state serialization.
- Touch enabled device capable of running a modern browser
- Chrome 67+
- Firefox 68+
- Safari 12+ (pointer events supported)
- Edge 79+
- Mobile browsers (iOS Safari, Android Chrome) – works with touch and pointer events.
Caveat: Web MIDI is only available in Chrome, Edge, and Opera. Safari and Firefox currently do not support Web MIDI API.
- Light programming experience recommend.ed. The component is meant to be integrated into other projects.
Files can be copied directly or npm installed for the additional testing library.
<script src="https://unpkg.com/horizon@latest/horizon/main.js"></script> <script> const sl = new Horizon(); </script>
npm install horizon
Build and serve for production:
npm run build # Output file is build/main.js # Serve the static folder npx serve -p 8080
Open these files locally or serve them via npm run serve.
- / : Minimal UI that loads the library.
- midi-demo : Showcases real‑time MIDI CC, note, and pitchbend.
- audio-demo : Demonstrates Web Audio parameter control.
HTML:
<div id="array-1" class="slider-array"> <div class="channel" data-type="int" data-channel="0"></div> <div class="channel" data-type="int" data-channel="1"></div> <div class="channel" data-type="bool" data-channel="2"></div> </div>JS:
import { MultiTouchSlider, Sliders } from "horizon/main.js";
const slider = new MultiTouchSlider(); // Bind channel 0 of array-1 to an external value Sliders.bind("array-1", 0, 10, { type: "int", min: -127, max: 127 });
| Method | Description | Example |
|---|---|---|
Sliders.bind(arrayId, channelIndex, valueOrFn, options) |
Attach a binding. | Sliders.bind('array-1', 0, () => Math.random()*127, {type:'int', min:0, max:127}); |
Sliders.get(arrayId, channelIndex) |
Get a binding object. | const b = Sliders.get('array-1',0); |
Sliders.unbind(arrayId, channelIndex) |
Remove a binding. | Sliders.unbind('array-1',0); |
Sliders.clear() |
Remove all bindings. | Sliders.clear(); |
Sliders.export(presetName) |
Export current slider state to an object. | const config = Sliders.export('myPreset'); |
Sliders.import(data) |
Load a previously exported state. | Sliders.import(config); |
Sliders.savePreset(name) |
Persist preset to localStorage. | Sliders.savePreset('default'); |
Sliders.listPresets() |
List stored presets. | console.log(Sliders.listPresets()); |
Sliders.loadPreset(name) |
Load a preset. | Sliders.loadPreset('default'); |
Sliders.deletePreset(name) |
Delete preset. | Sliders.deletePreset('default'); |