pinToTop: element-level pin-to-top overlays - #26

Merged
daedeloth merged 7 commits into
masterfrom
flung-emojis-qr
Jul 14, 2026
Merged

pinToTop: element-level pin-to-top overlays#26
daedeloth merged 7 commits into
masterfrom
flung-emojis-qr

Conversation

@daedeloth

Copy link
Copy Markdown
Member

Adds an element-level pin-to-top primitive so a display object can render above a chosen layer while still tracking its original placeholder's position/scale/animation.

API

  • easelbone.pinToTop(obj) / easelbone.unpinFromTop(obj)
  • RootView.setPinContainer(container) — designate the layer pinned objects render into
  • stage._pinsHidden — hide all pinned overlays (e.g. while a modal is open)

How it works

Pins reparent obj into a per-pin wrapper on the pin container; the wrapper carries the anchor's bounds (so bounds-sizing Fill/Background objects keep their size) and is re-synced to the anchor's global transform every paint. State lives on the shared stage object so separate easelbone bundles on one stage cooperate. Includes idempotent re-pin, auto-teardown when the anchor leaves the stage, deferred pinning until the object is on a stage, and a Playwright regression test (tools/pin-test.js).

Consumed by catlab-remote-library # and client.quizwitz.com # to keep connect/portal QR codes above the flung-emoji layer. Release v1.2.8.

🤖 Generated with Claude Code

daedelothand others added 7 commits July 14, 2026 14:49
pinToTop reparents an object onto a designated pin container and re-syncs
its transform from its original anchor each paint, so it renders on top
while following the anchor's position/scale/animation. State lives on the
stage object so separate easelbone bundles on one stage cooperate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
pin() previously re-derived the anchor from obj.parent, which is wrong
for an already-pinned object (parent is by then the pin container),
causing a leaked never-torn-down record plus redundant per-frame
matrix work on every re-pin of the same instance. Guard pin() to no-op
when the object is already tracked.
Also mark RootView dirty on successful pin/unpin via DirtyFlag, since
reparenting/removing a child doesn't itself trigger a repaint under
dirtyRendering: true.
Extends the pin-baseline fixture/test with re-pin-replace,
idempotent-re-pin, and anchor-removed auto-teardown coverage; the
idempotent case reproduces FAIL against the pre-fix pin() (2 tracked
records instead of 1) and passes after the fix.
…l size
pinToTop reparented the pinned obj directly into the shared pin
container and rewrote its transform. That broke Fill/Background
objects (e.g. QR codes), which size themselves via
parent.getBounds() -- the plain pin container has no bounds, so the
Fill fell back to a 100x100 default and rendered tiny in the
top-left of its placeholder.
Fix: reparent obj into a per-pin wrapper Container instead. The
wrapper carries the anchor's bounds and is transformed to the
anchor's global position; obj itself (and its own transform/regX/
regY) is left untouched. This reproduces the anchor as obj's parent
exactly (same bounds + same global transform), so Fills size
correctly and non-Fill objects render identically to before.
Record shape is now { obj, anchor, wrapper }. _restore detaches the
wrapper and reattaches obj to its original anchor (if still on
stage), which also makes explicit unpin() put the object back where
it came from instead of leaving it stranded with regX/regY reset.
Added a regression assertion in tools/pin-test.js (via a new
window.__wrapperBounds() fixture hook) proving the wrapper carries
the anchor's [50,50] bounds -- this fails against the pre-fix code
(no wrapper existed) and passes after.
pin() relied on obj's 'added' event when the object wasn't on a stage yet,
but the object is typically addChild'd to its (still-detached) placeholder
BEFORE pinToTop is called -- so 'added' already fired and never fires again
when the placeholder is later attached, silently dropping the pin. Retry on
the ticker until getStage() is truthy. Adds a regression test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lets callers hide all pinned overlays (e.g. the portal QR) while a modal is
open over them, restoring on close. Adds a regression test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
DisplayObject.getStage() is deprecated and logs a warning on every call;
the per-tick sync/teardown checks spammed thousands of warnings. Use the
non-deprecated .stage getter.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds pinToTop (element-level pin-to-top overlays) + stage._pinsHidden.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

📦 PR Preview deployed!

Examples are available at:

@daedeloth
daedeloth merged commit 45bd30d into masterJul 14, 2026
2 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@daedeloth
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

pinToTop: element-level pin-to-top overlays - #26

Merged
daedeloth merged 7 commits into
masterfrom
flung-emojis-qr
Jul 14, 2026
Merged

pinToTop: element-level pin-to-top overlays#26
daedeloth merged 7 commits into
masterfrom
flung-emojis-qr

Conversation

@daedeloth

Copy link
Copy Markdown
Member

Adds an element-level pin-to-top primitive so a display object can render above a chosen layer while still tracking its original placeholder's position/scale/animation.

API

  • easelbone.pinToTop(obj) / easelbone.unpinFromTop(obj)
  • RootView.setPinContainer(container) — designate the layer pinned objects render into
  • stage._pinsHidden — hide all pinned overlays (e.g. while a modal is open)

How it works

Pins reparent obj into a per-pin wrapper on the pin container; the wrapper carries the anchor's bounds (so bounds-sizing Fill/Background objects keep their size) and is re-synced to the anchor's global transform every paint. State lives on the shared stage object so separate easelbone bundles on one stage cooperate. Includes idempotent re-pin, auto-teardown when the anchor leaves the stage, deferred pinning until the object is on a stage, and a Playwright regression test (tools/pin-test.js).

Consumed by catlab-remote-library # and client.quizwitz.com # to keep connect/portal QR codes above the flung-emoji layer. Release v1.2.8.

🤖 Generated with Claude Code

daedelothand others added 7 commits July 14, 2026 14:49
pinToTop reparents an object onto a designated pin container and re-syncs
its transform from its original anchor each paint, so it renders on top
while following the anchor's position/scale/animation. State lives on the
stage object so separate easelbone bundles on one stage cooperate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
pin() previously re-derived the anchor from obj.parent, which is wrong
for an already-pinned object (parent is by then the pin container),
causing a leaked never-torn-down record plus redundant per-frame
matrix work on every re-pin of the same instance. Guard pin() to no-op
when the object is already tracked.
Also mark RootView dirty on successful pin/unpin via DirtyFlag, since
reparenting/removing a child doesn't itself trigger a repaint under
dirtyRendering: true.
Extends the pin-baseline fixture/test with re-pin-replace,
idempotent-re-pin, and anchor-removed auto-teardown coverage; the
idempotent case reproduces FAIL against the pre-fix pin() (2 tracked
records instead of 1) and passes after the fix.
…l size
pinToTop reparented the pinned obj directly into the shared pin
container and rewrote its transform. That broke Fill/Background
objects (e.g. QR codes), which size themselves via
parent.getBounds() -- the plain pin container has no bounds, so the
Fill fell back to a 100x100 default and rendered tiny in the
top-left of its placeholder.
Fix: reparent obj into a per-pin wrapper Container instead. The
wrapper carries the anchor's bounds and is transformed to the
anchor's global position; obj itself (and its own transform/regX/
regY) is left untouched. This reproduces the anchor as obj's parent
exactly (same bounds + same global transform), so Fills size
correctly and non-Fill objects render identically to before.
Record shape is now { obj, anchor, wrapper }. _restore detaches the
wrapper and reattaches obj to its original anchor (if still on
stage), which also makes explicit unpin() put the object back where
it came from instead of leaving it stranded with regX/regY reset.
Added a regression assertion in tools/pin-test.js (via a new
window.__wrapperBounds() fixture hook) proving the wrapper carries
the anchor's [50,50] bounds -- this fails against the pre-fix code
(no wrapper existed) and passes after.
pin() relied on obj's 'added' event when the object wasn't on a stage yet,
but the object is typically addChild'd to its (still-detached) placeholder
BEFORE pinToTop is called -- so 'added' already fired and never fires again
when the placeholder is later attached, silently dropping the pin. Retry on
the ticker until getStage() is truthy. Adds a regression test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lets callers hide all pinned overlays (e.g. the portal QR) while a modal is
open over them, restoring on close. Adds a regression test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
DisplayObject.getStage() is deprecated and logs a warning on every call;
the per-tick sync/teardown checks spammed thousands of warnings. Use the
non-deprecated .stage getter.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds pinToTop (element-level pin-to-top overlays) + stage._pinsHidden.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

📦 PR Preview deployed!

Examples are available at:

@daedeloth
daedeloth merged commit 45bd30d into masterJul 14, 2026
2 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@daedeloth
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

pinToTop: element-level pin-to-top overlays - #26

Merged
daedeloth merged 7 commits into
masterfrom
flung-emojis-qr
Jul 14, 2026
Merged

pinToTop: element-level pin-to-top overlays#26
daedeloth merged 7 commits into
masterfrom
flung-emojis-qr

Conversation

@daedeloth

Copy link
Copy Markdown
Member

Adds an element-level pin-to-top primitive so a display object can render above a chosen layer while still tracking its original placeholder's position/scale/animation.

API

  • easelbone.pinToTop(obj) / easelbone.unpinFromTop(obj)
  • RootView.setPinContainer(container) — designate the layer pinned objects render into
  • stage._pinsHidden — hide all pinned overlays (e.g. while a modal is open)

How it works

Pins reparent obj into a per-pin wrapper on the pin container; the wrapper carries the anchor's bounds (so bounds-sizing Fill/Background objects keep their size) and is re-synced to the anchor's global transform every paint. State lives on the shared stage object so separate easelbone bundles on one stage cooperate. Includes idempotent re-pin, auto-teardown when the anchor leaves the stage, deferred pinning until the object is on a stage, and a Playwright regression test (tools/pin-test.js).

Consumed by catlab-remote-library # and client.quizwitz.com # to keep connect/portal QR codes above the flung-emoji layer. Release v1.2.8.

🤖 Generated with Claude Code

daedelothand others added 7 commits July 14, 2026 14:49
pinToTop reparents an object onto a designated pin container and re-syncs
its transform from its original anchor each paint, so it renders on top
while following the anchor's position/scale/animation. State lives on the
stage object so separate easelbone bundles on one stage cooperate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
pin() previously re-derived the anchor from obj.parent, which is wrong
for an already-pinned object (parent is by then the pin container),
causing a leaked never-torn-down record plus redundant per-frame
matrix work on every re-pin of the same instance. Guard pin() to no-op
when the object is already tracked.
Also mark RootView dirty on successful pin/unpin via DirtyFlag, since
reparenting/removing a child doesn't itself trigger a repaint under
dirtyRendering: true.
Extends the pin-baseline fixture/test with re-pin-replace,
idempotent-re-pin, and anchor-removed auto-teardown coverage; the
idempotent case reproduces FAIL against the pre-fix pin() (2 tracked
records instead of 1) and passes after the fix.
…l size
pinToTop reparented the pinned obj directly into the shared pin
container and rewrote its transform. That broke Fill/Background
objects (e.g. QR codes), which size themselves via
parent.getBounds() -- the plain pin container has no bounds, so the
Fill fell back to a 100x100 default and rendered tiny in the
top-left of its placeholder.
Fix: reparent obj into a per-pin wrapper Container instead. The
wrapper carries the anchor's bounds and is transformed to the
anchor's global position; obj itself (and its own transform/regX/
regY) is left untouched. This reproduces the anchor as obj's parent
exactly (same bounds + same global transform), so Fills size
correctly and non-Fill objects render identically to before.
Record shape is now { obj, anchor, wrapper }. _restore detaches the
wrapper and reattaches obj to its original anchor (if still on
stage), which also makes explicit unpin() put the object back where
it came from instead of leaving it stranded with regX/regY reset.
Added a regression assertion in tools/pin-test.js (via a new
window.__wrapperBounds() fixture hook) proving the wrapper carries
the anchor's [50,50] bounds -- this fails against the pre-fix code
(no wrapper existed) and passes after.
pin() relied on obj's 'added' event when the object wasn't on a stage yet,
but the object is typically addChild'd to its (still-detached) placeholder
BEFORE pinToTop is called -- so 'added' already fired and never fires again
when the placeholder is later attached, silently dropping the pin. Retry on
the ticker until getStage() is truthy. Adds a regression test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lets callers hide all pinned overlays (e.g. the portal QR) while a modal is
open over them, restoring on close. Adds a regression test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
DisplayObject.getStage() is deprecated and logs a warning on every call;
the per-tick sync/teardown checks spammed thousands of warnings. Use the
non-deprecated .stage getter.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds pinToTop (element-level pin-to-top overlays) + stage._pinsHidden.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

📦 PR Preview deployed!

Examples are available at:

@daedeloth
daedeloth merged commit 45bd30d into masterJul 14, 2026
2 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@daedeloth
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

