mirror of
https://github.com/narrrl/pl8list-rewind.git
synced 2026-11-13 17:17:03 +01:00
Draw the title, waveform and logo as bevelled chrome in WebGL
A distance transform turns the glyphs and waveform bars into a height field with bevelled edges and some depth, and a shader lights them as metal: a studio of softboxes, a dark horizon and the card's colour and art as the floor, colour split at steep edges, a key light that follows the pointer (drifts on phones) and flares on kicks, and a sweep over each new title. One offscreen context serves every plate. The title turns slightly towards the pointer. Display text uses Bruno Ace SC, bundled; "simple" visuals keep plain text and the drawn waveform.
This commit is contained in:
1 parent
62b28bd30e
commit
cfccfcaac6
7 files changed
+778
-13
No files matched your search
+36
-1
@@ -176,6 +176,11 @@ export class Card {
|
||||
if (this.dragging && !force) return;
|
||||
this.lastProgress = progress;
|
||||
this.lastBuffered = buffered;
|
||||
if (this.onWave) {
|
||||
this.onWave(progress, buffered);
|
||||
this.drawn = ""; // drawn here again once chrome lets go
|
||||
return;
|
||||
}
|
||||
const canvas = this.canvas;
|
||||
if (!canvas) return;
|
||||
const w = canvas.clientWidth, h = canvas.clientHeight;
|
||||
@@ -199,7 +204,7 @@ export class Card {
|
||||
const accent = getComputedStyle(canvas).getPropertyValue("--card-accent").trim() || "#ff4d6d";
|
||||
const base = Math.round(h * (1 - MIRROR)) - 1;
|
||||
const below = h - base - 2;
|
||||
const level = (i: number) => (data.length ? data[Math.floor((i / bars) * data.length)] / max : 0.15);
|
||||
const level = (i: number) => this.level(i, bars, data, max);
|
||||
const grad = ctx.createLinearGradient(0, base, 0, 0);
|
||||
grad.addColorStop(0, accent);
|
||||
grad.addColorStop(0.65, accent);
|
||||
@@ -228,6 +233,36 @@ export class Card {
|
||||
ctx.globalAlpha = 1;
|
||||
}
|
||||
|
||||
/// Set while the waveform is chrome (chrome.ts via visual.ts), which then draws it.
|
||||
onWave: ((progress: number, buffered: number) => void) | null = null;
|
||||
|
||||
get waveCanvas(): HTMLCanvasElement | null {
|
||||
return this.canvas;
|
||||
}
|
||||
|
||||
private level(i: number, bars: number, data: number[], max: number): number {
|
||||
return data.length ? data[Math.floor((i / bars) * data.length)] / max : 0.15;
|
||||
}
|
||||
|
||||
/// The bars alone, as a mask for chrome, in CSS px of a `w` x `h` canvas, `bar`
|
||||
/// px apart. Returns the line they stand on and, per bar, where its top is.
|
||||
waveMask(ctx: CanvasRenderingContext2D, w: number, h: number, bar: number): { base: number; tops: number[]; width: number } {
|
||||
const data = this.track.waveform || [];
|
||||
const max = Math.max(1, ...data);
|
||||
const bars = Math.max(1, Math.floor(w / bar));
|
||||
const width = bar * 0.7;
|
||||
const base = Math.round(h * (1 - MIRROR)) - 1;
|
||||
const tops: number[] = [];
|
||||
for (let i = 0; i < bars; i++) {
|
||||
const top = Math.max(width, this.level(i, bars, data, max) * (base - 2));
|
||||
tops.push(base - top);
|
||||
ctx.beginPath();
|
||||
ctx.roundRect(i * bar, base - top, width, top, width / 2);
|
||||
ctx.fill();
|
||||
}
|
||||
return { base, tops, width };
|
||||
}
|
||||
|
||||
/// Loudness at `progress` from the waveform, 0..1. Stands in for the analyser
|
||||
/// where there is no Web Audio graph.
|
||||
loudnessAt(progress: number): number {
|
||||
|
||||
Reference in new issue
Block a user