Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save divyam234/0ab9540475fd65f7f254b3b6d37a263b to your computer and use it in GitHub Desktop.

Select an option

Save divyam234/0ab9540475fd65f7f254b3b6d37a263b to your computer and use it in GitHub Desktop.
Chatgpt large chat lag fix
// ==UserScript==
// @name ChatGPT Large Chat Performance
// @namespace local.chatgpt.performance
// @version 0.4.0
// @description Makes very large ChatGPT conversations less sluggish with CSS containment and detachable turbo scrolling.
// @match https://chatgpt.com/*
// @match https://chat.openai.com/*
// @run-at document-idle
// @grant none
// ==/UserScript==
(function () {
'use strict';
const STYLE_ID = 'tm-chatgpt-large-chat-performance-style';
const HEIGHT_VAR = '--tm-cgpt-turn-height';
const TURN_SELECTOR = '[data-turn-id-container]';
const SCROLL_IDLE_MS = 180;
let enabled = true;
let root = null;
let ro = null;
let mo = null;
let scanTimer = 0;
let scrollIdleTimer = 0;
let parked = false;
let parkedNodes = [];
let placeholder = null;
const seen = new WeakSet();
function addStyles() {
if (document.getElementById(STYLE_ID)) return;
const style = document.createElement('style');
style.id = STYLE_ID;
style.textContent = `
${TURN_SELECTOR} {
content-visibility: auto !important;
contain: layout style paint !important;
contain-intrinsic-size: auto var(${HEIGHT_VAR}, 760px) !important;
}
.markdown,
.text-message,
pre,
code {
overflow-wrap: anywhere !important;
}
video,
canvas,
iframe {
content-visibility: auto !important;
contain: layout paint !important;
}
#tm-cgpt-thread-placeholder {
display: block !important;
contain: strict !important;
visibility: hidden !important;
pointer-events: none !important;
}
`;
document.documentElement.appendChild(style);
}
function findThreadScrollRoot() {
const thread = document.querySelector('#thread');
for (let el = thread?.parentElement; el; el = el.parentElement) {
const style = getComputedStyle(el);
if (/(auto|scroll|overlay)/.test(style.overflowY) && el.scrollHeight > el.clientHeight + 200) {
return el;
}
}
return document.scrollingElement || document.documentElement;
}
function rememberHeight(entry) {
const height = Math.ceil(entry.borderBoxSize?.[0]?.blockSize || entry.contentRect.height);
if (height > 40) entry.target.style.setProperty(HEIGHT_VAR, `${height}px`);
}
function observeTurn(turn) {
if (seen.has(turn)) return;
seen.add(turn);
ro.observe(turn);
}
function scanTurns() {
if (!enabled || !ro) return;
document.querySelectorAll(TURN_SELECTOR).forEach(observeTurn);
}
function scheduleScan() {
clearTimeout(scanTimer);
scanTimer = window.setTimeout(scanTurns, 150);
}
function getThread() {
return document.querySelector('#thread');
}
function parkThread() {
if (parked) return;
const thread = getThread();
if (!thread || !thread.childNodes.length) return;
const height = Math.max(thread.scrollHeight, thread.getBoundingClientRect().height, 1000);
placeholder = document.createElement('div');
placeholder.id = 'tm-cgpt-thread-placeholder';
placeholder.style.minHeight = `${Math.ceil(height)}px`;
parkedNodes = [...thread.childNodes];
thread.replaceChildren(placeholder);
thread.style.minHeight = `${Math.ceil(height)}px`;
parked = true;
}
function restoreThread() {
if (!parked) return;
const thread = getThread();
if (thread) {
thread.replaceChildren(...parkedNodes);
thread.style.minHeight = '';
}
parkedNodes = [];
placeholder = null;
parked = false;
scheduleScan();
}
function onScroll() {
parkThread();
clearTimeout(scrollIdleTimer);
scrollIdleTimer = window.setTimeout(restoreThread, SCROLL_IDLE_MS);
}
function start() {
stop(false);
enabled = true;
addStyles();
root = findThreadScrollRoot();
ro = new ResizeObserver((entries) => entries.forEach(rememberHeight));
scanTurns();
mo = new MutationObserver(scheduleScan);
mo.observe(document.body, { childList: true, subtree: true });
root?.addEventListener('scroll', onScroll, { passive: true });
}
function stop(removeStyles = true) {
root?.removeEventListener('scroll', onScroll);
ro?.disconnect();
mo?.disconnect();
root = null;
ro = null;
mo = null;
clearTimeout(scanTimer);
clearTimeout(scrollIdleTimer);
restoreThread();
if (removeStyles) document.getElementById(STYLE_ID)?.remove();
}
function toggle() {
enabled = !enabled;
if (enabled) start();
else stop();
console.info(`[ChatGPT Large Chat Performance] ${enabled ? 'enabled' : 'disabled'}`);
}
window.addEventListener('keydown', (event) => {
if (event.altKey && event.code === 'KeyV') toggle();
});
start();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment