rename: slopsmith → feedBack, byron → got-feedBack (#537)

* Update GitHub repo references from feedback* to feedBack*

* rename: slopsmith -> feedBack, byron -> got-feedBack

Renames across the entire codebase:
- slopsmith/Slopsmith/SLOPSMITH/SlopSmith -> feedBack/FeedBack/FEEDBACK/FeedBack
- byron/Byron/Byrongamatos -> got-feedBack/got-feedBack/got-feedBack
- /home/byron/ -> /opt/got-feedBack/
- byron@ougsoft.com -> hi@got-feedBack.org
- github.com/byrongamatos/ -> github.com/got-feedback/
- com.byron. -> com.got-feedback.
- SLOPSMITH_ env vars -> FEEDBACK_ with backward-compat fallback
- Protocol/storage strings migrated with read-old/write-new pattern
- window.slopsmith JS API -> window.feedBack (canonical) + backward-compat alias

Refs: #rename-slopsmith

* rename: complete regen against current main + fix backward-compat alias

Regenerated the slopsmith->feedBack / byron->got-feedBack rename on top of
current main (3 commits had landed since the branch: #572/#554/#574),
resolving the four content conflicts in favour of main's newer content
(autoplay/auto-exit, accuracy-badge, Virtuoso re-home, feedpak badge).

Completion fixes on top of the mechanical rename:
- Re-apply rename to post-branch content the original rename never saw:
  window.slopsmith(.Tour) consumers in lessons.js / notifications.js /
  onboarding-tour.js, and the matching JS + python tests (autoplay_exit,
  progression_*, test_feedpak_extension FEEDBACK_* env vars). The test env
  vars now match server.py (which reads FEEDBACK_SYNC_STARTUP /
  FEEDBACK_SKIP_STARTUP_TASKS), so the sync-startup test exercises the real
  path again.
- Restore the window.slopsmith backward-compat alias dropped during conflict
  resolution, and move the bus aliases to AFTER the _feedBackExisting merge
  block so they reference the fully-assembled object (also fixes the
  loop_api.test.js API-surface regex, which the original PR latently broke).
- Drop the stray empty data/web_library.db (runtime DB lives in CONFIG_DIR)
  and gitignore it.
- Fix stale tone-source test: feed[dB]ack -> fee[dB]ack to match shipped
  source labels.

Verified locally (org CI billing-blocked): JS 819/819 pass; pytest 1669
passed / 1683 collected with 0 import errors; zero residual slopsmith/byron
except the two intentional window.slopsmith aliases.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* 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>

---------

Co-authored-by: byrongamatos <xasiklas@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Bret Mogilefsky
2026-06-23 11:03:01 +02:00
committed by GitHub
co-authored by Claude Opus 4.8 byrongamatos
parent a8ad02739a
commit af2949677a
257 changed files with 2389 additions and 2293 deletions
+1 -1
View File
@@ -13,7 +13,7 @@
*/
(function () {
'use strict';
const sm = window.slopsmith;
const sm = window.feedBack;
const esc = (s) => String(s == null ? '' : s).replace(/[&<>"']/g, (c) => (
{ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]));
+1 -1
View File
@@ -17,7 +17,7 @@
*/
(function () {
'use strict';
const sm = window.slopsmith;
const sm = window.feedBack;
const esc = (s) => String(s == null ? '' : s).replace(/[&<>"']/g, (c) => (
{ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]));
+2 -2
View File
@@ -11,12 +11,12 @@
*/
(function () {
'use strict';
const sm = window.slopsmith;
const sm = window.feedBack;
if (!sm || !sm.libraryCardActions) return;
const STD_RETUNABLE = ['Eb Standard', 'D Standard', 'C# Standard', 'C Standard'];
const reg = sm.libraryCardActions;
const hooks = window.__slopsmithV3CoreCardActions || (window.__slopsmithV3CoreCardActions = {});
const hooks = window.__feedBackV3CoreCardActions || (window.__feedBackV3CoreCardActions = {});
if (hooks.installed) return;
hooks.installed = true;
+2 -2
View File
@@ -9,7 +9,7 @@
*/
(function () {
'use strict';
const sm = window.slopsmith;
const sm = window.feedBack;
const esc = (s) => String(s == null ? '' : s).replace(/[&<>"']/g, (c) => (
{ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]));
const enc = encodeURIComponent;
@@ -106,7 +106,7 @@
const name = (profile && profile.display_name) || 'there';
const ver = (version && version.version) || '';
const changelogUrl = ((version && version.source_url) || 'https://github.com/got-feedback/feedback') + '/blob/main/CHANGELOG.md';
const changelogUrl = ((version && version.source_url) || 'https://github.com/got-feedback/feedBack') + '/blob/main/CHANGELOG.md';
const songCount = (libStats && (libStats.total_songs ?? libStats.total)) || 0;
const pluginCount = Array.isArray(plugins)
? plugins.filter((p) => (p && (p.status || 'ready') === 'ready')).length : 0;
+5 -5
View File
@@ -3,14 +3,14 @@
*
* A vanilla-JS reskin of the bundled `minigames` plugin's screen into the fb-*
* design (constitution P-II). It REUSES the minigames backend + the
* window.slopsmithMinigames SDK — it does not fork scoring/run logic and adds
* window.feedBackMinigames SDK — it does not fork scoring/run logic and adds
* no second XP curve. XP stays unified through the core store (P15): the header
* reads /api/profile/progress (the same data the topbar profile badge shows),
* while per-game bests + cross-game unlocks come from the minigames /profile.
*
* UI placement is a DEFERRED capability domain (design/05): we use the legacy
* plugin loader + /api/plugins/minigames/* routes, NOT capability dispatch.
* Launch delegates to slopsmithMinigames.start(gameId), which mounts the
* Launch delegates to feedBackMinigames.start(gameId), which mounts the
* plugin's own #mg-stage overlay (eagerly injected at boot) — so this screen
* never needs to visit the legacy #plugin-minigames hub.
*/
@@ -18,7 +18,7 @@
'use strict';
const SCREEN_ID = 'v3-feedbarcade';
const sm = window.slopsmith;
const sm = window.feedBack;
const esc = (s) => String(s == null ? '' : s).replace(/[&<>"']/g, (c) => (
{ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]));
const enc = encodeURIComponent;
@@ -32,7 +32,7 @@
let _stageWasVisible = false;
let _refreshTimer = null;
function sdk() { return window.slopsmithMinigames || null; }
function sdk() { return window.feedBackMinigames || null; }
function registeredList() {
const s = sdk();
try { return (s && typeof s.listRegistered === 'function') ? s.listRegistered() : []; }
@@ -271,7 +271,7 @@
// The minigames plugin publishes its SDK + injects #mg-stage at boot and
// fires this once ready; re-render so late-registered specs appear and
// the stage observer attaches.
window.addEventListener('slopsmith-minigames-ready', () => { ensureStageObserver(); refresh(); });
window.addEventListener('feedBack-minigames-ready', () => { ensureStageObserver(); refresh(); });
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', boot, { once: true });
+21 -21
View File
@@ -1,6 +1,6 @@
<!DOCTYPE html>
<!--
fee[dB]ack v0.3.0 shell (SLOPSMITH_UI=v3 / GET /v3).
fee[dB]ack v0.3.0 shell (FEEDBACK_UI=v3 / GET /v3).
This is a re-chromed copy of the legacy static/index.html: the v0.3.0
sidebar + topbar replace the (hidden) legacy navbar, new #v3-* screens are
@@ -9,7 +9,7 @@
boots UNMODIFIED and the whole engine — player/highway, plugin loader,
capabilities, audio, library, settings — is reused as-is. Navigation is the
shared window.showScreen across both #v3-* and legacy/#plugin-* screens.
See ~/Repositories/slopsmith-feedback-v030/prompts/12-app-shell.md.
See ~/Repositories/feedBack-feedback-v030/prompts/12-app-shell.md.
-->
<html lang="en" class="dark scroll-smooth">
<head>
@@ -69,7 +69,7 @@
stylesheet (regenerated by scripts/build-tailwind.sh). The old
Play CDN (cdn.tailwindcss.com) JIT scanned the DOM ~1.8x/sec
on the main thread, dropping ~26% of frames with the 3D
highway running — see slopsmith-desktop#110. Theme extensions
highway running — see feedBack-desktop#110. Theme extensions
(dark/accent/gold colors, Inter font) live in tailwind.config.js. -->
<link rel="stylesheet" href="/static/tailwind.min.css">
<!-- UI font: Rubik (Google Fonts, OFL). Applied via fontFamily.display in tailwind.config.js. -->
@@ -82,7 +82,7 @@
<link rel="stylesheet" href="/static/v3/v3.css">
<!-- Diagnostics console capture must wrap console.* before any other
script logs anything; load it as early as possible. See
docs/diagnostics-bundle-spec.md (slopsmith#166). -->
docs/diagnostics-bundle-spec.md (feedBack#166). -->
<script src="/static/diagnostics.js"></script>
<script src="/static/capabilities.js"></script>
<script src="/static/capabilities/library.js"></script>
@@ -143,7 +143,7 @@
<div class="max-w-7xl mx-auto px-6 h-16 flex items-center justify-between">
<div class="flex items-end gap-1.5">
<a href="#" onclick="showScreen('home');return false" class="text-xl font-bold bg-gradient-to-r from-accent-light to-purple-400 bg-clip-text text-transparent">
Slopsmith
FeedBack
</a>
<span id="app-version" class="text-xs text-gray-600 mb-0.5"></span>
</div>
@@ -229,7 +229,7 @@
<!-- Tree controls -->
<button onclick="toggleAllArtists(true)" class="lib-tree-ctrl bg-dark-700 border border-gray-800 rounded-xl px-3 py-2.5 text-sm text-gray-400 hover:text-white transition">Expand All</button>
<button onclick="toggleAllArtists(false)" class="lib-tree-ctrl bg-dark-700 border border-gray-800 rounded-xl px-3 py-2.5 text-sm text-gray-400 hover:text-white transition">Collapse All</button>
<!-- Filters drawer toggle (slopsmith#129) -->
<!-- Filters drawer toggle (feedBack#129) -->
<button onclick="toggleLibFilters()" id="btn-lib-filters"
class="bg-dark-700 border border-gray-800 hover:border-accent/40 rounded-xl px-4 py-2.5 text-sm text-gray-300 transition flex items-center gap-2"
title="Filter by parts, tuning, lyrics">
@@ -242,7 +242,7 @@
class="bg-dark-700 border border-gray-800 rounded-xl px-4 py-2.5 text-sm text-gray-300 placeholder-gray-600 focus:border-accent/50 focus:ring-1 focus:ring-accent/30 outline-none flex-1 md:w-60 transition">
</div>
</div>
<!-- Active-filter chip row (only visible when filters are set, slopsmith#129) -->
<!-- Active-filter chip row (only visible when filters are set, feedBack#129) -->
<div id="lib-filter-chips" class="hidden flex flex-wrap gap-2 mb-5"></div>
<div id="lib-grid" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-5">
<!-- Cards populated by JS -->
@@ -252,7 +252,7 @@
</div>
</section>
<!-- ══ Filters drawer (slopsmith#129/#69/#22) ═════════════════════ -->
<!-- ══ Filters drawer (feedBack#129/#69/#22) ═════════════════════ -->
<div id="lib-filter-overlay" class="fixed inset-0 bg-black/40 z-40 hidden"
onclick="toggleLibFilters(false)"></div>
<aside id="lib-filter-drawer"
@@ -352,7 +352,7 @@
<div class="space-y-10">
<!-- App Updates — Velopack auto-update, desktop only. Stays
hidden in the plain web app; setupAppUpdates() unhides
this block when window.slopsmithDesktop.update exists,
this block when window.feedBackDesktop.update exists,
and shows a disabled "not available on Linux" fallback
when running on Linux. -->
<div id="app-updates-block" class="hidden border border-gray-800 rounded-xl bg-dark-800/40 p-5">
@@ -378,13 +378,13 @@
<p id="app-update-status" class="text-xs text-gray-500 mt-3">Loading updater status…</p>
<p id="app-update-linux-note" class="hidden text-xs text-yellow-300 mt-2">
Auto-update is not available on Linux —
<a href="https://github.com/got-feedback/feedback-desktop/releases" target="_blank" rel="noopener" class="text-accent hover:text-accent-light underline">download new versions from GitHub Releases</a>.
<a href="https://github.com/got-feedback/feedBack-desktop/releases" target="_blank" rel="noopener" class="text-accent hover:text-accent-light underline">download new versions from GitHub Releases</a>.
</p>
</div>
<!-- ── Core Slopsmith settings ─────────────────────────────── -->
<!-- ── Core FeedBack settings ─────────────────────────────── -->
<section>
<h3 class="text-xs font-semibold uppercase tracking-wider text-gray-500 mb-4">Slopsmith</h3>
<h3 class="text-xs font-semibold uppercase tracking-wider text-gray-500 mb-4">FeedBack</h3>
<div class="space-y-6">
<div>
<label class="text-sm font-medium text-gray-400 mb-2 block">Library Folder Path</label>
@@ -455,7 +455,7 @@
class="flex-1 bg-dark-700 border border-gray-800 rounded-xl px-4 py-2.5 text-sm text-gray-300 placeholder-gray-600 focus:border-accent/50 outline-none">
<button onclick="saveSettings()" class="bg-accent hover:bg-accent-light px-6 py-2.5 rounded-xl text-sm font-semibold text-white transition">Save</button>
</div>
<p class="text-xs text-gray-600 mt-1">Optional. Run <a href="https://github.com/byrongamatos/slopsmith-demucs-server" target="_blank" rel="noopener" class="text-accent hover:text-accent-light underline">slopsmith-demucs-server</a> on a machine with a GPU to offload stem splitting and avoid resource exhaustion on the host running Slopsmith.</p>
<p class="text-xs text-gray-600 mt-1">Optional. Run <a href="https://github.com/got-feedBack/feedBack-demucs-server" target="_blank" rel="noopener" class="text-accent hover:text-accent-light underline">feedBack-demucs-server</a> on a machine with a GPU to offload stem splitting and avoid resource exhaustion on the host running FeedBack.</p>
</div>
<div>
<label class="text-sm font-medium text-gray-400 mb-2 block">Library</label>
@@ -476,7 +476,7 @@
</div>
<p class="text-xs text-gray-600 mt-1">Export bundles server config, browser preferences, and opted-in plugin data into one JSON file. Import overwrites current settings and reloads.</p>
</div>
<!-- ── Diagnostics (slopsmith#166) ────────────────────── -->
<!-- ── Diagnostics (feedBack#166) ────────────────────── -->
<div>
<label class="text-sm font-medium text-gray-400 mb-2 block">Diagnostics</label>
<div class="grid grid-cols-2 gap-2 mb-3 text-xs text-gray-400">
@@ -520,10 +520,10 @@
<section>
<h3 class="text-xs font-semibold uppercase tracking-wider text-gray-500 mb-4">About</h3>
<div class="space-y-2 text-sm text-gray-400">
<div>Slopsmith <span id="app-version-about" class="text-gray-500"></span></div>
<div>Licensed under <a id="about-license-link" href="https://github.com/got-feedback/feedback/blob/main/LICENSE" target="_blank" rel="noopener" class="text-accent hover:text-accent-light underline">GNU AGPL v3.0</a>.</div>
<div><a id="about-source-link" href="https://github.com/got-feedback/feedback" target="_blank" rel="noopener" class="text-accent hover:text-accent-light underline">Source code repository</a></div>
<p class="text-xs text-gray-600 mt-2">Slopsmith is free software. You can redistribute it and modify it under the terms of the AGPL. If you run a modified version that interacts with users over a network, you must make the modified source available to those users.</p>
<div>FeedBack <span id="app-version-about" class="text-gray-500"></span></div>
<div>Licensed under <a id="about-license-link" href="https://github.com/got-feedback/feedBack/blob/main/LICENSE" target="_blank" rel="noopener" class="text-accent hover:text-accent-light underline">GNU AGPL v3.0</a>.</div>
<div><a id="about-source-link" href="https://github.com/got-feedback/feedBack" target="_blank" rel="noopener" class="text-accent hover:text-accent-light underline">Source code repository</a></div>
<p class="text-xs text-gray-600 mt-2">FeedBack is free software. You can redistribute it and modify it under the terms of the AGPL. If you run a modified version that interacts with users over a network, you must make the modified source available to those users.</p>
</div>
</section>
</div>
@@ -701,7 +701,7 @@
<select id="viz-picker" onchange="setViz(this.value)" class="v3-pop-select" aria-labelledby="viz-picker-label" title="Visualization">
<option value="auto">Auto (match arrangement)</option>
<option value="default">Classic 2D Highway</option>
<!-- Additional entries populated on load from /api/plugins (slopsmith#36).
<!-- Additional entries populated on load from /api/plugins (feedBack#36).
The bundled 3D Highway plugin (plugins/highway_3d/) registers as
`highway_3d` and is the default on fresh installs — see
_populateVizPicker() in app.js. -->
@@ -762,7 +762,7 @@
<div id="v3-rail-pop-mixer" class="v3-rail-pop hidden" role="group" aria-label="Mixer">
<div id="mixer-control">
<div id="mixer-anchor" class="relative">
<button id="btn-mixer" type="button" onclick="window.slopsmith.audio.toggleMixer()" class="v3-pop-btn" aria-haspopup="true" aria-expanded="false" aria-controls="mixer-popover" title="Audio mixer">Mixer ▾</button>
<button id="btn-mixer" type="button" onclick="window.feedBack.audio.toggleMixer()" class="v3-pop-btn" aria-haspopup="true" aria-expanded="false" aria-controls="mixer-popover" title="Audio mixer">Mixer ▾</button>
<div id="mixer-popover" class="hidden absolute left-0 top-full mt-2 z-50 bg-dark-700 border border-gray-800 rounded-xl shadow-xl" role="group" aria-label="Audio mixer"></div>
</div>
</div>
@@ -858,7 +858,7 @@
<script src="/static/tour-engine.js"></script>
<!-- fee[dB]ack v0.3.0 shell: brand helper, then the shell (sidebar/topbar/
routing). Loaded after app.js/audio-mixer so window.showScreen and
window.slopsmith(.audio) exist; dashboard.js is filled in prompt 13. -->
window.feedBack(.audio) exist; dashboard.js is filled in prompt 13. -->
<script src="/static/v3/brand.js"></script>
<script src="/static/v3/shell.js"></script>
<!-- Progression (spec 010): theme-core before profile.js so the equipped
+5 -5
View File
@@ -17,7 +17,7 @@
*/
(function () {
'use strict';
const sm = window.slopsmith;
const sm = window.feedBack;
const PLUGIN_ID = 'tutorials';
const API = '/api/plugins/' + PLUGIN_ID;
const esc = (s) => String(s == null ? '' : s).replace(/[&<>"']/g, (c) => (
@@ -228,16 +228,16 @@
// the first navigation that leaves the launch flow (any screen other
// than the tutorials waypoint or the player that consumes it).
try {
if (window.slopsmith && typeof window.slopsmith.setReturnScreen === 'function') {
window.slopsmith.setReturnScreen('v3-lessons');
if (window.feedBack && typeof window.feedBack.setReturnScreen === 'function') {
window.feedBack.setReturnScreen('v3-lessons');
if (sm && typeof sm.on === 'function' && typeof sm.off === 'function') {
const clearStale = (e) => {
const id = e && e.detail && e.detail.id;
if (id === 'plugin-tutorials') return; // expected waypoint — keep waiting
// 'player' means playSong already consumed the override;
// anything else means the launch was abandoned.
if (id !== 'player' && window.slopsmith._nextReturnScreen === 'v3-lessons') {
window.slopsmith.setReturnScreen(null);
if (id !== 'player' && window.feedBack._nextReturnScreen === 'v3-lessons') {
window.feedBack.setReturnScreen(null);
}
sm.off('screen:changed', clearStale);
};
+1 -1
View File
@@ -8,7 +8,7 @@
(function (root) {
'use strict';
const KEY = 'slopsmith-live-guitar-tone-source';
const KEY = 'feedBack-live-guitar-tone-source';
const SOURCES = Object.freeze({
INTERNAL: 'internal',
+1 -1
View File
@@ -240,7 +240,7 @@
if (typeof document !== 'undefined') {
const boot = () => {
const sm = root && root.slopsmith;
const sm = root && root.feedBack;
if (sm) bindRuntime(sm);
};
if (document.readyState === 'loading') {
+3 -3
View File
@@ -12,7 +12,7 @@
*
* Vanilla JS, no framework (constitution P-II). Animation + accent colors are
* inline styles so the prebuilt Tailwind stylesheet needs no new utilities.
* Self-contained: it subscribes through window.slopsmith.on, degrading to a
* Self-contained: it subscribes through window.feedBack.on, degrading to a
* no-op when the bus or DOM isn't present (SSR/headless safety, P15).
*/
(function () {
@@ -95,7 +95,7 @@
window.fbNotify = { show: show, clear: clear };
// ── Progression wiring ────────────────────────────────────────────────────
const sm = window.slopsmith;
const sm = window.feedBack;
if (!sm || typeof sm.on !== 'function') return; // no bus → toasts API still usable
const periodLabel = (p) => (p === 'weekly' ? 'Weekly Quest' : p === 'daily' ? 'Daily Quest' : 'Quest');
@@ -106,7 +106,7 @@
};
// The bus delivers a CustomEvent; the progression payload is e.detail
// (matches every other window.slopsmith.on consumer, e.g. progress.js).
// (matches every other window.feedBack.on consumer, e.g. progress.js).
sm.on('progression:quest-progressed', (e) => {
const q = e && e.detail;
if (!q) return;
+6 -6
View File
@@ -2,7 +2,7 @@
* fee[dB]ack v0.3.0 — first-run home tour.
*
* Registers a spotlight tour over the home-page cards with the shared tour
* engine (window.slopsmithTour / Shepherd) and auto-runs it once, the first
* engine (window.feedBackTour / Shepherd) and auto-runs it once, the first
* time the user lands on the home page after completing onboarding. It stays
* replayable forever from the per-screen "?" tour menu (registered with
* screens: ['v3-home']).
@@ -72,7 +72,7 @@
}
function register() {
var t = window.slopsmithTour;
var t = window.feedBackTour;
if (!t || typeof t.register !== 'function') return false;
t.register(TOUR_ID, {
name: 'Welcome tour', // label in the "?" tour menu
@@ -88,7 +88,7 @@
// honour the engine's own seen/dismissed state so it never repeats and a
// dismissal isn't nagged. Stays replayable from the "?" menu either way.
function startFirstRun() {
var t = window.slopsmithTour;
var t = window.feedBackTour;
if (!t || typeof t.start !== 'function') return;
try {
if (t.hasSeen(TOUR_ID) || t.hasDismissed(TOUR_ID)) return;
@@ -118,12 +118,12 @@
// can't start the tour immediately — there is no home screen to spotlight
// yet. Arm it to run the first time the user lands back on v3-home.
function armPendingFirstRun() {
var t = window.slopsmithTour;
var t = window.feedBackTour;
if (!t || typeof t.start !== 'function') return;
try {
if (t.hasSeen(TOUR_ID) || t.hasDismissed(TOUR_ID)) return;
} catch (e) { /* private mode — fall through */ }
var sm = window.slopsmith;
var sm = window.feedBack;
if (!sm || typeof sm.on !== 'function') return;
var onScreen = function (e) {
if (!(e && e.detail && e.detail.id === 'v3-home')) return;
@@ -135,7 +135,7 @@
window.v3OnboardingTour = { startFirstRun: startFirstRun, armPendingFirstRun: armPendingFirstRun };
// tour-engine.js assigns window.slopsmithTour at script-eval time, so if it
// tour-engine.js assigns window.feedBackTour at script-eval time, so if it
// is loaded before us register() succeeds immediately; otherwise retry once
// the DOM (and the engine) are ready.
if (!register()) {
+1 -1
View File
@@ -33,7 +33,7 @@
// the pedal photos measure ~57.5% down), so they stay aligned at any size.
var JACK_FRAC = 0.575;
var sm = window.slopsmith;
var sm = window.feedBack;
// ---- pure geometry helpers (exported for tests) -----------------------
+6 -6
View File
@@ -26,13 +26,13 @@
let openPop = null; // { btn, pop }
// ── v3 UI signal + plugin-control slot API ───────────────────────────────
// Lets plugins detect v3 (window.slopsmith.uiVersion === 'v3') and mount
// Lets plugins detect v3 (window.feedBack.uiVersion === 'v3') and mount
// controls into a stable slot instead of the auto-hiding transport.
window.slopsmith = window.slopsmith || {};
window.slopsmith.uiVersion = 'v3';
window.slopsmith.ui = window.slopsmith.ui || {};
window.slopsmith.ui.version = 'v3';
window.slopsmith.ui.playerControlSlot = function () { return $('v3-plugin-controls-slot'); };
window.feedBack = window.feedBack || {};
window.feedBack.uiVersion = 'v3';
window.feedBack.ui = window.feedBack.ui || {};
window.feedBack.ui.version = 'v3';
window.feedBack.ui.playerControlSlot = function () { return $('v3-plugin-controls-slot'); };
// ── Plugin-control re-homing shim ────────────────────────────────────────
// Legacy plugins inject controls into #player-controls (now an auto-hiding
+1 -1
View File
@@ -9,7 +9,7 @@
*/
(function () {
'use strict';
const sm = window.slopsmith;
const sm = window.feedBack;
const esc = (s) => String(s == null ? '' : s).replace(/[&<>"']/g, (c) => (
{ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]));
+2 -2
View File
@@ -13,7 +13,7 @@
*/
(function () {
'use strict';
var sm = window.slopsmith;
var sm = window.feedBack;
var esc = function (s) { return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) {
return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]; }); };
@@ -209,7 +209,7 @@
return '<div class="v3-pedal' + (off ? ' v3-pedal-off' : '') + '" data-id="' + esc(p.id) + '" tabindex="0" role="button" ' +
'aria-label="' + esc((p.name || p.id) + action) + '" title="' + esc(tip) + '"' + style + '>' +
'<span class="v3-pedal-glow" aria-hidden="true"></span>' +
(p.bundled ? '<span class="v3-pedal-bundled" title="Ships with Slopsmith core">core</span>' : '') +
(p.bundled ? '<span class="v3-pedal-bundled" title="Ships with FeedBack core">core</span>' : '') +
'<span class="v3-pedal-offbadge" aria-hidden="true">off</span>' +
'<div class="v3-pedal-label">' +
'<img class="v3-pedal-thumb" alt="" loading="lazy" src="' + esc(thumbUrl(p)) + '">' +
+8 -8
View File
@@ -206,7 +206,7 @@
// public global is set at the end of the plugin's screen.js, after the
// owner is registered, so it is a reliable readiness signal.
function waitForInputSetup(timeoutMs) {
const ready = () => !!(window.slopsmithInputSetup && typeof window.slopsmithInputSetup.launch === 'function');
const ready = () => !!(window.feedBackInputSetup && typeof window.feedBackInputSetup.launch === 'function');
return new Promise((resolve) => {
if (ready()) { resolve(true); return; }
const t0 = Date.now();
@@ -222,9 +222,9 @@
if (!instruments.length) return;
// Don't let a plugin-load race skip the mandatory input-setup step.
if (!(await waitForInputSetup(8000))) return;
const caps = window.slopsmith && window.slopsmith.capabilities;
const caps = window.feedBack && window.feedBack.capabilities;
if (!caps || typeof caps.command !== 'function') {
try { await window.slopsmithInputSetup.launch(instruments); } catch (e) { /* proceed */ }
try { await window.feedBackInputSetup.launch(instruments); } catch (e) { /* proceed */ }
return;
}
await new Promise((resolve) => {
@@ -459,7 +459,7 @@
songDirEl.addEventListener('input', () => { songDir = songDirEl.value.trim(); refreshSubmit(); });
}
// Native folder picker on desktop; web users type/paste the path.
const _desktop = window.slopsmithDesktop;
const _desktop = window.feedBackDesktop;
if (songDirBrowse && _desktop && typeof _desktop.pickDirectory === 'function') {
songDirBrowse.classList.remove('hidden');
songDirBrowse.addEventListener('click', async () => {
@@ -510,7 +510,7 @@
}
renderBadge();
renderProfileScreen();
if (window.slopsmith && window.slopsmith.emit) window.slopsmith.emit('v3:profile-updated', _profile);
if (window.feedBack && window.feedBack.emit) window.feedBack.emit('v3:profile-updated', _profile);
// First-run only: after a genuine onboarding completion (not a
// profile edit), kick off the one-time home tour — but NOT when we're
// about to launch the diagnostic ("Play it now"), which navigates to
@@ -627,9 +627,9 @@
renderProfileScreen();
// Rank / dB / frames re-render whenever progression state or equipped
// cosmetics move (progression-core.js / theme-core.js own the fetches).
if (window.slopsmith && typeof window.slopsmith.on === 'function') {
window.slopsmith.on('progression:updated', () => { renderBadge(); renderProfileScreen(); });
window.slopsmith.on('v3:cosmetics-applied', () => { renderBadge(); renderProfileScreen(); });
if (window.feedBack && typeof window.feedBack.on === 'function') {
window.feedBack.on('progression:updated', () => { renderBadge(); renderProfileScreen(); });
window.feedBack.on('v3:cosmetics-applied', () => { renderBadge(); renderProfileScreen(); });
}
}
if (document.readyState === 'loading') {
+1 -1
View File
@@ -11,7 +11,7 @@
*/
(function () {
'use strict';
const sm = window.slopsmith;
const sm = window.feedBack;
const SCREEN_ID = 'v3-progress';
const esc = (s) => String(s == null ? '' : s).replace(/[&<>"']/g, (c) => (
+3 -3
View File
@@ -13,7 +13,7 @@
* (buy/equip require authorization:'user-action')
*
* Lifecycle events are emitted on the capability surface and mirrored on
* window.slopsmith as `progression:*` for non-capability consumers:
* window.feedBack as `progression:*` for non-capability consumers:
* challenge-completed, quest-completed, quest-progressed, path-level-up,
* path-progressed, rank-changed, db-changed, calibration-completed,
* cosmetic-equipped (+ progression:updated whenever fresh state lands).
@@ -24,7 +24,7 @@
*/
(function () {
'use strict';
const sm = window.slopsmith = window.slopsmith || {};
const sm = window.feedBack = window.feedBack || {};
let _state = null; // last /api/progression payload
let _fetching = null; // in-flight refresh (coalesced)
@@ -151,7 +151,7 @@
if (!diagnostics || typeof diagnostics.contribute !== 'function' || !_state) return;
try {
diagnostics.contribute('progression', {
schema: 'slopsmith.progression.diag.v1',
schema: 'feedBack.progression.diag.v1',
mastery_rank: _state.mastery_rank,
calibration_status: (_state.onboarding || {}).calibration_status,
paths: (_state.paths || []).map((p) => ({ id: p.id, level: p.level, max_level: p.max_level })),
+3 -3
View File
@@ -287,7 +287,7 @@
// ── showScreen wrapper (idempotent rehydration — design/05 §Rehydration) ─
function installShowScreenHook() {
const hooks = window.__slopsmithV3ShellHooks || (window.__slopsmithV3ShellHooks = {});
const hooks = window.__feedBackV3ShellHooks || (window.__feedBackV3ShellHooks = {});
hooks.syncActive = syncActive; // always point at the latest impl
if (hooks.installed) return;
hooks.installed = true;
@@ -359,8 +359,8 @@
// The "Welcome back, {name}!" title needs the profile, which loads
// async — refresh once it's in (and whenever it changes).
function refreshHomeTitle() { if (currentScreenId() === 'v3-home') setTopbarTitle(titleFor('v3-home')); }
if (window.slopsmith && typeof window.slopsmith.on === 'function') {
window.slopsmith.on('v3:profile-updated', refreshHomeTitle);
if (window.feedBack && typeof window.feedBack.on === 'function') {
window.feedBack.on('v3:profile-updated', refreshHomeTitle);
}
setTimeout(refreshHomeTitle, 700);
}
+1 -1
View File
@@ -12,7 +12,7 @@
*/
(function () {
'use strict';
const sm = window.slopsmith;
const sm = window.feedBack;
const SCREEN_ID = 'v3-shop';
let _data = null; // last GET /api/shop payload
+3 -3
View File
@@ -11,7 +11,7 @@
*/
(function () {
'use strict';
const sm = window.slopsmith;
const sm = window.feedBack;
const esc = (s) => String(s == null ? '' : s).replace(/[&<>"']/g, (c) => (
{ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]));
const enc = encodeURIComponent;
@@ -266,7 +266,7 @@
async function jget(url) { try { const r = await fetch(url); return r.ok ? r.json() : null; } catch (e) { return null; } }
// ── Provider-aware song helpers ────────────────────────────────────────
// Remote library providers (slopsmith-plugin-remote-library-*) expose songs
// Remote library providers (feedBack-plugin-remote-library-*) expose songs
// by provider-owned id with their own art/sync/play flow. Reuse the legacy
// app.js globals (the shared engine) so v3 behaves identically for remote
// providers instead of assuming every row is a local file. All degrade to
@@ -835,7 +835,7 @@
try {
const lp = sm && sm.libraryProviders;
// refresh() re-fetches /api/library/providers so REMOTE providers
// (registered by slopsmith-plugin-remote-library-*) appear — list()
// (registered by feedBack-plugin-remote-library-*) appear — list()
// returns only the capability's initial local-only snapshot.
const fn = lp && (typeof lp.refresh === 'function' ? lp.refresh : (typeof lp.list === 'function' ? lp.list : null));
if (fn) {
+3 -3
View File
@@ -3,8 +3,8 @@
*
* Bridges the highway note-detection scorer to the core song_stats store
* (POST /api/stats). The scorer lives in the OPTIONAL external plugin
* slopsmith-plugin-notedetect, which emits `note:hit` / `note:miss` per note
* on window.slopsmith — note-detection is a DEFERRED capability domain, so we
* feedBack-plugin-notedetect, which emits `note:hit` / `note:miss` per note
* on window.feedBack — note-detection is a DEFERRED capability domain, so we
* use those legacy events directly (design/05-capability-pipelines.md). If the
* plugin isn't installed, no note events fire and nothing is recorded
* (graceful degrade — the dashboard simply shows no accuracy).
@@ -21,7 +21,7 @@
*/
(function () {
'use strict';
const sm = window.slopsmith;
const sm = window.feedBack;
if (!sm || typeof sm.on !== 'function') return;
let cur = null; // active session
+4 -4
View File
@@ -116,8 +116,8 @@
if (r.ok) {
const profile = await r.json();
applyCosmetics(profile.cosmetics);
if (window.slopsmith && typeof window.slopsmith.emit === 'function') {
window.slopsmith.emit('v3:cosmetics-applied', profile.cosmetics || {});
if (window.feedBack && typeof window.feedBack.emit === 'function') {
window.feedBack.emit('v3:cosmetics-applied', profile.cosmetics || {});
}
}
} catch (e) { /* offline — keep current look */ }
@@ -134,7 +134,7 @@
refresh();
// Re-apply when an equip/unequip happens anywhere (shop screen, capability
// command from a plugin).
if (window.slopsmith && typeof window.slopsmith.on === 'function') {
window.slopsmith.on('progression:cosmetic-equipped', refresh);
if (window.feedBack && typeof window.feedBack.on === 'function') {
window.feedBack.on('progression:cosmetic-equipped', refresh);
}
})();
+3 -3
View File
@@ -10,8 +10,8 @@
(function (root) {
'use strict';
const KEY = 'slopsmith-venue-mood-fx';
const MOTION_KEY = 'slopsmith-venue-motion';
const KEY = 'feedBack-venue-mood-fx';
const MOTION_KEY = 'feedBack-venue-motion';
const SETTINGS = Object.freeze({ OFF: 'off', SUBTLE: 'subtle', FULL: 'full' });
const DEFAULT = SETTINGS.SUBTLE;
const MOTION_DEFAULT = SETTINGS.SUBTLE;
@@ -508,7 +508,7 @@
if (typeof document !== 'undefined') {
const boot = () => {
const sm = root && root.slopsmith;
const sm = root && root.feedBack;
if (sm) bindRuntime(sm);
};
if (document.readyState === 'loading') {
+2 -2
View File
@@ -80,7 +80,7 @@
? root.highway.getSongInfo()
: null;
if (si && si.arrangement) return si.arrangement;
const cs = root.slopsmith && root.slopsmith.currentSong;
const cs = root.feedBack && root.feedBack.currentSong;
if (cs && cs.arrangement) return cs.arrangement;
if (cs && cs.arrangementSmartName) return cs.arrangementSmartName;
} catch (_) { /* visual-only */ }
@@ -166,7 +166,7 @@
function bindRuntime() {
if (_bound) return;
_bound = true;
const sm = root && root.slopsmith;
const sm = root && root.feedBack;
if (sm && typeof sm.on === 'function') {
sm.on('v3:live-performance-state', onPerformanceState);
sm.on('song:loaded', () => {