npx claudepluginhub wende/dejitterBrowser-injectable animation recorder & jank detector. Record rAF at full speed, auto-detect jitter, flicker, shiver, jumps, stutter, stuck, and outliers.
A browser-injectable animation frame recorder that captures every requestAnimationFrame at full speed, then downsamples intelligently and auto-detects visual anomalies.
claude plugin add dejitter from wende/dejitter
Then use /dejitter in any conversation to get injection and usage instructions.
Inject into any page:
const s = document.createElement('script');
s.src = 'http://localhost:8787/recorder.js';
document.head.appendChild(s);
Serve the file locally:
python3 -m http.server 8787 --bind 127.0.0.1
Then use the floating UI button or the console API:
dejitter.configure({
selector: '.chat-container',
props: ['transform', 'opacity', 'boundingRect'],
});
dejitter.start();
// ... interact with the page ...
dejitter.stop();
dejitter.findings(); // YAML report of detected anomalies
| Method | Description |
|---|---|
configure(opts) | Set selector, props, sampleRate, maxDuration, etc. |
start() | Begin recording at full rAF speed |
stop() | Stop recording, fire onStop callbacks |
onStop(callback) | Register a callback to run after stop |
findings(raw?) | Auto-detected anomalies (YAML default, pass true for array) |
summary(raw?) | Recording stats (YAML default, pass true for object) |
getData() | Full export: samples, elements, propStats, mutations |
toJSON() | JSON string of getData() |
getRaw() | Raw unprocessed frames and mutations |
| Type | What it catches |
|---|---|
| jitter | Property bounces from rest state and returns — layout thrashing |
| flicker | Opacity-specific bounce — element appears/disappears |
| shiver | High-frequency oscillation — two forces fighting (e.g. scroll vs overscroll) |
| jump | Single-frame discontinuity far exceeding typical delta |
| stutter | Brief mid-motion direction reversal (1–3 frames) during smooth movement |
| stuck | Animation stalls for several frames mid-motion then resumes |
| outlier | Property changing at statistically unusual rate vs siblings |
dejitter.configure({
selector: '*', // CSS selector for elements to track
props: ['opacity', 'transform'], // properties to sample
sampleRate: 15, // target output samples/sec
maxDuration: 10000, // auto-stop after ms (0 = manual)
minTextLength: 0, // ignore elements with short text
mutations: false, // observe DOM mutations
idleTimeout: 2000, // auto-stop after idle ms (0 = off)
thresholds: { // anomaly detection sensitivity (partial overrides OK)
jitter: { minDeviation: 1, maxDuration: 1000, highSeverity: 20, medSeverity: 5 },
shiver: { minReversals: 5, minDensity: 0.3, highDensity: 0.7, medDensity: 0.5, minDelta: 0.01 },
jump: { medianMultiplier: 10, minAbsolute: 50, highMultiplier: 50, medMultiplier: 20 },
stutter: { velocityRatio: 0.3, maxFrames: 3, minVelocity: 0.5 },
stuck: { minStillFrames: 3, maxDelta: 0.5, minSurroundingVelocity: 1, highDuration: 500, medDuration: 200 },
outlier: { ratioThreshold: 3 },
},
});
Only specify the values you want to change — unset values keep their defaults.