adding script vis

This commit is contained in:
2023-10-22 21:13:18 +02:00
parent 094fb57049
commit d6577718a6
5 changed files with 183 additions and 11 deletions

View File

@ -22,6 +22,11 @@
padding: 0;
}
.fluid-bg-transition {
transition: background-color 0.05s ease-in-out;
}
#hydra-bg {
position: fixed; /* ignore margins */
top: 0px;

View File

@ -26,6 +26,7 @@ import {
} from "superdough";
import { Speaker } from "./StringExtensions";
import { getScaleNotes } from "zifferjs";
import { blinkScript } from "./AudioVisualisation";
interface ControlChange {
channel: number;
@ -269,10 +270,13 @@ export class UserAPI {
* @returns The result of the evaluation
*/
args.forEach((arg) => {
tryEvaluate(
this.app,
this.app.universes[this.app.selected_universe].locals[arg]
);
if (arg >= 1 && arg <= 9) {
blinkScript(this.app, "local", arg);
tryEvaluate(
this.app,
this.app.universes[this.app.selected_universe].locals[arg]
);
}
});
};
s = this.script;

View File

@ -1,2 +1,115 @@
// @ts-ignore
import { analyser, getAnalyzerData } from "superdough";
import { type Editor } from "./main";
/**
* Draw a circle at a specific position on the canvas.
* @param {number} x - The x-coordinate of the circle's center.
* @param {number} y - The y-coordinate of the circle's center.
* @param {number} radius - The radius of the circle.
* @param {string} color - The fill color of the circle.
*/
export const drawCircle = (
app: Editor,
x: number,
y: number,
radius: number,
color: string
): void => {
// @ts-ignore
const canvas: HTMLCanvasElement = app.interface.feedback;
const ctx = canvas.getContext("2d");
if (!ctx) return;
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.fillStyle = color;
ctx.fill();
ctx.closePath();
};
/**
* Blinks a script indicator circle.
* @param script - The type of script.
* @param no - The shift amount multiplier.
*/
export const blinkScript = (
app: Editor,
script: "local" | "global" | "init",
no?: number
) => {
if (no !== undefined && no < 1 && no > 9) return;
const blinkDuration =
(app.clock.bpm / 60 / app.clock.time_signature[1]) * 200;
// @ts-ignore
const ctx = app.interface.feedback.getContext("2d"); // Assuming a canvas context
/**
* Draws a circle at a given shift.
* @param shift - The pixel distance from the origin.
*/
const _drawBlinker = (shift: number) => {
const horizontalOffset = 50;
drawCircle(
app,
horizontalOffset + shift,
app.interface.feedback.clientHeight - 15,
8,
"#fdba74"
);
};
/**
* Clears the circle at a given shift.
* @param shift - The pixel distance from the origin.
*/
const _clearBlinker = (shift: number) => {
const x = 50 + shift;
const y = app.interface.feedback.clientHeight - 15;
const radius = 8;
ctx.clearRect(x - radius, y - radius, radius * 2, radius * 2);
};
if (script === "local" && no !== undefined) {
const shiftAmount = no * 25;
// Clear existing timeout if any
if (app.blinkTimeouts[shiftAmount]) {
clearTimeout(app.blinkTimeouts[shiftAmount]);
}
_drawBlinker(shiftAmount);
// Save timeout ID for later clearing
app.blinkTimeouts[shiftAmount] = setTimeout(() => {
_clearBlinker(shiftAmount);
// Clear the canvas before drawing new blinkers
(app.interface.feedback as HTMLCanvasElement)
.getContext("2d")!
.clearRect(
0,
0,
(app.interface.feedback as HTMLCanvasElement).width,
(app.interface.feedback as HTMLCanvasElement).height
);
drawEmptyBlinkers(app);
}, blinkDuration);
}
};
/**
* Draws a series of 9 white circles.
* @param app - The Editor application context.
*/
export const drawEmptyBlinkers = (app: Editor) => {
for (let no = 1; no <= 9; no++) {
const shiftAmount = no * 25;
drawCircle(
app,
50 + shiftAmount,
app.interface.feedback.clientHeight - 15,
8,
"white"
);
}
};

View File

@ -1,10 +1,28 @@
import { type Editor } from "./main";
const handleResize = (app: Editor) => {
const canvas = app.interface.feedback as HTMLCanvasElement | null; // add type guard
if (!canvas) return;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext("2d");
const dpr = window.devicePixelRatio || 1;
// Assuming the canvas takes up the whole window
canvas.width = window.innerWidth * dpr;
canvas.height = window.innerHeight * dpr;
if (ctx) {
ctx.scale(dpr, dpr);
}
};
export const installWindowBehaviors = (
app: Editor,
window: Window,
preventMultipleTabs: boolean = false
) => {
window.addEventListener("resize", () => handleResize(app));
window.addEventListener("beforeunload", () => {
// @ts-ignore
event.preventDefault();

View File

@ -24,6 +24,7 @@ import showdown from "showdown";
import { makeStringExtensions } from "./StringExtensions";
import { installInterfaceLogic } from "./InterfaceLogic";
import { installWindowBehaviors } from "./WindowBehavior";
import { drawEmptyBlinkers } from "./AudioVisualisation";
export class Editor {
// Universes and settings
@ -56,6 +57,7 @@ export class Editor {
show_error: boolean = false;
buttonElements: Record<string, HTMLButtonElement[]> = {};
interface: ElementMap = {};
blinkTimeouts: Record<number, number> = {};
// UserAPI
api: UserAPI;
@ -79,6 +81,7 @@ export class Editor {
this.initializeElements();
this.initializeButtonGroups();
this.initializeHydra();
this.setCanvas();
// ================================================================================
// Loading the universe from local storage
@ -127,6 +130,7 @@ export class Editor {
registerFillKeys(this);
registerOnKeyDown(this);
installInterfaceLogic(this);
drawEmptyBlinkers(this);
// ================================================================================
// Building CodeMirror Editor
@ -381,25 +385,36 @@ export class Editor {
}
/**
* @param color the color to flash the background
* @param duration the duration of the flash
* Flashes the background of the view and its gutters.
* @param {string} color - The color to set.
* @param {number} duration - Duration in milliseconds to maintain the color.
*/
flashBackground(color: string, duration: number): void {
// Set the flashing color
this.view.dom.style.backgroundColor = color;
const gutters = this.view.dom.getElementsByClassName(
const domElement = this.view.dom;
const gutters = domElement.getElementsByClassName(
"cm-gutter"
) as HTMLCollectionOf<HTMLElement>;
domElement.classList.add("fluid-bg-transition");
Array.from(gutters).forEach((gutter) =>
gutter.classList.add("fluid-bg-transition")
);
domElement.style.backgroundColor = color;
Array.from(gutters).forEach(
(gutter) => (gutter.style.backgroundColor = color)
);
// Reset to original color after duration
setTimeout(() => {
this.view.dom.style.backgroundColor = "";
domElement.style.backgroundColor = "";
Array.from(gutters).forEach(
(gutter) => (gutter.style.backgroundColor = "")
);
domElement.classList.remove("fluid-bg-transition");
Array.from(gutters).forEach((gutter) =>
gutter.classList.remove("fluid-bg-transition")
);
}, duration);
}
@ -428,6 +443,23 @@ export class Editor {
});
this.hydra = this.hydra_backend.synth;
}
private setCanvas(): void {
const canvas = this.interface.feedback as HTMLCanvasElement | null; // add type guard
if (!canvas) return;
const ctx = canvas.getContext("2d");
const dpr = window.devicePixelRatio || 1;
// Assuming the canvas takes up the whole window
canvas.width = window.innerWidth * dpr;
canvas.height = window.innerHeight * dpr;
if (ctx) {
ctx.scale(dpr, dpr);
}
}
}
let app = new Editor();