A browser-based 3D chart previewer for World Dai Star, powered by the wds-editor preview core.
Sirius Chart Viewer brings the chart preview experience of wds-editor to the browser.
Instead of reimplementing the renderer in JavaScript, the project compiles the upstream C++ preview core to WebAssembly with Emscripten and reproduces its rendering pipeline on top of WebGL2. Playback timing and hit sound scheduling are handled through the Web Audio API, while the standalone UI and embeddable component are built with Vue 3 + TypeScript.
The goal is to keep browser previews visually and behaviorally close to the desktop editor while remaining easy to deploy and embed into other web applications.
This project is a viewer only. It does not provide chart editing functionality.
- Browser-native chart preview with no desktop application required.
- Upstream preview-core reuse from
wds-editorthrough a Git submodule. - Supports
.wdschart, official.csv, and.suscharts. - Optional music, jacket/cover image, and official
music_config.csv. - Rendering behavior designed to match the desktop preview, including:
- stage and note rendering;
- split lines and effects;
- combo display;
- judgment text;
- hit-effect timing.
- Web Audio based playback clock and scheduled hit sounds.
- Playback rate control from 0.5× to 2×.
- Adjustable note speed, lane cover/start offset, note thickness, split-line opacity, music volume, and SFX volume.
- Keyboard shortcuts, seeking, fullscreen support, and mobile-responsive controls.
- Can be built as:
- a standalone static web page;
- an embeddable Vue component/library.
- URL-based chart loading for integration with other services.
| Input | Supported formats / behavior |
|---|---|
| Chart | .wdschart, official .csv, .sus |
| Music | Browser-decodable audio such as OGG, MP3, WAV, M4A/AAC, FLAC, Opus, WebM |
| Cover | PNG, JPEG, WebP, GIF, AVIF, BMP and other browser-decodable images |
| Timing config | Official music_config.csv, using DelaySeconds |
Audio and image codec support ultimately depends on the browser.
| Layer | Technology |
|---|---|
| UI | Vue 3, TypeScript |
| Web build | Vite |
| Preview core | C++17 from wds-editor |
| Native-to-web toolchain | Emscripten + CMake |
| Rendering | WebGL2 |
| Audio / timing | Web Audio API |
| CI | GitHub Actions |
- Node.js 20+
- Emscripten / emsdk
- CMake 3.20+
- Ninja is recommended
Clone the repository with submodules:
git clone --recursive https://github.com/TeamOpenSirius/SiriusChartViewer.git
cd SiriusChartViewer
npm ci
npm run devIf the repository was cloned without submodules:
git submodule update --init --recursiveThe development command performs three steps:
- synchronizes hit-sound assets from
wds-editor; - compiles the C++ preview core to WebAssembly;
- starts the Vite development server.
scripts/build-wasm.mjs searches for Emscripten in this order:
- the
EMSDKenvironment variable; emccavailable onPATH;C:/SDK/emsc/emsdkon Windows.
To build a debug WASM version with verbose WDS_LOG output:
node scripts/build-wasm.mjs --debugThe debug build directory is build/wasm-debug/.
| Command | Description |
|---|---|
npm run dev |
Sync assets, build WASM, then start Vite |
npm run build |
Build the standalone site into dist/ |
npm run preview |
Preview the production Vite build |
npm run typecheck |
Run Vue/TypeScript type checking |
npm run sync:assets |
Copy runtime hit-sound assets from the submodule |
npm run build:wasm |
Compile the native preview core into public/wasm/ |
npm run build:lib |
Build the embeddable library into dist-lib/ |
The standalone Vite build uses a relative base path, so dist/ can be deployed under an arbitrary subdirectory.
Open or drag files into the page. Multiple related files can be selected at once.
Typical inputs are:
expert.csv
song.mp3
cover.jpg
music_config.csv
The page automatically separates chart, audio, cover, and timing configuration files.
| Key | Action |
|---|---|
Space |
Play / pause |
← / → |
Seek backward / forward 5 seconds |
Shift + ← / Shift + → |
Seek backward / forward 1 second |
Home |
Return to chart start |
F |
Toggle fullscreen |
| Double-click stage | Toggle fullscreen |
On browsers without element fullscreen support, such as iOS Safari, the component falls back to filling the viewport.
The standalone page can load remote resources directly:
index.html?chart=<chart-url>&music=<music-url>&cover=<cover-url>&config=<music_config-url>&name=<display-name>&t=<start-seconds>
| Parameter | Meaning |
|---|---|
chart |
Chart URL |
music |
Optional music URL |
cover |
Optional jacket/cover URL |
config |
Optional music_config.csv URL |
name |
Optional chart file name / display name |
t |
Optional initial playback position in seconds |
Remote resources must permit browser access through CORS.
Build the library:
npm run build:libOutput:
dist-lib/
├── sirius-chart-viewer.js
├── sirius-chart-viewer.css
├── types/
└── assets/
├── wasm/
│ ├── sirius-viewer.js
│ ├── sirius-viewer.wasm
│ └── sirius-viewer.data
└── effects/
Vue is treated as a peer dependency. The runtime assets/ directory must be hosted by the integrating application.
The package is currently marked
privateinpackage.json; the documented workflow is to builddist-lib/from the repository rather than install it from npm.
<script setup lang="ts">
import { SiriusChartViewer } from 'sirius-chart-viewer'
import 'sirius-chart-viewer/style.css'
</script>
<template>
<div style="height: 480px">
<SiriusChartViewer
:chart="chartBlob"
chart-name="expert.csv"
:music="'/api/song/audio'"
:cover="'/api/song/cover'"
asset-base="/sirius-chart-viewer/"
autoplay
@loaded="info => console.log(info)"
@error="console.error"
/>
</div>
</template>The component fills its parent container, so the parent should provide an explicit height.
| Prop | Type / purpose |
|---|---|
chart |
File, Blob, ArrayBuffer, typed-array view, or URL string |
chart-name |
File name used to detect .wdschart, .csv, or .sus; optional when the source already has a name |
music |
Optional music source using the same source types |
music-config |
Optional official music_config.csv |
cover |
Optional jacket/cover image |
asset-base |
Base URL containing wasm/ and effects/; defaults to /sirius-chart-viewer/ |
autoplay |
Start playback after loading, subject to browser autoplay policy |
fetch-init |
Optional fetch() options for URL sources, such as authentication headers |
| Event | Payload |
|---|---|
ready |
None — preview engine initialized |
loaded |
ChartInfo containing note count and timing information |
error |
Error message string |
ended |
None — playback reached the end |
Using a Vue template ref, the component exposes:
play()
pause()
toggle()
seek(seconds)It also exposes the underlying ChartViewer instance for advanced integrations.
If the host page uses CSP, WebAssembly execution generally requires:
script-src 'wasm-unsafe-eval'
Adjust the full policy according to the host application's own security requirements.
flowchart LR
UI["Vue UI / SiriusChartViewer"] --> Viewer["ChartViewer glue"]
Audio["AudioTransport<br/>Web Audio clock"] --> Viewer
Viewer --> WASM["wds-editor C++ core<br/>WebAssembly"]
WASM --> Preview["PlaybackPreviewView"]
Preview --> Batch["DrawBatch / draw commands"]
Batch --> GL["GlRenderer<br/>WebGL2"]
WASM --> SFX["SFX command queue"]
SFX --> Player["SfxPlayer<br/>Web Audio scheduling"]
At runtime, the audible music clock drives the preview timeline. The WebAssembly side applies the chart timeline and produces rendering commands plus SFX events. JavaScript then renders those commands through WebGL2 and schedules hit sounds against the Web Audio clock.
This split allows the project to reuse the mature upstream chart/preview logic without carrying the desktop editor's Vulkan, BASS, or UI dependencies into the browser.
| Path | Purpose |
|---|---|
third_party/wds-editor/ |
Upstream editor Git submodule; kept unmodified |
native/CMakeLists.txt |
Builds selected upstream C++ sources with Emscripten |
native/shim/ |
Browser-side replacement headers for desktop-only dependencies |
native/src/viewer.cpp |
Exposes the wv_* bridge API used by JavaScript |
native/src/web_renderer.cpp |
Web implementation of the renderer command path |
native/src/split_colors.cpp |
Split-line color logic adapted from upstream editor code |
src/lib/viewer.ts |
High-level glue between WASM, WebGL2, and Web Audio |
src/lib/glRenderer.ts |
WebGL2 rendering backend |
src/lib/audioTransport.ts |
Playback clock and music transport |
src/lib/sfx.ts |
Hit-sound scheduling |
src/components/SiriusChartViewer.vue |
Embeddable player component |
src/App.vue |
Standalone viewer application |
scripts/ |
WASM build, asset sync, and library packaging scripts |
The skin PNG files from wds-editor are embedded into sirius-viewer.data during the Emscripten build. Hit-sound assets are copied separately into public/effects/.
The project intentionally reuses upstream source files rather than maintaining a forked copy.
To update the submodule:
git -C third_party/wds-editor pull origin main
npm run build:wasmIf compilation breaks after an upstream update, the most likely cause is an API change around PlaybackPreviewView or another reused renderer interface. Update the compatibility code under native/shim/ or the small web-specific bridge implementations as needed.
A modern browser with the following features is required:
- WebAssembly;
- WebGL2;
- Web Audio API;
- ES modules.
Recent Chromium, Firefox, and Safari releases are the intended targets. Actual audio codec support varies by browser and operating system.
- Hold-body SFX gating is updated per frame (roughly 16 ms) rather than reproducing the exact BASS hold-gate edge behavior from the desktop editor.
.wdsprojectis not supported because it represents a multi-file project; load its chart and music files directly instead.- This project is a previewer, not an editor.
- Hit SFX assets are OGG. Older Safari versions without Ogg Vorbis support will not play hit sounds, although music playback may still work with supported codecs.
- Browser autoplay policies may block
autoplayuntil the user interacts with the page.
GitHub Actions builds the project on pushes to main, version tags, and pull requests. The workflow builds both:
dist/— standalone site;dist-lib/— embeddable component package.
Both directories are uploaded as workflow artifacts.
Issues and pull requests are welcome.
For changes touching the preview core integration, prefer keeping third_party/wds-editor unmodified and implementing browser-specific compatibility in native/shim/ or native/src/. This keeps upstream updates easier to track.
The source code in this repository is licensed under GNU GPL v3 only (GPL-3.0-only). See LICENSE.
wds-editor is included as a Git submodule and is governed by its own repository and licensing terms.
This is an unofficial community project. World Dai Star and related names, game content, artwork, audio, and other assets belong to their respective rights holders. This project is not affiliated with or endorsed by the official game operators or publishers.
