Skip to content

Instantly share code, notes, and snippets.

@kurtextrem
Created August 5, 2025 13:22
Show Gist options
  • Save kurtextrem/038aa36e504485381a78e518dfc6a600 to your computer and use it in GitHub Desktop.
Save kurtextrem/038aa36e504485381a78e518dfc6a600 to your computer and use it in GitHub Desktop.
/**
* DevTools snippet – find potential stutter sources
* Run in the Chrome DevTools console on any page
* Flags:
* 1. Elements > 1000×1000 px that have any transform-like props set
* 2. Elements that have any filter/backdrop-filter applied
*/
;(() => {
const TRANSFORM_PROPS = [
"transform",
"transformOrigin",
"transformStyle",
"perspective",
"backfaceVisibility",
"translate",
"rotate",
"scale",
"opacity",
"willChange",
]
const FILTER_PROPS = ["filter", "backdropFilter"]
const CRITICAL_FILTERS = ["contrast", "blur"]
const IGNORE_EL = ["html", "body", "div#main"]
const DEFAULTS = {
transform: "none",
transformOrigin: "50% 50%",
transformStyle: "flat",
perspective: "none",
backfaceVisibility: "visible",
translate: "none",
rotate: "none",
scale: "none",
opacity: "1",
willChange: "auto",
filter: "none",
}
const style = (el, pseudo = null) => window.getComputedStyle(el, pseudo)
const pickProps = (obj, keys) => {
const out = {}
keys.forEach(k => {
const v = obj[k]
if (!v) return
const defaultVal = DEFAULTS[k]
if (v === defaultVal || v === "none" || v === "normal") return
out[k] = v
})
return out
}
const hasAny = o => Object.keys(o).length > 0
const filterRegex = /[a-z-]+\([^)]+\)/gi
const splitRegex = /\(|\)/
const isMeaningfulFilter = val => {
if (!val || val === "none") return false
if (val.includes("var(--")) return true
const parts = val.match(filterRegex) || []
return parts.some(p => {
const [fn, rawVal] = p.split(splitRegex).filter(Boolean)
const v = parseFloat(rawVal)
switch (fn.trim()) {
case "brightness":
case "contrast":
case "saturate":
case "sepia":
case "grayscale":
return v !== 1 && v !== 100
case "invert":
return v !== 0
case "opacity":
return v !== 1 && v !== 100
case "blur":
return v !== 0
case "hue-rotate":
return v !== 0
case "drop-shadow":
return true
default:
return true
}
})
}
function getIdentifier(el, pseudo = null) {
return `${el.tagName.toLowerCase()}${el.id ? "#" + el.id : ""}${typeof el.className === "string" && el.className !== "" ? "." + el.className.split(" ").join(".") : ""}${pseudo || ""}`
}
const bigTransforms = []
const withFilters = []
const scanElement = (el, pseudo = null) => {
const identifier = getIdentifier(el, pseudo)
if (!pseudo && IGNORE_EL.includes(identifier)) return
const r = el.getBoundingClientRect()
const s = style(el, pseudo)
if (r.width > 1000 && r.height > 1000) {
const tProps = pickProps(s, TRANSFORM_PROPS)
if (hasAny(tProps)) bigTransforms.push({ el, r, props: tProps, pseudo })
}
const fProps = pickProps(s, FILTER_PROPS)
Object.keys(fProps).forEach(k => {
if (!isMeaningfulFilter(fProps[k])) delete fProps[k]
})
if (hasAny(fProps)) withFilters.push({ el, r, props: fProps, pseudo })
}
document.querySelectorAll("*").forEach(el => {
try {
scanElement(el)
scanElement(el, "::before")
scanElement(el, "::after")
} catch (e) {
console.error(e, el)
}
})
const OUTLINE = "3px solid red"
const KEY = "__stutterOutline"
const highlight = arr =>
arr.forEach(({ el }) => {
el[KEY] = el.style.outline
el.style.outline = OUTLINE
})
const unhighlight = arr =>
arr.forEach(({ el }) => {
el.style.outline = el[KEY] || ""
delete el[KEY]
})
if (bigTransforms.length || withFilters.length) {
console.group(
`%c⚠️ Match found! Marked in red are elements that are larger than the viewport width.`,
"color:orange;font-weight:bold;"
)
const viewportWidth = window.innerWidth
console.groupCollapsed(`Big-transform elements (${bigTransforms.length})`)
bigTransforms
.sort((a, b) => b.r.width - a.r.width)
.forEach(({ el, r, props, pseudo }) => {
console.groupCollapsed(
`%c${getIdentifier(el, pseudo)} ${el.dataset.framerName ? "('" + el.dataset.framerName + "') " : ""}| %c${r.width}x${r.height}`,
"font-weight:bold",
r.width > viewportWidth ? "color:red" : ""
)
console.log("Node →", el)
console.log("Pseudo →", pseudo || "(none)")
console.log("Rect →", r.width, "x", r.height, r)
console.log("Props →", props)
console.groupEnd()
})
console.groupEnd()
console.groupCollapsed(`Elements with filter (${withFilters.length})`)
withFilters
.sort((a, b) => (a.props.filter || "").localeCompare(b.props.filter || ""))
.forEach(({ el, props, pseudo }) => {
console.groupCollapsed(
`%c${getIdentifier(el, pseudo)} ${el.dataset.framerName ? "('" + el.dataset.framerName + "') " : ""}| %c${props.filter || props.backdropFilter}`,
"font-weight:bold",
CRITICAL_FILTERS.some(f => (props.filter || "").includes(f)) ? "color:red" : ""
)
console.log("Node →", el)
console.log("Pseudo →", pseudo || "(none)")
console.log("Props →", props)
console.groupEnd()
})
console.groupEnd()
console.groupEnd()
highlight([...bigTransforms, ...withFilters])
window.unhighlightStutter = () => {
unhighlight([...bigTransforms, ...withFilters])
console.log("Outlines removed.")
}
console.log("%cRun `unhighlightStutter()` to remove outlines.", "color:steelblue")
} else {
console.log("%c✅ No stutter candidates found.", "color:green;font-weight:bold")
}
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment