title: BMS Scope of Work updatedAt: 1724302564000 #
Summary and goals #
Be-Music Source (BMS) is a file format for rhythm game charts
There are many BMS clients that parse BMS files allowing users to play songs. The current BMS ecosystem runs off sites known as Tables. These tables are arrays of Chart objects sorted by difficulty. Chart objects do not actually contain the chart, they instead contain and MD5 hash of the charts corresponding .bms file (as well as other metadata like title & author). It is up to the user to source this file & for their client to link the local file to the Chart object.
Sometimes, the metadata sent along with the Chart object includes a link to a site where the files can be downloaded. Other times, it's up to the user to hunt down packs or other users who already have the chart.
This app would list all Charts in a Table in a easy to navigate web application. With a majority of the data being driven by metadata provided by the table. Admin users are able to create a corresponding object in the apps database against a Chart, where extra metadata can be included, such as download links & descriptions.
Once a corresponding object has been created, even if the chart is no longer in the table; it can still be viewed on the website.
This site will attempt to mirror an osu-esque style of browsing charts:
Scope Breakdown #
Deliverables #
- An admin panel for managing database objects
- CRUD Tables
- CRUD Charts
- An end user application for viewing database objects
- Read Tables
- Read Charts
Timeline #
gantt
dateFormat YYYY-MM-DD
axisFormat %H-%M
title BMS Site timeline
section Initial Deploy
Stand up Baseline Core : a1, 2023-08-01, 1h
Deploy dev environment : after a1, 1h
Deploy prod environment : a2, after a1, 1h
Create public view webapp : a3, after a2, 2h
Deploy dev environment : deploy, after a3, 1h
Deploy prod environment : after a3, 1h
section Chart Object
Create Chart object : a4, after deploy, 1h
Allow admin to view chart objects : a5, after a4, 1h
Allow admin to edit chart objects : after a5, 1h
Allow admin to delete chart objects : after a5, 1h
section Table integration
Create localTable Object : a6, after deploy, 1h
Allow admin to configure localTable : a7, after a6, 2h
Scheduled job to ping table : a8, after a7, 1h
Link charts in system to table : after a8, 2h
Clean up dead link objects : after a8, 2h
Allow admin to view links : after a8, 2h
Technical Breakdown #
Personas #
- Admin User
- End User
External Integrations #
Table Objects #
Tables consist of two JSON files served from a URL: A header, and a body.
The header file contains the name of the table and assorted information.
The body file contains all charts in the table as an array.
There is no agreed upon schema in the community for these objects. However, most clients handle some defaults.
interface Header {
// The name of the table
name: string;
// The icon to show in clients (usually unicode shape)
symbol: string;
// URL or Path to the tables body
data_url: string;
// Order levels should be put in in clients, optional?
level_order?: string[];
// What mode (7k/14k/PMS/24k) is the table for, optional?
mode?: string;
}
type TableBody = {
// The title of the song
title: string;
// The songs artist
artist: string;
// MD5 hash used by clients to identify charts
md5: string;
// The charts level
level: string;
// The URL where the chart can be downloaded
url?: string;
// Another URL where the chart can be downloaded (stellabms only?)
url_diff?: string;
// SHA256 of the chart (stellabms only?)
sha256?: string;
// A comment by the uploader. Completely optional.
comment?: string;
}[]
Local Objects #
TableMirror Objects #
Still unsure how to tackle this one! Two potential ways to handle this. From what I've heard from other devs working with external tables is they're unreliable and sometimes require multiple pings to get data from. Was told about a good NodeJS library that handles all this written by zkldi. Handles a lot of existing edge cases too!
We should store basic metadata about the table to prevent spamming the table host when users view our site. When users view a table we should show extremely slim amounts of information as well as the related localChart objects in our system. If the user wishes to, they can load the remaining charts we do not have dedicated objects for.
OR
We should store clones of the tables locally to allow users to view the entire tables list of charts in one go. Charts with localChart data associated will be moved to the top &/ displayed separately.
LocalChart Objects #
A more complex object containing metadata about the chart. This could include an image, a brief description, links to more reliable downloads, or even note analysis to generate stats like density/chords. We could also include an array of charts that are similar or considered other difficulties.
Linking #
A chart can be in multiple tables, knowing only the chart we should be able to fetch tables its in, and knowing only the table, we should be able to fetch charts.
- Get all charts in table
- Get all tables for chart
If using dynamoDB a linking object would likely have to exist with an index for querying by table identifiers and an index for querying by chart identifiers. Since we expect to be querying this a lot it's worth making this an index
User activities #
Users almost always have read only permissions to all objects.
Admins can read and write
Admin User #
- Can manage external tables we fetch from
- Manage
TableMirrorobjects - Can create
LocalChartobjects based on table information - Can edit existing
LocalChartobjects - Can delete existing
LocalChartobjects
End User #
- Can view
LocalChartobjects related to a table - Can view an external table
- Can view
TableMirrorobjects - Can view all
LocalChartobjects paginated by creationDate
User requests #
Users will be triggering the bulk of requests in the system
Request system tables #
sequenceDiagram
User->>+API: Request all tables
API->>+DynamoDB: Get all tables
DynamoDB-->>-API: Return all tables
API-->>-User: Return all tables
Note right of User: User can browse tables in system
Request system localCharts #
sequenceDiagram
User->>+API: Request tables charts
API->>+DynamoDB: Get local chart objects
DynamoDB-->>-API: Return local chart objects
API-->>-User: Return charts
Note right of User: User can browse charts in system
Request table charts (non-local) #
sequenceDiagram
User->>+API: Request tables charts
API->>+Table: Request table charts
Table-->>-API: Return table charts
Note right of API: Mutate the returned chart objects
Note right of API: Potentially cache this?
API-->>-User: Return charts
Note right of User: User can view basic chart data
Implementation timeline #
Assuming baseline core starter
- Create admin app
- Create tableMirror object admin CRUD/UI
- Create localChart object admin CRUD/UI
- Create linking object admin CRUD
- Create auto linking function when tables are updated
- Design user table list screen
- Design user chart list screen
- Design user chart view screen
- Create end user app
- Allow end users to browse tables
- Allow end users to browse local charts
- Allow end users to view chart data
Complexities #
Things to keep in mind when scoping work out
- Charts can be in multiple tables
- Charts could potentially have many related charts in different tables
- Potentially store hardcoded tables/difficulties against charts to avoid extra queries. Alert admins via UI if their local table data conflicts with the saved data against a chart?
- Table data is inconsistent