Files
feedBack/tests/js/highway_3d_lefty.test.js
T
byrongamatosandClaude Sonnet 4.6 10c7ec8a9d refactor(h3d-carve-9): extract W-section (camera lerp) → src/camera.js
effectiveVfov + camUpdate (~192 lines) extracted from the screen.js IIFE
into a createCamera() ES-module factory in plugins/highway_3d/src/camera.js.
screen.js imports and destructures the return { effectiveVfov, camUpdate }.

DI surface (48 params): 22 plain constants, 11 getters, 5 getter+setter pairs,
5 fn-refs (DI-renamed: _freeCamFor→freeCamFor, _aspectPaneKey→aspectPaneKey,
_resolveTuneFor→resolveTuneFor, _aspectRegisterPane→aspectRegisterPane).
Peer ES imports at module level: computeBPM (geometry.js), _ssActive (utils.js).
Per-call write-backs: setCurX, setCurDist, setCurLookY, setTgtLookY,
setFretRowFitBoost (all write-backs confirmed by setter class-killer tests).

Test retargeting (54 tests across 4 files):
- highway_3d_wide_fov.test.js:   6 tests → cameraSrc; 4 regexes updated for
  DI-renamed fn refs (resolveTuneFor, aspectRegisterPane, aspectPaneKey/getPaneUid)
- highway_3d_camera_framing.test.js: 5 tests → cameraSrc; getTgtDist() regex fix
- highway_3d_camera_bootstrap.test.js: extractFn retargeted to cameraSrc;
  getTgtX() ordering-check fix; 2 new setter class-killers added (setCurX,
  setFretRowFitBoost)
- highway_3d_lefty.test.js: shoulder-offset test → cameraSrc + getLeftyCached()
- highway_3d_panel_controls.test.js: createCamera stub added

Bite proofs:
- Gut effectiveVfov in camera.js → wide_fov not ok 4 (RED) ✓
- Gut camUpdate body (H_NEAR lerp) → framing not ok 3 (RED) ✓
- Gut camUpdate body (curX+=) → bootstrap not ok 11 (RED) ✓
- Sever setCurX → bootstrap not ok 12 (RED) ✓
- Sever setFretRowFitBoost → bootstrap not ok 13 (RED) ✓

