Commit Graph
8 Commits
Author SHA1 Message Date
byrongamatosandClaude Sonnet 4.6 c4eebe1c9f refactor(h3d-carve-5): move H-section player-chrome bg-control to src/bg-control.js
Extracted _pc* subsystem (420 lines) from screen.js IIFE into
src/bg-control.js using a factory DI pattern (createBgControl({...})).

Exports: createBgControl({ BG_STYLE_IDS, _bgReadGlobal, _bgSubscribe,
         _bgUnsubscribe, getVenueSceneOverride })
         → { _pcAcquire, _pcRelease }
screen.js: const { _pcAcquire, _pcRelease } = createBgControl({...})

Beyond-subst (2):
1. Factory wrapper (IIFE-scope closure → DI params) — factory export pattern
   required because DI values are IIFE-scope, not ES module imports.
2. _venueSceneOverride → getVenueSceneOverride() (live accessor, 1 call site
   in _pcSync — mutable let at screen.js:1523 must be read per-call).

DI values all defined before the createBgControl call (screen.js):
- BG_STYLE_IDS: line 1435 | _bgReadGlobal: 1825
- _bgSubscribe/_bgUnsubscribe: 1917-18 | _venueSceneOverride: 1523
First _pcAcquire caller: init() in createFactory() (~line 14850 post-cut).
Construction order correct: createBgControl call before createFactory.

Surprise declared to god before commit (outbox/h3d-cut5-surprise.json):
No bc-panel.js dependency — §8's anticipation was wrong. The
_bcCreateController call at what was ~line 8082 is in _bcSyncMode
(P-section / factory scope), not the H-section. bg-control.js has ZERO
dependency on bc-panel.js.

Tests:
- tests/js/highway_3d_bg_control.test.js (new, 13 class-killers):
  stranded-caller (test 13, factory-adapted from bc-panel test 12),
  construction-order (tests 11-12), DI completeness (test 2),
  live-accessor enforcement (test 3), lifecycle (tests 4-7).
- plugins/highway_3d/tests/background_control.test.js: retargeted from
  screen.js slice → bg-control.js factory eval; all 20 existing behaviour
  tests preserved (load() uses vm.createContext + augmented return getters).
- tests/js/highway_3d_panel_controls.test.js: createBgControl stub added.

