Skip to content

Commit 79a8a6a

Browse files
committed
fix(turn-points-count): stabilize count animation and frame scope
- rewind browser-updated score before counting to the new value - scope electric frame to the score node instead of the parent row - reduce glow spill and avoid repeated text pulse loops
1 parent 474f233 commit 79a8a6a

5 files changed

Lines changed: 387 additions & 72 deletions

File tree

dist/autodarts-xconfig.user.js

Lines changed: 93 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -25851,12 +25851,12 @@
2585125851
function buildStyleText13() {
2585225852
return `
2585325853
${SCORE_SELECTOR2}.${SCORE_FLASH_CLASS}[${SCORE_FLASH_SEQUENCE_ATTRIBUTE}="0"]{
25854-
animation:ad-ext-turn-points-count-flash-a 220ms cubic-bezier(.16,.92,.24,1) infinite;
25854+
animation:ad-ext-turn-points-count-flash-a 390ms cubic-bezier(.16,.92,.24,1) both;
2585525855
will-change:transform,filter,text-shadow,opacity;
2585625856
}
2585725857

2585825858
${SCORE_SELECTOR2}.${SCORE_FLASH_CLASS}[${SCORE_FLASH_SEQUENCE_ATTRIBUTE}="1"]{
25859-
animation:ad-ext-turn-points-count-flash-b 220ms cubic-bezier(.16,.92,.24,1) infinite;
25859+
animation:ad-ext-turn-points-count-flash-b 390ms cubic-bezier(.16,.92,.24,1) both;
2586025860
will-change:transform,filter,text-shadow,opacity;
2586125861
}
2586225862

@@ -25865,18 +25865,20 @@ ${SCORE_SELECTOR2}.${SCORE_FLASH_CLASS}[${SCORE_FLASH_SEQUENCE_ATTRIBUTE}="1"]{
2586525865
--ad-ext-turn-points-electric-filter-strong:url(#${ELECTRIC_FILTER_STRONG_ID});
2586625866
position:relative;
2586725867
isolation:isolate;
25868+
z-index:0;
2586825869
}
2586925870

2587025871
.${SCORE_FRAME_CLASS}::before,
2587125872
.${SCORE_FRAME_CLASS}::after{
2587225873
content:"";
2587325874
position:absolute;
2587425875
pointer-events:none;
25876+
z-index:-1;
2587525877
}
2587625878

2587725879
.${SCORE_FRAME_CLASS}[${SCORE_FRAME_SEQUENCE_ATTRIBUTE}="0"]::before{
25878-
inset:-7px;
25879-
border-radius:12px;
25880+
inset:-5px;
25881+
border-radius:10px;
2588025882
border:1px solid color-mix(in srgb,rgba(255,204,132,.92) 76%,white 24%);
2588125883
background:
2588225884
linear-gradient(110deg,rgba(255,255,255,.14) 0%,rgba(255,255,255,0) 34%,rgba(255,255,255,0) 66%,rgba(255,255,255,.14) 100%);
@@ -25889,13 +25891,13 @@ ${SCORE_SELECTOR2}.${SCORE_FLASH_CLASS}[${SCORE_FLASH_SEQUENCE_ATTRIBUTE}="1"]{
2588925891
0 0 38px rgba(255,152,72,.2);
2589025892
filter:var(--ad-ext-turn-points-electric-filter-strong);
2589125893
animation:
25892-
ad-ext-turn-points-count-frame-electric-a 560ms steps(4,end) infinite,
25893-
ad-ext-turn-points-count-frame-glow-a 560ms ease-in-out infinite;
25894+
ad-ext-turn-points-count-frame-electric-a 840ms steps(4,end) infinite,
25895+
ad-ext-turn-points-count-frame-glow-a 840ms ease-in-out infinite;
2589425896
}
2589525897

2589625898
.${SCORE_FRAME_CLASS}[${SCORE_FRAME_SEQUENCE_ATTRIBUTE}="1"]::before{
25897-
inset:-7px;
25898-
border-radius:12px;
25899+
inset:-5px;
25900+
border-radius:10px;
2589925901
border:1px solid color-mix(in srgb,rgba(255,204,132,.92) 76%,white 24%);
2590025902
background:
2590125903
linear-gradient(110deg,rgba(255,255,255,.14) 0%,rgba(255,255,255,0) 34%,rgba(255,255,255,0) 66%,rgba(255,255,255,.14) 100%);
@@ -25908,30 +25910,30 @@ ${SCORE_SELECTOR2}.${SCORE_FLASH_CLASS}[${SCORE_FLASH_SEQUENCE_ATTRIBUTE}="1"]{
2590825910
0 0 38px rgba(255,152,72,.2);
2590925911
filter:var(--ad-ext-turn-points-electric-filter-strong);
2591025912
animation:
25911-
ad-ext-turn-points-count-frame-electric-b 560ms steps(4,end) infinite,
25912-
ad-ext-turn-points-count-frame-glow-b 560ms ease-in-out infinite;
25913+
ad-ext-turn-points-count-frame-electric-b 840ms steps(4,end) infinite,
25914+
ad-ext-turn-points-count-frame-glow-b 840ms ease-in-out infinite;
2591325915
}
2591425916

2591525917
.${SCORE_FRAME_CLASS}[${SCORE_FRAME_SEQUENCE_ATTRIBUTE}="0"]::after{
25916-
inset:-12px;
25917-
border-radius:15px;
25918-
opacity:.72;
25918+
inset:-7px;
25919+
border-radius:12px;
25920+
opacity:.58;
2591925921
background:
2592025922
radial-gradient(65% 150% at 50% 0%,rgba(255,224,180,.34),rgba(255,224,180,0) 72%),
2592125923
radial-gradient(65% 150% at 50% 100%,rgba(255,180,109,.3),rgba(255,180,109,0) 72%);
2592225924
filter:var(--ad-ext-turn-points-electric-filter-soft) blur(4px);
25923-
animation:ad-ext-turn-points-count-frame-aura-a 560ms ease-out infinite;
25925+
animation:ad-ext-turn-points-count-frame-aura-a 840ms ease-out infinite;
2592425926
}
2592525927

2592625928
.${SCORE_FRAME_CLASS}[${SCORE_FRAME_SEQUENCE_ATTRIBUTE}="1"]::after{
25927-
inset:-12px;
25928-
border-radius:15px;
25929-
opacity:.72;
25929+
inset:-7px;
25930+
border-radius:12px;
25931+
opacity:.58;
2593025932
background:
2593125933
radial-gradient(65% 150% at 50% 0%,rgba(255,224,180,.34),rgba(255,224,180,0) 72%),
2593225934
radial-gradient(65% 150% at 50% 100%,rgba(255,180,109,.3),rgba(255,180,109,0) 72%);
2593325935
filter:var(--ad-ext-turn-points-electric-filter-soft) blur(4px);
25934-
animation:ad-ext-turn-points-count-frame-aura-b 560ms ease-out infinite;
25936+
animation:ad-ext-turn-points-count-frame-aura-b 840ms ease-out infinite;
2593525937
}
2593625938

2593725939
@keyframes ad-ext-turn-points-count-flash-a{
@@ -26093,6 +26095,7 @@ ${SCORE_SELECTOR2}.${SCORE_FLASH_CLASS}[${SCORE_FLASH_SEQUENCE_ATTRIBUTE}="1"]{
2609326095
// src/features/turn-points-count/logic.js
2609426096
var FLASH_MODE_ON_CHANGE = "on-change";
2609526097
var FLASH_MODE_PERMANENT = "permanent";
26098+
var SCORE_CLASS_NAME = SCORE_SELECTOR2.startsWith(".") ? SCORE_SELECTOR2.slice(1) : SCORE_SELECTOR2;
2609626099
function easeOutCubic(value) {
2609726100
return 1 - Math.pow(1 - value, 3);
2609826101
}
@@ -26104,11 +26107,31 @@ ${SCORE_SELECTOR2}.${SCORE_FLASH_CLASS}[${SCORE_FLASH_SEQUENCE_ATTRIBUTE}="1"]{
2610426107
const value = Number(match[0]);
2610526108
return Number.isFinite(value) ? value : null;
2610626109
}
26107-
function collectScoreNodes(documentRef) {
26110+
function isValidCachedScoreNode(node) {
26111+
if (!node || node.isConnected === false) {
26112+
return false;
26113+
}
26114+
if (!SCORE_CLASS_NAME) {
26115+
return true;
26116+
}
26117+
return node.classList?.contains?.(SCORE_CLASS_NAME) === true;
26118+
}
26119+
function collectScoreNodes(documentRef, state = null) {
26120+
const cachedNodes = Array.isArray(state?.scoreNodeCache) ? state.scoreNodeCache : [];
26121+
if (cachedNodes.length > 0 && cachedNodes.every(isValidCachedScoreNode)) {
26122+
return cachedNodes;
26123+
}
2610826124
if (!documentRef || typeof documentRef.querySelectorAll !== "function") {
26125+
if (state) {
26126+
state.scoreNodeCache = [];
26127+
}
2610926128
return [];
2611026129
}
26111-
return Array.from(documentRef.querySelectorAll(SCORE_SELECTOR2));
26130+
const scoreNodes = Array.from(documentRef.querySelectorAll(SCORE_SELECTOR2));
26131+
if (state) {
26132+
state.scoreNodeCache = scoreNodes;
26133+
}
26134+
return scoreNodes;
2611226135
}
2611326136
function resolveFrameNode(scoreNode) {
2611426137
if (!scoreNode) {
@@ -26184,6 +26207,19 @@ ${SCORE_SELECTOR2}.${SCORE_FLASH_CLASS}[${SCORE_FLASH_SEQUENCE_ATTRIBUTE}="1"]{
2618426207
node.setAttribute?.(attributeName, nextValue);
2618526208
return nextValue;
2618626209
}
26210+
function renderScoreValue(node, state, value) {
26211+
if (!node || !state || !Number.isFinite(value)) {
26212+
return false;
26213+
}
26214+
const normalizedValue = Number(value);
26215+
const textValue = String(normalizedValue);
26216+
if (Number(state.renderedValueByNode.get(node)) === normalizedValue && node.textContent === textValue) {
26217+
return false;
26218+
}
26219+
node.textContent = textValue;
26220+
state.renderedValueByNode.set(node, normalizedValue);
26221+
return true;
26222+
}
2618726223
function triggerScoreFlash(node, state, windowRef = null, options = {}) {
2618826224
if (!node || !state) {
2618926225
return;
@@ -26276,6 +26312,7 @@ ${SCORE_SELECTOR2}.${SCORE_FLASH_CLASS}[${SCORE_FLASH_SEQUENCE_ATTRIBUTE}="1"]{
2627626312
return;
2627726313
}
2627826314
stopAnimation(node, state, windowRef);
26315+
renderScoreValue(node, state, fromValue);
2627926316
state.targetValueByNode.set(node, toValue);
2628026317
if (flashEnabled) {
2628126318
triggerScoreFlash(node, state, windowRef, { flashMode });
@@ -26289,17 +26326,18 @@ ${SCORE_SELECTOR2}.${SCORE_FLASH_CLASS}[${SCORE_FLASH_SEQUENCE_ATTRIBUTE}="1"]{
2628926326
duration: durationMs,
2629026327
easing: "easeOutCubic",
2629126328
update: () => {
26292-
node.textContent = String(Number(valueHolder.value));
26293-
state.renderedValueByNode.set(node, Number(valueHolder.value));
26329+
const value = Math.round(Number(valueHolder.value));
26330+
if (Number.isFinite(value)) {
26331+
renderScoreValue(node, state, value);
26332+
}
2629426333
},
2629526334
complete: () => {
2629626335
stopAnimation(node, state, windowRef, {
2629726336
flashAfterglowMs: flashEnabled ? flashAfterglowMs : 0,
2629826337
preserveFrame: flashEnabled && flashMode === FLASH_MODE_PERMANENT
2629926338
});
26300-
node.textContent = String(toValue);
2630126339
state.lastValueByNode.set(node, toValue);
26302-
state.renderedValueByNode.set(node, toValue);
26340+
renderScoreValue(node, state, toValue);
2630326341
}
2630426342
});
2630526343
state.activeAnimeByNode.set(node, animeInstance);
@@ -26312,16 +26350,14 @@ ${SCORE_SELECTOR2}.${SCORE_FLASH_CLASS}[${SCORE_FLASH_SEQUENCE_ATTRIBUTE}="1"]{
2631226350
const progress = Math.max(0, Math.min(1, elapsed / durationMs));
2631326351
const eased = easeOutCubic(progress);
2631426352
const value = Math.round(fromValue + (toValue - fromValue) * eased);
26315-
node.textContent = String(value);
26316-
state.renderedValueByNode.set(node, value);
26353+
renderScoreValue(node, state, value);
2631726354
if (progress >= 1) {
2631826355
stopAnimation(node, state, windowRef, {
2631926356
flashAfterglowMs: flashEnabled ? flashAfterglowMs : 0,
2632026357
preserveFrame: flashEnabled && flashMode === FLASH_MODE_PERMANENT
2632126358
});
26322-
node.textContent = String(toValue);
2632326359
state.lastValueByNode.set(node, toValue);
26324-
state.renderedValueByNode.set(node, toValue);
26360+
renderScoreValue(node, state, toValue);
2632526361
return;
2632626362
}
2632726363
const nextHandle = requestRaf(animateFrame);
@@ -26342,7 +26378,7 @@ ${SCORE_SELECTOR2}.${SCORE_FLASH_CLASS}[${SCORE_FLASH_SEQUENCE_ATTRIBUTE}="1"]{
2634226378
if (!documentRef || !state) {
2634326379
return;
2634426380
}
26345-
const scoreNodes = collectScoreNodes(documentRef);
26381+
const scoreNodes = collectScoreNodes(documentRef, state);
2634626382
const nodeSet = new Set(scoreNodes);
2634726383
state.lastValueByNode.forEach((_value, node) => {
2634826384
if (nodeSet.has(node)) {
@@ -26423,7 +26459,8 @@ ${SCORE_SELECTOR2}.${SCORE_FLASH_CLASS}[${SCORE_FLASH_SEQUENCE_ATTRIBUTE}="1"]{
2642326459
activeAnimeByNode: /* @__PURE__ */ new Map(),
2642426460
flashFrameByScoreNode: /* @__PURE__ */ new Map(),
2642526461
flashRafByNode: /* @__PURE__ */ new Map(),
26426-
flashTimeoutByNode: /* @__PURE__ */ new Map()
26462+
flashTimeoutByNode: /* @__PURE__ */ new Map(),
26463+
scoreNodeCache: []
2642726464
};
2642826465
let animeRef = getAnime(windowRef);
2642926466
let disposed = false;
@@ -26440,13 +26477,34 @@ ${SCORE_SELECTOR2}.${SCORE_FLASH_CLASS}[${SCORE_FLASH_SEQUENCE_ATTRIBUTE}="1"]{
2644026477
durationMs: featureConfig.durationMs,
2644126478
flashEnabled: featureConfig.flashOnChange !== false,
2644226479
flashMode: featureConfig.flashMode,
26443-
flashAfterglowMs: featureConfig.flashOnChange !== false ? 500 : 0,
26480+
flashAfterglowMs: featureConfig.flashOnChange !== false ? 750 : 0,
2644426481
animeRef,
2644526482
windowRef
2644626483
});
2644726484
}
2644826485
const scheduler = schedulerFactory(update, { windowRef });
26449-
const rootNode = findTurnContainer(documentRef) || documentRef.documentElement || documentRef.body || documentRef;
26486+
const initialScoreNode = collectScoreNodes(documentRef, state)[0] || null;
26487+
const scoreContainer = initialScoreNode?.closest?.("#ad-ext-turn") ? initialScoreNode.parentElement || null : null;
26488+
const rootNode = scoreContainer || findTurnContainer(documentRef) || documentRef.documentElement || documentRef.body || documentRef;
26489+
const observerUsesScoreContainer = Boolean(scoreContainer && rootNode === scoreContainer);
26490+
const isWithinObserverRoot = (node) => {
26491+
if (!node) {
26492+
return false;
26493+
}
26494+
if (node === rootNode) {
26495+
return true;
26496+
}
26497+
return typeof rootNode.contains === "function" && rootNode.contains(node);
26498+
};
26499+
const isRelevantObservedNode = (node) => {
26500+
if (!node) {
26501+
return false;
26502+
}
26503+
if (observerUsesScoreContainer) {
26504+
return isWithinObserverRoot(node);
26505+
}
26506+
return Boolean(node?.closest?.("#ad-ext-turn") || isWithinObserverRoot(node));
26507+
};
2645026508
const isAnimatingScoreNode = (node) => {
2645126509
const candidate = node?.nodeType === 3 ? node.parentNode || null : node;
2645226510
return state.activeAnimeByNode.has(candidate) || state.activeRafByNode.has(candidate);
@@ -26459,20 +26517,20 @@ ${SCORE_SELECTOR2}.${SCORE_FLASH_CLASS}[${SCORE_FLASH_SEQUENCE_ATTRIBUTE}="1"]{
2645926517
const hasRelevantTurnMutation = !Array.isArray(mutations) || mutations.length === 0 || mutations.some((mutation) => {
2646026518
if (mutation?.type === "characterData") {
2646126519
const targetNode = mutation?.target?.parentNode || null;
26462-
return Boolean(targetNode?.closest?.("#ad-ext-turn"));
26520+
return isRelevantObservedNode(targetNode);
2646326521
}
2646426522
if (mutation?.type === "attributes") {
2646526523
const attributeName = String(mutation?.attributeName || "").trim().toLowerCase();
2646626524
if (attributeName === "class" && (mutation?.target?.classList?.contains?.("ad-ext-turn-points-count--flash") || mutation?.target?.classList?.contains?.("ad-ext-turn-points-count--frame"))) {
2646726525
return false;
2646826526
}
26469-
return Boolean(mutation?.target?.closest?.("#ad-ext-turn"));
26527+
return isRelevantObservedNode(mutation?.target || null);
2647026528
}
2647126529
return [
2647226530
mutation?.target || null,
2647326531
...Array.from(mutation?.addedNodes || []),
2647426532
...Array.from(mutation?.removedNodes || [])
26475-
].some((node) => Boolean(node?.closest?.("#ad-ext-turn")));
26533+
].some((node) => isRelevantObservedNode(node));
2647626534
});
2647726535
if (Array.isArray(mutations) && mutations.length && mutations.every((mutation) => {
2647826536
return mutation?.type === "characterData" && isAnimatingScoreNode(mutation?.target || null);

src/features/turn-points-count/index.js

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export function initializeTurnPointsCount(context = {}) {
5252
flashFrameByScoreNode: new Map(),
5353
flashRafByNode: new Map(),
5454
flashTimeoutByNode: new Map(),
55+
scoreNodeCache: [],
5556
};
5657
let animeRef = getAnime(windowRef);
5758
let disposed = false;
@@ -70,18 +71,42 @@ export function initializeTurnPointsCount(context = {}) {
7071
durationMs: featureConfig.durationMs,
7172
flashEnabled: featureConfig.flashOnChange !== false,
7273
flashMode: featureConfig.flashMode,
73-
flashAfterglowMs: featureConfig.flashOnChange !== false ? 500 : 0,
74+
flashAfterglowMs: featureConfig.flashOnChange !== false ? 750 : 0,
7475
animeRef,
7576
windowRef,
7677
});
7778
}
7879

7980
const scheduler = schedulerFactory(update, { windowRef });
81+
const initialScoreNode = collectScoreNodes(documentRef, state)[0] || null;
82+
const scoreContainer = initialScoreNode?.closest?.("#ad-ext-turn")
83+
? initialScoreNode.parentElement || null
84+
: null;
8085
const rootNode =
86+
scoreContainer ||
8187
findTurnContainer(documentRef) ||
8288
documentRef.documentElement ||
8389
documentRef.body ||
8490
documentRef;
91+
const observerUsesScoreContainer = Boolean(scoreContainer && rootNode === scoreContainer);
92+
const isWithinObserverRoot = (node) => {
93+
if (!node) {
94+
return false;
95+
}
96+
if (node === rootNode) {
97+
return true;
98+
}
99+
return typeof rootNode.contains === "function" && rootNode.contains(node);
100+
};
101+
const isRelevantObservedNode = (node) => {
102+
if (!node) {
103+
return false;
104+
}
105+
if (observerUsesScoreContainer) {
106+
return isWithinObserverRoot(node);
107+
}
108+
return Boolean(node?.closest?.("#ad-ext-turn") || isWithinObserverRoot(node));
109+
};
85110
const isAnimatingScoreNode = (node) => {
86111
const candidate = node?.nodeType === 3 ? node.parentNode || null : node;
87112
return (
@@ -101,7 +126,7 @@ export function initializeTurnPointsCount(context = {}) {
101126
mutations.some((mutation) => {
102127
if (mutation?.type === "characterData") {
103128
const targetNode = mutation?.target?.parentNode || null;
104-
return Boolean(targetNode?.closest?.("#ad-ext-turn"));
129+
return isRelevantObservedNode(targetNode);
105130
}
106131

107132
if (mutation?.type === "attributes") {
@@ -113,14 +138,14 @@ export function initializeTurnPointsCount(context = {}) {
113138
) {
114139
return false;
115140
}
116-
return Boolean(mutation?.target?.closest?.("#ad-ext-turn"));
141+
return isRelevantObservedNode(mutation?.target || null);
117142
}
118143

119144
return [
120145
mutation?.target || null,
121146
...Array.from(mutation?.addedNodes || []),
122147
...Array.from(mutation?.removedNodes || []),
123-
].some((node) => Boolean(node?.closest?.("#ad-ext-turn")));
148+
].some((node) => isRelevantObservedNode(node));
124149
});
125150
if (
126151
Array.isArray(mutations) &&

0 commit comments

Comments
 (0)