Suite: 1271/1273 pass; 2 pre-existing failures unchanged from cut-8 baseline
(#46 analyser fallback, #591 nut-labels — both in flight before cut 9).

plugin.json: 3.44.0 → 3.45.0

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

98 lines
4.3 KiB
JavaScript

// Pins 3D Highway left-handed fret ordering (feedBack#321).
// Source-level only, matching the other tests/js/ regression guards: the
// runtime path is browser/WebGL-heavy, so these tests preserve the exact
// contracts that keep the lefty geometry coherent.
const { test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const ROOT = path.join(__dirname, '..', '..');
const HIGHWAY_JS = path.join(ROOT, 'static', 'highway.js');
const SCREEN_JS = path.join(ROOT, 'plugins', 'highway_3d', 'screen.js');
const CLAUDE_MD = path.join(ROOT, 'plugins', 'highway_3d', 'CLAUDE.md');
// h3d-carve-9: camUpdate (including shoulderOffset + _camX) moved to camera.js.
const CAMERA_JS = path.join(ROOT, 'plugins', 'highway_3d', 'src', 'camera.js');
function src(file) {
return fs.readFileSync(file, 'utf8');
}
test('highway renderer bundles surface the core lefty flag', () => {
assert.match(
src(HIGHWAY_JS),
/lefty\s*[:=]\s*hwState\._lefty/,
'custom renderer bundles must include lefty: _lefty',
);
});
test('3D Highway defines lefty-aware fret-position helpers', () => {
const screen = src(SCREEN_JS);
assert.match(
screen,
/let\s+_leftyCached\s*=\s*false\s*;/,
'renderer must cache the bundle lefty flag',
);
assert.match(
screen,
/const\s+xFret\s*=\s*f\s*=>\s*\(\s*_leftyCached\s*\?\s*-fretX\(f\)\s*:\s*fretX\(f\)\s*\)/,
'xFret must mirror fret edges when lefty is active',
);
assert.match(
screen,
/const\s+xFretMid\s*=\s*f\s*=>\s*\(\s*_leftyCached\s*\?\s*-fretMid\(f\)\s*:\s*fretMid\(f\)\s*\)/,
'xFretMid must mirror fret centers when lefty is active',
);
assert.match(
screen,
/const\s+boardSpanX\s*=\s*\(\s*\)\s*=>\s*\{[\s\S]*?const\s+x0\s*=\s*xFret\(0\)\s*;[\s\S]*?const\s+xN\s*=\s*xFret\(NFRETS\)\s*;[\s\S]*?min\s*:\s*Math\.min\(x0,\s*xN\)[\s\S]*?max\s*:\s*Math\.max\(x0,\s*xN\)[\s\S]*?center\s*:\s*\(x0\s*\+\s*xN\)\s*\/\s*2[\s\S]*?width\s*:\s*Math\.abs\(xN\s*-\s*x0\)/,
'boardSpanX must derive min/max/center/width from the lefty-aware xFret helper',
);
});
test('draw(bundle) handles lefty changes by flipping camera X state and rebuilding the board', () => {
const screen = src(SCREEN_JS);
assert.match(
screen,
/_leftyCached\s*=\s*!!bundle\.lefty\s*;/,
'draw(bundle) must refresh _leftyCached from bundle.lefty',
);
assert.match(
screen,
/const\s+leftyChanged\s*=\s*_leftyCached\s*!==\s*_leftyForBoard\s*;/,
'draw(bundle) must detect runtime lefty changes',
);
assert.match(
screen,
/if\s*\(\s*_invertedCached\s*!==\s*_invertedForBoard\s*\|\|\s*leftyChanged\s*\|\|\s*newNStr\s*!==\s*nStr\s*\)\s*\{[\s\S]*?if\s*\(\s*leftyChanged\s*\)\s*\{[\s\S]*?curX\s*=\s*-curX\s*;[\s\S]*?tgtX\s*=\s*-tgtX\s*;[\s\S]*?_lookaheadCamX\s*=\s*-_lookaheadCamX\s*;[\s\S]*?\}[\s\S]*?buildBoard\(\)\s*;[\s\S]*?_leftyForBoard\s*=\s*_leftyCached\s*;/,
'lefty changes must mirror curX/tgtX/_lookaheadCamX, rebuild board geometry, and update _leftyForBoard',
);
});
test('camera shoulder offset follows the cached lefty orientation', () => {
// h3d-carve-9: camUpdate (shoulderOffset + _camX) moved to src/camera.js;
// _leftyCached is DI-rewired to getLeftyCached() direct call.
assert.match(
src(CAMERA_JS),
// The shoulder offset now feeds the base _camX (which the opt-in
// free-camera bridge layers on top of) before cam.position.set (#771).
/const\s+shoulderOffset\s*=\s*\(\s*getLeftyCached\(\)\s*\?\s*-1\s*:\s*1\s*\)\s*\*\s*10\s*\*\s*K\s*;[\s\S]*?_camX\s*=\s*curX\s*\+\s*shoulderOffset/,
'camera shoulder offset must flip with getLeftyCached()',
);
});
test('3D Highway documentation says the renderer consumes bundle.lefty', () => {
const doc = src(CLAUDE_MD);
assert.doesNotMatch(
doc,
/bundle\.lefty[\s\S]{0,180}renderer never reads it/,
'CLAUDE.md must not claim the 3D renderer ignores bundle.lefty',
);
assert.match(
doc,
/bundle\.lefty[\s\S]{0,240}(?:mirrors|lefty|left-handed|left-handed)/i,
'CLAUDE.md should document the lefty flag as part of the renderer contract',
);
});