Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add delayed resume for taiko/catch/mania #27079

Merged
merged 18 commits into from
Mar 21, 2024
Merged

Conversation

smoogipoo
Copy link
Contributor

Resolves #10202
Supersedes / closes #26992

@bdach
Copy link
Collaborator

bdach commented Feb 10, 2024

The lack of any visual cue here is bothering me. It's almost like a second pause, I find myself struggling to anticipate the moment where gameplay resumes.

Maybe we could do something super simple like this even at least? (very rough)

diff --git a/osu.Game/Screens/Play/DelayedResumeOverlay.cs b/osu.Game/Screens/Play/DelayedResumeOverlay.cs
index ef39c8eb76..5dfbb681c9 100644
--- a/osu.Game/Screens/Play/DelayedResumeOverlay.cs
+++ b/osu.Game/Screens/Play/DelayedResumeOverlay.cs
@@ -1,6 +1,9 @@
 // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
 // See the LICENCE file in the repository root for full licence text.
 
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Shapes;
 using osu.Framework.Localisation;
 using osu.Framework.Threading;
 
@@ -14,10 +17,24 @@ public partial class DelayedResumeOverlay : ResumeOverlay
         protected override LocalisableString Message => string.Empty;
 
         private ScheduledDelegate? scheduledResume;
+        private Box background = null!;
+
+        [BackgroundDependencyLoader]
+        private void load()
+        {
+            Add(background = new Box
+            {
+                RelativeSizeAxes = Axes.Both,
+                Colour = Colour4.Black,
+                Alpha = 0.75f,
+            });
+        }
 
         protected override void PopIn()
         {
-            base.PopIn();
+            this.FadeIn();
+            background.FadeIn()
+                      .Then().FadeOut(800, Easing.OutSine);
 
             scheduledResume?.Cancel();
             scheduledResume = Scheduler.AddDelayed(Resume, 800);
@@ -25,7 +42,8 @@ protected override void PopIn()
 
         protected override void PopOut()
         {
-            base.PopOut();
+            this.FadeOut();
+
             scheduledResume?.Cancel();
         }
     }

@pull-request-size pull-request-size bot added size/L and removed size/M labels Mar 4, 2024
@smoogipoo
Copy link
Contributor Author

I didn't really like the fading overlay because it doesn't work well with the classic taiko skin. I tried to add a countdown instead:

https://drive.google.com/file/d/1wAnOjFAirLGd7cn2jULz0A7sl0jD2q0q/view?usp=sharing

AutoSizeAxes = Axes.Both,
Masking = true,
BorderColour = colours.Yellow,
BorderThickness = 1,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 is... not much... It aliases pretty badly on my screen. I'd probably put in at least 2.

BorderThickness = 2 BorderThickness = 1
osu_2024-03-05_18-53-43 osu_2024-03-05_18-51-49

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the animation in general - it's obviously going to be subjective but I find myself wanting to apply a few improvements to it, namely:

  • It zooms in too fast for my liking, I'd increase the countdown interval
  • The fade-in is concurrent with the counting, I'd like it not to be

Something like the following feels better to me personally, so open to thoughts on that:

