diff --git a/nix/package.nix b/nix/package.nix index 7363031..a932f07 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -47,7 +47,13 @@ in { }; shell = pkgs.npmlock2nix.shell { - inherit buildInputs prePatch node_modules_attrs; + inherit prePatch node_modules_attrs; + + buildInputs = + buildInputs + ++ (with pkgs; [ + clang-tools + ]); src = nix-filter { root = self; diff --git a/package-lock.json b/package-lock.json index 63b65aa..3542461 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7812,6 +7812,11 @@ "integrity": "sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==", "dev": true }, + "react-use-error-boundary": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-use-error-boundary/-/react-use-error-boundary-3.0.0.tgz", + "integrity": "sha512-5urkfyU3ZzInEMSHe1gxtDzlQAHs0krTt0V6h8H2L5nXhDKq3OYXnCs9lGHDkEkYvLmsphw8ap5g8uYfvrkJng==" + }, "read-chunk": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-1.0.1.tgz", diff --git a/package.yaml b/package.yaml index db811fd..43a09dc 100644 --- a/package.yaml +++ b/package.yaml @@ -22,6 +22,7 @@ dependencies: # React-redux stuff react: ^18.2.0 react-dom: ^18.2.0 + react-use-error-boundary: ^3.0.0 # TODO(tlater): Remove when react implement their own redux: ^4.2.0 '@reduxjs/toolkit': ^1.8.3 react-redux: ^8.0.2 diff --git a/src/lib/scss/_custom-bulma.scss b/src/lib/scss/_custom-bulma.scss index d5ed286..769137b 100644 --- a/src/lib/scss/_custom-bulma.scss +++ b/src/lib/scss/_custom-bulma.scss @@ -40,5 +40,7 @@ $content-heading-color: $text; $hr-background-color: $grey-light; $hr-height: 1px; +$pre-background: $grey-darker; + @import "~/node_modules/bulma"; @import "./_navbar"; diff --git a/src/music/features/musicplayer/MusicPlayer.tsx b/src/music/features/musicplayer/MusicPlayer.tsx index e9f6e32..abb3cfb 100644 --- a/src/music/features/musicplayer/MusicPlayer.tsx +++ b/src/music/features/musicplayer/MusicPlayer.tsx @@ -1,13 +1,17 @@ import React from "react"; import Controls from "../controls/Controls"; +import Visualizer from "../visualizer/Visualizer"; import { musicPlayer } from "./musicPlayerSlice"; function MusicPlayer() { return (
+
+ {error.message}
+
+
+
+ );
+ } else if (error instanceof RendererError) {
+ setRenderError(
+
+ This browser does not support WebGL 2, sadly. This
+ demo uses WebGL and specifically instanced drawing,
+ so unfortunately this means it can't run on your
+ browser/device.
+
+ );
+ } else if (error instanceof Error) {
+ setRenderError(
+
+ Something went very wrong; apologies, either your
+ browser is not behaving or there's a serious bug.
+ You can contact me with this error message:
+
+
+ {error.message}
+
+
+
+ );
+ } else {
+ setRenderError(
+
+ Something went very wrong; apologies, either your
+ browser is not behaving or there's a serious bug.
+
+ );
+ }
+ }
+ },
+ [audioContext, audioNode]
+ );
+
+ if (renderError === null) {
+ return ;
+ } else {
+ return renderError;
+ }
+}
+
+export default Visualizer;
diff --git a/src/music/features/visualizer/cube.ts b/src/music/features/visualizer/cube.ts
new file mode 100644
index 0000000..ea044de
--- /dev/null
+++ b/src/music/features/visualizer/cube.ts
@@ -0,0 +1,84 @@
+/** * A hand-written 3d model of a cube.
+ *
+ * If this ever needs to be more than this, consider moving it to a
+ * proper .obj model.
+ */
+const Cube = {
+ // prettier-ignore
+ vertices: new Float32Array([
+ -1.0, -1.0, 1.0,
+ 1.0, -1.0, 1.0,
+ 1.0, 1.0, 1.0,
+ -1.0, 1.0, 1.0,
+
+ -1.0, -1.0, -1.0,
+ -1.0, 1.0, -1.0,
+ 1.0, 1.0, -1.0,
+ 1.0, -1.0, -1.0,
+
+ -1.0, 1.0, -1.0,
+ -1.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0,
+ 1.0, 1.0, -1.0,
+
+ -1.0, -1.0, -1.0,
+ 1.0, -1.0, -1.0,
+ 1.0, -1.0, 1.0,
+ -1.0, -1.0, 1.0,
+
+ 1.0, -1.0, -1.0,
+ 1.0, 1.0, -1.0,
+ 1.0, 1.0, 1.0,
+ 1.0, -1.0, 1.0,
+
+ -1.0, -1.0, -1.0,
+ -1.0, -1.0, 1.0,
+ -1.0, 1.0, 1.0,
+ -1.0, 1.0, -1.0,
+ ]),
+
+ // prettier-ignore
+ indices: new Uint16Array([
+ 0, 1, 2, 0, 2, 3,
+ 4, 5, 6, 4, 6, 7,
+ 8, 9, 10, 8, 10, 11,
+ 12, 13, 14, 12, 14, 15,
+ 16, 17, 18, 16, 18, 19,
+ 20, 21, 22, 20, 22, 23,
+ ]),
+
+ // prettier-ignore
+ normals: new Float32Array([
+ 0.0, 0.0, 1.0,
+ 0.0, 0.0, 1.0,
+ 0.0, 0.0, 1.0,
+ 0.0, 0.0, 1.0,
+
+ 0.0, 0.0, -1.0,
+ 0.0, 0.0, -1.0,
+ 0.0, 0.0, -1.0,
+ 0.0, 0.0, -1.0,
+
+ 0.0, 1.0, 0.0,
+ 0.0, 1.0, 0.0,
+ 0.0, 1.0, 0.0,
+ 0.0, 1.0, 0.0,
+
+ 0.0, -1.0, 0.0,
+ 0.0, -1.0, 0.0,
+ 0.0, -1.0, 0.0,
+ 0.0, -1.0, 0.0,
+
+ 1.0, 0.0, 0.0,
+ 1.0, 0.0, 0.0,
+ 1.0, 0.0, 0.0,
+ 1.0, 0.0, 0.0,
+
+ -1.0, 0.0, 0.0,
+ -1.0, 0.0, 0.0,
+ -1.0, 0.0, 0.0,
+ -1.0, 0.0, 0.0
+ ]),
+};
+
+export { Cube };
diff --git a/src/music/features/visualizer/fragments.glsl b/src/music/features/visualizer/fragments.glsl
new file mode 100644
index 0000000..b0d6784
--- /dev/null
+++ b/src/music/features/visualizer/fragments.glsl
@@ -0,0 +1,8 @@
+#version 300 es
+
+precision highp float;
+
+flat in vec4 vColor;
+out vec4 color;
+
+void main() { color = vColor; }
diff --git a/src/music/features/visualizer/fragments.glsl.d.ts b/src/music/features/visualizer/fragments.glsl.d.ts
new file mode 100644
index 0000000..5f4fa30
--- /dev/null
+++ b/src/music/features/visualizer/fragments.glsl.d.ts
@@ -0,0 +1,2 @@
+declare const fragments: string;
+export default fragments;
diff --git a/src/music/features/visualizer/vertices.glsl b/src/music/features/visualizer/vertices.glsl
new file mode 100644
index 0000000..8a66554
--- /dev/null
+++ b/src/music/features/visualizer/vertices.glsl
@@ -0,0 +1,40 @@
+#version 300 es
+
+#define BASE_COLOR vec4(1.0, 1.0, 1.0, 1.0)
+#define AMBIENT_LIGHT vec3(0.3, 0.3, 0.3)
+#define LIGHT_DIRECTION normalize(vec3(0.85, 0.8, 0.75))
+#define LIGHT_COLOR vec3(1.0, 1.0, 1.0)
+
+precision highp float;
+
+layout(location = 0) in vec4 aVertexPosition;
+layout(location = 1) in vec3 aVertexNormal;
+layout(location = 2) in float aHeight;
+flat out vec4 vColor;
+
+uniform mat4 uModelViewMatrix;
+uniform mat4 uProjectionMatrix;
+uniform mat4 uNormalMatrix;
+
+void main() {
+ float instanceX =
+ aVertexPosition.x + float(gl_InstanceID) * 2.0 * abs(aVertexPosition.x);
+ float vertexY =
+ aVertexPosition.y > 0.0 ? aVertexPosition.y * aHeight : aVertexPosition.y;
+
+ gl_Position = uProjectionMatrix * uModelViewMatrix *
+ vec4(instanceX, vertexY, aVertexPosition.zw);
+
+ vec4 transformedNormal = uNormalMatrix * vec4(aVertexNormal, 1.0);
+ float directionalLight =
+ max(dot(transformedNormal.xyz, LIGHT_DIRECTION), 0.0);
+
+ if (aHeight == 0.0) {
+ vColor = vec4(0.0, 0.0, 0.0, 0.0);
+ } else {
+ vec4 transformedNormal = uNormalMatrix * vec4(aVertexNormal, 1.0);
+ float directionalLight =
+ max(dot(transformedNormal.xyz, LIGHT_DIRECTION), 0.0);
+ vColor = vec4(AMBIENT_LIGHT + (directionalLight * LIGHT_COLOR), 1.0);
+ }
+}
diff --git a/src/music/features/visualizer/vertices.glsl.d.ts b/src/music/features/visualizer/vertices.glsl.d.ts
new file mode 100644
index 0000000..dae6095
--- /dev/null
+++ b/src/music/features/visualizer/vertices.glsl.d.ts
@@ -0,0 +1,2 @@
+declare const vertices: string;
+export default vertices;
diff --git a/tsconfig.json b/tsconfig.json
index 1a93d76..8e0a4bb 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -5,7 +5,8 @@
"esModuleInterop": true,
"jsx": "react",
"isolatedModules": true,
- "target": "es5",
+ "target": "es2015",
+ "moduleResolution": "node",
"plugins": [
{
"name": "typescript-eslint-language-service"