1export default async function (req: Request): Promise<Response> {
2 const fftSize = 2048;
3 const TWO_PI = 2.0 * 3.141592653579;
56 const errorBox = document.getElementById("errorBox");
57
58 function showError(e) {
59 console.error(e);
60 errorBox.style.display = "block";
63
64 // DPR-aware resize
65 function resize() {
66 const dpr = Math.min(window.devicePixelRatio || 1, 2);
67 const w = Math.floor(window.innerWidth * dpr);
178 \`;
179
180 function compileShader(type, src) {
181 const s = gl.createShader(type);
182 gl.shaderSource(s, src);
204 gl.bindVertexArray(vao);
205
206 function createAttrib(data, attribName, usage) {
207 const loc = gl.getAttribLocation(program, attribName);
208 if (loc === -1) throw new Error("Attrib not found or optimized out: " + attribName);
230
231 // Matrices
232 function mat4Perspective(fovDeg, aspect, near, far) {
233 const f = 1.0 / Math.tan((fovDeg * Math.PI) / 360);
234 const nf = 1 / (near - far);
241 return out;
242 }
243 function subtract(a, b) { return [a[0]-b[0], a[1]-b[1], a[2]-b[2]]; }
244 function normalize(v) {
245 const l = Math.hypot(v[0], v[1], v[2]) || 1;
246 return [v[0]/l, v[1]/l, v[2]/l];
247 }
248 function cross(a, b) {
249 return [a[1]*b[2] - a[2]*b[1], a[2]*b[0] - a[0]*b[2], a[0]*b[1] - a[1]*b[0]];
250 }
251 function dot(a, b) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; }
252 function mat4LookAt(eye, target, up) {
253 const z = normalize(subtract(eye, target));
254 const x = normalize(cross(up, z));
296
297 // Render loop
298 function render(ts) {
299 // Update audio only if ready
300 if (analyser) {