diff --git a/osu.Game/Screens/Play/DelayedResumeOverlay.cs b/osu.Game/Screens/Play/DelayedResumeOverlay.cs
index 08d00f8ac2..9c23bf5cfa 100644
--- a/osu.Game/Screens/Play/DelayedResumeOverlay.cs
+++ b/osu.Game/Screens/Play/DelayedResumeOverlay.cs
@@ -21,7 +21,7 @@ namespace osu.Game.Screens.Play
     /// </summary>
     public partial class DelayedResumeOverlay : ResumeOverlay
     {
-        private const double countdown_time = 800;
+        private const double countdown_time = 1000;
 
         protected override LocalisableString Message => string.Empty;
 
@@ -97,7 +97,7 @@ protected override void PopIn()
             content.ScaleTo(new Vector2(1.5f, 1)).Then().ScaleTo(1, 150, Easing.OutElasticQuarter);
 
             countdownCount = 3;
-            countdownStartTime = Time.Current;
+            countdownStartTime = content.LatestTransformEndTime;
 
             scheduledResume?.Cancel();
             scheduledResume = Scheduler.AddDelayed(Resume, countdown_time);
@@ -114,7 +114,7 @@ private void updateCountdown()
             double amountTimePassed = Math.Min(countdown_time, Time.Current - countdownStartTime) / countdown_time;
             int newCount = 3 - (int)Math.Floor(amountTimePassed * 3);
 
-            if (newCount > 0)
+            if (newCount > 0 && newCount <= 3)
             {
                 countdown.Alpha = 1;
                 countdown.Text = newCount.ToString();

Copy link
Contributor Author

@smoogipoo smoogipoo Mar 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kind of don't really like the delay, because it feels empty for the first little bit and then it jumps. I have this other idea in mind, which might fit better?

diff --git a/osu.Game/Screens/Play/DelayedResumeOverlay.cs b/osu.Game/Screens/Play/DelayedResumeOverlay.cs
index ba49810b2b..ca4a421bd4 100644
--- a/osu.Game/Screens/Play/DelayedResumeOverlay.cs
+++ b/osu.Game/Screens/Play/DelayedResumeOverlay.cs
@@ -4,8 +4,6 @@
 using System;
 using osu.Framework.Allocation;
 using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Shapes;
 using osu.Framework.Graphics.Sprites;
 using osu.Framework.Localisation;
 using osu.Framework.Threading;
@@ -21,7 +19,7 @@ namespace osu.Game.Screens.Play
     /// </summary>
     public partial class DelayedResumeOverlay : ResumeOverlay
     {
-        private const double countdown_time = 800;
+        private const double countdown_time = 1000;
 
         protected override LocalisableString Message => string.Empty;
 
@@ -32,7 +30,6 @@ public partial class DelayedResumeOverlay : ResumeOverlay
         private int countdownCount = 3;
         private double countdownStartTime;
 
-        private Drawable content = null!;
         private SpriteText countdown = null!;
 
         public DelayedResumeOverlay()
@@ -44,48 +41,16 @@ public DelayedResumeOverlay()
         [BackgroundDependencyLoader]
         private void load()
         {
-            Add(content = new CircularContainer
+            Add(countdown = new OsuSpriteText
             {
                 Anchor = Anchor.Centre,
                 Origin = Anchor.Centre,
-                AutoSizeAxes = Axes.Both,
-                Masking = true,
-                BorderColour = colours.Yellow,
-                BorderThickness = 2,
-                Children = new Drawable[]
-                {
-                    new Box
-                    {
-                        Size = new Vector2(250, 40),
-                        Colour = Color4.Black,
-                        Alpha = 0.8f
-                    },
-                    new Container
-                    {
-                        Anchor = Anchor.Centre,
-                        Origin = Anchor.Centre,
-                        AutoSizeAxes = Axes.Both,
-                        Children = new Drawable[]
-                        {
-                            new FillFlowContainer
-                            {
-                                Anchor = Anchor.Centre,
-                                Origin = Anchor.Centre,
-                                AutoSizeAxes = Axes.Both,
-                                Spacing = new Vector2(5),
-                                Colour = colours.Yellow,
-                                Child = countdown = new OsuSpriteText
-                                {
-                                    Anchor = Anchor.Centre,
-                                    Origin = Anchor.Centre,
-                                    UseFullGlyphHeight = false,
-                                    AlwaysPresent = true,
-                                    Font = OsuFont.Numeric.With(size: 20, fixedWidth: true)
-                                },
-                            }
-                        }
-                    }
-                }
+                UseFullGlyphHeight = false,
+                Colour = colours.Yellow,
+                Font = OsuFont.Numeric.With(size: 40, fixedWidth: true),
+                // Harsh shadow to make this visible on top of a wide range of backgrounds.
+                Shadow = true,
+                ShadowColour = Color4.Black
             });
         }
 
@@ -93,10 +58,7 @@ protected override void PopIn()
         {
             this.FadeIn();
 
-            content.FadeInFromZero(150, Easing.OutQuint);
-            content.ScaleTo(new Vector2(1.5f, 1)).Then().ScaleTo(1, 150, Easing.OutElasticQuarter);
-
-            countdownCount = 3;
+            countdownCount = -1;
             countdownStartTime = Time.Current;
 
             scheduledResume?.Cancel();
@@ -111,23 +73,17 @@ protected override void Update()
 
         private void updateCountdown()
         {
-            double amountTimePassed = Math.Min(countdown_time, Time.Current - countdownStartTime) / countdown_time;
+            double amountTimePassed = Math.Clamp(Time.Current - countdownStartTime, 0, countdown_time) / countdown_time;
             int newCount = 3 - (int)Math.Floor(amountTimePassed * 3);
 
-            if (newCount > 0)
-            {
-                countdown.Alpha = 1;
-                countdown.Text = newCount.ToString();
-            }
-            else
-                countdown.Alpha = 0;
+            countdown.Text = newCount > 0 ? newCount.ToString() : "GO";
 
             if (newCount != countdownCount)
             {
                 if (newCount == 0)
-                    content.ScaleTo(new Vector2(1.5f, 1), 150, Easing.OutQuint);
+                    countdown.ScaleTo(new Vector2(1.25f, 1), 150, Easing.OutQuint);
                 else
-                    content.ScaleTo(new Vector2(1.05f, 1), 50, Easing.OutQuint).Then().ScaleTo(1, 50, Easing.Out);
+                    countdown.ScaleTo(1.5f, 50, Easing.OutQuint).Then().ScaleTo(1, 50, Easing.Out);
             }
 
             countdownCount = newCount;
@@ -135,10 +91,7 @@ private void updateCountdown()
 
         protected override void PopOut()
         {
-            this.Delay(150).FadeOut();
-
-            content.FadeOut(150, Easing.OutQuint);
-
+            this.FadeOut(150, Easing.Out);
             scheduledResume?.Cancel();
         }
     }

In the future this should probably use the countdown display from gameplay, which more closely matches this, but that isn't implemented yet.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kind of don't really like the delay, because it feels empty for the first little bit and then it jumps.

I'm not gonna insist on that too much, just bumping the interval is enough as far as I'm concerned.

I have this other idea in mind, which might fit better?

Can't say I like this other proposal too much :/ The background is important, it ensures that the count-in is actually seen. While a plain counter sometimes just isn't doing enough visually to cut through everything else for me:

osu_2024-03-07_10-11-02
osu_2024-03-07_10-12-44

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's why I added the background in the first place, and tried to make it look "good"... :(

Copy link
Member

@peppy peppy Mar 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dunno, why are we dev-designing this when we have a full time designer? None of the above seem any good to me. The animations and presence are off.

@arflyte please advise by end of week so we can get this in the game, just need anything that looks better than these proposals. including animation.

Copy link
Contributor Author

@smoogipoo smoogipoo Mar 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a little bit of my own flavour to it because the countdown felt a little bit empty, but how does this look?

https://drive.google.com/file/d/1wesAUY891v9PphMWxXutfYs5aAIiiRf7/view?usp=sharing
https://drive.google.com/file/d/1wg8NUfX9E7rM6vMIrCt1AVU6cVTC-0HO/view?usp=sharing

(videos are 120fps if downloaded)

One thing I'm not sure about is it looks like this was intended to be centred to the screen whereas this is currently centred to the playfield. I thought it'd look worse than it does but still need opinions.

@arflyte please advise further.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How it looks with a reduced timer (videos above are 3s, old was 800ms, this is 1sec):

https://drive.google.com/file/d/1wlNhXZoWD8p0OmcnYXlNdn1Jya8juf03/view?usp=sharing

And without the outer bounce:

https://drive.google.com/file/d/1wmJ3srApVAoKKZRDeT8xSEunwEFzZ126/view?usp=sharing

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is okay as a starting point, I'll apply some changes of my own on top of this though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not flyte, but I think the counter needs a different background colour with possibly a drop shadow below it, it's conflicting badly with the background colour of the taiko playfield.

The hue is probably going to be different from the argon HUD, but using B5/B6 of OverlayColourScheme.Blue would look somewhat better:

CleanShot.2024-03-14.at.06.49.35.mp4

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was part of the change I was going to make – it had zero definition.

What you propose looks better, so feel free to commit that ahead of me making further changes to animation.

@@ -52,5 +54,7 @@ private void load()
protected override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo);

public override DrawableHitObject<CatchHitObject>? CreateDrawableRepresentation(CatchHitObject h) => null;

protected override ResumeOverlay CreateResumeOverlay() => new DelayedResumeOverlay { Scale = new Vector2(0.65f) };
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was 0.65f derived from something or is that a throwaway figure?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to comment on this, but it's an eyeballed value that brings the size of it in line with other rulesets. Looks like the playfield adjustment container is scaling things up here.

I'll either comment on it, or remove it if my above proposal is accepted (because it doesn't look too bad there).

@peppy
Copy link
Member

peppy commented Mar 14, 2024

This needs sound effects added of any kind.

Also I dunno, it still feels super out of place and awkward.

@smoogipoo
Copy link
Contributor Author

Also I dunno, it still feels super out of place and awkward.

Is that in relation to the design or what? This originally didn't have any design which matches stable. I imagine a world in which every ruleset has a resume overlay that matches gameplay, but that increases the scope of this PR a thousand-fold.

It was intended as an early thing that could be agreed to without much discussion...

@frenzibyte
Copy link
Member

I've added what I felt would make it good and got this:

CleanShot.2024-03-16.at.06.47.49.mp4

Basically made the countdown appear specifically on the center of the screen, and added a dim to indicate that the game is still paused and there's a countdown.

patch
diff --git a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs
index adc7bd97ff..2401b044c4 100644
--- a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs
+++ b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs
@@ -28,6 +28,22 @@ public partial class OsuResumeOverlay : ResumeOverlay
 
         protected override LocalisableString Message => "Click the orange cursor to resume";
 
+        private readonly Container content;
+
+        protected override Container<Drawable> Content => content;
+
+        public OsuResumeOverlay()
+        {
+            InternalChild = new OsuPlayfieldAdjustmentContainer
+            {
+                AlignWithStoryboard = true,
+                Child = content = new Container
+                {
+                    RelativeSizeAxes = Axes.Both,
+                },
+            };
+        }
+
         [BackgroundDependencyLoader]
         private void load()
         {
@@ -40,7 +56,7 @@ private void load()
         protected override void PopIn()
         {
             // Can't display if the cursor is outside the window.
-            if (GameplayCursor.LastFrameState == Visibility.Hidden || !Contains(GameplayCursor.ActiveCursor.ScreenSpaceDrawQuad.Centre))
+            if (GameplayCursor.LastFrameState == Visibility.Hidden || !Content.Contains(GameplayCursor.ActiveCursor.ScreenSpaceDrawQuad.Centre))
             {
                 Resume();
                 return;
@@ -49,7 +65,7 @@ protected override void PopIn()
             base.PopIn();
 
             GameplayCursor.ActiveCursor.Hide();
-            cursorScaleContainer.Position = ToLocalSpace(GameplayCursor.ActiveCursor.ScreenSpaceDrawQuad.Centre);
+            cursorScaleContainer.Position = GameplayCursor.ActiveCursor.Position;
             clickToResumeCursor.Appear();
 
             if (localCursorContainer == null)
diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs
index a422761800..1f474af10f 100644
--- a/osu.Game/Rulesets/UI/DrawableRuleset.cs
+++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs
@@ -207,8 +207,7 @@ private void load(CancellationToken? cancellationToken)
             if ((ResumeOverlay = CreateResumeOverlay()) != null)
             {
                 AddInternal(CreateInputManager()
-                    .WithChild(CreatePlayfieldAdjustmentContainer()
-                        .WithChild(ResumeOverlay)));
+                    .WithChild(ResumeOverlay));
             }
 
             applyRulesetMods(Mods, config);
diff --git a/osu.Game/Screens/Play/DelayedResumeOverlay.cs b/osu.Game/Screens/Play/DelayedResumeOverlay.cs
index fd1ce5d829..392c636cc2 100644
--- a/osu.Game/Screens/Play/DelayedResumeOverlay.cs
+++ b/osu.Game/Screens/Play/DelayedResumeOverlay.cs
@@ -3,6 +3,7 @@
 
 using System;
 using osu.Framework.Allocation;
+using osu.Framework.Extensions.Color4Extensions;
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Containers;
 using osu.Framework.Graphics.Shapes;
@@ -14,6 +15,8 @@
 using osu.Game.Graphics.Sprites;
 using osu.Game.Overlays;
 using osuTK;
+using osuTK.Graphics;
+using Box = osu.Framework.Graphics.Shapes.Box;
 
 namespace osu.Game.Screens.Play
 {
@@ -39,6 +42,7 @@ public partial class DelayedResumeOverlay : ResumeOverlay
         private double countdownStartTime;
         private bool countdownComplete;
 
+        private Box dim = null!;
         private Drawable outerContent = null!;
         private Container innerContent = null!;
 
@@ -56,6 +60,12 @@ public DelayedResumeOverlay()
         [BackgroundDependencyLoader]
         private void load()
         {
+            Add(dim = new Box
+            {
+                RelativeSizeAxes = Axes.Both,
+                Colour = Color4.Black.Opacity(0.75f),
+            });
+
             Add(outerContent = new Circle
             {
                 Anchor = Anchor.Centre,
@@ -109,6 +119,8 @@ protected override void PopIn()
         {
             this.FadeIn();
 
+            dim.FadeIn();
+
             // The transition effects.
             outerContent.FadeIn().ScaleTo(Vector2.Zero).Then().ScaleTo(Vector2.One, 200, Easing.OutQuint);
             innerContent.FadeIn().ScaleTo(Vector2.Zero).Then().ScaleTo(Vector2.One, 400, Easing.OutElasticHalf);
@@ -143,9 +155,13 @@ protected override void PopOut()
             {
                 countdownProgress.ScaleTo(2f, 300, Easing.OutQuint);
                 countdownProgress.FadeOut(300, Easing.OutQuint);
+                dim.FadeOut(300, Easing.OutQuint);
             }
             else
+            {
                 countdownProgress.FadeOut();
+                dim.FadeOut(GameplayMenuOverlay.TRANSITION_DURATION, Easing.InQuint);
+            }
 
             scheduledResume?.Cancel();
         }
diff --git a/osu.Game/Screens/Play/GameplayMenuOverlay.cs b/osu.Game/Screens/Play/GameplayMenuOverlay.cs
index da239d585e..e87c04363d 100644
--- a/osu.Game/Screens/Play/GameplayMenuOverlay.cs
+++ b/osu.Game/Screens/Play/GameplayMenuOverlay.cs
@@ -27,7 +27,7 @@ namespace osu.Game.Screens.Play
 {
     public abstract partial class GameplayMenuOverlay : OverlayContainer, IKeyBindingHandler<GlobalAction>
     {
-        protected const int TRANSITION_DURATION = 200;
+        public const int TRANSITION_DURATION = 200;
 
         private const int button_height = 70;
         private const float background_alpha = 0.75f;

@peppy
Copy link
Member

peppy commented Mar 16, 2024

Dim is too harsh, the idea is to prepare for gameplay so you need to be able to see it.

@nekodex
Copy link
Contributor

nekodex commented Mar 21, 2024

@peppy asked me to whip some sound design for this, so here's something I quickly put together:

resume2.mov

Feel free to adjust to taste or whatever. PR for sample: ppy/osu-resources#314

diff
diff --git a/osu.Game/Screens/Play/DelayedResumeOverlay.cs b/osu.Game/Screens/Play/DelayedResumeOverlay.cs
index 8bb3ae8182..9de6f94d59 100644
--- a/osu.Game/Screens/Play/DelayedResumeOverlay.cs
+++ b/osu.Game/Screens/Play/DelayedResumeOverlay.cs
@@ -3,6 +3,8 @@
 
 using System;
 using osu.Framework.Allocation;
+using osu.Framework.Audio;
+using osu.Framework.Audio.Sample;
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Containers;
 using osu.Framework.Graphics.Shapes;
@@ -47,6 +49,8 @@ public partial class DelayedResumeOverlay : ResumeOverlay
         private SpriteText countdownText = null!;
         private CircularProgress countdownProgress = null!;
 
+        private Sample sampleCountdown = null!;
+
         public DelayedResumeOverlay()
         {
             Anchor = Anchor.Centre;
@@ -54,7 +58,7 @@ public DelayedResumeOverlay()
         }
 
         [BackgroundDependencyLoader]
-        private void load()
+        private void load(AudioManager audio)
         {
             Add(outerContent = new Circle
             {
@@ -103,6 +107,8 @@ private void load()
                     }
                 }
             });
+
+            sampleCountdown = audio.Samples.Get(@"Gameplay/resume-countdown");
         }
 
         protected override void PopIn()
@@ -164,13 +170,20 @@ private void updateCountdown()
             countdownProgress.Progress = amountTimePassed;
             countdownProgress.InnerRadius = progress_stroke_width / progress_size / countdownProgress.Scale.X;
 
-            if (countdownCount != newCount && newCount > 0)
+            if (countdownCount != newCount)
             {
-                countdownText.Text = Math.Max(1, newCount).ToString();
-                countdownText.ScaleTo(0.25f).Then().ScaleTo(1, 200, Easing.OutQuint);
-                outerContent.Delay(25).Then().ScaleTo(1.05f, 100).Then().ScaleTo(1f, 200, Easing.Out);
+                if (newCount > 0)
+                {
+                    countdownText.Text = Math.Max(1, newCount).ToString();
+                    countdownText.ScaleTo(0.25f).Then().ScaleTo(1, 200, Easing.OutQuint);
+                    outerContent.Delay(25).Then().ScaleTo(1.05f, 100).Then().ScaleTo(1f, 200, Easing.Out);
+
+                    countdownBackground.FlashColour(colourProvider.Background3, 400, Easing.Out);
+                }
 
-                countdownBackground.FlashColour(colourProvider.Background3, 400, Easing.Out);
+                var chan = sampleCountdown.GetChannel();
+                chan.Frequency.Value = newCount == 0 ? 0.5f : 1;
+                chan.Play();
             }
 
             countdownCount = newCount;

@peppy peppy merged commit 0589924 into ppy:master Mar 21, 2024
11 of 17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add resume leniency for scrolling rulesets
6 participants