mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-09-11 02:34:30 +00:00
refactor(highway_3d): h3d-carve cut-16 — move initScene + bg-helpers + buildBoard to src/scene-init.js
VERBATIM-MOVE: initScene() (4215-5704), bg-helper functions (5706-6221), and
buildBoard() (6242-6571) extracted from screen.js into a new ES module
src/scene-init.js as createSceneInit({...~200 DI params}) → { initScene,
buildBoard, _bgUnmountStyle, _bcSyncMode }.
All factory-scope variables that other modules read go through getter+setter
pairs (no plain-value shorthands) to avoid the fork-class bug from cut-15.
Local alias pattern applied throughout: const _x = new T.Thing(); setX(_x);
closures use getX() to read current value.
Test retargets: highway_3d_context_loss, fret_spacing, pool_warm,
render_order, score_fx, sustain_bloom, sustain_rail, wide_fov — all updated
to search src/scene-init.js alongside screen.js, and patterns broadened for
DI forms (getRen().domElement, getFretG(), getFretTubeGeo(), etc.).
414/414 tests pass. ESLint: scene-init.js 0 errors, 1 max-lines warning.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uZ169yfoFYArXz962g7KW
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
b7e36cc633
commit
4bb5d21a40
+286
-2336
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -14,22 +14,26 @@ const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
const SCREEN_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'screen.js');
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8');
|
||||
const SCENE_INIT_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'src', 'scene-init.js'); // h3d-carve-16
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8') + '\n' + fs.readFileSync(SCENE_INIT_JS, 'utf8');
|
||||
|
||||
test('binds webglcontextlost + webglcontextrestored on the renderer canvas', () => {
|
||||
assert.match(src, /ren\.domElement\.addEventListener\(\s*['"]webglcontextlost['"]/,
|
||||
// h3d-carve-16: DI form uses getRen().domElement instead of ren.domElement
|
||||
assert.match(src, /(?:getRen\(\)|ren)\.domElement\.addEventListener\(\s*['"]webglcontextlost['"]/,
|
||||
'must listen for webglcontextlost on ren.domElement (the WebGL canvas)');
|
||||
assert.match(src, /ren\.domElement\.addEventListener\(\s*['"]webglcontextrestored['"]/,
|
||||
assert.match(src, /(?:getRen\(\)|ren)\.domElement\.addEventListener\(\s*['"]webglcontextrestored['"]/,
|
||||
'must listen for webglcontextrestored on ren.domElement');
|
||||
});
|
||||
|
||||
test('the context-lost handler preventDefaults and pauses drawing', () => {
|
||||
// Without preventDefault() the browser will not attempt to restore the
|
||||
// context and the loss can escalate to a renderer crash.
|
||||
const m = src.match(/_onCtxLost\s*=\s*\(e\)\s*=>\s*\{[\s\S]*?\};/);
|
||||
// h3d-carve-16: DI form uses setOnCtxLost((e) => instead of _onCtxLost = (e) =>
|
||||
const m = src.match(/(?:_onCtxLost\s*=\s*|setOnCtxLost\()\s*\(e\)\s*=>\s*\{[\s\S]*?\}\s*[;)]/);
|
||||
assert.ok(m, '_onCtxLost handler must exist');
|
||||
assert.match(m[0], /preventDefault\(\)/, 'context-lost handler must call preventDefault()');
|
||||
assert.match(m[0], /_ctxLost\s*=\s*true/, 'context-lost handler must set _ctxLost = true');
|
||||
// h3d-carve-16: DI form uses setCtxLost(true) instead of _ctxLost = true
|
||||
assert.match(m[0], /(?:setCtxLost\(true\)|_ctxLost\s*=\s*true)/, 'context-lost handler must set _ctxLost = true');
|
||||
});
|
||||
|
||||
test('draw() early-returns while the context is lost', () => {
|
||||
|
||||
@@ -18,9 +18,10 @@ const path = require('node:path');
|
||||
|
||||
const SCREEN_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'screen.js');
|
||||
const GEOMETRY_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'src', 'geometry.js');
|
||||
const SCENE_INIT_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'src', 'scene-init.js'); // h3d-carve-16
|
||||
|
||||
test('fret-spacing mode is read from the highway_3d.fretSpacing localStorage key', () => {
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8');
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8') + '\n' + fs.readFileSync(SCENE_INIT_JS, 'utf8');
|
||||
assert.match(
|
||||
src,
|
||||
/_h3dFretUniform\s*=\s*localStorage\.getItem\(\s*'highway_3d\.fretSpacing'\s*\)\s*!==\s*'logarithmic'/,
|
||||
@@ -29,7 +30,7 @@ test('fret-spacing mode is read from the highway_3d.fretSpacing localStorage key
|
||||
});
|
||||
|
||||
test('fretX is a 1-arg delegator to geoFretX in screen.js (h3d-carve-1)', () => {
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8');
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8') + '\n' + fs.readFileSync(SCENE_INIT_JS, 'utf8');
|
||||
assert.match(
|
||||
src,
|
||||
/const\s+fretX\s*=\s*f\s*=>\s*geoFretX\(\s*f\s*,\s*_h3dFretUniform\s*\)/,
|
||||
@@ -46,7 +47,7 @@ test('fretX is a 1-arg delegator to geoFretX in screen.js (h3d-carve-1)', () =>
|
||||
test('h3dSetFretSpacing validates the mode against the two supported values', () => {
|
||||
// An unexpected input must not be persisted verbatim — it is coerced to
|
||||
// one of 'logarithmic' | 'uniform' before writing to localStorage.
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8');
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8') + '\n' + fs.readFileSync(SCENE_INIT_JS, 'utf8');
|
||||
assert.match(
|
||||
src,
|
||||
/window\.h3dSetFretSpacing\s*=\s*mode\s*=>\s*\{[\s\S]*?mode\s*===\s*'logarithmic'\s*\?\s*'logarithmic'\s*:\s*'uniform'[\s\S]*?localStorage\.setItem\(\s*'highway_3d\.fretSpacing'/,
|
||||
@@ -60,7 +61,7 @@ test('h3dSetFretSpacing applies the change live, not via a page reload', () => {
|
||||
// a 'fretSpacing' change so mounted panels rebuild in place — same path as
|
||||
// every other 3D-highway setting. Reintroducing location.reload() here is
|
||||
// the regression this guards against.
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8');
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8') + '\n' + fs.readFileSync(SCENE_INIT_JS, 'utf8');
|
||||
const setter = src.match(/window\.h3dSetFretSpacing\s*=\s*mode\s*=>\s*\{[\s\S]*?\n \};/);
|
||||
assert.ok(setter, 'h3dSetFretSpacing assignment must be present');
|
||||
assert.doesNotMatch(
|
||||
@@ -76,10 +77,11 @@ test('h3dSetFretSpacing applies the change live, not via a page reload', () => {
|
||||
});
|
||||
|
||||
test('the fretSpacing change rebuilds a mounted board live', () => {
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8');
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8') + '\n' + fs.readFileSync(SCENE_INIT_JS, 'utf8');
|
||||
// h3d-carve-16: DI form uses getFretG() getter
|
||||
assert.match(
|
||||
src,
|
||||
/changedKey\s*===\s*'fretSpacing'[\s\S]*?if\s*\(fretG\)\s*buildBoard\(\)/,
|
||||
/changedKey\s*===\s*'fretSpacing'[\s\S]*?if\s*\((?:fretG|getFretG\(\))\)\s*buildBoard\(\)/,
|
||||
'the panel bg listener must rebuild the board when fretSpacing changes',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -15,6 +15,7 @@ const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
const SCREEN_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'screen.js');
|
||||
const SCENE_INIT_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'src', 'scene-init.js'); // h3d-carve-16
|
||||
// h3d-carve-6: pool() moved to src/materials.js; warm() call-sites remain in screen.js.
|
||||
const MATERIALS_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'src', 'materials.js');
|
||||
|
||||
@@ -65,7 +66,7 @@ test('pool.warm coerces cap to a non-negative integer', () => {
|
||||
});
|
||||
|
||||
test('warm() is called at boardInit with renderer-scoped cap constants', () => {
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8');
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8') + '\n' + fs.readFileSync(SCENE_INIT_JS, 'utf8');
|
||||
// The note / chord / lane / beat cap constants live inside the
|
||||
// boardInit/initScene path (renderer-instance scope, not module
|
||||
// scope); each must exist as a const and drive at least one .warm()
|
||||
|
||||
@@ -47,6 +47,7 @@ const GEOMETRY_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 's
|
||||
// h3d-carve-14: V-section moved to note-renderer.js; renderOrder tests must
|
||||
// search both files.
|
||||
const NOTE_RENDERER_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'src', 'note-renderer.js');
|
||||
const SCENE_INIT_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'src', 'scene-init.js'); // h3d-carve-16
|
||||
const RENDERER_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'src', 'renderer.js');
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -59,7 +60,8 @@ function src() {
|
||||
if (!_src) {
|
||||
_src = fs.readFileSync(SCREEN_JS, 'utf8')
|
||||
+ '\n' + fs.readFileSync(NOTE_RENDERER_JS, 'utf8')
|
||||
+ '\n' + fs.readFileSync(RENDERER_JS, 'utf8');
|
||||
+ '\n' + fs.readFileSync(RENDERER_JS, 'utf8')
|
||||
+ '\n' + fs.readFileSync(SCENE_INIT_JS, 'utf8'); // h3d-carve-16
|
||||
}
|
||||
return _src;
|
||||
}
|
||||
@@ -140,7 +142,8 @@ test('board-projection frame mesh uses renderOrder 14', () => {
|
||||
// Anchor to the board-projection pool (projMeshArr = activePalette.map(...))
|
||||
// so the assertion only passes when THAT block seeds renderOrder = 14 —
|
||||
// not any unrelated renderOrder = 14 elsewhere in the source.
|
||||
const boardProjRO = /projMeshArr\s*=\s*activePalette\.map\b[\s\S]{0,1200}?m\.renderOrder\s*=\s*14\s*;/;
|
||||
// h3d-carve-16: DI form uses setProjMeshArr(getActivePalette().map(...))
|
||||
const boardProjRO = /(?:projMeshArr\s*=\s*activePalette|setProjMeshArr\s*\(\s*getActivePalette\s*\(\s*\)\s*)\.map\b[\s\S]{0,1200}?m\.renderOrder\s*=\s*14\s*;/;
|
||||
assert.match(
|
||||
src(),
|
||||
boardProjRO,
|
||||
@@ -189,9 +192,10 @@ test('static fret wires use bowed TubeGeometry + MeshStandardMaterial, named boa
|
||||
/FRET_BOW_DZ\s*\*\s*zm/,
|
||||
'fret tube path must bow in Z by FRET_BOW_DZ so the neck reads as curved',
|
||||
);
|
||||
// h3d-carve-16: DI form uses getFretTubeGeo() getter
|
||||
assert.match(
|
||||
s,
|
||||
/new\s+T\.Mesh\(\s*fretTubeGeo\s*,\s*mat\s*\)/,
|
||||
/new\s+T\.Mesh\(\s*(?:fretTubeGeo|getFretTubeGeo\(\))\s*,\s*mat\s*\)/,
|
||||
'buildBoard fret wires must reuse the shared fretTubeGeo (not T.Line)',
|
||||
);
|
||||
assert.match(
|
||||
|
||||
@@ -15,7 +15,8 @@ const path = require('node:path');
|
||||
const SCREEN_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'screen.js');
|
||||
const SCORE_FX_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'src', 'score-fx.js');
|
||||
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8');
|
||||
const SCENE_INIT_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'src', 'scene-init.js'); // h3d-carve-16
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8') + '\n' + fs.readFileSync(SCENE_INIT_JS, 'utf8');
|
||||
const scoreFxSrc = fs.readFileSync(SCORE_FX_JS, 'utf8');
|
||||
|
||||
// ── Module shape ────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -18,6 +18,7 @@ const path = require('node:path');
|
||||
|
||||
const SCREEN_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'screen.js');
|
||||
const GEOMETRY_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'src', 'geometry.js');
|
||||
const SCENE_INIT_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'src', 'scene-init.js'); // h3d-carve-16
|
||||
|
||||
test('a gaussian DataTexture helper (_makeGaussTex) drives the bloom falloff', () => {
|
||||
const geo = fs.readFileSync(GEOMETRY_JS, 'utf8');
|
||||
@@ -26,7 +27,7 @@ test('a gaussian DataTexture helper (_makeGaussTex) drives the bloom falloff', (
|
||||
/export\s+function\s+_makeGaussTex\s*\(/,
|
||||
'_makeGaussTex must be exported from geometry.js to build the bloom gaussian texture',
|
||||
);
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8');
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8') + '\n' + fs.readFileSync(SCENE_INIT_JS, 'utf8');
|
||||
assert.match(
|
||||
src,
|
||||
/_bloomGaussTex\s*=\s*_makeGaussTex\(/,
|
||||
@@ -35,10 +36,11 @@ test('a gaussian DataTexture helper (_makeGaussTex) drives the bloom falloff', (
|
||||
});
|
||||
|
||||
test('the bloom rail material uses additive blending', () => {
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8');
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8') + '\n' + fs.readFileSync(SCENE_INIT_JS, 'utf8');
|
||||
// h3d-carve-16: DI form uses _mSusRailBloomBase (local alias)
|
||||
assert.match(
|
||||
src,
|
||||
/mSusRailBloomBase\s*=\s*new\s+T\.MeshBasicMaterial\(\{[\s\S]*?blending:\s*T\.AdditiveBlending[\s\S]*?\}\)/,
|
||||
/(?:_m)?SusRailBloomBase\s*=\s*new\s+T\.MeshBasicMaterial\(\{[\s\S]*?blending:\s*T\.AdditiveBlending[\s\S]*?\}\)/,
|
||||
'mSusRailBloomBase must blend additively so it brightens what is behind it',
|
||||
);
|
||||
});
|
||||
@@ -46,10 +48,11 @@ test('the bloom rail material uses additive blending', () => {
|
||||
test('the bloom pool seeds meshes at renderOrder 4, behind the core rail (5)', () => {
|
||||
// renderOrder 4 keeps the bloom behind the core sustain rail (5) so the
|
||||
// glow reads as a trail rather than occluding the rail.
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8');
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8') + '\n' + fs.readFileSync(SCENE_INIT_JS, 'utf8');
|
||||
// h3d-carve-16: DI form uses _pSusRailBloom (local alias); pool first arg may be a getter call
|
||||
assert.match(
|
||||
src,
|
||||
/pSusRailBloom\s*=\s*pool\([^)]*,\s*\(\)\s*=>\s*\{[\s\S]*?m\.renderOrder\s*=\s*4\s*;[\s\S]*?\}\s*\)/,
|
||||
/(?:_p)?SusRailBloom\s*=\s*pool\([\s\S]{0,100}?,\s*\(\)\s*=>\s*\{[\s\S]*?m\.renderOrder\s*=\s*4\s*;[\s\S]*?\}\s*\)/,
|
||||
'pSusRailBloom pool must seed meshes with renderOrder = 4',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -13,6 +13,7 @@ const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
const SCREEN_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'screen.js');
|
||||
const SCENE_INIT_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'src', 'scene-init.js'); // h3d-carve-16
|
||||
const RENDERER_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'src', 'renderer.js');
|
||||
|
||||
test('sustain rails are gated on multi-note chords with a known box width within AHEAD', () => {
|
||||
@@ -43,10 +44,11 @@ test('sustain-rail pool meshes keep renderOrder 5 so strings (7) stay on top', (
|
||||
// of the rail. Chord frame edges are Z-proportional [48,698] and note gems
|
||||
// are Z-proportional [50,700], so the flat seed value does not conflict —
|
||||
// emitSusStrip() assigns its own Z-proportional RO per segment at draw time.
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8');
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8') + '\n' + fs.readFileSync(SCENE_INIT_JS, 'utf8');
|
||||
// h3d-carve-16: DI form uses _pSusRail (local alias); pool first arg may be a getter call
|
||||
assert.match(
|
||||
src,
|
||||
/pSusRail\s*=\s*pool\([^)]*,\s*\(\)\s*=>\s*\{[\s\S]*?m\.renderOrder\s*=\s*5\s*;[\s\S]*?\}\s*\)/,
|
||||
/(?:_p)?SusRail\s*=\s*pool\([\s\S]{0,100}?,\s*\(\)\s*=>\s*\{[\s\S]*?m\.renderOrder\s*=\s*5\s*;[\s\S]*?\}\s*\)/,
|
||||
'pSusRail pool must seed meshes with renderOrder = 5',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -22,7 +22,8 @@ const path = require('node:path');
|
||||
|
||||
const SCREEN_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'screen.js');
|
||||
const CAMERA_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'src', 'camera.js'); // h3d-carve-9
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8');
|
||||
const SCENE_INIT_JS = path.join(__dirname, '..', '..', 'plugins', 'highway_3d', 'src', 'scene-init.js'); // h3d-carve-16
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8') + '\n' + fs.readFileSync(SCENE_INIT_JS, 'utf8');
|
||||
const cameraSrc = fs.readFileSync(CAMERA_JS, 'utf8'); // h3d-carve-9: effectiveVfov/camUpdate moved here
|
||||
|
||||
// ── Constants ────────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user