pinToTop: element-level pin-to-top overlays - #26

Merged
daedeloth merged 7 commits into
masterfrom
flung-emojis-qr
Jul 14, 2026
Merged

pinToTop: element-level pin-to-top overlays#26
daedeloth merged 7 commits into
masterfrom
flung-emojis-qr

Conversation

@daedeloth

Copy link
Copy Markdown
Member

Adds an element-level pin-to-top primitive so a display object can render above a chosen layer while still tracking its original placeholder's position/scale/animation.

API

  • easelbone.pinToTop(obj) / easelbone.unpinFromTop(obj)
  • RootView.setPinContainer(container) — designate the layer pinned objects render into
  • stage._pinsHidden — hide all pinned overlays (e.g. while a modal is open)

How it works

Pins reparent obj into a per-pin wrapper on the pin container; the wrapper carries the anchor's bounds (so bounds-sizing Fill/Background objects keep their size) and is re-synced to the anchor's global transform every paint. State lives on the shared stage object so separate easelbone bundles on one stage cooperate. Includes idempotent re-pin, auto-teardown when the anchor leaves the stage, deferred pinning until the object is on a stage, and a Playwright regression test (tools/pin-test.js).

Consumed by catlab-remote-library # and client.quizwitz.com # to keep connect/portal QR codes above the flung-emoji layer. Release v1.2.8.

🤖 Generated with Claude Code

daedelothand others added 7 commits July 14, 2026 14:49
pinToTop reparents an object onto a designated pin container and re-syncs
its transform from its original anchor each paint, so it renders on top
while following the anchor's position/scale/animation. State lives on the
stage object so separate easelbone bundles on one stage cooperate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
pin() previously re-derived the anchor from obj.parent, which is wrong
for an already-pinned object (parent is by then the pin container),
causing a leaked never-torn-down record plus redundant per-frame
matrix work on every re-pin of the same instance. Guard pin() to no-op
when the object is already tracked.
Also mark RootView dirty on successful pin/unpin via DirtyFlag, since
reparenting/removing a child doesn't itself trigger a repaint under
dirtyRendering: true.
Extends the pin-baseline fixture/test with re-pin-replace,
idempotent-re-pin, and anchor-removed auto-teardown coverage; the
idempotent case reproduces FAIL against the pre-fix pin() (2 tracked
records instead of 1) and passes after the fix.
…l size
pinToTop reparented the pinned obj directly into the shared pin
container and rewrote its transform. That broke Fill/Background
objects (e.g. QR codes), which size themselves via
parent.getBounds() -- the plain pin container has no bounds, so the
Fill fell back to a 100x100 default and rendered tiny in the
top-left of its placeholder.
Fix: reparent obj into a per-pin wrapper Container instead. The
wrapper carries the anchor's bounds and is transformed to the
anchor's global position; obj itself (and its own transform/regX/
regY) is left untouched. This reproduces the anchor as obj's parent
exactly (same bounds + same global transform), so Fills size
correctly and non-Fill objects render identically to before.
Record shape is now { obj, anchor, wrapper }. _restore detaches the
wrapper and reattaches obj to its original anchor (if still on
stage), which also makes explicit unpin() put the object back where
it came from instead of leaving it stranded with regX/regY reset.
Added a regression assertion in tools/pin-test.js (via a new
window.__wrapperBounds() fixture hook) proving the wrapper carries
the anchor's [50,50] bounds -- this fails against the pre-fix code
(no wrapper existed) and passes after.
pin() relied on obj's 'added' event when the object wasn't on a stage yet,
but the object is typically addChild'd to its (still-detached) placeholder
BEFORE pinToTop is called -- so 'added' already fired and never fires again
when the placeholder is later attached, silently dropping the pin. Retry on
the ticker until getStage() is truthy. Adds a regression test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lets callers hide all pinned overlays (e.g. the portal QR) while a modal is
open over them, restoring on close. Adds a regression test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
DisplayObject.getStage() is deprecated and logs a warning on every call;
the per-tick sync/teardown checks spammed thousands of warnings. Use the
non-deprecated .stage getter.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds pinToTop (element-level pin-to-top overlays) + stage._pinsHidden.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

📦 PR Preview deployed!

Examples are available at:

@daedeloth
daedeloth merged commit 45bd30d into masterJul 14, 2026
2 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@daedeloth
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

