MusicQuiz 🎵

FieldValue
Status✅ Live (Practice + Arena relay)
Version1.0.0
Pathgames/music-quiz/index/
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

flowchart LR
    Host["Funday Play Page (Host)"]
    Game["Game (/games/assets/music-quiz/?embed=1)"]

    Host -->|renders iframe| Game
    Game -->|postMessage: ack, ready, HUD, score| Host
    Host -->|postMessage: theme, pause/resume| Game
  • It’s a folder of HTML/JS/CSS in games/music-quiz/index/.
  • 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.jsonintegrationType: "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.generated.ts mapping music-quizgeneric_match (generated from manifest).
  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:0for 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).

0 items under this folder.

    Ask Docs

    AI assistant to help answer questions about the documentation. Answers are read-only and cite docs/source.

    Hi! How can I help you with the documentation today? Answers are read-only and cite docs/source.

    Ctrl+Enter to send