feedBack/plugins/minigames
Byron Gamatos b123ab3258
fix(minigames): drain legacy slopsmith pending queue + alias SDK (#578)
After the slopsmith→feedBack rename (#537) the minigames SDK publishes
window.feedBackMinigames and only drains window.__feedBackMinigamesPending.
Minigame plugins that still use the pre-rename shim register against
window.slopsmithMinigames and queue to window.__slopsmithMinigamesPending
when the SDK isn't up yet, so their specs are stranded in the legacy queue
and never register. In v3, FeedBarcade renders those games as non-launchable
"Loading…" tiles that do nothing on click (the tile itself comes from the
server registry, so it appears even though the JS spec never registered).

Publish window.slopsmithMinigames as an alias and drain the legacy pending
queue too (register() is keyed on spec.id, so double-queued specs register
once). Also fire the legacy slopsmith-minigames-ready event. Bump the plugin
version so the desktop renderer cache-busts the updated screen.js.

This rescues every not-yet-migrated minigame plugin, including community
ones we don't control.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 16:30:00 +02:00
..
plugin.json fix(minigames): drain legacy slopsmith pending queue + alias SDK (#578) 2026-06-23 16:30:00 +02:00
README.md rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00
routes.py rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00
screen.html rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00
screen.js fix(minigames): drain legacy slopsmith pending queue + alias SDK (#578) 2026-06-23 16:30:00 +02:00
settings.html rename: slopsmith → feedBack, byron → got-feedBack (#537) 2026-06-23 11:03:01 +02:00

feedBack-plugin-minigames

The minigame framework for FeedBack.

This plugin provides:

  • A Minigames hub screen that discovers every installed minigame plugin and lists them as tiles with leaderboards.
  • A shared profile (XP, level, unlocks, totals) that aggregates runs across every minigame.
  • A JS SDK exposed at window.feedBackMinigames that minigame plugins use to access scoring, HUD primitives, run persistence, and a scheduler — so individual minigames do not need their own DSP or backend.

Writing a minigame

A minigame is a standard FeedBack plugin that:

  1. Adds a minigame block to its plugin.json:

    {
      "id": "my_game",
      "name": "My Game",
      "version": "0.1.0",
      "script": "game.js",
      "minigame": {
        "title": "My Game",
        "tagline": "Short pitch",
        "type": "chart-free",
        "scoring": "pitch-continuous",
        "thumbnail": "thumb.png"
      }
    }
    
  2. On script load, registers itself with the SDK using the safe late-binding pattern (minigame plugins may load before the SDK; the pending queue handles both orderings — the SDK drains it on init, and the feedBack-minigames-ready event is an alternative for plugins that prefer event-driven registration):

    Important: spec.id must exactly match the id field in plugin.json. The backend registry uses plugin_id (sourced from plugin.json) and the hub UI merges manifest metadata (title, tagline, thumbnail, modifiers) by that key. If spec.id and plugin.json id diverge, runs and leaderboard data will be attributed to an unrecognised game and display metadata (title, thumbnail) will fall back to JS-spec values rather than the richer manifest values.

    const spec = {
      id: 'my_game',
      start: ({ container, modifiers, sdk }) => { /* mount game into container */ },
      stop:  () => { /* tear down */ },
    };
    
    if (window.feedBackMinigames) {
      window.feedBackMinigames.register(spec);
    } else {
      (window.__feedBackMinigamesPending = window.__feedBackMinigamesPending || []).push(spec);
    }
    
  3. Calls window.feedBackMinigames.end({ score, durationMs, modifiers, meta }) when the run ends.

See feedBack-plugin-flappy-bend for a working example.

SDK reference

window.feedBackMinigames exposes:

  • register(spec) — declare a minigame
  • start(gameId, opts) / end(result) — lifecycle
  • scoring.createContinuous(opts) — emits per-frame pitch (YIN, ~60 Hz)
  • scoring.createDiscrete(opts) — wraps createNoteDetector, emits hit/miss
  • scoring.createChord(opts) — full chord scorer (delegates to note_detect)
  • ui.mountHUD(html) / ui.runSummary(result) / ui.modifierPicker(defs)
  • submitRun(...) / getLeaderboard(...) / getProfile()
  • scheduler.every(ms, cb) / in(ms, cb) / cancel(id)

Dependencies

  • feedBack-plugin-notedetect >= 1.10.0 — required for discrete/chord scoring modes (continuous mode is self-contained).