pinToTop: element-level pin-to-top overlays - #26

Merged
daedeloth merged 7 commits into
masterfrom
flung-emojis-qr
Jul 14, 2026
Merged

pinToTop: element-level pin-to-top overlays#26
daedeloth merged 7 commits into
masterfrom
flung-emojis-qr

Conversation

@daedeloth

Copy link
Copy Markdown
Member

Adds an element-level pin-to-top primitive so a display object can render above a chosen layer while still tracking its original placeholder's position/scale/animation.

API

  • easelbone.pinToTop(obj) / easelbone.unpinFromTop(obj)
  • RootView.setPinContainer(container) — designate the layer pinned objects render into
  • stage._pinsHidden — hide all pinned overlays (e.g. while a modal is open)

How it works

Pins reparent obj into a per-pin wrapper on the pin container; the wrapper carries the anchor's bounds (so bounds-sizing Fill/Background objects keep their size) and is re-synced to the anchor's global transform every paint. State lives on the shared stage object so separate easelbone bundles on one stage cooperate. Includes idempotent re-pin, auto-teardown when the anchor leaves the stage, deferred pinning until the object is on a stage, and a Playwright regression test (tools/pin-test.js).

Consumed by catlab-remote-library # and client.quizwitz.com # to keep connect/portal QR codes above the flung-emoji layer. Release v1.2.8.

🤖 Generated with Claude Code

daedelothand others added 7 commits July 14, 2026 14:49
pinToTop reparents an object onto a designated pin container and re-syncs
its transform from its original anchor each paint, so it renders on top
while following the anchor's position/scale/animation. State lives on the
stage object so separate easelbone bundles on one stage cooperate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
pin() previously re-derived the anchor from obj.parent, which is wrong
for an already-pinned object (parent is by then the pin container),
causing a leaked never-torn-down record plus redundant per-frame
matrix work on every re-pin of the same instance. Guard pin() to no-op
when the object is already tracked.
Also mark RootView dirty on successful pin/unpin via DirtyFlag, since
reparenting/removing a child doesn't itself trigger a repaint under
dirtyRendering: true.
Extends the pin-baseline fixture/test with re-pin-replace,
idempotent-re-pin, and anchor-removed auto-teardown coverage; the
idempotent case reproduces FAIL against the pre-fix pin() (2 tracked
records instead of 1) and passes after the fix.
…l size
pinToTop reparented the pinned obj directly into the shared pin
container and rewrote its transform. That broke Fill/Background
objects (e.g. QR codes), which size themselves via
parent.getBounds() -- the plain pin container has no bounds, so the
Fill fell back to a 100x100 default and rendered tiny in the
top-left of its placeholder.
Fix: reparent obj into a per-pin wrapper Container instead. The
wrapper carries the anchor's bounds and is transformed to the
anchor's global position; obj itself (and its own transform/regX/
regY) is left untouched. This reproduces the anchor as obj's parent
exactly (same bounds + same global transform), so Fills size
correctly and non-Fill objects render identically to before.
Record shape is now { obj, anchor, wrapper }. _restore detaches the
wrapper and reattaches obj to its original anchor (if still on
stage), which also makes explicit unpin() put the object back where
it came from instead of leaving it stranded with regX/regY reset.
Added a regression assertion in tools/pin-test.js (via a new
window.__wrapperBounds() fixture hook) proving the wrapper carries
the anchor's [50,50] bounds -- this fails against the pre-fix code
(no wrapper existed) and passes after.
pin() relied on obj's 'added' event when the object wasn't on a stage yet,
but the object is typically addChild'd to its (still-detached) placeholder
BEFORE pinToTop is called -- so 'added' already fired and never fires again
when the placeholder is later attached, silently dropping the pin. Retry on
the ticker until getStage() is truthy. Adds a regression test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lets callers hide all pinned overlays (e.g. the portal QR) while a modal is
open over them, restoring on close. Adds a regression test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
DisplayObject.getStage() is deprecated and logs a warning on every call;
the per-tick sync/teardown checks spammed thousands of warnings. Use the
non-deprecated .stage getter.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds pinToTop (element-level pin-to-top overlays) + stage._pinsHidden.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

📦 PR Preview deployed!

Examples are available at:

@daedeloth
daedeloth merged commit 45bd30d into masterJul 14, 2026
2 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@daedeloth
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