Suite: node --test tests/js/highway_3d*.test.js plugins/highway_3d/tests/*.test.js
  base 222/222 (f69c544) → tip 235/235 (+13: 13 new class-killers)
plugin.json: 3.40.0 → 3.41.0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uZ169yfoFYArXz962g7KW
2026-09-05 09:25:44 +02:00
byrongamatosandClaude Sonnet 4.6 f69c544eea fix(h3d-carve-4): export _bcLoadSettings + _bcFfIdx; add caller-coverage test (Creed HIGH)
screen.js H/P-section render path at lines 15396-15402 calls _bcLoadSettings()
and _bcFfIdx() (3×) — both moved to bc-panel.js in cut 4 but omitted from the
export list.  Browser: first render() after bcCtrl creation → ReferenceError;
seek/loop fast-forward index also dead.  Suite was green because no test
executed the butterchurn render path.

Fix:
- export _bcLoadSettings and _bcFfIdx from bc-panel.js
- add both to the tagged import in screen.js

Class-killer (test 12 — generic, not instance-specific):
  Extracts all exports from bc-panel.js, all imports in screen.js's
  bc-panel.js import clause, then asserts no exported symbol appears as a
  bare reference in the screen.js IIFE body without being imported.
  Generic: adding a new export + new caller without updating the import → RED.

Own grep (audit):
  grep (non-comment lines, all private _bc* names from bc-panel.js):
    _bcLoadSettings  1 hit  (line 15396)
    _bcFfIdx         3 hits (lines 15400-15402)
    all others: 0 hits
  Only the two symbols Creed found.

Mutation-verify:
  remove _bcLoadSettings from screen.js import →
    node --test tests/js/highway_3d_bc_panel.test.js
    tests 12   pass 11   fail 1   (test 12 RED)  ✓
  restore →
    node --test tests/js/highway_3d*.test.js plugins/highway_3d/tests/*.test.js
    tests 222   pass 222   fail 0               ✓ GREEN

Plan §8 amended: exports 2→4 with dated note.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uZ169yfoFYArXz962g7KW
2026-09-05 09:03:10 +02:00
byrongamatosandClaude Sonnet 4.6 4e060cbf7b refactor(h3d-carve-4): extract Butterchurn panel to src/bc-panel.js
Move all _bc* constants, mutable state, and functions (~670 lines) from
screen.js B-section (lines 27-695) to src/bc-panel.js.

Public API: _bcCreateController, _bcIsDesktop (2 named exports).
window.h3dBcApplySettings assigned at bc-panel.js module scope (1
beyond-subst; body verbatim — scope moves from IIFE to ES module top-level).
THREE_URL / THREE_CDN dead-code tombstoned (unused since three-loader.js).
Vendor files untouched (R2); asset URL constants verbatim (R3).

Delta note: original survey estimated ~1,333 lines for B-section. Actual is
~670 because (a) prior cuts 1b/2/3 moved material that was interleaved in the
B-section range, and (b) the original survey section boundaries were wrong —
the B-section ends where the H-section factory begins, not at line 695 of the
pre-cut file.

Completeness grep (post-cut):
  grep -nP '^\s*(function|const|let|var)\s+_bc' screen.js
  → 2 hits: _bcActive and _bcSyncMode at line 8081-8082 (factory-scope
    H/P-section helpers that orchestrate the imported controller; not B-section
    symbols — confirmed F-section in the survey table).
  B-section _bc* definitions in IIFE: 0.

Suite: node --test tests/js/highway_3d*.test.js plugins/highway_3d/tests/*.test.js
  tests 221   pass 221   fail 0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uZ169yfoFYArXz962g7KW
2026-09-05 08:43:00 +02:00
byrongamatosandClaude Sonnet 4.6 6050b6262b fix(h3d): thread maxStrings param through resolveStringCount (Toby r1)
Toby r1 on c7f7c88: MAX_RENDER_STRINGS=6 hardcoded in utils.js is a
stale compile-time copy — if S_COL grows to 7 entries, resolveStringCount
silently clamps a 7-string chart to 6 and no test fails.

Fix: delegator-param pattern (mirrors fretX / geoFretX):
  - Remove const MAX_RENDER_STRINGS from utils.js
  - resolveStringCount(bundle, maxStrings) — param replaces the copy
  - _openStringPitchLabelsForTuning(bundle, songInfo, n, maxStrings) — same
  - screen.js import aliases (_resolveStringCountBase, _openStringPitchLabelsForTuningBase)
  - 1-line delegators in IIFE supply MAX_RENDER_STRINGS (= S_COL.length); zero call sites change
  - NSTR=6 kept (it is a fixed semantic fact about standard guitar, not a palette ceiling)

New test: 'maxStrings param is authoritative, not a hardcoded 6'
  — resolveStringCount({stringCount:7}, 7)=7; re-hardcode mutation → RED.
Wiring tests: delegator lines asserting _resolveStringCountBase/
_openStringPitchLabelsForTuningBase each receive MAX_RENDER_STRINGS.

Mutation-verified: re-hardcode 6 → 1 RED; original → 210/210 GREEN.
Suite: node --test tests/js/highway_3d*.test.js plugins/highway_3d/tests/*.test.js
207→210/210 pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uZ169yfoFYArXz962g7KW
2026-09-05 08:02:00 +02:00
byrongamatosandClaude Sonnet 4.6 c7f7c88c62 refactor(h3d): extract color/tuning/splitscreen utils to src/utils.js (h3d-carve-3)
Moves 12 pure-function / compile-time-constant exports from the screen.js
IIFE into a new src/utils.js ES module:

  Color utils: _h3dHexToInt, _clampByteI, _darkenInt, _lightenInt
  String-count: resolveStringCount
  Tuning/pitch: _NOTE_NAMES_SHARP, _BASE_OPEN_MIDI_BASS4/5, _BASE_OPEN_MIDI_GUITAR6/7/8,
                _baseOpenStringMidis, _midiToPitchLabel, _openStringPitchLabelsForTuning
  Splitscreen:  _ssActive, _ssIsCanvasFocused

Free-identifier audit: all clean. resolveStringCount uses MAX_RENDER_STRINGS
and NSTR — copied as compile-time constants (both = 6) matching IIFE values.
_ssActive/_ssIsCanvasFocused read window.feedBackSplitscreen live per call.

Survey discrepancy declared: the 12 functions span two non-contiguous regions
in current screen.js (lines 741–882 and 1490–1503) rather than the plan's
original 1703–2193 range; function list from the plan is exact.

New test file highway_3d_utils.test.js: 19 class-killer tests.
Mutation-verified (3-char shorthand removal → RED, original → GREEN).
Panel-controls sandbox: 16 stubs added for the new imports.

Suite: node --test tests/js/highway_3d*.test.js plugins/highway_3d/tests/*.test.js
188→207/207 pass.

Plugin: 3.38.0 → 3.39.0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uZ169yfoFYArXz962g7KW
2026-09-05 07:52:41 +02:00
byrongamatosandClaude Sonnet 4.6 8ea123deaf refactor(h3d-carve-2): extract Three.js loader to src/three-loader.js
Move the D-section (~21 lines) from screen.js factory scope to its own module.

Exports:
- loadThree() — memoised import() with local-vendor→CDN fallback; same body verbatim
- T (live let-binding) — updated to the Three.js namespace on first resolution

screen.js gains: import { loadThree, T } from './src/three-loader.js'
screen.js loses: let T = null; let threeLoadPromise = null; function loadThree()
T and loadThree remain accessible to the IIFE via module-scope closure. The live
let-binding means the IIFE reads the populated T after loadThree() resolves
without any call-site changes.

Panel-controls vm test: strip regex extended to consume all consecutive import
lines; T: null + loadThree stubs added to sandbox context.

Class-killer tests (8 new — highway_3d_three_loader.test.js):
- loadThree exported (mutation: rename/remove → import fails)
- T exported as mutable let (mutation: const → T=mod throws TypeError)
- T=mod in both .then handlers (mutation: remove both → T stays null)
- memoisation guard !threeLoadPromise (mutation: remove → race + duplicate loads)
- CDN fallback .catch chain (mutation: remove → deploy failures unrecoverable)
- threeLoadPromise reset on failure (mutation: remove → no retry possible)
- screen.js imports loadThree+T (wiring confirmed)
- IIFE no longer declares local T or threeLoadPromise (shadow defeated)

All class-killer mutations confirmed distinguishable before commit.

Base run (5e401af): 180/180 pass.
Post-cut run: 188/188 pass.
Command: node --test tests/js/highway_3d*.test.js plugins/highway_3d/tests/*.test.js

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uZ169yfoFYArXz962g7KW
2026-09-05 07:35:27 +02:00
byrongamatosandClaude Sonnet 4.6 5e401afe87 refactor(h3d-carve-1b): extract render-order, note-key, camera-bootstrap, fretMid to src/geometry.js
Move 9 symbols verbatim from screen.js factory scope to geometry.js:
- RENDER_ORDER_LAYER_STACK, RENDER_ORDER_LAYER_INDEX, RENDER_ORDER_AT_Z_ZERO,
  RENDER_ORDER_FAR_CLAMP — compile-time constants, now exported from geometry.js
- renderOrderForLayerAtZ — pure fn; reads K + RENDER_ORDER_* from geometry scope
- _noteKey, lowerBoundT — hot-path helpers; no external deps
- hwyFirstRelevantFrettedTime — camera bootstrap scan; no external deps
- fretMid → geoFretMid(f, uniform) — same fretX delegator pattern as Cut 1;
  screen.js keeps: const fretMid = f => geoFretMid(f, _h3dFretUniform); (1 beyond-subst)

screen.js import line updated to import all 9 new exports; tombstones replace
each original definition.

Source-scan retargets:
- highway_3d_render_order.test.js: layers()/zZeroRenderOrder() now read
  GEOMETRY_JS; the 5 renderOrderForLayerAtZ-internals asserts in
  chordFrameRenderOrder test retargeted to geo() (call-site assert stays on src()).
- highway_3d_camera_bootstrap.test.js: extractFn now reads geoSrc (GEOMETRY_JS);
  sourceBetween wiring tests remain on SCREEN_JS.
- highway_3d_panel_controls.test.js: sandbox stubs extended with 9 new names.

Class-killer tests added to highway_3d_geometry.test.js (8 new tests, 180 total):
- RENDER_ORDER_LAYER_STACK length + first/last entries
- RENDER_ORDER_LAYER_INDEX spot-checks (CHORD_FILL=0, NOTE_CORE=10)
- renderOrderForLayerAtZ far-clamp (worldZ=-5 gives 50, not 33 without max)
- renderOrderForLayerAtZ unknown-layer throws
- _noteKey |0 truncation (1.5,3)=150003 not float-derived 150008
- lowerBoundT strict lower-bound (3 in [{t:1},{t:3},{t:5}] gives 1, not 2)
- hwyFirstRelevantFrettedTime smoke (empty → null)
- geoFretMid sentinel (f=0 gives -2K≈-0.015, not 0) + ratio invariant

Mutation analysis confirmed all 8 tests fail under their named mutation before
committing (per Toby r1 lesson).

Base run (a1f7ad5): 172/172 pass.
Post-cut run: 180/180 pass.
Command: node --test tests/js/highway_3d*.test.js plugins/highway_3d/tests/*.test.js

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uZ169yfoFYArXz962g7KW
2026-09-05 07:19:58 +02:00
byrongamatosandClaude Sonnet 4.6 84d33769b8 refactor(h3d-carve-1): extract pure geometry helpers to src/geometry.js
Moves 7 exports from screen.js to a new ES module src/geometry.js:
  geoFretX (was fretX, now 2-arg), dZ, slideTrailEnd, camBaseDistU,
  camLowFretPullbackU, computeBPM, _makeGaussTex.

Internal helpers _fretXLog / _fretXUniStep / _fretXUni are module-private
inside geometry.js. Module-level constants (SCALE, K, FRET_SCALE, NFRETS,
FRET_SPACING_*, TS) are duplicated at geometry.js module scope — values
are compile-time and never vary at runtime.

screen.js keeps a 1-arg delegator (1 beyond-subst):
  const fretX = f => geoFretX(f, _h3dFretUniform);
No call site changes; fretMid / fretColumnWorldW / slideOffsetWorldX /
_recomputeFretSpacingDerived stay in screen.js and use the delegator.

Tests:
- highway_3d_geometry.test.js: class-killer via import() with 9
  known-answer assertions (geoFretX uniform/log invariants, dZ linearity,
  slideTrailEnd, computeBPM BPM estimate).
- highway_3d_fret_spacing: test updated to match delegator pattern + adds
  GEOMETRY_JS read to verify geoFretX export.
- highway_3d_sustain_bloom: retargeted _makeGaussTex check to GEOMETRY_JS
  (definition moved); call-site check stays on SCREEN_JS.
- highway_3d_panel_controls: vm loader strips ES import line and injects
  geometry stubs; all factory-statics tests unaffected.

Suite: 169/169 pass
  node --test tests/js/highway_3d*.test.js plugins/highway_3d/tests/*.test.js
Version bump: 3.35.0 -> 3.36.0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uZ169yfoFYArXz962g7KW
2026-09-05 06:50:52 +02:00