MusicQuiz ๐ต
| Field | Value |
|---|---|
| Status | โ Live (Practice + Arena relay) |
| Version | 1.0.0 |
| Path | games/music-quiz/ |
| Type | iframe-themeable |
| Players | 1โ8 |
| Live | funday.gg/play/music-quiz |
A fast trivia quiz: 10 questions, beat-the-clock scoring, lifelines (โjokersโ), streaks. Questions come from the free Open Trivia DB. It started life as a websim project and was ported to run cleanly on Funday.
How it works in 10 seconds
Funday play page โโiframeโโโบ /games/assets/music-quiz/?embed=1
โฒ โ
โ postMessage (the bridge) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
theme, pause/resume ack, ready, HUD, score
- Itโs a folder of HTML/JS/CSS in
games/music-quiz/. - Funday serves it at runtime from that folder โ no game build step.
funday-bridge.jstalks to the host viapostMessage.- Arena multiplayer uses Fundayโs platform lobby plus the
generic_matchNakama relay throughwebsim-multiplayer.js; Practice mode stays client-side.
The Recipe ๐ณ (repeat this for ANY websim game)
A websim export is a self-contained web app. Turning it into a Funday game is usually 6 boring steps. If the game has multiplayer, replace websim rooms with the Funday bridge + Nakama relay instead of faking or disabling it.
- Drop the files into
games/<slug>/(slug = lowercase-dashes, e.g.music-quiz). - Write
funday-plugin.jsonโintegrationType: "iframe-themeable",entryPoint: "index.html", nestedmetadata(title, description, genre, min/maxPlayers, thumbnail). See below. - Add a thumbnail (
thumbnail.png) โ the manifest validator requires the file to exist. - Rip out or replace websim. Anything using
WebsimSocket,window.websim, websim rooms/AI must be removed or routed through Funday APIs โ websim globals do not exist on Funday. - Vendor external CDNs into a local
vendor/folder (DaisyUI, fonts, icons). A Funday game should make zero off-platform network calls for its own assets. - Add
funday-bridge.jsand<script src="funday-bridge.js">toindex.htmlto talk to the host.
Then verify (2 commands) and itโs live. Thatโs it.
The Bridge ๐ (funday-bridge.js)
The bridge is a small, self-contained script. It speaks FundayBridge v1 over postMessage
and is the only allowed channel between a game and the platform. No platform imports, ever.
| When | Message | Why |
|---|---|---|
| Host says hello | host โ funday:handshake | platform announces itself |
| We answer | game โ funday:ack + game:ready | stops the handshake, says โloadedโ |
| Each question | game โ funday:nav:set | top-bar HUD: Question 3/10 ยท Score 1200 |
| On load | game โ funday:dock:set | dock buttons: Restart / Settings / Fullscreen |
| Game over | game โ funday:score-submitted | writes to the music-quiz_high_score leaderboard |
| Host theme | host โ funday:theme-inject | we mirror it onto data-theme (light/dark) |
| Host pause | host โ funday:pause / funday:resume | we pause/resume the question timer |
ELI5: the game and the platform are in two different windows. They canโt call each
otherโs functions โ they can only mail letters (postMessage). The bridge is the mailroom.
What we changed from the websim original
| # | Change | Why |
|---|---|---|
| 1 | game-core.js: websim dependency removed from the Practice path | Practice boots immediately without a websim runtime |
| 2 | websim-multiplayer.js: replaced websim transport with a Funday Nakama-relay adapter | Arena mode can use platform lobby + generic_match |
| 3 | funday-bridge.js: injects platform match/session context into the iframe | Host shell owns lobby, match, theme, pause/resume, and score submission |
| 4 | DaisyUI + Google Fonts + Feather icons vendored into vendor/ | self-contained, no external CDN at runtime |
| 5 | Added data-theme=\"dark\" to <html> | the game never set it โ DaisyUI surfaces were invisible (transparent) |
| 6 | Added leaderboard metadata and score-submitted bridge event | high score writes to music-quiz_high_score |
Everything else (scoring, timer, jokers, animations, themes, the OpenTDB question API) is the original game, untouched.
File map
| File / dir | What it is |
|---|---|
index.html | entry โ importmap + vendored deps + bridge |
funday-bridge.js | Funday-added โ the bridge + game glue |
funday-plugin.json | the manifest Funday reads |
thumbnail.png | library card image |
vendor/ | local DaisyUI / fonts / Feather (no external calls) |
question-api.js | OpenTDB fetch + offline fallback bank |
game-core.js, game-modes.js, game-ui.js | engine / modes / DOM |
scoring-system.js, timer-system.js, joker-*.js | scoring, timer, lifelines |
multiplayer*.js, websim-multiplayer.js, reactions.js | Arena multiplayer UI + Funday Nakama relay adapter |
Manifest essentials (funday-plugin.json)
{
"id": "music-quiz",
"integrationType": "iframe-themeable",
"entryPoint": "index.html",
"status": "available",
"metadata": {
"title": "MusicQuiz",
"minPlayers": 1,
"maxPlayers": 8,
"thumbnail": "thumbnail.png"
},
"leaderboards": {
"default": "music-quiz_high_score",
"configs": {
"music-quiz_high_score": { "type": "high_score", "sortOrder": "desc", "operator": "best" }
}
}
}Run & verify โ
# from funday/
node scripts/validate-game-manifest.mjs music-quiz # โ VALID
cd frontend && node ../scripts/check-game-boundaries.mjs # โ no violations for music-quizNo build or restart needed: iframe-themeable games are served at runtime from
GAME_PLUGINS_DIR and the plugin list is re-scanned on every request. Edit a file โ reload the page.
Verified 2026-06-09: boots with 0 page errors, real OpenTDB questions load, answering scores
and advances all 10 questions, bridge handshake + theme + score-submitted confirmed end-to-end.
Multiplayer Arena
The original websim version used websim rooms. The Funday version now uses:
- Platform lobby/GameDrawer to create or join a match.
games/_platform/server/game_registry.tsmappingmusic-quizโgeneric_match.websim-multiplayer.jsas a drop-in adapter that keeps the original game API but relays quiz state over Nakama opcode messages.- Practice mode as the instant solo/client-side path.
This is a relay model, not an authoritative quiz server: the host coordinates selected questions and room state, and generic_match rebroadcasts messages to participants.
Gotchas (learned the hard way) โ ๏ธ
- DaisyUI needs
data-theme. With none set, every surface uses undefined color vars and renders transparent โ the whole game looks blank. Always set<html data-theme="...">. - Headless screenshots can lie. The gameโs background is
position:fixed; z-index:-1. Real browsers render it fine; headless Chromium (SwiftShader) drops everything inside that layer, so captures look blank. To screenshot in headless, override it toposition:relative; z-index:0โ for the capture only, never in the shipped file. - Third-party APIs are allowed; platform URLs are not. Calling
opentdb.comis fine; hardcodingfunday.gg/nakama.funday.ggfails the boundary check.
Credits
Original MusicQuiz by rebeljam (built on websim). Questions: Open Trivia DB (CC BY-SA 4.0). Feather icons (MIT), DaisyUI (MIT).