Skip to content

fix(ui): resolve hover flicker on icon edges and quote sound-in SCSS …#10485

Closed
pedroforbeck wants to merge 953 commits intoFacepunch:masterfrom
pedroforbeck:fix/hover-flicker-rebased
Closed

fix(ui): resolve hover flicker on icon edges and quote sound-in SCSS …#10485
pedroforbeck wants to merge 953 commits intoFacepunch:masterfrom
pedroforbeck:fix/hover-flicker-rebased

Conversation

@pedroforbeck
Copy link
Copy Markdown

Pull Request

Summary

Resolves hover state flickering on icon edges in the main menu and fixes SCSS compilation errors caused by unquoted sound-in property values across the entire menu addon.

When the cursor is near the border of interactive icons (Maps tab, "Create a Party", "Friends"), the hover state rapidly toggles on/off due to tooltip panels intercepting mouse events, tight hit areas, and a ::after overlay stealing pointer events on GameCard. This PR eliminates the flicker and also quotes all sound-in SCSS values to prevent "identifier or variable expected" parse errors.

Motivation & Context

Users experience a jarring visual flicker when hovering near icon edges in the main menu. The root causes are:

  1. Tooltip child panels intercept MouseLeave from parent icons, causing a hover loop
  2. Icon hit areas are too tight, causing sub-pixel edge detection issues
  3. GameCard's ::after pseudo-element had pointer-events: all, stealing events at card edges
  4. All sound-in values used unquoted dot-separated tokens that SCSS interprets as member access

Fixes: #10329

Implementation Details

Hover flicker fixes (6 files):

  • Added pointer-events: none to .tooltip in MainMenu.razor.scss and MenuOverlay.cs.scss so tooltips no longer intercept mouse events from parent icons
  • Expanded hit areas: padding: 4px + margin: -4px on Avatar, padding 0px6px on PartyDeck .vertical-button, padding 4px8px on FriendEntry
  • Changed pointer-events: allpointer-events: none on GameCard ::after overlay

SCSS sound-in quoting (23 files total):

  • Wrapped all sound-in values in double quotes (e.g., sound-in: "ui.button.over") to prevent SCSS from parsing dot-separated tokens as member access chains. This is a codebase-wide fix — every occurrence across the menu addon has been quoted.

All padding changes use compensating negative margins so visual layout is unchanged.

Screenshots / Videos (if applicable)

Unable to provide runtime screenshots as s&box is not yet publicly available on Steam and building from source requires dependencies not currently installed. However, the changes are purely SCSS and can be verified by code review:

  • pointer-events: none on tooltips prevents them from intercepting parent hover events
  • Padding expansion with compensating negative margins widens hit areas without layout shift
  • ::after overlay changed from pointer-events: all to none stops it from stealing mouse events
  • All sound-in values quoted to fix SCSS compilation errors

Checklist

  • Code follows existing style and conventions
  • No unnecessary formatting or unrelated changes
  • Public APIs are documented (if applicable)
  • Unit tests added where applicable and all passing
  • I'm okay with this PR being rejected or requested to change 🙂

lolleko and others added 30 commits March 9, 2026 11:05
So we don't allocate when a GameObejct doesn't have any tags
Fast & alloc free pass for GameTags.SetFrom
* Remove unnecessary static singletons in MainMenu code

* Empty SceneWorld delete queues during shutdown

* Dresser cancel async load operation on destroy

* Use reflection to null references to static native resources on shutdown

This way we don't  have to remember doing this manually.

* Fix SoundOcclusionSystem using static lists to reference resources

* Sound System: Use weak references to refer to scenes

* Cleanup static logging listeners that kept strong refs to panels

* UISystem Cleanup, make sure all panel/stylesheet refs are released

* RenderTarget and RenderAttributes shutdown cleanup

* Rework AvatarLoader, ThumbLoader & HTTPImageLoader Cache

First try to go through ResourceLibrary.WeakIndex which might already hold the texture.

If there is no hit, go through a second cache that caches HTTP & Steam API response bytes instead of textures.
We want to cache the response bytes rather than the actual Texture, so stuff cached sits in RAM not VRAM.
Before avatars and thumbs would reside in VRAM.

* Fix rendertarget leak in CommandList.Attr.SetValue