pinToTop: element-level pin-to-top overlays - #26

Merged
daedeloth merged 7 commits into
masterfrom
flung-emojis-qr
Jul 14, 2026
Merged

pinToTop: element-level pin-to-top overlays#26
daedeloth merged 7 commits into
masterfrom
flung-emojis-qr

Conversation

@daedeloth

Copy link
Copy Markdown
Member

Adds an element-level pin-to-top primitive so a display object can render above a chosen layer while still tracking its original placeholder's position/scale/animation.

API

  • easelbone.pinToTop(obj) / easelbone.unpinFromTop(obj)
  • RootView.setPinContainer(container) — designate the layer pinned objects render into
  • stage._pinsHidden — hide all pinned overlays (e.g. while a modal is open)

How it works

Pins reparent obj into a per-pin wrapper on the pin container; the wrapper carries the anchor's bounds (so bounds-sizing Fill/Background objects keep their size) and is re-synced to the anchor's global transform every paint. State lives on the shared stage object so separate easelbone bundles on one stage cooperate. Includes idempotent re-pin, auto-teardown when the anchor leaves the stage, deferred pinning until the object is on a stage, and a Playwright regression test (tools/pin-test.js).

Consumed by catlab-remote-library # and client.quizwitz.com # to keep connect/portal QR codes above the flung-emoji layer. Release v1.2.8.

🤖 Generated with Claude Code

daedelothand others added 7 commits July 14, 2026 14:49
pinToTop reparents an object onto a designated pin container and re-syncs
its transform from its original anchor each paint, so it renders on top
while following the anchor's position/scale/animation. State lives on the
stage object so separate easelbone bundles on one stage cooperate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
pin() previously re-derived the anchor from obj.parent, which is wrong
for an already-pinned object (parent is by then the pin container),
causing a leaked never-torn-down record plus redundant per-frame
matrix work on every re-pin of the same instance. Guard pin() to no-op
when the object is already tracked.
Also mark RootView dirty on successful pin/unpin via DirtyFlag, since
reparenting/removing a child doesn't itself trigger a repaint under
dirtyRendering: true.
Extends the pin-baseline fixture/test with re-pin-replace,
idempotent-re-pin, and anchor-removed auto-teardown coverage; the
idempotent case reproduces FAIL against the pre-fix pin() (2 tracked
records instead of 1) and passes after the fix.
…l size
pinToTop reparented the pinned obj directly into the shared pin
container and rewrote its transform. That broke Fill/Background
objects (e.g. QR codes), which size themselves via
parent.getBounds() -- the plain pin container has no bounds, so the
Fill fell back to a 100x100 default and rendered tiny in the
top-left of its placeholder.
Fix: reparent obj into a per-pin wrapper Container instead. The
wrapper carries the anchor's bounds and is transformed to the
anchor's global position; obj itself (and its own transform/regX/
regY) is left untouched. This reproduces the anchor as obj's parent
exactly (same bounds + same global transform), so Fills size
correctly and non-Fill objects render identically to before.
Record shape is now { obj, anchor, wrapper }. _restore detaches the
wrapper and reattaches obj to its original anchor (if still on
stage), which also makes explicit unpin() put the object back where
it came from instead of leaving it stranded with regX/regY reset.
Added a regression assertion in tools/pin-test.js (via a new
window.__wrapperBounds() fixture hook) proving the wrapper carries
the anchor's [50,50] bounds -- this fails against the pre-fix code
(no wrapper existed) and passes after.
pin() relied on obj's 'added' event when the object wasn't on a stage yet,
but the object is typically addChild'd to its (still-detached) placeholder
BEFORE pinToTop is called -- so 'added' already fired and never fires again
when the placeholder is later attached, silently dropping the pin. Retry on
the ticker until getStage() is truthy. Adds a regression test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lets callers hide all pinned overlays (e.g. the portal QR) while a modal is
open over them, restoring on close. Adds a regression test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
DisplayObject.getStage() is deprecated and logs a warning on every call;
the per-tick sync/teardown checks spammed thousands of warnings. Use the
non-deprecated .stage getter.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds pinToTop (element-level pin-to-top overlays) + stage._pinsHidden.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

📦 PR Preview deployed!

Examples are available at:

@daedeloth
daedeloth merged commit 45bd30d into masterJul 14, 2026
2 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@daedeloth
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

