Files
feedBack/plugins/minigames
byrongamatosandClaude Opus 4.8 932c0b28ac rename: implement advertised backward-compat + prune dead community plugins
Address gaps where PR #537's "Backward compatibility" section was advertised
but not implemented, and clean up the community plugin list.

Env vars (FEEDBACK_* canonical, legacy SLOPSMITH_* honoured):
- New lib/env_compat.py (getenv_compat / env_flag_compat) + tests. server.py
  (_env_flag + all FEEDBACK_* reads), diagnostics_hardware, gp2midi and
  tailwind_rebuild now resolve the legacy alias, so existing SLOPSMITH_UI /
  SLOPSMITH_PLUGINS_DIR / etc. deployments keep working.
- Fix the rename collapsing plugins/__init__.py and minigames/routes.py from
  `FEEDBACK_PLUGINS_DIR or SLOPSMITH_PLUGINS_DIR` into a redundant
  `FEEDBACK_ or FEEDBACK_` (the fallback was silently lost).

Storage (app.js update-channel):
- Read feedBack-update-channel, fall back to legacy slopsmith-update-channel,
  and clear the legacy key on write — so a user's update-channel preference
  survives the rename instead of resetting to "stable".

Community plugin list (README): the rename rewrote third-party repo URLs we
don't own. Probed every one; their owners never renamed, so:
- Restore the 13 live community plugins to their real slopsmith-* names.
- Prune 6 that are 404 to the public (topkoa splitscreen/stems, OmikronApex
  tuner, Jafz2001 nam-rig-builder, DeathlySin song-preview, Erikcb91 shuffle).
- Fix a pre-existing Guitar Theory clone-command typo (nam-tone -> guitar-theory).

Verified: env_compat 7/7, JS 819/819, pytest 1690 collected / 0 import errors,
rename-sensitive + startup suites green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 10:43:48 +02:00
..
2026-06-16 18:47:13 +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).