Spaces:
Running on Zero
Compute Backend in Advanced + kill empty space in browser app
Browse filesBrowser runtime:
- MutationObserver inside the iframe re-tags anything added by later
foldkit renders, so Compute Backend (Auto/WebGPU/WASM) and any
advanced section reliably gets .studio-adv-section and stays hidden
until the Advanced toggle is opened.
- Inject the Advanced toggle button with a fallback re-injector on DOM
mutation, so the toggle survives SPA re-renders.
- Explicit CSS hide of .grid.grid-cols-3.studio-adv-section as a hard
fallback for the compute backend grid.
- Kill the empty space at the bottom of the compose column:
.embedded-compose / .embedded-sidebar use align-self:start + flex:0 0
auto so they don't stretch; the empty border-t pt-6 wrapper and the
flex.w-full download bar (when empty) are hidden; embedded-grid items
align at start.
Co-Authored-By: Claude <noreply@anthropic.com>
- index.html +91 -16
|
@@ -564,14 +564,15 @@ $("seed").addEventListener("input",(e)=>{ $("seed-val").textContent=e.target.val
|
|
| 564 |
/* ---- injected "Advanced" disclosure for the runtime ---- */
|
| 565 |
/* advanced sections hidden by default; revealed by body.studio-adv-open */
|
| 566 |
.voice-controls, .playback-setting, .session-status, .embedded-logs { display:none !important }
|
| 567 |
-
/*
|
|
|
|
|
|
|
| 568 |
body.studio-adv-open .voice-controls,
|
| 569 |
body.studio-adv-open .playback-setting,
|
| 570 |
body.studio-adv-open .session-status,
|
| 571 |
-
body.studio-adv-open .embedded-logs
|
| 572 |
-
body.studio-adv-open .studio-
|
| 573 |
-
body.studio-adv-open .studio-adv-section { display:flex !important }
|
| 574 |
-
.studio-adv-section{display:none !important}
|
| 575 |
|
| 576 |
.studio-adv-toggle{
|
| 577 |
appearance:none;border:1px solid #2a2c2e;background:#1c1e20;color:#f5f5f7;
|
|
@@ -596,9 +597,21 @@ $("seed").addEventListener("input",(e)=>{ $("seed-val").textContent=e.target.val
|
|
| 596 |
.model-option .h-2.w-2{height:7px !important;width:7px !important}
|
| 597 |
|
| 598 |
/* ---- reduce extra blank space in the embedded runtime ---- */
|
|
|
|
|
|
|
|
|
|
|
|
|
| 599 |
.embedded-compose{gap:14px !important;padding:18px !important}
|
| 600 |
.embedded-sidebar{padding:18px !important;gap:14px !important}
|
| 601 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 602 |
.section-label{font-size:11px !important;letter-spacing:.1em !important;text-transform:uppercase;color:#86868b !important}
|
| 603 |
.embedded-compose>div:first-child>h2,
|
| 604 |
.embedded-compose .text-lg{font-size:15px !important;margin-top:2px !important}
|
|
@@ -629,21 +642,41 @@ $("seed").addEventListener("input",(e)=>{ $("seed-val").textContent=e.target.val
|
|
| 629 |
};
|
| 630 |
/* Move the runtime's advanced sections under an injected disclosure,
|
| 631 |
leaving only Write / Model / Generate visible by default. Pure CSS
|
| 632 |
-
toggle (no node-moving) so it survives the runtime's re-renders.
|
|
|
|
|
|
|
| 633 |
const ADVANCED_LABELS = new Set(["Compute backend","Runtime","Playback mode","Voice controls","Logs","Activity","Details"]);
|
| 634 |
-
const
|
| 635 |
const root = doc.getElementById("root");
|
| 636 |
if (!root) return;
|
| 637 |
-
//
|
|
|
|
| 638 |
doc.querySelectorAll(".section-label").forEach((lab) => {
|
| 639 |
const t = (lab.textContent || "").trim();
|
| 640 |
-
if (!t) return;
|
| 641 |
-
|
| 642 |
-
|
| 643 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 644 |
}
|
| 645 |
});
|
| 646 |
-
|
|
|
|
| 647 |
if (doc.getElementById("studio-adv-toggle")) return;
|
| 648 |
const sidebar = doc.querySelector(".embedded-sidebar") || doc.querySelector(".embedded-compose");
|
| 649 |
if (!sidebar) return;
|
|
@@ -655,14 +688,56 @@ $("seed").addEventListener("input",(e)=>{ $("seed-val").textContent=e.target.val
|
|
| 655 |
btn.addEventListener("click", () => {
|
| 656 |
const open = doc.body.classList.toggle("studio-adv-open");
|
| 657 |
btn.setAttribute("aria-expanded", String(open));
|
| 658 |
-
// tell the parent to re-measure the iframe height after the layout changes
|
| 659 |
try { frame.contentWindow.postMessage({ type: "inflect-web-resize", height: Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight) }, window.location.origin); } catch (_) {}
|
| 660 |
});
|
| 661 |
sidebar.appendChild(btn);
|
| 662 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 663 |
frame.addEventListener("load", apply);
|
| 664 |
// re-apply if the SPA mounts after load
|
| 665 |
-
[100, 400, 900, 1800, 3000].forEach((d) => window.setTimeout(apply, d));
|
| 666 |
})();
|
| 667 |
|
| 668 |
/* responsive browser frame height */
|
|
|
|
| 564 |
/* ---- injected "Advanced" disclosure for the runtime ---- */
|
| 565 |
/* advanced sections hidden by default; revealed by body.studio-adv-open */
|
| 566 |
.voice-controls, .playback-setting, .session-status, .embedded-logs { display:none !important }
|
| 567 |
+
/* Compute Backend (no stable class) is tagged .studio-adv-section by JS; also hide the Auto/WebGPU/WASM grid by sibling match */
|
| 568 |
+
.grid.grid-cols-3.studio-adv-section{display:none !important}
|
| 569 |
+
/* show on open */
|
| 570 |
body.studio-adv-open .voice-controls,
|
| 571 |
body.studio-adv-open .playback-setting,
|
| 572 |
body.studio-adv-open .session-status,
|
| 573 |
+
body.studio-adv-open .embedded-logs,
|
| 574 |
+
body.studio-adv-open .studio-adv-section,
|
| 575 |
+
body.studio-adv-open .grid.grid-cols-3.studio-adv-section { display:flex !important }
|
|
|
|
| 576 |
|
| 577 |
.studio-adv-toggle{
|
| 578 |
appearance:none;border:1px solid #2a2c2e;background:#1c1e20;color:#f5f5f7;
|
|
|
|
| 597 |
.model-option .h-2.w-2{height:7px !important;width:7px !important}
|
| 598 |
|
| 599 |
/* ---- reduce extra blank space in the embedded runtime ---- */
|
| 600 |
+
/* stop the compose/sidebar from stretching to fill the embed height */
|
| 601 |
+
.embedded-compose, .embedded-sidebar { align-self:start !important; flex:0 0 auto !important }
|
| 602 |
+
.embedded-panel{align-items:start !important}
|
| 603 |
+
.embedded-grid{align-items:start !important;gap:0 !important}
|
| 604 |
.embedded-compose{gap:14px !important;padding:18px !important}
|
| 605 |
.embedded-sidebar{padding:18px !important;gap:14px !important}
|
| 606 |
+
/* kill the empty playback-area block at the bottom of compose (border-t pt-6 wrapper with nothing inside) */
|
| 607 |
+
.embedded-compose>div.border-t.border-slate-200.pt-6:empty,
|
| 608 |
+
.embedded-compose>div.border-t.border-slate-200.pt-6:not(:has(*)),
|
| 609 |
+
.embedded-compose>.flex.w-full:empty,
|
| 610 |
+
.embedded-compose>.flex.w-full:not(:has(*)) { display:none !important }
|
| 611 |
+
/* also kill the wrapper if it contains only an invisible download link */
|
| 612 |
+
.embedded-compose>.flex.w-full:not(:has(a:not(.hidden)):not(button)){display:none !important}
|
| 613 |
+
/* collapse the big empty area under the button */
|
| 614 |
+
.embedded-compose>div:last-child:not(.flex):empty{display:none !important}
|
| 615 |
.section-label{font-size:11px !important;letter-spacing:.1em !important;text-transform:uppercase;color:#86868b !important}
|
| 616 |
.embedded-compose>div:first-child>h2,
|
| 617 |
.embedded-compose .text-lg{font-size:15px !important;margin-top:2px !important}
|
|
|
|
| 642 |
};
|
| 643 |
/* Move the runtime's advanced sections under an injected disclosure,
|
| 644 |
leaving only Write / Model / Generate visible by default. Pure CSS
|
| 645 |
+
toggle (no node-moving) so it survives the runtime's re-renders.
|
| 646 |
+
A MutationObserver re-tags anything added later (foldkit renders
|
| 647 |
+
sections progressively). */
|
| 648 |
const ADVANCED_LABELS = new Set(["Compute backend","Runtime","Playback mode","Voice controls","Logs","Activity","Details"]);
|
| 649 |
+
const tagAdvanced = (doc) => {
|
| 650 |
const root = doc.getElementById("root");
|
| 651 |
if (!root) return;
|
| 652 |
+
// tag any section-label whose text is in the advanced set; walk up to the
|
| 653 |
+
// nearest flex/block wrapper so the whole section hides together.
|
| 654 |
doc.querySelectorAll(".section-label").forEach((lab) => {
|
| 655 |
const t = (lab.textContent || "").trim();
|
| 656 |
+
if (!t || !ADVANCED_LABELS.has(t)) return;
|
| 657 |
+
// the label's parent is the section wrapper; climb one more level to
|
| 658 |
+
// capture the outer block (some labels sit inside an inner heading div)
|
| 659 |
+
let node = lab.parentElement;
|
| 660 |
+
if (node) {
|
| 661 |
+
// mark the immediate parent + any flex/gap wrapper above it
|
| 662 |
+
node.classList.add("studio-adv-section");
|
| 663 |
+
if (node.parentElement && /flex|grid/.test(node.parentElement.className)) {
|
| 664 |
+
node.parentElement.classList.add("studio-adv-section");
|
| 665 |
+
}
|
| 666 |
+
}
|
| 667 |
+
});
|
| 668 |
+
// also tag the Auto/WebGPU/WASM grid directly as a safety net
|
| 669 |
+
doc.querySelectorAll(".grid.grid-cols-3").forEach((g) => {
|
| 670 |
+
const prev = g.previousElementSibling;
|
| 671 |
+
if (prev && (prev.textContent || "").trim() === "Compute backend") {
|
| 672 |
+
g.classList.add("studio-adv-section");
|
| 673 |
+
// and its container
|
| 674 |
+
const wrap = g.closest(".flex.flex-col");
|
| 675 |
+
if (wrap) wrap.classList.add("studio-adv-section");
|
| 676 |
}
|
| 677 |
});
|
| 678 |
+
};
|
| 679 |
+
const ensureToggle = (doc) => {
|
| 680 |
if (doc.getElementById("studio-adv-toggle")) return;
|
| 681 |
const sidebar = doc.querySelector(".embedded-sidebar") || doc.querySelector(".embedded-compose");
|
| 682 |
if (!sidebar) return;
|
|
|
|
| 688 |
btn.addEventListener("click", () => {
|
| 689 |
const open = doc.body.classList.toggle("studio-adv-open");
|
| 690 |
btn.setAttribute("aria-expanded", String(open));
|
|
|
|
| 691 |
try { frame.contentWindow.postMessage({ type: "inflect-web-resize", height: Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight) }, window.location.origin); } catch (_) {}
|
| 692 |
});
|
| 693 |
sidebar.appendChild(btn);
|
| 694 |
};
|
| 695 |
+
const groupAdvanced = (doc) => {
|
| 696 |
+
const root = doc.getElementById("root");
|
| 697 |
+
if (!root) return;
|
| 698 |
+
tagAdvanced(doc);
|
| 699 |
+
ensureToggle(doc);
|
| 700 |
+
// MutationObserver so later renders (foldkit re-renders) get re-tagged
|
| 701 |
+
if (!doc.getElementById("studio-adv-mobs")) {
|
| 702 |
+
const script = doc.createElement("script");
|
| 703 |
+
script.id = "studio-adv-mobs";
|
| 704 |
+
script.textContent = `(function(){
|
| 705 |
+
var mo = new MutationObserver(function(){
|
| 706 |
+
var doc = document;
|
| 707 |
+
var LABELS = ["Compute backend","Runtime","Playback mode","Voice controls","Logs","Activity","Details"];
|
| 708 |
+
doc.querySelectorAll(".section-label").forEach(function(lab){
|
| 709 |
+
var t=(lab.textContent||"").trim();
|
| 710 |
+
if (!LABELS.includes(t)) return;
|
| 711 |
+
var n = lab.parentElement;
|
| 712 |
+
if (n){ n.classList.add("studio-adv-section");
|
| 713 |
+
if (n.parentElement && /flex|grid/.test(n.parentElement.className)) n.parentElement.classList.add("studio-adv-section"); }
|
| 714 |
+
});
|
| 715 |
+
// also tag the Auto/WebGPU/WASM grid each render
|
| 716 |
+
doc.querySelectorAll(".grid.grid-cols-3").forEach(function(g){
|
| 717 |
+
var prev=g.previousElementSibling;
|
| 718 |
+
if (prev && (prev.textContent||"").trim()==="Compute backend"){
|
| 719 |
+
g.classList.add("studio-adv-section"); var w=g.closest(".flex.flex-col"); if (w) w.classList.add("studio-adv-section");
|
| 720 |
+
}
|
| 721 |
+
});
|
| 722 |
+
// re-inject toggle if wiped
|
| 723 |
+
if (!doc.getElementById("studio-adv-toggle")) {
|
| 724 |
+
var sb = doc.querySelector(".embedded-sidebar") || doc.querySelector(".embedded-compose");
|
| 725 |
+
if (sb){ var b = doc.createElement("button"); b.id="studio-adv-toggle"; b.type="button"; b.className="studio-adv-toggle";
|
| 726 |
+
b.innerHTML='<span class="dot"></span><span>Advanced</span><span class="chev">▸</span>';
|
| 727 |
+
b.addEventListener("click",function(){ var o=doc.body.classList.toggle("studio-adv-open"); b.setAttribute("aria-expanded",String(o));
|
| 728 |
+
try{ var fr=window.frameElement; (window.parent||{}).postMessage({type:"inflect-web-resize",height:Math.max(doc.body.scrollHeight,doc.documentElement.scrollHeight)}, "*"); }catch(_){} });
|
| 729 |
+
sb.appendChild(b);
|
| 730 |
+
}
|
| 731 |
+
}
|
| 732 |
+
});
|
| 733 |
+
mo.observe(document.getElementById("root") || document.body, { childList: true, subtree: true });
|
| 734 |
+
})();`;
|
| 735 |
+
doc.body.appendChild(script);
|
| 736 |
+
}
|
| 737 |
+
};
|
| 738 |
frame.addEventListener("load", apply);
|
| 739 |
// re-apply if the SPA mounts after load
|
| 740 |
+
[100, 400, 900, 1800, 3000, 5000].forEach((d) => window.setTimeout(apply, d));
|
| 741 |
})();
|
| 742 |
|
| 743 |
/* responsive browser frame height */
|