render
This commit is contained in:
parent
3dd301a334
commit
132524eba3
8 changed files with 130 additions and 53 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
node_modules
|
node_modules
|
||||||
|
dist
|
1
.tokeignore
Normal file
1
.tokeignore
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pnpm-lock.yaml
|
49
package.json
49
package.json
|
@ -1,25 +1,28 @@
|
||||||
{
|
{
|
||||||
"name": "osuplayer.js",
|
"name": "osuplayer.js",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"type": "module",
|
||||||
"dev": "vite"
|
"scripts": {
|
||||||
},
|
"dev": "vite",
|
||||||
"keywords": [],
|
"build": "vite build"
|
||||||
"author": "",
|
},
|
||||||
"license": "ISC",
|
"keywords": [],
|
||||||
"devDependencies": {
|
"author": "",
|
||||||
"@biomejs/biome": "1.7.2",
|
"license": "ISC",
|
||||||
"@types/three": "^0.164.0",
|
"devDependencies": {
|
||||||
"vite": "^5.2.11",
|
"@biomejs/biome": "1.7.2",
|
||||||
"vite-plugin-node-polyfills": "^0.21.0"
|
"@types/three": "^0.164.0",
|
||||||
},
|
"vite": "^5.2.11",
|
||||||
"dependencies": {
|
"vite-bundle-analyzer": "^0.9.4",
|
||||||
"@zip.js/zip.js": "^2.7.43",
|
"vite-plugin-node-polyfills": "^0.21.0"
|
||||||
"osu-classes": "^3.1.0",
|
},
|
||||||
"osu-parsers": "^4.1.7",
|
"dependencies": {
|
||||||
"rosu-pp-js": "https://github.com/MaxOhn/rosu-pp-js/releases/download/v1.0.2/rosu_pp_js_web.tar.gz",
|
"@zip.js/zip.js": "^2.7.43",
|
||||||
"three": "^0.164.1"
|
"osu-classes": "^3.1.0",
|
||||||
}
|
"osu-parsers": "^4.1.7",
|
||||||
|
"rosu-pp-js": "https://github.com/MaxOhn/rosu-pp-js/releases/download/v1.0.2/rosu_pp_js_web.tar.gz",
|
||||||
|
"three": "^0.164.1"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,9 @@ devDependencies:
|
||||||
vite:
|
vite:
|
||||||
specifier: ^5.2.11
|
specifier: ^5.2.11
|
||||||
version: 5.2.11
|
version: 5.2.11
|
||||||
|
vite-bundle-analyzer:
|
||||||
|
specifier: ^0.9.4
|
||||||
|
version: 0.9.4
|
||||||
vite-plugin-node-polyfills:
|
vite-plugin-node-polyfills:
|
||||||
specifier: ^0.21.0
|
specifier: ^0.21.0
|
||||||
version: 0.21.0(vite@5.2.11)
|
version: 0.21.0(vite@5.2.11)
|
||||||
|
@ -1379,6 +1382,11 @@ packages:
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/source-map@0.7.4:
|
||||||
|
resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==}
|
||||||
|
engines: {node: '>= 8'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/stream-browserify@3.0.0:
|
/stream-browserify@3.0.0:
|
||||||
resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==}
|
resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -1452,6 +1460,13 @@ packages:
|
||||||
which-typed-array: 1.1.15
|
which-typed-array: 1.1.15
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/vite-bundle-analyzer@0.9.4:
|
||||||
|
resolution: {integrity: sha512-a/w4ShKQEbTe7wllLXI+3D8ELgRv7iHDuWEPaXokA+FhWBXJCdtOZYIvLzvnn8vxHf+7pm1c23AeGyW/0Ge0Yw==}
|
||||||
|
dependencies:
|
||||||
|
picocolors: 1.0.0
|
||||||
|
source-map: 0.7.4
|
||||||
|
dev: true
|
||||||
|
|
||||||
/vite-plugin-node-polyfills@0.21.0(vite@5.2.11):
|
/vite-plugin-node-polyfills@0.21.0(vite@5.2.11):
|
||||||
resolution: {integrity: sha512-Sk4DiKnmxN8E0vhgEhzLudfJQfaT8k4/gJ25xvUPG54KjLJ6HAmDKbr4rzDD/QWEY+Lwg80KE85fGYBQihEPQA==}
|
resolution: {integrity: sha512-Sk4DiKnmxN8E0vhgEhzLudfJQfaT8k4/gJ25xvUPG54KjLJ6HAmDKbr4rzDD/QWEY+Lwg80KE85fGYBQihEPQA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|
95
src/index.ts
95
src/index.ts
|
@ -20,6 +20,8 @@ class OsuPlayer {
|
||||||
beatmapSet: BeatmapSet = new BeatmapSet();
|
beatmapSet: BeatmapSet = new BeatmapSet();
|
||||||
diffsByStarRating: [number, number][] = [];
|
diffsByStarRating: [number, number][] = [];
|
||||||
diffs: Map<number, Beatmap> = new Map();
|
diffs: Map<number, Beatmap> = new Map();
|
||||||
|
audioTimestamp: number;
|
||||||
|
audioBuffer: AudioBuffer;
|
||||||
|
|
||||||
constructor(opts?: OsuPlayerOpts) {
|
constructor(opts?: OsuPlayerOpts) {
|
||||||
if (opts) this.opts = opts;
|
if (opts) this.opts = opts;
|
||||||
|
@ -66,29 +68,7 @@ class OsuPlayer {
|
||||||
}
|
}
|
||||||
this.diffsByStarRating.sort((a, b) => a[0] - b[0]);
|
this.diffsByStarRating.sort((a, b) => a[0] - b[0]);
|
||||||
|
|
||||||
/*
|
// TODO: Debug
|
||||||
const listEl = document.createElement("ul");
|
|
||||||
listEl.style.margin = "0";
|
|
||||||
for (const [stars, id] of this.diffsByStarRating) {
|
|
||||||
// biome-ignore lint/style/noNonNullAssertion: <explanation>
|
|
||||||
const diff = this.diffs.get(id)!;
|
|
||||||
const liEl = document.createElement("li");
|
|
||||||
const aEl = document.createElement("a");
|
|
||||||
aEl.href = "javascript:void(0)";
|
|
||||||
aEl.text = `${diff.osuInner.metadata.version} (${
|
|
||||||
Math.round(stars * 100) / 100
|
|
||||||
}*)`;
|
|
||||||
aEl.addEventListener("click", (evt) => {
|
|
||||||
this.setBeatmap(id);
|
|
||||||
});
|
|
||||||
liEl.appendChild(aEl);
|
|
||||||
listEl.appendChild(liEl);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log([...this.beatmapSet.assets.entries()]);
|
|
||||||
this.el?.replaceChildren(listEl);
|
|
||||||
*/
|
|
||||||
|
|
||||||
this.setBeatmap(
|
this.setBeatmap(
|
||||||
this.diffsByStarRating[this.diffsByStarRating.length - 1][1],
|
this.diffsByStarRating[this.diffsByStarRating.length - 1][1],
|
||||||
);
|
);
|
||||||
|
@ -99,6 +79,29 @@ class OsuPlayer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showDiffSelector() {
|
||||||
|
const listEl = document.createElement("ul");
|
||||||
|
listEl.style.margin = "0";
|
||||||
|
for (const [stars, id] of this.diffsByStarRating) {
|
||||||
|
// biome-ignore lint/style/noNonNullAssertion: <explanation>
|
||||||
|
const diff = this.diffs.get(id)!;
|
||||||
|
const liEl = document.createElement("li");
|
||||||
|
const aEl = document.createElement("a");
|
||||||
|
aEl.href = "javascript:void(0)";
|
||||||
|
aEl.text = `${diff.osuInner.metadata.version} (${
|
||||||
|
Math.round(stars * 100) / 100
|
||||||
|
}*)`;
|
||||||
|
aEl.addEventListener("click", (evt) => {
|
||||||
|
this.setBeatmap(id);
|
||||||
|
});
|
||||||
|
liEl.appendChild(aEl);
|
||||||
|
listEl.appendChild(liEl);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log([...this.beatmapSet.assets.entries()]);
|
||||||
|
this.el?.replaceChildren(listEl);
|
||||||
|
}
|
||||||
|
|
||||||
setBeatmap(id: number) {
|
setBeatmap(id: number) {
|
||||||
this.canvasEl = document.createElement("canvas");
|
this.canvasEl = document.createElement("canvas");
|
||||||
this.canvasEl.width = 1024;
|
this.canvasEl.width = 1024;
|
||||||
|
@ -111,14 +114,17 @@ class OsuPlayer {
|
||||||
const beatmap = this.diffs.get(id)!;
|
const beatmap = this.diffs.get(id)!;
|
||||||
|
|
||||||
const backgroundUrl = URL.createObjectURL(beatmap.background());
|
const backgroundUrl = URL.createObjectURL(beatmap.background());
|
||||||
|
const audioUrl = beatmap.audioFile();
|
||||||
|
console.log(audioUrl);
|
||||||
|
|
||||||
const scene = new THREE.Scene();
|
const scene = new THREE.Scene();
|
||||||
const camera = new THREE.OrthographicCamera(-512, 512, -384, 384, 1, 1000);
|
const camera = new THREE.OrthographicCamera(-512, 512, -384, 384, 1, 1000);
|
||||||
scene.add(camera);
|
scene.add(camera);
|
||||||
|
|
||||||
scene.add(new THREE.AmbientLight());
|
scene.add(new THREE.AmbientLight());
|
||||||
|
|
||||||
|
const clock = new THREE.Clock();
|
||||||
const loader = new THREE.TextureLoader();
|
const loader = new THREE.TextureLoader();
|
||||||
|
const audioContext = new AudioContext();
|
||||||
|
|
||||||
let backgroundPlane: THREE.Mesh;
|
let backgroundPlane: THREE.Mesh;
|
||||||
{
|
{
|
||||||
|
@ -140,15 +146,46 @@ class OsuPlayer {
|
||||||
|
|
||||||
const renderer = new THREE.WebGLRenderer({ canvas: this.canvasEl });
|
const renderer = new THREE.WebGLRenderer({ canvas: this.canvasEl });
|
||||||
const stats = new Stats();
|
const stats = new Stats();
|
||||||
|
|
||||||
this.el?.replaceChildren(this.canvasEl, stats.dom);
|
this.el?.replaceChildren(this.canvasEl, stats.dom);
|
||||||
|
|
||||||
function animate() {
|
const loadMusic = async () => {
|
||||||
requestAnimationFrame(animate);
|
const audioStream = audioUrl.stream();
|
||||||
|
const buffer = await new Response(audioStream).arrayBuffer();
|
||||||
|
const musicBuffer = await audioContext.decodeAudioData(buffer);
|
||||||
|
this.audioBuffer = musicBuffer;
|
||||||
|
};
|
||||||
|
|
||||||
renderer.render(scene, camera);
|
const loadStuff = () => {
|
||||||
}
|
return Promise.all([loadMusic()]);
|
||||||
|
};
|
||||||
|
|
||||||
animate();
|
const play = () => {
|
||||||
|
const gainNode = audioContext.createGain();
|
||||||
|
gainNode.gain.value = 0.01;
|
||||||
|
gainNode.connect(audioContext.destination);
|
||||||
|
|
||||||
|
const audioSource = audioContext.createBufferSource();
|
||||||
|
audioSource.buffer = this.audioBuffer;
|
||||||
|
audioSource.connect(gainNode);
|
||||||
|
audioSource.start();
|
||||||
|
|
||||||
|
const updateObjects = () => {};
|
||||||
|
|
||||||
|
const animate = () => {
|
||||||
|
requestAnimationFrame(animate);
|
||||||
|
this.audioTimestamp = audioContext.getOutputTimestamp().contextTime;
|
||||||
|
updateObjects();
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
};
|
||||||
|
|
||||||
|
animate();
|
||||||
|
};
|
||||||
|
|
||||||
|
loadStuff().then(() => {
|
||||||
|
console.log("loaded!");
|
||||||
|
play();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,12 @@ export class Beatmap {
|
||||||
return this.osuInner.metadata.beatmapId;
|
return this.osuInner.metadata.beatmapId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public audioFile(): Blob {
|
||||||
|
const filename = this.osuInner.general.audioFilename;
|
||||||
|
// biome-ignore lint/style/noNonNullAssertion: <explanation>
|
||||||
|
return this.set.assets.get(filename)!;
|
||||||
|
}
|
||||||
|
|
||||||
public background(): Blob {
|
public background(): Blob {
|
||||||
// biome-ignore lint/style/noNonNullAssertion: <explanation>
|
// biome-ignore lint/style/noNonNullAssertion: <explanation>
|
||||||
const filename = this.osuInner.events.backgroundPath!;
|
const filename = this.osuInner.events.backgroundPath!;
|
||||||
|
|
7
tsconfig.json
Normal file
7
tsconfig.json
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ESNext",
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "Bundler"
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,14 @@
|
||||||
|
import { analyzer } from "vite-bundle-analyzer";
|
||||||
import { defineConfig } from "vite";
|
import { defineConfig } from "vite";
|
||||||
import { nodePolyfills } from "vite-plugin-node-polyfills";
|
import { nodePolyfills } from "vite-plugin-node-polyfills";
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [],
|
build: {
|
||||||
|
lib: {
|
||||||
|
entry: "src/index.ts",
|
||||||
|
name: "osuplayer",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [analyzer()],
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue