diff --git a/CLAUDE.md b/CLAUDE.md index 32c0ff3..7fe826b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -22,13 +22,23 @@ reading state straight off the Host's `window.highway` object. see `feedBack/static/js/session.js`'s comment on `showScreen()` re: feedBack#923/#924. Patching `window.showScreen` here would silently never fire for real navigation; this was an actual regression until fixed. -- **No bespoke API with `feedback-plugin-dynamic-difficulty`.** Both plugins - independently read the same Host surface (`highway.getPhrases()` / - `hasPhraseData()` / `getMastery()`) for section-difficulty data — this - plugin works whether or not dynamic_difficulty is installed, as long as - *something* populates that phrase data. Don't reach into - dynamic_difficulty's own globals/localStorage directly; go through - `window.highway`. +- **Section-difficulty data comes from `difficulty_ladder`'s + `difficulty:sections-updated` event, not independent `highway` reads + (issue #63).** This plugin used to independently read `highway.getPhrases()` + / `hasPhraseData()` / `getMastery()` for section-difficulty data — that + changed when the glass-fill rendering was rewritten to consume + `difficulty_ladder`'s emitted event instead (`_smUpdateDifficultyFills` / + `_smGetSectionDifficulty` just render whatever `fillPercentage` / + `glassSize` the event's payload carries per section). This plugin still + works standalone with no ladder plugin installed — `_smIsDynamicDifficultyAvailable()` + gates the subscription on `window._ddCapabilities`, absent means no + glasses are shown, not an error — but when a ladder plugin *is* installed, + this is the API, not a coincidence of both sides reading the same Host + state. See `difficulty_ladder`'s `INTEGRATION.md` for the full contract + (fill formula, fallback/timing behavior). Load order matters: plugins load + alphabetically, so `difficulty_ladder` (< `section_map`) sets + `window._ddCapabilities` before this plugin's one-time availability check + runs. - **Seeking must go through the Host's canonical funnel** (`window.feedBack.seek` / `window.slopsmith.seek`, wrapped by `_smSeek`), not by poking `audio.currentTime` directly — see the comment on `_smSeek` diff --git a/plugin.json b/plugin.json index c63e7ec..8d0dd09 100644 --- a/plugin.json +++ b/plugin.json @@ -1,7 +1,7 @@ { "id": "section_map", "name": "Section Map", - "version": "1.2.4", + "version": "1.2.5", "private": false, "script": "screen.js", "category": "practice", diff --git a/screen.js b/screen.js index de00f21..8627dd1 100644 --- a/screen.js +++ b/screen.js @@ -49,12 +49,17 @@ function _smGetColor(name) { return SM_COLORS.default; } -// Check if dynamic-difficulty plugin is installed and available +// Check if the difficulty_ladder plugin (formerly "dynamic-difficulty") is +// installed and available. `window._ddCapabilities` is the compatibility +// marker it sets at load time (see difficulty_ladder's screen.js and +// INTEGRATION.md, issue #63) -- the marker name predates that plugin's +// rename from `dynamic_difficulty` to `difficulty_ladder`, kept as-is since +// it's the established capability-marker contract between the two plugins. +// (A second check here used to also probe `window.feedBackViz_dynamic_difficulty`, +// a viz-factory-naming-convention global difficulty_ladder never actually +// set even before the rename -- dead since this function was written.) function _smIsDynamicDifficultyAvailable() { if (typeof window.feedBack === 'undefined') return false; - // Check if dynamic-difficulty is in the active plugins list or has exposed a capability - if (typeof window.feedBackViz_dynamic_difficulty !== 'undefined') return true; - // Additional check: look for dynamic-difficulty's global scope if available if (typeof window._ddCapabilities !== 'undefined') return true; return false; }