fix(h3d-carve-15): resolve Toby r1 F1/F2/F3 + scope-check test

F1 (HIGH): remove 44 phantom constants + fireDrawHooks + fxSpawnPop from
createRenderer DI signature and screen.js wiring. None ever existed in
screen.js scope; the engine threw ReferenceError at plugin init before
any argument was passed to createRenderer.

F2 (HIGH): un-move _setLabelMap back to screen.js (declared before
createNoteRenderer wiring at line ~6631), pass as DI to both
createNoteRenderer and createRenderer. Removing it from screen.js scope
caused a second independent ReferenceError before F1 even fired.

F3 (MED): drop 16 confirmed-dead DI params (0 body occurrences in
renderer.js): S_COL, SLIDE_RIBBON_SAMPLES, drawNotedetectLabels,
drawScoreFx, _resetStringDependentCaches, getCurDist, getCurLookY,
getTgtLookY, getFretRowFitBoost, getNdHitMarks, getNdMissMarks,
getImPMXFillCount, getImPMXLinesCount, getImFHXFillCount,
getImFHXLinesCount, getMeasureStarts. getMeasureStartsRef retained
(1 body use at renderer.js:831).

Scope-check also caught 4 pre-existing phantoms:
- PROJ_WIN, PROJ_WIN_G in createNoteRenderer wiring: note-renderer.js
  body uses hardcoded 0.6 / _PROJ_WIN_ARP; these DI params only appear
  in comments. Removed from note-renderer.js signature and both wiring
  calls.
- camAhead, camTau in createRenderer wiring: update() re-declares both
  as local let vars that shadow any DI value; also not declared in
  screen.js. Removed from renderer.js signature and wiring.