pinToTop: element-level pin-to-top overlays - #26

Merged
daedeloth merged 7 commits into
masterfrom
flung-emojis-qr
Jul 14, 2026
Merged

pinToTop: element-level pin-to-top overlays#26
daedeloth merged 7 commits into
masterfrom
flung-emojis-qr

Conversation

@daedeloth

Copy link
Copy Markdown
Member

Adds an element-level pin-to-top primitive so a display object can render above a chosen layer while still tracking its original placeholder's position/scale/animation.

API

  • easelbone.pinToTop(obj) / easelbone.unpinFromTop(obj)
  • RootView.setPinContainer(container) — designate the layer pinned objects render into
  • stage._pinsHidden — hide all pinned overlays (e.g. while a modal is open)

How it works

Pins reparent obj into a per-pin wrapper on the pin container; the wrapper carries the anchor's bounds (so bounds-sizing Fill/Background objects keep their size) and is re-synced to the anchor's global transform every paint. State lives on the shared stage object so separate easelbone bundles on one stage cooperate. Includes idempotent re-pin, auto-teardown when the anchor leaves the stage, deferred pinning until the object is on a stage, and a Playwright regression test (tools/pin-test.js).

Consumed by catlab-remote-library # and client.quizwitz.com # to keep connect/portal QR codes above the flung-emoji layer. Release v1.2.8.

🤖 Generated with Claude Code

daedelothand others added 7 commits July 14, 2026 14:49
pinToTop reparents an object onto a designated pin container and re-syncs
its transform from its original anchor each paint, so it renders on top
while following the anchor's position/scale/animation. State lives on the
stage object so separate easelbone bundles on one stage cooperate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
pin() previously re-derived the anchor from obj.parent, which is wrong
for an already-pinned object (parent is by then the pin container),
causing a leaked never-torn-down record plus redundant per-frame
matrix work on every re-pin of the same instance. Guard pin() to no-op
when the object is already tracked.
Also mark RootView dirty on successful pin/unpin via DirtyFlag, since
reparenting/removing a child doesn't itself trigger a repaint under
dirtyRendering: true.
Extends the pin-baseline fixture/test with re-pin-replace,
idempotent-re-pin, and anchor-removed auto-teardown coverage; the
idempotent case reproduces FAIL against the pre-fix pin() (2 tracked
records instead of 1) and passes after the fix.
…l size
pinToTop reparented the pinned obj directly into the shared pin
container and rewrote its transform. That broke Fill/Background
objects (e.g. QR codes), which size themselves via
parent.getBounds() -- the plain pin container has no bounds, so the
Fill fell back to a 100x100 default and rendered tiny in the
top-left of its placeholder.
Fix: reparent obj into a per-pin wrapper Container instead. The
wrapper carries the anchor's bounds and is transformed to the
anchor's global position; obj itself (and its own transform/regX/
regY) is left untouched. This reproduces the anchor as obj's parent
exactly (same bounds + same global transform), so Fills size
correctly and non-Fill objects render identically to before.
Record shape is now { obj, anchor, wrapper }. _restore detaches the
wrapper and reattaches obj to its original anchor (if still on
stage), which also makes explicit unpin() put the object back where
it came from instead of leaving it stranded with regX/regY reset.
Added a regression assertion in tools/pin-test.js (via a new
window.__wrapperBounds() fixture hook) proving the wrapper carries
the anchor's [50,50] bounds -- this fails against the pre-fix code
(no wrapper existed) and passes after.
pin() relied on obj's 'added' event when the object wasn't on a stage yet,
but the object is typically addChild'd to its (still-detached) placeholder
BEFORE pinToTop is called -- so 'added' already fired and never fires again
when the placeholder is later attached, silently dropping the pin. Retry on
the ticker until getStage() is truthy. Adds a regression test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lets callers hide all pinned overlays (e.g. the portal QR) while a modal is
open over them, restoring on close. Adds a regression test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
DisplayObject.getStage() is deprecated and logs a warning on every call;
the per-tick sync/teardown checks spammed thousands of warnings. Use the
non-deprecated .stage getter.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds pinToTop (element-level pin-to-top overlays) + stage._pinsHidden.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

📦 PR Preview deployed!

Examples are available at:

@daedeloth
daedeloth merged commit 45bd30d into masterJul 14, 2026
2 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@daedeloth
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