GetDepthTarget() / GetColorTarget() return a new strong handle (ref count +1).
We need to DestroyStrongHandle()  that ref. So handles don't leak.

* Call EngineLoop.DrainFrameEndDisposables before shutdown

* NativeResourceCache now report leaks on shutdown

* Override Resource.Destroy for native resources, kill stronghandles

* Deregister SceneWorld from SceneWorld.All during destruction

* Ensure async texture loading cancels on shutdown

* SkinnedModelRender bonemergetarget deregister from target OnDisabled

* Clear shaderMaterials cache during shutdown

* Refactor Shutdown code

Mostly renaming methods from Clear() -> Shutdown()
Adding separate GlobalContext.Shutdown function (more aggressive than GlobalContext.Reset).
Clear some static input state.

* Deregister surfaces from Surface.All in OnDestroy

* RunAllStaticConstructors when loading a mount

* Advanced managed resource leak tracker enabled via `resource_leak_tracking 1`

Works by never pruning the WeakTable in NativeResourceCache.
So we can check for all resources if they are still being held on to and log a callstack.
* Support types like Curve, Gradient, ParticleGradient in movies
* Fix TransformOperation.OnReduce: old implementation was nonsense, could stack overflow
* Add optional filePath parameter to GenerateScreenshotFilename
* Force movie project to save even if we don't think it's changed
* ITemporaryEffect.IsActive pseudo-property for movie recordings
* Add ITrack.GetPathString() extension
* Safety when trying to compress a sample block
* Skip updating playback rate on renderers with a bone merge target
* Move PropertySignal<T>.FromSamples to PropertySignal
* Fix view not always updating when zooming
* Enabled tracks defaults to false when applying
* Movie export: manually call Scene.EditorTick, pause updates elsewhere (fixes Facepunch#10137)
* CanMakeTrackFromProperties: default to only allowing user types
Introduced in Facepunch/sbox#4242 , which added some additional panel cleanup
Ignore static members when serializing or cloning components, makes no sense and breaks cloning with Expression Trees (that was introduced in Facepunch/sbox#4202)

Fixes Facepunch#10161
Synthesizer never disposed its SpeechSynthesizer, causing background VoiceSynthesis threads to accumulate indefinitely (30+ seen in crash dumps).
This may have caused crashes in TTS heavy games like DXRP.

In addition we now properly terminate the SoundStream so SoundHandle.IsPlaying will become false after the stream has been played.

See: Facepunch#4184
Needs to be rethought, it gets in the way often -- keeping view handle though
* Sync localisation files to clients thru network files
* Changing lang triggers Panel.LanguageChanged again, so we can rebuild panels, labels, etc.
* Init ActiveFriends as Enumerable.Empty

* Snip IconPanel logging its url
…punch#4283)

Benchmark runner loads scenes in succession.
If a previous scene already generated a navmesh, on the load of another scene the navmesh bounds would not update, because the bounds where already set by the previous scene.
Fixed by always updating the bounds if CustomBounds is not set.
* Kill CrashReporter before unloading steam DLL

* Properly shutdown SteamAPI on SourceEngine exit

* Smaller minidumps for retail builds

We can use a minimal minidump and still extract managed stack traces
lolleko and others added 21 commits April 12, 2026 13:27
…acepunch#4525)

* WildcardMatch use MatchesSimpleExpression instead of expensive regex

* More WildcardMatch tests
Dot-based AlmostEqual returned false for zero quaternions (default==default would be false), breaking the transform guard that catches uninitialized transforms.
* Don't UpdatePrefabInstances if the edited PrefabScene is the only one open in editor

* Avoid some allocations when processing prefab guid mappings

* Json Diff use 64bit hash isntead of paths for presence tracking, which avoids a ton of string allocations

* Less LINQ in prefab GUID tracking code
* Add Texture Pool section to shadow debug

https://files.facepunch.com/lolleko/2026/April/13_16-21-UsedRook.png

Shows of orphaned textures (in flight stat keeps growing.

* Return shadow map to pool when light is destroyed

https://files.facepunch.com/lolleko/2026/April/13_16-24-ClutteredCooter.png

* Use Queue instead of Stack for shadow texture pool eviction

We want FIFO semantics instead of LIFO.
Stack (LIFO) buried old textures under newer ones, potentially preventing disposal

* Remove unused OnLightRemoved callback
* Reduce allocation pressure in shadow mapper hot path.

Gets rid of a Bunch of array, IEnumerable and LINQ allocations.
It's only tiny bit more verbose

* Avoid string allocation every frame

* FindOrCreateProjectedCubeShadowMap: avoid allocations & frustum/matrix math

* AddShadowView: avoid CFmtStr in hot path
- Fix hotloading breaking ScenePanels
- `ScenePanel.Scene` setter now handles cleanup and will make sure re-assigning the same scene instance doessn't break anything
- Add tests
- `movie` command records light components
- Only include shadow properties if shadows are enabled
- Record DirectionalLight.SkyColor so things like day/night cycles are included in recordings properly

https://files.facepunch.com/CarsonKompon/2026/April/13_11-16-RoastedRook.mp4
* Hotspot tweaks

-Use Active Material
-Allow Mirror Horizontal/ Vertical
-Button for apply per face.

https://files.facepunch.com/louie/1b1411b1/sbox-dev_M3ykoez2o2.png
* Make Editable Mesh inside undo scope

* Copilot suggestion

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Stupid robot just getcomponent

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
New UI rendering that groups multiple panels to be grouped into a single draw call when possible.

New custom rendering API for custom panels using `Panel.Draw.XX` to emit drawing commands.
* Remove duplicated linux libraries and renamed them correctly, managed native libraries should have no versioning, libswscale was still being symlinked

* Fix case sensitiveness on these, causes Code folder to be doubled and make case insensitive vfs confused, no idea how this even happened

* Fix case sensitivity in asset paths to ensure sanity
* Use Hilbert Index instead of Blue Noise for GTAO, same as the original paper, allows us to have better quality with less work, GTAOPasses::DenoiseSpatial does two pixels for one thread

* Force Float16 for GTAO, good speedups on modern GPUs, default behaviour from reference implementation, do explicit casts to supress warnings

* More accurate MSAAUtils::GetSampleIndex  https://files.facepunch.com/sampavlovic/1b2611b1/image.psd.png

* adjustments

* reduce blending for non-edge pixels to preserve more details instead of using the raw amount at edges

* Early out here, no good way to have a non uniform size dispatch yet, should still keep 2x spatial speedup

* Remove unused comment

* update shaders
…values

- Add pointer-events: none to tooltip panels (MainMenu, MenuOverlay)
- Expand icon hit areas with padding (Avatar, PartyDeck, FriendEntry)
- Fix ::after overlay stealing pointer events (GameCard)
- Quote all sound-in values to prevent SCSS parse errors (23 files)

Fixes Facepunch#10329
@boxden
Copy link
Copy Markdown

boxden commented Apr 15, 2026

Pedro, I just checked, the issue is still there

sbox_mfmdDIGoxR.mp4

@pedroforbeck
Copy link
Copy Markdown
Author

pedroforbeck commented Apr 16, 2026

Pedro, I just checked, the issue is still there

sbox_mfmdDIGoxR.mp4

Got it, thanks for the video! I'm on it. I'll investigate why the fix didn't cover this case and update the PR as soon as possible.

@pedroforbeck
Copy link
Copy Markdown
Author

Pedro, I just checked, the issue is still there

sbox_mfmdDIGoxR.mp4

I've pushed another fix focusing strictly on pointer-events. The inner items (such as IconPanel, i, and the avatars) were intercepting events when transitioning over their outlines rather than the encapsulating containers securely obtaining the hits box bounds. Let me know if that finally rectifies the rendering edge behavior.

@boxden
Copy link
Copy Markdown

boxden commented Apr 16, 2026

Compiled with the latest changes, issue is still present

@pedroforbeck pedroforbeck force-pushed the fix/hover-flicker-rebased branch from 67dbc88 to f502831 Compare April 16, 2026 01:41
@pedroforbeck
Copy link
Copy Markdown
Author

Compiled with the latest changes, issue is still present

Thanks for checking again. I've completely refactored the tooltip rendering overlay parameters – the inner text elements of dynamically spawned components were mistakenly intercepting cursors during bounding sweeps. I've sent down a reset pushing global exclusions. If for some reason the rendering jitter keeps occurring under these properties, I will dive significantly deeper into the core HitTest engine parameters tomorrow morning.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UI hover flickering when cursor is near icon edges