Skip to content

Instantly share code, notes, and snippets.

@neongreen
Created October 7, 2025 09:12
Show Gist options
  • Select an option

  • Save neongreen/b9303670ea854b72b60cc7763fc921c1 to your computer and use it in GitHub Desktop.

Select an option

Save neongreen/b9303670ea854b72b60cc7763fc921c1 to your computer and use it in GitHub Desktop.
memory killer (i had to restart my mac)
// App.jsx
import { useEffect, useMemo, useRef, useState } from "react";
import "./styles.css";
export default function App() {
const [running, setRunning] = useState(false);
const [slider, setSlider] = useState(30); // 0..100 exponential
const [backdrop, setBackdrop] = useState(true);
const [shadows, setShadows] = useState(true);
const [bigLayers, setBigLayers] = useState(true);
const bucketRef = useRef(null);
const timerRef = useRef(null);
const styleRef = useRef(null);
// exponential batches per tick
const batch = useMemo(() => Math.max(1, Math.floor(Math.pow(2, slider / 7))), [slider]);
// element size scales gently to push larger layer backing stores
const baseSide = useMemo(() => 256 + Math.floor(slider / 100 * 1024), [slider]); // 256..1280
// very long durations to keep cpu low but keep layers alive
const dur = useMemo(() => 20 + Math.floor(slider / 2), [slider]); // seconds
useEffect(() => {
// dynamic stylesheet keeps big rules outside inline attrs to avoid JS churn each frame
const style = document.createElement("style");
style.id = "dom-stress-style";
style.textContent = `
:root { --dur:${dur}s }
/* slow animations that still allocate compositor layers */
@keyframes pan { from { transform: translate3d(0,0,0) } to { transform: translate3d(8px,6px,0) } }
@keyframes pulse { from { opacity:.92 } to { opacity:.98 } }
@keyframes bg { from { background-position:0 0 } to { background-position:2048px 2048px } }
.layer {
position: fixed;
/* spread across screen randomly to force many visible layers */
top: 0; left: 0;
will-change: transform, opacity, filter;
animation:
pan var(--dur) linear infinite alternate,
pulse calc(var(--dur) * 1.3) ease-in-out infinite alternate;
pointer-events: none;
contain: layout paint style;
mix-blend-mode: multiply;
}
.layer.big { width: 80vmin; height: 80vmin }
.layer.mid { width: 48vmin; height: 48vmin }
.layer.small { width: 28vmin; height: 28vmin }
/* heavy backgrounds that create large raster surfaces without JS buffers */
.grad {
background-image:
radial-gradient(circle at 20% 30%, rgba(99,102,241,.25), transparent 60%),
radial-gradient(circle at 80% 60%, rgba(244,114,182,.20), transparent 55%),
conic-gradient(from 30deg, rgba(0,0,0,.06), transparent 20%, rgba(0,0,0,.08) 40%, transparent 60%, rgba(0,0,0,.06) 80%, transparent);
background-size: 1024px 1024px, 1536px 1536px, 2048px 2048px;
animation: bg calc(var(--dur) * 2) linear infinite;
}
/* optional big shadow lists to balloon paint memory */
.shadowy {
box-shadow:
0 0 0 1px rgba(0,0,0,.04),
0 4px 8px rgba(0,0,0,.07),
0 8px 20px rgba(0,0,0,.06),
0 18px 38px rgba(0,0,0,.05),
0 36px 64px rgba(0,0,0,.05);
filter: saturate(1.03) contrast(1.02);
}
/* backdrop layers trigger separate backing stores per element on supporting browsers */
.glass {
background: rgba(255,255,255,.06);
-webkit-backdrop-filter: blur(6px) saturate(1.1);
backdrop-filter: blur(6px) saturate(1.1);
}
/* dense text to grow dom text nodes a bit without causing layout thrash */
.payload { position:absolute; inset: 6px; font: 12px/1.15 ui-sans-serif, system-ui; opacity:.001; user-select:none }
`;
document.head.appendChild(style);
styleRef.current = style;
return () => { style.remove(); styleRef.current = null; };
}, [dur]);
useEffect(() => {
if (!running) {
clearInterval(timerRef.current);
timerRef.current = null;
return;
}
const bucket = bucketRef.current;
// create batches on a gentle interval to avoid script load
timerRef.current = setInterval(() => {
const frag = document.createDocumentFragment();
for (let i = 0; i < batch; i++) {
const el = document.createElement("div");
// choose a size class to vary layer dimensions
const cls = i % 3 === 0 ? "big" : i % 3 === 1 ? "mid" : "small";
el.className = `layer grad ${cls} ${shadows ? "shadowy" : ""} ${backdrop ? "glass" : ""}`;
// randomize position via inline to avoid selector reuse and layer sharing
const vw = Math.max(100, window.innerWidth);
const vh = Math.max(100, window.innerHeight);
const x = Math.floor(Math.random() * vw);
const y = Math.floor(Math.random() * vh);
el.style.transform = `translate3d(${x}px, ${y}px, 0)`;
if (bigLayers) {
// optionally force big fixed pixel sizes rather than vmin
const side = baseSide + ((i * 31) % 256);
el.style.width = side + "px";
el.style.height = side + "px";
}
// a tiny hidden text payload increases dom memory without work
const p = document.createElement("div");
p.className = "payload";
p.textContent = "x".repeat(4000 + (i % 2000));
el.appendChild(p);
frag.appendChild(el);
}
bucket.appendChild(frag);
}, 200); // low frequency so cpu stays chilled
return () => { clearInterval(timerRef.current); timerRef.current = null; };
}, [running, batch, baseSide, backdrop, shadows, bigLayers]);
function start() { setRunning(true); }
function stop() { setRunning(false); }
function panic() {
setRunning(false);
clearInterval(timerRef.current);
timerRef.current = null;
if (bucketRef.current) bucketRef.current.innerHTML = "";
}
return (
<div className="App">
<h1>dom layer memory eater</h1>
<p className="warn">creates many large compositor layers with slow css animations and optional backdrop blur</p>
<label className="row">
<span>growth</span>
<input type="range" min={0} max={100} value={slider} onChange={(e)=>setSlider(+e.target.value)} />
<code>batch≈{batch}</code>
<code>side≈{baseSide}px</code>
<code>dur≈{dur}s</code>
</label>
<div className="row">
<label><input type="checkbox" checked={bigLayers} onChange={e=>setBigLayers(e.target.checked)} /> big fixed pixel layers</label>
<label><input type="checkbox" checked={shadows} onChange={e=>setShadows(e.target.checked)} /> heavy shadows</label>
<label title="requires browser support"><input type="checkbox" checked={backdrop} onChange={e=>setBackdrop(e.target.checked)} /> backdrop blur</label>
</div>
<div className="row">
{!running ? <button className="start" onClick={start}>start</button> : <button className="stop" onClick={stop}>stop</button>}
<button className="panic" onClick={panic}>panic</button>
</div>
<div className="bucket" ref={bucketRef} />
</div>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment