MusicQuiz ๐ŸŽต

FieldValue
Statusโœ… Live (Practice + Arena relay)
Version1.0.0
Pathgames/music-quiz/
Typeiframe-themeable
Players1โ€“8
Livefunday.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.js talks to the host via postMessage.
  • Arena multiplayer uses Fundayโ€™s platform lobby plus the generic_match Nakama relay through websim-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.

  1. Drop the files into games/<slug>/ (slug = lowercase-dashes, e.g. music-quiz).
  2. Write funday-plugin.json โ€” integrationType: "iframe-themeable", entryPoint: "index.html", nested metadata (title, description, genre, min/maxPlayers, thumbnail). See below.
  3. Add a thumbnail (thumbnail.png) โ€” the manifest validator requires the file to exist.
  4. 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.
  5. 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.
  6. Add funday-bridge.js and <script src="funday-bridge.js"> to index.html to 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.

WhenMessageWhy
Host says hellohost โ†’ funday:handshakeplatform announces itself
We answergame โ†’ funday:ack + game:readystops the handshake, says โ€œloadedโ€
Each questiongame โ†’ funday:nav:settop-bar HUD: Question 3/10 ยท Score 1200
On loadgame โ†’ funday:dock:setdock buttons: Restart / Settings / Fullscreen
Game overgame โ†’ funday:score-submittedwrites to the music-quiz_high_score leaderboard
Host themehost โ†’ funday:theme-injectwe mirror it onto data-theme (light/dark)
Host pausehost โ†’ funday:pause / funday:resumewe 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

#ChangeWhy
1game-core.js: websim dependency removed from the Practice pathPractice boots immediately without a websim runtime
2websim-multiplayer.js: replaced websim transport with a Funday Nakama-relay adapterArena mode can use platform lobby + generic_match
3funday-bridge.js: injects platform match/session context into the iframeHost shell owns lobby, match, theme, pause/resume, and score submission
4DaisyUI + Google Fonts + Feather icons vendored into vendor/self-contained, no external CDN at runtime
5Added data-theme=\"dark\" to <html>the game never set it โ†’ DaisyUI surfaces were invisible (transparent)
6Added leaderboard metadata and score-submitted bridge eventhigh 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 / dirWhat it is
index.htmlentry โ€” importmap + vendored deps + bridge
funday-bridge.jsFunday-added โ€” the bridge + game glue
funday-plugin.jsonthe manifest Funday reads
thumbnail.pnglibrary card image
vendor/local DaisyUI / fonts / Feather (no external calls)
question-api.jsOpenTDB fetch + offline fallback bank
game-core.js, game-modes.js, game-ui.jsengine / modes / DOM
scoring-system.js, timer-system.js, joker-*.jsscoring, timer, lifelines
multiplayer*.js, websim-multiplayer.js, reactions.jsArena 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-quiz

No 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:

  1. Platform lobby/GameDrawer to create or join a match.
  2. games/_platform/server/game_registry.ts mapping music-quiz โ†’ generic_match.
  3. websim-multiplayer.js as a drop-in adapter that keeps the original game API but relays quiz state over Nakama opcode messages.
  4. 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 to position:relative; z-index:0 โ€” for the capture only, never in the shipped file.
  • Third-party APIs are allowed; platform URLs are not. Calling opentdb.com is fine; hardcoding funday.gg / nakama.funday.gg fails 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).