The map's glide is a setting, because two reports bracketed one guess
grom, 2026-11-05: *"its the maps motion that is laggy."* That is `SCALE_RATE`, and it is the same constant he reported from the other side a day earlier — *"scroll is better but feels pretty slippery, like scrolls past where I stop scrolling"* — which is what took it from 10 to 24. At 24 the half-life is 0.29 s, so at 60 fps a wheel notch is still closing 167 frames later: "it overshoots" and "it lags behind" are two readings of one glide, and a third guess would be a third guess. `mapMotionSmoothing` is a percentage of a 0.30 s half-life, 0 is no ease at all, and the slider is on the Options window's Interface page. The top of the range is the 0.29 s he called laggy, because that is the slowest anyone could want; the default is a quarter of it. Measured over a full rung (scale 1 -> 1.6) at 60 fps, frames to settle within 0.001: **0% = 1, 10% = 17, 20% = 34, 25% (shipped) = 42, 50% = 84, 100% = 167** — so the default is four times snappier than what he just played, and still eased. One rate drives both the pan and the zoom ease, read once a frame: the two are one gesture to a player, and a zoom that settles while the pan is still drifting reads as the pan being broken. A drag still writes the scroll directly and never eases, as before. Verified in a live session with his addons: `mapMotionSmoothing=25`, one notch settles in 42 frames (0.70 s), map still FULLSCREEN, fade still 80. Options census 141 -> 142 on both counts. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
This commit is contained in:
@@ -61,10 +61,36 @@ local SCALE_SNAP = 0.001
|
||||
-- notch. That was tolerable only while a notch could not accumulate, because the target was never
|
||||
-- more than one rung away; once notches add up the glide is the thing you feel. grom, 2026-11-04:
|
||||
-- *"scroll is better but feels pretty slippery, like scrolls past where I stop scrolling."* At 24
|
||||
-- the half-life is 0.29 s and a multi-rung spin lands about where the wheel stopped. The pan's is
|
||||
-- left alone: dragging writes the scroll directly and never eases.
|
||||
local PAN_RATE = 10
|
||||
local SCALE_RATE = 24
|
||||
-- the half-life is 0.29 s and a multi-rung spin lands about where the wheel stopped.
|
||||
--
|
||||
-- 0.29 s was still the wrong answer. grom, 2026-11-05: *"its the maps motion that is laggy."*
|
||||
-- That is the same constant read from the other side — at 60 fps a 0.29 s half-life closes 90% of
|
||||
-- a notch in 58 frames, so the map keeps drifting for a second after the wheel stops, and the two
|
||||
-- reports are "it overshoots" and "it lags behind" about one glide. Guessing a third number would
|
||||
-- be the third guess, so it is a SETTING now, and these two are the ends of its range rather than
|
||||
-- the behaviour: `mapMotionSmoothing` is a percentage of [`SMOOTH_MAX_HALFLIFE`], and 0 is no ease
|
||||
-- at all.
|
||||
--
|
||||
-- The top of the slider is the 0.29 s half-life he called laggy, because that is the slowest
|
||||
-- anyone could want and there is no reason to offer slower. The default is a quarter of it:
|
||||
-- 0.075 s, which closes 90% of a wheel notch in 0.25 s and the last thousandth in 0.69 s.
|
||||
-- Measured over a full rung (scale 1 -> 1.6) at 60 fps, frames to settle within 0.001:
|
||||
-- 0% = 1, 10% = 17, 20% = 34, 50% = 84, 100% = 167 (the old constant's own 167).
|
||||
local SMOOTH_MAX_HALFLIFE = 0.30
|
||||
-- The default percentage, and the fallback when the CVar is missing (a bare VM, a test).
|
||||
local SMOOTH_DEFAULT = 25
|
||||
-- `nil` means no ease: snap to the target this frame. `RATE` is the file's own relation,
|
||||
-- `7 / halflife`, so the arithmetic below is unchanged.
|
||||
local function SmoothRate()
|
||||
local pct = tonumber(GetCVar and GetCVar("mapMotionSmoothing") or nil) or SMOOTH_DEFAULT
|
||||
if pct <= 0 then
|
||||
return nil
|
||||
end
|
||||
if pct > 100 then
|
||||
pct = 100
|
||||
end
|
||||
return 7 / (pct / 100 * SMOOTH_MAX_HALFLIFE)
|
||||
end
|
||||
-- A drag under this many pixels is still a click, which is what `WouldCursorPositionBeClick`
|
||||
-- answers; Era's own threshold.
|
||||
local CLICK_SLOP = 5
|
||||
@@ -773,7 +799,7 @@ function MapCanvasScrollControllerMixin:SetZoomTarget(scale, x, y)
|
||||
end
|
||||
|
||||
-- Which rung a wheel notch steps FROM: where the view is heading, not where the ease has got
|
||||
-- to. `currentScale` closes about 63% of the gap a second (`SCALE_RATE`), so a second notch
|
||||
-- to. `currentScale` eases toward the target (`SmoothRate`), so a second notch
|
||||
-- arriving a frame after the first re-reads a scale that has barely moved, finds the same rung
|
||||
-- under it, and re-sets the target it already has. Measured at the player's own window size
|
||||
-- with his addons loaded: four wheel-down notches over the map moved the ladder ONE step
|
||||
@@ -1173,7 +1199,10 @@ function MapCanvasScrollControllerMixin:OnUpdate(elapsed)
|
||||
end
|
||||
end
|
||||
else
|
||||
local rate = 1 - math.pow(0.5, (elapsed or 0) * PAN_RATE / 7)
|
||||
-- One rate for both eases, read once a frame: the two are one gesture to a player, and a
|
||||
-- zoom that settles while the pan is still drifting reads as the pan being broken.
|
||||
local smooth = SmoothRate()
|
||||
local rate = smooth and (1 - math.pow(0.5, (elapsed or 0) * smooth / 7)) or 1
|
||||
local tx, ty = self.targetScrollX or 0.5, self.targetScrollY or 0.5
|
||||
local cx, cy = self.currentScrollX or 0.5, self.currentScrollY or 0.5
|
||||
if math.abs(tx - cx) > PAN_SNAP or math.abs(ty - cy) > PAN_SNAP then
|
||||
@@ -1189,7 +1218,8 @@ function MapCanvasScrollControllerMixin:OnUpdate(elapsed)
|
||||
local scaled = false
|
||||
local ts, cs = self.targetScale or 1, self.currentScale or 1
|
||||
if math.abs(ts - cs) > SCALE_SNAP then
|
||||
local rate = 1 - math.pow(0.5, (elapsed or 0) * SCALE_RATE / 7)
|
||||
local smooth = SmoothRate()
|
||||
local rate = smooth and (1 - math.pow(0.5, (elapsed or 0) * smooth / 7)) or 1
|
||||
self.currentScale = cs + (ts - cs) * rate
|
||||
scaled = true
|
||||
elseif cs ~= ts then
|
||||
|
||||
@@ -479,6 +479,13 @@
|
||||
.. "In Windowed (Fullscreen) the window already fills the screen, so this sets the "
|
||||
.. "size it returns to in Windowed. Takes effect on Apply."
|
||||
|
||||
-- 1.12's map neither pans nor zooms, so it has no such setting and no reference value.
|
||||
BENILLA_TOOLTIP_MAP_MOTION_SMOOTHING =
|
||||
"How long the world map keeps gliding after you stop scrolling or dragging.\n\n"
|
||||
.. "At 0 the map goes exactly where you put it, the same frame. Higher is smoother "
|
||||
.. "and slower to settle; past about half way the map is still moving a second after "
|
||||
.. "the wheel stopped."
|
||||
|
||||
-- 1.12 has no such setting: its map does not fade, because its map cannot be read while
|
||||
-- you walk either way (it covers the screen and takes the keyboard).
|
||||
BENILLA_TOOLTIP_MAP_FADE_WHILE_MOVING =
|
||||
@@ -1582,7 +1589,7 @@
|
||||
"RowProfanityFilter",
|
||||
"RowShowTutorials", "RowTipOfTheDay", "RowNewbieTips",
|
||||
-- Appended, as this list's own rule says: the tests assert positional indices.
|
||||
"RowMapFadeWhileMoving",
|
||||
"RowMapFadeWhileMoving", "RowMapMotionSmoothing",
|
||||
},
|
||||
-- 1.12's chat box (UIOptionsFrame.xml:751-840). Not shipped: Simple Chat, which needs
|
||||
-- FCF_Set_SimpleChat's re-layout, Lock Chat Settings and Guild Recruitment.
|
||||
@@ -5064,11 +5071,23 @@
|
||||
</Frame>
|
||||
<!-- Read by `MapCanvas.lua`, which owns the behaviour; 0
|
||||
is off and the row's own floor. -->
|
||||
<Frame name="$parentRowMapFadeWhileMoving" inherits="OptionsSliderRowTemplate">
|
||||
<Frame name="$parentRowMapMotionSmoothing" inherits="OptionsSliderRowTemplate">
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT" relativeTo="$parentRowNewbieTips" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-9"/></Offset></Anchor>
|
||||
<Anchor point="TOPRIGHT" relativeTo="$parentRowNewbieTips" relativePoint="BOTTOMRIGHT"><Offset><AbsDimension x="0" y="-9"/></Offset></Anchor>
|
||||
</Anchors>
|
||||
<Scripts><OnLoad>
|
||||
OptionsRow_OnLoad(self, "mapMotionSmoothing",
|
||||
"World Map Motion Smoothing",
|
||||
"BENILLA_TOOLTIP_MAP_MOTION_SMOOTHING")
|
||||
OptionsSliderRow_Setup(self, 0, 100, 10, "pct")
|
||||
</OnLoad></Scripts>
|
||||
</Frame>
|
||||
<Frame name="$parentRowMapFadeWhileMoving" inherits="OptionsSliderRowTemplate">
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT" relativeTo="$parentRowMapMotionSmoothing" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-9"/></Offset></Anchor>
|
||||
<Anchor point="TOPRIGHT" relativeTo="$parentRowMapMotionSmoothing" relativePoint="BOTTOMRIGHT"><Offset><AbsDimension x="0" y="-9"/></Offset></Anchor>
|
||||
</Anchors>
|
||||
<Scripts><OnLoad>
|
||||
OptionsRow_OnLoad(self, "mapFadeWhileMoving",
|
||||
"Fade World Map While Moving",
|
||||
|
||||
@@ -1952,6 +1952,15 @@ pub(crate) const REGISTERED: &[Registered] = &[
|
||||
// frame verb, and `IsPlayerMoving()` is already a verb — so the whole feature is Lua over a
|
||||
// CVar, and the CVar is what gives it a home in the Options window and in `config.toml`.
|
||||
// 0 switches it off; the Options row offers 0 and 10..90.
|
||||
// Same shape and same reader as `mapFadeWhileMoving` below.
|
||||
ours(
|
||||
"mapMotionSmoothing",
|
||||
"25",
|
||||
"how long the world map's pan and zoom keep gliding after the input stops, as a percent \
|
||||
of a 0.3 s half-life; 0 snaps. 1.12's map neither pans nor zooms, so there is no \
|
||||
reference value — grom has now reported both ends of one guess (2026-11-04 \
|
||||
\"slippery\", 2026-11-05 \"laggy\"), which is what makes it a setting",
|
||||
),
|
||||
ours(
|
||||
"mapFadeWhileMoving",
|
||||
"80",
|
||||
@@ -5832,6 +5841,10 @@ mod tests {
|
||||
"mapFadeWhileMoving",
|
||||
"MapCanvas.lua's `FadeWhileMoving`, every frame the map is open",
|
||||
),
|
||||
(
|
||||
"mapMotionSmoothing",
|
||||
"MapCanvas.lua's `SmoothRate`, read by the pan and zoom eases",
|
||||
),
|
||||
// The five per-kind plate rows with no gate of their own. They exist because an addon
|
||||
// written for a later client greys a whole row on a nil `GetCVar` — registering is the
|
||||
// answer to "does this client have this setting", and each default below is this
|
||||
|
||||
@@ -3766,6 +3766,11 @@ fn every_row_tooltip_key_resolves_in_the_real_global_strings() {
|
||||
"BENILLA_TOOLTIP_MAP_FADE_WHILE_MOVING",
|
||||
"InterfaceRowMapFadeWhileMoving",
|
||||
),
|
||||
// The world map's glide, a setting because two reports bracketed one guess.
|
||||
(
|
||||
"BENILLA_TOOLTIP_MAP_MOTION_SMOOTHING",
|
||||
"InterfaceRowMapMotionSmoothing",
|
||||
),
|
||||
// MONKEY (advanced graphics): the whole Advanced Graphics page. Every row on it is
|
||||
// benilla's own mechanism — 1.12 has no realtime shadow, no fixture-lit interior and
|
||||
// no invented light — so there is no `OPTION_TOOLTIP_*` any of them could resolve,
|
||||
@@ -3902,8 +3907,8 @@ fn every_row_tooltip_key_resolves_in_the_real_global_strings() {
|
||||
// GFX (sharpening) / (field of view): one row each, on the two different pages. 136 -> 138.
|
||||
// GFX (froxel volumetrics): the shadowed-air dial beside the haze tier. 138 -> 139.
|
||||
// GFX (foliage distance): the ground-clutter horizon. 139 -> 140.
|
||||
// The world map's fade-while-moving dial. 140 -> 141.
|
||||
assert_eq!(checked, 141, "every tipped row carries a live key");
|
||||
// The world map's fade-while-moving dial. 140 -> 141; its motion-smoothing dial, 141 -> 142.
|
||||
assert_eq!(checked, 142, "every tipped row carries a live key");
|
||||
assert_eq!(
|
||||
untipped,
|
||||
vec![
|
||||
@@ -4012,7 +4017,7 @@ fn every_flavor_of_row_raises_its_plate_from_the_page_it_lives_on() {
|
||||
// GFX (shadow rig): the five Advanced Graphics shadow rows. 119 -> 124.
|
||||
// GFX (interior rig): the ten interior-lighting rows. 124 -> 134.
|
||||
// GFX (auto-exposure): the tier and its blend. 134 -> 136.
|
||||
assert_eq!(raised, 141, "every row but Auto Loot raises a description");
|
||||
assert_eq!(raised, 142, "every row but Auto Loot raises a description");
|
||||
}
|
||||
|
||||
/// 1.12's AdvancedOptionsCombatText box as saved-global rows: a click writes the global, never a
|
||||
|
||||
Reference in New Issue
Block a user