pinToTop: element-level pin-to-top overlays - #26

Merged
daedeloth merged 7 commits into
masterfrom
flung-emojis-qr
Jul 14, 2026
Merged

pinToTop: element-level pin-to-top overlays#26
daedeloth merged 7 commits into
masterfrom
flung-emojis-qr

Conversation

@daedeloth

Copy link
Copy Markdown
Member

Adds an element-level pin-to-top primitive so a display object can render above a chosen layer while still tracking its original placeholder's position/scale/animation.

API

  • easelbone.pinToTop(obj) / easelbone.unpinFromTop(obj)
  • RootView.setPinContainer(container) — designate the layer pinned objects render into
  • stage._pinsHidden — hide all pinned overlays (e.g. while a modal is open)

How it works

Pins reparent obj into a per-pin wrapper on the pin container; the wrapper carries the anchor's bounds (so bounds-sizing Fill/Background objects keep their size) and is re-synced to the anchor's global transform every paint. State lives on the shared stage object so separate easelbone bundles on one stage cooperate. Includes idempotent re-pin, auto-teardown when the anchor leaves the stage, deferred pinning until the object is on a stage, and a Playwright regression test (tools/pin-test.js).

Consumed by catlab-remote-library # and client.quizwitz.com # to keep connect/portal QR codes above the flung-emoji layer. Release v1.2.8.

🤖 Generated with Claude Code

daedelothand others added 7 commits July 14, 2026 14:49
pinToTop reparents an object onto a designated pin container and re-syncs
its transform from its original anchor each paint, so it renders on top
while following the anchor's position/scale/animation. State lives on the
stage object so separate easelbone bundles on one stage cooperate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
pin() previously re-derived the anchor from obj.parent, which is wrong
for an already-pinned object (parent is by then the pin container),
causing a leaked never-torn-down record plus redundant per-frame
matrix work on every re-pin of the same instance. Guard pin() to no-op
when the object is already tracked.
Also mark RootView dirty on successful pin/unpin via DirtyFlag, since
reparenting/removing a child doesn't itself trigger a repaint under
dirtyRendering: true.
Extends the pin-baseline fixture/test with re-pin-replace,
idempotent-re-pin, and anchor-removed auto-teardown coverage; the
idempotent case reproduces FAIL against the pre-fix pin() (2 tracked
records instead of 1) and passes after the fix.
…l size
pinToTop reparented the pinned obj directly into the shared pin
container and rewrote its transform. That broke Fill/Background
objects (e.g. QR codes), which size themselves via
parent.getBounds() -- the plain pin container has no bounds, so the
Fill fell back to a 100x100 default and rendered tiny in the
top-left of its placeholder.
Fix: reparent obj into a per-pin wrapper Container instead. The
wrapper carries the anchor's bounds and is transformed to the
anchor's global position; obj itself (and its own transform/regX/
regY) is left untouched. This reproduces the anchor as obj's parent
exactly (same bounds + same global transform), so Fills size
correctly and non-Fill objects render identically to before.
Record shape is now { obj, anchor, wrapper }. _restore detaches the
wrapper and reattaches obj to its original anchor (if still on
stage), which also makes explicit unpin() put the object back where
it came from instead of leaving it stranded with regX/regY reset.
Added a regression assertion in tools/pin-test.js (via a new
window.__wrapperBounds() fixture hook) proving the wrapper carries
the anchor's [50,50] bounds -- this fails against the pre-fix code
(no wrapper existed) and passes after.
pin() relied on obj's 'added' event when the object wasn't on a stage yet,
but the object is typically addChild'd to its (still-detached) placeholder
BEFORE pinToTop is called -- so 'added' already fired and never fires again
when the placeholder is later attached, silently dropping the pin. Retry on
the ticker until getStage() is truthy. Adds a regression test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lets callers hide all pinned overlays (e.g. the portal QR) while a modal is
open over them, restoring on close. Adds a regression test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
DisplayObject.getStage() is deprecated and logs a warning on every call;
the per-tick sync/teardown checks spammed thousands of warnings. Use the
non-deprecated .stage getter.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds pinToTop (element-level pin-to-top overlays) + stage._pinsHidden.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

📦 PR Preview deployed!

Examples are available at:

@daedeloth
daedeloth merged commit 45bd30d into masterJul 14, 2026
2 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@daedeloth