Finalize part3 performance pass with Worker preprocessing, WebAssembly note math, and activation diagnostics#16
Conversation
Agent-Logs-Url: https://github.com/7effrey89/PianoHero/sessions/6d3fb3f9-ff53-4148-8d93-687ef6486650 Co-authored-by: 7effrey89 <30802073+7effrey89@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR completes the “part3 performance pass” by moving song preprocessing work off the main thread into a Web Worker and introducing a WebAssembly-backed fast path for repeated note-height calculations during rendering.
Changes:
- Added
performance-worker.jsto precompute BPM, merged notes for simple mode, and durations in a worker. - Updated
app.jsto request/apply worker-precomputed caches and to use WASM-backed helpers (with JS fallback) for note height math. - Bumped
app.jscache-bust version inindex.html.
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| performance-worker.js | New worker that precomputes BPM, simple-mode merged notes, and durations. |
| app.js | Initializes worker + WASM, adds caches for precompute output, and routes hot-path note height math through shared helpers. |
| index.html | Updates app.js query-string version to pick up the runtime changes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| async _precomputeSongData(notes) { | ||
| const safeNotes = Array.isArray(notes) ? notes : []; | ||
| this._simpleModeCache = null; | ||
| this._durationCache = null; | ||
| let bpm = this.estimateBPM(safeNotes); | ||
| let normalDuration = 0; | ||
| for (let i = 0; i < safeNotes.length; i++) { | ||
| const n = safeNotes[i]; | ||
| const end = n.time + (n.duration || 0.15); | ||
| if (end > normalDuration) normalDuration = end; | ||
| } |
| return new Promise((resolve, reject) => { | ||
| const id = ++this._perfWorkerReqId; | ||
| this._perfWorkerPending.set(id, { resolve, reject }); | ||
| this._perfWorker.postMessage({ id, task, payload }); |
|
@copilot Fix according to the pr reviews |
Agent-Logs-Url: https://github.com/7effrey89/PianoHero/sessions/e48db5e3-aec8-46a0-995d-79eb8be859eb Co-authored-by: 7effrey89 <30802073+7effrey89@users.noreply.github.com>
Implemented the review fixes in
I couldn’t attach a UI screenshot here because the Playwright browser profile is locked in this environment ( |
|
@copilot how would we verify that all the optimizations have been implemented and activated? |
Good callout — with dense songs, the biggest cost can still be per-frame draw/update work, so load-time optimizations may feel subtle during playback. To verify optimizations are active right now:
If you want, I can add a small debug indicator (e.g., in settings or console) showing |
|
@copilot yws please do that |
Agent-Logs-Url: https://github.com/7effrey89/PianoHero/sessions/603cfdde-d889-4273-b67b-29725238cc9f Co-authored-by: 7effrey89 <30802073+7effrey89@users.noreply.github.com>
Implemented in Added a live diagnostics indicator showing Worker/WASM activation state and precompute mode/time, plus console timing logs per precompute run. |
|
ADD to features and readme about all these optimization from previous and current pr and how to verify their activation @copilot |
Agent-Logs-Url: https://github.com/7effrey89/PianoHero/sessions/4d64e3dc-10f1-4dff-8bff-0553a6f3c2fe Co-authored-by: 7effrey89 <30802073+7effrey89@users.noreply.github.com>
Implemented in Added documentation in both |


This PR completes the remaining optimization work from the prior performance pass by offloading heavy note preprocessing and adding a WebAssembly-backed fast path for repeated note-height math. Existing GPU note rendering remains in place and is now paired with lower main-thread preprocessing cost, plus runtime diagnostics to verify optimization activation.
Web Worker offload for song preprocessing
performance-worker.jsto precompute:app.jsnow asynchronously requests this precompute during song load/upload flows and applies cached outputs inapplyGameMode().postMessagefailure and request timeout handling to avoid stuck pending tasks.WebAssembly hot-path optimization
note-math.wasmwith exported math functions for note height calculation.app.js.Math.max(12, dur * noteSpeed * speed...)logic in hot render/update paths with shared helpers.Mode/duration caching integration
_simpleModeCacheand_durationCacheto avoid recomputing merged-note timelines on mode switches.applyGameMode()now consumes cached precompute output when available.Activation/verification diagnostics
init/ready/error/unsupported)init/ready/error/fetch-failed/unsupported)worker/mixed/fallback) and elapsed timeAsset wiring
app.jscache-bust version inindex.htmlto pick up runtime changes.