feat(highway_3d): fret wires flash on a confirmed hit#969
Draft
topkoa wants to merge 2 commits into
Draft
Conversation
Contributor
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
The fret wires were static scenery: gold inside the anchor lane, grey outside, and nothing tied them to what the player was actually doing. Give them a job. Widen the lane/neck contrast so the wires around the active lane read as a focus cue, and flash the wires bracketing a note when a scorer confirms it. A fretted note lights the wire behind it and the wire it is pressed against; a chord lights only the outermost wires of its shape, so it reads as one bracketed block rather than a picket fence; an open string has no fret of its own and its gem is drawn as a slab spanning the lane, so it lights the lane's edge wires instead. Gated on the provider verdict, never the proximity heuristic -- the latter only means "near the strike line", so it would flash on every passing note whether or not it was played. With no scorer attached the neck behaves exactly as before. Emissive (and emissiveIntensity) carry the flash, not albedo: these are MeshStandard materials in a scene with no envMap, so raising albedo alone barely brightens them. Every value is a named constant -- see FRET_WIRE_* -- because the look is a taste call that wants tuning by eye, not a derivation. Signed-off-by: Kris Anderson <topkoa@gmail.com>
topkoa
force-pushed
the
feat/highway-3d-fret-wire-hit-flash
branch
from
July 14, 2026 21:50
f55c021 to
981b779
Compare
Bring the branch up to date with main (includes #994, which also touched highway_3d/screen.js — the lane hit-line fix — in a different region).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The 3D highway's fret wires were static scenery — gold inside the anchor lane, grey outside, and nothing tied them to what the player was doing. This gives them a job:
Which wires flash depends on the note:
ff-1andf— the wire behind it, and the wire it's pressed againstThis has not been run. It typechecks and the logic is reviewed, but every value here is a taste call that has to be judged by eye, and it hasn't been. The brightness in particular went through several rounds of "brighter" / "too bright" and landed at a value that was never actually looked at. Treat the constants as a starting point, not a finished look.
The levers — all named constants, all in one block
All in
plugins/highway_3d/screen.js, in the fret-wire constants block next toFRET_METALNESS/FRET_BOW_DZ. Nothing here is derived from anything else, so each can be moved independently.Hit flash
FRET_WIRE_HIT_INTENSITY4.2emissiveIntensityat full flash (baseline1). This is what makes a wire read as a light source rather than a brightly-lit object. Went3.0 → 6.0 → 4.2; last feedback on6.0was "slightly too bright", so4.2is an untested guess between.FRET_WIRE_HIT_DECAY0.320.22before dropping the intensity.FRET_WIRE_HIT_EMISSIVE0xFFE9B0FRET_WIRE_HIT_HEX0xFFFFFFFRET_WIRE_HIT_OP1.0Why emissive and not colour: these are
MeshStandardMaterialin a scene with no envMap, so raising albedo alone barely brightens them — it saturates toward white and stops.emissiveIntensityis the lever with real range. Corollary: there's no bloom/post-processing pass in this scene, so past ~8 you're just painting white pixels for longer and can't get glow bleed into the surrounding area. If it needs to be brighter than the material can go, the next step is an additive halo mesh around the flashing wire — a bigger change, not a constant.Base look (the two idle tiers)
FRET_WIRE_ACTIVE_HEX/_OP0xD8A636/0.90xD8A636/0.8FRET_WIRE_IDLE_HEX/_OP0x4A4A60/0.280x666688/0.4FRET_TUBE_RADIUSSTR_THICK * 0.75* 0.55FRET_TUBE_RADIAL86Things to actually look at when picking this up
0.32s tail, consecutive notes on nearby frets overlap their flashes, so neighbouring wires may stay lit more or less continuously. That could look great (a glowing band tracking your hand) or muddy (nothing ever goes dark). This is the single most likely thing to need tuning.alphatracking live input level for a held note, which jitters frame to frame. The decay tail is what smooths it — check it's actually smooth and not pulsing.0.28vs0.4); confirm distant wires haven't been swallowed entirely.anchorLaneBoundsAtreturns null, so open-string flashes silently do nothing (fretted notes are unaffected). Rare — GP imports synthesise anchors — but it's the one case that fails quietly rather than visibly.Implementation notes for a reviewer
_ndGood), never the proximityhitheuristic. The latter only means "near the strike line" — using it would flash on every passing note whether or not it was played. So with no scorer attached, the neck behaves exactly as it does today.update(), long before any note is drawn. The flash is applied in a second pass after the note and chord draw loops, so it sees this frame's verdicts rather than the previous frame's.emissive/emissiveIntensityare re-seeded to baseline in the tier loop each frame — without that, a flash would never fade back out.drawNote()is the chord loop's per-note call and can't see the chord's span, so chord hits collect into a smallMap(keyed by chord id, falling back to chord time —ch.idcan be absent, a documented pitfall) and the flash pass resolves min/max fret into the outer wire pair. This avoided restructuring the chord loop with begin/end hooks.drawNote()is a sibling ofupdate(), not nested in it, so the anchors are snapshotted into a closure var (_drawAnchors) — following the pattern already established there for_drawChordTemplates.🤖 Generated with Claude Code