From 1de834020ac49286efa02637cf03e2198a7b2dc4 Mon Sep 17 00:00:00 2001 From: Kai Vogelgesang Date: Wed, 28 Dec 2022 02:30:36 +0100 Subject: [PATCH] Implement fixtures and library --- webserial/src/editor/Monaco.svelte | 8 +- webserial/src/editor/code.ts | 3 +- webserial/src/editor/defaultCode.ts | 103 ++++++++++++++++++- webserial/src/editor/defaultEnv.d.ts | 27 ++++- webserial/src/eval/EvalLoop.svelte | 16 +-- webserial/src/eval/lib.ts | 16 +++ webserial/src/eval/tsOptions.ts | 7 ++ webserial/src/serial/SerialConnection.svelte | 6 +- webserial/src/serial/SerialManager.svelte | 27 +++-- 9 files changed, 185 insertions(+), 28 deletions(-) create mode 100644 webserial/src/eval/lib.ts create mode 100644 webserial/src/eval/tsOptions.ts diff --git a/webserial/src/editor/Monaco.svelte b/webserial/src/editor/Monaco.svelte index f19343f..13307da 100644 --- a/webserial/src/editor/Monaco.svelte +++ b/webserial/src/editor/Monaco.svelte @@ -7,12 +7,13 @@ import defaultCode from "./defaultCode.ts?raw"; import defaultEnv from "./defaultEnv.d.ts?raw"; import { code } from "./code"; + import tsOptions from "../eval/tsOptions"; let divEl: HTMLDivElement = null; let editor: monaco.editor.IStandaloneCodeEditor; let value = defaultCode; - $: $code = TS.transpile(value, { strict: true }); + $: $code = TS.transpile(value, tsOptions); onMount(async () => { // @ts-ignore @@ -30,7 +31,10 @@ language: "typescript", }); - let lib = monaco.languages.typescript.typescriptDefaults.addExtraLib(defaultEnv); + let lib = + monaco.languages.typescript.typescriptDefaults.addExtraLib( + defaultEnv + ); editor.onKeyUp((_e) => (value = editor.getValue())); diff --git a/webserial/src/editor/code.ts b/webserial/src/editor/code.ts index 2b329af..d8f486c 100644 --- a/webserial/src/editor/code.ts +++ b/webserial/src/editor/code.ts @@ -1,6 +1,7 @@ import { writable } from "svelte/store"; import defaultCode from "./defaultCode.ts?raw"; import TS from "typescript"; +import tsOptions from "../eval/tsOptions"; /** the transpiled JavaScript code */ -export const code = writable(TS.transpile(defaultCode, {strict: true})); \ No newline at end of file +export const code = writable(TS.transpile(defaultCode, tsOptions)); \ No newline at end of file diff --git a/webserial/src/editor/defaultCode.ts b/webserial/src/editor/defaultCode.ts index 9c5bd09..ed40918 100644 --- a/webserial/src/editor/defaultCode.ts +++ b/webserial/src/editor/defaultCode.ts @@ -1,4 +1,101 @@ -// ayaya ayaya +// Connect the interface with the button below and modify the code here. +// The output should update in real time as you type :) -ctx.set(1, 255); -ctx.set(2, 255); \ No newline at end of file +// Fixtures library. TODO move this into a separate file + +class Fixture { + address: number + ctx: Context + + constructor(address: number, ctx: Context) { + this.address = address; + this.ctx = ctx; + } +} + +interface GenericRGBW { + /** + * Set the brightness + * + * @param value between 0 and 1 + * @param strobe enable strobe (turn off if unsupported) + */ + setBrightness(value: number, strobe?: boolean): void + setRGBW(rgb: [number, number, number], w?: number): void +} + +class Par extends Fixture implements GenericRGBW { + setBrightness(value: number, strobe?: boolean) { + if (strobe || false) { + this.ctx.set(this.address, 255); + this.ctx.set(this.address + 7, value * 255); + } else { + this.ctx.set(this.address, value * 255); + this.ctx.set(this.address + 7, 0); + } + } + + setRGBW(rgb: [number, number, number], w?: number) { + let [r, g, b] = rgb; + this.ctx.set(this.address + 1, r); + this.ctx.set(this.address + 2, g); + this.ctx.set(this.address + 3, b); + this.ctx.set(this.address + 4, w || 0); + } + + setAUV(a: number, uv: number) { + this.ctx.set(this.address + 5, a); + this.ctx.set(this.address + 6, uv); + } +} + +class MovingHead extends Fixture implements GenericRGBW { + setBrightness(value: number, strobe?: boolean) { + let out = (strobe || false) + ? 135 + (239 - 135) * value + : 8 + (134 - 8) * value; + this.ctx.set(this.address + 5, out); + } + + setRGBW(rgb: [number, number, number], w?: number) { + let [r, g, b] = rgb; + this.ctx.set(this.address + 6, r); + this.ctx.set(this.address + 7, g); + this.ctx.set(this.address + 8, b); + this.ctx.set(this.address + 9, w || 0); + } + + /** + * Rotate the moving head. Pan and tilt are in radians. + * @param pan between -1.5pi and 1.5pi + * @param tilt between -0.5pi and 0.5pi + * @param speed between 0 (fast) and 255 (slow) + */ + setPanTilt(pan: number, tilt: number, speed?: number) { + let panRough = (pan + 3 * Math.PI / 2) / (Math.PI * 3) * 256 + panRough = Math.max(0, Math.min(255, panRough)) + + let tiltRough = (tilt + Math.PI / 2) / (Math.PI) * 256 + tiltRough = Math.max(0, Math.min(255, tiltRough)) + + // TODO + let panFine = 0 + let tiltFine = 0 + + this.ctx.set(this.address + 0, panRough); + this.ctx.set(this.address + 1, panFine); + this.ctx.set(this.address + 2, tiltRough); + this.ctx.set(this.address + 3, tiltFine); + this.ctx.set(this.address + 4, speed || 0); + } +} + +// ****************** +// * CODE GOES HERE * +// ****************** + +let color = lib.hsl2rgb(360 * t, 100, 50); + +let par = new Par(1, ctx); +par.setBrightness(1); +par.setRGBW(color); \ No newline at end of file diff --git a/webserial/src/editor/defaultEnv.d.ts b/webserial/src/editor/defaultEnv.d.ts index 1d43a76..9d7cbfd 100644 --- a/webserial/src/editor/defaultEnv.d.ts +++ b/webserial/src/editor/defaultEnv.d.ts @@ -1,9 +1,30 @@ type Context = { + /** + * Set DMX address `address` to `value` + * @param address between 1 and 511 + * @param value between 0 and 255 + */ set(address: number, value: number): void, }; -/** the global Context object */ +/** The global Context object */ declare const ctx: Context; -/** the current time (in seconds, e.g. 1.25 after 1250 milliseconds) */ -declare const t: number; \ No newline at end of file +/** The current time (in seconds, e.g. 1.25 after 1250 milliseconds) */ +declare const t: number; + +type Lib = { + /** + * Converts from the HSL color space to RGB + * + * Outputs [r, g, b] between 0 and 255 each + * + * @param h in degrees, i.e. 0 to 360 + * @param s between 0 and 100 + * @param l between 0 and 100 + */ + hsl2rgb(h: number, s: number, l: number): [number, number, number] +} + +/** The standard library */ +declare const lib: Lib; \ No newline at end of file diff --git a/webserial/src/eval/EvalLoop.svelte b/webserial/src/eval/EvalLoop.svelte index bedba0d..b902bd3 100644 --- a/webserial/src/eval/EvalLoop.svelte +++ b/webserial/src/eval/EvalLoop.svelte @@ -3,14 +3,16 @@ import { onMount } from "svelte"; import { code } from "../editor/code"; import { dmxData } from "../dmx/store"; + import { lib } from "./lib"; let startTime: number; let payload = new Uint8Array(512); let ctx: Context = { set(address: number, value: number) { - payload[address - 1] = value; - } - } + let rounded = Math.round(value); + payload[address - 1] = Math.max(0, Math.min(255, rounded)); + }, + }; let result: string; @@ -18,7 +20,7 @@ payload = new Uint8Array(512); const t = (performance.now() - startTime) / 1000; try { - let ret = Function("ctx", "t", $code).call({}, ctx, t); + let ret = Function("ctx", "t", "lib", $code).call({}, ctx, t, lib); result = JSON.stringify(ret); } catch (err) { result = JSON.stringify(err); @@ -36,8 +38,8 @@ return () => { clearInterval(int); - } - }) + }; + }); - \ No newline at end of file + diff --git a/webserial/src/eval/lib.ts b/webserial/src/eval/lib.ts new file mode 100644 index 0000000..6f1f18b --- /dev/null +++ b/webserial/src/eval/lib.ts @@ -0,0 +1,16 @@ +/// + +export const lib: Lib = { + hsl2rgb(h, s, l): [number, number, number] { + // https://stackoverflow.com/a/44134328 + l /= 100; + const a = s * Math.min(l, 1 - l) / 100; + const f = n => { + const k = (n + h / 30) % 12; + const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); + return Math.round(255 * color) + }; + return [f(0), f(8), f(4)]; + + }, +} \ No newline at end of file diff --git a/webserial/src/eval/tsOptions.ts b/webserial/src/eval/tsOptions.ts new file mode 100644 index 0000000..a3c073e --- /dev/null +++ b/webserial/src/eval/tsOptions.ts @@ -0,0 +1,7 @@ +import type { CompilerOptions } from "typescript" + +const tsOptions: CompilerOptions = { + strict: true +} + +export default tsOptions \ No newline at end of file diff --git a/webserial/src/serial/SerialConnection.svelte b/webserial/src/serial/SerialConnection.svelte index 6e8f1bf..a90309a 100644 --- a/webserial/src/serial/SerialConnection.svelte +++ b/webserial/src/serial/SerialConnection.svelte @@ -98,7 +98,11 @@ if (loopTime < FRAME_TIME) { await sleep(FRAME_TIME - loopTime); } else { - console.warn(`loop took too long (+${(loopTime - FRAME_TIME).toFixed(2)} ms)`); + console.warn( + `loop took too long (+${(loopTime - FRAME_TIME).toFixed( + 2 + )} ms)` + ); } lastLoopTime = loopTime; } diff --git a/webserial/src/serial/SerialManager.svelte b/webserial/src/serial/SerialManager.svelte index 7ed2812..360737c 100644 --- a/webserial/src/serial/SerialManager.svelte +++ b/webserial/src/serial/SerialManager.svelte @@ -14,22 +14,27 @@
-{#if navigator.serial} -

Serial available 🚀

- {#if port !== null} - -

+ {#if navigator.serial} +

Serial available 🚀

+ {#if port !== null} + +

+ {:else} +

+ {/if} {:else} -

+

Looks like your browser does not support WebSerial 😢

+

+ Check here for a list of compatible browsers +

{/if} -{:else} -

Looks like your browser does not support WebSerial 😢

-

Check here for a list of compatible browsers

-{/if}
\ No newline at end of file +