New test (highway_3d_renderer.test.js #16): static wiring-scope check
blanks all four factory wiring blocks from the corpus, then asserts each
shorthand token appears in the remainder. RED at 7623ad8 on BEAT_HEAD_SEC
(44 phantoms), GREEN at this tip.

DI count: 241 → 177 (createRenderer), 130 → 128 (createNoteRenderer).
Suite: 1396/1397 (test 46 pre-existing).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uZ169yfoFYArXz962g7KW
This commit is contained in:
byrongamatos
2026-09-05 23:37:57 +02:00
co-authored by Claude Sonnet 4.6
parent 7623ad85e3
commit 7180eff05d
5 changed files with 109 additions and 102 deletions
+17 -40
View File
@@ -6628,13 +6628,24 @@ import { createRenderer } from './src/renderer.js'; // h3d-carve-15
// lookaheadTargetWorldX extracted below in the createCamera() destructure.
// h3d-carve-15 F2: _setLabelMap must be in scope before both createNoteRenderer
// and createRenderer wiring calls; defined here, passed as DI to both factories.
// See renderer.js DI comment for the full explanation.
function _setLabelMap(sprite, srcMat) {
const m = sprite.material;
if (m.map === srcMat.map) return;
const nullnessChanged = (m.map == null) !== (srcMat.map == null);
m.map = srcMat.map;
if (nullnessChanged) m.needsUpdate = true;
}
/* ── h3d-carve-14: V-section (note renderer) → src/note-renderer.js ── */
const { drawNote, drawArpBrackets, drawNotedetectLabels, chordHarmonyLabels } = createNoteRenderer({
// ── Constants ──────────────────────────────────────────────────
K, NFRETS, NW, NH, AHEAD,
GHOST_HOLD_AFTER_ONSET, NEXT_ON_STRING_T_EPS, NOTEDETECT_GEM_VERDICT_WINDOW,
SLIDE_RIBBON_SAMPLES, S_GAP,
BEND_HALFSTEP_WORLD_Y, PROJ_WIN, PROJ_WIN_G, PROJ_GROW_MIN,
BEND_HALFSTEP_WORLD_Y, PROJ_GROW_MIN,
GHOST_FRET_LBL_FADE_S,
BEND_ENV_RISE_FRAC, BEND_ENV_RELEASE_FRAC,
VIBRATO_HALF_WAVE_S, TREMOLO_BUMP_S,
@@ -6838,7 +6849,7 @@ import { createRenderer } from './src/renderer.js'; // h3d-carve-15
// in renderer.js with ponytail: comments.
const { update } = createRenderer({
// ── Consts ─────────────────────────────────────────────────────
K, NFRETS, NW, NH, AHEAD, BEHIND, S_GAP, S_COL,
K, NFRETS, NW, NH, AHEAD, BEHIND, S_GAP,
CAM_FOCUS_BLEND_RATE,
CAM_LOCK_ZOOM_MIN, CAM_LOCK_ZOOM_MAX, CAM_LOCK_CENTER_FRET,
LOOKAHEAD_LOCK_ENGAGE_MAXF, LOOKAHEAD_LOCK_RELEASE_MAXF,
@@ -6846,35 +6857,13 @@ import { createRenderer } from './src/renderer.js'; // h3d-carve-15
FRET_WIDTH_MID, CAM_TGT_BEHIND, CAM_DIST_BASE,
VENUE_GEM_EMISSIVE_MUL, NOTEDETECT_GEM_VERDICT_WINDOW,
INLAY_LABEL_FRETS,
GHOST_HOLD_AFTER_ONSET, camAhead, camTau,
BEAT_HEAD_SEC, SEC_HEAD_SEC,
LANE_BEAT_W, LANE_BEAT_DIV_W, LANE_LANE_W, LANE_OPEN_W, LANE_OPEN_H,
CHORD_BOX_LEAD_S, CHORD_BOX_TRAIL_S, CHORD_BOX_FADE_S,
CHORD_BOX_FRET_LABEL_THRESH_W,
GHOST_HOLD_AFTER_ONSET,
CHORD_FRAME_RIM_MIN, CHORD_FRAME_RIM_FRAC_H,
SLIDE_RIBBON_SAMPLES,
HALO_BAR_HALF_H, HALO_BAR_HALF_W,
PM_X_BOX_TRAIL_S, PM_X_BOX_LEAD_S,
FH_X_BOX_TRAIL_S, FH_X_BOX_LEAD_S,
MUTE_X_LINES_TRAIL_S, MUTE_X_LINES_LEAD_S,
FH_X_LINES_TRAIL_S, FH_X_LINES_LEAD_S,
TECH_PLANE_LEAD_S, TECH_PLANE_TRAIL_S,
CONNECTOR_LINE_LEAD_S, CONNECTOR_LINE_TRAIL_S,
DROP_LINE_TRAIL_S, DROP_LINE_LEAD_S,
SUS_RAIL_LEAD_S, SUS_RAIL_TRAIL_S,
FRET_COL_MARKER_LEAD_S, FRET_COL_MARKER_TRAIL_S,
TEACH_MARK_LBL_TRAIL_S, TEACH_MARK_LBL_LEAD_S,
NOTE_FRET_LABEL_LEAD_S, NOTE_FRET_LABEL_TRAIL_S,
GHOST_FRET_LBL_TRAIL_S, GHOST_FRET_LBL_LEAD_S,
ARP_BRACKET_LEAD_S, ARP_BRACKET_TRAIL_S,
HALO_BAR_LEAD_S, HALO_BAR_TRAIL_S,
SEC_LABEL_LEAD_S, SEC_LABEL_TRAIL_S,
BARLINE_LEAD_S, BARLINE_TRAIL_S,
// ── Fn-refs ─────────────────────────────────────────────────────
sY, xFret, xFretMid, fretLabelScaleForFret, pbBeg, pbEnd, pbReportTick,
hwyFirstRelevantFrettedTime, _syncOpenStringPitchLabels, txtMat, fireDrawHooks,
hwyFirstRelevantFrettedTime, _syncOpenStringPitchLabels, txtMat, _setLabelMap,
// createNoteRenderer outputs:
drawNote, drawArpBrackets, drawNotedetectLabels, chordHarmonyLabels,
drawNote, drawArpBrackets, chordHarmonyLabels,
// createCamera outputs:
camUpdate,
// createArp outputs:
@@ -6888,8 +6877,7 @@ import { createRenderer } from './src/renderer.js'; // h3d-carve-15
arpeggioLaneOuterRailLaneSlice, arpeggioLaneOuterRailAtChartTime,
arpeggioLaneDividerFrameAccentMul, arpeggioLaneDividerXYScaleMatchFrameRim,
// Other fn-refs:
validString, filterValidNotes, fxSpawnPop, drawScoreFx,
_resetStringDependentCaches,
validString, filterValidNotes,
// ── Pool getters (all 33) ────────────────────────────────────────
getPNote: () => pNote,
getPNoteEdge: () => pNoteEdge,
@@ -6944,10 +6932,6 @@ import { createRenderer } from './src/renderer.js'; // h3d-carve-15
getTgtX: () => tgtX,
getTgtDist: () => tgtDist,
getCurX: () => curX,
getCurDist: () => curDist,
getCurLookY: () => curLookY,
getTgtLookY: () => tgtLookY,
getFretRowFitBoost: () => fretRowFitBoost,
getPrevLowFretBonus: () => prevLowFretBonus,
getPrevLockActive: () => prevLockActive,
// ── Lookahead / clock state getters ─────────────────────────────
@@ -6970,8 +6954,6 @@ import { createRenderer } from './src/renderer.js'; // h3d-carve-15
getNdVerdictSawAlpha: () => _ndVerdictSawAlpha,
getNdVerdictMaxAlpha: () => _ndVerdictMaxAlpha,
getNdFrameNowMs: () => _ndFrameNowMs,
getNdHitMarks: () => _ndHitMarks,
getNdMissMarks: () => _ndMissMarks,
// ── Per-frame state getters ──────────────────────────────────────
getInlayLabels: () => _inlayLabels,
getLeanSusPollCounter: () => _leanSusPollCounter,
@@ -6980,11 +6962,6 @@ import { createRenderer } from './src/renderer.js'; // h3d-carve-15
getTextSizeMulApplied: () => _textSizeMulApplied,
getImPMTechCount: () => _imPMTechCount,
getImFHTechCount: () => _imFHTechCount,
getImPMXFillCount: () => _imPMXFillCount,
getImPMXLinesCount: () => _imPMXLinesCount,
getImFHXFillCount: () => _imFHXFillCount,
getImFHXLinesCount: () => _imFHXLinesCount,
getMeasureStarts: () => _measureStarts,
getMeasureStartsRef: () => _measureStartsRef,
// ── Stable object refs ───────────────────────────────────────────
_frameLabeledKeys, _ndLabels, _scrGhostUpcomingCount,
+2 -1
View File
@@ -27,7 +27,8 @@ export function createNoteRenderer({
K, NFRETS, NW, NH, AHEAD,
GHOST_HOLD_AFTER_ONSET, NEXT_ON_STRING_T_EPS, NOTEDETECT_GEM_VERDICT_WINDOW,
SLIDE_RIBBON_SAMPLES, S_GAP,
BEND_HALFSTEP_WORLD_Y, PROJ_WIN, PROJ_WIN_G, PROJ_GROW_MIN,
BEND_HALFSTEP_WORLD_Y, PROJ_GROW_MIN,
// PROJ_WIN, PROJ_WIN_G: body uses hardcoded 0.6/_PROJ_WIN_ARP locals — not DI
GHOST_FRET_LBL_FADE_S,
BEND_ENV_RISE_FRAC, BEND_ENV_RELEASE_FRAC,
VIBRATO_HALF_WAVE_S, TREMOLO_BUMP_S,
+10 -52
View File
@@ -14,7 +14,7 @@ import {
// ─────────────────────────────────────────────────────────────────────────────
export function createRenderer({
// ── Plain consts (shorthand) ──────────────────────────────────────────
K, NFRETS, NW, NH, AHEAD, BEHIND, S_GAP, S_COL,
K, NFRETS, NW, NH, AHEAD, BEHIND, S_GAP,
CAM_FOCUS_BLEND_RATE,
CAM_LOCK_ZOOM_MIN, CAM_LOCK_ZOOM_MAX, CAM_LOCK_CENTER_FRET,
LOOKAHEAD_LOCK_ENGAGE_MAXF, LOOKAHEAD_LOCK_RELEASE_MAXF,
@@ -22,36 +22,14 @@ export function createRenderer({
FRET_WIDTH_MID, CAM_TGT_BEHIND, CAM_DIST_BASE,
VENUE_GEM_EMISSIVE_MUL, NOTEDETECT_GEM_VERDICT_WINDOW,
INLAY_LABEL_FRETS,
GHOST_HOLD_AFTER_ONSET, camAhead, camTau,
BEAT_HEAD_SEC, SEC_HEAD_SEC,
LANE_BEAT_W, LANE_BEAT_DIV_W, LANE_LANE_W, LANE_OPEN_W, LANE_OPEN_H,
CHORD_BOX_LEAD_S, CHORD_BOX_TRAIL_S, CHORD_BOX_FADE_S,
CHORD_BOX_FRET_LABEL_THRESH_W,
GHOST_HOLD_AFTER_ONSET,
CHORD_FRAME_RIM_MIN, CHORD_FRAME_RIM_FRAC_H,
SLIDE_RIBBON_SAMPLES,
HALO_BAR_HALF_H, HALO_BAR_HALF_W,
PM_X_BOX_TRAIL_S, PM_X_BOX_LEAD_S,
FH_X_BOX_TRAIL_S, FH_X_BOX_LEAD_S,
MUTE_X_LINES_TRAIL_S, MUTE_X_LINES_LEAD_S,
FH_X_LINES_TRAIL_S, FH_X_LINES_LEAD_S,
TECH_PLANE_LEAD_S, TECH_PLANE_TRAIL_S,
CONNECTOR_LINE_LEAD_S, CONNECTOR_LINE_TRAIL_S,
DROP_LINE_TRAIL_S, DROP_LINE_LEAD_S,
SUS_RAIL_LEAD_S, SUS_RAIL_TRAIL_S,
FRET_COL_MARKER_LEAD_S, FRET_COL_MARKER_TRAIL_S,
TEACH_MARK_LBL_TRAIL_S, TEACH_MARK_LBL_LEAD_S,
NOTE_FRET_LABEL_LEAD_S, NOTE_FRET_LABEL_TRAIL_S,
GHOST_FRET_LBL_TRAIL_S, GHOST_FRET_LBL_LEAD_S,
ARP_BRACKET_LEAD_S, ARP_BRACKET_TRAIL_S,
HALO_BAR_LEAD_S, HALO_BAR_TRAIL_S,
SEC_LABEL_LEAD_S, SEC_LABEL_TRAIL_S,
BARLINE_LEAD_S, BARLINE_TRAIL_S,
// camAhead, camTau: re-declared as let vars inside update() — not DI
// ── Stable fn-refs (shorthand) ────────────────────────────────────────
sY, xFret, xFretMid, fretLabelScaleForFret, pbBeg, pbEnd, pbReportTick,
hwyFirstRelevantFrettedTime, _syncOpenStringPitchLabels, txtMat,
fireDrawHooks,
hwyFirstRelevantFrettedTime, _syncOpenStringPitchLabels, txtMat, _setLabelMap,
// createNoteRenderer outputs (fn-refs from screen.js wiring):
drawNote, drawArpBrackets, drawNotedetectLabels, chordHarmonyLabels,
drawNote, drawArpBrackets, chordHarmonyLabels,
// createCamera outputs:
camUpdate,
// arp.js outputs (from createArp destructure in screen.js):
@@ -66,8 +44,6 @@ export function createRenderer({
arpeggioLaneDividerFrameAccentMul, arpeggioLaneDividerXYScaleMatchFrameRim,
// other screen.js fn-refs:
validString, filterValidNotes,
fxSpawnPop, drawScoreFx,
_resetStringDependentCaches,
// ── Getters (live state reads) ─────────────────────────────────────────
// New pools:
// All 33 pools (note-renderer 15 + new 18):
@@ -84,8 +60,7 @@ export function createRenderer({
getTextSize, getCameraMode, getCameraSmoothing, getZoomSmoothing,
getCameraLockLow, getCameraLockZoom, getNStr, getLeftyCached, getInverted,
// Camera state:
getTgtX, getTgtDist, getCurX, getCurDist,
getCurLookY, getTgtLookY, getFretRowFitBoost,
getTgtX, getTgtDist, getCurX,
getPrevLowFretBonus, getPrevLockActive,
// Lookahead / clock state:
getLookaheadCamX, getLookaheadFretSpan,
@@ -95,13 +70,11 @@ export function createRenderer({
getCamSnapped, getCamPreScanned, getCamBootstrapHolding, getCamBootstrapMode, getSongKey,
// ND / per-frame state:
getNdVerdictSawAlpha, getNdVerdictMaxAlpha, getNdFrameNowMs,
getNdHitMarks, getNdMissMarks,
// Other frame state:
getInlayLabels,
getLeanSusPollCounter, getLeanSus, getTextSizeMul, getTextSizeMulApplied,
getImPMTechCount, getImFHTechCount,
getImPMXFillCount, getImPMXLinesCount, getImFHXFillCount, getImFHXLinesCount,
getMeasureStarts, getMeasureStartsRef,
getMeasureStartsRef,
// Stable object refs (mutable arrays/maps, passed by reference):
_frameLabeledKeys,
_ndLabels,
@@ -344,24 +317,9 @@ function smoothNow(bundle) {
// draw() after each init.
// txtMat() rasterises into the unbounded cache these draws hit
// anyway; ren.initTexture() forces the GPU upload now.
// Swap a pooled label sprite's cached texture WITHOUT recompiling.
// Setting material.needsUpdate bumps material.version, which forces
// Three.js through getParameters/getProgramCacheKey on the next
// render. Swapping one non-null texture for another does NOT change
// the compiled program (the USE_MAP define is unchanged); only a
// null <-> non-null transition does, and pooled label sprites are
// constructed with a non-null map, so in practice this never
// recompiles. (Note: the DOMINANT getParameters churn turned out to
// be Three's transparent-DoubleSide two-pass path — see the
// forceSinglePass comment in _spriteMat2MeshMat — this helper
// removes the label-swap contribution on top of that.)
function _setLabelMap(sprite, srcMat) {
const m = sprite.material;
if (m.map === srcMat.map) return;
const nullnessChanged = (m.map == null) !== (srcMat.map == null);
m.map = srcMat.map;
if (nullnessChanged) m.needsUpdate = true;
}
// _setLabelMap is defined in screen.js and passed as DI (F2: used by both
// createNoteRenderer and createRenderer — must live in screen.js scope before
// either factory is wired).
let _chartPrewarmed = false;
function _prewarmTex(mat) {