Initial commit

This commit is contained in:
Samraaj Bath
2026-06-29 15:11:48 -07:00
commit 66dfdcc58d
404 changed files with 45970 additions and 0 deletions
@@ -0,0 +1,193 @@
// Exposes window.__CLONE_DUMP_COMPUTED__() which walks the DOM and returns a minimal tree
// of resolved computed styles (only non-default values). The capture script calls this on demand
// after each scroll step — cheap to call repeatedly, much richer than the inline per-step snapshot
// the Playwright script does as a fallback.
(() => {
const PROPS = [
'color',
'backgroundColor',
'backgroundImage',
'backgroundSize',
'backgroundPosition',
'backgroundRepeat',
'backgroundAttachment',
'backgroundClip',
'fontFamily',
'fontSize',
'fontWeight',
'lineHeight',
'letterSpacing',
'textTransform',
'textAlign',
'textDecoration',
'textShadow',
'whiteSpace',
'display',
'flexDirection',
'flexWrap',
'justifyContent',
'alignItems',
'alignContent',
'alignSelf',
'gap',
'rowGap',
'columnGap',
'gridTemplateColumns',
'gridTemplateRows',
'gridTemplateAreas',
'gridColumn',
'gridRow',
'gridAutoFlow',
'padding',
'paddingTop',
'paddingRight',
'paddingBottom',
'paddingLeft',
'margin',
'marginTop',
'marginRight',
'marginBottom',
'marginLeft',
'width',
'height',
'maxWidth',
'maxHeight',
'minWidth',
'minHeight',
'aspectRatio',
'position',
'top',
'right',
'bottom',
'left',
'zIndex',
'inset',
'border',
'borderTop',
'borderRight',
'borderBottom',
'borderLeft',
'borderRadius',
'borderColor',
'borderWidth',
'borderStyle',
'boxShadow',
'opacity',
'transform',
'transformOrigin',
'filter',
'backdropFilter',
'clipPath',
'mask',
'maskImage',
'mixBlendMode',
'isolation',
'overflow',
'overflowX',
'overflowY',
'scrollBehavior',
'scrollSnapType',
'cursor',
'pointerEvents',
'userSelect',
'willChange',
'contain',
];
// Compute defaults once per tag by creating a hidden iframe so we don't treat
// inherited defaults as "used styles". The iframe is created lazily — at
// init-script time, document.documentElement may still be null (Playwright
// fires add_init_script before the HTML parser materialises <html>).
let iframe = null;
function ensureIframe() {
if (iframe) return iframe;
if (!document.documentElement) return null;
try {
iframe = document.createElement('iframe');
iframe.style.cssText = 'position:absolute;width:0;height:0;border:0;opacity:0;pointer-events:none';
iframe.srcdoc = '<!doctype html><html><body></body></html>';
document.documentElement.appendChild(iframe);
} catch {
iframe = null;
}
return iframe;
}
const defaultsByTag = new Map();
function defaultsFor(tag) {
if (defaultsByTag.has(tag)) return defaultsByTag.get(tag);
const ifr = ensureIframe();
const doc = ifr ? ifr.contentDocument : null;
if (!doc || !doc.body) return {};
const el = doc.createElement(tag);
doc.body.appendChild(el);
const cs = doc.defaultView.getComputedStyle(el);
const d = {};
for (const p of PROPS) d[p] = cs[p];
doc.body.removeChild(el);
defaultsByTag.set(tag, d);
return d;
}
function nonDefault(el) {
const cs = getComputedStyle(el);
const defaults = defaultsFor(el.tagName.toLowerCase());
const out = {};
for (const p of PROPS) {
const v = cs[p];
if (v == null || v === '') continue;
if (v === defaults[p]) continue;
out[p] = v;
}
return out;
}
function pseudoStyles(el) {
const out = {};
for (const pseudo of ['::before', '::after']) {
try {
const cs = getComputedStyle(el, pseudo);
const content = cs.content;
if (content && content !== 'normal' && content !== 'none') {
const block = {};
for (const p of PROPS) {
const v = cs[p];
if (v && v !== 'none' && v !== 'normal' && v !== 'auto') block[p] = v;
}
block.content = content;
out[pseudo] = block;
}
} catch {}
}
return Object.keys(out).length ? out : undefined;
}
function serialize(el) {
if (el.nodeType === Node.TEXT_NODE) {
const t = el.textContent;
return t && t.trim() ? { text: t } : null;
}
if (el.nodeType !== Node.ELEMENT_NODE) return null;
if (el.tagName === 'SCRIPT' || el.tagName === 'STYLE' || el.tagName === 'NOSCRIPT') return null;
const attrs = {};
for (const a of el.attributes) attrs[a.name] = a.value;
const computed = nonDefault(el);
const pseudo = pseudoStyles(el);
if (pseudo) computed.pseudo = pseudo;
const r = el.getBoundingClientRect();
const children = [];
for (const c of el.childNodes) {
const s = serialize(c);
if (s) children.push(s);
}
return {
tag: el.tagName.toLowerCase(),
attrs,
computed,
bbox: { x: r.x, y: r.y + window.scrollY, width: r.width, height: r.height },
children,
};
}
window.__CLONE_DUMP_COMPUTED__ = () => serialize(document.body);
})();