joshwcomeau / beatmapper Goto Github PK
View Code? Open in Web Editor NEWA 3D editor for creating Beat Saber maps
Home Page: https://beatmapper.app
License: MIT License
A 3D editor for creating Beat Saber maps
Home Page: https://beatmapper.app
License: MIT License
Let users come up with fun names for difficulties
I save often, and I have to redo the 3D camera view everytime I come back to the editor.
Would be nice if it kept the view as it was before :)
Often, mappers will start with the hardest difficulty they want to map (eg. Ex+) and then "map down" to easier difficulties, starting with the full map and removing/tweaking blocks.
Relatedly, someone might want to convert an Ex map to Ex+ if it winds up more difficult than they expected.
I should first add the ability to "copy" a difficulty, and then an easy tweak should be to "move" a difficulty (or, at the very least, someone could copy it and then delete the original)
Unless I am mistaken, but i couldnt figure out how to rotate the block with click and drag (on Chrome).
Doc says:
Finally, you can click and drag to dynamically select a block direction. This is my personal favourite way to place blocks:
Bookmarks are a handy feature in other editors - you can bookmark specific bars/beats, and jump between bookmarks easily.
I think the UI for showing bookmarks could be little colored flags over the ScrubbableWaveform at the bottom. You could click the flag to jump to that point, and maybe hover over it to expand a label for it?
For creating bookmarks, I imagine it could just be the B
key, which'd prompt the user to enter a label, and create it for the cursor's current position.
When reloading a map, the selected notes are reloaded too. This feels dangerous, since someone may not realize notes are already selected. It could cause problems, if they try to copy/paste, with some other random notes being duplicated.
I can solve this by running a map
on the notes when loading, and forcing selected: false
Recently I found an amazing guide that covers how to map down for lesser difficulties (eg if you have an Ex+ song and want to map Normal). One of the key things is just managing the number of notes per second (NPS). The doc lists the following ranges as guidelines:
0.9 - 1.3 Easy
1.4 - 1.8 Normal
1.8 - 2.7 Hard
2.4 - 3.7 Expert
It would be good to add a "Note Per Second" display somewhere in the Notes view. As a bonus, it would be good if it had a small warning when the player was outside the ranges provided.
Set the precision to 1/8 beat
Place for example a block on 3/8 of the beat. The click wont sound for this block.
Right now I have 1 type of prompt. It's big and blocking and pretty annoying.
Sometimes this is a good UI element because I really need to let someone know something. Other times, though, it's overkill.
It'd be good to add a smaller popup in the corner of the screen, like a "tip of the day" type UI. Ideally it would support a queue of messages and you could tab through them with arrows, or click to dismiss them all.
MappingExtension maps aren't correctly viewable in Beatmapper. I should still allow folks to import (maybe they just want to see the lighting), but whenever there's an extension dependency, I should warn that Beatmapper isn't set up to deal with mods.
Sometimes, when trying to light the very tail of a window, it's tough since playing the song will jump to the next window.
I should add a toggle to "lock" and loop playback within the current window.
I'm currently working on rudimentary Mapping Extensions support. This issue is a list of things I don't want to forget about:
rowHeight
I don't need to worry about being able to stagger / offsetI should have low/medium/high video options.
Things they could tweak:
Wifey and I put together a song for our Quest but we cannot get BeatOn or Mediocre Mapper to parse files that Beatmapper outputs. The file passes JSON validation but yeah can't load it anywhere ๐ฅ
Here is an example:
https://drive.google.com/file/d/1TYr1VeG-dn34UCflV8SwATOP5YRFpj0J/view?usp=sharing
Recently I learned that other keyboard layouts, like the French AZERTY one, don't remap the controls properly. Because of that, the Ctrl+Z shortcut on QWERTY becomes Ctrl+W on this layout, which just closes the Chrome tab :(
While the best solution would be to allow people to remap shortcuts, that's also a lot of work. Plus, people might not know about the keyboard shortcuts. I should add onscreen buttons somewhere. Not sure where yet.
Options:
Also I should document it
The snapping intervals assume that the song is in 4/4, and so it's missing snapping editors like 1/3, 1/6, etc.
While a quick fix could be to just add those in, I feel like they'd be clutter in 95%+ of cases, so I think maybe we can have a little toggle beside the snapping select, to show/hide "extended" intervals?
Just suddenly, it has been making multiple blocks facing the same or different direction, causing a lot of lag. It creates so much lag that moving forward or backwards one beat takes up to 10 seconds each. This is probably because it is making one block for the direction on the side and then one to whichever direction my mouse is.
A couple times now I've changed the NJS of a map and forgotten to hit "save". I should warn users when they attempt to navigate away from this screen without saving.
I noticed when re-opening files with odd times (eg. 1/6th), they're ever-so-slightly rounded. This is a problem since it means you can "double-add" events, since they're not technically at the same time.
Checklist of cases to check:
(Currently the checked item are fixed in a working branch, not yet in master)
The data files that Beat Saber uses organizes the timing of blocks in terms of # of beats - if there's a block on the 5th kick in a house track, the data file would say that the block is on Beat 5. This is how other mappers treat it as well.
Beatmapper uses bars instead; that 5th kick is at the 2nd bar, so it's given the number 2.
The big reason for being different is that most music is synchronized around bars. It's common for many songs to have 16 or 32 bars of intro, 16-32 bars of breakdown, 16-32 bars of drop, etc. I used to DJ, and thinking in bars is a much more intuitive way to think about chunks of songs. Incidentally, DJ software uses bars as well, as does the editor in Stepmania (popular editor for another rhythm game, DDR).
In 4/4 time, you can just multiply the bars by 4 to get the beat, so you might be thinking that it doesn't actually matter. A 16-bar chunk is a 64-beat chunk, and so you can think in chunks of 64 instead of 16, and it's the same thing. The reason this doesn't work is time signatures; a 3/4 song will have 3 beats per bar, and suddenly that same 16-bar chunk is 48 beats.
This is one of those things where I recognize that there will be friction for folks coming from MM or other mappers, since it's different. The community thinks in beats, not bars, and it's weird that the editor uses a different system from the files it produces. I'm considering adding a toggle to allow the user to switch between bars and beats, but I'm hesitant to add any new feature that isn't obviously valuable for a lot of people.
So, please respond to this post with a ๐ if you feel like this feature would be helpful, or a ๐ if you don't think it's a big deal / not a priority. Thanks!
When uploading a map, Beatmapper expects it to be a direct .zip of the files, NOT in an enclosing folder. I've made the mistake a few times now where I zipped the enclosing folder, and Beatmapper throws a confusing error.
Ideally I should allow imports to be in a directory. At the very least, I should improve the error messaging.
A shocking number of people I've spoken to about this editor want it to be a downloadable desktop application.
I was initially resistant to this idea because I spent a lot of time making everything work in-browser, it wasn't an easy feat! And I do still want there to be a browser-based version; One of the big issues I had with MediocreMapper was the amount of friction to get started, I want my editor to be effortless to use, and downloading 100mb+ (as it would be, for an Electron app) is a burden.
But, I do see a few compelling advantages:
It shouldn't be that much trouble to create a desktop app (famous last words), as it would just be a thin electron wrapper around the page. I wouldn't take many (any?) steps to match desktop-app conventions, it would just be the same deal but in a nice wrapper.
Say you have a song already created that you load throught the main menu. If you import another version of that same song, it will warn you have a duplicate, you click yes to overwrite. However the editor is still loaded with the previous version.
When trying to open the website in Chromium I'm getting a black page with nothing in it. If I open in Firefox on the same box it does render and I can interact. When using the Chromium inspect I saw some errors on the console:
three.module.js:15829 THREE.WebGLRenderer 106
three.module.js:15963 THREE.WebGLRenderer: Error creating WebGL context.
three.module.js:15829 THREE.WebGLRenderer 106
three.module.js:15963 THREE.WebGLRenderer: Error creating WebGL context.
2
react-dom.production.min.js:4408 Error: Error creating WebGL context.
at new $i (three.module.js:15948)
at index.js:631
at Object.useState (react-dom.production.min.js:3560)
at useState (react.production.min.js:362)
at index.js:630
at $i (react-dom.production.min.js:3274)
at Mo (react-dom.production.min.js:3745)
at To (react-dom.production.min.js:3733)
at So (react-dom.production.min.js:3716)
at Lo (react-dom.production.min.js:4077)
three.module.js:15948 Uncaught (in promise) Error: Error creating WebGL context.
at new $i (three.module.js:15948)
at index.js:631
at Object.useState (react-dom.production.min.js:3560)
at useState (react.production.min.js:362)
at index.js:630
at $i (react-dom.production.min.js:3274)
at Mo (react-dom.production.min.js:3745)
at To (react-dom.production.min.js:3733)
at So (react-dom.production.min.js:3716)
at Lo (react-dom.production.min.js:4077)
If I expand out that first error I get:
three.module.js:15963 THREE.WebGLRenderer: Error creating WebGL context.
$i @ three.module.js:15963
(anonymous) @ index.js:631
useState @ react-dom.production.min.js:3560
useState @ react.production.min.js:362
(anonymous) @ index.js:630
$i @ react-dom.production.min.js:3274
Mo @ react-dom.production.min.js:3745
To @ react-dom.production.min.js:3733
So @ react-dom.production.min.js:3716
Lo @ react-dom.production.min.js:4077
qa @ react-dom.production.min.js:5514
Ya @ react-dom.production.min.js:5536
Ps @ react-dom.production.min.js:5958
Ms @ react-dom.production.min.js:5925
Ds @ react-dom.production.min.js:5992
notify @ Subscription.js:23
t.notifyNestedSubs @ Subscription.js:65
o.notifySubscribers @ Provider.js:59
t.handleChangeWrapper @ Subscription.js:70
v @ redux.js:213
(anonymous) @ backup.middleware.js:13
(anonymous) @ createMiddleware.js:98
(anonymous) @ demo.middleware.js:12
(anonymous) @ packaging.middleware.js:22
l @ runtime.js:45
(anonymous) @ runtime.js:264
e.<computed> @ runtime.js:98
r @ asyncToGenerator.js:3
s @ asyncToGenerator.js:25
(anonymous) @ asyncToGenerator.js:32
(anonymous) @ asyncToGenerator.js:21
(anonymous) @ packaging.middleware.js:20
(anonymous) @ selection.middleware.js:79
(anonymous) @ song.middleware.js:599
l @ runtime.js:45
(anonymous) @ runtime.js:264
e.<computed> @ runtime.js:98
r @ asyncToGenerator.js:3
s @ asyncToGenerator.js:25
(anonymous) @ asyncToGenerator.js:32
(anonymous) @ asyncToGenerator.js:21
(anonymous) @ song.middleware.js:70
(anonymous) @ syncState.js:177
(anonymous) @ index.js:11
(anonymous) @ createLoader.js:12
Promise.then (async)
(anonymous) @ createLoader.js:15
ue @ store.prod.js:20
(anonymous) @ index.js:9
p @ (index):1
(anonymous) @ index.js:6
p @ (index):1
l @ (index):1
e @ (index):1
(anonymous) @ main.b1496be2.chunk.js:1
There are also some warnings about the AudioContext:
audio.service.js:13 The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page. https://goo.gl/7K7WLu
Browser info:
Chromium 77.0.3865.120 (Official Build) Arch Linux (64-bit)
Revision 416d6d8013e9adb6dd33b0c12e7614ff403d1a94-refs/branch-heads/3865@{#884}
OS Linux
Please let me know if there's anything else I should test / logs to gather. This is not insurmountable as I can run this in Firefox, but figure you'd be interested in the error.
Saving is actually friggin slow. I should do it in a separate thread.
Do this magic in backup.middleware.js
Anywhere else that moving stuff off-thread could be good for performance?
Quick-select is an awesome feature but it selects EVERYTHING. Might be good to allow only selecting walls or notes within a section.
It happens frequently where I try and make a selection in select mode on the events view only to accidentally mouseover the waveform area and wind up in a totally different window.
Couple possible solutions:
Copy paste some notes. The pasted notes are up side down.
(on windows + chrome)
A few small tweaks related to "song details":
your-song (21)
-> your-song 2019-11-13 8:40am
There is currently no way to tweak the amount of space between bars; it's a fixed size. This fixed size might be a bit narrow for some (it's a trade-off between having a bird's eye view of a few bars vs. being able to distinguish rhythms in busy Expert and Expert+ sections).
I could implement it as a slider in the status bar, next to the slider for song speed?
I added a "Perf" option in the app settings!
Some stuff:
Using ctrl+1-4 switches between beat snap settings fine, but also switches between the selected item (block, mine, or wall). The intended result is that the beat snap setting would change, but the selected item type would remain unchanged.
Also, sorry about the edits, keep accidentally pressing extra keys on this keyboard.
When exactly 1 wall is selected, I show the option to change beat duration.
Initially I wanted to restrict it to only 1 wall since it multiple walls were selected, and those walls were of different lengths, it wasn't clear to me what I should do; felt like something someone might do by accident.
Now I think as long as at least 1 wall is selected, I should show that button. When the user clicks it, I can check if there are multiple lengths selected. If so, I can warn the user, but allow them to change the duration anyway.
A couple times I've had to switch out the audio file for a track I've already started, due to it having been too quiet or too long. Having the option to change the audio file, and the image as well, would save a lot of trouble in switching over.
Beat Saver, the common repository for BeatSaber songs, has a few restrictions:
Elle King
doesn't work (this is a restriction with BeatOn/MM, but maybe also affects Beat Saver since presumably they all use the same validation)Might be good to warn the user if their downloaded ZIP doesn't meet these requirements?
A few days ago, Beat Saver added schema validation - this means it checks the .dat
files to ensure that no superfluous properties are hung on it, outside of _customData
.
Right now there are a few cases where I add custom data in "illegal" places:
There may be others, I'll do some testing
Being able to flip the selected notes is good, and I know you can cut, copy, and paste using the standard keybinds, but it would be nice to be able to shift notes forwards and backwards as well, in the case of mistiming or even just accidental misplacement.
Aside from that, having buttons for cut, copy, and paste is generally a good idea, for those who don't realize the functionality already exists or somehow don't know those standard hotkeys.
I like to create a "Lightshow" difficulty, instead of easy, both for the (hypothetical?) folks who really care about lighting, but also for during creation, so I can see the lights explicitly.
Right now I'm doing it manually, which is tedious because I also want to include "decorative" mapping-extension walls. I wind up modifying the JSON to copy the obstacles over.
A setting in the Map Settings page should:
I should warn the user in 2 cases:
Creating an obstacle can sometimes trigger a crash. Not yet sure why. Digging into it!
Here's a quick video of it not loading: https://imgur.com/a/yrpLhZr
Looking in the DOM it looks like it just doesn't receive any HTML to display if there's unknown characters in the title. There's also no errors in the console when it won't load.
notes that are "in each other's way" can't be swapped.
____
R__B
____
Most of the time, unless it's from the start of the song, the audio from the song is a little out of sync with the blocks (while starting playing at any bar from the song other than the start).
Works fine on Explorer (which is not supported)
Some things to do to improve perf:
EditorStatusBar
on every tick. Make noteDensity
a connected component so only it has to updateEditorNavigationControls
are rendering often too for unknown reasonsOn larger windows, the right panel in the notes editor doesn't fill the vertical space, but you can't click on items in the environment anywhere in that column. This is frustrating and confusing for users.
The problem is that layout is hard when you don't have a flex parent, and flex parents block all clicks :/
In the discord, there are some stats people care about:
We can easily derive this kind of information, the trick is to figure out how to present it. It could be another tab, accessible from the left-hand sidebar, with some graphs and data viz stuff? Could be fun :o
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.