fix(bench): fill the 3D scene, center the ×, one-line input with send arrow
Browse files- The voxel root section wasn't stretched to the scene, so its stage collapsed
to auto height and setupVoxel fell back to a 300px canvas — leaving an empty
blue band below the model. Stretch .buddy-voxel-root (and force the canvas to
fill) so the 3D fills the full 380px scene (verified canvas 380 == scene 380,
gap 0).
- Re-center the × token on the now-full scene (xVsScene ~0).
- Tweak controls on ONE line: widen the row to the scene width + nowrap so the
input and send button no longer stack. Replace the 'Apply' button with a
compact ChatGPT-style accent square showing an up-arrow (↑).
Verified on the fake runtime; 76 tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
src/buddy_fusion/fusion_ui.py
CHANGED
|
@@ -133,7 +133,9 @@ CSS = (
|
|
| 133 |
".buddy-slot-clear{position:absolute;top:4px;right:6px;border:none;background:#0001;border-radius:50%;"
|
| 134 |
"width:22px;height:22px;cursor:pointer;color:var(--lab-ink);font-weight:700;line-height:1;}"
|
| 135 |
# inline per-slot AI tweak inputs (sit under the A / B staged previews)
|
| 136 |
-
|
|
|
|
|
|
|
| 137 |
".buddy-tweak-row textarea,.buddy-tweak-row input{border-radius:10px!important;text-align:center;"
|
| 138 |
"border:1px solid #2a274022!important;background:#ffffffcc!important;color:var(--lab-ink)!important;}"
|
| 139 |
".buddy-tweak-row textarea::placeholder{color:#2a274077;}"
|
|
@@ -212,7 +214,7 @@ CSS = (
|
|
| 212 |
# Each side sizes to its scene; flex-wrap lets A/B stack on very narrow screens.
|
| 213 |
".buddy-bench-col{flex:0 1 460px!important;min-width:300px!important;}"
|
| 214 |
# × is a soft game-token circle aligned to the scene's vertical centre.
|
| 215 |
-
".buddy-bench-x{flex:0 0 auto;align-self:flex-start;margin-top:
|
| 216 |
"display:flex;align-items:center;justify-content:center;font-size:1.6rem;font-weight:800;color:var(--lab-accent);"
|
| 217 |
"background:#fff;box-shadow:0 6px 18px #5a93c733,inset 0 0 0 1.5px #ff7a1840;}"
|
| 218 |
".buddy-bench-cell{position:relative;display:flex;flex-direction:column;align-items:center;text-align:center;}"
|
|
@@ -225,7 +227,12 @@ CSS = (
|
|
| 225 |
# The big 3D scene: the creature fills it; hint bubbles float over it.
|
| 226 |
".buddy-bench-scene{position:relative;width:440px;max-width:100%;height:380px;border-radius:24px;overflow:hidden;"
|
| 227 |
"background:#cfeaff;box-shadow:inset 0 0 0 2px #ffffffcc,0 16px 40px #5a93c733;}"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 228 |
".buddy-bench-scene .buddy-voxel-stage{width:100%;height:100%;border-radius:24px;overflow:hidden;}"
|
|
|
|
| 229 |
# Floating hint bubble: glassy pill positioned over the canvas, gentle bob.
|
| 230 |
".buddy-bubble{position:absolute;z-index:3;width:150px;border:1.5px solid #ffffffcc;"
|
| 231 |
"background:rgba(255,255,255,.88);backdrop-filter:blur(4px);border-radius:16px;padding:7px 11px;"
|
|
@@ -237,10 +244,13 @@ CSS = (
|
|
| 237 |
"@keyframes buddy-float{0%{transform:translateY(0)}50%{transform:translateY(-5px)}100%{transform:translateY(0)}}"
|
| 238 |
"@media (prefers-reduced-motion:no-preference){.buddy-bubble{animation:buddy-float 3.4s ease-in-out infinite;}"
|
| 239 |
".buddy-bubble:nth-child(odd){animation-delay:.9s;}}"
|
| 240 |
-
#
|
| 241 |
-
#
|
| 242 |
-
"#buddy-tweak-a-btn,#buddy-tweak-b-btn{
|
| 243 |
-
"
|
|
|
|
|
|
|
|
|
|
| 244 |
# ---- Lab entry actions (Compendium + Draw, side by side, centered) -------
|
| 245 |
".buddy-lab-actions{display:flex;gap:10px;justify-content:center;align-items:center;margin:2px auto 4px;}"
|
| 246 |
# White secondary pill (matches #buddy-free-enter), subordinate to the tree.
|
|
@@ -568,14 +578,14 @@ def build_app() -> gr.Blocks:
|
|
| 568 |
with gr.Row(elem_classes=["buddy-tweak-row"]):
|
| 569 |
tweak_a = gr.Textbox(show_label=False, container=False, scale=1, lines=1, max_lines=1,
|
| 570 |
elem_id="buddy-tweak-a", placeholder='✎ or type your own — "add two horns"')
|
| 571 |
-
tweak_a_btn = gr.Button("
|
| 572 |
gr.HTML('<div class="buddy-bench-x">×</div>')
|
| 573 |
with gr.Column(scale=1, elem_classes=["buddy-bench-col"]):
|
| 574 |
bench_b_view = gr.HTML()
|
| 575 |
with gr.Row(elem_classes=["buddy-tweak-row"]):
|
| 576 |
tweak_b = gr.Textbox(show_label=False, container=False, scale=1, lines=1, max_lines=1,
|
| 577 |
elem_id="buddy-tweak-b", placeholder='✎ or type your own — "make it a frog"')
|
| 578 |
-
tweak_b_btn = gr.Button("
|
| 579 |
splice_btn = gr.Button("Splice! 🧬", elem_id="buddy-fuse-btn", variant="primary")
|
| 580 |
# Hidden chip bridge: JS writes {side,prompt} into chip_in then clicks chip_btn.
|
| 581 |
chip_in = gr.Textbox(elem_id="buddy-chip-in", elem_classes=["buddy-bridge-box"],
|
|
|
|
| 133 |
".buddy-slot-clear{position:absolute;top:4px;right:6px;border:none;background:#0001;border-radius:50%;"
|
| 134 |
"width:22px;height:22px;cursor:pointer;color:var(--lab-ink);font-weight:700;line-height:1;}"
|
| 135 |
# inline per-slot AI tweak inputs (sit under the A / B staged previews)
|
| 136 |
+
# One line under the scene: input fills, send button sits at the right. Width
|
| 137 |
+
# matches the scene so input + send never wrap.
|
| 138 |
+
".buddy-tweak-row{max-width:440px;margin:14px auto 4px;gap:8px;align-items:center;flex-wrap:nowrap!important;}"
|
| 139 |
".buddy-tweak-row textarea,.buddy-tweak-row input{border-radius:10px!important;text-align:center;"
|
| 140 |
"border:1px solid #2a274022!important;background:#ffffffcc!important;color:var(--lab-ink)!important;}"
|
| 141 |
".buddy-tweak-row textarea::placeholder{color:#2a274077;}"
|
|
|
|
| 214 |
# Each side sizes to its scene; flex-wrap lets A/B stack on very narrow screens.
|
| 215 |
".buddy-bench-col{flex:0 1 460px!important;min-width:300px!important;}"
|
| 216 |
# × is a soft game-token circle aligned to the scene's vertical centre.
|
| 217 |
+
".buddy-bench-x{flex:0 0 auto;align-self:flex-start;margin-top:204px;width:48px;height:48px;border-radius:50%;"
|
| 218 |
"display:flex;align-items:center;justify-content:center;font-size:1.6rem;font-weight:800;color:var(--lab-accent);"
|
| 219 |
"background:#fff;box-shadow:0 6px 18px #5a93c733,inset 0 0 0 1.5px #ff7a1840;}"
|
| 220 |
".buddy-bench-cell{position:relative;display:flex;flex-direction:column;align-items:center;text-align:center;}"
|
|
|
|
| 227 |
# The big 3D scene: the creature fills it; hint bubbles float over it.
|
| 228 |
".buddy-bench-scene{position:relative;width:440px;max-width:100%;height:380px;border-radius:24px;overflow:hidden;"
|
| 229 |
"background:#cfeaff;box-shadow:inset 0 0 0 2px #ffffffcc,0 16px 40px #5a93c733;}"
|
| 230 |
+
# The voxel root section must FILL the scene, or its child stage collapses to
|
| 231 |
+
# auto height (parent has no definite height) and setupVoxel falls back to a
|
| 232 |
+
# 300px canvas — leaving an empty blue band below the model.
|
| 233 |
+
".buddy-bench-scene .buddy-voxel-root{display:block;width:100%;height:100%;}"
|
| 234 |
".buddy-bench-scene .buddy-voxel-stage{width:100%;height:100%;border-radius:24px;overflow:hidden;}"
|
| 235 |
+
".buddy-bench-scene .buddy-voxel-stage canvas{width:100%!important;height:100%!important;display:block;}"
|
| 236 |
# Floating hint bubble: glassy pill positioned over the canvas, gentle bob.
|
| 237 |
".buddy-bubble{position:absolute;z-index:3;width:150px;border:1.5px solid #ffffffcc;"
|
| 238 |
"background:rgba(255,255,255,.88);backdrop-filter:blur(4px);border-radius:16px;padding:7px 11px;"
|
|
|
|
| 244 |
"@keyframes buddy-float{0%{transform:translateY(0)}50%{transform:translateY(-5px)}100%{transform:translateY(0)}}"
|
| 245 |
"@media (prefers-reduced-motion:no-preference){.buddy-bubble{animation:buddy-float 3.4s ease-in-out infinite;}"
|
| 246 |
".buddy-bubble:nth-child(odd){animation-delay:.9s;}}"
|
| 247 |
+
# ChatGPT-style send: a compact accent square with an up-arrow glyph, sitting
|
| 248 |
+
# at the right end of the one-line tweak row.
|
| 249 |
+
"#buddy-tweak-a-btn,#buddy-tweak-b-btn{flex:0 0 auto!important;min-width:46px!important;max-width:46px!important;"
|
| 250 |
+
"width:46px;height:46px;padding:0!important;border-radius:13px!important;font-size:1.4rem;font-weight:900;line-height:1;"
|
| 251 |
+
"color:#fff!important;background:linear-gradient(135deg,#ff7a18,#ff4d8d)!important;border:none!important;"
|
| 252 |
+
"box-shadow:0 4px 14px #ff4d8d44!important;}"
|
| 253 |
+
"#buddy-tweak-a-btn:hover,#buddy-tweak-b-btn:hover{filter:brightness(1.05);box-shadow:0 6px 18px #ff4d8d55!important;}"
|
| 254 |
# ---- Lab entry actions (Compendium + Draw, side by side, centered) -------
|
| 255 |
".buddy-lab-actions{display:flex;gap:10px;justify-content:center;align-items:center;margin:2px auto 4px;}"
|
| 256 |
# White secondary pill (matches #buddy-free-enter), subordinate to the tree.
|
|
|
|
| 578 |
with gr.Row(elem_classes=["buddy-tweak-row"]):
|
| 579 |
tweak_a = gr.Textbox(show_label=False, container=False, scale=1, lines=1, max_lines=1,
|
| 580 |
elem_id="buddy-tweak-a", placeholder='✎ or type your own — "add two horns"')
|
| 581 |
+
tweak_a_btn = gr.Button("↑", elem_id="buddy-tweak-a-btn", scale=0)
|
| 582 |
gr.HTML('<div class="buddy-bench-x">×</div>')
|
| 583 |
with gr.Column(scale=1, elem_classes=["buddy-bench-col"]):
|
| 584 |
bench_b_view = gr.HTML()
|
| 585 |
with gr.Row(elem_classes=["buddy-tweak-row"]):
|
| 586 |
tweak_b = gr.Textbox(show_label=False, container=False, scale=1, lines=1, max_lines=1,
|
| 587 |
elem_id="buddy-tweak-b", placeholder='✎ or type your own — "make it a frog"')
|
| 588 |
+
tweak_b_btn = gr.Button("↑", elem_id="buddy-tweak-b-btn", scale=0)
|
| 589 |
splice_btn = gr.Button("Splice! 🧬", elem_id="buddy-fuse-btn", variant="primary")
|
| 590 |
# Hidden chip bridge: JS writes {side,prompt} into chip_in then clicks chip_btn.
|
| 591 |
chip_in = gr.Textbox(elem_id="buddy-chip-in", elem_classes=["buddy-bridge-box"],
|